diff --git a/packages/cli/src/ui/commands/planCommand.ts b/packages/cli/src/ui/commands/planCommand.ts index b90c74323c..b0d48d107a 100644 --- a/packages/cli/src/ui/commands/planCommand.ts +++ b/packages/cli/src/ui/commands/planCommand.ts @@ -82,7 +82,7 @@ export const planCommand: SlashCommand = { try { const content = await processSingleFileContent( approvedPlanPath, - config.storage.getPlansDir(), + config.getPlansDir(), config.getFileSystemService(), ); const fileName = path.basename(approvedPlanPath); diff --git a/packages/cli/src/ui/components/ExitPlanModeDialog.tsx b/packages/cli/src/ui/components/ExitPlanModeDialog.tsx index 11adf8e82b..69420a1c67 100644 --- a/packages/cli/src/ui/components/ExitPlanModeDialog.tsx +++ b/packages/cli/src/ui/components/ExitPlanModeDialog.tsx @@ -84,7 +84,7 @@ function usePlanContent(planPath: string, config: Config): PlanContentState { try { const pathError = await validatePlanPath( planPath, - config.storage.getPlansDir(), + config.getPlansDir(), ); if (ignore) return; if (pathError) { @@ -101,7 +101,7 @@ function usePlanContent(planPath: string, config: Config): PlanContentState { const result = await processSingleFileContent( planPath, - config.storage.getPlansDir(), + config.getPlansDir(), config.getFileSystemService(), ); diff --git a/packages/core/src/tools/exit-plan-mode.ts b/packages/core/src/tools/exit-plan-mode.ts index 6975b36533..b82b95bc81 100644 --- a/packages/core/src/tools/exit-plan-mode.ts +++ b/packages/core/src/tools/exit-plan-mode.ts @@ -63,20 +63,20 @@ export class ExitPlanModeTool extends BaseDeclarativeTool< if (!params.plan_filename || params.plan_filename.trim() === '') { return 'plan_filename is required.'; } -try { - resolveAndValidatePlanPath( - params.plan_filename, - this.config.getPlansDir(), - ); -} catch (e) { - if (e instanceof Error && e.message.startsWith('Security violation')) { - return `Access denied: plan path (${path.join( - this.config.getPlansDir(), - params.plan_filename, - )}) must be within the designated plans directory (${this.config.getPlansDir()}).`; - } - return e instanceof Error ? e.message : String(e); -} + try { + resolveAndValidatePlanPath( + params.plan_filename, + this.config.getPlansDir(), + ); + } catch (e) { + if (e instanceof Error && e.message.startsWith('Security violation')) { + return `Access denied: plan path (${path.join( + this.config.getPlansDir(), + params.plan_filename, + )}) must be within the designated plans directory (${this.config.getPlansDir()}).`; + } + return e instanceof Error ? e.message : String(e); + } return null; } @@ -184,8 +184,10 @@ export class ExitPlanModeInvocation extends BaseToolInvocation< * Note: Validation is done in validateToolParamValues, so this assumes the path is valid. */ private getResolvedPlanPath(): string { - const safeFilename = path.basename(this.params.plan_filename); - return path.join(this.config.getPlansDir(), safeFilename); + return resolveAndValidatePlanPath( + this.params.plan_filename, + this.config.getPlansDir(), + ); } async execute({ abortSignal: _signal }: ExecuteOptions): Promise { diff --git a/packages/core/src/tools/write-file.ts b/packages/core/src/tools/write-file.ts index e4e7d86933..4f972d8cf1 100644 --- a/packages/core/src/tools/write-file.ts +++ b/packages/core/src/tools/write-file.ts @@ -504,7 +504,7 @@ export class WriteFileTool try { resolvedPath = resolveAndValidatePlanPath( filePath, - this.config.storage.getPlansDir(), + this.config.getPlansDir(), ); } catch (err) { return err instanceof Error ? err.message : String(err);