@mutmutco/cli 3.80.0 → 3.81.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/main.cjs +374 -196
  2. package/package.json +1 -1
package/dist/main.cjs CHANGED
@@ -3416,8 +3416,8 @@ var program = new Command();
3416
3416
 
3417
3417
  // src/index.ts
3418
3418
  var import_promises10 = require("node:fs/promises");
3419
- var import_node_fs34 = require("node:fs");
3420
- var import_node_child_process15 = require("node:child_process");
3419
+ var import_node_fs35 = require("node:fs");
3420
+ var import_node_child_process16 = require("node:child_process");
3421
3421
 
3422
3422
  // src/cli-shared.ts
3423
3423
  var import_node_child_process3 = require("node:child_process");
@@ -4483,6 +4483,7 @@ function trackedPathStatus(c, realPath, repoAnchor) {
4483
4483
  const gitPath = c.kind === "dir" ? `${rel.replace(/\/+$/, "")}/` : rel;
4484
4484
  try {
4485
4485
  (0, import_node_child_process4.execFileSync)("git", ["-C", repoAnchor, "rev-parse", "--is-inside-work-tree"], {
4486
+ windowsHide: true,
4486
4487
  stdio: ["ignore", "ignore", "ignore"],
4487
4488
  timeout: 1e4
4488
4489
  });
@@ -4491,6 +4492,7 @@ function trackedPathStatus(c, realPath, repoAnchor) {
4491
4492
  }
4492
4493
  try {
4493
4494
  const out = (0, import_node_child_process4.execFileSync)("git", ["-C", repoAnchor, "ls-files", "-z", "--", gitPath], {
4495
+ windowsHide: true,
4494
4496
  encoding: "utf8",
4495
4497
  stdio: ["ignore", "pipe", "ignore"],
4496
4498
  timeout: 1e4
@@ -6259,6 +6261,8 @@ function readSettingsAutoUpdate(raw, name) {
6259
6261
  var AUTO_UPDATE_TOGGLE_STEPS = "`/plugin` \u2192 Marketplaces tab \u2192 select the marketplace \u2192 Enable auto-update";
6260
6262
  var CATALOG_CONTENT_REF = "main";
6261
6263
  var CATALOG_REF_PIN_STEPS = `add \`"ref": "${CATALOG_CONTENT_REF}"\` to this marketplace's \`source\` in ~/.claude/plugins/known_marketplaces.json, then restart Claude`;
6264
+ var PIN_HEAL_COMMAND = "run `mmi-cli doctor --apply`";
6265
+ var ORG_MARKETPLACE_PINS = { autoUpdate: true, ref: CATALOG_CONTENT_REF };
6262
6266
  function resolveCatalogRef(probe) {
6263
6267
  const { name, registered, ref, autoUpdate } = probe;
6264
6268
  if (!registered) return void 0;
@@ -6281,7 +6285,7 @@ function resolveCatalogRef(probe) {
6281
6285
  reason: `no ref pinned \u2014 the catalog is served from the repo's default branch while plugin content is pinned to ${CATALOG_CONTENT_REF}`
6282
6286
  };
6283
6287
  }
6284
- function checkMarketplaceAutoUpdate(probe) {
6288
+ function checkMarketplaceAutoUpdate(probe, healable = false) {
6285
6289
  if (!probe) return null;
6286
6290
  const evidence = [`${probe.name}: auto-update ${probe.effective ? "on" : "off"} \u2014 ${probe.reason}`];
6287
6291
  if (probe.effective) {
@@ -6292,11 +6296,11 @@ function checkMarketplaceAutoUpdate(probe) {
6292
6296
  ok: true,
6293
6297
  warn: true,
6294
6298
  label: `marketplace auto-update (${probe.name})`,
6295
- detail: `off \u2014 this machine will not pick up a new plugin release on its own; turn it on with ${AUTO_UPDATE_TOGGLE_STEPS}`,
6299
+ detail: `off \u2014 this machine will not pick up a new plugin release on its own; ${healable ? `${PIN_HEAL_COMMAND} to turn it on` : `turn it on with ${AUTO_UPDATE_TOGGLE_STEPS}`}`,
6296
6300
  verbose: evidence
6297
6301
  };
6298
6302
  }
6299
- function checkMarketplaceCatalogRef(probe) {
6303
+ function checkMarketplaceCatalogRef(probe, healable = false) {
6300
6304
  if (!probe) return null;
6301
6305
  const label = `marketplace catalog ref (${probe.name})`;
6302
6306
  const evidence = [`${probe.name}: ${probe.reason}`, `auto-update: ${probe.autoUpdate ? "on" : "off"}`];
@@ -6313,7 +6317,7 @@ function checkMarketplaceCatalogRef(probe) {
6313
6317
  // ✗ branch carried it in `fix` only because `renderCheckLine` discarded `detail` on failure — one
6314
6318
  // row, two conventions, decided by which field would actually print.
6315
6319
  detail: `${drift} while auto-update is ON`,
6316
- fix: `this machine installs plugin releases advertised by a branch nobody released; ${CATALOG_REF_PIN_STEPS}`,
6320
+ fix: `this machine installs plugin releases advertised by a branch nobody released; ${healable ? `${PIN_HEAL_COMMAND} to pin it` : CATALOG_REF_PIN_STEPS}`,
6317
6321
  verbose: evidence
6318
6322
  };
6319
6323
  }
@@ -6322,11 +6326,11 @@ function checkMarketplaceCatalogRef(probe) {
6322
6326
  ok: true,
6323
6327
  warn: true,
6324
6328
  label,
6325
- detail: `${drift} \u2014 harmless while auto-update is off, and the thing to fix before turning it on; ${CATALOG_REF_PIN_STEPS}`,
6329
+ detail: `${drift} \u2014 harmless while auto-update is off, and the thing to fix before turning it on; ${healable ? `${PIN_HEAL_COMMAND} to pin it` : CATALOG_REF_PIN_STEPS}`,
6326
6330
  verbose: evidence
6327
6331
  };
6328
6332
  }
6329
- function marketplaceRows(name, known, settings) {
6333
+ function marketplaceRows(name, known, settings, healable = false) {
6330
6334
  const { registered, declared, ref } = readKnownMarketplace(known, name);
6331
6335
  const autoUpdate = resolveAutoUpdate({
6332
6336
  name,
@@ -6334,8 +6338,9 @@ function marketplaceRows(name, known, settings) {
6334
6338
  declared,
6335
6339
  settingsDeclared: readSettingsAutoUpdate(settings, name)
6336
6340
  });
6337
- const rows = [checkMarketplaceAutoUpdate(autoUpdate), checkMarketplaceCatalogRef(
6338
- resolveCatalogRef({ name, registered, ref, autoUpdate: autoUpdate.effective })
6341
+ const rows = [checkMarketplaceAutoUpdate(autoUpdate, healable), checkMarketplaceCatalogRef(
6342
+ resolveCatalogRef({ name, registered, ref, autoUpdate: autoUpdate.effective }),
6343
+ healable
6339
6344
  )];
6340
6345
  return rows.filter((r) => r !== null);
6341
6346
  }
@@ -6619,7 +6624,7 @@ function commandLadderHint() {
6619
6624
  }
6620
6625
 
6621
6626
  // src/index.ts
6622
- var import_node_path33 = require("node:path");
6627
+ var import_node_path34 = require("node:path");
6623
6628
 
6624
6629
  // src/merge-ci-policy.ts
6625
6630
  function resolveMergeCiPolicy(input) {
@@ -13440,6 +13445,7 @@ function spawnExitCode(status, signal) {
13440
13445
  function defaultSpawn(command, args, env) {
13441
13446
  const target = resolveSpawnTarget(command, args);
13442
13447
  const r = (0, import_node_child_process6.spawnSync)(target.cmd, target.args, {
13448
+ windowsHide: true,
13443
13449
  stdio: "inherit",
13444
13450
  env,
13445
13451
  windowsVerbatimArguments: target.windowsVerbatimArguments
@@ -14892,7 +14898,7 @@ function readKnownMarketplacesFile(path2) {
14892
14898
  return void 0;
14893
14899
  }
14894
14900
  }
14895
- function restoreMarketplacePinsOnDisk(path2, pins) {
14901
+ function writeMarketplacePinsOnDisk(path2, pins, succeeded, failedVerb) {
14896
14902
  if (pins.size === 0) return void 0;
14897
14903
  const after = readKnownMarketplacesFile(path2);
14898
14904
  const next = restoreMarketplacePins(after, pins);
@@ -14900,14 +14906,35 @@ function restoreMarketplacePinsOnDisk(path2, pins) {
14900
14906
  try {
14901
14907
  (0, import_node_fs18.writeFileSync)(path2, next, "utf8");
14902
14908
  } catch {
14903
- return `could NOT restore ${[...pins.keys()].join(", ")} \u2014 re-pin by hand`;
14909
+ return `could NOT ${failedVerb} ${[...pins.keys()].join(", ")} \u2014 set it by hand`;
14904
14910
  }
14905
14911
  const verify = readKnownMarketplacesFile(path2);
14906
14912
  const failed = [...pins].filter(([name, want]) => {
14907
14913
  const got = readKnownMarketplace(verify, name);
14908
14914
  return typeof want.autoUpdate === "boolean" && got.declared !== want.autoUpdate || want.ref !== void 0 && got.ref !== want.ref;
14909
14915
  });
14910
- return failed.length ? `restore did NOT take for ${failed.map(([n]) => n).join(", ")} \u2014 re-pin by hand` : `re-pinned ${[...pins.keys()].join(", ")} (auto-update + catalog ref survive the reinstall)`;
14916
+ return failed.length ? `${failedVerb} did NOT take for ${failed.map(([n]) => n).join(", ")} \u2014 set it by hand` : succeeded(pins);
14917
+ }
14918
+ function restoreMarketplacePinsOnDisk(path2, pins) {
14919
+ return writeMarketplacePinsOnDisk(path2, pins, restoredPinsLine, "restore");
14920
+ }
14921
+ function applyOrgMarketplacePins(path2, names) {
14922
+ return writeMarketplacePinsOnDisk(
14923
+ path2,
14924
+ new Map(names.map((name) => [name, ORG_MARKETPLACE_PINS])),
14925
+ (pins) => `pinned ${[...pins.keys()].join(", ")} to ${ORG_MARKETPLACE_PINS.ref} with auto-update on`,
14926
+ "pin"
14927
+ );
14928
+ }
14929
+ function restoredPinsLine(pins) {
14930
+ const named = [...pins].map(([name, want]) => {
14931
+ const fields = [
14932
+ ...typeof want.autoUpdate === "boolean" ? ["auto-update"] : [],
14933
+ ...want.ref ? ["catalog ref"] : []
14934
+ ];
14935
+ return `${name} (${fields.join(" + ")})`;
14936
+ });
14937
+ return `re-pinned ${named.join(", ")} \u2014 restored across the reinstall`;
14911
14938
  }
14912
14939
  async function runGuard(readOrigin) {
14913
14940
  const surface = detectSurface(process.env);
@@ -16562,12 +16589,13 @@ var PRIMARY_GROUPS = [
16562
16589
  ["Plan and work", ["board", "issue", "worktree", "stage"]],
16563
16590
  ["Review and ship", ["pr", "ci", "rcand", "release", "hotfix", "train"]],
16564
16591
  // `tests` sits beside `docs` deliberately: both are deterministic, repo-local gates a workflow
16565
- // step invokes (`docs refs`, `tests policy`), not org-plane operations (#3605).
16566
- ["Setup and support", ["bootstrap", "secrets", "docs", "tests"]],
16592
+ // step invokes (`docs refs`, `tests policy`), not org-plane operations (#3605). `spawn policy`
16593
+ // joins them on the same footing (#3979).
16594
+ ["Setup and support", ["bootstrap", "secrets", "docs", "tests", "spawn"]],
16567
16595
  ["Coordinate and improve", ["wave", "report", "skill-lesson"]]
16568
16596
  ];
16569
16597
  var OPERATIONAL_TOP_LEVEL = /* @__PURE__ */ new Set(["org", "runtime", "plugin"]);
16570
- var SUPPORT_PRIMARY = /* @__PURE__ */ new Set(["doctor", "whoami", "commands", "explain", "docs", "tests", "wave", "report", "skill-lesson"]);
16598
+ var SUPPORT_PRIMARY = /* @__PURE__ */ new Set(["doctor", "whoami", "commands", "explain", "docs", "tests", "spawn", "wave", "report", "skill-lesson"]);
16571
16599
  var TOP_LEVEL_ORDER = /* @__PURE__ */ new Map();
16572
16600
  var HELP_GROUP_ORDER = /* @__PURE__ */ new Map();
16573
16601
  var topLevelPosition = 0;
@@ -16607,6 +16635,7 @@ var COMMAND_OWNERSHIP = {
16607
16635
  secrets: { module_owner: "cli/src/secrets-commands.ts", consumer: "authenticated-operator" },
16608
16636
  docs: { module_owner: "cli/src/docs-index-command.ts", consumer: "repo-gates" },
16609
16637
  tests: { module_owner: "cli/src/test-policy-core.ts", consumer: "repo-gates" },
16638
+ spawn: { module_owner: "cli/src/spawn-policy-core.ts", consumer: "repo-gates" },
16610
16639
  wave: { module_owner: "cli/src/wave-land.ts", consumer: "campaign-orchestrator" },
16611
16640
  report: { module_owner: "cli/src/report.ts", consumer: "campaign-orchestrator" },
16612
16641
  "skill-lesson": { module_owner: "cli/src/skill-lesson.ts", consumer: "campaign-orchestrator" },
@@ -18898,10 +18927,115 @@ function runDocRefs(root, deps = {}) {
18898
18927
  };
18899
18928
  }
18900
18929
 
18901
- // src/test-policy-core.ts
18930
+ // src/spawn-policy-core.ts
18902
18931
  var import_node_child_process11 = require("node:child_process");
18903
18932
  var import_node_fs21 = require("node:fs");
18904
18933
  var import_node_path19 = require("node:path");
18934
+ var SPAWNERS = ["spawn", "spawnSync", "exec", "execSync", "execFile", "execFileSync"];
18935
+ var CALL_SOURCE = String.raw`(^|[^.\w$])(${SPAWNERS.join("|")})\s*\(`;
18936
+ var SOURCE_EXT = /\.(ts|mts|cts|js|mjs|cjs)$/;
18937
+ var EXCLUDED = [
18938
+ /(^|\/)node_modules\//,
18939
+ /(^|\/)(dist|build|coverage)\//,
18940
+ /(^|\/)(test|tests|__tests__|fixtures|__fixtures__)\//,
18941
+ /\.(test|spec)\.[cm]?[jt]s$/,
18942
+ /\.d\.[cm]?ts$/
18943
+ ];
18944
+ function stripComments(src) {
18945
+ return src.replace(/\/\*[\s\S]*?\*\//g, (m) => m.replace(/[^\n]/g, " ")).replace(/(^|[^:])\/\/[^\n]*/g, (m, p) => p + " ".repeat(m.length - p.length));
18946
+ }
18947
+ function callArgs(src, open2) {
18948
+ let depth = 0;
18949
+ for (let i = open2; i < src.length; i++) {
18950
+ const c = src[i];
18951
+ if (c === "(") depth++;
18952
+ else if (c === ")") {
18953
+ depth--;
18954
+ if (depth === 0) return src.slice(open2, i + 1);
18955
+ }
18956
+ }
18957
+ return "";
18958
+ }
18959
+ function findViolationsInSource(raw) {
18960
+ if (!/from\s+["']node:child_process["']/.test(raw)) return [];
18961
+ const importBlock = /import\s*(?:type\s*)?\{([^}]*)\}\s*from\s+["']node:child_process["']/.exec(raw);
18962
+ const imported = new Set(
18963
+ (importBlock?.[1] ?? "").split(",").map((s) => s.trim().split(/\s+as\s+/)[0].trim()).filter(Boolean)
18964
+ );
18965
+ if (imported.size === 0) return [];
18966
+ const rawLines = raw.split("\n");
18967
+ const src = stripComments(raw);
18968
+ const call = new RegExp(CALL_SOURCE, "g");
18969
+ const found = [];
18970
+ let m;
18971
+ while (m = call.exec(src)) {
18972
+ const callee = m[2];
18973
+ if (!imported.has(callee)) continue;
18974
+ const open2 = m.index + m[0].length - 1;
18975
+ const args = callArgs(src, open2);
18976
+ if (!args) continue;
18977
+ if (args.includes("windowsHide")) continue;
18978
+ const line = src.slice(0, m.index + m[1].length).split("\n").length;
18979
+ if (/windows-hide-exempt:/.test(rawLines[line - 2] ?? "")) continue;
18980
+ if (/\.{3}\s*\w+/.test(args)) continue;
18981
+ if (/\b(opts|options|spawnOptions)\b/.test(args)) continue;
18982
+ const identifiers = new Set(args.match(/\b[A-Za-z_$][\w$]*\b/g) ?? []);
18983
+ let satisfied = false;
18984
+ for (const id of identifiers) {
18985
+ if (SPAWNERS.includes(id)) continue;
18986
+ const decl = new RegExp(String.raw`\b(?:const|let|var)\s+${id}\b[^;]*`, "s").exec(src);
18987
+ if (decl && decl[0].includes("windowsHide")) {
18988
+ satisfied = true;
18989
+ break;
18990
+ }
18991
+ if (new RegExp(String.raw`\b${id}\s*:\s*\{[^}]*windowsHide`, "s").test(src)) {
18992
+ satisfied = true;
18993
+ break;
18994
+ }
18995
+ }
18996
+ if (satisfied) continue;
18997
+ found.push({ line, callee });
18998
+ }
18999
+ return found;
19000
+ }
19001
+ function policedFiles(root) {
19002
+ const r = (0, import_node_child_process11.spawnSync)("git", ["ls-files", "-z", "--cached", "--others", "--exclude-standard"], {
19003
+ cwd: root,
19004
+ encoding: "utf8",
19005
+ windowsHide: true,
19006
+ maxBuffer: 32 * 1024 * 1024
19007
+ });
19008
+ if (r.status !== 0) {
19009
+ throw new Error(`spawn policy: git ls-files failed: ${(r.stderr || "").trim() || `exit ${r.status}`}`);
19010
+ }
19011
+ return (r.stdout ?? "").split("\0").filter(Boolean).filter((f) => SOURCE_EXT.test(f)).filter((f) => !EXCLUDED.some((re) => re.test(f)));
19012
+ }
19013
+ function runSpawnPolicy(root) {
19014
+ const files = policedFiles(root);
19015
+ const findings = [];
19016
+ for (const file of files) {
19017
+ let raw;
19018
+ try {
19019
+ raw = (0, import_node_fs21.readFileSync)((0, import_node_path19.join)(root, file), "utf8");
19020
+ } catch {
19021
+ continue;
19022
+ }
19023
+ for (const v of findViolationsInSource(raw)) {
19024
+ findings.push({
19025
+ file,
19026
+ line: v.line,
19027
+ callee: v.callee,
19028
+ detail: `${file}:${v.line} ${v.callee}(...) has no windowsHide`
19029
+ });
19030
+ }
19031
+ }
19032
+ return { ok: findings.length === 0, scannedCount: files.length, findings };
19033
+ }
19034
+
19035
+ // src/test-policy-core.ts
19036
+ var import_node_child_process12 = require("node:child_process");
19037
+ var import_node_fs22 = require("node:fs");
19038
+ var import_node_path20 = require("node:path");
18905
19039
  var POLICY_FILE = "test-policy.json";
18906
19040
  var TEST_RE = /\.(?:test|spec)\.[cm]?[jt]sx?$/;
18907
19041
  var PY_TEST_RE = /(?:^|\/)test_[^/]*\.py$|_test\.py$/;
@@ -18954,7 +19088,7 @@ function isTestPath(path2) {
18954
19088
  return TEST_RE.test(path2) || PY_TEST_RE.test(path2);
18955
19089
  }
18956
19090
  function loadPolicy(root, readFile9 = readFileOrNull2) {
18957
- const raw = readFile9((0, import_node_path19.join)(root, POLICY_FILE));
19091
+ const raw = readFile9((0, import_node_path20.join)(root, POLICY_FILE));
18958
19092
  if (raw == null) return { mandatory: [], declared: false };
18959
19093
  try {
18960
19094
  return { ...JSON.parse(raw), declared: true };
@@ -18964,7 +19098,7 @@ function loadPolicy(root, readFile9 = readFileOrNull2) {
18964
19098
  }
18965
19099
  function readFileOrNull2(path2) {
18966
19100
  try {
18967
- return (0, import_node_fs21.readFileSync)(path2, "utf8");
19101
+ return (0, import_node_fs22.readFileSync)(path2, "utf8");
18968
19102
  } catch {
18969
19103
  return null;
18970
19104
  }
@@ -18991,12 +19125,12 @@ function classify(changed, policy, present = () => false) {
18991
19125
  const removedProtected = [...removed].filter((p) => protectedBy.has(p)).map((p) => ({ path: p, why: protectedBy.get(p) ?? "" }));
18992
19126
  return { mandatoryHits, untestedHits, testChanges, addedTests, removedProtected };
18993
19127
  }
18994
- function unresolvedProtectedEntries(policy, root, exists = (path2) => (0, import_node_fs21.existsSync)(path2)) {
18995
- return (policy.protected ?? []).map((p) => p.path).filter((p) => !exists((0, import_node_path19.join)(root, p)));
19128
+ function unresolvedProtectedEntries(policy, root, exists = (path2) => (0, import_node_fs22.existsSync)(path2)) {
19129
+ return (policy.protected ?? []).map((p) => p.path).filter((p) => !exists((0, import_node_path20.join)(root, p)));
18996
19130
  }
18997
- function unresolvedSatisfiers(policy, root, exists = (path2) => (0, import_node_fs21.existsSync)(path2)) {
19131
+ function unresolvedSatisfiers(policy, root, exists = (path2) => (0, import_node_fs22.existsSync)(path2)) {
18998
19132
  const declared = (policy.mandatory ?? []).flatMap((m) => m.satisfiedBy ?? []);
18999
- return [...new Set(declared)].filter((p) => !exists((0, import_node_path19.join)(root, p)));
19133
+ return [...new Set(declared)].filter((p) => !exists((0, import_node_path20.join)(root, p)));
19000
19134
  }
19001
19135
  function evaluate(changed, policy, present = () => false) {
19002
19136
  const { mandatoryHits, untestedHits, testChanges, addedTests, removedProtected } = classify(changed, policy, present);
@@ -19029,14 +19163,15 @@ function evaluate(changed, policy, present = () => false) {
19029
19163
  return findings;
19030
19164
  }
19031
19165
  function git(args, cwd) {
19032
- return (0, import_node_child_process11.execFileSync)("git", args, { cwd, encoding: "utf8", maxBuffer: 32 * 1024 * 1024 });
19166
+ return (0, import_node_child_process12.execFileSync)("git", args, { windowsHide: true, cwd, encoding: "utf8", maxBuffer: 32 * 1024 * 1024 });
19033
19167
  }
19034
19168
  var COAUTHOR_KEY = "Co-authored-by";
19035
19169
  var GH_MESSAGE_SEPARATOR = /^-{5,}$/;
19036
19170
  var LIFTED_KEYS = new RegExp(`^(?:${TRAILER_KEY}|${COAUTHOR_KEY}):`, "i");
19037
19171
  function parseTrailers(message, cwd) {
19038
19172
  try {
19039
- return (0, import_node_child_process11.execFileSync)("git", ["interpret-trailers", "--parse", "--unfold"], {
19173
+ return (0, import_node_child_process12.execFileSync)("git", ["interpret-trailers", "--parse", "--unfold"], {
19174
+ windowsHide: true,
19040
19175
  cwd,
19041
19176
  input: message,
19042
19177
  encoding: "utf8",
@@ -19177,13 +19312,13 @@ function changedFilesSince(base, cwd) {
19177
19312
  }
19178
19313
  function runTestPolicy(root, deps = {}) {
19179
19314
  const policy = deps.policy ?? loadPolicy(root);
19180
- const exists = deps.exists ?? ((path2) => (0, import_node_fs21.existsSync)(path2));
19315
+ const exists = deps.exists ?? ((path2) => (0, import_node_fs22.existsSync)(path2));
19181
19316
  const counts = { mandatoryCount: (policy.mandatory ?? []).length, protectedCount: (policy.protected ?? []).length };
19182
19317
  const base = deps.changed ? "(injected)" : resolveBase(root, deps.base);
19183
19318
  const refusal = deps.changed ? null : untrustworthyRange(root, base);
19184
19319
  const changed = deps.changed ?? (refusal ? [] : changedFilesSince(base, root));
19185
19320
  const lookup = deps.override !== void 0 ? { override: deps.override, refusals: [] } : !deps.changed && !refusal ? readOverride(base, root) : { override: null, refusals: [] };
19186
- const present = (path2) => exists((0, import_node_path19.join)(root, path2));
19321
+ const present = (path2) => exists((0, import_node_path20.join)(root, path2));
19187
19322
  const removedByThisDiff = removedPaths(changed);
19188
19323
  const staleFindings = [];
19189
19324
  const unresolved = unresolvedProtectedEntries(policy, root, exists).filter((p) => !removedByThisDiff.has(p));
@@ -19339,8 +19474,8 @@ function docsAuditStatus(fetch2, opts) {
19339
19474
  }
19340
19475
 
19341
19476
  // src/project-info-sync.ts
19342
- var import_node_fs22 = require("node:fs");
19343
- var import_node_path20 = require("node:path");
19477
+ var import_node_fs23 = require("node:fs");
19478
+ var import_node_path21 = require("node:path");
19344
19479
  var UPDATE_PROJECT_INFO = `mutation($projectId: ID!, $shortDescription: String!, $readme: String!) {
19345
19480
  updateProjectV2(input: { projectId: $projectId, shortDescription: $shortDescription, readme: $readme }) {
19346
19481
  projectV2 { id }
@@ -19385,14 +19520,14 @@ function sharedName(entries, fallback) {
19385
19520
  }
19386
19521
  function buildProjectInfoSyncPlan(targetRepo2, project2, projects, repoRoot2) {
19387
19522
  if (!project2.projectId) throw new Error(`org project sync-info: ${targetRepo2} registry META has no projectId`);
19388
- const readmePath = (0, import_node_path20.join)(repoRoot2, "README.md");
19389
- if (!(0, import_node_fs22.existsSync)(readmePath)) throw new Error(`org project sync-info: ${targetRepo2} has no README.md`);
19523
+ const readmePath = (0, import_node_path21.join)(repoRoot2, "README.md");
19524
+ if (!(0, import_node_fs23.existsSync)(readmePath)) throw new Error(`org project sync-info: ${targetRepo2} has no README.md`);
19390
19525
  const entries = entriesFor(project2, projects);
19391
19526
  const memberRepos = [...new Set(entries.flatMap((entry) => entry.repos ?? []))].filter((repo) => /^[^/]+\/[^/]+$/.test(repo)).sort((a, b) => a.localeCompare(b));
19392
19527
  const projectName = sharedName(entries, project2.name?.trim() || targetRepo2.split("/").pop() || targetRepo2);
19393
19528
  if (!memberRepos.length) throw new Error(`org project sync-info: project ${projectName} has no registered member repos`);
19394
19529
  const entryNames = entries.map((entry) => entry.name?.trim()).filter((name) => Boolean(name));
19395
- const shortDescription = memberRepos.length === 1 ? shortDescriptionFromReadme((0, import_node_fs22.readFileSync)(readmePath, "utf8")) : `Shared work across ${new Intl.ListFormat("en", { type: "conjunction" }).format(entryNames)}.`;
19530
+ const shortDescription = memberRepos.length === 1 ? shortDescriptionFromReadme((0, import_node_fs23.readFileSync)(readmePath, "utf8")) : `Shared work across ${new Intl.ListFormat("en", { type: "conjunction" }).format(entryNames)}.`;
19396
19531
  const lines = [
19397
19532
  `# ${projectName}`,
19398
19533
  "",
@@ -19411,8 +19546,8 @@ function buildProjectInfoSyncPlan(targetRepo2, project2, projects, repoRoot2) {
19411
19546
  const targetBase = `https://github.com/${targetRepo2}`;
19412
19547
  const targetBranch = branchFor(targetRepo2, projects);
19413
19548
  const orgDocs = [
19414
- (0, import_node_fs22.existsSync)((0, import_node_path20.join)(repoRoot2, "docs", "org-readme.md")) ? `- [Org identity](${targetBase}/blob/${targetBranch}/docs/org-readme.md)` : "",
19415
- (0, import_node_fs22.existsSync)((0, import_node_path20.join)(repoRoot2, "docs", "org-architecture.md")) ? `- [Org architecture](${targetBase}/blob/${targetBranch}/docs/org-architecture.md)` : ""
19549
+ (0, import_node_fs23.existsSync)((0, import_node_path21.join)(repoRoot2, "docs", "org-readme.md")) ? `- [Org identity](${targetBase}/blob/${targetBranch}/docs/org-readme.md)` : "",
19550
+ (0, import_node_fs23.existsSync)((0, import_node_path21.join)(repoRoot2, "docs", "org-architecture.md")) ? `- [Org architecture](${targetBase}/blob/${targetBranch}/docs/org-architecture.md)` : ""
19416
19551
  ].filter(Boolean);
19417
19552
  if (orgDocs.length) lines.push("", "## Organisation docs", "", ...orgDocs);
19418
19553
  return { projectId: project2.projectId, projectName, targetRepo: targetRepo2, memberRepos, shortDescription, readme: `${lines.join("\n")}
@@ -20271,8 +20406,8 @@ function writeError(res) {
20271
20406
  }
20272
20407
 
20273
20408
  // src/secrets-commands.ts
20274
- var import_node_fs23 = require("node:fs");
20275
- var import_node_path21 = require("node:path");
20409
+ var import_node_fs24 = require("node:fs");
20410
+ var import_node_path22 = require("node:path");
20276
20411
  var import_node_os8 = require("node:os");
20277
20412
 
20278
20413
  // src/project-runtime.ts
@@ -20396,18 +20531,18 @@ function collectMap(value, previous = []) {
20396
20531
  return [...previous, value];
20397
20532
  }
20398
20533
  async function decryptRailsCredentials(input) {
20399
- const appDir = (0, import_node_path21.resolve)(input.appDir ?? process.cwd());
20534
+ const appDir = (0, import_node_path22.resolve)(input.appDir ?? process.cwd());
20400
20535
  const credentialsFile = input.credentialsFile ?? DEFAULT_RAILS_CREDENTIALS_FILE;
20401
20536
  const masterKeyFile = input.masterKeyFile ?? DEFAULT_RAILS_MASTER_KEY_FILE;
20402
- const credentialsPath = (0, import_node_path21.resolve)(appDir, credentialsFile);
20403
- const masterKeyPath = (0, import_node_path21.resolve)(appDir, masterKeyFile);
20537
+ const credentialsPath = (0, import_node_path22.resolve)(appDir, credentialsFile);
20538
+ const masterKeyPath = (0, import_node_path22.resolve)(appDir, masterKeyFile);
20404
20539
  const env = {
20405
20540
  ...process.env,
20406
20541
  MMI_RAILS_CREDENTIALS_FILE: credentialsPath,
20407
20542
  MMI_RAILS_MASTER_KEY_FILE: masterKeyPath
20408
20543
  };
20409
- if ((0, import_node_fs23.existsSync)(masterKeyPath)) {
20410
- env.RAILS_MASTER_KEY = (0, import_node_fs23.readFileSync)(masterKeyPath, "utf8").trim();
20544
+ if ((0, import_node_fs24.existsSync)(masterKeyPath)) {
20545
+ env.RAILS_MASTER_KEY = (0, import_node_fs24.readFileSync)(masterKeyPath, "utf8").trim();
20411
20546
  }
20412
20547
  const script = [
20413
20548
  'require "json"',
@@ -20417,9 +20552,9 @@ async function decryptRailsCredentials(input) {
20417
20552
  'config = ActiveSupport::EncryptedConfiguration.new(config_path: config_path, key_path: key_path, env_key: "RAILS_MASTER_KEY", raise_if_missing_key: true)',
20418
20553
  "puts JSON.generate(config.config)"
20419
20554
  ].join("\n");
20420
- const scriptDir = (0, import_node_fs23.mkdtempSync)((0, import_node_path21.join)((0, import_node_os8.tmpdir)(), "mmi-rails-decrypt-"));
20421
- const scriptPath = (0, import_node_path21.join)(scriptDir, "decrypt.rb");
20422
- (0, import_node_fs23.writeFileSync)(scriptPath, script, "utf8");
20555
+ const scriptDir = (0, import_node_fs24.mkdtempSync)((0, import_node_path22.join)((0, import_node_os8.tmpdir)(), "mmi-rails-decrypt-"));
20556
+ const scriptPath = (0, import_node_path22.join)(scriptDir, "decrypt.rb");
20557
+ (0, import_node_fs24.writeFileSync)(scriptPath, script, "utf8");
20423
20558
  try {
20424
20559
  const args = ["exec", "ruby", scriptPath];
20425
20560
  const cmd = process.platform === "win32" ? "cmd.exe" : "bundle";
@@ -20431,7 +20566,7 @@ async function decryptRailsCredentials(input) {
20431
20566
  });
20432
20567
  return JSON.parse(stdout);
20433
20568
  } finally {
20434
- (0, import_node_fs23.rmSync)(scriptDir, { recursive: true, force: true });
20569
+ (0, import_node_fs24.rmSync)(scriptDir, { recursive: true, force: true });
20435
20570
  }
20436
20571
  }
20437
20572
  async function readSecretStdin() {
@@ -20521,7 +20656,7 @@ function registerSecretsCommands(program3) {
20521
20656
  let body;
20522
20657
  if (o.file) {
20523
20658
  try {
20524
- body = (0, import_node_fs23.readFileSync)((0, import_node_path21.resolve)(o.file), "utf8");
20659
+ body = (0, import_node_fs24.readFileSync)((0, import_node_path22.resolve)(o.file), "utf8");
20525
20660
  } catch (e) {
20526
20661
  return fail(`secrets org-catalog: cannot read --file ${o.file}: ${e.message}`);
20527
20662
  }
@@ -20626,7 +20761,7 @@ function registerSecretsCommands(program3) {
20626
20761
  {
20627
20762
  ...d,
20628
20763
  decryptRailsCredentials,
20629
- removeFile: (path2) => (0, import_node_fs23.unlinkSync)((0, import_node_path21.resolve)(o.appDir ?? process.cwd(), path2))
20764
+ removeFile: (path2) => (0, import_node_fs24.unlinkSync)((0, import_node_path22.resolve)(o.appDir ?? process.cwd(), path2))
20630
20765
  },
20631
20766
  {
20632
20767
  repo: o.repo,
@@ -20820,7 +20955,7 @@ function checkGithubPools(probe) {
20820
20955
  }
20821
20956
 
20822
20957
  // src/box-commands.ts
20823
- var import_node_fs24 = require("node:fs");
20958
+ var import_node_fs25 = require("node:fs");
20824
20959
 
20825
20960
  // src/box.ts
20826
20961
  var BOX_KEYS = {
@@ -21023,7 +21158,7 @@ function registerBoxCommands(program3) {
21023
21158
  }
21024
21159
  if (o.json) console.log(JSON.stringify({ box: found, incomplete }, null, 2));
21025
21160
  else if (o.ssh && o.script) {
21026
- (0, import_node_fs24.writeFileSync)(o.script, sshRecipeScript(found), "utf8");
21161
+ (0, import_node_fs25.writeFileSync)(o.script, sshRecipeScript(found), "utf8");
21027
21162
  console.log(`wrote ${o.script} \u2014 run: bash "${o.script}"`);
21028
21163
  } else if (o.ssh) console.log(`${formatSshRecipe(found)}
21029
21164
  ${SSH_RECIPE_AGENT_NOTE}`);
@@ -21038,7 +21173,7 @@ ${SSH_RECIPE_AGENT_NOTE}`);
21038
21173
 
21039
21174
  // src/schedules-commands.ts
21040
21175
  var import_promises3 = require("node:fs/promises");
21041
- var import_node_child_process12 = require("node:child_process");
21176
+ var import_node_child_process13 = require("node:child_process");
21042
21177
  var import_node_util7 = require("node:util");
21043
21178
 
21044
21179
  // src/schedules.ts
@@ -21478,7 +21613,7 @@ function assembleReconciliation(githubEntries2, readRepos, registry2, activeWork
21478
21613
  }
21479
21614
 
21480
21615
  // src/schedules-commands.ts
21481
- var execFileP5 = (0, import_node_util7.promisify)(import_node_child_process12.execFile);
21616
+ var execFileP5 = (0, import_node_util7.promisify)(import_node_child_process13.execFile);
21482
21617
  var AWS_REGION = "eu-central-1";
21483
21618
  var AWS_TIMEOUT_MS = 3e4;
21484
21619
  var AWS_RETRY_DELAY_MS = 1500;
@@ -21715,7 +21850,7 @@ function registerSchedulesCommands(program3) {
21715
21850
 
21716
21851
  // src/file-lock.ts
21717
21852
  var import_promises4 = require("node:fs/promises");
21718
- var import_node_path22 = require("node:path");
21853
+ var import_node_path23 = require("node:path");
21719
21854
  var sleep = (ms) => new Promise((resolve5) => setTimeout(resolve5, ms));
21720
21855
  var IMMEDIATE_RETRY_BUDGET = 3;
21721
21856
  var FileLockBusyError = class extends Error {
@@ -21800,7 +21935,7 @@ async function releaseFileLock(lockPath, guard) {
21800
21935
  }
21801
21936
  async function withFileLock(lockPath, opts, fn) {
21802
21937
  const resolved = resolveFileLockOpts(opts);
21803
- await (0, import_promises4.mkdir)((0, import_node_path22.dirname)(lockPath), { recursive: true }).catch(() => void 0);
21938
+ await (0, import_promises4.mkdir)((0, import_node_path23.dirname)(lockPath), { recursive: true }).catch(() => void 0);
21804
21939
  const guard = await acquireFileLock(lockPath, resolved, Date.now() + resolved.maxWaitMs);
21805
21940
  try {
21806
21941
  return await fn();
@@ -21811,7 +21946,7 @@ async function withFileLock(lockPath, opts, fn) {
21811
21946
 
21812
21947
  // src/schedules-lift-command.ts
21813
21948
  var import_promises5 = require("node:fs/promises");
21814
- var import_node_path23 = require("node:path");
21949
+ var import_node_path24 = require("node:path");
21815
21950
 
21816
21951
  // src/schedules-lift.ts
21817
21952
  var SCHEDULE_HEADER_FIELDS = ["schedule", "what", "owner", "cadence", "executor", "llm", "output", "breaks", "kill"];
@@ -21917,7 +22052,7 @@ async function readWorkflowFiles(dir) {
21917
22052
  const files = [];
21918
22053
  for (const name of names.sort()) {
21919
22054
  if (!/\.ya?ml$/.test(name)) continue;
21920
- files.push({ path: `.github/workflows/${name}`, text: await (0, import_promises5.readFile)((0, import_node_path23.join)(dir, name), "utf8") });
22055
+ files.push({ path: `.github/workflows/${name}`, text: await (0, import_promises5.readFile)((0, import_node_path24.join)(dir, name), "utf8") });
21921
22056
  }
21922
22057
  return files;
21923
22058
  }
@@ -22459,9 +22594,9 @@ function registerQueryCommands(program3) {
22459
22594
  }
22460
22595
 
22461
22596
  // src/bootstrap-commands.ts
22462
- var import_node_fs25 = require("node:fs");
22597
+ var import_node_fs26 = require("node:fs");
22463
22598
  var import_node_os9 = require("node:os");
22464
- var import_node_path24 = require("node:path");
22599
+ var import_node_path25 = require("node:path");
22465
22600
 
22466
22601
  // src/bootstrap-drift.ts
22467
22602
  function byteComparableSeeds(manifest, cls) {
@@ -23075,13 +23210,13 @@ function registerBootstrapCommands(program3) {
23075
23210
  client: defaultGitHubClient(),
23076
23211
  projectMeta: meta,
23077
23212
  deployModel: typeof meta?.deployModel === "string" ? meta.deployModel : void 0,
23078
- readLocalFile: (path2) => path2 === "projects.json" && apiProjects != null ? apiProjects : (0, import_node_fs25.existsSync)(path2) ? (0, import_node_fs25.readFileSync)(path2, "utf8") : null,
23213
+ readLocalFile: (path2) => path2 === "projects.json" && apiProjects != null ? apiProjects : (0, import_node_fs26.existsSync)(path2) ? (0, import_node_fs26.readFileSync)(path2, "utf8") : null,
23079
23214
  // requiredGcpApis is stored as an array by a JSON write, but `org project set --var KEY=VALUE` stores a raw
23080
23215
  // comma-string — accept either so the seeded value verifies regardless of how it was written.
23081
23216
  // #3689: the same committed map the org access audit reads (#3664), so a sanctioned admin is not a
23082
23217
  // permanent bootstrap failure on one surface and an intended state on the other. Absent file → no
23083
23218
  // sanction, which is the pre-#3664 behaviour.
23084
- sanctionedAdmins: (0, import_node_fs25.existsSync)("access-matrix.json") ? entriesValueByCanonicalRepo(loadSanctionedAdmins((0, import_node_fs25.readFileSync)("access-matrix.json", "utf8")), repo) : void 0,
23219
+ sanctionedAdmins: (0, import_node_fs26.existsSync)("access-matrix.json") ? entriesValueByCanonicalRepo(loadSanctionedAdmins((0, import_node_fs26.readFileSync)("access-matrix.json", "utf8")), repo) : void 0,
23085
23220
  requiredGcpApis: (() => {
23086
23221
  const v = meta?.requiredGcpApis;
23087
23222
  if (Array.isArray(v)) return v;
@@ -23119,12 +23254,12 @@ function registerBootstrapCommands(program3) {
23119
23254
  bootstrap.command("drift").description("#3818: compare every org-owned whole-file seed against MMI-Hub's copy across the registry roster; read-only").option("--repo <owner/repo>", "audit one repo instead of the roster (never a fleet verdict)").option("--json", "machine-readable output").action(async () => {
23120
23255
  const o = { repo: rawValue("--repo", ""), json: rawFlag("--json") };
23121
23256
  const manifestPath = "skills/bootstrap/seeds/manifest.json";
23122
- if (!(0, import_node_fs25.existsSync)(manifestPath)) return fail(`bootstrap drift: ${manifestPath} not found; run from the MMI-Hub repo root \u2014 the Hub's copies ARE the reference this compares against`);
23123
- const manifest = loadBootstrapSeeds((0, import_node_fs25.readFileSync)(manifestPath, "utf8"));
23257
+ if (!(0, import_node_fs26.existsSync)(manifestPath)) return fail(`bootstrap drift: ${manifestPath} not found; run from the MMI-Hub repo root \u2014 the Hub's copies ARE the reference this compares against`);
23258
+ const manifest = loadBootstrapSeeds((0, import_node_fs26.readFileSync)(manifestPath, "utf8"));
23124
23259
  const hubContents = /* @__PURE__ */ new Map();
23125
23260
  for (const s of manifest.seeds) {
23126
23261
  if (s.ownership !== "org" || s.source !== "self") continue;
23127
- hubContents.set(s.target, (0, import_node_fs25.existsSync)(s.target) ? (0, import_node_fs25.readFileSync)(s.target, "utf8") : null);
23262
+ hubContents.set(s.target, (0, import_node_fs26.existsSync)(s.target) ? (0, import_node_fs26.readFileSync)(s.target, "utf8") : null);
23128
23263
  }
23129
23264
  let targets;
23130
23265
  let classOf = (_repo) => "deployable";
@@ -23201,8 +23336,8 @@ function registerBootstrapCommands(program3) {
23201
23336
  return fail(`bootstrap apply: ${e.message}`);
23202
23337
  }
23203
23338
  const manifestPath = "skills/bootstrap/seeds/manifest.json";
23204
- if (!(0, import_node_fs25.existsSync)(manifestPath)) return fail(`bootstrap apply: ${manifestPath} not found; bootstrap runs from the MMI-Hub repo root by design \u2014 it stamps org-level resources (Project, Ruleset, secrets, access) through the GitHub App, which is only authorized from the Hub checkout`);
23205
- const manifest = loadBootstrapSeeds((0, import_node_fs25.readFileSync)(manifestPath, "utf8"));
23339
+ if (!(0, import_node_fs26.existsSync)(manifestPath)) return fail(`bootstrap apply: ${manifestPath} not found; bootstrap runs from the MMI-Hub repo root by design \u2014 it stamps org-level resources (Project, Ruleset, secrets, access) through the GitHub App, which is only authorized from the Hub checkout`);
23340
+ const manifest = loadBootstrapSeeds((0, import_node_fs26.readFileSync)(manifestPath, "utf8"));
23206
23341
  const baseBranch = o.class === "content" ? "main" : "development";
23207
23342
  const slug = parsedRepo.slug;
23208
23343
  const onlyTarget = o.only.trim();
@@ -23213,16 +23348,16 @@ function registerBootstrapCommands(program3) {
23213
23348
  ${known}`);
23214
23349
  }
23215
23350
  const gh = async (args) => execFileP2("gh", args, { timeout: 2e4 });
23216
- const readFile9 = (p) => (0, import_node_fs25.existsSync)(p) ? (0, import_node_fs25.readFileSync)(p, "utf8") : null;
23351
+ const readFile9 = (p) => (0, import_node_fs26.existsSync)(p) ? (0, import_node_fs26.readFileSync)(p, "utf8") : null;
23217
23352
  const enc = (p) => p.split("/").map(encodeURIComponent).join("/");
23218
23353
  const putSeed = async (target, content, ref, sha) => {
23219
- const tmp = (0, import_node_path24.join)((0, import_node_os9.tmpdir)(), `mmi-seed-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
23220
- (0, import_node_fs25.writeFileSync)(tmp, JSON.stringify(contentPutBody(target, content, ref, sha)), "utf8");
23354
+ const tmp = (0, import_node_path25.join)((0, import_node_os9.tmpdir)(), `mmi-seed-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
23355
+ (0, import_node_fs26.writeFileSync)(tmp, JSON.stringify(contentPutBody(target, content, ref, sha)), "utf8");
23221
23356
  try {
23222
23357
  await gh(contentPutInputArgs(repo, target, tmp));
23223
23358
  } finally {
23224
23359
  try {
23225
- (0, import_node_fs25.unlinkSync)(tmp);
23360
+ (0, import_node_fs26.unlinkSync)(tmp);
23226
23361
  } catch {
23227
23362
  }
23228
23363
  }
@@ -23474,12 +23609,12 @@ LIVE apply to ${repo}:
23474
23609
  }
23475
23610
 
23476
23611
  // src/stage-commands.ts
23477
- var import_node_fs27 = require("node:fs");
23478
- var import_node_path26 = require("node:path");
23612
+ var import_node_fs28 = require("node:fs");
23613
+ var import_node_path27 = require("node:path");
23479
23614
 
23480
23615
  // src/port-registry.ts
23481
- var import_node_fs26 = require("node:fs");
23482
- var import_node_path25 = require("node:path");
23616
+ var import_node_fs27 = require("node:fs");
23617
+ var import_node_path26 = require("node:path");
23483
23618
 
23484
23619
  // ../infra/port-geometry.mjs
23485
23620
  var PORT_BLOCK = 100;
@@ -23493,8 +23628,8 @@ function nextPortBlock(registry2) {
23493
23628
  return [base, base + PORT_SPAN];
23494
23629
  }
23495
23630
  function loadPortRegistry(path2) {
23496
- if (!(0, import_node_fs26.existsSync)(path2)) return {};
23497
- const raw = JSON.parse((0, import_node_fs26.readFileSync)(path2, "utf8"));
23631
+ if (!(0, import_node_fs27.existsSync)(path2)) return {};
23632
+ const raw = JSON.parse((0, import_node_fs27.readFileSync)(path2, "utf8"));
23498
23633
  const out = {};
23499
23634
  for (const [key, value] of Object.entries(raw)) {
23500
23635
  if (Array.isArray(value) && value.length === 2 && value.every((n) => typeof n === "number")) {
@@ -23508,9 +23643,9 @@ function ensurePortRange(repo, path2) {
23508
23643
  const existing = registry2[repo];
23509
23644
  if (existing) return existing;
23510
23645
  const range = nextPortBlock(registry2);
23511
- const raw = (0, import_node_fs26.existsSync)(path2) ? JSON.parse((0, import_node_fs26.readFileSync)(path2, "utf8")) : {};
23646
+ const raw = (0, import_node_fs27.existsSync)(path2) ? JSON.parse((0, import_node_fs27.readFileSync)(path2, "utf8")) : {};
23512
23647
  raw[repo] = range;
23513
- (0, import_node_fs26.writeFileSync)(path2, JSON.stringify(raw, null, 2) + "\n", "utf8");
23648
+ (0, import_node_fs27.writeFileSync)(path2, JSON.stringify(raw, null, 2) + "\n", "utf8");
23514
23649
  return range;
23515
23650
  }
23516
23651
  function portCursorSeed(registry2) {
@@ -23532,22 +23667,22 @@ function existingPortRange(repo, registry2) {
23532
23667
  return registry2[repo] ?? null;
23533
23668
  }
23534
23669
  function portRangeInfraAt(root, source) {
23535
- const registryPath = (0, import_node_path25.join)(root, "infra", "port-ranges.json");
23536
- const ddbScriptPath = (0, import_node_path25.join)(root, "infra", "port-ddb.mjs");
23537
- if (!(0, import_node_fs26.existsSync)(registryPath) || !(0, import_node_fs26.existsSync)(ddbScriptPath)) return null;
23670
+ const registryPath = (0, import_node_path26.join)(root, "infra", "port-ranges.json");
23671
+ const ddbScriptPath = (0, import_node_path26.join)(root, "infra", "port-ddb.mjs");
23672
+ if (!(0, import_node_fs27.existsSync)(registryPath) || !(0, import_node_fs27.existsSync)(ddbScriptPath)) return null;
23538
23673
  return { root, source, registryPath, ddbScriptPath };
23539
23674
  }
23540
23675
  function resolvePortRangeInfra(cwd, packageDir) {
23541
23676
  const direct = portRangeInfraAt(cwd, "cwd");
23542
23677
  if (direct) return direct;
23543
- for (let dir = cwd; ; dir = (0, import_node_path25.dirname)(dir)) {
23544
- const sibling = portRangeInfraAt((0, import_node_path25.join)(dir, "MMI-Hub"), "sibling-hub");
23678
+ for (let dir = cwd; ; dir = (0, import_node_path26.dirname)(dir)) {
23679
+ const sibling = portRangeInfraAt((0, import_node_path26.join)(dir, "MMI-Hub"), "sibling-hub");
23545
23680
  if (sibling) return sibling;
23546
- const parent = (0, import_node_path25.dirname)(dir);
23681
+ const parent = (0, import_node_path26.dirname)(dir);
23547
23682
  if (parent === dir) break;
23548
23683
  }
23549
23684
  if (packageDir) {
23550
- const pkgRoot = (0, import_node_path25.join)(packageDir, "..", "..");
23685
+ const pkgRoot = (0, import_node_path26.join)(packageDir, "..", "..");
23551
23686
  const pkgFrom = portRangeInfraAt(pkgRoot, "pkg-root");
23552
23687
  if (pkgFrom) return pkgFrom;
23553
23688
  }
@@ -23723,8 +23858,8 @@ function registerStageCommands(program3) {
23723
23858
  const portRange = portRangeMeta && typeof portRangeMeta.start === "number" && typeof portRangeMeta.end === "number" ? [portRangeMeta.start, portRangeMeta.end] : void 0;
23724
23859
  return decideStage({
23725
23860
  registry: { deployModel: project2?.deployModel, portRange, error: read.ok ? void 0 : read.error },
23726
- hasCompose: (0, import_node_fs27.existsSync)((0, import_node_path26.join)(process.cwd(), "docker-compose.yml")),
23727
- hasEnvExample: (0, import_node_fs27.existsSync)((0, import_node_path26.join)(process.cwd(), ".env.example"))
23861
+ hasCompose: (0, import_node_fs28.existsSync)((0, import_node_path27.join)(process.cwd(), "docker-compose.yml")),
23862
+ hasEnvExample: (0, import_node_fs28.existsSync)((0, import_node_path27.join)(process.cwd(), ".env.example"))
23728
23863
  });
23729
23864
  }
23730
23865
  async function fetchStageVaultEnvMerge() {
@@ -24162,11 +24297,11 @@ function registerBoardCommands(program3) {
24162
24297
  }
24163
24298
 
24164
24299
  // src/merge-cleanup.ts
24165
- var import_node_fs28 = require("node:fs");
24300
+ var import_node_fs29 = require("node:fs");
24166
24301
  var import_promises7 = require("node:fs/promises");
24167
- var import_node_path28 = require("node:path");
24302
+ var import_node_path29 = require("node:path");
24168
24303
  var import_node_os10 = require("node:os");
24169
- var import_node_child_process13 = require("node:child_process");
24304
+ var import_node_child_process14 = require("node:child_process");
24170
24305
 
24171
24306
  // src/board-advance.ts
24172
24307
  function repoOf2(ref) {
@@ -24252,7 +24387,7 @@ function boardAdvanceFailureMessage(result) {
24252
24387
 
24253
24388
  // src/deferred-registry-store.ts
24254
24389
  var import_promises6 = require("node:fs/promises");
24255
- var import_node_path27 = require("node:path");
24390
+ var import_node_path28 = require("node:path");
24256
24391
  var sleep2 = (ms) => new Promise((resolve5) => setTimeout(resolve5, ms));
24257
24392
  async function atomicWrite(target, contents) {
24258
24393
  const tmp = `${target}.tmp-${process.pid}-${Math.random().toString(36).slice(2)}`;
@@ -24303,12 +24438,12 @@ function makeDeferredWorktreeStore(registryPath, lockOpts = {}) {
24303
24438
  },
24304
24439
  // Standalone atomic write — THROWS on failure (no best-effort swallow, #2846).
24305
24440
  write: async (entries) => {
24306
- await (0, import_promises6.mkdir)((0, import_node_path27.dirname)(registryPath), { recursive: true });
24441
+ await (0, import_promises6.mkdir)((0, import_node_path28.dirname)(registryPath), { recursive: true });
24307
24442
  await atomicWrite(registryPath, serializeDeferredWorktrees(entries));
24308
24443
  },
24309
24444
  // Serialized read-modify-write under the repo-wide lock (#2846).
24310
24445
  update: async (mutate) => {
24311
- await (0, import_promises6.mkdir)((0, import_node_path27.dirname)(registryPath), { recursive: true });
24446
+ await (0, import_promises6.mkdir)((0, import_node_path28.dirname)(registryPath), { recursive: true });
24312
24447
  const deadline = Date.now() + opts.maxWaitMs;
24313
24448
  for (; ; ) {
24314
24449
  const guard = await acquireLock(lockPath, opts, deadline);
@@ -24469,7 +24604,7 @@ async function applyGcPlan(plan, remote, opts = {}) {
24469
24604
  );
24470
24605
  const repoRoot2 = (await execFileP2("git", ["rev-parse", "--show-toplevel"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim() || process.cwd();
24471
24606
  const worktreeGitRoot = await currentRepoWorktreeGitRoot(repoRoot2);
24472
- const primaryRepoRoot = worktreeGitRoot ? (0, import_node_path28.dirname)((0, import_node_path28.dirname)(worktreeGitRoot)) : repoRoot2;
24607
+ const primaryRepoRoot = worktreeGitRoot ? (0, import_node_path29.dirname)((0, import_node_path29.dirname)(worktreeGitRoot)) : repoRoot2;
24473
24608
  const gcActor = describeActor({ env: process.env, surface: detectSurface(process.env), cwd: process.cwd() });
24474
24609
  const owners = readWorktreeOwners(primaryRepoRoot);
24475
24610
  const removalNow = Date.now();
@@ -24500,7 +24635,7 @@ async function applyGcPlan(plan, remote, opts = {}) {
24500
24635
  const cleanup = await cleanupPrMergeLocalBranch(branch.branch, {
24501
24636
  beforeWorktrees,
24502
24637
  startingPath: branch.worktreePath,
24503
- pathExists: (p) => (0, import_node_fs28.existsSync)(p),
24638
+ pathExists: (p) => (0, import_node_fs29.existsSync)(p),
24504
24639
  execGit: async (args) => (await execFileP2("git", args, { timeout: GIT_TIMEOUT_MS })).stdout,
24505
24640
  teardownWorktreeStage,
24506
24641
  deferredStore,
@@ -24528,7 +24663,7 @@ async function applyGcPlan(plan, remote, opts = {}) {
24528
24663
  for (const wt of worktreeDirsToRemove) {
24529
24664
  try {
24530
24665
  const cleanupTarget = resolveSafeSiblingWorktreeCleanupTarget(wt.path, siblingRoot, {
24531
- realpath: (path2) => (0, import_node_fs28.realpathSync)(path2)
24666
+ realpath: (path2) => (0, import_node_fs29.realpathSync)(path2)
24532
24667
  });
24533
24668
  if (!cleanupTarget.ok) {
24534
24669
  result.failed.push(`${wt.path}: ${cleanupTarget.reason}`);
@@ -24593,13 +24728,13 @@ async function composeOverrideBodyFile(prNumber, repoArgs, gh) {
24593
24728
  const commits = JSON.parse(raw).commits ?? [];
24594
24729
  const body = squashBodyWithOverride(commits.map((c) => ({ headline: c.messageHeadline ?? "", body: c.messageBody ?? "" })), process.cwd());
24595
24730
  if (!body) return void 0;
24596
- const dir = (0, import_node_fs28.mkdtempSync)((0, import_node_path28.join)((0, import_node_os10.tmpdir)(), "mmi-squash-body-"));
24597
- const path2 = (0, import_node_path28.join)(dir, "body.txt");
24598
- (0, import_node_fs28.writeFileSync)(path2, `${body}
24731
+ const dir = (0, import_node_fs29.mkdtempSync)((0, import_node_path29.join)((0, import_node_os10.tmpdir)(), "mmi-squash-body-"));
24732
+ const path2 = (0, import_node_path29.join)(dir, "body.txt");
24733
+ (0, import_node_fs29.writeFileSync)(path2, `${body}
24599
24734
  `, "utf8");
24600
24735
  return { path: path2, cleanup: () => {
24601
24736
  try {
24602
- (0, import_node_fs28.rmSync)(dir, { recursive: true, force: true });
24737
+ (0, import_node_fs29.rmSync)(dir, { recursive: true, force: true });
24603
24738
  } catch {
24604
24739
  }
24605
24740
  } };
@@ -24707,7 +24842,7 @@ async function remoteBranchExists2(branch, options = {}) {
24707
24842
  }
24708
24843
  var COMPOSE_TIMEOUT_MS = 12e4;
24709
24844
  function spawnDeferredGcSweep() {
24710
- spawnDetachedSelf(["worktree", "gc", "sweep-deferred", "--quiet"], { spawn: import_node_child_process13.spawn, execPath: process.execPath, scriptPath: process.argv[1] });
24845
+ spawnDetachedSelf(["worktree", "gc", "sweep-deferred", "--quiet"], { spawn: import_node_child_process14.spawn, execPath: process.execPath, scriptPath: process.argv[1] });
24711
24846
  }
24712
24847
  async function createDeferredWorktreeStore() {
24713
24848
  try {
@@ -24721,13 +24856,13 @@ var realWorktreeDirRemover = {
24721
24856
  probe: (p) => {
24722
24857
  let st;
24723
24858
  try {
24724
- st = (0, import_node_fs28.lstatSync)(p);
24859
+ st = (0, import_node_fs29.lstatSync)(p);
24725
24860
  } catch {
24726
24861
  return null;
24727
24862
  }
24728
24863
  if (st.isSymbolicLink()) return "link";
24729
24864
  try {
24730
- (0, import_node_fs28.readlinkSync)(p);
24865
+ (0, import_node_fs29.readlinkSync)(p);
24731
24866
  return "link";
24732
24867
  } catch {
24733
24868
  }
@@ -24735,7 +24870,7 @@ var realWorktreeDirRemover = {
24735
24870
  },
24736
24871
  readdir: (p) => {
24737
24872
  try {
24738
- return (0, import_node_fs28.readdirSync)(p);
24873
+ return (0, import_node_fs29.readdirSync)(p);
24739
24874
  } catch {
24740
24875
  return [];
24741
24876
  }
@@ -24744,9 +24879,9 @@ var realWorktreeDirRemover = {
24744
24879
  // leaving the target); a file symlink with unlink. rmdir first, fall back to unlink.
24745
24880
  detachLink: (p) => {
24746
24881
  try {
24747
- (0, import_node_fs28.rmdirSync)(p);
24882
+ (0, import_node_fs29.rmdirSync)(p);
24748
24883
  } catch {
24749
- (0, import_node_fs28.unlinkSync)(p);
24884
+ (0, import_node_fs29.unlinkSync)(p);
24750
24885
  }
24751
24886
  },
24752
24887
  removeTree: (p) => (0, import_promises7.rm)(p, { recursive: true, force: true, maxRetries: 5, retryDelay: 200 })
@@ -24779,9 +24914,9 @@ async function worktreeHasStageState(worktreePath) {
24779
24914
  }
24780
24915
  }
24781
24916
  function stageStateFileBelongsToWorktree(statePath, worktreePath) {
24782
- if (!(0, import_node_fs28.existsSync)(statePath)) return false;
24917
+ if (!(0, import_node_fs29.existsSync)(statePath)) return false;
24783
24918
  try {
24784
- const state = JSON.parse((0, import_node_fs28.readFileSync)(statePath, "utf8"));
24919
+ const state = JSON.parse((0, import_node_fs29.readFileSync)(statePath, "utf8"));
24785
24920
  const recordedCwd = typeof state.identity?.cwd === "string" ? state.identity.cwd : typeof state.cwd === "string" ? state.cwd : "";
24786
24921
  return Boolean(recordedCwd && isPathUnderDirectory(recordedCwd, worktreePath));
24787
24922
  } catch {
@@ -24988,9 +25123,9 @@ async function fetchRestCorePool(gh = defaultGhApi) {
24988
25123
  }
24989
25124
 
24990
25125
  // src/worktree-lifecycle-commands.ts
24991
- var import_node_fs29 = require("node:fs");
25126
+ var import_node_fs30 = require("node:fs");
24992
25127
  var import_promises8 = require("node:fs/promises");
24993
- var import_node_path29 = require("node:path");
25128
+ var import_node_path30 = require("node:path");
24994
25129
  var GH_TIMEOUT_MS = 2e4;
24995
25130
  var DEFAULT_BASE = "origin/development";
24996
25131
  var DEFAULT_REMOTE = "origin";
@@ -25126,7 +25261,7 @@ function classifyStaleLeaks(input) {
25126
25261
  var defaultOrphanDirScanDeps = {
25127
25262
  listDirs: (root) => {
25128
25263
  try {
25129
- return (0, import_node_fs29.readdirSync)(root, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => (0, import_node_path29.join)(root, e.name));
25264
+ return (0, import_node_fs30.readdirSync)(root, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => (0, import_node_path30.join)(root, e.name));
25130
25265
  } catch {
25131
25266
  return [];
25132
25267
  }
@@ -25273,13 +25408,13 @@ function registerWorktreeCommands(program3) {
25273
25408
  const headBorn = await execFileP2("git", ["-C", wtPath || ".", "rev-parse", "--verify", "--quiet", "HEAD"], { timeout: GIT_TIMEOUT_MS }).then(() => true).catch(() => false);
25274
25409
  const branch = headBorn ? (await execFileP2("git", ["rev-parse", "--abbrev-ref", "HEAD"], { timeout: GIT_TIMEOUT_MS })).stdout.trim() : (await execFileP2("git", ["symbolic-ref", "--quiet", "--short", "HEAD"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim();
25275
25410
  if (!wtPath || !branch) return fail("worktree land: not inside a git worktree");
25276
- const gitFile = (0, import_node_path29.join)(wtPath, ".git");
25277
- const isLinked = (0, import_node_fs29.existsSync)(gitFile) && (0, import_node_fs29.statSync)(gitFile).isFile();
25411
+ const gitFile = (0, import_node_path30.join)(wtPath, ".git");
25412
+ const isLinked = (0, import_node_fs30.existsSync)(gitFile) && (0, import_node_fs30.statSync)(gitFile).isFile();
25278
25413
  if (apply && !isLinked) {
25279
25414
  return fail("worktree land: run from inside the linked worktree you want to land (this is the primary checkout)");
25280
25415
  }
25281
25416
  const commonDir = (await execFileP2("git", ["rev-parse", "--git-common-dir"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim();
25282
- const primaryCheckout = commonDir ? (0, import_node_path29.dirname)(commonDir) : wtPath;
25417
+ const primaryCheckout = commonDir ? (0, import_node_path30.dirname)(commonDir) : wtPath;
25283
25418
  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);
25284
25419
  const orphan = classifyOrphanedWorktree({
25285
25420
  branch,
@@ -25466,10 +25601,10 @@ async function gatherWorktreeContext() {
25466
25601
  if (s) stages.push({ path: wt.path, port: s.port });
25467
25602
  }
25468
25603
  const worktreeGitRoot = await currentRepoWorktreeGitRoot(repoRoot2);
25469
- const primaryRepoRoot = worktreeGitRoot ? (0, import_node_path29.dirname)((0, import_node_path29.dirname)(worktreeGitRoot)) : repoRoot2;
25604
+ const primaryRepoRoot = worktreeGitRoot ? (0, import_node_path30.dirname)((0, import_node_path30.dirname)(worktreeGitRoot)) : repoRoot2;
25470
25605
  const wtRoot = siblingMmiWorktreesRoot(primaryRepoRoot);
25471
25606
  let orphanDirs = [];
25472
- if ((0, import_node_fs29.existsSync)(wtRoot)) {
25607
+ if ((0, import_node_fs30.existsSync)(wtRoot)) {
25473
25608
  orphanDirs = scanOrphanDirs(wtRoot, worktreeGitRoot, {
25474
25609
  ...defaultOrphanDirScanDeps,
25475
25610
  listDirs: (root) => worktreeScanDirs(root, primaryRepoRoot, defaultOrphanDirScanDeps.listDirs, isRepoCheckoutDir)
@@ -25492,7 +25627,7 @@ async function bestEffortGit(args, cwd, step, timeoutMs = GIT_TIMEOUT_MS) {
25492
25627
  }
25493
25628
 
25494
25629
  // src/issue-commands.ts
25495
- var import_node_fs30 = require("node:fs");
25630
+ var import_node_fs31 = require("node:fs");
25496
25631
  var import_node_crypto5 = require("node:crypto");
25497
25632
  var ghRunner = async (args, timeoutMs) => (await execFileP2("gh", args, { timeout: timeoutMs })).stdout;
25498
25633
  var ReparentConflictError = class extends Error {
@@ -25510,7 +25645,7 @@ async function editIssue(client, options, deps = {}) {
25510
25645
  const url = `https://github.com/${repo}/issues/${parsed.number}`;
25511
25646
  const patch = {};
25512
25647
  let bodyChanged = false;
25513
- const textDeps = () => deps.textDeps ?? { readFile: (p, e) => Promise.resolve((0, import_node_fs30.readFileSync)(p, e)), readStdin: () => Promise.resolve("") };
25648
+ const textDeps = () => deps.textDeps ?? { readFile: (p, e) => Promise.resolve((0, import_node_fs31.readFileSync)(p, e)), readStdin: () => Promise.resolve("") };
25514
25649
  if (options.titleFile !== void 0) {
25515
25650
  patch.title = await resolveIssueTitle({ title: options.title, titleFile: options.titleFile }, textDeps());
25516
25651
  } else if (options.title !== void 0) {
@@ -26073,7 +26208,7 @@ function extendCreateCommand(issue2, batchAttach) {
26073
26208
  if (opts.batch) {
26074
26209
  let specs;
26075
26210
  try {
26076
- const raw = (0, import_node_fs30.readFileSync)(opts.batch, "utf8");
26211
+ const raw = (0, import_node_fs31.readFileSync)(opts.batch, "utf8");
26077
26212
  specs = JSON.parse(raw);
26078
26213
  if (!Array.isArray(specs)) throw new Error("batch file must contain a JSON array");
26079
26214
  } catch (e) {
@@ -26147,8 +26282,8 @@ ${lines}`, {
26147
26282
  }
26148
26283
 
26149
26284
  // src/train-commands.ts
26150
- var import_node_fs31 = require("node:fs");
26151
- var import_node_path30 = require("node:path");
26285
+ var import_node_fs32 = require("node:fs");
26286
+ var import_node_path31 = require("node:path");
26152
26287
 
26153
26288
  // src/train-status.ts
26154
26289
  function buildTrainStatusReport(input) {
@@ -26188,7 +26323,7 @@ function formatTrainStatus(r) {
26188
26323
  // src/train-commands.ts
26189
26324
  function readRepoVersion() {
26190
26325
  try {
26191
- return JSON.parse((0, import_node_fs31.readFileSync)((0, import_node_path30.join)(process.cwd(), ".claude-plugin", "plugin.json"), "utf8")).version || void 0;
26326
+ return JSON.parse((0, import_node_fs32.readFileSync)((0, import_node_path31.join)(process.cwd(), ".claude-plugin", "plugin.json"), "utf8")).version || void 0;
26192
26327
  } catch {
26193
26328
  return void 0;
26194
26329
  }
@@ -26334,9 +26469,9 @@ function registerDeployCommands(program3) {
26334
26469
  }
26335
26470
 
26336
26471
  // src/discovery-commands.ts
26337
- var import_node_fs32 = require("node:fs");
26472
+ var import_node_fs33 = require("node:fs");
26338
26473
  var import_node_os11 = require("node:os");
26339
- var import_node_path31 = require("node:path");
26474
+ var import_node_path32 = require("node:path");
26340
26475
  var GC_GH_TIMEOUT_MS3 = 2e4;
26341
26476
  async function collectStatus() {
26342
26477
  let branch = "";
@@ -26513,8 +26648,8 @@ async function collectOnboardStatus() {
26513
26648
  }
26514
26649
  const home = (0, import_node_os11.homedir)();
26515
26650
  const plugin = onboardPluginGate({
26516
- readKnown: () => readFileSyncSafe((0, import_node_path31.join)(home, ...KNOWN_MARKETPLACES_RELATIVE), import_node_fs32.readFileSync),
26517
- readSettings: () => readFileSyncSafe((0, import_node_path31.join)(home, ".claude", "settings.json"), import_node_fs32.readFileSync)
26651
+ readKnown: () => readFileSyncSafe((0, import_node_path32.join)(home, ...KNOWN_MARKETPLACES_RELATIVE), import_node_fs33.readFileSync),
26652
+ readSettings: () => readFileSyncSafe((0, import_node_path32.join)(home, ".claude", "settings.json"), import_node_fs33.readFileSync)
26518
26653
  });
26519
26654
  return { track, board, registry: registry2, secrets, plugin, nextCommand };
26520
26655
  }
@@ -28611,6 +28746,13 @@ async function runDoctorClean(opts, io, deps) {
28611
28746
  if (payload) emitNow(payload);
28612
28747
  }
28613
28748
  async function runMarketplaceRows() {
28749
+ if (applyEnv) {
28750
+ const healed = deps.healMarketplacePins();
28751
+ if (healed) {
28752
+ healIntent(`marketplace pins \u2014 ${healed}`);
28753
+ restartPending = true;
28754
+ }
28755
+ }
28614
28756
  for (const row of deps.marketplaceRows()) emitNow(row);
28615
28757
  }
28616
28758
  async function runSchedulesRow() {
@@ -28789,17 +28931,17 @@ function parseOriginRepo(remoteUrl) {
28789
28931
  }
28790
28932
  function ghHostsConfigPath(env, platform2) {
28791
28933
  const sep2 = platform2 === "win32" ? "\\" : "/";
28792
- const join28 = (...parts) => parts.join(sep2);
28934
+ const join29 = (...parts) => parts.join(sep2);
28793
28935
  const explicit = env.GH_CONFIG_DIR?.trim();
28794
- if (explicit) return join28(explicit, "hosts.yml");
28936
+ if (explicit) return join29(explicit, "hosts.yml");
28795
28937
  if (platform2 === "win32") {
28796
28938
  const appData = (env.AppData ?? env.APPDATA)?.trim();
28797
- return appData ? join28(appData, "GitHub CLI", "hosts.yml") : void 0;
28939
+ return appData ? join29(appData, "GitHub CLI", "hosts.yml") : void 0;
28798
28940
  }
28799
28941
  const xdg = env.XDG_CONFIG_HOME?.trim();
28800
- if (xdg) return join28(xdg, "gh", "hosts.yml");
28942
+ if (xdg) return join29(xdg, "gh", "hosts.yml");
28801
28943
  const home = env.HOME?.trim();
28802
- return home ? join28(home, ".config", "gh", "hosts.yml") : void 0;
28944
+ return home ? join29(home, ".config", "gh", "hosts.yml") : void 0;
28803
28945
  }
28804
28946
  function parseGhHostsAccounts(yaml, host = "github.com") {
28805
28947
  let hostIndent = null;
@@ -28849,17 +28991,17 @@ function ghAccountCaveat(announcedLogin, accounts) {
28849
28991
  }
28850
28992
 
28851
28993
  // src/doctor-io.ts
28852
- var import_node_fs33 = require("node:fs");
28994
+ var import_node_fs34 = require("node:fs");
28853
28995
  var import_node_os12 = require("node:os");
28854
- var import_node_path32 = require("node:path");
28855
- var import_node_child_process14 = require("node:child_process");
28996
+ var import_node_path33 = require("node:path");
28997
+ var import_node_child_process15 = require("node:child_process");
28856
28998
  var import_node_util8 = require("node:util");
28857
- var execFileP6 = (0, import_node_util8.promisify)(import_node_child_process14.execFile);
28999
+ var execFileP6 = (0, import_node_util8.promisify)(import_node_child_process15.execFile);
28858
29000
  var MMI_PLUGIN_ID2 = "mmi@mutmutco";
28859
29001
  function installedClaudePluginVersion() {
28860
29002
  try {
28861
29003
  const file = JSON.parse(
28862
- (0, import_node_fs33.readFileSync)((0, import_node_path32.join)((0, import_node_os12.homedir)(), ".claude", "plugins", "installed_plugins.json"), "utf8")
29004
+ (0, import_node_fs34.readFileSync)((0, import_node_path33.join)((0, import_node_os12.homedir)(), ".claude", "plugins", "installed_plugins.json"), "utf8")
28863
29005
  );
28864
29006
  const versions = (file.plugins?.[MMI_PLUGIN_ID2] ?? []).map((r) => r.version).filter((v) => Boolean(v));
28865
29007
  if (versions.length === 0) return void 0;
@@ -28870,7 +29012,7 @@ function installedClaudePluginVersion() {
28870
29012
  }
28871
29013
  function manifestVersion(path2) {
28872
29014
  try {
28873
- const manifest = JSON.parse((0, import_node_fs33.readFileSync)(path2, "utf8"));
29015
+ const manifest = JSON.parse((0, import_node_fs34.readFileSync)(path2, "utf8"));
28874
29016
  return typeof manifest.version === "string" && manifest.version.trim() ? manifest.version.trim() : void 0;
28875
29017
  } catch {
28876
29018
  return void 0;
@@ -28880,27 +29022,27 @@ function installedSurfacePluginVersion(surface) {
28880
29022
  const token = surfaceToken(surface);
28881
29023
  if (token === "kilo") {
28882
29024
  try {
28883
- const stamp = (0, import_node_fs33.readFileSync)((0, import_node_path32.join)((0, import_node_os12.homedir)(), ".kilo", ".mmi-kilo-version"), "utf8").trim();
29025
+ const stamp = (0, import_node_fs34.readFileSync)((0, import_node_path33.join)((0, import_node_os12.homedir)(), ".kilo", ".mmi-kilo-version"), "utf8").trim();
28884
29026
  return stamp || void 0;
28885
29027
  } catch {
28886
29028
  return void 0;
28887
29029
  }
28888
29030
  }
28889
29031
  if (token === "cursor") {
28890
- return manifestVersion((0, import_node_path32.join)(cursorLocalPluginRoot(), ".cursor-plugin", "plugin.json"));
29032
+ return manifestVersion((0, import_node_path33.join)(cursorLocalPluginRoot(), ".cursor-plugin", "plugin.json"));
28891
29033
  }
28892
29034
  if (token === "kimi") {
28893
- return manifestVersion((0, import_node_path32.join)(surfaceConfigRoot(surface), "plugins", "managed", "mmi", ".kimi-plugin", "plugin.json"));
29035
+ return manifestVersion((0, import_node_path33.join)(surfaceConfigRoot(surface), "plugins", "managed", "mmi", ".kimi-plugin", "plugin.json"));
28894
29036
  }
28895
29037
  if (token === "claude") return installedClaudePluginVersion();
28896
29038
  if (token !== "codex") return void 0;
28897
29039
  try {
28898
- const raw = process.platform === "win32" ? (0, import_node_child_process14.execFileSync)("cmd.exe", ["/c", "codex", "plugin", "list", "--json"], {
29040
+ const raw = process.platform === "win32" ? (0, import_node_child_process15.execFileSync)("cmd.exe", ["/c", "codex", "plugin", "list", "--json"], {
28899
29041
  encoding: "utf8",
28900
29042
  stdio: ["ignore", "pipe", "ignore"],
28901
29043
  timeout: 15e3,
28902
29044
  windowsHide: true
28903
- }) : (0, import_node_child_process14.execFileSync)("codex", ["plugin", "list", "--json"], {
29045
+ }) : (0, import_node_child_process15.execFileSync)("codex", ["plugin", "list", "--json"], {
28904
29046
  encoding: "utf8",
28905
29047
  stdio: ["ignore", "pipe", "ignore"],
28906
29048
  timeout: 15e3,
@@ -28918,7 +29060,7 @@ function installedActivePluginVersion(surface = detectSurface(process.env)) {
28918
29060
  }
28919
29061
  function worktreeRootSync() {
28920
29062
  try {
28921
- const out = (0, import_node_child_process14.execFileSync)("git", ["rev-parse", "--show-toplevel"], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] });
29063
+ const out = (0, import_node_child_process15.execFileSync)("git", ["rev-parse", "--show-toplevel"], { windowsHide: true, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] });
28922
29064
  let root = out.endsWith("\n") ? out.slice(0, -1) : out;
28923
29065
  if (process.platform === "win32" && root.endsWith("\r")) root = root.slice(0, -1);
28924
29066
  return root || null;
@@ -28928,13 +29070,13 @@ function worktreeRootSync() {
28928
29070
  }
28929
29071
  var gitignorePath = () => {
28930
29072
  const root = worktreeRootSync();
28931
- return root === null ? null : (0, import_node_path32.join)(root, ".gitignore");
29073
+ return root === null ? null : (0, import_node_path33.join)(root, ".gitignore");
28932
29074
  };
28933
29075
  function readGitignore() {
28934
29076
  const path2 = gitignorePath();
28935
29077
  if (path2 === null) return null;
28936
29078
  try {
28937
- return (0, import_node_fs33.readFileSync)(path2, "utf8");
29079
+ return (0, import_node_fs34.readFileSync)(path2, "utf8");
28938
29080
  } catch {
28939
29081
  return null;
28940
29082
  }
@@ -28943,7 +29085,7 @@ function writeGitignore(content) {
28943
29085
  const path2 = gitignorePath();
28944
29086
  if (path2 === null) return false;
28945
29087
  try {
28946
- (0, import_node_fs33.writeFileSync)(path2, content, "utf8");
29088
+ (0, import_node_fs34.writeFileSync)(path2, content, "utf8");
28947
29089
  return true;
28948
29090
  } catch {
28949
29091
  return false;
@@ -28967,7 +29109,7 @@ async function repoRoot() {
28967
29109
  }
28968
29110
  function hasRepoLocalWorktrees() {
28969
29111
  const root = worktreeRootSync();
28970
- return root !== null && (0, import_node_fs33.existsSync)((0, import_node_path32.join)(root, ".worktrees"));
29112
+ return root !== null && (0, import_node_fs34.existsSync)((0, import_node_path33.join)(root, ".worktrees"));
28971
29113
  }
28972
29114
 
28973
29115
  // src/index.ts
@@ -29003,8 +29145,8 @@ ${r.stderr ?? ""}`).catch(() => "");
29003
29145
  function ghMultiAccountCaveat(announcedLogin) {
29004
29146
  try {
29005
29147
  const hostsPath = ghHostsConfigPath(process.env, process.platform);
29006
- if (!hostsPath || !(0, import_node_fs34.existsSync)(hostsPath)) return void 0;
29007
- return ghAccountCaveat(announcedLogin, parseGhHostsAccounts((0, import_node_fs34.readFileSync)(hostsPath, "utf8")));
29148
+ if (!hostsPath || !(0, import_node_fs35.existsSync)(hostsPath)) return void 0;
29149
+ return ghAccountCaveat(announcedLogin, parseGhHostsAccounts((0, import_node_fs35.readFileSync)(hostsPath, "utf8")));
29008
29150
  } catch {
29009
29151
  return void 0;
29010
29152
  }
@@ -29012,7 +29154,7 @@ function ghMultiAccountCaveat(announcedLogin) {
29012
29154
  var ENV_HEAL_LOCK_STALE_MS = 10 * 6e4;
29013
29155
  var ENV_HEAL_LOCK_MAX_WAIT_MS = 2 * 6e4;
29014
29156
  function envHealLockPath(home) {
29015
- return (0, import_node_path33.join)(home, ".claude", "plugins", ".mmi-env-heal.lock");
29157
+ return (0, import_node_path34.join)(home, ".claude", "plugins", ".mmi-env-heal.lock");
29016
29158
  }
29017
29159
  async function withEnvHealLock(what, run) {
29018
29160
  try {
@@ -29198,12 +29340,25 @@ function mmiDoctorDeps(opts = {}) {
29198
29340
  const home = (0, import_node_os13.homedir)();
29199
29341
  return marketplaceRows(
29200
29342
  MMI_MARKETPLACE_NAME,
29201
- readFileSyncSafe((0, import_node_path33.join)(home, ...KNOWN_MARKETPLACES_RELATIVE), import_node_fs34.readFileSync),
29202
- readFileSyncSafe((0, import_node_path33.join)(home, ".claude", "settings.json"), import_node_fs34.readFileSync)
29343
+ readFileSyncSafe((0, import_node_path34.join)(home, ...KNOWN_MARKETPLACES_RELATIVE), import_node_fs35.readFileSync),
29344
+ readFileSyncSafe((0, import_node_path34.join)(home, ".claude", "settings.json"), import_node_fs35.readFileSync),
29345
+ // #3974: this CLI heals these rows, so report mode names `doctor --apply` rather than the hand
29346
+ // edit. Unconditional — it is a fact about mmi-cli, not about whether --apply was passed.
29347
+ true
29203
29348
  );
29204
29349
  } catch {
29205
29350
  return [];
29206
29351
  }
29352
+ },
29353
+ // #3974: the heal behind those rows, under --apply only. Same Codex carve-out as the rows above —
29354
+ // Codex keeps its registration in config.toml, so there is no ~/.claude registration to pin.
29355
+ healMarketplacePins: () => {
29356
+ try {
29357
+ if (detectSurface(process.env) === "codex") return void 0;
29358
+ return applyOrgMarketplacePins((0, import_node_path34.join)((0, import_node_os13.homedir)(), ...KNOWN_MARKETPLACES_RELATIVE), [MMI_MARKETPLACE_NAME]);
29359
+ } catch {
29360
+ return void 0;
29361
+ }
29207
29362
  }
29208
29363
  };
29209
29364
  }
@@ -29405,19 +29560,19 @@ program2.hook("preAction", async (_thisCommand, actionCommand) => {
29405
29560
  });
29406
29561
  var rules = program2.command("rules").description("org-managed .gitignore delivery");
29407
29562
  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) => {
29408
- const path2 = (0, import_node_path33.join)(process.cwd(), ".gitignore");
29409
- const current = (0, import_node_fs34.existsSync)(path2) ? (0, import_node_fs34.readFileSync)(path2, "utf8") : null;
29563
+ const path2 = (0, import_node_path34.join)(process.cwd(), ".gitignore");
29564
+ const current = (0, import_node_fs35.existsSync)(path2) ? (0, import_node_fs35.readFileSync)(path2, "utf8") : null;
29410
29565
  const plan = planManagedGitignore(current);
29411
29566
  const drift = [...plan.added.map((l) => `+${l}`), ...plan.removed.map((l) => `-${l}`)].join(", ") || "block normalize";
29412
29567
  if (opts.json) {
29413
- if (opts.write && plan.changed) (0, import_node_fs34.writeFileSync)(path2, plan.content, "utf8");
29568
+ if (opts.write && plan.changed) (0, import_node_fs35.writeFileSync)(path2, plan.content, "utf8");
29414
29569
  console.log(JSON.stringify(plan, null, 2));
29415
29570
  if (!opts.write && plan.changed) process.exitCode = 1;
29416
29571
  return;
29417
29572
  }
29418
29573
  if (opts.write) {
29419
29574
  if (plan.changed) {
29420
- (0, import_node_fs34.writeFileSync)(path2, plan.content, "utf8");
29575
+ (0, import_node_fs35.writeFileSync)(path2, plan.content, "utf8");
29421
29576
  console.log(`mmi-cli org rules gitignore: updated .gitignore (${drift})`);
29422
29577
  } else {
29423
29578
  console.log("mmi-cli org rules gitignore: up to date");
@@ -29572,8 +29727,8 @@ gcCmd.option("--dry-run", "show what would be deleted (default)").option("--appl
29572
29727
  if (!Number.isFinite(limit) || limit < 1) return fail("worktree gc: --limit must be a positive integer");
29573
29728
  let root;
29574
29729
  if (o.root !== void 0) {
29575
- root = (0, import_node_path33.resolve)(o.root);
29576
- if (!(0, import_node_fs34.existsSync)(root) || !(0, import_node_fs34.statSync)(root).isDirectory()) return fail(`worktree gc: --root ${o.root} is not a directory`);
29730
+ root = (0, import_node_path34.resolve)(o.root);
29731
+ if (!(0, import_node_fs35.existsSync)(root) || !(0, import_node_fs35.statSync)(root).isDirectory()) return fail(`worktree gc: --root ${o.root} is not a directory`);
29577
29732
  const gcRepoRoot = (await execFileP2("git", ["rev-parse", "--show-toplevel"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim() || process.cwd();
29578
29733
  if (isPathUnderDirectory(gcRepoRoot, root)) {
29579
29734
  return fail(`worktree gc: --root ${root} contains this checkout \u2014 name a worktrees root, not the repo or an ancestor of it`);
@@ -29615,7 +29770,7 @@ function runWorktreeInstall(command, cwd, quiet) {
29615
29770
  const file = isWin2 ? "cmd.exe" : bin;
29616
29771
  const spawnArgs = isWin2 ? ["/c", bin, ...args] : args;
29617
29772
  return new Promise((resolve5, reject) => {
29618
- const child2 = (0, import_node_child_process15.spawn)(file, spawnArgs, { cwd, stdio: quiet ? "ignore" : "inherit", windowsHide: true });
29773
+ const child2 = (0, import_node_child_process16.spawn)(file, spawnArgs, { cwd, stdio: quiet ? "ignore" : "inherit", windowsHide: true });
29619
29774
  const timer = setTimeout(() => {
29620
29775
  try {
29621
29776
  child2.kill();
@@ -29638,7 +29793,7 @@ async function primaryCheckoutRoot(from) {
29638
29793
  return primaryCheckoutRootOf(async (args) => (await execFileP2("git", ["-C", from, ...args], { timeout: GIT_TIMEOUT_MS })).stdout);
29639
29794
  }
29640
29795
  async function unprovenWorktreeReason(wtPath, repoRoot2) {
29641
- if (!(0, import_node_fs34.existsSync)(wtPath)) return `${wtPath} does not exist on disk`;
29796
+ if (!(0, import_node_fs35.existsSync)(wtPath)) return `${wtPath} does not exist on disk`;
29642
29797
  const porcelain = (await execFileP2("git", ["-C", repoRoot2, "worktree", "list", "--porcelain"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout;
29643
29798
  const registered = parseWorktreePorcelainEntries(porcelain);
29644
29799
  if (!registered.length) {
@@ -29659,26 +29814,26 @@ function makeProvisionDeps(worktreeRoot, quiet, log) {
29659
29814
  function acquireWorktreeSetupLock(worktreeRoot) {
29660
29815
  const lockPath = repoRuntimeStatePath(worktreeRoot, "worktree-setup.lock");
29661
29816
  const take = () => {
29662
- const fd = (0, import_node_fs34.openSync)(lockPath, "wx");
29817
+ const fd = (0, import_node_fs35.openSync)(lockPath, "wx");
29663
29818
  try {
29664
- (0, import_node_fs34.writeSync)(fd, String(Date.now()));
29819
+ (0, import_node_fs35.writeSync)(fd, String(Date.now()));
29665
29820
  } finally {
29666
- (0, import_node_fs34.closeSync)(fd);
29821
+ (0, import_node_fs35.closeSync)(fd);
29667
29822
  }
29668
29823
  return () => {
29669
29824
  try {
29670
- (0, import_node_fs34.rmSync)(lockPath, { force: true });
29825
+ (0, import_node_fs35.rmSync)(lockPath, { force: true });
29671
29826
  } catch {
29672
29827
  }
29673
29828
  };
29674
29829
  };
29675
29830
  try {
29676
- (0, import_node_fs34.mkdirSync)((0, import_node_path33.dirname)(lockPath), { recursive: true });
29831
+ (0, import_node_fs35.mkdirSync)((0, import_node_path34.dirname)(lockPath), { recursive: true });
29677
29832
  return take();
29678
29833
  } catch {
29679
29834
  try {
29680
- if (Date.now() - (0, import_node_fs34.statSync)(lockPath).mtimeMs > WORKTREE_SETUP_LOCK_TTL_MS) {
29681
- (0, import_node_fs34.rmSync)(lockPath, { force: true });
29835
+ if (Date.now() - (0, import_node_fs35.statSync)(lockPath).mtimeMs > WORKTREE_SETUP_LOCK_TTL_MS) {
29836
+ (0, import_node_fs35.rmSync)(lockPath, { force: true });
29682
29837
  return take();
29683
29838
  }
29684
29839
  } catch {
@@ -29901,7 +30056,7 @@ function scheduleRelatedDiscovery(o) {
29901
30056
  try {
29902
30057
  const args = ["issue", "discover-related", "--number", String(o.number), "--title", o.title, "--body", o.body, "--fail-soft"];
29903
30058
  if (o.repo) args.push("--repo", o.repo);
29904
- spawnDetachedSelf(args, { spawn: import_node_child_process15.spawn, execPath: process.execPath, scriptPath: process.argv[1] }, { cwd: process.cwd() });
30059
+ spawnDetachedSelf(args, { spawn: import_node_child_process16.spawn, execPath: process.execPath, scriptPath: process.argv[1] }, { cwd: process.cwd() });
29905
30060
  } catch {
29906
30061
  }
29907
30062
  }
@@ -29951,6 +30106,29 @@ docs.command("refs").description("deterministic doc reference gate: every backti
29951
30106
  await failGraceful(e.message);
29952
30107
  }
29953
30108
  });
30109
+ var spawnCmd = program2.command("spawn").description("this repo's process-spawn contract \u2014 every child process must be unable to pop a console window");
30110
+ spawnCmd.command("policy").description("enforce the windowsHide contract across this repo's tracked source: a child_process call must set windowsHide, or take its options from a named constant, a type annotation, or a forwarded caller bag that does. Waive a call the scan cannot classify with a `// windows-hide-exempt: <reason>` comment on the line above it (#3979)").option("--json", "machine-readable result: { ok, scannedCount, findings[] }").action(async (o) => {
30111
+ try {
30112
+ const root = await repoRoot();
30113
+ const result = runSpawnPolicy(root);
30114
+ if (o.json) {
30115
+ consoleIo.log(JSON.stringify(result, null, 2));
30116
+ if (!result.ok) process.exitCode = 1;
30117
+ return;
30118
+ }
30119
+ if (result.ok) {
30120
+ console.log(`spawn policy: OK (${result.scannedCount} source file(s) scanned).`);
30121
+ return;
30122
+ }
30123
+ for (const f of result.findings) console.error(`spawn policy: ${f.detail}`);
30124
+ console.error(
30125
+ "\nA process spawned without windowsHide allocates a console when it has none to inherit.\nWhere Windows Terminal is the default terminal, that console becomes a desktop window the\nhost never reaps \u2014 it outlives the process as an empty frame. Set windowsHide: true, or\nroute the call through a helper that does."
30126
+ );
30127
+ process.exitCode = 1;
30128
+ } catch (e) {
30129
+ await failGraceful(e.message);
30130
+ }
30131
+ });
29954
30132
  var tests = program2.command("tests").description("a repo's test-policy.json \u2014 the opt-in test contract and its enforcement");
29955
30133
  tests.command("policy").description("enforce this repo's test-policy.json against the diff: a mandatory-zone change must carry a test, an unrequested new test file is refused, a `protected` test file may not be deleted or renamed away, and a `protected` entry naming a missing file is refused. Override any of them with a `Test-Policy-Override: <reason>` commit trailer (#3605)").option("--json", "machine-readable result: { ok, base, changedCount, findings[] }").option("--base <ref>", "comparison base (default: TEST_POLICY_BASE, then origin/development, then origin/main)").action(async (o) => {
29956
30134
  try {
@@ -30257,7 +30435,7 @@ project.command("set [owner/repo]").description("upsert project META (idempotent
30257
30435
  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`);
30258
30436
  if (o.secretsFile) {
30259
30437
  try {
30260
- vars.push(`secrets=${(0, import_node_fs34.readFileSync)(o.secretsFile, "utf8")}`);
30438
+ vars.push(`secrets=${(0, import_node_fs35.readFileSync)(o.secretsFile, "utf8")}`);
30261
30439
  } catch (e) {
30262
30440
  return fail(`org project set: cannot read --secrets-file ${o.secretsFile}: ${e.message}`);
30263
30441
  }
@@ -31005,11 +31183,11 @@ pr.command("view <number>").description("read a PR as structured JSON (merged st
31005
31183
  }
31006
31184
  });
31007
31185
  async function listCiWorkflowPaths(cwd = process.cwd()) {
31008
- const wfDir = (0, import_node_path33.join)(cwd, ".github", "workflows");
31009
- if (!(0, import_node_fs34.existsSync)(wfDir)) return [];
31010
- return (0, import_node_fs34.readdirSync)(wfDir).filter((name) => /\.(ya?ml)$/i.test(name)).filter((name) => {
31186
+ const wfDir = (0, import_node_path34.join)(cwd, ".github", "workflows");
31187
+ if (!(0, import_node_fs35.existsSync)(wfDir)) return [];
31188
+ return (0, import_node_fs35.readdirSync)(wfDir).filter((name) => /\.(ya?ml)$/i.test(name)).filter((name) => {
31011
31189
  try {
31012
- return workflowReportsPrChecks((0, import_node_fs34.readFileSync)((0, import_node_path33.join)(wfDir, name), "utf8"));
31190
+ return workflowReportsPrChecks((0, import_node_fs35.readFileSync)((0, import_node_path34.join)(wfDir, name), "utf8"));
31013
31191
  } catch {
31014
31192
  return true;
31015
31193
  }
@@ -31041,16 +31219,16 @@ function ciAuditDeps() {
31041
31219
  // gate re-seed step is skipped gracefully rather than failing mid-run.
31042
31220
  readSeedFile: (path2) => {
31043
31221
  if (!root) return null;
31044
- const fullPath = (0, import_node_path33.join)(root, path2);
31045
- return (0, import_node_fs34.existsSync)(fullPath) ? (0, import_node_fs34.readFileSync)(fullPath, "utf8") : null;
31222
+ const fullPath = (0, import_node_path34.join)(root, path2);
31223
+ return (0, import_node_fs35.existsSync)(fullPath) ? (0, import_node_fs35.readFileSync)(fullPath, "utf8") : null;
31046
31224
  }
31047
31225
  };
31048
31226
  }
31049
31227
  function hubRoot() {
31050
- const fromPkg = (0, import_node_path33.join)(__dirname, "..", "..");
31228
+ const fromPkg = (0, import_node_path34.join)(__dirname, "..", "..");
31051
31229
  const marker = "skills/bootstrap/seeds/manifest.json";
31052
- if ((0, import_node_fs34.existsSync)((0, import_node_path33.join)(fromPkg, marker))) return fromPkg;
31053
- if ((0, import_node_fs34.existsSync)((0, import_node_path33.join)(process.cwd(), marker))) return process.cwd();
31230
+ if ((0, import_node_fs35.existsSync)((0, import_node_path34.join)(fromPkg, marker))) return fromPkg;
31231
+ if ((0, import_node_fs35.existsSync)((0, import_node_path34.join)(process.cwd(), marker))) return process.cwd();
31054
31232
  return null;
31055
31233
  }
31056
31234
  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) => {
@@ -31353,7 +31531,7 @@ jsonParity(pr.command("merge <number>").description("merge a PR (squash by defau
31353
31531
  localCleanup = await cleanupPrMergeLocalBranch(headRef, {
31354
31532
  beforeWorktrees,
31355
31533
  startingPath,
31356
- pathExists: (p) => (0, import_node_fs34.existsSync)(p),
31534
+ pathExists: (p) => (0, import_node_fs35.existsSync)(p),
31357
31535
  execGit: async (args) => (await execFileP2("git", args, { timeout: GIT_TIMEOUT_MS })).stdout,
31358
31536
  teardownWorktreeStage,
31359
31537
  deferredStore,
@@ -31828,12 +32006,12 @@ access.command("audit").description("audit collaborator roles + train-branch pus
31828
32006
  targets = resolution.targets;
31829
32007
  }
31830
32008
  const derivedMatrix = registryProjects ? accessMatrixFromProjects(registryProjects) : {};
31831
- const fileMatrix = (0, import_node_fs34.existsSync)("access-matrix.json") ? loadAccessMatrix((0, import_node_fs34.readFileSync)("access-matrix.json", "utf8")) : {};
32009
+ const fileMatrix = (0, import_node_fs35.existsSync)("access-matrix.json") ? loadAccessMatrix((0, import_node_fs35.readFileSync)("access-matrix.json", "utf8")) : {};
31832
32010
  const matrix = mergeAccessMatrix(fileMatrix, derivedMatrix);
31833
32011
  const derivedContracts = registryProjects ? dataAccessContractsFromProjects(registryProjects) : { consumers: {} };
31834
- const fileContracts = (0, import_node_fs34.existsSync)("data-access-contracts.json") ? loadDataAccessContracts((0, import_node_fs34.readFileSync)("data-access-contracts.json", "utf8")) : { consumers: {} };
32012
+ const fileContracts = (0, import_node_fs35.existsSync)("data-access-contracts.json") ? loadDataAccessContracts((0, import_node_fs35.readFileSync)("data-access-contracts.json", "utf8")) : { consumers: {} };
31835
32013
  const dataAccess = mergeDataAccessContracts(fileContracts, derivedContracts);
31836
- const sanctioned = (0, import_node_fs34.existsSync)("access-matrix.json") ? loadSanctionedAdmins((0, import_node_fs34.readFileSync)("access-matrix.json", "utf8")) : {};
32014
+ const sanctioned = (0, import_node_fs35.existsSync)("access-matrix.json") ? loadSanctionedAdmins((0, import_node_fs35.readFileSync)("access-matrix.json", "utf8")) : {};
31837
32015
  const report = await auditOrgAccess(targets, deps, matrix, dataAccess, sanctioned);
31838
32016
  console.log(o.json ? JSON.stringify(report, null, 2) : renderAccessReport(report));
31839
32017
  if (!report.ok) process.exitCode = 1;
@@ -31866,16 +32044,16 @@ function directoryBytes(path2) {
31866
32044
  let total = 0;
31867
32045
  let entries;
31868
32046
  try {
31869
- entries = (0, import_node_fs34.readdirSync)(path2, { withFileTypes: true });
32047
+ entries = (0, import_node_fs35.readdirSync)(path2, { withFileTypes: true });
31870
32048
  } catch {
31871
32049
  return 0;
31872
32050
  }
31873
32051
  for (const entry of entries) {
31874
- const child2 = (0, import_node_path33.join)(path2, entry.name);
32052
+ const child2 = (0, import_node_path34.join)(path2, entry.name);
31875
32053
  if (entry.isDirectory()) total += directoryBytes(child2);
31876
32054
  else {
31877
32055
  try {
31878
- total += (0, import_node_fs34.statSync)(child2).size;
32056
+ total += (0, import_node_fs35.statSync)(child2).size;
31879
32057
  } catch {
31880
32058
  }
31881
32059
  }
@@ -31883,25 +32061,25 @@ function directoryBytes(path2) {
31883
32061
  return total;
31884
32062
  }
31885
32063
  function listDirEntries(dir) {
31886
- return (0, import_node_fs34.readdirSync)(dir, { withFileTypes: true }).map((d) => ({ name: d.name, isDirectory: d.isDirectory() }));
32064
+ return (0, import_node_fs35.readdirSync)(dir, { withFileTypes: true }).map((d) => ({ name: d.name, isDirectory: d.isDirectory() }));
31887
32065
  }
31888
32066
  function readInstalledPluginRefs(configRoot) {
31889
32067
  const p = installedPluginsPathForConfig(configRoot);
31890
- if (!(0, import_node_fs34.existsSync)(p)) return [];
32068
+ if (!(0, import_node_fs35.existsSync)(p)) return [];
31891
32069
  try {
31892
- return installedPluginPaths((0, import_node_fs34.readFileSync)(p, "utf8"));
32070
+ return installedPluginPaths((0, import_node_fs35.readFileSync)(p, "utf8"));
31893
32071
  } catch {
31894
32072
  return null;
31895
32073
  }
31896
32074
  }
31897
32075
  function pluginCacheFsDeps(configRoot, dirBytes) {
31898
32076
  return {
31899
- exists: (p) => (0, import_node_fs34.existsSync)(p),
31900
- listVersionDirs: (root) => (0, import_node_fs34.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name),
32077
+ exists: (p) => (0, import_node_fs35.existsSync)(p),
32078
+ listVersionDirs: (root) => (0, import_node_fs35.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name),
31901
32079
  dirBytes,
31902
- listStagingDirs: (root) => (0, import_node_fs34.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => {
32080
+ listStagingDirs: (root) => (0, import_node_fs35.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => {
31903
32081
  try {
31904
- return { name: d.name, mtimeMs: newestMtimeMs((0, import_node_path33.join)(root, d.name), listDirEntries, (p) => (0, import_node_fs34.statSync)(p).mtimeMs) };
32082
+ return { name: d.name, mtimeMs: newestMtimeMs((0, import_node_path34.join)(root, d.name), listDirEntries, (p) => (0, import_node_fs35.statSync)(p).mtimeMs) };
31905
32083
  } catch {
31906
32084
  return { name: d.name, mtimeMs: Date.now() };
31907
32085
  }
@@ -31915,10 +32093,10 @@ function stagingApplyFsGuard(configRoot) {
31915
32093
  return {
31916
32094
  referencedPaths: () => readInstalledPluginRefs(configRoot),
31917
32095
  mtimeMs: (name) => {
31918
- const p = (0, import_node_path33.join)(stagingRoot, name);
31919
- if (!(0, import_node_fs34.existsSync)(p)) return null;
32096
+ const p = (0, import_node_path34.join)(stagingRoot, name);
32097
+ if (!(0, import_node_fs35.existsSync)(p)) return null;
31920
32098
  try {
31921
- return newestMtimeMs(p, listDirEntries, (q) => (0, import_node_fs34.statSync)(q).mtimeMs);
32099
+ return newestMtimeMs(p, listDirEntries, (q) => (0, import_node_fs35.statSync)(q).mtimeMs);
31922
32100
  } catch {
31923
32101
  return null;
31924
32102
  }
@@ -31944,7 +32122,7 @@ program2.command("plugin-prune").description(`prune stale cached MMI plugin vers
31944
32122
  { withBytes: true, configRoot, includeStaging: surface !== "codex" }
31945
32123
  );
31946
32124
  const anythingToDelete = plan.prune.length > 0 || plan.staging.length > 0;
31947
- const result = o.apply && anythingToDelete ? applyPluginCachePlan(plan, (p) => (0, import_node_fs34.rmSync)(p, { recursive: true, force: true }), stagingApplyFsGuard(configRoot)) : void 0;
32125
+ const result = o.apply && anythingToDelete ? applyPluginCachePlan(plan, (p) => (0, import_node_fs35.rmSync)(p, { recursive: true, force: true }), stagingApplyFsGuard(configRoot)) : void 0;
31948
32126
  const warnings = plan.prune.length > 0 ? [CONCURRENT_SESSION_WARNING] : [];
31949
32127
  if (o.json) console.log(JSON.stringify({ ...plan, warnings, applied: result ?? null }));
31950
32128
  else console.log(renderPluginCachePlan(plan, result));
@@ -32007,7 +32185,7 @@ program2.command("session-start").description("run the SessionStart verbs (whoam
32007
32185
  for (const line of scratchGcLines(process.cwd())) bannerIo.log(line);
32008
32186
  const worktreeBanner = worktreeAutoProvisionBanner(process.cwd());
32009
32187
  if (worktreeBanner) {
32010
- spawnDetachedSelf(["worktree", "setup", "--quiet"], { spawn: import_node_child_process15.spawn, execPath: process.execPath, scriptPath: process.argv[1] });
32188
+ spawnDetachedSelf(["worktree", "setup", "--quiet"], { spawn: import_node_child_process16.spawn, execPath: process.execPath, scriptPath: process.argv[1] });
32011
32189
  bannerIo.log(worktreeBanner);
32012
32190
  }
32013
32191
  if (isLinkedWorktree(process.cwd())) {