@machina.ai/cell-cli 1.40.1-rc2 → 1.41.1-rc2

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 (144) hide show
  1. package/dist/package.json +4 -4
  2. package/dist/src/acp/acpClient.js +8 -1
  3. package/dist/src/acp/acpClient.js.map +1 -1
  4. package/dist/src/acp/acpClient.test.js +6 -4
  5. package/dist/src/acp/acpClient.test.js.map +1 -1
  6. package/dist/src/acp/commands/restore.test.d.ts +6 -0
  7. package/dist/src/acp/commands/restore.test.js +179 -0
  8. package/dist/src/acp/commands/restore.test.js.map +1 -0
  9. package/dist/src/commands/mcp/list.js +14 -4
  10. package/dist/src/commands/mcp/list.js.map +1 -1
  11. package/dist/src/commands/mcp/list.test.js +48 -0
  12. package/dist/src/commands/mcp/list.test.js.map +1 -1
  13. package/dist/src/config/config.d.ts +1 -0
  14. package/dist/src/config/config.js +41 -7
  15. package/dist/src/config/config.js.map +1 -1
  16. package/dist/src/config/config.test.js +126 -71
  17. package/dist/src/config/config.test.js.map +1 -1
  18. package/dist/src/config/settings-validation.js +24 -6
  19. package/dist/src/config/settings-validation.js.map +1 -1
  20. package/dist/src/config/settings-validation.test.js +96 -0
  21. package/dist/src/config/settings-validation.test.js.map +1 -1
  22. package/dist/src/config/settings.js +34 -67
  23. package/dist/src/config/settings.js.map +1 -1
  24. package/dist/src/config/settings.test.js +78 -0
  25. package/dist/src/config/settings.test.js.map +1 -1
  26. package/dist/src/config/settingsSchema.d.ts +101 -0
  27. package/dist/src/config/settingsSchema.js +98 -0
  28. package/dist/src/config/settingsSchema.js.map +1 -1
  29. package/dist/src/gemini.d.ts +1 -1
  30. package/dist/src/gemini.js +36 -18
  31. package/dist/src/gemini.js.map +1 -1
  32. package/dist/src/gemini.test.js +42 -4
  33. package/dist/src/gemini.test.js.map +1 -1
  34. package/dist/src/gemini_cleanup.test.js +103 -1
  35. package/dist/src/gemini_cleanup.test.js.map +1 -1
  36. package/dist/src/generated/git-commit.d.ts +2 -2
  37. package/dist/src/generated/git-commit.js +2 -2
  38. package/dist/src/services/BuiltinCommandLoader.js +2 -0
  39. package/dist/src/services/BuiltinCommandLoader.js.map +1 -1
  40. package/dist/src/services/BuiltinCommandLoader.test.js +2 -0
  41. package/dist/src/services/BuiltinCommandLoader.test.js.map +1 -1
  42. package/dist/src/services/prompt-processors/shellProcessor.test.js +1 -0
  43. package/dist/src/services/prompt-processors/shellProcessor.test.js.map +1 -1
  44. package/dist/src/test-utils/mockConfig.js +1 -0
  45. package/dist/src/test-utils/mockConfig.js.map +1 -1
  46. package/dist/src/test-utils/render.js +3 -0
  47. package/dist/src/test-utils/render.js.map +1 -1
  48. package/dist/src/ui/AppContainer.js +19 -0
  49. package/dist/src/ui/AppContainer.js.map +1 -1
  50. package/dist/src/ui/commands/marketplaceCommand.js +13 -1
  51. package/dist/src/ui/commands/marketplaceCommand.js.map +1 -1
  52. package/dist/src/ui/commands/types.d.ts +2 -1
  53. package/dist/src/ui/commands/types.js.map +1 -1
  54. package/dist/src/ui/commands/voiceCommand.d.ts +7 -0
  55. package/dist/src/ui/commands/voiceCommand.js +29 -0
  56. package/dist/src/ui/commands/voiceCommand.js.map +1 -0
  57. package/dist/src/ui/components/AsciiArt.d.ts +6 -6
  58. package/dist/src/ui/components/AsciiArt.js +6 -6
  59. package/dist/src/ui/components/DialogManager.js +4 -0
  60. package/dist/src/ui/components/DialogManager.js.map +1 -1
  61. package/dist/src/ui/components/InputPrompt.js +34 -13
  62. package/dist/src/ui/components/InputPrompt.js.map +1 -1
  63. package/dist/src/ui/components/InputPrompt.test.js +289 -0
  64. package/dist/src/ui/components/InputPrompt.test.js.map +1 -1
  65. package/dist/src/ui/components/ModelDialog.js +28 -5
  66. package/dist/src/ui/components/ModelDialog.js.map +1 -1
  67. package/dist/src/ui/components/ModelDialog.test.js +1 -0
  68. package/dist/src/ui/components/ModelDialog.test.js.map +1 -1
  69. package/dist/src/ui/components/SessionBrowser.test.js +1 -0
  70. package/dist/src/ui/components/SessionBrowser.test.js.map +1 -1
  71. package/dist/src/ui/components/SettingsDialog.test.js +22 -0
  72. package/dist/src/ui/components/SettingsDialog.test.js.map +1 -1
  73. package/dist/src/ui/components/VoiceModelDialog.d.ts +11 -0
  74. package/dist/src/ui/components/VoiceModelDialog.js +118 -0
  75. package/dist/src/ui/components/VoiceModelDialog.js.map +1 -0
  76. package/dist/src/ui/components/messages/HintMessage.js +2 -1
  77. package/dist/src/ui/components/messages/HintMessage.js.map +1 -1
  78. package/dist/src/ui/components/messages/HintMessage.test.d.ts +6 -0
  79. package/dist/src/ui/components/messages/HintMessage.test.js +42 -0
  80. package/dist/src/ui/components/messages/HintMessage.test.js.map +1 -0
  81. package/dist/src/ui/components/messages/UserMessage.js +2 -1
  82. package/dist/src/ui/components/messages/UserMessage.js.map +1 -1
  83. package/dist/src/ui/components/messages/UserMessage.test.js +24 -0
  84. package/dist/src/ui/components/messages/UserMessage.test.js.map +1 -1
  85. package/dist/src/ui/components/messages/UserShellMessage.js +2 -1
  86. package/dist/src/ui/components/messages/UserShellMessage.js.map +1 -1
  87. package/dist/src/ui/components/messages/UserShellMessage.test.d.ts +6 -0
  88. package/dist/src/ui/components/messages/UserShellMessage.test.js +40 -0
  89. package/dist/src/ui/components/messages/UserShellMessage.test.js.map +1 -0
  90. package/dist/src/ui/components/shared/BaseSettingsDialog.js +1 -1
  91. package/dist/src/ui/components/shared/BaseSettingsDialog.js.map +1 -1
  92. package/dist/src/ui/contexts/KeypressContext.test.js +5 -3
  93. package/dist/src/ui/contexts/KeypressContext.test.js.map +1 -1
  94. package/dist/src/ui/contexts/UIActionsContext.d.ts +3 -0
  95. package/dist/src/ui/contexts/UIActionsContext.js.map +1 -1
  96. package/dist/src/ui/contexts/UIStateContext.d.ts +2 -0
  97. package/dist/src/ui/contexts/UIStateContext.js.map +1 -1
  98. package/dist/src/ui/hooks/atCommandProcessor.js +10 -9
  99. package/dist/src/ui/hooks/atCommandProcessor.js.map +1 -1
  100. package/dist/src/ui/hooks/atCommandProcessor.test.js +6 -24
  101. package/dist/src/ui/hooks/atCommandProcessor.test.js.map +1 -1
  102. package/dist/src/ui/hooks/slashCommandProcessor.d.ts +2 -0
  103. package/dist/src/ui/hooks/slashCommandProcessor.js +4 -0
  104. package/dist/src/ui/hooks/slashCommandProcessor.js.map +1 -1
  105. package/dist/src/ui/hooks/slashCommandProcessor.test.js +2 -0
  106. package/dist/src/ui/hooks/slashCommandProcessor.test.js.map +1 -1
  107. package/dist/src/ui/hooks/useSlashCompletion.js +15 -11
  108. package/dist/src/ui/hooks/useSlashCompletion.js.map +1 -1
  109. package/dist/src/ui/hooks/useSlashCompletion.test.js +40 -0
  110. package/dist/src/ui/hooks/useSlashCompletion.test.js.map +1 -1
  111. package/dist/src/ui/hooks/useVoiceMode.d.ts +28 -0
  112. package/dist/src/ui/hooks/useVoiceMode.js +333 -0
  113. package/dist/src/ui/hooks/useVoiceMode.js.map +1 -0
  114. package/dist/src/ui/hooks/useVoiceModelCommand.d.ts +12 -0
  115. package/dist/src/ui/hooks/useVoiceModelCommand.js +21 -0
  116. package/dist/src/ui/hooks/useVoiceModelCommand.js.map +1 -0
  117. package/dist/src/ui/key/keyBindings.d.ts +1 -0
  118. package/dist/src/ui/key/keyBindings.js +7 -3
  119. package/dist/src/ui/key/keyBindings.js.map +1 -1
  120. package/dist/src/ui/noninteractive/nonInteractiveUi.js +1 -0
  121. package/dist/src/ui/noninteractive/nonInteractiveUi.js.map +1 -1
  122. package/dist/src/utils/activityLogger.js +19 -9
  123. package/dist/src/utils/activityLogger.js.map +1 -1
  124. package/dist/src/utils/activityLogger.test.js +76 -1
  125. package/dist/src/utils/activityLogger.test.js.map +1 -1
  126. package/dist/src/utils/handleAutoUpdate.js +4 -3
  127. package/dist/src/utils/handleAutoUpdate.js.map +1 -1
  128. package/dist/src/utils/handleAutoUpdate.test.js +8 -6
  129. package/dist/src/utils/handleAutoUpdate.test.js.map +1 -1
  130. package/dist/src/utils/sandbox.js +23 -10
  131. package/dist/src/utils/sandbox.js.map +1 -1
  132. package/dist/src/utils/sandbox.test.js +46 -0
  133. package/dist/src/utils/sandbox.test.js.map +1 -1
  134. package/dist/src/utils/sessionCleanup.test.js +1 -0
  135. package/dist/src/utils/sessionCleanup.test.js.map +1 -1
  136. package/dist/src/utils/sessionUtils.d.ts +4 -0
  137. package/dist/src/utils/sessionUtils.js +24 -0
  138. package/dist/src/utils/sessionUtils.js.map +1 -1
  139. package/dist/src/utils/sessionUtils.test.js +27 -0
  140. package/dist/src/utils/sessionUtils.test.js.map +1 -1
  141. package/dist/src/utils/userStartupWarnings.test.js +14 -0
  142. package/dist/src/utils/userStartupWarnings.test.js.map +1 -1
  143. package/dist/tsconfig.tsbuildinfo +1 -1
  144. package/package.json +4 -4
