@mutmutco/cli 3.127.0 → 3.128.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 +742 -336
  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.128.0",
16041
+ tag: "v3.128.0",
16042
+ commit: "95241fa22be9",
16043
+ npm: "@mutmutco/cli@3.128.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.128.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.128.0 and redeploy the Hub Lambda from tag v3.128.0 (95241fa22be9); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
16067
+ v3Target: "v3.128.0 (@mutmutco/cli@3.128.0, tag commit 95241fa22be9 \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
@@ -24025,14 +24213,14 @@ function probeLocalClaimSession(marker, now = Date.now()) {
24025
24213
  claimSessionProbeCache.set(cacheKey, { checkedAt: now, state });
24026
24214
  return state;
24027
24215
  };
24028
- const root = (0, import_node_path22.join)((0, import_node_os8.homedir)(), ".claude", "projects");
24216
+ const root = (0, import_node_path23.join)((0, import_node_os8.homedir)(), ".claude", "projects");
24029
24217
  try {
24030
24218
  const wanted = `${marker.session}.jsonl`.toLowerCase();
24031
24219
  const pending = [root];
24032
24220
  while (pending.length) {
24033
24221
  const dir = pending.pop();
24034
24222
  for (const entry of (0, import_node_fs24.readdirSync)(dir, { withFileTypes: true })) {
24035
- const path2 = (0, import_node_path22.join)(dir, entry.name);
24223
+ const path2 = (0, import_node_path23.join)(dir, entry.name);
24036
24224
  if (entry.isDirectory()) pending.push(path2);
24037
24225
  else if (entry.isFile() && entry.name.toLowerCase() === wanted) {
24038
24226
  return remember(now - (0, import_node_fs24.statSync)(path2).mtimeMs <= CLAIM_SESSION_ACTIVITY_MS ? "live" : "dead");
@@ -24938,7 +25126,7 @@ function consolidateCommandNamespaces(program3) {
24938
25126
 
24939
25127
  // src/pi-plugin-registration.ts
24940
25128
  var import_node_fs25 = require("node:fs");
24941
- var import_node_path23 = require("node:path");
25129
+ var import_node_path24 = require("node:path");
24942
25130
  var import_proper_lockfile2 = __toESM(require_proper_lockfile(), 1);
24943
25131
 
24944
25132
  // src/plugin-cache-prune.ts
@@ -25201,17 +25389,17 @@ function newestExistingPiPlugin(home) {
25201
25389
  return void 0;
25202
25390
  }
25203
25391
  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");
25392
+ const candidate = (0, import_node_path24.join)(cacheRoot, version, ".pi-plugin");
25205
25393
  if ((0, import_node_fs25.existsSync)(candidate)) return candidate;
25206
25394
  }
25207
25395
  return void 0;
25208
25396
  }
25209
25397
  function expectedPiPluginPath(home, env, installedVersion) {
25210
25398
  const root = env.CLAUDE_PLUGIN_ROOT?.trim();
25211
- if (root && /[\\/]mutmutco[\\/]mmi[\\/]/.test(root)) return (0, import_node_path23.join)(root, ".pi-plugin");
25399
+ if (root && /[\\/]mutmutco[\\/]mmi[\\/]/.test(root)) return (0, import_node_path24.join)(root, ".pi-plugin");
25212
25400
  const version = installedVersion ?? runningPluginVersion(env);
25213
25401
  if (version) {
25214
- const pinned = (0, import_node_path23.join)(home, ".claude", "plugins", "cache", "mutmutco", "mmi", version, ".pi-plugin");
25402
+ const pinned = (0, import_node_path24.join)(home, ".claude", "plugins", "cache", "mutmutco", "mmi", version, ".pi-plugin");
25215
25403
  if ((0, import_node_fs25.existsSync)(pinned)) return pinned;
25216
25404
  }
25217
25405
  return newestExistingPiPlugin(home);
@@ -25219,15 +25407,15 @@ function expectedPiPluginPath(home, env, installedVersion) {
25219
25407
  function agentDirs(home, env = process.env) {
25220
25408
  const override = env.JERVCODE_CODING_AGENT_DIR?.trim() || env.PI_CODING_AGENT_DIR?.trim();
25221
25409
  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");
25410
+ const jerv = (0, import_node_path24.join)(home, ".jerv", "agent");
25411
+ const pi = (0, import_node_path24.join)(home, ".pi", "agent");
25224
25412
  if (!(0, import_node_fs25.existsSync)(jerv) && !(0, import_node_fs25.existsSync)(pi)) return [];
25225
25413
  const dirs = [jerv];
25226
25414
  if ((0, import_node_fs25.existsSync)(pi) && pi !== jerv) dirs.push(pi);
25227
25415
  return dirs;
25228
25416
  }
25229
25417
  function settingsPath(agentDir) {
25230
- return (0, import_node_path23.join)(agentDir, "settings.json");
25418
+ return (0, import_node_path24.join)(agentDir, "settings.json");
25231
25419
  }
25232
25420
  function readPiPluginState(home, env, installedVersion) {
25233
25421
  const dirs = agentDirs(home, env);
@@ -25261,7 +25449,7 @@ function acquirePiSettingsLock2(settingsFile) {
25261
25449
  return void 0;
25262
25450
  }
25263
25451
  function atomicWriteSettings(file, body) {
25264
- (0, import_node_fs25.mkdirSync)((0, import_node_path23.dirname)(file), { recursive: true });
25452
+ (0, import_node_fs25.mkdirSync)((0, import_node_path24.dirname)(file), { recursive: true });
25265
25453
  const tmp = `${file}.tmp-${process.pid}`;
25266
25454
  (0, import_node_fs25.writeFileSync)(tmp, body, "utf8");
25267
25455
  try {
@@ -25339,18 +25527,18 @@ function healPiPluginRegistration(home, env, installedVersion) {
25339
25527
  // src/claude-binary-doctor.ts
25340
25528
  var import_node_fs27 = require("node:fs");
25341
25529
  var import_node_os11 = require("node:os");
25342
- var import_node_path25 = require("node:path");
25530
+ var import_node_path26 = require("node:path");
25343
25531
 
25344
25532
  // src/jerv-cli-spawn.ts
25345
25533
  var import_node_fs26 = require("node:fs");
25346
25534
  var import_node_os10 = require("node:os");
25347
- var import_node_path24 = require("node:path");
25535
+ var import_node_path25 = require("node:path");
25348
25536
  var WIN_NAMES = ["jerv-cli.cmd", "jerv-cli.exe", "jerv-cli"];
25349
25537
  var POSIX_NAMES = ["jerv-cli"];
25350
- var JERV_CLI_ENTRY = (0, import_node_path24.join)("node_modules", "@jervaise", "jerv-cli", "dist", "index.cjs");
25538
+ var JERV_CLI_ENTRY = (0, import_node_path25.join)("node_modules", "@jervaise", "jerv-cli", "dist", "index.cjs");
25351
25539
  function pathEnvEntries(pathEnv, platform2 = process.platform) {
25352
25540
  if (platform2 !== "win32") {
25353
- return pathEnv.split(import_node_path24.delimiter).map((e) => e.trim()).filter(Boolean);
25541
+ return pathEnv.split(import_node_path25.delimiter).map((e) => e.trim()).filter(Boolean);
25354
25542
  }
25355
25543
  if (pathEnv.includes(";")) {
25356
25544
  return pathEnv.split(";").map((e) => e.trim()).filter(Boolean);
@@ -25383,10 +25571,10 @@ function jervCliCandidateDirs(env = process.env, home = (0, import_node_os10.hom
25383
25571
  push(normalizeSpawnPathEntry(entry, platform2));
25384
25572
  }
25385
25573
  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"));
25574
+ if (env.APPDATA) push((0, import_node_path25.join)(env.APPDATA, "npm"));
25575
+ if (env.LOCALAPPDATA) push((0, import_node_path25.join)(env.LOCALAPPDATA, "npm"));
25388
25576
  } else {
25389
- push((0, import_node_path24.join)(home, ".local", "bin"));
25577
+ push((0, import_node_path25.join)(home, ".local", "bin"));
25390
25578
  }
25391
25579
  return out;
25392
25580
  }
@@ -25394,7 +25582,7 @@ function jervCliCandidatePaths(env = process.env, home = (0, import_node_os10.ho
25394
25582
  const names = platform2 === "win32" ? WIN_NAMES : POSIX_NAMES;
25395
25583
  const out = [];
25396
25584
  for (const dir of jervCliCandidateDirs(env, home, platform2)) {
25397
- for (const name of names) out.push((0, import_node_path24.join)(dir, name));
25585
+ for (const name of names) out.push((0, import_node_path25.join)(dir, name));
25398
25586
  }
25399
25587
  return out;
25400
25588
  }
@@ -25405,7 +25593,7 @@ function resolveJervCliPath(env = process.env, home = (0, import_node_os10.homed
25405
25593
  return void 0;
25406
25594
  }
25407
25595
  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);
25596
+ const entry = (0, import_node_path25.join)((0, import_node_path25.dirname)(shimPath), JERV_CLI_ENTRY);
25409
25597
  return exists(entry) ? entry : void 0;
25410
25598
  }
25411
25599
  function jervCliExecFileArgs(args, opts = {}) {
@@ -25500,10 +25688,10 @@ function globalNodeModulesRoots(host) {
25500
25688
  out.push(dir);
25501
25689
  };
25502
25690
  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"));
25691
+ if (prefix) push(platform2 === "win32" ? (0, import_node_path26.join)(prefix, "node_modules") : (0, import_node_path26.join)(prefix, "lib", "node_modules"));
25504
25692
  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"));
25693
+ push((0, import_node_path26.join)(dir, "node_modules"));
25694
+ push((0, import_node_path26.join)((0, import_node_path26.dirname)(dir), "lib", "node_modules"));
25507
25695
  }
25508
25696
  return out;
25509
25697
  }
@@ -25541,17 +25729,17 @@ function readClaudeBinaryState(host = {}) {
25541
25729
  const arch = host.arch ?? process.arch;
25542
25730
  const magic = EXECUTABLE_MAGIC[platform2];
25543
25731
  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")));
25732
+ 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
25733
  if (!packageRoot) return void 0;
25546
25734
  const keys = platformPackageKeys(platform2, arch);
25547
25735
  const fallbackPackage = `${PACKAGE}-${keys[0]}`;
25548
25736
  let manifest;
25549
25737
  try {
25550
- manifest = JSON.parse((0, import_node_fs27.readFileSync)((0, import_node_path25.join)(packageRoot, "package.json"), "utf8"));
25738
+ manifest = JSON.parse((0, import_node_fs27.readFileSync)((0, import_node_path26.join)(packageRoot, "package.json"), "utf8"));
25551
25739
  } catch (e) {
25552
25740
  return {
25553
25741
  state: "unreadable",
25554
- binPath: (0, import_node_path25.join)(packageRoot, "package.json"),
25742
+ binPath: (0, import_node_path26.join)(packageRoot, "package.json"),
25555
25743
  expectedMagic: magic.name,
25556
25744
  platformPackage: fallbackPackage,
25557
25745
  error: `package.json could not be read \u2014 ${e.message}`
@@ -25568,15 +25756,15 @@ function readClaudeBinaryState(host = {}) {
25568
25756
  error: "package.json declares no `bin` entry \u2014 the executed file cannot be resolved"
25569
25757
  };
25570
25758
  }
25571
- const binPath = (0, import_node_path25.join)(packageRoot, binRelative);
25572
- const binName = (0, import_node_path25.basename)(binRelative);
25759
+ const binPath = (0, import_node_path26.join)(packageRoot, binRelative);
25760
+ const binName = (0, import_node_path26.basename)(binRelative);
25573
25761
  const optional = manifest.optionalDependencies;
25574
25762
  const publishes = (name) => typeof optional === "object" && optional !== null && Object.prototype.hasOwnProperty.call(optional, name);
25575
25763
  const published = keys.map((key) => `${PACKAGE}-${key}`).filter(publishes);
25576
25764
  if (published.length === 0) return void 0;
25577
25765
  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)
25766
+ (0, import_node_path26.join)(packageRoot, "node_modules", ...name.split("/"), binName),
25767
+ (0, import_node_path26.join)((0, import_node_path26.dirname)((0, import_node_path26.dirname)(packageRoot)), ...name.split("/"), binName)
25580
25768
  ];
25581
25769
  const found = published.map((name) => ({ name, path: binIn(name).find((file) => (0, import_node_fs27.existsSync)(file)) })).find((c) => c.path);
25582
25770
  const platformPackage = found?.name ?? published[0];
@@ -25901,7 +26089,7 @@ function renderVerifyBroker(input) {
25901
26089
  var import_node_crypto4 = require("node:crypto");
25902
26090
  var import_node_fs28 = require("node:fs");
25903
26091
  var import_promises5 = require("node:fs/promises");
25904
- var import_node_path26 = require("node:path");
26092
+ var import_node_path27 = require("node:path");
25905
26093
  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
26094
  var MAX_BYTES = 5 * 1024 * 1024 * 1024;
25907
26095
  async function sha256File(path2) {
@@ -25911,7 +26099,7 @@ async function sha256File(path2) {
25911
26099
  }
25912
26100
  async function putTenantArtifact(repo, stage, inputPath, deps) {
25913
26101
  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);
26102
+ const path2 = (0, import_node_path27.resolve)(inputPath);
25915
26103
  const info = await (0, import_promises5.stat)(path2);
25916
26104
  if (!info.isFile()) throw new Error("tenant artifact put: input path must be a file");
25917
26105
  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 +27236,7 @@ async function announceRelease(deps, args) {
27048
27236
  var import_node_crypto5 = require("node:crypto");
27049
27237
  var import_node_child_process13 = require("node:child_process");
27050
27238
  var import_node_fs29 = require("node:fs");
27051
- var import_node_path27 = require("node:path");
27239
+ var import_node_path28 = require("node:path");
27052
27240
  var REPO_INDEX_SCHEMA = 1;
27053
27241
  var HARD_DENY = [
27054
27242
  /(^|\/)\.env(\.|$)/i,
@@ -27173,7 +27361,7 @@ function loadReadmeHints(cwd, candidatePaths) {
27173
27361
  }
27174
27362
  for (const rel of readmes) {
27175
27363
  if (isHardDeniedPath(rel)) continue;
27176
- const abs = (0, import_node_path27.join)(cwd, ...rel.split("/"));
27364
+ const abs = (0, import_node_path28.join)(cwd, ...rel.split("/"));
27177
27365
  if (!(0, import_node_fs29.existsSync)(abs)) continue;
27178
27366
  let text;
27179
27367
  try {
@@ -27190,7 +27378,7 @@ function loadReadmeHints(cwd, candidatePaths) {
27190
27378
  return hints;
27191
27379
  }
27192
27380
  function toPosix(p) {
27193
- return p.split(import_node_path27.sep).join("/");
27381
+ return p.split(import_node_path28.sep).join("/");
27194
27382
  }
27195
27383
  function listCandidatePaths(cwd, exec = import_node_child_process13.execFileSync) {
27196
27384
  try {
@@ -27212,7 +27400,7 @@ function rebuildRepoIndex(cwd, repoSlug2) {
27212
27400
  for (const rel of candidates) {
27213
27401
  if (ignored.has(rel)) continue;
27214
27402
  if (isHardDeniedPath(rel)) continue;
27215
- const abs = (0, import_node_path27.join)(cwd, ...rel.split("/"));
27403
+ const abs = (0, import_node_path28.join)(cwd, ...rel.split("/"));
27216
27404
  if (!(0, import_node_fs29.existsSync)(abs)) continue;
27217
27405
  let text;
27218
27406
  try {
@@ -27241,7 +27429,7 @@ function rebuildRepoIndex(cwd, repoSlug2) {
27241
27429
  entries
27242
27430
  };
27243
27431
  const store = repoIndexStorePath(cwd);
27244
- (0, import_node_fs29.mkdirSync)((0, import_node_path27.dirname)(store), { recursive: true });
27432
+ (0, import_node_fs29.mkdirSync)((0, import_node_path28.dirname)(store), { recursive: true });
27245
27433
  (0, import_node_fs29.writeFileSync)(store, `${JSON.stringify(projection, null, 2)}
27246
27434
  `, "utf8");
27247
27435
  return projection;
@@ -27322,7 +27510,7 @@ function inferRepoSlug(cwd, exec = import_node_child_process13.execFileSync) {
27322
27510
  if (m?.[1]) return m[1].toLowerCase();
27323
27511
  } catch {
27324
27512
  }
27325
- return ((0, import_node_path27.basename)(cwd) || "local").toLowerCase();
27513
+ return ((0, import_node_path28.basename)(cwd) || "local").toLowerCase();
27326
27514
  }
27327
27515
 
27328
27516
  // src/repo-index-cloud-client.ts
@@ -27464,7 +27652,7 @@ async function gcRepoIndexCloud(deps) {
27464
27652
  // src/repo-index-sync.ts
27465
27653
  var import_node_fs30 = require("node:fs");
27466
27654
  var import_node_os12 = require("node:os");
27467
- var import_node_path28 = require("node:path");
27655
+ var import_node_path29 = require("node:path");
27468
27656
  var import_node_child_process14 = require("node:child_process");
27469
27657
  var MAX_EMBED_BACKFILL_ROUNDS = 40;
27470
27658
  function normalizeRepo(raw) {
@@ -27508,7 +27696,7 @@ async function syncEstateRepoIndex(opts) {
27508
27696
  const failed = [];
27509
27697
  const skipped = [];
27510
27698
  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-"));
27699
+ const dir = (0, import_node_fs30.mkdtempSync)((0, import_node_path29.join)((0, import_node_os12.tmpdir)(), "mmi-repo-index-"));
27512
27700
  try {
27513
27701
  shallowClone(repo, dir, opts.githubToken);
27514
27702
  const built = rebuildRepoIndex(dir, repo);
@@ -27764,7 +27952,7 @@ async function runRepoIndexHealth(opts) {
27764
27952
  // src/spawn-policy-core.ts
27765
27953
  var import_node_child_process15 = require("node:child_process");
27766
27954
  var import_node_fs32 = require("node:fs");
27767
- var import_node_path29 = require("node:path");
27955
+ var import_node_path30 = require("node:path");
27768
27956
  var SPAWNERS = ["spawn", "spawnSync", "exec", "execSync", "execFile", "execFileSync"];
27769
27957
  var CALL_SOURCE = String.raw`(^|[^.\w$])(${SPAWNERS.join("|")})\s*\(`;
27770
27958
  var SOURCE_EXT = /\.(ts|mts|cts|js|mjs|cjs)$/;
@@ -27850,7 +28038,7 @@ function runSpawnPolicy(root) {
27850
28038
  for (const file of files) {
27851
28039
  let raw;
27852
28040
  try {
27853
- raw = (0, import_node_fs32.readFileSync)((0, import_node_path29.join)(root, file), "utf8");
28041
+ raw = (0, import_node_fs32.readFileSync)((0, import_node_path30.join)(root, file), "utf8");
27854
28042
  } catch {
27855
28043
  continue;
27856
28044
  }
@@ -27869,7 +28057,7 @@ function runSpawnPolicy(root) {
27869
28057
  // src/test-policy-core.ts
27870
28058
  var import_node_child_process16 = require("node:child_process");
27871
28059
  var import_node_fs33 = require("node:fs");
27872
- var import_node_path30 = require("node:path");
28060
+ var import_node_path31 = require("node:path");
27873
28061
  var POLICY_FILE = "test-policy.json";
27874
28062
  var TEST_RE = /\.(?:test|spec)\.[cm]?[jt]sx?$/;
27875
28063
  var PY_TEST_RE = /(?:^|\/)test_[^/]*\.py$|_test\.py$/;
@@ -27922,7 +28110,7 @@ function isTestPath(path2) {
27922
28110
  return TEST_RE.test(path2) || PY_TEST_RE.test(path2);
27923
28111
  }
27924
28112
  function loadPolicy(root, readFile9 = readFileOrNull2) {
27925
- const raw = readFile9((0, import_node_path30.join)(root, POLICY_FILE));
28113
+ const raw = readFile9((0, import_node_path31.join)(root, POLICY_FILE));
27926
28114
  if (raw == null) return { mandatory: [], declared: false };
27927
28115
  try {
27928
28116
  return { ...JSON.parse(raw), declared: true };
@@ -27960,11 +28148,11 @@ function classify(changed, policy, present = () => false) {
27960
28148
  return { mandatoryHits, untestedHits, testChanges, addedTests, removedProtected };
27961
28149
  }
27962
28150
  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)));
28151
+ return (policy.protected ?? []).map((p) => p.path).filter((p) => !exists((0, import_node_path31.join)(root, p)));
27964
28152
  }
27965
28153
  function unresolvedSatisfiers(policy, root, exists = (path2) => (0, import_node_fs33.existsSync)(path2)) {
27966
28154
  const declared = (policy.mandatory ?? []).flatMap((m) => m.satisfiedBy ?? []);
27967
- return [...new Set(declared)].filter((p) => !exists((0, import_node_path30.join)(root, p)));
28155
+ return [...new Set(declared)].filter((p) => !exists((0, import_node_path31.join)(root, p)));
27968
28156
  }
27969
28157
  function evaluate(changed, policy, present = () => false) {
27970
28158
  const { mandatoryHits, untestedHits, testChanges, addedTests, removedProtected } = classify(changed, policy, present);
@@ -28152,7 +28340,7 @@ function runTestPolicy(root, deps = {}) {
28152
28340
  const refusal = deps.changed ? null : untrustworthyRange(root, base);
28153
28341
  const changed = deps.changed ?? (refusal ? [] : changedFilesSince(base, root));
28154
28342
  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));
28343
+ const present = (path2) => exists((0, import_node_path31.join)(root, path2));
28156
28344
  const removedByThisDiff = removedPaths(changed);
28157
28345
  const staleFindings = [];
28158
28346
  const unresolved = unresolvedProtectedEntries(policy, root, exists).filter((p) => !removedByThisDiff.has(p));
@@ -28191,7 +28379,7 @@ function runTestPolicy(root, deps = {}) {
28191
28379
 
28192
28380
  // src/project-info-sync.ts
28193
28381
  var import_node_fs34 = require("node:fs");
28194
- var import_node_path31 = require("node:path");
28382
+ var import_node_path32 = require("node:path");
28195
28383
  var UPDATE_PROJECT_INFO = `mutation($projectId: ID!, $shortDescription: String!, $readme: String!) {
28196
28384
  updateProjectV2(input: { projectId: $projectId, shortDescription: $shortDescription, readme: $readme }) {
28197
28385
  projectV2 { id }
@@ -28236,7 +28424,7 @@ function sharedName(entries, fallback) {
28236
28424
  }
28237
28425
  function buildProjectInfoSyncPlan(targetRepo2, project2, projects, repoRoot2) {
28238
28426
  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");
28427
+ const readmePath = (0, import_node_path32.join)(repoRoot2, "README.md");
28240
28428
  if (!(0, import_node_fs34.existsSync)(readmePath)) throw new Error(`org project sync-info: ${targetRepo2} has no README.md`);
28241
28429
  const entries = entriesFor(project2, projects);
28242
28430
  const memberRepos = [...new Set(entries.flatMap((entry) => entry.repos ?? []))].filter((repo) => /^[^/]+\/[^/]+$/.test(repo)).sort((a, b) => a.localeCompare(b));
@@ -28262,8 +28450,8 @@ function buildProjectInfoSyncPlan(targetRepo2, project2, projects, repoRoot2) {
28262
28450
  const targetBase = `https://github.com/${targetRepo2}`;
28263
28451
  const targetBranch = branchFor(targetRepo2, projects);
28264
28452
  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)` : ""
28453
+ (0, import_node_fs34.existsSync)((0, import_node_path32.join)(repoRoot2, "docs", "org-readme.md")) ? `- [Org identity](${targetBase}/blob/${targetBranch}/docs/org-readme.md)` : "",
28454
+ (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
28455
  ].filter(Boolean);
28268
28456
  if (orgDocs.length) lines.push("", "## Organisation docs", "", ...orgDocs);
28269
28457
  return { projectId: project2.projectId, projectName, targetRepo: targetRepo2, memberRepos, shortDescription, readme: `${lines.join("\n")}
@@ -29090,7 +29278,7 @@ function writeError(res) {
29090
29278
 
29091
29279
  // src/secrets-commands.ts
29092
29280
  var import_node_fs35 = require("node:fs");
29093
- var import_node_path32 = require("node:path");
29281
+ var import_node_path33 = require("node:path");
29094
29282
  var import_node_os13 = require("node:os");
29095
29283
 
29096
29284
  // src/secrets-diff.ts
@@ -29193,11 +29381,11 @@ function collectMap(value, previous = []) {
29193
29381
  return [...previous, value];
29194
29382
  }
29195
29383
  async function decryptRailsCredentials(input) {
29196
- const appDir = (0, import_node_path32.resolve)(input.appDir ?? process.cwd());
29384
+ const appDir = (0, import_node_path33.resolve)(input.appDir ?? process.cwd());
29197
29385
  const credentialsFile = input.credentialsFile ?? DEFAULT_RAILS_CREDENTIALS_FILE;
29198
29386
  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);
29387
+ const credentialsPath = (0, import_node_path33.resolve)(appDir, credentialsFile);
29388
+ const masterKeyPath = (0, import_node_path33.resolve)(appDir, masterKeyFile);
29201
29389
  const env = {
29202
29390
  ...process.env,
29203
29391
  MMI_RAILS_CREDENTIALS_FILE: credentialsPath,
@@ -29214,8 +29402,8 @@ async function decryptRailsCredentials(input) {
29214
29402
  'config = ActiveSupport::EncryptedConfiguration.new(config_path: config_path, key_path: key_path, env_key: "RAILS_MASTER_KEY", raise_if_missing_key: true)',
29215
29403
  "puts JSON.generate(config.config)"
29216
29404
  ].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");
29405
+ const scriptDir = (0, import_node_fs35.mkdtempSync)((0, import_node_path33.join)((0, import_node_os13.tmpdir)(), "mmi-rails-decrypt-"));
29406
+ const scriptPath = (0, import_node_path33.join)(scriptDir, "decrypt.rb");
29219
29407
  (0, import_node_fs35.writeFileSync)(scriptPath, script, "utf8");
29220
29408
  try {
29221
29409
  const args = ["exec", "ruby", scriptPath];
@@ -29318,7 +29506,7 @@ function registerSecretsCommands(program3) {
29318
29506
  let body;
29319
29507
  if (o.file) {
29320
29508
  try {
29321
- body = (0, import_node_fs35.readFileSync)((0, import_node_path32.resolve)(o.file), "utf8");
29509
+ body = (0, import_node_fs35.readFileSync)((0, import_node_path33.resolve)(o.file), "utf8");
29322
29510
  } catch (e) {
29323
29511
  return fail(`secrets org-catalog: cannot read --file ${o.file}: ${e.message}`);
29324
29512
  }
@@ -29423,7 +29611,7 @@ function registerSecretsCommands(program3) {
29423
29611
  {
29424
29612
  ...d,
29425
29613
  decryptRailsCredentials,
29426
- removeFile: (path2) => (0, import_node_fs35.unlinkSync)((0, import_node_path32.resolve)(o.appDir ?? process.cwd(), path2))
29614
+ removeFile: (path2) => (0, import_node_fs35.unlinkSync)((0, import_node_path33.resolve)(o.appDir ?? process.cwd(), path2))
29427
29615
  },
29428
29616
  {
29429
29617
  repo: o.repo,
@@ -29877,8 +30065,8 @@ async function repoWorkflowEntries(client, repo) {
29877
30065
  for (const wf of workflowsList) {
29878
30066
  if (typeof wf?.path !== "string" || !wf.path) continue;
29879
30067
  if (!wf.path.startsWith(".github/workflows/")) continue;
29880
- const basename6 = wf.path.split("/").pop() ?? wf.path;
29881
- const name = `${repo}/${basename6.replace(/\.ya?ml$/, "")}`;
30068
+ const basename8 = wf.path.split("/").pop() ?? wf.path;
30069
+ const name = `${repo}/${basename8.replace(/\.ya?ml$/, "")}`;
29882
30070
  if (wf.state !== "active") {
29883
30071
  disabled.push(name);
29884
30072
  continue;
@@ -30150,7 +30338,7 @@ function registerSchedulesCommands(program3) {
30150
30338
 
30151
30339
  // src/schedules-lift-command.ts
30152
30340
  var import_promises7 = require("node:fs/promises");
30153
- var import_node_path33 = require("node:path");
30341
+ var import_node_path34 = require("node:path");
30154
30342
  var DEFAULT_WORKFLOWS_DIR = ".github/workflows";
30155
30343
  var SCHEDULE_REPO_RE = /^[A-Za-z0-9_.-]+$/;
30156
30344
  var SchedulesLiftUsageError = class extends Error {
@@ -30177,7 +30365,7 @@ async function readWorkflowFiles(dir) {
30177
30365
  const files = [];
30178
30366
  for (const name of names.sort()) {
30179
30367
  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") });
30368
+ files.push({ path: `.github/workflows/${name}`, text: await (0, import_promises7.readFile)((0, import_node_path34.join)(dir, name), "utf8") });
30181
30369
  }
30182
30370
  return files;
30183
30371
  }
@@ -30327,7 +30515,7 @@ function registerEdgeCommands(program3) {
30327
30515
  // src/bootstrap-commands.ts
30328
30516
  var import_node_fs37 = require("node:fs");
30329
30517
  var import_node_os14 = require("node:os");
30330
- var import_node_path34 = require("node:path");
30518
+ var import_node_path35 = require("node:path");
30331
30519
 
30332
30520
  // src/bootstrap-drift.ts
30333
30521
  var import_node_crypto7 = require("node:crypto");
@@ -31369,7 +31557,7 @@ function registerBootstrapCommands(program3) {
31369
31557
  const readFile9 = (p) => (0, import_node_fs37.existsSync)(p) ? (0, import_node_fs37.readFileSync)(p, "utf8") : null;
31370
31558
  const enc = (p) => p.split("/").map(encodeURIComponent).join("/");
31371
31559
  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`);
31560
+ 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
31561
  (0, import_node_fs37.writeFileSync)(tmp, JSON.stringify(contentPutBody(target, content, ref, sha)), "utf8");
31374
31562
  try {
31375
31563
  await gh(contentPutInputArgs(repo, target, tmp));
@@ -31780,7 +31968,7 @@ LIVE apply to ${repo}:
31780
31968
  } catch {
31781
31969
  existingSha = void 0;
31782
31970
  }
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`);
31971
+ 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
31972
  (0, import_node_fs37.writeFileSync)(tmp, JSON.stringify(contentPutBody(seed.target, hubContent, branch, existingSha)), "utf8");
31785
31973
  try {
31786
31974
  await gh(contentPutInputArgs(rec.repo, seed.target, tmp));
@@ -31936,7 +32124,7 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
31936
32124
  } catch {
31937
32125
  existingSha = void 0;
31938
32126
  }
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`);
32127
+ 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
32128
  (0, import_node_fs37.writeFileSync)(tmp, JSON.stringify(contentPutBody(seed.target, preSeedContent, plan.branch, existingSha)), "utf8");
31941
32129
  try {
31942
32130
  await gh(contentPutInputArgs(repo, seed.target, tmp));
@@ -31965,11 +32153,11 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
31965
32153
 
31966
32154
  // src/stage-commands.ts
31967
32155
  var import_node_fs39 = require("node:fs");
31968
- var import_node_path36 = require("node:path");
32156
+ var import_node_path37 = require("node:path");
31969
32157
 
31970
32158
  // src/port-registry.ts
31971
32159
  var import_node_fs38 = require("node:fs");
31972
- var import_node_path35 = require("node:path");
32160
+ var import_node_path36 = require("node:path");
31973
32161
 
31974
32162
  // ../infra/port-geometry.mjs
31975
32163
  var PORT_BLOCK = 100;
@@ -32022,22 +32210,22 @@ function existingPortRange(repo, registry2) {
32022
32210
  return registry2[repo] ?? null;
32023
32211
  }
32024
32212
  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");
32213
+ const registryPath = (0, import_node_path36.join)(root, "infra", "port-ranges.json");
32214
+ const ddbScriptPath = (0, import_node_path36.join)(root, "infra", "port-ddb.mjs");
32027
32215
  if (!(0, import_node_fs38.existsSync)(registryPath) || !(0, import_node_fs38.existsSync)(ddbScriptPath)) return null;
32028
32216
  return { root, source, registryPath, ddbScriptPath };
32029
32217
  }
32030
32218
  function resolvePortRangeInfra(cwd, packageDir) {
32031
32219
  const direct = portRangeInfraAt(cwd, "cwd");
32032
32220
  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");
32221
+ for (let dir = cwd; ; dir = (0, import_node_path36.dirname)(dir)) {
32222
+ const sibling = portRangeInfraAt((0, import_node_path36.join)(dir, "MMI-Hub"), "sibling-hub");
32035
32223
  if (sibling) return sibling;
32036
- const parent = (0, import_node_path35.dirname)(dir);
32224
+ const parent = (0, import_node_path36.dirname)(dir);
32037
32225
  if (parent === dir) break;
32038
32226
  }
32039
32227
  if (packageDir) {
32040
- const pkgRoot = (0, import_node_path35.join)(packageDir, "..", "..");
32228
+ const pkgRoot = (0, import_node_path36.join)(packageDir, "..", "..");
32041
32229
  const pkgFrom = portRangeInfraAt(pkgRoot, "pkg-root");
32042
32230
  if (pkgFrom) return pkgFrom;
32043
32231
  }
@@ -32231,8 +32419,8 @@ function registerStageCommands(program3) {
32231
32419
  const portRange = portRangeMeta && typeof portRangeMeta.start === "number" && typeof portRangeMeta.end === "number" ? [portRangeMeta.start, portRangeMeta.end] : void 0;
32232
32420
  return decideStage({
32233
32421
  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"))
32422
+ hasCompose: (0, import_node_fs39.existsSync)((0, import_node_path37.join)(process.cwd(), "docker-compose.yml")),
32423
+ hasEnvExample: (0, import_node_fs39.existsSync)((0, import_node_path37.join)(process.cwd(), ".env.example"))
32236
32424
  });
32237
32425
  }
32238
32426
  async function fetchStageVaultEnvMerge() {
@@ -32726,7 +32914,7 @@ function registerBoardCommands(program3) {
32726
32914
  // src/merge-cleanup.ts
32727
32915
  var import_node_fs40 = require("node:fs");
32728
32916
  var import_promises9 = require("node:fs/promises");
32729
- var import_node_path38 = require("node:path");
32917
+ var import_node_path39 = require("node:path");
32730
32918
  var import_node_os15 = require("node:os");
32731
32919
  var import_node_child_process18 = require("node:child_process");
32732
32920
 
@@ -32814,7 +33002,7 @@ function boardAdvanceFailureMessage(result) {
32814
33002
 
32815
33003
  // src/deferred-registry-store.ts
32816
33004
  var import_promises8 = require("node:fs/promises");
32817
- var import_node_path37 = require("node:path");
33005
+ var import_node_path38 = require("node:path");
32818
33006
  var sleep2 = (ms) => new Promise((resolve6) => setTimeout(resolve6, ms));
32819
33007
  async function atomicWrite(target, contents) {
32820
33008
  const tmp = `${target}.tmp-${process.pid}-${Math.random().toString(36).slice(2)}`;
@@ -32865,12 +33053,12 @@ function makeDeferredWorktreeStore(registryPath, lockOpts = {}) {
32865
33053
  },
32866
33054
  // Standalone atomic write — THROWS on failure (no best-effort swallow, #2846).
32867
33055
  write: async (entries) => {
32868
- await (0, import_promises8.mkdir)((0, import_node_path37.dirname)(registryPath), { recursive: true });
33056
+ await (0, import_promises8.mkdir)((0, import_node_path38.dirname)(registryPath), { recursive: true });
32869
33057
  await atomicWrite(registryPath, serializeDeferredWorktrees(entries));
32870
33058
  },
32871
33059
  // Serialized read-modify-write under the repo-wide lock (#2846).
32872
33060
  update: async (mutate) => {
32873
- await (0, import_promises8.mkdir)((0, import_node_path37.dirname)(registryPath), { recursive: true });
33061
+ await (0, import_promises8.mkdir)((0, import_node_path38.dirname)(registryPath), { recursive: true });
32874
33062
  const deadline = Date.now() + opts.maxWaitMs;
32875
33063
  for (; ; ) {
32876
33064
  const guard = await acquireLock(lockPath, opts, deadline);
@@ -33034,6 +33222,23 @@ ${err.stderr ?? ""}`;
33034
33222
  return { step, status: `failed: ${msg}` };
33035
33223
  }
33036
33224
  }
33225
+ async function bestEffortCloseMissingWorktreeLeases(leaseDir = (0, import_node_path39.join)((0, import_node_os15.homedir)(), ".jerv", "leases"), exists = import_node_fs40.existsSync) {
33226
+ let names = [];
33227
+ try {
33228
+ names = (0, import_node_fs40.readdirSync)(leaseDir);
33229
+ } catch {
33230
+ return;
33231
+ }
33232
+ for (const name of names) {
33233
+ if (!name.endsWith(".json")) continue;
33234
+ try {
33235
+ const rec = JSON.parse((0, import_node_fs40.readFileSync)((0, import_node_path39.join)(leaseDir, name), "utf8"));
33236
+ if (rec.kind !== "worktree" || rec.state === "closed" || typeof rec.ref !== "string" || !rec.ref.trim()) continue;
33237
+ if (!exists(rec.ref)) await bestEffortLeaseClose(rec.ref);
33238
+ } catch {
33239
+ }
33240
+ }
33241
+ }
33037
33242
  async function applyGcPlan(plan, remote, opts = {}) {
33038
33243
  const result = { removedBranches: [], removedRemoteBranches: [], removedTrackingRefs: [], removedWorktreeDirs: [], refused: [], failed: [], pruned: false };
33039
33244
  const beforeWorktrees = parseWorktreePorcelain(
@@ -33041,7 +33246,7 @@ async function applyGcPlan(plan, remote, opts = {}) {
33041
33246
  );
33042
33247
  const repoRoot2 = (await execFileP2("git", ["rev-parse", "--show-toplevel"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim() || process.cwd();
33043
33248
  const worktreeGitRoot = await currentRepoWorktreeGitRoot(repoRoot2);
33044
- const primaryRepoRoot = worktreeGitRoot ? (0, import_node_path38.dirname)((0, import_node_path38.dirname)(worktreeGitRoot)) : repoRoot2;
33249
+ const primaryRepoRoot = worktreeGitRoot ? (0, import_node_path39.dirname)((0, import_node_path39.dirname)(worktreeGitRoot)) : repoRoot2;
33045
33250
  const gcActor = describeActor({ env: process.env, surface: detectSurface(process.env), cwd: process.cwd() });
33046
33251
  const owners = readWorktreeOwners(primaryRepoRoot);
33047
33252
  const removalNow = Date.now();
@@ -33050,7 +33255,9 @@ async function applyGcPlan(plan, remote, opts = {}) {
33050
33255
  const activeWorkspaceDeferred = [];
33051
33256
  const refusesRemoval = (path2, branch) => {
33052
33257
  if (!path2) return false;
33053
- const activeGuard = decideActiveWorkspaceGuard(path2, activeWorkspaceRoot);
33258
+ const activeGuard = decideActiveWorkspaceGuard(path2, activeWorkspaceRoot, process.platform, {
33259
+ cursorAgentHost: isCursorAgentHost()
33260
+ });
33054
33261
  if (activeGuard.action === "refuse") {
33055
33262
  result.refused.push(activeGuard.message);
33056
33263
  const owner2 = findWorktreeOwner(owners, path2);
@@ -33129,7 +33336,8 @@ async function applyGcPlan(plan, remote, opts = {}) {
33129
33336
  const removeDeps = worktreeRemoveDeps(async (args) => (await execFileP2("git", args, { timeout: GIT_TIMEOUT_MS })).stdout);
33130
33337
  const cleanupRoots = [
33131
33338
  opts.root ? resolveExplicitScanRoot(opts.root, primaryRepoRoot) : siblingMmiWorktreesRoot(primaryRepoRoot),
33132
- agentWorktreesRoot(primaryRepoRoot)
33339
+ agentWorktreesRoot(primaryRepoRoot),
33340
+ ...helperWorktreeRoots(primaryRepoRoot)
33133
33341
  ];
33134
33342
  for (const wt of worktreeDirsToRemove) {
33135
33343
  const owner = findWorktreeOwner(owners, wt.path);
@@ -33181,12 +33389,27 @@ async function applyGcPlan(plan, remote, opts = {}) {
33181
33389
  }
33182
33390
  }
33183
33391
  }
33392
+ for (const head of plan.reapOriginHeads ?? []) {
33393
+ try {
33394
+ await execFileP2("git", ["push", remote, "--delete", head.branch], { timeout: GIT_TIMEOUT_MS });
33395
+ result.removedRemoteBranches.push(head.branch);
33396
+ } catch (e) {
33397
+ const detail = `${e.message}
33398
+ ${e.stderr ?? ""}`;
33399
+ if (/not found|does not exist|unable to delete|remote ref does not exist/i.test(detail)) {
33400
+ result.removedRemoteBranches.push(head.branch);
33401
+ } else {
33402
+ result.failed.push(`${head.branch}: origin delete failed (${e.message.split("\n")[0]})`);
33403
+ }
33404
+ }
33405
+ }
33184
33406
  try {
33185
33407
  await execFileP2("git", ["worktree", "prune"], { timeout: GIT_TIMEOUT_MS });
33186
33408
  result.pruned = true;
33187
33409
  } catch (e) {
33188
33410
  result.failed.push(`worktree prune: ${e.message.split("\n")[0]}`);
33189
33411
  }
33412
+ await bestEffortCloseMissingWorktreeLeases();
33190
33413
  return result;
33191
33414
  }
33192
33415
  async function pollGhPrChecks(prNumber, repoArgs) {
@@ -33223,8 +33446,8 @@ async function composeOverrideBodyFile(prNumber, repoArgs, gh) {
33223
33446
  const commits = JSON.parse(raw).commits ?? [];
33224
33447
  const body = squashBodyWithOverride(commits.map((c) => ({ headline: c.messageHeadline ?? "", body: c.messageBody ?? "" })), process.cwd());
33225
33448
  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");
33449
+ const dir = (0, import_node_fs40.mkdtempSync)((0, import_node_path39.join)((0, import_node_os15.tmpdir)(), "mmi-squash-body-"));
33450
+ const path2 = (0, import_node_path39.join)(dir, "body.txt");
33228
33451
  (0, import_node_fs40.writeFileSync)(path2, `${body}
33229
33452
  `, "utf8");
33230
33453
  return { path: path2, cleanup: () => {
@@ -33349,15 +33572,16 @@ async function createDeferredWorktreeStore() {
33349
33572
  }
33350
33573
  var realWorktreeDirRemover = {
33351
33574
  probe: (p) => {
33575
+ const target = win32LongPath(p);
33352
33576
  let st;
33353
33577
  try {
33354
- st = (0, import_node_fs40.lstatSync)(p);
33578
+ st = (0, import_node_fs40.lstatSync)(target);
33355
33579
  } catch {
33356
33580
  return null;
33357
33581
  }
33358
33582
  if (st.isSymbolicLink()) return "link";
33359
33583
  try {
33360
- (0, import_node_fs40.readlinkSync)(p);
33584
+ (0, import_node_fs40.readlinkSync)(target);
33361
33585
  return "link";
33362
33586
  } catch {
33363
33587
  }
@@ -33365,7 +33589,7 @@ var realWorktreeDirRemover = {
33365
33589
  },
33366
33590
  readdir: (p) => {
33367
33591
  try {
33368
- return (0, import_node_fs40.readdirSync)(p);
33592
+ return (0, import_node_fs40.readdirSync)(win32LongPath(p));
33369
33593
  } catch {
33370
33594
  return [];
33371
33595
  }
@@ -33373,13 +33597,16 @@ var realWorktreeDirRemover = {
33373
33597
  // A directory reparse point (junction / dir-symlink) is detached with rmdir (unlinks the mount point,
33374
33598
  // leaving the target); a file symlink with unlink. rmdir first, fall back to unlink.
33375
33599
  detachLink: (p) => {
33600
+ const target = win32LongPath(p);
33376
33601
  try {
33377
- (0, import_node_fs40.rmdirSync)(p);
33602
+ (0, import_node_fs40.rmdirSync)(target);
33378
33603
  } catch {
33379
- (0, import_node_fs40.unlinkSync)(p);
33604
+ (0, import_node_fs40.unlinkSync)(target);
33380
33605
  }
33381
33606
  },
33382
- removeTree: (p) => (0, import_promises9.rm)(p, { recursive: true, force: true, maxRetries: 5, retryDelay: 200 })
33607
+ // #4904: Windows MAX_PATH aborts git worktree remove; the fallback must use \\?\ so the dir
33608
+ // (and its lease) do not survive as an unregistered leftover.
33609
+ removeTree: (p) => (0, import_promises9.rm)(win32LongPath(p), { recursive: true, force: true, maxRetries: 5, retryDelay: 200 })
33383
33610
  };
33384
33611
  async function resolvePrimaryCheckout(execGit) {
33385
33612
  try {
@@ -33850,12 +34077,13 @@ async function checkDocsIndexAtHead(opts, deps) {
33850
34077
  // src/worktree-lifecycle-commands.ts
33851
34078
  var import_node_fs42 = require("node:fs");
33852
34079
  var import_promises10 = require("node:fs/promises");
33853
- var import_node_path40 = require("node:path");
34080
+ var import_node_os16 = require("node:os");
34081
+ var import_node_path41 = require("node:path");
33854
34082
 
33855
34083
  // src/worktree-install-cache.ts
33856
34084
  var import_node_crypto8 = require("node:crypto");
33857
34085
  var import_node_fs41 = require("node:fs");
33858
- var import_node_path39 = require("node:path");
34086
+ var import_node_path40 = require("node:path");
33859
34087
  var CACHE_DIR = "worktree-install-cache";
33860
34088
  var MANIFEST = "manifest.json";
33861
34089
  var NODE_MODULES2 = "node_modules";
@@ -33885,7 +34113,7 @@ function hashLockfileBytes(contents) {
33885
34113
  }
33886
34114
  function resolveWorktreeInstallLockfile(packageDir, fs2 = realWorktreeInstallCacheFs) {
33887
34115
  for (const name of LOCKFILE_NAMES) {
33888
- const path2 = (0, import_node_path39.join)(packageDir, name);
34116
+ const path2 = (0, import_node_path40.join)(packageDir, name);
33889
34117
  if (!fs2.exists(path2)) continue;
33890
34118
  try {
33891
34119
  const hash = hashLockfileBytes(fs2.readFile(path2));
@@ -33900,8 +34128,8 @@ function worktreeInstallCacheEntry(primaryRoot, lockfileHash) {
33900
34128
  const root = repoRuntimeStatePath(primaryRoot, CACHE_DIR, lockfileHash);
33901
34129
  return {
33902
34130
  root,
33903
- manifestPath: (0, import_node_path39.join)(root, MANIFEST),
33904
- nodeModulesPath: (0, import_node_path39.join)(root, NODE_MODULES2)
34131
+ manifestPath: (0, import_node_path40.join)(root, MANIFEST),
34132
+ nodeModulesPath: (0, import_node_path40.join)(root, NODE_MODULES2)
33905
34133
  };
33906
34134
  }
33907
34135
  function readWorktreeInstallCacheManifest(manifestPath, fs2 = realWorktreeInstallCacheFs) {
@@ -33941,7 +34169,7 @@ function invalidateWorktreeInstallCacheEntry(entry, fs2 = realWorktreeInstallCac
33941
34169
  }
33942
34170
  }
33943
34171
  function removeMaterializedTree(packageDir, fs2) {
33944
- const dest = (0, import_node_path39.join)(packageDir, NODE_MODULES2);
34172
+ const dest = (0, import_node_path40.join)(packageDir, NODE_MODULES2);
33945
34173
  if (!fs2.exists(dest)) return;
33946
34174
  fs2.rm(dest);
33947
34175
  if (fs2.exists(dest)) {
@@ -33949,7 +34177,7 @@ function removeMaterializedTree(packageDir, fs2) {
33949
34177
  }
33950
34178
  }
33951
34179
  function materializeCachedNodeModules(entry, destPackageDir, fs2 = realWorktreeInstallCacheFs) {
33952
- const dest = (0, import_node_path39.join)(destPackageDir, NODE_MODULES2);
34180
+ const dest = (0, import_node_path40.join)(destPackageDir, NODE_MODULES2);
33953
34181
  try {
33954
34182
  if (fs2.exists(dest)) fs2.rm(dest);
33955
34183
  fs2.mkdirp(destPackageDir);
@@ -33964,7 +34192,7 @@ function materializeCachedNodeModules(entry, destPackageDir, fs2 = realWorktreeI
33964
34192
  }
33965
34193
  }
33966
34194
  async function storeWorktreeInstallCacheEntry(primaryRoot, lockfile3, command, sourcePackageDir, fs2 = realWorktreeInstallCacheFs, now = Date.now()) {
33967
- const source = (0, import_node_path39.join)(sourcePackageDir, NODE_MODULES2);
34195
+ const source = (0, import_node_path40.join)(sourcePackageDir, NODE_MODULES2);
33968
34196
  if (!isMaterializableNodeModulesDir(source, fs2)) return;
33969
34197
  const entry = worktreeInstallCacheEntry(primaryRoot, lockfile3.hash);
33970
34198
  const manifest = {
@@ -34219,12 +34447,36 @@ function classifyStaleLeaks(input) {
34219
34447
  remediation: "mmi-cli worktree gc --apply"
34220
34448
  });
34221
34449
  }
34450
+ for (const leftover of input.originLeftovers ?? []) {
34451
+ leaks.push({
34452
+ kind: "origin-leftover",
34453
+ ref: leftover.branch,
34454
+ detail: leftover.detail,
34455
+ 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)"
34456
+ });
34457
+ }
34458
+ for (const helper of input.helperWorktrees ?? []) {
34459
+ leaks.push({
34460
+ kind: "helper-worktree",
34461
+ ref: helper.path,
34462
+ detail: helper.detail,
34463
+ remediation: helper.reapable ? "mmi-cli worktree gc --apply" : "inspect / git -C <primary> worktree remove --force after the helper is abandoned"
34464
+ });
34465
+ }
34466
+ for (const ref of input.missingLeaseRefs ?? []) {
34467
+ leaks.push({
34468
+ kind: "missing-lease",
34469
+ ref,
34470
+ detail: `jerv worktree lease still active but path is gone`,
34471
+ remediation: "mmi-cli worktree gc --apply (closes the lease; JPT #5548 also reaps on sweep)"
34472
+ });
34473
+ }
34222
34474
  return leaks;
34223
34475
  }
34224
34476
  var defaultOrphanDirScanDeps = {
34225
34477
  listDirs: (root) => {
34226
34478
  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));
34479
+ return (0, import_node_fs42.readdirSync)(root, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => (0, import_node_path41.join)(root, e.name));
34228
34480
  } catch {
34229
34481
  return [];
34230
34482
  }
@@ -34239,8 +34491,12 @@ function scanOrphanDirs(worktreesRoot, worktreeGitRoot, deps = defaultOrphanDirS
34239
34491
  }
34240
34492
  return candidates;
34241
34493
  }
34242
- function formatStaleLeaks(leaks, prLookupFailures = []) {
34243
- const lines = leaks.length ? [`worktree list --stale: ${leaks.length} leak(s)`] : ["worktree list --stale: no leaks found"];
34494
+ function formatStaleLeaks(leaks, prLookupFailures = [], audit) {
34495
+ const blocked = Boolean(audit?.blocksGreen);
34496
+ 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"];
34497
+ if (audit) {
34498
+ for (const line of formatEstateAuditLines(audit)) lines.push(` ${line}`);
34499
+ }
34244
34500
  for (const leak of leaks) {
34245
34501
  lines.push(` [${leak.kind}] ${leak.ref} \u2014 ${leak.detail}`);
34246
34502
  lines.push(` fix: ${leak.remediation}`);
@@ -34390,13 +34646,13 @@ function registerWorktreeCommands(program3) {
34390
34646
  const detached = headBorn && !symbolicBranch;
34391
34647
  const branch = symbolicBranch || (detached ? "HEAD" : "");
34392
34648
  if (!wtPath || !branch) return fail("worktree land: not inside a git worktree");
34393
- const gitFile = (0, import_node_path40.join)(wtPath, ".git");
34649
+ const gitFile = (0, import_node_path41.join)(wtPath, ".git");
34394
34650
  const isLinked = (0, import_node_fs42.existsSync)(gitFile) && (0, import_node_fs42.statSync)(gitFile).isFile();
34395
34651
  if (apply && !isLinked) {
34396
34652
  return fail("worktree land: run from inside the linked worktree you want to land (this is the primary checkout)");
34397
34653
  }
34398
34654
  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;
34655
+ const primaryCheckout = commonDir ? (0, import_node_path41.dirname)(commonDir) : wtPath;
34400
34656
  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
34657
  const orphan = classifyOrphanedWorktree({
34402
34658
  branch,
@@ -34460,7 +34716,9 @@ function registerWorktreeCommands(program3) {
34460
34716
  const reportedMergeState = treeOnly ? "not-checked" : mergeVerdict.state;
34461
34717
  const landOwner = lookupWorktreeOwner(primaryCheckout, wtPath);
34462
34718
  const activeWorkspaceRoot = resolveActiveWorkspaceRoot();
34463
- const activeGuard = decideActiveWorkspaceGuard(wtPath, activeWorkspaceRoot);
34719
+ const activeGuard = decideActiveWorkspaceGuard(wtPath, activeWorkspaceRoot, process.platform, {
34720
+ cursorAgentHost: isCursorAgentHost()
34721
+ });
34464
34722
  if (activeGuard.action === "refuse") {
34465
34723
  const deferredStore = await createDeferredWorktreeStore();
34466
34724
  if (deferredStore) {
@@ -34536,6 +34794,9 @@ function registerWorktreeCommands(program3) {
34536
34794
  step: "remove worktree",
34537
34795
  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
34796
  });
34797
+ if (!removeOutcome.remainsOnDisk) {
34798
+ report.push(await bestEffortLeaseClose(wtPath));
34799
+ }
34539
34800
  if (!shouldContinueLandCleanup(removeOutcome.status)) {
34540
34801
  const result2 = {
34541
34802
  dryRun: false,
@@ -34620,8 +34881,17 @@ function registerWorktreeCommands(program3) {
34620
34881
  if (o.stale) {
34621
34882
  const leaks = classifyStaleLeaks(ctx);
34622
34883
  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));
34884
+ const complete = failures.length === 0 && !ctx.audit?.blocksGreen;
34885
+ if (o.json) {
34886
+ return console.log(JSON.stringify({
34887
+ stale: leaks,
34888
+ count: leaks.length,
34889
+ prLookupFailures: failures,
34890
+ complete,
34891
+ audit: ctx.audit
34892
+ }, null, 2));
34893
+ }
34894
+ return console.log(formatStaleLeaks(leaks, failures, ctx.audit));
34625
34895
  }
34626
34896
  if (o.json) return console.log(JSON.stringify({ worktrees: ctx.worktrees }, null, 2));
34627
34897
  if (!ctx.worktrees.length) return console.log("worktree list: no worktrees");
@@ -34645,10 +34915,18 @@ async function gatherWorktreeContext() {
34645
34915
  const branchOut = (await execFileP2("git", ["branch", "--format=%(refname:short)"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout;
34646
34916
  const localBranches = branchOut.split(/\r?\n/).map((l) => l.trim()).filter(Boolean);
34647
34917
  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);
34918
+ const remoteBranchOut = (await execFileP2("git", ["branch", "-r", "--format=%(refname:short)"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout;
34919
+ const remoteBranches = remoteBranchOut.split(/\r?\n/).map((l) => l.trim()).filter((b) => b.startsWith("origin/") && b !== "origin/HEAD");
34920
+ const remoteNames = remoteBranches.map((b) => b.replace(/^origin\//, ""));
34921
+ const prTargets = [.../* @__PURE__ */ new Set([
34922
+ ...localBranches.filter((b) => !PROTECTED_BRANCHES2.has(b)),
34923
+ ...remoteNames.filter((b) => !PROTECTED_BRANCHES2.has(b))
34924
+ ])];
34925
+ const { prs, failures: prLookupFailures } = await resolveBranchPrs(prTargets, STALE_PR_LOOKUP_LIMIT);
34649
34926
  const openPrBranches = /* @__PURE__ */ new Set();
34650
34927
  const closedBranches = /* @__PURE__ */ new Set();
34651
34928
  const closedUnmergedBranches = /* @__PURE__ */ new Set();
34929
+ const mergedPrBranches = /* @__PURE__ */ new Set();
34652
34930
  const byBranch = /* @__PURE__ */ new Map();
34653
34931
  for (const pr2 of prs) {
34654
34932
  const arr = byBranch.get(pr2.headRefName) ?? [];
@@ -34659,6 +34937,7 @@ async function gatherWorktreeContext() {
34659
34937
  if (states.some((s) => s === "OPEN")) openPrBranches.add(br);
34660
34938
  else if (states.some((s) => s === "MERGED" || s === "CLOSED")) {
34661
34939
  closedBranches.add(br);
34940
+ if (states.some((s) => s === "MERGED")) mergedPrBranches.add(br);
34662
34941
  if (!states.some((s) => s === "MERGED") && states.some((s) => s === "CLOSED")) {
34663
34942
  closedUnmergedBranches.add(br);
34664
34943
  }
@@ -34670,7 +34949,7 @@ async function gatherWorktreeContext() {
34670
34949
  if (s) stages.push({ path: wt.path, port: s.port });
34671
34950
  }
34672
34951
  const worktreeGitRoot = await currentRepoWorktreeGitRoot(repoRoot2);
34673
- const primaryRepoRoot = worktreeGitRoot ? (0, import_node_path40.dirname)((0, import_node_path40.dirname)(worktreeGitRoot)) : repoRoot2;
34952
+ const primaryRepoRoot = worktreeGitRoot ? (0, import_node_path41.dirname)((0, import_node_path41.dirname)(worktreeGitRoot)) : repoRoot2;
34674
34953
  const wtRoot = siblingMmiWorktreesRoot(primaryRepoRoot);
34675
34954
  let orphanDirs = [];
34676
34955
  if ((0, import_node_fs42.existsSync)(wtRoot)) {
@@ -34679,6 +34958,44 @@ async function gatherWorktreeContext() {
34679
34958
  listDirs: (root) => worktreeScanDirs(root, primaryRepoRoot, defaultOrphanDirScanDeps.listDirs, isRepoCheckoutDir)
34680
34959
  });
34681
34960
  }
34961
+ const repoContainer = worktreesRootOf(primaryRepoRoot);
34962
+ if ((0, import_node_fs42.existsSync)(repoContainer)) {
34963
+ for (const dir of defaultOrphanDirScanDeps.listDirs(repoContainer)) {
34964
+ if (orphanDirs.some((o) => o.path === dir)) continue;
34965
+ const inspected = inspectSiblingWorktreeDir(dir, worktreeGitRoot);
34966
+ const classified = classifySiblingWorktreeDir(inspected);
34967
+ if (classified.cleanup) {
34968
+ orphanDirs.push({ path: dir, reason: classified.cleanup.reason });
34969
+ continue;
34970
+ }
34971
+ if (inspected.gitType === "missing" && pathProvesRepoContainerOwnership(dir, repoContainer)) {
34972
+ orphanDirs.push({ path: dir, reason: "orphaned-folder" });
34973
+ }
34974
+ }
34975
+ }
34976
+ const originLeftovers = classifyOriginLeftovers({
34977
+ remoteBranches,
34978
+ localBranches,
34979
+ protectedBranches: PROTECTED_BRANCHES2,
34980
+ openPrBranches,
34981
+ mergedPrBranches,
34982
+ closedUnmergedBranches
34983
+ });
34984
+ const helperWorktrees = scanHelperWorktrees(primaryRepoRoot, worktreeGitRoot);
34985
+ const leaseRefs = readJervWorktreeLeaseRefs();
34986
+ const missingLeaseRefs = leaseRefs.filter((ref) => !(0, import_node_fs42.existsSync)(ref));
34987
+ const remoteUrls = await gitRemoteUrls();
34988
+ const otherCheckouts = discoverOtherPrimaries(primaryRepoRoot).map((path2) => ({
34989
+ path: path2,
34990
+ remoteUrls: gitConfigRemoteUrls(path2)
34991
+ }));
34992
+ const audit = classifyEstateAudit({
34993
+ auditedClone: primaryRepoRoot,
34994
+ remoteUrls,
34995
+ otherCheckouts,
34996
+ leaseRefs,
34997
+ thisWorktreesRoot: repoContainer
34998
+ });
34682
34999
  return {
34683
35000
  worktrees,
34684
35001
  localBranches,
@@ -34688,9 +35005,96 @@ async function gatherWorktreeContext() {
34688
35005
  closedUnmergedBranches,
34689
35006
  stages,
34690
35007
  orphanDirs,
34691
- prLookupFailures
35008
+ prLookupFailures,
35009
+ originLeftovers,
35010
+ helperWorktrees,
35011
+ missingLeaseRefs,
35012
+ audit
34692
35013
  };
34693
35014
  }
35015
+ function gitConfigRemoteUrls(checkout) {
35016
+ const gitPath = (0, import_node_path41.join)(checkout, ".git");
35017
+ let configPath = (0, import_node_path41.join)(checkout, ".git", "config");
35018
+ try {
35019
+ const st = (0, import_node_fs42.statSync)(gitPath);
35020
+ if (st.isFile()) return [];
35021
+ } catch {
35022
+ return [];
35023
+ }
35024
+ try {
35025
+ const text = (0, import_node_fs42.readFileSync)(configPath, "utf8");
35026
+ return [...text.matchAll(/^\s*url\s*=\s*(.+)$/gm)].map((m) => m[1].trim());
35027
+ } catch {
35028
+ return [];
35029
+ }
35030
+ }
35031
+ async function gitRemoteUrls() {
35032
+ const out = (await execFileP2("git", ["remote", "-v"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout;
35033
+ return [...new Set(
35034
+ out.split(/\r?\n/).map((line) => line.trim().split(/\s+/)[1]).filter((url) => Boolean(url))
35035
+ )];
35036
+ }
35037
+ function discoverOtherPrimaries(primaryRepoRoot) {
35038
+ const found = /* @__PURE__ */ new Set();
35039
+ const parent = (0, import_node_path41.dirname)(primaryRepoRoot);
35040
+ try {
35041
+ for (const name of (0, import_node_fs42.readdirSync)(parent)) {
35042
+ const path2 = (0, import_node_path41.join)(parent, name);
35043
+ if (path2 === primaryRepoRoot) continue;
35044
+ if ((0, import_node_fs42.existsSync)((0, import_node_path41.join)(path2, ".git"))) found.add(path2);
35045
+ }
35046
+ } catch {
35047
+ }
35048
+ const mirror = (0, import_node_path41.join)((0, import_node_os16.homedir)(), "Projects", (0, import_node_path41.basename)(primaryRepoRoot));
35049
+ if (mirror !== primaryRepoRoot && (0, import_node_fs42.existsSync)((0, import_node_path41.join)(mirror, ".git"))) found.add(mirror);
35050
+ return [...found];
35051
+ }
35052
+ function readJervWorktreeLeaseRefs(leaseDir = (0, import_node_path41.join)((0, import_node_os16.homedir)(), ".jerv", "leases")) {
35053
+ try {
35054
+ const refs = [];
35055
+ for (const name of (0, import_node_fs42.readdirSync)(leaseDir)) {
35056
+ if (!name.endsWith(".json")) continue;
35057
+ try {
35058
+ const rec = JSON.parse((0, import_node_fs42.readFileSync)((0, import_node_path41.join)(leaseDir, name), "utf8"));
35059
+ if (rec.kind === "worktree" && rec.state !== "closed" && typeof rec.ref === "string" && rec.ref.trim()) {
35060
+ refs.push(rec.ref);
35061
+ }
35062
+ } catch {
35063
+ }
35064
+ }
35065
+ return refs;
35066
+ } catch {
35067
+ return [];
35068
+ }
35069
+ }
35070
+ function scanHelperWorktrees(thisPrimary, thisWorktreeGitRoot) {
35071
+ const primaries = [thisPrimary, ...discoverOtherPrimaries(thisPrimary)];
35072
+ const out = [];
35073
+ for (const primary of primaries) {
35074
+ const gitRoot = primary === thisPrimary ? thisWorktreeGitRoot : (0, import_node_path41.join)(primary, ".git", "worktrees");
35075
+ for (const root of helperWorktreeRoots(primary)) {
35076
+ if (!(0, import_node_fs42.existsSync)(root)) continue;
35077
+ for (const dir of defaultOrphanDirScanDeps.listDirs(root)) {
35078
+ const inspected = inspectSiblingWorktreeDir(dir, gitRoot);
35079
+ const classified = classifySiblingWorktreeDir(inspected);
35080
+ if (classified.cleanup) {
35081
+ out.push({
35082
+ path: dir,
35083
+ detail: `${classified.cleanup.reason} helper worktree under ${root}`,
35084
+ reapable: true
35085
+ });
35086
+ } else {
35087
+ out.push({
35088
+ path: dir,
35089
+ detail: `helper worktree outside ../mmi-worktrees (${classified.skip?.reason ?? inspected.gitType}) at ${dir}`,
35090
+ reapable: false
35091
+ });
35092
+ }
35093
+ }
35094
+ }
35095
+ }
35096
+ return out;
35097
+ }
34694
35098
  async function bestEffortGit(args, cwd, step, timeoutMs = GIT_TIMEOUT_MS) {
34695
35099
  try {
34696
35100
  const fullArgs = cwd ? ["-C", cwd, ...args] : args;
@@ -35408,7 +35812,7 @@ ${lines}`, {
35408
35812
 
35409
35813
  // src/train-commands.ts
35410
35814
  var import_node_fs44 = require("node:fs");
35411
- var import_node_path41 = require("node:path");
35815
+ var import_node_path42 = require("node:path");
35412
35816
  var RELEASE_BUMP_INTENTS = ["major", "minor", "patch"];
35413
35817
  function resolveReleaseBumpIntent(raw) {
35414
35818
  const intent = typeof raw === "string" ? raw.trim() : "";
@@ -35419,7 +35823,7 @@ function resolveReleaseBumpIntent(raw) {
35419
35823
  }
35420
35824
  function readRepoVersion() {
35421
35825
  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;
35826
+ return JSON.parse((0, import_node_fs44.readFileSync)((0, import_node_path42.join)(process.cwd(), ".claude-plugin", "plugin.json"), "utf8")).version || void 0;
35423
35827
  } catch {
35424
35828
  return void 0;
35425
35829
  }
@@ -35577,8 +35981,8 @@ function registerDeployCommands(program3) {
35577
35981
 
35578
35982
  // src/discovery-commands.ts
35579
35983
  var import_node_fs45 = require("node:fs");
35580
- var import_node_os16 = require("node:os");
35581
- var import_node_path42 = require("node:path");
35984
+ var import_node_os17 = require("node:os");
35985
+ var import_node_path43 = require("node:path");
35582
35986
  var GC_GH_TIMEOUT_MS3 = 2e4;
35583
35987
  async function collectStatus() {
35584
35988
  const repo = await resolveRepo();
@@ -35766,10 +36170,10 @@ async function collectOnboardStatus(opts = {}) {
35766
36170
  else if (top) nextCommand = `mmi-cli oracle board claim ${top.number} # ${top.title}`;
35767
36171
  else nextCommand = "mmi-cli oracle board read \u2014 no claimable items found";
35768
36172
  }
35769
- const home = (0, import_node_os16.homedir)();
36173
+ const home = (0, import_node_os17.homedir)();
35770
36174
  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)
36175
+ readKnown: () => readFileSyncSafe((0, import_node_path43.join)(home, ...KNOWN_MARKETPLACES_RELATIVE), import_node_fs45.readFileSync),
36176
+ readSettings: () => readFileSyncSafe((0, import_node_path43.join)(home, ".claude", "settings.json"), import_node_fs45.readFileSync)
35773
36177
  });
35774
36178
  return { track, board, registry: registry2, secrets, plugin, estateCli, doors: opts.doors ?? [], nextCommand };
35775
36179
  }
@@ -36905,18 +37309,18 @@ function registerOrgHealthQuery(program3, deps = defaultOrgHealthQueryDeps()) {
36905
37309
 
36906
37310
  // src/plugin-release-catchup.ts
36907
37311
  var import_node_fs46 = require("node:fs");
36908
- var import_node_path43 = require("node:path");
36909
- var import_node_os17 = require("node:os");
37312
+ var import_node_path44 = require("node:path");
37313
+ var import_node_os18 = require("node:os");
36910
37314
  var RELEASE_CATCHUP_TTL_MS = 24 * 60 * 60 * 1e3;
36911
37315
  var RELEASE_CATCHUP_DISABLE_ENV = "MMI_NO_RELEASE_CATCHUP";
36912
37316
  function releaseCatchupStatePath(env = process.env) {
36913
37317
  if (env.MMI_RELEASE_CATCHUP_STATE) return env.MMI_RELEASE_CATCHUP_STATE;
36914
37318
  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");
37319
+ const base2 = env.LOCALAPPDATA || (0, import_node_path44.join)((0, import_node_os18.homedir)(), "AppData", "Local");
37320
+ return (0, import_node_path44.join)(base2, "MMI Future", "mmi-cli", "release-catchup.json");
36917
37321
  }
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");
37322
+ const base = env.XDG_STATE_HOME || (0, import_node_path44.join)((0, import_node_os18.homedir)(), ".local", "state");
37323
+ return (0, import_node_path44.join)(base, "mmi-cli", "release-catchup.json");
36920
37324
  }
36921
37325
  function releaseCatchupDue(state, now, force = false) {
36922
37326
  if (force) return true;
@@ -36934,15 +37338,15 @@ function newestCachedPluginVersion(home) {
36934
37338
  }
36935
37339
  function marketplaceClonePath(home) {
36936
37340
  try {
36937
- const parsed = JSON.parse((0, import_node_fs46.readFileSync)((0, import_node_path43.join)(home, ".claude", "plugins", "known_marketplaces.json"), "utf8"));
37341
+ const parsed = JSON.parse((0, import_node_fs46.readFileSync)((0, import_node_path44.join)(home, ".claude", "plugins", "known_marketplaces.json"), "utf8"));
36938
37342
  if (parsed.mutmutco?.installLocation) return parsed.mutmutco.installLocation;
36939
37343
  } catch {
36940
37344
  }
36941
- return (0, import_node_path43.join)(home, ".claude", "plugins", "marketplaces", "mutmutco");
37345
+ return (0, import_node_path44.join)(home, ".claude", "plugins", "marketplaces", "mutmutco");
36942
37346
  }
36943
37347
  function readCatalogVersion(home) {
36944
37348
  try {
36945
- const parsed = JSON.parse((0, import_node_fs46.readFileSync)((0, import_node_path43.join)(marketplaceClonePath(home), ".claude-plugin", "marketplace.json"), "utf8"));
37349
+ const parsed = JSON.parse((0, import_node_fs46.readFileSync)((0, import_node_path44.join)(marketplaceClonePath(home), ".claude-plugin", "marketplace.json"), "utf8"));
36946
37350
  return parsed.plugins?.find((p) => p.name === "mmi")?.version;
36947
37351
  } catch {
36948
37352
  return void 0;
@@ -36950,7 +37354,7 @@ function readCatalogVersion(home) {
36950
37354
  }
36951
37355
  function readMmiInstallRecord(home) {
36952
37356
  try {
36953
- const parsed = JSON.parse((0, import_node_fs46.readFileSync)((0, import_node_path43.join)(home, ".claude", "plugins", "installed_plugins.json"), "utf8"));
37357
+ const parsed = JSON.parse((0, import_node_fs46.readFileSync)((0, import_node_path44.join)(home, ".claude", "plugins", "installed_plugins.json"), "utf8"));
36954
37358
  const record = parsed.plugins?.["mmi@mutmutco"]?.[0];
36955
37359
  return record?.version ? { version: record.version, gitCommitSha: record.gitCommitSha } : void 0;
36956
37360
  } catch {
@@ -37012,7 +37416,7 @@ async function runReleaseCatchup(home, env, deps, opts = {}) {
37012
37416
  return { ok: false, detail: `${cliUpdateDetail}; plugin install record could not be cleared (still ${prior.version})` };
37013
37417
  }
37014
37418
  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");
37419
+ const payload = (0, import_node_path44.join)(pluginCacheRoot(home), latest, ".pi-plugin");
37016
37420
  if (!installed || !(0, import_node_fs46.existsSync)(payload)) {
37017
37421
  const why = installed ? `install of ${latest} did not produce a verifiable .pi-plugin payload` : `install of ${latest} failed`;
37018
37422
  if (!prior) return { ok: false, detail: `${cliUpdateDetail}; ${why}; no prior record to restore` };
@@ -38048,10 +38452,10 @@ function checkRepoWorktrees(probe) {
38048
38452
  ok: !(probe.isOrgRepo && probe.hasRepoLocalWorktrees),
38049
38453
  id: "repo-worktrees",
38050
38454
  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/`",
38455
+ 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
38456
  verbose: [
38053
38457
  `org repo: ${probe.isOrgRepo ? "yes" : "no"}`,
38054
- `repo-local .worktrees/: ${probe.hasRepoLocalWorktrees ? "present" : "absent"}`
38458
+ `repo-local .worktrees/ or .claude/worktrees/: ${probe.hasRepoLocalWorktrees ? "present" : "absent"}`
38055
38459
  ]
38056
38460
  };
38057
38461
  }
@@ -39238,17 +39642,17 @@ function parseOriginRepo(remoteUrl) {
39238
39642
  }
39239
39643
  function ghHostsConfigPath(env, platform2) {
39240
39644
  const sep3 = platform2 === "win32" ? "\\" : "/";
39241
- const join40 = (...parts) => parts.join(sep3);
39645
+ const join41 = (...parts) => parts.join(sep3);
39242
39646
  const explicit = env.GH_CONFIG_DIR?.trim();
39243
- if (explicit) return join40(explicit, "hosts.yml");
39647
+ if (explicit) return join41(explicit, "hosts.yml");
39244
39648
  if (platform2 === "win32") {
39245
39649
  const appData = (env.AppData ?? env.APPDATA)?.trim();
39246
- return appData ? join40(appData, "GitHub CLI", "hosts.yml") : void 0;
39650
+ return appData ? join41(appData, "GitHub CLI", "hosts.yml") : void 0;
39247
39651
  }
39248
39652
  const xdg = env.XDG_CONFIG_HOME?.trim();
39249
- if (xdg) return join40(xdg, "gh", "hosts.yml");
39653
+ if (xdg) return join41(xdg, "gh", "hosts.yml");
39250
39654
  const home = env.HOME?.trim();
39251
- return home ? join40(home, ".config", "gh", "hosts.yml") : void 0;
39655
+ return home ? join41(home, ".config", "gh", "hosts.yml") : void 0;
39252
39656
  }
39253
39657
  function parseGhHostsAccounts(yaml, host = "github.com") {
39254
39658
  let hostIndent = null;
@@ -39299,8 +39703,8 @@ function ghAccountCaveat(announcedLogin, accounts) {
39299
39703
 
39300
39704
  // src/doctor-io.ts
39301
39705
  var import_node_fs47 = require("node:fs");
39302
- var import_node_os18 = require("node:os");
39303
- var import_node_path44 = require("node:path");
39706
+ var import_node_os19 = require("node:os");
39707
+ var import_node_path45 = require("node:path");
39304
39708
  var import_node_child_process19 = require("node:child_process");
39305
39709
  var import_node_util8 = require("node:util");
39306
39710
  var execFileP6 = (0, import_node_util8.promisify)(import_node_child_process19.execFile);
@@ -39308,7 +39712,7 @@ var MMI_PLUGIN_ID2 = "mmi@mutmutco";
39308
39712
  function installedClaudePluginVersion() {
39309
39713
  try {
39310
39714
  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")
39715
+ (0, import_node_fs47.readFileSync)((0, import_node_path45.join)((0, import_node_os19.homedir)(), ".claude", "plugins", "installed_plugins.json"), "utf8")
39312
39716
  );
39313
39717
  const versions = (file.plugins?.[MMI_PLUGIN_ID2] ?? []).map((r) => r.version).filter((v) => Boolean(v));
39314
39718
  if (versions.length === 0) return void 0;
@@ -39329,22 +39733,22 @@ function installedSurfacePluginVersion(surface) {
39329
39733
  const token = surfaceToken(surface);
39330
39734
  if (token === "kilo") {
39331
39735
  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();
39736
+ const stamp = (0, import_node_fs47.readFileSync)((0, import_node_path45.join)((0, import_node_os19.homedir)(), ".kilo", ".mmi-kilo-version"), "utf8").trim();
39333
39737
  return stamp || void 0;
39334
39738
  } catch {
39335
39739
  return void 0;
39336
39740
  }
39337
39741
  }
39338
39742
  if (token === "cursor") {
39339
- return manifestVersion((0, import_node_path44.join)(cursorLocalPluginRoot(), ".cursor-plugin", "plugin.json"));
39743
+ return manifestVersion((0, import_node_path45.join)(cursorLocalPluginRoot(), ".cursor-plugin", "plugin.json"));
39340
39744
  }
39341
39745
  if (token === "jervcode") {
39342
39746
  const entry = mmiPiWrapperEntry();
39343
39747
  if (!entry) return void 0;
39344
- return manifestVersion((0, import_node_path44.join)(decodeURIComponent(entry.replace(/^file:\/\/\/?/, "")), "package.json"));
39748
+ return manifestVersion((0, import_node_path45.join)(decodeURIComponent(entry.replace(/^file:\/\/\/?/, "")), "package.json"));
39345
39749
  }
39346
39750
  if (token === "kimi") {
39347
- return manifestVersion((0, import_node_path44.join)(surfaceConfigRoot(surface), "plugins", "managed", "mmi", ".kimi-plugin", "plugin.json"));
39751
+ return manifestVersion((0, import_node_path45.join)(surfaceConfigRoot(surface), "plugins", "managed", "mmi", ".kimi-plugin", "plugin.json"));
39348
39752
  }
39349
39753
  if (token === "claude") return installedClaudePluginVersion();
39350
39754
  if (token !== "codex") return void 0;
@@ -39382,7 +39786,7 @@ function worktreeRootSync() {
39382
39786
  }
39383
39787
  var gitignorePath = () => {
39384
39788
  const root = worktreeRootSync();
39385
- return root === null ? null : (0, import_node_path44.join)(root, ".gitignore");
39789
+ return root === null ? null : (0, import_node_path45.join)(root, ".gitignore");
39386
39790
  };
39387
39791
  function readGitignore() {
39388
39792
  const path2 = gitignorePath();
@@ -39416,7 +39820,7 @@ async function repoRoot() {
39416
39820
  }
39417
39821
  function hasRepoLocalWorktrees() {
39418
39822
  const root = worktreeRootSync();
39419
- return root !== null && (0, import_node_fs47.existsSync)((0, import_node_path44.join)(root, ".worktrees"));
39823
+ 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
39824
  }
39421
39825
 
39422
39826
  // src/cross-repo-filing-issue.ts
@@ -39512,7 +39916,7 @@ function binaryOnPath(bin) {
39512
39916
  for (const dir of pathEnvEntries(process.env.PATH ?? "")) {
39513
39917
  for (const ext of exts) {
39514
39918
  try {
39515
- if ((0, import_node_fs48.existsSync)((0, import_node_path45.join)(dir, `${bin}${ext}`))) return true;
39919
+ if ((0, import_node_fs48.existsSync)((0, import_node_path46.join)(dir, `${bin}${ext}`))) return true;
39516
39920
  } catch {
39517
39921
  }
39518
39922
  }
@@ -39543,12 +39947,12 @@ function ghMultiAccountCaveat(announcedLogin) {
39543
39947
  var ENV_HEAL_LOCK_STALE_MS = 10 * 6e4;
39544
39948
  var ENV_HEAL_LOCK_MAX_WAIT_MS = 2 * 6e4;
39545
39949
  function envHealLockPath(home) {
39546
- return (0, import_node_path45.join)(home, ".claude", "plugins", ".mmi-env-heal.lock");
39950
+ return (0, import_node_path46.join)(home, ".claude", "plugins", ".mmi-env-heal.lock");
39547
39951
  }
39548
39952
  async function withEnvHealLock(what, run) {
39549
39953
  try {
39550
39954
  return await withFileLock(
39551
- envHealLockPath((0, import_node_os19.homedir)()),
39955
+ envHealLockPath((0, import_node_os20.homedir)()),
39552
39956
  { staleMs: ENV_HEAL_LOCK_STALE_MS, maxWaitMs: ENV_HEAL_LOCK_MAX_WAIT_MS, label: "mmi env-heal lock" },
39553
39957
  run
39554
39958
  );
@@ -39645,7 +40049,7 @@ function mmiDoctorDeps(opts = {}) {
39645
40049
  const configRoot = surfaceConfigRoot(surface);
39646
40050
  const running = surface === "codex" ? installedActivePluginVersion(surface) : runningPluginVersion(process.env, resolveClientVersion());
39647
40051
  const plan = buildPluginCachePlan(
39648
- (0, import_node_os19.homedir)(),
40052
+ (0, import_node_os20.homedir)(),
39649
40053
  running,
39650
40054
  pluginCacheFsDeps(configRoot, () => 0),
39651
40055
  { configRoot, includeStaging: surface !== "codex" }
@@ -39669,7 +40073,7 @@ function mmiDoctorDeps(opts = {}) {
39669
40073
  const running = surface === "codex" ? installedActivePluginVersion(surface) : runningPluginVersion(process.env, resolveClientVersion());
39670
40074
  const installed = installedActivePluginVersion(surface);
39671
40075
  const plan = buildPluginCachePlan(
39672
- (0, import_node_os19.homedir)(),
40076
+ (0, import_node_os20.homedir)(),
39673
40077
  running,
39674
40078
  pluginCacheFsDeps(configRoot, () => 0),
39675
40079
  { configRoot, includeStaging: surface !== "codex", installedVersion: installed }
@@ -39704,12 +40108,12 @@ function mmiDoctorDeps(opts = {}) {
39704
40108
  piPluginState: () => {
39705
40109
  const env = { ...process.env };
39706
40110
  delete env.CLAUDE_PLUGIN_ROOT;
39707
- return readPiPluginState((0, import_node_os19.homedir)(), env);
40111
+ return readPiPluginState((0, import_node_os20.homedir)(), env);
39708
40112
  },
39709
40113
  healPiPlugin: () => {
39710
40114
  const env = { ...process.env };
39711
40115
  delete env.CLAUDE_PLUGIN_ROOT;
39712
- return healPiPluginRegistration((0, import_node_os19.homedir)(), env);
40116
+ return healPiPluginRegistration((0, import_node_os20.homedir)(), env);
39713
40117
  },
39714
40118
  // #4743: the global `claude` binary left as a ~500-byte placeholder by a self-update that died
39715
40119
  // EBUSY mid-install. A local read (package.json + the first bytes of two files) — no npm spawn:
@@ -39748,7 +40152,7 @@ function mmiDoctorDeps(opts = {}) {
39748
40152
  disableAutoUpdate: () => {
39749
40153
  if (detectSurface(process.env) === "codex") return void 0;
39750
40154
  return disableOrgMarketplaceBackgroundUpdates(
39751
- (0, import_node_path45.join)((0, import_node_os19.homedir)(), ...KNOWN_MARKETPLACES_RELATIVE),
40155
+ (0, import_node_path46.join)((0, import_node_os20.homedir)(), ...KNOWN_MARKETPLACES_RELATIVE),
39752
40156
  [MMI_MARKETPLACE_NAME]
39753
40157
  );
39754
40158
  }
@@ -39762,7 +40166,7 @@ function mmiDoctorDeps(opts = {}) {
39762
40166
  // adopted the generated routing index (MMG-Unlive: `docs/Archive/**` only, no index, no gate.yml) would
39763
40167
  // get a permanent — demanding an artifact it never asked for.
39764
40168
  docsIndexState: (root) => {
39765
- if (!(0, import_node_fs48.existsSync)((0, import_node_path45.join)(root, DOCS_INDEX_PATH))) return void 0;
40169
+ if (!(0, import_node_fs48.existsSync)((0, import_node_path46.join)(root, DOCS_INDEX_PATH))) return void 0;
39766
40170
  const real = createDocsIndexDeps(root);
39767
40171
  let docs2;
39768
40172
  const listDocs = () => docs2 ??= real.listDocs();
@@ -39771,7 +40175,7 @@ function mmiDoctorDeps(opts = {}) {
39771
40175
  },
39772
40176
  // #4168: working-tree heal — write if drifted, then re-check. Commit remains the operator's step.
39773
40177
  healDocsIndex: (root) => {
39774
- if (!(0, import_node_fs48.existsSync)((0, import_node_path45.join)(root, DOCS_INDEX_PATH))) return { drift: false, docCount: 0 };
40178
+ if (!(0, import_node_fs48.existsSync)((0, import_node_path46.join)(root, DOCS_INDEX_PATH))) return { drift: false, docCount: 0 };
39775
40179
  const real = createDocsIndexDeps(root);
39776
40180
  let docs2;
39777
40181
  const listDocs = () => docs2 ??= real.listDocs();
@@ -40137,7 +40541,7 @@ program2.hook("preAction", async (_thisCommand, actionCommand) => {
40137
40541
  });
40138
40542
  var rules = program2.command("rules").description("org-managed .gitignore delivery");
40139
40543
  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");
40544
+ const path2 = (0, import_node_path46.join)(process.cwd(), ".gitignore");
40141
40545
  const current = (0, import_node_fs48.existsSync)(path2) ? (0, import_node_fs48.readFileSync)(path2, "utf8") : null;
40142
40546
  const plan = planManagedGitignore(current);
40143
40547
  const drift = [...plan.added.map((l) => `+${l}`), ...plan.removed.map((l) => `-${l}`)].join(", ") || "block normalize";
@@ -40291,7 +40695,7 @@ gcCmd.command("sweep-deferred").description("retry IDE-locked deferred worktree
40291
40695
  process.exit(process.exitCode ?? 0);
40292
40696
  });
40293
40697
  });
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) => {
40698
+ 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
40699
  if (o.apply && o.dryRun) return fail("worktree gc: choose either --dry-run or --apply");
40296
40700
  if (o.scratch) {
40297
40701
  try {
@@ -40308,7 +40712,7 @@ gcCmd.option("--dry-run", "show what would be deleted (default)").option("--appl
40308
40712
  if (!Number.isFinite(limit) || limit < 1) return fail("worktree gc: --limit must be a positive integer");
40309
40713
  let root;
40310
40714
  if (o.root !== void 0) {
40311
- root = (0, import_node_path45.resolve)(o.root);
40715
+ root = (0, import_node_path46.resolve)(o.root);
40312
40716
  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
40717
  const gcRepoRoot = (await execFileP2("git", ["rev-parse", "--show-toplevel"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim() || process.cwd();
40314
40718
  if (isPathUnderDirectory2(gcRepoRoot, root)) {
@@ -40316,10 +40720,11 @@ gcCmd.option("--dry-run", "show what would be deleted (default)").option("--appl
40316
40720
  }
40317
40721
  }
40318
40722
  try {
40319
- const plan = await gcPlan(o.remote, limit, { root });
40723
+ const plan = await gcPlan(o.remote, limit, { root, trainOnly: o.trainOnly });
40724
+ const auditedClone = (await execFileP2("git", ["rev-parse", "--show-toplevel"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim() || process.cwd();
40320
40725
  if (root && !o.json) console.log(`worktree gc: scanning the explicitly named root ${root} for worktrees proven to belong to this repo
40321
40726
  `);
40322
- if (o.apply && !o.json) console.log(formatGcPlan(plan, true));
40727
+ if (o.apply && !o.json) console.log(formatGcPlan(plan, true, auditedClone));
40323
40728
  let applyResult;
40324
40729
  if (o.apply) {
40325
40730
  const deferredStore = await createDeferredWorktreeStore();
@@ -40338,7 +40743,7 @@ gcCmd.option("--dry-run", "show what would be deleted (default)").option("--appl
40338
40743
  if (o.json) {
40339
40744
  console.log(JSON.stringify({ dryRun: !o.apply, remote: o.remote, ...root ? { root } : {}, plan, applyResult }, null, 2));
40340
40745
  } else if (!o.apply) {
40341
- console.log(formatGcPlan(plan, false));
40746
+ console.log(formatGcPlan(plan, false, auditedClone));
40342
40747
  } else {
40343
40748
  if (applyResult) console.log(`
40344
40749
  ${renderGcApplyResult(applyResult, plan.skipped)}`);
@@ -40402,7 +40807,8 @@ async function currentWorktreeRemovalContext(command, force) {
40402
40807
  actor: describeActor({ env: process.env, surface: detectSurface(process.env), cwd }),
40403
40808
  command,
40404
40809
  ...force ? { force: true } : {},
40405
- ...activeWorkspaceRoot ? { activeWorkspaceRoot } : {}
40810
+ ...activeWorkspaceRoot ? { activeWorkspaceRoot } : {},
40811
+ cursorAgentHost: isCursorAgentHost()
40406
40812
  };
40407
40813
  }
40408
40814
  async function unprovenWorktreeReason(wtPath, repoRoot2) {
@@ -40450,7 +40856,7 @@ function acquireWorktreeSetupLock(worktreeRoot) {
40450
40856
  };
40451
40857
  };
40452
40858
  try {
40453
- (0, import_node_fs48.mkdirSync)((0, import_node_path45.dirname)(lockPath), { recursive: true });
40859
+ (0, import_node_fs48.mkdirSync)((0, import_node_path46.dirname)(lockPath), { recursive: true });
40454
40860
  return take();
40455
40861
  } catch {
40456
40862
  try {
@@ -42136,11 +42542,11 @@ pr.command("view <number>").description("read a PR as structured JSON (merged st
42136
42542
  }
42137
42543
  });
42138
42544
  async function listCiWorkflowPaths(cwd = process.cwd()) {
42139
- const wfDir = (0, import_node_path45.join)(cwd, ".github", "workflows");
42545
+ const wfDir = (0, import_node_path46.join)(cwd, ".github", "workflows");
42140
42546
  if (!(0, import_node_fs48.existsSync)(wfDir)) return [];
42141
42547
  return (0, import_node_fs48.readdirSync)(wfDir).filter((name) => /\.(ya?ml)$/i.test(name)).filter((name) => {
42142
42548
  try {
42143
- return workflowReportsPrChecks((0, import_node_fs48.readFileSync)((0, import_node_path45.join)(wfDir, name), "utf8"));
42549
+ return workflowReportsPrChecks((0, import_node_fs48.readFileSync)((0, import_node_path46.join)(wfDir, name), "utf8"));
42144
42550
  } catch {
42145
42551
  return true;
42146
42552
  }
@@ -42192,16 +42598,16 @@ function ciAuditDeps() {
42192
42598
  // gate re-seed step is skipped gracefully rather than failing mid-run.
42193
42599
  readSeedFile: (path2) => {
42194
42600
  if (!root) return null;
42195
- const fullPath = (0, import_node_path45.join)(root, path2);
42601
+ const fullPath = (0, import_node_path46.join)(root, path2);
42196
42602
  return (0, import_node_fs48.existsSync)(fullPath) ? (0, import_node_fs48.readFileSync)(fullPath, "utf8") : null;
42197
42603
  }
42198
42604
  };
42199
42605
  }
42200
42606
  function hubRoot() {
42201
- const fromPkg = (0, import_node_path45.join)(__dirname, "..", "..");
42607
+ const fromPkg = (0, import_node_path46.join)(__dirname, "..", "..");
42202
42608
  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();
42609
+ if ((0, import_node_fs48.existsSync)((0, import_node_path46.join)(fromPkg, marker))) return fromPkg;
42610
+ if ((0, import_node_fs48.existsSync)((0, import_node_path46.join)(process.cwd(), marker))) return process.cwd();
42205
42611
  return null;
42206
42612
  }
42207
42613
  async function waitLoopCorePool(label) {
@@ -43257,7 +43663,7 @@ function directoryBytes(path2) {
43257
43663
  return 0;
43258
43664
  }
43259
43665
  for (const entry of entries) {
43260
- const child2 = (0, import_node_path45.join)(path2, entry.name);
43666
+ const child2 = (0, import_node_path46.join)(path2, entry.name);
43261
43667
  if (entry.isDirectory()) total += directoryBytes(child2);
43262
43668
  else {
43263
43669
  try {
@@ -43287,7 +43693,7 @@ function pluginCacheFsDeps(configRoot, dirBytes) {
43287
43693
  dirBytes,
43288
43694
  listStagingDirs: (root) => (0, import_node_fs48.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => {
43289
43695
  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) };
43696
+ return { name: d.name, mtimeMs: newestMtimeMs((0, import_node_path46.join)(root, d.name), listDirEntries, (p) => (0, import_node_fs48.statSync)(p).mtimeMs) };
43291
43697
  } catch {
43292
43698
  return { name: d.name, mtimeMs: Date.now() };
43293
43699
  }
@@ -43301,7 +43707,7 @@ function stagingApplyFsGuard(configRoot) {
43301
43707
  return {
43302
43708
  referencedPaths: () => readInstalledPluginRefs(configRoot),
43303
43709
  mtimeMs: (name) => {
43304
- const p = (0, import_node_path45.join)(stagingRoot, name);
43710
+ const p = (0, import_node_path46.join)(stagingRoot, name);
43305
43711
  if (!(0, import_node_fs48.existsSync)(p)) return null;
43306
43712
  try {
43307
43713
  return newestMtimeMs(p, listDirEntries, (q) => (0, import_node_fs48.statSync)(q).mtimeMs);
@@ -43324,7 +43730,7 @@ program2.command("plugin-prune").description(`prune stale cached MMI plugin vers
43324
43730
  return;
43325
43731
  }
43326
43732
  const plan = buildPluginCachePlan(
43327
- (0, import_node_os19.homedir)(),
43733
+ (0, import_node_os20.homedir)(),
43328
43734
  running,
43329
43735
  pluginCacheFsDeps(configRoot, directoryBytes),
43330
43736
  { withBytes: true, configRoot, includeStaging: surface !== "codex" }
@@ -43346,7 +43752,7 @@ function readReleaseCatchupState(path2) {
43346
43752
  }
43347
43753
  function writeReleaseCatchupState(path2, state) {
43348
43754
  try {
43349
- (0, import_node_fs48.mkdirSync)((0, import_node_path45.dirname)(path2), { recursive: true });
43755
+ (0, import_node_fs48.mkdirSync)((0, import_node_path46.dirname)(path2), { recursive: true });
43350
43756
  (0, import_node_fs48.writeFileSync)(path2, `${JSON.stringify(state)}
43351
43757
  `);
43352
43758
  } catch {
@@ -43355,7 +43761,7 @@ function writeReleaseCatchupState(path2, state) {
43355
43761
  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
43762
  const outcome = await withEnvHealLock(
43357
43763
  "plugin release catch-up",
43358
- () => runReleaseCatchup((0, import_node_os19.homedir)(), process.env, {
43764
+ () => runReleaseCatchup((0, import_node_os20.homedir)(), process.env, {
43359
43765
  fetchReleased: fetchNpmReleasedVersion,
43360
43766
  runClaude: (args, step) => runPluginCli("claude", args, (msg) => {
43361
43767
  if (!o.quiet && !o.json) console.log(msg);
@@ -43371,7 +43777,7 @@ program2.command("plugin-release-catchup").description("install a newer released
43371
43777
  },
43372
43778
  readState: readReleaseCatchupState,
43373
43779
  writeState: writeReleaseCatchupState,
43374
- healRegistration: defaultRegistrationHeal((0, import_node_os19.homedir)(), process.env),
43780
+ healRegistration: defaultRegistrationHeal((0, import_node_os20.homedir)(), process.env),
43375
43781
  now: () => Date.now()
43376
43782
  }, { force: o.force })
43377
43783
  );
@@ -43439,7 +43845,7 @@ program2.command("session-start").description("run the SessionStart verbs (whoam
43439
43845
  spawnDetachedSelf(["worktree", "setup", "--quiet"], { spawn: import_node_child_process20.spawn, execPath: process.execPath, scriptPath: process.argv[1] });
43440
43846
  bannerIo.log(worktreeBanner);
43441
43847
  }
43442
- if (shouldSpawnReleaseCatchup((0, import_node_os19.homedir)(), process.env, readReleaseCatchupState)) {
43848
+ if (shouldSpawnReleaseCatchup((0, import_node_os20.homedir)(), process.env, readReleaseCatchupState)) {
43443
43849
  spawnDetachedSelf(["plugin", "release-catchup", "--quiet"], { spawn: import_node_child_process20.spawn, execPath: process.execPath, scriptPath: process.argv[1] });
43444
43850
  }
43445
43851
  if (isLinkedWorktree(process.cwd())) {