@mutmutco/cli 3.127.0 → 3.129.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 +749 -468
  2. package/package.json +1 -1
package/dist/main.cjs CHANGED
@@ -6744,7 +6744,7 @@ function localTrainSyncBannerLine(result) {
6744
6744
  // src/gc.ts
6745
6745
  var import_node_fs11 = require("node:fs");
6746
6746
  var import_promises = require("node:fs/promises");
6747
- var import_node_path9 = require("node:path");
6747
+ var import_node_path10 = require("node:path");
6748
6748
 
6749
6749
  // src/active-workspace-root.ts
6750
6750
  var import_node_fs9 = require("node:fs");
@@ -6762,6 +6762,12 @@ function isPathUnderDirectory(childPath, parentPath, platform2 = process.platfor
6762
6762
  if (child2 === parent) return true;
6763
6763
  return child2.startsWith(`${parent}/`);
6764
6764
  }
6765
+ function isCursorAgentHost(env = process.env) {
6766
+ return env.CURSOR_AGENT === "1" || Boolean(env.CURSOR_EXTENSION_HOST_ROLE?.trim()) || Boolean(env.AGENT_TRANSCRIPTS?.trim());
6767
+ }
6768
+ function unresolvedWorkspaceRefusalMessage() {
6769
+ return "refusing to remove a worktree: Cursor agent host cannot resolve the active workspace root. Open the primary checkout in Cursor first (keep the workspace root on the primary; edit the worktree without move_agent_to_root), or set MMI_ACTIVE_WORKSPACE_ROOT to the primary path, then retry `mmi-cli worktree gc sweep-deferred` / `worktree gc --apply` / `worktree land --apply`.";
6770
+ }
6765
6771
  function normalizeActiveWorkspaceRoot(value, opts = {}) {
6766
6772
  const raw = value?.trim();
6767
6773
  if (!raw) return void 0;
@@ -6779,8 +6785,13 @@ function removalTouchesActiveWorkspace(targetPath, activeWorkspaceRoot, platform
6779
6785
  function activeWorkspaceRefusalMessage(targetPath, activeWorkspaceRoot) {
6780
6786
  return `refusing to remove active Cursor workspace ${activeWorkspaceRoot} (target ${targetPath}). Open the primary checkout in Cursor first, then retry \`mmi-cli worktree gc sweep-deferred\` / \`worktree gc --apply\`.`;
6781
6787
  }
6782
- function decideActiveWorkspaceGuard(targetPath, activeWorkspaceRoot, platform2 = process.platform) {
6783
- if (!activeWorkspaceRoot) return { action: "proceed" };
6788
+ function decideActiveWorkspaceGuard(targetPath, activeWorkspaceRoot, platform2 = process.platform, opts = {}) {
6789
+ if (!activeWorkspaceRoot) {
6790
+ if (opts.cursorAgentHost) {
6791
+ return { action: "refuse", reason: "unresolved-workspace", message: unresolvedWorkspaceRefusalMessage() };
6792
+ }
6793
+ return { action: "proceed" };
6794
+ }
6784
6795
  if (!removalTouchesActiveWorkspace(targetPath, activeWorkspaceRoot, platform2)) {
6785
6796
  return { action: "proceed" };
6786
6797
  }
@@ -6882,10 +6893,137 @@ function resolveActiveWorkspaceRoot(deps = {}) {
6882
6893
  return resolveCursorAgentWorkspaceRoot(deps);
6883
6894
  }
6884
6895
 
6896
+ // src/estate-hygiene.ts
6897
+ var import_node_path8 = require("node:path");
6898
+ function win32LongPath(p, platform2 = process.platform) {
6899
+ if (platform2 !== "win32") return p;
6900
+ if (p.startsWith("\\\\?\\")) return p;
6901
+ if (p.startsWith("\\\\")) return `\\\\?\\UNC\\${p.slice(2)}`;
6902
+ return `\\\\?\\${p}`;
6903
+ }
6904
+ function normalizeGithubRemote(url) {
6905
+ const raw = url.trim();
6906
+ if (!raw) return void 0;
6907
+ const ssh = raw.match(/^git@github\.com:([^/]+)\/(.+?)(?:\.git)?$/i);
6908
+ if (ssh) return `${ssh[1]}/${ssh[2]}`.toLowerCase();
6909
+ const https = raw.match(/^https?:\/\/github\.com\/([^/]+)\/(.+?)(?:\.git)?$/i);
6910
+ if (https) return `${https[1]}/${https[2]}`.toLowerCase();
6911
+ return void 0;
6912
+ }
6913
+ function remotesOverlap(a, b) {
6914
+ const left = new Set(a.map(normalizeGithubRemote).filter((x) => Boolean(x)));
6915
+ if (!left.size) return false;
6916
+ return b.some((url) => {
6917
+ const key = normalizeGithubRemote(url);
6918
+ return Boolean(key && left.has(key));
6919
+ });
6920
+ }
6921
+ function worktreesRootOf(primaryCheckout) {
6922
+ return (0, import_node_path8.join)((0, import_node_path8.dirname)(primaryCheckout), "mmi-worktrees", (0, import_node_path8.basename)(primaryCheckout));
6923
+ }
6924
+ function helperWorktreeRoots(primaryCheckout) {
6925
+ return [
6926
+ (0, import_node_path8.join)(primaryCheckout, ".claude", "worktrees"),
6927
+ (0, import_node_path8.join)(primaryCheckout, ".worktrees")
6928
+ ];
6929
+ }
6930
+ function pathProvesRepoContainerOwnership(dir, repoContainer, platform2 = process.platform) {
6931
+ const norm = (p) => {
6932
+ const unified = p.replace(/\\/g, "/").replace(/\/+$/, "");
6933
+ return platform2 === "win32" || platform2 === "darwin" ? unified.toLowerCase() : unified;
6934
+ };
6935
+ return norm((0, import_node_path8.dirname)(dir)) === norm(repoContainer);
6936
+ }
6937
+ function worktreesRootFromLeaseRef(ref) {
6938
+ const unified = ref.replace(/\\/g, "/");
6939
+ const marker = "/mmi-worktrees/";
6940
+ const idx = unified.toLowerCase().lastIndexOf(marker);
6941
+ if (idx < 0) return void 0;
6942
+ const after = unified.slice(idx + marker.length);
6943
+ const repo = after.split("/").filter(Boolean)[0];
6944
+ if (!repo) return void 0;
6945
+ return unified.slice(0, idx + marker.length + repo.length);
6946
+ }
6947
+ function classifyEstateAudit(input) {
6948
+ const otherPrimaries = input.otherCheckouts.filter((c) => remotesOverlap(input.remoteUrls, c.remoteUrls)).map((c) => c.path);
6949
+ const thisRoot = input.thisWorktreesRoot.replace(/\\/g, "/").replace(/\/+$/, "").toLowerCase();
6950
+ const foreignLeaseRoots = [...new Set(
6951
+ (input.leaseRefs ?? []).map(worktreesRootFromLeaseRef).filter((root) => Boolean(root)).filter((root) => root.replace(/\\/g, "/").replace(/\/+$/, "").toLowerCase() !== thisRoot)
6952
+ )];
6953
+ const reasons = [];
6954
+ if (otherPrimaries.length) {
6955
+ reasons.push(
6956
+ `another primary checkout of the same remotes exists: ${otherPrimaries.join(", ")}`
6957
+ );
6958
+ }
6959
+ if (foreignLeaseRoots.length) {
6960
+ reasons.push(
6961
+ `jerv lease ledger points at another worktrees root: ${foreignLeaseRoots.join(", ")}`
6962
+ );
6963
+ }
6964
+ return {
6965
+ auditedClone: input.auditedClone,
6966
+ otherPrimaries,
6967
+ foreignLeaseRoots,
6968
+ blocksGreen: reasons.length > 0,
6969
+ reasons
6970
+ };
6971
+ }
6972
+ function formatEstateAuditLines(audit) {
6973
+ const lines = [`audited clone: ${audit.auditedClone}`];
6974
+ if (!audit.blocksGreen) return lines;
6975
+ lines.push('refusing a clean "no leaks" report \u2014 this clone is not the whole estate:');
6976
+ for (const reason of audit.reasons) lines.push(` ${reason}`);
6977
+ lines.push(" fix: run doctor / worktree list --stale / worktree gc from the canonical primary (E:\\AI Projects\\Mutatis Mutandis\\\u2026), not a second clone");
6978
+ return lines;
6979
+ }
6980
+ function classifyOriginLeftovers(input) {
6981
+ const local = new Set(input.localBranches ?? []);
6982
+ const leftovers = [];
6983
+ for (const branch of input.remoteBranches) {
6984
+ const name = branch.replace(/^origin\//, "").trim();
6985
+ if (!name || name === "HEAD" || input.protectedBranches.has(name)) continue;
6986
+ if (input.openPrBranches.has(name)) {
6987
+ leftovers.push({
6988
+ branch: name,
6989
+ kind: "open-pr",
6990
+ autoReap: false,
6991
+ detail: `origin/${name} has an open PR \u2014 gc will not delete it`
6992
+ });
6993
+ continue;
6994
+ }
6995
+ if (input.mergedPrBranches.has(name)) {
6996
+ leftovers.push({
6997
+ branch: name,
6998
+ kind: "merged-missed",
6999
+ autoReap: true,
7000
+ detail: local.has(name) ? `origin/${name} is merged; this clone still has the head` : `origin/${name} is merged; this clone has no local branch (missed reap)`
7001
+ });
7002
+ continue;
7003
+ }
7004
+ if (input.closedUnmergedBranches.has(name)) {
7005
+ leftovers.push({
7006
+ branch: name,
7007
+ kind: "closed-not-merged",
7008
+ autoReap: Boolean(input.trainOnly),
7009
+ detail: `origin/${name} is closed-not-merged \u2014 gc will not auto-delete it${input.trainOnly ? " unless --train-only --apply" : ""}`
7010
+ });
7011
+ continue;
7012
+ }
7013
+ leftovers.push({
7014
+ branch: name,
7015
+ kind: local.has(name) ? "no-pr" : "other-clone",
7016
+ autoReap: Boolean(input.trainOnly),
7017
+ detail: local.has(name) ? `origin/${name} has no PR \u2014 gc will not auto-delete it` : `origin/${name} is an other-clone leftover with no PR this clone can see`
7018
+ });
7019
+ }
7020
+ return leftovers;
7021
+ }
7022
+
6885
7023
  // src/worktree-ownership.ts
6886
7024
  var import_node_fs10 = require("node:fs");
6887
7025
  var import_node_os4 = require("node:os");
6888
- var import_node_path8 = require("node:path");
7026
+ var import_node_path9 = require("node:path");
6889
7027
  var OWNERS_FILE = "worktree-owners.json";
6890
7028
  var EVENTS_FILE = "worktree-events.jsonl";
6891
7029
  var WORKTREE_ACTIVITY_WINDOW_MS = 30 * 6e4;
@@ -6990,7 +7128,7 @@ function decideWorktreeRemoval(input) {
6990
7128
  }
6991
7129
  function readFreshWorktreeLease(path2, now) {
6992
7130
  try {
6993
- const candidate = JSON.parse((0, import_node_fs10.readFileSync)((0, import_node_path8.join)(path2, WORKTREE_LEASE_MARKER), "utf8"));
7131
+ const candidate = JSON.parse((0, import_node_fs10.readFileSync)((0, import_node_path9.join)(path2, WORKTREE_LEASE_MARKER), "utf8"));
6994
7132
  if (!candidate || typeof candidate !== "object" || Array.isArray(candidate)) return void 0;
6995
7133
  const lease = candidate;
6996
7134
  if (lease.kind !== "worktree" || lease.state !== "active" || typeof lease.agent !== "string" || !lease.agent.trim() || typeof lease.ref !== "string" || !sameWorktreePath(lease.ref, path2) || typeof lease.createdAt !== "string" || typeof lease.ttlHours !== "number" || !Number.isFinite(lease.ttlHours) || lease.ttlHours <= 0) return void 0;
@@ -7017,7 +7155,7 @@ function readOwners(primaryRoot) {
7017
7155
  function writeOwners(primaryRoot, entries) {
7018
7156
  try {
7019
7157
  const path2 = worktreeOwnersPath(primaryRoot);
7020
- (0, import_node_fs10.mkdirSync)((0, import_node_path8.dirname)(path2), { recursive: true });
7158
+ (0, import_node_fs10.mkdirSync)((0, import_node_path9.dirname)(path2), { recursive: true });
7021
7159
  (0, import_node_fs10.writeFileSync)(path2, serializeWorktreeOwners(entries), "utf8");
7022
7160
  } catch {
7023
7161
  }
@@ -7053,7 +7191,7 @@ function dropWorktreeOwner(primaryRoot, path2, expectedCreatedAt) {
7053
7191
  function appendWorktreeEvent(primaryRoot, event) {
7054
7192
  try {
7055
7193
  const path2 = worktreeEventsPath(primaryRoot);
7056
- (0, import_node_fs10.mkdirSync)((0, import_node_path8.dirname)(path2), { recursive: true });
7194
+ (0, import_node_fs10.mkdirSync)((0, import_node_path9.dirname)(path2), { recursive: true });
7057
7195
  (0, import_node_fs10.appendFileSync)(path2, `${JSON.stringify({ at: event.at ?? (/* @__PURE__ */ new Date()).toISOString(), ...event })}
7058
7196
  `, "utf8");
7059
7197
  } catch {
@@ -7132,7 +7270,7 @@ function archiveWorktreeJervArtifacts(args, deps = {}) {
7132
7270
  const resolveRoot = deps.resolveArchiveRoot ?? repoRuntimeStatePath;
7133
7271
  if (!args.primaryRoot?.trim()) return { status: "skipped", reason: "missing-primary-root" };
7134
7272
  if (!args.worktreePath?.trim()) return { status: "skipped", reason: "missing-worktree-path" };
7135
- const source = (0, import_node_path9.join)(args.worktreePath, ".jerv");
7273
+ const source = (0, import_node_path10.join)(args.worktreePath, ".jerv");
7136
7274
  if (!exists(source)) return { status: "absent" };
7137
7275
  if (!isDirectory(source)) return { status: "skipped", reason: "jerv-not-a-directory" };
7138
7276
  const runScope = resolveJervArtifactRunScope(env);
@@ -7140,7 +7278,7 @@ function archiveWorktreeJervArtifacts(args, deps = {}) {
7140
7278
  const stamp = now().toISOString().replace(/[:.]/g, "-");
7141
7279
  const dest = resolveRoot(args.primaryRoot, "jerv-artifacts", runScope, branchSlug, stamp, ".jerv");
7142
7280
  try {
7143
- mkdirp((0, import_node_path9.dirname)(dest));
7281
+ mkdirp((0, import_node_path10.dirname)(dest));
7144
7282
  copyDir(source, dest);
7145
7283
  if (!exists(dest)) return { status: "failed", error: `archive write left no directory at ${dest}` };
7146
7284
  return { status: "archived", path: dest, runScope };
@@ -7294,7 +7432,9 @@ async function sweepDeferredWorktrees(store, deps, removalContext) {
7294
7432
  const owner = removalContext ? lookupWorktreeOwner(removalContext.primaryRoot, entry.path) : void 0;
7295
7433
  if (removalContext) {
7296
7434
  const activeRoot = removalContext.activeWorkspaceRoot ?? resolveActiveWorkspaceRoot();
7297
- const activeGuard = decideActiveWorkspaceGuard(entry.path, activeRoot);
7435
+ const activeGuard = decideActiveWorkspaceGuard(entry.path, activeRoot, process.platform, {
7436
+ cursorAgentHost: removalContext.cursorAgentHost ?? false
7437
+ });
7298
7438
  if (activeGuard.action === "refuse") {
7299
7439
  stillDeferred.push({ ...entry, reason: "active-workspace" });
7300
7440
  recordWorktreeRemoval(removalContext.primaryRoot, {
@@ -7639,23 +7779,23 @@ function resolveSafeSiblingWorktreeCleanupTarget(worktreePath, siblingRoots, dep
7639
7779
  return { ok: false, reason: reasons.join("; ") || "no worktrees root to check against" };
7640
7780
  }
7641
7781
  function siblingMmiWorktreesRoot(repoRoot2) {
7642
- const parent = (0, import_node_path9.dirname)(repoRoot2);
7643
- if ((0, import_node_path9.basename)(parent).toLowerCase() === "mmi-worktrees") return parent;
7644
- const grandparent = (0, import_node_path9.dirname)(parent);
7645
- if ((0, import_node_path9.basename)(grandparent).toLowerCase() === "mmi-worktrees") return grandparent;
7646
- return (0, import_node_path9.join)(parent, "mmi-worktrees");
7782
+ const parent = (0, import_node_path10.dirname)(repoRoot2);
7783
+ if ((0, import_node_path10.basename)(parent).toLowerCase() === "mmi-worktrees") return parent;
7784
+ const grandparent = (0, import_node_path10.dirname)(parent);
7785
+ if ((0, import_node_path10.basename)(grandparent).toLowerCase() === "mmi-worktrees") return grandparent;
7786
+ return (0, import_node_path10.join)(parent, "mmi-worktrees");
7647
7787
  }
7648
7788
  function agentWorktreesRoot(repoRoot2) {
7649
- return (0, import_node_path9.join)(repoRoot2, ".claude", "worktrees");
7789
+ return (0, import_node_path10.join)(repoRoot2, ".claude", "worktrees");
7650
7790
  }
7651
7791
  function worktreeScanDirs(root, repoRoot2, listDirs, isRepoCheckout) {
7652
- const projectsDir = (0, import_node_path9.dirname)(root);
7653
- const ownName = (0, import_node_path9.basename)(repoRoot2).toLowerCase();
7792
+ const projectsDir = (0, import_node_path10.dirname)(root);
7793
+ const ownName = (0, import_node_path10.basename)(repoRoot2).toLowerCase();
7654
7794
  const flat = [];
7655
7795
  let ownContainer = null;
7656
7796
  for (const dir of listDirs(root)) {
7657
- const name = (0, import_node_path9.basename)(dir);
7658
- if (isRepoCheckout((0, import_node_path9.join)(projectsDir, name))) {
7797
+ const name = (0, import_node_path10.basename)(dir);
7798
+ if (isRepoCheckout((0, import_node_path10.join)(projectsDir, name))) {
7659
7799
  if (name.toLowerCase() === ownName) ownContainer = dir;
7660
7800
  continue;
7661
7801
  }
@@ -7664,9 +7804,9 @@ function worktreeScanDirs(root, repoRoot2, listDirs, isRepoCheckout) {
7664
7804
  return ownContainer ? [...flat, ...listDirs(ownContainer)] : flat;
7665
7805
  }
7666
7806
  function explicitRepoWorktreesRoot(root, repoRoot2, rootDirs) {
7667
- const repoName2 = (0, import_node_path9.basename)(repoRoot2);
7807
+ const repoName2 = (0, import_node_path10.basename)(repoRoot2);
7668
7808
  const repoDir = rootDirs.find((name) => name.toLowerCase() === repoName2.toLowerCase());
7669
- return repoDir ? (0, import_node_path9.join)(root, repoDir) : root;
7809
+ return repoDir ? (0, import_node_path10.join)(root, repoDir) : root;
7670
7810
  }
7671
7811
  function classifySiblingWorktreeDir(entry) {
7672
7812
  if (!entry.ownedByCurrentRepo) {
@@ -7914,7 +8054,33 @@ function buildGcPlan(inputs) {
7914
8054
  const state = closedState(prSet);
7915
8055
  return state ? { ref, branch, prState: state.state, prNumbers: state.numbers } : null;
7916
8056
  }).filter((r) => Boolean(r));
7917
- return { branches, trackingRefs, worktreeDirs, skippedWorktreeDirs, skipped };
8057
+ const originLeftovers = classifyOriginLeftovers({
8058
+ remoteBranches: inputs.originBranches ?? [],
8059
+ localBranches: inputs.localBranches,
8060
+ protectedBranches,
8061
+ openPrBranches: new Set(
8062
+ [...prs.entries()].filter(([, set]) => set.some((pr2) => pr2.state === "OPEN")).map(([b]) => b)
8063
+ ),
8064
+ mergedPrBranches: new Set(
8065
+ [...prs.entries()].filter(([, set]) => set.some((pr2) => pr2.state === "MERGED")).map(([b]) => b)
8066
+ ),
8067
+ closedUnmergedBranches: new Set(
8068
+ [...prs.entries()].filter(([, set]) => set.some((pr2) => pr2.state === "CLOSED") && !set.some((pr2) => pr2.state === "MERGED")).map(([b]) => b)
8069
+ ),
8070
+ trainOnly: inputs.trainOnly
8071
+ });
8072
+ const plannedBranches = new Set(branches.map((b) => b.branch));
8073
+ const reapOriginHeads = originLeftovers.filter((l) => l.autoReap && !plannedBranches.has(l.branch)).map((l) => {
8074
+ const prSet = prs.get(l.branch);
8075
+ const state = closedState(prSet);
8076
+ return {
8077
+ branch: l.branch,
8078
+ prState: state?.state ?? "MERGED",
8079
+ prNumbers: state?.numbers ?? [],
8080
+ ...state?.headOids.length ? { reviewedHeadOids: state.headOids } : {}
8081
+ };
8082
+ });
8083
+ return { branches, trackingRefs, worktreeDirs, skippedWorktreeDirs, skipped, originLeftovers, reapOriginHeads };
7918
8084
  }
7919
8085
  function parseRemotePruneDryRun(stdout) {
7920
8086
  const refs = [];
@@ -8229,7 +8395,9 @@ async function cleanupPrMergeLocalBranch(branch, options) {
8229
8395
  report.worktree = { path: wtPath, status: "not-attempted", reason: "main-worktree" };
8230
8396
  } else if (wtPath) {
8231
8397
  const activeRoot = options.removalContext?.activeWorkspaceRoot ?? resolveActiveWorkspaceRoot();
8232
- const activeGuard = decideActiveWorkspaceGuard(wtPath, activeRoot);
8398
+ const activeGuard = decideActiveWorkspaceGuard(wtPath, activeRoot, process.platform, {
8399
+ cursorAgentHost: options.removalContext?.cursorAgentHost ?? false
8400
+ });
8233
8401
  if (activeGuard.action === "refuse") {
8234
8402
  if (options.deferredStore) {
8235
8403
  try {
@@ -8463,9 +8631,13 @@ async function cleanupPrMergeLocalBranch(branch, options) {
8463
8631
  if (wtPath) await git2(["worktree", "prune"]).catch(() => "");
8464
8632
  return report;
8465
8633
  }
8466
- function formatGcPlan(plan, apply) {
8634
+ function formatGcPlan(plan, apply, auditClone) {
8467
8635
  const lines = [`mmi-cli worktree gc: ${apply ? "apply" : "dry-run"}`];
8468
- if (!plan.branches.length && !plan.trackingRefs.length && !plan.worktreeDirs.length) lines.push("nothing to clean");
8636
+ if (auditClone) lines.push(`audited clone: ${auditClone}`);
8637
+ const hasOriginNames = Boolean(plan.originLeftovers?.length);
8638
+ if (!plan.branches.length && !plan.trackingRefs.length && !plan.worktreeDirs.length && !plan.reapOriginHeads?.length) {
8639
+ lines.push(hasOriginNames ? "nothing this clone will auto-delete" : "nothing to clean");
8640
+ }
8469
8641
  if (plan.branches.length) {
8470
8642
  lines.push("local branches:");
8471
8643
  for (const b of plan.branches) {
@@ -8507,6 +8679,12 @@ function formatGcPlan(plan, apply) {
8507
8679
  lines.push(` - ${s.path}: ${s.reason}${s.detail ? ` (${s.detail})` : ""}`);
8508
8680
  }
8509
8681
  }
8682
+ if (plan.originLeftovers?.length) {
8683
+ lines.push("origin leftovers gc will not silently delete (use --train-only for closed-not-merged / no-PR):");
8684
+ for (const leftover of plan.originLeftovers) {
8685
+ lines.push(` - ${leftover.branch}: ${leftover.kind}${leftover.autoReap ? " (will reap)" : ""} \u2014 ${leftover.detail}`);
8686
+ }
8687
+ }
8510
8688
  if (!apply && (plan.branches.length || plan.trackingRefs.length || plan.worktreeDirs.length)) lines.push("rerun with --apply to delete only the listed local, remote, tracking, and directory items");
8511
8689
  return lines.join("\n");
8512
8690
  }
@@ -8592,7 +8770,7 @@ async function gatherStaleWorktreeWarning(gitRun = defaultGitRun) {
8592
8770
 
8593
8771
  // src/released-version-cache.ts
8594
8772
  var import_node_fs12 = require("node:fs");
8595
- var import_node_path10 = require("node:path");
8773
+ var import_node_path11 = require("node:path");
8596
8774
 
8597
8775
  // src/version-lag.ts
8598
8776
  var VERSION_LABEL = "installed plugin/adapter cache freshness";
@@ -8688,7 +8866,7 @@ function versionAutoUpdateAction(report, releasedSource) {
8688
8866
  // src/released-version-cache.ts
8689
8867
  var RELEASED_VERSION_CACHE_MS = 24 * 36e5;
8690
8868
  function releasedVersionCachePath(runtimeRoot) {
8691
- return (0, import_node_path10.join)(runtimeRoot, "head-ts", ".released-version");
8869
+ return (0, import_node_path11.join)(runtimeRoot, "head-ts", ".released-version");
8692
8870
  }
8693
8871
  function readReleasedVersionCache(cachePath, now = Date.now(), read = import_node_fs12.readFileSync, currentVersion = resolveClientVersion()) {
8694
8872
  let parsed;
@@ -8708,7 +8886,7 @@ function readReleasedVersionCache(cachePath, now = Date.now(), read = import_nod
8708
8886
  }
8709
8887
  function writeReleasedVersionCache(cachePath, version, now = Date.now()) {
8710
8888
  try {
8711
- (0, import_node_fs12.mkdirSync)((0, import_node_path10.dirname)(cachePath), { recursive: true });
8889
+ (0, import_node_fs12.mkdirSync)((0, import_node_path11.dirname)(cachePath), { recursive: true });
8712
8890
  (0, import_node_fs12.writeFileSync)(cachePath, JSON.stringify({ version, at: now }), "utf8");
8713
8891
  } catch {
8714
8892
  }
@@ -8723,10 +8901,10 @@ function cachedReadNote(cachedAt, now = Date.now()) {
8723
8901
 
8724
8902
  // src/schedules-drift-cache.ts
8725
8903
  var import_node_fs13 = require("node:fs");
8726
- var import_node_path11 = require("node:path");
8904
+ var import_node_path12 = require("node:path");
8727
8905
  var SCHEDULES_DRIFT_CACHE_MS = 6 * 36e5;
8728
8906
  function schedulesDriftCachePath(runtimeRoot) {
8729
- return (0, import_node_path11.join)(runtimeRoot, "head-ts", ".schedules-drift");
8907
+ return (0, import_node_path12.join)(runtimeRoot, "head-ts", ".schedules-drift");
8730
8908
  }
8731
8909
  function readSchedulesDriftCache(cachePath, now = Date.now(), read = import_node_fs13.readFileSync) {
8732
8910
  let parsed;
@@ -8745,7 +8923,7 @@ function readSchedulesDriftCache(cachePath, now = Date.now(), read = import_node
8745
8923
  }
8746
8924
  function writeSchedulesDriftCache(cachePath, driftLines, now = Date.now()) {
8747
8925
  try {
8748
- (0, import_node_fs13.mkdirSync)((0, import_node_path11.dirname)(cachePath), { recursive: true });
8926
+ (0, import_node_fs13.mkdirSync)((0, import_node_path12.dirname)(cachePath), { recursive: true });
8749
8927
  (0, import_node_fs13.writeFileSync)(cachePath, JSON.stringify({ driftLines, at: now }), "utf8");
8750
8928
  } catch {
8751
8929
  }
@@ -8901,7 +9079,7 @@ function resolveCatalogRef(probe) {
8901
9079
  // src/plugin-guard-io.ts
8902
9080
  var import_node_fs14 = require("node:fs");
8903
9081
  var import_node_child_process6 = require("node:child_process");
8904
- var import_node_path12 = require("node:path");
9082
+ var import_node_path13 = require("node:path");
8905
9083
  var import_node_os5 = require("node:os");
8906
9084
  var import_proper_lockfile = __toESM(require_proper_lockfile(), 1);
8907
9085
 
@@ -9204,17 +9382,17 @@ function runHostBin(bin, args, opts) {
9204
9382
  return step ? execFileHard(file, argv, { ...shared, step }) : execFileP2(file, argv, shared);
9205
9383
  }
9206
9384
  function surfaceConfigRoot(surface, env = process.env, home = (0, import_node_os5.homedir)()) {
9207
- if (surface === "codex") return env.CODEX_HOME?.trim() || (0, import_node_path12.join)(home, ".codex");
9208
- if (surface === "kimi") return env.KIMI_CODE_HOME?.trim() || (0, import_node_path12.join)(home, ".kimi-code");
9209
- if (surface === "kilo") return env.KILO_CONFIG_DIR?.trim() || (0, import_node_path12.join)(home, ".config", "kilo");
9210
- if (surface === "cursor") return (0, import_node_path12.join)(home, ".cursor");
9385
+ if (surface === "codex") return env.CODEX_HOME?.trim() || (0, import_node_path13.join)(home, ".codex");
9386
+ if (surface === "kimi") return env.KIMI_CODE_HOME?.trim() || (0, import_node_path13.join)(home, ".kimi-code");
9387
+ if (surface === "kilo") return env.KILO_CONFIG_DIR?.trim() || (0, import_node_path13.join)(home, ".config", "kilo");
9388
+ if (surface === "cursor") return (0, import_node_path13.join)(home, ".cursor");
9211
9389
  if (surface === "jervcode") {
9212
- return env.JERVCODE_CODING_AGENT_DIR?.trim() || env.PI_CODING_AGENT_DIR?.trim() || (0, import_node_path12.join)(home, ".jerv", "agent");
9390
+ return env.JERVCODE_CODING_AGENT_DIR?.trim() || env.PI_CODING_AGENT_DIR?.trim() || (0, import_node_path13.join)(home, ".jerv", "agent");
9213
9391
  }
9214
- return (0, import_node_path12.join)(home, ".claude");
9392
+ return (0, import_node_path13.join)(home, ".claude");
9215
9393
  }
9216
9394
  var installedPluginsPath = (surface = detectSurface(process.env)) => {
9217
- return (0, import_node_path12.join)(surfaceConfigRoot(surface), "plugins", "installed_plugins.json");
9395
+ return (0, import_node_path13.join)(surfaceConfigRoot(surface), "plugins", "installed_plugins.json");
9218
9396
  };
9219
9397
  function readInstalledPlugins(surface = detectSurface(process.env)) {
9220
9398
  try {
@@ -9227,15 +9405,15 @@ function marketplaceCloneCandidates(surface, home, env = process.env) {
9227
9405
  if (surface === "codex") {
9228
9406
  const root = surfaceConfigRoot(surface, env, home);
9229
9407
  return [
9230
- (0, import_node_path12.join)(root, ".tmp", "marketplaces", CODEX_MARKETPLACE),
9231
- (0, import_node_path12.join)(root, "plugins", "marketplaces", CODEX_MARKETPLACE)
9408
+ (0, import_node_path13.join)(root, ".tmp", "marketplaces", CODEX_MARKETPLACE),
9409
+ (0, import_node_path13.join)(root, "plugins", "marketplaces", CODEX_MARKETPLACE)
9232
9410
  ];
9233
9411
  }
9234
9412
  if (surface === "kimi") return [];
9235
9413
  if (surface === "kilo") return [];
9236
9414
  if (surface === "cursor") return [];
9237
9415
  if (surface === "jervcode") return [];
9238
- return [(0, import_node_path12.join)(home, ".claude", "plugins", "marketplaces", "mutmutco")];
9416
+ return [(0, import_node_path13.join)(home, ".claude", "plugins", "marketplaces", "mutmutco")];
9239
9417
  }
9240
9418
  function marketplaceClonePresent(surface, home, exists = import_node_fs14.existsSync, env = process.env) {
9241
9419
  return marketplaceCloneCandidates(surface, home, env).some(exists);
@@ -9286,11 +9464,11 @@ function codexHookTrustState(status = codexPluginStatus()) {
9286
9464
  return { applicable: false, trusted: false, trustedCount: 0, requiredCount: 0 };
9287
9465
  }
9288
9466
  const root = surfaceConfigRoot("codex");
9289
- const hooksPath = (0, import_node_path12.join)(root, "plugins", "cache", CODEX_MARKETPLACE, "mmi", status.version, "hooks", "codex-hooks.json");
9467
+ const hooksPath = (0, import_node_path13.join)(root, "plugins", "cache", CODEX_MARKETPLACE, "mmi", status.version, "hooks", "codex-hooks.json");
9290
9468
  const requiredCount = countCodexHookCommands(hooksPath);
9291
9469
  let config = "";
9292
9470
  try {
9293
- config = (0, import_node_fs14.readFileSync)((0, import_node_path12.join)(root, "config.toml"), "utf8");
9471
+ config = (0, import_node_fs14.readFileSync)((0, import_node_path13.join)(root, "config.toml"), "utf8");
9294
9472
  } catch {
9295
9473
  return { applicable: true, trusted: false, trustedCount: 0, requiredCount };
9296
9474
  }
@@ -9317,7 +9495,7 @@ var NPM_INSTALL_TIMEOUT_MS = 12e4;
9317
9495
  var CLI_VERSION_PROBE_TIMEOUT_MS = 3e4;
9318
9496
  function resolveNpmSpawn(args) {
9319
9497
  if (!isWin) return { file: "npm", args };
9320
- const cli = (0, import_node_path12.join)((0, import_node_path12.dirname)(process.execPath), "node_modules", "npm", "bin", "npm-cli.js");
9498
+ const cli = (0, import_node_path13.join)((0, import_node_path13.dirname)(process.execPath), "node_modules", "npm", "bin", "npm-cli.js");
9321
9499
  if ((0, import_node_fs14.existsSync)(cli)) return { file: process.execPath, args: [cli, ...args] };
9322
9500
  return { file: "cmd.exe", args: ["/c", "npm", ...args] };
9323
9501
  }
@@ -9346,9 +9524,9 @@ async function npmSelfUpdateCli(target, onStep, deps = {}) {
9346
9524
  }
9347
9525
  function kiloConfigListsPlugin(configRoot, home = (0, import_node_os5.homedir)(), read = (p) => (0, import_node_fs14.readFileSync)(p, "utf8"), exists = import_node_fs14.existsSync) {
9348
9526
  const candidates = ["kilo.json", "kilo.jsonc", "opencode.json", "opencode.jsonc", "config.json"];
9349
- for (const dir of [configRoot, (0, import_node_path12.join)(home, ".kilo")]) {
9527
+ for (const dir of [configRoot, (0, import_node_path13.join)(home, ".kilo")]) {
9350
9528
  for (const file of candidates) {
9351
- const path2 = (0, import_node_path12.join)(dir, file);
9529
+ const path2 = (0, import_node_path13.join)(dir, file);
9352
9530
  if (!exists(path2)) continue;
9353
9531
  try {
9354
9532
  const stripped = read(path2).replace(/\/\*[\s\S]*?\*\//g, "").replace(/\/\/.*$/gm, "");
@@ -9365,7 +9543,7 @@ function kiloConfigListsPlugin(configRoot, home = (0, import_node_os5.homedir)()
9365
9543
  return false;
9366
9544
  }
9367
9545
  function cursorLocalPluginRoot(env = process.env, home = (0, import_node_os5.homedir)()) {
9368
- return (0, import_node_path12.join)(surfaceConfigRoot("cursor", env, home), "plugins", "local", "mmi");
9546
+ return (0, import_node_path13.join)(surfaceConfigRoot("cursor", env, home), "plugins", "local", "mmi");
9369
9547
  }
9370
9548
  function cursorPluginTreeHealthy(root, exists = import_node_fs14.existsSync) {
9371
9549
  return [
@@ -9374,14 +9552,14 @@ function cursorPluginTreeHealthy(root, exists = import_node_fs14.existsSync) {
9374
9552
  "hooks/cursor-hooks.json",
9375
9553
  "scripts/hook-run.mjs",
9376
9554
  "scripts/hook-policy.mjs"
9377
- ].every((path2) => exists((0, import_node_path12.join)(root, ...path2.split("/"))));
9555
+ ].every((path2) => exists((0, import_node_path13.join)(root, ...path2.split("/"))));
9378
9556
  }
9379
9557
  function kimiPluginTreeHealthy(root, exists = import_node_fs14.existsSync) {
9380
9558
  return [
9381
9559
  ".kimi-plugin/plugin.json",
9382
9560
  "skills/mmi/SKILL.md",
9383
9561
  "scripts/hook-run.mjs"
9384
- ].every((path2) => exists((0, import_node_path12.join)(root, ...path2.split("/"))));
9562
+ ].every((path2) => exists((0, import_node_path13.join)(root, ...path2.split("/"))));
9385
9563
  }
9386
9564
  var JERVCODE_WRAPPER_DIR = ".pi-plugin";
9387
9565
  function normalizePiEntry(value) {
@@ -9404,7 +9582,7 @@ function jervcodePackageFamily(entry) {
9404
9582
  function isMmiOwnedPiEntry(entry) {
9405
9583
  if (typeof entry !== "string") return false;
9406
9584
  try {
9407
- const pkg = JSON.parse((0, import_node_fs14.readFileSync)((0, import_node_path12.join)(piEntryFsPath(entry), "package.json"), "utf8"));
9585
+ const pkg = JSON.parse((0, import_node_fs14.readFileSync)((0, import_node_path13.join)(piEntryFsPath(entry), "package.json"), "utf8"));
9408
9586
  return pkg.name === "mmi";
9409
9587
  } catch {
9410
9588
  return false;
@@ -9436,8 +9614,8 @@ function readPiSettings(path2) {
9436
9614
  }
9437
9615
  }
9438
9616
  function jervcodeSettingsCandidates(env = process.env, home = (0, import_node_os5.homedir)()) {
9439
- const primary = (0, import_node_path12.join)(surfaceConfigRoot("jervcode", env, home), "settings.json");
9440
- const legacy = (0, import_node_path12.join)(home, ".pi", "agent", "settings.json");
9617
+ const primary = (0, import_node_path13.join)(surfaceConfigRoot("jervcode", env, home), "settings.json");
9618
+ const legacy = (0, import_node_path13.join)(home, ".pi", "agent", "settings.json");
9441
9619
  return legacy === primary ? [primary] : [primary, legacy];
9442
9620
  }
9443
9621
  function mmiPiWrapperEntry(env = process.env, home = (0, import_node_os5.homedir)()) {
@@ -9456,17 +9634,17 @@ function mmiPiWrapperEntry(env = process.env, home = (0, import_node_os5.homedir
9456
9634
  function mmiPiWrapperHealthy(entry) {
9457
9635
  if (!entry) return false;
9458
9636
  const wrapper = piEntryFsPath(entry);
9459
- return isMmiOwnedPiEntry(entry) && (0, import_node_fs14.existsSync)((0, import_node_path12.join)((0, import_node_path12.dirname)(wrapper), "skills", "mmi", "SKILL.md"));
9637
+ return isMmiOwnedPiEntry(entry) && (0, import_node_fs14.existsSync)((0, import_node_path13.join)((0, import_node_path13.dirname)(wrapper), "skills", "mmi", "SKILL.md"));
9460
9638
  }
9461
9639
  function findMmiPiSourceClone(home = (0, import_node_os5.homedir)()) {
9462
- const cacheRoot = (0, import_node_path12.join)(home, ".claude", "plugins", "cache", "mutmutco", "mmi");
9640
+ const cacheRoot = (0, import_node_path13.join)(home, ".claude", "plugins", "cache", "mutmutco", "mmi");
9463
9641
  let best = null;
9464
9642
  try {
9465
9643
  for (const entry of (0, import_node_fs14.readdirSync)(cacheRoot, { withFileTypes: true })) {
9466
9644
  if (!entry.isDirectory() || !/^\d+\.\d+\.\d+$/.test(entry.name)) continue;
9467
- if (!(0, import_node_fs14.existsSync)((0, import_node_path12.join)(cacheRoot, entry.name, JERVCODE_WRAPPER_DIR, "package.json"))) continue;
9645
+ if (!(0, import_node_fs14.existsSync)((0, import_node_path13.join)(cacheRoot, entry.name, JERVCODE_WRAPPER_DIR, "package.json"))) continue;
9468
9646
  if (!best || compareVersions(entry.name, best.version) > 0) {
9469
- best = { path: (0, import_node_path12.join)(cacheRoot, entry.name), version: entry.name };
9647
+ best = { path: (0, import_node_path13.join)(cacheRoot, entry.name), version: entry.name };
9470
9648
  }
9471
9649
  }
9472
9650
  } catch {
@@ -9520,7 +9698,7 @@ function healOneJervCodeSettingsFile(settingsPath2, packagePath, version, nextLa
9520
9698
  }
9521
9699
  current.packages = merged.next;
9522
9700
  try {
9523
- (0, import_node_fs14.mkdirSync)((0, import_node_path12.dirname)(settingsPath2), { recursive: true });
9701
+ (0, import_node_fs14.mkdirSync)((0, import_node_path13.dirname)(settingsPath2), { recursive: true });
9524
9702
  const tmp = `${settingsPath2}.tmp-${process.pid}`;
9525
9703
  (0, import_node_fs14.writeFileSync)(tmp, `${JSON.stringify(current, null, 2)}
9526
9704
  `, "utf8");
@@ -9551,7 +9729,7 @@ function healJervCodePackageRegistration(opts = {}) {
9551
9729
  const nextLaunch = inSeat ? " \u2014 takes effect on the next seat launch" : "";
9552
9730
  const home = opts.home ?? (0, import_node_os5.homedir)();
9553
9731
  const agentDir = surfaceConfigRoot("jervcode", env, home);
9554
- const legacyPi = (0, import_node_path12.join)(home, ".pi", "agent");
9732
+ const legacyPi = (0, import_node_path13.join)(home, ".pi", "agent");
9555
9733
  if (!(0, import_node_fs14.existsSync)(agentDir) && !(0, import_node_fs14.existsSync)(legacyPi)) {
9556
9734
  return { available: false, ok: true, changed: false, version: null, detail: "skipped \u2014 no Pi/JervCode install (no agent config dir)" };
9557
9735
  }
@@ -9560,8 +9738,8 @@ function healJervCodePackageRegistration(opts = {}) {
9560
9738
  return { available: true, ok: true, changed: false, version: null, detail: "skipped \u2014 no installed MMI clone carries the pi wrapper (install the Claude plugin first)" };
9561
9739
  }
9562
9740
  const packagePath = `${clone.path.replace(/\\/g, "/").replace(/\/+$/, "")}/${JERVCODE_WRAPPER_DIR}`;
9563
- const targets = [(0, import_node_path12.join)(agentDir, "settings.json")];
9564
- const legacySettings = (0, import_node_path12.join)(legacyPi, "settings.json");
9741
+ const targets = [(0, import_node_path13.join)(agentDir, "settings.json")];
9742
+ const legacySettings = (0, import_node_path13.join)(legacyPi, "settings.json");
9565
9743
  if ((0, import_node_fs14.existsSync)(legacyPi) && legacySettings !== targets[0]) targets.push(legacySettings);
9566
9744
  const details = [];
9567
9745
  let anyChanged = false;
@@ -9590,7 +9768,7 @@ function snapshotPluginGuardInput(surface = detectSurface(process.env), isOrgRep
9590
9768
  return {
9591
9769
  isOrgRepo,
9592
9770
  installRecordPresent: hasUserInstallRecord(installed, MMI_PLUGIN_ID) || hasProjectInstallRecord(installed, MMI_PLUGIN_ID, process.cwd()) || // Kimi's managed plugin directory is its native install record; it has no Claude-style ledger.
9593
- surface === "kimi" && (0, import_node_fs14.existsSync)((0, import_node_path12.join)(root, "plugins", "managed", "mmi")) || // kilo-p1: the install record is the config file itself.
9771
+ surface === "kimi" && (0, import_node_fs14.existsSync)((0, import_node_path13.join)(root, "plugins", "managed", "mmi")) || // kilo-p1: the install record is the config file itself.
9594
9772
  surface === "kilo" && kiloConfigListsPlugin(root) || // #4188: jervcode's install record is the settings-file packages[] entry itself.
9595
9773
  surface === "jervcode" && piEntry !== null || surface === "cursor" && (0, import_node_fs14.existsSync)(cursorLocalPluginRoot()),
9596
9774
  // Kilo has no marketplace to clone — the config file IS the install record, so this dimension of
@@ -9599,9 +9777,9 @@ function snapshotPluginGuardInput(surface = detectSurface(process.env), isOrgRep
9599
9777
  // Kimi keeps no plugin cache dir — installs are copied to plugins/managed/<id> and run from there.
9600
9778
  // Kilo (kilo-p1) keeps no cache dir either: the plugin's server() provisions ~/.kilo behind the
9601
9779
  // version stamp, so the stamp's presence is the cache signal.
9602
- pluginCachePresent: surface === "jervcode" ? mmiPiWrapperHealthy(piEntry) : surface === "kilo" ? (0, import_node_fs14.existsSync)((0, import_node_path12.join)((0, import_node_os5.homedir)(), ".kilo", ".mmi-kilo-version")) : surface === "kimi" ? kimiPluginTreeHealthy((0, import_node_path12.join)(root, "plugins", "managed", "mmi")) : surface === "cursor" ? cursorPluginTreeHealthy(cursorLocalPluginRoot()) : surface === "codex" ? Boolean(
9603
- codexStatus?.installed && codexStatus.enabled && codexStatus.version && (0, import_node_fs14.existsSync)((0, import_node_path12.join)(root, "plugins", "cache", CODEX_MARKETPLACE, "mmi", codexStatus.version))
9604
- ) : (0, import_node_fs14.existsSync)((0, import_node_path12.join)(root, "plugins", "cache", "mutmutco", "mmi"))
9780
+ pluginCachePresent: surface === "jervcode" ? mmiPiWrapperHealthy(piEntry) : surface === "kilo" ? (0, import_node_fs14.existsSync)((0, import_node_path13.join)((0, import_node_os5.homedir)(), ".kilo", ".mmi-kilo-version")) : surface === "kimi" ? kimiPluginTreeHealthy((0, import_node_path13.join)(root, "plugins", "managed", "mmi")) : surface === "cursor" ? cursorPluginTreeHealthy(cursorLocalPluginRoot()) : surface === "codex" ? Boolean(
9781
+ codexStatus?.installed && codexStatus.enabled && codexStatus.version && (0, import_node_fs14.existsSync)((0, import_node_path13.join)(root, "plugins", "cache", CODEX_MARKETPLACE, "mmi", codexStatus.version))
9782
+ ) : (0, import_node_fs14.existsSync)((0, import_node_path13.join)(root, "plugins", "cache", "mutmutco", "mmi"))
9605
9783
  };
9606
9784
  }
9607
9785
  async function runHostBinLogged(bin, args, opts) {
@@ -9621,9 +9799,9 @@ async function runPluginCli(bin, args, log) {
9621
9799
  function captureCodexHookLauncher() {
9622
9800
  const status = codexPluginStatus();
9623
9801
  if (!status.installed || !status.enabled || !status.version) return void 0;
9624
- const root = (0, import_node_path12.join)(surfaceConfigRoot("codex"), "plugins", "cache", CODEX_MARKETPLACE, "mmi", status.version);
9802
+ const root = (0, import_node_path13.join)(surfaceConfigRoot("codex"), "plugins", "cache", CODEX_MARKETPLACE, "mmi", status.version);
9625
9803
  const files = ["mmi-hook", "mmi-hook.exe"].flatMap((name) => {
9626
- const path2 = (0, import_node_path12.join)(root, "bin", name);
9804
+ const path2 = (0, import_node_path13.join)(root, "bin", name);
9627
9805
  try {
9628
9806
  return [{ name, content: (0, import_node_fs14.readFileSync)(path2) }];
9629
9807
  } catch {
@@ -9633,11 +9811,11 @@ function captureCodexHookLauncher() {
9633
9811
  return files.length === 2 ? { root, files } : void 0;
9634
9812
  }
9635
9813
  function restoreCodexHookLauncher(snapshot) {
9636
- if (!snapshot || (0, import_node_fs14.existsSync)((0, import_node_path12.join)(snapshot.root, "scripts", "hook-run.mjs"))) return false;
9637
- const bin = (0, import_node_path12.join)(snapshot.root, "bin");
9814
+ if (!snapshot || (0, import_node_fs14.existsSync)((0, import_node_path13.join)(snapshot.root, "scripts", "hook-run.mjs"))) return false;
9815
+ const bin = (0, import_node_path13.join)(snapshot.root, "bin");
9638
9816
  (0, import_node_fs14.mkdirSync)(bin, { recursive: true });
9639
9817
  for (const file of snapshot.files) {
9640
- const path2 = (0, import_node_path12.join)(bin, file.name);
9818
+ const path2 = (0, import_node_path13.join)(bin, file.name);
9641
9819
  (0, import_node_fs14.writeFileSync)(path2, file.content);
9642
9820
  if (file.name === "mmi-hook") (0, import_node_fs14.chmodSync)(path2, 493);
9643
9821
  }
@@ -9648,8 +9826,8 @@ function canonicalCursorRemote(remote) {
9648
9826
  }
9649
9827
  async function installCursorPluginCheckout(env = process.env) {
9650
9828
  const configRoot = surfaceConfigRoot("cursor", env);
9651
- const pluginsRoot = (0, import_node_path12.join)(configRoot, "plugins");
9652
- const target = (0, import_node_path12.join)(pluginsRoot, "local", "mmi");
9829
+ const pluginsRoot = (0, import_node_path13.join)(configRoot, "plugins");
9830
+ const target = (0, import_node_path13.join)(pluginsRoot, "local", "mmi");
9653
9831
  const source = env.MMI_CURSOR_PLUGIN_SOURCE?.trim();
9654
9832
  if ((0, import_node_fs14.existsSync)(target) && !source) {
9655
9833
  try {
@@ -9661,12 +9839,12 @@ async function installCursorPluginCheckout(env = process.env) {
9661
9839
  return { ok: false, detail: `refused to replace unmanaged Cursor plugin directory at ${target}` };
9662
9840
  }
9663
9841
  }
9664
- (0, import_node_fs14.mkdirSync)((0, import_node_path12.join)(pluginsRoot, "local"), { recursive: true });
9665
- (0, import_node_fs14.mkdirSync)((0, import_node_path12.join)(pluginsRoot, "staging"), { recursive: true });
9666
- (0, import_node_fs14.mkdirSync)((0, import_node_path12.join)(pluginsRoot, "quarantine"), { recursive: true });
9842
+ (0, import_node_fs14.mkdirSync)((0, import_node_path13.join)(pluginsRoot, "local"), { recursive: true });
9843
+ (0, import_node_fs14.mkdirSync)((0, import_node_path13.join)(pluginsRoot, "staging"), { recursive: true });
9844
+ (0, import_node_fs14.mkdirSync)((0, import_node_path13.join)(pluginsRoot, "quarantine"), { recursive: true });
9667
9845
  const suffix = `${Date.now()}-${process.pid}`;
9668
- const staged = (0, import_node_path12.join)(pluginsRoot, "staging", `mmi-${suffix}`);
9669
- const quarantined = (0, import_node_path12.join)(pluginsRoot, "quarantine", `mmi-${suffix}`);
9846
+ const staged = (0, import_node_path13.join)(pluginsRoot, "staging", `mmi-${suffix}`);
9847
+ const quarantined = (0, import_node_path13.join)(pluginsRoot, "quarantine", `mmi-${suffix}`);
9670
9848
  try {
9671
9849
  if (source) {
9672
9850
  (0, import_node_fs14.cpSync)(source, staged, {
@@ -9737,7 +9915,7 @@ async function runHealSteps(host, tableSteps, deps) {
9737
9915
  const refSupported = needsRefProbe ? await marketplaceAddRefSupported(host) : true;
9738
9916
  const { steps } = adaptHealStepsForRefSupport(tableSteps, refSupported);
9739
9917
  if (deps.banner) log(deps.banner(refSupported));
9740
- const pinsPath = (0, import_node_path12.join)((0, import_node_os5.homedir)(), ...KNOWN_MARKETPLACES_RELATIVE);
9918
+ const pinsPath = (0, import_node_path13.join)((0, import_node_os5.homedir)(), ...KNOWN_MARKETPLACES_RELATIVE);
9741
9919
  const pins = host === "claude" ? captureMarketplacePins(readKnownMarketplacesFile(pinsPath), [MMI_MARKETPLACE_NAME, JERV_MARKETPLACE_NAME]) : /* @__PURE__ */ new Map();
9742
9920
  let failure;
9743
9921
  try {
@@ -10048,7 +10226,7 @@ function describeUpdatePlan(hasBinary) {
10048
10226
 
10049
10227
  // src/hook-activity.ts
10050
10228
  var import_node_fs15 = require("node:fs");
10051
- var import_node_path13 = require("node:path");
10229
+ var import_node_path14 = require("node:path");
10052
10230
  var DEFAULT_SURFACE = "claude";
10053
10231
  function activityLogPath(cwd) {
10054
10232
  return repoRuntimeStatePath(cwd, "hooks", "activity.jsonl");
@@ -10061,7 +10239,7 @@ function appendHookActivity(cwd, entry) {
10061
10239
  surface: DEFAULT_SURFACE,
10062
10240
  ...entry
10063
10241
  };
10064
- (0, import_node_fs15.mkdirSync)((0, import_node_path13.dirname)(path2), { recursive: true });
10242
+ (0, import_node_fs15.mkdirSync)((0, import_node_path14.dirname)(path2), { recursive: true });
10065
10243
  (0, import_node_fs15.appendFileSync)(path2, `${JSON.stringify(line)}
10066
10244
  `, "utf8");
10067
10245
  } catch {
@@ -10070,11 +10248,11 @@ function appendHookActivity(cwd, entry) {
10070
10248
 
10071
10249
  // src/worktree.ts
10072
10250
  var import_node_fs16 = require("node:fs");
10073
- var import_node_path15 = require("node:path");
10251
+ var import_node_path16 = require("node:path");
10074
10252
 
10075
10253
  // src/file-lock.ts
10076
10254
  var import_promises2 = require("node:fs/promises");
10077
- var import_node_path14 = require("node:path");
10255
+ var import_node_path15 = require("node:path");
10078
10256
  var sleep = (ms) => new Promise((resolve6) => setTimeout(resolve6, ms));
10079
10257
  var IMMEDIATE_RETRY_BUDGET = 3;
10080
10258
  var FileLockBusyError = class extends Error {
@@ -10159,7 +10337,7 @@ async function releaseFileLock(lockPath, guard) {
10159
10337
  }
10160
10338
  async function withFileLock(lockPath, opts, fn) {
10161
10339
  const resolved = resolveFileLockOpts(opts);
10162
- await (0, import_promises2.mkdir)((0, import_node_path14.dirname)(lockPath), { recursive: true }).catch(() => void 0);
10340
+ await (0, import_promises2.mkdir)((0, import_node_path15.dirname)(lockPath), { recursive: true }).catch(() => void 0);
10163
10341
  const guard = await acquireFileLock(lockPath, resolved, Date.now() + resolved.maxWaitMs);
10164
10342
  try {
10165
10343
  return await fn();
@@ -10214,7 +10392,7 @@ var realFsProbe = {
10214
10392
  }
10215
10393
  };
10216
10394
  function declaredProvision(fs2, abs) {
10217
- const raw = fs2.readFile?.((0, import_node_path15.join)(abs, PKG));
10395
+ const raw = fs2.readFile?.((0, import_node_path16.join)(abs, PKG));
10218
10396
  if (raw === void 0) return void 0;
10219
10397
  try {
10220
10398
  const scripts = JSON.parse(raw).scripts;
@@ -10226,13 +10404,13 @@ function declaredProvision(fs2, abs) {
10226
10404
  }
10227
10405
  function scanInstallDirs(root, fs2 = realFsProbe) {
10228
10406
  const factsFor = (dir) => {
10229
- const abs = dir ? (0, import_node_path15.join)(root, dir) : root;
10230
- const match = LOCKFILE_INSTALLS.find((c) => fs2.isFile((0, import_node_path15.join)(abs, c.lockfile)));
10231
- const hasPackageJson = fs2.isFile((0, import_node_path15.join)(abs, PKG));
10407
+ const abs = dir ? (0, import_node_path16.join)(root, dir) : root;
10408
+ const match = LOCKFILE_INSTALLS.find((c) => fs2.isFile((0, import_node_path16.join)(abs, c.lockfile)));
10409
+ const hasPackageJson = fs2.isFile((0, import_node_path16.join)(abs, PKG));
10232
10410
  return {
10233
10411
  dir,
10234
10412
  hasPackageJson,
10235
- hasNodeModules: fs2.isDir((0, import_node_path15.join)(abs, NODE_MODULES)),
10413
+ hasNodeModules: fs2.isDir((0, import_node_path16.join)(abs, NODE_MODULES)),
10236
10414
  install: match?.command,
10237
10415
  provision: hasPackageJson ? declaredProvision(fs2, abs) : void 0
10238
10416
  };
@@ -10248,7 +10426,7 @@ function npmInstallTargets(dirs) {
10248
10426
  }));
10249
10427
  }
10250
10428
  function isLinkedWorktree(root, fs2 = realFsProbe) {
10251
- return fs2.isFile((0, import_node_path15.join)(root, ".git"));
10429
+ return fs2.isFile((0, import_node_path16.join)(root, ".git"));
10252
10430
  }
10253
10431
  function worktreeAutoProvisionBanner(root, fs2 = realFsProbe) {
10254
10432
  if (!isLinkedWorktree(root, fs2)) return null;
@@ -10258,7 +10436,7 @@ function worktreeAutoProvisionBanner(root, fs2 = realFsProbe) {
10258
10436
  return `[worktree] provisioning tooling in the background (deps in ${where} + local config) \u2014 \`mmi-cli worktree setup\` to redo`;
10259
10437
  }
10260
10438
  function defaultCopyFile(from, to) {
10261
- (0, import_node_fs16.mkdirSync)((0, import_node_path15.dirname)(to), { recursive: true });
10439
+ (0, import_node_fs16.mkdirSync)((0, import_node_path16.dirname)(to), { recursive: true });
10262
10440
  (0, import_node_fs16.copyFileSync)(from, to);
10263
10441
  }
10264
10442
  async function runDeclaredProvision(target, cwd, runInstall) {
@@ -10289,7 +10467,7 @@ async function provisionWorktree(worktreeRoot, deps) {
10289
10467
  const targets = npmInstallTargets(allDirs);
10290
10468
  if (deps.validateInstall) {
10291
10469
  for (const dir of allDirs.filter((d) => d.hasPackageJson && (d.provision ?? d.install) && d.hasNodeModules)) {
10292
- const cwd = dir.dir ? (0, import_node_path15.join)(worktreeRoot, dir.dir) : worktreeRoot;
10470
+ const cwd = dir.dir ? (0, import_node_path16.join)(worktreeRoot, dir.dir) : worktreeRoot;
10293
10471
  if (!await deps.validateInstall(cwd)) {
10294
10472
  targets.push({
10295
10473
  dir: dir.dir,
@@ -10303,7 +10481,7 @@ async function provisionWorktree(worktreeRoot, deps) {
10303
10481
  const skippedInstall = allDirs.filter((d) => d.hasPackageJson && d.hasNodeModules && !targetDirs.has(d.dir)).map((d) => d.dir);
10304
10482
  const installed = [];
10305
10483
  for (const target of targets) {
10306
- const cwd = target.dir ? (0, import_node_path15.join)(worktreeRoot, target.dir) : worktreeRoot;
10484
+ const cwd = target.dir ? (0, import_node_path16.join)(worktreeRoot, target.dir) : worktreeRoot;
10307
10485
  log(`installing deps: ${target.command} in ${target.dir || "."}`);
10308
10486
  if (target.declared) await runDeclaredProvision(target, cwd, deps.runInstall);
10309
10487
  else await deps.runInstall(target.command, cwd);
@@ -10313,7 +10491,7 @@ async function provisionWorktree(worktreeRoot, deps) {
10313
10491
  const copySkipped = [];
10314
10492
  const primary = await deps.primaryCheckout();
10315
10493
  for (const rel of LOCAL_ONLY_FILES) {
10316
- const dest = (0, import_node_path15.join)(worktreeRoot, rel);
10494
+ const dest = (0, import_node_path16.join)(worktreeRoot, rel);
10317
10495
  if (fs2.isFile(dest)) {
10318
10496
  copySkipped.push({ file: rel, reason: "already-present" });
10319
10497
  continue;
@@ -10322,11 +10500,11 @@ async function provisionWorktree(worktreeRoot, deps) {
10322
10500
  copySkipped.push({ file: rel, reason: "no-primary" });
10323
10501
  continue;
10324
10502
  }
10325
- if (!fs2.isFile((0, import_node_path15.join)(primary, rel))) {
10503
+ if (!fs2.isFile((0, import_node_path16.join)(primary, rel))) {
10326
10504
  copySkipped.push({ file: rel, reason: "absent-in-primary" });
10327
10505
  continue;
10328
10506
  }
10329
- copyFile((0, import_node_path15.join)(primary, rel), dest);
10507
+ copyFile((0, import_node_path16.join)(primary, rel), dest);
10330
10508
  copied.push(rel);
10331
10509
  log(`copied local config: ${rel}`);
10332
10510
  }
@@ -10340,12 +10518,12 @@ function capWorktreeDirName(name, max = 40) {
10340
10518
  }
10341
10519
  function defaultWorktreePath(repoRoot2, branch) {
10342
10520
  const safe = capWorktreeDirName(branch.replace(/[/\\]+/g, "-"));
10343
- return (0, import_node_path15.join)((0, import_node_path15.dirname)(repoRoot2), "mmi-worktrees", (0, import_node_path15.basename)(repoRoot2), safe);
10521
+ return (0, import_node_path16.join)((0, import_node_path16.dirname)(repoRoot2), "mmi-worktrees", (0, import_node_path16.basename)(repoRoot2), safe);
10344
10522
  }
10345
10523
  async function primaryCheckoutRootOf(git2) {
10346
10524
  try {
10347
10525
  const out = (await git2(["rev-parse", "--path-format=absolute", "--git-common-dir"])).trim();
10348
- return out ? (0, import_node_path15.dirname)(out) : void 0;
10526
+ return out ? (0, import_node_path16.dirname)(out) : void 0;
10349
10527
  } catch {
10350
10528
  return void 0;
10351
10529
  }
@@ -10488,7 +10666,7 @@ function commandLadderHint() {
10488
10666
  }
10489
10667
 
10490
10668
  // src/index.ts
10491
- var import_node_path45 = require("node:path");
10669
+ var import_node_path46 = require("node:path");
10492
10670
 
10493
10671
  // src/merge-ci-policy.ts
10494
10672
  function resolveMergeCiPolicy(input) {
@@ -11162,12 +11340,12 @@ function planManagedGitignore(current) {
11162
11340
 
11163
11341
  // src/docs-index-command.ts
11164
11342
  var import_node_fs18 = require("node:fs");
11165
- var import_node_path17 = require("node:path");
11343
+ var import_node_path18 = require("node:path");
11166
11344
 
11167
11345
  // src/doc-refs-core.ts
11168
11346
  var import_node_child_process7 = require("node:child_process");
11169
11347
  var import_node_fs17 = require("node:fs");
11170
- var import_node_path16 = require("node:path");
11348
+ var import_node_path17 = require("node:path");
11171
11349
  var PIN_RE = /<!--\s*pinned by\s+([^:]+?)\s*:\s*"([^"]+)"[^"]*-->/;
11172
11350
  var PIN_MENTION_RE = /<!--\s*pinned by\b/;
11173
11351
  var FWD_RE = /<!--\s*forward-ref:\s*(\S+?)\s*-->/;
@@ -11226,7 +11404,7 @@ function checkPins(root, readFile9, docs2) {
11226
11404
  findings.push({ kind: "malformed-pin", doc, line: pin.line, detail: pin.text });
11227
11405
  continue;
11228
11406
  }
11229
- const source = readFile9((0, import_node_path16.join)(root, pin.file));
11407
+ const source = readFile9((0, import_node_path17.join)(root, pin.file));
11230
11408
  if (source == null) {
11231
11409
  findings.push({ kind: "missing-test", doc, line: pin.line, detail: pin.file });
11232
11410
  continue;
@@ -11288,11 +11466,11 @@ function checkRefs(root, deps, docs2) {
11288
11466
  for (const { ref } of extractRefs(markdown)) allFirstSegments.add(refFirstSegment(ref));
11289
11467
  }
11290
11468
  const tracked = allFirstSegments.size ? deps.trackedFirstSegments?.([...allFirstSegments]) ?? null : null;
11291
- const firstVerifiable = (first) => tracked ? tracked.has(first) : exists((0, import_node_path16.join)(root, first));
11469
+ const firstVerifiable = (first) => tracked ? tracked.has(first) : exists((0, import_node_path17.join)(root, first));
11292
11470
  const candidates = [];
11293
11471
  const direct = [];
11294
11472
  for (const [doc, markdown] of Object.entries(docs2)) {
11295
- const docDir = import_node_path16.posix.dirname(doc);
11473
+ const docDir = import_node_path17.posix.dirname(doc);
11296
11474
  const base = docDir === "." ? "" : docDir;
11297
11475
  const covered = /* @__PURE__ */ new Set();
11298
11476
  const markers = [];
@@ -11301,21 +11479,21 @@ function checkRefs(root, deps, docs2) {
11301
11479
  direct.push({ kind: "malformed-forward-ref", doc, line: fwd.line, detail: fwd.text });
11302
11480
  continue;
11303
11481
  }
11304
- const docRel = import_node_path16.posix.normalize(import_node_path16.posix.join(base, fwd.target));
11305
- const rootRel = import_node_path16.posix.normalize(fwd.target.replace(/^\/+/, ""));
11482
+ const docRel = import_node_path17.posix.normalize(import_node_path17.posix.join(base, fwd.target));
11483
+ const rootRel = import_node_path17.posix.normalize(fwd.target.replace(/^\/+/, ""));
11306
11484
  markers.push({ target: fwd.target, line: fwd.line, docRel, rootRel });
11307
11485
  covered.add(docRel);
11308
11486
  covered.add(rootRel);
11309
11487
  }
11310
11488
  const links = extractLinks(markdown).map(({ target, line }) => {
11311
- const resolved = import_node_path16.posix.normalize(import_node_path16.posix.join(base, target));
11312
- return { target, line, resolved, missing: !exists((0, import_node_path16.join)(root, resolved)) };
11489
+ const resolved = import_node_path17.posix.normalize(import_node_path17.posix.join(base, target));
11490
+ return { target, line, resolved, missing: !exists((0, import_node_path17.join)(root, resolved)) };
11313
11491
  });
11314
11492
  for (const marker of markers) {
11315
11493
  const coversMissing = links.some(
11316
11494
  (l) => l.missing && (l.resolved === marker.docRel || l.resolved === marker.rootRel)
11317
11495
  );
11318
- if (!coversMissing && (exists((0, import_node_path16.join)(root, marker.docRel)) || exists((0, import_node_path16.join)(root, marker.rootRel)))) {
11496
+ if (!coversMissing && (exists((0, import_node_path17.join)(root, marker.docRel)) || exists((0, import_node_path17.join)(root, marker.rootRel)))) {
11319
11497
  direct.push({
11320
11498
  kind: "stale-forward-ref",
11321
11499
  doc,
@@ -11326,7 +11504,7 @@ function checkRefs(root, deps, docs2) {
11326
11504
  }
11327
11505
  for (const { ref, line } of extractRefs(markdown)) {
11328
11506
  if (!firstVerifiable(refFirstSegment(ref))) continue;
11329
- if (!exists((0, import_node_path16.join)(root, ref))) candidates.push({ kind: "missing-path", doc, line, detail: ref });
11507
+ if (!exists((0, import_node_path17.join)(root, ref))) candidates.push({ kind: "missing-path", doc, line, detail: ref });
11330
11508
  }
11331
11509
  for (const { target, line, resolved, missing } of links) {
11332
11510
  if (resolved.startsWith("..")) {
@@ -11378,18 +11556,18 @@ function readFileOrNull(path2) {
11378
11556
  }
11379
11557
  function walk(dir, root, out) {
11380
11558
  for (const entry of (0, import_node_fs17.readdirSync)(dir)) {
11381
- const full = (0, import_node_path16.join)(dir, entry);
11559
+ const full = (0, import_node_path17.join)(dir, entry);
11382
11560
  if ((0, import_node_fs17.statSync)(full).isDirectory()) walk(full, root, out);
11383
11561
  else if (entry.endsWith(".md")) out.push(full.slice(root.length + 1).replaceAll("\\", "/"));
11384
11562
  }
11385
11563
  return out;
11386
11564
  }
11387
11565
  function defaultListDocs(root) {
11388
- const docsDir = (0, import_node_path16.join)(root, "docs");
11566
+ const docsDir = (0, import_node_path17.join)(root, "docs");
11389
11567
  const docs2 = ((0, import_node_fs17.existsSync)(docsDir) ? walk(docsDir, root, []) : []).filter(
11390
11568
  (rel) => !SKIP_WALK.some((skip) => rel.startsWith(skip))
11391
11569
  );
11392
- return [...ROOT_DOCS.filter((rel) => (0, import_node_fs17.existsSync)((0, import_node_path16.join)(root, rel))), ...docs2];
11570
+ return [...ROOT_DOCS.filter((rel) => (0, import_node_fs17.existsSync)((0, import_node_path17.join)(root, rel))), ...docs2];
11393
11571
  }
11394
11572
  var CHECK_IGNORE_MAX_BUFFER = 32 * 1024 * 1024;
11395
11573
  function defaultIsIgnored(root, relPaths, exec = import_node_child_process7.execFileSync) {
@@ -11449,7 +11627,7 @@ function runDocRefs(root, deps = {}) {
11449
11627
  const walked = listDocs(root);
11450
11628
  const ignoredDocs = walked.length ? isIgnored(walked) : /* @__PURE__ */ new Set();
11451
11629
  const docs2 = Object.fromEntries(
11452
- walked.filter((rel) => !ignoredDocs.has(rel)).map((rel) => [rel, readFile9((0, import_node_path16.join)(root, rel))]).filter(([, body]) => body != null)
11630
+ walked.filter((rel) => !ignoredDocs.has(rel)).map((rel) => [rel, readFile9((0, import_node_path17.join)(root, rel))]).filter(([, body]) => body != null)
11453
11631
  );
11454
11632
  const refResult = checkRefs(root, { exists, isIgnored, trackedFirstSegments }, docs2);
11455
11633
  const findings = [
@@ -11557,19 +11735,19 @@ function walkMarkdown(dir) {
11557
11735
  while (stack.length) {
11558
11736
  const current = stack.pop();
11559
11737
  for (const entry of (0, import_node_fs18.readdirSync)(current, { withFileTypes: true })) {
11560
- const full = (0, import_node_path17.join)(current, entry.name);
11738
+ const full = (0, import_node_path18.join)(current, entry.name);
11561
11739
  if (entry.isDirectory()) {
11562
11740
  stack.push(full);
11563
11741
  } else if (entry.isFile() && entry.name.endsWith(".md")) {
11564
- out.push((0, import_node_path17.relative)(dir, full).split(import_node_path17.sep).join("/"));
11742
+ out.push((0, import_node_path18.relative)(dir, full).split(import_node_path18.sep).join("/"));
11565
11743
  }
11566
11744
  }
11567
11745
  }
11568
11746
  return out;
11569
11747
  }
11570
11748
  function createDocsIndexDeps(repoRoot2) {
11571
- const docsDir = (0, import_node_path17.join)(repoRoot2, "docs");
11572
- const indexPath = (0, import_node_path17.join)(repoRoot2, DOCS_INDEX_PATH);
11749
+ const docsDir = (0, import_node_path18.join)(repoRoot2, "docs");
11750
+ const indexPath = (0, import_node_path18.join)(repoRoot2, DOCS_INDEX_PATH);
11573
11751
  return {
11574
11752
  listDocs: () => {
11575
11753
  if (!(0, import_node_fs18.existsSync)(docsDir)) return [];
@@ -11578,7 +11756,7 @@ function createDocsIndexDeps(repoRoot2) {
11578
11756
  const ignored = defaultIsIgnored(repoRoot2, walked.map((rel) => `docs/${rel}`));
11579
11757
  return walked.filter((rel) => !ignored.has(`docs/${rel}`)).sort();
11580
11758
  },
11581
- readDoc: (relPath) => (0, import_node_fs18.readFileSync)((0, import_node_path17.join)(docsDir, relPath), "utf8"),
11759
+ readDoc: (relPath) => (0, import_node_fs18.readFileSync)((0, import_node_path18.join)(docsDir, relPath), "utf8"),
11582
11760
  readIndex: () => (0, import_node_fs18.existsSync)(indexPath) ? (0, import_node_fs18.readFileSync)(indexPath, "utf8") : null,
11583
11761
  writeIndex: (content) => (0, import_node_fs18.writeFileSync)(indexPath, content, "utf8")
11584
11762
  };
@@ -12373,7 +12551,7 @@ function parseVerifyBroker(stdout) {
12373
12551
  // src/train-apply.ts
12374
12552
  var import_node_fs21 = require("node:fs");
12375
12553
  var import_promises4 = require("node:fs/promises");
12376
- var import_node_path20 = require("node:path");
12554
+ var import_node_path21 = require("node:path");
12377
12555
 
12378
12556
  // src/bootstrap-org-ruleset.ts
12379
12557
  var ORG_NO_AGENT_FILES_RULESET_NAME = "mmi-no-agent-files-org";
@@ -12846,7 +13024,7 @@ function renderAccessReport(report) {
12846
13024
 
12847
13025
  // src/cli-doctor-shared.ts
12848
13026
  var import_node_fs19 = require("node:fs");
12849
- var import_node_path19 = require("node:path");
13027
+ var import_node_path20 = require("node:path");
12850
13028
  var import_node_fs20 = require("node:fs");
12851
13029
 
12852
13030
  // ../infra/registry-endpoints.mjs
@@ -12976,9 +13154,9 @@ function extractWorkflowCrons(yamlText) {
12976
13154
  function workflowEntry(repo, workflowPath, yamlText) {
12977
13155
  const crons = extractWorkflowCrons(yamlText);
12978
13156
  if (!crons.length) return null;
12979
- const basename6 = workflowPath.split("/").pop() ?? workflowPath;
13157
+ const basename8 = workflowPath.split("/").pop() ?? workflowPath;
12980
13158
  return {
12981
- name: `${repo}/${basename6.replace(/\.ya?ml$/, "")}`,
13159
+ name: `${repo}/${basename8.replace(/\.ya?ml$/, "")}`,
12982
13160
  cadence: crons.join(" + "),
12983
13161
  executor: "github-actions",
12984
13162
  llm: llmFromHeader(yamlText),
@@ -13388,8 +13566,8 @@ function scheduleRecordFromWorkflow(repo, workflowPath, yamlText) {
13388
13566
  const crons = extractWorkflowCrons(yamlText);
13389
13567
  const header = parseScheduleHeader(yamlText);
13390
13568
  if (!crons.length && !header.schedule) return null;
13391
- const basename6 = workflowPath.split("/").pop() ?? workflowPath;
13392
- const expectedId = `${repo}/${basename6.replace(/\.ya?ml$/, "")}`;
13569
+ const basename8 = workflowPath.split("/").pop() ?? workflowPath;
13570
+ const expectedId = `${repo}/${basename8.replace(/\.ya?ml$/, "")}`;
13393
13571
  if (isHarbourUnmanaged(yamlText)) return null;
13394
13572
  const missing = SCHEDULE_HEADER_FIELDS.filter((f) => !header[f]);
13395
13573
  if (missing.length) {
@@ -13764,7 +13942,7 @@ var import_node_os7 = require("node:os");
13764
13942
  // src/gh-create.ts
13765
13943
  var import_promises3 = require("node:fs/promises");
13766
13944
  var import_node_os6 = require("node:os");
13767
- var import_node_path18 = require("node:path");
13945
+ var import_node_path19 = require("node:path");
13768
13946
  var import_node_crypto3 = require("node:crypto");
13769
13947
 
13770
13948
  // src/board-priority.ts
@@ -13847,8 +14025,8 @@ async function bodyArgsViaFile(args, deps = {}) {
13847
14025
  const remove2 = deps.remove ?? import_promises3.unlink;
13848
14026
  const ensureDir = deps.ensureDir ?? import_promises3.mkdir;
13849
14027
  const dir = deps.dir ?? (0, import_node_os6.tmpdir)();
13850
- const file = (0, import_node_path18.join)(dir, `mmi-gh-body-${process.pid}-${(0, import_node_crypto3.randomBytes)(4).toString("hex")}.md`);
13851
- await ensureDir((0, import_node_path18.dirname)(file), { recursive: true }).catch(() => {
14028
+ const file = (0, import_node_path19.join)(dir, `mmi-gh-body-${process.pid}-${(0, import_node_crypto3.randomBytes)(4).toString("hex")}.md`);
14029
+ await ensureDir((0, import_node_path19.dirname)(file), { recursive: true }).catch(() => {
13852
14030
  });
13853
14031
  await write(file, args[i + 1], "utf8");
13854
14032
  return {
@@ -15391,7 +15569,7 @@ async function localBranchHeads() {
15391
15569
  }
15392
15570
  async function currentRepoWorktreeGitRoot(repoRoot2) {
15393
15571
  const gitCommonDir = (await execFileP2("git", ["rev-parse", "--git-common-dir"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim();
15394
- return gitCommonDir ? (0, import_node_path19.resolve)(repoRoot2, gitCommonDir, "worktrees") : "";
15572
+ return gitCommonDir ? (0, import_node_path20.resolve)(repoRoot2, gitCommonDir, "worktrees") : "";
15395
15573
  }
15396
15574
  async function worktreeBranches() {
15397
15575
  const { stdout } = await execFileP2("git", ["worktree", "list", "--porcelain"], { timeout: GIT_TIMEOUT_MS });
@@ -15411,7 +15589,7 @@ function resolveGitdirForWorktreeFile(worktreePath, content) {
15411
15589
  const match = /^gitdir:\s*(.+)\s*$/im.exec(content);
15412
15590
  if (!match?.[1]) return void 0;
15413
15591
  const raw = match[1].trim();
15414
- return (0, import_node_path19.isAbsolute)(raw) ? raw : (0, import_node_path19.resolve)(worktreePath, raw);
15592
+ return (0, import_node_path20.isAbsolute)(raw) ? raw : (0, import_node_path20.resolve)(worktreePath, raw);
15415
15593
  }
15416
15594
  function metadataOwnsMissingWorktreeDir(worktreePath, worktreeGitRoot) {
15417
15595
  if (!worktreeGitRoot) return false;
@@ -15420,9 +15598,9 @@ function metadataOwnsMissingWorktreeDir(worktreePath, worktreeGitRoot) {
15420
15598
  for (const ent of entries) {
15421
15599
  if (!ent.isDirectory()) continue;
15422
15600
  try {
15423
- const gitdirPath = (0, import_node_fs19.readFileSync)((0, import_node_path19.join)(worktreeGitRoot, ent.name, "gitdir"), "utf8").trim();
15424
- const resolvedGitdir = (0, import_node_path19.isAbsolute)(gitdirPath) ? gitdirPath : (0, import_node_path19.resolve)(worktreeGitRoot, ent.name, gitdirPath);
15425
- if (sameWorktreeMetadataPath((0, import_node_path19.dirname)(resolvedGitdir), worktreePath)) return true;
15601
+ const gitdirPath = (0, import_node_fs19.readFileSync)((0, import_node_path20.join)(worktreeGitRoot, ent.name, "gitdir"), "utf8").trim();
15602
+ const resolvedGitdir = (0, import_node_path20.isAbsolute)(gitdirPath) ? gitdirPath : (0, import_node_path20.resolve)(worktreeGitRoot, ent.name, gitdirPath);
15603
+ if (sameWorktreeMetadataPath((0, import_node_path20.dirname)(resolvedGitdir), worktreePath)) return true;
15426
15604
  } catch {
15427
15605
  }
15428
15606
  }
@@ -15441,7 +15619,7 @@ function pathExistsKnown(path2) {
15441
15619
  }
15442
15620
  }
15443
15621
  function inspectSiblingWorktreeDir(path2, worktreeGitRoot) {
15444
- const gitPath = (0, import_node_path19.join)(path2, ".git");
15622
+ const gitPath = (0, import_node_path20.join)(path2, ".git");
15445
15623
  let st;
15446
15624
  try {
15447
15625
  st = (0, import_node_fs20.lstatSync)(gitPath);
@@ -15495,24 +15673,25 @@ async function preservedBranches() {
15495
15673
  async function siblingWorktreeDirs(explicitRoot) {
15496
15674
  const repoRoot2 = (await execFileP2("git", ["rev-parse", "--show-toplevel"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim() || process.cwd();
15497
15675
  const worktreeGitRoot = await currentRepoWorktreeGitRoot(repoRoot2);
15498
- const primaryRepoRoot = worktreeGitRoot ? (0, import_node_path19.dirname)((0, import_node_path19.dirname)(worktreeGitRoot)) : repoRoot2;
15676
+ const primaryRepoRoot = worktreeGitRoot ? (0, import_node_path20.dirname)((0, import_node_path20.dirname)(worktreeGitRoot)) : repoRoot2;
15499
15677
  try {
15500
15678
  const dirs = explicitRoot ? listDirsIn(resolveExplicitScanRoot(explicitRoot, primaryRepoRoot)) : worktreeScanDirs(siblingMmiWorktreesRoot(primaryRepoRoot), primaryRepoRoot, listDirsIn, isRepoCheckoutDir);
15501
15679
  const agentDirs2 = listDirsIn(agentWorktreesRoot(primaryRepoRoot));
15502
- return [...dirs, ...agentDirs2].map((dir) => inspectSiblingWorktreeDir(dir, worktreeGitRoot)).filter((entry) => Boolean(entry));
15680
+ const repoLocalWorktrees = listDirsIn((0, import_node_path20.join)(primaryRepoRoot, ".worktrees"));
15681
+ return [...dirs, ...agentDirs2, ...repoLocalWorktrees].map((dir) => inspectSiblingWorktreeDir(dir, worktreeGitRoot)).filter((entry) => Boolean(entry));
15503
15682
  } catch {
15504
15683
  return [];
15505
15684
  }
15506
15685
  }
15507
15686
  function listDirsIn(dir) {
15508
15687
  try {
15509
- return (0, import_node_fs20.readdirSync)(dir, { withFileTypes: true }).filter((ent) => ent.isDirectory()).map((ent) => (0, import_node_path19.join)(dir, ent.name));
15688
+ return (0, import_node_fs20.readdirSync)(dir, { withFileTypes: true }).filter((ent) => ent.isDirectory()).map((ent) => (0, import_node_path20.join)(dir, ent.name));
15510
15689
  } catch {
15511
15690
  return [];
15512
15691
  }
15513
15692
  }
15514
15693
  function isRepoCheckoutDir(dir) {
15515
- return (0, import_node_fs20.existsSync)((0, import_node_path19.join)(dir, ".git"));
15694
+ return (0, import_node_fs20.existsSync)((0, import_node_path20.join)(dir, ".git"));
15516
15695
  }
15517
15696
  function resolveExplicitScanRoot(explicitRoot, repoRoot2) {
15518
15697
  let rootDirs;
@@ -15524,7 +15703,7 @@ function resolveExplicitScanRoot(explicitRoot, repoRoot2) {
15524
15703
  return explicitRepoWorktreesRoot(explicitRoot, repoRoot2, rootDirs);
15525
15704
  }
15526
15705
  async function gcPlan(remote, limit, opts = {}) {
15527
- const [branches, heads, current, stale, worktrees, siblingDirs, preserved, mergedIntoBase] = await Promise.all([
15706
+ const [branches, heads, current, stale, worktrees, siblingDirs, preserved, mergedIntoBase, originListed] = await Promise.all([
15528
15707
  gitOut(["branch", "--format=%(refname:short)"]),
15529
15708
  localBranchHeads(),
15530
15709
  gitOut(["rev-parse", "--abbrev-ref", "HEAD"]),
@@ -15534,11 +15713,18 @@ async function gcPlan(remote, limit, opts = {}) {
15534
15713
  worktreeBranches(),
15535
15714
  siblingWorktreeDirs(opts.root),
15536
15715
  preservedBranches(),
15537
- branchesMergedIntoBase(remote)
15716
+ branchesMergedIntoBase(remote),
15717
+ gitOut(["branch", "-r", "--format=%(refname:short)"]).catch(() => "")
15538
15718
  ]);
15539
15719
  const localBranches = branches.split(/\r?\n/).map((b) => b.trim()).filter(Boolean);
15720
+ const originBranches = originListed.split(/\r?\n/).map((b) => b.trim()).filter((b) => b.startsWith(`${remote}/`) && b !== `${remote}/HEAD`);
15721
+ const originNames = originBranches.map((b) => b.slice(remote.length + 1));
15540
15722
  const { prs, failures } = await resolveBranchPrs(
15541
- [...localBranches, ...stale.map((ref) => branchForTrackingRef(ref, remote)).filter((b) => Boolean(b))].filter((b) => !isProtectedBranch(b)),
15723
+ [.../* @__PURE__ */ new Set([
15724
+ ...localBranches,
15725
+ ...stale.map((ref) => branchForTrackingRef(ref, remote)).filter((b) => Boolean(b)),
15726
+ ...originNames
15727
+ ])].filter((b) => !isProtectedBranch(b)),
15542
15728
  limit
15543
15729
  );
15544
15730
  return buildGcPlan({
@@ -15552,7 +15738,9 @@ async function gcPlan(remote, limit, opts = {}) {
15552
15738
  worktrees,
15553
15739
  remote,
15554
15740
  preservedBranches: preserved,
15555
- mergedIntoBase
15741
+ mergedIntoBase,
15742
+ originBranches,
15743
+ trainOnly: opts.trainOnly
15556
15744
  });
15557
15745
  }
15558
15746
  async function branchesMergedIntoBase(remote) {
@@ -15849,10 +16037,10 @@ var rollout_plan_default = {
15849
16037
  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)."
15850
16038
  },
15851
16039
  baseline: {
15852
- version: "3.127.0",
15853
- tag: "v3.127.0",
15854
- commit: "2f170f4e63d4",
15855
- npm: "@mutmutco/cli@3.127.0"
16040
+ version: "3.129.0",
16041
+ tag: "v3.129.0",
16042
+ commit: "7067f7164642",
16043
+ npm: "@mutmutco/cli@3.129.0"
15856
16044
  },
15857
16045
  exitCriterion: "fleet-n-of-n",
15858
16046
  hubOnlyShortcut: "forbidden",
@@ -15869,14 +16057,14 @@ var rollout_plan_default = {
15869
16057
  repo: "mutmutco/mmi-hub",
15870
16058
  role: "canary",
15871
16059
  schedule: "train",
15872
- v3Target: "v3.127.0"
16060
+ v3Target: "v3.129.0"
15873
16061
  }
15874
16062
  ],
15875
16063
  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.",
15876
16064
  rollback: {
15877
16065
  independent: true,
15878
- mechanism: "npm dist-tag latest -> 3.127.0 and redeploy the Hub Lambda from tag v3.127.0 (2f170f4e63d4); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
15879
- v3Target: "v3.127.0 (@mutmutco/cli@3.127.0, tag commit 2f170f4e63d4 \u2014 the preserved latest-v3 distribution, D6b)"
16066
+ mechanism: "npm dist-tag latest -> 3.129.0 and redeploy the Hub Lambda from tag v3.129.0 (7067f7164642); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
16067
+ v3Target: "v3.129.0 (@mutmutco/cli@3.129.0, tag commit 7067f7164642 \u2014 the preserved latest-v3 distribution, D6b)"
15880
16068
  }
15881
16069
  },
15882
16070
  {
@@ -18125,7 +18313,7 @@ function publishVisibilityFor(surfaceId) {
18125
18313
  }
18126
18314
  function npmPackArtifactName(packagePath) {
18127
18315
  try {
18128
- const pkg = JSON.parse((0, import_node_fs21.readFileSync)((0, import_node_path20.join)(packagePath, "package.json"), "utf8"));
18316
+ const pkg = JSON.parse((0, import_node_fs21.readFileSync)((0, import_node_path21.join)(packagePath, "package.json"), "utf8"));
18129
18317
  return pkg.name || void 0;
18130
18318
  } catch {
18131
18319
  return void 0;
@@ -19296,7 +19484,7 @@ async function dispatchDeploy(deps, ctx, stage, ref, model, watch, autoRunSince,
19296
19484
  return { note: `no manual dispatch: ${model} repo deploys via its own push-triggered workflow`, deployStatus: "pending" };
19297
19485
  }
19298
19486
  function readLocalGateWorkflows() {
19299
- const dir = (0, import_node_path20.join)(".github", "workflows");
19487
+ const dir = (0, import_node_path21.join)(".github", "workflows");
19300
19488
  let names;
19301
19489
  try {
19302
19490
  names = (0, import_node_fs21.readdirSync)(dir);
@@ -19306,7 +19494,7 @@ function readLocalGateWorkflows() {
19306
19494
  const files = [];
19307
19495
  for (const name of names.filter(isGateWorkflowPath)) {
19308
19496
  try {
19309
- files.push({ path: `${dir}/${name}`.replace(/\\/g, "/"), body: (0, import_node_fs21.readFileSync)((0, import_node_path20.join)(dir, name), "utf8") });
19497
+ files.push({ path: `${dir}/${name}`.replace(/\\/g, "/"), body: (0, import_node_fs21.readFileSync)((0, import_node_path21.join)(dir, name), "utf8") });
19310
19498
  } catch {
19311
19499
  }
19312
19500
  }
@@ -21543,7 +21731,7 @@ var import_node_fs23 = require("node:fs");
21543
21731
  // src/stage-runner.ts
21544
21732
  var import_node_child_process9 = require("node:child_process");
21545
21733
  var import_node_fs22 = require("node:fs");
21546
- var import_node_path21 = require("node:path");
21734
+ var import_node_path22 = require("node:path");
21547
21735
  var import_node_net = require("node:net");
21548
21736
  var import_node_util5 = require("node:util");
21549
21737
 
@@ -21682,11 +21870,11 @@ function appendForceRecreate(up) {
21682
21870
  return `${up.trimEnd()} --force-recreate`;
21683
21871
  }
21684
21872
  function stageStatePath(cwd = process.cwd()) {
21685
- return (0, import_node_path21.join)(cwd, "tmp", "stage", "state.json");
21873
+ return (0, import_node_path22.join)(cwd, "tmp", "stage", "state.json");
21686
21874
  }
21687
21875
  function stageGlobalStatePath(cwd = process.cwd(), gitCommonDir = ".git") {
21688
- const dir = (0, import_node_path21.isAbsolute)(gitCommonDir) ? gitCommonDir : (0, import_node_path21.resolve)(cwd, gitCommonDir);
21689
- return (0, import_node_path21.join)(dir, "mmi", "stage", "state.json");
21876
+ const dir = (0, import_node_path22.isAbsolute)(gitCommonDir) ? gitCommonDir : (0, import_node_path22.resolve)(cwd, gitCommonDir);
21877
+ return (0, import_node_path22.join)(dir, "mmi", "stage", "state.json");
21690
21878
  }
21691
21879
  function normPath3(path2) {
21692
21880
  return path2.replace(/\\/g, "/").replace(/\/+$/, "").toLowerCase();
@@ -21910,8 +22098,8 @@ function stageProcessEnv(stagePort, extraEnv) {
21910
22098
  }
21911
22099
  async function ensureStageRuntimeEnv(config, opts, cwd) {
21912
22100
  if (!config.ensureEnv) return;
21913
- const target = (0, import_node_path21.join)(cwd, config.ensureEnv.target);
21914
- const example = (0, import_node_path21.join)(cwd, config.ensureEnv.example);
22101
+ const target = (0, import_node_path22.join)(cwd, config.ensureEnv.target);
22102
+ const example = (0, import_node_path22.join)(cwd, config.ensureEnv.example);
21915
22103
  if (!(0, import_node_fs22.existsSync)(target) && (0, import_node_fs22.existsSync)(example)) {
21916
22104
  (0, import_node_fs22.copyFileSync)(example, target);
21917
22105
  } else if ((0, import_node_fs22.existsSync)(target) && (0, import_node_fs22.existsSync)(example)) {
@@ -22276,13 +22464,13 @@ async function executeWaveLand(plan, deps, opts = { preserveWorktree: true }) {
22276
22464
  }
22277
22465
 
22278
22466
  // src/index.ts
22279
- var import_node_os19 = require("node:os");
22467
+ var import_node_os20 = require("node:os");
22280
22468
 
22281
22469
  // src/board.ts
22282
22470
  var import_node_child_process10 = require("node:child_process");
22283
22471
  var import_node_fs24 = require("node:fs");
22284
22472
  var import_node_os8 = require("node:os");
22285
- var import_node_path22 = require("node:path");
22473
+ var import_node_path23 = require("node:path");
22286
22474
  var import_node_util6 = require("node:util");
22287
22475
 
22288
22476
  // src/board-dependency.ts
@@ -22629,9 +22817,6 @@ var BOARD_GIT_TIMEOUT_MS = 1e4;
22629
22817
  var WRITE_PROBE_CONCURRENCY = 8;
22630
22818
  var CLAIM_CONCURRENCY = 5;
22631
22819
  var BOARD_ACTIVE_READ_MAX_PAGES = 100;
22632
- var BOARD_PROJECTION_STALE_MS = 24 * 60 * 6e4;
22633
- var BOARD_PROJECTION_RECONCILE_STALE_MS = 3 * 60 * 6e4;
22634
- var BOARD_PROJECTION_TIMEOUT_MS = 8e3;
22635
22820
  var execFileP4 = (file, args, options = {}) => (
22636
22821
  // encoding 'utf8' guarantees string output at runtime; the cast pins the type (promisify's
22637
22822
  // overloads widen to string|Buffer when options is spread in).
@@ -22899,7 +23084,7 @@ function renderBoardItem(item) {
22899
23084
  return lines.join("\n");
22900
23085
  }
22901
23086
  function renderBoardReport(report) {
22902
- const lines = [`Board \xB7 ${report.project.title} \xB7 @${report.viewer}`, renderBoardSource(report)];
23087
+ const lines = [`Board \xB7 ${report.project.title} \xB7 @${report.viewer}`, renderBoardSource()];
22903
23088
  renderScope(lines, "PRIMARY", report.repo, report.primary, report.viewer);
22904
23089
  renderScope(lines, "SECONDARY", "Other repos on this project", report.secondary, report.viewer);
22905
23090
  if (report.warnings.length) {
@@ -23003,132 +23188,13 @@ async function resolveWritableReposForClaimables(items, client) {
23003
23188
  function writableOrUnknown(writable) {
23004
23189
  return /* @__PURE__ */ new Set([...writable.repos, ...writable.unknown]);
23005
23190
  }
23006
- async function defaultFetchBoardProjection(owner, number, baseUrl) {
23007
- if (!baseUrl) throw new Error("Hub API URL not configured");
23008
- const token = await hubAuthToken({ baseUrl, githubToken });
23009
- if (!token) throw new Error("no Hub session token");
23010
- const url = new URL("/board-projection", `${baseUrl.replace(/\/$/, "")}/`);
23011
- url.searchParams.set("owner", owner);
23012
- url.searchParams.set("number", String(number));
23013
- const res = await fetch(url, {
23014
- method: "GET",
23015
- headers: { ...clientVersionHeaders(), Authorization: `Bearer ${token}` },
23016
- signal: AbortSignal.timeout(BOARD_PROJECTION_TIMEOUT_MS)
23017
- });
23018
- if (res.status === 404) return null;
23019
- if (res.status === 426) throw new Error(upgradeRequiredError(res, await res.json().catch(() => null)));
23020
- if (!res.ok) throw new Error(`board projection HTTP ${res.status}`);
23021
- return await res.json();
23022
- }
23023
- function projectionItems(row) {
23024
- if (!row.items || typeof row.items !== "object" || Array.isArray(row.items)) {
23025
- throw new Error("malformed projection items");
23026
- }
23027
- const items = [];
23028
- for (const raw of Object.values(row.items)) {
23029
- if (!raw || typeof raw !== "object") throw new Error("malformed projection item");
23030
- if (raw.tombstone === true) continue;
23031
- const item = raw;
23032
- if (typeof item.itemId !== "string" || typeof item.contentId !== "string" || item.contentType !== "Issue" && item.contentType !== "PullRequest" || typeof item.repository !== "string" || typeof item.number !== "number" || !Number.isFinite(item.number) || typeof item.ref !== "string" || typeof item.url !== "string" || typeof item.title !== "string" || typeof item.state !== "string" || !BOARD_STATUSES.includes(item.status) || !Array.isArray(item.assignees) || item.assignees.some((value) => typeof value !== "string") || !Array.isArray(item.labels) || item.labels.some((value) => typeof value !== "string") || typeof item.sourceTimestamp !== "string") {
23033
- throw new Error("malformed projection item");
23034
- }
23035
- if (item.state.toUpperCase() === "CLOSED" || item.status === "Done") continue;
23036
- items.push(withLoopState({
23037
- itemId: item.itemId,
23038
- contentId: item.contentId,
23039
- contentType: item.contentType,
23040
- repository: item.repository,
23041
- number: item.number,
23042
- ref: item.ref,
23043
- url: item.url,
23044
- title: item.title,
23045
- state: item.state,
23046
- // #4441: the reconciler stamps each item's content updatedAt as sourceTimestamp — the same
23047
- // idle-age evidence the live read carries, so projection reads derive staleness too.
23048
- updatedAt: item.sourceTimestamp,
23049
- status: item.status,
23050
- statusOptionId: item.statusOptionId,
23051
- priority: item.priority,
23052
- priorityOptionId: item.priorityOptionId,
23053
- assignees: [...item.assignees],
23054
- labels: [...item.labels],
23055
- type: item.type
23056
- }));
23057
- }
23058
- return items;
23059
- }
23060
- async function readViewerLogin(client) {
23061
- const user = await client.rest("GET", "user");
23062
- if (!user?.login) throw new Error("viewer login unavailable");
23063
- return user.login;
23064
- }
23065
- function projectionFreshness(row, now) {
23066
- const projectedAtMs = Date.parse(row.watermark?.projectedAt);
23067
- const sourceTimestampMs = Date.parse(row.watermark?.sourceTimestamp);
23068
- if (!Number.isFinite(projectedAtMs) || !Number.isFinite(sourceTimestampMs)) {
23069
- throw new Error("malformed projection watermark");
23070
- }
23071
- const projectedAgeMs = Math.max(0, now - projectedAtMs);
23072
- const sourceAgeMs = Math.max(0, now - sourceTimestampMs);
23073
- return {
23074
- projectedAt: row.watermark.projectedAt,
23075
- projectedAgeMs,
23076
- sourceTimestamp: row.watermark.sourceTimestamp,
23077
- sourceAgeMs,
23078
- // #4774: health must agree with BOTH ages a caller can see on the source line — a projection whose
23079
- // rebuild (projectedAt) went stale is exactly as unreliable as one whose source events did, even
23080
- // while recent webhook activity keeps sourceAgeMs looking fresh.
23081
- health: row.watermark.health === "stale" || sourceAgeMs > BOARD_PROJECTION_STALE_MS || projectedAgeMs > BOARD_PROJECTION_RECONCILE_STALE_MS ? "stale" : "fresh"
23082
- };
23083
- }
23084
- function renderBoardSource(report) {
23085
- if (report.source === "projection" && report.freshness) {
23086
- return `source: projection \xB7 projected ${formatClaimAge(report.freshness.projectedAgeMs)} ago \xB7 source events through ${report.freshness.sourceTimestamp} \xB7 health ${report.freshness.health}`;
23087
- }
23088
- return `source: live${report.sourceReason ? ` (${report.sourceReason})` : ""}`;
23191
+ function renderBoardSource() {
23192
+ return "source: live";
23089
23193
  }
23090
23194
  async function readBoard(options, deps = {}) {
23091
23195
  const cfg = resolveBoardConfig(options.config);
23092
23196
  const client = deps.client ?? defaultGitHubClient();
23093
- let collected;
23094
- let source = "live";
23095
- let freshness = null;
23096
- let sourceReason;
23097
- if (!options.live) {
23098
- try {
23099
- const baseUrl = options.config.sagaApiUrl;
23100
- const row = await (deps.fetchProjection ?? defaultFetchBoardProjection)(cfg.projectOwner, cfg.projectNumber, baseUrl);
23101
- if (!row) {
23102
- sourceReason = "projection absent";
23103
- } else if (row.schemaVersion !== 1) {
23104
- sourceReason = `unsupported projection schema ${String(row.schemaVersion)}`;
23105
- } else if (row.watermark?.health === "oversize") {
23106
- sourceReason = "projection oversize";
23107
- } else {
23108
- const [viewer, repo] = await Promise.all([
23109
- readViewerLogin(client),
23110
- resolveCurrentRepo(options, deps)
23111
- ]);
23112
- const now = (deps.now ?? Date.now)();
23113
- collected = {
23114
- items: projectionItems(row),
23115
- viewer,
23116
- repo,
23117
- projectId: cfg.projectId,
23118
- projectTitle: String(cfg.projectNumber),
23119
- warnings: [],
23120
- partial: false
23121
- };
23122
- freshness = projectionFreshness(row, now);
23123
- source = "projection";
23124
- }
23125
- } catch {
23126
- sourceReason = "projection read error";
23127
- }
23128
- }
23129
- if (!collected) {
23130
- collected = await collectBoardItems(cfg, { repo: options.repo, allowPartial: options.allowPartial, activeOnly: true }, deps);
23131
- }
23197
+ const collected = await collectBoardItems(cfg, { repo: options.repo, allowPartial: options.allowPartial, activeOnly: true }, deps);
23132
23198
  const writable = await resolveWritableReposForClaimables(collected.items, client);
23133
23199
  collected.warnings.push(...writable.warnings);
23134
23200
  collected.partial = collected.partial || writable.partial;
@@ -23140,9 +23206,7 @@ async function readBoard(options, deps = {}) {
23140
23206
  ...groups,
23141
23207
  warnings: collected.warnings,
23142
23208
  partial: collected.partial,
23143
- source,
23144
- freshness,
23145
- ...sourceReason ? { sourceReason } : {}
23209
+ source: "live"
23146
23210
  };
23147
23211
  if (options.includeBundleDetails || options.includeAllBodies) {
23148
23212
  await attachBundleDetails(report, client, options.allowPartial ?? false, { all: options.includeAllBodies });
@@ -24025,14 +24089,14 @@ function probeLocalClaimSession(marker, now = Date.now()) {
24025
24089
  claimSessionProbeCache.set(cacheKey, { checkedAt: now, state });
24026
24090
  return state;
24027
24091
  };
24028
- const root = (0, import_node_path22.join)((0, import_node_os8.homedir)(), ".claude", "projects");
24092
+ const root = (0, import_node_path23.join)((0, import_node_os8.homedir)(), ".claude", "projects");
24029
24093
  try {
24030
24094
  const wanted = `${marker.session}.jsonl`.toLowerCase();
24031
24095
  const pending = [root];
24032
24096
  while (pending.length) {
24033
24097
  const dir = pending.pop();
24034
24098
  for (const entry of (0, import_node_fs24.readdirSync)(dir, { withFileTypes: true })) {
24035
- const path2 = (0, import_node_path22.join)(dir, entry.name);
24099
+ const path2 = (0, import_node_path23.join)(dir, entry.name);
24036
24100
  if (entry.isDirectory()) pending.push(path2);
24037
24101
  else if (entry.isFile() && entry.name.toLowerCase() === wanted) {
24038
24102
  return remember(now - (0, import_node_fs24.statSync)(path2).mtimeMs <= CLAIM_SESSION_ACTIVITY_MS ? "live" : "dead");
@@ -24938,7 +25002,7 @@ function consolidateCommandNamespaces(program3) {
24938
25002
 
24939
25003
  // src/pi-plugin-registration.ts
24940
25004
  var import_node_fs25 = require("node:fs");
24941
- var import_node_path23 = require("node:path");
25005
+ var import_node_path24 = require("node:path");
24942
25006
  var import_proper_lockfile2 = __toESM(require_proper_lockfile(), 1);
24943
25007
 
24944
25008
  // src/plugin-cache-prune.ts
@@ -25201,17 +25265,17 @@ function newestExistingPiPlugin(home) {
25201
25265
  return void 0;
25202
25266
  }
25203
25267
  for (const version of names.filter(isVersionDirName).sort((a, b) => compareVersions(b, a))) {
25204
- const candidate = (0, import_node_path23.join)(cacheRoot, version, ".pi-plugin");
25268
+ const candidate = (0, import_node_path24.join)(cacheRoot, version, ".pi-plugin");
25205
25269
  if ((0, import_node_fs25.existsSync)(candidate)) return candidate;
25206
25270
  }
25207
25271
  return void 0;
25208
25272
  }
25209
25273
  function expectedPiPluginPath(home, env, installedVersion) {
25210
25274
  const root = env.CLAUDE_PLUGIN_ROOT?.trim();
25211
- if (root && /[\\/]mutmutco[\\/]mmi[\\/]/.test(root)) return (0, import_node_path23.join)(root, ".pi-plugin");
25275
+ if (root && /[\\/]mutmutco[\\/]mmi[\\/]/.test(root)) return (0, import_node_path24.join)(root, ".pi-plugin");
25212
25276
  const version = installedVersion ?? runningPluginVersion(env);
25213
25277
  if (version) {
25214
- const pinned = (0, import_node_path23.join)(home, ".claude", "plugins", "cache", "mutmutco", "mmi", version, ".pi-plugin");
25278
+ const pinned = (0, import_node_path24.join)(home, ".claude", "plugins", "cache", "mutmutco", "mmi", version, ".pi-plugin");
25215
25279
  if ((0, import_node_fs25.existsSync)(pinned)) return pinned;
25216
25280
  }
25217
25281
  return newestExistingPiPlugin(home);
@@ -25219,15 +25283,15 @@ function expectedPiPluginPath(home, env, installedVersion) {
25219
25283
  function agentDirs(home, env = process.env) {
25220
25284
  const override = env.JERVCODE_CODING_AGENT_DIR?.trim() || env.PI_CODING_AGENT_DIR?.trim();
25221
25285
  if (override) return [override];
25222
- const jerv = (0, import_node_path23.join)(home, ".jerv", "agent");
25223
- const pi = (0, import_node_path23.join)(home, ".pi", "agent");
25286
+ const jerv = (0, import_node_path24.join)(home, ".jerv", "agent");
25287
+ const pi = (0, import_node_path24.join)(home, ".pi", "agent");
25224
25288
  if (!(0, import_node_fs25.existsSync)(jerv) && !(0, import_node_fs25.existsSync)(pi)) return [];
25225
25289
  const dirs = [jerv];
25226
25290
  if ((0, import_node_fs25.existsSync)(pi) && pi !== jerv) dirs.push(pi);
25227
25291
  return dirs;
25228
25292
  }
25229
25293
  function settingsPath(agentDir) {
25230
- return (0, import_node_path23.join)(agentDir, "settings.json");
25294
+ return (0, import_node_path24.join)(agentDir, "settings.json");
25231
25295
  }
25232
25296
  function readPiPluginState(home, env, installedVersion) {
25233
25297
  const dirs = agentDirs(home, env);
@@ -25261,7 +25325,7 @@ function acquirePiSettingsLock2(settingsFile) {
25261
25325
  return void 0;
25262
25326
  }
25263
25327
  function atomicWriteSettings(file, body) {
25264
- (0, import_node_fs25.mkdirSync)((0, import_node_path23.dirname)(file), { recursive: true });
25328
+ (0, import_node_fs25.mkdirSync)((0, import_node_path24.dirname)(file), { recursive: true });
25265
25329
  const tmp = `${file}.tmp-${process.pid}`;
25266
25330
  (0, import_node_fs25.writeFileSync)(tmp, body, "utf8");
25267
25331
  try {
@@ -25339,18 +25403,18 @@ function healPiPluginRegistration(home, env, installedVersion) {
25339
25403
  // src/claude-binary-doctor.ts
25340
25404
  var import_node_fs27 = require("node:fs");
25341
25405
  var import_node_os11 = require("node:os");
25342
- var import_node_path25 = require("node:path");
25406
+ var import_node_path26 = require("node:path");
25343
25407
 
25344
25408
  // src/jerv-cli-spawn.ts
25345
25409
  var import_node_fs26 = require("node:fs");
25346
25410
  var import_node_os10 = require("node:os");
25347
- var import_node_path24 = require("node:path");
25411
+ var import_node_path25 = require("node:path");
25348
25412
  var WIN_NAMES = ["jerv-cli.cmd", "jerv-cli.exe", "jerv-cli"];
25349
25413
  var POSIX_NAMES = ["jerv-cli"];
25350
- var JERV_CLI_ENTRY = (0, import_node_path24.join)("node_modules", "@jervaise", "jerv-cli", "dist", "index.cjs");
25414
+ var JERV_CLI_ENTRY = (0, import_node_path25.join)("node_modules", "@jervaise", "jerv-cli", "dist", "index.cjs");
25351
25415
  function pathEnvEntries(pathEnv, platform2 = process.platform) {
25352
25416
  if (platform2 !== "win32") {
25353
- return pathEnv.split(import_node_path24.delimiter).map((e) => e.trim()).filter(Boolean);
25417
+ return pathEnv.split(import_node_path25.delimiter).map((e) => e.trim()).filter(Boolean);
25354
25418
  }
25355
25419
  if (pathEnv.includes(";")) {
25356
25420
  return pathEnv.split(";").map((e) => e.trim()).filter(Boolean);
@@ -25383,10 +25447,10 @@ function jervCliCandidateDirs(env = process.env, home = (0, import_node_os10.hom
25383
25447
  push(normalizeSpawnPathEntry(entry, platform2));
25384
25448
  }
25385
25449
  if (platform2 === "win32") {
25386
- if (env.APPDATA) push((0, import_node_path24.join)(env.APPDATA, "npm"));
25387
- if (env.LOCALAPPDATA) push((0, import_node_path24.join)(env.LOCALAPPDATA, "npm"));
25450
+ if (env.APPDATA) push((0, import_node_path25.join)(env.APPDATA, "npm"));
25451
+ if (env.LOCALAPPDATA) push((0, import_node_path25.join)(env.LOCALAPPDATA, "npm"));
25388
25452
  } else {
25389
- push((0, import_node_path24.join)(home, ".local", "bin"));
25453
+ push((0, import_node_path25.join)(home, ".local", "bin"));
25390
25454
  }
25391
25455
  return out;
25392
25456
  }
@@ -25394,7 +25458,7 @@ function jervCliCandidatePaths(env = process.env, home = (0, import_node_os10.ho
25394
25458
  const names = platform2 === "win32" ? WIN_NAMES : POSIX_NAMES;
25395
25459
  const out = [];
25396
25460
  for (const dir of jervCliCandidateDirs(env, home, platform2)) {
25397
- for (const name of names) out.push((0, import_node_path24.join)(dir, name));
25461
+ for (const name of names) out.push((0, import_node_path25.join)(dir, name));
25398
25462
  }
25399
25463
  return out;
25400
25464
  }
@@ -25405,7 +25469,7 @@ function resolveJervCliPath(env = process.env, home = (0, import_node_os10.homed
25405
25469
  return void 0;
25406
25470
  }
25407
25471
  function resolveJervCliNodeEntry(shimPath, exists = import_node_fs26.existsSync) {
25408
- const entry = (0, import_node_path24.join)((0, import_node_path24.dirname)(shimPath), JERV_CLI_ENTRY);
25472
+ const entry = (0, import_node_path25.join)((0, import_node_path25.dirname)(shimPath), JERV_CLI_ENTRY);
25409
25473
  return exists(entry) ? entry : void 0;
25410
25474
  }
25411
25475
  function jervCliExecFileArgs(args, opts = {}) {
@@ -25500,10 +25564,10 @@ function globalNodeModulesRoots(host) {
25500
25564
  out.push(dir);
25501
25565
  };
25502
25566
  const prefix = env.npm_config_prefix?.trim();
25503
- if (prefix) push(platform2 === "win32" ? (0, import_node_path25.join)(prefix, "node_modules") : (0, import_node_path25.join)(prefix, "lib", "node_modules"));
25567
+ if (prefix) push(platform2 === "win32" ? (0, import_node_path26.join)(prefix, "node_modules") : (0, import_node_path26.join)(prefix, "lib", "node_modules"));
25504
25568
  for (const dir of jervCliCandidateDirs(env, host.home ?? (0, import_node_os11.homedir)(), platform2)) {
25505
- push((0, import_node_path25.join)(dir, "node_modules"));
25506
- push((0, import_node_path25.join)((0, import_node_path25.dirname)(dir), "lib", "node_modules"));
25569
+ push((0, import_node_path26.join)(dir, "node_modules"));
25570
+ push((0, import_node_path26.join)((0, import_node_path26.dirname)(dir), "lib", "node_modules"));
25507
25571
  }
25508
25572
  return out;
25509
25573
  }
@@ -25541,17 +25605,17 @@ function readClaudeBinaryState(host = {}) {
25541
25605
  const arch = host.arch ?? process.arch;
25542
25606
  const magic = EXECUTABLE_MAGIC[platform2];
25543
25607
  if (!magic) return void 0;
25544
- const packageRoot = globalNodeModulesRoots(host).map((root) => (0, import_node_path25.join)(root, ...PACKAGE.split("/"))).find((dir) => (0, import_node_fs27.existsSync)((0, import_node_path25.join)(dir, "package.json")));
25608
+ 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")));
25545
25609
  if (!packageRoot) return void 0;
25546
25610
  const keys = platformPackageKeys(platform2, arch);
25547
25611
  const fallbackPackage = `${PACKAGE}-${keys[0]}`;
25548
25612
  let manifest;
25549
25613
  try {
25550
- manifest = JSON.parse((0, import_node_fs27.readFileSync)((0, import_node_path25.join)(packageRoot, "package.json"), "utf8"));
25614
+ manifest = JSON.parse((0, import_node_fs27.readFileSync)((0, import_node_path26.join)(packageRoot, "package.json"), "utf8"));
25551
25615
  } catch (e) {
25552
25616
  return {
25553
25617
  state: "unreadable",
25554
- binPath: (0, import_node_path25.join)(packageRoot, "package.json"),
25618
+ binPath: (0, import_node_path26.join)(packageRoot, "package.json"),
25555
25619
  expectedMagic: magic.name,
25556
25620
  platformPackage: fallbackPackage,
25557
25621
  error: `package.json could not be read \u2014 ${e.message}`
@@ -25568,15 +25632,15 @@ function readClaudeBinaryState(host = {}) {
25568
25632
  error: "package.json declares no `bin` entry \u2014 the executed file cannot be resolved"
25569
25633
  };
25570
25634
  }
25571
- const binPath = (0, import_node_path25.join)(packageRoot, binRelative);
25572
- const binName = (0, import_node_path25.basename)(binRelative);
25635
+ const binPath = (0, import_node_path26.join)(packageRoot, binRelative);
25636
+ const binName = (0, import_node_path26.basename)(binRelative);
25573
25637
  const optional = manifest.optionalDependencies;
25574
25638
  const publishes = (name) => typeof optional === "object" && optional !== null && Object.prototype.hasOwnProperty.call(optional, name);
25575
25639
  const published = keys.map((key) => `${PACKAGE}-${key}`).filter(publishes);
25576
25640
  if (published.length === 0) return void 0;
25577
25641
  const binIn = (name) => [
25578
- (0, import_node_path25.join)(packageRoot, "node_modules", ...name.split("/"), binName),
25579
- (0, import_node_path25.join)((0, import_node_path25.dirname)((0, import_node_path25.dirname)(packageRoot)), ...name.split("/"), binName)
25642
+ (0, import_node_path26.join)(packageRoot, "node_modules", ...name.split("/"), binName),
25643
+ (0, import_node_path26.join)((0, import_node_path26.dirname)((0, import_node_path26.dirname)(packageRoot)), ...name.split("/"), binName)
25580
25644
  ];
25581
25645
  const found = published.map((name) => ({ name, path: binIn(name).find((file) => (0, import_node_fs27.existsSync)(file)) })).find((c) => c.path);
25582
25646
  const platformPackage = found?.name ?? published[0];
@@ -25901,7 +25965,7 @@ function renderVerifyBroker(input) {
25901
25965
  var import_node_crypto4 = require("node:crypto");
25902
25966
  var import_node_fs28 = require("node:fs");
25903
25967
  var import_promises5 = require("node:fs/promises");
25904
- var import_node_path26 = require("node:path");
25968
+ var import_node_path27 = require("node:path");
25905
25969
  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}$/;
25906
25970
  var MAX_BYTES = 5 * 1024 * 1024 * 1024;
25907
25971
  async function sha256File(path2) {
@@ -25911,7 +25975,7 @@ async function sha256File(path2) {
25911
25975
  }
25912
25976
  async function putTenantArtifact(repo, stage, inputPath, deps) {
25913
25977
  if (!["dev", "rc", "main"].includes(stage)) throw new Error("tenant artifact put: <stage> must be dev, rc, or main");
25914
- const path2 = (0, import_node_path26.resolve)(inputPath);
25978
+ const path2 = (0, import_node_path27.resolve)(inputPath);
25915
25979
  const info = await (0, import_promises5.stat)(path2);
25916
25980
  if (!info.isFile()) throw new Error("tenant artifact put: input path must be a file");
25917
25981
  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`);
@@ -27048,7 +27112,7 @@ async function announceRelease(deps, args) {
27048
27112
  var import_node_crypto5 = require("node:crypto");
27049
27113
  var import_node_child_process13 = require("node:child_process");
27050
27114
  var import_node_fs29 = require("node:fs");
27051
- var import_node_path27 = require("node:path");
27115
+ var import_node_path28 = require("node:path");
27052
27116
  var REPO_INDEX_SCHEMA = 1;
27053
27117
  var HARD_DENY = [
27054
27118
  /(^|\/)\.env(\.|$)/i,
@@ -27173,7 +27237,7 @@ function loadReadmeHints(cwd, candidatePaths) {
27173
27237
  }
27174
27238
  for (const rel of readmes) {
27175
27239
  if (isHardDeniedPath(rel)) continue;
27176
- const abs = (0, import_node_path27.join)(cwd, ...rel.split("/"));
27240
+ const abs = (0, import_node_path28.join)(cwd, ...rel.split("/"));
27177
27241
  if (!(0, import_node_fs29.existsSync)(abs)) continue;
27178
27242
  let text;
27179
27243
  try {
@@ -27190,7 +27254,7 @@ function loadReadmeHints(cwd, candidatePaths) {
27190
27254
  return hints;
27191
27255
  }
27192
27256
  function toPosix(p) {
27193
- return p.split(import_node_path27.sep).join("/");
27257
+ return p.split(import_node_path28.sep).join("/");
27194
27258
  }
27195
27259
  function listCandidatePaths(cwd, exec = import_node_child_process13.execFileSync) {
27196
27260
  try {
@@ -27212,7 +27276,7 @@ function rebuildRepoIndex(cwd, repoSlug2) {
27212
27276
  for (const rel of candidates) {
27213
27277
  if (ignored.has(rel)) continue;
27214
27278
  if (isHardDeniedPath(rel)) continue;
27215
- const abs = (0, import_node_path27.join)(cwd, ...rel.split("/"));
27279
+ const abs = (0, import_node_path28.join)(cwd, ...rel.split("/"));
27216
27280
  if (!(0, import_node_fs29.existsSync)(abs)) continue;
27217
27281
  let text;
27218
27282
  try {
@@ -27241,7 +27305,7 @@ function rebuildRepoIndex(cwd, repoSlug2) {
27241
27305
  entries
27242
27306
  };
27243
27307
  const store = repoIndexStorePath(cwd);
27244
- (0, import_node_fs29.mkdirSync)((0, import_node_path27.dirname)(store), { recursive: true });
27308
+ (0, import_node_fs29.mkdirSync)((0, import_node_path28.dirname)(store), { recursive: true });
27245
27309
  (0, import_node_fs29.writeFileSync)(store, `${JSON.stringify(projection, null, 2)}
27246
27310
  `, "utf8");
27247
27311
  return projection;
@@ -27322,7 +27386,7 @@ function inferRepoSlug(cwd, exec = import_node_child_process13.execFileSync) {
27322
27386
  if (m?.[1]) return m[1].toLowerCase();
27323
27387
  } catch {
27324
27388
  }
27325
- return ((0, import_node_path27.basename)(cwd) || "local").toLowerCase();
27389
+ return ((0, import_node_path28.basename)(cwd) || "local").toLowerCase();
27326
27390
  }
27327
27391
 
27328
27392
  // src/repo-index-cloud-client.ts
@@ -27464,7 +27528,7 @@ async function gcRepoIndexCloud(deps) {
27464
27528
  // src/repo-index-sync.ts
27465
27529
  var import_node_fs30 = require("node:fs");
27466
27530
  var import_node_os12 = require("node:os");
27467
- var import_node_path28 = require("node:path");
27531
+ var import_node_path29 = require("node:path");
27468
27532
  var import_node_child_process14 = require("node:child_process");
27469
27533
  var MAX_EMBED_BACKFILL_ROUNDS = 40;
27470
27534
  function normalizeRepo(raw) {
@@ -27508,7 +27572,7 @@ async function syncEstateRepoIndex(opts) {
27508
27572
  const failed = [];
27509
27573
  const skipped = [];
27510
27574
  for (const repo of repos) {
27511
- const dir = (0, import_node_fs30.mkdtempSync)((0, import_node_path28.join)((0, import_node_os12.tmpdir)(), "mmi-repo-index-"));
27575
+ const dir = (0, import_node_fs30.mkdtempSync)((0, import_node_path29.join)((0, import_node_os12.tmpdir)(), "mmi-repo-index-"));
27512
27576
  try {
27513
27577
  shallowClone(repo, dir, opts.githubToken);
27514
27578
  const built = rebuildRepoIndex(dir, repo);
@@ -27764,7 +27828,7 @@ async function runRepoIndexHealth(opts) {
27764
27828
  // src/spawn-policy-core.ts
27765
27829
  var import_node_child_process15 = require("node:child_process");
27766
27830
  var import_node_fs32 = require("node:fs");
27767
- var import_node_path29 = require("node:path");
27831
+ var import_node_path30 = require("node:path");
27768
27832
  var SPAWNERS = ["spawn", "spawnSync", "exec", "execSync", "execFile", "execFileSync"];
27769
27833
  var CALL_SOURCE = String.raw`(^|[^.\w$])(${SPAWNERS.join("|")})\s*\(`;
27770
27834
  var SOURCE_EXT = /\.(ts|mts|cts|js|mjs|cjs)$/;
@@ -27850,7 +27914,7 @@ function runSpawnPolicy(root) {
27850
27914
  for (const file of files) {
27851
27915
  let raw;
27852
27916
  try {
27853
- raw = (0, import_node_fs32.readFileSync)((0, import_node_path29.join)(root, file), "utf8");
27917
+ raw = (0, import_node_fs32.readFileSync)((0, import_node_path30.join)(root, file), "utf8");
27854
27918
  } catch {
27855
27919
  continue;
27856
27920
  }
@@ -27869,7 +27933,7 @@ function runSpawnPolicy(root) {
27869
27933
  // src/test-policy-core.ts
27870
27934
  var import_node_child_process16 = require("node:child_process");
27871
27935
  var import_node_fs33 = require("node:fs");
27872
- var import_node_path30 = require("node:path");
27936
+ var import_node_path31 = require("node:path");
27873
27937
  var POLICY_FILE = "test-policy.json";
27874
27938
  var TEST_RE = /\.(?:test|spec)\.[cm]?[jt]sx?$/;
27875
27939
  var PY_TEST_RE = /(?:^|\/)test_[^/]*\.py$|_test\.py$/;
@@ -27922,7 +27986,7 @@ function isTestPath(path2) {
27922
27986
  return TEST_RE.test(path2) || PY_TEST_RE.test(path2);
27923
27987
  }
27924
27988
  function loadPolicy(root, readFile9 = readFileOrNull2) {
27925
- const raw = readFile9((0, import_node_path30.join)(root, POLICY_FILE));
27989
+ const raw = readFile9((0, import_node_path31.join)(root, POLICY_FILE));
27926
27990
  if (raw == null) return { mandatory: [], declared: false };
27927
27991
  try {
27928
27992
  return { ...JSON.parse(raw), declared: true };
@@ -27960,11 +28024,11 @@ function classify(changed, policy, present = () => false) {
27960
28024
  return { mandatoryHits, untestedHits, testChanges, addedTests, removedProtected };
27961
28025
  }
27962
28026
  function unresolvedProtectedEntries(policy, root, exists = (path2) => (0, import_node_fs33.existsSync)(path2)) {
27963
- return (policy.protected ?? []).map((p) => p.path).filter((p) => !exists((0, import_node_path30.join)(root, p)));
28027
+ return (policy.protected ?? []).map((p) => p.path).filter((p) => !exists((0, import_node_path31.join)(root, p)));
27964
28028
  }
27965
28029
  function unresolvedSatisfiers(policy, root, exists = (path2) => (0, import_node_fs33.existsSync)(path2)) {
27966
28030
  const declared = (policy.mandatory ?? []).flatMap((m) => m.satisfiedBy ?? []);
27967
- return [...new Set(declared)].filter((p) => !exists((0, import_node_path30.join)(root, p)));
28031
+ return [...new Set(declared)].filter((p) => !exists((0, import_node_path31.join)(root, p)));
27968
28032
  }
27969
28033
  function evaluate(changed, policy, present = () => false) {
27970
28034
  const { mandatoryHits, untestedHits, testChanges, addedTests, removedProtected } = classify(changed, policy, present);
@@ -28152,7 +28216,7 @@ function runTestPolicy(root, deps = {}) {
28152
28216
  const refusal = deps.changed ? null : untrustworthyRange(root, base);
28153
28217
  const changed = deps.changed ?? (refusal ? [] : changedFilesSince(base, root));
28154
28218
  const lookup = deps.override !== void 0 ? { override: deps.override, refusals: [] } : !deps.changed && !refusal ? readOverride(base, root) : { override: null, refusals: [] };
28155
- const present = (path2) => exists((0, import_node_path30.join)(root, path2));
28219
+ const present = (path2) => exists((0, import_node_path31.join)(root, path2));
28156
28220
  const removedByThisDiff = removedPaths(changed);
28157
28221
  const staleFindings = [];
28158
28222
  const unresolved = unresolvedProtectedEntries(policy, root, exists).filter((p) => !removedByThisDiff.has(p));
@@ -28191,7 +28255,7 @@ function runTestPolicy(root, deps = {}) {
28191
28255
 
28192
28256
  // src/project-info-sync.ts
28193
28257
  var import_node_fs34 = require("node:fs");
28194
- var import_node_path31 = require("node:path");
28258
+ var import_node_path32 = require("node:path");
28195
28259
  var UPDATE_PROJECT_INFO = `mutation($projectId: ID!, $shortDescription: String!, $readme: String!) {
28196
28260
  updateProjectV2(input: { projectId: $projectId, shortDescription: $shortDescription, readme: $readme }) {
28197
28261
  projectV2 { id }
@@ -28236,7 +28300,7 @@ function sharedName(entries, fallback) {
28236
28300
  }
28237
28301
  function buildProjectInfoSyncPlan(targetRepo2, project2, projects, repoRoot2) {
28238
28302
  if (!project2.projectId) throw new Error(`org project sync-info: ${targetRepo2} registry META has no projectId`);
28239
- const readmePath = (0, import_node_path31.join)(repoRoot2, "README.md");
28303
+ const readmePath = (0, import_node_path32.join)(repoRoot2, "README.md");
28240
28304
  if (!(0, import_node_fs34.existsSync)(readmePath)) throw new Error(`org project sync-info: ${targetRepo2} has no README.md`);
28241
28305
  const entries = entriesFor(project2, projects);
28242
28306
  const memberRepos = [...new Set(entries.flatMap((entry) => entry.repos ?? []))].filter((repo) => /^[^/]+\/[^/]+$/.test(repo)).sort((a, b) => a.localeCompare(b));
@@ -28262,8 +28326,8 @@ function buildProjectInfoSyncPlan(targetRepo2, project2, projects, repoRoot2) {
28262
28326
  const targetBase = `https://github.com/${targetRepo2}`;
28263
28327
  const targetBranch = branchFor(targetRepo2, projects);
28264
28328
  const orgDocs = [
28265
- (0, import_node_fs34.existsSync)((0, import_node_path31.join)(repoRoot2, "docs", "org-readme.md")) ? `- [Org identity](${targetBase}/blob/${targetBranch}/docs/org-readme.md)` : "",
28266
- (0, import_node_fs34.existsSync)((0, import_node_path31.join)(repoRoot2, "docs", "org-architecture.md")) ? `- [Org architecture](${targetBase}/blob/${targetBranch}/docs/org-architecture.md)` : ""
28329
+ (0, import_node_fs34.existsSync)((0, import_node_path32.join)(repoRoot2, "docs", "org-readme.md")) ? `- [Org identity](${targetBase}/blob/${targetBranch}/docs/org-readme.md)` : "",
28330
+ (0, import_node_fs34.existsSync)((0, import_node_path32.join)(repoRoot2, "docs", "org-architecture.md")) ? `- [Org architecture](${targetBase}/blob/${targetBranch}/docs/org-architecture.md)` : ""
28267
28331
  ].filter(Boolean);
28268
28332
  if (orgDocs.length) lines.push("", "## Organisation docs", "", ...orgDocs);
28269
28333
  return { projectId: project2.projectId, projectName, targetRepo: targetRepo2, memberRepos, shortDescription, readme: `${lines.join("\n")}
@@ -29090,7 +29154,7 @@ function writeError(res) {
29090
29154
 
29091
29155
  // src/secrets-commands.ts
29092
29156
  var import_node_fs35 = require("node:fs");
29093
- var import_node_path32 = require("node:path");
29157
+ var import_node_path33 = require("node:path");
29094
29158
  var import_node_os13 = require("node:os");
29095
29159
 
29096
29160
  // src/secrets-diff.ts
@@ -29193,11 +29257,11 @@ function collectMap(value, previous = []) {
29193
29257
  return [...previous, value];
29194
29258
  }
29195
29259
  async function decryptRailsCredentials(input) {
29196
- const appDir = (0, import_node_path32.resolve)(input.appDir ?? process.cwd());
29260
+ const appDir = (0, import_node_path33.resolve)(input.appDir ?? process.cwd());
29197
29261
  const credentialsFile = input.credentialsFile ?? DEFAULT_RAILS_CREDENTIALS_FILE;
29198
29262
  const masterKeyFile = input.masterKeyFile ?? DEFAULT_RAILS_MASTER_KEY_FILE;
29199
- const credentialsPath = (0, import_node_path32.resolve)(appDir, credentialsFile);
29200
- const masterKeyPath = (0, import_node_path32.resolve)(appDir, masterKeyFile);
29263
+ const credentialsPath = (0, import_node_path33.resolve)(appDir, credentialsFile);
29264
+ const masterKeyPath = (0, import_node_path33.resolve)(appDir, masterKeyFile);
29201
29265
  const env = {
29202
29266
  ...process.env,
29203
29267
  MMI_RAILS_CREDENTIALS_FILE: credentialsPath,
@@ -29214,8 +29278,8 @@ async function decryptRailsCredentials(input) {
29214
29278
  'config = ActiveSupport::EncryptedConfiguration.new(config_path: config_path, key_path: key_path, env_key: "RAILS_MASTER_KEY", raise_if_missing_key: true)',
29215
29279
  "puts JSON.generate(config.config)"
29216
29280
  ].join("\n");
29217
- const scriptDir = (0, import_node_fs35.mkdtempSync)((0, import_node_path32.join)((0, import_node_os13.tmpdir)(), "mmi-rails-decrypt-"));
29218
- const scriptPath = (0, import_node_path32.join)(scriptDir, "decrypt.rb");
29281
+ const scriptDir = (0, import_node_fs35.mkdtempSync)((0, import_node_path33.join)((0, import_node_os13.tmpdir)(), "mmi-rails-decrypt-"));
29282
+ const scriptPath = (0, import_node_path33.join)(scriptDir, "decrypt.rb");
29219
29283
  (0, import_node_fs35.writeFileSync)(scriptPath, script, "utf8");
29220
29284
  try {
29221
29285
  const args = ["exec", "ruby", scriptPath];
@@ -29318,7 +29382,7 @@ function registerSecretsCommands(program3) {
29318
29382
  let body;
29319
29383
  if (o.file) {
29320
29384
  try {
29321
- body = (0, import_node_fs35.readFileSync)((0, import_node_path32.resolve)(o.file), "utf8");
29385
+ body = (0, import_node_fs35.readFileSync)((0, import_node_path33.resolve)(o.file), "utf8");
29322
29386
  } catch (e) {
29323
29387
  return fail(`secrets org-catalog: cannot read --file ${o.file}: ${e.message}`);
29324
29388
  }
@@ -29423,7 +29487,7 @@ function registerSecretsCommands(program3) {
29423
29487
  {
29424
29488
  ...d,
29425
29489
  decryptRailsCredentials,
29426
- removeFile: (path2) => (0, import_node_fs35.unlinkSync)((0, import_node_path32.resolve)(o.appDir ?? process.cwd(), path2))
29490
+ removeFile: (path2) => (0, import_node_fs35.unlinkSync)((0, import_node_path33.resolve)(o.appDir ?? process.cwd(), path2))
29427
29491
  },
29428
29492
  {
29429
29493
  repo: o.repo,
@@ -29877,8 +29941,8 @@ async function repoWorkflowEntries(client, repo) {
29877
29941
  for (const wf of workflowsList) {
29878
29942
  if (typeof wf?.path !== "string" || !wf.path) continue;
29879
29943
  if (!wf.path.startsWith(".github/workflows/")) continue;
29880
- const basename6 = wf.path.split("/").pop() ?? wf.path;
29881
- const name = `${repo}/${basename6.replace(/\.ya?ml$/, "")}`;
29944
+ const basename8 = wf.path.split("/").pop() ?? wf.path;
29945
+ const name = `${repo}/${basename8.replace(/\.ya?ml$/, "")}`;
29882
29946
  if (wf.state !== "active") {
29883
29947
  disabled.push(name);
29884
29948
  continue;
@@ -30150,7 +30214,7 @@ function registerSchedulesCommands(program3) {
30150
30214
 
30151
30215
  // src/schedules-lift-command.ts
30152
30216
  var import_promises7 = require("node:fs/promises");
30153
- var import_node_path33 = require("node:path");
30217
+ var import_node_path34 = require("node:path");
30154
30218
  var DEFAULT_WORKFLOWS_DIR = ".github/workflows";
30155
30219
  var SCHEDULE_REPO_RE = /^[A-Za-z0-9_.-]+$/;
30156
30220
  var SchedulesLiftUsageError = class extends Error {
@@ -30177,7 +30241,7 @@ async function readWorkflowFiles(dir) {
30177
30241
  const files = [];
30178
30242
  for (const name of names.sort()) {
30179
30243
  if (!/\.ya?ml$/.test(name)) continue;
30180
- files.push({ path: `.github/workflows/${name}`, text: await (0, import_promises7.readFile)((0, import_node_path33.join)(dir, name), "utf8") });
30244
+ files.push({ path: `.github/workflows/${name}`, text: await (0, import_promises7.readFile)((0, import_node_path34.join)(dir, name), "utf8") });
30181
30245
  }
30182
30246
  return files;
30183
30247
  }
@@ -30327,7 +30391,7 @@ function registerEdgeCommands(program3) {
30327
30391
  // src/bootstrap-commands.ts
30328
30392
  var import_node_fs37 = require("node:fs");
30329
30393
  var import_node_os14 = require("node:os");
30330
- var import_node_path34 = require("node:path");
30394
+ var import_node_path35 = require("node:path");
30331
30395
 
30332
30396
  // src/bootstrap-drift.ts
30333
30397
  var import_node_crypto7 = require("node:crypto");
@@ -31369,7 +31433,7 @@ function registerBootstrapCommands(program3) {
31369
31433
  const readFile9 = (p) => (0, import_node_fs37.existsSync)(p) ? (0, import_node_fs37.readFileSync)(p, "utf8") : null;
31370
31434
  const enc = (p) => p.split("/").map(encodeURIComponent).join("/");
31371
31435
  const putSeed = async (target, content, ref, sha) => {
31372
- const tmp = (0, import_node_path34.join)((0, import_node_os14.tmpdir)(), `mmi-seed-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
31436
+ const tmp = (0, import_node_path35.join)((0, import_node_os14.tmpdir)(), `mmi-seed-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
31373
31437
  (0, import_node_fs37.writeFileSync)(tmp, JSON.stringify(contentPutBody(target, content, ref, sha)), "utf8");
31374
31438
  try {
31375
31439
  await gh(contentPutInputArgs(repo, target, tmp));
@@ -31780,7 +31844,7 @@ LIVE apply to ${repo}:
31780
31844
  } catch {
31781
31845
  existingSha = void 0;
31782
31846
  }
31783
- const tmp = (0, import_node_path34.join)((0, import_node_os14.tmpdir)(), `mmi-propagate-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
31847
+ const tmp = (0, import_node_path35.join)((0, import_node_os14.tmpdir)(), `mmi-propagate-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
31784
31848
  (0, import_node_fs37.writeFileSync)(tmp, JSON.stringify(contentPutBody(seed.target, hubContent, branch, existingSha)), "utf8");
31785
31849
  try {
31786
31850
  await gh(contentPutInputArgs(rec.repo, seed.target, tmp));
@@ -31936,7 +32000,7 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
31936
32000
  } catch {
31937
32001
  existingSha = void 0;
31938
32002
  }
31939
- const tmp = (0, import_node_path34.join)((0, import_node_os14.tmpdir)(), `mmi-rollback-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
32003
+ const tmp = (0, import_node_path35.join)((0, import_node_os14.tmpdir)(), `mmi-rollback-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
31940
32004
  (0, import_node_fs37.writeFileSync)(tmp, JSON.stringify(contentPutBody(seed.target, preSeedContent, plan.branch, existingSha)), "utf8");
31941
32005
  try {
31942
32006
  await gh(contentPutInputArgs(repo, seed.target, tmp));
@@ -31965,11 +32029,11 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
31965
32029
 
31966
32030
  // src/stage-commands.ts
31967
32031
  var import_node_fs39 = require("node:fs");
31968
- var import_node_path36 = require("node:path");
32032
+ var import_node_path37 = require("node:path");
31969
32033
 
31970
32034
  // src/port-registry.ts
31971
32035
  var import_node_fs38 = require("node:fs");
31972
- var import_node_path35 = require("node:path");
32036
+ var import_node_path36 = require("node:path");
31973
32037
 
31974
32038
  // ../infra/port-geometry.mjs
31975
32039
  var PORT_BLOCK = 100;
@@ -32022,22 +32086,22 @@ function existingPortRange(repo, registry2) {
32022
32086
  return registry2[repo] ?? null;
32023
32087
  }
32024
32088
  function portRangeInfraAt(root, source) {
32025
- const registryPath = (0, import_node_path35.join)(root, "infra", "port-ranges.json");
32026
- const ddbScriptPath = (0, import_node_path35.join)(root, "infra", "port-ddb.mjs");
32089
+ const registryPath = (0, import_node_path36.join)(root, "infra", "port-ranges.json");
32090
+ const ddbScriptPath = (0, import_node_path36.join)(root, "infra", "port-ddb.mjs");
32027
32091
  if (!(0, import_node_fs38.existsSync)(registryPath) || !(0, import_node_fs38.existsSync)(ddbScriptPath)) return null;
32028
32092
  return { root, source, registryPath, ddbScriptPath };
32029
32093
  }
32030
32094
  function resolvePortRangeInfra(cwd, packageDir) {
32031
32095
  const direct = portRangeInfraAt(cwd, "cwd");
32032
32096
  if (direct) return direct;
32033
- for (let dir = cwd; ; dir = (0, import_node_path35.dirname)(dir)) {
32034
- const sibling = portRangeInfraAt((0, import_node_path35.join)(dir, "MMI-Hub"), "sibling-hub");
32097
+ for (let dir = cwd; ; dir = (0, import_node_path36.dirname)(dir)) {
32098
+ const sibling = portRangeInfraAt((0, import_node_path36.join)(dir, "MMI-Hub"), "sibling-hub");
32035
32099
  if (sibling) return sibling;
32036
- const parent = (0, import_node_path35.dirname)(dir);
32100
+ const parent = (0, import_node_path36.dirname)(dir);
32037
32101
  if (parent === dir) break;
32038
32102
  }
32039
32103
  if (packageDir) {
32040
- const pkgRoot = (0, import_node_path35.join)(packageDir, "..", "..");
32104
+ const pkgRoot = (0, import_node_path36.join)(packageDir, "..", "..");
32041
32105
  const pkgFrom = portRangeInfraAt(pkgRoot, "pkg-root");
32042
32106
  if (pkgFrom) return pkgFrom;
32043
32107
  }
@@ -32231,8 +32295,8 @@ function registerStageCommands(program3) {
32231
32295
  const portRange = portRangeMeta && typeof portRangeMeta.start === "number" && typeof portRangeMeta.end === "number" ? [portRangeMeta.start, portRangeMeta.end] : void 0;
32232
32296
  return decideStage({
32233
32297
  registry: { deployModel: project2?.deployModel, portRange, error: read.ok ? void 0 : read.error },
32234
- hasCompose: (0, import_node_fs39.existsSync)((0, import_node_path36.join)(process.cwd(), "docker-compose.yml")),
32235
- hasEnvExample: (0, import_node_fs39.existsSync)((0, import_node_path36.join)(process.cwd(), ".env.example"))
32298
+ hasCompose: (0, import_node_fs39.existsSync)((0, import_node_path37.join)(process.cwd(), "docker-compose.yml")),
32299
+ hasEnvExample: (0, import_node_fs39.existsSync)((0, import_node_path37.join)(process.cwd(), ".env.example"))
32236
32300
  });
32237
32301
  }
32238
32302
  async function fetchStageVaultEnvMerge() {
@@ -32503,8 +32567,7 @@ function registerBoardCommands(program3) {
32503
32567
  repo: o.repo,
32504
32568
  includeBundleDetails: o.bundleDetails,
32505
32569
  includeAllBodies: o.bodies,
32506
- allowPartial: o.allowPartial,
32507
- live: o.live
32570
+ allowPartial: o.allowPartial
32508
32571
  });
32509
32572
  console.log(o.json ? JSON.stringify(report) : renderBoardReport(report));
32510
32573
  } catch (e) {
@@ -32515,7 +32578,7 @@ function registerBoardCommands(program3) {
32515
32578
  return alreadyClaimed ? `Check ${ref}: claimed and In Progress, no live contest - claim would renew the lease (nothing written)` : `Check ${ref}: free - claim would proceed (nothing written)`;
32516
32579
  }
32517
32580
  const board = program3.command("board").description("read, claim, show, and move Project v2 work items for the current repo");
32518
- board.command("read", { isDefault: true }).description("read the board and print user-owned, claimable, and taken items").option("--json", "machine-readable output").option("--repo <owner/repo>", "current repo (defaults to git origin)").option("--bundle-details", "fetch body/comments only for user-owned and claimable issues").option("--bodies", "fetch body/comments for EVERY scoped row, including taken and unowned in-flight ones \u2014 for consumers that scope by Status rather than ownership (#4861); implies --bundle-details and costs one extra read per row").option("--allow-partial", "return partial board results when later page/detail reads fail").option("--live", "bypass the projection and read the authoritative GitHub Project v2 board").addHelpText("after", "\nBy default, read uses the explicitly-stale Hub projection and prints its watermark. --live is authoritative.\n--allow-partial applies to the live paginated path and detail reads; the projection row itself is atomic.\n").action((o) => runBoardRead(o));
32581
+ board.command("read", { isDefault: true }).description("read the board and print user-owned, claimable, and taken items").option("--json", "machine-readable output").option("--repo <owner/repo>", "current repo (defaults to git origin)").option("--bundle-details", "fetch body/comments only for user-owned and claimable issues").option("--bodies", "fetch body/comments for EVERY scoped row, including taken and unowned in-flight ones \u2014 for consumers that scope by Status rather than ownership (#4861); implies --bundle-details and costs one extra read per row").option("--allow-partial", "return partial board results when later page/detail reads fail").addHelpText("after", "\nread is always the authoritative live GitHub Project v2 board (#4926).\n--allow-partial applies to the paginated path and detail reads.\n").action((o) => runBoardRead(o));
32519
32582
  withExamples(mutating(
32520
32583
  board.command("claim <issues...>").description("claim issues: assign them and move their Project v2 Status to In Progress \u2014 idempotent, so an item already yours and In Progress succeeds unchanged (one or more refs)").option("--json", "machine-readable output").option("--repo <owner/repo>", "current repo for local issue numbers (defaults to git origin)").option("--for <login>", "assign to this login instead of @me \u2014 agent claims on behalf of the master").option("--force", "take an item already claimed by another lane that shows live evidence of active work (#3727)").option("--check", "read-only: run every claim gate and report the verdict, writing nothing \u2014 exits 1 with the same refusal a real claim would raise (#4511)").option("--allow-partial", "return success JSON if assignment succeeds but the status move fails"),
32521
32584
  (_opts, args) => ({ command: "board claim", issues: args[0] ?? [] })
@@ -32726,7 +32789,7 @@ function registerBoardCommands(program3) {
32726
32789
  // src/merge-cleanup.ts
32727
32790
  var import_node_fs40 = require("node:fs");
32728
32791
  var import_promises9 = require("node:fs/promises");
32729
- var import_node_path38 = require("node:path");
32792
+ var import_node_path39 = require("node:path");
32730
32793
  var import_node_os15 = require("node:os");
32731
32794
  var import_node_child_process18 = require("node:child_process");
32732
32795
 
@@ -32814,7 +32877,7 @@ function boardAdvanceFailureMessage(result) {
32814
32877
 
32815
32878
  // src/deferred-registry-store.ts
32816
32879
  var import_promises8 = require("node:fs/promises");
32817
- var import_node_path37 = require("node:path");
32880
+ var import_node_path38 = require("node:path");
32818
32881
  var sleep2 = (ms) => new Promise((resolve6) => setTimeout(resolve6, ms));
32819
32882
  async function atomicWrite(target, contents) {
32820
32883
  const tmp = `${target}.tmp-${process.pid}-${Math.random().toString(36).slice(2)}`;
@@ -32865,12 +32928,12 @@ function makeDeferredWorktreeStore(registryPath, lockOpts = {}) {
32865
32928
  },
32866
32929
  // Standalone atomic write — THROWS on failure (no best-effort swallow, #2846).
32867
32930
  write: async (entries) => {
32868
- await (0, import_promises8.mkdir)((0, import_node_path37.dirname)(registryPath), { recursive: true });
32931
+ await (0, import_promises8.mkdir)((0, import_node_path38.dirname)(registryPath), { recursive: true });
32869
32932
  await atomicWrite(registryPath, serializeDeferredWorktrees(entries));
32870
32933
  },
32871
32934
  // Serialized read-modify-write under the repo-wide lock (#2846).
32872
32935
  update: async (mutate) => {
32873
- await (0, import_promises8.mkdir)((0, import_node_path37.dirname)(registryPath), { recursive: true });
32936
+ await (0, import_promises8.mkdir)((0, import_node_path38.dirname)(registryPath), { recursive: true });
32874
32937
  const deadline = Date.now() + opts.maxWaitMs;
32875
32938
  for (; ; ) {
32876
32939
  const guard = await acquireLock(lockPath, opts, deadline);
@@ -33034,6 +33097,23 @@ ${err.stderr ?? ""}`;
33034
33097
  return { step, status: `failed: ${msg}` };
33035
33098
  }
33036
33099
  }
33100
+ async function bestEffortCloseMissingWorktreeLeases(leaseDir = (0, import_node_path39.join)((0, import_node_os15.homedir)(), ".jerv", "leases"), exists = import_node_fs40.existsSync) {
33101
+ let names = [];
33102
+ try {
33103
+ names = (0, import_node_fs40.readdirSync)(leaseDir);
33104
+ } catch {
33105
+ return;
33106
+ }
33107
+ for (const name of names) {
33108
+ if (!name.endsWith(".json")) continue;
33109
+ try {
33110
+ const rec = JSON.parse((0, import_node_fs40.readFileSync)((0, import_node_path39.join)(leaseDir, name), "utf8"));
33111
+ if (rec.kind !== "worktree" || rec.state === "closed" || typeof rec.ref !== "string" || !rec.ref.trim()) continue;
33112
+ if (!exists(rec.ref)) await bestEffortLeaseClose(rec.ref);
33113
+ } catch {
33114
+ }
33115
+ }
33116
+ }
33037
33117
  async function applyGcPlan(plan, remote, opts = {}) {
33038
33118
  const result = { removedBranches: [], removedRemoteBranches: [], removedTrackingRefs: [], removedWorktreeDirs: [], refused: [], failed: [], pruned: false };
33039
33119
  const beforeWorktrees = parseWorktreePorcelain(
@@ -33041,7 +33121,7 @@ async function applyGcPlan(plan, remote, opts = {}) {
33041
33121
  );
33042
33122
  const repoRoot2 = (await execFileP2("git", ["rev-parse", "--show-toplevel"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim() || process.cwd();
33043
33123
  const worktreeGitRoot = await currentRepoWorktreeGitRoot(repoRoot2);
33044
- const primaryRepoRoot = worktreeGitRoot ? (0, import_node_path38.dirname)((0, import_node_path38.dirname)(worktreeGitRoot)) : repoRoot2;
33124
+ const primaryRepoRoot = worktreeGitRoot ? (0, import_node_path39.dirname)((0, import_node_path39.dirname)(worktreeGitRoot)) : repoRoot2;
33045
33125
  const gcActor = describeActor({ env: process.env, surface: detectSurface(process.env), cwd: process.cwd() });
33046
33126
  const owners = readWorktreeOwners(primaryRepoRoot);
33047
33127
  const removalNow = Date.now();
@@ -33050,7 +33130,9 @@ async function applyGcPlan(plan, remote, opts = {}) {
33050
33130
  const activeWorkspaceDeferred = [];
33051
33131
  const refusesRemoval = (path2, branch) => {
33052
33132
  if (!path2) return false;
33053
- const activeGuard = decideActiveWorkspaceGuard(path2, activeWorkspaceRoot);
33133
+ const activeGuard = decideActiveWorkspaceGuard(path2, activeWorkspaceRoot, process.platform, {
33134
+ cursorAgentHost: isCursorAgentHost()
33135
+ });
33054
33136
  if (activeGuard.action === "refuse") {
33055
33137
  result.refused.push(activeGuard.message);
33056
33138
  const owner2 = findWorktreeOwner(owners, path2);
@@ -33129,7 +33211,8 @@ async function applyGcPlan(plan, remote, opts = {}) {
33129
33211
  const removeDeps = worktreeRemoveDeps(async (args) => (await execFileP2("git", args, { timeout: GIT_TIMEOUT_MS })).stdout);
33130
33212
  const cleanupRoots = [
33131
33213
  opts.root ? resolveExplicitScanRoot(opts.root, primaryRepoRoot) : siblingMmiWorktreesRoot(primaryRepoRoot),
33132
- agentWorktreesRoot(primaryRepoRoot)
33214
+ agentWorktreesRoot(primaryRepoRoot),
33215
+ ...helperWorktreeRoots(primaryRepoRoot)
33133
33216
  ];
33134
33217
  for (const wt of worktreeDirsToRemove) {
33135
33218
  const owner = findWorktreeOwner(owners, wt.path);
@@ -33181,12 +33264,27 @@ async function applyGcPlan(plan, remote, opts = {}) {
33181
33264
  }
33182
33265
  }
33183
33266
  }
33267
+ for (const head of plan.reapOriginHeads ?? []) {
33268
+ try {
33269
+ await execFileP2("git", ["push", remote, "--delete", head.branch], { timeout: GIT_TIMEOUT_MS });
33270
+ result.removedRemoteBranches.push(head.branch);
33271
+ } catch (e) {
33272
+ const detail = `${e.message}
33273
+ ${e.stderr ?? ""}`;
33274
+ if (/not found|does not exist|unable to delete|remote ref does not exist/i.test(detail)) {
33275
+ result.removedRemoteBranches.push(head.branch);
33276
+ } else {
33277
+ result.failed.push(`${head.branch}: origin delete failed (${e.message.split("\n")[0]})`);
33278
+ }
33279
+ }
33280
+ }
33184
33281
  try {
33185
33282
  await execFileP2("git", ["worktree", "prune"], { timeout: GIT_TIMEOUT_MS });
33186
33283
  result.pruned = true;
33187
33284
  } catch (e) {
33188
33285
  result.failed.push(`worktree prune: ${e.message.split("\n")[0]}`);
33189
33286
  }
33287
+ await bestEffortCloseMissingWorktreeLeases();
33190
33288
  return result;
33191
33289
  }
33192
33290
  async function pollGhPrChecks(prNumber, repoArgs) {
@@ -33223,8 +33321,8 @@ async function composeOverrideBodyFile(prNumber, repoArgs, gh) {
33223
33321
  const commits = JSON.parse(raw).commits ?? [];
33224
33322
  const body = squashBodyWithOverride(commits.map((c) => ({ headline: c.messageHeadline ?? "", body: c.messageBody ?? "" })), process.cwd());
33225
33323
  if (!body) return void 0;
33226
- const dir = (0, import_node_fs40.mkdtempSync)((0, import_node_path38.join)((0, import_node_os15.tmpdir)(), "mmi-squash-body-"));
33227
- const path2 = (0, import_node_path38.join)(dir, "body.txt");
33324
+ const dir = (0, import_node_fs40.mkdtempSync)((0, import_node_path39.join)((0, import_node_os15.tmpdir)(), "mmi-squash-body-"));
33325
+ const path2 = (0, import_node_path39.join)(dir, "body.txt");
33228
33326
  (0, import_node_fs40.writeFileSync)(path2, `${body}
33229
33327
  `, "utf8");
33230
33328
  return { path: path2, cleanup: () => {
@@ -33349,15 +33447,16 @@ async function createDeferredWorktreeStore() {
33349
33447
  }
33350
33448
  var realWorktreeDirRemover = {
33351
33449
  probe: (p) => {
33450
+ const target = win32LongPath(p);
33352
33451
  let st;
33353
33452
  try {
33354
- st = (0, import_node_fs40.lstatSync)(p);
33453
+ st = (0, import_node_fs40.lstatSync)(target);
33355
33454
  } catch {
33356
33455
  return null;
33357
33456
  }
33358
33457
  if (st.isSymbolicLink()) return "link";
33359
33458
  try {
33360
- (0, import_node_fs40.readlinkSync)(p);
33459
+ (0, import_node_fs40.readlinkSync)(target);
33361
33460
  return "link";
33362
33461
  } catch {
33363
33462
  }
@@ -33365,7 +33464,7 @@ var realWorktreeDirRemover = {
33365
33464
  },
33366
33465
  readdir: (p) => {
33367
33466
  try {
33368
- return (0, import_node_fs40.readdirSync)(p);
33467
+ return (0, import_node_fs40.readdirSync)(win32LongPath(p));
33369
33468
  } catch {
33370
33469
  return [];
33371
33470
  }
@@ -33373,13 +33472,16 @@ var realWorktreeDirRemover = {
33373
33472
  // A directory reparse point (junction / dir-symlink) is detached with rmdir (unlinks the mount point,
33374
33473
  // leaving the target); a file symlink with unlink. rmdir first, fall back to unlink.
33375
33474
  detachLink: (p) => {
33475
+ const target = win32LongPath(p);
33376
33476
  try {
33377
- (0, import_node_fs40.rmdirSync)(p);
33477
+ (0, import_node_fs40.rmdirSync)(target);
33378
33478
  } catch {
33379
- (0, import_node_fs40.unlinkSync)(p);
33479
+ (0, import_node_fs40.unlinkSync)(target);
33380
33480
  }
33381
33481
  },
33382
- removeTree: (p) => (0, import_promises9.rm)(p, { recursive: true, force: true, maxRetries: 5, retryDelay: 200 })
33482
+ // #4904: Windows MAX_PATH aborts git worktree remove; the fallback must use \\?\ so the dir
33483
+ // (and its lease) do not survive as an unregistered leftover.
33484
+ removeTree: (p) => (0, import_promises9.rm)(win32LongPath(p), { recursive: true, force: true, maxRetries: 5, retryDelay: 200 })
33383
33485
  };
33384
33486
  async function resolvePrimaryCheckout(execGit) {
33385
33487
  try {
@@ -33850,12 +33952,13 @@ async function checkDocsIndexAtHead(opts, deps) {
33850
33952
  // src/worktree-lifecycle-commands.ts
33851
33953
  var import_node_fs42 = require("node:fs");
33852
33954
  var import_promises10 = require("node:fs/promises");
33853
- var import_node_path40 = require("node:path");
33955
+ var import_node_os16 = require("node:os");
33956
+ var import_node_path41 = require("node:path");
33854
33957
 
33855
33958
  // src/worktree-install-cache.ts
33856
33959
  var import_node_crypto8 = require("node:crypto");
33857
33960
  var import_node_fs41 = require("node:fs");
33858
- var import_node_path39 = require("node:path");
33961
+ var import_node_path40 = require("node:path");
33859
33962
  var CACHE_DIR = "worktree-install-cache";
33860
33963
  var MANIFEST = "manifest.json";
33861
33964
  var NODE_MODULES2 = "node_modules";
@@ -33885,7 +33988,7 @@ function hashLockfileBytes(contents) {
33885
33988
  }
33886
33989
  function resolveWorktreeInstallLockfile(packageDir, fs2 = realWorktreeInstallCacheFs) {
33887
33990
  for (const name of LOCKFILE_NAMES) {
33888
- const path2 = (0, import_node_path39.join)(packageDir, name);
33991
+ const path2 = (0, import_node_path40.join)(packageDir, name);
33889
33992
  if (!fs2.exists(path2)) continue;
33890
33993
  try {
33891
33994
  const hash = hashLockfileBytes(fs2.readFile(path2));
@@ -33900,8 +34003,8 @@ function worktreeInstallCacheEntry(primaryRoot, lockfileHash) {
33900
34003
  const root = repoRuntimeStatePath(primaryRoot, CACHE_DIR, lockfileHash);
33901
34004
  return {
33902
34005
  root,
33903
- manifestPath: (0, import_node_path39.join)(root, MANIFEST),
33904
- nodeModulesPath: (0, import_node_path39.join)(root, NODE_MODULES2)
34006
+ manifestPath: (0, import_node_path40.join)(root, MANIFEST),
34007
+ nodeModulesPath: (0, import_node_path40.join)(root, NODE_MODULES2)
33905
34008
  };
33906
34009
  }
33907
34010
  function readWorktreeInstallCacheManifest(manifestPath, fs2 = realWorktreeInstallCacheFs) {
@@ -33941,7 +34044,7 @@ function invalidateWorktreeInstallCacheEntry(entry, fs2 = realWorktreeInstallCac
33941
34044
  }
33942
34045
  }
33943
34046
  function removeMaterializedTree(packageDir, fs2) {
33944
- const dest = (0, import_node_path39.join)(packageDir, NODE_MODULES2);
34047
+ const dest = (0, import_node_path40.join)(packageDir, NODE_MODULES2);
33945
34048
  if (!fs2.exists(dest)) return;
33946
34049
  fs2.rm(dest);
33947
34050
  if (fs2.exists(dest)) {
@@ -33949,7 +34052,7 @@ function removeMaterializedTree(packageDir, fs2) {
33949
34052
  }
33950
34053
  }
33951
34054
  function materializeCachedNodeModules(entry, destPackageDir, fs2 = realWorktreeInstallCacheFs) {
33952
- const dest = (0, import_node_path39.join)(destPackageDir, NODE_MODULES2);
34055
+ const dest = (0, import_node_path40.join)(destPackageDir, NODE_MODULES2);
33953
34056
  try {
33954
34057
  if (fs2.exists(dest)) fs2.rm(dest);
33955
34058
  fs2.mkdirp(destPackageDir);
@@ -33964,7 +34067,7 @@ function materializeCachedNodeModules(entry, destPackageDir, fs2 = realWorktreeI
33964
34067
  }
33965
34068
  }
33966
34069
  async function storeWorktreeInstallCacheEntry(primaryRoot, lockfile3, command, sourcePackageDir, fs2 = realWorktreeInstallCacheFs, now = Date.now()) {
33967
- const source = (0, import_node_path39.join)(sourcePackageDir, NODE_MODULES2);
34070
+ const source = (0, import_node_path40.join)(sourcePackageDir, NODE_MODULES2);
33968
34071
  if (!isMaterializableNodeModulesDir(source, fs2)) return;
33969
34072
  const entry = worktreeInstallCacheEntry(primaryRoot, lockfile3.hash);
33970
34073
  const manifest = {
@@ -34219,12 +34322,36 @@ function classifyStaleLeaks(input) {
34219
34322
  remediation: "mmi-cli worktree gc --apply"
34220
34323
  });
34221
34324
  }
34325
+ for (const leftover of input.originLeftovers ?? []) {
34326
+ leaks.push({
34327
+ kind: "origin-leftover",
34328
+ ref: leftover.branch,
34329
+ detail: leftover.detail,
34330
+ remediation: leftover.autoReap ? "mmi-cli worktree gc --apply (conservative merged-head reap)" : leftover.kind === "open-pr" ? "leave open \u2014 gc will not delete an open PR head" : "mmi-cli worktree gc --apply --train-only (explicit; will not silently delete every non-train branch)"
34331
+ });
34332
+ }
34333
+ for (const helper of input.helperWorktrees ?? []) {
34334
+ leaks.push({
34335
+ kind: "helper-worktree",
34336
+ ref: helper.path,
34337
+ detail: helper.detail,
34338
+ remediation: helper.reapable ? "mmi-cli worktree gc --apply" : "inspect / git -C <primary> worktree remove --force after the helper is abandoned"
34339
+ });
34340
+ }
34341
+ for (const ref of input.missingLeaseRefs ?? []) {
34342
+ leaks.push({
34343
+ kind: "missing-lease",
34344
+ ref,
34345
+ detail: `jerv worktree lease still active but path is gone`,
34346
+ remediation: "mmi-cli worktree gc --apply (closes the lease; JPT #5548 also reaps on sweep)"
34347
+ });
34348
+ }
34222
34349
  return leaks;
34223
34350
  }
34224
34351
  var defaultOrphanDirScanDeps = {
34225
34352
  listDirs: (root) => {
34226
34353
  try {
34227
- return (0, import_node_fs42.readdirSync)(root, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => (0, import_node_path40.join)(root, e.name));
34354
+ return (0, import_node_fs42.readdirSync)(root, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => (0, import_node_path41.join)(root, e.name));
34228
34355
  } catch {
34229
34356
  return [];
34230
34357
  }
@@ -34239,8 +34366,12 @@ function scanOrphanDirs(worktreesRoot, worktreeGitRoot, deps = defaultOrphanDirS
34239
34366
  }
34240
34367
  return candidates;
34241
34368
  }
34242
- function formatStaleLeaks(leaks, prLookupFailures = []) {
34243
- const lines = leaks.length ? [`worktree list --stale: ${leaks.length} leak(s)`] : ["worktree list --stale: no leaks found"];
34369
+ function formatStaleLeaks(leaks, prLookupFailures = [], audit) {
34370
+ const blocked = Boolean(audit?.blocksGreen);
34371
+ const lines = leaks.length ? [`worktree list --stale: ${leaks.length} leak(s)`] : blocked ? ["worktree list --stale: incomplete \u2014 refusing a clean report"] : ["worktree list --stale: no leaks found"];
34372
+ if (audit) {
34373
+ for (const line of formatEstateAuditLines(audit)) lines.push(` ${line}`);
34374
+ }
34244
34375
  for (const leak of leaks) {
34245
34376
  lines.push(` [${leak.kind}] ${leak.ref} \u2014 ${leak.detail}`);
34246
34377
  lines.push(` fix: ${leak.remediation}`);
@@ -34390,13 +34521,13 @@ function registerWorktreeCommands(program3) {
34390
34521
  const detached = headBorn && !symbolicBranch;
34391
34522
  const branch = symbolicBranch || (detached ? "HEAD" : "");
34392
34523
  if (!wtPath || !branch) return fail("worktree land: not inside a git worktree");
34393
- const gitFile = (0, import_node_path40.join)(wtPath, ".git");
34524
+ const gitFile = (0, import_node_path41.join)(wtPath, ".git");
34394
34525
  const isLinked = (0, import_node_fs42.existsSync)(gitFile) && (0, import_node_fs42.statSync)(gitFile).isFile();
34395
34526
  if (apply && !isLinked) {
34396
34527
  return fail("worktree land: run from inside the linked worktree you want to land (this is the primary checkout)");
34397
34528
  }
34398
34529
  const commonDir = (await execFileP2("git", ["rev-parse", "--git-common-dir"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim();
34399
- const primaryCheckout = commonDir ? (0, import_node_path40.dirname)(commonDir) : wtPath;
34530
+ const primaryCheckout = commonDir ? (0, import_node_path41.dirname)(commonDir) : wtPath;
34400
34531
  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);
34401
34532
  const orphan = classifyOrphanedWorktree({
34402
34533
  branch,
@@ -34460,7 +34591,9 @@ function registerWorktreeCommands(program3) {
34460
34591
  const reportedMergeState = treeOnly ? "not-checked" : mergeVerdict.state;
34461
34592
  const landOwner = lookupWorktreeOwner(primaryCheckout, wtPath);
34462
34593
  const activeWorkspaceRoot = resolveActiveWorkspaceRoot();
34463
- const activeGuard = decideActiveWorkspaceGuard(wtPath, activeWorkspaceRoot);
34594
+ const activeGuard = decideActiveWorkspaceGuard(wtPath, activeWorkspaceRoot, process.platform, {
34595
+ cursorAgentHost: isCursorAgentHost()
34596
+ });
34464
34597
  if (activeGuard.action === "refuse") {
34465
34598
  const deferredStore = await createDeferredWorktreeStore();
34466
34599
  if (deferredStore) {
@@ -34536,6 +34669,9 @@ function registerWorktreeCommands(program3) {
34536
34669
  step: "remove worktree",
34537
34670
  status: removeOutcome.status === "removed" ? removeOutcome.recovery ? `done (${removeOutcome.recovery})` : "done" : removeOutcome.remainsOnDisk ? `failed: ${removeOutcome.error ?? "lock held"} \u2014 the directory "${wtPath}" is still on disk; cd every shell out of it (a cwd inside holds it open on Windows), then delete that directory` : `failed: ${removeOutcome.error ?? "lock held"} \u2014 run: git -C "${primaryCheckout}" worktree remove --force "${wtPath}"`
34538
34671
  });
34672
+ if (!removeOutcome.remainsOnDisk) {
34673
+ report.push(await bestEffortLeaseClose(wtPath));
34674
+ }
34539
34675
  if (!shouldContinueLandCleanup(removeOutcome.status)) {
34540
34676
  const result2 = {
34541
34677
  dryRun: false,
@@ -34620,8 +34756,17 @@ function registerWorktreeCommands(program3) {
34620
34756
  if (o.stale) {
34621
34757
  const leaks = classifyStaleLeaks(ctx);
34622
34758
  const failures = ctx.prLookupFailures ?? [];
34623
- if (o.json) return console.log(JSON.stringify({ stale: leaks, count: leaks.length, prLookupFailures: failures, complete: failures.length === 0 }, null, 2));
34624
- return console.log(formatStaleLeaks(leaks, failures));
34759
+ const complete = failures.length === 0 && !ctx.audit?.blocksGreen;
34760
+ if (o.json) {
34761
+ return console.log(JSON.stringify({
34762
+ stale: leaks,
34763
+ count: leaks.length,
34764
+ prLookupFailures: failures,
34765
+ complete,
34766
+ audit: ctx.audit
34767
+ }, null, 2));
34768
+ }
34769
+ return console.log(formatStaleLeaks(leaks, failures, ctx.audit));
34625
34770
  }
34626
34771
  if (o.json) return console.log(JSON.stringify({ worktrees: ctx.worktrees }, null, 2));
34627
34772
  if (!ctx.worktrees.length) return console.log("worktree list: no worktrees");
@@ -34645,10 +34790,18 @@ async function gatherWorktreeContext() {
34645
34790
  const branchOut = (await execFileP2("git", ["branch", "--format=%(refname:short)"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout;
34646
34791
  const localBranches = branchOut.split(/\r?\n/).map((l) => l.trim()).filter(Boolean);
34647
34792
  const currentBranch2 = (await execFileP2("git", ["rev-parse", "--abbrev-ref", "HEAD"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim() || void 0;
34648
- const { prs, failures: prLookupFailures } = await resolveBranchPrs(localBranches.filter((b) => !PROTECTED_BRANCHES2.has(b)), STALE_PR_LOOKUP_LIMIT);
34793
+ const remoteBranchOut = (await execFileP2("git", ["branch", "-r", "--format=%(refname:short)"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout;
34794
+ const remoteBranches = remoteBranchOut.split(/\r?\n/).map((l) => l.trim()).filter((b) => b.startsWith("origin/") && b !== "origin/HEAD");
34795
+ const remoteNames = remoteBranches.map((b) => b.replace(/^origin\//, ""));
34796
+ const prTargets = [.../* @__PURE__ */ new Set([
34797
+ ...localBranches.filter((b) => !PROTECTED_BRANCHES2.has(b)),
34798
+ ...remoteNames.filter((b) => !PROTECTED_BRANCHES2.has(b))
34799
+ ])];
34800
+ const { prs, failures: prLookupFailures } = await resolveBranchPrs(prTargets, STALE_PR_LOOKUP_LIMIT);
34649
34801
  const openPrBranches = /* @__PURE__ */ new Set();
34650
34802
  const closedBranches = /* @__PURE__ */ new Set();
34651
34803
  const closedUnmergedBranches = /* @__PURE__ */ new Set();
34804
+ const mergedPrBranches = /* @__PURE__ */ new Set();
34652
34805
  const byBranch = /* @__PURE__ */ new Map();
34653
34806
  for (const pr2 of prs) {
34654
34807
  const arr = byBranch.get(pr2.headRefName) ?? [];
@@ -34659,6 +34812,7 @@ async function gatherWorktreeContext() {
34659
34812
  if (states.some((s) => s === "OPEN")) openPrBranches.add(br);
34660
34813
  else if (states.some((s) => s === "MERGED" || s === "CLOSED")) {
34661
34814
  closedBranches.add(br);
34815
+ if (states.some((s) => s === "MERGED")) mergedPrBranches.add(br);
34662
34816
  if (!states.some((s) => s === "MERGED") && states.some((s) => s === "CLOSED")) {
34663
34817
  closedUnmergedBranches.add(br);
34664
34818
  }
@@ -34670,7 +34824,7 @@ async function gatherWorktreeContext() {
34670
34824
  if (s) stages.push({ path: wt.path, port: s.port });
34671
34825
  }
34672
34826
  const worktreeGitRoot = await currentRepoWorktreeGitRoot(repoRoot2);
34673
- const primaryRepoRoot = worktreeGitRoot ? (0, import_node_path40.dirname)((0, import_node_path40.dirname)(worktreeGitRoot)) : repoRoot2;
34827
+ const primaryRepoRoot = worktreeGitRoot ? (0, import_node_path41.dirname)((0, import_node_path41.dirname)(worktreeGitRoot)) : repoRoot2;
34674
34828
  const wtRoot = siblingMmiWorktreesRoot(primaryRepoRoot);
34675
34829
  let orphanDirs = [];
34676
34830
  if ((0, import_node_fs42.existsSync)(wtRoot)) {
@@ -34679,6 +34833,44 @@ async function gatherWorktreeContext() {
34679
34833
  listDirs: (root) => worktreeScanDirs(root, primaryRepoRoot, defaultOrphanDirScanDeps.listDirs, isRepoCheckoutDir)
34680
34834
  });
34681
34835
  }
34836
+ const repoContainer = worktreesRootOf(primaryRepoRoot);
34837
+ if ((0, import_node_fs42.existsSync)(repoContainer)) {
34838
+ for (const dir of defaultOrphanDirScanDeps.listDirs(repoContainer)) {
34839
+ if (orphanDirs.some((o) => o.path === dir)) continue;
34840
+ const inspected = inspectSiblingWorktreeDir(dir, worktreeGitRoot);
34841
+ const classified = classifySiblingWorktreeDir(inspected);
34842
+ if (classified.cleanup) {
34843
+ orphanDirs.push({ path: dir, reason: classified.cleanup.reason });
34844
+ continue;
34845
+ }
34846
+ if (inspected.gitType === "missing" && pathProvesRepoContainerOwnership(dir, repoContainer)) {
34847
+ orphanDirs.push({ path: dir, reason: "orphaned-folder" });
34848
+ }
34849
+ }
34850
+ }
34851
+ const originLeftovers = classifyOriginLeftovers({
34852
+ remoteBranches,
34853
+ localBranches,
34854
+ protectedBranches: PROTECTED_BRANCHES2,
34855
+ openPrBranches,
34856
+ mergedPrBranches,
34857
+ closedUnmergedBranches
34858
+ });
34859
+ const helperWorktrees = scanHelperWorktrees(primaryRepoRoot, worktreeGitRoot);
34860
+ const leaseRefs = readJervWorktreeLeaseRefs();
34861
+ const missingLeaseRefs = leaseRefs.filter((ref) => !(0, import_node_fs42.existsSync)(ref));
34862
+ const remoteUrls = await gitRemoteUrls();
34863
+ const otherCheckouts = discoverOtherPrimaries(primaryRepoRoot).map((path2) => ({
34864
+ path: path2,
34865
+ remoteUrls: gitConfigRemoteUrls(path2)
34866
+ }));
34867
+ const audit = classifyEstateAudit({
34868
+ auditedClone: primaryRepoRoot,
34869
+ remoteUrls,
34870
+ otherCheckouts,
34871
+ leaseRefs,
34872
+ thisWorktreesRoot: repoContainer
34873
+ });
34682
34874
  return {
34683
34875
  worktrees,
34684
34876
  localBranches,
@@ -34688,9 +34880,96 @@ async function gatherWorktreeContext() {
34688
34880
  closedUnmergedBranches,
34689
34881
  stages,
34690
34882
  orphanDirs,
34691
- prLookupFailures
34883
+ prLookupFailures,
34884
+ originLeftovers,
34885
+ helperWorktrees,
34886
+ missingLeaseRefs,
34887
+ audit
34692
34888
  };
34693
34889
  }
34890
+ function gitConfigRemoteUrls(checkout) {
34891
+ const gitPath = (0, import_node_path41.join)(checkout, ".git");
34892
+ let configPath = (0, import_node_path41.join)(checkout, ".git", "config");
34893
+ try {
34894
+ const st = (0, import_node_fs42.statSync)(gitPath);
34895
+ if (st.isFile()) return [];
34896
+ } catch {
34897
+ return [];
34898
+ }
34899
+ try {
34900
+ const text = (0, import_node_fs42.readFileSync)(configPath, "utf8");
34901
+ return [...text.matchAll(/^\s*url\s*=\s*(.+)$/gm)].map((m) => m[1].trim());
34902
+ } catch {
34903
+ return [];
34904
+ }
34905
+ }
34906
+ async function gitRemoteUrls() {
34907
+ const out = (await execFileP2("git", ["remote", "-v"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout;
34908
+ return [...new Set(
34909
+ out.split(/\r?\n/).map((line) => line.trim().split(/\s+/)[1]).filter((url) => Boolean(url))
34910
+ )];
34911
+ }
34912
+ function discoverOtherPrimaries(primaryRepoRoot) {
34913
+ const found = /* @__PURE__ */ new Set();
34914
+ const parent = (0, import_node_path41.dirname)(primaryRepoRoot);
34915
+ try {
34916
+ for (const name of (0, import_node_fs42.readdirSync)(parent)) {
34917
+ const path2 = (0, import_node_path41.join)(parent, name);
34918
+ if (path2 === primaryRepoRoot) continue;
34919
+ if ((0, import_node_fs42.existsSync)((0, import_node_path41.join)(path2, ".git"))) found.add(path2);
34920
+ }
34921
+ } catch {
34922
+ }
34923
+ const mirror = (0, import_node_path41.join)((0, import_node_os16.homedir)(), "Projects", (0, import_node_path41.basename)(primaryRepoRoot));
34924
+ if (mirror !== primaryRepoRoot && (0, import_node_fs42.existsSync)((0, import_node_path41.join)(mirror, ".git"))) found.add(mirror);
34925
+ return [...found];
34926
+ }
34927
+ function readJervWorktreeLeaseRefs(leaseDir = (0, import_node_path41.join)((0, import_node_os16.homedir)(), ".jerv", "leases")) {
34928
+ try {
34929
+ const refs = [];
34930
+ for (const name of (0, import_node_fs42.readdirSync)(leaseDir)) {
34931
+ if (!name.endsWith(".json")) continue;
34932
+ try {
34933
+ const rec = JSON.parse((0, import_node_fs42.readFileSync)((0, import_node_path41.join)(leaseDir, name), "utf8"));
34934
+ if (rec.kind === "worktree" && rec.state !== "closed" && typeof rec.ref === "string" && rec.ref.trim()) {
34935
+ refs.push(rec.ref);
34936
+ }
34937
+ } catch {
34938
+ }
34939
+ }
34940
+ return refs;
34941
+ } catch {
34942
+ return [];
34943
+ }
34944
+ }
34945
+ function scanHelperWorktrees(thisPrimary, thisWorktreeGitRoot) {
34946
+ const primaries = [thisPrimary, ...discoverOtherPrimaries(thisPrimary)];
34947
+ const out = [];
34948
+ for (const primary of primaries) {
34949
+ const gitRoot = primary === thisPrimary ? thisWorktreeGitRoot : (0, import_node_path41.join)(primary, ".git", "worktrees");
34950
+ for (const root of helperWorktreeRoots(primary)) {
34951
+ if (!(0, import_node_fs42.existsSync)(root)) continue;
34952
+ for (const dir of defaultOrphanDirScanDeps.listDirs(root)) {
34953
+ const inspected = inspectSiblingWorktreeDir(dir, gitRoot);
34954
+ const classified = classifySiblingWorktreeDir(inspected);
34955
+ if (classified.cleanup) {
34956
+ out.push({
34957
+ path: dir,
34958
+ detail: `${classified.cleanup.reason} helper worktree under ${root}`,
34959
+ reapable: true
34960
+ });
34961
+ } else {
34962
+ out.push({
34963
+ path: dir,
34964
+ detail: `helper worktree outside ../mmi-worktrees (${classified.skip?.reason ?? inspected.gitType}) at ${dir}`,
34965
+ reapable: false
34966
+ });
34967
+ }
34968
+ }
34969
+ }
34970
+ }
34971
+ return out;
34972
+ }
34694
34973
  async function bestEffortGit(args, cwd, step, timeoutMs = GIT_TIMEOUT_MS) {
34695
34974
  try {
34696
34975
  const fullArgs = cwd ? ["-C", cwd, ...args] : args;
@@ -35408,7 +35687,7 @@ ${lines}`, {
35408
35687
 
35409
35688
  // src/train-commands.ts
35410
35689
  var import_node_fs44 = require("node:fs");
35411
- var import_node_path41 = require("node:path");
35690
+ var import_node_path42 = require("node:path");
35412
35691
  var RELEASE_BUMP_INTENTS = ["major", "minor", "patch"];
35413
35692
  function resolveReleaseBumpIntent(raw) {
35414
35693
  const intent = typeof raw === "string" ? raw.trim() : "";
@@ -35419,7 +35698,7 @@ function resolveReleaseBumpIntent(raw) {
35419
35698
  }
35420
35699
  function readRepoVersion() {
35421
35700
  try {
35422
- return JSON.parse((0, import_node_fs44.readFileSync)((0, import_node_path41.join)(process.cwd(), ".claude-plugin", "plugin.json"), "utf8")).version || void 0;
35701
+ return JSON.parse((0, import_node_fs44.readFileSync)((0, import_node_path42.join)(process.cwd(), ".claude-plugin", "plugin.json"), "utf8")).version || void 0;
35423
35702
  } catch {
35424
35703
  return void 0;
35425
35704
  }
@@ -35577,8 +35856,8 @@ function registerDeployCommands(program3) {
35577
35856
 
35578
35857
  // src/discovery-commands.ts
35579
35858
  var import_node_fs45 = require("node:fs");
35580
- var import_node_os16 = require("node:os");
35581
- var import_node_path42 = require("node:path");
35859
+ var import_node_os17 = require("node:os");
35860
+ var import_node_path43 = require("node:path");
35582
35861
  var GC_GH_TIMEOUT_MS3 = 2e4;
35583
35862
  async function collectStatus() {
35584
35863
  const repo = await resolveRepo();
@@ -35766,10 +36045,10 @@ async function collectOnboardStatus(opts = {}) {
35766
36045
  else if (top) nextCommand = `mmi-cli oracle board claim ${top.number} # ${top.title}`;
35767
36046
  else nextCommand = "mmi-cli oracle board read \u2014 no claimable items found";
35768
36047
  }
35769
- const home = (0, import_node_os16.homedir)();
36048
+ const home = (0, import_node_os17.homedir)();
35770
36049
  const plugin = onboardPluginGate({
35771
- readKnown: () => readFileSyncSafe((0, import_node_path42.join)(home, ...KNOWN_MARKETPLACES_RELATIVE), import_node_fs45.readFileSync),
35772
- readSettings: () => readFileSyncSafe((0, import_node_path42.join)(home, ".claude", "settings.json"), import_node_fs45.readFileSync)
36050
+ readKnown: () => readFileSyncSafe((0, import_node_path43.join)(home, ...KNOWN_MARKETPLACES_RELATIVE), import_node_fs45.readFileSync),
36051
+ readSettings: () => readFileSyncSafe((0, import_node_path43.join)(home, ".claude", "settings.json"), import_node_fs45.readFileSync)
35773
36052
  });
35774
36053
  return { track, board, registry: registry2, secrets, plugin, estateCli, doors: opts.doors ?? [], nextCommand };
35775
36054
  }
@@ -36905,18 +37184,18 @@ function registerOrgHealthQuery(program3, deps = defaultOrgHealthQueryDeps()) {
36905
37184
 
36906
37185
  // src/plugin-release-catchup.ts
36907
37186
  var import_node_fs46 = require("node:fs");
36908
- var import_node_path43 = require("node:path");
36909
- var import_node_os17 = require("node:os");
37187
+ var import_node_path44 = require("node:path");
37188
+ var import_node_os18 = require("node:os");
36910
37189
  var RELEASE_CATCHUP_TTL_MS = 24 * 60 * 60 * 1e3;
36911
37190
  var RELEASE_CATCHUP_DISABLE_ENV = "MMI_NO_RELEASE_CATCHUP";
36912
37191
  function releaseCatchupStatePath(env = process.env) {
36913
37192
  if (env.MMI_RELEASE_CATCHUP_STATE) return env.MMI_RELEASE_CATCHUP_STATE;
36914
37193
  if (process.platform === "win32") {
36915
- const base2 = env.LOCALAPPDATA || (0, import_node_path43.join)((0, import_node_os17.homedir)(), "AppData", "Local");
36916
- return (0, import_node_path43.join)(base2, "MMI Future", "mmi-cli", "release-catchup.json");
37194
+ const base2 = env.LOCALAPPDATA || (0, import_node_path44.join)((0, import_node_os18.homedir)(), "AppData", "Local");
37195
+ return (0, import_node_path44.join)(base2, "MMI Future", "mmi-cli", "release-catchup.json");
36917
37196
  }
36918
- const base = env.XDG_STATE_HOME || (0, import_node_path43.join)((0, import_node_os17.homedir)(), ".local", "state");
36919
- return (0, import_node_path43.join)(base, "mmi-cli", "release-catchup.json");
37197
+ const base = env.XDG_STATE_HOME || (0, import_node_path44.join)((0, import_node_os18.homedir)(), ".local", "state");
37198
+ return (0, import_node_path44.join)(base, "mmi-cli", "release-catchup.json");
36920
37199
  }
36921
37200
  function releaseCatchupDue(state, now, force = false) {
36922
37201
  if (force) return true;
@@ -36934,15 +37213,15 @@ function newestCachedPluginVersion(home) {
36934
37213
  }
36935
37214
  function marketplaceClonePath(home) {
36936
37215
  try {
36937
- const parsed = JSON.parse((0, import_node_fs46.readFileSync)((0, import_node_path43.join)(home, ".claude", "plugins", "known_marketplaces.json"), "utf8"));
37216
+ const parsed = JSON.parse((0, import_node_fs46.readFileSync)((0, import_node_path44.join)(home, ".claude", "plugins", "known_marketplaces.json"), "utf8"));
36938
37217
  if (parsed.mutmutco?.installLocation) return parsed.mutmutco.installLocation;
36939
37218
  } catch {
36940
37219
  }
36941
- return (0, import_node_path43.join)(home, ".claude", "plugins", "marketplaces", "mutmutco");
37220
+ return (0, import_node_path44.join)(home, ".claude", "plugins", "marketplaces", "mutmutco");
36942
37221
  }
36943
37222
  function readCatalogVersion(home) {
36944
37223
  try {
36945
- const parsed = JSON.parse((0, import_node_fs46.readFileSync)((0, import_node_path43.join)(marketplaceClonePath(home), ".claude-plugin", "marketplace.json"), "utf8"));
37224
+ const parsed = JSON.parse((0, import_node_fs46.readFileSync)((0, import_node_path44.join)(marketplaceClonePath(home), ".claude-plugin", "marketplace.json"), "utf8"));
36946
37225
  return parsed.plugins?.find((p) => p.name === "mmi")?.version;
36947
37226
  } catch {
36948
37227
  return void 0;
@@ -36950,7 +37229,7 @@ function readCatalogVersion(home) {
36950
37229
  }
36951
37230
  function readMmiInstallRecord(home) {
36952
37231
  try {
36953
- const parsed = JSON.parse((0, import_node_fs46.readFileSync)((0, import_node_path43.join)(home, ".claude", "plugins", "installed_plugins.json"), "utf8"));
37232
+ const parsed = JSON.parse((0, import_node_fs46.readFileSync)((0, import_node_path44.join)(home, ".claude", "plugins", "installed_plugins.json"), "utf8"));
36954
37233
  const record = parsed.plugins?.["mmi@mutmutco"]?.[0];
36955
37234
  return record?.version ? { version: record.version, gitCommitSha: record.gitCommitSha } : void 0;
36956
37235
  } catch {
@@ -37012,7 +37291,7 @@ async function runReleaseCatchup(home, env, deps, opts = {}) {
37012
37291
  return { ok: false, detail: `${cliUpdateDetail}; plugin install record could not be cleared (still ${prior.version})` };
37013
37292
  }
37014
37293
  const installed = await deps.runClaude(["plugin", "install", "mmi@mutmutco"], "claude plugin install mmi@mutmutco");
37015
- const payload = (0, import_node_path43.join)(pluginCacheRoot(home), latest, ".pi-plugin");
37294
+ const payload = (0, import_node_path44.join)(pluginCacheRoot(home), latest, ".pi-plugin");
37016
37295
  if (!installed || !(0, import_node_fs46.existsSync)(payload)) {
37017
37296
  const why = installed ? `install of ${latest} did not produce a verifiable .pi-plugin payload` : `install of ${latest} failed`;
37018
37297
  if (!prior) return { ok: false, detail: `${cliUpdateDetail}; ${why}; no prior record to restore` };
@@ -38048,10 +38327,10 @@ function checkRepoWorktrees(probe) {
38048
38327
  ok: !(probe.isOrgRepo && probe.hasRepoLocalWorktrees),
38049
38328
  id: "repo-worktrees",
38050
38329
  label: "repo worktrees",
38051
- fix: "repo-local `.worktrees/` is not the canonical path \u2014 use `mmi-cli worktree create <branch>` (sibling `../worktrees/`), then remove the in-repo `.worktrees/`",
38330
+ fix: "repo-local `.worktrees/` / `.claude/worktrees` are not the canonical path \u2014 use `mmi-cli worktree create <branch>` (sibling `../mmi-worktrees/<Repo>/`), then `mmi-cli worktree gc --apply` for abandoned helper trees",
38052
38331
  verbose: [
38053
38332
  `org repo: ${probe.isOrgRepo ? "yes" : "no"}`,
38054
- `repo-local .worktrees/: ${probe.hasRepoLocalWorktrees ? "present" : "absent"}`
38333
+ `repo-local .worktrees/ or .claude/worktrees/: ${probe.hasRepoLocalWorktrees ? "present" : "absent"}`
38055
38334
  ]
38056
38335
  };
38057
38336
  }
@@ -39238,17 +39517,17 @@ function parseOriginRepo(remoteUrl) {
39238
39517
  }
39239
39518
  function ghHostsConfigPath(env, platform2) {
39240
39519
  const sep3 = platform2 === "win32" ? "\\" : "/";
39241
- const join40 = (...parts) => parts.join(sep3);
39520
+ const join41 = (...parts) => parts.join(sep3);
39242
39521
  const explicit = env.GH_CONFIG_DIR?.trim();
39243
- if (explicit) return join40(explicit, "hosts.yml");
39522
+ if (explicit) return join41(explicit, "hosts.yml");
39244
39523
  if (platform2 === "win32") {
39245
39524
  const appData = (env.AppData ?? env.APPDATA)?.trim();
39246
- return appData ? join40(appData, "GitHub CLI", "hosts.yml") : void 0;
39525
+ return appData ? join41(appData, "GitHub CLI", "hosts.yml") : void 0;
39247
39526
  }
39248
39527
  const xdg = env.XDG_CONFIG_HOME?.trim();
39249
- if (xdg) return join40(xdg, "gh", "hosts.yml");
39528
+ if (xdg) return join41(xdg, "gh", "hosts.yml");
39250
39529
  const home = env.HOME?.trim();
39251
- return home ? join40(home, ".config", "gh", "hosts.yml") : void 0;
39530
+ return home ? join41(home, ".config", "gh", "hosts.yml") : void 0;
39252
39531
  }
39253
39532
  function parseGhHostsAccounts(yaml, host = "github.com") {
39254
39533
  let hostIndent = null;
@@ -39299,8 +39578,8 @@ function ghAccountCaveat(announcedLogin, accounts) {
39299
39578
 
39300
39579
  // src/doctor-io.ts
39301
39580
  var import_node_fs47 = require("node:fs");
39302
- var import_node_os18 = require("node:os");
39303
- var import_node_path44 = require("node:path");
39581
+ var import_node_os19 = require("node:os");
39582
+ var import_node_path45 = require("node:path");
39304
39583
  var import_node_child_process19 = require("node:child_process");
39305
39584
  var import_node_util8 = require("node:util");
39306
39585
  var execFileP6 = (0, import_node_util8.promisify)(import_node_child_process19.execFile);
@@ -39308,7 +39587,7 @@ var MMI_PLUGIN_ID2 = "mmi@mutmutco";
39308
39587
  function installedClaudePluginVersion() {
39309
39588
  try {
39310
39589
  const file = JSON.parse(
39311
- (0, import_node_fs47.readFileSync)((0, import_node_path44.join)((0, import_node_os18.homedir)(), ".claude", "plugins", "installed_plugins.json"), "utf8")
39590
+ (0, import_node_fs47.readFileSync)((0, import_node_path45.join)((0, import_node_os19.homedir)(), ".claude", "plugins", "installed_plugins.json"), "utf8")
39312
39591
  );
39313
39592
  const versions = (file.plugins?.[MMI_PLUGIN_ID2] ?? []).map((r) => r.version).filter((v) => Boolean(v));
39314
39593
  if (versions.length === 0) return void 0;
@@ -39329,22 +39608,22 @@ function installedSurfacePluginVersion(surface) {
39329
39608
  const token = surfaceToken(surface);
39330
39609
  if (token === "kilo") {
39331
39610
  try {
39332
- const stamp = (0, import_node_fs47.readFileSync)((0, import_node_path44.join)((0, import_node_os18.homedir)(), ".kilo", ".mmi-kilo-version"), "utf8").trim();
39611
+ const stamp = (0, import_node_fs47.readFileSync)((0, import_node_path45.join)((0, import_node_os19.homedir)(), ".kilo", ".mmi-kilo-version"), "utf8").trim();
39333
39612
  return stamp || void 0;
39334
39613
  } catch {
39335
39614
  return void 0;
39336
39615
  }
39337
39616
  }
39338
39617
  if (token === "cursor") {
39339
- return manifestVersion((0, import_node_path44.join)(cursorLocalPluginRoot(), ".cursor-plugin", "plugin.json"));
39618
+ return manifestVersion((0, import_node_path45.join)(cursorLocalPluginRoot(), ".cursor-plugin", "plugin.json"));
39340
39619
  }
39341
39620
  if (token === "jervcode") {
39342
39621
  const entry = mmiPiWrapperEntry();
39343
39622
  if (!entry) return void 0;
39344
- return manifestVersion((0, import_node_path44.join)(decodeURIComponent(entry.replace(/^file:\/\/\/?/, "")), "package.json"));
39623
+ return manifestVersion((0, import_node_path45.join)(decodeURIComponent(entry.replace(/^file:\/\/\/?/, "")), "package.json"));
39345
39624
  }
39346
39625
  if (token === "kimi") {
39347
- return manifestVersion((0, import_node_path44.join)(surfaceConfigRoot(surface), "plugins", "managed", "mmi", ".kimi-plugin", "plugin.json"));
39626
+ return manifestVersion((0, import_node_path45.join)(surfaceConfigRoot(surface), "plugins", "managed", "mmi", ".kimi-plugin", "plugin.json"));
39348
39627
  }
39349
39628
  if (token === "claude") return installedClaudePluginVersion();
39350
39629
  if (token !== "codex") return void 0;
@@ -39382,7 +39661,7 @@ function worktreeRootSync() {
39382
39661
  }
39383
39662
  var gitignorePath = () => {
39384
39663
  const root = worktreeRootSync();
39385
- return root === null ? null : (0, import_node_path44.join)(root, ".gitignore");
39664
+ return root === null ? null : (0, import_node_path45.join)(root, ".gitignore");
39386
39665
  };
39387
39666
  function readGitignore() {
39388
39667
  const path2 = gitignorePath();
@@ -39416,7 +39695,7 @@ async function repoRoot() {
39416
39695
  }
39417
39696
  function hasRepoLocalWorktrees() {
39418
39697
  const root = worktreeRootSync();
39419
- return root !== null && (0, import_node_fs47.existsSync)((0, import_node_path44.join)(root, ".worktrees"));
39698
+ 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")));
39420
39699
  }
39421
39700
 
39422
39701
  // src/cross-repo-filing-issue.ts
@@ -39512,7 +39791,7 @@ function binaryOnPath(bin) {
39512
39791
  for (const dir of pathEnvEntries(process.env.PATH ?? "")) {
39513
39792
  for (const ext of exts) {
39514
39793
  try {
39515
- if ((0, import_node_fs48.existsSync)((0, import_node_path45.join)(dir, `${bin}${ext}`))) return true;
39794
+ if ((0, import_node_fs48.existsSync)((0, import_node_path46.join)(dir, `${bin}${ext}`))) return true;
39516
39795
  } catch {
39517
39796
  }
39518
39797
  }
@@ -39543,12 +39822,12 @@ function ghMultiAccountCaveat(announcedLogin) {
39543
39822
  var ENV_HEAL_LOCK_STALE_MS = 10 * 6e4;
39544
39823
  var ENV_HEAL_LOCK_MAX_WAIT_MS = 2 * 6e4;
39545
39824
  function envHealLockPath(home) {
39546
- return (0, import_node_path45.join)(home, ".claude", "plugins", ".mmi-env-heal.lock");
39825
+ return (0, import_node_path46.join)(home, ".claude", "plugins", ".mmi-env-heal.lock");
39547
39826
  }
39548
39827
  async function withEnvHealLock(what, run) {
39549
39828
  try {
39550
39829
  return await withFileLock(
39551
- envHealLockPath((0, import_node_os19.homedir)()),
39830
+ envHealLockPath((0, import_node_os20.homedir)()),
39552
39831
  { staleMs: ENV_HEAL_LOCK_STALE_MS, maxWaitMs: ENV_HEAL_LOCK_MAX_WAIT_MS, label: "mmi env-heal lock" },
39553
39832
  run
39554
39833
  );
@@ -39645,7 +39924,7 @@ function mmiDoctorDeps(opts = {}) {
39645
39924
  const configRoot = surfaceConfigRoot(surface);
39646
39925
  const running = surface === "codex" ? installedActivePluginVersion(surface) : runningPluginVersion(process.env, resolveClientVersion());
39647
39926
  const plan = buildPluginCachePlan(
39648
- (0, import_node_os19.homedir)(),
39927
+ (0, import_node_os20.homedir)(),
39649
39928
  running,
39650
39929
  pluginCacheFsDeps(configRoot, () => 0),
39651
39930
  { configRoot, includeStaging: surface !== "codex" }
@@ -39669,7 +39948,7 @@ function mmiDoctorDeps(opts = {}) {
39669
39948
  const running = surface === "codex" ? installedActivePluginVersion(surface) : runningPluginVersion(process.env, resolveClientVersion());
39670
39949
  const installed = installedActivePluginVersion(surface);
39671
39950
  const plan = buildPluginCachePlan(
39672
- (0, import_node_os19.homedir)(),
39951
+ (0, import_node_os20.homedir)(),
39673
39952
  running,
39674
39953
  pluginCacheFsDeps(configRoot, () => 0),
39675
39954
  { configRoot, includeStaging: surface !== "codex", installedVersion: installed }
@@ -39704,12 +39983,12 @@ function mmiDoctorDeps(opts = {}) {
39704
39983
  piPluginState: () => {
39705
39984
  const env = { ...process.env };
39706
39985
  delete env.CLAUDE_PLUGIN_ROOT;
39707
- return readPiPluginState((0, import_node_os19.homedir)(), env);
39986
+ return readPiPluginState((0, import_node_os20.homedir)(), env);
39708
39987
  },
39709
39988
  healPiPlugin: () => {
39710
39989
  const env = { ...process.env };
39711
39990
  delete env.CLAUDE_PLUGIN_ROOT;
39712
- return healPiPluginRegistration((0, import_node_os19.homedir)(), env);
39991
+ return healPiPluginRegistration((0, import_node_os20.homedir)(), env);
39713
39992
  },
39714
39993
  // #4743: the global `claude` binary left as a ~500-byte placeholder by a self-update that died
39715
39994
  // EBUSY mid-install. A local read (package.json + the first bytes of two files) — no npm spawn:
@@ -39748,7 +40027,7 @@ function mmiDoctorDeps(opts = {}) {
39748
40027
  disableAutoUpdate: () => {
39749
40028
  if (detectSurface(process.env) === "codex") return void 0;
39750
40029
  return disableOrgMarketplaceBackgroundUpdates(
39751
- (0, import_node_path45.join)((0, import_node_os19.homedir)(), ...KNOWN_MARKETPLACES_RELATIVE),
40030
+ (0, import_node_path46.join)((0, import_node_os20.homedir)(), ...KNOWN_MARKETPLACES_RELATIVE),
39752
40031
  [MMI_MARKETPLACE_NAME]
39753
40032
  );
39754
40033
  }
@@ -39762,7 +40041,7 @@ function mmiDoctorDeps(opts = {}) {
39762
40041
  // adopted the generated routing index (MMG-Unlive: `docs/Archive/**` only, no index, no gate.yml) would
39763
40042
  // get a permanent — demanding an artifact it never asked for.
39764
40043
  docsIndexState: (root) => {
39765
- if (!(0, import_node_fs48.existsSync)((0, import_node_path45.join)(root, DOCS_INDEX_PATH))) return void 0;
40044
+ if (!(0, import_node_fs48.existsSync)((0, import_node_path46.join)(root, DOCS_INDEX_PATH))) return void 0;
39766
40045
  const real = createDocsIndexDeps(root);
39767
40046
  let docs2;
39768
40047
  const listDocs = () => docs2 ??= real.listDocs();
@@ -39771,7 +40050,7 @@ function mmiDoctorDeps(opts = {}) {
39771
40050
  },
39772
40051
  // #4168: working-tree heal — write if drifted, then re-check. Commit remains the operator's step.
39773
40052
  healDocsIndex: (root) => {
39774
- if (!(0, import_node_fs48.existsSync)((0, import_node_path45.join)(root, DOCS_INDEX_PATH))) return { drift: false, docCount: 0 };
40053
+ if (!(0, import_node_fs48.existsSync)((0, import_node_path46.join)(root, DOCS_INDEX_PATH))) return { drift: false, docCount: 0 };
39775
40054
  const real = createDocsIndexDeps(root);
39776
40055
  let docs2;
39777
40056
  const listDocs = () => docs2 ??= real.listDocs();
@@ -40137,7 +40416,7 @@ program2.hook("preAction", async (_thisCommand, actionCommand) => {
40137
40416
  });
40138
40417
  var rules = program2.command("rules").description("org-managed .gitignore delivery");
40139
40418
  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) => {
40140
- const path2 = (0, import_node_path45.join)(process.cwd(), ".gitignore");
40419
+ const path2 = (0, import_node_path46.join)(process.cwd(), ".gitignore");
40141
40420
  const current = (0, import_node_fs48.existsSync)(path2) ? (0, import_node_fs48.readFileSync)(path2, "utf8") : null;
40142
40421
  const plan = planManagedGitignore(current);
40143
40422
  const drift = [...plan.added.map((l) => `+${l}`), ...plan.removed.map((l) => `-${l}`)].join(", ") || "block normalize";
@@ -40291,7 +40570,7 @@ gcCmd.command("sweep-deferred").description("retry IDE-locked deferred worktree
40291
40570
  process.exit(process.exitCode ?? 0);
40292
40571
  });
40293
40572
  });
40294
- gcCmd.option("--dry-run", "show what would be deleted (default)").option("--apply", "delete only the listed clean merged/closed PR local+remote branches, linked worktrees, and stale tracking refs").option("--json", "machine-readable output").option("--scratch", "prune safe local scratch (#1864) instead of git branches/refs; local plans are surfaced advisory-only, never auto-pruned").option("--remote <name>", "remote name", "origin").option("--limit <n>", "PRs to read PER BRANCH \u2014 an effort bound, not a correctness one: merge state is resolved per branch, so no branch is ever skipped for being old (#4227)", "200").option("--force", "remove worktrees even when the ownership registry shows another session created or worked in them recently (#3580), or when a dead worktree directory still holds leftover files (#4779)").option("--root <path>", "sweep an explicitly named worktrees root instead of the authoritative ../mmi-worktrees (#3471) \u2014 descends into this repo container when present; ownership, dead-dir, and content guards still apply").action(async (o) => {
40573
+ gcCmd.option("--dry-run", "show what would be deleted (default)").option("--apply", "delete only the listed clean merged/closed PR local+remote branches, linked worktrees, and stale tracking refs").option("--json", "machine-readable output").option("--scratch", "prune safe local scratch (#1864) instead of git branches/refs; local plans are surfaced advisory-only, never auto-pruned").option("--remote <name>", "remote name", "origin").option("--limit <n>", "PRs to read PER BRANCH \u2014 an effort bound, not a correctness one: merge state is resolved per branch, so no branch is ever skipped for being old (#4227)", "200").option("--force", "remove worktrees even when the ownership registry shows another session created or worked in them recently (#3580), or when a dead worktree directory still holds leftover files (#4779)").option("--root <path>", "sweep an explicitly named worktrees root instead of the authoritative ../mmi-worktrees (#3471) \u2014 descends into this repo container when present; ownership, dead-dir, and content guards still apply").option("--train-only", "explicit keep-only-train path: also reap closed-not-merged / no-PR origin leftovers; never deletes open PR heads (#4903)").action(async (o) => {
40295
40574
  if (o.apply && o.dryRun) return fail("worktree gc: choose either --dry-run or --apply");
40296
40575
  if (o.scratch) {
40297
40576
  try {
@@ -40308,7 +40587,7 @@ gcCmd.option("--dry-run", "show what would be deleted (default)").option("--appl
40308
40587
  if (!Number.isFinite(limit) || limit < 1) return fail("worktree gc: --limit must be a positive integer");
40309
40588
  let root;
40310
40589
  if (o.root !== void 0) {
40311
- root = (0, import_node_path45.resolve)(o.root);
40590
+ root = (0, import_node_path46.resolve)(o.root);
40312
40591
  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`);
40313
40592
  const gcRepoRoot = (await execFileP2("git", ["rev-parse", "--show-toplevel"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim() || process.cwd();
40314
40593
  if (isPathUnderDirectory2(gcRepoRoot, root)) {
@@ -40316,10 +40595,11 @@ gcCmd.option("--dry-run", "show what would be deleted (default)").option("--appl
40316
40595
  }
40317
40596
  }
40318
40597
  try {
40319
- const plan = await gcPlan(o.remote, limit, { root });
40598
+ const plan = await gcPlan(o.remote, limit, { root, trainOnly: o.trainOnly });
40599
+ const auditedClone = (await execFileP2("git", ["rev-parse", "--show-toplevel"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim() || process.cwd();
40320
40600
  if (root && !o.json) console.log(`worktree gc: scanning the explicitly named root ${root} for worktrees proven to belong to this repo
40321
40601
  `);
40322
- if (o.apply && !o.json) console.log(formatGcPlan(plan, true));
40602
+ if (o.apply && !o.json) console.log(formatGcPlan(plan, true, auditedClone));
40323
40603
  let applyResult;
40324
40604
  if (o.apply) {
40325
40605
  const deferredStore = await createDeferredWorktreeStore();
@@ -40338,7 +40618,7 @@ gcCmd.option("--dry-run", "show what would be deleted (default)").option("--appl
40338
40618
  if (o.json) {
40339
40619
  console.log(JSON.stringify({ dryRun: !o.apply, remote: o.remote, ...root ? { root } : {}, plan, applyResult }, null, 2));
40340
40620
  } else if (!o.apply) {
40341
- console.log(formatGcPlan(plan, false));
40621
+ console.log(formatGcPlan(plan, false, auditedClone));
40342
40622
  } else {
40343
40623
  if (applyResult) console.log(`
40344
40624
  ${renderGcApplyResult(applyResult, plan.skipped)}`);
@@ -40402,7 +40682,8 @@ async function currentWorktreeRemovalContext(command, force) {
40402
40682
  actor: describeActor({ env: process.env, surface: detectSurface(process.env), cwd }),
40403
40683
  command,
40404
40684
  ...force ? { force: true } : {},
40405
- ...activeWorkspaceRoot ? { activeWorkspaceRoot } : {}
40685
+ ...activeWorkspaceRoot ? { activeWorkspaceRoot } : {},
40686
+ cursorAgentHost: isCursorAgentHost()
40406
40687
  };
40407
40688
  }
40408
40689
  async function unprovenWorktreeReason(wtPath, repoRoot2) {
@@ -40450,7 +40731,7 @@ function acquireWorktreeSetupLock(worktreeRoot) {
40450
40731
  };
40451
40732
  };
40452
40733
  try {
40453
- (0, import_node_fs48.mkdirSync)((0, import_node_path45.dirname)(lockPath), { recursive: true });
40734
+ (0, import_node_fs48.mkdirSync)((0, import_node_path46.dirname)(lockPath), { recursive: true });
40454
40735
  return take();
40455
40736
  } catch {
40456
40737
  try {
@@ -42136,11 +42417,11 @@ pr.command("view <number>").description("read a PR as structured JSON (merged st
42136
42417
  }
42137
42418
  });
42138
42419
  async function listCiWorkflowPaths(cwd = process.cwd()) {
42139
- const wfDir = (0, import_node_path45.join)(cwd, ".github", "workflows");
42420
+ const wfDir = (0, import_node_path46.join)(cwd, ".github", "workflows");
42140
42421
  if (!(0, import_node_fs48.existsSync)(wfDir)) return [];
42141
42422
  return (0, import_node_fs48.readdirSync)(wfDir).filter((name) => /\.(ya?ml)$/i.test(name)).filter((name) => {
42142
42423
  try {
42143
- return workflowReportsPrChecks((0, import_node_fs48.readFileSync)((0, import_node_path45.join)(wfDir, name), "utf8"));
42424
+ return workflowReportsPrChecks((0, import_node_fs48.readFileSync)((0, import_node_path46.join)(wfDir, name), "utf8"));
42144
42425
  } catch {
42145
42426
  return true;
42146
42427
  }
@@ -42192,16 +42473,16 @@ function ciAuditDeps() {
42192
42473
  // gate re-seed step is skipped gracefully rather than failing mid-run.
42193
42474
  readSeedFile: (path2) => {
42194
42475
  if (!root) return null;
42195
- const fullPath = (0, import_node_path45.join)(root, path2);
42476
+ const fullPath = (0, import_node_path46.join)(root, path2);
42196
42477
  return (0, import_node_fs48.existsSync)(fullPath) ? (0, import_node_fs48.readFileSync)(fullPath, "utf8") : null;
42197
42478
  }
42198
42479
  };
42199
42480
  }
42200
42481
  function hubRoot() {
42201
- const fromPkg = (0, import_node_path45.join)(__dirname, "..", "..");
42482
+ const fromPkg = (0, import_node_path46.join)(__dirname, "..", "..");
42202
42483
  const marker = "skills/bootstrap/seeds/manifest.json";
42203
- if ((0, import_node_fs48.existsSync)((0, import_node_path45.join)(fromPkg, marker))) return fromPkg;
42204
- if ((0, import_node_fs48.existsSync)((0, import_node_path45.join)(process.cwd(), marker))) return process.cwd();
42484
+ if ((0, import_node_fs48.existsSync)((0, import_node_path46.join)(fromPkg, marker))) return fromPkg;
42485
+ if ((0, import_node_fs48.existsSync)((0, import_node_path46.join)(process.cwd(), marker))) return process.cwd();
42205
42486
  return null;
42206
42487
  }
42207
42488
  async function waitLoopCorePool(label) {
@@ -43257,7 +43538,7 @@ function directoryBytes(path2) {
43257
43538
  return 0;
43258
43539
  }
43259
43540
  for (const entry of entries) {
43260
- const child2 = (0, import_node_path45.join)(path2, entry.name);
43541
+ const child2 = (0, import_node_path46.join)(path2, entry.name);
43261
43542
  if (entry.isDirectory()) total += directoryBytes(child2);
43262
43543
  else {
43263
43544
  try {
@@ -43287,7 +43568,7 @@ function pluginCacheFsDeps(configRoot, dirBytes) {
43287
43568
  dirBytes,
43288
43569
  listStagingDirs: (root) => (0, import_node_fs48.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => {
43289
43570
  try {
43290
- return { name: d.name, mtimeMs: newestMtimeMs((0, import_node_path45.join)(root, d.name), listDirEntries, (p) => (0, import_node_fs48.statSync)(p).mtimeMs) };
43571
+ return { name: d.name, mtimeMs: newestMtimeMs((0, import_node_path46.join)(root, d.name), listDirEntries, (p) => (0, import_node_fs48.statSync)(p).mtimeMs) };
43291
43572
  } catch {
43292
43573
  return { name: d.name, mtimeMs: Date.now() };
43293
43574
  }
@@ -43301,7 +43582,7 @@ function stagingApplyFsGuard(configRoot) {
43301
43582
  return {
43302
43583
  referencedPaths: () => readInstalledPluginRefs(configRoot),
43303
43584
  mtimeMs: (name) => {
43304
- const p = (0, import_node_path45.join)(stagingRoot, name);
43585
+ const p = (0, import_node_path46.join)(stagingRoot, name);
43305
43586
  if (!(0, import_node_fs48.existsSync)(p)) return null;
43306
43587
  try {
43307
43588
  return newestMtimeMs(p, listDirEntries, (q) => (0, import_node_fs48.statSync)(q).mtimeMs);
@@ -43324,7 +43605,7 @@ program2.command("plugin-prune").description(`prune stale cached MMI plugin vers
43324
43605
  return;
43325
43606
  }
43326
43607
  const plan = buildPluginCachePlan(
43327
- (0, import_node_os19.homedir)(),
43608
+ (0, import_node_os20.homedir)(),
43328
43609
  running,
43329
43610
  pluginCacheFsDeps(configRoot, directoryBytes),
43330
43611
  { withBytes: true, configRoot, includeStaging: surface !== "codex" }
@@ -43346,7 +43627,7 @@ function readReleaseCatchupState(path2) {
43346
43627
  }
43347
43628
  function writeReleaseCatchupState(path2, state) {
43348
43629
  try {
43349
- (0, import_node_fs48.mkdirSync)((0, import_node_path45.dirname)(path2), { recursive: true });
43630
+ (0, import_node_fs48.mkdirSync)((0, import_node_path46.dirname)(path2), { recursive: true });
43350
43631
  (0, import_node_fs48.writeFileSync)(path2, `${JSON.stringify(state)}
43351
43632
  `);
43352
43633
  } catch {
@@ -43355,7 +43636,7 @@ function writeReleaseCatchupState(path2, state) {
43355
43636
  program2.command("plugin-release-catchup").description("install a newer released MMI plugin clone non-destructively and re-point the Pi registration (#4297); TTL-gated no-op when current").option("--force", "skip the 24h TTL (acceptance proof / manual run)").option("--quiet", "print only failures (the detached session-start lane)").option("--json", "machine-readable output").action(async (o) => {
43356
43637
  const outcome = await withEnvHealLock(
43357
43638
  "plugin release catch-up",
43358
- () => runReleaseCatchup((0, import_node_os19.homedir)(), process.env, {
43639
+ () => runReleaseCatchup((0, import_node_os20.homedir)(), process.env, {
43359
43640
  fetchReleased: fetchNpmReleasedVersion,
43360
43641
  runClaude: (args, step) => runPluginCli("claude", args, (msg) => {
43361
43642
  if (!o.quiet && !o.json) console.log(msg);
@@ -43371,7 +43652,7 @@ program2.command("plugin-release-catchup").description("install a newer released
43371
43652
  },
43372
43653
  readState: readReleaseCatchupState,
43373
43654
  writeState: writeReleaseCatchupState,
43374
- healRegistration: defaultRegistrationHeal((0, import_node_os19.homedir)(), process.env),
43655
+ healRegistration: defaultRegistrationHeal((0, import_node_os20.homedir)(), process.env),
43375
43656
  now: () => Date.now()
43376
43657
  }, { force: o.force })
43377
43658
  );
@@ -43439,7 +43720,7 @@ program2.command("session-start").description("run the SessionStart verbs (whoam
43439
43720
  spawnDetachedSelf(["worktree", "setup", "--quiet"], { spawn: import_node_child_process20.spawn, execPath: process.execPath, scriptPath: process.argv[1] });
43440
43721
  bannerIo.log(worktreeBanner);
43441
43722
  }
43442
- if (shouldSpawnReleaseCatchup((0, import_node_os19.homedir)(), process.env, readReleaseCatchupState)) {
43723
+ if (shouldSpawnReleaseCatchup((0, import_node_os20.homedir)(), process.env, readReleaseCatchupState)) {
43443
43724
  spawnDetachedSelf(["plugin", "release-catchup", "--quiet"], { spawn: import_node_child_process20.spawn, execPath: process.execPath, scriptPath: process.argv[1] });
43444
43725
  }
43445
43726
  if (isLinkedWorktree(process.cwd())) {