@mutmutco/cli 3.105.0 → 3.105.3

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 +430 -147
  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 {
@@ -20462,7 +20474,8 @@ async function runHotfixStart(deps, options) {
20462
20474
  }
20463
20475
  notes.push(`cherry-picked ${label} onto ${branch} (from origin/main, -x trailer recorded)`);
20464
20476
  if (deployModel === "hub-serverless") {
20465
- await deps.run("node", ["scripts/release-distribution.mjs", "prepare", version, "--source-commit", "HEAD"]);
20477
+ const durableSource = clean3(await deps.run("git", ["merge-base", "HEAD", "origin/main"]));
20478
+ await deps.run("node", ["scripts/release-distribution.mjs", "prepare", version, "--source-commit", durableSource]);
20466
20479
  const changedFiles = (await deps.run("node", ["scripts/release-distribution.mjs", "changed-files"])).split("\n").map((s) => s.trim()).filter(Boolean);
20467
20480
  await deps.run("git", ["add", "-f", "--", ...changedFiles]);
20468
20481
  const staged = await deps.run("git", ["diff", "--cached", "--name-only"]);
@@ -25439,6 +25452,148 @@ async function runIssueChildren(deps, epic, opts) {
25439
25452
  }
25440
25453
  return out;
25441
25454
  }
25455
+ var FRONTIER_BUCKET_ORDER = {
25456
+ in_flight: 0,
25457
+ partial: 1,
25458
+ ready: 2,
25459
+ landed: 3
25460
+ };
25461
+ function prStateIs(pr2, want) {
25462
+ return String(pr2.state ?? "").toUpperCase() === want;
25463
+ }
25464
+ function isBoardDone(boardStatus) {
25465
+ return /^done$/i.test(String(boardStatus ?? "").trim());
25466
+ }
25467
+ function isBoardInFlight(boardStatus) {
25468
+ return /^(in\s*progress|in\s*review|review|doing)$/i.test(String(boardStatus ?? "").trim());
25469
+ }
25470
+ function classifyFrontierChild(child2) {
25471
+ const mergedPrs = child2.linkedPrs.filter((p) => prStateIs(p, "MERGED"));
25472
+ const openPrs = child2.linkedPrs.filter((p) => prStateIs(p, "OPEN"));
25473
+ const otherPrs = child2.linkedPrs.filter((p) => !prStateIs(p, "MERGED") && !prStateIs(p, "OPEN"));
25474
+ const closed = String(child2.state ?? "").toUpperCase() === "CLOSED";
25475
+ let bucket;
25476
+ if (closed || isBoardDone(child2.boardStatus)) {
25477
+ bucket = "landed";
25478
+ } else if (openPrs.length > 0 || isBoardInFlight(child2.boardStatus)) {
25479
+ bucket = "in_flight";
25480
+ } else if (mergedPrs.length > 0) {
25481
+ bucket = "partial";
25482
+ } else {
25483
+ bucket = "ready";
25484
+ }
25485
+ return {
25486
+ number: child2.number,
25487
+ title: child2.title,
25488
+ state: child2.state,
25489
+ url: child2.url,
25490
+ repo: child2.repo,
25491
+ assignee: child2.assignee,
25492
+ boardStatus: child2.boardStatus,
25493
+ depth: child2.depth,
25494
+ bucket,
25495
+ mergedPrs,
25496
+ openPrs,
25497
+ otherPrs
25498
+ };
25499
+ }
25500
+ function sortFrontierChildren(rows) {
25501
+ return [...rows].sort((a, b) => {
25502
+ const byBucket = FRONTIER_BUCKET_ORDER[a.bucket] - FRONTIER_BUCKET_ORDER[b.bucket];
25503
+ if (byBucket !== 0) return byBucket;
25504
+ return a.number - b.number;
25505
+ });
25506
+ }
25507
+ function buildFrontierReport(epic, children) {
25508
+ const classified = children.map(classifyFrontierChild);
25509
+ const landed = classified.filter((c) => c.bucket === "landed").sort((a, b) => a.number - b.number);
25510
+ const frontier = sortFrontierChildren(classified.filter((c) => c.bucket !== "landed"));
25511
+ const inFlight = frontier.filter((c) => c.bucket === "in_flight").length;
25512
+ const partial = frontier.filter((c) => c.bucket === "partial").length;
25513
+ const ready = frontier.filter((c) => c.bucket === "ready").length;
25514
+ const report = {
25515
+ epic,
25516
+ counts: {
25517
+ total: classified.length,
25518
+ landed: landed.length,
25519
+ frontier: frontier.length,
25520
+ inFlight,
25521
+ partial,
25522
+ ready
25523
+ },
25524
+ landed,
25525
+ frontier,
25526
+ children: classified,
25527
+ summary: ""
25528
+ };
25529
+ report.summary = formatFrontierSummary(report);
25530
+ return report;
25531
+ }
25532
+ function fmtChildLine(c) {
25533
+ const board = c.boardStatus ? ` board=${c.boardStatus}` : "";
25534
+ const merged = c.mergedPrs.length ? ` merged=[${c.mergedPrs.map((p) => `#${p.number}`).join(",")}]` : "";
25535
+ const open2 = c.openPrs.length ? ` open=[${c.openPrs.map((p) => `#${p.number}`).join(",")}]` : "";
25536
+ return ` #${c.number} [${c.bucket}] ${c.title} (${c.state}${board}${merged}${open2})`;
25537
+ }
25538
+ function formatFrontierSummary(report) {
25539
+ const { epic, counts } = report;
25540
+ const lines = [
25541
+ `issue frontier \u2014 ${epic.repo}#${epic.number} ${epic.title} (${epic.state})`,
25542
+ ` ${counts.total} children \xB7 ${counts.landed} landed \xB7 ${counts.frontier} frontier (${counts.inFlight} in-flight, ${counts.partial} partial, ${counts.ready} ready)`
25543
+ ];
25544
+ if (report.frontier.length) {
25545
+ lines.push("frontier:");
25546
+ for (const c of report.frontier) lines.push(fmtChildLine(c));
25547
+ } else {
25548
+ lines.push("frontier: (empty \u2014 every walked child is landed)");
25549
+ }
25550
+ if (report.landed.length) {
25551
+ lines.push("landed:");
25552
+ for (const c of report.landed) lines.push(fmtChildLine(c));
25553
+ }
25554
+ return lines.join("\n");
25555
+ }
25556
+ function frontierEpicGraphqlArgs(owner, name, number) {
25557
+ const query = "query($owner:String!,$name:String!){repository(owner:$owner,name:$name){issue(number:" + number + "){number title state url}}}";
25558
+ return ["api", "graphql", "-f", `query=${query}`, "-f", `owner=${owner}`, "-f", `name=${name}`];
25559
+ }
25560
+ function extractFrontierEpicResponse(resp, repo) {
25561
+ const r = resp ?? {};
25562
+ const issue2 = r.data?.repository?.issue;
25563
+ if (!issue2 || (r.errors ?? []).some((e) => e?.type === "NOT_FOUND")) {
25564
+ throw new QueryReadError("NOT_FOUND", "issue not found");
25565
+ }
25566
+ return {
25567
+ number: Number(issue2.number),
25568
+ title: String(issue2.title ?? ""),
25569
+ state: String(issue2.state ?? ""),
25570
+ url: String(issue2.url ?? ""),
25571
+ repo
25572
+ };
25573
+ }
25574
+ async function runIssueFrontier(deps, epic, opts) {
25575
+ const ref = parseIssueRef(epic);
25576
+ const repo = ref.repo ?? await deps.resolveRepo(void 0);
25577
+ if (!repo) {
25578
+ throw new QueryReadError("BAD_INPUT", `could not resolve repo for #${ref.number} (pass --repo <owner/repo>)`);
25579
+ }
25580
+ const { owner, name } = splitRepo(repo);
25581
+ let headerResp;
25582
+ try {
25583
+ headerResp = await deps.ghJson(frontierEpicGraphqlArgs(owner, name, ref.number), GH_LIST_TIMEOUT_MS);
25584
+ } catch (e) {
25585
+ if (isGhNotFound(e)) {
25586
+ throw new QueryReadError("NOT_FOUND", `#${ref.number} not found in ${repo}`);
25587
+ }
25588
+ throw e;
25589
+ }
25590
+ const epicHeader = extractFrontierEpicResponse(headerResp, repo);
25591
+ const children = await runIssueChildren(deps, `${repo}#${ref.number}`, {
25592
+ recursive: opts.recursive,
25593
+ boardProjectId: opts.boardProjectId
25594
+ });
25595
+ return buildFrontierReport(epicHeader, children);
25596
+ }
25442
25597
  function buildPrListArgs(opts, repo, author) {
25443
25598
  const limit = clampLimit(opts.limit, DEFAULT_LIMIT);
25444
25599
  const state = opts.state ?? "open";
@@ -25615,6 +25770,17 @@ function registerQueryCommands(program3) {
25615
25770
  queryFail("issue children", e);
25616
25771
  }
25617
25772
  });
