@machina.ai/cell-cli 1.10.0-rc1 → 1.11.0-rc1

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 (508) hide show
  1. package/dist/index.js +5 -5
  2. package/dist/index.js.map +1 -1
  3. package/dist/package.json +7 -7
  4. package/dist/src/commands/extensions/disable.js +8 -5
  5. package/dist/src/commands/extensions/disable.js.map +1 -1
  6. package/dist/src/commands/extensions/enable.js +8 -6
  7. package/dist/src/commands/extensions/enable.js.map +1 -1
  8. package/dist/src/commands/extensions/examples/mcp-server/example.d.ts +6 -0
  9. package/dist/src/commands/extensions/examples/mcp-server/example.js +46 -0
  10. package/dist/src/commands/extensions/examples/mcp-server/example.js.map +1 -0
  11. package/dist/src/commands/extensions/install.d.ts +1 -0
  12. package/dist/src/commands/extensions/install.js +18 -4
  13. package/dist/src/commands/extensions/install.js.map +1 -1
  14. package/dist/src/commands/extensions/link.js +3 -2
  15. package/dist/src/commands/extensions/link.js.map +1 -1
  16. package/dist/src/commands/extensions/list.js +7 -5
  17. package/dist/src/commands/extensions/list.js.map +1 -1
  18. package/dist/src/commands/extensions/new.js +14 -20
  19. package/dist/src/commands/extensions/new.js.map +1 -1
  20. package/dist/src/commands/extensions/uninstall.js +3 -2
  21. package/dist/src/commands/extensions/uninstall.js.map +1 -1
  22. package/dist/src/commands/extensions/update.js +17 -17
  23. package/dist/src/commands/extensions/update.js.map +1 -1
  24. package/dist/src/commands/mcp/add.js +7 -4
  25. package/dist/src/commands/mcp/add.js.map +1 -1
  26. package/dist/src/commands/mcp/add.test.d.ts +6 -0
  27. package/dist/src/commands/mcp/add.test.js +244 -0
  28. package/dist/src/commands/mcp/add.test.js.map +1 -0
  29. package/dist/src/commands/mcp/list.js +10 -8
  30. package/dist/src/commands/mcp/list.js.map +1 -1
  31. package/dist/src/commands/mcp/list.test.d.ts +6 -0
  32. package/dist/src/commands/mcp/list.test.js +118 -0
  33. package/dist/src/commands/mcp/list.test.js.map +1 -0
  34. package/dist/src/commands/mcp/remove.js +3 -2
  35. package/dist/src/commands/mcp/remove.js.map +1 -1
  36. package/dist/src/commands/mcp/remove.test.d.ts +6 -0
  37. package/dist/src/commands/mcp/remove.test.js +175 -0
  38. package/dist/src/commands/mcp/remove.test.js.map +1 -0
  39. package/dist/src/commands/mcp.test.d.ts +6 -0
  40. package/dist/src/commands/mcp.test.js +62 -0
  41. package/dist/src/commands/mcp.test.js.map +1 -0
  42. package/dist/src/config/auth.js +3 -1
  43. package/dist/src/config/auth.js.map +1 -1
  44. package/dist/src/config/config.d.ts +2 -14
  45. package/dist/src/config/config.integration.test.d.ts +6 -0
  46. package/dist/src/config/config.integration.test.js +321 -0
  47. package/dist/src/config/config.integration.test.js.map +1 -0
  48. package/dist/src/config/config.js +37 -101
  49. package/dist/src/config/config.js.map +1 -1
  50. package/dist/src/config/config.test.d.ts +6 -0
  51. package/dist/src/config/config.test.js +1949 -0
  52. package/dist/src/config/config.test.js.map +1 -0
  53. package/dist/src/config/extension.d.ts +5 -15
  54. package/dist/src/config/extension.js +106 -109
  55. package/dist/src/config/extension.js.map +1 -1
  56. package/dist/src/config/extension.test.d.ts +6 -0
  57. package/dist/src/config/extension.test.js +1088 -0
  58. package/dist/src/config/extension.test.js.map +1 -0
  59. package/dist/src/config/extensions/extensionEnablement.d.ts +1 -1
  60. package/dist/src/config/extensions/extensionEnablement.js +4 -3
  61. package/dist/src/config/extensions/extensionEnablement.js.map +1 -1
  62. package/dist/src/config/extensions/extensionEnablement.test.js +21 -18
  63. package/dist/src/config/extensions/extensionEnablement.test.js.map +1 -1
  64. package/dist/src/config/extensions/github.d.ts +18 -9
  65. package/dist/src/config/extensions/github.js +106 -29
  66. package/dist/src/config/extensions/github.js.map +1 -1
  67. package/dist/src/config/extensions/github.test.js +25 -17
  68. package/dist/src/config/extensions/github.test.js.map +1 -1
  69. package/dist/src/config/extensions/update.d.ts +5 -4
  70. package/dist/src/config/extensions/update.js +10 -6
  71. package/dist/src/config/extensions/update.js.map +1 -1
  72. package/dist/src/config/extensions/update.test.js +57 -57
  73. package/dist/src/config/extensions/update.test.js.map +1 -1
  74. package/dist/src/config/extensions/variableSchema.d.ts +2 -0
  75. package/dist/src/config/extensions/variableSchema.js.map +1 -1
  76. package/dist/src/config/keyBindings.d.ts +2 -1
  77. package/dist/src/config/keyBindings.js +4 -2
  78. package/dist/src/config/keyBindings.js.map +1 -1
  79. package/dist/src/config/policy.d.ts +3 -2
  80. package/dist/src/config/policy.js +32 -23
  81. package/dist/src/config/policy.js.map +1 -1
  82. package/dist/src/config/policy.test.js +60 -36
  83. package/dist/src/config/policy.test.js.map +1 -1
  84. package/dist/src/config/sandboxConfig.d.ts +0 -1
  85. package/dist/src/config/sandboxConfig.js +1 -3
  86. package/dist/src/config/sandboxConfig.js.map +1 -1
  87. package/dist/src/config/settings.js +9 -5
  88. package/dist/src/config/settings.js.map +1 -1
  89. package/dist/src/config/settings.test.d.ts +6 -0
  90. package/dist/src/config/settings.test.js +1941 -0
  91. package/dist/src/config/settings.test.js.map +1 -0
  92. package/dist/src/gemini.js +30 -24
  93. package/dist/src/gemini.js.map +1 -1
  94. package/dist/src/gemini.test.js +42 -11
  95. package/dist/src/gemini.test.js.map +1 -1
  96. package/dist/src/generated/git-commit.d.ts +2 -2
  97. package/dist/src/generated/git-commit.js +2 -2
  98. package/dist/src/nonInteractiveCli.js +92 -4
  99. package/dist/src/nonInteractiveCli.js.map +1 -1
  100. package/dist/src/nonInteractiveCli.test.d.ts +6 -0
  101. package/dist/src/nonInteractiveCli.test.js +741 -0
  102. package/dist/src/nonInteractiveCli.test.js.map +1 -0
  103. package/dist/src/nonInteractiveCliCommands.js +2 -2
  104. package/dist/src/nonInteractiveCliCommands.js.map +1 -1
  105. package/dist/src/services/CommandService.js +2 -1
  106. package/dist/src/services/CommandService.js.map +1 -1
  107. package/dist/src/services/FileCommandLoader.test.d.ts +6 -0
  108. package/dist/src/services/FileCommandLoader.test.js +971 -0
  109. package/dist/src/services/FileCommandLoader.test.js.map +1 -0
  110. package/dist/src/services/prompt-processors/argumentProcessor.test.d.ts +6 -0
  111. package/dist/src/services/prompt-processors/argumentProcessor.test.js +40 -0
  112. package/dist/src/services/prompt-processors/argumentProcessor.test.js.map +1 -0
  113. package/dist/src/services/prompt-processors/atFileProcessor.js +3 -2
  114. package/dist/src/services/prompt-processors/atFileProcessor.js.map +1 -1
  115. package/dist/src/services/prompt-processors/shellProcessor.test.d.ts +6 -0
  116. package/dist/src/services/prompt-processors/shellProcessor.test.js +482 -0
  117. package/dist/src/services/prompt-processors/shellProcessor.test.js.map +1 -0
  118. package/dist/src/test-utils/render.d.ts +2 -1
  119. package/dist/src/test-utils/render.js +5 -2
  120. package/dist/src/test-utils/render.js.map +1 -1
  121. package/dist/src/ui/App.test.d.ts +6 -0
  122. package/dist/src/ui/App.test.js +110 -0
  123. package/dist/src/ui/App.test.js.map +1 -0
  124. package/dist/src/ui/AppContainer.js +47 -32
  125. package/dist/src/ui/AppContainer.js.map +1 -1
  126. package/dist/src/ui/AppContainer.test.js +35 -9
  127. package/dist/src/ui/AppContainer.test.js.map +1 -1
  128. package/dist/src/ui/auth/AuthDialog.d.ts +1 -1
  129. package/dist/src/ui/auth/AuthDialog.js +5 -3
  130. package/dist/src/ui/auth/AuthDialog.js.map +1 -1
  131. package/dist/src/ui/auth/useAuth.d.ts +1 -1
  132. package/dist/src/ui/auth/useAuth.js +5 -3
  133. package/dist/src/ui/auth/useAuth.js.map +1 -1
  134. package/dist/src/ui/commands/aboutCommand.js +1 -1
  135. package/dist/src/ui/commands/aboutCommand.test.d.ts +6 -0
  136. package/dist/src/ui/commands/aboutCommand.test.js +130 -0
  137. package/dist/src/ui/commands/aboutCommand.test.js.map +1 -0
  138. package/dist/src/ui/commands/authCommand.js +1 -1
  139. package/dist/src/ui/commands/authCommand.test.d.ts +6 -0
  140. package/dist/src/ui/commands/authCommand.test.js +30 -0
  141. package/dist/src/ui/commands/authCommand.test.js.map +1 -0
  142. package/dist/src/ui/commands/bugCommand.js +1 -1
  143. package/dist/src/ui/commands/bugCommand.test.d.ts +6 -0
  144. package/dist/src/ui/commands/bugCommand.test.js +105 -0
  145. package/dist/src/ui/commands/bugCommand.test.js.map +1 -0
  146. package/dist/src/ui/commands/chatCommand.js +1 -1
  147. package/dist/src/ui/commands/chatCommand.js.map +1 -1
  148. package/dist/src/ui/commands/chatCommand.test.d.ts +6 -0
  149. package/dist/src/ui/commands/chatCommand.test.js +555 -0
  150. package/dist/src/ui/commands/chatCommand.test.js.map +1 -0
  151. package/dist/src/ui/commands/clearCommand.js +1 -1
  152. package/dist/src/ui/commands/clearCommand.test.d.ts +6 -0
  153. package/dist/src/ui/commands/clearCommand.test.js +76 -0
  154. package/dist/src/ui/commands/clearCommand.test.js.map +1 -0
  155. package/dist/src/ui/commands/compressCommand.js +1 -1
  156. package/dist/src/ui/commands/compressCommand.js.map +1 -1
  157. package/dist/src/ui/commands/compressCommand.test.d.ts +6 -0
  158. package/dist/src/ui/commands/compressCommand.test.js +98 -0
  159. package/dist/src/ui/commands/compressCommand.test.js.map +1 -0
  160. package/dist/src/ui/commands/copyCommand.js +2 -1
  161. package/dist/src/ui/commands/copyCommand.js.map +1 -1
  162. package/dist/src/ui/commands/copyCommand.test.d.ts +6 -0
  163. package/dist/src/ui/commands/copyCommand.test.js +242 -0
  164. package/dist/src/ui/commands/copyCommand.test.js.map +1 -0
  165. package/dist/src/ui/commands/corgiCommand.js +1 -1
  166. package/dist/src/ui/commands/corgiCommand.js.map +1 -1
  167. package/dist/src/ui/commands/corgiCommand.test.d.ts +6 -0
  168. package/dist/src/ui/commands/corgiCommand.test.js +28 -0
  169. package/dist/src/ui/commands/corgiCommand.test.js.map +1 -0
  170. package/dist/src/ui/commands/directoryCommand.js +1 -1
  171. package/dist/src/ui/commands/directoryCommand.js.map +1 -1
  172. package/dist/src/ui/commands/directoryCommand.test.d.ts +6 -0
  173. package/dist/src/ui/commands/directoryCommand.test.js +144 -0
  174. package/dist/src/ui/commands/directoryCommand.test.js.map +1 -0
  175. package/dist/src/ui/commands/docsCommand.js +1 -1
  176. package/dist/src/ui/commands/docsCommand.test.d.ts +6 -0
  177. package/dist/src/ui/commands/docsCommand.test.js +72 -0
  178. package/dist/src/ui/commands/docsCommand.test.js.map +1 -0
  179. package/dist/src/ui/commands/editorCommand.js +1 -1
  180. package/dist/src/ui/commands/editorCommand.test.d.ts +6 -0
  181. package/dist/src/ui/commands/editorCommand.test.js +27 -0
  182. package/dist/src/ui/commands/editorCommand.test.js.map +1 -0
  183. package/dist/src/ui/commands/extensionsCommand.test.d.ts +6 -0
  184. package/dist/src/ui/commands/extensionsCommand.test.js +244 -0
  185. package/dist/src/ui/commands/extensionsCommand.test.js.map +1 -0
  186. package/dist/src/ui/commands/helpCommand.js +1 -1
  187. package/dist/src/ui/commands/helpCommand.test.d.ts +6 -0
  188. package/dist/src/ui/commands/helpCommand.test.js +42 -0
  189. package/dist/src/ui/commands/helpCommand.test.js.map +1 -0
  190. package/dist/src/ui/commands/ideCommand.js +6 -6
  191. package/dist/src/ui/commands/ideCommand.test.d.ts +6 -0
  192. package/dist/src/ui/commands/ideCommand.test.js +205 -0
  193. package/dist/src/ui/commands/ideCommand.test.js.map +1 -0
  194. package/dist/src/ui/commands/initCommand.js +1 -1
  195. package/dist/src/ui/commands/initCommand.js.map +1 -1
  196. package/dist/src/ui/commands/initCommand.test.d.ts +6 -0
  197. package/dist/src/ui/commands/initCommand.test.js +80 -0
  198. package/dist/src/ui/commands/initCommand.test.js.map +1 -0
  199. package/dist/src/ui/commands/mcpCommand.js +98 -88
  200. package/dist/src/ui/commands/mcpCommand.js.map +1 -1
  201. package/dist/src/ui/commands/mcpCommand.test.d.ts +6 -0
  202. package/dist/src/ui/commands/mcpCommand.test.js +148 -0
  203. package/dist/src/ui/commands/mcpCommand.test.js.map +1 -0
  204. package/dist/src/ui/commands/memoryCommand.js +6 -6
  205. package/dist/src/ui/commands/memoryCommand.js.map +1 -1
  206. package/dist/src/ui/commands/memoryCommand.test.d.ts +6 -0
  207. package/dist/src/ui/commands/memoryCommand.test.js +266 -0
  208. package/dist/src/ui/commands/memoryCommand.test.js.map +1 -0
  209. package/dist/src/ui/commands/privacyCommand.js +1 -1
  210. package/dist/src/ui/commands/privacyCommand.test.d.ts +6 -0
  211. package/dist/src/ui/commands/privacyCommand.test.js +32 -0
  212. package/dist/src/ui/commands/privacyCommand.test.js.map +1 -0
  213. package/dist/src/ui/commands/quitCommand.js +1 -1
  214. package/dist/src/ui/commands/quitCommand.test.d.ts +6 -0
  215. package/dist/src/ui/commands/quitCommand.test.js +50 -0
  216. package/dist/src/ui/commands/quitCommand.test.js.map +1 -0
  217. package/dist/src/ui/commands/restoreCommand.test.d.ts +6 -0
  218. package/dist/src/ui/commands/restoreCommand.test.js +190 -0
  219. package/dist/src/ui/commands/restoreCommand.test.js.map +1 -0
  220. package/dist/src/ui/commands/settingsCommand.test.d.ts +6 -0
  221. package/dist/src/ui/commands/settingsCommand.test.js +30 -0
  222. package/dist/src/ui/commands/settingsCommand.test.js.map +1 -0
  223. package/dist/src/ui/commands/setupGithubCommand.js +4 -3
  224. package/dist/src/ui/commands/setupGithubCommand.js.map +1 -1
  225. package/dist/src/ui/commands/setupGithubCommand.test.js +1 -2
  226. package/dist/src/ui/commands/setupGithubCommand.test.js.map +1 -1
  227. package/dist/src/ui/commands/statsCommand.js +3 -3
  228. package/dist/src/ui/commands/statsCommand.js.map +1 -1
  229. package/dist/src/ui/commands/statsCommand.test.d.ts +6 -0
  230. package/dist/src/ui/commands/statsCommand.test.js +53 -0
  231. package/dist/src/ui/commands/statsCommand.test.js.map +1 -0
  232. package/dist/src/ui/commands/terminalSetupCommand.test.d.ts +6 -0
  233. package/dist/src/ui/commands/terminalSetupCommand.test.js +66 -0
  234. package/dist/src/ui/commands/terminalSetupCommand.test.js.map +1 -0
  235. package/dist/src/ui/commands/themeCommand.js +1 -1
  236. package/dist/src/ui/commands/themeCommand.test.d.ts +6 -0
  237. package/dist/src/ui/commands/themeCommand.test.js +32 -0
  238. package/dist/src/ui/commands/themeCommand.test.js.map +1 -0
  239. package/dist/src/ui/commands/toolsCommand.js +1 -1
  240. package/dist/src/ui/commands/toolsCommand.test.d.ts +6 -0
  241. package/dist/src/ui/commands/toolsCommand.test.js +100 -0
  242. package/dist/src/ui/commands/toolsCommand.test.js.map +1 -0
  243. package/dist/src/ui/commands/types.d.ts +1 -0
  244. package/dist/src/ui/commands/vimCommand.js +1 -1
  245. package/dist/src/ui/components/AsciiArt.d.ts +3 -3
  246. package/dist/src/ui/components/AsciiArt.js +3 -3
  247. package/dist/src/ui/components/Composer.js +6 -4
  248. package/dist/src/ui/components/Composer.js.map +1 -1
  249. package/dist/src/ui/components/Composer.test.js +16 -1
  250. package/dist/src/ui/components/Composer.test.js.map +1 -1
  251. package/dist/src/ui/components/ContextSummaryDisplay.d.ts +0 -1
  252. package/dist/src/ui/components/ContextSummaryDisplay.js +2 -12
  253. package/dist/src/ui/components/ContextSummaryDisplay.js.map +1 -1
  254. package/dist/src/ui/components/ContextSummaryDisplay.test.d.ts +6 -0
  255. package/dist/src/ui/components/ContextSummaryDisplay.test.js +66 -0
  256. package/dist/src/ui/components/ContextSummaryDisplay.test.js.map +1 -0
  257. package/dist/src/ui/components/DialogManager.js +1 -5
  258. package/dist/src/ui/components/DialogManager.js.map +1 -1
  259. package/dist/src/ui/components/EditorSettingsDialog.js +1 -1
  260. package/dist/src/ui/components/EditorSettingsDialog.js.map +1 -1
  261. package/dist/src/ui/components/FolderTrustDialog.test.js +7 -3
  262. package/dist/src/ui/components/FolderTrustDialog.test.js.map +1 -1
  263. package/dist/src/ui/components/Footer.js +1 -1
  264. package/dist/src/ui/components/Footer.js.map +1 -1
  265. package/dist/src/ui/components/Footer.test.d.ts +6 -0
  266. package/dist/src/ui/components/Footer.test.js +231 -0
  267. package/dist/src/ui/components/Footer.test.js.map +1 -0
  268. package/dist/src/ui/components/InputPrompt.d.ts +4 -0
  269. package/dist/src/ui/components/InputPrompt.js +53 -4
  270. package/dist/src/ui/components/InputPrompt.js.map +1 -1
  271. package/dist/src/ui/components/InputPrompt.test.d.ts +6 -0
  272. package/dist/src/ui/components/InputPrompt.test.js +1737 -0
  273. package/dist/src/ui/components/InputPrompt.test.js.map +1 -0
  274. package/dist/src/ui/components/ModelStatsDisplay.test.d.ts +6 -0
  275. package/dist/src/ui/components/ModelStatsDisplay.test.js +285 -0
  276. package/dist/src/ui/components/ModelStatsDisplay.test.js.map +1 -0
  277. package/dist/src/ui/components/PermissionsModifyTrustDialog.js +22 -18
  278. package/dist/src/ui/components/PermissionsModifyTrustDialog.js.map +1 -1
  279. package/dist/src/ui/components/PermissionsModifyTrustDialog.test.js +10 -2
  280. package/dist/src/ui/components/PermissionsModifyTrustDialog.test.js.map +1 -1
  281. package/dist/src/ui/components/QueuedMessageDisplay.js +3 -3
  282. package/dist/src/ui/components/QueuedMessageDisplay.js.map +1 -1
  283. package/dist/src/ui/components/QueuedMessageDisplay.test.js +4 -0
  284. package/dist/src/ui/components/QueuedMessageDisplay.test.js.map +1 -1
  285. package/dist/src/ui/components/RawMarkdownIndicator.d.ts +7 -0
  286. package/dist/src/ui/components/RawMarkdownIndicator.js +8 -0
  287. package/dist/src/ui/components/RawMarkdownIndicator.js.map +1 -0
  288. package/dist/src/ui/components/SessionSummaryDisplay.test.d.ts +6 -0
  289. package/dist/src/ui/components/SessionSummaryDisplay.test.js +74 -0
  290. package/dist/src/ui/components/SessionSummaryDisplay.test.js.map +1 -0
  291. package/dist/src/ui/components/SettingsDialog.js +11 -10
  292. package/dist/src/ui/components/SettingsDialog.js.map +1 -1
  293. package/dist/src/ui/components/SettingsDialog.test.js +189 -76
  294. package/dist/src/ui/components/SettingsDialog.test.js.map +1 -1
  295. package/dist/src/ui/components/StatsDisplay.test.d.ts +6 -0
  296. package/dist/src/ui/components/StatsDisplay.test.js +351 -0
  297. package/dist/src/ui/components/StatsDisplay.test.js.map +1 -0
  298. package/dist/src/ui/components/ThemeDialog.d.ts +4 -2
  299. package/dist/src/ui/components/ThemeDialog.js +3 -3
  300. package/dist/src/ui/components/ThemeDialog.js.map +1 -1
  301. package/dist/src/ui/components/ThemeDialog.test.js +13 -0
  302. package/dist/src/ui/components/ThemeDialog.test.js.map +1 -1
  303. package/dist/src/ui/components/ToolStatsDisplay.test.d.ts +6 -0
  304. package/dist/src/ui/components/ToolStatsDisplay.test.js +227 -0
  305. package/dist/src/ui/components/ToolStatsDisplay.test.js.map +1 -0
  306. package/dist/src/ui/components/messages/GeminiMessage.js +3 -1
  307. package/dist/src/ui/components/messages/GeminiMessage.js.map +1 -1
  308. package/dist/src/ui/components/messages/GeminiMessage.test.d.ts +6 -0
  309. package/dist/src/ui/components/messages/GeminiMessage.test.js +35 -0
  310. package/dist/src/ui/components/messages/GeminiMessage.test.js.map +1 -0
  311. package/dist/src/ui/components/messages/GeminiMessageContent.js +3 -1
  312. package/dist/src/ui/components/messages/GeminiMessageContent.js.map +1 -1
  313. package/dist/src/ui/components/messages/Todo.d.ts +7 -0
  314. package/dist/src/ui/components/messages/Todo.js +69 -0
  315. package/dist/src/ui/components/messages/Todo.js.map +1 -0
  316. package/dist/src/ui/components/messages/Todo.test.d.ts +6 -0
  317. package/dist/src/ui/components/messages/Todo.test.js +102 -0
  318. package/dist/src/ui/components/messages/Todo.test.js.map +1 -0
  319. package/dist/src/ui/components/messages/ToolGroupMessage.js +1 -1
  320. package/dist/src/ui/components/messages/ToolGroupMessage.js.map +1 -1
  321. package/dist/src/ui/components/messages/ToolMessage.js +8 -3
  322. package/dist/src/ui/components/messages/ToolMessage.js.map +1 -1
  323. package/dist/src/ui/components/messages/ToolMessage.test.js +2 -2
  324. package/dist/src/ui/components/messages/ToolMessage.test.js.map +1 -1
  325. package/dist/src/ui/components/messages/ToolMessageRawMarkdown.test.d.ts +6 -0
  326. package/dist/src/ui/components/messages/ToolMessageRawMarkdown.test.js +30 -0
  327. package/dist/src/ui/components/messages/ToolMessageRawMarkdown.test.js.map +1 -0
  328. package/dist/src/ui/components/messages/UserShellMessage.js +1 -1
  329. package/dist/src/ui/components/messages/UserShellMessage.js.map +1 -1
  330. package/dist/src/ui/components/shared/BaseSelectionList.test.js +33 -24
  331. package/dist/src/ui/components/shared/BaseSelectionList.test.js.map +1 -1
  332. package/dist/src/ui/components/shared/text-buffer.js +1 -1
  333. package/dist/src/ui/components/shared/text-buffer.js.map +1 -1
  334. package/dist/src/ui/components/shared/text-buffer.test.d.ts +6 -0
  335. package/dist/src/ui/components/shared/text-buffer.test.js +1578 -0
  336. package/dist/src/ui/components/shared/text-buffer.test.js.map +1 -0
  337. package/dist/src/ui/components/shared/vim-buffer-actions.test.d.ts +6 -0
  338. package/dist/src/ui/components/shared/vim-buffer-actions.test.js +951 -0
  339. package/dist/src/ui/components/shared/vim-buffer-actions.test.js.map +1 -0
  340. package/dist/src/ui/components/views/ExtensionsList.js +3 -4
  341. package/dist/src/ui/components/views/ExtensionsList.js.map +1 -1
  342. package/dist/src/ui/components/views/ExtensionsList.test.js +2 -9
  343. package/dist/src/ui/components/views/ExtensionsList.test.js.map +1 -1
  344. package/dist/src/ui/components/views/McpStatus.d.ts +0 -1
  345. package/dist/src/ui/components/views/McpStatus.js +4 -4
  346. package/dist/src/ui/components/views/McpStatus.js.map +1 -1
  347. package/dist/src/ui/components/views/McpStatus.test.js +0 -5
  348. package/dist/src/ui/components/views/McpStatus.test.js.map +1 -1
  349. package/dist/src/ui/components/views/ToolsList.test.js +4 -4
  350. package/dist/src/ui/components/views/ToolsList.test.js.map +1 -1
  351. package/dist/src/ui/contexts/KeypressContext.d.ts +1 -0
  352. package/dist/src/ui/contexts/KeypressContext.js +176 -50
  353. package/dist/src/ui/contexts/KeypressContext.js.map +1 -1
  354. package/dist/src/ui/contexts/KeypressContext.test.js +413 -14
  355. package/dist/src/ui/contexts/KeypressContext.test.js.map +1 -1
  356. package/dist/src/ui/contexts/SessionContext.test.d.ts +6 -0
  357. package/dist/src/ui/contexts/SessionContext.test.js +177 -0
  358. package/dist/src/ui/contexts/SessionContext.test.js.map +1 -0
  359. package/dist/src/ui/contexts/UIActionsContext.d.ts +5 -4
  360. package/dist/src/ui/contexts/UIActionsContext.js.map +1 -1
  361. package/dist/src/ui/contexts/UIStateContext.d.ts +3 -3
  362. package/dist/src/ui/contexts/UIStateContext.js.map +1 -1
  363. package/dist/src/ui/hooks/atCommandProcessor.js +2 -2
  364. package/dist/src/ui/hooks/atCommandProcessor.js.map +1 -1
  365. package/dist/src/ui/hooks/shellCommandProcessor.js +0 -1
  366. package/dist/src/ui/hooks/shellCommandProcessor.js.map +1 -1
  367. package/dist/src/ui/hooks/slashCommandProcessor.js +2 -0
  368. package/dist/src/ui/hooks/slashCommandProcessor.js.map +1 -1
  369. package/dist/src/ui/hooks/slashCommandProcessor.test.d.ts +6 -0
  370. package/dist/src/ui/hooks/slashCommandProcessor.test.js +779 -0
  371. package/dist/src/ui/hooks/slashCommandProcessor.test.js.map +1 -0
  372. package/dist/src/ui/hooks/useAtCompletion.js +2 -2
  373. package/dist/src/ui/hooks/useAtCompletion.js.map +1 -1
  374. package/dist/src/ui/hooks/useAtCompletion.test.d.ts +6 -0
  375. package/dist/src/ui/hooks/useAtCompletion.test.js +385 -0
  376. package/dist/src/ui/hooks/useAtCompletion.test.js.map +1 -0
  377. package/dist/src/ui/hooks/useAutoAcceptIndicator.test.js +0 -1
  378. package/dist/src/ui/hooks/useAutoAcceptIndicator.test.js.map +1 -1
  379. package/dist/src/ui/hooks/useCommandCompletion.d.ts +1 -1
  380. package/dist/src/ui/hooks/useCommandCompletion.js +5 -3
  381. package/dist/src/ui/hooks/useCommandCompletion.js.map +1 -1
  382. package/dist/src/ui/hooks/useCommandCompletion.test.d.ts +6 -0
  383. package/dist/src/ui/hooks/useCommandCompletion.test.js +375 -0
  384. package/dist/src/ui/hooks/useCommandCompletion.test.js.map +1 -0
  385. package/dist/src/ui/hooks/useConsoleMessages.test.d.ts +6 -0
  386. package/dist/src/ui/hooks/useConsoleMessages.test.js +110 -0
  387. package/dist/src/ui/hooks/useConsoleMessages.test.js.map +1 -0
  388. package/dist/src/ui/hooks/useExtensionUpdates.d.ts +2 -1
  389. package/dist/src/ui/hooks/useExtensionUpdates.js +5 -3
  390. package/dist/src/ui/hooks/useExtensionUpdates.js.map +1 -1
  391. package/dist/src/ui/hooks/useExtensionUpdates.test.js +25 -13
  392. package/dist/src/ui/hooks/useExtensionUpdates.test.js.map +1 -1
  393. package/dist/src/ui/hooks/useFocus.test.d.ts +6 -0
  394. package/dist/src/ui/hooks/useFocus.test.js +115 -0
  395. package/dist/src/ui/hooks/useFocus.test.js.map +1 -0
  396. package/dist/src/ui/hooks/useFolderTrust.test.d.ts +6 -0
  397. package/dist/src/ui/hooks/useFolderTrust.test.js +164 -0
  398. package/dist/src/ui/hooks/useFolderTrust.test.js.map +1 -0
  399. package/dist/src/ui/hooks/useGeminiStream.js +63 -55
  400. package/dist/src/ui/hooks/useGeminiStream.js.map +1 -1
  401. package/dist/src/ui/hooks/useGeminiStream.test.d.ts +6 -0
  402. package/dist/src/ui/hooks/useGeminiStream.test.js +1971 -0
  403. package/dist/src/ui/hooks/useGeminiStream.test.js.map +1 -0
  404. package/dist/src/ui/hooks/useInputHistoryStore.js +2 -1
  405. package/dist/src/ui/hooks/useInputHistoryStore.js.map +1 -1
  406. package/dist/src/ui/hooks/useKeypress.test.d.ts +6 -0
  407. package/dist/src/ui/hooks/useKeypress.test.js +234 -0
  408. package/dist/src/ui/hooks/useKeypress.test.js.map +1 -0
  409. package/dist/src/ui/hooks/useLoadingIndicator.test.js +5 -0
  410. package/dist/src/ui/hooks/useLoadingIndicator.test.js.map +1 -1
  411. package/dist/src/ui/hooks/useMessageQueue.d.ts +1 -0
  412. package/dist/src/ui/hooks/useMessageQueue.js +14 -0
  413. package/dist/src/ui/hooks/useMessageQueue.js.map +1 -1
  414. package/dist/src/ui/hooks/useMessageQueue.test.js +121 -0
  415. package/dist/src/ui/hooks/useMessageQueue.test.js.map +1 -1
  416. package/dist/src/ui/hooks/usePhraseCycler.d.ts +1 -0
  417. package/dist/src/ui/hooks/usePhraseCycler.js +156 -5
  418. package/dist/src/ui/hooks/usePhraseCycler.js.map +1 -1
  419. package/dist/src/ui/hooks/usePhraseCycler.test.d.ts +6 -0
  420. package/dist/src/ui/hooks/usePhraseCycler.test.js +155 -0
  421. package/dist/src/ui/hooks/usePhraseCycler.test.js.map +1 -0
  422. package/dist/src/ui/hooks/useReactToolScheduler.js +2 -2
  423. package/dist/src/ui/hooks/useReactToolScheduler.js.map +1 -1
  424. package/dist/src/ui/hooks/useShowMemoryCommand.d.ts +1 -1
  425. package/dist/src/ui/hooks/useShowMemoryCommand.js +4 -3
  426. package/dist/src/ui/hooks/useShowMemoryCommand.js.map +1 -1
  427. package/dist/src/ui/hooks/useSlashCompletion.js +2 -1
  428. package/dist/src/ui/hooks/useSlashCompletion.js.map +1 -1
  429. package/dist/src/ui/hooks/useThemeCommand.d.ts +2 -1
  430. package/dist/src/ui/hooks/useThemeCommand.js +6 -0
  431. package/dist/src/ui/hooks/useThemeCommand.js.map +1 -1
  432. package/dist/src/ui/hooks/useToolScheduler.test.js +3 -0
  433. package/dist/src/ui/hooks/useToolScheduler.test.js.map +1 -1
  434. package/dist/src/ui/hooks/vim.js +2 -1
  435. package/dist/src/ui/hooks/vim.js.map +1 -1
  436. package/dist/src/ui/hooks/vim.test.d.ts +6 -0
  437. package/dist/src/ui/hooks/vim.test.js +1389 -0
  438. package/dist/src/ui/hooks/vim.test.js.map +1 -0
  439. package/dist/src/ui/keyMatchers.test.js +9 -3
  440. package/dist/src/ui/keyMatchers.test.js.map +1 -1
  441. package/dist/src/ui/themes/color-utils.js +2 -1
  442. package/dist/src/ui/themes/color-utils.js.map +1 -1
  443. package/dist/src/ui/themes/theme-manager.js +8 -7
  444. package/dist/src/ui/themes/theme-manager.js.map +1 -1
  445. package/dist/src/ui/themes/theme.test.d.ts +6 -0
  446. package/dist/src/ui/themes/theme.test.js +85 -0
  447. package/dist/src/ui/themes/theme.test.js.map +1 -0
  448. package/dist/src/ui/types.d.ts +0 -1
  449. package/dist/src/ui/types.js.map +1 -1
  450. package/dist/src/ui/utils/CodeColorizer.d.ts +1 -1
  451. package/dist/src/ui/utils/CodeColorizer.js +4 -2
  452. package/dist/src/ui/utils/CodeColorizer.js.map +1 -1
  453. package/dist/src/ui/utils/MarkdownDisplay.d.ts +1 -0
  454. package/dist/src/ui/utils/MarkdownDisplay.js +8 -1
  455. package/dist/src/ui/utils/MarkdownDisplay.js.map +1 -1
  456. package/dist/src/ui/utils/commandUtils.js +20 -3
  457. package/dist/src/ui/utils/commandUtils.js.map +1 -1
  458. package/dist/src/ui/utils/commandUtils.test.js +61 -6
  459. package/dist/src/ui/utils/commandUtils.test.js.map +1 -1
  460. package/dist/src/ui/utils/computeStats.js +5 -2
  461. package/dist/src/ui/utils/computeStats.js.map +1 -1
  462. package/dist/src/ui/utils/computeStats.test.d.ts +6 -0
  463. package/dist/src/ui/utils/computeStats.test.js +262 -0
  464. package/dist/src/ui/utils/computeStats.test.js.map +1 -0
  465. package/dist/src/ui/utils/terminalSetup.js +3 -2
  466. package/dist/src/ui/utils/terminalSetup.js.map +1 -1
  467. package/dist/src/ui/utils/updateCheck.d.ts +2 -1
  468. package/dist/src/ui/utils/updateCheck.js +6 -2
  469. package/dist/src/ui/utils/updateCheck.js.map +1 -1
  470. package/dist/src/ui/utils/updateCheck.test.js +25 -10
  471. package/dist/src/ui/utils/updateCheck.test.js.map +1 -1
  472. package/dist/src/utils/cleanup.test.d.ts +6 -0
  473. package/dist/src/utils/cleanup.test.js +49 -0
  474. package/dist/src/utils/cleanup.test.js.map +1 -0
  475. package/dist/src/utils/errors.d.ts +1 -0
  476. package/dist/src/utils/errors.js +66 -5
  477. package/dist/src/utils/errors.js.map +1 -1
  478. package/dist/src/utils/gitUtils.js +3 -2
  479. package/dist/src/utils/gitUtils.js.map +1 -1
  480. package/dist/src/utils/handleAutoUpdate.test.d.ts +6 -0
  481. package/dist/src/utils/handleAutoUpdate.test.js +225 -0
  482. package/dist/src/utils/handleAutoUpdate.test.js.map +1 -0
  483. package/dist/src/utils/installationInfo.js +2 -2
  484. package/dist/src/utils/installationInfo.js.map +1 -1
  485. package/dist/src/utils/installationInfo.test.js +8 -4
  486. package/dist/src/utils/installationInfo.test.js.map +1 -1
  487. package/dist/src/utils/readStdin.js +2 -1
  488. package/dist/src/utils/readStdin.js.map +1 -1
  489. package/dist/src/utils/sandbox-macos-permissive-open.sb +2 -0
  490. package/dist/src/utils/sandbox.js +13 -13
  491. package/dist/src/utils/sandbox.js.map +1 -1
  492. package/dist/src/utils/sessionCleanup.js +4 -4
  493. package/dist/src/utils/sessionCleanup.js.map +1 -1
  494. package/dist/src/utils/startupWarnings.test.d.ts +6 -0
  495. package/dist/src/utils/startupWarnings.test.js +61 -0
  496. package/dist/src/utils/startupWarnings.test.js.map +1 -0
  497. package/dist/src/validateNonInterActiveAuth.js +2 -2
  498. package/dist/src/validateNonInterActiveAuth.js.map +1 -1
  499. package/dist/src/zed-integration/zedIntegration.js +6 -8
  500. package/dist/src/zed-integration/zedIntegration.js.map +1 -1
  501. package/dist/tsconfig.tsbuildinfo +1 -1
  502. package/package.json +6 -6
  503. package/dist/src/ui/components/WorkspaceMigrationDialog.d.ts +0 -11
  504. package/dist/src/ui/components/WorkspaceMigrationDialog.js +0 -44
  505. package/dist/src/ui/components/WorkspaceMigrationDialog.js.map +0 -1
  506. package/dist/src/ui/hooks/useWorkspaceMigration.d.ts +0 -13
  507. package/dist/src/ui/hooks/useWorkspaceMigration.js +0 -59
  508. package/dist/src/ui/hooks/useWorkspaceMigration.js.map +0 -1
