From 3c51e760f8796200c8f9d7bb1ce1e48309c17707 Mon Sep 17 00:00:00 2001 From: Tom Boucher Date: Sun, 17 May 2026 00:17:31 -0400 Subject: [PATCH] fix(windows): harden nested-root and archive-warning assertions --- get-shit-done/bin/lib/init.cjs | 17 ++++++++++++++++- .../bug-1974-context-exhaustion-record.test.cjs | 13 ++++++++++++- .../bug-3164-milestone-archive-layout.test.cjs | 6 +++--- 3 files changed, 31 insertions(+), 5 deletions(-) diff --git a/get-shit-done/bin/lib/init.cjs b/get-shit-done/bin/lib/init.cjs index 4db7ef0c5..adc32e587 100644 --- a/get-shit-done/bin/lib/init.cjs +++ b/get-shit-done/bin/lib/init.cjs @@ -98,7 +98,22 @@ function getInitGitState(cwd) { return resolved; }; - let inNestedSubdir = info.inside && worktreeRoot !== null; + // Most reliable signal: git reports a non-empty prefix only when cwd is + // below the worktree root. This avoids short/long path alias issues on Windows. + let inNestedSubdir = false; + if (info.inside) { + try { + const prefixResult = execGit(['rev-parse', '--show-prefix'], { cwd, timeout: 5000 }); + if (prefixResult.exitCode === 0) { + inNestedSubdir = String(prefixResult.stdout || '').trim().length > 0; + } else { + inNestedSubdir = worktreeRoot !== null; + } + } catch { + inNestedSubdir = worktreeRoot !== null; + } + } + if (inNestedSubdir) { const rootNorm = normalizeForCompare(worktreeRoot); const cwdNorm = normalizeForCompare(cwd); diff --git a/tests/bug-1974-context-exhaustion-record.test.cjs b/tests/bug-1974-context-exhaustion-record.test.cjs index 507bab80d..3d68a31f6 100644 --- a/tests/bug-1974-context-exhaustion-record.test.cjs +++ b/tests/bug-1974-context-exhaustion-record.test.cjs @@ -100,7 +100,18 @@ describe('#1974 context exhaustion auto-record', () => { }); afterEach(() => { - cleanup(tmpDir); + const sleep = (ms) => Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms); + for (let attempt = 0; attempt < 5; attempt += 1) { + try { + cleanup(tmpDir); + break; + } catch (err) { + const code = err && err.code; + const transient = code === 'EPERM' || code === 'EBUSY' || code === 'ENOTEMPTY'; + if (!transient || attempt === 4) throw err; + sleep(250 * (attempt + 1)); + } + } // Clean up bridge files try { const warnPath = path.join(os.tmpdir(), `claude-ctx-${sessionId}-warned.json`); diff --git a/tests/bug-3164-milestone-archive-layout.test.cjs b/tests/bug-3164-milestone-archive-layout.test.cjs index e91addfb2..d1f07237e 100644 --- a/tests/bug-3164-milestone-archive-layout.test.cjs +++ b/tests/bug-3164-milestone-archive-layout.test.cjs @@ -159,12 +159,12 @@ describe('#3164 — validate consistency: milestone-archive layout', () => { `Old archived milestone phase 64 should not be treated as active:\n ${phase64Warnings.join('\n ')}` ); assert.ok( - warningsPosix.some(w => w.includes('Gap in plan numbering in milestones/v1.7-phases/65-current')), + warningsPosix.some(w => /Gap in plan numbering in .*milestones\/v1\.7-phases\/65-current/.test(w)), `Expected plan numbering warning from active archive root, got:\n ${warnings.join('\n ')}` ); assert.ok( - warningsPosix.some(w => w.includes("milestones/v1.7-phases/65-current/65-01-PLAN.md: missing 'wave'")) - || warningsPosix.some(w => w.includes("milestones/v1.7-phases/65-current/65-03-PLAN.md: missing 'wave'")), + warningsPosix.some(w => /milestones\/v1\.7-phases\/65-current\/65-01-PLAN\.md: missing 'wave'/.test(w)) + || warningsPosix.some(w => /milestones\/v1\.7-phases\/65-current\/65-03-PLAN\.md: missing 'wave'/.test(w)), `Expected frontmatter warning from active archive plans, got:\n ${warnings.join('\n ')}` ); });