@google/gemini-cli 0.24.0-nightly.20251231.05049b5ab → 0.24.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 (218) hide show
  1. package/dist/package.json +2 -2
  2. package/dist/src/commands/extensions/settings.js +4 -0
  3. package/dist/src/commands/extensions/settings.js.map +1 -1
  4. package/dist/src/commands/extensions/settings.test.d.ts +6 -0
  5. package/dist/src/commands/extensions/settings.test.js +170 -0
  6. package/dist/src/commands/extensions/settings.test.js.map +1 -0
  7. package/dist/src/commands/hooks/migrate.js +1 -1
  8. package/dist/src/commands/hooks/migrate.js.map +1 -1
  9. package/dist/src/commands/hooks/migrate.test.js +1 -1
  10. package/dist/src/commands/hooks/migrate.test.js.map +1 -1
  11. package/dist/src/commands/skills/disable.d.ts +14 -0
  12. package/dist/src/commands/skills/disable.js +47 -0
  13. package/dist/src/commands/skills/disable.js.map +1 -0
  14. package/dist/src/commands/skills/disable.test.d.ts +6 -0
  15. package/dist/src/commands/skills/disable.test.js +80 -0
  16. package/dist/src/commands/skills/disable.test.js.map +1 -0
  17. package/dist/src/commands/skills/enable.d.ts +14 -0
  18. package/dist/src/commands/skills/enable.js +47 -0
  19. package/dist/src/commands/skills/enable.js.map +1 -0
  20. package/dist/src/commands/skills/enable.test.d.ts +6 -0
  21. package/dist/src/commands/skills/enable.test.js +80 -0
  22. package/dist/src/commands/skills/enable.test.js.map +1 -0
  23. package/dist/src/commands/skills/list.d.ts +8 -0
  24. package/dist/src/commands/skills/list.js +46 -0
  25. package/dist/src/commands/skills/list.js.map +1 -0
  26. package/dist/src/commands/skills/list.test.d.ts +6 -0
  27. package/dist/src/commands/skills/list.test.js +102 -0
  28. package/dist/src/commands/skills/list.test.js.map +1 -0
  29. package/dist/src/commands/skills.d.ts +7 -0
  30. package/dist/src/commands/skills.js +26 -0
  31. package/dist/src/commands/skills.js.map +1 -0
  32. package/dist/src/commands/skills.test.d.ts +6 -0
  33. package/dist/src/commands/skills.test.js +49 -0
  34. package/dist/src/commands/skills.test.js.map +1 -0
  35. package/dist/src/config/config.d.ts +0 -1
  36. package/dist/src/config/config.js +57 -22
  37. package/dist/src/config/config.js.map +1 -1
  38. package/dist/src/config/config.test.js +187 -1
  39. package/dist/src/config/config.test.js.map +1 -1
  40. package/dist/src/config/extension-manager-skills.test.d.ts +6 -0
  41. package/dist/src/config/extension-manager-skills.test.js +98 -0
  42. package/dist/src/config/extension-manager-skills.test.js.map +1 -0
  43. package/dist/src/config/extension-manager.js +27 -17
  44. package/dist/src/config/extension-manager.js.map +1 -1
  45. package/dist/src/config/extension.test.js +16 -10
  46. package/dist/src/config/extension.test.js.map +1 -1
  47. package/dist/src/config/extensions/consent.d.ts +5 -3
  48. package/dist/src/config/extensions/consent.js +30 -7
  49. package/dist/src/config/extensions/consent.js.map +1 -1
  50. package/dist/src/config/extensions/consent.test.js +97 -3
  51. package/dist/src/config/extensions/consent.test.js.map +1 -1
  52. package/dist/src/config/extensions/extensionSettings.d.ts +1 -0
  53. package/dist/src/config/extensions/extensionSettings.js +14 -0
  54. package/dist/src/config/extensions/extensionSettings.js.map +1 -1
  55. package/dist/src/config/extensions/extensionUpdates.test.d.ts +6 -0
  56. package/dist/src/config/extensions/extensionUpdates.test.js +243 -0
  57. package/dist/src/config/extensions/extensionUpdates.test.js.map +1 -0
  58. package/dist/src/config/settings.d.ts +2 -1
  59. package/dist/src/config/settings.js +25 -6
  60. package/dist/src/config/settings.js.map +1 -1
  61. package/dist/src/config/settings.test.js +86 -28
  62. package/dist/src/config/settings.test.js.map +1 -1
  63. package/dist/src/config/settingsSchema.d.ts +99 -14
  64. package/dist/src/config/settingsSchema.js +101 -14
  65. package/dist/src/config/settingsSchema.js.map +1 -1
  66. package/dist/src/config/settingsSchema.test.js +8 -0
  67. package/dist/src/config/settingsSchema.test.js.map +1 -1
  68. package/dist/src/gemini.js +22 -9
  69. package/dist/src/gemini.js.map +1 -1
  70. package/dist/src/gemini.test.js +0 -1
  71. package/dist/src/gemini.test.js.map +1 -1
  72. package/dist/src/generated/git-commit.d.ts +3 -3
  73. package/dist/src/generated/git-commit.js +3 -3
  74. package/dist/src/generated/git-commit.js.map +1 -1
  75. package/dist/src/nonInteractiveCli.js +24 -0
  76. package/dist/src/nonInteractiveCli.js.map +1 -1
  77. package/dist/src/nonInteractiveCli.test.js +44 -0
  78. package/dist/src/nonInteractiveCli.test.js.map +1 -1
  79. package/dist/src/services/BuiltinCommandLoader.d.ts +1 -1
  80. package/dist/src/services/BuiltinCommandLoader.js +17 -1
  81. package/dist/src/services/BuiltinCommandLoader.js.map +1 -1
  82. package/dist/src/services/BuiltinCommandLoader.test.js +3 -0
  83. package/dist/src/services/BuiltinCommandLoader.test.js.map +1 -1
  84. package/dist/src/ui/AppContainer.js +41 -8
  85. package/dist/src/ui/AppContainer.js.map +1 -1
  86. package/dist/src/ui/AppContainer.test.js +16 -0
  87. package/dist/src/ui/AppContainer.test.js.map +1 -1
  88. package/dist/src/ui/commands/clearCommand.js +9 -1
  89. package/dist/src/ui/commands/clearCommand.js.map +1 -1
  90. package/dist/src/ui/commands/directoryCommand.js +18 -1
  91. package/dist/src/ui/commands/directoryCommand.js.map +1 -1
  92. package/dist/src/ui/commands/directoryCommand.test.js +38 -2
  93. package/dist/src/ui/commands/directoryCommand.test.js.map +1 -1
  94. package/dist/src/ui/commands/hooksCommand.js +1 -1
  95. package/dist/src/ui/commands/hooksCommand.js.map +1 -1
  96. package/dist/src/ui/commands/hooksCommand.test.js +1 -1
  97. package/dist/src/ui/commands/hooksCommand.test.js.map +1 -1
  98. package/dist/src/ui/commands/mcpCommand.test.js +10 -2
  99. package/dist/src/ui/commands/mcpCommand.test.js.map +1 -1
  100. package/dist/src/ui/commands/skillsCommand.d.ts +1 -1
  101. package/dist/src/ui/commands/skillsCommand.js +79 -5
  102. package/dist/src/ui/commands/skillsCommand.js.map +1 -1
  103. package/dist/src/ui/commands/skillsCommand.test.d.ts +1 -1
  104. package/dist/src/ui/commands/skillsCommand.test.js +146 -6
  105. package/dist/src/ui/commands/skillsCommand.test.js.map +1 -1
  106. package/dist/src/ui/commands/types.d.ts +5 -0
  107. package/dist/src/ui/components/Composer.js +4 -6
  108. package/dist/src/ui/components/Composer.js.map +1 -1
  109. package/dist/src/ui/components/Composer.test.js +22 -4
  110. package/dist/src/ui/components/Composer.test.js.map +1 -1
  111. package/dist/src/ui/components/ContextSummaryDisplay.d.ts +1 -0
  112. package/dist/src/ui/components/ContextSummaryDisplay.js +12 -5
  113. package/dist/src/ui/components/ContextSummaryDisplay.js.map +1 -1
  114. package/dist/src/ui/components/ContextSummaryDisplay.test.js +56 -25
  115. package/dist/src/ui/components/ContextSummaryDisplay.test.js.map +1 -1
  116. package/dist/src/ui/components/FolderTrustDialog.js +19 -14
  117. package/dist/src/ui/components/FolderTrustDialog.js.map +1 -1
  118. package/dist/src/ui/components/FolderTrustDialog.test.js +12 -2
  119. package/dist/src/ui/components/FolderTrustDialog.test.js.map +1 -1
  120. package/dist/src/ui/components/Footer.js +4 -4
  121. package/dist/src/ui/components/Footer.js.map +1 -1
  122. package/dist/src/ui/components/HookStatusDisplay.d.ts +12 -0
  123. package/dist/src/ui/components/HookStatusDisplay.js +20 -0
  124. package/dist/src/ui/components/HookStatusDisplay.js.map +1 -0
  125. package/dist/src/ui/components/HookStatusDisplay.test.d.ts +6 -0
  126. package/dist/src/ui/components/HookStatusDisplay.test.js +51 -0
  127. package/dist/src/ui/components/HookStatusDisplay.test.js.map +1 -0
  128. package/dist/src/ui/components/InputPrompt.js +14 -6
  129. package/dist/src/ui/components/InputPrompt.js.map +1 -1
  130. package/dist/src/ui/components/InputPrompt.test.js +21 -2
  131. package/dist/src/ui/components/InputPrompt.test.js.map +1 -1
  132. package/dist/src/ui/components/ModelDialog.js +7 -3
  133. package/dist/src/ui/components/ModelDialog.js.map +1 -1
  134. package/dist/src/ui/components/ModelDialog.test.js +16 -3
  135. package/dist/src/ui/components/ModelDialog.test.js.map +1 -1
  136. package/dist/src/ui/components/SettingsDialog.js +33 -13
  137. package/dist/src/ui/components/SettingsDialog.js.map +1 -1
  138. package/dist/src/ui/components/SettingsDialog.test.js +16 -0
  139. package/dist/src/ui/components/SettingsDialog.test.js.map +1 -1
  140. package/dist/src/ui/components/StatusDisplay.d.ts +11 -0
  141. package/dist/src/ui/components/StatusDisplay.js +40 -0
  142. package/dist/src/ui/components/StatusDisplay.js.map +1 -0
  143. package/dist/src/ui/components/StatusDisplay.test.d.ts +6 -0
  144. package/dist/src/ui/components/StatusDisplay.test.js +143 -0
  145. package/dist/src/ui/components/StatusDisplay.test.js.map +1 -0
  146. package/dist/src/ui/components/views/SkillsList.test.js +22 -4
  147. package/dist/src/ui/components/views/SkillsList.test.js.map +1 -1
  148. package/dist/src/ui/constants/tips.js +0 -1
  149. package/dist/src/ui/constants/tips.js.map +1 -1
  150. package/dist/src/ui/constants.d.ts +2 -0
  151. package/dist/src/ui/constants.js +2 -0
  152. package/dist/src/ui/constants.js.map +1 -1
  153. package/dist/src/ui/contexts/KeypressContext.d.ts +1 -0
  154. package/dist/src/ui/contexts/KeypressContext.js +79 -6
  155. package/dist/src/ui/contexts/KeypressContext.js.map +1 -1
  156. package/dist/src/ui/contexts/KeypressContext.test.js +71 -0
  157. package/dist/src/ui/contexts/KeypressContext.test.js.map +1 -1
  158. package/dist/src/ui/contexts/UIStateContext.d.ts +3 -1
  159. package/dist/src/ui/contexts/UIStateContext.js.map +1 -1
  160. package/dist/src/ui/hooks/atCommandProcessor.js +1 -1
  161. package/dist/src/ui/hooks/atCommandProcessor.js.map +1 -1
  162. package/dist/src/ui/hooks/atCommandProcessor.test.js +9 -3
  163. package/dist/src/ui/hooks/atCommandProcessor.test.js.map +1 -1
  164. package/dist/src/ui/hooks/useFolderTrust.js +14 -19
  165. package/dist/src/ui/hooks/useFolderTrust.js.map +1 -1
  166. package/dist/src/ui/hooks/useFolderTrust.test.js +30 -22
  167. package/dist/src/ui/hooks/useFolderTrust.test.js.map +1 -1
  168. package/dist/src/ui/hooks/useGeminiStream.js +29 -0
  169. package/dist/src/ui/hooks/useGeminiStream.js.map +1 -1
  170. package/dist/src/ui/hooks/useGeminiStream.test.js +39 -1
  171. package/dist/src/ui/hooks/useGeminiStream.test.js.map +1 -1
  172. package/dist/src/ui/hooks/useHookDisplayState.d.ts +7 -0
  173. package/dist/src/ui/hooks/useHookDisplayState.js +83 -0
  174. package/dist/src/ui/hooks/useHookDisplayState.js.map +1 -0
  175. package/dist/src/ui/hooks/useHookDisplayState.test.d.ts +6 -0
  176. package/dist/src/ui/hooks/useHookDisplayState.test.js +180 -0
  177. package/dist/src/ui/hooks/useHookDisplayState.test.js.map +1 -0
  178. package/dist/src/ui/hooks/useQuotaAndFallback.js +1 -1
  179. package/dist/src/ui/hooks/useQuotaAndFallback.js.map +1 -1
  180. package/dist/src/ui/hooks/useSlashCompletion.js +4 -1
  181. package/dist/src/ui/hooks/useSlashCompletion.js.map +1 -1
  182. package/dist/src/ui/hooks/useToolScheduler.test.js +2 -2
  183. package/dist/src/ui/hooks/useToolScheduler.test.js.map +1 -1
  184. package/dist/src/ui/types.d.ts +8 -7
  185. package/dist/src/ui/types.js.map +1 -1
  186. package/dist/src/ui/utils/commandUtils.js +12 -7
  187. package/dist/src/ui/utils/commandUtils.js.map +1 -1
  188. package/dist/src/ui/utils/commandUtils.test.js +24 -0
  189. package/dist/src/ui/utils/commandUtils.test.js.map +1 -1
  190. package/dist/src/ui/utils/directoryUtils.d.ts +8 -0
  191. package/dist/src/ui/utils/directoryUtils.js +92 -0
  192. package/dist/src/ui/utils/directoryUtils.js.map +1 -1
  193. package/dist/src/ui/utils/directoryUtils.test.js +189 -2
  194. package/dist/src/ui/utils/directoryUtils.test.js.map +1 -1
  195. package/dist/src/ui/utils/terminalCapabilityManager.d.ts +7 -4
  196. package/dist/src/ui/utils/terminalCapabilityManager.js +61 -66
  197. package/dist/src/ui/utils/terminalCapabilityManager.js.map +1 -1
  198. package/dist/src/ui/utils/terminalCapabilityManager.test.js +35 -0
  199. package/dist/src/ui/utils/terminalCapabilityManager.test.js.map +1 -1
  200. package/dist/src/ui/utils/ui-sizing.js +1 -1
  201. package/dist/src/ui/utils/ui-sizing.js.map +1 -1
  202. package/dist/src/ui/utils/ui-sizing.test.js +2 -2
  203. package/dist/src/ui/utils/ui-sizing.test.js.map +1 -1
  204. package/dist/src/utils/settingsUtils.js +0 -5
  205. package/dist/src/utils/settingsUtils.js.map +1 -1
  206. package/dist/src/zed-integration/zedIntegration.js +1 -1
  207. package/dist/src/zed-integration/zedIntegration.js.map +1 -1
  208. package/dist/src/zed-integration/zedIntegration.test.js +12 -0
  209. package/dist/src/zed-integration/zedIntegration.test.js.map +1 -1
  210. package/dist/tsconfig.tsbuildinfo +1 -1
  211. package/package.json +3 -3
  212. package/dist/google-gemini-cli-0.24.0-nightly.20251227.37be16243.tgz +0 -0
  213. package/dist/src/ui/hooks/useBracketedPaste.d.ts +0 -12
  214. package/dist/src/ui/hooks/useBracketedPaste.js +0 -31
  215. package/dist/src/ui/hooks/useBracketedPaste.js.map +0 -1
  216. package/dist/src/ui/utils/bracketedPaste.d.ts +0 -7
  217. package/dist/src/ui/utils/bracketedPaste.js +0 -15
  218. package/dist/src/ui/utils/bracketedPaste.js.map +0 -1
