@machina.ai/cell-cli 1.10.0-rc1 → 1.13.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 (813) hide show
  1. package/dist/index.js +5 -5
  2. package/dist/index.js.map +1 -1
  3. package/dist/package.json +14 -12
  4. package/dist/src/commands/extensions/disable.d.ts +1 -1
  5. package/dist/src/commands/extensions/disable.js +19 -8
  6. package/dist/src/commands/extensions/disable.js.map +1 -1
  7. package/dist/src/commands/extensions/enable.d.ts +1 -1
  8. package/dist/src/commands/extensions/enable.js +19 -9
  9. package/dist/src/commands/extensions/enable.js.map +1 -1
  10. package/dist/src/commands/extensions/examples/mcp-server/example.js +46 -0
  11. package/dist/src/commands/extensions/examples/mcp-server/example.js.map +1 -0
  12. package/dist/src/commands/extensions/install.d.ts +1 -0
  13. package/dist/src/commands/extensions/install.js +29 -4
  14. package/dist/src/commands/extensions/install.js.map +1 -1
  15. package/dist/src/commands/extensions/install.test.js +39 -19
  16. package/dist/src/commands/extensions/install.test.js.map +1 -1
  17. package/dist/src/commands/extensions/link.js +16 -4
  18. package/dist/src/commands/extensions/link.js.map +1 -1
  19. package/dist/src/commands/extensions/list.js +17 -6
  20. package/dist/src/commands/extensions/list.js.map +1 -1
  21. package/dist/src/commands/extensions/new.js +14 -20
  22. package/dist/src/commands/extensions/new.js.map +1 -1
  23. package/dist/src/commands/extensions/uninstall.js +16 -4
  24. package/dist/src/commands/extensions/uninstall.js.map +1 -1
  25. package/dist/src/commands/extensions/update.js +28 -23
  26. package/dist/src/commands/extensions/update.js.map +1 -1
  27. package/dist/src/commands/extensions/validate.d.ts +12 -0
  28. package/dist/src/commands/extensions/validate.js +83 -0
  29. package/dist/src/commands/extensions/validate.js.map +1 -0
  30. package/dist/src/commands/extensions/validate.test.d.ts +6 -0
  31. package/dist/src/commands/extensions/validate.test.js +93 -0
  32. package/dist/src/commands/extensions/validate.test.js.map +1 -0
  33. package/dist/src/commands/extensions.js +3 -0
  34. package/dist/src/commands/extensions.js.map +1 -1
  35. package/dist/src/commands/mcp/add.js +7 -4
  36. package/dist/src/commands/mcp/add.js.map +1 -1
  37. package/dist/src/commands/mcp/add.test.d.ts +6 -0
  38. package/dist/src/commands/mcp/add.test.js +247 -0
  39. package/dist/src/commands/mcp/add.test.js.map +1 -0
  40. package/dist/src/commands/mcp/list.js +18 -9
  41. package/dist/src/commands/mcp/list.js.map +1 -1
  42. package/dist/src/commands/mcp/list.test.d.ts +6 -0
  43. package/dist/src/commands/mcp/list.test.js +128 -0
  44. package/dist/src/commands/mcp/list.test.js.map +1 -0
  45. package/dist/src/commands/mcp/remove.js +3 -2
  46. package/dist/src/commands/mcp/remove.js.map +1 -1
  47. package/dist/src/commands/mcp/remove.test.d.ts +6 -0
  48. package/dist/src/commands/mcp/remove.test.js +175 -0
  49. package/dist/src/commands/mcp/remove.test.js.map +1 -0
  50. package/dist/src/commands/mcp.test.d.ts +6 -0
  51. package/dist/src/commands/mcp.test.js +62 -0
  52. package/dist/src/commands/mcp.test.js.map +1 -0
  53. package/dist/src/config/auth.js +0 -3
  54. package/dist/src/config/auth.js.map +1 -1
  55. package/dist/src/config/config.d.ts +6 -15
  56. package/dist/src/config/config.integration.test.d.ts +6 -0
  57. package/dist/src/config/config.integration.test.js +321 -0
  58. package/dist/src/config/config.integration.test.js.map +1 -0
  59. package/dist/src/config/config.js +85 -164
  60. package/dist/src/config/config.js.map +1 -1
  61. package/dist/src/config/config.test.d.ts +6 -0
  62. package/dist/src/config/config.test.js +1972 -0
  63. package/dist/src/config/config.test.js.map +1 -0
  64. package/dist/src/config/extension-manager.d.ts +63 -0
  65. package/dist/src/config/extension-manager.js +450 -0
  66. package/dist/src/config/extension-manager.js.map +1 -0
  67. package/dist/src/config/extension.d.ts +4 -61
  68. package/dist/src/config/extension.js +1 -538
  69. package/dist/src/config/extension.js.map +1 -1
  70. package/dist/src/config/extension.test.d.ts +6 -0
  71. package/dist/src/config/extension.test.js +1412 -0
  72. package/dist/src/config/extension.test.js.map +1 -0
  73. package/dist/src/config/extensions/consent.d.ts +38 -0
  74. package/dist/src/config/extensions/consent.js +123 -0
  75. package/dist/src/config/extensions/consent.js.map +1 -0
  76. package/dist/src/config/extensions/extensionEnablement.d.ts +2 -2
  77. package/dist/src/config/extensions/extensionEnablement.js +7 -5
  78. package/dist/src/config/extensions/extensionEnablement.js.map +1 -1
  79. package/dist/src/config/extensions/extensionEnablement.test.js +31 -28
  80. package/dist/src/config/extensions/extensionEnablement.test.js.map +1 -1
  81. package/dist/src/config/extensions/extensionSettings.d.ts +15 -0
  82. package/dist/src/config/extensions/extensionSettings.js +113 -0
  83. package/dist/src/config/extensions/extensionSettings.js.map +1 -0
  84. package/dist/src/config/extensions/extensionSettings.test.d.ts +6 -0
  85. package/dist/src/config/extensions/extensionSettings.test.js +254 -0
  86. package/dist/src/config/extensions/extensionSettings.test.js.map +1 -0
  87. package/dist/src/config/extensions/github.d.ts +18 -9
  88. package/dist/src/config/extensions/github.js +108 -36
  89. package/dist/src/config/extensions/github.js.map +1 -1
  90. package/dist/src/config/extensions/github.test.js +158 -164
  91. package/dist/src/config/extensions/github.test.js.map +1 -1
  92. package/dist/src/config/extensions/github_fetch.d.ts +1 -1
  93. package/dist/src/config/extensions/github_fetch.js +13 -1
  94. package/dist/src/config/extensions/github_fetch.js.map +1 -1
  95. package/dist/src/config/extensions/github_fetch.test.d.ts +6 -0
  96. package/dist/src/config/extensions/github_fetch.test.js +169 -0
  97. package/dist/src/config/extensions/github_fetch.test.js.map +1 -0
  98. package/dist/src/config/extensions/storage.d.ts +14 -0
  99. package/dist/src/config/extensions/storage.js +32 -0
  100. package/dist/src/config/extensions/storage.js.map +1 -0
  101. package/dist/src/config/extensions/update.d.ts +5 -4
  102. package/dist/src/config/extensions/update.js +41 -37
  103. package/dist/src/config/extensions/update.js.map +1 -1
  104. package/dist/src/config/extensions/update.test.js +72 -74
  105. package/dist/src/config/extensions/update.test.js.map +1 -1
  106. package/dist/src/config/extensions/variableSchema.d.ts +0 -4
  107. package/dist/src/config/extensions/variableSchema.js.map +1 -1
  108. package/dist/src/config/extensions/variables.d.ts +4 -0
  109. package/dist/src/config/extensions/variables.js +6 -0
  110. package/dist/src/config/extensions/variables.js.map +1 -1
  111. package/dist/src/config/keyBindings.d.ts +5 -1
  112. package/dist/src/config/keyBindings.js +34 -10
  113. package/dist/src/config/keyBindings.js.map +1 -1
  114. package/dist/src/config/keyBindings.test.js +17 -0
  115. package/dist/src/config/keyBindings.test.js.map +1 -1
  116. package/dist/src/config/policies/read-only.toml +56 -0
  117. package/dist/src/config/policies/write.toml +63 -0
  118. package/dist/src/config/policies/yolo.toml +31 -0
  119. package/dist/src/config/policy-engine.integration.test.js +41 -38
  120. package/dist/src/config/policy-engine.integration.test.js.map +1 -1
  121. package/dist/src/config/policy.d.ts +4 -3
  122. package/dist/src/config/policy.js +13 -142
  123. package/dist/src/config/policy.js.map +1 -1
  124. package/dist/src/config/sandboxConfig.d.ts +1 -2
  125. package/dist/src/config/sandboxConfig.js +7 -6
  126. package/dist/src/config/sandboxConfig.js.map +1 -1
  127. package/dist/src/config/settings.d.ts +2 -1
  128. package/dist/src/config/settings.js +59 -15
  129. package/dist/src/config/settings.js.map +1 -1
  130. package/dist/src/config/settings.test.d.ts +6 -0
  131. package/dist/src/config/settings.test.js +2000 -0
  132. package/dist/src/config/settings.test.js.map +1 -0
  133. package/dist/src/config/settingsSchema.d.ts +170 -28
  134. package/dist/src/config/settingsSchema.js +418 -27
  135. package/dist/src/config/settingsSchema.js.map +1 -1
  136. package/dist/src/config/settingsSchema.test.js +42 -1
  137. package/dist/src/config/settingsSchema.test.js.map +1 -1
  138. package/dist/src/config/trustedFolders.d.ts +1 -1
  139. package/dist/src/config/trustedFolders.js +4 -2
  140. package/dist/src/config/trustedFolders.js.map +1 -1
  141. package/dist/src/core/initializer.js +2 -1
  142. package/dist/src/core/initializer.js.map +1 -1
  143. package/dist/src/gemini.d.ts +1 -1
  144. package/dist/src/gemini.js +63 -27
  145. package/dist/src/gemini.js.map +1 -1
  146. package/dist/src/gemini.test.js +123 -34
  147. package/dist/src/gemini.test.js.map +1 -1
  148. package/dist/src/generated/git-commit.d.ts +2 -2
  149. package/dist/src/generated/git-commit.js +2 -2
  150. package/dist/src/nonInteractiveCli.d.ts +9 -1
  151. package/dist/src/nonInteractiveCli.js +205 -10
  152. package/dist/src/nonInteractiveCli.js.map +1 -1
  153. package/dist/src/nonInteractiveCli.test.d.ts +6 -0
  154. package/dist/src/nonInteractiveCli.test.js +984 -0
  155. package/dist/src/nonInteractiveCli.test.js.map +1 -0
  156. package/dist/src/nonInteractiveCliCommands.js +2 -2
  157. package/dist/src/nonInteractiveCliCommands.js.map +1 -1
  158. package/dist/src/services/BuiltinCommandLoader.js +4 -0
  159. package/dist/src/services/BuiltinCommandLoader.js.map +1 -1
  160. package/dist/src/services/BuiltinCommandLoader.test.js +22 -0
  161. package/dist/src/services/BuiltinCommandLoader.test.js.map +1 -1
  162. package/dist/src/services/CommandService.js +2 -1
  163. package/dist/src/services/CommandService.js.map +1 -1
  164. package/dist/src/services/FeedbackService.js +2 -2
  165. package/dist/src/services/FeedbackService.js.map +1 -1
  166. package/dist/src/services/FileCommandLoader.test.d.ts +6 -0
  167. package/dist/src/services/FileCommandLoader.test.js +971 -0
  168. package/dist/src/services/FileCommandLoader.test.js.map +1 -0
  169. package/dist/src/services/McpPromptLoader.js +2 -2
  170. package/dist/src/services/McpPromptLoader.js.map +1 -1
  171. package/dist/src/services/McpPromptLoader.test.js +4 -2
  172. package/dist/src/services/McpPromptLoader.test.js.map +1 -1
  173. package/dist/src/services/prompt-processors/argumentProcessor.test.d.ts +6 -0
  174. package/dist/src/services/prompt-processors/argumentProcessor.test.js +40 -0
  175. package/dist/src/services/prompt-processors/argumentProcessor.test.js.map +1 -0
  176. package/dist/src/services/prompt-processors/atFileProcessor.js +3 -2
  177. package/dist/src/services/prompt-processors/atFileProcessor.js.map +1 -1
  178. package/dist/src/services/prompt-processors/shellProcessor.test.d.ts +6 -0
  179. package/dist/src/services/prompt-processors/shellProcessor.test.js +482 -0
  180. package/dist/src/services/prompt-processors/shellProcessor.test.js.map +1 -0
  181. package/dist/src/test-utils/async.d.ts +9 -0
  182. package/dist/src/test-utils/async.js +29 -0
  183. package/dist/src/test-utils/async.js.map +1 -0
  184. package/dist/src/test-utils/createExtension.d.ts +3 -1
  185. package/dist/src/test-utils/createExtension.js +3 -3
  186. package/dist/src/test-utils/createExtension.js.map +1 -1
  187. package/dist/src/test-utils/render.d.ts +17 -2
  188. package/dist/src/test-utils/render.js +69 -4
  189. package/dist/src/test-utils/render.js.map +1 -1
  190. package/dist/src/test-utils/render.test.d.ts +6 -0
  191. package/dist/src/test-utils/render.test.js +79 -0
  192. package/dist/src/test-utils/render.test.js.map +1 -0
  193. package/dist/src/ui/App.test.d.ts +6 -0
  194. package/dist/src/ui/App.test.js +110 -0
  195. package/dist/src/ui/App.test.js.map +1 -0
  196. package/dist/src/ui/AppContainer.js +223 -92
  197. package/dist/src/ui/AppContainer.js.map +1 -1
  198. package/dist/src/ui/AppContainer.test.js +531 -147
  199. package/dist/src/ui/AppContainer.test.js.map +1 -1
  200. package/dist/src/ui/IdeIntegrationNudge.js +1 -1
  201. package/dist/src/ui/IdeIntegrationNudge.js.map +1 -1
  202. package/dist/src/ui/auth/ApiAuthDialog.d.ts +14 -0
  203. package/dist/src/ui/auth/ApiAuthDialog.js +26 -0
  204. package/dist/src/ui/auth/ApiAuthDialog.js.map +1 -0
  205. package/dist/src/ui/auth/ApiAuthDialog.test.d.ts +6 -0
  206. package/dist/src/ui/auth/ApiAuthDialog.test.js +91 -0
  207. package/dist/src/ui/auth/ApiAuthDialog.test.js.map +1 -0
  208. package/dist/src/ui/auth/AuthDialog.d.ts +1 -1
  209. package/dist/src/ui/auth/AuthDialog.js +9 -3
  210. package/dist/src/ui/auth/AuthDialog.js.map +1 -1
  211. package/dist/src/ui/auth/useAuth.d.ts +3 -1
  212. package/dist/src/ui/auth/useAuth.js +35 -4
  213. package/dist/src/ui/auth/useAuth.js.map +1 -1
  214. package/dist/src/ui/colors.js +3 -0
  215. package/dist/src/ui/colors.js.map +1 -1
  216. package/dist/src/ui/commands/aboutCommand.js +1 -1
  217. package/dist/src/ui/commands/aboutCommand.test.d.ts +6 -0
  218. package/dist/src/ui/commands/aboutCommand.test.js +130 -0
  219. package/dist/src/ui/commands/aboutCommand.test.js.map +1 -0
  220. package/dist/src/ui/commands/authCommand.js +1 -1
  221. package/dist/src/ui/commands/authCommand.test.d.ts +6 -0
  222. package/dist/src/ui/commands/authCommand.test.js +30 -0
  223. package/dist/src/ui/commands/authCommand.test.js.map +1 -0
  224. package/dist/src/ui/commands/bugCommand.js +1 -1
  225. package/dist/src/ui/commands/bugCommand.test.d.ts +6 -0
  226. package/dist/src/ui/commands/bugCommand.test.js +105 -0
  227. package/dist/src/ui/commands/bugCommand.test.js.map +1 -0
  228. package/dist/src/ui/commands/chatCommand.js +1 -1
  229. package/dist/src/ui/commands/chatCommand.js.map +1 -1
  230. package/dist/src/ui/commands/chatCommand.test.d.ts +6 -0
  231. package/dist/src/ui/commands/chatCommand.test.js +555 -0
  232. package/dist/src/ui/commands/chatCommand.test.js.map +1 -0
  233. package/dist/src/ui/commands/clearCommand.js +1 -1
  234. package/dist/src/ui/commands/clearCommand.test.d.ts +6 -0
  235. package/dist/src/ui/commands/clearCommand.test.js +76 -0
  236. package/dist/src/ui/commands/clearCommand.test.js.map +1 -0
  237. package/dist/src/ui/commands/compressCommand.js +1 -1
  238. package/dist/src/ui/commands/compressCommand.js.map +1 -1
  239. package/dist/src/ui/commands/compressCommand.test.d.ts +6 -0
  240. package/dist/src/ui/commands/compressCommand.test.js +98 -0
  241. package/dist/src/ui/commands/compressCommand.test.js.map +1 -0
  242. package/dist/src/ui/commands/copyCommand.js +2 -1
  243. package/dist/src/ui/commands/copyCommand.js.map +1 -1
  244. package/dist/src/ui/commands/copyCommand.test.d.ts +6 -0
  245. package/dist/src/ui/commands/copyCommand.test.js +242 -0
  246. package/dist/src/ui/commands/copyCommand.test.js.map +1 -0
  247. package/dist/src/ui/commands/corgiCommand.js +1 -1
  248. package/dist/src/ui/commands/corgiCommand.js.map +1 -1
  249. package/dist/src/ui/commands/corgiCommand.test.d.ts +6 -0
  250. package/dist/src/ui/commands/corgiCommand.test.js +28 -0
  251. package/dist/src/ui/commands/corgiCommand.test.js.map +1 -0
  252. package/dist/src/ui/commands/directoryCommand.js +1 -1
  253. package/dist/src/ui/commands/directoryCommand.js.map +1 -1
  254. package/dist/src/ui/commands/directoryCommand.test.d.ts +6 -0
  255. package/dist/src/ui/commands/directoryCommand.test.js +144 -0
  256. package/dist/src/ui/commands/directoryCommand.test.js.map +1 -0
  257. package/dist/src/ui/commands/docsCommand.js +1 -1
  258. package/dist/src/ui/commands/docsCommand.test.d.ts +6 -0
  259. package/dist/src/ui/commands/docsCommand.test.js +72 -0
  260. package/dist/src/ui/commands/docsCommand.test.js.map +1 -0
  261. package/dist/src/ui/commands/editorCommand.js +1 -1
  262. package/dist/src/ui/commands/editorCommand.test.d.ts +6 -0
  263. package/dist/src/ui/commands/editorCommand.test.js +27 -0
  264. package/dist/src/ui/commands/editorCommand.test.js.map +1 -0
  265. package/dist/src/ui/commands/extensionsCommand.js +64 -11
  266. package/dist/src/ui/commands/extensionsCommand.js.map +1 -1
  267. package/dist/src/ui/commands/extensionsCommand.test.d.ts +6 -0
  268. package/dist/src/ui/commands/extensionsCommand.test.js +315 -0
  269. package/dist/src/ui/commands/extensionsCommand.test.js.map +1 -0
  270. package/dist/src/ui/commands/helpCommand.js +1 -1
  271. package/dist/src/ui/commands/helpCommand.test.d.ts +6 -0
  272. package/dist/src/ui/commands/helpCommand.test.js +42 -0
  273. package/dist/src/ui/commands/helpCommand.test.js.map +1 -0
  274. package/dist/src/ui/commands/ideCommand.js +6 -6
  275. package/dist/src/ui/commands/ideCommand.test.d.ts +6 -0
  276. package/dist/src/ui/commands/ideCommand.test.js +205 -0
  277. package/dist/src/ui/commands/ideCommand.test.js.map +1 -0
  278. package/dist/src/ui/commands/initCommand.js +1 -1
  279. package/dist/src/ui/commands/initCommand.js.map +1 -1
  280. package/dist/src/ui/commands/initCommand.test.d.ts +6 -0
  281. package/dist/src/ui/commands/initCommand.test.js +80 -0
  282. package/dist/src/ui/commands/initCommand.test.js.map +1 -0
  283. package/dist/src/ui/commands/mcpCommand.js +110 -100
  284. package/dist/src/ui/commands/mcpCommand.js.map +1 -1
  285. package/dist/src/ui/commands/mcpCommand.test.d.ts +6 -0
  286. package/dist/src/ui/commands/mcpCommand.test.js +152 -0
  287. package/dist/src/ui/commands/mcpCommand.test.js.map +1 -0
  288. package/dist/src/ui/commands/memoryCommand.js +6 -6
  289. package/dist/src/ui/commands/memoryCommand.js.map +1 -1
  290. package/dist/src/ui/commands/memoryCommand.test.d.ts +6 -0
  291. package/dist/src/ui/commands/memoryCommand.test.js +268 -0
  292. package/dist/src/ui/commands/memoryCommand.test.js.map +1 -0
  293. package/dist/src/ui/commands/policiesCommand.d.ts +7 -0
  294. package/dist/src/ui/commands/policiesCommand.js +59 -0
  295. package/dist/src/ui/commands/policiesCommand.js.map +1 -0
  296. package/dist/src/ui/commands/policiesCommand.test.d.ts +6 -0
  297. package/dist/src/ui/commands/policiesCommand.test.js +83 -0
  298. package/dist/src/ui/commands/policiesCommand.test.js.map +1 -0
  299. package/dist/src/ui/commands/privacyCommand.js +1 -1
  300. package/dist/src/ui/commands/privacyCommand.test.d.ts +6 -0
  301. package/dist/src/ui/commands/privacyCommand.test.js +32 -0
  302. package/dist/src/ui/commands/privacyCommand.test.js.map +1 -0
  303. package/dist/src/ui/commands/quitCommand.js +1 -1
  304. package/dist/src/ui/commands/quitCommand.test.d.ts +6 -0
  305. package/dist/src/ui/commands/quitCommand.test.js +50 -0
  306. package/dist/src/ui/commands/quitCommand.test.js.map +1 -0
  307. package/dist/src/ui/commands/restoreCommand.test.d.ts +6 -0
  308. package/dist/src/ui/commands/restoreCommand.test.js +190 -0
  309. package/dist/src/ui/commands/restoreCommand.test.js.map +1 -0
  310. package/dist/src/ui/commands/settingsCommand.test.d.ts +6 -0
  311. package/dist/src/ui/commands/settingsCommand.test.js +30 -0
  312. package/dist/src/ui/commands/settingsCommand.test.js.map +1 -0
  313. package/dist/src/ui/commands/setupGithubCommand.js +4 -3
  314. package/dist/src/ui/commands/setupGithubCommand.js.map +1 -1
  315. package/dist/src/ui/commands/setupGithubCommand.test.js +1 -2
  316. package/dist/src/ui/commands/setupGithubCommand.test.js.map +1 -1
  317. package/dist/src/ui/commands/statsCommand.js +3 -3
  318. package/dist/src/ui/commands/statsCommand.js.map +1 -1
  319. package/dist/src/ui/commands/statsCommand.test.d.ts +6 -0
  320. package/dist/src/ui/commands/statsCommand.test.js +53 -0
  321. package/dist/src/ui/commands/statsCommand.test.js.map +1 -0
  322. package/dist/src/ui/commands/terminalSetupCommand.test.d.ts +6 -0
  323. package/dist/src/ui/commands/terminalSetupCommand.test.js +66 -0
  324. package/dist/src/ui/commands/terminalSetupCommand.test.js.map +1 -0
  325. package/dist/src/ui/commands/themeCommand.js +1 -1
  326. package/dist/src/ui/commands/themeCommand.test.d.ts +6 -0
  327. package/dist/src/ui/commands/themeCommand.test.js +32 -0
  328. package/dist/src/ui/commands/themeCommand.test.js.map +1 -0
  329. package/dist/src/ui/commands/toolsCommand.js +1 -1
  330. package/dist/src/ui/commands/toolsCommand.test.d.ts +6 -0
  331. package/dist/src/ui/commands/toolsCommand.test.js +100 -0
  332. package/dist/src/ui/commands/toolsCommand.test.js.map +1 -0
  333. package/dist/src/ui/commands/types.d.ts +1 -0
  334. package/dist/src/ui/commands/vimCommand.js +1 -1
  335. package/dist/src/ui/components/AnsiOutput.test.js +1 -1
  336. package/dist/src/ui/components/AnsiOutput.test.js.map +1 -1
  337. package/dist/src/ui/components/AsciiArt.d.ts +3 -3
  338. package/dist/src/ui/components/AsciiArt.js +3 -3
  339. package/dist/src/ui/components/Composer.js +6 -4
  340. package/dist/src/ui/components/Composer.js.map +1 -1
  341. package/dist/src/ui/components/Composer.test.js +21 -3
  342. package/dist/src/ui/components/Composer.test.js.map +1 -1
  343. package/dist/src/ui/components/ConfigInitDisplay.js +4 -6
  344. package/dist/src/ui/components/ConfigInitDisplay.js.map +1 -1
  345. package/dist/src/ui/components/ConsentPrompt.test.js +18 -8
  346. package/dist/src/ui/components/ConsentPrompt.test.js.map +1 -1
  347. package/dist/src/ui/components/ConsoleSummaryDisplay.js +1 -1
  348. package/dist/src/ui/components/ConsoleSummaryDisplay.js.map +1 -1
  349. package/dist/src/ui/components/ContextSummaryDisplay.d.ts +0 -1
  350. package/dist/src/ui/components/ContextSummaryDisplay.js +2 -12
  351. package/dist/src/ui/components/ContextSummaryDisplay.js.map +1 -1
  352. package/dist/src/ui/components/ContextSummaryDisplay.test.d.ts +6 -0
  353. package/dist/src/ui/components/ContextSummaryDisplay.test.js +71 -0
  354. package/dist/src/ui/components/ContextSummaryDisplay.test.js.map +1 -0
  355. package/dist/src/ui/components/DetailedMessagesDisplay.js +1 -1
  356. package/dist/src/ui/components/DetailedMessagesDisplay.js.map +1 -1
  357. package/dist/src/ui/components/DialogManager.js +5 -5
  358. package/dist/src/ui/components/DialogManager.js.map +1 -1
  359. package/dist/src/ui/components/EditorSettingsDialog.js +1 -1
  360. package/dist/src/ui/components/EditorSettingsDialog.js.map +1 -1
  361. package/dist/src/ui/components/FolderTrustDialog.test.js +8 -3
  362. package/dist/src/ui/components/FolderTrustDialog.test.js.map +1 -1
  363. package/dist/src/ui/components/Footer.js +4 -3
  364. package/dist/src/ui/components/Footer.js.map +1 -1
  365. package/dist/src/ui/components/Footer.test.d.ts +6 -0
  366. package/dist/src/ui/components/Footer.test.js +314 -0
  367. package/dist/src/ui/components/Footer.test.js.map +1 -0
  368. package/dist/src/ui/components/Header.test.js +13 -5
  369. package/dist/src/ui/components/Header.test.js.map +1 -1
  370. package/dist/src/ui/components/Help.test.js +5 -4
  371. package/dist/src/ui/components/Help.test.js.map +1 -1
  372. package/dist/src/ui/components/HistoryItemDisplay.js +1 -1
  373. package/dist/src/ui/components/HistoryItemDisplay.js.map +1 -1
  374. package/dist/src/ui/components/InputPrompt.d.ts +4 -0
  375. package/dist/src/ui/components/InputPrompt.js +80 -12
  376. package/dist/src/ui/components/InputPrompt.js.map +1 -1
  377. package/dist/src/ui/components/InputPrompt.test.d.ts +6 -0
  378. package/dist/src/ui/components/InputPrompt.test.js +1786 -0
  379. package/dist/src/ui/components/InputPrompt.test.js.map +1 -0
  380. package/dist/src/ui/components/LoadingIndicator.js +2 -2
  381. package/dist/src/ui/components/LoadingIndicator.js.map +1 -1
  382. package/dist/src/ui/components/LoadingIndicator.test.js +28 -15
  383. package/dist/src/ui/components/LoadingIndicator.test.js.map +1 -1
  384. package/dist/src/ui/components/LoopDetectionConfirmation.js +1 -1
  385. package/dist/src/ui/components/LoopDetectionConfirmation.js.map +1 -1
  386. package/dist/src/ui/components/LoopDetectionConfirmation.test.js +2 -2
  387. package/dist/src/ui/components/LoopDetectionConfirmation.test.js.map +1 -1
  388. package/dist/src/ui/components/MainContent.js +15 -4
  389. package/dist/src/ui/components/MainContent.js.map +1 -1
  390. package/dist/src/ui/components/ModelDialog.js +1 -1
  391. package/dist/src/ui/components/ModelDialog.js.map +1 -1
  392. package/dist/src/ui/components/ModelDialog.test.js +23 -13
  393. package/dist/src/ui/components/ModelDialog.test.js.map +1 -1
  394. package/dist/src/ui/components/ModelStatsDisplay.test.d.ts +6 -0
  395. package/dist/src/ui/components/ModelStatsDisplay.test.js +285 -0
  396. package/dist/src/ui/components/ModelStatsDisplay.test.js.map +1 -0
  397. package/dist/src/ui/components/Notifications.js +38 -5
  398. package/dist/src/ui/components/Notifications.js.map +1 -1
  399. package/dist/src/ui/components/PermissionsModifyTrustDialog.js +22 -18
  400. package/dist/src/ui/components/PermissionsModifyTrustDialog.js.map +1 -1
  401. package/dist/src/ui/components/PermissionsModifyTrustDialog.test.js +12 -4
  402. package/dist/src/ui/components/PermissionsModifyTrustDialog.test.js.map +1 -1
  403. package/dist/src/ui/components/PrepareLabel.test.js +14 -8
  404. package/dist/src/ui/components/PrepareLabel.test.js.map +1 -1
  405. package/dist/src/ui/components/ProQuotaDialog.test.js +14 -6
  406. package/dist/src/ui/components/ProQuotaDialog.test.js.map +1 -1
  407. package/dist/src/ui/components/QueuedMessageDisplay.js +3 -3
  408. package/dist/src/ui/components/QueuedMessageDisplay.js.map +1 -1
  409. package/dist/src/ui/components/QueuedMessageDisplay.test.js +15 -6
  410. package/dist/src/ui/components/QueuedMessageDisplay.test.js.map +1 -1
  411. package/dist/src/ui/components/RawMarkdownIndicator.d.ts +7 -0
  412. package/dist/src/ui/components/RawMarkdownIndicator.js +8 -0
  413. package/dist/src/ui/components/RawMarkdownIndicator.js.map +1 -0
  414. package/dist/src/ui/components/SessionSummaryDisplay.test.d.ts +6 -0
  415. package/dist/src/ui/components/SessionSummaryDisplay.test.js +74 -0
  416. package/dist/src/ui/components/SessionSummaryDisplay.test.js.map +1 -0
  417. package/dist/src/ui/components/SettingsDialog.js +43 -35
  418. package/dist/src/ui/components/SettingsDialog.js.map +1 -1
  419. package/dist/src/ui/components/SettingsDialog.test.js +554 -545
  420. package/dist/src/ui/components/SettingsDialog.test.js.map +1 -1
  421. package/dist/src/ui/components/ShellConfirmationDialog.js +1 -1
  422. package/dist/src/ui/components/ShellConfirmationDialog.js.map +1 -1
  423. package/dist/src/ui/components/ShellConfirmationDialog.test.js +2 -2
  424. package/dist/src/ui/components/ShellConfirmationDialog.test.js.map +1 -1
  425. package/dist/src/ui/components/StatsDisplay.test.d.ts +6 -0
  426. package/dist/src/ui/components/StatsDisplay.test.js +351 -0
  427. package/dist/src/ui/components/StatsDisplay.test.js.map +1 -0
  428. package/dist/src/ui/components/SuggestionsDisplay.js +1 -1
  429. package/dist/src/ui/components/SuggestionsDisplay.js.map +1 -1
  430. package/dist/src/ui/components/ThemeDialog.d.ts +4 -2
  431. package/dist/src/ui/components/ThemeDialog.js +3 -3
  432. package/dist/src/ui/components/ThemeDialog.js.map +1 -1
  433. package/dist/src/ui/components/ThemeDialog.test.js +14 -1
  434. package/dist/src/ui/components/ThemeDialog.test.js.map +1 -1
  435. package/dist/src/ui/components/ToolStatsDisplay.test.d.ts +6 -0
  436. package/dist/src/ui/components/ToolStatsDisplay.test.js +227 -0
  437. package/dist/src/ui/components/ToolStatsDisplay.test.js.map +1 -0
  438. package/dist/src/ui/components/messages/CompressionMessage.test.js +25 -17
  439. package/dist/src/ui/components/messages/CompressionMessage.test.js.map +1 -1
  440. package/dist/src/ui/components/messages/DiffRenderer.test.js +1 -1
  441. package/dist/src/ui/components/messages/DiffRenderer.test.js.map +1 -1
  442. package/dist/src/ui/components/messages/GeminiMessage.js +3 -1
  443. package/dist/src/ui/components/messages/GeminiMessage.js.map +1 -1
  444. package/dist/src/ui/components/messages/GeminiMessage.test.d.ts +6 -0
  445. package/dist/src/ui/components/messages/GeminiMessage.test.js +35 -0
  446. package/dist/src/ui/components/messages/GeminiMessage.test.js.map +1 -0
  447. package/dist/src/ui/components/messages/GeminiMessageContent.js +3 -1
  448. package/dist/src/ui/components/messages/GeminiMessageContent.js.map +1 -1
  449. package/dist/src/ui/components/messages/InfoMessage.js +1 -1
  450. package/dist/src/ui/components/messages/InfoMessage.js.map +1 -1
  451. package/dist/src/ui/components/messages/Todo.d.ts +7 -0
  452. package/dist/src/ui/components/messages/Todo.js +91 -0
  453. package/dist/src/ui/components/messages/Todo.js.map +1 -0
  454. package/dist/src/ui/components/messages/Todo.test.d.ts +6 -0
  455. package/dist/src/ui/components/messages/Todo.test.js +114 -0
  456. package/dist/src/ui/components/messages/Todo.test.js.map +1 -0
  457. package/dist/src/ui/components/messages/ToolConfirmationMessage.js +1 -1
  458. package/dist/src/ui/components/messages/ToolConfirmationMessage.js.map +1 -1
  459. package/dist/src/ui/components/messages/ToolGroupMessage.js +1 -1
  460. package/dist/src/ui/components/messages/ToolGroupMessage.js.map +1 -1
  461. package/dist/src/ui/components/messages/ToolGroupMessage.test.js +29 -15
  462. package/dist/src/ui/components/messages/ToolGroupMessage.test.js.map +1 -1
  463. package/dist/src/ui/components/messages/ToolMessage.js +8 -3
  464. package/dist/src/ui/components/messages/ToolMessage.js.map +1 -1
  465. package/dist/src/ui/components/messages/ToolMessage.test.js +2 -2
  466. package/dist/src/ui/components/messages/ToolMessage.test.js.map +1 -1
  467. package/dist/src/ui/components/messages/ToolMessageRawMarkdown.test.d.ts +6 -0
  468. package/dist/src/ui/components/messages/ToolMessageRawMarkdown.test.js +30 -0
  469. package/dist/src/ui/components/messages/ToolMessageRawMarkdown.test.js.map +1 -0
  470. package/dist/src/ui/components/messages/UserShellMessage.js +1 -1
  471. package/dist/src/ui/components/messages/UserShellMessage.js.map +1 -1
  472. package/dist/src/ui/components/messages/WarningMessage.js +2 -2
  473. package/dist/src/ui/components/messages/WarningMessage.js.map +1 -1
  474. package/dist/src/ui/components/shared/BaseSelectionList.test.js +34 -25
  475. package/dist/src/ui/components/shared/BaseSelectionList.test.js.map +1 -1
  476. package/dist/src/ui/components/shared/MaxSizedBox.test.js +43 -22
  477. package/dist/src/ui/components/shared/MaxSizedBox.test.js.map +1 -1
  478. package/dist/src/ui/components/shared/TextInput.d.ts +15 -0
  479. package/dist/src/ui/components/shared/TextInput.js +38 -0
  480. package/dist/src/ui/components/shared/TextInput.js.map +1 -0
  481. package/dist/src/ui/components/shared/TextInput.test.d.ts +6 -0
  482. package/dist/src/ui/components/shared/TextInput.test.js +242 -0
  483. package/dist/src/ui/components/shared/TextInput.test.js.map +1 -0
  484. package/dist/src/ui/components/shared/text-buffer.d.ts +9 -2
  485. package/dist/src/ui/components/shared/text-buffer.js +52 -14
  486. package/dist/src/ui/components/shared/text-buffer.js.map +1 -1
  487. package/dist/src/ui/components/shared/text-buffer.test.d.ts +6 -0
  488. package/dist/src/ui/components/shared/text-buffer.test.js +1761 -0
  489. package/dist/src/ui/components/shared/text-buffer.test.js.map +1 -0
  490. package/dist/src/ui/components/shared/vim-buffer-actions.test.d.ts +6 -0
  491. package/dist/src/ui/components/shared/vim-buffer-actions.test.js +951 -0
  492. package/dist/src/ui/components/shared/vim-buffer-actions.test.js.map +1 -0
  493. package/dist/src/ui/components/views/ChatList.test.js +7 -4
  494. package/dist/src/ui/components/views/ChatList.test.js.map +1 -1
  495. package/dist/src/ui/components/views/ExtensionsList.d.ts +7 -1
  496. package/dist/src/ui/components/views/ExtensionsList.js +12 -15
  497. package/dist/src/ui/components/views/ExtensionsList.js.map +1 -1
  498. package/dist/src/ui/components/views/ExtensionsList.test.js +43 -29
  499. package/dist/src/ui/components/views/ExtensionsList.test.js.map +1 -1
  500. package/dist/src/ui/components/views/McpStatus.d.ts +0 -1
  501. package/dist/src/ui/components/views/McpStatus.js +4 -4
  502. package/dist/src/ui/components/views/McpStatus.js.map +1 -1
  503. package/dist/src/ui/components/views/McpStatus.test.js +23 -17
  504. package/dist/src/ui/components/views/McpStatus.test.js.map +1 -1
  505. package/dist/src/ui/components/views/ToolsList.test.js +4 -4
  506. package/dist/src/ui/components/views/ToolsList.test.js.map +1 -1
  507. package/dist/src/ui/contexts/KeypressContext.d.ts +4 -2
  508. package/dist/src/ui/contexts/KeypressContext.js +635 -439
  509. package/dist/src/ui/contexts/KeypressContext.js.map +1 -1
  510. package/dist/src/ui/contexts/KeypressContext.test.js +634 -515
  511. package/dist/src/ui/contexts/KeypressContext.test.js.map +1 -1
  512. package/dist/src/ui/contexts/MouseContext.d.ts +21 -0
  513. package/dist/src/ui/contexts/MouseContext.js +89 -0
  514. package/dist/src/ui/contexts/MouseContext.js.map +1 -0
  515. package/dist/src/ui/contexts/MouseContext.test.d.ts +6 -0
  516. package/dist/src/ui/contexts/MouseContext.test.js +164 -0
  517. package/dist/src/ui/contexts/MouseContext.test.js.map +1 -0
  518. package/dist/src/ui/contexts/SessionContext.test.d.ts +6 -0
  519. package/dist/src/ui/contexts/SessionContext.test.js +195 -0
  520. package/dist/src/ui/contexts/SessionContext.test.js.map +1 -0
  521. package/dist/src/ui/contexts/UIActionsContext.d.ts +7 -4
  522. package/dist/src/ui/contexts/UIStateContext.d.ts +5 -3
  523. package/dist/src/ui/contexts/UIStateContext.js.map +1 -1
  524. package/dist/src/ui/hooks/atCommandProcessor.js +33 -11
  525. package/dist/src/ui/hooks/atCommandProcessor.js.map +1 -1
  526. package/dist/src/ui/hooks/atCommandProcessor.test.js +163 -64
  527. package/dist/src/ui/hooks/atCommandProcessor.test.js.map +1 -1
  528. package/dist/src/ui/hooks/shellCommandProcessor.js +0 -1
  529. package/dist/src/ui/hooks/shellCommandProcessor.js.map +1 -1
  530. package/dist/src/ui/hooks/shellCommandProcessor.test.js +64 -35
  531. package/dist/src/ui/hooks/shellCommandProcessor.test.js.map +1 -1
  532. package/dist/src/ui/hooks/slashCommandProcessor.js +2 -0
  533. package/dist/src/ui/hooks/slashCommandProcessor.js.map +1 -1
  534. package/dist/src/ui/hooks/slashCommandProcessor.test.d.ts +6 -0
  535. package/dist/src/ui/hooks/slashCommandProcessor.test.js +807 -0
  536. package/dist/src/ui/hooks/slashCommandProcessor.test.js.map +1 -0
  537. package/dist/src/ui/hooks/useAtCompletion.js +2 -2
  538. package/dist/src/ui/hooks/useAtCompletion.js.map +1 -1
  539. package/dist/src/ui/hooks/useAtCompletion.test.d.ts +6 -0
  540. package/dist/src/ui/hooks/useAtCompletion.test.js +396 -0
  541. package/dist/src/ui/hooks/useAtCompletion.test.js.map +1 -0
  542. package/dist/src/ui/hooks/useAutoAcceptIndicator.js +10 -0
  543. package/dist/src/ui/hooks/useAutoAcceptIndicator.js.map +1 -1
  544. package/dist/src/ui/hooks/useAutoAcceptIndicator.test.js +32 -2
  545. package/dist/src/ui/hooks/useAutoAcceptIndicator.test.js.map +1 -1
  546. package/dist/src/ui/hooks/useCommandCompletion.d.ts +1 -1
  547. package/dist/src/ui/hooks/useCommandCompletion.js +5 -3
  548. package/dist/src/ui/hooks/useCommandCompletion.js.map +1 -1
  549. package/dist/src/ui/hooks/useCommandCompletion.test.d.ts +6 -0
  550. package/dist/src/ui/hooks/useCommandCompletion.test.js +377 -0
  551. package/dist/src/ui/hooks/useCommandCompletion.test.js.map +1 -0
  552. package/dist/src/ui/hooks/useConsoleMessages.test.d.ts +6 -0
  553. package/dist/src/ui/hooks/useConsoleMessages.test.js +127 -0
  554. package/dist/src/ui/hooks/useConsoleMessages.test.js.map +1 -0
  555. package/dist/src/ui/hooks/useEditorSettings.test.js +40 -34
  556. package/dist/src/ui/hooks/useEditorSettings.test.js.map +1 -1
  557. package/dist/src/ui/hooks/useExtensionUpdates.d.ts +14 -4
  558. package/dist/src/ui/hooks/useExtensionUpdates.js +18 -11
  559. package/dist/src/ui/hooks/useExtensionUpdates.js.map +1 -1
  560. package/dist/src/ui/hooks/useExtensionUpdates.test.js +52 -35
  561. package/dist/src/ui/hooks/useExtensionUpdates.test.js.map +1 -1
  562. package/dist/src/ui/hooks/useFlickerDetector.test.js +9 -5
  563. package/dist/src/ui/hooks/useFlickerDetector.test.js.map +1 -1
  564. package/dist/src/ui/hooks/useFocus.test.d.ts +6 -0
  565. package/dist/src/ui/hooks/useFocus.test.js +131 -0
  566. package/dist/src/ui/hooks/useFocus.test.js.map +1 -0
  567. package/dist/src/ui/hooks/useFolderTrust.test.d.ts +6 -0
  568. package/dist/src/ui/hooks/useFolderTrust.test.js +188 -0
  569. package/dist/src/ui/hooks/useFolderTrust.test.js.map +1 -0
  570. package/dist/src/ui/hooks/useGeminiStream.js +119 -74
  571. package/dist/src/ui/hooks/useGeminiStream.js.map +1 -1
  572. package/dist/src/ui/hooks/useGeminiStream.test.d.ts +6 -0
  573. package/dist/src/ui/hooks/useGeminiStream.test.js +1820 -0
  574. package/dist/src/ui/hooks/useGeminiStream.test.js.map +1 -0
  575. package/dist/src/ui/hooks/useGitBranchName.js +4 -0
  576. package/dist/src/ui/hooks/useGitBranchName.js.map +1 -1
  577. package/dist/src/ui/hooks/useGitBranchName.test.js +46 -34
  578. package/dist/src/ui/hooks/useGitBranchName.test.js.map +1 -1
  579. package/dist/src/ui/hooks/useHistoryManager.test.js +2 -1
  580. package/dist/src/ui/hooks/useHistoryManager.test.js.map +1 -1
  581. package/dist/src/ui/hooks/useIdeTrustListener.test.js +40 -9
  582. package/dist/src/ui/hooks/useIdeTrustListener.test.js.map +1 -1
  583. package/dist/src/ui/hooks/useInputHistory.test.js +2 -1
  584. package/dist/src/ui/hooks/useInputHistory.test.js.map +1 -1
  585. package/dist/src/ui/hooks/useInputHistoryStore.js +2 -1
  586. package/dist/src/ui/hooks/useInputHistoryStore.js.map +1 -1
  587. package/dist/src/ui/hooks/useInputHistoryStore.test.js +2 -1
  588. package/dist/src/ui/hooks/useInputHistoryStore.test.js.map +1 -1
  589. package/dist/src/ui/hooks/useKeypress.test.d.ts +6 -0
  590. package/dist/src/ui/hooks/useKeypress.test.js +223 -0
  591. package/dist/src/ui/hooks/useKeypress.test.js.map +1 -0
  592. package/dist/src/ui/hooks/useLoadingIndicator.test.js +29 -6
  593. package/dist/src/ui/hooks/useLoadingIndicator.test.js.map +1 -1
  594. package/dist/src/ui/hooks/useMemoryMonitor.test.js +10 -5
  595. package/dist/src/ui/hooks/useMemoryMonitor.test.js.map +1 -1
  596. package/dist/src/ui/hooks/useMessageQueue.d.ts +1 -0
  597. package/dist/src/ui/hooks/useMessageQueue.js +14 -0
  598. package/dist/src/ui/hooks/useMessageQueue.js.map +1 -1
  599. package/dist/src/ui/hooks/useMessageQueue.test.js +173 -35
  600. package/dist/src/ui/hooks/useMessageQueue.test.js.map +1 -1
  601. package/dist/src/ui/hooks/useModelCommand.test.js +21 -11
  602. package/dist/src/ui/hooks/useModelCommand.test.js.map +1 -1
  603. package/dist/src/ui/hooks/useMouse.d.ts +17 -0
  604. package/dist/src/ui/hooks/useMouse.js +27 -0
  605. package/dist/src/ui/hooks/useMouse.js.map +1 -0
  606. package/dist/src/ui/hooks/useMouse.test.d.ts +6 -0
  607. package/dist/src/ui/hooks/useMouse.test.js +57 -0
  608. package/dist/src/ui/hooks/useMouse.test.js.map +1 -0
  609. package/dist/src/ui/hooks/usePermissionsModifyTrust.test.js +2 -2
  610. package/dist/src/ui/hooks/usePermissionsModifyTrust.test.js.map +1 -1
  611. package/dist/src/ui/hooks/usePhraseCycler.d.ts +1 -0
  612. package/dist/src/ui/hooks/usePhraseCycler.js +156 -5
  613. package/dist/src/ui/hooks/usePhraseCycler.js.map +1 -1
  614. package/dist/src/ui/hooks/usePhraseCycler.test.d.ts +6 -0
  615. package/dist/src/ui/hooks/usePhraseCycler.test.js +158 -0
  616. package/dist/src/ui/hooks/usePhraseCycler.test.js.map +1 -0
  617. package/dist/src/ui/hooks/usePrivacySettings.test.js +26 -6
  618. package/dist/src/ui/hooks/usePrivacySettings.test.js.map +1 -1
  619. package/dist/src/ui/hooks/usePromptCompletion.js +2 -2
  620. package/dist/src/ui/hooks/usePromptCompletion.js.map +1 -1
  621. package/dist/src/ui/hooks/useQuotaAndFallback.js +13 -14
  622. package/dist/src/ui/hooks/useQuotaAndFallback.js.map +1 -1
  623. package/dist/src/ui/hooks/useQuotaAndFallback.test.js +55 -48
  624. package/dist/src/ui/hooks/useQuotaAndFallback.test.js.map +1 -1
  625. package/dist/src/ui/hooks/useReactToolScheduler.d.ts +8 -1
  626. package/dist/src/ui/hooks/useReactToolScheduler.js +61 -36
  627. package/dist/src/ui/hooks/useReactToolScheduler.js.map +1 -1
  628. package/dist/src/ui/hooks/useReactToolScheduler.test.d.ts +6 -0
  629. package/dist/src/ui/hooks/useReactToolScheduler.test.js +65 -0
  630. package/dist/src/ui/hooks/useReactToolScheduler.test.js.map +1 -0
  631. package/dist/src/ui/hooks/useReverseSearchCompletion.test.js +2 -2
  632. package/dist/src/ui/hooks/useReverseSearchCompletion.test.js.map +1 -1
  633. package/dist/src/ui/hooks/useSelectionList.js +5 -4
  634. package/dist/src/ui/hooks/useSelectionList.js.map +1 -1
  635. package/dist/src/ui/hooks/useSelectionList.test.js +272 -183
  636. package/dist/src/ui/hooks/useSelectionList.test.js.map +1 -1
  637. package/dist/src/ui/hooks/useShellHistory.test.js +52 -20
  638. package/dist/src/ui/hooks/useShellHistory.test.js.map +1 -1
  639. package/dist/src/ui/hooks/useShowMemoryCommand.d.ts +1 -1
  640. package/dist/src/ui/hooks/useShowMemoryCommand.js +4 -3
  641. package/dist/src/ui/hooks/useShowMemoryCommand.js.map +1 -1
  642. package/dist/src/ui/hooks/useSlashCompletion.js +20 -8
  643. package/dist/src/ui/hooks/useSlashCompletion.js.map +1 -1
  644. package/dist/src/ui/hooks/useSlashCompletion.test.js +275 -137
  645. package/dist/src/ui/hooks/useSlashCompletion.test.js.map +1 -1
  646. package/dist/src/ui/hooks/useThemeCommand.d.ts +2 -1
  647. package/dist/src/ui/hooks/useThemeCommand.js +6 -0
  648. package/dist/src/ui/hooks/useThemeCommand.js.map +1 -1
  649. package/dist/src/ui/hooks/useTimer.test.js +43 -14
  650. package/dist/src/ui/hooks/useTimer.test.js.map +1 -1
  651. package/dist/src/ui/hooks/useToolScheduler.test.js +229 -242
  652. package/dist/src/ui/hooks/useToolScheduler.test.js.map +1 -1
  653. package/dist/src/ui/hooks/vim.js +2 -1
  654. package/dist/src/ui/hooks/vim.js.map +1 -1
  655. package/dist/src/ui/hooks/vim.test.d.ts +6 -0
  656. package/dist/src/ui/hooks/vim.test.js +1269 -0
  657. package/dist/src/ui/hooks/vim.test.js.map +1 -0
  658. package/dist/src/ui/keyMatchers.test.js +39 -6
  659. package/dist/src/ui/keyMatchers.test.js.map +1 -1
  660. package/dist/src/ui/state/extensions.d.ts +1 -0
  661. package/dist/src/ui/state/extensions.js +1 -0
  662. package/dist/src/ui/state/extensions.js.map +1 -1
  663. package/dist/src/ui/themes/ansi-light.js +1 -0
  664. package/dist/src/ui/themes/ansi-light.js.map +1 -1
  665. package/dist/src/ui/themes/ansi.js +1 -0
  666. package/dist/src/ui/themes/ansi.js.map +1 -1
  667. package/dist/src/ui/themes/atom-one-dark.js +2 -0
  668. package/dist/src/ui/themes/atom-one-dark.js.map +1 -1
  669. package/dist/src/ui/themes/ayu-light.js +2 -0
  670. package/dist/src/ui/themes/ayu-light.js.map +1 -1
  671. package/dist/src/ui/themes/ayu.js +2 -0
  672. package/dist/src/ui/themes/ayu.js.map +1 -1
  673. package/dist/src/ui/themes/color-utils.d.ts +1 -0
  674. package/dist/src/ui/themes/color-utils.js +8 -1
  675. package/dist/src/ui/themes/color-utils.js.map +1 -1
  676. package/dist/src/ui/themes/color-utils.test.js +13 -1
  677. package/dist/src/ui/themes/color-utils.test.js.map +1 -1
  678. package/dist/src/ui/themes/dracula.js +2 -0
  679. package/dist/src/ui/themes/dracula.js.map +1 -1
  680. package/dist/src/ui/themes/github-dark.js +2 -0
  681. package/dist/src/ui/themes/github-dark.js.map +1 -1
  682. package/dist/src/ui/themes/github-light.js +2 -0
  683. package/dist/src/ui/themes/github-light.js.map +1 -1
  684. package/dist/src/ui/themes/googlecode.js +2 -0
  685. package/dist/src/ui/themes/googlecode.js.map +1 -1
  686. package/dist/src/ui/themes/no-color.js +3 -0
  687. package/dist/src/ui/themes/no-color.js.map +1 -1
  688. package/dist/src/ui/themes/semantic-tokens.d.ts +2 -0
  689. package/dist/src/ui/themes/semantic-tokens.js +6 -0
  690. package/dist/src/ui/themes/semantic-tokens.js.map +1 -1
  691. package/dist/src/ui/themes/shades-of-purple.js +2 -0
  692. package/dist/src/ui/themes/shades-of-purple.js.map +1 -1
  693. package/dist/src/ui/themes/theme-manager.js +8 -7
  694. package/dist/src/ui/themes/theme-manager.js.map +1 -1
  695. package/dist/src/ui/themes/theme.d.ts +3 -0
  696. package/dist/src/ui/themes/theme.js +14 -3
  697. package/dist/src/ui/themes/theme.js.map +1 -1
  698. package/dist/src/ui/themes/theme.test.d.ts +6 -0
  699. package/dist/src/ui/themes/theme.test.js +151 -0
  700. package/dist/src/ui/themes/theme.test.js.map +1 -0
  701. package/dist/src/ui/themes/xcode.js +2 -0
  702. package/dist/src/ui/themes/xcode.js.map +1 -1
  703. package/dist/src/ui/types.d.ts +3 -2
  704. package/dist/src/ui/types.js +2 -0
  705. package/dist/src/ui/types.js.map +1 -1
  706. package/dist/src/ui/utils/CodeColorizer.d.ts +1 -1
  707. package/dist/src/ui/utils/CodeColorizer.js +6 -3
  708. package/dist/src/ui/utils/CodeColorizer.js.map +1 -1
  709. package/dist/src/ui/utils/InlineMarkdownRenderer.d.ts +1 -0
  710. package/dist/src/ui/utils/InlineMarkdownRenderer.js +11 -10
  711. package/dist/src/ui/utils/InlineMarkdownRenderer.js.map +1 -1
  712. package/dist/src/ui/utils/MarkdownDisplay.d.ts +1 -0
  713. package/dist/src/ui/utils/MarkdownDisplay.js +19 -10
  714. package/dist/src/ui/utils/MarkdownDisplay.js.map +1 -1
  715. package/dist/src/ui/utils/clipboardUtils.js +2 -2
  716. package/dist/src/ui/utils/clipboardUtils.js.map +1 -1
  717. package/dist/src/ui/utils/commandUtils.js +20 -3
  718. package/dist/src/ui/utils/commandUtils.js.map +1 -1
  719. package/dist/src/ui/utils/commandUtils.test.js +61 -6
  720. package/dist/src/ui/utils/commandUtils.test.js.map +1 -1
  721. package/dist/src/ui/utils/computeStats.js +5 -2
  722. package/dist/src/ui/utils/computeStats.js.map +1 -1
  723. package/dist/src/ui/utils/computeStats.test.d.ts +6 -0
  724. package/dist/src/ui/utils/computeStats.test.js +262 -0
  725. package/dist/src/ui/utils/computeStats.test.js.map +1 -0
  726. package/dist/src/ui/utils/input.d.ts +17 -0
  727. package/dist/src/ui/utils/input.js +51 -0
  728. package/dist/src/ui/utils/input.js.map +1 -0
  729. package/dist/src/ui/utils/input.test.d.ts +6 -0
  730. package/dist/src/ui/utils/input.test.js +44 -0
  731. package/dist/src/ui/utils/input.test.js.map +1 -0
  732. package/dist/src/ui/utils/kittyProtocolDetector.js +13 -4
  733. package/dist/src/ui/utils/kittyProtocolDetector.js.map +1 -1
  734. package/dist/src/ui/utils/mouse.d.ts +31 -0
  735. package/dist/src/ui/utils/mouse.js +164 -0
  736. package/dist/src/ui/utils/mouse.js.map +1 -0
  737. package/dist/src/ui/utils/mouse.test.d.ts +6 -0
  738. package/dist/src/ui/utils/mouse.test.js +131 -0
  739. package/dist/src/ui/utils/mouse.test.js.map +1 -0
  740. package/dist/src/ui/utils/terminalSetup.js +3 -2
  741. package/dist/src/ui/utils/terminalSetup.js.map +1 -1
  742. package/dist/src/ui/utils/textOutput.d.ts +25 -0
  743. package/dist/src/ui/utils/textOutput.js +49 -0
  744. package/dist/src/ui/utils/textOutput.js.map +1 -0
  745. package/dist/src/ui/utils/textOutput.test.d.ts +6 -0
  746. package/dist/src/ui/utils/textOutput.test.js +79 -0
  747. package/dist/src/ui/utils/textOutput.test.js.map +1 -0
  748. package/dist/src/ui/utils/updateCheck.d.ts +9 -2
  749. package/dist/src/ui/utils/updateCheck.js +38 -30
  750. package/dist/src/ui/utils/updateCheck.js.map +1 -1
  751. package/dist/src/ui/utils/updateCheck.test.js +48 -59
  752. package/dist/src/ui/utils/updateCheck.test.js.map +1 -1
  753. package/dist/src/utils/cleanup.test.d.ts +6 -0
  754. package/dist/src/utils/cleanup.test.js +49 -0
  755. package/dist/src/utils/cleanup.test.js.map +1 -0
  756. package/dist/src/utils/commentJson.js +2 -2
  757. package/dist/src/utils/commentJson.js.map +1 -1
  758. package/dist/src/utils/commentJson.test.js +7 -6
  759. package/dist/src/utils/commentJson.test.js.map +1 -1
  760. package/dist/src/utils/envVarResolver.d.ts +2 -2
  761. package/dist/src/utils/envVarResolver.js +10 -7
  762. package/dist/src/utils/envVarResolver.js.map +1 -1
  763. package/dist/src/utils/errors.d.ts +1 -0
  764. package/dist/src/utils/errors.js +66 -5
  765. package/dist/src/utils/errors.js.map +1 -1
  766. package/dist/src/utils/events.d.ts +11 -2
  767. package/dist/src/utils/events.js +1 -0
  768. package/dist/src/utils/events.js.map +1 -1
  769. package/dist/src/utils/gitUtils.js +3 -2
  770. package/dist/src/utils/gitUtils.js.map +1 -1
  771. package/dist/src/utils/handleAutoUpdate.js +9 -3
  772. package/dist/src/utils/handleAutoUpdate.js.map +1 -1
  773. package/dist/src/utils/handleAutoUpdate.test.d.ts +6 -0
  774. package/dist/src/utils/handleAutoUpdate.test.js +225 -0
  775. package/dist/src/utils/handleAutoUpdate.test.js.map +1 -0
  776. package/dist/src/utils/installationInfo.js +2 -2
  777. package/dist/src/utils/installationInfo.js.map +1 -1
  778. package/dist/src/utils/installationInfo.test.js +8 -4
  779. package/dist/src/utils/installationInfo.test.js.map +1 -1
  780. package/dist/src/utils/readStdin.js +2 -1
  781. package/dist/src/utils/readStdin.js.map +1 -1
  782. package/dist/src/utils/sandbox-macos-permissive-open.sb +2 -0
  783. package/dist/src/utils/sandbox.js +28 -30
  784. package/dist/src/utils/sandbox.js.map +1 -1
  785. package/dist/src/utils/sessionCleanup.js +4 -4
  786. package/dist/src/utils/sessionCleanup.js.map +1 -1
  787. package/dist/src/utils/startupWarnings.test.d.ts +6 -0
  788. package/dist/src/utils/startupWarnings.test.js +61 -0
  789. package/dist/src/utils/startupWarnings.test.js.map +1 -0
  790. package/dist/src/utils/version.js +6 -2
  791. package/dist/src/utils/version.js.map +1 -1
  792. package/dist/src/validateNonInterActiveAuth.js +2 -2
  793. package/dist/src/validateNonInterActiveAuth.js.map +1 -1
  794. package/dist/src/zed-integration/acp.js +2 -1
  795. package/dist/src/zed-integration/acp.js.map +1 -1
  796. package/dist/src/zed-integration/schema.d.ts +4 -4
  797. package/dist/src/zed-integration/zedIntegration.d.ts +2 -2
  798. package/dist/src/zed-integration/zedIntegration.js +16 -25
  799. package/dist/src/zed-integration/zedIntegration.js.map +1 -1
  800. package/dist/tsconfig.tsbuildinfo +1 -1
  801. package/package.json +17 -17
  802. package/dist/src/config/policy.test.js +0 -336
  803. package/dist/src/config/policy.test.js.map +0 -1
  804. package/dist/src/ui/components/WorkspaceMigrationDialog.d.ts +0 -11
  805. package/dist/src/ui/components/WorkspaceMigrationDialog.js +0 -44
  806. package/dist/src/ui/components/WorkspaceMigrationDialog.js.map +0 -1
  807. package/dist/src/ui/hooks/useWorkspaceMigration.d.ts +0 -13
  808. package/dist/src/ui/hooks/useWorkspaceMigration.js +0 -59
  809. package/dist/src/ui/hooks/useWorkspaceMigration.js.map +0 -1
  810. package/dist/src/utils/package.d.ts +0 -12
  811. package/dist/src/utils/package.js +0 -24
  812. package/dist/src/utils/package.js.map +0 -1
  813. /package/dist/src/{config/policy.test.d.ts → commands/extensions/examples/mcp-server/example.d.ts} +0 -0
