@google/gemini-cli 0.25.0-preview.0 → 0.26.0-nightly.20260119.20580d754

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 (319) hide show
  1. package/dist/google-gemini-cli-0.26.0-nightly.20260115.6cb3ae4e0.tgz +0 -0
  2. package/dist/package.json +4 -3
  3. package/dist/src/commands/extensions/configure.js +8 -1
  4. package/dist/src/commands/extensions/configure.js.map +1 -1
  5. package/dist/src/commands/hooks/migrate.js +1 -1
  6. package/dist/src/commands/hooks/migrate.js.map +1 -1
  7. package/dist/src/commands/mcp/list.js +2 -2
  8. package/dist/src/commands/mcp/list.js.map +1 -1
  9. package/dist/src/commands/mcp/list.test.js +25 -8
  10. package/dist/src/commands/mcp/list.test.js.map +1 -1
  11. package/dist/src/commands/skills/disable.js +6 -4
  12. package/dist/src/commands/skills/disable.js.map +1 -1
  13. package/dist/src/commands/skills/disable.test.js +16 -0
  14. package/dist/src/commands/skills/disable.test.js.map +1 -1
  15. package/dist/src/commands/skills/enable.test.js +3 -3
  16. package/dist/src/commands/skills/enable.test.js.map +1 -1
  17. package/dist/src/commands/skills/install.d.ts +1 -0
  18. package/dist/src/commands/skills/install.js +17 -2
  19. package/dist/src/commands/skills/install.js.map +1 -1
  20. package/dist/src/commands/skills/install.test.js +43 -5
  21. package/dist/src/commands/skills/install.test.js.map +1 -1
  22. package/dist/src/config/config.d.ts +3 -3
  23. package/dist/src/config/config.integration.test.js +3 -2
  24. package/dist/src/config/config.integration.test.js.map +1 -1
  25. package/dist/src/config/config.js +37 -26
  26. package/dist/src/config/config.js.map +1 -1
  27. package/dist/src/config/config.test.js +361 -280
  28. package/dist/src/config/config.test.js.map +1 -1
  29. package/dist/src/config/extension-manager-agents.test.js +3 -4
  30. package/dist/src/config/extension-manager-agents.test.js.map +1 -1
  31. package/dist/src/config/extension-manager-scope.test.js +13 -15
  32. package/dist/src/config/extension-manager-scope.test.js.map +1 -1
  33. package/dist/src/config/extension-manager-skills.test.js +5 -7
  34. package/dist/src/config/extension-manager-skills.test.js.map +1 -1
  35. package/dist/src/config/extension-manager.d.ts +2 -2
  36. package/dist/src/config/extension-manager.js +16 -11
  37. package/dist/src/config/extension-manager.js.map +1 -1
  38. package/dist/src/config/extension.test.js +13 -21
  39. package/dist/src/config/extension.test.js.map +1 -1
  40. package/dist/src/config/extensions/consent.d.ts +4 -0
  41. package/dist/src/config/extensions/consent.js +40 -16
  42. package/dist/src/config/extensions/consent.js.map +1 -1
  43. package/dist/src/config/extensions/consent.test.js +31 -7
  44. package/dist/src/config/extensions/consent.test.js.map +1 -1
  45. package/dist/src/config/extensions/extensionUpdates.test.js +5 -2
  46. package/dist/src/config/extensions/extensionUpdates.test.js.map +1 -1
  47. package/dist/src/config/keyBindings.d.ts +58 -59
  48. package/dist/src/config/keyBindings.js +131 -135
  49. package/dist/src/config/keyBindings.js.map +1 -1
  50. package/dist/src/config/keyBindings.test.js +3 -8
  51. package/dist/src/config/keyBindings.test.js.map +1 -1
  52. package/dist/src/config/policy-engine.integration.test.js +15 -0
  53. package/dist/src/config/policy-engine.integration.test.js.map +1 -1
  54. package/dist/src/config/settings.d.ts +24 -6
  55. package/dist/src/config/settings.js +150 -6
  56. package/dist/src/config/settings.js.map +1 -1
  57. package/dist/src/config/settings.test.js +258 -3
  58. package/dist/src/config/settings.test.js.map +1 -1
  59. package/dist/src/config/settingsSchema.d.ts +53 -20
  60. package/dist/src/config/settingsSchema.js +48 -22
  61. package/dist/src/config/settingsSchema.js.map +1 -1
  62. package/dist/src/config/settingsSchema.test.js +22 -2
  63. package/dist/src/config/settingsSchema.test.js.map +1 -1
  64. package/dist/src/config/skills-backward-compatibility.test.js +99 -0
  65. package/dist/src/config/skills-backward-compatibility.test.js.map +1 -0
  66. package/dist/src/core/initializer.js +2 -2
  67. package/dist/src/core/initializer.js.map +1 -1
  68. package/dist/src/core/initializer.test.js.map +1 -1
  69. package/dist/src/core/theme.js +1 -1
  70. package/dist/src/core/theme.js.map +1 -1
  71. package/dist/src/core/theme.test.js.map +1 -1
  72. package/dist/src/gemini.js +51 -19
  73. package/dist/src/gemini.js.map +1 -1
  74. package/dist/src/gemini.test.js +48 -61
  75. package/dist/src/gemini.test.js.map +1 -1
  76. package/dist/src/generated/git-commit.d.ts +2 -2
  77. package/dist/src/generated/git-commit.js +2 -2
  78. package/dist/src/generated/git-commit.js.map +1 -1
  79. package/dist/src/nonInteractiveCli.d.ts +1 -2
  80. package/dist/src/nonInteractiveCli.js +1 -16
  81. package/dist/src/nonInteractiveCli.js.map +1 -1
  82. package/dist/src/nonInteractiveCli.test.js +0 -39
  83. package/dist/src/nonInteractiveCli.test.js.map +1 -1
  84. package/dist/src/test-utils/mockCommandContext.js +7 -1
  85. package/dist/src/test-utils/mockCommandContext.js.map +1 -1
  86. package/dist/src/test-utils/render.js +2 -0
  87. package/dist/src/test-utils/render.js.map +1 -1
  88. package/dist/src/ui/App.test.js +2 -2
  89. package/dist/src/ui/App.test.js.map +1 -1
  90. package/dist/src/ui/AppContainer.js +41 -35
  91. package/dist/src/ui/AppContainer.js.map +1 -1
  92. package/dist/src/ui/AppContainer.test.js +33 -22
  93. package/dist/src/ui/AppContainer.test.js.map +1 -1
  94. package/dist/src/ui/auth/ApiAuthDialog.test.js +0 -1
  95. package/dist/src/ui/auth/ApiAuthDialog.test.js.map +1 -1
  96. package/dist/src/ui/auth/AuthDialog.js +5 -5
  97. package/dist/src/ui/auth/AuthDialog.js.map +1 -1
  98. package/dist/src/ui/auth/AuthDialog.test.js.map +1 -1
  99. package/dist/src/ui/auth/LoginWithGoogleRestartDialog.test.js +0 -2
  100. package/dist/src/ui/auth/LoginWithGoogleRestartDialog.test.js.map +1 -1
  101. package/dist/src/ui/auth/useAuth.js +3 -3
  102. package/dist/src/ui/auth/useAuth.js.map +1 -1
  103. package/dist/src/ui/commands/aboutCommand.js +1 -1
  104. package/dist/src/ui/commands/aboutCommand.js.map +1 -1
  105. package/dist/src/ui/commands/agentsCommand.js +158 -1
  106. package/dist/src/ui/commands/agentsCommand.js.map +1 -1
  107. package/dist/src/ui/commands/agentsCommand.test.js +140 -1
  108. package/dist/src/ui/commands/agentsCommand.test.js.map +1 -1
  109. package/dist/src/ui/commands/hooksCommand.js +23 -23
  110. package/dist/src/ui/commands/hooksCommand.js.map +1 -1
  111. package/dist/src/ui/commands/hooksCommand.test.js +12 -15
  112. package/dist/src/ui/commands/hooksCommand.test.js.map +1 -1
  113. package/dist/src/ui/commands/policiesCommand.js +3 -0
  114. package/dist/src/ui/commands/policiesCommand.js.map +1 -1
  115. package/dist/src/ui/commands/policiesCommand.test.js +2 -1
  116. package/dist/src/ui/commands/policiesCommand.test.js.map +1 -1
  117. package/dist/src/ui/commands/skillsCommand.test.js +14 -7
  118. package/dist/src/ui/commands/skillsCommand.test.js.map +1 -1
  119. package/dist/src/ui/components/AdminSettingsChangedDialog.d.ts +6 -0
  120. package/dist/src/ui/components/AdminSettingsChangedDialog.js +22 -0
  121. package/dist/src/ui/components/AdminSettingsChangedDialog.js.map +1 -0
  122. package/dist/src/ui/components/AdminSettingsChangedDialog.test.d.ts +6 -0
  123. package/dist/src/ui/components/AdminSettingsChangedDialog.test.js +43 -0
  124. package/dist/src/ui/components/AdminSettingsChangedDialog.test.js.map +1 -0
  125. package/dist/src/ui/components/AppHeader.js +1 -1
  126. package/dist/src/ui/components/AppHeader.js.map +1 -1
  127. package/dist/src/ui/components/Composer.js +4 -6
  128. package/dist/src/ui/components/Composer.js.map +1 -1
  129. package/dist/src/ui/components/Composer.test.js +17 -9
  130. package/dist/src/ui/components/Composer.test.js.map +1 -1
  131. package/dist/src/ui/components/DialogManager.js +4 -4
  132. package/dist/src/ui/components/DialogManager.js.map +1 -1
  133. package/dist/src/ui/components/DialogManager.test.js +0 -14
  134. package/dist/src/ui/components/DialogManager.test.js.map +1 -1
  135. package/dist/src/ui/components/EditorSettingsDialog.js +3 -3
  136. package/dist/src/ui/components/EditorSettingsDialog.js.map +1 -1
  137. package/dist/src/ui/components/Footer.js +5 -5
  138. package/dist/src/ui/components/Footer.js.map +1 -1
  139. package/dist/src/ui/components/Help.js +2 -1
  140. package/dist/src/ui/components/Help.js.map +1 -1
  141. package/dist/src/ui/components/HistoryItemDisplay.test.js +1 -0
  142. package/dist/src/ui/components/HistoryItemDisplay.test.js.map +1 -1
  143. package/dist/src/ui/components/InputPrompt.js +6 -9
  144. package/dist/src/ui/components/InputPrompt.js.map +1 -1
  145. package/dist/src/ui/components/InputPrompt.test.js +8 -14
  146. package/dist/src/ui/components/InputPrompt.test.js.map +1 -1
  147. package/dist/src/ui/components/MultiFolderTrustDialog.test.js +0 -1
  148. package/dist/src/ui/components/MultiFolderTrustDialog.test.js.map +1 -1
  149. package/dist/src/ui/components/RewindConfirmation.d.ts +21 -0
  150. package/dist/src/ui/components/RewindConfirmation.js +63 -0
  151. package/dist/src/ui/components/RewindConfirmation.js.map +1 -0
  152. package/dist/src/ui/components/RewindConfirmation.test.d.ts +6 -0
  153. package/dist/src/ui/components/RewindConfirmation.test.js +53 -0
  154. package/dist/src/ui/components/RewindConfirmation.test.js.map +1 -0
  155. package/dist/src/ui/components/RewindViewer.d.ts +15 -0
  156. package/dist/src/ui/components/RewindViewer.js +79 -0
  157. package/dist/src/ui/components/RewindViewer.js.map +1 -0
  158. package/dist/src/ui/components/RewindViewer.test.d.ts +6 -0
  159. package/dist/src/ui/components/RewindViewer.test.js +239 -0
  160. package/dist/src/ui/components/RewindViewer.test.js.map +1 -0
  161. package/dist/src/ui/components/SessionBrowser.test.js +0 -1
  162. package/dist/src/ui/components/SessionBrowser.test.js.map +1 -1
  163. package/dist/src/ui/components/SettingsDialog.js +4 -4
  164. package/dist/src/ui/components/SettingsDialog.js.map +1 -1
  165. package/dist/src/ui/components/SettingsDialog.test.js +14 -14
  166. package/dist/src/ui/components/SettingsDialog.test.js.map +1 -1
  167. package/dist/src/ui/components/StatusDisplay.js +3 -4
  168. package/dist/src/ui/components/StatusDisplay.js.map +1 -1
  169. package/dist/src/ui/components/ThemeDialog.js +2 -2
  170. package/dist/src/ui/components/ThemeDialog.js.map +1 -1
  171. package/dist/src/ui/components/messages/ToolConfirmationMessage.js +8 -3
  172. package/dist/src/ui/components/messages/ToolConfirmationMessage.js.map +1 -1
  173. package/dist/src/ui/components/messages/ToolConfirmationMessage.test.js +18 -0
  174. package/dist/src/ui/components/messages/ToolConfirmationMessage.test.js.map +1 -1
  175. package/dist/src/ui/components/shared/TextInput.test.js +0 -8
  176. package/dist/src/ui/components/shared/TextInput.test.js.map +1 -1
  177. package/dist/src/ui/components/shared/performance.test.d.ts +1 -0
  178. package/dist/src/ui/components/shared/performance.test.js +67 -0
  179. package/dist/src/ui/components/shared/performance.test.js.map +1 -0
  180. package/dist/src/ui/components/shared/text-buffer.d.ts +1 -0
  181. package/dist/src/ui/components/shared/text-buffer.js +80 -54
  182. package/dist/src/ui/components/shared/text-buffer.js.map +1 -1
  183. package/dist/src/ui/components/shared/text-buffer.test.js +97 -21
  184. package/dist/src/ui/components/shared/text-buffer.test.js.map +1 -1
  185. package/dist/src/ui/constants/tips.js +150 -150
  186. package/dist/src/ui/constants/tips.js.map +1 -1
  187. package/dist/src/ui/constants/wittyPhrases.js +118 -118
  188. package/dist/src/ui/constants/wittyPhrases.js.map +1 -1
  189. package/dist/src/ui/constants.d.ts +2 -0
  190. package/dist/src/ui/constants.js +2 -0
  191. package/dist/src/ui/constants.js.map +1 -1
  192. package/dist/src/ui/contexts/KeypressContext.d.ts +0 -1
  193. package/dist/src/ui/contexts/KeypressContext.js +2 -6
  194. package/dist/src/ui/contexts/KeypressContext.js.map +1 -1
  195. package/dist/src/ui/contexts/KeypressContext.test.js +2 -10
  196. package/dist/src/ui/contexts/KeypressContext.test.js.map +1 -1
  197. package/dist/src/ui/contexts/UIActionsContext.d.ts +1 -0
  198. package/dist/src/ui/contexts/UIActionsContext.js.map +1 -1
  199. package/dist/src/ui/contexts/UIStateContext.d.ts +2 -2
  200. package/dist/src/ui/contexts/UIStateContext.js.map +1 -1
  201. package/dist/src/ui/contexts/VimModeContext.js +3 -3
  202. package/dist/src/ui/contexts/VimModeContext.js.map +1 -1
  203. package/dist/src/ui/hooks/slashCommandProcessor.d.ts +0 -5
  204. package/dist/src/ui/hooks/slashCommandProcessor.js +42 -11
  205. package/dist/src/ui/hooks/slashCommandProcessor.js.map +1 -1
  206. package/dist/src/ui/hooks/slashCommandProcessor.test.js +1 -144
  207. package/dist/src/ui/hooks/slashCommandProcessor.test.js.map +1 -1
  208. package/dist/src/ui/hooks/useAlternateBuffer.js +1 -1
  209. package/dist/src/ui/hooks/useAlternateBuffer.js.map +1 -1
  210. package/dist/src/ui/hooks/useAtCompletion.js +21 -1
  211. package/dist/src/ui/hooks/useAtCompletion.js.map +1 -1
  212. package/dist/src/ui/hooks/useAtCompletion.test.js +4 -4
  213. package/dist/src/ui/hooks/useAtCompletion.test.js.map +1 -1
  214. package/dist/src/ui/hooks/useAtCompletion_agents.test.js +2 -0
  215. package/dist/src/ui/hooks/useAtCompletion_agents.test.js.map +1 -1
  216. package/dist/src/ui/hooks/useFolderTrust.js +1 -1
  217. package/dist/src/ui/hooks/useFolderTrust.js.map +1 -1
  218. package/dist/src/ui/hooks/useGeminiStream.js +17 -5
  219. package/dist/src/ui/hooks/useGeminiStream.js.map +1 -1
  220. package/dist/src/ui/hooks/useGeminiStream.test.js +103 -1
  221. package/dist/src/ui/hooks/useGeminiStream.test.js.map +1 -1
  222. package/dist/src/ui/hooks/useKeypress.test.js +11 -13
  223. package/dist/src/ui/hooks/useKeypress.test.js.map +1 -1
  224. package/dist/src/ui/hooks/usePermissionsModifyTrust.js +1 -1
  225. package/dist/src/ui/hooks/usePermissionsModifyTrust.js.map +1 -1
  226. package/dist/src/ui/hooks/useReactToolScheduler.d.ts +1 -1
  227. package/dist/src/ui/hooks/useReactToolScheduler.js +1 -1
  228. package/dist/src/ui/hooks/useReactToolScheduler.js.map +1 -1
  229. package/dist/src/ui/hooks/useSelectionList.test.js +0 -3
  230. package/dist/src/ui/hooks/useSelectionList.test.js.map +1 -1
  231. package/dist/src/ui/hooks/useShowMemoryCommand.js +1 -1
  232. package/dist/src/ui/hooks/useShowMemoryCommand.js.map +1 -1
  233. package/dist/src/ui/hooks/useThemeCommand.js +4 -4
  234. package/dist/src/ui/hooks/useThemeCommand.js.map +1 -1
  235. package/dist/src/ui/hooks/useToolScheduler.test.js +62 -46
  236. package/dist/src/ui/hooks/useToolScheduler.test.js.map +1 -1
  237. package/dist/src/ui/hooks/vim.js +0 -1
  238. package/dist/src/ui/hooks/vim.js.map +1 -1
  239. package/dist/src/ui/hooks/vim.test.js +0 -1
  240. package/dist/src/ui/hooks/vim.test.js.map +1 -1
  241. package/dist/src/ui/keyMatchers.js +1 -16
  242. package/dist/src/ui/keyMatchers.js.map +1 -1
  243. package/dist/src/ui/keyMatchers.test.js +2 -14
  244. package/dist/src/ui/keyMatchers.test.js.map +1 -1
  245. package/dist/src/ui/types.d.ts +1 -5
  246. package/dist/src/ui/types.js.map +1 -1
  247. package/dist/src/ui/utils/CodeColorizer.js +1 -1
  248. package/dist/src/ui/utils/CodeColorizer.js.map +1 -1
  249. package/dist/src/ui/utils/commandUtils.js +31 -6
  250. package/dist/src/ui/utils/commandUtils.js.map +1 -1
  251. package/dist/src/ui/utils/commandUtils.test.js +71 -10
  252. package/dist/src/ui/utils/commandUtils.test.js.map +1 -1
  253. package/dist/src/ui/utils/formatters.d.ts +9 -0
  254. package/dist/src/ui/utils/formatters.js +26 -0
  255. package/dist/src/ui/utils/formatters.js.map +1 -1
  256. package/dist/src/ui/utils/formatters.test.js +70 -2
  257. package/dist/src/ui/utils/formatters.test.js.map +1 -1
  258. package/dist/src/ui/utils/highlight.js +18 -1
  259. package/dist/src/ui/utils/highlight.js.map +1 -1
  260. package/dist/src/ui/utils/highlight.test.js +2 -2
  261. package/dist/src/ui/utils/highlight.test.js.map +1 -1
  262. package/dist/src/ui/utils/textUtils.d.ts +0 -1
  263. package/dist/src/ui/utils/textUtils.js +17 -12
  264. package/dist/src/ui/utils/textUtils.js.map +1 -1
  265. package/dist/src/ui/utils/textUtils.test.js +1 -0
  266. package/dist/src/ui/utils/textUtils.test.js.map +1 -1
  267. package/dist/src/ui/utils/ui-sizing.js +1 -1
  268. package/dist/src/ui/utils/ui-sizing.js.map +1 -1
  269. package/dist/src/ui/utils/updateCheck.js +1 -1
  270. package/dist/src/ui/utils/updateCheck.js.map +1 -1
  271. package/dist/src/ui/utils/updateCheck.test.js +3 -3
  272. package/dist/src/ui/utils/updateCheck.test.js.map +1 -1
  273. package/dist/src/utils/agentSettings.d.ts +31 -0
  274. package/dist/src/utils/agentSettings.js +103 -0
  275. package/dist/src/utils/agentSettings.js.map +1 -0
  276. package/dist/src/utils/agentUtils.d.ts +15 -0
  277. package/dist/src/utils/agentUtils.js +50 -0
  278. package/dist/src/utils/agentUtils.js.map +1 -0
  279. package/dist/src/utils/agentUtils.test.d.ts +6 -0
  280. package/dist/src/utils/agentUtils.test.js +121 -0
  281. package/dist/src/utils/agentUtils.test.js.map +1 -0
  282. package/dist/src/utils/handleAutoUpdate.js +4 -4
  283. package/dist/src/utils/handleAutoUpdate.js.map +1 -1
  284. package/dist/src/utils/handleAutoUpdate.test.js +8 -4
  285. package/dist/src/utils/handleAutoUpdate.test.js.map +1 -1
  286. package/dist/src/utils/installationInfo.d.ts +1 -1
  287. package/dist/src/utils/installationInfo.js +13 -13
  288. package/dist/src/utils/installationInfo.js.map +1 -1
  289. package/dist/src/utils/installationInfo.test.js +28 -20
  290. package/dist/src/utils/installationInfo.test.js.map +1 -1
  291. package/dist/src/utils/relaunch.d.ts +2 -1
  292. package/dist/src/utils/relaunch.js +6 -3
  293. package/dist/src/utils/relaunch.js.map +1 -1
  294. package/dist/src/utils/settingsUtils.d.ts +7 -0
  295. package/dist/src/utils/settingsUtils.js +17 -0
  296. package/dist/src/utils/settingsUtils.js.map +1 -1
  297. package/dist/src/utils/settingsUtils.test.js +33 -33
  298. package/dist/src/utils/settingsUtils.test.js.map +1 -1
  299. package/dist/src/utils/skillUtils.d.ts +2 -1
  300. package/dist/src/utils/skillUtils.js +58 -56
  301. package/dist/src/utils/skillUtils.js.map +1 -1
  302. package/dist/src/utils/skillUtils.test.js +13 -0
  303. package/dist/src/utils/skillUtils.test.js.map +1 -1
  304. package/dist/src/utils/terminalTheme.js +4 -4
  305. package/dist/src/utils/terminalTheme.js.map +1 -1
  306. package/dist/src/validateNonInterActiveAuth.js +1 -1
  307. package/dist/src/validateNonInterActiveAuth.js.map +1 -1
  308. package/dist/src/validateNonInterActiveAuth.test.js +2 -4
  309. package/dist/src/validateNonInterActiveAuth.test.js.map +1 -1
  310. package/dist/src/zed-integration/zedIntegration.js +8 -3
  311. package/dist/src/zed-integration/zedIntegration.js.map +1 -1
  312. package/dist/tsconfig.tsbuildinfo +1 -1
  313. package/package.json +5 -4
  314. package/dist/src/ui/components/ShellConfirmationDialog.d.ts +0 -15
  315. package/dist/src/ui/components/ShellConfirmationDialog.js +0 -49
  316. package/dist/src/ui/components/ShellConfirmationDialog.js.map +0 -1
  317. package/dist/src/ui/components/ShellConfirmationDialog.test.js +0 -40
  318. package/dist/src/ui/components/ShellConfirmationDialog.test.js.map +0 -1
  319. /package/dist/src/{ui/components/ShellConfirmationDialog.test.d.ts → config/skills-backward-compatibility.test.d.ts} +0 -0
