fix(doctor): Windows path compatibility for worktree/branch detection
Three fixes for Windows CI failures: 1. Remove single quotes from git branch --list glob patterns. On Windows, cmd.exe passes single quotes literally to git, preventing glob expansion. Affects shouldUseWorktreeIsolation() and stale branch detection. 2. Extend listWorktrees() branch-name fallback to cover milestone/* branches, not just worktree/* branches. On Windows, path normalization can prevent path-based worktree matching; the branch-name fallback is the safety net. 3. Use path.sep instead of hardcoded "/" in CWD prefix checks (doctor.ts orphan fix guard, worktree-manager.ts removeWorktree guard). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
d27bf45740
commit
954e333228
3 changed files with 15 additions and 7 deletions
|
|
@ -54,7 +54,9 @@ export function shouldUseWorktreeIsolation(basePath: string, overridePrefs?: { i
|
|||
|
||||
// Legacy detection: check for existing gsd/*/* branches (branch-per-slice pattern)
|
||||
try {
|
||||
const output = execSync("git branch --list 'gsd/*/*'", {
|
||||
// Use unquoted glob pattern — single quotes are not interpreted by cmd.exe on Windows,
|
||||
// causing the pattern to match literally instead of as a glob.
|
||||
const output = execSync("git branch --list gsd/*/*", {
|
||||
cwd: basePath,
|
||||
stdio: ["ignore", "pipe", "pipe"],
|
||||
encoding: "utf-8",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { execSync } from "node:child_process";
|
||||
import { existsSync, mkdirSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
import { join, sep } from "node:path";
|
||||
|
||||
import { loadFile, parsePlan, parseRoadmap, parseSummary, saveFile, parseTaskPlanMustHaves, countMustHavesMentionedInSummary } from "./files.js";
|
||||
import { resolveMilestoneFile, resolveMilestonePath, resolveSliceFile, resolveSlicePath, resolveTaskFile, resolveTaskFiles, resolveTasksDir, milestonesDir, gsdRoot, relMilestoneFile, relSliceFile, relTaskFile, relSlicePath, relGsdRootFile, resolveGsdRootFile } from "./paths.js";
|
||||
|
|
@ -511,7 +511,7 @@ async function checkGitHealth(
|
|||
if (shouldFix("orphaned_auto_worktree")) {
|
||||
// Never remove a worktree matching current working directory
|
||||
const cwd = process.cwd();
|
||||
if (wt.path === cwd || cwd.startsWith(wt.path + "/")) {
|
||||
if (wt.path === cwd || cwd.startsWith(wt.path + sep)) {
|
||||
fixesApplied.push(`skipped removing worktree at ${wt.path} (is cwd)`);
|
||||
} else {
|
||||
try {
|
||||
|
|
@ -527,7 +527,9 @@ async function checkGitHealth(
|
|||
|
||||
// ── Stale milestone branches ─────────────────────────────────────────
|
||||
try {
|
||||
const branchOutput = execSync("git branch --list 'milestone/*'", { cwd: basePath, stdio: "pipe" }).toString().trim();
|
||||
// Use unquoted glob — single quotes are not interpreted by cmd.exe on Windows,
|
||||
// causing the pattern to match literally instead of as a glob.
|
||||
const branchOutput = execSync("git branch --list milestone/*", { cwd: basePath, stdio: "pipe" }).toString().trim();
|
||||
if (branchOutput) {
|
||||
const branches = branchOutput.split("\n").map(b => b.trim().replace(/^\*\s*/, "")).filter(Boolean);
|
||||
const worktreeBranches = new Set(milestoneWorktrees.map(wt => wt.branch));
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
import { existsSync, mkdirSync, realpathSync } from "node:fs";
|
||||
import { execSync } from "node:child_process";
|
||||
import { join, resolve } from "node:path";
|
||||
import { join, resolve, sep } from "node:path";
|
||||
|
||||
// ─── Types ─────────────────────────────────────────────────────────────────
|
||||
|
||||
|
|
@ -213,7 +213,11 @@ export function listWorktrees(basePath: string): WorktreeInfo[] {
|
|||
|
||||
const entryPath = wtLine.replace("worktree ", "");
|
||||
const branch = branchLine.replace("branch refs/heads/", "");
|
||||
const branchWorktreeName = branch.startsWith("worktree/") ? branch.slice("worktree/".length) : null;
|
||||
const branchWorktreeName = branch.startsWith("worktree/")
|
||||
? branch.slice("worktree/".length)
|
||||
: branch.startsWith("milestone/")
|
||||
? branch.slice("milestone/".length)
|
||||
: null;
|
||||
const entryVariants = [resolve(entryPath)];
|
||||
if (existsSync(entryPath)) {
|
||||
entryVariants.push(realpathSync(entryPath));
|
||||
|
|
@ -272,7 +276,7 @@ export function removeWorktree(
|
|||
// If we're inside the worktree, move out first — git can't remove an in-use directory
|
||||
const cwd = process.cwd();
|
||||
const resolvedCwd = existsSync(cwd) ? realpathSync(cwd) : cwd;
|
||||
if (resolvedCwd === resolvedWtPath || resolvedCwd.startsWith(resolvedWtPath + "/")) {
|
||||
if (resolvedCwd === resolvedWtPath || resolvedCwd.startsWith(resolvedWtPath + sep)) {
|
||||
process.chdir(basePath);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue