Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions LifeOS/install/LIFEOS/TOOLS/lifeos.ts
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,26 @@ function cmdWallpaper(args: string[]) {
}


// True when the current directory is a git repo's MAIN checkout (not a linked
// worktree) AND the repo uses the .claude/worktrees convention. The main checkout
// has --git-dir == --git-common-dir; a linked worktree's --git-dir points into
// .git/worktrees/<name>, so they differ. Used to stop a --local launch from running
// a whole session on whatever branch the root happens to be parked on.
export function inMainCheckoutWithWorktrees(): boolean {
try {
// No --path-format flag → works on any git version; the two paths stay directly
// comparable (both ".git" in a main checkout, divergent in a linked worktree).
const r = spawnSync(["git", "rev-parse", "--git-dir", "--git-common-dir"]);
if (r.exitCode !== 0) return false; // not a git repo
const [gitDir, commonDir] = r.stdout.toString().trim().split("\n");
if (!gitDir || gitDir !== commonDir) return false; // linked worktree → fine
const top = spawnSync(["git", "rev-parse", "--show-toplevel"]).stdout.toString().trim();
return top.length > 0 && existsSync(join(top, ".claude", "worktrees"));
} catch {
return false;
}
}

// ============================================================================
// Commands
// ============================================================================
Expand All @@ -403,6 +423,17 @@ async function cmdLaunch(options: { mcp?: string; resume?: boolean; resumeId?: s
// Algorithm spec is loaded on-demand when Algorithm mode triggers.
// (InstantiatePAI.ts is retired — kept for reference only)

// Guard: --local launches Claude in the CURRENT directory. If that's a repo's main
// checkout (not a worktree) and the repo uses worktrees, the whole session would run
// on whatever stale branch the root is parked on. Refuse unless explicitly overridden.
if (options.local && process.env.LIFEOS_ALLOW_ROOT !== "1" && inMainCheckoutWithWorktrees()) {
error(
"You're in the main checkout root, not a worktree.\n" +
" A --local session here runs on whatever branch the root is parked on.\n" +
" cd into a worktree first, or set LIFEOS_ALLOW_ROOT=1 to override.",
);
}

requireClaudeCli();
displayBanner();
const args = ["claude"];
Expand Down
Loading