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,244 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ import { render } from 'ink-testing-library';
8
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
9
+ import { MarkdownDisplay } from './MarkdownDisplay.js';
10
+ import { LoadedSettings } from '../../config/settings.js';
11
+ import { SettingsContext } from '../contexts/SettingsContext.js';
12
+
13
+ describe('<MarkdownDisplay />', () => {
14
+ const baseProps = {
15
+ isPending: false,
16
+ terminalWidth: 80,
17
+ availableTerminalHeight: 40,
18
+ };
19
+
20
+ const mockSettings = new LoadedSettings(
21
+ { path: '', settings: {} },
22
+ { path: '', settings: {} },
23
+ { path: '', settings: {} },
24
+ [],
25
+ );
26
+
27
+ beforeEach(() => {
28
+ vi.clearAllMocks();
29
+ });
30
+
31
+ it('renders nothing for empty text', () => {
32
+ const { lastFrame } = render(
33
+ <SettingsContext.Provider value={mockSettings}>
34
+ <MarkdownDisplay {...baseProps} text="" />
35
+ </SettingsContext.Provider>,
36
+ );
37
+ expect(lastFrame()).toMatchSnapshot();
38
+ });
39
+
40
+ it('renders a simple paragraph', () => {
41
+ const text = 'Hello, world.';
42
+ const { lastFrame } = render(
43
+ <SettingsContext.Provider value={mockSettings}>
44
+ <MarkdownDisplay {...baseProps} text={text} />
45
+ </SettingsContext.Provider>,
46
+ );
47
+ expect(lastFrame()).toMatchSnapshot();
48
+ });
49
+
50
+ it('renders headers with correct levels', () => {
51
+ const text = `
52
+ # Header 1
53
+ ## Header 2
54
+ ### Header 3
55
+ #### Header 4
56
+ `;
57
+ const { lastFrame } = render(
58
+ <SettingsContext.Provider value={mockSettings}>
59
+ <MarkdownDisplay {...baseProps} text={text} />
60
+ </SettingsContext.Provider>,
61
+ );
62
+ expect(lastFrame()).toMatchSnapshot();
63
+ });
64
+
65
+ it('renders a fenced code block with a language', () => {
66
+ const text = '```javascript\nconst x = 1;\nconsole.log(x);\n```';
67
+ const { lastFrame } = render(
68
+ <SettingsContext.Provider value={mockSettings}>
69
+ <MarkdownDisplay {...baseProps} text={text} />
70
+ </SettingsContext.Provider>,
71
+ );
72
+ expect(lastFrame()).toMatchSnapshot();
73
+ });
74
+
75
+ it('renders a fenced code block without a language', () => {
76
+ const text = '```\nplain text\n```';
77
+ const { lastFrame } = render(
78
+ <SettingsContext.Provider value={mockSettings}>
79
+ <MarkdownDisplay {...baseProps} text={text} />
80
+ </SettingsContext.Provider>,
81
+ );
82
+ expect(lastFrame()).toMatchSnapshot();
83
+ });
84
+
85
+ it('handles unclosed (pending) code blocks', () => {
86
+ const text = '```typescript\nlet y = 2;';
87
+ const { lastFrame } = render(
88
+ <SettingsContext.Provider value={mockSettings}>
89
+ <MarkdownDisplay {...baseProps} text={text} isPending={true} />
90
+ </SettingsContext.Provider>,
91
+ );
92
+ expect(lastFrame()).toMatchSnapshot();
93
+ });
94
+
95
+ it('renders unordered lists with different markers', () => {
96
+ const text = `
97
+ - item A
98
+ * item B
99
+ + item C
100
+ `;
101
+ const { lastFrame } = render(
102
+ <SettingsContext.Provider value={mockSettings}>
103
+ <MarkdownDisplay {...baseProps} text={text} />
104
+ </SettingsContext.Provider>,
105
+ );
106
+ expect(lastFrame()).toMatchSnapshot();
107
+ });
108
+
109
+ it('renders nested unordered lists', () => {
110
+ const text = `
111
+ * Level 1
112
+ * Level 2
113
+ * Level 3
114
+ `;
115
+ const { lastFrame } = render(
116
+ <SettingsContext.Provider value={mockSettings}>
117
+ <MarkdownDisplay {...baseProps} text={text} />
118
+ </SettingsContext.Provider>,
119
+ );
120
+ expect(lastFrame()).toMatchSnapshot();
121
+ });
122
+
123
+ it('renders ordered lists', () => {
124
+ const text = `
125
+ 1. First item
126
+ 2. Second item
127
+ `;
128
+ const { lastFrame } = render(
129
+ <SettingsContext.Provider value={mockSettings}>
130
+ <MarkdownDisplay {...baseProps} text={text} />
131
+ </SettingsContext.Provider>,
132
+ );
133
+ expect(lastFrame()).toMatchSnapshot();
134
+ });
135
+
136
+ it('renders horizontal rules', () => {
137
+ const text = `
138
+ Hello
139
+ ---
140
+ World
141
+ ***
142
+ Test
143
+ `;
144
+ const { lastFrame } = render(
145
+ <SettingsContext.Provider value={mockSettings}>
146
+ <MarkdownDisplay {...baseProps} text={text} />
147
+ </SettingsContext.Provider>,
148
+ );
149
+ expect(lastFrame()).toMatchSnapshot();
150
+ });
151
+
152
+ it('renders tables correctly', () => {
153
+ const text = `
154
+ | Header 1 | Header 2 |
155
+ |----------|:--------:|
156
+ | Cell 1 | Cell 2 |
157
+ | Cell 3 | Cell 4 |
158
+ `;
159
+ const { lastFrame } = render(
160
+ <SettingsContext.Provider value={mockSettings}>
161
+ <MarkdownDisplay {...baseProps} text={text} />
162
+ </SettingsContext.Provider>,
163
+ );
164
+ expect(lastFrame()).toMatchSnapshot();
165
+ });
166
+
167
+ it('handles a table at the end of the input', () => {
168
+ const text = `
169
+ Some text before.
170
+ | A | B |
171
+ |---|
172
+ | 1 | 2 |`;
173
+ const { lastFrame } = render(
174
+ <SettingsContext.Provider value={mockSettings}>
175
+ <MarkdownDisplay {...baseProps} text={text} />
176
+ </SettingsContext.Provider>,
177
+ );
178
+ expect(lastFrame()).toMatchSnapshot();
179
+ });
180
+
181
+ it('inserts a single space between paragraphs', () => {
182
+ const text = `Paragraph 1.
183
+
184
+ Paragraph 2.`;
185
+ const { lastFrame } = render(
186
+ <SettingsContext.Provider value={mockSettings}>
187
+ <MarkdownDisplay {...baseProps} text={text} />
188
+ </SettingsContext.Provider>,
189
+ );
190
+ expect(lastFrame()).toMatchSnapshot();
191
+ });
192
+
193
+ it('correctly parses a mix of markdown elements', () => {
194
+ const text = `
195
+ # Main Title
196
+
197
+ Here is a paragraph.
198
+
199
+ - List item 1
200
+ - List item 2
201
+
202
+ \`\`\`
203
+ some code
204
+ \`\`\`
205
+
206
+ Another paragraph.
207
+ `;
208
+ const { lastFrame } = render(
209
+ <SettingsContext.Provider value={mockSettings}>
210
+ <MarkdownDisplay {...baseProps} text={text} />
211
+ </SettingsContext.Provider>,
212
+ );
213
+ expect(lastFrame()).toMatchSnapshot();
214
+ });
215
+
216
+ it('hides line numbers in code blocks when showLineNumbers is false', () => {
217
+ const text = '```javascript\nconst x = 1;\n```';
218
+ const settings = new LoadedSettings(
219
+ { path: '', settings: {} },
220
+ { path: '', settings: { showLineNumbers: false } },
221
+ { path: '', settings: {} },
222
+ [],
223
+ );
224
+
225
+ const { lastFrame } = render(
226
+ <SettingsContext.Provider value={settings}>
227
+ <MarkdownDisplay {...baseProps} text={text} />
228
+ </SettingsContext.Provider>,
229
+ );
230
+ expect(lastFrame()).toMatchSnapshot();
231
+ expect(lastFrame()).not.toContain(' 1 ');
232
+ });
233
+
234
+ it('shows line numbers in code blocks by default', () => {
235
+ const text = '```javascript\nconst x = 1;\n```';
236
+ const { lastFrame } = render(
237
+ <SettingsContext.Provider value={mockSettings}>
238
+ <MarkdownDisplay {...baseProps} text={text} />
239
+ </SettingsContext.Provider>,
240
+ );
241
+ expect(lastFrame()).toMatchSnapshot();
242
+ expect(lastFrame()).toContain(' 1 ');
243
+ });
244
+ });
@@ -0,0 +1,415 @@
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 { colorizeCode } from './CodeColorizer.js';
11
+ import { TableRenderer } from './TableRenderer.js';
12
+ import { RenderInline } from './InlineMarkdownRenderer.js';
13
+ import { useSettings } from '../contexts/SettingsContext.js';
14
+
15
+ interface MarkdownDisplayProps {
16
+ text: string;
17
+ isPending: boolean;
18
+ availableTerminalHeight?: number;
19
+ terminalWidth: number;
20
+ }
21
+
22
+ // Constants for Markdown parsing and rendering
23
+
24
+ const EMPTY_LINE_HEIGHT = 1;
25
+ const CODE_BLOCK_PREFIX_PADDING = 1;
26
+ const LIST_ITEM_PREFIX_PADDING = 1;
27
+ const LIST_ITEM_TEXT_FLEX_GROW = 1;
28
+
29
+ const MarkdownDisplayInternal: React.FC<MarkdownDisplayProps> = ({
30
+ text,
31
+ isPending,
32
+ availableTerminalHeight,
33
+ terminalWidth,
34
+ }) => {
35
+ if (!text) return <></>;
36
+
37
+ const lines = text.split('\n');
38
+ const headerRegex = /^ *(#{1,4}) +(.*)/;
39
+ const codeFenceRegex = /^ *(`{3,}|~{3,}) *(\w*?) *$/;
40
+ const ulItemRegex = /^([ \t]*)([-*+]) +(.*)/;
41
+ const olItemRegex = /^([ \t]*)(\d+)\. +(.*)/;
42
+ const hrRegex = /^ *([-*_] *){3,} *$/;
43
+ const tableRowRegex = /^\s*\|(.+)\|\s*$/;
44
+ const tableSeparatorRegex = /^\s*\|?\s*(:?-+:?)\s*(\|\s*(:?-+:?)\s*)+\|?\s*$/;
45
+
46
+ const contentBlocks: React.ReactNode[] = [];
47
+ let inCodeBlock = false;
48
+ let lastLineEmpty = true;
49
+ let codeBlockContent: string[] = [];
50
+ let codeBlockLang: string | null = null;
51
+ let codeBlockFence = '';
52
+ let inTable = false;
53
+ let tableRows: string[][] = [];
54
+ let tableHeaders: string[] = [];
55
+
56
+ function addContentBlock(block: React.ReactNode) {
57
+ if (block) {
58
+ contentBlocks.push(block);
59
+ lastLineEmpty = false;
60
+ }
61
+ }
62
+
63
+ lines.forEach((line, index) => {
64
+ const key = `line-${index}`;
65
+
66
+ if (inCodeBlock) {
67
+ const fenceMatch = line.match(codeFenceRegex);
68
+ if (
69
+ fenceMatch &&
70
+ fenceMatch[1].startsWith(codeBlockFence[0]) &&
71
+ fenceMatch[1].length >= codeBlockFence.length
72
+ ) {
73
+ addContentBlock(
74
+ <RenderCodeBlock
75
+ key={key}
76
+ content={codeBlockContent}
77
+ lang={codeBlockLang}
78
+ isPending={isPending}
79
+ availableTerminalHeight={availableTerminalHeight}
80
+ terminalWidth={terminalWidth}
81
+ />,
82
+ );
83
+ inCodeBlock = false;
84
+ codeBlockContent = [];
85
+ codeBlockLang = null;
86
+ codeBlockFence = '';
87
+ } else {
88
+ codeBlockContent.push(line);
89
+ }
90
+ return;
91
+ }
92
+
93
+ const codeFenceMatch = line.match(codeFenceRegex);
94
+ const headerMatch = line.match(headerRegex);
95
+ const ulMatch = line.match(ulItemRegex);
96
+ const olMatch = line.match(olItemRegex);
97
+ const hrMatch = line.match(hrRegex);
98
+ const tableRowMatch = line.match(tableRowRegex);
99
+ const tableSeparatorMatch = line.match(tableSeparatorRegex);
100
+
101
+ if (codeFenceMatch) {
102
+ inCodeBlock = true;
103
+ codeBlockFence = codeFenceMatch[1];
104
+ codeBlockLang = codeFenceMatch[2] || null;
105
+ } else if (tableRowMatch && !inTable) {
106
+ // Potential table start - check if next line is separator
107
+ if (
108
+ index + 1 < lines.length &&
109
+ lines[index + 1].match(tableSeparatorRegex)
110
+ ) {
111
+ inTable = true;
112
+ tableHeaders = tableRowMatch[1].split('|').map((cell) => cell.trim());
113
+ tableRows = [];
114
+ } else {
115
+ // Not a table, treat as regular text
116
+ addContentBlock(
117
+ <Box key={key}>
118
+ <Text wrap="wrap">
119
+ <RenderInline text={line} />
120
+ </Text>
121
+ </Box>,
122
+ );
123
+ }
124
+ } else if (inTable && tableSeparatorMatch) {
125
+ // Skip separator line - already handled
126
+ } else if (inTable && tableRowMatch) {
127
+ // Add table row
128
+ const cells = tableRowMatch[1].split('|').map((cell) => cell.trim());
129
+ // Ensure row has same column count as headers
130
+ while (cells.length < tableHeaders.length) {
131
+ cells.push('');
132
+ }
133
+ if (cells.length > tableHeaders.length) {
134
+ cells.length = tableHeaders.length;
135
+ }
136
+ tableRows.push(cells);
137
+ } else if (inTable && !tableRowMatch) {
138
+ // End of table
139
+ if (tableHeaders.length > 0 && tableRows.length > 0) {
140
+ addContentBlock(
141
+ <RenderTable
142
+ key={`table-${contentBlocks.length}`}
143
+ headers={tableHeaders}
144
+ rows={tableRows}
145
+ terminalWidth={terminalWidth}
146
+ />,
147
+ );
148
+ }
149
+ inTable = false;
150
+ tableRows = [];
151
+ tableHeaders = [];
152
+
153
+ // Process current line as normal
154
+ if (line.trim().length > 0) {
155
+ addContentBlock(
156
+ <Box key={key}>
157
+ <Text wrap="wrap">
158
+ <RenderInline text={line} />
159
+ </Text>
160
+ </Box>,
161
+ );
162
+ }
163
+ } else if (hrMatch) {
164
+ addContentBlock(
165
+ <Box key={key}>
166
+ <Text dimColor>---</Text>
167
+ </Box>,
168
+ );
169
+ } else if (headerMatch) {
170
+ const level = headerMatch[1].length;
171
+ const headerText = headerMatch[2];
172
+ let headerNode: React.ReactNode = null;
173
+ switch (level) {
174
+ case 1:
175
+ headerNode = (
176
+ <Text bold color={Colors.AccentCyan}>
177
+ <RenderInline text={headerText} />
178
+ </Text>
179
+ );
180
+ break;
181
+ case 2:
182
+ headerNode = (
183
+ <Text bold color={Colors.AccentBlue}>
184
+ <RenderInline text={headerText} />
185
+ </Text>
186
+ );
187
+ break;
188
+ case 3:
189
+ headerNode = (
190
+ <Text bold>
191
+ <RenderInline text={headerText} />
192
+ </Text>
193
+ );
194
+ break;
195
+ case 4:
196
+ headerNode = (
197
+ <Text italic color={Colors.Gray}>
198
+ <RenderInline text={headerText} />
199
+ </Text>
200
+ );
201
+ break;
202
+ default:
203
+ headerNode = (
204
+ <Text>
205
+ <RenderInline text={headerText} />
206
+ </Text>
207
+ );
208
+ break;
209
+ }
210
+ if (headerNode) addContentBlock(<Box key={key}>{headerNode}</Box>);
211
+ } else if (ulMatch) {
212
+ const leadingWhitespace = ulMatch[1];
213
+ const marker = ulMatch[2];
214
+ const itemText = ulMatch[3];
215
+ addContentBlock(
216
+ <RenderListItem
217
+ key={key}
218
+ itemText={itemText}
219
+ type="ul"
220
+ marker={marker}
221
+ leadingWhitespace={leadingWhitespace}
222
+ />,
223
+ );
224
+ } else if (olMatch) {
225
+ const leadingWhitespace = olMatch[1];
226
+ const marker = olMatch[2];
227
+ const itemText = olMatch[3];
228
+ addContentBlock(
229
+ <RenderListItem
230
+ key={key}
231
+ itemText={itemText}
232
+ type="ol"
233
+ marker={marker}
234
+ leadingWhitespace={leadingWhitespace}
235
+ />,
236
+ );
237
+ } else {
238
+ if (line.trim().length === 0 && !inCodeBlock) {
239
+ if (!lastLineEmpty) {
240
+ contentBlocks.push(
241
+ <Box key={`spacer-${index}`} height={EMPTY_LINE_HEIGHT} />,
242
+ );
243
+ lastLineEmpty = true;
244
+ }
245
+ } else {
246
+ addContentBlock(
247
+ <Box key={key}>
248
+ <Text wrap="wrap">
249
+ <RenderInline text={line} />
250
+ </Text>
251
+ </Box>,
252
+ );
253
+ }
254
+ }
255
+ });
256
+
257
+ if (inCodeBlock) {
258
+ addContentBlock(
259
+ <RenderCodeBlock
260
+ key="line-eof"
261
+ content={codeBlockContent}
262
+ lang={codeBlockLang}
263
+ isPending={isPending}
264
+ availableTerminalHeight={availableTerminalHeight}
265
+ terminalWidth={terminalWidth}
266
+ />,
267
+ );
268
+ }
269
+
270
+ // Handle table at end of content
271
+ if (inTable && tableHeaders.length > 0 && tableRows.length > 0) {
272
+ addContentBlock(
273
+ <RenderTable
274
+ key={`table-${contentBlocks.length}`}
275
+ headers={tableHeaders}
276
+ rows={tableRows}
277
+ terminalWidth={terminalWidth}
278
+ />,
279
+ );
280
+ }
281
+
282
+ return <>{contentBlocks}</>;
283
+ };
284
+
285
+ // Helper functions (adapted from static methods of MarkdownRenderer)
286
+
287
+ interface RenderCodeBlockProps {
288
+ content: string[];
289
+ lang: string | null;
290
+ isPending: boolean;
291
+ availableTerminalHeight?: number;
292
+ terminalWidth: number;
293
+ }
294
+
295
+ const RenderCodeBlockInternal: React.FC<RenderCodeBlockProps> = ({
296
+ content,
297
+ lang,
298
+ isPending,
299
+ availableTerminalHeight,
300
+ terminalWidth,
301
+ }) => {
302
+ const settings = useSettings();
303
+ const MIN_LINES_FOR_MESSAGE = 1; // Minimum lines to show before the "generating more" message
304
+ const RESERVED_LINES = 2; // Lines reserved for the message itself and potential padding
305
+
306
+ if (isPending && availableTerminalHeight !== undefined) {
307
+ const MAX_CODE_LINES_WHEN_PENDING = Math.max(
308
+ 0,
309
+ availableTerminalHeight - RESERVED_LINES,
310
+ );
311
+
312
+ if (content.length > MAX_CODE_LINES_WHEN_PENDING) {
313
+ if (MAX_CODE_LINES_WHEN_PENDING < MIN_LINES_FOR_MESSAGE) {
314
+ // Not enough space to even show the message meaningfully
315
+ return (
316
+ <Box paddingLeft={CODE_BLOCK_PREFIX_PADDING}>
317
+ <Text color={Colors.Gray}>... code is being written ...</Text>
318
+ </Box>
319
+ );
320
+ }
321
+ const truncatedContent = content.slice(0, MAX_CODE_LINES_WHEN_PENDING);
322
+ const colorizedTruncatedCode = colorizeCode(
323
+ truncatedContent.join('\n'),
324
+ lang,
325
+ availableTerminalHeight,
326
+ terminalWidth - CODE_BLOCK_PREFIX_PADDING,
327
+ undefined,
328
+ settings,
329
+ );
330
+ return (
331
+ <Box paddingLeft={CODE_BLOCK_PREFIX_PADDING} flexDirection="column">
332
+ {colorizedTruncatedCode}
333
+ <Text color={Colors.Gray}>... generating more ...</Text>
334
+ </Box>
335
+ );
336
+ }
337
+ }
338
+
339
+ const fullContent = content.join('\n');
340
+ const colorizedCode = colorizeCode(
341
+ fullContent,
342
+ lang,
343
+ availableTerminalHeight,
344
+ terminalWidth - CODE_BLOCK_PREFIX_PADDING,
345
+ undefined,
346
+ settings,
347
+ );
348
+
349
+ return (
350
+ <Box
351
+ paddingLeft={CODE_BLOCK_PREFIX_PADDING}
352
+ flexDirection="column"
353
+ width={terminalWidth}
354
+ flexShrink={0}
355
+ >
356
+ {colorizedCode}
357
+ </Box>
358
+ );
359
+ };
360
+
361
+ const RenderCodeBlock = React.memo(RenderCodeBlockInternal);
362
+
363
+ interface RenderListItemProps {
364
+ itemText: string;
365
+ type: 'ul' | 'ol';
366
+ marker: string;
367
+ leadingWhitespace?: string;
368
+ }
369
+
370
+ const RenderListItemInternal: React.FC<RenderListItemProps> = ({
371
+ itemText,
372
+ type,
373
+ marker,
374
+ leadingWhitespace = '',
375
+ }) => {
376
+ const prefix = type === 'ol' ? `${marker}. ` : `${marker} `;
377
+ const prefixWidth = prefix.length;
378
+ const indentation = leadingWhitespace.length;
379
+
380
+ return (
381
+ <Box
382
+ paddingLeft={indentation + LIST_ITEM_PREFIX_PADDING}
383
+ flexDirection="row"
384
+ >
385
+ <Box width={prefixWidth}>
386
+ <Text>{prefix}</Text>
387
+ </Box>
388
+ <Box flexGrow={LIST_ITEM_TEXT_FLEX_GROW}>
389
+ <Text wrap="wrap">
390
+ <RenderInline text={itemText} />
391
+ </Text>
392
+ </Box>
393
+ </Box>
394
+ );
395
+ };
396
+
397
+ const RenderListItem = React.memo(RenderListItemInternal);
398
+
399
+ interface RenderTableProps {
400
+ headers: string[];
401
+ rows: string[][];
402
+ terminalWidth: number;
403
+ }
404
+
405
+ const RenderTableInternal: React.FC<RenderTableProps> = ({
406
+ headers,
407
+ rows,
408
+ terminalWidth,
409
+ }) => (
410
+ <TableRenderer headers={headers} rows={rows} terminalWidth={terminalWidth} />
411
+ );
412
+
413
+ const RenderTable = React.memo(RenderTableInternal);
414
+
415
+ export const MarkdownDisplay = React.memo(MarkdownDisplayInternal);