@google/gemini-cli 0.18.0-preview.1 → 0.19.0-nightly.20251122.42c2e1b21

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 (203) hide show
  1. package/dist/google-gemini-cli-0.19.0-nightly.20251120.8e531dc02.tgz +0 -0
  2. package/dist/index.js +8 -6
  3. package/dist/index.js.map +1 -1
  4. package/dist/package.json +3 -3
  5. package/dist/src/commands/extensions/examples/mcp-server/package.json +1 -1
  6. package/dist/src/config/auth.js +4 -0
  7. package/dist/src/config/auth.js.map +1 -1
  8. package/dist/src/config/auth.test.js +61 -37
  9. package/dist/src/config/auth.test.js.map +1 -1
  10. package/dist/src/config/config.integration.test.js +81 -198
  11. package/dist/src/config/config.integration.test.js.map +1 -1
  12. package/dist/src/config/config.js +2 -6
  13. package/dist/src/config/config.js.map +1 -1
  14. package/dist/src/config/config.test.js +196 -299
  15. package/dist/src/config/config.test.js.map +1 -1
  16. package/dist/src/config/extension.test.js +109 -133
  17. package/dist/src/config/extension.test.js.map +1 -1
  18. package/dist/src/config/extensions/consent.test.js +152 -0
  19. package/dist/src/config/extensions/consent.test.js.map +1 -0
  20. package/dist/src/config/extensions/extensionEnablement.test.js +82 -15
  21. package/dist/src/config/extensions/extensionEnablement.test.js.map +1 -1
  22. package/dist/src/config/extensions/extensionSettings.test.js +105 -1
  23. package/dist/src/config/extensions/extensionSettings.test.js.map +1 -1
  24. package/dist/src/config/extensions/github.d.ts +1 -0
  25. package/dist/src/config/extensions/github.js +1 -1
  26. package/dist/src/config/extensions/github.js.map +1 -1
  27. package/dist/src/config/extensions/github.test.js +197 -318
  28. package/dist/src/config/extensions/github.test.js.map +1 -1
  29. package/dist/src/config/extensions/storage.test.d.ts +6 -0
  30. package/dist/src/config/extensions/storage.test.js +64 -0
  31. package/dist/src/config/extensions/storage.test.js.map +1 -0
  32. package/dist/src/config/extensions/update.test.js +154 -263
  33. package/dist/src/config/extensions/update.test.js.map +1 -1
  34. package/dist/src/config/extensions/variables.test.js +87 -1
  35. package/dist/src/config/extensions/variables.test.js.map +1 -1
  36. package/dist/src/config/sandboxConfig.d.ts +1 -1
  37. package/dist/src/config/sandboxConfig.js.map +1 -1
  38. package/dist/src/config/sandboxConfig.test.d.ts +6 -0
  39. package/dist/src/config/sandboxConfig.test.js +178 -0
  40. package/dist/src/config/sandboxConfig.test.js.map +1 -0
  41. package/dist/src/config/settingPaths.test.d.ts +6 -0
  42. package/dist/src/config/settingPaths.test.js +22 -0
  43. package/dist/src/config/settingPaths.test.js.map +1 -0
  44. package/dist/src/config/settings.test.js +164 -226
  45. package/dist/src/config/settings.test.js.map +1 -1
  46. package/dist/src/config/settingsSchema.d.ts +10 -10
  47. package/dist/src/config/settingsSchema.js +10 -10
  48. package/dist/src/config/settingsSchema.js.map +1 -1
  49. package/dist/src/config/settingsSchema.test.js +0 -6
  50. package/dist/src/config/settingsSchema.test.js.map +1 -1
  51. package/dist/src/gemini.d.ts +1 -1
  52. package/dist/src/gemini.js +5 -7
  53. package/dist/src/gemini.js.map +1 -1
  54. package/dist/src/gemini.test.js +18 -21
  55. package/dist/src/gemini.test.js.map +1 -1
  56. package/dist/src/generated/git-commit.d.ts +2 -2
  57. package/dist/src/generated/git-commit.js +2 -2
  58. package/dist/src/generated/git-commit.js.map +1 -1
  59. package/dist/src/services/BuiltinCommandLoader.js +1 -1
  60. package/dist/src/services/BuiltinCommandLoader.js.map +1 -1
  61. package/dist/src/services/BuiltinCommandLoader.test.js +0 -22
  62. package/dist/src/services/BuiltinCommandLoader.test.js.map +1 -1
  63. package/dist/src/test-utils/mockCommandContext.js +1 -1
  64. package/dist/src/test-utils/render.js +1 -1
  65. package/dist/src/test-utils/render.js.map +1 -1
  66. package/dist/src/ui/AppContainer.js +13 -11
  67. package/dist/src/ui/AppContainer.js.map +1 -1
  68. package/dist/src/ui/AppContainer.test.js +10 -16
  69. package/dist/src/ui/AppContainer.test.js.map +1 -1
  70. package/dist/src/ui/auth/AuthDialog.js +17 -10
  71. package/dist/src/ui/auth/AuthDialog.js.map +1 -1
  72. package/dist/src/ui/auth/AuthDialog.test.js +5 -2
  73. package/dist/src/ui/auth/AuthDialog.test.js.map +1 -1
  74. package/dist/src/ui/components/AppHeader.js +3 -17
  75. package/dist/src/ui/components/AppHeader.js.map +1 -1
  76. package/dist/src/ui/components/AppHeader.test.js +10 -4
  77. package/dist/src/ui/components/AppHeader.test.js.map +1 -1
  78. package/dist/src/ui/components/DebugProfiler.js +1 -1
  79. package/dist/src/ui/components/DebugProfiler.js.map +1 -1
  80. package/dist/src/ui/components/DialogManager.js +6 -1
  81. package/dist/src/ui/components/DialogManager.js.map +1 -1
  82. package/dist/src/ui/components/InputPrompt.js +1 -1
  83. package/dist/src/ui/components/InputPrompt.js.map +1 -1
  84. package/dist/src/ui/components/LoadingIndicator.js +6 -1
  85. package/dist/src/ui/components/LoadingIndicator.js.map +1 -1
  86. package/dist/src/ui/components/ModelDialog.test.js +1 -1
  87. package/dist/src/ui/components/ModelDialog.test.js.map +1 -1
  88. package/dist/src/ui/components/SessionBrowser.d.ts +98 -0
  89. package/dist/src/ui/components/SessionBrowser.js +457 -0
  90. package/dist/src/ui/components/SessionBrowser.js.map +1 -0
  91. package/dist/src/ui/components/SessionBrowser.test.d.ts +6 -0
  92. package/dist/src/ui/components/SessionBrowser.test.js +245 -0
  93. package/dist/src/ui/components/SessionBrowser.test.js.map +1 -0
  94. package/dist/src/ui/components/messages/ShellToolMessage.js +2 -2
  95. package/dist/src/ui/components/messages/ShellToolMessage.js.map +1 -1
  96. package/dist/src/ui/components/messages/ToolMessage.d.ts +5 -0
  97. package/dist/src/ui/components/messages/ToolMessage.js +32 -3
  98. package/dist/src/ui/components/messages/ToolMessage.js.map +1 -1
  99. package/dist/src/ui/components/shared/text-buffer.js +20 -4
  100. package/dist/src/ui/components/shared/text-buffer.js.map +1 -1
  101. package/dist/src/ui/components/shared/text-buffer.test.js +20 -0
  102. package/dist/src/ui/components/shared/text-buffer.test.js.map +1 -1
  103. package/dist/src/ui/constants.d.ts +1 -0
  104. package/dist/src/ui/constants.js +1 -0
  105. package/dist/src/ui/constants.js.map +1 -1
  106. package/dist/src/ui/hooks/shellCommandProcessor.d.ts +1 -0
  107. package/dist/src/ui/hooks/shellCommandProcessor.js +3 -1
  108. package/dist/src/ui/hooks/shellCommandProcessor.js.map +1 -1
  109. package/dist/src/ui/hooks/useAlternateBuffer.js +1 -1
  110. package/dist/src/ui/hooks/useAlternateBuffer.js.map +1 -1
  111. package/dist/src/ui/hooks/useBanner.d.ts +14 -0
  112. package/dist/src/ui/hooks/useBanner.js +48 -0
  113. package/dist/src/ui/hooks/useBanner.js.map +1 -0
  114. package/dist/src/ui/hooks/useBanner.test.d.ts +6 -0
  115. package/dist/src/ui/hooks/useBanner.test.js +92 -0
  116. package/dist/src/ui/hooks/useBanner.test.js.map +1 -0
  117. package/dist/src/ui/hooks/useBracketedPaste.js +3 -5
  118. package/dist/src/ui/hooks/useBracketedPaste.js.map +1 -1
  119. package/dist/src/ui/hooks/useGeminiStream.d.ts +1 -0
  120. package/dist/src/ui/hooks/useGeminiStream.js +6 -4
  121. package/dist/src/ui/hooks/useGeminiStream.js.map +1 -1
  122. package/dist/src/ui/hooks/useGeminiStream.test.js +1 -1
  123. package/dist/src/ui/hooks/useGeminiStream.test.js.map +1 -1
  124. package/dist/src/ui/hooks/useInactivityTimer.d.ts +14 -0
  125. package/dist/src/ui/hooks/useInactivityTimer.js +30 -0
  126. package/dist/src/ui/hooks/useInactivityTimer.js.map +1 -0
  127. package/dist/src/ui/hooks/useLoadingIndicator.d.ts +1 -1
  128. package/dist/src/ui/hooks/useLoadingIndicator.js +2 -2
  129. package/dist/src/ui/hooks/useLoadingIndicator.js.map +1 -1
  130. package/dist/src/ui/hooks/useLoadingIndicator.test.js +16 -5
  131. package/dist/src/ui/hooks/useLoadingIndicator.test.js.map +1 -1
  132. package/dist/src/ui/hooks/usePhraseCycler.d.ts +4 -1
  133. package/dist/src/ui/hooks/usePhraseCycler.js +52 -43
  134. package/dist/src/ui/hooks/usePhraseCycler.js.map +1 -1
  135. package/dist/src/ui/hooks/usePhraseCycler.test.js +52 -3
  136. package/dist/src/ui/hooks/usePhraseCycler.test.js.map +1 -1
  137. package/dist/src/ui/hooks/useReactToolScheduler.d.ts +2 -1
  138. package/dist/src/ui/hooks/useReactToolScheduler.js +3 -0
  139. package/dist/src/ui/hooks/useReactToolScheduler.js.map +1 -1
  140. package/dist/src/ui/hooks/useSessionBrowser.d.ts +18 -1
  141. package/dist/src/ui/hooks/useSessionBrowser.js +59 -0
  142. package/dist/src/ui/hooks/useSessionBrowser.js.map +1 -1
  143. package/dist/src/ui/hooks/useSessionBrowser.test.js +154 -526
  144. package/dist/src/ui/hooks/useSessionBrowser.test.js.map +1 -1
  145. package/dist/src/ui/hooks/useSlashCompletion.test.js +1 -1
  146. package/dist/src/ui/hooks/useSlashCompletion.test.js.map +1 -1
  147. package/dist/src/ui/hooks/useToolScheduler.test.js +1 -1
  148. package/dist/src/ui/hooks/useToolScheduler.test.js.map +1 -1
  149. package/dist/src/ui/privacy/CloudFreePrivacyNotice.test.d.ts +6 -0
  150. package/dist/src/ui/privacy/CloudFreePrivacyNotice.test.js +121 -0
  151. package/dist/src/ui/privacy/CloudFreePrivacyNotice.test.js.map +1 -0
  152. package/dist/src/ui/privacy/CloudPaidPrivacyNotice.test.d.ts +6 -0
  153. package/dist/src/ui/privacy/CloudPaidPrivacyNotice.test.js +34 -0
  154. package/dist/src/ui/privacy/CloudPaidPrivacyNotice.test.js.map +1 -0
  155. package/dist/src/ui/privacy/GeminiPrivacyNotice.test.d.ts +6 -0
  156. package/dist/src/ui/privacy/GeminiPrivacyNotice.test.js +34 -0
  157. package/dist/src/ui/privacy/GeminiPrivacyNotice.test.js.map +1 -0
  158. package/dist/src/ui/privacy/PrivacyNotice.test.d.ts +6 -0
  159. package/dist/src/ui/privacy/PrivacyNotice.test.js +62 -0
  160. package/dist/src/ui/privacy/PrivacyNotice.test.js.map +1 -0
  161. package/dist/src/ui/types.js +1 -1
  162. package/dist/src/ui/utils/bracketedPaste.d.ts +7 -0
  163. package/dist/src/ui/utils/bracketedPaste.js +15 -0
  164. package/dist/src/ui/utils/bracketedPaste.js.map +1 -0
  165. package/dist/src/ui/utils/kittyProtocolDetector.js +3 -4
  166. package/dist/src/ui/utils/kittyProtocolDetector.js.map +1 -1
  167. package/dist/src/ui/utils/mouse.d.ts +2 -2
  168. package/dist/src/ui/utils/mouse.js +2 -11
  169. package/dist/src/ui/utils/mouse.js.map +1 -1
  170. package/dist/src/utils/persistentState.d.ts +1 -1
  171. package/dist/src/utils/sessionCleanup.test.js +38 -0
  172. package/dist/src/utils/sessionCleanup.test.js.map +1 -1
  173. package/dist/src/utils/sessionUtils.d.ts +49 -4
  174. package/dist/src/utils/sessionUtils.js +100 -25
  175. package/dist/src/utils/sessionUtils.js.map +1 -1
  176. package/dist/src/utils/sessionUtils.test.js +46 -3
  177. package/dist/src/utils/sessionUtils.test.js.map +1 -1
  178. package/dist/src/utils/sessions.js +4 -1
  179. package/dist/src/utils/sessions.js.map +1 -1
  180. package/dist/src/utils/sessions.test.js +42 -0
  181. package/dist/src/utils/sessions.test.js.map +1 -1
  182. package/dist/src/zed-integration/connection.test.d.ts +6 -0
  183. package/dist/src/zed-integration/connection.test.js +175 -0
  184. package/dist/src/zed-integration/connection.test.js.map +1 -0
  185. package/dist/src/zed-integration/fileSystemService.test.d.ts +6 -0
  186. package/dist/src/zed-integration/fileSystemService.test.js +98 -0
  187. package/dist/src/zed-integration/fileSystemService.test.js.map +1 -0
  188. package/dist/src/zed-integration/schema.d.ts +30 -30
  189. package/dist/src/zed-integration/zedIntegration.d.ts +31 -1
  190. package/dist/src/zed-integration/zedIntegration.js +5 -2
  191. package/dist/src/zed-integration/zedIntegration.js.map +1 -1
  192. package/dist/src/zed-integration/zedIntegration.test.d.ts +6 -0
  193. package/dist/src/zed-integration/zedIntegration.test.js +619 -0
  194. package/dist/src/zed-integration/zedIntegration.test.js.map +1 -0
  195. package/dist/tsconfig.tsbuildinfo +1 -1
  196. package/package.json +4 -4
  197. package/dist/google-gemini-cli-0.18.0-preview.0.tgz +0 -0
  198. package/dist/src/utils/stdio.d.ts +0 -32
  199. package/dist/src/utils/stdio.js +0 -85
  200. package/dist/src/utils/stdio.js.map +0 -1
  201. package/dist/src/utils/stdio.test.js +0 -47
  202. package/dist/src/utils/stdio.test.js.map +0 -1
  203. /package/dist/src/{utils/stdio.test.d.ts → config/extensions/consent.test.d.ts} +0 -0
@@ -6,7 +6,7 @@
6
6
  import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
7
7
  import * as os from 'node:os';
8
8
  import * as path from 'node:path';
9
- import { DEFAULT_FILE_FILTERING_OPTIONS, DEFAULT_GEMINI_MODEL, DEFAULT_GEMINI_MODEL_AUTO, OutputFormat, SHELL_TOOL_NAME, WRITE_FILE_TOOL_NAME, EDIT_TOOL_NAME, debugLogger, } from '@google/gemini-cli-core';
9
+ import { DEFAULT_FILE_FILTERING_OPTIONS, OutputFormat, SHELL_TOOL_NAME, WRITE_FILE_TOOL_NAME, EDIT_TOOL_NAME, debugLogger, } from '@google/gemini-cli-core';
10
10
  import { loadCliConfig, parseArguments } from './config.js';
11
11
  import * as ServerConfig from '@google/gemini-cli-core';
12
12
  import { isWorkspaceTrusted } from './trustedFolders.js';
@@ -111,241 +111,223 @@ afterEach(() => {
111
111
  }
112
112
  });
113
113
  describe('parseArguments', () => {
114
- it('should throw an error when both --prompt and --prompt-interactive are used together', async () => {
115
- process.argv = [
116
- 'node',
117
- 'script.js',
118
- '--prompt',
119
- 'test prompt',
120
- '--prompt-interactive',
121
- 'interactive prompt',
122
- ];
123
- const mockExit = vi.spyOn(process, 'exit').mockImplementation(() => {
124
- throw new Error('process.exit called');
125
- });
126
- const mockConsoleError = vi
127
- .spyOn(console, 'error')
128
- .mockImplementation(() => { });
129
- const debugErrorSpy = vi
130
- .spyOn(debugLogger, 'error')
131
- .mockImplementation(() => { });
132
- await expect(parseArguments({})).rejects.toThrow('process.exit called');
133
- expect(debugErrorSpy).toHaveBeenCalledWith(expect.stringContaining('Cannot use both --prompt (-p) and --prompt-interactive (-i) together'));
134
- // yargs.showHelp() calls console.error
135
- expect(mockConsoleError).toHaveBeenCalled();
136
- mockExit.mockRestore();
137
- mockConsoleError.mockRestore();
138
- debugErrorSpy.mockRestore();
139
- });
140
- it('should throw an error when using short flags -p and -i together', async () => {
141
- process.argv = [
142
- 'node',
143
- 'script.js',
144
- '-p',
145
- 'test prompt',
146
- '-i',
147
- 'interactive prompt',
148
- ];
114
+ it.each([
115
+ {
116
+ description: 'long flags',
117
+ argv: [
118
+ 'node',
119
+ 'script.js',
120
+ '--prompt',
121
+ 'test prompt',
122
+ '--prompt-interactive',
123
+ 'interactive prompt',
124
+ ],
125
+ },
126
+ {
127
+ description: 'short flags',
128
+ argv: [
129
+ 'node',
130
+ 'script.js',
131
+ '-p',
132
+ 'test prompt',
133
+ '-i',
134
+ 'interactive prompt',
135
+ ],
136
+ },
137
+ ])('should throw an error when using conflicting prompt flags ($description)', async ({ argv }) => {
138
+ process.argv = argv;
149
139
  const mockExit = vi.spyOn(process, 'exit').mockImplementation(() => {
150
140
  throw new Error('process.exit called');
151
141
  });
152
142
  const mockConsoleError = vi
153
143
  .spyOn(console, 'error')
154
144
  .mockImplementation(() => { });
155
- const debugErrorSpy = vi
156
- .spyOn(debugLogger, 'error')
157
- .mockImplementation(() => { });
158
145
  await expect(parseArguments({})).rejects.toThrow('process.exit called');
159
- expect(debugErrorSpy).toHaveBeenCalledWith(expect.stringContaining('Cannot use both --prompt (-p) and --prompt-interactive (-i) together'));
160
- expect(mockConsoleError).toHaveBeenCalled();
146
+ expect(mockConsoleError).toHaveBeenCalledWith(expect.stringContaining('Cannot use both --prompt (-p) and --prompt-interactive (-i) together'));
161
147
  mockExit.mockRestore();
162
148
  mockConsoleError.mockRestore();
163
- debugErrorSpy.mockRestore();
164
- });
165
- it('should allow --prompt without --prompt-interactive', async () => {
166
- process.argv = ['node', 'script.js', '--prompt', 'test prompt'];
167
- const argv = await parseArguments({});
168
- expect(argv.prompt).toBe('test prompt');
169
- expect(argv.promptInteractive).toBeUndefined();
170
- });
171
- it('should allow --prompt-interactive without --prompt', async () => {
172
- process.argv = [
173
- 'node',
174
- 'script.js',
175
- '--prompt-interactive',
176
- 'interactive prompt',
177
- ];
178
- const argv = await parseArguments({});
179
- expect(argv.promptInteractive).toBe('interactive prompt');
180
- expect(argv.prompt).toBeUndefined();
181
- });
182
- it('should allow -i flag as alias for --prompt-interactive', async () => {
183
- process.argv = ['node', 'script.js', '-i', 'interactive prompt'];
184
- const argv = await parseArguments({});
185
- expect(argv.promptInteractive).toBe('interactive prompt');
186
- expect(argv.prompt).toBeUndefined();
187
- });
188
- it('should convert positional query argument to prompt by default', async () => {
189
- process.argv = ['node', 'script.js', 'Hi Gemini'];
190
- const argv = await parseArguments({});
191
- expect(argv.query).toBe('Hi Gemini');
192
- expect(argv.prompt).toBe('Hi Gemini');
193
- expect(argv.promptInteractive).toBeUndefined();
194
- });
195
- it('should map @path to prompt (one-shot) when it starts with @', async () => {
196
- process.argv = ['node', 'script.js', '@path ./file.md'];
197
- const argv = await parseArguments({});
198
- expect(argv.query).toBe('@path ./file.md');
199
- expect(argv.prompt).toBe('@path ./file.md');
200
- expect(argv.promptInteractive).toBeUndefined();
201
149
  });
202
- it('should map @path to prompt even when config flags are present', async () => {
203
- // @path queries should now go to one-shot mode regardless of other flags
204
- process.argv = [
205
- 'node',
206
- 'script.js',
207
- '@path',
208
- './file.md',
209
- '--model',
210
- 'gemini-2.5-pro',
211
- ];
212
- const argv = await parseArguments({});
213
- expect(argv.query).toBe('@path ./file.md');
214
- expect(argv.prompt).toBe('@path ./file.md'); // Should map to one-shot
215
- expect(argv.promptInteractive).toBeUndefined();
216
- expect(argv.model).toBe('gemini-2.5-pro');
217
- });
218
- it('maps unquoted positional @path + arg to prompt (one-shot)', async () => {
219
- // Simulate: gemini @path ./file.md
220
- process.argv = ['node', 'script.js', '@path', './file.md'];
221
- const argv = await parseArguments({});
222
- // After normalization, query is a single string
223
- expect(argv.query).toBe('@path ./file.md');
224
- // And it's mapped to one-shot prompt when no -p/-i flags are set
225
- expect(argv.prompt).toBe('@path ./file.md');
226
- expect(argv.promptInteractive).toBeUndefined();
227
- });
228
- it('should handle multiple @path arguments in a single command (one-shot)', async () => {
229
- // Simulate: gemini @path ./file1.md @path ./file2.md
230
- process.argv = [
231
- 'node',
232
- 'script.js',
233
- '@path',
234
- './file1.md',
235
- '@path',
236
- './file2.md',
237
- ];
238
- const argv = await parseArguments({});
239
- // After normalization, all arguments are joined with spaces
240
- expect(argv.query).toBe('@path ./file1.md @path ./file2.md');
241
- // And it's mapped to one-shot prompt
242
- expect(argv.prompt).toBe('@path ./file1.md @path ./file2.md');
243
- expect(argv.promptInteractive).toBeUndefined();
244
- });
245
- it('should handle mixed quoted and unquoted @path arguments (one-shot)', async () => {
246
- // Simulate: gemini "@path ./file1.md" @path ./file2.md "additional text"
247
- process.argv = [
248
- 'node',
249
- 'script.js',
250
- '@path ./file1.md',
251
- '@path',
252
- './file2.md',
253
- 'additional text',
254
- ];
255
- const argv = await parseArguments({});
256
- // After normalization, all arguments are joined with spaces
257
- expect(argv.query).toBe('@path ./file1.md @path ./file2.md additional text');
258
- // And it's mapped to one-shot prompt
259
- expect(argv.prompt).toBe('@path ./file1.md @path ./file2.md additional text');
260
- expect(argv.promptInteractive).toBeUndefined();
261
- });
262
- it('should map @path to prompt with ambient flags (debug)', async () => {
263
- // Ambient flags like debug should NOT affect routing
264
- process.argv = ['node', 'script.js', '@path', './file.md', '--debug'];
265
- const argv = await parseArguments({});
266
- expect(argv.query).toBe('@path ./file.md');
267
- expect(argv.prompt).toBe('@path ./file.md'); // Should map to one-shot
268
- expect(argv.promptInteractive).toBeUndefined();
269
- expect(argv.debug).toBe(true);
270
- });
271
- it('should map any @command to prompt (one-shot)', async () => {
272
- // Test that all @commands now go to one-shot mode
273
- const testCases = [
274
- '@path ./file.md',
275
- '@include src/',
276
- '@search pattern',
277
- '@web query',
278
- '@git status',
279
- ];
280
- for (const testQuery of testCases) {
281
- process.argv = ['node', 'script.js', testQuery];
282
- const argv = await parseArguments({});
283
- expect(argv.query).toBe(testQuery);
284
- expect(argv.prompt).toBe(testQuery);
285
- expect(argv.promptInteractive).toBeUndefined();
286
- }
287
- });
288
- it('should handle @command with leading whitespace', async () => {
289
- // Test that trim() + routing handles leading whitespace correctly
290
- process.argv = ['node', 'script.js', ' @path ./file.md'];
291
- const argv = await parseArguments({});
292
- expect(argv.query).toBe(' @path ./file.md');
293
- expect(argv.prompt).toBe(' @path ./file.md');
294
- expect(argv.promptInteractive).toBeUndefined();
295
- });
296
- it('should throw an error when both --yolo and --approval-mode are used together', async () => {
297
- process.argv = [
298
- 'node',
299
- 'script.js',
300
- '--yolo',
301
- '--approval-mode',
302
- 'default',
303
- ];
304
- const mockExit = vi.spyOn(process, 'exit').mockImplementation(() => {
305
- throw new Error('process.exit called');
150
+ it.each([
151
+ {
152
+ description: 'should allow --prompt without --prompt-interactive',
153
+ argv: ['node', 'script.js', '--prompt', 'test prompt'],
154
+ expected: { prompt: 'test prompt', promptInteractive: undefined },
155
+ },
156
+ {
157
+ description: 'should allow --prompt-interactive without --prompt',
158
+ argv: ['node', 'script.js', '--prompt-interactive', 'interactive prompt'],
159
+ expected: { prompt: undefined, promptInteractive: 'interactive prompt' },
160
+ },
161
+ {
162
+ description: 'should allow -i flag as alias for --prompt-interactive',
163
+ argv: ['node', 'script.js', '-i', 'interactive prompt'],
164
+ expected: { prompt: undefined, promptInteractive: 'interactive prompt' },
165
+ },
166
+ ])('$description', async ({ argv, expected }) => {
167
+ process.argv = argv;
168
+ const parsedArgs = await parseArguments({});
169
+ expect(parsedArgs.prompt).toBe(expected.prompt);
170
+ expect(parsedArgs.promptInteractive).toBe(expected.promptInteractive);
171
+ });
172
+ describe('positional arguments and @commands', () => {
173
+ it.each([
174
+ {
175
+ description: 'should convert positional query argument to prompt by default',
176
+ argv: ['node', 'script.js', 'Hi Gemini'],
177
+ expectedQuery: 'Hi Gemini',
178
+ expectedModel: undefined,
179
+ debug: false,
180
+ },
181
+ {
182
+ description: 'should map @path to prompt (one-shot) when it starts with @',
183
+ argv: ['node', 'script.js', '@path ./file.md'],
184
+ expectedQuery: '@path ./file.md',
185
+ expectedModel: undefined,
186
+ debug: false,
187
+ },
188
+ {
189
+ description: 'should map @path to prompt even when config flags are present',
190
+ argv: [
191
+ 'node',
192
+ 'script.js',
193
+ '@path',
194
+ './file.md',
195
+ '--model',
196
+ 'gemini-2.5-pro',
197
+ ],
198
+ expectedQuery: '@path ./file.md',
199
+ expectedModel: 'gemini-2.5-pro',
200
+ debug: false,
201
+ },
202
+ {
203
+ description: 'maps unquoted positional @path + arg to prompt (one-shot)',
204
+ argv: ['node', 'script.js', '@path', './file.md'],
205
+ expectedQuery: '@path ./file.md',
206
+ expectedModel: undefined,
207
+ debug: false,
208
+ },
209
+ {
210
+ description: 'should handle multiple @path arguments in a single command (one-shot)',
211
+ argv: [
212
+ 'node',
213
+ 'script.js',
214
+ '@path',
215
+ './file1.md',
216
+ '@path',
217
+ './file2.md',
218
+ ],
219
+ expectedQuery: '@path ./file1.md @path ./file2.md',
220
+ expectedModel: undefined,
221
+ debug: false,
222
+ },
223
+ {
224
+ description: 'should handle mixed quoted and unquoted @path arguments (one-shot)',
225
+ argv: [
226
+ 'node',
227
+ 'script.js',
228
+ '@path ./file1.md',
229
+ '@path',
230
+ './file2.md',
231
+ 'additional text',
232
+ ],
233
+ expectedQuery: '@path ./file1.md @path ./file2.md additional text',
234
+ expectedModel: undefined,
235
+ debug: false,
236
+ },
237
+ {
238
+ description: 'should map @path to prompt with ambient flags (debug)',
239
+ argv: ['node', 'script.js', '@path', './file.md', '--debug'],
240
+ expectedQuery: '@path ./file.md',
241
+ expectedModel: undefined,
242
+ debug: true,
243
+ },
244
+ {
245
+ description: 'should map @include to prompt (one-shot)',
246
+ argv: ['node', 'script.js', '@include src/'],
247
+ expectedQuery: '@include src/',
248
+ expectedModel: undefined,
249
+ debug: false,
250
+ },
251
+ {
252
+ description: 'should map @search to prompt (one-shot)',
253
+ argv: ['node', 'script.js', '@search pattern'],
254
+ expectedQuery: '@search pattern',
255
+ expectedModel: undefined,
256
+ debug: false,
257
+ },
258
+ {
259
+ description: 'should map @web to prompt (one-shot)',
260
+ argv: ['node', 'script.js', '@web query'],
261
+ expectedQuery: '@web query',
262
+ expectedModel: undefined,
263
+ debug: false,
264
+ },
265
+ {
266
+ description: 'should map @git to prompt (one-shot)',
267
+ argv: ['node', 'script.js', '@git status'],
268
+ expectedQuery: '@git status',
269
+ expectedModel: undefined,
270
+ debug: false,
271
+ },
272
+ {
273
+ description: 'should handle @command with leading whitespace',
274
+ argv: ['node', 'script.js', ' @path ./file.md'],
275
+ expectedQuery: ' @path ./file.md',
276
+ expectedModel: undefined,
277
+ debug: false,
278
+ },
279
+ ])('$description', async ({ argv, expectedQuery, expectedModel, debug }) => {
280
+ process.argv = argv;
281
+ const parsedArgs = await parseArguments({});
282
+ expect(parsedArgs.query).toBe(expectedQuery);
283
+ expect(parsedArgs.prompt).toBe(expectedQuery);
284
+ expect(parsedArgs.promptInteractive).toBeUndefined();
285
+ if (expectedModel) {
286
+ expect(parsedArgs.model).toBe(expectedModel);
287
+ }
288
+ if (debug) {
289
+ expect(parsedArgs.debug).toBe(true);
290
+ }
306
291
  });
307
- const mockConsoleError = vi
308
- .spyOn(console, 'error')
309
- .mockImplementation(() => { });
310
- const debugErrorSpy = vi
311
- .spyOn(debugLogger, 'error')
312
- .mockImplementation(() => { });
313
- await expect(parseArguments({})).rejects.toThrow('process.exit called');
314
- expect(debugErrorSpy).toHaveBeenCalledWith(expect.stringContaining('Cannot use both --yolo (-y) and --approval-mode together. Use --approval-mode=yolo instead.'));
315
- expect(mockConsoleError).toHaveBeenCalled();
316
- mockExit.mockRestore();
317
- mockConsoleError.mockRestore();
318
- debugErrorSpy.mockRestore();
319
292
  });
320
- it('should throw an error when using short flags -y and --approval-mode together', async () => {
321
- process.argv = ['node', 'script.js', '-y', '--approval-mode', 'yolo'];
293
+ it.each([
294
+ {
295
+ description: 'long flags',
296
+ argv: ['node', 'script.js', '--yolo', '--approval-mode', 'default'],
297
+ },
298
+ {
299
+ description: 'short flags',
300
+ argv: ['node', 'script.js', '-y', '--approval-mode', 'yolo'],
301
+ },
302
+ ])('should throw an error when using conflicting yolo/approval-mode flags ($description)', async ({ argv }) => {
303
+ process.argv = argv;
322
304
  const mockExit = vi.spyOn(process, 'exit').mockImplementation(() => {
323
305
  throw new Error('process.exit called');
324
306
  });
325
307
  const mockConsoleError = vi
326
308
  .spyOn(console, 'error')
327
309
  .mockImplementation(() => { });
328
- const debugErrorSpy = vi
329
- .spyOn(debugLogger, 'error')
330
- .mockImplementation(() => { });
331
310
  await expect(parseArguments({})).rejects.toThrow('process.exit called');
332
- expect(debugErrorSpy).toHaveBeenCalledWith(expect.stringContaining('Cannot use both --yolo (-y) and --approval-mode together. Use --approval-mode=yolo instead.'));
333
- expect(mockConsoleError).toHaveBeenCalled();
311
+ expect(mockConsoleError).toHaveBeenCalledWith(expect.stringContaining('Cannot use both --yolo (-y) and --approval-mode together. Use --approval-mode=yolo instead.'));
334
312
  mockExit.mockRestore();
335
313
  mockConsoleError.mockRestore();
336
- debugErrorSpy.mockRestore();
337
314
  });
338
- it('should allow --approval-mode without --yolo', async () => {
339
- process.argv = ['node', 'script.js', '--approval-mode', 'auto_edit'];
340
- const argv = await parseArguments({});
341
- expect(argv.approvalMode).toBe('auto_edit');
342
- expect(argv.yolo).toBe(false);
343
- });
344
- it('should allow --yolo without --approval-mode', async () => {
345
- process.argv = ['node', 'script.js', '--yolo'];
346
- const argv = await parseArguments({});
347
- expect(argv.yolo).toBe(true);
348
- expect(argv.approvalMode).toBeUndefined();
315
+ it.each([
316
+ {
317
+ description: 'should allow --approval-mode without --yolo',
318
+ argv: ['node', 'script.js', '--approval-mode', 'auto_edit'],
319
+ expected: { approvalMode: 'auto_edit', yolo: false },
320
+ },
321
+ {
322
+ description: 'should allow --yolo without --approval-mode',
323
+ argv: ['node', 'script.js', '--yolo'],
324
+ expected: { approvalMode: undefined, yolo: true },
325
+ },
326
+ ])('$description', async ({ argv, expected }) => {
327
+ process.argv = argv;
328
+ const parsedArgs = await parseArguments({});
329
+ expect(parsedArgs.approvalMode).toBe(expected.approvalMode);
330
+ expect(parsedArgs.yolo).toBe(expected.yolo);
349
331
  });
350
332
  it('should reject invalid --approval-mode values', async () => {
351
333
  process.argv = ['node', 'script.js', '--approval-mode', 'invalid'];
@@ -1150,68 +1132,6 @@ describe('loadCliConfig model selection', () => {
1150
1132
  expect(config.getModel()).toBe('gemini-2.5-flash-preview');
1151
1133
  });
1152
1134
  });
1153
- describe('loadCliConfig model selection with model router', () => {
1154
- beforeEach(() => {
1155
- vi.spyOn(ExtensionManager.prototype, 'getExtensions').mockReturnValue([]);
1156
- });
1157
- afterEach(() => {
1158
- vi.resetAllMocks();
1159
- });
1160
- it('should use auto model when useModelRouter is true and no model is provided', async () => {
1161
- process.argv = ['node', 'script.js'];
1162
- const argv = await parseArguments({});
1163
- const config = await loadCliConfig({
1164
- experimental: {
1165
- useModelRouter: true,
1166
- },
1167
- }, 'test-session', argv);
1168
- expect(config.getModel()).toBe(DEFAULT_GEMINI_MODEL_AUTO);
1169
- });
1170
- it('should use default model when useModelRouter is false and no model is provided', async () => {
1171
- process.argv = ['node', 'script.js'];
1172
- const argv = await parseArguments({});
1173
- const config = await loadCliConfig({
1174
- experimental: {
1175
- useModelRouter: false,
1176
- },
1177
- }, 'test-session', argv);
1178
- expect(config.getModel()).toBe(DEFAULT_GEMINI_MODEL);
1179
- });
1180
- it('should prioritize argv over useModelRouter', async () => {
1181
- process.argv = ['node', 'script.js', '--model', 'gemini-from-argv'];
1182
- const argv = await parseArguments({});
1183
- const config = await loadCliConfig({
1184
- experimental: {
1185
- useModelRouter: true,
1186
- },
1187
- }, 'test-session', argv);
1188
- expect(config.getModel()).toBe('gemini-from-argv');
1189
- });
1190
- it('should prioritize settings over useModelRouter', async () => {
1191
- process.argv = ['node', 'script.js'];
1192
- const argv = await parseArguments({});
1193
- const config = await loadCliConfig({
1194
- experimental: {
1195
- useModelRouter: true,
1196
- },
1197
- model: {
1198
- name: 'gemini-from-settings',
1199
- },
1200
- }, 'test-session', argv);
1201
- expect(config.getModel()).toBe('gemini-from-settings');
1202
- });
1203
- it('should prioritize environment variable over useModelRouter', async () => {
1204
- process.argv = ['node', 'script.js'];
1205
- vi.stubEnv('GEMINI_MODEL', 'gemini-from-env');
1206
- const argv = await parseArguments({});
1207
- const config = await loadCliConfig({
1208
- experimental: {
1209
- useModelRouter: true,
1210
- },
1211
- }, 'test-session', argv);
1212
- expect(config.getModel()).toBe('gemini-from-env');
1213
- });
1214
- });
1215
1135
  describe('loadCliConfig folderTrust', () => {
1216
1136
  beforeEach(() => {
1217
1137
  vi.resetAllMocks();
@@ -1363,29 +1283,6 @@ describe('loadCliConfig useRipgrep', () => {
1363
1283
  const config = await loadCliConfig(settings, 'test-session', argv);
1364
1284
  expect(config.getUseRipgrep()).toBe(true);
1365
1285
  });
1366
- describe('loadCliConfig useModelRouter', () => {
1367
- it('should be true by default when useModelRouter is not set in settings', async () => {
1368
- process.argv = ['node', 'script.js'];
1369
- const argv = await parseArguments({});
1370
- const settings = {};
1371
- const config = await loadCliConfig(settings, 'test-session', argv);
1372
- expect(config.getUseModelRouter()).toBe(true);
1373
- });
1374
- it('should be true when useModelRouter is set to true in settings', async () => {
1375
- process.argv = ['node', 'script.js'];
1376
- const argv = await parseArguments({});
1377
- const settings = { experimental: { useModelRouter: true } };
1378
- const config = await loadCliConfig(settings, 'test-session', argv);
1379
- expect(config.getUseModelRouter()).toBe(true);
1380
- });
1381
- it('should be false when useModelRouter is explicitly set to false in settings', async () => {
1382
- process.argv = ['node', 'script.js'];
1383
- const argv = await parseArguments({});
1384
- const settings = { experimental: { useModelRouter: false } };
1385
- const config = await loadCliConfig(settings, 'test-session', argv);
1386
- expect(config.getUseModelRouter()).toBe(false);
1387
- });
1388
- });
1389
1286
  });
1390
1287
  describe('screenReader configuration', () => {
1391
1288
  beforeEach(() => {