mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-05-05 15:31:27 +00:00
feat(cli): add bare startup mode (#3448)
* feat(cli): add bare startup mode Skip implicit startup discovery in bare mode while keeping explicit inputs such as include directories and extension overrides. Add a repository plan document and targeted tests for config, startup, skills, extensions, and memory discovery. * fix(bare): enforce explicit-only startup behavior * fix(cli): preserve bare tools in non-interactive mode * chore(docs): remove bare mode planning note
This commit is contained in:
parent
cfe142e9a3
commit
41f71ab7e7
19 changed files with 750 additions and 72 deletions
|
|
@ -19,6 +19,7 @@ import {
|
|||
validateDnsResolutionOrder,
|
||||
startInteractiveUI,
|
||||
} from './gemini.js';
|
||||
import type { CliArgs } from './config/config.js';
|
||||
import { type LoadedSettings } from './config/settings.js';
|
||||
import { appEvents, AppEvent } from './utils/events.js';
|
||||
import type { Config } from '@qwen-code/qwen-code-core';
|
||||
|
|
@ -40,6 +41,7 @@ vi.mock('./config/settings.js', async (importOriginal) => {
|
|||
return {
|
||||
...actual,
|
||||
loadSettings: vi.fn(),
|
||||
createMinimalSettings: vi.fn(),
|
||||
};
|
||||
});
|
||||
|
||||
|
|
@ -109,6 +111,7 @@ vi.mock('./core/initializer.js', () => ({
|
|||
describe('gemini.tsx main function', () => {
|
||||
let originalEnvGeminiSandbox: string | undefined;
|
||||
let originalEnvSandbox: string | undefined;
|
||||
let originalEnvQwenCodeSimple: string | undefined;
|
||||
let initialUnhandledRejectionListeners: NodeJS.UnhandledRejectionListener[] =
|
||||
[];
|
||||
|
||||
|
|
@ -116,8 +119,10 @@ describe('gemini.tsx main function', () => {
|
|||
// Store and clear sandbox-related env variables to ensure a consistent test environment
|
||||
originalEnvGeminiSandbox = process.env['QWEN_SANDBOX'];
|
||||
originalEnvSandbox = process.env['SANDBOX'];
|
||||
originalEnvQwenCodeSimple = process.env['QWEN_CODE_SIMPLE'];
|
||||
delete process.env['QWEN_SANDBOX'];
|
||||
delete process.env['SANDBOX'];
|
||||
delete process.env['QWEN_CODE_SIMPLE'];
|
||||
|
||||
initialUnhandledRejectionListeners =
|
||||
process.listeners('unhandledRejection');
|
||||
|
|
@ -135,6 +140,11 @@ describe('gemini.tsx main function', () => {
|
|||
} else {
|
||||
delete process.env['SANDBOX'];
|
||||
}
|
||||
if (originalEnvQwenCodeSimple !== undefined) {
|
||||
process.env['QWEN_CODE_SIMPLE'] = originalEnvQwenCodeSimple;
|
||||
} else {
|
||||
delete process.env['QWEN_CODE_SIMPLE'];
|
||||
}
|
||||
|
||||
const currentListeners = process.listeners('unhandledRejection');
|
||||
const addedListener = currentListeners.find(
|
||||
|
|
@ -215,6 +225,87 @@ describe('gemini.tsx main function', () => {
|
|||
processExitSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('should skip full settings discovery in bare mode', async () => {
|
||||
const originalArgv = process.argv;
|
||||
process.argv = ['node', 'script.js', '--bare'];
|
||||
|
||||
const { loadCliConfig, parseArguments } = await import(
|
||||
'./config/config.js'
|
||||
);
|
||||
const { loadSettings, createMinimalSettings } = await import(
|
||||
'./config/settings.js'
|
||||
);
|
||||
const { loadSandboxConfig } = await import('./config/sandboxConfig.js');
|
||||
const { relaunchAppInChildProcess } = await import('./utils/relaunch.js');
|
||||
const nonInteractiveModule = await import('./nonInteractiveCli.js');
|
||||
const processExitSpy = vi
|
||||
.spyOn(process, 'exit')
|
||||
.mockImplementation((code) => {
|
||||
throw new MockProcessExitError(code);
|
||||
});
|
||||
|
||||
const minimalSettings = {
|
||||
errors: [],
|
||||
merged: {},
|
||||
setValue: vi.fn(),
|
||||
forScope: () => ({ settings: {}, originalSettings: {}, path: '' }),
|
||||
migrationWarnings: [],
|
||||
getUserHooks: () => undefined,
|
||||
getProjectHooks: () => undefined,
|
||||
};
|
||||
const configStub = {
|
||||
isInteractive: () => false,
|
||||
getQuestion: () => 'bare prompt',
|
||||
getSandbox: () => false,
|
||||
getDebugMode: () => false,
|
||||
getListExtensions: () => false,
|
||||
getMcpServers: () => ({}),
|
||||
initialize: vi.fn().mockResolvedValue(undefined),
|
||||
getIdeMode: () => false,
|
||||
getExperimentalZedIntegration: () => false,
|
||||
getScreenReader: () => false,
|
||||
getGeminiMdFileCount: () => 0,
|
||||
getProjectRoot: () => '/',
|
||||
getOutputFormat: () => OutputFormat.TEXT,
|
||||
getWarnings: () => [],
|
||||
getModelsConfig: () => ({ getCurrentAuthType: () => null }),
|
||||
getSessionId: () => 'test-session-id',
|
||||
} as unknown as Config;
|
||||
|
||||
vi.mocked(parseArguments).mockResolvedValue({
|
||||
bare: true,
|
||||
} as unknown as CliArgs);
|
||||
vi.mocked(createMinimalSettings).mockReturnValue(minimalSettings as never);
|
||||
vi.mocked(loadSandboxConfig).mockResolvedValue(undefined);
|
||||
vi.mocked(relaunchAppInChildProcess).mockResolvedValue(undefined);
|
||||
vi.mocked(loadCliConfig).mockResolvedValue(configStub);
|
||||
vi.spyOn(nonInteractiveModule, 'runNonInteractive').mockResolvedValue();
|
||||
|
||||
try {
|
||||
await main();
|
||||
} catch (error) {
|
||||
if (!(error instanceof MockProcessExitError)) {
|
||||
throw error;
|
||||
}
|
||||
} finally {
|
||||
process.argv = originalArgv;
|
||||
processExitSpy.mockRestore();
|
||||
}
|
||||
|
||||
expect(createMinimalSettings).toHaveBeenCalledOnce();
|
||||
expect(loadSettings).not.toHaveBeenCalled();
|
||||
expect(loadCliConfig).toHaveBeenCalledWith(
|
||||
{},
|
||||
expect.objectContaining({ bare: true }),
|
||||
process.cwd(),
|
||||
undefined,
|
||||
{
|
||||
userHooks: undefined,
|
||||
projectHooks: undefined,
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it('should log unhandled promise rejections and open debug console on first error', async () => {
|
||||
const processExitSpy = vi
|
||||
.spyOn(process, 'exit')
|
||||
|
|
@ -483,6 +574,7 @@ describe('gemini.tsx main function kitty protocol', () => {
|
|||
appendSystemPrompt: undefined,
|
||||
query: undefined,
|
||||
yolo: undefined,
|
||||
bare: undefined,
|
||||
approvalMode: undefined,
|
||||
telemetry: undefined,
|
||||
checkpointing: undefined,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue