@google/gemini-cli 0.12.0-nightly.20251027.cb0947c5 → 0.12.0-preview.0

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 (168) hide show
  1. package/README.md +7 -5
  2. package/dist/package.json +2 -2
  3. package/dist/src/commands/extensions/disable.d.ts +1 -1
  4. package/dist/src/commands/extensions/disable.js +5 -4
  5. package/dist/src/commands/extensions/disable.js.map +1 -1
  6. package/dist/src/commands/extensions/enable.d.ts +1 -1
  7. package/dist/src/commands/extensions/enable.js +3 -2
  8. package/dist/src/commands/extensions/enable.js.map +1 -1
  9. package/dist/src/commands/extensions/install.js +2 -1
  10. package/dist/src/commands/extensions/install.js.map +1 -1
  11. package/dist/src/commands/extensions/install.test.js +1 -0
  12. package/dist/src/commands/extensions/install.test.js.map +1 -1
  13. package/dist/src/commands/extensions/link.js +2 -1
  14. package/dist/src/commands/extensions/link.js.map +1 -1
  15. package/dist/src/commands/extensions/list.js +2 -2
  16. package/dist/src/commands/extensions/list.js.map +1 -1
  17. package/dist/src/commands/extensions/uninstall.js +2 -1
  18. package/dist/src/commands/extensions/uninstall.js.map +1 -1
  19. package/dist/src/commands/extensions/update.js +2 -2
  20. package/dist/src/commands/extensions/update.js.map +1 -1
  21. package/dist/src/commands/mcp/list.js +2 -2
  22. package/dist/src/commands/mcp/list.js.map +1 -1
  23. package/dist/src/config/config.d.ts +5 -3
  24. package/dist/src/config/config.js +42 -9
  25. package/dist/src/config/config.js.map +1 -1
  26. package/dist/src/config/config.test.js +186 -161
  27. package/dist/src/config/config.test.js.map +1 -1
  28. package/dist/src/config/extension-manager.d.ts +23 -10
  29. package/dist/src/config/extension-manager.js +89 -62
  30. package/dist/src/config/extension-manager.js.map +1 -1
  31. package/dist/src/config/extension.test.js +158 -74
  32. package/dist/src/config/extension.test.js.map +1 -1
  33. package/dist/src/config/extensions/extensionSettings.d.ts +3 -3
  34. package/dist/src/config/extensions/extensionSettings.js +74 -24
  35. package/dist/src/config/extensions/extensionSettings.js.map +1 -1
  36. package/dist/src/config/extensions/extensionSettings.test.js +145 -24
  37. package/dist/src/config/extensions/extensionSettings.test.js.map +1 -1
  38. package/dist/src/config/extensions/github.js +3 -3
  39. package/dist/src/config/extensions/github.js.map +1 -1
  40. package/dist/src/config/extensions/github.test.js +1 -1
  41. package/dist/src/config/extensions/github.test.js.map +1 -1
  42. package/dist/src/config/extensions/update.js +7 -6
  43. package/dist/src/config/extensions/update.js.map +1 -1
  44. package/dist/src/config/extensions/update.test.js +54 -31
  45. package/dist/src/config/extensions/update.test.js.map +1 -1
  46. package/dist/src/config/keyBindings.js +1 -1
  47. package/dist/src/config/keyBindings.js.map +1 -1
  48. package/dist/src/config/policies/read-only.toml +56 -0
  49. package/dist/src/config/policies/write.toml +63 -0
  50. package/dist/src/config/policies/yolo.toml +31 -0
  51. package/dist/src/config/policy-engine.integration.test.js +41 -38
  52. package/dist/src/config/policy-engine.integration.test.js.map +1 -1
  53. package/dist/src/config/policy-toml-loader.d.ts +46 -0
  54. package/dist/src/config/policy-toml-loader.js +314 -0
  55. package/dist/src/config/policy-toml-loader.js.map +1 -0
  56. package/dist/src/config/policy-toml-loader.test.d.ts +6 -0
  57. package/dist/src/config/policy-toml-loader.test.js +626 -0
  58. package/dist/src/config/policy-toml-loader.test.js.map +1 -0
  59. package/dist/src/config/policy.d.ts +9 -2
  60. package/dist/src/config/policy.js +139 -110
  61. package/dist/src/config/policy.js.map +1 -1
  62. package/dist/src/config/policy.test.js +780 -82
  63. package/dist/src/config/policy.test.js.map +1 -1
  64. package/dist/src/config/settings.test.js +4 -4
  65. package/dist/src/config/settings.test.js.map +1 -1
  66. package/dist/src/gemini.js +6 -17
  67. package/dist/src/gemini.js.map +1 -1
  68. package/dist/src/gemini.test.js +1 -0
  69. package/dist/src/gemini.test.js.map +1 -1
  70. package/dist/src/generated/git-commit.d.ts +2 -2
  71. package/dist/src/generated/git-commit.js +2 -2
  72. package/dist/src/generated/git-commit.js.map +1 -1
  73. package/dist/src/test-utils/render.d.ts +12 -0
  74. package/dist/src/test-utils/render.js +28 -1
  75. package/dist/src/test-utils/render.js.map +1 -1
  76. package/dist/src/test-utils/render.test.d.ts +6 -0
  77. package/dist/src/test-utils/render.test.js +54 -0
  78. package/dist/src/test-utils/render.test.js.map +1 -0
  79. package/dist/src/ui/AppContainer.js +28 -22
  80. package/dist/src/ui/AppContainer.js.map +1 -1
  81. package/dist/src/ui/AppContainer.test.js +8 -0
  82. package/dist/src/ui/AppContainer.test.js.map +1 -1
  83. package/dist/src/ui/commands/directoryCommand.js +1 -1
  84. package/dist/src/ui/commands/directoryCommand.js.map +1 -1
  85. package/dist/src/ui/commands/extensionsCommand.js +45 -1
  86. package/dist/src/ui/commands/extensionsCommand.js.map +1 -1
  87. package/dist/src/ui/commands/extensionsCommand.test.js +64 -1
  88. package/dist/src/ui/commands/extensionsCommand.test.js.map +1 -1
  89. package/dist/src/ui/commands/memoryCommand.js +1 -1
  90. package/dist/src/ui/commands/memoryCommand.js.map +1 -1
  91. package/dist/src/ui/commands/memoryCommand.test.js +3 -1
  92. package/dist/src/ui/commands/memoryCommand.test.js.map +1 -1
  93. package/dist/src/ui/components/ConsoleSummaryDisplay.js +1 -1
  94. package/dist/src/ui/components/ConsoleSummaryDisplay.js.map +1 -1
  95. package/dist/src/ui/components/DetailedMessagesDisplay.js +1 -1
  96. package/dist/src/ui/components/DetailedMessagesDisplay.js.map +1 -1
  97. package/dist/src/ui/components/FolderTrustDialog.test.js +4 -5
  98. package/dist/src/ui/components/FolderTrustDialog.test.js.map +1 -1
  99. package/dist/src/ui/components/Footer.js +1 -1
  100. package/dist/src/ui/components/Footer.js.map +1 -1
  101. package/dist/src/ui/components/Footer.test.js +24 -0
  102. package/dist/src/ui/components/Footer.test.js.map +1 -1
  103. package/dist/src/ui/components/Help.test.js +0 -1
  104. package/dist/src/ui/components/Help.test.js.map +1 -1
  105. package/dist/src/ui/components/ModelDialog.test.js +5 -6
  106. package/dist/src/ui/components/ModelDialog.test.js.map +1 -1
  107. package/dist/src/ui/components/PermissionsModifyTrustDialog.test.js +11 -13
  108. package/dist/src/ui/components/PermissionsModifyTrustDialog.test.js.map +1 -1
  109. package/dist/src/ui/components/SettingsDialog.test.js +12 -14
  110. package/dist/src/ui/components/SettingsDialog.test.js.map +1 -1
  111. package/dist/src/ui/components/shared/BaseSelectionList.test.js +11 -13
  112. package/dist/src/ui/components/shared/BaseSelectionList.test.js.map +1 -1
  113. package/dist/src/ui/components/shared/text-buffer.test.js +2 -2
  114. package/dist/src/ui/components/shared/text-buffer.test.js.map +1 -1
  115. package/dist/src/ui/contexts/KeypressContext.test.js +6 -5
  116. package/dist/src/ui/contexts/KeypressContext.test.js.map +1 -1
  117. package/dist/src/ui/contexts/SessionContext.test.js +27 -14
  118. package/dist/src/ui/contexts/SessionContext.test.js.map +1 -1
  119. package/dist/src/ui/hooks/atCommandProcessor.js +2 -2
  120. package/dist/src/ui/hooks/atCommandProcessor.js.map +1 -1
  121. package/dist/src/ui/hooks/useAtCompletion.test.js +32 -23
  122. package/dist/src/ui/hooks/useAtCompletion.test.js.map +1 -1
  123. package/dist/src/ui/hooks/useAutoAcceptIndicator.test.js +2 -2
  124. package/dist/src/ui/hooks/useAutoAcceptIndicator.test.js.map +1 -1
  125. package/dist/src/ui/hooks/useExtensionUpdates.d.ts +1 -2
  126. package/dist/src/ui/hooks/useExtensionUpdates.js +2 -1
  127. package/dist/src/ui/hooks/useExtensionUpdates.js.map +1 -1
  128. package/dist/src/ui/hooks/useExtensionUpdates.test.js +14 -20
  129. package/dist/src/ui/hooks/useExtensionUpdates.test.js.map +1 -1
  130. package/dist/src/ui/hooks/useFlickerDetector.test.js +9 -6
  131. package/dist/src/ui/hooks/useFlickerDetector.test.js.map +1 -1
  132. package/dist/src/ui/hooks/useFolderTrust.test.js +45 -23
  133. package/dist/src/ui/hooks/useFolderTrust.test.js.map +1 -1
  134. package/dist/src/ui/hooks/useGeminiStream.js +7 -5
  135. package/dist/src/ui/hooks/useGeminiStream.js.map +1 -1
  136. package/dist/src/ui/hooks/useGeminiStream.test.js +42 -41
  137. package/dist/src/ui/hooks/useGeminiStream.test.js.map +1 -1
  138. package/dist/src/ui/hooks/useHistoryManager.test.js +2 -2
  139. package/dist/src/ui/hooks/useHistoryManager.test.js.map +1 -1
  140. package/dist/src/ui/hooks/useInputHistory.test.js +2 -2
  141. package/dist/src/ui/hooks/useInputHistory.test.js.map +1 -1
  142. package/dist/src/ui/hooks/useInputHistoryStore.test.js +2 -2
  143. package/dist/src/ui/hooks/useInputHistoryStore.test.js.map +1 -1
  144. package/dist/src/ui/hooks/usePermissionsModifyTrust.test.js +2 -3
  145. package/dist/src/ui/hooks/usePermissionsModifyTrust.test.js.map +1 -1
  146. package/dist/src/ui/hooks/usePhraseCycler.js +1 -1
  147. package/dist/src/ui/hooks/usePhraseCycler.js.map +1 -1
  148. package/dist/src/ui/hooks/usePhraseCycler.test.js +83 -111
  149. package/dist/src/ui/hooks/usePhraseCycler.test.js.map +1 -1
  150. package/dist/src/ui/hooks/useQuotaAndFallback.test.js +2 -2
  151. package/dist/src/ui/hooks/useQuotaAndFallback.test.js.map +1 -1
  152. package/dist/src/ui/hooks/useReactToolScheduler.test.js +1 -2
  153. package/dist/src/ui/hooks/useReactToolScheduler.test.js.map +1 -1
  154. package/dist/src/ui/hooks/useReverseSearchCompletion.test.js +2 -2
  155. package/dist/src/ui/hooks/useReverseSearchCompletion.test.js.map +1 -1
  156. package/dist/src/ui/hooks/useShellHistory.test.js +40 -17
  157. package/dist/src/ui/hooks/useShellHistory.test.js.map +1 -1
  158. package/dist/src/ui/hooks/useSlashCompletion.test.js +54 -49
  159. package/dist/src/ui/hooks/useSlashCompletion.test.js.map +1 -1
  160. package/dist/src/ui/hooks/useToolScheduler.test.js +48 -42
  161. package/dist/src/ui/hooks/useToolScheduler.test.js.map +1 -1
  162. package/dist/src/ui/keyMatchers.test.js +3 -3
  163. package/dist/src/ui/keyMatchers.test.js.map +1 -1
  164. package/dist/src/zed-integration/zedIntegration.d.ts +2 -2
  165. package/dist/src/zed-integration/zedIntegration.js +4 -6
  166. package/dist/src/zed-integration/zedIntegration.js.map +1 -1
  167. package/dist/tsconfig.tsbuildinfo +1 -1
  168. package/package.json +3 -3
