@mutmutco/cli 3.105.2 → 3.105.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/main.cjs +298 -148
  2. package/package.json +1 -1
package/dist/main.cjs CHANGED
@@ -5000,7 +5000,7 @@ var program = new Command();
5000
5000
 
5001
5001
  // src/index.ts
5002
5002
  var import_promises11 = require("node:fs/promises");
5003
- var import_node_fs41 = require("node:fs");
5003
+ var import_node_fs42 = require("node:fs");
5004
5004
  var import_node_child_process19 = require("node:child_process");
5005
5005
 
5006
5006
  // src/cli-shared.ts
@@ -8590,7 +8590,7 @@ function commandLadderHint() {
8590
8590
  }
8591
8591
 
8592
8592
  // src/index.ts
8593
- var import_node_path39 = require("node:path");
8593
+ var import_node_path40 = require("node:path");
8594
8594
 
8595
8595
  // src/merge-ci-policy.ts
8596
8596
  function resolveMergeCiPolicy(input) {
@@ -15206,7 +15206,7 @@ async function executeWaveLand(plan, deps, opts = { preserveWorktree: true }) {
15206
15206
  }
15207
15207
 
15208
15208
  // src/index.ts
15209
- var import_node_os16 = require("node:os");
15209
+ var import_node_os17 = require("node:os");
15210
15210
 
15211
15211
  // src/board.ts
15212
15212
  var import_node_child_process9 = require("node:child_process");
@@ -18832,13 +18832,25 @@ function liveEvidenceLines(evidence, repo) {
18832
18832
  if (evidence.branch) live.push(`live branch ${evidence.branch} on ${repo}`);
18833
18833
  return live;
18834
18834
  }
18835
- function laneOwnership(marker, currentSession) {
18836
- if (marker?.session && currentSession) return marker.session === currentSession ? "mine" : "other";
18835
+ function sameClaimHost(a, b) {
18836
+ return Boolean(a && b && a.toLowerCase() === b.toLowerCase());
18837
+ }
18838
+ function laneOwnership(marker, current) {
18839
+ if (!marker) return "unknown";
18840
+ if (marker.session && current.session) {
18841
+ return marker.session === current.session ? "mine" : "other";
18842
+ }
18843
+ if (marker.surface && current.surface && marker.surface !== current.surface) return "other";
18844
+ if (marker.host && current.host && !sameClaimHost(marker.host, current.host)) return "other";
18845
+ if (marker.surface && current.surface && marker.surface === current.surface && marker.host && current.host && sameClaimHost(marker.host, current.host)) {
18846
+ return "mine";
18847
+ }
18837
18848
  return "unknown";
18838
18849
  }
18839
18850
  async function checkLaneContest(client, item) {
18840
18851
  const evidence = await gatherClaimLiveness(client, item.repository, item.number, openPullsFetcher(client));
18841
- const ownership = laneOwnership(evidence.marker, readSessionId(process.env));
18852
+ const actor = describeActor({ env: process.env, surface: detectSurface(process.env), cwd: process.cwd() });
18853
+ const ownership = laneOwnership(evidence.marker, actor);
18842
18854
  const live = ownership === "mine" ? [] : liveEvidenceLines(evidence, item.repository);
18843
18855
  const unverifiable = ownership === "mine" ? [] : evidence.failed;
18844
18856
  return {
@@ -20413,6 +20425,14 @@ async function hotfixBaseTagForRelease(deps, tag) {
20413
20425
  const current = normalizeHotfixVersion(tag).tag;
20414
20426
  return tags.find((t) => compareHotfixVersions(t, current) < 0) ?? tags.find((t) => t !== current) ?? "origin/main^";
20415
20427
  }
20428
+ async function hotfixReleaseExists(deps, ctx, tag) {
20429
+ try {
20430
+ await deps.run("gh", ["release", "view", tag, "--repo", ctx.repo, "--json", "tagName"]);
20431
+ return true;
20432
+ } catch {
20433
+ return false;
20434
+ }
20435
+ }
20416
20436
  async function runHotfixStart(deps, options) {
20417
20437
  const ctx = await buildTrainApplyContext(deps);
20418
20438
  const deployModel = await resolveHotfixDeployModel(deps, ctx);
@@ -20425,7 +20445,11 @@ async function runHotfixStart(deps, options) {
20425
20445
  const branch = hotfixBranch(tag);
20426
20446
  const notes = [];
20427
20447
  const existingPr = await findHotfixPr(deps, ctx, tag);
20428
- if (existingPr) {
20448
+ const existingState = (existingPr?.state ?? "").toUpperCase();
20449
+ const releaseExists = existingState === "MERGED" ? await hotfixReleaseExists(deps, ctx, tag) : false;
20450
+ const reusable = existingState === "OPEN" || existingState === "MERGED" && releaseExists;
20451
+ if (existingPr && reusable) {
20452
+ const next = existingState === "MERGED" ? `next: mmi-cli hotfix release ${tag}` : `next: merge it, then mmi-cli hotfix release ${tag}`;
20429
20453
  return {
20430
20454
  ...ctx,
20431
20455
  command: "hotfix-start",
@@ -20435,9 +20459,18 @@ async function runHotfixStart(deps, options) {
20435
20459
  source: options.from,
20436
20460
  prUrl: existingPr.url,
20437
20461
  reused: true,
20438
- notes: [`hotfix PR for ${tag} already exists (#${existingPr.number}, ${existingPr.state}) \u2014 reused; next: merge it, then mmi-cli hotfix release ${tag}`]
20462
+ notes: [`hotfix PR for ${tag} already exists (#${existingPr.number}, ${existingPr.state}) \u2014 reused; ${next}`]
20439
20463
  };
20440
20464
  }
20465
+ if (existingPr) {
20466
+ const reason = existingState === "MERGED" && !releaseExists ? `MERGED with no GitHub Release for ${tag} \u2014 recreating ${branch} from origin/main (#4381/#4383)` : `${existingPr.state} \u2014 recreating ${branch} from origin/main (#4369)`;
20467
+ notes.push(`prior hotfix PR #${existingPr.number} is ${reason}`);
20468
+ const staleRemote = clean3(await deps.run("git", ["ls-remote", "origin", `refs/heads/${branch}`]));
20469
+ if (staleRemote) {
20470
+ await deps.run("git", ["push", "origin", "--delete", branch]);
20471
+ notes.push(`deleted stale origin/${branch} left by the incomplete train`);
20472
+ }
20473
+ }
20441
20474
  const { sha, label } = await resolveHotfixSource(deps, ctx, options.from);
20442
20475
  if (deployModel === "hub-serverless") {
20443
20476
  await deps.run("node", ["scripts/release-distribution.mjs", "verify-deps"]);
@@ -28179,10 +28212,10 @@ function registerBoardCommands(program3) {
28179
28212
  }
28180
28213
 
28181
28214
  // src/merge-cleanup.ts
28182
- var import_node_fs34 = require("node:fs");
28215
+ var import_node_fs35 = require("node:fs");
28183
28216
  var import_promises8 = require("node:fs/promises");
28184
- var import_node_path33 = require("node:path");
28185
- var import_node_os12 = require("node:os");
28217
+ var import_node_path34 = require("node:path");
28218
+ var import_node_os13 = require("node:os");
28186
28219
  var import_node_child_process17 = require("node:child_process");
28187
28220
 
28188
28221
  // src/board-advance.ts
@@ -28348,6 +28381,117 @@ function makeDeferredWorktreeStore(registryPath, lockOpts = {}) {
28348
28381
  };
28349
28382
  }
28350
28383
 
28384
+ // src/jerv-cli-spawn.ts
28385
+ var import_node_fs34 = require("node:fs");
28386
+ var import_node_os12 = require("node:os");
28387
+ var import_node_path33 = require("node:path");
28388
+ var WIN_NAMES = ["jerv-cli.cmd", "jerv-cli.exe", "jerv-cli"];
28389
+ var POSIX_NAMES = ["jerv-cli"];
28390
+ var JERV_CLI_ENTRY = (0, import_node_path33.join)("node_modules", "@jervaise", "jerv-cli", "dist", "index.cjs");
28391
+ function pathEnvEntries(pathEnv, platform2 = process.platform) {
28392
+ if (platform2 !== "win32") {
28393
+ return pathEnv.split(import_node_path33.delimiter).map((e) => e.trim()).filter(Boolean);
28394
+ }
28395
+ if (pathEnv.includes(";")) {
28396
+ return pathEnv.split(";").map((e) => e.trim()).filter(Boolean);
28397
+ }
28398
+ const looksUnix = pathEnv.startsWith("/") || /(?:^|:)\/[a-zA-Z]\//.test(pathEnv);
28399
+ if (looksUnix && pathEnv.includes(":")) {
28400
+ return pathEnv.split(":").map((e) => e.trim()).filter(Boolean);
28401
+ }
28402
+ return pathEnv.trim() ? [pathEnv.trim()] : [];
28403
+ }
28404
+ function normalizeSpawnPathEntry(entry, platform2 = process.platform) {
28405
+ const trimmed = entry.trim();
28406
+ if (!trimmed) return void 0;
28407
+ if (platform2 !== "win32") return trimmed;
28408
+ const msys = /^\/([a-zA-Z])\/(.*)$/.exec(trimmed.replace(/\\/g, "/"));
28409
+ if (msys) return `${msys[1].toUpperCase()}:\\${msys[2].replace(/\//g, "\\")}`;
28410
+ return trimmed;
28411
+ }
28412
+ function jervCliCandidateDirs(env = process.env, home = (0, import_node_os12.homedir)(), platform2 = process.platform) {
28413
+ const seen = /* @__PURE__ */ new Set();
28414
+ const out = [];
28415
+ const push = (dir) => {
28416
+ if (!dir) return;
28417
+ const key = platform2 === "win32" ? dir.toLowerCase() : dir;
28418
+ if (seen.has(key)) return;
28419
+ seen.add(key);
28420
+ out.push(dir);
28421
+ };
28422
+ for (const entry of pathEnvEntries(env.PATH ?? "", platform2)) {
28423
+ push(normalizeSpawnPathEntry(entry, platform2));
28424
+ }
28425
+ if (platform2 === "win32") {
28426
+ if (env.APPDATA) push((0, import_node_path33.join)(env.APPDATA, "npm"));
28427
+ if (env.LOCALAPPDATA) push((0, import_node_path33.join)(env.LOCALAPPDATA, "npm"));
28428
+ } else {
28429
+ push((0, import_node_path33.join)(home, ".local", "bin"));
28430
+ }
28431
+ return out;
28432
+ }
28433
+ function jervCliCandidatePaths(env = process.env, home = (0, import_node_os12.homedir)(), platform2 = process.platform) {
28434
+ const names = platform2 === "win32" ? WIN_NAMES : POSIX_NAMES;
28435
+ const out = [];
28436
+ for (const dir of jervCliCandidateDirs(env, home, platform2)) {
28437
+ for (const name of names) out.push((0, import_node_path33.join)(dir, name));
28438
+ }
28439
+ return out;
28440
+ }
28441
+ function resolveJervCliPath(env = process.env, home = (0, import_node_os12.homedir)(), platform2 = process.platform, exists = import_node_fs34.existsSync) {
28442
+ for (const candidate of jervCliCandidatePaths(env, home, platform2)) {
28443
+ if (exists(candidate)) return candidate;
28444
+ }
28445
+ return void 0;
28446
+ }
28447
+ function resolveJervCliNodeEntry(shimPath, exists = import_node_fs34.existsSync) {
28448
+ const entry = (0, import_node_path33.join)((0, import_node_path33.dirname)(shimPath), JERV_CLI_ENTRY);
28449
+ return exists(entry) ? entry : void 0;
28450
+ }
28451
+ function jervCliExecFileArgs(args, opts = {}) {
28452
+ const platform2 = opts.platform ?? process.platform;
28453
+ const exists = opts.exists ?? import_node_fs34.existsSync;
28454
+ const resolved = resolveJervCliPath(opts.env ?? process.env, opts.home ?? (0, import_node_os12.homedir)(), platform2, exists);
28455
+ if (resolved) {
28456
+ const entry = resolveJervCliNodeEntry(resolved, exists);
28457
+ if (entry) {
28458
+ return { file: opts.execPath ?? process.execPath, args: [entry, ...args], via: "node-entry" };
28459
+ }
28460
+ }
28461
+ const bin = resolved ?? "jerv-cli";
28462
+ if (platform2 === "win32") {
28463
+ return { file: "cmd.exe", args: ["/c", bin, ...args], via: resolved ? "cmd-shim" : "bare" };
28464
+ }
28465
+ return { file: bin, args: [...args], via: resolved ? "posix" : "bare" };
28466
+ }
28467
+ function formatJervCliSpawnFailure(err, plan, candidates) {
28468
+ const base = (err.stderr?.trim() || err.message.trim()).split("\n")[0] || "spawn failed";
28469
+ const code = err.code;
28470
+ if (code !== "ENOENT" && !/\bENOENT\b/i.test(base)) return base;
28471
+ const tried = candidates.length > 0 ? candidates.join(" | ") : "(no candidates)";
28472
+ return `${base} [via=${plan.via} file=${plan.file}; tried: ${tried}]`;
28473
+ }
28474
+ function isEnoent(err) {
28475
+ const code = err.code;
28476
+ if (code === "ENOENT") return true;
28477
+ return /\bENOENT\b/i.test(err.message ?? "");
28478
+ }
28479
+ function execJervCli(args, options = {}) {
28480
+ const env = options.env ?? process.env;
28481
+ const candidates = jervCliCandidatePaths(env);
28482
+ const plan = jervCliExecFileArgs(args, { env });
28483
+ return execFileP2(plan.file, plan.args, options).catch((err) => {
28484
+ if (!isEnoent(err)) throw err;
28485
+ const wrapped = new Error(formatJervCliSpawnFailure(err, plan, candidates));
28486
+ Object.assign(wrapped, {
28487
+ code: "ENOENT",
28488
+ stderr: err.stderr,
28489
+ cause: err
28490
+ });
28491
+ throw wrapped;
28492
+ });
28493
+ }
28494
+
28351
28495
  // src/merge-cleanup.ts
28352
28496
  var GC_GH_TIMEOUT_MS2 = 2e4;
28353
28497
  async function advanceClosedIssuesToDone2(prNumber, repoOption) {
@@ -28466,7 +28610,8 @@ function assertPrMergeHousekeepingClean(startingPath, context, options = {}) {
28466
28610
  if (verdict.blocked) throw new Error(verdict.reason);
28467
28611
  return housekeeping;
28468
28612
  }
28469
- async function bestEffortLeaseClose(wtPath, exec = (cmd, args) => execFileP2(cmd, args, { timeout: GIT_TIMEOUT_MS })) {
28613
+ var defaultLeaseCloseExec = (_cmd, args) => execJervCli(args, { timeout: GIT_TIMEOUT_MS });
28614
+ async function bestEffortLeaseClose(wtPath, exec = defaultLeaseCloseExec) {
28470
28615
  const step = "close jerv worktree lease";
28471
28616
  try {
28472
28617
  await exec("jerv-cli", ["lease", "close", "--ref", wtPath]);
@@ -28489,7 +28634,7 @@ async function applyGcPlan(plan, remote, opts = {}) {
28489
28634
  );
28490
28635
  const repoRoot2 = (await execFileP2("git", ["rev-parse", "--show-toplevel"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim() || process.cwd();
28491
28636
  const worktreeGitRoot = await currentRepoWorktreeGitRoot(repoRoot2);
28492
- const primaryRepoRoot = worktreeGitRoot ? (0, import_node_path33.dirname)((0, import_node_path33.dirname)(worktreeGitRoot)) : repoRoot2;
28637
+ const primaryRepoRoot = worktreeGitRoot ? (0, import_node_path34.dirname)((0, import_node_path34.dirname)(worktreeGitRoot)) : repoRoot2;
28493
28638
  const gcActor = describeActor({ env: process.env, surface: detectSurface(process.env), cwd: process.cwd() });
28494
28639
  const owners = readWorktreeOwners(primaryRepoRoot);
28495
28640
  const removalNow = Date.now();
@@ -28520,7 +28665,7 @@ async function applyGcPlan(plan, remote, opts = {}) {
28520
28665
  const cleanup = await cleanupPrMergeLocalBranch(branch.branch, {
28521
28666
  beforeWorktrees,
28522
28667
  startingPath: branch.worktreePath,
28523
- pathExists: (p) => (0, import_node_fs34.existsSync)(p),
28668
+ pathExists: (p) => (0, import_node_fs35.existsSync)(p),
28524
28669
  execGit: async (args) => (await execFileP2("git", args, { timeout: GIT_TIMEOUT_MS })).stdout,
28525
28670
  teardownWorktreeStage,
28526
28671
  deferredStore,
@@ -28549,7 +28694,7 @@ async function applyGcPlan(plan, remote, opts = {}) {
28549
28694
  let removalAttempted = false;
28550
28695
  try {
28551
28696
  const cleanupTarget = resolveSafeSiblingWorktreeCleanupTarget(wt.path, siblingRoot, {
28552
- realpath: (path2) => (0, import_node_fs34.realpathSync)(path2)
28697
+ realpath: (path2) => (0, import_node_fs35.realpathSync)(path2)
28553
28698
  });
28554
28699
  if (!cleanupTarget.ok) {
28555
28700
  result.failed.push(`${wt.path}: ${cleanupTarget.reason}`);
@@ -28636,13 +28781,13 @@ async function composeOverrideBodyFile(prNumber, repoArgs, gh) {
28636
28781
  const commits = JSON.parse(raw).commits ?? [];
28637
28782
  const body = squashBodyWithOverride(commits.map((c) => ({ headline: c.messageHeadline ?? "", body: c.messageBody ?? "" })), process.cwd());
28638
28783
  if (!body) return void 0;
28639
- const dir = (0, import_node_fs34.mkdtempSync)((0, import_node_path33.join)((0, import_node_os12.tmpdir)(), "mmi-squash-body-"));
28640
- const path2 = (0, import_node_path33.join)(dir, "body.txt");
28641
- (0, import_node_fs34.writeFileSync)(path2, `${body}
28784
+ const dir = (0, import_node_fs35.mkdtempSync)((0, import_node_path34.join)((0, import_node_os13.tmpdir)(), "mmi-squash-body-"));
28785
+ const path2 = (0, import_node_path34.join)(dir, "body.txt");
28786
+ (0, import_node_fs35.writeFileSync)(path2, `${body}
28642
28787
  `, "utf8");
28643
28788
  return { path: path2, cleanup: () => {
28644
28789
  try {
28645
- (0, import_node_fs34.rmSync)(dir, { recursive: true, force: true });
28790
+ (0, import_node_fs35.rmSync)(dir, { recursive: true, force: true });
28646
28791
  } catch {
28647
28792
  }
28648
28793
  } };
@@ -28764,13 +28909,13 @@ var realWorktreeDirRemover = {
28764
28909
  probe: (p) => {
28765
28910
  let st;
28766
28911
  try {
28767
- st = (0, import_node_fs34.lstatSync)(p);
28912
+ st = (0, import_node_fs35.lstatSync)(p);
28768
28913
  } catch {
28769
28914
  return null;
28770
28915
  }
28771
28916
  if (st.isSymbolicLink()) return "link";
28772
28917
  try {
28773
- (0, import_node_fs34.readlinkSync)(p);
28918
+ (0, import_node_fs35.readlinkSync)(p);
28774
28919
  return "link";
28775
28920
  } catch {
28776
28921
  }
@@ -28778,7 +28923,7 @@ var realWorktreeDirRemover = {
28778
28923
  },
28779
28924
  readdir: (p) => {
28780
28925
  try {
28781
- return (0, import_node_fs34.readdirSync)(p);
28926
+ return (0, import_node_fs35.readdirSync)(p);
28782
28927
  } catch {
28783
28928
  return [];
28784
28929
  }
@@ -28787,9 +28932,9 @@ var realWorktreeDirRemover = {
28787
28932
  // leaving the target); a file symlink with unlink. rmdir first, fall back to unlink.
28788
28933
  detachLink: (p) => {
28789
28934
  try {
28790
- (0, import_node_fs34.rmdirSync)(p);
28935
+ (0, import_node_fs35.rmdirSync)(p);
28791
28936
  } catch {
28792
- (0, import_node_fs34.unlinkSync)(p);
28937
+ (0, import_node_fs35.unlinkSync)(p);
28793
28938
  }
28794
28939
  },
28795
28940
  removeTree: (p) => (0, import_promises8.rm)(p, { recursive: true, force: true, maxRetries: 5, retryDelay: 200 })
@@ -28822,9 +28967,9 @@ async function worktreeHasStageState(worktreePath) {
28822
28967
  }
28823
28968
  }
28824
28969
  function stageStateFileBelongsToWorktree(statePath, worktreePath) {
28825
- if (!(0, import_node_fs34.existsSync)(statePath)) return false;
28970
+ if (!(0, import_node_fs35.existsSync)(statePath)) return false;
28826
28971
  try {
28827
- const state = JSON.parse((0, import_node_fs34.readFileSync)(statePath, "utf8"));
28972
+ const state = JSON.parse((0, import_node_fs35.readFileSync)(statePath, "utf8"));
28828
28973
  const recordedCwd = typeof state.identity?.cwd === "string" ? state.identity.cwd : typeof state.cwd === "string" ? state.cwd : "";
28829
28974
  return Boolean(recordedCwd && isPathUnderDirectory(recordedCwd, worktreePath));
28830
28975
  } catch {
@@ -29155,9 +29300,9 @@ async function checkDocsIndexAtHead(opts, deps) {
29155
29300
  }
29156
29301
 
29157
29302
  // src/worktree-lifecycle-commands.ts
29158
- var import_node_fs35 = require("node:fs");
29303
+ var import_node_fs36 = require("node:fs");
29159
29304
  var import_promises9 = require("node:fs/promises");
29160
- var import_node_path34 = require("node:path");
29305
+ var import_node_path35 = require("node:path");
29161
29306
  var GH_TIMEOUT_MS = 2e4;
29162
29307
  var STALE_PR_LOOKUP_LIMIT = 20;
29163
29308
  var DEFAULT_BASE = "origin/development";
@@ -29304,7 +29449,7 @@ function classifyStaleLeaks(input) {
29304
29449
  var defaultOrphanDirScanDeps = {
29305
29450
  listDirs: (root) => {
29306
29451
  try {
29307
- return (0, import_node_fs35.readdirSync)(root, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => (0, import_node_path34.join)(root, e.name));
29452
+ return (0, import_node_fs36.readdirSync)(root, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => (0, import_node_path35.join)(root, e.name));
29308
29453
  } catch {
29309
29454
  return [];
29310
29455
  }
@@ -29460,13 +29605,13 @@ function registerWorktreeCommands(program3) {
29460
29605
  const detached = headBorn && !symbolicBranch;
29461
29606
  const branch = symbolicBranch || (detached ? "HEAD" : "");
29462
29607
  if (!wtPath || !branch) return fail("worktree land: not inside a git worktree");
29463
- const gitFile = (0, import_node_path34.join)(wtPath, ".git");
29464
- const isLinked = (0, import_node_fs35.existsSync)(gitFile) && (0, import_node_fs35.statSync)(gitFile).isFile();
29608
+ const gitFile = (0, import_node_path35.join)(wtPath, ".git");
29609
+ const isLinked = (0, import_node_fs36.existsSync)(gitFile) && (0, import_node_fs36.statSync)(gitFile).isFile();
29465
29610
  if (apply && !isLinked) {
29466
29611
  return fail("worktree land: run from inside the linked worktree you want to land (this is the primary checkout)");
29467
29612
  }
29468
29613
  const commonDir = (await execFileP2("git", ["rev-parse", "--git-common-dir"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim();
29469
- const primaryCheckout = commonDir ? (0, import_node_path34.dirname)(commonDir) : wtPath;
29614
+ const primaryCheckout = commonDir ? (0, import_node_path35.dirname)(commonDir) : wtPath;
29470
29615
  const localBranchNames = await execFileP2("git", ["-C", primaryCheckout, "for-each-ref", "--format=%(refname:short)", "refs/heads"], { timeout: GIT_TIMEOUT_MS }).then(({ stdout }) => new Set((stdout || "").split("\n").map((l) => l.trim()).filter(Boolean))).catch(() => void 0);
29471
29616
  const orphan = classifyOrphanedWorktree({
29472
29617
  branch,
@@ -29675,10 +29820,10 @@ async function gatherWorktreeContext() {
29675
29820
  if (s) stages.push({ path: wt.path, port: s.port });
29676
29821
  }
29677
29822
  const worktreeGitRoot = await currentRepoWorktreeGitRoot(repoRoot2);
29678
- const primaryRepoRoot = worktreeGitRoot ? (0, import_node_path34.dirname)((0, import_node_path34.dirname)(worktreeGitRoot)) : repoRoot2;
29823
+ const primaryRepoRoot = worktreeGitRoot ? (0, import_node_path35.dirname)((0, import_node_path35.dirname)(worktreeGitRoot)) : repoRoot2;
29679
29824
  const wtRoot = siblingMmiWorktreesRoot(primaryRepoRoot);
29680
29825
  let orphanDirs = [];
29681
- if ((0, import_node_fs35.existsSync)(wtRoot)) {
29826
+ if ((0, import_node_fs36.existsSync)(wtRoot)) {
29682
29827
  orphanDirs = scanOrphanDirs(wtRoot, worktreeGitRoot, {
29683
29828
  ...defaultOrphanDirScanDeps,
29684
29829
  listDirs: (root) => worktreeScanDirs(root, primaryRepoRoot, defaultOrphanDirScanDeps.listDirs, isRepoCheckoutDir)
@@ -29704,7 +29849,7 @@ ${err.stderr ?? ""}`;
29704
29849
  }
29705
29850
 
29706
29851
  // src/issue-commands.ts
29707
- var import_node_fs36 = require("node:fs");
29852
+ var import_node_fs37 = require("node:fs");
29708
29853
  var import_node_crypto7 = require("node:crypto");
29709
29854
  var ghRunner = async (args, timeoutMs) => (await execFileP2("gh", args, { timeout: timeoutMs })).stdout;
29710
29855
  var ReparentConflictError = class extends Error {
@@ -29722,7 +29867,7 @@ async function editIssue(client, options, deps = {}) {
29722
29867
  const url = `https://github.com/${repo}/issues/${parsed.number}`;
29723
29868
  const patch = {};
29724
29869
  let bodyChanged = false;
29725
- const textDeps = () => deps.textDeps ?? { readFile: (p, e) => Promise.resolve((0, import_node_fs36.readFileSync)(p, e)), readStdin: () => Promise.resolve("") };
29870
+ const textDeps = () => deps.textDeps ?? { readFile: (p, e) => Promise.resolve((0, import_node_fs37.readFileSync)(p, e)), readStdin: () => Promise.resolve("") };
29726
29871
  if (options.titleFile !== void 0) {
29727
29872
  patch.title = await resolveIssueTitle({ title: options.title, titleFile: options.titleFile }, textDeps());
29728
29873
  } else if (options.title !== void 0) {
@@ -30327,7 +30472,7 @@ function extendCreateCommand(issue2, batchAttach) {
30327
30472
  if (opts.batch) {
30328
30473
  let specs;
30329
30474
  try {
30330
- const raw = (0, import_node_fs36.readFileSync)(opts.batch, "utf8");
30475
+ const raw = (0, import_node_fs37.readFileSync)(opts.batch, "utf8");
30331
30476
  specs = JSON.parse(raw);
30332
30477
  if (!Array.isArray(specs)) throw new Error("batch file must contain a JSON array");
30333
30478
  } catch (e) {
@@ -30402,8 +30547,8 @@ ${lines}`, {
30402
30547
  }
30403
30548
 
30404
30549
  // src/train-commands.ts
30405
- var import_node_fs37 = require("node:fs");
30406
- var import_node_path35 = require("node:path");
30550
+ var import_node_fs38 = require("node:fs");
30551
+ var import_node_path36 = require("node:path");
30407
30552
 
30408
30553
  // src/train-status.ts
30409
30554
  function buildTrainStatusReport(input) {
@@ -30443,7 +30588,7 @@ function formatTrainStatus(r) {
30443
30588
  // src/train-commands.ts
30444
30589
  function readRepoVersion() {
30445
30590
  try {
30446
- return JSON.parse((0, import_node_fs37.readFileSync)((0, import_node_path35.join)(process.cwd(), ".claude-plugin", "plugin.json"), "utf8")).version || void 0;
30591
+ return JSON.parse((0, import_node_fs38.readFileSync)((0, import_node_path36.join)(process.cwd(), ".claude-plugin", "plugin.json"), "utf8")).version || void 0;
30447
30592
  } catch {
30448
30593
  return void 0;
30449
30594
  }
@@ -30589,9 +30734,9 @@ function registerDeployCommands(program3) {
30589
30734
  }
30590
30735
 
30591
30736
  // src/discovery-commands.ts
30592
- var import_node_fs38 = require("node:fs");
30593
- var import_node_os13 = require("node:os");
30594
- var import_node_path36 = require("node:path");
30737
+ var import_node_fs39 = require("node:fs");
30738
+ var import_node_os14 = require("node:os");
30739
+ var import_node_path37 = require("node:path");
30595
30740
  var GC_GH_TIMEOUT_MS3 = 2e4;
30596
30741
  async function collectStatus() {
30597
30742
  const repo = await resolveRepo();
@@ -30779,10 +30924,10 @@ async function collectOnboardStatus(opts = {}) {
30779
30924
  else if (top) nextCommand = `mmi-cli board claim ${top.number} # ${top.title}`;
30780
30925
  else nextCommand = "mmi-cli board read \u2014 no claimable items found";
30781
30926
  }
30782
- const home = (0, import_node_os13.homedir)();
30927
+ const home = (0, import_node_os14.homedir)();
30783
30928
  const plugin = onboardPluginGate({
30784
- readKnown: () => readFileSyncSafe((0, import_node_path36.join)(home, ...KNOWN_MARKETPLACES_RELATIVE), import_node_fs38.readFileSync),
30785
- readSettings: () => readFileSyncSafe((0, import_node_path36.join)(home, ".claude", "settings.json"), import_node_fs38.readFileSync)
30929
+ readKnown: () => readFileSyncSafe((0, import_node_path37.join)(home, ...KNOWN_MARKETPLACES_RELATIVE), import_node_fs39.readFileSync),
30930
+ readSettings: () => readFileSyncSafe((0, import_node_path37.join)(home, ".claude", "settings.json"), import_node_fs39.readFileSync)
30786
30931
  });
30787
30932
  return { track, board, registry: registry2, secrets, plugin, estateCli, nextCommand };
30788
30933
  }
@@ -31686,19 +31831,19 @@ function registerSessionReport(program3) {
31686
31831
  }
31687
31832
 
31688
31833
  // src/plugin-release-catchup.ts
31689
- var import_node_fs39 = require("node:fs");
31690
- var import_node_path37 = require("node:path");
31691
- var import_node_os14 = require("node:os");
31834
+ var import_node_fs40 = require("node:fs");
31835
+ var import_node_path38 = require("node:path");
31836
+ var import_node_os15 = require("node:os");
31692
31837
  var RELEASE_CATCHUP_TTL_MS = 24 * 60 * 60 * 1e3;
31693
31838
  var RELEASE_CATCHUP_DISABLE_ENV = "MMI_NO_RELEASE_CATCHUP";
31694
31839
  function releaseCatchupStatePath(env = process.env) {
31695
31840
  if (env.MMI_RELEASE_CATCHUP_STATE) return env.MMI_RELEASE_CATCHUP_STATE;
31696
31841
  if (process.platform === "win32") {
31697
- const base2 = env.LOCALAPPDATA || (0, import_node_path37.join)((0, import_node_os14.homedir)(), "AppData", "Local");
31698
- return (0, import_node_path37.join)(base2, "MMI Future", "mmi-cli", "release-catchup.json");
31842
+ const base2 = env.LOCALAPPDATA || (0, import_node_path38.join)((0, import_node_os15.homedir)(), "AppData", "Local");
31843
+ return (0, import_node_path38.join)(base2, "MMI Future", "mmi-cli", "release-catchup.json");
31699
31844
  }
31700
- const base = env.XDG_STATE_HOME || (0, import_node_path37.join)((0, import_node_os14.homedir)(), ".local", "state");
31701
- return (0, import_node_path37.join)(base, "mmi-cli", "release-catchup.json");
31845
+ const base = env.XDG_STATE_HOME || (0, import_node_path38.join)((0, import_node_os15.homedir)(), ".local", "state");
31846
+ return (0, import_node_path38.join)(base, "mmi-cli", "release-catchup.json");
31702
31847
  }
31703
31848
  function releaseCatchupDue(state, now, force = false) {
31704
31849
  if (force) return true;
@@ -31708,7 +31853,7 @@ function releaseCatchupDue(state, now, force = false) {
31708
31853
  function newestCachedPluginVersion(home) {
31709
31854
  let names;
31710
31855
  try {
31711
- names = (0, import_node_fs39.readdirSync)(pluginCacheRoot(home));
31856
+ names = (0, import_node_fs40.readdirSync)(pluginCacheRoot(home));
31712
31857
  } catch {
31713
31858
  return void 0;
31714
31859
  }
@@ -31716,15 +31861,15 @@ function newestCachedPluginVersion(home) {
31716
31861
  }
31717
31862
  function marketplaceClonePath(home) {
31718
31863
  try {
31719
- const parsed = JSON.parse((0, import_node_fs39.readFileSync)((0, import_node_path37.join)(home, ".claude", "plugins", "known_marketplaces.json"), "utf8"));
31864
+ const parsed = JSON.parse((0, import_node_fs40.readFileSync)((0, import_node_path38.join)(home, ".claude", "plugins", "known_marketplaces.json"), "utf8"));
31720
31865
  if (parsed.mutmutco?.installLocation) return parsed.mutmutco.installLocation;
31721
31866
  } catch {
31722
31867
  }
31723
- return (0, import_node_path37.join)(home, ".claude", "plugins", "marketplaces", "mutmutco");
31868
+ return (0, import_node_path38.join)(home, ".claude", "plugins", "marketplaces", "mutmutco");
31724
31869
  }
31725
31870
  function readCatalogVersion(home) {
31726
31871
  try {
31727
- const parsed = JSON.parse((0, import_node_fs39.readFileSync)((0, import_node_path37.join)(marketplaceClonePath(home), ".claude-plugin", "marketplace.json"), "utf8"));
31872
+ const parsed = JSON.parse((0, import_node_fs40.readFileSync)((0, import_node_path38.join)(marketplaceClonePath(home), ".claude-plugin", "marketplace.json"), "utf8"));
31728
31873
  return parsed.plugins?.find((p) => p.name === "mmi")?.version;
31729
31874
  } catch {
31730
31875
  return void 0;
@@ -31732,7 +31877,7 @@ function readCatalogVersion(home) {
31732
31877
  }
31733
31878
  function readMmiInstallRecord(home) {
31734
31879
  try {
31735
- const parsed = JSON.parse((0, import_node_fs39.readFileSync)((0, import_node_path37.join)(home, ".claude", "plugins", "installed_plugins.json"), "utf8"));
31880
+ const parsed = JSON.parse((0, import_node_fs40.readFileSync)((0, import_node_path38.join)(home, ".claude", "plugins", "installed_plugins.json"), "utf8"));
31736
31881
  const record = parsed.plugins?.["mmi@mutmutco"]?.[0];
31737
31882
  return record?.version ? { version: record.version, gitCommitSha: record.gitCommitSha } : void 0;
31738
31883
  } catch {
@@ -31741,7 +31886,7 @@ function readMmiInstallRecord(home) {
31741
31886
  }
31742
31887
  async function runReleaseCatchup(home, env, deps, opts = {}) {
31743
31888
  if (env[RELEASE_CATCHUP_DISABLE_ENV]) return { ok: true, skipped: true, detail: `disabled via ${RELEASE_CATCHUP_DISABLE_ENV}` };
31744
- if (!(0, import_node_fs39.existsSync)(pluginCacheRoot(home))) return { ok: true, skipped: true, detail: "no mmi plugin cache on this machine \u2014 nothing to catch up" };
31889
+ if (!(0, import_node_fs40.existsSync)(pluginCacheRoot(home))) return { ok: true, skipped: true, detail: "no mmi plugin cache on this machine \u2014 nothing to catch up" };
31745
31890
  const statePath = releaseCatchupStatePath(env);
31746
31891
  const state = deps.readState(statePath);
31747
31892
  if (!releaseCatchupDue(state, deps.now(), opts.force)) {
@@ -31766,8 +31911,8 @@ async function runReleaseCatchup(home, env, deps, opts = {}) {
31766
31911
  return { ok: false, detail: `released ${latest} but the install record could not be cleared \u2014 nothing changed (record still ${prior.version})` };
31767
31912
  }
31768
31913
  const installed = await deps.runClaude(["plugin", "install", "mmi@mutmutco"], "claude plugin install mmi@mutmutco");
31769
- const payload = (0, import_node_path37.join)(pluginCacheRoot(home), latest, ".pi-plugin");
31770
- if (!installed || !(0, import_node_fs39.existsSync)(payload)) {
31914
+ const payload = (0, import_node_path38.join)(pluginCacheRoot(home), latest, ".pi-plugin");
31915
+ if (!installed || !(0, import_node_fs40.existsSync)(payload)) {
31771
31916
  const why = installed ? `install of ${latest} did not produce a verifiable .pi-plugin payload` : `install of ${latest} failed`;
31772
31917
  if (!prior) return { ok: false, detail: `${why}; no prior record to restore` };
31773
31918
  const rollback = await restorePriorRecord(home, prior, deps);
@@ -31795,7 +31940,7 @@ async function restorePriorRecord(home, prior, deps) {
31795
31940
  }
31796
31941
  function shouldSpawnReleaseCatchup(home, env, readState2, now = Date.now()) {
31797
31942
  if (env[RELEASE_CATCHUP_DISABLE_ENV]) return false;
31798
- if (!(0, import_node_fs39.existsSync)(pluginCacheRoot(home))) return false;
31943
+ if (!(0, import_node_fs40.existsSync)(pluginCacheRoot(home))) return false;
31799
31944
  return releaseCatchupDue(readState2(releaseCatchupStatePath(env)), now);
31800
31945
  }
31801
31946
  function defaultRegistrationHeal(home, env) {
@@ -33841,17 +33986,17 @@ function parseOriginRepo(remoteUrl) {
33841
33986
  }
33842
33987
  function ghHostsConfigPath(env, platform2) {
33843
33988
  const sep3 = platform2 === "win32" ? "\\" : "/";
33844
- const join35 = (...parts) => parts.join(sep3);
33989
+ const join36 = (...parts) => parts.join(sep3);
33845
33990
  const explicit = env.GH_CONFIG_DIR?.trim();
33846
- if (explicit) return join35(explicit, "hosts.yml");
33991
+ if (explicit) return join36(explicit, "hosts.yml");
33847
33992
  if (platform2 === "win32") {
33848
33993
  const appData = (env.AppData ?? env.APPDATA)?.trim();
33849
- return appData ? join35(appData, "GitHub CLI", "hosts.yml") : void 0;
33994
+ return appData ? join36(appData, "GitHub CLI", "hosts.yml") : void 0;
33850
33995
  }
33851
33996
  const xdg = env.XDG_CONFIG_HOME?.trim();
33852
- if (xdg) return join35(xdg, "gh", "hosts.yml");
33997
+ if (xdg) return join36(xdg, "gh", "hosts.yml");
33853
33998
  const home = env.HOME?.trim();
33854
- return home ? join35(home, ".config", "gh", "hosts.yml") : void 0;
33999
+ return home ? join36(home, ".config", "gh", "hosts.yml") : void 0;
33855
34000
  }
33856
34001
  function parseGhHostsAccounts(yaml, host = "github.com") {
33857
34002
  let hostIndent = null;
@@ -33901,9 +34046,9 @@ function ghAccountCaveat(announcedLogin, accounts) {
33901
34046
  }
33902
34047
 
33903
34048
  // src/doctor-io.ts
33904
- var import_node_fs40 = require("node:fs");
33905
- var import_node_os15 = require("node:os");
33906
- var import_node_path38 = require("node:path");
34049
+ var import_node_fs41 = require("node:fs");
34050
+ var import_node_os16 = require("node:os");
34051
+ var import_node_path39 = require("node:path");
33907
34052
  var import_node_child_process18 = require("node:child_process");
33908
34053
  var import_node_util8 = require("node:util");
33909
34054
  var execFileP6 = (0, import_node_util8.promisify)(import_node_child_process18.execFile);
@@ -33911,7 +34056,7 @@ var MMI_PLUGIN_ID2 = "mmi@mutmutco";
33911
34056
  function installedClaudePluginVersion() {
33912
34057
  try {
33913
34058
  const file = JSON.parse(
33914
- (0, import_node_fs40.readFileSync)((0, import_node_path38.join)((0, import_node_os15.homedir)(), ".claude", "plugins", "installed_plugins.json"), "utf8")
34059
+ (0, import_node_fs41.readFileSync)((0, import_node_path39.join)((0, import_node_os16.homedir)(), ".claude", "plugins", "installed_plugins.json"), "utf8")
33915
34060
  );
33916
34061
  const versions = (file.plugins?.[MMI_PLUGIN_ID2] ?? []).map((r) => r.version).filter((v) => Boolean(v));
33917
34062
  if (versions.length === 0) return void 0;
@@ -33922,7 +34067,7 @@ function installedClaudePluginVersion() {
33922
34067
  }
33923
34068
  function manifestVersion(path2) {
33924
34069
  try {
33925
- const manifest = JSON.parse((0, import_node_fs40.readFileSync)(path2, "utf8"));
34070
+ const manifest = JSON.parse((0, import_node_fs41.readFileSync)(path2, "utf8"));
33926
34071
  return typeof manifest.version === "string" && manifest.version.trim() ? manifest.version.trim() : void 0;
33927
34072
  } catch {
33928
34073
  return void 0;
@@ -33932,22 +34077,22 @@ function installedSurfacePluginVersion(surface) {
33932
34077
  const token = surfaceToken(surface);
33933
34078
  if (token === "kilo") {
33934
34079
  try {
33935
- const stamp = (0, import_node_fs40.readFileSync)((0, import_node_path38.join)((0, import_node_os15.homedir)(), ".kilo", ".mmi-kilo-version"), "utf8").trim();
34080
+ const stamp = (0, import_node_fs41.readFileSync)((0, import_node_path39.join)((0, import_node_os16.homedir)(), ".kilo", ".mmi-kilo-version"), "utf8").trim();
33936
34081
  return stamp || void 0;
33937
34082
  } catch {
33938
34083
  return void 0;
33939
34084
  }
33940
34085
  }
33941
34086
  if (token === "cursor") {
33942
- return manifestVersion((0, import_node_path38.join)(cursorLocalPluginRoot(), ".cursor-plugin", "plugin.json"));
34087
+ return manifestVersion((0, import_node_path39.join)(cursorLocalPluginRoot(), ".cursor-plugin", "plugin.json"));
33943
34088
  }
33944
34089
  if (token === "jervcode") {
33945
34090
  const entry = mmiPiWrapperEntry();
33946
34091
  if (!entry) return void 0;
33947
- return manifestVersion((0, import_node_path38.join)(decodeURIComponent(entry.replace(/^file:\/\/\/?/, "")), "package.json"));
34092
+ return manifestVersion((0, import_node_path39.join)(decodeURIComponent(entry.replace(/^file:\/\/\/?/, "")), "package.json"));
33948
34093
  }
33949
34094
  if (token === "kimi") {
33950
- return manifestVersion((0, import_node_path38.join)(surfaceConfigRoot(surface), "plugins", "managed", "mmi", ".kimi-plugin", "plugin.json"));
34095
+ return manifestVersion((0, import_node_path39.join)(surfaceConfigRoot(surface), "plugins", "managed", "mmi", ".kimi-plugin", "plugin.json"));
33951
34096
  }
33952
34097
  if (token === "claude") return installedClaudePluginVersion();
33953
34098
  if (token !== "codex") return void 0;
@@ -33985,13 +34130,13 @@ function worktreeRootSync() {
33985
34130
  }
33986
34131
  var gitignorePath = () => {
33987
34132
  const root = worktreeRootSync();
33988
- return root === null ? null : (0, import_node_path38.join)(root, ".gitignore");
34133
+ return root === null ? null : (0, import_node_path39.join)(root, ".gitignore");
33989
34134
  };
33990
34135
  function readGitignore() {
33991
34136
  const path2 = gitignorePath();
33992
34137
  if (path2 === null) return null;
33993
34138
  try {
33994
- return (0, import_node_fs40.readFileSync)(path2, "utf8");
34139
+ return (0, import_node_fs41.readFileSync)(path2, "utf8");
33995
34140
  } catch {
33996
34141
  return null;
33997
34142
  }
@@ -34000,7 +34145,7 @@ function writeGitignore(content) {
34000
34145
  const path2 = gitignorePath();
34001
34146
  if (path2 === null) return false;
34002
34147
  try {
34003
- (0, import_node_fs40.writeFileSync)(path2, content, "utf8");
34148
+ (0, import_node_fs41.writeFileSync)(path2, content, "utf8");
34004
34149
  return true;
34005
34150
  } catch {
34006
34151
  return false;
@@ -34024,7 +34169,7 @@ async function repoRoot() {
34024
34169
  }
34025
34170
  function hasRepoLocalWorktrees() {
34026
34171
  const root = worktreeRootSync();
34027
- return root !== null && (0, import_node_fs40.existsSync)((0, import_node_path38.join)(root, ".worktrees"));
34172
+ return root !== null && (0, import_node_fs41.existsSync)((0, import_node_path39.join)(root, ".worktrees"));
34028
34173
  }
34029
34174
 
34030
34175
  // src/index.ts
@@ -34043,8 +34188,8 @@ ${r.stderr ?? ""}`).catch(() => "");
34043
34188
  function ghMultiAccountCaveat(announcedLogin) {
34044
34189
  try {
34045
34190
  const hostsPath = ghHostsConfigPath(process.env, process.platform);
34046
- if (!hostsPath || !(0, import_node_fs41.existsSync)(hostsPath)) return void 0;
34047
- return ghAccountCaveat(announcedLogin, parseGhHostsAccounts((0, import_node_fs41.readFileSync)(hostsPath, "utf8")));
34191
+ if (!hostsPath || !(0, import_node_fs42.existsSync)(hostsPath)) return void 0;
34192
+ return ghAccountCaveat(announcedLogin, parseGhHostsAccounts((0, import_node_fs42.readFileSync)(hostsPath, "utf8")));
34048
34193
  } catch {
34049
34194
  return void 0;
34050
34195
  }
@@ -34052,12 +34197,12 @@ function ghMultiAccountCaveat(announcedLogin) {
34052
34197
  var ENV_HEAL_LOCK_STALE_MS = 10 * 6e4;
34053
34198
  var ENV_HEAL_LOCK_MAX_WAIT_MS = 2 * 6e4;
34054
34199
  function envHealLockPath(home) {
34055
- return (0, import_node_path39.join)(home, ".claude", "plugins", ".mmi-env-heal.lock");
34200
+ return (0, import_node_path40.join)(home, ".claude", "plugins", ".mmi-env-heal.lock");
34056
34201
  }
34057
34202
  async function withEnvHealLock(what, run) {
34058
34203
  try {
34059
34204
  return await withFileLock(
34060
- envHealLockPath((0, import_node_os16.homedir)()),
34205
+ envHealLockPath((0, import_node_os17.homedir)()),
34061
34206
  { staleMs: ENV_HEAL_LOCK_STALE_MS, maxWaitMs: ENV_HEAL_LOCK_MAX_WAIT_MS, label: "mmi env-heal lock" },
34062
34207
  run
34063
34208
  );
@@ -34154,7 +34299,7 @@ function mmiDoctorDeps(opts = {}) {
34154
34299
  const configRoot = surfaceConfigRoot(surface);
34155
34300
  const running = surface === "codex" ? installedActivePluginVersion(surface) : runningPluginVersion(process.env, resolveClientVersion());
34156
34301
  const plan = buildPluginCachePlan(
34157
- (0, import_node_os16.homedir)(),
34302
+ (0, import_node_os17.homedir)(),
34158
34303
  running,
34159
34304
  pluginCacheFsDeps(configRoot, () => 0),
34160
34305
  { configRoot, includeStaging: surface !== "codex" }
@@ -34178,14 +34323,14 @@ function mmiDoctorDeps(opts = {}) {
34178
34323
  const running = surface === "codex" ? installedActivePluginVersion(surface) : runningPluginVersion(process.env, resolveClientVersion());
34179
34324
  const installed = installedActivePluginVersion(surface);
34180
34325
  const plan = buildPluginCachePlan(
34181
- (0, import_node_os16.homedir)(),
34326
+ (0, import_node_os17.homedir)(),
34182
34327
  running,
34183
34328
  pluginCacheFsDeps(configRoot, () => 0),
34184
34329
  { configRoot, includeStaging: surface !== "codex", installedVersion: installed }
34185
34330
  );
34186
34331
  const result = applyPluginCachePlan(
34187
34332
  plan,
34188
- (p) => (0, import_node_fs41.rmSync)(p, { recursive: true }),
34333
+ (p) => (0, import_node_fs42.rmSync)(p, { recursive: true }),
34189
34334
  stagingApplyFsGuard(configRoot)
34190
34335
  );
34191
34336
  return {
@@ -34213,12 +34358,12 @@ function mmiDoctorDeps(opts = {}) {
34213
34358
  piPluginState: () => {
34214
34359
  const env = { ...process.env };
34215
34360
  delete env.CLAUDE_PLUGIN_ROOT;
34216
- return readPiPluginState((0, import_node_os16.homedir)(), env);
34361
+ return readPiPluginState((0, import_node_os17.homedir)(), env);
34217
34362
  },
34218
34363
  healPiPlugin: () => {
34219
34364
  const env = { ...process.env };
34220
34365
  delete env.CLAUDE_PLUGIN_ROOT;
34221
- return healPiPluginRegistration((0, import_node_os16.homedir)(), env);
34366
+ return healPiPluginRegistration((0, import_node_os17.homedir)(), env);
34222
34367
  },
34223
34368
  // #3470: what the SessionStart hook LAST emitted, measured at emission by the session-start verb below.
34224
34369
  // A local record read ? cheap enough for every lane, including the banner.
@@ -34228,17 +34373,17 @@ function mmiDoctorDeps(opts = {}) {
34228
34373
  marketplaceRows: () => {
34229
34374
  try {
34230
34375
  if (detectSurface(process.env) === "codex") return [];
34231
- const home = (0, import_node_os16.homedir)();
34376
+ const home = (0, import_node_os17.homedir)();
34232
34377
  const rows = marketplaceRows(
34233
34378
  MMI_MARKETPLACE_NAME,
34234
- readFileSyncSafe((0, import_node_path39.join)(home, ...KNOWN_MARKETPLACES_RELATIVE), import_node_fs41.readFileSync),
34235
- readFileSyncSafe((0, import_node_path39.join)(home, ".claude", "settings.json"), import_node_fs41.readFileSync),
34379
+ readFileSyncSafe((0, import_node_path40.join)(home, ...KNOWN_MARKETPLACES_RELATIVE), import_node_fs42.readFileSync),
34380
+ readFileSyncSafe((0, import_node_path40.join)(home, ".claude", "settings.json"), import_node_fs42.readFileSync),
34236
34381
  // #3974: this CLI heals these rows, so report mode names the doctor run rather than the hand
34237
34382
  // edit. Unconditional ? it is a fact about mmi-cli, not about the lane this run is on.
34238
34383
  true
34239
34384
  );
34240
34385
  const pending = readMarketplacePinPending(
34241
- (0, import_node_path39.join)(home, ".claude", "plugins", ".mmi-marketplace-pin-pending.json"),
34386
+ (0, import_node_path40.join)(home, ".claude", "plugins", ".mmi-marketplace-pin-pending.json"),
34242
34387
  MMI_MARKETPLACE_NAME
34243
34388
  );
34244
34389
  if (!pending) return rows;
@@ -34262,11 +34407,11 @@ function mmiDoctorDeps(opts = {}) {
34262
34407
  healMarketplacePins: () => {
34263
34408
  try {
34264
34409
  if (detectSurface(process.env) === "codex") return void 0;
34265
- const home = (0, import_node_os16.homedir)();
34410
+ const home = (0, import_node_os17.homedir)();
34266
34411
  const names = [MMI_MARKETPLACE_NAME];
34267
- const result = applyOrgMarketplacePins((0, import_node_path39.join)(home, ...KNOWN_MARKETPLACES_RELATIVE), names);
34412
+ const result = applyOrgMarketplacePins((0, import_node_path40.join)(home, ...KNOWN_MARKETPLACES_RELATIVE), names);
34268
34413
  if (result?.wrote) {
34269
- writeMarketplacePinPending((0, import_node_path39.join)(home, ".claude", "plugins", ".mmi-marketplace-pin-pending.json"), names);
34414
+ writeMarketplacePinPending((0, import_node_path40.join)(home, ".claude", "plugins", ".mmi-marketplace-pin-pending.json"), names);
34270
34415
  }
34271
34416
  return result;
34272
34417
  } catch {
@@ -34282,7 +34427,7 @@ function mmiDoctorDeps(opts = {}) {
34282
34427
  // adopted the generated routing index (MMG-Unlive: `docs/Archive/**` only, no index, no gate.yml) would
34283
34428
  // get a permanent ? demanding an artifact it never asked for.
34284
34429
  docsIndexState: (root) => {
34285
- if (!(0, import_node_fs41.existsSync)((0, import_node_path39.join)(root, DOCS_INDEX_PATH))) return void 0;
34430
+ if (!(0, import_node_fs42.existsSync)((0, import_node_path40.join)(root, DOCS_INDEX_PATH))) return void 0;
34286
34431
  const real = createDocsIndexDeps(root);
34287
34432
  let docs2;
34288
34433
  const listDocs = () => docs2 ??= real.listDocs();
@@ -34291,7 +34436,7 @@ function mmiDoctorDeps(opts = {}) {
34291
34436
  },
34292
34437
  // #4168: working-tree heal — write if drifted, then re-check. Commit remains the operator's step.
34293
34438
  healDocsIndex: (root) => {
34294
- if (!(0, import_node_fs41.existsSync)((0, import_node_path39.join)(root, DOCS_INDEX_PATH))) return { drift: false, docCount: 0 };
34439
+ if (!(0, import_node_fs42.existsSync)((0, import_node_path40.join)(root, DOCS_INDEX_PATH))) return { drift: false, docCount: 0 };
34295
34440
  const real = createDocsIndexDeps(root);
34296
34441
  let docs2;
34297
34442
  const listDocs = () => docs2 ??= real.listDocs();
@@ -34626,19 +34771,19 @@ program2.hook("preAction", async (_thisCommand, actionCommand) => {
34626
34771
  });
34627
34772
  var rules = program2.command("rules").description("org-managed .gitignore delivery");
34628
34773
  rules.command("gitignore").option("--write", "upsert the managed block into .gitignore (default: check only, non-zero exit on drift)").option("--json", "machine-readable output").description("verify (or --write) this repo's org-managed .gitignore block matches the SSOT").action((opts) => {
34629
- const path2 = (0, import_node_path39.join)(process.cwd(), ".gitignore");
34630
- const current = (0, import_node_fs41.existsSync)(path2) ? (0, import_node_fs41.readFileSync)(path2, "utf8") : null;
34774
+ const path2 = (0, import_node_path40.join)(process.cwd(), ".gitignore");
34775
+ const current = (0, import_node_fs42.existsSync)(path2) ? (0, import_node_fs42.readFileSync)(path2, "utf8") : null;
34631
34776
  const plan = planManagedGitignore(current);
34632
34777
  const drift = [...plan.added.map((l) => `+${l}`), ...plan.removed.map((l) => `-${l}`)].join(", ") || "block normalize";
34633
34778
  if (opts.json) {
34634
- if (opts.write && plan.changed) (0, import_node_fs41.writeFileSync)(path2, plan.content, "utf8");
34779
+ if (opts.write && plan.changed) (0, import_node_fs42.writeFileSync)(path2, plan.content, "utf8");
34635
34780
  console.log(JSON.stringify(plan, null, 2));
34636
34781
  if (!opts.write && plan.changed) process.exitCode = 1;
34637
34782
  return;
34638
34783
  }
34639
34784
  if (opts.write) {
34640
34785
  if (plan.changed) {
34641
- (0, import_node_fs41.writeFileSync)(path2, plan.content, "utf8");
34786
+ (0, import_node_fs42.writeFileSync)(path2, plan.content, "utf8");
34642
34787
  console.log(`mmi-cli org rules gitignore: updated .gitignore (${drift})`);
34643
34788
  } else {
34644
34789
  console.log("mmi-cli org rules gitignore: up to date");
@@ -34796,8 +34941,8 @@ gcCmd.option("--dry-run", "show what would be deleted (default)").option("--appl
34796
34941
  if (!Number.isFinite(limit) || limit < 1) return fail("worktree gc: --limit must be a positive integer");
34797
34942
  let root;
34798
34943
  if (o.root !== void 0) {
34799
- root = (0, import_node_path39.resolve)(o.root);
34800
- if (!(0, import_node_fs41.existsSync)(root) || !(0, import_node_fs41.statSync)(root).isDirectory()) return fail(`worktree gc: --root ${o.root} is not a directory`);
34944
+ root = (0, import_node_path40.resolve)(o.root);
34945
+ if (!(0, import_node_fs42.existsSync)(root) || !(0, import_node_fs42.statSync)(root).isDirectory()) return fail(`worktree gc: --root ${o.root} is not a directory`);
34801
34946
  const gcRepoRoot = (await execFileP2("git", ["rev-parse", "--show-toplevel"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim() || process.cwd();
34802
34947
  if (isPathUnderDirectory(gcRepoRoot, root)) {
34803
34948
  return fail(`worktree gc: --root ${root} contains this checkout ? name a worktrees root, not the repo or an ancestor of it`);
@@ -34877,7 +35022,7 @@ async function currentWorktreeRemovalContext(command, force) {
34877
35022
  };
34878
35023
  }
34879
35024
  async function unprovenWorktreeReason(wtPath, repoRoot2) {
34880
- if (!(0, import_node_fs41.existsSync)(wtPath)) return `${wtPath} does not exist on disk`;
35025
+ if (!(0, import_node_fs42.existsSync)(wtPath)) return `${wtPath} does not exist on disk`;
34881
35026
  const porcelain = (await execFileP2("git", ["-C", repoRoot2, "worktree", "list", "--porcelain"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout;
34882
35027
  const registered = parseWorktreePorcelainEntries(porcelain);
34883
35028
  if (!registered.length) {
@@ -34899,26 +35044,26 @@ function makeProvisionDeps(worktreeRoot, quiet, log) {
34899
35044
  function acquireWorktreeSetupLock(worktreeRoot) {
34900
35045
  const lockPath = repoRuntimeStatePath(worktreeRoot, "worktree-setup.lock");
34901
35046
  const take = () => {
34902
- const fd = (0, import_node_fs41.openSync)(lockPath, "wx");
35047
+ const fd = (0, import_node_fs42.openSync)(lockPath, "wx");
34903
35048
  try {
34904
- (0, import_node_fs41.writeSync)(fd, String(Date.now()));
35049
+ (0, import_node_fs42.writeSync)(fd, String(Date.now()));
34905
35050
  } finally {
34906
- (0, import_node_fs41.closeSync)(fd);
35051
+ (0, import_node_fs42.closeSync)(fd);
34907
35052
  }
34908
35053
  return () => {
34909
35054
  try {
34910
- (0, import_node_fs41.rmSync)(lockPath, { force: true });
35055
+ (0, import_node_fs42.rmSync)(lockPath, { force: true });
34911
35056
  } catch {
34912
35057
  }
34913
35058
  };
34914
35059
  };
34915
35060
  try {
34916
- (0, import_node_fs41.mkdirSync)((0, import_node_path39.dirname)(lockPath), { recursive: true });
35061
+ (0, import_node_fs42.mkdirSync)((0, import_node_path40.dirname)(lockPath), { recursive: true });
34917
35062
  return take();
34918
35063
  } catch {
34919
35064
  try {
34920
- if (Date.now() - (0, import_node_fs41.statSync)(lockPath).mtimeMs > WORKTREE_SETUP_LOCK_TTL_MS) {
34921
- (0, import_node_fs41.rmSync)(lockPath, { force: true });
35065
+ if (Date.now() - (0, import_node_fs42.statSync)(lockPath).mtimeMs > WORKTREE_SETUP_LOCK_TTL_MS) {
35066
+ (0, import_node_fs42.rmSync)(lockPath, { force: true });
34922
35067
  return take();
34923
35068
  }
34924
35069
  } catch {
@@ -34944,6 +35089,11 @@ withExamples(mutating(
34944
35089
  const resolvedRepo = await resolveRepo();
34945
35090
  if (!resolvedRepo) return fail("worktree create: could not resolve the repo for the issue ref (run from a repo checkout)");
34946
35091
  selector = parseIssueSelector(target, resolvedRepo);
35092
+ if (selector.repo.toLowerCase() !== resolvedRepo.toLowerCase()) {
35093
+ return fail(
35094
+ `worktree create: issue ${selector.repo}#${selector.number} belongs to ${selector.repo}, but this checkout is ${resolvedRepo} \u2014 re-run from ${selector.repo}'s primary checkout. Refusing to attach a foreign issue branch here (MMI-Hub#4351).`
35095
+ );
35096
+ }
34947
35097
  const slug = o.slug ?? await fetchIssueTitle(selector.repo, selector.number).then((t) => t ? slugifyIssueTitle(t) : "");
34948
35098
  branch = buildNewBranchName(selector.number, slug ?? "");
34949
35099
  if (PROTECTED_BRANCHES2.has(branch)) {
@@ -35057,7 +35207,7 @@ withExamples(mutating(
35057
35207
  appendWorktreeEvent(repoRoot2, { action: "created", command: "worktree create", target: wtPath, branch, actor: owner.actor });
35058
35208
  let lease;
35059
35209
  try {
35060
- await execFileP2("jerv-cli", [
35210
+ await execJervCli([
35061
35211
  "lease",
35062
35212
  "open",
35063
35213
  "--kind",
@@ -35766,7 +35916,7 @@ project.command("set [owner/repo]").description("upsert project META (idempotent
35766
35916
  if (dupe) return fail(`org project set: KEY "${dupe}" was passed to both --var and --set; --set is an alias of --var, so pass each KEY once`);
35767
35917
  if (o.secretsFile) {
35768
35918
  try {
35769
- vars.push(`secrets=${(0, import_node_fs41.readFileSync)(o.secretsFile, "utf8")}`);
35919
+ vars.push(`secrets=${(0, import_node_fs42.readFileSync)(o.secretsFile, "utf8")}`);
35770
35920
  } catch (e) {
35771
35921
  return fail(`org project set: cannot read --secrets-file ${o.secretsFile}: ${e.message}`);
35772
35922
  }
@@ -36520,11 +36670,11 @@ pr.command("view <number>").description("read a PR as structured JSON (merged st
36520
36670
  }
36521
36671
  });
36522
36672
  async function listCiWorkflowPaths(cwd = process.cwd()) {
36523
- const wfDir = (0, import_node_path39.join)(cwd, ".github", "workflows");
36524
- if (!(0, import_node_fs41.existsSync)(wfDir)) return [];
36525
- return (0, import_node_fs41.readdirSync)(wfDir).filter((name) => /\.(ya?ml)$/i.test(name)).filter((name) => {
36673
+ const wfDir = (0, import_node_path40.join)(cwd, ".github", "workflows");
36674
+ if (!(0, import_node_fs42.existsSync)(wfDir)) return [];
36675
+ return (0, import_node_fs42.readdirSync)(wfDir).filter((name) => /\.(ya?ml)$/i.test(name)).filter((name) => {
36526
36676
  try {
36527
- return workflowReportsPrChecks((0, import_node_fs41.readFileSync)((0, import_node_path39.join)(wfDir, name), "utf8"));
36677
+ return workflowReportsPrChecks((0, import_node_fs42.readFileSync)((0, import_node_path40.join)(wfDir, name), "utf8"));
36528
36678
  } catch {
36529
36679
  return true;
36530
36680
  }
@@ -36556,16 +36706,16 @@ function ciAuditDeps() {
36556
36706
  // gate re-seed step is skipped gracefully rather than failing mid-run.
36557
36707
  readSeedFile: (path2) => {
36558
36708
  if (!root) return null;
36559
- const fullPath = (0, import_node_path39.join)(root, path2);
36560
- return (0, import_node_fs41.existsSync)(fullPath) ? (0, import_node_fs41.readFileSync)(fullPath, "utf8") : null;
36709
+ const fullPath = (0, import_node_path40.join)(root, path2);
36710
+ return (0, import_node_fs42.existsSync)(fullPath) ? (0, import_node_fs42.readFileSync)(fullPath, "utf8") : null;
36561
36711
  }
36562
36712
  };
36563
36713
  }
36564
36714
  function hubRoot() {
36565
- const fromPkg = (0, import_node_path39.join)(__dirname, "..", "..");
36715
+ const fromPkg = (0, import_node_path40.join)(__dirname, "..", "..");
36566
36716
  const marker = "skills/bootstrap/seeds/manifest.json";
36567
- if ((0, import_node_fs41.existsSync)((0, import_node_path39.join)(fromPkg, marker))) return fromPkg;
36568
- if ((0, import_node_fs41.existsSync)((0, import_node_path39.join)(process.cwd(), marker))) return process.cwd();
36717
+ if ((0, import_node_fs42.existsSync)((0, import_node_path40.join)(fromPkg, marker))) return fromPkg;
36718
+ if ((0, import_node_fs42.existsSync)((0, import_node_path40.join)(process.cwd(), marker))) return process.cwd();
36569
36719
  return null;
36570
36720
  }
36571
36721
  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) => {
@@ -36877,7 +37027,7 @@ jsonParity(pr.command("merge <number>").description("merge a PR (squash by defau
36877
37027
  localCleanup = await cleanupPrMergeLocalBranch(headRef, {
36878
37028
  beforeWorktrees,
36879
37029
  startingPath,
36880
- pathExists: (p) => (0, import_node_fs41.existsSync)(p),
37030
+ pathExists: (p) => (0, import_node_fs42.existsSync)(p),
36881
37031
  execGit: async (args) => (await execFileP2("git", args, { timeout: GIT_TIMEOUT_MS })).stdout,
36882
37032
  teardownWorktreeStage,
36883
37033
  deferredStore,
@@ -37373,12 +37523,12 @@ access.command("audit").description("audit collaborator roles + train-branch pus
37373
37523
  targets = resolution.targets;
37374
37524
  }
37375
37525
  const derivedMatrix = registryProjects ? accessMatrixFromProjects(registryProjects) : {};
37376
- const fileMatrix = (0, import_node_fs41.existsSync)("access-matrix.json") ? loadAccessMatrix((0, import_node_fs41.readFileSync)("access-matrix.json", "utf8")) : {};
37526
+ const fileMatrix = (0, import_node_fs42.existsSync)("access-matrix.json") ? loadAccessMatrix((0, import_node_fs42.readFileSync)("access-matrix.json", "utf8")) : {};
37377
37527
  const matrix = mergeAccessMatrix(fileMatrix, derivedMatrix);
37378
37528
  const derivedContracts = registryProjects ? dataAccessContractsFromProjects(registryProjects) : { consumers: {} };
37379
- const fileContracts = (0, import_node_fs41.existsSync)("data-access-contracts.json") ? loadDataAccessContracts((0, import_node_fs41.readFileSync)("data-access-contracts.json", "utf8")) : { consumers: {} };
37529
+ const fileContracts = (0, import_node_fs42.existsSync)("data-access-contracts.json") ? loadDataAccessContracts((0, import_node_fs42.readFileSync)("data-access-contracts.json", "utf8")) : { consumers: {} };
37380
37530
  const dataAccess = mergeDataAccessContracts(fileContracts, derivedContracts);
37381
- const sanctioned = (0, import_node_fs41.existsSync)("access-matrix.json") ? loadSanctionedAdmins((0, import_node_fs41.readFileSync)("access-matrix.json", "utf8")) : {};
37531
+ const sanctioned = (0, import_node_fs42.existsSync)("access-matrix.json") ? loadSanctionedAdmins((0, import_node_fs42.readFileSync)("access-matrix.json", "utf8")) : {};
37382
37532
  const report = await auditOrgAccess(targets, deps, matrix, dataAccess, sanctioned);
37383
37533
  console.log(o.json ? JSON.stringify(report, null, 2) : renderAccessReport(report));
37384
37534
  if (!report.ok) process.exitCode = 1;
@@ -37410,16 +37560,16 @@ function directoryBytes(path2) {
37410
37560
  let total = 0;
37411
37561
  let entries;
37412
37562
  try {
37413
- entries = (0, import_node_fs41.readdirSync)(path2, { withFileTypes: true });
37563
+ entries = (0, import_node_fs42.readdirSync)(path2, { withFileTypes: true });
37414
37564
  } catch {
37415
37565
  return 0;
37416
37566
  }
37417
37567
  for (const entry of entries) {
37418
- const child2 = (0, import_node_path39.join)(path2, entry.name);
37568
+ const child2 = (0, import_node_path40.join)(path2, entry.name);
37419
37569
  if (entry.isDirectory()) total += directoryBytes(child2);
37420
37570
  else {
37421
37571
  try {
37422
- total += (0, import_node_fs41.statSync)(child2).size;
37572
+ total += (0, import_node_fs42.statSync)(child2).size;
37423
37573
  } catch {
37424
37574
  }
37425
37575
  }
@@ -37427,25 +37577,25 @@ function directoryBytes(path2) {
37427
37577
  return total;
37428
37578
  }
37429
37579
  function listDirEntries(dir) {
37430
- return (0, import_node_fs41.readdirSync)(dir, { withFileTypes: true }).map((d) => ({ name: d.name, isDirectory: d.isDirectory() }));
37580
+ return (0, import_node_fs42.readdirSync)(dir, { withFileTypes: true }).map((d) => ({ name: d.name, isDirectory: d.isDirectory() }));
37431
37581
  }
37432
37582
  function readInstalledPluginRefs(configRoot) {
37433
37583
  const p = installedPluginsPathForConfig(configRoot);
37434
- if (!(0, import_node_fs41.existsSync)(p)) return [];
37584
+ if (!(0, import_node_fs42.existsSync)(p)) return [];
37435
37585
  try {
37436
- return installedPluginPaths((0, import_node_fs41.readFileSync)(p, "utf8"));
37586
+ return installedPluginPaths((0, import_node_fs42.readFileSync)(p, "utf8"));
37437
37587
  } catch {
37438
37588
  return null;
37439
37589
  }
37440
37590
  }
37441
37591
  function pluginCacheFsDeps(configRoot, dirBytes) {
37442
37592
  return {
37443
- exists: (p) => (0, import_node_fs41.existsSync)(p),
37444
- listVersionDirs: (root) => (0, import_node_fs41.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name),
37593
+ exists: (p) => (0, import_node_fs42.existsSync)(p),
37594
+ listVersionDirs: (root) => (0, import_node_fs42.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name),
37445
37595
  dirBytes,
37446
- listStagingDirs: (root) => (0, import_node_fs41.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => {
37596
+ listStagingDirs: (root) => (0, import_node_fs42.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => {
37447
37597
  try {
37448
- return { name: d.name, mtimeMs: newestMtimeMs((0, import_node_path39.join)(root, d.name), listDirEntries, (p) => (0, import_node_fs41.statSync)(p).mtimeMs) };
37598
+ return { name: d.name, mtimeMs: newestMtimeMs((0, import_node_path40.join)(root, d.name), listDirEntries, (p) => (0, import_node_fs42.statSync)(p).mtimeMs) };
37449
37599
  } catch {
37450
37600
  return { name: d.name, mtimeMs: Date.now() };
37451
37601
  }
@@ -37459,10 +37609,10 @@ function stagingApplyFsGuard(configRoot) {
37459
37609
  return {
37460
37610
  referencedPaths: () => readInstalledPluginRefs(configRoot),
37461
37611
  mtimeMs: (name) => {
37462
- const p = (0, import_node_path39.join)(stagingRoot, name);
37463
- if (!(0, import_node_fs41.existsSync)(p)) return null;
37612
+ const p = (0, import_node_path40.join)(stagingRoot, name);
37613
+ if (!(0, import_node_fs42.existsSync)(p)) return null;
37464
37614
  try {
37465
- return newestMtimeMs(p, listDirEntries, (q) => (0, import_node_fs41.statSync)(q).mtimeMs);
37615
+ return newestMtimeMs(p, listDirEntries, (q) => (0, import_node_fs42.statSync)(q).mtimeMs);
37466
37616
  } catch {
37467
37617
  return null;
37468
37618
  }
@@ -37482,13 +37632,13 @@ program2.command("plugin-prune").description(`prune stale cached MMI plugin vers
37482
37632
  return;
37483
37633
  }
37484
37634
  const plan = buildPluginCachePlan(
37485
- (0, import_node_os16.homedir)(),
37635
+ (0, import_node_os17.homedir)(),
37486
37636
  running,
37487
37637
  pluginCacheFsDeps(configRoot, directoryBytes),
37488
37638
  { withBytes: true, configRoot, includeStaging: surface !== "codex" }
37489
37639
  );
37490
37640
  const anythingToDelete = plan.prune.length > 0 || plan.staging.length > 0;
37491
- const result = o.apply && anythingToDelete ? applyPluginCachePlan(plan, (p) => (0, import_node_fs41.rmSync)(p, { recursive: true, force: true }), stagingApplyFsGuard(configRoot)) : void 0;
37641
+ const result = o.apply && anythingToDelete ? applyPluginCachePlan(plan, (p) => (0, import_node_fs42.rmSync)(p, { recursive: true, force: true }), stagingApplyFsGuard(configRoot)) : void 0;
37492
37642
  const warnings = plan.prune.length > 0 ? [CONCURRENT_SESSION_WARNING] : [];
37493
37643
  if (o.json) console.log(JSON.stringify({ ...plan, warnings, applied: result ?? null }));
37494
37644
  else console.log(renderPluginCachePlan(plan, result));
@@ -37496,7 +37646,7 @@ program2.command("plugin-prune").description(`prune stale cached MMI plugin vers
37496
37646
  });
37497
37647
  function readReleaseCatchupState(path2) {
37498
37648
  try {
37499
- const parsed = JSON.parse((0, import_node_fs41.readFileSync)(path2, "utf8"));
37649
+ const parsed = JSON.parse((0, import_node_fs42.readFileSync)(path2, "utf8"));
37500
37650
  return typeof parsed?.checkedAt === "number" ? parsed : void 0;
37501
37651
  } catch {
37502
37652
  return void 0;
@@ -37504,8 +37654,8 @@ function readReleaseCatchupState(path2) {
37504
37654
  }
37505
37655
  function writeReleaseCatchupState(path2, state) {
37506
37656
  try {
37507
- (0, import_node_fs41.mkdirSync)((0, import_node_path39.dirname)(path2), { recursive: true });
37508
- (0, import_node_fs41.writeFileSync)(path2, `${JSON.stringify(state)}
37657
+ (0, import_node_fs42.mkdirSync)((0, import_node_path40.dirname)(path2), { recursive: true });
37658
+ (0, import_node_fs42.writeFileSync)(path2, `${JSON.stringify(state)}
37509
37659
  `);
37510
37660
  } catch {
37511
37661
  }
@@ -37513,7 +37663,7 @@ function writeReleaseCatchupState(path2, state) {
37513
37663
  program2.command("plugin-release-catchup").description("install a newer released MMI plugin clone non-destructively and re-point the Pi registration (#4297); TTL-gated no-op when current").option("--force", "skip the 24h TTL (acceptance proof / manual run)").option("--quiet", "print only failures (the detached session-start lane)").option("--json", "machine-readable output").action(async (o) => {
37514
37664
  const outcome = await withEnvHealLock(
37515
37665
  "plugin release catch-up",
37516
- () => runReleaseCatchup((0, import_node_os16.homedir)(), process.env, {
37666
+ () => runReleaseCatchup((0, import_node_os17.homedir)(), process.env, {
37517
37667
  fetchReleased: fetchNpmReleasedVersion,
37518
37668
  runClaude: (args, step) => runPluginCli("claude", args, (msg) => {
37519
37669
  if (!o.quiet && !o.json) console.log(msg);
@@ -37529,7 +37679,7 @@ program2.command("plugin-release-catchup").description("install a newer released
37529
37679
  },
37530
37680
  readState: readReleaseCatchupState,
37531
37681
  writeState: writeReleaseCatchupState,
37532
- healRegistration: defaultRegistrationHeal((0, import_node_os16.homedir)(), process.env),
37682
+ healRegistration: defaultRegistrationHeal((0, import_node_os17.homedir)(), process.env),
37533
37683
  now: () => Date.now()
37534
37684
  }, { force: o.force })
37535
37685
  );
@@ -37597,7 +37747,7 @@ program2.command("session-start").description("run the SessionStart verbs (whoam
37597
37747
  spawnDetachedSelf(["worktree", "setup", "--quiet"], { spawn: import_node_child_process19.spawn, execPath: process.execPath, scriptPath: process.argv[1] });
37598
37748
  bannerIo.log(worktreeBanner);
37599
37749
  }
37600
- if (shouldSpawnReleaseCatchup((0, import_node_os16.homedir)(), process.env, readReleaseCatchupState)) {
37750
+ if (shouldSpawnReleaseCatchup((0, import_node_os17.homedir)(), process.env, readReleaseCatchupState)) {
37601
37751
  spawnDetachedSelf(["plugin", "release-catchup", "--quiet"], { spawn: import_node_child_process19.spawn, execPath: process.execPath, scriptPath: process.argv[1] });
37602
37752
  }
37603
37753
  if (isLinkedWorktree(process.cwd())) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mutmutco/cli",
3
- "version": "3.105.2",
3
+ "version": "3.105.4",
4
4
  "description": "MMI Future CLI — the org dev toolbox and shared cross-IDE engine for every registry-declared MMI coding surface.",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",