feat(cli): support tools.sandboxImage in settings (#3146)

Co-authored-by: jinye.djy <jinye.djy@alibaba-inc.com>
This commit is contained in:
jinye 2026-04-13 09:43:34 +08:00 committed by GitHub
parent 116796b2a4
commit 1557d93043
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 146 additions and 19 deletions

View file

@ -111,10 +111,21 @@ vi.mock('open', () => ({
vi.mock('read-package-up', () => ({
readPackageUp: vi.fn(() =>
Promise.resolve({ packageJson: { version: 'test-version' } }),
Promise.resolve({
packageJson: {
version: 'test-version',
config: { sandboxImageUri: 'pkg-default-image' },
},
}),
),
}));
vi.mock('command-exists', () => ({
default: {
sync: vi.fn(() => true),
},
}));
vi.mock('@qwen-code/qwen-code-core', async (importOriginal) => {
const actualServer = await importOriginal<typeof ServerConfig>();
const SkillManagerMock = vi.fn();
@ -2441,6 +2452,83 @@ describe('Telemetry configuration via environment variables', () => {
});
});
describe('sandbox image resolution precedence', () => {
const originalArgv = process.argv;
beforeEach(() => {
vi.resetAllMocks();
vi.mocked(os.homedir).mockReturnValue('/mock/home/user');
vi.stubEnv('GEMINI_API_KEY', 'test-api-key');
delete process.env['QWEN_SANDBOX_IMAGE'];
});
afterEach(() => {
process.argv = originalArgv;
vi.unstubAllEnvs();
vi.restoreAllMocks();
delete process.env['QWEN_SANDBOX_IMAGE'];
});
it('uses --sandbox-image over env and settings', async () => {
vi.stubEnv('QWEN_SANDBOX_IMAGE', 'env-image');
process.argv = [
'node',
'script.js',
'--sandbox',
'--sandbox-image',
'cli-image',
];
const argv = await parseArguments();
const settings: Settings = {
tools: {
sandbox: true,
sandboxImage: 'settings-image',
},
};
const config = await loadCliConfig(settings, argv, undefined, []);
expect(config.getSandbox()?.image).toBe('cli-image');
});
it('uses QWEN_SANDBOX_IMAGE over tools.sandboxImage', async () => {
vi.stubEnv('QWEN_SANDBOX_IMAGE', 'env-image');
process.argv = ['node', 'script.js', '--sandbox'];
const argv = await parseArguments();
const settings: Settings = {
tools: {
sandbox: true,
sandboxImage: 'settings-image',
},
};
const config = await loadCliConfig(settings, argv, undefined, []);
expect(config.getSandbox()?.image).toBe('env-image');
});
it('uses tools.sandboxImage when cli and env are absent', async () => {
process.argv = ['node', 'script.js', '--sandbox'];
const argv = await parseArguments();
const settings: Settings = {
tools: {
sandbox: true,
sandboxImage: 'settings-image',
},
};
const config = await loadCliConfig(settings, argv, undefined, []);
expect(config.getSandbox()?.image).toBe('settings-image');
});
it('falls back to package default image when no explicit source is provided', async () => {
process.argv = ['node', 'script.js', '--sandbox'];
const argv = await parseArguments();
const settings: Settings = {
tools: {
sandbox: true,
},
};
const config = await loadCliConfig(settings, argv, undefined, []);
expect(config.getSandbox()?.image).toBe('pkg-default-image');
});
});
describe('loadCliConfig runtimeOutputDir', () => {
const originalArgv = process.argv;
const originalRuntimeEnv = process.env['QWEN_RUNTIME_DIR'];