@@ -8,6 +8,7 @@ import * as os from 'node:os';
8
8
  import * as path from 'node:path';
9
9
  import { DEFAULT_FILE_FILTERING_OPTIONS, OutputFormat, SHELL_TOOL_NAME, WRITE_FILE_TOOL_NAME, EDIT_TOOL_NAME, WEB_FETCH_TOOL_NAME, debugLogger, ApprovalMode, } from '@google/gemini-cli-core';
10
10
  import { loadCliConfig, parseArguments } from './config.js';
11
+ import { createTestMergedSettings } from './settings.js';
11
12
  import * as ServerConfig from '@google/gemini-cli-core';
12
13
  import { isWorkspaceTrusted } from './trustedFolders.js';
13
14
  import { ExtensionManager } from './extension-manager.js';
@@ -146,7 +147,7 @@ describe('parseArguments', () => {
146
147
  const mockConsoleError = vi
147
148
  .spyOn(console, 'error')
148
149
  .mockImplementation(() => { });
149
- await expect(parseArguments({})).rejects.toThrow('process.exit called');
150
+ await expect(parseArguments(createTestMergedSettings())).rejects.toThrow('process.exit called');
150
151
  expect(mockConsoleError).toHaveBeenCalledWith(expect.stringContaining('Cannot use both --prompt (-p) and --prompt-interactive (-i) together'));
151
152
  mockExit.mockRestore();
152
153
  mockConsoleError.mockRestore();
@@ -169,7 +170,7 @@ describe('parseArguments', () => {
169
170
  },
170
171
  ])('$description', async ({ argv, expected }) => {
171
172
  process.argv = argv;
172
- const parsedArgs = await parseArguments({});
173
+ const parsedArgs = await parseArguments(createTestMergedSettings());
173
174
  expect(parsedArgs.prompt).toBe(expected.prompt);
174
175
  expect(parsedArgs.promptInteractive).toBe(expected.promptInteractive);
175
176
  });
@@ -282,7 +283,7 @@ describe('parseArguments', () => {
282
283
  },
283
284
  ])('$description', async ({ argv, expectedQuery, expectedModel, debug }) => {
284
285
  process.argv = argv;
285
- const parsedArgs = await parseArguments({});
286
+ const parsedArgs = await parseArguments(createTestMergedSettings());
286
287
  expect(parsedArgs.query).toBe(expectedQuery);
287
288
  expect(parsedArgs.prompt).toBe(expectedQuery);
288
289
  expect(parsedArgs.promptInteractive).toBeUndefined();
@@ -311,7 +312,7 @@ describe('parseArguments', () => {
311
312
  const mockConsoleError = vi
312
313
  .spyOn(console, 'error')
313
314
  .mockImplementation(() => { });
314
- await expect(parseArguments({})).rejects.toThrow('process.exit called');
315
+ await expect(parseArguments(createTestMergedSettings())).rejects.toThrow('process.exit called');
315
316
  expect(mockConsoleError).toHaveBeenCalledWith(expect.stringContaining('Cannot use both --yolo (-y) and --approval-mode together. Use --approval-mode=yolo instead.'));
316
317
  mockExit.mockRestore();
317
318
  mockConsoleError.mockRestore();
@@ -329,7 +330,7 @@ describe('parseArguments', () => {
329
330
  },
330
331
  ])('$description', async ({ argv, expected }) => {
331
332
  process.argv = argv;
332
- const parsedArgs = await parseArguments({});
333
+ const parsedArgs = await parseArguments(createTestMergedSettings());
333
334
  expect(parsedArgs.approvalMode).toBe(expected.approvalMode);
334
335
  expect(parsedArgs.yolo).toBe(expected.yolo);
335
336
  });
@@ -344,7 +345,7 @@ describe('parseArguments', () => {
344
345
  const debugErrorSpy = vi
345
346
  .spyOn(debugLogger, 'error')
346
347
  .mockImplementation(() => { });
347
- await expect(parseArguments({})).rejects.toThrow('process.exit called');
348
+ await expect(parseArguments(createTestMergedSettings())).rejects.toThrow('process.exit called');
348
349
  expect(debugErrorSpy).toHaveBeenCalledWith(expect.stringContaining('Invalid values:'));
349
350
  expect(mockConsoleError).toHaveBeenCalled();
350
351
  mockExit.mockRestore();
@@ -356,7 +357,7 @@ describe('parseArguments', () => {
356
357
  process.stdin.isTTY = false;
357
358
  process.argv = ['node', 'script.js', '--resume', 'session-id'];
358
359
  try {
359
- const argv = await parseArguments({});
360
+ const argv = await parseArguments(createTestMergedSettings());
360
361
  expect(argv.resume).toBe('session-id');
361
362
  }
362
363
  finally {
@@ -368,7 +369,7 @@ describe('parseArguments', () => {
368
369
  process.stdin.isTTY = true; // Make it interactive to avoid validation error
369
370
  process.argv = ['node', 'script.js', '--resume'];
370
371
  try {
371
- const argv = await parseArguments({});
372
+ const argv = await parseArguments(createTestMergedSettings());
372
373
  expect(argv.resume).toBe(RESUME_LATEST);
373
374
  expect(argv.resume).toBe('latest');
374
375
  }
@@ -383,7 +384,7 @@ describe('parseArguments', () => {
383
384
  '--allowed-tools',
384
385
  'read_file,ShellTool(git status)',
385
386
  ];
386
- const argv = await parseArguments({});
387
+ const argv = await parseArguments(createTestMergedSettings());
387
388
  expect(argv.allowedTools).toEqual(['read_file', 'ShellTool(git status)']);
388
389
  });
389
390
  it('should support comma-separated values for --allowed-mcp-server-names', async () => {
@@ -393,12 +394,12 @@ describe('parseArguments', () => {
393
394
  '--allowed-mcp-server-names',
394
395
  'server1,server2',
395
396
  ];
396
- const argv = await parseArguments({});
397
+ const argv = await parseArguments(createTestMergedSettings());
397
398
  expect(argv.allowedMcpServerNames).toEqual(['server1', 'server2']);
398
399
  });
399
400
  it('should support comma-separated values for --extensions', async () => {
400
401
  process.argv = ['node', 'script.js', '--extensions', 'ext1,ext2'];
401
- const argv = await parseArguments({});
402
+ const argv = await parseArguments(createTestMergedSettings());
402
403
  expect(argv.extensions).toEqual(['ext1', 'ext2']);
403
404
  });
404
405
  it('should correctly parse positional arguments when flags with arguments are present', async () => {
@@ -409,7 +410,7 @@ describe('parseArguments', () => {
409
410
  'test-model-string',
410
411
  'my-positional-arg',
411
412
  ];
412
- const argv = await parseArguments({});
413
+ const argv = await parseArguments(createTestMergedSettings());
413
414
  expect(argv.model).toBe('test-model-string');
414
415
  expect(argv.query).toBe('my-positional-arg');
415
416
  });
@@ -425,7 +426,7 @@ describe('parseArguments', () => {
425
426
  '--allowed-tools=ShellTool(wc)',
426
427
  '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.',
427
428
  ];
428
- const argv = await parseArguments({});
429
+ const argv = await parseArguments(createTestMergedSettings());
429
430
  expect(argv.extensions).toEqual(['none']);
430
431
  expect(argv.approvalMode).toBe('auto_edit');
431
432
  expect(argv.allowedTools).toEqual([
@@ -473,8 +474,8 @@ describe('loadCliConfig', () => {
473
474
  });
474
475
  it(`should leave proxy to empty by default`, async () => {
475
476
  process.argv = ['node', 'script.js'];
476
- const argv = await parseArguments({});
477
- const settings = {};
477
+ const argv = await parseArguments(createTestMergedSettings());
478
+ const settings = createTestMergedSettings();
478
479
  const config = await loadCliConfig(settings, 'test-session', argv);
479
480
  expect(config.getProxy()).toBeFalsy();
480
481
  });
@@ -513,8 +514,8 @@ describe('loadCliConfig', () => {
513
514
  it(`should set proxy to ${expected} according to environment variable [${input.env_name}]`, async () => {
514
515
  vi.stubEnv(input.env_name, input.proxy_url);
515
516
  process.argv = ['node', 'script.js'];
516
- const argv = await parseArguments({});
517
- const settings = {};
517
+ const argv = await parseArguments(createTestMergedSettings());
518
+ const settings = createTestMergedSettings();
518
519
  const config = await loadCliConfig(settings, 'test-session', argv);
519
520
  expect(config.getProxy()).toBe(expected);
520
521
  });
@@ -522,8 +523,8 @@ describe('loadCliConfig', () => {
522
523
  });
523
524
  it('should use default fileFilter options when unconfigured', async () => {
524
525
  process.argv = ['node', 'script.js'];
525
- const argv = await parseArguments({});
526
- const settings = {};
526
+ const argv = await parseArguments(createTestMergedSettings());
527
+ const settings = createTestMergedSettings();
527
528
  const config = await loadCliConfig(settings, 'test-session', argv);
528
529
  expect(config.getFileFilteringRespectGitIgnore()).toBe(DEFAULT_FILE_FILTERING_OPTIONS.respectGitIgnore);
529
530
  expect(config.getFileFilteringRespectGeminiIgnore()).toBe(DEFAULT_FILE_FILTERING_OPTIONS.respectGeminiIgnore);
@@ -541,7 +542,7 @@ describe('Hierarchical Memory Loading (config.ts) - Placeholder Suite', () => {
541
542
  });
542
543
  it('should pass extension context file paths to loadServerHierarchicalMemory', async () => {
543
544
  process.argv = ['node', 'script.js'];
544
- const settings = {};
545
+ const settings = createTestMergedSettings();
545
546
  vi.spyOn(ExtensionManager.prototype, 'getExtensions').mockReturnValue([
546
547
  {
547
548
  path: '/path/to/ext1',
@@ -571,23 +572,23 @@ describe('Hierarchical Memory Loading (config.ts) - Placeholder Suite', () => {
571
572
  isActive: true,
572
573
  },
573
574
  ]);
574
- const argv = await parseArguments({});
575
+ const argv = await parseArguments(createTestMergedSettings());
575
576
  await loadCliConfig(settings, 'session-id', argv);
576
- expect(ServerConfig.loadServerHierarchicalMemory).toHaveBeenCalledWith(expect.any(String), [], false, expect.any(Object), expect.any(ExtensionManager), true, 'tree', {
577
- respectGitIgnore: false,
577
+ expect(ServerConfig.loadServerHierarchicalMemory).toHaveBeenCalledWith(expect.any(String), [], false, expect.any(Object), expect.any(ExtensionManager), true, 'tree', expect.objectContaining({
578
+ respectGitIgnore: true,
578
579
  respectGeminiIgnore: true,
579
- }, undefined);
580
+ }), 200);
580
581
  });
581
582
  });
582
583
  describe('mergeMcpServers', () => {
583
584
  it('should not modify the original settings object', async () => {
584
- const settings = {
585
+ const settings = createTestMergedSettings({
585
586
  mcpServers: {
586
587
  'test-server': {
587
588
  url: 'http://localhost:8080',
588
589
  },
589
590
  },
590
- };
591
+ });
591
592
  vi.spyOn(ExtensionManager.prototype, 'getExtensions').mockReturnValue([
592
593
  {
593
594
  path: '/path/to/ext1',
@@ -605,7 +606,7 @@ describe('mergeMcpServers', () => {
605
606
  ]);
606
607
  const originalSettings = JSON.parse(JSON.stringify(settings));
607
608
  process.argv = ['node', 'script.js'];
608
- const argv = await parseArguments({});
609
+ const argv = await parseArguments(createTestMergedSettings());
609
610
  await loadCliConfig(settings, 'test-session', argv);
610
611
  expect(settings).toEqual(originalSettings);
611
612
  });
@@ -626,7 +627,9 @@ describe('mergeExcludeTools', () => {
626
627
  process.stdin.isTTY = originalIsTTY;
627
628
  });
628
629
  it('should merge excludeTools from settings and extensions', async () => {
629
- const settings = { tools: { exclude: ['tool1', 'tool2'] } };
630
+ const settings = createTestMergedSettings({
631
+ tools: { exclude: ['tool1', 'tool2'] },
632
+ });
630
633
  vi.spyOn(ExtensionManager.prototype, 'getExtensions').mockReturnValue([
631
634
  {
632
635
  path: '/path/to/ext1',
@@ -648,13 +651,15 @@ describe('mergeExcludeTools', () => {
648
651
  },
649
652
  ]);
650
653
  process.argv = ['node', 'script.js'];
651
- const argv = await parseArguments({});
654
+ const argv = await parseArguments(createTestMergedSettings());
652
655
  const config = await loadCliConfig(settings, 'test-session', argv);
653
656
  expect(config.getExcludeTools()).toEqual(new Set(['tool1', 'tool2', 'tool3', 'tool4', 'tool5']));
654
657
  expect(config.getExcludeTools()).toHaveLength(5);
655
658
  });
656
659
  it('should handle overlapping excludeTools between settings and extensions', async () => {
657
- const settings = { tools: { exclude: ['tool1', 'tool2'] } };
660
+ const settings = createTestMergedSettings({
661
+ tools: { exclude: ['tool1', 'tool2'] },
662
+ });
658
663
  vi.spyOn(ExtensionManager.prototype, 'getExtensions').mockReturnValue([
659
664
  {
660
665
  path: '/path/to/ext1',
@@ -667,13 +672,15 @@ describe('mergeExcludeTools', () => {
667
672
  },
668
673
  ]);
669
674
  process.argv = ['node', 'script.js'];
670
- const argv = await parseArguments({});
675
+ const argv = await parseArguments(createTestMergedSettings());
671
676
  const config = await loadCliConfig(settings, 'test-session', argv);
672
677
  expect(config.getExcludeTools()).toEqual(new Set(['tool1', 'tool2', 'tool3']));
673
678
  expect(config.getExcludeTools()).toHaveLength(3);
674
679
  });
675
680
  it('should handle overlapping excludeTools between extensions', async () => {
676
- const settings = { tools: { exclude: ['tool1'] } };
681
+ const settings = createTestMergedSettings({
682
+ tools: { exclude: ['tool1'] },
683
+ });
677
684
  vi.spyOn(ExtensionManager.prototype, 'getExtensions').mockReturnValue([
678
685
  {
679
686
  path: '/path/to/ext1',
@@ -695,38 +702,40 @@ describe('mergeExcludeTools', () => {
695
702
  },
696
703
  ]);
697
704
  process.argv = ['node', 'script.js'];
698
- const argv = await parseArguments({});
705
+ const argv = await parseArguments(createTestMergedSettings());
699
706
  const config = await loadCliConfig(settings, 'test-session', argv);
700
707
  expect(config.getExcludeTools()).toEqual(new Set(['tool1', 'tool2', 'tool3', 'tool4']));
701
708
  expect(config.getExcludeTools()).toHaveLength(4);
702
709
  });
703
710
  it('should return an empty array when no excludeTools are specified and it is interactive', async () => {
704
711
  process.stdin.isTTY = true;
705
- const settings = {};
712
+ const settings = createTestMergedSettings();
706
713
  process.argv = ['node', 'script.js'];
707
- const argv = await parseArguments({});
714
+ const argv = await parseArguments(createTestMergedSettings());
708
715
  const config = await loadCliConfig(settings, 'test-session', argv);
709
716
  expect(config.getExcludeTools()).toEqual(new Set([]));
710
717
  });
711
718
  it('should return default excludes when no excludeTools are specified and it is not interactive', async () => {
712
719
  process.stdin.isTTY = false;
713
- const settings = {};
720
+ const settings = createTestMergedSettings();
714
721
  process.argv = ['node', 'script.js', '-p', 'test'];
715
- const argv = await parseArguments({});
722
+ const argv = await parseArguments(createTestMergedSettings());
716
723
  const config = await loadCliConfig(settings, 'test-session', argv);
717
724
  expect(config.getExcludeTools()).toEqual(defaultExcludes);
718
725
  });
719
726
  it('should handle settings with excludeTools but no extensions', async () => {
720
727
  process.argv = ['node', 'script.js'];
721
- const argv = await parseArguments({});
722
- const settings = { tools: { exclude: ['tool1', 'tool2'] } };
728
+ const argv = await parseArguments(createTestMergedSettings());
729
+ const settings = createTestMergedSettings({
730
+ tools: { exclude: ['tool1', 'tool2'] },
731
+ });
723
732
  vi.spyOn(ExtensionManager.prototype, 'getExtensions').mockReturnValue([]);
724
733
  const config = await loadCliConfig(settings, 'test-session', argv);
725
734
  expect(config.getExcludeTools()).toEqual(new Set(['tool1', 'tool2']));
726
735
  expect(config.getExcludeTools()).toHaveLength(2);
727
736
  });
728
737
  it('should handle extensions with excludeTools but no settings', async () => {
729
- const settings = {};
738
+ const settings = createTestMergedSettings();
730
739
  vi.spyOn(ExtensionManager.prototype, 'getExtensions').mockReturnValue([
731
740
  {
732
741
  path: '/path/to/ext',
@@ -739,13 +748,15 @@ describe('mergeExcludeTools', () => {
739
748
  },
740
749
  ]);
741
750
  process.argv = ['node', 'script.js'];
742
- const argv = await parseArguments({});
751
+ const argv = await parseArguments(createTestMergedSettings());
743
752
  const config = await loadCliConfig(settings, 'test-session', argv);
744
753
  expect(config.getExcludeTools()).toEqual(new Set(['tool1', 'tool2']));
745
754
  expect(config.getExcludeTools()).toHaveLength(2);
746
755
  });
747
756
  it('should not modify the original settings object', async () => {
748
- const settings = { tools: { exclude: ['tool1'] } };
757
+ const settings = createTestMergedSettings({
758
+ tools: { exclude: ['tool1'] },
759
+ });
749
760
  vi.spyOn(ExtensionManager.prototype, 'getExtensions').mockReturnValue([
750
761
  {
751
762
  path: '/path/to/ext',
@@ -759,7 +770,7 @@ describe('mergeExcludeTools', () => {
759
770
  ]);
760
771
  const originalSettings = JSON.parse(JSON.stringify(settings));
761
772
  process.argv = ['node', 'script.js'];
762
- const argv = await parseArguments({});
773
+ const argv = await parseArguments(createTestMergedSettings());
763
774
  await loadCliConfig(settings, 'test-session', argv);
764
775
  expect(settings).toEqual(originalSettings);
765
776
  });
@@ -779,8 +790,8 @@ describe('Approval mode tool exclusion logic', () => {
779
790
  });
780
791
  it('should exclude all interactive tools in non-interactive mode with default approval mode', async () => {
781
792
  process.argv = ['node', 'script.js', '-p', 'test'];
782
- const argv = await parseArguments({});
783
- const settings = {};
793
+ const argv = await parseArguments(createTestMergedSettings());
794
+ const settings = createTestMergedSettings();
784
795
  const config = await loadCliConfig(settings, 'test-session', argv);
785
796
  const excludedTools = config.getExcludeTools();
786
797
  expect(excludedTools).toContain(SHELL_TOOL_NAME);
@@ -796,8 +807,8 @@ describe('Approval mode tool exclusion logic', () => {
796
807
  '-p',
797
808
  'test',
798
809
  ];
799
- const argv = await parseArguments({});
800
- const settings = {};
810
+ const argv = await parseArguments(createTestMergedSettings());
811
+ const settings = createTestMergedSettings();
801
812
  const config = await loadCliConfig(settings, 'test-session', argv);
802
813
  const excludedTools = config.getExcludeTools();
803
814
  expect(excludedTools).toContain(SHELL_TOOL_NAME);
@@ -813,8 +824,8 @@ describe('Approval mode tool exclusion logic', () => {
813
824
  '-p',
814
825
  'test',
815
826
  ];
816
- const argv = await parseArguments({});
817
- const settings = {};
827
+ const argv = await parseArguments(createTestMergedSettings());
828
+ const settings = createTestMergedSettings();
818
829
  const config = await loadCliConfig(settings, 'test-session', argv);
819
830
  const excludedTools = config.getExcludeTools();
820
831
  expect(excludedTools).toContain(SHELL_TOOL_NAME);
@@ -830,18 +841,39 @@ describe('Approval mode tool exclusion logic', () => {
830
841
  '-p',
831
842
  'test',
832
843
  ];
833
- const argv = await parseArguments({});
834
- const settings = {};
844
+ const argv = await parseArguments(createTestMergedSettings());
845
+ const settings = createTestMergedSettings();
835
846
  const config = await loadCliConfig(settings, 'test-session', argv);
836
847
  const excludedTools = config.getExcludeTools();
837
848
  expect(excludedTools).not.toContain(SHELL_TOOL_NAME);
838
849
  expect(excludedTools).not.toContain(EDIT_TOOL_NAME);
839
850
  expect(excludedTools).not.toContain(WRITE_FILE_TOOL_NAME);
840
851
  });
852
+ it('should exclude all interactive tools in non-interactive mode with plan approval mode', async () => {
853
+ process.argv = [
854
+ 'node',
855
+ 'script.js',
856
+ '--approval-mode',
857
+ 'plan',
858
+ '-p',
859
+ 'test',
860
+ ];
861
+ const settings = createTestMergedSettings({
862
+ experimental: {
863
+ plan: true,
864
+ },
865
+ });
866
+ const argv = await parseArguments(createTestMergedSettings());
867
+ const config = await loadCliConfig(settings, 'test-session', argv);
868
+ const excludedTools = config.getExcludeTools();
869
+ expect(excludedTools).toContain(SHELL_TOOL_NAME);
870
+ expect(excludedTools).toContain(EDIT_TOOL_NAME);
871
+ expect(excludedTools).toContain(WRITE_FILE_TOOL_NAME);
872
+ });
841
873
  it('should exclude no interactive tools in non-interactive mode with legacy yolo flag', async () => {
842
874
  process.argv = ['node', 'script.js', '--yolo', '-p', 'test'];
843
- const argv = await parseArguments({});
844
- const settings = {};
875
+ const argv = await parseArguments(createTestMergedSettings());
876
+ const settings = createTestMergedSettings();
845
877
  const config = await loadCliConfig(settings, 'test-session', argv);
846
878
  const excludedTools = config.getExcludeTools();
847
879
  expect(excludedTools).not.toContain(SHELL_TOOL_NAME);
@@ -859,8 +891,8 @@ describe('Approval mode tool exclusion logic', () => {
859
891
  ];
860
892
  for (const testCase of testCases) {
861
893
  process.argv = testCase.args;
862
- const argv = await parseArguments({});
863
- const settings = {};
894
+ const argv = await parseArguments(createTestMergedSettings());
895
+ const settings = createTestMergedSettings();
864
896
  const config = await loadCliConfig(settings, 'test-session', argv);
865
897
  const excludedTools = config.getExcludeTools();
866
898
  expect(excludedTools).not.toContain(SHELL_TOOL_NAME);
@@ -877,8 +909,10 @@ describe('Approval mode tool exclusion logic', () => {
877
909
  '-p',
878
910
  'test',
879
911
  ];
880
- const argv = await parseArguments({});
881
- const settings = { tools: { exclude: ['custom_tool'] } };
912
+ const argv = await parseArguments(createTestMergedSettings());
913
+ const settings = createTestMergedSettings({
914
+ tools: { exclude: ['custom_tool'] },
915
+ });
882
916
  const config = await loadCliConfig(settings, 'test-session', argv);
883
917
  const excludedTools = config.getExcludeTools();
884
918
  expect(excludedTools).toContain('custom_tool'); // From settings
@@ -888,12 +922,12 @@ describe('Approval mode tool exclusion logic', () => {
888
922
  });
889
923
  it('should throw an error if YOLO mode is attempted when disableYoloMode is true', async () => {
890
924
  process.argv = ['node', 'script.js', '--yolo'];
891
- const argv = await parseArguments({});
892
- const settings = {
925
+ const argv = await parseArguments(createTestMergedSettings());
926
+ const settings = createTestMergedSettings({
893
927
  security: {
894
928
  disableYoloMode: true,
895
929
  },
896
- };
930
+ });
897
931
  await expect(loadCliConfig(settings, 'test-session', argv)).rejects.toThrow('Cannot start in YOLO mode since it is disabled by your admin');
898
932
  });
899
933
  it('should throw an error for invalid approval mode values in loadCliConfig', async () => {
@@ -904,8 +938,8 @@ describe('Approval mode tool exclusion logic', () => {
904
938
  prompt: '',
905
939
  yolo: false,
906
940
  };
907
- const settings = {};
908
- await expect(loadCliConfig(settings, 'test-session', invalidArgv)).rejects.toThrow('Invalid approval mode: invalid_mode. Valid values are: yolo, auto_edit, default');
941
+ const settings = createTestMergedSettings();
942
+ await expect(loadCliConfig(settings, 'test-session', invalidArgv)).rejects.toThrow('Invalid approval mode: invalid_mode. Valid values are: yolo, auto_edit, plan, default');
909
943
  });
910
944
  });
911
945
  describe('loadCliConfig with allowed-mcp-server-names', () => {
@@ -919,16 +953,16 @@ describe('loadCliConfig with allowed-mcp-server-names', () => {
919
953
  vi.unstubAllEnvs();
920
954
  vi.restoreAllMocks();
921
955
  });
922
- const baseSettings = {
956
+ const baseSettings = createTestMergedSettings({
923
957
  mcpServers: {
924
958
  server1: { url: 'http://localhost:8080' },
925
959
  server2: { url: 'http://localhost:8081' },
926
960
  server3: { url: 'http://localhost:8082' },
927
961
  },
928
- };
962
+ });
929
963
  it('should allow all MCP servers if the flag is not provided', async () => {
930
964
  process.argv = ['node', 'script.js'];
931
- const argv = await parseArguments({});
965
+ const argv = await parseArguments(createTestMergedSettings());
932
966
  const config = await loadCliConfig(baseSettings, 'test-session', argv);
933
967
  expect(config.getMcpServers()).toEqual(baseSettings.mcpServers);
934
968
  });
@@ -939,7 +973,7 @@ describe('loadCliConfig with allowed-mcp-server-names', () => {
939
973
  '--allowed-mcp-server-names',
940
974
  'server1',
941
975
  ];
942
- const argv = await parseArguments({});
976
+ const argv = await parseArguments(createTestMergedSettings());
943
977
  const config = await loadCliConfig(baseSettings, 'test-session', argv);
944
978
  expect(config.getAllowedMcpServers()).toEqual(['server1']);
945
979
  });
@@ -952,7 +986,7 @@ describe('loadCliConfig with allowed-mcp-server-names', () => {
952
986
  '--allowed-mcp-server-names',
953
987
  'server3',
954
988
  ];
955
- const argv = await parseArguments({});
989
+ const argv = await parseArguments(createTestMergedSettings());
956
990
  const config = await loadCliConfig(baseSettings, 'test-session', argv);
957
991
  expect(config.getAllowedMcpServers()).toEqual(['server1', 'server3']);
958
992
  });
@@ -965,46 +999,46 @@ describe('loadCliConfig with allowed-mcp-server-names', () => {
965
999
  '--allowed-mcp-server-names',
966
1000
  'server4',
967
1001
  ];
968
- const argv = await parseArguments({});
1002
+ const argv = await parseArguments(createTestMergedSettings());
969
1003
  const config = await loadCliConfig(baseSettings, 'test-session', argv);
970
1004
  expect(config.getAllowedMcpServers()).toEqual(['server1', 'server4']);
971
1005
  });
972
1006
  it('should allow no MCP servers if the flag is provided but empty', async () => {
973
1007
  process.argv = ['node', 'script.js', '--allowed-mcp-server-names', ''];
974
- const argv = await parseArguments({});
1008
+ const argv = await parseArguments(createTestMergedSettings());
975
1009
  const config = await loadCliConfig(baseSettings, 'test-session', argv);
976
1010
  expect(config.getAllowedMcpServers()).toEqual(['']);
977
1011
  });
978
1012
  it('should read allowMCPServers from settings', async () => {
979
1013
  process.argv = ['node', 'script.js'];
980
- const argv = await parseArguments({});
981
- const settings = {
1014
+ const argv = await parseArguments(createTestMergedSettings());
1015
+ const settings = createTestMergedSettings({
982
1016
  ...baseSettings,
983
1017
  mcp: { allowed: ['server1', 'server2'] },
984
- };
1018
+ });
985
1019
  const config = await loadCliConfig(settings, 'test-session', argv);
986
1020
  expect(config.getAllowedMcpServers()).toEqual(['server1', 'server2']);
987
1021
  });
988
1022
  it('should read excludeMCPServers from settings', async () => {
989
1023
  process.argv = ['node', 'script.js'];
990
- const argv = await parseArguments({});
991
- const settings = {
1024
+ const argv = await parseArguments(createTestMergedSettings());
1025
+ const settings = createTestMergedSettings({
992
1026
  ...baseSettings,
993
1027
  mcp: { excluded: ['server1', 'server2'] },
994
- };
1028
+ });
995
1029
  const config = await loadCliConfig(settings, 'test-session', argv);
996
1030
  expect(config.getBlockedMcpServers()).toEqual(['server1', 'server2']);
997
1031
  });
998
1032
  it('should override allowMCPServers with excludeMCPServers if overlapping', async () => {
999
1033
  process.argv = ['node', 'script.js'];
1000
- const argv = await parseArguments({});
1001
- const settings = {
1034
+ const argv = await parseArguments(createTestMergedSettings());
1035
+ const settings = createTestMergedSettings({
1002
1036
  ...baseSettings,
1003
1037
  mcp: {
1004
1038
  excluded: ['server1'],
1005
1039
  allowed: ['server1', 'server2'],
1006
1040
  },
1007
- };
1041
+ });
1008
1042
  const config = await loadCliConfig(settings, 'test-session', argv);
1009
1043
  expect(config.getAllowedMcpServers()).toEqual(['server1', 'server2']);
1010
1044
  expect(config.getBlockedMcpServers()).toEqual(['server1']);
@@ -1016,14 +1050,14 @@ describe('loadCliConfig with allowed-mcp-server-names', () => {
1016
1050
  '--allowed-mcp-server-names',
1017
1051
  'server1',
1018
1052
  ];
1019
- const argv = await parseArguments({});
1020
- const settings = {
1053
+ const argv = await parseArguments(createTestMergedSettings());
1054
+ const settings = createTestMergedSettings({
1021
1055
  ...baseSettings,
1022
1056
  mcp: {
1023
1057
  excluded: ['server1'],
1024
1058
  allowed: ['server2'],
1025
1059
  },
1026
- };
1060
+ });
1027
1061
  const config = await loadCliConfig(settings, 'test-session', argv);
1028
1062
  expect(config.getAllowedMcpServers()).toEqual(['server1']);
1029
1063
  });
@@ -1036,14 +1070,14 @@ describe('loadCliConfig with allowed-mcp-server-names', () => {
1036
1070
  '--allowed-mcp-server-names',
1037
1071
  'server3',
1038
1072
  ];
1039
- const argv = await parseArguments({});
1040
- const settings = {
1073
+ const argv = await parseArguments(createTestMergedSettings());
1074
+ const settings = createTestMergedSettings({
1041
1075
  ...baseSettings,
1042
1076
  mcp: {
1043
1077
  allowed: ['server1', 'server2'], // Should be ignored
1044
1078
  excluded: ['server3'], // Should be ignored
1045
1079
  },
1046
- };
1080
+ });
1047
1081
  const config = await loadCliConfig(settings, 'test-session', argv);
1048
1082
  expect(config.getAllowedMcpServers()).toEqual(['server2', 'server3']);
1049
1083
  expect(config.getBlockedMcpServers()).toEqual([]);
@@ -1058,40 +1092,48 @@ describe('loadCliConfig model selection', () => {
1058
1092
  });
1059
1093
  it('selects a model from settings.json if provided', async () => {
1060
1094
  process.argv = ['node', 'script.js'];
1061
- const argv = await parseArguments({});
1062
- const config = await loadCliConfig({
1095
+ const argv = await parseArguments(createTestMergedSettings());
1096
+ const config = await loadCliConfig(createTestMergedSettings({
1063
1097
  model: {
1064
1098
  name: 'gemini-2.5-pro',
1065
1099
  },
1066
- }, 'test-session', argv);
1100
+ }), 'test-session', argv);
1067
1101
  expect(config.getModel()).toBe('gemini-2.5-pro');
1068
1102
  });
1069
1103
  it('uses the default gemini model if nothing is set', async () => {
1070
1104
  process.argv = ['node', 'script.js']; // No model set.
1071
- const argv = await parseArguments({});
1072
- const config = await loadCliConfig({
1105
+ const argv = await parseArguments(createTestMergedSettings());
1106
+ const config = await loadCliConfig(createTestMergedSettings({
1073
1107
  // No model set.
1074
- }, 'test-session', argv);
1108
+ }), 'test-session', argv);
1075
1109
  expect(config.getModel()).toBe('auto-gemini-2.5');
1076
1110
  });
1077
1111
  it('always prefers model from argv', async () => {
1078
1112
  process.argv = ['node', 'script.js', '--model', 'gemini-2.5-flash-preview'];
1079
- const argv = await parseArguments({});
1080
- const config = await loadCliConfig({
1113
+ const argv = await parseArguments(createTestMergedSettings());
1114
+ const config = await loadCliConfig(createTestMergedSettings({
1081
1115
  model: {
1082
1116
  name: 'gemini-2.5-pro',
1083
1117
  },
1084
- }, 'test-session', argv);
1118
+ }), 'test-session', argv);
1085
1119
  expect(config.getModel()).toBe('gemini-2.5-flash-preview');
1086
1120
  });
1087
1121
  it('selects the model from argv if provided', async () => {
1088
1122
  process.argv = ['node', 'script.js', '--model', 'gemini-2.5-flash-preview'];
1089
- const argv = await parseArguments({});
1090
- const config = await loadCliConfig({
1123
+ const argv = await parseArguments(createTestMergedSettings());
1124
+ const config = await loadCliConfig(createTestMergedSettings({
1091
1125
  // No model provided via settings.
1092
- }, 'test-session', argv);
1126
+ }), 'test-session', argv);
1093
1127
  expect(config.getModel()).toBe('gemini-2.5-flash-preview');
1094
1128
  });
1129
+ it('selects the default auto model if provided via auto alias', async () => {
1130
+ process.argv = ['node', 'script.js', '--model', 'auto'];
1131
+ const argv = await parseArguments(createTestMergedSettings());
1132
+ const config = await loadCliConfig(createTestMergedSettings({
1133
+ // No model provided via settings.
1134
+ }), 'test-session', argv);
1135
+ expect(config.getModel()).toBe('auto-gemini-2.5');
1136
+ });
1095
1137
  });
1096
1138
  describe('loadCliConfig folderTrust', () => {
1097
1139
  beforeEach(() => {
@@ -1106,34 +1148,34 @@ describe('loadCliConfig folderTrust', () => {
1106
1148
  });
1107
1149
  it('should be false when folderTrust is false', async () => {
1108
1150
  process.argv = ['node', 'script.js'];
1109
- const settings = {
1151
+ const settings = createTestMergedSettings({
1110
1152
  security: {
1111
1153
  folderTrust: {
1112
1154
  enabled: false,
1113
1155
  },
1114
1156
  },
1115
- };
1116
- const argv = await parseArguments({});
1157
+ });
1158
+ const argv = await parseArguments(createTestMergedSettings());
1117
1159
  const config = await loadCliConfig(settings, 'test-session', argv);
1118
1160
  expect(config.getFolderTrust()).toBe(false);
1119
1161
  });
1120
1162
  it('should be true when folderTrust is true', async () => {
1121
1163
  process.argv = ['node', 'script.js'];
1122
- const argv = await parseArguments({});
1123
- const settings = {
1164
+ const argv = await parseArguments(createTestMergedSettings());
1165
+ const settings = createTestMergedSettings({
1124
1166
  security: {
1125
1167
  folderTrust: {
1126
1168
  enabled: true,
1127
1169
  },
1128
1170
  },
1129
- };
1171
+ });
1130
1172
  const config = await loadCliConfig(settings, 'test-session', argv);
1131
1173
  expect(config.getFolderTrust()).toBe(true);
1132
1174
  });
1133
1175
  it('should be false by default', async () => {
1134
1176
  process.argv = ['node', 'script.js'];
1135
- const argv = await parseArguments({});
1136
- const settings = {};
1177
+ const argv = await parseArguments(createTestMergedSettings());
1178
+ const settings = createTestMergedSettings();
1137
1179
  const config = await loadCliConfig(settings, 'test-session', argv);
1138
1180
  expect(config.getFolderTrust()).toBe(false);
1139
1181
  });
@@ -1157,8 +1199,8 @@ describe('loadCliConfig with includeDirectories', () => {
1157
1199
  '--include-directories',
1158
1200
  `${path.resolve(path.sep, 'cli', 'path1')},${path.join(mockCwd, 'cli', 'path2')}`,
1159
1201
  ];
1160
- const argv = await parseArguments({});
1161
- const settings = {
1202
+ const argv = await parseArguments(createTestMergedSettings());
1203
+ const settings = createTestMergedSettings({
1162
1204
  context: {
1163
1205
  includeDirectories: [
1164
1206
  path.resolve(path.sep, 'settings', 'path1'),
@@ -1166,7 +1208,7 @@ describe('loadCliConfig with includeDirectories', () => {
1166
1208
  path.join(mockCwd, 'settings', 'path3'),
1167
1209
  ],
1168
1210
  },
1169
- };
1211
+ });
1170
1212
  const config = await loadCliConfig(settings, 'test-session', argv);
1171
1213
  const expected = [
1172
1214
  mockCwd,
@@ -1195,21 +1237,21 @@ describe('loadCliConfig compressionThreshold', () => {
1195
1237
  });
1196
1238
  it('should pass settings to the core config', async () => {
1197
1239
  process.argv = ['node', 'script.js'];
1198
- const argv = await parseArguments({});
1199
- const settings = {
1240
+ const argv = await parseArguments(createTestMergedSettings());
1241
+ const settings = createTestMergedSettings({
1200
1242
  model: {
1201
1243
  compressionThreshold: 0.5,
1202
1244
  },
1203
- };
1245
+ });
1204
1246
  const config = await loadCliConfig(settings, 'test-session', argv);
1205
1247
  expect(await config.getCompressionThreshold()).toBe(0.5);
1206
1248
  });
1207
- it('should have undefined compressionThreshold if not in settings', async () => {
1249
+ it('should have default compressionThreshold if not in settings', async () => {
1208
1250
  process.argv = ['node', 'script.js'];
1209
- const argv = await parseArguments({});
1210
- const settings = {};
1251
+ const argv = await parseArguments(createTestMergedSettings());
1252
+ const settings = createTestMergedSettings();
1211
1253
  const config = await loadCliConfig(settings, 'test-session', argv);
1212
- expect(await config.getCompressionThreshold()).toBeUndefined();
1254
+ expect(await config.getCompressionThreshold()).toBe(0.5);
1213
1255
  });
1214
1256
  });
1215
1257
  describe('loadCliConfig useRipgrep', () => {
@@ -1225,22 +1267,22 @@ describe('loadCliConfig useRipgrep', () => {
1225
1267
  });
1226
1268
  it('should be true by default when useRipgrep is not set in settings', async () => {
1227
1269
  process.argv = ['node', 'script.js'];
1228
- const argv = await parseArguments({});
1229
- const settings = {};
1270
+ const argv = await parseArguments(createTestMergedSettings());
1271
+ const settings = createTestMergedSettings();
1230
1272
  const config = await loadCliConfig(settings, 'test-session', argv);
1231
1273
  expect(config.getUseRipgrep()).toBe(true);
1232
1274
  });
1233
1275
  it('should be false when useRipgrep is set to false in settings', async () => {
1234
1276
  process.argv = ['node', 'script.js'];
1235
- const argv = await parseArguments({});
1236
- const settings = { tools: { useRipgrep: false } };
1277
+ const argv = await parseArguments(createTestMergedSettings());
1278
+ const settings = createTestMergedSettings({ tools: { useRipgrep: false } });
1237
1279
  const config = await loadCliConfig(settings, 'test-session', argv);
1238
1280
  expect(config.getUseRipgrep()).toBe(false);
1239
1281
  });
1240
1282
  it('should be true when useRipgrep is explicitly set to true in settings', async () => {
1241
1283
  process.argv = ['node', 'script.js'];
1242
- const argv = await parseArguments({});
1243
- const settings = { tools: { useRipgrep: true } };
1284
+ const argv = await parseArguments(createTestMergedSettings());
1285
+ const settings = createTestMergedSettings({ tools: { useRipgrep: true } });
1244
1286
  const config = await loadCliConfig(settings, 'test-session', argv);
1245
1287
  expect(config.getUseRipgrep()).toBe(true);
1246
1288
  });
@@ -1258,35 +1300,35 @@ describe('screenReader configuration', () => {
1258
1300
  });
1259
1301
  it('should use screenReader value from settings if CLI flag is not present (settings true)', async () => {
1260
1302
  process.argv = ['node', 'script.js'];
1261
- const argv = await parseArguments({});
1262
- const settings = {
1303
+ const argv = await parseArguments(createTestMergedSettings());
1304
+ const settings = createTestMergedSettings({
1263
1305
  ui: { accessibility: { screenReader: true } },
1264
- };
1306
+ });
1265
1307
  const config = await loadCliConfig(settings, 'test-session', argv);
1266
1308
  expect(config.getScreenReader()).toBe(true);
1267
1309
  });
1268
1310
  it('should use screenReader value from settings if CLI flag is not present (settings false)', async () => {
1269
1311
  process.argv = ['node', 'script.js'];
1270
- const argv = await parseArguments({});
1271
- const settings = {
1312
+ const argv = await parseArguments(createTestMergedSettings());
1313
+ const settings = createTestMergedSettings({
1272
1314
  ui: { accessibility: { screenReader: false } },
1273
- };
1315
+ });
1274
1316
  const config = await loadCliConfig(settings, 'test-session', argv);
1275
1317
  expect(config.getScreenReader()).toBe(false);
1276
1318
  });
1277
1319
  it('should prioritize --screen-reader CLI flag (true) over settings (false)', async () => {
1278
1320
  process.argv = ['node', 'script.js', '--screen-reader'];
1279
- const argv = await parseArguments({});
1280
- const settings = {
1321
+ const argv = await parseArguments(createTestMergedSettings());
1322
+ const settings = createTestMergedSettings({
1281
1323
  ui: { accessibility: { screenReader: false } },
1282
- };
1324
+ });
1283
1325
  const config = await loadCliConfig(settings, 'test-session', argv);
1284
1326
  expect(config.getScreenReader()).toBe(true);
1285
1327
  });
1286
1328
  it('should be false by default when no flag or setting is present', async () => {
1287
1329
  process.argv = ['node', 'script.js'];
1288
- const argv = await parseArguments({});
1289
- const settings = {};
1330
+ const argv = await parseArguments(createTestMergedSettings());
1331
+ const settings = createTestMergedSettings();
1290
1332
  const config = await loadCliConfig(settings, 'test-session', argv);
1291
1333
  expect(config.getScreenReader()).toBe(false);
1292
1334
  });
@@ -1312,8 +1354,8 @@ describe('loadCliConfig tool exclusions', () => {
1312
1354
  it('should not exclude interactive tools in interactive mode without YOLO', async () => {
1313
1355
  process.stdin.isTTY = true;
1314
1356
  process.argv = ['node', 'script.js'];
1315
- const argv = await parseArguments({});
1316
- const config = await loadCliConfig({}, 'test-session', argv);
1357
+ const argv = await parseArguments(createTestMergedSettings());
1358
+ const config = await loadCliConfig(createTestMergedSettings(), 'test-session', argv);
1317
1359
  expect(config.getExcludeTools()).not.toContain('run_shell_command');
1318
1360
  expect(config.getExcludeTools()).not.toContain('replace');
1319
1361
  expect(config.getExcludeTools()).not.toContain('write_file');
@@ -1321,8 +1363,8 @@ describe('loadCliConfig tool exclusions', () => {
1321
1363
  it('should not exclude interactive tools in interactive mode with YOLO', async () => {
1322
1364
  process.stdin.isTTY = true;
1323
1365
  process.argv = ['node', 'script.js', '--yolo'];
1324
- const argv = await parseArguments({});
1325
- const config = await loadCliConfig({}, 'test-session', argv);
1366
+ const argv = await parseArguments(createTestMergedSettings());
1367
+ const config = await loadCliConfig(createTestMergedSettings(), 'test-session', argv);
1326
1368
  expect(config.getExcludeTools()).not.toContain('run_shell_command');
1327
1369
  expect(config.getExcludeTools()).not.toContain('replace');
1328
1370
  expect(config.getExcludeTools()).not.toContain('write_file');
@@ -1330,8 +1372,8 @@ describe('loadCliConfig tool exclusions', () => {
1330
1372
  it('should exclude interactive tools in non-interactive mode without YOLO', async () => {
1331
1373
  process.stdin.isTTY = false;
1332
1374
  process.argv = ['node', 'script.js', '-p', 'test'];
1333
- const argv = await parseArguments({});
1334
- const config = await loadCliConfig({}, 'test-session', argv);
1375
+ const argv = await parseArguments(createTestMergedSettings());
1376
+ const config = await loadCliConfig(createTestMergedSettings(), 'test-session', argv);
1335
1377
  expect(config.getExcludeTools()).toContain('run_shell_command');
1336
1378
  expect(config.getExcludeTools()).toContain('replace');
1337
1379
  expect(config.getExcludeTools()).toContain('write_file');
@@ -1339,8 +1381,8 @@ describe('loadCliConfig tool exclusions', () => {
1339
1381
  it('should not exclude interactive tools in non-interactive mode with YOLO', async () => {
1340
1382
  process.stdin.isTTY = false;
1341
1383
  process.argv = ['node', 'script.js', '-p', 'test', '--yolo'];
1342
- const argv = await parseArguments({});
1343
- const config = await loadCliConfig({}, 'test-session', argv);
1384
+ const argv = await parseArguments(createTestMergedSettings());
1385
+ const config = await loadCliConfig(createTestMergedSettings(), 'test-session', argv);
1344
1386
  expect(config.getExcludeTools()).not.toContain('run_shell_command');
1345
1387
  expect(config.getExcludeTools()).not.toContain('replace');
1346
1388
  expect(config.getExcludeTools()).not.toContain('write_file');
@@ -1355,15 +1397,15 @@ describe('loadCliConfig tool exclusions', () => {
1355
1397
  '--allowed-tools',
1356
1398
  'ShellTool',
1357
1399
  ];
1358
- const argv = await parseArguments({});
1359
- const config = await loadCliConfig({}, 'test-session', argv);
1400
+ const argv = await parseArguments(createTestMergedSettings());
1401
+ const config = await loadCliConfig(createTestMergedSettings(), 'test-session', argv);
1360
1402
  expect(config.getExcludeTools()).not.toContain(SHELL_TOOL_NAME);
1361
1403
  });
1362
1404
  it('should exclude web-fetch in non-interactive mode when not allowed', async () => {
1363
1405
  process.stdin.isTTY = false;
1364
1406
  process.argv = ['node', 'script.js', '-p', 'test'];
1365
- const argv = await parseArguments({});
1366
- const config = await loadCliConfig({}, 'test-session', argv);
1407
+ const argv = await parseArguments(createTestMergedSettings());
1408
+ const config = await loadCliConfig(createTestMergedSettings(), 'test-session', argv);
1367
1409
  expect(config.getExcludeTools()).toContain(WEB_FETCH_TOOL_NAME);
1368
1410
  });
1369
1411
  it('should not exclude web-fetch in non-interactive mode when allowed', async () => {
@@ -1376,8 +1418,8 @@ describe('loadCliConfig tool exclusions', () => {
1376
1418
  '--allowed-tools',
1377
1419
  WEB_FETCH_TOOL_NAME,
1378
1420
  ];
1379
- const argv = await parseArguments({});
1380
- const config = await loadCliConfig({}, 'test-session', argv);
1421
+ const argv = await parseArguments(createTestMergedSettings());
1422
+ const config = await loadCliConfig(createTestMergedSettings(), 'test-session', argv);
1381
1423
  expect(config.getExcludeTools()).not.toContain(WEB_FETCH_TOOL_NAME);
1382
1424
  });
1383
1425
  it('should not exclude shell tool in non-interactive mode when --allowed-tools="run_shell_command" is set', async () => {
@@ -1390,8 +1432,8 @@ describe('loadCliConfig tool exclusions', () => {
1390
1432
  '--allowed-tools',
1391
1433
  'run_shell_command',
1392
1434
  ];
1393
- const argv = await parseArguments({});
1394
- const config = await loadCliConfig({}, 'test-session', argv);
1435
+ const argv = await parseArguments(createTestMergedSettings());
1436
+ const config = await loadCliConfig(createTestMergedSettings(), 'test-session', argv);
1395
1437
  expect(config.getExcludeTools()).not.toContain(SHELL_TOOL_NAME);
1396
1438
  });
1397
1439
  it('should not exclude shell tool in non-interactive mode when --allowed-tools="ShellTool(wc)" is set', async () => {
@@ -1404,8 +1446,8 @@ describe('loadCliConfig tool exclusions', () => {
1404
1446
  '--allowed-tools',
1405
1447
  'ShellTool(wc)',
1406
1448
  ];
1407
- const argv = await parseArguments({});
1408
- const config = await loadCliConfig({}, 'test-session', argv);
1449
+ const argv = await parseArguments(createTestMergedSettings());
1450
+ const config = await loadCliConfig(createTestMergedSettings(), 'test-session', argv);
1409
1451
  expect(config.getExcludeTools()).not.toContain(SHELL_TOOL_NAME);
1410
1452
  });
1411
1453
  });
@@ -1426,36 +1468,36 @@ describe('loadCliConfig interactive', () => {
1426
1468
  it('should be interactive if isTTY and no prompt', async () => {
1427
1469
  process.stdin.isTTY = true;
1428
1470
  process.argv = ['node', 'script.js'];
1429
- const argv = await parseArguments({});
1430
- const config = await loadCliConfig({}, 'test-session', argv);
1471
+ const argv = await parseArguments(createTestMergedSettings());
1472
+ const config = await loadCliConfig(createTestMergedSettings(), 'test-session', argv);
1431
1473
  expect(config.isInteractive()).toBe(true);
1432
1474
  });
1433
1475
  it('should be interactive if prompt-interactive is set', async () => {
1434
1476
  process.stdin.isTTY = false;
1435
1477
  process.argv = ['node', 'script.js', '--prompt-interactive', 'test'];
1436
- const argv = await parseArguments({});
1437
- const config = await loadCliConfig({}, 'test-session', argv);
1478
+ const argv = await parseArguments(createTestMergedSettings());
1479
+ const config = await loadCliConfig(createTestMergedSettings(), 'test-session', argv);
1438
1480
  expect(config.isInteractive()).toBe(true);
1439
1481
  });
1440
1482
  it('should not be interactive if not isTTY and no prompt', async () => {
1441
1483
  process.stdin.isTTY = false;
1442
1484
  process.argv = ['node', 'script.js'];
1443
- const argv = await parseArguments({});
1444
- const config = await loadCliConfig({}, 'test-session', argv);
1485
+ const argv = await parseArguments(createTestMergedSettings());
1486
+ const config = await loadCliConfig(createTestMergedSettings(), 'test-session', argv);
1445
1487
  expect(config.isInteractive()).toBe(false);
1446
1488
  });
1447
1489
  it('should not be interactive if prompt is set', async () => {
1448
1490
  process.stdin.isTTY = true;
1449
1491
  process.argv = ['node', 'script.js', '--prompt', 'test'];
1450
- const argv = await parseArguments({});
1451
- const config = await loadCliConfig({}, 'test-session', argv);
1492
+ const argv = await parseArguments(createTestMergedSettings());
1493
+ const config = await loadCliConfig(createTestMergedSettings(), 'test-session', argv);
1452
1494
  expect(config.isInteractive()).toBe(false);
1453
1495
  });
1454
1496
  it('should not be interactive if positional prompt words are provided with other flags', async () => {
1455
1497
  process.stdin.isTTY = true;
1456
1498
  process.argv = ['node', 'script.js', '--model', 'gemini-2.5-pro', 'Hello'];
1457
- const argv = await parseArguments({});
1458
- const config = await loadCliConfig({}, 'test-session', argv);
1499
+ const argv = await parseArguments(createTestMergedSettings());
1500
+ const config = await loadCliConfig(createTestMergedSettings(), 'test-session', argv);
1459
1501
  expect(config.isInteractive()).toBe(false);
1460
1502
  });
1461
1503
  it('should not be interactive if positional prompt words are provided with multiple flags', async () => {
@@ -1468,8 +1510,8 @@ describe('loadCliConfig interactive', () => {
1468
1510
  '--yolo',
1469
1511
  'Hello world',
1470
1512
  ];
1471
- const argv = await parseArguments({});
1472
- const config = await loadCliConfig({}, 'test-session', argv);
1513
+ const argv = await parseArguments(createTestMergedSettings());
1514
+ const config = await loadCliConfig(createTestMergedSettings(), 'test-session', argv);
1473
1515
  expect(config.isInteractive()).toBe(false);
1474
1516
  // Verify the question is preserved for one-shot execution
1475
1517
  expect(argv.prompt).toBe('Hello world');
@@ -1478,8 +1520,8 @@ describe('loadCliConfig interactive', () => {
1478
1520
  it('should not be interactive if positional prompt words are provided with extensions flag', async () => {
1479
1521
  process.stdin.isTTY = true;
1480
1522
  process.argv = ['node', 'script.js', '-e', 'none', 'hello'];
1481
- const argv = await parseArguments({});
1482
- const config = await loadCliConfig({}, 'test-session', argv);
1523
+ const argv = await parseArguments(createTestMergedSettings());
1524
+ const config = await loadCliConfig(createTestMergedSettings(), 'test-session', argv);
1483
1525
  expect(config.isInteractive()).toBe(false);
1484
1526
  expect(argv.query).toBe('hello');
1485
1527
  expect(argv.extensions).toEqual(['none']);
@@ -1487,8 +1529,8 @@ describe('loadCliConfig interactive', () => {
1487
1529
  it('should handle multiple positional words correctly', async () => {
1488
1530
  process.stdin.isTTY = true;
1489
1531
  process.argv = ['node', 'script.js', 'hello world how are you'];
1490
- const argv = await parseArguments({});
1491
- const config = await loadCliConfig({}, 'test-session', argv);
1532
+ const argv = await parseArguments(createTestMergedSettings());
1533
+ const config = await loadCliConfig(createTestMergedSettings(), 'test-session', argv);
1492
1534
  expect(config.isInteractive()).toBe(false);
1493
1535
  expect(argv.query).toBe('hello world how are you');
1494
1536
  expect(argv.prompt).toBe('hello world how are you');
@@ -1507,8 +1549,8 @@ describe('loadCliConfig interactive', () => {
1507
1549
  'sort',
1508
1550
  'array',
1509
1551
  ];
1510
- const argv = await parseArguments({});
1511
- const config = await loadCliConfig({}, 'test-session', argv);
1552
+ const argv = await parseArguments(createTestMergedSettings());
1553
+ const config = await loadCliConfig(createTestMergedSettings(), 'test-session', argv);
1512
1554
  expect(config.isInteractive()).toBe(false);
1513
1555
  expect(argv.query).toBe('write a function to sort array');
1514
1556
  expect(argv.model).toBe('gemini-2.5-pro');
@@ -1516,8 +1558,8 @@ describe('loadCliConfig interactive', () => {
1516
1558
  it('should handle empty positional arguments', async () => {
1517
1559
  process.stdin.isTTY = true;
1518
1560
  process.argv = ['node', 'script.js', ''];
1519
- const argv = await parseArguments({});
1520
- const config = await loadCliConfig({}, 'test-session', argv);
1561
+ const argv = await parseArguments(createTestMergedSettings());
1562
+ const config = await loadCliConfig(createTestMergedSettings(), 'test-session', argv);
1521
1563
  expect(config.isInteractive()).toBe(true);
1522
1564
  expect(argv.query).toBeUndefined();
1523
1565
  });
@@ -1534,8 +1576,8 @@ describe('loadCliConfig interactive', () => {
1534
1576
  'are',
1535
1577
  'you',
1536
1578
  ];
1537
- const argv = await parseArguments({});
1538
- const config = await loadCliConfig({}, 'test-session', argv);
1579
+ const argv = await parseArguments(createTestMergedSettings());
1580
+ const config = await loadCliConfig(createTestMergedSettings(), 'test-session', argv);
1539
1581
  expect(config.isInteractive()).toBe(false);
1540
1582
  expect(argv.query).toBe('hello world how are you');
1541
1583
  expect(argv.extensions).toEqual(['none']);
@@ -1543,8 +1585,8 @@ describe('loadCliConfig interactive', () => {
1543
1585
  it('should be interactive if no positional prompt words are provided with flags', async () => {
1544
1586
  process.stdin.isTTY = true;
1545
1587
  process.argv = ['node', 'script.js', '--model', 'gemini-2.5-pro'];
1546
- const argv = await parseArguments({});
1547
- const config = await loadCliConfig({}, 'test-session', argv);
1588
+ const argv = await parseArguments(createTestMergedSettings());
1589
+ const config = await loadCliConfig(createTestMergedSettings(), 'test-session', argv);
1548
1590
  expect(config.isInteractive()).toBe(true);
1549
1591
  });
1550
1592
  });
@@ -1568,56 +1610,83 @@ describe('loadCliConfig approval mode', () => {
1568
1610
  });
1569
1611
  it('should default to DEFAULT approval mode when no flags are set', async () => {
1570
1612
  process.argv = ['node', 'script.js'];
1571
- const argv = await parseArguments({});
1572
- const config = await loadCliConfig({}, 'test-session', argv);
1613
+ const argv = await parseArguments(createTestMergedSettings());
1614
+ const config = await loadCliConfig(createTestMergedSettings(), 'test-session', argv);
1573
1615
  expect(config.getApprovalMode()).toBe(ServerConfig.ApprovalMode.DEFAULT);
1574
1616
  });
1575
1617
  it('should set YOLO approval mode when --yolo flag is used', async () => {
1576
1618
  process.argv = ['node', 'script.js', '--yolo'];
1577
- const argv = await parseArguments({});
1578
- const config = await loadCliConfig({}, 'test-session', argv);
1619
+ const argv = await parseArguments(createTestMergedSettings());
1620
+ const config = await loadCliConfig(createTestMergedSettings(), 'test-session', argv);
1579
1621
  expect(config.getApprovalMode()).toBe(ServerConfig.ApprovalMode.YOLO);
1580
1622
  });
1581
1623
  it('should set YOLO approval mode when -y flag is used', async () => {
1582
1624
  process.argv = ['node', 'script.js', '-y'];
1583
- const argv = await parseArguments({});
1584
- const config = await loadCliConfig({}, 'test-session', argv);
1625
+ const argv = await parseArguments(createTestMergedSettings());
1626
+ const config = await loadCliConfig(createTestMergedSettings(), 'test-session', argv);
1585
1627
  expect(config.getApprovalMode()).toBe(ServerConfig.ApprovalMode.YOLO);
1586
1628
  });
1587
1629
  it('should set DEFAULT approval mode when --approval-mode=default', async () => {
1588
1630
  process.argv = ['node', 'script.js', '--approval-mode', 'default'];
1589
- const argv = await parseArguments({});
1590
- const config = await loadCliConfig({}, 'test-session', argv);
1631
+ const argv = await parseArguments(createTestMergedSettings());
1632
+ const config = await loadCliConfig(createTestMergedSettings(), 'test-session', argv);
1591
1633
  expect(config.getApprovalMode()).toBe(ServerConfig.ApprovalMode.DEFAULT);
1592
1634
  });
1593
1635
  it('should set AUTO_EDIT approval mode when --approval-mode=auto_edit', async () => {
1594
1636
  process.argv = ['node', 'script.js', '--approval-mode', 'auto_edit'];
1595
- const argv = await parseArguments({});
1596
- const config = await loadCliConfig({}, 'test-session', argv);
1637
+ const argv = await parseArguments(createTestMergedSettings());
1638
+ const config = await loadCliConfig(createTestMergedSettings(), 'test-session', argv);
1597
1639
  expect(config.getApprovalMode()).toBe(ServerConfig.ApprovalMode.AUTO_EDIT);
1598
1640
  });
1599
1641
  it('should set YOLO approval mode when --approval-mode=yolo', async () => {
1600
1642
  process.argv = ['node', 'script.js', '--approval-mode', 'yolo'];
1601
- const argv = await parseArguments({});
1602
- const config = await loadCliConfig({}, 'test-session', argv);
1643
+ const argv = await parseArguments(createTestMergedSettings());
1644
+ const config = await loadCliConfig(createTestMergedSettings(), 'test-session', argv);
1603
1645
  expect(config.getApprovalMode()).toBe(ServerConfig.ApprovalMode.YOLO);
1604
1646
  });
1605
1647
  it('should prioritize --approval-mode over --yolo when both would be valid (but validation prevents this)', async () => {
1606
1648
  // Note: This test documents the intended behavior, but in practice the validation
1607
1649
  // prevents both flags from being used together
1608
1650
  process.argv = ['node', 'script.js', '--approval-mode', 'default'];
1609
- const argv = await parseArguments({});
1651
+ const argv = await parseArguments(createTestMergedSettings());
1610
1652
  // Manually set yolo to true to simulate what would happen if validation didn't prevent it
1611
1653
  argv.yolo = true;
1612
- const config = await loadCliConfig({}, 'test-session', argv);
1654
+ const config = await loadCliConfig(createTestMergedSettings(), 'test-session', argv);
1613
1655
  expect(config.getApprovalMode()).toBe(ServerConfig.ApprovalMode.DEFAULT);
1614
1656
  });
1615
1657
  it('should fall back to --yolo behavior when --approval-mode is not set', async () => {
1616
1658
  process.argv = ['node', 'script.js', '--yolo'];
1617
- const argv = await parseArguments({});
1618
- const config = await loadCliConfig({}, 'test-session', argv);
1659
+ const argv = await parseArguments(createTestMergedSettings());
1660
+ const config = await loadCliConfig(createTestMergedSettings(), 'test-session', argv);
1619
1661
  expect(config.getApprovalMode()).toBe(ServerConfig.ApprovalMode.YOLO);
1620
1662
  });
1663
+ it('should set Plan approval mode when --approval-mode=plan is used and experimental.plan is enabled', async () => {
1664
+ process.argv = ['node', 'script.js', '--approval-mode', 'plan'];
1665
+ const argv = await parseArguments(createTestMergedSettings());
1666
+ const settings = createTestMergedSettings({
1667
+ experimental: {
1668
+ plan: true,
1669
+ },
1670
+ });
1671
+ const config = await loadCliConfig(settings, 'test-session', argv);
1672
+ expect(config.getApprovalMode()).toBe(ServerConfig.ApprovalMode.PLAN);
1673
+ });
1674
+ it('should throw error when --approval-mode=plan is used but experimental.plan is disabled', async () => {
1675
+ process.argv = ['node', 'script.js', '--approval-mode', 'plan'];
1676
+ const argv = await parseArguments(createTestMergedSettings());
1677
+ const settings = createTestMergedSettings({
1678
+ experimental: {
1679
+ plan: false,
1680
+ },
1681
+ });
1682
+ await expect(loadCliConfig(settings, 'test-session', argv)).rejects.toThrow('Approval mode "plan" is only available when experimental.plan is enabled.');
1683
+ });
1684
+ it('should throw error when --approval-mode=plan is used but experimental.plan setting is missing', async () => {
1685
+ process.argv = ['node', 'script.js', '--approval-mode', 'plan'];
1686
+ const argv = await parseArguments(createTestMergedSettings());
1687
+ const settings = createTestMergedSettings({});
1688
+ await expect(loadCliConfig(settings, 'test-session', argv)).rejects.toThrow('Approval mode "plan" is only available when experimental.plan is enabled.');
1689
+ });
1621
1690
  // --- Untrusted Folder Scenarios ---
1622
1691
  describe('when folder is NOT trusted', () => {
1623
1692
  beforeEach(() => {
@@ -1628,26 +1697,26 @@ describe('loadCliConfig approval mode', () => {
1628
1697
  });
1629
1698
  it('should override --approval-mode=yolo to DEFAULT', async () => {
1630
1699
  process.argv = ['node', 'script.js', '--approval-mode', 'yolo'];
1631
- const argv = await parseArguments({});
1632
- const config = await loadCliConfig({}, 'test-session', argv);
1700
+ const argv = await parseArguments(createTestMergedSettings());
1701
+ const config = await loadCliConfig(createTestMergedSettings(), 'test-session', argv);
1633
1702
  expect(config.getApprovalMode()).toBe(ServerConfig.ApprovalMode.DEFAULT);
1634
1703
  });
1635
1704
  it('should override --approval-mode=auto_edit to DEFAULT', async () => {
1636
1705
  process.argv = ['node', 'script.js', '--approval-mode', 'auto_edit'];
1637
- const argv = await parseArguments({});
1638
- const config = await loadCliConfig({}, 'test-session', argv);
1706
+ const argv = await parseArguments(createTestMergedSettings());
1707
+ const config = await loadCliConfig(createTestMergedSettings(), 'test-session', argv);
1639
1708
  expect(config.getApprovalMode()).toBe(ServerConfig.ApprovalMode.DEFAULT);
1640
1709
  });
1641
1710
  it('should override --yolo flag to DEFAULT', async () => {
1642
1711
  process.argv = ['node', 'script.js', '--yolo'];
1643
- const argv = await parseArguments({});
1644
- const config = await loadCliConfig({}, 'test-session', argv);
1712
+ const argv = await parseArguments(createTestMergedSettings());
1713
+ const config = await loadCliConfig(createTestMergedSettings(), 'test-session', argv);
1645
1714
  expect(config.getApprovalMode()).toBe(ServerConfig.ApprovalMode.DEFAULT);
1646
1715
  });
1647
1716
  it('should remain DEFAULT when --approval-mode=default', async () => {
1648
1717
  process.argv = ['node', 'script.js', '--approval-mode', 'default'];
1649
- const argv = await parseArguments({});
1650
- const config = await loadCliConfig({}, 'test-session', argv);
1718
+ const argv = await parseArguments(createTestMergedSettings());
1719
+ const config = await loadCliConfig(createTestMergedSettings(), 'test-session', argv);
1651
1720
  expect(config.getApprovalMode()).toBe(ServerConfig.ApprovalMode.DEFAULT);
1652
1721
  });
1653
1722
  });
@@ -1668,13 +1737,13 @@ describe('loadCliConfig fileFiltering', () => {
1668
1737
  });
1669
1738
  const testCases = [
1670
1739
  {
1671
- property: 'disableFuzzySearch',
1672
- getter: (c) => c.getFileFilteringDisableFuzzySearch(),
1740
+ property: 'enableFuzzySearch',
1741
+ getter: (c) => c.getFileFilteringEnableFuzzySearch(),
1673
1742
  value: true,
1674
1743
  },
1675
1744
  {
1676
- property: 'disableFuzzySearch',
1677
- getter: (c) => c.getFileFilteringDisableFuzzySearch(),
1745
+ property: 'enableFuzzySearch',
1746
+ getter: (c) => c.getFileFilteringEnableFuzzySearch(),
1678
1747
  value: false,
1679
1748
  },
1680
1749
  {
@@ -1709,11 +1778,11 @@ describe('loadCliConfig fileFiltering', () => {
1709
1778
  },
1710
1779
  ];
1711
1780
  it.each(testCases)('should pass $property from settings to config when $value', async ({ property, getter, value }) => {
1712
- const settings = {
1781
+ const settings = createTestMergedSettings({
1713
1782
  context: {
1714
1783
  fileFiltering: { [property]: value },
1715
1784
  },
1716
- };
1785
+ });
1717
1786
  const argv = await parseArguments(settings);
1718
1787
  const config = await loadCliConfig(settings, 'test-session', argv);
1719
1788
  expect(getter(config)).toBe(value);
@@ -1728,26 +1797,26 @@ describe('Output format', () => {
1728
1797
  });
1729
1798
  it('should default to TEXT', async () => {
1730
1799
  process.argv = ['node', 'script.js'];
1731
- const argv = await parseArguments({});
1732
- const config = await loadCliConfig({}, 'test-session', argv);
1800
+ const argv = await parseArguments(createTestMergedSettings());
1801
+ const config = await loadCliConfig(createTestMergedSettings(), 'test-session', argv);
1733
1802
  expect(config.getOutputFormat()).toBe(OutputFormat.TEXT);
1734
1803
  });
1735
1804
  it('should use the format from settings', async () => {
1736
1805
  process.argv = ['node', 'script.js'];
1737
- const argv = await parseArguments({});
1738
- const config = await loadCliConfig({ output: { format: OutputFormat.JSON } }, 'test-session', argv);
1806
+ const argv = await parseArguments(createTestMergedSettings());
1807
+ const config = await loadCliConfig(createTestMergedSettings({ output: { format: OutputFormat.JSON } }), 'test-session', argv);
1739
1808
  expect(config.getOutputFormat()).toBe(OutputFormat.JSON);
1740
1809
  });
1741
1810
  it('should prioritize the format from argv', async () => {
1742
1811
  process.argv = ['node', 'script.js', '--output-format', 'json'];
1743
- const argv = await parseArguments({});
1744
- const config = await loadCliConfig({ output: { format: OutputFormat.JSON } }, 'test-session', argv);
1812
+ const argv = await parseArguments(createTestMergedSettings());
1813
+ const config = await loadCliConfig(createTestMergedSettings({ output: { format: OutputFormat.JSON } }), 'test-session', argv);
1745
1814
  expect(config.getOutputFormat()).toBe(OutputFormat.JSON);
1746
1815
  });
1747
1816
  it('should accept stream-json as a valid output format', async () => {
1748
1817
  process.argv = ['node', 'script.js', '--output-format', 'stream-json'];
1749
- const argv = await parseArguments({});
1750
- const config = await loadCliConfig({}, 'test-session', argv);
1818
+ const argv = await parseArguments(createTestMergedSettings());
1819
+ const config = await loadCliConfig(createTestMergedSettings(), 'test-session', argv);
1751
1820
  expect(config.getOutputFormat()).toBe(OutputFormat.STREAM_JSON);
1752
1821
  });
1753
1822
  it('should error on invalid --output-format argument', async () => {
@@ -1761,7 +1830,7 @@ describe('Output format', () => {
1761
1830
  const debugErrorSpy = vi
1762
1831
  .spyOn(debugLogger, 'error')
1763
1832
  .mockImplementation(() => { });
1764
- await expect(parseArguments({})).rejects.toThrow('process.exit called');
1833
+ await expect(parseArguments(createTestMergedSettings())).rejects.toThrow('process.exit called');
1765
1834
  expect(debugErrorSpy).toHaveBeenCalledWith(expect.stringContaining('Invalid values:'));
1766
1835
  expect(mockConsoleError).toHaveBeenCalled();
1767
1836
  mockExit.mockRestore();
@@ -1792,7 +1861,7 @@ describe('parseArguments with positional prompt', () => {
1792
1861
  const debugErrorSpy = vi
1793
1862
  .spyOn(debugLogger, 'error')
1794
1863
  .mockImplementation(() => { });
1795
- await expect(parseArguments({})).rejects.toThrow('process.exit called');
1864
+ await expect(parseArguments(createTestMergedSettings())).rejects.toThrow('process.exit called');
1796
1865
  expect(debugErrorSpy).toHaveBeenCalledWith(expect.stringContaining('Cannot use both a positional prompt and the --prompt (-p) flag together'));
1797
1866
  mockExit.mockRestore();
1798
1867
  mockConsoleError.mockRestore();
@@ -1800,7 +1869,7 @@ describe('parseArguments with positional prompt', () => {
1800
1869
  });
1801
1870
  it('should correctly parse a positional prompt to query field', async () => {
1802
1871
  process.argv = ['node', 'script.js', 'positional', 'prompt'];
1803
- const argv = await parseArguments({});
1872
+ const argv = await parseArguments(createTestMergedSettings());
1804
1873
  expect(argv.query).toBe('positional prompt');
1805
1874
  // Since no explicit prompt flags are set and query doesn't start with @, should map to prompt (one-shot)
1806
1875
  expect(argv.prompt).toBe('positional prompt');
@@ -1812,12 +1881,12 @@ describe('parseArguments with positional prompt', () => {
1812
1881
  // This test verifies that the positional 'query' argument is properly configured
1813
1882
  // with the description: "Positional prompt. Defaults to one-shot; use -i/--prompt-interactive for interactive."
1814
1883
  process.argv = ['node', 'script.js', 'test', 'query'];
1815
- const argv = await yargsInstance.parseArguments({});
1884
+ const argv = await yargsInstance.parseArguments(createTestMergedSettings());
1816
1885
  expect(argv.query).toBe('test query');
1817
1886
  });
1818
1887
  it('should correctly parse a prompt from the --prompt flag', async () => {
1819
1888
  process.argv = ['node', 'script.js', '--prompt', 'test prompt'];
1820
- const argv = await parseArguments({});
1889
+ const argv = await parseArguments(createTestMergedSettings());
1821
1890
  expect(argv.prompt).toBe('test prompt');
1822
1891
  });
1823
1892
  });
@@ -1831,28 +1900,30 @@ describe('Telemetry configuration via environment variables', () => {
1831
1900
  it('should prioritize GEMINI_TELEMETRY_ENABLED over settings', async () => {
1832
1901
  vi.stubEnv('GEMINI_TELEMETRY_ENABLED', 'true');
1833
1902
  process.argv = ['node', 'script.js'];
1834
- const argv = await parseArguments({});
1835
- const settings = { telemetry: { enabled: false } };
1903
+ const argv = await parseArguments(createTestMergedSettings());
1904
+ const settings = createTestMergedSettings({
1905
+ telemetry: { enabled: false },
1906
+ });
1836
1907
  const config = await loadCliConfig(settings, 'test-session', argv);
1837
1908
  expect(config.getTelemetryEnabled()).toBe(true);
1838
1909
  });
1839
1910
  it('should prioritize GEMINI_TELEMETRY_TARGET over settings', async () => {
1840
1911
  vi.stubEnv('GEMINI_TELEMETRY_TARGET', 'gcp');
1841
1912
  process.argv = ['node', 'script.js'];
1842
- const argv = await parseArguments({});
1843
- const settings = {
1913
+ const argv = await parseArguments(createTestMergedSettings());
1914
+ const settings = createTestMergedSettings({
1844
1915
  telemetry: { target: ServerConfig.TelemetryTarget.LOCAL },
1845
- };
1916
+ });
1846
1917
  const config = await loadCliConfig(settings, 'test-session', argv);
1847
1918
  expect(config.getTelemetryTarget()).toBe('gcp');
1848
1919
  });
1849
1920
  it('should throw when GEMINI_TELEMETRY_TARGET is invalid', async () => {
1850
1921
  vi.stubEnv('GEMINI_TELEMETRY_TARGET', 'bogus');
1851
1922
  process.argv = ['node', 'script.js'];
1852
- const argv = await parseArguments({});
1853
- const settings = {
1923
+ const argv = await parseArguments(createTestMergedSettings());
1924
+ const settings = createTestMergedSettings({
1854
1925
  telemetry: { target: ServerConfig.TelemetryTarget.GCP },
1855
- };
1926
+ });
1856
1927
  await expect(loadCliConfig(settings, 'test-session', argv)).rejects.toThrow(/Invalid telemetry configuration: .*Invalid telemetry target/i);
1857
1928
  vi.unstubAllEnvs();
1858
1929
  });
@@ -1860,91 +1931,97 @@ describe('Telemetry configuration via environment variables', () => {
1860
1931
  vi.stubEnv('OTEL_EXPORTER_OTLP_ENDPOINT', 'http://default.env.com');
1861
1932
  vi.stubEnv('GEMINI_TELEMETRY_OTLP_ENDPOINT', 'http://gemini.env.com');
1862
1933
  process.argv = ['node', 'script.js'];
1863
- const argv = await parseArguments({});
1864
- const settings = {
1934
+ const argv = await parseArguments(createTestMergedSettings());
1935
+ const settings = createTestMergedSettings({
1865
1936
  telemetry: { otlpEndpoint: 'http://settings.com' },
1866
- };
1937
+ });
1867
1938
  const config = await loadCliConfig(settings, 'test-session', argv);
1868
1939
  expect(config.getTelemetryOtlpEndpoint()).toBe('http://gemini.env.com');
1869
1940
  });
1870
1941
  it('should prioritize GEMINI_TELEMETRY_OTLP_PROTOCOL over settings', async () => {
1871
1942
  vi.stubEnv('GEMINI_TELEMETRY_OTLP_PROTOCOL', 'http');
1872
1943
  process.argv = ['node', 'script.js'];
1873
- const argv = await parseArguments({});
1874
- const settings = { telemetry: { otlpProtocol: 'grpc' } };
1944
+ const argv = await parseArguments(createTestMergedSettings());
1945
+ const settings = createTestMergedSettings({
1946
+ telemetry: { otlpProtocol: 'grpc' },
1947
+ });
1875
1948
  const config = await loadCliConfig(settings, 'test-session', argv);
1876
1949
  expect(config.getTelemetryOtlpProtocol()).toBe('http');
1877
1950
  });
1878
1951
  it('should prioritize GEMINI_TELEMETRY_LOG_PROMPTS over settings', async () => {
1879
1952
  vi.stubEnv('GEMINI_TELEMETRY_LOG_PROMPTS', 'false');
1880
1953
  process.argv = ['node', 'script.js'];
1881
- const argv = await parseArguments({});
1882
- const settings = { telemetry: { logPrompts: true } };
1954
+ const argv = await parseArguments(createTestMergedSettings());
1955
+ const settings = createTestMergedSettings({
1956
+ telemetry: { logPrompts: true },
1957
+ });
1883
1958
  const config = await loadCliConfig(settings, 'test-session', argv);
1884
1959
  expect(config.getTelemetryLogPromptsEnabled()).toBe(false);
1885
1960
  });
1886
1961
  it('should prioritize GEMINI_TELEMETRY_OUTFILE over settings', async () => {
1887
1962
  vi.stubEnv('GEMINI_TELEMETRY_OUTFILE', '/gemini/env/telemetry.log');
1888
1963
  process.argv = ['node', 'script.js'];
1889
- const argv = await parseArguments({});
1890
- const settings = {
1964
+ const argv = await parseArguments(createTestMergedSettings());
1965
+ const settings = createTestMergedSettings({
1891
1966
  telemetry: { outfile: '/settings/telemetry.log' },
1892
- };
1967
+ });
1893
1968
  const config = await loadCliConfig(settings, 'test-session', argv);
1894
1969
  expect(config.getTelemetryOutfile()).toBe('/gemini/env/telemetry.log');
1895
1970
  });
1896
1971
  it('should prioritize GEMINI_TELEMETRY_USE_COLLECTOR over settings', async () => {
1897
1972
  vi.stubEnv('GEMINI_TELEMETRY_USE_COLLECTOR', 'true');
1898
1973
  process.argv = ['node', 'script.js'];
1899
- const argv = await parseArguments({});
1900
- const settings = { telemetry: { useCollector: false } };
1974
+ const argv = await parseArguments(createTestMergedSettings());
1975
+ const settings = createTestMergedSettings({
1976
+ telemetry: { useCollector: false },
1977
+ });
1901
1978
  const config = await loadCliConfig(settings, 'test-session', argv);
1902
1979
  expect(config.getTelemetryUseCollector()).toBe(true);
1903
1980
  });
1904
1981
  it('should use settings value when GEMINI_TELEMETRY_ENABLED is not set', async () => {
1905
1982
  vi.stubEnv('GEMINI_TELEMETRY_ENABLED', undefined);
1906
1983
  process.argv = ['node', 'script.js'];
1907
- const argv = await parseArguments({});
1908
- const settings = { telemetry: { enabled: true } };
1984
+ const argv = await parseArguments(createTestMergedSettings());
1985
+ const settings = createTestMergedSettings({ telemetry: { enabled: true } });
1909
1986
  const config = await loadCliConfig(settings, 'test-session', argv);
1910
1987
  expect(config.getTelemetryEnabled()).toBe(true);
1911
1988
  });
1912
1989
  it('should use settings value when GEMINI_TELEMETRY_TARGET is not set', async () => {
1913
1990
  vi.stubEnv('GEMINI_TELEMETRY_TARGET', undefined);
1914
1991
  process.argv = ['node', 'script.js'];
1915
- const argv = await parseArguments({});
1916
- const settings = {
1992
+ const argv = await parseArguments(createTestMergedSettings());
1993
+ const settings = createTestMergedSettings({
1917
1994
  telemetry: { target: ServerConfig.TelemetryTarget.LOCAL },
1918
- };
1995
+ });
1919
1996
  const config = await loadCliConfig(settings, 'test-session', argv);
1920
1997
  expect(config.getTelemetryTarget()).toBe('local');
1921
1998
  });
1922
1999
  it("should treat GEMINI_TELEMETRY_ENABLED='1' as true", async () => {
1923
2000
  vi.stubEnv('GEMINI_TELEMETRY_ENABLED', '1');
1924
2001
  process.argv = ['node', 'script.js'];
1925
- const argv = await parseArguments({});
1926
- const config = await loadCliConfig({}, 'test-session', argv);
2002
+ const argv = await parseArguments(createTestMergedSettings());
2003
+ const config = await loadCliConfig(createTestMergedSettings(), 'test-session', argv);
1927
2004
  expect(config.getTelemetryEnabled()).toBe(true);
1928
2005
  });
1929
2006
  it("should treat GEMINI_TELEMETRY_ENABLED='0' as false", async () => {
1930
2007
  vi.stubEnv('GEMINI_TELEMETRY_ENABLED', '0');
1931
2008
  process.argv = ['node', 'script.js'];
1932
- const argv = await parseArguments({});
1933
- const config = await loadCliConfig({ telemetry: { enabled: true } }, 'test-session', argv);
2009
+ const argv = await parseArguments(createTestMergedSettings());
2010
+ const config = await loadCliConfig(createTestMergedSettings({ telemetry: { enabled: true } }), 'test-session', argv);
1934
2011
  expect(config.getTelemetryEnabled()).toBe(false);
1935
2012
  });
1936
2013
  it("should treat GEMINI_TELEMETRY_LOG_PROMPTS='1' as true", async () => {
1937
2014
  vi.stubEnv('GEMINI_TELEMETRY_LOG_PROMPTS', '1');
1938
2015
  process.argv = ['node', 'script.js'];
1939
- const argv = await parseArguments({});
1940
- const config = await loadCliConfig({}, 'test-session', argv);
2016
+ const argv = await parseArguments(createTestMergedSettings());
2017
+ const config = await loadCliConfig(createTestMergedSettings(), 'test-session', argv);
1941
2018
  expect(config.getTelemetryLogPromptsEnabled()).toBe(true);
1942
2019
  });
1943
2020
  it("should treat GEMINI_TELEMETRY_LOG_PROMPTS='false' as false", async () => {
1944
2021
  vi.stubEnv('GEMINI_TELEMETRY_LOG_PROMPTS', 'false');
1945
2022
  process.argv = ['node', 'script.js'];
1946
- const argv = await parseArguments({});
1947
- const config = await loadCliConfig({ telemetry: { logPrompts: true } }, 'test-session', argv);
2023
+ const argv = await parseArguments(createTestMergedSettings());
2024
+ const config = await loadCliConfig(createTestMergedSettings({ telemetry: { logPrompts: true } }), 'test-session', argv);
1948
2025
  expect(config.getTelemetryLogPromptsEnabled()).toBe(false);
1949
2026
  });
1950
2027
  });
@@ -1962,8 +2039,8 @@ describe('PolicyEngine nonInteractive wiring', () => {
1962
2039
  it('should set nonInteractive to true in one-shot mode', async () => {
1963
2040
  process.stdin.isTTY = true;
1964
2041
  process.argv = ['node', 'script.js', 'echo hello']; // Positional query makes it one-shot
1965
- const argv = await parseArguments({});
1966
- const config = await loadCliConfig({}, 'test-session', argv);
2042
+ const argv = await parseArguments(createTestMergedSettings());
2043
+ const config = await loadCliConfig(createTestMergedSettings(), 'test-session', argv);
1967
2044
  expect(config.isInteractive()).toBe(false);
1968
2045
  expect(config.getPolicyEngine()
1969
2046
  .nonInteractive).toBe(true);
@@ -1971,8 +2048,8 @@ describe('PolicyEngine nonInteractive wiring', () => {
1971
2048
  it('should set nonInteractive to false in interactive mode', async () => {
1972
2049
  process.stdin.isTTY = true;
1973
2050
  process.argv = ['node', 'script.js'];
1974
- const argv = await parseArguments({});
1975
- const config = await loadCliConfig({}, 'test-session', argv);
2051
+ const argv = await parseArguments(createTestMergedSettings());
2052
+ const config = await loadCliConfig(createTestMergedSettings(), 'test-session', argv);
1976
2053
  expect(config.isInteractive()).toBe(true);
1977
2054
  expect(config.getPolicyEngine()
1978
2055
  .nonInteractive).toBe(false);
@@ -1991,8 +2068,10 @@ describe('Policy Engine Integration in loadCliConfig', () => {
1991
2068
  });
1992
2069
  it('should pass merged allowed tools from CLI and settings to createPolicyEngineConfig', async () => {
1993
2070
  process.argv = ['node', 'script.js', '--allowed-tools', 'cli-tool'];
1994
- const settings = { tools: { allowed: ['settings-tool'] } };
1995
- const argv = await parseArguments({});
2071
+ const settings = createTestMergedSettings({
2072
+ tools: { allowed: ['settings-tool'] },
2073
+ });
2074
+ const argv = await parseArguments(createTestMergedSettings());
1996
2075
  await loadCliConfig(settings, 'test-session', argv);
1997
2076
  expect(ServerConfig.createPolicyEngineConfig).toHaveBeenCalledWith(expect.objectContaining({
1998
2077
  tools: expect.objectContaining({
@@ -2003,8 +2082,10 @@ describe('Policy Engine Integration in loadCliConfig', () => {
2003
2082
  it('should pass merged exclude tools from CLI logic and settings to createPolicyEngineConfig', async () => {
2004
2083
  process.stdin.isTTY = false; // Non-interactive to trigger default excludes
2005
2084
  process.argv = ['node', 'script.js', '-p', 'test'];
2006
- const settings = { tools: { exclude: ['settings-exclude'] } };
2007
- const argv = await parseArguments({});
2085
+ const settings = createTestMergedSettings({
2086
+ tools: { exclude: ['settings-exclude'] },
2087
+ });
2088
+ const argv = await parseArguments(createTestMergedSettings());
2008
2089
  await loadCliConfig(settings, 'test-session', argv);
2009
2090
  // In non-interactive mode, ShellTool, etc. are excluded
2010
2091
  expect(ServerConfig.createPolicyEngineConfig).toHaveBeenCalledWith(expect.objectContaining({
@@ -2031,19 +2112,19 @@ describe('loadCliConfig disableYoloMode', () => {
2031
2112
  });
2032
2113
  it('should allow auto_edit mode even if yolo mode is disabled', async () => {
2033
2114
  process.argv = ['node', 'script.js', '--approval-mode=auto_edit'];
2034
- const argv = await parseArguments({});
2035
- const settings = {
2115
+ const argv = await parseArguments(createTestMergedSettings());
2116
+ const settings = createTestMergedSettings({
2036
2117
  security: { disableYoloMode: true },
2037
- };
2118
+ });
2038
2119
  const config = await loadCliConfig(settings, 'test-session', argv);
2039
2120
  expect(config.getApprovalMode()).toBe(ApprovalMode.AUTO_EDIT);
2040
2121
  });
2041
2122
  it('should throw if YOLO mode is attempted when disableYoloMode is true', async () => {
2042
2123
  process.argv = ['node', 'script.js', '--yolo'];
2043
- const argv = await parseArguments({});
2044
- const settings = {
2124
+ const argv = await parseArguments(createTestMergedSettings());
2125
+ const settings = createTestMergedSettings({
2045
2126
  security: { disableYoloMode: true },
2046
- };
2127
+ });
2047
2128
  await expect(loadCliConfig(settings, 'test-session', argv)).rejects.toThrow('Cannot start in YOLO mode since it is disabled by your admin');
2048
2129
  });
2049
2130
  });
@@ -2064,32 +2145,32 @@ describe('loadCliConfig secureModeEnabled', () => {
2064
2145
  });
2065
2146
  it('should throw an error if YOLO mode is attempted when secureModeEnabled is true', async () => {
2066
2147
  process.argv = ['node', 'script.js', '--yolo'];
2067
- const argv = await parseArguments({});
2068
- const settings = {
2148
+ const argv = await parseArguments(createTestMergedSettings());
2149
+ const settings = createTestMergedSettings({
2069
2150
  admin: {
2070
2151
  secureModeEnabled: true,
2071
2152
  },
2072
- };
2153
+ });
2073
2154
  await expect(loadCliConfig(settings, 'test-session', argv)).rejects.toThrow('Cannot start in YOLO mode since it is disabled by your admin');
2074
2155
  });
2075
2156
  it('should throw an error if approval-mode=yolo is attempted when secureModeEnabled is true', async () => {
2076
2157
  process.argv = ['node', 'script.js', '--approval-mode=yolo'];
2077
- const argv = await parseArguments({});
2078
- const settings = {
2158
+ const argv = await parseArguments(createTestMergedSettings());
2159
+ const settings = createTestMergedSettings({
2079
2160
  admin: {
2080
2161
  secureModeEnabled: true,
2081
2162
  },
2082
- };
2163
+ });
2083
2164
  await expect(loadCliConfig(settings, 'test-session', argv)).rejects.toThrow('Cannot start in YOLO mode since it is disabled by your admin');
2084
2165
  });
2085
2166
  it('should set disableYoloMode to true when secureModeEnabled is true', async () => {
2086
2167
  process.argv = ['node', 'script.js'];
2087
- const argv = await parseArguments({});
2088
- const settings = {
2168
+ const argv = await parseArguments(createTestMergedSettings());
2169
+ const settings = createTestMergedSettings({
2089
2170
  admin: {
2090
2171
  secureModeEnabled: true,
2091
2172
  },
2092
- };
2173
+ });
2093
2174
  const config = await loadCliConfig(settings, 'test-session', argv);
2094
2175
  expect(config.isYoloModeDisabled()).toBe(true);
2095
2176
  });
@@ -2115,8 +2196,8 @@ describe('loadCliConfig mcpEnabled', () => {
2115
2196
  };
2116
2197
  it('should enable MCP by default', async () => {
2117
2198
  process.argv = ['node', 'script.js'];
2118
- const argv = await parseArguments({});
2119
- const settings = { ...mcpSettings };
2199
+ const argv = await parseArguments(createTestMergedSettings());
2200
+ const settings = createTestMergedSettings({ ...mcpSettings });
2120
2201
  const config = await loadCliConfig(settings, 'test-session', argv);
2121
2202
  expect(config.getMcpEnabled()).toBe(true);
2122
2203
  expect(config.getMcpServerCommand()).toBe('mcp-server');
@@ -2126,15 +2207,15 @@ describe('loadCliConfig mcpEnabled', () => {
2126
2207
  });
2127
2208
  it('should disable MCP when mcpEnabled is false', async () => {
2128
2209
  process.argv = ['node', 'script.js'];
2129
- const argv = await parseArguments({});
2130
- const settings = {
2210
+ const argv = await parseArguments(createTestMergedSettings());
2211
+ const settings = createTestMergedSettings({
2131
2212
  ...mcpSettings,
2132
2213
  admin: {
2133
2214
  mcp: {
2134
2215
  enabled: false,
2135
2216
  },
2136
2217
  },
2137
- };
2218
+ });
2138
2219
  const config = await loadCliConfig(settings, 'test-session', argv);
2139
2220
  expect(config.getMcpEnabled()).toBe(false);
2140
2221
  expect(config.getMcpServerCommand()).toBeUndefined();
@@ -2144,15 +2225,15 @@ describe('loadCliConfig mcpEnabled', () => {
2144
2225
  });
2145
2226
  it('should enable MCP when mcpEnabled is true', async () => {
2146
2227
  process.argv = ['node', 'script.js'];
2147
- const argv = await parseArguments({});
2148
- const settings = {
2228
+ const argv = await parseArguments(createTestMergedSettings());
2229
+ const settings = createTestMergedSettings({
2149
2230
  ...mcpSettings,
2150
2231
  admin: {
2151
2232
  mcp: {
2152
2233
  enabled: true,
2153
2234
  },
2154
2235
  },
2155
- };
2236
+ });
2156
2237
  const config = await loadCliConfig(settings, 'test-session', argv);
2157
2238
  expect(config.getMcpEnabled()).toBe(true);
2158
2239
  expect(config.getMcpServerCommand()).toBe('mcp-server');