Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 20 additions & 24 deletions docs/users/configuration/settings.md

Large diffs are not rendered by default.

49 changes: 49 additions & 0 deletions packages/cli/src/config/config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2409,6 +2409,17 @@ describe('loadCliConfig with includeDirectories', () => {
ToolNames.SHELL,
]);
});

it('should preserve plansDirectory in bare mode', async () => {
process.argv = ['node', 'script.js', '--bare'];
const argv = await parseArguments();
const settings: Settings = {
plansDirectory: './project-plans',
};
const config = await loadCliConfig(settings, argv, undefined, []);

expect(config.getPlansDir()).toContain('project-plans');
});
});

describe('loadCliConfig chatCompression', () => {
Expand Down Expand Up @@ -3393,3 +3404,41 @@ describe('loadCliConfig runtimeOutputDir', () => {
expect(Storage.getRuntimeBaseDir()).toBe(Storage.getGlobalQwenDir());
});
});

describe('loadCliConfig plansDirectory', () => {
const originalArgv = process.argv;

beforeEach(() => {
process.argv = ['node', 'script.js'];
});

afterEach(() => {
process.argv = originalArgv;
vi.restoreAllMocks();
});

it('should resolve relative plansDirectory against cwd', async () => {
const argv = await parseArguments();
const cwd = path.resolve('workspace', 'my-project');
const settings: Settings = {
plansDirectory: './project-plans',
};

const config = await loadCliConfig(settings, argv, cwd);

expect(config.getPlansDir()).toBe(path.join(cwd, 'project-plans'));
expect(config.getPlanFilePath()).toContain(path.join(cwd, 'project-plans'));
});

it('should reject plansDirectory values outside cwd', async () => {
const argv = await parseArguments();
const cwd = path.resolve('workspace', 'my-project');
const settings: Settings = {
plansDirectory: '../plans',
};

await expect(loadCliConfig(settings, argv, cwd)).rejects.toThrow(
'plansDirectory must resolve within the project root',
);
});
});
1 change: 1 addition & 0 deletions packages/cli/src/config/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1685,6 +1685,7 @@ export async function loadCliConfig(
fileFiltering: settings.context?.fileFiltering,
checkpointing:
argv.checkpointing || settings.general?.checkpointing?.enabled,
plansDirectory: settings.plansDirectory,
proxy:
argv.proxy ||
settings.proxy ||
Expand Down
13 changes: 10 additions & 3 deletions packages/cli/src/config/settingsSchema.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@ describe('SettingsSchema', () => {
'ide',
'privacy',
'telemetry',
'proxy',
'model',
'context',
'tools',
'mcp',
'security',
'advanced',
'plansDirectory',
];

expectedSettings.forEach((setting) => {
Expand Down Expand Up @@ -129,6 +129,15 @@ describe('SettingsSchema', () => {
expect(getSettingsSchema().proxy.showInDialog).toBe(false);
});

it('should have plansDirectory setting in schema', () => {
expect(getSettingsSchema().plansDirectory).toBeDefined();
expect(getSettingsSchema().plansDirectory.type).toBe('string');
expect(getSettingsSchema().plansDirectory.category).toBe('Advanced');
expect(getSettingsSchema().plansDirectory.default).toBe(undefined);
expect(getSettingsSchema().plansDirectory.requiresRestart).toBe(true);
expect(getSettingsSchema().plansDirectory.showInDialog).toBe(false);
});

it('should have unique categories', () => {
const categories = new Set();

Expand Down Expand Up @@ -251,15 +260,13 @@ describe('SettingsSchema', () => {
includeDirectories: ['/path/to/dir'],
loadFromIncludeDirectories: true,
},
proxy: 'http://localhost:7890',
};

// TypeScript should not complain about these properties
expect(settings.ui?.theme).toBe('dark');
expect(settings.ui?.renderMode).toBe('raw');
expect(settings.context?.includeDirectories).toEqual(['/path/to/dir']);
expect(settings.context?.loadFromIncludeDirectories).toBe(true);
expect(settings.proxy).toBe('http://localhost:7890');
});

it('should have includeDirectories setting in schema', () => {
Expand Down
11 changes: 11 additions & 0 deletions packages/cli/src/config/settingsSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,17 @@ const SETTINGS_SCHEMA = {
mergeStrategy: MergeStrategy.REPLACE,
},

plansDirectory: {
Comment thread
shenyankm marked this conversation as resolved.
Resolved
type: 'string',
label: 'Plans Directory',
category: 'Advanced',
requiresRestart: true,
default: undefined as string | undefined,
description:
'Custom directory for approved Plan Mode files. Relative paths are resolved from the project root, and the resolved path must stay within the project root. Defaults to ~/.qwen/plans.',
showInDialog: false,
},

// Environment variables fallback
env: {
type: 'object',
Expand Down
Loading
Loading