[extensions] Add extension management install command (#6703)

This commit is contained in:
christine betts
2025-08-25 17:02:10 +00:00
committed by GitHub
parent 49cce8a15d
commit 0bd496bd51
14 changed files with 562 additions and 115 deletions

View File

@@ -125,7 +125,9 @@ describe('parseArguments', () => {
.spyOn(console, 'error')
.mockImplementation(() => {});
await expect(parseArguments()).rejects.toThrow('process.exit called');
await expect(parseArguments({} as Settings)).rejects.toThrow(
'process.exit called',
);
expect(mockConsoleError).toHaveBeenCalledWith(
expect.stringContaining(
@@ -155,7 +157,9 @@ describe('parseArguments', () => {
.spyOn(console, 'error')
.mockImplementation(() => {});
await expect(parseArguments()).rejects.toThrow('process.exit called');
await expect(parseArguments({} as Settings)).rejects.toThrow(
'process.exit called',
);
expect(mockConsoleError).toHaveBeenCalledWith(
expect.stringContaining(
@@ -169,7 +173,7 @@ describe('parseArguments', () => {
it('should allow --prompt without --prompt-interactive', async () => {
process.argv = ['node', 'script.js', '--prompt', 'test prompt'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
expect(argv.prompt).toBe('test prompt');
expect(argv.promptInteractive).toBeUndefined();
});
@@ -181,14 +185,14 @@ describe('parseArguments', () => {
'--prompt-interactive',
'interactive prompt',
];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
expect(argv.promptInteractive).toBe('interactive prompt');
expect(argv.prompt).toBeUndefined();
});
it('should allow -i flag as alias for --prompt-interactive', async () => {
process.argv = ['node', 'script.js', '-i', 'interactive prompt'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
expect(argv.promptInteractive).toBe('interactive prompt');
expect(argv.prompt).toBeUndefined();
});
@@ -210,7 +214,9 @@ describe('parseArguments', () => {
.spyOn(console, 'error')
.mockImplementation(() => {});
await expect(parseArguments()).rejects.toThrow('process.exit called');
await expect(parseArguments({} as Settings)).rejects.toThrow(
'process.exit called',
);
expect(mockConsoleError).toHaveBeenCalledWith(
expect.stringContaining(
@@ -233,7 +239,9 @@ describe('parseArguments', () => {
.spyOn(console, 'error')
.mockImplementation(() => {});
await expect(parseArguments()).rejects.toThrow('process.exit called');
await expect(parseArguments({} as Settings)).rejects.toThrow(
'process.exit called',
);
expect(mockConsoleError).toHaveBeenCalledWith(
expect.stringContaining(
@@ -247,14 +255,14 @@ describe('parseArguments', () => {
it('should allow --approval-mode without --yolo', async () => {
process.argv = ['node', 'script.js', '--approval-mode', 'auto_edit'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
expect(argv.approvalMode).toBe('auto_edit');
expect(argv.yolo).toBe(false);
});
it('should allow --yolo without --approval-mode', async () => {
process.argv = ['node', 'script.js', '--yolo'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
expect(argv.yolo).toBe(true);
expect(argv.approvalMode).toBeUndefined();
});
@@ -270,7 +278,9 @@ describe('parseArguments', () => {
.spyOn(console, 'error')
.mockImplementation(() => {});
await expect(parseArguments()).rejects.toThrow('process.exit called');
await expect(parseArguments({} as Settings)).rejects.toThrow(
'process.exit called',
);
expect(mockConsoleError).toHaveBeenCalledWith(
expect.stringContaining('Invalid values:'),
@@ -298,7 +308,7 @@ describe('loadCliConfig', () => {
it('should set showMemoryUsage to true when --show-memory-usage flag is present', async () => {
process.argv = ['node', 'script.js', '--show-memory-usage'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const settings: Settings = {};
const config = await loadCliConfig(settings, [], 'test-session', argv);
expect(config.getShowMemoryUsage()).toBe(true);
@@ -306,7 +316,7 @@ describe('loadCliConfig', () => {
it('should set showMemoryUsage to false when --memory flag is not present', async () => {
process.argv = ['node', 'script.js'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const settings: Settings = {};
const config = await loadCliConfig(settings, [], 'test-session', argv);
expect(config.getShowMemoryUsage()).toBe(false);
@@ -314,7 +324,7 @@ describe('loadCliConfig', () => {
it('should set showMemoryUsage to false by default from settings if CLI flag is not present', async () => {
process.argv = ['node', 'script.js'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const settings: Settings = { showMemoryUsage: false };
const config = await loadCliConfig(settings, [], 'test-session', argv);
expect(config.getShowMemoryUsage()).toBe(false);
@@ -322,7 +332,7 @@ describe('loadCliConfig', () => {
it('should prioritize CLI flag over settings for showMemoryUsage (CLI true, settings false)', async () => {
process.argv = ['node', 'script.js', '--show-memory-usage'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const settings: Settings = { showMemoryUsage: false };
const config = await loadCliConfig(settings, [], 'test-session', argv);
expect(config.getShowMemoryUsage()).toBe(true);
@@ -356,7 +366,7 @@ describe('loadCliConfig', () => {
it(`should leave proxy to empty by default`, async () => {
process.argv = ['node', 'script.js'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const settings: Settings = {};
const config = await loadCliConfig(settings, [], 'test-session', argv);
expect(config.getProxy()).toBeFalsy();
@@ -397,7 +407,7 @@ describe('loadCliConfig', () => {
it(`should set proxy to ${expected} according to environment variable [${input.env_name}]`, async () => {
vi.stubEnv(input.env_name, input.proxy_url);
process.argv = ['node', 'script.js'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const settings: Settings = {};
const config = await loadCliConfig(settings, [], 'test-session', argv);
expect(config.getProxy()).toBe(expected);
@@ -406,7 +416,7 @@ describe('loadCliConfig', () => {
it('should set proxy when --proxy flag is present', async () => {
process.argv = ['node', 'script.js', '--proxy', 'http://localhost:7890'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const settings: Settings = {};
const config = await loadCliConfig(settings, [], 'test-session', argv);
expect(config.getProxy()).toBe('http://localhost:7890');
@@ -415,7 +425,7 @@ describe('loadCliConfig', () => {
it('should prioritize CLI flag over environment variable for proxy (CLI http://localhost:7890, environment variable http://localhost:7891)', async () => {
vi.stubEnv('http_proxy', 'http://localhost:7891');
process.argv = ['node', 'script.js', '--proxy', 'http://localhost:7890'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const settings: Settings = {};
const config = await loadCliConfig(settings, [], 'test-session', argv);
expect(config.getProxy()).toBe('http://localhost:7890');
@@ -440,7 +450,7 @@ describe('loadCliConfig telemetry', () => {
it('should set telemetry to false by default when no flag or setting is present', async () => {
process.argv = ['node', 'script.js'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const settings: Settings = {};
const config = await loadCliConfig(settings, [], 'test-session', argv);
expect(config.getTelemetryEnabled()).toBe(false);
@@ -448,7 +458,7 @@ describe('loadCliConfig telemetry', () => {
it('should set telemetry to true when --telemetry flag is present', async () => {
process.argv = ['node', 'script.js', '--telemetry'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const settings: Settings = {};
const config = await loadCliConfig(settings, [], 'test-session', argv);
expect(config.getTelemetryEnabled()).toBe(true);
@@ -456,7 +466,7 @@ describe('loadCliConfig telemetry', () => {
it('should set telemetry to false when --no-telemetry flag is present', async () => {
process.argv = ['node', 'script.js', '--no-telemetry'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const settings: Settings = {};
const config = await loadCliConfig(settings, [], 'test-session', argv);
expect(config.getTelemetryEnabled()).toBe(false);
@@ -464,7 +474,7 @@ describe('loadCliConfig telemetry', () => {
it('should use telemetry value from settings if CLI flag is not present (settings true)', async () => {
process.argv = ['node', 'script.js'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const settings: Settings = { telemetry: { enabled: true } };
const config = await loadCliConfig(settings, [], 'test-session', argv);
expect(config.getTelemetryEnabled()).toBe(true);
@@ -472,7 +482,7 @@ describe('loadCliConfig telemetry', () => {
it('should use telemetry value from settings if CLI flag is not present (settings false)', async () => {
process.argv = ['node', 'script.js'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const settings: Settings = { telemetry: { enabled: false } };
const config = await loadCliConfig(settings, [], 'test-session', argv);
expect(config.getTelemetryEnabled()).toBe(false);
@@ -480,7 +490,7 @@ describe('loadCliConfig telemetry', () => {
it('should prioritize --telemetry CLI flag (true) over settings (false)', async () => {
process.argv = ['node', 'script.js', '--telemetry'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const settings: Settings = { telemetry: { enabled: false } };
const config = await loadCliConfig(settings, [], 'test-session', argv);
expect(config.getTelemetryEnabled()).toBe(true);
@@ -488,7 +498,7 @@ describe('loadCliConfig telemetry', () => {
it('should prioritize --no-telemetry CLI flag (false) over settings (true)', async () => {
process.argv = ['node', 'script.js', '--no-telemetry'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const settings: Settings = { telemetry: { enabled: true } };
const config = await loadCliConfig(settings, [], 'test-session', argv);
expect(config.getTelemetryEnabled()).toBe(false);
@@ -496,7 +506,7 @@ describe('loadCliConfig telemetry', () => {
it('should use telemetry OTLP endpoint from settings if CLI flag is not present', async () => {
process.argv = ['node', 'script.js'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const settings: Settings = {
telemetry: { otlpEndpoint: 'http://settings.example.com' },
};
@@ -513,7 +523,7 @@ describe('loadCliConfig telemetry', () => {
'--telemetry-otlp-endpoint',
'http://cli.example.com',
];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const settings: Settings = {
telemetry: { otlpEndpoint: 'http://settings.example.com' },
};
@@ -523,7 +533,7 @@ describe('loadCliConfig telemetry', () => {
it('should use default endpoint if no OTLP endpoint is provided via CLI or settings', async () => {
process.argv = ['node', 'script.js'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const settings: Settings = { telemetry: { enabled: true } };
const config = await loadCliConfig(settings, [], 'test-session', argv);
expect(config.getTelemetryOtlpEndpoint()).toBe('http://localhost:4317');
@@ -531,7 +541,7 @@ describe('loadCliConfig telemetry', () => {
it('should use telemetry target from settings if CLI flag is not present', async () => {
process.argv = ['node', 'script.js'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const settings: Settings = {
telemetry: { target: ServerConfig.DEFAULT_TELEMETRY_TARGET },
};
@@ -543,7 +553,7 @@ describe('loadCliConfig telemetry', () => {
it('should prioritize --telemetry-target CLI flag over settings', async () => {
process.argv = ['node', 'script.js', '--telemetry-target', 'gcp'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const settings: Settings = {
telemetry: { target: ServerConfig.DEFAULT_TELEMETRY_TARGET },
};
@@ -553,7 +563,7 @@ describe('loadCliConfig telemetry', () => {
it('should use default target if no target is provided via CLI or settings', async () => {
process.argv = ['node', 'script.js'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const settings: Settings = { telemetry: { enabled: true } };
const config = await loadCliConfig(settings, [], 'test-session', argv);
expect(config.getTelemetryTarget()).toBe(
@@ -563,7 +573,7 @@ describe('loadCliConfig telemetry', () => {
it('should use telemetry log prompts from settings if CLI flag is not present', async () => {
process.argv = ['node', 'script.js'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const settings: Settings = { telemetry: { logPrompts: false } };
const config = await loadCliConfig(settings, [], 'test-session', argv);
expect(config.getTelemetryLogPromptsEnabled()).toBe(false);
@@ -571,7 +581,7 @@ describe('loadCliConfig telemetry', () => {
it('should prioritize --telemetry-log-prompts CLI flag (true) over settings (false)', async () => {
process.argv = ['node', 'script.js', '--telemetry-log-prompts'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const settings: Settings = { telemetry: { logPrompts: false } };
const config = await loadCliConfig(settings, [], 'test-session', argv);
expect(config.getTelemetryLogPromptsEnabled()).toBe(true);
@@ -579,7 +589,7 @@ describe('loadCliConfig telemetry', () => {
it('should prioritize --no-telemetry-log-prompts CLI flag (false) over settings (true)', async () => {
process.argv = ['node', 'script.js', '--no-telemetry-log-prompts'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const settings: Settings = { telemetry: { logPrompts: true } };
const config = await loadCliConfig(settings, [], 'test-session', argv);
expect(config.getTelemetryLogPromptsEnabled()).toBe(false);
@@ -587,7 +597,7 @@ describe('loadCliConfig telemetry', () => {
it('should use default log prompts (true) if no value is provided via CLI or settings', async () => {
process.argv = ['node', 'script.js'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const settings: Settings = { telemetry: { enabled: true } };
const config = await loadCliConfig(settings, [], 'test-session', argv);
expect(config.getTelemetryLogPromptsEnabled()).toBe(true);
@@ -595,7 +605,7 @@ describe('loadCliConfig telemetry', () => {
it('should use telemetry OTLP protocol from settings if CLI flag is not present', async () => {
process.argv = ['node', 'script.js'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const settings: Settings = {
telemetry: { otlpProtocol: 'http' },
};
@@ -605,7 +615,7 @@ describe('loadCliConfig telemetry', () => {
it('should prioritize --telemetry-otlp-protocol CLI flag over settings', async () => {
process.argv = ['node', 'script.js', '--telemetry-otlp-protocol', 'http'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const settings: Settings = {
telemetry: { otlpProtocol: 'grpc' },
};
@@ -615,7 +625,7 @@ describe('loadCliConfig telemetry', () => {
it('should use default protocol if no OTLP protocol is provided via CLI or settings', async () => {
process.argv = ['node', 'script.js'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const settings: Settings = { telemetry: { enabled: true } };
const config = await loadCliConfig(settings, [], 'test-session', argv);
expect(config.getTelemetryOtlpProtocol()).toBe('grpc');
@@ -637,7 +647,9 @@ describe('loadCliConfig telemetry', () => {
.spyOn(console, 'error')
.mockImplementation(() => {});
await expect(parseArguments()).rejects.toThrow('process.exit called');
await expect(parseArguments({} as Settings)).rejects.toThrow(
'process.exit called',
);
expect(mockConsoleError).toHaveBeenCalledWith(
expect.stringContaining('Invalid values:'),
@@ -691,7 +703,7 @@ describe('Hierarchical Memory Loading (config.ts) - Placeholder Suite', () => {
],
},
];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
await loadCliConfig(settings, extensions, 'session-id', argv);
expect(ServerConfig.loadServerHierarchicalMemory).toHaveBeenCalledWith(
expect.any(String),
@@ -765,7 +777,7 @@ describe('mergeMcpServers', () => {
];
const originalSettings = JSON.parse(JSON.stringify(settings));
process.argv = ['node', 'script.js'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
await loadCliConfig(settings, extensions, 'test-session', argv);
expect(settings).toEqual(originalSettings);
});
@@ -806,7 +818,7 @@ describe('mergeExcludeTools', () => {
},
];
process.argv = ['node', 'script.js'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const config = await loadCliConfig(
settings,
extensions,
@@ -833,7 +845,7 @@ describe('mergeExcludeTools', () => {
},
];
process.argv = ['node', 'script.js'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const config = await loadCliConfig(
settings,
extensions,
@@ -869,7 +881,7 @@ describe('mergeExcludeTools', () => {
},
];
process.argv = ['node', 'script.js'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const config = await loadCliConfig(
settings,
extensions,
@@ -887,7 +899,7 @@ describe('mergeExcludeTools', () => {
const settings: Settings = {};
const extensions: Extension[] = [];
process.argv = ['node', 'script.js'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const config = await loadCliConfig(
settings,
extensions,
@@ -902,7 +914,7 @@ describe('mergeExcludeTools', () => {
const settings: Settings = {};
const extensions: Extension[] = [];
process.argv = ['node', 'script.js', '-p', 'test'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const config = await loadCliConfig(
settings,
extensions,
@@ -914,7 +926,7 @@ describe('mergeExcludeTools', () => {
it('should handle settings with excludeTools but no extensions', async () => {
process.argv = ['node', 'script.js'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const settings: Settings = { excludeTools: ['tool1', 'tool2'] };
const extensions: Extension[] = [];
const config = await loadCliConfig(
@@ -943,7 +955,7 @@ describe('mergeExcludeTools', () => {
},
];
process.argv = ['node', 'script.js'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const config = await loadCliConfig(
settings,
extensions,
@@ -971,7 +983,7 @@ describe('mergeExcludeTools', () => {
];
const originalSettings = JSON.parse(JSON.stringify(settings));
process.argv = ['node', 'script.js'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
await loadCliConfig(settings, extensions, 'test-session', argv);
expect(settings).toEqual(originalSettings);
});
@@ -990,7 +1002,7 @@ describe('Approval mode tool exclusion logic', () => {
it('should exclude all interactive tools in non-interactive mode with default approval mode', async () => {
process.argv = ['node', 'script.js', '-p', 'test'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const settings: Settings = {};
const extensions: Extension[] = [];
@@ -1016,7 +1028,7 @@ describe('Approval mode tool exclusion logic', () => {
'-p',
'test',
];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const settings: Settings = {};
const extensions: Extension[] = [];
@@ -1042,7 +1054,7 @@ describe('Approval mode tool exclusion logic', () => {
'-p',
'test',
];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const settings: Settings = {};
const extensions: Extension[] = [];
@@ -1068,7 +1080,7 @@ describe('Approval mode tool exclusion logic', () => {
'-p',
'test',
];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const settings: Settings = {};
const extensions: Extension[] = [];
@@ -1087,7 +1099,7 @@ describe('Approval mode tool exclusion logic', () => {
it('should exclude no interactive tools in non-interactive mode with legacy yolo flag', async () => {
process.argv = ['node', 'script.js', '--yolo', '-p', 'test'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const settings: Settings = {};
const extensions: Extension[] = [];
@@ -1117,7 +1129,7 @@ describe('Approval mode tool exclusion logic', () => {
for (const testCase of testCases) {
process.argv = testCase.args;
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const settings: Settings = {};
const extensions: Extension[] = [];
@@ -1144,7 +1156,7 @@ describe('Approval mode tool exclusion logic', () => {
'-p',
'test',
];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const settings: Settings = { excludeTools: ['custom_tool'] };
const extensions: Extension[] = [];
@@ -1212,7 +1224,7 @@ describe('loadCliConfig with allowed-mcp-server-names', () => {
it('should allow all MCP servers if the flag is not provided', async () => {
process.argv = ['node', 'script.js'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const config = await loadCliConfig(baseSettings, [], 'test-session', argv);
expect(config.getMcpServers()).toEqual(baseSettings.mcpServers);
});
@@ -1224,7 +1236,7 @@ describe('loadCliConfig with allowed-mcp-server-names', () => {
'--allowed-mcp-server-names',
'server1',
];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const config = await loadCliConfig(baseSettings, [], 'test-session', argv);
expect(config.getMcpServers()).toEqual({
server1: { url: 'http://localhost:8080' },
@@ -1240,7 +1252,7 @@ describe('loadCliConfig with allowed-mcp-server-names', () => {
'--allowed-mcp-server-names',
'server3',
];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const config = await loadCliConfig(baseSettings, [], 'test-session', argv);
expect(config.getMcpServers()).toEqual({
server1: { url: 'http://localhost:8080' },
@@ -1257,7 +1269,7 @@ describe('loadCliConfig with allowed-mcp-server-names', () => {
'--allowed-mcp-server-names',
'server4',
];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const config = await loadCliConfig(baseSettings, [], 'test-session', argv);
expect(config.getMcpServers()).toEqual({
server1: { url: 'http://localhost:8080' },
@@ -1266,14 +1278,14 @@ describe('loadCliConfig with allowed-mcp-server-names', () => {
it('should allow no MCP servers if the flag is provided but empty', async () => {
process.argv = ['node', 'script.js', '--allowed-mcp-server-names', ''];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const config = await loadCliConfig(baseSettings, [], 'test-session', argv);
expect(config.getMcpServers()).toEqual({});
});
it('should read allowMCPServers from settings', async () => {
process.argv = ['node', 'script.js'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const settings: Settings = {
...baseSettings,
allowMCPServers: ['server1', 'server2'],
@@ -1287,7 +1299,7 @@ describe('loadCliConfig with allowed-mcp-server-names', () => {
it('should read excludeMCPServers from settings', async () => {
process.argv = ['node', 'script.js'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const settings: Settings = {
...baseSettings,
excludeMCPServers: ['server1', 'server2'],
@@ -1300,7 +1312,7 @@ describe('loadCliConfig with allowed-mcp-server-names', () => {
it('should override allowMCPServers with excludeMCPServers if overlapping', async () => {
process.argv = ['node', 'script.js'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const settings: Settings = {
...baseSettings,
excludeMCPServers: ['server1'],
@@ -1319,7 +1331,7 @@ describe('loadCliConfig with allowed-mcp-server-names', () => {
'--allowed-mcp-server-names',
'server1',
];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const settings: Settings = {
...baseSettings,
excludeMCPServers: ['server1'],
@@ -1348,7 +1360,7 @@ describe('loadCliConfig extensions', () => {
it('should not filter extensions if --extensions flag is not used', async () => {
process.argv = ['node', 'script.js'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const settings: Settings = {};
const config = await loadCliConfig(
settings,
@@ -1364,7 +1376,7 @@ describe('loadCliConfig extensions', () => {
it('should filter extensions if --extensions flag is used', async () => {
process.argv = ['node', 'script.js', '--extensions', 'ext1'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const settings: Settings = {};
const config = await loadCliConfig(
settings,
@@ -1379,7 +1391,7 @@ describe('loadCliConfig extensions', () => {
describe('loadCliConfig model selection', () => {
it('selects a model from settings.json if provided', async () => {
process.argv = ['node', 'script.js'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const config = await loadCliConfig(
{
model: 'gemini-9001-ultra',
@@ -1394,7 +1406,7 @@ describe('loadCliConfig model selection', () => {
it('uses the default gemini model if nothing is set', async () => {
process.argv = ['node', 'script.js']; // No model set.
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const config = await loadCliConfig(
{
// No model set.
@@ -1409,7 +1421,7 @@ describe('loadCliConfig model selection', () => {
it('always prefers model from argvs', async () => {
process.argv = ['node', 'script.js', '--model', 'gemini-8675309-ultra'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const config = await loadCliConfig(
{
model: 'gemini-9001-ultra',
@@ -1424,7 +1436,7 @@ describe('loadCliConfig model selection', () => {
it('selects the model from argvs if provided', async () => {
process.argv = ['node', 'script.js', '--model', 'gemini-8675309-ultra'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const config = await loadCliConfig(
{
// No model provided via settings.
@@ -1456,14 +1468,14 @@ describe('loadCliConfig folderTrustFeature', () => {
it('should be false by default', async () => {
process.argv = ['node', 'script.js'];
const settings: Settings = {};
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const config = await loadCliConfig(settings, [], 'test-session', argv);
expect(config.getFolderTrustFeature()).toBe(false);
});
it('should be true when settings.folderTrustFeature is true', async () => {
process.argv = ['node', 'script.js'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const settings: Settings = { folderTrustFeature: true };
const config = await loadCliConfig(settings, [], 'test-session', argv);
expect(config.getFolderTrustFeature()).toBe(true);
@@ -1491,14 +1503,14 @@ describe('loadCliConfig folderTrust', () => {
folderTrustFeature: false,
folderTrust: false,
};
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const config = await loadCliConfig(settings, [], 'test-session', argv);
expect(config.getFolderTrust()).toBe(false);
});
it('should be false if folderTrustFeature is true and folderTrust is false', async () => {
process.argv = ['node', 'script.js'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const settings: Settings = { folderTrustFeature: true, folderTrust: false };
const config = await loadCliConfig(settings, [], 'test-session', argv);
expect(config.getFolderTrust()).toBe(false);
@@ -1506,7 +1518,7 @@ describe('loadCliConfig folderTrust', () => {
it('should be false if folderTrustFeature is false and folderTrust is true', async () => {
process.argv = ['node', 'script.js'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const settings: Settings = { folderTrustFeature: false, folderTrust: true };
const config = await loadCliConfig(settings, [], 'test-session', argv);
expect(config.getFolderTrust()).toBe(false);
@@ -1514,7 +1526,7 @@ describe('loadCliConfig folderTrust', () => {
it('should be true when folderTrustFeature is true and folderTrust is true', async () => {
process.argv = ['node', 'script.js'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const settings: Settings = { folderTrustFeature: true, folderTrust: true };
const config = await loadCliConfig(settings, [], 'test-session', argv);
expect(config.getFolderTrust()).toBe(true);
@@ -1547,7 +1559,7 @@ describe('loadCliConfig with includeDirectories', () => {
'--include-directories',
`${path.resolve(path.sep, 'cli', 'path1')},${path.join(mockCwd, 'cli', 'path2')}`,
];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const settings: Settings = {
includeDirectories: [
path.resolve(path.sep, 'settings', 'path1'),
@@ -1590,7 +1602,7 @@ describe('loadCliConfig chatCompression', () => {
it('should pass chatCompression settings to the core config', async () => {
process.argv = ['node', 'script.js'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const settings: Settings = {
chatCompression: {
contextPercentageThreshold: 0.5,
@@ -1604,7 +1616,7 @@ describe('loadCliConfig chatCompression', () => {
it('should have undefined chatCompression if not in settings', async () => {
process.argv = ['node', 'script.js'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const settings: Settings = {};
const config = await loadCliConfig(settings, [], 'test-session', argv);
expect(config.getChatCompression()).toBeUndefined();
@@ -1628,7 +1640,7 @@ describe('loadCliConfig useRipgrep', () => {
it('should be false by default when useRipgrep is not set in settings', async () => {
process.argv = ['node', 'script.js'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const settings: Settings = {};
const config = await loadCliConfig(settings, [], 'test-session', argv);
expect(config.getUseRipgrep()).toBe(false);
@@ -1636,7 +1648,7 @@ describe('loadCliConfig useRipgrep', () => {
it('should be true when useRipgrep is set to true in settings', async () => {
process.argv = ['node', 'script.js'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const settings: Settings = { useRipgrep: true };
const config = await loadCliConfig(settings, [], 'test-session', argv);
expect(config.getUseRipgrep()).toBe(true);
@@ -1644,7 +1656,7 @@ describe('loadCliConfig useRipgrep', () => {
it('should be false when useRipgrep is explicitly set to false in settings', async () => {
process.argv = ['node', 'script.js'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const settings: Settings = { useRipgrep: false };
const config = await loadCliConfig(settings, [], 'test-session', argv);
expect(config.getUseRipgrep()).toBe(false);
@@ -1672,7 +1684,7 @@ describe('loadCliConfig tool exclusions', () => {
it('should not exclude interactive tools in interactive mode without YOLO', async () => {
process.stdin.isTTY = true;
process.argv = ['node', 'script.js'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const config = await loadCliConfig({}, [], 'test-session', argv);
expect(config.getExcludeTools()).not.toContain('run_shell_command');
expect(config.getExcludeTools()).not.toContain('replace');
@@ -1682,7 +1694,7 @@ describe('loadCliConfig tool exclusions', () => {
it('should not exclude interactive tools in interactive mode with YOLO', async () => {
process.stdin.isTTY = true;
process.argv = ['node', 'script.js', '--yolo'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const config = await loadCliConfig({}, [], 'test-session', argv);
expect(config.getExcludeTools()).not.toContain('run_shell_command');
expect(config.getExcludeTools()).not.toContain('replace');
@@ -1692,7 +1704,7 @@ describe('loadCliConfig tool exclusions', () => {
it('should exclude interactive tools in non-interactive mode without YOLO', async () => {
process.stdin.isTTY = false;
process.argv = ['node', 'script.js', '-p', 'test'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const config = await loadCliConfig({}, [], 'test-session', argv);
expect(config.getExcludeTools()).toContain('run_shell_command');
expect(config.getExcludeTools()).toContain('replace');
@@ -1702,7 +1714,7 @@ describe('loadCliConfig tool exclusions', () => {
it('should not exclude interactive tools in non-interactive mode with YOLO', async () => {
process.stdin.isTTY = false;
process.argv = ['node', 'script.js', '-p', 'test', '--yolo'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const config = await loadCliConfig({}, [], 'test-session', argv);
expect(config.getExcludeTools()).not.toContain('run_shell_command');
expect(config.getExcludeTools()).not.toContain('replace');
@@ -1731,7 +1743,7 @@ describe('loadCliConfig interactive', () => {
it('should be interactive if isTTY and no prompt', async () => {
process.stdin.isTTY = true;
process.argv = ['node', 'script.js'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const config = await loadCliConfig({}, [], 'test-session', argv);
expect(config.isInteractive()).toBe(true);
});
@@ -1739,7 +1751,7 @@ describe('loadCliConfig interactive', () => {
it('should be interactive if prompt-interactive is set', async () => {
process.stdin.isTTY = false;
process.argv = ['node', 'script.js', '--prompt-interactive', 'test'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const config = await loadCliConfig({}, [], 'test-session', argv);
expect(config.isInteractive()).toBe(true);
});
@@ -1747,7 +1759,7 @@ describe('loadCliConfig interactive', () => {
it('should not be interactive if not isTTY and no prompt', async () => {
process.stdin.isTTY = false;
process.argv = ['node', 'script.js'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const config = await loadCliConfig({}, [], 'test-session', argv);
expect(config.isInteractive()).toBe(false);
});
@@ -1755,7 +1767,7 @@ describe('loadCliConfig interactive', () => {
it('should not be interactive if prompt is set', async () => {
process.stdin.isTTY = true;
process.argv = ['node', 'script.js', '--prompt', 'test'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const config = await loadCliConfig({}, [], 'test-session', argv);
expect(config.isInteractive()).toBe(false);
});
@@ -1779,42 +1791,42 @@ describe('loadCliConfig approval mode', () => {
it('should default to DEFAULT approval mode when no flags are set', async () => {
process.argv = ['node', 'script.js'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const config = await loadCliConfig({}, [], 'test-session', argv);
expect(config.getApprovalMode()).toBe(ServerConfig.ApprovalMode.DEFAULT);
});
it('should set YOLO approval mode when --yolo flag is used', async () => {
process.argv = ['node', 'script.js', '--yolo'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const config = await loadCliConfig({}, [], 'test-session', argv);
expect(config.getApprovalMode()).toBe(ServerConfig.ApprovalMode.YOLO);
});
it('should set YOLO approval mode when -y flag is used', async () => {
process.argv = ['node', 'script.js', '-y'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const config = await loadCliConfig({}, [], 'test-session', argv);
expect(config.getApprovalMode()).toBe(ServerConfig.ApprovalMode.YOLO);
});
it('should set DEFAULT approval mode when --approval-mode=default', async () => {
process.argv = ['node', 'script.js', '--approval-mode', 'default'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const config = await loadCliConfig({}, [], 'test-session', argv);
expect(config.getApprovalMode()).toBe(ServerConfig.ApprovalMode.DEFAULT);
});
it('should set AUTO_EDIT approval mode when --approval-mode=auto_edit', async () => {
process.argv = ['node', 'script.js', '--approval-mode', 'auto_edit'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const config = await loadCliConfig({}, [], 'test-session', argv);
expect(config.getApprovalMode()).toBe(ServerConfig.ApprovalMode.AUTO_EDIT);
});
it('should set YOLO approval mode when --approval-mode=yolo', async () => {
process.argv = ['node', 'script.js', '--approval-mode', 'yolo'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const config = await loadCliConfig({}, [], 'test-session', argv);
expect(config.getApprovalMode()).toBe(ServerConfig.ApprovalMode.YOLO);
});
@@ -1823,7 +1835,7 @@ describe('loadCliConfig approval mode', () => {
// Note: This test documents the intended behavior, but in practice the validation
// prevents both flags from being used together
process.argv = ['node', 'script.js', '--approval-mode', 'default'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
// Manually set yolo to true to simulate what would happen if validation didn't prevent it
argv.yolo = true;
const config = await loadCliConfig({}, [], 'test-session', argv);
@@ -1832,7 +1844,7 @@ describe('loadCliConfig approval mode', () => {
it('should fall back to --yolo behavior when --approval-mode is not set', async () => {
process.argv = ['node', 'script.js', '--yolo'];
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const config = await loadCliConfig({}, [], 'test-session', argv);
expect(config.getApprovalMode()).toBe(ServerConfig.ApprovalMode.YOLO);
});
@@ -1949,7 +1961,7 @@ describe('loadCliConfig trustedFolder', () => {
(settings.folderTrust ?? true);
return featureIsEnabled ? mockTrustValue : true;
});
const argv = await parseArguments();
const argv = await parseArguments({} as Settings);
const settings: Settings = { folderTrustFeature, folderTrust };
const config = await loadCliConfig(settings, [], 'test-session', argv);