@@ -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, OutputFormat, SHELL_TOOL_NAME, WRITE_FILE_TOOL_NAME, EDIT_TOOL_NAME, WEB_FETCH_TOOL_NAME, ASK_USER_TOOL_NAME, debugLogger, ApprovalMode, Storage, generalistProfile, } from '@google/gemini-cli-core';
9
+ import { DEFAULT_FILE_FILTERING_OPTIONS, OutputFormat, SHELL_TOOL_NAME, WRITE_FILE_TOOL_NAME, EDIT_TOOL_NAME, WEB_FETCH_TOOL_NAME, ASK_USER_TOOL_NAME, debugLogger, ApprovalMode, Storage, } from '@google/gemini-cli-core';
10
10
  import { loadCliConfig, parseArguments } from './config.js';
11
11
  import { createTestMergedSettings, } from './settings.js';
12
12
  import * as ServerConfig from '@google/gemini-cli-core';
@@ -171,6 +171,34 @@ afterEach(() => {
171
171
  });
172
172
  });
173
173
  describe('parseArguments', () => {
174
+ afterEach(() => {
175
+ vi.restoreAllMocks();
176
+ });
177
+ it('should fail if both --resume and --session-id are provided', async () => {
178
+ process.argv = [
179
+ 'node',
180
+ 'script.js',
181
+ '--resume',
182
+ '--session-id',
183
+ 'test-uuid-1234',
184
+ ];
185
+ const mockConsoleError = vi
186
+ .spyOn(console, 'error')
187
+ .mockImplementation(() => { });
188
+ vi.spyOn(process, 'exit').mockImplementation(() => {
189
+ throw new Error('process.exit called');
190
+ });
191
+ await expect(parseArguments(createTestMergedSettings())).rejects.toThrow('process.exit called');
192
+ expect(mockConsoleError).toHaveBeenCalledWith(expect.stringContaining('Cannot use both --resume (-r) and --session-id together'));
193
+ });
194
+ it('should parse --session-id option correctly', async () => {
195
+ process.argv = ['node', 'script.js', '--session-id', 'test-uuid-1234'];
196
+ vi.spyOn(process, 'exit').mockImplementation(() => {
197
+ throw new Error('process.exit called');
198
+ });
199
+ const parsedArgs = await parseArguments(createTestMergedSettings());
200
+ expect(parsedArgs.sessionId).toBe('test-uuid-1234');
201
+ });
174
202
  describe('worktree', () => {
175
203
  it('should parse --worktree flag when provided with a name', async () => {
176
204
  process.argv = ['node', 'script.js', '--worktree', 'my-feature'];
@@ -192,7 +220,7 @@ describe('parseArguments', () => {
192
220
  process.argv = ['node', 'script.js', '--worktree', 'feature'];
193
221
  const settings = createTestMergedSettings();
194
222
  settings.experimental.worktrees = false;
195
- const mockExit = vi.spyOn(process, 'exit').mockImplementation(() => {
223
+ vi.spyOn(process, 'exit').mockImplementation(() => {
196
224
  throw new Error('process.exit called');
197
225
  });
198
226
  const mockConsoleError = vi
@@ -200,8 +228,6 @@ describe('parseArguments', () => {
200
228
  .mockImplementation(() => { });
201
229
  await expect(parseArguments(settings)).rejects.toThrow('process.exit called');
202
230
  expect(mockConsoleError).toHaveBeenCalledWith(expect.stringContaining('The --worktree flag is only available when experimental.worktrees is enabled in your settings.'));
203
- mockExit.mockRestore();
204
- mockConsoleError.mockRestore();
205
231
  });
206
232
  });
207
233
  it.each([
@@ -229,7 +255,7 @@ describe('parseArguments', () => {
229
255
  },
230
256
  ])('should throw an error when using conflicting prompt flags ($description)', async ({ argv }) => {
231
257
  process.argv = argv;
232
- const mockExit = vi.spyOn(process, 'exit').mockImplementation(() => {
258
+ vi.spyOn(process, 'exit').mockImplementation(() => {
233
259
  throw new Error('process.exit called');
234
260
  });
235
261
  const mockConsoleError = vi
@@ -237,8 +263,6 @@ describe('parseArguments', () => {
237
263
  .mockImplementation(() => { });
238
264
  await expect(parseArguments(createTestMergedSettings())).rejects.toThrow('process.exit called');
239
265
  expect(mockConsoleError).toHaveBeenCalledWith(expect.stringContaining('Cannot use both --prompt (-p) and --prompt-interactive (-i) together'));
240
- mockExit.mockRestore();
241
- mockConsoleError.mockRestore();
242
266
  });
243
267
  describe('isCommand middleware', () => {
244
268
  it.each([
@@ -451,7 +475,7 @@ describe('parseArguments', () => {
451
475
  },
452
476
  ])('should throw an error when using conflicting yolo/approval-mode flags ($description)', async ({ argv }) => {
453
477
  process.argv = argv;
454
- const mockExit = vi.spyOn(process, 'exit').mockImplementation(() => {
478
+ vi.spyOn(process, 'exit').mockImplementation(() => {
455
479
  throw new Error('process.exit called');
456
480
  });
457
481
  const mockConsoleError = vi
@@ -459,8 +483,6 @@ describe('parseArguments', () => {
459
483
  .mockImplementation(() => { });
460
484
  await expect(parseArguments(createTestMergedSettings())).rejects.toThrow('process.exit called');
461
485
  expect(mockConsoleError).toHaveBeenCalledWith(expect.stringContaining('Cannot use both --yolo (-y) and --approval-mode together. Use --approval-mode=yolo instead.'));
462
- mockExit.mockRestore();
463
- mockConsoleError.mockRestore();
464
486
  });
465
487
  it.each([
466
488
  {
@@ -481,7 +503,7 @@ describe('parseArguments', () => {
481
503
  });
482
504
  it('should reject invalid --approval-mode values', async () => {
483
505
  process.argv = ['node', 'script.js', '--approval-mode', 'invalid'];
484
- const mockExit = vi.spyOn(process, 'exit').mockImplementation(() => {
506
+ vi.spyOn(process, 'exit').mockImplementation(() => {
485
507
  throw new Error('process.exit called');
486
508
  });
487
509
  const mockConsoleError = vi
@@ -493,9 +515,6 @@ describe('parseArguments', () => {
493
515
  await expect(parseArguments(createTestMergedSettings())).rejects.toThrow('process.exit called');
494
516
  expect(debugErrorSpy).toHaveBeenCalledWith(expect.stringContaining('Invalid values:'));
495
517
  expect(mockConsoleError).toHaveBeenCalled();
496
- mockExit.mockRestore();
497
- mockConsoleError.mockRestore();
498
- debugErrorSpy.mockRestore();
499
518
  });
500
519
  it('should allow resuming a session without prompt argument in non-interactive mode (expecting stdin)', async () => {
501
520
  const originalIsTTY = process.stdin.isTTY;
@@ -630,6 +649,84 @@ describe('loadCliConfig', () => {
630
649
  vi.unstubAllEnvs();
631
650
  vi.restoreAllMocks();
632
651
  });
652
+ describe('Model resolution', () => {
653
+ it('should handle multiple --model flags by taking the last one', async () => {
654
+ const argv = {
655
+ query: undefined,
656
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
657
+ model: ['gemini-1.5-pro', 'gemini-2.0-flash'],
658
+ sandbox: undefined,
659
+ debug: false,
660
+ prompt: undefined,
661
+ promptInteractive: undefined,
662
+ yolo: undefined,
663
+ approvalMode: undefined,
664
+ policy: undefined,
665
+ adminPolicy: undefined,
666
+ allowedMcpServerNames: undefined,
667
+ allowedTools: undefined,
668
+ extensions: undefined,
669
+ listExtensions: false,
670
+ listSessions: false,
671
+ deleteSession: undefined,
672
+ screenReader: undefined,
673
+ isCommand: false,
674
+ rawOutput: false,
675
+ acceptRawOutputRisk: false,
676
+ startupMessages: [],
677
+ resume: undefined,
678
+ includeDirectories: [],
679
+ useWriteTodos: false,
680
+ outputFormat: undefined,
681
+ fakeResponses: undefined,
682
+ recordResponses: undefined,
683
+ skipTrust: false,
684
+ };
685
+ const settings = createTestMergedSettings();
686
+ const config = await loadCliConfig(settings, 'test-session', argv, {
687
+ cwd: process.cwd(),
688
+ });
689
+ expect(config.getModel()).toBe('gemini-2.0-flash');
690
+ });
691
+ it('should handle non-string model flags by coercing to string', async () => {
692
+ const argv = {
693
+ query: undefined,
694
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
695
+ model: true,
696
+ sandbox: undefined,
697
+ debug: false,
698
+ prompt: undefined,
699
+ promptInteractive: undefined,
700
+ yolo: undefined,
701
+ approvalMode: undefined,
702
+ policy: undefined,
703
+ adminPolicy: undefined,
704
+ allowedMcpServerNames: undefined,
705
+ allowedTools: undefined,
706
+ extensions: undefined,
707
+ listExtensions: false,
708
+ listSessions: false,
709
+ deleteSession: undefined,
710
+ screenReader: undefined,
711
+ isCommand: false,
712
+ rawOutput: false,
713
+ acceptRawOutputRisk: false,
714
+ startupMessages: [],
715
+ resume: undefined,
716
+ includeDirectories: [],
717
+ useWriteTodos: false,
718
+ outputFormat: undefined,
719
+ fakeResponses: undefined,
720
+ recordResponses: undefined,
721
+ skipTrust: false,
722
+ };
723
+ const settings = createTestMergedSettings();
724
+ const config = await loadCliConfig(settings, 'test-session', argv, {
725
+ cwd: process.cwd(),
726
+ });
727
+ expect(config.getModel()).toBe('true');
728
+ });
729
+ });
633
730
  describe('Proxy configuration', () => {
634
731
  const originalProxyEnv = {};
635
732
  const proxyEnvVars = [
@@ -714,9 +811,7 @@ describe('loadCliConfig', () => {
714
811
  expect(dirs).toContain('/project/folderB');
715
812
  });
716
813
  it('should skip inaccessible workspace folders from CELL_CLI_IDE_WORKSPACE_PATH', async () => {
717
- const resolveToRealPathSpy = vi
718
- .spyOn(ServerConfig, 'resolveToRealPath')
719
- .mockImplementation((p) => {
814
+ vi.spyOn(ServerConfig, 'resolveToRealPath').mockImplementation((p) => {
720
815
  if (p.toString().includes('restricted')) {
721
816
  const err = new Error('EACCES: permission denied');
722
817
  err.code = 'EACCES';
@@ -732,7 +827,6 @@ describe('loadCliConfig', () => {
732
827
  const dirs = config.getPendingIncludeDirectories();
733
828
  expect(dirs).toContain('/project/folderA');
734
829
  expect(dirs).not.toContain('/nonexistent/restricted/folder');
735
- resolveToRealPathSpy.mockRestore();
736
830
  });
737
831
  it('should use default fileFilter options when unconfigured', async () => {
738
832
  process.argv = ['node', 'script.js'];
@@ -1843,48 +1937,6 @@ describe('loadCliConfig context management', () => {
1843
1937
  },
1844
1938
  });
1845
1939
  const config = await loadCliConfig(settings, 'test-session', argv);
1846
- expect(config.getContextManagementConfig()).toStrictEqual(generalistProfile);
1847
- expect(config.isContextManagementEnabled()).toBe(true);
1848
- });
1849
- it('should be true when contextManagement is set to true in settings', async () => {
1850
- process.argv = ['node', 'script.js'];
1851
- const argv = await parseArguments(createTestMergedSettings());
1852
- const contextManagementConfig = {
1853
- historyWindow: {
1854
- maxTokens: 100_000,
1855
- retainedTokens: 50_000,
1856
- },
1857
- messageLimits: {
1858
- normalMaxTokens: 1000,
1859
- retainedMaxTokens: 10_000,
1860
- normalizationHeadRatio: 0.25,
1861
- },
1862
- tools: {
1863
- distillation: {
1864
- maxOutputTokens: 10_000,
1865
- summarizationThresholdTokens: 15_000,
1866
- },
1867
- outputMasking: {
1868
- protectionThresholdTokens: 30_000,
1869
- minPrunableThresholdTokens: 10_000,
1870
- protectLatestTurn: false,
1871
- },
1872
- },
1873
- };
1874
- const settings = createTestMergedSettings({
1875
- experimental: {
1876
- contextManagement: true,
1877
- },
1878
- // The type of numbers is being inferred strangely, and so we have to cast
1879
- // to `any` here.
1880
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1881
- contextManagement: contextManagementConfig,
1882
- });
1883
- const config = await loadCliConfig(settings, 'test-session', argv);
1884
- expect(config.getContextManagementConfig()).toStrictEqual({
1885
- enabled: true,
1886
- ...contextManagementConfig,
1887
- });
1888
1940
  expect(config.isContextManagementEnabled()).toBe(true);
1889
1941
  });
1890
1942
  });
@@ -2466,6 +2518,17 @@ describe('loadCliConfig gemmaModelRouter', () => {
2466
2518
  expect(gemmaSettings.classifier?.host).toBe('http://custom:1234');
2467
2519
  expect(gemmaSettings.classifier?.model).toBe('custom-gemma');
2468
2520
  });
2521
+ it('should load experimental.gemma setting from merged settings', async () => {
2522
+ process.argv = ['node', 'script.js'];
2523
+ const argv = await parseArguments(createTestMergedSettings());
2524
+ const settings = createTestMergedSettings({
2525
+ experimental: {
2526
+ gemma: true,
2527
+ },
2528
+ });
2529
+ const config = await loadCliConfig(settings, 'test-session', argv);
2530
+ expect(config.getExperimentalGemma()).toBe(true);
2531
+ });
2469
2532
  it('should handle partial gemmaModelRouter settings', async () => {
2470
2533
  process.argv = ['node', 'script.js'];
2471
2534
  const argv = await parseArguments(createTestMergedSettings());
@@ -2585,7 +2648,7 @@ describe('Output format', () => {
2585
2648
  });
2586
2649
  it('should error on invalid --output-format argument', async () => {
2587
2650
  process.argv = ['node', 'script.js', '--output-format', 'invalid'];
2588
- const mockExit = vi.spyOn(process, 'exit').mockImplementation(() => {
2651
+ vi.spyOn(process, 'exit').mockImplementation(() => {
2589
2652
  throw new Error('process.exit called');
2590
2653
  });
2591
2654
  const mockConsoleError = vi
@@ -2597,9 +2660,6 @@ describe('Output format', () => {
2597
2660
  await expect(parseArguments(createTestMergedSettings())).rejects.toThrow('process.exit called');
2598
2661
  expect(debugErrorSpy).toHaveBeenCalledWith(expect.stringContaining('Invalid values:'));
2599
2662
  expect(mockConsoleError).toHaveBeenCalled();
2600
- mockExit.mockRestore();
2601
- mockConsoleError.mockRestore();
2602
- debugErrorSpy.mockRestore();
2603
2663
  });
2604
2664
  });
2605
2665
  describe('parseArguments with positional prompt', () => {
@@ -2625,20 +2685,15 @@ describe('parseArguments with positional prompt', () => {
2625
2685
  '--prompt',
2626
2686
  'test prompt',
2627
2687
  ];
2628
- const mockExit = vi.spyOn(process, 'exit').mockImplementation(() => {
2688
+ vi.spyOn(process, 'exit').mockImplementation(() => {
2629
2689
  throw new Error('process.exit called');
2630
2690
  });
2631
- const mockConsoleError = vi
2632
- .spyOn(console, 'error')
2633
- .mockImplementation(() => { });
2691
+ vi.spyOn(console, 'error').mockImplementation(() => { });
2634
2692
  const debugErrorSpy = vi
2635
2693
  .spyOn(debugLogger, 'error')
2636
2694
  .mockImplementation(() => { });
2637
2695
  await expect(parseArguments(createTestMergedSettings())).rejects.toThrow('process.exit called');
2638
2696
  expect(debugErrorSpy).toHaveBeenCalledWith(expect.stringContaining('Cannot use both a positional prompt and the --prompt (-p) flag together'));
2639
- mockExit.mockRestore();
2640
- mockConsoleError.mockRestore();
2641
- debugErrorSpy.mockRestore();
2642
2697
  });
2643
2698
  it('should correctly parse a positional prompt to query field', async () => {
2644
2699
  process.argv = ['node', 'script.js', 'positional', 'prompt'];