import React, { useEffect, useRef } from 'react' import { useNotifications } from 'src/context/notifications.js' import { Text } from '@anthropic/ink' import type { MCPServerConnection } from 'src/services/mcp/types.js' import { getGlobalConfig, saveGlobalConfig } from 'src/utils/config.js' import { detectIDEs, type IDEExtensionInstallationStatus, isJetBrainsIde, isSupportedTerminal, } from 'src/utils/ide.js' import { getIsRemoteMode } from '../../bootstrap/state.js' import { useIdeConnectionStatus } from '../useIdeConnectionStatus.js' import type { IDESelection } from '../useIdeSelection.js' const MAX_IDE_HINT_SHOW_COUNT = 5 type Props = { ideInstallationStatus: IDEExtensionInstallationStatus | null ideSelection: IDESelection | undefined mcpClients: MCPServerConnection[] } export function useIDEStatusIndicator({ ideSelection, mcpClients, ideInstallationStatus, }: Props): void { const { addNotification, removeNotification } = useNotifications() const { status: ideStatus, ideName } = useIdeConnectionStatus(mcpClients) const hasShownHintRef = useRef(false) const isJetBrains = ideInstallationStatus ? isJetBrainsIde(ideInstallationStatus?.ideType) : false const showIDEInstallErrorOrJetBrainsInfo = ideInstallationStatus?.error || isJetBrains const shouldShowIdeSelection = ideStatus === 'connected' && (ideSelection?.filePath || (ideSelection?.text && ideSelection.lineCount > 0)) // Only show the connected if not showing context const shouldShowConnected = ideStatus === 'connected' && !shouldShowIdeSelection const showIDEInstallError = showIDEInstallErrorOrJetBrainsInfo && !isJetBrains && !shouldShowConnected && !shouldShowIdeSelection const showJetBrainsInfo = showIDEInstallErrorOrJetBrainsInfo && isJetBrains && !shouldShowConnected && !shouldShowIdeSelection // Show the /ide command hint if running from an external terminal and found running IDE(s) // Delay showing hint to avoid brief flash during auto-connect startup useEffect(() => { if (getIsRemoteMode()) return if (isSupportedTerminal() || ideStatus !== null || showJetBrainsInfo) { removeNotification('ide-status-hint') return } // Wait a bit to let auto-connect happen first, avoiding brief hint flash if ( hasShownHintRef.current || (getGlobalConfig().ideHintShownCount ?? 0) >= MAX_IDE_HINT_SHOW_COUNT ) { return } const timeoutId = setTimeout( (hasShownHintRef, addNotification) => { void detectIDEs(true).then(infos => { const ideName = infos[0]?.name if (ideName && !hasShownHintRef.current) { hasShownHintRef.current = true saveGlobalConfig(current => ({ ...current, ideHintShownCount: (current.ideHintShownCount ?? 0) + 1, })) addNotification({ key: 'ide-status-hint', jsx: ( /ide for {ideName} ), priority: 'low', }) } }) }, 3000, hasShownHintRef, addNotification, ) return () => clearTimeout(timeoutId) }, [addNotification, removeNotification, ideStatus, showJetBrainsInfo]) // Show IDE disconnected/failed notification when status is disconnected useEffect(() => { if (getIsRemoteMode()) return if ( showIDEInstallError || showJetBrainsInfo || ideStatus !== 'disconnected' || !ideName ) { removeNotification('ide-status-disconnected') return } addNotification({ key: 'ide-status-disconnected', text: `${ideName} disconnected`, color: 'error', priority: 'medium', }) }, [ addNotification, removeNotification, ideStatus, ideName, showIDEInstallError, showJetBrainsInfo, ]) // Show JetBrains plugin not connected hint useEffect(() => { if (getIsRemoteMode()) return if (!showJetBrainsInfo) { removeNotification('ide-status-jetbrains-disconnected') return } addNotification({ key: 'ide-status-jetbrains-disconnected', text: 'IDE plugin not connected ยท /status for info', priority: 'medium', }) }, [addNotification, removeNotification, showJetBrainsInfo]) // Show IDE install error useEffect(() => { if (getIsRemoteMode()) return if (!showIDEInstallError) { removeNotification('ide-status-install-error') return } addNotification({ key: 'ide-status-install-error', text: 'IDE extension install failed (see /status for info)', color: 'error', priority: 'medium', }) }, [addNotification, removeNotification, showIDEInstallError]) }