@titan-design/worktree 0.1.2 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -256,6 +256,10 @@ interface WorktreeReleaseSafety {
256
256
  /**
257
257
  * Is it safe to destroy this worktree and its branch?
258
258
  *
259
+ * The tree's files go through the same check as park, so a status git cannot
260
+ * read, a hidden untracked file, or an ignored file no build regenerates all
261
+ * count as dirty. A tree already gone from disk has no files left to lose.
262
+ *
259
263
  * With no remote the comparison falls back to the commit the branch forked
260
264
  * from, since treating "no remote" as safe would silently delete every commit
261
265
  * the agent made. Over-refusal is the failure mode we accept: `force` is one
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/allocator.ts
2
- import { existsSync as existsSync4, rmSync as rmSync2 } from "fs";
2
+ import { existsSync as existsSync5, rmSync as rmSync2 } from "fs";
3
3
  import path5 from "path";
4
4
 
5
5
  // src/add.ts
@@ -249,7 +249,7 @@ var OriginUnreachableError = class extends Error {
249
249
  };
250
250
 
251
251
  // src/layout.ts
252
- import { cpSync, lstatSync } from "fs";
252
+ import { cpSync, existsSync as existsSync2, lstatSync } from "fs";
253
253
  import path2 from "path";
254
254
  async function allocatedPaths(gitRoot, basePath) {
255
255
  const out = await gitOrNull(["worktree", "list", "--porcelain"], gitRoot);
@@ -292,12 +292,20 @@ function copyClaudeDir(gitRoot, worktreePath) {
292
292
  `${target} is ${kindOf(existing)} from the branch, so the repository's .claude was not copied in; this agent runs with the branch's .claude`
293
293
  ];
294
294
  }
295
- async function removeWorktree(gitRoot, worktreePath, branch) {
296
- if (await gitOrNull(["worktree", "remove", worktreePath], gitRoot) === null) {
297
- await gitOrNull(["worktree", "remove", "--force", worktreePath], gitRoot);
295
+ async function removeWorktree(gitRoot, worktreePath, branch, opts = {}) {
296
+ const remove = ["worktree", "remove", ...opts.force ? ["--force"] : [], worktreePath];
297
+ try {
298
+ await gitText(remove, gitRoot);
299
+ } catch (err) {
300
+ if (existsSync2(worktreePath)) return `git would not remove ${worktreePath}: ${firstLine(err)}`;
298
301
  }
299
- await gitOrNull(["branch", "-D", branch], gitRoot);
300
302
  await pruneStaleWorktrees(gitRoot);
303
+ await gitOrNull(["branch", "-D", branch], gitRoot);
304
+ return void 0;
305
+ }
306
+ function firstLine(err) {
307
+ const detail = String(err.stderr || err.message).trim();
308
+ return detail.split("\n")[0] ?? detail;
301
309
  }
302
310
 
303
311
  // src/options.ts
@@ -316,7 +324,7 @@ var slug = (name) => name.replace(/[^A-Za-z0-9._-]/g, "-").replace(/^[.-]+/, "")
316
324
  var branchFor = (name, opts = {}) => `${branchPrefixOf(opts)}${slug(name)}`;
317
325
 
318
326
  // src/reattach.ts
319
- import { existsSync as existsSync2 } from "fs";
327
+ import { existsSync as existsSync3 } from "fs";
320
328
  import path4 from "path";
321
329
 
322
330
  // src/setup.ts
@@ -541,10 +549,10 @@ async function originHasBranch(gitRoot, branch, timeoutMs) {
541
549
  return true;
542
550
  } catch (err) {
543
551
  if (err.code === 2) return false;
544
- throw new OriginUnreachableError(branch, firstLine(err));
552
+ throw new OriginUnreachableError(branch, firstLine2(err));
545
553
  }
546
554
  }
547
- var firstLine = (err) => String(err.stderr || err.message).trim().split("\n")[0] ?? "unknown error";
555
+ var firstLine2 = (err) => String(err.stderr || err.message).trim().split("\n")[0] ?? "unknown error";
548
556
  async function branchSource(gitRoot, branch, timeoutMs) {
549
557
  if (await gitOrNull(["rev-parse", "--verify", branch], gitRoot) !== null) return "local";
550
558
  if (await gitOrNull(["remote", "get-url", "origin"], gitRoot) === null) return "fresh";
@@ -563,7 +571,7 @@ async function addForSource(record, source, base, run) {
563
571
  await addWorktree(record.gitRoot, addArgs(record, source, base), run);
564
572
  } catch (err) {
565
573
  const holder = await checkoutOf(record.gitRoot, record.branch);
566
- if (holder !== null || existsSync2(record.worktree))
574
+ if (holder !== null || existsSync3(record.worktree))
567
575
  throw new WorktreeInUseError(record.branch, holder ?? record.worktree);
568
576
  throw err;
569
577
  }
@@ -582,7 +590,7 @@ function checkRecordPlacement(record, basePath) {
582
590
  async function checkReattachable(record, opts) {
583
591
  const { gitRoot, worktree, branch } = record;
584
592
  checkRecordPlacement(record, basePathOf(opts));
585
- if (existsSync2(worktree)) throw new WorktreeInUseError(branch, worktree);
593
+ if (existsSync3(worktree)) throw new WorktreeInUseError(branch, worktree);
586
594
  await pruneStaleWorktrees(gitRoot);
587
595
  const allocated = await allocatedPaths(gitRoot, basePathOf(opts));
588
596
  const budget = budgetOf(opts);
@@ -632,8 +640,27 @@ function recreateWorktree(record, opts = {}) {
632
640
 
633
641
  // src/release-safety.ts
634
642
  import { execFile as execFile3 } from "child_process";
635
- import { existsSync as existsSync3 } from "fs";
643
+ import { existsSync as existsSync4 } from "fs";
636
644
  import { promisify as promisify3 } from "util";
645
+
646
+ // src/unsaved-work.ts
647
+ var REGENERABLE_DIRS = ["node_modules", "dist", "coverage", ".turbo"];
648
+ var isRegenerable = (entry) => {
649
+ const segments = entry.split("/").filter(Boolean);
650
+ return segments[0] === ".claude" || segments.some((segment) => REGENERABLE_DIRS.includes(segment));
651
+ };
652
+ async function unsavedWork(worktree) {
653
+ const status = await gitOrNull(["status", "--porcelain", "-uall"], worktree);
654
+ if (status === null) return `could not read git status in ${worktree}`;
655
+ if (status !== "") return `uncommitted or untracked changes in ${worktree}`;
656
+ const ignored = await gitOrNull(["ls-files", "--others", "--ignored", "--exclude-standard", "--directory"], worktree);
657
+ if (ignored === null) return `could not list ignored files in ${worktree}`;
658
+ const kept = ignored.split("\n").filter((entry) => entry !== "" && !isRegenerable(entry));
659
+ if (kept.length === 0) return void 0;
660
+ return `ignored files in ${worktree} would be deleted (${kept.slice(0, 3).join(", ")}); only ignored ${REGENERABLE_DIRS.join(", ")} and a top-level .claude are removed`;
661
+ }
662
+
663
+ // src/release-safety.ts
637
664
  var execFileAsync3 = promisify3(execFile3);
638
665
  async function landingTargets(gitRoot) {
639
666
  const head = await gitOrNull(["symbolic-ref", "--quiet", "--short", "HEAD"], gitRoot);
@@ -669,8 +696,8 @@ async function ghPrState(gitRoot, branch) {
669
696
  return null;
670
697
  }
671
698
  }
672
- function dirtyCheck(dirty) {
673
- return { name: "dirty", ok: !dirty, detail: dirty ? "uncommitted changes in the worktree" : "worktree clean" };
699
+ function dirtyCheck(unsaved) {
700
+ return { name: "dirty", ok: unsaved === void 0, detail: unsaved ?? "worktree clean" };
674
701
  }
675
702
  function pushedCheck(ahead, compareTo) {
676
703
  if (ahead === null) return { name: "pushed", ok: false, detail: `could not count commits against ${compareTo}` };
@@ -686,9 +713,9 @@ async function commitsAhead(gitRoot, branch, baseRef) {
686
713
  return [count === null ? null : Number.parseInt(count, 10), compareTo];
687
714
  }
688
715
  async function inspectForRelease(gitRoot, worktreePath, branch, baseRef) {
689
- const status = existsSync3(worktreePath) ? await gitOrNull(["status", "--porcelain"], worktreePath) : null;
690
- const dirty = (status ?? "").length > 0;
691
- const checked = [dirtyCheck(dirty)];
716
+ const unsaved = existsSync4(worktreePath) ? await unsavedWork(worktreePath) : void 0;
717
+ const dirty = unsaved !== void 0;
718
+ const checked = [dirtyCheck(unsaved)];
692
719
  if (await gitOrNull(["rev-parse", "--verify", branch], gitRoot) === null)
693
720
  return { dirty, unmerged: false, landed: false, ahead: 0, checked };
694
721
  const [ahead, compareTo] = await commitsAhead(gitRoot, branch, baseRef);
@@ -726,7 +753,7 @@ async function attachWorktree(gitRoot, branch, worktreePath, opts) {
726
753
  return false;
727
754
  }
728
755
  const holder = await checkoutOf(gitRoot, branch);
729
- if (holder !== null || existsSync4(worktreePath)) throw new WorktreeInUseError(branch, holder ?? worktreePath);
756
+ if (holder !== null || existsSync5(worktreePath)) throw new WorktreeInUseError(branch, holder ?? worktreePath);
730
757
  const safety = await inspectForRelease(gitRoot, worktreePath, branch, opts.base);
731
758
  if (safety.unmerged) await addWorktree(gitRoot, ["worktree", "add", worktreePath, branch], opts.run);
732
759
  else await resetTo(gitRoot, branch, worktreePath, opts);
@@ -747,7 +774,7 @@ function recreateAssigned(assigned, record, opts) {
747
774
  }
748
775
  async function adoptAssigned(req, gitRoot, opts) {
749
776
  const assigned = path5.resolve(req.assignedWorktree);
750
- if (!existsSync4(assigned)) return recreateAssigned(assigned, req.assignedRecord, opts);
777
+ if (!existsSync5(assigned)) return recreateAssigned(assigned, req.assignedRecord, opts);
751
778
  const branch = await gitOrNull(["rev-parse", "--abbrev-ref", "HEAD"], assigned) ?? "HEAD";
752
779
  return {
753
780
  cwd: assigned,
@@ -814,8 +841,8 @@ async function release(req, alloc, opts = {}) {
814
841
  const refusal = await refuseRelease(req.exitedAt, { gitRoot, worktree, branch, base: ref.base ?? "HEAD" });
815
842
  if (refusal !== null) return { released: false, refusal };
816
843
  }
817
- await removeWorktree(gitRoot, worktree, branch);
818
- return { released: true };
844
+ const refused = await removeWorktree(gitRoot, worktree, branch, opts);
845
+ return refused === void 0 ? { released: true } : { released: false, refusal: refused };
819
846
  }
820
847
  function createWorktreeAllocator(opts = {}) {
821
848
  return {
@@ -842,23 +869,8 @@ async function offBranch(target) {
842
869
  const where = head === null ? "detached" : `on ${head}`;
843
870
  return `HEAD in ${target.worktree} is ${where}, not on ${target.branch}; check out ${target.branch} first`;
844
871
  }
845
- var REGENERABLE_DIRS = ["node_modules", "dist", "coverage", ".turbo"];
846
- var isRegenerable = (entry) => {
847
- const segments = entry.split("/").filter(Boolean);
848
- return segments[0] === ".claude" || segments.some((segment) => REGENERABLE_DIRS.includes(segment));
849
- };
850
- async function unsaved(worktree) {
851
- const status = await gitOrNull(["status", "--porcelain", "-uall"], worktree);
852
- if (status === null) return `could not read git status in ${worktree}`;
853
- if (status !== "") return `uncommitted or untracked changes in ${worktree}`;
854
- const ignored = await gitOrNull(["ls-files", "--others", "--ignored", "--exclude-standard", "--directory"], worktree);
855
- if (ignored === null) return `could not list ignored files in ${worktree}`;
856
- const kept = ignored.split("\n").filter((entry) => entry !== "" && !isRegenerable(entry));
857
- if (kept.length === 0) return void 0;
858
- return `ignored files in ${worktree} would be deleted (${kept.slice(0, 3).join(", ")}); park removes only ignored ${REGENERABLE_DIRS.join(", ")} and a top-level .claude`;
859
- }
860
872
  async function parkWorktree(target, recheck = () => void 0) {
861
- const refusal = await offBranch(target) ?? await unsaved(target.worktree) ?? await unpushed(target);
873
+ const refusal = await offBranch(target) ?? await unsavedWork(target.worktree) ?? await unpushed(target);
862
874
  if (refusal) return { ok: false, reason: refusal };
863
875
  const head = await gitText(["rev-parse", "HEAD"], target.worktree);
864
876
  const late = recheck();
@@ -911,7 +923,8 @@ async function classify(found, owner, base, now) {
911
923
  if (byOwner) return { ...withAgent, ...byOwner };
912
924
  const safety = await inspectForRelease(found.gitRoot, found.worktree, found.branch, base);
913
925
  if (!safety.dirty && !safety.unmerged) return { ...withAgent, status: "reclaimable", detail: idleDetail(owner) };
914
- const detail = [safety.dirty && "uncommitted changes", safety.unmerged && "commits that exist nowhere else"].filter(Boolean).join(" and ");
926
+ const unsaved = safety.checked.find((check2) => check2.name === "dirty" && !check2.ok)?.detail;
927
+ const detail = [unsaved, safety.unmerged && "commits that exist nowhere else"].filter(Boolean).join(" and ");
915
928
  return { ...withAgent, status: "holds-work", detail };
916
929
  }
917
930
  async function sweepWorktrees(options = {}) {
@@ -931,8 +944,8 @@ async function sweepWorktrees(options = {}) {
931
944
  async function reclaimWorktree(entry, options = {}) {
932
945
  if (entry.status !== "reclaimable" && options.force !== true)
933
946
  return { ok: false, reason: `${entry.branch} is ${entry.status}: ${entry.detail}` };
934
- await removeWorktree(entry.gitRoot, entry.worktree, entry.branch);
935
- return { ok: true };
947
+ const refused = await removeWorktree(entry.gitRoot, entry.worktree, entry.branch, options);
948
+ return refused === void 0 ? { ok: true } : { ok: false, reason: refused };
936
949
  }
937
950
  export {
938
951
  BRANCH_PREFIX,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/allocator.ts","../src/add.ts","../src/git.ts","../src/process-group.ts","../src/branch-base.ts","../src/errors.ts","../src/layout.ts","../src/options.ts","../src/reattach.ts","../src/setup.ts","../src/release-safety.ts","../src/park.ts","../src/sweep.ts"],"sourcesContent":["import { existsSync, rmSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { addWorktree, boundedAdd, WORKTREE_ADD_TIMEOUT_MS, type WorktreeAddRunner } from \"./add.js\";\nimport { resolveBranchBase } from \"./branch-base.js\";\nimport { WorktreeBudgetExhaustedError, WorktreeInUseError } from \"./errors.js\";\nimport { findGitRoot, gitOrNull } from \"./git.js\";\nimport { allocatedPaths, checkoutOf, copyClaudeDir, pruneStaleWorktrees, removeWorktree } from \"./layout.js\";\nimport {\n basePathOf,\n branchFor,\n budgetOf,\n DEFAULT_FETCH_TIMEOUT_MS,\n RECLAIM_GRACE_MS,\n slug,\n type WorktreeOptions,\n} from \"./options.js\";\nimport { readoptWorktree, setupTarget, type WorktreeAllocation, type WorktreeRecord } from \"./reattach.js\";\nimport { describeRefusal, inspectForRelease } from \"./release-safety.js\";\nimport { runWorktreeSetup } from \"./setup.js\";\n\n/** One agent's request for a worktree. A caller's richer context record satisfies it structurally. */\nexport interface WorktreeRequest {\n agentName: string;\n baseCwd: string;\n /**\n * A worktree the caller assigned. It is ADOPTED instead of allocated: no\n * branch is created, no budget slot is taken, and release leaves it alone.\n */\n assignedWorktree?: string;\n /** The caller's record of allocating `assignedWorktree`, which re-creates it if it was removed. */\n assignedRecord?: WorktreeRecord;\n /** When the agent exited; anchors the reclaim grace window. */\n exitedAt?: number;\n /** Discard a leftover branch instead of adopting it. Allocation can destroy commits as release can. */\n forceReset?: boolean;\n}\n\nexport interface WorktreeCheck {\n /** Reasons the allocation would fail. */\n refusals: string[];\n /** Advisory lines; allocation proceeds. */\n warnings: string[];\n}\n\nexport type WorktreeReleaseOutcome = { released: true } | { released: false; refusal: string };\n\nexport interface WorktreeAllocator {\n check(req: WorktreeRequest): Promise<WorktreeCheck>;\n allocate(req: WorktreeRequest): Promise<WorktreeAllocation>;\n /** A refusal (dirty, unmerged, inside the grace window) leaves everything on disk. */\n release(\n req: Pick<WorktreeRequest, \"exitedAt\">,\n alloc: { ref?: Record<string, string> },\n opts?: { force?: boolean }\n ): Promise<WorktreeReleaseOutcome>;\n}\n\ninterface AttachOptions {\n base: string;\n force: boolean;\n run?: WorktreeAddRunner | undefined;\n}\n\nasync function resetTo(gitRoot: string, branch: string, worktreePath: string, opts: AttachOptions): Promise<void> {\n await gitOrNull([\"worktree\", \"remove\", \"--force\", worktreePath], gitRoot);\n rmSync(worktreePath, { recursive: true, force: true });\n await gitOrNull([\"branch\", \"-D\", branch], gitRoot);\n await addWorktree(gitRoot, [\"worktree\", \"add\", \"-b\", branch, worktreePath, opts.base], opts.run);\n}\n\n/**\n * Attach a worktree for `branch`, and return whether an existing branch was adopted.\n *\n * The crash path: an agent commits, then dies without ever calling release. Its\n * directory is gone but the branch holds the only copy of those commits, so an\n * unconditional `branch -D` here would make them unreachable. Adopting beats\n * refusing: a respawn under the same name IS that agent continuing. A branch\n * holding nothing worth keeping is still reset, so it does not inherit a stale base.\n */\nasync function attachWorktree(\n gitRoot: string,\n branch: string,\n worktreePath: string,\n opts: AttachOptions\n): Promise<boolean> {\n if ((await gitOrNull([\"rev-parse\", \"--verify\", branch], gitRoot)) === null) {\n await addWorktree(gitRoot, [\"worktree\", \"add\", \"-b\", branch, worktreePath, opts.base], opts.run);\n return false;\n }\n if (opts.force) {\n await resetTo(gitRoot, branch, worktreePath, opts);\n return false;\n }\n const holder = await checkoutOf(gitRoot, branch);\n if (holder !== null || existsSync(worktreePath)) throw new WorktreeInUseError(branch, holder ?? worktreePath);\n\n const safety = await inspectForRelease(gitRoot, worktreePath, branch, opts.base);\n if (safety.unmerged) await addWorktree(gitRoot, [\"worktree\", \"add\", worktreePath, branch], opts.run);\n else await resetTo(gitRoot, branch, worktreePath, opts);\n return safety.unmerged;\n}\n\n/** Null when release may proceed, otherwise the reason it may not. */\nasync function refuseRelease(\n exitedAt: number | undefined,\n ref: { gitRoot: string; worktree: string; branch: string; base: string }\n): Promise<string | null> {\n if (exitedAt !== undefined && Date.now() - exitedAt < RECLAIM_GRACE_MS)\n return `agent exited less than ${RECLAIM_GRACE_MS / 1000}s ago; inside the reclaim grace window`;\n const safety = await inspectForRelease(ref.gitRoot, ref.worktree, ref.branch, ref.base);\n return safety.dirty || safety.unmerged ? describeRefusal(safety) : null;\n}\n\n/** A gone assigned tree comes back only from the caller's record of allocating it. */\nfunction recreateAssigned(\n assigned: string,\n record: WorktreeRecord | undefined,\n opts: WorktreeOptions\n): Promise<WorktreeAllocation> {\n if (record === undefined || path.resolve(record.worktree) !== assigned)\n throw new Error(\n `assigned worktree ${assigned} does not exist, and there is no record of allocating it ` +\n \"to re-create it from. Not spawned\"\n );\n return readoptWorktree(record, opts);\n}\n\nasync function adoptAssigned(\n req: WorktreeRequest,\n gitRoot: string,\n opts: WorktreeOptions\n): Promise<WorktreeAllocation> {\n const assigned = path.resolve(req.assignedWorktree as string);\n if (!existsSync(assigned)) return recreateAssigned(assigned, req.assignedRecord, opts);\n const branch = (await gitOrNull([\"rev-parse\", \"--abbrev-ref\", \"HEAD\"], assigned)) ?? \"HEAD\";\n return {\n cwd: assigned,\n note: `You are in a worktree assigned to this task at ${assigned}, on branch ${branch}. You may be sharing it with other agents, so stay inside the paths you were given.`,\n ref: { branch, worktree: assigned, gitRoot, assigned: \"true\" },\n };\n}\n\nasync function check(req: WorktreeRequest, opts: WorktreeOptions): Promise<WorktreeCheck> {\n const gitRoot = await findGitRoot(req.baseCwd);\n if (gitRoot === null)\n return { refusals: [`${req.baseCwd} is not a git repository; worktree isolation needs one`], warnings: [] };\n\n await pruneStaleWorktrees(gitRoot);\n const allocated = await allocatedPaths(gitRoot, basePathOf(opts));\n const budget = budgetOf(opts);\n const refusals =\n allocated.length >= budget\n ? [`worktree budget exhausted: ${allocated.length}/${budget} allocated under ${basePathOf(opts)}`]\n : [];\n const branch = branchFor(req.agentName, opts);\n const exists = (await gitOrNull([\"rev-parse\", \"--verify\", branch], gitRoot)) !== null;\n const warnings = exists\n ? [`branch ${branch} already exists; it will be adopted if it holds commits, reset if it does not`]\n : [];\n return { refusals, warnings };\n}\n\nasync function allocate(req: WorktreeRequest, opts: WorktreeOptions): Promise<WorktreeAllocation> {\n const gitRoot = await findGitRoot(req.baseCwd);\n if (gitRoot === null) throw new Error(`${req.baseCwd} is not a git repository`);\n if (req.assignedWorktree !== undefined) return adoptAssigned(req, gitRoot, opts);\n\n await pruneStaleWorktrees(gitRoot);\n const allocated = await allocatedPaths(gitRoot, basePathOf(opts));\n const budget = budgetOf(opts);\n if (allocated.length >= budget) throw new WorktreeBudgetExhaustedError(allocated.length, budget);\n\n const branch = branchFor(req.agentName, opts);\n const worktreePath = path.resolve(gitRoot, basePathOf(opts), slug(req.agentName));\n const base = await resolveBranchBase(gitRoot, opts.fetchTimeoutMs ?? DEFAULT_FETCH_TIMEOUT_MS);\n const reused = await attachWorktree(gitRoot, branch, worktreePath, {\n base: base.sha,\n force: req.forceReset === true,\n run: boundedAdd(opts.runWorktreeAdd, opts.addTimeoutMs ?? WORKTREE_ADD_TIMEOUT_MS),\n });\n const warnings = [\n ...copyClaudeDir(gitRoot, worktreePath),\n ...(base.warning === undefined ? [] : [base.warning]),\n ...(await runWorktreeSetup(setupTarget(gitRoot, worktreePath, base), opts.runSetup)),\n ];\n const carried = reused ? \" It already carries commits from an earlier run under this name.\" : \"\";\n return {\n cwd: worktreePath,\n note: `You are on branch ${branch} in an isolated worktree at ${worktreePath}.${carried} Commit your work there; nothing outside it is yours to change.`,\n ref: {\n branch,\n worktree: worktreePath,\n gitRoot,\n base: base.sha,\n base_ref: base.ref,\n ...(reused ? { reused: \"true\" } : {}),\n },\n ...(warnings.length === 0 ? {} : { warnings }),\n };\n}\n\nasync function release(\n req: Pick<WorktreeRequest, \"exitedAt\">,\n alloc: { ref?: Record<string, string> },\n opts: { force?: boolean } = {}\n): Promise<WorktreeReleaseOutcome> {\n const ref = alloc.ref;\n if (!ref?.branch || !ref.worktree || !ref.gitRoot)\n return { released: false, refusal: \"allocation carries no worktree reference\" };\n const { branch, worktree, gitRoot } = ref;\n\n // An assigned tree belongs to whoever assigned it and may be shared, so even\n // `force` leaves it: force discards THIS agent's commits, not someone else's tree.\n if (ref.assigned === \"true\") return { released: true };\n\n if (!opts.force) {\n const refusal = await refuseRelease(req.exitedAt, { gitRoot, worktree, branch, base: ref.base ?? \"HEAD\" });\n if (refusal !== null) return { released: false, refusal };\n }\n await removeWorktree(gitRoot, worktree, branch);\n return { released: true };\n}\n\n/** Worktree isolation for agents: one branch and one directory per agent name, under a per-repo budget. */\nexport function createWorktreeAllocator(opts: WorktreeOptions = {}): WorktreeAllocator {\n return {\n check: (req) => check(req, opts),\n allocate: (req) => allocate(req, opts),\n release,\n };\n}\n","import { spawn } from \"node:child_process\";\nimport { existsSync, rmSync } from \"node:fs\";\nimport { gitChildEnv, gitOrNull, gitText } from \"./git.js\";\nimport { groupAlive, signalGroup } from \"./process-group.js\";\n\n/** Runs one `git worktree add`, resolving to its output and rejecting on failure. */\nexport type WorktreeAddRunner = (args: readonly string[], cwd: string) => Promise<string>;\n\n/** Five minutes: a cold checkout of a multi-gigabyte repo takes tens of seconds, so only a hang reaches it. */\nexport const WORKTREE_ADD_TIMEOUT_MS = 300_000;\n\nconst CLEANUP_TIMEOUT_MS = 30_000;\n/** SIGTERM first so git can drop its lock files; SIGKILL follows for whatever ignores it. */\nconst TERM_GRACE_MS = 1_000;\n\n/** The tail of each repo's queue of `worktree add`s; it never rejects, so one failure does not jam the rest. */\nconst addQueues = new Map<string, Promise<unknown>>();\n\n/** Concurrent adds in one repo read each other's half-written `.git/worktrees/<name>/commondir` and die. */\nexport function addWorktree(\n gitRoot: string,\n args: readonly string[],\n run: WorktreeAddRunner = gitText\n): Promise<string> {\n const adding = (addQueues.get(gitRoot) ?? Promise.resolve()).then(() => run(args, gitRoot));\n const tail = adding.catch(() => undefined);\n addQueues.set(gitRoot, tail);\n void tail.then(() => addQueues.get(gitRoot) === tail && addQueues.delete(gitRoot));\n return adding;\n}\n\nconst addTarget = (args: readonly string[]): string | undefined => (args[2] === \"-b\" ? args[4] : args[2]);\n\nclass AddTimedOut extends Error {}\n\nasync function reapGroup(pid: number): Promise<void> {\n signalGroup(pid, \"SIGKILL\");\n for (let i = 0; i < 100 && groupAlive(pid); i++) await new Promise((r) => setTimeout(r, 20));\n}\n\nfunction settleAdd(code: number | null, out: string, err: string): Error | string {\n if (code === 0) return out.trim();\n return Object.assign(new Error(err.trim() || `git exited with code ${code}`), { code, stderr: err });\n}\n\n/**\n * Run git in its own process group, so a timeout can kill the hooks and filters\n * it spawned and not only git itself. Settles only after the child has exited and\n * the group is reaped, so cleanup never races a process that can still write.\n */\nfunction gitInGroup(args: readonly string[], cwd: string, timeoutMs: number): Promise<string> {\n return new Promise((resolve, reject) => {\n const child = spawn(\"git\", [...args], { cwd, env: gitChildEnv(), detached: true });\n const pid = child.pid;\n let out = \"\";\n let err = \"\";\n let timedOut = false;\n child.stdout.on(\"data\", (chunk) => (out += chunk));\n child.stderr.on(\"data\", (chunk) => (err += chunk));\n const term = setTimeout(() => {\n timedOut = true;\n if (pid !== undefined) signalGroup(pid, \"SIGTERM\");\n }, timeoutMs);\n const kill = setTimeout(() => pid !== undefined && signalGroup(pid, \"SIGKILL\"), timeoutMs + TERM_GRACE_MS);\n child.on(\"error\", reject);\n child.on(\"close\", (code) => {\n clearTimeout(term);\n clearTimeout(kill);\n void (pid === undefined ? Promise.resolve() : reapGroup(pid)).then(() => {\n const settled = timedOut ? new AddTimedOut() : settleAdd(code, out, err);\n if (typeof settled === \"string\") resolve(settled);\n else reject(settled);\n });\n });\n });\n}\n\n/**\n * A timed-out add can leave a half-written directory and a registration under\n * `.git/worktrees`. Only a directory the add itself created is removed: one that\n * existed beforehand belongs to someone else. The branch a `-b` add created is\n * kept, since it holds no commits and the next attach resets it.\n */\nasync function discardHalfCreated(gitRoot: string, args: readonly string[], created: boolean): Promise<void> {\n const target = addTarget(args);\n if (created && target !== undefined) {\n await gitOrNull([\"worktree\", \"remove\", \"--force\", target], gitRoot, CLEANUP_TIMEOUT_MS);\n rmSync(target, { recursive: true, force: true });\n }\n await gitOrNull([\"worktree\", \"prune\"], gitRoot, CLEANUP_TIMEOUT_MS);\n}\n\n/** The newest add per path; a late finisher only cleans up if no later add has taken the path since. */\nconst latestAdd = new Map<string, object>();\n\n/** One hung add (a hook, a filter) must not hold the repo's queue forever. */\nexport function boundedAdd(run: WorktreeAddRunner | undefined, timeoutMs: number): WorktreeAddRunner {\n return async (args, cwd) => {\n const target = addTarget(args);\n const created = target !== undefined && !existsSync(target);\n const mine = {};\n if (target !== undefined) latestAdd.set(target, mine);\n const timedOut = new Error(`git worktree add in ${cwd} timed out after ${timeoutMs}ms and was killed`);\n try {\n return await (run === undefined\n ? gitInGroup(args, cwd, timeoutMs)\n : raceTimer(run(args, cwd), timeoutMs, () => cleanLate(cwd, args, created, mine)));\n } catch (err) {\n if (!(err instanceof AddTimedOut)) throw err;\n await discardHalfCreated(cwd, args, created);\n throw timedOut;\n }\n };\n}\n\nasync function cleanLate(cwd: string, args: readonly string[], created: boolean, mine: object): Promise<void> {\n const target = addTarget(args);\n if (target === undefined || latestAdd.get(target) !== mine) return;\n await discardHalfCreated(cwd, args, created);\n}\n\nasync function raceTimer(add: Promise<string>, timeoutMs: number, onLate: () => Promise<void>): Promise<string> {\n let timer: NodeJS.Timeout | undefined;\n const expired = new Promise<never>((_, reject) => {\n timer = setTimeout(() => reject(new AddTimedOut()), timeoutMs);\n });\n try {\n return await Promise.race([add, expired]);\n } catch (err) {\n if (err instanceof AddTimedOut) void add.then(onLate, () => undefined);\n throw err;\n } finally {\n clearTimeout(timer);\n }\n}\n","import { execFile } from \"node:child_process\";\nimport path from \"node:path\";\nimport { promisify } from \"node:util\";\n\nconst execFileAsync = promisify(execFile);\n\n/**\n * One `git` invocation, returning null rather than throwing.\n *\n * git failures are routine control flow here: \"is this a repository at all\" is\n * a failing command, and every caller treats a miss as an answer. Injectable so\n * tests of callers never shell out.\n */\nexport type GitRunner = (args: readonly string[], cwd: string) => Promise<string | null>;\n\n/** A git child that inherits a dispatcher's identity variables can register as the agent that spawned it. */\nexport const DEFAULT_STRIPPED_ENV_PREFIXES: readonly string[] = [\"AGENT_CHAT_\"];\n\nexport function gitChildEnv(\n env: NodeJS.ProcessEnv = process.env,\n stripPrefixes: readonly string[] = DEFAULT_STRIPPED_ENV_PREFIXES\n): NodeJS.ProcessEnv {\n const out: NodeJS.ProcessEnv = { ...env, GIT_TERMINAL_PROMPT: \"0\" };\n for (const key of Object.keys(out)) {\n if (stripPrefixes.some((prefix) => key.startsWith(prefix))) delete out[key];\n }\n return out;\n}\n\n/** Throws on a non-zero exit; `stderr` and `code` ride on the error. */\nexport async function gitText(args: readonly string[], cwd: string, timeout?: number): Promise<string> {\n const { stdout } = await execFileAsync(\"git\", [...args], {\n cwd,\n encoding: \"utf8\",\n env: gitChildEnv(),\n ...(timeout === undefined ? {} : { timeout }),\n });\n return stdout.trim();\n}\n\nexport async function gitOrNull(args: readonly string[], cwd: string, timeout?: number): Promise<string | null> {\n try {\n return await gitText(args, cwd, timeout);\n } catch {\n return null;\n }\n}\n\nexport const runGit: GitRunner = (args, cwd) => gitOrNull(args, cwd);\n\n/**\n * The true repository root, resolved through worktrees.\n *\n * `--git-common-dir` rather than `--show-toplevel`: from inside a worktree the\n * toplevel is that worktree, and allocating from it would nest worktrees.\n */\nexport async function findGitRoot(cwd: string, git: GitRunner = runGit): Promise<string | null> {\n const commonDir = await git([\"rev-parse\", \"--path-format=absolute\", \"--git-common-dir\"], cwd);\n return commonDir === null ? null : path.dirname(commonDir);\n}\n\n/** Where a process is observably running, as git sees it, as opposed to what it says about itself. */\nexport interface GitPresence {\n gitBranch?: string;\n /** The checkout this process's files live in. */\n worktreePath?: string;\n /** The repository behind the checkout; two worktrees of one repo share it. */\n repoPath?: string;\n isLinkedWorktree?: boolean;\n}\n\n/**\n * Undefined outside a git repository. The toplevel and the common dir answer\n * different questions: when they disagree, this is a linked worktree.\n */\nexport async function observedPresence(cwd: string, git: GitRunner = runGit): Promise<GitPresence | undefined> {\n const [branch, toplevel, commonDir, gitDir] = await Promise.all([\n git([\"rev-parse\", \"--abbrev-ref\", \"HEAD\"], cwd),\n git([\"rev-parse\", \"--show-toplevel\"], cwd),\n git([\"rev-parse\", \"--path-format=absolute\", \"--git-common-dir\"], cwd),\n git([\"rev-parse\", \"--path-format=absolute\", \"--git-dir\"], cwd),\n ]);\n if (toplevel === null && commonDir === null) return undefined;\n\n const observed: GitPresence = {\n // 'HEAD' means detached, which is not a branch name.\n ...(branch !== null && branch !== \"\" && branch !== \"HEAD\" ? { gitBranch: branch } : {}),\n ...(toplevel === null || toplevel === \"\" ? {} : { worktreePath: toplevel }),\n ...(commonDir === null ? {} : { repoPath: path.dirname(path.resolve(commonDir)) }),\n ...(commonDir === null || gitDir === null\n ? {}\n : { isLinkedWorktree: path.resolve(commonDir) !== path.resolve(gitDir) }),\n };\n return Object.keys(observed).length === 0 ? undefined : observed;\n}\n","export const groupAlive = (pid: number): boolean => {\n try {\n process.kill(-pid, 0);\n return true;\n } catch {\n return false;\n }\n};\n\nexport const signalGroup = (pid: number, signal: NodeJS.Signals): void => {\n try {\n process.kill(-pid, signal);\n } catch {\n // The group is already gone.\n }\n};\n","import { gitOrNull } from \"./git.js\";\n\n/** The commit a new branch is cut from, the ref it was read from, and a warning when that ref is not origin's. */\nexport interface BranchBase {\n sha: string;\n ref: string;\n warning?: string;\n}\n\n/** origin/HEAD when this clone knows it; otherwise the two conventional names, in order. */\nasync function defaultBranchCandidates(gitRoot: string): Promise<string[]> {\n const head = await gitOrNull([\"symbolic-ref\", \"--quiet\", \"--short\", \"refs/remotes/origin/HEAD\"], gitRoot);\n return head?.startsWith(\"origin/\") ? [head.slice(\"origin/\".length)] : [\"main\", \"master\"];\n}\n\n/** Fetch only: it moves a remote-tracking ref and never the main checkout's HEAD or files. */\nexport async function fetchTip(gitRoot: string, branch: string, timeoutMs: number): Promise<string | null> {\n const tracking = `refs/remotes/origin/${branch}`;\n const fetched = await gitOrNull(\n [\"fetch\", \"--quiet\", \"--no-tags\", \"origin\", `+refs/heads/${branch}:${tracking}`],\n gitRoot,\n timeoutMs\n );\n return fetched === null ? null : gitOrNull([\"rev-parse\", \"--verify\", `${tracking}^{commit}`], gitRoot);\n}\n\n/** The timeout is one budget shared by every candidate, not one per candidate. */\nasync function fetchDefaultTip(gitRoot: string, timeoutMs: number): Promise<BranchBase | string> {\n if ((await gitOrNull([\"remote\", \"get-url\", \"origin\"], gitRoot)) === null)\n return \"the repository has no origin remote\";\n const deadline = Date.now() + timeoutMs;\n const candidates = await defaultBranchCandidates(gitRoot);\n for (const branch of candidates) {\n const remaining = deadline - Date.now();\n if (remaining <= 0) break;\n const sha = await fetchTip(gitRoot, branch, remaining);\n if (sha !== null) return { sha, ref: `origin/${branch}` };\n }\n return `fetching ${candidates.map((b) => `origin/${b}`).join(\" or \")} failed or timed out`;\n}\n\n/** Concurrent fetches of one ref race on its lock and the loser fails, so allocations in a repo share one. */\nconst inflightBases = new Map<string, Promise<BranchBase>>();\n\n/**\n * The main checkout's HEAD may lag origin or hold another session's unpushed\n * commits, and a branch cut from it ships both. So cut from a fresh fetch of\n * origin's default branch, and say so loudly when that is impossible.\n */\nexport function resolveBranchBase(gitRoot: string, timeoutMs: number): Promise<BranchBase> {\n const pending = inflightBases.get(gitRoot);\n if (pending !== undefined) return pending;\n const resolving = resolveBranchBaseNow(gitRoot, timeoutMs).finally(() => inflightBases.delete(gitRoot));\n inflightBases.set(gitRoot, resolving);\n return resolving;\n}\n\nasync function resolveBranchBaseNow(gitRoot: string, timeoutMs: number): Promise<BranchBase> {\n const reason = await fetchDefaultTip(gitRoot, timeoutMs);\n if (typeof reason !== \"string\") return reason;\n const sha = (await gitOrNull([\"rev-parse\", \"HEAD\"], gitRoot)) ?? \"HEAD\";\n return {\n sha,\n ref: \"HEAD\",\n warning:\n `worktree branched from the local HEAD at ${sha} because ${reason}; ` +\n \"it may lag origin or carry unpushed commits\",\n };\n}\n","export class WorktreeBudgetExhaustedError extends Error {\n constructor(readonly allocated: number, readonly budget: number) {\n super(`Worktree budget exhausted: ${allocated}/${budget} allocated`);\n this.name = \"WorktreeBudgetExhaustedError\";\n }\n}\n\n/**\n * Adoption is impossible: something is still holding the branch or the path.\n *\n * Distinct from \"the branch holds work\", which is recoverable by adopting it.\n * This one means a live agent of the same name already has the worktree, or a\n * directory is sitting in the way: cases where proceeding would clobber files\n * nobody has agreed to lose.\n */\nexport class WorktreeInUseError extends Error {\n constructor(readonly branch: string, readonly worktreePath: string) {\n super(\n `${worktreePath} is still on disk and holds branch ${branch}. Another agent of this name may be ` +\n \"live. Release it, spawn under a different name, or force the allocation to discard it.\"\n );\n this.name = \"WorktreeInUseError\";\n }\n}\n\n/** Origin could not answer whether it holds the branch, so a fresh fork might discard real work. */\nexport class OriginUnreachableError extends Error {\n constructor(readonly branch: string, detail: string) {\n super(\n `cannot reach origin to look for branch ${branch} (${detail}); it may still hold the agent's work, ` +\n \"so the worktree was not re-created. Fix the remote and resume again.\"\n );\n this.name = \"OriginUnreachableError\";\n }\n}\n","import { cpSync, lstatSync, type Stats } from \"node:fs\";\nimport path from \"node:path\";\nimport { gitOrNull } from \"./git.js\";\n\n/** Live worktrees under basePath, from git itself rather than a parallel table. */\nexport async function allocatedPaths(gitRoot: string, basePath: string): Promise<string[]> {\n const out = await gitOrNull([\"worktree\", \"list\", \"--porcelain\"], gitRoot);\n if (out === null) return [];\n const base = path.resolve(gitRoot, basePath) + path.sep;\n return out\n .split(\"\\n\")\n .filter((line) => line.startsWith(\"worktree \"))\n .map((line) => path.resolve(line.slice(\"worktree \".length).trim()))\n .filter((dir) => dir.startsWith(base));\n}\n\n/**\n * Drop registrations whose directory is gone from disk, so a machine that was\n * rebooted mid-run does not permanently hold budget it is not using.\n */\nexport async function pruneStaleWorktrees(gitRoot: string): Promise<void> {\n await gitOrNull([\"worktree\", \"prune\"], gitRoot);\n}\n\n/** The worktree currently holding `branch`, or null. Prune first, or this lies. */\nexport async function checkoutOf(gitRoot: string, branch: string): Promise<string | null> {\n const out = (await gitOrNull([\"worktree\", \"list\", \"--porcelain\"], gitRoot)) ?? \"\";\n const holder = out.split(\"\\n\\n\").find((block) => block.includes(`branch refs/heads/${branch}`));\n const line = holder?.split(\"\\n\").find((l) => l.startsWith(\"worktree \"));\n return line ? path.resolve(line.slice(\"worktree \".length).trim()) : null;\n}\n\nfunction lstatOrNull(target: string): Stats | null {\n try {\n return lstatSync(target);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return null;\n throw error;\n }\n}\n\nfunction kindOf(stat: Stats): string {\n if (stat.isSymbolicLink()) return \"a symlink\";\n if (stat.isDirectory()) return \"a directory\";\n return stat.isFile() ? \"a file\" : \"not a regular file\";\n}\n\n/**\n * Hooks and settings live in gitignored .claude/, so a fresh worktree runs unhooked without this.\n * The target is branch-controlled: lstat it, since a committed symlink would let the copy write\n * outside the tree. Anything already there is kept and reported as a warning.\n */\nexport function copyClaudeDir(gitRoot: string, worktreePath: string): string[] {\n const source = path.resolve(gitRoot, \".claude\");\n const target = path.resolve(worktreePath, \".claude\");\n if (lstatOrNull(source) === null) return [];\n const existing = lstatOrNull(target);\n if (existing === null) {\n cpSync(source, target, { recursive: true });\n return [];\n }\n return [\n `${target} is ${kindOf(existing)} from the branch, so the repository's .claude was not copied in; this agent runs with the branch's .claude`,\n ];\n}\n\n/** Remove the tree and its branch. Callers decide first whether anything would be lost. */\nexport async function removeWorktree(gitRoot: string, worktreePath: string, branch: string): Promise<void> {\n if ((await gitOrNull([\"worktree\", \"remove\", worktreePath], gitRoot)) === null) {\n await gitOrNull([\"worktree\", \"remove\", \"--force\", worktreePath], gitRoot);\n }\n await gitOrNull([\"branch\", \"-D\", branch], gitRoot);\n await pruneStaleWorktrees(gitRoot);\n}\n","import type { WorktreeAddRunner } from \"./add.js\";\nimport type { SetupRunner } from \"./setup.js\";\n\nexport const DEFAULT_WORKTREE_BUDGET = 3;\nexport const DEFAULT_BASE_PATH = \".worktrees\";\n/** Ownership marker: the sweep treats only branches carrying this prefix as its own. */\nexport const BRANCH_PREFIX = \"agent-chat/\";\nexport const DEFAULT_FETCH_TIMEOUT_MS = 15_000;\n\n/**\n * Grace window between an agent exiting and its worktree becoming reclaimable.\n *\n * It guards the window between an agent exiting and a human noticing the\n * unpushed commits it left behind. Release does `git branch -D`, so reclaiming\n * inside that window turns \"I'll look at it in a minute\" into a dangling commit.\n * Anchored on the exit timestamp, not on wall clock since allocation.\n *\n * This window and the dirty/unmerged refusal are the two things most likely to\n * be dropped as incidental. They are not: both exist because work was lost.\n */\nexport const RECLAIM_GRACE_MS = 120_000;\n\nexport interface WorktreeOptions {\n /** Relative to the git root. */\n basePath?: string;\n /** Per-repository cap on allocated worktrees. A function is read on every allocation. */\n budget?: number | (() => number);\n branchPrefix?: string;\n /** Bound on fetching origin's default branch before cutting a new one. */\n fetchTimeoutMs?: number;\n /** Bound on one `git worktree add`; the add is killed and the repo's queue moves on when it passes. */\n addTimeoutMs?: number;\n /** Runs each `git worktree add`; tests inject one to observe how adds interleave. */\n runWorktreeAdd?: WorktreeAddRunner;\n /** Runs the repository's declared setup step; tests inject one so no real install runs. */\n runSetup?: SetupRunner;\n}\n\nexport const basePathOf = (opts: WorktreeOptions): string => opts.basePath ?? DEFAULT_BASE_PATH;\n\nexport const branchPrefixOf = (opts: WorktreeOptions): string => opts.branchPrefix ?? BRANCH_PREFIX;\n\nexport function budgetOf(opts: WorktreeOptions): number {\n const { budget } = opts;\n return typeof budget === \"function\" ? budget() : budget ?? DEFAULT_WORKTREE_BUDGET;\n}\n\n/** A name reaches this from a model, so it must not be able to escape basePath. */\nexport const slug = (name: string): string => name.replace(/[^A-Za-z0-9._-]/g, \"-\").replace(/^[.-]+/, \"\") || \"agent\";\n\nexport const branchFor = (name: string, opts: WorktreeOptions = {}): string => `${branchPrefixOf(opts)}${slug(name)}`;\n","import { existsSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { addWorktree, boundedAdd, WORKTREE_ADD_TIMEOUT_MS, type WorktreeAddRunner } from \"./add.js\";\nimport { fetchTip, resolveBranchBase, type BranchBase } from \"./branch-base.js\";\nimport { OriginUnreachableError, WorktreeBudgetExhaustedError, WorktreeInUseError } from \"./errors.js\";\nimport { gitOrNull, gitText } from \"./git.js\";\nimport { allocatedPaths, checkoutOf, copyClaudeDir, pruneStaleWorktrees } from \"./layout.js\";\nimport { basePathOf, budgetOf, DEFAULT_FETCH_TIMEOUT_MS, type WorktreeOptions } from \"./options.js\";\nimport { runWorktreeSetup, type SetupTarget } from \"./setup.js\";\n\n/** Where a worktree an allocator created sat, as its caller recorded it. */\nexport interface WorktreeRecord {\n gitRoot: string;\n worktree: string;\n branch: string;\n /** An agent adopted this tree from the allocator the record came from, so it is not that agent's to remove. */\n adopted?: boolean;\n}\n\n/** What an allocation hands back: where the agent works, one line for its brief, and a handle for release. */\nexport interface WorktreeAllocation {\n cwd: string;\n note: string;\n /** Branch, worktree, gitRoot and base; flags are the string 'true'. Persist it to release later. */\n ref: Record<string, string>;\n /** Advisory lines for the requester. */\n warnings?: string[];\n}\n\n/** How a re-attached worktree got its branch back. */\ntype BranchSource = \"local\" | \"origin\" | \"fresh\";\n\n/** `warning` is set exactly when the base is a local HEAD, which no setup declaration is trusted from. */\nexport const setupTarget = (gitRoot: string, worktree: string, base: BranchBase): SetupTarget => ({\n gitRoot,\n worktree,\n baseSha: base.sha,\n fetched: base.warning === undefined,\n});\n\n/** `ls-remote --exit-code` exits 2 only when the ref is absent; anything else is a failed lookup. */\nasync function originHasBranch(gitRoot: string, branch: string, timeoutMs: number): Promise<boolean> {\n try {\n await gitText([\"ls-remote\", \"--exit-code\", \"--heads\", \"origin\", `refs/heads/${branch}`], gitRoot, timeoutMs);\n return true;\n } catch (err) {\n if ((err as { code?: unknown }).code === 2) return false;\n throw new OriginUnreachableError(branch, firstLine(err));\n }\n}\n\nconst firstLine = (err: unknown): string =>\n String((err as { stderr?: unknown }).stderr || (err as Error).message)\n .trim()\n .split(\"\\n\")[0] ?? \"unknown error\";\n\n/** Local first, since it may hold commits origin never saw; a squash merge deletes both. */\nasync function branchSource(gitRoot: string, branch: string, timeoutMs: number): Promise<BranchSource> {\n if ((await gitOrNull([\"rev-parse\", \"--verify\", branch], gitRoot)) !== null) return \"local\";\n if ((await gitOrNull([\"remote\", \"get-url\", \"origin\"], gitRoot)) === null) return \"fresh\";\n if (!(await originHasBranch(gitRoot, branch, timeoutMs))) return \"fresh\";\n if ((await fetchTip(gitRoot, branch, timeoutMs)) === null)\n throw new OriginUnreachableError(branch, \"origin lists it but fetching it failed\");\n return \"origin\";\n}\n\nfunction addArgs(record: WorktreeRecord, source: BranchSource, base: string): string[] {\n const { worktree, branch } = record;\n if (source === \"local\") return [\"worktree\", \"add\", worktree, branch];\n return [\"worktree\", \"add\", \"-b\", branch, worktree, source === \"origin\" ? `origin/${branch}` : base];\n}\n\n/** A concurrent re-attach of the same record loses the race here; say so rather than pass git's text on. */\nasync function addForSource(\n record: WorktreeRecord,\n source: BranchSource,\n base: string,\n run?: WorktreeAddRunner\n): Promise<void> {\n try {\n await addWorktree(record.gitRoot, addArgs(record, source, base), run);\n } catch (err) {\n const holder = await checkoutOf(record.gitRoot, record.branch);\n if (holder !== null || existsSync(record.worktree))\n throw new WorktreeInUseError(record.branch, holder ?? record.worktree);\n throw err;\n }\n}\n\nfunction reattachWarnings(record: WorktreeRecord, source: BranchSource, base: BranchBase): string[] {\n const inherited = base.warning === undefined ? [] : [base.warning];\n if (source !== \"fresh\") return inherited;\n const fresh =\n `branch ${record.branch} no longer exists locally or on origin (a squash merge deletes it), so ` +\n `${record.worktree} was re-created on a fresh ${record.branch} from ${base.ref} ${base.sha}; ` +\n \"commits the conversation mentions may be merged or gone\";\n return [fresh, ...inherited];\n}\n\n/** The record comes from the caller's log, so it may only name a tree under this repository's worktree base. */\nfunction checkRecordPlacement(record: WorktreeRecord, basePath: string): void {\n const base = path.resolve(record.gitRoot, basePath) + path.sep;\n if (!path.resolve(record.worktree).startsWith(base))\n throw new Error(`recorded worktree ${record.worktree} is not under ${base}; not re-created`);\n}\n\n/** Refuses when the tree is on disk, the budget is spent, or another tree holds the branch. */\nasync function checkReattachable(record: WorktreeRecord, opts: WorktreeOptions): Promise<void> {\n const { gitRoot, worktree, branch } = record;\n checkRecordPlacement(record, basePathOf(opts));\n if (existsSync(worktree)) throw new WorktreeInUseError(branch, worktree);\n await pruneStaleWorktrees(gitRoot);\n const allocated = await allocatedPaths(gitRoot, basePathOf(opts));\n const budget = budgetOf(opts);\n if (allocated.length >= budget) throw new WorktreeBudgetExhaustedError(allocated.length, budget);\n const holder = await checkoutOf(gitRoot, branch);\n if (holder !== null) throw new WorktreeInUseError(branch, holder);\n}\n\n/**\n * Put a removed worktree back at its recorded path, under the allocator's budget.\n *\n * `claude --resume` finds a transcript only under the project dir of the cwd it\n * starts in, and that dir is derived from the worktree path, so the path must be\n * the original one. Every file path in the conversation points there too.\n */\nexport async function reattachWorktree(\n record: WorktreeRecord,\n opts: WorktreeOptions = {},\n requireBranch = false\n): Promise<WorktreeAllocation> {\n const { gitRoot, worktree, branch } = record;\n await checkReattachable(record, opts);\n const timeoutMs = opts.fetchTimeoutMs ?? DEFAULT_FETCH_TIMEOUT_MS;\n const base = await resolveBranchBase(gitRoot, timeoutMs);\n const source = await branchSource(gitRoot, branch, timeoutMs);\n if (source === \"fresh\" && requireBranch)\n throw new Error(\n `branch ${branch} no longer exists locally or on origin, so the adopted worktree ${worktree} ` +\n \"was not re-created on a fresh one\"\n );\n await addForSource(\n record,\n source,\n base.sha,\n boundedAdd(opts.runWorktreeAdd, opts.addTimeoutMs ?? WORKTREE_ADD_TIMEOUT_MS)\n );\n const warnings = [\n ...copyClaudeDir(gitRoot, worktree),\n ...reattachWarnings(record, source, base),\n ...(await runWorktreeSetup(setupTarget(gitRoot, worktree, base), opts.runSetup)),\n ];\n return {\n cwd: worktree,\n note: `Your worktree at ${worktree} had been removed and was re-created on branch ${branch}. Commit your work there; nothing outside it is yours to change.`,\n ref: { branch, worktree, gitRoot, base: base.sha, base_ref: base.ref, reattached: source },\n ...(warnings.length === 0 ? {} : { warnings }),\n };\n}\n\n/**\n * Put back a removed tree an agent adopted, on its allocator's branch.\n *\n * It stays marked assigned, so the adopter's release leaves it, and a branch that\n * is gone refuses rather than forking a fresh one the adopter never worked on.\n */\nexport async function readoptWorktree(record: WorktreeRecord, opts: WorktreeOptions): Promise<WorktreeAllocation> {\n const allocation = await reattachWorktree(record, opts, true);\n return {\n ...allocation,\n note: `The worktree assigned to this task at ${record.worktree} had been removed and was re-created on branch ${record.branch}. You may be sharing it with other agents, so stay inside the paths you were given.`,\n ref: { ...allocation.ref, assigned: \"true\" },\n };\n}\n\n/** Re-create a removed tree from its record, keeping an adopted one adopted. */\nexport function recreateWorktree(record: WorktreeRecord, opts: WorktreeOptions = {}): Promise<WorktreeAllocation> {\n return record.adopted === true ? readoptWorktree(record, opts) : reattachWorktree(record, opts);\n}\n","import { execFile, spawn } from \"node:child_process\";\nimport { lstatSync, writeFileSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { promisify } from \"node:util\";\nimport { gitChildEnv } from \"./git.js\";\nimport { signalGroup } from \"./process-group.js\";\n\nconst execFileAsync = promisify(execFile);\n\n/** A path inside a commit: the declaration is read from git, never from a working tree. */\nexport const SETUP_FILE = \".agent-chat/worktree.json\";\n/** Kept in the worktree's git dir, so it is neither tracked nor counted as dirt, and goes with the worktree. */\nexport const SETUP_LOG = \"agent-chat-setup.log\";\n\n/** Five minutes: a cold `npm ci` takes well under that, so only a hang reaches it. */\nexport const DEFAULT_SETUP_TIMEOUT_MS = 300_000;\nconst MAX_SETUP_TIMEOUT_MS = 1_800_000;\nconst TERM_GRACE_MS = 2_000;\nconst OUTPUT_TAIL_CHARS = 4_000;\n\nexport interface SetupStep {\n command: string[];\n timeoutMs: number;\n}\n\nexport interface SetupResult {\n /** Null when the process never started or was killed by a signal. */\n exitCode: number | null;\n timedOut: boolean;\n output: string;\n}\n\nexport type SetupRunner = (\n command: readonly string[],\n cwd: string,\n timeoutMs: number\n) => Promise<SetupResult>;\n\nexport interface SetupTarget {\n gitRoot: string;\n worktree: string;\n /** The commit the branch base resolved to; the only place a declaration is read from. */\n baseSha: string;\n /** False when that commit is a local HEAD rather than origin's default branch as fetched. */\n fetched: boolean;\n}\n\nconst SETUP_ENV_KEYS = new Set([\n \"PATH\",\n \"HOME\",\n \"USER\",\n \"LOGNAME\",\n \"SHELL\",\n \"TMPDIR\",\n \"LANG\",\n \"PNPM_HOME\",\n \"NODE_EXTRA_CA_CERTS\",\n \"XDG_CACHE_HOME\",\n \"XDG_CONFIG_HOME\",\n \"XDG_DATA_HOME\",\n \"HTTP_PROXY\",\n \"HTTPS_PROXY\",\n \"NO_PROXY\",\n \"http_proxy\",\n \"https_proxy\",\n \"no_proxy\",\n]);\nconst SETUP_ENV_PREFIXES = [\"LC_\", \"npm_config_\", \"NPM_CONFIG_\", \"COREPACK_\"];\n\n/** A resumed tree holds the branch's package.json and .npmrc; env outranks the .npmrc, so no branch program runs. */\nconst PINNED_NPM_CONFIG: Readonly<Record<string, string>> = {\n ignore_scripts: \"true\",\n git: \"git\",\n // npm reads an empty value as unset, which lets the .npmrc win.\n node_options: \"--no-deprecation\",\n script_shell: \"/bin/sh\",\n shell: \"/bin/sh\",\n // pnpm loads a branch .pnpmfile.cjs (arbitrary code) even with ignore-scripts on.\n ignore_pnpmfile: \"true\",\n // pnpm otherwise downloads and runs the branch package.json's packageManager version.\n manage_package_manager_versions: \"false\",\n};\n\n/** A corepack shim reads a branch .corepack.env for any COREPACK_ key the env leaves unset. */\nconst PINNED_COREPACK: Readonly<Record<string, string>> = {\n COREPACK_ENV_FILE: \"0\",\n COREPACK_ENABLE_UNSAFE_CUSTOM_URLS: \"0\",\n};\n\n/** pnpm 10 ranks this file's ignorePnpmfile and ignoreScripts above every env pin. */\nexport const PNPM_WORKSPACE_FILE = \"pnpm-workspace.yaml\";\n/** npm exec exports this file's keys as npm_config_* over the env pins, and its registry picks what npx runs. */\nexport const NPMRC_FILE = \".npmrc\";\nconst BASE_ONLY_FILES = [PNPM_WORKSPACE_FILE, NPMRC_FILE];\n\n/** An allowlist of what an install needs: the step runs with the host's authority, outside any permission profile. */\nexport function setupEnv(\n env: NodeJS.ProcessEnv = process.env\n): NodeJS.ProcessEnv {\n const out: NodeJS.ProcessEnv = { GIT_TERMINAL_PROMPT: \"0\" };\n for (const [key, value] of Object.entries(env)) {\n if (\n SETUP_ENV_KEYS.has(key) ||\n SETUP_ENV_PREFIXES.some((prefix) => key.startsWith(prefix))\n )\n out[key] = value;\n }\n for (const [key, value] of Object.entries(PINNED_NPM_CONFIG)) {\n out[`npm_config_${key}`] = value;\n out[`NPM_CONFIG_${key.toUpperCase()}`] = value;\n }\n return { ...out, ...PINNED_COREPACK };\n}\n\nconst isCommand = (value: unknown): value is string[] =>\n Array.isArray(value) &&\n value.length > 0 &&\n value.every((part) => typeof part === \"string\" && part !== \"\");\n\nconst isTimeout = (value: unknown): value is number =>\n typeof value === \"number\" &&\n Number.isInteger(value) &&\n value > 0 &&\n value <= MAX_SETUP_TIMEOUT_MS;\n\n/** Keys it does not know are ignored, so a newer declaration still runs on an older host. */\nexport function parseSetupStep(text: string): SetupStep | null | string {\n if (text.trim() === \"\") return `${SETUP_FILE} is empty`;\n let parsed: unknown;\n try {\n parsed = JSON.parse(text);\n } catch (err) {\n return `${SETUP_FILE} is not valid JSON (${(err as Error).message})`;\n }\n const setup = (parsed as { setup?: unknown } | null)?.setup;\n if (setup === undefined) return null;\n if (typeof setup !== \"object\" || setup === null)\n return `${SETUP_FILE} setup must be an object`;\n const { command, timeoutMs } = setup as {\n command?: unknown;\n timeoutMs?: unknown;\n };\n if (!isCommand(command))\n return `${SETUP_FILE} setup.command must be a non-empty array of strings`;\n if (timeoutMs !== undefined && !isTimeout(timeoutMs))\n return `${SETUP_FILE} setup.timeoutMs must be a positive integer of at most ${MAX_SETUP_TIMEOUT_MS}`;\n return { command, timeoutMs: timeoutMs ?? DEFAULT_SETUP_TIMEOUT_MS };\n}\n\nasync function gitOutput(\n args: readonly string[],\n cwd: string\n): Promise<string | null> {\n try {\n const { stdout } = await execFileAsync(\"git\", [...args], {\n cwd,\n encoding: \"utf8\",\n env: gitChildEnv(),\n });\n return stdout;\n } catch {\n return null;\n }\n}\n\n/** The declaration as committed at `sha`, or null when that commit has none. */\nconst declarationAt = (gitRoot: string, sha: string): Promise<string | null> =>\n gitOutput([\"cat-file\", \"blob\", `${sha}:${SETUP_FILE}`], gitRoot);\n\n/** The tree's entry for `file`: absent, a regular file, or anything else, which is never read. */\nfunction kindInTree(worktree: string, file: string): \"absent\" | \"regular\" | \"other\" {\n try {\n return lstatSync(path.join(worktree, file)).isFile() ? \"regular\" : \"other\";\n } catch {\n return \"absent\";\n }\n}\n\n/** The blob id of `file` as the tree holds it, or null when the tree has none; a non-regular or unhashable file never matches. */\nfunction blobInTree(worktree: string, file: string): Promise<string | null> {\n const kind = kindInTree(worktree, file);\n if (kind === \"absent\") return Promise.resolve(null);\n if (kind === \"other\") return Promise.resolve(\"unhashable\");\n return gitOutput([\"hash-object\", \"--\", file], worktree).then(\n (blob) => blob ?? \"unhashable\"\n );\n}\n\n/** True when the tree's `file` is not byte-for-byte the one at the trusted base; adding or deleting it counts. */\nasync function differsFromBase(\n target: SetupTarget,\n file: string\n): Promise<boolean> {\n const [atBase, inTree] = await Promise.all([\n gitOutput(\n [\"rev-parse\", \"--verify\", \"--quiet\", `${target.baseSha}:${file}`],\n target.gitRoot\n ),\n blobInTree(target.worktree, file),\n ]);\n return (atBase?.trim() ?? null) !== (inTree?.trim() ?? null);\n}\n\n/** The first file the env pins cannot outrank whose tree copy differs from base, or null. */\nasync function changedBaseOnlyFile(target: SetupTarget): Promise<string | null> {\n const changed = await Promise.all(\n BASE_ONLY_FILES.map((file) => differsFromBase(target, file))\n );\n return BASE_ONLY_FILES[changed.indexOf(true)] ?? null;\n}\n\n/** Its own process group, so a timeout also kills what the step spawned (npm runs scripts in children). */\nexport const runSetupCommand: SetupRunner = (command, cwd, timeoutMs) =>\n new Promise((resolve) => {\n const [file, ...args] = command;\n const child = spawn(file ?? \"\", args, {\n cwd,\n env: setupEnv(),\n detached: true,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n });\n let output = \"\";\n let timedOut = false;\n const collect = (chunk: Buffer): void => {\n output = (output + chunk.toString()).slice(-OUTPUT_TAIL_CHARS);\n };\n child.stdout.on(\"data\", collect);\n child.stderr.on(\"data\", collect);\n const term = setTimeout(() => {\n timedOut = true;\n if (child.pid !== undefined) signalGroup(child.pid, \"SIGTERM\");\n }, timeoutMs);\n const kill = setTimeout(\n () => child.pid !== undefined && signalGroup(child.pid, \"SIGKILL\"),\n timeoutMs + TERM_GRACE_MS\n );\n const settle = (exitCode: number | null, extra = \"\"): void => {\n clearTimeout(term);\n clearTimeout(kill);\n resolve({ exitCode, timedOut, output: output + extra });\n };\n child.on(\"error\", (err) => settle(null, err.message));\n child.on(\"close\", (code) => settle(code));\n });\n\n/** The step's output can carry registry tokens, so it goes to an owner-only file and not into the spawn reply. */\nasync function writeSetupLog(\n worktree: string,\n output: string\n): Promise<string | null> {\n const gitDir = await gitOutput([\"rev-parse\", \"--absolute-git-dir\"], worktree);\n if (gitDir === null) return null;\n const file = path.join(gitDir.trim(), SETUP_LOG);\n try {\n writeFileSync(file, output, { mode: 0o600 });\n return file;\n } catch {\n return null;\n }\n}\n\nfunction describeFailure(\n step: SetupStep,\n result: SetupResult,\n log: string | null\n): string {\n const name = step.command.join(\" \");\n const how = result.timedOut\n ? `timed out after ${step.timeoutMs}ms and was killed`\n : `exited with ${\n result.exitCode === null ? \"no exit code\" : `code ${result.exitCode}`\n }`;\n const where = log === null ? \"\" : `; its output is in ${log}`;\n return `worktree setup step \\`${name}\\` ${how}${where}; the worktree may be missing its dependencies`;\n}\n\n/**\n * Run the repository's declared setup step in a fresh worktree, before the agent launches.\n *\n * The step runs with the host's authority, so its declaration comes only from origin's default\n * branch as fetched: a branch that edits the file changes nothing until it lands.\n * A tree whose pnpm-workspace.yaml or .npmrc differs from that branch's is skipped, since each can override the env pins.\n *\n * Never throws: a failed step is a warning and the spawn proceeds, since whatever\n * depended on it (the egress pre-push hook) fails closed on its own.\n */\nexport async function runWorktreeSetup(\n target: SetupTarget,\n run: SetupRunner = runSetupCommand\n): Promise<string[]> {\n const declared = await declarationAt(target.gitRoot, target.baseSha);\n if (declared === null) return [];\n if (!target.fetched)\n return [\n `worktree setup skipped: ${SETUP_FILE} is trusted only from origin's fetched default branch`,\n ];\n const step = parseSetupStep(declared);\n if (step === null) return [];\n if (typeof step === \"string\") return [`worktree setup skipped: ${step}`];\n const changed = await changedBaseOnlyFile(target);\n if (changed !== null)\n return [\n `worktree setup skipped: the tree's ${changed} differs from origin's default branch`,\n ];\n const result = await run(step.command, target.worktree, step.timeoutMs).catch(\n (err: unknown): SetupResult => ({\n exitCode: null,\n timedOut: false,\n output: String(err),\n })\n );\n if (result.exitCode === 0 && !result.timedOut) return [];\n return [\n describeFailure(\n step,\n result,\n await writeSetupLog(target.worktree, result.output)\n ),\n ];\n}\n","import { execFile } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\nimport { promisify } from \"node:util\";\nimport { gitOrNull } from \"./git.js\";\n\nconst execFileAsync = promisify(execFile);\n\nexport interface ReleaseCheck {\n name: \"dirty\" | \"pushed\" | \"landed\" | \"gh\";\n ok: boolean;\n detail: string;\n}\n\nexport interface WorktreeReleaseSafety {\n dirty: boolean;\n /** Commits that exist nowhere else: not on the remote, not in the base ref, and not landed. */\n unmerged: boolean;\n /** Every file the branch changed already matches the current base: a squash or rebase merge. */\n landed: boolean;\n /** Commits on the branch but not on `compareTo`; null when the range could not be counted. */\n ahead: number | null;\n checked: ReleaseCheck[];\n}\n\n/** The checkout's current branch, and the remote default if one is known locally. */\nasync function landingTargets(gitRoot: string): Promise<string[]> {\n const head = await gitOrNull([\"symbolic-ref\", \"--quiet\", \"--short\", \"HEAD\"], gitRoot);\n const remoteHead = await gitOrNull([\"rev-parse\", \"--verify\", \"--quiet\", \"origin/HEAD\"], gitRoot);\n return [head ?? \"HEAD\", ...(remoteHead === null ? [] : [\"origin/HEAD\"])];\n}\n\n/**\n * Has the branch's content reached `target`, whatever the commit ids say?\n *\n * A squash or rebase merge leaves the branch's own commits unreachable from the\n * base, so the commit count calls them unmerged. If every file the branch\n * changed since it forked is identical on `target`, nothing is lost by deleting\n * the branch. A later edit on `target` to one of those files makes this refuse,\n * which is the over-refusal we accept.\n */\nasync function hasLanded(gitRoot: string, branch: string, target: string): Promise<boolean> {\n if ((await gitOrNull([\"diff\", \"--quiet\", target, branch], gitRoot)) !== null) return true;\n const base = await gitOrNull([\"merge-base\", target, branch], gitRoot);\n if (base === null) return false;\n const files = await gitOrNull([\"diff\", \"--no-renames\", \"--name-only\", base, branch], gitRoot);\n if (files === null) return false;\n const touched = files.split(\"\\n\").filter(Boolean);\n if (touched.length === 0) return true;\n return (await gitOrNull([\"diff\", \"--quiet\", target, branch, \"--\", ...touched], gitRoot)) !== null;\n}\n\nasync function landedOn(gitRoot: string, branch: string, targets: readonly string[]): Promise<string | null> {\n for (const target of targets) {\n if (await hasLanded(gitRoot, branch, target)) return target;\n }\n return null;\n}\n\nconst GH_TIMEOUT_MS = 3_000;\n\n/** Advisory only: never required, never allowed to change the git answer. */\nasync function ghPrState(gitRoot: string, branch: string): Promise<string | null> {\n try {\n const { stdout } = await execFileAsync(\"gh\", [\"pr\", \"view\", branch, \"--json\", \"state\", \"--jq\", \".state\"], {\n cwd: gitRoot,\n encoding: \"utf8\",\n timeout: GH_TIMEOUT_MS,\n });\n return stdout.trim() || null;\n } catch {\n return null;\n }\n}\n\nfunction dirtyCheck(dirty: boolean): ReleaseCheck {\n return { name: \"dirty\", ok: !dirty, detail: dirty ? \"uncommitted changes in the worktree\" : \"worktree clean\" };\n}\n\nfunction pushedCheck(ahead: number | null, compareTo: string): ReleaseCheck {\n if (ahead === null) return { name: \"pushed\", ok: false, detail: `could not count commits against ${compareTo}` };\n return { name: \"pushed\", ok: ahead === 0, detail: `${ahead} commit(s) not on ${compareTo}` };\n}\n\nfunction landedCheck(target: string | null, targets: readonly string[]): ReleaseCheck {\n return target === null\n ? { name: \"landed\", ok: false, detail: `work not landed on ${targets.join(\" or \")}` }\n : { name: \"landed\", ok: true, detail: `work landed on ${target}` };\n}\n\n/** Commits on `branch` that are on neither its remote copy nor `baseRef`; null when uncountable. */\nasync function commitsAhead(gitRoot: string, branch: string, baseRef: string): Promise<[number | null, string]> {\n const remote = await gitOrNull([\"rev-parse\", \"--verify\", `origin/${branch}`], gitRoot);\n const compareTo = remote === null ? baseRef : `origin/${branch}`;\n const count = await gitOrNull([\"rev-list\", \"--count\", `${compareTo}..${branch}`], gitRoot);\n return [count === null ? null : Number.parseInt(count, 10), compareTo];\n}\n\n/**\n * Is it safe to destroy this worktree and its branch?\n *\n * With no remote the comparison falls back to the commit the branch forked\n * from, since treating \"no remote\" as safe would silently delete every commit\n * the agent made. Over-refusal is the failure mode we accept: `force` is one\n * flag away.\n *\n * Commits that fail that count are still safe when their content has landed on\n * the checkout's current branch (or `origin/HEAD`), which is how a squash-merged\n * PR looks once the host deletes the remote branch. Nothing is fetched: a stale\n * local main makes this refuse until someone pulls.\n */\nexport async function inspectForRelease(\n gitRoot: string,\n worktreePath: string,\n branch: string,\n baseRef: string\n): Promise<WorktreeReleaseSafety> {\n const status = existsSync(worktreePath) ? await gitOrNull([\"status\", \"--porcelain\"], worktreePath) : null;\n const dirty = (status ?? \"\").length > 0;\n const checked = [dirtyCheck(dirty)];\n\n if ((await gitOrNull([\"rev-parse\", \"--verify\", branch], gitRoot)) === null)\n return { dirty, unmerged: false, landed: false, ahead: 0, checked };\n\n const [ahead, compareTo] = await commitsAhead(gitRoot, branch, baseRef);\n checked.push(pushedCheck(ahead, compareTo));\n if (ahead === 0) return { dirty, unmerged: false, landed: false, ahead, checked };\n\n const targets = await landingTargets(gitRoot);\n const target = await landedOn(gitRoot, branch, targets);\n checked.push(landedCheck(target, targets));\n if (target === null) {\n const state = await ghPrState(gitRoot, branch);\n if (state !== null) checked.push({ name: \"gh\", ok: true, detail: `gh reports the PR as ${state}` });\n }\n return { dirty, unmerged: target === null, landed: target !== null, ahead, checked };\n}\n\n/** The failed checks, as one line a coordinator can act on. */\nexport function describeRefusal(safety: WorktreeReleaseSafety): string {\n const failed = safety.checked.filter((c) => !c.ok && !(c.name === \"pushed\" && safety.landed));\n const advisory = safety.checked.filter((c) => c.name === \"gh\").map((c) => c.detail);\n return [...failed.map((c) => c.detail), ...advisory].join(\"; \");\n}\n","import { gitOrNull, gitText as git } from \"./git.js\";\nimport type { WorktreeRecord } from \"./reattach.js\";\n\n/**\n * Park a finished agent's worktree: the tree is removed and the branch kept, so\n * `recreateWorktree` puts it back at the same path. Parking never deletes a\n * branch: in a repo with no remote the local branch is the only copy of the work.\n */\n\n/** With an origin, the branch must be on it with nothing ahead; without one, the kept local branch is the copy. */\nasync function unpushed(target: WorktreeRecord): Promise<string | undefined> {\n const { worktree, branch } = target;\n if ((await gitOrNull([\"remote\", \"get-url\", \"origin\"], worktree)) === null) return undefined;\n if ((await gitOrNull([\"rev-parse\", \"--verify\", \"--quiet\", `origin/${branch}`], worktree)) === null)\n return `${branch} is not on origin; push it first`;\n const ahead = await gitOrNull([\"rev-list\", `origin/${branch}..HEAD`], worktree);\n if (ahead === null) return `could not compare ${worktree} with origin/${branch}`;\n const count = ahead.split(\"\\n\").filter(Boolean).length;\n return count === 0 ? undefined : `${count} commit(s) in ${worktree} are not on origin/${branch}; push first`;\n}\n\n/** A commit on a detached HEAD or another branch would be unreachable once the tree is gone, since only `branch` is kept. */\nasync function offBranch(target: WorktreeRecord): Promise<string | undefined> {\n const head = await gitOrNull([\"symbolic-ref\", \"--quiet\", \"--short\", \"HEAD\"], target.worktree);\n if (head === target.branch) return undefined;\n const where = head === null ? \"detached\" : `on ${head}`;\n return `HEAD in ${target.worktree} is ${where}, not on ${target.branch}; check out ${target.branch} first`;\n}\n\n/** Ignored paths `git worktree remove` would delete that a build or re-attach puts back. */\nconst REGENERABLE_DIRS = [\"node_modules\", \"dist\", \"coverage\", \".turbo\"];\n\n/** `.claude` only at the top, since re-attach copies it from the repository root. */\nconst isRegenerable = (entry: string): boolean => {\n const segments = entry.split(\"/\").filter(Boolean);\n return segments[0] === \".claude\" || segments.some((segment) => REGENERABLE_DIRS.includes(segment));\n};\n\n/** `-uall` so `status.showUntrackedFiles=no` cannot hide an untracked file the removal would take. */\nasync function unsaved(worktree: string): Promise<string | undefined> {\n const status = await gitOrNull([\"status\", \"--porcelain\", \"-uall\"], worktree);\n if (status === null) return `could not read git status in ${worktree}`;\n if (status !== \"\") return `uncommitted or untracked changes in ${worktree}`;\n const ignored = await gitOrNull([\"ls-files\", \"--others\", \"--ignored\", \"--exclude-standard\", \"--directory\"], worktree);\n if (ignored === null) return `could not list ignored files in ${worktree}`;\n const kept = ignored.split(\"\\n\").filter((entry) => entry !== \"\" && !isRegenerable(entry));\n if (kept.length === 0) return undefined;\n return (\n `ignored files in ${worktree} would be deleted (${kept.slice(0, 3).join(\", \")}); ` +\n `park removes only ignored ${REGENERABLE_DIRS.join(\", \")} and a top-level .claude`\n );\n}\n\n/**\n * Refuse a tree that would lose anything; otherwise remove it without --force and keep the branch.\n * `recheck` runs after the git checks and right before the removal, so a spawn or resume that\n * started meanwhile is caught. Returns the parked head.\n */\nexport async function parkWorktree(\n target: WorktreeRecord,\n recheck: () => string | undefined = () => undefined\n): Promise<{ ok: true; head: string } | { ok: false; reason: string }> {\n const refusal = (await offBranch(target)) ?? (await unsaved(target.worktree)) ?? (await unpushed(target));\n if (refusal) return { ok: false, reason: refusal };\n const head = await git([\"rev-parse\", \"HEAD\"], target.worktree);\n const late = recheck();\n if (late) return { ok: false, reason: late };\n try {\n await git([\"worktree\", \"remove\", target.worktree], target.gitRoot);\n } catch (err) {\n const detail = String((err as { stderr?: unknown }).stderr || (err as Error).message).trim();\n return { ok: false, reason: `git would not remove ${target.worktree}: ${detail.split(\"\\n\")[0]}` };\n }\n return { ok: true, head };\n}\n","import { execFileSync } from \"node:child_process\";\nimport path from \"node:path\";\nimport { gitChildEnv } from \"./git.js\";\nimport { removeWorktree } from \"./layout.js\";\nimport { branchPrefixOf, RECLAIM_GRACE_MS } from \"./options.js\";\nimport { inspectForRelease } from \"./release-safety.js\";\n\n/**\n * Find the worktrees an allocator is holding, and say which ones nobody is using.\n *\n * Release is driven by a person deciding they are done. The leak is the case\n * where nobody decides: an agent exits, is never released, and holds its\n * worktree and branch indefinitely.\n *\n * Ownership is the branch prefix, not the path: the prefix is what the allocator\n * writes and nothing else creates. That keeps the sweep off other tools' agent\n * worktrees, which sit on ordinary branch names and are usually locked.\n */\n\n/** Where a worktree sits in the lifecycle, and therefore what may be done to it. */\nexport type SweepStatus =\n /** Its agent is still running. Nothing to do, and nothing safe to do. */\n | \"held\"\n /** Its agent has exited, but inside the window that protects unnoticed work. */\n | \"in-grace\"\n /** Uncommitted changes, or commits that exist nowhere else. Needs a person. */\n | \"holds-work\"\n /** Nobody is using it and nothing would be lost. `reclaimWorktree` takes these. */\n | \"reclaimable\";\n\n/** The agent a caller says owns a found worktree. */\nexport interface SweepOwner {\n agentId: string;\n name: string;\n state: string;\n lastEventAt: number;\n exitedAt?: number;\n}\n\n/** An allocation the caller believes it still holds. */\nexport interface HeldWorktree {\n gitRoot: string;\n branch: string;\n /** The commit the branch was cut from; release safety compares against it when there is no remote. */\n base?: string;\n}\n\nexport interface FoundWorktree {\n gitRoot: string;\n worktree: string;\n branch: string;\n}\n\nexport interface SweptWorktree extends FoundWorktree {\n status: SweepStatus;\n /** Absent when no owner was found for the worktree. */\n agent?: { agentId: string; name: string; state: string; lastEventAt: number };\n /** One line of why it is in this state, for a human reading the report. */\n detail: string;\n}\n\nexport type GitLister = (gitRoot: string) => Promise<string>;\n\nexport interface SweepOptions {\n /** Repositories to scan beyond the ones `held` names, which catches a tree no record points at. */\n roots?: readonly string[];\n held?: readonly HeldWorktree[];\n /** Joins a found worktree to its agent; the caller owns the roster. */\n ownerOf?: (found: FoundWorktree) => SweepOwner | undefined;\n branchPrefix?: string;\n list?: GitLister;\n now?: () => number;\n}\n\nconst porcelain: GitLister = async (gitRoot) =>\n execFileSync(\"git\", [\"worktree\", \"list\", \"--porcelain\"], { cwd: gitRoot, encoding: \"utf8\", env: gitChildEnv() });\n\ninterface ListedWorktree {\n worktree?: string;\n branch?: string;\n locked: boolean;\n}\n\nconst parseBlock = (block: string): ListedWorktree => ({\n worktree: block.match(/^worktree (.+)$/m)?.[1]?.trim(),\n branch: block.match(/^branch refs\\/heads\\/(.+)$/m)?.[1]?.trim(),\n locked: /^locked/m.test(block),\n});\n\n/** Every unlocked worktree in `gitRoot` whose branch carries `branchPrefix`, from git itself. */\nexport async function agentWorktreesIn(\n gitRoot: string,\n list: GitLister = porcelain,\n branchPrefix: string = branchPrefixOf({})\n): Promise<{ worktree: string; branch: string }[]> {\n const out = await list(gitRoot).catch(() => \"\");\n return (\n out\n .split(\"\\n\\n\")\n .map(parseBlock)\n .filter((e): e is Required<ListedWorktree> => e.worktree !== undefined && e.branch !== undefined)\n // Locked is another tool's \"do not touch\"; honour it rather than report a reclaim we would refuse.\n .filter((e) => !e.locked && e.branch.startsWith(branchPrefix))\n .map(({ worktree, branch }) => ({ worktree: path.resolve(worktree), branch }))\n );\n}\n\n/** Live means someone is in it; anything else has stopped and may be reclaimable. */\nexport const isLive = (state: string): boolean => state === \"live\" || state === \"spawning\";\n\nfunction classifyByOwner(\n owner: SweepOwner | undefined,\n now: number\n): { status: SweepStatus; detail: string } | undefined {\n if (owner === undefined) return undefined;\n if (isLive(owner.state)) return { status: \"held\", detail: `${owner.name} is ${owner.state}` };\n const since = now - (owner.exitedAt ?? owner.lastEventAt);\n if (since >= RECLAIM_GRACE_MS) return undefined;\n return {\n status: \"in-grace\",\n detail: `${owner.name} stopped ${Math.round(since / 1000)}s ago; reclaimable after ${RECLAIM_GRACE_MS / 1000}s`,\n };\n}\n\nfunction idleDetail(owner: SweepOwner | undefined): string {\n return owner === undefined\n ? \"no agent in the log claims this branch, and it holds nothing\"\n : `${owner.name} is ${owner.state}, and it holds nothing`;\n}\n\n/** An unknown owner is not a reason to destroy commits; the dirty/unmerged check decides. */\nasync function classify(\n found: FoundWorktree,\n owner: SweepOwner | undefined,\n base: string,\n now: number\n): Promise<SweptWorktree> {\n const agent = owner && {\n agentId: owner.agentId,\n name: owner.name,\n state: owner.state,\n lastEventAt: owner.lastEventAt,\n };\n const withAgent = { ...found, ...(agent ? { agent } : {}) };\n const byOwner = classifyByOwner(owner, now);\n if (byOwner) return { ...withAgent, ...byOwner };\n\n const safety = await inspectForRelease(found.gitRoot, found.worktree, found.branch, base);\n if (!safety.dirty && !safety.unmerged) return { ...withAgent, status: \"reclaimable\", detail: idleDetail(owner) };\n const detail = [safety.dirty && \"uncommitted changes\", safety.unmerged && \"commits that exist nowhere else\"]\n .filter(Boolean)\n .join(\" and \");\n return { ...withAgent, status: \"holds-work\", detail };\n}\n\n/** Every allocator worktree in the named and held repositories, classified. */\nexport async function sweepWorktrees(options: SweepOptions = {}): Promise<SweptWorktree[]> {\n const now = (options.now ?? Date.now)();\n const held = new Map((options.held ?? []).map((h) => [h.branch, h]));\n const roots = new Set<string>([...(options.roots ?? []), ...[...held.values()].map((h) => h.gitRoot)]);\n const prefix = options.branchPrefix ?? branchPrefixOf({});\n\n const swept: SweptWorktree[] = [];\n for (const gitRoot of roots) {\n for (const { worktree, branch } of await agentWorktreesIn(gitRoot, options.list ?? porcelain, prefix)) {\n const found = { gitRoot, worktree, branch };\n swept.push(await classify(found, options.ownerOf?.(found), held.get(branch)?.base ?? \"HEAD\", now));\n }\n }\n return swept;\n}\n\n/**\n * Destroy one swept worktree and its branch.\n *\n * Refuses anything not `reclaimable` unless forced, so the classification is the\n * guard rather than advice. The grace window and the safety check already ran in\n * the sweep, against the report the caller read, so they are not re-derived here.\n */\nexport async function reclaimWorktree(\n entry: SweptWorktree,\n options: { force?: boolean } = {}\n): Promise<{ ok: boolean; reason?: string }> {\n if (entry.status !== \"reclaimable\" && options.force !== true)\n return { ok: false, reason: `${entry.branch} is ${entry.status}: ${entry.detail}` };\n await removeWorktree(entry.gitRoot, entry.worktree, entry.branch);\n return { ok: true };\n}\n"],"mappings":"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","names":["existsSync","rmSync","path","path","path","existsSync","path","execFile","spawn","lstatSync","path","promisify","execFileAsync","promisify","execFile","TERM_GRACE_MS","lstatSync","path","spawn","existsSync","path","execFile","existsSync","promisify","execFileAsync","promisify","execFile","existsSync","rmSync","existsSync","path","path","path"]}
1
+ {"version":3,"sources":["../src/allocator.ts","../src/add.ts","../src/git.ts","../src/process-group.ts","../src/branch-base.ts","../src/errors.ts","../src/layout.ts","../src/options.ts","../src/reattach.ts","../src/setup.ts","../src/release-safety.ts","../src/unsaved-work.ts","../src/park.ts","../src/sweep.ts"],"sourcesContent":["import { existsSync, rmSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { addWorktree, boundedAdd, WORKTREE_ADD_TIMEOUT_MS, type WorktreeAddRunner } from \"./add.js\";\nimport { resolveBranchBase } from \"./branch-base.js\";\nimport { WorktreeBudgetExhaustedError, WorktreeInUseError } from \"./errors.js\";\nimport { findGitRoot, gitOrNull } from \"./git.js\";\nimport { allocatedPaths, checkoutOf, copyClaudeDir, pruneStaleWorktrees, removeWorktree } from \"./layout.js\";\nimport {\n basePathOf,\n branchFor,\n budgetOf,\n DEFAULT_FETCH_TIMEOUT_MS,\n RECLAIM_GRACE_MS,\n slug,\n type WorktreeOptions,\n} from \"./options.js\";\nimport { readoptWorktree, setupTarget, type WorktreeAllocation, type WorktreeRecord } from \"./reattach.js\";\nimport { describeRefusal, inspectForRelease } from \"./release-safety.js\";\nimport { runWorktreeSetup } from \"./setup.js\";\n\n/** One agent's request for a worktree. A caller's richer context record satisfies it structurally. */\nexport interface WorktreeRequest {\n agentName: string;\n baseCwd: string;\n /**\n * A worktree the caller assigned. It is ADOPTED instead of allocated: no\n * branch is created, no budget slot is taken, and release leaves it alone.\n */\n assignedWorktree?: string;\n /** The caller's record of allocating `assignedWorktree`, which re-creates it if it was removed. */\n assignedRecord?: WorktreeRecord;\n /** When the agent exited; anchors the reclaim grace window. */\n exitedAt?: number;\n /** Discard a leftover branch instead of adopting it. Allocation can destroy commits as release can. */\n forceReset?: boolean;\n}\n\nexport interface WorktreeCheck {\n /** Reasons the allocation would fail. */\n refusals: string[];\n /** Advisory lines; allocation proceeds. */\n warnings: string[];\n}\n\nexport type WorktreeReleaseOutcome = { released: true } | { released: false; refusal: string };\n\nexport interface WorktreeAllocator {\n check(req: WorktreeRequest): Promise<WorktreeCheck>;\n allocate(req: WorktreeRequest): Promise<WorktreeAllocation>;\n /** A refusal (dirty, unmerged, inside the grace window) leaves everything on disk. */\n release(\n req: Pick<WorktreeRequest, \"exitedAt\">,\n alloc: { ref?: Record<string, string> },\n opts?: { force?: boolean }\n ): Promise<WorktreeReleaseOutcome>;\n}\n\ninterface AttachOptions {\n base: string;\n force: boolean;\n run?: WorktreeAddRunner | undefined;\n}\n\nasync function resetTo(gitRoot: string, branch: string, worktreePath: string, opts: AttachOptions): Promise<void> {\n await gitOrNull([\"worktree\", \"remove\", \"--force\", worktreePath], gitRoot);\n rmSync(worktreePath, { recursive: true, force: true });\n await gitOrNull([\"branch\", \"-D\", branch], gitRoot);\n await addWorktree(gitRoot, [\"worktree\", \"add\", \"-b\", branch, worktreePath, opts.base], opts.run);\n}\n\n/**\n * Attach a worktree for `branch`, and return whether an existing branch was adopted.\n *\n * The crash path: an agent commits, then dies without ever calling release. Its\n * directory is gone but the branch holds the only copy of those commits, so an\n * unconditional `branch -D` here would make them unreachable. Adopting beats\n * refusing: a respawn under the same name IS that agent continuing. A branch\n * holding nothing worth keeping is still reset, so it does not inherit a stale base.\n */\nasync function attachWorktree(\n gitRoot: string,\n branch: string,\n worktreePath: string,\n opts: AttachOptions\n): Promise<boolean> {\n if ((await gitOrNull([\"rev-parse\", \"--verify\", branch], gitRoot)) === null) {\n await addWorktree(gitRoot, [\"worktree\", \"add\", \"-b\", branch, worktreePath, opts.base], opts.run);\n return false;\n }\n if (opts.force) {\n await resetTo(gitRoot, branch, worktreePath, opts);\n return false;\n }\n const holder = await checkoutOf(gitRoot, branch);\n if (holder !== null || existsSync(worktreePath)) throw new WorktreeInUseError(branch, holder ?? worktreePath);\n\n const safety = await inspectForRelease(gitRoot, worktreePath, branch, opts.base);\n if (safety.unmerged) await addWorktree(gitRoot, [\"worktree\", \"add\", worktreePath, branch], opts.run);\n else await resetTo(gitRoot, branch, worktreePath, opts);\n return safety.unmerged;\n}\n\n/** Null when release may proceed, otherwise the reason it may not. */\nasync function refuseRelease(\n exitedAt: number | undefined,\n ref: { gitRoot: string; worktree: string; branch: string; base: string }\n): Promise<string | null> {\n if (exitedAt !== undefined && Date.now() - exitedAt < RECLAIM_GRACE_MS)\n return `agent exited less than ${RECLAIM_GRACE_MS / 1000}s ago; inside the reclaim grace window`;\n const safety = await inspectForRelease(ref.gitRoot, ref.worktree, ref.branch, ref.base);\n return safety.dirty || safety.unmerged ? describeRefusal(safety) : null;\n}\n\n/** A gone assigned tree comes back only from the caller's record of allocating it. */\nfunction recreateAssigned(\n assigned: string,\n record: WorktreeRecord | undefined,\n opts: WorktreeOptions\n): Promise<WorktreeAllocation> {\n if (record === undefined || path.resolve(record.worktree) !== assigned)\n throw new Error(\n `assigned worktree ${assigned} does not exist, and there is no record of allocating it ` +\n \"to re-create it from. Not spawned\"\n );\n return readoptWorktree(record, opts);\n}\n\nasync function adoptAssigned(\n req: WorktreeRequest,\n gitRoot: string,\n opts: WorktreeOptions\n): Promise<WorktreeAllocation> {\n const assigned = path.resolve(req.assignedWorktree as string);\n if (!existsSync(assigned)) return recreateAssigned(assigned, req.assignedRecord, opts);\n const branch = (await gitOrNull([\"rev-parse\", \"--abbrev-ref\", \"HEAD\"], assigned)) ?? \"HEAD\";\n return {\n cwd: assigned,\n note: `You are in a worktree assigned to this task at ${assigned}, on branch ${branch}. You may be sharing it with other agents, so stay inside the paths you were given.`,\n ref: { branch, worktree: assigned, gitRoot, assigned: \"true\" },\n };\n}\n\nasync function check(req: WorktreeRequest, opts: WorktreeOptions): Promise<WorktreeCheck> {\n const gitRoot = await findGitRoot(req.baseCwd);\n if (gitRoot === null)\n return { refusals: [`${req.baseCwd} is not a git repository; worktree isolation needs one`], warnings: [] };\n\n await pruneStaleWorktrees(gitRoot);\n const allocated = await allocatedPaths(gitRoot, basePathOf(opts));\n const budget = budgetOf(opts);\n const refusals =\n allocated.length >= budget\n ? [`worktree budget exhausted: ${allocated.length}/${budget} allocated under ${basePathOf(opts)}`]\n : [];\n const branch = branchFor(req.agentName, opts);\n const exists = (await gitOrNull([\"rev-parse\", \"--verify\", branch], gitRoot)) !== null;\n const warnings = exists\n ? [`branch ${branch} already exists; it will be adopted if it holds commits, reset if it does not`]\n : [];\n return { refusals, warnings };\n}\n\nasync function allocate(req: WorktreeRequest, opts: WorktreeOptions): Promise<WorktreeAllocation> {\n const gitRoot = await findGitRoot(req.baseCwd);\n if (gitRoot === null) throw new Error(`${req.baseCwd} is not a git repository`);\n if (req.assignedWorktree !== undefined) return adoptAssigned(req, gitRoot, opts);\n\n await pruneStaleWorktrees(gitRoot);\n const allocated = await allocatedPaths(gitRoot, basePathOf(opts));\n const budget = budgetOf(opts);\n if (allocated.length >= budget) throw new WorktreeBudgetExhaustedError(allocated.length, budget);\n\n const branch = branchFor(req.agentName, opts);\n const worktreePath = path.resolve(gitRoot, basePathOf(opts), slug(req.agentName));\n const base = await resolveBranchBase(gitRoot, opts.fetchTimeoutMs ?? DEFAULT_FETCH_TIMEOUT_MS);\n const reused = await attachWorktree(gitRoot, branch, worktreePath, {\n base: base.sha,\n force: req.forceReset === true,\n run: boundedAdd(opts.runWorktreeAdd, opts.addTimeoutMs ?? WORKTREE_ADD_TIMEOUT_MS),\n });\n const warnings = [\n ...copyClaudeDir(gitRoot, worktreePath),\n ...(base.warning === undefined ? [] : [base.warning]),\n ...(await runWorktreeSetup(setupTarget(gitRoot, worktreePath, base), opts.runSetup)),\n ];\n const carried = reused ? \" It already carries commits from an earlier run under this name.\" : \"\";\n return {\n cwd: worktreePath,\n note: `You are on branch ${branch} in an isolated worktree at ${worktreePath}.${carried} Commit your work there; nothing outside it is yours to change.`,\n ref: {\n branch,\n worktree: worktreePath,\n gitRoot,\n base: base.sha,\n base_ref: base.ref,\n ...(reused ? { reused: \"true\" } : {}),\n },\n ...(warnings.length === 0 ? {} : { warnings }),\n };\n}\n\nasync function release(\n req: Pick<WorktreeRequest, \"exitedAt\">,\n alloc: { ref?: Record<string, string> },\n opts: { force?: boolean } = {}\n): Promise<WorktreeReleaseOutcome> {\n const ref = alloc.ref;\n if (!ref?.branch || !ref.worktree || !ref.gitRoot)\n return { released: false, refusal: \"allocation carries no worktree reference\" };\n const { branch, worktree, gitRoot } = ref;\n\n // An assigned tree belongs to whoever assigned it and may be shared, so even\n // `force` leaves it: force discards THIS agent's commits, not someone else's tree.\n if (ref.assigned === \"true\") return { released: true };\n\n if (!opts.force) {\n const refusal = await refuseRelease(req.exitedAt, { gitRoot, worktree, branch, base: ref.base ?? \"HEAD\" });\n if (refusal !== null) return { released: false, refusal };\n }\n const refused = await removeWorktree(gitRoot, worktree, branch, opts);\n return refused === undefined ? { released: true } : { released: false, refusal: refused };\n}\n\n/** Worktree isolation for agents: one branch and one directory per agent name, under a per-repo budget. */\nexport function createWorktreeAllocator(opts: WorktreeOptions = {}): WorktreeAllocator {\n return {\n check: (req) => check(req, opts),\n allocate: (req) => allocate(req, opts),\n release,\n };\n}\n","import { spawn } from \"node:child_process\";\nimport { existsSync, rmSync } from \"node:fs\";\nimport { gitChildEnv, gitOrNull, gitText } from \"./git.js\";\nimport { groupAlive, signalGroup } from \"./process-group.js\";\n\n/** Runs one `git worktree add`, resolving to its output and rejecting on failure. */\nexport type WorktreeAddRunner = (args: readonly string[], cwd: string) => Promise<string>;\n\n/** Five minutes: a cold checkout of a multi-gigabyte repo takes tens of seconds, so only a hang reaches it. */\nexport const WORKTREE_ADD_TIMEOUT_MS = 300_000;\n\nconst CLEANUP_TIMEOUT_MS = 30_000;\n/** SIGTERM first so git can drop its lock files; SIGKILL follows for whatever ignores it. */\nconst TERM_GRACE_MS = 1_000;\n\n/** The tail of each repo's queue of `worktree add`s; it never rejects, so one failure does not jam the rest. */\nconst addQueues = new Map<string, Promise<unknown>>();\n\n/** Concurrent adds in one repo read each other's half-written `.git/worktrees/<name>/commondir` and die. */\nexport function addWorktree(\n gitRoot: string,\n args: readonly string[],\n run: WorktreeAddRunner = gitText\n): Promise<string> {\n const adding = (addQueues.get(gitRoot) ?? Promise.resolve()).then(() => run(args, gitRoot));\n const tail = adding.catch(() => undefined);\n addQueues.set(gitRoot, tail);\n void tail.then(() => addQueues.get(gitRoot) === tail && addQueues.delete(gitRoot));\n return adding;\n}\n\nconst addTarget = (args: readonly string[]): string | undefined => (args[2] === \"-b\" ? args[4] : args[2]);\n\nclass AddTimedOut extends Error {}\n\nasync function reapGroup(pid: number): Promise<void> {\n signalGroup(pid, \"SIGKILL\");\n for (let i = 0; i < 100 && groupAlive(pid); i++) await new Promise((r) => setTimeout(r, 20));\n}\n\nfunction settleAdd(code: number | null, out: string, err: string): Error | string {\n if (code === 0) return out.trim();\n return Object.assign(new Error(err.trim() || `git exited with code ${code}`), { code, stderr: err });\n}\n\n/**\n * Run git in its own process group, so a timeout can kill the hooks and filters\n * it spawned and not only git itself. Settles only after the child has exited and\n * the group is reaped, so cleanup never races a process that can still write.\n */\nfunction gitInGroup(args: readonly string[], cwd: string, timeoutMs: number): Promise<string> {\n return new Promise((resolve, reject) => {\n const child = spawn(\"git\", [...args], { cwd, env: gitChildEnv(), detached: true });\n const pid = child.pid;\n let out = \"\";\n let err = \"\";\n let timedOut = false;\n child.stdout.on(\"data\", (chunk) => (out += chunk));\n child.stderr.on(\"data\", (chunk) => (err += chunk));\n const term = setTimeout(() => {\n timedOut = true;\n if (pid !== undefined) signalGroup(pid, \"SIGTERM\");\n }, timeoutMs);\n const kill = setTimeout(() => pid !== undefined && signalGroup(pid, \"SIGKILL\"), timeoutMs + TERM_GRACE_MS);\n child.on(\"error\", reject);\n child.on(\"close\", (code) => {\n clearTimeout(term);\n clearTimeout(kill);\n void (pid === undefined ? Promise.resolve() : reapGroup(pid)).then(() => {\n const settled = timedOut ? new AddTimedOut() : settleAdd(code, out, err);\n if (typeof settled === \"string\") resolve(settled);\n else reject(settled);\n });\n });\n });\n}\n\n/**\n * A timed-out add can leave a half-written directory and a registration under\n * `.git/worktrees`. Only a directory the add itself created is removed: one that\n * existed beforehand belongs to someone else. The branch a `-b` add created is\n * kept, since it holds no commits and the next attach resets it.\n */\nasync function discardHalfCreated(gitRoot: string, args: readonly string[], created: boolean): Promise<void> {\n const target = addTarget(args);\n if (created && target !== undefined) {\n await gitOrNull([\"worktree\", \"remove\", \"--force\", target], gitRoot, CLEANUP_TIMEOUT_MS);\n rmSync(target, { recursive: true, force: true });\n }\n await gitOrNull([\"worktree\", \"prune\"], gitRoot, CLEANUP_TIMEOUT_MS);\n}\n\n/** The newest add per path; a late finisher only cleans up if no later add has taken the path since. */\nconst latestAdd = new Map<string, object>();\n\n/** One hung add (a hook, a filter) must not hold the repo's queue forever. */\nexport function boundedAdd(run: WorktreeAddRunner | undefined, timeoutMs: number): WorktreeAddRunner {\n return async (args, cwd) => {\n const target = addTarget(args);\n const created = target !== undefined && !existsSync(target);\n const mine = {};\n if (target !== undefined) latestAdd.set(target, mine);\n const timedOut = new Error(`git worktree add in ${cwd} timed out after ${timeoutMs}ms and was killed`);\n try {\n return await (run === undefined\n ? gitInGroup(args, cwd, timeoutMs)\n : raceTimer(run(args, cwd), timeoutMs, () => cleanLate(cwd, args, created, mine)));\n } catch (err) {\n if (!(err instanceof AddTimedOut)) throw err;\n await discardHalfCreated(cwd, args, created);\n throw timedOut;\n }\n };\n}\n\nasync function cleanLate(cwd: string, args: readonly string[], created: boolean, mine: object): Promise<void> {\n const target = addTarget(args);\n if (target === undefined || latestAdd.get(target) !== mine) return;\n await discardHalfCreated(cwd, args, created);\n}\n\nasync function raceTimer(add: Promise<string>, timeoutMs: number, onLate: () => Promise<void>): Promise<string> {\n let timer: NodeJS.Timeout | undefined;\n const expired = new Promise<never>((_, reject) => {\n timer = setTimeout(() => reject(new AddTimedOut()), timeoutMs);\n });\n try {\n return await Promise.race([add, expired]);\n } catch (err) {\n if (err instanceof AddTimedOut) void add.then(onLate, () => undefined);\n throw err;\n } finally {\n clearTimeout(timer);\n }\n}\n","import { execFile } from \"node:child_process\";\nimport path from \"node:path\";\nimport { promisify } from \"node:util\";\n\nconst execFileAsync = promisify(execFile);\n\n/**\n * One `git` invocation, returning null rather than throwing.\n *\n * git failures are routine control flow here: \"is this a repository at all\" is\n * a failing command, and every caller treats a miss as an answer. Injectable so\n * tests of callers never shell out.\n */\nexport type GitRunner = (args: readonly string[], cwd: string) => Promise<string | null>;\n\n/** A git child that inherits a dispatcher's identity variables can register as the agent that spawned it. */\nexport const DEFAULT_STRIPPED_ENV_PREFIXES: readonly string[] = [\"AGENT_CHAT_\"];\n\nexport function gitChildEnv(\n env: NodeJS.ProcessEnv = process.env,\n stripPrefixes: readonly string[] = DEFAULT_STRIPPED_ENV_PREFIXES\n): NodeJS.ProcessEnv {\n const out: NodeJS.ProcessEnv = { ...env, GIT_TERMINAL_PROMPT: \"0\" };\n for (const key of Object.keys(out)) {\n if (stripPrefixes.some((prefix) => key.startsWith(prefix))) delete out[key];\n }\n return out;\n}\n\n/** Throws on a non-zero exit; `stderr` and `code` ride on the error. */\nexport async function gitText(args: readonly string[], cwd: string, timeout?: number): Promise<string> {\n const { stdout } = await execFileAsync(\"git\", [...args], {\n cwd,\n encoding: \"utf8\",\n env: gitChildEnv(),\n ...(timeout === undefined ? {} : { timeout }),\n });\n return stdout.trim();\n}\n\nexport async function gitOrNull(args: readonly string[], cwd: string, timeout?: number): Promise<string | null> {\n try {\n return await gitText(args, cwd, timeout);\n } catch {\n return null;\n }\n}\n\nexport const runGit: GitRunner = (args, cwd) => gitOrNull(args, cwd);\n\n/**\n * The true repository root, resolved through worktrees.\n *\n * `--git-common-dir` rather than `--show-toplevel`: from inside a worktree the\n * toplevel is that worktree, and allocating from it would nest worktrees.\n */\nexport async function findGitRoot(cwd: string, git: GitRunner = runGit): Promise<string | null> {\n const commonDir = await git([\"rev-parse\", \"--path-format=absolute\", \"--git-common-dir\"], cwd);\n return commonDir === null ? null : path.dirname(commonDir);\n}\n\n/** Where a process is observably running, as git sees it, as opposed to what it says about itself. */\nexport interface GitPresence {\n gitBranch?: string;\n /** The checkout this process's files live in. */\n worktreePath?: string;\n /** The repository behind the checkout; two worktrees of one repo share it. */\n repoPath?: string;\n isLinkedWorktree?: boolean;\n}\n\n/**\n * Undefined outside a git repository. The toplevel and the common dir answer\n * different questions: when they disagree, this is a linked worktree.\n */\nexport async function observedPresence(cwd: string, git: GitRunner = runGit): Promise<GitPresence | undefined> {\n const [branch, toplevel, commonDir, gitDir] = await Promise.all([\n git([\"rev-parse\", \"--abbrev-ref\", \"HEAD\"], cwd),\n git([\"rev-parse\", \"--show-toplevel\"], cwd),\n git([\"rev-parse\", \"--path-format=absolute\", \"--git-common-dir\"], cwd),\n git([\"rev-parse\", \"--path-format=absolute\", \"--git-dir\"], cwd),\n ]);\n if (toplevel === null && commonDir === null) return undefined;\n\n const observed: GitPresence = {\n // 'HEAD' means detached, which is not a branch name.\n ...(branch !== null && branch !== \"\" && branch !== \"HEAD\" ? { gitBranch: branch } : {}),\n ...(toplevel === null || toplevel === \"\" ? {} : { worktreePath: toplevel }),\n ...(commonDir === null ? {} : { repoPath: path.dirname(path.resolve(commonDir)) }),\n ...(commonDir === null || gitDir === null\n ? {}\n : { isLinkedWorktree: path.resolve(commonDir) !== path.resolve(gitDir) }),\n };\n return Object.keys(observed).length === 0 ? undefined : observed;\n}\n","export const groupAlive = (pid: number): boolean => {\n try {\n process.kill(-pid, 0);\n return true;\n } catch {\n return false;\n }\n};\n\nexport const signalGroup = (pid: number, signal: NodeJS.Signals): void => {\n try {\n process.kill(-pid, signal);\n } catch {\n // The group is already gone.\n }\n};\n","import { gitOrNull } from \"./git.js\";\n\n/** The commit a new branch is cut from, the ref it was read from, and a warning when that ref is not origin's. */\nexport interface BranchBase {\n sha: string;\n ref: string;\n warning?: string;\n}\n\n/** origin/HEAD when this clone knows it; otherwise the two conventional names, in order. */\nasync function defaultBranchCandidates(gitRoot: string): Promise<string[]> {\n const head = await gitOrNull([\"symbolic-ref\", \"--quiet\", \"--short\", \"refs/remotes/origin/HEAD\"], gitRoot);\n return head?.startsWith(\"origin/\") ? [head.slice(\"origin/\".length)] : [\"main\", \"master\"];\n}\n\n/** Fetch only: it moves a remote-tracking ref and never the main checkout's HEAD or files. */\nexport async function fetchTip(gitRoot: string, branch: string, timeoutMs: number): Promise<string | null> {\n const tracking = `refs/remotes/origin/${branch}`;\n const fetched = await gitOrNull(\n [\"fetch\", \"--quiet\", \"--no-tags\", \"origin\", `+refs/heads/${branch}:${tracking}`],\n gitRoot,\n timeoutMs\n );\n return fetched === null ? null : gitOrNull([\"rev-parse\", \"--verify\", `${tracking}^{commit}`], gitRoot);\n}\n\n/** The timeout is one budget shared by every candidate, not one per candidate. */\nasync function fetchDefaultTip(gitRoot: string, timeoutMs: number): Promise<BranchBase | string> {\n if ((await gitOrNull([\"remote\", \"get-url\", \"origin\"], gitRoot)) === null)\n return \"the repository has no origin remote\";\n const deadline = Date.now() + timeoutMs;\n const candidates = await defaultBranchCandidates(gitRoot);\n for (const branch of candidates) {\n const remaining = deadline - Date.now();\n if (remaining <= 0) break;\n const sha = await fetchTip(gitRoot, branch, remaining);\n if (sha !== null) return { sha, ref: `origin/${branch}` };\n }\n return `fetching ${candidates.map((b) => `origin/${b}`).join(\" or \")} failed or timed out`;\n}\n\n/** Concurrent fetches of one ref race on its lock and the loser fails, so allocations in a repo share one. */\nconst inflightBases = new Map<string, Promise<BranchBase>>();\n\n/**\n * The main checkout's HEAD may lag origin or hold another session's unpushed\n * commits, and a branch cut from it ships both. So cut from a fresh fetch of\n * origin's default branch, and say so loudly when that is impossible.\n */\nexport function resolveBranchBase(gitRoot: string, timeoutMs: number): Promise<BranchBase> {\n const pending = inflightBases.get(gitRoot);\n if (pending !== undefined) return pending;\n const resolving = resolveBranchBaseNow(gitRoot, timeoutMs).finally(() => inflightBases.delete(gitRoot));\n inflightBases.set(gitRoot, resolving);\n return resolving;\n}\n\nasync function resolveBranchBaseNow(gitRoot: string, timeoutMs: number): Promise<BranchBase> {\n const reason = await fetchDefaultTip(gitRoot, timeoutMs);\n if (typeof reason !== \"string\") return reason;\n const sha = (await gitOrNull([\"rev-parse\", \"HEAD\"], gitRoot)) ?? \"HEAD\";\n return {\n sha,\n ref: \"HEAD\",\n warning:\n `worktree branched from the local HEAD at ${sha} because ${reason}; ` +\n \"it may lag origin or carry unpushed commits\",\n };\n}\n","export class WorktreeBudgetExhaustedError extends Error {\n constructor(readonly allocated: number, readonly budget: number) {\n super(`Worktree budget exhausted: ${allocated}/${budget} allocated`);\n this.name = \"WorktreeBudgetExhaustedError\";\n }\n}\n\n/**\n * Adoption is impossible: something is still holding the branch or the path.\n *\n * Distinct from \"the branch holds work\", which is recoverable by adopting it.\n * This one means a live agent of the same name already has the worktree, or a\n * directory is sitting in the way: cases where proceeding would clobber files\n * nobody has agreed to lose.\n */\nexport class WorktreeInUseError extends Error {\n constructor(readonly branch: string, readonly worktreePath: string) {\n super(\n `${worktreePath} is still on disk and holds branch ${branch}. Another agent of this name may be ` +\n \"live. Release it, spawn under a different name, or force the allocation to discard it.\"\n );\n this.name = \"WorktreeInUseError\";\n }\n}\n\n/** Origin could not answer whether it holds the branch, so a fresh fork might discard real work. */\nexport class OriginUnreachableError extends Error {\n constructor(readonly branch: string, detail: string) {\n super(\n `cannot reach origin to look for branch ${branch} (${detail}); it may still hold the agent's work, ` +\n \"so the worktree was not re-created. Fix the remote and resume again.\"\n );\n this.name = \"OriginUnreachableError\";\n }\n}\n","import { cpSync, existsSync, lstatSync, type Stats } from \"node:fs\";\nimport path from \"node:path\";\nimport { gitOrNull, gitText } from \"./git.js\";\n\n/** Live worktrees under basePath, from git itself rather than a parallel table. */\nexport async function allocatedPaths(gitRoot: string, basePath: string): Promise<string[]> {\n const out = await gitOrNull([\"worktree\", \"list\", \"--porcelain\"], gitRoot);\n if (out === null) return [];\n const base = path.resolve(gitRoot, basePath) + path.sep;\n return out\n .split(\"\\n\")\n .filter((line) => line.startsWith(\"worktree \"))\n .map((line) => path.resolve(line.slice(\"worktree \".length).trim()))\n .filter((dir) => dir.startsWith(base));\n}\n\n/**\n * Drop registrations whose directory is gone from disk, so a machine that was\n * rebooted mid-run does not permanently hold budget it is not using.\n */\nexport async function pruneStaleWorktrees(gitRoot: string): Promise<void> {\n await gitOrNull([\"worktree\", \"prune\"], gitRoot);\n}\n\n/** The worktree currently holding `branch`, or null. Prune first, or this lies. */\nexport async function checkoutOf(gitRoot: string, branch: string): Promise<string | null> {\n const out = (await gitOrNull([\"worktree\", \"list\", \"--porcelain\"], gitRoot)) ?? \"\";\n const holder = out.split(\"\\n\\n\").find((block) => block.includes(`branch refs/heads/${branch}`));\n const line = holder?.split(\"\\n\").find((l) => l.startsWith(\"worktree \"));\n return line ? path.resolve(line.slice(\"worktree \".length).trim()) : null;\n}\n\nfunction lstatOrNull(target: string): Stats | null {\n try {\n return lstatSync(target);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return null;\n throw error;\n }\n}\n\nfunction kindOf(stat: Stats): string {\n if (stat.isSymbolicLink()) return \"a symlink\";\n if (stat.isDirectory()) return \"a directory\";\n return stat.isFile() ? \"a file\" : \"not a regular file\";\n}\n\n/**\n * Hooks and settings live in gitignored .claude/, so a fresh worktree runs unhooked without this.\n * The target is branch-controlled: lstat it, since a committed symlink would let the copy write\n * outside the tree. Anything already there is kept and reported as a warning.\n */\nexport function copyClaudeDir(gitRoot: string, worktreePath: string): string[] {\n const source = path.resolve(gitRoot, \".claude\");\n const target = path.resolve(worktreePath, \".claude\");\n if (lstatOrNull(source) === null) return [];\n const existing = lstatOrNull(target);\n if (existing === null) {\n cpSync(source, target, { recursive: true });\n return [];\n }\n return [\n `${target} is ${kindOf(existing)} from the branch, so the repository's .claude was not copied in; this agent runs with the branch's .claude`,\n ];\n}\n\n/**\n * Remove the tree and its branch, or say why git would not. Callers decide first whether anything\n * would be lost; a refusal from git's own non-forced remove still stands unless the caller forced,\n * since it is the last check before files are deleted. The branch is kept while the tree remains.\n */\nexport async function removeWorktree(\n gitRoot: string,\n worktreePath: string,\n branch: string,\n opts: { force?: boolean } = {}\n): Promise<string | undefined> {\n const remove = [\"worktree\", \"remove\", ...(opts.force ? [\"--force\"] : []), worktreePath];\n try {\n await gitText(remove, gitRoot);\n } catch (err) {\n if (existsSync(worktreePath)) return `git would not remove ${worktreePath}: ${firstLine(err)}`;\n }\n await pruneStaleWorktrees(gitRoot);\n await gitOrNull([\"branch\", \"-D\", branch], gitRoot);\n return undefined;\n}\n\nfunction firstLine(err: unknown): string {\n const detail = String((err as { stderr?: unknown }).stderr || (err as Error).message).trim();\n return detail.split(\"\\n\")[0] ?? detail;\n}\n","import type { WorktreeAddRunner } from \"./add.js\";\nimport type { SetupRunner } from \"./setup.js\";\n\nexport const DEFAULT_WORKTREE_BUDGET = 3;\nexport const DEFAULT_BASE_PATH = \".worktrees\";\n/** Ownership marker: the sweep treats only branches carrying this prefix as its own. */\nexport const BRANCH_PREFIX = \"agent-chat/\";\nexport const DEFAULT_FETCH_TIMEOUT_MS = 15_000;\n\n/**\n * Grace window between an agent exiting and its worktree becoming reclaimable.\n *\n * It guards the window between an agent exiting and a human noticing the\n * unpushed commits it left behind. Release does `git branch -D`, so reclaiming\n * inside that window turns \"I'll look at it in a minute\" into a dangling commit.\n * Anchored on the exit timestamp, not on wall clock since allocation.\n *\n * This window and the dirty/unmerged refusal are the two things most likely to\n * be dropped as incidental. They are not: both exist because work was lost.\n */\nexport const RECLAIM_GRACE_MS = 120_000;\n\nexport interface WorktreeOptions {\n /** Relative to the git root. */\n basePath?: string;\n /** Per-repository cap on allocated worktrees. A function is read on every allocation. */\n budget?: number | (() => number);\n branchPrefix?: string;\n /** Bound on fetching origin's default branch before cutting a new one. */\n fetchTimeoutMs?: number;\n /** Bound on one `git worktree add`; the add is killed and the repo's queue moves on when it passes. */\n addTimeoutMs?: number;\n /** Runs each `git worktree add`; tests inject one to observe how adds interleave. */\n runWorktreeAdd?: WorktreeAddRunner;\n /** Runs the repository's declared setup step; tests inject one so no real install runs. */\n runSetup?: SetupRunner;\n}\n\nexport const basePathOf = (opts: WorktreeOptions): string => opts.basePath ?? DEFAULT_BASE_PATH;\n\nexport const branchPrefixOf = (opts: WorktreeOptions): string => opts.branchPrefix ?? BRANCH_PREFIX;\n\nexport function budgetOf(opts: WorktreeOptions): number {\n const { budget } = opts;\n return typeof budget === \"function\" ? budget() : budget ?? DEFAULT_WORKTREE_BUDGET;\n}\n\n/** A name reaches this from a model, so it must not be able to escape basePath. */\nexport const slug = (name: string): string => name.replace(/[^A-Za-z0-9._-]/g, \"-\").replace(/^[.-]+/, \"\") || \"agent\";\n\nexport const branchFor = (name: string, opts: WorktreeOptions = {}): string => `${branchPrefixOf(opts)}${slug(name)}`;\n","import { existsSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { addWorktree, boundedAdd, WORKTREE_ADD_TIMEOUT_MS, type WorktreeAddRunner } from \"./add.js\";\nimport { fetchTip, resolveBranchBase, type BranchBase } from \"./branch-base.js\";\nimport { OriginUnreachableError, WorktreeBudgetExhaustedError, WorktreeInUseError } from \"./errors.js\";\nimport { gitOrNull, gitText } from \"./git.js\";\nimport { allocatedPaths, checkoutOf, copyClaudeDir, pruneStaleWorktrees } from \"./layout.js\";\nimport { basePathOf, budgetOf, DEFAULT_FETCH_TIMEOUT_MS, type WorktreeOptions } from \"./options.js\";\nimport { runWorktreeSetup, type SetupTarget } from \"./setup.js\";\n\n/** Where a worktree an allocator created sat, as its caller recorded it. */\nexport interface WorktreeRecord {\n gitRoot: string;\n worktree: string;\n branch: string;\n /** An agent adopted this tree from the allocator the record came from, so it is not that agent's to remove. */\n adopted?: boolean;\n}\n\n/** What an allocation hands back: where the agent works, one line for its brief, and a handle for release. */\nexport interface WorktreeAllocation {\n cwd: string;\n note: string;\n /** Branch, worktree, gitRoot and base; flags are the string 'true'. Persist it to release later. */\n ref: Record<string, string>;\n /** Advisory lines for the requester. */\n warnings?: string[];\n}\n\n/** How a re-attached worktree got its branch back. */\ntype BranchSource = \"local\" | \"origin\" | \"fresh\";\n\n/** `warning` is set exactly when the base is a local HEAD, which no setup declaration is trusted from. */\nexport const setupTarget = (gitRoot: string, worktree: string, base: BranchBase): SetupTarget => ({\n gitRoot,\n worktree,\n baseSha: base.sha,\n fetched: base.warning === undefined,\n});\n\n/** `ls-remote --exit-code` exits 2 only when the ref is absent; anything else is a failed lookup. */\nasync function originHasBranch(gitRoot: string, branch: string, timeoutMs: number): Promise<boolean> {\n try {\n await gitText([\"ls-remote\", \"--exit-code\", \"--heads\", \"origin\", `refs/heads/${branch}`], gitRoot, timeoutMs);\n return true;\n } catch (err) {\n if ((err as { code?: unknown }).code === 2) return false;\n throw new OriginUnreachableError(branch, firstLine(err));\n }\n}\n\nconst firstLine = (err: unknown): string =>\n String((err as { stderr?: unknown }).stderr || (err as Error).message)\n .trim()\n .split(\"\\n\")[0] ?? \"unknown error\";\n\n/** Local first, since it may hold commits origin never saw; a squash merge deletes both. */\nasync function branchSource(gitRoot: string, branch: string, timeoutMs: number): Promise<BranchSource> {\n if ((await gitOrNull([\"rev-parse\", \"--verify\", branch], gitRoot)) !== null) return \"local\";\n if ((await gitOrNull([\"remote\", \"get-url\", \"origin\"], gitRoot)) === null) return \"fresh\";\n if (!(await originHasBranch(gitRoot, branch, timeoutMs))) return \"fresh\";\n if ((await fetchTip(gitRoot, branch, timeoutMs)) === null)\n throw new OriginUnreachableError(branch, \"origin lists it but fetching it failed\");\n return \"origin\";\n}\n\nfunction addArgs(record: WorktreeRecord, source: BranchSource, base: string): string[] {\n const { worktree, branch } = record;\n if (source === \"local\") return [\"worktree\", \"add\", worktree, branch];\n return [\"worktree\", \"add\", \"-b\", branch, worktree, source === \"origin\" ? `origin/${branch}` : base];\n}\n\n/** A concurrent re-attach of the same record loses the race here; say so rather than pass git's text on. */\nasync function addForSource(\n record: WorktreeRecord,\n source: BranchSource,\n base: string,\n run?: WorktreeAddRunner\n): Promise<void> {\n try {\n await addWorktree(record.gitRoot, addArgs(record, source, base), run);\n } catch (err) {\n const holder = await checkoutOf(record.gitRoot, record.branch);\n if (holder !== null || existsSync(record.worktree))\n throw new WorktreeInUseError(record.branch, holder ?? record.worktree);\n throw err;\n }\n}\n\nfunction reattachWarnings(record: WorktreeRecord, source: BranchSource, base: BranchBase): string[] {\n const inherited = base.warning === undefined ? [] : [base.warning];\n if (source !== \"fresh\") return inherited;\n const fresh =\n `branch ${record.branch} no longer exists locally or on origin (a squash merge deletes it), so ` +\n `${record.worktree} was re-created on a fresh ${record.branch} from ${base.ref} ${base.sha}; ` +\n \"commits the conversation mentions may be merged or gone\";\n return [fresh, ...inherited];\n}\n\n/** The record comes from the caller's log, so it may only name a tree under this repository's worktree base. */\nfunction checkRecordPlacement(record: WorktreeRecord, basePath: string): void {\n const base = path.resolve(record.gitRoot, basePath) + path.sep;\n if (!path.resolve(record.worktree).startsWith(base))\n throw new Error(`recorded worktree ${record.worktree} is not under ${base}; not re-created`);\n}\n\n/** Refuses when the tree is on disk, the budget is spent, or another tree holds the branch. */\nasync function checkReattachable(record: WorktreeRecord, opts: WorktreeOptions): Promise<void> {\n const { gitRoot, worktree, branch } = record;\n checkRecordPlacement(record, basePathOf(opts));\n if (existsSync(worktree)) throw new WorktreeInUseError(branch, worktree);\n await pruneStaleWorktrees(gitRoot);\n const allocated = await allocatedPaths(gitRoot, basePathOf(opts));\n const budget = budgetOf(opts);\n if (allocated.length >= budget) throw new WorktreeBudgetExhaustedError(allocated.length, budget);\n const holder = await checkoutOf(gitRoot, branch);\n if (holder !== null) throw new WorktreeInUseError(branch, holder);\n}\n\n/**\n * Put a removed worktree back at its recorded path, under the allocator's budget.\n *\n * `claude --resume` finds a transcript only under the project dir of the cwd it\n * starts in, and that dir is derived from the worktree path, so the path must be\n * the original one. Every file path in the conversation points there too.\n */\nexport async function reattachWorktree(\n record: WorktreeRecord,\n opts: WorktreeOptions = {},\n requireBranch = false\n): Promise<WorktreeAllocation> {\n const { gitRoot, worktree, branch } = record;\n await checkReattachable(record, opts);\n const timeoutMs = opts.fetchTimeoutMs ?? DEFAULT_FETCH_TIMEOUT_MS;\n const base = await resolveBranchBase(gitRoot, timeoutMs);\n const source = await branchSource(gitRoot, branch, timeoutMs);\n if (source === \"fresh\" && requireBranch)\n throw new Error(\n `branch ${branch} no longer exists locally or on origin, so the adopted worktree ${worktree} ` +\n \"was not re-created on a fresh one\"\n );\n await addForSource(\n record,\n source,\n base.sha,\n boundedAdd(opts.runWorktreeAdd, opts.addTimeoutMs ?? WORKTREE_ADD_TIMEOUT_MS)\n );\n const warnings = [\n ...copyClaudeDir(gitRoot, worktree),\n ...reattachWarnings(record, source, base),\n ...(await runWorktreeSetup(setupTarget(gitRoot, worktree, base), opts.runSetup)),\n ];\n return {\n cwd: worktree,\n note: `Your worktree at ${worktree} had been removed and was re-created on branch ${branch}. Commit your work there; nothing outside it is yours to change.`,\n ref: { branch, worktree, gitRoot, base: base.sha, base_ref: base.ref, reattached: source },\n ...(warnings.length === 0 ? {} : { warnings }),\n };\n}\n\n/**\n * Put back a removed tree an agent adopted, on its allocator's branch.\n *\n * It stays marked assigned, so the adopter's release leaves it, and a branch that\n * is gone refuses rather than forking a fresh one the adopter never worked on.\n */\nexport async function readoptWorktree(record: WorktreeRecord, opts: WorktreeOptions): Promise<WorktreeAllocation> {\n const allocation = await reattachWorktree(record, opts, true);\n return {\n ...allocation,\n note: `The worktree assigned to this task at ${record.worktree} had been removed and was re-created on branch ${record.branch}. You may be sharing it with other agents, so stay inside the paths you were given.`,\n ref: { ...allocation.ref, assigned: \"true\" },\n };\n}\n\n/** Re-create a removed tree from its record, keeping an adopted one adopted. */\nexport function recreateWorktree(record: WorktreeRecord, opts: WorktreeOptions = {}): Promise<WorktreeAllocation> {\n return record.adopted === true ? readoptWorktree(record, opts) : reattachWorktree(record, opts);\n}\n","import { execFile, spawn } from \"node:child_process\";\nimport { lstatSync, writeFileSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { promisify } from \"node:util\";\nimport { gitChildEnv } from \"./git.js\";\nimport { signalGroup } from \"./process-group.js\";\n\nconst execFileAsync = promisify(execFile);\n\n/** A path inside a commit: the declaration is read from git, never from a working tree. */\nexport const SETUP_FILE = \".agent-chat/worktree.json\";\n/** Kept in the worktree's git dir, so it is neither tracked nor counted as dirt, and goes with the worktree. */\nexport const SETUP_LOG = \"agent-chat-setup.log\";\n\n/** Five minutes: a cold `npm ci` takes well under that, so only a hang reaches it. */\nexport const DEFAULT_SETUP_TIMEOUT_MS = 300_000;\nconst MAX_SETUP_TIMEOUT_MS = 1_800_000;\nconst TERM_GRACE_MS = 2_000;\nconst OUTPUT_TAIL_CHARS = 4_000;\n\nexport interface SetupStep {\n command: string[];\n timeoutMs: number;\n}\n\nexport interface SetupResult {\n /** Null when the process never started or was killed by a signal. */\n exitCode: number | null;\n timedOut: boolean;\n output: string;\n}\n\nexport type SetupRunner = (\n command: readonly string[],\n cwd: string,\n timeoutMs: number\n) => Promise<SetupResult>;\n\nexport interface SetupTarget {\n gitRoot: string;\n worktree: string;\n /** The commit the branch base resolved to; the only place a declaration is read from. */\n baseSha: string;\n /** False when that commit is a local HEAD rather than origin's default branch as fetched. */\n fetched: boolean;\n}\n\nconst SETUP_ENV_KEYS = new Set([\n \"PATH\",\n \"HOME\",\n \"USER\",\n \"LOGNAME\",\n \"SHELL\",\n \"TMPDIR\",\n \"LANG\",\n \"PNPM_HOME\",\n \"NODE_EXTRA_CA_CERTS\",\n \"XDG_CACHE_HOME\",\n \"XDG_CONFIG_HOME\",\n \"XDG_DATA_HOME\",\n \"HTTP_PROXY\",\n \"HTTPS_PROXY\",\n \"NO_PROXY\",\n \"http_proxy\",\n \"https_proxy\",\n \"no_proxy\",\n]);\nconst SETUP_ENV_PREFIXES = [\"LC_\", \"npm_config_\", \"NPM_CONFIG_\", \"COREPACK_\"];\n\n/** A resumed tree holds the branch's package.json and .npmrc; env outranks the .npmrc, so no branch program runs. */\nconst PINNED_NPM_CONFIG: Readonly<Record<string, string>> = {\n ignore_scripts: \"true\",\n git: \"git\",\n // npm reads an empty value as unset, which lets the .npmrc win.\n node_options: \"--no-deprecation\",\n script_shell: \"/bin/sh\",\n shell: \"/bin/sh\",\n // pnpm loads a branch .pnpmfile.cjs (arbitrary code) even with ignore-scripts on.\n ignore_pnpmfile: \"true\",\n // pnpm otherwise downloads and runs the branch package.json's packageManager version.\n manage_package_manager_versions: \"false\",\n};\n\n/** A corepack shim reads a branch .corepack.env for any COREPACK_ key the env leaves unset. */\nconst PINNED_COREPACK: Readonly<Record<string, string>> = {\n COREPACK_ENV_FILE: \"0\",\n COREPACK_ENABLE_UNSAFE_CUSTOM_URLS: \"0\",\n};\n\n/** pnpm 10 ranks this file's ignorePnpmfile and ignoreScripts above every env pin. */\nexport const PNPM_WORKSPACE_FILE = \"pnpm-workspace.yaml\";\n/** npm exec exports this file's keys as npm_config_* over the env pins, and its registry picks what npx runs. */\nexport const NPMRC_FILE = \".npmrc\";\nconst BASE_ONLY_FILES = [PNPM_WORKSPACE_FILE, NPMRC_FILE];\n\n/** An allowlist of what an install needs: the step runs with the host's authority, outside any permission profile. */\nexport function setupEnv(\n env: NodeJS.ProcessEnv = process.env\n): NodeJS.ProcessEnv {\n const out: NodeJS.ProcessEnv = { GIT_TERMINAL_PROMPT: \"0\" };\n for (const [key, value] of Object.entries(env)) {\n if (\n SETUP_ENV_KEYS.has(key) ||\n SETUP_ENV_PREFIXES.some((prefix) => key.startsWith(prefix))\n )\n out[key] = value;\n }\n for (const [key, value] of Object.entries(PINNED_NPM_CONFIG)) {\n out[`npm_config_${key}`] = value;\n out[`NPM_CONFIG_${key.toUpperCase()}`] = value;\n }\n return { ...out, ...PINNED_COREPACK };\n}\n\nconst isCommand = (value: unknown): value is string[] =>\n Array.isArray(value) &&\n value.length > 0 &&\n value.every((part) => typeof part === \"string\" && part !== \"\");\n\nconst isTimeout = (value: unknown): value is number =>\n typeof value === \"number\" &&\n Number.isInteger(value) &&\n value > 0 &&\n value <= MAX_SETUP_TIMEOUT_MS;\n\n/** Keys it does not know are ignored, so a newer declaration still runs on an older host. */\nexport function parseSetupStep(text: string): SetupStep | null | string {\n if (text.trim() === \"\") return `${SETUP_FILE} is empty`;\n let parsed: unknown;\n try {\n parsed = JSON.parse(text);\n } catch (err) {\n return `${SETUP_FILE} is not valid JSON (${(err as Error).message})`;\n }\n const setup = (parsed as { setup?: unknown } | null)?.setup;\n if (setup === undefined) return null;\n if (typeof setup !== \"object\" || setup === null)\n return `${SETUP_FILE} setup must be an object`;\n const { command, timeoutMs } = setup as {\n command?: unknown;\n timeoutMs?: unknown;\n };\n if (!isCommand(command))\n return `${SETUP_FILE} setup.command must be a non-empty array of strings`;\n if (timeoutMs !== undefined && !isTimeout(timeoutMs))\n return `${SETUP_FILE} setup.timeoutMs must be a positive integer of at most ${MAX_SETUP_TIMEOUT_MS}`;\n return { command, timeoutMs: timeoutMs ?? DEFAULT_SETUP_TIMEOUT_MS };\n}\n\nasync function gitOutput(\n args: readonly string[],\n cwd: string\n): Promise<string | null> {\n try {\n const { stdout } = await execFileAsync(\"git\", [...args], {\n cwd,\n encoding: \"utf8\",\n env: gitChildEnv(),\n });\n return stdout;\n } catch {\n return null;\n }\n}\n\n/** The declaration as committed at `sha`, or null when that commit has none. */\nconst declarationAt = (gitRoot: string, sha: string): Promise<string | null> =>\n gitOutput([\"cat-file\", \"blob\", `${sha}:${SETUP_FILE}`], gitRoot);\n\n/** The tree's entry for `file`: absent, a regular file, or anything else, which is never read. */\nfunction kindInTree(worktree: string, file: string): \"absent\" | \"regular\" | \"other\" {\n try {\n return lstatSync(path.join(worktree, file)).isFile() ? \"regular\" : \"other\";\n } catch {\n return \"absent\";\n }\n}\n\n/** The blob id of `file` as the tree holds it, or null when the tree has none; a non-regular or unhashable file never matches. */\nfunction blobInTree(worktree: string, file: string): Promise<string | null> {\n const kind = kindInTree(worktree, file);\n if (kind === \"absent\") return Promise.resolve(null);\n if (kind === \"other\") return Promise.resolve(\"unhashable\");\n return gitOutput([\"hash-object\", \"--\", file], worktree).then(\n (blob) => blob ?? \"unhashable\"\n );\n}\n\n/** True when the tree's `file` is not byte-for-byte the one at the trusted base; adding or deleting it counts. */\nasync function differsFromBase(\n target: SetupTarget,\n file: string\n): Promise<boolean> {\n const [atBase, inTree] = await Promise.all([\n gitOutput(\n [\"rev-parse\", \"--verify\", \"--quiet\", `${target.baseSha}:${file}`],\n target.gitRoot\n ),\n blobInTree(target.worktree, file),\n ]);\n return (atBase?.trim() ?? null) !== (inTree?.trim() ?? null);\n}\n\n/** The first file the env pins cannot outrank whose tree copy differs from base, or null. */\nasync function changedBaseOnlyFile(target: SetupTarget): Promise<string | null> {\n const changed = await Promise.all(\n BASE_ONLY_FILES.map((file) => differsFromBase(target, file))\n );\n return BASE_ONLY_FILES[changed.indexOf(true)] ?? null;\n}\n\n/** Its own process group, so a timeout also kills what the step spawned (npm runs scripts in children). */\nexport const runSetupCommand: SetupRunner = (command, cwd, timeoutMs) =>\n new Promise((resolve) => {\n const [file, ...args] = command;\n const child = spawn(file ?? \"\", args, {\n cwd,\n env: setupEnv(),\n detached: true,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n });\n let output = \"\";\n let timedOut = false;\n const collect = (chunk: Buffer): void => {\n output = (output + chunk.toString()).slice(-OUTPUT_TAIL_CHARS);\n };\n child.stdout.on(\"data\", collect);\n child.stderr.on(\"data\", collect);\n const term = setTimeout(() => {\n timedOut = true;\n if (child.pid !== undefined) signalGroup(child.pid, \"SIGTERM\");\n }, timeoutMs);\n const kill = setTimeout(\n () => child.pid !== undefined && signalGroup(child.pid, \"SIGKILL\"),\n timeoutMs + TERM_GRACE_MS\n );\n const settle = (exitCode: number | null, extra = \"\"): void => {\n clearTimeout(term);\n clearTimeout(kill);\n resolve({ exitCode, timedOut, output: output + extra });\n };\n child.on(\"error\", (err) => settle(null, err.message));\n child.on(\"close\", (code) => settle(code));\n });\n\n/** The step's output can carry registry tokens, so it goes to an owner-only file and not into the spawn reply. */\nasync function writeSetupLog(\n worktree: string,\n output: string\n): Promise<string | null> {\n const gitDir = await gitOutput([\"rev-parse\", \"--absolute-git-dir\"], worktree);\n if (gitDir === null) return null;\n const file = path.join(gitDir.trim(), SETUP_LOG);\n try {\n writeFileSync(file, output, { mode: 0o600 });\n return file;\n } catch {\n return null;\n }\n}\n\nfunction describeFailure(\n step: SetupStep,\n result: SetupResult,\n log: string | null\n): string {\n const name = step.command.join(\" \");\n const how = result.timedOut\n ? `timed out after ${step.timeoutMs}ms and was killed`\n : `exited with ${\n result.exitCode === null ? \"no exit code\" : `code ${result.exitCode}`\n }`;\n const where = log === null ? \"\" : `; its output is in ${log}`;\n return `worktree setup step \\`${name}\\` ${how}${where}; the worktree may be missing its dependencies`;\n}\n\n/**\n * Run the repository's declared setup step in a fresh worktree, before the agent launches.\n *\n * The step runs with the host's authority, so its declaration comes only from origin's default\n * branch as fetched: a branch that edits the file changes nothing until it lands.\n * A tree whose pnpm-workspace.yaml or .npmrc differs from that branch's is skipped, since each can override the env pins.\n *\n * Never throws: a failed step is a warning and the spawn proceeds, since whatever\n * depended on it (the egress pre-push hook) fails closed on its own.\n */\nexport async function runWorktreeSetup(\n target: SetupTarget,\n run: SetupRunner = runSetupCommand\n): Promise<string[]> {\n const declared = await declarationAt(target.gitRoot, target.baseSha);\n if (declared === null) return [];\n if (!target.fetched)\n return [\n `worktree setup skipped: ${SETUP_FILE} is trusted only from origin's fetched default branch`,\n ];\n const step = parseSetupStep(declared);\n if (step === null) return [];\n if (typeof step === \"string\") return [`worktree setup skipped: ${step}`];\n const changed = await changedBaseOnlyFile(target);\n if (changed !== null)\n return [\n `worktree setup skipped: the tree's ${changed} differs from origin's default branch`,\n ];\n const result = await run(step.command, target.worktree, step.timeoutMs).catch(\n (err: unknown): SetupResult => ({\n exitCode: null,\n timedOut: false,\n output: String(err),\n })\n );\n if (result.exitCode === 0 && !result.timedOut) return [];\n return [\n describeFailure(\n step,\n result,\n await writeSetupLog(target.worktree, result.output)\n ),\n ];\n}\n","import { execFile } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\nimport { promisify } from \"node:util\";\nimport { gitOrNull } from \"./git.js\";\nimport { unsavedWork } from \"./unsaved-work.js\";\n\nconst execFileAsync = promisify(execFile);\n\nexport interface ReleaseCheck {\n name: \"dirty\" | \"pushed\" | \"landed\" | \"gh\";\n ok: boolean;\n detail: string;\n}\n\nexport interface WorktreeReleaseSafety {\n dirty: boolean;\n /** Commits that exist nowhere else: not on the remote, not in the base ref, and not landed. */\n unmerged: boolean;\n /** Every file the branch changed already matches the current base: a squash or rebase merge. */\n landed: boolean;\n /** Commits on the branch but not on `compareTo`; null when the range could not be counted. */\n ahead: number | null;\n checked: ReleaseCheck[];\n}\n\n/** The checkout's current branch, and the remote default if one is known locally. */\nasync function landingTargets(gitRoot: string): Promise<string[]> {\n const head = await gitOrNull([\"symbolic-ref\", \"--quiet\", \"--short\", \"HEAD\"], gitRoot);\n const remoteHead = await gitOrNull([\"rev-parse\", \"--verify\", \"--quiet\", \"origin/HEAD\"], gitRoot);\n return [head ?? \"HEAD\", ...(remoteHead === null ? [] : [\"origin/HEAD\"])];\n}\n\n/**\n * Has the branch's content reached `target`, whatever the commit ids say?\n *\n * A squash or rebase merge leaves the branch's own commits unreachable from the\n * base, so the commit count calls them unmerged. If every file the branch\n * changed since it forked is identical on `target`, nothing is lost by deleting\n * the branch. A later edit on `target` to one of those files makes this refuse,\n * which is the over-refusal we accept.\n */\nasync function hasLanded(gitRoot: string, branch: string, target: string): Promise<boolean> {\n if ((await gitOrNull([\"diff\", \"--quiet\", target, branch], gitRoot)) !== null) return true;\n const base = await gitOrNull([\"merge-base\", target, branch], gitRoot);\n if (base === null) return false;\n const files = await gitOrNull([\"diff\", \"--no-renames\", \"--name-only\", base, branch], gitRoot);\n if (files === null) return false;\n const touched = files.split(\"\\n\").filter(Boolean);\n if (touched.length === 0) return true;\n return (await gitOrNull([\"diff\", \"--quiet\", target, branch, \"--\", ...touched], gitRoot)) !== null;\n}\n\nasync function landedOn(gitRoot: string, branch: string, targets: readonly string[]): Promise<string | null> {\n for (const target of targets) {\n if (await hasLanded(gitRoot, branch, target)) return target;\n }\n return null;\n}\n\nconst GH_TIMEOUT_MS = 3_000;\n\n/** Advisory only: never required, never allowed to change the git answer. */\nasync function ghPrState(gitRoot: string, branch: string): Promise<string | null> {\n try {\n const { stdout } = await execFileAsync(\"gh\", [\"pr\", \"view\", branch, \"--json\", \"state\", \"--jq\", \".state\"], {\n cwd: gitRoot,\n encoding: \"utf8\",\n timeout: GH_TIMEOUT_MS,\n });\n return stdout.trim() || null;\n } catch {\n return null;\n }\n}\n\nfunction dirtyCheck(unsaved: string | undefined): ReleaseCheck {\n return { name: \"dirty\", ok: unsaved === undefined, detail: unsaved ?? \"worktree clean\" };\n}\n\nfunction pushedCheck(ahead: number | null, compareTo: string): ReleaseCheck {\n if (ahead === null) return { name: \"pushed\", ok: false, detail: `could not count commits against ${compareTo}` };\n return { name: \"pushed\", ok: ahead === 0, detail: `${ahead} commit(s) not on ${compareTo}` };\n}\n\nfunction landedCheck(target: string | null, targets: readonly string[]): ReleaseCheck {\n return target === null\n ? { name: \"landed\", ok: false, detail: `work not landed on ${targets.join(\" or \")}` }\n : { name: \"landed\", ok: true, detail: `work landed on ${target}` };\n}\n\n/** Commits on `branch` that are on neither its remote copy nor `baseRef`; null when uncountable. */\nasync function commitsAhead(gitRoot: string, branch: string, baseRef: string): Promise<[number | null, string]> {\n const remote = await gitOrNull([\"rev-parse\", \"--verify\", `origin/${branch}`], gitRoot);\n const compareTo = remote === null ? baseRef : `origin/${branch}`;\n const count = await gitOrNull([\"rev-list\", \"--count\", `${compareTo}..${branch}`], gitRoot);\n return [count === null ? null : Number.parseInt(count, 10), compareTo];\n}\n\n/**\n * Is it safe to destroy this worktree and its branch?\n *\n * The tree's files go through the same check as park, so a status git cannot\n * read, a hidden untracked file, or an ignored file no build regenerates all\n * count as dirty. A tree already gone from disk has no files left to lose.\n *\n * With no remote the comparison falls back to the commit the branch forked\n * from, since treating \"no remote\" as safe would silently delete every commit\n * the agent made. Over-refusal is the failure mode we accept: `force` is one\n * flag away.\n *\n * Commits that fail that count are still safe when their content has landed on\n * the checkout's current branch (or `origin/HEAD`), which is how a squash-merged\n * PR looks once the host deletes the remote branch. Nothing is fetched: a stale\n * local main makes this refuse until someone pulls.\n */\nexport async function inspectForRelease(\n gitRoot: string,\n worktreePath: string,\n branch: string,\n baseRef: string\n): Promise<WorktreeReleaseSafety> {\n const unsaved = existsSync(worktreePath) ? await unsavedWork(worktreePath) : undefined;\n const dirty = unsaved !== undefined;\n const checked = [dirtyCheck(unsaved)];\n\n if ((await gitOrNull([\"rev-parse\", \"--verify\", branch], gitRoot)) === null)\n return { dirty, unmerged: false, landed: false, ahead: 0, checked };\n\n const [ahead, compareTo] = await commitsAhead(gitRoot, branch, baseRef);\n checked.push(pushedCheck(ahead, compareTo));\n if (ahead === 0) return { dirty, unmerged: false, landed: false, ahead, checked };\n\n const targets = await landingTargets(gitRoot);\n const target = await landedOn(gitRoot, branch, targets);\n checked.push(landedCheck(target, targets));\n if (target === null) {\n const state = await ghPrState(gitRoot, branch);\n if (state !== null) checked.push({ name: \"gh\", ok: true, detail: `gh reports the PR as ${state}` });\n }\n return { dirty, unmerged: target === null, landed: target !== null, ahead, checked };\n}\n\n/** The failed checks, as one line a coordinator can act on. */\nexport function describeRefusal(safety: WorktreeReleaseSafety): string {\n const failed = safety.checked.filter((c) => !c.ok && !(c.name === \"pushed\" && safety.landed));\n const advisory = safety.checked.filter((c) => c.name === \"gh\").map((c) => c.detail);\n return [...failed.map((c) => c.detail), ...advisory].join(\"; \");\n}\n","import { gitOrNull } from \"./git.js\";\n\n/** Ignored paths `git worktree remove` would delete that a build or re-attach puts back. */\nconst REGENERABLE_DIRS = [\"node_modules\", \"dist\", \"coverage\", \".turbo\"];\n\n/** `.claude` only at the top, since re-attach copies it from the repository root. */\nconst isRegenerable = (entry: string): boolean => {\n const segments = entry.split(\"/\").filter(Boolean);\n return segments[0] === \".claude\" || segments.some((segment) => REGENERABLE_DIRS.includes(segment));\n};\n\n/**\n * Why removing this worktree would lose files, or undefined when it would not.\n *\n * `-uall` so `status.showUntrackedFiles=no` cannot hide an untracked file the removal would take.\n * A status git cannot read counts as dirty: a broken gitdir says nothing about what is on disk.\n */\nexport async function unsavedWork(worktree: string): Promise<string | undefined> {\n const status = await gitOrNull([\"status\", \"--porcelain\", \"-uall\"], worktree);\n if (status === null) return `could not read git status in ${worktree}`;\n if (status !== \"\") return `uncommitted or untracked changes in ${worktree}`;\n const ignored = await gitOrNull([\"ls-files\", \"--others\", \"--ignored\", \"--exclude-standard\", \"--directory\"], worktree);\n if (ignored === null) return `could not list ignored files in ${worktree}`;\n const kept = ignored.split(\"\\n\").filter((entry) => entry !== \"\" && !isRegenerable(entry));\n if (kept.length === 0) return undefined;\n return (\n `ignored files in ${worktree} would be deleted (${kept.slice(0, 3).join(\", \")}); ` +\n `only ignored ${REGENERABLE_DIRS.join(\", \")} and a top-level .claude are removed`\n );\n}\n","import { gitOrNull, gitText as git } from \"./git.js\";\nimport type { WorktreeRecord } from \"./reattach.js\";\nimport { unsavedWork } from \"./unsaved-work.js\";\n\n/**\n * Park a finished agent's worktree: the tree is removed and the branch kept, so\n * `recreateWorktree` puts it back at the same path. Parking never deletes a\n * branch: in a repo with no remote the local branch is the only copy of the work.\n */\n\n/** With an origin, the branch must be on it with nothing ahead; without one, the kept local branch is the copy. */\nasync function unpushed(target: WorktreeRecord): Promise<string | undefined> {\n const { worktree, branch } = target;\n if ((await gitOrNull([\"remote\", \"get-url\", \"origin\"], worktree)) === null) return undefined;\n if ((await gitOrNull([\"rev-parse\", \"--verify\", \"--quiet\", `origin/${branch}`], worktree)) === null)\n return `${branch} is not on origin; push it first`;\n const ahead = await gitOrNull([\"rev-list\", `origin/${branch}..HEAD`], worktree);\n if (ahead === null) return `could not compare ${worktree} with origin/${branch}`;\n const count = ahead.split(\"\\n\").filter(Boolean).length;\n return count === 0 ? undefined : `${count} commit(s) in ${worktree} are not on origin/${branch}; push first`;\n}\n\n/** A commit on a detached HEAD or another branch would be unreachable once the tree is gone, since only `branch` is kept. */\nasync function offBranch(target: WorktreeRecord): Promise<string | undefined> {\n const head = await gitOrNull([\"symbolic-ref\", \"--quiet\", \"--short\", \"HEAD\"], target.worktree);\n if (head === target.branch) return undefined;\n const where = head === null ? \"detached\" : `on ${head}`;\n return `HEAD in ${target.worktree} is ${where}, not on ${target.branch}; check out ${target.branch} first`;\n}\n\n/**\n * Refuse a tree that would lose anything; otherwise remove it without --force and keep the branch.\n * `recheck` runs after the git checks and right before the removal, so a spawn or resume that\n * started meanwhile is caught. Returns the parked head.\n */\nexport async function parkWorktree(\n target: WorktreeRecord,\n recheck: () => string | undefined = () => undefined\n): Promise<{ ok: true; head: string } | { ok: false; reason: string }> {\n const refusal = (await offBranch(target)) ?? (await unsavedWork(target.worktree)) ?? (await unpushed(target));\n if (refusal) return { ok: false, reason: refusal };\n const head = await git([\"rev-parse\", \"HEAD\"], target.worktree);\n const late = recheck();\n if (late) return { ok: false, reason: late };\n try {\n await git([\"worktree\", \"remove\", target.worktree], target.gitRoot);\n } catch (err) {\n const detail = String((err as { stderr?: unknown }).stderr || (err as Error).message).trim();\n return { ok: false, reason: `git would not remove ${target.worktree}: ${detail.split(\"\\n\")[0]}` };\n }\n return { ok: true, head };\n}\n","import { execFileSync } from \"node:child_process\";\nimport path from \"node:path\";\nimport { gitChildEnv } from \"./git.js\";\nimport { removeWorktree } from \"./layout.js\";\nimport { branchPrefixOf, RECLAIM_GRACE_MS } from \"./options.js\";\nimport { inspectForRelease } from \"./release-safety.js\";\n\n/**\n * Find the worktrees an allocator is holding, and say which ones nobody is using.\n *\n * Release is driven by a person deciding they are done. The leak is the case\n * where nobody decides: an agent exits, is never released, and holds its\n * worktree and branch indefinitely.\n *\n * Ownership is the branch prefix, not the path: the prefix is what the allocator\n * writes and nothing else creates. That keeps the sweep off other tools' agent\n * worktrees, which sit on ordinary branch names and are usually locked.\n */\n\n/** Where a worktree sits in the lifecycle, and therefore what may be done to it. */\nexport type SweepStatus =\n /** Its agent is still running. Nothing to do, and nothing safe to do. */\n | \"held\"\n /** Its agent has exited, but inside the window that protects unnoticed work. */\n | \"in-grace\"\n /** Uncommitted changes, or commits that exist nowhere else. Needs a person. */\n | \"holds-work\"\n /** Nobody is using it and nothing would be lost. `reclaimWorktree` takes these. */\n | \"reclaimable\";\n\n/** The agent a caller says owns a found worktree. */\nexport interface SweepOwner {\n agentId: string;\n name: string;\n state: string;\n lastEventAt: number;\n exitedAt?: number;\n}\n\n/** An allocation the caller believes it still holds. */\nexport interface HeldWorktree {\n gitRoot: string;\n branch: string;\n /** The commit the branch was cut from; release safety compares against it when there is no remote. */\n base?: string;\n}\n\nexport interface FoundWorktree {\n gitRoot: string;\n worktree: string;\n branch: string;\n}\n\nexport interface SweptWorktree extends FoundWorktree {\n status: SweepStatus;\n /** Absent when no owner was found for the worktree. */\n agent?: { agentId: string; name: string; state: string; lastEventAt: number };\n /** One line of why it is in this state, for a human reading the report. */\n detail: string;\n}\n\nexport type GitLister = (gitRoot: string) => Promise<string>;\n\nexport interface SweepOptions {\n /** Repositories to scan beyond the ones `held` names, which catches a tree no record points at. */\n roots?: readonly string[];\n held?: readonly HeldWorktree[];\n /** Joins a found worktree to its agent; the caller owns the roster. */\n ownerOf?: (found: FoundWorktree) => SweepOwner | undefined;\n branchPrefix?: string;\n list?: GitLister;\n now?: () => number;\n}\n\nconst porcelain: GitLister = async (gitRoot) =>\n execFileSync(\"git\", [\"worktree\", \"list\", \"--porcelain\"], { cwd: gitRoot, encoding: \"utf8\", env: gitChildEnv() });\n\ninterface ListedWorktree {\n worktree?: string;\n branch?: string;\n locked: boolean;\n}\n\nconst parseBlock = (block: string): ListedWorktree => ({\n worktree: block.match(/^worktree (.+)$/m)?.[1]?.trim(),\n branch: block.match(/^branch refs\\/heads\\/(.+)$/m)?.[1]?.trim(),\n locked: /^locked/m.test(block),\n});\n\n/** Every unlocked worktree in `gitRoot` whose branch carries `branchPrefix`, from git itself. */\nexport async function agentWorktreesIn(\n gitRoot: string,\n list: GitLister = porcelain,\n branchPrefix: string = branchPrefixOf({})\n): Promise<{ worktree: string; branch: string }[]> {\n const out = await list(gitRoot).catch(() => \"\");\n return (\n out\n .split(\"\\n\\n\")\n .map(parseBlock)\n .filter((e): e is Required<ListedWorktree> => e.worktree !== undefined && e.branch !== undefined)\n // Locked is another tool's \"do not touch\"; honour it rather than report a reclaim we would refuse.\n .filter((e) => !e.locked && e.branch.startsWith(branchPrefix))\n .map(({ worktree, branch }) => ({ worktree: path.resolve(worktree), branch }))\n );\n}\n\n/** Live means someone is in it; anything else has stopped and may be reclaimable. */\nexport const isLive = (state: string): boolean => state === \"live\" || state === \"spawning\";\n\nfunction classifyByOwner(\n owner: SweepOwner | undefined,\n now: number\n): { status: SweepStatus; detail: string } | undefined {\n if (owner === undefined) return undefined;\n if (isLive(owner.state)) return { status: \"held\", detail: `${owner.name} is ${owner.state}` };\n const since = now - (owner.exitedAt ?? owner.lastEventAt);\n if (since >= RECLAIM_GRACE_MS) return undefined;\n return {\n status: \"in-grace\",\n detail: `${owner.name} stopped ${Math.round(since / 1000)}s ago; reclaimable after ${RECLAIM_GRACE_MS / 1000}s`,\n };\n}\n\nfunction idleDetail(owner: SweepOwner | undefined): string {\n return owner === undefined\n ? \"no agent in the log claims this branch, and it holds nothing\"\n : `${owner.name} is ${owner.state}, and it holds nothing`;\n}\n\n/** An unknown owner is not a reason to destroy commits; the dirty/unmerged check decides. */\nasync function classify(\n found: FoundWorktree,\n owner: SweepOwner | undefined,\n base: string,\n now: number\n): Promise<SweptWorktree> {\n const agent = owner && {\n agentId: owner.agentId,\n name: owner.name,\n state: owner.state,\n lastEventAt: owner.lastEventAt,\n };\n const withAgent = { ...found, ...(agent ? { agent } : {}) };\n const byOwner = classifyByOwner(owner, now);\n if (byOwner) return { ...withAgent, ...byOwner };\n\n const safety = await inspectForRelease(found.gitRoot, found.worktree, found.branch, base);\n if (!safety.dirty && !safety.unmerged) return { ...withAgent, status: \"reclaimable\", detail: idleDetail(owner) };\n const unsaved = safety.checked.find((check) => check.name === \"dirty\" && !check.ok)?.detail;\n const detail = [unsaved, safety.unmerged && \"commits that exist nowhere else\"]\n .filter(Boolean)\n .join(\" and \");\n return { ...withAgent, status: \"holds-work\", detail };\n}\n\n/** Every allocator worktree in the named and held repositories, classified. */\nexport async function sweepWorktrees(options: SweepOptions = {}): Promise<SweptWorktree[]> {\n const now = (options.now ?? Date.now)();\n const held = new Map((options.held ?? []).map((h) => [h.branch, h]));\n const roots = new Set<string>([...(options.roots ?? []), ...[...held.values()].map((h) => h.gitRoot)]);\n const prefix = options.branchPrefix ?? branchPrefixOf({});\n\n const swept: SweptWorktree[] = [];\n for (const gitRoot of roots) {\n for (const { worktree, branch } of await agentWorktreesIn(gitRoot, options.list ?? porcelain, prefix)) {\n const found = { gitRoot, worktree, branch };\n swept.push(await classify(found, options.ownerOf?.(found), held.get(branch)?.base ?? \"HEAD\", now));\n }\n }\n return swept;\n}\n\n/**\n * Destroy one swept worktree and its branch.\n *\n * Refuses anything not `reclaimable` unless forced, so the classification is the\n * guard rather than advice. The grace window and the safety check already ran in\n * the sweep, against the report the caller read, so they are not re-derived here.\n */\nexport async function reclaimWorktree(\n entry: SweptWorktree,\n options: { force?: boolean } = {}\n): Promise<{ ok: boolean; reason?: string }> {\n if (entry.status !== \"reclaimable\" && options.force !== true)\n return { ok: false, reason: `${entry.branch} is ${entry.status}: ${entry.detail}` };\n const refused = await removeWorktree(entry.gitRoot, entry.worktree, entry.branch, options);\n return refused === undefined ? { ok: true } : { ok: false, reason: refused };\n}\n"],"mappings":"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","names":["existsSync","rmSync","path","existsSync","path","path","existsSync","existsSync","path","execFile","spawn","lstatSync","path","promisify","execFileAsync","promisify","execFile","TERM_GRACE_MS","lstatSync","path","spawn","firstLine","existsSync","path","execFile","existsSync","promisify","execFileAsync","promisify","execFile","existsSync","rmSync","existsSync","path","path","path","check"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@titan-design/worktree",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "Git worktree mechanics for headless agents: budgeted allocation, release safety, park, re-create and sweep",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",