@within-7/minto 0.1.5 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (273) hide show
  1. package/dist/commands/agents/AgentsCommand.js +2342 -0
  2. package/dist/commands/agents/AgentsCommand.js.map +7 -0
  3. package/dist/commands/agents/constants.js +58 -0
  4. package/dist/commands/agents/constants.js.map +7 -0
  5. package/dist/commands/agents/index.js +37 -0
  6. package/dist/commands/agents/index.js.map +7 -0
  7. package/dist/commands/agents/types.js +10 -0
  8. package/dist/commands/agents/types.js.map +7 -0
  9. package/dist/commands/agents/utils/fileOperations.js +185 -0
  10. package/dist/commands/agents/utils/fileOperations.js.map +7 -0
  11. package/dist/commands/agents/utils/index.js +21 -0
  12. package/dist/commands/agents/utils/index.js.map +7 -0
  13. package/dist/commands/bug.js +2 -2
  14. package/dist/commands/bug.js.map +2 -2
  15. package/dist/commands/compact.js +5 -5
  16. package/dist/commands/compact.js.map +2 -2
  17. package/dist/commands/ctx_viz.js +55 -22
  18. package/dist/commands/ctx_viz.js.map +2 -2
  19. package/dist/commands/mcp-interactive.js +11 -11
  20. package/dist/commands/mcp-interactive.js.map +2 -2
  21. package/dist/commands/model.js +94 -32
  22. package/dist/commands/model.js.map +3 -3
  23. package/dist/commands/plugin/AddMarketplaceForm.js +49 -21
  24. package/dist/commands/plugin/AddMarketplaceForm.js.map +2 -2
  25. package/dist/commands/plugin/ConfirmDialog.js +38 -26
  26. package/dist/commands/plugin/ConfirmDialog.js.map +2 -2
  27. package/dist/commands/plugin/InstalledPluginsByMarketplace.js +24 -8
  28. package/dist/commands/plugin/InstalledPluginsByMarketplace.js.map +2 -2
  29. package/dist/commands/plugin/InstalledPluginsManager.js +3 -1
  30. package/dist/commands/plugin/InstalledPluginsManager.js.map +2 -2
  31. package/dist/commands/plugin/MainMenu.js +16 -7
  32. package/dist/commands/plugin/MainMenu.js.map +2 -2
  33. package/dist/commands/plugin/MarketplaceManager.js +84 -39
  34. package/dist/commands/plugin/MarketplaceManager.js.map +2 -2
  35. package/dist/commands/plugin/MarketplaceSelector.js +7 -3
  36. package/dist/commands/plugin/MarketplaceSelector.js.map +2 -2
  37. package/dist/commands/plugin/PlaceholderScreen.js +16 -2
  38. package/dist/commands/plugin/PlaceholderScreen.js.map +2 -2
  39. package/dist/commands/plugin/PluginBrowser.js +4 -2
  40. package/dist/commands/plugin/PluginBrowser.js.map +2 -2
  41. package/dist/commands/plugin/PluginDetailsInstall.js +12 -6
  42. package/dist/commands/plugin/PluginDetailsInstall.js.map +2 -2
  43. package/dist/commands/plugin/PluginDetailsManage.js +14 -5
  44. package/dist/commands/plugin/PluginDetailsManage.js.map +2 -2
  45. package/dist/commands/plugin/example-usage.js.map +2 -2
  46. package/dist/commands/plugin/utils.js.map +2 -2
  47. package/dist/commands/plugin.js +226 -46
  48. package/dist/commands/plugin.js.map +2 -2
  49. package/dist/commands/refreshCommands.js +6 -3
  50. package/dist/commands/refreshCommands.js.map +2 -2
  51. package/dist/commands/resume.js +2 -1
  52. package/dist/commands/resume.js.map +2 -2
  53. package/dist/commands/setup.js +19 -5
  54. package/dist/commands/setup.js.map +2 -2
  55. package/dist/commands/terminalSetup.js +2 -2
  56. package/dist/commands/terminalSetup.js.map +1 -1
  57. package/dist/commands.js +14 -30
  58. package/dist/commands.js.map +2 -2
  59. package/dist/components/AskUserQuestionDialog/AskUserQuestionDialog.js.map +2 -2
  60. package/dist/components/AskUserQuestionDialog/QuestionView.js +10 -1
  61. package/dist/components/AskUserQuestionDialog/QuestionView.js.map +2 -2
  62. package/dist/components/BackgroundTasksPanel.js +5 -1
  63. package/dist/components/BackgroundTasksPanel.js.map +2 -2
  64. package/dist/components/Config.js +17 -4
  65. package/dist/components/Config.js.map +2 -2
  66. package/dist/components/ConsoleOAuthFlow.js.map +2 -2
  67. package/dist/components/CustomSelect/select-option.js +4 -1
  68. package/dist/components/CustomSelect/select-option.js.map +2 -2
  69. package/dist/components/Help.js +6 -8
  70. package/dist/components/Help.js.map +2 -2
  71. package/dist/components/Logo.js +1 -1
  72. package/dist/components/Logo.js.map +2 -2
  73. package/dist/components/ModelListManager.js.map +2 -2
  74. package/dist/components/ModelSelector/ModelSelector.js +2030 -0
  75. package/dist/components/ModelSelector/ModelSelector.js.map +7 -0
  76. package/dist/components/ModelSelector/ScreenContainer.js +27 -0
  77. package/dist/components/ModelSelector/ScreenContainer.js.map +7 -0
  78. package/dist/components/ModelSelector/constants.js +37 -0
  79. package/dist/components/ModelSelector/constants.js.map +7 -0
  80. package/dist/components/ModelSelector/hooks/index.js +5 -0
  81. package/dist/components/ModelSelector/hooks/index.js.map +7 -0
  82. package/dist/components/ModelSelector/hooks/useEscapeNavigation.js +21 -0
  83. package/dist/components/ModelSelector/hooks/useEscapeNavigation.js.map +7 -0
  84. package/dist/components/ModelSelector/index.js +17 -0
  85. package/dist/components/ModelSelector/index.js.map +7 -0
  86. package/dist/components/ModelSelector/types.js +1 -0
  87. package/dist/components/ModelSelector/types.js.map +7 -0
  88. package/dist/components/PressEnterToContinue.js +1 -1
  89. package/dist/components/PressEnterToContinue.js.map +2 -2
  90. package/dist/components/ProjectOnboarding.js +1 -1
  91. package/dist/components/ProjectOnboarding.js.map +2 -2
  92. package/dist/components/PromptInput.js +88 -37
  93. package/dist/components/PromptInput.js.map +2 -2
  94. package/dist/components/QuitSummary.js +17 -10
  95. package/dist/components/QuitSummary.js.map +2 -2
  96. package/dist/components/SentryErrorBoundary.js.map +2 -2
  97. package/dist/components/StreamingBashOutput.js.map +2 -2
  98. package/dist/components/StructuredDiff.js.map +2 -2
  99. package/dist/components/SubagentProgress.js.map +2 -2
  100. package/dist/components/TaskCard.js.map +2 -2
  101. package/dist/components/TextInput.js.map +1 -1
  102. package/dist/components/TodoItem.js.map +1 -1
  103. package/dist/components/binary-feedback/BinaryFeedbackOption.js +1 -3
  104. package/dist/components/binary-feedback/BinaryFeedbackOption.js.map +2 -2
  105. package/dist/components/messages/AssistantLocalCommandOutputMessage.js.map +1 -1
  106. package/dist/components/messages/AssistantToolUseMessage.js +3 -1
  107. package/dist/components/messages/AssistantToolUseMessage.js.map +2 -2
  108. package/dist/components/messages/TaskProgressMessage.js.map +2 -2
  109. package/dist/components/messages/TaskToolMessage.js.map +2 -2
  110. package/dist/components/messages/UserToolResultMessage/utils.js.map +2 -2
  111. package/dist/components/permissions/FileEditPermissionRequest/FileEditToolDiff.js.map +2 -2
  112. package/dist/components/permissions/FileWritePermissionRequest/FileWriteToolDiff.js.map +2 -2
  113. package/dist/components/permissions/hooks.js.map +2 -2
  114. package/dist/constants/modelCapabilities.js +1 -1
  115. package/dist/constants/modelCapabilities.js.map +2 -2
  116. package/dist/constants/prompts.js.map +1 -1
  117. package/dist/constants/timing.js +34 -0
  118. package/dist/constants/timing.js.map +7 -0
  119. package/dist/entrypoints/cli.js +128 -33
  120. package/dist/entrypoints/cli.js.map +3 -3
  121. package/dist/entrypoints/mcp.js +13 -18
  122. package/dist/entrypoints/mcp.js.map +2 -2
  123. package/dist/hooks/useCanUseTool.js.map +2 -2
  124. package/dist/hooks/useCancelRequest.js.map +1 -1
  125. package/dist/hooks/useHistorySearch.js.map +2 -2
  126. package/dist/hooks/useLogStartupTime.js.map +2 -2
  127. package/dist/hooks/usePermissionRequestLogging.js.map +2 -2
  128. package/dist/hooks/useTextInput.js.map +1 -1
  129. package/dist/hooks/useUnifiedCompletion.js +493 -394
  130. package/dist/hooks/useUnifiedCompletion.js.map +2 -2
  131. package/dist/index.js.map +2 -2
  132. package/dist/permissions.js +4 -7
  133. package/dist/permissions.js.map +2 -2
  134. package/dist/query.js +6 -1
  135. package/dist/query.js.map +2 -2
  136. package/dist/screens/REPL.js +72 -36
  137. package/dist/screens/REPL.js.map +2 -2
  138. package/dist/screens/ResumeConversation.js +2 -1
  139. package/dist/screens/ResumeConversation.js.map +2 -2
  140. package/dist/services/adapters/base.js.map +2 -2
  141. package/dist/services/adapters/chatCompletions.js.map +2 -2
  142. package/dist/services/adapters/responsesAPI.js +3 -1
  143. package/dist/services/adapters/responsesAPI.js.map +2 -2
  144. package/dist/services/claude.js +327 -328
  145. package/dist/services/claude.js.map +2 -2
  146. package/dist/services/customCommands.js +6 -1
  147. package/dist/services/customCommands.js.map +2 -2
  148. package/dist/services/fileFreshness.js.map +2 -2
  149. package/dist/services/gpt5ConnectionTest.js +20 -7
  150. package/dist/services/gpt5ConnectionTest.js.map +2 -2
  151. package/dist/services/hookExecutor.js +6 -12
  152. package/dist/services/hookExecutor.js.map +2 -2
  153. package/dist/services/mcpClient.js +29 -2
  154. package/dist/services/mcpClient.js.map +2 -2
  155. package/dist/services/mentionProcessor.js +23 -10
  156. package/dist/services/mentionProcessor.js.map +2 -2
  157. package/dist/services/modelAdapterFactory.js.map +2 -2
  158. package/dist/services/oauth.js.map +2 -2
  159. package/dist/services/openai.js +109 -72
  160. package/dist/services/openai.js.map +3 -3
  161. package/dist/services/responseStateManager.js.map +2 -2
  162. package/dist/services/systemReminder.js.map +2 -2
  163. package/dist/tools/ArchitectTool/ArchitectTool.js +10 -9
  164. package/dist/tools/ArchitectTool/ArchitectTool.js.map +2 -2
  165. package/dist/tools/AskExpertModelTool/AskExpertModelTool.js +14 -8
  166. package/dist/tools/AskExpertModelTool/AskExpertModelTool.js.map +2 -2
  167. package/dist/tools/AskUserQuestionTool/AskUserQuestionTool.js +8 -1
  168. package/dist/tools/AskUserQuestionTool/AskUserQuestionTool.js.map +2 -2
  169. package/dist/tools/BashOutputTool/BashOutputTool.js.map +2 -2
  170. package/dist/tools/BashTool/BashTool.js.map +2 -2
  171. package/dist/tools/FileReadTool/FileReadTool.js +23 -4
  172. package/dist/tools/FileReadTool/FileReadTool.js.map +2 -2
  173. package/dist/tools/FileWriteTool/FileWriteTool.js.map +2 -2
  174. package/dist/tools/GlobTool/GlobTool.js +11 -2
  175. package/dist/tools/GlobTool/GlobTool.js.map +2 -2
  176. package/dist/tools/GrepTool/GrepTool.js +7 -5
  177. package/dist/tools/GrepTool/GrepTool.js.map +2 -2
  178. package/dist/tools/MCPTool/MCPTool.js +11 -12
  179. package/dist/tools/MCPTool/MCPTool.js.map +2 -2
  180. package/dist/tools/MultiEditTool/MultiEditTool.js +4 -1
  181. package/dist/tools/MultiEditTool/MultiEditTool.js.map +2 -2
  182. package/dist/tools/NotebookReadTool/NotebookReadTool.js +11 -5
  183. package/dist/tools/NotebookReadTool/NotebookReadTool.js.map +2 -2
  184. package/dist/tools/SkillTool/SkillTool.js +18 -6
  185. package/dist/tools/SkillTool/SkillTool.js.map +2 -2
  186. package/dist/tools/TaskTool/TaskTool.js +37 -51
  187. package/dist/tools/TaskTool/TaskTool.js.map +2 -2
  188. package/dist/tools/TaskTool/prompt.js.map +2 -2
  189. package/dist/tools/ThinkTool/ThinkTool.js +6 -1
  190. package/dist/tools/ThinkTool/ThinkTool.js.map +2 -2
  191. package/dist/tools/TodoWriteTool/TodoWriteTool.js +29 -5
  192. package/dist/tools/TodoWriteTool/TodoWriteTool.js.map +2 -2
  193. package/dist/tools/URLFetcherTool/URLFetcherTool.js +5 -2
  194. package/dist/tools/URLFetcherTool/URLFetcherTool.js.map +2 -2
  195. package/dist/tools/URLFetcherTool/cache.js +6 -3
  196. package/dist/tools/URLFetcherTool/cache.js.map +2 -2
  197. package/dist/tools/URLFetcherTool/htmlToMarkdown.js +3 -1
  198. package/dist/tools/URLFetcherTool/htmlToMarkdown.js.map +2 -2
  199. package/dist/tools/WebSearchTool/WebSearchTool.js +6 -1
  200. package/dist/tools/WebSearchTool/WebSearchTool.js.map +2 -2
  201. package/dist/tools/WebSearchTool/prompt.js.map +2 -2
  202. package/dist/tools/WebSearchTool/searchProviders.js +15 -6
  203. package/dist/tools/WebSearchTool/searchProviders.js.map +2 -2
  204. package/dist/tools.js +4 -1
  205. package/dist/tools.js.map +2 -2
  206. package/dist/types/core.js +1 -0
  207. package/dist/types/core.js.map +7 -0
  208. package/dist/types/hooks.js +1 -4
  209. package/dist/types/hooks.js.map +2 -2
  210. package/dist/types/marketplace.js +8 -2
  211. package/dist/types/marketplace.js.map +2 -2
  212. package/dist/types/plugin.js +9 -6
  213. package/dist/types/plugin.js.map +2 -2
  214. package/dist/utils/BackgroundShellManager.js +76 -10
  215. package/dist/utils/BackgroundShellManager.js.map +2 -2
  216. package/dist/utils/PersistentShell.js +7 -2
  217. package/dist/utils/PersistentShell.js.map +2 -2
  218. package/dist/utils/advancedFuzzyMatcher.js +4 -1
  219. package/dist/utils/advancedFuzzyMatcher.js.map +2 -2
  220. package/dist/utils/agentLoader.js +69 -35
  221. package/dist/utils/agentLoader.js.map +2 -2
  222. package/dist/utils/agentStorage.js.map +2 -2
  223. package/dist/utils/async.js +163 -0
  224. package/dist/utils/async.js.map +7 -0
  225. package/dist/utils/autoUpdater.js +8 -2
  226. package/dist/utils/autoUpdater.js.map +2 -2
  227. package/dist/utils/commands.js +23 -11
  228. package/dist/utils/commands.js.map +2 -2
  229. package/dist/utils/commonUnixCommands.js +3 -1
  230. package/dist/utils/commonUnixCommands.js.map +2 -2
  231. package/dist/utils/compressionMode.js.map +2 -2
  232. package/dist/utils/config.js +30 -14
  233. package/dist/utils/config.js.map +2 -2
  234. package/dist/utils/debugLogger.js.map +2 -2
  235. package/dist/utils/env.js.map +2 -2
  236. package/dist/utils/envConfig.js +82 -0
  237. package/dist/utils/envConfig.js.map +7 -0
  238. package/dist/utils/errorHandling.js +89 -0
  239. package/dist/utils/errorHandling.js.map +7 -0
  240. package/dist/utils/expertChatStorage.js.map +2 -2
  241. package/dist/utils/fuzzyMatcher.js +13 -7
  242. package/dist/utils/fuzzyMatcher.js.map +2 -2
  243. package/dist/utils/hookManager.js +14 -4
  244. package/dist/utils/hookManager.js.map +2 -2
  245. package/dist/utils/log.js.map +2 -2
  246. package/dist/utils/marketplaceManager.js +44 -9
  247. package/dist/utils/marketplaceManager.js.map +2 -2
  248. package/dist/utils/messageContextManager.js.map +1 -1
  249. package/dist/utils/messages.js +6 -3
  250. package/dist/utils/messages.js.map +2 -2
  251. package/dist/utils/model.js +3 -1
  252. package/dist/utils/model.js.map +2 -2
  253. package/dist/utils/pluginInstaller.js +3 -15
  254. package/dist/utils/pluginInstaller.js.map +2 -2
  255. package/dist/utils/pluginLoader.js +41 -13
  256. package/dist/utils/pluginLoader.js.map +2 -2
  257. package/dist/utils/pluginRegistry.js.map +2 -2
  258. package/dist/utils/pluginValidator.js +71 -49
  259. package/dist/utils/pluginValidator.js.map +2 -2
  260. package/dist/utils/ptyCompat.js.map +2 -2
  261. package/dist/utils/roundConverter.js.map +2 -2
  262. package/dist/utils/secureFile.js +43 -14
  263. package/dist/utils/secureFile.js.map +2 -2
  264. package/dist/utils/sessionState.js.map +2 -2
  265. package/dist/utils/skillLoader.js.map +2 -2
  266. package/dist/utils/teamConfig.js +7 -4
  267. package/dist/utils/teamConfig.js.map +2 -2
  268. package/dist/utils/theme.js.map +2 -2
  269. package/dist/utils/thinking.js.map +2 -2
  270. package/dist/utils/unaryLogging.js.map +2 -2
  271. package/dist/version.js +2 -2
  272. package/dist/version.js.map +1 -1
  273. package/package.json +5 -5
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/components/PromptInput.tsx"],
4
- "sourcesContent": ["import { Box, Text, useInput } from 'ink'\nimport { sample } from 'lodash-es'\nimport * as React from 'react'\nimport { type Message } from '@query'\nimport { processUserInput } from '@utils/messages'\nimport { useArrowKeyHistory } from '@hooks/useArrowKeyHistory'\nimport { useUnifiedCompletion } from '@hooks/useUnifiedCompletion'\nimport { useHistorySearch } from '@hooks/useHistorySearch'\nimport { addToHistory, getHistory } from '@history'\nimport TextInput from './TextInput'\nimport { HistorySearchOverlay } from './HistorySearchOverlay'\nimport { memo, useCallback, useEffect, useMemo, useState } from 'react'\nimport { countTokens } from '@utils/tokens'\nimport { SentryErrorBoundary } from './SentryErrorBoundary'\nimport type { Command } from '@commands'\nimport type { SetToolJSXFn, Tool } from '@tool'\nimport { TokenWarning, WARNING_THRESHOLD } from './TokenWarning'\nimport { useTerminalSize } from '@hooks/useTerminalSize'\nimport { getTheme } from '@utils/theme'\nimport { getModelManager, reloadModelManager } from '@utils/model'\nimport { getGlobalConfig, saveGlobalConfig } from '@utils/config'\nimport { setTerminalTitle, clearScreen } from '@utils/terminal'\nimport terminalSetup, {\n isShiftEnterKeyBindingInstalled,\n handleHashCommand,\n} from '@commands/terminalSetup'\nimport { usePermissionContext } from '@context/PermissionContext'\nimport { getHookManager } from '@utils/hookManager'\nimport { debug as debugLogger } from '@utils/debugLogger'\nimport { PROJECT_FILE } from '@constants/product'\n\n// Async function to interpret the '#' command input using AI\nasync function interpretHashCommand(input: string): Promise<string> {\n // Use the AI to interpret the input\n try {\n const { queryQuick } = await import('@services/claude')\n\n // Create a prompt for the model to interpret the hash command\n const systemPrompt = [\n \"You're helping the user structure notes that will be added to their KODING.md file.\",\n \"Format the user's input into a well-structured note that will be useful for later reference.\",\n 'Add appropriate markdown formatting, headings, bullet points, or other structural elements as needed.',\n 'The goal is to transform the raw note into something that will be more useful when reviewed later.',\n 'You should keep the original meaning but make the structure clear.',\n ]\n\n // Send the request to the AI\n const result = await queryQuick({\n systemPrompt,\n userPrompt: `Transform this note for KODING.md: ${input}`,\n })\n\n // Extract the content from the response\n if (typeof result.message.content === 'string') {\n return result.message.content\n } else if (Array.isArray(result.message.content)) {\n return result.message.content\n .filter(block => block.type === 'text')\n .map(block => (block.type === 'text' ? block.text : ''))\n .join('\\n')\n }\n\n return `# ${input}\\n\\n_Added on ${new Date().toLocaleString()}_`\n } catch (e) {\n // If interpretation fails, return the input with minimal formatting\n return `# ${input}\\n\\n_Added on ${new Date().toLocaleString()}_`\n }\n}\n\ntype Props = {\n commands: Command[]\n forkNumber: number\n messageLogName: string\n isDisabled: boolean\n isLoading: boolean\n onQuery: (\n newMessages: Message[],\n abortController?: AbortController,\n ) => Promise<void>\n debug: boolean\n verbose: boolean\n messages: Message[]\n setToolJSX: SetToolJSXFn\n tools: Tool[]\n input: string\n onInputChange: (value: string) => void\n mode: 'bash' | 'prompt' | 'koding'\n onModeChange: (mode: 'bash' | 'prompt' | 'koding') => void\n submitCount: number\n onSubmitCountChange: (updater: (prev: number) => number) => void\n setIsLoading: (isLoading: boolean) => void\n setAbortController: (abortController: AbortController | null) => void\n onShowMessageSelector: () => void\n setForkConvoWithMessagesOnTheNextRender: (\n forkConvoWithMessages: Message[],\n ) => void\n readFileTimestamps: { [filename: string]: number }\n abortController: AbortController | null\n onModelChange?: () => void\n onRollbackConversation?: () => boolean // Phase 4.1: Esc Esc rollback\n onToggleTodoPanel?: () => void // Ctrl+T: Toggle TodoPanel\n onToggleVerbose?: () => void // Ctrl+O: Toggle verbose mode\n onToggleBackgroundPanel?: () => void // View background tasks\n backgroundShellCount?: number // Number of active background shells\n isBackgroundPanelOpen?: boolean // Whether background panel is currently visible\n fallbackMode?: boolean // Whether to use limited input mode (raw mode not supported)\n}\n\nfunction getPastedTextPrompt(text: string): string {\n const newlineCount = (text.match(/\\r\\n|\\r|\\n/g) || []).length\n return `[Pasted text +${newlineCount} lines] `\n}\nfunction PromptInput({\n commands,\n forkNumber,\n messageLogName,\n isDisabled,\n isLoading,\n onQuery,\n debug,\n verbose,\n messages,\n setToolJSX,\n tools,\n input,\n onInputChange,\n mode,\n onModeChange,\n submitCount,\n onSubmitCountChange,\n setIsLoading,\n fallbackMode = false,\n abortController,\n setAbortController,\n onShowMessageSelector,\n setForkConvoWithMessagesOnTheNextRender,\n readFileTimestamps,\n onToggleTodoPanel,\n onToggleVerbose,\n onModelChange,\n onRollbackConversation,\n onToggleBackgroundPanel,\n backgroundShellCount = 0,\n isBackgroundPanelOpen = false,\n}: Props): React.ReactNode {\n const [exitMessage, setExitMessage] = useState<{\n show: boolean\n key?: string\n }>({ show: false })\n const [message, setMessage] = useState<{ show: boolean; text?: string }>({\n show: false,\n })\n const [modelSwitchMessage, setModelSwitchMessage] = useState<{\n show: boolean\n text?: string\n }>({\n show: false,\n })\n const [pastedImage, setPastedImage] = useState<string | null>(null)\n const [placeholder, setPlaceholder] = useState('')\n const [cursorOffset, setCursorOffset] = useState<number>(input.length)\n const [pastedText, setPastedText] = useState<string | null>(null)\n\n // Ctrl-D double-tap tracking\n const [ctrlDCount, setCtrlDCount] = useState(0)\n const [ctrlDTimer, setCtrlDTimer] = useState<NodeJS.Timeout | null>(null)\n\n // Phase 4.1: Esc double-tap tracking for conversation rollback\n const [escCount, setEscCount] = useState(0)\n const [escTimer, setEscTimer] = useState<NodeJS.Timeout | null>(null)\n\n // Hotkey feedback messages (for Ctrl-C, Ctrl-L, Ctrl-O)\n const [hotkeyMessage, setHotkeyMessage] = useState<{\n show: boolean\n text?: string\n }>({ show: false })\n\n // Background task indicator focus state\n const [backgroundIndicatorFocused, setBackgroundIndicatorFocused] = useState(false)\n\n // Permission context for mode management\n const { cycleMode, currentMode } = usePermissionContext()\n\n // useEffect(() => {\n // getExampleCommands().then(commands => {\n // setPlaceholder(`Try \"${sample(commands)}\"`)\n // })\n // }, [])\n const { columns } = useTerminalSize()\n\n const commandWidth = useMemo(\n () => Math.max(...commands.map(cmd => cmd.userFacingName().length)) + 5,\n [commands],\n )\n\n // Unified completion system - one hook to rule them all (now with terminal behavior)\n const {\n suggestions,\n selectedIndex,\n isActive: completionActive,\n emptyDirMessage,\n } = useUnifiedCompletion({\n input,\n cursorOffset,\n onInputChange,\n setCursorOffset,\n commands,\n onSubmit,\n })\n\n // Phase 3: History search with Ctrl-R\n const history = useMemo(() => getHistory(), [submitCount]) // Refresh on submit\n const historySearch = useHistorySearch(history)\n\n // Get theme early for memoized rendering\n const theme = getTheme()\n\n // Visible window size for suggestions - show limited items with scrolling\n const MAX_VISIBLE_SUGGESTIONS = 8\n\n // Calculate visible window for suggestions (pagination logic)\n const visibleSuggestions = useMemo(() => {\n if (suggestions.length === 0) return []\n\n // If all suggestions fit in window, show them all\n if (suggestions.length <= MAX_VISIBLE_SUGGESTIONS) {\n return suggestions.map((s, i) => ({ ...s, globalIndex: i }))\n }\n\n // Calculate scroll window to keep selected item visible\n const halfWindow = Math.floor(MAX_VISIBLE_SUGGESTIONS / 2)\n let startIndex = Math.max(0, selectedIndex - halfWindow)\n let endIndex = startIndex + MAX_VISIBLE_SUGGESTIONS\n\n // Adjust if we're near the end\n if (endIndex > suggestions.length) {\n endIndex = suggestions.length\n startIndex = Math.max(0, endIndex - MAX_VISIBLE_SUGGESTIONS)\n }\n\n return suggestions\n .slice(startIndex, endIndex)\n .map((s, i) => ({ ...s, globalIndex: startIndex + i }))\n }, [suggestions, selectedIndex])\n\n // Memoized completion suggestions rendering - with scroll indicators\n const renderedSuggestions = useMemo(() => {\n if (suggestions.length === 0) return null\n\n const hasMoreAbove = visibleSuggestions.length > 0 && visibleSuggestions[0].globalIndex > 0\n const hasMoreBelow = visibleSuggestions.length > 0 &&\n visibleSuggestions[visibleSuggestions.length - 1].globalIndex < suggestions.length - 1\n\n return (\n <>\n {hasMoreAbove && (\n <Box>\n <Text dimColor> \u2191 {visibleSuggestions[0].globalIndex} more above...</Text>\n </Box>\n )}\n {visibleSuggestions.map((suggestion) => {\n const isSelected = suggestion.globalIndex === selectedIndex\n const isAgent = suggestion.type === 'agent'\n\n // Simple color logic without complex lookups\n const displayColor = isSelected\n ? theme.suggestion\n : (isAgent && suggestion.metadata?.color)\n ? suggestion.metadata.color\n : undefined\n\n return (\n <Box key={`${suggestion.type}-${suggestion.value}-${suggestion.globalIndex}`} flexDirection=\"row\">\n <Text\n color={displayColor}\n dimColor={!isSelected && !displayColor}\n >\n {isSelected ? '\u25C6 ' : ' '}\n {suggestion.displayValue}\n </Text>\n </Box>\n )\n })}\n {hasMoreBelow && (\n <Box>\n <Text dimColor> \u2193 {suggestions.length - visibleSuggestions[visibleSuggestions.length - 1].globalIndex - 1} more below...</Text>\n </Box>\n )}\n </>\n )\n }, [suggestions, selectedIndex, visibleSuggestions, theme.suggestion])\n\n const onChange = useCallback(\n (value: string) => {\n if (value.startsWith('!')) {\n onModeChange('bash')\n return\n }\n if (value.startsWith('#')) {\n onModeChange('koding')\n return\n }\n onInputChange(value)\n },\n [onModeChange, onInputChange],\n )\n\n // Handle Shift+M model switching with enhanced debugging\n const handleQuickModelSwitch = useCallback(async () => {\n const modelManager = getModelManager()\n const currentTokens = countTokens(messages)\n\n // Get debug info for better error reporting\n const debugInfo = modelManager.getModelSwitchingDebugInfo()\n \n const switchResult = modelManager.switchToNextModel(currentTokens)\n\n if (switchResult.success && switchResult.modelName) {\n // Successful switch - use enhanced message from model manager\n onSubmitCountChange(prev => prev + 1)\n setModelSwitchMessage({\n show: true,\n text: switchResult.message || `\u2705 Switched to ${switchResult.modelName}`,\n })\n setTimeout(() => setModelSwitchMessage({ show: false }), 3000)\n } else if (switchResult.blocked && switchResult.message) {\n // Context overflow - show detailed message\n setModelSwitchMessage({\n show: true,\n text: switchResult.message,\n })\n setTimeout(() => setModelSwitchMessage({ show: false }), 5000)\n } else {\n // Enhanced error reporting with debug info \n let errorMessage = switchResult.message\n \n if (!errorMessage) {\n if (debugInfo.totalModels === 0) {\n errorMessage = '\u274C No models configured. Use /model to add models.'\n } else if (debugInfo.activeModels === 0) {\n errorMessage = `\u274C No active models (${debugInfo.totalModels} total, all inactive). Use /model to activate models.`\n } else if (debugInfo.activeModels === 1) {\n // Show ALL models including inactive ones for debugging\n const allModelNames = debugInfo.availableModels.map(m => `${m.name}${m.isActive ? '' : ' (inactive)'}`).join(', ')\n errorMessage = `\u26A0\uFE0F Only 1 active model out of ${debugInfo.totalModels} total models: ${allModelNames}. ALL configured models will be activated for switching.`\n } else {\n errorMessage = `\u274C Model switching failed (${debugInfo.activeModels} active, ${debugInfo.totalModels} total models available)`\n }\n }\n \n setModelSwitchMessage({\n show: true,\n text: errorMessage,\n })\n setTimeout(() => setModelSwitchMessage({ show: false }), 6000)\n }\n }, [onSubmitCountChange, messages])\n\n const { resetHistory, onHistoryUp, onHistoryDown } = useArrowKeyHistory(\n (value: string, mode: 'bash' | 'prompt' | 'koding') => {\n onChange(value)\n onModeChange(mode)\n },\n input,\n )\n\n // Only use history navigation when there are no suggestions\n const handleHistoryUp = () => {\n if (!completionActive) {\n onHistoryUp()\n }\n }\n\n const handleHistoryDown = () => {\n if (!completionActive) {\n onHistoryDown()\n }\n }\n\n async function onSubmit(input: string, isSubmittingSlashCommand = false) {\n // UserPromptSubmit hook\n const hookManager = getHookManager()\n if (hookManager && input && input.trim()) {\n try {\n const decision = await hookManager.executeUserPromptSubmit(input)\n\n if (!decision.shouldContinue) {\n if (decision.shouldAskUser) {\n // Show confirmation to user (simplified - in real UI might show dialog)\n const confirmed = confirm(\n decision.reason || 'Hook requested approval. Continue?'\n )\n if (!confirmed) {\n return // Don't submit\n }\n } else {\n // Blocked by hook\n setMessage({ show: true, text: decision.reason || 'Blocked by hook' })\n setTimeout(() => setMessage({ show: false }), 3000)\n return\n }\n }\n } catch (err) {\n debugLogger.error('UserPromptSubmit hook failed', { error: err })\n // Continue on error (fail-safe)\n }\n }\n\n // Special handling for \"put a verbose summary\" and similar action prompts in koding mode\n if (\n (mode === 'koding' || input.startsWith('#')) &&\n input.match(/^(#\\s*)?(put|create|generate|write|give|provide)/i)\n ) {\n try {\n // Store the original input for history\n const originalInput = input\n\n // Strip the # prefix if present\n const cleanInput = mode === 'koding' ? input : input.substring(1).trim()\n\n // Add to history and clear input field\n addToHistory(mode === 'koding' ? `#${input}` : input)\n onInputChange('')\n\n // Create additional context to inform the assistant this is for KODING.md\n const kodingContext =\n `The user is using Koding mode. Format your response as a comprehensive, well-structured document suitable for adding to ${PROJECT_FILE}. Use proper markdown formatting with headings, lists, code blocks, etc. The response should be complete and ready to add to ${PROJECT_FILE} documentation.`\n\n // Switch to prompt mode but tag the submission for later capture\n onModeChange('prompt')\n\n // \uD83D\uDD27 Fix Koding mode: clean up previous state\n if (abortController) {\n abortController.abort()\n }\n setIsLoading(false)\n await new Promise(resolve => setTimeout(resolve, 0))\n\n // Set loading state - AbortController now created in onQuery\n setIsLoading(true)\n\n // Process as a normal user input but with special handling\n const messages = await processUserInput(\n cleanInput,\n 'prompt', // Use prompt mode for processing\n setToolJSX,\n {\n options: {\n commands,\n forkNumber,\n messageLogName,\n tools,\n verbose,\n maxThinkingTokens: 0,\n // Add context flag for koding mode\n isKodingRequest: true,\n kodingContext,\n },\n messageId: undefined,\n abortController: abortController || new AbortController(), // Temporary controller, actual one created in onQuery\n readFileTimestamps,\n setForkConvoWithMessagesOnTheNextRender,\n },\n pastedImage ?? null,\n )\n\n // Send query and capture response\n if (messages.length) {\n await onQuery(messages)\n\n // After query completes, the last message should be the assistant's response\n // We'll set up a one-time listener to capture and save that response\n // This will be handled by the REPL component or message handler\n }\n\n return\n } catch (e) {\n // If something fails, log the error\n console.error('Error processing Koding request:', e)\n }\n }\n\n // If in koding mode or input starts with '#', interpret it using AI before appending to MINTO.md\n else if (mode === 'koding' || input.startsWith('#')) {\n try {\n // Strip the # if we're in koding mode and the user didn't type it (since it's implied)\n const contentToInterpret =\n mode === 'koding' && !input.startsWith('#')\n ? input.trim()\n : input.substring(1).trim()\n\n const interpreted = await interpretHashCommand(contentToInterpret)\n handleHashCommand(interpreted)\n } catch (e) {\n // If interpretation fails, log the error\n }\n onInputChange('')\n addToHistory(mode === 'koding' ? `#${input}` : input)\n onModeChange('prompt')\n return\n }\n if (input === '') {\n return\n }\n if (isDisabled) {\n return\n }\n if (isLoading) {\n return\n }\n \n // Handle Enter key when completions are active\n // If there are suggestions showing, Enter should complete the selection, not send the message\n if (suggestions.length > 0 && completionActive) {\n // The completion is handled by useUnifiedCompletion hook\n // Just return to prevent message sending\n return\n }\n\n // Handle exit commands\n if (['exit', 'quit', ':q', ':q!', ':wq', ':wq!'].includes(input.trim())) {\n exit()\n }\n\n let finalInput = input\n if (pastedText) {\n // Create the prompt pattern that would have been used for this pasted text\n const pastedPrompt = getPastedTextPrompt(pastedText)\n if (finalInput.includes(pastedPrompt)) {\n finalInput = finalInput.replace(pastedPrompt, pastedText)\n } // otherwise, ignore the pastedText if the user has modified the prompt\n }\n onInputChange('')\n onModeChange('prompt')\n // Suggestions are now handled by unified completion\n setPastedImage(null)\n setPastedText(null)\n onSubmitCountChange(_ => _ + 1)\n\n setIsLoading(true)\n \n const newAbortController = new AbortController()\n setAbortController(newAbortController)\n\n const messages = await processUserInput(\n finalInput,\n mode,\n setToolJSX,\n {\n options: {\n commands,\n forkNumber,\n messageLogName,\n tools,\n verbose,\n maxThinkingTokens: 0,\n },\n messageId: undefined,\n abortController: newAbortController,\n readFileTimestamps,\n setForkConvoWithMessagesOnTheNextRender,\n },\n pastedImage ?? null,\n )\n\n if (messages.length) {\n onQuery(messages, newAbortController)\n } else {\n // Local JSX commands\n addToHistory(input)\n resetHistory()\n return\n }\n\n for (const message of messages) {\n if (message.type === 'user') {\n const inputToAdd = mode === 'bash' ? `!${input}` : input\n addToHistory(inputToAdd)\n resetHistory()\n }\n }\n }\n\n function onImagePaste(image: string) {\n onModeChange('prompt')\n setPastedImage(image)\n }\n\n function onTextPaste(rawText: string) {\n // Replace any \\r with \\n first to match useTextInput's conversion behavior\n const text = rawText.replace(/\\r/g, '\\n')\n\n // Get prompt with newline count\n const pastedPrompt = getPastedTextPrompt(text)\n\n // Update the input with a visual indicator that text has been pasted\n const newInput =\n input.slice(0, cursorOffset) + pastedPrompt + input.slice(cursorOffset)\n onInputChange(newInput)\n\n // Update cursor position to be after the inserted indicator\n setCursorOffset(cursorOffset + pastedPrompt.length)\n\n // Still set the pastedText state for actual submission\n setPastedText(text)\n }\n\n // IMPORTANT: useInput must be called unconditionally (React Hook rule)\n // In fallback mode, we provide an empty handler to satisfy the Hook requirement\n useInput(\n fallbackMode\n ? () => {} // Fallback mode: no-op handler\n : (inputChar, key) => {\n // ========== NORMAL MODE: Full interactive input handling ==========\n // ========== NEW HOTKEYS (Phase 1) ==========\n\n // Ctrl-C: Enhanced cancel/interrupt\n if (key.ctrl && inputChar === 'c') {\n if (isLoading) {\n // Cancel ongoing request\n if (abortController && !abortController.signal.aborted) {\n abortController.abort()\n }\n setIsLoading(false)\n setHotkeyMessage({ show: true, text: 'Interrupted by user (Ctrl-C)' })\n setTimeout(() => setHotkeyMessage({ show: false }), 2000)\n } else if (input.length > 0) {\n // Clear input\n onInputChange('')\n setHotkeyMessage({ show: true, text: 'Input cleared' })\n setTimeout(() => setHotkeyMessage({ show: false }), 1000)\n } else {\n // Hint for exit (optional: could implement double Ctrl-C to exit)\n setHotkeyMessage({ show: true, text: 'Press Ctrl-D to exit' })\n setTimeout(() => setHotkeyMessage({ show: false }), 2000)\n }\n return true\n }\n\n // Ctrl-D: Graceful EOF exit (double-tap safety)\n if (key.ctrl && inputChar === 'd') {\n if (input.length > 0) {\n // If there's input, just clear it\n onInputChange('')\n setHotkeyMessage({ show: true, text: 'Input cleared (Ctrl-D)' })\n setTimeout(() => setHotkeyMessage({ show: false }), 1000)\n return true\n }\n\n // Empty input: increment Ctrl-D count for double-tap safety\n setCtrlDCount(prev => prev + 1)\n\n if (ctrlDTimer) clearTimeout(ctrlDTimer)\n const timer = setTimeout(() => setCtrlDCount(0), 1000)\n setCtrlDTimer(timer)\n\n if (ctrlDCount >= 1) {\n // Second Ctrl-D: graceful exit\n setHotkeyMessage({ show: true, text: 'Exiting gracefully...' })\n setTimeout(() => exit(), 500)\n } else {\n // First Ctrl-D: show hint\n setHotkeyMessage({ show: true, text: 'Press Ctrl-D again to exit' })\n setTimeout(() => setHotkeyMessage({ show: false }), 2000)\n }\n\n return true\n }\n\n // Ctrl-L: Clear screen\n if (key.ctrl && inputChar === 'l') {\n clearScreen()\n setHotkeyMessage({ show: true, text: 'Screen cleared (Ctrl-L)' })\n setTimeout(() => setHotkeyMessage({ show: false }), 1000)\n return true\n }\n\n // Ctrl-O: Toggle verbose mode\n if (key.ctrl && inputChar === 'o') {\n const config = getGlobalConfig()\n const newVerbose = !verbose\n\n // Update global config\n saveGlobalConfig({\n ...config,\n verbose: newVerbose,\n })\n\n // Show feedback\n setHotkeyMessage({\n show: true,\n text: `Verbose mode ${newVerbose ? 'enabled' : 'disabled'} (Ctrl-O)`,\n })\n setTimeout(() => setHotkeyMessage({ show: false }), 2000)\n\n // Notify parent component to update verbose state\n if (onToggleVerbose) {\n onToggleVerbose()\n }\n\n return true\n }\n\n // Ctrl+T: Toggle TodoPanel visibility\n if (key.ctrl && inputChar === 't') {\n if (onToggleTodoPanel) {\n onToggleTodoPanel()\n setHotkeyMessage({\n show: true,\n text: 'TodoPanel toggled (Ctrl-T)',\n })\n setTimeout(() => setHotkeyMessage({ show: false }), 2000)\n }\n return true\n }\n\n // Phase 4.3: Ctrl-B: Quick bash command execution\n // Note: Moving to background is handled by StreamingBashOutput component\n if (key.ctrl && inputChar === 'b') {\n if (!input || input.trim().length === 0) {\n setHotkeyMessage({\n show: true,\n text: 'Type a command first, then press Ctrl-B',\n })\n setTimeout(() => setHotkeyMessage({ show: false }), 2000)\n return true\n }\n\n // If already in bash mode (starts with !), just submit\n if (mode === 'bash') {\n setHotkeyMessage({\n show: true,\n text: 'Executing bash command... (Ctrl-B)',\n })\n setTimeout(() => setHotkeyMessage({ show: false }), 1000)\n // Let it submit normally via Enter handling\n onSubmit(input)\n return true\n }\n\n // Otherwise, convert to bash command and submit\n const bashCommand = `!${input}`\n setHotkeyMessage({\n show: true,\n text: 'Executing bash command... (Ctrl-B)',\n })\n setTimeout(() => setHotkeyMessage({ show: false }), 1000)\n\n // Submit as bash command\n onSubmit(bashCommand)\n return true\n }\n\n // Phase 3: Ctrl-R: Reverse history search\n if (key.ctrl && inputChar === 'r') {\n if (!historySearch.isActive) {\n // Activate history search\n historySearch.activate()\n return true\n }\n // If already active, cycle to next match (move up in history)\n historySearch.moveUp()\n return true\n }\n\n // History search mode: handle special keys\n if (historySearch.isActive) {\n // Esc: Cancel search\n if (key.escape) {\n historySearch.reset()\n return true\n }\n\n // Enter: Select current item and exit search\n if (key.return) {\n if (historySearch.selectedItem) {\n onInputChange(historySearch.selectedItem)\n }\n historySearch.reset()\n return true\n }\n\n // Up/Down: Navigate through results\n if (key.upArrow) {\n historySearch.moveUp()\n return true\n }\n if (key.downArrow) {\n historySearch.moveDown()\n return true\n }\n\n // Any other character: Update search term\n if (inputChar && !key.ctrl && !key.meta) {\n historySearch.setSearchTerm(historySearch.searchTerm + inputChar)\n return true\n }\n\n // Backspace: Remove character from search\n if (key.backspace || key.delete) {\n if (historySearch.searchTerm.length > 0) {\n historySearch.setSearchTerm(\n historySearch.searchTerm.slice(0, -1),\n )\n } else {\n // No search term, cancel search\n historySearch.reset()\n }\n return true\n }\n }\n\n // Background task indicator navigation\n if (backgroundIndicatorFocused) {\n // Up arrow: return focus to input\n if (key.upArrow) {\n setBackgroundIndicatorFocused(false)\n return true\n }\n\n // Enter: open background tasks panel\n if (key.return) {\n if (onToggleBackgroundPanel) {\n onToggleBackgroundPanel()\n }\n setBackgroundIndicatorFocused(false)\n return true\n }\n\n // Esc: unfocus indicator\n if (key.escape) {\n setBackgroundIndicatorFocused(false)\n return true\n }\n\n return true // Consume all other input when indicator is focused\n }\n\n // Down arrow when input is active: focus background indicator if it exists\n if (key.downArrow && backgroundShellCount > 0 && !completionActive) {\n setBackgroundIndicatorFocused(true)\n return true\n }\n\n // ========== EXISTING HOTKEYS ==========\n\n // For bash mode, only exit when deleting the last character (which would be the '!' character)\n if (mode === 'bash' && (key.backspace || key.delete)) {\n // Check the current input state, not the inputChar parameter\n // If current input is empty, we're about to delete the '!' character, so exit bash mode\n if (input === '') {\n onModeChange('prompt')\n }\n return\n }\n\n // For koding mode, only exit when deleting the last character (which would be the '#' character)\n if (mode === 'koding' && (key.backspace || key.delete)) {\n // Check the current input state, not the inputChar parameter\n // If current input is empty, we're about to delete the '#' character, so exit koding mode\n if (input === '') {\n onModeChange('prompt')\n }\n return\n }\n\n // For other modes, keep the original behavior\n if (inputChar === '' && (key.escape || key.backspace || key.delete)) {\n onModeChange('prompt')\n }\n\n // Phase 4.1: Esc Esc double-press for conversation rollback\n if (key.escape && !input && !isLoading && messages.length > 0 && onRollbackConversation) {\n // Increment Esc count for double-tap detection\n setEscCount(prev => prev + 1)\n\n if (escTimer) clearTimeout(escTimer)\n const timer = setTimeout(() => setEscCount(0), 1000)\n setEscTimer(timer)\n\n if (escCount >= 1) {\n // Second Esc: rollback conversation\n const success = onRollbackConversation()\n if (success) {\n setMessage({ show: true, text: 'Conversation rolled back (Esc Esc)' })\n setTimeout(() => setMessage({ show: false }), 2000)\n } else {\n setMessage({ show: true, text: 'No history to rollback' })\n setTimeout(() => setMessage({ show: false }), 2000)\n }\n setEscCount(0) // Reset after action\n return true\n } else {\n // First Esc: show hint (only if message selector won't be shown)\n setMessage({ show: true, text: 'Press Esc again to rollback conversation' })\n setTimeout(() => setMessage({ show: false }), 2000)\n return true\n }\n }\n\n // esc is a little overloaded:\n // - when we're loading a response, it's used to cancel the request\n // - otherwise, it's used to show the message selector\n // - when double pressed, it's used to clear the input\n if (key.escape && messages.length > 0 && !input && !isLoading) {\n onShowMessageSelector()\n }\n\n // Tab (without Shift) for thinking mode toggle (Phase 4.2)\n // Only when completion is NOT active\n if (key.tab && !key.shift && !completionActive) {\n const config = getGlobalConfig()\n const newThinking = !config.thinking\n\n // Update global config\n saveGlobalConfig({\n ...config,\n thinking: newThinking,\n })\n\n // Show feedback\n setMessage({\n show: true,\n text: `Thinking mode ${newThinking ? 'enabled' : 'disabled'} (Tab)`,\n })\n setTimeout(() => setMessage({ show: false }), 2000)\n\n return true // Explicitly handled\n }\n\n // Shift+Tab for mode cycling (retains legacy keyboard behavior)\n if (key.shift && key.tab) {\n cycleMode()\n return true // Explicitly handled\n }\n\n return false // Not handled, allow other hooks\n },\n { isActive: !isBackgroundPanelOpen && !fallbackMode },\n )\n\n // Handle special key combinations before character input\n const handleSpecialKey = useCallback((inputChar: string, key: any): boolean => {\n // Shift+M for model switching - intercept before character input\n if (key.shift && (inputChar === 'M' || inputChar === 'm')) {\n handleQuickModelSwitch()\n return true // Prevent character from being input\n }\n \n return false // Not handled, allow normal processing\n }, [handleQuickModelSwitch])\n\n const textInputColumns = useTerminalSize().columns - 6\n const tokenUsage = useMemo(() => countTokens(messages), [messages])\n\n // \uD83D\uDD27 Fix: Track model ID changes to detect external config updates\n const modelManager = getModelManager()\n const currentModelId = (modelManager.getModel('main') as any)?.id || null\n\n const modelInfo = useMemo(() => {\n // Force fresh ModelManager instance to detect config changes\n const freshModelManager = getModelManager()\n const currentModel = freshModelManager.getModel('main')\n if (!currentModel) {\n return null\n }\n\n return {\n name: currentModel.modelName, // \uD83D\uDD27 Fix: Use actual model name, not display name\n id: (currentModel as any).id, // \u6DFB\u52A0\u6A21\u578BID\u7528\u4E8E\u8C03\u8BD5\n provider: currentModel.provider, // \u6DFB\u52A0\u63D0\u4F9B\u5546\u4FE1\u606F\n contextLength: currentModel.contextLength,\n currentTokens: tokenUsage,\n }\n }, [tokenUsage, modelSwitchMessage.show, submitCount, currentModelId]) // Track model ID to detect config changes\n\n return (\n <Box flexDirection=\"column\">\n {/* Fallback mode warning */}\n {fallbackMode && (\n <Box marginBottom={1}>\n <Text color=\"yellow\">\u26A0\uFE0F Limited input mode</Text>\n <Text dimColor>\n {' '}\n (Advanced keyboard shortcuts unavailable - raw mode not supported)\n </Text>\n </Box>\n )}\n\n {/* Phase 3: History search overlay */}\n {historySearch.isActive && (\n <HistorySearchOverlay\n searchTerm={historySearch.searchTerm}\n results={historySearch.filteredResults}\n selectedIndex={historySearch.selectedIndex}\n />\n )}\n\n {/* Model info in top-right corner */}\n {modelInfo && (\n <Box justifyContent=\"flex-end\" marginBottom={1}>\n <Text dimColor>\n [{modelInfo.provider}] {modelInfo.name}:{' '}\n {Math.round(modelInfo.currentTokens / 1000)}k /{' '}\n {Math.round(modelInfo.contextLength / 1000)}k\n </Text>\n </Box>\n )}\n\n <Box\n alignItems=\"flex-start\"\n justifyContent=\"flex-start\"\n borderColor={\n mode === 'bash'\n ? theme.bashBorder\n : mode === 'koding'\n ? theme.noting\n : theme.secondaryBorder\n }\n borderDimColor\n borderStyle=\"round\"\n marginTop={1}\n width=\"100%\"\n >\n <Box\n alignItems=\"flex-start\"\n alignSelf=\"flex-start\"\n flexWrap=\"nowrap\"\n justifyContent=\"flex-start\"\n width={3}\n >\n {mode === 'bash' ? (\n <Text color={theme.bashBorder}>&nbsp;!&nbsp;</Text>\n ) : mode === 'koding' ? (\n <Text color={theme.noting}>&nbsp;#&nbsp;</Text>\n ) : (\n <Text color={isLoading ? theme.secondaryText : undefined}>\n &nbsp;&gt;&nbsp;\n </Text>\n )}\n </Box>\n <Box paddingRight={1}>\n <TextInput\n multiline\n focus={!isBackgroundPanelOpen}\n onSubmit={onSubmit}\n onChange={onChange}\n value={input}\n onHistoryUp={handleHistoryUp}\n onHistoryDown={handleHistoryDown}\n onHistoryReset={() => resetHistory()}\n placeholder={submitCount > 0 ? undefined : placeholder}\n onExit={() => process.exit(0)}\n onExitMessage={(show, key) => setExitMessage({ show, key })}\n onMessage={(show, text) => setMessage({ show, text })}\n onImagePaste={onImagePaste}\n columns={textInputColumns}\n isDimmed={isDisabled || isLoading}\n disableCursorMovementForUpDownKeys={completionActive}\n cursorOffset={cursorOffset}\n onChangeCursorOffset={setCursorOffset}\n onPaste={onTextPaste}\n onSpecialKey={handleSpecialKey}\n />\n </Box>\n </Box>\n {!completionActive && suggestions.length === 0 && (\n <Box\n flexDirection=\"row\"\n justifyContent=\"space-between\"\n paddingX={2}\n paddingY={0}\n >\n <Box justifyContent=\"flex-start\" gap={1}>\n {exitMessage.show ? (\n <Text dimColor>Press {exitMessage.key} again to exit</Text>\n ) : message.show ? (\n <Text dimColor>{message.text}</Text>\n ) : hotkeyMessage.show ? (\n <Text color={theme.success}>{hotkeyMessage.text}</Text>\n ) : modelSwitchMessage.show ? (\n <Text color={theme.success}>{modelSwitchMessage.text}</Text>\n ) : (\n <>\n <Text\n color={mode === 'bash' ? theme.bashBorder : undefined}\n dimColor={mode !== 'bash'}\n >\n ! for bash mode\n </Text>\n <Text\n color={mode === 'koding' ? theme.noting : undefined}\n dimColor={mode !== 'koding'}\n >\n \u00B7 # for {PROJECT_FILE}\n </Text>\n <Text dimColor>\n \u00B7 / for commands \u00B7 ctrl+c cancel \u00B7 ctrl+l clear\n </Text>\n {backgroundShellCount > 0 && (\n <Text\n color={backgroundIndicatorFocused ? theme.primary : theme.success}\n backgroundColor={backgroundIndicatorFocused ? theme.success : undefined}\n dimColor={!backgroundIndicatorFocused}\n >\n \u00B7 {backgroundIndicatorFocused ? '\u25BA ' : ''}{backgroundShellCount} background task{backgroundShellCount > 1 ? 's' : ''}\n </Text>\n )}\n </>\n )}\n </Box>\n <SentryErrorBoundary children={\n <Box justifyContent=\"flex-end\" gap={1}>\n {!debug &&\n tokenUsage < WARNING_THRESHOLD && (\n <Text dimColor>\n {terminalSetup.isEnabled &&\n isShiftEnterKeyBindingInstalled()\n ? 'shift + \u23CE for newline'\n : '\\\\\u23CE for newline'}\n </Text>\n )}\n <TokenWarning tokenUsage={tokenUsage} />\n </Box>\n } />\n </Box>\n )}\n\n {/* Unified completion suggestions - optimized rendering */}\n {suggestions.length > 0 && (\n <Box\n flexDirection=\"row\"\n justifyContent=\"space-between\"\n paddingX={2}\n paddingY={0}\n >\n <Box flexDirection=\"column\">\n {renderedSuggestions}\n \n {/* \u7B80\u6D01\u64CD\u4F5C\u63D0\u793A\u6846 - \u5305\u542B\u5217\u8868\u4F4D\u7F6E\u4FE1\u606F */}\n <Box marginTop={1} paddingX={3} borderStyle=\"round\" borderColor=\"gray\">\n <Text dimColor={!emptyDirMessage} color={emptyDirMessage ? \"yellow\" : undefined}>\n {emptyDirMessage || (() => {\n const selected = suggestions[selectedIndex]\n const positionInfo = suggestions.length > 1 ? `[${selectedIndex + 1}/${suggestions.length}] ` : ''\n\n if (!selected) {\n return `${positionInfo}\u2191\u2193 navigate \u2022 \u2192 accept \u2022 Tab cycle \u2022 Esc close`\n }\n if (selected?.value.endsWith('/')) {\n return `${positionInfo}\u2192 enter directory \u2022 \u2191\u2193 navigate \u2022 Tab cycle \u2022 Esc close`\n } else if (selected?.type === 'agent') {\n return `${positionInfo}\u2192 select agent \u2022 \u2191\u2193 navigate \u2022 Tab cycle \u2022 Esc close`\n } else {\n return `${positionInfo}\u2192 insert reference \u2022 \u2191\u2193 navigate \u2022 Tab cycle \u2022 Esc close`\n }\n })()}\n </Text>\n </Box>\n </Box>\n <SentryErrorBoundary children={\n <Box justifyContent=\"flex-end\" gap={1}>\n <TokenWarning tokenUsage={countTokens(messages)} />\n </Box>\n } />\n </Box>\n )}\n </Box>\n )\n}\n\nexport default memo(PromptInput)\n\nfunction exit(): never {\n setTerminalTitle('')\n process.exit(0)\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { Box, Text, useInput } from 'ink'\nimport { sample } from 'lodash-es'\nimport * as React from 'react'\nimport { type Message } from '@query'\nimport { processUserInput } from '@utils/messages'\nimport { useArrowKeyHistory } from '@hooks/useArrowKeyHistory'\nimport { useUnifiedCompletion } from '@hooks/useUnifiedCompletion'\nimport { useHistorySearch } from '@hooks/useHistorySearch'\nimport { addToHistory, getHistory } from '@history'\nimport TextInput from './TextInput'\nimport { HistorySearchOverlay } from './HistorySearchOverlay'\nimport { memo, useCallback, useEffect, useMemo, useState } from 'react'\nimport { countTokens } from '@utils/tokens'\nimport { SentryErrorBoundary } from './SentryErrorBoundary'\nimport type { Command } from '@commands'\nimport type { SetToolJSXFn, Tool } from '@tool'\nimport { TokenWarning, WARNING_THRESHOLD } from './TokenWarning'\nimport { useTerminalSize } from '@hooks/useTerminalSize'\nimport { getTheme } from '@utils/theme'\nimport { getModelManager, reloadModelManager } from '@utils/model'\nimport { getGlobalConfig, saveGlobalConfig } from '@utils/config'\nimport { setTerminalTitle, clearScreen } from '@utils/terminal'\nimport terminalSetup, {\n isShiftEnterKeyBindingInstalled,\n handleHashCommand,\n} from '@commands/terminalSetup'\nimport { usePermissionContext } from '@context/PermissionContext'\nimport { getHookManager } from '@utils/hookManager'\nimport { debug as debugLogger } from '@utils/debugLogger'\nimport { PROJECT_FILE } from '@constants/product'\n\n// Async function to interpret the '#' command input using AI\nasync function interpretHashCommand(input: string): Promise<string> {\n // Use the AI to interpret the input\n try {\n const { queryQuick } = await import('@services/claude')\n\n // Create a prompt for the model to interpret the hash command\n const systemPrompt = [\n \"You're helping the user structure notes that will be added to their KODING.md file.\",\n \"Format the user's input into a well-structured note that will be useful for later reference.\",\n 'Add appropriate markdown formatting, headings, bullet points, or other structural elements as needed.',\n 'The goal is to transform the raw note into something that will be more useful when reviewed later.',\n 'You should keep the original meaning but make the structure clear.',\n ]\n\n // Send the request to the AI\n const result = await queryQuick({\n systemPrompt,\n userPrompt: `Transform this note for KODING.md: ${input}`,\n })\n\n // Extract the content from the response\n if (typeof result.message.content === 'string') {\n return result.message.content\n } else if (Array.isArray(result.message.content)) {\n return result.message.content\n .filter(block => block.type === 'text')\n .map(block => (block.type === 'text' ? block.text : ''))\n .join('\\n')\n }\n\n return `# ${input}\\n\\n_Added on ${new Date().toLocaleString()}_`\n } catch (e) {\n // If interpretation fails, return the input with minimal formatting\n return `# ${input}\\n\\n_Added on ${new Date().toLocaleString()}_`\n }\n}\n\ntype Props = {\n commands: Command[]\n forkNumber: number\n messageLogName: string\n isDisabled: boolean\n isLoading: boolean\n onQuery: (\n newMessages: Message[],\n abortController?: AbortController,\n ) => Promise<void>\n debug: boolean\n verbose: boolean\n messages: Message[]\n setToolJSX: SetToolJSXFn\n tools: Tool[]\n input: string\n onInputChange: (value: string) => void\n mode: 'bash' | 'prompt' | 'koding'\n onModeChange: (mode: 'bash' | 'prompt' | 'koding') => void\n submitCount: number\n onSubmitCountChange: (updater: (prev: number) => number) => void\n setIsLoading: (isLoading: boolean) => void\n setAbortController: (abortController: AbortController | null) => void\n onShowMessageSelector: () => void\n setForkConvoWithMessagesOnTheNextRender: (\n forkConvoWithMessages: Message[],\n ) => void\n readFileTimestamps: { [filename: string]: number }\n abortController: AbortController | null\n onModelChange?: () => void\n onRollbackConversation?: () => boolean // Phase 4.1: Esc Esc rollback\n onToggleTodoPanel?: () => void // Ctrl+T: Toggle TodoPanel\n onToggleVerbose?: () => void // Ctrl+O: Toggle verbose mode\n onToggleBackgroundPanel?: () => void // View background tasks\n backgroundShellCount?: number // Number of active background shells\n isBackgroundPanelOpen?: boolean // Whether background panel is currently visible\n fallbackMode?: boolean // Whether to use limited input mode (raw mode not supported)\n}\n\nfunction getPastedTextPrompt(text: string): string {\n const newlineCount = (text.match(/\\r\\n|\\r|\\n/g) || []).length\n return `[Pasted text +${newlineCount} lines] `\n}\nfunction PromptInput({\n commands,\n forkNumber,\n messageLogName,\n isDisabled,\n isLoading,\n onQuery,\n debug,\n verbose,\n messages,\n setToolJSX,\n tools,\n input,\n onInputChange,\n mode,\n onModeChange,\n submitCount,\n onSubmitCountChange,\n setIsLoading,\n fallbackMode = false,\n abortController,\n setAbortController,\n onShowMessageSelector,\n setForkConvoWithMessagesOnTheNextRender,\n readFileTimestamps,\n onToggleTodoPanel,\n onToggleVerbose,\n onModelChange,\n onRollbackConversation,\n onToggleBackgroundPanel,\n backgroundShellCount = 0,\n isBackgroundPanelOpen = false,\n}: Props): React.ReactNode {\n const [exitMessage, setExitMessage] = useState<{\n show: boolean\n key?: string\n }>({ show: false })\n const [message, setMessage] = useState<{ show: boolean; text?: string }>({\n show: false,\n })\n const [modelSwitchMessage, setModelSwitchMessage] = useState<{\n show: boolean\n text?: string\n }>({\n show: false,\n })\n const [pastedImage, setPastedImage] = useState<string | null>(null)\n const [placeholder, setPlaceholder] = useState('')\n const [cursorOffset, setCursorOffset] = useState<number>(input.length)\n const [pastedText, setPastedText] = useState<string | null>(null)\n\n // Ctrl-D double-tap tracking\n const [ctrlDCount, setCtrlDCount] = useState(0)\n const [ctrlDTimer, setCtrlDTimer] = useState<NodeJS.Timeout | null>(null)\n\n // Phase 4.1: Esc double-tap tracking for conversation rollback\n const [escCount, setEscCount] = useState(0)\n const [escTimer, setEscTimer] = useState<NodeJS.Timeout | null>(null)\n\n // Hotkey feedback messages (for Ctrl-C, Ctrl-L, Ctrl-O)\n const [hotkeyMessage, setHotkeyMessage] = useState<{\n show: boolean\n text?: string\n }>({ show: false })\n\n // Background task indicator focus state\n const [backgroundIndicatorFocused, setBackgroundIndicatorFocused] =\n useState(false)\n\n // Permission context for mode management\n const { cycleMode, currentMode } = usePermissionContext()\n\n // useEffect(() => {\n // getExampleCommands().then(commands => {\n // setPlaceholder(`Try \"${sample(commands)}\"`)\n // })\n // }, [])\n const { columns } = useTerminalSize()\n\n const commandWidth = useMemo(\n () => Math.max(...commands.map(cmd => cmd.userFacingName().length)) + 5,\n [commands],\n )\n\n // Unified completion system - one hook to rule them all (now with terminal behavior)\n const {\n suggestions,\n selectedIndex,\n isActive: completionActive,\n emptyDirMessage,\n } = useUnifiedCompletion({\n input,\n cursorOffset,\n onInputChange,\n setCursorOffset,\n commands,\n onSubmit,\n })\n\n // Phase 3: History search with Ctrl-R\n const history = useMemo(() => getHistory(), [submitCount]) // Refresh on submit\n const historySearch = useHistorySearch(history)\n\n // Get theme early for memoized rendering\n const theme = getTheme()\n\n // Visible window size for suggestions - show limited items with scrolling\n const MAX_VISIBLE_SUGGESTIONS = 8\n\n // Calculate visible window for suggestions (pagination logic)\n const visibleSuggestions = useMemo(() => {\n if (suggestions.length === 0) return []\n\n // If all suggestions fit in window, show them all\n if (suggestions.length <= MAX_VISIBLE_SUGGESTIONS) {\n return suggestions.map((s, i) => ({ ...s, globalIndex: i }))\n }\n\n // Calculate scroll window to keep selected item visible\n const halfWindow = Math.floor(MAX_VISIBLE_SUGGESTIONS / 2)\n let startIndex = Math.max(0, selectedIndex - halfWindow)\n let endIndex = startIndex + MAX_VISIBLE_SUGGESTIONS\n\n // Adjust if we're near the end\n if (endIndex > suggestions.length) {\n endIndex = suggestions.length\n startIndex = Math.max(0, endIndex - MAX_VISIBLE_SUGGESTIONS)\n }\n\n return suggestions\n .slice(startIndex, endIndex)\n .map((s, i) => ({ ...s, globalIndex: startIndex + i }))\n }, [suggestions, selectedIndex])\n\n // Memoized completion suggestions rendering - with scroll indicators\n const renderedSuggestions = useMemo(() => {\n if (suggestions.length === 0) return null\n\n const hasMoreAbove =\n visibleSuggestions.length > 0 && visibleSuggestions[0].globalIndex > 0\n const hasMoreBelow =\n visibleSuggestions.length > 0 &&\n visibleSuggestions[visibleSuggestions.length - 1].globalIndex <\n suggestions.length - 1\n\n return (\n <>\n {hasMoreAbove && (\n <Box>\n <Text dimColor>\n {' '}\n \u2191 {visibleSuggestions[0].globalIndex} more above...\n </Text>\n </Box>\n )}\n {visibleSuggestions.map(suggestion => {\n const isSelected = suggestion.globalIndex === selectedIndex\n const isAgent = suggestion.type === 'agent'\n\n // Simple color logic without complex lookups\n const displayColor = isSelected\n ? theme.suggestion\n : isAgent && suggestion.metadata?.color\n ? suggestion.metadata.color\n : undefined\n\n return (\n <Box\n key={`${suggestion.type}-${suggestion.value}-${suggestion.globalIndex}`}\n flexDirection=\"row\"\n >\n <Text\n color={displayColor}\n dimColor={!isSelected && !displayColor}\n >\n {isSelected ? '\u25C6 ' : ' '}\n {suggestion.displayValue}\n </Text>\n </Box>\n )\n })}\n {hasMoreBelow && (\n <Box>\n <Text dimColor>\n {' '}\n \u2193{' '}\n {suggestions.length -\n visibleSuggestions[visibleSuggestions.length - 1].globalIndex -\n 1}{' '}\n more below...\n </Text>\n </Box>\n )}\n </>\n )\n }, [suggestions, selectedIndex, visibleSuggestions, theme.suggestion])\n\n const onChange = useCallback(\n (value: string) => {\n if (value.startsWith('!')) {\n onModeChange('bash')\n return\n }\n if (value.startsWith('#')) {\n onModeChange('koding')\n return\n }\n onInputChange(value)\n },\n [onModeChange, onInputChange],\n )\n\n // Handle Shift+M model switching with enhanced debugging\n const handleQuickModelSwitch = useCallback(async () => {\n const modelManager = getModelManager()\n const currentTokens = countTokens(messages)\n\n // Get debug info for better error reporting\n const debugInfo = modelManager.getModelSwitchingDebugInfo()\n\n const switchResult = modelManager.switchToNextModel(currentTokens)\n\n if (switchResult.success && switchResult.modelName) {\n // Successful switch - use enhanced message from model manager\n onSubmitCountChange(prev => prev + 1)\n setModelSwitchMessage({\n show: true,\n text:\n switchResult.message || `\u2705 Switched to ${switchResult.modelName}`,\n })\n setTimeout(() => setModelSwitchMessage({ show: false }), 3000)\n } else if (switchResult.blocked && switchResult.message) {\n // Context overflow - show detailed message\n setModelSwitchMessage({\n show: true,\n text: switchResult.message,\n })\n setTimeout(() => setModelSwitchMessage({ show: false }), 5000)\n } else {\n // Enhanced error reporting with debug info\n let errorMessage = switchResult.message\n\n if (!errorMessage) {\n if (debugInfo.totalModels === 0) {\n errorMessage = '\u274C No models configured. Use /model to add models.'\n } else if (debugInfo.activeModels === 0) {\n errorMessage = `\u274C No active models (${debugInfo.totalModels} total, all inactive). Use /model to activate models.`\n } else if (debugInfo.activeModels === 1) {\n // Show ALL models including inactive ones for debugging\n const allModelNames = debugInfo.availableModels\n .map(m => `${m.name}${m.isActive ? '' : ' (inactive)'}`)\n .join(', ')\n errorMessage = `\u26A0\uFE0F Only 1 active model out of ${debugInfo.totalModels} total models: ${allModelNames}. ALL configured models will be activated for switching.`\n } else {\n errorMessage = `\u274C Model switching failed (${debugInfo.activeModels} active, ${debugInfo.totalModels} total models available)`\n }\n }\n\n setModelSwitchMessage({\n show: true,\n text: errorMessage,\n })\n setTimeout(() => setModelSwitchMessage({ show: false }), 6000)\n }\n }, [onSubmitCountChange, messages])\n\n const { resetHistory, onHistoryUp, onHistoryDown } = useArrowKeyHistory(\n (value: string, mode: 'bash' | 'prompt' | 'koding') => {\n onChange(value)\n onModeChange(mode)\n },\n input,\n )\n\n // Only use history navigation when there are no suggestions\n const handleHistoryUp = () => {\n if (!completionActive) {\n onHistoryUp()\n }\n }\n\n const handleHistoryDown = () => {\n if (!completionActive) {\n onHistoryDown()\n }\n }\n\n async function onSubmit(input: string, isSubmittingSlashCommand = false) {\n // UserPromptSubmit hook\n const hookManager = getHookManager()\n if (hookManager && input && input.trim()) {\n try {\n const decision = await hookManager.executeUserPromptSubmit(input)\n\n if (!decision.shouldContinue) {\n if (decision.shouldAskUser) {\n // Show confirmation to user (simplified - in real UI might show dialog)\n const confirmed = confirm(\n decision.reason || 'Hook requested approval. Continue?',\n )\n if (!confirmed) {\n return // Don't submit\n }\n } else {\n // Blocked by hook\n setMessage({\n show: true,\n text: decision.reason || 'Blocked by hook',\n })\n setTimeout(() => setMessage({ show: false }), 3000)\n return\n }\n }\n } catch (err) {\n debugLogger.error('UserPromptSubmit hook failed', { error: err })\n // Continue on error (fail-safe)\n }\n }\n\n // Special handling for \"put a verbose summary\" and similar action prompts in koding mode\n if (\n (mode === 'koding' || input.startsWith('#')) &&\n input.match(/^(#\\s*)?(put|create|generate|write|give|provide)/i)\n ) {\n try {\n // Store the original input for history\n const originalInput = input\n\n // Strip the # prefix if present\n const cleanInput = mode === 'koding' ? input : input.substring(1).trim()\n\n // Add to history and clear input field\n addToHistory(mode === 'koding' ? `#${input}` : input)\n onInputChange('')\n\n // Create additional context to inform the assistant this is for KODING.md\n const kodingContext = `The user is using Koding mode. Format your response as a comprehensive, well-structured document suitable for adding to ${PROJECT_FILE}. Use proper markdown formatting with headings, lists, code blocks, etc. The response should be complete and ready to add to ${PROJECT_FILE} documentation.`\n\n // Switch to prompt mode but tag the submission for later capture\n onModeChange('prompt')\n\n // \uD83D\uDD27 Fix Koding mode: clean up previous state\n if (abortController) {\n abortController.abort()\n }\n setIsLoading(false)\n await new Promise(resolve => setTimeout(resolve, 0))\n\n // Set loading state - AbortController now created in onQuery\n setIsLoading(true)\n\n // Process as a normal user input but with special handling\n const messages = await processUserInput(\n cleanInput,\n 'prompt', // Use prompt mode for processing\n setToolJSX,\n {\n options: {\n commands,\n forkNumber,\n messageLogName,\n tools,\n verbose,\n maxThinkingTokens: 0,\n // Add context flag for koding mode\n isKodingRequest: true,\n kodingContext,\n },\n messageId: undefined,\n abortController: abortController || new AbortController(), // Temporary controller, actual one created in onQuery\n readFileTimestamps,\n setForkConvoWithMessagesOnTheNextRender,\n },\n pastedImage ?? null,\n )\n\n // Send query and capture response\n if (messages.length) {\n await onQuery(messages)\n\n // After query completes, the last message should be the assistant's response\n // We'll set up a one-time listener to capture and save that response\n // This will be handled by the REPL component or message handler\n }\n\n return\n } catch (e) {\n // If something fails, log the error\n console.error('Error processing Koding request:', e)\n }\n }\n\n // If in koding mode or input starts with '#', interpret it using AI before appending to MINTO.md\n else if (mode === 'koding' || input.startsWith('#')) {\n try {\n // Strip the # if we're in koding mode and the user didn't type it (since it's implied)\n const contentToInterpret =\n mode === 'koding' && !input.startsWith('#')\n ? input.trim()\n : input.substring(1).trim()\n\n const interpreted = await interpretHashCommand(contentToInterpret)\n handleHashCommand(interpreted)\n } catch (e) {\n // If interpretation fails, log the error\n }\n onInputChange('')\n addToHistory(mode === 'koding' ? `#${input}` : input)\n onModeChange('prompt')\n return\n }\n if (input === '') {\n return\n }\n if (isDisabled) {\n return\n }\n if (isLoading) {\n return\n }\n\n // Handle Enter key when completions are active\n // If there are suggestions showing, Enter should complete the selection, not send the message\n if (suggestions.length > 0 && completionActive) {\n // The completion is handled by useUnifiedCompletion hook\n // Just return to prevent message sending\n return\n }\n\n // Handle exit commands\n if (['exit', 'quit', ':q', ':q!', ':wq', ':wq!'].includes(input.trim())) {\n exit()\n }\n\n let finalInput = input\n if (pastedText) {\n // Create the prompt pattern that would have been used for this pasted text\n const pastedPrompt = getPastedTextPrompt(pastedText)\n if (finalInput.includes(pastedPrompt)) {\n finalInput = finalInput.replace(pastedPrompt, pastedText)\n } // otherwise, ignore the pastedText if the user has modified the prompt\n }\n onInputChange('')\n onModeChange('prompt')\n // Suggestions are now handled by unified completion\n setPastedImage(null)\n setPastedText(null)\n onSubmitCountChange(_ => _ + 1)\n\n setIsLoading(true)\n\n const newAbortController = new AbortController()\n setAbortController(newAbortController)\n\n const messages = await processUserInput(\n finalInput,\n mode,\n setToolJSX,\n {\n options: {\n commands,\n forkNumber,\n messageLogName,\n tools,\n verbose,\n maxThinkingTokens: 0,\n },\n messageId: undefined,\n abortController: newAbortController,\n readFileTimestamps,\n setForkConvoWithMessagesOnTheNextRender,\n },\n pastedImage ?? null,\n )\n\n if (messages.length) {\n onQuery(messages, newAbortController)\n } else {\n // Local JSX commands\n addToHistory(input)\n resetHistory()\n return\n }\n\n for (const message of messages) {\n if (message.type === 'user') {\n const inputToAdd = mode === 'bash' ? `!${input}` : input\n addToHistory(inputToAdd)\n resetHistory()\n }\n }\n }\n\n function onImagePaste(image: string) {\n onModeChange('prompt')\n setPastedImage(image)\n }\n\n function onTextPaste(rawText: string) {\n // Replace any \\r with \\n first to match useTextInput's conversion behavior\n const text = rawText.replace(/\\r/g, '\\n')\n\n // Get prompt with newline count\n const pastedPrompt = getPastedTextPrompt(text)\n\n // Update the input with a visual indicator that text has been pasted\n const newInput =\n input.slice(0, cursorOffset) + pastedPrompt + input.slice(cursorOffset)\n onInputChange(newInput)\n\n // Update cursor position to be after the inserted indicator\n setCursorOffset(cursorOffset + pastedPrompt.length)\n\n // Still set the pastedText state for actual submission\n setPastedText(text)\n }\n\n // IMPORTANT: useInput must be called unconditionally (React Hook rule)\n // In fallback mode, we provide an empty handler to satisfy the Hook requirement\n useInput(\n fallbackMode\n ? () => {} // Fallback mode: no-op handler\n : (inputChar, key) => {\n // ========== NORMAL MODE: Full interactive input handling ==========\n // ========== NEW HOTKEYS (Phase 1) ==========\n\n // Ctrl-C: Enhanced cancel/interrupt\n if (key.ctrl && inputChar === 'c') {\n if (isLoading) {\n // Cancel ongoing request\n if (abortController && !abortController.signal.aborted) {\n abortController.abort()\n }\n setIsLoading(false)\n setHotkeyMessage({\n show: true,\n text: 'Interrupted by user (Ctrl-C)',\n })\n setTimeout(() => setHotkeyMessage({ show: false }), 2000)\n } else if (input.length > 0) {\n // Clear input\n onInputChange('')\n setHotkeyMessage({ show: true, text: 'Input cleared' })\n setTimeout(() => setHotkeyMessage({ show: false }), 1000)\n } else {\n // Hint for exit (optional: could implement double Ctrl-C to exit)\n setHotkeyMessage({ show: true, text: 'Press Ctrl-D to exit' })\n setTimeout(() => setHotkeyMessage({ show: false }), 2000)\n }\n return true\n }\n\n // Ctrl-D: Graceful EOF exit (double-tap safety)\n if (key.ctrl && inputChar === 'd') {\n if (input.length > 0) {\n // If there's input, just clear it\n onInputChange('')\n setHotkeyMessage({ show: true, text: 'Input cleared (Ctrl-D)' })\n setTimeout(() => setHotkeyMessage({ show: false }), 1000)\n return true\n }\n\n // Empty input: increment Ctrl-D count for double-tap safety\n setCtrlDCount(prev => prev + 1)\n\n if (ctrlDTimer) clearTimeout(ctrlDTimer)\n const timer = setTimeout(() => setCtrlDCount(0), 1000)\n setCtrlDTimer(timer)\n\n if (ctrlDCount >= 1) {\n // Second Ctrl-D: graceful exit\n setHotkeyMessage({ show: true, text: 'Exiting gracefully...' })\n setTimeout(() => exit(), 500)\n } else {\n // First Ctrl-D: show hint\n setHotkeyMessage({\n show: true,\n text: 'Press Ctrl-D again to exit',\n })\n setTimeout(() => setHotkeyMessage({ show: false }), 2000)\n }\n\n return true\n }\n\n // Ctrl-L: Clear screen\n if (key.ctrl && inputChar === 'l') {\n clearScreen()\n setHotkeyMessage({ show: true, text: 'Screen cleared (Ctrl-L)' })\n setTimeout(() => setHotkeyMessage({ show: false }), 1000)\n return true\n }\n\n // Ctrl-O: Toggle verbose mode\n if (key.ctrl && inputChar === 'o') {\n const config = getGlobalConfig()\n const newVerbose = !verbose\n\n // Update global config\n saveGlobalConfig({\n ...config,\n verbose: newVerbose,\n })\n\n // Show feedback\n setHotkeyMessage({\n show: true,\n text: `Verbose mode ${newVerbose ? 'enabled' : 'disabled'} (Ctrl-O)`,\n })\n setTimeout(() => setHotkeyMessage({ show: false }), 2000)\n\n // Notify parent component to update verbose state\n if (onToggleVerbose) {\n onToggleVerbose()\n }\n\n return true\n }\n\n // Ctrl+T: Toggle TodoPanel visibility\n if (key.ctrl && inputChar === 't') {\n if (onToggleTodoPanel) {\n onToggleTodoPanel()\n setHotkeyMessage({\n show: true,\n text: 'TodoPanel toggled (Ctrl-T)',\n })\n setTimeout(() => setHotkeyMessage({ show: false }), 2000)\n }\n return true\n }\n\n // Phase 4.3: Ctrl-B: Quick bash command execution\n // Note: Moving to background is handled by StreamingBashOutput component\n if (key.ctrl && inputChar === 'b') {\n if (!input || input.trim().length === 0) {\n setHotkeyMessage({\n show: true,\n text: 'Type a command first, then press Ctrl-B',\n })\n setTimeout(() => setHotkeyMessage({ show: false }), 2000)\n return true\n }\n\n // If already in bash mode (starts with !), just submit\n if (mode === 'bash') {\n setHotkeyMessage({\n show: true,\n text: 'Executing bash command... (Ctrl-B)',\n })\n setTimeout(() => setHotkeyMessage({ show: false }), 1000)\n // Let it submit normally via Enter handling\n onSubmit(input)\n return true\n }\n\n // Otherwise, convert to bash command and submit\n const bashCommand = `!${input}`\n setHotkeyMessage({\n show: true,\n text: 'Executing bash command... (Ctrl-B)',\n })\n setTimeout(() => setHotkeyMessage({ show: false }), 1000)\n\n // Submit as bash command\n onSubmit(bashCommand)\n return true\n }\n\n // Phase 3: Ctrl-R: Reverse history search\n if (key.ctrl && inputChar === 'r') {\n if (!historySearch.isActive) {\n // Activate history search\n historySearch.activate()\n return true\n }\n // If already active, cycle to next match (move up in history)\n historySearch.moveUp()\n return true\n }\n\n // History search mode: handle special keys\n if (historySearch.isActive) {\n // Esc: Cancel search\n if (key.escape) {\n historySearch.reset()\n return true\n }\n\n // Enter: Select current item and exit search\n if (key.return) {\n if (historySearch.selectedItem) {\n onInputChange(historySearch.selectedItem)\n }\n historySearch.reset()\n return true\n }\n\n // Up/Down: Navigate through results\n if (key.upArrow) {\n historySearch.moveUp()\n return true\n }\n if (key.downArrow) {\n historySearch.moveDown()\n return true\n }\n\n // Any other character: Update search term\n if (inputChar && !key.ctrl && !key.meta) {\n historySearch.setSearchTerm(historySearch.searchTerm + inputChar)\n return true\n }\n\n // Backspace: Remove character from search\n if (key.backspace || key.delete) {\n if (historySearch.searchTerm.length > 0) {\n historySearch.setSearchTerm(\n historySearch.searchTerm.slice(0, -1),\n )\n } else {\n // No search term, cancel search\n historySearch.reset()\n }\n return true\n }\n }\n\n // Background task indicator navigation\n if (backgroundIndicatorFocused) {\n // Up arrow: return focus to input\n if (key.upArrow) {\n setBackgroundIndicatorFocused(false)\n return true\n }\n\n // Enter: open background tasks panel\n if (key.return) {\n if (onToggleBackgroundPanel) {\n onToggleBackgroundPanel()\n }\n setBackgroundIndicatorFocused(false)\n return true\n }\n\n // Esc: unfocus indicator\n if (key.escape) {\n setBackgroundIndicatorFocused(false)\n return true\n }\n\n return true // Consume all other input when indicator is focused\n }\n\n // Down arrow when input is active: focus background indicator if it exists\n if (key.downArrow && backgroundShellCount > 0 && !completionActive) {\n setBackgroundIndicatorFocused(true)\n return true\n }\n\n // ========== EXISTING HOTKEYS ==========\n\n // For bash mode, only exit when deleting the last character (which would be the '!' character)\n if (mode === 'bash' && (key.backspace || key.delete)) {\n // Check the current input state, not the inputChar parameter\n // If current input is empty, we're about to delete the '!' character, so exit bash mode\n if (input === '') {\n onModeChange('prompt')\n }\n return\n }\n\n // For koding mode, only exit when deleting the last character (which would be the '#' character)\n if (mode === 'koding' && (key.backspace || key.delete)) {\n // Check the current input state, not the inputChar parameter\n // If current input is empty, we're about to delete the '#' character, so exit koding mode\n if (input === '') {\n onModeChange('prompt')\n }\n return\n }\n\n // For other modes, keep the original behavior\n if (inputChar === '' && (key.escape || key.backspace || key.delete)) {\n onModeChange('prompt')\n }\n\n // Phase 4.1: Esc Esc double-press for conversation rollback\n if (\n key.escape &&\n !input &&\n !isLoading &&\n messages.length > 0 &&\n onRollbackConversation\n ) {\n // Increment Esc count for double-tap detection\n setEscCount(prev => prev + 1)\n\n if (escTimer) clearTimeout(escTimer)\n const timer = setTimeout(() => setEscCount(0), 1000)\n setEscTimer(timer)\n\n if (escCount >= 1) {\n // Second Esc: rollback conversation\n const success = onRollbackConversation()\n if (success) {\n setMessage({\n show: true,\n text: 'Conversation rolled back (Esc Esc)',\n })\n setTimeout(() => setMessage({ show: false }), 2000)\n } else {\n setMessage({ show: true, text: 'No history to rollback' })\n setTimeout(() => setMessage({ show: false }), 2000)\n }\n setEscCount(0) // Reset after action\n return true\n } else {\n // First Esc: show hint (only if message selector won't be shown)\n setMessage({\n show: true,\n text: 'Press Esc again to rollback conversation',\n })\n setTimeout(() => setMessage({ show: false }), 2000)\n return true\n }\n }\n\n // esc is a little overloaded:\n // - when we're loading a response, it's used to cancel the request\n // - otherwise, it's used to show the message selector\n // - when double pressed, it's used to clear the input\n if (key.escape && messages.length > 0 && !input && !isLoading) {\n onShowMessageSelector()\n }\n\n // Tab (without Shift) for thinking mode toggle (Phase 4.2)\n // Only when completion is NOT active\n if (key.tab && !key.shift && !completionActive) {\n const config = getGlobalConfig()\n const newThinking = !config.thinking\n\n // Update global config\n saveGlobalConfig({\n ...config,\n thinking: newThinking,\n })\n\n // Show feedback\n setMessage({\n show: true,\n text: `Thinking mode ${newThinking ? 'enabled' : 'disabled'} (Tab)`,\n })\n setTimeout(() => setMessage({ show: false }), 2000)\n\n return true // Explicitly handled\n }\n\n // Shift+Tab for mode cycling (retains legacy keyboard behavior)\n if (key.shift && key.tab) {\n cycleMode()\n return true // Explicitly handled\n }\n\n return false // Not handled, allow other hooks\n },\n { isActive: !isBackgroundPanelOpen && !fallbackMode },\n )\n\n // Handle special key combinations before character input\n const handleSpecialKey = useCallback(\n (inputChar: string, key: any): boolean => {\n // Shift+M for model switching - intercept before character input\n if (key.shift && (inputChar === 'M' || inputChar === 'm')) {\n handleQuickModelSwitch()\n return true // Prevent character from being input\n }\n\n return false // Not handled, allow normal processing\n },\n [handleQuickModelSwitch],\n )\n\n const textInputColumns = useTerminalSize().columns - 6\n const tokenUsage = useMemo(() => countTokens(messages), [messages])\n\n // \uD83D\uDD27 Fix: Track model ID changes to detect external config updates\n const modelManager = getModelManager()\n const currentModelId = (modelManager.getModel('main') as any)?.id || null\n\n const modelInfo = useMemo(() => {\n // Force fresh ModelManager instance to detect config changes\n const freshModelManager = getModelManager()\n const currentModel = freshModelManager.getModel('main')\n if (!currentModel) {\n return null\n }\n\n return {\n name: currentModel.modelName, // \uD83D\uDD27 Fix: Use actual model name, not display name\n id: (currentModel as any).id, // \u6DFB\u52A0\u6A21\u578BID\u7528\u4E8E\u8C03\u8BD5\n provider: currentModel.provider, // \u6DFB\u52A0\u63D0\u4F9B\u5546\u4FE1\u606F\n contextLength: currentModel.contextLength,\n currentTokens: tokenUsage,\n }\n }, [tokenUsage, modelSwitchMessage.show, submitCount, currentModelId]) // Track model ID to detect config changes\n\n return (\n <Box flexDirection=\"column\">\n {/* Fallback mode warning */}\n {fallbackMode && (\n <Box marginBottom={1}>\n <Text color=\"yellow\">\u26A0\uFE0F Limited input mode</Text>\n <Text dimColor>\n {' '}\n (Advanced keyboard shortcuts unavailable - raw mode not supported)\n </Text>\n </Box>\n )}\n\n {/* Phase 3: History search overlay */}\n {historySearch.isActive && (\n <HistorySearchOverlay\n searchTerm={historySearch.searchTerm}\n results={historySearch.filteredResults}\n selectedIndex={historySearch.selectedIndex}\n />\n )}\n\n {/* Model info in top-right corner */}\n {modelInfo && (\n <Box justifyContent=\"flex-end\" marginBottom={1}>\n <Text dimColor>\n [{modelInfo.provider}] {modelInfo.name}:{' '}\n {Math.round(modelInfo.currentTokens / 1000)}k /{' '}\n {Math.round(modelInfo.contextLength / 1000)}k\n </Text>\n </Box>\n )}\n\n <Box\n alignItems=\"flex-start\"\n justifyContent=\"flex-start\"\n borderColor={\n mode === 'bash'\n ? theme.bashBorder\n : mode === 'koding'\n ? theme.noting\n : theme.secondaryBorder\n }\n borderDimColor\n borderStyle=\"round\"\n marginTop={1}\n width=\"100%\"\n >\n <Box\n alignItems=\"flex-start\"\n alignSelf=\"flex-start\"\n flexWrap=\"nowrap\"\n justifyContent=\"flex-start\"\n width={3}\n >\n {mode === 'bash' ? (\n <Text color={theme.bashBorder}>&nbsp;!&nbsp;</Text>\n ) : mode === 'koding' ? (\n <Text color={theme.noting}>&nbsp;#&nbsp;</Text>\n ) : (\n <Text color={isLoading ? theme.secondaryText : undefined}>\n &nbsp;&gt;&nbsp;\n </Text>\n )}\n </Box>\n <Box paddingRight={1}>\n <TextInput\n multiline\n focus={!isBackgroundPanelOpen}\n onSubmit={onSubmit}\n onChange={onChange}\n value={input}\n onHistoryUp={handleHistoryUp}\n onHistoryDown={handleHistoryDown}\n onHistoryReset={() => resetHistory()}\n placeholder={submitCount > 0 ? undefined : placeholder}\n onExit={() => process.exit(0)}\n onExitMessage={(show, key) => setExitMessage({ show, key })}\n onMessage={(show, text) => setMessage({ show, text })}\n onImagePaste={onImagePaste}\n columns={textInputColumns}\n isDimmed={isDisabled || isLoading}\n disableCursorMovementForUpDownKeys={completionActive}\n cursorOffset={cursorOffset}\n onChangeCursorOffset={setCursorOffset}\n onPaste={onTextPaste}\n onSpecialKey={handleSpecialKey}\n />\n </Box>\n </Box>\n {!completionActive && suggestions.length === 0 && (\n <Box\n flexDirection=\"row\"\n justifyContent=\"space-between\"\n paddingX={2}\n paddingY={0}\n >\n <Box justifyContent=\"flex-start\" gap={1}>\n {exitMessage.show ? (\n <Text dimColor>Press {exitMessage.key} again to exit</Text>\n ) : message.show ? (\n <Text dimColor>{message.text}</Text>\n ) : hotkeyMessage.show ? (\n <Text color={theme.success}>{hotkeyMessage.text}</Text>\n ) : modelSwitchMessage.show ? (\n <Text color={theme.success}>{modelSwitchMessage.text}</Text>\n ) : (\n <>\n <Text\n color={mode === 'bash' ? theme.bashBorder : undefined}\n dimColor={mode !== 'bash'}\n >\n ! for bash mode\n </Text>\n <Text\n color={mode === 'koding' ? theme.noting : undefined}\n dimColor={mode !== 'koding'}\n >\n \u00B7 # for {PROJECT_FILE}\n </Text>\n <Text dimColor>\n \u00B7 / for commands \u00B7 ctrl+c cancel \u00B7 ctrl+l clear\n </Text>\n {backgroundShellCount > 0 && (\n <Text\n color={\n backgroundIndicatorFocused ? theme.primary : theme.success\n }\n backgroundColor={\n backgroundIndicatorFocused ? theme.success : undefined\n }\n dimColor={!backgroundIndicatorFocused}\n >\n \u00B7 {backgroundIndicatorFocused ? '\u25BA ' : ''}\n {backgroundShellCount} background task\n {backgroundShellCount > 1 ? 's' : ''}\n </Text>\n )}\n </>\n )}\n </Box>\n <SentryErrorBoundary\n children={\n <Box justifyContent=\"flex-end\" gap={1}>\n {!debug && tokenUsage < WARNING_THRESHOLD && (\n <Text dimColor>\n {terminalSetup.isEnabled &&\n isShiftEnterKeyBindingInstalled()\n ? 'shift + \u23CE for newline'\n : '\\\\\u23CE for newline'}\n </Text>\n )}\n <TokenWarning tokenUsage={tokenUsage} />\n </Box>\n }\n />\n </Box>\n )}\n\n {/* Unified completion suggestions - optimized rendering */}\n {suggestions.length > 0 && (\n <Box\n flexDirection=\"row\"\n justifyContent=\"space-between\"\n paddingX={2}\n paddingY={0}\n >\n <Box flexDirection=\"column\">\n {renderedSuggestions}\n\n {/* \u7B80\u6D01\u64CD\u4F5C\u63D0\u793A\u6846 - \u5305\u542B\u5217\u8868\u4F4D\u7F6E\u4FE1\u606F */}\n <Box\n marginTop={1}\n paddingX={3}\n borderStyle=\"round\"\n borderColor=\"gray\"\n >\n <Text\n dimColor={!emptyDirMessage}\n color={emptyDirMessage ? 'yellow' : undefined}\n >\n {emptyDirMessage ||\n (() => {\n const selected = suggestions[selectedIndex]\n const positionInfo =\n suggestions.length > 1\n ? `[${selectedIndex + 1}/${suggestions.length}] `\n : ''\n\n if (!selected) {\n return `${positionInfo}\u2191\u2193 navigate \u2022 \u2192 accept \u2022 Tab cycle \u2022 Esc close`\n }\n if (selected?.value.endsWith('/')) {\n return `${positionInfo}\u2192 enter directory \u2022 \u2191\u2193 navigate \u2022 Tab cycle \u2022 Esc close`\n } else if (selected?.type === 'agent') {\n return `${positionInfo}\u2192 select agent \u2022 \u2191\u2193 navigate \u2022 Tab cycle \u2022 Esc close`\n } else {\n return `${positionInfo}\u2192 insert reference \u2022 \u2191\u2193 navigate \u2022 Tab cycle \u2022 Esc close`\n }\n })()}\n </Text>\n </Box>\n </Box>\n <SentryErrorBoundary\n children={\n <Box justifyContent=\"flex-end\" gap={1}>\n <TokenWarning tokenUsage={countTokens(messages)} />\n </Box>\n }\n />\n </Box>\n )}\n </Box>\n )\n}\n\nexport default memo(PromptInput)\n\nfunction exit(): never {\n setTerminalTitle('')\n process.exit(0)\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["modelManager", "mode", "input", "messages", "message"]
7
7
  }