@@ -10,6 +10,7 @@ import { DEFAULT_FILE_FILTERING_OPTIONS, DEFAULT_GEMINI_MODEL, DEFAULT_GEMINI_MO
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';
13
+ import { ExtensionManager } from './extension-manager.js';
13
14
  vi.mock('./trustedFolders.js', () => ({
14
15
  isWorkspaceTrusted: vi
15
16
  .fn()
@@ -72,10 +73,15 @@ vi.mock('@google/gemini-cli-core', async () => {
72
73
  }),
73
74
  },
74
75
  loadEnvironment: vi.fn(),
75
- loadServerHierarchicalMemory: vi.fn((cwd, dirs, debug, fileService, extensionPaths, _maxDirs) => Promise.resolve({
76
- memoryContent: extensionPaths?.join(',') || '',
77
- fileCount: extensionPaths?.length || 0,
78
- })),
76
+ loadServerHierarchicalMemory: vi.fn((cwd, dirs, debug, fileService, extensionLoader, _maxDirs) => {
77
+ const extensionPaths = extensionLoader
78
+ .getExtensions()
79
+ .flatMap((e) => e.contextFiles);
80
+ return Promise.resolve({
81
+ memoryContent: extensionPaths.join(',') || '',
82
+ fileCount: extensionPaths?.length || 0,
83
+ });
84
+ }),
79
85
  DEFAULT_MEMORY_FILE_FILTERING_OPTIONS: {
80
86
  respectGitIgnore: false,
81
87
  respectGeminiIgnore: true,
@@ -86,11 +92,23 @@ vi.mock('@google/gemini-cli-core', async () => {
86
92
  },
87
93
  };
88
94
  });
95
+ vi.mock('./extension-manager.js');
96
+ // Global setup to ensure clean environment for all tests in this file
97
+ const originalArgv = process.argv;
98
+ const originalGeminiModel = process.env['GEMINI_MODEL'];
99
+ beforeEach(() => {
100
+ delete process.env['GEMINI_MODEL'];
101
+ });
102
+ afterEach(() => {
103
+ process.argv = originalArgv;
104
+ if (originalGeminiModel !== undefined) {
105
+ process.env['GEMINI_MODEL'] = originalGeminiModel;
106
+ }
107
+ else {
108
+ delete process.env['GEMINI_MODEL'];
109
+ }
110
+ });
89
111
  describe('parseArguments', () => {
90
- const originalArgv = process.argv;
91
- afterEach(() => {
92
- process.argv = originalArgv;
93
- });
94
112
  it('should throw an error when both --prompt and --prompt-interactive are used together', async () => {
95
113
  process.argv = [
96
114
  'node',
@@ -380,14 +398,13 @@ describe('parseArguments', () => {
380
398
  });
381
399
  });
382
400
  describe('loadCliConfig', () => {
383
- const originalArgv = process.argv;
384
401
  beforeEach(() => {
385
402
  vi.resetAllMocks();
386
403
  vi.mocked(os.homedir).mockReturnValue('/mock/home/user');
387
404
  vi.stubEnv('GEMINI_API_KEY', 'test-api-key');
405
+ vi.spyOn(ExtensionManager.prototype, 'getExtensions').mockReturnValue([]);
388
406
  });
389
407
  afterEach(() => {
390
- process.argv = originalArgv;
391
408
  vi.unstubAllEnvs();
392
409
  vi.restoreAllMocks();
393
410
  });
@@ -419,7 +436,7 @@ describe('loadCliConfig', () => {
419
436
  process.argv = ['node', 'script.js'];
420
437
  const argv = await parseArguments({});
421
438
  const settings = {};
422
- const config = await loadCliConfig(settings, [], 'test-session', argv);
439
+ const config = await loadCliConfig(settings, 'test-session', argv);
423
440
  expect(config.getProxy()).toBeFalsy();
424
441
  });
425
442
  const proxy_url = 'http://localhost:7890';
@@ -459,7 +476,7 @@ describe('loadCliConfig', () => {
459
476
  process.argv = ['node', 'script.js'];
460
477
  const argv = await parseArguments({});
461
478
  const settings = {};
462
- const config = await loadCliConfig(settings, [], 'test-session', argv);
479
+ const config = await loadCliConfig(settings, 'test-session', argv);
463
480
  expect(config.getProxy()).toBe(expected);
464
481
  });
465
482
  });
@@ -468,7 +485,7 @@ describe('loadCliConfig', () => {
468
485
  process.argv = ['node', 'script.js'];
469
486
  const argv = await parseArguments({});
470
487
  const settings = {};
471
- const config = await loadCliConfig(settings, [], 'test-session', argv);
488
+ const config = await loadCliConfig(settings, 'test-session', argv);
472
489
  expect(config.getFileFilteringRespectGitIgnore()).toBe(DEFAULT_FILE_FILTERING_OPTIONS.respectGitIgnore);
473
490
  expect(config.getFileFilteringRespectGeminiIgnore()).toBe(DEFAULT_FILE_FILTERING_OPTIONS.respectGeminiIgnore);
474
491
  });
@@ -485,7 +502,7 @@ describe('Hierarchical Memory Loading (config.ts) - Placeholder Suite', () => {
485
502
  it('should pass extension context file paths to loadServerHierarchicalMemory', async () => {
486
503
  process.argv = ['node', 'script.js'];
487
504
  const settings = {};
488
- const extensions = [
505
+ vi.spyOn(ExtensionManager.prototype, 'getExtensions').mockReturnValue([
489
506
  {
490
507
  path: '/path/to/ext1',
491
508
  name: 'ext1',
@@ -513,10 +530,10 @@ describe('Hierarchical Memory Loading (config.ts) - Placeholder Suite', () => {
513
530
  ],
514
531
  isActive: true,
515
532
  },
516
- ];
533
+ ]);
517
534
  const argv = await parseArguments({});
518
- await loadCliConfig(settings, extensions, 'session-id', argv);
519
- expect(ServerConfig.loadServerHierarchicalMemory).toHaveBeenCalledWith(expect.any(String), [], false, expect.any(Object), extensions, true, 'tree', {
535
+ await loadCliConfig(settings, 'session-id', argv);
536
+ expect(ServerConfig.loadServerHierarchicalMemory).toHaveBeenCalledWith(expect.any(String), [], false, expect.any(Object), expect.any(ExtensionManager), true, 'tree', {
520
537
  respectGitIgnore: false,
521
538
  respectGeminiIgnore: true,
522
539
  }, undefined);
@@ -563,7 +580,7 @@ describe('mergeMcpServers', () => {
563
580
  },
564
581
  },
565
582
  };
566
- const extensions = [
583
+ vi.spyOn(ExtensionManager.prototype, 'getExtensions').mockReturnValue([
567
584
  {
568
585
  path: '/path/to/ext1',
569
586
  name: 'ext1',
@@ -577,11 +594,11 @@ describe('mergeMcpServers', () => {
577
594
  contextFiles: [],
578
595
  isActive: true,
579
596
  },
580
- ];
597
+ ]);
581
598
  const originalSettings = JSON.parse(JSON.stringify(settings));
582
599
  process.argv = ['node', 'script.js'];
583
600
  const argv = await parseArguments({});
584
- await loadCliConfig(settings, extensions, 'test-session', argv);
601
+ await loadCliConfig(settings, 'test-session', argv);
585
602
  expect(settings).toEqual(originalSettings);
586
603
  });
587
604
  });
@@ -593,6 +610,7 @@ describe('mergeExcludeTools', () => {
593
610
  ];
594
611
  const originalIsTTY = process.stdin.isTTY;
595
612
  beforeEach(() => {
613
+ vi.spyOn(ExtensionManager.prototype, 'getExtensions').mockReturnValue([]);
596
614
  process.stdin.isTTY = true;
597
615
  });
598
616
  afterEach(() => {
@@ -600,7 +618,7 @@ describe('mergeExcludeTools', () => {
600
618
  });
601
619
  it('should merge excludeTools from settings and extensions', async () => {
602
620
  const settings = { tools: { exclude: ['tool1', 'tool2'] } };
603
- const extensions = [
621
+ vi.spyOn(ExtensionManager.prototype, 'getExtensions').mockReturnValue([
604
622
  {
605
623
  path: '/path/to/ext1',
606
624
  name: 'ext1',
@@ -619,16 +637,16 @@ describe('mergeExcludeTools', () => {
619
637
  contextFiles: [],
620
638
  isActive: true,
621
639
  },
622
- ];
640
+ ]);
623
641
  process.argv = ['node', 'script.js'];
624
642
  const argv = await parseArguments({});
625
- const config = await loadCliConfig(settings, extensions, 'test-session', argv);
643
+ const config = await loadCliConfig(settings, 'test-session', argv);
626
644
  expect(config.getExcludeTools()).toEqual(expect.arrayContaining(['tool1', 'tool2', 'tool3', 'tool4', 'tool5']));
627
645
  expect(config.getExcludeTools()).toHaveLength(5);
628
646
  });
629
647
  it('should handle overlapping excludeTools between settings and extensions', async () => {
630
648
  const settings = { tools: { exclude: ['tool1', 'tool2'] } };
631
- const extensions = [
649
+ vi.spyOn(ExtensionManager.prototype, 'getExtensions').mockReturnValue([
632
650
  {
633
651
  path: '/path/to/ext1',
634
652
  name: 'ext1',
@@ -638,16 +656,16 @@ describe('mergeExcludeTools', () => {
638
656
  contextFiles: [],
639
657
  isActive: true,
640
658
  },
641
- ];
659
+ ]);
642
660
  process.argv = ['node', 'script.js'];
643
661
  const argv = await parseArguments({});
644
- const config = await loadCliConfig(settings, extensions, 'test-session', argv);
662
+ const config = await loadCliConfig(settings, 'test-session', argv);
645
663
  expect(config.getExcludeTools()).toEqual(expect.arrayContaining(['tool1', 'tool2', 'tool3']));
646
664
  expect(config.getExcludeTools()).toHaveLength(3);
647
665
  });
648
666
  it('should handle overlapping excludeTools between extensions', async () => {
649
667
  const settings = { tools: { exclude: ['tool1'] } };
650
- const extensions = [
668
+ vi.spyOn(ExtensionManager.prototype, 'getExtensions').mockReturnValue([
651
669
  {
652
670
  path: '/path/to/ext1',
653
671
  name: 'ext1',
@@ -666,43 +684,41 @@ describe('mergeExcludeTools', () => {
666
684
  contextFiles: [],
667
685
  isActive: true,
668
686
  },
669
- ];
687
+ ]);
670
688
  process.argv = ['node', 'script.js'];
671
689
  const argv = await parseArguments({});
672
- const config = await loadCliConfig(settings, extensions, 'test-session', argv);
690
+ const config = await loadCliConfig(settings, 'test-session', argv);
673
691
  expect(config.getExcludeTools()).toEqual(expect.arrayContaining(['tool1', 'tool2', 'tool3', 'tool4']));
674
692
  expect(config.getExcludeTools()).toHaveLength(4);
675
693
  });
676
694
  it('should return an empty array when no excludeTools are specified and it is interactive', async () => {
677
695
  process.stdin.isTTY = true;
678
696
  const settings = {};
679
- const extensions = [];
680
697
  process.argv = ['node', 'script.js'];
681
698
  const argv = await parseArguments({});
682
- const config = await loadCliConfig(settings, extensions, 'test-session', argv);
699
+ const config = await loadCliConfig(settings, 'test-session', argv);
683
700
  expect(config.getExcludeTools()).toEqual([]);
684
701
  });
685
702
  it('should return default excludes when no excludeTools are specified and it is not interactive', async () => {
686
703
  process.stdin.isTTY = false;
687
704
  const settings = {};
688
- const extensions = [];
689
705
  process.argv = ['node', 'script.js', '-p', 'test'];
690
706
  const argv = await parseArguments({});
691
- const config = await loadCliConfig(settings, extensions, 'test-session', argv);
707
+ const config = await loadCliConfig(settings, 'test-session', argv);
692
708
  expect(config.getExcludeTools()).toEqual(defaultExcludes);
693
709
  });
694
710
  it('should handle settings with excludeTools but no extensions', async () => {
695
711
  process.argv = ['node', 'script.js'];
696
712
  const argv = await parseArguments({});
697
713
  const settings = { tools: { exclude: ['tool1', 'tool2'] } };
698
- const extensions = [];
699
- const config = await loadCliConfig(settings, extensions, 'test-session', argv);
714
+ vi.spyOn(ExtensionManager.prototype, 'getExtensions').mockReturnValue([]);
715
+ const config = await loadCliConfig(settings, 'test-session', argv);
700
716
  expect(config.getExcludeTools()).toEqual(expect.arrayContaining(['tool1', 'tool2']));
701
717
  expect(config.getExcludeTools()).toHaveLength(2);
702
718
  });
703
719
  it('should handle extensions with excludeTools but no settings', async () => {
704
720
  const settings = {};
705
- const extensions = [
721
+ vi.spyOn(ExtensionManager.prototype, 'getExtensions').mockReturnValue([
706
722
  {
707
723
  path: '/path/to/ext',
708
724
  name: 'ext1',
@@ -712,16 +728,16 @@ describe('mergeExcludeTools', () => {
712
728
  contextFiles: [],
713
729
  isActive: true,
714
730
  },
715
- ];
731
+ ]);
716
732
  process.argv = ['node', 'script.js'];
717
733
  const argv = await parseArguments({});
718
- const config = await loadCliConfig(settings, extensions, 'test-session', argv);
734
+ const config = await loadCliConfig(settings, 'test-session', argv);
719
735
  expect(config.getExcludeTools()).toEqual(expect.arrayContaining(['tool1', 'tool2']));
720
736
  expect(config.getExcludeTools()).toHaveLength(2);
721
737
  });
722
738
  it('should not modify the original settings object', async () => {
723
739
  const settings = { tools: { exclude: ['tool1'] } };
724
- const extensions = [
740
+ vi.spyOn(ExtensionManager.prototype, 'getExtensions').mockReturnValue([
725
741
  {
726
742
  path: '/path/to/ext',
727
743
  name: 'ext1',
@@ -731,11 +747,11 @@ describe('mergeExcludeTools', () => {
731
747
  contextFiles: [],
732
748
  isActive: true,
733
749
  },
734
- ];
750
+ ]);
735
751
  const originalSettings = JSON.parse(JSON.stringify(settings));
736
752
  process.argv = ['node', 'script.js'];
737
753
  const argv = await parseArguments({});
738
- await loadCliConfig(settings, extensions, 'test-session', argv);
754
+ await loadCliConfig(settings, 'test-session', argv);
739
755
  expect(settings).toEqual(originalSettings);
740
756
  });
741
757
  });
@@ -747,6 +763,7 @@ describe('Approval mode tool exclusion logic', () => {
747
763
  isTrusted: true,
748
764
  source: undefined,
749
765
  });
766
+ vi.spyOn(ExtensionManager.prototype, 'getExtensions').mockReturnValue([]);
750
767
  });
751
768
  afterEach(() => {
752
769
  process.stdin.isTTY = originalIsTTY;
@@ -755,8 +772,7 @@ describe('Approval mode tool exclusion logic', () => {
755
772
  process.argv = ['node', 'script.js', '-p', 'test'];
756
773
  const argv = await parseArguments({});
757
774
  const settings = {};
758
- const extensions = [];
759
- const config = await loadCliConfig(settings, extensions, 'test-session', argv);
775
+ const config = await loadCliConfig(settings, 'test-session', argv);
760
776
  const excludedTools = config.getExcludeTools();
761
777
  expect(excludedTools).toContain(SHELL_TOOL_NAME);
762
778
  expect(excludedTools).toContain(EDIT_TOOL_NAME);
@@ -773,8 +789,7 @@ describe('Approval mode tool exclusion logic', () => {
773
789
  ];
774
790
  const argv = await parseArguments({});
775
791
  const settings = {};
776
- const extensions = [];
777
- const config = await loadCliConfig(settings, extensions, 'test-session', argv);
792
+ const config = await loadCliConfig(settings, 'test-session', argv);
778
793
  const excludedTools = config.getExcludeTools();
779
794
  expect(excludedTools).toContain(SHELL_TOOL_NAME);
780
795
  expect(excludedTools).toContain(EDIT_TOOL_NAME);
@@ -791,8 +806,7 @@ describe('Approval mode tool exclusion logic', () => {
791
806
  ];
792
807
  const argv = await parseArguments({});
793
808
  const settings = {};
794
- const extensions = [];
795
- const config = await loadCliConfig(settings, extensions, 'test-session', argv);
809
+ const config = await loadCliConfig(settings, 'test-session', argv);
796
810
  const excludedTools = config.getExcludeTools();
797
811
  expect(excludedTools).toContain(SHELL_TOOL_NAME);
798
812
  expect(excludedTools).not.toContain(EDIT_TOOL_NAME);
@@ -809,8 +823,7 @@ describe('Approval mode tool exclusion logic', () => {
809
823
  ];
810
824
  const argv = await parseArguments({});
811
825
  const settings = {};
812
- const extensions = [];
813
- const config = await loadCliConfig(settings, extensions, 'test-session', argv);
826
+ const config = await loadCliConfig(settings, 'test-session', argv);
814
827
  const excludedTools = config.getExcludeTools();
815
828
  expect(excludedTools).not.toContain(SHELL_TOOL_NAME);
816
829
  expect(excludedTools).not.toContain(EDIT_TOOL_NAME);
@@ -820,8 +833,7 @@ describe('Approval mode tool exclusion logic', () => {
820
833
  process.argv = ['node', 'script.js', '--yolo', '-p', 'test'];
821
834
  const argv = await parseArguments({});
822
835
  const settings = {};
823
- const extensions = [];
824
- const config = await loadCliConfig(settings, extensions, 'test-session', argv);
836
+ const config = await loadCliConfig(settings, 'test-session', argv);
825
837
  const excludedTools = config.getExcludeTools();
826
838
  expect(excludedTools).not.toContain(SHELL_TOOL_NAME);
827
839
  expect(excludedTools).not.toContain(EDIT_TOOL_NAME);
@@ -840,8 +852,7 @@ describe('Approval mode tool exclusion logic', () => {
840
852
  process.argv = testCase.args;
841
853
  const argv = await parseArguments({});
842
854
  const settings = {};
843
- const extensions = [];
844
- const config = await loadCliConfig(settings, extensions, 'test-session', argv);
855
+ const config = await loadCliConfig(settings, 'test-session', argv);
845
856
  const excludedTools = config.getExcludeTools();
846
857
  expect(excludedTools).not.toContain(SHELL_TOOL_NAME);
847
858
  expect(excludedTools).not.toContain(EDIT_TOOL_NAME);
@@ -859,8 +870,7 @@ describe('Approval mode tool exclusion logic', () => {
859
870
  ];
860
871
  const argv = await parseArguments({});
861
872
  const settings = { tools: { exclude: ['custom_tool'] } };
862
- const extensions = [];
863
- const config = await loadCliConfig(settings, extensions, 'test-session', argv);
873
+ const config = await loadCliConfig(settings, 'test-session', argv);
864
874
  const excludedTools = config.getExcludeTools();
865
875
  expect(excludedTools).toContain('custom_tool'); // From settings
866
876
  expect(excludedTools).toContain(SHELL_TOOL_NAME); // From approval mode
@@ -875,8 +885,7 @@ describe('Approval mode tool exclusion logic', () => {
875
885
  disableYoloMode: true,
876
886
  },
877
887
  };
878
- const extensions = [];
879
- await expect(loadCliConfig(settings, extensions, 'test-session', argv)).rejects.toThrow('Cannot start in YOLO mode when it is disabled by settings');
888
+ await expect(loadCliConfig(settings, 'test-session', argv)).rejects.toThrow('Cannot start in YOLO mode when it is disabled by settings');
880
889
  });
881
890
  it('should throw an error for invalid approval mode values in loadCliConfig', async () => {
882
891
  // Create a mock argv with an invalid approval mode that bypasses argument parsing validation
@@ -887,19 +896,17 @@ describe('Approval mode tool exclusion logic', () => {
887
896
  yolo: false,
888
897
  };
889
898
  const settings = {};
890
- const extensions = [];
891
- await expect(loadCliConfig(settings, extensions, 'test-session', invalidArgv)).rejects.toThrow('Invalid approval mode: invalid_mode. Valid values are: yolo, auto_edit, default');
899
+ await expect(loadCliConfig(settings, 'test-session', invalidArgv)).rejects.toThrow('Invalid approval mode: invalid_mode. Valid values are: yolo, auto_edit, default');
892
900
  });
893
901
  });
894
902
  describe('loadCliConfig with allowed-mcp-server-names', () => {
895
- const originalArgv = process.argv;
896
903
  beforeEach(() => {
897
904
  vi.resetAllMocks();
898
905
  vi.mocked(os.homedir).mockReturnValue('/mock/home/user');
899
906
  vi.stubEnv('GEMINI_API_KEY', 'test-api-key');
907
+ vi.spyOn(ExtensionManager.prototype, 'getExtensions').mockReturnValue([]);
900
908
  });
901
909
  afterEach(() => {
902
- process.argv = originalArgv;
903
910
  vi.unstubAllEnvs();
904
911
  vi.restoreAllMocks();
905
912
  });
@@ -913,7 +920,7 @@ describe('loadCliConfig with allowed-mcp-server-names', () => {
913
920
  it('should allow all MCP servers if the flag is not provided', async () => {
914
921
  process.argv = ['node', 'script.js'];
915
922
  const argv = await parseArguments({});
916
- const config = await loadCliConfig(baseSettings, [], 'test-session', argv);
923
+ const config = await loadCliConfig(baseSettings, 'test-session', argv);
917
924
  expect(config.getMcpServers()).toEqual(baseSettings.mcpServers);
918
925
  });
919
926
  it('should allow only the specified MCP server', async () => {
@@ -924,7 +931,7 @@ describe('loadCliConfig with allowed-mcp-server-names', () => {
924
931
  'server1',
925
932
  ];
926
933
  const argv = await parseArguments({});
927
- const config = await loadCliConfig(baseSettings, [], 'test-session', argv);
934
+ const config = await loadCliConfig(baseSettings, 'test-session', argv);
928
935
  expect(config.getMcpServers()).toEqual({
929
936
  server1: { url: 'http://localhost:8080' },
930
937
  });
@@ -939,7 +946,7 @@ describe('loadCliConfig with allowed-mcp-server-names', () => {
939
946
  'server3',
940
947
  ];
941
948
  const argv = await parseArguments({});
942
- const config = await loadCliConfig(baseSettings, [], 'test-session', argv);
949
+ const config = await loadCliConfig(baseSettings, 'test-session', argv);
943
950
  expect(config.getMcpServers()).toEqual({
944
951
  server1: { url: 'http://localhost:8080' },
945
952
  server3: { url: 'http://localhost:8082' },
@@ -955,7 +962,7 @@ describe('loadCliConfig with allowed-mcp-server-names', () => {
955
962
  'server4',
956
963
  ];
957
964
  const argv = await parseArguments({});
958
- const config = await loadCliConfig(baseSettings, [], 'test-session', argv);
965
+ const config = await loadCliConfig(baseSettings, 'test-session', argv);
959
966
  expect(config.getMcpServers()).toEqual({
960
967
  server1: { url: 'http://localhost:8080' },
961
968
  });
@@ -963,7 +970,7 @@ describe('loadCliConfig with allowed-mcp-server-names', () => {
963
970
  it('should allow no MCP servers if the flag is provided but empty', async () => {
964
971
  process.argv = ['node', 'script.js', '--allowed-mcp-server-names', ''];
965
972
  const argv = await parseArguments({});
966
- const config = await loadCliConfig(baseSettings, [], 'test-session', argv);
973
+ const config = await loadCliConfig(baseSettings, 'test-session', argv);
967
974
  expect(config.getMcpServers()).toEqual({});
968
975
  });
969
976
  it('should read allowMCPServers from settings', async () => {
@@ -973,7 +980,7 @@ describe('loadCliConfig with allowed-mcp-server-names', () => {
973
980
  ...baseSettings,
974
981
  mcp: { allowed: ['server1', 'server2'] },
975
982
  };
976
- const config = await loadCliConfig(settings, [], 'test-session', argv);
983
+ const config = await loadCliConfig(settings, 'test-session', argv);
977
984
  expect(config.getMcpServers()).toEqual({
978
985
  server1: { url: 'http://localhost:8080' },
979
986
  server2: { url: 'http://localhost:8081' },
@@ -986,7 +993,7 @@ describe('loadCliConfig with allowed-mcp-server-names', () => {
986
993
  ...baseSettings,
987
994
  mcp: { excluded: ['server1', 'server2'] },
988
995
  };
989
- const config = await loadCliConfig(settings, [], 'test-session', argv);
996
+ const config = await loadCliConfig(settings, 'test-session', argv);
990
997
  expect(config.getMcpServers()).toEqual({
991
998
  server3: { url: 'http://localhost:8082' },
992
999
  });
@@ -1001,7 +1008,7 @@ describe('loadCliConfig with allowed-mcp-server-names', () => {
1001
1008
  allowed: ['server1', 'server2'],
1002
1009
  },
1003
1010
  };
1004
- const config = await loadCliConfig(settings, [], 'test-session', argv);
1011
+ const config = await loadCliConfig(settings, 'test-session', argv);
1005
1012
  expect(config.getMcpServers()).toEqual({
1006
1013
  server2: { url: 'http://localhost:8081' },
1007
1014
  });
@@ -1021,7 +1028,7 @@ describe('loadCliConfig with allowed-mcp-server-names', () => {
1021
1028
  allowed: ['server2'],
1022
1029
  },
1023
1030
  };
1024
- const config = await loadCliConfig(settings, [], 'test-session', argv);
1031
+ const config = await loadCliConfig(settings, 'test-session', argv);
1025
1032
  expect(config.getMcpServers()).toEqual({
1026
1033
  server1: { url: 'http://localhost:8080' },
1027
1034
  });
@@ -1043,7 +1050,7 @@ describe('loadCliConfig with allowed-mcp-server-names', () => {
1043
1050
  excluded: ['server3'], // Should be ignored
1044
1051
  },
1045
1052
  };
1046
- const config = await loadCliConfig(settings, [], 'test-session', argv);
1053
+ const config = await loadCliConfig(settings, 'test-session', argv);
1047
1054
  expect(config.getMcpServers()).toEqual({
1048
1055
  server2: { url: 'http://localhost:8081' },
1049
1056
  server3: { url: 'http://localhost:8082' },
@@ -1051,6 +1058,12 @@ describe('loadCliConfig with allowed-mcp-server-names', () => {
1051
1058
  });
1052
1059
  });
1053
1060
  describe('loadCliConfig model selection', () => {
1061
+ beforeEach(() => {
1062
+ vi.spyOn(ExtensionManager.prototype, 'getExtensions').mockReturnValue([]);
1063
+ });
1064
+ afterEach(() => {
1065
+ vi.resetAllMocks();
1066
+ });
1054
1067
  it('selects a model from settings.json if provided', async () => {
1055
1068
  process.argv = ['node', 'script.js'];
1056
1069
  const argv = await parseArguments({});
@@ -1058,7 +1071,7 @@ describe('loadCliConfig model selection', () => {
1058
1071
  model: {
1059
1072
  name: 'gemini-2.5-pro',
1060
1073
  },
1061
- }, [], 'test-session', argv);
1074
+ }, 'test-session', argv);
1062
1075
  expect(config.getModel()).toBe('gemini-2.5-pro');
1063
1076
  });
1064
1077
  it('uses the default gemini model if nothing is set', async () => {
@@ -1066,7 +1079,7 @@ describe('loadCliConfig model selection', () => {
1066
1079
  const argv = await parseArguments({});
1067
1080
  const config = await loadCliConfig({
1068
1081
  // No model set.
1069
- }, [], 'test-session', argv);
1082
+ }, 'test-session', argv);
1070
1083
  expect(config.getModel()).toBe('auto');
1071
1084
  });
1072
1085
  it('always prefers model from argv', async () => {
@@ -1076,7 +1089,7 @@ describe('loadCliConfig model selection', () => {
1076
1089
  model: {
1077
1090
  name: 'gemini-2.5-pro',
1078
1091
  },
1079
- }, [], 'test-session', argv);
1092
+ }, 'test-session', argv);
1080
1093
  expect(config.getModel()).toBe('gemini-2.5-flash-preview');
1081
1094
  });
1082
1095
  it('selects the model from argv if provided', async () => {
@@ -1084,11 +1097,17 @@ describe('loadCliConfig model selection', () => {
1084
1097
  const argv = await parseArguments({});
1085
1098
  const config = await loadCliConfig({
1086
1099
  // No model provided via settings.
1087
- }, [], 'test-session', argv);
1100
+ }, 'test-session', argv);
1088
1101
  expect(config.getModel()).toBe('gemini-2.5-flash-preview');
1089
1102
  });
1090
1103
  });
1091
1104
  describe('loadCliConfig model selection with model router', () => {
1105
+ beforeEach(() => {
1106
+ vi.spyOn(ExtensionManager.prototype, 'getExtensions').mockReturnValue([]);
1107
+ });
1108
+ afterEach(() => {
1109
+ vi.resetAllMocks();
1110
+ });
1092
1111
  it('should use auto model when useModelRouter is true and no model is provided', async () => {
1093
1112
  process.argv = ['node', 'script.js'];
1094
1113
  const argv = await parseArguments({});
@@ -1096,7 +1115,7 @@ describe('loadCliConfig model selection with model router', () => {
1096
1115
  experimental: {
1097
1116
  useModelRouter: true,
1098
1117
  },
1099
- }, [], 'test-session', argv);
1118
+ }, 'test-session', argv);
1100
1119
  expect(config.getModel()).toBe(DEFAULT_GEMINI_MODEL_AUTO);
1101
1120
  });
1102
1121
  it('should use default model when useModelRouter is false and no model is provided', async () => {
@@ -1106,7 +1125,7 @@ describe('loadCliConfig model selection with model router', () => {
1106
1125
  experimental: {
1107
1126
  useModelRouter: false,
1108
1127
  },
1109
- }, [], 'test-session', argv);
1128
+ }, 'test-session', argv);
1110
1129
  expect(config.getModel()).toBe(DEFAULT_GEMINI_MODEL);
1111
1130
  });
1112
1131
  it('should prioritize argv over useModelRouter', async () => {
@@ -1116,7 +1135,7 @@ describe('loadCliConfig model selection with model router', () => {
1116
1135
  experimental: {
1117
1136
  useModelRouter: true,
1118
1137
  },
1119
- }, [], 'test-session', argv);
1138
+ }, 'test-session', argv);
1120
1139
  expect(config.getModel()).toBe('gemini-from-argv');
1121
1140
  });
1122
1141
  it('should prioritize settings over useModelRouter', async () => {
@@ -1129,7 +1148,7 @@ describe('loadCliConfig model selection with model router', () => {
1129
1148
  model: {
1130
1149
  name: 'gemini-from-settings',
1131
1150
  },
1132
- }, [], 'test-session', argv);
1151
+ }, 'test-session', argv);
1133
1152
  expect(config.getModel()).toBe('gemini-from-settings');
1134
1153
  });
1135
1154
  it('should prioritize environment variable over useModelRouter', async () => {
@@ -1140,19 +1159,18 @@ describe('loadCliConfig model selection with model router', () => {
1140
1159
  experimental: {
1141
1160
  useModelRouter: true,
1142
1161
  },
1143
- }, [], 'test-session', argv);
1162
+ }, 'test-session', argv);
1144
1163
  expect(config.getModel()).toBe('gemini-from-env');
1145
1164
  });
1146
1165
  });
1147
1166
  describe('loadCliConfig folderTrust', () => {
1148
- const originalArgv = process.argv;
1149
1167
  beforeEach(() => {
1150
1168
  vi.resetAllMocks();
1151
1169
  vi.mocked(os.homedir).mockReturnValue('/mock/home/user');
1152
1170
  vi.stubEnv('GEMINI_API_KEY', 'test-api-key');
1171
+ vi.spyOn(ExtensionManager.prototype, 'getExtensions').mockReturnValue([]);
1153
1172
  });
1154
1173
  afterEach(() => {
1155
- process.argv = originalArgv;
1156
1174
  vi.unstubAllEnvs();
1157
1175
  vi.restoreAllMocks();
1158
1176
  });
@@ -1166,7 +1184,7 @@ describe('loadCliConfig folderTrust', () => {
1166
1184
  },
1167
1185
  };
1168
1186
  const argv = await parseArguments({});
1169
- const config = await loadCliConfig(settings, [], 'test-session', argv);
1187
+ const config = await loadCliConfig(settings, 'test-session', argv);
1170
1188
  expect(config.getFolderTrust()).toBe(false);
1171
1189
  });
1172
1190
  it('should be true when folderTrust is true', async () => {
@@ -1179,28 +1197,26 @@ describe('loadCliConfig folderTrust', () => {
1179
1197
  },
1180
1198
  },
1181
1199
  };
1182
- const config = await loadCliConfig(settings, [], 'test-session', argv);
1200
+ const config = await loadCliConfig(settings, 'test-session', argv);
1183
1201
  expect(config.getFolderTrust()).toBe(true);
1184
1202
  });
1185
1203
  it('should be false by default', async () => {
1186
1204
  process.argv = ['node', 'script.js'];
1187
1205
  const argv = await parseArguments({});
1188
1206
  const settings = {};
1189
- const config = await loadCliConfig(settings, [], 'test-session', argv);
1207
+ const config = await loadCliConfig(settings, 'test-session', argv);
1190
1208
  expect(config.getFolderTrust()).toBe(false);
1191
1209
  });
1192
1210
  });
1193
1211
  describe('loadCliConfig with includeDirectories', () => {
1194
- const originalArgv = process.argv;
1195
1212
  beforeEach(() => {
1196
1213
  vi.resetAllMocks();
1197
1214
  vi.mocked(os.homedir).mockReturnValue('/mock/home/user');
1198
1215
  vi.stubEnv('GEMINI_API_KEY', 'test-api-key');
1199
1216
  vi.spyOn(process, 'cwd').mockReturnValue(path.resolve(path.sep, 'home', 'user', 'project'));
1217
+ vi.spyOn(ExtensionManager.prototype, 'getExtensions').mockReturnValue([]);
1200
1218
  });
1201
1219
  afterEach(() => {
1202
- process.argv = originalArgv;
1203
- vi.unstubAllEnvs();
1204
1220
  vi.restoreAllMocks();
1205
1221
  });
1206
1222
  it('should combine and resolve paths from settings and CLI arguments', async () => {
@@ -1221,7 +1237,7 @@ describe('loadCliConfig with includeDirectories', () => {
1221
1237
  ],
1222
1238
  },
1223
1239
  };
1224
- const config = await loadCliConfig(settings, [], 'test-session', argv);
1240
+ const config = await loadCliConfig(settings, 'test-session', argv);
1225
1241
  const expected = [
1226
1242
  mockCwd,
1227
1243
  path.resolve(path.sep, 'cli', 'path1'),
@@ -1235,14 +1251,13 @@ describe('loadCliConfig with includeDirectories', () => {
1235
1251
  });
1236
1252
  });
1237
1253
  describe('loadCliConfig chatCompression', () => {
1238
- const originalArgv = process.argv;
1239
1254
  beforeEach(() => {
1240
1255
  vi.resetAllMocks();
1241
1256
  vi.mocked(os.homedir).mockReturnValue('/mock/home/user');
1242
1257
  vi.stubEnv('GEMINI_API_KEY', 'test-api-key');
1258
+ vi.spyOn(ExtensionManager.prototype, 'getExtensions').mockReturnValue([]);
1243
1259
  });
1244
1260
  afterEach(() => {
1245
- process.argv = originalArgv;
1246
1261
  vi.unstubAllEnvs();
1247
1262
  vi.restoreAllMocks();
1248
1263
  });
@@ -1256,7 +1271,7 @@ describe('loadCliConfig chatCompression', () => {
1256
1271
  },
1257
1272
  },
1258
1273
  };
1259
- const config = await loadCliConfig(settings, [], 'test-session', argv);
1274
+ const config = await loadCliConfig(settings, 'test-session', argv);
1260
1275
  expect(config.getChatCompression()).toEqual({
1261
1276
  contextPercentageThreshold: 0.5,
1262
1277
  });
@@ -1265,19 +1280,18 @@ describe('loadCliConfig chatCompression', () => {
1265
1280
  process.argv = ['node', 'script.js'];
1266
1281
  const argv = await parseArguments({});
1267
1282
  const settings = {};
1268
- const config = await loadCliConfig(settings, [], 'test-session', argv);
1283
+ const config = await loadCliConfig(settings, 'test-session', argv);
1269
1284
  expect(config.getChatCompression()).toBeUndefined();
1270
1285
  });
1271
1286
  });
1272
1287
  describe('loadCliConfig useRipgrep', () => {
1273
- const originalArgv = process.argv;
1274
1288
  beforeEach(() => {
1275
1289
  vi.resetAllMocks();
1276
1290
  vi.mocked(os.homedir).mockReturnValue('/mock/home/user');
1277
1291
  vi.stubEnv('GEMINI_API_KEY', 'test-api-key');
1292
+ vi.spyOn(ExtensionManager.prototype, 'getExtensions').mockReturnValue([]);
1278
1293
  });
1279
1294
  afterEach(() => {
1280
- process.argv = originalArgv;
1281
1295
  vi.unstubAllEnvs();
1282
1296
  vi.restoreAllMocks();
1283
1297
  });
@@ -1285,21 +1299,21 @@ describe('loadCliConfig useRipgrep', () => {
1285
1299
  process.argv = ['node', 'script.js'];
1286
1300
  const argv = await parseArguments({});
1287
1301
  const settings = {};
1288
- const config = await loadCliConfig(settings, [], 'test-session', argv);
1302
+ const config = await loadCliConfig(settings, 'test-session', argv);
1289
1303
  expect(config.getUseRipgrep()).toBe(true);
1290
1304
  });
1291
1305
  it('should be false when useRipgrep is set to false in settings', async () => {
1292
1306
  process.argv = ['node', 'script.js'];
1293
1307
  const argv = await parseArguments({});
1294
1308
  const settings = { tools: { useRipgrep: false } };
1295
- const config = await loadCliConfig(settings, [], 'test-session', argv);
1309
+ const config = await loadCliConfig(settings, 'test-session', argv);
1296
1310
  expect(config.getUseRipgrep()).toBe(false);
1297
1311
  });
1298
1312
  it('should be true when useRipgrep is explicitly set to true in settings', async () => {
1299
1313
  process.argv = ['node', 'script.js'];
1300
1314
  const argv = await parseArguments({});
1301
1315
  const settings = { tools: { useRipgrep: true } };
1302
- const config = await loadCliConfig(settings, [], 'test-session', argv);
1316
+ const config = await loadCliConfig(settings, 'test-session', argv);
1303
1317
  expect(config.getUseRipgrep()).toBe(true);
1304
1318
  });
1305
1319
  describe('loadCliConfig useModelRouter', () => {
@@ -1307,34 +1321,33 @@ describe('loadCliConfig useRipgrep', () => {
1307
1321
  process.argv = ['node', 'script.js'];
1308
1322
  const argv = await parseArguments({});
1309
1323
  const settings = {};
1310
- const config = await loadCliConfig(settings, [], 'test-session', argv);
1324
+ const config = await loadCliConfig(settings, 'test-session', argv);
1311
1325
  expect(config.getUseModelRouter()).toBe(true);
1312
1326
  });
1313
1327
  it('should be true when useModelRouter is set to true in settings', async () => {
1314
1328
  process.argv = ['node', 'script.js'];
1315
1329
  const argv = await parseArguments({});
1316
1330
  const settings = { experimental: { useModelRouter: true } };
1317
- const config = await loadCliConfig(settings, [], 'test-session', argv);
1331
+ const config = await loadCliConfig(settings, 'test-session', argv);
1318
1332
  expect(config.getUseModelRouter()).toBe(true);
1319
1333
  });
1320
1334
  it('should be false when useModelRouter is explicitly set to false in settings', async () => {
1321
1335
  process.argv = ['node', 'script.js'];
1322
1336
  const argv = await parseArguments({});
1323
1337
  const settings = { experimental: { useModelRouter: false } };
1324
- const config = await loadCliConfig(settings, [], 'test-session', argv);
1338
+ const config = await loadCliConfig(settings, 'test-session', argv);
1325
1339
  expect(config.getUseModelRouter()).toBe(false);
1326
1340
  });
1327
1341
  });
1328
1342
  });
1329
1343
  describe('screenReader configuration', () => {
1330
- const originalArgv = process.argv;
1331
1344
  beforeEach(() => {
1332
1345
  vi.resetAllMocks();
1333
1346
  vi.mocked(os.homedir).mockReturnValue('/mock/home/user');
1334
1347
  vi.stubEnv('GEMINI_API_KEY', 'test-api-key');
1348
+ vi.spyOn(ExtensionManager.prototype, 'getExtensions').mockReturnValue([]);
1335
1349
  });
1336
1350
  afterEach(() => {
1337
- process.argv = originalArgv;
1338
1351
  vi.unstubAllEnvs();
1339
1352
  vi.restoreAllMocks();
1340
1353
  });
@@ -1344,7 +1357,7 @@ describe('screenReader configuration', () => {
1344
1357
  const settings = {
1345
1358
  ui: { accessibility: { screenReader: true } },
1346
1359
  };
1347
- const config = await loadCliConfig(settings, [], 'test-session', argv);
1360
+ const config = await loadCliConfig(settings, 'test-session', argv);
1348
1361
  expect(config.getScreenReader()).toBe(true);
1349
1362
  });
1350
1363
  it('should use screenReader value from settings if CLI flag is not present (settings false)', async () => {
@@ -1353,7 +1366,7 @@ describe('screenReader configuration', () => {
1353
1366
  const settings = {
1354
1367
  ui: { accessibility: { screenReader: false } },
1355
1368
  };
1356
- const config = await loadCliConfig(settings, [], 'test-session', argv);
1369
+ const config = await loadCliConfig(settings, 'test-session', argv);
1357
1370
  expect(config.getScreenReader()).toBe(false);
1358
1371
  });
1359
1372
  it('should prioritize --screen-reader CLI flag (true) over settings (false)', async () => {
@@ -1362,19 +1375,18 @@ describe('screenReader configuration', () => {
1362
1375
  const settings = {
1363
1376
  ui: { accessibility: { screenReader: false } },
1364
1377
  };
1365
- const config = await loadCliConfig(settings, [], 'test-session', argv);
1378
+ const config = await loadCliConfig(settings, 'test-session', argv);
1366
1379
  expect(config.getScreenReader()).toBe(true);
1367
1380
  });
1368
1381
  it('should be false by default when no flag or setting is present', async () => {
1369
1382
  process.argv = ['node', 'script.js'];
1370
1383
  const argv = await parseArguments({});
1371
1384
  const settings = {};
1372
- const config = await loadCliConfig(settings, [], 'test-session', argv);
1385
+ const config = await loadCliConfig(settings, 'test-session', argv);
1373
1386
  expect(config.getScreenReader()).toBe(false);
1374
1387
  });
1375
1388
  });
1376
1389
  describe('loadCliConfig tool exclusions', () => {
1377
- const originalArgv = process.argv;
1378
1390
  const originalIsTTY = process.stdin.isTTY;
1379
1391
  beforeEach(() => {
1380
1392
  vi.resetAllMocks();
@@ -1385,9 +1397,9 @@ describe('loadCliConfig tool exclusions', () => {
1385
1397
  isTrusted: true,
1386
1398
  source: undefined,
1387
1399
  });
1400
+ vi.spyOn(ExtensionManager.prototype, 'getExtensions').mockReturnValue([]);
1388
1401
  });
1389
1402
  afterEach(() => {
1390
- process.argv = originalArgv;
1391
1403
  process.stdin.isTTY = originalIsTTY;
1392
1404
  vi.unstubAllEnvs();
1393
1405
  vi.restoreAllMocks();
@@ -1396,7 +1408,7 @@ describe('loadCliConfig tool exclusions', () => {
1396
1408
  process.stdin.isTTY = true;
1397
1409
  process.argv = ['node', 'script.js'];
1398
1410
  const argv = await parseArguments({});
1399
- const config = await loadCliConfig({}, [], 'test-session', argv);
1411
+ const config = await loadCliConfig({}, 'test-session', argv);
1400
1412
  expect(config.getExcludeTools()).not.toContain('run_shell_command');
1401
1413
  expect(config.getExcludeTools()).not.toContain('replace');
1402
1414
  expect(config.getExcludeTools()).not.toContain('write_file');
@@ -1405,7 +1417,7 @@ describe('loadCliConfig tool exclusions', () => {
1405
1417
  process.stdin.isTTY = true;
1406
1418
  process.argv = ['node', 'script.js', '--yolo'];
1407
1419
  const argv = await parseArguments({});
1408
- const config = await loadCliConfig({}, [], 'test-session', argv);
1420
+ const config = await loadCliConfig({}, 'test-session', argv);
1409
1421
  expect(config.getExcludeTools()).not.toContain('run_shell_command');
1410
1422
  expect(config.getExcludeTools()).not.toContain('replace');
1411
1423
  expect(config.getExcludeTools()).not.toContain('write_file');
@@ -1414,7 +1426,7 @@ describe('loadCliConfig tool exclusions', () => {
1414
1426
  process.stdin.isTTY = false;
1415
1427
  process.argv = ['node', 'script.js', '-p', 'test'];
1416
1428
  const argv = await parseArguments({});
1417
- const config = await loadCliConfig({}, [], 'test-session', argv);
1429
+ const config = await loadCliConfig({}, 'test-session', argv);
1418
1430
  expect(config.getExcludeTools()).toContain('run_shell_command');
1419
1431
  expect(config.getExcludeTools()).toContain('replace');
1420
1432
  expect(config.getExcludeTools()).toContain('write_file');
@@ -1423,7 +1435,7 @@ describe('loadCliConfig tool exclusions', () => {
1423
1435
  process.stdin.isTTY = false;
1424
1436
  process.argv = ['node', 'script.js', '-p', 'test', '--yolo'];
1425
1437
  const argv = await parseArguments({});
1426
- const config = await loadCliConfig({}, [], 'test-session', argv);
1438
+ const config = await loadCliConfig({}, 'test-session', argv);
1427
1439
  expect(config.getExcludeTools()).not.toContain('run_shell_command');
1428
1440
  expect(config.getExcludeTools()).not.toContain('replace');
1429
1441
  expect(config.getExcludeTools()).not.toContain('write_file');
@@ -1439,7 +1451,7 @@ describe('loadCliConfig tool exclusions', () => {
1439
1451
  'ShellTool',
1440
1452
  ];
1441
1453
  const argv = await parseArguments({});
1442
- const config = await loadCliConfig({}, [], 'test-session', argv);
1454
+ const config = await loadCliConfig({}, 'test-session', argv);
1443
1455
  expect(config.getExcludeTools()).not.toContain(SHELL_TOOL_NAME);
1444
1456
  });
1445
1457
  it('should not exclude shell tool in non-interactive mode when --allowed-tools="run_shell_command" is set', async () => {
@@ -1453,7 +1465,7 @@ describe('loadCliConfig tool exclusions', () => {
1453
1465
  'run_shell_command',
1454
1466
  ];
1455
1467
  const argv = await parseArguments({});
1456
- const config = await loadCliConfig({}, [], 'test-session', argv);
1468
+ const config = await loadCliConfig({}, 'test-session', argv);
1457
1469
  expect(config.getExcludeTools()).not.toContain(SHELL_TOOL_NAME);
1458
1470
  });
1459
1471
  it('should not exclude shell tool in non-interactive mode when --allowed-tools="ShellTool(wc)" is set', async () => {
@@ -1467,21 +1479,20 @@ describe('loadCliConfig tool exclusions', () => {
1467
1479
  'ShellTool(wc)',
1468
1480
  ];
1469
1481
  const argv = await parseArguments({});
1470
- const config = await loadCliConfig({}, [], 'test-session', argv);
1482
+ const config = await loadCliConfig({}, 'test-session', argv);
1471
1483
  expect(config.getExcludeTools()).not.toContain(SHELL_TOOL_NAME);
1472
1484
  });
1473
1485
  });
1474
1486
  describe('loadCliConfig interactive', () => {
1475
- const originalArgv = process.argv;
1476
1487
  const originalIsTTY = process.stdin.isTTY;
1477
1488
  beforeEach(() => {
1478
1489
  vi.resetAllMocks();
1479
1490
  vi.mocked(os.homedir).mockReturnValue('/mock/home/user');
1480
1491
  vi.stubEnv('GEMINI_API_KEY', 'test-api-key');
1481
1492
  process.stdin.isTTY = true;
1493
+ vi.spyOn(ExtensionManager.prototype, 'getExtensions').mockReturnValue([]);
1482
1494
  });
1483
1495
  afterEach(() => {
1484
- process.argv = originalArgv;
1485
1496
  process.stdin.isTTY = originalIsTTY;
1486
1497
  vi.unstubAllEnvs();
1487
1498
  vi.restoreAllMocks();
@@ -1490,35 +1501,35 @@ describe('loadCliConfig interactive', () => {
1490
1501
  process.stdin.isTTY = true;
1491
1502
  process.argv = ['node', 'script.js'];
1492
1503
  const argv = await parseArguments({});
1493
- const config = await loadCliConfig({}, [], 'test-session', argv);
1504
+ const config = await loadCliConfig({}, 'test-session', argv);
1494
1505
  expect(config.isInteractive()).toBe(true);
1495
1506
  });
1496
1507
  it('should be interactive if prompt-interactive is set', async () => {
1497
1508
  process.stdin.isTTY = false;
1498
1509
  process.argv = ['node', 'script.js', '--prompt-interactive', 'test'];
1499
1510
  const argv = await parseArguments({});
1500
- const config = await loadCliConfig({}, [], 'test-session', argv);
1511
+ const config = await loadCliConfig({}, 'test-session', argv);
1501
1512
  expect(config.isInteractive()).toBe(true);
1502
1513
  });
1503
1514
  it('should not be interactive if not isTTY and no prompt', async () => {
1504
1515
  process.stdin.isTTY = false;
1505
1516
  process.argv = ['node', 'script.js'];
1506
1517
  const argv = await parseArguments({});
1507
- const config = await loadCliConfig({}, [], 'test-session', argv);
1518
+ const config = await loadCliConfig({}, 'test-session', argv);
1508
1519
  expect(config.isInteractive()).toBe(false);
1509
1520
  });
1510
1521
  it('should not be interactive if prompt is set', async () => {
1511
1522
  process.stdin.isTTY = true;
1512
1523
  process.argv = ['node', 'script.js', '--prompt', 'test'];
1513
1524
  const argv = await parseArguments({});
1514
- const config = await loadCliConfig({}, [], 'test-session', argv);
1525
+ const config = await loadCliConfig({}, 'test-session', argv);
1515
1526
  expect(config.isInteractive()).toBe(false);
1516
1527
  });
1517
1528
  it('should not be interactive if positional prompt words are provided with other flags', async () => {
1518
1529
  process.stdin.isTTY = true;
1519
1530
  process.argv = ['node', 'script.js', '--model', 'gemini-2.5-pro', 'Hello'];
1520
1531
  const argv = await parseArguments({});
1521
- const config = await loadCliConfig({}, [], 'test-session', argv);
1532
+ const config = await loadCliConfig({}, 'test-session', argv);
1522
1533
  expect(config.isInteractive()).toBe(false);
1523
1534
  });
1524
1535
  it('should not be interactive if positional prompt words are provided with multiple flags', async () => {
@@ -1532,7 +1543,7 @@ describe('loadCliConfig interactive', () => {
1532
1543
  'Hello world',
1533
1544
  ];
1534
1545
  const argv = await parseArguments({});
1535
- const config = await loadCliConfig({}, [], 'test-session', argv);
1546
+ const config = await loadCliConfig({}, 'test-session', argv);
1536
1547
  expect(config.isInteractive()).toBe(false);
1537
1548
  // Verify the question is preserved for one-shot execution
1538
1549
  expect(argv.prompt).toBe('Hello world');
@@ -1542,7 +1553,7 @@ describe('loadCliConfig interactive', () => {
1542
1553
  process.stdin.isTTY = true;
1543
1554
  process.argv = ['node', 'script.js', '-e', 'none', 'hello'];
1544
1555
  const argv = await parseArguments({});
1545
- const config = await loadCliConfig({}, [], 'test-session', argv);
1556
+ const config = await loadCliConfig({}, 'test-session', argv);
1546
1557
  expect(config.isInteractive()).toBe(false);
1547
1558
  expect(argv.query).toBe('hello');
1548
1559
  expect(argv.extensions).toEqual(['none']);
@@ -1551,7 +1562,7 @@ describe('loadCliConfig interactive', () => {
1551
1562
  process.stdin.isTTY = true;
1552
1563
  process.argv = ['node', 'script.js', 'hello world how are you'];
1553
1564
  const argv = await parseArguments({});
1554
- const config = await loadCliConfig({}, [], 'test-session', argv);
1565
+ const config = await loadCliConfig({}, 'test-session', argv);
1555
1566
  expect(config.isInteractive()).toBe(false);
1556
1567
  expect(argv.query).toBe('hello world how are you');
1557
1568
  expect(argv.prompt).toBe('hello world how are you');
@@ -1571,7 +1582,7 @@ describe('loadCliConfig interactive', () => {
1571
1582
  'array',
1572
1583
  ];
1573
1584
  const argv = await parseArguments({});
1574
- const config = await loadCliConfig({}, [], 'test-session', argv);
1585
+ const config = await loadCliConfig({}, 'test-session', argv);
1575
1586
  expect(config.isInteractive()).toBe(false);
1576
1587
  expect(argv.query).toBe('write a function to sort array');
1577
1588
  expect(argv.model).toBe('gemini-2.5-pro');
@@ -1580,7 +1591,7 @@ describe('loadCliConfig interactive', () => {
1580
1591
  process.stdin.isTTY = true;
1581
1592
  process.argv = ['node', 'script.js', ''];
1582
1593
  const argv = await parseArguments({});
1583
- const config = await loadCliConfig({}, [], 'test-session', argv);
1594
+ const config = await loadCliConfig({}, 'test-session', argv);
1584
1595
  expect(config.isInteractive()).toBe(true);
1585
1596
  expect(argv.query).toBeUndefined();
1586
1597
  });
@@ -1598,7 +1609,7 @@ describe('loadCliConfig interactive', () => {
1598
1609
  'you',
1599
1610
  ];
1600
1611
  const argv = await parseArguments({});
1601
- const config = await loadCliConfig({}, [], 'test-session', argv);
1612
+ const config = await loadCliConfig({}, 'test-session', argv);
1602
1613
  expect(config.isInteractive()).toBe(false);
1603
1614
  expect(argv.query).toBe('hello world how are you');
1604
1615
  expect(argv.extensions).toEqual(['none']);
@@ -1607,7 +1618,7 @@ describe('loadCliConfig interactive', () => {
1607
1618
  process.stdin.isTTY = true;
1608
1619
  process.argv = ['node', 'script.js', '--model', 'gemini-2.5-pro'];
1609
1620
  const argv = await parseArguments({});
1610
- const config = await loadCliConfig({}, [], 'test-session', argv);
1621
+ const config = await loadCliConfig({}, 'test-session', argv);
1611
1622
  expect(config.isInteractive()).toBe(true);
1612
1623
  });
1613
1624
  });
@@ -1622,6 +1633,7 @@ describe('loadCliConfig approval mode', () => {
1622
1633
  isTrusted: true,
1623
1634
  source: undefined,
1624
1635
  });
1636
+ vi.spyOn(ExtensionManager.prototype, 'getExtensions').mockReturnValue([]);
1625
1637
  });
1626
1638
  afterEach(() => {
1627
1639
  process.argv = originalArgv;
@@ -1631,37 +1643,37 @@ describe('loadCliConfig approval mode', () => {
1631
1643
  it('should default to DEFAULT approval mode when no flags are set', async () => {
1632
1644
  process.argv = ['node', 'script.js'];
1633
1645
  const argv = await parseArguments({});
1634
- const config = await loadCliConfig({}, [], 'test-session', argv);
1646
+ const config = await loadCliConfig({}, 'test-session', argv);
1635
1647
  expect(config.getApprovalMode()).toBe(ServerConfig.ApprovalMode.DEFAULT);
1636
1648
  });
1637
1649
  it('should set YOLO approval mode when --yolo flag is used', async () => {
1638
1650
  process.argv = ['node', 'script.js', '--yolo'];
1639
1651
  const argv = await parseArguments({});
1640
- const config = await loadCliConfig({}, [], 'test-session', argv);
1652
+ const config = await loadCliConfig({}, 'test-session', argv);
1641
1653
  expect(config.getApprovalMode()).toBe(ServerConfig.ApprovalMode.YOLO);
1642
1654
  });
1643
1655
  it('should set YOLO approval mode when -y flag is used', async () => {
1644
1656
  process.argv = ['node', 'script.js', '-y'];
1645
1657
  const argv = await parseArguments({});
1646
- const config = await loadCliConfig({}, [], 'test-session', argv);
1658
+ const config = await loadCliConfig({}, 'test-session', argv);
1647
1659
  expect(config.getApprovalMode()).toBe(ServerConfig.ApprovalMode.YOLO);
1648
1660
  });
1649
1661
  it('should set DEFAULT approval mode when --approval-mode=default', async () => {
1650
1662
  process.argv = ['node', 'script.js', '--approval-mode', 'default'];
1651
1663
  const argv = await parseArguments({});
1652
- const config = await loadCliConfig({}, [], 'test-session', argv);
1664
+ const config = await loadCliConfig({}, 'test-session', argv);
1653
1665
  expect(config.getApprovalMode()).toBe(ServerConfig.ApprovalMode.DEFAULT);
1654
1666
  });
1655
1667
  it('should set AUTO_EDIT approval mode when --approval-mode=auto_edit', async () => {
1656
1668
  process.argv = ['node', 'script.js', '--approval-mode', 'auto_edit'];
1657
1669
  const argv = await parseArguments({});
1658
- const config = await loadCliConfig({}, [], 'test-session', argv);
1670
+ const config = await loadCliConfig({}, 'test-session', argv);
1659
1671
  expect(config.getApprovalMode()).toBe(ServerConfig.ApprovalMode.AUTO_EDIT);
1660
1672
  });
1661
1673
  it('should set YOLO approval mode when --approval-mode=yolo', async () => {
1662
1674
  process.argv = ['node', 'script.js', '--approval-mode', 'yolo'];
1663
1675
  const argv = await parseArguments({});
1664
- const config = await loadCliConfig({}, [], 'test-session', argv);
1676
+ const config = await loadCliConfig({}, 'test-session', argv);
1665
1677
  expect(config.getApprovalMode()).toBe(ServerConfig.ApprovalMode.YOLO);
1666
1678
  });
1667
1679
  it('should prioritize --approval-mode over --yolo when both would be valid (but validation prevents this)', async () => {
@@ -1671,13 +1683,13 @@ describe('loadCliConfig approval mode', () => {
1671
1683
  const argv = await parseArguments({});
1672
1684
  // Manually set yolo to true to simulate what would happen if validation didn't prevent it
1673
1685
  argv.yolo = true;
1674
- const config = await loadCliConfig({}, [], 'test-session', argv);
1686
+ const config = await loadCliConfig({}, 'test-session', argv);
1675
1687
  expect(config.getApprovalMode()).toBe(ServerConfig.ApprovalMode.DEFAULT);
1676
1688
  });
1677
1689
  it('should fall back to --yolo behavior when --approval-mode is not set', async () => {
1678
1690
  process.argv = ['node', 'script.js', '--yolo'];
1679
1691
  const argv = await parseArguments({});
1680
- const config = await loadCliConfig({}, [], 'test-session', argv);
1692
+ const config = await loadCliConfig({}, 'test-session', argv);
1681
1693
  expect(config.getApprovalMode()).toBe(ServerConfig.ApprovalMode.YOLO);
1682
1694
  });
1683
1695
  // --- Untrusted Folder Scenarios ---
@@ -1691,25 +1703,25 @@ describe('loadCliConfig approval mode', () => {
1691
1703
  it('should override --approval-mode=yolo to DEFAULT', async () => {
1692
1704
  process.argv = ['node', 'script.js', '--approval-mode', 'yolo'];
1693
1705
  const argv = await parseArguments({});
1694
- const config = await loadCliConfig({}, [], 'test-session', argv);
1706
+ const config = await loadCliConfig({}, 'test-session', argv);
1695
1707
  expect(config.getApprovalMode()).toBe(ServerConfig.ApprovalMode.DEFAULT);
1696
1708
  });
1697
1709
  it('should override --approval-mode=auto_edit to DEFAULT', async () => {
1698
1710
  process.argv = ['node', 'script.js', '--approval-mode', 'auto_edit'];
1699
1711
  const argv = await parseArguments({});
1700
- const config = await loadCliConfig({}, [], 'test-session', argv);
1712
+ const config = await loadCliConfig({}, 'test-session', argv);
1701
1713
  expect(config.getApprovalMode()).toBe(ServerConfig.ApprovalMode.DEFAULT);
1702
1714
  });
1703
1715
  it('should override --yolo flag to DEFAULT', async () => {
1704
1716
  process.argv = ['node', 'script.js', '--yolo'];
1705
1717
  const argv = await parseArguments({});
1706
- const config = await loadCliConfig({}, [], 'test-session', argv);
1718
+ const config = await loadCliConfig({}, 'test-session', argv);
1707
1719
  expect(config.getApprovalMode()).toBe(ServerConfig.ApprovalMode.DEFAULT);
1708
1720
  });
1709
1721
  it('should remain DEFAULT when --approval-mode=default', async () => {
1710
1722
  process.argv = ['node', 'script.js', '--approval-mode', 'default'];
1711
1723
  const argv = await parseArguments({});
1712
- const config = await loadCliConfig({}, [], 'test-session', argv);
1724
+ const config = await loadCliConfig({}, 'test-session', argv);
1713
1725
  expect(config.getApprovalMode()).toBe(ServerConfig.ApprovalMode.DEFAULT);
1714
1726
  });
1715
1727
  });
@@ -1721,6 +1733,7 @@ describe('loadCliConfig fileFiltering', () => {
1721
1733
  vi.mocked(os.homedir).mockReturnValue('/mock/home/user');
1722
1734
  vi.stubEnv('GEMINI_API_KEY', 'test-api-key');
1723
1735
  process.argv = ['node', 'script.js']; // Reset argv for each test
1736
+ vi.spyOn(ExtensionManager.prototype, 'getExtensions').mockReturnValue([]);
1724
1737
  });
1725
1738
  afterEach(() => {
1726
1739
  process.argv = originalArgv;
@@ -1776,33 +1789,39 @@ describe('loadCliConfig fileFiltering', () => {
1776
1789
  },
1777
1790
  };
1778
1791
  const argv = await parseArguments(settings);
1779
- const config = await loadCliConfig(settings, [], 'test-session', argv);
1792
+ const config = await loadCliConfig(settings, 'test-session', argv);
1780
1793
  expect(getter(config)).toBe(value);
1781
1794
  });
1782
1795
  });
1783
1796
  describe('Output format', () => {
1797
+ beforeEach(() => {
1798
+ vi.spyOn(ExtensionManager.prototype, 'getExtensions').mockReturnValue([]);
1799
+ });
1800
+ afterEach(() => {
1801
+ vi.resetAllMocks();
1802
+ });
1784
1803
  it('should default to TEXT', async () => {
1785
1804
  process.argv = ['node', 'script.js'];
1786
1805
  const argv = await parseArguments({});
1787
- const config = await loadCliConfig({}, [], 'test-session', argv);
1806
+ const config = await loadCliConfig({}, 'test-session', argv);
1788
1807
  expect(config.getOutputFormat()).toBe(OutputFormat.TEXT);
1789
1808
  });
1790
1809
  it('should use the format from settings', async () => {
1791
1810
  process.argv = ['node', 'script.js'];
1792
1811
  const argv = await parseArguments({});
1793
- const config = await loadCliConfig({ output: { format: OutputFormat.JSON } }, [], 'test-session', argv);
1812
+ const config = await loadCliConfig({ output: { format: OutputFormat.JSON } }, 'test-session', argv);
1794
1813
  expect(config.getOutputFormat()).toBe(OutputFormat.JSON);
1795
1814
  });
1796
1815
  it('should prioritize the format from argv', async () => {
1797
1816
  process.argv = ['node', 'script.js', '--output-format', 'json'];
1798
1817
  const argv = await parseArguments({});
1799
- const config = await loadCliConfig({ output: { format: OutputFormat.JSON } }, [], 'test-session', argv);
1818
+ const config = await loadCliConfig({ output: { format: OutputFormat.JSON } }, 'test-session', argv);
1800
1819
  expect(config.getOutputFormat()).toBe(OutputFormat.JSON);
1801
1820
  });
1802
1821
  it('should accept stream-json as a valid output format', async () => {
1803
1822
  process.argv = ['node', 'script.js', '--output-format', 'stream-json'];
1804
1823
  const argv = await parseArguments({});
1805
- const config = await loadCliConfig({}, [], 'test-session', argv);
1824
+ const config = await loadCliConfig({}, 'test-session', argv);
1806
1825
  expect(config.getOutputFormat()).toBe(OutputFormat.STREAM_JSON);
1807
1826
  });
1808
1827
  it('should error on invalid --output-format argument', async () => {
@@ -1868,12 +1887,18 @@ describe('parseArguments with positional prompt', () => {
1868
1887
  });
1869
1888
  });
1870
1889
  describe('Telemetry configuration via environment variables', () => {
1890
+ beforeEach(() => {
1891
+ vi.spyOn(ExtensionManager.prototype, 'getExtensions').mockReturnValue([]);
1892
+ });
1893
+ afterEach(() => {
1894
+ vi.resetAllMocks();
1895
+ });
1871
1896
  it('should prioritize GEMINI_TELEMETRY_ENABLED over settings', async () => {
1872
1897
  vi.stubEnv('GEMINI_TELEMETRY_ENABLED', 'true');
1873
1898
  process.argv = ['node', 'script.js'];
1874
1899
  const argv = await parseArguments({});
1875
1900
  const settings = { telemetry: { enabled: false } };
1876
- const config = await loadCliConfig(settings, [], 'test-session', argv);
1901
+ const config = await loadCliConfig(settings, 'test-session', argv);
1877
1902
  expect(config.getTelemetryEnabled()).toBe(true);
1878
1903
  });
1879
1904
  it('should prioritize GEMINI_TELEMETRY_TARGET over settings', async () => {
@@ -1883,7 +1908,7 @@ describe('Telemetry configuration via environment variables', () => {
1883
1908
  const settings = {
1884
1909
  telemetry: { target: ServerConfig.TelemetryTarget.LOCAL },
1885
1910
  };
1886
- const config = await loadCliConfig(settings, [], 'test-session', argv);
1911
+ const config = await loadCliConfig(settings, 'test-session', argv);
1887
1912
  expect(config.getTelemetryTarget()).toBe('gcp');
1888
1913
  });
1889
1914
  it('should throw when GEMINI_TELEMETRY_TARGET is invalid', async () => {
@@ -1893,7 +1918,7 @@ describe('Telemetry configuration via environment variables', () => {
1893
1918
  const settings = {
1894
1919
  telemetry: { target: ServerConfig.TelemetryTarget.GCP },
1895
1920
  };
1896
- await expect(loadCliConfig(settings, [], 'test-session', argv)).rejects.toThrow(/Invalid telemetry configuration: .*Invalid telemetry target/i);
1921
+ await expect(loadCliConfig(settings, 'test-session', argv)).rejects.toThrow(/Invalid telemetry configuration: .*Invalid telemetry target/i);
1897
1922
  vi.unstubAllEnvs();
1898
1923
  });
1899
1924
  it('should prioritize GEMINI_TELEMETRY_OTLP_ENDPOINT over settings and default env var', async () => {
@@ -1904,7 +1929,7 @@ describe('Telemetry configuration via environment variables', () => {
1904
1929
  const settings = {
1905
1930
  telemetry: { otlpEndpoint: 'http://settings.com' },
1906
1931
  };
1907
- const config = await loadCliConfig(settings, [], 'test-session', argv);
1932
+ const config = await loadCliConfig(settings, 'test-session', argv);
1908
1933
  expect(config.getTelemetryOtlpEndpoint()).toBe('http://gemini.env.com');
1909
1934
  });
1910
1935
  it('should prioritize GEMINI_TELEMETRY_OTLP_PROTOCOL over settings', async () => {
@@ -1912,7 +1937,7 @@ describe('Telemetry configuration via environment variables', () => {
1912
1937
  process.argv = ['node', 'script.js'];
1913
1938
  const argv = await parseArguments({});
1914
1939
  const settings = { telemetry: { otlpProtocol: 'grpc' } };
1915
- const config = await loadCliConfig(settings, [], 'test-session', argv);
1940
+ const config = await loadCliConfig(settings, 'test-session', argv);
1916
1941
  expect(config.getTelemetryOtlpProtocol()).toBe('http');
1917
1942
  });
1918
1943
  it('should prioritize GEMINI_TELEMETRY_LOG_PROMPTS over settings', async () => {
@@ -1920,7 +1945,7 @@ describe('Telemetry configuration via environment variables', () => {
1920
1945
  process.argv = ['node', 'script.js'];
1921
1946
  const argv = await parseArguments({});
1922
1947
  const settings = { telemetry: { logPrompts: true } };
1923
- const config = await loadCliConfig(settings, [], 'test-session', argv);
1948
+ const config = await loadCliConfig(settings, 'test-session', argv);
1924
1949
  expect(config.getTelemetryLogPromptsEnabled()).toBe(false);
1925
1950
  });
1926
1951
  it('should prioritize GEMINI_TELEMETRY_OUTFILE over settings', async () => {
@@ -1930,7 +1955,7 @@ describe('Telemetry configuration via environment variables', () => {
1930
1955
  const settings = {
1931
1956
  telemetry: { outfile: '/settings/telemetry.log' },
1932
1957
  };
1933
- const config = await loadCliConfig(settings, [], 'test-session', argv);
1958
+ const config = await loadCliConfig(settings, 'test-session', argv);
1934
1959
  expect(config.getTelemetryOutfile()).toBe('/gemini/env/telemetry.log');
1935
1960
  });
1936
1961
  it('should prioritize GEMINI_TELEMETRY_USE_COLLECTOR over settings', async () => {
@@ -1938,7 +1963,7 @@ describe('Telemetry configuration via environment variables', () => {
1938
1963
  process.argv = ['node', 'script.js'];
1939
1964
  const argv = await parseArguments({});
1940
1965
  const settings = { telemetry: { useCollector: false } };
1941
- const config = await loadCliConfig(settings, [], 'test-session', argv);
1966
+ const config = await loadCliConfig(settings, 'test-session', argv);
1942
1967
  expect(config.getTelemetryUseCollector()).toBe(true);
1943
1968
  });
1944
1969
  it('should use settings value when GEMINI_TELEMETRY_ENABLED is not set', async () => {
@@ -1946,7 +1971,7 @@ describe('Telemetry configuration via environment variables', () => {
1946
1971
  process.argv = ['node', 'script.js'];
1947
1972
  const argv = await parseArguments({});
1948
1973
  const settings = { telemetry: { enabled: true } };
1949
- const config = await loadCliConfig(settings, [], 'test-session', argv);
1974
+ const config = await loadCliConfig(settings, 'test-session', argv);
1950
1975
  expect(config.getTelemetryEnabled()).toBe(true);
1951
1976
  });
1952
1977
  it('should use settings value when GEMINI_TELEMETRY_TARGET is not set', async () => {
@@ -1956,35 +1981,35 @@ describe('Telemetry configuration via environment variables', () => {
1956
1981
  const settings = {
1957
1982
  telemetry: { target: ServerConfig.TelemetryTarget.LOCAL },
1958
1983
  };
1959
- const config = await loadCliConfig(settings, [], 'test-session', argv);
1984
+ const config = await loadCliConfig(settings, 'test-session', argv);
1960
1985
  expect(config.getTelemetryTarget()).toBe('local');
1961
1986
  });
1962
1987
  it("should treat GEMINI_TELEMETRY_ENABLED='1' as true", async () => {
1963
1988
  vi.stubEnv('GEMINI_TELEMETRY_ENABLED', '1');
1964
1989
  process.argv = ['node', 'script.js'];
1965
1990
  const argv = await parseArguments({});
1966
- const config = await loadCliConfig({}, [], 'test-session', argv);
1991
+ const config = await loadCliConfig({}, 'test-session', argv);
1967
1992
  expect(config.getTelemetryEnabled()).toBe(true);
1968
1993
  });
1969
1994
  it("should treat GEMINI_TELEMETRY_ENABLED='0' as false", async () => {
1970
1995
  vi.stubEnv('GEMINI_TELEMETRY_ENABLED', '0');
1971
1996
  process.argv = ['node', 'script.js'];
1972
1997
  const argv = await parseArguments({});
1973
- const config = await loadCliConfig({ telemetry: { enabled: true } }, [], 'test-session', argv);
1998
+ const config = await loadCliConfig({ telemetry: { enabled: true } }, 'test-session', argv);
1974
1999
  expect(config.getTelemetryEnabled()).toBe(false);
1975
2000
  });
1976
2001
  it("should treat GEMINI_TELEMETRY_LOG_PROMPTS='1' as true", async () => {
1977
2002
  vi.stubEnv('GEMINI_TELEMETRY_LOG_PROMPTS', '1');
1978
2003
  process.argv = ['node', 'script.js'];
1979
2004
  const argv = await parseArguments({});
1980
- const config = await loadCliConfig({}, [], 'test-session', argv);
2005
+ const config = await loadCliConfig({}, 'test-session', argv);
1981
2006
  expect(config.getTelemetryLogPromptsEnabled()).toBe(true);
1982
2007
  });
1983
2008
  it("should treat GEMINI_TELEMETRY_LOG_PROMPTS='false' as false", async () => {
1984
2009
  vi.stubEnv('GEMINI_TELEMETRY_LOG_PROMPTS', 'false');
1985
2010
  process.argv = ['node', 'script.js'];
1986
2011
  const argv = await parseArguments({});
1987
- const config = await loadCliConfig({ telemetry: { logPrompts: true } }, [], 'test-session', argv);
2012
+ const config = await loadCliConfig({ telemetry: { logPrompts: true } }, 'test-session', argv);
1988
2013
  expect(config.getTelemetryLogPromptsEnabled()).toBe(false);
1989
2014
  });
1990
2015
  });