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,358 @@
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 { Colors } from '../../colors.js';
10
+ import crypto from 'crypto';
11
+ import { colorizeCode, colorizeLine } from '../../utils/CodeColorizer.js';
12
+ import { MaxSizedBox } from '../shared/MaxSizedBox.js';
13
+ import { theme } from '../../semantic-colors.js';
14
+
15
+ interface DiffLine {
16
+ type: 'add' | 'del' | 'context' | 'hunk' | 'other';
17
+ oldLine?: number;
18
+ newLine?: number;
19
+ content: string;
20
+ }
21
+
22
+ function parseDiffWithLineNumbers(diffContent: string): DiffLine[] {
23
+ const lines = diffContent.split('\n');
24
+ const result: DiffLine[] = [];
25
+ let currentOldLine = 0;
26
+ let currentNewLine = 0;
27
+ let inHunk = false;
28
+ const hunkHeaderRegex = /^@@ -(\d+),?\d* \+(\d+),?\d* @@/;
29
+
30
+ for (const line of lines) {
31
+ const hunkMatch = line.match(hunkHeaderRegex);
32
+ if (hunkMatch) {
33
+ currentOldLine = parseInt(hunkMatch[1], 10);
34
+ currentNewLine = parseInt(hunkMatch[2], 10);
35
+ inHunk = true;
36
+ result.push({ type: 'hunk', content: line });
37
+ // We need to adjust the starting point because the first line number applies to the *first* actual line change/context,
38
+ // but we increment *before* pushing that line. So decrement here.
39
+ currentOldLine--;
40
+ currentNewLine--;
41
+ continue;
42
+ }
43
+ if (!inHunk) {
44
+ // Skip standard Git header lines more robustly
45
+ if (
46
+ line.startsWith('--- ') ||
47
+ line.startsWith('+++ ') ||
48
+ line.startsWith('diff --git') ||
49
+ line.startsWith('index ') ||
50
+ line.startsWith('similarity index') ||
51
+ line.startsWith('rename from') ||
52
+ line.startsWith('rename to') ||
53
+ line.startsWith('new file mode') ||
54
+ line.startsWith('deleted file mode')
55
+ )
56
+ continue;
57
+ // If it's not a hunk or header, skip (or handle as 'other' if needed)
58
+ continue;
59
+ }
60
+ if (line.startsWith('+')) {
61
+ currentNewLine++; // Increment before pushing
62
+ result.push({
63
+ type: 'add',
64
+ newLine: currentNewLine,
65
+ content: line.substring(1),
66
+ });
67
+ } else if (line.startsWith('-')) {
68
+ currentOldLine++; // Increment before pushing
69
+ result.push({
70
+ type: 'del',
71
+ oldLine: currentOldLine,
72
+ content: line.substring(1),
73
+ });
74
+ } else if (line.startsWith(' ')) {
75
+ currentOldLine++; // Increment before pushing
76
+ currentNewLine++;
77
+ result.push({
78
+ type: 'context',
79
+ oldLine: currentOldLine,
80
+ newLine: currentNewLine,
81
+ content: line.substring(1),
82
+ });
83
+ } else if (line.startsWith('\\')) {
84
+ // Handle ""
85
+ result.push({ type: 'other', content: line });
86
+ }
87
+ }
88
+ return result;
89
+ }
90
+
91
+ interface DiffRendererProps {
92
+ diffContent: string;
93
+ filename?: string;
94
+ tabWidth?: number;
95
+ availableTerminalHeight?: number;
96
+ terminalWidth: number;
97
+ theme?: import('../../themes/theme.js').Theme;
98
+ }
99
+
100
+ const DEFAULT_TAB_WIDTH = 4; // Spaces per tab for normalization
101
+
102
+ export const DiffRenderer: React.FC<DiffRendererProps> = ({
103
+ diffContent,
104
+ filename,
105
+ tabWidth = DEFAULT_TAB_WIDTH,
106
+ availableTerminalHeight,
107
+ terminalWidth,
108
+ theme,
109
+ }) => {
110
+ if (!diffContent || typeof diffContent !== 'string') {
111
+ return <Text color={Colors.AccentYellow}>No diff content.</Text>;
112
+ }
113
+
114
+ const parsedLines = parseDiffWithLineNumbers(diffContent);
115
+
116
+ if (parsedLines.length === 0) {
117
+ return (
118
+ <Box borderStyle="round" borderColor={Colors.Gray} padding={1}>
119
+ <Text dimColor>No changes detected.</Text>
120
+ </Box>
121
+ );
122
+ }
123
+
124
+ // Check if the diff represents a new file (only additions and header lines)
125
+ const isNewFile = parsedLines.every(
126
+ (line) =>
127
+ line.type === 'add' ||
128
+ line.type === 'hunk' ||
129
+ line.type === 'other' ||
130
+ line.content.startsWith('diff --git') ||
131
+ line.content.startsWith('new file mode'),
132
+ );
133
+
134
+ let renderedOutput;
135
+
136
+ if (isNewFile) {
137
+ // Extract only the added lines' content
138
+ const addedContent = parsedLines
139
+ .filter((line) => line.type === 'add')
140
+ .map((line) => line.content)
141
+ .join('\n');
142
+ // Attempt to infer language from filename, default to plain text if no filename
143
+ const fileExtension = filename?.split('.').pop() || null;
144
+ const language = fileExtension
145
+ ? getLanguageFromExtension(fileExtension)
146
+ : null;
147
+ renderedOutput = colorizeCode(
148
+ addedContent,
149
+ language,
150
+ availableTerminalHeight,
151
+ terminalWidth,
152
+ theme,
153
+ );
154
+ } else {
155
+ renderedOutput = renderDiffContent(
156
+ parsedLines,
157
+ filename,
158
+ tabWidth,
159
+ availableTerminalHeight,
160
+ terminalWidth,
161
+ );
162
+ }
163
+
164
+ return renderedOutput;
165
+ };
166
+
167
+ const renderDiffContent = (
168
+ parsedLines: DiffLine[],
169
+ filename: string | undefined,
170
+ tabWidth = DEFAULT_TAB_WIDTH,
171
+ availableTerminalHeight: number | undefined,
172
+ terminalWidth: number,
173
+ ) => {
174
+ // 1. Normalize whitespace (replace tabs with spaces) *before* further processing
175
+ const normalizedLines = parsedLines.map((line) => ({
176
+ ...line,
177
+ content: line.content.replace(/\t/g, ' '.repeat(tabWidth)),
178
+ }));
179
+
180
+ // Filter out non-displayable lines (hunks, potentially 'other') using the normalized list
181
+ const displayableLines = normalizedLines.filter(
182
+ (l) => l.type !== 'hunk' && l.type !== 'other',
183
+ );
184
+
185
+ if (displayableLines.length === 0) {
186
+ return (
187
+ <Box borderStyle="round" borderColor={Colors.Gray} padding={1}>
188
+ <Text dimColor>No changes detected.</Text>
189
+ </Box>
190
+ );
191
+ }
192
+
193
+ const maxLineNumber = Math.max(
194
+ 0,
195
+ ...displayableLines.map((l) => l.oldLine ?? 0),
196
+ ...displayableLines.map((l) => l.newLine ?? 0),
197
+ );
198
+ const gutterWidth = Math.max(1, maxLineNumber.toString().length);
199
+
200
+ const fileExtension = filename?.split('.').pop() || null;
201
+ const language = fileExtension
202
+ ? getLanguageFromExtension(fileExtension)
203
+ : null;
204
+
205
+ // Calculate the minimum indentation across all displayable lines
206
+ let baseIndentation = Infinity; // Start high to find the minimum
207
+ for (const line of displayableLines) {
208
+ // Only consider lines with actual content for indentation calculation
209
+ if (line.content.trim() === '') continue;
210
+
211
+ const firstCharIndex = line.content.search(/\S/); // Find index of first non-whitespace char
212
+ const currentIndent = firstCharIndex === -1 ? 0 : firstCharIndex; // Indent is 0 if no non-whitespace found
213
+ baseIndentation = Math.min(baseIndentation, currentIndent);
214
+ }
215
+ // If baseIndentation remained Infinity (e.g., no displayable lines with content), default to 0
216
+ if (!isFinite(baseIndentation)) {
217
+ baseIndentation = 0;
218
+ }
219
+
220
+ const key = filename
221
+ ? `diff-box-${filename}`
222
+ : `diff-box-${crypto.createHash('sha1').update(JSON.stringify(parsedLines)).digest('hex')}`;
223
+
224
+ let lastLineNumber: number | null = null;
225
+ const MAX_CONTEXT_LINES_WITHOUT_GAP = 5;
226
+
227
+ return (
228
+ <MaxSizedBox
229
+ maxHeight={availableTerminalHeight}
230
+ maxWidth={terminalWidth}
231
+ key={key}
232
+ >
233
+ {displayableLines.reduce<React.ReactNode[]>((acc, line, index) => {
234
+ // Determine the relevant line number for gap calculation based on type
235
+ let relevantLineNumberForGapCalc: number | null = null;
236
+ if (line.type === 'add' || line.type === 'context') {
237
+ relevantLineNumberForGapCalc = line.newLine ?? null;
238
+ } else if (line.type === 'del') {
239
+ // For deletions, the gap is typically in relation to the original file's line numbering
240
+ relevantLineNumberForGapCalc = line.oldLine ?? null;
241
+ }
242
+
243
+ if (
244
+ lastLineNumber !== null &&
245
+ relevantLineNumberForGapCalc !== null &&
246
+ relevantLineNumberForGapCalc >
247
+ lastLineNumber + MAX_CONTEXT_LINES_WITHOUT_GAP + 1
248
+ ) {
249
+ acc.push(
250
+ <Box key={`gap-${index}`}>
251
+ <Text wrap="truncate" color={Colors.Gray}>
252
+ {'═'.repeat(terminalWidth)}
253
+ </Text>
254
+ </Box>,
255
+ );
256
+ }
257
+
258
+ const lineKey = `diff-line-${index}`;
259
+ let gutterNumStr = '';
260
+ let prefixSymbol = ' ';
261
+
262
+ switch (line.type) {
263
+ case 'add':
264
+ gutterNumStr = (line.newLine ?? '').toString();
265
+ prefixSymbol = '+';
266
+ lastLineNumber = line.newLine ?? null;
267
+ break;
268
+ case 'del':
269
+ gutterNumStr = (line.oldLine ?? '').toString();
270
+ prefixSymbol = '-';
271
+ // For deletions, update lastLineNumber based on oldLine if it's advancing.
272
+ // This helps manage gaps correctly if there are multiple consecutive deletions
273
+ // or if a deletion is followed by a context line far away in the original file.
274
+ if (line.oldLine !== undefined) {
275
+ lastLineNumber = line.oldLine;
276
+ }
277
+ break;
278
+ case 'context':
279
+ gutterNumStr = (line.newLine ?? '').toString();
280
+ prefixSymbol = ' ';
281
+ lastLineNumber = line.newLine ?? null;
282
+ break;
283
+ default:
284
+ return acc;
285
+ }
286
+
287
+ const displayContent = line.content.substring(baseIndentation);
288
+
289
+ acc.push(
290
+ <Box key={lineKey} flexDirection="row">
291
+ <Text
292
+ color={theme.text.secondary}
293
+ backgroundColor={
294
+ line.type === 'add'
295
+ ? theme.background.diff.added
296
+ : line.type === 'del'
297
+ ? theme.background.diff.removed
298
+ : undefined
299
+ }
300
+ >
301
+ {gutterNumStr.padStart(gutterWidth)}{' '}
302
+ </Text>
303
+ {line.type === 'context' ? (
304
+ <>
305
+ <Text>{prefixSymbol} </Text>
306
+ <Text wrap="wrap">
307
+ {colorizeLine(displayContent, language)}
308
+ </Text>
309
+ </>
310
+ ) : (
311
+ <Text
312
+ backgroundColor={
313
+ line.type === 'add'
314
+ ? theme.background.diff.added
315
+ : theme.background.diff.removed
316
+ }
317
+ wrap="wrap"
318
+ >
319
+ <Text
320
+ color={
321
+ line.type === 'add'
322
+ ? theme.status.success
323
+ : theme.status.error
324
+ }
325
+ >
326
+ {prefixSymbol}
327
+ </Text>{' '}
328
+ {colorizeLine(displayContent, language)}
329
+ </Text>
330
+ )}
331
+ </Box>,
332
+ );
333
+ return acc;
334
+ }, [])}
335
+ </MaxSizedBox>
336
+ );
337
+ };
338
+
339
+ const getLanguageFromExtension = (extension: string): string | null => {
340
+ const languageMap: { [key: string]: string } = {
341
+ js: 'javascript',
342
+ ts: 'typescript',
343
+ py: 'python',
344
+ json: 'json',
345
+ css: 'css',
346
+ html: 'html',
347
+ sh: 'bash',
348
+ md: 'markdown',
349
+ yaml: 'yaml',
350
+ yml: 'yaml',
351
+ txt: 'plaintext',
352
+ java: 'java',
353
+ c: 'c',
354
+ cpp: 'cpp',
355
+ rb: 'ruby',
356
+ };
357
+ return languageMap[extension] || null; // Return null if extension not found
358
+ };
@@ -0,0 +1,31 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ import React from 'react';
8
+ import { Text, Box } from 'ink';
9
+ import { Colors } from '../../colors.js';
10
+
11
+ interface ErrorMessageProps {
12
+ text: string;
13
+ }
14
+
15
+ export const ErrorMessage: React.FC<ErrorMessageProps> = ({ text }) => {
16
+ const prefix = '✕ ';
17
+ const prefixWidth = prefix.length;
18
+
19
+ return (
20
+ <Box flexDirection="row" marginBottom={1}>
21
+ <Box width={prefixWidth}>
22
+ <Text color={Colors.AccentRed}>{prefix}</Text>
23
+ </Box>
24
+ <Box flexGrow={1}>
25
+ <Text wrap="wrap" color={Colors.AccentRed}>
26
+ {text}
27
+ </Text>
28
+ </Box>
29
+ </Box>
30
+ );
31
+ };
@@ -0,0 +1,43 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ import React from 'react';
8
+ import { Text, Box } from 'ink';
9
+ import { MarkdownDisplay } from '../../utils/MarkdownDisplay.js';
10
+ import { Colors } from '../../colors.js';
11
+
12
+ interface GeminiMessageProps {
13
+ text: string;
14
+ isPending: boolean;
15
+ availableTerminalHeight?: number;
16
+ terminalWidth: number;
17
+ }
18
+
19
+ export const GeminiMessage: React.FC<GeminiMessageProps> = ({
20
+ text,
21
+ isPending,
22
+ availableTerminalHeight,
23
+ terminalWidth,
24
+ }) => {
25
+ const prefix = '✦ ';
26
+ const prefixWidth = prefix.length;
27
+
28
+ return (
29
+ <Box flexDirection="row">
30
+ <Box width={prefixWidth}>
31
+ <Text color={Colors.AccentPurple}>{prefix}</Text>
32
+ </Box>
33
+ <Box flexGrow={1} flexDirection="column">
34
+ <MarkdownDisplay
35
+ text={text}
36
+ isPending={isPending}
37
+ availableTerminalHeight={availableTerminalHeight}
38
+ terminalWidth={terminalWidth}
39
+ />
40
+ </Box>
41
+ </Box>
42
+ );
43
+ };
@@ -0,0 +1,43 @@
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 } from 'ink';
9
+ import { MarkdownDisplay } from '../../utils/MarkdownDisplay.js';
10
+
11
+ interface GeminiMessageContentProps {
12
+ text: string;
13
+ isPending: boolean;
14
+ availableTerminalHeight?: number;
15
+ terminalWidth: number;
16
+ }
17
+
18
+ /*
19
+ * Gemini message content is a semi-hacked component. The intention is to represent a partial
20
+ * of GeminiMessage and is only used when a response gets too long. In that instance messages
21
+ * are split into multiple GeminiMessageContent's to enable the root <Static> component in
22
+ * App.tsx to be as performant as humanly possible.
23
+ */
24
+ export const GeminiMessageContent: React.FC<GeminiMessageContentProps> = ({
25
+ text,
26
+ isPending,
27
+ availableTerminalHeight,
28
+ terminalWidth,
29
+ }) => {
30
+ const originalPrefix = '✦ ';
31
+ const prefixWidth = originalPrefix.length;
32
+
33
+ return (
34
+ <Box flexDirection="column" paddingLeft={prefixWidth}>
35
+ <MarkdownDisplay
36
+ text={text}
37
+ isPending={isPending}
38
+ availableTerminalHeight={availableTerminalHeight}
39
+ terminalWidth={terminalWidth}
40
+ />
41
+ </Box>
42
+ );
43
+ };
@@ -0,0 +1,32 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ import React from 'react';
8
+ import { Text, Box } from 'ink';
9
+ import { Colors } from '../../colors.js';
10
+ import { RenderInline } from '../../utils/InlineMarkdownRenderer.js';
11
+
12
+ interface InfoMessageProps {
13
+ text: string;
14
+ }
15
+
16
+ export const InfoMessage: React.FC<InfoMessageProps> = ({ text }) => {
17
+ const prefix = 'ℹ ';
18
+ const prefixWidth = prefix.length;
19
+
20
+ return (
21
+ <Box flexDirection="row" marginTop={1}>
22
+ <Box width={prefixWidth}>
23
+ <Text color={Colors.AccentYellow}>{prefix}</Text>
24
+ </Box>
25
+ <Box flexGrow={1}>
26
+ <Text wrap="wrap" color={Colors.AccentYellow}>
27
+ <RenderInline text={text} />
28
+ </Text>
29
+ </Box>
30
+ </Box>
31
+ );
32
+ };
@@ -0,0 +1,58 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ import { describe, it, expect, vi } from 'vitest';
8
+ import { ToolConfirmationMessage } from './ToolConfirmationMessage.js';
9
+ import { ToolCallConfirmationDetails } from 'fss-link-core';
10
+ import { renderWithProviders } from '../../../test-utils/render.js';
11
+
12
+ describe('ToolConfirmationMessage', () => {
13
+ it('should not display urls if prompt and url are the same', () => {
14
+ const confirmationDetails: ToolCallConfirmationDetails = {
15
+ type: 'info',
16
+ title: 'Confirm Web Fetch',
17
+ prompt: 'https://example.com',
18
+ urls: ['https://example.com'],
19
+ onConfirm: vi.fn(),
20
+ };
21
+
22
+ const { lastFrame } = renderWithProviders(
23
+ <ToolConfirmationMessage
24
+ confirmationDetails={confirmationDetails}
25
+ availableTerminalHeight={30}
26
+ terminalWidth={80}
27
+ />,
28
+ );
29
+
30
+ expect(lastFrame()).not.toContain('URLs to fetch:');
31
+ });
32
+
33
+ it('should display urls if prompt and url are different', () => {
34
+ const confirmationDetails: ToolCallConfirmationDetails = {
35
+ type: 'info',
36
+ title: 'Confirm Web Fetch',
37
+ prompt:
38
+ 'fetch https://github.com/google/gemini-react/blob/main/README.md',
39
+ urls: [
40
+ 'https://raw.githubusercontent.com/google/gemini-react/main/README.md',
41
+ ],
42
+ onConfirm: vi.fn(),
43
+ };
44
+
45
+ const { lastFrame } = renderWithProviders(
46
+ <ToolConfirmationMessage
47
+ confirmationDetails={confirmationDetails}
48
+ availableTerminalHeight={30}
49
+ terminalWidth={80}
50
+ />,
51
+ );
52
+
53
+ expect(lastFrame()).toContain('URLs to fetch:');
54
+ expect(lastFrame()).toContain(
55
+ '- https://raw.githubusercontent.com/google/gemini-react/main/README.md',
56
+ );
57
+ });
58
+ });