@@ -0,0 +1,80 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import { vi, describe, it, expect, beforeEach, afterEach } from 'vitest';
7
+ import { format } from 'node:util';
8
+ import { handleEnable, enableCommand } from './enable.js';
9
+ import { loadSettings, SettingScope, } from '../../config/settings.js';
10
+ const emitConsoleLog = vi.hoisted(() => vi.fn());
11
+ const debugLogger = vi.hoisted(() => ({
12
+ log: vi.fn((message, ...args) => {
13
+ emitConsoleLog('log', format(message, ...args));
14
+ }),
15
+ }));
16
+ vi.mock('@google/gemini-cli-core', async (importOriginal) => {
17
+ const actual = await importOriginal();
18
+ return {
19
+ ...actual,
20
+ debugLogger,
21
+ };
22
+ });
23
+ vi.mock('../../config/settings.js', async (importOriginal) => {
24
+ const actual = await importOriginal();
25
+ return {
26
+ ...actual,
27
+ loadSettings: vi.fn(),
28
+ };
29
+ });
30
+ vi.mock('../utils.js', () => ({
31
+ exitCli: vi.fn(),
32
+ }));
33
+ describe('skills enable command', () => {
34
+ const mockLoadSettings = vi.mocked(loadSettings);
35
+ beforeEach(() => {
36
+ vi.clearAllMocks();
37
+ });
38
+ afterEach(() => {
39
+ vi.restoreAllMocks();
40
+ });
41
+ describe('handleEnable', () => {
42
+ it('should enable a disabled skill in user scope', async () => {
43
+ const mockSettings = {
44
+ forScope: vi.fn().mockReturnValue({
45
+ settings: { skills: { disabled: ['skill1'] } },
46
+ }),
47
+ setValue: vi.fn(),
48
+ };
49
+ mockLoadSettings.mockReturnValue(mockSettings);
50
+ await handleEnable({
51
+ name: 'skill1',
52
+ scope: SettingScope.User,
53
+ });
54
+ expect(mockSettings.setValue).toHaveBeenCalledWith(SettingScope.User, 'skills.disabled', []);
55
+ expect(emitConsoleLog).toHaveBeenCalledWith('log', 'Skill "skill1" successfully enabled in scope "User".');
56
+ });
57
+ it('should log a message if the skill is already enabled', async () => {
58
+ const mockSettings = {
59
+ forScope: vi.fn().mockReturnValue({
60
+ settings: { skills: { disabled: [] } },
61
+ }),
62
+ setValue: vi.fn(),
63
+ };
64
+ mockLoadSettings.mockReturnValue(mockSettings);
65
+ await handleEnable({
66
+ name: 'skill1',
67
+ scope: SettingScope.User,
68
+ });
69
+ expect(mockSettings.setValue).not.toHaveBeenCalled();
70
+ expect(emitConsoleLog).toHaveBeenCalledWith('log', 'Skill "skill1" is already enabled in scope "User".');
71
+ });
72
+ });
73
+ describe('enableCommand', () => {
74
+ it('should have correct command and describe', () => {
75
+ expect(enableCommand.command).toBe('enable <name>');
76
+ expect(enableCommand.describe).toBe('Enables an agent skill.');
77
+ });
78
+ });
79
+ });
80
+ //# sourceMappingURL=enable.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"enable.test.js","sourceRoot":"","sources":["../../../../src/commands/skills/enable.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import type { CommandModule } from 'yargs';
7
+ export declare function handleList(): Promise<void>;
8
+ export declare const listCommand: CommandModule;
@@ -0,0 +1,46 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import { debugLogger } from '@google/gemini-cli-core';
7
+ import { loadSettings } from '../../config/settings.js';
8
+ import { loadCliConfig } from '../../config/config.js';
9
+ import { exitCli } from '../utils.js';
10
+ import chalk from 'chalk';
11
+ export async function handleList() {
12
+ const workspaceDir = process.cwd();
13
+ const settings = loadSettings(workspaceDir);
14
+ const config = await loadCliConfig(settings.merged, 'skills-list-session', {
15
+ debug: false,
16
+ }, { cwd: workspaceDir });
17
+ // Initialize to trigger extension loading and skill discovery
18
+ await config.initialize();
19
+ const skillManager = config.getSkillManager();
20
+ const skills = skillManager.getAllSkills();
21
+ if (skills.length === 0) {
22
+ debugLogger.log('No skills discovered.');
23
+ return;
24
+ }
25
+ debugLogger.log(chalk.bold('Discovered Agent Skills:'));
26
+ debugLogger.log('');
27
+ for (const skill of skills) {
28
+ const status = skill.disabled
29
+ ? chalk.red('[Disabled]')
30
+ : chalk.green('[Enabled]');
31
+ debugLogger.log(`${chalk.bold(skill.name)} ${status}`);
32
+ debugLogger.log(` Description: ${skill.description}`);
33
+ debugLogger.log(` Location: ${skill.location}`);
34
+ debugLogger.log('');
35
+ }
36
+ }
37
+ export const listCommand = {
38
+ command: 'list',
39
+ describe: 'Lists discovered agent skills.',
40
+ builder: (yargs) => yargs,
41
+ handler: async () => {
42
+ await handleList();
43
+ await exitCli();
44
+ },
45
+ };
46
+ //# sourceMappingURL=list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.js","sourceRoot":"","sources":["../../../../src/commands/skills/list.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,aAAa,EAAgB,MAAM,wBAAwB,CAAC;AACrE,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACtC,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,MAAM,CAAC,KAAK,UAAU,UAAU;IAC9B,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IACnC,MAAM,QAAQ,GAAG,YAAY,CAAC,YAAY,CAAC,CAAC;IAE5C,MAAM,MAAM,GAAG,MAAM,aAAa,CAChC,QAAQ,CAAC,MAAM,EACf,qBAAqB,EACrB;QACE,KAAK,EAAE,KAAK;KACkB,EAChC,EAAE,GAAG,EAAE,YAAY,EAAE,CACtB,CAAC;IAEF,8DAA8D;IAC9D,MAAM,MAAM,CAAC,UAAU,EAAE,CAAC;IAE1B,MAAM,YAAY,GAAG,MAAM,CAAC,eAAe,EAAE,CAAC;IAC9C,MAAM,MAAM,GAAG,YAAY,CAAC,YAAY,EAAE,CAAC;IAE3C,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,WAAW,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;QACzC,OAAO;IACT,CAAC;IAED,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC,CAAC;IACxD,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAEpB,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,MAAM,GAAG,KAAK,CAAC,QAAQ;YAC3B,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,YAAY,CAAC;YACzB,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;QAE7B,WAAW,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,MAAM,EAAE,CAAC,CAAC;QACvD,WAAW,CAAC,GAAG,CAAC,kBAAkB,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC;QACvD,WAAW,CAAC,GAAG,CAAC,kBAAkB,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC;QACpD,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACtB,CAAC;AACH,CAAC;AAED,MAAM,CAAC,MAAM,WAAW,GAAkB;IACxC,OAAO,EAAE,MAAM;IACf,QAAQ,EAAE,gCAAgC;IAC1C,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK;IACzB,OAAO,EAAE,KAAK,IAAI,EAAE;QAClB,MAAM,UAAU,EAAE,CAAC;QACnB,MAAM,OAAO,EAAE,CAAC;IAClB,CAAC;CACF,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ export {};
@@ -0,0 +1,102 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import { vi, describe, it, expect, beforeEach, afterEach } from 'vitest';
7
+ import { format } from 'node:util';
8
+ import { handleList, listCommand } from './list.js';
9
+ import { loadSettings } from '../../config/settings.js';
10
+ import { loadCliConfig } from '../../config/config.js';
11
+ import chalk from 'chalk';
12
+ const emitConsoleLog = vi.hoisted(() => vi.fn());
13
+ const debugLogger = vi.hoisted(() => ({
14
+ log: vi.fn((message, ...args) => {
15
+ emitConsoleLog('log', format(message, ...args));
16
+ }),
17
+ error: vi.fn((message, ...args) => {
18
+ emitConsoleLog('error', format(message, ...args));
19
+ }),
20
+ }));
21
+ vi.mock('@google/gemini-cli-core', async (importOriginal) => {
22
+ const actual = await importOriginal();
23
+ return {
24
+ ...actual,
25
+ coreEvents: {
26
+ emitConsoleLog,
27
+ },
28
+ debugLogger,
29
+ };
30
+ });
31
+ vi.mock('../../config/settings.js');
32
+ vi.mock('../../config/config.js');
33
+ vi.mock('../utils.js', () => ({
34
+ exitCli: vi.fn(),
35
+ }));
36
+ describe('skills list command', () => {
37
+ const mockLoadSettings = vi.mocked(loadSettings);
38
+ const mockLoadCliConfig = vi.mocked(loadCliConfig);
39
+ beforeEach(async () => {
40
+ vi.clearAllMocks();
41
+ mockLoadSettings.mockReturnValue({
42
+ merged: {},
43
+ });
44
+ });
45
+ afterEach(() => {
46
+ vi.restoreAllMocks();
47
+ });
48
+ describe('handleList', () => {
49
+ it('should log a message if no skills are discovered', async () => {
50
+ const mockConfig = {
51
+ initialize: vi.fn().mockResolvedValue(undefined),
52
+ getSkillManager: vi.fn().mockReturnValue({
53
+ getAllSkills: vi.fn().mockReturnValue([]),
54
+ }),
55
+ };
56
+ mockLoadCliConfig.mockResolvedValue(mockConfig);
57
+ await handleList();
58
+ expect(emitConsoleLog).toHaveBeenCalledWith('log', 'No skills discovered.');
59
+ });
60
+ it('should list all discovered skills', async () => {
61
+ const skills = [
62
+ {
63
+ name: 'skill1',
64
+ description: 'desc1',
65
+ disabled: false,
66
+ location: '/path/to/skill1',
67
+ },
68
+ {
69
+ name: 'skill2',
70
+ description: 'desc2',
71
+ disabled: true,
72
+ location: '/path/to/skill2',
73
+ },
74
+ ];
75
+ const mockConfig = {
76
+ initialize: vi.fn().mockResolvedValue(undefined),
77
+ getSkillManager: vi.fn().mockReturnValue({
78
+ getAllSkills: vi.fn().mockReturnValue(skills),
79
+ }),
80
+ };
81
+ mockLoadCliConfig.mockResolvedValue(mockConfig);
82
+ await handleList();
83
+ expect(emitConsoleLog).toHaveBeenCalledWith('log', chalk.bold('Discovered Agent Skills:'));
84
+ expect(emitConsoleLog).toHaveBeenCalledWith('log', expect.stringContaining('skill1'));
85
+ expect(emitConsoleLog).toHaveBeenCalledWith('log', expect.stringContaining(chalk.green('[Enabled]')));
86
+ expect(emitConsoleLog).toHaveBeenCalledWith('log', expect.stringContaining('skill2'));
87
+ expect(emitConsoleLog).toHaveBeenCalledWith('log', expect.stringContaining(chalk.red('[Disabled]')));
88
+ });
89
+ it('should throw an error when listing fails', async () => {
90
+ mockLoadCliConfig.mockRejectedValue(new Error('List failed'));
91
+ await expect(handleList()).rejects.toThrow('List failed');
92
+ });
93
+ });
94
+ describe('listCommand', () => {
95
+ const command = listCommand;
96
+ it('should have correct command and describe', () => {
97
+ expect(command.command).toBe('list');
98
+ expect(command.describe).toBe('Lists discovered agent skills.');
99
+ });
100
+ });
101
+ });
102
+ //# sourceMappingURL=list.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.test.js","sourceRoot":"","sources":["../../../../src/commands/skills/list.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import type { CommandModule } from 'yargs';
7
+ export declare const skillsCommand: CommandModule;
@@ -0,0 +1,26 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import { listCommand } from './skills/list.js';
7
+ import { enableCommand } from './skills/enable.js';
8
+ import { disableCommand } from './skills/disable.js';
9
+ import { initializeOutputListenersAndFlush } from '../gemini.js';
10
+ export const skillsCommand = {
11
+ command: 'skills <command>',
12
+ aliases: ['skill'],
13
+ describe: 'Manage agent skills.',
14
+ builder: (yargs) => yargs
15
+ .middleware(() => initializeOutputListenersAndFlush())
16
+ .command(listCommand)
17
+ .command(enableCommand)
18
+ .command(disableCommand)
19
+ .demandCommand(1, 'You need at least one command before continuing.')
20
+ .version(false),
21
+ handler: () => {
22
+ // This handler is not called when a subcommand is provided.
23
+ // Yargs will show the help menu.
24
+ },
25
+ };
26
+ //# sourceMappingURL=skills.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skills.js","sourceRoot":"","sources":["../../../src/commands/skills.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,iCAAiC,EAAE,MAAM,cAAc,CAAC;AAEjE,MAAM,CAAC,MAAM,aAAa,GAAkB;IAC1C,OAAO,EAAE,kBAAkB;IAC3B,OAAO,EAAE,CAAC,OAAO,CAAC;IAClB,QAAQ,EAAE,sBAAsB;IAChC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE,CACjB,KAAK;SACF,UAAU,CAAC,GAAG,EAAE,CAAC,iCAAiC,EAAE,CAAC;SACrD,OAAO,CAAC,WAAW,CAAC;SACpB,OAAO,CAAC,aAAa,CAAC;SACtB,OAAO,CAAC,cAAc,CAAC;SACvB,aAAa,CAAC,CAAC,EAAE,kDAAkD,CAAC;SACpE,OAAO,CAAC,KAAK,CAAC;IACnB,OAAO,EAAE,GAAG,EAAE;QACZ,4DAA4D;QAC5D,iCAAiC;IACnC,CAAC;CACF,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ export {};
@@ -0,0 +1,49 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import { describe, it, expect, vi } from 'vitest';
7
+ import { skillsCommand } from './skills.js';
8
+ vi.mock('./skills/list.js', () => ({ listCommand: { command: 'list' } }));
9
+ vi.mock('./skills/enable.js', () => ({
10
+ enableCommand: { command: 'enable <name>' },
11
+ }));
12
+ vi.mock('./skills/disable.js', () => ({
13
+ disableCommand: { command: 'disable <name>' },
14
+ }));
15
+ vi.mock('../gemini.js', () => ({
16
+ initializeOutputListenersAndFlush: vi.fn(),
17
+ }));
18
+ describe('skillsCommand', () => {
19
+ it('should have correct command and aliases', () => {
20
+ expect(skillsCommand.command).toBe('skills <command>');
21
+ expect(skillsCommand.aliases).toEqual(['skill']);
22
+ expect(skillsCommand.describe).toBe('Manage agent skills.');
23
+ });
24
+ it('should register all subcommands in builder', () => {
25
+ const mockYargs = {
26
+ middleware: vi.fn().mockReturnThis(),
27
+ command: vi.fn().mockReturnThis(),
28
+ demandCommand: vi.fn().mockReturnThis(),
29
+ version: vi.fn().mockReturnThis(),
30
+ };
31
+ // @ts-expect-error - Mocking yargs
32
+ skillsCommand.builder(mockYargs);
33
+ expect(mockYargs.middleware).toHaveBeenCalled();
34
+ expect(mockYargs.command).toHaveBeenCalledWith({ command: 'list' });
35
+ expect(mockYargs.command).toHaveBeenCalledWith({
36
+ command: 'enable <name>',
37
+ });
38
+ expect(mockYargs.command).toHaveBeenCalledWith({
39
+ command: 'disable <name>',
40
+ });
41
+ expect(mockYargs.demandCommand).toHaveBeenCalledWith(1, expect.any(String));
42
+ expect(mockYargs.version).toHaveBeenCalledWith(false);
43
+ });
44
+ it('should have a handler that does nothing', () => {
45
+ // @ts-expect-error - Handler doesn't take arguments in this case
46
+ expect(skillsCommand.handler()).toBeUndefined();
47
+ });
48
+ });
49
+ //# sourceMappingURL=skills.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skills.test.js","sourceRoot":"","sources":["../../../src/commands/skills.test.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,EAAE,CAAC,IAAI,CAAC,kBAAkB,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,WAAW,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC;AAC1E,EAAE,CAAC,IAAI,CAAC,oBAAoB,EAAE,GAAG,EAAE,CAAC,CAAC;IACnC,aAAa,EAAE,EAAE,OAAO,EAAE,eAAe,EAAE;CAC5C,CAAC,CAAC,CAAC;AACJ,EAAE,CAAC,IAAI,CAAC,qBAAqB,EAAE,GAAG,EAAE,CAAC,CAAC;IACpC,cAAc,EAAE,EAAE,OAAO,EAAE,gBAAgB,EAAE;CAC9C,CAAC,CAAC,CAAC;AAEJ,EAAE,CAAC,IAAI,CAAC,cAAc,EAAE,GAAG,EAAE,CAAC,CAAC;IAC7B,iCAAiC,EAAE,EAAE,CAAC,EAAE,EAAE;CAC3C,CAAC,CAAC,CAAC;AAEJ,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;IAC7B,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;QACjD,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;QACvD,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;QACjD,MAAM,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;IAC9D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACpD,MAAM,SAAS,GAAG;YAChB,UAAU,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,cAAc,EAAE;YACpC,OAAO,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,cAAc,EAAE;YACjC,aAAa,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,cAAc,EAAE;YACvC,OAAO,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,cAAc,EAAE;SAClC,CAAC;QAEF,mCAAmC;QACnC,aAAa,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAEjC,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,gBAAgB,EAAE,CAAC;QAChD,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,oBAAoB,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;QACpE,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,oBAAoB,CAAC;YAC7C,OAAO,EAAE,eAAe;SACzB,CAAC,CAAC;QACH,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,oBAAoB,CAAC;YAC7C,OAAO,EAAE,gBAAgB;SAC1B,CAAC,CAAC;QACH,MAAM,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,oBAAoB,CAAC,CAAC,EAAE,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;QAC5E,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;QACjD,iEAAiE;QACjE,MAAM,CAAC,aAAa,CAAC,OAAO,EAAE,CAAC,CAAC,aAAa,EAAE,CAAC;IAClD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -25,7 +25,6 @@ export interface CliArgs {
25
25
  deleteSession: string | undefined;