25773
+ issue2.command("frontier <epic>").description("compute an epic's landed-vs-open frontier from merged PRs + board Status (read-only; never mutates the epic body) \u2014 human summary by default, --json for the structured report").option("--recursive", "walk the full sub-issue tree (bounded depth + total cap)").option("--repo <owner/repo>", "repo for a bare epic ref (defaults to the current repo)").option("--json", "print the structured FrontierReport JSON (includes summary)").action(async (epic, o) => {
25774
+ try {
25775
+ const frontierDeps = { ...deps, resolveRepo: async (r) => deps.resolveRepo(r ?? o.repo) };
25776
+ const boardProjectId = await resolveBoardProjectId(o.repo);
25777
+ const report = await runIssueFrontier(frontierDeps, epic, { recursive: o.recursive, boardProjectId });
25778
+ if (o.json) console.log(JSON.stringify(report, null, 2));
25779
+ else console.log(report.summary);
25780
+ } catch (e) {
25781
+ queryFail("issue frontier", e);
25782
+ }
25783
+ });
25618
25784
  pr2.command("list").description("bounded PR read \u2014 --mine scopes to the viewer's own PRs (resolves the viewer via gh); always prints JSON").option("--mine", "only the caller's own PRs (resolves the viewer via `gh api user`)").addOption(new Option("--state <state>", "open | all").default("open").choices(PR_STATES)).option("--limit <n>", "max PRs to return (capped at 100)", (v) => Number(v), DEFAULT_LIMIT).option("--repo <owner/repo>", "target repo (defaults to the current repo)").option("--json", "machine-readable output (already the default \u2014 accepted for contract uniformity)").action(async (o) => {
25619
25785
  try {
25620
25786
  const state = validateEnum("--state", PR_STATES, o.state, "pr list");
@@ -28025,10 +28191,10 @@ function registerBoardCommands(program3) {
28025
28191
  }
28026
28192
 
28027
28193
  // src/merge-cleanup.ts
28028
- var import_node_fs34 = require("node:fs");
28194
+ var import_node_fs35 = require("node:fs");
28029
28195
  var import_promises8 = require("node:fs/promises");
28030
- var import_node_path33 = require("node:path");
28031
- var import_node_os12 = require("node:os");
28196
+ var import_node_path34 = require("node:path");
28197
+ var import_node_os13 = require("node:os");
28032
28198
  var import_node_child_process17 = require("node:child_process");
28033
28199
 
28034
28200
  // src/board-advance.ts
@@ -28194,6 +28360,117 @@ function makeDeferredWorktreeStore(registryPath, lockOpts = {}) {
28194
28360
  };
28195
28361
  }
28196
28362
 
28363
+ // src/jerv-cli-spawn.ts
28364
+ var import_node_fs34 = require("node:fs");
28365
+ var import_node_os12 = require("node:os");
28366
+ var import_node_path33 = require("node:path");
28367
+ var WIN_NAMES = ["jerv-cli.cmd", "jerv-cli.exe", "jerv-cli"];
28368
+ var POSIX_NAMES = ["jerv-cli"];
28369
+ var JERV_CLI_ENTRY = (0, import_node_path33.join)("node_modules", "@jervaise", "jerv-cli", "dist", "index.cjs");
28370
+ function pathEnvEntries(pathEnv, platform2 = process.platform) {
28371
+ if (platform2 !== "win32") {
28372
+ return pathEnv.split(import_node_path33.delimiter).map((e) => e.trim()).filter(Boolean);
28373
+ }
28374
+ if (pathEnv.includes(";")) {
28375
+ return pathEnv.split(";").map((e) => e.trim()).filter(Boolean);
28376
+ }
28377
+ const looksUnix = pathEnv.startsWith("/") || /(?:^|:)\/[a-zA-Z]\//.test(pathEnv);
28378
+ if (looksUnix && pathEnv.includes(":")) {
28379
+ return pathEnv.split(":").map((e) => e.trim()).filter(Boolean);
28380
+ }
28381
+ return pathEnv.trim() ? [pathEnv.trim()] : [];
28382
+ }
28383
+ function normalizeSpawnPathEntry(entry, platform2 = process.platform) {
28384
+ const trimmed = entry.trim();
28385
+ if (!trimmed) return void 0;
28386
+ if (platform2 !== "win32") return trimmed;
28387
+ const msys = /^\/([a-zA-Z])\/(.*)$/.exec(trimmed.replace(/\\/g, "/"));
28388
+ if (msys) return `${msys[1].toUpperCase()}:\\${msys[2].replace(/\//g, "\\")}`;
28389
+ return trimmed;
28390
+ }
28391
+ function jervCliCandidateDirs(env = process.env, home = (0, import_node_os12.homedir)(), platform2 = process.platform) {
28392
+ const seen = /* @__PURE__ */ new Set();
28393
+ const out = [];
28394
+ const push = (dir) => {
28395
+ if (!dir) return;
28396
+ const key = platform2 === "win32" ? dir.toLowerCase() : dir;
28397
+ if (seen.has(key)) return;
28398
+ seen.add(key);
28399
+ out.push(dir);
28400
+ };
28401
+ for (const entry of pathEnvEntries(env.PATH ?? "", platform2)) {
28402
+ push(normalizeSpawnPathEntry(entry, platform2));
28403
+ }
28404
+ if (platform2 === "win32") {
28405
+ if (env.APPDATA) push((0, import_node_path33.join)(env.APPDATA, "npm"));
28406
+ if (env.LOCALAPPDATA) push((0, import_node_path33.join)(env.LOCALAPPDATA, "npm"));
28407
+ } else {
28408
+ push((0, import_node_path33.join)(home, ".local", "bin"));
28409
+ }
28410
+ return out;
28411
+ }
28412
+ function jervCliCandidatePaths(env = process.env, home = (0, import_node_os12.homedir)(), platform2 = process.platform) {
28413
+ const names = platform2 === "win32" ? WIN_NAMES : POSIX_NAMES;
28414
+ const out = [];
28415
+ for (const dir of jervCliCandidateDirs(env, home, platform2)) {
28416
+ for (const name of names) out.push((0, import_node_path33.join)(dir, name));
28417
+ }
28418
+ return out;
28419
+ }
28420
+ function resolveJervCliPath(env = process.env, home = (0, import_node_os12.homedir)(), platform2 = process.platform, exists = import_node_fs34.existsSync) {
28421
+ for (const candidate of jervCliCandidatePaths(env, home, platform2)) {
28422
+ if (exists(candidate)) return candidate;
28423
+ }
28424
+ return void 0;
28425
+ }
28426
+ function resolveJervCliNodeEntry(shimPath, exists = import_node_fs34.existsSync) {
28427
+ const entry = (0, import_node_path33.join)((0, import_node_path33.dirname)(shimPath), JERV_CLI_ENTRY);
28428
+ return exists(entry) ? entry : void 0;
28429
+ }
28430
+ function jervCliExecFileArgs(args, opts = {}) {
28431
+ const platform2 = opts.platform ?? process.platform;
28432
+ const exists = opts.exists ?? import_node_fs34.existsSync;
28433
+ const resolved = resolveJervCliPath(opts.env ?? process.env, opts.home ?? (0, import_node_os12.homedir)(), platform2, exists);
28434
+ if (resolved) {
28435
+ const entry = resolveJervCliNodeEntry(resolved, exists);
28436
+ if (entry) {
28437
+ return { file: opts.execPath ?? process.execPath, args: [entry, ...args], via: "node-entry" };
28438
+ }
28439
+ }
28440
+ const bin = resolved ?? "jerv-cli";
28441
+ if (platform2 === "win32") {
28442
+ return { file: "cmd.exe", args: ["/c", bin, ...args], via: resolved ? "cmd-shim" : "bare" };
28443
+ }
28444
+ return { file: bin, args: [...args], via: resolved ? "posix" : "bare" };
28445
+ }
28446
+ function formatJervCliSpawnFailure(err, plan, candidates) {
28447
+ const base = (err.stderr?.trim() || err.message.trim()).split("\n")[0] || "spawn failed";
28448
+ const code = err.code;
28449
+ if (code !== "ENOENT" && !/\bENOENT\b/i.test(base)) return base;
28450
+ const tried = candidates.length > 0 ? candidates.join(" | ") : "(no candidates)";
28451
+ return `${base} [via=${plan.via} file=${plan.file}; tried: ${tried}]`;
28452
+ }
28453
+ function isEnoent(err) {
28454
+ const code = err.code;
28455
+ if (code === "ENOENT") return true;
28456
+ return /\bENOENT\b/i.test(err.message ?? "");
28457
+ }
28458
+ function execJervCli(args, options = {}) {
28459
+ const env = options.env ?? process.env;
28460
+ const candidates = jervCliCandidatePaths(env);
28461
+ const plan = jervCliExecFileArgs(args, { env });
28462
+ return execFileP2(plan.file, plan.args, options).catch((err) => {
28463
+ if (!isEnoent(err)) throw err;
28464
+ const wrapped = new Error(formatJervCliSpawnFailure(err, plan, candidates));
28465
+ Object.assign(wrapped, {
28466
+ code: "ENOENT",
28467
+ stderr: err.stderr,
28468
+ cause: err
28469
+ });
28470
+ throw wrapped;
28471
+ });
28472
+ }
28473
+
28197
28474
  // src/merge-cleanup.ts
28198
28475
  var GC_GH_TIMEOUT_MS2 = 2e4;
28199
28476
  async function advanceClosedIssuesToDone2(prNumber, repoOption) {
@@ -28312,7 +28589,8 @@ function assertPrMergeHousekeepingClean(startingPath, context, options = {}) {
28312
28589
  if (verdict.blocked) throw new Error(verdict.reason);
28313
28590
  return housekeeping;
28314
28591
  }
28315
- async function bestEffortLeaseClose(wtPath, exec = (cmd, args) => execFileP2(cmd, args, { timeout: GIT_TIMEOUT_MS })) {
28592
+ var defaultLeaseCloseExec = (_cmd, args) => execJervCli(args, { timeout: GIT_TIMEOUT_MS });
28593
+ async function bestEffortLeaseClose(wtPath, exec = defaultLeaseCloseExec) {
28316
28594
  const step = "close jerv worktree lease";
28317
28595
  try {
28318
28596
  await exec("jerv-cli", ["lease", "close", "--ref", wtPath]);
@@ -28335,7 +28613,7 @@ async function applyGcPlan(plan, remote, opts = {}) {
28335
28613
  );
28336
28614
  const repoRoot2 = (await execFileP2("git", ["rev-parse", "--show-toplevel"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim() || process.cwd();
28337
28615
  const worktreeGitRoot = await currentRepoWorktreeGitRoot(repoRoot2);
28338
- const primaryRepoRoot = worktreeGitRoot ? (0, import_node_path33.dirname)((0, import_node_path33.dirname)(worktreeGitRoot)) : repoRoot2;
28616
+ const primaryRepoRoot = worktreeGitRoot ? (0, import_node_path34.dirname)((0, import_node_path34.dirname)(worktreeGitRoot)) : repoRoot2;
28339
28617
  const gcActor = describeActor({ env: process.env, surface: detectSurface(process.env), cwd: process.cwd() });
28340
28618
  const owners = readWorktreeOwners(primaryRepoRoot);
28341
28619
  const removalNow = Date.now();
@@ -28366,7 +28644,7 @@ async function applyGcPlan(plan, remote, opts = {}) {
28366
28644
  const cleanup = await cleanupPrMergeLocalBranch(branch.branch, {
28367
28645
  beforeWorktrees,
28368
28646
  startingPath: branch.worktreePath,
28369
- pathExists: (p) => (0, import_node_fs34.existsSync)(p),
28647
+ pathExists: (p) => (0, import_node_fs35.existsSync)(p),
28370
28648
  execGit: async (args) => (await execFileP2("git", args, { timeout: GIT_TIMEOUT_MS })).stdout,
28371
28649
  teardownWorktreeStage,
28372
28650
  deferredStore,
@@ -28395,7 +28673,7 @@ async function applyGcPlan(plan, remote, opts = {}) {
28395
28673
  let removalAttempted = false;
28396
28674
  try {
28397
28675
  const cleanupTarget = resolveSafeSiblingWorktreeCleanupTarget(wt.path, siblingRoot, {
28398
- realpath: (path2) => (0, import_node_fs34.realpathSync)(path2)
28676
+ realpath: (path2) => (0, import_node_fs35.realpathSync)(path2)
28399
28677
  });
28400
28678
  if (!cleanupTarget.ok) {
28401
28679
  result.failed.push(`${wt.path}: ${cleanupTarget.reason}`);
@@ -28482,13 +28760,13 @@ async function composeOverrideBodyFile(prNumber, repoArgs, gh) {
28482
28760
  const commits = JSON.parse(raw).commits ?? [];
28483
28761
  const body = squashBodyWithOverride(commits.map((c) => ({ headline: c.messageHeadline ?? "", body: c.messageBody ?? "" })), process.cwd());
28484
28762
  if (!body) return void 0;
28485
- const dir = (0, import_node_fs34.mkdtempSync)((0, import_node_path33.join)((0, import_node_os12.tmpdir)(), "mmi-squash-body-"));
28486
- const path2 = (0, import_node_path33.join)(dir, "body.txt");
28487
- (0, import_node_fs34.writeFileSync)(path2, `${body}
28763
+ const dir = (0, import_node_fs35.mkdtempSync)((0, import_node_path34.join)((0, import_node_os13.tmpdir)(), "mmi-squash-body-"));
28764
+ const path2 = (0, import_node_path34.join)(dir, "body.txt");
28765
+ (0, import_node_fs35.writeFileSync)(path2, `${body}
28488
28766
  `, "utf8");
28489
28767
  return { path: path2, cleanup: () => {
28490
28768
  try {
28491
- (0, import_node_fs34.rmSync)(dir, { recursive: true, force: true });
28769
+ (0, import_node_fs35.rmSync)(dir, { recursive: true, force: true });
28492
28770
  } catch {
28493
28771
  }
28494
28772
  } };
@@ -28610,13 +28888,13 @@ var realWorktreeDirRemover = {
28610
28888
  probe: (p) => {
28611
28889
  let st;
28612
28890
  try {
28613
- st = (0, import_node_fs34.lstatSync)(p);
28891
+ st = (0, import_node_fs35.lstatSync)(p);
28614
28892
  } catch {
28615
28893
  return null;
28616
28894
  }
28617
28895
  if (st.isSymbolicLink()) return "link";
28618
28896
  try {
28619
- (0, import_node_fs34.readlinkSync)(p);
28897
+ (0, import_node_fs35.readlinkSync)(p);
28620
28898
  return "link";
28621
28899
  } catch {
28622
28900
  }
@@ -28624,7 +28902,7 @@ var realWorktreeDirRemover = {
28624
28902
  },
28625
28903
  readdir: (p) => {
28626
28904
  try {
28627
- return (0, import_node_fs34.readdirSync)(p);
28905
+ return (0, import_node_fs35.readdirSync)(p);
28628
28906
  } catch {
28629
28907
  return [];
28630
28908
  }
@@ -28633,9 +28911,9 @@ var realWorktreeDirRemover = {
28633
28911
  // leaving the target); a file symlink with unlink. rmdir first, fall back to unlink.
28634
28912
  detachLink: (p) => {
28635
28913
  try {
28636
- (0, import_node_fs34.rmdirSync)(p);
28914
+ (0, import_node_fs35.rmdirSync)(p);
28637
28915
  } catch {
28638
- (0, import_node_fs34.unlinkSync)(p);
28916
+ (0, import_node_fs35.unlinkSync)(p);
28639
28917
  }
28640
28918
  },
28641
28919
  removeTree: (p) => (0, import_promises8.rm)(p, { recursive: true, force: true, maxRetries: 5, retryDelay: 200 })
@@ -28668,9 +28946,9 @@ async function worktreeHasStageState(worktreePath) {
28668
28946
  }
28669
28947
  }
28670
28948
  function stageStateFileBelongsToWorktree(statePath, worktreePath) {
28671
- if (!(0, import_node_fs34.existsSync)(statePath)) return false;
28949
+ if (!(0, import_node_fs35.existsSync)(statePath)) return false;
28672
28950
  try {
28673
- const state = JSON.parse((0, import_node_fs34.readFileSync)(statePath, "utf8"));
28951
+ const state = JSON.parse((0, import_node_fs35.readFileSync)(statePath, "utf8"));
28674
28952
  const recordedCwd = typeof state.identity?.cwd === "string" ? state.identity.cwd : typeof state.cwd === "string" ? state.cwd : "";
28675
28953
  return Boolean(recordedCwd && isPathUnderDirectory(recordedCwd, worktreePath));
28676
28954
  } catch {
@@ -29001,9 +29279,9 @@ async function checkDocsIndexAtHead(opts, deps) {
29001
29279
  }
29002
29280
 
29003
29281
  // src/worktree-lifecycle-commands.ts
29004
- var import_node_fs35 = require("node:fs");
29282
+ var import_node_fs36 = require("node:fs");
29005
29283
  var import_promises9 = require("node:fs/promises");
29006
- var import_node_path34 = require("node:path");
29284
+ var import_node_path35 = require("node:path");
29007
29285
  var GH_TIMEOUT_MS = 2e4;
29008
29286
  var STALE_PR_LOOKUP_LIMIT = 20;
29009
29287
  var DEFAULT_BASE = "origin/development";
@@ -29150,7 +29428,7 @@ function classifyStaleLeaks(input) {
29150
29428
  var defaultOrphanDirScanDeps = {
29151
29429
  listDirs: (root) => {
29152
29430
  try {
29153
- return (0, import_node_fs35.readdirSync)(root, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => (0, import_node_path34.join)(root, e.name));
29431
+ return (0, import_node_fs36.readdirSync)(root, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => (0, import_node_path35.join)(root, e.name));
29154
29432
  } catch {
29155
29433
  return [];
29156
29434
  }
@@ -29306,13 +29584,13 @@ function registerWorktreeCommands(program3) {
29306
29584
  const detached = headBorn && !symbolicBranch;
29307
29585
  const branch = symbolicBranch || (detached ? "HEAD" : "");
29308
29586
  if (!wtPath || !branch) return fail("worktree land: not inside a git worktree");
29309
- const gitFile = (0, import_node_path34.join)(wtPath, ".git");
29310
- const isLinked = (0, import_node_fs35.existsSync)(gitFile) && (0, import_node_fs35.statSync)(gitFile).isFile();
29587
+ const gitFile = (0, import_node_path35.join)(wtPath, ".git");
29588
+ const isLinked = (0, import_node_fs36.existsSync)(gitFile) && (0, import_node_fs36.statSync)(gitFile).isFile();
29311
29589
  if (apply && !isLinked) {
29312
29590
  return fail("worktree land: run from inside the linked worktree you want to land (this is the primary checkout)");
29313
29591
  }
29314
29592
  const commonDir = (await execFileP2("git", ["rev-parse", "--git-common-dir"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim();
29315
- const primaryCheckout = commonDir ? (0, import_node_path34.dirname)(commonDir) : wtPath;
29593
+ const primaryCheckout = commonDir ? (0, import_node_path35.dirname)(commonDir) : wtPath;
29316
29594
  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);
29317
29595
  const orphan = classifyOrphanedWorktree({
29318
29596
  branch,
@@ -29521,10 +29799,10 @@ async function gatherWorktreeContext() {
29521
29799
  if (s) stages.push({ path: wt.path, port: s.port });
29522
29800
  }
29523
29801
  const worktreeGitRoot = await currentRepoWorktreeGitRoot(repoRoot2);
29524
- const primaryRepoRoot = worktreeGitRoot ? (0, import_node_path34.dirname)((0, import_node_path34.dirname)(worktreeGitRoot)) : repoRoot2;
29802
+ const primaryRepoRoot = worktreeGitRoot ? (0, import_node_path35.dirname)((0, import_node_path35.dirname)(worktreeGitRoot)) : repoRoot2;
29525
29803
  const wtRoot = siblingMmiWorktreesRoot(primaryRepoRoot);
29526
29804
  let orphanDirs = [];
29527
- if ((0, import_node_fs35.existsSync)(wtRoot)) {
29805
+ if ((0, import_node_fs36.existsSync)(wtRoot)) {
29528
29806
  orphanDirs = scanOrphanDirs(wtRoot, worktreeGitRoot, {
29529
29807
  ...defaultOrphanDirScanDeps,
29530
29808
  listDirs: (root) => worktreeScanDirs(root, primaryRepoRoot, defaultOrphanDirScanDeps.listDirs, isRepoCheckoutDir)
@@ -29550,7 +29828,7 @@ ${err.stderr ?? ""}`;
29550
29828
  }
29551
29829
 
29552
29830
  // src/issue-commands.ts
29553
- var import_node_fs36 = require("node:fs");
29831
+ var import_node_fs37 = require("node:fs");
29554
29832
  var import_node_crypto7 = require("node:crypto");
29555
29833
  var ghRunner = async (args, timeoutMs) => (await execFileP2("gh", args, { timeout: timeoutMs })).stdout;
29556
29834
  var ReparentConflictError = class extends Error {
@@ -29568,7 +29846,7 @@ async function editIssue(client, options, deps = {}) {
29568
29846
  const url = `https://github.com/${repo}/issues/${parsed.number}`;
29569
29847
  const patch = {};
29570
29848
  let bodyChanged = false;
29571
- const textDeps = () => deps.textDeps ?? { readFile: (p, e) => Promise.resolve((0, import_node_fs36.readFileSync)(p, e)), readStdin: () => Promise.resolve("") };
29849
+ const textDeps = () => deps.textDeps ?? { readFile: (p, e) => Promise.resolve((0, import_node_fs37.readFileSync)(p, e)), readStdin: () => Promise.resolve("") };
29572
29850
  if (options.titleFile !== void 0) {
29573
29851
  patch.title = await resolveIssueTitle({ title: options.title, titleFile: options.titleFile }, textDeps());
29574
29852
  } else if (options.title !== void 0) {
@@ -30173,7 +30451,7 @@ function extendCreateCommand(issue2, batchAttach) {
30173
30451
  if (opts.batch) {
30174
30452
  let specs;
30175
30453
  try {
30176
- const raw = (0, import_node_fs36.readFileSync)(opts.batch, "utf8");
30454
+ const raw = (0, import_node_fs37.readFileSync)(opts.batch, "utf8");
30177
30455
  specs = JSON.parse(raw);
30178
30456
  if (!Array.isArray(specs)) throw new Error("batch file must contain a JSON array");
30179
30457
  } catch (e) {
@@ -30248,8 +30526,8 @@ ${lines}`, {
30248
30526
  }
30249
30527
 
30250
30528
  // src/train-commands.ts
30251
- var import_node_fs37 = require("node:fs");
30252
- var import_node_path35 = require("node:path");
30529
+ var import_node_fs38 = require("node:fs");
30530
+ var import_node_path36 = require("node:path");
30253
30531
 
30254
30532
  // src/train-status.ts
30255
30533
  function buildTrainStatusReport(input) {
@@ -30289,7 +30567,7 @@ function formatTrainStatus(r) {
30289
30567
  // src/train-commands.ts
30290
30568
  function readRepoVersion() {
30291
30569
  try {
30292
- return JSON.parse((0, import_node_fs37.readFileSync)((0, import_node_path35.join)(process.cwd(), ".claude-plugin", "plugin.json"), "utf8")).version || void 0;
30570
+ return JSON.parse((0, import_node_fs38.readFileSync)((0, import_node_path36.join)(process.cwd(), ".claude-plugin", "plugin.json"), "utf8")).version || void 0;
30293
30571
  } catch {
30294
30572
  return void 0;
30295
30573
  }
@@ -30435,9 +30713,9 @@ function registerDeployCommands(program3) {
30435
30713
  }
30436
30714
 
30437
30715
  // src/discovery-commands.ts
30438
- var import_node_fs38 = require("node:fs");
30439
- var import_node_os13 = require("node:os");
30440
- var import_node_path36 = require("node:path");
30716
+ var import_node_fs39 = require("node:fs");
30717
+ var import_node_os14 = require("node:os");
30718
+ var import_node_path37 = require("node:path");
30441
30719
  var GC_GH_TIMEOUT_MS3 = 2e4;
30442
30720
  async function collectStatus() {
30443
30721
  const repo = await resolveRepo();
@@ -30625,10 +30903,10 @@ async function collectOnboardStatus(opts = {}) {
30625
30903
  else if (top) nextCommand = `mmi-cli board claim ${top.number} # ${top.title}`;
30626
30904
  else nextCommand = "mmi-cli board read \u2014 no claimable items found";
30627
30905
  }
30628
- const home = (0, import_node_os13.homedir)();
30906
+ const home = (0, import_node_os14.homedir)();
30629
30907
  const plugin = onboardPluginGate({
30630
- readKnown: () => readFileSyncSafe((0, import_node_path36.join)(home, ...KNOWN_MARKETPLACES_RELATIVE), import_node_fs38.readFileSync),
30631
- readSettings: () => readFileSyncSafe((0, import_node_path36.join)(home, ".claude", "settings.json"), import_node_fs38.readFileSync)
30908
+ readKnown: () => readFileSyncSafe((0, import_node_path37.join)(home, ...KNOWN_MARKETPLACES_RELATIVE), import_node_fs39.readFileSync),
30909
+ readSettings: () => readFileSyncSafe((0, import_node_path37.join)(home, ".claude", "settings.json"), import_node_fs39.readFileSync)
30632
30910
  });
30633
30911
  return { track, board, registry: registry2, secrets, plugin, estateCli, nextCommand };
30634
30912
  }
@@ -31532,19 +31810,19 @@ function registerSessionReport(program3) {
31532
31810
  }
31533
31811
 
31534
31812
  // src/plugin-release-catchup.ts
31535
- var import_node_fs39 = require("node:fs");
31536
- var import_node_path37 = require("node:path");
31537
- var import_node_os14 = require("node:os");
31813
+ var import_node_fs40 = require("node:fs");
31814
+ var import_node_path38 = require("node:path");
31815
+ var import_node_os15 = require("node:os");
31538
31816
  var RELEASE_CATCHUP_TTL_MS = 24 * 60 * 60 * 1e3;
31539
31817
  var RELEASE_CATCHUP_DISABLE_ENV = "MMI_NO_RELEASE_CATCHUP";
31540
31818
  function releaseCatchupStatePath(env = process.env) {
31541
31819
  if (env.MMI_RELEASE_CATCHUP_STATE) return env.MMI_RELEASE_CATCHUP_STATE;
31542
31820
  if (process.platform === "win32") {
31543
- const base2 = env.LOCALAPPDATA || (0, import_node_path37.join)((0, import_node_os14.homedir)(), "AppData", "Local");
31544
- return (0, import_node_path37.join)(base2, "MMI Future", "mmi-cli", "release-catchup.json");
31821
+ const base2 = env.LOCALAPPDATA || (0, import_node_path38.join)((0, import_node_os15.homedir)(), "AppData", "Local");
31822
+ return (0, import_node_path38.join)(base2, "MMI Future", "mmi-cli", "release-catchup.json");
31545
31823
  }
31546
- const base = env.XDG_STATE_HOME || (0, import_node_path37.join)((0, import_node_os14.homedir)(), ".local", "state");
31547
- return (0, import_node_path37.join)(base, "mmi-cli", "release-catchup.json");
31824
+ const base = env.XDG_STATE_HOME || (0, import_node_path38.join)((0, import_node_os15.homedir)(), ".local", "state");
31825
+ return (0, import_node_path38.join)(base, "mmi-cli", "release-catchup.json");
31548
31826
  }
31549
31827
  function releaseCatchupDue(state, now, force = false) {
31550
31828
  if (force) return true;
@@ -31554,7 +31832,7 @@ function releaseCatchupDue(state, now, force = false) {
31554
31832
  function newestCachedPluginVersion(home) {
31555
31833
  let names;
31556
31834
  try {
31557
- names = (0, import_node_fs39.readdirSync)(pluginCacheRoot(home));
31835
+ names = (0, import_node_fs40.readdirSync)(pluginCacheRoot(home));
31558
31836
  } catch {
31559
31837
  return void 0;
31560
31838
  }
@@ -31562,15 +31840,15 @@ function newestCachedPluginVersion(home) {
31562
31840
  }
31563
31841
  function marketplaceClonePath(home) {
31564
31842
  try {
31565
- const parsed = JSON.parse((0, import_node_fs39.readFileSync)((0, import_node_path37.join)(home, ".claude", "plugins", "known_marketplaces.json"), "utf8"));
31843
+ const parsed = JSON.parse((0, import_node_fs40.readFileSync)((0, import_node_path38.join)(home, ".claude", "plugins", "known_marketplaces.json"), "utf8"));
31566
31844
  if (parsed.mutmutco?.installLocation) return parsed.mutmutco.installLocation;
31567
31845
  } catch {
31568
31846
  }
31569
- return (0, import_node_path37.join)(home, ".claude", "plugins", "marketplaces", "mutmutco");
31847
+ return (0, import_node_path38.join)(home, ".claude", "plugins", "marketplaces", "mutmutco");
31570
31848
  }
31571
31849
  function readCatalogVersion(home) {
31572
31850
  try {
31573
- const parsed = JSON.parse((0, import_node_fs39.readFileSync)((0, import_node_path37.join)(marketplaceClonePath(home), ".claude-plugin", "marketplace.json"), "utf8"));
31851
+ const parsed = JSON.parse((0, import_node_fs40.readFileSync)((0, import_node_path38.join)(marketplaceClonePath(home), ".claude-plugin", "marketplace.json"), "utf8"));
31574
31852
  return parsed.plugins?.find((p) => p.name === "mmi")?.version;
31575
31853
  } catch {
31576
31854
  return void 0;
@@ -31578,7 +31856,7 @@ function readCatalogVersion(home) {
31578
31856
  }
31579
31857
  function readMmiInstallRecord(home) {
31580
31858
  try {
31581
- const parsed = JSON.parse((0, import_node_fs39.readFileSync)((0, import_node_path37.join)(home, ".claude", "plugins", "installed_plugins.json"), "utf8"));
31859
+ const parsed = JSON.parse((0, import_node_fs40.readFileSync)((0, import_node_path38.join)(home, ".claude", "plugins", "installed_plugins.json"), "utf8"));
31582
31860
  const record = parsed.plugins?.["mmi@mutmutco"]?.[0];
31583
31861
  return record?.version ? { version: record.version, gitCommitSha: record.gitCommitSha } : void 0;
31584
31862
  } catch {
@@ -31587,7 +31865,7 @@ function readMmiInstallRecord(home) {
31587
31865
  }
31588
31866
  async function runReleaseCatchup(home, env, deps, opts = {}) {
31589
31867
  if (env[RELEASE_CATCHUP_DISABLE_ENV]) return { ok: true, skipped: true, detail: `disabled via ${RELEASE_CATCHUP_DISABLE_ENV}` };
31590
- 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" };
31868
+ 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" };
31591
31869
  const statePath = releaseCatchupStatePath(env);
31592
31870
  const state = deps.readState(statePath);
31593
31871
  if (!releaseCatchupDue(state, deps.now(), opts.force)) {
@@ -31612,8 +31890,8 @@ async function runReleaseCatchup(home, env, deps, opts = {}) {
31612
31890
  return { ok: false, detail: `released ${latest} but the install record could not be cleared \u2014 nothing changed (record still ${prior.version})` };
31613
31891
  }
31614
31892
  const installed = await deps.runClaude(["plugin", "install", "mmi@mutmutco"], "claude plugin install mmi@mutmutco");
31615
- const payload = (0, import_node_path37.join)(pluginCacheRoot(home), latest, ".pi-plugin");
31616
- if (!installed || !(0, import_node_fs39.existsSync)(payload)) {
31893
+ const payload = (0, import_node_path38.join)(pluginCacheRoot(home), latest, ".pi-plugin");
31894
+ if (!installed || !(0, import_node_fs40.existsSync)(payload)) {
31617
31895
  const why = installed ? `install of ${latest} did not produce a verifiable .pi-plugin payload` : `install of ${latest} failed`;
31618
31896
  if (!prior) return { ok: false, detail: `${why}; no prior record to restore` };
31619
31897
  const rollback = await restorePriorRecord(home, prior, deps);
@@ -31641,7 +31919,7 @@ async function restorePriorRecord(home, prior, deps) {
31641
31919
  }
31642
31920
  function shouldSpawnReleaseCatchup(home, env, readState2, now = Date.now()) {
31643
31921
  if (env[RELEASE_CATCHUP_DISABLE_ENV]) return false;
31644
- if (!(0, import_node_fs39.existsSync)(pluginCacheRoot(home))) return false;
31922
+ if (!(0, import_node_fs40.existsSync)(pluginCacheRoot(home))) return false;
31645
31923
  return releaseCatchupDue(readState2(releaseCatchupStatePath(env)), now);
31646
31924
  }
31647
31925
  function defaultRegistrationHeal(home, env) {
@@ -33687,17 +33965,17 @@ function parseOriginRepo(remoteUrl) {
33687
33965
  }
33688
33966
  function ghHostsConfigPath(env, platform2) {
33689
33967
  const sep3 = platform2 === "win32" ? "\\" : "/";
33690
- const join35 = (...parts) => parts.join(sep3);
33968
+ const join36 = (...parts) => parts.join(sep3);
33691
33969
  const explicit = env.GH_CONFIG_DIR?.trim();
33692
- if (explicit) return join35(explicit, "hosts.yml");
33970
+ if (explicit) return join36(explicit, "hosts.yml");
33693
33971
  if (platform2 === "win32") {
33694
33972
  const appData = (env.AppData ?? env.APPDATA)?.trim();
33695
- return appData ? join35(appData, "GitHub CLI", "hosts.yml") : void 0;
33973
+ return appData ? join36(appData, "GitHub CLI", "hosts.yml") : void 0;
33696
33974
  }
33697
33975
  const xdg = env.XDG_CONFIG_HOME?.trim();
33698
- if (xdg) return join35(xdg, "gh", "hosts.yml");
33976
+ if (xdg) return join36(xdg, "gh", "hosts.yml");
33699
33977
  const home = env.HOME?.trim();
33700
- return home ? join35(home, ".config", "gh", "hosts.yml") : void 0;
33978
+ return home ? join36(home, ".config", "gh", "hosts.yml") : void 0;
33701
33979
  }
33702
33980
  function parseGhHostsAccounts(yaml, host = "github.com") {
33703
33981
  let hostIndent = null;
@@ -33747,9 +34025,9 @@ function ghAccountCaveat(announcedLogin, accounts) {
33747
34025
  }
33748
34026
 
33749
34027
  // src/doctor-io.ts
33750
- var import_node_fs40 = require("node:fs");
33751
- var import_node_os15 = require("node:os");
33752
- var import_node_path38 = require("node:path");
34028
+ var import_node_fs41 = require("node:fs");
34029
+ var import_node_os16 = require("node:os");
34030
+ var import_node_path39 = require("node:path");
33753
34031
  var import_node_child_process18 = require("node:child_process");
33754
34032
  var import_node_util8 = require("node:util");
33755
34033
  var execFileP6 = (0, import_node_util8.promisify)(import_node_child_process18.execFile);
@@ -33757,7 +34035,7 @@ var MMI_PLUGIN_ID2 = "mmi@mutmutco";
33757
34035
  function installedClaudePluginVersion() {
33758
34036
  try {
33759
34037
  const file = JSON.parse(
33760
- (0, import_node_fs40.readFileSync)((0, import_node_path38.join)((0, import_node_os15.homedir)(), ".claude", "plugins", "installed_plugins.json"), "utf8")
34038
+ (0, import_node_fs41.readFileSync)((0, import_node_path39.join)((0, import_node_os16.homedir)(), ".claude", "plugins", "installed_plugins.json"), "utf8")
33761
34039
  );
33762
34040
  const versions = (file.plugins?.[MMI_PLUGIN_ID2] ?? []).map((r) => r.version).filter((v) => Boolean(v));
33763
34041
  if (versions.length === 0) return void 0;
@@ -33768,7 +34046,7 @@ function installedClaudePluginVersion() {
33768
34046
  }
33769
34047
  function manifestVersion(path2) {
33770
34048
  try {
33771
- const manifest = JSON.parse((0, import_node_fs40.readFileSync)(path2, "utf8"));
34049
+ const manifest = JSON.parse((0, import_node_fs41.readFileSync)(path2, "utf8"));
33772
34050
  return typeof manifest.version === "string" && manifest.version.trim() ? manifest.version.trim() : void 0;
33773
34051
  } catch {
33774
34052
  return void 0;
@@ -33778,22 +34056,22 @@ function installedSurfacePluginVersion(surface) {
33778
34056
  const token = surfaceToken(surface);
33779
34057
  if (token === "kilo") {
33780
34058
  try {
33781
- const stamp = (0, import_node_fs40.readFileSync)((0, import_node_path38.join)((0, import_node_os15.homedir)(), ".kilo", ".mmi-kilo-version"), "utf8").trim();
34059
+ const stamp = (0, import_node_fs41.readFileSync)((0, import_node_path39.join)((0, import_node_os16.homedir)(), ".kilo", ".mmi-kilo-version"), "utf8").trim();
33782
34060
  return stamp || void 0;
33783
34061
  } catch {
33784
34062
  return void 0;
33785
34063
  }
33786
34064
  }
33787
34065
  if (token === "cursor") {
33788
- return manifestVersion((0, import_node_path38.join)(cursorLocalPluginRoot(), ".cursor-plugin", "plugin.json"));
34066
+ return manifestVersion((0, import_node_path39.join)(cursorLocalPluginRoot(), ".cursor-plugin", "plugin.json"));
33789
34067
  }
33790
34068
  if (token === "jervcode") {
33791
34069
  const entry = mmiPiWrapperEntry();
33792
34070
  if (!entry) return void 0;
33793
- return manifestVersion((0, import_node_path38.join)(decodeURIComponent(entry.replace(/^file:\/\/\/?/, "")), "package.json"));
34071
+ return manifestVersion((0, import_node_path39.join)(decodeURIComponent(entry.replace(/^file:\/\/\/?/, "")), "package.json"));
33794
34072
  }
33795
34073
  if (token === "kimi") {
33796
- return manifestVersion((0, import_node_path38.join)(surfaceConfigRoot(surface), "plugins", "managed", "mmi", ".kimi-plugin", "plugin.json"));
34074
+ return manifestVersion((0, import_node_path39.join)(surfaceConfigRoot(surface), "plugins", "managed", "mmi", ".kimi-plugin", "plugin.json"));
33797
34075
  }
33798
34076
  if (token === "claude") return installedClaudePluginVersion();
33799
34077
  if (token !== "codex") return void 0;
@@ -33831,13 +34109,13 @@ function worktreeRootSync() {
33831
34109
  }
33832
34110
  var gitignorePath = () => {
33833
34111
  const root = worktreeRootSync();
33834
- return root === null ? null : (0, import_node_path38.join)(root, ".gitignore");
34112
+ return root === null ? null : (0, import_node_path39.join)(root, ".gitignore");
33835
34113
  };
33836
34114
  function readGitignore() {
33837
34115
  const path2 = gitignorePath();
33838
34116
  if (path2 === null) return null;
33839
34117
  try {
33840
- return (0, import_node_fs40.readFileSync)(path2, "utf8");
34118
+ return (0, import_node_fs41.readFileSync)(path2, "utf8");
33841
34119
  } catch {
33842
34120
  return null;
33843
34121
  }
@@ -33846,7 +34124,7 @@ function writeGitignore(content) {
33846
34124
  const path2 = gitignorePath();
33847
34125
  if (path2 === null) return false;
33848
34126
  try {
33849
- (0, import_node_fs40.writeFileSync)(path2, content, "utf8");
34127
+ (0, import_node_fs41.writeFileSync)(path2, content, "utf8");
33850
34128
  return true;
33851
34129
  } catch {
33852
34130
  return false;
@@ -33870,7 +34148,7 @@ async function repoRoot() {
33870
34148
  }
33871
34149
  function hasRepoLocalWorktrees() {
33872
34150
  const root = worktreeRootSync();
33873
- return root !== null && (0, import_node_fs40.existsSync)((0, import_node_path38.join)(root, ".worktrees"));
34151
+ return root !== null && (0, import_node_fs41.existsSync)((0, import_node_path39.join)(root, ".worktrees"));
33874
34152
  }
33875
34153
 
33876
34154
  // src/index.ts
@@ -33889,8 +34167,8 @@ ${r.stderr ?? ""}`).catch(() => "");
33889
34167
  function ghMultiAccountCaveat(announcedLogin) {
33890
34168
  try {
33891
34169
  const hostsPath = ghHostsConfigPath(process.env, process.platform);
33892
- if (!hostsPath || !(0, import_node_fs41.existsSync)(hostsPath)) return void 0;
33893
- return ghAccountCaveat(announcedLogin, parseGhHostsAccounts((0, import_node_fs41.readFileSync)(hostsPath, "utf8")));
34170
+ if (!hostsPath || !(0, import_node_fs42.existsSync)(hostsPath)) return void 0;
34171
+ return ghAccountCaveat(announcedLogin, parseGhHostsAccounts((0, import_node_fs42.readFileSync)(hostsPath, "utf8")));
33894
34172
  } catch {
33895
34173
  return void 0;
33896
34174
  }
@@ -33898,12 +34176,12 @@ function ghMultiAccountCaveat(announcedLogin) {
33898
34176
  var ENV_HEAL_LOCK_STALE_MS = 10 * 6e4;
33899
34177
  var ENV_HEAL_LOCK_MAX_WAIT_MS = 2 * 6e4;
33900
34178
  function envHealLockPath(home) {
33901
- return (0, import_node_path39.join)(home, ".claude", "plugins", ".mmi-env-heal.lock");
34179
+ return (0, import_node_path40.join)(home, ".claude", "plugins", ".mmi-env-heal.lock");
33902
34180
  }
33903
34181
  async function withEnvHealLock(what, run) {
33904
34182
  try {
33905
34183
  return await withFileLock(
33906
- envHealLockPath((0, import_node_os16.homedir)()),
34184
+ envHealLockPath((0, import_node_os17.homedir)()),
33907
34185
  { staleMs: ENV_HEAL_LOCK_STALE_MS, maxWaitMs: ENV_HEAL_LOCK_MAX_WAIT_MS, label: "mmi env-heal lock" },
33908
34186
  run
33909
34187
  );
@@ -34000,7 +34278,7 @@ function mmiDoctorDeps(opts = {}) {
34000
34278
  const configRoot = surfaceConfigRoot(surface);
34001
34279
  const running = surface === "codex" ? installedActivePluginVersion(surface) : runningPluginVersion(process.env, resolveClientVersion());
34002
34280
  const plan = buildPluginCachePlan(
34003
- (0, import_node_os16.homedir)(),
34281
+ (0, import_node_os17.homedir)(),
34004
34282
  running,
34005
34283
  pluginCacheFsDeps(configRoot, () => 0),
34006
34284
  { configRoot, includeStaging: surface !== "codex" }
@@ -34024,14 +34302,14 @@ function mmiDoctorDeps(opts = {}) {
34024
34302
  const running = surface === "codex" ? installedActivePluginVersion(surface) : runningPluginVersion(process.env, resolveClientVersion());
34025
34303
  const installed = installedActivePluginVersion(surface);
34026
34304
  const plan = buildPluginCachePlan(
34027
- (0, import_node_os16.homedir)(),
34305
+ (0, import_node_os17.homedir)(),
34028
34306
  running,
34029
34307
  pluginCacheFsDeps(configRoot, () => 0),
34030
34308
  { configRoot, includeStaging: surface !== "codex", installedVersion: installed }
34031
34309
  );
34032
34310
  const result = applyPluginCachePlan(
34033
34311
  plan,
34034
- (p) => (0, import_node_fs41.rmSync)(p, { recursive: true }),
34312
+ (p) => (0, import_node_fs42.rmSync)(p, { recursive: true }),
34035
34313
  stagingApplyFsGuard(configRoot)
34036
34314
  );
34037
34315
  return {
@@ -34059,12 +34337,12 @@ function mmiDoctorDeps(opts = {}) {
34059
34337
  piPluginState: () => {
34060
34338
  const env = { ...process.env };
34061
34339
  delete env.CLAUDE_PLUGIN_ROOT;
34062
- return readPiPluginState((0, import_node_os16.homedir)(), env);
34340
+ return readPiPluginState((0, import_node_os17.homedir)(), env);
34063
34341
  },
34064
34342
  healPiPlugin: () => {
34065
34343
  const env = { ...process.env };
34066
34344
  delete env.CLAUDE_PLUGIN_ROOT;
34067
- return healPiPluginRegistration((0, import_node_os16.homedir)(), env);
34345
+ return healPiPluginRegistration((0, import_node_os17.homedir)(), env);
34068
34346
  },
34069
34347
  // #3470: what the SessionStart hook LAST emitted, measured at emission by the session-start verb below.
34070
34348
  // A local record read ? cheap enough for every lane, including the banner.
@@ -34074,17 +34352,17 @@ function mmiDoctorDeps(opts = {}) {
34074
34352
  marketplaceRows: () => {
34075
34353
  try {
34076
34354
  if (detectSurface(process.env) === "codex") return [];
34077
- const home = (0, import_node_os16.homedir)();
34355
+ const home = (0, import_node_os17.homedir)();
34078
34356
  const rows = marketplaceRows(
34079
34357
  MMI_MARKETPLACE_NAME,
34080
- readFileSyncSafe((0, import_node_path39.join)(home, ...KNOWN_MARKETPLACES_RELATIVE), import_node_fs41.readFileSync),
34081
- readFileSyncSafe((0, import_node_path39.join)(home, ".claude", "settings.json"), import_node_fs41.readFileSync),
34358
+ readFileSyncSafe((0, import_node_path40.join)(home, ...KNOWN_MARKETPLACES_RELATIVE), import_node_fs42.readFileSync),
34359
+ readFileSyncSafe((0, import_node_path40.join)(home, ".claude", "settings.json"), import_node_fs42.readFileSync),
34082
34360
  // #3974: this CLI heals these rows, so report mode names the doctor run rather than the hand
34083
34361
  // edit. Unconditional ? it is a fact about mmi-cli, not about the lane this run is on.
34084
34362
  true
34085
34363
  );
34086
34364
  const pending = readMarketplacePinPending(
34087
- (0, import_node_path39.join)(home, ".claude", "plugins", ".mmi-marketplace-pin-pending.json"),
34365
+ (0, import_node_path40.join)(home, ".claude", "plugins", ".mmi-marketplace-pin-pending.json"),
34088
34366
  MMI_MARKETPLACE_NAME
34089
34367
  );
34090
34368
  if (!pending) return rows;
@@ -34108,11 +34386,11 @@ function mmiDoctorDeps(opts = {}) {
34108
34386
  healMarketplacePins: () => {
34109
34387
  try {
34110
34388
  if (detectSurface(process.env) === "codex") return void 0;
34111
- const home = (0, import_node_os16.homedir)();
34389
+ const home = (0, import_node_os17.homedir)();
34112
34390
  const names = [MMI_MARKETPLACE_NAME];
34113
- const result = applyOrgMarketplacePins((0, import_node_path39.join)(home, ...KNOWN_MARKETPLACES_RELATIVE), names);
34391
+ const result = applyOrgMarketplacePins((0, import_node_path40.join)(home, ...KNOWN_MARKETPLACES_RELATIVE), names);
34114
34392
  if (result?.wrote) {
34115
- writeMarketplacePinPending((0, import_node_path39.join)(home, ".claude", "plugins", ".mmi-marketplace-pin-pending.json"), names);
34393
+ writeMarketplacePinPending((0, import_node_path40.join)(home, ".claude", "plugins", ".mmi-marketplace-pin-pending.json"), names);
34116
34394
  }
34117
34395
  return result;
34118
34396
  } catch {
@@ -34128,7 +34406,7 @@ function mmiDoctorDeps(opts = {}) {
34128
34406
  // adopted the generated routing index (MMG-Unlive: `docs/Archive/**` only, no index, no gate.yml) would
34129
34407
  // get a permanent ? demanding an artifact it never asked for.
34130
34408
  docsIndexState: (root) => {
34131
- if (!(0, import_node_fs41.existsSync)((0, import_node_path39.join)(root, DOCS_INDEX_PATH))) return void 0;
34409
+ if (!(0, import_node_fs42.existsSync)((0, import_node_path40.join)(root, DOCS_INDEX_PATH))) return void 0;
34132
34410
  const real = createDocsIndexDeps(root);
34133
34411
  let docs2;
34134
34412
  const listDocs = () => docs2 ??= real.listDocs();
@@ -34137,7 +34415,7 @@ function mmiDoctorDeps(opts = {}) {
34137
34415
  },
34138
34416
  // #4168: working-tree heal — write if drifted, then re-check. Commit remains the operator's step.
34139
34417
  healDocsIndex: (root) => {
34140
- if (!(0, import_node_fs41.existsSync)((0, import_node_path39.join)(root, DOCS_INDEX_PATH))) return { drift: false, docCount: 0 };
34418
+ if (!(0, import_node_fs42.existsSync)((0, import_node_path40.join)(root, DOCS_INDEX_PATH))) return { drift: false, docCount: 0 };
34141
34419
  const real = createDocsIndexDeps(root);
34142
34420
  let docs2;
34143
34421
  const listDocs = () => docs2 ??= real.listDocs();
@@ -34472,19 +34750,19 @@ program2.hook("preAction", async (_thisCommand, actionCommand) => {
34472
34750
  });
34473
34751
  var rules = program2.command("rules").description("org-managed .gitignore delivery");
34474
34752
  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) => {
34475
- const path2 = (0, import_node_path39.join)(process.cwd(), ".gitignore");
34476
- const current = (0, import_node_fs41.existsSync)(path2) ? (0, import_node_fs41.readFileSync)(path2, "utf8") : null;
34753
+ const path2 = (0, import_node_path40.join)(process.cwd(), ".gitignore");
34754
+ const current = (0, import_node_fs42.existsSync)(path2) ? (0, import_node_fs42.readFileSync)(path2, "utf8") : null;
34477
34755
  const plan = planManagedGitignore(current);
34478
34756
  const drift = [...plan.added.map((l) => `+${l}`), ...plan.removed.map((l) => `-${l}`)].join(", ") || "block normalize";
34479
34757
  if (opts.json) {
34480
- if (opts.write && plan.changed) (0, import_node_fs41.writeFileSync)(path2, plan.content, "utf8");
34758
+ if (opts.write && plan.changed) (0, import_node_fs42.writeFileSync)(path2, plan.content, "utf8");
34481
34759
  console.log(JSON.stringify(plan, null, 2));
34482
34760
  if (!opts.write && plan.changed) process.exitCode = 1;
34483
34761
  return;
34484
34762
  }
34485
34763
  if (opts.write) {
34486
34764
  if (plan.changed) {
34487
- (0, import_node_fs41.writeFileSync)(path2, plan.content, "utf8");
34765
+ (0, import_node_fs42.writeFileSync)(path2, plan.content, "utf8");
34488
34766
  console.log(`mmi-cli org rules gitignore: updated .gitignore (${drift})`);
34489
34767
  } else {
34490
34768
  console.log("mmi-cli org rules gitignore: up to date");
@@ -34642,8 +34920,8 @@ gcCmd.option("--dry-run", "show what would be deleted (default)").option("--appl
34642
34920
  if (!Number.isFinite(limit) || limit < 1) return fail("worktree gc: --limit must be a positive integer");
34643
34921
  let root;
34644
34922
  if (o.root !== void 0) {
34645
- root = (0, import_node_path39.resolve)(o.root);
34646
- 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`);
34923
+ root = (0, import_node_path40.resolve)(o.root);
34924
+ 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`);
34647
34925
  const gcRepoRoot = (await execFileP2("git", ["rev-parse", "--show-toplevel"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim() || process.cwd();
34648
34926
  if (isPathUnderDirectory(gcRepoRoot, root)) {
34649
34927
  return fail(`worktree gc: --root ${root} contains this checkout ? name a worktrees root, not the repo or an ancestor of it`);
@@ -34723,7 +35001,7 @@ async function currentWorktreeRemovalContext(command, force) {
34723
35001
  };
34724
35002
  }
34725
35003
  async function unprovenWorktreeReason(wtPath, repoRoot2) {
34726
- if (!(0, import_node_fs41.existsSync)(wtPath)) return `${wtPath} does not exist on disk`;
35004
+ if (!(0, import_node_fs42.existsSync)(wtPath)) return `${wtPath} does not exist on disk`;
34727
35005
  const porcelain = (await execFileP2("git", ["-C", repoRoot2, "worktree", "list", "--porcelain"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout;
34728
35006
  const registered = parseWorktreePorcelainEntries(porcelain);
34729
35007
  if (!registered.length) {
@@ -34745,26 +35023,26 @@ function makeProvisionDeps(worktreeRoot, quiet, log) {
34745
35023
  function acquireWorktreeSetupLock(worktreeRoot) {
34746
35024
  const lockPath = repoRuntimeStatePath(worktreeRoot, "worktree-setup.lock");
34747
35025
  const take = () => {
34748
- const fd = (0, import_node_fs41.openSync)(lockPath, "wx");
35026
+ const fd = (0, import_node_fs42.openSync)(lockPath, "wx");
34749
35027
  try {
34750
- (0, import_node_fs41.writeSync)(fd, String(Date.now()));
35028
+ (0, import_node_fs42.writeSync)(fd, String(Date.now()));
34751
35029
  } finally {
34752
- (0, import_node_fs41.closeSync)(fd);
35030
+ (0, import_node_fs42.closeSync)(fd);
34753
35031
  }
34754
35032
  return () => {
34755
35033
  try {
34756
- (0, import_node_fs41.rmSync)(lockPath, { force: true });
35034
+ (0, import_node_fs42.rmSync)(lockPath, { force: true });
34757
35035
  } catch {
34758
35036
  }
34759
35037
  };
34760
35038
  };
34761
35039
  try {
34762
- (0, import_node_fs41.mkdirSync)((0, import_node_path39.dirname)(lockPath), { recursive: true });
35040
+ (0, import_node_fs42.mkdirSync)((0, import_node_path40.dirname)(lockPath), { recursive: true });
34763
35041
  return take();
34764
35042
  } catch {
34765
35043
  try {
34766
- if (Date.now() - (0, import_node_fs41.statSync)(lockPath).mtimeMs > WORKTREE_SETUP_LOCK_TTL_MS) {
34767
- (0, import_node_fs41.rmSync)(lockPath, { force: true });
35044
+ if (Date.now() - (0, import_node_fs42.statSync)(lockPath).mtimeMs > WORKTREE_SETUP_LOCK_TTL_MS) {
35045
+ (0, import_node_fs42.rmSync)(lockPath, { force: true });
34768
35046
  return take();
34769
35047
  }
34770
35048
  } catch {
@@ -34790,6 +35068,11 @@ withExamples(mutating(
34790
35068
  const resolvedRepo = await resolveRepo();
34791
35069
  if (!resolvedRepo) return fail("worktree create: could not resolve the repo for the issue ref (run from a repo checkout)");
34792
35070
  selector = parseIssueSelector(target, resolvedRepo);
35071
+ if (selector.repo.toLowerCase() !== resolvedRepo.toLowerCase()) {
35072
+ return fail(
35073
+ `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).`
35074
+ );
35075
+ }
34793
35076
  const slug = o.slug ?? await fetchIssueTitle(selector.repo, selector.number).then((t) => t ? slugifyIssueTitle(t) : "");
34794
35077
  branch = buildNewBranchName(selector.number, slug ?? "");
34795
35078
  if (PROTECTED_BRANCHES2.has(branch)) {
@@ -34903,7 +35186,7 @@ withExamples(mutating(
34903
35186
  appendWorktreeEvent(repoRoot2, { action: "created", command: "worktree create", target: wtPath, branch, actor: owner.actor });
34904
35187
  let lease;
34905
35188
  try {
34906
- await execFileP2("jerv-cli", [
35189
+ await execJervCli([
34907
35190
  "lease",
34908
35191
  "open",
34909
35192
  "--kind",
@@ -35612,7 +35895,7 @@ project.command("set [owner/repo]").description("upsert project META (idempotent
35612
35895
  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`);
35613
35896
  if (o.secretsFile) {
35614
35897
  try {
35615
- vars.push(`secrets=${(0, import_node_fs41.readFileSync)(o.secretsFile, "utf8")}`);
35898
+ vars.push(`secrets=${(0, import_node_fs42.readFileSync)(o.secretsFile, "utf8")}`);
35616
35899
  } catch (e) {
35617
35900
  return fail(`org project set: cannot read --secrets-file ${o.secretsFile}: ${e.message}`);
35618
35901
  }
@@ -36366,11 +36649,11 @@ pr.command("view <number>").description("read a PR as structured JSON (merged st
36366
36649
  }
36367
36650
  });
36368
36651
  async function listCiWorkflowPaths(cwd = process.cwd()) {
36369
- const wfDir = (0, import_node_path39.join)(cwd, ".github", "workflows");
36370
- if (!(0, import_node_fs41.existsSync)(wfDir)) return [];
36371
- return (0, import_node_fs41.readdirSync)(wfDir).filter((name) => /\.(ya?ml)$/i.test(name)).filter((name) => {
36652
+ const wfDir = (0, import_node_path40.join)(cwd, ".github", "workflows");
36653
+ if (!(0, import_node_fs42.existsSync)(wfDir)) return [];
36654
+ return (0, import_node_fs42.readdirSync)(wfDir).filter((name) => /\.(ya?ml)$/i.test(name)).filter((name) => {
36372
36655
  try {
36373
- return workflowReportsPrChecks((0, import_node_fs41.readFileSync)((0, import_node_path39.join)(wfDir, name), "utf8"));
36656
+ return workflowReportsPrChecks((0, import_node_fs42.readFileSync)((0, import_node_path40.join)(wfDir, name), "utf8"));
36374
36657
  } catch {
36375
36658
  return true;
36376
36659
  }
@@ -36402,16 +36685,16 @@ function ciAuditDeps() {
36402
36685
  // gate re-seed step is skipped gracefully rather than failing mid-run.
36403
36686
  readSeedFile: (path2) => {
36404
36687
  if (!root) return null;
36405
- const fullPath = (0, import_node_path39.join)(root, path2);
36406
- return (0, import_node_fs41.existsSync)(fullPath) ? (0, import_node_fs41.readFileSync)(fullPath, "utf8") : null;
36688
+ const fullPath = (0, import_node_path40.join)(root, path2);
36689
+ return (0, import_node_fs42.existsSync)(fullPath) ? (0, import_node_fs42.readFileSync)(fullPath, "utf8") : null;
36407
36690
  }
36408
36691
  };
36409
36692
  }
36410
36693
  function hubRoot() {
36411
- const fromPkg = (0, import_node_path39.join)(__dirname, "..", "..");
36694
+ const fromPkg = (0, import_node_path40.join)(__dirname, "..", "..");
36412
36695
  const marker = "skills/bootstrap/seeds/manifest.json";
36413
- if ((0, import_node_fs41.existsSync)((0, import_node_path39.join)(fromPkg, marker))) return fromPkg;
36414
- if ((0, import_node_fs41.existsSync)((0, import_node_path39.join)(process.cwd(), marker))) return process.cwd();
36696
+ if ((0, import_node_fs42.existsSync)((0, import_node_path40.join)(fromPkg, marker))) return fromPkg;
36697
+ if ((0, import_node_fs42.existsSync)((0, import_node_path40.join)(process.cwd(), marker))) return process.cwd();
36415
36698
  return null;
36416
36699
  }
36417
36700
  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) => {
@@ -36723,7 +37006,7 @@ jsonParity(pr.command("merge <number>").description("merge a PR (squash by defau
36723
37006
  localCleanup = await cleanupPrMergeLocalBranch(headRef, {
36724
37007
  beforeWorktrees,
36725
37008
  startingPath,
36726
- pathExists: (p) => (0, import_node_fs41.existsSync)(p),
37009
+ pathExists: (p) => (0, import_node_fs42.existsSync)(p),
36727
37010
  execGit: async (args) => (await execFileP2("git", args, { timeout: GIT_TIMEOUT_MS })).stdout,
36728
37011
  teardownWorktreeStage,
36729
37012
  deferredStore,
@@ -37219,12 +37502,12 @@ access.command("audit").description("audit collaborator roles + train-branch pus
37219
37502
  targets = resolution.targets;
37220
37503
  }
37221
37504
  const derivedMatrix = registryProjects ? accessMatrixFromProjects(registryProjects) : {};
37222
- const fileMatrix = (0, import_node_fs41.existsSync)("access-matrix.json") ? loadAccessMatrix((0, import_node_fs41.readFileSync)("access-matrix.json", "utf8")) : {};
37505
+ const fileMatrix = (0, import_node_fs42.existsSync)("access-matrix.json") ? loadAccessMatrix((0, import_node_fs42.readFileSync)("access-matrix.json", "utf8")) : {};
37223
37506
  const matrix = mergeAccessMatrix(fileMatrix, derivedMatrix);
37224
37507
  const derivedContracts = registryProjects ? dataAccessContractsFromProjects(registryProjects) : { consumers: {} };
37225
- const fileContracts = (0, import_node_fs41.existsSync)("data-access-contracts.json") ? loadDataAccessContracts((0, import_node_fs41.readFileSync)("data-access-contracts.json", "utf8")) : { consumers: {} };
37508
+ const fileContracts = (0, import_node_fs42.existsSync)("data-access-contracts.json") ? loadDataAccessContracts((0, import_node_fs42.readFileSync)("data-access-contracts.json", "utf8")) : { consumers: {} };
37226
37509
  const dataAccess = mergeDataAccessContracts(fileContracts, derivedContracts);
37227
- const sanctioned = (0, import_node_fs41.existsSync)("access-matrix.json") ? loadSanctionedAdmins((0, import_node_fs41.readFileSync)("access-matrix.json", "utf8")) : {};
37510
+ const sanctioned = (0, import_node_fs42.existsSync)("access-matrix.json") ? loadSanctionedAdmins((0, import_node_fs42.readFileSync)("access-matrix.json", "utf8")) : {};
37228
37511
  const report = await auditOrgAccess(targets, deps, matrix, dataAccess, sanctioned);
37229
37512
  console.log(o.json ? JSON.stringify(report, null, 2) : renderAccessReport(report));
37230
37513
  if (!report.ok) process.exitCode = 1;
@@ -37256,16 +37539,16 @@ function directoryBytes(path2) {
37256
37539
  let total = 0;
37257
37540
  let entries;
37258
37541
  try {
37259
- entries = (0, import_node_fs41.readdirSync)(path2, { withFileTypes: true });
37542
+ entries = (0, import_node_fs42.readdirSync)(path2, { withFileTypes: true });
37260
37543
  } catch {
37261
37544
  return 0;
37262
37545
  }
37263
37546
  for (const entry of entries) {
37264
- const child2 = (0, import_node_path39.join)(path2, entry.name);
37547
+ const child2 = (0, import_node_path40.join)(path2, entry.name);
37265
37548
  if (entry.isDirectory()) total += directoryBytes(child2);
37266
37549
  else {
37267
37550
  try {
37268
- total += (0, import_node_fs41.statSync)(child2).size;
37551
+ total += (0, import_node_fs42.statSync)(child2).size;
37269
37552
  } catch {
37270
37553
  }
37271
37554
  }
@@ -37273,25 +37556,25 @@ function directoryBytes(path2) {
37273
37556
  return total;
37274
37557
  }
37275
37558
  function listDirEntries(dir) {
37276
- return (0, import_node_fs41.readdirSync)(dir, { withFileTypes: true }).map((d) => ({ name: d.name, isDirectory: d.isDirectory() }));
37559
+ return (0, import_node_fs42.readdirSync)(dir, { withFileTypes: true }).map((d) => ({ name: d.name, isDirectory: d.isDirectory() }));
37277
37560
  }
37278
37561
  function readInstalledPluginRefs(configRoot) {
37279
37562
  const p = installedPluginsPathForConfig(configRoot);
37280
- if (!(0, import_node_fs41.existsSync)(p)) return [];
37563
+ if (!(0, import_node_fs42.existsSync)(p)) return [];
37281
37564
  try {
37282
- return installedPluginPaths((0, import_node_fs41.readFileSync)(p, "utf8"));
37565
+ return installedPluginPaths((0, import_node_fs42.readFileSync)(p, "utf8"));
37283
37566
  } catch {
37284
37567
  return null;
37285
37568
  }
37286
37569
  }
37287
37570
  function pluginCacheFsDeps(configRoot, dirBytes) {
37288
37571
  return {
37289
- exists: (p) => (0, import_node_fs41.existsSync)(p),
37290
- listVersionDirs: (root) => (0, import_node_fs41.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name),
37572
+ exists: (p) => (0, import_node_fs42.existsSync)(p),
37573
+ listVersionDirs: (root) => (0, import_node_fs42.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name),
37291
37574
  dirBytes,
37292
- listStagingDirs: (root) => (0, import_node_fs41.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => {
37575
+ listStagingDirs: (root) => (0, import_node_fs42.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => {
37293
37576
  try {
37294
- return { name: d.name, mtimeMs: newestMtimeMs((0, import_node_path39.join)(root, d.name), listDirEntries, (p) => (0, import_node_fs41.statSync)(p).mtimeMs) };
37577
+ return { name: d.name, mtimeMs: newestMtimeMs((0, import_node_path40.join)(root, d.name), listDirEntries, (p) => (0, import_node_fs42.statSync)(p).mtimeMs) };
37295
37578
  } catch {
37296
37579
  return { name: d.name, mtimeMs: Date.now() };
37297
37580
  }
@@ -37305,10 +37588,10 @@ function stagingApplyFsGuard(configRoot) {
37305
37588
  return {
37306
37589
  referencedPaths: () => readInstalledPluginRefs(configRoot),
37307
37590
  mtimeMs: (name) => {
37308
- const p = (0, import_node_path39.join)(stagingRoot, name);
37309
- if (!(0, import_node_fs41.existsSync)(p)) return null;
37591
+ const p = (0, import_node_path40.join)(stagingRoot, name);
37592
+ if (!(0, import_node_fs42.existsSync)(p)) return null;
37310
37593
  try {
37311
- return newestMtimeMs(p, listDirEntries, (q) => (0, import_node_fs41.statSync)(q).mtimeMs);
37594
+ return newestMtimeMs(p, listDirEntries, (q) => (0, import_node_fs42.statSync)(q).mtimeMs);
37312
37595
  } catch {
37313
37596
  return null;
37314
37597
  }
@@ -37328,13 +37611,13 @@ program2.command("plugin-prune").description(`prune stale cached MMI plugin vers
37328
37611
  return;
37329
37612
  }
37330
37613
  const plan = buildPluginCachePlan(
37331
- (0, import_node_os16.homedir)(),
37614
+ (0, import_node_os17.homedir)(),
37332
37615
  running,
37333
37616
  pluginCacheFsDeps(configRoot, directoryBytes),
37334
37617
  { withBytes: true, configRoot, includeStaging: surface !== "codex" }
37335
37618
  );
37336
37619
  const anythingToDelete = plan.prune.length > 0 || plan.staging.length > 0;
37337
- const result = o.apply && anythingToDelete ? applyPluginCachePlan(plan, (p) => (0, import_node_fs41.rmSync)(p, { recursive: true, force: true }), stagingApplyFsGuard(configRoot)) : void 0;
37620
+ const result = o.apply && anythingToDelete ? applyPluginCachePlan(plan, (p) => (0, import_node_fs42.rmSync)(p, { recursive: true, force: true }), stagingApplyFsGuard(configRoot)) : void 0;
37338
37621
  const warnings = plan.prune.length > 0 ? [CONCURRENT_SESSION_WARNING] : [];
37339
37622
  if (o.json) console.log(JSON.stringify({ ...plan, warnings, applied: result ?? null }));
37340
37623
  else console.log(renderPluginCachePlan(plan, result));
@@ -37342,7 +37625,7 @@ program2.command("plugin-prune").description(`prune stale cached MMI plugin vers
37342
37625
  });
37343
37626
  function readReleaseCatchupState(path2) {
37344
37627
  try {
37345
- const parsed = JSON.parse((0, import_node_fs41.readFileSync)(path2, "utf8"));
37628
+ const parsed = JSON.parse((0, import_node_fs42.readFileSync)(path2, "utf8"));
37346
37629
  return typeof parsed?.checkedAt === "number" ? parsed : void 0;
37347
37630
  } catch {
37348
37631
  return void 0;
@@ -37350,8 +37633,8 @@ function readReleaseCatchupState(path2) {
37350
37633
  }
37351
37634
  function writeReleaseCatchupState(path2, state) {
37352
37635
  try {
37353
- (0, import_node_fs41.mkdirSync)((0, import_node_path39.dirname)(path2), { recursive: true });
37354
- (0, import_node_fs41.writeFileSync)(path2, `${JSON.stringify(state)}
37636
+ (0, import_node_fs42.mkdirSync)((0, import_node_path40.dirname)(path2), { recursive: true });
37637
+ (0, import_node_fs42.writeFileSync)(path2, `${JSON.stringify(state)}
37355
37638
  `);
37356
37639
  } catch {
37357
37640
  }
@@ -37359,7 +37642,7 @@ function writeReleaseCatchupState(path2, state) {
37359
37642
  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) => {
37360
37643
  const outcome = await withEnvHealLock(
37361
37644
  "plugin release catch-up",
37362
- () => runReleaseCatchup((0, import_node_os16.homedir)(), process.env, {
37645
+ () => runReleaseCatchup((0, import_node_os17.homedir)(), process.env, {
37363
37646
  fetchReleased: fetchNpmReleasedVersion,
37364
37647
  runClaude: (args, step) => runPluginCli("claude", args, (msg) => {
37365
37648
  if (!o.quiet && !o.json) console.log(msg);
@@ -37375,7 +37658,7 @@ program2.command("plugin-release-catchup").description("install a newer released
37375
37658
  },
37376
37659
  readState: readReleaseCatchupState,
37377
37660
  writeState: writeReleaseCatchupState,
37378
- healRegistration: defaultRegistrationHeal((0, import_node_os16.homedir)(), process.env),
37661
+ healRegistration: defaultRegistrationHeal((0, import_node_os17.homedir)(), process.env),
37379
37662
  now: () => Date.now()
37380
37663
  }, { force: o.force })
37381
37664
  );
@@ -37443,7 +37726,7 @@ program2.command("session-start").description("run the SessionStart verbs (whoam
37443
37726
  spawnDetachedSelf(["worktree", "setup", "--quiet"], { spawn: import_node_child_process19.spawn, execPath: process.execPath, scriptPath: process.argv[1] });
37444
37727
  bannerIo.log(worktreeBanner);
37445
37728
  }
37446
- if (shouldSpawnReleaseCatchup((0, import_node_os16.homedir)(), process.env, readReleaseCatchupState)) {
37729
+ if (shouldSpawnReleaseCatchup((0, import_node_os17.homedir)(), process.env, readReleaseCatchupState)) {
37447
37730
  spawnDetachedSelf(["plugin", "release-catchup", "--quiet"], { spawn: import_node_child_process19.spawn, execPath: process.execPath, scriptPath: process.argv[1] });
37448
37731
  }
37449
37732
  if (isLinkedWorktree(process.cwd())) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mutmutco/cli",
3
- "version": "3.105.0",
3
+ "version": "3.105.3",
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",