From 7382437eee63545c772ed1921672ba234eca4d25 Mon Sep 17 00:00:00 2001 From: tt-a1i <53142663+tt-a1i@users.noreply.github.com> Date: Sat, 20 Jun 2026 17:07:58 +0800 Subject: [PATCH] fix(core): allow dot-prefixed plans directories --- packages/core/src/config/storage.test.ts | 6 ++++++ packages/core/src/config/storage.ts | 16 +++++++++++----- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/packages/core/src/config/storage.test.ts b/packages/core/src/config/storage.test.ts index b81278e1554..160bcb74f4a 100644 --- a/packages/core/src/config/storage.test.ts +++ b/packages/core/src/config/storage.test.ts @@ -219,6 +219,12 @@ describe('Storage – getPlansDir', () => { ); }); + it('allows project subdirectories whose names start with two dots', () => { + expect(Storage.getPlansDir(projectRoot, './..plans')).toBe( + path.join(projectRoot, '..plans'), + ); + }); + it('expands tilde in configured plansDirectory values', () => { const projectInHome = path.join(os.homedir(), 'workspace', 'project'); expect( diff --git a/packages/core/src/config/storage.ts b/packages/core/src/config/storage.ts index e7bf967bee4..e47ae7a7d5f 100644 --- a/packages/core/src/config/storage.ts +++ b/packages/core/src/config/storage.ts @@ -23,6 +23,16 @@ const PLANS_DIR_NAME = 'plans'; const DEBUG_DIR_NAME = 'debug'; const ARENA_DIR_NAME = 'arena'; +function isResolvedPathWithinDirectory(childPath: string, parentPath: string) { + const relativePath = path.relative(parentPath, childPath); + return ( + relativePath === '' || + (!relativePath.startsWith(`..${path.sep}`) && + relativePath !== '..' && + !path.isAbsolute(relativePath)) + ); +} + export class Storage { private readonly targetDir: string; @@ -233,11 +243,7 @@ export class Storage { const realParent = Storage.resolvePathThroughExistingAncestor(parentPath); const realChild = Storage.resolvePathThroughExistingAncestor(childPath); - const relativePath = path.relative(realParent, realChild); - return ( - relativePath === '' || - (!relativePath.startsWith('..') && !path.isAbsolute(relativePath)) - ); + return isResolvedPathWithinDirectory(realChild, realParent); } static assertPathWithinDirectory(