fss-link 1.0.40 → 1.0.45

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 (428) hide show
  1. package/dist/commands/mcp/add.test.ts +122 -0
  2. package/dist/commands/mcp/add.ts +222 -0
  3. package/dist/commands/mcp/list.test.ts +154 -0
  4. package/dist/commands/mcp/list.ts +139 -0
  5. package/dist/commands/mcp/remove.test.ts +69 -0
  6. package/dist/commands/mcp/remove.ts +60 -0
  7. package/dist/commands/mcp.test.ts +55 -0
  8. package/dist/commands/mcp.ts +27 -0
  9. package/dist/config/apiValidation.test.ts +118 -0
  10. package/dist/config/auth.test.ts +79 -0
  11. package/dist/config/auth.ts +100 -0
  12. package/dist/config/config.integration.test.ts +407 -0
  13. package/dist/config/config.test.ts +1952 -0
  14. package/dist/config/config.ts +690 -0
  15. package/dist/config/database.test.ts +96 -0
  16. package/dist/config/database.ts +752 -0
  17. package/dist/config/extension.test.ts +236 -0
  18. package/dist/config/extension.ts +180 -0
  19. package/dist/config/keyBindings.test.ts +62 -0
  20. package/dist/config/keyBindings.ts +184 -0
  21. package/dist/config/modelManager.ts +275 -0
  22. package/dist/config/providerManager.ts +244 -0
  23. package/dist/config/providerPersistence.test.ts +377 -0
  24. package/dist/config/providerPersistence.ts +105 -0
  25. package/dist/config/sandboxConfig.ts +107 -0
  26. package/dist/config/settings.test.ts +1424 -0
  27. package/dist/config/settings.ts +517 -0
  28. package/dist/config/settingsSchema.test.ts +252 -0
  29. package/dist/config/settingsSchema.ts +728 -0
  30. package/dist/config/trustedFolders.test.ts +208 -0
  31. package/dist/config/trustedFolders.ts +167 -0
  32. package/dist/gemini.test.tsx +252 -0
  33. package/dist/gemini.tsx +357 -0
  34. package/dist/generated/git-commit.ts +10 -0
  35. package/dist/index.ts +21 -0
  36. package/dist/nonInteractiveCli.test.ts +276 -0
  37. package/dist/nonInteractiveCli.ts +143 -0
  38. package/dist/package.json +87 -87
  39. package/dist/patches/is-in-ci.ts +17 -0
  40. package/dist/services/BuiltinCommandLoader.test.ts +127 -0
  41. package/dist/services/BuiltinCommandLoader.ts +95 -0
  42. package/dist/services/CommandService.test.ts +352 -0
  43. package/dist/services/CommandService.ts +103 -0
  44. package/dist/services/FileCommandLoader.test.ts +1002 -0
  45. package/dist/services/FileCommandLoader.ts +289 -0
  46. package/dist/services/McpPromptLoader.ts +231 -0
  47. package/dist/services/SearchEngineConfigProvider.ts +100 -0
  48. package/dist/services/prompt-processors/argumentProcessor.test.ts +41 -0
  49. package/dist/services/prompt-processors/argumentProcessor.ts +23 -0
  50. package/dist/services/prompt-processors/shellProcessor.test.ts +709 -0
  51. package/dist/services/prompt-processors/shellProcessor.ts +248 -0
  52. package/dist/services/prompt-processors/types.ts +44 -0
  53. package/dist/services/types.ts +24 -0
  54. package/dist/src/config/apiValidation.test.d.ts +6 -0
  55. package/dist/src/config/apiValidation.test.js +99 -0
  56. package/dist/src/config/apiValidation.test.js.map +1 -0
  57. package/dist/src/config/database.d.ts +32 -0
  58. package/dist/src/config/database.js +281 -2
  59. package/dist/src/config/database.js.map +1 -1
  60. package/dist/src/config/database.test.d.ts +6 -0
  61. package/dist/src/config/database.test.js +80 -0
  62. package/dist/src/config/database.test.js.map +1 -0
  63. package/dist/src/config/providerManager.d.ts +74 -0
  64. package/dist/src/config/providerManager.js +203 -0
  65. package/dist/src/config/providerManager.js.map +1 -0
  66. package/dist/src/config/providerPersistence.d.ts +75 -0
  67. package/dist/src/config/providerPersistence.js +55 -0
  68. package/dist/src/config/providerPersistence.js.map +1 -0
  69. package/dist/src/config/providerPersistence.test.d.ts +6 -0
  70. package/dist/src/config/providerPersistence.test.js +283 -0
  71. package/dist/src/config/providerPersistence.test.js.map +1 -0
  72. package/dist/src/config/settingsSchema.d.ts +9 -0
  73. package/dist/src/config/settingsSchema.js +9 -0
  74. package/dist/src/config/settingsSchema.js.map +1 -1
  75. package/dist/src/generated/git-commit.d.ts +1 -1
  76. package/dist/src/generated/git-commit.js +1 -1
  77. package/dist/src/services/BuiltinCommandLoader.js +2 -0
  78. package/dist/src/services/BuiltinCommandLoader.js.map +1 -1
  79. package/dist/src/ui/App.js +14 -2
  80. package/dist/src/ui/App.js.map +1 -1
  81. package/dist/src/ui/commands/contextCommand.d.ts +7 -0
  82. package/dist/src/ui/commands/contextCommand.js +115 -0
  83. package/dist/src/ui/commands/contextCommand.js.map +1 -0
  84. package/dist/src/ui/components/ContextUsageDisplay.d.ts +3 -1
  85. package/dist/src/ui/components/ContextUsageDisplay.js +43 -3
  86. package/dist/src/ui/components/ContextUsageDisplay.js.map +1 -1
  87. package/dist/src/ui/components/Footer.d.ts +1 -0
  88. package/dist/src/ui/components/Footer.js +2 -2
  89. package/dist/src/ui/components/Footer.js.map +1 -1
  90. package/dist/src/ui/components/GeminiKeyDialog.d.ts +11 -0
  91. package/dist/src/ui/components/GeminiKeyDialog.js +156 -0
  92. package/dist/src/ui/components/GeminiKeyDialog.js.map +1 -0
  93. package/dist/src/ui/components/OpenAIEndpointDialog.d.ts +19 -0
  94. package/dist/src/ui/components/OpenAIEndpointDialog.js +163 -0
  95. package/dist/src/ui/components/OpenAIEndpointDialog.js.map +1 -0
  96. package/dist/src/ui/components/WelcomeBackDialog.d.ts +36 -0
  97. package/dist/src/ui/components/WelcomeBackDialog.js +109 -0
  98. package/dist/src/ui/components/WelcomeBackDialog.js.map +1 -0
  99. package/dist/src/ui/hooks/useWelcomeBack.d.ts +52 -0
  100. package/dist/src/ui/hooks/useWelcomeBack.js +214 -0
  101. package/dist/src/ui/hooks/useWelcomeBack.js.map +1 -0
  102. package/dist/src/zed-integration/schema.d.ts +1516 -1516
  103. package/dist/test-setup.ts +12 -0
  104. package/dist/test-utils/customMatchers.ts +65 -0
  105. package/dist/test-utils/mockCommandContext.test.ts +62 -0
  106. package/dist/test-utils/mockCommandContext.ts +105 -0
  107. package/dist/test-utils/render.tsx +18 -0
  108. package/dist/tsconfig.tsbuildinfo +1 -1
  109. package/dist/ui/App.test.tsx +2181 -0
  110. package/dist/ui/App.tsx +1344 -0
  111. package/dist/ui/IdeIntegrationNudge.tsx +98 -0
  112. package/dist/ui/__snapshots__/App.test.tsx.snap +124 -0
  113. package/dist/ui/colors.ts +56 -0
  114. package/dist/ui/commands/aboutCommand.test.ts +153 -0
  115. package/dist/ui/commands/aboutCommand.ts +49 -0
  116. package/dist/ui/commands/authCommand.test.ts +36 -0
  117. package/dist/ui/commands/authCommand.ts +17 -0
  118. package/dist/ui/commands/bugCommand.test.ts +114 -0
  119. package/dist/ui/commands/bugCommand.ts +92 -0
  120. package/dist/ui/commands/chatCommand.test.ts +414 -0
  121. package/dist/ui/commands/chatCommand.ts +280 -0
  122. package/dist/ui/commands/clearCommand.test.ts +100 -0
  123. package/dist/ui/commands/clearCommand.ts +29 -0
  124. package/dist/ui/commands/compressCommand.test.ts +129 -0
  125. package/dist/ui/commands/compressCommand.ts +78 -0
  126. package/dist/ui/commands/contextCommand.ts +132 -0
  127. package/dist/ui/commands/copyCommand.test.ts +296 -0
  128. package/dist/ui/commands/copyCommand.ts +67 -0
  129. package/dist/ui/commands/corgiCommand.test.ts +34 -0
  130. package/dist/ui/commands/corgiCommand.ts +16 -0
  131. package/dist/ui/commands/directoryCommand.test.tsx +185 -0
  132. package/dist/ui/commands/directoryCommand.tsx +179 -0
  133. package/dist/ui/commands/docsCommand.test.ts +99 -0
  134. package/dist/ui/commands/docsCommand.ts +42 -0
  135. package/dist/ui/commands/editorCommand.test.ts +30 -0
  136. package/dist/ui/commands/editorCommand.ts +21 -0
  137. package/dist/ui/commands/extensionsCommand.test.ts +67 -0
  138. package/dist/ui/commands/extensionsCommand.ts +46 -0
  139. package/dist/ui/commands/helpCommand.test.ts +52 -0
  140. package/dist/ui/commands/helpCommand.ts +23 -0
  141. package/dist/ui/commands/ideCommand.test.ts +255 -0
  142. package/dist/ui/commands/ideCommand.ts +283 -0
  143. package/dist/ui/commands/initCommand.test.ts +127 -0
  144. package/dist/ui/commands/initCommand.ts +117 -0
  145. package/dist/ui/commands/mcpCommand.test.ts +1057 -0
  146. package/dist/ui/commands/mcpCommand.ts +531 -0
  147. package/dist/ui/commands/memoryCommand.test.ts +344 -0
  148. package/dist/ui/commands/memoryCommand.ts +305 -0
  149. package/dist/ui/commands/privacyCommand.test.ts +38 -0
  150. package/dist/ui/commands/privacyCommand.ts +17 -0
  151. package/dist/ui/commands/quitCommand.test.ts +55 -0
  152. package/dist/ui/commands/quitCommand.ts +36 -0
  153. package/dist/ui/commands/restoreCommand.test.ts +250 -0
  154. package/dist/ui/commands/restoreCommand.ts +157 -0
  155. package/dist/ui/commands/searchEngineSetupCommand.ts +18 -0
  156. package/dist/ui/commands/settingsCommand.test.ts +36 -0
  157. package/dist/ui/commands/settingsCommand.ts +17 -0
  158. package/dist/ui/commands/setupGithubCommand.test.ts +238 -0
  159. package/dist/ui/commands/setupGithubCommand.ts +212 -0
  160. package/dist/ui/commands/speakCommand.ts +175 -0
  161. package/dist/ui/commands/statsCommand.test.ts +78 -0
  162. package/dist/ui/commands/statsCommand.ts +70 -0
  163. package/dist/ui/commands/terminalSetupCommand.test.ts +85 -0
  164. package/dist/ui/commands/terminalSetupCommand.ts +45 -0
  165. package/dist/ui/commands/themeCommand.test.ts +38 -0
  166. package/dist/ui/commands/themeCommand.ts +17 -0
  167. package/dist/ui/commands/toolsCommand.test.ts +105 -0
  168. package/dist/ui/commands/toolsCommand.ts +71 -0
  169. package/dist/ui/commands/ttsCommand.ts +143 -0
  170. package/dist/ui/commands/types.ts +204 -0
  171. package/dist/ui/commands/vimCommand.ts +25 -0
  172. package/dist/ui/commands/voiceCommand.ts +125 -0
  173. package/dist/ui/components/AboutBox.tsx +133 -0
  174. package/dist/ui/components/AsciiArt.ts +54 -0
  175. package/dist/ui/components/AuthDialog.test.tsx +334 -0
  176. package/dist/ui/components/AuthDialog.tsx +289 -0
  177. package/dist/ui/components/AuthInProgress.tsx +62 -0
  178. package/dist/ui/components/AutoAcceptIndicator.tsx +47 -0
  179. package/dist/ui/components/ConsoleSummaryDisplay.tsx +35 -0
  180. package/dist/ui/components/ContextSummaryDisplay.test.tsx +85 -0
  181. package/dist/ui/components/ContextSummaryDisplay.tsx +120 -0
  182. package/dist/ui/components/ContextUsageDisplay.tsx +77 -0
  183. package/dist/ui/components/DebugProfiler.tsx +36 -0
  184. package/dist/ui/components/DetailedMessagesDisplay.tsx +82 -0
  185. package/dist/ui/components/EditorSettingsDialog.tsx +172 -0
  186. package/dist/ui/components/FolderTrustDialog.test.tsx +36 -0
  187. package/dist/ui/components/FolderTrustDialog.tsx +74 -0
  188. package/dist/ui/components/Footer.test.tsx +159 -0
  189. package/dist/ui/components/Footer.tsx +158 -0
  190. package/dist/ui/components/GeminiKeyDialog.tsx +252 -0
  191. package/dist/ui/components/GeminiRespondingSpinner.tsx +34 -0
  192. package/dist/ui/components/Header.test.tsx +44 -0
  193. package/dist/ui/components/Header.tsx +70 -0
  194. package/dist/ui/components/Help.tsx +174 -0
  195. package/dist/ui/components/HistoryItemDisplay.test.tsx +125 -0
  196. package/dist/ui/components/HistoryItemDisplay.tsx +98 -0
  197. package/dist/ui/components/InputPrompt.test.tsx +1467 -0
  198. package/dist/ui/components/InputPrompt.tsx +641 -0
  199. package/dist/ui/components/LMStudioModelPrompt.tsx +215 -0
  200. package/dist/ui/components/LoadingIndicator.test.tsx +296 -0
  201. package/dist/ui/components/LoadingIndicator.tsx +82 -0
  202. package/dist/ui/components/MemoryUsageDisplay.tsx +36 -0
  203. package/dist/ui/components/ModelStatsDisplay.test.tsx +252 -0
  204. package/dist/ui/components/ModelStatsDisplay.tsx +197 -0
  205. package/dist/ui/components/OllamaModelPrompt.tsx +206 -0
  206. package/dist/ui/components/OpenAIEndpointDialog.tsx +261 -0
  207. package/dist/ui/components/OpenAIKeyPrompt.test.tsx +64 -0
  208. package/dist/ui/components/OpenAIKeyPrompt.tsx +197 -0
  209. package/dist/ui/components/PrepareLabel.tsx +48 -0
  210. package/dist/ui/components/SearchEngineConfigDialog.tsx +280 -0
  211. package/dist/ui/components/SessionSummaryDisplay.test.tsx +75 -0
  212. package/dist/ui/components/SessionSummaryDisplay.tsx +18 -0
  213. package/dist/ui/components/SettingsDialog.test.tsx +865 -0
  214. package/dist/ui/components/SettingsDialog.tsx +753 -0
  215. package/dist/ui/components/ShellConfirmationDialog.test.tsx +53 -0
  216. package/dist/ui/components/ShellConfirmationDialog.tsx +103 -0
  217. package/dist/ui/components/ShellModeIndicator.tsx +18 -0
  218. package/dist/ui/components/ShowMoreLines.tsx +40 -0
  219. package/dist/ui/components/StatsDisplay.test.tsx +401 -0
  220. package/dist/ui/components/StatsDisplay.tsx +273 -0
  221. package/dist/ui/components/SuggestionsDisplay.tsx +102 -0
  222. package/dist/ui/components/ThemeDialog.tsx +310 -0
  223. package/dist/ui/components/Tips.tsx +45 -0
  224. package/dist/ui/components/TodoDisplay.test.tsx +97 -0
  225. package/dist/ui/components/TodoDisplay.tsx +72 -0
  226. package/dist/ui/components/ToolStatsDisplay.test.tsx +180 -0
  227. package/dist/ui/components/ToolStatsDisplay.tsx +208 -0
  228. package/dist/ui/components/UpdateNotification.tsx +23 -0
  229. package/dist/ui/components/WelcomeBackDialog.tsx +290 -0
  230. package/dist/ui/components/__snapshots__/IDEContextDetailDisplay.test.tsx.snap +24 -0
  231. package/dist/ui/components/__snapshots__/ModelStatsDisplay.test.tsx.snap +121 -0
  232. package/dist/ui/components/__snapshots__/SessionSummaryDisplay.test.tsx.snap +30 -0
  233. package/dist/ui/components/__snapshots__/ShellConfirmationDialog.test.tsx.snap +21 -0
  234. package/dist/ui/components/__snapshots__/StatsDisplay.test.tsx.snap +264 -0
  235. package/dist/ui/components/__snapshots__/ToolStatsDisplay.test.tsx.snap +91 -0
  236. package/dist/ui/components/messages/CompressionMessage.tsx +49 -0
  237. package/dist/ui/components/messages/DiffRenderer.test.tsx +365 -0
  238. package/dist/ui/components/messages/DiffRenderer.tsx +358 -0
  239. package/dist/ui/components/messages/ErrorMessage.tsx +31 -0
  240. package/dist/ui/components/messages/GeminiMessage.tsx +43 -0
  241. package/dist/ui/components/messages/GeminiMessageContent.tsx +43 -0
  242. package/dist/ui/components/messages/InfoMessage.tsx +32 -0
  243. package/dist/ui/components/messages/ToolConfirmationMessage.test.tsx +58 -0
  244. package/dist/ui/components/messages/ToolConfirmationMessage.tsx +297 -0
  245. package/dist/ui/components/messages/ToolGroupMessage.tsx +126 -0
  246. package/dist/ui/components/messages/ToolMessage.test.tsx +183 -0
  247. package/dist/ui/components/messages/ToolMessage.tsx +296 -0
  248. package/dist/ui/components/messages/UserMessage.tsx +43 -0
  249. package/dist/ui/components/messages/UserShellMessage.tsx +25 -0
  250. package/dist/ui/components/shared/MaxSizedBox.test.tsx +425 -0
  251. package/dist/ui/components/shared/MaxSizedBox.tsx +624 -0
  252. package/dist/ui/components/shared/RadioButtonSelect.test.tsx +181 -0
  253. package/dist/ui/components/shared/RadioButtonSelect.tsx +234 -0
  254. package/dist/ui/components/shared/__snapshots__/RadioButtonSelect.test.tsx.snap +47 -0
  255. package/dist/ui/components/shared/text-buffer.test.ts +1728 -0
  256. package/dist/ui/components/shared/text-buffer.ts +2227 -0
  257. package/dist/ui/components/shared/vim-buffer-actions.test.ts +1119 -0
  258. package/dist/ui/components/shared/vim-buffer-actions.ts +814 -0
  259. package/dist/ui/constants.ts +17 -0
  260. package/dist/ui/contexts/KeypressContext.test.tsx +391 -0
  261. package/dist/ui/contexts/KeypressContext.tsx +440 -0
  262. package/dist/ui/contexts/OverflowContext.tsx +87 -0
  263. package/dist/ui/contexts/SessionContext.test.tsx +132 -0
  264. package/dist/ui/contexts/SessionContext.tsx +143 -0
  265. package/dist/ui/contexts/SettingsContext.tsx +20 -0
  266. package/dist/ui/contexts/StreamingContext.tsx +22 -0
  267. package/dist/ui/contexts/VimModeContext.tsx +79 -0
  268. package/dist/ui/editors/editorSettingsManager.ts +66 -0
  269. package/dist/ui/hooks/atCommandProcessor.test.ts +1102 -0
  270. package/dist/ui/hooks/atCommandProcessor.ts +485 -0
  271. package/dist/ui/hooks/shellCommandProcessor.test.ts +481 -0
  272. package/dist/ui/hooks/shellCommandProcessor.ts +314 -0
  273. package/dist/ui/hooks/slashCommandProcessor.test.ts +1044 -0
  274. package/dist/ui/hooks/slashCommandProcessor.ts +595 -0
  275. package/dist/ui/hooks/useAtCompletion.test.ts +497 -0
  276. package/dist/ui/hooks/useAtCompletion.ts +244 -0
  277. package/dist/ui/hooks/useAuthCommand.ts +129 -0
  278. package/dist/ui/hooks/useAutoAcceptIndicator.test.ts +300 -0
  279. package/dist/ui/hooks/useAutoAcceptIndicator.ts +52 -0
  280. package/dist/ui/hooks/useBracketedPaste.ts +37 -0
  281. package/dist/ui/hooks/useCommandCompletion.test.ts +518 -0
  282. package/dist/ui/hooks/useCommandCompletion.tsx +238 -0
  283. package/dist/ui/hooks/useCompletion.ts +128 -0
  284. package/dist/ui/hooks/useConsoleMessages.test.ts +147 -0
  285. package/dist/ui/hooks/useConsoleMessages.ts +110 -0
  286. package/dist/ui/hooks/useEditorSettings.test.ts +283 -0
  287. package/dist/ui/hooks/useEditorSettings.ts +75 -0
  288. package/dist/ui/hooks/useFocus.test.ts +119 -0
  289. package/dist/ui/hooks/useFocus.ts +48 -0
  290. package/dist/ui/hooks/useFolderTrust.test.ts +159 -0
  291. package/dist/ui/hooks/useFolderTrust.ts +72 -0
  292. package/dist/ui/hooks/useGeminiStream.test.tsx +1998 -0
  293. package/dist/ui/hooks/useGeminiStream.ts +1017 -0
  294. package/dist/ui/hooks/useGitBranchName.test.ts +280 -0
  295. package/dist/ui/hooks/useGitBranchName.ts +79 -0
  296. package/dist/ui/hooks/useHistoryManager.test.ts +202 -0
  297. package/dist/ui/hooks/useHistoryManager.ts +111 -0
  298. package/dist/ui/hooks/useInputHistory.test.ts +261 -0
  299. package/dist/ui/hooks/useInputHistory.ts +111 -0
  300. package/dist/ui/hooks/useKeypress.test.ts +280 -0
  301. package/dist/ui/hooks/useKeypress.ts +39 -0
  302. package/dist/ui/hooks/useKittyKeyboardProtocol.ts +31 -0
  303. package/dist/ui/hooks/useLoadingIndicator.test.ts +139 -0
  304. package/dist/ui/hooks/useLoadingIndicator.ts +57 -0
  305. package/dist/ui/hooks/useLogger.ts +32 -0
  306. package/dist/ui/hooks/useMessageQueue.test.ts +226 -0
  307. package/dist/ui/hooks/useMessageQueue.ts +69 -0
  308. package/dist/ui/hooks/usePhraseCycler.test.ts +145 -0
  309. package/dist/ui/hooks/usePhraseCycler.ts +198 -0
  310. package/dist/ui/hooks/usePrivacySettings.test.ts +242 -0
  311. package/dist/ui/hooks/usePrivacySettings.ts +150 -0
  312. package/dist/ui/hooks/useReactToolScheduler.ts +309 -0
  313. package/dist/ui/hooks/useRefreshMemoryCommand.ts +7 -0
  314. package/dist/ui/hooks/useReverseSearchCompletion.test.tsx +260 -0
  315. package/dist/ui/hooks/useReverseSearchCompletion.tsx +95 -0
  316. package/dist/ui/hooks/useSettingsCommand.ts +25 -0
  317. package/dist/ui/hooks/useShellHistory.test.ts +219 -0
  318. package/dist/ui/hooks/useShellHistory.ts +133 -0
  319. package/dist/ui/hooks/useShowMemoryCommand.ts +75 -0
  320. package/dist/ui/hooks/useSlashCompletion.test.ts +434 -0
  321. package/dist/ui/hooks/useSlashCompletion.ts +187 -0
  322. package/dist/ui/hooks/useStateAndRef.ts +36 -0
  323. package/dist/ui/hooks/useTerminalSize.ts +32 -0
  324. package/dist/ui/hooks/useThemeCommand.ts +110 -0
  325. package/dist/ui/hooks/useTimer.test.ts +120 -0
  326. package/dist/ui/hooks/useTimer.ts +65 -0
  327. package/dist/ui/hooks/useToolScheduler.test.ts +1123 -0
  328. package/dist/ui/hooks/useWelcomeBack.ts +253 -0
  329. package/dist/ui/hooks/vim.test.ts +1691 -0
  330. package/dist/ui/hooks/vim.ts +784 -0
  331. package/dist/ui/keyMatchers.test.ts +337 -0
  332. package/dist/ui/keyMatchers.ts +105 -0
  333. package/dist/ui/privacy/CloudFreePrivacyNotice.tsx +117 -0
  334. package/dist/ui/privacy/CloudPaidPrivacyNotice.tsx +59 -0
  335. package/dist/ui/privacy/GeminiPrivacyNotice.tsx +62 -0
  336. package/dist/ui/privacy/PrivacyNotice.tsx +42 -0
  337. package/dist/ui/semantic-colors.ts +26 -0
  338. package/dist/ui/themes/ansi-light.ts +150 -0
  339. package/dist/ui/themes/ansi.ts +159 -0
  340. package/dist/ui/themes/atom-one-dark.ts +147 -0
  341. package/dist/ui/themes/ayu-light.ts +139 -0
  342. package/dist/ui/themes/ayu.ts +113 -0
  343. package/dist/ui/themes/color-utils.test.ts +221 -0
  344. package/dist/ui/themes/color-utils.ts +231 -0
  345. package/dist/ui/themes/default-light.ts +108 -0
  346. package/dist/ui/themes/default.ts +151 -0
  347. package/dist/ui/themes/dracula.ts +124 -0
  348. package/dist/ui/themes/fss-code-dark.ts +156 -0
  349. package/dist/ui/themes/fss-dark.ts +113 -0
  350. package/dist/ui/themes/fss-light.ts +139 -0
  351. package/dist/ui/themes/github-dark.ts +147 -0
  352. package/dist/ui/themes/github-light.ts +149 -0
  353. package/dist/ui/themes/googlecode.ts +146 -0
  354. package/dist/ui/themes/no-color.ts +125 -0
  355. package/dist/ui/themes/qwen-dark.ts +118 -0
  356. package/dist/ui/themes/qwen-light.ts +144 -0
  357. package/dist/ui/themes/semantic-tokens.ts +127 -0
  358. package/dist/ui/themes/shades-of-purple.ts +352 -0
  359. package/dist/ui/themes/theme-manager.test.ts +99 -0
  360. package/dist/ui/themes/theme-manager.ts +257 -0
  361. package/dist/ui/themes/theme.test.ts +97 -0
  362. package/dist/ui/themes/theme.ts +451 -0
  363. package/dist/ui/themes/xcode.ts +154 -0
  364. package/dist/ui/types.ts +255 -0
  365. package/dist/ui/utils/CodeColorizer.tsx +217 -0
  366. package/dist/ui/utils/ConsolePatcher.ts +71 -0
  367. package/dist/ui/utils/InlineMarkdownRenderer.tsx +173 -0
  368. package/dist/ui/utils/MarkdownDisplay.test.tsx +244 -0
  369. package/dist/ui/utils/MarkdownDisplay.tsx +415 -0
  370. package/dist/ui/utils/TableRenderer.tsx +159 -0
  371. package/dist/ui/utils/__snapshots__/MarkdownDisplay.test.tsx.snap +93 -0
  372. package/dist/ui/utils/clipboardUtils.test.ts +76 -0
  373. package/dist/ui/utils/clipboardUtils.ts +149 -0
  374. package/dist/ui/utils/commandUtils.test.ts +384 -0
  375. package/dist/ui/utils/commandUtils.ts +106 -0
  376. package/dist/ui/utils/computeStats.test.ts +292 -0
  377. package/dist/ui/utils/computeStats.ts +86 -0
  378. package/dist/ui/utils/displayUtils.test.ts +58 -0
  379. package/dist/ui/utils/displayUtils.ts +32 -0
  380. package/dist/ui/utils/formatters.test.ts +72 -0
  381. package/dist/ui/utils/formatters.ts +63 -0
  382. package/dist/ui/utils/isNarrowWidth.ts +9 -0
  383. package/dist/ui/utils/kittyProtocolDetector.ts +105 -0
  384. package/dist/ui/utils/markdownUtilities.test.ts +50 -0
  385. package/dist/ui/utils/markdownUtilities.ts +125 -0
  386. package/dist/ui/utils/platformConstants.ts +52 -0
  387. package/dist/ui/utils/terminalSetup.ts +342 -0
  388. package/dist/ui/utils/textUtils.ts +40 -0
  389. package/dist/ui/utils/updateCheck.test.ts +163 -0
  390. package/dist/ui/utils/updateCheck.ts +100 -0
  391. package/dist/utils/checks.ts +28 -0
  392. package/dist/utils/cleanup.test.ts +68 -0
  393. package/dist/utils/cleanup.ts +36 -0
  394. package/dist/utils/dialogScopeUtils.ts +64 -0
  395. package/dist/utils/events.ts +14 -0
  396. package/dist/utils/gitUtils.test.ts +149 -0
  397. package/dist/utils/gitUtils.ts +116 -0
  398. package/dist/utils/handleAutoUpdate.test.ts +272 -0
  399. package/dist/utils/handleAutoUpdate.ts +145 -0
  400. package/dist/utils/installationInfo.test.ts +315 -0
  401. package/dist/utils/installationInfo.ts +176 -0
  402. package/dist/utils/package.ts +38 -0
  403. package/dist/utils/readStdin.ts +51 -0
  404. package/dist/utils/resolvePath.ts +21 -0
  405. package/dist/utils/sandbox-macos-permissive-closed.sb +32 -0
  406. package/dist/utils/sandbox-macos-permissive-open.sb +25 -0
  407. package/dist/utils/sandbox-macos-permissive-proxied.sb +37 -0
  408. package/dist/utils/sandbox-macos-restrictive-closed.sb +93 -0
  409. package/dist/utils/sandbox-macos-restrictive-open.sb +96 -0
  410. package/dist/utils/sandbox-macos-restrictive-proxied.sb +98 -0
  411. package/dist/utils/sandbox.ts +962 -0
  412. package/dist/utils/settingsUtils.test.ts +797 -0
  413. package/dist/utils/settingsUtils.ts +489 -0
  414. package/dist/utils/spawnWrapper.ts +9 -0
  415. package/dist/utils/startupWarnings.test.ts +83 -0
  416. package/dist/utils/startupWarnings.ts +40 -0
  417. package/dist/utils/updateEventEmitter.ts +13 -0
  418. package/dist/utils/userStartupWarnings.test.ts +87 -0
  419. package/dist/utils/userStartupWarnings.ts +69 -0
  420. package/dist/utils/version.ts +12 -0
  421. package/dist/validateNonInterActiveAuth.test.ts +260 -0
  422. package/dist/validateNonInterActiveAuth.ts +51 -0
  423. package/dist/vitest.config.ts +37 -0
  424. package/dist/zed-integration/acp.ts +366 -0
  425. package/dist/zed-integration/fileSystemService.ts +47 -0
  426. package/dist/zed-integration/schema.ts +466 -0
  427. package/dist/zed-integration/zedIntegration.ts +944 -0
  428. package/package.json +2 -2
