Merge pull request #1287 from gsd-build/fix/monorepo-worktree-cwd-preservation-1283

fix: preserve subdirectory CWD in monorepo worktrees
This commit is contained in:
Tom Boucher
2026-03-21 09:28:42 -04:00
committed by GitHub
2 changed files with 46 additions and 4 deletions

View File

@@ -174,11 +174,15 @@ async function main() {
error(`Invalid --cwd: ${cwd}`);
}
// Resolve worktree root: in a linked worktree, .planning/ lives in the main worktree
// Resolve worktree root: in a linked worktree, .planning/ lives in the main worktree.
// However, in monorepo worktrees where the subdirectory itself owns .planning/,
// skip worktree resolution — the CWD is already the correct project root.
const { resolveWorktreeRoot } = require('./lib/core.cjs');
const worktreeRoot = resolveWorktreeRoot(cwd);
if (worktreeRoot !== cwd) {
cwd = worktreeRoot;
if (!fs.existsSync(path.join(cwd, '.planning'))) {
const worktreeRoot = resolveWorktreeRoot(cwd);
if (worktreeRoot !== cwd) {
cwd = worktreeRoot;
}
}
const rawIndex = args.indexOf('--raw');

View File

@@ -1039,6 +1039,44 @@ describe('resolveWorktreeRoot', () => {
});
});
// ─── monorepo worktree CWD preservation (#1283) ─────────────────────────────
describe('monorepo worktree CWD preservation', () => {
const { resolveWorktreeRoot } = require('../get-shit-done/bin/lib/core.cjs');
test('CWD with .planning/ skips worktree resolution (monorepo subdirectory)', () => {
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-monorepo-wt-'));
const subDir = path.join(tmpDir, 'service-alpha');
fs.mkdirSync(path.join(subDir, '.planning'), { recursive: true });
try {
let cwd = subDir;
if (!fs.existsSync(path.join(cwd, '.planning'))) {
const worktreeRoot = resolveWorktreeRoot(cwd);
if (worktreeRoot !== cwd) cwd = worktreeRoot;
}
assert.strictEqual(cwd, subDir, 'CWD with .planning/ must not be overridden by worktree resolution');
} finally {
fs.rmSync(tmpDir, { recursive: true, force: true });
}
});
test('CWD without .planning/ still goes through worktree resolution', () => {
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-monorepo-wt-'));
try {
let cwd = tmpDir;
let worktreeResolutionCalled = false;
if (!fs.existsSync(path.join(cwd, '.planning'))) {
worktreeResolutionCalled = true;
const worktreeRoot = resolveWorktreeRoot(cwd);
if (worktreeRoot !== cwd) cwd = worktreeRoot;
}
assert.ok(worktreeResolutionCalled, 'worktree resolution must be called when .planning/ is absent');
} finally {
fs.rmSync(tmpDir, { recursive: true, force: true });
}
});
});
// ─── withPlanningLock ────────────────────────────────────────────────────────
describe('withPlanningLock', () => {