feat: implement extensible plan mode with custom directory configuration

- Adds 'general.plan' configuration object for plan settings (directory).
- Updates 'experimental.plan' to a boolean flag for enablement.
- Implements dynamic high-priority policy for custom plan directories in core.
- Adds migration logic for previous configuration formats.
- Updates documentation and schema.
This commit is contained in:
Mahima Shanware
2026-02-17 19:44:19 +00:00
parent e51876b108
commit c1dfcd9a2d
15 changed files with 254 additions and 13 deletions
+9
View File
@@ -833,6 +833,15 @@ export async function loadCliConfig(
enableExtensionReloading: settings.experimental?.extensionReloading,
enableAgents: settings.experimental?.enableAgents,
plan: settings.experimental?.plan,
planDirectory:
settings.general &&
'plan' in settings.general &&
typeof settings.general.plan === 'object' &&
settings.general.plan !== null &&
'directory' in settings.general.plan &&
typeof settings.general.plan.directory === 'string'
? settings.general.plan.directory
: undefined,
enableEventDrivenScheduler: true,
skillsSupport: settings.skills?.enabled ?? true,
disabledSkills: settings.skills?.disabled,
@@ -401,6 +401,18 @@ describe('SettingsSchema', () => {
);
});
it('should have plan config in general schema', () => {
const setting = getSettingsSchema().general.properties.plan;
expect(setting).toBeDefined();
expect(setting.type).toBe('object');
expect(setting.category).toBe('General');
expect(setting.default).toStrictEqual({});
expect(setting.requiresRestart).toBe(false);
expect(setting.showInDialog).toBe(false);
expect(setting.ref).toBe('PlanConfig');
expect(setting.description).toBe('Configuration for planning features.');
});
it('should have hooksConfig.notifications setting in schema', () => {
const setting = getSettingsSchema().hooksConfig?.properties.notifications;
expect(setting).toBeDefined();
+21
View File
@@ -266,6 +266,16 @@ const SETTINGS_SCHEMA = {
},
},
},
plan: {
type: 'object',
label: 'Plan Configuration',
category: 'General',
requiresRestart: false,
default: {},
description: 'Configuration for planning features.',
showInDialog: false,
ref: 'PlanConfig',
},
enablePromptCompletion: {
type: 'boolean',
label: 'Enable Prompt Completion',
@@ -2131,6 +2141,17 @@ export const SETTINGS_SCHEMA_DEFINITIONS: Record<
},
},
},
PlanConfig: {
type: 'object',
description: 'Planning features configuration.',
additionalProperties: false,
properties: {
directory: {
type: 'string',
description: 'Custom directory for implementation plans.',
},
},
},
TelemetrySettings: {
type: 'object',
description: 'Telemetry configuration for Gemini CLI.',
@@ -151,6 +151,7 @@ Implement a comprehensive authentication system with multiple providers.
...options,
config: {
getTargetDir: () => mockTargetDir,
getPlanDirectory: () => mockPlansDir,
getIdeMode: () => false,
isTrustedFolder: () => true,
storage: {
@@ -426,6 +427,7 @@ Implement a comprehensive authentication system with multiple providers.
useAlternateBuffer,
config: {
getTargetDir: () => mockTargetDir,
getPlanDirectory: () => mockPlansDir,
getIdeMode: () => false,
isTrustedFolder: () => true,
storage: {
@@ -65,7 +65,7 @@ function usePlanContent(planPath: string, config: Config): PlanContentState {
try {
const pathError = await validatePlanPath(
planPath,
config.storage.getProjectTempPlansDir(),
config.getPlanDirectory(),
config.getTargetDir(),
);
if (ignore) return;
@@ -83,7 +83,7 @@ function usePlanContent(planPath: string, config: Config): PlanContentState {
const result = await processSingleFileContent(
planPath,
config.storage.getProjectTempPlansDir(),
config.getPlanDirectory(),
config.getFileSystemService(),
);
@@ -45,6 +45,7 @@ describe('ToolConfirmationQueue', () => {
getModel: () => 'gemini-pro',
getDebugMode: () => false,
getTargetDir: () => '/mock/target/dir',
getPlanDirectory: () => '/mock/temp/plans',
getFileSystemService: () => ({
readFile: vi.fn().mockResolvedValue('Plan content'),
}),