26
26
  includeDirectories: string[] | undefined;
27
27
  screenReader: boolean | undefined;
28
- useSmartEdit: boolean | undefined;
29
28
  useWriteTodos: boolean | undefined;
30
29
  outputFormat: string | undefined;
31
30
  fakeResponses: string | undefined;
@@ -8,6 +8,7 @@ import { hideBin } from 'yargs/helpers';
8
8
  import process from 'node:process';
9
9
  import { mcpCommand } from '../commands/mcp.js';
10
10
  import { extensionsCommand } from '../commands/extensions.js';
11
+ import { skillsCommand } from '../commands/skills.js';
11
12
  import { hooksCommand } from '../commands/hooks.js';
12
13
  import { Config, setGeminiMdFilename as setServerGeminiMdFilename, getCurrentGeminiMdFilename, ApprovalMode, DEFAULT_GEMINI_MODEL_AUTO, DEFAULT_GEMINI_EMBEDDING_MODEL, DEFAULT_FILE_FILTERING_OPTIONS, DEFAULT_MEMORY_FILE_FILTERING_OPTIONS, FileDiscoveryService, WRITE_FILE_TOOL_NAME, SHELL_TOOL_NAMES, SHELL_TOOL_NAME, resolveTelemetrySettings, FatalConfigError, getPty, EDIT_TOOL_NAME, debugLogger, loadServerHierarchicalMemory, WEB_FETCH_TOOL_NAME, getVersion, PREVIEW_GEMINI_MODEL_AUTO, } from '@google/gemini-cli-core';
