@mutmutco/cli 2.65.0 → 2.66.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +1 -2
  2. package/dist/main.cjs +343 -351
  3. package/package.json +1 -1
package/dist/main.cjs CHANGED
@@ -3408,7 +3408,7 @@ var program = new Command();
3408
3408
 
3409
3409
  // src/index.ts
3410
3410
  var import_promises4 = require("node:fs/promises");
3411
- var import_node_fs17 = require("node:fs");
3411
+ var import_node_fs18 = require("node:fs");
3412
3412
 
3413
3413
  // src/rules-sync.ts
3414
3414
  function normalizeEol(s) {
@@ -3543,7 +3543,7 @@ function hardExit(code) {
3543
3543
  async function cleanExit(code) {
3544
3544
  process.exitCode = code;
3545
3545
  await closeHttpPool();
3546
- await new Promise((resolve5) => setImmediate(resolve5));
3546
+ await new Promise((resolve6) => setImmediate(resolve6));
3547
3547
  process.exit(code);
3548
3548
  }
3549
3549
  async function failGraceful(msg) {
@@ -3708,7 +3708,7 @@ async function fetchWithRetry(fetchImpl, url, init, opts = {}) {
3708
3708
  const attempts = opts.attempts ?? 3;
3709
3709
  const baseDelayMs = opts.baseDelayMs ?? 250;
3710
3710
  const retryOn = opts.retryOn ?? ((res) => res.status >= 500);
3711
- const sleep = opts.sleep ?? ((ms) => new Promise((resolve5) => setTimeout(resolve5, ms)));
3711
+ const sleep = opts.sleep ?? ((ms) => new Promise((resolve6) => setTimeout(resolve6, ms)));
3712
3712
  let lastErr;
3713
3713
  for (let i = 0; i < attempts; i++) {
3714
3714
  const isLast = i === attempts - 1;
@@ -3745,7 +3745,7 @@ function defaultHubSessionCachePath(env = process.env) {
3745
3745
  const base2 = env.LOCALAPPDATA || (0, import_node_path3.join)((0, import_node_os.homedir)(), "AppData", "Local");
3746
3746
  return (0, import_node_path3.join)(base2, "MMI Future", "mmi-cli", "hub-session.json");
3747
3747
  }
3748
- const base = env.XDG_STATE_HOME || (0, import_node_path3.join)((0, import_node_os.homedir)(), ".mmi");
3748
+ const base = env.XDG_STATE_HOME || (0, import_node_path3.join)((0, import_node_os.homedir)(), ".local", "state");
3749
3749
  return (0, import_node_path3.join)(base, "mmi-cli", "hub-session.json");
3750
3750
  }
3751
3751
  function readCache(path2, apiUrl, now, githubTokenFingerprint) {
@@ -3852,8 +3852,8 @@ async function readStdin(opts = {}) {
3852
3852
  })().catch(() => {
3853
3853
  });
3854
3854
  let timer;
3855
- const timeout = new Promise((resolve5) => {
3856
- timer = setTimeout(resolve5, timeoutMs);
3855
+ const timeout = new Promise((resolve6) => {
3856
+ timer = setTimeout(resolve6, timeoutMs);
3857
3857
  });
3858
3858
  try {
3859
3859
  await Promise.race([drain, timeout]);
@@ -3948,8 +3948,8 @@ async function syncDocs(deps, docs2 = SYNCED_DOCS) {
3948
3948
  }
3949
3949
 
3950
3950
  // src/session-start.ts
3951
- var import_node_fs6 = require("node:fs");
3952
- var import_node_path6 = require("node:path");
3951
+ var import_node_fs7 = require("node:fs");
3952
+ var import_node_path7 = require("node:path");
3953
3953
 
3954
3954
  // src/scratch-gc.ts
3955
3955
  var import_node_child_process4 = require("node:child_process");
@@ -3980,15 +3980,12 @@ function hashContent(s) {
3980
3980
  }
3981
3981
 
3982
3982
  // src/scratch-gc.ts
3983
- var TMP_STALE_MS = 6e4;
3984
- var FLUSH_LOCK_GC_MS = 6e5;
3985
3983
  var HEAD_TS_STALE_MS = 48 * 36e5;
3986
- var CONFLICT_COPY_STALE_MS = 24 * 36e5;
3987
3984
  var PLAN_ADVISORY_AGE_MS = 30 * 24 * 36e5;
3988
3985
  var ROOT_SCRATCH_STALE_MS = 24 * 36e5;
3989
3986
  var SCRATCH_GC_THROTTLE_MS = 24 * 36e5;
3990
- function scratchGcThrottlePath(mmiRoot) {
3991
- return (0, import_node_path5.join)(mmiRoot, "head-ts", ".scratch-gc-last");
3987
+ function scratchGcThrottlePath(runtimeRoot) {
3988
+ return (0, import_node_path5.join)(runtimeRoot, "head-ts", ".scratch-gc-last");
3992
3989
  }
3993
3990
  function scratchGcDue(stampPath, now = Date.now(), read = import_node_fs5.readFileSync) {
3994
3991
  try {
@@ -4046,21 +4043,11 @@ function buildPrMergeScratchHousekeeping(repoRoot, deps = {}) {
4046
4043
  }
4047
4044
  var ROOT_SCRATCH_DIRS = /* @__PURE__ */ new Set(["tmp", ".playwright-mcp", "test-results", "playwright-report"]);
4048
4045
  var ROOT_SCRATCH_FILE_PREFIXES = ["tmp_"];
4049
- var NEVER_BASENAMES = /* @__PURE__ */ new Set([".session", "config.json", "saga-pending.jsonl"]);
4050
- var TMP_SIDECAR_BASES = ["saga-pending.jsonl"];
4051
- var CONFLICT_COPY_ALLOWLIST = /* @__PURE__ */ new Set(["saga-pending.jsonl"]);
4052
- function conflictCopyOriginal(name) {
4053
- const m = /^(.+) \d+(\.[^.]+)$/.exec(name);
4054
- return m ? `${m[1]}${m[2]}` : null;
4055
- }
4056
- function isTmpSidecar(name) {
4057
- return name.endsWith(".tmp") && TMP_SIDECAR_BASES.some((b) => name.startsWith(`${b}.`));
4058
- }
4046
+ var NEVER_BASENAMES = /* @__PURE__ */ new Set([".session", "config.json"]);
4059
4047
  function planScratchGc(snap, now = Date.now()) {
4060
4048
  const candidates = [];
4061
4049
  const normalizePath = (p) => p.replace(/\\/g, "/");
4062
4050
  const repoRoot = normalizePath((snap.repoRoot ?? (0, import_node_path5.dirname)(snap.mmiRoot)).replace(/[\\/]+$/, ""));
4063
- const mmiPaths = new Set(snap.mmiFiles.map((f) => normalizePath(f.path)));
4064
4051
  const headTsPrefix = `${snap.mmiRoot.replace(/[\\/]+$/, "")}/head-ts/`.replace(/\\/g, "/");
4065
4052
  const days = (ms) => `${Math.floor(ms / 864e5)}d`;
4066
4053
  for (const f of snap.rootScratchFiles ?? []) {
@@ -4094,23 +4081,11 @@ function planScratchGc(snap, now = Date.now()) {
4094
4081
  for (const f of snap.mmiFiles) {
4095
4082
  const age = now - f.mtimeMs;
4096
4083
  const add = (family, reason) => candidates.push({ path: f.path, family, kind: "file", tier: "safe-auto", reason, bytes: f.bytes });
4097
- if (isTmpSidecar(f.name)) {
4098
- if (age > TMP_STALE_MS) add("tmp-sidecar", `crashed atomic-write sidecar (${days(age)} old)`);
4099
- continue;
4100
- }
4101
- if (f.name === "saga-flush.lock") {
4102
- if (age > FLUSH_LOCK_GC_MS) add("flush-lock", `abandoned flush lock (${days(age)} old)`);
4103
- continue;
4104
- }
4105
4084
  if (NEVER_BASENAMES.has(f.name)) continue;
4106
4085
  if (f.path.replace(/\\/g, "/").startsWith(headTsPrefix) && !f.name.startsWith(".")) {
4107
4086
  if (age > HEAD_TS_STALE_MS) add("head-ts", `stale throttle stamp (${days(age)} old)`);
4108
4087
  continue;
4109
4088
  }
4110
- const orig = conflictCopyOriginal(f.name);
4111
- if (orig && CONFLICT_COPY_ALLOWLIST.has(orig) && mmiPaths.has(normalizePath((0, import_node_path5.join)(f.dir, orig))) && age > CONFLICT_COPY_STALE_MS) {
4112
- add("conflict-copy", `cloud-sync conflict copy of ${orig} (${days(age)} old)`);
4113
- }
4114
4089
  }
4115
4090
  if (snap.syncQueueSlugs === null) {
4116
4091
  for (const f of snap.planMdFiles) {
@@ -4330,7 +4305,7 @@ function applyScratchGc(plan, mmiRoot, now = Date.now()) {
4330
4305
  continue;
4331
4306
  }
4332
4307
  }
4333
- const floor = c.family === "flush-lock" ? FLUSH_LOCK_GC_MS : c.family === "tmp-sidecar" ? TMP_STALE_MS : c.family === "head-ts" ? HEAD_TS_STALE_MS : c.family === "conflict-copy" ? CONFLICT_COPY_STALE_MS : c.family === "plan" ? PLAN_ADVISORY_AGE_MS : c.family === "scratch-dir" || c.family === "scratch-file" ? ROOT_SCRATCH_STALE_MS : 0;
4308
+ const floor = c.family === "head-ts" ? HEAD_TS_STALE_MS : c.family === "plan" ? PLAN_ADVISORY_AGE_MS : c.family === "scratch-dir" || c.family === "scratch-file" ? ROOT_SCRATCH_STALE_MS : 0;
4334
4309
  if (floor > 0 && now - st.mtimeMs <= floor) {
4335
4310
  result.skipped += 1;
4336
4311
  continue;
@@ -4498,6 +4473,40 @@ function collectScratchSnapshot(repoRoot, deps = {}) {
4498
4473
  return { repoRoot, mmiRoot, mmiFiles, rootScratchFiles, planMdFiles, planMeta, project: project2, syncQueueSlugs };
4499
4474
  }
4500
4475
 
4476
+ // src/repo-runtime-state.ts
4477
+ var import_node_crypto2 = require("node:crypto");
4478
+ var import_node_fs6 = require("node:fs");
4479
+ var import_node_os2 = require("node:os");
4480
+ var import_node_path6 = require("node:path");
4481
+ var RUNTIME_DIR = "mmi-runtime";
4482
+ function hashPath(path2) {
4483
+ return (0, import_node_crypto2.createHash)("sha256").update((0, import_node_path6.resolve)(path2)).digest("hex").slice(0, 16);
4484
+ }
4485
+ function resolveGitDir(cwd) {
4486
+ const dotGit = (0, import_node_path6.join)(cwd, ".git");
4487
+ try {
4488
+ const st = (0, import_node_fs6.statSync)(dotGit);
4489
+ if (st.isDirectory()) return dotGit;
4490
+ if (!st.isFile()) return void 0;
4491
+ } catch {
4492
+ return void 0;
4493
+ }
4494
+ try {
4495
+ const raw = (0, import_node_fs6.readFileSync)(dotGit, "utf8").trim();
4496
+ const match = /^gitdir:\s*(.+)$/i.exec(raw);
4497
+ if (!match) return void 0;
4498
+ const gitdir = match[1].trim();
4499
+ return (0, import_node_path6.isAbsolute)(gitdir) ? gitdir : (0, import_node_path6.resolve)(cwd, gitdir);
4500
+ } catch {
4501
+ return void 0;
4502
+ }
4503
+ }
4504
+ function repoRuntimeStatePath(cwd, ...parts) {
4505
+ const gitDir = resolveGitDir(cwd);
4506
+ if (gitDir && (0, import_node_fs6.existsSync)(gitDir)) return (0, import_node_path6.join)(gitDir, RUNTIME_DIR, ...parts);
4507
+ return (0, import_node_path6.join)((0, import_node_os2.tmpdir)(), "mmi-cli", hashPath(cwd), ...parts);
4508
+ }
4509
+
4501
4510
  // src/session-start.ts
4502
4511
  async function runBufferedStep(step) {
4503
4512
  const lines = [];
@@ -4542,20 +4551,20 @@ function spawnDetachedSelf(args, deps) {
4542
4551
  } catch {
4543
4552
  }
4544
4553
  }
4545
- function isInsideRepoSubdir(cwd, exists = import_node_fs6.existsSync) {
4546
- if (exists((0, import_node_path6.join)(cwd, ".git"))) return false;
4554
+ function isInsideRepoSubdir(cwd, exists = import_node_fs7.existsSync) {
4555
+ if (exists((0, import_node_path7.join)(cwd, ".git"))) return false;
4547
4556
  let dir = cwd;
4548
4557
  for (; ; ) {
4549
- const parent = (0, import_node_path6.dirname)(dir);
4558
+ const parent = (0, import_node_path7.dirname)(dir);
4550
4559
  if (parent === dir) return false;
4551
- if (exists((0, import_node_path6.join)(parent, ".git"))) return true;
4560
+ if (exists((0, import_node_path7.join)(parent, ".git"))) return true;
4552
4561
  dir = parent;
4553
4562
  }
4554
4563
  }
4555
4564
  function scratchGcLines(cwd, env = process.env, now = Date.now()) {
4556
4565
  if (env.MMI_NO_AUTO_GC) return [];
4557
4566
  try {
4558
- const stamp = scratchGcThrottlePath((0, import_node_path6.join)(cwd, ".mmi"));
4567
+ const stamp = scratchGcThrottlePath(repoRuntimeStatePath(cwd));
4559
4568
  if (!scratchGcDue(stamp, now)) return [];
4560
4569
  const run = executeScratchGc(cwd, { apply: true }, now);
4561
4570
  markScratchGcRun(stamp, now);
@@ -5533,16 +5542,16 @@ function ghError(e) {
5533
5542
  }
5534
5543
 
5535
5544
  // src/board-slice-cache.ts
5536
- var import_node_fs7 = require("node:fs");
5537
- var import_node_path7 = require("node:path");
5538
- var BOARD_SLICE_CACHE_FILE = (0, import_node_path7.join)(".mmi", "board-slice.json");
5545
+ var import_node_fs8 = require("node:fs");
5546
+ var import_node_path8 = require("node:path");
5547
+ var BOARD_SLICE_CACHE_FILE = (0, import_node_path8.join)("board-slice.json");
5539
5548
  var BOARD_SLICE_CACHE_TTL_MS = 10 * 60 * 1e3;
5540
5549
  function boardSliceCachePath(cwd) {
5541
- return (0, import_node_path7.join)(cwd, BOARD_SLICE_CACHE_FILE);
5550
+ return repoRuntimeStatePath(cwd, BOARD_SLICE_CACHE_FILE);
5542
5551
  }
5543
5552
  function readCachedBoardSlice(cwd) {
5544
5553
  try {
5545
- const parsed = JSON.parse((0, import_node_fs7.readFileSync)(boardSliceCachePath(cwd), "utf8"));
5554
+ const parsed = JSON.parse((0, import_node_fs8.readFileSync)(boardSliceCachePath(cwd), "utf8"));
5546
5555
  if (typeof parsed.ts !== "number") return null;
5547
5556
  return { block: typeof parsed.block === "string" ? parsed.block : null, ts: parsed.ts };
5548
5557
  } catch {
@@ -5553,12 +5562,12 @@ function writeCachedBoardSlice(cwd, slice) {
5553
5562
  const path2 = boardSliceCachePath(cwd);
5554
5563
  const tmp = `${path2}.${process.pid}.tmp`;
5555
5564
  try {
5556
- (0, import_node_fs7.mkdirSync)((0, import_node_path7.dirname)(path2), { recursive: true });
5557
- (0, import_node_fs7.writeFileSync)(tmp, JSON.stringify(slice));
5558
- (0, import_node_fs7.renameSync)(tmp, path2);
5565
+ (0, import_node_fs8.mkdirSync)((0, import_node_path8.dirname)(path2), { recursive: true });
5566
+ (0, import_node_fs8.writeFileSync)(tmp, JSON.stringify(slice));
5567
+ (0, import_node_fs8.renameSync)(tmp, path2);
5559
5568
  } catch {
5560
5569
  try {
5561
- (0, import_node_fs7.rmSync)(tmp, { force: true });
5570
+ (0, import_node_fs8.rmSync)(tmp, { force: true });
5562
5571
  } catch {
5563
5572
  }
5564
5573
  }
@@ -5570,7 +5579,7 @@ function boardSliceCacheStale(cached, now, ttlMs = BOARD_SLICE_CACHE_TTL_MS) {
5570
5579
  // src/board-slice.ts
5571
5580
  var SESSION_START_BOARD_TIMEOUT_MS = 3e3;
5572
5581
  var BOARD_SLICE_REFRESH_TIMEOUT_MS = 3e4;
5573
- var BOARD_SLICE_FRAMING = "BOARD SLICE \u2014 reconcile with saga HEAD; board Status is authoritative for work lifecycle.";
5582
+ var BOARD_SLICE_FRAMING = "BOARD SLICE \u2014 board Status is authoritative for work lifecycle.";
5574
5583
  var BOARD_SLICE_EMPTY = "Board: nothing assigned or claimable right now \u2014 `mmi-cli board read` (or `/mmi`) for the full board.";
5575
5584
  var BOARD_SLICE_PENDING = "Board: loading your slice in the background \u2014 run `/mmi` now; it renders here next session.";
5576
5585
  var BOARD_SLICE_MAX_LINES = 5;
@@ -5686,8 +5695,8 @@ async function refreshBoardSliceCache(deps) {
5686
5695
  }
5687
5696
 
5688
5697
  // src/worktree.ts
5689
- var import_node_fs8 = require("node:fs");
5690
- var import_node_path8 = require("node:path");
5698
+ var import_node_fs9 = require("node:fs");
5699
+ var import_node_path9 = require("node:path");
5691
5700
  var LOCAL_ONLY_FILES = [".claude/settings.local.json"];
5692
5701
  var PKG = "package.json";
5693
5702
  var LOCKFILE = "package-lock.json";
@@ -5695,21 +5704,21 @@ var NODE_MODULES = "node_modules";
5695
5704
  var realFsProbe = {
5696
5705
  isDir: (p) => {
5697
5706
  try {
5698
- return (0, import_node_fs8.statSync)(p).isDirectory();
5707
+ return (0, import_node_fs9.statSync)(p).isDirectory();
5699
5708
  } catch {
5700
5709
  return false;
5701
5710
  }
5702
5711
  },
5703
5712
  isFile: (p) => {
5704
5713
  try {
5705
- return (0, import_node_fs8.statSync)(p).isFile();
5714
+ return (0, import_node_fs9.statSync)(p).isFile();
5706
5715
  } catch {
5707
5716
  return false;
5708
5717
  }
5709
5718
  },
5710
5719
  listDirs: (p) => {
5711
5720
  try {
5712
- return (0, import_node_fs8.readdirSync)(p, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
5721
+ return (0, import_node_fs9.readdirSync)(p, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
5713
5722
  } catch {
5714
5723
  return [];
5715
5724
  }
@@ -5717,12 +5726,12 @@ var realFsProbe = {
5717
5726
  };
5718
5727
  function scanInstallDirs(root, fs2 = realFsProbe) {
5719
5728
  const factsFor = (dir) => {
5720
- const abs = dir ? (0, import_node_path8.join)(root, dir) : root;
5729
+ const abs = dir ? (0, import_node_path9.join)(root, dir) : root;
5721
5730
  return {
5722
5731
  dir,
5723
- hasPackageJson: fs2.isFile((0, import_node_path8.join)(abs, PKG)),
5724
- hasLockfile: fs2.isFile((0, import_node_path8.join)(abs, LOCKFILE)),
5725
- hasNodeModules: fs2.isDir((0, import_node_path8.join)(abs, NODE_MODULES))
5732
+ hasPackageJson: fs2.isFile((0, import_node_path9.join)(abs, PKG)),
5733
+ hasLockfile: fs2.isFile((0, import_node_path9.join)(abs, LOCKFILE)),
5734
+ hasNodeModules: fs2.isDir((0, import_node_path9.join)(abs, NODE_MODULES))
5726
5735
  };
5727
5736
  };
5728
5737
  const children = fs2.listDirs(root).filter((name) => name !== NODE_MODULES && name !== ".git");
@@ -5732,7 +5741,7 @@ function npmInstallTargets(dirs) {
5732
5741
  return dirs.filter((d) => d.hasPackageJson && !d.hasNodeModules).map((d) => ({ dir: d.dir, command: d.hasLockfile ? "npm ci" : "npm install" }));
5733
5742
  }
5734
5743
  function isLinkedWorktree(root, fs2 = realFsProbe) {
5735
- return fs2.isFile((0, import_node_path8.join)(root, ".git"));
5744
+ return fs2.isFile((0, import_node_path9.join)(root, ".git"));
5736
5745
  }
5737
5746
  function worktreeAutoProvisionBanner(root, fs2 = realFsProbe) {
5738
5747
  if (!isLinkedWorktree(root, fs2)) return null;
@@ -5742,8 +5751,8 @@ function worktreeAutoProvisionBanner(root, fs2 = realFsProbe) {
5742
5751
  return `[worktree] provisioning tooling in the background (deps in ${where} + local config) \u2014 \`mmi-cli worktree setup\` to redo`;
5743
5752
  }
5744
5753
  function defaultCopyFile(from, to) {
5745
- (0, import_node_fs8.mkdirSync)((0, import_node_path8.dirname)(to), { recursive: true });
5746
- (0, import_node_fs8.copyFileSync)(from, to);
5754
+ (0, import_node_fs9.mkdirSync)((0, import_node_path9.dirname)(to), { recursive: true });
5755
+ (0, import_node_fs9.copyFileSync)(from, to);
5747
5756
  }
5748
5757
  async function provisionWorktree(worktreeRoot, deps) {
5749
5758
  const fs2 = deps.fs ?? realFsProbe;
@@ -5755,7 +5764,7 @@ async function provisionWorktree(worktreeRoot, deps) {
5755
5764
  const skippedInstall = allDirs.filter((d) => d.hasPackageJson && d.hasNodeModules).map((d) => d.dir);
5756
5765
  const installed = [];
5757
5766
  for (const target of targets) {
5758
- const cwd = target.dir ? (0, import_node_path8.join)(worktreeRoot, target.dir) : worktreeRoot;
5767
+ const cwd = target.dir ? (0, import_node_path9.join)(worktreeRoot, target.dir) : worktreeRoot;
5759
5768
  log(`installing deps: ${target.command} in ${target.dir || "."}`);
5760
5769
  await deps.runInstall(target.command, cwd);
5761
5770
  installed.push(target);
@@ -5764,7 +5773,7 @@ async function provisionWorktree(worktreeRoot, deps) {
5764
5773
  const copySkipped = [];
5765
5774
  const primary = await deps.primaryCheckout();
5766
5775
  for (const rel of LOCAL_ONLY_FILES) {
5767
- const dest = (0, import_node_path8.join)(worktreeRoot, rel);
5776
+ const dest = (0, import_node_path9.join)(worktreeRoot, rel);
5768
5777
  if (fs2.isFile(dest)) {
5769
5778
  copySkipped.push({ file: rel, reason: "already-present" });
5770
5779
  continue;
@@ -5773,11 +5782,11 @@ async function provisionWorktree(worktreeRoot, deps) {
5773
5782
  copySkipped.push({ file: rel, reason: "no-primary" });
5774
5783
  continue;
5775
5784
  }
5776
- if (!fs2.isFile((0, import_node_path8.join)(primary, rel))) {
5785
+ if (!fs2.isFile((0, import_node_path9.join)(primary, rel))) {
5777
5786
  copySkipped.push({ file: rel, reason: "absent-in-primary" });
5778
5787
  continue;
5779
5788
  }
5780
- copyFile((0, import_node_path8.join)(primary, rel), dest);
5789
+ copyFile((0, import_node_path9.join)(primary, rel), dest);
5781
5790
  copied.push(rel);
5782
5791
  log(`copied local config: ${rel}`);
5783
5792
  }
@@ -5785,7 +5794,7 @@ async function provisionWorktree(worktreeRoot, deps) {
5785
5794
  }
5786
5795
  function defaultWorktreePath(repoRoot, branch) {
5787
5796
  const safe = branch.replace(/[/\\]+/g, "-");
5788
- return (0, import_node_path8.join)((0, import_node_path8.dirname)(repoRoot), "mmi-worktrees", safe);
5797
+ return (0, import_node_path9.join)((0, import_node_path9.dirname)(repoRoot), "mmi-worktrees", safe);
5789
5798
  }
5790
5799
  function resolveWorktreeBase(from, remote) {
5791
5800
  const remotePrefix = `${remote}/`;
@@ -5817,7 +5826,7 @@ function whoamiLine(report) {
5817
5826
  }
5818
5827
 
5819
5828
  // src/index.ts
5820
- var import_node_path17 = require("node:path");
5829
+ var import_node_path18 = require("node:path");
5821
5830
 
5822
5831
  // src/merge-ci-policy.ts
5823
5832
  function resolveMergeCiPolicy(input) {
@@ -6056,12 +6065,6 @@ var MANAGED_GITIGNORE_LINES = [
6056
6065
  "docs/superpowers/",
6057
6066
  ".playwright-mcp/",
6058
6067
  ".claude/worktrees/",
6059
- // .mmi is agent/CI scratch — ignore the WHOLE tree at any depth (root + cli/.mmi, .github/workflows/.mmi,
6060
- // and any future feature's subdir) so new scratch NEVER needs a new ignore line. `**/.mmi/*` ignores the
6061
- // dir's contents (not the dir itself). hub-v3 step-back: there is no longer a tracked `.mmi/config.json`
6062
- // marker (the org-repo gate is the git `origin` remote check now), so nothing under .mmi is re-included.
6063
- // MMI-Hub's own already-tracked config.json keeps tracking — git never untracks a tracked file.
6064
- "**/.mmi/*",
6065
6068
  ".aws-sam/",
6066
6069
  "/*.png",
6067
6070
  // Runtime secrets/config are vault-only (AGENTS.md "Privileged ops") — never commit a local .env. The
@@ -6948,7 +6951,7 @@ var PR_LAND_STATE_READ_DELAY_MS = 2e3;
6948
6951
  async function readGhPrStateWithRetry(fetchState, options) {
6949
6952
  const retries = options?.retries ?? PR_LAND_STATE_READ_RETRIES;
6950
6953
  const delayMs = options?.delayMs ?? PR_LAND_STATE_READ_DELAY_MS;
6951
- const sleep = options?.sleep ?? ((ms) => new Promise((resolve5) => setTimeout(resolve5, ms)));
6954
+ const sleep = options?.sleep ?? ((ms) => new Promise((resolve6) => setTimeout(resolve6, ms)));
6952
6955
  let lastError = "empty state";
6953
6956
  for (let attempt = 0; attempt < retries; attempt++) {
6954
6957
  try {
@@ -7008,10 +7011,10 @@ async function runPrLand(prNumber, options, deps) {
7008
7011
  }
7009
7012
 
7010
7013
  // src/wave-status.ts
7011
- var import_node_fs10 = require("node:fs");
7014
+ var import_node_fs11 = require("node:fs");
7012
7015
 
7013
7016
  // src/gc.ts
7014
- var import_node_path9 = require("node:path");
7017
+ var import_node_path10 = require("node:path");
7015
7018
  var DEFERRED_SWEEP_COMMAND = "mmi-cli gc sweep-deferred";
7016
7019
  var DEFERRED_NOTE = "Worktree cleanup queued (IDE lock). Detached sweep will retry automatically \u2014 no human action required.";
7017
7020
  var PRESERVED_WORKTREE_CONFIG = "mmi.preservedWorktreeBranch";
@@ -7081,7 +7084,7 @@ async function sweepDeferredWorktreesWithRetry(store, deps, opts = {}) {
7081
7084
  }
7082
7085
  return last;
7083
7086
  }
7084
- var defaultSleep = (ms) => new Promise((resolve5) => setTimeout(resolve5, ms));
7087
+ var defaultSleep = (ms) => new Promise((resolve6) => setTimeout(resolve6, ms));
7085
7088
  async function removeWorktreeWithRecovery(wtPath, deps) {
7086
7089
  const maxAttempts = deps.maxAttempts ?? 3;
7087
7090
  const backoff = deps.backoffMs ?? [250, 1e3];
@@ -7282,8 +7285,8 @@ function resolveSafeSiblingWorktreeCleanupTarget(worktreePath, siblingRoot, deps
7282
7285
  return { ok: true, path: worktreePath };
7283
7286
  }
7284
7287
  function siblingMmiWorktreesRoot(repoRoot) {
7285
- const parent = (0, import_node_path9.dirname)(repoRoot);
7286
- return (0, import_node_path9.basename)(parent).toLowerCase() === "mmi-worktrees" ? parent : (0, import_node_path9.join)(parent, "mmi-worktrees");
7288
+ const parent = (0, import_node_path10.dirname)(repoRoot);
7289
+ return (0, import_node_path10.basename)(parent).toLowerCase() === "mmi-worktrees" ? parent : (0, import_node_path10.join)(parent, "mmi-worktrees");
7287
7290
  }
7288
7291
  function classifySiblingWorktreeDir(entry) {
7289
7292
  if (!entry.ownedByCurrentRepo) {
@@ -7944,15 +7947,15 @@ function formatGcPlan(plan, apply) {
7944
7947
 
7945
7948
  // src/stage-runner.ts
7946
7949
  var import_node_child_process6 = require("node:child_process");
7947
- var import_node_fs9 = require("node:fs");
7948
- var import_node_path10 = require("node:path");
7950
+ var import_node_fs10 = require("node:fs");
7951
+ var import_node_path11 = require("node:path");
7949
7952
  var import_node_net = require("node:net");
7950
7953
  var import_node_util6 = require("node:util");
7951
7954
  var execFileP4 = (0, import_node_util6.promisify)(import_node_child_process6.execFile);
7952
7955
  var DOCKER_TIMEOUT_MS = 15e3;
7953
7956
  var EARLY_EXIT_GRACE_MS = 2e3;
7954
7957
  function waitForProcessStability(child, graceMs = EARLY_EXIT_GRACE_MS) {
7955
- return new Promise((resolve5, reject) => {
7958
+ return new Promise((resolve6, reject) => {
7956
7959
  let settled = false;
7957
7960
  const finish = (fn) => {
7958
7961
  if (settled) return;
@@ -7962,7 +7965,7 @@ function waitForProcessStability(child, graceMs = EARLY_EXIT_GRACE_MS) {
7962
7965
  child.removeAllListeners("exit");
7963
7966
  fn();
7964
7967
  };
7965
- const timer = setTimeout(() => finish(resolve5), graceMs);
7968
+ const timer = setTimeout(() => finish(resolve6), graceMs);
7966
7969
  child.on("error", (err) => finish(() => reject(new Error(`stage process failed to start: ${err.message}`))));
7967
7970
  child.on("exit", (code, signal) => {
7968
7971
  const detail = code != null ? `code ${code}` : signal ? `signal ${signal}` : "unknown reason";
@@ -8062,11 +8065,11 @@ function appendForceRecreate(up) {
8062
8065
  return `${up.trimEnd()} --force-recreate`;
8063
8066
  }
8064
8067
  function stageStatePath(cwd = process.cwd()) {
8065
- return (0, import_node_path10.join)(cwd, "tmp", "stage", "state.json");
8068
+ return (0, import_node_path11.join)(cwd, "tmp", "stage", "state.json");
8066
8069
  }
8067
8070
  function stageGlobalStatePath(cwd = process.cwd(), gitCommonDir = ".git") {
8068
- const dir = (0, import_node_path10.isAbsolute)(gitCommonDir) ? gitCommonDir : (0, import_node_path10.resolve)(cwd, gitCommonDir);
8069
- return (0, import_node_path10.join)(dir, "mmi", "stage", "state.json");
8071
+ const dir = (0, import_node_path11.isAbsolute)(gitCommonDir) ? gitCommonDir : (0, import_node_path11.resolve)(cwd, gitCommonDir);
8072
+ return (0, import_node_path11.join)(dir, "mmi", "stage", "state.json");
8070
8073
  }
8071
8074
  function normPath2(path2) {
8072
8075
  return path2.replace(/\\/g, "/").replace(/\/+$/, "").toLowerCase();
@@ -8172,10 +8175,10 @@ function pickStagePort(range, isFree) {
8172
8175
  throw new Error(`no free stage port in range ${start}-${end} \u2014 every port is in use`);
8173
8176
  }
8174
8177
  function isPortFree(port) {
8175
- return new Promise((resolve5) => {
8178
+ return new Promise((resolve6) => {
8176
8179
  const srv = (0, import_node_net.createServer)();
8177
- srv.once("error", () => resolve5(false));
8178
- srv.once("listening", () => srv.close(() => resolve5(true)));
8180
+ srv.once("error", () => resolve6(false));
8181
+ srv.once("listening", () => srv.close(() => resolve6(true)));
8179
8182
  srv.listen(port, "127.0.0.1");
8180
8183
  });
8181
8184
  }
@@ -8290,14 +8293,14 @@ function stageProcessEnv(stagePort, extraEnv) {
8290
8293
  }
8291
8294
  async function ensureStageRuntimeEnv(config, opts, cwd) {
8292
8295
  if (!config.ensureEnv) return;
8293
- const target = (0, import_node_path10.join)(cwd, config.ensureEnv.target);
8294
- const example = (0, import_node_path10.join)(cwd, config.ensureEnv.example);
8295
- if (!(0, import_node_fs9.existsSync)(target) && (0, import_node_fs9.existsSync)(example)) {
8296
- (0, import_node_fs9.copyFileSync)(example, target);
8297
- } else if ((0, import_node_fs9.existsSync)(target) && (0, import_node_fs9.existsSync)(example)) {
8298
- const stale = detectStaleEnvFile((0, import_node_fs9.readFileSync)(example, "utf8"), (0, import_node_fs9.readFileSync)(target, "utf8"), {
8299
- exampleMtimeMs: (0, import_node_fs9.statSync)(example).mtimeMs,
8300
- targetMtimeMs: (0, import_node_fs9.statSync)(target).mtimeMs
8296
+ const target = (0, import_node_path11.join)(cwd, config.ensureEnv.target);
8297
+ const example = (0, import_node_path11.join)(cwd, config.ensureEnv.example);
8298
+ if (!(0, import_node_fs10.existsSync)(target) && (0, import_node_fs10.existsSync)(example)) {
8299
+ (0, import_node_fs10.copyFileSync)(example, target);
8300
+ } else if ((0, import_node_fs10.existsSync)(target) && (0, import_node_fs10.existsSync)(example)) {
8301
+ const stale = detectStaleEnvFile((0, import_node_fs10.readFileSync)(example, "utf8"), (0, import_node_fs10.readFileSync)(target, "utf8"), {
8302
+ exampleMtimeMs: (0, import_node_fs10.statSync)(example).mtimeMs,
8303
+ targetMtimeMs: (0, import_node_fs10.statSync)(target).mtimeMs
8301
8304
  });
8302
8305
  if (stale) {
8303
8306
  const msg = `stale ${config.ensureEnv.target} (${stale}) \u2014 delete it or refresh from ${config.ensureEnv.example} before re-running /stage`;
@@ -8305,8 +8308,8 @@ async function ensureStageRuntimeEnv(config, opts, cwd) {
8305
8308
  console.error(`mmi-cli stage: ${msg} (allowed via --allow-stale-env)`);
8306
8309
  }
8307
8310
  }
8308
- if (opts.vaultEnvMerge && Object.keys(opts.vaultEnvMerge).length && (0, import_node_fs9.existsSync)(target)) {
8309
- (0, import_node_fs9.writeFileSync)(target, mergeEnvSecretsIntoFile((0, import_node_fs9.readFileSync)(target, "utf8"), opts.vaultEnvMerge), "utf8");
8311
+ if (opts.vaultEnvMerge && Object.keys(opts.vaultEnvMerge).length && (0, import_node_fs10.existsSync)(target)) {
8312
+ (0, import_node_fs10.writeFileSync)(target, mergeEnvSecretsIntoFile((0, import_node_fs10.readFileSync)(target, "utf8"), opts.vaultEnvMerge), "utf8");
8310
8313
  }
8311
8314
  }
8312
8315
  async function gitText(cwd, args) {
@@ -8336,20 +8339,20 @@ async function resolveGlobalStatePath(cwd, explicit) {
8336
8339
  return void 0;
8337
8340
  }
8338
8341
  function readState(path2) {
8339
- if (!(0, import_node_fs9.existsSync)(path2)) return null;
8342
+ if (!(0, import_node_fs10.existsSync)(path2)) return null;
8340
8343
  try {
8341
- return JSON.parse((0, import_node_fs9.readFileSync)(path2, "utf8"));
8344
+ return JSON.parse((0, import_node_fs10.readFileSync)(path2, "utf8"));
8342
8345
  } catch {
8343
8346
  return null;
8344
8347
  }
8345
8348
  }
8346
8349
  function mkdirFor(path2) {
8347
8350
  const dir = path2.slice(0, Math.max(path2.lastIndexOf("/"), path2.lastIndexOf("\\")));
8348
- (0, import_node_fs9.mkdirSync)(dir, { recursive: true });
8351
+ (0, import_node_fs10.mkdirSync)(dir, { recursive: true });
8349
8352
  }
8350
8353
  function writeState(path2, state) {
8351
8354
  mkdirFor(path2);
8352
- (0, import_node_fs9.writeFileSync)(path2, JSON.stringify(state, null, 2), "utf8");
8355
+ (0, import_node_fs10.writeFileSync)(path2, JSON.stringify(state, null, 2), "utf8");
8353
8356
  }
8354
8357
  function writeStagePortReservation(port, cwd, statePath, globalStatePath, now) {
8355
8358
  const reservation = {
@@ -8369,7 +8372,7 @@ async function cleanupStageState(state, paths, timeoutMs, fallbackCwd) {
8369
8372
  await shell(state.teardown.command.trim(), state.teardown.cwd || state.cwd || fallbackCwd, timeoutMs);
8370
8373
  }
8371
8374
  for (const path2 of [...new Set(paths.filter((p) => Boolean(p)))]) {
8372
- (0, import_node_fs9.rmSync)(path2, { force: true });
8375
+ (0, import_node_fs10.rmSync)(path2, { force: true });
8373
8376
  }
8374
8377
  }
8375
8378
  async function killTree(pid) {
@@ -8386,7 +8389,7 @@ async function killTree(pid) {
8386
8389
  } catch {
8387
8390
  }
8388
8391
  }
8389
- await new Promise((resolve5) => setTimeout(resolve5, 500));
8392
+ await new Promise((resolve6) => setTimeout(resolve6, 500));
8390
8393
  try {
8391
8394
  process.kill(-pid, "SIGKILL");
8392
8395
  } catch {
@@ -8407,7 +8410,7 @@ async function waitForHealth(url, timeoutMs, anyStatus = false) {
8407
8410
  } catch (e) {
8408
8411
  last = e.message;
8409
8412
  }
8410
- await new Promise((resolve5) => setTimeout(resolve5, 1e3));
8413
+ await new Promise((resolve6) => setTimeout(resolve6, 1e3));
8411
8414
  }
8412
8415
  throw new Error(`stage health check timed out for ${url}${last ? ` (${last})` : ""}`);
8413
8416
  }
@@ -8525,8 +8528,8 @@ async function runStage(config = {}, opts = {}) {
8525
8528
  await ensureStageRuntimeEnv(config, opts, cwd);
8526
8529
  if (build) await shell(sub(build), cwd, timeoutMs, stageProcessEnv(stagePort, extraEnv));
8527
8530
  } catch (e) {
8528
- (0, import_node_fs9.rmSync)(statePath, { force: true });
8529
- if (globalStatePath && globalStatePath !== statePath) (0, import_node_fs9.rmSync)(globalStatePath, { force: true });
8531
+ (0, import_node_fs10.rmSync)(statePath, { force: true });
8532
+ if (globalStatePath && globalStatePath !== statePath) (0, import_node_fs10.rmSync)(globalStatePath, { force: true });
8530
8533
  throw e;
8531
8534
  }
8532
8535
  const started = await startStage(config, {
@@ -8551,9 +8554,9 @@ function parseNextFromHead(headText) {
8551
8554
  }
8552
8555
  function readStageSummary(worktreePath) {
8553
8556
  const statePath = stageStatePath(worktreePath);
8554
- if (!(0, import_node_fs10.existsSync)(statePath)) return void 0;
8557
+ if (!(0, import_node_fs11.existsSync)(statePath)) return void 0;
8555
8558
  try {
8556
- const state = JSON.parse((0, import_node_fs10.readFileSync)(statePath, "utf8"));
8559
+ const state = JSON.parse((0, import_node_fs11.readFileSync)(statePath, "utf8"));
8557
8560
  const port = typeof state.port === "number" ? state.port : void 0;
8558
8561
  if (port == null || !Number.isInteger(port) || port <= 0) return void 0;
8559
8562
  return { port, url: typeof state.url === "string" ? state.url : void 0 };
@@ -8596,7 +8599,7 @@ async function collectWaveStatus(deps) {
8596
8599
  } catch {
8597
8600
  dirty = true;
8598
8601
  }
8599
- const headText = await deps.fetchSagaHeadText(wt.branch).catch(() => void 0);
8602
+ const headText = await deps.fetchSagaHeadText?.(wt.branch).catch(() => void 0);
8600
8603
  rows.push({
8601
8604
  path: wt.path,
8602
8605
  branch: wt.branch,
@@ -8669,9 +8672,9 @@ async function resolveAutoAddBoardAttach(client, cfg, selector, priority, warn =
8669
8672
 
8670
8673
  // src/gh-create.ts
8671
8674
  var import_promises2 = require("node:fs/promises");
8672
- var import_node_os2 = require("node:os");
8673
- var import_node_path11 = require("node:path");
8674
- var import_node_crypto2 = require("node:crypto");
8675
+ var import_node_os3 = require("node:os");
8676
+ var import_node_path12 = require("node:path");
8677
+ var import_node_crypto3 = require("node:crypto");
8675
8678
  var ISSUE_TYPES = ["bug", "feature", "task"];
8676
8679
  var GH_MUTATION_TIMEOUT_MS = 12e4;
8677
8680
  function timeoutKillNote(err, timeoutMs) {
@@ -8711,7 +8714,7 @@ async function bodyArgsViaFile(args, deps = {}) {
8711
8714
  } };
8712
8715
  const write = deps.write ?? import_promises2.writeFile;
8713
8716
  const remove = deps.remove ?? import_promises2.unlink;
8714
- const file = (0, import_node_path11.join)(deps.dir ?? (0, import_node_os2.tmpdir)(), `mmi-gh-body-${process.pid}-${(0, import_node_crypto2.randomBytes)(4).toString("hex")}.md`);
8717
+ const file = (0, import_node_path12.join)(deps.dir ?? (0, import_node_os3.tmpdir)(), `mmi-gh-body-${process.pid}-${(0, import_node_crypto3.randomBytes)(4).toString("hex")}.md`);
8715
8718
  await write(file, args[i + 1], "utf8");
8716
8719
  return {
8717
8720
  args: [...args.slice(0, i), "--body-file", file, ...args.slice(i + 2)],
@@ -8757,9 +8760,9 @@ function buildPrArgs({ title, body, base, head, repo }) {
8757
8760
  }
8758
8761
 
8759
8762
  // src/issue-body.ts
8760
- var import_node_os3 = require("node:os");
8763
+ var import_node_os4 = require("node:os");
8761
8764
  function emptyStdinMessage(fileFlag) {
8762
- if ((0, import_node_os3.platform)() === "win32") {
8765
+ if ((0, import_node_os4.platform)() === "win32") {
8763
8766
  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)`;
8764
8767
  }
8765
8768
  return `${fileFlag} - read empty stdin (nothing piped \u2014 pass a heredoc/pipe, or ${fileFlag} <path>)`;
@@ -9410,7 +9413,7 @@ function bootstrapPlan(repo, repoClass) {
9410
9413
  { label: `create or inspect ${repo}` },
9411
9414
  { label: `provision branch model: ${branchModel}`, gated: true },
9412
9415
  { label: `apply branch protection / allowlist: ${protectedBranches}`, gated: true },
9413
- { label: "attach GitHub Project v2 and register saga-ready Hub registry META", gated: true },
9416
+ { label: "attach GitHub Project v2 and register Hub registry META", gated: true },
9414
9417
  { label: "seed README.md and architecture.md", gated: true },
9415
9418
  { label: "commit .cursor/rules/<repo>.mdc and .cursor/environment.json", gated: true },
9416
9419
  { label: `register fanout target on ${repoClass === "content" ? "main" : "development"}`, gated: true }
@@ -9600,9 +9603,6 @@ async function runStageLiveDown(deps, t) {
9600
9603
  // src/git-clean-tree.ts
9601
9604
  function isAgentScratchPath(path2) {
9602
9605
  const normalized = path2.replace(/\\/g, "/").trim();
9603
- if (normalized === ".mmi" || normalized.startsWith(".mmi/")) {
9604
- return true;
9605
- }
9606
9606
  return /^tmp_[^/]+$/.test(normalized);
9607
9607
  }
9608
9608
  function porcelainHasBlockingChanges(porcelain) {
@@ -9746,7 +9746,7 @@ async function runMergeTreePreflight(deps, ours, theirs) {
9746
9746
  async function predictMergeConflicts(deps, ours, theirs) {
9747
9747
  return runMergeTreePreflight(deps, ours, theirs);
9748
9748
  }
9749
- async function mergeWithToleratedResolution(deps, sourceRef, label, resolve5, extraTolerated = []) {
9749
+ async function mergeWithToleratedResolution(deps, sourceRef, label, resolve6, extraTolerated = []) {
9750
9750
  try {
9751
9751
  await deps.run("git", ["merge", sourceRef, "--no-edit"]);
9752
9752
  return;
@@ -9760,7 +9760,7 @@ async function mergeWithToleratedResolution(deps, sourceRef, label, resolve5, ex
9760
9760
  unmerged.length === 0 ? `${label} merge failed without conflicted paths \u2014 merge aborted; inspect the repo state and rerun` : `${label} merge conflicts on untolerated path(s): ${blocking.join(", ")} \u2014 merge aborted (the train is misaligned; reconcile the branches via an approved alignment PR, then rerun)`
9761
9761
  );
9762
9762
  }
9763
- await deps.run("git", ["checkout", `--${resolve5}`, "--", ...unmerged]);
9763
+ await deps.run("git", ["checkout", `--${resolve6}`, "--", ...unmerged]);
9764
9764
  await deps.run("git", ["add", "--", ...unmerged]);
9765
9765
  await deps.run("git", ["commit", "--no-edit"]);
9766
9766
  }
@@ -9877,7 +9877,7 @@ function requireProjectMetaForTrain(load, repo) {
9877
9877
  var CORRELATE_ATTEMPTS = 5;
9878
9878
  var CORRELATE_DELAY_MS = 1500;
9879
9879
  var CORRELATE_SKEW_SLACK_MS = 1e4;
9880
- var defaultSleep2 = (ms) => new Promise((resolve5) => setTimeout(resolve5, ms));
9880
+ var defaultSleep2 = (ms) => new Promise((resolve6) => setTimeout(resolve6, ms));
9881
9881
  function resolveSleep(deps) {
9882
9882
  return deps.sleep ?? defaultSleep2;
9883
9883
  }
@@ -10887,7 +10887,7 @@ function clean2(out) {
10887
10887
  return out.trim();
10888
10888
  }
10889
10889
  function sleeper(deps) {
10890
- return deps.sleep ?? ((ms) => new Promise((resolve5) => setTimeout(resolve5, ms)));
10890
+ return deps.sleep ?? ((ms) => new Promise((resolve6) => setTimeout(resolve6, ms)));
10891
10891
  }
10892
10892
  function normalizeHotfixVersion(input) {
10893
10893
  const m = /^v?(\d+\.\d+\.\d+)$/.exec(input.trim());
@@ -11464,8 +11464,8 @@ async function announceRelease(deps, args) {
11464
11464
  }
11465
11465
 
11466
11466
  // src/port-registry.ts
11467
- var import_node_fs11 = require("node:fs");
11468
- var import_node_path12 = require("node:path");
11467
+ var import_node_fs12 = require("node:fs");
11468
+ var import_node_path13 = require("node:path");
11469
11469
 
11470
11470
  // ../infra/port-geometry.mjs
11471
11471
  var PORT_BLOCK = 100;
@@ -11479,8 +11479,8 @@ function nextPortBlock(registry2) {
11479
11479
  return [base, base + PORT_SPAN];
11480
11480
  }
11481
11481
  function loadPortRegistry(path2) {
11482
- if (!(0, import_node_fs11.existsSync)(path2)) return {};
11483
- const raw = JSON.parse((0, import_node_fs11.readFileSync)(path2, "utf8"));
11482
+ if (!(0, import_node_fs12.existsSync)(path2)) return {};
11483
+ const raw = JSON.parse((0, import_node_fs12.readFileSync)(path2, "utf8"));
11484
11484
  const out = {};
11485
11485
  for (const [key, value] of Object.entries(raw)) {
11486
11486
  if (Array.isArray(value) && value.length === 2 && value.every((n) => typeof n === "number")) {
@@ -11494,9 +11494,9 @@ function ensurePortRange(repo, path2) {
11494
11494
  const existing = registry2[repo];
11495
11495
  if (existing) return existing;
11496
11496
  const range = nextPortBlock(registry2);
11497
- const raw = (0, import_node_fs11.existsSync)(path2) ? JSON.parse((0, import_node_fs11.readFileSync)(path2, "utf8")) : {};
11497
+ const raw = (0, import_node_fs12.existsSync)(path2) ? JSON.parse((0, import_node_fs12.readFileSync)(path2, "utf8")) : {};
11498
11498
  raw[repo] = range;
11499
- (0, import_node_fs11.writeFileSync)(path2, JSON.stringify(raw, null, 2) + "\n", "utf8");
11499
+ (0, import_node_fs12.writeFileSync)(path2, JSON.stringify(raw, null, 2) + "\n", "utf8");
11500
11500
  return range;
11501
11501
  }
11502
11502
  function portCursorSeed(registry2) {
@@ -11518,18 +11518,18 @@ function existingPortRange(repo, registry2) {
11518
11518
  return registry2[repo] ?? null;
11519
11519
  }
11520
11520
  function portRangeInfraAt(root, source) {
11521
- const registryPath = (0, import_node_path12.join)(root, "infra", "port-ranges.json");
11522
- const ddbScriptPath = (0, import_node_path12.join)(root, "infra", "port-ddb.mjs");
11523
- if (!(0, import_node_fs11.existsSync)(registryPath) || !(0, import_node_fs11.existsSync)(ddbScriptPath)) return null;
11521
+ const registryPath = (0, import_node_path13.join)(root, "infra", "port-ranges.json");
11522
+ const ddbScriptPath = (0, import_node_path13.join)(root, "infra", "port-ddb.mjs");
11523
+ if (!(0, import_node_fs12.existsSync)(registryPath) || !(0, import_node_fs12.existsSync)(ddbScriptPath)) return null;
11524
11524
  return { root, source, registryPath, ddbScriptPath };
11525
11525
  }
11526
11526
  function resolvePortRangeInfra(cwd) {
11527
11527
  const direct = portRangeInfraAt(cwd, "cwd");
11528
11528
  if (direct) return direct;
11529
- for (let dir = cwd; ; dir = (0, import_node_path12.dirname)(dir)) {
11530
- const sibling = portRangeInfraAt((0, import_node_path12.join)(dir, "MMI-Hub"), "sibling-hub");
11529
+ for (let dir = cwd; ; dir = (0, import_node_path13.dirname)(dir)) {
11530
+ const sibling = portRangeInfraAt((0, import_node_path13.join)(dir, "MMI-Hub"), "sibling-hub");
11531
11531
  if (sibling) return sibling;
11532
- const parent = (0, import_node_path12.dirname)(dir);
11532
+ const parent = (0, import_node_path13.dirname)(dir);
11533
11533
  if (parent === dir) return null;
11534
11534
  }
11535
11535
  }
@@ -14307,8 +14307,8 @@ async function secretsUse(deps, key, opts) {
14307
14307
  }
14308
14308
 
14309
14309
  // src/secrets-commands.ts
14310
- var import_node_fs12 = require("node:fs");
14311
- var import_node_path13 = require("node:path");
14310
+ var import_node_fs13 = require("node:fs");
14311
+ var import_node_path14 = require("node:path");
14312
14312
  var RAILS_CREDENTIALS_DECRYPT_TIMEOUT_MS = 3e4;
14313
14313
  var DEFAULT_RAILS_CREDENTIALS_FILE = "config/credentials.yml.enc";
14314
14314
  var DEFAULT_RAILS_MASTER_KEY_FILE = "config/master.key";
@@ -14316,18 +14316,18 @@ function collectMap(value, previous = []) {
14316
14316
  return [...previous, value];
14317
14317
  }
14318
14318
  async function decryptRailsCredentials(input) {
14319
- const appDir = (0, import_node_path13.resolve)(input.appDir ?? process.cwd());
14319
+ const appDir = (0, import_node_path14.resolve)(input.appDir ?? process.cwd());
14320
14320
  const credentialsFile = input.credentialsFile ?? DEFAULT_RAILS_CREDENTIALS_FILE;
14321
14321
  const masterKeyFile = input.masterKeyFile ?? DEFAULT_RAILS_MASTER_KEY_FILE;
14322
- const credentialsPath = (0, import_node_path13.resolve)(appDir, credentialsFile);
14323
- const masterKeyPath = (0, import_node_path13.resolve)(appDir, masterKeyFile);
14322
+ const credentialsPath = (0, import_node_path14.resolve)(appDir, credentialsFile);
14323
+ const masterKeyPath = (0, import_node_path14.resolve)(appDir, masterKeyFile);
14324
14324
  const env = {
14325
14325
  ...process.env,
14326
14326
  MMI_RAILS_CREDENTIALS_FILE: credentialsPath,
14327
14327
  MMI_RAILS_MASTER_KEY_FILE: masterKeyPath
14328
14328
  };
14329
- if ((0, import_node_fs12.existsSync)(masterKeyPath)) {
14330
- env.RAILS_MASTER_KEY = (0, import_node_fs12.readFileSync)(masterKeyPath, "utf8").trim();
14329
+ if ((0, import_node_fs13.existsSync)(masterKeyPath)) {
14330
+ env.RAILS_MASTER_KEY = (0, import_node_fs13.readFileSync)(masterKeyPath, "utf8").trim();
14331
14331
  }
14332
14332
  const script = [
14333
14333
  'require "json"',
@@ -14393,7 +14393,7 @@ function registerSecretsCommands(program3) {
14393
14393
  secrets.command("org-catalog").description("MASTER-ONLY: set the _org/<provider>/* catalog declarations from a JSON file (#2244)").requiredOption("--file <path>", 'JSON file: { "entries": { "<provider>/<KEY>": {key,purpose,group,owner,provider,stages[],consumers[]} } }').action((o) => withSecrets(async (d) => {
14394
14394
  let body;
14395
14395
  try {
14396
- body = (0, import_node_fs12.readFileSync)((0, import_node_path13.resolve)(o.file), "utf8");
14396
+ body = (0, import_node_fs13.readFileSync)((0, import_node_path14.resolve)(o.file), "utf8");
14397
14397
  } catch (e) {
14398
14398
  return fail(`secrets org-catalog: cannot read --file ${o.file}: ${e.message}`);
14399
14399
  }
@@ -14468,7 +14468,7 @@ function registerSecretsCommands(program3) {
14468
14468
  {
14469
14469
  ...d,
14470
14470
  decryptRailsCredentials,
14471
- removeFile: (path2) => (0, import_node_fs12.unlinkSync)((0, import_node_path13.resolve)(o.appDir ?? process.cwd(), path2))
14471
+ removeFile: (path2) => (0, import_node_fs13.unlinkSync)((0, import_node_path14.resolve)(o.appDir ?? process.cwd(), path2))
14472
14472
  },
14473
14473
  {
14474
14474
  repo: o.repo,
@@ -14557,11 +14557,11 @@ function registerEdgeCommands(program3) {
14557
14557
  }
14558
14558
 
14559
14559
  // src/doctor-run.ts
14560
- var import_node_fs16 = require("node:fs");
14560
+ var import_node_fs17 = require("node:fs");
14561
14561
  var import_node_child_process10 = require("node:child_process");
14562
14562
  var import_promises3 = require("node:fs/promises");
14563
- var import_node_path16 = require("node:path");
14564
- var import_node_os5 = require("node:os");
14563
+ var import_node_path17 = require("node:path");
14564
+ var import_node_os6 = require("node:os");
14565
14565
 
14566
14566
  // src/plugin-guard.ts
14567
14567
  function buildPluginGuardDecision(i) {
@@ -14582,9 +14582,9 @@ function buildGuardSessionStartLine(state, opts = {}) {
14582
14582
 
14583
14583
  // src/cursor-plugin-seed.ts
14584
14584
  var import_node_child_process9 = require("node:child_process");
14585
- var import_node_fs13 = require("node:fs");
14586
- var import_node_os4 = require("node:os");
14587
- var import_node_path14 = require("node:path");
14585
+ var import_node_fs14 = require("node:fs");
14586
+ var import_node_os5 = require("node:os");
14587
+ var import_node_path15 = require("node:path");
14588
14588
  var import_node_util7 = require("node:util");
14589
14589
  function isSemverVersion(v) {
14590
14590
  return typeof v === "string" && /^v?\d+\.\d+\.\d+/.test(v.trim());
@@ -14601,17 +14601,17 @@ function ghReleaseTarballApiArgs(tag) {
14601
14601
  }
14602
14602
  function cursorUserGlobalStatePath() {
14603
14603
  if (process.platform === "win32") {
14604
- const base = process.env.APPDATA || (0, import_node_path14.join)((0, import_node_os4.homedir)(), "AppData", "Roaming");
14605
- return (0, import_node_path14.join)(base, "Cursor", "User", "globalStorage", "state.vscdb");
14604
+ const base = process.env.APPDATA || (0, import_node_path15.join)((0, import_node_os5.homedir)(), "AppData", "Roaming");
14605
+ return (0, import_node_path15.join)(base, "Cursor", "User", "globalStorage", "state.vscdb");
14606
14606
  }
14607
14607
  if (process.platform === "darwin") {
14608
- return (0, import_node_path14.join)((0, import_node_os4.homedir)(), "Library", "Application Support", "Cursor", "User", "globalStorage", "state.vscdb");
14608
+ return (0, import_node_path15.join)((0, import_node_os5.homedir)(), "Library", "Application Support", "Cursor", "User", "globalStorage", "state.vscdb");
14609
14609
  }
14610
- return (0, import_node_path14.join)((0, import_node_os4.homedir)(), ".config", "Cursor", "User", "globalStorage", "state.vscdb");
14610
+ return (0, import_node_path15.join)((0, import_node_os5.homedir)(), ".config", "Cursor", "User", "globalStorage", "state.vscdb");
14611
14611
  }
14612
14612
  async function readCursorThirdPartyExtensibilityEnabled(execFileP5) {
14613
14613
  const dbPath = cursorUserGlobalStatePath();
14614
- if (!(0, import_node_fs13.existsSync)(dbPath)) return void 0;
14614
+ if (!(0, import_node_fs14.existsSync)(dbPath)) return void 0;
14615
14615
  try {
14616
14616
  const { stdout } = await execFileP5("sqlite3", [dbPath, `SELECT value FROM ItemTable WHERE key = '${CURSOR_THIRD_PARTY_STATE_KEY}';`], {
14617
14617
  timeout: 5e3
@@ -14625,57 +14625,57 @@ async function readCursorThirdPartyExtensibilityEnabled(execFileP5) {
14625
14625
  }
14626
14626
  }
14627
14627
  function syncDirContents(src, dest) {
14628
- (0, import_node_fs13.mkdirSync)(dest, { recursive: true });
14629
- for (const name of (0, import_node_fs13.readdirSync)(dest)) {
14630
- (0, import_node_fs13.rmSync)((0, import_node_path14.join)(dest, name), { recursive: true, force: true });
14628
+ (0, import_node_fs14.mkdirSync)(dest, { recursive: true });
14629
+ for (const name of (0, import_node_fs14.readdirSync)(dest)) {
14630
+ (0, import_node_fs14.rmSync)((0, import_node_path15.join)(dest, name), { recursive: true, force: true });
14631
14631
  }
14632
- (0, import_node_fs13.cpSync)(src, dest, { recursive: true });
14632
+ (0, import_node_fs14.cpSync)(src, dest, { recursive: true });
14633
14633
  }
14634
14634
  function releaseTag(releasedVersion) {
14635
14635
  return releasedVersion.startsWith("v") ? releasedVersion : `v${releasedVersion}`;
14636
14636
  }
14637
14637
  async function extractPluginMmiFromHubCheckout(hubCheckout, tag, tmpRoot, execFileP5) {
14638
- const tarFile = (0, import_node_path14.join)(tmpRoot, "archive.tar");
14638
+ const tarFile = (0, import_node_path15.join)(tmpRoot, "archive.tar");
14639
14639
  try {
14640
14640
  await execFileP5("git", gitFetchReleaseTagArgs(hubCheckout, tag), { timeout: 6e4 });
14641
14641
  await execFileP5("git", ["-C", hubCheckout, "archive", "--format=tar", `--output=${tarFile}`, tag, "plugins/mmi"], {
14642
14642
  timeout: 6e4
14643
14643
  });
14644
14644
  await execFileP5("tar", ["-xf", tarFile, "-C", tmpRoot], { timeout: 6e4 });
14645
- const pluginMmi = (0, import_node_path14.join)(tmpRoot, "plugins", "mmi");
14646
- return (0, import_node_fs13.existsSync)((0, import_node_path14.join)(pluginMmi, PLUGIN_JSON_REL)) ? pluginMmi : void 0;
14645
+ const pluginMmi = (0, import_node_path15.join)(tmpRoot, "plugins", "mmi");
14646
+ return (0, import_node_fs14.existsSync)((0, import_node_path15.join)(pluginMmi, PLUGIN_JSON_REL)) ? pluginMmi : void 0;
14647
14647
  } catch {
14648
14648
  return void 0;
14649
14649
  }
14650
14650
  }
14651
14651
  async function downloadPluginMmiViaGh(tag, tmpRoot) {
14652
- const tarPath = (0, import_node_path14.join)(tmpRoot, "repo.tgz");
14652
+ const tarPath = (0, import_node_path15.join)(tmpRoot, "repo.tgz");
14653
14653
  try {
14654
- (0, import_node_fs13.mkdirSync)(tmpRoot, { recursive: true });
14654
+ (0, import_node_fs14.mkdirSync)(tmpRoot, { recursive: true });
14655
14655
  const { stdout } = await execFileBuffer("gh", ghReleaseTarballApiArgs(tag), {
14656
14656
  timeout: 12e4,
14657
14657
  maxBuffer: 100 * 1024 * 1024,
14658
14658
  encoding: "buffer",
14659
14659
  windowsHide: true
14660
14660
  });
14661
- (0, import_node_fs13.writeFileSync)(tarPath, stdout);
14661
+ (0, import_node_fs14.writeFileSync)(tarPath, stdout);
14662
14662
  await execFileBuffer("tar", ["-xzf", tarPath, "-C", tmpRoot], { timeout: 12e4, windowsHide: true });
14663
- const top = (0, import_node_fs13.readdirSync)(tmpRoot).find((entry) => entry !== "repo.tgz");
14663
+ const top = (0, import_node_fs14.readdirSync)(tmpRoot).find((entry) => entry !== "repo.tgz");
14664
14664
  if (!top) return void 0;
14665
- const pluginMmi = (0, import_node_path14.join)(tmpRoot, top, "plugins", "mmi");
14666
- return (0, import_node_fs13.existsSync)((0, import_node_path14.join)(pluginMmi, PLUGIN_JSON_REL)) ? pluginMmi : void 0;
14665
+ const pluginMmi = (0, import_node_path15.join)(tmpRoot, top, "plugins", "mmi");
14666
+ return (0, import_node_fs14.existsSync)((0, import_node_path15.join)(pluginMmi, PLUGIN_JSON_REL)) ? pluginMmi : void 0;
14667
14667
  } catch {
14668
14668
  return void 0;
14669
14669
  }
14670
14670
  }
14671
14671
  async function resolvePluginMmiSource(releasedVersion, hubCheckout, tmpRoot, execFileP5) {
14672
- (0, import_node_fs13.mkdirSync)(tmpRoot, { recursive: true });
14672
+ (0, import_node_fs14.mkdirSync)(tmpRoot, { recursive: true });
14673
14673
  const tag = releaseTag(releasedVersion);
14674
14674
  if (hubCheckout) {
14675
14675
  const fromHub = await extractPluginMmiFromHubCheckout(hubCheckout, tag, tmpRoot, execFileP5);
14676
14676
  if (fromHub) return fromHub;
14677
14677
  }
14678
- return downloadPluginMmiViaGh(tag, (0, import_node_path14.join)(tmpRoot, "gh"));
14678
+ return downloadPluginMmiViaGh(tag, (0, import_node_path15.join)(tmpRoot, "gh"));
14679
14679
  }
14680
14680
  function cursorPluginPinsNeedingSeed(pins, releasedVersion) {
14681
14681
  if (!isSemverVersion(releasedVersion)) return pins.filter((pin) => !pin.hasPluginJson || !pin.hasHooksJson || pin.isEmpty);
@@ -14696,7 +14696,7 @@ async function applyCursorPluginCacheSeed(input) {
14696
14696
  for (const pin of pinsToSeed) {
14697
14697
  syncDirContents(source, pin.path);
14698
14698
  }
14699
- (0, import_node_fs13.rmSync)(tmpRoot, { recursive: true, force: true });
14699
+ (0, import_node_fs14.rmSync)(tmpRoot, { recursive: true, force: true });
14700
14700
  return true;
14701
14701
  }
14702
14702
 
@@ -14715,7 +14715,7 @@ function buildGithubAuthCheck(input) {
14715
14715
  const ok = Boolean(input.login?.trim());
14716
14716
  return {
14717
14717
  ok,
14718
- label: "GitHub auth identity (saga + gh ops)",
14718
+ label: "GitHub auth identity (gh ops)",
14719
14719
  fix: input.ghInstalled ? GH_PROJECT_LOGIN_FIX : `install GitHub CLI (https://cli.github.com), then: ${GH_PROJECT_LOGIN_FIX.replace(/^run: /, "")}`
14720
14720
  };
14721
14721
  }
@@ -15802,9 +15802,9 @@ function buildPluginResolvabilityCheck(input) {
15802
15802
  }
15803
15803
 
15804
15804
  // src/cli-doctor-shared.ts
15805
- var import_node_fs14 = require("node:fs");
15806
- var import_node_path15 = require("node:path");
15807
15805
  var import_node_fs15 = require("node:fs");
15806
+ var import_node_path16 = require("node:path");
15807
+ var import_node_fs16 = require("node:fs");
15808
15808
  var GC_GH_TIMEOUT_MS = 2e4;
15809
15809
  async function awsCallerArn() {
15810
15810
  try {
@@ -15850,7 +15850,7 @@ async function localBranchHeads() {
15850
15850
  }
15851
15851
  async function currentRepoWorktreeGitRoot(repoRoot) {
15852
15852
  const gitCommonDir = (await execFileP2("git", ["rev-parse", "--git-common-dir"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim();
15853
- return gitCommonDir ? (0, import_node_path15.resolve)(repoRoot, gitCommonDir, "worktrees") : "";
15853
+ return gitCommonDir ? (0, import_node_path16.resolve)(repoRoot, gitCommonDir, "worktrees") : "";
15854
15854
  }
15855
15855
  async function worktreeBranches() {
15856
15856
  const { stdout } = await execFileP2("git", ["worktree", "list", "--porcelain"], { timeout: GIT_TIMEOUT_MS });
@@ -15870,18 +15870,18 @@ function resolveGitdirForWorktreeFile(worktreePath, content) {
15870
15870
  const match = /^gitdir:\s*(.+)\s*$/im.exec(content);
15871
15871
  if (!match?.[1]) return void 0;
15872
15872
  const raw = match[1].trim();
15873
- return (0, import_node_path15.isAbsolute)(raw) ? raw : (0, import_node_path15.resolve)(worktreePath, raw);
15873
+ return (0, import_node_path16.isAbsolute)(raw) ? raw : (0, import_node_path16.resolve)(worktreePath, raw);
15874
15874
  }
15875
15875
  function metadataOwnsMissingWorktreeDir(worktreePath, worktreeGitRoot) {
15876
15876
  if (!worktreeGitRoot) return false;
15877
15877
  try {
15878
- const entries = (0, import_node_fs15.readdirSync)(worktreeGitRoot, { withFileTypes: true });
15878
+ const entries = (0, import_node_fs16.readdirSync)(worktreeGitRoot, { withFileTypes: true });
15879
15879
  for (const ent of entries) {
15880
15880
  if (!ent.isDirectory()) continue;
15881
15881
  try {
15882
- const gitdirPath = (0, import_node_fs14.readFileSync)((0, import_node_path15.join)(worktreeGitRoot, ent.name, "gitdir"), "utf8").trim();
15883
- const resolvedGitdir = (0, import_node_path15.isAbsolute)(gitdirPath) ? gitdirPath : (0, import_node_path15.resolve)(worktreeGitRoot, ent.name, gitdirPath);
15884
- if (sameWorktreeMetadataPath((0, import_node_path15.dirname)(resolvedGitdir), worktreePath)) return true;
15882
+ const gitdirPath = (0, import_node_fs15.readFileSync)((0, import_node_path16.join)(worktreeGitRoot, ent.name, "gitdir"), "utf8").trim();
15883
+ const resolvedGitdir = (0, import_node_path16.isAbsolute)(gitdirPath) ? gitdirPath : (0, import_node_path16.resolve)(worktreeGitRoot, ent.name, gitdirPath);
15884
+ if (sameWorktreeMetadataPath((0, import_node_path16.dirname)(resolvedGitdir), worktreePath)) return true;
15885
15885
  } catch {
15886
15886
  }
15887
15887
  }
@@ -15891,7 +15891,7 @@ function metadataOwnsMissingWorktreeDir(worktreePath, worktreeGitRoot) {
15891
15891
  }
15892
15892
  function pathExistsKnown(path2) {
15893
15893
  try {
15894
- (0, import_node_fs15.statSync)(path2);
15894
+ (0, import_node_fs16.statSync)(path2);
15895
15895
  return true;
15896
15896
  } catch (e) {
15897
15897
  const code = typeof e === "object" && e && "code" in e ? String(e.code ?? "") : "";
@@ -15900,10 +15900,10 @@ function pathExistsKnown(path2) {
15900
15900
  }
15901
15901
  }
15902
15902
  function inspectSiblingWorktreeDir(path2, worktreeGitRoot) {
15903
- const gitPath = (0, import_node_path15.join)(path2, ".git");
15903
+ const gitPath = (0, import_node_path16.join)(path2, ".git");
15904
15904
  let st;
15905
15905
  try {
15906
- st = (0, import_node_fs15.lstatSync)(gitPath);
15906
+ st = (0, import_node_fs16.lstatSync)(gitPath);
15907
15907
  } catch (e) {
15908
15908
  const code = typeof e === "object" && e && "code" in e ? String(e.code ?? "") : "";
15909
15909
  if (code === "ENOENT" || code === "ENOTDIR") {
@@ -15920,7 +15920,7 @@ function inspectSiblingWorktreeDir(path2, worktreeGitRoot) {
15920
15920
  if (st.isDirectory()) return { path: path2, gitType: "dir" };
15921
15921
  if (!st.isFile()) return { path: path2, gitType: "other" };
15922
15922
  try {
15923
- const gitFileContent = (0, import_node_fs14.readFileSync)(gitPath, "utf8");
15923
+ const gitFileContent = (0, import_node_fs15.readFileSync)(gitPath, "utf8");
15924
15924
  const gitdir = resolveGitdirForWorktreeFile(path2, gitFileContent);
15925
15925
  const gitDirExists = gitdir ? pathExistsKnown(gitdir) : false;
15926
15926
  return {
@@ -15937,7 +15937,7 @@ function inspectSiblingWorktreeDir(path2, worktreeGitRoot) {
15937
15937
  }
15938
15938
  function inspectDeadWorktreeDirContent(path2) {
15939
15939
  try {
15940
- return { entries: (0, import_node_fs15.readdirSync)(path2) };
15940
+ return { entries: (0, import_node_fs16.readdirSync)(path2) };
15941
15941
  } catch (e) {
15942
15942
  const code = typeof e === "object" && e && "code" in e ? String(e.code ?? "") : "";
15943
15943
  return { error: code ? `unable to inspect directory contents (${code})` : "unable to inspect directory contents" };
@@ -15956,8 +15956,8 @@ async function siblingWorktreeDirs() {
15956
15956
  const worktreeGitRoot = await currentRepoWorktreeGitRoot(repoRoot);
15957
15957
  const siblingRoot = siblingMmiWorktreesRoot(repoRoot);
15958
15958
  try {
15959
- const entries = (0, import_node_fs15.readdirSync)(siblingRoot, { withFileTypes: true });
15960
- return entries.filter((ent) => ent.isDirectory()).map((ent) => inspectSiblingWorktreeDir((0, import_node_path15.join)(siblingRoot, ent.name), worktreeGitRoot)).filter((entry) => Boolean(entry));
15959
+ const entries = (0, import_node_fs16.readdirSync)(siblingRoot, { withFileTypes: true });
15960
+ return entries.filter((ent) => ent.isDirectory()).map((ent) => inspectSiblingWorktreeDir((0, import_node_path16.join)(siblingRoot, ent.name), worktreeGitRoot)).filter((entry) => Boolean(entry));
15961
15961
  } catch {
15962
15962
  return [];
15963
15963
  }
@@ -16007,7 +16007,7 @@ async function fetchHubVersionInfo(baseUrl) {
16007
16007
  }
16008
16008
  function readRepoVersion() {
16009
16009
  try {
16010
- return JSON.parse((0, import_node_fs16.readFileSync)((0, import_node_path16.join)(process.cwd(), ".claude-plugin", "plugin.json"), "utf8")).version || void 0;
16010
+ return JSON.parse((0, import_node_fs17.readFileSync)((0, import_node_path17.join)(process.cwd(), ".claude-plugin", "plugin.json"), "utf8")).version || void 0;
16011
16011
  } catch {
16012
16012
  return void 0;
16013
16013
  }
@@ -16058,12 +16058,12 @@ function runHostBin(bin, args, opts) {
16058
16058
  return isWin ? execFileP2("cmd.exe", ["/c", bin, ...args], opts) : execFileP2(bin, args, opts);
16059
16059
  }
16060
16060
  function reexecMmiCli(args) {
16061
- return new Promise((resolve5) => {
16061
+ return new Promise((resolve6) => {
16062
16062
  let settled = false;
16063
16063
  const done = (code) => {
16064
16064
  if (!settled) {
16065
16065
  settled = true;
16066
- resolve5(code);
16066
+ resolve6(code);
16067
16067
  }
16068
16068
  };
16069
16069
  const env = { ...process.env, [DOCTOR_POST_SELF_UPDATE_ENV]: "1" };
@@ -16124,11 +16124,11 @@ async function applyPluginHeal(token, surface, log, opts) {
16124
16124
  }
16125
16125
  var installedPluginsPath = (surface = detectSurface(process.env)) => {
16126
16126
  const homeDir = surface === "codex" ? ".codex" : ".claude";
16127
- return (0, import_node_path16.join)((0, import_node_os5.homedir)(), homeDir, "plugins", "installed_plugins.json");
16127
+ return (0, import_node_path17.join)((0, import_node_os6.homedir)(), homeDir, "plugins", "installed_plugins.json");
16128
16128
  };
16129
16129
  function readInstalledPlugins(surface = detectSurface(process.env)) {
16130
16130
  try {
16131
- return JSON.parse((0, import_node_fs16.readFileSync)(installedPluginsPath(surface), "utf8"));
16131
+ return JSON.parse((0, import_node_fs17.readFileSync)(installedPluginsPath(surface), "utf8"));
16132
16132
  } catch {
16133
16133
  return null;
16134
16134
  }
@@ -16139,15 +16139,15 @@ function snapshotPluginGuardInput(surface = detectSurface(process.env), isOrgRep
16139
16139
  return {
16140
16140
  isOrgRepo,
16141
16141
  installRecordPresent: hasUserInstallRecord(installed, MMI_PLUGIN_ID) || hasProjectInstallRecord(installed, MMI_PLUGIN_ID, process.cwd()),
16142
- marketplaceClonePresent: (0, import_node_fs16.existsSync)((0, import_node_path16.join)((0, import_node_os5.homedir)(), homeDir, "plugins", "marketplaces", "mutmutco")),
16143
- pluginCachePresent: (0, import_node_fs16.existsSync)((0, import_node_path16.join)((0, import_node_os5.homedir)(), homeDir, "plugins", "cache", "mutmutco", "mmi"))
16142
+ marketplaceClonePresent: (0, import_node_fs17.existsSync)((0, import_node_path17.join)((0, import_node_os6.homedir)(), homeDir, "plugins", "marketplaces", "mutmutco")),
16143
+ pluginCachePresent: (0, import_node_fs17.existsSync)((0, import_node_path17.join)((0, import_node_os6.homedir)(), homeDir, "plugins", "cache", "mutmutco", "mmi"))
16144
16144
  };
16145
16145
  }
16146
16146
  function installedPluginSources() {
16147
16147
  return ["claude", "codex"].map((surface) => {
16148
- const recordPath = (0, import_node_path16.join)((0, import_node_os5.homedir)(), `.${surface}`, "plugins", "installed_plugins.json");
16148
+ const recordPath = (0, import_node_path17.join)((0, import_node_os6.homedir)(), `.${surface}`, "plugins", "installed_plugins.json");
16149
16149
  try {
16150
- return { surface, installed: JSON.parse((0, import_node_fs16.readFileSync)(recordPath, "utf8")), recordPath };
16150
+ return { surface, installed: JSON.parse((0, import_node_fs17.readFileSync)(recordPath, "utf8")), recordPath };
16151
16151
  } catch {
16152
16152
  return { surface, installed: null, recordPath };
16153
16153
  }
@@ -16155,7 +16155,7 @@ function installedPluginSources() {
16155
16155
  }
16156
16156
  function readClaudeSettings() {
16157
16157
  try {
16158
- return JSON.parse((0, import_node_fs16.readFileSync)((0, import_node_path16.join)(process.cwd(), ".claude", "settings.json"), "utf8"));
16158
+ return JSON.parse((0, import_node_fs17.readFileSync)((0, import_node_path17.join)(process.cwd(), ".claude", "settings.json"), "utf8"));
16159
16159
  } catch {
16160
16160
  return null;
16161
16161
  }
@@ -16177,7 +16177,7 @@ function writeProjectInstallRecord(record) {
16177
16177
  const list = file.plugins[MMI_PLUGIN_ID] ?? [];
16178
16178
  list.push(record);
16179
16179
  file.plugins[MMI_PLUGIN_ID] = list;
16180
- (0, import_node_fs16.writeFileSync)(installedPluginsPath(), `${JSON.stringify(file, null, 2)}
16180
+ (0, import_node_fs17.writeFileSync)(installedPluginsPath(), `${JSON.stringify(file, null, 2)}
16181
16181
  `, "utf8");
16182
16182
  return true;
16183
16183
  } catch {
@@ -16190,9 +16190,9 @@ function backupAndWriteInstalledPlugins(records, pluginId) {
16190
16190
  if (!file) return false;
16191
16191
  if (!file.plugins) file.plugins = {};
16192
16192
  const path2 = installedPluginsPath();
16193
- (0, import_node_fs16.copyFileSync)(path2, `${path2}.bak`);
16193
+ (0, import_node_fs17.copyFileSync)(path2, `${path2}.bak`);
16194
16194
  file.plugins[pluginId] = records;
16195
- (0, import_node_fs16.writeFileSync)(path2, `${JSON.stringify(file, null, 2)}
16195
+ (0, import_node_fs17.writeFileSync)(path2, `${JSON.stringify(file, null, 2)}
16196
16196
  `, "utf8");
16197
16197
  return true;
16198
16198
  } catch {
@@ -16200,22 +16200,22 @@ function backupAndWriteInstalledPlugins(records, pluginId) {
16200
16200
  }
16201
16201
  }
16202
16202
  function opencodeConfigDir() {
16203
- return (0, import_node_path16.join)((0, import_node_os5.homedir)(), ".config", "opencode");
16203
+ return (0, import_node_path17.join)((0, import_node_os6.homedir)(), ".config", "opencode");
16204
16204
  }
16205
16205
  function opencodeConfigPath() {
16206
- return (0, import_node_path16.join)(opencodeConfigDir(), "opencode.jsonc");
16206
+ return (0, import_node_path17.join)(opencodeConfigDir(), "opencode.jsonc");
16207
16207
  }
16208
16208
  function opencodeCommandsDir() {
16209
- return (0, import_node_path16.join)(opencodeConfigDir(), "commands");
16209
+ return (0, import_node_path17.join)(opencodeConfigDir(), "commands");
16210
16210
  }
16211
16211
  function opencodeSkillsPath() {
16212
- return (0, import_node_path16.join)(opencodeConfigDir(), "node_modules", "@mutmutco", "opencode-mmi", "skills");
16212
+ return (0, import_node_path17.join)(opencodeConfigDir(), "node_modules", "@mutmutco", "opencode-mmi", "skills");
16213
16213
  }
16214
16214
  function opencodeConfigSnapshot() {
16215
16215
  const path2 = opencodeConfigPath();
16216
- if (!(0, import_node_fs16.existsSync)(path2)) return { path: path2, hasConfig: false, hasPluginField: false, parseOk: true };
16216
+ if (!(0, import_node_fs17.existsSync)(path2)) return { path: path2, hasConfig: false, hasPluginField: false, parseOk: true };
16217
16217
  try {
16218
- const raw = (0, import_node_fs16.readFileSync)(path2, "utf8");
16218
+ const raw = (0, import_node_fs17.readFileSync)(path2, "utf8");
16219
16219
  const parsed = JSON.parse(stripJsonc(raw));
16220
16220
  const hasPluginField = Object.prototype.hasOwnProperty.call(parsed, "plugin");
16221
16221
  const skillsPaths = Array.isArray(parsed.skills?.paths) ? parsed.skills.paths.filter((p) => typeof p === "string") : void 0;
@@ -16238,9 +16238,9 @@ function writeOpencodeConfigPlugin(snapshot) {
16238
16238
  const plan = planOpencodeConfigWrite(snapshot.hasConfig ? snapshot.raw : void 0);
16239
16239
  if (plan.action === "already") return true;
16240
16240
  if (!plan.text || plan.action === "unsafe") return false;
16241
- (0, import_node_fs16.mkdirSync)((0, import_node_path16.dirname)(path2), { recursive: true });
16242
- if (snapshot.hasConfig) (0, import_node_fs16.copyFileSync)(path2, `${path2}.bak`);
16243
- (0, import_node_fs16.writeFileSync)(path2, plan.text, "utf8");
16241
+ (0, import_node_fs17.mkdirSync)((0, import_node_path17.dirname)(path2), { recursive: true });
16242
+ if (snapshot.hasConfig) (0, import_node_fs17.copyFileSync)(path2, `${path2}.bak`);
16243
+ (0, import_node_fs17.writeFileSync)(path2, plan.text, "utf8");
16244
16244
  return true;
16245
16245
  } catch {
16246
16246
  return false;
@@ -16255,9 +16255,9 @@ function writeOpencodeSkillsPath(snapshot, skillsPath) {
16255
16255
  const normalized = skillsPath.replace(/\\/g, "/");
16256
16256
  if (!paths.some((p) => p.replace(/\\/g, "/") === normalized)) paths.push(skillsPath.replace(/\\/g, "/"));
16257
16257
  parsed.skills = { ...skills, paths };
16258
- (0, import_node_fs16.mkdirSync)((0, import_node_path16.dirname)(snapshot.path), { recursive: true });
16259
- if (snapshot.hasConfig && (0, import_node_fs16.existsSync)(snapshot.path)) (0, import_node_fs16.copyFileSync)(snapshot.path, `${snapshot.path}.bak`);
16260
- (0, import_node_fs16.writeFileSync)(snapshot.path, `${JSON.stringify(parsed, null, 2)}
16258
+ (0, import_node_fs17.mkdirSync)((0, import_node_path17.dirname)(snapshot.path), { recursive: true });
16259
+ if (snapshot.hasConfig && (0, import_node_fs17.existsSync)(snapshot.path)) (0, import_node_fs17.copyFileSync)(snapshot.path, `${snapshot.path}.bak`);
16260
+ (0, import_node_fs17.writeFileSync)(snapshot.path, `${JSON.stringify(parsed, null, 2)}
16261
16261
  `, "utf8");
16262
16262
  return true;
16263
16263
  } catch {
@@ -16266,7 +16266,7 @@ function writeOpencodeSkillsPath(snapshot, skillsPath) {
16266
16266
  }
16267
16267
  function opencodeExistingCommands() {
16268
16268
  try {
16269
- return (0, import_node_fs16.readdirSync)(opencodeCommandsDir(), { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".md")).map((entry) => entry.name.slice(0, -3).toLowerCase());
16269
+ return (0, import_node_fs17.readdirSync)(opencodeCommandsDir(), { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".md")).map((entry) => entry.name.slice(0, -3).toLowerCase());
16270
16270
  } catch {
16271
16271
  return [];
16272
16272
  }
@@ -16274,9 +16274,9 @@ function opencodeExistingCommands() {
16274
16274
  function writeOpencodeCommandFiles() {
16275
16275
  try {
16276
16276
  const dir = opencodeCommandsDir();
16277
- (0, import_node_fs16.mkdirSync)(dir, { recursive: true });
16277
+ (0, import_node_fs17.mkdirSync)(dir, { recursive: true });
16278
16278
  for (const command of OPENCODE_WORKFLOW_COMMANDS) {
16279
- (0, import_node_fs16.writeFileSync)((0, import_node_path16.join)(dir, `${command}.md`), opencodeCommandMarkdown(command), "utf8");
16279
+ (0, import_node_fs17.writeFileSync)((0, import_node_path17.join)(dir, `${command}.md`), opencodeCommandMarkdown(command), "utf8");
16280
16280
  }
16281
16281
  return true;
16282
16282
  } catch {
@@ -16285,12 +16285,12 @@ function writeOpencodeCommandFiles() {
16285
16285
  }
16286
16286
  function readOpencodeAdapterDiskVersion() {
16287
16287
  const candidates = [
16288
- (0, import_node_path16.join)(opencodeConfigDir(), "node_modules", "@mutmutco", "opencode-mmi", "package.json"),
16289
- (0, import_node_path16.join)((0, import_node_os5.homedir)(), ".cache", "opencode", "node_modules", "@mutmutco", "opencode-mmi", "package.json")
16288
+ (0, import_node_path17.join)(opencodeConfigDir(), "node_modules", "@mutmutco", "opencode-mmi", "package.json"),
16289
+ (0, import_node_path17.join)((0, import_node_os6.homedir)(), ".cache", "opencode", "node_modules", "@mutmutco", "opencode-mmi", "package.json")
16290
16290
  ];
16291
16291
  for (const path2 of candidates) {
16292
16292
  try {
16293
- const parsed = JSON.parse((0, import_node_fs16.readFileSync)(path2, "utf8"));
16293
+ const parsed = JSON.parse((0, import_node_fs17.readFileSync)(path2, "utf8"));
16294
16294
  if (typeof parsed.version === "string" && parsed.version.trim()) return parsed.version.trim();
16295
16295
  } catch {
16296
16296
  continue;
@@ -16306,7 +16306,7 @@ async function forceInstallOpencodeMmiPlugins(snapshot, log) {
16306
16306
  try {
16307
16307
  const specs = opencodeMmiPluginSpecs(snapshot);
16308
16308
  log(` \u21BB force-refreshing OpenCode MMI npm plugin(s): ${specs.join(", ")}\u2026`);
16309
- (0, import_node_fs16.mkdirSync)(opencodeConfigDir(), { recursive: true });
16309
+ (0, import_node_fs17.mkdirSync)(opencodeConfigDir(), { recursive: true });
16310
16310
  await runHostBin("npm", ["install", "--prefix", opencodeConfigDir(), "--force", ...specs], { timeout: NPM_UPDATE_TIMEOUT_MS });
16311
16311
  return true;
16312
16312
  } catch {
@@ -16321,30 +16321,30 @@ function opencodePluginVersionsForReport() {
16321
16321
  }
16322
16322
  function opencodeDesktopLogsRoot() {
16323
16323
  if (process.platform === "win32") {
16324
- const base = process.env.APPDATA || (0, import_node_path16.join)((0, import_node_os5.homedir)(), "AppData", "Roaming");
16325
- return (0, import_node_path16.join)(base, "ai.opencode.desktop", "logs");
16324
+ const base = process.env.APPDATA || (0, import_node_path17.join)((0, import_node_os6.homedir)(), "AppData", "Roaming");
16325
+ return (0, import_node_path17.join)(base, "ai.opencode.desktop", "logs");
16326
16326
  }
16327
16327
  if (process.platform === "darwin") {
16328
- return (0, import_node_path16.join)((0, import_node_os5.homedir)(), "Library", "Application Support", "ai.opencode.desktop", "logs");
16328
+ return (0, import_node_path17.join)((0, import_node_os6.homedir)(), "Library", "Application Support", "ai.opencode.desktop", "logs");
16329
16329
  }
16330
- return (0, import_node_path16.join)((0, import_node_os5.homedir)(), ".config", "ai.opencode.desktop", "logs");
16330
+ return (0, import_node_path17.join)((0, import_node_os6.homedir)(), ".config", "ai.opencode.desktop", "logs");
16331
16331
  }
16332
16332
  function opencodeDesktopBootstrapSnapshot() {
16333
16333
  const root = opencodeDesktopLogsRoot();
16334
16334
  try {
16335
- const sessionDirs = (0, import_node_fs16.readdirSync)(root, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => (0, import_node_path16.join)(root, entry.name)).sort((a, b) => (0, import_node_fs16.statSync)(b).mtimeMs - (0, import_node_fs16.statSync)(a).mtimeMs);
16335
+ const sessionDirs = (0, import_node_fs17.readdirSync)(root, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => (0, import_node_path17.join)(root, entry.name)).sort((a, b) => (0, import_node_fs17.statSync)(b).mtimeMs - (0, import_node_fs17.statSync)(a).mtimeMs);
16336
16336
  const newest = sessionDirs[0];
16337
16337
  if (!newest) return [];
16338
- const logPath = (0, import_node_path16.join)(newest, "renderer.log");
16339
- const text = (0, import_node_fs16.readFileSync)(logPath, "utf8");
16340
- return opencodeAgentDirectoriesFromLog(text).filter((directory) => !(0, import_node_fs16.existsSync)(directory)).map((directory) => ({ directory, logPath }));
16338
+ const logPath = (0, import_node_path17.join)(newest, "renderer.log");
16339
+ const text = (0, import_node_fs17.readFileSync)(logPath, "utf8");
16340
+ return opencodeAgentDirectoriesFromLog(text).filter((directory) => !(0, import_node_fs17.existsSync)(directory)).map((directory) => ({ directory, logPath }));
16341
16341
  } catch {
16342
16342
  return [];
16343
16343
  }
16344
16344
  }
16345
16345
  function opencodeLegacyConfigSnapshot() {
16346
- const legacyPath = (0, import_node_path16.join)((0, import_node_os5.homedir)(), ".opencode", "opencode.json");
16347
- if (!(0, import_node_fs16.existsSync)(legacyPath)) return {};
16346
+ const legacyPath = (0, import_node_path17.join)((0, import_node_os6.homedir)(), ".opencode", "opencode.json");
16347
+ if (!(0, import_node_fs17.existsSync)(legacyPath)) return {};
16348
16348
  const content = readTextFile(legacyPath);
16349
16349
  if (content == null) return {};
16350
16350
  const plugins = parseOpencodeLegacyConfigPlugins(content);
@@ -16356,45 +16356,45 @@ function opencodeLegacyConfigSnapshot() {
16356
16356
  function quarantineOpencodeLegacyConfig(legacyPath) {
16357
16357
  try {
16358
16358
  const backupPath = `${legacyPath}.bak`;
16359
- if ((0, import_node_fs16.existsSync)(backupPath)) return false;
16360
- (0, import_node_fs16.renameSync)(legacyPath, backupPath);
16359
+ if ((0, import_node_fs17.existsSync)(backupPath)) return false;
16360
+ (0, import_node_fs17.renameSync)(legacyPath, backupPath);
16361
16361
  return true;
16362
16362
  } catch {
16363
16363
  return false;
16364
16364
  }
16365
16365
  }
16366
16366
  function cursorPluginCacheRoot() {
16367
- return (0, import_node_path16.join)((0, import_node_os5.homedir)(), ".cursor", "plugins", "cache", "mutmutco", "mmi");
16367
+ return (0, import_node_path17.join)((0, import_node_os6.homedir)(), ".cursor", "plugins", "cache", "mutmutco", "mmi");
16368
16368
  }
16369
16369
  function cursorPluginCachePinSnapshots() {
16370
16370
  const root = cursorPluginCacheRoot();
16371
16371
  try {
16372
- return (0, import_node_fs16.readdirSync)(root, { withFileTypes: true }).filter((entry) => entry.isDirectory() && !entry.name.startsWith(".")).map((entry) => {
16373
- const path2 = (0, import_node_path16.join)(root, entry.name);
16374
- const pluginJson = (0, import_node_path16.join)(path2, ".cursor-plugin", "plugin.json");
16375
- const hooksJson = (0, import_node_path16.join)(path2, "hooks", "hooks.json");
16376
- const cliBundle = (0, import_node_path16.join)(path2, "cli", "dist", "index.cjs");
16377
- const cursorHook = (0, import_node_path16.join)(path2, "scripts", "cursor-hook.mjs");
16372
+ return (0, import_node_fs17.readdirSync)(root, { withFileTypes: true }).filter((entry) => entry.isDirectory() && !entry.name.startsWith(".")).map((entry) => {
16373
+ const path2 = (0, import_node_path17.join)(root, entry.name);
16374
+ const pluginJson = (0, import_node_path17.join)(path2, ".cursor-plugin", "plugin.json");
16375
+ const hooksJson = (0, import_node_path17.join)(path2, "hooks", "hooks.json");
16376
+ const cliBundle = (0, import_node_path17.join)(path2, "cli", "dist", "index.cjs");
16377
+ const cursorHook = (0, import_node_path17.join)(path2, "scripts", "cursor-hook.mjs");
16378
16378
  let version;
16379
16379
  try {
16380
- const raw = JSON.parse((0, import_node_fs16.readFileSync)(pluginJson, "utf8"));
16380
+ const raw = JSON.parse((0, import_node_fs17.readFileSync)(pluginJson, "utf8"));
16381
16381
  version = typeof raw.version === "string" ? raw.version : void 0;
16382
16382
  } catch {
16383
16383
  version = void 0;
16384
16384
  }
16385
16385
  let isEmpty = true;
16386
16386
  try {
16387
- isEmpty = (0, import_node_fs16.readdirSync)(path2).length === 0;
16387
+ isEmpty = (0, import_node_fs17.readdirSync)(path2).length === 0;
16388
16388
  } catch {
16389
16389
  isEmpty = true;
16390
16390
  }
16391
16391
  return {
16392
16392
  name: entry.name,
16393
16393
  path: path2,
16394
- hasPluginJson: (0, import_node_fs16.existsSync)(pluginJson),
16395
- hasHooksJson: (0, import_node_fs16.existsSync)(hooksJson),
16396
- hasCliBundle: (0, import_node_fs16.existsSync)(cliBundle),
16397
- hasCursorHookScript: (0, import_node_fs16.existsSync)(cursorHook),
16394
+ hasPluginJson: (0, import_node_fs17.existsSync)(pluginJson),
16395
+ hasHooksJson: (0, import_node_fs17.existsSync)(hooksJson),
16396
+ hasCliBundle: (0, import_node_fs17.existsSync)(cliBundle),
16397
+ hasCursorHookScript: (0, import_node_fs17.existsSync)(cursorHook),
16398
16398
  isEmpty,
16399
16399
  version
16400
16400
  };
@@ -16404,19 +16404,19 @@ function cursorPluginCachePinSnapshots() {
16404
16404
  }
16405
16405
  }
16406
16406
  function hubCheckoutForCursorSeed() {
16407
- const manifest = (0, import_node_path16.join)(process.cwd(), "plugins", "mmi", ".cursor-plugin", "plugin.json");
16408
- return (0, import_node_fs16.existsSync)(manifest) ? process.cwd() : void 0;
16407
+ const manifest = (0, import_node_path17.join)(process.cwd(), "plugins", "mmi", ".cursor-plugin", "plugin.json");
16408
+ return (0, import_node_fs17.existsSync)(manifest) ? process.cwd() : void 0;
16409
16409
  }
16410
16410
  function mmiPluginCacheRootSnapshots() {
16411
16411
  const roots = [
16412
- { surface: "claude", root: (0, import_node_path16.join)((0, import_node_os5.homedir)(), ".claude", "plugins", "cache", "mutmutco", "mmi") },
16413
- { surface: "codex", root: (0, import_node_path16.join)((0, import_node_os5.homedir)(), ".codex", "plugins", "cache", "mutmutco", "mmi") }
16412
+ { surface: "claude", root: (0, import_node_path17.join)((0, import_node_os6.homedir)(), ".claude", "plugins", "cache", "mutmutco", "mmi") },
16413
+ { surface: "codex", root: (0, import_node_path17.join)((0, import_node_os6.homedir)(), ".codex", "plugins", "cache", "mutmutco", "mmi") }
16414
16414
  ];
16415
16415
  return roots.flatMap(({ surface, root }) => {
16416
16416
  try {
16417
- const entries = (0, import_node_fs16.readdirSync)(root, { withFileTypes: true }).map((entry) => ({
16417
+ const entries = (0, import_node_fs17.readdirSync)(root, { withFileTypes: true }).map((entry) => ({
16418
16418
  name: entry.name,
16419
- path: (0, import_node_path16.join)(root, entry.name),
16419
+ path: (0, import_node_path17.join)(root, entry.name),
16420
16420
  isDirectory: entry.isDirectory()
16421
16421
  }));
16422
16422
  return [{ surface, root, entries }];
@@ -16427,7 +16427,7 @@ function mmiPluginCacheRootSnapshots() {
16427
16427
  }
16428
16428
  function hasNestedMmiChild(versionDir) {
16429
16429
  try {
16430
- return (0, import_node_fs16.statSync)((0, import_node_path16.join)(versionDir, "mmi")).isDirectory();
16430
+ return (0, import_node_fs17.statSync)((0, import_node_path17.join)(versionDir, "mmi")).isDirectory();
16431
16431
  } catch {
16432
16432
  return false;
16433
16433
  }
@@ -16438,10 +16438,10 @@ function nestedPluginTreeSnapshot() {
16438
16438
  );
16439
16439
  }
16440
16440
  function uniqueQuarantineTarget(path2) {
16441
- if (!(0, import_node_fs16.existsSync)(path2)) return path2;
16441
+ if (!(0, import_node_fs17.existsSync)(path2)) return path2;
16442
16442
  for (let i = 1; i < 100; i += 1) {
16443
16443
  const candidate = `${path2}-${i}`;
16444
- if (!(0, import_node_fs16.existsSync)(candidate)) return candidate;
16444
+ if (!(0, import_node_fs17.existsSync)(candidate)) return candidate;
16445
16445
  }
16446
16446
  return `${path2}-${Date.now()}`;
16447
16447
  }
@@ -16450,10 +16450,10 @@ function quarantinePluginCacheDirs(plan) {
16450
16450
  const failed = [];
16451
16451
  for (const move of plan) {
16452
16452
  try {
16453
- if (!(0, import_node_fs16.existsSync)(move.from)) continue;
16453
+ if (!(0, import_node_fs17.existsSync)(move.from)) continue;
16454
16454
  const target = uniqueQuarantineTarget(move.to);
16455
- (0, import_node_fs16.mkdirSync)((0, import_node_path16.dirname)(target), { recursive: true });
16456
- (0, import_node_fs16.renameSync)(move.from, target);
16455
+ (0, import_node_fs17.mkdirSync)((0, import_node_path17.dirname)(target), { recursive: true });
16456
+ (0, import_node_fs17.renameSync)(move.from, target);
16457
16457
  moved += 1;
16458
16458
  } catch {
16459
16459
  failed.push(move);
@@ -16472,23 +16472,23 @@ async function robocopyMirrorEmpty(emptyDir, target) {
16472
16472
  }
16473
16473
  async function clearNestedPluginTreeDir(targetPath) {
16474
16474
  try {
16475
- if (!(0, import_node_fs16.existsSync)(targetPath)) return true;
16475
+ if (!(0, import_node_fs17.existsSync)(targetPath)) return true;
16476
16476
  if (isWin) {
16477
- const emptyDir = (0, import_node_path16.join)((0, import_node_os5.tmpdir)(), `mmi-empty-${Date.now()}`);
16478
- (0, import_node_fs16.mkdirSync)(emptyDir, { recursive: true });
16477
+ const emptyDir = (0, import_node_path17.join)((0, import_node_os6.tmpdir)(), `mmi-empty-${Date.now()}`);
16478
+ (0, import_node_fs17.mkdirSync)(emptyDir, { recursive: true });
16479
16479
  try {
16480
16480
  await robocopyMirrorEmpty(emptyDir, targetPath);
16481
- (0, import_node_fs16.rmSync)(targetPath, { recursive: true, force: true });
16481
+ (0, import_node_fs17.rmSync)(targetPath, { recursive: true, force: true });
16482
16482
  } finally {
16483
16483
  try {
16484
- (0, import_node_fs16.rmSync)(emptyDir, { recursive: true, force: true });
16484
+ (0, import_node_fs17.rmSync)(emptyDir, { recursive: true, force: true });
16485
16485
  } catch {
16486
16486
  }
16487
16487
  }
16488
- return !(0, import_node_fs16.existsSync)(targetPath);
16488
+ return !(0, import_node_fs17.existsSync)(targetPath);
16489
16489
  }
16490
- (0, import_node_fs16.rmSync)(targetPath, { recursive: true, force: true });
16491
- return !(0, import_node_fs16.existsSync)(targetPath);
16490
+ (0, import_node_fs17.rmSync)(targetPath, { recursive: true, force: true });
16491
+ return !(0, import_node_fs17.existsSync)(targetPath);
16492
16492
  } catch {
16493
16493
  return false;
16494
16494
  }
@@ -16501,23 +16501,23 @@ async function applyNestedPluginTreeCleanup(paths, log) {
16501
16501
  }
16502
16502
  return true;
16503
16503
  }
16504
- var gitignorePath = () => (0, import_node_path16.join)(process.cwd(), ".gitignore");
16504
+ var gitignorePath = () => (0, import_node_path17.join)(process.cwd(), ".gitignore");
16505
16505
  function readTextFile(path2) {
16506
16506
  try {
16507
- if (!(0, import_node_fs16.existsSync)(path2)) return null;
16508
- return (0, import_node_fs16.readFileSync)(path2, "utf8");
16507
+ if (!(0, import_node_fs17.existsSync)(path2)) return null;
16508
+ return (0, import_node_fs17.readFileSync)(path2, "utf8");
16509
16509
  } catch {
16510
16510
  return null;
16511
16511
  }
16512
16512
  }
16513
16513
  function playwrightMcpConfigSnapshots() {
16514
16514
  const cwd = process.cwd();
16515
- const home = (0, import_node_os5.homedir)();
16515
+ const home = (0, import_node_os6.homedir)();
16516
16516
  const candidates = [
16517
- (0, import_node_path16.join)(cwd, ".mcp.json"),
16518
- (0, import_node_path16.join)(cwd, ".cursor", "mcp.json"),
16519
- (0, import_node_path16.join)(home, ".cursor", "mcp.json"),
16520
- (0, import_node_path16.join)(home, ".codex", "config.toml")
16517
+ (0, import_node_path17.join)(cwd, ".mcp.json"),
16518
+ (0, import_node_path17.join)(cwd, ".cursor", "mcp.json"),
16519
+ (0, import_node_path17.join)(home, ".cursor", "mcp.json"),
16520
+ (0, import_node_path17.join)(home, ".codex", "config.toml")
16521
16521
  ];
16522
16522
  const out = [];
16523
16523
  for (const path2 of candidates) {
@@ -16530,7 +16530,7 @@ function strayBrowserArtifactPaths() {
16530
16530
  const cwd = process.cwd();
16531
16531
  return STRAY_BROWSER_ARTIFACT_DIRS.filter((rel) => {
16532
16532
  try {
16533
- return (0, import_node_fs16.existsSync)((0, import_node_path16.join)(cwd, rel));
16533
+ return (0, import_node_fs17.existsSync)((0, import_node_path17.join)(cwd, rel));
16534
16534
  } catch {
16535
16535
  return false;
16536
16536
  }
@@ -16538,14 +16538,14 @@ function strayBrowserArtifactPaths() {
16538
16538
  }
16539
16539
  function readGitignore() {
16540
16540
  try {
16541
- return (0, import_node_fs16.readFileSync)(gitignorePath(), "utf8");
16541
+ return (0, import_node_fs17.readFileSync)(gitignorePath(), "utf8");
16542
16542
  } catch {
16543
16543
  return null;
16544
16544
  }
16545
16545
  }
16546
16546
  function writeGitignore(content) {
16547
16547
  try {
16548
- (0, import_node_fs16.writeFileSync)(gitignorePath(), content, "utf8");
16548
+ (0, import_node_fs17.writeFileSync)(gitignorePath(), content, "utf8");
16549
16549
  return true;
16550
16550
  } catch {
16551
16551
  return false;
@@ -16587,7 +16587,7 @@ async function runDoctor(opts, io = consoleIo, readOrigin) {
16587
16587
  const semverPrefix = /^\d+\.\d+\.\d+/;
16588
16588
  const isBehind = (installed2, released) => Boolean(installed2 && released && semverPrefix.test(installed2) && semverPrefix.test(released) && compareVersions(installed2, released) < 0);
16589
16589
  const opencodeAdapterStale = isBehind(opencodeInstalledVersionForDoctor(), releasedVersion);
16590
- const cursorCacheStale = (0, import_node_fs16.existsSync)(cursorPluginCacheRoot()) && (cursorPluginCachePinSnapshots() ?? []).some((p) => isBehind(p.version, releasedVersion));
16590
+ const cursorCacheStale = (0, import_node_fs17.existsSync)(cursorPluginCacheRoot()) && (cursorPluginCachePinSnapshots() ?? []).some((p) => isBehind(p.version, releasedVersion));
16591
16591
  const healPlan = doctorHealPlan({
16592
16592
  isOrgRepo,
16593
16593
  surface,
@@ -16622,7 +16622,7 @@ async function runDoctor(opts, io = consoleIo, readOrigin) {
16622
16622
  let onPath = pathProbe;
16623
16623
  if (!onPath) {
16624
16624
  const root = process.env.CLAUDE_PLUGIN_ROOT;
16625
- if (root && (0, import_node_fs16.existsSync)(`${root}/bin/mmi-cli${isWin ? ".cmd" : ""}`)) onPath = true;
16625
+ if (root && (0, import_node_fs17.existsSync)(`${root}/bin/mmi-cli${isWin ? ".cmd" : ""}`)) onPath = true;
16626
16626
  }
16627
16627
  checks.push({ ok: onPath, label: "mmi-cli on PATH", fix: "auto-provisioned at session start \u2014 reopen the session, or install the MMI plugin" });
16628
16628
  const reloadHint = reloadAction(surface);
@@ -16991,7 +16991,7 @@ async function runDoctor(opts, io = consoleIo, readOrigin) {
16991
16991
  isOrgRepo,
16992
16992
  surface,
16993
16993
  cacheRoot: cursorCacheRoot,
16994
- cacheRootExists: (0, import_node_fs16.existsSync)(cursorCacheRoot),
16994
+ cacheRootExists: (0, import_node_fs17.existsSync)(cursorCacheRoot),
16995
16995
  pins: cursorPins,
16996
16996
  hubCheckout: hubCheckoutForCursorSeed(),
16997
16997
  releasedVersion
@@ -17002,7 +17002,7 @@ async function runDoctor(opts, io = consoleIo, readOrigin) {
17002
17002
  releasedVersion,
17003
17003
  hubCheckout: hubCheckoutForCursorSeed(),
17004
17004
  execFileP: execFileP2,
17005
- mkdtemp: (prefix) => (0, import_promises3.mkdtemp)((0, import_node_path16.join)((0, import_node_os5.tmpdir)(), prefix)),
17005
+ mkdtemp: (prefix) => (0, import_promises3.mkdtemp)((0, import_node_path17.join)((0, import_node_os6.tmpdir)(), prefix)),
17006
17006
  log: (m) => io.err(m)
17007
17007
  });
17008
17008
  if (seeded) {
@@ -17011,7 +17011,7 @@ async function runDoctor(opts, io = consoleIo, readOrigin) {
17011
17011
  isOrgRepo,
17012
17012
  surface,
17013
17013
  cacheRoot: cursorCacheRoot,
17014
- cacheRootExists: (0, import_node_fs16.existsSync)(cursorCacheRoot),
17014
+ cacheRootExists: (0, import_node_fs17.existsSync)(cursorCacheRoot),
17015
17015
  pins: cursorPins,
17016
17016
  hubCheckout: hubCheckoutForCursorSeed(),
17017
17017
  releasedVersion
@@ -17150,23 +17150,23 @@ function mergeGuardHook(settings) {
17150
17150
  next.hooks = hooks;
17151
17151
  return next;
17152
17152
  }
17153
- var userScopeSettingsPath = (surface = detectSurface(process.env)) => (0, import_node_path16.join)((0, import_node_os5.homedir)(), surface === "codex" ? ".codex" : ".claude", "settings.json");
17153
+ var userScopeSettingsPath = (surface = detectSurface(process.env)) => (0, import_node_path17.join)((0, import_node_os6.homedir)(), surface === "codex" ? ".codex" : ".claude", "settings.json");
17154
17154
  function ensureUserScopeGuardHook(opts = {}) {
17155
17155
  const path2 = opts.settingsPath ?? userScopeSettingsPath();
17156
17156
  try {
17157
17157
  let current = null;
17158
- if ((0, import_node_fs16.existsSync)(path2)) {
17158
+ if ((0, import_node_fs17.existsSync)(path2)) {
17159
17159
  try {
17160
- current = JSON.parse((0, import_node_fs16.readFileSync)(path2, "utf8"));
17160
+ current = JSON.parse((0, import_node_fs17.readFileSync)(path2, "utf8"));
17161
17161
  } catch {
17162
17162
  return "failed";
17163
17163
  }
17164
17164
  }
17165
17165
  if (settingsHasGuardHook(current)) return "already";
17166
17166
  const merged = mergeGuardHook(current);
17167
- (0, import_node_fs16.mkdirSync)((0, import_node_path16.dirname)(path2), { recursive: true });
17168
- if ((0, import_node_fs16.existsSync)(path2)) (0, import_node_fs16.copyFileSync)(path2, `${path2}.bak`);
17169
- (0, import_node_fs16.writeFileSync)(path2, `${JSON.stringify(merged, null, 2)}
17167
+ (0, import_node_fs17.mkdirSync)((0, import_node_path17.dirname)(path2), { recursive: true });
17168
+ if ((0, import_node_fs17.existsSync)(path2)) (0, import_node_fs17.copyFileSync)(path2, `${path2}.bak`);
17169
+ (0, import_node_fs17.writeFileSync)(path2, `${JSON.stringify(merged, null, 2)}
17170
17170
  `, "utf8");
17171
17171
  return "written";
17172
17172
  } catch {
@@ -17301,7 +17301,7 @@ async function applyGcPlan(plan, remote) {
17301
17301
  cleanupBranch: (branch, expectedHeadOid) => cleanupPrMergeLocalBranch(branch.branch, {
17302
17302
  beforeWorktrees,
17303
17303
  startingPath: branch.worktreePath,
17304
- pathExists: (p) => (0, import_node_fs17.existsSync)(p),
17304
+ pathExists: (p) => (0, import_node_fs18.existsSync)(p),
17305
17305
  execGit: async (args) => (await execFileP2("git", args, { timeout: GIT_TIMEOUT_MS })).stdout,
17306
17306
  teardownWorktreeStage,
17307
17307
  deferredStore,
@@ -17324,7 +17324,7 @@ async function applyGcPlan(plan, remote) {
17324
17324
  for (const wt of plan.worktreeDirs) {
17325
17325
  try {
17326
17326
  const cleanupTarget = resolveSafeSiblingWorktreeCleanupTarget(wt.path, siblingRoot, {
17327
- realpath: (path2) => (0, import_node_fs17.realpathSync)(path2)
17327
+ realpath: (path2) => (0, import_node_fs18.realpathSync)(path2)
17328
17328
  });
17329
17329
  if (!cleanupTarget.ok) {
17330
17330
  result.failed.push(`${wt.path}: ${cleanupTarget.reason}`);
@@ -17404,10 +17404,10 @@ async function runRulesSync(opts, io = consoleIo) {
17404
17404
  for (const entry of fetched) {
17405
17405
  if ("error" in entry) continue;
17406
17406
  const { file, source } = entry;
17407
- const current = (0, import_node_fs17.existsSync)(file) ? await (0, import_promises4.readFile)(file, "utf8") : null;
17407
+ const current = (0, import_node_fs18.existsSync)(file) ? await (0, import_promises4.readFile)(file, "utf8") : null;
17408
17408
  if (needsUpdate(source, current)) {
17409
17409
  const slash = file.lastIndexOf("/");
17410
- if (slash > 0) (0, import_node_fs17.mkdirSync)(file.slice(0, slash), { recursive: true });
17410
+ if (slash > 0) (0, import_node_fs18.mkdirSync)(file.slice(0, slash), { recursive: true });
17411
17411
  await (0, import_promises4.writeFile)(file, normalizeEol(source), "utf8");
17412
17412
  changed++;
17413
17413
  if (!opts.quiet) io.log(`mmi-cli rules: updated ${file}`);
@@ -17421,13 +17421,13 @@ rules.command("sync").option("--quiet", "stay silent unless something changed or
17421
17421
  if (!await runRulesSync(opts)) process.exitCode = 1;
17422
17422
  });
17423
17423
  rules.command("gitignore").option("--write", "upsert the managed block into .gitignore (default: check only, non-zero exit on drift)").description("verify (or --write) this repo's org-managed .gitignore block matches the SSOT").action((opts) => {
17424
- const path2 = (0, import_node_path17.join)(process.cwd(), ".gitignore");
17425
- const current = (0, import_node_fs17.existsSync)(path2) ? (0, import_node_fs17.readFileSync)(path2, "utf8") : null;
17424
+ const path2 = (0, import_node_path18.join)(process.cwd(), ".gitignore");
17425
+ const current = (0, import_node_fs18.existsSync)(path2) ? (0, import_node_fs18.readFileSync)(path2, "utf8") : null;
17426
17426
  const plan = planManagedGitignore(current);
17427
17427
  const drift = [...plan.added.map((l) => `+${l}`), ...plan.removed.map((l) => `-${l}`)].join(", ") || "block normalize";
17428
17428
  if (opts.write) {
17429
17429
  if (plan.changed) {
17430
- (0, import_node_fs17.writeFileSync)(path2, plan.content, "utf8");
17430
+ (0, import_node_fs18.writeFileSync)(path2, plan.content, "utf8");
17431
17431
  console.log(`mmi-cli rules gitignore: updated .gitignore (${drift})`);
17432
17432
  } else {
17433
17433
  console.log("mmi-cli rules gitignore: up to date");
@@ -17454,7 +17454,7 @@ async function runDocsSync(opts, io = consoleIo) {
17454
17454
  return null;
17455
17455
  }
17456
17456
  },
17457
- localContent: async (f) => (0, import_node_fs17.existsSync)(f) ? await (0, import_promises4.readFile)(f, "utf8") : null,
17457
+ localContent: async (f) => (0, import_node_fs18.existsSync)(f) ? await (0, import_promises4.readFile)(f, "utf8") : null,
17458
17458
  writeDoc: async (f, c) => {
17459
17459
  await (0, import_promises4.writeFile)(f, c, "utf8");
17460
17460
  }
@@ -17464,7 +17464,7 @@ async function runDocsSync(opts, io = consoleIo) {
17464
17464
  if (!opts.quiet && result.updated.length === 0 && result.skippedDirty.length === 0) io.log("mmi-cli docs: up to date");
17465
17465
  }
17466
17466
  var docs = program2.command("docs").description("repo-owned authoritative docs");
17467
- docs.command("sync").option("--quiet", "stay silent unless something changed or errored").description("refresh README.md / architecture.md from the repo default branch (keeper-authored); never clobbers uncommitted edits").action((opts) => runDocsSync(opts));
17467
+ docs.command("sync").option("--quiet", "stay silent unless something changed or errored").description("refresh README.md / architecture.md from the repo default branch; never clobbers uncommitted edits").action((opts) => runDocsSync(opts));
17468
17468
  program2.command("commands").description("print the command manifest \u2014 every subcommand + its flags (ground against this instead of guessing)").option("--json", "machine-readable JSON: { name, version, tree, index } \u2014 index is a flat list of every leaf command path").action((o) => {
17469
17469
  const manifest = buildCommandManifest(program2);
17470
17470
  consoleIo.log(o.json ? JSON.stringify(manifest, null, 2) : formatManifestHuman(manifest));
@@ -17482,21 +17482,13 @@ program2.command("whoami").description('resolve the logged-in human: {login, sou
17482
17482
  await runWhoami();
17483
17483
  });
17484
17484
  var wave = program2.command("wave").description("multi-worktree visibility and serial merge train");
17485
- wave.command("status").description("worktrees, open PRs, local stages, and saga compass at a glance (#1927)").option("--json", "machine-readable output").action(async (o) => {
17485
+ wave.command("status").description("worktrees, open PRs, and local stages at a glance (#1927)").option("--json", "machine-readable output").action(async (o) => {
17486
17486
  try {
17487
- const cfg = await loadConfig();
17488
- const project2 = cfg.project || (await gitOut(["remote", "get-url", "origin"])).replace(/\.git$/, "").split("/").pop() || "-";
17489
17487
  const rows = await collectWaveStatus({
17490
17488
  execGit: async (args) => (await execFileP2("git", args, { timeout: GIT_TIMEOUT_MS })).stdout,
17491
17489
  listOpenPrs: async () => {
17492
17490
  const { stdout } = await execFileP2("gh", ["pr", "list", "--state", "open", "--limit", "100", "--json", "number,headRefName,state,url"], { timeout: GC_GH_TIMEOUT_MS2 });
17493
17491
  return JSON.parse(stdout || "[]");
17494
- },
17495
- fetchSagaHeadText: async (branch) => {
17496
- if (!cfg.sagaApiUrl) return void 0;
17497
- const qs = new URLSearchParams({ project: project2, branch }).toString();
17498
- const res = await fetchWithRetry(fetch, `${cfg.sagaApiUrl}/saga/head?${qs}`, { headers: await hubHeaders() }, { attempts: 1, timeoutMs: 3e3 });
17499
- return res.ok ? await res.text() : void 0;
17500
17492
  }
17501
17493
  });
17502
17494
  if (o.json) return console.log(JSON.stringify({ worktrees: rows }, null, 2));
@@ -17601,7 +17593,7 @@ function runWorktreeInstall(command, cwd, quiet) {
17601
17593
  const [bin, ...args] = command.split(" ");
17602
17594
  const file = isWin2 ? "cmd.exe" : bin;
17603
17595
  const spawnArgs = isWin2 ? ["/c", bin, ...args] : args;
17604
- return new Promise((resolve5, reject) => {
17596
+ return new Promise((resolve6, reject) => {
17605
17597
  const child = (0, import_node_child_process11.spawn)(file, spawnArgs, { cwd, stdio: quiet ? "ignore" : "inherit", windowsHide: true });
17606
17598
  const timer = setTimeout(() => {
17607
17599
  try {
@@ -17616,7 +17608,7 @@ function runWorktreeInstall(command, cwd, quiet) {
17616
17608
  });
17617
17609
  child.on("exit", (code) => {
17618
17610
  clearTimeout(timer);
17619
- if (code === 0) resolve5();
17611
+ if (code === 0) resolve6();
17620
17612
  else reject(new Error(`${command} exited ${code} in ${cwd}`));
17621
17613
  });
17622
17614
  });
@@ -17624,7 +17616,7 @@ function runWorktreeInstall(command, cwd, quiet) {
17624
17616
  async function primaryCheckoutRoot(worktreeRoot) {
17625
17617
  try {
17626
17618
  const out = (await execFileP2("git", ["-C", worktreeRoot, "rev-parse", "--path-format=absolute", "--git-common-dir"], { timeout: GIT_TIMEOUT_MS })).stdout.trim();
17627
- return out ? (0, import_node_path17.dirname)(out) : void 0;
17619
+ return out ? (0, import_node_path18.dirname)(out) : void 0;
17628
17620
  } catch {
17629
17621
  return void 0;
17630
17622
  }
@@ -17637,28 +17629,28 @@ function makeProvisionDeps(worktreeRoot, quiet, log) {
17637
17629
  };
17638
17630
  }
17639
17631
  function acquireWorktreeSetupLock(worktreeRoot) {
17640
- const lockPath = (0, import_node_path17.join)(worktreeRoot, ".mmi", "worktree-setup.lock");
17632
+ const lockPath = repoRuntimeStatePath(worktreeRoot, "worktree-setup.lock");
17641
17633
  const take = () => {
17642
- const fd = (0, import_node_fs17.openSync)(lockPath, "wx");
17634
+ const fd = (0, import_node_fs18.openSync)(lockPath, "wx");
17643
17635
  try {
17644
- (0, import_node_fs17.writeSync)(fd, String(Date.now()));
17636
+ (0, import_node_fs18.writeSync)(fd, String(Date.now()));
17645
17637
  } finally {
17646
- (0, import_node_fs17.closeSync)(fd);
17638
+ (0, import_node_fs18.closeSync)(fd);
17647
17639
  }
17648
17640
  return () => {
17649
17641
  try {
17650
- (0, import_node_fs17.rmSync)(lockPath, { force: true });
17642
+ (0, import_node_fs18.rmSync)(lockPath, { force: true });
17651
17643
  } catch {
17652
17644
  }
17653
17645
  };
17654
17646
  };
17655
17647
  try {
17656
- (0, import_node_fs17.mkdirSync)((0, import_node_path17.dirname)(lockPath), { recursive: true });
17648
+ (0, import_node_fs18.mkdirSync)((0, import_node_path18.dirname)(lockPath), { recursive: true });
17657
17649
  return take();
17658
17650
  } catch {
17659
17651
  try {
17660
- if (Date.now() - (0, import_node_fs17.statSync)(lockPath).mtimeMs > WORKTREE_SETUP_LOCK_TTL_MS) {
17661
- (0, import_node_fs17.rmSync)(lockPath, { force: true });
17652
+ if (Date.now() - (0, import_node_fs18.statSync)(lockPath).mtimeMs > WORKTREE_SETUP_LOCK_TTL_MS) {
17653
+ (0, import_node_fs18.rmSync)(lockPath, { force: true });
17662
17654
  return take();
17663
17655
  }
17664
17656
  } catch {
@@ -17890,8 +17882,8 @@ tenant.command("sweep-rc").description("discover (and optionally retire) running
17890
17882
  async function resolveDnsBounded(host, timeoutMs = 3e3) {
17891
17883
  const { lookup } = await import("node:dns/promises");
17892
17884
  const probe = lookup(host).then(() => true).catch((e) => dnsErrorToResolution(e?.code));
17893
- const timeout = new Promise((resolve5) => {
17894
- setTimeout(() => resolve5(void 0), timeoutMs).unref?.();
17885
+ const timeout = new Promise((resolve6) => {
17886
+ setTimeout(() => resolve6(void 0), timeoutMs).unref?.();
17895
17887
  });
17896
17888
  return Promise.race([probe, timeout]);
17897
17889
  }
@@ -18153,7 +18145,7 @@ project.command("set [owner/repo]").description("upsert project META (idempotent
18153
18145
  const vars = rawValues("--var");
18154
18146
  if (o.secretsFile) {
18155
18147
  try {
18156
- vars.push(`secrets=${(0, import_node_fs17.readFileSync)(o.secretsFile, "utf8")}`);
18148
+ vars.push(`secrets=${(0, import_node_fs18.readFileSync)(o.secretsFile, "utf8")}`);
18157
18149
  } catch (e) {
18158
18150
  return fail(`project set: cannot read --secrets-file ${o.secretsFile}: ${e.message}`);
18159
18151
  }
@@ -18693,9 +18685,9 @@ pr.command("create").description("create a PR and print {number,url} JSON").opti
18693
18685
  console.log(JSON.stringify(created));
18694
18686
  });
18695
18687
  async function listCiWorkflowPaths(cwd = process.cwd()) {
18696
- const wfDir = (0, import_node_path17.join)(cwd, ".github", "workflows");
18697
- if (!(0, import_node_fs17.existsSync)(wfDir)) return [];
18698
- return (0, import_node_fs17.readdirSync)(wfDir).filter((name) => /\.(ya?ml)$/i.test(name)).map((name) => `.github/workflows/${name}`);
18688
+ const wfDir = (0, import_node_path18.join)(cwd, ".github", "workflows");
18689
+ if (!(0, import_node_fs18.existsSync)(wfDir)) return [];
18690
+ return (0, import_node_fs18.readdirSync)(wfDir).filter((name) => /\.(ya?ml)$/i.test(name)).map((name) => `.github/workflows/${name}`);
18699
18691
  }
18700
18692
  async function resolveMergeCiPolicyForCheckout(repoOpt) {
18701
18693
  const repo = repoOpt ?? await resolveRepo();
@@ -18714,7 +18706,7 @@ function ciAuditDeps() {
18714
18706
  // Continuous CI delivery (#1550): the gate re-seed renders from the Hub's on-disk seed templates. The
18715
18707
  // reconcile runs IN the Hub checkout, so this is local-file I/O (no network fetch). Path is relative to
18716
18708
  // the repo root (e.g. skills/bootstrap/seeds/gate.template.yml).
18717
- readSeedFile: (path2) => (0, import_node_fs17.existsSync)(path2) ? (0, import_node_fs17.readFileSync)(path2, "utf8") : null
18709
+ readSeedFile: (path2) => (0, import_node_fs18.existsSync)(path2) ? (0, import_node_fs18.readFileSync)(path2, "utf8") : null
18718
18710
  };
18719
18711
  }
18720
18712
  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) => {
@@ -18744,7 +18736,7 @@ pr.command("checks-wait <number>").description("bounded wait for PR checks; skip
18744
18736
  const result = await waitForPrChecks({
18745
18737
  resolvePolicy: () => resolveMergeCiPolicyForCheckout(o.repo),
18746
18738
  pollChecks: () => pollGhPrChecks(number, repoArgs),
18747
- sleep: (ms) => new Promise((resolve5) => setTimeout(resolve5, ms))
18739
+ sleep: (ms) => new Promise((resolve6) => setTimeout(resolve6, ms))
18748
18740
  });
18749
18741
  if (o.json) printLine(JSON.stringify(result));
18750
18742
  else printLine(`pr checks-wait: ${result.status}${result.reason ? ` \u2014 ${result.reason}` : ""}${result.detail ? ` (${result.detail})` : ""}`);
@@ -18771,7 +18763,7 @@ pr.command("land <number>").description("agent merge path (#1440): train probe \
18771
18763
  waitForChecks: (prNumber, repo) => waitForPrChecks({
18772
18764
  resolvePolicy: () => resolveRepoMergeCiPolicy(repo, ciAuditDeps()),
18773
18765
  pollChecks: () => pollGhPrChecks(prNumber, repo ? ["--repo", repo] : []),
18774
- sleep: (ms) => new Promise((resolve5) => setTimeout(resolve5, ms))
18766
+ sleep: (ms) => new Promise((resolve6) => setTimeout(resolve6, ms))
18775
18767
  }),
18776
18768
  mergeAuto: async (prNumber, repo) => {
18777
18769
  const args = repo ? ["--repo", repo] : [];
@@ -18807,7 +18799,7 @@ pr.command("land <number>").description("agent merge path (#1440): train probe \
18807
18799
  while (Date.now() < deadlineMs) {
18808
18800
  const stateRead = await readGhPrStateWithRetry(async () => (await execFileP2("gh", ["pr", "view", prNumber, ...args, "--json", "state", "--jq", ".state"], { timeout: GC_GH_TIMEOUT_MS2 })).stdout, { retries: 2, delayMs: 1e3 });
18809
18801
  if (stateRead.ok && stateRead.state === "MERGED") return true;
18810
- await new Promise((resolve5) => setTimeout(resolve5, PR_LAND_POLL_MS));
18802
+ await new Promise((resolve6) => setTimeout(resolve6, PR_LAND_POLL_MS));
18811
18803
  }
18812
18804
  return false;
18813
18805
  }
@@ -18867,7 +18859,7 @@ async function createDeferredWorktreeStore() {
18867
18859
  },
18868
18860
  write: async (entries) => {
18869
18861
  try {
18870
- await (0, import_promises4.mkdir)((0, import_node_path17.dirname)(registryPath), { recursive: true });
18862
+ await (0, import_promises4.mkdir)((0, import_node_path18.dirname)(registryPath), { recursive: true });
18871
18863
  await (0, import_promises4.writeFile)(registryPath, serializeDeferredWorktrees(entries), "utf8");
18872
18864
  } catch {
18873
18865
  }
@@ -18881,13 +18873,13 @@ var realWorktreeDirRemover = {
18881
18873
  probe: (p) => {
18882
18874
  let st;
18883
18875
  try {
18884
- st = (0, import_node_fs17.lstatSync)(p);
18876
+ st = (0, import_node_fs18.lstatSync)(p);
18885
18877
  } catch {
18886
18878
  return null;
18887
18879
  }
18888
18880
  if (st.isSymbolicLink()) return "link";
18889
18881
  try {
18890
- (0, import_node_fs17.readlinkSync)(p);
18882
+ (0, import_node_fs18.readlinkSync)(p);
18891
18883
  return "link";
18892
18884
  } catch {
18893
18885
  }
@@ -18895,7 +18887,7 @@ var realWorktreeDirRemover = {
18895
18887
  },
18896
18888
  readdir: (p) => {
18897
18889
  try {
18898
- return (0, import_node_fs17.readdirSync)(p);
18890
+ return (0, import_node_fs18.readdirSync)(p);
18899
18891
  } catch {
18900
18892
  return [];
18901
18893
  }
@@ -18904,9 +18896,9 @@ var realWorktreeDirRemover = {
18904
18896
  // leaving the target); a file symlink with unlink. rmdir first, fall back to unlink.
18905
18897
  detachLink: (p) => {
18906
18898
  try {
18907
- (0, import_node_fs17.rmdirSync)(p);
18899
+ (0, import_node_fs18.rmdirSync)(p);
18908
18900
  } catch {
18909
- (0, import_node_fs17.unlinkSync)(p);
18901
+ (0, import_node_fs18.unlinkSync)(p);
18910
18902
  }
18911
18903
  },
18912
18904
  removeTree: (p) => (0, import_promises4.rm)(p, { recursive: true, force: true, maxRetries: 5, retryDelay: 200 })
@@ -18921,7 +18913,7 @@ async function resolvePrimaryCheckout(execGit) {
18921
18913
  function worktreeRemoveDeps(execGit) {
18922
18914
  return {
18923
18915
  git: execGit,
18924
- sleep: (ms) => new Promise((resolve5) => setTimeout(resolve5, ms)),
18916
+ sleep: (ms) => new Promise((resolve6) => setTimeout(resolve6, ms)),
18925
18917
  removeWorktreeDir: async (worktreePath) => removeWorktreeTree(worktreePath, await resolvePrimaryCheckout(execGit), realWorktreeDirRemover)
18926
18918
  };
18927
18919
  }
@@ -18936,9 +18928,9 @@ async function worktreeHasStageState(worktreePath) {
18936
18928
  }
18937
18929
  }
18938
18930
  function stageStateFileBelongsToWorktree(statePath, worktreePath) {
18939
- if (!(0, import_node_fs17.existsSync)(statePath)) return false;
18931
+ if (!(0, import_node_fs18.existsSync)(statePath)) return false;
18940
18932
  try {
18941
- const state = JSON.parse((0, import_node_fs17.readFileSync)(statePath, "utf8"));
18933
+ const state = JSON.parse((0, import_node_fs18.readFileSync)(statePath, "utf8"));
18942
18934
  const recordedCwd = typeof state.identity?.cwd === "string" ? state.identity.cwd : typeof state.cwd === "string" ? state.cwd : "";
18943
18935
  return Boolean(recordedCwd && isPathUnderDirectory(recordedCwd, worktreePath));
18944
18936
  } catch {
@@ -19011,7 +19003,7 @@ pr.command("merge <number>").description("merge a PR (squash by default) and cle
19011
19003
  } : await cleanupPrMergeLocalBranch(headRef, {
19012
19004
  beforeWorktrees,
19013
19005
  startingPath,
19014
- pathExists: (p) => (0, import_node_fs17.existsSync)(p),
19006
+ pathExists: (p) => (0, import_node_fs18.existsSync)(p),
19015
19007
  execGit: async (args) => (await execFileP2("git", args, { timeout: GIT_TIMEOUT_MS })).stdout,
19016
19008
  teardownWorktreeStage,
19017
19009
  deferredStore,
@@ -19208,7 +19200,7 @@ function stageScopedRunOpts(o) {
19208
19200
  };
19209
19201
  }
19210
19202
  function printLine(value) {
19211
- (0, import_node_fs17.writeSync)(1, `${value}
19203
+ (0, import_node_fs18.writeSync)(1, `${value}
19212
19204
  `);
19213
19205
  }
19214
19206
  function stageKeepAlive() {
@@ -19225,8 +19217,8 @@ async function resolveStage() {
19225
19217
  local,
19226
19218
  shell: shellFor(),
19227
19219
  registry: { deployModel: project2?.deployModel, portRange, error: read.ok ? void 0 : read.error },
19228
- hasCompose: (0, import_node_fs17.existsSync)((0, import_node_path17.join)(process.cwd(), "docker-compose.yml")),
19229
- hasEnvExample: (0, import_node_fs17.existsSync)((0, import_node_path17.join)(process.cwd(), ".env.example"))
19220
+ hasCompose: (0, import_node_fs18.existsSync)((0, import_node_path18.join)(process.cwd(), "docker-compose.yml")),
19221
+ hasEnvExample: (0, import_node_fs18.existsSync)((0, import_node_path18.join)(process.cwd(), ".env.example"))
19230
19222
  });
19231
19223
  }
19232
19224
  async function fetchStageVaultEnvMerge() {
@@ -19690,7 +19682,7 @@ bootstrap.command("verify <repo>").description("audit whether an existing repo i
19690
19682
  client: defaultGitHubClient(),
19691
19683
  projectMeta: meta,
19692
19684
  deployModel: typeof meta?.deployModel === "string" ? meta.deployModel : void 0,
19693
- readLocalFile: (path2) => path2 === "projects.json" && apiProjects != null ? apiProjects : (0, import_node_fs17.existsSync)(path2) ? (0, import_node_fs17.readFileSync)(path2, "utf8") : null,
19685
+ readLocalFile: (path2) => path2 === "projects.json" && apiProjects != null ? apiProjects : (0, import_node_fs18.existsSync)(path2) ? (0, import_node_fs18.readFileSync)(path2, "utf8") : null,
19694
19686
  // requiredGcpApis is stored as an array by a JSON write, but `project set --var KEY=VALUE` stores a raw
19695
19687
  // comma-string — accept either so the seeded value verifies regardless of how it was written.
19696
19688
  requiredGcpApis: (() => {
@@ -19733,12 +19725,12 @@ bootstrap.command("apply <repo>").description("idempotent seed apply from skills
19733
19725
  return fail(`bootstrap apply: ${e.message}`);
19734
19726
  }
19735
19727
  const manifestPath = "skills/bootstrap/seeds/manifest.json";
19736
- if (!(0, import_node_fs17.existsSync)(manifestPath)) return fail(`bootstrap apply: ${manifestPath} not found; run from the MMI-Hub repo root`);
19737
- const manifest = loadBootstrapSeeds((0, import_node_fs17.readFileSync)(manifestPath, "utf8"));
19728
+ if (!(0, import_node_fs18.existsSync)(manifestPath)) return fail(`bootstrap apply: ${manifestPath} not found; run from the MMI-Hub repo root`);
19729
+ const manifest = loadBootstrapSeeds((0, import_node_fs18.readFileSync)(manifestPath, "utf8"));
19738
19730
  const baseBranch = o.class === "content" ? "main" : "development";
19739
19731
  const slug = parsedRepo.slug;
19740
19732
  const gh = async (args) => execFileP2("gh", args, { timeout: 2e4 });
19741
- const readFile3 = (p) => (0, import_node_fs17.existsSync)(p) ? (0, import_node_fs17.readFileSync)(p, "utf8") : null;
19733
+ const readFile3 = (p) => (0, import_node_fs18.existsSync)(p) ? (0, import_node_fs18.readFileSync)(p, "utf8") : null;
19742
19734
  const enc = (p) => p.split("/").map(encodeURIComponent).join("/");
19743
19735
  const rawVars = {};
19744
19736
  for (const value of rawValues("--var")) {
@@ -19985,16 +19977,16 @@ access.command("audit").description("audit collaborator roles + train-branch pus
19985
19977
  const repoClass = o.class;
19986
19978
  targets = [{ repo: o.repo, class: repoClass, releaseTrack: repoClass === "content" ? "trunk" : resolveReleaseTrack(meta, void 0, o.repo) }];
19987
19979
  } else {
19988
- const projectsJson = registryProjects ? JSON.stringify({ projects: registryProjects }) : (0, import_node_fs17.existsSync)("projects.json") ? (0, import_node_fs17.readFileSync)("projects.json", "utf8") : null;
19980
+ const projectsJson = registryProjects ? JSON.stringify({ projects: registryProjects }) : (0, import_node_fs18.existsSync)("projects.json") ? (0, import_node_fs18.readFileSync)("projects.json", "utf8") : null;
19989
19981
  if (!projectsJson) return failGraceful("access audit: no project registry \u2014 Hub API unreachable and projects.json not found; run from the MMI-Hub repo root or pass --repo <owner/repo>");
19990
- const fanoutJson = (0, import_node_fs17.existsSync)(".github/fanout-targets.json") ? (0, import_node_fs17.readFileSync)(".github/fanout-targets.json", "utf8") : null;
19982
+ const fanoutJson = (0, import_node_fs18.existsSync)(".github/fanout-targets.json") ? (0, import_node_fs18.readFileSync)(".github/fanout-targets.json", "utf8") : null;
19991
19983
  targets = loadAccessTargets(projectsJson, fanoutJson);
19992
19984
  }
19993
19985
  const derivedMatrix = registryProjects ? accessMatrixFromProjects(registryProjects) : {};
19994
- const fileMatrix = (0, import_node_fs17.existsSync)("access-matrix.json") ? loadAccessMatrix((0, import_node_fs17.readFileSync)("access-matrix.json", "utf8")) : {};
19986
+ const fileMatrix = (0, import_node_fs18.existsSync)("access-matrix.json") ? loadAccessMatrix((0, import_node_fs18.readFileSync)("access-matrix.json", "utf8")) : {};
19995
19987
  const matrix = mergeAccessMatrix(fileMatrix, derivedMatrix);
19996
19988
  const derivedContracts = registryProjects ? dataAccessContractsFromProjects(registryProjects) : { consumers: {} };
19997
- const fileContracts = (0, import_node_fs17.existsSync)("data-access-contracts.json") ? loadDataAccessContracts((0, import_node_fs17.readFileSync)("data-access-contracts.json", "utf8")) : { consumers: {} };
19989
+ const fileContracts = (0, import_node_fs18.existsSync)("data-access-contracts.json") ? loadDataAccessContracts((0, import_node_fs18.readFileSync)("data-access-contracts.json", "utf8")) : { consumers: {} };
19998
19990
  const dataAccess = mergeDataAccessContracts(fileContracts, derivedContracts);
19999
19991
  const report = await auditOrgAccess(targets, deps, matrix, dataAccess);
20000
19992
  console.log(o.json ? JSON.stringify(report, null, 2) : renderAccessReport(report));