@@ -0,0 +1,741 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import { executeToolCall, ToolErrorType, shutdownTelemetry, GeminiEventType, OutputFormat, uiTelemetryService, FatalInputError, } from '@google/gemini-cli-core';
7
+ import { runNonInteractive } from './nonInteractiveCli.js';
8
+ import { vi } from 'vitest';
9
+ // Mock core modules
10
+ vi.mock('./ui/hooks/atCommandProcessor.js');
11
+ vi.mock('@google/gemini-cli-core', async (importOriginal) => {
12
+ const original = await importOriginal();
13
+ class MockChatRecordingService {
14
+ initialize = vi.fn();
15
+ recordMessage = vi.fn();
16
+ recordMessageTokens = vi.fn();
17
+ recordToolCalls = vi.fn();
18
+ }
19
+ return {
20
+ ...original,
21
+ executeToolCall: vi.fn(),
22
+ shutdownTelemetry: vi.fn(),
23
+ isTelemetrySdkInitialized: vi.fn().mockReturnValue(true),
24
+ ChatRecordingService: MockChatRecordingService,
25
+ uiTelemetryService: {
26
+ getMetrics: vi.fn(),
27
+ },
28
+ };
29
+ });
30
+ const mockGetCommands = vi.hoisted(() => vi.fn());
31
+ const mockCommandServiceCreate = vi.hoisted(() => vi.fn());
32
+ vi.mock('./services/CommandService.js', () => ({
33
+ CommandService: {
34
+ create: mockCommandServiceCreate,
35
+ },
36
+ }));
37
+ vi.mock('./services/FileCommandLoader.js');
38
+ vi.mock('./services/McpPromptLoader.js');
39
+ describe('runNonInteractive', () => {
40
+ let mockConfig;
41
+ let mockSettings;
42
+ let mockToolRegistry;
43
+ let mockCoreExecuteToolCall;
44
+ let mockShutdownTelemetry;
45
+ let consoleErrorSpy;
46
+ let processStdoutSpy;
47
+ let mockGeminiClient;
48
+ beforeEach(async () => {
49
+ mockCoreExecuteToolCall = vi.mocked(executeToolCall);
50
+ mockShutdownTelemetry = vi.mocked(shutdownTelemetry);
51
+ mockCommandServiceCreate.mockResolvedValue({
52
+ getCommands: mockGetCommands,
53
+ });
54
+ consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => { });
55
+ processStdoutSpy = vi
56
+ .spyOn(process.stdout, 'write')
57
+ .mockImplementation(() => true);
58
+ vi.spyOn(process, 'exit').mockImplementation((code) => {
59
+ throw new Error(`process.exit(${code}) called`);
60
+ });
61
+ mockToolRegistry = {
62
+ getTool: vi.fn(),
63
+ getFunctionDeclarations: vi.fn().mockReturnValue([]),
64
+ };
65
+ mockGeminiClient = {
66
+ sendMessageStream: vi.fn(),
67
+ getChatRecordingService: vi.fn(() => ({
68
+ initialize: vi.fn(),
69
+ recordMessage: vi.fn(),
70
+ recordMessageTokens: vi.fn(),
71
+ recordToolCalls: vi.fn(),
72
+ })),
73
+ };
74
+ mockConfig = {
75
+ initialize: vi.fn().mockResolvedValue(undefined),
76
+ getGeminiClient: vi.fn().mockReturnValue(mockGeminiClient),
77
+ getToolRegistry: vi.fn().mockReturnValue(mockToolRegistry),
78
+ getMaxSessionTurns: vi.fn().mockReturnValue(10),
79
+ getSessionId: vi.fn().mockReturnValue('test-session-id'),
80
+ getProjectRoot: vi.fn().mockReturnValue('/test/project'),
81
+ storage: {
82
+ getProjectTempDir: vi
83
+ .fn()
84
+ .mockReturnValue('/test/project/.cell-cli/tmp'),
85
+ },
86
+ getIdeMode: vi.fn().mockReturnValue(false),
87
+ getContentGeneratorConfig: vi.fn().mockReturnValue({}),
88
+ getDebugMode: vi.fn().mockReturnValue(false),
89
+ getOutputFormat: vi.fn().mockReturnValue('text'),
90
+ getFolderTrust: vi.fn().mockReturnValue(false),
91
+ isTrustedFolder: vi.fn().mockReturnValue(false),
92
+ };
93
+ mockSettings = {
94
+ system: { path: '', settings: {} },
95
+ systemDefaults: { path: '', settings: {} },
96
+ user: { path: '', settings: {} },
97
+ workspace: { path: '', settings: {} },
98
+ errors: [],
99
+ setValue: vi.fn(),
100
+ merged: {
101
+ security: {
102
+ auth: {
103
+ enforcedType: undefined,
104
+ },
105
+ },
106
+ },
107
+ isTrusted: true,
108
+ migratedInMemorScopes: new Set(),
109
+ forScope: vi.fn(),
110
+ computeMergedSettings: vi.fn(),
111
+ };
112
+ const { handleAtCommand } = await import('./ui/hooks/atCommandProcessor.js');
113
+ vi.mocked(handleAtCommand).mockImplementation(async ({ query }) => ({
114
+ processedQuery: [{ text: query }],
115
+ shouldProceed: true,
116
+ }));
117
+ });
118
+ afterEach(() => {
119
+ vi.restoreAllMocks();
120
+ });
121
+ async function* createStreamFromEvents(events) {
122
+ for (const event of events) {
123
+ yield event;
124
+ }
125
+ }
126
+ it('should process input and write text output', async () => {
127
+ const events = [
128
+ { type: GeminiEventType.Content, value: 'Hello' },
129
+ { type: GeminiEventType.Content, value: ' World' },
130
+ {
131
+ type: GeminiEventType.Finished,
132
+ value: { reason: undefined, usageMetadata: { totalTokenCount: 10 } },
133
+ },
134
+ ];
135
+ mockGeminiClient.sendMessageStream.mockReturnValue(createStreamFromEvents(events));
136
+ await runNonInteractive(mockConfig, mockSettings, 'Test input', 'prompt-id-1');
137
+ expect(mockGeminiClient.sendMessageStream).toHaveBeenCalledWith([{ text: 'Test input' }], expect.any(AbortSignal), 'prompt-id-1');
138
+ expect(processStdoutSpy).toHaveBeenCalledWith('Hello');
139
+ expect(processStdoutSpy).toHaveBeenCalledWith(' World');
140
+ expect(processStdoutSpy).toHaveBeenCalledWith('\n');
141
+ expect(mockShutdownTelemetry).toHaveBeenCalled();
142
+ });
143
+ it('should handle a single tool call and respond', async () => {
144
+ const toolCallEvent = {
145
+ type: GeminiEventType.ToolCallRequest,
146
+ value: {
147
+ callId: 'tool-1',
148
+ name: 'testTool',
149
+ args: { arg1: 'value1' },
150
+ isClientInitiated: false,
151
+ prompt_id: 'prompt-id-2',
152
+ },
153
+ };
154
+ const toolResponse = [{ text: 'Tool response' }];
155
+ mockCoreExecuteToolCall.mockResolvedValue({
156
+ status: 'success',
157
+ request: {
158
+ callId: 'tool-1',
159
+ name: 'testTool',
160
+ args: { arg1: 'value1' },
161
+ isClientInitiated: false,
162
+ prompt_id: 'prompt-id-2',
163
+ },
164
+ tool: {},
165
+ invocation: {},
166
+ response: {
167
+ responseParts: toolResponse,
168
+ callId: 'tool-1',
169
+ error: undefined,
170
+ errorType: undefined,
171
+ contentLength: undefined,
172
+ },
173
+ });
174
+ const firstCallEvents = [toolCallEvent];
175
+ const secondCallEvents = [
176
+ { type: GeminiEventType.Content, value: 'Final answer' },
177
+ {
178
+ type: GeminiEventType.Finished,
179
+ value: { reason: undefined, usageMetadata: { totalTokenCount: 10 } },
180
+ },
181
+ ];
182
+ mockGeminiClient.sendMessageStream
183
+ .mockReturnValueOnce(createStreamFromEvents(firstCallEvents))
184
+ .mockReturnValueOnce(createStreamFromEvents(secondCallEvents));
185
+ await runNonInteractive(mockConfig, mockSettings, 'Use a tool', 'prompt-id-2');
186
+ expect(mockGeminiClient.sendMessageStream).toHaveBeenCalledTimes(2);
187
+ expect(mockCoreExecuteToolCall).toHaveBeenCalledWith(mockConfig, expect.objectContaining({ name: 'testTool' }), expect.any(AbortSignal));
188
+ expect(mockGeminiClient.sendMessageStream).toHaveBeenNthCalledWith(2, [{ text: 'Tool response' }], expect.any(AbortSignal), 'prompt-id-2');
189
+ expect(processStdoutSpy).toHaveBeenCalledWith('Final answer');
190
+ expect(processStdoutSpy).toHaveBeenCalledWith('\n');
191
+ });
192
+ it('should handle error during tool execution and should send error back to the model', async () => {
193
+ const toolCallEvent = {
194
+ type: GeminiEventType.ToolCallRequest,
195
+ value: {
196
+ callId: 'tool-1',
197
+ name: 'errorTool',
198
+ args: {},
199
+ isClientInitiated: false,
200
+ prompt_id: 'prompt-id-3',
201
+ },
202
+ };
203
+ mockCoreExecuteToolCall.mockResolvedValue({
204
+ status: 'error',
205
+ request: {
206
+ callId: 'tool-1',
207
+ name: 'errorTool',
208
+ args: {},
209
+ isClientInitiated: false,
210
+ prompt_id: 'prompt-id-3',
211
+ },
212
+ tool: {},
213
+ response: {
214
+ callId: 'tool-1',
215
+ error: new Error('Execution failed'),
216
+ errorType: ToolErrorType.EXECUTION_FAILED,
217
+ responseParts: [
218
+ {
219
+ functionResponse: {
220
+ name: 'errorTool',
221
+ response: {
222
+ output: 'Error: Execution failed',
223
+ },
224
+ },
225
+ },
226
+ ],
227
+ resultDisplay: 'Execution failed',
228
+ contentLength: undefined,
229
+ },
230
+ });
231
+ const finalResponse = [
232
+ {
233
+ type: GeminiEventType.Content,
234
+ value: 'Sorry, let me try again.',
235
+ },
236
+ {
237
+ type: GeminiEventType.Finished,
238
+ value: { reason: undefined, usageMetadata: { totalTokenCount: 10 } },
239
+ },
240
+ ];
241
+ mockGeminiClient.sendMessageStream
242
+ .mockReturnValueOnce(createStreamFromEvents([toolCallEvent]))
243
+ .mockReturnValueOnce(createStreamFromEvents(finalResponse));
244
+ await runNonInteractive(mockConfig, mockSettings, 'Trigger tool error', 'prompt-id-3');
245
+ expect(mockCoreExecuteToolCall).toHaveBeenCalled();
246
+ expect(consoleErrorSpy).toHaveBeenCalledWith('Error executing tool errorTool: Execution failed');
247
+ expect(mockGeminiClient.sendMessageStream).toHaveBeenCalledTimes(2);
248
+ expect(mockGeminiClient.sendMessageStream).toHaveBeenNthCalledWith(2, [
249
+ {
250
+ functionResponse: {
251
+ name: 'errorTool',
252
+ response: {
253
+ output: 'Error: Execution failed',
254
+ },
255
+ },
256
+ },
257
+ ], expect.any(AbortSignal), 'prompt-id-3');
258
+ expect(processStdoutSpy).toHaveBeenCalledWith('Sorry, let me try again.');
259
+ });
260
+ it('should exit with error if sendMessageStream throws initially', async () => {
261
+ const apiError = new Error('API connection failed');
262
+ mockGeminiClient.sendMessageStream.mockImplementation(() => {
263
+ throw apiError;
264
+ });
265
+ await expect(runNonInteractive(mockConfig, mockSettings, 'Initial fail', 'prompt-id-4')).rejects.toThrow(apiError);
266
+ });
267
+ it('should not exit if a tool is not found, and should send error back to model', async () => {
268
+ const toolCallEvent = {
269
+ type: GeminiEventType.ToolCallRequest,
270
+ value: {
271
+ callId: 'tool-1',
272
+ name: 'nonexistentTool',
273
+ args: {},
274
+ isClientInitiated: false,
275
+ prompt_id: 'prompt-id-5',
276
+ },
277
+ };
278
+ mockCoreExecuteToolCall.mockResolvedValue({
279
+ status: 'error',
280
+ request: {
281
+ callId: 'tool-1',
282
+ name: 'nonexistentTool',
283
+ args: {},
284
+ isClientInitiated: false,
285
+ prompt_id: 'prompt-id-5',
286
+ },
287
+ response: {
288
+ callId: 'tool-1',
289
+ error: new Error('Tool "nonexistentTool" not found in registry.'),
290
+ resultDisplay: 'Tool "nonexistentTool" not found in registry.',
291
+ responseParts: [],
292
+ errorType: undefined,
293
+ contentLength: undefined,
294
+ },
295
+ });
296
+ const finalResponse = [
297
+ {
298
+ type: GeminiEventType.Content,
299
+ value: "Sorry, I can't find that tool.",
300
+ },
301
+ {
302
+ type: GeminiEventType.Finished,
303
+ value: { reason: undefined, usageMetadata: { totalTokenCount: 10 } },
304
+ },
305
+ ];
306
+ mockGeminiClient.sendMessageStream
307
+ .mockReturnValueOnce(createStreamFromEvents([toolCallEvent]))
308
+ .mockReturnValueOnce(createStreamFromEvents(finalResponse));
309
+ await runNonInteractive(mockConfig, mockSettings, 'Trigger tool not found', 'prompt-id-5');
310
+ expect(mockCoreExecuteToolCall).toHaveBeenCalled();
311
+ expect(consoleErrorSpy).toHaveBeenCalledWith('Error executing tool nonexistentTool: Tool "nonexistentTool" not found in registry.');
312
+ expect(mockGeminiClient.sendMessageStream).toHaveBeenCalledTimes(2);
313
+ expect(processStdoutSpy).toHaveBeenCalledWith("Sorry, I can't find that tool.");
314
+ });
315
+ it('should exit when max session turns are exceeded', async () => {
316
+ vi.mocked(mockConfig.getMaxSessionTurns).mockReturnValue(0);
317
+ await expect(runNonInteractive(mockConfig, mockSettings, 'Trigger loop', 'prompt-id-6')).rejects.toThrow('process.exit(53) called');
318
+ });
319
+ it('should preprocess @include commands before sending to the model', async () => {
320
+ // 1. Mock the imported atCommandProcessor
321
+ const { handleAtCommand } = await import('./ui/hooks/atCommandProcessor.js');
322
+ const mockHandleAtCommand = vi.mocked(handleAtCommand);
323
+ // 2. Define the raw input and the expected processed output
324
+ const rawInput = 'Summarize @file.txt';
325
+ const processedParts = [
326
+ { text: 'Summarize @file.txt' },
327
+ { text: '\n--- Content from referenced files ---\n' },
328
+ { text: 'This is the content of the file.' },
329
+ { text: '\n--- End of content ---' },
330
+ ];
331
+ // 3. Setup the mock to return the processed parts
332
+ mockHandleAtCommand.mockResolvedValue({
333
+ processedQuery: processedParts,
334
+ shouldProceed: true,
335
+ });
336
+ // Mock a simple stream response from the Gemini client
337
+ const events = [
338
+ { type: GeminiEventType.Content, value: 'Summary complete.' },
339
+ {
340
+ type: GeminiEventType.Finished,
341
+ value: { reason: undefined, usageMetadata: { totalTokenCount: 10 } },
342
+ },
343
+ ];
344
+ mockGeminiClient.sendMessageStream.mockReturnValue(createStreamFromEvents(events));
345
+ // 4. Run the non-interactive mode with the raw input
346
+ await runNonInteractive(mockConfig, mockSettings, rawInput, 'prompt-id-7');
347
+ // 5. Assert that sendMessageStream was called with the PROCESSED parts, not the raw input
348
+ expect(mockGeminiClient.sendMessageStream).toHaveBeenCalledWith(processedParts, expect.any(AbortSignal), 'prompt-id-7');
349
+ // 6. Assert the final output is correct
350
+ expect(processStdoutSpy).toHaveBeenCalledWith('Summary complete.');
351
+ });
352
+ it('should process input and write JSON output with stats', async () => {
353
+ const events = [
354
+ { type: GeminiEventType.Content, value: 'Hello World' },
355
+ {
356
+ type: GeminiEventType.Finished,
357
+ value: { reason: undefined, usageMetadata: { totalTokenCount: 10 } },
358
+ },
359
+ ];
360
+ mockGeminiClient.sendMessageStream.mockReturnValue(createStreamFromEvents(events));
361
+ vi.mocked(mockConfig.getOutputFormat).mockReturnValue(OutputFormat.JSON);
362
+ const mockMetrics = {
363
+ models: {},
364
+ tools: {
365
+ totalCalls: 0,
366
+ totalSuccess: 0,
367
+ totalFail: 0,
368
+ totalDurationMs: 0,
369
+ totalDecisions: {
370
+ accept: 0,
371
+ reject: 0,
372
+ modify: 0,
373
+ auto_accept: 0,
374
+ },
375
+ byName: {},
376
+ },
377
+ files: {
378
+ totalLinesAdded: 0,
379
+ totalLinesRemoved: 0,
380
+ },
381
+ };
382
+ vi.mocked(uiTelemetryService.getMetrics).mockReturnValue(mockMetrics);
383
+ await runNonInteractive(mockConfig, mockSettings, 'Test input', 'prompt-id-1');
384
+ expect(mockGeminiClient.sendMessageStream).toHaveBeenCalledWith([{ text: 'Test input' }], expect.any(AbortSignal), 'prompt-id-1');
385
+ expect(processStdoutSpy).toHaveBeenCalledWith(JSON.stringify({ response: 'Hello World', stats: mockMetrics }, null, 2));
386
+ });
387
+ it('should write JSON output with stats for tool-only commands (no text response)', async () => {
388
+ // Test the scenario where a command completes successfully with only tool calls
389
+ // but no text response - this would have caught the original bug
390
+ const toolCallEvent = {
391
+ type: GeminiEventType.ToolCallRequest,
392
+ value: {
393
+ callId: 'tool-1',
394
+ name: 'testTool',
395
+ args: { arg1: 'value1' },
396
+ isClientInitiated: false,
397
+ prompt_id: 'prompt-id-tool-only',
398
+ },
399
+ };
400
+ const toolResponse = [{ text: 'Tool executed successfully' }];
401
+ mockCoreExecuteToolCall.mockResolvedValue({
402
+ status: 'success',
403
+ request: {
404
+ callId: 'tool-1',
405
+ name: 'testTool',
406
+ args: { arg1: 'value1' },
407
+ isClientInitiated: false,
408
+ prompt_id: 'prompt-id-tool-only',
409
+ },
410
+ tool: {},
411
+ invocation: {},
412
+ response: {
413
+ responseParts: toolResponse,
414
+ callId: 'tool-1',
415
+ error: undefined,
416
+ errorType: undefined,
417
+ contentLength: undefined,
418
+ },
419
+ });
420
+ // First call returns only tool call, no content
421
+ const firstCallEvents = [
422
+ toolCallEvent,
423
+ {
424
+ type: GeminiEventType.Finished,
425
+ value: { reason: undefined, usageMetadata: { totalTokenCount: 5 } },
426
+ },
427
+ ];
428
+ // Second call returns no content (tool-only completion)
429
+ const secondCallEvents = [
430
+ {
431
+ type: GeminiEventType.Finished,
432
+ value: { reason: undefined, usageMetadata: { totalTokenCount: 3 } },
433
+ },
434
+ ];
435
+ mockGeminiClient.sendMessageStream
436
+ .mockReturnValueOnce(createStreamFromEvents(firstCallEvents))
437
+ .mockReturnValueOnce(createStreamFromEvents(secondCallEvents));
438
+ vi.mocked(mockConfig.getOutputFormat).mockReturnValue(OutputFormat.JSON);
439
+ const mockMetrics = {
440
+ models: {},
441
+ tools: {
442
+ totalCalls: 1,
443
+ totalSuccess: 1,
444
+ totalFail: 0,
445
+ totalDurationMs: 100,
446
+ totalDecisions: {
447
+ accept: 1,
448
+ reject: 0,
449
+ modify: 0,
450
+ auto_accept: 0,
451
+ },
452
+ byName: {
453
+ testTool: {
454
+ count: 1,
455
+ success: 1,
456
+ fail: 0,
457
+ durationMs: 100,
458
+ decisions: {
459
+ accept: 1,
460
+ reject: 0,
461
+ modify: 0,
462
+ auto_accept: 0,
463
+ },
464
+ },
465
+ },
466
+ },
467
+ files: {
468
+ totalLinesAdded: 0,
469
+ totalLinesRemoved: 0,
470
+ },
471
+ };
472
+ vi.mocked(uiTelemetryService.getMetrics).mockReturnValue(mockMetrics);
473
+ await runNonInteractive(mockConfig, mockSettings, 'Execute tool only', 'prompt-id-tool-only');
474
+ expect(mockGeminiClient.sendMessageStream).toHaveBeenCalledTimes(2);
475
+ expect(mockCoreExecuteToolCall).toHaveBeenCalledWith(mockConfig, expect.objectContaining({ name: 'testTool' }), expect.any(AbortSignal));
476
+ // This should output JSON with empty response but include stats
477
+ expect(processStdoutSpy).toHaveBeenCalledWith(JSON.stringify({ response: '', stats: mockMetrics }, null, 2));
478
+ });
479
+ it('should write JSON output with stats for empty response commands', async () => {
480
+ // Test the scenario where a command completes but produces no content at all
481
+ const events = [
482
+ {
483
+ type: GeminiEventType.Finished,
484
+ value: { reason: undefined, usageMetadata: { totalTokenCount: 1 } },
485
+ },
486
+ ];
487
+ mockGeminiClient.sendMessageStream.mockReturnValue(createStreamFromEvents(events));
488
+ vi.mocked(mockConfig.getOutputFormat).mockReturnValue(OutputFormat.JSON);
489
+ const mockMetrics = {
490
+ models: {},
491
+ tools: {
492
+ totalCalls: 0,
493
+ totalSuccess: 0,
494
+ totalFail: 0,
495
+ totalDurationMs: 0,
496
+ totalDecisions: {
497
+ accept: 0,
498
+ reject: 0,
499
+ modify: 0,
500
+ auto_accept: 0,
501
+ },
502
+ byName: {},
503
+ },
504
+ files: {
505
+ totalLinesAdded: 0,
506
+ totalLinesRemoved: 0,
507
+ },
508
+ };
509
+ vi.mocked(uiTelemetryService.getMetrics).mockReturnValue(mockMetrics);
510
+ await runNonInteractive(mockConfig, mockSettings, 'Empty response test', 'prompt-id-empty');
511
+ expect(mockGeminiClient.sendMessageStream).toHaveBeenCalledWith([{ text: 'Empty response test' }], expect.any(AbortSignal), 'prompt-id-empty');
512
+ // This should output JSON with empty response but include stats
513
+ expect(processStdoutSpy).toHaveBeenCalledWith(JSON.stringify({ response: '', stats: mockMetrics }, null, 2));
514
+ });
515
+ it('should handle errors in JSON format', async () => {
516
+ vi.mocked(mockConfig.getOutputFormat).mockReturnValue(OutputFormat.JSON);
517
+ const testError = new Error('Invalid input provided');
518
+ mockGeminiClient.sendMessageStream.mockImplementation(() => {
519
+ throw testError;
520
+ });
521
+ // Mock console.error to capture JSON error output
522
+ const consoleErrorJsonSpy = vi
523
+ .spyOn(console, 'error')
524
+ .mockImplementation(() => { });
525
+ let thrownError = null;
526
+ try {
527
+ await runNonInteractive(mockConfig, mockSettings, 'Test input', 'prompt-id-error');
528
+ // Should not reach here
529
+ expect.fail('Expected process.exit to be called');
530
+ }
531
+ catch (error) {
532
+ thrownError = error;
533
+ }
534
+ // Should throw because of mocked process.exit
535
+ expect(thrownError?.message).toBe('process.exit(1) called');
536
+ expect(consoleErrorJsonSpy).toHaveBeenCalledWith(JSON.stringify({
537
+ error: {
538
+ type: 'Error',
539
+ message: 'Invalid input provided',
540
+ code: 1,
541
+ },
542
+ }, null, 2));
543
+ });
544
+ it('should handle FatalInputError with custom exit code in JSON format', async () => {
545
+ vi.mocked(mockConfig.getOutputFormat).mockReturnValue(OutputFormat.JSON);
546
+ const fatalError = new FatalInputError('Invalid command syntax provided');
547
+ mockGeminiClient.sendMessageStream.mockImplementation(() => {
548
+ throw fatalError;
549
+ });
550
+ // Mock console.error to capture JSON error output
551
+ const consoleErrorJsonSpy = vi
552
+ .spyOn(console, 'error')
553
+ .mockImplementation(() => { });
554
+ let thrownError = null;
555
+ try {
556
+ await runNonInteractive(mockConfig, mockSettings, 'Invalid syntax', 'prompt-id-fatal');
557
+ // Should not reach here
558
+ expect.fail('Expected process.exit to be called');
559
+ }
560
+ catch (error) {
561
+ thrownError = error;
562
+ }
563
+ // Should throw because of mocked process.exit with custom exit code
564
+ expect(thrownError?.message).toBe('process.exit(42) called');
565
+ expect(consoleErrorJsonSpy).toHaveBeenCalledWith(JSON.stringify({
566
+ error: {
567
+ type: 'FatalInputError',
568
+ message: 'Invalid command syntax provided',
569
+ code: 42,
570
+ },
571
+ }, null, 2));
572
+ });
573
+ it('should execute a slash command that returns a prompt', async () => {
574
+ const mockCommand = {
575
+ name: 'testcommand',
576
+ description: 'a test command',
577
+ action: vi.fn().mockResolvedValue({
578
+ type: 'submit_prompt',
579
+ content: [{ text: 'Prompt from command' }],
580
+ }),
581
+ };
582
+ mockGetCommands.mockReturnValue([mockCommand]);
583
+ const events = [
584
+ { type: GeminiEventType.Content, value: 'Response from command' },
585
+ {
586
+ type: GeminiEventType.Finished,
587
+ value: { reason: undefined, usageMetadata: { totalTokenCount: 5 } },
588
+ },
589
+ ];
590
+ mockGeminiClient.sendMessageStream.mockReturnValue(createStreamFromEvents(events));
591
+ await runNonInteractive(mockConfig, mockSettings, '/testcommand', 'prompt-id-slash');
592
+ // Ensure the prompt sent to the model is from the command, not the raw input
593
+ expect(mockGeminiClient.sendMessageStream).toHaveBeenCalledWith([{ text: 'Prompt from command' }], expect.any(AbortSignal), 'prompt-id-slash');
594
+ expect(processStdoutSpy).toHaveBeenCalledWith('Response from command');
595
+ });
596
+ it('should throw FatalInputError if a command requires confirmation', async () => {
597
+ const mockCommand = {
598
+ name: 'confirm',
599
+ description: 'a command that needs confirmation',
600
+ action: vi.fn().mockResolvedValue({
601
+ type: 'confirm_shell_commands',
602
+ commands: ['rm -rf /'],
603
+ }),
604
+ };
605
+ mockGetCommands.mockReturnValue([mockCommand]);
606
+ await expect(runNonInteractive(mockConfig, mockSettings, '/confirm', 'prompt-id-confirm')).rejects.toThrow('Exiting due to a confirmation prompt requested by the command.');
607
+ });
608
+ it('should treat an unknown slash command as a regular prompt', async () => {
609
+ // No commands are mocked, so any slash command is "unknown"
610
+ mockGetCommands.mockReturnValue([]);
611
+ const events = [
612
+ { type: GeminiEventType.Content, value: 'Response to unknown' },
613
+ {
614
+ type: GeminiEventType.Finished,
615
+ value: { reason: undefined, usageMetadata: { totalTokenCount: 5 } },
616
+ },
617
+ ];
618
+ mockGeminiClient.sendMessageStream.mockReturnValue(createStreamFromEvents(events));
619
+ await runNonInteractive(mockConfig, mockSettings, '/unknowncommand', 'prompt-id-unknown');
620
+ // Ensure the raw input is sent to the model
621
+ expect(mockGeminiClient.sendMessageStream).toHaveBeenCalledWith([{ text: '/unknowncommand' }], expect.any(AbortSignal), 'prompt-id-unknown');
622
+ expect(processStdoutSpy).toHaveBeenCalledWith('Response to unknown');
623
+ });
624
+ it('should throw for unhandled command result types', async () => {
625
+ const mockCommand = {
626
+ name: 'noaction',
627
+ description: 'unhandled type',
628
+ action: vi.fn().mockResolvedValue({
629
+ type: 'unhandled',
630
+ }),
631
+ };
632
+ mockGetCommands.mockReturnValue([mockCommand]);
633
+ await expect(runNonInteractive(mockConfig, mockSettings, '/noaction', 'prompt-id-unhandled')).rejects.toThrow('Exiting due to command result that is not supported in non-interactive mode.');
634
+ });
635
+ it('should pass arguments to the slash command action', async () => {
636
+ const mockAction = vi.fn().mockResolvedValue({
637
+ type: 'submit_prompt',
638
+ content: [{ text: 'Prompt from command' }],
639
+ });
640
+ const mockCommand = {
641
+ name: 'testargs',
642
+ description: 'a test command',
643
+ action: mockAction,
644
+ };
645
+ mockGetCommands.mockReturnValue([mockCommand]);
646
+ const events = [
647
+ { type: GeminiEventType.Content, value: 'Acknowledged' },
648
+ {
649
+ type: GeminiEventType.Finished,
650
+ value: { reason: undefined, usageMetadata: { totalTokenCount: 1 } },
651
+ },
652
+ ];
653
+ mockGeminiClient.sendMessageStream.mockReturnValue(createStreamFromEvents(events));
654
+ await runNonInteractive(mockConfig, mockSettings, '/testargs arg1 arg2', 'prompt-id-args');
655
+ expect(mockAction).toHaveBeenCalledWith(expect.any(Object), 'arg1 arg2');
656
+ expect(processStdoutSpy).toHaveBeenCalledWith('Acknowledged');
657
+ });
658
+ it('should instantiate CommandService with correct loaders for slash commands', async () => {
659
+ // This test indirectly checks that handleSlashCommand is using the right loaders.
660
+ const { FileCommandLoader } = await import('./services/FileCommandLoader.js');
661
+ const { McpPromptLoader } = await import('./services/McpPromptLoader.js');
662
+ mockGetCommands.mockReturnValue([]); // No commands found, so it will fall through
663
+ const events = [
664
+ { type: GeminiEventType.Content, value: 'Acknowledged' },
665
+ {
666
+ type: GeminiEventType.Finished,
667
+ value: { reason: undefined, usageMetadata: { totalTokenCount: 1 } },
668
+ },
669
+ ];
670
+ mockGeminiClient.sendMessageStream.mockReturnValue(createStreamFromEvents(events));
671
+ await runNonInteractive(mockConfig, mockSettings, '/mycommand', 'prompt-id-loaders');
672
+ // Check that loaders were instantiated with the config
673
+ expect(FileCommandLoader).toHaveBeenCalledTimes(1);
674
+ expect(FileCommandLoader).toHaveBeenCalledWith(mockConfig);
675
+ expect(McpPromptLoader).toHaveBeenCalledTimes(1);
676
+ expect(McpPromptLoader).toHaveBeenCalledWith(mockConfig);
677
+ // Check that instances were passed to CommandService.create
678
+ expect(mockCommandServiceCreate).toHaveBeenCalledTimes(1);
679
+ const loadersArg = mockCommandServiceCreate.mock.calls[0][0];
680
+ expect(loadersArg).toHaveLength(2);
681
+ expect(loadersArg[0]).toBe(vi.mocked(McpPromptLoader).mock.instances[0]);
682
+ expect(loadersArg[1]).toBe(vi.mocked(FileCommandLoader).mock.instances[0]);
683
+ });
684
+ it('should allow a normally-excluded tool when --allowed-tools is set', async () => {
685
+ // By default, ShellTool is excluded in non-interactive mode.
686
+ // This test ensures that --allowed-tools overrides this exclusion.
687
+ vi.mocked(mockConfig.getToolRegistry).mockReturnValue({
688
+ getTool: vi.fn().mockReturnValue({
689
+ name: 'ShellTool',
690
+ description: 'A shell tool',
691
+ run: vi.fn(),
692
+ }),
693
+ getFunctionDeclarations: vi.fn().mockReturnValue([{ name: 'ShellTool' }]),
694
+ });
695
+ const toolCallEvent = {
696
+ type: GeminiEventType.ToolCallRequest,
697
+ value: {
698
+ callId: 'tool-shell-1',
699
+ name: 'ShellTool',
700
+ args: { command: 'ls' },
701
+ isClientInitiated: false,
702
+ prompt_id: 'prompt-id-allowed',
703
+ },
704
+ };
705
+ const toolResponse = [{ text: 'file.txt' }];
706
+ mockCoreExecuteToolCall.mockResolvedValue({
707
+ status: 'success',
708
+ request: {
709
+ callId: 'tool-shell-1',
710
+ name: 'ShellTool',
711
+ args: { command: 'ls' },
712
+ isClientInitiated: false,
713
+ prompt_id: 'prompt-id-allowed',
714
+ },
715
+ tool: {},
716
+ invocation: {},
717
+ response: {
718
+ responseParts: toolResponse,
719
+ callId: 'tool-shell-1',
720
+ error: undefined,
721
+ errorType: undefined,
722
+ contentLength: undefined,
723
+ },
724
+ });
725
+ const firstCallEvents = [toolCallEvent];
726
+ const secondCallEvents = [
727
+ { type: GeminiEventType.Content, value: 'file.txt' },
728
+ {
729
+ type: GeminiEventType.Finished,
730
+ value: { reason: undefined, usageMetadata: { totalTokenCount: 10 } },
731
+ },
732
+ ];
733
+ mockGeminiClient.sendMessageStream
734
+ .mockReturnValueOnce(createStreamFromEvents(firstCallEvents))
735
+ .mockReturnValueOnce(createStreamFromEvents(secondCallEvents));
736
+ await runNonInteractive(mockConfig, mockSettings, 'List the files', 'prompt-id-allowed');
737
+ expect(mockCoreExecuteToolCall).toHaveBeenCalledWith(mockConfig, expect.objectContaining({ name: 'ShellTool' }), expect.any(AbortSignal));
738
+ expect(processStdoutSpy).toHaveBeenCalledWith('file.txt');
739
+ });
740
+ });
741
+ //# sourceMappingURL=nonInteractiveCli.test.js.map