13
14
  import { saveModelChange, loadSettings } from './settings.js';
@@ -21,6 +22,7 @@ import { ExtensionManager } from './extension-manager.js';
21
22
  import { requestConsentNonInteractive } from './extensions/consent.js';
22
23
  import { promptForSetting } from './extensions/extensionSettings.js';
23
24
  import { runExitCleanup } from '../utils/cleanup.js';
25
+ import { getEnableHooks } from './settingsSchema.js';
24
26
  export async function parseArguments(settings) {
25
27
  const rawArgv = hideBin(process.argv);
26
28
  const yargsInstance = yargs(rawArgv)
@@ -199,8 +201,11 @@ export async function parseArguments(settings) {
199
201
  if (settings?.experimental?.extensionManagement ?? true) {
200
202
  yargsInstance.command(extensionsCommand);
201
203
  }
204
+ if (settings?.experimental?.skills ?? false) {
205
+ yargsInstance.command(skillsCommand);
206
+ }
202
207
  // Register hooks command if hooks are enabled
203
- if (settings?.tools?.enableHooks) {
208
+ if (getEnableHooks(settings)) {
204
209
  yargsInstance.command(hooksCommand);
205
210
  }
206
211
  yargsInstance
@@ -287,7 +292,7 @@ export async function loadCliConfig(settings, sessionId, argv, options = {}) {
287
292
  const memoryImportFormat = settings.context?.importFormat || 'tree';
288
293
  const ideMode = settings.ide?.enabled ?? false;
289
294
  const folderTrust = settings.security?.folderTrust?.enabled ?? false;
290
- const trustedFolder = isWorkspaceTrusted(settings)?.isTrusted ?? true;
295
+ const trustedFolder = isWorkspaceTrusted(settings)?.isTrusted ?? false;
291
296
  // Set the context filename in the server's memoryTool module BEFORE loading memory
292
297
  // TODO(b/343434939): This is a bit of a hack. The contextFileName should ideally be passed
293
298
  // directly to the Config constructor in core, and have core handle setGeminiMdFilename.
@@ -356,10 +361,15 @@ export async function loadCliConfig(settings, sessionId, argv, options = {}) {
356
361
  argv.yolo || false ? ApprovalMode.YOLO : ApprovalMode.DEFAULT;
357
362
  }
358
363
  // Override approval mode if disableYoloMode is set.
359
- if (settings.security?.disableYoloMode) {
364
+ if (settings.security?.disableYoloMode || settings.admin?.secureModeEnabled) {
360
365
  if (approvalMode === ApprovalMode.YOLO) {
361
- debugLogger.error('YOLO mode is disabled by the "disableYolo" setting.');
362
- throw new FatalConfigError('Cannot start in YOLO mode when it is disabled by settings');
366
+ if (settings.admin?.secureModeEnabled) {
367
+ debugLogger.error('YOLO mode is disabled by "secureModeEnabled" setting.');
368
+ }
369
+ else {
370
+ debugLogger.error('YOLO mode is disabled by the "disableYolo" setting.');
371
+ }
372
+ throw new FatalConfigError('Cannot start in YOLO mode since it is disabled by your admin');
363
373
  }
364
374
  approvalMode = ApprovalMode.DEFAULT;
365
375
  }
@@ -384,14 +394,13 @@ export async function loadCliConfig(settings, sessionId, argv, options = {}) {
384
394
  }
385
395
  throw err;
386
396
  }
387
- const policyEngineConfig = await createPolicyEngineConfig(settings, approvalMode);
388
- const allowedTools = argv.allowedTools || settings.tools?.allowed || [];
389
- const allowedToolsSet = new Set(allowedTools);
390
397
  // Interactive mode: explicit -i flag or (TTY + no args + no -p flag)
391
398
  const hasQuery = !!argv.query;
392
399
  const interactive = !!argv.promptInteractive ||
393
400
  !!argv.experimentalAcp ||
394
401
  (process.stdin.isTTY && !hasQuery && !argv.prompt);
402
+ const allowedTools = argv.allowedTools || settings.tools?.allowed || [];
403
+ const allowedToolsSet = new Set(allowedTools);
395
404
  // In non-interactive mode, exclude tools that require a prompt.
396
405
  const extraExcludes = [];
397
406
  if (!interactive) {
@@ -421,6 +430,21 @@ export async function loadCliConfig(settings, sessionId, argv, options = {}) {
421
430
  }
422
431
  }
423
432
  const excludeTools = mergeExcludeTools(settings, extraExcludes.length > 0 ? extraExcludes : undefined);
433
+ // Create a settings object that includes CLI overrides for policy generation
434
+ const effectiveSettings = {
435
+ ...settings,
436
+ tools: {
437
+ ...settings.tools,
438
+ allowed: allowedTools,
439
+ exclude: excludeTools,
440
+ },
441
+ mcp: {
442
+ ...settings.mcp,
443
+ allowed: argv.allowedMcpServerNames ?? settings.mcp?.allowed,
444
+ },
445
+ };
446
+ const policyEngineConfig = await createPolicyEngineConfig(effectiveSettings, approvalMode);
447
+ policyEngineConfig.nonInteractive = !interactive;
424
448
  const defaultModel = settings.general?.previewFeatures
425
449
  ? PREVIEW_GEMINI_MODEL_AUTO
426
450
  : DEFAULT_GEMINI_MODEL_AUTO;
@@ -433,6 +457,7 @@ export async function loadCliConfig(settings, sessionId, argv, options = {}) {
433
457
  ? argv.screenReader
434
458
  : (settings.ui?.accessibility?.screenReader ?? false);
435
459
  const ptyInfo = await getPty();
460
+ const mcpEnabled = settings.admin?.mcp?.enabled ?? true;
436
461
  return new Config({
437
462
  sessionId,
438
463
  embeddingModel: DEFAULT_GEMINI_EMBEDDING_MODEL,
@@ -449,26 +474,31 @@ export async function loadCliConfig(settings, sessionId, argv, options = {}) {
449
474
  excludeTools,
450
475
  toolDiscoveryCommand: settings.tools?.discoveryCommand,
451
476
  toolCallCommand: settings.tools?.callCommand,
452
- mcpServerCommand: settings.mcp?.serverCommand,
453
- mcpServers: settings.mcpServers,
454
- allowedMcpServers: argv.allowedMcpServerNames ?? settings.mcp?.allowed,
455
- blockedMcpServers: argv.allowedMcpServerNames
456
- ? undefined
457
- : settings.mcp?.excluded,
477
+ mcpServerCommand: mcpEnabled ? settings.mcp?.serverCommand : undefined,
478
+ mcpServers: mcpEnabled ? settings.mcpServers : {},
479
+ mcpEnabled,
480
+ allowedMcpServers: mcpEnabled
481
+ ? (argv.allowedMcpServerNames ?? settings.mcp?.allowed)
482
+ : undefined,
483
+ blockedMcpServers: mcpEnabled
484
+ ? argv.allowedMcpServerNames
485
+ ? undefined
486
+ : settings.mcp?.excluded
487
+ : undefined,
458
488
  blockedEnvironmentVariables: settings.security?.environmentVariableRedaction?.blocked,
459
489
  enableEnvironmentVariableRedaction: settings.security?.environmentVariableRedaction?.enabled,
460
490
  userMemory: memoryContent,
461
491
  geminiMdFileCount: fileCount,
462
492
  geminiMdFilePaths: filePaths,
463
493
  approvalMode,
464
- disableYoloMode: settings.security?.disableYoloMode,
494
+ disableYoloMode: settings.security?.disableYoloMode || settings.admin?.secureModeEnabled,
465
495
  showMemoryUsage: settings.ui?.showMemoryUsage || false,
466
496
  accessibility: {
467
497
  ...settings.ui?.accessibility,
468
498
  screenReader,
469
499
  },
470
500
  telemetry: telemetrySettings,
471
- usageStatisticsEnabled: settings.privacy?.usageStatisticsEnabled ?? true,
501
+ usageStatisticsEnabled: settings.privacy?.usageStatisticsEnabled,
472
502
  fileFiltering,
473
503
  checkpointing: settings.general?.checkpointing?.enabled,
474
504
  proxy: process.env['HTTPS_PROXY'] ||
@@ -479,7 +509,7 @@ export async function loadCliConfig(settings, sessionId, argv, options = {}) {
479
509
  fileDiscoveryService: fileService,
480
510
  bugCommand: settings.advanced?.bugCommand,
481
511
  model: resolvedModel,
482
- maxSessionTurns: settings.model?.maxSessionTurns ?? -1,
512
+ maxSessionTurns: settings.model?.maxSessionTurns,
483
513
  experimentalZedIntegration: argv.experimentalAcp || false,
484
514
  listExtensions: argv.listExtensions || false,
485
515
  listSessions: argv.listSessions || false,
@@ -499,16 +529,15 @@ export async function loadCliConfig(settings, sessionId, argv, options = {}) {
499
529
  interactive,
500
530
  trustedFolder,
501
531
  useRipgrep: settings.tools?.useRipgrep,
502
- enableInteractiveShell: settings.tools?.shell?.enableInteractiveShell ?? true,
532
+ enableInteractiveShell: settings.tools?.shell?.enableInteractiveShell,
503
533
  shellToolInactivityTimeout: settings.tools?.shell?.inactivityTimeout,
504
534
  enableShellOutputEfficiency: settings.tools?.shell?.enableShellOutputEfficiency ?? true,
505
535
  skipNextSpeakerCheck: settings.model?.skipNextSpeakerCheck,
506
- enablePromptCompletion: settings.general?.enablePromptCompletion ?? false,
536
+ enablePromptCompletion: settings.general?.enablePromptCompletion,
507
537
  truncateToolOutputThreshold: settings.tools?.truncateToolOutputThreshold,
508
538
  truncateToolOutputLines: settings.tools?.truncateToolOutputLines,
509
539
  enableToolOutputTruncation: settings.tools?.enableToolOutputTruncation,
510
540
  eventEmitter: appEvents,
511
- useSmartEdit: argv.useSmartEdit ?? settings.useSmartEdit,
512
541
  useWriteTodos: argv.useWriteTodos ?? settings.useWriteTodos,
513
542
  output: {
514
543
  format: (argv.outputFormat ?? settings.output?.format),
@@ -517,14 +546,20 @@ export async function loadCliConfig(settings, sessionId, argv, options = {}) {
517
546
  introspectionAgentSettings: settings.experimental?.introspectionAgentSettings,
518
547
  fakeResponses: argv.fakeResponses,
519
548
  recordResponses: argv.recordResponses,
520
- retryFetchErrors: settings.general?.retryFetchErrors ?? false,
549
+ retryFetchErrors: settings.general?.retryFetchErrors,
521
550
  ptyInfo: ptyInfo?.name,
522
551
  modelConfigServiceConfig: settings.modelConfigs,
523
552
  // TODO: loading of hooks based on workspace trust
524
- enableHooks: settings.tools?.enableHooks ?? false,
553
+ enableHooks: getEnableHooks(settings),
525
554
  hooks: settings.hooks || {},
526
555
  projectHooks: projectHooks || {},
527
556
  onModelChange: (model) => saveModelChange(loadedSettings, model),
557
+ onReload: async () => {
558
+ const refreshedSettings = loadSettings(cwd);
559
+ return {
560
+ disabledSkills: refreshedSettings.merged.skills?.disabled,
561
+ };
562
+ },
528
563
  });
529
564
  }
530
565
  function mergeExcludeTools(settings, extraExcludes) {