@mutmutco/cli 3.134.0 → 3.136.0

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.
Files changed (2) hide show
  1. package/dist/main.cjs +644 -398
  2. package/package.json +1 -1
package/dist/main.cjs CHANGED
@@ -3416,7 +3416,7 @@ var program = new Command();
3416
3416
 
3417
3417
  // src/index.ts
3418
3418
  var import_promises12 = require("node:fs/promises");
3419
- var import_node_fs47 = require("node:fs");
3419
+ var import_node_fs48 = require("node:fs");
3420
3420
  var import_node_child_process19 = require("node:child_process");
3421
3421
 
3422
3422
  // src/cli-shared.ts
@@ -5313,9 +5313,10 @@ function resolveActiveWorkspaceRoot(deps = {}) {
5313
5313
  var import_node_path8 = require("node:path");
5314
5314
  function win32LongPath(p, platform2 = process.platform) {
5315
5315
  if (platform2 !== "win32") return p;
5316
- if (p.startsWith("\\\\?\\")) return p;
5317
- if (p.startsWith("\\\\")) return `\\\\?\\UNC\\${p.slice(2)}`;
5318
- return `\\\\?\\${p}`;
5316
+ const normalized = p.replace(/\//g, "\\");
5317
+ if (normalized.startsWith("\\\\?\\")) return normalized;
5318
+ if (normalized.startsWith("\\\\")) return `\\\\?\\UNC\\${normalized.slice(2)}`;
5319
+ return `\\\\?\\${normalized}`;
5319
5320
  }
5320
5321
  function normalizeGithubRemote(url) {
5321
5322
  const raw = url.trim();
@@ -5501,7 +5502,9 @@ function parseWorktreeOwners(text) {
5501
5502
  return parsed.entries.filter((e) => {
5502
5503
  if (!e || typeof e !== "object") return false;
5503
5504
  const entry = e;
5504
- return typeof entry.path === "string" && entry.path.length > 0 && typeof entry.branch === "string" && typeof entry.createdAt === "string" && typeof entry.lastSeenAt === "string" && isActor(entry.actor);
5505
+ const provenance = entry.provenance;
5506
+ const provenanceValid = provenance === void 0 || typeof provenance === "object" && typeof provenance.creationBaseOid === "string" && /^[0-9a-f]{40,64}$/i.test(provenance.creationBaseOid) && typeof provenance.workerBranch === "string" && provenance.workerBranch.length > 0;
5507
+ return typeof entry.path === "string" && entry.path.length > 0 && typeof entry.branch === "string" && typeof entry.createdAt === "string" && typeof entry.lastSeenAt === "string" && isActor(entry.actor) && provenanceValid;
5505
5508
  });
5506
5509
  }
5507
5510
  function serializeWorktreeOwners(entries) {
@@ -6399,6 +6402,8 @@ function buildGcPlan(inputs) {
6399
6402
  const preservedBranches2 = new Set(inputs.preservedBranches ?? []);
6400
6403
  const preservedWorktrees = new Set((inputs.worktrees ?? []).filter((w) => w.preserved).map((w) => w.branch));
6401
6404
  const mergedIntoBase = new Set((inputs.mergedIntoBase ?? []).map((b) => b.trim()).filter(Boolean));
6405
+ const exactTreeLanded = new Map((inputs.exactTreeLanded ?? []).map((p) => [p.branch.trim(), p]));
6406
+ const exactTreeRefusals = new Map((inputs.exactTreeRefusals ?? []).map((p) => [p.branch.trim(), p.detail]));
6402
6407
  const prLookupFailures = new Map((inputs.prLookupFailures ?? []).map((f) => [f.branch.trim(), f.detail]));
6403
6408
  const skipped = [];
6404
6409
  const branches = [];
@@ -6425,8 +6430,10 @@ function buildGcPlan(inputs) {
6425
6430
  skipped.push({ branch, reason: "open-pr" });
6426
6431
  continue;
6427
6432
  }
6428
- const state = closedState(prSet);
6429
- if (!state) continue;
6433
+ const exactDelivery = exactTreeLanded.get(branch);
6434
+ const exactRefusal = exactTreeRefusals.get(branch);
6435
+ const state = closedState(prSet) ?? (exactDelivery ? { state: "EXACT_TREE", numbers: [], headOids: [] } : null);
6436
+ if (!state && !exactRefusal) continue;
6430
6437
  if (branch === inputs.currentBranch) {
6431
6438
  skipped.push({ branch, reason: "current-branch" });
6432
6439
  skipTrackingBranches.add(branch);
@@ -6443,8 +6450,14 @@ function buildGcPlan(inputs) {
6443
6450
  skipTrackingBranches.add(branch);
6444
6451
  continue;
6445
6452
  }
6453
+ if (!state) {
6454
+ skipped.push({ branch, reason: "exact-tree-proof-refused", detail: exactRefusal });
6455
+ skipTrackingBranches.add(branch);
6456
+ continue;
6457
+ }
6446
6458
  const localHead = branchHeads?.get(branch);
6447
- const containedInBase = mergedIntoBase.has(branch);
6459
+ const exactHeadStillMatches = Boolean(exactDelivery && localHead === exactDelivery.headOid);
6460
+ const containedInBase = mergedIntoBase.has(branch) || exactHeadStillMatches;
6448
6461
  if (!containedInBase && (worktree2?.unpushed || branchHeads && (!localHead || !state.headOids.length || !state.headOids.includes(localHead)))) {
6449
6462
  const detail = worktree2?.unpushed ? worktree2.path : localHead && state.headOids.length ? `${localHead} != ${state.headOids.join("|")}` : "local branch head could not be verified against the PR head";
6450
6463
  skipped.push({ branch, reason: "unpushed-branch", detail });
@@ -6457,7 +6470,8 @@ function buildGcPlan(inputs) {
6457
6470
  prNumbers: state.numbers,
6458
6471
  worktreePath: worktree2?.path,
6459
6472
  ...state.headOids.length ? { reviewedHeadOids: state.headOids } : {},
6460
- ...containedInBase ? { containedInBase: true, ...localHead ? { plannedHeadOid: localHead } : {} } : {}
6473
+ ...containedInBase ? { containedInBase: true, ...localHead ? { plannedHeadOid: localHead } : {} } : {},
6474
+ ...exactHeadStillMatches ? { deliveredBy: exactDelivery.candidateOid } : {}
6461
6475
  });
6462
6476
  }
6463
6477
  const trackingRefs = [...new Set(inputs.staleTrackingRefs ?? [])].map((ref) => {
@@ -7059,7 +7073,8 @@ function formatGcPlan(plan, apply, auditClone) {
7059
7073
  for (const b of plan.branches) {
7060
7074
  const prs = b.prNumbers.length ? ` #${b.prNumbers.join(",#")}` : "";
7061
7075
  const wt = b.worktreePath ? ` (worktree: ${b.worktreePath})` : "";
7062
- lines.push(` - ${b.branch} (${b.prState}${prs})${wt}`);
7076
+ const authority = b.deliveredBy ? `${b.prState}; deliveredBy ${b.deliveredBy}` : `${b.prState}${prs}`;
7077
+ lines.push(` - ${b.branch} (${authority})${wt}`);
7063
7078
  }
7064
7079
  }
7065
7080
  const remoteBranches = plan.branches.filter((b) => (b.reviewedHeadOids?.length ?? 0) > 0);
@@ -7868,7 +7883,7 @@ function commandLadderHint() {
7868
7883
  }
7869
7884
 
7870
7885
  // src/index.ts
7871
- var import_node_path45 = require("node:path");
7886
+ var import_node_path46 = require("node:path");
7872
7887
 
7873
7888
  // src/merge-ci-policy.ts
7874
7889
  function resolveMergeCiPolicy(input) {
@@ -9751,9 +9766,9 @@ function parseVerifyBroker(stdout) {
9751
9766
  }
9752
9767
 
9753
9768
  // src/train-apply.ts
9754
- var import_node_fs22 = require("node:fs");
9769
+ var import_node_fs23 = require("node:fs");
9755
9770
  var import_promises4 = require("node:fs/promises");
9756
- var import_node_path22 = require("node:path");
9771
+ var import_node_path23 = require("node:path");
9757
9772
 
9758
9773
  // src/plugin-guard-io.ts
9759
9774
  var import_node_fs19 = require("node:fs");
@@ -11185,9 +11200,9 @@ function renderAccessReport(report) {
11185
11200
  }
11186
11201
 
11187
11202
  // src/cli-doctor-shared.ts
11188
- var import_node_fs20 = require("node:fs");
11189
- var import_node_path21 = require("node:path");
11190
11203
  var import_node_fs21 = require("node:fs");
11204
+ var import_node_path22 = require("node:path");
11205
+ var import_node_fs22 = require("node:fs");
11191
11206
 
11192
11207
  // ../infra/registry-endpoints.mjs
11193
11208
  var PROJECTS_LIST_PATH = "/projects/list";
@@ -13629,6 +13644,142 @@ async function fileReport(deps, req) {
13629
13644
  return { ok: true, body };
13630
13645
  }
13631
13646
 
13647
+ // src/worktree-delivery-proof.ts
13648
+ var import_node_fs20 = require("node:fs");
13649
+ var import_node_os9 = require("node:os");
13650
+ var import_node_path21 = require("node:path");
13651
+ var OID_RE = /^[0-9a-f]{40,64}$/i;
13652
+ var EXACT_TREE_CANDIDATE_LIMIT = 32;
13653
+ async function repointDeliveredWorktreeTransactionally(input) {
13654
+ const symbolic = (await input.git(["symbolic-ref", "--quiet", "--short", "HEAD"]).catch(() => "")).trim();
13655
+ if (symbolic !== input.branch) return { action: "refuse", reason: "wrong-branch", detail: symbolic || "detached HEAD" };
13656
+ const current = (await input.git(["rev-parse", "--verify", `refs/heads/${input.branch}`]).catch(() => "")).trim();
13657
+ if (current !== input.expectedWorkerOid) {
13658
+ return { action: "refuse", reason: "worker-moved", detail: `${current || "unreadable"} != ${input.expectedWorkerOid}` };
13659
+ }
13660
+ const status = await input.git(["status", "--porcelain"]).catch(() => "unreadable");
13661
+ if (status.trim()) return { action: "refuse", reason: "dirty-worktree", detail: "tracked or untracked files present" };
13662
+ try {
13663
+ await input.git(["checkout", "-B", input.branch, input.landedTipOid]);
13664
+ return { action: "repointed" };
13665
+ } catch (error) {
13666
+ return { action: "refuse", reason: "checkout-failed", detail: error instanceof Error ? error.message : String(error) };
13667
+ }
13668
+ }
13669
+ function supportsExactTreeProofGit(versionOutput) {
13670
+ const match = /\bgit version (\d+)\.(\d+)(?:\.\d+)?/i.exec(versionOutput.trim());
13671
+ if (!match) return false;
13672
+ const major = Number(match[1]);
13673
+ const minor = Number(match[2]);
13674
+ return major > 2 || major === 2 && minor >= 32;
13675
+ }
13676
+ function describeExactTreeRefusal(verdict) {
13677
+ return `${verdict.reason}${verdict.detail ? `: ${verdict.detail}` : ""}`;
13678
+ }
13679
+ function sameChangedPathSet(a, b) {
13680
+ const sorted = (value) => value.split("\0").filter(Boolean).sort().join("\0");
13681
+ return sorted(a) === sorted(b);
13682
+ }
13683
+ async function proveExactTreeDelivery(input, deps = {}) {
13684
+ const base = input.creationBaseOid?.trim();
13685
+ if (!base || !OID_RE.test(base)) return { action: "refuse", reason: "missing-provenance" };
13686
+ if (!input.recordedWorkerBranch || input.recordedWorkerBranch !== input.branch) {
13687
+ return { action: "refuse", reason: "worker-identity-mismatch" };
13688
+ }
13689
+ if (!OID_RE.test(input.workerOid)) return { action: "refuse", reason: "proof-failed", detail: "worker OID is invalid" };
13690
+ const run = deps.git ?? (async (args, env) => (await execFileP2("git", ["-C", input.repoRoot, ...args], {
13691
+ timeout: GIT_TIMEOUT_MS,
13692
+ ...env ? { env: { ...process.env, ...env } } : {}
13693
+ })).stdout);
13694
+ const isAncestor = (ancestor, descendant) => run(["merge-base", "--is-ancestor", ancestor, descendant]).then(() => true).catch(() => false);
13695
+ let version;
13696
+ try {
13697
+ version = await run(["version"]);
13698
+ } catch {
13699
+ return { action: "refuse", reason: "proof-failed", detail: "Git capability probe failed" };
13700
+ }
13701
+ if (!supportsExactTreeProofGit(version)) {
13702
+ return { action: "refuse", reason: "unsupported-git", detail: `requires Git >=2.32; found ${version.trim() || "unparseable version"}` };
13703
+ }
13704
+ try {
13705
+ const [baseType, workerType] = await Promise.all([
13706
+ run(["cat-file", "-t", base]).then((v) => v.trim()).catch(() => ""),
13707
+ run(["cat-file", "-t", input.workerOid]).then((v) => v.trim()).catch(() => "")
13708
+ ]);
13709
+ if (baseType !== "commit" || workerType !== "commit" || !await isAncestor(base, input.workerOid)) {
13710
+ return { action: "refuse", reason: "unverified-base" };
13711
+ }
13712
+ const candidates = /* @__PURE__ */ new Map();
13713
+ for (const tip of [...new Set(input.landedTips.map((v) => v.trim()).filter(Boolean))]) {
13714
+ if (!OID_RE.test(tip) || !await isAncestor(base, tip)) continue;
13715
+ const listed = await run([
13716
+ "rev-list",
13717
+ "--first-parent",
13718
+ "--parents",
13719
+ `--max-count=${EXACT_TREE_CANDIDATE_LIMIT + 1}`,
13720
+ `${base}..${tip}`
13721
+ ]);
13722
+ const rows = listed.split(/\r?\n/).map((v) => v.trim()).filter(Boolean);
13723
+ if (rows.length > EXACT_TREE_CANDIDATE_LIMIT) {
13724
+ return {
13725
+ action: "refuse",
13726
+ reason: "candidate-limit-exceeded",
13727
+ detail: `more than ${EXACT_TREE_CANDIDATE_LIMIT} first-parent candidates since stored base`
13728
+ };
13729
+ }
13730
+ for (const row of rows) {
13731
+ const [oid, parent] = row.split(/\s+/);
13732
+ if (oid && parent && OID_RE.test(oid) && OID_RE.test(parent)) candidates.set(oid, parent);
13733
+ }
13734
+ if (candidates.size > EXACT_TREE_CANDIDATE_LIMIT) {
13735
+ return {
13736
+ action: "refuse",
13737
+ reason: "candidate-limit-exceeded",
13738
+ detail: `more than ${EXACT_TREE_CANDIDATE_LIMIT} unique first-parent candidates across landed tips`
13739
+ };
13740
+ }
13741
+ }
13742
+ if (!candidates.size) return { action: "refuse", reason: "no-candidate" };
13743
+ const workerPaths = await run(["diff", "--name-only", "-z", "--no-renames", base, input.workerOid]);
13744
+ const pathMatches = [];
13745
+ for (const [candidate, parent] of candidates) {
13746
+ const candidatePaths = await run(["diff", "--name-only", "-z", "--no-renames", parent, candidate]);
13747
+ if (sameChangedPathSet(workerPaths, candidatePaths)) pathMatches.push([candidate, parent]);
13748
+ }
13749
+ if (!pathMatches.length) return { action: "refuse", reason: "tree-mismatch" };
13750
+ const makeTempDir = deps.makeTempDir ?? (() => (0, import_node_fs20.mkdtempSync)((0, import_node_path21.join)((0, import_node_os9.tmpdir)(), "mmi-tree-proof-")));
13751
+ const writeTextFile = deps.writeTextFile ?? ((path2, text) => (0, import_node_fs20.writeFileSync)(path2, text, "utf8"));
13752
+ const removeTempDir = deps.removeTempDir ?? ((path2) => (0, import_node_fs20.rmSync)(path2, { recursive: true, force: true }));
13753
+ const root = makeTempDir();
13754
+ try {
13755
+ const synthesize = async (name, from, to) => {
13756
+ const index = (0, import_node_path21.join)(root, `${name}.index`);
13757
+ const patch = (0, import_node_path21.join)(root, `${name}.patch`);
13758
+ const env = { GIT_INDEX_FILE: index };
13759
+ await run(["read-tree", base], env);
13760
+ const delta = await run(["diff-tree", "-p", "--binary", "--full-index", "--no-renames", "--no-ext-diff", from, to]);
13761
+ writeTextFile(patch, delta);
13762
+ if (delta.length) await run(["apply", "--cached", "--binary", "--3way", patch], env);
13763
+ return (await run(["write-tree"], env)).trim();
13764
+ };
13765
+ const workerTreeOid = await synthesize("worker", base, input.workerOid);
13766
+ const matches = [];
13767
+ let candidateNumber = 0;
13768
+ for (const [candidate, parent] of pathMatches) {
13769
+ const tree = await synthesize(`candidate-${candidateNumber++}`, parent, candidate).catch(() => void 0);
13770
+ if (tree === workerTreeOid) matches.push(candidate);
13771
+ }
13772
+ if (matches.length === 1) return { action: "settle", workerTreeOid, candidateOid: matches[0] };
13773
+ if (matches.length > 1) return { action: "refuse", reason: "ambiguous-candidate" };
13774
+ return { action: "refuse", reason: "tree-mismatch" };
13775
+ } finally {
13776
+ removeTempDir(root);
13777
+ }
13778
+ } catch (error) {
13779
+ return { action: "refuse", reason: "proof-failed", detail: error instanceof Error ? error.message : String(error) };
13780
+ }
13781
+ }
13782
+
13632
13783
  // src/cli-doctor-shared.ts
13633
13784
  var GC_GH_TIMEOUT_MS = 2e4;
13634
13785
  var RUN_LIST_TIMEOUT_MS = 2e4;
@@ -13731,7 +13882,7 @@ async function localBranchHeads() {
13731
13882
  }
13732
13883
  async function currentRepoWorktreeGitRoot(repoRoot2) {
13733
13884
  const gitCommonDir = (await execFileP2("git", ["rev-parse", "--git-common-dir"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim();
13734
- return gitCommonDir ? (0, import_node_path21.resolve)(repoRoot2, gitCommonDir, "worktrees") : "";
13885
+ return gitCommonDir ? (0, import_node_path22.resolve)(repoRoot2, gitCommonDir, "worktrees") : "";
13735
13886
  }
13736
13887
  async function worktreeBranches() {
13737
13888
  const { stdout } = await execFileP2("git", ["worktree", "list", "--porcelain"], { timeout: GIT_TIMEOUT_MS });
@@ -13751,18 +13902,18 @@ function resolveGitdirForWorktreeFile(worktreePath, content) {
13751
13902
  const match = /^gitdir:\s*(.+)\s*$/im.exec(content);
13752
13903
  if (!match?.[1]) return void 0;
13753
13904
  const raw = match[1].trim();
13754
- return (0, import_node_path21.isAbsolute)(raw) ? raw : (0, import_node_path21.resolve)(worktreePath, raw);
13905
+ return (0, import_node_path22.isAbsolute)(raw) ? raw : (0, import_node_path22.resolve)(worktreePath, raw);
13755
13906
  }
13756
13907
  function metadataOwnsMissingWorktreeDir(worktreePath, worktreeGitRoot) {
13757
13908
  if (!worktreeGitRoot) return false;
13758
13909
  try {
13759
- const entries = (0, import_node_fs21.readdirSync)(worktreeGitRoot, { withFileTypes: true });
13910
+ const entries = (0, import_node_fs22.readdirSync)(worktreeGitRoot, { withFileTypes: true });
13760
13911
  for (const ent of entries) {
13761
13912
  if (!ent.isDirectory()) continue;
13762
13913
  try {
13763
- const gitdirPath = (0, import_node_fs20.readFileSync)((0, import_node_path21.join)(worktreeGitRoot, ent.name, "gitdir"), "utf8").trim();
13764
- const resolvedGitdir = (0, import_node_path21.isAbsolute)(gitdirPath) ? gitdirPath : (0, import_node_path21.resolve)(worktreeGitRoot, ent.name, gitdirPath);
13765
- if (sameWorktreeMetadataPath((0, import_node_path21.dirname)(resolvedGitdir), worktreePath)) return true;
13914
+ const gitdirPath = (0, import_node_fs21.readFileSync)((0, import_node_path22.join)(worktreeGitRoot, ent.name, "gitdir"), "utf8").trim();
13915
+ const resolvedGitdir = (0, import_node_path22.isAbsolute)(gitdirPath) ? gitdirPath : (0, import_node_path22.resolve)(worktreeGitRoot, ent.name, gitdirPath);
13916
+ if (sameWorktreeMetadataPath((0, import_node_path22.dirname)(resolvedGitdir), worktreePath)) return true;
13766
13917
  } catch {
13767
13918
  }
13768
13919
  }
@@ -13772,7 +13923,7 @@ function metadataOwnsMissingWorktreeDir(worktreePath, worktreeGitRoot) {
13772
13923
  }
13773
13924
  function pathExistsKnown(path2) {
13774
13925
  try {
13775
- (0, import_node_fs21.statSync)(path2);
13926
+ (0, import_node_fs22.statSync)(path2);
13776
13927
  return true;
13777
13928
  } catch (e) {
13778
13929
  const code = typeof e === "object" && e && "code" in e ? String(e.code ?? "") : "";
@@ -13781,10 +13932,10 @@ function pathExistsKnown(path2) {
13781
13932
  }
13782
13933
  }
13783
13934
  function inspectSiblingWorktreeDir(path2, worktreeGitRoot) {
13784
- const gitPath = (0, import_node_path21.join)(path2, ".git");
13935
+ const gitPath = (0, import_node_path22.join)(path2, ".git");
13785
13936
  let st;
13786
13937
  try {
13787
- st = (0, import_node_fs21.lstatSync)(gitPath);
13938
+ st = (0, import_node_fs22.lstatSync)(gitPath);
13788
13939
  } catch (e) {
13789
13940
  const code = typeof e === "object" && e && "code" in e ? String(e.code ?? "") : "";
13790
13941
  if (code === "ENOENT" || code === "ENOTDIR") {
@@ -13801,7 +13952,7 @@ function inspectSiblingWorktreeDir(path2, worktreeGitRoot) {
13801
13952
  if (st.isDirectory()) return { path: path2, gitType: "dir" };
13802
13953
  if (!st.isFile()) return { path: path2, gitType: "other" };
13803
13954
  try {
13804
- const gitFileContent = (0, import_node_fs20.readFileSync)(gitPath, "utf8");
13955
+ const gitFileContent = (0, import_node_fs21.readFileSync)(gitPath, "utf8");
13805
13956
  const gitdir = resolveGitdirForWorktreeFile(path2, gitFileContent);
13806
13957
  const gitDirExists = gitdir ? pathExistsKnown(gitdir) : false;
13807
13958
  return {
@@ -13818,7 +13969,7 @@ function inspectSiblingWorktreeDir(path2, worktreeGitRoot) {
13818
13969
  }
13819
13970
  function inspectDeadWorktreeDirContent(path2) {
13820
13971
  try {
13821
- return { entries: (0, import_node_fs21.readdirSync)(path2) };
13972
+ return { entries: (0, import_node_fs22.readdirSync)(path2) };
13822
13973
  } catch (e) {
13823
13974
  const code = typeof e === "object" && e && "code" in e ? String(e.code ?? "") : "";
13824
13975
  return { error: code ? `unable to inspect directory contents (${code})` : "unable to inspect directory contents" };
@@ -13835,11 +13986,11 @@ async function preservedBranches() {
13835
13986
  async function siblingWorktreeDirs(explicitRoot) {
13836
13987
  const repoRoot2 = (await execFileP2("git", ["rev-parse", "--show-toplevel"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim() || process.cwd();
13837
13988
  const worktreeGitRoot = await currentRepoWorktreeGitRoot(repoRoot2);
13838
- const primaryRepoRoot = worktreeGitRoot ? (0, import_node_path21.dirname)((0, import_node_path21.dirname)(worktreeGitRoot)) : repoRoot2;
13989
+ const primaryRepoRoot = worktreeGitRoot ? (0, import_node_path22.dirname)((0, import_node_path22.dirname)(worktreeGitRoot)) : repoRoot2;
13839
13990
  try {
13840
13991
  const dirs = explicitRoot ? listDirsIn(resolveExplicitScanRoot(explicitRoot, primaryRepoRoot)) : worktreeScanDirs(siblingMmiWorktreesRoot(primaryRepoRoot), primaryRepoRoot, listDirsIn, isRepoCheckoutDir);
13841
13992
  const agentDirs = listDirsIn(agentWorktreesRoot(primaryRepoRoot));
13842
- const repoLocalWorktrees = listDirsIn((0, import_node_path21.join)(primaryRepoRoot, ".worktrees"));
13993
+ const repoLocalWorktrees = listDirsIn((0, import_node_path22.join)(primaryRepoRoot, ".worktrees"));
13843
13994
  return [...dirs, ...agentDirs, ...repoLocalWorktrees].map((dir) => inspectSiblingWorktreeDir(dir, worktreeGitRoot)).filter((entry) => Boolean(entry));
13844
13995
  } catch {
13845
13996
  return [];
@@ -13847,18 +13998,18 @@ async function siblingWorktreeDirs(explicitRoot) {
13847
13998
  }
13848
13999
  function listDirsIn(dir) {
13849
14000
  try {
13850
- return (0, import_node_fs21.readdirSync)(dir, { withFileTypes: true }).filter((ent) => ent.isDirectory()).map((ent) => (0, import_node_path21.join)(dir, ent.name));
14001
+ return (0, import_node_fs22.readdirSync)(dir, { withFileTypes: true }).filter((ent) => ent.isDirectory()).map((ent) => (0, import_node_path22.join)(dir, ent.name));
13851
14002
  } catch {
13852
14003
  return [];
13853
14004
  }
13854
14005
  }
13855
14006
  function isRepoCheckoutDir(dir) {
13856
- return (0, import_node_fs21.existsSync)((0, import_node_path21.join)(dir, ".git"));
14007
+ return (0, import_node_fs22.existsSync)((0, import_node_path22.join)(dir, ".git"));
13857
14008
  }
13858
14009
  function resolveExplicitScanRoot(explicitRoot, repoRoot2) {
13859
14010
  let rootDirs;
13860
14011
  try {
13861
- rootDirs = (0, import_node_fs21.readdirSync)(explicitRoot, { withFileTypes: true }).filter((ent) => ent.isDirectory()).map((ent) => ent.name);
14012
+ rootDirs = (0, import_node_fs22.readdirSync)(explicitRoot, { withFileTypes: true }).filter((ent) => ent.isDirectory()).map((ent) => ent.name);
13862
14013
  } catch {
13863
14014
  return explicitRoot;
13864
14015
  }
@@ -13889,6 +14040,38 @@ async function gcPlan(remote, limit, opts = {}) {
13889
14040
  ])].filter((b) => !isProtectedBranch(b)),
13890
14041
  limit
13891
14042
  );
14043
+ const primaryRoot = await primaryCheckoutRootOf(gitOut);
14044
+ const owners = primaryRoot ? readWorktreeOwners(primaryRoot) : [];
14045
+ const mergedSet = new Set(mergedIntoBase);
14046
+ const preservedSet = new Set(preserved);
14047
+ const failedLookups = new Set(failures.map((failure) => failure.branch));
14048
+ const openBranches = new Set(prs.filter((pr2) => pr2.state === "OPEN").map((pr2) => pr2.headRefName));
14049
+ const proofWorktrees = worktrees.filter((wt) => !wt.dirty && wt.branch !== current.trim() && !isProtectedBranch(wt.branch) && !preservedSet.has(wt.branch) && !mergedSet.has(wt.branch) && !failedLookups.has(wt.branch) && !openBranches.has(wt.branch));
14050
+ const trainTips = [];
14051
+ if (proofWorktrees.length) {
14052
+ for (const name of ["development", "main", "master"]) {
14053
+ const oid = (await gitOut(["rev-parse", "--verify", `${remote}/${name}`]).catch(() => "")).trim();
14054
+ if (oid) trainTips.push(oid);
14055
+ }
14056
+ }
14057
+ const headByBranch = new Map(heads.map((h) => [h.branch, h.oid]));
14058
+ const exactTreeLanded = [];
14059
+ const exactTreeRefusals = [];
14060
+ for (const wt of proofWorktrees) {
14061
+ const headOid = headByBranch.get(wt.branch);
14062
+ const owner = owners.find((entry) => sameWorktreeMetadataPath(entry.path, wt.path));
14063
+ if (!headOid || !owner || !primaryRoot) continue;
14064
+ const proof = await proveExactTreeDelivery({
14065
+ repoRoot: primaryRoot,
14066
+ branch: wt.branch,
14067
+ workerOid: headOid,
14068
+ creationBaseOid: owner.provenance?.creationBaseOid,
14069
+ recordedWorkerBranch: owner.provenance?.workerBranch,
14070
+ landedTips: trainTips
14071
+ });
14072
+ if (proof.action === "settle") exactTreeLanded.push({ branch: wt.branch, headOid, candidateOid: proof.candidateOid });
14073
+ else exactTreeRefusals.push({ branch: wt.branch, detail: describeExactTreeRefusal(proof) });
14074
+ }
13892
14075
  return buildGcPlan({
13893
14076
  localBranches,
13894
14077
  prLookupFailures: failures,
@@ -13901,6 +14084,8 @@ async function gcPlan(remote, limit, opts = {}) {
13901
14084
  remote,
13902
14085
  preservedBranches: preserved,
13903
14086
  mergedIntoBase,
14087
+ exactTreeLanded,
14088
+ exactTreeRefusals,
13904
14089
  originBranches,
13905
14090
  trainOnly: opts.trainOnly
13906
14091
  });
@@ -14199,10 +14384,10 @@ var rollout_plan_default = {
14199
14384
  note: "The v4.0.0 stamp happens at cut time (D6e #4463); until then the candidate is the origin/development head artifacts (built cli/dist + npm pack), identity proven by dist content hash (D6a)."
14200
14385
  },
14201
14386
  baseline: {
14202
- version: "3.134.0",
14203
- tag: "v3.134.0",
14204
- commit: "15870712ab5a",
14205
- npm: "@mutmutco/cli@3.134.0"
14387
+ version: "3.136.0",
14388
+ tag: "v3.136.0",
14389
+ commit: "acba68c21013",
14390
+ npm: "@mutmutco/cli@3.136.0"
14206
14391
  },
14207
14392
  exitCriterion: "fleet-n-of-n",
14208
14393
  hubOnlyShortcut: "forbidden",
@@ -14219,14 +14404,14 @@ var rollout_plan_default = {
14219
14404
  repo: "mutmutco/mmi-hub",
14220
14405
  role: "canary",
14221
14406
  schedule: "train",
14222
- v3Target: "v3.134.0"
14407
+ v3Target: "v3.136.0"
14223
14408
  }
14224
14409
  ],
14225
14410
  rollbackTrigger: "Any red inside the post-cut soak window: `devops train gate` FAIL attributable to the v4 doors, Hub endpoint health probe failure, a v3 client refused while the compat window must still admit it (SUPPORTED_MINOR_WINDOW=2, MIN_CLIENT_VERSION 0.0.0 \u2014 D6a), or npm consumer install/doctor failure on the v4 dist.",
14226
14411
  rollback: {
14227
14412
  independent: true,
14228
- mechanism: "npm dist-tag latest -> 3.134.0 and redeploy the Hub Lambda from tag v3.134.0 (15870712ab5a); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
14229
- v3Target: "v3.134.0 (@mutmutco/cli@3.134.0, tag commit 15870712ab5a \u2014 the preserved latest-v3 distribution, D6b)"
14413
+ mechanism: "npm dist-tag latest -> 3.136.0 and redeploy the Hub Lambda from tag v3.136.0 (acba68c21013); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
14414
+ v3Target: "v3.136.0 (@mutmutco/cli@3.136.0, tag commit acba68c21013 \u2014 the preserved latest-v3 distribution, D6b)"
14230
14415
  }
14231
14416
  },
14232
14417
  {
@@ -16310,7 +16495,7 @@ function planTrainApplyRepoGuard(applyRepo, cwdRepo, rerun) {
16310
16495
  async function resolveFoldPaths(deps, model) {
16311
16496
  const helper = "scripts/release-distribution.mjs";
16312
16497
  if (model === "hub-serverless" || model === "registry-publish") {
16313
- if ((0, import_node_fs22.existsSync)(helper)) {
16498
+ if ((0, import_node_fs23.existsSync)(helper)) {
16314
16499
  let out;
16315
16500
  try {
16316
16501
  out = await deps.run("node", [helper, "changed-files"]);
@@ -16429,7 +16614,7 @@ async function restoreMainNpmPackIdentities(deps, version) {
16429
16614
  if (mainBom.version !== version) return void 0;
16430
16615
  let localBom;
16431
16616
  try {
16432
- localBom = JSON.parse((0, import_node_fs22.readFileSync)(bomPath, "utf8"));
16617
+ localBom = JSON.parse((0, import_node_fs23.readFileSync)(bomPath, "utf8"));
16433
16618
  } catch (e) {
16434
16619
  throw new Error(
16435
16620
  `version fold refused: ${bomPath} written by this fold's prepare is unreadable (${describeReadError(e)}) \u2014 cannot restore the published ${version} npm-pack identities from origin/main (#4503/#4713).`
@@ -16447,14 +16632,14 @@ async function restoreMainNpmPackIdentities(deps, version) {
16447
16632
  restored += 1;
16448
16633
  }
16449
16634
  if (restored === 0) return void 0;
16450
- (0, import_node_fs22.writeFileSync)(bomPath, `${JSON.stringify(localBom, null, 2)}
16635
+ (0, import_node_fs23.writeFileSync)(bomPath, `${JSON.stringify(localBom, null, 2)}
16451
16636
  `);
16452
16637
  return `restored ${restored} npm-pack BOM identit${restored === 1 ? "y" : "ies"} from origin/main (#4503)`;
16453
16638
  }
16454
16639
  function publishVisibilityFor(surfaceId) {
16455
16640
  let raw;
16456
16641
  try {
16457
- raw = (0, import_node_fs22.readFileSync)("surfaces.json", "utf8");
16642
+ raw = (0, import_node_fs23.readFileSync)("surfaces.json", "utf8");
16458
16643
  } catch (e) {
16459
16644
  if (e.code === "ENOENT") return "unknown";
16460
16645
  throw trainReadFailure(
@@ -16475,7 +16660,7 @@ function publishVisibilityFor(surfaceId) {
16475
16660
  }
16476
16661
  function npmPackArtifactName(packagePath) {
16477
16662
  try {
16478
- const pkg = JSON.parse((0, import_node_fs22.readFileSync)((0, import_node_path22.join)(packagePath, "package.json"), "utf8"));
16663
+ const pkg = JSON.parse((0, import_node_fs23.readFileSync)((0, import_node_path23.join)(packagePath, "package.json"), "utf8"));
16479
16664
  return pkg.name || void 0;
16480
16665
  } catch {
16481
16666
  return void 0;
@@ -16484,7 +16669,7 @@ function npmPackArtifactName(packagePath) {
16484
16669
  async function refuseDivergentPublishedNpmPack(deps, version) {
16485
16670
  let localBom;
16486
16671
  try {
16487
- localBom = JSON.parse((0, import_node_fs22.readFileSync)("distribution-bom.json", "utf8"));
16672
+ localBom = JSON.parse((0, import_node_fs23.readFileSync)("distribution-bom.json", "utf8"));
16488
16673
  } catch (e) {
16489
16674
  throw new Error(
16490
16675
  `version fold refused: distribution-bom.json written by this fold's prepare is unreadable (${e instanceof Error ? e.message.split("\n")[0] : String(e)}) \u2014 cannot compare the same-PATCH ${version} npm-pack identities against published npm (#4503/#4662).`
@@ -17646,17 +17831,17 @@ async function dispatchDeploy(deps, ctx, stage, ref, model, watch, autoRunSince,
17646
17831
  return { note: `no manual dispatch: ${model} repo deploys via its own push-triggered workflow`, deployStatus: "pending" };
17647
17832
  }
17648
17833
  function readLocalGateWorkflows() {
17649
- const dir = (0, import_node_path22.join)(".github", "workflows");
17834
+ const dir = (0, import_node_path23.join)(".github", "workflows");
17650
17835
  let names;
17651
17836
  try {
17652
- names = (0, import_node_fs22.readdirSync)(dir);
17837
+ names = (0, import_node_fs23.readdirSync)(dir);
17653
17838
  } catch {
17654
17839
  return null;
17655
17840
  }
17656
17841
  const files = [];
17657
17842
  for (const name of names.filter(isGateWorkflowPath)) {
17658
17843
  try {
17659
- files.push({ path: `${dir}/${name}`.replace(/\\/g, "/"), body: (0, import_node_fs22.readFileSync)((0, import_node_path22.join)(dir, name), "utf8") });
17844
+ files.push({ path: `${dir}/${name}`.replace(/\\/g, "/"), body: (0, import_node_fs23.readFileSync)((0, import_node_path23.join)(dir, name), "utf8") });
17660
17845
  } catch {
17661
17846
  }
17662
17847
  }
@@ -19874,12 +20059,12 @@ async function runPrLand(prNumber, options, deps) {
19874
20059
  }
19875
20060
 
19876
20061
  // src/wave-status.ts
19877
- var import_node_fs24 = require("node:fs");
20062
+ var import_node_fs25 = require("node:fs");
19878
20063
 
19879
20064
  // src/stage-runner.ts
19880
20065
  var import_node_child_process8 = require("node:child_process");
19881
- var import_node_fs23 = require("node:fs");
19882
- var import_node_path23 = require("node:path");
20066
+ var import_node_fs24 = require("node:fs");
20067
+ var import_node_path24 = require("node:path");
19883
20068
  var import_node_net = require("node:net");
19884
20069
  var import_node_util5 = require("node:util");
19885
20070
 
@@ -20018,11 +20203,11 @@ function appendForceRecreate(up) {
20018
20203
  return `${up.trimEnd()} --force-recreate`;
20019
20204
  }
20020
20205
  function stageStatePath(cwd = process.cwd()) {
20021
- return (0, import_node_path23.join)(cwd, "tmp", "stage", "state.json");
20206
+ return (0, import_node_path24.join)(cwd, "tmp", "stage", "state.json");
20022
20207
  }
20023
20208
  function stageGlobalStatePath(cwd = process.cwd(), gitCommonDir = ".git") {
20024
- const dir = (0, import_node_path23.isAbsolute)(gitCommonDir) ? gitCommonDir : (0, import_node_path23.resolve)(cwd, gitCommonDir);
20025
- return (0, import_node_path23.join)(dir, "mmi", "stage", "state.json");
20209
+ const dir = (0, import_node_path24.isAbsolute)(gitCommonDir) ? gitCommonDir : (0, import_node_path24.resolve)(cwd, gitCommonDir);
20210
+ return (0, import_node_path24.join)(dir, "mmi", "stage", "state.json");
20026
20211
  }
20027
20212
  function normPath3(path2) {
20028
20213
  return path2.replace(/\\/g, "/").replace(/\/+$/, "").toLowerCase();
@@ -20246,14 +20431,14 @@ function stageProcessEnv(stagePort, extraEnv) {
20246
20431
  }
20247
20432
  async function ensureStageRuntimeEnv(config, opts, cwd) {
20248
20433
  if (!config.ensureEnv) return;
20249
- const target = (0, import_node_path23.join)(cwd, config.ensureEnv.target);
20250
- const example = (0, import_node_path23.join)(cwd, config.ensureEnv.example);
20251
- if (!(0, import_node_fs23.existsSync)(target) && (0, import_node_fs23.existsSync)(example)) {
20252
- (0, import_node_fs23.copyFileSync)(example, target);
20253
- } else if ((0, import_node_fs23.existsSync)(target) && (0, import_node_fs23.existsSync)(example)) {
20254
- const stale = detectStaleEnvFile((0, import_node_fs23.readFileSync)(example, "utf8"), (0, import_node_fs23.readFileSync)(target, "utf8"), {
20255
- exampleMtimeMs: (0, import_node_fs23.statSync)(example).mtimeMs,
20256
- targetMtimeMs: (0, import_node_fs23.statSync)(target).mtimeMs
20434
+ const target = (0, import_node_path24.join)(cwd, config.ensureEnv.target);
20435
+ const example = (0, import_node_path24.join)(cwd, config.ensureEnv.example);
20436
+ if (!(0, import_node_fs24.existsSync)(target) && (0, import_node_fs24.existsSync)(example)) {
20437
+ (0, import_node_fs24.copyFileSync)(example, target);
20438
+ } else if ((0, import_node_fs24.existsSync)(target) && (0, import_node_fs24.existsSync)(example)) {
20439
+ const stale = detectStaleEnvFile((0, import_node_fs24.readFileSync)(example, "utf8"), (0, import_node_fs24.readFileSync)(target, "utf8"), {
20440
+ exampleMtimeMs: (0, import_node_fs24.statSync)(example).mtimeMs,
20441
+ targetMtimeMs: (0, import_node_fs24.statSync)(target).mtimeMs
20257
20442
  });
20258
20443
  if (stale) {
20259
20444
  const msg = `stale ${config.ensureEnv.target} (${stale}) \u2014 delete it or refresh from ${config.ensureEnv.example} before re-running /stage`;
@@ -20261,8 +20446,8 @@ async function ensureStageRuntimeEnv(config, opts, cwd) {
20261
20446
  console.error(`mmi-cli stage: ${msg} (allowed via --allow-stale-env)`);
20262
20447
  }
20263
20448
  }
20264
- if (opts.vaultEnvMerge && Object.keys(opts.vaultEnvMerge).length && (0, import_node_fs23.existsSync)(target)) {
20265
- (0, import_node_fs23.writeFileSync)(target, mergeEnvSecretsIntoFile((0, import_node_fs23.readFileSync)(target, "utf8"), opts.vaultEnvMerge), "utf8");
20449
+ if (opts.vaultEnvMerge && Object.keys(opts.vaultEnvMerge).length && (0, import_node_fs24.existsSync)(target)) {
20450
+ (0, import_node_fs24.writeFileSync)(target, mergeEnvSecretsIntoFile((0, import_node_fs24.readFileSync)(target, "utf8"), opts.vaultEnvMerge), "utf8");
20266
20451
  }
20267
20452
  }
20268
20453
  async function gitText(cwd, args) {
@@ -20292,20 +20477,20 @@ async function resolveGlobalStatePath(cwd, explicit) {
20292
20477
  return void 0;
20293
20478
  }
20294
20479
  function readState(path2) {
20295
- if (!(0, import_node_fs23.existsSync)(path2)) return null;
20480
+ if (!(0, import_node_fs24.existsSync)(path2)) return null;
20296
20481
  try {
20297
- return JSON.parse((0, import_node_fs23.readFileSync)(path2, "utf8"));
20482
+ return JSON.parse((0, import_node_fs24.readFileSync)(path2, "utf8"));
20298
20483
  } catch {
20299
20484
  return null;
20300
20485
  }
20301
20486
  }
20302
20487
  function mkdirFor(path2) {
20303
20488
  const dir = path2.slice(0, Math.max(path2.lastIndexOf("/"), path2.lastIndexOf("\\")));
20304
- (0, import_node_fs23.mkdirSync)(dir, { recursive: true });
20489
+ (0, import_node_fs24.mkdirSync)(dir, { recursive: true });
20305
20490
  }
20306
20491
  function writeState(path2, state) {
20307
20492
  mkdirFor(path2);
20308
- (0, import_node_fs23.writeFileSync)(path2, JSON.stringify(state, null, 2), "utf8");
20493
+ (0, import_node_fs24.writeFileSync)(path2, JSON.stringify(state, null, 2), "utf8");
20309
20494
  }
20310
20495
  function writeStagePortReservation(port, cwd, statePath, globalStatePath, now) {
20311
20496
  const reservation = {
@@ -20325,7 +20510,7 @@ async function cleanupStageState(state, paths, timeoutMs, fallbackCwd) {
20325
20510
  await shell(state.teardown.command.trim(), state.teardown.cwd || state.cwd || fallbackCwd, Math.max(timeoutMs, 1e4));
20326
20511
  }
20327
20512
  for (const path2 of [...new Set(paths.filter((p) => Boolean(p)))]) {
20328
- (0, import_node_fs23.rmSync)(path2, { force: true });
20513
+ (0, import_node_fs24.rmSync)(path2, { force: true });
20329
20514
  }
20330
20515
  }
20331
20516
  async function killTree(pid) {
@@ -20483,8 +20668,8 @@ async function runStage(config = {}, opts = {}) {
20483
20668
  await ensureStageRuntimeEnv(config, opts, cwd);
20484
20669
  if (build) await shell(sub(build), cwd, timeoutMs, stageProcessEnv(stagePort, extraEnv));
20485
20670
  } catch (e) {
20486
- (0, import_node_fs23.rmSync)(statePath, { force: true });
20487
- if (globalStatePath && globalStatePath !== statePath) (0, import_node_fs23.rmSync)(globalStatePath, { force: true });
20671
+ (0, import_node_fs24.rmSync)(statePath, { force: true });
20672
+ if (globalStatePath && globalStatePath !== statePath) (0, import_node_fs24.rmSync)(globalStatePath, { force: true });
20488
20673
  throw e;
20489
20674
  }
20490
20675
  const started = await startStage(config, {
@@ -20505,9 +20690,9 @@ function parseNextFromHead(headText) {
20505
20690
  }
20506
20691
  function readStageSummary(worktreePath) {
20507
20692
  const statePath = stageStatePath(worktreePath);
20508
- if (!(0, import_node_fs24.existsSync)(statePath)) return void 0;
20693
+ if (!(0, import_node_fs25.existsSync)(statePath)) return void 0;
20509
20694
  try {
20510
- const state = JSON.parse((0, import_node_fs24.readFileSync)(statePath, "utf8"));
20695
+ const state = JSON.parse((0, import_node_fs25.readFileSync)(statePath, "utf8"));
20511
20696
  const port = typeof state.port === "number" ? state.port : void 0;
20512
20697
  if (port == null || !Number.isInteger(port) || port <= 0) return void 0;
20513
20698
  return { port, url: typeof state.url === "string" ? state.url : void 0 };
@@ -20612,13 +20797,13 @@ async function executeWaveLand(plan, deps, opts = { preserveWorktree: true }) {
20612
20797
  }
20613
20798
 
20614
20799
  // src/index.ts
20615
- var import_node_os20 = require("node:os");
20800
+ var import_node_os21 = require("node:os");
20616
20801
 
20617
20802
  // src/board.ts
20618
20803
  var import_node_child_process9 = require("node:child_process");
20619
- var import_node_fs25 = require("node:fs");
20620
- var import_node_os9 = require("node:os");
20621
- var import_node_path24 = require("node:path");
20804
+ var import_node_fs26 = require("node:fs");
20805
+ var import_node_os10 = require("node:os");
20806
+ var import_node_path25 = require("node:path");
20622
20807
  var import_node_util6 = require("node:util");
20623
20808
 
20624
20809
  // src/board-dependency.ts
@@ -22228,7 +22413,7 @@ var CLAIM_SESSION_ACTIVITY_MS = 30 * 6e4;
22228
22413
  var CLAIM_SESSION_PROBE_CACHE_MS = 6e4;
22229
22414
  var claimSessionProbeCache = /* @__PURE__ */ new Map();
22230
22415
  function probeLocalClaimSession(marker, now = Date.now()) {
22231
- if (!marker.session || !marker.host || marker.host.toLowerCase() !== (0, import_node_os9.hostname)().toLowerCase()) return void 0;
22416
+ if (!marker.session || !marker.host || marker.host.toLowerCase() !== (0, import_node_os10.hostname)().toLowerCase()) return void 0;
22232
22417
  if (!marker.surface?.toLowerCase().startsWith("claude")) return void 0;
22233
22418
  const cacheKey = `${marker.host.toLowerCase()}/${marker.session}`;
22234
22419
  const cached = claimSessionProbeCache.get(cacheKey);
@@ -22237,17 +22422,17 @@ function probeLocalClaimSession(marker, now = Date.now()) {
22237
22422
  claimSessionProbeCache.set(cacheKey, { checkedAt: now, state });
22238
22423
  return state;
22239
22424
  };
22240
- const root = (0, import_node_path24.join)((0, import_node_os9.homedir)(), ".claude", "projects");
22425
+ const root = (0, import_node_path25.join)((0, import_node_os10.homedir)(), ".claude", "projects");
22241
22426
  try {
22242
22427
  const wanted = `${marker.session}.jsonl`.toLowerCase();
22243
22428
  const pending = [root];
22244
22429
  while (pending.length) {
22245
22430
  const dir = pending.pop();
22246
- for (const entry of (0, import_node_fs25.readdirSync)(dir, { withFileTypes: true })) {
22247
- const path2 = (0, import_node_path24.join)(dir, entry.name);
22431
+ for (const entry of (0, import_node_fs26.readdirSync)(dir, { withFileTypes: true })) {
22432
+ const path2 = (0, import_node_path25.join)(dir, entry.name);
22248
22433
  if (entry.isDirectory()) pending.push(path2);
22249
22434
  else if (entry.isFile() && entry.name.toLowerCase() === wanted) {
22250
- return remember(now - (0, import_node_fs25.statSync)(path2).mtimeMs <= CLAIM_SESSION_ACTIVITY_MS ? "live" : "dead");
22435
+ return remember(now - (0, import_node_fs26.statSync)(path2).mtimeMs <= CLAIM_SESSION_ACTIVITY_MS ? "live" : "dead");
22251
22436
  }
22252
22437
  }
22253
22438
  }
@@ -22535,7 +22720,7 @@ async function resolveAutoAddBoardAttach(client, cfg, selector, priority, warn =
22535
22720
  }
22536
22721
 
22537
22722
  // src/issue-body.ts
22538
- var import_node_os10 = require("node:os");
22723
+ var import_node_os11 = require("node:os");
22539
22724
  var TextArgError = class extends Error {
22540
22725
  constructor(message, code, offendingFlag) {
22541
22726
  super(message);
@@ -22547,7 +22732,7 @@ var TextArgError = class extends Error {
22547
22732
  offendingFlag;
22548
22733
  };
22549
22734
  function emptyStdinMessage(fileFlag) {
22550
- if ((0, import_node_os10.platform)() === "win32") {
22735
+ if ((0, import_node_os11.platform)() === "win32") {
22551
22736
  return `${fileFlag} - read empty stdin (on Windows, ${fileFlag} - is unreliable through the npm .cmd shim \u2014 use ${fileFlag} <path>, or pipe to \`node cli/dist/index.cjs\` directly)`;
22552
22737
  }
22553
22738
  return `${fileFlag} - read empty stdin (nothing piped \u2014 pass a heredoc/pipe, or ${fileFlag} <path>)`;
@@ -22784,6 +22969,13 @@ function applyCommandTaxonomy(program3) {
22784
22969
  }
22785
22970
  program3.configureHelp({
22786
22971
  ...REQUIRED_OPTION_HELP,
22972
+ // #5014: the root help must show the CANONICAL house-prefixed term (`oracle board`, `devops pr`),
22973
+ // not the retired flat leaf name — an agent grounding on `mmi-cli help` and running the flat name
22974
+ // hits the Wave 3 refusal. `canonicalPathFor` is the identity for `core`, so core stays unprefixed.
22975
+ subcommandTerm(command) {
22976
+ const stock = Help.prototype.subcommandTerm.call(this, command);
22977
+ return `${canonicalPathFor(command.name()) ?? command.name()}${stock.slice(command.name().length)}`;
22978
+ },
22787
22979
  visibleCommands(command) {
22788
22980
  const visible = command.commands.filter((child2) => !child2._hidden);
22789
22981
  const helpCommand = command._getHelpCommand();
@@ -23148,20 +23340,20 @@ function consolidateCommandNamespaces(program3) {
23148
23340
  }
23149
23341
 
23150
23342
  // src/claude-binary-doctor.ts
23343
+ var import_node_fs28 = require("node:fs");
23344
+ var import_node_os13 = require("node:os");
23345
+ var import_node_path27 = require("node:path");
23346
+
23347
+ // src/jerv-cli-spawn.ts
23151
23348
  var import_node_fs27 = require("node:fs");
23152
23349
  var import_node_os12 = require("node:os");
23153
23350
  var import_node_path26 = require("node:path");
23154
-
23155
- // src/jerv-cli-spawn.ts
23156
- var import_node_fs26 = require("node:fs");
23157
- var import_node_os11 = require("node:os");
23158
- var import_node_path25 = require("node:path");
23159
23351
  var WIN_NAMES = ["jerv-cli.cmd", "jerv-cli.exe", "jerv-cli"];
23160
23352
  var POSIX_NAMES = ["jerv-cli"];
23161
- var JERV_CLI_ENTRY = (0, import_node_path25.join)("node_modules", "@jervaise", "jerv-cli", "dist", "index.cjs");
23353
+ var JERV_CLI_ENTRY = (0, import_node_path26.join)("node_modules", "@jervaise", "jerv-cli", "dist", "index.cjs");
23162
23354
  function pathEnvEntries(pathEnv, platform2 = process.platform) {
23163
23355
  if (platform2 !== "win32") {
23164
- return pathEnv.split(import_node_path25.delimiter).map((e) => e.trim()).filter(Boolean);
23356
+ return pathEnv.split(import_node_path26.delimiter).map((e) => e.trim()).filter(Boolean);
23165
23357
  }
23166
23358
  if (pathEnv.includes(";")) {
23167
23359
  return pathEnv.split(";").map((e) => e.trim()).filter(Boolean);
@@ -23180,7 +23372,7 @@ function normalizeSpawnPathEntry(entry, platform2 = process.platform) {
23180
23372
  if (msys) return `${msys[1].toUpperCase()}:\\${msys[2].replace(/\//g, "\\")}`;
23181
23373
  return trimmed;
23182
23374
  }
23183
- function jervCliCandidateDirs(env = process.env, home = (0, import_node_os11.homedir)(), platform2 = process.platform) {
23375
+ function jervCliCandidateDirs(env = process.env, home = (0, import_node_os12.homedir)(), platform2 = process.platform) {
23184
23376
  const seen = /* @__PURE__ */ new Set();
23185
23377
  const out = [];
23186
23378
  const push = (dir) => {
@@ -23194,35 +23386,35 @@ function jervCliCandidateDirs(env = process.env, home = (0, import_node_os11.hom
23194
23386
  push(normalizeSpawnPathEntry(entry, platform2));
23195
23387
  }
23196
23388
  if (platform2 === "win32") {
23197
- if (env.APPDATA) push((0, import_node_path25.join)(env.APPDATA, "npm"));
23198
- if (env.LOCALAPPDATA) push((0, import_node_path25.join)(env.LOCALAPPDATA, "npm"));
23389
+ if (env.APPDATA) push((0, import_node_path26.join)(env.APPDATA, "npm"));
23390
+ if (env.LOCALAPPDATA) push((0, import_node_path26.join)(env.LOCALAPPDATA, "npm"));
23199
23391
  } else {
23200
- push((0, import_node_path25.join)(home, ".local", "bin"));
23392
+ push((0, import_node_path26.join)(home, ".local", "bin"));
23201
23393
  }
23202
23394
  return out;
23203
23395
  }
23204
- function jervCliCandidatePaths(env = process.env, home = (0, import_node_os11.homedir)(), platform2 = process.platform) {
23396
+ function jervCliCandidatePaths(env = process.env, home = (0, import_node_os12.homedir)(), platform2 = process.platform) {
23205
23397
  const names = platform2 === "win32" ? WIN_NAMES : POSIX_NAMES;
23206
23398
  const out = [];
23207
23399
  for (const dir of jervCliCandidateDirs(env, home, platform2)) {
23208
- for (const name of names) out.push((0, import_node_path25.join)(dir, name));
23400
+ for (const name of names) out.push((0, import_node_path26.join)(dir, name));
23209
23401
  }
23210
23402
  return out;
23211
23403
  }
23212
- function resolveJervCliPath(env = process.env, home = (0, import_node_os11.homedir)(), platform2 = process.platform, exists = import_node_fs26.existsSync) {
23404
+ function resolveJervCliPath(env = process.env, home = (0, import_node_os12.homedir)(), platform2 = process.platform, exists = import_node_fs27.existsSync) {
23213
23405
  for (const candidate of jervCliCandidatePaths(env, home, platform2)) {
23214
23406
  if (exists(candidate)) return candidate;
23215
23407
  }
23216
23408
  return void 0;
23217
23409
  }
23218
- function resolveJervCliNodeEntry(shimPath, exists = import_node_fs26.existsSync) {
23219
- const entry = (0, import_node_path25.join)((0, import_node_path25.dirname)(shimPath), JERV_CLI_ENTRY);
23410
+ function resolveJervCliNodeEntry(shimPath, exists = import_node_fs27.existsSync) {
23411
+ const entry = (0, import_node_path26.join)((0, import_node_path26.dirname)(shimPath), JERV_CLI_ENTRY);
23220
23412
  return exists(entry) ? entry : void 0;
23221
23413
  }
23222
23414
  function jervCliExecFileArgs(args, opts = {}) {
23223
23415
  const platform2 = opts.platform ?? process.platform;
23224
- const exists = opts.exists ?? import_node_fs26.existsSync;
23225
- const resolved = resolveJervCliPath(opts.env ?? process.env, opts.home ?? (0, import_node_os11.homedir)(), platform2, exists);
23416
+ const exists = opts.exists ?? import_node_fs27.existsSync;
23417
+ const resolved = resolveJervCliPath(opts.env ?? process.env, opts.home ?? (0, import_node_os12.homedir)(), platform2, exists);
23226
23418
  if (resolved) {
23227
23419
  const entry = resolveJervCliNodeEntry(resolved, exists);
23228
23420
  if (entry) {
@@ -23311,26 +23503,26 @@ function globalNodeModulesRoots(host) {
23311
23503
  out.push(dir);
23312
23504
  };
23313
23505
  const prefix = env.npm_config_prefix?.trim();
23314
- if (prefix) push(platform2 === "win32" ? (0, import_node_path26.join)(prefix, "node_modules") : (0, import_node_path26.join)(prefix, "lib", "node_modules"));
23315
- for (const dir of jervCliCandidateDirs(env, host.home ?? (0, import_node_os12.homedir)(), platform2)) {
23316
- push((0, import_node_path26.join)(dir, "node_modules"));
23317
- push((0, import_node_path26.join)((0, import_node_path26.dirname)(dir), "lib", "node_modules"));
23506
+ if (prefix) push(platform2 === "win32" ? (0, import_node_path27.join)(prefix, "node_modules") : (0, import_node_path27.join)(prefix, "lib", "node_modules"));
23507
+ for (const dir of jervCliCandidateDirs(env, host.home ?? (0, import_node_os13.homedir)(), platform2)) {
23508
+ push((0, import_node_path27.join)(dir, "node_modules"));
23509
+ push((0, import_node_path27.join)((0, import_node_path27.dirname)(dir), "lib", "node_modules"));
23318
23510
  }
23319
23511
  return out;
23320
23512
  }
23321
23513
  function readHead(path2) {
23322
23514
  let fd;
23323
23515
  try {
23324
- fd = (0, import_node_fs27.openSync)(path2, "r");
23516
+ fd = (0, import_node_fs28.openSync)(path2, "r");
23325
23517
  const buffer = new Uint8Array(MAGIC_HEAD_BYTES);
23326
- const read = (0, import_node_fs27.readSync)(fd, buffer, 0, MAGIC_HEAD_BYTES, 0);
23518
+ const read = (0, import_node_fs28.readSync)(fd, buffer, 0, MAGIC_HEAD_BYTES, 0);
23327
23519
  return buffer.subarray(0, read);
23328
23520
  } catch {
23329
23521
  return void 0;
23330
23522
  } finally {
23331
23523
  if (fd !== void 0) {
23332
23524
  try {
23333
- (0, import_node_fs27.closeSync)(fd);
23525
+ (0, import_node_fs28.closeSync)(fd);
23334
23526
  } catch {
23335
23527
  }
23336
23528
  }
@@ -23338,7 +23530,7 @@ function readHead(path2) {
23338
23530
  }
23339
23531
  function fileBytes(path2) {
23340
23532
  try {
23341
- return (0, import_node_fs27.statSync)(path2).size;
23533
+ return (0, import_node_fs28.statSync)(path2).size;
23342
23534
  } catch {
23343
23535
  return void 0;
23344
23536
  }
@@ -23352,17 +23544,17 @@ function readClaudeBinaryState(host = {}) {
23352
23544
  const arch = host.arch ?? process.arch;
23353
23545
  const magic = EXECUTABLE_MAGIC[platform2];
23354
23546
  if (!magic) return void 0;
23355
- const packageRoot = globalNodeModulesRoots(host).map((root) => (0, import_node_path26.join)(root, ...PACKAGE.split("/"))).find((dir) => (0, import_node_fs27.existsSync)((0, import_node_path26.join)(dir, "package.json")));
23547
+ const packageRoot = globalNodeModulesRoots(host).map((root) => (0, import_node_path27.join)(root, ...PACKAGE.split("/"))).find((dir) => (0, import_node_fs28.existsSync)((0, import_node_path27.join)(dir, "package.json")));
23356
23548
  if (!packageRoot) return void 0;
23357
23549
  const keys = platformPackageKeys(platform2, arch);
23358
23550
  const fallbackPackage = `${PACKAGE}-${keys[0]}`;
23359
23551
  let manifest;
23360
23552
  try {
23361
- manifest = JSON.parse((0, import_node_fs27.readFileSync)((0, import_node_path26.join)(packageRoot, "package.json"), "utf8"));
23553
+ manifest = JSON.parse((0, import_node_fs28.readFileSync)((0, import_node_path27.join)(packageRoot, "package.json"), "utf8"));
23362
23554
  } catch (e) {
23363
23555
  return {
23364
23556
  state: "unreadable",
23365
- binPath: (0, import_node_path26.join)(packageRoot, "package.json"),
23557
+ binPath: (0, import_node_path27.join)(packageRoot, "package.json"),
23366
23558
  expectedMagic: magic.name,
23367
23559
  platformPackage: fallbackPackage,
23368
23560
  error: `package.json could not be read \u2014 ${e.message}`
@@ -23379,17 +23571,17 @@ function readClaudeBinaryState(host = {}) {
23379
23571
  error: "package.json declares no `bin` entry \u2014 the executed file cannot be resolved"
23380
23572
  };
23381
23573
  }
23382
- const binPath = (0, import_node_path26.join)(packageRoot, binRelative);
23383
- const binName = (0, import_node_path26.basename)(binRelative);
23574
+ const binPath = (0, import_node_path27.join)(packageRoot, binRelative);
23575
+ const binName = (0, import_node_path27.basename)(binRelative);
23384
23576
  const optional = manifest.optionalDependencies;
23385
23577
  const publishes = (name) => typeof optional === "object" && optional !== null && Object.prototype.hasOwnProperty.call(optional, name);
23386
23578
  const published = keys.map((key) => `${PACKAGE}-${key}`).filter(publishes);
23387
23579
  if (published.length === 0) return void 0;
23388
23580
  const binIn = (name) => [
23389
- (0, import_node_path26.join)(packageRoot, "node_modules", ...name.split("/"), binName),
23390
- (0, import_node_path26.join)((0, import_node_path26.dirname)((0, import_node_path26.dirname)(packageRoot)), ...name.split("/"), binName)
23581
+ (0, import_node_path27.join)(packageRoot, "node_modules", ...name.split("/"), binName),
23582
+ (0, import_node_path27.join)((0, import_node_path27.dirname)((0, import_node_path27.dirname)(packageRoot)), ...name.split("/"), binName)
23391
23583
  ];
23392
- const found = published.map((name) => ({ name, path: binIn(name).find((file) => (0, import_node_fs27.existsSync)(file)) })).find((c) => c.path);
23584
+ const found = published.map((name) => ({ name, path: binIn(name).find((file) => (0, import_node_fs28.existsSync)(file)) })).find((c) => c.path);
23393
23585
  const platformPackage = found?.name ?? published[0];
23394
23586
  let source;
23395
23587
  let sourceProblem;
@@ -23400,7 +23592,7 @@ function readClaudeBinaryState(host = {}) {
23400
23592
  } else {
23401
23593
  source = { path: found.path, bytes: fileBytes(found.path) ?? 0 };
23402
23594
  }
23403
- if (!(0, import_node_fs27.existsSync)(binPath)) {
23595
+ if (!(0, import_node_fs28.existsSync)(binPath)) {
23404
23596
  return { state: "missing", binPath, expectedMagic: magic.name, platformPackage, ...source ? { source } : {}, ...sourceProblem ? { sourceProblem } : {} };
23405
23597
  }
23406
23598
  const head = readHead(binPath);
@@ -23443,9 +23635,9 @@ function healClaudeBinary(host = {}, onStep) {
23443
23635
  const platform2 = host.platform ?? process.platform;
23444
23636
  const aside = `${probe.binPath}.stub-${Date.now()}`;
23445
23637
  let renamed = false;
23446
- if ((0, import_node_fs27.existsSync)(probe.binPath)) {
23638
+ if ((0, import_node_fs28.existsSync)(probe.binPath)) {
23447
23639
  try {
23448
- (0, import_node_fs27.renameSync)(probe.binPath, aside);
23640
+ (0, import_node_fs28.renameSync)(probe.binPath, aside);
23449
23641
  renamed = true;
23450
23642
  onStep?.(`renamed the stub aside: ${aside}`);
23451
23643
  } catch (e) {
@@ -23454,12 +23646,12 @@ function healClaudeBinary(host = {}, onStep) {
23454
23646
  }
23455
23647
  try {
23456
23648
  onStep?.(`copying ${probe.source.path} \u2192 ${probe.binPath} (${(probe.source.bytes / 1e6).toFixed(0)} MB)`);
23457
- (0, import_node_fs27.copyFileSync)(probe.source.path, probe.binPath);
23458
- if (platform2 !== "win32") (0, import_node_fs27.chmodSync)(probe.binPath, 493);
23649
+ (0, import_node_fs28.copyFileSync)(probe.source.path, probe.binPath);
23650
+ if (platform2 !== "win32") (0, import_node_fs28.chmodSync)(probe.binPath, 493);
23459
23651
  } catch (e) {
23460
23652
  if (renamed) {
23461
23653
  try {
23462
- (0, import_node_fs27.renameSync)(aside, probe.binPath);
23654
+ (0, import_node_fs28.renameSync)(aside, probe.binPath);
23463
23655
  } catch {
23464
23656
  return { ok: false, detail: `copy failed (${e.message}) and the stub could not be restored \u2014 the original is at ${aside}` };
23465
23657
  }
@@ -23473,7 +23665,7 @@ function healClaudeBinary(host = {}, onStep) {
23473
23665
  let kept = false;
23474
23666
  if (renamed) {
23475
23667
  try {
23476
- (0, import_node_fs27.rmSync)(aside);
23668
+ (0, import_node_fs28.rmSync)(aside);
23477
23669
  } catch {
23478
23670
  kept = true;
23479
23671
  }
@@ -23951,19 +24143,19 @@ function renderVerifyBroker(input) {
23951
24143
 
23952
24144
  // src/tenant-artifact.ts
23953
24145
  var import_node_crypto4 = require("node:crypto");
23954
- var import_node_fs28 = require("node:fs");
24146
+ var import_node_fs29 = require("node:fs");
23955
24147
  var import_promises5 = require("node:fs/promises");
23956
- var import_node_path27 = require("node:path");
24148
+ var import_node_path28 = require("node:path");
23957
24149
  var ARTIFACT_ID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
23958
24150
  var MAX_BYTES = 5 * 1024 * 1024 * 1024;
23959
24151
  async function sha256File(path2) {
23960
24152
  const hash = (0, import_node_crypto4.createHash)("sha256");
23961
- for await (const chunk of (0, import_node_fs28.createReadStream)(path2)) hash.update(chunk);
24153
+ for await (const chunk of (0, import_node_fs29.createReadStream)(path2)) hash.update(chunk);
23962
24154
  return hash.digest("hex");
23963
24155
  }
23964
24156
  async function putTenantArtifact(repo, stage, inputPath, deps) {
23965
24157
  if (!["dev", "rc", "main"].includes(stage)) throw new Error("tenant artifact put: <stage> must be dev, rc, or main");
23966
- const path2 = (0, import_node_path27.resolve)(inputPath);
24158
+ const path2 = (0, import_node_path28.resolve)(inputPath);
23967
24159
  const info = await (0, import_promises5.stat)(path2);
23968
24160
  if (!info.isFile()) throw new Error("tenant artifact put: input path must be a file");
23969
24161
  if (!Number.isSafeInteger(info.size) || info.size < 1 || info.size > MAX_BYTES) throw new Error(`tenant artifact put: file must be 1..${MAX_BYTES} bytes`);
@@ -23981,7 +24173,7 @@ async function putTenantArtifact(repo, stage, inputPath, deps) {
23981
24173
  return [key, value];
23982
24174
  }));
23983
24175
  headers["content-length"] = String(info.size);
23984
- const stream = (0, import_node_fs28.createReadStream)(path2);
24176
+ const stream = (0, import_node_fs29.createReadStream)(path2);
23985
24177
  let uploaded;
23986
24178
  try {
23987
24179
  uploaded = await fetch(body.uploadUrl, {
@@ -25099,8 +25291,8 @@ async function announceRelease(deps, args) {
25099
25291
  // src/repo-index.ts
25100
25292
  var import_node_crypto5 = require("node:crypto");
25101
25293
  var import_node_child_process12 = require("node:child_process");
25102
- var import_node_fs29 = require("node:fs");
25103
- var import_node_path28 = require("node:path");
25294
+ var import_node_fs30 = require("node:fs");
25295
+ var import_node_path29 = require("node:path");
25104
25296
  var REPO_INDEX_SCHEMA = 1;
25105
25297
  var HARD_DENY = [
25106
25298
  /(^|\/)\.env(\.|$)/i,
@@ -25225,11 +25417,11 @@ function loadReadmeHints(cwd, candidatePaths) {
25225
25417
  }
25226
25418
  for (const rel of readmes) {
25227
25419
  if (isHardDeniedPath(rel)) continue;
25228
- const abs = (0, import_node_path28.join)(cwd, ...rel.split("/"));
25229
- if (!(0, import_node_fs29.existsSync)(abs)) continue;
25420
+ const abs = (0, import_node_path29.join)(cwd, ...rel.split("/"));
25421
+ if (!(0, import_node_fs30.existsSync)(abs)) continue;
25230
25422
  let text;
25231
25423
  try {
25232
- text = (0, import_node_fs29.readFileSync)(abs, "utf8");
25424
+ text = (0, import_node_fs30.readFileSync)(abs, "utf8");
25233
25425
  } catch {
25234
25426
  continue;
25235
25427
  }
@@ -25242,7 +25434,7 @@ function loadReadmeHints(cwd, candidatePaths) {
25242
25434
  return hints;
25243
25435
  }
25244
25436
  function toPosix(p) {
25245
- return p.split(import_node_path28.sep).join("/");
25437
+ return p.split(import_node_path29.sep).join("/");
25246
25438
  }
25247
25439
  function listCandidatePaths(cwd, exec = import_node_child_process12.execFileSync) {
25248
25440
  try {
@@ -25264,11 +25456,11 @@ function rebuildRepoIndex(cwd, repoSlug2) {
25264
25456
  for (const rel of candidates) {
25265
25457
  if (ignored.has(rel)) continue;
25266
25458
  if (isHardDeniedPath(rel)) continue;
25267
- const abs = (0, import_node_path28.join)(cwd, ...rel.split("/"));
25268
- if (!(0, import_node_fs29.existsSync)(abs)) continue;
25459
+ const abs = (0, import_node_path29.join)(cwd, ...rel.split("/"));
25460
+ if (!(0, import_node_fs30.existsSync)(abs)) continue;
25269
25461
  let text;
25270
25462
  try {
25271
- text = (0, import_node_fs29.readFileSync)(abs, "utf8");
25463
+ text = (0, import_node_fs30.readFileSync)(abs, "utf8");
25272
25464
  } catch {
25273
25465
  continue;
25274
25466
  }
@@ -25293,16 +25485,16 @@ function rebuildRepoIndex(cwd, repoSlug2) {
25293
25485
  entries
25294
25486
  };
25295
25487
  const store = repoIndexStorePath(cwd);
25296
- (0, import_node_fs29.mkdirSync)((0, import_node_path28.dirname)(store), { recursive: true });
25297
- (0, import_node_fs29.writeFileSync)(store, `${JSON.stringify(projection, null, 2)}
25488
+ (0, import_node_fs30.mkdirSync)((0, import_node_path29.dirname)(store), { recursive: true });
25489
+ (0, import_node_fs30.writeFileSync)(store, `${JSON.stringify(projection, null, 2)}
25298
25490
  `, "utf8");
25299
25491
  return projection;
25300
25492
  }
25301
25493
  function loadRepoIndex(cwd) {
25302
25494
  const store = repoIndexStorePath(cwd);
25303
- if (!(0, import_node_fs29.existsSync)(store)) return null;
25495
+ if (!(0, import_node_fs30.existsSync)(store)) return null;
25304
25496
  try {
25305
- const raw = JSON.parse((0, import_node_fs29.readFileSync)(store, "utf8"));
25497
+ const raw = JSON.parse((0, import_node_fs30.readFileSync)(store, "utf8"));
25306
25498
  if (raw?.schema !== REPO_INDEX_SCHEMA || !Array.isArray(raw.entries)) return null;
25307
25499
  return raw;
25308
25500
  } catch {
@@ -25374,7 +25566,7 @@ function inferRepoSlug(cwd, exec = import_node_child_process12.execFileSync) {
25374
25566
  if (m?.[1]) return m[1].toLowerCase();
25375
25567
  } catch {
25376
25568
  }
25377
- return ((0, import_node_path28.basename)(cwd) || "local").toLowerCase();
25569
+ return ((0, import_node_path29.basename)(cwd) || "local").toLowerCase();
25378
25570
  }
25379
25571
 
25380
25572
  // src/repo-index-cloud-client.ts
@@ -25514,9 +25706,9 @@ async function gcRepoIndexCloud(deps) {
25514
25706
  }
25515
25707
 
25516
25708
  // src/repo-index-sync.ts
25517
- var import_node_fs30 = require("node:fs");
25518
- var import_node_os13 = require("node:os");
25519
- var import_node_path29 = require("node:path");
25709
+ var import_node_fs31 = require("node:fs");
25710
+ var import_node_os14 = require("node:os");
25711
+ var import_node_path30 = require("node:path");
25520
25712
  var import_node_child_process13 = require("node:child_process");
25521
25713
  var MAX_EMBED_BACKFILL_ROUNDS = 40;
25522
25714
  function normalizeRepo(raw) {
@@ -25560,7 +25752,7 @@ async function syncEstateRepoIndex(opts) {
25560
25752
  const failed = [];
25561
25753
  const skipped = [];
25562
25754
  for (const repo of repos) {
25563
- const dir = (0, import_node_fs30.mkdtempSync)((0, import_node_path29.join)((0, import_node_os13.tmpdir)(), "mmi-repo-index-"));
25755
+ const dir = (0, import_node_fs31.mkdtempSync)((0, import_node_path30.join)((0, import_node_os14.tmpdir)(), "mmi-repo-index-"));
25564
25756
  try {
25565
25757
  shallowClone(repo, dir, opts.githubToken);
25566
25758
  const built = rebuildRepoIndex(dir, repo);
@@ -25610,7 +25802,7 @@ async function syncEstateRepoIndex(opts) {
25610
25802
  failed.push({ repo, error: e.message });
25611
25803
  } finally {
25612
25804
  try {
25613
- (0, import_node_fs30.rmSync)(dir, { recursive: true, force: true });
25805
+ (0, import_node_fs31.rmSync)(dir, { recursive: true, force: true });
25614
25806
  } catch {
25615
25807
  }
25616
25808
  }
@@ -25619,7 +25811,7 @@ async function syncEstateRepoIndex(opts) {
25619
25811
  }
25620
25812
 
25621
25813
  // src/repo-index-health.ts
25622
- var import_node_fs31 = require("node:fs");
25814
+ var import_node_fs32 = require("node:fs");
25623
25815
 
25624
25816
  // testdata/repo-index-golden-queries.json
25625
25817
  var repo_index_golden_queries_default = {
@@ -25661,7 +25853,7 @@ function assertGoldenSuite(raw, source) {
25661
25853
  function loadGoldenSuite(path2) {
25662
25854
  let text;
25663
25855
  try {
25664
- text = (0, import_node_fs31.readFileSync)(path2, "utf8");
25856
+ text = (0, import_node_fs32.readFileSync)(path2, "utf8");
25665
25857
  } catch (e) {
25666
25858
  throw new Error(`golden suite unreadable at ${path2}: ${e.message}`);
25667
25859
  }
@@ -25815,8 +26007,8 @@ async function runRepoIndexHealth(opts) {
25815
26007
 
25816
26008
  // src/spawn-policy-core.ts
25817
26009
  var import_node_child_process14 = require("node:child_process");
25818
- var import_node_fs32 = require("node:fs");
25819
- var import_node_path30 = require("node:path");
26010
+ var import_node_fs33 = require("node:fs");
26011
+ var import_node_path31 = require("node:path");
25820
26012
  var SPAWNERS = ["spawn", "spawnSync", "exec", "execSync", "execFile", "execFileSync"];
25821
26013
  var CALL_SOURCE = String.raw`(^|[^.\w$])(${SPAWNERS.join("|")})\s*\(`;
25822
26014
  var SOURCE_EXT = /\.(ts|mts|cts|js|mjs|cjs)$/;
@@ -25902,7 +26094,7 @@ function runSpawnPolicy(root) {
25902
26094
  for (const file of files) {
25903
26095
  let raw;
25904
26096
  try {
25905
- raw = (0, import_node_fs32.readFileSync)((0, import_node_path30.join)(root, file), "utf8");
26097
+ raw = (0, import_node_fs33.readFileSync)((0, import_node_path31.join)(root, file), "utf8");
25906
26098
  } catch {
25907
26099
  continue;
25908
26100
  }
@@ -25920,8 +26112,8 @@ function runSpawnPolicy(root) {
25920
26112
 
25921
26113
  // src/test-policy-core.ts
25922
26114
  var import_node_child_process15 = require("node:child_process");
25923
- var import_node_fs33 = require("node:fs");
25924
- var import_node_path31 = require("node:path");
26115
+ var import_node_fs34 = require("node:fs");
26116
+ var import_node_path32 = require("node:path");
25925
26117
  var POLICY_FILE = "test-policy.json";
25926
26118
  var TEST_RE = /\.(?:test|spec)\.[cm]?[jt]sx?$/;
25927
26119
  var PY_TEST_RE = /(?:^|\/)test_[^/]*\.py$|_test\.py$/;
@@ -25974,7 +26166,7 @@ function isTestPath(path2) {
25974
26166
  return TEST_RE.test(path2) || PY_TEST_RE.test(path2);
25975
26167
  }
25976
26168
  function loadPolicy(root, readFile9 = readFileOrNull2) {
25977
- const raw = readFile9((0, import_node_path31.join)(root, POLICY_FILE));
26169
+ const raw = readFile9((0, import_node_path32.join)(root, POLICY_FILE));
25978
26170
  if (raw == null) return { mandatory: [], declared: false };
25979
26171
  try {
25980
26172
  return { ...JSON.parse(raw), declared: true };
@@ -25984,7 +26176,7 @@ function loadPolicy(root, readFile9 = readFileOrNull2) {
25984
26176
  }
25985
26177
  function readFileOrNull2(path2) {
25986
26178
  try {
25987
- return (0, import_node_fs33.readFileSync)(path2, "utf8");
26179
+ return (0, import_node_fs34.readFileSync)(path2, "utf8");
25988
26180
  } catch {
25989
26181
  return null;
25990
26182
  }
@@ -26011,12 +26203,12 @@ function classify(changed, policy, present = () => false) {
26011
26203
  const removedProtected = [...removed].filter((p) => protectedBy.has(p)).map((p) => ({ path: p, why: protectedBy.get(p) ?? "" }));
26012
26204
  return { mandatoryHits, untestedHits, testChanges, addedTests, removedProtected };
26013
26205
  }
26014
- function unresolvedProtectedEntries(policy, root, exists = (path2) => (0, import_node_fs33.existsSync)(path2)) {
26015
- return (policy.protected ?? []).map((p) => p.path).filter((p) => !exists((0, import_node_path31.join)(root, p)));
26206
+ function unresolvedProtectedEntries(policy, root, exists = (path2) => (0, import_node_fs34.existsSync)(path2)) {
26207
+ return (policy.protected ?? []).map((p) => p.path).filter((p) => !exists((0, import_node_path32.join)(root, p)));
26016
26208
  }
26017
- function unresolvedSatisfiers(policy, root, exists = (path2) => (0, import_node_fs33.existsSync)(path2)) {
26209
+ function unresolvedSatisfiers(policy, root, exists = (path2) => (0, import_node_fs34.existsSync)(path2)) {
26018
26210
  const declared = (policy.mandatory ?? []).flatMap((m) => m.satisfiedBy ?? []);
26019
- return [...new Set(declared)].filter((p) => !exists((0, import_node_path31.join)(root, p)));
26211
+ return [...new Set(declared)].filter((p) => !exists((0, import_node_path32.join)(root, p)));
26020
26212
  }
26021
26213
  function evaluate(changed, policy, present = () => false) {
26022
26214
  const { mandatoryHits, untestedHits, testChanges, addedTests, removedProtected } = classify(changed, policy, present);
@@ -26198,13 +26390,13 @@ function changedFilesSince(base, cwd) {
26198
26390
  }
26199
26391
  function runTestPolicy(root, deps = {}) {
26200
26392
  const policy = deps.policy ?? loadPolicy(root);
26201
- const exists = deps.exists ?? ((path2) => (0, import_node_fs33.existsSync)(path2));
26393
+ const exists = deps.exists ?? ((path2) => (0, import_node_fs34.existsSync)(path2));
26202
26394
  const counts = { mandatoryCount: (policy.mandatory ?? []).length, protectedCount: (policy.protected ?? []).length };
26203
26395
  const base = deps.changed ? "(injected)" : resolveBase(root, deps.base);
26204
26396
  const refusal = deps.changed ? null : untrustworthyRange(root, base);
26205
26397
  const changed = deps.changed ?? (refusal ? [] : changedFilesSince(base, root));
26206
26398
  const lookup = deps.override !== void 0 ? { override: deps.override, refusals: [] } : !deps.changed && !refusal ? readOverride(base, root) : { override: null, refusals: [] };
26207
- const present = (path2) => exists((0, import_node_path31.join)(root, path2));
26399
+ const present = (path2) => exists((0, import_node_path32.join)(root, path2));
26208
26400
  const removedByThisDiff = removedPaths(changed);
26209
26401
  const staleFindings = [];
26210
26402
  const unresolved = unresolvedProtectedEntries(policy, root, exists).filter((p) => !removedByThisDiff.has(p));
@@ -26242,8 +26434,8 @@ function runTestPolicy(root, deps = {}) {
26242
26434
  }
26243
26435
 
26244
26436
  // src/project-info-sync.ts
26245
- var import_node_fs34 = require("node:fs");
26246
- var import_node_path32 = require("node:path");
26437
+ var import_node_fs35 = require("node:fs");
26438
+ var import_node_path33 = require("node:path");
26247
26439
  var UPDATE_PROJECT_INFO = `mutation($projectId: ID!, $shortDescription: String!, $readme: String!) {
26248
26440
  updateProjectV2(input: { projectId: $projectId, shortDescription: $shortDescription, readme: $readme }) {
26249
26441
  projectV2 { id }
@@ -26288,14 +26480,14 @@ function sharedName(entries, fallback) {
26288
26480
  }
26289
26481
  function buildProjectInfoSyncPlan(targetRepo2, project2, projects, repoRoot2) {
26290
26482
  if (!project2.projectId) throw new Error(`org project sync-info: ${targetRepo2} registry META has no projectId`);
26291
- const readmePath = (0, import_node_path32.join)(repoRoot2, "README.md");
26292
- if (!(0, import_node_fs34.existsSync)(readmePath)) throw new Error(`org project sync-info: ${targetRepo2} has no README.md`);
26483
+ const readmePath = (0, import_node_path33.join)(repoRoot2, "README.md");
26484
+ if (!(0, import_node_fs35.existsSync)(readmePath)) throw new Error(`org project sync-info: ${targetRepo2} has no README.md`);
26293
26485
  const entries = entriesFor(project2, projects);
26294
26486
  const memberRepos = [...new Set(entries.flatMap((entry) => entry.repos ?? []))].filter((repo) => /^[^/]+\/[^/]+$/.test(repo)).sort((a, b) => a.localeCompare(b));
26295
26487
  const projectName = sharedName(entries, project2.name?.trim() || targetRepo2.split("/").pop() || targetRepo2);
26296
26488
  if (!memberRepos.length) throw new Error(`org project sync-info: project ${projectName} has no registered member repos`);
26297
26489
  const entryNames = entries.map((entry) => entry.name?.trim()).filter((name) => Boolean(name));
26298
- const shortDescription = memberRepos.length === 1 ? shortDescriptionFromReadme((0, import_node_fs34.readFileSync)(readmePath, "utf8")) : `Shared work across ${new Intl.ListFormat("en", { type: "conjunction" }).format(entryNames)}.`;
26490
+ const shortDescription = memberRepos.length === 1 ? shortDescriptionFromReadme((0, import_node_fs35.readFileSync)(readmePath, "utf8")) : `Shared work across ${new Intl.ListFormat("en", { type: "conjunction" }).format(entryNames)}.`;
26299
26491
  const lines = [
26300
26492
  `# ${projectName}`,
26301
26493
  "",
@@ -26314,8 +26506,8 @@ function buildProjectInfoSyncPlan(targetRepo2, project2, projects, repoRoot2) {
26314
26506
  const targetBase = `https://github.com/${targetRepo2}`;
26315
26507
  const targetBranch = branchFor(targetRepo2, projects);
26316
26508
  const orgDocs = [
26317
- (0, import_node_fs34.existsSync)((0, import_node_path32.join)(repoRoot2, "docs", "org-readme.md")) ? `- [Org identity](${targetBase}/blob/${targetBranch}/docs/org-readme.md)` : "",
26318
- (0, import_node_fs34.existsSync)((0, import_node_path32.join)(repoRoot2, "docs", "org-architecture.md")) ? `- [Org architecture](${targetBase}/blob/${targetBranch}/docs/org-architecture.md)` : ""
26509
+ (0, import_node_fs35.existsSync)((0, import_node_path33.join)(repoRoot2, "docs", "org-readme.md")) ? `- [Org identity](${targetBase}/blob/${targetBranch}/docs/org-readme.md)` : "",
26510
+ (0, import_node_fs35.existsSync)((0, import_node_path33.join)(repoRoot2, "docs", "org-architecture.md")) ? `- [Org architecture](${targetBase}/blob/${targetBranch}/docs/org-architecture.md)` : ""
26319
26511
  ].filter(Boolean);
26320
26512
  if (orgDocs.length) lines.push("", "## Organisation docs", "", ...orgDocs);
26321
26513
  return { projectId: project2.projectId, projectName, targetRepo: targetRepo2, memberRepos, shortDescription, readme: `${lines.join("\n")}
@@ -27141,9 +27333,9 @@ function writeError(res) {
27141
27333
  }
27142
27334
 
27143
27335
  // src/secrets-commands.ts
27144
- var import_node_fs35 = require("node:fs");
27145
- var import_node_path33 = require("node:path");
27146
- var import_node_os14 = require("node:os");
27336
+ var import_node_fs36 = require("node:fs");
27337
+ var import_node_path34 = require("node:path");
27338
+ var import_node_os15 = require("node:os");
27147
27339
 
27148
27340
  // src/secrets-diff.ts
27149
27341
  var TIMEOUT_MS2 = 8e3;
@@ -27245,18 +27437,18 @@ function collectMap(value, previous = []) {
27245
27437
  return [...previous, value];
27246
27438
  }
27247
27439
  async function decryptRailsCredentials(input) {
27248
- const appDir = (0, import_node_path33.resolve)(input.appDir ?? process.cwd());
27440
+ const appDir = (0, import_node_path34.resolve)(input.appDir ?? process.cwd());
27249
27441
  const credentialsFile = input.credentialsFile ?? DEFAULT_RAILS_CREDENTIALS_FILE;
27250
27442
  const masterKeyFile = input.masterKeyFile ?? DEFAULT_RAILS_MASTER_KEY_FILE;
27251
- const credentialsPath = (0, import_node_path33.resolve)(appDir, credentialsFile);
27252
- const masterKeyPath = (0, import_node_path33.resolve)(appDir, masterKeyFile);
27443
+ const credentialsPath = (0, import_node_path34.resolve)(appDir, credentialsFile);
27444
+ const masterKeyPath = (0, import_node_path34.resolve)(appDir, masterKeyFile);
27253
27445
  const env = {
27254
27446
  ...process.env,
27255
27447
  MMI_RAILS_CREDENTIALS_FILE: credentialsPath,
27256
27448
  MMI_RAILS_MASTER_KEY_FILE: masterKeyPath
27257
27449
  };
27258
- if ((0, import_node_fs35.existsSync)(masterKeyPath)) {
27259
- env.RAILS_MASTER_KEY = (0, import_node_fs35.readFileSync)(masterKeyPath, "utf8").trim();
27450
+ if ((0, import_node_fs36.existsSync)(masterKeyPath)) {
27451
+ env.RAILS_MASTER_KEY = (0, import_node_fs36.readFileSync)(masterKeyPath, "utf8").trim();
27260
27452
  }
27261
27453
  const script = [
27262
27454
  'require "json"',
@@ -27266,9 +27458,9 @@ async function decryptRailsCredentials(input) {
27266
27458
  'config = ActiveSupport::EncryptedConfiguration.new(config_path: config_path, key_path: key_path, env_key: "RAILS_MASTER_KEY", raise_if_missing_key: true)',
27267
27459
  "puts JSON.generate(config.config)"
27268
27460
  ].join("\n");
27269
- const scriptDir = (0, import_node_fs35.mkdtempSync)((0, import_node_path33.join)((0, import_node_os14.tmpdir)(), "mmi-rails-decrypt-"));
27270
- const scriptPath = (0, import_node_path33.join)(scriptDir, "decrypt.rb");
27271
- (0, import_node_fs35.writeFileSync)(scriptPath, script, "utf8");
27461
+ const scriptDir = (0, import_node_fs36.mkdtempSync)((0, import_node_path34.join)((0, import_node_os15.tmpdir)(), "mmi-rails-decrypt-"));
27462
+ const scriptPath = (0, import_node_path34.join)(scriptDir, "decrypt.rb");
27463
+ (0, import_node_fs36.writeFileSync)(scriptPath, script, "utf8");
27272
27464
  try {
27273
27465
  const args = ["exec", "ruby", scriptPath];
27274
27466
  const cmd = process.platform === "win32" ? "cmd.exe" : "bundle";
@@ -27280,7 +27472,7 @@ async function decryptRailsCredentials(input) {
27280
27472
  });
27281
27473
  return JSON.parse(stdout);
27282
27474
  } finally {
27283
- (0, import_node_fs35.rmSync)(scriptDir, { recursive: true, force: true });
27475
+ (0, import_node_fs36.rmSync)(scriptDir, { recursive: true, force: true });
27284
27476
  }
27285
27477
  }
27286
27478
  async function readSecretStdin() {
@@ -27370,7 +27562,7 @@ function registerSecretsCommands(program3) {
27370
27562
  let body;
27371
27563
  if (o.file) {
27372
27564
  try {
27373
- body = (0, import_node_fs35.readFileSync)((0, import_node_path33.resolve)(o.file), "utf8");
27565
+ body = (0, import_node_fs36.readFileSync)((0, import_node_path34.resolve)(o.file), "utf8");
27374
27566
  } catch (e) {
27375
27567
  return fail(`secrets org-catalog: cannot read --file ${o.file}: ${e.message}`);
27376
27568
  }
@@ -27475,7 +27667,7 @@ function registerSecretsCommands(program3) {
27475
27667
  {
27476
27668
  ...d,
27477
27669
  decryptRailsCredentials,
27478
- removeFile: (path2) => (0, import_node_fs35.unlinkSync)((0, import_node_path33.resolve)(o.appDir ?? process.cwd(), path2))
27670
+ removeFile: (path2) => (0, import_node_fs36.unlinkSync)((0, import_node_path34.resolve)(o.appDir ?? process.cwd(), path2))
27479
27671
  },
27480
27672
  {
27481
27673
  repo: o.repo,
@@ -27680,7 +27872,7 @@ function emitCliCallTelemetry(command) {
27680
27872
  }
27681
27873
 
27682
27874
  // src/box-commands.ts
27683
- var import_node_fs36 = require("node:fs");
27875
+ var import_node_fs37 = require("node:fs");
27684
27876
 
27685
27877
  // src/box.ts
27686
27878
  var BOX_KEYS = {
@@ -27883,7 +28075,7 @@ function registerBoxCommands(program3) {
27883
28075
  }
27884
28076
  if (o.json) console.log(JSON.stringify({ box: found, incomplete }, null, 2));
27885
28077
  else if (o.ssh && o.script) {
27886
- (0, import_node_fs36.writeFileSync)(o.script, sshRecipeScript(found), "utf8");
28078
+ (0, import_node_fs37.writeFileSync)(o.script, sshRecipeScript(found), "utf8");
27887
28079
  console.log(`wrote ${o.script} \u2014 run: bash "${o.script}"`);
27888
28080
  } else if (o.ssh) console.log(`${formatSshRecipe(found)}
27889
28081
  ${SSH_RECIPE_AGENT_NOTE}`);
@@ -28202,7 +28394,7 @@ function registerSchedulesCommands(program3) {
28202
28394
 
28203
28395
  // src/schedules-lift-command.ts
28204
28396
  var import_promises7 = require("node:fs/promises");
28205
- var import_node_path34 = require("node:path");
28397
+ var import_node_path35 = require("node:path");
28206
28398
  var DEFAULT_WORKFLOWS_DIR = ".github/workflows";
28207
28399
  var SCHEDULE_REPO_RE = /^[A-Za-z0-9_.-]+$/;
28208
28400
  var SchedulesLiftUsageError = class extends Error {
@@ -28229,7 +28421,7 @@ async function readWorkflowFiles(dir) {
28229
28421
  const files = [];
28230
28422
  for (const name of names.sort()) {
28231
28423
  if (!/\.ya?ml$/.test(name)) continue;
28232
- files.push({ path: `.github/workflows/${name}`, text: await (0, import_promises7.readFile)((0, import_node_path34.join)(dir, name), "utf8") });
28424
+ files.push({ path: `.github/workflows/${name}`, text: await (0, import_promises7.readFile)((0, import_node_path35.join)(dir, name), "utf8") });
28233
28425
  }
28234
28426
  return files;
28235
28427
  }
@@ -28377,9 +28569,9 @@ function registerEdgeCommands(program3) {
28377
28569
  }
28378
28570
 
28379
28571
  // src/bootstrap-commands.ts
28380
- var import_node_fs37 = require("node:fs");
28381
- var import_node_os15 = require("node:os");
28382
- var import_node_path35 = require("node:path");
28572
+ var import_node_fs38 = require("node:fs");
28573
+ var import_node_os16 = require("node:os");
28574
+ var import_node_path36 = require("node:path");
28383
28575
 
28384
28576
  // src/bootstrap-drift.ts
28385
28577
  var import_node_crypto7 = require("node:crypto");
@@ -29259,13 +29451,13 @@ function registerBootstrapCommands(program3) {
29259
29451
  client: defaultGitHubClient(),
29260
29452
  projectMeta: meta,
29261
29453
  deployModel: typeof meta?.deployModel === "string" ? meta.deployModel : void 0,
29262
- readLocalFile: (path2) => path2 === "projects.json" && apiProjects != null ? apiProjects : (0, import_node_fs37.existsSync)(path2) ? (0, import_node_fs37.readFileSync)(path2, "utf8") : null,
29454
+ readLocalFile: (path2) => path2 === "projects.json" && apiProjects != null ? apiProjects : (0, import_node_fs38.existsSync)(path2) ? (0, import_node_fs38.readFileSync)(path2, "utf8") : null,
29263
29455
  // requiredGcpApis is stored as an array by a JSON write, but `org project set --var KEY=VALUE` stores a raw
29264
29456
  // comma-string — accept either so the seeded value verifies regardless of how it was written.
29265
29457
  // #3689: the same committed map the org access audit reads (#3664), so a sanctioned admin is not a
29266
29458
  // permanent bootstrap failure on one surface and an intended state on the other. Absent file → no
29267
29459
  // sanction, which is the pre-#3664 behaviour.
29268
- sanctionedAdmins: (0, import_node_fs37.existsSync)("access-matrix.json") ? entriesValueByCanonicalRepo(loadSanctionedAdmins((0, import_node_fs37.readFileSync)("access-matrix.json", "utf8")), repo) : void 0,
29460
+ sanctionedAdmins: (0, import_node_fs38.existsSync)("access-matrix.json") ? entriesValueByCanonicalRepo(loadSanctionedAdmins((0, import_node_fs38.readFileSync)("access-matrix.json", "utf8")), repo) : void 0,
29269
29461
  requiredGcpApis: (() => {
29270
29462
  const v = meta?.requiredGcpApis;
29271
29463
  if (Array.isArray(v)) return v;
@@ -29318,14 +29510,14 @@ function registerBootstrapCommands(program3) {
29318
29510
  bootstrap.command("drift").description("#3818: compare every org-owned whole-file seed against MMI-Hub's copy across the registry roster; read-only").option("--repo <owner/repo>", "audit one repo instead of the roster (never a fleet verdict)").option("--json", "machine-readable output").action(async () => {
29319
29511
  const o = { repo: rawValue("--repo", ""), json: rawFlag("--json") };
29320
29512
  const manifestPath = "skills/bootstrap/seeds/manifest.json";
29321
- if (!(0, import_node_fs37.existsSync)(manifestPath)) return fail(`bootstrap drift: ${manifestPath} not found; run from the MMI-Hub repo root \u2014 the Hub's copies ARE the reference this compares against`);
29513
+ if (!(0, import_node_fs38.existsSync)(manifestPath)) return fail(`bootstrap drift: ${manifestPath} not found; run from the MMI-Hub repo root \u2014 the Hub's copies ARE the reference this compares against`);
29322
29514
  const seedSource = await resolveHubSeedSource(execGitForSeedSource);
29323
29515
  if (!seedSource.ok) return fail(`bootstrap drift: ${seedSource.reason}`);
29324
- const manifest = loadBootstrapSeeds((0, import_node_fs37.readFileSync)(manifestPath, "utf8"));
29516
+ const manifest = loadBootstrapSeeds((0, import_node_fs38.readFileSync)(manifestPath, "utf8"));
29325
29517
  const hubContents = /* @__PURE__ */ new Map();
29326
29518
  for (const s of manifest.seeds) {
29327
29519
  if (s.ownership !== "org" || s.source !== "self") continue;
29328
- hubContents.set(s.target, (0, import_node_fs37.existsSync)(s.target) ? (0, import_node_fs37.readFileSync)(s.target, "utf8") : null);
29520
+ hubContents.set(s.target, (0, import_node_fs38.existsSync)(s.target) ? (0, import_node_fs38.readFileSync)(s.target, "utf8") : null);
29329
29521
  }
29330
29522
  let targets;
29331
29523
  let classOf = (_repo) => "deployable";
@@ -29404,10 +29596,10 @@ function registerBootstrapCommands(program3) {
29404
29596
  return fail(`bootstrap apply: ${e.message}`);
29405
29597
  }
29406
29598
  const manifestPath = "skills/bootstrap/seeds/manifest.json";
29407
- if (!(0, import_node_fs37.existsSync)(manifestPath)) return fail(`bootstrap apply: ${manifestPath} not found; bootstrap runs from the MMI-Hub repo root by design \u2014 it stamps org-level resources (Project, Ruleset, secrets, access) through the GitHub App, which is only authorized from the Hub checkout`);
29599
+ if (!(0, import_node_fs38.existsSync)(manifestPath)) return fail(`bootstrap apply: ${manifestPath} not found; bootstrap runs from the MMI-Hub repo root by design \u2014 it stamps org-level resources (Project, Ruleset, secrets, access) through the GitHub App, which is only authorized from the Hub checkout`);
29408
29600
  const seedSource = await resolveHubSeedSource(execGitForSeedSource);
29409
29601
  if (!seedSource.ok) return fail(`bootstrap apply: ${seedSource.reason}`);
29410
- const manifest = loadBootstrapSeeds((0, import_node_fs37.readFileSync)(manifestPath, "utf8"));
29602
+ const manifest = loadBootstrapSeeds((0, import_node_fs38.readFileSync)(manifestPath, "utf8"));
29411
29603
  const baseBranch = o.class === "content" ? "main" : "development";
29412
29604
  const slug = parsedRepo.slug;
29413
29605
  const onlyTarget = o.only.trim();
@@ -29418,16 +29610,16 @@ function registerBootstrapCommands(program3) {
29418
29610
  ${known}`);
29419
29611
  }
29420
29612
  const gh = async (args) => execFileP2("gh", args, { timeout: 2e4 });
29421
- const readFile9 = (p) => (0, import_node_fs37.existsSync)(p) ? (0, import_node_fs37.readFileSync)(p, "utf8") : null;
29613
+ const readFile9 = (p) => (0, import_node_fs38.existsSync)(p) ? (0, import_node_fs38.readFileSync)(p, "utf8") : null;
29422
29614
  const enc = (p) => p.split("/").map(encodeURIComponent).join("/");
29423
29615
  const putSeed = async (target, content, ref, sha) => {
29424
- const tmp = (0, import_node_path35.join)((0, import_node_os15.tmpdir)(), `mmi-seed-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
29425
- (0, import_node_fs37.writeFileSync)(tmp, JSON.stringify(contentPutBody(target, content, ref, sha)), "utf8");
29616
+ const tmp = (0, import_node_path36.join)((0, import_node_os16.tmpdir)(), `mmi-seed-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
29617
+ (0, import_node_fs38.writeFileSync)(tmp, JSON.stringify(contentPutBody(target, content, ref, sha)), "utf8");
29426
29618
  try {
29427
29619
  await gh(contentPutInputArgs(repo, target, tmp));
29428
29620
  } finally {
29429
29621
  try {
29430
- (0, import_node_fs37.unlinkSync)(tmp);
29622
+ (0, import_node_fs38.unlinkSync)(tmp);
29431
29623
  } catch {
29432
29624
  }
29433
29625
  }
@@ -29692,10 +29884,10 @@ LIVE apply to ${repo}:
29692
29884
  bootstrap.command("propagate").description("#4238: re-entrant canary\u2192wave tick \u2014 plan (or, with --execute, open) per-repo PRs fanning an org-owned seed out to the fleet").option("--target <path>", "the manifest target to propagate (an ownership:org + source:self seed, e.g. .github/workflows/agent-pr.yml)").option("--execute", "LIVE tick via gh (master-gated) \u2014 opens/reuses per-repo seed-propagate PRs; dry-run prints the plan only").option("--json", "machine-readable output").action(async () => {
29693
29885
  const o = { target: rawValue("--target", ""), execute: rawFlag("--execute"), json: rawFlag("--json") };
29694
29886
  const manifestPath = "skills/bootstrap/seeds/manifest.json";
29695
- if (!(0, import_node_fs37.existsSync)(manifestPath)) return fail(`bootstrap propagate: ${manifestPath} not found; run from the MMI-Hub repo root \u2014 the Hub's copies ARE the desired state this tick propagates`);
29887
+ if (!(0, import_node_fs38.existsSync)(manifestPath)) return fail(`bootstrap propagate: ${manifestPath} not found; run from the MMI-Hub repo root \u2014 the Hub's copies ARE the desired state this tick propagates`);
29696
29888
  const seedSource = await resolveHubSeedSource(execGitForSeedSource);
29697
29889
  if (!seedSource.ok) return fail(`bootstrap propagate: ${seedSource.reason}`);
29698
- const manifest = loadBootstrapSeeds((0, import_node_fs37.readFileSync)(manifestPath, "utf8"));
29890
+ const manifest = loadBootstrapSeeds((0, import_node_fs38.readFileSync)(manifestPath, "utf8"));
29699
29891
  const propagatable = manifest.seeds.filter((s) => s.ownership === "org" && s.source === "self");
29700
29892
  if (!o.target) {
29701
29893
  return fail(`bootstrap propagate: --target <path> is required \u2014 one of:
@@ -29704,8 +29896,8 @@ LIVE apply to ${repo}:
29704
29896
  const seed = propagatable.find((s) => s.target === o.target);
29705
29897
  if (!seed) return fail(`bootstrap propagate: --target '${o.target}' names no ownership:org + source:self seed in ${manifestPath}. Propagatable targets:
29706
29898
  ${propagatable.map((s) => s.target).join("\n ")}`);
29707
- if (!(0, import_node_fs37.existsSync)(seed.target)) return fail(`bootstrap propagate: the Hub's own copy of '${seed.target}' is missing \u2014 nothing to propagate`);
29708
- const hubContent = (0, import_node_fs37.readFileSync)(seed.target, "utf8");
29899
+ if (!(0, import_node_fs38.existsSync)(seed.target)) return fail(`bootstrap propagate: the Hub's own copy of '${seed.target}' is missing \u2014 nothing to propagate`);
29900
+ const hubContent = (0, import_node_fs38.readFileSync)(seed.target, "utf8");
29709
29901
  const isWorkflowSeed = seed.target.startsWith(".github/workflows/");
29710
29902
  const cfg = await loadConfig();
29711
29903
  const projects = await fetchProjectsList(registryClientDeps(cfg));
@@ -29714,9 +29906,9 @@ LIVE apply to ${repo}:
29714
29906
  }
29715
29907
  const rosterRepos2 = collectRegistryRepos(projects).filter((r) => r.toLowerCase() !== "mutmutco/mmi-hub");
29716
29908
  let independentCount = rosterRepos2.length;
29717
- if ((0, import_node_fs37.existsSync)("projects.json")) {
29909
+ if ((0, import_node_fs38.existsSync)("projects.json")) {
29718
29910
  try {
29719
- const local = JSON.parse((0, import_node_fs37.readFileSync)("projects.json", "utf8"));
29911
+ const local = JSON.parse((0, import_node_fs38.readFileSync)("projects.json", "utf8"));
29720
29912
  const localRepos = /* @__PURE__ */ new Set();
29721
29913
  for (const p of local.projects ?? []) for (const r of p.repos ?? []) {
29722
29914
  const full = (r.includes("/") ? r : `mutmutco/${r}`).toLowerCase();
@@ -29832,13 +30024,13 @@ LIVE apply to ${repo}:
29832
30024
  } catch {
29833
30025
  existingSha = void 0;
29834
30026
  }
29835
- const tmp = (0, import_node_path35.join)((0, import_node_os15.tmpdir)(), `mmi-propagate-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
29836
- (0, import_node_fs37.writeFileSync)(tmp, JSON.stringify(contentPutBody(seed.target, hubContent, branch, existingSha)), "utf8");
30027
+ const tmp = (0, import_node_path36.join)((0, import_node_os16.tmpdir)(), `mmi-propagate-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
30028
+ (0, import_node_fs38.writeFileSync)(tmp, JSON.stringify(contentPutBody(seed.target, hubContent, branch, existingSha)), "utf8");
29837
30029
  try {
29838
30030
  await gh(contentPutInputArgs(rec.repo, seed.target, tmp));
29839
30031
  } finally {
29840
30032
  try {
29841
- (0, import_node_fs37.unlinkSync)(tmp);
30033
+ (0, import_node_fs38.unlinkSync)(tmp);
29842
30034
  } catch {
29843
30035
  }
29844
30036
  }
@@ -29896,10 +30088,10 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
29896
30088
  return fail(`bootstrap rollback: ${e.message}`);
29897
30089
  }
29898
30090
  const manifestPath = "skills/bootstrap/seeds/manifest.json";
29899
- if (!(0, import_node_fs37.existsSync)(manifestPath)) return fail(`bootstrap rollback: ${manifestPath} not found; run from the MMI-Hub repo root \u2014 the manifest names which targets are org-owned and therefore propagated (and rollback-able)`);
30091
+ if (!(0, import_node_fs38.existsSync)(manifestPath)) return fail(`bootstrap rollback: ${manifestPath} not found; run from the MMI-Hub repo root \u2014 the manifest names which targets are org-owned and therefore propagated (and rollback-able)`);
29900
30092
  const seedSource = await resolveHubSeedSource(execGitForSeedSource);
29901
30093
  if (!seedSource.ok) return fail(`bootstrap rollback: ${seedSource.reason}`);
29902
- const manifest = loadBootstrapSeeds((0, import_node_fs37.readFileSync)(manifestPath, "utf8"));
30094
+ const manifest = loadBootstrapSeeds((0, import_node_fs38.readFileSync)(manifestPath, "utf8"));
29903
30095
  const propagatable = manifest.seeds.filter((s) => s.ownership === "org" && s.source === "self");
29904
30096
  if (!o.target) {
29905
30097
  return fail(`bootstrap rollback: --target <path> is required \u2014 one of:
@@ -29916,10 +30108,10 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
29916
30108
  const enc = (p) => p.split("/").map(encodeURIComponent).join("/");
29917
30109
  let candidates;
29918
30110
  if (o.record) {
29919
- if (!(0, import_node_fs37.existsSync)(o.record)) return fail(`bootstrap rollback: --record '${o.record}' not found`);
30111
+ if (!(0, import_node_fs38.existsSync)(o.record)) return fail(`bootstrap rollback: --record '${o.record}' not found`);
29920
30112
  let parsed;
29921
30113
  try {
29922
- parsed = JSON.parse((0, import_node_fs37.readFileSync)(o.record, "utf8"));
30114
+ parsed = JSON.parse((0, import_node_fs38.readFileSync)(o.record, "utf8"));
29923
30115
  } catch (e) {
29924
30116
  return fail(`bootstrap rollback: --record '${o.record}' is not valid JSON: ${e.message}`);
29925
30117
  }
@@ -29988,13 +30180,13 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
29988
30180
  } catch {
29989
30181
  existingSha = void 0;
29990
30182
  }
29991
- const tmp = (0, import_node_path35.join)((0, import_node_os15.tmpdir)(), `mmi-rollback-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
29992
- (0, import_node_fs37.writeFileSync)(tmp, JSON.stringify(contentPutBody(seed.target, preSeedContent, plan.branch, existingSha)), "utf8");
30183
+ const tmp = (0, import_node_path36.join)((0, import_node_os16.tmpdir)(), `mmi-rollback-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
30184
+ (0, import_node_fs38.writeFileSync)(tmp, JSON.stringify(contentPutBody(seed.target, preSeedContent, plan.branch, existingSha)), "utf8");
29993
30185
  try {
29994
30186
  await gh(contentPutInputArgs(repo, seed.target, tmp));
29995
30187
  } finally {
29996
30188
  try {
29997
- (0, import_node_fs37.unlinkSync)(tmp);
30189
+ (0, import_node_fs38.unlinkSync)(tmp);
29998
30190
  } catch {
29999
30191
  }
30000
30192
  }
@@ -30016,12 +30208,12 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
30016
30208
  }
30017
30209
 
30018
30210
  // src/stage-commands.ts
30019
- var import_node_fs39 = require("node:fs");
30020
- var import_node_path37 = require("node:path");
30211
+ var import_node_fs40 = require("node:fs");
30212
+ var import_node_path38 = require("node:path");
30021
30213
 
30022
30214
  // src/port-registry.ts
30023
- var import_node_fs38 = require("node:fs");
30024
- var import_node_path36 = require("node:path");
30215
+ var import_node_fs39 = require("node:fs");
30216
+ var import_node_path37 = require("node:path");
30025
30217
 
30026
30218
  // ../infra/port-geometry.mjs
30027
30219
  var PORT_BLOCK = 100;
@@ -30035,8 +30227,8 @@ function nextPortBlock(registry2) {
30035
30227
  return [base, base + PORT_SPAN];
30036
30228
  }
30037
30229
  function loadPortRegistry(path2) {
30038
- if (!(0, import_node_fs38.existsSync)(path2)) return {};
30039
- const raw = JSON.parse((0, import_node_fs38.readFileSync)(path2, "utf8"));
30230
+ if (!(0, import_node_fs39.existsSync)(path2)) return {};
30231
+ const raw = JSON.parse((0, import_node_fs39.readFileSync)(path2, "utf8"));
30040
30232
  const out = {};
30041
30233
  for (const [key, value] of Object.entries(raw)) {
30042
30234
  if (Array.isArray(value) && value.length === 2 && value.every((n) => typeof n === "number")) {
@@ -30050,9 +30242,9 @@ function ensurePortRange(repo, path2) {
30050
30242
  const existing = registry2[repo];
30051
30243
  if (existing) return existing;
30052
30244
  const range = nextPortBlock(registry2);
30053
- const raw = (0, import_node_fs38.existsSync)(path2) ? JSON.parse((0, import_node_fs38.readFileSync)(path2, "utf8")) : {};
30245
+ const raw = (0, import_node_fs39.existsSync)(path2) ? JSON.parse((0, import_node_fs39.readFileSync)(path2, "utf8")) : {};
30054
30246
  raw[repo] = range;
30055
- (0, import_node_fs38.writeFileSync)(path2, JSON.stringify(raw, null, 2) + "\n", "utf8");
30247
+ (0, import_node_fs39.writeFileSync)(path2, JSON.stringify(raw, null, 2) + "\n", "utf8");
30056
30248
  return range;
30057
30249
  }
30058
30250
  function portCursorSeed(registry2) {
@@ -30074,22 +30266,22 @@ function existingPortRange(repo, registry2) {
30074
30266
  return registry2[repo] ?? null;
30075
30267
  }
30076
30268
  function portRangeInfraAt(root, source) {
30077
- const registryPath = (0, import_node_path36.join)(root, "infra", "port-ranges.json");
30078
- const ddbScriptPath = (0, import_node_path36.join)(root, "infra", "port-ddb.mjs");
30079
- if (!(0, import_node_fs38.existsSync)(registryPath) || !(0, import_node_fs38.existsSync)(ddbScriptPath)) return null;
30269
+ const registryPath = (0, import_node_path37.join)(root, "infra", "port-ranges.json");
30270
+ const ddbScriptPath = (0, import_node_path37.join)(root, "infra", "port-ddb.mjs");
30271
+ if (!(0, import_node_fs39.existsSync)(registryPath) || !(0, import_node_fs39.existsSync)(ddbScriptPath)) return null;
30080
30272
  return { root, source, registryPath, ddbScriptPath };
30081
30273
  }
30082
30274
  function resolvePortRangeInfra(cwd, packageDir) {
30083
30275
  const direct = portRangeInfraAt(cwd, "cwd");
30084
30276
  if (direct) return direct;
30085
- for (let dir = cwd; ; dir = (0, import_node_path36.dirname)(dir)) {
30086
- const sibling = portRangeInfraAt((0, import_node_path36.join)(dir, "MMI-Hub"), "sibling-hub");
30277
+ for (let dir = cwd; ; dir = (0, import_node_path37.dirname)(dir)) {
30278
+ const sibling = portRangeInfraAt((0, import_node_path37.join)(dir, "MMI-Hub"), "sibling-hub");
30087
30279
  if (sibling) return sibling;
30088
- const parent = (0, import_node_path36.dirname)(dir);
30280
+ const parent = (0, import_node_path37.dirname)(dir);
30089
30281
  if (parent === dir) break;
30090
30282
  }
30091
30283
  if (packageDir) {
30092
- const pkgRoot = (0, import_node_path36.join)(packageDir, "..", "..");
30284
+ const pkgRoot = (0, import_node_path37.join)(packageDir, "..", "..");
30093
30285
  const pkgFrom = portRangeInfraAt(pkgRoot, "pkg-root");
30094
30286
  if (pkgFrom) return pkgFrom;
30095
30287
  }
@@ -30283,8 +30475,8 @@ function registerStageCommands(program3) {
30283
30475
  const portRange = portRangeMeta && typeof portRangeMeta.start === "number" && typeof portRangeMeta.end === "number" ? [portRangeMeta.start, portRangeMeta.end] : void 0;
30284
30476
  return decideStage({
30285
30477
  registry: { deployModel: project2?.deployModel, portRange, error: read.ok ? void 0 : read.error },
30286
- hasCompose: (0, import_node_fs39.existsSync)((0, import_node_path37.join)(process.cwd(), "docker-compose.yml")),
30287
- hasEnvExample: (0, import_node_fs39.existsSync)((0, import_node_path37.join)(process.cwd(), ".env.example"))
30478
+ hasCompose: (0, import_node_fs40.existsSync)((0, import_node_path38.join)(process.cwd(), "docker-compose.yml")),
30479
+ hasEnvExample: (0, import_node_fs40.existsSync)((0, import_node_path38.join)(process.cwd(), ".env.example"))
30288
30480
  });
30289
30481
  }
30290
30482
  async function fetchStageVaultEnvMerge() {
@@ -30775,10 +30967,10 @@ function registerBoardCommands(program3) {
30775
30967
  }
30776
30968
 
30777
30969
  // src/merge-cleanup.ts
30778
- var import_node_fs40 = require("node:fs");
30970
+ var import_node_fs41 = require("node:fs");
30779
30971
  var import_promises9 = require("node:fs/promises");
30780
- var import_node_path39 = require("node:path");
30781
- var import_node_os16 = require("node:os");
30972
+ var import_node_path40 = require("node:path");
30973
+ var import_node_os17 = require("node:os");
30782
30974
  var import_node_child_process17 = require("node:child_process");
30783
30975
 
30784
30976
  // src/board-advance.ts
@@ -30865,7 +31057,7 @@ function boardAdvanceFailureMessage(result) {
30865
31057
 
30866
31058
  // src/deferred-registry-store.ts
30867
31059
  var import_promises8 = require("node:fs/promises");
30868
- var import_node_path38 = require("node:path");
31060
+ var import_node_path39 = require("node:path");
30869
31061
  var sleep2 = (ms) => new Promise((resolve7) => setTimeout(resolve7, ms));
30870
31062
  async function atomicWrite(target, contents) {
30871
31063
  const tmp = `${target}.tmp-${process.pid}-${Math.random().toString(36).slice(2)}`;
@@ -30916,12 +31108,12 @@ function makeDeferredWorktreeStore(registryPath, lockOpts = {}) {
30916
31108
  },
30917
31109
  // Standalone atomic write — THROWS on failure (no best-effort swallow, #2846).
30918
31110
  write: async (entries) => {
30919
- await (0, import_promises8.mkdir)((0, import_node_path38.dirname)(registryPath), { recursive: true });
31111
+ await (0, import_promises8.mkdir)((0, import_node_path39.dirname)(registryPath), { recursive: true });
30920
31112
  await atomicWrite(registryPath, serializeDeferredWorktrees(entries));
30921
31113
  },
30922
31114
  // Serialized read-modify-write under the repo-wide lock (#2846).
30923
31115
  update: async (mutate) => {
30924
- await (0, import_promises8.mkdir)((0, import_node_path38.dirname)(registryPath), { recursive: true });
31116
+ await (0, import_promises8.mkdir)((0, import_node_path39.dirname)(registryPath), { recursive: true });
30925
31117
  const deadline = Date.now() + opts.maxWaitMs;
30926
31118
  for (; ; ) {
30927
31119
  const guard = await acquireLock(lockPath, opts, deadline);
@@ -31085,17 +31277,17 @@ ${err.stderr ?? ""}`;
31085
31277
  return { step, status: `failed: ${msg}` };
31086
31278
  }
31087
31279
  }
31088
- async function bestEffortCloseMissingWorktreeLeases(leaseDir = (0, import_node_path39.join)((0, import_node_os16.homedir)(), ".jerv", "leases"), exists = import_node_fs40.existsSync) {
31280
+ async function bestEffortCloseMissingWorktreeLeases(leaseDir = (0, import_node_path40.join)((0, import_node_os17.homedir)(), ".jerv", "leases"), exists = import_node_fs41.existsSync) {
31089
31281
  let names = [];
31090
31282
  try {
31091
- names = (0, import_node_fs40.readdirSync)(leaseDir);
31283
+ names = (0, import_node_fs41.readdirSync)(leaseDir);
31092
31284
  } catch {
31093
31285
  return;
31094
31286
  }
31095
31287
  for (const name of names) {
31096
31288
  if (!name.endsWith(".json")) continue;
31097
31289
  try {
31098
- const rec = JSON.parse((0, import_node_fs40.readFileSync)((0, import_node_path39.join)(leaseDir, name), "utf8"));
31290
+ const rec = JSON.parse((0, import_node_fs41.readFileSync)((0, import_node_path40.join)(leaseDir, name), "utf8"));
31099
31291
  if (rec.kind !== "worktree" || rec.state === "closed" || typeof rec.ref !== "string" || !rec.ref.trim()) continue;
31100
31292
  if (!exists(rec.ref)) await bestEffortLeaseClose(rec.ref);
31101
31293
  } catch {
@@ -31109,7 +31301,7 @@ async function applyGcPlan(plan, remote, opts = {}) {
31109
31301
  );
31110
31302
  const repoRoot2 = (await execFileP2("git", ["rev-parse", "--show-toplevel"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim() || process.cwd();
31111
31303
  const worktreeGitRoot = await currentRepoWorktreeGitRoot(repoRoot2);
31112
- const primaryRepoRoot = worktreeGitRoot ? (0, import_node_path39.dirname)((0, import_node_path39.dirname)(worktreeGitRoot)) : repoRoot2;
31304
+ const primaryRepoRoot = worktreeGitRoot ? (0, import_node_path40.dirname)((0, import_node_path40.dirname)(worktreeGitRoot)) : repoRoot2;
31113
31305
  const gcActor = describeActor({ env: process.env, surface: detectSurface(process.env), cwd: process.cwd() });
31114
31306
  const owners = readWorktreeOwners(primaryRepoRoot);
31115
31307
  const removalNow = Date.now();
@@ -31168,7 +31360,7 @@ async function applyGcPlan(plan, remote, opts = {}) {
31168
31360
  const cleanup = await cleanupPrMergeLocalBranch(branch.branch, {
31169
31361
  beforeWorktrees,
31170
31362
  startingPath: branch.worktreePath,
31171
- pathExists: (p) => (0, import_node_fs40.existsSync)(p),
31363
+ pathExists: (p) => (0, import_node_fs41.existsSync)(p),
31172
31364
  execGit: async (args) => (await execFileP2("git", args, { timeout: GIT_TIMEOUT_MS })).stdout,
31173
31365
  teardownWorktreeStage,
31174
31366
  deferredStore,
@@ -31207,7 +31399,7 @@ async function applyGcPlan(plan, remote, opts = {}) {
31207
31399
  let removalAttempted = false;
31208
31400
  try {
31209
31401
  const cleanupTarget = resolveSafeSiblingWorktreeCleanupTarget(wt.path, cleanupRoots, {
31210
- realpath: (path2) => (0, import_node_fs40.realpathSync)(path2)
31402
+ realpath: (path2) => (0, import_node_fs41.realpathSync)(path2)
31211
31403
  });
31212
31404
  if (!cleanupTarget.ok) {
31213
31405
  result.failed.push(`${wt.path}: ${cleanupTarget.reason}`);
@@ -31309,13 +31501,13 @@ async function composeOverrideBodyFile(prNumber, repoArgs, gh) {
31309
31501
  const commits = JSON.parse(raw).commits ?? [];
31310
31502
  const body = squashBodyWithOverride(commits.map((c) => ({ headline: c.messageHeadline ?? "", body: c.messageBody ?? "" })), process.cwd());
31311
31503
  if (!body) return void 0;
31312
- const dir = (0, import_node_fs40.mkdtempSync)((0, import_node_path39.join)((0, import_node_os16.tmpdir)(), "mmi-squash-body-"));
31313
- const path2 = (0, import_node_path39.join)(dir, "body.txt");
31314
- (0, import_node_fs40.writeFileSync)(path2, `${body}
31504
+ const dir = (0, import_node_fs41.mkdtempSync)((0, import_node_path40.join)((0, import_node_os17.tmpdir)(), "mmi-squash-body-"));
31505
+ const path2 = (0, import_node_path40.join)(dir, "body.txt");
31506
+ (0, import_node_fs41.writeFileSync)(path2, `${body}
31315
31507
  `, "utf8");
31316
31508
  return { path: path2, cleanup: () => {
31317
31509
  try {
31318
- (0, import_node_fs40.rmSync)(dir, { recursive: true, force: true });
31510
+ (0, import_node_fs41.rmSync)(dir, { recursive: true, force: true });
31319
31511
  } catch {
31320
31512
  }
31321
31513
  } };
@@ -31438,13 +31630,13 @@ var realWorktreeDirRemover = {
31438
31630
  const target = win32LongPath(p);
31439
31631
  let st;
31440
31632
  try {
31441
- st = (0, import_node_fs40.lstatSync)(target);
31633
+ st = (0, import_node_fs41.lstatSync)(target);
31442
31634
  } catch {
31443
31635
  return null;
31444
31636
  }
31445
31637
  if (st.isSymbolicLink()) return "link";
31446
31638
  try {
31447
- (0, import_node_fs40.readlinkSync)(target);
31639
+ (0, import_node_fs41.readlinkSync)(target);
31448
31640
  return "link";
31449
31641
  } catch {
31450
31642
  }
@@ -31452,7 +31644,7 @@ var realWorktreeDirRemover = {
31452
31644
  },
31453
31645
  readdir: (p) => {
31454
31646
  try {
31455
- return (0, import_node_fs40.readdirSync)(win32LongPath(p));
31647
+ return (0, import_node_fs41.readdirSync)(win32LongPath(p));
31456
31648
  } catch {
31457
31649
  return [];
31458
31650
  }
@@ -31462,9 +31654,9 @@ var realWorktreeDirRemover = {
31462
31654
  detachLink: (p) => {
31463
31655
  const target = win32LongPath(p);
31464
31656
  try {
31465
- (0, import_node_fs40.rmdirSync)(target);
31657
+ (0, import_node_fs41.rmdirSync)(target);
31466
31658
  } catch {
31467
- (0, import_node_fs40.unlinkSync)(target);
31659
+ (0, import_node_fs41.unlinkSync)(target);
31468
31660
  }
31469
31661
  },
31470
31662
  // #4904: Windows MAX_PATH aborts git worktree remove; the fallback must use \\?\ so the dir
@@ -31487,7 +31679,7 @@ function worktreeRemoveDeps(execGit) {
31487
31679
  detachReparsePoints: (worktreePath) => detachReparsePoints(worktreePath, realWorktreeDirRemover),
31488
31680
  removeWorktreeDir: async (worktreePath) => removeWorktreeTree(worktreePath, await resolvePrimaryCheckout(execGit), realWorktreeDirRemover),
31489
31681
  // #4850: verify the directory is actually gone before any caller reports completion.
31490
- pathExists: (worktreePath) => (0, import_node_fs40.existsSync)(worktreePath)
31682
+ pathExists: (worktreePath) => (0, import_node_fs41.existsSync)(worktreePath)
31491
31683
  };
31492
31684
  }
31493
31685
  async function worktreeHasStageState(worktreePath) {
@@ -31501,9 +31693,9 @@ async function worktreeHasStageState(worktreePath) {
31501
31693
  }
31502
31694
  }
31503
31695
  function stageStateFileBelongsToWorktree(statePath, worktreePath) {
31504
- if (!(0, import_node_fs40.existsSync)(statePath)) return false;
31696
+ if (!(0, import_node_fs41.existsSync)(statePath)) return false;
31505
31697
  try {
31506
- const state = JSON.parse((0, import_node_fs40.readFileSync)(statePath, "utf8"));
31698
+ const state = JSON.parse((0, import_node_fs41.readFileSync)(statePath, "utf8"));
31507
31699
  const recordedCwd = typeof state.identity?.cwd === "string" ? state.identity.cwd : typeof state.cwd === "string" ? state.cwd : "";
31508
31700
  return Boolean(recordedCwd && isPathUnderDirectory2(recordedCwd, worktreePath));
31509
31701
  } catch {
@@ -31938,15 +32130,15 @@ async function checkDocsIndexAtHead(opts, deps) {
31938
32130
  }
31939
32131
 
31940
32132
  // src/worktree-lifecycle-commands.ts
31941
- var import_node_fs42 = require("node:fs");
32133
+ var import_node_fs43 = require("node:fs");
31942
32134
  var import_promises10 = require("node:fs/promises");
31943
- var import_node_os17 = require("node:os");
31944
- var import_node_path41 = require("node:path");
32135
+ var import_node_os18 = require("node:os");
32136
+ var import_node_path42 = require("node:path");
31945
32137
 
31946
32138
  // src/worktree-install-cache.ts
31947
32139
  var import_node_crypto8 = require("node:crypto");
31948
- var import_node_fs41 = require("node:fs");
31949
- var import_node_path40 = require("node:path");
32140
+ var import_node_fs42 = require("node:fs");
32141
+ var import_node_path41 = require("node:path");
31950
32142
  var CACHE_DIR = "worktree-install-cache";
31951
32143
  var MANIFEST = "manifest.json";
31952
32144
  var NODE_MODULES2 = "node_modules";
@@ -31959,16 +32151,16 @@ var LOCKFILE_NAMES = [
31959
32151
  "package-lock.json"
31960
32152
  ];
31961
32153
  var realWorktreeInstallCacheFs = {
31962
- exists: import_node_fs41.existsSync,
31963
- readFile: (path2) => (0, import_node_fs41.readFileSync)(path2, "utf8"),
31964
- lstat: (path2) => (0, import_node_fs41.lstatSync)(path2),
31965
- copyDir: (from, to) => (0, import_node_fs41.cpSync)(from, to, { recursive: true, force: true }),
32154
+ exists: import_node_fs42.existsSync,
32155
+ readFile: (path2) => (0, import_node_fs42.readFileSync)(path2, "utf8"),
32156
+ lstat: (path2) => (0, import_node_fs42.lstatSync)(path2),
32157
+ copyDir: (from, to) => (0, import_node_fs42.cpSync)(from, to, { recursive: true, force: true }),
31966
32158
  mkdirp: (path2) => {
31967
- (0, import_node_fs41.mkdirSync)(path2, { recursive: true });
32159
+ (0, import_node_fs42.mkdirSync)(path2, { recursive: true });
31968
32160
  },
31969
- writeFile: (path2, contents) => (0, import_node_fs41.writeFileSync)(path2, contents, "utf8"),
32161
+ writeFile: (path2, contents) => (0, import_node_fs42.writeFileSync)(path2, contents, "utf8"),
31970
32162
  rm: (path2) => {
31971
- (0, import_node_fs41.rmSync)(path2, { recursive: true, force: true });
32163
+ (0, import_node_fs42.rmSync)(path2, { recursive: true, force: true });
31972
32164
  }
31973
32165
  };
31974
32166
  function hashLockfileBytes(contents) {
@@ -31976,7 +32168,7 @@ function hashLockfileBytes(contents) {
31976
32168
  }
31977
32169
  function resolveWorktreeInstallLockfile(packageDir, fs2 = realWorktreeInstallCacheFs) {
31978
32170
  for (const name of LOCKFILE_NAMES) {
31979
- const path2 = (0, import_node_path40.join)(packageDir, name);
32171
+ const path2 = (0, import_node_path41.join)(packageDir, name);
31980
32172
  if (!fs2.exists(path2)) continue;
31981
32173
  try {
31982
32174
  const hash = hashLockfileBytes(fs2.readFile(path2));
@@ -31991,8 +32183,8 @@ function worktreeInstallCacheEntry(primaryRoot, lockfileHash) {
31991
32183
  const root = repoRuntimeStatePath(primaryRoot, CACHE_DIR, lockfileHash);
31992
32184
  return {
31993
32185
  root,
31994
- manifestPath: (0, import_node_path40.join)(root, MANIFEST),
31995
- nodeModulesPath: (0, import_node_path40.join)(root, NODE_MODULES2)
32186
+ manifestPath: (0, import_node_path41.join)(root, MANIFEST),
32187
+ nodeModulesPath: (0, import_node_path41.join)(root, NODE_MODULES2)
31996
32188
  };
31997
32189
  }
31998
32190
  function readWorktreeInstallCacheManifest(manifestPath, fs2 = realWorktreeInstallCacheFs) {
@@ -32032,7 +32224,7 @@ function invalidateWorktreeInstallCacheEntry(entry, fs2 = realWorktreeInstallCac
32032
32224
  }
32033
32225
  }
32034
32226
  function removeMaterializedTree(packageDir, fs2) {
32035
- const dest = (0, import_node_path40.join)(packageDir, NODE_MODULES2);
32227
+ const dest = (0, import_node_path41.join)(packageDir, NODE_MODULES2);
32036
32228
  if (!fs2.exists(dest)) return;
32037
32229
  fs2.rm(dest);
32038
32230
  if (fs2.exists(dest)) {
@@ -32040,7 +32232,7 @@ function removeMaterializedTree(packageDir, fs2) {
32040
32232
  }
32041
32233
  }
32042
32234
  function materializeCachedNodeModules(entry, destPackageDir, fs2 = realWorktreeInstallCacheFs) {
32043
- const dest = (0, import_node_path40.join)(destPackageDir, NODE_MODULES2);
32235
+ const dest = (0, import_node_path41.join)(destPackageDir, NODE_MODULES2);
32044
32236
  try {
32045
32237
  if (fs2.exists(dest)) fs2.rm(dest);
32046
32238
  fs2.mkdirp(destPackageDir);
@@ -32055,7 +32247,7 @@ function materializeCachedNodeModules(entry, destPackageDir, fs2 = realWorktreeI
32055
32247
  }
32056
32248
  }
32057
32249
  async function storeWorktreeInstallCacheEntry(primaryRoot, lockfile, command, sourcePackageDir, fs2 = realWorktreeInstallCacheFs, now = Date.now()) {
32058
- const source = (0, import_node_path40.join)(sourcePackageDir, NODE_MODULES2);
32250
+ const source = (0, import_node_path41.join)(sourcePackageDir, NODE_MODULES2);
32059
32251
  if (!isMaterializableNodeModulesDir(source, fs2)) return;
32060
32252
  const entry = worktreeInstallCacheEntry(primaryRoot, lockfile.hash);
32061
32253
  const manifest = {
@@ -32339,7 +32531,7 @@ function classifyStaleLeaks(input) {
32339
32531
  var defaultOrphanDirScanDeps = {
32340
32532
  listDirs: (root) => {
32341
32533
  try {
32342
- return (0, import_node_fs42.readdirSync)(root, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => (0, import_node_path41.join)(root, e.name));
32534
+ return (0, import_node_fs43.readdirSync)(root, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => (0, import_node_path42.join)(root, e.name));
32343
32535
  } catch {
32344
32536
  return [];
32345
32537
  }
@@ -32529,13 +32721,13 @@ function registerWorktreeCommands(program3) {
32529
32721
  const detached = headBorn && !symbolicBranch;
32530
32722
  const branch = symbolicBranch || (detached ? "HEAD" : "");
32531
32723
  if (!wtPath || !branch) return fail("worktree land: not inside a git worktree");
32532
- const gitFile = (0, import_node_path41.join)(wtPath, ".git");
32533
- const isLinked = (0, import_node_fs42.existsSync)(gitFile) && (0, import_node_fs42.statSync)(gitFile).isFile();
32724
+ const gitFile = (0, import_node_path42.join)(wtPath, ".git");
32725
+ const isLinked = (0, import_node_fs43.existsSync)(gitFile) && (0, import_node_fs43.statSync)(gitFile).isFile();
32534
32726
  if (apply && !isLinked) {
32535
32727
  return fail("worktree land: run from inside the linked worktree you want to land (this is the primary checkout)");
32536
32728
  }
32537
32729
  const commonDir = (await execFileP2("git", ["rev-parse", "--git-common-dir"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim();
32538
- const primaryCheckout = commonDir ? (0, import_node_path41.dirname)(commonDir) : wtPath;
32730
+ const primaryCheckout = commonDir ? (0, import_node_path42.dirname)(commonDir) : wtPath;
32539
32731
  const localBranchNames = await execFileP2("git", ["-C", primaryCheckout, "for-each-ref", "--format=%(refname:short)", "refs/heads"], { timeout: GIT_TIMEOUT_MS }).then(({ stdout }) => new Set((stdout || "").split("\n").map((l) => l.trim()).filter(Boolean))).catch(() => void 0);
32540
32732
  const orphan = classifyOrphanedWorktree({
32541
32733
  branch,
@@ -32795,7 +32987,7 @@ async function gatherWorktreeContext() {
32795
32987
  const porcelain = (await execFileP2("git", ["worktree", "list", "--porcelain"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout;
32796
32988
  const parsed = parseWorktreePorcelain(porcelain);
32797
32989
  const primaryPath = parsed[0]?.path ?? repoRoot2;
32798
- const worktrees = parsed.map((w) => ({ path: (0, import_node_path41.resolve)(toNativePath(w.path)), branch: w.branch, primary: w.path === primaryPath }));
32990
+ const worktrees = parsed.map((w) => ({ path: (0, import_node_path42.resolve)(toNativePath(w.path)), branch: w.branch, primary: w.path === primaryPath }));
32799
32991
  const branchOut = (await execFileP2("git", ["branch", "--format=%(refname:short)"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout;
32800
32992
  const localBranches = branchOut.split(/\r?\n/).map((l) => l.trim()).filter(Boolean);
32801
32993
  const currentBranch2 = (await execFileP2("git", ["rev-parse", "--abbrev-ref", "HEAD"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim() || void 0;
@@ -32833,17 +33025,17 @@ async function gatherWorktreeContext() {
32833
33025
  if (s) stages.push({ path: wt.path, port: s.port });
32834
33026
  }
32835
33027
  const worktreeGitRoot = await currentRepoWorktreeGitRoot(repoRoot2);
32836
- const primaryRepoRoot = worktreeGitRoot ? (0, import_node_path41.dirname)((0, import_node_path41.dirname)(worktreeGitRoot)) : repoRoot2;
33028
+ const primaryRepoRoot = worktreeGitRoot ? (0, import_node_path42.dirname)((0, import_node_path42.dirname)(worktreeGitRoot)) : repoRoot2;
32837
33029
  const wtRoot = siblingMmiWorktreesRoot(primaryRepoRoot);
32838
33030
  let orphanDirs = [];
32839
- if ((0, import_node_fs42.existsSync)(wtRoot)) {
33031
+ if ((0, import_node_fs43.existsSync)(wtRoot)) {
32840
33032
  orphanDirs = scanOrphanDirs(wtRoot, worktreeGitRoot, {
32841
33033
  ...defaultOrphanDirScanDeps,
32842
33034
  listDirs: (root) => worktreeScanDirs(root, primaryRepoRoot, defaultOrphanDirScanDeps.listDirs, isRepoCheckoutDir)
32843
33035
  });
32844
33036
  }
32845
33037
  const repoContainer = worktreesRootOf(primaryRepoRoot);
32846
- if ((0, import_node_fs42.existsSync)(repoContainer)) {
33038
+ if ((0, import_node_fs43.existsSync)(repoContainer)) {
32847
33039
  for (const dir of defaultOrphanDirScanDeps.listDirs(repoContainer)) {
32848
33040
  if (orphanDirs.some((o) => o.path === dir)) continue;
32849
33041
  const inspected = inspectSiblingWorktreeDir(dir, worktreeGitRoot);
@@ -32867,7 +33059,7 @@ async function gatherWorktreeContext() {
32867
33059
  });
32868
33060
  const helperWorktrees = scanHelperWorktrees(primaryRepoRoot, worktreeGitRoot);
32869
33061
  const leaseRefs = readJervWorktreeLeaseRefs();
32870
- const missingLeaseRefs = leaseRefs.filter((ref) => !(0, import_node_fs42.existsSync)(ref));
33062
+ const missingLeaseRefs = leaseRefs.filter((ref) => !(0, import_node_fs43.existsSync)(ref));
32871
33063
  const remoteUrls = await gitRemoteUrls();
32872
33064
  const otherCheckouts = discoverOtherPrimaries(primaryRepoRoot).map((path2) => ({
32873
33065
  path: path2,
@@ -32897,16 +33089,16 @@ async function gatherWorktreeContext() {
32897
33089
  };
32898
33090
  }
32899
33091
  function gitConfigRemoteUrls(checkout) {
32900
- const gitPath = (0, import_node_path41.join)(checkout, ".git");
32901
- let configPath = (0, import_node_path41.join)(checkout, ".git", "config");
33092
+ const gitPath = (0, import_node_path42.join)(checkout, ".git");
33093
+ let configPath = (0, import_node_path42.join)(checkout, ".git", "config");
32902
33094
  try {
32903
- const st = (0, import_node_fs42.statSync)(gitPath);
33095
+ const st = (0, import_node_fs43.statSync)(gitPath);
32904
33096
  if (st.isFile()) return [];
32905
33097
  } catch {
32906
33098
  return [];
32907
33099
  }
32908
33100
  try {
32909
- const text = (0, import_node_fs42.readFileSync)(configPath, "utf8");
33101
+ const text = (0, import_node_fs43.readFileSync)(configPath, "utf8");
32910
33102
  return [...text.matchAll(/^\s*url\s*=\s*(.+)$/gm)].map((m) => m[1].trim());
32911
33103
  } catch {
32912
33104
  return [];
@@ -32920,26 +33112,26 @@ async function gitRemoteUrls() {
32920
33112
  }
32921
33113
  function discoverOtherPrimaries(primaryRepoRoot) {
32922
33114
  const found = /* @__PURE__ */ new Set();
32923
- const parent = (0, import_node_path41.dirname)(primaryRepoRoot);
33115
+ const parent = (0, import_node_path42.dirname)(primaryRepoRoot);
32924
33116
  try {
32925
- for (const name of (0, import_node_fs42.readdirSync)(parent)) {
32926
- const path2 = (0, import_node_path41.join)(parent, name);
33117
+ for (const name of (0, import_node_fs43.readdirSync)(parent)) {
33118
+ const path2 = (0, import_node_path42.join)(parent, name);
32927
33119
  if (path2 === primaryRepoRoot) continue;
32928
- if ((0, import_node_fs42.existsSync)((0, import_node_path41.join)(path2, ".git"))) found.add(path2);
33120
+ if ((0, import_node_fs43.existsSync)((0, import_node_path42.join)(path2, ".git"))) found.add(path2);
32929
33121
  }
32930
33122
  } catch {
32931
33123
  }
32932
- const mirror = (0, import_node_path41.join)((0, import_node_os17.homedir)(), "Projects", (0, import_node_path41.basename)(primaryRepoRoot));
32933
- if (mirror !== primaryRepoRoot && (0, import_node_fs42.existsSync)((0, import_node_path41.join)(mirror, ".git"))) found.add(mirror);
33124
+ const mirror = (0, import_node_path42.join)((0, import_node_os18.homedir)(), "Projects", (0, import_node_path42.basename)(primaryRepoRoot));
33125
+ if (mirror !== primaryRepoRoot && (0, import_node_fs43.existsSync)((0, import_node_path42.join)(mirror, ".git"))) found.add(mirror);
32934
33126
  return [...found];
32935
33127
  }
32936
- function readJervWorktreeLeaseRefs(leaseDir = (0, import_node_path41.join)((0, import_node_os17.homedir)(), ".jerv", "leases")) {
33128
+ function readJervWorktreeLeaseRefs(leaseDir = (0, import_node_path42.join)((0, import_node_os18.homedir)(), ".jerv", "leases")) {
32937
33129
  try {
32938
33130
  const refs = [];
32939
- for (const name of (0, import_node_fs42.readdirSync)(leaseDir)) {
33131
+ for (const name of (0, import_node_fs43.readdirSync)(leaseDir)) {
32940
33132
  if (!name.endsWith(".json")) continue;
32941
33133
  try {
32942
- const rec = JSON.parse((0, import_node_fs42.readFileSync)((0, import_node_path41.join)(leaseDir, name), "utf8"));
33134
+ const rec = JSON.parse((0, import_node_fs43.readFileSync)((0, import_node_path42.join)(leaseDir, name), "utf8"));
32943
33135
  if (rec.kind === "worktree" && rec.state !== "closed" && typeof rec.ref === "string" && rec.ref.trim()) {
32944
33136
  refs.push(rec.ref);
32945
33137
  }
@@ -32955,9 +33147,9 @@ function scanHelperWorktrees(thisPrimary, thisWorktreeGitRoot) {
32955
33147
  const primaries = [thisPrimary, ...discoverOtherPrimaries(thisPrimary)];
32956
33148
  const out = [];
32957
33149
  for (const primary of primaries) {
32958
- const gitRoot = primary === thisPrimary ? thisWorktreeGitRoot : (0, import_node_path41.join)(primary, ".git", "worktrees");
33150
+ const gitRoot = primary === thisPrimary ? thisWorktreeGitRoot : (0, import_node_path42.join)(primary, ".git", "worktrees");
32959
33151
  for (const root of helperWorktreeRoots(primary)) {
32960
- if (!(0, import_node_fs42.existsSync)(root)) continue;
33152
+ if (!(0, import_node_fs43.existsSync)(root)) continue;
32961
33153
  for (const dir of defaultOrphanDirScanDeps.listDirs(root)) {
32962
33154
  const inspected = inspectSiblingWorktreeDir(dir, gitRoot);
32963
33155
  const classified = classifySiblingWorktreeDir(inspected);
@@ -32997,7 +33189,7 @@ ${err.stderr ?? ""}`;
32997
33189
  }
32998
33190
 
32999
33191
  // src/issue-commands.ts
33000
- var import_node_fs43 = require("node:fs");
33192
+ var import_node_fs44 = require("node:fs");
33001
33193
  var import_node_crypto9 = require("node:crypto");
33002
33194
  var ghRunner = async (args, timeoutMs) => (await execFileP2("gh", args, { timeout: timeoutMs })).stdout;
33003
33195
  var ReparentConflictError = class extends Error {
@@ -33015,7 +33207,7 @@ async function editIssue(client, options, deps = {}) {
33015
33207
  const url = `https://github.com/${repo}/issues/${parsed.number}`;
33016
33208
  const patch = {};
33017
33209
  let bodyChanged = false;
33018
- const textDeps = () => deps.textDeps ?? { readFile: (p, e) => Promise.resolve((0, import_node_fs43.readFileSync)(p, e)), readStdin: () => Promise.resolve("") };
33210
+ const textDeps = () => deps.textDeps ?? { readFile: (p, e) => Promise.resolve((0, import_node_fs44.readFileSync)(p, e)), readStdin: () => Promise.resolve("") };
33019
33211
  if (options.titleFile !== void 0) {
33020
33212
  patch.title = await resolveIssueTitle({ title: options.title, titleFile: options.titleFile }, textDeps());
33021
33213
  } else if (options.title !== void 0) {
@@ -33620,7 +33812,7 @@ function extendCreateCommand(issue2, batchAttach) {
33620
33812
  if (opts.batch) {
33621
33813
  let specs;
33622
33814
  try {
33623
- const raw = (0, import_node_fs43.readFileSync)(opts.batch, "utf8");
33815
+ const raw = (0, import_node_fs44.readFileSync)(opts.batch, "utf8");
33624
33816
  specs = JSON.parse(raw);
33625
33817
  if (!Array.isArray(specs)) throw new Error("batch file must contain a JSON array");
33626
33818
  } catch (e) {
@@ -33695,8 +33887,8 @@ ${lines}`, {
33695
33887
  }
33696
33888
 
33697
33889
  // src/train-commands.ts
33698
- var import_node_fs44 = require("node:fs");
33699
- var import_node_path42 = require("node:path");
33890
+ var import_node_fs45 = require("node:fs");
33891
+ var import_node_path43 = require("node:path");
33700
33892
  var RELEASE_BUMP_INTENTS = ["major", "minor", "patch"];
33701
33893
  function resolveReleaseBumpIntent(raw) {
33702
33894
  const intent = typeof raw === "string" ? raw.trim() : "";
@@ -33707,7 +33899,7 @@ function resolveReleaseBumpIntent(raw) {
33707
33899
  }
33708
33900
  function readRepoVersion() {
33709
33901
  try {
33710
- return JSON.parse((0, import_node_fs44.readFileSync)((0, import_node_path42.join)(process.cwd(), ".claude-plugin", "plugin.json"), "utf8")).version || void 0;
33902
+ return JSON.parse((0, import_node_fs45.readFileSync)((0, import_node_path43.join)(process.cwd(), ".claude-plugin", "plugin.json"), "utf8")).version || void 0;
33711
33903
  } catch {
33712
33904
  return void 0;
33713
33905
  }
@@ -33864,9 +34056,9 @@ function registerDeployCommands(program3) {
33864
34056
  }
33865
34057
 
33866
34058
  // src/discovery-commands.ts
33867
- var import_node_fs45 = require("node:fs");
33868
- var import_node_os18 = require("node:os");
33869
- var import_node_path43 = require("node:path");
34059
+ var import_node_fs46 = require("node:fs");
34060
+ var import_node_os19 = require("node:os");
34061
+ var import_node_path44 = require("node:path");
33870
34062
  var GC_GH_TIMEOUT_MS3 = 2e4;
33871
34063
  async function collectStatus() {
33872
34064
  const repo = await resolveRepo();
@@ -34050,10 +34242,10 @@ async function collectOnboardStatus(opts = {}) {
34050
34242
  else if (top) nextCommand = `mmi-cli oracle board claim ${top.number} # ${top.title}`;
34051
34243
  else nextCommand = "mmi-cli oracle board read \u2014 no claimable items found";
34052
34244
  }
34053
- const home = (0, import_node_os18.homedir)();
34245
+ const home = (0, import_node_os19.homedir)();
34054
34246
  const plugin = onboardPluginGate({
34055
- readKnown: () => readFileSyncSafe((0, import_node_path43.join)(home, ...KNOWN_MARKETPLACES_RELATIVE), import_node_fs45.readFileSync),
34056
- readSettings: () => readFileSyncSafe((0, import_node_path43.join)(home, ".claude", "settings.json"), import_node_fs45.readFileSync)
34247
+ readKnown: () => readFileSyncSafe((0, import_node_path44.join)(home, ...KNOWN_MARKETPLACES_RELATIVE), import_node_fs46.readFileSync),
34248
+ readSettings: () => readFileSyncSafe((0, import_node_path44.join)(home, ".claude", "settings.json"), import_node_fs46.readFileSync)
34057
34249
  });
34058
34250
  return { track, board, registry: registry2, secrets, plugin, estateCli, doors: opts.doors ?? [], nextCommand };
34059
34251
  }
@@ -37834,17 +38026,17 @@ function parseOriginRepo(remoteUrl) {
37834
38026
  }
37835
38027
  function ghHostsConfigPath(env, platform2) {
37836
38028
  const sep3 = platform2 === "win32" ? "\\" : "/";
37837
- const join40 = (...parts) => parts.join(sep3);
38029
+ const join41 = (...parts) => parts.join(sep3);
37838
38030
  const explicit = env.GH_CONFIG_DIR?.trim();
37839
- if (explicit) return join40(explicit, "hosts.yml");
38031
+ if (explicit) return join41(explicit, "hosts.yml");
37840
38032
  if (platform2 === "win32") {
37841
38033
  const appData = (env.AppData ?? env.APPDATA)?.trim();
37842
- return appData ? join40(appData, "GitHub CLI", "hosts.yml") : void 0;
38034
+ return appData ? join41(appData, "GitHub CLI", "hosts.yml") : void 0;
37843
38035
  }
37844
38036
  const xdg = env.XDG_CONFIG_HOME?.trim();
37845
- if (xdg) return join40(xdg, "gh", "hosts.yml");
38037
+ if (xdg) return join41(xdg, "gh", "hosts.yml");
37846
38038
  const home = env.HOME?.trim();
37847
- return home ? join40(home, ".config", "gh", "hosts.yml") : void 0;
38039
+ return home ? join41(home, ".config", "gh", "hosts.yml") : void 0;
37848
38040
  }
37849
38041
  function parseGhHostsAccounts(yaml, host = "github.com") {
37850
38042
  let hostIndent = null;
@@ -37894,9 +38086,9 @@ function ghAccountCaveat(announcedLogin, accounts) {
37894
38086
  }
37895
38087
 
37896
38088
  // src/doctor-io.ts
37897
- var import_node_fs46 = require("node:fs");
37898
- var import_node_os19 = require("node:os");
37899
- var import_node_path44 = require("node:path");
38089
+ var import_node_fs47 = require("node:fs");
38090
+ var import_node_os20 = require("node:os");
38091
+ var import_node_path45 = require("node:path");
37900
38092
  var import_node_child_process18 = require("node:child_process");
37901
38093
  var import_node_util8 = require("node:util");
37902
38094
  var execFileP6 = (0, import_node_util8.promisify)(import_node_child_process18.execFile);
@@ -37904,7 +38096,7 @@ var MMI_PLUGIN_ID2 = "mmi@mutmutco";
37904
38096
  function installedClaudePluginVersion() {
37905
38097
  try {
37906
38098
  const file = JSON.parse(
37907
- (0, import_node_fs46.readFileSync)((0, import_node_path44.join)((0, import_node_os19.homedir)(), ".claude", "plugins", "installed_plugins.json"), "utf8")
38099
+ (0, import_node_fs47.readFileSync)((0, import_node_path45.join)((0, import_node_os20.homedir)(), ".claude", "plugins", "installed_plugins.json"), "utf8")
37908
38100
  );
37909
38101
  const versions = (file.plugins?.[MMI_PLUGIN_ID2] ?? []).map((r) => r.version).filter((v) => Boolean(v));
37910
38102
  if (versions.length === 0) return void 0;
@@ -37915,7 +38107,7 @@ function installedClaudePluginVersion() {
37915
38107
  }
37916
38108
  function manifestVersion(path2) {
37917
38109
  try {
37918
- const manifest = JSON.parse((0, import_node_fs46.readFileSync)(path2, "utf8"));
38110
+ const manifest = JSON.parse((0, import_node_fs47.readFileSync)(path2, "utf8"));
37919
38111
  return typeof manifest.version === "string" && manifest.version.trim() ? manifest.version.trim() : void 0;
37920
38112
  } catch {
37921
38113
  return void 0;
@@ -37925,20 +38117,20 @@ function installedSurfacePluginVersion(surface) {
37925
38117
  const token = surfaceToken(surface);
37926
38118
  if (token === "kilo") {
37927
38119
  try {
37928
- const stamp = (0, import_node_fs46.readFileSync)((0, import_node_path44.join)((0, import_node_os19.homedir)(), ".kilo", ".mmi-kilo-version"), "utf8").trim();
38120
+ const stamp = (0, import_node_fs47.readFileSync)((0, import_node_path45.join)((0, import_node_os20.homedir)(), ".kilo", ".mmi-kilo-version"), "utf8").trim();
37929
38121
  return stamp || void 0;
37930
38122
  } catch {
37931
38123
  return void 0;
37932
38124
  }
37933
38125
  }
37934
38126
  if (token === "cursor") {
37935
- return manifestVersion((0, import_node_path44.join)(cursorLocalPluginRoot(), ".cursor-plugin", "plugin.json"));
38127
+ return manifestVersion((0, import_node_path45.join)(cursorLocalPluginRoot(), ".cursor-plugin", "plugin.json"));
37936
38128
  }
37937
38129
  if (token === "jervcode") {
37938
38130
  return installedJervCodePackageVersion();
37939
38131
  }
37940
38132
  if (token === "kimi") {
37941
- return manifestVersion((0, import_node_path44.join)(surfaceConfigRoot(surface), "plugins", "managed", "mmi", ".kimi-plugin", "plugin.json"));
38133
+ return manifestVersion((0, import_node_path45.join)(surfaceConfigRoot(surface), "plugins", "managed", "mmi", ".kimi-plugin", "plugin.json"));
37942
38134
  }
37943
38135
  if (token === "claude") return installedClaudePluginVersion();
37944
38136
  if (token !== "codex") return void 0;
@@ -37976,13 +38168,13 @@ function worktreeRootSync() {
37976
38168
  }
37977
38169
  var gitignorePath = () => {
37978
38170
  const root = worktreeRootSync();
37979
- return root === null ? null : (0, import_node_path44.join)(root, ".gitignore");
38171
+ return root === null ? null : (0, import_node_path45.join)(root, ".gitignore");
37980
38172
  };
37981
38173
  function readGitignore() {
37982
38174
  const path2 = gitignorePath();
37983
38175
  if (path2 === null) return null;
37984
38176
  try {
37985
- return (0, import_node_fs46.readFileSync)(path2, "utf8");
38177
+ return (0, import_node_fs47.readFileSync)(path2, "utf8");
37986
38178
  } catch {
37987
38179
  return null;
37988
38180
  }
@@ -37991,7 +38183,7 @@ function writeGitignore(content) {
37991
38183
  const path2 = gitignorePath();
37992
38184
  if (path2 === null) return false;
37993
38185
  try {
37994
- (0, import_node_fs46.writeFileSync)(path2, content, "utf8");
38186
+ (0, import_node_fs47.writeFileSync)(path2, content, "utf8");
37995
38187
  return true;
37996
38188
  } catch {
37997
38189
  return false;
@@ -38010,7 +38202,7 @@ async function repoRoot() {
38010
38202
  }
38011
38203
  function hasRepoLocalWorktrees() {
38012
38204
  const root = worktreeRootSync();
38013
- return root !== null && ((0, import_node_fs46.existsSync)((0, import_node_path44.join)(root, ".worktrees")) || (0, import_node_fs46.existsSync)((0, import_node_path44.join)(root, ".claude", "worktrees")));
38205
+ return root !== null && ((0, import_node_fs47.existsSync)((0, import_node_path45.join)(root, ".worktrees")) || (0, import_node_fs47.existsSync)((0, import_node_path45.join)(root, ".claude", "worktrees")));
38014
38206
  }
38015
38207
 
38016
38208
  // src/cross-repo-filing-issue.ts
@@ -38116,8 +38308,8 @@ ${r.stderr ?? ""}`).catch(() => "");
38116
38308
  function ghMultiAccountCaveat(announcedLogin) {
38117
38309
  try {
38118
38310
  const hostsPath = ghHostsConfigPath(process.env, process.platform);
38119
- if (!hostsPath || !(0, import_node_fs47.existsSync)(hostsPath)) return void 0;
38120
- return ghAccountCaveat(announcedLogin, parseGhHostsAccounts((0, import_node_fs47.readFileSync)(hostsPath, "utf8")));
38311
+ if (!hostsPath || !(0, import_node_fs48.existsSync)(hostsPath)) return void 0;
38312
+ return ghAccountCaveat(announcedLogin, parseGhHostsAccounts((0, import_node_fs48.readFileSync)(hostsPath, "utf8")));
38121
38313
  } catch {
38122
38314
  return void 0;
38123
38315
  }
@@ -38125,12 +38317,12 @@ function ghMultiAccountCaveat(announcedLogin) {
38125
38317
  var ENV_HEAL_LOCK_STALE_MS = 10 * 6e4;
38126
38318
  var ENV_HEAL_LOCK_MAX_WAIT_MS = 2 * 6e4;
38127
38319
  function envHealLockPath(home) {
38128
- return (0, import_node_path45.join)(home, ".claude", "plugins", ".mmi-env-heal.lock");
38320
+ return (0, import_node_path46.join)(home, ".claude", "plugins", ".mmi-env-heal.lock");
38129
38321
  }
38130
38322
  async function withEnvHealLock(what, run) {
38131
38323
  try {
38132
38324
  return await withFileLock(
38133
- envHealLockPath((0, import_node_os20.homedir)()),
38325
+ envHealLockPath((0, import_node_os21.homedir)()),
38134
38326
  { staleMs: ENV_HEAL_LOCK_STALE_MS, maxWaitMs: ENV_HEAL_LOCK_MAX_WAIT_MS, label: "mmi env-heal lock" },
38135
38327
  run
38136
38328
  );
@@ -38225,7 +38417,7 @@ function mmiDoctorDeps(opts = {}) {
38225
38417
  const configRoot = surfaceConfigRoot(surface);
38226
38418
  const running = surface === "codex" ? installedActivePluginVersion(surface) : runningPluginVersion(process.env, resolveClientVersion());
38227
38419
  const plan = buildPluginCachePlan(
38228
- (0, import_node_os20.homedir)(),
38420
+ (0, import_node_os21.homedir)(),
38229
38421
  running,
38230
38422
  pluginCacheFsDeps(configRoot, () => 0),
38231
38423
  { configRoot, includeStaging: surface !== "codex" }
@@ -38249,14 +38441,14 @@ function mmiDoctorDeps(opts = {}) {
38249
38441
  const running = surface === "codex" ? installedActivePluginVersion(surface) : runningPluginVersion(process.env, resolveClientVersion());
38250
38442
  const installed = installedActivePluginVersion(surface);
38251
38443
  const plan = buildPluginCachePlan(
38252
- (0, import_node_os20.homedir)(),
38444
+ (0, import_node_os21.homedir)(),
38253
38445
  running,
38254
38446
  pluginCacheFsDeps(configRoot, () => 0),
38255
38447
  { configRoot, includeStaging: surface !== "codex", installedVersion: installed }
38256
38448
  );
38257
38449
  const result = applyPluginCachePlan(
38258
38450
  plan,
38259
- (p) => (0, import_node_fs47.rmSync)(p, { recursive: true }),
38451
+ (p) => (0, import_node_fs48.rmSync)(p, { recursive: true }),
38260
38452
  stagingApplyFsGuard(configRoot)
38261
38453
  );
38262
38454
  return {
@@ -38294,7 +38486,7 @@ function mmiDoctorDeps(opts = {}) {
38294
38486
  // adopted the generated routing index (MMG-Unlive: `docs/Archive/**` only, no index, no gate.yml) would
38295
38487
  // get a permanent — demanding an artifact it never asked for.
38296
38488
  docsIndexState: (root) => {
38297
- if (!(0, import_node_fs47.existsSync)((0, import_node_path45.join)(root, DOCS_INDEX_PATH))) return void 0;
38489
+ if (!(0, import_node_fs48.existsSync)((0, import_node_path46.join)(root, DOCS_INDEX_PATH))) return void 0;
38298
38490
  const real = createDocsIndexDeps(root);
38299
38491
  let docs2;
38300
38492
  const listDocs = () => docs2 ??= real.listDocs();
@@ -38303,7 +38495,7 @@ function mmiDoctorDeps(opts = {}) {
38303
38495
  },
38304
38496
  // #4168: working-tree heal — write if drifted, then re-check. Commit remains the operator's step.
38305
38497
  healDocsIndex: (root) => {
38306
- if (!(0, import_node_fs47.existsSync)((0, import_node_path45.join)(root, DOCS_INDEX_PATH))) return { drift: false, docCount: 0 };
38498
+ if (!(0, import_node_fs48.existsSync)((0, import_node_path46.join)(root, DOCS_INDEX_PATH))) return { drift: false, docCount: 0 };
38307
38499
  const real = createDocsIndexDeps(root);
38308
38500
  let docs2;
38309
38501
  const listDocs = () => docs2 ??= real.listDocs();
@@ -38669,19 +38861,19 @@ program2.hook("preAction", async (_thisCommand, actionCommand) => {
38669
38861
  });
38670
38862
  var rules = program2.command("rules").description("org-managed .gitignore delivery");
38671
38863
  rules.command("gitignore").option("--write", "upsert the managed block into .gitignore (default: check only, non-zero exit on drift)").option("--json", "machine-readable output").description("verify (or --write) this repo's org-managed .gitignore block matches the SSOT").action((opts) => {
38672
- const path2 = (0, import_node_path45.join)(process.cwd(), ".gitignore");
38673
- const current = (0, import_node_fs47.existsSync)(path2) ? (0, import_node_fs47.readFileSync)(path2, "utf8") : null;
38864
+ const path2 = (0, import_node_path46.join)(process.cwd(), ".gitignore");
38865
+ const current = (0, import_node_fs48.existsSync)(path2) ? (0, import_node_fs48.readFileSync)(path2, "utf8") : null;
38674
38866
  const plan = planManagedGitignore(current);
38675
38867
  const drift = [...plan.added.map((l) => `+${l}`), ...plan.removed.map((l) => `-${l}`)].join(", ") || "block normalize";
38676
38868
  if (opts.json) {
38677
- if (opts.write && plan.changed) (0, import_node_fs47.writeFileSync)(path2, plan.content, "utf8");
38869
+ if (opts.write && plan.changed) (0, import_node_fs48.writeFileSync)(path2, plan.content, "utf8");
38678
38870
  console.log(JSON.stringify(plan, null, 2));
38679
38871
  if (!opts.write && plan.changed) process.exitCode = 1;
38680
38872
  return;
38681
38873
  }
38682
38874
  if (opts.write) {
38683
38875
  if (plan.changed) {
38684
- (0, import_node_fs47.writeFileSync)(path2, plan.content, "utf8");
38876
+ (0, import_node_fs48.writeFileSync)(path2, plan.content, "utf8");
38685
38877
  console.log(`mmi-cli devops org rules gitignore: updated .gitignore (${drift})`);
38686
38878
  } else {
38687
38879
  console.log("mmi-cli devops org rules gitignore: up to date");
@@ -38840,8 +39032,8 @@ gcCmd.option("--dry-run", "show what would be deleted (default)").option("--appl
38840
39032
  if (!Number.isFinite(limit) || limit < 1) return fail("worktree gc: --limit must be a positive integer");
38841
39033
  let root;
38842
39034
  if (o.root !== void 0) {
38843
- root = (0, import_node_path45.resolve)(o.root);
38844
- if (!(0, import_node_fs47.existsSync)(root) || !(0, import_node_fs47.statSync)(root).isDirectory()) return fail(`worktree gc: --root ${o.root} is not a directory`);
39035
+ root = (0, import_node_path46.resolve)(o.root);
39036
+ if (!(0, import_node_fs48.existsSync)(root) || !(0, import_node_fs48.statSync)(root).isDirectory()) return fail(`worktree gc: --root ${o.root} is not a directory`);
38845
39037
  const gcRepoRoot = (await execFileP2("git", ["rev-parse", "--show-toplevel"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim() || process.cwd();
38846
39038
  if (isPathUnderDirectory2(gcRepoRoot, root)) {
38847
39039
  return fail(`worktree gc: --root ${root} contains this checkout \u2014 name a worktrees root, not the repo or an ancestor of it`);
@@ -38940,7 +39132,7 @@ async function currentWorktreeRemovalContext(command, force) {
38940
39132
  };
38941
39133
  }
38942
39134
  async function unprovenWorktreeReason(wtPath, repoRoot2) {
38943
- if (!(0, import_node_fs47.existsSync)(wtPath)) return `${wtPath} does not exist on disk`;
39135
+ if (!(0, import_node_fs48.existsSync)(wtPath)) return `${wtPath} does not exist on disk`;
38944
39136
  const porcelain = (await execFileP2("git", ["-C", repoRoot2, "worktree", "list", "--porcelain"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout;
38945
39137
  const registered = parseWorktreePorcelainEntries(porcelain);
38946
39138
  if (!registered.length) {
@@ -38970,26 +39162,26 @@ function makeProvisionDeps(worktreeRoot, quiet, log) {
38970
39162
  function acquireWorktreeSetupLock(worktreeRoot) {
38971
39163
  const lockPath = repoRuntimeStatePath(worktreeRoot, "worktree-setup.lock");
38972
39164
  const take = () => {
38973
- const fd = (0, import_node_fs47.openSync)(lockPath, "wx");
39165
+ const fd = (0, import_node_fs48.openSync)(lockPath, "wx");
38974
39166
  try {
38975
- (0, import_node_fs47.writeSync)(fd, String(Date.now()));
39167
+ (0, import_node_fs48.writeSync)(fd, String(Date.now()));
38976
39168
  } finally {
38977
- (0, import_node_fs47.closeSync)(fd);
39169
+ (0, import_node_fs48.closeSync)(fd);
38978
39170
  }
38979
39171
  return () => {
38980
39172
  try {
38981
- (0, import_node_fs47.rmSync)(lockPath, { force: true });
39173
+ (0, import_node_fs48.rmSync)(lockPath, { force: true });
38982
39174
  } catch {
38983
39175
  }
38984
39176
  };
38985
39177
  };
38986
39178
  try {
38987
- (0, import_node_fs47.mkdirSync)((0, import_node_path45.dirname)(lockPath), { recursive: true });
39179
+ (0, import_node_fs48.mkdirSync)((0, import_node_path46.dirname)(lockPath), { recursive: true });
38988
39180
  return take();
38989
39181
  } catch {
38990
39182
  try {
38991
- if (Date.now() - (0, import_node_fs47.statSync)(lockPath).mtimeMs > WORKTREE_SETUP_LOCK_TTL_MS) {
38992
- (0, import_node_fs47.rmSync)(lockPath, { force: true });
39183
+ if (Date.now() - (0, import_node_fs48.statSync)(lockPath).mtimeMs > WORKTREE_SETUP_LOCK_TTL_MS) {
39184
+ (0, import_node_fs48.rmSync)(lockPath, { force: true });
38993
39185
  return take();
38994
39186
  }
38995
39187
  } catch {
@@ -39069,8 +39261,10 @@ withExamples(mutating(
39069
39261
  }
39070
39262
  };
39071
39263
  if (preferRemote && await revParseRef(preferRemote)) base = preferRemote;
39264
+ const resolvedBaseOid = await revParseRef(base);
39265
+ if (!resolvedBaseOid) return fail(`worktree create: could not resolve creation base '${base}' to an immutable commit`);
39072
39266
  if (!o.json) {
39073
- const baseSha = (await revParseRef(base))?.slice(0, 12) ?? "unresolved";
39267
+ const baseSha = resolvedBaseOid.slice(0, 12);
39074
39268
  const localOnly = preferRemote && base !== preferRemote ? ` (no ${preferRemote} ? local ref)` : "";
39075
39269
  console.error(` base ${base} ${baseSha}${localOnly}`);
39076
39270
  }
@@ -39089,23 +39283,45 @@ withExamples(mutating(
39089
39283
  const status = (await execFileP2("git", ["-C", wtPath, "status", "--porcelain"], { timeout: GIT_TIMEOUT_MS })).stdout.trim();
39090
39284
  if (status) return fail(`worktree create: refusing to resume ${wtPath} \u2014 it has uncommitted changes`);
39091
39285
  const head = await revParseRef(`refs/heads/${branch}`);
39092
- const baseOid = await revParseRef(base);
39093
- if (!head || !baseOid) return fail(`worktree create: could not prove '${branch}' and '${base}' before resume`);
39286
+ const baseOid = resolvedBaseOid;
39287
+ if (!head) return fail(`worktree create: could not prove '${branch}' and '${base}' before resume`);
39094
39288
  const canFastForward = await execFileP2(
39095
39289
  "git",
39096
39290
  ["-C", repoRoot2, "merge-base", "--is-ancestor", head, baseOid],
39097
39291
  { timeout: GIT_TIMEOUT_MS }
39098
39292
  // io-census-allow: an unprovable ancestor probe conservatively refuses the resume below rather than fast-forwarding onto unproven history
39099
39293
  ).then(() => true).catch(() => false);
39100
- if (!canFastForward) {
39101
- return fail(`worktree create: refusing to resume '${branch}' \u2014 it has local commits or diverges from ${base}`);
39294
+ if (canFastForward) {
39295
+ await execFileP2("git", ["-C", wtPath, "merge", "--ff-only", base], { timeout: GIT_TIMEOUT_MS });
39296
+ resumed = true;
39297
+ } else {
39298
+ const owner2 = lookupWorktreeOwner(repoRoot2, wtPath);
39299
+ const delivered = await proveExactTreeDelivery({
39300
+ repoRoot: repoRoot2,
39301
+ branch,
39302
+ workerOid: head,
39303
+ creationBaseOid: owner2?.provenance?.creationBaseOid,
39304
+ recordedWorkerBranch: owner2?.provenance?.workerBranch,
39305
+ landedTips: [baseOid]
39306
+ });
39307
+ if (delivered.action !== "settle") {
39308
+ return fail(`worktree create: refusing to resume '${branch}' \u2014 it has local commits or diverges from ${base}; exact-tree delivery proof refused (${describeExactTreeRefusal(delivered)})`);
39309
+ }
39310
+ const repoint = await repointDeliveredWorktreeTransactionally({
39311
+ branch,
39312
+ expectedWorkerOid: head,
39313
+ landedTipOid: baseOid,
39314
+ git: async (args) => (await execFileP2("git", ["-C", wtPath, ...args], { timeout: GIT_TIMEOUT_MS })).stdout
39315
+ });
39316
+ if (repoint.action !== "repointed") {
39317
+ return fail(`worktree create: exact-tree delivery was proven by ${delivered.candidateOid}, but transactional resume refused (${repoint.reason}${repoint.detail ? `: ${repoint.detail}` : ""})`);
39318
+ }
39319
+ resumed = true;
39102
39320
  }
39103
- await execFileP2("git", ["-C", wtPath, "merge", "--ff-only", base], { timeout: GIT_TIMEOUT_MS });
39104
- resumed = true;
39105
39321
  }
39106
39322
  if (!resumed) {
39107
39323
  step = `git worktree add ${wtPath}`;
39108
- const wtPathPreExisted = (0, import_node_fs47.existsSync)(wtPath);
39324
+ const wtPathPreExisted = (0, import_node_fs48.existsSync)(wtPath);
39109
39325
  const partialRemove = worktreeRemoveDeps(async (args) => (await execFileP2("git", args, { timeout: GIT_TIMEOUT_MS })).stdout);
39110
39326
  await withWorktreeAddLock(repoRoot2, () => addWorktreeRobust(wtPath, branch, base, {
39111
39327
  // #4834: `-c core.longpaths=true` rides the add command itself — a Windows worktree path
@@ -39121,7 +39337,7 @@ withExamples(mutating(
39121
39337
  },
39122
39338
  deleteBranch: (b) => execFileP2("git", ["branch", "-D", b], { timeout: GIT_TIMEOUT_MS }).then(() => void 0),
39123
39339
  cleanupPartial: async () => {
39124
- if (wtPathPreExisted || !(0, import_node_fs47.existsSync)(wtPath)) return;
39340
+ if (wtPathPreExisted || !(0, import_node_fs48.existsSync)(wtPath)) return;
39125
39341
  partialRemove.detachReparsePoints(wtPath);
39126
39342
  await execFileP2("git", ["worktree", "remove", "--force", wtPath], { timeout: GIT_TIMEOUT_MS }).catch(() => partialRemove.removeWorktreeDir(wtPath).then(() => void 0));
39127
39343
  await execFileP2("git", ["worktree", "prune"], { timeout: GIT_TIMEOUT_MS }).catch(() => {
@@ -39165,7 +39381,14 @@ withExamples(mutating(
39165
39381
  }
39166
39382
  const createActor = describeActor({ env: process.env, surface: detectSurface(process.env), cwd: process.cwd() });
39167
39383
  const createdAt = (/* @__PURE__ */ new Date()).toISOString();
39168
- const owner = { path: wtPath, branch, createdAt, lastSeenAt: createdAt, actor: createActor };
39384
+ const owner = {
39385
+ path: wtPath,
39386
+ branch,
39387
+ provenance: { creationBaseOid: resolvedBaseOid, workerBranch: branch },
39388
+ createdAt,
39389
+ lastSeenAt: createdAt,
39390
+ actor: createActor
39391
+ };
39169
39392
  recordWorktreeOwner(repoRoot2, owner);
39170
39393
  appendWorktreeEvent(repoRoot2, { action: "created", command: "worktree create", target: wtPath, branch, actor: owner.actor });
39171
39394
  let lease;
@@ -39902,7 +40125,7 @@ project.command("set [owner/repo]").description("upsert project META (idempotent
39902
40125
  if (dupe) return fail(`org project set: KEY "${dupe}" was passed to both --var and --set; --set is an alias of --var, so pass each KEY once`);
39903
40126
  if (o.secretsFile) {
39904
40127
  try {
39905
- vars.push(`secrets=${(0, import_node_fs47.readFileSync)(o.secretsFile, "utf8")}`);
40128
+ vars.push(`secrets=${(0, import_node_fs48.readFileSync)(o.secretsFile, "utf8")}`);
39906
40129
  } catch (e) {
39907
40130
  return fail(`org project set: cannot read --secrets-file ${o.secretsFile}: ${e.message}`);
39908
40131
  }
@@ -40670,11 +40893,11 @@ pr.command("view <number>").description("read a PR as structured JSON (merged st
40670
40893
  }
40671
40894
  });
40672
40895
  async function listCiWorkflowPaths(cwd = process.cwd()) {
40673
- const wfDir = (0, import_node_path45.join)(cwd, ".github", "workflows");
40674
- if (!(0, import_node_fs47.existsSync)(wfDir)) return [];
40675
- return (0, import_node_fs47.readdirSync)(wfDir).filter((name) => /\.(ya?ml)$/i.test(name)).filter((name) => {
40896
+ const wfDir = (0, import_node_path46.join)(cwd, ".github", "workflows");
40897
+ if (!(0, import_node_fs48.existsSync)(wfDir)) return [];
40898
+ return (0, import_node_fs48.readdirSync)(wfDir).filter((name) => /\.(ya?ml)$/i.test(name)).filter((name) => {
40676
40899
  try {
40677
- return workflowReportsPrChecks((0, import_node_fs47.readFileSync)((0, import_node_path45.join)(wfDir, name), "utf8"));
40900
+ return workflowReportsPrChecks((0, import_node_fs48.readFileSync)((0, import_node_path46.join)(wfDir, name), "utf8"));
40678
40901
  } catch {
40679
40902
  return true;
40680
40903
  }
@@ -40726,16 +40949,16 @@ function ciAuditDeps() {
40726
40949
  // gate re-seed step is skipped gracefully rather than failing mid-run.
40727
40950
  readSeedFile: (path2) => {
40728
40951
  if (!root) return null;
40729
- const fullPath = (0, import_node_path45.join)(root, path2);
40730
- return (0, import_node_fs47.existsSync)(fullPath) ? (0, import_node_fs47.readFileSync)(fullPath, "utf8") : null;
40952
+ const fullPath = (0, import_node_path46.join)(root, path2);
40953
+ return (0, import_node_fs48.existsSync)(fullPath) ? (0, import_node_fs48.readFileSync)(fullPath, "utf8") : null;
40731
40954
  }
40732
40955
  };
40733
40956
  }
40734
40957
  function hubRoot() {
40735
- const fromPkg = (0, import_node_path45.join)(__dirname, "..", "..");
40958
+ const fromPkg = (0, import_node_path46.join)(__dirname, "..", "..");
40736
40959
  const marker = "skills/bootstrap/seeds/manifest.json";
40737
- if ((0, import_node_fs47.existsSync)((0, import_node_path45.join)(fromPkg, marker))) return fromPkg;
40738
- if ((0, import_node_fs47.existsSync)((0, import_node_path45.join)(process.cwd(), marker))) return process.cwd();
40960
+ if ((0, import_node_fs48.existsSync)((0, import_node_path46.join)(fromPkg, marker))) return fromPkg;
40961
+ if ((0, import_node_fs48.existsSync)((0, import_node_path46.join)(process.cwd(), marker))) return process.cwd();
40739
40962
  return null;
40740
40963
  }
40741
40964
  async function waitLoopCorePool(label) {
@@ -40938,23 +41161,46 @@ pr.command("land <number>").description("agent merge path (#1440): train probe \
40938
41161
  if (trimmed) {
40939
41162
  try {
40940
41163
  result.cleanup = JSON.parse(trimmed);
40941
- const wt = result.cleanup.worktree;
40942
- if (wt?.status === "deferred") spawnDeferredGcSweep();
41164
+ const childCleanup = result.cleanup;
41165
+ result.cleanupStatus = childCleanup.cleanupStatus === "clean" ? "clean" : "deferred";
41166
+ if (childCleanup.worktree?.status === "deferred" || childCleanup.worktree?.status === "failed") spawnDeferredGcSweep();
40943
41167
  } catch {
40944
41168
  result.cleanupError = "cleanup output was not JSON";
41169
+ result.cleanupStatus = "deferred";
40945
41170
  }
40946
41171
  }
40947
41172
  } catch (e) {
40948
- result.cleanupError = String(e.message || "pr merge cleanup failed");
41173
+ const err = e;
41174
+ const childStdout = (err.stdout ?? "").trim();
41175
+ const childStderr = (err.stderr ?? "").trim().split("\n")[0];
41176
+ let parsed;
41177
+ try {
41178
+ parsed = childStdout ? JSON.parse(childStdout) : void 0;
41179
+ } catch {
41180
+ parsed = void 0;
41181
+ }
41182
+ if (parsed && typeof parsed === "object") {
41183
+ result.cleanup = parsed;
41184
+ const wt = parsed.worktree;
41185
+ if (wt?.status === "deferred" || wt?.status === "failed") spawnDeferredGcSweep();
41186
+ result.cleanupError = childStderr || "post-merge cleanup did not complete";
41187
+ } else {
41188
+ result.cleanupError = childStderr || String(err.message || "pr merge cleanup failed");
41189
+ spawnDeferredGcSweep();
41190
+ }
41191
+ result.cleanupStatus = "deferred";
40949
41192
  }
40950
41193
  }
40951
41194
  if (o.json) printLine(JSON.stringify(result));
40952
41195
  else {
40953
41196
  printLine(`pr land: ${result.status}${result.error ? ` \u2014 ${result.error}` : ""}`);
40954
41197
  for (const line of renderPrLandCleanupLines(result.cleanup)) printLine(line);
40955
- if (result.cleanupError) printLine(`pr land cleanup: ${result.cleanupError}`);
41198
+ if (result.cleanupError) {
41199
+ printLine(`pr land: ${result.status} \u2014 post-merge cleanup DEFERRED (${result.cleanupError})`);
41200
+ printLine(`pr land: sweep the deferred cleanup with: mmi-cli worktree gc sweep-deferred`);
41201
+ }
40956
41202
  }
40957
- if (result.status === "failed" || result.cleanupError) process.exitCode = 1;
41203
+ if (result.status === "failed") process.exitCode = 1;
40958
41204
  });
40959
41205
  jsonParity(pr.command("merge <number>").description("merge a PR (squash by default) and clean up its branch + worktree \u2014 no leftover local branch; on no-ci repos run pr ci-policy / checks-wait first (#1432)").option("--squash", "squash merge (default)").option("--merge", "create a merge commit").option("--rebase", "rebase merge").option("--repo <owner/repo>", "target repo (defaults to the current repo)").option("--auto", "enable auto-merge \u2014 merge once the base-branch policy is satisfied (use for policy-gated repos)").option("--wait", `wait for checks to reach a terminal passing verdict before merging (default budget ${PR_CHECKS_TIMEOUT_MS / 6e4}m)`).option("--preserve-worktree", "keep the local PR worktree/stage/branch for an active multi-issue batch (#1888)").option("--force", "acknowledge and merge past a remaining prunable/severe scratch housekeeping block (advisory kept plans/ never blocks, #3012) or a negated-closing-keyword (#3718) or ambiguous-cross-repo-closing (#4279) refusal")).action(async (number, o) => {
40960
41206
  const method = o.rebase ? "--rebase" : o.merge ? "--merge" : "--squash";
@@ -41043,7 +41289,7 @@ jsonParity(pr.command("merge <number>").description("merge a PR (squash by defau
41043
41289
  }
41044
41290
  if (!repoForPostCleanup) throw e;
41045
41291
  console.warn(`pr merge: gh GraphQL rate-limited \u2014 merging PR #${number} via REST PUT instead (#4588).`);
41046
- const commitMessage = bodyFile ? (0, import_node_fs47.readFileSync)(bodyFile, "utf8") : void 0;
41292
+ const commitMessage = bodyFile ? (0, import_node_fs48.readFileSync)(bodyFile, "utf8") : void 0;
41047
41293
  await defaultGitHubClient().rest("PUT", `repos/${repoForPostCleanup}/pulls/${number}/merge`, {
41048
41294
  body: { merge_method: method.slice(2), ...commitMessage ? { commit_message: commitMessage } : {} },
41049
41295
  timeoutMs: GH_MUTATION_TIMEOUT_MS
@@ -41139,7 +41385,7 @@ jsonParity(pr.command("merge <number>").description("merge a PR (squash by defau
41139
41385
  localCleanup = await cleanupPrMergeLocalBranch(headRef, {
41140
41386
  beforeWorktrees,
41141
41387
  startingPath,
41142
- pathExists: (p) => (0, import_node_fs47.existsSync)(p),
41388
+ pathExists: (p) => (0, import_node_fs48.existsSync)(p),
41143
41389
  execGit: async (args) => (await execFileP2("git", args, { timeout: GIT_TIMEOUT_MS })).stdout,
41144
41390
  teardownWorktreeStage,
41145
41391
  deferredStore,
@@ -41743,12 +41989,12 @@ access.command("audit").description("audit collaborator roles + train-branch pus
41743
41989
  targets = resolution.targets;
41744
41990
  }
41745
41991
  const derivedMatrix = registryProjects ? accessMatrixFromProjects(registryProjects) : {};
41746
- const fileMatrix = (0, import_node_fs47.existsSync)("access-matrix.json") ? loadAccessMatrix((0, import_node_fs47.readFileSync)("access-matrix.json", "utf8")) : {};
41992
+ const fileMatrix = (0, import_node_fs48.existsSync)("access-matrix.json") ? loadAccessMatrix((0, import_node_fs48.readFileSync)("access-matrix.json", "utf8")) : {};
41747
41993
  const matrix = mergeAccessMatrix(fileMatrix, derivedMatrix);
41748
41994
  const derivedContracts = registryProjects ? dataAccessContractsFromProjects(registryProjects) : { consumers: {} };
41749
- const fileContracts = (0, import_node_fs47.existsSync)("data-access-contracts.json") ? loadDataAccessContracts((0, import_node_fs47.readFileSync)("data-access-contracts.json", "utf8")) : { consumers: {} };
41995
+ const fileContracts = (0, import_node_fs48.existsSync)("data-access-contracts.json") ? loadDataAccessContracts((0, import_node_fs48.readFileSync)("data-access-contracts.json", "utf8")) : { consumers: {} };
41750
41996
  const dataAccess = mergeDataAccessContracts(fileContracts, derivedContracts);
41751
- const sanctioned = (0, import_node_fs47.existsSync)("access-matrix.json") ? loadSanctionedAdmins((0, import_node_fs47.readFileSync)("access-matrix.json", "utf8")) : {};
41997
+ const sanctioned = (0, import_node_fs48.existsSync)("access-matrix.json") ? loadSanctionedAdmins((0, import_node_fs48.readFileSync)("access-matrix.json", "utf8")) : {};
41752
41998
  const report = await auditOrgAccess(targets, deps, matrix, dataAccess, sanctioned);
41753
41999
  console.log(o.json ? JSON.stringify(report, null, 2) : renderAccessReport(report));
41754
42000
  if (!report.ok) process.exitCode = 1;
@@ -41780,16 +42026,16 @@ function directoryBytes(path2) {
41780
42026
  let total = 0;
41781
42027
  let entries;
41782
42028
  try {
41783
- entries = (0, import_node_fs47.readdirSync)(path2, { withFileTypes: true });
42029
+ entries = (0, import_node_fs48.readdirSync)(path2, { withFileTypes: true });
41784
42030
  } catch {
41785
42031
  return 0;
41786
42032
  }
41787
42033
  for (const entry of entries) {
41788
- const child2 = (0, import_node_path45.join)(path2, entry.name);
42034
+ const child2 = (0, import_node_path46.join)(path2, entry.name);
41789
42035
  if (entry.isDirectory()) total += directoryBytes(child2);
41790
42036
  else {
41791
42037
  try {
41792
- total += (0, import_node_fs47.statSync)(child2).size;
42038
+ total += (0, import_node_fs48.statSync)(child2).size;
41793
42039
  } catch {
41794
42040
  }
41795
42041
  }
@@ -41797,25 +42043,25 @@ function directoryBytes(path2) {
41797
42043
  return total;
41798
42044
  }
41799
42045
  function listDirEntries(dir) {
41800
- return (0, import_node_fs47.readdirSync)(dir, { withFileTypes: true }).map((d) => ({ name: d.name, isDirectory: d.isDirectory() }));
42046
+ return (0, import_node_fs48.readdirSync)(dir, { withFileTypes: true }).map((d) => ({ name: d.name, isDirectory: d.isDirectory() }));
41801
42047
  }
41802
42048
  function readInstalledPluginRefs(configRoot) {
41803
42049
  const p = installedPluginsPathForConfig(configRoot);
41804
- if (!(0, import_node_fs47.existsSync)(p)) return [];
42050
+ if (!(0, import_node_fs48.existsSync)(p)) return [];
41805
42051
  try {
41806
- return installedPluginPaths((0, import_node_fs47.readFileSync)(p, "utf8"));
42052
+ return installedPluginPaths((0, import_node_fs48.readFileSync)(p, "utf8"));
41807
42053
  } catch {
41808
42054
  return null;
41809
42055
  }
41810
42056
  }
41811
42057
  function pluginCacheFsDeps(configRoot, dirBytes) {
41812
42058
  return {
41813
- exists: (p) => (0, import_node_fs47.existsSync)(p),
41814
- listVersionDirs: (root) => (0, import_node_fs47.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name),
42059
+ exists: (p) => (0, import_node_fs48.existsSync)(p),
42060
+ listVersionDirs: (root) => (0, import_node_fs48.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name),
41815
42061
  dirBytes,
41816
- listStagingDirs: (root) => (0, import_node_fs47.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => {
42062
+ listStagingDirs: (root) => (0, import_node_fs48.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => {
41817
42063
  try {
41818
- return { name: d.name, mtimeMs: newestMtimeMs((0, import_node_path45.join)(root, d.name), listDirEntries, (p) => (0, import_node_fs47.statSync)(p).mtimeMs) };
42064
+ return { name: d.name, mtimeMs: newestMtimeMs((0, import_node_path46.join)(root, d.name), listDirEntries, (p) => (0, import_node_fs48.statSync)(p).mtimeMs) };
41819
42065
  } catch {
41820
42066
  return { name: d.name, mtimeMs: Date.now() };
41821
42067
  }
@@ -41829,10 +42075,10 @@ function stagingApplyFsGuard(configRoot) {
41829
42075
  return {
41830
42076
  referencedPaths: () => readInstalledPluginRefs(configRoot),
41831
42077
  mtimeMs: (name) => {
41832
- const p = (0, import_node_path45.join)(stagingRoot, name);
41833
- if (!(0, import_node_fs47.existsSync)(p)) return null;
42078
+ const p = (0, import_node_path46.join)(stagingRoot, name);
42079
+ if (!(0, import_node_fs48.existsSync)(p)) return null;
41834
42080
  try {
41835
- return newestMtimeMs(p, listDirEntries, (q) => (0, import_node_fs47.statSync)(q).mtimeMs);
42081
+ return newestMtimeMs(p, listDirEntries, (q) => (0, import_node_fs48.statSync)(q).mtimeMs);
41836
42082
  } catch {
41837
42083
  return null;
41838
42084
  }
@@ -41852,13 +42098,13 @@ program2.command("plugin-prune").description(`prune stale cached MMI plugin vers
41852
42098
  return;
41853
42099
  }
41854
42100
  const plan = buildPluginCachePlan(
41855
- (0, import_node_os20.homedir)(),
42101
+ (0, import_node_os21.homedir)(),
41856
42102
  running,
41857
42103
  pluginCacheFsDeps(configRoot, directoryBytes),
41858
42104
  { withBytes: true, configRoot, includeStaging: surface !== "codex" }
41859
42105
  );
41860
42106
  const anythingToDelete = plan.prune.length > 0 || plan.staging.length > 0;
41861
- const result = o.apply && anythingToDelete ? applyPluginCachePlan(plan, (p) => (0, import_node_fs47.rmSync)(p, { recursive: true, force: true }), stagingApplyFsGuard(configRoot)) : void 0;
42107
+ const result = o.apply && anythingToDelete ? applyPluginCachePlan(plan, (p) => (0, import_node_fs48.rmSync)(p, { recursive: true, force: true }), stagingApplyFsGuard(configRoot)) : void 0;
41862
42108
  const warnings = plan.prune.length > 0 ? [CONCURRENT_SESSION_WARNING] : [];
41863
42109
  if (o.json) console.log(JSON.stringify({ ...plan, warnings, applied: result ?? null }));
41864
42110
  else console.log(renderPluginCachePlan(plan, result));