@@ -0,0 +1,1972 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
7
+ import * as os from 'node:os';
8
+ import * as path from 'node:path';
9
+ import { DEFAULT_FILE_FILTERING_OPTIONS, DEFAULT_GEMINI_MODEL, DEFAULT_GEMINI_MODEL_AUTO, OutputFormat, SHELL_TOOL_NAME, WRITE_FILE_TOOL_NAME, EDIT_TOOL_NAME, } from '@google/gemini-cli-core';
10
+ import { loadCliConfig, parseArguments } from './config.js';
11
+ import * as ServerConfig from '@google/gemini-cli-core';
12
+ import { isWorkspaceTrusted } from './trustedFolders.js';
13
+ import { ExtensionManager } from './extension-manager.js';
14
+ vi.mock('./trustedFolders.js', () => ({
15
+ isWorkspaceTrusted: vi
16
+ .fn()
17
+ .mockReturnValue({ isTrusted: true, source: 'file' }), // Default to trusted
18
+ }));
19
+ vi.mock('./sandboxConfig.js', () => ({
20
+ loadSandboxConfig: vi.fn().mockResolvedValue(undefined),
21
+ }));
22
+ vi.mock('fs', async (importOriginal) => {
23
+ const actualFs = await importOriginal();
24
+ const pathMod = await import('node:path');
25
+ const mockHome = '/mock/home/user';
26
+ const MOCK_CWD1 = process.cwd();
27
+ const MOCK_CWD2 = pathMod.resolve(pathMod.sep, 'home', 'user', 'project');
28
+ const mockPaths = new Set([
29
+ MOCK_CWD1,
30
+ MOCK_CWD2,
31
+ pathMod.resolve(pathMod.sep, 'cli', 'path1'),
32
+ pathMod.resolve(pathMod.sep, 'settings', 'path1'),
33
+ pathMod.join(mockHome, 'settings', 'path2'),
34
+ pathMod.join(MOCK_CWD2, 'cli', 'path2'),
35
+ pathMod.join(MOCK_CWD2, 'settings', 'path3'),
36
+ ]);
37
+ return {
38
+ ...actualFs,
39
+ mkdirSync: vi.fn(),
40
+ writeFileSync: vi.fn(),
41
+ existsSync: vi.fn((p) => mockPaths.has(p.toString())),
42
+ statSync: vi.fn((p) => {
43
+ if (mockPaths.has(p.toString())) {
44
+ return { isDirectory: () => true };
45
+ }
46
+ return actualFs.statSync(p);
47
+ }),
48
+ realpathSync: vi.fn((p) => p),
49
+ };
50
+ });
51
+ vi.mock('os', async (importOriginal) => {
52
+ const actualOs = await importOriginal();
53
+ return {
54
+ ...actualOs,
55
+ homedir: vi.fn(() => '/mock/home/user'),
56
+ };
57
+ });
58
+ vi.mock('open', () => ({
59
+ default: vi.fn(),
60
+ }));
61
+ vi.mock('read-package-up', () => ({
62
+ readPackageUp: vi.fn(() => Promise.resolve({ packageJson: { version: 'test-version' } })),
63
+ }));
64
+ vi.mock('@google/gemini-cli-core', async () => {
65
+ const actualServer = await vi.importActual('@google/gemini-cli-core');
66
+ return {
67
+ ...actualServer,
68
+ IdeClient: {
69
+ getInstance: vi.fn().mockResolvedValue({
70
+ getConnectionStatus: vi.fn(),
71
+ initialize: vi.fn(),
72
+ shutdown: vi.fn(),
73
+ }),
74
+ },
75
+ loadEnvironment: vi.fn(),
76
+ loadServerHierarchicalMemory: vi.fn((cwd, dirs, debug, fileService, extensionLoader, _maxDirs) => {
77
+ const extensionPaths = extensionLoader
78
+ .getExtensions()
79
+ .flatMap((e) => e.contextFiles);
80
+ return Promise.resolve({
81
+ memoryContent: extensionPaths.join(',') || '',
82
+ fileCount: extensionPaths?.length || 0,
83
+ });
84
+ }),
85
+ DEFAULT_MEMORY_FILE_FILTERING_OPTIONS: {
86
+ respectGitIgnore: false,
87
+ respectGeminiIgnore: true,
88
+ },
89
+ DEFAULT_FILE_FILTERING_OPTIONS: {
90
+ respectGitIgnore: true,
91
+ respectGeminiIgnore: true,
92
+ },
93
+ };
94
+ });
95
+ vi.mock('./extension-manager.js');
96
+ // Global setup to ensure clean environment for all tests in this file
97
+ const originalArgv = process.argv;
98
+ const originalGeminiModel = process.env['GEMINI_MODEL'];
99
+ beforeEach(() => {
100
+ delete process.env['GEMINI_MODEL'];
101
+ });
102
+ afterEach(() => {
103
+ process.argv = originalArgv;
104
+ if (originalGeminiModel !== undefined) {
105
+ process.env['GEMINI_MODEL'] = originalGeminiModel;
106
+ }
107
+ else {
108
+ delete process.env['GEMINI_MODEL'];
109
+ }
110
+ });
111
+ describe('parseArguments', () => {
112
+ it('should throw an error when both --prompt and --prompt-interactive are used together', async () => {
113
+ process.argv = [
114
+ 'node',
115
+ 'script.js',
116
+ '--prompt',
117
+ 'test prompt',
118
+ '--prompt-interactive',
119
+ 'interactive prompt',
120
+ ];
121
+ const mockExit = vi.spyOn(process, 'exit').mockImplementation(() => {
122
+ throw new Error('process.exit called');
123
+ });
124
+ const mockConsoleError = vi
125
+ .spyOn(console, 'error')
126
+ .mockImplementation(() => { });
127
+ await expect(parseArguments({})).rejects.toThrow('process.exit called');
128
+ expect(mockConsoleError).toHaveBeenCalledWith(expect.stringContaining('Cannot use both --prompt (-p) and --prompt-interactive (-i) together'));
129
+ mockExit.mockRestore();
130
+ mockConsoleError.mockRestore();
131
+ });
132
+ it('should throw an error when using short flags -p and -i together', async () => {
133
+ process.argv = [
134
+ 'node',
135
+ 'script.js',
136
+ '-p',
137
+ 'test prompt',
138
+ '-i',
139
+ 'interactive prompt',
140
+ ];
141
+ const mockExit = vi.spyOn(process, 'exit').mockImplementation(() => {
142
+ throw new Error('process.exit called');
143
+ });
144
+ const mockConsoleError = vi
145
+ .spyOn(console, 'error')
146
+ .mockImplementation(() => { });
147
+ await expect(parseArguments({})).rejects.toThrow('process.exit called');
148
+ expect(mockConsoleError).toHaveBeenCalledWith(expect.stringContaining('Cannot use both --prompt (-p) and --prompt-interactive (-i) together'));
149
+ mockExit.mockRestore();
150
+ mockConsoleError.mockRestore();
151
+ });
152
+ it('should allow --prompt without --prompt-interactive', async () => {
153
+ process.argv = ['node', 'script.js', '--prompt', 'test prompt'];
154
+ const argv = await parseArguments({});
155
+ expect(argv.prompt).toBe('test prompt');
156
+ expect(argv.promptInteractive).toBeUndefined();
157
+ });
158
+ it('should allow --prompt-interactive without --prompt', async () => {
159
+ process.argv = [
160
+ 'node',
161
+ 'script.js',
162
+ '--prompt-interactive',
163
+ 'interactive prompt',
164
+ ];
165
+ const argv = await parseArguments({});
166
+ expect(argv.promptInteractive).toBe('interactive prompt');
167
+ expect(argv.prompt).toBeUndefined();
168
+ });
169
+ it('should allow -i flag as alias for --prompt-interactive', async () => {
170
+ process.argv = ['node', 'script.js', '-i', 'interactive prompt'];
171
+ const argv = await parseArguments({});
172
+ expect(argv.promptInteractive).toBe('interactive prompt');
173
+ expect(argv.prompt).toBeUndefined();
174
+ });
175
+ it('should convert positional query argument to prompt by default', async () => {
176
+ process.argv = ['node', 'script.js', 'Hi Gemini'];
177
+ const argv = await parseArguments({});
178
+ expect(argv.query).toBe('Hi Gemini');
179
+ expect(argv.prompt).toBe('Hi Gemini');
180
+ expect(argv.promptInteractive).toBeUndefined();
181
+ });
182
+ it('should map @path to prompt (one-shot) when it starts with @', async () => {
183
+ process.argv = ['node', 'script.js', '@path ./file.md'];
184
+ const argv = await parseArguments({});
185
+ expect(argv.query).toBe('@path ./file.md');
186
+ expect(argv.prompt).toBe('@path ./file.md');
187
+ expect(argv.promptInteractive).toBeUndefined();
188
+ });
189
+ it('should map @path to prompt even when config flags are present', async () => {
190
+ // @path queries should now go to one-shot mode regardless of other flags
191
+ process.argv = [
192
+ 'node',
193
+ 'script.js',
194
+ '@path',
195
+ './file.md',
196
+ '--model',
197
+ 'gemini-2.5-pro',
198
+ ];
199
+ const argv = await parseArguments({});
200
+ expect(argv.query).toBe('@path ./file.md');
201
+ expect(argv.prompt).toBe('@path ./file.md'); // Should map to one-shot
202
+ expect(argv.promptInteractive).toBeUndefined();
203
+ expect(argv.model).toBe('gemini-2.5-pro');
204
+ });
205
+ it('maps unquoted positional @path + arg to prompt (one-shot)', async () => {
206
+ // Simulate: gemini @path ./file.md
207
+ process.argv = ['node', 'script.js', '@path', './file.md'];
208
+ const argv = await parseArguments({});
209
+ // After normalization, query is a single string
210
+ expect(argv.query).toBe('@path ./file.md');
211
+ // And it's mapped to one-shot prompt when no -p/-i flags are set
212
+ expect(argv.prompt).toBe('@path ./file.md');
213
+ expect(argv.promptInteractive).toBeUndefined();
214
+ });
215
+ it('should handle multiple @path arguments in a single command (one-shot)', async () => {
216
+ // Simulate: gemini @path ./file1.md @path ./file2.md
217
+ process.argv = [
218
+ 'node',
219
+ 'script.js',
220
+ '@path',
221
+ './file1.md',
222
+ '@path',
223
+ './file2.md',
224
+ ];
225
+ const argv = await parseArguments({});
226
+ // After normalization, all arguments are joined with spaces
227
+ expect(argv.query).toBe('@path ./file1.md @path ./file2.md');
228
+ // And it's mapped to one-shot prompt
229
+ expect(argv.prompt).toBe('@path ./file1.md @path ./file2.md');
230
+ expect(argv.promptInteractive).toBeUndefined();
231
+ });
232
+ it('should handle mixed quoted and unquoted @path arguments (one-shot)', async () => {
233
+ // Simulate: gemini "@path ./file1.md" @path ./file2.md "additional text"
234
+ process.argv = [
235
+ 'node',
236
+ 'script.js',
237
+ '@path ./file1.md',
238
+ '@path',
239
+ './file2.md',
240
+ 'additional text',
241
+ ];
242
+ const argv = await parseArguments({});
243
+ // After normalization, all arguments are joined with spaces
244
+ expect(argv.query).toBe('@path ./file1.md @path ./file2.md additional text');
245
+ // And it's mapped to one-shot prompt
246
+ expect(argv.prompt).toBe('@path ./file1.md @path ./file2.md additional text');
247
+ expect(argv.promptInteractive).toBeUndefined();
248
+ });
249
+ it('should map @path to prompt with ambient flags (debug)', async () => {
250
+ // Ambient flags like debug should NOT affect routing
251
+ process.argv = ['node', 'script.js', '@path', './file.md', '--debug'];
252
+ const argv = await parseArguments({});
253
+ expect(argv.query).toBe('@path ./file.md');
254
+ expect(argv.prompt).toBe('@path ./file.md'); // Should map to one-shot
255
+ expect(argv.promptInteractive).toBeUndefined();
256
+ expect(argv.debug).toBe(true);
257
+ });
258
+ it('should map any @command to prompt (one-shot)', async () => {
259
+ // Test that all @commands now go to one-shot mode
260
+ const testCases = [
261
+ '@path ./file.md',
262
+ '@include src/',
263
+ '@search pattern',
264
+ '@web query',
265
+ '@git status',
266
+ ];
267
+ for (const testQuery of testCases) {
268
+ process.argv = ['node', 'script.js', testQuery];
269
+ const argv = await parseArguments({});
270
+ expect(argv.query).toBe(testQuery);
271
+ expect(argv.prompt).toBe(testQuery);
272
+ expect(argv.promptInteractive).toBeUndefined();
273
+ }
274
+ });
275
+ it('should handle @command with leading whitespace', async () => {
276
+ // Test that trim() + routing handles leading whitespace correctly
277
+ process.argv = ['node', 'script.js', ' @path ./file.md'];
278
+ const argv = await parseArguments({});
279
+ expect(argv.query).toBe(' @path ./file.md');
280
+ expect(argv.prompt).toBe(' @path ./file.md');
281
+ expect(argv.promptInteractive).toBeUndefined();
282
+ });
283
+ it('should throw an error when both --yolo and --approval-mode are used together', async () => {
284
+ process.argv = [
285
+ 'node',
286
+ 'script.js',
287
+ '--yolo',
288
+ '--approval-mode',
289
+ 'default',
290
+ ];
291
+ const mockExit = vi.spyOn(process, 'exit').mockImplementation(() => {
292
+ throw new Error('process.exit called');
293
+ });
294
+ const mockConsoleError = vi
295
+ .spyOn(console, 'error')
296
+ .mockImplementation(() => { });
297
+ await expect(parseArguments({})).rejects.toThrow('process.exit called');
298
+ expect(mockConsoleError).toHaveBeenCalledWith(expect.stringContaining('Cannot use both --yolo (-y) and --approval-mode together. Use --approval-mode=yolo instead.'));
299
+ mockExit.mockRestore();
300
+ mockConsoleError.mockRestore();
301
+ });
302
+ it('should throw an error when using short flags -y and --approval-mode together', async () => {
303
+ process.argv = ['node', 'script.js', '-y', '--approval-mode', 'yolo'];
304
+ const mockExit = vi.spyOn(process, 'exit').mockImplementation(() => {
305
+ throw new Error('process.exit called');
306
+ });
307
+ const mockConsoleError = vi
308
+ .spyOn(console, 'error')
309
+ .mockImplementation(() => { });
310
+ await expect(parseArguments({})).rejects.toThrow('process.exit called');
311
+ expect(mockConsoleError).toHaveBeenCalledWith(expect.stringContaining('Cannot use both --yolo (-y) and --approval-mode together. Use --approval-mode=yolo instead.'));
312
+ mockExit.mockRestore();
313
+ mockConsoleError.mockRestore();
314
+ });
315
+ it('should allow --approval-mode without --yolo', async () => {
316
+ process.argv = ['node', 'script.js', '--approval-mode', 'auto_edit'];
317
+ const argv = await parseArguments({});
318
+ expect(argv.approvalMode).toBe('auto_edit');
319
+ expect(argv.yolo).toBe(false);
320
+ });
321
+ it('should allow --yolo without --approval-mode', async () => {
322
+ process.argv = ['node', 'script.js', '--yolo'];
323
+ const argv = await parseArguments({});
324
+ expect(argv.yolo).toBe(true);
325
+ expect(argv.approvalMode).toBeUndefined();
326
+ });
327
+ it('should reject invalid --approval-mode values', async () => {
328
+ process.argv = ['node', 'script.js', '--approval-mode', 'invalid'];
329
+ const mockExit = vi.spyOn(process, 'exit').mockImplementation(() => {
330
+ throw new Error('process.exit called');
331
+ });
332
+ const mockConsoleError = vi
333
+ .spyOn(console, 'error')
334
+ .mockImplementation(() => { });
335
+ await expect(parseArguments({})).rejects.toThrow('process.exit called');
336
+ expect(mockConsoleError).toHaveBeenCalledWith(expect.stringContaining('Invalid values:'));
337
+ mockExit.mockRestore();
338
+ mockConsoleError.mockRestore();
339
+ });
340
+ it('should support comma-separated values for --allowed-tools', async () => {
341
+ process.argv = [
342
+ 'node',
343
+ 'script.js',
344
+ '--allowed-tools',
345
+ 'read_file,ShellTool(git status)',
346
+ ];
347
+ const argv = await parseArguments({});
348
+ expect(argv.allowedTools).toEqual(['read_file', 'ShellTool(git status)']);
349
+ });
350
+ it('should support comma-separated values for --allowed-mcp-server-names', async () => {
351
+ process.argv = [
352
+ 'node',
353
+ 'script.js',
354
+ '--allowed-mcp-server-names',
355
+ 'server1,server2',
356
+ ];
357
+ const argv = await parseArguments({});
358
+ expect(argv.allowedMcpServerNames).toEqual(['server1', 'server2']);
359
+ });
360
+ it('should support comma-separated values for --extensions', async () => {
361
+ process.argv = ['node', 'script.js', '--extensions', 'ext1,ext2'];
362
+ const argv = await parseArguments({});
363
+ expect(argv.extensions).toEqual(['ext1', 'ext2']);
364
+ });
365
+ it('should correctly parse positional arguments when flags with arguments are present', async () => {
366
+ process.argv = [
367
+ 'node',
368
+ 'script.js',
369
+ '--model',
370
+ 'test-model-string',
371
+ 'my-positional-arg',
372
+ ];
373
+ const argv = await parseArguments({});
374
+ expect(argv.model).toBe('test-model-string');
375
+ expect(argv.query).toBe('my-positional-arg');
376
+ });
377
+ it('should handle long positional prompts with multiple flags', async () => {
378
+ process.argv = [
379
+ 'node',
380
+ 'script.js',
381
+ '-e',
382
+ 'none',
383
+ '--approval-mode=auto_edit',
384
+ '--allowed-tools=ShellTool',
385
+ '--allowed-tools=ShellTool(whoami)',
386
+ '--allowed-tools=ShellTool(wc)',
387
+ 'Use whoami to write a poem in file poem.md about my username in pig latin and use wc to tell me how many lines are in the poem you wrote.',
388
+ ];
389
+ const argv = await parseArguments({});
390
+ expect(argv.extensions).toEqual(['none']);
391
+ expect(argv.approvalMode).toBe('auto_edit');
392
+ expect(argv.allowedTools).toEqual([
393
+ 'ShellTool',
394
+ 'ShellTool(whoami)',
395
+ 'ShellTool(wc)',
396
+ ]);
397
+ expect(argv.query).toBe('Use whoami to write a poem in file poem.md about my username in pig latin and use wc to tell me how many lines are in the poem you wrote.');
398
+ });
399
+ });
400
+ describe('loadCliConfig', () => {
401
+ beforeEach(() => {
402
+ vi.resetAllMocks();
403
+ vi.mocked(os.homedir).mockReturnValue('/mock/home/user');
404
+ vi.stubEnv('GEMINI_API_KEY', 'test-api-key');
405
+ vi.spyOn(ExtensionManager.prototype, 'getExtensions').mockReturnValue([]);
406
+ });
407
+ afterEach(() => {
408
+ vi.unstubAllEnvs();
409
+ vi.restoreAllMocks();
410
+ });
411
+ describe('Proxy configuration', () => {
412
+ const originalProxyEnv = {};
413
+ const proxyEnvVars = [
414
+ 'HTTP_PROXY',
415
+ 'HTTPS_PROXY',
416
+ 'http_proxy',
417
+ 'https_proxy',
418
+ ];
419
+ beforeEach(() => {
420
+ for (const key of proxyEnvVars) {
421
+ originalProxyEnv[key] = process.env[key];
422
+ delete process.env[key];
423
+ }
424
+ });
425
+ afterEach(() => {
426
+ for (const key of proxyEnvVars) {
427
+ if (originalProxyEnv[key]) {
428
+ process.env[key] = originalProxyEnv[key];
429
+ }
430
+ else {
431
+ delete process.env[key];
432
+ }
433
+ }
434
+ });
435
+ it(`should leave proxy to empty by default`, async () => {
436
+ process.argv = ['node', 'script.js'];
437
+ const argv = await parseArguments({});
438
+ const settings = {};
439
+ const config = await loadCliConfig(settings, 'test-session', argv);
440
+ expect(config.getProxy()).toBeFalsy();
441
+ });
442
+ const proxy_url = 'http://localhost:7890';
443
+ const testCases = [
444
+ {
445
+ input: {
446
+ env_name: 'https_proxy',
447
+ proxy_url,
448
+ },
449
+ expected: proxy_url,
450
+ },
451
+ {
452
+ input: {
453
+ env_name: 'http_proxy',
454
+ proxy_url,
455
+ },
456
+ expected: proxy_url,
457
+ },
458
+ {
459
+ input: {
460
+ env_name: 'HTTPS_PROXY',
461
+ proxy_url,
462
+ },
463
+ expected: proxy_url,
464
+ },
465
+ {
466
+ input: {
467
+ env_name: 'HTTP_PROXY',
468
+ proxy_url,
469
+ },
470
+ expected: proxy_url,
471
+ },
472
+ ];
473
+ testCases.forEach(({ input, expected }) => {
474
+ it(`should set proxy to ${expected} according to environment variable [${input.env_name}]`, async () => {
475
+ vi.stubEnv(input.env_name, input.proxy_url);
476
+ process.argv = ['node', 'script.js'];
477
+ const argv = await parseArguments({});
478
+ const settings = {};
479
+ const config = await loadCliConfig(settings, 'test-session', argv);
480
+ expect(config.getProxy()).toBe(expected);
481
+ });
482
+ });
483
+ });
484
+ it('should use default fileFilter options when unconfigured', async () => {
485
+ process.argv = ['node', 'script.js'];
486
+ const argv = await parseArguments({});
487
+ const settings = {};
488
+ const config = await loadCliConfig(settings, 'test-session', argv);
489
+ expect(config.getFileFilteringRespectGitIgnore()).toBe(DEFAULT_FILE_FILTERING_OPTIONS.respectGitIgnore);
490
+ expect(config.getFileFilteringRespectGeminiIgnore()).toBe(DEFAULT_FILE_FILTERING_OPTIONS.respectGeminiIgnore);
491
+ });
492
+ });
493
+ describe('Hierarchical Memory Loading (config.ts) - Placeholder Suite', () => {
494
+ beforeEach(() => {
495
+ vi.resetAllMocks();
496
+ vi.mocked(os.homedir).mockReturnValue('/mock/home/user');
497
+ // Other common mocks would be reset here.
498
+ });
499
+ afterEach(() => {
500
+ vi.restoreAllMocks();
501
+ });
502
+ it('should pass extension context file paths to loadServerHierarchicalMemory', async () => {
503
+ process.argv = ['node', 'script.js'];
504
+ const settings = {};
505
+ vi.spyOn(ExtensionManager.prototype, 'getExtensions').mockReturnValue([
506
+ {
507
+ path: '/path/to/ext1',
508
+ name: 'ext1',
509
+ id: 'ext1-id',
510
+ version: '1.0.0',
511
+ contextFiles: ['/path/to/ext1/GEMINI.md'],
512
+ isActive: true,
513
+ },
514
+ {
515
+ path: '/path/to/ext2',
516
+ name: 'ext2',
517
+ id: 'ext2-id',
518
+ version: '1.0.0',
519
+ contextFiles: [],
520
+ isActive: true,
521
+ },
522
+ {
523
+ path: '/path/to/ext3',
524
+ name: 'ext3',
525
+ id: 'ext3-id',
526
+ version: '1.0.0',
527
+ contextFiles: [
528
+ '/path/to/ext3/context1.md',
529
+ '/path/to/ext3/context2.md',
530
+ ],
531
+ isActive: true,
532
+ },
533
+ ]);
534
+ const argv = await parseArguments({});
535
+ await loadCliConfig(settings, 'session-id', argv);
536
+ expect(ServerConfig.loadServerHierarchicalMemory).toHaveBeenCalledWith(expect.any(String), [], false, expect.any(Object), expect.any(ExtensionManager), true, 'tree', {
537
+ respectGitIgnore: false,
538
+ respectGeminiIgnore: true,
539
+ }, undefined);
540
+ });
541
+ // NOTE TO FUTURE DEVELOPERS:
542
+ // To re-enable tests for loadHierarchicalGeminiMemory, ensure that:
543
+ // 1. os.homedir() is reliably mocked *before* the config.ts module is loaded
544
+ // and its functions (which use os.homedir()) are called.
545
+ // 2. fs/promises and fs mocks correctly simulate file/directory existence,
546
+ // readability, and content based on paths derived from the mocked os.homedir().
547
+ // 3. Spies on console functions (for logger output) are correctly set up if needed.
548
+ // Example of a previously failing test structure:
549
+ it.skip('should correctly use mocked homedir for global path', async () => { });
550
+ });
551
+ describe('mergeMcpServers', () => {
552
+ it('should not modify the original settings object', async () => {
553
+ const settings = {
554
+ mcpServers: {
555
+ 'test-server': {
556
+ url: 'http://localhost:8080',
557
+ },
558
+ },
559
+ };
560
+ vi.spyOn(ExtensionManager.prototype, 'getExtensions').mockReturnValue([
561
+ {
562
+ path: '/path/to/ext1',
563
+ name: 'ext1',
564
+ id: 'ext1-id',
565
+ version: '1.0.0',
566
+ mcpServers: {
567
+ 'ext1-server': {
568
+ url: 'http://localhost:8081',
569
+ },
570
+ },
571
+ contextFiles: [],
572
+ isActive: true,
573
+ },
574
+ ]);
575
+ const originalSettings = JSON.parse(JSON.stringify(settings));
576
+ process.argv = ['node', 'script.js'];
577
+ const argv = await parseArguments({});
578
+ await loadCliConfig(settings, 'test-session', argv);
579
+ expect(settings).toEqual(originalSettings);
580
+ });
581
+ });
582
+ describe('mergeExcludeTools', () => {
583
+ const defaultExcludes = [
584
+ SHELL_TOOL_NAME,
585
+ EDIT_TOOL_NAME,
586
+ WRITE_FILE_TOOL_NAME,
587
+ ];
588
+ const originalIsTTY = process.stdin.isTTY;
589
+ beforeEach(() => {
590
+ vi.spyOn(ExtensionManager.prototype, 'getExtensions').mockReturnValue([]);
591
+ process.stdin.isTTY = true;
592
+ });
593
+ afterEach(() => {
594
+ process.stdin.isTTY = originalIsTTY;
595
+ });
596
+ it('should merge excludeTools from settings and extensions', async () => {
597
+ const settings = { tools: { exclude: ['tool1', 'tool2'] } };
598
+ vi.spyOn(ExtensionManager.prototype, 'getExtensions').mockReturnValue([
599
+ {
600
+ path: '/path/to/ext1',
601
+ name: 'ext1',
602
+ id: 'ext1-id',
603
+ version: '1.0.0',
604
+ excludeTools: ['tool3', 'tool4'],
605
+ contextFiles: [],
606
+ isActive: true,
607
+ },
608
+ {
609
+ path: '/path/to/ext2',
610
+ name: 'ext2',
611
+ id: 'ext2-id',
612
+ version: '1.0.0',
613
+ excludeTools: ['tool5'],
614
+ contextFiles: [],
615
+ isActive: true,
616
+ },
617
+ ]);
618
+ process.argv = ['node', 'script.js'];
619
+ const argv = await parseArguments({});
620
+ const config = await loadCliConfig(settings, 'test-session', argv);
621
+ expect(config.getExcludeTools()).toEqual(expect.arrayContaining(['tool1', 'tool2', 'tool3', 'tool4', 'tool5']));
622
+ expect(config.getExcludeTools()).toHaveLength(5);
623
+ });
624
+ it('should handle overlapping excludeTools between settings and extensions', async () => {
625
+ const settings = { tools: { exclude: ['tool1', 'tool2'] } };
626
+ vi.spyOn(ExtensionManager.prototype, 'getExtensions').mockReturnValue([
627
+ {
628
+ path: '/path/to/ext1',
629
+ name: 'ext1',
630
+ id: 'ext1-id',
631
+ version: '1.0.0',
632
+ excludeTools: ['tool2', 'tool3'],
633
+ contextFiles: [],
634
+ isActive: true,
635
+ },
636
+ ]);
637
+ process.argv = ['node', 'script.js'];
638
+ const argv = await parseArguments({});
639
+ const config = await loadCliConfig(settings, 'test-session', argv);
640
+ expect(config.getExcludeTools()).toEqual(expect.arrayContaining(['tool1', 'tool2', 'tool3']));
641
+ expect(config.getExcludeTools()).toHaveLength(3);
642
+ });
643
+ it('should handle overlapping excludeTools between extensions', async () => {
644
+ const settings = { tools: { exclude: ['tool1'] } };
645
+ vi.spyOn(ExtensionManager.prototype, 'getExtensions').mockReturnValue([
646
+ {
647
+ path: '/path/to/ext1',
648
+ name: 'ext1',
649
+ id: 'ext1-id',
650
+ version: '1.0.0',
651
+ excludeTools: ['tool2', 'tool3'],
652
+ contextFiles: [],
653
+ isActive: true,
654
+ },
655
+ {
656
+ path: '/path/to/ext2',
657
+ name: 'ext2',
658
+ id: 'ext2-id',
659
+ version: '1.0.0',
660
+ excludeTools: ['tool3', 'tool4'],
661
+ contextFiles: [],
662
+ isActive: true,
663
+ },
664
+ ]);
665
+ process.argv = ['node', 'script.js'];
666
+ const argv = await parseArguments({});
667
+ const config = await loadCliConfig(settings, 'test-session', argv);
668
+ expect(config.getExcludeTools()).toEqual(expect.arrayContaining(['tool1', 'tool2', 'tool3', 'tool4']));
669
+ expect(config.getExcludeTools()).toHaveLength(4);
670
+ });
671
+ it('should return an empty array when no excludeTools are specified and it is interactive', async () => {
672
+ process.stdin.isTTY = true;
673
+ const settings = {};
674
+ process.argv = ['node', 'script.js'];
675
+ const argv = await parseArguments({});
676
+ const config = await loadCliConfig(settings, 'test-session', argv);
677
+ expect(config.getExcludeTools()).toEqual([]);
678
+ });
679
+ it('should return default excludes when no excludeTools are specified and it is not interactive', async () => {
680
+ process.stdin.isTTY = false;
681
+ const settings = {};
682
+ process.argv = ['node', 'script.js', '-p', 'test'];
683
+ const argv = await parseArguments({});
684
+ const config = await loadCliConfig(settings, 'test-session', argv);
685
+ expect(config.getExcludeTools()).toEqual(defaultExcludes);
686
+ });
687
+ it('should handle settings with excludeTools but no extensions', async () => {
688
+ process.argv = ['node', 'script.js'];
689
+ const argv = await parseArguments({});
690
+ const settings = { tools: { exclude: ['tool1', 'tool2'] } };
691
+ vi.spyOn(ExtensionManager.prototype, 'getExtensions').mockReturnValue([]);
692
+ const config = await loadCliConfig(settings, 'test-session', argv);
693
+ expect(config.getExcludeTools()).toEqual(expect.arrayContaining(['tool1', 'tool2']));
694
+ expect(config.getExcludeTools()).toHaveLength(2);
695
+ });
696
+ it('should handle extensions with excludeTools but no settings', async () => {
697
+ const settings = {};
698
+ vi.spyOn(ExtensionManager.prototype, 'getExtensions').mockReturnValue([
699
+ {
700
+ path: '/path/to/ext',
701
+ name: 'ext1',
702
+ id: 'ext1-id',
703
+ version: '1.0.0',
704
+ excludeTools: ['tool1', 'tool2'],
705
+ contextFiles: [],
706
+ isActive: true,
707
+ },
708
+ ]);
709
+ process.argv = ['node', 'script.js'];
710
+ const argv = await parseArguments({});
711
+ const config = await loadCliConfig(settings, 'test-session', argv);
712
+ expect(config.getExcludeTools()).toEqual(expect.arrayContaining(['tool1', 'tool2']));
713
+ expect(config.getExcludeTools()).toHaveLength(2);
714
+ });
715
+ it('should not modify the original settings object', async () => {
716
+ const settings = { tools: { exclude: ['tool1'] } };
717
+ vi.spyOn(ExtensionManager.prototype, 'getExtensions').mockReturnValue([
718
+ {
719
+ path: '/path/to/ext',
720
+ name: 'ext1',
721
+ id: 'ext1-id',
722
+ version: '1.0.0',
723
+ excludeTools: ['tool2'],
724
+ contextFiles: [],
725
+ isActive: true,
726
+ },
727
+ ]);
728
+ const originalSettings = JSON.parse(JSON.stringify(settings));
729
+ process.argv = ['node', 'script.js'];
730
+ const argv = await parseArguments({});
731
+ await loadCliConfig(settings, 'test-session', argv);
732
+ expect(settings).toEqual(originalSettings);
733
+ });
734
+ });
735
+ describe('Approval mode tool exclusion logic', () => {
736
+ const originalIsTTY = process.stdin.isTTY;
737
+ beforeEach(() => {
738
+ process.stdin.isTTY = false; // Ensure non-interactive mode
739
+ vi.mocked(isWorkspaceTrusted).mockReturnValue({
740
+ isTrusted: true,
741
+ source: undefined,
742
+ });
743
+ vi.spyOn(ExtensionManager.prototype, 'getExtensions').mockReturnValue([]);
744
+ });
745
+ afterEach(() => {
746
+ process.stdin.isTTY = originalIsTTY;
747
+ });
748
+ it('should exclude all interactive tools in non-interactive mode with default approval mode', async () => {
749
+ process.argv = ['node', 'script.js', '-p', 'test'];
750
+ const argv = await parseArguments({});
751
+ const settings = {};
752
+ const config = await loadCliConfig(settings, 'test-session', argv);
753
+ const excludedTools = config.getExcludeTools();
754
+ expect(excludedTools).toContain(SHELL_TOOL_NAME);
755
+ expect(excludedTools).toContain(EDIT_TOOL_NAME);
756
+ expect(excludedTools).toContain(WRITE_FILE_TOOL_NAME);
757
+ });
758
+ it('should exclude all interactive tools in non-interactive mode with explicit default approval mode', async () => {
759
+ process.argv = [
760
+ 'node',
761
+ 'script.js',
762
+ '--approval-mode',
763
+ 'default',
764
+ '-p',
765
+ 'test',
766
+ ];
767
+ const argv = await parseArguments({});
768
+ const settings = {};
769
+ const config = await loadCliConfig(settings, 'test-session', argv);
770
+ const excludedTools = config.getExcludeTools();
771
+ expect(excludedTools).toContain(SHELL_TOOL_NAME);
772
+ expect(excludedTools).toContain(EDIT_TOOL_NAME);
773
+ expect(excludedTools).toContain(WRITE_FILE_TOOL_NAME);
774
+ });
775
+ it('should exclude only shell tools in non-interactive mode with auto_edit approval mode', async () => {
776
+ process.argv = [
777
+ 'node',
778
+ 'script.js',
779
+ '--approval-mode',
780
+ 'auto_edit',
781
+ '-p',
782
+ 'test',
783
+ ];
784
+ const argv = await parseArguments({});
785
+ const settings = {};
786
+ const config = await loadCliConfig(settings, 'test-session', argv);
787
+ const excludedTools = config.getExcludeTools();
788
+ expect(excludedTools).toContain(SHELL_TOOL_NAME);
789
+ expect(excludedTools).not.toContain(EDIT_TOOL_NAME);
790
+ expect(excludedTools).not.toContain(WRITE_FILE_TOOL_NAME);
791
+ });
792
+ it('should exclude no interactive tools in non-interactive mode with yolo approval mode', async () => {
793
+ process.argv = [
794
+ 'node',
795
+ 'script.js',
796
+ '--approval-mode',
797
+ 'yolo',
798
+ '-p',
799
+ 'test',
800
+ ];
801
+ const argv = await parseArguments({});
802
+ const settings = {};
803
+ const config = await loadCliConfig(settings, 'test-session', argv);
804
+ const excludedTools = config.getExcludeTools();
805
+ expect(excludedTools).not.toContain(SHELL_TOOL_NAME);
806
+ expect(excludedTools).not.toContain(EDIT_TOOL_NAME);
807
+ expect(excludedTools).not.toContain(WRITE_FILE_TOOL_NAME);
808
+ });
809
+ it('should exclude no interactive tools in non-interactive mode with legacy yolo flag', async () => {
810
+ process.argv = ['node', 'script.js', '--yolo', '-p', 'test'];
811
+ const argv = await parseArguments({});
812
+ const settings = {};
813
+ const config = await loadCliConfig(settings, 'test-session', argv);
814
+ const excludedTools = config.getExcludeTools();
815
+ expect(excludedTools).not.toContain(SHELL_TOOL_NAME);
816
+ expect(excludedTools).not.toContain(EDIT_TOOL_NAME);
817
+ expect(excludedTools).not.toContain(WRITE_FILE_TOOL_NAME);
818
+ });
819
+ it('should not exclude interactive tools in interactive mode regardless of approval mode', async () => {
820
+ process.stdin.isTTY = true; // Interactive mode
821
+ const testCases = [
822
+ { args: ['node', 'script.js'] }, // default
823
+ { args: ['node', 'script.js', '--approval-mode', 'default'] },
824
+ { args: ['node', 'script.js', '--approval-mode', 'auto_edit'] },
825
+ { args: ['node', 'script.js', '--approval-mode', 'yolo'] },
826
+ { args: ['node', 'script.js', '--yolo'] },
827
+ ];
828
+ for (const testCase of testCases) {
829
+ process.argv = testCase.args;
830
+ const argv = await parseArguments({});
831
+ const settings = {};
832
+ const config = await loadCliConfig(settings, 'test-session', argv);
833
+ const excludedTools = config.getExcludeTools();
834
+ expect(excludedTools).not.toContain(SHELL_TOOL_NAME);
835
+ expect(excludedTools).not.toContain(EDIT_TOOL_NAME);
836
+ expect(excludedTools).not.toContain(WRITE_FILE_TOOL_NAME);
837
+ }
838
+ });
839
+ it('should merge approval mode exclusions with settings exclusions in auto_edit mode', async () => {
840
+ process.argv = [
841
+ 'node',
842
+ 'script.js',
843
+ '--approval-mode',
844
+ 'auto_edit',
845
+ '-p',
846
+ 'test',
847
+ ];
848
+ const argv = await parseArguments({});
849
+ const settings = { tools: { exclude: ['custom_tool'] } };
850
+ const config = await loadCliConfig(settings, 'test-session', argv);
851
+ const excludedTools = config.getExcludeTools();
852
+ expect(excludedTools).toContain('custom_tool'); // From settings
853
+ expect(excludedTools).toContain(SHELL_TOOL_NAME); // From approval mode
854
+ expect(excludedTools).not.toContain(EDIT_TOOL_NAME); // Should be allowed in auto_edit
855
+ expect(excludedTools).not.toContain(WRITE_FILE_TOOL_NAME); // Should be allowed in auto_edit
856
+ });
857
+ it('should throw an error if YOLO mode is attempted when disableYoloMode is true', async () => {
858
+ process.argv = ['node', 'script.js', '--yolo'];
859
+ const argv = await parseArguments({});
860
+ const settings = {
861
+ security: {
862
+ disableYoloMode: true,
863
+ },
864
+ };
865
+ await expect(loadCliConfig(settings, 'test-session', argv)).rejects.toThrow('Cannot start in YOLO mode when it is disabled by settings');
866
+ });
867
+ it('should throw an error for invalid approval mode values in loadCliConfig', async () => {
868
+ // Create a mock argv with an invalid approval mode that bypasses argument parsing validation
869
+ const invalidArgv = {
870
+ approvalMode: 'invalid_mode',
871
+ promptInteractive: '',
872
+ prompt: '',
873
+ yolo: false,
874
+ };
875
+ const settings = {};
876
+ await expect(loadCliConfig(settings, 'test-session', invalidArgv)).rejects.toThrow('Invalid approval mode: invalid_mode. Valid values are: yolo, auto_edit, default');
877
+ });
878
+ });
879
+ describe('loadCliConfig with allowed-mcp-server-names', () => {
880
+ beforeEach(() => {
881
+ vi.resetAllMocks();
882
+ vi.mocked(os.homedir).mockReturnValue('/mock/home/user');
883
+ vi.stubEnv('GEMINI_API_KEY', 'test-api-key');
884
+ vi.spyOn(ExtensionManager.prototype, 'getExtensions').mockReturnValue([]);
885
+ });
886
+ afterEach(() => {
887
+ vi.unstubAllEnvs();
888
+ vi.restoreAllMocks();
889
+ });
890
+ const baseSettings = {
891
+ mcpServers: {
892
+ server1: { url: 'http://localhost:8080' },
893
+ server2: { url: 'http://localhost:8081' },
894
+ server3: { url: 'http://localhost:8082' },
895
+ },
896
+ };
897
+ it('should allow all MCP servers if the flag is not provided', async () => {
898
+ process.argv = ['node', 'script.js'];
899
+ const argv = await parseArguments({});
900
+ const config = await loadCliConfig(baseSettings, 'test-session', argv);
901
+ expect(config.getMcpServers()).toEqual(baseSettings.mcpServers);
902
+ });
903
+ it('should allow only the specified MCP server', async () => {
904
+ process.argv = [
905
+ 'node',
906
+ 'script.js',
907
+ '--allowed-mcp-server-names',
908
+ 'server1',
909
+ ];
910
+ const argv = await parseArguments({});
911
+ const config = await loadCliConfig(baseSettings, 'test-session', argv);
912
+ expect(config.getAllowedMcpServers()).toEqual(['server1']);
913
+ });
914
+ it('should allow multiple specified MCP servers', async () => {
915
+ process.argv = [
916
+ 'node',
917
+ 'script.js',
918
+ '--allowed-mcp-server-names',
919
+ 'server1',
920
+ '--allowed-mcp-server-names',
921
+ 'server3',
922
+ ];
923
+ const argv = await parseArguments({});
924
+ const config = await loadCliConfig(baseSettings, 'test-session', argv);
925
+ expect(config.getAllowedMcpServers()).toEqual(['server1', 'server3']);
926
+ });
927
+ it('should handle server names that do not exist', async () => {
928
+ process.argv = [
929
+ 'node',
930
+ 'script.js',
931
+ '--allowed-mcp-server-names',
932
+ 'server1',
933
+ '--allowed-mcp-server-names',
934
+ 'server4',
935
+ ];
936
+ const argv = await parseArguments({});
937
+ const config = await loadCliConfig(baseSettings, 'test-session', argv);
938
+ expect(config.getAllowedMcpServers()).toEqual(['server1', 'server4']);
939
+ });
940
+ it('should allow no MCP servers if the flag is provided but empty', async () => {
941
+ process.argv = ['node', 'script.js', '--allowed-mcp-server-names', ''];
942
+ const argv = await parseArguments({});
943
+ const config = await loadCliConfig(baseSettings, 'test-session', argv);
944
+ expect(config.getAllowedMcpServers()).toEqual(['']);
945
+ });
946
+ it('should read allowMCPServers from settings', async () => {
947
+ process.argv = ['node', 'script.js'];
948
+ const argv = await parseArguments({});
949
+ const settings = {
950
+ ...baseSettings,
951
+ mcp: { allowed: ['server1', 'server2'] },
952
+ };
953
+ const config = await loadCliConfig(settings, 'test-session', argv);
954
+ expect(config.getAllowedMcpServers()).toEqual(['server1', 'server2']);
955
+ });
956
+ it('should read excludeMCPServers from settings', async () => {
957
+ process.argv = ['node', 'script.js'];
958
+ const argv = await parseArguments({});
959
+ const settings = {
960
+ ...baseSettings,
961
+ mcp: { excluded: ['server1', 'server2'] },
962
+ };
963
+ const config = await loadCliConfig(settings, 'test-session', argv);
964
+ expect(config.getBlockedMcpServers()).toEqual(['server1', 'server2']);
965
+ });
966
+ it('should override allowMCPServers with excludeMCPServers if overlapping', async () => {
967
+ process.argv = ['node', 'script.js'];
968
+ const argv = await parseArguments({});
969
+ const settings = {
970
+ ...baseSettings,
971
+ mcp: {
972
+ excluded: ['server1'],
973
+ allowed: ['server1', 'server2'],
974
+ },
975
+ };
976
+ const config = await loadCliConfig(settings, 'test-session', argv);
977
+ expect(config.getAllowedMcpServers()).toEqual(['server1', 'server2']);
978
+ expect(config.getBlockedMcpServers()).toEqual(['server1']);
979
+ });
980
+ it('should prioritize mcp server flag if set', async () => {
981
+ process.argv = [
982
+ 'node',
983
+ 'script.js',
984
+ '--allowed-mcp-server-names',
985
+ 'server1',
986
+ ];
987
+ const argv = await parseArguments({});
988
+ const settings = {
989
+ ...baseSettings,
990
+ mcp: {
991
+ excluded: ['server1'],
992
+ allowed: ['server2'],
993
+ },
994
+ };
995
+ const config = await loadCliConfig(settings, 'test-session', argv);
996
+ expect(config.getAllowedMcpServers()).toEqual(['server1']);
997
+ });
998
+ it('should prioritize CLI flag over both allowed and excluded settings', async () => {
999
+ process.argv = [
1000
+ 'node',
1001
+ 'script.js',
1002
+ '--allowed-mcp-server-names',
1003
+ 'server2',
1004
+ '--allowed-mcp-server-names',
1005
+ 'server3',
1006
+ ];
1007
+ const argv = await parseArguments({});
1008
+ const settings = {
1009
+ ...baseSettings,
1010
+ mcp: {
1011
+ allowed: ['server1', 'server2'], // Should be ignored
1012
+ excluded: ['server3'], // Should be ignored
1013
+ },
1014
+ };
1015
+ const config = await loadCliConfig(settings, 'test-session', argv);
1016
+ expect(config.getAllowedMcpServers()).toEqual(['server2', 'server3']);
1017
+ expect(config.getBlockedMcpServers()).toEqual([]);
1018
+ });
1019
+ });
1020
+ describe('loadCliConfig model selection', () => {
1021
+ beforeEach(() => {
1022
+ vi.spyOn(ExtensionManager.prototype, 'getExtensions').mockReturnValue([]);
1023
+ });
1024
+ afterEach(() => {
1025
+ vi.resetAllMocks();
1026
+ });
1027
+ it('selects a model from settings.json if provided', async () => {
1028
+ process.argv = ['node', 'script.js'];
1029
+ const argv = await parseArguments({});
1030
+ const config = await loadCliConfig({
1031
+ model: {
1032
+ name: 'gemini-2.5-pro',
1033
+ },
1034
+ }, 'test-session', argv);
1035
+ expect(config.getModel()).toBe('gemini-2.5-pro');
1036
+ });
1037
+ it('uses the default gemini model if nothing is set', async () => {
1038
+ process.argv = ['node', 'script.js']; // No model set.
1039
+ const argv = await parseArguments({});
1040
+ const config = await loadCliConfig({
1041
+ // No model set.
1042
+ }, 'test-session', argv);
1043
+ expect(config.getModel()).toBe(DEFAULT_GEMINI_MODEL);
1044
+ });
1045
+ it('always prefers model from argv', async () => {
1046
+ process.argv = ['node', 'script.js', '--model', 'gemini-2.5-flash-preview'];
1047
+ const argv = await parseArguments({});
1048
+ const config = await loadCliConfig({
1049
+ model: {
1050
+ name: 'gemini-2.5-pro',
1051
+ },
1052
+ }, 'test-session', argv);
1053
+ expect(config.getModel()).toBe('gemini-2.5-flash-preview');
1054
+ });
1055
+ it('selects the model from argv if provided', async () => {
1056
+ process.argv = ['node', 'script.js', '--model', 'gemini-2.5-flash-preview'];
1057
+ const argv = await parseArguments({});
1058
+ const config = await loadCliConfig({
1059
+ // No model provided via settings.
1060
+ }, 'test-session', argv);
1061
+ expect(config.getModel()).toBe('gemini-2.5-flash-preview');
1062
+ });
1063
+ });
1064
+ describe('loadCliConfig model selection with model router', () => {
1065
+ beforeEach(() => {
1066
+ vi.spyOn(ExtensionManager.prototype, 'getExtensions').mockReturnValue([]);
1067
+ });
1068
+ afterEach(() => {
1069
+ vi.resetAllMocks();
1070
+ });
1071
+ it('should use auto model when useModelRouter is true and no model is provided', async () => {
1072
+ process.argv = ['node', 'script.js'];
1073
+ const argv = await parseArguments({});
1074
+ const config = await loadCliConfig({
1075
+ experimental: {
1076
+ useModelRouter: true,
1077
+ },
1078
+ }, 'test-session', argv);
1079
+ expect(config.getModel()).toBe(DEFAULT_GEMINI_MODEL_AUTO);
1080
+ });
1081
+ it('should use default model when useModelRouter is false and no model is provided', async () => {
1082
+ process.argv = ['node', 'script.js'];
1083
+ const argv = await parseArguments({});
1084
+ const config = await loadCliConfig({
1085
+ experimental: {
1086
+ useModelRouter: false,
1087
+ },
1088
+ }, 'test-session', argv);
1089
+ expect(config.getModel()).toBe(DEFAULT_GEMINI_MODEL);
1090
+ });
1091
+ it('should prioritize argv over useModelRouter', async () => {
1092
+ process.argv = ['node', 'script.js', '--model', 'gemini-from-argv'];
1093
+ const argv = await parseArguments({});
1094
+ const config = await loadCliConfig({
1095
+ experimental: {
1096
+ useModelRouter: true,
1097
+ },
1098
+ }, 'test-session', argv);
1099
+ expect(config.getModel()).toBe('gemini-from-argv');
1100
+ });
1101
+ it('should prioritize settings over useModelRouter', async () => {
1102
+ process.argv = ['node', 'script.js'];
1103
+ const argv = await parseArguments({});
1104
+ const config = await loadCliConfig({
1105
+ experimental: {
1106
+ useModelRouter: true,
1107
+ },
1108
+ model: {
1109
+ name: 'gemini-from-settings',
1110
+ },
1111
+ }, 'test-session', argv);
1112
+ expect(config.getModel()).toBe('gemini-from-settings');
1113
+ });
1114
+ it('should prioritize environment variable over useModelRouter', async () => {
1115
+ process.argv = ['node', 'script.js'];
1116
+ vi.stubEnv('GEMINI_MODEL', 'gemini-from-env');
1117
+ const argv = await parseArguments({});
1118
+ const config = await loadCliConfig({
1119
+ experimental: {
1120
+ useModelRouter: true,
1121
+ },
1122
+ }, 'test-session', argv);
1123
+ expect(config.getModel()).toBe('gemini-from-env');
1124
+ });
1125
+ });
1126
+ describe('loadCliConfig folderTrust', () => {
1127
+ beforeEach(() => {
1128
+ vi.resetAllMocks();
1129
+ vi.mocked(os.homedir).mockReturnValue('/mock/home/user');
1130
+ vi.stubEnv('GEMINI_API_KEY', 'test-api-key');
1131
+ vi.spyOn(ExtensionManager.prototype, 'getExtensions').mockReturnValue([]);
1132
+ });
1133
+ afterEach(() => {
1134
+ vi.unstubAllEnvs();
1135
+ vi.restoreAllMocks();
1136
+ });
1137
+ it('should be false when folderTrust is false', async () => {
1138
+ process.argv = ['node', 'script.js'];
1139
+ const settings = {
1140
+ security: {
1141
+ folderTrust: {
1142
+ enabled: false,
1143
+ },
1144
+ },
1145
+ };
1146
+ const argv = await parseArguments({});
1147
+ const config = await loadCliConfig(settings, 'test-session', argv);
1148
+ expect(config.getFolderTrust()).toBe(false);
1149
+ });
1150
+ it('should be true when folderTrust is true', async () => {
1151
+ process.argv = ['node', 'script.js'];
1152
+ const argv = await parseArguments({});
1153
+ const settings = {
1154
+ security: {
1155
+ folderTrust: {
1156
+ enabled: true,
1157
+ },
1158
+ },
1159
+ };
1160
+ const config = await loadCliConfig(settings, 'test-session', argv);
1161
+ expect(config.getFolderTrust()).toBe(true);
1162
+ });
1163
+ it('should be false by default', async () => {
1164
+ process.argv = ['node', 'script.js'];
1165
+ const argv = await parseArguments({});
1166
+ const settings = {};
1167
+ const config = await loadCliConfig(settings, 'test-session', argv);
1168
+ expect(config.getFolderTrust()).toBe(false);
1169
+ });
1170
+ });
1171
+ describe('loadCliConfig with includeDirectories', () => {
1172
+ beforeEach(() => {
1173
+ vi.resetAllMocks();
1174
+ vi.mocked(os.homedir).mockReturnValue('/mock/home/user');
1175
+ vi.stubEnv('GEMINI_API_KEY', 'test-api-key');
1176
+ vi.spyOn(process, 'cwd').mockReturnValue(path.resolve(path.sep, 'home', 'user', 'project'));
1177
+ vi.spyOn(ExtensionManager.prototype, 'getExtensions').mockReturnValue([]);
1178
+ });
1179
+ afterEach(() => {
1180
+ vi.restoreAllMocks();
1181
+ });
1182
+ it('should combine and resolve paths from settings and CLI arguments', async () => {
1183
+ const mockCwd = path.resolve(path.sep, 'home', 'user', 'project');
1184
+ process.argv = [
1185
+ 'node',
1186
+ 'script.js',
1187
+ '--include-directories',
1188
+ `${path.resolve(path.sep, 'cli', 'path1')},${path.join(mockCwd, 'cli', 'path2')}`,
1189
+ ];
1190
+ const argv = await parseArguments({});
1191
+ const settings = {
1192
+ context: {
1193
+ includeDirectories: [
1194
+ path.resolve(path.sep, 'settings', 'path1'),
1195
+ path.join(os.homedir(), 'settings', 'path2'),
1196
+ path.join(mockCwd, 'settings', 'path3'),
1197
+ ],
1198
+ },
1199
+ };
1200
+ const config = await loadCliConfig(settings, 'test-session', argv);
1201
+ const expected = [
1202
+ mockCwd,
1203
+ path.resolve(path.sep, 'cli', 'path1'),
1204
+ path.join(mockCwd, 'cli', 'path2'),
1205
+ path.resolve(path.sep, 'settings', 'path1'),
1206
+ path.join(os.homedir(), 'settings', 'path2'),
1207
+ path.join(mockCwd, 'settings', 'path3'),
1208
+ ];
1209
+ expect(config.getWorkspaceContext().getDirectories()).toEqual(expect.arrayContaining(expected));
1210
+ expect(config.getWorkspaceContext().getDirectories()).toHaveLength(expected.length);
1211
+ });
1212
+ });
1213
+ describe('loadCliConfig compressionThreshold', () => {
1214
+ beforeEach(() => {
1215
+ vi.resetAllMocks();
1216
+ vi.mocked(os.homedir).mockReturnValue('/mock/home/user');
1217
+ vi.stubEnv('GEMINI_API_KEY', 'test-api-key');
1218
+ vi.spyOn(ExtensionManager.prototype, 'getExtensions').mockReturnValue([]);
1219
+ });
1220
+ afterEach(() => {
1221
+ vi.unstubAllEnvs();
1222
+ vi.restoreAllMocks();
1223
+ });
1224
+ it('should pass settings to the core config', async () => {
1225
+ process.argv = ['node', 'script.js'];
1226
+ const argv = await parseArguments({});
1227
+ const settings = {
1228
+ model: {
1229
+ compressionThreshold: 0.5,
1230
+ },
1231
+ };
1232
+ const config = await loadCliConfig(settings, 'test-session', argv);
1233
+ expect(await config.getCompressionThreshold()).toBe(0.5);
1234
+ });
1235
+ it('should have undefined compressionThreshold if not in settings', async () => {
1236
+ process.argv = ['node', 'script.js'];
1237
+ const argv = await parseArguments({});
1238
+ const settings = {};
1239
+ const config = await loadCliConfig(settings, 'test-session', argv);
1240
+ expect(await config.getCompressionThreshold()).toBeUndefined();
1241
+ });
1242
+ });
1243
+ describe('loadCliConfig useRipgrep', () => {
1244
+ beforeEach(() => {
1245
+ vi.resetAllMocks();
1246
+ vi.mocked(os.homedir).mockReturnValue('/mock/home/user');
1247
+ vi.stubEnv('GEMINI_API_KEY', 'test-api-key');
1248
+ vi.spyOn(ExtensionManager.prototype, 'getExtensions').mockReturnValue([]);
1249
+ });
1250
+ afterEach(() => {
1251
+ vi.unstubAllEnvs();
1252
+ vi.restoreAllMocks();
1253
+ });
1254
+ it('should be true by default when useRipgrep is not set in settings', async () => {
1255
+ process.argv = ['node', 'script.js'];
1256
+ const argv = await parseArguments({});
1257
+ const settings = {};
1258
+ const config = await loadCliConfig(settings, 'test-session', argv);
1259
+ expect(config.getUseRipgrep()).toBe(true);
1260
+ });
1261
+ it('should be false when useRipgrep is set to false in settings', async () => {
1262
+ process.argv = ['node', 'script.js'];
1263
+ const argv = await parseArguments({});
1264
+ const settings = { tools: { useRipgrep: false } };
1265
+ const config = await loadCliConfig(settings, 'test-session', argv);
1266
+ expect(config.getUseRipgrep()).toBe(false);
1267
+ });
1268
+ it('should be true when useRipgrep is explicitly set to true in settings', async () => {
1269
+ process.argv = ['node', 'script.js'];
1270
+ const argv = await parseArguments({});
1271
+ const settings = { tools: { useRipgrep: true } };
1272
+ const config = await loadCliConfig(settings, 'test-session', argv);
1273
+ expect(config.getUseRipgrep()).toBe(true);
1274
+ });
1275
+ describe('loadCliConfig useModelRouter', () => {
1276
+ it('should be false by default when useModelRouter is not set in settings', async () => {
1277
+ process.argv = ['node', 'script.js'];
1278
+ const _argv = await parseArguments({});
1279
+ const settings = {};
1280
+ const config = await loadCliConfig(settings, 'test-session', _argv);
1281
+ expect(config.getUseModelRouter()).toBe(false);
1282
+ });
1283
+ it('should be true when useModelRouter is set to true in settings', async () => {
1284
+ process.argv = ['node', 'script.js'];
1285
+ const argv = await parseArguments({});
1286
+ const settings = { experimental: { useModelRouter: true } };
1287
+ const config = await loadCliConfig(settings, 'test-session', argv);
1288
+ expect(config.getUseModelRouter()).toBe(true);
1289
+ });
1290
+ it('should be false when useModelRouter is explicitly set to false in settings', async () => {
1291
+ process.argv = ['node', 'script.js'];
1292
+ const argv = await parseArguments({});
1293
+ const settings = { experimental: { useModelRouter: false } };
1294
+ const config = await loadCliConfig(settings, 'test-session', argv);
1295
+ expect(config.getUseModelRouter()).toBe(false);
1296
+ });
1297
+ });
1298
+ });
1299
+ describe('screenReader configuration', () => {
1300
+ beforeEach(() => {
1301
+ vi.resetAllMocks();
1302
+ vi.mocked(os.homedir).mockReturnValue('/mock/home/user');
1303
+ vi.stubEnv('GEMINI_API_KEY', 'test-api-key');
1304
+ vi.spyOn(ExtensionManager.prototype, 'getExtensions').mockReturnValue([]);
1305
+ });
1306
+ afterEach(() => {
1307
+ vi.unstubAllEnvs();
1308
+ vi.restoreAllMocks();
1309
+ });
1310
+ it('should use screenReader value from settings if CLI flag is not present (settings true)', async () => {
1311
+ process.argv = ['node', 'script.js'];
1312
+ const argv = await parseArguments({});
1313
+ const settings = {
1314
+ ui: { accessibility: { screenReader: true } },
1315
+ };
1316
+ const config = await loadCliConfig(settings, 'test-session', argv);
1317
+ expect(config.getScreenReader()).toBe(true);
1318
+ });
1319
+ it('should use screenReader value from settings if CLI flag is not present (settings false)', async () => {
1320
+ process.argv = ['node', 'script.js'];
1321
+ const argv = await parseArguments({});
1322
+ const settings = {
1323
+ ui: { accessibility: { screenReader: false } },
1324
+ };
1325
+ const config = await loadCliConfig(settings, 'test-session', argv);
1326
+ expect(config.getScreenReader()).toBe(false);
1327
+ });
1328
+ it('should prioritize --screen-reader CLI flag (true) over settings (false)', async () => {
1329
+ process.argv = ['node', 'script.js', '--screen-reader'];
1330
+ const argv = await parseArguments({});
1331
+ const settings = {
1332
+ ui: { accessibility: { screenReader: false } },
1333
+ };
1334
+ const config = await loadCliConfig(settings, 'test-session', argv);
1335
+ expect(config.getScreenReader()).toBe(true);
1336
+ });
1337
+ it('should be false by default when no flag or setting is present', async () => {
1338
+ process.argv = ['node', 'script.js'];
1339
+ const argv = await parseArguments({});
1340
+ const settings = {};
1341
+ const config = await loadCliConfig(settings, 'test-session', argv);
1342
+ expect(config.getScreenReader()).toBe(false);
1343
+ });
1344
+ });
1345
+ describe('loadCliConfig tool exclusions', () => {
1346
+ const originalIsTTY = process.stdin.isTTY;
1347
+ beforeEach(() => {
1348
+ vi.resetAllMocks();
1349
+ vi.mocked(os.homedir).mockReturnValue('/mock/home/user');
1350
+ vi.stubEnv('GEMINI_API_KEY', 'test-api-key');
1351
+ process.stdin.isTTY = true;
1352
+ vi.mocked(isWorkspaceTrusted).mockReturnValue({
1353
+ isTrusted: true,
1354
+ source: undefined,
1355
+ });
1356
+ vi.spyOn(ExtensionManager.prototype, 'getExtensions').mockReturnValue([]);
1357
+ });
1358
+ afterEach(() => {
1359
+ process.stdin.isTTY = originalIsTTY;
1360
+ vi.unstubAllEnvs();
1361
+ vi.restoreAllMocks();
1362
+ });
1363
+ it('should not exclude interactive tools in interactive mode without YOLO', async () => {
1364
+ process.stdin.isTTY = true;
1365
+ process.argv = ['node', 'script.js'];
1366
+ const argv = await parseArguments({});
1367
+ const config = await loadCliConfig({}, 'test-session', argv);
1368
+ expect(config.getExcludeTools()).not.toContain('run_shell_command');
1369
+ expect(config.getExcludeTools()).not.toContain('replace');
1370
+ expect(config.getExcludeTools()).not.toContain('write_file');
1371
+ });
1372
+ it('should not exclude interactive tools in interactive mode with YOLO', async () => {
1373
+ process.stdin.isTTY = true;
1374
+ process.argv = ['node', 'script.js', '--yolo'];
1375
+ const argv = await parseArguments({});
1376
+ const config = await loadCliConfig({}, 'test-session', argv);
1377
+ expect(config.getExcludeTools()).not.toContain('run_shell_command');
1378
+ expect(config.getExcludeTools()).not.toContain('replace');
1379
+ expect(config.getExcludeTools()).not.toContain('write_file');
1380
+ });
1381
+ it('should exclude interactive tools in non-interactive mode without YOLO', async () => {
1382
+ process.stdin.isTTY = false;
1383
+ process.argv = ['node', 'script.js', '-p', 'test'];
1384
+ const argv = await parseArguments({});
1385
+ const config = await loadCliConfig({}, 'test-session', argv);
1386
+ expect(config.getExcludeTools()).toContain('run_shell_command');
1387
+ expect(config.getExcludeTools()).toContain('replace');
1388
+ expect(config.getExcludeTools()).toContain('write_file');
1389
+ });
1390
+ it('should not exclude interactive tools in non-interactive mode with YOLO', async () => {
1391
+ process.stdin.isTTY = false;
1392
+ process.argv = ['node', 'script.js', '-p', 'test', '--yolo'];
1393
+ const argv = await parseArguments({});
1394
+ const config = await loadCliConfig({}, 'test-session', argv);
1395
+ expect(config.getExcludeTools()).not.toContain('run_shell_command');
1396
+ expect(config.getExcludeTools()).not.toContain('replace');
1397
+ expect(config.getExcludeTools()).not.toContain('write_file');
1398
+ });
1399
+ it('should not exclude shell tool in non-interactive mode when --allowed-tools="ShellTool" is set', async () => {
1400
+ process.stdin.isTTY = false;
1401
+ process.argv = [
1402
+ 'node',
1403
+ 'script.js',
1404
+ '-p',
1405
+ 'test',
1406
+ '--allowed-tools',
1407
+ 'ShellTool',
1408
+ ];
1409
+ const argv = await parseArguments({});
1410
+ const config = await loadCliConfig({}, 'test-session', argv);
1411
+ expect(config.getExcludeTools()).not.toContain(SHELL_TOOL_NAME);
1412
+ });
1413
+ it('should not exclude shell tool in non-interactive mode when --allowed-tools="run_shell_command" is set', async () => {
1414
+ process.stdin.isTTY = false;
1415
+ process.argv = [
1416
+ 'node',
1417
+ 'script.js',
1418
+ '-p',
1419
+ 'test',
1420
+ '--allowed-tools',
1421
+ 'run_shell_command',
1422
+ ];
1423
+ const argv = await parseArguments({});
1424
+ const config = await loadCliConfig({}, 'test-session', argv);
1425
+ expect(config.getExcludeTools()).not.toContain(SHELL_TOOL_NAME);
1426
+ });
1427
+ it('should not exclude shell tool in non-interactive mode when --allowed-tools="ShellTool(wc)" is set', async () => {
1428
+ process.stdin.isTTY = false;
1429
+ process.argv = [
1430
+ 'node',
1431
+ 'script.js',
1432
+ '-p',
1433
+ 'test',
1434
+ '--allowed-tools',
1435
+ 'ShellTool(wc)',
1436
+ ];
1437
+ const argv = await parseArguments({});
1438
+ const config = await loadCliConfig({}, 'test-session', argv);
1439
+ expect(config.getExcludeTools()).not.toContain(SHELL_TOOL_NAME);
1440
+ });
1441
+ });
1442
+ describe('loadCliConfig interactive', () => {
1443
+ const originalIsTTY = process.stdin.isTTY;
1444
+ beforeEach(() => {
1445
+ vi.resetAllMocks();
1446
+ vi.mocked(os.homedir).mockReturnValue('/mock/home/user');
1447
+ vi.stubEnv('GEMINI_API_KEY', 'test-api-key');
1448
+ process.stdin.isTTY = true;
1449
+ vi.spyOn(ExtensionManager.prototype, 'getExtensions').mockReturnValue([]);
1450
+ });
1451
+ afterEach(() => {
1452
+ process.stdin.isTTY = originalIsTTY;
1453
+ vi.unstubAllEnvs();
1454
+ vi.restoreAllMocks();
1455
+ });
1456
+ it('should be interactive if isTTY and no prompt', async () => {
1457
+ process.stdin.isTTY = true;
1458
+ process.argv = ['node', 'script.js'];
1459
+ const argv = await parseArguments({});
1460
+ const config = await loadCliConfig({}, 'test-session', argv);
1461
+ expect(config.isInteractive()).toBe(true);
1462
+ });
1463
+ it('should be interactive if prompt-interactive is set', async () => {
1464
+ process.stdin.isTTY = false;
1465
+ process.argv = ['node', 'script.js', '--prompt-interactive', 'test'];
1466
+ const argv = await parseArguments({});
1467
+ const config = await loadCliConfig({}, 'test-session', argv);
1468
+ expect(config.isInteractive()).toBe(true);
1469
+ });
1470
+ it('should not be interactive if not isTTY and no prompt', async () => {
1471
+ process.stdin.isTTY = false;
1472
+ process.argv = ['node', 'script.js'];
1473
+ const argv = await parseArguments({});
1474
+ const config = await loadCliConfig({}, 'test-session', argv);
1475
+ expect(config.isInteractive()).toBe(false);
1476
+ });
1477
+ it('should not be interactive if prompt is set', async () => {
1478
+ process.stdin.isTTY = true;
1479
+ process.argv = ['node', 'script.js', '--prompt', 'test'];
1480
+ const argv = await parseArguments({});
1481
+ const config = await loadCliConfig({}, 'test-session', argv);
1482
+ expect(config.isInteractive()).toBe(false);
1483
+ });
1484
+ it('should not be interactive if positional prompt words are provided with other flags', async () => {
1485
+ process.stdin.isTTY = true;
1486
+ process.argv = ['node', 'script.js', '--model', 'gemini-2.5-pro', 'Hello'];
1487
+ const argv = await parseArguments({});
1488
+ const config = await loadCliConfig({}, 'test-session', argv);
1489
+ expect(config.isInteractive()).toBe(false);
1490
+ });
1491
+ it('should not be interactive if positional prompt words are provided with multiple flags', async () => {
1492
+ process.stdin.isTTY = true;
1493
+ process.argv = [
1494
+ 'node',
1495
+ 'script.js',
1496
+ '--model',
1497
+ 'gemini-2.5-pro',
1498
+ '--yolo',
1499
+ 'Hello world',
1500
+ ];
1501
+ const argv = await parseArguments({});
1502
+ const config = await loadCliConfig({}, 'test-session', argv);
1503
+ expect(config.isInteractive()).toBe(false);
1504
+ // Verify the question is preserved for one-shot execution
1505
+ expect(argv.prompt).toBe('Hello world');
1506
+ expect(argv.promptInteractive).toBeUndefined();
1507
+ });
1508
+ it('should not be interactive if positional prompt words are provided with extensions flag', async () => {
1509
+ process.stdin.isTTY = true;
1510
+ process.argv = ['node', 'script.js', '-e', 'none', 'hello'];
1511
+ const argv = await parseArguments({});
1512
+ const config = await loadCliConfig({}, 'test-session', argv);
1513
+ expect(config.isInteractive()).toBe(false);
1514
+ expect(argv.query).toBe('hello');
1515
+ expect(argv.extensions).toEqual(['none']);
1516
+ });
1517
+ it('should handle multiple positional words correctly', async () => {
1518
+ process.stdin.isTTY = true;
1519
+ process.argv = ['node', 'script.js', 'hello world how are you'];
1520
+ const argv = await parseArguments({});
1521
+ const config = await loadCliConfig({}, 'test-session', argv);
1522
+ expect(config.isInteractive()).toBe(false);
1523
+ expect(argv.query).toBe('hello world how are you');
1524
+ expect(argv.prompt).toBe('hello world how are you');
1525
+ });
1526
+ it('should handle multiple positional words with flags', async () => {
1527
+ process.stdin.isTTY = true;
1528
+ process.argv = [
1529
+ 'node',
1530
+ 'script.js',
1531
+ '--model',
1532
+ 'gemini-2.5-pro',
1533
+ 'write',
1534
+ 'a',
1535
+ 'function',
1536
+ 'to',
1537
+ 'sort',
1538
+ 'array',
1539
+ ];
1540
+ const argv = await parseArguments({});
1541
+ const config = await loadCliConfig({}, 'test-session', argv);
1542
+ expect(config.isInteractive()).toBe(false);
1543
+ expect(argv.query).toBe('write a function to sort array');
1544
+ expect(argv.model).toBe('gemini-2.5-pro');
1545
+ });
1546
+ it('should handle empty positional arguments', async () => {
1547
+ process.stdin.isTTY = true;
1548
+ process.argv = ['node', 'script.js', ''];
1549
+ const argv = await parseArguments({});
1550
+ const config = await loadCliConfig({}, 'test-session', argv);
1551
+ expect(config.isInteractive()).toBe(true);
1552
+ expect(argv.query).toBeUndefined();
1553
+ });
1554
+ it('should handle extensions flag with positional arguments correctly', async () => {
1555
+ process.stdin.isTTY = true;
1556
+ process.argv = [
1557
+ 'node',
1558
+ 'script.js',
1559
+ '-e',
1560
+ 'none',
1561
+ 'hello',
1562
+ 'world',
1563
+ 'how',
1564
+ 'are',
1565
+ 'you',
1566
+ ];
1567
+ const argv = await parseArguments({});
1568
+ const config = await loadCliConfig({}, 'test-session', argv);
1569
+ expect(config.isInteractive()).toBe(false);
1570
+ expect(argv.query).toBe('hello world how are you');
1571
+ expect(argv.extensions).toEqual(['none']);
1572
+ });
1573
+ it('should be interactive if no positional prompt words are provided with flags', async () => {
1574
+ process.stdin.isTTY = true;
1575
+ process.argv = ['node', 'script.js', '--model', 'gemini-2.5-pro'];
1576
+ const argv = await parseArguments({});
1577
+ const config = await loadCliConfig({}, 'test-session', argv);
1578
+ expect(config.isInteractive()).toBe(true);
1579
+ });
1580
+ });
1581
+ describe('loadCliConfig approval mode', () => {
1582
+ const originalArgv = process.argv;
1583
+ beforeEach(() => {
1584
+ vi.resetAllMocks();
1585
+ vi.mocked(os.homedir).mockReturnValue('/mock/home/user');
1586
+ vi.stubEnv('GEMINI_API_KEY', 'test-api-key');
1587
+ process.argv = ['node', 'script.js']; // Reset argv for each test
1588
+ vi.mocked(isWorkspaceTrusted).mockReturnValue({
1589
+ isTrusted: true,
1590
+ source: undefined,
1591
+ });
1592
+ vi.spyOn(ExtensionManager.prototype, 'getExtensions').mockReturnValue([]);
1593
+ });
1594
+ afterEach(() => {
1595
+ process.argv = originalArgv;
1596
+ vi.unstubAllEnvs();
1597
+ vi.restoreAllMocks();
1598
+ });
1599
+ it('should default to DEFAULT approval mode when no flags are set', async () => {
1600
+ process.argv = ['node', 'script.js'];
1601
+ const argv = await parseArguments({});
1602
+ const config = await loadCliConfig({}, 'test-session', argv);
1603
+ expect(config.getApprovalMode()).toBe(ServerConfig.ApprovalMode.DEFAULT);
1604
+ });
1605
+ it('should set YOLO approval mode when --yolo flag is used', async () => {
1606
+ process.argv = ['node', 'script.js', '--yolo'];
1607
+ const argv = await parseArguments({});
1608
+ const config = await loadCliConfig({}, 'test-session', argv);
1609
+ expect(config.getApprovalMode()).toBe(ServerConfig.ApprovalMode.YOLO);
1610
+ });
1611
+ it('should set YOLO approval mode when -y flag is used', async () => {
1612
+ process.argv = ['node', 'script.js', '-y'];
1613
+ const argv = await parseArguments({});
1614
+ const config = await loadCliConfig({}, 'test-session', argv);
1615
+ expect(config.getApprovalMode()).toBe(ServerConfig.ApprovalMode.YOLO);
1616
+ });
1617
+ it('should set DEFAULT approval mode when --approval-mode=default', async () => {
1618
+ process.argv = ['node', 'script.js', '--approval-mode', 'default'];
1619
+ const argv = await parseArguments({});
1620
+ const config = await loadCliConfig({}, 'test-session', argv);
1621
+ expect(config.getApprovalMode()).toBe(ServerConfig.ApprovalMode.DEFAULT);
1622
+ });
1623
+ it('should set AUTO_EDIT approval mode when --approval-mode=auto_edit', async () => {
1624
+ process.argv = ['node', 'script.js', '--approval-mode', 'auto_edit'];
1625
+ const argv = await parseArguments({});
1626
+ const config = await loadCliConfig({}, 'test-session', argv);
1627
+ expect(config.getApprovalMode()).toBe(ServerConfig.ApprovalMode.AUTO_EDIT);
1628
+ });
1629
+ it('should set YOLO approval mode when --approval-mode=yolo', async () => {
1630
+ process.argv = ['node', 'script.js', '--approval-mode', 'yolo'];
1631
+ const argv = await parseArguments({});
1632
+ const config = await loadCliConfig({}, 'test-session', argv);
1633
+ expect(config.getApprovalMode()).toBe(ServerConfig.ApprovalMode.YOLO);
1634
+ });
1635
+ it('should prioritize --approval-mode over --yolo when both would be valid (but validation prevents this)', async () => {
1636
+ // Note: This test documents the intended behavior, but in practice the validation
1637
+ // prevents both flags from being used together
1638
+ process.argv = ['node', 'script.js', '--approval-mode', 'default'];
1639
+ const argv = await parseArguments({});
1640
+ // Manually set yolo to true to simulate what would happen if validation didn't prevent it
1641
+ argv.yolo = true;
1642
+ const config = await loadCliConfig({}, 'test-session', argv);
1643
+ expect(config.getApprovalMode()).toBe(ServerConfig.ApprovalMode.DEFAULT);
1644
+ });
1645
+ it('should fall back to --yolo behavior when --approval-mode is not set', async () => {
1646
+ process.argv = ['node', 'script.js', '--yolo'];
1647
+ const argv = await parseArguments({});
1648
+ const config = await loadCliConfig({}, 'test-session', argv);
1649
+ expect(config.getApprovalMode()).toBe(ServerConfig.ApprovalMode.YOLO);
1650
+ });
1651
+ // --- Untrusted Folder Scenarios ---
1652
+ describe('when folder is NOT trusted', () => {
1653
+ beforeEach(() => {
1654
+ vi.mocked(isWorkspaceTrusted).mockReturnValue({
1655
+ isTrusted: false,
1656
+ source: 'file',
1657
+ });
1658
+ });
1659
+ it('should override --approval-mode=yolo to DEFAULT', async () => {
1660
+ process.argv = ['node', 'script.js', '--approval-mode', 'yolo'];
1661
+ const argv = await parseArguments({});
1662
+ const config = await loadCliConfig({}, 'test-session', argv);
1663
+ expect(config.getApprovalMode()).toBe(ServerConfig.ApprovalMode.DEFAULT);
1664
+ });
1665
+ it('should override --approval-mode=auto_edit to DEFAULT', async () => {
1666
+ process.argv = ['node', 'script.js', '--approval-mode', 'auto_edit'];
1667
+ const argv = await parseArguments({});
1668
+ const config = await loadCliConfig({}, 'test-session', argv);
1669
+ expect(config.getApprovalMode()).toBe(ServerConfig.ApprovalMode.DEFAULT);
1670
+ });
1671
+ it('should override --yolo flag to DEFAULT', async () => {
1672
+ process.argv = ['node', 'script.js', '--yolo'];
1673
+ const argv = await parseArguments({});
1674
+ const config = await loadCliConfig({}, 'test-session', argv);
1675
+ expect(config.getApprovalMode()).toBe(ServerConfig.ApprovalMode.DEFAULT);
1676
+ });
1677
+ it('should remain DEFAULT when --approval-mode=default', async () => {
1678
+ process.argv = ['node', 'script.js', '--approval-mode', 'default'];
1679
+ const argv = await parseArguments({});
1680
+ const config = await loadCliConfig({}, 'test-session', argv);
1681
+ expect(config.getApprovalMode()).toBe(ServerConfig.ApprovalMode.DEFAULT);
1682
+ });
1683
+ });
1684
+ });
1685
+ describe('loadCliConfig fileFiltering', () => {
1686
+ const originalArgv = process.argv;
1687
+ beforeEach(() => {
1688
+ vi.resetAllMocks();
1689
+ vi.mocked(os.homedir).mockReturnValue('/mock/home/user');
1690
+ vi.stubEnv('GEMINI_API_KEY', 'test-api-key');
1691
+ process.argv = ['node', 'script.js']; // Reset argv for each test
1692
+ vi.spyOn(ExtensionManager.prototype, 'getExtensions').mockReturnValue([]);
1693
+ });
1694
+ afterEach(() => {
1695
+ process.argv = originalArgv;
1696
+ vi.unstubAllEnvs();
1697
+ vi.restoreAllMocks();
1698
+ });
1699
+ const testCases = [
1700
+ {
1701
+ property: 'disableFuzzySearch',
1702
+ getter: (c) => c.getFileFilteringDisableFuzzySearch(),
1703
+ value: true,
1704
+ },
1705
+ {
1706
+ property: 'disableFuzzySearch',
1707
+ getter: (c) => c.getFileFilteringDisableFuzzySearch(),
1708
+ value: false,
1709
+ },
1710
+ {
1711
+ property: 'respectGitIgnore',
1712
+ getter: (c) => c.getFileFilteringRespectGitIgnore(),
1713
+ value: true,
1714
+ },
1715
+ {
1716
+ property: 'respectGitIgnore',
1717
+ getter: (c) => c.getFileFilteringRespectGitIgnore(),
1718
+ value: false,
1719
+ },
1720
+ {
1721
+ property: 'respectGeminiIgnore',
1722
+ getter: (c) => c.getFileFilteringRespectGeminiIgnore(),
1723
+ value: true,
1724
+ },
1725
+ {
1726
+ property: 'respectGeminiIgnore',
1727
+ getter: (c) => c.getFileFilteringRespectGeminiIgnore(),
1728
+ value: false,
1729
+ },
1730
+ {
1731
+ property: 'enableRecursiveFileSearch',
1732
+ getter: (c) => c.getEnableRecursiveFileSearch(),
1733
+ value: true,
1734
+ },
1735
+ {
1736
+ property: 'enableRecursiveFileSearch',
1737
+ getter: (c) => c.getEnableRecursiveFileSearch(),
1738
+ value: false,
1739
+ },
1740
+ ];
1741
+ it.each(testCases)('should pass $property from settings to config when $value', async ({ property, getter, value }) => {
1742
+ const settings = {
1743
+ context: {
1744
+ fileFiltering: { [property]: value },
1745
+ },
1746
+ };
1747
+ const argv = await parseArguments(settings);
1748
+ const config = await loadCliConfig(settings, 'test-session', argv);
1749
+ expect(getter(config)).toBe(value);
1750
+ });
1751
+ });
1752
+ describe('Output format', () => {
1753
+ beforeEach(() => {
1754
+ vi.spyOn(ExtensionManager.prototype, 'getExtensions').mockReturnValue([]);
1755
+ });
1756
+ afterEach(() => {
1757
+ vi.resetAllMocks();
1758
+ });
1759
+ it('should default to TEXT', async () => {
1760
+ process.argv = ['node', 'script.js'];
1761
+ const argv = await parseArguments({});
1762
+ const config = await loadCliConfig({}, 'test-session', argv);
1763
+ expect(config.getOutputFormat()).toBe(OutputFormat.TEXT);
1764
+ });
1765
+ it('should use the format from settings', async () => {
1766
+ process.argv = ['node', 'script.js'];
1767
+ const argv = await parseArguments({});
1768
+ const config = await loadCliConfig({ output: { format: OutputFormat.JSON } }, 'test-session', argv);
1769
+ expect(config.getOutputFormat()).toBe(OutputFormat.JSON);
1770
+ });
1771
+ it('should prioritize the format from argv', async () => {
1772
+ process.argv = ['node', 'script.js', '--output-format', 'json'];
1773
+ const argv = await parseArguments({});
1774
+ const config = await loadCliConfig({ output: { format: OutputFormat.JSON } }, 'test-session', argv);
1775
+ expect(config.getOutputFormat()).toBe(OutputFormat.JSON);
1776
+ });
1777
+ it('should accept stream-json as a valid output format', async () => {
1778
+ process.argv = ['node', 'script.js', '--output-format', 'stream-json'];
1779
+ const argv = await parseArguments({});
1780
+ const config = await loadCliConfig({}, 'test-session', argv);
1781
+ expect(config.getOutputFormat()).toBe(OutputFormat.STREAM_JSON);
1782
+ });
1783
+ it('should error on invalid --output-format argument', async () => {
1784
+ process.argv = ['node', 'script.js', '--output-format', 'yaml'];
1785
+ const mockExit = vi.spyOn(process, 'exit').mockImplementation(() => {
1786
+ throw new Error('process.exit called');
1787
+ });
1788
+ const mockConsoleError = vi
1789
+ .spyOn(console, 'error')
1790
+ .mockImplementation(() => { });
1791
+ await expect(parseArguments({})).rejects.toThrow('process.exit called');
1792
+ expect(mockConsoleError).toHaveBeenCalledWith(expect.stringContaining('Invalid values:'));
1793
+ mockExit.mockRestore();
1794
+ mockConsoleError.mockRestore();
1795
+ });
1796
+ });
1797
+ describe('parseArguments with positional prompt', () => {
1798
+ const originalArgv = process.argv;
1799
+ afterEach(() => {
1800
+ process.argv = originalArgv;
1801
+ });
1802
+ it('should throw an error when both a positional prompt and the --prompt flag are used', async () => {
1803
+ process.argv = [
1804
+ 'node',
1805
+ 'script.js',
1806
+ 'positional',
1807
+ 'prompt',
1808
+ '--prompt',
1809
+ 'test prompt',
1810
+ ];
1811
+ const mockExit = vi.spyOn(process, 'exit').mockImplementation(() => {
1812
+ throw new Error('process.exit called');
1813
+ });
1814
+ const mockConsoleError = vi
1815
+ .spyOn(console, 'error')
1816
+ .mockImplementation(() => { });
1817
+ await expect(parseArguments({})).rejects.toThrow('process.exit called');
1818
+ expect(mockConsoleError).toHaveBeenCalledWith(expect.stringContaining('Cannot use both a positional prompt and the --prompt (-p) flag together'));
1819
+ mockExit.mockRestore();
1820
+ mockConsoleError.mockRestore();
1821
+ });
1822
+ it('should correctly parse a positional prompt to query field', async () => {
1823
+ process.argv = ['node', 'script.js', 'positional', 'prompt'];
1824
+ const argv = await parseArguments({});
1825
+ expect(argv.query).toBe('positional prompt');
1826
+ // Since no explicit prompt flags are set and query doesn't start with @, should map to prompt (one-shot)
1827
+ expect(argv.prompt).toBe('positional prompt');
1828
+ expect(argv.promptInteractive).toBeUndefined();
1829
+ });
1830
+ it('should have correct positional argument description', async () => {
1831
+ // Test that the positional argument has the expected description
1832
+ const yargsInstance = await import('./config.js');
1833
+ // This test verifies that the positional 'query' argument is properly configured
1834
+ // with the description: "Positional prompt. Defaults to one-shot; use -i/--prompt-interactive for interactive."
1835
+ process.argv = ['node', 'script.js', 'test', 'query'];
1836
+ const argv = await yargsInstance.parseArguments({});
1837
+ expect(argv.query).toBe('test query');
1838
+ });
1839
+ it('should correctly parse a prompt from the --prompt flag', async () => {
1840
+ process.argv = ['node', 'script.js', '--prompt', 'test prompt'];
1841
+ const argv = await parseArguments({});
1842
+ expect(argv.prompt).toBe('test prompt');
1843
+ });
1844
+ });
1845
+ describe('Telemetry configuration via environment variables', () => {
1846
+ beforeEach(() => {
1847
+ vi.spyOn(ExtensionManager.prototype, 'getExtensions').mockReturnValue([]);
1848
+ });
1849
+ afterEach(() => {
1850
+ vi.resetAllMocks();
1851
+ });
1852
+ it('should prioritize CELL_TELEMETRY_ENABLED over settings', async () => {
1853
+ vi.stubEnv('CELL_TELEMETRY_ENABLED', 'true');
1854
+ process.argv = ['node', 'script.js'];
1855
+ const argv = await parseArguments({});
1856
+ const settings = { telemetry: { enabled: false } };
1857
+ const config = await loadCliConfig(settings, 'test-session', argv);
1858
+ expect(config.getTelemetryEnabled()).toBe(true);
1859
+ });
1860
+ it('should prioritize CELL_TELEMETRY_TARGET over settings', async () => {
1861
+ vi.stubEnv('CELL_TELEMETRY_TARGET', 'gcp');
1862
+ process.argv = ['node', 'script.js'];
1863
+ const argv = await parseArguments({});
1864
+ const settings = {
1865
+ telemetry: { target: ServerConfig.TelemetryTarget.LOCAL },
1866
+ };
1867
+ const config = await loadCliConfig(settings, 'test-session', argv);
1868
+ expect(config.getTelemetryTarget()).toBe('gcp');
1869
+ });
1870
+ it('should throw when CELL_TELEMETRY_TARGET is invalid', async () => {
1871
+ vi.stubEnv('CELL_TELEMETRY_TARGET', 'bogus');
1872
+ process.argv = ['node', 'script.js'];
1873
+ const argv = await parseArguments({});
1874
+ const settings = {
1875
+ telemetry: { target: ServerConfig.TelemetryTarget.GCP },
1876
+ };
1877
+ await expect(loadCliConfig(settings, 'test-session', argv)).rejects.toThrow(/Invalid telemetry configuration: .*Invalid telemetry target/i);
1878
+ vi.unstubAllEnvs();
1879
+ });
1880
+ it('should prioritize CELL_TELEMETRY_OTLP_ENDPOINT over settings and default env var', async () => {
1881
+ vi.stubEnv('OTEL_EXPORTER_OTLP_ENDPOINT', 'http://default.env.com');
1882
+ vi.stubEnv('CELL_TELEMETRY_OTLP_ENDPOINT', 'http://gemini.env.com');
1883
+ process.argv = ['node', 'script.js'];
1884
+ const argv = await parseArguments({});
1885
+ const settings = {
1886
+ telemetry: { otlpEndpoint: 'http://settings.com' },
1887
+ };
1888
+ const config = await loadCliConfig(settings, 'test-session', argv);
1889
+ expect(config.getTelemetryOtlpEndpoint()).toBe('http://gemini.env.com');
1890
+ });
1891
+ it('should prioritize CELL_TELEMETRY_OTLP_PROTOCOL over settings', async () => {
1892
+ vi.stubEnv('CELL_TELEMETRY_OTLP_PROTOCOL', 'http');
1893
+ process.argv = ['node', 'script.js'];
1894
+ const argv = await parseArguments({});
1895
+ const settings = { telemetry: { otlpProtocol: 'grpc' } };
1896
+ const config = await loadCliConfig(settings, 'test-session', argv);
1897
+ expect(config.getTelemetryOtlpProtocol()).toBe('http');
1898
+ });
1899
+ it('should prioritize CELL_TELEMETRY_LOG_PROMPTS over settings', async () => {
1900
+ vi.stubEnv('CELL_TELEMETRY_LOG_PROMPTS', 'false');
1901
+ process.argv = ['node', 'script.js'];
1902
+ const argv = await parseArguments({});
1903
+ const settings = { telemetry: { logPrompts: true } };
1904
+ const config = await loadCliConfig(settings, 'test-session', argv);
1905
+ expect(config.getTelemetryLogPromptsEnabled()).toBe(false);
1906
+ });
1907
+ it('should prioritize CELL_TELEMETRY_OUTFILE over settings', async () => {
1908
+ vi.stubEnv('CELL_TELEMETRY_OUTFILE', '/gemini/env/telemetry.log');
1909
+ process.argv = ['node', 'script.js'];
1910
+ const argv = await parseArguments({});
1911
+ const settings = {
1912
+ telemetry: { outfile: '/settings/telemetry.log' },
1913
+ };
1914
+ const config = await loadCliConfig(settings, 'test-session', argv);
1915
+ expect(config.getTelemetryOutfile()).toBe('/gemini/env/telemetry.log');
1916
+ });
1917
+ it('should prioritize CELL_TELEMETRY_USE_COLLECTOR over settings', async () => {
1918
+ vi.stubEnv('CELL_TELEMETRY_USE_COLLECTOR', 'true');
1919
+ process.argv = ['node', 'script.js'];
1920
+ const argv = await parseArguments({});
1921
+ const settings = { telemetry: { useCollector: false } };
1922
+ const config = await loadCliConfig(settings, 'test-session', argv);
1923
+ expect(config.getTelemetryUseCollector()).toBe(true);
1924
+ });
1925
+ it('should use settings value when CELL_TELEMETRY_ENABLED is not set', async () => {
1926
+ vi.stubEnv('CELL_TELEMETRY_ENABLED', undefined);
1927
+ process.argv = ['node', 'script.js'];
1928
+ const argv = await parseArguments({});
1929
+ const settings = { telemetry: { enabled: true } };
1930
+ const config = await loadCliConfig(settings, 'test-session', argv);
1931
+ expect(config.getTelemetryEnabled()).toBe(true);
1932
+ });
1933
+ it('should use settings value when CELL_TELEMETRY_TARGET is not set', async () => {
1934
+ vi.stubEnv('CELL_TELEMETRY_TARGET', undefined);
1935
+ process.argv = ['node', 'script.js'];
1936
+ const argv = await parseArguments({});
1937
+ const settings = {
1938
+ telemetry: { target: ServerConfig.TelemetryTarget.LOCAL },
1939
+ };
1940
+ const config = await loadCliConfig(settings, 'test-session', argv);
1941
+ expect(config.getTelemetryTarget()).toBe('local');
1942
+ });
1943
+ it("should treat CELL_TELEMETRY_ENABLED='1' as true", async () => {
1944
+ vi.stubEnv('CELL_TELEMETRY_ENABLED', '1');
1945
+ process.argv = ['node', 'script.js'];
1946
+ const argv = await parseArguments({});
1947
+ const config = await loadCliConfig({}, 'test-session', argv);
1948
+ expect(config.getTelemetryEnabled()).toBe(true);
1949
+ });
1950
+ it("should treat CELL_TELEMETRY_ENABLED='0' as false", async () => {
1951
+ vi.stubEnv('CELL_TELEMETRY_ENABLED', '0');
1952
+ process.argv = ['node', 'script.js'];
1953
+ const argv = await parseArguments({});
1954
+ const config = await loadCliConfig({ telemetry: { enabled: true } }, 'test-session', argv);
1955
+ expect(config.getTelemetryEnabled()).toBe(false);
1956
+ });
1957
+ it("should treat CELL_TELEMETRY_LOG_PROMPTS='1' as true", async () => {
1958
+ vi.stubEnv('CELL_TELEMETRY_LOG_PROMPTS', '1');
1959
+ process.argv = ['node', 'script.js'];
1960
+ const argv = await parseArguments({});
1961
+ const config = await loadCliConfig({}, 'test-session', argv);
1962
+ expect(config.getTelemetryLogPromptsEnabled()).toBe(true);
1963
+ });
1964
+ it("should treat CELL_TELEMETRY_LOG_PROMPTS='false' as false", async () => {
1965
+ vi.stubEnv('CELL_TELEMETRY_LOG_PROMPTS', 'false');
1966
+ process.argv = ['node', 'script.js'];
1967
+ const argv = await parseArguments({});
1968
+ const config = await loadCliConfig({ telemetry: { logPrompts: true } }, 'test-session', argv);
1969
+ expect(config.getTelemetryLogPromptsEnabled()).toBe(false);
1970
+ });
1971
+ });
1972
+ //# sourceMappingURL=config.test.js.map