@@ -1,10 +1,17 @@
1
1
  import { Box, Text } from "ink";
2
2
  import * as React from "react";
3
- import { getTotalCost, getTotalDuration, getTotalAPIDuration } from "../cost-tracker.js";
3
+ import {
4
+ getTotalCost,
5
+ getTotalDuration,
6
+ getTotalAPIDuration
7
+ } from "../cost-tracker.js";
4
8
  import { SESSION_ID } from "../utils/log.js";
5
9
  import { getTheme } from "../utils/theme.js";
6
10
  import { formatDuration } from "../utils/format.js";
7
- function QuitSummary({ messages, onClose }) {
11
+ function QuitSummary({
12
+ messages,
13
+ onClose
14
+ }) {
8
15
  const theme = getTheme();
9
16
  const toolCallStats = React.useMemo(() => {
10
17
  let totalCalls = 0;
@@ -64,15 +71,15 @@ function QuitSummary({ messages, onClose }) {
64
71
  },
65
72
  /* @__PURE__ */ React.createElement(Box, { marginBottom: 1 }, /* @__PURE__ */ React.createElement(Text, { bold: true, color: theme.success }, "Agent powering down. Goodbye!")),
66
73
  /* @__PURE__ */ React.createElement(Box, { marginBottom: 1 }, /* @__PURE__ */ React.createElement(Text, { bold: true }, "Interaction Summary")),
67
- /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, null, "Session ID: ", SESSION_ID)),
68
- /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, null, "Tool Calls: ", toolCallStats.total, " ( \u2713 ", toolCallStats.successful, " \u2717 ", toolCallStats.failed, " )")),
69
- /* @__PURE__ */ React.createElement(Box, { marginBottom: 1 }, /* @__PURE__ */ React.createElement(Text, null, "Success Rate: ", toolCallStats.successRate.toFixed(1), "%")),
74
+ /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, null, "Session ID: ", SESSION_ID)),
75
+ /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, null, "Tool Calls: ", toolCallStats.total, " ( \u2713 ", toolCallStats.successful, " \u2717", " ", toolCallStats.failed, " )")),
76
+ /* @__PURE__ */ React.createElement(Box, { marginBottom: 1 }, /* @__PURE__ */ React.createElement(Text, null, "Success Rate: ", toolCallStats.successRate.toFixed(1), "%")),
70
77
  /* @__PURE__ */ React.createElement(Box, { marginTop: 1, marginBottom: 1 }, /* @__PURE__ */ React.createElement(Text, { bold: true }, "Performance")),
