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,255 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ import {
8
+ ToolCallConfirmationDetails,
9
+ ToolResultDisplay,
10
+ } from 'fss-link-core';
11
+
12
+ // Only defining the state enum needed by the UI
13
+ export enum StreamingState {
14
+ Idle = 'idle',
15
+ Responding = 'responding',
16
+ WaitingForConfirmation = 'waiting_for_confirmation',
17
+ }
18
+
19
+ // Copied from server/src/core/turn.ts for CLI usage
20
+ export enum GeminiEventType {
21
+ Content = 'content',
22
+ ToolCallRequest = 'tool_call_request',
23
+ // Add other event types if the UI hook needs to handle them
24
+ }
25
+
26
+ export enum ToolCallStatus {
27
+ Pending = 'Pending',
28
+ Canceled = 'Canceled',
29
+ Confirming = 'Confirming',
30
+ Executing = 'Executing',
31
+ Success = 'Success',
32
+ Error = 'Error',
33
+ }
34
+
35
+ export interface ToolCallEvent {
36
+ type: 'tool_call';
37
+ status: ToolCallStatus;
38
+ callId: string;
39
+ name: string;
40
+ args: Record<string, never>;
41
+ resultDisplay: ToolResultDisplay | undefined;
42
+ confirmationDetails: ToolCallConfirmationDetails | undefined;
43
+ }
44
+
45
+ export interface IndividualToolCallDisplay {
46
+ callId: string;
47
+ name: string;
48
+ description: string;
49
+ resultDisplay: ToolResultDisplay | undefined;
50
+ status: ToolCallStatus;
51
+ confirmationDetails: ToolCallConfirmationDetails | undefined;
52
+ renderOutputAsMarkdown?: boolean;
53
+ }
54
+
55
+ export interface CompressionProps {
56
+ isPending: boolean;
57
+ originalTokenCount: number | null;
58
+ newTokenCount: number | null;
59
+ }
60
+
61
+ export interface HistoryItemBase {
62
+ text?: string; // Text content for user/gemini/info/error messages
63
+ }
64
+
65
+ export type HistoryItemUser = HistoryItemBase & {
66
+ type: 'user';
67
+ text: string;
68
+ };
69
+
70
+ export type HistoryItemGemini = HistoryItemBase & {
71
+ type: 'gemini';
72
+ text: string;
73
+ };
74
+
75
+ export type HistoryItemGeminiContent = HistoryItemBase & {
76
+ type: 'gemini_content';
77
+ text: string;
78
+ };
79
+
80
+ export type HistoryItemInfo = HistoryItemBase & {
81
+ type: 'info';
82
+ text: string;
83
+ };
84
+
85
+ export type HistoryItemError = HistoryItemBase & {
86
+ type: 'error';
87
+ text: string;
88
+ };
89
+
90
+ export type HistoryItemAbout = HistoryItemBase & {
91
+ type: 'about';
92
+ cliVersion: string;
93
+ osVersion: string;
94
+ sandboxEnv: string;
95
+ modelVersion: string;
96
+ selectedAuthType: string;
97
+ gcpProject: string;
98
+ ideClient: string;
99
+ };
100
+
101
+ export type HistoryItemHelp = HistoryItemBase & {
102
+ type: 'help';
103
+ timestamp: Date;
104
+ };
105
+
106
+ export type HistoryItemStats = HistoryItemBase & {
107
+ type: 'stats';
108
+ duration: string;
109
+ };
110
+
111
+ export type HistoryItemModelStats = HistoryItemBase & {
112
+ type: 'model_stats';
113
+ };
114
+
115
+ export type HistoryItemToolStats = HistoryItemBase & {
116
+ type: 'tool_stats';
117
+ };
118
+
119
+ export type HistoryItemQuit = HistoryItemBase & {
120
+ type: 'quit';
121
+ duration: string;
122
+ };
123
+
124
+ export type HistoryItemToolGroup = HistoryItemBase & {
125
+ type: 'tool_group';
126
+ tools: IndividualToolCallDisplay[];
127
+ };
128
+
129
+ export type HistoryItemUserShell = HistoryItemBase & {
130
+ type: 'user_shell';
131
+ text: string;
132
+ };
133
+
134
+ export type HistoryItemCompression = HistoryItemBase & {
135
+ type: 'compression';
136
+ compression: CompressionProps;
137
+ };
138
+
139
+ // Using Omit<HistoryItem, 'id'> seems to have some issues with typescript's
140
+ // type inference e.g. historyItem.type === 'tool_group' isn't auto-inferring that
141
+ // 'tools' in historyItem.
142
+ // Individually exported types extending HistoryItemBase
143
+ export type HistoryItemWithoutId =
144
+ | HistoryItemUser
145
+ | HistoryItemUserShell
146
+ | HistoryItemGemini
147
+ | HistoryItemGeminiContent
148
+ | HistoryItemInfo
149
+ | HistoryItemError
150
+ | HistoryItemAbout
151
+ | HistoryItemHelp
152
+ | HistoryItemToolGroup
153
+ | HistoryItemStats
154
+ | HistoryItemModelStats
155
+ | HistoryItemToolStats
156
+ | HistoryItemQuit
157
+ | HistoryItemCompression;
158
+
159
+ export type HistoryItem = HistoryItemWithoutId & { id: number };
160
+
161
+ // Message types used by internal command feedback (subset of HistoryItem types)
162
+ export enum MessageType {
163
+ INFO = 'info',
164
+ ERROR = 'error',
165
+ USER = 'user',
166
+ ABOUT = 'about',
167
+ HELP = 'help',
168
+ STATS = 'stats',
169
+ MODEL_STATS = 'model_stats',
170
+ TOOL_STATS = 'tool_stats',
171
+ QUIT = 'quit',
172
+ FSS_LINK = 'fss_link',
173
+ COMPRESSION = 'compression',
174
+ }
175
+
176
+ // Simplified message structure for internal feedback
177
+ export type Message =
178
+ | {
179
+ type: MessageType.INFO | MessageType.ERROR | MessageType.USER;
180
+ content: string; // Renamed from text for clarity in this context
181
+ timestamp: Date;
182
+ }
183
+ | {
184
+ type: MessageType.ABOUT;
185
+ timestamp: Date;
186
+ cliVersion: string;
187
+ osVersion: string;
188
+ sandboxEnv: string;
189
+ modelVersion: string;
190
+ selectedAuthType: string;
191
+ gcpProject: string;
192
+ ideClient: string;
193
+ content?: string; // Optional content, not really used for ABOUT
194
+ }
195
+ | {
196
+ type: MessageType.HELP;
197
+ timestamp: Date;
198
+ content?: string; // Optional content, not really used for HELP
199
+ }
200
+ | {
201
+ type: MessageType.STATS;
202
+ timestamp: Date;
203
+ duration: string;
204
+ content?: string;
205
+ }
206
+ | {
207
+ type: MessageType.MODEL_STATS;
208
+ timestamp: Date;
209
+ content?: string;
210
+ }
211
+ | {
212
+ type: MessageType.TOOL_STATS;
213
+ timestamp: Date;
214
+ content?: string;
215
+ }
216
+ | {
217
+ type: MessageType.QUIT;
218
+ timestamp: Date;
219
+ duration: string;
220
+ content?: string;
221
+ }
222
+ | {
223
+ type: MessageType.COMPRESSION;
224
+ compression: CompressionProps;
225
+ timestamp: Date;
226
+ };
227
+
228
+ export interface ConsoleMessageItem {
229
+ type: 'log' | 'warn' | 'error' | 'debug' | 'info';
230
+ content: string;
231
+ count: number;
232
+ }
233
+
234
+ /**
235
+ * Result type for a slash command that should immediately result in a prompt
236
+ * being submitted to the Gemini model.
237
+ */
238
+ export interface SubmitPromptResult {
239
+ type: 'submit_prompt';
240
+ content: string;
241
+ }
242
+
243
+ /**
244
+ * Defines the result of the slash command processor for its consumer (useGeminiStream).
245
+ */
246
+ export type SlashCommandProcessorResult =
247
+ | {
248
+ type: 'schedule_tool';
249
+ toolName: string;
250
+ toolArgs: Record<string, unknown>;
251
+ }
252
+ | {
253
+ type: 'handled'; // Indicates the command was processed and no further action is needed.
254
+ }
255
+ | SubmitPromptResult;
@@ -0,0 +1,217 @@
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 { common, createLowlight } from 'lowlight';
10
+ import type {
11
+ Root,
12
+ Element,
13
+ Text as HastText,
14
+ ElementContent,
15
+ RootContent,
16
+ } from 'hast';
17
+ import { themeManager } from '../themes/theme-manager.js';
18
+ import { Theme } from '../themes/theme.js';
19
+ import {
20
+ MaxSizedBox,
21
+ MINIMUM_MAX_HEIGHT,
22
+ } from '../components/shared/MaxSizedBox.js';
23
+ import { LoadedSettings } from '../../config/settings.js';
24
+
25
+ // Configure theming and parsing utilities.
26
+ const lowlight = createLowlight(common);
27
+
28
+ function renderHastNode(
29
+ node: Root | Element | HastText | RootContent,
30
+ theme: Theme,
31
+ inheritedColor: string | undefined,
32
+ ): React.ReactNode {
33
+ if (node.type === 'text') {
34
+ // Use the color passed down from parent element, if any
35
+ return <Text color={inheritedColor}>{node.value}</Text>;
36
+ }
37
+
38
+ // Handle Element Nodes: Determine color and pass it down, don't wrap
39
+ if (node.type === 'element') {
40
+ const nodeClasses: string[] =
41
+ (node.properties?.['className'] as string[]) || [];
42
+ let elementColor: string | undefined = undefined;
43
+
44
+ // Find color defined specifically for this element's class
45
+ for (let i = nodeClasses.length - 1; i >= 0; i--) {
46
+ const color = theme.getInkColor(nodeClasses[i]);
47
+ if (color) {
48
+ elementColor = color;
49
+ break;
50
+ }
51
+ }
52
+
53
+ // Determine the color to pass down: Use this element's specific color
54
+ // if found; otherwise, continue passing down the already inherited color.
55
+ const colorToPassDown = elementColor || inheritedColor;
56
+
57
+ // Recursively render children, passing the determined color down
58
+ // Ensure child type matches expected HAST structure (ElementContent is common)
59
+ const children = node.children?.map(
60
+ (child: ElementContent, index: number) => (
61
+ <React.Fragment key={index}>
62
+ {renderHastNode(child, theme, colorToPassDown)}
63
+ </React.Fragment>
64
+ ),
65
+ );
66
+
67
+ // Element nodes now only group children; color is applied by Text nodes.
68
+ // Use a React Fragment to avoid adding unnecessary elements.
69
+ return <React.Fragment>{children}</React.Fragment>;
70
+ }
71
+
72
+ // Handle Root Node: Start recursion with initially inherited color
73
+ if (node.type === 'root') {
74
+ // Check if children array is empty - this happens when lowlight can't detect language – fall back to plain text
75
+ if (!node.children || node.children.length === 0) {
76
+ return null;
77
+ }
78
+
79
+ // Pass down the initial inheritedColor (likely undefined from the top call)
80
+ // Ensure child type matches expected HAST structure (RootContent is common)
81
+ return node.children?.map((child: RootContent, index: number) => (
82
+ <React.Fragment key={index}>
83
+ {renderHastNode(child, theme, inheritedColor)}
84
+ </React.Fragment>
85
+ ));
86
+ }
87
+
88
+ // Handle unknown or unsupported node types
89
+ return null;
90
+ }
91
+
92
+ function highlightAndRenderLine(
93
+ line: string,
94
+ language: string | null,
95
+ theme: Theme,
96
+ ): React.ReactNode {
97
+ try {
98
+ const getHighlightedLine = () =>
99
+ !language || !lowlight.registered(language)
100
+ ? lowlight.highlightAuto(line)
101
+ : lowlight.highlight(language, line);
102
+
103
+ const renderedNode = renderHastNode(getHighlightedLine(), theme, undefined);
104
+
105
+ return renderedNode !== null ? renderedNode : line;
106
+ } catch (_error) {
107
+ return line;
108
+ }
109
+ }
110
+
111
+ export function colorizeLine(
112
+ line: string,
113
+ language: string | null,
114
+ theme?: Theme,
115
+ ): React.ReactNode {
116
+ const activeTheme = theme || themeManager.getActiveTheme();
117
+ return highlightAndRenderLine(line, language, activeTheme);
118
+ }
119
+
120
+ /**
121
+ * Renders syntax-highlighted code for Ink applications using a selected theme.
122
+ *
123
+ * @param code The code string to highlight.
124
+ * @param language The language identifier (e.g., 'javascript', 'css', 'html')
125
+ * @returns A React.ReactNode containing Ink <Text> elements for the highlighted code.
126
+ */
127
+ export function colorizeCode(
128
+ code: string,
129
+ language: string | null,
130
+ availableHeight?: number,
131
+ maxWidth?: number,
132
+ theme?: Theme,
133
+ settings?: LoadedSettings,
134
+ ): React.ReactNode {
135
+ const codeToHighlight = code.replace(/\n$/, '');
136
+ const activeTheme = theme || themeManager.getActiveTheme();
137
+ const showLineNumbers = settings?.merged.showLineNumbers ?? true;
138
+
139
+ try {
140
+ // Render the HAST tree using the adapted theme
141
+ // Apply the theme's default foreground color to the top-level Text element
142
+ let lines = codeToHighlight.split('\n');
143
+ const padWidth = String(lines.length).length; // Calculate padding width based on number of lines
144
+
145
+ let hiddenLinesCount = 0;
146
+
147
+ // Optimization to avoid highlighting lines that cannot possibly be displayed.
148
+ if (availableHeight !== undefined) {
149
+ availableHeight = Math.max(availableHeight, MINIMUM_MAX_HEIGHT);
150
+ if (lines.length > availableHeight) {
151
+ const sliceIndex = lines.length - availableHeight;
152
+ hiddenLinesCount = sliceIndex;
153
+ lines = lines.slice(sliceIndex);
154
+ }
155
+ }
156
+
157
+ return (
158
+ <MaxSizedBox
159
+ maxHeight={availableHeight}
160
+ maxWidth={maxWidth}
161
+ additionalHiddenLinesCount={hiddenLinesCount}
162
+ overflowDirection="top"
163
+ >
164
+ {lines.map((line, index) => {
165
+ const contentToRender = highlightAndRenderLine(
166
+ line,
167
+ language,
168
+ activeTheme,
169
+ );
170
+
171
+ return (
172
+ <Box key={index}>
173
+ {showLineNumbers && (
174
+ <Text color={activeTheme.colors.Gray}>
175
+ {`${String(index + 1 + hiddenLinesCount).padStart(
176
+ padWidth,
177
+ ' ',
178
+ )} `}
179
+ </Text>
180
+ )}
181
+ <Text color={activeTheme.defaultColor} wrap="wrap">
182
+ {contentToRender}
183
+ </Text>
184
+ </Box>
185
+ );
186
+ })}
187
+ </MaxSizedBox>
188
+ );
189
+ } catch (error) {
190
+ console.error(
191
+ `[colorizeCode] Error highlighting code for language "${language}":`,
192
+ error,
193
+ );
194
+ // Fall back to plain text with default color on error
195
+ // Also display line numbers in fallback
196
+ const lines = codeToHighlight.split('\n');
197
+ const padWidth = String(lines.length).length; // Calculate padding width based on number of lines
198
+ return (
199
+ <MaxSizedBox
200
+ maxHeight={availableHeight}
201
+ maxWidth={maxWidth}
202
+ overflowDirection="top"
203
+ >
204
+ {lines.map((line, index) => (
205
+ <Box key={index}>
206
+ {showLineNumbers && (
207
+ <Text color={activeTheme.defaultColor}>
208
+ {`${String(index + 1).padStart(padWidth, ' ')} `}
209
+ </Text>
210
+ )}
211
+ <Text color={activeTheme.colors.Gray}>{line}</Text>
212
+ </Box>
213
+ ))}
214
+ </MaxSizedBox>
215
+ );
216
+ }
217
+ }
@@ -0,0 +1,71 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ import util from 'util';
8
+ import { ConsoleMessageItem } from '../types.js';
9
+
10
+ interface ConsolePatcherParams {
11
+ onNewMessage?: (message: Omit<ConsoleMessageItem, 'id'>) => void;
12
+ debugMode: boolean;
13
+ stderr?: boolean;
14
+ }
15
+
16
+ export class ConsolePatcher {
17
+ private originalConsoleLog = console.log;
18
+ private originalConsoleWarn = console.warn;
19
+ private originalConsoleError = console.error;
20
+ private originalConsoleDebug = console.debug;
21
+ private originalConsoleInfo = console.info;
22
+
23
+ private params: ConsolePatcherParams;
24
+
25
+ constructor(params: ConsolePatcherParams) {
26
+ this.params = params;
27
+ }
28
+
29
+ patch() {
30
+ console.log = this.patchConsoleMethod('log', this.originalConsoleLog);
31
+ console.warn = this.patchConsoleMethod('warn', this.originalConsoleWarn);
32
+ console.error = this.patchConsoleMethod('error', this.originalConsoleError);
33
+ console.debug = this.patchConsoleMethod('debug', this.originalConsoleDebug);
34
+ console.info = this.patchConsoleMethod('info', this.originalConsoleInfo);
35
+ }
36
+
37
+ cleanup = () => {
38
+ console.log = this.originalConsoleLog;
39
+ console.warn = this.originalConsoleWarn;
40
+ console.error = this.originalConsoleError;
41
+ console.debug = this.originalConsoleDebug;
42
+ console.info = this.originalConsoleInfo;
43
+ };
44
+
45
+ private formatArgs = (args: unknown[]): string => util.format(...args);
46
+
47
+ private patchConsoleMethod =
48
+ (
49
+ type: 'log' | 'warn' | 'error' | 'debug' | 'info',
50
+ originalMethod: (...args: unknown[]) => void,
51
+ ) =>
52
+ (...args: unknown[]) => {
53
+ if (this.params.stderr) {
54
+ if (type !== 'debug' || this.params.debugMode) {
55
+ this.originalConsoleError(this.formatArgs(args));
56
+ }
57
+ } else {
58
+ if (this.params.debugMode) {
59
+ originalMethod.apply(console, args);
60
+ }
61
+
62
+ if (type !== 'debug' || this.params.debugMode) {
63
+ this.params.onNewMessage?.({
64
+ type,
65
+ content: this.formatArgs(args),
66
+ count: 1,
67
+ });
68
+ }
69
+ }
70
+ };
71
+ }
@@ -0,0 +1,173 @@
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 } from 'ink';
9
+ import { Colors } from '../colors.js';
10
+ import stringWidth from 'string-width';
11
+
12
+ // Constants for Markdown parsing
13
+ const BOLD_MARKER_LENGTH = 2; // For "**"
14
+ const ITALIC_MARKER_LENGTH = 1; // For "*" or "_"
15
+ const STRIKETHROUGH_MARKER_LENGTH = 2; // For "~~"
16
+ const INLINE_CODE_MARKER_LENGTH = 1; // For "`"
17
+ const UNDERLINE_TAG_START_LENGTH = 3; // For "<u>"
18
+ const UNDERLINE_TAG_END_LENGTH = 4; // For "</u>"
19
+
20
+ interface RenderInlineProps {
21
+ text: string;
22
+ }
23
+
24
+ const RenderInlineInternal: React.FC<RenderInlineProps> = ({ text }) => {
25
+ // Early return for plain text without markdown or URLs
26
+ if (!/[*_~`<[https?:]/.test(text)) {
27
+ return <Text>{text}</Text>;
28
+ }
29
+
30
+ const nodes: React.ReactNode[] = [];
31
+ let lastIndex = 0;
32
+ const inlineRegex =
33
+ /(\*\*.*?\*\*|\*.*?\*|_.*?_|~~.*?~~|\[.*?\]\(.*?\)|`+.+?`+|<u>.*?<\/u>|https?:\/\/\S+)/g;
34
+ let match;
35
+
36
+ while ((match = inlineRegex.exec(text)) !== null) {
37
+ if (match.index > lastIndex) {
38
+ nodes.push(
39
+ <Text key={`t-${lastIndex}`}>
40
+ {text.slice(lastIndex, match.index)}
41
+ </Text>,
42
+ );
43
+ }
44
+
45
+ const fullMatch = match[0];
46
+ let renderedNode: React.ReactNode = null;
47
+ const key = `m-${match.index}`;
48
+
49
+ try {
50
+ if (
51
+ fullMatch.startsWith('**') &&
52
+ fullMatch.endsWith('**') &&
53
+ fullMatch.length > BOLD_MARKER_LENGTH * 2
54
+ ) {
55
+ renderedNode = (
56
+ <Text key={key} bold>
57
+ {fullMatch.slice(BOLD_MARKER_LENGTH, -BOLD_MARKER_LENGTH)}
58
+ </Text>
59
+ );
60
+ } else if (
61
+ fullMatch.length > ITALIC_MARKER_LENGTH * 2 &&
62
+ ((fullMatch.startsWith('*') && fullMatch.endsWith('*')) ||
63
+ (fullMatch.startsWith('_') && fullMatch.endsWith('_'))) &&
64
+ !/\w/.test(text.substring(match.index - 1, match.index)) &&
65
+ !/\w/.test(
66
+ text.substring(inlineRegex.lastIndex, inlineRegex.lastIndex + 1),
67
+ ) &&
68
+ !/\S[./\\]/.test(text.substring(match.index - 2, match.index)) &&
69
+ !/[./\\]\S/.test(
70
+ text.substring(inlineRegex.lastIndex, inlineRegex.lastIndex + 2),
71
+ )
72
+ ) {
73
+ renderedNode = (
74
+ <Text key={key} italic>
75
+ {fullMatch.slice(ITALIC_MARKER_LENGTH, -ITALIC_MARKER_LENGTH)}
76
+ </Text>
77
+ );
78
+ } else if (
79
+ fullMatch.startsWith('~~') &&
80
+ fullMatch.endsWith('~~') &&
81
+ fullMatch.length > STRIKETHROUGH_MARKER_LENGTH * 2
82
+ ) {
83
+ renderedNode = (
84
+ <Text key={key} strikethrough>
85
+ {fullMatch.slice(
86
+ STRIKETHROUGH_MARKER_LENGTH,
87
+ -STRIKETHROUGH_MARKER_LENGTH,
88
+ )}
89
+ </Text>
90
+ );
91
+ } else if (
92
+ fullMatch.startsWith('`') &&
93
+ fullMatch.endsWith('`') &&
94
+ fullMatch.length > INLINE_CODE_MARKER_LENGTH
95
+ ) {
96
+ const codeMatch = fullMatch.match(/^(`+)(.+?)\1$/s);
97
+ if (codeMatch && codeMatch[2]) {
98
+ renderedNode = (
99
+ <Text key={key} color={Colors.AccentPurple}>
100
+ {codeMatch[2]}
101
+ </Text>
102
+ );
103
+ }
104
+ } else if (
105
+ fullMatch.startsWith('[') &&
106
+ fullMatch.includes('](') &&
107
+ fullMatch.endsWith(')')
108
+ ) {
109
+ const linkMatch = fullMatch.match(/\[(.*?)\]\((.*?)\)/);
110
+ if (linkMatch) {
111
+ const linkText = linkMatch[1];
112
+ const url = linkMatch[2];
113
+ renderedNode = (
114
+ <Text key={key}>
115
+ {linkText}
116
+ <Text color={Colors.AccentBlue}> ({url})</Text>
117
+ </Text>
118
+ );
119
+ }
120
+ } else if (
121
+ fullMatch.startsWith('<u>') &&
122
+ fullMatch.endsWith('</u>') &&
123
+ fullMatch.length >
124
+ UNDERLINE_TAG_START_LENGTH + UNDERLINE_TAG_END_LENGTH - 1 // -1 because length is compared to combined length of start and end tags
125
+ ) {
126
+ renderedNode = (
127
+ <Text key={key} underline>
128
+ {fullMatch.slice(
129
+ UNDERLINE_TAG_START_LENGTH,
130
+ -UNDERLINE_TAG_END_LENGTH,
131
+ )}
132
+ </Text>
133
+ );
134
+ } else if (fullMatch.match(/^https?:\/\//)) {
135
+ renderedNode = (
136
+ <Text key={key} color={Colors.AccentBlue}>
137
+ {fullMatch}
138
+ </Text>
139
+ );
140
+ }
141
+ } catch (e) {
142
+ console.error('Error parsing inline markdown part:', fullMatch, e);
143
+ renderedNode = null;
144
+ }
145
+
146
+ nodes.push(renderedNode ?? <Text key={key}>{fullMatch}</Text>);
147
+ lastIndex = inlineRegex.lastIndex;
148
+ }
149
+
150
+ if (lastIndex < text.length) {
151
+ nodes.push(<Text key={`t-${lastIndex}`}>{text.slice(lastIndex)}</Text>);
152
+ }
153
+
154
+ return <>{nodes.filter((node) => node !== null)}</>;
155
+ };
156
+
157
+ export const RenderInline = React.memo(RenderInlineInternal);
158
+
159
+ /**
160
+ * Utility function to get the plain text length of a string with markdown formatting
161
+ * This is useful for calculating column widths in tables
162
+ */
163
+ export const getPlainTextLength = (text: string): number => {
164
+ const cleanText = text
165
+ .replace(/\*\*(.*?)\*\*/g, '$1')
166
+ .replace(/\*(.*?)\*/g, '$1')
167
+ .replace(/_(.*?)_/g, '$1')
168
+ .replace(/~~(.*?)~~/g, '$1')
169
+ .replace(/`(.*?)`/g, '$1')
170
+ .replace(/<u>(.*?)<\/u>/g, '$1')
171
+ .replace(/\[(.*?)\]\(.*?\)/g, '$1');
172
+ return stringWidth(cleanText);
173
+ };