fix(auto): copy planning artifacts into new auto-worktrees (#516)

Auto-worktrees are fresh git checkouts — untracked .gsd/ files don't
carry over. Projects with the old blanket .gsd/ gitignore have planning
artifacts on disk but not in git. When createAutoWorktree makes a new
worktree, the milestones/, DECISIONS.md, REQUIREMENTS.md etc are missing,
causing auto-mode to loop on plan-slice (plan file not found in worktree).

Copy .gsd/ planning artifacts from the source repo into the new worktree
after git worktree add. Skips runtime files and the worktrees/ dir.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
TÂCHES 2026-03-15 15:33:05 -06:00 committed by GitHub
parent b333d450a3
commit 5ae8cf8851

View file

@ -6,7 +6,7 @@
* manages create, enter, detect, and teardown for auto-mode worktrees.
*/
import { existsSync, readFileSync, realpathSync, utimesSync } from "node:fs";
import { existsSync, cpSync, readFileSync, realpathSync, utimesSync } from "node:fs";
import { join, resolve } from "node:path";
import { execSync, execFileSync } from "node:child_process";
import {
@ -90,6 +90,14 @@ export function autoWorktreeBranch(milestoneId: string): string {
export function createAutoWorktree(basePath: string, milestoneId: string): string {
const branch = autoWorktreeBranch(milestoneId);
const info = createWorktree(basePath, milestoneId, { branch });
// Copy .gsd/ planning artifacts from the source repo into the new worktree.
// Worktrees are fresh git checkouts — untracked files don't carry over.
// Planning artifacts may be untracked if the project's .gitignore had a
// blanket .gsd/ rule (pre-v2.14.0). Without this copy, auto-mode loops
// on plan-slice because the plan file doesn't exist in the worktree.
copyPlanningArtifacts(basePath, info.path);
const previousCwd = process.cwd();
try {
@ -107,6 +115,36 @@ export function createAutoWorktree(basePath: string, milestoneId: string): strin
return info.path;
}
/**
* Copy .gsd/ planning artifacts from source repo to a new worktree.
* Copies milestones/, DECISIONS.md, REQUIREMENTS.md, PROJECT.md, QUEUE.md.
* Skips runtime files (auto.lock, metrics.json, etc.) and the worktrees/ dir.
* Best-effort failures are non-fatal since auto-mode can recreate artifacts.
*/
function copyPlanningArtifacts(srcBase: string, wtPath: string): void {
const srcGsd = join(srcBase, ".gsd");
const dstGsd = join(wtPath, ".gsd");
if (!existsSync(srcGsd)) return;
// Copy milestones/ directory (planning files, roadmaps, plans, research)
const srcMilestones = join(srcGsd, "milestones");
if (existsSync(srcMilestones)) {
try {
cpSync(srcMilestones, join(dstGsd, "milestones"), { recursive: true, force: true });
} catch { /* non-fatal */ }
}
// Copy top-level planning files
for (const file of ["DECISIONS.md", "REQUIREMENTS.md", "PROJECT.md", "QUEUE.md"]) {
const src = join(srcGsd, file);
if (existsSync(src)) {
try {
cpSync(src, join(dstGsd, file), { force: true });
} catch { /* non-fatal */ }
}
}
}
/**
* Teardown an auto-worktree: chdir back to original base, then remove
* the worktree and its branch.