71
- /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, null, "Wall Time: ", wallTimeStr)),
72
- /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, null, "Agent Active: ", apiTimeStr)),
73
- /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, null, " \xBB API Time: ", apiTimeStr, " (", apiPercentage, "%)")),
74
- /* @__PURE__ */ React.createElement(Box, { marginBottom: 1 }, /* @__PURE__ */ React.createElement(Text, null, " \xBB Tool Time: ", toolTimeStr, " (", toolPercentage, "%)")),
75
- totalCost > 0 && /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, null, "Total Cost: $", totalCost > 0.5 ? totalCost.toFixed(2) : totalCost.toFixed(4)))
78
+ /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, null, "Wall Time: ", wallTimeStr)),
79
+ /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, null, "Agent Active: ", apiTimeStr)),
80
+ /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, null, " ", "\xBB API Time: ", apiTimeStr, " (", apiPercentage, "%)")),
81
+ /* @__PURE__ */ React.createElement(Box, { marginBottom: 1 }, /* @__PURE__ */ React.createElement(Text, null, " ", "\xBB Tool Time: ", toolTimeStr, " (", toolPercentage, "%)")),
82
+ totalCost > 0 && /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, null, "Total Cost: $", totalCost > 0.5 ? totalCost.toFixed(2) : totalCost.toFixed(4)))
76
83
  ));
77
84
  }
78
85
  export {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/components/QuitSummary.tsx"],
4
- "sourcesContent": ["import { Box, Text } from 'ink'\nimport * as React from 'react'\nimport { getTotalCost, getTotalDuration, getTotalAPIDuration } from '../cost-tracker'\nimport { SESSION_ID } from '../utils/log'\nimport type { Message } from '../query'\nimport { getTheme } from '@utils/theme'\nimport { formatDuration } from '@utils/format'\n\ninterface QuitSummaryProps {\n messages: Message[]\n onClose: () => void\n}\n\nexport function QuitSummary({ messages, onClose }: QuitSummaryProps): React.ReactNode {\n const theme = getTheme()\n\n // Calculate tool call statistics\n const toolCallStats = React.useMemo(() => {\n let totalCalls = 0\n let successfulCalls = 0\n let failedCalls = 0\n\n messages.forEach(message => {\n if (message.type === 'assistant' && Array.isArray(message.message.content)) {\n message.message.content.forEach(block => {\n if (block.type === 'tool_use') {\n totalCalls++\n }\n })\n }\n if (message.type === 'user' && Array.isArray(message.message.content)) {\n message.message.content.forEach(block => {\n if (block.type === 'tool_result') {\n if (!block.is_error) {\n successfulCalls++\n } else {\n failedCalls++\n }\n }\n })\n }\n })\n\n const successRate = totalCalls > 0 ? (successfulCalls / totalCalls) * 100 : 0\n\n return {\n total: totalCalls,\n successful: successfulCalls,\n failed: failedCalls,\n successRate,\n }\n }, [messages])\n\n const totalDuration = getTotalDuration()\n const apiDuration = getTotalAPIDuration()\n const toolDuration = totalDuration - apiDuration\n const totalCost = getTotalCost()\n\n // Format durations\n const wallTimeStr = formatDuration(totalDuration)\n const apiTimeStr = formatDuration(apiDuration)\n const toolTimeStr = formatDuration(toolDuration)\n const apiPercentage = totalDuration > 0 ? ((apiDuration / totalDuration) * 100).toFixed(1) : '0.0'\n const toolPercentage = totalDuration > 0 ? ((toolDuration / totalDuration) * 100).toFixed(1) : '0.0'\n\n React.useEffect(() => {\n // Automatically close after 3 seconds\n const timer = setTimeout(() => {\n onClose()\n }, 3000)\n\n return () => clearTimeout(timer)\n }, [onClose])\n\n return (\n <Box flexDirection=\"column\" paddingY={1}>\n <Box\n borderStyle=\"round\"\n borderColor={theme.minto}\n flexDirection=\"column\"\n paddingX={2}\n paddingY={1}\n >\n <Box marginBottom={1}>\n <Text bold color={theme.success}>Agent powering down. Goodbye!</Text>\n </Box>\n\n <Box marginBottom={1}>\n <Text bold>Interaction Summary</Text>\n </Box>\n\n <Box>\n <Text>Session ID: {SESSION_ID}</Text>\n </Box>\n\n <Box>\n <Text>\n Tool Calls: {toolCallStats.total} ( \u2713 {toolCallStats.successful} \u2717 {toolCallStats.failed} )\n </Text>\n </Box>\n\n <Box marginBottom={1}>\n <Text>Success Rate: {toolCallStats.successRate.toFixed(1)}%</Text>\n </Box>\n\n <Box marginTop={1} marginBottom={1}>\n <Text bold>Performance</Text>\n </Box>\n\n <Box>\n <Text>Wall Time: {wallTimeStr}</Text>\n </Box>\n\n <Box>\n <Text>Agent Active: {apiTimeStr}</Text>\n </Box>\n\n <Box>\n <Text> \u00BB API Time: {apiTimeStr} ({apiPercentage}%)</Text>\n </Box>\n\n <Box marginBottom={1}>\n <Text> \u00BB Tool Time: {toolTimeStr} ({toolPercentage}%)</Text>\n </Box>\n\n {totalCost > 0 && (\n <Box marginTop={1}>\n <Text>Total Cost: ${totalCost > 0.5 ? totalCost.toFixed(2) : totalCost.toFixed(4)}</Text>\n </Box>\n )}\n </Box>\n </Box>\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { Box, Text } from 'ink'\nimport * as React from 'react'\nimport {\n getTotalCost,\n getTotalDuration,\n getTotalAPIDuration,\n} from '../cost-tracker'\nimport { SESSION_ID } from '../utils/log'\nimport type { Message } from '../query'\nimport { getTheme } from '@utils/theme'\nimport { formatDuration } from '@utils/format'\n\ninterface QuitSummaryProps {\n messages: Message[]\n onClose: () => void\n}\n\nexport function QuitSummary({\n messages,\n onClose,\n}: QuitSummaryProps): React.ReactNode {\n const theme = getTheme()\n\n // Calculate tool call statistics\n const toolCallStats = React.useMemo(() => {\n let totalCalls = 0\n let successfulCalls = 0\n let failedCalls = 0\n\n messages.forEach(message => {\n if (\n message.type === 'assistant' &&\n Array.isArray(message.message.content)\n ) {\n message.message.content.forEach(block => {\n if (block.type === 'tool_use') {\n totalCalls++\n }\n })\n }\n if (message.type === 'user' && Array.isArray(message.message.content)) {\n message.message.content.forEach(block => {\n if (block.type === 'tool_result') {\n if (!block.is_error) {\n successfulCalls++\n } else {\n failedCalls++\n }\n }\n })\n }\n })\n\n const successRate =\n totalCalls > 0 ? (successfulCalls / totalCalls) * 100 : 0\n\n return {\n total: totalCalls,\n successful: successfulCalls,\n failed: failedCalls,\n successRate,\n }\n }, [messages])\n\n const totalDuration = getTotalDuration()\n const apiDuration = getTotalAPIDuration()\n const toolDuration = totalDuration - apiDuration\n const totalCost = getTotalCost()\n\n // Format durations\n const wallTimeStr = formatDuration(totalDuration)\n const apiTimeStr = formatDuration(apiDuration)\n const toolTimeStr = formatDuration(toolDuration)\n const apiPercentage =\n totalDuration > 0 ? ((apiDuration / totalDuration) * 100).toFixed(1) : '0.0'\n const toolPercentage =\n totalDuration > 0\n ? ((toolDuration / totalDuration) * 100).toFixed(1)\n : '0.0'\n\n React.useEffect(() => {\n // Automatically close after 3 seconds\n const timer = setTimeout(() => {\n onClose()\n }, 3000)\n\n return () => clearTimeout(timer)\n }, [onClose])\n\n return (\n <Box flexDirection=\"column\" paddingY={1}>\n <Box\n borderStyle=\"round\"\n borderColor={theme.minto}\n flexDirection=\"column\"\n paddingX={2}\n paddingY={1}\n >\n <Box marginBottom={1}>\n <Text bold color={theme.success}>\n Agent powering down. Goodbye!\n </Text>\n </Box>\n\n <Box marginBottom={1}>\n <Text bold>Interaction Summary</Text>\n </Box>\n\n <Box>\n <Text>Session ID: {SESSION_ID}</Text>\n </Box>\n\n <Box>\n <Text>\n Tool Calls: {toolCallStats.total} ( \u2713 {toolCallStats.successful} \u2717{' '}\n {toolCallStats.failed} )\n </Text>\n </Box>\n\n <Box marginBottom={1}>\n <Text>Success Rate: {toolCallStats.successRate.toFixed(1)}%</Text>\n </Box>\n\n <Box marginTop={1} marginBottom={1}>\n <Text bold>Performance</Text>\n </Box>\n\n <Box>\n <Text>Wall Time: {wallTimeStr}</Text>\n </Box>\n\n <Box>\n <Text>Agent Active: {apiTimeStr}</Text>\n </Box>\n\n <Box>\n <Text>\n {' '}\n \u00BB API Time: {apiTimeStr} ({apiPercentage}%)\n </Text>\n </Box>\n\n <Box marginBottom={1}>\n <Text>\n {' '}\n \u00BB Tool Time: {toolTimeStr} ({toolPercentage}%)\n </Text>\n </Box>\n\n {totalCost > 0 && (\n <Box marginTop={1}>\n <Text>\n Total Cost: $\n {totalCost > 0.5 ? totalCost.toFixed(2) : totalCost.toFixed(4)}\n </Text>\n </Box>\n )}\n </Box>\n </Box>\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/components/SentryErrorBoundary.ts"],
4
- "sourcesContent": ["import * as React from 'react'\nimport { captureException } from '@services/sentry'\n\ninterface Props {\n children: React.ReactNode\n}\n\ninterface State {\n hasError: boolean\n}\n\nexport class SentryErrorBoundary extends React.Component<Props, State> {\n constructor(props: Props) {\n super(props)\n ;(this as any).state = { hasError: false }\n }\n\n static getDerivedStateFromError(): State {\n return { hasError: true }\n }\n\n componentDidCatch(error: Error): void {\n // Don't report user-initiated cancellations to Sentry\n if (error.name === 'AbortError' || \n error.message?.includes('abort') ||\n error.message?.includes('The operation was aborted')) {\n return\n }\n captureException(error)\n }\n\n render(): React.ReactNode {\n if ((this as any).state.hasError) {\n return null\n }\n\n return (this as any).props.children\n }\n}\n"],
5
- "mappings": "AAAA,YAAY,WAAW;AACvB,SAAS,wBAAwB;AAU1B,MAAM,4BAA4B,MAAM,UAAwB;AAAA,EACrE,YAAY,OAAc;AACxB,UAAM,KAAK;AACV,IAAC,KAAa,QAAQ,EAAE,UAAU,MAAM;AAAA,EAC3C;AAAA,EAEA,OAAO,2BAAkC;AACvC,WAAO,EAAE,UAAU,KAAK;AAAA,EAC1B;AAAA,EAEA,kBAAkB,OAAoB;AAEpC,QAAI,MAAM,SAAS,gBACf,MAAM,SAAS,SAAS,OAAO,KAC/B,MAAM,SAAS,SAAS,2BAA2B,GAAG;AACxD;AAAA,IACF;AACA,qBAAiB,KAAK;AAAA,EACxB;AAAA,EAEA,SAA0B;AACxB,QAAK,KAAa,MAAM,UAAU;AAChC,aAAO;AAAA,IACT;AAEA,WAAQ,KAAa,MAAM;AAAA,EAC7B;AACF;",
4
+ "sourcesContent": ["import * as React from 'react'\nimport { captureException } from '@services/sentry'\n\ninterface Props {\n children: React.ReactNode\n}\n\ninterface State {\n hasError: boolean\n}\n\nexport class SentryErrorBoundary extends React.Component<Props, State> {\n constructor(props: Props) {\n super(props)\n ;(this as any).state = { hasError: false }\n }\n\n static getDerivedStateFromError(): State {\n return { hasError: true }\n }\n\n componentDidCatch(error: Error): void {\n // Don't report user-initiated cancellations to Sentry\n if (\n error.name === 'AbortError' ||\n error.message?.includes('abort') ||\n error.message?.includes('The operation was aborted')\n ) {\n return\n }\n captureException(error)\n }\n\n render(): React.ReactNode {\n if ((this as any).state.hasError) {\n return null\n }\n\n return (this as any).props.children\n }\n}\n"],
5
+ "mappings": "AAAA,YAAY,WAAW;AACvB,SAAS,wBAAwB;AAU1B,MAAM,4BAA4B,MAAM,UAAwB;AAAA,EACrE,YAAY,OAAc;AACxB,UAAM,KAAK;AACV,IAAC,KAAa,QAAQ,EAAE,UAAU,MAAM;AAAA,EAC3C;AAAA,EAEA,OAAO,2BAAkC;AACvC,WAAO,EAAE,UAAU,KAAK;AAAA,EAC1B;AAAA,EAEA,kBAAkB,OAAoB;AAEpC,QACE,MAAM,SAAS,gBACf,MAAM,SAAS,SAAS,OAAO,KAC/B,MAAM,SAAS,SAAS,2BAA2B,GACnD;AACA;AAAA,IACF;AACA,qBAAiB,KAAK;AAAA,EACxB;AAAA,EAEA,SAA0B;AACxB,QAAK,KAAa,MAAM,UAAU;AAChC,aAAO;AAAA,IACT;AAEA,WAAQ,KAAa,MAAM;AAAA,EAC7B;AACF;",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/components/StreamingBashOutput.tsx"],
4
- "sourcesContent": ["import { Box, Text, useInput } from 'ink'\nimport * as React from 'react'\nimport { useState, useEffect, useRef } from 'react'\nimport { getTheme } from '@utils/theme'\nimport { BackgroundShellManager } from '@utils/BackgroundShellManager'\n\ntype Props = {\n shellId: string\n command: string\n onMoveToBackground: () => void\n onComplete: (stdout: string, stderr: string, exitCode: number) => void\n}\n\nconst MAX_SUMMARY_LINES = 5 // Show only first few lines in summary mode\nconst MAX_DETAIL_LINES = 50 // Show more lines in detail mode\n\nexport function StreamingBashOutput({\n shellId,\n command,\n onMoveToBackground,\n onComplete,\n}: Props) {\n const [outputLines, setOutputLines] = useState<string[]>([])\n const [hiddenLineCount, setHiddenLineCount] = useState(0)\n const [elapsedTime, setElapsedTime] = useState(0)\n const [isComplete, setIsComplete] = useState(false)\n const [showDetail, setShowDetail] = useState(false) // Ctrl+O toggle\n const startTime = useRef(Date.now())\n const theme = getTheme()\n\n // Listen for keyboard shortcuts\n useInput((input, key) => {\n if (key.ctrl && input === 'b') {\n onMoveToBackground()\n } else if (key.ctrl && input === 'o') {\n setShowDetail(prev => !prev)\n }\n })\n\n // Update elapsed time\n useEffect(() => {\n const interval = setInterval(() => {\n setElapsedTime(Math.floor((Date.now() - startTime.current) / 1000))\n }, 1000)\n\n return () => clearInterval(interval)\n }, [])\n\n // Poll for output from background shell\n useEffect(() => {\n const manager = BackgroundShellManager.getInstance()\n\n const interval = setInterval(() => {\n const shell = manager.get(shellId)\n if (!shell) return\n\n // Get all output\n const allLines = [...shell.stdout, ...shell.stderr].filter(\n line => line.trim().length > 0,\n )\n setOutputLines(allLines)\n\n // Calculate hidden lines based on current mode\n const maxLines = showDetail ? MAX_DETAIL_LINES : MAX_SUMMARY_LINES\n if (allLines.length > maxLines) {\n setHiddenLineCount(allLines.length - maxLines)\n } else {\n setHiddenLineCount(0)\n }\n\n // Check if complete\n if (shell.status !== 'running' && !isComplete) {\n setIsComplete(true)\n clearInterval(interval)\n\n // Clean up the shell after getting final output\n const stdout = shell.stdout.join('\\n')\n const stderr = shell.stderr.join('\\n')\n const exitCode = shell.exitCode ?? 0\n\n // Remove from manager after a short delay\n setTimeout(() => {\n manager.remove(shellId)\n }, 1000)\n\n onComplete(stdout, stderr, exitCode)\n }\n }, 100)\n\n return () => clearInterval(interval)\n }, [shellId, isComplete, onComplete, showDetail])\n\n const maxLines = showDetail ? MAX_DETAIL_LINES : MAX_SUMMARY_LINES\n const visibleLines = outputLines.slice(0, maxLines) // Show first N lines, not last N\n\n return (\n <Box flexDirection=\"column\" marginTop={1}>\n <Box>\n <Text color={theme.bashBorder}>! </Text>\n <Text>{command}</Text>\n </Box>\n\n {visibleLines.length > 0 && (\n <Box flexDirection=\"column\" paddingLeft={2}>\n <Text color={theme.secondaryText}>\u23BF </Text>\n {visibleLines.map((line, index) => (\n <Box key={index}>\n <Text>{line}</Text>\n </Box>\n ))}\n </Box>\n )}\n\n {hiddenLineCount > 0 && (\n <Box paddingLeft={2}>\n <Text color={theme.secondaryText}>\n +{hiddenLineCount} more lines ({elapsedTime}s)\n </Text>\n </Box>\n )}\n\n {!isComplete && (\n <Box paddingLeft={2} marginTop={1} flexDirection=\"row\" gap={1}>\n <Text color={theme.secondaryText}>\n ctrl+o {showDetail ? 'hide details' : 'show details'}\n </Text>\n <Text color={theme.secondaryText}>\u00B7</Text>\n <Text color={theme.warning}>\n ctrl+b run in background\n </Text>\n </Box>\n )}\n </Box>\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { Box, Text, useInput } from 'ink'\nimport * as React from 'react'\nimport { useState, useEffect, useRef } from 'react'\nimport { getTheme } from '@utils/theme'\nimport { BackgroundShellManager } from '@utils/BackgroundShellManager'\n\ntype Props = {\n shellId: string\n command: string\n onMoveToBackground: () => void\n onComplete: (stdout: string, stderr: string, exitCode: number) => void\n}\n\nconst MAX_SUMMARY_LINES = 5 // Show only first few lines in summary mode\nconst MAX_DETAIL_LINES = 50 // Show more lines in detail mode\n\nexport function StreamingBashOutput({\n shellId,\n command,\n onMoveToBackground,\n onComplete,\n}: Props) {\n const [outputLines, setOutputLines] = useState<string[]>([])\n const [hiddenLineCount, setHiddenLineCount] = useState(0)\n const [elapsedTime, setElapsedTime] = useState(0)\n const [isComplete, setIsComplete] = useState(false)\n const [showDetail, setShowDetail] = useState(false) // Ctrl+O toggle\n const startTime = useRef(Date.now())\n const theme = getTheme()\n\n // Listen for keyboard shortcuts\n useInput((input, key) => {\n if (key.ctrl && input === 'b') {\n onMoveToBackground()\n } else if (key.ctrl && input === 'o') {\n setShowDetail(prev => !prev)\n }\n })\n\n // Update elapsed time\n useEffect(() => {\n const interval = setInterval(() => {\n setElapsedTime(Math.floor((Date.now() - startTime.current) / 1000))\n }, 1000)\n\n return () => clearInterval(interval)\n }, [])\n\n // Poll for output from background shell\n useEffect(() => {\n const manager = BackgroundShellManager.getInstance()\n\n const interval = setInterval(() => {\n const shell = manager.get(shellId)\n if (!shell) return\n\n // Get all output\n const allLines = [...shell.stdout, ...shell.stderr].filter(\n line => line.trim().length > 0,\n )\n setOutputLines(allLines)\n\n // Calculate hidden lines based on current mode\n const maxLines = showDetail ? MAX_DETAIL_LINES : MAX_SUMMARY_LINES\n if (allLines.length > maxLines) {\n setHiddenLineCount(allLines.length - maxLines)\n } else {\n setHiddenLineCount(0)\n }\n\n // Check if complete\n if (shell.status !== 'running' && !isComplete) {\n setIsComplete(true)\n clearInterval(interval)\n\n // Clean up the shell after getting final output\n const stdout = shell.stdout.join('\\n')\n const stderr = shell.stderr.join('\\n')\n const exitCode = shell.exitCode ?? 0\n\n // Remove from manager after a short delay\n setTimeout(() => {\n manager.remove(shellId)\n }, 1000)\n\n onComplete(stdout, stderr, exitCode)\n }\n }, 100)\n\n return () => clearInterval(interval)\n }, [shellId, isComplete, onComplete, showDetail])\n\n const maxLines = showDetail ? MAX_DETAIL_LINES : MAX_SUMMARY_LINES\n const visibleLines = outputLines.slice(0, maxLines) // Show first N lines, not last N\n\n return (\n <Box flexDirection=\"column\" marginTop={1}>\n <Box>\n <Text color={theme.bashBorder}>! </Text>\n <Text>{command}</Text>\n </Box>\n\n {visibleLines.length > 0 && (\n <Box flexDirection=\"column\" paddingLeft={2}>\n <Text color={theme.secondaryText}>\u23BF </Text>\n {visibleLines.map((line, index) => (\n <Box key={index}>\n <Text>{line}</Text>\n </Box>\n ))}\n </Box>\n )}\n\n {hiddenLineCount > 0 && (\n <Box paddingLeft={2}>\n <Text color={theme.secondaryText}>\n +{hiddenLineCount} more lines ({elapsedTime}s)\n </Text>\n </Box>\n )}\n\n {!isComplete && (\n <Box paddingLeft={2} marginTop={1} flexDirection=\"row\" gap={1}>\n <Text color={theme.secondaryText}>\n ctrl+o {showDetail ? 'hide details' : 'show details'}\n </Text>\n <Text color={theme.secondaryText}>\u00B7</Text>\n <Text color={theme.warning}>ctrl+b run in background</Text>\n </Box>\n )}\n </Box>\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["maxLines"]
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/components/StructuredDiff.tsx"],
4
- "sourcesContent": ["import { Box, Text } from 'ink'\nimport * as React from 'react'\nimport { Hunk } from 'diff'\nimport { getTheme, ThemeNames } from '@utils/theme'\nimport { useMemo } from 'react'\nimport { wrapText } from '@utils/format'\n\ntype Props = {\n patch: Hunk\n dim: boolean\n width: number\n overrideTheme?: ThemeNames // custom theme for previews\n key?: React.Key\n}\n\nexport function StructuredDiff({\n patch,\n dim,\n width,\n overrideTheme,\n}: Props): React.ReactNode {\n const diff = useMemo(\n () => formatDiff(patch.lines, patch.oldStart, width, dim, overrideTheme),\n [patch.lines, patch.oldStart, width, dim, overrideTheme],\n )\n\n return diff.map((_, i) => <Box key={i}>{_}</Box>)\n}\n\nfunction formatDiff(\n lines: string[],\n startingLineNumber: number,\n width: number,\n dim: boolean,\n overrideTheme?: ThemeNames,\n): React.ReactNode[] {\n const theme = getTheme(overrideTheme)\n\n const ls = numberDiffLines(\n lines.map(code => {\n if (code.startsWith('+')) {\n return {\n code: ' ' + code.slice(1),\n i: 0,\n type: 'add',\n }\n }\n if (code.startsWith('-')) {\n return {\n code: ' ' + code.slice(1),\n i: 0,\n type: 'remove',\n }\n }\n return { code, i: 0, type: 'nochange' }\n }),\n startingLineNumber,\n )\n\n const maxLineNumber = Math.max(...ls.map(({ i }) => i))\n const maxWidth = maxLineNumber.toString().length\n\n return ls.flatMap(({ type, code, i }) => {\n const wrappedLines = wrapText(code, width - maxWidth)\n return wrappedLines.map((line, lineIndex) => {\n const key = `${type}-${i}-${lineIndex}`\n switch (type) {\n case 'add':\n return (\n <React.Fragment key={key}>\n <Text>\n <LineNumber\n i={lineIndex === 0 ? i : undefined}\n width={maxWidth}\n />\n <Text\n color={overrideTheme ? theme.text : undefined}\n backgroundColor={\n dim ? theme.diff.addedDimmed : theme.diff.added\n }\n dimColor={dim}\n >\n {line}\n </Text>\n </Text>\n </React.Fragment>\n )\n case 'remove':\n return (\n <React.Fragment key={key}>\n <Text>\n <LineNumber\n i={lineIndex === 0 ? i : undefined}\n width={maxWidth}\n />\n <Text\n color={overrideTheme ? theme.text : undefined}\n backgroundColor={\n dim ? theme.diff.removedDimmed : theme.diff.removed\n }\n dimColor={dim}\n >\n {line}\n </Text>\n </Text>\n </React.Fragment>\n )\n case 'nochange':\n return (\n <React.Fragment key={key}>\n <Text>\n <LineNumber\n i={lineIndex === 0 ? i : undefined}\n width={maxWidth}\n />\n <Text\n color={overrideTheme ? theme.text : undefined}\n dimColor={dim}\n >\n {line}\n </Text>\n </Text>\n </React.Fragment>\n )\n }\n })\n })\n}\n\nfunction LineNumber({\n i,\n width,\n}: {\n i: number | undefined\n width: number\n}): React.ReactNode {\n return (\n <Text color={getTheme().secondaryText}>\n {i !== undefined ? i.toString().padStart(width) : ' '.repeat(width)}{' '}\n </Text>\n )\n}\n\nfunction numberDiffLines(\n diff: { code: string; type: string }[],\n startLine: number,\n): { code: string; type: string; i: number }[] {\n let i = startLine\n const result: { code: string; type: string; i: number }[] = []\n const queue = [...diff]\n\n while (queue.length > 0) {\n const { code, type } = queue.shift()!\n const line = {\n code: code,\n type,\n i,\n }\n\n // Update counters based on change type\n switch (type) {\n case 'nochange':\n i++\n result.push(line)\n break\n case 'add':\n i++\n result.push(line)\n break\n case 'remove': {\n result.push(line)\n let numRemoved = 0\n while (queue[0]?.type === 'remove') {\n i++\n const { code, type } = queue.shift()!\n const line = {\n code: code,\n type,\n i,\n }\n result.push(line)\n numRemoved++\n }\n i -= numRemoved\n break\n }\n }\n }\n\n return result\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { Box, Text } from 'ink'\nimport * as React from 'react'\nimport { Hunk } from 'diff'\nimport { getTheme, ThemeNames } from '@utils/theme'\nimport { useMemo } from 'react'\nimport { wrapText } from '@utils/format'\n\ntype Props = {\n patch: Hunk\n dim: boolean\n width: number\n overrideTheme?: ThemeNames // custom theme for previews\n key?: React.Key\n}\n\nexport function StructuredDiff({\n patch,\n dim,\n width,\n overrideTheme,\n}: Props): React.ReactNode {\n const diff = useMemo(\n () => formatDiff(patch.lines, patch.oldStart, width, dim, overrideTheme),\n [patch.lines, patch.oldStart, width, dim, overrideTheme],\n )\n\n return diff.map((_, i) => <Box key={i}>{_}</Box>)\n}\n\nfunction formatDiff(\n lines: string[],\n startingLineNumber: number,\n width: number,\n dim: boolean,\n overrideTheme?: ThemeNames,\n): React.ReactNode[] {\n const theme = getTheme(overrideTheme)\n\n const ls = numberDiffLines(\n lines.map(code => {\n if (code.startsWith('+')) {\n return {\n code: ' ' + code.slice(1),\n i: 0,\n type: 'add',\n }\n }\n if (code.startsWith('-')) {\n return {\n code: ' ' + code.slice(1),\n i: 0,\n type: 'remove',\n }\n }\n return { code, i: 0, type: 'nochange' }\n }),\n startingLineNumber,\n )\n\n const maxLineNumber = Math.max(...ls.map(({ i }) => i))\n const maxWidth = maxLineNumber.toString().length\n\n return ls.flatMap(({ type, code, i }) => {\n const wrappedLines = wrapText(code, width - maxWidth)\n return wrappedLines.map((line, lineIndex) => {\n const key = `${type}-${i}-${lineIndex}`\n switch (type) {\n case 'add':\n return (\n <React.Fragment key={key}>\n <Text>\n <LineNumber\n i={lineIndex === 0 ? i : undefined}\n width={maxWidth}\n />\n <Text\n color={overrideTheme ? theme.text : undefined}\n backgroundColor={\n dim ? theme.diff.addedDimmed : theme.diff.added\n }\n dimColor={dim}\n >\n {line}\n </Text>\n </Text>\n </React.Fragment>\n )\n case 'remove':\n return (\n <React.Fragment key={key}>\n <Text>\n <LineNumber\n i={lineIndex === 0 ? i : undefined}\n width={maxWidth}\n />\n <Text\n color={overrideTheme ? theme.text : undefined}\n backgroundColor={\n dim ? theme.diff.removedDimmed : theme.diff.removed\n }\n dimColor={dim}\n >\n {line}\n </Text>\n </Text>\n </React.Fragment>\n )\n case 'nochange':\n return (\n <React.Fragment key={key}>\n <Text>\n <LineNumber\n i={lineIndex === 0 ? i : undefined}\n width={maxWidth}\n />\n <Text\n color={overrideTheme ? theme.text : undefined}\n dimColor={dim}\n >\n {line}\n </Text>\n </Text>\n </React.Fragment>\n )\n }\n })\n })\n}\n\nfunction LineNumber({\n i,\n width,\n}: {\n i: number | undefined\n width: number\n}): React.ReactNode {\n return (\n <Text color={getTheme().secondaryText}>\n {i !== undefined ? i.toString().padStart(width) : ' '.repeat(width)}{' '}\n </Text>\n )\n}\n\nfunction numberDiffLines(\n diff: { code: string; type: string }[],\n startLine: number,\n): { code: string; type: string; i: number }[] {\n let i = startLine\n const result: { code: string; type: string; i: number }[] = []\n const queue = [...diff]\n\n while (queue.length > 0) {\n const { code, type } = queue.shift()!\n const line = {\n code: code,\n type,\n i,\n }\n\n // Update counters based on change type\n switch (type) {\n case 'nochange':\n i++\n result.push(line)\n break\n case 'add':\n i++\n result.push(line)\n break\n case 'remove': {\n result.push(line)\n let numRemoved = 0\n while (queue[0]?.type === 'remove') {\n i++\n const { code, type } = queue.shift()!\n const line = {\n code: code,\n type,\n i,\n }\n result.push(line)\n numRemoved++\n }\n i -= numRemoved\n break\n }\n }\n }\n\n return result\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["code", "type", "line"]
7
7
  }