@mutmutco/cli 3.105.9 → 3.105.11

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 +872 -546
  2. package/package.json +1 -1
package/dist/main.cjs CHANGED
@@ -5000,7 +5000,7 @@ var program = new Command();
5000
5000
 
5001
5001
  // src/index.ts
5002
5002
  var import_promises11 = require("node:fs/promises");
5003
- var import_node_fs42 = require("node:fs");
5003
+ var import_node_fs43 = require("node:fs");
5004
5004
  var import_node_child_process19 = require("node:child_process");
5005
5005
 
5006
5006
  // src/cli-shared.ts
@@ -6517,12 +6517,148 @@ function localTrainSyncBannerLine(result) {
6517
6517
 
6518
6518
  // src/gc.ts
6519
6519
  var import_promises = require("node:fs/promises");
6520
- var import_node_path8 = require("node:path");
6520
+ var import_node_path9 = require("node:path");
6521
6521
 
6522
- // src/worktree-ownership.ts
6522
+ // src/active-workspace-root.ts
6523
6523
  var import_node_fs9 = require("node:fs");
6524
6524
  var import_node_os3 = require("node:os");
6525
6525
  var import_node_path7 = require("node:path");
6526
+ var ACTIVE_WORKSPACE_ROOT_ENV = "MMI_ACTIVE_WORKSPACE_ROOT";
6527
+ function normPath(p, platform2 = process.platform) {
6528
+ const unified = p.replace(/\\/g, "/").replace(/\/+$/, "");
6529
+ return platform2 === "win32" || platform2 === "darwin" ? unified.toLowerCase() : unified;
6530
+ }
6531
+ function isPathUnderDirectory(childPath, parentPath, platform2 = process.platform) {
6532
+ const child2 = normPath(childPath, platform2);
6533
+ const parent = normPath(parentPath, platform2);
6534
+ if (!child2 || !parent) return false;
6535
+ if (child2 === parent) return true;
6536
+ return child2.startsWith(`${parent}/`);
6537
+ }
6538
+ function normalizeActiveWorkspaceRoot(value, opts = {}) {
6539
+ const raw = value?.trim();
6540
+ if (!raw) return void 0;
6541
+ if (!(0, import_node_path7.isAbsolute)(raw)) return void 0;
6542
+ const exists = opts.exists ?? import_node_fs9.existsSync;
6543
+ if (!exists(raw)) return void 0;
6544
+ return normPath(raw, opts.platform);
6545
+ }
6546
+ function removalTouchesActiveWorkspace(targetPath, activeWorkspaceRoot, platform2 = process.platform) {
6547
+ const target = normPath(targetPath, platform2);
6548
+ const root = normPath(activeWorkspaceRoot, platform2);
6549
+ if (!target || !root) return false;
6550
+ return isPathUnderDirectory(root, target, platform2);
6551
+ }
6552
+ function activeWorkspaceRefusalMessage(targetPath, activeWorkspaceRoot) {
6553
+ 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\`.`;
6554
+ }
6555
+ function decideActiveWorkspaceGuard(targetPath, activeWorkspaceRoot, platform2 = process.platform) {
6556
+ if (!activeWorkspaceRoot) return { action: "proceed" };
6557
+ if (!removalTouchesActiveWorkspace(targetPath, activeWorkspaceRoot, platform2)) {
6558
+ return { action: "proceed" };
6559
+ }
6560
+ return {
6561
+ action: "refuse",
6562
+ reason: "active-workspace",
6563
+ activeWorkspaceRoot,
6564
+ message: activeWorkspaceRefusalMessage(targetPath, activeWorkspaceRoot)
6565
+ };
6566
+ }
6567
+ function cursorProjectSlugFromAgentTranscripts(agentTranscripts) {
6568
+ const raw = agentTranscripts?.trim();
6569
+ if (!raw) return void 0;
6570
+ const unified = raw.replace(/\\/g, "/").replace(/\/+$/, "");
6571
+ const parts = unified.split("/");
6572
+ const idx = parts.lastIndexOf("agent-transcripts");
6573
+ if (idx <= 0) return void 0;
6574
+ const slug = parts[idx - 1]?.trim();
6575
+ return slug || void 0;
6576
+ }
6577
+ function cursorProjectSlugFromFolderPath(folderPath, platform2 = process.platform) {
6578
+ let unified = folderPath.replace(/\\/g, "/").replace(/\/+$/, "");
6579
+ if (platform2 === "win32") {
6580
+ unified = unified.replace(/^\/+/, "");
6581
+ } else if (unified.startsWith("/")) {
6582
+ unified = unified.slice(1);
6583
+ }
6584
+ return unified.replace(/\//g, "-");
6585
+ }
6586
+ function cursorWorkspaceStorageRoot(platform2 = process.platform, home = (0, import_node_os3.homedir)()) {
6587
+ if (platform2 === "darwin") {
6588
+ return (0, import_node_path7.join)(home, "Library", "Application Support", "Cursor", "User", "workspaceStorage");
6589
+ }
6590
+ if (platform2 === "win32") {
6591
+ return (0, import_node_path7.join)(home, "AppData", "Roaming", "Cursor", "User", "workspaceStorage");
6592
+ }
6593
+ return (0, import_node_path7.join)(home, ".config", "Cursor", "User", "workspaceStorage");
6594
+ }
6595
+ function folderUriToPath(uri) {
6596
+ const trimmed = uri.trim();
6597
+ if (!trimmed.startsWith("file://")) return void 0;
6598
+ let rest = trimmed.slice("file://".length);
6599
+ if (/^\/[A-Za-z]:\//.test(rest)) rest = rest.slice(1);
6600
+ try {
6601
+ return decodeURIComponent(rest);
6602
+ } catch {
6603
+ return rest;
6604
+ }
6605
+ }
6606
+ function resolveCursorAgentWorkspaceRoot(deps = {}) {
6607
+ const env = deps.env ?? process.env;
6608
+ const platform2 = deps.platform ?? process.platform;
6609
+ const exists = deps.exists ?? import_node_fs9.existsSync;
6610
+ const readTextFile = deps.readTextFile ?? ((path2) => {
6611
+ try {
6612
+ return (0, import_node_fs9.readFileSync)(path2, "utf8");
6613
+ } catch {
6614
+ return void 0;
6615
+ }
6616
+ });
6617
+ const listDir = deps.listDir ?? ((path2) => {
6618
+ try {
6619
+ return (0, import_node_fs9.readdirSync)(path2);
6620
+ } catch {
6621
+ return [];
6622
+ }
6623
+ });
6624
+ const slug = cursorProjectSlugFromAgentTranscripts(env.AGENT_TRANSCRIPTS);
6625
+ if (!slug) return void 0;
6626
+ const storageRoot = cursorWorkspaceStorageRoot(platform2, (deps.homedir ?? import_node_os3.homedir)());
6627
+ if (!exists(storageRoot)) return void 0;
6628
+ const matches = /* @__PURE__ */ new Set();
6629
+ for (const entry of listDir(storageRoot)) {
6630
+ const text = readTextFile((0, import_node_path7.join)(storageRoot, entry, "workspace.json"));
6631
+ if (!text) continue;
6632
+ let parsed;
6633
+ try {
6634
+ parsed = JSON.parse(text.replace(/^\uFEFF/, ""));
6635
+ } catch {
6636
+ continue;
6637
+ }
6638
+ if (typeof parsed.folder !== "string") continue;
6639
+ const folderPath = folderUriToPath(parsed.folder);
6640
+ if (!folderPath || !exists(folderPath)) continue;
6641
+ if (cursorProjectSlugFromFolderPath(folderPath, platform2) !== slug) continue;
6642
+ matches.add(normPath(folderPath, platform2));
6643
+ }
6644
+ if (matches.size !== 1) return void 0;
6645
+ return [...matches][0];
6646
+ }
6647
+ function resolveActiveWorkspaceRoot(deps = {}) {
6648
+ const env = deps.env ?? process.env;
6649
+ const platform2 = deps.platform ?? process.platform;
6650
+ const exists = deps.exists ?? import_node_fs9.existsSync;
6651
+ const fromEnv = normalizeActiveWorkspaceRoot(env[ACTIVE_WORKSPACE_ROOT_ENV], { exists, platform: platform2 });
6652
+ if (fromEnv) return fromEnv;
6653
+ const cursorAgent = env.CURSOR_AGENT === "1" || Boolean(env.CURSOR_EXTENSION_HOST_ROLE?.trim());
6654
+ if (!cursorAgent && !env.AGENT_TRANSCRIPTS?.trim()) return void 0;
6655
+ return resolveCursorAgentWorkspaceRoot(deps);
6656
+ }
6657
+
6658
+ // src/worktree-ownership.ts
6659
+ var import_node_fs10 = require("node:fs");
6660
+ var import_node_os4 = require("node:os");
6661
+ var import_node_path8 = require("node:path");
6526
6662
  var OWNERS_FILE = "worktree-owners.json";
6527
6663
  var EVENTS_FILE = "worktree-events.jsonl";
6528
6664
  var WORKTREE_ACTIVITY_WINDOW_MS = 30 * 6e4;
@@ -6546,7 +6682,7 @@ function describeActor(input) {
6546
6682
  const session = readSessionId(input.env);
6547
6683
  return {
6548
6684
  surface: input.surface,
6549
- host: input.host ?? (0, import_node_os3.hostname)(),
6685
+ host: input.host ?? (0, import_node_os4.hostname)(),
6550
6686
  pid: input.pid ?? process.pid,
6551
6687
  cwd: input.cwd,
6552
6688
  ...session ? { session } : {}
@@ -6627,7 +6763,7 @@ function decideWorktreeRemoval(input) {
6627
6763
  }
6628
6764
  function readFreshWorktreeLease(path2, now) {
6629
6765
  try {
6630
- const candidate = JSON.parse((0, import_node_fs9.readFileSync)((0, import_node_path7.join)(path2, WORKTREE_LEASE_MARKER), "utf8"));
6766
+ const candidate = JSON.parse((0, import_node_fs10.readFileSync)((0, import_node_path8.join)(path2, WORKTREE_LEASE_MARKER), "utf8"));
6631
6767
  if (!candidate || typeof candidate !== "object" || Array.isArray(candidate)) return void 0;
6632
6768
  const lease = candidate;
6633
6769
  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;
@@ -6646,7 +6782,7 @@ function describeActorShort(actor) {
6646
6782
  }
6647
6783
  function readOwners(primaryRoot) {
6648
6784
  try {
6649
- return parseWorktreeOwners((0, import_node_fs9.readFileSync)(worktreeOwnersPath(primaryRoot), "utf8"));
6785
+ return parseWorktreeOwners((0, import_node_fs10.readFileSync)(worktreeOwnersPath(primaryRoot), "utf8"));
6650
6786
  } catch {
6651
6787
  return [];
6652
6788
  }
@@ -6654,8 +6790,8 @@ function readOwners(primaryRoot) {
6654
6790
  function writeOwners(primaryRoot, entries) {
6655
6791
  try {
6656
6792
  const path2 = worktreeOwnersPath(primaryRoot);
6657
- (0, import_node_fs9.mkdirSync)((0, import_node_path7.dirname)(path2), { recursive: true });
6658
- (0, import_node_fs9.writeFileSync)(path2, serializeWorktreeOwners(entries), "utf8");
6793
+ (0, import_node_fs10.mkdirSync)((0, import_node_path8.dirname)(path2), { recursive: true });
6794
+ (0, import_node_fs10.writeFileSync)(path2, serializeWorktreeOwners(entries), "utf8");
6659
6795
  } catch {
6660
6796
  }
6661
6797
  }
@@ -6690,8 +6826,8 @@ function dropWorktreeOwner(primaryRoot, path2, expectedCreatedAt) {
6690
6826
  function appendWorktreeEvent(primaryRoot, event) {
6691
6827
  try {
6692
6828
  const path2 = worktreeEventsPath(primaryRoot);
6693
- (0, import_node_fs9.mkdirSync)((0, import_node_path7.dirname)(path2), { recursive: true });
6694
- (0, import_node_fs9.appendFileSync)(path2, `${JSON.stringify({ at: event.at ?? (/* @__PURE__ */ new Date()).toISOString(), ...event })}
6829
+ (0, import_node_fs10.mkdirSync)((0, import_node_path8.dirname)(path2), { recursive: true });
6830
+ (0, import_node_fs10.appendFileSync)(path2, `${JSON.stringify({ at: event.at ?? (/* @__PURE__ */ new Date()).toISOString(), ...event })}
6695
6831
  `, "utf8");
6696
6832
  } catch {
6697
6833
  }
@@ -6708,7 +6844,7 @@ function recordWorktreeRemoval(primaryRoot, event) {
6708
6844
  function readWorktreeEvents(primaryRoot, limit = 50) {
6709
6845
  let text;
6710
6846
  try {
6711
- text = (0, import_node_fs9.readFileSync)(worktreeEventsPath(primaryRoot), "utf8");
6847
+ text = (0, import_node_fs10.readFileSync)(worktreeEventsPath(primaryRoot), "utf8");
6712
6848
  } catch {
6713
6849
  return [];
6714
6850
  }
@@ -6805,7 +6941,12 @@ async function isCommitUnreferenced(oid, git2) {
6805
6941
  return refs !== void 0 && !refs.trim();
6806
6942
  }
6807
6943
  var DEFERRED_SWEEP_COMMAND = "mmi-cli worktree gc sweep-deferred";
6808
- var DEFERRED_NOTE = "Worktree cleanup queued (IDE lock). Detached sweep will retry automatically \u2014 no human action required.";
6944
+ function deferredNoteFor(reason) {
6945
+ if (reason === "active-workspace") {
6946
+ return "Worktree cleanup queued (active Cursor workspace). Open the primary checkout in Cursor first \u2014 then detached sweep / `worktree gc sweep-deferred` can remove it.";
6947
+ }
6948
+ return "Worktree cleanup queued (IDE lock). Detached sweep will retry automatically \u2014 no human action required.";
6949
+ }
6809
6950
  var PRESERVED_WORKTREE_CONFIG = "mmi.preservedWorktreeBranch";
6810
6951
  var WORKTREE_LOCK_RE = /EPERM|EBUSY|EACCES|ENOTEMPTY|permission denied|access is denied|used by another process|resource busy|directory not empty/i;
6811
6952
  function isWorktreeLockError(error) {
@@ -6821,14 +6962,14 @@ function deferredWorktreesRegistryPath(gitDir) {
6821
6962
  function parseDeferredWorktreesFile(text) {
6822
6963
  const parsed = JSON.parse(text.replace(/^\uFEFF/, ""));
6823
6964
  if (!parsed || !Array.isArray(parsed.entries)) return [];
6824
- return parsed.entries.filter((e) => Boolean(e) && typeof e === "object" && typeof e.path === "string" && typeof e.branch === "string" && e.reason === "lock-held").map((e) => ({ ...e, registeredAt: e.registeredAt || (/* @__PURE__ */ new Date(0)).toISOString() }));
6965
+ return parsed.entries.filter((e) => Boolean(e) && typeof e === "object" && typeof e.path === "string" && typeof e.branch === "string" && (e.reason === "lock-held" || e.reason === "active-workspace")).map((e) => ({ ...e, registeredAt: e.registeredAt || (/* @__PURE__ */ new Date(0)).toISOString() }));
6825
6966
  }
6826
6967
  function serializeDeferredWorktrees(entries) {
6827
6968
  return `${JSON.stringify({ entries }, null, 2)}
6828
6969
  `;
6829
6970
  }
6830
6971
  function deferredPathKey(path2) {
6831
- return normPath(path2);
6972
+ return normPath2(path2);
6832
6973
  }
6833
6974
  function isPersistentWorktreeLockFailure(outcome) {
6834
6975
  return outcome.status === "failed" && isWorktreeLockError(outcome.error);
@@ -6838,7 +6979,7 @@ async function registerDeferredWorktree(store, entry) {
6838
6979
  const built = {
6839
6980
  ...entry,
6840
6981
  registeredAt: entry.registeredAt ?? (/* @__PURE__ */ new Date()).toISOString(),
6841
- reason: "lock-held"
6982
+ reason: entry.reason ?? "lock-held"
6842
6983
  };
6843
6984
  let newlyRegistered = false;
6844
6985
  const mutate = (existing2) => {
@@ -6879,6 +7020,21 @@ async function sweepDeferredWorktrees(store, deps, removalContext) {
6879
7020
  }
6880
7021
  const owner = removalContext ? lookupWorktreeOwner(removalContext.primaryRoot, entry.path) : void 0;
6881
7022
  if (removalContext) {
7023
+ const activeRoot = removalContext.activeWorkspaceRoot ?? resolveActiveWorkspaceRoot();
7024
+ const activeGuard = decideActiveWorkspaceGuard(entry.path, activeRoot);
7025
+ if (activeGuard.action === "refuse") {
7026
+ stillDeferred.push({ ...entry, reason: "active-workspace" });
7027
+ recordWorktreeRemoval(removalContext.primaryRoot, {
7028
+ action: "refused",
7029
+ command: removalContext.command,
7030
+ target: entry.path,
7031
+ branch: entry.branch,
7032
+ actor: removalContext.actor,
7033
+ owner,
7034
+ reason: activeGuard.message
7035
+ });
7036
+ continue;
7037
+ }
6882
7038
  const verdict = decideWorktreeRemoval({
6883
7039
  path: entry.path,
6884
7040
  owner,
@@ -7002,10 +7158,10 @@ function baseName(p) {
7002
7158
  return p.replace(/[/\\]+$/, "").split(/[/\\]/).pop() ?? "";
7003
7159
  }
7004
7160
  function assertSafeWorktreeTarget(worktreePath, primaryCheckout) {
7005
- const wt = normPath(worktreePath);
7161
+ const wt = normPath2(worktreePath);
7006
7162
  if (!wt) throw new Error("worktree teardown refused: empty target path");
7007
7163
  if (!primaryCheckout) return;
7008
- const primary = normPath(primaryCheckout);
7164
+ const primary = normPath2(primaryCheckout);
7009
7165
  if (wt === primary) throw new Error(`worktree teardown refused: target is the primary checkout (${worktreePath})`);
7010
7166
  if (primary.startsWith(`${wt}/`)) {
7011
7167
  throw new Error(`worktree teardown refused: target ${worktreePath} contains the primary checkout`);
@@ -7161,7 +7317,7 @@ function resolveSafeSiblingWorktreeCleanupTarget(worktreePath, siblingRoot, deps
7161
7317
  } catch {
7162
7318
  return { ok: false, reason: "sibling root could not be resolved" };
7163
7319
  }
7164
- if (!isPathUnderDirectory(rootReal, siblingRoot) || !isPathUnderDirectory(siblingRoot, rootReal)) {
7320
+ if (!isPathUnderDirectory2(rootReal, siblingRoot) || !isPathUnderDirectory2(siblingRoot, rootReal)) {
7165
7321
  return { ok: false, reason: "sibling root resolves outside expected path" };
7166
7322
  }
7167
7323
  try {
@@ -7169,26 +7325,26 @@ function resolveSafeSiblingWorktreeCleanupTarget(worktreePath, siblingRoot, deps
7169
7325
  } catch {
7170
7326
  return { ok: false, reason: "worktree path could not be resolved" };
7171
7327
  }
7172
- if (!isPathUnderDirectory(worktreeReal, rootReal)) {
7328
+ if (!isPathUnderDirectory2(worktreeReal, rootReal)) {
7173
7329
  return { ok: false, reason: "resolved worktree path outside sibling root" };
7174
7330
  }
7175
7331
  return { ok: true, path: worktreePath };
7176
7332
  }
7177
7333
  function siblingMmiWorktreesRoot(repoRoot2) {
7178
- const parent = (0, import_node_path8.dirname)(repoRoot2);
7179
- if ((0, import_node_path8.basename)(parent).toLowerCase() === "mmi-worktrees") return parent;
7180
- const grandparent = (0, import_node_path8.dirname)(parent);
7181
- if ((0, import_node_path8.basename)(grandparent).toLowerCase() === "mmi-worktrees") return grandparent;
7182
- return (0, import_node_path8.join)(parent, "mmi-worktrees");
7334
+ const parent = (0, import_node_path9.dirname)(repoRoot2);
7335
+ if ((0, import_node_path9.basename)(parent).toLowerCase() === "mmi-worktrees") return parent;
7336
+ const grandparent = (0, import_node_path9.dirname)(parent);
7337
+ if ((0, import_node_path9.basename)(grandparent).toLowerCase() === "mmi-worktrees") return grandparent;
7338
+ return (0, import_node_path9.join)(parent, "mmi-worktrees");
7183
7339
  }
7184
7340
  function worktreeScanDirs(root, repoRoot2, listDirs, isRepoCheckout) {
7185
- const projectsDir = (0, import_node_path8.dirname)(root);
7186
- const ownName = (0, import_node_path8.basename)(repoRoot2).toLowerCase();
7341
+ const projectsDir = (0, import_node_path9.dirname)(root);
7342
+ const ownName = (0, import_node_path9.basename)(repoRoot2).toLowerCase();
7187
7343
  const flat = [];
7188
7344
  let ownContainer = null;
7189
7345
  for (const dir of listDirs(root)) {
7190
- const name = (0, import_node_path8.basename)(dir);
7191
- if (isRepoCheckout((0, import_node_path8.join)(projectsDir, name))) {
7346
+ const name = (0, import_node_path9.basename)(dir);
7347
+ if (isRepoCheckout((0, import_node_path9.join)(projectsDir, name))) {
7192
7348
  if (name.toLowerCase() === ownName) ownContainer = dir;
7193
7349
  continue;
7194
7350
  }
@@ -7197,9 +7353,9 @@ function worktreeScanDirs(root, repoRoot2, listDirs, isRepoCheckout) {
7197
7353
  return ownContainer ? [...flat, ...listDirs(ownContainer)] : flat;
7198
7354
  }
7199
7355
  function explicitRepoWorktreesRoot(root, repoRoot2, rootDirs) {
7200
- const repoName = (0, import_node_path8.basename)(repoRoot2);
7356
+ const repoName = (0, import_node_path9.basename)(repoRoot2);
7201
7357
  const repoDir = rootDirs.find((name) => name.toLowerCase() === repoName.toLowerCase());
7202
- return repoDir ? (0, import_node_path8.join)(root, repoDir) : root;
7358
+ return repoDir ? (0, import_node_path9.join)(root, repoDir) : root;
7203
7359
  }
7204
7360
  function classifySiblingWorktreeDir(entry) {
7205
7361
  if (!entry.ownedByCurrentRepo) {
@@ -7475,12 +7631,12 @@ function parseWorktreePorcelain(stdout) {
7475
7631
  function pathsAreCaseInsensitive(platform2 = process.platform) {
7476
7632
  return platform2 === "win32" || platform2 === "darwin";
7477
7633
  }
7478
- function normPath(p, platform2 = process.platform) {
7634
+ function normPath2(p, platform2 = process.platform) {
7479
7635
  const unified = p.replace(/\\/g, "/").replace(/\/+$/, "");
7480
7636
  return pathsAreCaseInsensitive(platform2) ? unified.toLowerCase() : unified;
7481
7637
  }
7482
7638
  function samePath(a, b, platform2 = process.platform) {
7483
- return normPath(a, platform2) === normPath(b, platform2);
7639
+ return normPath2(a, platform2) === normPath2(b, platform2);
7484
7640
  }
7485
7641
  function toNativePath(p) {
7486
7642
  return process.platform === "win32" ? p.replace(/\//g, "\\") : p;
@@ -7515,12 +7671,12 @@ function parseComposeLs(stdout) {
7515
7671
  }).filter((p) => Boolean(p));
7516
7672
  }
7517
7673
  function selectWorktreeComposeProjects(worktreePath, projects) {
7518
- const root = normPath(worktreePath);
7674
+ const root = normPath2(worktreePath);
7519
7675
  if (!root) return [];
7520
7676
  const names = [];
7521
7677
  for (const project2 of projects) {
7522
7678
  const inside = project2.configFiles.some((file) => {
7523
- const f = normPath(file);
7679
+ const f = normPath2(file);
7524
7680
  return f === root || f.startsWith(`${root}/`);
7525
7681
  });
7526
7682
  if (inside && !names.includes(project2.name)) names.push(project2.name);
@@ -7528,7 +7684,7 @@ function selectWorktreeComposeProjects(worktreePath, projects) {
7528
7684
  return names;
7529
7685
  }
7530
7686
  function deriveComposeProjectName(worktreePath) {
7531
- const norm = normPath(worktreePath).toLowerCase();
7687
+ const norm = normPath2(worktreePath).toLowerCase();
7532
7688
  if (!norm) return void 0;
7533
7689
  const base = norm.slice(norm.lastIndexOf("/") + 1);
7534
7690
  const name = base.replace(/[^a-z0-9_-]+/g, "_").replace(/^[^a-z0-9]+/, "");
@@ -7589,15 +7745,15 @@ function selectSafeWorktreeCwd(worktrees, targetPath, options) {
7589
7745
  const exists = options?.pathExists ?? (() => true);
7590
7746
  return worktrees.find((w) => !samePath(w.path, targetPath) && exists(w.path))?.path;
7591
7747
  }
7592
- function isPathUnderDirectory(childPath, parentPath) {
7593
- const child2 = normPath(childPath);
7594
- const parent = normPath(parentPath);
7748
+ function isPathUnderDirectory2(childPath, parentPath) {
7749
+ const child2 = normPath2(childPath);
7750
+ const parent = normPath2(parentPath);
7595
7751
  if (!child2 || !parent) return false;
7596
7752
  if (child2 === parent) return true;
7597
7753
  return child2.startsWith(`${parent}/`);
7598
7754
  }
7599
7755
  function planReleaseCwdBeforeWorktreeRemoval(targetPath, safeCwd, currentCwd) {
7600
- if (!safeCwd || !isPathUnderDirectory(currentCwd, targetPath)) return void 0;
7756
+ if (!safeCwd || !isPathUnderDirectory2(currentCwd, targetPath)) return void 0;
7601
7757
  if (samePath(currentCwd, safeCwd)) return void 0;
7602
7758
  return safeCwd;
7603
7759
  }
@@ -7748,6 +7904,57 @@ async function cleanupPrMergeLocalBranch(branch, options) {
7748
7904
  if (wtPath && mainWorktreeTarget) {
7749
7905
  report.worktree = { path: wtPath, status: "not-attempted", reason: "main-worktree" };
7750
7906
  } else if (wtPath) {
7907
+ const activeRoot = options.removalContext?.activeWorkspaceRoot ?? resolveActiveWorkspaceRoot();
7908
+ const activeGuard = decideActiveWorkspaceGuard(wtPath, activeRoot);
7909
+ if (activeGuard.action === "refuse") {
7910
+ if (options.deferredStore) {
7911
+ try {
7912
+ const { newlyRegistered } = await registerDeferredWorktree(options.deferredStore, {
7913
+ path: wtPath,
7914
+ branch,
7915
+ reason: "active-workspace"
7916
+ });
7917
+ report.worktree = {
7918
+ path: wtPath,
7919
+ status: "deferred",
7920
+ reason: "active-workspace",
7921
+ deferredNote: deferredNoteFor("active-workspace"),
7922
+ deferredSweepCommand: DEFERRED_SWEEP_COMMAND,
7923
+ ...newlyRegistered ? { safeCleanupCommand: safeWorktreeRemoveCommand(safeCwd, wtPath) } : {}
7924
+ };
7925
+ if (options.removalContext) {
7926
+ recordWorktreeRemoval(options.removalContext.primaryRoot, {
7927
+ action: "refused",
7928
+ command: options.removalContext.command,
7929
+ target: wtPath,
7930
+ branch,
7931
+ actor: options.removalContext.actor,
7932
+ owner: lookupWorktreeOwner(options.removalContext.primaryRoot, wtPath),
7933
+ reason: activeGuard.message
7934
+ });
7935
+ }
7936
+ noteBranchBlocked("active-workspace");
7937
+ return report;
7938
+ } catch (e) {
7939
+ report.worktree = {
7940
+ path: wtPath,
7941
+ status: "not-attempted",
7942
+ reason: "active-workspace",
7943
+ error: `${activeGuard.message}; deferred registry unavailable: ${errorMessage(e)}`
7944
+ };
7945
+ noteBranchBlocked("active-workspace");
7946
+ return report;
7947
+ }
7948
+ }
7949
+ report.worktree = {
7950
+ path: wtPath,
7951
+ status: "not-attempted",
7952
+ reason: "active-workspace",
7953
+ error: activeGuard.message
7954
+ };
7955
+ noteBranchBlocked("active-workspace");
7956
+ return report;
7957
+ }
7751
7958
  const dirt = await worktreeDirtyAtActTime(wtPath);
7752
7959
  if (dirt !== void 0 && !isRemovableDirt(dirt)) {
7753
7960
  const reason = dirt === "untracked-files" ? "untracked-files" : "dirty-worktree";
@@ -7813,7 +8020,7 @@ async function cleanupPrMergeLocalBranch(branch, options) {
7813
8020
  status: "deferred",
7814
8021
  reason: "lock-held",
7815
8022
  error: outcome.error,
7816
- deferredNote: DEFERRED_NOTE,
8023
+ deferredNote: deferredNoteFor("lock-held"),
7817
8024
  deferredSweepCommand: DEFERRED_SWEEP_COMMAND,
7818
8025
  ...newlyRegistered ? { safeCleanupCommand: safeWorktreeRemoveCommand(safeCwd, wtPath) } : {},
7819
8026
  stageTeardown
@@ -8027,13 +8234,13 @@ async function gatherStaleWorktreeWarning(gitRun = defaultGitRun) {
8027
8234
  }
8028
8235
 
8029
8236
  // src/released-version-cache.ts
8030
- var import_node_fs10 = require("node:fs");
8031
- var import_node_path9 = require("node:path");
8237
+ var import_node_fs11 = require("node:fs");
8238
+ var import_node_path10 = require("node:path");
8032
8239
  var RELEASED_VERSION_CACHE_MS = 24 * 36e5;
8033
8240
  function releasedVersionCachePath(runtimeRoot) {
8034
- return (0, import_node_path9.join)(runtimeRoot, "head-ts", ".released-version");
8241
+ return (0, import_node_path10.join)(runtimeRoot, "head-ts", ".released-version");
8035
8242
  }
8036
- function readReleasedVersionCache(cachePath, now = Date.now(), read = import_node_fs10.readFileSync) {
8243
+ function readReleasedVersionCache(cachePath, now = Date.now(), read = import_node_fs11.readFileSync) {
8037
8244
  let parsed;
8038
8245
  try {
8039
8246
  parsed = JSON.parse(read(cachePath, "utf8"));
@@ -8050,8 +8257,8 @@ function readReleasedVersionCache(cachePath, now = Date.now(), read = import_nod
8050
8257
  }
8051
8258
  function writeReleasedVersionCache(cachePath, version, now = Date.now()) {
8052
8259
  try {
8053
- (0, import_node_fs10.mkdirSync)((0, import_node_path9.dirname)(cachePath), { recursive: true });
8054
- (0, import_node_fs10.writeFileSync)(cachePath, JSON.stringify({ version, at: now }), "utf8");
8260
+ (0, import_node_fs11.mkdirSync)((0, import_node_path10.dirname)(cachePath), { recursive: true });
8261
+ (0, import_node_fs11.writeFileSync)(cachePath, JSON.stringify({ version, at: now }), "utf8");
8055
8262
  } catch {
8056
8263
  }
8057
8264
  }
@@ -8268,8 +8475,8 @@ function marketplaceRows(name, known, settings, healable = false) {
8268
8475
  }
8269
8476
 
8270
8477
  // src/hook-activity.ts
8271
- var import_node_fs11 = require("node:fs");
8272
- var import_node_path10 = require("node:path");
8478
+ var import_node_fs12 = require("node:fs");
8479
+ var import_node_path11 = require("node:path");
8273
8480
  var DEFAULT_SURFACE = "claude";
8274
8481
  function activityLogPath(cwd) {
8275
8482
  return repoRuntimeStatePath(cwd, "hooks", "activity.jsonl");
@@ -8282,20 +8489,20 @@ function appendHookActivity(cwd, entry) {
8282
8489
  surface: DEFAULT_SURFACE,
8283
8490
  ...entry
8284
8491
  };
8285
- (0, import_node_fs11.mkdirSync)((0, import_node_path10.dirname)(path2), { recursive: true });
8286
- (0, import_node_fs11.appendFileSync)(path2, `${JSON.stringify(line)}
8492
+ (0, import_node_fs12.mkdirSync)((0, import_node_path11.dirname)(path2), { recursive: true });
8493
+ (0, import_node_fs12.appendFileSync)(path2, `${JSON.stringify(line)}
8287
8494
  `, "utf8");
8288
8495
  } catch {
8289
8496
  }
8290
8497
  }
8291
8498
 
8292
8499
  // src/worktree.ts
8293
- var import_node_fs12 = require("node:fs");
8294
- var import_node_path12 = require("node:path");
8500
+ var import_node_fs13 = require("node:fs");
8501
+ var import_node_path13 = require("node:path");
8295
8502
 
8296
8503
  // src/file-lock.ts
8297
8504
  var import_promises2 = require("node:fs/promises");
8298
- var import_node_path11 = require("node:path");
8505
+ var import_node_path12 = require("node:path");
8299
8506
  var sleep = (ms) => new Promise((resolve5) => setTimeout(resolve5, ms));
8300
8507
  var IMMEDIATE_RETRY_BUDGET = 3;
8301
8508
  var FileLockBusyError = class extends Error {
@@ -8380,7 +8587,7 @@ async function releaseFileLock(lockPath, guard) {
8380
8587
  }
8381
8588
  async function withFileLock(lockPath, opts, fn) {
8382
8589
  const resolved = resolveFileLockOpts(opts);
8383
- await (0, import_promises2.mkdir)((0, import_node_path11.dirname)(lockPath), { recursive: true }).catch(() => void 0);
8590
+ await (0, import_promises2.mkdir)((0, import_node_path12.dirname)(lockPath), { recursive: true }).catch(() => void 0);
8384
8591
  const guard = await acquireFileLock(lockPath, resolved, Date.now() + resolved.maxWaitMs);
8385
8592
  try {
8386
8593
  return await fn();
@@ -8407,35 +8614,35 @@ var PROVISION_ENV_MARKER = "MMI_PROVISION_RUNNING";
8407
8614
  var realFsProbe = {
8408
8615
  isDir: (p) => {
8409
8616
  try {
8410
- return (0, import_node_fs12.statSync)(p).isDirectory();
8617
+ return (0, import_node_fs13.statSync)(p).isDirectory();
8411
8618
  } catch {
8412
8619
  return false;
8413
8620
  }
8414
8621
  },
8415
8622
  isFile: (p) => {
8416
8623
  try {
8417
- return (0, import_node_fs12.statSync)(p).isFile();
8624
+ return (0, import_node_fs13.statSync)(p).isFile();
8418
8625
  } catch {
8419
8626
  return false;
8420
8627
  }
8421
8628
  },
8422
8629
  listDirs: (p) => {
8423
8630
  try {
8424
- return (0, import_node_fs12.readdirSync)(p, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
8631
+ return (0, import_node_fs13.readdirSync)(p, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
8425
8632
  } catch {
8426
8633
  return [];
8427
8634
  }
8428
8635
  },
8429
8636
  readFile: (p) => {
8430
8637
  try {
8431
- return (0, import_node_fs12.readFileSync)(p, "utf8");
8638
+ return (0, import_node_fs13.readFileSync)(p, "utf8");
8432
8639
  } catch {
8433
8640
  return void 0;
8434
8641
  }
8435
8642
  }
8436
8643
  };
8437
8644
  function declaredProvision(fs2, abs) {
8438
- const raw = fs2.readFile?.((0, import_node_path12.join)(abs, PKG));
8645
+ const raw = fs2.readFile?.((0, import_node_path13.join)(abs, PKG));
8439
8646
  if (raw === void 0) return void 0;
8440
8647
  try {
8441
8648
  const scripts = JSON.parse(raw).scripts;
@@ -8447,13 +8654,13 @@ function declaredProvision(fs2, abs) {
8447
8654
  }
8448
8655
  function scanInstallDirs(root, fs2 = realFsProbe) {
8449
8656
  const factsFor = (dir) => {
8450
- const abs = dir ? (0, import_node_path12.join)(root, dir) : root;
8451
- const match = LOCKFILE_INSTALLS.find((c) => fs2.isFile((0, import_node_path12.join)(abs, c.lockfile)));
8452
- const hasPackageJson = fs2.isFile((0, import_node_path12.join)(abs, PKG));
8657
+ const abs = dir ? (0, import_node_path13.join)(root, dir) : root;
8658
+ const match = LOCKFILE_INSTALLS.find((c) => fs2.isFile((0, import_node_path13.join)(abs, c.lockfile)));
8659
+ const hasPackageJson = fs2.isFile((0, import_node_path13.join)(abs, PKG));
8453
8660
  return {
8454
8661
  dir,
8455
8662
  hasPackageJson,
8456
- hasNodeModules: fs2.isDir((0, import_node_path12.join)(abs, NODE_MODULES)),
8663
+ hasNodeModules: fs2.isDir((0, import_node_path13.join)(abs, NODE_MODULES)),
8457
8664
  install: match?.command,
8458
8665
  provision: hasPackageJson ? declaredProvision(fs2, abs) : void 0
8459
8666
  };
@@ -8469,7 +8676,7 @@ function npmInstallTargets(dirs) {
8469
8676
  }));
8470
8677
  }
8471
8678
  function isLinkedWorktree(root, fs2 = realFsProbe) {
8472
- return fs2.isFile((0, import_node_path12.join)(root, ".git"));
8679
+ return fs2.isFile((0, import_node_path13.join)(root, ".git"));
8473
8680
  }
8474
8681
  function worktreeAutoProvisionBanner(root, fs2 = realFsProbe) {
8475
8682
  if (!isLinkedWorktree(root, fs2)) return null;
@@ -8479,8 +8686,8 @@ function worktreeAutoProvisionBanner(root, fs2 = realFsProbe) {
8479
8686
  return `[worktree] provisioning tooling in the background (deps in ${where} + local config) \u2014 \`mmi-cli worktree setup\` to redo`;
8480
8687
  }
8481
8688
  function defaultCopyFile(from, to) {
8482
- (0, import_node_fs12.mkdirSync)((0, import_node_path12.dirname)(to), { recursive: true });
8483
- (0, import_node_fs12.copyFileSync)(from, to);
8689
+ (0, import_node_fs13.mkdirSync)((0, import_node_path13.dirname)(to), { recursive: true });
8690
+ (0, import_node_fs13.copyFileSync)(from, to);
8484
8691
  }
8485
8692
  async function runDeclaredProvision(target, cwd, runInstall) {
8486
8693
  const previous = process.env[PROVISION_ENV_MARKER];
@@ -8510,7 +8717,7 @@ async function provisionWorktree(worktreeRoot, deps) {
8510
8717
  const targets = npmInstallTargets(allDirs);
8511
8718
  if (deps.validateInstall) {
8512
8719
  for (const dir of allDirs.filter((d) => d.hasPackageJson && (d.provision ?? d.install) && d.hasNodeModules)) {
8513
- const cwd = dir.dir ? (0, import_node_path12.join)(worktreeRoot, dir.dir) : worktreeRoot;
8720
+ const cwd = dir.dir ? (0, import_node_path13.join)(worktreeRoot, dir.dir) : worktreeRoot;
8514
8721
  if (!await deps.validateInstall(cwd)) {
8515
8722
  targets.push({
8516
8723
  dir: dir.dir,
@@ -8524,7 +8731,7 @@ async function provisionWorktree(worktreeRoot, deps) {
8524
8731
  const skippedInstall = allDirs.filter((d) => d.hasPackageJson && d.hasNodeModules && !targetDirs.has(d.dir)).map((d) => d.dir);
8525
8732
  const installed = [];
8526
8733
  for (const target of targets) {
8527
- const cwd = target.dir ? (0, import_node_path12.join)(worktreeRoot, target.dir) : worktreeRoot;
8734
+ const cwd = target.dir ? (0, import_node_path13.join)(worktreeRoot, target.dir) : worktreeRoot;
8528
8735
  log(`installing deps: ${target.command} in ${target.dir || "."}`);
8529
8736
  if (target.declared) await runDeclaredProvision(target, cwd, deps.runInstall);
8530
8737
  else await deps.runInstall(target.command, cwd);
@@ -8534,7 +8741,7 @@ async function provisionWorktree(worktreeRoot, deps) {
8534
8741
  const copySkipped = [];
8535
8742
  const primary = await deps.primaryCheckout();
8536
8743
  for (const rel of LOCAL_ONLY_FILES) {
8537
- const dest = (0, import_node_path12.join)(worktreeRoot, rel);
8744
+ const dest = (0, import_node_path13.join)(worktreeRoot, rel);
8538
8745
  if (fs2.isFile(dest)) {
8539
8746
  copySkipped.push({ file: rel, reason: "already-present" });
8540
8747
  continue;
@@ -8543,11 +8750,11 @@ async function provisionWorktree(worktreeRoot, deps) {
8543
8750
  copySkipped.push({ file: rel, reason: "no-primary" });
8544
8751
  continue;
8545
8752
  }
8546
- if (!fs2.isFile((0, import_node_path12.join)(primary, rel))) {
8753
+ if (!fs2.isFile((0, import_node_path13.join)(primary, rel))) {
8547
8754
  copySkipped.push({ file: rel, reason: "absent-in-primary" });
8548
8755
  continue;
8549
8756
  }
8550
- copyFile((0, import_node_path12.join)(primary, rel), dest);
8757
+ copyFile((0, import_node_path13.join)(primary, rel), dest);
8551
8758
  copied.push(rel);
8552
8759
  log(`copied local config: ${rel}`);
8553
8760
  }
@@ -8561,12 +8768,12 @@ function capWorktreeDirName(name, max = 40) {
8561
8768
  }
8562
8769
  function defaultWorktreePath(repoRoot2, branch) {
8563
8770
  const safe = capWorktreeDirName(branch.replace(/[/\\]+/g, "-"));
8564
- return (0, import_node_path12.join)((0, import_node_path12.dirname)(repoRoot2), "mmi-worktrees", (0, import_node_path12.basename)(repoRoot2), safe);
8771
+ return (0, import_node_path13.join)((0, import_node_path13.dirname)(repoRoot2), "mmi-worktrees", (0, import_node_path13.basename)(repoRoot2), safe);
8565
8772
  }
8566
8773
  async function primaryCheckoutRootOf(git2) {
8567
8774
  try {
8568
8775
  const out = (await git2(["rev-parse", "--path-format=absolute", "--git-common-dir"])).trim();
8569
- return out ? (0, import_node_path12.dirname)(out) : void 0;
8776
+ return out ? (0, import_node_path13.dirname)(out) : void 0;
8570
8777
  } catch {
8571
8778
  return void 0;
8572
8779
  }
@@ -8704,7 +8911,7 @@ function commandLadderHint() {
8704
8911
  }
8705
8912
 
8706
8913
  // src/index.ts
8707
- var import_node_path40 = require("node:path");
8914
+ var import_node_path41 = require("node:path");
8708
8915
 
8709
8916
  // src/merge-ci-policy.ts
8710
8917
  function resolveMergeCiPolicy(input) {
@@ -9364,13 +9571,13 @@ function planManagedGitignore(current) {
9364
9571
  }
9365
9572
 
9366
9573
  // src/docs-index-command.ts
9367
- var import_node_fs14 = require("node:fs");
9368
- var import_node_path14 = require("node:path");
9574
+ var import_node_fs15 = require("node:fs");
9575
+ var import_node_path15 = require("node:path");
9369
9576
 
9370
9577
  // src/doc-refs-core.ts
9371
9578
  var import_node_child_process5 = require("node:child_process");
9372
- var import_node_fs13 = require("node:fs");
9373
- var import_node_path13 = require("node:path");
9579
+ var import_node_fs14 = require("node:fs");
9580
+ var import_node_path14 = require("node:path");
9374
9581
  var PIN_RE = /<!--\s*pinned by\s+([^:]+?)\s*:\s*"([^"]+)"[^"]*-->/;
9375
9582
  var PIN_MENTION_RE = /<!--\s*pinned by\b/;
9376
9583
  var FWD_RE = /<!--\s*forward-ref:\s*(\S+?)\s*-->/;
@@ -9429,7 +9636,7 @@ function checkPins(root, readFile9, docs2) {
9429
9636
  findings.push({ kind: "malformed-pin", doc, line: pin.line, detail: pin.text });
9430
9637
  continue;
9431
9638
  }
9432
- const source = readFile9((0, import_node_path13.join)(root, pin.file));
9639
+ const source = readFile9((0, import_node_path14.join)(root, pin.file));
9433
9640
  if (source == null) {
9434
9641
  findings.push({ kind: "missing-test", doc, line: pin.line, detail: pin.file });
9435
9642
  continue;
@@ -9491,11 +9698,11 @@ function checkRefs(root, deps, docs2) {
9491
9698
  for (const { ref } of extractRefs(markdown)) allFirstSegments.add(refFirstSegment(ref));
9492
9699
  }
9493
9700
  const tracked = allFirstSegments.size ? deps.trackedFirstSegments?.([...allFirstSegments]) ?? null : null;
9494
- const firstVerifiable = (first) => tracked ? tracked.has(first) : exists((0, import_node_path13.join)(root, first));
9701
+ const firstVerifiable = (first) => tracked ? tracked.has(first) : exists((0, import_node_path14.join)(root, first));
9495
9702
  const candidates = [];
9496
9703
  const direct = [];
9497
9704
  for (const [doc, markdown] of Object.entries(docs2)) {
9498
- const docDir = import_node_path13.posix.dirname(doc);
9705
+ const docDir = import_node_path14.posix.dirname(doc);
9499
9706
  const base = docDir === "." ? "" : docDir;
9500
9707
  const covered = /* @__PURE__ */ new Set();
9501
9708
  const markers = [];
@@ -9504,21 +9711,21 @@ function checkRefs(root, deps, docs2) {
9504
9711
  direct.push({ kind: "malformed-forward-ref", doc, line: fwd.line, detail: fwd.text });
9505
9712
  continue;
9506
9713
  }
9507
- const docRel = import_node_path13.posix.normalize(import_node_path13.posix.join(base, fwd.target));
9508
- const rootRel = import_node_path13.posix.normalize(fwd.target.replace(/^\/+/, ""));
9714
+ const docRel = import_node_path14.posix.normalize(import_node_path14.posix.join(base, fwd.target));
9715
+ const rootRel = import_node_path14.posix.normalize(fwd.target.replace(/^\/+/, ""));
9509
9716
  markers.push({ target: fwd.target, line: fwd.line, docRel, rootRel });
9510
9717
  covered.add(docRel);
9511
9718
  covered.add(rootRel);
9512
9719
  }
9513
9720
  const links = extractLinks(markdown).map(({ target, line }) => {
9514
- const resolved = import_node_path13.posix.normalize(import_node_path13.posix.join(base, target));
9515
- return { target, line, resolved, missing: !exists((0, import_node_path13.join)(root, resolved)) };
9721
+ const resolved = import_node_path14.posix.normalize(import_node_path14.posix.join(base, target));
9722
+ return { target, line, resolved, missing: !exists((0, import_node_path14.join)(root, resolved)) };
9516
9723
  });
9517
9724
  for (const marker of markers) {
9518
9725
  const coversMissing = links.some(
9519
9726
  (l) => l.missing && (l.resolved === marker.docRel || l.resolved === marker.rootRel)
9520
9727
  );
9521
- if (!coversMissing && (exists((0, import_node_path13.join)(root, marker.docRel)) || exists((0, import_node_path13.join)(root, marker.rootRel)))) {
9728
+ if (!coversMissing && (exists((0, import_node_path14.join)(root, marker.docRel)) || exists((0, import_node_path14.join)(root, marker.rootRel)))) {
9522
9729
  direct.push({
9523
9730
  kind: "stale-forward-ref",
9524
9731
  doc,
@@ -9529,7 +9736,7 @@ function checkRefs(root, deps, docs2) {
9529
9736
  }
9530
9737
  for (const { ref, line } of extractRefs(markdown)) {
9531
9738
  if (!firstVerifiable(refFirstSegment(ref))) continue;
9532
- if (!exists((0, import_node_path13.join)(root, ref))) candidates.push({ kind: "missing-path", doc, line, detail: ref });
9739
+ if (!exists((0, import_node_path14.join)(root, ref))) candidates.push({ kind: "missing-path", doc, line, detail: ref });
9533
9740
  }
9534
9741
  for (const { target, line, resolved, missing } of links) {
9535
9742
  if (resolved.startsWith("..")) {
@@ -9577,22 +9784,22 @@ function checkCommands(docs2, commandPaths) {
9577
9784
  return { ok: findings.length === 0, findings, warnings: [] };
9578
9785
  }
9579
9786
  function readFileOrNull(path2) {
9580
- return (0, import_node_fs13.existsSync)(path2) ? (0, import_node_fs13.readFileSync)(path2, "utf8") : null;
9787
+ return (0, import_node_fs14.existsSync)(path2) ? (0, import_node_fs14.readFileSync)(path2, "utf8") : null;
9581
9788
  }
9582
9789
  function walk(dir, root, out) {
9583
- for (const entry of (0, import_node_fs13.readdirSync)(dir)) {
9584
- const full = (0, import_node_path13.join)(dir, entry);
9585
- if ((0, import_node_fs13.statSync)(full).isDirectory()) walk(full, root, out);
9790
+ for (const entry of (0, import_node_fs14.readdirSync)(dir)) {
9791
+ const full = (0, import_node_path14.join)(dir, entry);
9792
+ if ((0, import_node_fs14.statSync)(full).isDirectory()) walk(full, root, out);
9586
9793
  else if (entry.endsWith(".md")) out.push(full.slice(root.length + 1).replaceAll("\\", "/"));
9587
9794
  }
9588
9795
  return out;
9589
9796
  }
9590
9797
  function defaultListDocs(root) {
9591
- const docsDir = (0, import_node_path13.join)(root, "docs");
9592
- const docs2 = ((0, import_node_fs13.existsSync)(docsDir) ? walk(docsDir, root, []) : []).filter(
9798
+ const docsDir = (0, import_node_path14.join)(root, "docs");
9799
+ const docs2 = ((0, import_node_fs14.existsSync)(docsDir) ? walk(docsDir, root, []) : []).filter(
9593
9800
  (rel) => !SKIP_WALK.some((skip) => rel.startsWith(skip))
9594
9801
  );
9595
- return [...ROOT_DOCS.filter((rel) => (0, import_node_fs13.existsSync)((0, import_node_path13.join)(root, rel))), ...docs2];
9802
+ return [...ROOT_DOCS.filter((rel) => (0, import_node_fs14.existsSync)((0, import_node_path14.join)(root, rel))), ...docs2];
9596
9803
  }
9597
9804
  var CHECK_IGNORE_MAX_BUFFER = 32 * 1024 * 1024;
9598
9805
  function defaultIsIgnored(root, relPaths, exec = import_node_child_process5.execFileSync) {
@@ -9644,7 +9851,7 @@ function defaultTrackedFirstSegments(root, firstSegments, exec = import_node_chi
9644
9851
  }
9645
9852
  function runDocRefs(root, deps = {}) {
9646
9853
  const readFile9 = deps.readFile ?? readFileOrNull;
9647
- const exists = deps.exists ?? import_node_fs13.existsSync;
9854
+ const exists = deps.exists ?? import_node_fs14.existsSync;
9648
9855
  const listDocs = deps.listDocs ?? defaultListDocs;
9649
9856
  const isIgnored = deps.isIgnored ?? ((paths) => defaultIsIgnored(root, paths));
9650
9857
  const trackedFirstSegments = deps.trackedFirstSegments ?? ((segs) => defaultTrackedFirstSegments(root, segs));
@@ -9652,7 +9859,7 @@ function runDocRefs(root, deps = {}) {
9652
9859
  const walked = listDocs(root);
9653
9860
  const ignoredDocs = walked.length ? isIgnored(walked) : /* @__PURE__ */ new Set();
9654
9861
  const docs2 = Object.fromEntries(
9655
- walked.filter((rel) => !ignoredDocs.has(rel)).map((rel) => [rel, readFile9((0, import_node_path13.join)(root, rel))]).filter(([, body]) => body != null)
9862
+ walked.filter((rel) => !ignoredDocs.has(rel)).map((rel) => [rel, readFile9((0, import_node_path14.join)(root, rel))]).filter(([, body]) => body != null)
9656
9863
  );
9657
9864
  const refResult = checkRefs(root, { exists, isIgnored, trackedFirstSegments }, docs2);
9658
9865
  const findings = [
@@ -9759,31 +9966,31 @@ function walkMarkdown(dir) {
9759
9966
  const stack = [dir];
9760
9967
  while (stack.length) {
9761
9968
  const current = stack.pop();
9762
- for (const entry of (0, import_node_fs14.readdirSync)(current, { withFileTypes: true })) {
9763
- const full = (0, import_node_path14.join)(current, entry.name);
9969
+ for (const entry of (0, import_node_fs15.readdirSync)(current, { withFileTypes: true })) {
9970
+ const full = (0, import_node_path15.join)(current, entry.name);
9764
9971
  if (entry.isDirectory()) {
9765
9972
  stack.push(full);
9766
9973
  } else if (entry.isFile() && entry.name.endsWith(".md")) {
9767
- out.push((0, import_node_path14.relative)(dir, full).split(import_node_path14.sep).join("/"));
9974
+ out.push((0, import_node_path15.relative)(dir, full).split(import_node_path15.sep).join("/"));
9768
9975
  }
9769
9976
  }
9770
9977
  }
9771
9978
  return out;
9772
9979
  }
9773
9980
  function createDocsIndexDeps(repoRoot2) {
9774
- const docsDir = (0, import_node_path14.join)(repoRoot2, "docs");
9775
- const indexPath = (0, import_node_path14.join)(repoRoot2, DOCS_INDEX_PATH);
9981
+ const docsDir = (0, import_node_path15.join)(repoRoot2, "docs");
9982
+ const indexPath = (0, import_node_path15.join)(repoRoot2, DOCS_INDEX_PATH);
9776
9983
  return {
9777
9984
  listDocs: () => {
9778
- if (!(0, import_node_fs14.existsSync)(docsDir)) return [];
9985
+ if (!(0, import_node_fs15.existsSync)(docsDir)) return [];
9779
9986
  const walked = walkMarkdown(docsDir).filter(isRoutableDocsPath);
9780
9987
  if (!walked.length) return [];
9781
9988
  const ignored = defaultIsIgnored(repoRoot2, walked.map((rel) => `docs/${rel}`));
9782
9989
  return walked.filter((rel) => !ignored.has(`docs/${rel}`)).sort();
9783
9990
  },
9784
- readDoc: (relPath) => (0, import_node_fs14.readFileSync)((0, import_node_path14.join)(docsDir, relPath), "utf8"),
9785
- readIndex: () => (0, import_node_fs14.existsSync)(indexPath) ? (0, import_node_fs14.readFileSync)(indexPath, "utf8") : null,
9786
- writeIndex: (content) => (0, import_node_fs14.writeFileSync)(indexPath, content, "utf8")
9991
+ readDoc: (relPath) => (0, import_node_fs15.readFileSync)((0, import_node_path15.join)(docsDir, relPath), "utf8"),
9992
+ readIndex: () => (0, import_node_fs15.existsSync)(indexPath) ? (0, import_node_fs15.readFileSync)(indexPath, "utf8") : null,
9993
+ writeIndex: (content) => (0, import_node_fs15.writeFileSync)(indexPath, content, "utf8")
9787
9994
  };
9788
9995
  }
9789
9996
 
@@ -10430,15 +10637,15 @@ function parseVerifyBroker(stdout) {
10430
10637
  }
10431
10638
 
10432
10639
  // src/train-apply.ts
10433
- var import_node_fs16 = require("node:fs");
10640
+ var import_node_fs17 = require("node:fs");
10434
10641
  var import_promises3 = require("node:fs/promises");
10435
- var import_node_path16 = require("node:path");
10642
+ var import_node_path17 = require("node:path");
10436
10643
 
10437
10644
  // src/plugin-guard-io.ts
10438
- var import_node_fs15 = require("node:fs");
10645
+ var import_node_fs16 = require("node:fs");
10439
10646
  var import_node_child_process6 = require("node:child_process");
10440
- var import_node_path15 = require("node:path");
10441
- var import_node_os4 = require("node:os");
10647
+ var import_node_path16 = require("node:path");
10648
+ var import_node_os5 = require("node:os");
10442
10649
  var import_proper_lockfile = __toESM(require_proper_lockfile(), 1);
10443
10650
 
10444
10651
  // src/version-lag.ts
@@ -10727,20 +10934,20 @@ function runHostBin(bin, args, opts) {
10727
10934
  const argv = isWin ? ["/c", bin, ...args] : args;
10728
10935
  return step ? execFileHard(file, argv, { ...shared, step }) : execFileP2(file, argv, shared);
10729
10936
  }
10730
- function surfaceConfigRoot(surface, env = process.env, home = (0, import_node_os4.homedir)()) {
10731
- if (surface === "codex") return env.CODEX_HOME?.trim() || (0, import_node_path15.join)(home, ".codex");
10732
- if (surface === "kimi") return env.KIMI_CODE_HOME?.trim() || (0, import_node_path15.join)(home, ".kimi-code");
10733
- if (surface === "kilo") return env.KILO_CONFIG_DIR?.trim() || (0, import_node_path15.join)(home, ".config", "kilo");
10734
- if (surface === "cursor") return (0, import_node_path15.join)(home, ".cursor");
10735
- if (surface === "jervcode") return env.PI_CODING_AGENT_DIR?.trim() || (0, import_node_path15.join)(home, ".pi", "agent");
10736
- return (0, import_node_path15.join)(home, ".claude");
10937
+ function surfaceConfigRoot(surface, env = process.env, home = (0, import_node_os5.homedir)()) {
10938
+ if (surface === "codex") return env.CODEX_HOME?.trim() || (0, import_node_path16.join)(home, ".codex");
10939
+ if (surface === "kimi") return env.KIMI_CODE_HOME?.trim() || (0, import_node_path16.join)(home, ".kimi-code");
10940
+ if (surface === "kilo") return env.KILO_CONFIG_DIR?.trim() || (0, import_node_path16.join)(home, ".config", "kilo");
10941
+ if (surface === "cursor") return (0, import_node_path16.join)(home, ".cursor");
10942
+ if (surface === "jervcode") return env.PI_CODING_AGENT_DIR?.trim() || (0, import_node_path16.join)(home, ".pi", "agent");
10943
+ return (0, import_node_path16.join)(home, ".claude");
10737
10944
  }
10738
10945
  var installedPluginsPath = (surface = detectSurface(process.env)) => {
10739
- return (0, import_node_path15.join)(surfaceConfigRoot(surface), "plugins", "installed_plugins.json");
10946
+ return (0, import_node_path16.join)(surfaceConfigRoot(surface), "plugins", "installed_plugins.json");
10740
10947
  };
10741
10948
  function readInstalledPlugins(surface = detectSurface(process.env)) {
10742
10949
  try {
10743
- return JSON.parse((0, import_node_fs15.readFileSync)(installedPluginsPath(surface), "utf8"));
10950
+ return JSON.parse((0, import_node_fs16.readFileSync)(installedPluginsPath(surface), "utf8"));
10744
10951
  } catch {
10745
10952
  return null;
10746
10953
  }
@@ -10749,17 +10956,17 @@ function marketplaceCloneCandidates(surface, home, env = process.env) {
10749
10956
  if (surface === "codex") {
10750
10957
  const root = surfaceConfigRoot(surface, env, home);
10751
10958
  return [
10752
- (0, import_node_path15.join)(root, ".tmp", "marketplaces", CODEX_MARKETPLACE),
10753
- (0, import_node_path15.join)(root, "plugins", "marketplaces", CODEX_MARKETPLACE)
10959
+ (0, import_node_path16.join)(root, ".tmp", "marketplaces", CODEX_MARKETPLACE),
10960
+ (0, import_node_path16.join)(root, "plugins", "marketplaces", CODEX_MARKETPLACE)
10754
10961
  ];
10755
10962
  }
10756
10963
  if (surface === "kimi") return [];
10757
10964
  if (surface === "kilo") return [];
10758
10965
  if (surface === "cursor") return [];
10759
10966
  if (surface === "jervcode") return [];
10760
- return [(0, import_node_path15.join)(home, ".claude", "plugins", "marketplaces", "mutmutco")];
10967
+ return [(0, import_node_path16.join)(home, ".claude", "plugins", "marketplaces", "mutmutco")];
10761
10968
  }
10762
- function marketplaceClonePresent(surface, home, exists = import_node_fs15.existsSync, env = process.env) {
10969
+ function marketplaceClonePresent(surface, home, exists = import_node_fs16.existsSync, env = process.env) {
10763
10970
  return marketplaceCloneCandidates(surface, home, env).some(exists);
10764
10971
  }
10765
10972
  function runHostBinSync(bin, args) {
@@ -10791,7 +10998,7 @@ function codexPluginStatus() {
10791
10998
  }
10792
10999
  function countCodexHookCommands(path2) {
10793
11000
  try {
10794
- const parsed = JSON.parse((0, import_node_fs15.readFileSync)(path2, "utf8"));
11001
+ const parsed = JSON.parse((0, import_node_fs16.readFileSync)(path2, "utf8"));
10795
11002
  let count = 0;
10796
11003
  for (const groups of Object.values(parsed.hooks ?? {})) {
10797
11004
  for (const group of groups) {
@@ -10808,11 +11015,11 @@ function codexHookTrustState(status = codexPluginStatus()) {
10808
11015
  return { applicable: false, trusted: false, trustedCount: 0, requiredCount: 0 };
10809
11016
  }
10810
11017
  const root = surfaceConfigRoot("codex");
10811
- const hooksPath = (0, import_node_path15.join)(root, "plugins", "cache", CODEX_MARKETPLACE, "mmi", status.version, "hooks", "codex-hooks.json");
11018
+ const hooksPath = (0, import_node_path16.join)(root, "plugins", "cache", CODEX_MARKETPLACE, "mmi", status.version, "hooks", "codex-hooks.json");
10812
11019
  const requiredCount = countCodexHookCommands(hooksPath);
10813
11020
  let config = "";
10814
11021
  try {
10815
- config = (0, import_node_fs15.readFileSync)((0, import_node_path15.join)(root, "config.toml"), "utf8");
11022
+ config = (0, import_node_fs16.readFileSync)((0, import_node_path16.join)(root, "config.toml"), "utf8");
10816
11023
  } catch {
10817
11024
  return { applicable: true, trusted: false, trustedCount: 0, requiredCount };
10818
11025
  }
@@ -10846,11 +11053,11 @@ async function npmSelfUpdateCli(target, onStep) {
10846
11053
  return { ok: false, detail: e.message.trim().slice(0, 200).replace(/\s+/g, " ") };
10847
11054
  }
10848
11055
  }
10849
- function kiloConfigListsPlugin(configRoot, home = (0, import_node_os4.homedir)(), read = (p) => (0, import_node_fs15.readFileSync)(p, "utf8"), exists = import_node_fs15.existsSync) {
11056
+ function kiloConfigListsPlugin(configRoot, home = (0, import_node_os5.homedir)(), read = (p) => (0, import_node_fs16.readFileSync)(p, "utf8"), exists = import_node_fs16.existsSync) {
10850
11057
  const candidates = ["kilo.json", "kilo.jsonc", "opencode.json", "opencode.jsonc", "config.json"];
10851
- for (const dir of [configRoot, (0, import_node_path15.join)(home, ".kilo")]) {
11058
+ for (const dir of [configRoot, (0, import_node_path16.join)(home, ".kilo")]) {
10852
11059
  for (const file of candidates) {
10853
- const path2 = (0, import_node_path15.join)(dir, file);
11060
+ const path2 = (0, import_node_path16.join)(dir, file);
10854
11061
  if (!exists(path2)) continue;
10855
11062
  try {
10856
11063
  const stripped = read(path2).replace(/\/\*[\s\S]*?\*\//g, "").replace(/\/\/.*$/gm, "");
@@ -10866,24 +11073,24 @@ function kiloConfigListsPlugin(configRoot, home = (0, import_node_os4.homedir)()
10866
11073
  }
10867
11074
  return false;
10868
11075
  }
10869
- function cursorLocalPluginRoot(env = process.env, home = (0, import_node_os4.homedir)()) {
10870
- return (0, import_node_path15.join)(surfaceConfigRoot("cursor", env, home), "plugins", "local", "mmi");
11076
+ function cursorLocalPluginRoot(env = process.env, home = (0, import_node_os5.homedir)()) {
11077
+ return (0, import_node_path16.join)(surfaceConfigRoot("cursor", env, home), "plugins", "local", "mmi");
10871
11078
  }
10872
- function cursorPluginTreeHealthy(root, exists = import_node_fs15.existsSync) {
11079
+ function cursorPluginTreeHealthy(root, exists = import_node_fs16.existsSync) {
10873
11080
  return [
10874
11081
  ".cursor-plugin/plugin.json",
10875
11082
  "skills/mmi/SKILL.md",
10876
11083
  "hooks/cursor-hooks.json",
10877
11084
  "scripts/hook-run.mjs",
10878
11085
  "scripts/hook-policy.mjs"
10879
- ].every((path2) => exists((0, import_node_path15.join)(root, ...path2.split("/"))));
11086
+ ].every((path2) => exists((0, import_node_path16.join)(root, ...path2.split("/"))));
10880
11087
  }
10881
- function kimiPluginTreeHealthy(root, exists = import_node_fs15.existsSync) {
11088
+ function kimiPluginTreeHealthy(root, exists = import_node_fs16.existsSync) {
10882
11089
  return [
10883
11090
  ".kimi-plugin/plugin.json",
10884
11091
  "skills/mmi/SKILL.md",
10885
11092
  "scripts/hook-run.mjs"
10886
- ].every((path2) => exists((0, import_node_path15.join)(root, ...path2.split("/"))));
11093
+ ].every((path2) => exists((0, import_node_path16.join)(root, ...path2.split("/"))));
10887
11094
  }
10888
11095
  var JERVCODE_WRAPPER_DIR = ".pi-plugin";
10889
11096
  function normalizePiEntry(value) {
@@ -10906,7 +11113,7 @@ function jervcodePackageFamily(entry) {
10906
11113
  function isMmiOwnedPiEntry(entry) {
10907
11114
  if (typeof entry !== "string") return false;
10908
11115
  try {
10909
- const pkg = JSON.parse((0, import_node_fs15.readFileSync)((0, import_node_path15.join)(piEntryFsPath(entry), "package.json"), "utf8"));
11116
+ const pkg = JSON.parse((0, import_node_fs16.readFileSync)((0, import_node_path16.join)(piEntryFsPath(entry), "package.json"), "utf8"));
10910
11117
  return pkg.name === "mmi";
10911
11118
  } catch {
10912
11119
  return false;
@@ -10928,17 +11135,17 @@ function mergeMmiPiPackageEntries(entries, packagePath) {
10928
11135
  };
10929
11136
  }
10930
11137
  function readPiSettings(path2) {
10931
- if (!(0, import_node_fs15.existsSync)(path2)) return void 0;
11138
+ if (!(0, import_node_fs16.existsSync)(path2)) return void 0;
10932
11139
  try {
10933
- const parsed = JSON.parse((0, import_node_fs15.readFileSync)(path2, "utf8"));
11140
+ const parsed = JSON.parse((0, import_node_fs16.readFileSync)(path2, "utf8"));
10934
11141
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return null;
10935
11142
  return parsed;
10936
11143
  } catch {
10937
11144
  return null;
10938
11145
  }
10939
11146
  }
10940
- function mmiPiWrapperEntry(env = process.env, home = (0, import_node_os4.homedir)()) {
10941
- const settings = readPiSettings((0, import_node_path15.join)(surfaceConfigRoot("jervcode", env, home), "settings.json"));
11147
+ function mmiPiWrapperEntry(env = process.env, home = (0, import_node_os5.homedir)()) {
11148
+ const settings = readPiSettings((0, import_node_path16.join)(surfaceConfigRoot("jervcode", env, home), "settings.json"));
10942
11149
  const entries = Array.isArray(settings?.packages) ? settings.packages : [];
10943
11150
  for (const entry of entries) {
10944
11151
  if (typeof entry !== "string") continue;
@@ -10951,17 +11158,17 @@ function mmiPiWrapperEntry(env = process.env, home = (0, import_node_os4.homedir
10951
11158
  function mmiPiWrapperHealthy(entry) {
10952
11159
  if (!entry) return false;
10953
11160
  const wrapper = piEntryFsPath(entry);
10954
- return isMmiOwnedPiEntry(entry) && (0, import_node_fs15.existsSync)((0, import_node_path15.join)((0, import_node_path15.dirname)(wrapper), "skills", "mmi", "SKILL.md"));
11161
+ return isMmiOwnedPiEntry(entry) && (0, import_node_fs16.existsSync)((0, import_node_path16.join)((0, import_node_path16.dirname)(wrapper), "skills", "mmi", "SKILL.md"));
10955
11162
  }
10956
- function findMmiPiSourceClone(home = (0, import_node_os4.homedir)()) {
10957
- const cacheRoot = (0, import_node_path15.join)(home, ".claude", "plugins", "cache", "mutmutco", "mmi");
11163
+ function findMmiPiSourceClone(home = (0, import_node_os5.homedir)()) {
11164
+ const cacheRoot = (0, import_node_path16.join)(home, ".claude", "plugins", "cache", "mutmutco", "mmi");
10958
11165
  let best = null;
10959
11166
  try {
10960
- for (const entry of (0, import_node_fs15.readdirSync)(cacheRoot, { withFileTypes: true })) {
11167
+ for (const entry of (0, import_node_fs16.readdirSync)(cacheRoot, { withFileTypes: true })) {
10961
11168
  if (!entry.isDirectory() || !/^\d+\.\d+\.\d+$/.test(entry.name)) continue;
10962
- if (!(0, import_node_fs15.existsSync)((0, import_node_path15.join)(cacheRoot, entry.name, JERVCODE_WRAPPER_DIR, "package.json"))) continue;
11169
+ if (!(0, import_node_fs16.existsSync)((0, import_node_path16.join)(cacheRoot, entry.name, JERVCODE_WRAPPER_DIR, "package.json"))) continue;
10963
11170
  if (!best || compareVersions(entry.name, best.version) > 0) {
10964
- best = { path: (0, import_node_path15.join)(cacheRoot, entry.name), version: entry.name };
11171
+ best = { path: (0, import_node_path16.join)(cacheRoot, entry.name), version: entry.name };
10965
11172
  }
10966
11173
  }
10967
11174
  } catch {
@@ -10989,9 +11196,9 @@ function healJervCodePackageRegistration(opts = {}) {
10989
11196
  const env = opts.env ?? process.env;
10990
11197
  const inSeat = !!env.PI_SESSION_ID?.trim();
10991
11198
  const nextLaunch = inSeat ? " \u2014 takes effect on the next seat launch" : "";
10992
- const home = opts.home ?? (0, import_node_os4.homedir)();
11199
+ const home = opts.home ?? (0, import_node_os5.homedir)();
10993
11200
  const agentDir = surfaceConfigRoot("jervcode", env, home);
10994
- if (!(0, import_node_fs15.existsSync)(agentDir)) {
11201
+ if (!(0, import_node_fs16.existsSync)(agentDir)) {
10995
11202
  return { available: false, ok: true, changed: false, version: null, detail: "skipped \u2014 no Pi/JervCode install (no agent config dir)" };
10996
11203
  }
10997
11204
  const clone = opts.clone === void 0 ? findMmiPiSourceClone(home) : opts.clone;
@@ -10999,9 +11206,9 @@ function healJervCodePackageRegistration(opts = {}) {
10999
11206
  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)" };
11000
11207
  }
11001
11208
  const packagePath = `${clone.path.replace(/\\/g, "/").replace(/\/+$/, "")}/${JERVCODE_WRAPPER_DIR}`;
11002
- const settingsPath2 = (0, import_node_path15.join)(agentDir, "settings.json");
11003
- const release = (0, import_node_fs15.existsSync)(settingsPath2) ? acquirePiSettingsLock(settingsPath2) : void 0;
11004
- if ((0, import_node_fs15.existsSync)(settingsPath2) && !release) {
11209
+ const settingsPath2 = (0, import_node_path16.join)(agentDir, "settings.json");
11210
+ const release = (0, import_node_fs16.existsSync)(settingsPath2) ? acquirePiSettingsLock(settingsPath2) : void 0;
11211
+ if ((0, import_node_fs16.existsSync)(settingsPath2) && !release) {
11005
11212
  return {
11006
11213
  available: true,
11007
11214
  ok: false,
@@ -11029,14 +11236,14 @@ function healJervCodePackageRegistration(opts = {}) {
11029
11236
  }
11030
11237
  current.packages = merged.next;
11031
11238
  try {
11032
- (0, import_node_fs15.mkdirSync)((0, import_node_path15.dirname)(settingsPath2), { recursive: true });
11239
+ (0, import_node_fs16.mkdirSync)((0, import_node_path16.dirname)(settingsPath2), { recursive: true });
11033
11240
  const tmp = `${settingsPath2}.tmp-${process.pid}`;
11034
- (0, import_node_fs15.writeFileSync)(tmp, `${JSON.stringify(current, null, 2)}
11241
+ (0, import_node_fs16.writeFileSync)(tmp, `${JSON.stringify(current, null, 2)}
11035
11242
  `, "utf8");
11036
11243
  try {
11037
- (0, import_node_fs15.renameSync)(tmp, settingsPath2);
11244
+ (0, import_node_fs16.renameSync)(tmp, settingsPath2);
11038
11245
  } catch (renameError) {
11039
- (0, import_node_fs15.rmSync)(tmp, { force: true });
11246
+ (0, import_node_fs16.rmSync)(tmp, { force: true });
11040
11247
  throw renameError;
11041
11248
  }
11042
11249
  } catch (error) {
@@ -11062,18 +11269,18 @@ function snapshotPluginGuardInput(surface = detectSurface(process.env), isOrgRep
11062
11269
  return {
11063
11270
  isOrgRepo,
11064
11271
  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.
11065
- surface === "kimi" && (0, import_node_fs15.existsSync)((0, import_node_path15.join)(root, "plugins", "managed", "mmi")) || // kilo-p1: the install record is the config file itself.
11272
+ surface === "kimi" && (0, import_node_fs16.existsSync)((0, import_node_path16.join)(root, "plugins", "managed", "mmi")) || // kilo-p1: the install record is the config file itself.
11066
11273
  surface === "kilo" && kiloConfigListsPlugin(root) || // #4188: jervcode's install record is the settings-file packages[] entry itself.
11067
- surface === "jervcode" && piEntry !== null || surface === "cursor" && (0, import_node_fs15.existsSync)(cursorLocalPluginRoot()),
11274
+ surface === "jervcode" && piEntry !== null || surface === "cursor" && (0, import_node_fs16.existsSync)(cursorLocalPluginRoot()),
11068
11275
  // Kilo has no marketplace to clone — the config file IS the install record, so this dimension of
11069
11276
  // the shared guard table is vacuously satisfied. Same for jervcode's settings entry.
11070
- marketplaceClonePresent: surface === "kimi" || surface === "kilo" || surface === "cursor" || surface === "jervcode" ? true : marketplaceClonePresent(surface, (0, import_node_os4.homedir)()),
11277
+ marketplaceClonePresent: surface === "kimi" || surface === "kilo" || surface === "cursor" || surface === "jervcode" ? true : marketplaceClonePresent(surface, (0, import_node_os5.homedir)()),
11071
11278
  // Kimi keeps no plugin cache dir — installs are copied to plugins/managed/<id> and run from there.
11072
11279
  // Kilo (kilo-p1) keeps no cache dir either: the plugin's server() provisions ~/.kilo behind the
11073
11280
  // version stamp, so the stamp's presence is the cache signal.
11074
- pluginCachePresent: surface === "jervcode" ? mmiPiWrapperHealthy(piEntry) : surface === "kilo" ? (0, import_node_fs15.existsSync)((0, import_node_path15.join)((0, import_node_os4.homedir)(), ".kilo", ".mmi-kilo-version")) : surface === "kimi" ? kimiPluginTreeHealthy((0, import_node_path15.join)(root, "plugins", "managed", "mmi")) : surface === "cursor" ? cursorPluginTreeHealthy(cursorLocalPluginRoot()) : surface === "codex" ? Boolean(
11075
- codexStatus?.installed && codexStatus.enabled && codexStatus.version && (0, import_node_fs15.existsSync)((0, import_node_path15.join)(root, "plugins", "cache", CODEX_MARKETPLACE, "mmi", codexStatus.version))
11076
- ) : (0, import_node_fs15.existsSync)((0, import_node_path15.join)(root, "plugins", "cache", "mutmutco", "mmi"))
11281
+ pluginCachePresent: surface === "jervcode" ? mmiPiWrapperHealthy(piEntry) : surface === "kilo" ? (0, import_node_fs16.existsSync)((0, import_node_path16.join)((0, import_node_os5.homedir)(), ".kilo", ".mmi-kilo-version")) : surface === "kimi" ? kimiPluginTreeHealthy((0, import_node_path16.join)(root, "plugins", "managed", "mmi")) : surface === "cursor" ? cursorPluginTreeHealthy(cursorLocalPluginRoot()) : surface === "codex" ? Boolean(
11282
+ codexStatus?.installed && codexStatus.enabled && codexStatus.version && (0, import_node_fs16.existsSync)((0, import_node_path16.join)(root, "plugins", "cache", CODEX_MARKETPLACE, "mmi", codexStatus.version))
11283
+ ) : (0, import_node_fs16.existsSync)((0, import_node_path16.join)(root, "plugins", "cache", "mutmutco", "mmi"))
11077
11284
  };
11078
11285
  }
11079
11286
  async function runHostBinLogged(bin, args, opts) {
@@ -11093,11 +11300,11 @@ async function runPluginCli(bin, args, log) {
11093
11300
  function captureCodexHookLauncher() {
11094
11301
  const status = codexPluginStatus();
11095
11302
  if (!status.installed || !status.enabled || !status.version) return void 0;
11096
- const root = (0, import_node_path15.join)(surfaceConfigRoot("codex"), "plugins", "cache", CODEX_MARKETPLACE, "mmi", status.version);
11303
+ const root = (0, import_node_path16.join)(surfaceConfigRoot("codex"), "plugins", "cache", CODEX_MARKETPLACE, "mmi", status.version);
11097
11304
  const files = ["mmi-hook", "mmi-hook.exe"].flatMap((name) => {
11098
- const path2 = (0, import_node_path15.join)(root, "bin", name);
11305
+ const path2 = (0, import_node_path16.join)(root, "bin", name);
11099
11306
  try {
11100
- return [{ name, content: (0, import_node_fs15.readFileSync)(path2) }];
11307
+ return [{ name, content: (0, import_node_fs16.readFileSync)(path2) }];
11101
11308
  } catch {
11102
11309
  return [];
11103
11310
  }
@@ -11105,13 +11312,13 @@ function captureCodexHookLauncher() {
11105
11312
  return files.length === 2 ? { root, files } : void 0;
11106
11313
  }
11107
11314
  function restoreCodexHookLauncher(snapshot) {
11108
- if (!snapshot || (0, import_node_fs15.existsSync)((0, import_node_path15.join)(snapshot.root, "scripts", "hook-run.mjs"))) return false;
11109
- const bin = (0, import_node_path15.join)(snapshot.root, "bin");
11110
- (0, import_node_fs15.mkdirSync)(bin, { recursive: true });
11315
+ if (!snapshot || (0, import_node_fs16.existsSync)((0, import_node_path16.join)(snapshot.root, "scripts", "hook-run.mjs"))) return false;
11316
+ const bin = (0, import_node_path16.join)(snapshot.root, "bin");
11317
+ (0, import_node_fs16.mkdirSync)(bin, { recursive: true });
11111
11318
  for (const file of snapshot.files) {
11112
- const path2 = (0, import_node_path15.join)(bin, file.name);
11113
- (0, import_node_fs15.writeFileSync)(path2, file.content);
11114
- if (file.name === "mmi-hook") (0, import_node_fs15.chmodSync)(path2, 493);
11319
+ const path2 = (0, import_node_path16.join)(bin, file.name);
11320
+ (0, import_node_fs16.writeFileSync)(path2, file.content);
11321
+ if (file.name === "mmi-hook") (0, import_node_fs16.chmodSync)(path2, 493);
11115
11322
  }
11116
11323
  return true;
11117
11324
  }
@@ -11120,10 +11327,10 @@ function canonicalCursorRemote(remote) {
11120
11327
  }
11121
11328
  async function installCursorPluginCheckout(env = process.env) {
11122
11329
  const configRoot = surfaceConfigRoot("cursor", env);
11123
- const pluginsRoot = (0, import_node_path15.join)(configRoot, "plugins");
11124
- const target = (0, import_node_path15.join)(pluginsRoot, "local", "mmi");
11330
+ const pluginsRoot = (0, import_node_path16.join)(configRoot, "plugins");
11331
+ const target = (0, import_node_path16.join)(pluginsRoot, "local", "mmi");
11125
11332
  const source = env.MMI_CURSOR_PLUGIN_SOURCE?.trim();
11126
- if ((0, import_node_fs15.existsSync)(target) && !source) {
11333
+ if ((0, import_node_fs16.existsSync)(target) && !source) {
11127
11334
  try {
11128
11335
  const { stdout } = await runHostBin("git", ["-C", target, "remote", "get-url", "origin"], { timeout: 15e3 });
11129
11336
  if (!canonicalCursorRemote(stdout)) {
@@ -11133,15 +11340,15 @@ async function installCursorPluginCheckout(env = process.env) {
11133
11340
  return { ok: false, detail: `refused to replace unmanaged Cursor plugin directory at ${target}` };
11134
11341
  }
11135
11342
  }
11136
- (0, import_node_fs15.mkdirSync)((0, import_node_path15.join)(pluginsRoot, "local"), { recursive: true });
11137
- (0, import_node_fs15.mkdirSync)((0, import_node_path15.join)(pluginsRoot, "staging"), { recursive: true });
11138
- (0, import_node_fs15.mkdirSync)((0, import_node_path15.join)(pluginsRoot, "quarantine"), { recursive: true });
11343
+ (0, import_node_fs16.mkdirSync)((0, import_node_path16.join)(pluginsRoot, "local"), { recursive: true });
11344
+ (0, import_node_fs16.mkdirSync)((0, import_node_path16.join)(pluginsRoot, "staging"), { recursive: true });
11345
+ (0, import_node_fs16.mkdirSync)((0, import_node_path16.join)(pluginsRoot, "quarantine"), { recursive: true });
11139
11346
  const suffix = `${Date.now()}-${process.pid}`;
11140
- const staged = (0, import_node_path15.join)(pluginsRoot, "staging", `mmi-${suffix}`);
11141
- const quarantined = (0, import_node_path15.join)(pluginsRoot, "quarantine", `mmi-${suffix}`);
11347
+ const staged = (0, import_node_path16.join)(pluginsRoot, "staging", `mmi-${suffix}`);
11348
+ const quarantined = (0, import_node_path16.join)(pluginsRoot, "quarantine", `mmi-${suffix}`);
11142
11349
  try {
11143
11350
  if (source) {
11144
- (0, import_node_fs15.cpSync)(source, staged, {
11351
+ (0, import_node_fs16.cpSync)(source, staged, {
11145
11352
  recursive: true,
11146
11353
  filter: (path2) => !path2.split(/[\\/]/).some((part) => part === ".git" || part === "node_modules")
11147
11354
  });
@@ -11152,18 +11359,18 @@ async function installCursorPluginCheckout(env = process.env) {
11152
11359
  });
11153
11360
  }
11154
11361
  if (!cursorPluginTreeHealthy(staged)) {
11155
- (0, import_node_fs15.rmSync)(staged, { recursive: true, force: true });
11362
+ (0, import_node_fs16.rmSync)(staged, { recursive: true, force: true });
11156
11363
  return { ok: false, detail: "downloaded Cursor plugin is incomplete; existing install was preserved" };
11157
11364
  }
11158
11365
  let movedOld = false;
11159
- if ((0, import_node_fs15.existsSync)(target)) {
11160
- (0, import_node_fs15.renameSync)(target, quarantined);
11366
+ if ((0, import_node_fs16.existsSync)(target)) {
11367
+ (0, import_node_fs16.renameSync)(target, quarantined);
11161
11368
  movedOld = true;
11162
11369
  }
11163
11370
  try {
11164
- (0, import_node_fs15.renameSync)(staged, target);
11371
+ (0, import_node_fs16.renameSync)(staged, target);
11165
11372
  } catch (error) {
11166
- if (movedOld && !(0, import_node_fs15.existsSync)(target)) (0, import_node_fs15.renameSync)(quarantined, target);
11373
+ if (movedOld && !(0, import_node_fs16.existsSync)(target)) (0, import_node_fs16.renameSync)(quarantined, target);
11167
11374
  throw error;
11168
11375
  }
11169
11376
  return {
@@ -11171,7 +11378,7 @@ async function installCursorPluginCheckout(env = process.env) {
11171
11378
  detail: movedOld ? `installed canonical Cursor plugin; previous checkout quarantined at ${quarantined}` : `installed canonical Cursor plugin at ${target}`
11172
11379
  };
11173
11380
  } catch (error) {
11174
- if ((0, import_node_fs15.existsSync)(staged)) (0, import_node_fs15.rmSync)(staged, { recursive: true, force: true });
11381
+ if ((0, import_node_fs16.existsSync)(staged)) (0, import_node_fs16.rmSync)(staged, { recursive: true, force: true });
11175
11382
  return { ok: false, detail: error.message.trim().slice(0, 240).replace(/\s+/g, " ") };
11176
11383
  }
11177
11384
  }
@@ -11221,7 +11428,7 @@ async function applyPluginHeal(surface, log, opts) {
11221
11428
  const refSupported = await marketplaceAddRefSupported(bin);
11222
11429
  const { steps } = adaptHealStepsForRefSupport(tableSteps, refSupported);
11223
11430
  log(healBannerLine(bin, token, refSupported));
11224
- const pinsPath = (0, import_node_path15.join)((0, import_node_os4.homedir)(), ...KNOWN_MARKETPLACES_RELATIVE);
11431
+ const pinsPath = (0, import_node_path16.join)((0, import_node_os5.homedir)(), ...KNOWN_MARKETPLACES_RELATIVE);
11225
11432
  const pins = token === "claude" ? captureMarketplacePins(readKnownMarketplacesFile(pinsPath), [MMI_MARKETPLACE_NAME, JERV_MARKETPLACE_NAME]) : /* @__PURE__ */ new Map();
11226
11433
  try {
11227
11434
  for (const step of steps) {
@@ -11296,7 +11503,7 @@ async function healActivePluginForDoctor(surface = detectSurface(process.env), o
11296
11503
  }
11297
11504
  function readKnownMarketplacesFile(path2) {
11298
11505
  try {
11299
- return (0, import_node_fs15.existsSync)(path2) ? (0, import_node_fs15.readFileSync)(path2, "utf8") : void 0;
11506
+ return (0, import_node_fs16.existsSync)(path2) ? (0, import_node_fs16.readFileSync)(path2, "utf8") : void 0;
11300
11507
  } catch {
11301
11508
  return void 0;
11302
11509
  }
@@ -11323,7 +11530,7 @@ function writeMarketplacePinsOnDisk(path2, pins, succeeded, failedVerb, declineW
11323
11530
  const declined = declineWhileHostLive?.();
11324
11531
  if (declined) return declined;
11325
11532
  try {
11326
- (0, import_node_fs15.writeFileSync)(path2, next, "utf8");
11533
+ (0, import_node_fs16.writeFileSync)(path2, next, "utf8");
11327
11534
  } catch {
11328
11535
  return `could NOT ${failedVerb} ${[...pins.keys()].join(", ")} \u2014 set it by hand`;
11329
11536
  }
@@ -11358,15 +11565,15 @@ function applyOrgMarketplacePins(path2, names, hostIsRunning = claudeCodeIsRunni
11358
11565
  }
11359
11566
  function writeMarketplacePinPending(path2, names, now = Date.now()) {
11360
11567
  try {
11361
- (0, import_node_fs15.mkdirSync)((0, import_node_path15.dirname)(path2), { recursive: true });
11362
- (0, import_node_fs15.writeFileSync)(path2, `${JSON.stringify({ v: 1, names: [...names], at: new Date(now).toISOString() })}
11568
+ (0, import_node_fs16.mkdirSync)((0, import_node_path16.dirname)(path2), { recursive: true });
11569
+ (0, import_node_fs16.writeFileSync)(path2, `${JSON.stringify({ v: 1, names: [...names], at: new Date(now).toISOString() })}
11363
11570
  `, "utf8");
11364
11571
  } catch {
11365
11572
  }
11366
11573
  }
11367
11574
  function readMarketplacePinPending(path2, name, now = Date.now()) {
11368
11575
  try {
11369
- const parsed = JSON.parse((0, import_node_fs15.readFileSync)(path2, "utf8"));
11576
+ const parsed = JSON.parse((0, import_node_fs16.readFileSync)(path2, "utf8"));
11370
11577
  const at = typeof parsed.at === "string" ? Date.parse(parsed.at) : Number.NaN;
11371
11578
  if (parsed.v !== 1 || !Array.isArray(parsed.names) || !parsed.names.includes(name) || !Number.isFinite(at)) return void 0;
11372
11579
  if (now - at < 0 || now - at > 12 * 60 * 6e4) return void 0;
@@ -12498,17 +12705,17 @@ async function dispatchDeploy(deps, ctx, stage, ref, model, watch, autoRunSince,
12498
12705
  return { note: `no manual dispatch: ${model} repo deploys via its own push-triggered workflow`, deployStatus: "pending" };
12499
12706
  }
12500
12707
  function readLocalGateWorkflows() {
12501
- const dir = (0, import_node_path16.join)(".github", "workflows");
12708
+ const dir = (0, import_node_path17.join)(".github", "workflows");
12502
12709
  let names;
12503
12710
  try {
12504
- names = (0, import_node_fs16.readdirSync)(dir);
12711
+ names = (0, import_node_fs17.readdirSync)(dir);
12505
12712
  } catch {
12506
12713
  return null;
12507
12714
  }
12508
12715
  const files = [];
12509
12716
  for (const name of names.filter(isGateWorkflowPath)) {
12510
12717
  try {
12511
- files.push({ path: `${dir}/${name}`.replace(/\\/g, "/"), body: (0, import_node_fs16.readFileSync)((0, import_node_path16.join)(dir, name), "utf8") });
12718
+ files.push({ path: `${dir}/${name}`.replace(/\\/g, "/"), body: (0, import_node_fs17.readFileSync)((0, import_node_path17.join)(dir, name), "utf8") });
12512
12719
  } catch {
12513
12720
  }
12514
12721
  }
@@ -14610,12 +14817,12 @@ async function runPrLand(prNumber, options, deps) {
14610
14817
  }
14611
14818
 
14612
14819
  // src/wave-status.ts
14613
- var import_node_fs18 = require("node:fs");
14820
+ var import_node_fs19 = require("node:fs");
14614
14821
 
14615
14822
  // src/stage-runner.ts
14616
14823
  var import_node_child_process7 = require("node:child_process");
14617
- var import_node_fs17 = require("node:fs");
14618
- var import_node_path17 = require("node:path");
14824
+ var import_node_fs18 = require("node:fs");
14825
+ var import_node_path18 = require("node:path");
14619
14826
  var import_node_net = require("node:net");
14620
14827
  var import_node_util5 = require("node:util");
14621
14828
 
@@ -14730,7 +14937,7 @@ function containersPublishingPort(containers, port) {
14730
14937
  return containers.filter((c) => c.publishedHostPorts.includes(port));
14731
14938
  }
14732
14939
  function isOwnComposeContainer(container, cwd) {
14733
- if (container.composeWorkingDir && normPath2(container.composeWorkingDir) === normPath2(cwd)) return true;
14940
+ if (container.composeWorkingDir && normPath3(container.composeWorkingDir) === normPath3(cwd)) return true;
14734
14941
  if (container.composeWorkingDir && pathUnder(container.composeWorkingDir, cwd)) return true;
14735
14942
  const derived = deriveComposeProjectName(cwd);
14736
14943
  return Boolean(derived && container.composeProject === derived);
@@ -14754,13 +14961,13 @@ function appendForceRecreate(up) {
14754
14961
  return `${up.trimEnd()} --force-recreate`;
14755
14962
  }
14756
14963
  function stageStatePath(cwd = process.cwd()) {
14757
- return (0, import_node_path17.join)(cwd, "tmp", "stage", "state.json");
14964
+ return (0, import_node_path18.join)(cwd, "tmp", "stage", "state.json");
14758
14965
  }
14759
14966
  function stageGlobalStatePath(cwd = process.cwd(), gitCommonDir = ".git") {
14760
- const dir = (0, import_node_path17.isAbsolute)(gitCommonDir) ? gitCommonDir : (0, import_node_path17.resolve)(cwd, gitCommonDir);
14761
- return (0, import_node_path17.join)(dir, "mmi", "stage", "state.json");
14967
+ const dir = (0, import_node_path18.isAbsolute)(gitCommonDir) ? gitCommonDir : (0, import_node_path18.resolve)(cwd, gitCommonDir);
14968
+ return (0, import_node_path18.join)(dir, "mmi", "stage", "state.json");
14762
14969
  }
14763
- function normPath2(path2) {
14970
+ function normPath3(path2) {
14764
14971
  return path2.replace(/\\/g, "/").replace(/\/+$/, "").toLowerCase();
14765
14972
  }
14766
14973
  function parseWorktreeListPaths(stdout) {
@@ -14791,8 +14998,8 @@ function parseStagePortFlag(raw) {
14791
14998
  return port;
14792
14999
  }
14793
15000
  function pathUnder(childPath, parentPath) {
14794
- const child2 = normPath2(childPath);
14795
- const parent = normPath2(parentPath);
15001
+ const child2 = normPath3(childPath);
15002
+ const parent = normPath3(parentPath);
14796
15003
  return Boolean(child2 && parent && (child2 === parent || child2.startsWith(`${parent}/`)));
14797
15004
  }
14798
15005
  function stageStateMatchesRequiredCwd(state, requiredCwd) {
@@ -14956,8 +15163,8 @@ async function resolveStagePort(config, guard, reservedPorts = /* @__PURE__ */ n
14956
15163
  return pickStagePort(config.portRange, (p) => free.has(p));
14957
15164
  }
14958
15165
  async function reservedPortsForWorktree(cwd) {
14959
- const self = normPath2(cwd);
14960
- const siblings = (await listRepoWorktreePaths(cwd)).filter((p) => normPath2(p) !== self);
15166
+ const self = normPath3(cwd);
15167
+ const siblings = (await listRepoWorktreePaths(cwd)).filter((p) => normPath3(p) !== self);
14961
15168
  return collectReservedStagePorts(siblings);
14962
15169
  }
14963
15170
  async function assertStagePortAvailable(port, cwd, guard, reserved) {
@@ -14982,14 +15189,14 @@ function stageProcessEnv(stagePort, extraEnv) {
14982
15189
  }
14983
15190
  async function ensureStageRuntimeEnv(config, opts, cwd) {
14984
15191
  if (!config.ensureEnv) return;
14985
- const target = (0, import_node_path17.join)(cwd, config.ensureEnv.target);
14986
- const example = (0, import_node_path17.join)(cwd, config.ensureEnv.example);
14987
- if (!(0, import_node_fs17.existsSync)(target) && (0, import_node_fs17.existsSync)(example)) {
14988
- (0, import_node_fs17.copyFileSync)(example, target);
14989
- } else if ((0, import_node_fs17.existsSync)(target) && (0, import_node_fs17.existsSync)(example)) {
14990
- const stale = detectStaleEnvFile((0, import_node_fs17.readFileSync)(example, "utf8"), (0, import_node_fs17.readFileSync)(target, "utf8"), {
14991
- exampleMtimeMs: (0, import_node_fs17.statSync)(example).mtimeMs,
14992
- targetMtimeMs: (0, import_node_fs17.statSync)(target).mtimeMs
15192
+ const target = (0, import_node_path18.join)(cwd, config.ensureEnv.target);
15193
+ const example = (0, import_node_path18.join)(cwd, config.ensureEnv.example);
15194
+ if (!(0, import_node_fs18.existsSync)(target) && (0, import_node_fs18.existsSync)(example)) {
15195
+ (0, import_node_fs18.copyFileSync)(example, target);
15196
+ } else if ((0, import_node_fs18.existsSync)(target) && (0, import_node_fs18.existsSync)(example)) {
15197
+ const stale = detectStaleEnvFile((0, import_node_fs18.readFileSync)(example, "utf8"), (0, import_node_fs18.readFileSync)(target, "utf8"), {
15198
+ exampleMtimeMs: (0, import_node_fs18.statSync)(example).mtimeMs,
15199
+ targetMtimeMs: (0, import_node_fs18.statSync)(target).mtimeMs
14993
15200
  });
14994
15201
  if (stale) {
14995
15202
  const msg = `stale ${config.ensureEnv.target} (${stale}) \u2014 delete it or refresh from ${config.ensureEnv.example} before re-running /stage`;
@@ -14997,8 +15204,8 @@ async function ensureStageRuntimeEnv(config, opts, cwd) {
14997
15204
  console.error(`mmi-cli stage: ${msg} (allowed via --allow-stale-env)`);
14998
15205
  }
14999
15206
  }
15000
- if (opts.vaultEnvMerge && Object.keys(opts.vaultEnvMerge).length && (0, import_node_fs17.existsSync)(target)) {
15001
- (0, import_node_fs17.writeFileSync)(target, mergeEnvSecretsIntoFile((0, import_node_fs17.readFileSync)(target, "utf8"), opts.vaultEnvMerge), "utf8");
15207
+ if (opts.vaultEnvMerge && Object.keys(opts.vaultEnvMerge).length && (0, import_node_fs18.existsSync)(target)) {
15208
+ (0, import_node_fs18.writeFileSync)(target, mergeEnvSecretsIntoFile((0, import_node_fs18.readFileSync)(target, "utf8"), opts.vaultEnvMerge), "utf8");
15002
15209
  }
15003
15210
  }
15004
15211
  async function gitText(cwd, args) {
@@ -15028,20 +15235,20 @@ async function resolveGlobalStatePath(cwd, explicit) {
15028
15235
  return void 0;
15029
15236
  }
15030
15237
  function readState(path2) {
15031
- if (!(0, import_node_fs17.existsSync)(path2)) return null;
15238
+ if (!(0, import_node_fs18.existsSync)(path2)) return null;
15032
15239
  try {
15033
- return JSON.parse((0, import_node_fs17.readFileSync)(path2, "utf8"));
15240
+ return JSON.parse((0, import_node_fs18.readFileSync)(path2, "utf8"));
15034
15241
  } catch {
15035
15242
  return null;
15036
15243
  }
15037
15244
  }
15038
15245
  function mkdirFor(path2) {
15039
15246
  const dir = path2.slice(0, Math.max(path2.lastIndexOf("/"), path2.lastIndexOf("\\")));
15040
- (0, import_node_fs17.mkdirSync)(dir, { recursive: true });
15247
+ (0, import_node_fs18.mkdirSync)(dir, { recursive: true });
15041
15248
  }
15042
15249
  function writeState(path2, state) {
15043
15250
  mkdirFor(path2);
15044
- (0, import_node_fs17.writeFileSync)(path2, JSON.stringify(state, null, 2), "utf8");
15251
+ (0, import_node_fs18.writeFileSync)(path2, JSON.stringify(state, null, 2), "utf8");
15045
15252
  }
15046
15253
  function writeStagePortReservation(port, cwd, statePath, globalStatePath, now) {
15047
15254
  const reservation = {
@@ -15061,7 +15268,7 @@ async function cleanupStageState(state, paths, timeoutMs, fallbackCwd) {
15061
15268
  await shell(state.teardown.command.trim(), state.teardown.cwd || state.cwd || fallbackCwd, Math.max(timeoutMs, 1e4));
15062
15269
  }
15063
15270
  for (const path2 of [...new Set(paths.filter((p) => Boolean(p)))]) {
15064
- (0, import_node_fs17.rmSync)(path2, { force: true });
15271
+ (0, import_node_fs18.rmSync)(path2, { force: true });
15065
15272
  }
15066
15273
  }
15067
15274
  async function killTree(pid) {
@@ -15219,8 +15426,8 @@ async function runStage(config = {}, opts = {}) {
15219
15426
  await ensureStageRuntimeEnv(config, opts, cwd);
15220
15427
  if (build) await shell(sub(build), cwd, timeoutMs, stageProcessEnv(stagePort, extraEnv));
15221
15428
  } catch (e) {
15222
- (0, import_node_fs17.rmSync)(statePath, { force: true });
15223
- if (globalStatePath && globalStatePath !== statePath) (0, import_node_fs17.rmSync)(globalStatePath, { force: true });
15429
+ (0, import_node_fs18.rmSync)(statePath, { force: true });
15430
+ if (globalStatePath && globalStatePath !== statePath) (0, import_node_fs18.rmSync)(globalStatePath, { force: true });
15224
15431
  throw e;
15225
15432
  }
15226
15433
  const started = await startStage(config, {
@@ -15241,9 +15448,9 @@ function parseNextFromHead(headText) {
15241
15448
  }
15242
15449
  function readStageSummary(worktreePath) {
15243
15450
  const statePath = stageStatePath(worktreePath);
15244
- if (!(0, import_node_fs18.existsSync)(statePath)) return void 0;
15451
+ if (!(0, import_node_fs19.existsSync)(statePath)) return void 0;
15245
15452
  try {
15246
- const state = JSON.parse((0, import_node_fs18.readFileSync)(statePath, "utf8"));
15453
+ const state = JSON.parse((0, import_node_fs19.readFileSync)(statePath, "utf8"));
15247
15454
  const port = typeof state.port === "number" ? state.port : void 0;
15248
15455
  if (port == null || !Number.isInteger(port) || port <= 0) return void 0;
15249
15456
  return { port, url: typeof state.url === "string" ? state.url : void 0 };
@@ -15348,13 +15555,13 @@ async function executeWaveLand(plan, deps, opts = { preserveWorktree: true }) {
15348
15555
  }
15349
15556
 
15350
15557
  // src/index.ts
15351
- var import_node_os17 = require("node:os");
15558
+ var import_node_os18 = require("node:os");
15352
15559
 
15353
15560
  // src/board.ts
15354
15561
  var import_node_child_process9 = require("node:child_process");
15355
- var import_node_fs21 = require("node:fs");
15356
- var import_node_os7 = require("node:os");
15357
- var import_node_path20 = require("node:path");
15562
+ var import_node_fs22 = require("node:fs");
15563
+ var import_node_os8 = require("node:os");
15564
+ var import_node_path21 = require("node:path");
15358
15565
  var import_node_util6 = require("node:util");
15359
15566
 
15360
15567
  // src/board-priority.ts
@@ -15708,9 +15915,9 @@ function boardConfigFromProject(meta, floor = {}) {
15708
15915
  }
15709
15916
 
15710
15917
  // src/cli-doctor-shared.ts
15711
- var import_node_fs19 = require("node:fs");
15712
- var import_node_path19 = require("node:path");
15713
15918
  var import_node_fs20 = require("node:fs");
15919
+ var import_node_path20 = require("node:path");
15920
+ var import_node_fs21 = require("node:fs");
15714
15921
 
15715
15922
  // src/readiness-audit.ts
15716
15923
  var TENANT_DEPLOY_RUN_SCAN_LIMIT = 100;
@@ -15827,12 +16034,12 @@ ${lines.join("\n")}`;
15827
16034
 
15828
16035
  // src/secrets.ts
15829
16036
  var import_node_child_process8 = require("node:child_process");
15830
- var import_node_os6 = require("node:os");
16037
+ var import_node_os7 = require("node:os");
15831
16038
 
15832
16039
  // src/gh-create.ts
15833
16040
  var import_promises4 = require("node:fs/promises");
15834
- var import_node_os5 = require("node:os");
15835
- var import_node_path18 = require("node:path");
16041
+ var import_node_os6 = require("node:os");
16042
+ var import_node_path19 = require("node:path");
15836
16043
  var import_node_crypto3 = require("node:crypto");
15837
16044
  var ISSUE_TYPES = ["bug", "feature", "task"];
15838
16045
  var GH_MUTATION_TIMEOUT_MS = 12e4;
@@ -15885,9 +16092,9 @@ async function bodyArgsViaFile(args, deps = {}) {
15885
16092
  const write = deps.write ?? import_promises4.writeFile;
15886
16093
  const remove2 = deps.remove ?? import_promises4.unlink;
15887
16094
  const ensureDir = deps.ensureDir ?? import_promises4.mkdir;
15888
- const dir = deps.dir ?? (0, import_node_os5.tmpdir)();
15889
- const file = (0, import_node_path18.join)(dir, `mmi-gh-body-${process.pid}-${(0, import_node_crypto3.randomBytes)(4).toString("hex")}.md`);
15890
- await ensureDir((0, import_node_path18.dirname)(file), { recursive: true }).catch(() => {
16095
+ const dir = deps.dir ?? (0, import_node_os6.tmpdir)();
16096
+ const file = (0, import_node_path19.join)(dir, `mmi-gh-body-${process.pid}-${(0, import_node_crypto3.randomBytes)(4).toString("hex")}.md`);
16097
+ await ensureDir((0, import_node_path19.dirname)(file), { recursive: true }).catch(() => {
15891
16098
  });
15892
16099
  await write(file, args[i + 1], "utf8");
15893
16100
  return {
@@ -17064,7 +17271,7 @@ function resolveSpawnTarget(command, args, platform2 = process.platform) {
17064
17271
  }
17065
17272
  function spawnExitCode(status, signal) {
17066
17273
  if (status != null) return status;
17067
- const signo = signal ? import_node_os6.constants.signals[signal] : void 0;
17274
+ const signo = signal ? import_node_os7.constants.signals[signal] : void 0;
17068
17275
  return signo ? 128 + signo : 1;
17069
17276
  }
17070
17277
  function defaultSpawn(command, args, env) {
@@ -17411,7 +17618,7 @@ async function localBranchHeads() {
17411
17618
  }
17412
17619
  async function currentRepoWorktreeGitRoot(repoRoot2) {
17413
17620
  const gitCommonDir = (await execFileP2("git", ["rev-parse", "--git-common-dir"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim();
17414
- return gitCommonDir ? (0, import_node_path19.resolve)(repoRoot2, gitCommonDir, "worktrees") : "";
17621
+ return gitCommonDir ? (0, import_node_path20.resolve)(repoRoot2, gitCommonDir, "worktrees") : "";
17415
17622
  }
17416
17623
  async function worktreeBranches() {
17417
17624
  const { stdout } = await execFileP2("git", ["worktree", "list", "--porcelain"], { timeout: GIT_TIMEOUT_MS });
@@ -17431,18 +17638,18 @@ function resolveGitdirForWorktreeFile(worktreePath, content) {
17431
17638
  const match = /^gitdir:\s*(.+)\s*$/im.exec(content);
17432
17639
  if (!match?.[1]) return void 0;
17433
17640
  const raw = match[1].trim();
17434
- return (0, import_node_path19.isAbsolute)(raw) ? raw : (0, import_node_path19.resolve)(worktreePath, raw);
17641
+ return (0, import_node_path20.isAbsolute)(raw) ? raw : (0, import_node_path20.resolve)(worktreePath, raw);
17435
17642
  }
17436
17643
  function metadataOwnsMissingWorktreeDir(worktreePath, worktreeGitRoot) {
17437
17644
  if (!worktreeGitRoot) return false;
17438
17645
  try {
17439
- const entries = (0, import_node_fs20.readdirSync)(worktreeGitRoot, { withFileTypes: true });
17646
+ const entries = (0, import_node_fs21.readdirSync)(worktreeGitRoot, { withFileTypes: true });
17440
17647
  for (const ent of entries) {
17441
17648
  if (!ent.isDirectory()) continue;
17442
17649
  try {
17443
- const gitdirPath = (0, import_node_fs19.readFileSync)((0, import_node_path19.join)(worktreeGitRoot, ent.name, "gitdir"), "utf8").trim();
17444
- const resolvedGitdir = (0, import_node_path19.isAbsolute)(gitdirPath) ? gitdirPath : (0, import_node_path19.resolve)(worktreeGitRoot, ent.name, gitdirPath);
17445
- if (sameWorktreeMetadataPath((0, import_node_path19.dirname)(resolvedGitdir), worktreePath)) return true;
17650
+ const gitdirPath = (0, import_node_fs20.readFileSync)((0, import_node_path20.join)(worktreeGitRoot, ent.name, "gitdir"), "utf8").trim();
17651
+ const resolvedGitdir = (0, import_node_path20.isAbsolute)(gitdirPath) ? gitdirPath : (0, import_node_path20.resolve)(worktreeGitRoot, ent.name, gitdirPath);
17652
+ if (sameWorktreeMetadataPath((0, import_node_path20.dirname)(resolvedGitdir), worktreePath)) return true;
17446
17653
  } catch {
17447
17654
  }
17448
17655
  }
@@ -17452,7 +17659,7 @@ function metadataOwnsMissingWorktreeDir(worktreePath, worktreeGitRoot) {
17452
17659
  }
17453
17660
  function pathExistsKnown(path2) {
17454
17661
  try {
17455
- (0, import_node_fs20.statSync)(path2);
17662
+ (0, import_node_fs21.statSync)(path2);
17456
17663
  return true;
17457
17664
  } catch (e) {
17458
17665
  const code = typeof e === "object" && e && "code" in e ? String(e.code ?? "") : "";
@@ -17461,10 +17668,10 @@ function pathExistsKnown(path2) {
17461
17668
  }
17462
17669
  }
17463
17670
  function inspectSiblingWorktreeDir(path2, worktreeGitRoot) {
17464
- const gitPath = (0, import_node_path19.join)(path2, ".git");
17671
+ const gitPath = (0, import_node_path20.join)(path2, ".git");
17465
17672
  let st;
17466
17673
  try {
17467
- st = (0, import_node_fs20.lstatSync)(gitPath);
17674
+ st = (0, import_node_fs21.lstatSync)(gitPath);
17468
17675
  } catch (e) {
17469
17676
  const code = typeof e === "object" && e && "code" in e ? String(e.code ?? "") : "";
17470
17677
  if (code === "ENOENT" || code === "ENOTDIR") {
@@ -17481,7 +17688,7 @@ function inspectSiblingWorktreeDir(path2, worktreeGitRoot) {
17481
17688
  if (st.isDirectory()) return { path: path2, gitType: "dir" };
17482
17689
  if (!st.isFile()) return { path: path2, gitType: "other" };
17483
17690
  try {
17484
- const gitFileContent = (0, import_node_fs19.readFileSync)(gitPath, "utf8");
17691
+ const gitFileContent = (0, import_node_fs20.readFileSync)(gitPath, "utf8");
17485
17692
  const gitdir = resolveGitdirForWorktreeFile(path2, gitFileContent);
17486
17693
  const gitDirExists = gitdir ? pathExistsKnown(gitdir) : false;
17487
17694
  return {
@@ -17489,7 +17696,7 @@ function inspectSiblingWorktreeDir(path2, worktreeGitRoot) {
17489
17696
  gitType: "file",
17490
17697
  gitFileContent,
17491
17698
  gitDirExists,
17492
- ownedByCurrentRepo: Boolean(gitdir && worktreeGitRoot && isPathUnderDirectory(gitdir, worktreeGitRoot)),
17699
+ ownedByCurrentRepo: Boolean(gitdir && worktreeGitRoot && isPathUnderDirectory2(gitdir, worktreeGitRoot)),
17493
17700
  detail: gitDirExists === void 0 ? "gitdir existence could not be verified" : void 0
17494
17701
  };
17495
17702
  } catch {
@@ -17498,7 +17705,7 @@ function inspectSiblingWorktreeDir(path2, worktreeGitRoot) {
17498
17705
  }
17499
17706
  function inspectDeadWorktreeDirContent(path2) {
17500
17707
  try {
17501
- return { entries: (0, import_node_fs20.readdirSync)(path2) };
17708
+ return { entries: (0, import_node_fs21.readdirSync)(path2) };
17502
17709
  } catch (e) {
17503
17710
  const code = typeof e === "object" && e && "code" in e ? String(e.code ?? "") : "";
17504
17711
  return { error: code ? `unable to inspect directory contents (${code})` : "unable to inspect directory contents" };
@@ -17515,7 +17722,7 @@ async function preservedBranches() {
17515
17722
  async function siblingWorktreeDirs(explicitRoot) {
17516
17723
  const repoRoot2 = (await execFileP2("git", ["rev-parse", "--show-toplevel"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim() || process.cwd();
17517
17724
  const worktreeGitRoot = await currentRepoWorktreeGitRoot(repoRoot2);
17518
- const primaryRepoRoot = worktreeGitRoot ? (0, import_node_path19.dirname)((0, import_node_path19.dirname)(worktreeGitRoot)) : repoRoot2;
17725
+ const primaryRepoRoot = worktreeGitRoot ? (0, import_node_path20.dirname)((0, import_node_path20.dirname)(worktreeGitRoot)) : repoRoot2;
17519
17726
  try {
17520
17727
  const dirs = explicitRoot ? listDirsIn(resolveExplicitScanRoot(explicitRoot, primaryRepoRoot)) : worktreeScanDirs(siblingMmiWorktreesRoot(primaryRepoRoot), primaryRepoRoot, listDirsIn, isRepoCheckoutDir);
17521
17728
  return dirs.map((dir) => inspectSiblingWorktreeDir(dir, worktreeGitRoot)).filter((entry) => Boolean(entry));
@@ -17525,18 +17732,18 @@ async function siblingWorktreeDirs(explicitRoot) {
17525
17732
  }
17526
17733
  function listDirsIn(dir) {
17527
17734
  try {
17528
- return (0, import_node_fs20.readdirSync)(dir, { withFileTypes: true }).filter((ent) => ent.isDirectory()).map((ent) => (0, import_node_path19.join)(dir, ent.name));
17735
+ return (0, import_node_fs21.readdirSync)(dir, { withFileTypes: true }).filter((ent) => ent.isDirectory()).map((ent) => (0, import_node_path20.join)(dir, ent.name));
17529
17736
  } catch {
17530
17737
  return [];
17531
17738
  }
17532
17739
  }
17533
17740
  function isRepoCheckoutDir(dir) {
17534
- return (0, import_node_fs20.existsSync)((0, import_node_path19.join)(dir, ".git"));
17741
+ return (0, import_node_fs21.existsSync)((0, import_node_path20.join)(dir, ".git"));
17535
17742
  }
17536
17743
  function resolveExplicitScanRoot(explicitRoot, repoRoot2) {
17537
17744
  let rootDirs;
17538
17745
  try {
17539
- rootDirs = (0, import_node_fs20.readdirSync)(explicitRoot, { withFileTypes: true }).filter((ent) => ent.isDirectory()).map((ent) => ent.name);
17746
+ rootDirs = (0, import_node_fs21.readdirSync)(explicitRoot, { withFileTypes: true }).filter((ent) => ent.isDirectory()).map((ent) => ent.name);
17540
17747
  } catch {
17541
17748
  return explicitRoot;
17542
17749
  }
@@ -18884,7 +19091,7 @@ var CLAIM_SESSION_ACTIVITY_MS = 30 * 6e4;
18884
19091
  var CLAIM_SESSION_PROBE_CACHE_MS = 6e4;
18885
19092
  var claimSessionProbeCache = /* @__PURE__ */ new Map();
18886
19093
  function probeLocalClaimSession(marker, now = Date.now()) {
18887
- if (!marker.session || !marker.host || marker.host.toLowerCase() !== (0, import_node_os7.hostname)().toLowerCase()) return void 0;
19094
+ if (!marker.session || !marker.host || marker.host.toLowerCase() !== (0, import_node_os8.hostname)().toLowerCase()) return void 0;
18888
19095
  if (!marker.surface?.toLowerCase().startsWith("claude")) return void 0;
18889
19096
  const cacheKey = `${marker.host.toLowerCase()}/${marker.session}`;
18890
19097
  const cached = claimSessionProbeCache.get(cacheKey);
@@ -18893,17 +19100,17 @@ function probeLocalClaimSession(marker, now = Date.now()) {
18893
19100
  claimSessionProbeCache.set(cacheKey, { checkedAt: now, state });
18894
19101
  return state;
18895
19102
  };
18896
- const root = (0, import_node_path20.join)((0, import_node_os7.homedir)(), ".claude", "projects");
19103
+ const root = (0, import_node_path21.join)((0, import_node_os8.homedir)(), ".claude", "projects");
18897
19104
  try {
18898
19105
  const wanted = `${marker.session}.jsonl`.toLowerCase();
18899
19106
  const pending = [root];
18900
19107
  while (pending.length) {
18901
19108
  const dir = pending.pop();
18902
- for (const entry of (0, import_node_fs21.readdirSync)(dir, { withFileTypes: true })) {
18903
- const path2 = (0, import_node_path20.join)(dir, entry.name);
19109
+ for (const entry of (0, import_node_fs22.readdirSync)(dir, { withFileTypes: true })) {
19110
+ const path2 = (0, import_node_path21.join)(dir, entry.name);
18904
19111
  if (entry.isDirectory()) pending.push(path2);
18905
19112
  else if (entry.isFile() && entry.name.toLowerCase() === wanted) {
18906
- return remember(now - (0, import_node_fs21.statSync)(path2).mtimeMs <= CLAIM_SESSION_ACTIVITY_MS ? "live" : "dead");
19113
+ return remember(now - (0, import_node_fs22.statSync)(path2).mtimeMs <= CLAIM_SESSION_ACTIVITY_MS ? "live" : "dead");
18907
19114
  }
18908
19115
  }
18909
19116
  }
@@ -19182,7 +19389,7 @@ async function resolveAutoAddBoardAttach(client, cfg, selector, priority, warn =
19182
19389
  }
19183
19390
 
19184
19391
  // src/issue-body.ts
19185
- var import_node_os8 = require("node:os");
19392
+ var import_node_os9 = require("node:os");
19186
19393
  var TextArgError = class extends Error {
19187
19394
  constructor(message, code, offendingFlag) {
19188
19395
  super(message);
@@ -19194,7 +19401,7 @@ var TextArgError = class extends Error {
19194
19401
  offendingFlag;
19195
19402
  };
19196
19403
  function emptyStdinMessage(fileFlag) {
19197
- if ((0, import_node_os8.platform)() === "win32") {
19404
+ if ((0, import_node_os9.platform)() === "win32") {
19198
19405
  return `${fileFlag} - read empty stdin (on Windows, ${fileFlag} - is unreliable through the npm .cmd shim \u2014 use ${fileFlag} <path>, or pipe to \`node cli/dist/index.cjs\` directly)`;
19199
19406
  }
19200
19407
  return `${fileFlag} - read empty stdin (nothing piped \u2014 pass a heredoc/pipe, or ${fileFlag} <path>)`;
@@ -19719,8 +19926,8 @@ function consolidateCommandNamespaces(program3) {
19719
19926
  }
19720
19927
 
19721
19928
  // src/pi-plugin-registration.ts
19722
- var import_node_fs22 = require("node:fs");
19723
- var import_node_path21 = require("node:path");
19929
+ var import_node_fs23 = require("node:fs");
19930
+ var import_node_path22 = require("node:path");
19724
19931
 
19725
19932
  // src/plugin-cache-prune.ts
19726
19933
  var PLUGIN_CACHE_KEEP = 2;
@@ -19974,37 +20181,37 @@ function newestExistingPiPlugin(home) {
19974
20181
  const cacheRoot = pluginCacheRoot(home);
19975
20182
  let names;
19976
20183
  try {
19977
- names = (0, import_node_fs22.readdirSync)(cacheRoot);
20184
+ names = (0, import_node_fs23.readdirSync)(cacheRoot);
19978
20185
  } catch {
19979
20186
  return void 0;
19980
20187
  }
19981
20188
  for (const version of names.filter(isVersionDirName).sort((a, b) => compareVersions(b, a))) {
19982
- const candidate = (0, import_node_path21.join)(cacheRoot, version, ".pi-plugin");
19983
- if ((0, import_node_fs22.existsSync)(candidate)) return candidate;
20189
+ const candidate = (0, import_node_path22.join)(cacheRoot, version, ".pi-plugin");
20190
+ if ((0, import_node_fs23.existsSync)(candidate)) return candidate;
19984
20191
  }
19985
20192
  return void 0;
19986
20193
  }
19987
20194
  function expectedPiPluginPath(home, env, installedVersion) {
19988
20195
  const root = env.CLAUDE_PLUGIN_ROOT?.trim();
19989
- if (root && /[\\/]mutmutco[\\/]mmi[\\/]/.test(root)) return (0, import_node_path21.join)(root, ".pi-plugin");
20196
+ if (root && /[\\/]mutmutco[\\/]mmi[\\/]/.test(root)) return (0, import_node_path22.join)(root, ".pi-plugin");
19990
20197
  const version = installedVersion ?? runningPluginVersion(env);
19991
20198
  if (version) {
19992
- const pinned = (0, import_node_path21.join)(home, ".claude", "plugins", "cache", "mutmutco", "mmi", version, ".pi-plugin");
19993
- if ((0, import_node_fs22.existsSync)(pinned)) return pinned;
20199
+ const pinned = (0, import_node_path22.join)(home, ".claude", "plugins", "cache", "mutmutco", "mmi", version, ".pi-plugin");
20200
+ if ((0, import_node_fs23.existsSync)(pinned)) return pinned;
19994
20201
  }
19995
20202
  return newestExistingPiPlugin(home);
19996
20203
  }
19997
20204
  function settingsPath(home) {
19998
- return (0, import_node_path21.join)(home, ".pi", "agent", "settings.json");
20205
+ return (0, import_node_path22.join)(home, ".pi", "agent", "settings.json");
19999
20206
  }
20000
20207
  function readPiPluginState(home, env, installedVersion) {
20001
- if (!(0, import_node_fs22.existsSync)((0, import_node_path21.join)(home, ".pi", "agent"))) return void 0;
20208
+ if (!(0, import_node_fs23.existsSync)((0, import_node_path22.join)(home, ".pi", "agent"))) return void 0;
20002
20209
  const expectedPath = expectedPiPluginPath(home, env, installedVersion);
20003
20210
  if (!expectedPath) return void 0;
20004
20211
  const file = settingsPath(home);
20005
- if (!(0, import_node_fs22.existsSync)(file)) return { expectedPath, settingsReadable: true };
20212
+ if (!(0, import_node_fs23.existsSync)(file)) return { expectedPath, settingsReadable: true };
20006
20213
  try {
20007
- const parsed = JSON.parse((0, import_node_fs22.readFileSync)(file, "utf8"));
20214
+ const parsed = JSON.parse((0, import_node_fs23.readFileSync)(file, "utf8"));
20008
20215
  const packages = Array.isArray(parsed.packages) ? parsed.packages : [];
20009
20216
  return { expectedPath, registeredPath: packages.find((p) => typeof p === "string" && isMmiPiPackage(p)), settingsReadable: true };
20010
20217
  } catch {
@@ -20017,11 +20224,11 @@ function healPiPluginRegistration(home, env, installedVersion) {
20017
20224
  if (!state.settingsReadable) return { ok: false, detail: "settings.json unreadable \u2014 nothing written (fail closed)" };
20018
20225
  const file = settingsPath(home);
20019
20226
  try {
20020
- const parsed = (0, import_node_fs22.existsSync)(file) ? JSON.parse((0, import_node_fs22.readFileSync)(file, "utf8")) : {};
20227
+ const parsed = (0, import_node_fs23.existsSync)(file) ? JSON.parse((0, import_node_fs23.readFileSync)(file, "utf8")) : {};
20021
20228
  const packages = Array.isArray(parsed.packages) ? parsed.packages : [];
20022
20229
  const next = packages.filter((p) => !(typeof p === "string" && isMmiPiPackage(p)));
20023
20230
  next.push(state.expectedPath);
20024
- (0, import_node_fs22.writeFileSync)(file, `${JSON.stringify({ ...parsed, packages: next }, null, 2)}
20231
+ (0, import_node_fs23.writeFileSync)(file, `${JSON.stringify({ ...parsed, packages: next }, null, 2)}
20025
20232
  `);
20026
20233
  return { ok: true, detail: state.registeredPath ? `replaced ${state.registeredPath}` : `registered ${state.expectedPath}` };
20027
20234
  } catch (e) {
@@ -20528,6 +20735,46 @@ async function cherryPickWithToleratedPaths(deps, sha, tolerated) {
20528
20735
  return unmerged;
20529
20736
  }
20530
20737
  }
20738
+ function parseCherryPickBlockingPaths(message) {
20739
+ const m = /conflicted on untolerated path\(s\): ([^(]+)/.exec(message);
20740
+ if (!m) return [];
20741
+ return m[1].split(",").map((s) => s.trim()).filter(Boolean);
20742
+ }
20743
+ function formatHotfixBatchPreflightRefusal(failures, fromSpecs) {
20744
+ const lines = failures.map((f) => ` - ${f.label}: ${f.blocking.join(", ")}`);
20745
+ const batchFrom = fromSpecs.join(",");
20746
+ return `hotfix start batch preflight refused: ${failures.length} pick(s) would hard-stop on origin/main:
20747
+ ${lines.join("\n")}
20748
+ Land ONE main-clean synthesis development PR for the whole batch (cut from origin/main, resolve every listed conflict for cherry-pick onto current origin/main, land to development \u2014 pattern #4467), then rerun \`mmi-cli hotfix start --from ${batchFrom}\` with the port merge SHA(s) \u2014 never hand-resolve onto main; never N serial main-clean ports (#3167).`;
20749
+ }
20750
+ async function preflightHotfixBatchPicks(deps, sources, pickTolerated) {
20751
+ if (sources.length === 0) return [];
20752
+ const startBranch = clean3(await deps.run("git", ["rev-parse", "--abbrev-ref", "HEAD"]));
20753
+ const preflightBranch = `__mmi_hotfix_preflight_${Date.now()}`;
20754
+ const failures = [];
20755
+ try {
20756
+ await deps.run("git", ["checkout", "-B", preflightBranch, "origin/main"]);
20757
+ for (const source of sources) {
20758
+ try {
20759
+ await cherryPickWithToleratedPaths(deps, source.sha, pickTolerated);
20760
+ } catch (e) {
20761
+ const message = e.message ?? String(e);
20762
+ const blocking = parseCherryPickBlockingPaths(message);
20763
+ failures.push({
20764
+ label: source.label,
20765
+ sha: source.sha,
20766
+ blocking: blocking.length > 0 ? blocking : [message.split("\n")[0] ?? message]
20767
+ });
20768
+ }
20769
+ }
20770
+ } finally {
20771
+ if (startBranch && startBranch !== "HEAD") {
20772
+ await deps.run("git", ["checkout", startBranch]).catch(() => void 0);
20773
+ }
20774
+ await deps.run("git", ["branch", "-D", preflightBranch]).catch(() => void 0);
20775
+ }
20776
+ return failures;
20777
+ }
20531
20778
  async function restoreAfterFailedPort(deps, opts) {
20532
20779
  const { startBranch, branch, created } = opts;
20533
20780
  if (!startBranch || startBranch === "HEAD" || startBranch === branch) {
@@ -20667,7 +20914,7 @@ async function runHotfixStart(deps, options) {
20667
20914
  }
20668
20915
  const label = sources.map((s) => s.label).join(", ");
20669
20916
  const foldPaths = deployModel === "hub-serverless" || deployModel === "registry-publish" ? await resolveFoldPaths(deps, deployModel) : [];
20670
- const pickTolerated = deployModel === "hub-serverless" ? [...foldPaths, ...HOTFIX_SKILL_TOLERATED_ROOTS] : foldPaths;
20917
+ const pickTolerated = deployModel === "hub-serverless" || deployModel === "registry-publish" ? [...foldPaths, ...HOTFIX_SKILL_TOLERATED_ROOTS] : foldPaths;
20671
20918
  if (deployModel === "hub-serverless") {
20672
20919
  await deps.run("node", ["scripts/release-distribution.mjs", "verify-deps"]);
20673
20920
  }
@@ -20677,6 +20924,10 @@ async function runHotfixStart(deps, options) {
20677
20924
  await deps.run("git", ["pull", "--ff-only", "origin", branch]);
20678
20925
  notes.push(`branch ${branch} already on origin \u2014 reused (cherry-pick/bump assumed present; PR step resumes)`);
20679
20926
  } else {
20927
+ const preflightFailures = await preflightHotfixBatchPicks(deps, sources, pickTolerated);
20928
+ if (preflightFailures.length > 0) {
20929
+ throw new Error(formatHotfixBatchPreflightRefusal(preflightFailures, specs));
20930
+ }
20680
20931
  const startBranch = clean3(await deps.run("git", ["rev-parse", "--abbrev-ref", "HEAD"]));
20681
20932
  const preexistingLocal = clean3(await deps.run("git", ["branch", "--list", branch]));
20682
20933
  await deps.run("git", ["checkout", "-B", branch, "origin/main"]);
@@ -21622,8 +21873,8 @@ function renderAccessReport(report) {
21622
21873
  // src/repo-index.ts
21623
21874
  var import_node_crypto4 = require("node:crypto");
21624
21875
  var import_node_child_process12 = require("node:child_process");
21625
- var import_node_fs23 = require("node:fs");
21626
- var import_node_path22 = require("node:path");
21876
+ var import_node_fs24 = require("node:fs");
21877
+ var import_node_path23 = require("node:path");
21627
21878
  var REPO_INDEX_SCHEMA = 1;
21628
21879
  var HARD_DENY = [
21629
21880
  /(^|\/)\.env(\.|$)/i,
@@ -21748,11 +21999,11 @@ function loadReadmeHints(cwd, candidatePaths) {
21748
21999
  }
21749
22000
  for (const rel of readmes) {
21750
22001
  if (isHardDeniedPath(rel)) continue;
21751
- const abs = (0, import_node_path22.join)(cwd, ...rel.split("/"));
21752
- if (!(0, import_node_fs23.existsSync)(abs)) continue;
22002
+ const abs = (0, import_node_path23.join)(cwd, ...rel.split("/"));
22003
+ if (!(0, import_node_fs24.existsSync)(abs)) continue;
21753
22004
  let text;
21754
22005
  try {
21755
- text = (0, import_node_fs23.readFileSync)(abs, "utf8");
22006
+ text = (0, import_node_fs24.readFileSync)(abs, "utf8");
21756
22007
  } catch {
21757
22008
  continue;
21758
22009
  }
@@ -21765,7 +22016,7 @@ function loadReadmeHints(cwd, candidatePaths) {
21765
22016
  return hints;
21766
22017
  }
21767
22018
  function toPosix(p) {
21768
- return p.split(import_node_path22.sep).join("/");
22019
+ return p.split(import_node_path23.sep).join("/");
21769
22020
  }
21770
22021
  function listCandidatePaths(cwd, exec = import_node_child_process12.execFileSync) {
21771
22022
  try {
@@ -21787,11 +22038,11 @@ function rebuildRepoIndex(cwd, repoSlug2) {
21787
22038
  for (const rel of candidates) {
21788
22039
  if (ignored.has(rel)) continue;
21789
22040
  if (isHardDeniedPath(rel)) continue;
21790
- const abs = (0, import_node_path22.join)(cwd, ...rel.split("/"));
21791
- if (!(0, import_node_fs23.existsSync)(abs)) continue;
22041
+ const abs = (0, import_node_path23.join)(cwd, ...rel.split("/"));
22042
+ if (!(0, import_node_fs24.existsSync)(abs)) continue;
21792
22043
  let text;
21793
22044
  try {
21794
- text = (0, import_node_fs23.readFileSync)(abs, "utf8");
22045
+ text = (0, import_node_fs24.readFileSync)(abs, "utf8");
21795
22046
  } catch {
21796
22047
  continue;
21797
22048
  }
@@ -21816,16 +22067,16 @@ function rebuildRepoIndex(cwd, repoSlug2) {
21816
22067
  entries
21817
22068
  };
21818
22069
  const store = repoIndexStorePath(cwd);
21819
- (0, import_node_fs23.mkdirSync)((0, import_node_path22.dirname)(store), { recursive: true });
21820
- (0, import_node_fs23.writeFileSync)(store, `${JSON.stringify(projection, null, 2)}
22070
+ (0, import_node_fs24.mkdirSync)((0, import_node_path23.dirname)(store), { recursive: true });
22071
+ (0, import_node_fs24.writeFileSync)(store, `${JSON.stringify(projection, null, 2)}
21821
22072
  `, "utf8");
21822
22073
  return projection;
21823
22074
  }
21824
22075
  function loadRepoIndex(cwd) {
21825
22076
  const store = repoIndexStorePath(cwd);
21826
- if (!(0, import_node_fs23.existsSync)(store)) return null;
22077
+ if (!(0, import_node_fs24.existsSync)(store)) return null;
21827
22078
  try {
21828
- const raw = JSON.parse((0, import_node_fs23.readFileSync)(store, "utf8"));
22079
+ const raw = JSON.parse((0, import_node_fs24.readFileSync)(store, "utf8"));
21829
22080
  if (raw?.schema !== REPO_INDEX_SCHEMA || !Array.isArray(raw.entries)) return null;
21830
22081
  return raw;
21831
22082
  } catch {
@@ -21897,7 +22148,7 @@ function inferRepoSlug(cwd, exec = import_node_child_process12.execFileSync) {
21897
22148
  if (m?.[1]) return m[1].toLowerCase();
21898
22149
  } catch {
21899
22150
  }
21900
- return ((0, import_node_path22.basename)(cwd) || "local").toLowerCase();
22151
+ return ((0, import_node_path23.basename)(cwd) || "local").toLowerCase();
21901
22152
  }
21902
22153
 
21903
22154
  // src/repo-index-cloud-client.ts
@@ -22037,9 +22288,9 @@ async function gcRepoIndexCloud(deps) {
22037
22288
  }
22038
22289
 
22039
22290
  // src/repo-index-sync.ts
22040
- var import_node_fs24 = require("node:fs");
22041
- var import_node_os9 = require("node:os");
22042
- var import_node_path23 = require("node:path");
22291
+ var import_node_fs25 = require("node:fs");
22292
+ var import_node_os10 = require("node:os");
22293
+ var import_node_path24 = require("node:path");
22043
22294
  var import_node_child_process13 = require("node:child_process");
22044
22295
  var MAX_EMBED_BACKFILL_ROUNDS = 40;
22045
22296
  function normalizeRepo(raw) {
@@ -22083,7 +22334,7 @@ async function syncEstateRepoIndex(opts) {
22083
22334
  const failed = [];
22084
22335
  const skipped = [];
22085
22336
  for (const repo of repos) {
22086
- const dir = (0, import_node_fs24.mkdtempSync)((0, import_node_path23.join)((0, import_node_os9.tmpdir)(), "mmi-repo-index-"));
22337
+ const dir = (0, import_node_fs25.mkdtempSync)((0, import_node_path24.join)((0, import_node_os10.tmpdir)(), "mmi-repo-index-"));
22087
22338
  try {
22088
22339
  shallowClone(repo, dir, opts.githubToken);
22089
22340
  const built = rebuildRepoIndex(dir, repo);
@@ -22133,7 +22384,7 @@ async function syncEstateRepoIndex(opts) {
22133
22384
  failed.push({ repo, error: e.message });
22134
22385
  } finally {
22135
22386
  try {
22136
- (0, import_node_fs24.rmSync)(dir, { recursive: true, force: true });
22387
+ (0, import_node_fs25.rmSync)(dir, { recursive: true, force: true });
22137
22388
  } catch {
22138
22389
  }
22139
22390
  }
@@ -22142,7 +22393,7 @@ async function syncEstateRepoIndex(opts) {
22142
22393
  }
22143
22394
 
22144
22395
  // src/repo-index-health.ts
22145
- var import_node_fs25 = require("node:fs");
22396
+ var import_node_fs26 = require("node:fs");
22146
22397
 
22147
22398
  // testdata/repo-index-golden-queries.json
22148
22399
  var repo_index_golden_queries_default = {
@@ -22184,7 +22435,7 @@ function assertGoldenSuite(raw, source) {
22184
22435
  function loadGoldenSuite(path2) {
22185
22436
  let text;
22186
22437
  try {
22187
- text = (0, import_node_fs25.readFileSync)(path2, "utf8");
22438
+ text = (0, import_node_fs26.readFileSync)(path2, "utf8");
22188
22439
  } catch (e) {
22189
22440
  throw new Error(`golden suite unreadable at ${path2}: ${e.message}`);
22190
22441
  }
@@ -22328,8 +22579,8 @@ async function runRepoIndexHealth(opts) {
22328
22579
 
22329
22580
  // src/spawn-policy-core.ts
22330
22581
  var import_node_child_process14 = require("node:child_process");
22331
- var import_node_fs26 = require("node:fs");
22332
- var import_node_path24 = require("node:path");
22582
+ var import_node_fs27 = require("node:fs");
22583
+ var import_node_path25 = require("node:path");
22333
22584
  var SPAWNERS = ["spawn", "spawnSync", "exec", "execSync", "execFile", "execFileSync"];
22334
22585
  var CALL_SOURCE = String.raw`(^|[^.\w$])(${SPAWNERS.join("|")})\s*\(`;
22335
22586
  var SOURCE_EXT = /\.(ts|mts|cts|js|mjs|cjs)$/;
@@ -22415,7 +22666,7 @@ function runSpawnPolicy(root) {
22415
22666
  for (const file of files) {
22416
22667
  let raw;
22417
22668
  try {
22418
- raw = (0, import_node_fs26.readFileSync)((0, import_node_path24.join)(root, file), "utf8");
22669
+ raw = (0, import_node_fs27.readFileSync)((0, import_node_path25.join)(root, file), "utf8");
22419
22670
  } catch {
22420
22671
  continue;
22421
22672
  }
@@ -22433,8 +22684,8 @@ function runSpawnPolicy(root) {
22433
22684
 
22434
22685
  // src/test-policy-core.ts
22435
22686
  var import_node_child_process15 = require("node:child_process");
22436
- var import_node_fs27 = require("node:fs");
22437
- var import_node_path25 = require("node:path");
22687
+ var import_node_fs28 = require("node:fs");
22688
+ var import_node_path26 = require("node:path");
22438
22689
  var POLICY_FILE = "test-policy.json";
22439
22690
  var TEST_RE = /\.(?:test|spec)\.[cm]?[jt]sx?$/;
22440
22691
  var PY_TEST_RE = /(?:^|\/)test_[^/]*\.py$|_test\.py$/;
@@ -22487,7 +22738,7 @@ function isTestPath(path2) {
22487
22738
  return TEST_RE.test(path2) || PY_TEST_RE.test(path2);
22488
22739
  }
22489
22740
  function loadPolicy(root, readFile9 = readFileOrNull2) {
22490
- const raw = readFile9((0, import_node_path25.join)(root, POLICY_FILE));
22741
+ const raw = readFile9((0, import_node_path26.join)(root, POLICY_FILE));
22491
22742
  if (raw == null) return { mandatory: [], declared: false };
22492
22743
  try {
22493
22744
  return { ...JSON.parse(raw), declared: true };
@@ -22497,7 +22748,7 @@ function loadPolicy(root, readFile9 = readFileOrNull2) {
22497
22748
  }
22498
22749
  function readFileOrNull2(path2) {
22499
22750
  try {
22500
- return (0, import_node_fs27.readFileSync)(path2, "utf8");
22751
+ return (0, import_node_fs28.readFileSync)(path2, "utf8");
22501
22752
  } catch {
22502
22753
  return null;
22503
22754
  }
@@ -22524,12 +22775,12 @@ function classify(changed, policy, present = () => false) {
22524
22775
  const removedProtected = [...removed].filter((p) => protectedBy.has(p)).map((p) => ({ path: p, why: protectedBy.get(p) ?? "" }));
22525
22776
  return { mandatoryHits, untestedHits, testChanges, addedTests, removedProtected };
22526
22777
  }
22527
- function unresolvedProtectedEntries(policy, root, exists = (path2) => (0, import_node_fs27.existsSync)(path2)) {
22528
- return (policy.protected ?? []).map((p) => p.path).filter((p) => !exists((0, import_node_path25.join)(root, p)));
22778
+ function unresolvedProtectedEntries(policy, root, exists = (path2) => (0, import_node_fs28.existsSync)(path2)) {
22779
+ return (policy.protected ?? []).map((p) => p.path).filter((p) => !exists((0, import_node_path26.join)(root, p)));
22529
22780
  }
22530
- function unresolvedSatisfiers(policy, root, exists = (path2) => (0, import_node_fs27.existsSync)(path2)) {
22781
+ function unresolvedSatisfiers(policy, root, exists = (path2) => (0, import_node_fs28.existsSync)(path2)) {
22531
22782
  const declared = (policy.mandatory ?? []).flatMap((m) => m.satisfiedBy ?? []);
22532
- return [...new Set(declared)].filter((p) => !exists((0, import_node_path25.join)(root, p)));
22783
+ return [...new Set(declared)].filter((p) => !exists((0, import_node_path26.join)(root, p)));
22533
22784
  }
22534
22785
  function evaluate(changed, policy, present = () => false) {
22535
22786
  const { mandatoryHits, untestedHits, testChanges, addedTests, removedProtected } = classify(changed, policy, present);
@@ -22711,13 +22962,13 @@ function changedFilesSince(base, cwd) {
22711
22962
  }
22712
22963
  function runTestPolicy(root, deps = {}) {
22713
22964
  const policy = deps.policy ?? loadPolicy(root);
22714
- const exists = deps.exists ?? ((path2) => (0, import_node_fs27.existsSync)(path2));
22965
+ const exists = deps.exists ?? ((path2) => (0, import_node_fs28.existsSync)(path2));
22715
22966
  const counts = { mandatoryCount: (policy.mandatory ?? []).length, protectedCount: (policy.protected ?? []).length };
22716
22967
  const base = deps.changed ? "(injected)" : resolveBase(root, deps.base);
22717
22968
  const refusal = deps.changed ? null : untrustworthyRange(root, base);
22718
22969
  const changed = deps.changed ?? (refusal ? [] : changedFilesSince(base, root));
22719
22970
  const lookup = deps.override !== void 0 ? { override: deps.override, refusals: [] } : !deps.changed && !refusal ? readOverride(base, root) : { override: null, refusals: [] };
22720
- const present = (path2) => exists((0, import_node_path25.join)(root, path2));
22971
+ const present = (path2) => exists((0, import_node_path26.join)(root, path2));
22721
22972
  const removedByThisDiff = removedPaths(changed);
22722
22973
  const staleFindings = [];
22723
22974
  const unresolved = unresolvedProtectedEntries(policy, root, exists).filter((p) => !removedByThisDiff.has(p));
@@ -22755,8 +23006,8 @@ function runTestPolicy(root, deps = {}) {
22755
23006
  }
22756
23007
 
22757
23008
  // src/project-info-sync.ts
22758
- var import_node_fs28 = require("node:fs");
22759
- var import_node_path26 = require("node:path");
23009
+ var import_node_fs29 = require("node:fs");
23010
+ var import_node_path27 = require("node:path");
22760
23011
  var UPDATE_PROJECT_INFO = `mutation($projectId: ID!, $shortDescription: String!, $readme: String!) {
22761
23012
  updateProjectV2(input: { projectId: $projectId, shortDescription: $shortDescription, readme: $readme }) {
22762
23013
  projectV2 { id }
@@ -22801,14 +23052,14 @@ function sharedName(entries, fallback) {
22801
23052
  }
22802
23053
  function buildProjectInfoSyncPlan(targetRepo2, project2, projects, repoRoot2) {
22803
23054
  if (!project2.projectId) throw new Error(`org project sync-info: ${targetRepo2} registry META has no projectId`);
22804
- const readmePath = (0, import_node_path26.join)(repoRoot2, "README.md");
22805
- if (!(0, import_node_fs28.existsSync)(readmePath)) throw new Error(`org project sync-info: ${targetRepo2} has no README.md`);
23055
+ const readmePath = (0, import_node_path27.join)(repoRoot2, "README.md");
23056
+ if (!(0, import_node_fs29.existsSync)(readmePath)) throw new Error(`org project sync-info: ${targetRepo2} has no README.md`);
22806
23057
  const entries = entriesFor(project2, projects);
22807
23058
  const memberRepos = [...new Set(entries.flatMap((entry) => entry.repos ?? []))].filter((repo) => /^[^/]+\/[^/]+$/.test(repo)).sort((a, b) => a.localeCompare(b));
22808
23059
  const projectName = sharedName(entries, project2.name?.trim() || targetRepo2.split("/").pop() || targetRepo2);
22809
23060
  if (!memberRepos.length) throw new Error(`org project sync-info: project ${projectName} has no registered member repos`);
22810
23061
  const entryNames = entries.map((entry) => entry.name?.trim()).filter((name) => Boolean(name));
22811
- const shortDescription = memberRepos.length === 1 ? shortDescriptionFromReadme((0, import_node_fs28.readFileSync)(readmePath, "utf8")) : `Shared work across ${new Intl.ListFormat("en", { type: "conjunction" }).format(entryNames)}.`;
23062
+ const shortDescription = memberRepos.length === 1 ? shortDescriptionFromReadme((0, import_node_fs29.readFileSync)(readmePath, "utf8")) : `Shared work across ${new Intl.ListFormat("en", { type: "conjunction" }).format(entryNames)}.`;
22812
23063
  const lines = [
22813
23064
  `# ${projectName}`,
22814
23065
  "",
@@ -22827,8 +23078,8 @@ function buildProjectInfoSyncPlan(targetRepo2, project2, projects, repoRoot2) {
22827
23078
  const targetBase = `https://github.com/${targetRepo2}`;
22828
23079
  const targetBranch = branchFor(targetRepo2, projects);
22829
23080
  const orgDocs = [
22830
- (0, import_node_fs28.existsSync)((0, import_node_path26.join)(repoRoot2, "docs", "org-readme.md")) ? `- [Org identity](${targetBase}/blob/${targetBranch}/docs/org-readme.md)` : "",
22831
- (0, import_node_fs28.existsSync)((0, import_node_path26.join)(repoRoot2, "docs", "org-architecture.md")) ? `- [Org architecture](${targetBase}/blob/${targetBranch}/docs/org-architecture.md)` : ""
23081
+ (0, import_node_fs29.existsSync)((0, import_node_path27.join)(repoRoot2, "docs", "org-readme.md")) ? `- [Org identity](${targetBase}/blob/${targetBranch}/docs/org-readme.md)` : "",
23082
+ (0, import_node_fs29.existsSync)((0, import_node_path27.join)(repoRoot2, "docs", "org-architecture.md")) ? `- [Org architecture](${targetBase}/blob/${targetBranch}/docs/org-architecture.md)` : ""
22832
23083
  ].filter(Boolean);
22833
23084
  if (orgDocs.length) lines.push("", "## Organisation docs", "", ...orgDocs);
22834
23085
  return { projectId: project2.projectId, projectName, targetRepo: targetRepo2, memberRepos, shortDescription, readme: `${lines.join("\n")}
@@ -23705,9 +23956,9 @@ function writeError(res) {
23705
23956
  }
23706
23957
 
23707
23958
  // src/secrets-commands.ts
23708
- var import_node_fs29 = require("node:fs");
23709
- var import_node_path27 = require("node:path");
23710
- var import_node_os10 = require("node:os");
23959
+ var import_node_fs30 = require("node:fs");
23960
+ var import_node_path28 = require("node:path");
23961
+ var import_node_os11 = require("node:os");
23711
23962
 
23712
23963
  // src/project-runtime.ts
23713
23964
  function hasRuntimeSecretContract(contract) {
@@ -23830,18 +24081,18 @@ function collectMap(value, previous = []) {
23830
24081
  return [...previous, value];
23831
24082
  }
23832
24083
  async function decryptRailsCredentials(input) {
23833
- const appDir = (0, import_node_path27.resolve)(input.appDir ?? process.cwd());
24084
+ const appDir = (0, import_node_path28.resolve)(input.appDir ?? process.cwd());
23834
24085
  const credentialsFile = input.credentialsFile ?? DEFAULT_RAILS_CREDENTIALS_FILE;
23835
24086
  const masterKeyFile = input.masterKeyFile ?? DEFAULT_RAILS_MASTER_KEY_FILE;
23836
- const credentialsPath = (0, import_node_path27.resolve)(appDir, credentialsFile);
23837
- const masterKeyPath = (0, import_node_path27.resolve)(appDir, masterKeyFile);
24087
+ const credentialsPath = (0, import_node_path28.resolve)(appDir, credentialsFile);
24088
+ const masterKeyPath = (0, import_node_path28.resolve)(appDir, masterKeyFile);
23838
24089
  const env = {
23839
24090
  ...process.env,
23840
24091
  MMI_RAILS_CREDENTIALS_FILE: credentialsPath,
23841
24092
  MMI_RAILS_MASTER_KEY_FILE: masterKeyPath
23842
24093
  };
23843
- if ((0, import_node_fs29.existsSync)(masterKeyPath)) {
23844
- env.RAILS_MASTER_KEY = (0, import_node_fs29.readFileSync)(masterKeyPath, "utf8").trim();
24094
+ if ((0, import_node_fs30.existsSync)(masterKeyPath)) {
24095
+ env.RAILS_MASTER_KEY = (0, import_node_fs30.readFileSync)(masterKeyPath, "utf8").trim();
23845
24096
  }
23846
24097
  const script = [
23847
24098
  'require "json"',
@@ -23851,9 +24102,9 @@ async function decryptRailsCredentials(input) {
23851
24102
  'config = ActiveSupport::EncryptedConfiguration.new(config_path: config_path, key_path: key_path, env_key: "RAILS_MASTER_KEY", raise_if_missing_key: true)',
23852
24103
  "puts JSON.generate(config.config)"
23853
24104
  ].join("\n");
23854
- const scriptDir = (0, import_node_fs29.mkdtempSync)((0, import_node_path27.join)((0, import_node_os10.tmpdir)(), "mmi-rails-decrypt-"));
23855
- const scriptPath = (0, import_node_path27.join)(scriptDir, "decrypt.rb");
23856
- (0, import_node_fs29.writeFileSync)(scriptPath, script, "utf8");
24105
+ const scriptDir = (0, import_node_fs30.mkdtempSync)((0, import_node_path28.join)((0, import_node_os11.tmpdir)(), "mmi-rails-decrypt-"));
24106
+ const scriptPath = (0, import_node_path28.join)(scriptDir, "decrypt.rb");
24107
+ (0, import_node_fs30.writeFileSync)(scriptPath, script, "utf8");
23857
24108
  try {
23858
24109
  const args = ["exec", "ruby", scriptPath];
23859
24110
  const cmd = process.platform === "win32" ? "cmd.exe" : "bundle";
@@ -23865,7 +24116,7 @@ async function decryptRailsCredentials(input) {
23865
24116
  });
23866
24117
  return JSON.parse(stdout);
23867
24118
  } finally {
23868
- (0, import_node_fs29.rmSync)(scriptDir, { recursive: true, force: true });
24119
+ (0, import_node_fs30.rmSync)(scriptDir, { recursive: true, force: true });
23869
24120
  }
23870
24121
  }
23871
24122
  async function readSecretStdin() {
@@ -23955,7 +24206,7 @@ function registerSecretsCommands(program3) {
23955
24206
  let body;
23956
24207
  if (o.file) {
23957
24208
  try {
23958
- body = (0, import_node_fs29.readFileSync)((0, import_node_path27.resolve)(o.file), "utf8");
24209
+ body = (0, import_node_fs30.readFileSync)((0, import_node_path28.resolve)(o.file), "utf8");
23959
24210
  } catch (e) {
23960
24211
  return fail(`secrets org-catalog: cannot read --file ${o.file}: ${e.message}`);
23961
24212
  }
@@ -24060,7 +24311,7 @@ function registerSecretsCommands(program3) {
24060
24311
  {
24061
24312
  ...d,
24062
24313
  decryptRailsCredentials,
24063
- removeFile: (path2) => (0, import_node_fs29.unlinkSync)((0, import_node_path27.resolve)(o.appDir ?? process.cwd(), path2))
24314
+ removeFile: (path2) => (0, import_node_fs30.unlinkSync)((0, import_node_path28.resolve)(o.appDir ?? process.cwd(), path2))
24064
24315
  },
24065
24316
  {
24066
24317
  repo: o.repo,
@@ -24224,7 +24475,7 @@ async function activateAppActor(commandPath3, env, mint) {
24224
24475
  }
24225
24476
 
24226
24477
  // src/box-commands.ts
24227
- var import_node_fs30 = require("node:fs");
24478
+ var import_node_fs31 = require("node:fs");
24228
24479
 
24229
24480
  // src/box.ts
24230
24481
  var BOX_KEYS = {
@@ -24427,7 +24678,7 @@ function registerBoxCommands(program3) {
24427
24678
  }
24428
24679
  if (o.json) console.log(JSON.stringify({ box: found, incomplete }, null, 2));
24429
24680
  else if (o.ssh && o.script) {
24430
- (0, import_node_fs30.writeFileSync)(o.script, sshRecipeScript(found), "utf8");
24681
+ (0, import_node_fs31.writeFileSync)(o.script, sshRecipeScript(found), "utf8");
24431
24682
  console.log(`wrote ${o.script} \u2014 run: bash "${o.script}"`);
24432
24683
  } else if (o.ssh) console.log(`${formatSshRecipe(found)}
24433
24684
  ${SSH_RECIPE_AGENT_NOTE}`);
@@ -25193,7 +25444,7 @@ function registerSchedulesCommands(program3) {
25193
25444
 
25194
25445
  // src/schedules-lift-command.ts
25195
25446
  var import_promises6 = require("node:fs/promises");
25196
- var import_node_path28 = require("node:path");
25447
+ var import_node_path29 = require("node:path");
25197
25448
 
25198
25449
  // src/schedules-lift.ts
25199
25450
  var SCHEDULE_HEADER_FIELDS = ["schedule", "what", "owner", "cadence", "executor", "llm", "output", "breaks", "kill"];
@@ -25299,7 +25550,7 @@ async function readWorkflowFiles(dir) {
25299
25550
  const files = [];
25300
25551
  for (const name of names.sort()) {
25301
25552
  if (!/\.ya?ml$/.test(name)) continue;
25302
- files.push({ path: `.github/workflows/${name}`, text: await (0, import_promises6.readFile)((0, import_node_path28.join)(dir, name), "utf8") });
25553
+ files.push({ path: `.github/workflows/${name}`, text: await (0, import_promises6.readFile)((0, import_node_path29.join)(dir, name), "utf8") });
25303
25554
  }
25304
25555
  return files;
25305
25556
  }
@@ -25994,9 +26245,9 @@ function registerQueryCommands(program3) {
25994
26245
  }
25995
26246
 
25996
26247
  // src/bootstrap-commands.ts
25997
- var import_node_fs31 = require("node:fs");
25998
- var import_node_os11 = require("node:os");
25999
- var import_node_path29 = require("node:path");
26248
+ var import_node_fs32 = require("node:fs");
26249
+ var import_node_os12 = require("node:os");
26250
+ var import_node_path30 = require("node:path");
26000
26251
 
26001
26252
  // src/bootstrap-drift.ts
26002
26253
  var import_node_crypto6 = require("node:crypto");
@@ -26900,13 +27151,13 @@ function registerBootstrapCommands(program3) {
26900
27151
  client: defaultGitHubClient(),
26901
27152
  projectMeta: meta,
26902
27153
  deployModel: typeof meta?.deployModel === "string" ? meta.deployModel : void 0,
26903
- readLocalFile: (path2) => path2 === "projects.json" && apiProjects != null ? apiProjects : (0, import_node_fs31.existsSync)(path2) ? (0, import_node_fs31.readFileSync)(path2, "utf8") : null,
27154
+ readLocalFile: (path2) => path2 === "projects.json" && apiProjects != null ? apiProjects : (0, import_node_fs32.existsSync)(path2) ? (0, import_node_fs32.readFileSync)(path2, "utf8") : null,
26904
27155
  // requiredGcpApis is stored as an array by a JSON write, but `org project set --var KEY=VALUE` stores a raw
26905
27156
  // comma-string — accept either so the seeded value verifies regardless of how it was written.
26906
27157
  // #3689: the same committed map the org access audit reads (#3664), so a sanctioned admin is not a
26907
27158
  // permanent bootstrap failure on one surface and an intended state on the other. Absent file → no
26908
27159
  // sanction, which is the pre-#3664 behaviour.
26909
- sanctionedAdmins: (0, import_node_fs31.existsSync)("access-matrix.json") ? entriesValueByCanonicalRepo(loadSanctionedAdmins((0, import_node_fs31.readFileSync)("access-matrix.json", "utf8")), repo) : void 0,
27160
+ sanctionedAdmins: (0, import_node_fs32.existsSync)("access-matrix.json") ? entriesValueByCanonicalRepo(loadSanctionedAdmins((0, import_node_fs32.readFileSync)("access-matrix.json", "utf8")), repo) : void 0,
26910
27161
  requiredGcpApis: (() => {
26911
27162
  const v = meta?.requiredGcpApis;
26912
27163
  if (Array.isArray(v)) return v;
@@ -26959,14 +27210,14 @@ function registerBootstrapCommands(program3) {
26959
27210
  bootstrap.command("drift").description("#3818: compare every org-owned whole-file seed against MMI-Hub's copy across the registry roster; read-only").option("--repo <owner/repo>", "audit one repo instead of the roster (never a fleet verdict)").option("--json", "machine-readable output").action(async () => {
26960
27211
  const o = { repo: rawValue("--repo", ""), json: rawFlag("--json") };
26961
27212
  const manifestPath = "skills/bootstrap/seeds/manifest.json";
26962
- if (!(0, import_node_fs31.existsSync)(manifestPath)) return fail(`bootstrap drift: ${manifestPath} not found; run from the MMI-Hub repo root \u2014 the Hub's copies ARE the reference this compares against`);
27213
+ if (!(0, import_node_fs32.existsSync)(manifestPath)) return fail(`bootstrap drift: ${manifestPath} not found; run from the MMI-Hub repo root \u2014 the Hub's copies ARE the reference this compares against`);
26963
27214
  const seedSource = await resolveHubSeedSource(execGitForSeedSource);
26964
27215
  if (!seedSource.ok) return fail(`bootstrap drift: ${seedSource.reason}`);
26965
- const manifest = loadBootstrapSeeds((0, import_node_fs31.readFileSync)(manifestPath, "utf8"));
27216
+ const manifest = loadBootstrapSeeds((0, import_node_fs32.readFileSync)(manifestPath, "utf8"));
26966
27217
  const hubContents = /* @__PURE__ */ new Map();
26967
27218
  for (const s of manifest.seeds) {
26968
27219
  if (s.ownership !== "org" || s.source !== "self") continue;
26969
- hubContents.set(s.target, (0, import_node_fs31.existsSync)(s.target) ? (0, import_node_fs31.readFileSync)(s.target, "utf8") : null);
27220
+ hubContents.set(s.target, (0, import_node_fs32.existsSync)(s.target) ? (0, import_node_fs32.readFileSync)(s.target, "utf8") : null);
26970
27221
  }
26971
27222
  let targets;
26972
27223
  let classOf = (_repo) => "deployable";
@@ -27045,10 +27296,10 @@ function registerBootstrapCommands(program3) {
27045
27296
  return fail(`bootstrap apply: ${e.message}`);
27046
27297
  }
27047
27298
  const manifestPath = "skills/bootstrap/seeds/manifest.json";
27048
- if (!(0, import_node_fs31.existsSync)(manifestPath)) return fail(`bootstrap apply: ${manifestPath} not found; bootstrap runs from the MMI-Hub repo root by design \u2014 it stamps org-level resources (Project, Ruleset, secrets, access) through the GitHub App, which is only authorized from the Hub checkout`);
27299
+ if (!(0, import_node_fs32.existsSync)(manifestPath)) return fail(`bootstrap apply: ${manifestPath} not found; bootstrap runs from the MMI-Hub repo root by design \u2014 it stamps org-level resources (Project, Ruleset, secrets, access) through the GitHub App, which is only authorized from the Hub checkout`);
27049
27300
  const seedSource = await resolveHubSeedSource(execGitForSeedSource);
27050
27301
  if (!seedSource.ok) return fail(`bootstrap apply: ${seedSource.reason}`);
27051
- const manifest = loadBootstrapSeeds((0, import_node_fs31.readFileSync)(manifestPath, "utf8"));
27302
+ const manifest = loadBootstrapSeeds((0, import_node_fs32.readFileSync)(manifestPath, "utf8"));
27052
27303
  const baseBranch = o.class === "content" ? "main" : "development";
27053
27304
  const slug = parsedRepo.slug;
27054
27305
  const onlyTarget = o.only.trim();
@@ -27059,16 +27310,16 @@ function registerBootstrapCommands(program3) {
27059
27310
  ${known}`);
27060
27311
  }
27061
27312
  const gh = async (args) => execFileP2("gh", args, { timeout: 2e4 });
27062
- const readFile9 = (p) => (0, import_node_fs31.existsSync)(p) ? (0, import_node_fs31.readFileSync)(p, "utf8") : null;
27313
+ const readFile9 = (p) => (0, import_node_fs32.existsSync)(p) ? (0, import_node_fs32.readFileSync)(p, "utf8") : null;
27063
27314
  const enc = (p) => p.split("/").map(encodeURIComponent).join("/");
27064
27315
  const putSeed = async (target, content, ref, sha) => {
27065
- const tmp = (0, import_node_path29.join)((0, import_node_os11.tmpdir)(), `mmi-seed-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
27066
- (0, import_node_fs31.writeFileSync)(tmp, JSON.stringify(contentPutBody(target, content, ref, sha)), "utf8");
27316
+ const tmp = (0, import_node_path30.join)((0, import_node_os12.tmpdir)(), `mmi-seed-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
27317
+ (0, import_node_fs32.writeFileSync)(tmp, JSON.stringify(contentPutBody(target, content, ref, sha)), "utf8");
27067
27318
  try {
27068
27319
  await gh(contentPutInputArgs(repo, target, tmp));
27069
27320
  } finally {
27070
27321
  try {
27071
- (0, import_node_fs31.unlinkSync)(tmp);
27322
+ (0, import_node_fs32.unlinkSync)(tmp);
27072
27323
  } catch {
27073
27324
  }
27074
27325
  }
@@ -27333,10 +27584,10 @@ LIVE apply to ${repo}:
27333
27584
  bootstrap.command("propagate").description("#4238: re-entrant canary\u2192wave tick \u2014 plan (or, with --execute, open) per-repo PRs fanning an org-owned seed out to the fleet").option("--target <path>", "the manifest target to propagate (an ownership:org + source:self seed, e.g. .github/workflows/agent-pr.yml)").option("--execute", "LIVE tick via gh (master-gated) \u2014 opens/reuses per-repo seed-propagate PRs; dry-run prints the plan only").option("--json", "machine-readable output").action(async () => {
27334
27585
  const o = { target: rawValue("--target", ""), execute: rawFlag("--execute"), json: rawFlag("--json") };
27335
27586
  const manifestPath = "skills/bootstrap/seeds/manifest.json";
27336
- if (!(0, import_node_fs31.existsSync)(manifestPath)) return fail(`bootstrap propagate: ${manifestPath} not found; run from the MMI-Hub repo root \u2014 the Hub's copies ARE the desired state this tick propagates`);
27587
+ if (!(0, import_node_fs32.existsSync)(manifestPath)) return fail(`bootstrap propagate: ${manifestPath} not found; run from the MMI-Hub repo root \u2014 the Hub's copies ARE the desired state this tick propagates`);
27337
27588
  const seedSource = await resolveHubSeedSource(execGitForSeedSource);
27338
27589
  if (!seedSource.ok) return fail(`bootstrap propagate: ${seedSource.reason}`);
27339
- const manifest = loadBootstrapSeeds((0, import_node_fs31.readFileSync)(manifestPath, "utf8"));
27590
+ const manifest = loadBootstrapSeeds((0, import_node_fs32.readFileSync)(manifestPath, "utf8"));
27340
27591
  const propagatable = manifest.seeds.filter((s) => s.ownership === "org" && s.source === "self");
27341
27592
  if (!o.target) {
27342
27593
  return fail(`bootstrap propagate: --target <path> is required \u2014 one of:
@@ -27345,8 +27596,8 @@ LIVE apply to ${repo}:
27345
27596
  const seed = propagatable.find((s) => s.target === o.target);
27346
27597
  if (!seed) return fail(`bootstrap propagate: --target '${o.target}' names no ownership:org + source:self seed in ${manifestPath}. Propagatable targets:
27347
27598
  ${propagatable.map((s) => s.target).join("\n ")}`);
27348
- if (!(0, import_node_fs31.existsSync)(seed.target)) return fail(`bootstrap propagate: the Hub's own copy of '${seed.target}' is missing \u2014 nothing to propagate`);
27349
- const hubContent = (0, import_node_fs31.readFileSync)(seed.target, "utf8");
27599
+ if (!(0, import_node_fs32.existsSync)(seed.target)) return fail(`bootstrap propagate: the Hub's own copy of '${seed.target}' is missing \u2014 nothing to propagate`);
27600
+ const hubContent = (0, import_node_fs32.readFileSync)(seed.target, "utf8");
27350
27601
  const isWorkflowSeed = seed.target.startsWith(".github/workflows/");
27351
27602
  const cfg = await loadConfig();
27352
27603
  const projects = await fetchProjectsList(registryClientDeps(cfg));
@@ -27355,9 +27606,9 @@ LIVE apply to ${repo}:
27355
27606
  }
27356
27607
  const rosterRepos2 = collectRegistryRepos(projects).filter((r) => r.toLowerCase() !== "mutmutco/mmi-hub");
27357
27608
  let independentCount = rosterRepos2.length;
27358
- if ((0, import_node_fs31.existsSync)("projects.json")) {
27609
+ if ((0, import_node_fs32.existsSync)("projects.json")) {
27359
27610
  try {
27360
- const local = JSON.parse((0, import_node_fs31.readFileSync)("projects.json", "utf8"));
27611
+ const local = JSON.parse((0, import_node_fs32.readFileSync)("projects.json", "utf8"));
27361
27612
  const localRepos = /* @__PURE__ */ new Set();
27362
27613
  for (const p of local.projects ?? []) for (const r of p.repos ?? []) {
27363
27614
  const full = (r.includes("/") ? r : `mutmutco/${r}`).toLowerCase();
@@ -27473,13 +27724,13 @@ LIVE apply to ${repo}:
27473
27724
  } catch {
27474
27725
  existingSha = void 0;
27475
27726
  }
27476
- const tmp = (0, import_node_path29.join)((0, import_node_os11.tmpdir)(), `mmi-propagate-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
27477
- (0, import_node_fs31.writeFileSync)(tmp, JSON.stringify(contentPutBody(seed.target, hubContent, branch, existingSha)), "utf8");
27727
+ const tmp = (0, import_node_path30.join)((0, import_node_os12.tmpdir)(), `mmi-propagate-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
27728
+ (0, import_node_fs32.writeFileSync)(tmp, JSON.stringify(contentPutBody(seed.target, hubContent, branch, existingSha)), "utf8");
27478
27729
  try {
27479
27730
  await gh(contentPutInputArgs(rec.repo, seed.target, tmp));
27480
27731
  } finally {
27481
27732
  try {
27482
- (0, import_node_fs31.unlinkSync)(tmp);
27733
+ (0, import_node_fs32.unlinkSync)(tmp);
27483
27734
  } catch {
27484
27735
  }
27485
27736
  }
@@ -27537,10 +27788,10 @@ Rollback: \`mmi-cli bootstrap rollback ${rec.repo} --target ${seed.target} --exe
27537
27788
  return fail(`bootstrap rollback: ${e.message}`);
27538
27789
  }
27539
27790
  const manifestPath = "skills/bootstrap/seeds/manifest.json";
27540
- if (!(0, import_node_fs31.existsSync)(manifestPath)) return fail(`bootstrap rollback: ${manifestPath} not found; run from the MMI-Hub repo root \u2014 the manifest names which targets are org-owned and therefore propagated (and rollback-able)`);
27791
+ if (!(0, import_node_fs32.existsSync)(manifestPath)) return fail(`bootstrap rollback: ${manifestPath} not found; run from the MMI-Hub repo root \u2014 the manifest names which targets are org-owned and therefore propagated (and rollback-able)`);
27541
27792
  const seedSource = await resolveHubSeedSource(execGitForSeedSource);
27542
27793
  if (!seedSource.ok) return fail(`bootstrap rollback: ${seedSource.reason}`);
27543
- const manifest = loadBootstrapSeeds((0, import_node_fs31.readFileSync)(manifestPath, "utf8"));
27794
+ const manifest = loadBootstrapSeeds((0, import_node_fs32.readFileSync)(manifestPath, "utf8"));
27544
27795
  const propagatable = manifest.seeds.filter((s) => s.ownership === "org" && s.source === "self");
27545
27796
  if (!o.target) {
27546
27797
  return fail(`bootstrap rollback: --target <path> is required \u2014 one of:
@@ -27557,10 +27808,10 @@ Rollback: \`mmi-cli bootstrap rollback ${rec.repo} --target ${seed.target} --exe
27557
27808
  const enc = (p) => p.split("/").map(encodeURIComponent).join("/");
27558
27809
  let candidates;
27559
27810
  if (o.record) {
27560
- if (!(0, import_node_fs31.existsSync)(o.record)) return fail(`bootstrap rollback: --record '${o.record}' not found`);
27811
+ if (!(0, import_node_fs32.existsSync)(o.record)) return fail(`bootstrap rollback: --record '${o.record}' not found`);
27561
27812
  let parsed;
27562
27813
  try {
27563
- parsed = JSON.parse((0, import_node_fs31.readFileSync)(o.record, "utf8"));
27814
+ parsed = JSON.parse((0, import_node_fs32.readFileSync)(o.record, "utf8"));
27564
27815
  } catch (e) {
27565
27816
  return fail(`bootstrap rollback: --record '${o.record}' is not valid JSON: ${e.message}`);
27566
27817
  }
@@ -27629,13 +27880,13 @@ Rollback: \`mmi-cli bootstrap rollback ${rec.repo} --target ${seed.target} --exe
27629
27880
  } catch {
27630
27881
  existingSha = void 0;
27631
27882
  }
27632
- const tmp = (0, import_node_path29.join)((0, import_node_os11.tmpdir)(), `mmi-rollback-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
27633
- (0, import_node_fs31.writeFileSync)(tmp, JSON.stringify(contentPutBody(seed.target, preSeedContent, plan.branch, existingSha)), "utf8");
27883
+ const tmp = (0, import_node_path30.join)((0, import_node_os12.tmpdir)(), `mmi-rollback-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
27884
+ (0, import_node_fs32.writeFileSync)(tmp, JSON.stringify(contentPutBody(seed.target, preSeedContent, plan.branch, existingSha)), "utf8");
27634
27885
  try {
27635
27886
  await gh(contentPutInputArgs(repo, seed.target, tmp));
27636
27887
  } finally {
27637
27888
  try {
27638
- (0, import_node_fs31.unlinkSync)(tmp);
27889
+ (0, import_node_fs32.unlinkSync)(tmp);
27639
27890
  } catch {
27640
27891
  }
27641
27892
  }
@@ -27657,12 +27908,12 @@ Rollback: \`mmi-cli bootstrap rollback ${rec.repo} --target ${seed.target} --exe
27657
27908
  }
27658
27909
 
27659
27910
  // src/stage-commands.ts
27660
- var import_node_fs33 = require("node:fs");
27661
- var import_node_path31 = require("node:path");
27911
+ var import_node_fs34 = require("node:fs");
27912
+ var import_node_path32 = require("node:path");
27662
27913
 
27663
27914
  // src/port-registry.ts
27664
- var import_node_fs32 = require("node:fs");
27665
- var import_node_path30 = require("node:path");
27915
+ var import_node_fs33 = require("node:fs");
27916
+ var import_node_path31 = require("node:path");
27666
27917
 
27667
27918
  // ../infra/port-geometry.mjs
27668
27919
  var PORT_BLOCK = 100;
@@ -27676,8 +27927,8 @@ function nextPortBlock(registry2) {
27676
27927
  return [base, base + PORT_SPAN];
27677
27928
  }
27678
27929
  function loadPortRegistry(path2) {
27679
- if (!(0, import_node_fs32.existsSync)(path2)) return {};
27680
- const raw = JSON.parse((0, import_node_fs32.readFileSync)(path2, "utf8"));
27930
+ if (!(0, import_node_fs33.existsSync)(path2)) return {};
27931
+ const raw = JSON.parse((0, import_node_fs33.readFileSync)(path2, "utf8"));
27681
27932
  const out = {};
27682
27933
  for (const [key, value] of Object.entries(raw)) {
27683
27934
  if (Array.isArray(value) && value.length === 2 && value.every((n) => typeof n === "number")) {
@@ -27691,9 +27942,9 @@ function ensurePortRange(repo, path2) {
27691
27942
  const existing = registry2[repo];
27692
27943
  if (existing) return existing;
27693
27944
  const range = nextPortBlock(registry2);
27694
- const raw = (0, import_node_fs32.existsSync)(path2) ? JSON.parse((0, import_node_fs32.readFileSync)(path2, "utf8")) : {};
27945
+ const raw = (0, import_node_fs33.existsSync)(path2) ? JSON.parse((0, import_node_fs33.readFileSync)(path2, "utf8")) : {};
27695
27946
  raw[repo] = range;
27696
- (0, import_node_fs32.writeFileSync)(path2, JSON.stringify(raw, null, 2) + "\n", "utf8");
27947
+ (0, import_node_fs33.writeFileSync)(path2, JSON.stringify(raw, null, 2) + "\n", "utf8");
27697
27948
  return range;
27698
27949
  }
27699
27950
  function portCursorSeed(registry2) {
@@ -27715,22 +27966,22 @@ function existingPortRange(repo, registry2) {
27715
27966
  return registry2[repo] ?? null;
27716
27967
  }
27717
27968
  function portRangeInfraAt(root, source) {
27718
- const registryPath = (0, import_node_path30.join)(root, "infra", "port-ranges.json");
27719
- const ddbScriptPath = (0, import_node_path30.join)(root, "infra", "port-ddb.mjs");
27720
- if (!(0, import_node_fs32.existsSync)(registryPath) || !(0, import_node_fs32.existsSync)(ddbScriptPath)) return null;
27969
+ const registryPath = (0, import_node_path31.join)(root, "infra", "port-ranges.json");
27970
+ const ddbScriptPath = (0, import_node_path31.join)(root, "infra", "port-ddb.mjs");
27971
+ if (!(0, import_node_fs33.existsSync)(registryPath) || !(0, import_node_fs33.existsSync)(ddbScriptPath)) return null;
27721
27972
  return { root, source, registryPath, ddbScriptPath };
27722
27973
  }
27723
27974
  function resolvePortRangeInfra(cwd, packageDir) {
27724
27975
  const direct = portRangeInfraAt(cwd, "cwd");
27725
27976
  if (direct) return direct;
27726
- for (let dir = cwd; ; dir = (0, import_node_path30.dirname)(dir)) {
27727
- const sibling = portRangeInfraAt((0, import_node_path30.join)(dir, "MMI-Hub"), "sibling-hub");
27977
+ for (let dir = cwd; ; dir = (0, import_node_path31.dirname)(dir)) {
27978
+ const sibling = portRangeInfraAt((0, import_node_path31.join)(dir, "MMI-Hub"), "sibling-hub");
27728
27979
  if (sibling) return sibling;
27729
- const parent = (0, import_node_path30.dirname)(dir);
27980
+ const parent = (0, import_node_path31.dirname)(dir);
27730
27981
  if (parent === dir) break;
27731
27982
  }
27732
27983
  if (packageDir) {
27733
- const pkgRoot = (0, import_node_path30.join)(packageDir, "..", "..");
27984
+ const pkgRoot = (0, import_node_path31.join)(packageDir, "..", "..");
27734
27985
  const pkgFrom = portRangeInfraAt(pkgRoot, "pkg-root");
27735
27986
  if (pkgFrom) return pkgFrom;
27736
27987
  }
@@ -27924,8 +28175,8 @@ function registerStageCommands(program3) {
27924
28175
  const portRange = portRangeMeta && typeof portRangeMeta.start === "number" && typeof portRangeMeta.end === "number" ? [portRangeMeta.start, portRangeMeta.end] : void 0;
27925
28176
  return decideStage({
27926
28177
  registry: { deployModel: project2?.deployModel, portRange, error: read.ok ? void 0 : read.error },
27927
- hasCompose: (0, import_node_fs33.existsSync)((0, import_node_path31.join)(process.cwd(), "docker-compose.yml")),
27928
- hasEnvExample: (0, import_node_fs33.existsSync)((0, import_node_path31.join)(process.cwd(), ".env.example"))
28178
+ hasCompose: (0, import_node_fs34.existsSync)((0, import_node_path32.join)(process.cwd(), "docker-compose.yml")),
28179
+ hasEnvExample: (0, import_node_fs34.existsSync)((0, import_node_path32.join)(process.cwd(), ".env.example"))
27929
28180
  });
27930
28181
  }
27931
28182
  async function fetchStageVaultEnvMerge() {
@@ -28383,10 +28634,10 @@ function registerBoardCommands(program3) {
28383
28634
  }
28384
28635
 
28385
28636
  // src/merge-cleanup.ts
28386
- var import_node_fs35 = require("node:fs");
28637
+ var import_node_fs36 = require("node:fs");
28387
28638
  var import_promises8 = require("node:fs/promises");
28388
- var import_node_path34 = require("node:path");
28389
- var import_node_os13 = require("node:os");
28639
+ var import_node_path35 = require("node:path");
28640
+ var import_node_os14 = require("node:os");
28390
28641
  var import_node_child_process17 = require("node:child_process");
28391
28642
 
28392
28643
  // src/board-advance.ts
@@ -28473,7 +28724,7 @@ function boardAdvanceFailureMessage(result) {
28473
28724
 
28474
28725
  // src/deferred-registry-store.ts
28475
28726
  var import_promises7 = require("node:fs/promises");
28476
- var import_node_path32 = require("node:path");
28727
+ var import_node_path33 = require("node:path");
28477
28728
  var sleep2 = (ms) => new Promise((resolve5) => setTimeout(resolve5, ms));
28478
28729
  async function atomicWrite(target, contents) {
28479
28730
  const tmp = `${target}.tmp-${process.pid}-${Math.random().toString(36).slice(2)}`;
@@ -28524,12 +28775,12 @@ function makeDeferredWorktreeStore(registryPath, lockOpts = {}) {
28524
28775
  },
28525
28776
  // Standalone atomic write — THROWS on failure (no best-effort swallow, #2846).
28526
28777
  write: async (entries) => {
28527
- await (0, import_promises7.mkdir)((0, import_node_path32.dirname)(registryPath), { recursive: true });
28778
+ await (0, import_promises7.mkdir)((0, import_node_path33.dirname)(registryPath), { recursive: true });
28528
28779
  await atomicWrite(registryPath, serializeDeferredWorktrees(entries));
28529
28780
  },
28530
28781
  // Serialized read-modify-write under the repo-wide lock (#2846).
28531
28782
  update: async (mutate) => {
28532
- await (0, import_promises7.mkdir)((0, import_node_path32.dirname)(registryPath), { recursive: true });
28783
+ await (0, import_promises7.mkdir)((0, import_node_path33.dirname)(registryPath), { recursive: true });
28533
28784
  const deadline = Date.now() + opts.maxWaitMs;
28534
28785
  for (; ; ) {
28535
28786
  const guard = await acquireLock(lockPath, opts, deadline);
@@ -28553,15 +28804,15 @@ function makeDeferredWorktreeStore(registryPath, lockOpts = {}) {
28553
28804
  }
28554
28805
 
28555
28806
  // src/jerv-cli-spawn.ts
28556
- var import_node_fs34 = require("node:fs");
28557
- var import_node_os12 = require("node:os");
28558
- var import_node_path33 = require("node:path");
28807
+ var import_node_fs35 = require("node:fs");
28808
+ var import_node_os13 = require("node:os");
28809
+ var import_node_path34 = require("node:path");
28559
28810
  var WIN_NAMES = ["jerv-cli.cmd", "jerv-cli.exe", "jerv-cli"];
28560
28811
  var POSIX_NAMES = ["jerv-cli"];
28561
- var JERV_CLI_ENTRY = (0, import_node_path33.join)("node_modules", "@jervaise", "jerv-cli", "dist", "index.cjs");
28812
+ var JERV_CLI_ENTRY = (0, import_node_path34.join)("node_modules", "@jervaise", "jerv-cli", "dist", "index.cjs");
28562
28813
  function pathEnvEntries(pathEnv, platform2 = process.platform) {
28563
28814
  if (platform2 !== "win32") {
28564
- return pathEnv.split(import_node_path33.delimiter).map((e) => e.trim()).filter(Boolean);
28815
+ return pathEnv.split(import_node_path34.delimiter).map((e) => e.trim()).filter(Boolean);
28565
28816
  }
28566
28817
  if (pathEnv.includes(";")) {
28567
28818
  return pathEnv.split(";").map((e) => e.trim()).filter(Boolean);
@@ -28580,7 +28831,7 @@ function normalizeSpawnPathEntry(entry, platform2 = process.platform) {
28580
28831
  if (msys) return `${msys[1].toUpperCase()}:\\${msys[2].replace(/\//g, "\\")}`;
28581
28832
  return trimmed;
28582
28833
  }
28583
- function jervCliCandidateDirs(env = process.env, home = (0, import_node_os12.homedir)(), platform2 = process.platform) {
28834
+ function jervCliCandidateDirs(env = process.env, home = (0, import_node_os13.homedir)(), platform2 = process.platform) {
28584
28835
  const seen = /* @__PURE__ */ new Set();
28585
28836
  const out = [];
28586
28837
  const push = (dir) => {
@@ -28594,35 +28845,35 @@ function jervCliCandidateDirs(env = process.env, home = (0, import_node_os12.hom
28594
28845
  push(normalizeSpawnPathEntry(entry, platform2));
28595
28846
  }
28596
28847
  if (platform2 === "win32") {
28597
- if (env.APPDATA) push((0, import_node_path33.join)(env.APPDATA, "npm"));
28598
- if (env.LOCALAPPDATA) push((0, import_node_path33.join)(env.LOCALAPPDATA, "npm"));
28848
+ if (env.APPDATA) push((0, import_node_path34.join)(env.APPDATA, "npm"));
28849
+ if (env.LOCALAPPDATA) push((0, import_node_path34.join)(env.LOCALAPPDATA, "npm"));
28599
28850
  } else {
28600
- push((0, import_node_path33.join)(home, ".local", "bin"));
28851
+ push((0, import_node_path34.join)(home, ".local", "bin"));
28601
28852
  }
28602
28853
  return out;
28603
28854
  }
28604
- function jervCliCandidatePaths(env = process.env, home = (0, import_node_os12.homedir)(), platform2 = process.platform) {
28855
+ function jervCliCandidatePaths(env = process.env, home = (0, import_node_os13.homedir)(), platform2 = process.platform) {
28605
28856
  const names = platform2 === "win32" ? WIN_NAMES : POSIX_NAMES;
28606
28857
  const out = [];
28607
28858
  for (const dir of jervCliCandidateDirs(env, home, platform2)) {
28608
- for (const name of names) out.push((0, import_node_path33.join)(dir, name));
28859
+ for (const name of names) out.push((0, import_node_path34.join)(dir, name));
28609
28860
  }
28610
28861
  return out;
28611
28862
  }
28612
- function resolveJervCliPath(env = process.env, home = (0, import_node_os12.homedir)(), platform2 = process.platform, exists = import_node_fs34.existsSync) {
28863
+ function resolveJervCliPath(env = process.env, home = (0, import_node_os13.homedir)(), platform2 = process.platform, exists = import_node_fs35.existsSync) {
28613
28864
  for (const candidate of jervCliCandidatePaths(env, home, platform2)) {
28614
28865
  if (exists(candidate)) return candidate;
28615
28866
  }
28616
28867
  return void 0;
28617
28868
  }
28618
- function resolveJervCliNodeEntry(shimPath, exists = import_node_fs34.existsSync) {
28619
- const entry = (0, import_node_path33.join)((0, import_node_path33.dirname)(shimPath), JERV_CLI_ENTRY);
28869
+ function resolveJervCliNodeEntry(shimPath, exists = import_node_fs35.existsSync) {
28870
+ const entry = (0, import_node_path34.join)((0, import_node_path34.dirname)(shimPath), JERV_CLI_ENTRY);
28620
28871
  return exists(entry) ? entry : void 0;
28621
28872
  }
28622
28873
  function jervCliExecFileArgs(args, opts = {}) {
28623
28874
  const platform2 = opts.platform ?? process.platform;
28624
- const exists = opts.exists ?? import_node_fs34.existsSync;
28625
- const resolved = resolveJervCliPath(opts.env ?? process.env, opts.home ?? (0, import_node_os12.homedir)(), platform2, exists);
28875
+ const exists = opts.exists ?? import_node_fs35.existsSync;
28876
+ const resolved = resolveJervCliPath(opts.env ?? process.env, opts.home ?? (0, import_node_os13.homedir)(), platform2, exists);
28626
28877
  if (resolved) {
28627
28878
  const entry = resolveJervCliNodeEntry(resolved, exists);
28628
28879
  if (entry) {
@@ -28805,12 +29056,31 @@ async function applyGcPlan(plan, remote, opts = {}) {
28805
29056
  );
28806
29057
  const repoRoot2 = (await execFileP2("git", ["rev-parse", "--show-toplevel"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim() || process.cwd();
28807
29058
  const worktreeGitRoot = await currentRepoWorktreeGitRoot(repoRoot2);
28808
- const primaryRepoRoot = worktreeGitRoot ? (0, import_node_path34.dirname)((0, import_node_path34.dirname)(worktreeGitRoot)) : repoRoot2;
29059
+ const primaryRepoRoot = worktreeGitRoot ? (0, import_node_path35.dirname)((0, import_node_path35.dirname)(worktreeGitRoot)) : repoRoot2;
28809
29060
  const gcActor = describeActor({ env: process.env, surface: detectSurface(process.env), cwd: process.cwd() });
28810
29061
  const owners = readWorktreeOwners(primaryRepoRoot);
28811
29062
  const removalNow = Date.now();
28812
- const refusesRemoval = (path2) => {
29063
+ const activeWorkspaceRoot = resolveActiveWorkspaceRoot();
29064
+ const deferredStore = await createDeferredWorktreeStore();
29065
+ const activeWorkspaceDeferred = [];
29066
+ const refusesRemoval = (path2, branch) => {
28813
29067
  if (!path2) return false;
29068
+ const activeGuard = decideActiveWorkspaceGuard(path2, activeWorkspaceRoot);
29069
+ if (activeGuard.action === "refuse") {
29070
+ result.refused.push(activeGuard.message);
29071
+ const owner2 = findWorktreeOwner(owners, path2);
29072
+ recordWorktreeRemoval(primaryRepoRoot, {
29073
+ action: "refused",
29074
+ command: "worktree gc",
29075
+ target: path2,
29076
+ branch: branch ?? owner2?.branch,
29077
+ actor: gcActor,
29078
+ owner: owner2,
29079
+ reason: activeGuard.message
29080
+ });
29081
+ activeWorkspaceDeferred.push({ path: path2, branch: branch ?? owner2?.branch ?? "(unknown)" });
29082
+ return true;
29083
+ }
28814
29084
  const owner = findWorktreeOwner(owners, path2);
28815
29085
  const verdict = decideWorktreeRemoval({ path: path2, owner, actor: gcActor, now: removalNow, force: opts.force });
28816
29086
  if (verdict.action !== "refuse") return false;
@@ -28826,9 +29096,16 @@ async function applyGcPlan(plan, remote, opts = {}) {
28826
29096
  });
28827
29097
  return true;
28828
29098
  };
28829
- const branchesToClean = plan.branches.filter((b) => !refusesRemoval(b.worktreePath));
29099
+ const branchesToClean = plan.branches.filter((b) => !refusesRemoval(b.worktreePath, b.branch));
28830
29100
  const worktreeDirsToRemove = plan.worktreeDirs.filter((d) => !refusesRemoval(d.path));
28831
- const deferredStore = await createDeferredWorktreeStore();
29101
+ if (deferredStore) {
29102
+ for (const entry of activeWorkspaceDeferred) {
29103
+ try {
29104
+ await registerDeferredWorktree(deferredStore, { ...entry, reason: "active-workspace" });
29105
+ } catch {
29106
+ }
29107
+ }
29108
+ }
28832
29109
  const branchTracking = await applyBranchAndTrackingCleanup({ ...plan, branches: branchesToClean }, {
28833
29110
  localBranchHeads,
28834
29111
  cleanupBranch: async (branch, expectedHeadOid) => {
@@ -28836,7 +29113,7 @@ async function applyGcPlan(plan, remote, opts = {}) {
28836
29113
  const cleanup = await cleanupPrMergeLocalBranch(branch.branch, {
28837
29114
  beforeWorktrees,
28838
29115
  startingPath: branch.worktreePath,
28839
- pathExists: (p) => (0, import_node_fs35.existsSync)(p),
29116
+ pathExists: (p) => (0, import_node_fs36.existsSync)(p),
28840
29117
  execGit: async (args) => (await execFileP2("git", args, { timeout: GIT_TIMEOUT_MS })).stdout,
28841
29118
  teardownWorktreeStage,
28842
29119
  deferredStore,
@@ -28844,7 +29121,13 @@ async function applyGcPlan(plan, remote, opts = {}) {
28844
29121
  detachReparsePoints: wtDeps.detachReparsePoints,
28845
29122
  // #3064: junction-safe teardown
28846
29123
  removeWorktreeDir: wtDeps.removeWorktreeDir,
28847
- removalContext: { primaryRoot: primaryRepoRoot, actor: gcActor, command: "worktree gc", force: opts.force }
29124
+ removalContext: {
29125
+ primaryRoot: primaryRepoRoot,
29126
+ actor: gcActor,
29127
+ command: "worktree gc",
29128
+ force: opts.force,
29129
+ activeWorkspaceRoot
29130
+ }
28848
29131
  });
28849
29132
  if (cleanup.worktree?.status === "removed") await bestEffortLeaseClose(cleanup.worktree.path);
28850
29133
  return cleanup;
@@ -28865,7 +29148,7 @@ async function applyGcPlan(plan, remote, opts = {}) {
28865
29148
  let removalAttempted = false;
28866
29149
  try {
28867
29150
  const cleanupTarget = resolveSafeSiblingWorktreeCleanupTarget(wt.path, siblingRoot, {
28868
- realpath: (path2) => (0, import_node_fs35.realpathSync)(path2)
29151
+ realpath: (path2) => (0, import_node_fs36.realpathSync)(path2)
28869
29152
  });
28870
29153
  if (!cleanupTarget.ok) {
28871
29154
  result.failed.push(`${wt.path}: ${cleanupTarget.reason}`);
@@ -28952,13 +29235,13 @@ async function composeOverrideBodyFile(prNumber, repoArgs, gh) {
28952
29235
  const commits = JSON.parse(raw).commits ?? [];
28953
29236
  const body = squashBodyWithOverride(commits.map((c) => ({ headline: c.messageHeadline ?? "", body: c.messageBody ?? "" })), process.cwd());
28954
29237
  if (!body) return void 0;
28955
- const dir = (0, import_node_fs35.mkdtempSync)((0, import_node_path34.join)((0, import_node_os13.tmpdir)(), "mmi-squash-body-"));
28956
- const path2 = (0, import_node_path34.join)(dir, "body.txt");
28957
- (0, import_node_fs35.writeFileSync)(path2, `${body}
29238
+ const dir = (0, import_node_fs36.mkdtempSync)((0, import_node_path35.join)((0, import_node_os14.tmpdir)(), "mmi-squash-body-"));
29239
+ const path2 = (0, import_node_path35.join)(dir, "body.txt");
29240
+ (0, import_node_fs36.writeFileSync)(path2, `${body}
28958
29241
  `, "utf8");
28959
29242
  return { path: path2, cleanup: () => {
28960
29243
  try {
28961
- (0, import_node_fs35.rmSync)(dir, { recursive: true, force: true });
29244
+ (0, import_node_fs36.rmSync)(dir, { recursive: true, force: true });
28962
29245
  } catch {
28963
29246
  }
28964
29247
  } };
@@ -29080,13 +29363,13 @@ var realWorktreeDirRemover = {
29080
29363
  probe: (p) => {
29081
29364
  let st;
29082
29365
  try {
29083
- st = (0, import_node_fs35.lstatSync)(p);
29366
+ st = (0, import_node_fs36.lstatSync)(p);
29084
29367
  } catch {
29085
29368
  return null;
29086
29369
  }
29087
29370
  if (st.isSymbolicLink()) return "link";
29088
29371
  try {
29089
- (0, import_node_fs35.readlinkSync)(p);
29372
+ (0, import_node_fs36.readlinkSync)(p);
29090
29373
  return "link";
29091
29374
  } catch {
29092
29375
  }
@@ -29094,7 +29377,7 @@ var realWorktreeDirRemover = {
29094
29377
  },
29095
29378
  readdir: (p) => {
29096
29379
  try {
29097
- return (0, import_node_fs35.readdirSync)(p);
29380
+ return (0, import_node_fs36.readdirSync)(p);
29098
29381
  } catch {
29099
29382
  return [];
29100
29383
  }
@@ -29103,9 +29386,9 @@ var realWorktreeDirRemover = {
29103
29386
  // leaving the target); a file symlink with unlink. rmdir first, fall back to unlink.
29104
29387
  detachLink: (p) => {
29105
29388
  try {
29106
- (0, import_node_fs35.rmdirSync)(p);
29389
+ (0, import_node_fs36.rmdirSync)(p);
29107
29390
  } catch {
29108
- (0, import_node_fs35.unlinkSync)(p);
29391
+ (0, import_node_fs36.unlinkSync)(p);
29109
29392
  }
29110
29393
  },
29111
29394
  removeTree: (p) => (0, import_promises8.rm)(p, { recursive: true, force: true, maxRetries: 5, retryDelay: 200 })
@@ -29138,11 +29421,11 @@ async function worktreeHasStageState(worktreePath) {
29138
29421
  }
29139
29422
  }
29140
29423
  function stageStateFileBelongsToWorktree(statePath, worktreePath) {
29141
- if (!(0, import_node_fs35.existsSync)(statePath)) return false;
29424
+ if (!(0, import_node_fs36.existsSync)(statePath)) return false;
29142
29425
  try {
29143
- const state = JSON.parse((0, import_node_fs35.readFileSync)(statePath, "utf8"));
29426
+ const state = JSON.parse((0, import_node_fs36.readFileSync)(statePath, "utf8"));
29144
29427
  const recordedCwd = typeof state.identity?.cwd === "string" ? state.identity.cwd : typeof state.cwd === "string" ? state.cwd : "";
29145
- return Boolean(recordedCwd && isPathUnderDirectory(recordedCwd, worktreePath));
29428
+ return Boolean(recordedCwd && isPathUnderDirectory2(recordedCwd, worktreePath));
29146
29429
  } catch {
29147
29430
  return false;
29148
29431
  }
@@ -29522,9 +29805,9 @@ async function checkDocsIndexAtHead(opts, deps) {
29522
29805
  }
29523
29806
 
29524
29807
  // src/worktree-lifecycle-commands.ts
29525
- var import_node_fs36 = require("node:fs");
29808
+ var import_node_fs37 = require("node:fs");
29526
29809
  var import_promises9 = require("node:fs/promises");
29527
- var import_node_path35 = require("node:path");
29810
+ var import_node_path36 = require("node:path");
29528
29811
  var GH_TIMEOUT_MS = 2e4;
29529
29812
  var STALE_PR_LOOKUP_LIMIT = 20;
29530
29813
  var DEFAULT_BASE = "origin/development";
@@ -29671,7 +29954,7 @@ function classifyStaleLeaks(input) {
29671
29954
  var defaultOrphanDirScanDeps = {
29672
29955
  listDirs: (root) => {
29673
29956
  try {
29674
- return (0, import_node_fs36.readdirSync)(root, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => (0, import_node_path35.join)(root, e.name));
29957
+ return (0, import_node_fs37.readdirSync)(root, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => (0, import_node_path36.join)(root, e.name));
29675
29958
  } catch {
29676
29959
  return [];
29677
29960
  }
@@ -29827,13 +30110,13 @@ function registerWorktreeCommands(program3) {
29827
30110
  const detached = headBorn && !symbolicBranch;
29828
30111
  const branch = symbolicBranch || (detached ? "HEAD" : "");
29829
30112
  if (!wtPath || !branch) return fail("worktree land: not inside a git worktree");
29830
- const gitFile = (0, import_node_path35.join)(wtPath, ".git");
29831
- const isLinked = (0, import_node_fs36.existsSync)(gitFile) && (0, import_node_fs36.statSync)(gitFile).isFile();
30113
+ const gitFile = (0, import_node_path36.join)(wtPath, ".git");
30114
+ const isLinked = (0, import_node_fs37.existsSync)(gitFile) && (0, import_node_fs37.statSync)(gitFile).isFile();
29832
30115
  if (apply && !isLinked) {
29833
30116
  return fail("worktree land: run from inside the linked worktree you want to land (this is the primary checkout)");
29834
30117
  }
29835
30118
  const commonDir = (await execFileP2("git", ["rev-parse", "--git-common-dir"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim();
29836
- const primaryCheckout = commonDir ? (0, import_node_path35.dirname)(commonDir) : wtPath;
30119
+ const primaryCheckout = commonDir ? (0, import_node_path36.dirname)(commonDir) : wtPath;
29837
30120
  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);
29838
30121
  const orphan = classifyOrphanedWorktree({
29839
30122
  branch,
@@ -29896,6 +30179,47 @@ function registerWorktreeCommands(program3) {
29896
30179
  if (landRefs.action === "keep-remote") console.warn(`worktree land: ${landRefs.message}.`);
29897
30180
  const reportedMergeState = treeOnly ? "not-checked" : mergeVerdict.state;
29898
30181
  const landOwner = lookupWorktreeOwner(primaryCheckout, wtPath);
30182
+ const activeWorkspaceRoot = resolveActiveWorkspaceRoot();
30183
+ const activeGuard = decideActiveWorkspaceGuard(wtPath, activeWorkspaceRoot);
30184
+ if (activeGuard.action === "refuse") {
30185
+ const deferredStore = await createDeferredWorktreeStore();
30186
+ if (deferredStore) {
30187
+ await registerDeferredWorktree(deferredStore, {
30188
+ path: toNativePath(wtPath),
30189
+ branch,
30190
+ reason: "active-workspace"
30191
+ }).catch(() => void 0);
30192
+ }
30193
+ const landActor2 = describeActor({ env: process.env, surface: detectSurface(process.env), cwd: wtPath });
30194
+ appendWorktreeEvent(primaryCheckout, {
30195
+ action: "refused",
30196
+ command: "worktree land",
30197
+ target: toNativePath(wtPath),
30198
+ branch,
30199
+ actor: landActor2,
30200
+ owner: landOwner ? { createdAt: landOwner.createdAt, lastSeenAt: landOwner.lastSeenAt, actor: landOwner.actor } : void 0,
30201
+ reason: activeGuard.message
30202
+ });
30203
+ const result2 = {
30204
+ dryRun: false,
30205
+ ...plan,
30206
+ ...o.keepRemote ? { keepRemote: true } : {},
30207
+ mergeState: reportedMergeState,
30208
+ prNumbers: mergeVerdict.numbers,
30209
+ cleanupState: "deferred",
30210
+ report: [
30211
+ { step: "remove worktree", status: `deferred: ${activeGuard.message}` },
30212
+ { step: "delete branch refs", status: "skipped: active Cursor workspace \u2014 open the primary checkout first" }
30213
+ ]
30214
+ };
30215
+ if (o.json) console.log(JSON.stringify(result2, null, 2));
30216
+ else {
30217
+ console.error(`worktree land: ${activeGuard.message}`);
30218
+ for (const row of result2.report) console.log(` ${row.step}: ${row.status}`);
30219
+ }
30220
+ process.exitCode = 1;
30221
+ return;
30222
+ }
29899
30223
  const report = [];
29900
30224
  if (hasStage) {
29901
30225
  try {
@@ -30042,10 +30366,10 @@ async function gatherWorktreeContext() {
30042
30366
  if (s) stages.push({ path: wt.path, port: s.port });
30043
30367
  }
30044
30368
  const worktreeGitRoot = await currentRepoWorktreeGitRoot(repoRoot2);
30045
- const primaryRepoRoot = worktreeGitRoot ? (0, import_node_path35.dirname)((0, import_node_path35.dirname)(worktreeGitRoot)) : repoRoot2;
30369
+ const primaryRepoRoot = worktreeGitRoot ? (0, import_node_path36.dirname)((0, import_node_path36.dirname)(worktreeGitRoot)) : repoRoot2;
30046
30370
  const wtRoot = siblingMmiWorktreesRoot(primaryRepoRoot);
30047
30371
  let orphanDirs = [];
30048
- if ((0, import_node_fs36.existsSync)(wtRoot)) {
30372
+ if ((0, import_node_fs37.existsSync)(wtRoot)) {
30049
30373
  orphanDirs = scanOrphanDirs(wtRoot, worktreeGitRoot, {
30050
30374
  ...defaultOrphanDirScanDeps,
30051
30375
  listDirs: (root) => worktreeScanDirs(root, primaryRepoRoot, defaultOrphanDirScanDeps.listDirs, isRepoCheckoutDir)
@@ -30071,7 +30395,7 @@ ${err.stderr ?? ""}`;
30071
30395
  }
30072
30396
 
30073
30397
  // src/issue-commands.ts
30074
- var import_node_fs37 = require("node:fs");
30398
+ var import_node_fs38 = require("node:fs");
30075
30399
  var import_node_crypto7 = require("node:crypto");
30076
30400
  var ghRunner = async (args, timeoutMs) => (await execFileP2("gh", args, { timeout: timeoutMs })).stdout;
30077
30401
  var ReparentConflictError = class extends Error {
@@ -30089,7 +30413,7 @@ async function editIssue(client, options, deps = {}) {
30089
30413
  const url = `https://github.com/${repo}/issues/${parsed.number}`;
30090
30414
  const patch = {};
30091
30415
  let bodyChanged = false;
30092
- const textDeps = () => deps.textDeps ?? { readFile: (p, e) => Promise.resolve((0, import_node_fs37.readFileSync)(p, e)), readStdin: () => Promise.resolve("") };
30416
+ const textDeps = () => deps.textDeps ?? { readFile: (p, e) => Promise.resolve((0, import_node_fs38.readFileSync)(p, e)), readStdin: () => Promise.resolve("") };
30093
30417
  if (options.titleFile !== void 0) {
30094
30418
  patch.title = await resolveIssueTitle({ title: options.title, titleFile: options.titleFile }, textDeps());
30095
30419
  } else if (options.title !== void 0) {
@@ -30694,7 +31018,7 @@ function extendCreateCommand(issue2, batchAttach) {
30694
31018
  if (opts.batch) {
30695
31019
  let specs;
30696
31020
  try {
30697
- const raw = (0, import_node_fs37.readFileSync)(opts.batch, "utf8");
31021
+ const raw = (0, import_node_fs38.readFileSync)(opts.batch, "utf8");
30698
31022
  specs = JSON.parse(raw);
30699
31023
  if (!Array.isArray(specs)) throw new Error("batch file must contain a JSON array");
30700
31024
  } catch (e) {
@@ -30769,8 +31093,8 @@ ${lines}`, {
30769
31093
  }
30770
31094
 
30771
31095
  // src/train-commands.ts
30772
- var import_node_fs38 = require("node:fs");
30773
- var import_node_path36 = require("node:path");
31096
+ var import_node_fs39 = require("node:fs");
31097
+ var import_node_path37 = require("node:path");
30774
31098
 
30775
31099
  // src/train-status.ts
30776
31100
  function buildTrainStatusReport(input) {
@@ -30810,7 +31134,7 @@ function formatTrainStatus(r) {
30810
31134
  // src/train-commands.ts
30811
31135
  function readRepoVersion() {
30812
31136
  try {
30813
- return JSON.parse((0, import_node_fs38.readFileSync)((0, import_node_path36.join)(process.cwd(), ".claude-plugin", "plugin.json"), "utf8")).version || void 0;
31137
+ return JSON.parse((0, import_node_fs39.readFileSync)((0, import_node_path37.join)(process.cwd(), ".claude-plugin", "plugin.json"), "utf8")).version || void 0;
30814
31138
  } catch {
30815
31139
  return void 0;
30816
31140
  }
@@ -30956,9 +31280,9 @@ function registerDeployCommands(program3) {
30956
31280
  }
30957
31281
 
30958
31282
  // src/discovery-commands.ts
30959
- var import_node_fs39 = require("node:fs");
30960
- var import_node_os14 = require("node:os");
30961
- var import_node_path37 = require("node:path");
31283
+ var import_node_fs40 = require("node:fs");
31284
+ var import_node_os15 = require("node:os");
31285
+ var import_node_path38 = require("node:path");
30962
31286
  var GC_GH_TIMEOUT_MS3 = 2e4;
30963
31287
  async function collectStatus() {
30964
31288
  const repo = await resolveRepo();
@@ -31146,10 +31470,10 @@ async function collectOnboardStatus(opts = {}) {
31146
31470
  else if (top) nextCommand = `mmi-cli board claim ${top.number} # ${top.title}`;
31147
31471
  else nextCommand = "mmi-cli board read \u2014 no claimable items found";
31148
31472
  }
31149
- const home = (0, import_node_os14.homedir)();
31473
+ const home = (0, import_node_os15.homedir)();
31150
31474
  const plugin = onboardPluginGate({
31151
- readKnown: () => readFileSyncSafe((0, import_node_path37.join)(home, ...KNOWN_MARKETPLACES_RELATIVE), import_node_fs39.readFileSync),
31152
- readSettings: () => readFileSyncSafe((0, import_node_path37.join)(home, ".claude", "settings.json"), import_node_fs39.readFileSync)
31475
+ readKnown: () => readFileSyncSafe((0, import_node_path38.join)(home, ...KNOWN_MARKETPLACES_RELATIVE), import_node_fs40.readFileSync),
31476
+ readSettings: () => readFileSyncSafe((0, import_node_path38.join)(home, ".claude", "settings.json"), import_node_fs40.readFileSync)
31153
31477
  });
31154
31478
  return { track, board, registry: registry2, secrets, plugin, estateCli, nextCommand };
31155
31479
  }
@@ -32053,19 +32377,19 @@ function registerSessionReport(program3) {
32053
32377
  }
32054
32378
 
32055
32379
  // src/plugin-release-catchup.ts
32056
- var import_node_fs40 = require("node:fs");
32057
- var import_node_path38 = require("node:path");
32058
- var import_node_os15 = require("node:os");
32380
+ var import_node_fs41 = require("node:fs");
32381
+ var import_node_path39 = require("node:path");
32382
+ var import_node_os16 = require("node:os");
32059
32383
  var RELEASE_CATCHUP_TTL_MS = 24 * 60 * 60 * 1e3;
32060
32384
  var RELEASE_CATCHUP_DISABLE_ENV = "MMI_NO_RELEASE_CATCHUP";
32061
32385
  function releaseCatchupStatePath(env = process.env) {
32062
32386
  if (env.MMI_RELEASE_CATCHUP_STATE) return env.MMI_RELEASE_CATCHUP_STATE;
32063
32387
  if (process.platform === "win32") {
32064
- const base2 = env.LOCALAPPDATA || (0, import_node_path38.join)((0, import_node_os15.homedir)(), "AppData", "Local");
32065
- return (0, import_node_path38.join)(base2, "MMI Future", "mmi-cli", "release-catchup.json");
32388
+ const base2 = env.LOCALAPPDATA || (0, import_node_path39.join)((0, import_node_os16.homedir)(), "AppData", "Local");
32389
+ return (0, import_node_path39.join)(base2, "MMI Future", "mmi-cli", "release-catchup.json");
32066
32390
  }
32067
- const base = env.XDG_STATE_HOME || (0, import_node_path38.join)((0, import_node_os15.homedir)(), ".local", "state");
32068
- return (0, import_node_path38.join)(base, "mmi-cli", "release-catchup.json");
32391
+ const base = env.XDG_STATE_HOME || (0, import_node_path39.join)((0, import_node_os16.homedir)(), ".local", "state");
32392
+ return (0, import_node_path39.join)(base, "mmi-cli", "release-catchup.json");
32069
32393
  }
32070
32394
  function releaseCatchupDue(state, now, force = false) {
32071
32395
  if (force) return true;
@@ -32075,7 +32399,7 @@ function releaseCatchupDue(state, now, force = false) {
32075
32399
  function newestCachedPluginVersion(home) {
32076
32400
  let names;
32077
32401
  try {
32078
- names = (0, import_node_fs40.readdirSync)(pluginCacheRoot(home));
32402
+ names = (0, import_node_fs41.readdirSync)(pluginCacheRoot(home));
32079
32403
  } catch {
32080
32404
  return void 0;
32081
32405
  }
@@ -32083,15 +32407,15 @@ function newestCachedPluginVersion(home) {
32083
32407
  }
32084
32408
  function marketplaceClonePath(home) {
32085
32409
  try {
32086
- const parsed = JSON.parse((0, import_node_fs40.readFileSync)((0, import_node_path38.join)(home, ".claude", "plugins", "known_marketplaces.json"), "utf8"));
32410
+ const parsed = JSON.parse((0, import_node_fs41.readFileSync)((0, import_node_path39.join)(home, ".claude", "plugins", "known_marketplaces.json"), "utf8"));
32087
32411
  if (parsed.mutmutco?.installLocation) return parsed.mutmutco.installLocation;
32088
32412
  } catch {
32089
32413
  }
32090
- return (0, import_node_path38.join)(home, ".claude", "plugins", "marketplaces", "mutmutco");
32414
+ return (0, import_node_path39.join)(home, ".claude", "plugins", "marketplaces", "mutmutco");
32091
32415
  }
32092
32416
  function readCatalogVersion(home) {
32093
32417
  try {
32094
- const parsed = JSON.parse((0, import_node_fs40.readFileSync)((0, import_node_path38.join)(marketplaceClonePath(home), ".claude-plugin", "marketplace.json"), "utf8"));
32418
+ const parsed = JSON.parse((0, import_node_fs41.readFileSync)((0, import_node_path39.join)(marketplaceClonePath(home), ".claude-plugin", "marketplace.json"), "utf8"));
32095
32419
  return parsed.plugins?.find((p) => p.name === "mmi")?.version;
32096
32420
  } catch {
32097
32421
  return void 0;
@@ -32099,7 +32423,7 @@ function readCatalogVersion(home) {
32099
32423
  }
32100
32424
  function readMmiInstallRecord(home) {
32101
32425
  try {
32102
- const parsed = JSON.parse((0, import_node_fs40.readFileSync)((0, import_node_path38.join)(home, ".claude", "plugins", "installed_plugins.json"), "utf8"));
32426
+ const parsed = JSON.parse((0, import_node_fs41.readFileSync)((0, import_node_path39.join)(home, ".claude", "plugins", "installed_plugins.json"), "utf8"));
32103
32427
  const record = parsed.plugins?.["mmi@mutmutco"]?.[0];
32104
32428
  return record?.version ? { version: record.version, gitCommitSha: record.gitCommitSha } : void 0;
32105
32429
  } catch {
@@ -32108,7 +32432,7 @@ function readMmiInstallRecord(home) {
32108
32432
  }
32109
32433
  async function runReleaseCatchup(home, env, deps, opts = {}) {
32110
32434
  if (env[RELEASE_CATCHUP_DISABLE_ENV]) return { ok: true, skipped: true, detail: `disabled via ${RELEASE_CATCHUP_DISABLE_ENV}` };
32111
- if (!(0, import_node_fs40.existsSync)(pluginCacheRoot(home))) return { ok: true, skipped: true, detail: "no mmi plugin cache on this machine \u2014 nothing to catch up" };
32435
+ if (!(0, import_node_fs41.existsSync)(pluginCacheRoot(home))) return { ok: true, skipped: true, detail: "no mmi plugin cache on this machine \u2014 nothing to catch up" };
32112
32436
  const statePath = releaseCatchupStatePath(env);
32113
32437
  const state = deps.readState(statePath);
32114
32438
  if (!releaseCatchupDue(state, deps.now(), opts.force)) {
@@ -32133,8 +32457,8 @@ async function runReleaseCatchup(home, env, deps, opts = {}) {
32133
32457
  return { ok: false, detail: `released ${latest} but the install record could not be cleared \u2014 nothing changed (record still ${prior.version})` };
32134
32458
  }
32135
32459
  const installed = await deps.runClaude(["plugin", "install", "mmi@mutmutco"], "claude plugin install mmi@mutmutco");
32136
- const payload = (0, import_node_path38.join)(pluginCacheRoot(home), latest, ".pi-plugin");
32137
- if (!installed || !(0, import_node_fs40.existsSync)(payload)) {
32460
+ const payload = (0, import_node_path39.join)(pluginCacheRoot(home), latest, ".pi-plugin");
32461
+ if (!installed || !(0, import_node_fs41.existsSync)(payload)) {
32138
32462
  const why = installed ? `install of ${latest} did not produce a verifiable .pi-plugin payload` : `install of ${latest} failed`;
32139
32463
  if (!prior) return { ok: false, detail: `${why}; no prior record to restore` };
32140
32464
  const rollback = await restorePriorRecord(home, prior, deps);
@@ -32162,7 +32486,7 @@ async function restorePriorRecord(home, prior, deps) {
32162
32486
  }
32163
32487
  function shouldSpawnReleaseCatchup(home, env, readState2, now = Date.now()) {
32164
32488
  if (env[RELEASE_CATCHUP_DISABLE_ENV]) return false;
32165
- if (!(0, import_node_fs40.existsSync)(pluginCacheRoot(home))) return false;
32489
+ if (!(0, import_node_fs41.existsSync)(pluginCacheRoot(home))) return false;
32166
32490
  return releaseCatchupDue(readState2(releaseCatchupStatePath(env)), now);
32167
32491
  }
32168
32492
  function defaultRegistrationHeal(home, env) {
@@ -34208,17 +34532,17 @@ function parseOriginRepo(remoteUrl) {
34208
34532
  }
34209
34533
  function ghHostsConfigPath(env, platform2) {
34210
34534
  const sep3 = platform2 === "win32" ? "\\" : "/";
34211
- const join36 = (...parts) => parts.join(sep3);
34535
+ const join37 = (...parts) => parts.join(sep3);
34212
34536
  const explicit = env.GH_CONFIG_DIR?.trim();
34213
- if (explicit) return join36(explicit, "hosts.yml");
34537
+ if (explicit) return join37(explicit, "hosts.yml");
34214
34538
  if (platform2 === "win32") {
34215
34539
  const appData = (env.AppData ?? env.APPDATA)?.trim();
34216
- return appData ? join36(appData, "GitHub CLI", "hosts.yml") : void 0;
34540
+ return appData ? join37(appData, "GitHub CLI", "hosts.yml") : void 0;
34217
34541
  }
34218
34542
  const xdg = env.XDG_CONFIG_HOME?.trim();
34219
- if (xdg) return join36(xdg, "gh", "hosts.yml");
34543
+ if (xdg) return join37(xdg, "gh", "hosts.yml");
34220
34544
  const home = env.HOME?.trim();
34221
- return home ? join36(home, ".config", "gh", "hosts.yml") : void 0;
34545
+ return home ? join37(home, ".config", "gh", "hosts.yml") : void 0;
34222
34546
  }
34223
34547
  function parseGhHostsAccounts(yaml, host = "github.com") {
34224
34548
  let hostIndent = null;
@@ -34268,9 +34592,9 @@ function ghAccountCaveat(announcedLogin, accounts) {
34268
34592
  }
34269
34593
 
34270
34594
  // src/doctor-io.ts
34271
- var import_node_fs41 = require("node:fs");
34272
- var import_node_os16 = require("node:os");
34273
- var import_node_path39 = require("node:path");
34595
+ var import_node_fs42 = require("node:fs");
34596
+ var import_node_os17 = require("node:os");
34597
+ var import_node_path40 = require("node:path");
34274
34598
  var import_node_child_process18 = require("node:child_process");
34275
34599
  var import_node_util8 = require("node:util");
34276
34600
  var execFileP6 = (0, import_node_util8.promisify)(import_node_child_process18.execFile);
@@ -34278,7 +34602,7 @@ var MMI_PLUGIN_ID2 = "mmi@mutmutco";
34278
34602
  function installedClaudePluginVersion() {
34279
34603
  try {
34280
34604
  const file = JSON.parse(
34281
- (0, import_node_fs41.readFileSync)((0, import_node_path39.join)((0, import_node_os16.homedir)(), ".claude", "plugins", "installed_plugins.json"), "utf8")
34605
+ (0, import_node_fs42.readFileSync)((0, import_node_path40.join)((0, import_node_os17.homedir)(), ".claude", "plugins", "installed_plugins.json"), "utf8")
34282
34606
  );
34283
34607
  const versions = (file.plugins?.[MMI_PLUGIN_ID2] ?? []).map((r) => r.version).filter((v) => Boolean(v));
34284
34608
  if (versions.length === 0) return void 0;
@@ -34289,7 +34613,7 @@ function installedClaudePluginVersion() {
34289
34613
  }
34290
34614
  function manifestVersion(path2) {
34291
34615
  try {
34292
- const manifest = JSON.parse((0, import_node_fs41.readFileSync)(path2, "utf8"));
34616
+ const manifest = JSON.parse((0, import_node_fs42.readFileSync)(path2, "utf8"));
34293
34617
  return typeof manifest.version === "string" && manifest.version.trim() ? manifest.version.trim() : void 0;
34294
34618
  } catch {
34295
34619
  return void 0;
@@ -34299,22 +34623,22 @@ function installedSurfacePluginVersion(surface) {
34299
34623
  const token = surfaceToken(surface);
34300
34624
  if (token === "kilo") {
34301
34625
  try {
34302
- const stamp = (0, import_node_fs41.readFileSync)((0, import_node_path39.join)((0, import_node_os16.homedir)(), ".kilo", ".mmi-kilo-version"), "utf8").trim();
34626
+ const stamp = (0, import_node_fs42.readFileSync)((0, import_node_path40.join)((0, import_node_os17.homedir)(), ".kilo", ".mmi-kilo-version"), "utf8").trim();
34303
34627
  return stamp || void 0;
34304
34628
  } catch {
34305
34629
  return void 0;
34306
34630
  }
34307
34631
  }
34308
34632
  if (token === "cursor") {
34309
- return manifestVersion((0, import_node_path39.join)(cursorLocalPluginRoot(), ".cursor-plugin", "plugin.json"));
34633
+ return manifestVersion((0, import_node_path40.join)(cursorLocalPluginRoot(), ".cursor-plugin", "plugin.json"));
34310
34634
  }
34311
34635
  if (token === "jervcode") {
34312
34636
  const entry = mmiPiWrapperEntry();
34313
34637
  if (!entry) return void 0;
34314
- return manifestVersion((0, import_node_path39.join)(decodeURIComponent(entry.replace(/^file:\/\/\/?/, "")), "package.json"));
34638
+ return manifestVersion((0, import_node_path40.join)(decodeURIComponent(entry.replace(/^file:\/\/\/?/, "")), "package.json"));
34315
34639
  }
34316
34640
  if (token === "kimi") {
34317
- return manifestVersion((0, import_node_path39.join)(surfaceConfigRoot(surface), "plugins", "managed", "mmi", ".kimi-plugin", "plugin.json"));
34641
+ return manifestVersion((0, import_node_path40.join)(surfaceConfigRoot(surface), "plugins", "managed", "mmi", ".kimi-plugin", "plugin.json"));
34318
34642
  }
34319
34643
  if (token === "claude") return installedClaudePluginVersion();
34320
34644
  if (token !== "codex") return void 0;
@@ -34352,13 +34676,13 @@ function worktreeRootSync() {
34352
34676
  }
34353
34677
  var gitignorePath = () => {
34354
34678
  const root = worktreeRootSync();
34355
- return root === null ? null : (0, import_node_path39.join)(root, ".gitignore");
34679
+ return root === null ? null : (0, import_node_path40.join)(root, ".gitignore");
34356
34680
  };
34357
34681
  function readGitignore() {
34358
34682
  const path2 = gitignorePath();
34359
34683
  if (path2 === null) return null;
34360
34684
  try {
34361
- return (0, import_node_fs41.readFileSync)(path2, "utf8");
34685
+ return (0, import_node_fs42.readFileSync)(path2, "utf8");
34362
34686
  } catch {
34363
34687
  return null;
34364
34688
  }
@@ -34367,7 +34691,7 @@ function writeGitignore(content) {
34367
34691
  const path2 = gitignorePath();
34368
34692
  if (path2 === null) return false;
34369
34693
  try {
34370
- (0, import_node_fs41.writeFileSync)(path2, content, "utf8");
34694
+ (0, import_node_fs42.writeFileSync)(path2, content, "utf8");
34371
34695
  return true;
34372
34696
  } catch {
34373
34697
  return false;
@@ -34391,7 +34715,7 @@ async function repoRoot() {
34391
34715
  }
34392
34716
  function hasRepoLocalWorktrees() {
34393
34717
  const root = worktreeRootSync();
34394
- return root !== null && (0, import_node_fs41.existsSync)((0, import_node_path39.join)(root, ".worktrees"));
34718
+ return root !== null && (0, import_node_fs42.existsSync)((0, import_node_path40.join)(root, ".worktrees"));
34395
34719
  }
34396
34720
 
34397
34721
  // src/index.ts
@@ -34410,8 +34734,8 @@ ${r.stderr ?? ""}`).catch(() => "");
34410
34734
  function ghMultiAccountCaveat(announcedLogin) {
34411
34735
  try {
34412
34736
  const hostsPath = ghHostsConfigPath(process.env, process.platform);
34413
- if (!hostsPath || !(0, import_node_fs42.existsSync)(hostsPath)) return void 0;
34414
- return ghAccountCaveat(announcedLogin, parseGhHostsAccounts((0, import_node_fs42.readFileSync)(hostsPath, "utf8")));
34737
+ if (!hostsPath || !(0, import_node_fs43.existsSync)(hostsPath)) return void 0;
34738
+ return ghAccountCaveat(announcedLogin, parseGhHostsAccounts((0, import_node_fs43.readFileSync)(hostsPath, "utf8")));
34415
34739
  } catch {
34416
34740
  return void 0;
34417
34741
  }
@@ -34419,12 +34743,12 @@ function ghMultiAccountCaveat(announcedLogin) {
34419
34743
  var ENV_HEAL_LOCK_STALE_MS = 10 * 6e4;
34420
34744
  var ENV_HEAL_LOCK_MAX_WAIT_MS = 2 * 6e4;
34421
34745
  function envHealLockPath(home) {
34422
- return (0, import_node_path40.join)(home, ".claude", "plugins", ".mmi-env-heal.lock");
34746
+ return (0, import_node_path41.join)(home, ".claude", "plugins", ".mmi-env-heal.lock");
34423
34747
  }
34424
34748
  async function withEnvHealLock(what, run) {
34425
34749
  try {
34426
34750
  return await withFileLock(
34427
- envHealLockPath((0, import_node_os17.homedir)()),
34751
+ envHealLockPath((0, import_node_os18.homedir)()),
34428
34752
  { staleMs: ENV_HEAL_LOCK_STALE_MS, maxWaitMs: ENV_HEAL_LOCK_MAX_WAIT_MS, label: "mmi env-heal lock" },
34429
34753
  run
34430
34754
  );
@@ -34521,7 +34845,7 @@ function mmiDoctorDeps(opts = {}) {
34521
34845
  const configRoot = surfaceConfigRoot(surface);
34522
34846
  const running = surface === "codex" ? installedActivePluginVersion(surface) : runningPluginVersion(process.env, resolveClientVersion());
34523
34847
  const plan = buildPluginCachePlan(
34524
- (0, import_node_os17.homedir)(),
34848
+ (0, import_node_os18.homedir)(),
34525
34849
  running,
34526
34850
  pluginCacheFsDeps(configRoot, () => 0),
34527
34851
  { configRoot, includeStaging: surface !== "codex" }
@@ -34545,14 +34869,14 @@ function mmiDoctorDeps(opts = {}) {
34545
34869
  const running = surface === "codex" ? installedActivePluginVersion(surface) : runningPluginVersion(process.env, resolveClientVersion());
34546
34870
  const installed = installedActivePluginVersion(surface);
34547
34871
  const plan = buildPluginCachePlan(
34548
- (0, import_node_os17.homedir)(),
34872
+ (0, import_node_os18.homedir)(),
34549
34873
  running,
34550
34874
  pluginCacheFsDeps(configRoot, () => 0),
34551
34875
  { configRoot, includeStaging: surface !== "codex", installedVersion: installed }
34552
34876
  );
34553
34877
  const result = applyPluginCachePlan(
34554
34878
  plan,
34555
- (p) => (0, import_node_fs42.rmSync)(p, { recursive: true }),
34879
+ (p) => (0, import_node_fs43.rmSync)(p, { recursive: true }),
34556
34880
  stagingApplyFsGuard(configRoot)
34557
34881
  );
34558
34882
  return {
@@ -34580,12 +34904,12 @@ function mmiDoctorDeps(opts = {}) {
34580
34904
  piPluginState: () => {
34581
34905
  const env = { ...process.env };
34582
34906
  delete env.CLAUDE_PLUGIN_ROOT;
34583
- return readPiPluginState((0, import_node_os17.homedir)(), env);
34907
+ return readPiPluginState((0, import_node_os18.homedir)(), env);
34584
34908
  },
34585
34909
  healPiPlugin: () => {
34586
34910
  const env = { ...process.env };
34587
34911
  delete env.CLAUDE_PLUGIN_ROOT;
34588
- return healPiPluginRegistration((0, import_node_os17.homedir)(), env);
34912
+ return healPiPluginRegistration((0, import_node_os18.homedir)(), env);
34589
34913
  },
34590
34914
  // #3470: what the SessionStart hook LAST emitted, measured at emission by the session-start verb below.
34591
34915
  // A local record read ? cheap enough for every lane, including the banner.
@@ -34595,17 +34919,17 @@ function mmiDoctorDeps(opts = {}) {
34595
34919
  marketplaceRows: () => {
34596
34920
  try {
34597
34921
  if (detectSurface(process.env) === "codex") return [];
34598
- const home = (0, import_node_os17.homedir)();
34922
+ const home = (0, import_node_os18.homedir)();
34599
34923
  const rows = marketplaceRows(
34600
34924
  MMI_MARKETPLACE_NAME,
34601
- readFileSyncSafe((0, import_node_path40.join)(home, ...KNOWN_MARKETPLACES_RELATIVE), import_node_fs42.readFileSync),
34602
- readFileSyncSafe((0, import_node_path40.join)(home, ".claude", "settings.json"), import_node_fs42.readFileSync),
34925
+ readFileSyncSafe((0, import_node_path41.join)(home, ...KNOWN_MARKETPLACES_RELATIVE), import_node_fs43.readFileSync),
34926
+ readFileSyncSafe((0, import_node_path41.join)(home, ".claude", "settings.json"), import_node_fs43.readFileSync),
34603
34927
  // #3974: this CLI heals these rows, so report mode names the doctor run rather than the hand
34604
34928
  // edit. Unconditional ? it is a fact about mmi-cli, not about the lane this run is on.
34605
34929
  true
34606
34930
  );
34607
34931
  const pending = readMarketplacePinPending(
34608
- (0, import_node_path40.join)(home, ".claude", "plugins", ".mmi-marketplace-pin-pending.json"),
34932
+ (0, import_node_path41.join)(home, ".claude", "plugins", ".mmi-marketplace-pin-pending.json"),
34609
34933
  MMI_MARKETPLACE_NAME
34610
34934
  );
34611
34935
  if (!pending) return rows;
@@ -34629,11 +34953,11 @@ function mmiDoctorDeps(opts = {}) {
34629
34953
  healMarketplacePins: () => {
34630
34954
  try {
34631
34955
  if (detectSurface(process.env) === "codex") return void 0;
34632
- const home = (0, import_node_os17.homedir)();
34956
+ const home = (0, import_node_os18.homedir)();
34633
34957
  const names = [MMI_MARKETPLACE_NAME];
34634
- const result = applyOrgMarketplacePins((0, import_node_path40.join)(home, ...KNOWN_MARKETPLACES_RELATIVE), names);
34958
+ const result = applyOrgMarketplacePins((0, import_node_path41.join)(home, ...KNOWN_MARKETPLACES_RELATIVE), names);
34635
34959
  if (result?.wrote) {
34636
- writeMarketplacePinPending((0, import_node_path40.join)(home, ".claude", "plugins", ".mmi-marketplace-pin-pending.json"), names);
34960
+ writeMarketplacePinPending((0, import_node_path41.join)(home, ".claude", "plugins", ".mmi-marketplace-pin-pending.json"), names);
34637
34961
  }
34638
34962
  return result;
34639
34963
  } catch {
@@ -34649,7 +34973,7 @@ function mmiDoctorDeps(opts = {}) {
34649
34973
  // adopted the generated routing index (MMG-Unlive: `docs/Archive/**` only, no index, no gate.yml) would
34650
34974
  // get a permanent ? demanding an artifact it never asked for.
34651
34975
  docsIndexState: (root) => {
34652
- if (!(0, import_node_fs42.existsSync)((0, import_node_path40.join)(root, DOCS_INDEX_PATH))) return void 0;
34976
+ if (!(0, import_node_fs43.existsSync)((0, import_node_path41.join)(root, DOCS_INDEX_PATH))) return void 0;
34653
34977
  const real = createDocsIndexDeps(root);
34654
34978
  let docs2;
34655
34979
  const listDocs = () => docs2 ??= real.listDocs();
@@ -34658,7 +34982,7 @@ function mmiDoctorDeps(opts = {}) {
34658
34982
  },
34659
34983
  // #4168: working-tree heal — write if drifted, then re-check. Commit remains the operator's step.
34660
34984
  healDocsIndex: (root) => {
34661
- if (!(0, import_node_fs42.existsSync)((0, import_node_path40.join)(root, DOCS_INDEX_PATH))) return { drift: false, docCount: 0 };
34985
+ if (!(0, import_node_fs43.existsSync)((0, import_node_path41.join)(root, DOCS_INDEX_PATH))) return { drift: false, docCount: 0 };
34662
34986
  const real = createDocsIndexDeps(root);
34663
34987
  let docs2;
34664
34988
  const listDocs = () => docs2 ??= real.listDocs();
@@ -34993,19 +35317,19 @@ program2.hook("preAction", async (_thisCommand, actionCommand) => {
34993
35317
  });
34994
35318
  var rules = program2.command("rules").description("org-managed .gitignore delivery");
34995
35319
  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) => {
34996
- const path2 = (0, import_node_path40.join)(process.cwd(), ".gitignore");
34997
- const current = (0, import_node_fs42.existsSync)(path2) ? (0, import_node_fs42.readFileSync)(path2, "utf8") : null;
35320
+ const path2 = (0, import_node_path41.join)(process.cwd(), ".gitignore");
35321
+ const current = (0, import_node_fs43.existsSync)(path2) ? (0, import_node_fs43.readFileSync)(path2, "utf8") : null;
34998
35322
  const plan = planManagedGitignore(current);
34999
35323
  const drift = [...plan.added.map((l) => `+${l}`), ...plan.removed.map((l) => `-${l}`)].join(", ") || "block normalize";
35000
35324
  if (opts.json) {
35001
- if (opts.write && plan.changed) (0, import_node_fs42.writeFileSync)(path2, plan.content, "utf8");
35325
+ if (opts.write && plan.changed) (0, import_node_fs43.writeFileSync)(path2, plan.content, "utf8");
35002
35326
  console.log(JSON.stringify(plan, null, 2));
35003
35327
  if (!opts.write && plan.changed) process.exitCode = 1;
35004
35328
  return;
35005
35329
  }
35006
35330
  if (opts.write) {
35007
35331
  if (plan.changed) {
35008
- (0, import_node_fs42.writeFileSync)(path2, plan.content, "utf8");
35332
+ (0, import_node_fs43.writeFileSync)(path2, plan.content, "utf8");
35009
35333
  console.log(`mmi-cli org rules gitignore: updated .gitignore (${drift})`);
35010
35334
  } else {
35011
35335
  console.log("mmi-cli org rules gitignore: up to date");
@@ -35163,10 +35487,10 @@ gcCmd.option("--dry-run", "show what would be deleted (default)").option("--appl
35163
35487
  if (!Number.isFinite(limit) || limit < 1) return fail("worktree gc: --limit must be a positive integer");
35164
35488
  let root;
35165
35489
  if (o.root !== void 0) {
35166
- root = (0, import_node_path40.resolve)(o.root);
35167
- if (!(0, import_node_fs42.existsSync)(root) || !(0, import_node_fs42.statSync)(root).isDirectory()) return fail(`worktree gc: --root ${o.root} is not a directory`);
35490
+ root = (0, import_node_path41.resolve)(o.root);
35491
+ if (!(0, import_node_fs43.existsSync)(root) || !(0, import_node_fs43.statSync)(root).isDirectory()) return fail(`worktree gc: --root ${o.root} is not a directory`);
35168
35492
  const gcRepoRoot = (await execFileP2("git", ["rev-parse", "--show-toplevel"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim() || process.cwd();
35169
- if (isPathUnderDirectory(gcRepoRoot, root)) {
35493
+ if (isPathUnderDirectory2(gcRepoRoot, root)) {
35170
35494
  return fail(`worktree gc: --root ${root} contains this checkout ? name a worktrees root, not the repo or an ancestor of it`);
35171
35495
  }
35172
35496
  }
@@ -35236,15 +35560,17 @@ async function primaryCheckoutRoot(from) {
35236
35560
  }
35237
35561
  async function currentWorktreeRemovalContext(command, force) {
35238
35562
  const cwd = process.cwd();
35563
+ const activeWorkspaceRoot = resolveActiveWorkspaceRoot();
35239
35564
  return {
35240
35565
  primaryRoot: await primaryCheckoutRoot(cwd) ?? cwd,
35241
35566
  actor: describeActor({ env: process.env, surface: detectSurface(process.env), cwd }),
35242
35567
  command,
35243
- ...force ? { force: true } : {}
35568
+ ...force ? { force: true } : {},
35569
+ ...activeWorkspaceRoot ? { activeWorkspaceRoot } : {}
35244
35570
  };
35245
35571
  }
35246
35572
  async function unprovenWorktreeReason(wtPath, repoRoot2) {
35247
- if (!(0, import_node_fs42.existsSync)(wtPath)) return `${wtPath} does not exist on disk`;
35573
+ if (!(0, import_node_fs43.existsSync)(wtPath)) return `${wtPath} does not exist on disk`;
35248
35574
  const porcelain = (await execFileP2("git", ["-C", repoRoot2, "worktree", "list", "--porcelain"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout;
35249
35575
  const registered = parseWorktreePorcelainEntries(porcelain);
35250
35576
  if (!registered.length) {
@@ -35266,26 +35592,26 @@ function makeProvisionDeps(worktreeRoot, quiet, log) {
35266
35592
  function acquireWorktreeSetupLock(worktreeRoot) {
35267
35593
  const lockPath = repoRuntimeStatePath(worktreeRoot, "worktree-setup.lock");
35268
35594
  const take = () => {
35269
- const fd = (0, import_node_fs42.openSync)(lockPath, "wx");
35595
+ const fd = (0, import_node_fs43.openSync)(lockPath, "wx");
35270
35596
  try {
35271
- (0, import_node_fs42.writeSync)(fd, String(Date.now()));
35597
+ (0, import_node_fs43.writeSync)(fd, String(Date.now()));
35272
35598
  } finally {
35273
- (0, import_node_fs42.closeSync)(fd);
35599
+ (0, import_node_fs43.closeSync)(fd);
35274
35600
  }
35275
35601
  return () => {
35276
35602
  try {
35277
- (0, import_node_fs42.rmSync)(lockPath, { force: true });
35603
+ (0, import_node_fs43.rmSync)(lockPath, { force: true });
35278
35604
  } catch {
35279
35605
  }
35280
35606
  };
35281
35607
  };
35282
35608
  try {
35283
- (0, import_node_fs42.mkdirSync)((0, import_node_path40.dirname)(lockPath), { recursive: true });
35609
+ (0, import_node_fs43.mkdirSync)((0, import_node_path41.dirname)(lockPath), { recursive: true });
35284
35610
  return take();
35285
35611
  } catch {
35286
35612
  try {
35287
- if (Date.now() - (0, import_node_fs42.statSync)(lockPath).mtimeMs > WORKTREE_SETUP_LOCK_TTL_MS) {
35288
- (0, import_node_fs42.rmSync)(lockPath, { force: true });
35613
+ if (Date.now() - (0, import_node_fs43.statSync)(lockPath).mtimeMs > WORKTREE_SETUP_LOCK_TTL_MS) {
35614
+ (0, import_node_fs43.rmSync)(lockPath, { force: true });
35289
35615
  return take();
35290
35616
  }
35291
35617
  } catch {
@@ -36138,7 +36464,7 @@ project.command("set [owner/repo]").description("upsert project META (idempotent
36138
36464
  if (dupe) return fail(`org project set: KEY "${dupe}" was passed to both --var and --set; --set is an alias of --var, so pass each KEY once`);
36139
36465
  if (o.secretsFile) {
36140
36466
  try {
36141
- vars.push(`secrets=${(0, import_node_fs42.readFileSync)(o.secretsFile, "utf8")}`);
36467
+ vars.push(`secrets=${(0, import_node_fs43.readFileSync)(o.secretsFile, "utf8")}`);
36142
36468
  } catch (e) {
36143
36469
  return fail(`org project set: cannot read --secrets-file ${o.secretsFile}: ${e.message}`);
36144
36470
  }
@@ -36893,11 +37219,11 @@ pr.command("view <number>").description("read a PR as structured JSON (merged st
36893
37219
  }
36894
37220
  });
36895
37221
  async function listCiWorkflowPaths(cwd = process.cwd()) {
36896
- const wfDir = (0, import_node_path40.join)(cwd, ".github", "workflows");
36897
- if (!(0, import_node_fs42.existsSync)(wfDir)) return [];
36898
- return (0, import_node_fs42.readdirSync)(wfDir).filter((name) => /\.(ya?ml)$/i.test(name)).filter((name) => {
37222
+ const wfDir = (0, import_node_path41.join)(cwd, ".github", "workflows");
37223
+ if (!(0, import_node_fs43.existsSync)(wfDir)) return [];
37224
+ return (0, import_node_fs43.readdirSync)(wfDir).filter((name) => /\.(ya?ml)$/i.test(name)).filter((name) => {
36899
37225
  try {
36900
- return workflowReportsPrChecks((0, import_node_fs42.readFileSync)((0, import_node_path40.join)(wfDir, name), "utf8"));
37226
+ return workflowReportsPrChecks((0, import_node_fs43.readFileSync)((0, import_node_path41.join)(wfDir, name), "utf8"));
36901
37227
  } catch {
36902
37228
  return true;
36903
37229
  }
@@ -36929,16 +37255,16 @@ function ciAuditDeps() {
36929
37255
  // gate re-seed step is skipped gracefully rather than failing mid-run.
36930
37256
  readSeedFile: (path2) => {
36931
37257
  if (!root) return null;
36932
- const fullPath = (0, import_node_path40.join)(root, path2);
36933
- return (0, import_node_fs42.existsSync)(fullPath) ? (0, import_node_fs42.readFileSync)(fullPath, "utf8") : null;
37258
+ const fullPath = (0, import_node_path41.join)(root, path2);
37259
+ return (0, import_node_fs43.existsSync)(fullPath) ? (0, import_node_fs43.readFileSync)(fullPath, "utf8") : null;
36934
37260
  }
36935
37261
  };
36936
37262
  }
36937
37263
  function hubRoot() {
36938
- const fromPkg = (0, import_node_path40.join)(__dirname, "..", "..");
37264
+ const fromPkg = (0, import_node_path41.join)(__dirname, "..", "..");
36939
37265
  const marker = "skills/bootstrap/seeds/manifest.json";
36940
- if ((0, import_node_fs42.existsSync)((0, import_node_path40.join)(fromPkg, marker))) return fromPkg;
36941
- if ((0, import_node_fs42.existsSync)((0, import_node_path40.join)(process.cwd(), marker))) return process.cwd();
37266
+ if ((0, import_node_fs43.existsSync)((0, import_node_path41.join)(fromPkg, marker))) return fromPkg;
37267
+ if ((0, import_node_fs43.existsSync)((0, import_node_path41.join)(process.cwd(), marker))) return process.cwd();
36942
37268
  return null;
36943
37269
  }
36944
37270
  pr.command("ci-policy").description("report merge CI policy: wait-for-checks vs no-ci (for grind/build agents)").option("--json", "machine-readable output").option("--repo <owner/repo>", "target repo (defaults to the current checkout)").action(async (o) => {
@@ -37258,7 +37584,7 @@ jsonParity(pr.command("merge <number>").description("merge a PR (squash by defau
37258
37584
  localCleanup = await cleanupPrMergeLocalBranch(headRef, {
37259
37585
  beforeWorktrees,
37260
37586
  startingPath,
37261
- pathExists: (p) => (0, import_node_fs42.existsSync)(p),
37587
+ pathExists: (p) => (0, import_node_fs43.existsSync)(p),
37262
37588
  execGit: async (args) => (await execFileP2("git", args, { timeout: GIT_TIMEOUT_MS })).stdout,
37263
37589
  teardownWorktreeStage,
37264
37590
  deferredStore,
@@ -37755,12 +38081,12 @@ access.command("audit").description("audit collaborator roles + train-branch pus
37755
38081
  targets = resolution.targets;
37756
38082
  }
37757
38083
  const derivedMatrix = registryProjects ? accessMatrixFromProjects(registryProjects) : {};
37758
- const fileMatrix = (0, import_node_fs42.existsSync)("access-matrix.json") ? loadAccessMatrix((0, import_node_fs42.readFileSync)("access-matrix.json", "utf8")) : {};
38084
+ const fileMatrix = (0, import_node_fs43.existsSync)("access-matrix.json") ? loadAccessMatrix((0, import_node_fs43.readFileSync)("access-matrix.json", "utf8")) : {};
37759
38085
  const matrix = mergeAccessMatrix(fileMatrix, derivedMatrix);
37760
38086
  const derivedContracts = registryProjects ? dataAccessContractsFromProjects(registryProjects) : { consumers: {} };
37761
- const fileContracts = (0, import_node_fs42.existsSync)("data-access-contracts.json") ? loadDataAccessContracts((0, import_node_fs42.readFileSync)("data-access-contracts.json", "utf8")) : { consumers: {} };
38087
+ const fileContracts = (0, import_node_fs43.existsSync)("data-access-contracts.json") ? loadDataAccessContracts((0, import_node_fs43.readFileSync)("data-access-contracts.json", "utf8")) : { consumers: {} };
37762
38088
  const dataAccess = mergeDataAccessContracts(fileContracts, derivedContracts);
37763
- const sanctioned = (0, import_node_fs42.existsSync)("access-matrix.json") ? loadSanctionedAdmins((0, import_node_fs42.readFileSync)("access-matrix.json", "utf8")) : {};
38089
+ const sanctioned = (0, import_node_fs43.existsSync)("access-matrix.json") ? loadSanctionedAdmins((0, import_node_fs43.readFileSync)("access-matrix.json", "utf8")) : {};
37764
38090
  const report = await auditOrgAccess(targets, deps, matrix, dataAccess, sanctioned);
37765
38091
  console.log(o.json ? JSON.stringify(report, null, 2) : renderAccessReport(report));
37766
38092
  if (!report.ok) process.exitCode = 1;
@@ -37792,16 +38118,16 @@ function directoryBytes(path2) {
37792
38118
  let total = 0;
37793
38119
  let entries;
37794
38120
  try {
37795
- entries = (0, import_node_fs42.readdirSync)(path2, { withFileTypes: true });
38121
+ entries = (0, import_node_fs43.readdirSync)(path2, { withFileTypes: true });
37796
38122
  } catch {
37797
38123
  return 0;
37798
38124
  }
37799
38125
  for (const entry of entries) {
37800
- const child2 = (0, import_node_path40.join)(path2, entry.name);
38126
+ const child2 = (0, import_node_path41.join)(path2, entry.name);
37801
38127
  if (entry.isDirectory()) total += directoryBytes(child2);
37802
38128
  else {
37803
38129
  try {
37804
- total += (0, import_node_fs42.statSync)(child2).size;
38130
+ total += (0, import_node_fs43.statSync)(child2).size;
37805
38131
  } catch {
37806
38132
  }
37807
38133
  }
@@ -37809,25 +38135,25 @@ function directoryBytes(path2) {
37809
38135
  return total;
37810
38136
  }
37811
38137
  function listDirEntries(dir) {
37812
- return (0, import_node_fs42.readdirSync)(dir, { withFileTypes: true }).map((d) => ({ name: d.name, isDirectory: d.isDirectory() }));
38138
+ return (0, import_node_fs43.readdirSync)(dir, { withFileTypes: true }).map((d) => ({ name: d.name, isDirectory: d.isDirectory() }));
37813
38139
  }
37814
38140
  function readInstalledPluginRefs(configRoot) {
37815
38141
  const p = installedPluginsPathForConfig(configRoot);
37816
- if (!(0, import_node_fs42.existsSync)(p)) return [];
38142
+ if (!(0, import_node_fs43.existsSync)(p)) return [];
37817
38143
  try {
37818
- return installedPluginPaths((0, import_node_fs42.readFileSync)(p, "utf8"));
38144
+ return installedPluginPaths((0, import_node_fs43.readFileSync)(p, "utf8"));
37819
38145
  } catch {
37820
38146
  return null;
37821
38147
  }
37822
38148
  }
37823
38149
  function pluginCacheFsDeps(configRoot, dirBytes) {
37824
38150
  return {
37825
- exists: (p) => (0, import_node_fs42.existsSync)(p),
37826
- listVersionDirs: (root) => (0, import_node_fs42.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name),
38151
+ exists: (p) => (0, import_node_fs43.existsSync)(p),
38152
+ listVersionDirs: (root) => (0, import_node_fs43.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name),
37827
38153
  dirBytes,
37828
- listStagingDirs: (root) => (0, import_node_fs42.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => {
38154
+ listStagingDirs: (root) => (0, import_node_fs43.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => {
37829
38155
  try {
37830
- return { name: d.name, mtimeMs: newestMtimeMs((0, import_node_path40.join)(root, d.name), listDirEntries, (p) => (0, import_node_fs42.statSync)(p).mtimeMs) };
38156
+ return { name: d.name, mtimeMs: newestMtimeMs((0, import_node_path41.join)(root, d.name), listDirEntries, (p) => (0, import_node_fs43.statSync)(p).mtimeMs) };
37831
38157
  } catch {
37832
38158
  return { name: d.name, mtimeMs: Date.now() };
37833
38159
  }
@@ -37841,10 +38167,10 @@ function stagingApplyFsGuard(configRoot) {
37841
38167
  return {
37842
38168
  referencedPaths: () => readInstalledPluginRefs(configRoot),
37843
38169
  mtimeMs: (name) => {
37844
- const p = (0, import_node_path40.join)(stagingRoot, name);
37845
- if (!(0, import_node_fs42.existsSync)(p)) return null;
38170
+ const p = (0, import_node_path41.join)(stagingRoot, name);
38171
+ if (!(0, import_node_fs43.existsSync)(p)) return null;
37846
38172
  try {
37847
- return newestMtimeMs(p, listDirEntries, (q) => (0, import_node_fs42.statSync)(q).mtimeMs);
38173
+ return newestMtimeMs(p, listDirEntries, (q) => (0, import_node_fs43.statSync)(q).mtimeMs);
37848
38174
  } catch {
37849
38175
  return null;
37850
38176
  }
@@ -37864,13 +38190,13 @@ program2.command("plugin-prune").description(`prune stale cached MMI plugin vers
37864
38190
  return;
37865
38191
  }
37866
38192
  const plan = buildPluginCachePlan(
37867
- (0, import_node_os17.homedir)(),
38193
+ (0, import_node_os18.homedir)(),
37868
38194
  running,
37869
38195
  pluginCacheFsDeps(configRoot, directoryBytes),
37870
38196
  { withBytes: true, configRoot, includeStaging: surface !== "codex" }
37871
38197
  );
37872
38198
  const anythingToDelete = plan.prune.length > 0 || plan.staging.length > 0;
37873
- const result = o.apply && anythingToDelete ? applyPluginCachePlan(plan, (p) => (0, import_node_fs42.rmSync)(p, { recursive: true, force: true }), stagingApplyFsGuard(configRoot)) : void 0;
38199
+ const result = o.apply && anythingToDelete ? applyPluginCachePlan(plan, (p) => (0, import_node_fs43.rmSync)(p, { recursive: true, force: true }), stagingApplyFsGuard(configRoot)) : void 0;
37874
38200
  const warnings = plan.prune.length > 0 ? [CONCURRENT_SESSION_WARNING] : [];
37875
38201
  if (o.json) console.log(JSON.stringify({ ...plan, warnings, applied: result ?? null }));
37876
38202
  else console.log(renderPluginCachePlan(plan, result));
@@ -37878,7 +38204,7 @@ program2.command("plugin-prune").description(`prune stale cached MMI plugin vers
37878
38204
  });
37879
38205
  function readReleaseCatchupState(path2) {
37880
38206
  try {
37881
- const parsed = JSON.parse((0, import_node_fs42.readFileSync)(path2, "utf8"));
38207
+ const parsed = JSON.parse((0, import_node_fs43.readFileSync)(path2, "utf8"));
37882
38208
  return typeof parsed?.checkedAt === "number" ? parsed : void 0;
37883
38209
  } catch {
37884
38210
  return void 0;
@@ -37886,8 +38212,8 @@ function readReleaseCatchupState(path2) {
37886
38212
  }
37887
38213
  function writeReleaseCatchupState(path2, state) {
37888
38214
  try {
37889
- (0, import_node_fs42.mkdirSync)((0, import_node_path40.dirname)(path2), { recursive: true });
37890
- (0, import_node_fs42.writeFileSync)(path2, `${JSON.stringify(state)}
38215
+ (0, import_node_fs43.mkdirSync)((0, import_node_path41.dirname)(path2), { recursive: true });
38216
+ (0, import_node_fs43.writeFileSync)(path2, `${JSON.stringify(state)}
37891
38217
  `);
37892
38218
  } catch {
37893
38219
  }
@@ -37895,7 +38221,7 @@ function writeReleaseCatchupState(path2, state) {
37895
38221
  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) => {
37896
38222
  const outcome = await withEnvHealLock(
37897
38223
  "plugin release catch-up",
37898
- () => runReleaseCatchup((0, import_node_os17.homedir)(), process.env, {
38224
+ () => runReleaseCatchup((0, import_node_os18.homedir)(), process.env, {
37899
38225
  fetchReleased: fetchNpmReleasedVersion,
37900
38226
  runClaude: (args, step) => runPluginCli("claude", args, (msg) => {
37901
38227
  if (!o.quiet && !o.json) console.log(msg);
@@ -37911,7 +38237,7 @@ program2.command("plugin-release-catchup").description("install a newer released
37911
38237
  },
37912
38238
  readState: readReleaseCatchupState,
37913
38239
  writeState: writeReleaseCatchupState,
37914
- healRegistration: defaultRegistrationHeal((0, import_node_os17.homedir)(), process.env),
38240
+ healRegistration: defaultRegistrationHeal((0, import_node_os18.homedir)(), process.env),
37915
38241
  now: () => Date.now()
37916
38242
  }, { force: o.force })
37917
38243
  );
@@ -37979,7 +38305,7 @@ program2.command("session-start").description("run the SessionStart verbs (whoam
37979
38305
  spawnDetachedSelf(["worktree", "setup", "--quiet"], { spawn: import_node_child_process19.spawn, execPath: process.execPath, scriptPath: process.argv[1] });
37980
38306
  bannerIo.log(worktreeBanner);
37981
38307
  }
37982
- if (shouldSpawnReleaseCatchup((0, import_node_os17.homedir)(), process.env, readReleaseCatchupState)) {
38308
+ if (shouldSpawnReleaseCatchup((0, import_node_os18.homedir)(), process.env, readReleaseCatchupState)) {
37983
38309
  spawnDetachedSelf(["plugin", "release-catchup", "--quiet"], { spawn: import_node_child_process19.spawn, execPath: process.execPath, scriptPath: process.argv[1] });
37984
38310
  }
37985
38311
  if (isLinkedWorktree(process.cwd())) {