@@ -0,0 +1,297 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ import React from 'react';
8
+ import { Box, Text } from 'ink';
9
+ import { DiffRenderer } from './DiffRenderer.js';
10
+ import { Colors } from '../../colors.js';
11
+ import { RenderInline } from '../../utils/InlineMarkdownRenderer.js';
12
+ import {
13
+ ToolCallConfirmationDetails,
14
+ ToolConfirmationOutcome,
15
+ ToolExecuteConfirmationDetails,
16
+ ToolMcpConfirmationDetails,
17
+ Config,
18
+ } from 'fss-link-core';
19
+ import {
20
+ RadioButtonSelect,
21
+ RadioSelectItem,
22
+ } from '../shared/RadioButtonSelect.js';
23
+ import { MaxSizedBox } from '../shared/MaxSizedBox.js';
24
+ import { useKeypress } from '../../hooks/useKeypress.js';
25
+
26
+ export interface ToolConfirmationMessageProps {
27
+ confirmationDetails: ToolCallConfirmationDetails;
28
+ config?: Config;
29
+ isFocused?: boolean;
30
+ availableTerminalHeight?: number;
31
+ terminalWidth: number;
32
+ }
33
+
34
+ export const ToolConfirmationMessage: React.FC<
35
+ ToolConfirmationMessageProps
36
+ > = ({
37
+ confirmationDetails,
38
+ config,
39
+ isFocused = true,
40
+ availableTerminalHeight,
41
+ terminalWidth,
42
+ }) => {
43
+ const { onConfirm } = confirmationDetails;
44
+ const childWidth = terminalWidth - 2; // 2 for padding
45
+
46
+ const handleConfirm = async (outcome: ToolConfirmationOutcome) => {
47
+ if (confirmationDetails.type === 'edit') {
48
+ const ideClient = config?.getIdeClient();
49
+ if (config?.getIdeMode()) {
50
+ const cliOutcome =
51
+ outcome === ToolConfirmationOutcome.Cancel ? 'rejected' : 'accepted';
52
+ await ideClient?.resolveDiffFromCli(
53
+ confirmationDetails.filePath,
54
+ cliOutcome,
55
+ );
56
+ }
57
+ }
58
+ onConfirm(outcome);
59
+ };
60
+
61
+ useKeypress(
62
+ (key) => {
63
+ if (!isFocused) return;
64
+ if (key.name === 'escape' || (key.ctrl && key.name === 'c')) {
65
+ handleConfirm(ToolConfirmationOutcome.Cancel);
66
+ }
67
+ },
68
+ { isActive: isFocused },
69
+ );
70
+
71
+ const handleSelect = (item: ToolConfirmationOutcome) => handleConfirm(item);
72
+
73
+ let bodyContent: React.ReactNode | null = null; // Removed contextDisplay here
74
+ let question: string;
75
+
76
+ const options: Array<RadioSelectItem<ToolConfirmationOutcome>> = new Array<
77
+ RadioSelectItem<ToolConfirmationOutcome>
78
+ >();
79
+
80
+ // Body content is now the DiffRenderer, passing filename to it
81
+ // The bordered box is removed from here and handled within DiffRenderer
82
+
83
+ function availableBodyContentHeight() {
84
+ if (options.length === 0) {
85
+ // This should not happen in practice as options are always added before this is called.
86
+ throw new Error('Options not provided for confirmation message');
87
+ }
88
+
89
+ if (availableTerminalHeight === undefined) {
90
+ return undefined;
91
+ }
92
+
93
+ // Calculate the vertical space (in lines) consumed by UI elements
94
+ // surrounding the main body content.
95
+ const PADDING_OUTER_Y = 2; // Main container has `padding={1}` (top & bottom).
96
+ const MARGIN_BODY_BOTTOM = 1; // margin on the body container.
97
+ const HEIGHT_QUESTION = 1; // The question text is one line.
98
+ const MARGIN_QUESTION_BOTTOM = 1; // Margin on the question container.
99
+ const HEIGHT_OPTIONS = options.length; // Each option in the radio select takes one line.
100
+
101
+ const surroundingElementsHeight =
102
+ PADDING_OUTER_Y +
103
+ MARGIN_BODY_BOTTOM +
104
+ HEIGHT_QUESTION +
105
+ MARGIN_QUESTION_BOTTOM +
106
+ HEIGHT_OPTIONS;
107
+ return Math.max(availableTerminalHeight - surroundingElementsHeight, 1);
108
+ }
109
+
110
+ if (confirmationDetails.type === 'edit') {
111
+ if (confirmationDetails.isModifying) {
112
+ return (
113
+ <Box
114
+ minWidth="90%"
115
+ borderStyle="round"
116
+ borderColor={Colors.Gray}
117
+ justifyContent="space-around"
118
+ padding={1}
119
+ overflow="hidden"
120
+ >
121
+ <Text>Modify in progress: </Text>
122
+ <Text color={Colors.AccentGreen}>
123
+ Save and close external editor to continue
124
+ </Text>
125
+ </Box>
126
+ );
127
+ }
128
+
129
+ question = `Apply this change?`;
130
+ options.push(
131
+ {
132
+ label: 'Yes, allow once',
133
+ value: ToolConfirmationOutcome.ProceedOnce,
134
+ },
135
+ {
136
+ label: 'Yes, allow always',
137
+ value: ToolConfirmationOutcome.ProceedAlways,
138
+ },
139
+ );
140
+ if (config?.getIdeMode()) {
141
+ options.push({
142
+ label: 'No (esc)',
143
+ value: ToolConfirmationOutcome.Cancel,
144
+ });
145
+ } else {
146
+ options.push({
147
+ label: 'Modify with external editor',
148
+ value: ToolConfirmationOutcome.ModifyWithEditor,
149
+ });
150
+ options.push({
151
+ label: 'No, suggest changes (esc)',
152
+ value: ToolConfirmationOutcome.Cancel,
153
+ });
154
+ }
155
+
156
+ bodyContent = (
157
+ <DiffRenderer
158
+ diffContent={confirmationDetails.fileDiff}
159
+ filename={confirmationDetails.fileName}
160
+ availableTerminalHeight={availableBodyContentHeight()}
161
+ terminalWidth={childWidth}
162
+ />
163
+ );
164
+ } else if (confirmationDetails.type === 'exec') {
165
+ const executionProps =
166
+ confirmationDetails as ToolExecuteConfirmationDetails;
167
+
168
+ question = `Allow execution of: '${executionProps.rootCommand}'?`;
169
+ options.push(
170
+ {
171
+ label: `Yes, allow once`,
172
+ value: ToolConfirmationOutcome.ProceedOnce,
173
+ },
174
+ {
175
+ label: `Yes, allow always ...`,
176
+ value: ToolConfirmationOutcome.ProceedAlways,
177
+ },
178
+ {
179
+ label: 'No, suggest changes (esc)',
180
+ value: ToolConfirmationOutcome.Cancel,
181
+ },
182
+ );
183
+
184
+ let bodyContentHeight = availableBodyContentHeight();
185
+ if (bodyContentHeight !== undefined) {
186
+ bodyContentHeight -= 2; // Account for padding;
187
+ }
188
+ bodyContent = (
189
+ <Box flexDirection="column">
190
+ <Box paddingX={1} marginLeft={1}>
191
+ <MaxSizedBox
192
+ maxHeight={bodyContentHeight}
193
+ maxWidth={Math.max(childWidth - 4, 1)}
194
+ >
195
+ <Box>
196
+ <Text color={Colors.AccentCyan}>{executionProps.command}</Text>
197
+ </Box>
198
+ </MaxSizedBox>
199
+ </Box>
200
+ </Box>
201
+ );
202
+ } else if (confirmationDetails.type === 'info') {
203
+ const infoProps = confirmationDetails;
204
+ const displayUrls =
205
+ infoProps.urls &&
206
+ !(infoProps.urls.length === 1 && infoProps.urls[0] === infoProps.prompt);
207
+
208
+ question = `Do you want to proceed?`;
209
+ options.push(
210
+ {
211
+ label: 'Yes, allow once',
212
+ value: ToolConfirmationOutcome.ProceedOnce,
213
+ },
214
+ {
215
+ label: 'Yes, allow always',
216
+ value: ToolConfirmationOutcome.ProceedAlways,
217
+ },
218
+ {
219
+ label: 'No, suggest changes (esc)',
220
+ value: ToolConfirmationOutcome.Cancel,
221
+ },
222
+ );
223
+
224
+ bodyContent = (
225
+ <Box flexDirection="column" paddingX={1} marginLeft={1}>
226
+ <Text color={Colors.AccentCyan}>
227
+ <RenderInline text={infoProps.prompt} />
228
+ </Text>
229
+ {displayUrls && infoProps.urls && infoProps.urls.length > 0 && (
230
+ <Box flexDirection="column" marginTop={1}>
231
+ <Text>URLs to fetch:</Text>
232
+ {infoProps.urls.map((url) => (
233
+ <Text key={url}>
234
+ {' '}
235
+ - <RenderInline text={url} />
236
+ </Text>
237
+ ))}
238
+ </Box>
239
+ )}
240
+ </Box>
241
+ );
242
+ } else {
243
+ // mcp tool confirmation
244
+ const mcpProps = confirmationDetails as ToolMcpConfirmationDetails;
245
+
246
+ bodyContent = (
247
+ <Box flexDirection="column" paddingX={1} marginLeft={1}>
248
+ <Text color={Colors.AccentCyan}>MCP Server: {mcpProps.serverName}</Text>
249
+ <Text color={Colors.AccentCyan}>Tool: {mcpProps.toolName}</Text>
250
+ </Box>
251
+ );
252
+
253
+ question = `Allow execution of MCP tool "${mcpProps.toolName}" from server "${mcpProps.serverName}"?`;
254
+ options.push(
255
+ {
256
+ label: 'Yes, allow once',
257
+ value: ToolConfirmationOutcome.ProceedOnce,
258
+ },
259
+ {
260
+ label: `Yes, always allow tool "${mcpProps.toolName}" from server "${mcpProps.serverName}"`,
261
+ value: ToolConfirmationOutcome.ProceedAlwaysTool, // Cast until types are updated
262
+ },
263
+ {
264
+ label: `Yes, always allow all tools from server "${mcpProps.serverName}"`,
265
+ value: ToolConfirmationOutcome.ProceedAlwaysServer,
266
+ },
267
+ {
268
+ label: 'No, suggest changes (esc)',
269
+ value: ToolConfirmationOutcome.Cancel,
270
+ },
271
+ );
272
+ }
273
+
274
+ return (
275
+ <Box flexDirection="column" padding={1} width={childWidth}>
276
+ {/* Body Content (Diff Renderer or Command Info) */}
277
+ {/* No separate context display here anymore for edits */}
278
+ <Box flexGrow={1} flexShrink={1} overflow="hidden" marginBottom={1}>
279
+ {bodyContent}
280
+ </Box>
281
+
282
+ {/* Confirmation Question */}
283
+ <Box marginBottom={1} flexShrink={0}>
284
+ <Text wrap="truncate">{question}</Text>
285
+ </Box>
286
+
287
+ {/* Select Input for Options */}
288
+ <Box flexShrink={0}>
289
+ <RadioButtonSelect
290
+ items={options}
291
+ onSelect={handleSelect}
292
+ isFocused={isFocused}
293
+ />
294
+ </Box>
295
+ </Box>
296
+ );
297
+ };
@@ -0,0 +1,126 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ import React, { useMemo } from 'react';
8
+ import { Box } from 'ink';
9
+ import { IndividualToolCallDisplay, ToolCallStatus } from '../../types.js';
10
+ import { ToolMessage } from './ToolMessage.js';
11
+ import { ToolConfirmationMessage } from './ToolConfirmationMessage.js';
12
+ import { Colors } from '../../colors.js';
13
+ import { Config } from 'fss-link-core';
14
+ import { SHELL_COMMAND_NAME } from '../../constants.js';
15
+
16
+ interface ToolGroupMessageProps {
17
+ groupId: number;
18
+ toolCalls: IndividualToolCallDisplay[];
19
+ availableTerminalHeight?: number;
20
+ terminalWidth: number;
21
+ config?: Config;
22
+ isFocused?: boolean;
23
+ }
24
+
25
+ // Main component renders the border and maps the tools using ToolMessage
26
+ export const ToolGroupMessage: React.FC<ToolGroupMessageProps> = ({
27
+ toolCalls,
28
+ availableTerminalHeight,
29
+ terminalWidth,
30
+ config,
31
+ isFocused = true,
32
+ }) => {
33
+ const hasPending = !toolCalls.every(
34
+ (t) => t.status === ToolCallStatus.Success,
35
+ );
36
+ const isShellCommand = toolCalls.some((t) => t.name === SHELL_COMMAND_NAME);
37
+ const borderColor =
38
+ hasPending || isShellCommand ? Colors.AccentYellow : Colors.Gray;
39
+
40
+ const staticHeight = /* border */ 2 + /* marginBottom */ 1;
41
+ // This is a bit of a magic number, but it accounts for the border and
42
+ // marginLeft.
43
+ const innerWidth = terminalWidth - 4;
44
+
45
+ // only prompt for tool approval on the first 'confirming' tool in the list
46
+ // note, after the CTA, this automatically moves over to the next 'confirming' tool
47
+ const toolAwaitingApproval = useMemo(
48
+ () => toolCalls.find((tc) => tc.status === ToolCallStatus.Confirming),
49
+ [toolCalls],
50
+ );
51
+
52
+ let countToolCallsWithResults = 0;
53
+ for (const tool of toolCalls) {
54
+ if (tool.resultDisplay !== undefined && tool.resultDisplay !== '') {
55
+ countToolCallsWithResults++;
56
+ }
57
+ }
58
+ const countOneLineToolCalls = toolCalls.length - countToolCallsWithResults;
59
+ const availableTerminalHeightPerToolMessage = availableTerminalHeight
60
+ ? Math.max(
61
+ Math.floor(
62
+ (availableTerminalHeight - staticHeight - countOneLineToolCalls) /
63
+ Math.max(1, countToolCallsWithResults),
64
+ ),
65
+ 1,
66
+ )
67
+ : undefined;
68
+
69
+ return (
70
+ <Box
71
+ flexDirection="column"
72
+ borderStyle="round"
73
+ /*
74
+ This width constraint is highly important and protects us from an Ink rendering bug.
75
+ Since the ToolGroup can typically change rendering states frequently, it can cause
76
+ Ink to render the border of the box incorrectly and span multiple lines and even
77
+ cause tearing.
78
+ */
79
+ width="100%"
80
+ marginLeft={1}
81
+ borderDimColor={hasPending}
82
+ borderColor={borderColor}
83
+ >
84
+ {toolCalls.map((tool) => {
85
+ const isConfirming = toolAwaitingApproval?.callId === tool.callId;
86
+ return (
87
+ <Box key={tool.callId} flexDirection="column" minHeight={1}>
88
+ <Box flexDirection="row" alignItems="center">
89
+ <ToolMessage
90
+ callId={tool.callId}
91
+ name={tool.name}
92
+ description={tool.description}
93
+ resultDisplay={tool.resultDisplay}
94
+ status={tool.status}
95
+ confirmationDetails={tool.confirmationDetails}
96
+ availableTerminalHeight={availableTerminalHeightPerToolMessage}
97
+ terminalWidth={innerWidth}
98
+ emphasis={
99
+ isConfirming
100
+ ? 'high'
101
+ : toolAwaitingApproval
102
+ ? 'low'
103
+ : 'medium'
104
+ }
105
+ renderOutputAsMarkdown={tool.renderOutputAsMarkdown}
106
+ />
107
+ </Box>
108
+ {tool.status === ToolCallStatus.Confirming &&
109
+ isConfirming &&
110
+ tool.confirmationDetails && (
111
+ <ToolConfirmationMessage
112
+ confirmationDetails={tool.confirmationDetails}
113
+ config={config}
114
+ isFocused={isFocused}
115
+ availableTerminalHeight={
116
+ availableTerminalHeightPerToolMessage
117
+ }
118
+ terminalWidth={innerWidth}
119
+ />
120
+ )}
121
+ </Box>
122
+ );
123
+ })}
124
+ </Box>
125
+ );
126
+ };
@@ -0,0 +1,183 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ import React from 'react';
8
+ import { render } from 'ink-testing-library';
9
+ import { ToolMessage, ToolMessageProps } from './ToolMessage.js';
10
+ import { StreamingState, ToolCallStatus } from '../../types.js';
11
+ import { Text } from 'ink';
12
+ import { StreamingContext } from '../../contexts/StreamingContext.js';
13
+
14
+ // Mock child components or utilities if they are complex or have side effects
15
+ vi.mock('../GeminiRespondingSpinner.js', () => ({
16
+ GeminiRespondingSpinner: ({
17
+ nonRespondingDisplay,
18
+ }: {
19
+ nonRespondingDisplay?: string;
20
+ }) => {
21
+ const streamingState = React.useContext(StreamingContext)!;
22
+ if (streamingState === StreamingState.Responding) {
23
+ return <Text>MockRespondingSpinner</Text>;
24
+ }
25
+ return nonRespondingDisplay ? <Text>{nonRespondingDisplay}</Text> : null;
26
+ },
27
+ }));
28
+ vi.mock('./DiffRenderer.js', () => ({
29
+ DiffRenderer: function MockDiffRenderer({
30
+ diffContent,
31
+ }: {
32
+ diffContent: string;
33
+ }) {
34
+ return <Text>MockDiff:{diffContent}</Text>;
35
+ },
36
+ }));
37
+ vi.mock('../../utils/MarkdownDisplay.js', () => ({
38
+ MarkdownDisplay: function MockMarkdownDisplay({ text }: { text: string }) {
39
+ return <Text>MockMarkdown:{text}</Text>;
40
+ },
41
+ }));
42
+
43
+ // Helper to render with context
44
+ const renderWithContext = (
45
+ ui: React.ReactElement,
46
+ streamingState: StreamingState,
47
+ ) => {
48
+ const contextValue: StreamingState = streamingState;
49
+ return render(
50
+ <StreamingContext.Provider value={contextValue}>
51
+ {ui}
52
+ </StreamingContext.Provider>,
53
+ );
54
+ };
55
+
56
+ describe('<ToolMessage />', () => {
57
+ const baseProps: ToolMessageProps = {
58
+ callId: 'tool-123',
59
+ name: 'test-tool',
60
+ description: 'A tool for testing',
61
+ resultDisplay: 'Test result',
62
+ status: ToolCallStatus.Success,
63
+ terminalWidth: 80,
64
+ confirmationDetails: undefined,
65
+ emphasis: 'medium',
66
+ };
67
+
68
+ it('renders basic tool information', () => {
69
+ const { lastFrame } = renderWithContext(
70
+ <ToolMessage {...baseProps} />,
71
+ StreamingState.Idle,
72
+ );
73
+ const output = lastFrame();
74
+ expect(output).toContain('✔'); // Success indicator
75
+ expect(output).toContain('test-tool');
76
+ expect(output).toContain('A tool for testing');
77
+ expect(output).toContain('MockMarkdown:Test result');
78
+ });
79
+
80
+ describe('ToolStatusIndicator rendering', () => {
81
+ it('shows ✔ for Success status', () => {
82
+ const { lastFrame } = renderWithContext(
83
+ <ToolMessage {...baseProps} status={ToolCallStatus.Success} />,
84
+ StreamingState.Idle,
85
+ );
86
+ expect(lastFrame()).toContain('✔');
87
+ });
88
+
89
+ it('shows o for Pending status', () => {
90
+ const { lastFrame } = renderWithContext(
91
+ <ToolMessage {...baseProps} status={ToolCallStatus.Pending} />,
92
+ StreamingState.Idle,
93
+ );
94
+ expect(lastFrame()).toContain('o');
95
+ });
96
+
97
+ it('shows ? for Confirming status', () => {
98
+ const { lastFrame } = renderWithContext(
99
+ <ToolMessage {...baseProps} status={ToolCallStatus.Confirming} />,
100
+ StreamingState.Idle,
101
+ );
102
+ expect(lastFrame()).toContain('?');
103
+ });
104
+
105
+ it('shows - for Canceled status', () => {
106
+ const { lastFrame } = renderWithContext(
107
+ <ToolMessage {...baseProps} status={ToolCallStatus.Canceled} />,
108
+ StreamingState.Idle,
109
+ );
110
+ expect(lastFrame()).toContain('-');
111
+ });
112
+
113
+ it('shows x for Error status', () => {
114
+ const { lastFrame } = renderWithContext(
115
+ <ToolMessage {...baseProps} status={ToolCallStatus.Error} />,
116
+ StreamingState.Idle,
117
+ );
118
+ expect(lastFrame()).toContain('x');
119
+ });
120
+
121
+ it('shows paused spinner for Executing status when streamingState is Idle', () => {
122
+ const { lastFrame } = renderWithContext(
123
+ <ToolMessage {...baseProps} status={ToolCallStatus.Executing} />,
124
+ StreamingState.Idle,
125
+ );
126
+ expect(lastFrame()).toContain('⊷');
127
+ expect(lastFrame()).not.toContain('MockRespondingSpinner');
128
+ expect(lastFrame()).not.toContain('✔');
129
+ });
130
+
131
+ it('shows paused spinner for Executing status when streamingState is WaitingForConfirmation', () => {
132
+ const { lastFrame } = renderWithContext(
133
+ <ToolMessage {...baseProps} status={ToolCallStatus.Executing} />,
134
+ StreamingState.WaitingForConfirmation,
135
+ );
136
+ expect(lastFrame()).toContain('⊷');
137
+ expect(lastFrame()).not.toContain('MockRespondingSpinner');
138
+ expect(lastFrame()).not.toContain('✔');
139
+ });
140
+
141
+ it('shows MockRespondingSpinner for Executing status when streamingState is Responding', () => {
142
+ const { lastFrame } = renderWithContext(
143
+ <ToolMessage {...baseProps} status={ToolCallStatus.Executing} />,
144
+ StreamingState.Responding, // Simulate app still responding
145
+ );
146
+ expect(lastFrame()).toContain('MockRespondingSpinner');
147
+ expect(lastFrame()).not.toContain('✔');
148
+ });
149
+ });
150
+
151
+ it('renders DiffRenderer for diff results', () => {
152
+ const diffResult = {
153
+ fileDiff: '--- a/file.txt\n+++ b/file.txt\n@@ -1 +1 @@\n-old\n+new',
154
+ fileName: 'file.txt',
155
+ originalContent: 'old',
156
+ newContent: 'new',
157
+ };
158
+ const { lastFrame } = renderWithContext(
159
+ <ToolMessage {...baseProps} resultDisplay={diffResult} />,
160
+ StreamingState.Idle,
161
+ );
162
+ // Check that the output contains the MockDiff content as part of the whole message
163
+ expect(lastFrame()).toMatch(/MockDiff:--- a\/file\.txt/);
164
+ });
165
+
166
+ it('renders emphasis correctly', () => {
167
+ const { lastFrame: highEmphasisFrame } = renderWithContext(
168
+ <ToolMessage {...baseProps} emphasis="high" />,
169
+ StreamingState.Idle,
170
+ );
171
+ // Check for trailing indicator or specific color if applicable (Colors are not easily testable here)
172
+ expect(highEmphasisFrame()).toContain('←'); // Trailing indicator for high emphasis
173
+
174
+ const { lastFrame: lowEmphasisFrame } = renderWithContext(
175
+ <ToolMessage {...baseProps} emphasis="low" />,
176
+ StreamingState.Idle,
177
+ );
178
+ // For low emphasis, the name and description might be dimmed (check for dimColor if possible)
179
+ // This is harder to assert directly in text output without color checks.
180
+ // We can at least ensure it doesn't have the high emphasis indicator.
181
+ expect(lowEmphasisFrame()).not.toContain('←');
182
+ });
183
+ });