fix(auto): reverse-sync root-level .gsd files on worktree teardown (#1831)
Add QUEUE.md and completed-units.json to the durable file whitelist in both syncGsdStateToWorktree (forward sync) and syncWorktreeStateBack (reverse sync). These files are written during milestone closeout but were not being copied back to the project root, causing state loss on worktree teardown. Adds regression test verifying both files survive reverse sync. Fixes #1787 Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
f29d54b7e0
commit
72f39b6e23
2 changed files with 71 additions and 1 deletions
|
|
@ -149,13 +149,15 @@ export function syncGsdStateToWorktree(
|
|||
|
||||
if (!existsSync(mainGsd) || !existsSync(wtGsd)) return { synced };
|
||||
|
||||
// Sync root-level .gsd/ files (DECISIONS, REQUIREMENTS, PROJECT, KNOWLEDGE)
|
||||
// Sync root-level .gsd/ files (DECISIONS, REQUIREMENTS, PROJECT, KNOWLEDGE, etc.)
|
||||
const rootFiles = [
|
||||
"DECISIONS.md",
|
||||
"REQUIREMENTS.md",
|
||||
"PROJECT.md",
|
||||
"KNOWLEDGE.md",
|
||||
"OVERRIDES.md",
|
||||
"QUEUE.md",
|
||||
"completed-units.json",
|
||||
];
|
||||
for (const f of rootFiles) {
|
||||
const src = join(mainGsd, f);
|
||||
|
|
@ -303,12 +305,16 @@ export function syncWorktreeStateBack(
|
|||
// ── 1. Sync root-level .gsd/ files back ──────────────────────────────
|
||||
// The worktree is authoritative — complete-milestone updates REQUIREMENTS,
|
||||
// PROJECT, etc. These must overwrite main's copies so they survive teardown.
|
||||
// Also includes QUEUE.md and completed-units.json which are written during
|
||||
// milestone closeout and lost on teardown without explicit sync (#1787).
|
||||
const rootFiles = [
|
||||
"DECISIONS.md",
|
||||
"REQUIREMENTS.md",
|
||||
"PROJECT.md",
|
||||
"KNOWLEDGE.md",
|
||||
"OVERRIDES.md",
|
||||
"QUEUE.md",
|
||||
"completed-units.json",
|
||||
];
|
||||
for (const f of rootFiles) {
|
||||
const src = join(wtGsd, f);
|
||||
|
|
|
|||
|
|
@ -453,6 +453,70 @@ async function main(): Promise<void> {
|
|||
}
|
||||
}
|
||||
|
||||
// ─── 13. syncWorktreeStateBack syncs QUEUE.md and completed-units.json (#1787) ──
|
||||
console.log('\n=== 13. QUEUE.md and completed-units.json synced from worktree (#1787) ===');
|
||||
{
|
||||
const mainBase = mkdtempSync(join(tmpdir(), 'gsd-wt-back-queue-main-'));
|
||||
const wtBase = mkdtempSync(join(tmpdir(), 'gsd-wt-back-queue-wt-'));
|
||||
|
||||
try {
|
||||
mkdirSync(join(mainBase, '.gsd', 'milestones', 'M001'), { recursive: true });
|
||||
mkdirSync(join(wtBase, '.gsd', 'milestones', 'M001'), { recursive: true });
|
||||
|
||||
// Worktree has QUEUE.md and completed-units.json written during milestone closeout
|
||||
writeFileSync(join(wtBase, '.gsd', 'QUEUE.md'), '# Queue\n- M002 next');
|
||||
writeFileSync(
|
||||
join(wtBase, '.gsd', 'completed-units.json'),
|
||||
JSON.stringify({ units: [{ id: 'M001-S01-T01', completed: true }] }),
|
||||
);
|
||||
|
||||
// Main has neither
|
||||
assertTrue(
|
||||
!existsSync(join(mainBase, '.gsd', 'QUEUE.md')),
|
||||
'QUEUE.md missing in main before sync',
|
||||
);
|
||||
assertTrue(
|
||||
!existsSync(join(mainBase, '.gsd', 'completed-units.json')),
|
||||
'completed-units.json missing in main before sync',
|
||||
);
|
||||
|
||||
const { synced } = syncWorktreeStateBack(mainBase, wtBase, 'M001');
|
||||
|
||||
// QUEUE.md should be synced
|
||||
assertTrue(
|
||||
existsSync(join(mainBase, '.gsd', 'QUEUE.md')),
|
||||
'#1787: QUEUE.md synced from worktree to main',
|
||||
);
|
||||
const queueContent = readFileSync(join(mainBase, '.gsd', 'QUEUE.md'), 'utf-8');
|
||||
assertTrue(
|
||||
queueContent.includes('M002 next'),
|
||||
'#1787: QUEUE.md has correct content',
|
||||
);
|
||||
assertTrue(
|
||||
synced.includes('QUEUE.md'),
|
||||
'#1787: QUEUE.md appears in synced list',
|
||||
);
|
||||
|
||||
// completed-units.json should be synced
|
||||
assertTrue(
|
||||
existsSync(join(mainBase, '.gsd', 'completed-units.json')),
|
||||
'#1787: completed-units.json synced from worktree to main',
|
||||
);
|
||||
const cuContent = readFileSync(join(mainBase, '.gsd', 'completed-units.json'), 'utf-8');
|
||||
assertTrue(
|
||||
cuContent.includes('M001-S01-T01'),
|
||||
'#1787: completed-units.json has correct content',
|
||||
);
|
||||
assertTrue(
|
||||
synced.includes('completed-units.json'),
|
||||
'#1787: completed-units.json appears in synced list',
|
||||
);
|
||||
} finally {
|
||||
rmSync(mainBase, { recursive: true, force: true });
|
||||
rmSync(wtBase, { recursive: true, force: true });
|
||||
}
|
||||
}
|
||||
|
||||
report();
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue