@mutmutco/cli 4.5.159 → 4.5.160

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.
package/dist/main.cjs CHANGED
@@ -589,6 +589,54 @@ var init_github_client = __esm({
589
589
  }
590
590
  });
591
591
 
592
+ // src/gh-read-route.ts
593
+ function isViewerFreeGhRead(args) {
594
+ if (args.some((a) => VIEWER.test(a))) return false;
595
+ const [group, verb] = args;
596
+ if (group === "api") return isReadOnlyApi(args.slice(1));
597
+ return Boolean(group && verb && READ_VERBS.get(group)?.has(verb));
598
+ }
599
+ function isReadOnlyApi(rest) {
600
+ let path2;
601
+ for (let i = 0; i < rest.length; i++) {
602
+ const a = rest[i];
603
+ if (a === "-X" || a === "--method") {
604
+ if ((rest[i + 1] ?? "").toUpperCase() !== "GET") return false;
605
+ i++;
606
+ } else if (/^--method=/.test(a)) {
607
+ if (a.slice(9).toUpperCase() !== "GET") return false;
608
+ } else if (a === "-f" || a === "-F" || a === "--field" || a === "--raw-field") {
609
+ const field = rest[i + 1] ?? "";
610
+ if (path2 !== "graphql" || !/^query=\s*(query\b|\{)/.test(field) || /projectV2|projectsV2/.test(field)) return false;
611
+ i++;
612
+ } else if (a === "--input" || a.startsWith("--input=")) {
613
+ return false;
614
+ } else if (a === "-H" || a === "--header" || a === "-q" || a === "--jq" || a === "-t" || a === "--template" || a === "--hostname" || a === "--cache") {
615
+ i++;
616
+ } else if (!a.startsWith("-") && path2 === void 0) {
617
+ path2 = a.replace(/^\//, "");
618
+ }
619
+ }
620
+ if (!path2) return false;
621
+ if (path2 === "graphql") return rest.some((a) => /^query=\s*(query\b|\{)/.test(a));
622
+ return !/^(user|users\/[^/]+\/|notifications|search\/|orgs\/[^/]+\/projectsV2|graphql)/.test(path2);
623
+ }
624
+ var READ_VERBS, VIEWER;
625
+ var init_gh_read_route = __esm({
626
+ "src/gh-read-route.ts"() {
627
+ "use strict";
628
+ READ_VERBS = /* @__PURE__ */ new Map([
629
+ ["pr", /* @__PURE__ */ new Set(["view", "list", "checks", "diff"])],
630
+ ["issue", /* @__PURE__ */ new Set(["view", "list"])],
631
+ ["run", /* @__PURE__ */ new Set(["view", "list", "watch"])],
632
+ ["label", /* @__PURE__ */ new Set(["list"])],
633
+ ["release", /* @__PURE__ */ new Set(["view", "list"])],
634
+ ["repo", /* @__PURE__ */ new Set(["view"])]
635
+ ]);
636
+ VIEWER = /@me\b|viewer|project/i;
637
+ }
638
+ });
639
+
592
640
  // src/github-quota.ts
593
641
  function hubQuotaResetWaitMs(resetAt, nowMs, capMs = RATE_LIMIT_WAIT_CAP_MS, jitterMs = 0) {
594
642
  if (typeof resetAt !== "string" || !resetAt) return void 0;
@@ -959,6 +1007,8 @@ var init_house_map = __esm({
959
1007
  pr: "devops",
960
1008
  read: "devops",
961
1009
  // closed typed GitHub reads on the App pool (run/pr/issue broker, #8042)
1010
+ github: "devops",
1011
+ // personal and App allowance visibility
962
1012
  api: "devops",
963
1013
  // allowlisted GitHub REST GET reads for automation (pull files, compare, contents)
964
1014
  ci: "devops",
@@ -1110,8 +1160,18 @@ __export(cli_shared_exports, {
1110
1160
  rawValue: () => rawValue,
1111
1161
  readStdin: () => readStdin,
1112
1162
  repoProject: () => repoProject,
1163
+ setGhReadTokenProvider: () => setGhReadTokenProvider,
1113
1164
  setInjectedStdin: () => setInjectedStdin
1114
1165
  });
1166
+ function setGhReadTokenProvider(provider) {
1167
+ ghReadTokenProvider = provider;
1168
+ }
1169
+ async function ghReadAppEnv(file, args) {
1170
+ if (!ghReadTokenProvider || !/(^|[\\/])gh(\.exe)?$/i.test(file) || process.env.MMI_ACTOR?.trim() === "personal") return void 0;
1171
+ if (!isViewerFreeGhRead(args)) return void 0;
1172
+ const token = await ghReadTokenProvider().catch(() => void 0);
1173
+ return token ? { ...process.env, GH_TOKEN: token } : void 0;
1174
+ }
1115
1175
  function killProcessTree(pid) {
1116
1176
  try {
1117
1177
  if (process.platform === "win32") {
@@ -1280,7 +1340,7 @@ function printLine(value) {
1280
1340
  (0, import_node_fs5.writeSync)(1, `${value}
1281
1341
  `);
1282
1342
  }
1283
- var import_node_child_process2, import_node_fs5, import_node_util3, rawExecFileP, DEFAULT_EXEC_TIMEOUT_MS, execFileP, GIT_TIMEOUT_MS, ExecDeadlineError, cachedGithubLogin, gitOut, consoleIo;
1343
+ var import_node_child_process2, import_node_fs5, import_node_util3, rawExecFileP, DEFAULT_EXEC_TIMEOUT_MS, execFileP, ghReadTokenProvider, GIT_TIMEOUT_MS, ExecDeadlineError, cachedGithubLogin, gitOut, consoleIo;
1284
1344
  var init_cli_shared = __esm({
1285
1345
  "src/cli-shared.ts"() {
1286
1346
  "use strict";
@@ -1292,16 +1352,27 @@ var init_cli_shared = __esm({
1292
1352
  init_clean_exit();
1293
1353
  init_error_codes();
1294
1354
  init_github_client();
1355
+ init_gh_read_route();
1295
1356
  init_hub_auth();
1296
1357
  init_house_map();
1297
1358
  init_stdin_inject();
1298
1359
  rawExecFileP = (0, import_node_util3.promisify)(import_node_child_process2.execFile);
1299
1360
  DEFAULT_EXEC_TIMEOUT_MS = 1e4;
1300
- execFileP = (file, args, options = {}) => (
1301
- // encoding 'utf8' guarantees string stdout/stderr at runtime; the cast pins the type because
1302
- // promisify(execFile)'s overloads widen to string|Buffer when options is spread in.
1303
- rawExecFileP(file, args, { encoding: "utf8", windowsHide: true, timeout: DEFAULT_EXEC_TIMEOUT_MS, killSignal: "SIGTERM", ...options })
1304
- );
1361
+ execFileP = async (file, args, options = {}) => {
1362
+ const run = (env) => (
1363
+ // encoding 'utf8' guarantees string stdout/stderr at runtime; the cast pins the type because
1364
+ // promisify(execFile)'s overloads widen to string|Buffer when options is spread in.
1365
+ rawExecFileP(file, args, { encoding: "utf8", windowsHide: true, timeout: DEFAULT_EXEC_TIMEOUT_MS, killSignal: "SIGTERM", ...options, ...env ? { env } : {} })
1366
+ );
1367
+ const appEnv = options.env ? void 0 : await ghReadAppEnv(file, args);
1368
+ if (!appEnv) return run();
1369
+ try {
1370
+ return await run(appEnv);
1371
+ } catch (e) {
1372
+ if (/Resource not accessible by integration/i.test(String(e.stderr ?? ""))) return run();
1373
+ throw e;
1374
+ }
1375
+ };
1305
1376
  GIT_TIMEOUT_MS = DEFAULT_EXEC_TIMEOUT_MS;
1306
1377
  ExecDeadlineError = class extends Error {
1307
1378
  constructor(step, timeoutMs, elapsedMs, killed) {
@@ -4755,7 +4826,7 @@ function useColor() {
4755
4826
  var program = new Command();
4756
4827
 
4757
4828
  // src/command-composition.ts
4758
- var import_node_fs58 = require("node:fs");
4829
+ var import_node_fs59 = require("node:fs");
4759
4830
  init_clean_exit();
4760
4831
  init_cli_shared();
4761
4832
 
@@ -6949,7 +7020,7 @@ var import_node_os25 = require("node:os");
6949
7020
  var import_node_path57 = require("node:path");
6950
7021
 
6951
7022
  // src/board-read.ts
6952
- var import_node_fs16 = require("node:fs");
7023
+ var import_node_fs17 = require("node:fs");
6953
7024
  var import_node_os10 = require("node:os");
6954
7025
  var import_node_path14 = require("node:path");
6955
7026
  init_cli_shared();
@@ -7167,6 +7238,19 @@ async function readAppVaultSecret(read) {
7167
7238
  async function mintInstallationToken(deps) {
7168
7239
  return mintScopedInstallationToken(deps, APP_POLL_PERMISSIONS);
7169
7240
  }
7241
+ var APP_WRITE_COMMANDS = /* @__PURE__ */ new Map([
7242
+ ["issue comment", { metadata: "read", issues: "write", pull_requests: "write" }]
7243
+ ]);
7244
+ async function mintCommandWriteToken(deps, commandPath3) {
7245
+ const permissions = APP_WRITE_COMMANDS.get(commandPath3);
7246
+ if (!permissions) throw new AppActorError(`app actor: '${commandPath3}' has no App write profile`);
7247
+ try {
7248
+ return await mintFromMember(deps, permissions, APP_VAULT_KEYS);
7249
+ } catch (e) {
7250
+ if (e instanceof AppActorError) throw e;
7251
+ throw new AppActorError(`app actor: write token mint failed (${e?.constructor?.name ?? "Error"})`);
7252
+ }
7253
+ }
7170
7254
  async function mintStatusWriteToken(deps) {
7171
7255
  return mintScopedInstallationToken(deps, { metadata: "read", statuses: "write" });
7172
7256
  }
@@ -7227,6 +7311,9 @@ async function allowanceSpent(deps, token) {
7227
7311
  return false;
7228
7312
  }
7229
7313
  }
7314
+ function mintBudgetToken(deps, keys) {
7315
+ return mintFromMember(deps, { metadata: "read" }, keys);
7316
+ }
7230
7317
  async function mintFromMember(deps, permissions, keys) {
7231
7318
  const [appId, installationId, privateKey] = await Promise.all(keys.map((k) => deps.fetchSecret(k)));
7232
7319
  if (!appId || !installationId || !privateKey) {
@@ -7294,7 +7381,7 @@ async function activateAppActor(commandPath3, env, mint, note = (line) => proces
7294
7381
  if (requested && requested !== "app") {
7295
7382
  throw new AppActorError(`app actor: unknown ${APP_ACTOR_ENV} value \u2014 only 'app' and 'personal' are supported; refusing to guess an identity`);
7296
7383
  }
7297
- if (!APP_ELIGIBLE_COMMANDS.has(commandPath3)) {
7384
+ if (!APP_ELIGIBLE_COMMANDS.has(commandPath3) && !APP_WRITE_COMMANDS.has(commandPath3)) {
7298
7385
  if (requested === "app" && !notedIneligibleCommand) {
7299
7386
  notedIneligibleCommand = true;
7300
7387
  note(`app actor: '${commandPath3}' is personal-only (viewer/@me/authorship) \u2014 running on the personal token despite ${APP_ACTOR_ENV}=app`);
@@ -11301,6 +11388,7 @@ init_clean_exit();
11301
11388
 
11302
11389
  // src/gh-create.ts
11303
11390
  var import_promises = require("node:fs/promises");
11391
+ var import_node_fs16 = require("node:fs");
11304
11392
  var import_node_os8 = require("node:os");
11305
11393
  var import_node_path13 = require("node:path");
11306
11394
  var import_node_crypto7 = require("node:crypto");
@@ -11566,18 +11654,23 @@ async function preflightPrCreateRemoteHead(args, deps) {
11566
11654
  if (compared !== "unknown" && compared.aheadBy <= 0) return emptyCompareMessage(base, head);
11567
11655
  return void 0;
11568
11656
  }
11657
+ function retryBodyFile(args) {
11658
+ const file = flagValue(args, "--body-file");
11659
+ if (file !== void 0) return file;
11660
+ const body = flagValue(args, "--body");
11661
+ if (body === void 0) return void 0;
11662
+ const path2 = (0, import_node_path13.join)((0, import_node_fs16.mkdtempSync)((0, import_node_path13.join)((0, import_node_os8.tmpdir)(), "mmi-create-retry-")), "body.md");
11663
+ (0, import_node_fs16.writeFileSync)(path2, body, "utf8");
11664
+ return path2;
11665
+ }
11569
11666
  function buildPrCreateRetryCommand(args) {
11570
11667
  const parts = ["mmi-cli", "devops", "pr", "create"];
11571
11668
  for (const flag of ["--repo", "--base", "--head", "--title"]) {
11572
11669
  const v = flagValue(args, flag);
11573
11670
  if (v !== void 0) parts.push(flag, shellQuote(v));
11574
11671
  }
11575
- const bodyFile = flagValue(args, "--body-file");
11672
+ const bodyFile = retryBodyFile(args);
11576
11673
  if (bodyFile !== void 0) parts.push("--body-file", shellQuote(bodyFile));
11577
- else {
11578
- const body = flagValue(args, "--body");
11579
- if (body !== void 0) parts.push("--body", shellQuote(body));
11580
- }
11581
11674
  if (args.includes("--draft")) parts.push("--draft");
11582
11675
  return parts.join(" ");
11583
11676
  }
@@ -11600,12 +11693,8 @@ function buildIssueCreateRetryCommand(args) {
11600
11693
  if (type) parts.push("--type", type);
11601
11694
  const title = flagValue(args, "--title");
11602
11695
  if (title !== void 0) parts.push("--title", shellQuote(title));
11603
- const bodyFile = flagValue(args, "--body-file");
11696
+ const bodyFile = retryBodyFile(args);
11604
11697
  if (bodyFile !== void 0) parts.push("--body-file", shellQuote(bodyFile));
11605
- else {
11606
- const body = flagValue(args, "--body");
11607
- if (body !== void 0) parts.push("--body", shellQuote(body));
11608
- }
11609
11698
  for (const label of labels) {
11610
11699
  if (label === type) continue;
11611
11700
  parts.push("--label", shellQuote(label));
@@ -14562,11 +14651,11 @@ function probeLocalClaimSession(marker, now = Date.now()) {
14562
14651
  const pending = [root];
14563
14652
  while (pending.length) {
14564
14653
  const dir = pending.pop();
14565
- for (const entry of (0, import_node_fs16.readdirSync)(dir, { withFileTypes: true })) {
14654
+ for (const entry of (0, import_node_fs17.readdirSync)(dir, { withFileTypes: true })) {
14566
14655
  const path2 = (0, import_node_path14.join)(dir, entry.name);
14567
14656
  if (entry.isDirectory()) pending.push(path2);
14568
14657
  else if (entry.isFile() && entry.name.toLowerCase() === wanted) {
14569
- return remember(now - (0, import_node_fs16.statSync)(path2).mtimeMs <= CLAIM_SESSION_ACTIVITY_MS ? "live" : "dead");
14658
+ return remember(now - (0, import_node_fs17.statSync)(path2).mtimeMs <= CLAIM_SESSION_ACTIVITY_MS ? "live" : "dead");
14570
14659
  }
14571
14660
  }
14572
14661
  }
@@ -16071,12 +16160,12 @@ function planManagedGitignore(current) {
16071
16160
  }
16072
16161
 
16073
16162
  // src/docs-index-command.ts
16074
- var import_node_fs18 = require("node:fs");
16163
+ var import_node_fs19 = require("node:fs");
16075
16164
  var import_node_path16 = require("node:path");
16076
16165
 
16077
16166
  // src/doc-refs-core.ts
16078
16167
  var import_node_child_process6 = require("node:child_process");
16079
- var import_node_fs17 = require("node:fs");
16168
+ var import_node_fs18 = require("node:fs");
16080
16169
  var import_node_path15 = require("node:path");
16081
16170
  var PIN_RE = /<!--\s*pinned by\s+([^:]+?)\s*:\s*"([^"]+)"[^"]*-->/;
16082
16171
  var PIN_MENTION_RE = /<!--\s*pinned by\b/;
@@ -16449,12 +16538,12 @@ function checkSeedRunbookReview(root, base, readFile10, git3) {
16449
16538
  return findings;
16450
16539
  }
16451
16540
  function readFileOrNull(path2) {
16452
- return (0, import_node_fs17.existsSync)(path2) ? (0, import_node_fs17.readFileSync)(path2, "utf8") : null;
16541
+ return (0, import_node_fs18.existsSync)(path2) ? (0, import_node_fs18.readFileSync)(path2, "utf8") : null;
16453
16542
  }
16454
16543
  function walk(dir, root, out) {
16455
- for (const entry of (0, import_node_fs17.readdirSync)(dir)) {
16544
+ for (const entry of (0, import_node_fs18.readdirSync)(dir)) {
16456
16545
  const full = (0, import_node_path15.join)(dir, entry);
16457
- if ((0, import_node_fs17.statSync)(full).isDirectory()) walk(full, root, out);
16546
+ if ((0, import_node_fs18.statSync)(full).isDirectory()) walk(full, root, out);
16458
16547
  else if (entry.endsWith(".md")) out.push(full.slice(root.length + 1).replaceAll("\\", "/"));
16459
16548
  }
16460
16549
  return out;
@@ -16462,11 +16551,11 @@ function walk(dir, root, out) {
16462
16551
  function defaultListDocs(root) {
16463
16552
  const docs = ["docs", "skills/org-guide", "skills/mmi-help"].flatMap((path2) => {
16464
16553
  const directory = (0, import_node_path15.join)(root, path2);
16465
- return (0, import_node_fs17.existsSync)(directory) ? walk(directory, root, []) : [];
16554
+ return (0, import_node_fs18.existsSync)(directory) ? walk(directory, root, []) : [];
16466
16555
  }).filter(
16467
16556
  (rel) => !SKIP_WALK.some((skip) => rel.startsWith(skip))
16468
16557
  );
16469
- return [...ROOT_DOCS.filter((rel) => (0, import_node_fs17.existsSync)((0, import_node_path15.join)(root, rel))), ...docs];
16558
+ return [...ROOT_DOCS.filter((rel) => (0, import_node_fs18.existsSync)((0, import_node_path15.join)(root, rel))), ...docs];
16470
16559
  }
16471
16560
  var CHECK_IGNORE_MAX_BUFFER = 32 * 1024 * 1024;
16472
16561
  function defaultIsIgnored(root, relPaths, exec3 = import_node_child_process6.execFileSync) {
@@ -16547,7 +16636,7 @@ function mergeGroupRunbookMessages(root, deps, readFile10, warnings) {
16547
16636
  }
16548
16637
  function runDocRefs(root, deps = {}) {
16549
16638
  const readFile10 = deps.readFile ?? readFileOrNull;
16550
- const exists = deps.exists ?? import_node_fs17.existsSync;
16639
+ const exists = deps.exists ?? import_node_fs18.existsSync;
16551
16640
  const listDocs = deps.listDocs ?? defaultListDocs;
16552
16641
  const isIgnored = deps.isIgnored ?? ((paths) => defaultIsIgnored(root, paths));
16553
16642
  const trackedFirstSegments = deps.trackedFirstSegments ?? ((segs) => defaultTrackedFirstSegments(root, segs));
@@ -16680,7 +16769,7 @@ function walkMarkdown(dir) {
16680
16769
  const stack = [dir];
16681
16770
  while (stack.length) {
16682
16771
  const current = stack.pop();
16683
- for (const entry of (0, import_node_fs18.readdirSync)(current, { withFileTypes: true })) {
16772
+ for (const entry of (0, import_node_fs19.readdirSync)(current, { withFileTypes: true })) {
16684
16773
  const full = (0, import_node_path16.join)(current, entry.name);
16685
16774
  if (entry.isDirectory()) {
16686
16775
  stack.push(full);
@@ -16696,15 +16785,15 @@ function createDocsIndexDeps(repoRoot2) {
16696
16785
  const indexPath = (0, import_node_path16.join)(repoRoot2, DOCS_INDEX_PATH);
16697
16786
  return {
16698
16787
  listDocs: () => {
16699
- if (!(0, import_node_fs18.existsSync)(docsDir)) return [];
16788
+ if (!(0, import_node_fs19.existsSync)(docsDir)) return [];
16700
16789
  const walked = walkMarkdown(docsDir).filter(isRoutableDocsPath);
16701
16790
  if (!walked.length) return [];
16702
16791
  const ignored = defaultIsIgnored(repoRoot2, walked.map((rel) => `docs/${rel}`));
16703
16792
  return walked.filter((rel) => !ignored.has(`docs/${rel}`)).sort();
16704
16793
  },
16705
- readDoc: (relPath) => (0, import_node_fs18.readFileSync)((0, import_node_path16.join)(docsDir, relPath), "utf8"),
16706
- readIndex: () => (0, import_node_fs18.existsSync)(indexPath) ? (0, import_node_fs18.readFileSync)(indexPath, "utf8") : null,
16707
- writeIndex: (content) => (0, import_node_fs18.writeFileSync)(indexPath, content, "utf8")
16794
+ readDoc: (relPath) => (0, import_node_fs19.readFileSync)((0, import_node_path16.join)(docsDir, relPath), "utf8"),
16795
+ readIndex: () => (0, import_node_fs19.existsSync)(indexPath) ? (0, import_node_fs19.readFileSync)(indexPath, "utf8") : null,
16796
+ writeIndex: (content) => (0, import_node_fs19.writeFileSync)(indexPath, content, "utf8")
16708
16797
  };
16709
16798
  }
16710
16799
 
@@ -17623,7 +17712,7 @@ function contentPutInputArgs(repo, path2, inputFile) {
17623
17712
  }
17624
17713
 
17625
17714
  // src/train-apply-contracts.ts
17626
- var import_node_fs19 = require("node:fs");
17715
+ var import_node_fs20 = require("node:fs");
17627
17716
  var import_node_path17 = require("node:path");
17628
17717
  function reduceFollowUpOutcomes(outcomes) {
17629
17718
  if (outcomes.includes("failure")) return "failure";
@@ -17704,7 +17793,7 @@ async function resolveFoldPaths(deps, model) {
17704
17793
  if (model === "vercel") return [];
17705
17794
  const helper = "scripts/release-distribution.mjs";
17706
17795
  if (model === "hub-serverless" || model === "registry-publish") {
17707
- if ((0, import_node_fs19.existsSync)(helper)) {
17796
+ if ((0, import_node_fs20.existsSync)(helper)) {
17708
17797
  let out;
17709
17798
  try {
17710
17799
  out = await deps.run("node", [helper, "changed-files"]);
@@ -17853,7 +17942,7 @@ async function restoreMainNpmPackIdentities(deps, version) {
17853
17942
  if (mainBom.version !== version) return void 0;
17854
17943
  let localBom;
17855
17944
  try {
17856
- localBom = JSON.parse((0, import_node_fs19.readFileSync)(bomPath, "utf8"));
17945
+ localBom = JSON.parse((0, import_node_fs20.readFileSync)(bomPath, "utf8"));
17857
17946
  } catch (e) {
17858
17947
  throw new Error(
17859
17948
  `version fold refused: ${bomPath} written by this fold's prepare is unreadable (${describeReadError(e)}) \u2014 cannot restore the published ${version} npm-pack identities from origin/main (#4503/#4713).`
@@ -17871,14 +17960,14 @@ async function restoreMainNpmPackIdentities(deps, version) {
17871
17960
  restored += 1;
17872
17961
  }
17873
17962
  if (restored === 0) return void 0;
17874
- (0, import_node_fs19.writeFileSync)(bomPath, `${JSON.stringify(localBom, null, 2)}
17963
+ (0, import_node_fs20.writeFileSync)(bomPath, `${JSON.stringify(localBom, null, 2)}
17875
17964
  `);
17876
17965
  return `restored ${restored} npm-pack BOM identit${restored === 1 ? "y" : "ies"} from origin/main (#4503)`;
17877
17966
  }
17878
17967
  function publishVisibilityFor(surfaceId) {
17879
17968
  let raw;
17880
17969
  try {
17881
- raw = (0, import_node_fs19.readFileSync)("surfaces.json", "utf8");
17970
+ raw = (0, import_node_fs20.readFileSync)("surfaces.json", "utf8");
17882
17971
  } catch (e) {
17883
17972
  if (e.code === "ENOENT") return "unknown";
17884
17973
  throw trainReadFailure(
@@ -17899,7 +17988,7 @@ function publishVisibilityFor(surfaceId) {
17899
17988
  }
17900
17989
  function npmPackArtifactName(packagePath) {
17901
17990
  try {
17902
- const pkg = JSON.parse((0, import_node_fs19.readFileSync)((0, import_node_path17.join)(packagePath, "package.json"), "utf8"));
17991
+ const pkg = JSON.parse((0, import_node_fs20.readFileSync)((0, import_node_path17.join)(packagePath, "package.json"), "utf8"));
17903
17992
  return pkg.name || void 0;
17904
17993
  } catch {
17905
17994
  return void 0;
@@ -17908,7 +17997,7 @@ function npmPackArtifactName(packagePath) {
17908
17997
  async function refuseDivergentPublishedNpmPack(deps, version) {
17909
17998
  let localBom;
17910
17999
  try {
17911
- localBom = JSON.parse((0, import_node_fs19.readFileSync)("distribution-bom.json", "utf8"));
18000
+ localBom = JSON.parse((0, import_node_fs20.readFileSync)("distribution-bom.json", "utf8"));
17912
18001
  } catch (e) {
17913
18002
  throw new Error(
17914
18003
  `version fold refused: distribution-bom.json written by this fold's prepare is unreadable (${e instanceof Error ? e.message.split("\n")[0] : String(e)}) \u2014 cannot compare the same-PATCH ${version} npm-pack identities against published npm (#4503/#4662).`
@@ -18053,7 +18142,7 @@ function assertGitBashOnWindowsForJervHubRelease(repo, platform2 = process.platf
18053
18142
  }
18054
18143
 
18055
18144
  // src/train-apply-correlation.ts
18056
- var import_node_fs21 = require("node:fs");
18145
+ var import_node_fs22 = require("node:fs");
18057
18146
  init_github_quota();
18058
18147
  var import_node_path19 = require("node:path");
18059
18148
 
@@ -18820,10 +18909,10 @@ var rollout_plan_default = {
18820
18909
  note: "The v4.0.0 stamp happens at cut time (D6e #4463); until then the candidate is the origin/development head artifacts (built cli/dist + npm pack), identity proven by dist content hash (D6a)."
18821
18910
  },
18822
18911
  baseline: {
18823
- version: "4.5.159",
18824
- tag: "v4.5.159",
18825
- commit: "daaf02084d87",
18826
- npm: "@mutmutco/cli@4.5.159"
18912
+ version: "4.5.160",
18913
+ tag: "v4.5.160",
18914
+ commit: "05c3cc8d56ee",
18915
+ npm: "@mutmutco/cli@4.5.160"
18827
18916
  },
18828
18917
  exitCriterion: "fleet-n-of-n",
18829
18918
  hubOnlyShortcut: "forbidden",
@@ -18840,14 +18929,14 @@ var rollout_plan_default = {
18840
18929
  repo: "mutmutco/mmi-hub",
18841
18930
  role: "canary",
18842
18931
  schedule: "train",
18843
- v3Target: "v4.5.159"
18932
+ v3Target: "v4.5.160"
18844
18933
  }
18845
18934
  ],
18846
18935
  rollbackTrigger: "Any red inside the post-contract soak window: `devops train gate` FAIL attributable to the v4 doors, Hub endpoint health probe failure, a pre-v4 client admitted instead of receiving actionable HTTP 426, or npm consumer install/doctor failure on the v4-only dist.",
18847
18936
  rollback: {
18848
18937
  independent: true,
18849
- mechanism: "npm dist-tag latest -> 4.5.159 and redeploy the Hub Lambda from tag v4.5.159 (daaf02084d87); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
18850
- v3Target: "v4.5.159 (@mutmutco/cli@4.5.159, tag commit daaf02084d87 \u2014 last known-good release carrying the repo-index v4-only contract)"
18938
+ mechanism: "npm dist-tag latest -> 4.5.160 and redeploy the Hub Lambda from tag v4.5.160 (05c3cc8d56ee); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
18939
+ v3Target: "v4.5.160 (@mutmutco/cli@4.5.160, tag commit 05c3cc8d56ee \u2014 last known-good release carrying the repo-index v4-only contract)"
18851
18940
  }
18852
18941
  },
18853
18942
  {
@@ -19181,13 +19270,13 @@ function resolveIssueViewGhFields(normalized) {
19181
19270
  }
19182
19271
 
19183
19272
  // src/utf8-receipt.ts
19184
- var import_node_fs20 = require("node:fs");
19273
+ var import_node_fs21 = require("node:fs");
19185
19274
  var import_node_path18 = require("node:path");
19186
19275
  function writeUtf8Receipt(path2, text) {
19187
- (0, import_node_fs20.mkdirSync)((0, import_node_path18.dirname)(path2), { recursive: true });
19276
+ (0, import_node_fs21.mkdirSync)((0, import_node_path18.dirname)(path2), { recursive: true });
19188
19277
  const body = text.endsWith("\n") ? text : `${text}
19189
19278
  `;
19190
- (0, import_node_fs20.writeFileSync)(path2, body, "utf8");
19279
+ (0, import_node_fs21.writeFileSync)(path2, body, "utf8");
19191
19280
  return Buffer.byteLength(body, "utf8");
19192
19281
  }
19193
19282
 
@@ -21073,7 +21162,7 @@ function resolveReleaseAbortNpmPackage(meta, repo) {
21073
21162
  if (isHubControlRepo(repo)) return "@mutmutco/cli";
21074
21163
  const publishDir = typeof meta.publishDir === "string" && meta.publishDir.trim() ? meta.publishDir.trim() : ".";
21075
21164
  try {
21076
- const pkg = JSON.parse((0, import_node_fs21.readFileSync)((0, import_node_path19.join)(publishDir, "package.json"), "utf8"));
21165
+ const pkg = JSON.parse((0, import_node_fs22.readFileSync)((0, import_node_path19.join)(publishDir, "package.json"), "utf8"));
21077
21166
  const name = pkg.name?.trim();
21078
21167
  if (!name) throw new Error("missing name field");
21079
21168
  return name;
@@ -22009,7 +22098,7 @@ function parseVerifyBroker(stdout) {
22009
22098
  }
22010
22099
 
22011
22100
  // src/train-apply-deploy.ts
22012
- var import_node_fs22 = require("node:fs");
22101
+ var import_node_fs23 = require("node:fs");
22013
22102
  var import_node_os11 = require("node:os");
22014
22103
  var import_node_path20 = require("node:path");
22015
22104
 
@@ -22150,7 +22239,7 @@ function mmiGetRedeployCommand(repo) {
22150
22239
  }
22151
22240
  function readLocalLauncherVersion(root = process.cwd()) {
22152
22241
  try {
22153
- const raw = (0, import_node_fs22.readFileSync)((0, import_node_path20.join)(root, "cli", "package.json"), "utf8");
22242
+ const raw = (0, import_node_fs23.readFileSync)((0, import_node_path20.join)(root, "cli", "package.json"), "utf8");
22154
22243
  const version = JSON.parse(raw).version;
22155
22244
  return typeof version === "string" && version.trim() ? version.trim() : null;
22156
22245
  } catch {
@@ -22159,7 +22248,7 @@ function readLocalLauncherVersion(root = process.cwd()) {
22159
22248
  }
22160
22249
  function readServedChannelUrl(product = HUB_SERVED_PRODUCT, root = process.cwd()) {
22161
22250
  try {
22162
- const raw = (0, import_node_fs22.readFileSync)((0, import_node_path20.join)(root, "config", `product.${product}.json`), "utf8");
22251
+ const raw = (0, import_node_fs23.readFileSync)((0, import_node_path20.join)(root, "config", `product.${product}.json`), "utf8");
22163
22252
  const host = JSON.parse(raw).host;
22164
22253
  if (typeof host !== "string" || !host.trim()) return null;
22165
22254
  return `${host.trim().replace(/\/+$/, "")}/release/version`;
@@ -22593,13 +22682,13 @@ async function runTaggedJervGatewayLocalWrapper(deps, tag, tagSha) {
22593
22682
  const reason = error instanceof Error ? error.message : String(error);
22594
22683
  throw new Error(`could not extract ${JERV_GATEWAY_RELEASE_DEPLOY_SCRIPT} from tagged commit ${tagSha.slice(0, 12)}: ${reason}`);
22595
22684
  }
22596
- const dir = (0, import_node_fs22.mkdtempSync)((0, import_node_path20.join)((0, import_node_os11.tmpdir)(), "jerv-gateway-release-deploy-"));
22685
+ const dir = (0, import_node_fs23.mkdtempSync)((0, import_node_path20.join)((0, import_node_os11.tmpdir)(), "jerv-gateway-release-deploy-"));
22597
22686
  const extracted = (0, import_node_path20.join)(dir, "jerv-gateway-release-deploy.sh");
22598
22687
  try {
22599
- (0, import_node_fs22.writeFileSync)(extracted, script, "utf8");
22688
+ (0, import_node_fs23.writeFileSync)(extracted, script, "utf8");
22600
22689
  return await deps.run("bash", [extracted, "--tag", tag]);
22601
22690
  } finally {
22602
- (0, import_node_fs22.rmSync)(dir, { recursive: true, force: true });
22691
+ (0, import_node_fs23.rmSync)(dir, { recursive: true, force: true });
22603
22692
  }
22604
22693
  }
22605
22694
  async function appendJervGatewayReleaseDeploy(deps, repo, tag, tagSha, dispatch) {
@@ -23175,7 +23264,7 @@ function renderTenantControl(r) {
23175
23264
  }
23176
23265
 
23177
23266
  // src/train-apply-phases.ts
23178
- var import_node_fs28 = require("node:fs");
23267
+ var import_node_fs29 = require("node:fs");
23179
23268
  var import_promises4 = require("node:fs/promises");
23180
23269
  var import_node_path27 = require("node:path");
23181
23270
 
@@ -23494,12 +23583,12 @@ function assertPreOneZero(repo, meta, tag) {
23494
23583
 
23495
23584
  // src/train-doctor.ts
23496
23585
  var import_node_child_process9 = require("node:child_process");
23497
- var import_node_fs26 = require("node:fs");
23586
+ var import_node_fs27 = require("node:fs");
23498
23587
  var import_node_os15 = require("node:os");
23499
23588
  var import_node_path26 = require("node:path");
23500
23589
 
23501
23590
  // src/doctor-io.ts
23502
- var import_node_fs23 = require("node:fs");
23591
+ var import_node_fs24 = require("node:fs");
23503
23592
  var import_node_os12 = require("node:os");
23504
23593
  var import_node_path21 = require("node:path");
23505
23594
  var import_node_child_process7 = require("node:child_process");
@@ -23514,8 +23603,8 @@ function nodeDiscardSinkPath(platform2 = process.platform) {
23514
23603
  var execFileP2 = (0, import_node_util4.promisify)(import_node_child_process7.execFile);
23515
23604
  function execFileCapture(file, args, opts = {}) {
23516
23605
  const sink = nodeDiscardSinkPath();
23517
- const inFd = (0, import_node_fs23.openSync)(sink, "r");
23518
- const errFd = (0, import_node_fs23.openSync)(sink, "w");
23606
+ const inFd = (0, import_node_fs24.openSync)(sink, "r");
23607
+ const errFd = (0, import_node_fs24.openSync)(sink, "w");
23519
23608
  try {
23520
23609
  return (0, import_node_child_process7.execFileSync)(file, args, {
23521
23610
  ...opts,
@@ -23523,17 +23612,17 @@ function execFileCapture(file, args, opts = {}) {
23523
23612
  stdio: [inFd, "pipe", errFd]
23524
23613
  });
23525
23614
  } finally {
23526
- (0, import_node_fs23.closeSync)(inFd);
23527
- (0, import_node_fs23.closeSync)(errFd);
23615
+ (0, import_node_fs24.closeSync)(inFd);
23616
+ (0, import_node_fs24.closeSync)(errFd);
23528
23617
  }
23529
23618
  }
23530
23619
  var MMI_PLUGIN_ID2 = "mmi@mutmutco";
23531
23620
  function stagedClaudePluginVersion() {
23532
23621
  try {
23533
23622
  const stagingRoot = (0, import_node_path21.join)((0, import_node_os12.homedir)(), ".claude", "plugins", "staging");
23534
- const record = JSON.parse((0, import_node_fs23.readFileSync)((0, import_node_path21.join)(stagingRoot, "launch-target.json"), "utf8"));
23623
+ const record = JSON.parse((0, import_node_fs24.readFileSync)((0, import_node_path21.join)(stagingRoot, "launch-target.json"), "utf8"));
23535
23624
  if (typeof record.target !== "string" || typeof record.incoming !== "string") return void 0;
23536
- const manifest = JSON.parse((0, import_node_fs23.readFileSync)((0, import_node_path21.join)(record.incoming, ".claude-plugin", "plugin.json"), "utf8"));
23625
+ const manifest = JSON.parse((0, import_node_fs24.readFileSync)((0, import_node_path21.join)(record.incoming, ".claude-plugin", "plugin.json"), "utf8"));
23537
23626
  if (typeof manifest.version !== "string") return void 0;
23538
23627
  return manifest.version === record.target ? record.target : void 0;
23539
23628
  } catch {
@@ -23543,7 +23632,7 @@ function stagedClaudePluginVersion() {
23543
23632
  function installedClaudePluginVersion() {
23544
23633
  try {
23545
23634
  const file = JSON.parse(
23546
- (0, import_node_fs23.readFileSync)((0, import_node_path21.join)((0, import_node_os12.homedir)(), ".claude", "plugins", "installed_plugins.json"), "utf8")
23635
+ (0, import_node_fs24.readFileSync)((0, import_node_path21.join)((0, import_node_os12.homedir)(), ".claude", "plugins", "installed_plugins.json"), "utf8")
23547
23636
  );
23548
23637
  const versions = (file.plugins?.[MMI_PLUGIN_ID2] ?? []).map((r) => r.version).filter((v) => Boolean(v));
23549
23638
  if (versions.length === 0) return void 0;
@@ -23555,12 +23644,12 @@ function installedClaudePluginVersion() {
23555
23644
  function readHermesPluginEvidence(env = process.env) {
23556
23645
  const host = hermesConfigRoot(env);
23557
23646
  const root = hermesPluginRoot(env);
23558
- const installRecordPresent = (0, import_node_fs23.existsSync)(root);
23647
+ const installRecordPresent = (0, import_node_fs24.existsSync)(root);
23559
23648
  const manifestPath = (0, import_node_path21.join)(root, "plugin.yaml");
23560
23649
  let installedVersion;
23561
23650
  let manifest = "missing";
23562
23651
  try {
23563
- const text = (0, import_node_fs23.readFileSync)(manifestPath, "utf8");
23652
+ const text = (0, import_node_fs24.readFileSync)(manifestPath, "utf8");
23564
23653
  let version;
23565
23654
  try {
23566
23655
  const parsed = JSON.parse(text).version;
@@ -23574,25 +23663,25 @@ function readHermesPluginEvidence(env = process.env) {
23574
23663
  if (version) {
23575
23664
  installedVersion = version;
23576
23665
  manifest = "valid";
23577
- } else if ((0, import_node_fs23.existsSync)(manifestPath)) manifest = "invalid";
23666
+ } else if ((0, import_node_fs24.existsSync)(manifestPath)) manifest = "invalid";
23578
23667
  } catch {
23579
- if ((0, import_node_fs23.existsSync)(manifestPath)) manifest = "invalid";
23668
+ if ((0, import_node_fs24.existsSync)(manifestPath)) manifest = "invalid";
23580
23669
  }
23581
23670
  let skills = false;
23582
23671
  try {
23583
- skills = (0, import_node_fs23.existsSync)((0, import_node_path21.join)(root, "skills")) && (0, import_node_fs23.statSync)((0, import_node_path21.join)(root, "skills")).isDirectory();
23672
+ skills = (0, import_node_fs24.existsSync)((0, import_node_path21.join)(root, "skills")) && (0, import_node_fs24.statSync)((0, import_node_path21.join)(root, "skills")).isDirectory();
23584
23673
  } catch {
23585
23674
  }
23586
23675
  let provisioned = false;
23587
23676
  const provisionedRoot = (0, import_node_path21.join)(host, "skills", "mmi");
23588
23677
  try {
23589
- provisioned = (0, import_node_fs23.existsSync)(provisionedRoot) && (0, import_node_fs23.statSync)(provisionedRoot).isDirectory();
23678
+ provisioned = (0, import_node_fs24.existsSync)(provisionedRoot) && (0, import_node_fs24.statSync)(provisionedRoot).isDirectory();
23590
23679
  } catch {
23591
23680
  }
23592
- const treeOk = (0, import_node_fs23.existsSync)((0, import_node_path21.join)(root, "__init__.py")) && skills && manifest === "valid";
23681
+ const treeOk = (0, import_node_fs24.existsSync)((0, import_node_path21.join)(root, "__init__.py")) && skills && manifest === "valid";
23593
23682
  const receipt = treeOk && !provisioned ? `hermes-skills-unprovisioned:${provisionedRoot}` : void 0;
23594
23683
  return {
23595
- hostPresent: (0, import_node_fs23.existsSync)(host),
23684
+ hostPresent: (0, import_node_fs24.existsSync)(host),
23596
23685
  installRecordPresent,
23597
23686
  manifest,
23598
23687
  payloadPresent: treeOk && provisioned,
@@ -23644,7 +23733,7 @@ function readGitignore() {
23644
23733
  const path2 = gitignorePath();
23645
23734
  if (path2 === null) return null;
23646
23735
  try {
23647
- return (0, import_node_fs23.readFileSync)(path2, "utf8");
23736
+ return (0, import_node_fs24.readFileSync)(path2, "utf8");
23648
23737
  } catch {
23649
23738
  return null;
23650
23739
  }
@@ -23653,14 +23742,14 @@ function writeGitignore(content) {
23653
23742
  const path2 = gitignorePath();
23654
23743
  if (path2 === null) return false;
23655
23744
  try {
23656
- (0, import_node_fs23.writeFileSync)(path2, content, "utf8");
23745
+ (0, import_node_fs24.writeFileSync)(path2, content, "utf8");
23657
23746
  return true;
23658
23747
  } catch {
23659
23748
  return false;
23660
23749
  }
23661
23750
  }
23662
23751
  function lineEndingState(root) {
23663
- const attributesPresent = (0, import_node_fs23.existsSync)((0, import_node_path21.join)(root, ".gitattributes"));
23752
+ const attributesPresent = (0, import_node_fs24.existsSync)((0, import_node_path21.join)(root, ".gitattributes"));
23664
23753
  try {
23665
23754
  const output = execFileCapture("git", ["-C", root, "ls-files", "--eol", "--", ":(glob)**/*.sh"], {
23666
23755
  windowsHide: true
@@ -23703,7 +23792,7 @@ function compatHolds(range, version) {
23703
23792
  }
23704
23793
 
23705
23794
  // src/claude-binary-doctor.ts
23706
- var import_node_fs24 = require("node:fs");
23795
+ var import_node_fs25 = require("node:fs");
23707
23796
  var import_node_os14 = require("node:os");
23708
23797
  var import_node_path23 = require("node:path");
23709
23798
 
@@ -23813,16 +23902,16 @@ function globalNodeModulesRoots(host) {
23813
23902
  function readHead(path2) {
23814
23903
  let fd;
23815
23904
  try {
23816
- fd = (0, import_node_fs24.openSync)(path2, "r");
23905
+ fd = (0, import_node_fs25.openSync)(path2, "r");
23817
23906
  const buffer = new Uint8Array(MAGIC_HEAD_BYTES);
23818
- const read = (0, import_node_fs24.readSync)(fd, buffer, 0, MAGIC_HEAD_BYTES, 0);
23907
+ const read = (0, import_node_fs25.readSync)(fd, buffer, 0, MAGIC_HEAD_BYTES, 0);
23819
23908
  return buffer.subarray(0, read);
23820
23909
  } catch {
23821
23910
  return void 0;
23822
23911
  } finally {
23823
23912
  if (fd !== void 0) {
23824
23913
  try {
23825
- (0, import_node_fs24.closeSync)(fd);
23914
+ (0, import_node_fs25.closeSync)(fd);
23826
23915
  } catch {
23827
23916
  }
23828
23917
  }
@@ -23830,7 +23919,7 @@ function readHead(path2) {
23830
23919
  }
23831
23920
  function fileBytes(path2) {
23832
23921
  try {
23833
- return (0, import_node_fs24.statSync)(path2).size;
23922
+ return (0, import_node_fs25.statSync)(path2).size;
23834
23923
  } catch {
23835
23924
  return void 0;
23836
23925
  }
@@ -23844,13 +23933,13 @@ function readClaudeBinaryState(host = {}) {
23844
23933
  const arch = host.arch ?? process.arch;
23845
23934
  const magic = EXECUTABLE_MAGIC[platform2];
23846
23935
  if (!magic) return void 0;
23847
- const packageRoot = globalNodeModulesRoots(host).map((root) => (0, import_node_path23.join)(root, ...PACKAGE.split("/"))).find((dir) => (0, import_node_fs24.existsSync)((0, import_node_path23.join)(dir, "package.json")));
23936
+ const packageRoot = globalNodeModulesRoots(host).map((root) => (0, import_node_path23.join)(root, ...PACKAGE.split("/"))).find((dir) => (0, import_node_fs25.existsSync)((0, import_node_path23.join)(dir, "package.json")));
23848
23937
  if (!packageRoot) return void 0;
23849
23938
  const keys = platformPackageKeys(platform2, arch);
23850
23939
  const fallbackPackage = `${PACKAGE}-${keys[0]}`;
23851
23940
  let manifest;
23852
23941
  try {
23853
- manifest = JSON.parse((0, import_node_fs24.readFileSync)((0, import_node_path23.join)(packageRoot, "package.json"), "utf8"));
23942
+ manifest = JSON.parse((0, import_node_fs25.readFileSync)((0, import_node_path23.join)(packageRoot, "package.json"), "utf8"));
23854
23943
  } catch (e) {
23855
23944
  return {
23856
23945
  state: "unreadable",
@@ -23881,7 +23970,7 @@ function readClaudeBinaryState(host = {}) {
23881
23970
  (0, import_node_path23.join)(packageRoot, "node_modules", ...name.split("/"), binName),
23882
23971
  (0, import_node_path23.join)((0, import_node_path23.dirname)((0, import_node_path23.dirname)(packageRoot)), ...name.split("/"), binName)
23883
23972
  ];
23884
- const found = published.map((name) => ({ name, path: binIn(name).find((file) => (0, import_node_fs24.existsSync)(file)) })).find((c) => c.path);
23973
+ const found = published.map((name) => ({ name, path: binIn(name).find((file) => (0, import_node_fs25.existsSync)(file)) })).find((c) => c.path);
23885
23974
  const platformPackage = found?.name ?? published[0];
23886
23975
  let source;
23887
23976
  let sourceProblem;
@@ -23892,7 +23981,7 @@ function readClaudeBinaryState(host = {}) {
23892
23981
  } else {
23893
23982
  source = { path: found.path, bytes: fileBytes(found.path) ?? 0 };
23894
23983
  }
23895
- if (!(0, import_node_fs24.existsSync)(binPath)) {
23984
+ if (!(0, import_node_fs25.existsSync)(binPath)) {
23896
23985
  return { state: "missing", binPath, expectedMagic: magic.name, platformPackage, ...source ? { source } : {}, ...sourceProblem ? { sourceProblem } : {} };
23897
23986
  }
23898
23987
  const head = readHead(binPath);
@@ -23935,9 +24024,9 @@ function healClaudeBinary(host = {}, onStep) {
23935
24024
  const platform2 = host.platform ?? process.platform;
23936
24025
  const aside = `${probe.binPath}.stub-${Date.now()}`;
23937
24026
  let renamed = false;
23938
- if ((0, import_node_fs24.existsSync)(probe.binPath)) {
24027
+ if ((0, import_node_fs25.existsSync)(probe.binPath)) {
23939
24028
  try {
23940
- (0, import_node_fs24.renameSync)(probe.binPath, aside);
24029
+ (0, import_node_fs25.renameSync)(probe.binPath, aside);
23941
24030
  renamed = true;
23942
24031
  onStep?.(`renamed the stub aside: ${aside}`);
23943
24032
  } catch (e) {
@@ -23946,12 +24035,12 @@ function healClaudeBinary(host = {}, onStep) {
23946
24035
  }
23947
24036
  try {
23948
24037
  onStep?.(`copying ${probe.source.path} \u2192 ${probe.binPath} (${(probe.source.bytes / 1e6).toFixed(0)} MB)`);
23949
- (0, import_node_fs24.copyFileSync)(probe.source.path, probe.binPath);
23950
- if (platform2 !== "win32") (0, import_node_fs24.chmodSync)(probe.binPath, 493);
24038
+ (0, import_node_fs25.copyFileSync)(probe.source.path, probe.binPath);
24039
+ if (platform2 !== "win32") (0, import_node_fs25.chmodSync)(probe.binPath, 493);
23951
24040
  } catch (e) {
23952
24041
  if (renamed) {
23953
24042
  try {
23954
- (0, import_node_fs24.renameSync)(aside, probe.binPath);
24043
+ (0, import_node_fs25.renameSync)(aside, probe.binPath);
23955
24044
  } catch {
23956
24045
  return { ok: false, detail: `copy failed (${e.message}) and the stub could not be restored \u2014 the original is at ${aside}` };
23957
24046
  }
@@ -23965,7 +24054,7 @@ function healClaudeBinary(host = {}, onStep) {
23965
24054
  let kept = false;
23966
24055
  if (renamed) {
23967
24056
  try {
23968
- (0, import_node_fs24.rmSync)(aside);
24057
+ (0, import_node_fs25.rmSync)(aside);
23969
24058
  } catch {
23970
24059
  kept = true;
23971
24060
  }
@@ -24324,7 +24413,7 @@ function checkLineEndings(probe) {
24324
24413
  }
24325
24414
 
24326
24415
  // src/release-ledger.ts
24327
- var import_node_fs25 = require("node:fs");
24416
+ var import_node_fs26 = require("node:fs");
24328
24417
  var import_node_path25 = require("node:path");
24329
24418
  var import_node_crypto9 = require("node:crypto");
24330
24419
 
@@ -24499,8 +24588,8 @@ function attachOutputNote(note, suffix) {
24499
24588
  }
24500
24589
  function writeFailingLegOutput(artifactPath, output) {
24501
24590
  const fileLines = lastNonEmptyLines(output, LEDGER_OUTPUT_FILE_LINES);
24502
- (0, import_node_fs25.mkdirSync)((0, import_node_path25.dirname)(artifactPath), { recursive: true });
24503
- (0, import_node_fs25.writeFileSync)(artifactPath, `${fileLines.join("\n")}
24591
+ (0, import_node_fs26.mkdirSync)((0, import_node_path25.dirname)(artifactPath), { recursive: true });
24592
+ (0, import_node_fs26.writeFileSync)(artifactPath, `${fileLines.join("\n")}
24504
24593
  `, "utf8");
24505
24594
  const tail = fileLines.slice(-LEDGER_OUTPUT_NOTE_LINES).join("\n");
24506
24595
  const noteSuffix = truncate(`failing-leg output: ${artifactPath}
@@ -24668,7 +24757,7 @@ function resolvePrimaryGitDir(cwd) {
24668
24757
  }
24669
24758
  let common;
24670
24759
  try {
24671
- common = (0, import_node_fs25.readFileSync)((0, import_node_path25.join)(gitDir, "commondir"), "utf8").trim();
24760
+ common = (0, import_node_fs26.readFileSync)((0, import_node_path25.join)(gitDir, "commondir"), "utf8").trim();
24672
24761
  } catch (e) {
24673
24762
  if (e.code !== "ENOENT") {
24674
24763
  throw new ReleaseLedgerError("unreadable", `release ledger: the worktree gitdir's commondir pointer could not be READ (${e instanceof Error ? e.message : String(e)}) \u2014 a failed read is unverified, not primary (#5987/#4713)`);
@@ -24677,7 +24766,7 @@ function resolvePrimaryGitDir(cwd) {
24677
24766
  if (!common) return gitDir;
24678
24767
  const commonDir = (0, import_node_path25.isAbsolute)(common) ? common : (0, import_node_path25.resolve)(gitDir, common);
24679
24768
  try {
24680
- (0, import_node_fs25.readFileSync)((0, import_node_path25.join)(commonDir, "HEAD"), "utf8");
24769
+ (0, import_node_fs26.readFileSync)((0, import_node_path25.join)(commonDir, "HEAD"), "utf8");
24681
24770
  } catch (e) {
24682
24771
  throw new ReleaseLedgerError("no-checkout", `release ledger: the worktree's commondir pointer names ${commonDir}, which has no readable HEAD (${e instanceof Error ? e.message : String(e)}) \u2014 the primary checkout may have been removed; refusing to write the ledger into a doomed location`);
24683
24772
  }
@@ -24687,11 +24776,11 @@ function releaseLedgerPath(cwd) {
24687
24776
  return (0, import_node_path25.join)(resolvePrimaryGitDir(cwd), "mmi-runtime", "release", "phases.json");
24688
24777
  }
24689
24778
  function atomicWriteJson(path2, ledger) {
24690
- (0, import_node_fs25.mkdirSync)((0, import_node_path25.dirname)(path2), { recursive: true });
24779
+ (0, import_node_fs26.mkdirSync)((0, import_node_path25.dirname)(path2), { recursive: true });
24691
24780
  const tmp = `${path2}.tmp-${process.pid}-${(0, import_node_crypto9.randomBytes)(4).toString("hex")}`;
24692
- (0, import_node_fs25.writeFileSync)(tmp, `${JSON.stringify(ledger, null, 2)}
24781
+ (0, import_node_fs26.writeFileSync)(tmp, `${JSON.stringify(ledger, null, 2)}
24693
24782
  `, "utf8");
24694
- (0, import_node_fs25.renameSync)(tmp, path2);
24783
+ (0, import_node_fs26.renameSync)(tmp, path2);
24695
24784
  }
24696
24785
  var LEDGER_LOCK_OPTS = { label: "release ledger", staleMs: 18e4, deadHolderSteal: true };
24697
24786
  async function withLedgerLock(path2, fn, opts = {}) {
@@ -24738,7 +24827,7 @@ function describeTrainWriterToken(token) {
24738
24827
  function liveTrainWriterHolder(cwd) {
24739
24828
  let token;
24740
24829
  try {
24741
- token = (0, import_node_fs25.readFileSync)(trainWriterLockPath(cwd), "utf8");
24830
+ token = (0, import_node_fs26.readFileSync)(trainWriterLockPath(cwd), "utf8");
24742
24831
  } catch {
24743
24832
  return void 0;
24744
24833
  }
@@ -24760,7 +24849,7 @@ async function acquireTrainWriterLock(cwd, verb) {
24760
24849
  if (heldTrainWriter) heldTrainWriter.depth -= 1;
24761
24850
  };
24762
24851
  }
24763
- (0, import_node_fs25.mkdirSync)((0, import_node_path25.dirname)(lockPath), { recursive: true });
24852
+ (0, import_node_fs26.mkdirSync)((0, import_node_path25.dirname)(lockPath), { recursive: true });
24764
24853
  const opts = resolveFileLockOpts({ label: "train writer", staleMs: TRAIN_WRITER_STALE_MS, deadHolderSteal: true, maxWaitMs: 0, holder: verb });
24765
24854
  let guard;
24766
24855
  try {
@@ -24769,7 +24858,7 @@ async function acquireTrainWriterLock(cwd, verb) {
24769
24858
  if (!(e instanceof FileLockBusyError)) throw e;
24770
24859
  let token = "";
24771
24860
  try {
24772
- token = (0, import_node_fs25.readFileSync)(lockPath, "utf8");
24861
+ token = (0, import_node_fs26.readFileSync)(lockPath, "utf8");
24773
24862
  } catch {
24774
24863
  token = "";
24775
24864
  }
@@ -24804,7 +24893,7 @@ async function withReleaseLedger(path2, expected, fn, opts = {}) {
24804
24893
  let current;
24805
24894
  let raw;
24806
24895
  try {
24807
- raw = (0, import_node_fs25.readFileSync)(path2, "utf8");
24896
+ raw = (0, import_node_fs26.readFileSync)(path2, "utf8");
24808
24897
  } catch (e) {
24809
24898
  if (e.code !== "ENOENT") {
24810
24899
  throw new ReleaseLedgerError("unreadable", `release ledger at ${path2} could not be READ (${e instanceof Error ? e.message : String(e)}) \u2014 a failed read is unverified, not absent (#5987)`);
@@ -25473,7 +25562,7 @@ async function clearLedgerFile(path2, anchors, maxWaitMs) {
25473
25562
  return withLedgerLock(path2, async (fence) => {
25474
25563
  let raw;
25475
25564
  try {
25476
- raw = (0, import_node_fs25.readFileSync)(path2, "utf8");
25565
+ raw = (0, import_node_fs26.readFileSync)(path2, "utf8");
25477
25566
  } catch (e) {
25478
25567
  if (e.code === "ENOENT") return { cleared: false };
25479
25568
  return { cleared: false, note: `release ledger at ${path2} could not be read for clearing (${e instanceof Error ? e.message : String(e)}) \u2014 left in place` };
@@ -25489,7 +25578,7 @@ async function clearLedgerFile(path2, anchors, maxWaitMs) {
25489
25578
  } catch (e) {
25490
25579
  return { cleared: false, note: `release ledger at ${path2} belongs to ${ledger.tag} @ ${ledger.tagSha.slice(0, 12)} \u2014 not this release; left in place (${e instanceof Error ? e.message : String(e)})` };
25491
25580
  }
25492
- await fence(() => (0, import_node_fs25.unlinkSync)(path2));
25581
+ await fence(() => (0, import_node_fs26.unlinkSync)(path2));
25493
25582
  return { cleared: true, note: `cleared the release ledger at ${path2} for the live-proven aborted ${anchors.tag}` };
25494
25583
  }, { maxWaitMs });
25495
25584
  }
@@ -25649,7 +25738,7 @@ async function healStaleAlignmentLeg(deps, cwd, expected) {
25649
25738
  return withLedgerLock(path2, async (fence) => {
25650
25739
  let prior;
25651
25740
  try {
25652
- prior = parseReleaseLedger((0, import_node_fs25.readFileSync)(path2, "utf8"));
25741
+ prior = parseReleaseLedger((0, import_node_fs26.readFileSync)(path2, "utf8"));
25653
25742
  } catch {
25654
25743
  return void 0;
25655
25744
  }
@@ -25674,7 +25763,7 @@ async function healUnfoldedRunLegs(deps, cwd, model) {
25674
25763
  const path2 = releaseLedgerPath(cwd);
25675
25764
  let prior;
25676
25765
  try {
25677
- prior = parseReleaseLedger((0, import_node_fs25.readFileSync)(path2, "utf8"));
25766
+ prior = parseReleaseLedger((0, import_node_fs26.readFileSync)(path2, "utf8"));
25678
25767
  } catch {
25679
25768
  return void 0;
25680
25769
  }
@@ -25743,7 +25832,7 @@ async function supersedeContentCausedDeployLeg(deps, cwd) {
25743
25832
  return withLedgerLock(path2, async (fence) => {
25744
25833
  let prior;
25745
25834
  try {
25746
- prior = parseReleaseLedger((0, import_node_fs25.readFileSync)(path2, "utf8"));
25835
+ prior = parseReleaseLedger((0, import_node_fs26.readFileSync)(path2, "utf8"));
25747
25836
  } catch (e) {
25748
25837
  throw new ReleaseLedgerError(
25749
25838
  "unreadable",
@@ -25841,10 +25930,10 @@ async function proveOriginPromotionOrArchived(deps, prior, path2, label, ref, fe
25841
25930
  throw new Error(`${label}: origin no longer has ${prior.tag} but its GitHub Release still exists \u2014 resolve the mixed external state before closing the ledger; nothing was written (${ref})`);
25842
25931
  }
25843
25932
  const archivePath = (0, import_node_path25.join)((0, import_node_path25.dirname)(path2), `phases.archive-${prior.tag}.json`);
25844
- if ((0, import_node_fs25.existsSync)(archivePath)) {
25933
+ if ((0, import_node_fs26.existsSync)(archivePath)) {
25845
25934
  throw new Error(`${label}: archive already exists at ${archivePath} \u2014 preserving both ledger records; resolve the collision by hand; nothing was written (${ref})`);
25846
25935
  }
25847
- await fence(() => (0, import_node_fs25.renameSync)(path2, archivePath));
25936
+ await fence(() => (0, import_node_fs26.renameSync)(path2, archivePath));
25848
25937
  return "deleted";
25849
25938
  }
25850
25939
  async function supersedeContentCausedPublishLeg(deps, cwd) {
@@ -25852,7 +25941,7 @@ async function supersedeContentCausedPublishLeg(deps, cwd) {
25852
25941
  return withLedgerLock(path2, async (fence) => {
25853
25942
  let prior;
25854
25943
  try {
25855
- prior = parseReleaseLedger((0, import_node_fs25.readFileSync)(path2, "utf8"));
25944
+ prior = parseReleaseLedger((0, import_node_fs26.readFileSync)(path2, "utf8"));
25856
25945
  } catch (e) {
25857
25946
  throw new ReleaseLedgerError(
25858
25947
  "unreadable",
@@ -25934,7 +26023,7 @@ async function supersedeContentCausedDeployAndPublishLegs(deps, cwd) {
25934
26023
  return withLedgerLock(path2, async (fence) => {
25935
26024
  let prior;
25936
26025
  try {
25937
- prior = parseReleaseLedger((0, import_node_fs25.readFileSync)(path2, "utf8"));
26026
+ prior = parseReleaseLedger((0, import_node_fs26.readFileSync)(path2, "utf8"));
25938
26027
  } catch (e) {
25939
26028
  throw new ReleaseLedgerError(
25940
26029
  "unreadable",
@@ -26039,7 +26128,7 @@ async function supersedeContentCausedDeployAndPublishLegs(deps, cwd) {
26039
26128
  async function reverifyPriorRunLegs(deps, path2, targetTag) {
26040
26129
  let prior;
26041
26130
  try {
26042
- prior = parseReleaseLedger((0, import_node_fs25.readFileSync)(path2, "utf8"));
26131
+ prior = parseReleaseLedger((0, import_node_fs26.readFileSync)(path2, "utf8"));
26043
26132
  } catch {
26044
26133
  return;
26045
26134
  }
@@ -26059,7 +26148,7 @@ async function beginReleaseLedger(deps, cwd, targetTag) {
26059
26148
  return withLedgerLock(path2, async (fence) => {
26060
26149
  let raw;
26061
26150
  try {
26062
- raw = (0, import_node_fs25.readFileSync)(path2, "utf8");
26151
+ raw = (0, import_node_fs26.readFileSync)(path2, "utf8");
26063
26152
  } catch (e) {
26064
26153
  if (e.code === "ENOENT") return { ok: true };
26065
26154
  return { ok: false, error: `the release ledger at ${path2} could not be READ (${e instanceof Error ? e.message : String(e)}) \u2014 a failed read is unverified, not absent (#5987/#4713)` };
@@ -26099,13 +26188,13 @@ async function beginReleaseLedger(deps, cwd, targetTag) {
26099
26188
  }
26100
26189
  const archivePath = (0, import_node_path25.join)((0, import_node_path25.dirname)(path2), `phases.archive-${prior.tag}.json`);
26101
26190
  try {
26102
- await fence(() => (0, import_node_fs25.unlinkSync)(archivePath));
26191
+ await fence(() => (0, import_node_fs26.unlinkSync)(archivePath));
26103
26192
  } catch (e) {
26104
26193
  if (e.code !== "ENOENT") {
26105
26194
  return { ok: false, error: `could not clear the stale archive at ${archivePath} (${e instanceof Error ? e.message : String(e)}) \u2014 the ledger for ${prior.tag} stays active (#5987)` };
26106
26195
  }
26107
26196
  }
26108
- await fence(() => (0, import_node_fs25.renameSync)(path2, archivePath));
26197
+ await fence(() => (0, import_node_fs26.renameSync)(path2, archivePath));
26109
26198
  return { ok: true, note: `archived the completed release ledger ${prior.tag} to ${archivePath} (live-proven at ${prior.tagSha.slice(0, 12)})` };
26110
26199
  });
26111
26200
  }
@@ -26133,7 +26222,7 @@ async function retryHotfixDeployLegs(deps, cwd, opts = {}) {
26133
26222
  return withLedgerLock(path2, async (fence) => {
26134
26223
  let prior;
26135
26224
  try {
26136
- prior = parseReleaseLedger((0, import_node_fs25.readFileSync)(path2, "utf8"));
26225
+ prior = parseReleaseLedger((0, import_node_fs26.readFileSync)(path2, "utf8"));
26137
26226
  } catch (e) {
26138
26227
  throw new ReleaseLedgerError(
26139
26228
  "unreadable",
@@ -26326,10 +26415,10 @@ function readOriginWorkflowsDefault(root, ref) {
26326
26415
  }
26327
26416
  var NPM_REGISTRY = "https://registry.npmjs.org";
26328
26417
  async function probeRegistryWhoami(train) {
26329
- const dir = (0, import_node_fs26.mkdtempSync)((0, import_node_path26.join)((0, import_node_os15.tmpdir)(), "mmi-npmrc-"));
26418
+ const dir = (0, import_node_fs27.mkdtempSync)((0, import_node_path26.join)((0, import_node_os15.tmpdir)(), "mmi-npmrc-"));
26330
26419
  const rc = (0, import_node_path26.join)(dir, "npmrc");
26331
26420
  try {
26332
- (0, import_node_fs26.writeFileSync)(rc, "//registry.npmjs.org/:_authToken=${NPM_TOKEN}\n");
26421
+ (0, import_node_fs27.writeFileSync)(rc, "//registry.npmjs.org/:_authToken=${NPM_TOKEN}\n");
26333
26422
  await train.runSelf(["secrets", "use", "npm/NPM_TOKEN", "--slug", "_org", "--", "npm", "whoami", "--registry", NPM_REGISTRY, "--userconfig", rc]);
26334
26423
  return { kind: "ok", detail: "the registry answered a login" };
26335
26424
  } catch (e) {
@@ -26340,7 +26429,7 @@ async function probeRegistryWhoami(train) {
26340
26429
  if (/\bE401\b|401 Unauthorized/.test(stderr)) return { kind: "rejected", detail: "npm whoami answered 401 Unauthorized" };
26341
26430
  return { kind: "unverified", detail: first };
26342
26431
  } finally {
26343
- (0, import_node_fs26.rmSync)(dir, { recursive: true, force: true });
26432
+ (0, import_node_fs27.rmSync)(dir, { recursive: true, force: true });
26344
26433
  }
26345
26434
  }
26346
26435
  var REGISTRY_TOKEN_ENV = /\b(NODE_AUTH_TOKEN|NPM_TOKEN)\b/;
@@ -26358,7 +26447,7 @@ var defaultDeps2 = {
26358
26447
  ledgerPath: releaseLedgerPath,
26359
26448
  readLedgerRaw: (path2) => {
26360
26449
  try {
26361
- return (0, import_node_fs26.readFileSync)(path2, "utf8");
26450
+ return (0, import_node_fs27.readFileSync)(path2, "utf8");
26362
26451
  } catch (e) {
26363
26452
  if (e.code === "ENOENT") return void 0;
26364
26453
  throw e;
@@ -26369,7 +26458,7 @@ var defaultDeps2 = {
26369
26458
  trainWriterHolder: liveTrainWriterHolder,
26370
26459
  readSurfacesRaw: (cwd) => {
26371
26460
  try {
26372
- return (0, import_node_fs26.readFileSync)((0, import_node_path26.join)(cwd, "surfaces.json"), "utf8");
26461
+ return (0, import_node_fs27.readFileSync)((0, import_node_path26.join)(cwd, "surfaces.json"), "utf8");
26373
26462
  } catch {
26374
26463
  return void 0;
26375
26464
  }
@@ -27008,7 +27097,7 @@ function formatTrainDoctor(v) {
27008
27097
 
27009
27098
  // src/release-plain-words.ts
27010
27099
  var import_promises3 = require("node:fs/promises");
27011
- var import_node_fs27 = require("node:fs");
27100
+ var import_node_fs28 = require("node:fs");
27012
27101
  function releaseCutByNotes(cutBy) {
27013
27102
  return `## Internal
27014
27103
  Cut by ${formatSessionIdentity(cutBy)}
@@ -27114,7 +27203,7 @@ function validateSuiteReleaseSummary(path2, pathTr) {
27114
27203
  for (const [lang, file] of files) {
27115
27204
  let content;
27116
27205
  try {
27117
- content = (0, import_node_fs27.readFileSync)(file, "utf8");
27206
+ content = (0, import_node_fs28.readFileSync)(file, "utf8");
27118
27207
  } catch (e) {
27119
27208
  throw new Error(`could not read summary file ${file}: ${e.message} \u2014 see ${SUMMARY_GUIDE}`);
27120
27209
  }
@@ -27329,14 +27418,14 @@ function readLocalGateWorkflows() {
27329
27418
  const dir = (0, import_node_path27.join)(".github", "workflows");
27330
27419
  let names;
27331
27420
  try {
27332
- names = (0, import_node_fs28.readdirSync)(dir);
27421
+ names = (0, import_node_fs29.readdirSync)(dir);
27333
27422
  } catch {
27334
27423
  return null;
27335
27424
  }
27336
27425
  const files = [];
27337
27426
  for (const name of names.filter(isGateWorkflowPath)) {
27338
27427
  try {
27339
- files.push({ path: `${dir}/${name}`.replace(/\\/g, "/"), body: (0, import_node_fs28.readFileSync)((0, import_node_path27.join)(dir, name), "utf8") });
27428
+ files.push({ path: `${dir}/${name}`.replace(/\\/g, "/"), body: (0, import_node_fs29.readFileSync)((0, import_node_path27.join)(dir, name), "utf8") });
27340
27429
  } catch {
27341
27430
  }
27342
27431
  }
@@ -27346,14 +27435,14 @@ function readLocalWorkflows() {
27346
27435
  const dir = (0, import_node_path27.join)(".github", "workflows");
27347
27436
  let names;
27348
27437
  try {
27349
- names = (0, import_node_fs28.readdirSync)(dir);
27438
+ names = (0, import_node_fs29.readdirSync)(dir);
27350
27439
  } catch {
27351
27440
  return null;
27352
27441
  }
27353
27442
  const files = [];
27354
27443
  for (const name of names.filter((n) => /\.ya?ml$/i.test(n))) {
27355
27444
  try {
27356
- files.push({ path: `${dir}/${name}`.replace(/\\/g, "/"), body: (0, import_node_fs28.readFileSync)((0, import_node_path27.join)(dir, name), "utf8") });
27445
+ files.push({ path: `${dir}/${name}`.replace(/\\/g, "/"), body: (0, import_node_fs29.readFileSync)((0, import_node_path27.join)(dir, name), "utf8") });
27357
27446
  } catch {
27358
27447
  }
27359
27448
  }
@@ -28235,7 +28324,7 @@ async function activeRcandLedgerCandidate(deps, cwd) {
28235
28324
  }
28236
28325
  let prior;
28237
28326
  try {
28238
- prior = parseReleaseLedger((0, import_node_fs28.readFileSync)(path2, "utf8"));
28327
+ prior = parseReleaseLedger((0, import_node_fs29.readFileSync)(path2, "utf8"));
28239
28328
  } catch {
28240
28329
  return void 0;
28241
28330
  }
@@ -30851,7 +30940,7 @@ var PRIMARY_GROUPS = [
30851
30940
  ["Setup and support", ["bootstrap", "secrets", "docs", "tests", "spawn", "dist"]],
30852
30941
  ["Coordinate and improve", ["wave", "report", "skill-lesson", "closure-rate"]]
30853
30942
  ];
30854
- var OPERATIONAL_TOP_LEVEL = /* @__PURE__ */ new Set(["org", "runtime", "plugin", "packages", "archive-prune"]);
30943
+ var OPERATIONAL_TOP_LEVEL = /* @__PURE__ */ new Set(["org", "runtime", "plugin", "packages", "github", "archive-prune"]);
30855
30944
  var CAMPAIGN_ORCHESTRATOR_TOP_LEVEL = /* @__PURE__ */ new Set(["pickup", "read"]);
30856
30945
  var SUPPORT_PRIMARY = /* @__PURE__ */ new Set(["doctor", "whoami", "commands", "explain", "docs", "tests", "spawn", "dist", "wave", "report", "skill-lesson", "closure-rate"]);
30857
30946
  var TOP_LEVEL_ORDER = /* @__PURE__ */ new Map();
@@ -30892,6 +30981,7 @@ var COMMAND_OWNERSHIP = {
30892
30981
  stage: { module_owner: "cli/src/stage-commands.ts", consumer: "agent-workflow" },
30893
30982
  pr: { module_owner: "cli/src/pr-commands.ts", consumer: "agent-workflow" },
30894
30983
  api: { module_owner: "cli/src/api-read.ts", consumer: "agent-workflow" },
30984
+ github: { module_owner: "cli/src/github-budget.ts", consumer: "release-operator" },
30895
30985
  read: { module_owner: "cli/src/app-read-broker.ts", consumer: "agent-workflow" },
30896
30986
  ci: { module_owner: "cli/src/ci-audit.ts", consumer: "release-operator" },
30897
30987
  rcand: { module_owner: "cli/src/train-commands.ts", consumer: "release-operator" },
@@ -31631,6 +31721,55 @@ function renderPluginCachePlan(plan, applied) {
31631
31721
  return lines2.join("\n");
31632
31722
  }
31633
31723
 
31724
+ // src/github-budget.ts
31725
+ init_cli_shared();
31726
+ function allowance(value) {
31727
+ const v = value;
31728
+ return v && [v.remaining, v.limit, v.reset].every((n) => typeof n === "number" && Number.isFinite(n)) ? { remaining: v.remaining, limit: v.limit, reset: v.reset } : null;
31729
+ }
31730
+ async function readGithubBudget(deps) {
31731
+ async function read(token) {
31732
+ try {
31733
+ const credential = await token();
31734
+ if (!credential) throw new Error("No identity");
31735
+ const res = await deps.fetch("https://api.github.com/rate_limit", {
31736
+ method: "GET",
31737
+ headers: { authorization: `Bearer ${credential}`, accept: "application/vnd.github+json", "user-agent": "mmi-cli" }
31738
+ });
31739
+ if (!res.ok) throw new Error("Unreadable");
31740
+ const body = await res.json();
31741
+ return { core: allowance(body.resources?.core), graphql: allowance(body.resources?.graphql) };
31742
+ } catch {
31743
+ return { core: null, graphql: null };
31744
+ }
31745
+ }
31746
+ const [personal, app1, app2] = await Promise.all([
31747
+ read(async () => {
31748
+ const env = { ...process.env };
31749
+ delete env.GH_TOKEN;
31750
+ delete env.GITHUB_TOKEN;
31751
+ return (await execFileP("gh", ["auth", "token"], { env })).stdout.trim();
31752
+ }),
31753
+ ...APP_POOL_MEMBERS.map((keys) => read(async () => (await mintBudgetToken(deps, keys)).token))
31754
+ ]);
31755
+ const pools = { personal, app1, app2 };
31756
+ const count = (v) => v ? `${v.remaining}/${v.limit}` : "unknown";
31757
+ const resets = [...new Set(Object.values(pools).flatMap((pool) => [pool.core, pool.graphql]).filter((v) => v !== null).map((v) => new Intl.DateTimeFormat("en-GB", {
31758
+ timeZone: "Europe/Istanbul",
31759
+ hour: "2-digit",
31760
+ minute: "2-digit",
31761
+ hourCycle: "h23"
31762
+ }).format(new Date(v.reset * 1e3))))].sort();
31763
+ const line = `GitHub budget \xB7 ${Object.entries(pools).map(([name, pool]) => `${name} core ${count(pool.core)} gql ${count(pool.graphql)}`).join(" \xB7 ")} \xB7 resets ${resets.join(", ") || "unknown"} (Istanbul)`;
31764
+ return { ...pools, line };
31765
+ }
31766
+ function registerGithubBudgetCommand(program3, deps) {
31767
+ program3.command("github").description("GitHub allowance visibility").command("budget").description("read personal and both App budgets (no allowance cost)").option("--json", "machine-readable output").action(async (options) => {
31768
+ const budget = await readGithubBudget(deps());
31769
+ console.log(options.json ? JSON.stringify(budget, null, 2) : budget.line);
31770
+ });
31771
+ }
31772
+
31634
31773
  // src/board-commands.ts
31635
31774
  init_cli_shared();
31636
31775
 
@@ -32132,7 +32271,7 @@ function registerBoardCommands(program3) {
32132
32271
  }
32133
32272
 
32134
32273
  // src/bootstrap-commands.ts
32135
- var import_node_fs32 = require("node:fs");
32274
+ var import_node_fs33 = require("node:fs");
32136
32275
  var import_node_os18 = require("node:os");
32137
32276
  var import_node_path31 = require("node:path");
32138
32277
  init_cli_shared();
@@ -32318,7 +32457,7 @@ init_github_client();
32318
32457
  init_cli_shared();
32319
32458
 
32320
32459
  // src/port-registry.ts
32321
- var import_node_fs29 = require("node:fs");
32460
+ var import_node_fs30 = require("node:fs");
32322
32461
  var import_node_path28 = require("node:path");
32323
32462
 
32324
32463
  // ../infra/port-geometry.mjs
@@ -32333,8 +32472,8 @@ function nextPortBlock(registry2) {
32333
32472
  return [base, base + PORT_SPAN];
32334
32473
  }
32335
32474
  function loadPortRegistry(path2) {
32336
- if (!(0, import_node_fs29.existsSync)(path2)) return {};
32337
- const raw = JSON.parse((0, import_node_fs29.readFileSync)(path2, "utf8"));
32475
+ if (!(0, import_node_fs30.existsSync)(path2)) return {};
32476
+ const raw = JSON.parse((0, import_node_fs30.readFileSync)(path2, "utf8"));
32338
32477
  const out = {};
32339
32478
  for (const [key, value] of Object.entries(raw)) {
32340
32479
  if (Array.isArray(value) && value.length === 2 && value.every((n) => typeof n === "number")) {
@@ -32364,7 +32503,7 @@ function existingPortRange(repo, registry2) {
32364
32503
  function portRangeInfraAt(root, source) {
32365
32504
  const registryPath = (0, import_node_path28.join)(root, "infra", "port-ranges.json");
32366
32505
  const ddbScriptPath = (0, import_node_path28.join)(root, "infra", "port-ddb.mjs");
32367
- if (!(0, import_node_fs29.existsSync)(registryPath) || !(0, import_node_fs29.existsSync)(ddbScriptPath)) return null;
32506
+ if (!(0, import_node_fs30.existsSync)(registryPath) || !(0, import_node_fs30.existsSync)(ddbScriptPath)) return null;
32368
32507
  return { root, source, registryPath, ddbScriptPath };
32369
32508
  }
32370
32509
  function resolvePortRangeInfra(cwd, packageDir) {
@@ -32446,7 +32585,7 @@ async function assignPersistedPortRange(repo, slug, reg, opts) {
32446
32585
  }
32447
32586
 
32448
32587
  // src/box-commands.ts
32449
- var import_node_fs31 = require("node:fs");
32588
+ var import_node_fs32 = require("node:fs");
32450
32589
  var import_node_child_process10 = require("node:child_process");
32451
32590
  var import_node_os17 = require("node:os");
32452
32591
  var import_node_path30 = require("node:path");
@@ -32580,7 +32719,7 @@ function applyRemoteScript(items, date) {
32580
32719
  init_clean_exit();
32581
32720
 
32582
32721
  // src/secrets-commands.ts
32583
- var import_node_fs30 = require("node:fs");
32722
+ var import_node_fs31 = require("node:fs");
32584
32723
  var import_node_path29 = require("node:path");
32585
32724
  var import_node_os16 = require("node:os");
32586
32725
  init_cli_shared();
@@ -33730,8 +33869,8 @@ async function decryptRailsCredentials(input) {
33730
33869
  MMI_RAILS_CREDENTIALS_FILE: credentialsPath,
33731
33870
  MMI_RAILS_MASTER_KEY_FILE: masterKeyPath
33732
33871
  };
33733
- if ((0, import_node_fs30.existsSync)(masterKeyPath)) {
33734
- env.RAILS_MASTER_KEY = (0, import_node_fs30.readFileSync)(masterKeyPath, "utf8").trim();
33872
+ if ((0, import_node_fs31.existsSync)(masterKeyPath)) {
33873
+ env.RAILS_MASTER_KEY = (0, import_node_fs31.readFileSync)(masterKeyPath, "utf8").trim();
33735
33874
  }
33736
33875
  const script = [
33737
33876
  'require "json"',
@@ -33741,9 +33880,9 @@ async function decryptRailsCredentials(input) {
33741
33880
  'config = ActiveSupport::EncryptedConfiguration.new(config_path: config_path, key_path: key_path, env_key: "RAILS_MASTER_KEY", raise_if_missing_key: true)',
33742
33881
  "puts JSON.generate(config.config)"
33743
33882
  ].join("\n");
33744
- const scriptDir = (0, import_node_fs30.mkdtempSync)((0, import_node_path29.join)((0, import_node_os16.tmpdir)(), "mmi-rails-decrypt-"));
33883
+ const scriptDir = (0, import_node_fs31.mkdtempSync)((0, import_node_path29.join)((0, import_node_os16.tmpdir)(), "mmi-rails-decrypt-"));
33745
33884
  const scriptPath = (0, import_node_path29.join)(scriptDir, "decrypt.rb");
33746
- (0, import_node_fs30.writeFileSync)(scriptPath, script, "utf8");
33885
+ (0, import_node_fs31.writeFileSync)(scriptPath, script, "utf8");
33747
33886
  try {
33748
33887
  const args = ["exec", "ruby", scriptPath];
33749
33888
  const cmd = process.platform === "win32" ? "cmd.exe" : "bundle";
@@ -33755,7 +33894,7 @@ async function decryptRailsCredentials(input) {
33755
33894
  });
33756
33895
  return JSON.parse(stdout);
33757
33896
  } finally {
33758
- (0, import_node_fs30.rmSync)(scriptDir, { recursive: true, force: true });
33897
+ (0, import_node_fs31.rmSync)(scriptDir, { recursive: true, force: true });
33759
33898
  }
33760
33899
  }
33761
33900
  async function readSecretStdin() {
@@ -33845,7 +33984,7 @@ function registerSecretsCommands(program3) {
33845
33984
  let body;
33846
33985
  if (o.file) {
33847
33986
  try {
33848
- body = (0, import_node_fs30.readFileSync)((0, import_node_path29.resolve)(o.file), "utf8");
33987
+ body = (0, import_node_fs31.readFileSync)((0, import_node_path29.resolve)(o.file), "utf8");
33849
33988
  } catch (e) {
33850
33989
  return fail(`secrets org-catalog: cannot read --file ${o.file}: ${e.message}`);
33851
33990
  }
@@ -33981,7 +34120,7 @@ function registerSecretsCommands(program3) {
33981
34120
  {
33982
34121
  ...d,
33983
34122
  decryptRailsCredentials,
33984
- removeFile: (path2) => (0, import_node_fs30.unlinkSync)((0, import_node_path29.resolve)(o.appDir ?? process.cwd(), path2))
34123
+ removeFile: (path2) => (0, import_node_fs31.unlinkSync)((0, import_node_path29.resolve)(o.appDir ?? process.cwd(), path2))
33985
34124
  },
33986
34125
  {
33987
34126
  repo: o.repo,
@@ -34237,7 +34376,7 @@ function registerBoxCommands(program3) {
34237
34376
  }
34238
34377
  const remote = command && command.length ? command.join(" ") : void 0;
34239
34378
  const wroteScript = o.ssh && o.script ? o.script : null;
34240
- if (wroteScript) (0, import_node_fs31.writeFileSync)(wroteScript, sshRecipeScript(found, remote), "utf8");
34379
+ if (wroteScript) (0, import_node_fs32.writeFileSync)(wroteScript, sshRecipeScript(found, remote), "utf8");
34241
34380
  if (o.json) {
34242
34381
  console.log(JSON.stringify({
34243
34382
  box: found,
@@ -34311,17 +34450,17 @@ function hubGitShow(ref) {
34311
34450
  return (path2) => git3(["show", `${ref}:${path2}`]);
34312
34451
  }
34313
34452
  function runOnBox(found, script) {
34314
- const dir = (0, import_node_fs31.mkdtempSync)((0, import_node_path30.join)((0, import_node_os17.tmpdir)(), "mmi-box-control-"));
34453
+ const dir = (0, import_node_fs32.mkdtempSync)((0, import_node_path30.join)((0, import_node_os17.tmpdir)(), "mmi-box-control-"));
34315
34454
  try {
34316
34455
  const recipe = (0, import_node_path30.join)(dir, "recipe.sh");
34317
- (0, import_node_fs31.writeFileSync)(recipe, sshRecipeScript(found, "sh -s"), "utf8");
34456
+ (0, import_node_fs32.writeFileSync)(recipe, sshRecipeScript(found, "sh -s"), "utf8");
34318
34457
  const r = (0, import_node_child_process10.spawnSync)("bash", [recipe], { input: script, encoding: "utf8", maxBuffer: 16 * 1024 * 1024, timeout: 18e4, windowsHide: true });
34319
34458
  if (r.status !== 0) {
34320
34459
  throw new UnreadableError(`box control: the ssh session to ${found.name} failed (exit ${r.status ?? r.signal}): ${(r.stderr || "").trim().split("\n").slice(-3).join(" | ")}`);
34321
34460
  }
34322
34461
  return r.stdout;
34323
34462
  } finally {
34324
- (0, import_node_fs31.rmSync)(dir, { recursive: true, force: true });
34463
+ (0, import_node_fs32.rmSync)(dir, { recursive: true, force: true });
34325
34464
  }
34326
34465
  }
34327
34466
  function formatControl(mode, box, rows) {
@@ -35956,12 +36095,12 @@ async function verifyTargetedSeedPr(repo, number, plan, target, expected, client
35956
36095
  // src/bootstrap-commands.ts
35957
36096
  var execGitForSeedSource = async (args) => (await execFileP("git", args, { timeout: GIT_TIMEOUT_MS })).stdout;
35958
36097
  async function gateRenderDiff(current, rendered) {
35959
- const dir = (0, import_node_fs32.mkdtempSync)((0, import_node_path31.join)((0, import_node_os18.tmpdir)(), "mmi-gate-diff-"));
36098
+ const dir = (0, import_node_fs33.mkdtempSync)((0, import_node_path31.join)((0, import_node_os18.tmpdir)(), "mmi-gate-diff-"));
35960
36099
  const before = (0, import_node_path31.join)(dir, "committed-gate.yml");
35961
36100
  const after = (0, import_node_path31.join)(dir, "registry-render.yml");
35962
36101
  try {
35963
- (0, import_node_fs32.writeFileSync)(before, current);
35964
- (0, import_node_fs32.writeFileSync)(after, rendered);
36102
+ (0, import_node_fs33.writeFileSync)(before, current);
36103
+ (0, import_node_fs33.writeFileSync)(after, rendered);
35965
36104
  try {
35966
36105
  return (await execFileP("git", ["diff", "--no-index", "--", before, after], { timeout: GIT_TIMEOUT_MS })).stdout;
35967
36106
  } catch (e) {
@@ -35970,7 +36109,7 @@ async function gateRenderDiff(current, rendered) {
35970
36109
  throw e;
35971
36110
  }
35972
36111
  } finally {
35973
- (0, import_node_fs32.rmSync)(dir, { recursive: true, force: true });
36112
+ (0, import_node_fs33.rmSync)(dir, { recursive: true, force: true });
35974
36113
  }
35975
36114
  }
35976
36115
  function bootstrapTrainDoctorDeps() {
@@ -36030,13 +36169,13 @@ function registerBootstrapCommands(program3) {
36030
36169
  })),
36031
36170
  pushAllowlistOwners: verifyOwners,
36032
36171
  pushAllowlistOwnersRead: verifyOwnersRead,
36033
- readLocalFile: (path2) => path2 === "projects.json" && apiProjects != null ? apiProjects : (0, import_node_fs32.existsSync)(path2) ? (0, import_node_fs32.readFileSync)(path2, "utf8") : null,
36172
+ readLocalFile: (path2) => path2 === "projects.json" && apiProjects != null ? apiProjects : (0, import_node_fs33.existsSync)(path2) ? (0, import_node_fs33.readFileSync)(path2, "utf8") : null,
36034
36173
  // requiredGcpApis is stored as an array by a JSON write, but `org project set --var KEY=VALUE` stores a raw
36035
36174
  // comma-string — accept either so the seeded value verifies regardless of how it was written.
36036
36175
  // #3689: the same committed map the org access audit reads (#3664), so a sanctioned admin is not a
36037
36176
  // permanent bootstrap failure on one surface and an intended state on the other. Absent file → no
36038
36177
  // sanction, which is the pre-#3664 behaviour.
36039
- sanctionedAdmins: (0, import_node_fs32.existsSync)("access-matrix.json") ? entriesValueByCanonicalRepo(loadSanctionedAdmins((0, import_node_fs32.readFileSync)("access-matrix.json", "utf8")), repo) : void 0,
36178
+ sanctionedAdmins: (0, import_node_fs33.existsSync)("access-matrix.json") ? entriesValueByCanonicalRepo(loadSanctionedAdmins((0, import_node_fs33.readFileSync)("access-matrix.json", "utf8")), repo) : void 0,
36040
36179
  requiredGcpApis: (() => {
36041
36180
  const v = meta?.requiredGcpApis;
36042
36181
  if (Array.isArray(v)) return v;
@@ -36114,14 +36253,14 @@ function registerBootstrapCommands(program3) {
36114
36253
  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 () => {
36115
36254
  const o = { repo: rawValue("--repo", ""), json: rawFlag("--json") };
36116
36255
  const manifestPath = "skills/bootstrap/seeds/manifest.json";
36117
- if (!(0, import_node_fs32.existsSync)(manifestPath)) return fail(`bootstrap drift: ${manifestPath} not found; run from the MMI-Hub repo root \u2014 the Hub's copies ARE the reference this compares against`);
36256
+ if (!(0, import_node_fs33.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`);
36118
36257
  const seedSource = await resolveHubSeedSource(execGitForSeedSource);
36119
36258
  if (!seedSource.ok) return fail(`bootstrap drift: ${seedSource.reason}`);
36120
- const manifest = loadBootstrapSeeds((0, import_node_fs32.readFileSync)(manifestPath, "utf8"));
36259
+ const manifest = loadBootstrapSeeds((0, import_node_fs33.readFileSync)(manifestPath, "utf8"));
36121
36260
  const hubContents = /* @__PURE__ */ new Map();
36122
36261
  for (const s of manifest.seeds) {
36123
36262
  if (s.ownership !== "org" || s.source !== "self") continue;
36124
- hubContents.set(s.target, (0, import_node_fs32.existsSync)(s.target) ? (0, import_node_fs32.readFileSync)(s.target, "utf8") : null);
36263
+ hubContents.set(s.target, (0, import_node_fs33.existsSync)(s.target) ? (0, import_node_fs33.readFileSync)(s.target, "utf8") : null);
36125
36264
  }
36126
36265
  let targets;
36127
36266
  let classOf = (_repo) => "deployable";
@@ -36329,24 +36468,24 @@ function registerBootstrapCommands(program3) {
36329
36468
  return;
36330
36469
  }
36331
36470
  const manifestPath = "skills/bootstrap/seeds/manifest.json";
36332
- if (!(0, import_node_fs32.existsSync)(manifestPath)) return fail(`bootstrap apply: ${manifestPath} not found; bootstrap runs from the MMI-Hub repo root by design \u2014 it stamps org-level resources (Project, Ruleset, secrets, access) through the GitHub App, which is only authorized from the Hub checkout`);
36471
+ if (!(0, import_node_fs33.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`);
36333
36472
  const seedSource = await resolveHubSeedSource(execGitForSeedSource);
36334
36473
  if (!seedSource.ok) return fail(`bootstrap apply: ${seedSource.reason}`);
36335
- const manifest = loadBootstrapSeeds((0, import_node_fs32.readFileSync)(manifestPath, "utf8"));
36474
+ const manifest = loadBootstrapSeeds((0, import_node_fs33.readFileSync)(manifestPath, "utf8"));
36336
36475
  const baseBranch = o.class === "content" ? "main" : "development";
36337
36476
  const slug = parsedRepo.slug;
36338
36477
  const onlyTarget = o.fromConfig && o.only.trim() === "gate.yml" ? ".github/workflows/gate.yml" : o.only.trim();
36339
36478
  const gh2 = async (args) => execFileP("gh", args, { timeout: 2e4 });
36340
- const readFile10 = (p) => (0, import_node_fs32.existsSync)(p) ? (0, import_node_fs32.readFileSync)(p, "utf8") : null;
36479
+ const readFile10 = (p) => (0, import_node_fs33.existsSync)(p) ? (0, import_node_fs33.readFileSync)(p, "utf8") : null;
36341
36480
  const enc = (p) => p.split("/").map(encodeURIComponent).join("/");
36342
36481
  const putSeed = async (target, content, ref, sha) => {
36343
36482
  const tmp = (0, import_node_path31.join)((0, import_node_os18.tmpdir)(), `mmi-seed-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
36344
- (0, import_node_fs32.writeFileSync)(tmp, JSON.stringify(contentPutBody(target, content, ref, sha)), "utf8");
36483
+ (0, import_node_fs33.writeFileSync)(tmp, JSON.stringify(contentPutBody(target, content, ref, sha)), "utf8");
36345
36484
  try {
36346
36485
  await gh2(contentPutInputArgs(repo, target, tmp));
36347
36486
  } finally {
36348
36487
  try {
36349
- (0, import_node_fs32.unlinkSync)(tmp);
36488
+ (0, import_node_fs33.unlinkSync)(tmp);
36350
36489
  } catch {
36351
36490
  }
36352
36491
  }
@@ -36982,10 +37121,10 @@ LIVE apply to ${repo}:
36982
37121
  bootstrap.command("propagate").description("#4238: re-entrant canary\u2192wave tick \u2014 plan (or, with --execute, open) per-repo PRs fanning an org-owned seed out to the fleet").option("--target <path>", "the manifest target to propagate (an org-owned whole file or declared Hub-managed block)").option("--execute", "LIVE tick via gh (master-gated) \u2014 opens/reuses per-repo seed-propagate PRs; dry-run prints the plan only").option("--json", "machine-readable output").action(async () => {
36983
37122
  const o = { target: rawValue("--target", ""), execute: rawFlag("--execute"), json: rawFlag("--json") };
36984
37123
  const manifestPath = "skills/bootstrap/seeds/manifest.json";
36985
- if (!(0, import_node_fs32.existsSync)(manifestPath)) return fail(`bootstrap propagate: ${manifestPath} not found; run from the MMI-Hub repo root \u2014 the Hub's copies ARE the desired state this tick propagates`);
37124
+ if (!(0, import_node_fs33.existsSync)(manifestPath)) return fail(`bootstrap propagate: ${manifestPath} not found; run from the MMI-Hub repo root \u2014 the Hub's copies ARE the desired state this tick propagates`);
36986
37125
  const seedSource = await resolveHubSeedSource(execGitForSeedSource);
36987
37126
  if (!seedSource.ok) return fail(`bootstrap propagate: ${seedSource.reason}`);
36988
- const manifest = loadBootstrapSeeds((0, import_node_fs32.readFileSync)(manifestPath, "utf8"));
37127
+ const manifest = loadBootstrapSeeds((0, import_node_fs33.readFileSync)(manifestPath, "utf8"));
36989
37128
  const propagatable = manifest.seeds.filter(isPropagatableSeed);
36990
37129
  if (!o.target) {
36991
37130
  return fail(`bootstrap propagate: --target <path> is required \u2014 one of:
@@ -36994,9 +37133,9 @@ LIVE apply to ${repo}:
36994
37133
  const seed = propagatable.find((s) => s.target === o.target);
36995
37134
  if (!seed) return fail(`bootstrap propagate: --target '${o.target}' names no centrally propagatable seed in ${manifestPath}. Propagatable targets:
36996
37135
  ${propagatable.map((s) => s.target).join("\n ")}`);
36997
- if (!seed.managedBlock && !(0, import_node_fs32.existsSync)(seed.target)) return fail(`bootstrap propagate: the Hub's own copy of '${seed.target}' is missing \u2014 nothing to propagate`);
36998
- const hubContent = seed.managedBlock ? null : (0, import_node_fs32.readFileSync)(seed.target, "utf8");
36999
- const readSeedFile2 = (path2) => (0, import_node_fs32.existsSync)(path2) ? (0, import_node_fs32.readFileSync)(path2, "utf8") : null;
37136
+ if (!seed.managedBlock && !(0, import_node_fs33.existsSync)(seed.target)) return fail(`bootstrap propagate: the Hub's own copy of '${seed.target}' is missing \u2014 nothing to propagate`);
37137
+ const hubContent = seed.managedBlock ? null : (0, import_node_fs33.readFileSync)(seed.target, "utf8");
37138
+ const readSeedFile2 = (path2) => (0, import_node_fs33.existsSync)(path2) ? (0, import_node_fs33.readFileSync)(path2, "utf8") : null;
37000
37139
  const isWorkflowSeed = seed.target.startsWith(".github/workflows/");
37001
37140
  const cfg = await loadConfig();
37002
37141
  const projects = await fetchProjectsList(registryClientDeps(cfg));
@@ -37005,9 +37144,9 @@ LIVE apply to ${repo}:
37005
37144
  }
37006
37145
  const rosterRepos = collectRegistryRepos(projects).filter((r) => r.toLowerCase() !== "mutmutco/mmi-hub");
37007
37146
  let independentCount = rosterRepos.length;
37008
- if ((0, import_node_fs32.existsSync)("projects.json")) {
37147
+ if ((0, import_node_fs33.existsSync)("projects.json")) {
37009
37148
  try {
37010
- const local = JSON.parse((0, import_node_fs32.readFileSync)("projects.json", "utf8"));
37149
+ const local = JSON.parse((0, import_node_fs33.readFileSync)("projects.json", "utf8"));
37011
37150
  const localRepos = /* @__PURE__ */ new Set();
37012
37151
  for (const p of local.projects ?? []) for (const r of p.repos ?? []) {
37013
37152
  const full = (r.includes("/") ? r : `mutmutco/${r}`).toLowerCase();
@@ -37157,7 +37296,7 @@ LIVE apply to ${repo}:
37157
37296
  if (plan.refusedNoCanary) return fail("bootstrap propagate --execute: no canary declared for this target \u2014 refusing to write (set seedCanary:true on exactly one registry repo)");
37158
37297
  const headSha = seedSource.sha;
37159
37298
  const sourceBlob = (await execGitForSeedSource(["rev-parse", `${headSha}:${seedSourcePath(seed)}`])).trim();
37160
- const runbookUnaffected = (0, import_node_fs32.existsSync)(RUNBOOK_UNAFFECTED_PATH) ? runbookUnaffectedReason(JSON.parse((0, import_node_fs32.readFileSync)(RUNBOOK_UNAFFECTED_PATH, "utf8")), seed.target, sourceBlob) : void 0;
37299
+ const runbookUnaffected = (0, import_node_fs33.existsSync)(RUNBOOK_UNAFFECTED_PATH) ? runbookUnaffectedReason(JSON.parse((0, import_node_fs33.readFileSync)(RUNBOOK_UNAFFECTED_PATH, "utf8")), seed.target, sourceBlob) : void 0;
37161
37300
  for (const rec of plan.records) {
37162
37301
  if (rec.action !== "open-pr") continue;
37163
37302
  const baseBranch = classOf(rec.repo) === "content" ? "main" : "development";
@@ -37182,12 +37321,12 @@ LIVE apply to ${repo}:
37182
37321
  const tmp = (0, import_node_path31.join)((0, import_node_os18.tmpdir)(), `mmi-propagate-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
37183
37322
  const desiredContent = desiredByRepo.get(rec.repo);
37184
37323
  if (desiredContent == null) return fail(`bootstrap propagate: no resolved content for ${rec.repo} ${seed.target} \u2014 refusing to write`);
37185
- (0, import_node_fs32.writeFileSync)(tmp, JSON.stringify(contentPutBody(seed.target, desiredContent, branch, existingSha, runbookUnaffected)), "utf8");
37324
+ (0, import_node_fs33.writeFileSync)(tmp, JSON.stringify(contentPutBody(seed.target, desiredContent, branch, existingSha, runbookUnaffected)), "utf8");
37186
37325
  try {
37187
37326
  await gh2(contentPutInputArgs(rec.repo, seed.target, tmp));
37188
37327
  } finally {
37189
37328
  try {
37190
- (0, import_node_fs32.unlinkSync)(tmp);
37329
+ (0, import_node_fs33.unlinkSync)(tmp);
37191
37330
  } catch {
37192
37331
  }
37193
37332
  }
@@ -37256,10 +37395,10 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
37256
37395
  return fail(`bootstrap rollback: ${e.message}`);
37257
37396
  }
37258
37397
  const manifestPath = "skills/bootstrap/seeds/manifest.json";
37259
- if (!(0, import_node_fs32.existsSync)(manifestPath)) return fail(`bootstrap rollback: ${manifestPath} not found; run from the MMI-Hub repo root \u2014 the manifest names which targets are org-owned and therefore propagated (and rollback-able)`);
37398
+ if (!(0, import_node_fs33.existsSync)(manifestPath)) return fail(`bootstrap rollback: ${manifestPath} not found; run from the MMI-Hub repo root \u2014 the manifest names which targets are org-owned and therefore propagated (and rollback-able)`);
37260
37399
  const seedSource = await resolveHubSeedSource(execGitForSeedSource);
37261
37400
  if (!seedSource.ok) return fail(`bootstrap rollback: ${seedSource.reason}`);
37262
- const manifest = loadBootstrapSeeds((0, import_node_fs32.readFileSync)(manifestPath, "utf8"));
37401
+ const manifest = loadBootstrapSeeds((0, import_node_fs33.readFileSync)(manifestPath, "utf8"));
37263
37402
  const propagatable = manifest.seeds.filter(isPropagatableSeed);
37264
37403
  if (!o.target) {
37265
37404
  return fail(`bootstrap rollback: --target <path> is required \u2014 one of:
@@ -37276,10 +37415,10 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
37276
37415
  const enc = (p) => p.split("/").map(encodeURIComponent).join("/");
37277
37416
  let candidates;
37278
37417
  if (o.record) {
37279
- if (!(0, import_node_fs32.existsSync)(o.record)) return fail(`bootstrap rollback: --record '${o.record}' not found`);
37418
+ if (!(0, import_node_fs33.existsSync)(o.record)) return fail(`bootstrap rollback: --record '${o.record}' not found`);
37280
37419
  let parsed;
37281
37420
  try {
37282
- parsed = JSON.parse((0, import_node_fs32.readFileSync)(o.record, "utf8"));
37421
+ parsed = JSON.parse((0, import_node_fs33.readFileSync)(o.record, "utf8"));
37283
37422
  } catch (e) {
37284
37423
  return fail(`bootstrap rollback: --record '${o.record}' is not valid JSON: ${e.message}`);
37285
37424
  }
@@ -37357,12 +37496,12 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
37357
37496
  existingSha = void 0;
37358
37497
  }
37359
37498
  const tmp = (0, import_node_path31.join)((0, import_node_os18.tmpdir)(), `mmi-rollback-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
37360
- (0, import_node_fs32.writeFileSync)(tmp, JSON.stringify(contentPutBody(seed.target, preSeedContent, plan.branch, existingSha)), "utf8");
37499
+ (0, import_node_fs33.writeFileSync)(tmp, JSON.stringify(contentPutBody(seed.target, preSeedContent, plan.branch, existingSha)), "utf8");
37361
37500
  try {
37362
37501
  await gh2(contentPutInputArgs(repo, seed.target, tmp));
37363
37502
  } finally {
37364
37503
  try {
37365
- (0, import_node_fs32.unlinkSync)(tmp);
37504
+ (0, import_node_fs33.unlinkSync)(tmp);
37366
37505
  } catch {
37367
37506
  }
37368
37507
  }
@@ -37819,7 +37958,7 @@ async function waitSuiteDev(deps, opts) {
37819
37958
  }
37820
37959
 
37821
37960
  // src/suite-train.ts
37822
- var import_node_fs33 = require("node:fs");
37961
+ var import_node_fs34 = require("node:fs");
37823
37962
  var import_node_path32 = require("node:path");
37824
37963
  var import_node_crypto15 = require("node:crypto");
37825
37964
 
@@ -37906,7 +38045,7 @@ function suiteReleaseTag(rc) {
37906
38045
  function readSuiteCut(path2) {
37907
38046
  let raw;
37908
38047
  try {
37909
- raw = (0, import_node_fs33.readFileSync)(path2, "utf8");
38048
+ raw = (0, import_node_fs34.readFileSync)(path2, "utf8");
37910
38049
  } catch (e) {
37911
38050
  if (e.code === "ENOENT") return void 0;
37912
38051
  throw e;
@@ -37922,11 +38061,11 @@ function readSuiteCut(path2) {
37922
38061
  return record;
37923
38062
  }
37924
38063
  function writeSuiteCut(path2, record) {
37925
- (0, import_node_fs33.mkdirSync)((0, import_node_path32.dirname)(path2), { recursive: true });
38064
+ (0, import_node_fs34.mkdirSync)((0, import_node_path32.dirname)(path2), { recursive: true });
37926
38065
  const temp = `${path2}.${(0, import_node_crypto15.randomBytes)(8).toString("hex")}.tmp`;
37927
38066
  try {
37928
- (0, import_node_fs33.writeFileSync)(temp, JSON.stringify(record, null, 2), { flag: "wx" });
37929
- (0, import_node_fs33.renameSync)(temp, path2);
38067
+ (0, import_node_fs34.writeFileSync)(temp, JSON.stringify(record, null, 2), { flag: "wx" });
38068
+ (0, import_node_fs34.renameSync)(temp, path2);
37930
38069
  } catch (e) {
37931
38070
  throw new Error(`suite cut record write failed at ${path2}: ${e.message}; stop, verify the file before retrying`);
37932
38071
  }
@@ -37975,25 +38114,25 @@ async function suiteMarkAbandoned(deps, ownerGo = false) {
37975
38114
  return tags.map((t) => `${t.repo}@${t.tag}`);
37976
38115
  }
37977
38116
  async function retireFailedLeadRcLedger(deps, ownerGo) {
37978
- if (!(0, import_node_fs33.existsSync)(deps.ledgerPath)) return void 0;
38117
+ if (!(0, import_node_fs34.existsSync)(deps.ledgerPath)) return void 0;
37979
38118
  return withLedgerLock(deps.ledgerPath, async (fence) => {
37980
- const ledger = parseReleaseLedger((0, import_node_fs33.readFileSync)(deps.ledgerPath, "utf8"));
38119
+ const ledger = parseReleaseLedger((0, import_node_fs34.readFileSync)(deps.ledgerPath, "utf8"));
37981
38120
  const states = Object.values(ledger.phases).map((p) => p.state);
37982
38121
  if (ledger.repo !== SUITE_REPO || ledger.lane !== "rcand" || ledger.phases.promotion.state === "complete" || !states.includes("failed")) return void 0;
37983
38122
  if (!ownerGo) throw new Error(`the lead's failed rcand ledger for ${ledger.tag} blocks every train; retire it with suite abandon --owner-go`);
37984
38123
  if ((await deps.rcHead())?.toLowerCase() === ledger.tagSha.toLowerCase()) throw new Error(`origin rc already points at ${ledger.tag}; it was promoted, so its ledger is not retired`);
37985
38124
  const archive = (0, import_node_path32.join)((0, import_node_path32.dirname)(deps.ledgerPath), `phases.archive-${ledger.tag}.json`);
37986
- if ((0, import_node_fs33.existsSync)(archive)) throw new Error(`ledger archive already exists at ${archive}; inspect before retiring again`);
38125
+ if ((0, import_node_fs34.existsSync)(archive)) throw new Error(`ledger archive already exists at ${archive}; inspect before retiring again`);
37987
38126
  await deps.markAbandoned(SUITE_REPO, ledger.tag, ledger.tagSha);
37988
- await fence(() => (0, import_node_fs33.renameSync)(deps.ledgerPath, archive));
38127
+ await fence(() => (0, import_node_fs34.renameSync)(deps.ledgerPath, archive));
37989
38128
  return `${ledger.tag} (ledger archived to ${archive})`;
37990
38129
  });
37991
38130
  }
37992
38131
  function suiteAbandon(recordPath, ownerGo = false, now = /* @__PURE__ */ new Date()) {
37993
38132
  const record = abandonableCut(recordPath, ownerGo);
37994
38133
  const archive = `${recordPath}.abandoned-${record.leadDevelopment.slice(0, 12)}-${now.toISOString().replace(/[:.]/g, "")}.json`;
37995
- if ((0, import_node_fs33.existsSync)(archive)) throw new Error(`abandoned-cut archive already exists at ${archive}; inspect before abandoning again`);
37996
- (0, import_node_fs33.renameSync)(recordPath, archive);
38134
+ if ((0, import_node_fs34.existsSync)(archive)) throw new Error(`abandoned-cut archive already exists at ${archive}; inspect before abandoning again`);
38135
+ (0, import_node_fs34.renameSync)(recordPath, archive);
37997
38136
  return { archive, orphanTags: record.members.filter((m) => m.tag).map((m) => `${m.repo}@${m.tag}`) };
37998
38137
  }
37999
38138
  async function suiteRestoreMainPins(deps) {
@@ -38076,12 +38215,12 @@ async function suiteRcandRun(deps, opts) {
38076
38215
  }
38077
38216
  if ((record?.announcement === "sent" || record?.announcement === "skipped") && record.leadReleased) {
38078
38217
  const archive = `${deps.recordPath}.${record.leadRcTag}.json`;
38079
- if ((0, import_node_fs33.existsSync)(archive)) throw new Error(`suite cut archive already exists at ${archive}; inspect before a new cut`);
38080
- (0, import_node_fs33.renameSync)(deps.recordPath, archive);
38218
+ if ((0, import_node_fs34.existsSync)(archive)) throw new Error(`suite cut archive already exists at ${archive}; inspect before a new cut`);
38219
+ (0, import_node_fs34.renameSync)(deps.recordPath, archive);
38081
38220
  record = void 0;
38082
38221
  }
38083
38222
  if (record && !record.pinPr && !record.leadRcTag && record.members.every((m) => !m.tag)) {
38084
- (0, import_node_fs33.rmSync)(deps.recordPath, { force: true });
38223
+ (0, import_node_fs34.rmSync)(deps.recordPath, { force: true });
38085
38224
  record = void 0;
38086
38225
  }
38087
38226
  if (!record) {
@@ -38135,7 +38274,7 @@ async function suiteRcandRun(deps, opts) {
38135
38274
  quiet.push(member);
38136
38275
  }
38137
38276
  if (record.members.every((m) => m.carried || quiet.includes(m)) && await deps.contains(SUITE_REPO, record.leadDevelopment, record.leadPreviousRc)) {
38138
- (0, import_node_fs33.rmSync)(deps.recordPath, { force: true });
38277
+ (0, import_node_fs34.rmSync)(deps.recordPath, { force: true });
38139
38278
  throw new Error("nothing to promote: neither MM-Work nor any module has new development commits since its rc; no suite cut started");
38140
38279
  }
38141
38280
  for (const member of quiet) {
@@ -38153,7 +38292,7 @@ async function suiteRcandRun(deps, opts) {
38153
38292
  }
38154
38293
  if (refusals.length) {
38155
38294
  const untouched = record.members.every((m) => !m.tag) && !record.pinPr;
38156
- if (untouched) (0, import_node_fs33.rmSync)(deps.recordPath, { force: true });
38295
+ if (untouched) (0, import_node_fs34.rmSync)(deps.recordPath, { force: true });
38157
38296
  throw new Error(`module rc serving is not ready; ${untouched ? "no suite cut started" : "no new tag was cut"}:
38158
38297
  ${refusals.join("\n")}
38159
38298
  Each module must ship a live release that bind-mounts <deployPath>/data read-only and serves <data>/rc/module.js at /rc/module.js (docs/Guides/suite-trains.md).`);
@@ -38349,7 +38488,7 @@ var hotfixRecordPath = (deps) => (0, import_node_path32.join)((0, import_node_pa
38349
38488
  function readSuiteHotfix(path2) {
38350
38489
  let raw;
38351
38490
  try {
38352
- raw = (0, import_node_fs33.readFileSync)(path2, "utf8");
38491
+ raw = (0, import_node_fs34.readFileSync)(path2, "utf8");
38353
38492
  } catch (e) {
38354
38493
  if (e.code === "ENOENT") return void 0;
38355
38494
  throw e;
@@ -38392,7 +38531,7 @@ async function suiteHotfix(deps, opts) {
38392
38531
  if (completed) record = void 0;
38393
38532
  if (record && record.repo !== found.repo) throw new Error(`an unfinished suite hotfix for ${record.repo} is recorded; finish it (rerun with that member) first`);
38394
38533
  if (!record?.tag) await deps.validateHotfixSummary();
38395
- if (completed) (0, import_node_fs33.renameSync)(path2, `${path2}.${completed.leadTag}.json`);
38534
+ if (completed) (0, import_node_fs34.renameSync)(path2, `${path2}.${completed.leadTag}.json`);
38396
38535
  const rec = record ?? { schema: "mmi-suite-hotfix/v1", member: found.id, repo: found.repo, from: opts.from, ...opts.ack?.length ? { ack: opts.ack } : {} };
38397
38536
  const save = () => writeSuiteHotfix(path2, rec);
38398
38537
  save();
@@ -38661,7 +38800,7 @@ async function runRcDataSwitch(deps, opts) {
38661
38800
  // src/suite-train-io.ts
38662
38801
  var import_node_child_process18 = require("node:child_process");
38663
38802
  var import_node_path45 = require("node:path");
38664
- var import_node_fs46 = require("node:fs");
38803
+ var import_node_fs47 = require("node:fs");
38665
38804
  var import_node_path46 = require("node:path");
38666
38805
  init_cli_shared();
38667
38806
 
@@ -40338,7 +40477,7 @@ function checkHotfixCarries(options) {
40338
40477
  }
40339
40478
 
40340
40479
  // src/merge-cleanup.ts
40341
- var import_node_fs35 = require("node:fs");
40480
+ var import_node_fs36 = require("node:fs");
40342
40481
  var import_node_path34 = require("node:path");
40343
40482
  var import_node_os19 = require("node:os");
40344
40483
  init_cli_shared();
@@ -40767,7 +40906,7 @@ function renderPrLandTable(entries) {
40767
40906
 
40768
40907
  // src/test-policy-core.ts
40769
40908
  var import_node_child_process13 = require("node:child_process");
40770
- var import_node_fs34 = require("node:fs");
40909
+ var import_node_fs35 = require("node:fs");
40771
40910
  var import_node_path33 = require("node:path");
40772
40911
 
40773
40912
  // src/test-command-policy-shared.mjs
@@ -41337,7 +41476,7 @@ function loadPolicySource(root, explicitRef, diffBase) {
41337
41476
  }
41338
41477
  function readFileOrNull2(path2) {
41339
41478
  try {
41340
- return (0, import_node_fs34.readFileSync)(path2, "utf8");
41479
+ return (0, import_node_fs35.readFileSync)(path2, "utf8");
41341
41480
  } catch {
41342
41481
  return null;
41343
41482
  }
@@ -41365,10 +41504,10 @@ function classify(changed, policy, present = () => false) {
41365
41504
  const removedProtected = [...removed].filter((p) => protectedBy.has(p)).map((p) => ({ path: p, why: protectedBy.get(p) ?? "" }));
41366
41505
  return { mandatoryHits, untestedHits, testChanges, meaningfulTestChanges, addedTests, removedProtected };
41367
41506
  }
41368
- function unresolvedProtectedEntries(policy, root, exists = (path2) => (0, import_node_fs34.existsSync)(path2)) {
41507
+ function unresolvedProtectedEntries(policy, root, exists = (path2) => (0, import_node_fs35.existsSync)(path2)) {
41369
41508
  return (policy.protected ?? []).map((p) => p.path).filter((p) => !exists((0, import_node_path33.join)(root, p)));
41370
41509
  }
41371
- function unresolvedSatisfiers(policy, root, exists = (path2) => (0, import_node_fs34.existsSync)(path2)) {
41510
+ function unresolvedSatisfiers(policy, root, exists = (path2) => (0, import_node_fs35.existsSync)(path2)) {
41372
41511
  const declared = (policy.mandatory ?? []).flatMap((m) => m.satisfiedBy ?? []);
41373
41512
  return [...new Set(declared)].filter((p) => !exists((0, import_node_path33.join)(root, p)));
41374
41513
  }
@@ -41509,7 +41648,7 @@ function runTestPolicy(root, deps = {}) {
41509
41648
  }
41510
41649
  const loaded = deps.policy ? { policy: deps.policy, source: { ref: null, sha: null, path: POLICY_FILE } } : loadPolicySource(root, deps.policyRef, deps.base);
41511
41650
  const { policy, source: policySource } = loaded;
41512
- const exists = deps.exists ?? ((path2) => (0, import_node_fs34.existsSync)(path2));
41651
+ const exists = deps.exists ?? ((path2) => (0, import_node_fs35.existsSync)(path2));
41513
41652
  const counts = { mandatoryCount: (policy.mandatory ?? []).length, protectedCount: (policy.protected ?? []).length };
41514
41653
  const base = deps.changed ? "(injected)" : deps.policyRef ? resolveHotfixBase(root) : resolveBase(root, deps.base);
41515
41654
  const refusal = deps.changed ? null : untrustworthyRange(root, base);
@@ -41807,13 +41946,13 @@ function resolveSquashMergeBodyText(commits, allowedClosing, cwd) {
41807
41946
  return rewritten === base ? null : rewritten;
41808
41947
  }
41809
41948
  function writeSquashBodyFile(body) {
41810
- const dir = (0, import_node_fs35.mkdtempSync)((0, import_node_path34.join)((0, import_node_os19.tmpdir)(), "mmi-squash-body-"));
41949
+ const dir = (0, import_node_fs36.mkdtempSync)((0, import_node_path34.join)((0, import_node_os19.tmpdir)(), "mmi-squash-body-"));
41811
41950
  const path2 = (0, import_node_path34.join)(dir, "body.txt");
41812
- (0, import_node_fs35.writeFileSync)(path2, body.endsWith("\n") ? body : `${body}
41951
+ (0, import_node_fs36.writeFileSync)(path2, body.endsWith("\n") ? body : `${body}
41813
41952
  `, "utf8");
41814
41953
  return { path: path2, cleanup: () => {
41815
41954
  try {
41816
- (0, import_node_fs35.rmSync)(dir, { recursive: true, force: true });
41955
+ (0, import_node_fs36.rmSync)(dir, { recursive: true, force: true });
41817
41956
  } catch {
41818
41957
  }
41819
41958
  } };
@@ -42102,7 +42241,7 @@ function prMergeQueueLine(result) {
42102
42241
  }
42103
42242
 
42104
42243
  // src/project-info-sync.ts
42105
- var import_node_fs36 = require("node:fs");
42244
+ var import_node_fs37 = require("node:fs");
42106
42245
  var import_node_path35 = require("node:path");
42107
42246
  var UPDATE_PROJECT_INFO = `mutation($projectId: ID!, $shortDescription: String!, $readme: String!) {
42108
42247
  updateProjectV2(input: { projectId: $projectId, shortDescription: $shortDescription, readme: $readme }) {
@@ -42151,13 +42290,13 @@ function sharedName(entries, fallback) {
42151
42290
  function buildProjectInfoSyncPlan(targetRepo2, project2, projects, repoRoot2) {
42152
42291
  if (!project2.projectId) throw new Error(`org project sync-info: ${targetRepo2} registry META has no projectId`);
42153
42292
  const readmePath = (0, import_node_path35.join)(repoRoot2, "README.md");
42154
- if (!(0, import_node_fs36.existsSync)(readmePath)) throw new Error(`org project sync-info: ${targetRepo2} has no README.md`);
42293
+ if (!(0, import_node_fs37.existsSync)(readmePath)) throw new Error(`org project sync-info: ${targetRepo2} has no README.md`);
42155
42294
  const entries = entriesFor(project2, projects);
42156
42295
  const memberRepos = [...new Set(entries.flatMap((entry) => entry.repos ?? []))].filter((repo) => /^[^/]+\/[^/]+$/.test(repo)).sort((a, b) => a.localeCompare(b));
42157
42296
  const projectName = sharedName(entries, project2.name?.trim() || targetRepo2.split("/").pop() || targetRepo2);
42158
42297
  if (!memberRepos.length) throw new Error(`org project sync-info: project ${projectName} has no registered member repos`);
42159
42298
  const entryNames = entries.map((entry) => entry.name?.trim()).filter((name) => Boolean(name));
42160
- const shortDescription = memberRepos.length === 1 ? shortDescriptionFromReadme((0, import_node_fs36.readFileSync)(readmePath, "utf8")) : `Shared work across ${new Intl.ListFormat("en", { type: "conjunction" }).format(entryNames)}.`;
42299
+ const shortDescription = memberRepos.length === 1 ? shortDescriptionFromReadme((0, import_node_fs37.readFileSync)(readmePath, "utf8")) : `Shared work across ${new Intl.ListFormat("en", { type: "conjunction" }).format(entryNames)}.`;
42161
42300
  const lines2 = [
42162
42301
  `# ${projectName}`,
42163
42302
  "",
@@ -42176,8 +42315,8 @@ function buildProjectInfoSyncPlan(targetRepo2, project2, projects, repoRoot2) {
42176
42315
  const targetBase = `https://github.com/${targetRepo2}`;
42177
42316
  const targetBranch = branchFor(targetRepo2, projects);
42178
42317
  const orgDocs = [
42179
- (0, import_node_fs36.existsSync)((0, import_node_path35.join)(repoRoot2, "architecture.md")) ? `- [Hub architecture](${targetBase}/blob/${targetBranch}/architecture.md)` : "",
42180
- (0, import_node_fs36.existsSync)((0, import_node_path35.join)(repoRoot2, "docs", "Architecture", "agentic-dev-environment.md")) ? `- [Agentic development environment](${targetBase}/blob/${targetBranch}/docs/Architecture/agentic-dev-environment.md)` : ""
42318
+ (0, import_node_fs37.existsSync)((0, import_node_path35.join)(repoRoot2, "architecture.md")) ? `- [Hub architecture](${targetBase}/blob/${targetBranch}/architecture.md)` : "",
42319
+ (0, import_node_fs37.existsSync)((0, import_node_path35.join)(repoRoot2, "docs", "Architecture", "agentic-dev-environment.md")) ? `- [Agentic development environment](${targetBase}/blob/${targetBranch}/docs/Architecture/agentic-dev-environment.md)` : ""
42181
42320
  ].filter(Boolean);
42182
42321
  if (orgDocs.length) lines2.push("", "## Organisation docs", "", ...orgDocs);
42183
42322
  return { projectId: project2.projectId, projectName, targetRepo: targetRepo2, memberRepos, shortDescription, readme: `${lines2.join("\n")}
@@ -42199,7 +42338,7 @@ async function syncProjectInfo(plan, client, apply) {
42199
42338
  }
42200
42339
 
42201
42340
  // src/train-commands.ts
42202
- var import_node_fs37 = require("node:fs");
42341
+ var import_node_fs38 = require("node:fs");
42203
42342
  var import_node_path36 = require("node:path");
42204
42343
  init_cli_shared();
42205
42344
  init_clean_exit();
@@ -42215,7 +42354,7 @@ function resolveReleaseBumpIntent(raw) {
42215
42354
  }
42216
42355
  function readRepoVersion() {
42217
42356
  try {
42218
- return JSON.parse((0, import_node_fs37.readFileSync)((0, import_node_path36.join)(process.cwd(), ".claude-plugin", "plugin.json"), "utf8")).version || void 0;
42357
+ return JSON.parse((0, import_node_fs38.readFileSync)((0, import_node_path36.join)(process.cwd(), ".claude-plugin", "plugin.json"), "utf8")).version || void 0;
42219
42358
  } catch {
42220
42359
  return void 0;
42221
42360
  }
@@ -42580,7 +42719,7 @@ async function openSuitePinPr(deps, input) {
42580
42719
 
42581
42720
  // src/command-register-collaboration.ts
42582
42721
  var import_node_child_process17 = require("node:child_process");
42583
- var import_node_fs45 = require("node:fs");
42722
+ var import_node_fs46 = require("node:fs");
42584
42723
  var import_promises8 = require("node:fs/promises");
42585
42724
  init_clean_exit();
42586
42725
  init_cli_shared();
@@ -42714,7 +42853,7 @@ init_github_client();
42714
42853
  init_github_quota();
42715
42854
 
42716
42855
  // src/issue-commands.ts
42717
- var import_node_fs38 = require("node:fs");
42856
+ var import_node_fs39 = require("node:fs");
42718
42857
  var import_node_crypto16 = require("node:crypto");
42719
42858
  init_cli_shared();
42720
42859
  init_clean_exit();
@@ -42907,7 +43046,7 @@ async function editIssue(client, options, deps = {}) {
42907
43046
  const url = `https://github.com/${repo}/issues/${parsed.number}`;
42908
43047
  const patch = {};
42909
43048
  let bodyChanged = false;
42910
- const textDeps = () => deps.textDeps ?? { readFile: (p, e) => Promise.resolve((0, import_node_fs38.readFileSync)(p, e)), readStdin: () => Promise.resolve("") };
43049
+ const textDeps = () => deps.textDeps ?? { readFile: (p, e) => Promise.resolve((0, import_node_fs39.readFileSync)(p, e)), readStdin: () => Promise.resolve("") };
42911
43050
  if (options.titleFile !== void 0) {
42912
43051
  patch.title = await resolveIssueTitle({ title: options.title, titleFile: options.titleFile }, textDeps());
42913
43052
  } else if (options.title !== void 0) {
@@ -43570,7 +43709,7 @@ function extendCreateCommand(issue, batchAttach) {
43570
43709
  if (opts.batch) {
43571
43710
  let specs;
43572
43711
  try {
43573
- const raw = (0, import_node_fs38.readFileSync)(opts.batch, "utf8");
43712
+ const raw = (0, import_node_fs39.readFileSync)(opts.batch, "utf8");
43574
43713
  specs = JSON.parse(raw);
43575
43714
  if (!Array.isArray(specs)) {
43576
43715
  const top = specs === null ? "null" : typeof specs === "object" ? `an object with keys: ${Object.keys(specs).join(", ") || "(none)"}` : `a ${typeof specs}`;
@@ -43647,7 +43786,7 @@ ${lines2}`, {
43647
43786
  }
43648
43787
 
43649
43788
  // src/post-merge-recon.ts
43650
- var import_node_fs39 = require("node:fs");
43789
+ var import_node_fs40 = require("node:fs");
43651
43790
  var import_node_path38 = require("node:path");
43652
43791
 
43653
43792
  // src/cross-repo-filing-issue.ts
@@ -43817,16 +43956,16 @@ function buildPostMergeReconRecovery(input) {
43817
43956
  }
43818
43957
  function writePostMergeReconRecovery(cwd, recovery) {
43819
43958
  const path2 = postMergeReconStatePath(cwd, recovery.repo, recovery.pr);
43820
- (0, import_node_fs39.mkdirSync)((0, import_node_path38.dirname)(path2), { recursive: true });
43821
- (0, import_node_fs39.writeFileSync)(path2, `${JSON.stringify(recovery, null, 2)}
43959
+ (0, import_node_fs40.mkdirSync)((0, import_node_path38.dirname)(path2), { recursive: true });
43960
+ (0, import_node_fs40.writeFileSync)(path2, `${JSON.stringify(recovery, null, 2)}
43822
43961
  `, "utf8");
43823
43962
  return path2;
43824
43963
  }
43825
43964
  function clearPostMergeReconRecovery(cwd, repo, pr) {
43826
43965
  const path2 = postMergeReconStatePath(cwd, repo, pr);
43827
- if (!(0, import_node_fs39.existsSync)(path2)) return;
43966
+ if (!(0, import_node_fs40.existsSync)(path2)) return;
43828
43967
  try {
43829
- (0, import_node_fs39.unlinkSync)(path2);
43968
+ (0, import_node_fs40.unlinkSync)(path2);
43830
43969
  } catch {
43831
43970
  }
43832
43971
  }
@@ -44302,7 +44441,7 @@ function registerPrLifecycleCommands(program3) {
44302
44441
 
44303
44442
  // src/review-verdict.ts
44304
44443
  var import_node_child_process14 = require("node:child_process");
44305
- var import_node_fs40 = require("node:fs");
44444
+ var import_node_fs41 = require("node:fs");
44306
44445
  var import_node_os21 = require("node:os");
44307
44446
  var import_node_path39 = require("node:path");
44308
44447
  init_cli_shared();
@@ -44469,15 +44608,15 @@ async function readPrIssueComments(number, repo) {
44469
44608
  return comments;
44470
44609
  }
44471
44610
  async function postPrCommentFromFile(number, repo, body) {
44472
- const dir = (0, import_node_fs40.mkdtempSync)((0, import_node_path39.join)((0, import_node_os21.tmpdir)(), "mmi-review-verdict-"));
44611
+ const dir = (0, import_node_fs41.mkdtempSync)((0, import_node_path39.join)((0, import_node_os21.tmpdir)(), "mmi-review-verdict-"));
44473
44612
  const path2 = (0, import_node_path39.join)(dir, "body.md");
44474
44613
  try {
44475
- (0, import_node_fs40.writeFileSync)(path2, body, "utf8");
44614
+ (0, import_node_fs41.writeFileSync)(path2, body, "utf8");
44476
44615
  const { stdout } = await execFileP("gh", ["pr", "comment", number, "--repo", repo, "--body-file", path2], { timeout: GH_MUTATION_TIMEOUT_MS });
44477
44616
  return stdout.trim();
44478
44617
  } finally {
44479
44618
  try {
44480
- (0, import_node_fs40.rmSync)(dir, { recursive: true, force: true });
44619
+ (0, import_node_fs41.rmSync)(dir, { recursive: true, force: true });
44481
44620
  } catch {
44482
44621
  }
44483
44622
  }
@@ -44711,17 +44850,17 @@ async function prCreateClaimRefusal(body, repoOption, deps = {}) {
44711
44850
  }
44712
44851
 
44713
44852
  // src/worktree-residue-sweep.ts
44714
- var import_node_fs44 = require("node:fs");
44853
+ var import_node_fs45 = require("node:fs");
44715
44854
  var import_node_path43 = require("node:path");
44716
44855
 
44717
44856
  // src/worktree-merge-cleanup.ts
44718
- var import_node_fs43 = require("node:fs");
44857
+ var import_node_fs44 = require("node:fs");
44719
44858
  var import_node_path42 = require("node:path");
44720
44859
  init_cli_shared();
44721
44860
 
44722
44861
  // src/stage-runner.ts
44723
44862
  var import_node_child_process16 = require("node:child_process");
44724
- var import_node_fs42 = require("node:fs");
44863
+ var import_node_fs43 = require("node:fs");
44725
44864
  var import_node_path41 = require("node:path");
44726
44865
  var import_node_net = require("node:net");
44727
44866
  var import_node_util5 = require("node:util");
@@ -44732,7 +44871,7 @@ function normalizeEol2(s) {
44732
44871
  }
44733
44872
 
44734
44873
  // src/env-detection.ts
44735
- var import_node_fs41 = require("node:fs");
44874
+ var import_node_fs42 = require("node:fs");
44736
44875
  var import_node_path40 = require("node:path");
44737
44876
  var SKIPPED_DIRS = /* @__PURE__ */ new Set([".git", "node_modules", "dist", ".jerv", ".pi", ".venv", "venv"]);
44738
44877
  function isEnvBaseName(name) {
@@ -44743,7 +44882,7 @@ function findEnvFiles(root) {
44743
44882
  const walk2 = (dir, rel) => {
44744
44883
  let entries;
44745
44884
  try {
44746
- entries = (0, import_node_fs41.readdirSync)(dir, { withFileTypes: true });
44885
+ entries = (0, import_node_fs42.readdirSync)(dir, { withFileTypes: true });
44747
44886
  } catch {
44748
44887
  return;
44749
44888
  }
@@ -44757,7 +44896,7 @@ function findEnvFiles(root) {
44757
44896
  if (isEnvBaseName(entry.name)) {
44758
44897
  let isDir = false;
44759
44898
  try {
44760
- isDir = (0, import_node_fs41.lstatSync)((0, import_node_path40.join)(dir, entry.name)).isDirectory();
44899
+ isDir = (0, import_node_fs42.lstatSync)((0, import_node_path40.join)(dir, entry.name)).isDirectory();
44761
44900
  } catch {
44762
44901
  }
44763
44902
  if (!isDir) found.push(relPath);
@@ -44896,12 +45035,12 @@ var DOCKER_TIMEOUT_MS = 15e3;
44896
45035
  function stageBash() {
44897
45036
  if (process.platform !== "win32") return "bash";
44898
45037
  const configured = process.env.SHELL;
44899
- if (configured && (0, import_node_path41.isAbsolute)(configured) && /[/\\]bash(?:\.exe)?$/i.test(configured) && !/[/\\](?:System32|Sysnative)[/\\]bash(?:\.exe)?$/i.test(configured) && (0, import_node_fs42.existsSync)(configured)) return configured;
45038
+ if (configured && (0, import_node_path41.isAbsolute)(configured) && /[/\\]bash(?:\.exe)?$/i.test(configured) && !/[/\\](?:System32|Sysnative)[/\\]bash(?:\.exe)?$/i.test(configured) && (0, import_node_fs43.existsSync)(configured)) return configured;
44900
45039
  const candidates = [
44901
45040
  (0, import_node_path41.join)(process.env.ProgramFiles || "C:\\Program Files", "Git", "bin", "bash.exe"),
44902
45041
  ...process.env.LOCALAPPDATA ? [(0, import_node_path41.join)(process.env.LOCALAPPDATA, "Programs", "Git", "bin", "bash.exe")] : []
44903
45042
  ];
44904
- const bash = candidates.find((path2) => (0, import_node_fs42.existsSync)(path2));
45043
+ const bash = candidates.find((path2) => (0, import_node_fs43.existsSync)(path2));
44905
45044
  if (!bash) throw new Error("Local stages require Git Bash on Windows. Install Git for Windows or set SHELL to its absolute bash.exe path.");
44906
45045
  return bash;
44907
45046
  }
@@ -45257,7 +45396,7 @@ function stageProcessEnv(stagePort, extraEnv) {
45257
45396
  function composeResolvesPort(cwd) {
45258
45397
  if (process.env.PORT) return true;
45259
45398
  const envFile = (0, import_node_path41.join)(cwd, ".env");
45260
- return (0, import_node_fs42.existsSync)(envFile) && envFileKeys((0, import_node_fs42.readFileSync)(envFile, "utf8")).has("PORT");
45399
+ return (0, import_node_fs43.existsSync)(envFile) && envFileKeys((0, import_node_fs43.readFileSync)(envFile, "utf8")).has("PORT");
45261
45400
  }
45262
45401
  function stageComposeEnv(config, stagePort, vaultEnvMerge, cwd) {
45263
45402
  const composeProject = config.env?.COMPOSE_PROJECT_NAME ?? vaultEnvMerge?.COMPOSE_PROJECT_NAME ?? stageComposeProjectName(cwd);
@@ -45272,13 +45411,13 @@ function stageComposeEnv(config, stagePort, vaultEnvMerge, cwd) {
45272
45411
  function stageComposeFiles(cwd) {
45273
45412
  const files = ["docker-compose.yml"];
45274
45413
  for (const conventional of ["docker-compose.override.yml", "docker-compose.override.yaml"]) {
45275
- if ((0, import_node_fs42.existsSync)((0, import_node_path41.join)(cwd, conventional))) files.push(conventional);
45414
+ if ((0, import_node_fs43.existsSync)((0, import_node_path41.join)(cwd, conventional))) files.push(conventional);
45276
45415
  }
45277
45416
  return [...files, RUNTIME_ENV_OVERRIDE_RELPATH];
45278
45417
  }
45279
45418
  async function prepareRuntimeEnvPassthrough(cwd, composeEnv, vaultEnvMerge) {
45280
45419
  const keys = Object.keys(vaultEnvMerge ?? {});
45281
- if (!keys.length || !(0, import_node_fs42.existsSync)((0, import_node_path41.join)(cwd, "docker-compose.yml"))) return {};
45420
+ if (!keys.length || !(0, import_node_fs43.existsSync)((0, import_node_path41.join)(cwd, "docker-compose.yml"))) return {};
45282
45421
  let configJson;
45283
45422
  try {
45284
45423
  const { stdout } = await execFileP3("docker", ["compose", "config", "--format", "json"], {
@@ -45295,20 +45434,20 @@ async function prepareRuntimeEnvPassthrough(cwd, composeEnv, vaultEnvMerge) {
45295
45434
  const body = renderRuntimeEnvOverride(runtimeEnvMarkedServices(configJson), keys, runtimeEnvExcludes(configJson), runtimeEnvSelects(configJson));
45296
45435
  if (!body) return {};
45297
45436
  const overridePath = (0, import_node_path41.join)(cwd, RUNTIME_ENV_OVERRIDE_RELPATH);
45298
- (0, import_node_fs42.mkdirSync)((0, import_node_path41.join)(cwd, "tmp", "stage"), { recursive: true });
45299
- (0, import_node_fs42.writeFileSync)(overridePath, body, "utf8");
45437
+ (0, import_node_fs43.mkdirSync)((0, import_node_path41.join)(cwd, "tmp", "stage"), { recursive: true });
45438
+ (0, import_node_fs43.writeFileSync)(overridePath, body, "utf8");
45300
45439
  return stageComposeFileEnv(stageComposeFiles(cwd));
45301
45440
  }
45302
45441
  async function ensureStageRuntimeEnv(config, opts, cwd) {
45303
45442
  if (!config.ensureEnv) return;
45304
45443
  const target = (0, import_node_path41.join)(cwd, config.ensureEnv.target);
45305
45444
  const example = (0, import_node_path41.join)(cwd, config.ensureEnv.example);
45306
- if (!(0, import_node_fs42.existsSync)(target) && (0, import_node_fs42.existsSync)(example)) {
45307
- (0, import_node_fs42.copyFileSync)(example, target);
45308
- } else if ((0, import_node_fs42.existsSync)(target) && (0, import_node_fs42.existsSync)(example)) {
45309
- const stale = detectStaleEnvFile((0, import_node_fs42.readFileSync)(example, "utf8"), (0, import_node_fs42.readFileSync)(target, "utf8"), {
45310
- exampleMtimeMs: (0, import_node_fs42.statSync)(example).mtimeMs,
45311
- targetMtimeMs: (0, import_node_fs42.statSync)(target).mtimeMs
45445
+ if (!(0, import_node_fs43.existsSync)(target) && (0, import_node_fs43.existsSync)(example)) {
45446
+ (0, import_node_fs43.copyFileSync)(example, target);
45447
+ } else if ((0, import_node_fs43.existsSync)(target) && (0, import_node_fs43.existsSync)(example)) {
45448
+ const stale = detectStaleEnvFile((0, import_node_fs43.readFileSync)(example, "utf8"), (0, import_node_fs43.readFileSync)(target, "utf8"), {
45449
+ exampleMtimeMs: (0, import_node_fs43.statSync)(example).mtimeMs,
45450
+ targetMtimeMs: (0, import_node_fs43.statSync)(target).mtimeMs
45312
45451
  });
45313
45452
  if (stale) {
45314
45453
  const msg = `stale ${config.ensureEnv.target} (${stale}) \u2014 delete it or refresh from ${config.ensureEnv.example} before re-running /stage`;
@@ -45316,8 +45455,8 @@ async function ensureStageRuntimeEnv(config, opts, cwd) {
45316
45455
  console.error(`mmi-cli stage: ${msg} (allowed via --allow-stale-env)`);
45317
45456
  }
45318
45457
  }
45319
- if (opts.vaultEnvMerge && Object.keys(opts.vaultEnvMerge).length && (0, import_node_fs42.existsSync)(target)) {
45320
- (0, import_node_fs42.writeFileSync)(target, mergeEnvSecretsIntoFile((0, import_node_fs42.readFileSync)(target, "utf8"), opts.vaultEnvMerge), "utf8");
45458
+ if (opts.vaultEnvMerge && Object.keys(opts.vaultEnvMerge).length && (0, import_node_fs43.existsSync)(target)) {
45459
+ (0, import_node_fs43.writeFileSync)(target, mergeEnvSecretsIntoFile((0, import_node_fs43.readFileSync)(target, "utf8"), opts.vaultEnvMerge), "utf8");
45321
45460
  }
45322
45461
  }
45323
45462
  async function gitText(cwd, args) {
@@ -45347,20 +45486,20 @@ async function resolveGlobalStatePath(cwd, explicit) {
45347
45486
  return void 0;
45348
45487
  }
45349
45488
  function readState(path2) {
45350
- if (!(0, import_node_fs42.existsSync)(path2)) return null;
45489
+ if (!(0, import_node_fs43.existsSync)(path2)) return null;
45351
45490
  try {
45352
- return JSON.parse((0, import_node_fs42.readFileSync)(path2, "utf8"));
45491
+ return JSON.parse((0, import_node_fs43.readFileSync)(path2, "utf8"));
45353
45492
  } catch {
45354
45493
  return null;
45355
45494
  }
45356
45495
  }
45357
45496
  function mkdirFor(path2) {
45358
45497
  const dir = path2.slice(0, Math.max(path2.lastIndexOf("/"), path2.lastIndexOf("\\")));
45359
- (0, import_node_fs42.mkdirSync)(dir, { recursive: true });
45498
+ (0, import_node_fs43.mkdirSync)(dir, { recursive: true });
45360
45499
  }
45361
45500
  function writeState(path2, state) {
45362
45501
  mkdirFor(path2);
45363
- (0, import_node_fs42.writeFileSync)(path2, JSON.stringify(state, null, 2), "utf8");
45502
+ (0, import_node_fs43.writeFileSync)(path2, JSON.stringify(state, null, 2), "utf8");
45364
45503
  }
45365
45504
  function writeStagePortReservation(port, cwd, statePath, globalStatePath, now) {
45366
45505
  const reservation = {
@@ -45389,7 +45528,7 @@ async function cleanupStageState(state, paths, timeoutMs, fallbackCwd, currentEn
45389
45528
  );
45390
45529
  }
45391
45530
  for (const path2 of [...new Set(paths.filter((p) => Boolean(p)))]) {
45392
- (0, import_node_fs42.rmSync)(path2, { force: true });
45531
+ (0, import_node_fs43.rmSync)(path2, { force: true });
45393
45532
  }
45394
45533
  }
45395
45534
  async function killTree(pid) {
@@ -45636,8 +45775,8 @@ async function runStage(config = {}, opts = {}) {
45636
45775
  });
45637
45776
  }
45638
45777
  } catch (e) {
45639
- (0, import_node_fs42.rmSync)(statePath, { force: true });
45640
- if (globalStatePath && globalStatePath !== statePath) (0, import_node_fs42.rmSync)(globalStatePath, { force: true });
45778
+ (0, import_node_fs43.rmSync)(statePath, { force: true });
45779
+ if (globalStatePath && globalStatePath !== statePath) (0, import_node_fs43.rmSync)(globalStatePath, { force: true });
45641
45780
  throw e;
45642
45781
  }
45643
45782
  const started = await startStage(config, {
@@ -45658,7 +45797,7 @@ function normPath2(p) {
45658
45797
  function unlinkNodeModulesJunction(wtPath) {
45659
45798
  const nm = (0, import_node_path42.join)(wtPath, "node_modules");
45660
45799
  try {
45661
- if ((0, import_node_fs43.lstatSync)(nm).isSymbolicLink()) (0, import_node_fs43.rmdirSync)(nm);
45800
+ if ((0, import_node_fs44.lstatSync)(nm).isSymbolicLink()) (0, import_node_fs44.rmdirSync)(nm);
45662
45801
  return { ok: true };
45663
45802
  } catch (e) {
45664
45803
  if (e.code === "ENOENT") return { ok: true };
@@ -45669,8 +45808,8 @@ function defaultSleep2(ms) {
45669
45808
  return new Promise((resolve8) => setTimeout(resolve8, ms));
45670
45809
  }
45671
45810
  async function removeResidueDirectory(wtPath, options = {}) {
45672
- const { sleep: sleep2 = defaultSleep2, removeEmptyDir = import_node_fs43.rmdirSync, exists = import_node_fs43.existsSync } = options;
45673
- const removeRecursive = options.removeRecursive ?? ((path2) => (0, import_node_fs43.rmSync)(path2, { recursive: true, force: true, maxRetries: 10, retryDelay: 100 }));
45811
+ const { sleep: sleep2 = defaultSleep2, removeEmptyDir = import_node_fs44.rmdirSync, exists = import_node_fs44.existsSync } = options;
45812
+ const removeRecursive = options.removeRecursive ?? ((path2) => (0, import_node_fs44.rmSync)(path2, { recursive: true, force: true, maxRetries: 10, retryDelay: 100 }));
45674
45813
  const junction = unlinkNodeModulesJunction(wtPath);
45675
45814
  if (!junction.ok) return junction;
45676
45815
  try {
@@ -45796,21 +45935,21 @@ async function listNestedIgnoredNodeModules(wtPath, execGit) {
45796
45935
  return out.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.endsWith("node_modules/") && line !== "node_modules/").map((line) => (0, import_node_path42.join)(wtPath, line.slice(0, -1)));
45797
45936
  }
45798
45937
  function safeRemoveTree(path2) {
45799
- const stat4 = (0, import_node_fs43.lstatSync)(path2);
45938
+ const stat4 = (0, import_node_fs44.lstatSync)(path2);
45800
45939
  if (stat4.isSymbolicLink()) {
45801
45940
  try {
45802
- (0, import_node_fs43.rmdirSync)(path2);
45941
+ (0, import_node_fs44.rmdirSync)(path2);
45803
45942
  } catch {
45804
- (0, import_node_fs43.unlinkSync)(path2);
45943
+ (0, import_node_fs44.unlinkSync)(path2);
45805
45944
  }
45806
45945
  return;
45807
45946
  }
45808
45947
  if (stat4.isDirectory()) {
45809
- for (const entry of (0, import_node_fs43.readdirSync)(path2)) safeRemoveTree((0, import_node_path42.join)(path2, entry));
45810
- (0, import_node_fs43.rmdirSync)(path2);
45948
+ for (const entry of (0, import_node_fs44.readdirSync)(path2)) safeRemoveTree((0, import_node_path42.join)(path2, entry));
45949
+ (0, import_node_fs44.rmdirSync)(path2);
45811
45950
  return;
45812
45951
  }
45813
- (0, import_node_fs43.unlinkSync)(path2);
45952
+ (0, import_node_fs44.unlinkSync)(path2);
45814
45953
  }
45815
45954
  async function removeWorktreeNodeModules(wtPath) {
45816
45955
  try {
@@ -45826,7 +45965,7 @@ function errorMessage(e) {
45826
45965
  }
45827
45966
  function resolvedOrRaw(path2) {
45828
45967
  try {
45829
- return normPath2((0, import_node_fs43.realpathSync)(path2));
45968
+ return normPath2((0, import_node_fs44.realpathSync)(path2));
45830
45969
  } catch {
45831
45970
  return normPath2(path2);
45832
45971
  }
@@ -45834,10 +45973,10 @@ function resolvedOrRaw(path2) {
45834
45973
  function unlinkEscapingReparsePoints(root, primaryRoot) {
45835
45974
  let realRoot;
45836
45975
  try {
45837
- if ((0, import_node_fs43.lstatSync)(root).isSymbolicLink()) {
45976
+ if ((0, import_node_fs44.lstatSync)(root).isSymbolicLink()) {
45838
45977
  return { ok: false, error: `delete root ${normPath2(root)} is a reparse point resolving to ${resolvedOrRaw(root)}` };
45839
45978
  }
45840
- realRoot = normPath2((0, import_node_fs43.realpathSync)(root));
45979
+ realRoot = normPath2((0, import_node_fs44.realpathSync)(root));
45841
45980
  } catch (e) {
45842
45981
  if (e.code === "ENOENT") return { ok: true, unlinked: [] };
45843
45982
  return { ok: false, error: `cannot resolve delete root ${normPath2(root)}: ${errorMessage(e)}` };
@@ -45853,7 +45992,7 @@ function unlinkEscapingReparsePoints(root, primaryRoot) {
45853
45992
  const dir = stack.pop();
45854
45993
  let entries;
45855
45994
  try {
45856
- entries = (0, import_node_fs43.readdirSync)(dir, { withFileTypes: true });
45995
+ entries = (0, import_node_fs44.readdirSync)(dir, { withFileTypes: true });
45857
45996
  } catch (e) {
45858
45997
  if (e.code === "ENOENT") continue;
45859
45998
  return { ok: false, error: `cannot scan ${normPath2(dir)} for reparse points: ${errorMessage(e)}` };
@@ -45863,7 +46002,7 @@ function unlinkEscapingReparsePoints(root, primaryRoot) {
45863
46002
  if (entry.isSymbolicLink()) {
45864
46003
  let target = "";
45865
46004
  try {
45866
- target = normPath2((0, import_node_fs43.realpathSync)(child2));
46005
+ target = normPath2((0, import_node_fs44.realpathSync)(child2));
45867
46006
  } catch {
45868
46007
  target = "";
45869
46008
  }
@@ -46046,7 +46185,7 @@ async function cleanupPrMergeLocalBranch(branch, options) {
46046
46185
  return report;
46047
46186
  }
46048
46187
  const execGit = options.execGit ?? (async (args) => (await execFileP("git", args, { timeout: GIT_TIMEOUT_MS })).stdout);
46049
- const pathExists = options.pathExists ?? import_node_fs43.existsSync;
46188
+ const pathExists = options.pathExists ?? import_node_fs44.existsSync;
46050
46189
  let afterWorktrees = [];
46051
46190
  try {
46052
46191
  afterWorktrees = parseGitWorktreePorcelain(await execGit(["worktree", "list", "--porcelain"]));
@@ -46333,7 +46472,7 @@ function residueLedgerPath(gitCommonDir) {
46333
46472
  }
46334
46473
  function readPaths(file, deps) {
46335
46474
  try {
46336
- const parsed = JSON.parse((deps.readLedger ?? ((f) => (0, import_node_fs44.readFileSync)(f, "utf8")))(file));
46475
+ const parsed = JSON.parse((deps.readLedger ?? ((f) => (0, import_node_fs45.readFileSync)(f, "utf8")))(file));
46337
46476
  return Array.isArray(parsed) ? parsed.filter((p) => typeof p === "string") : [];
46338
46477
  } catch {
46339
46478
  return [];
@@ -46342,8 +46481,8 @@ function readPaths(file, deps) {
46342
46481
  function writePaths(file, paths, deps) {
46343
46482
  try {
46344
46483
  const write = deps.writeLedger ?? ((f, t) => {
46345
- (0, import_node_fs44.mkdirSync)((0, import_node_path43.dirname)(f), { recursive: true });
46346
- (0, import_node_fs44.writeFileSync)(f, t, "utf8");
46484
+ (0, import_node_fs45.mkdirSync)((0, import_node_path43.dirname)(f), { recursive: true });
46485
+ (0, import_node_fs45.writeFileSync)(f, t, "utf8");
46347
46486
  });
46348
46487
  write(file, `${JSON.stringify([...new Set(paths)], null, 1)}
46349
46488
  `);
@@ -46357,17 +46496,17 @@ function recordResidue(gitCommonDir, path2, deps = {}) {
46357
46496
  writePaths(file, paths, deps);
46358
46497
  }
46359
46498
  async function sweepWorktreeResidue(gitCommonDir, registered, deps = {}) {
46360
- const exists = deps.exists ?? import_node_fs44.existsSync;
46361
- const readDir = deps.readDir ?? ((p) => (0, import_node_fs44.readdirSync)(p));
46499
+ const exists = deps.exists ?? import_node_fs45.existsSync;
46500
+ const readDir = deps.readDir ?? ((p) => (0, import_node_fs45.readdirSync)(p));
46362
46501
  const isDir = deps.isDir ?? ((p) => {
46363
46502
  try {
46364
- return (0, import_node_fs44.statSync)(p).isDirectory();
46503
+ return (0, import_node_fs45.statSync)(p).isDirectory();
46365
46504
  } catch {
46366
46505
  return false;
46367
46506
  }
46368
46507
  });
46369
46508
  const removeRecorded = deps.removeRecorded ?? ((p) => removeResidueDirectory(p));
46370
- const removeEmpty = deps.removeEmpty ?? ((p) => (0, import_node_fs44.rmdirSync)(p));
46509
+ const removeEmpty = deps.removeEmpty ?? ((p) => (0, import_node_fs45.rmdirSync)(p));
46371
46510
  const report = { swept: [], kept: [], dropped: [], emptyRemoved: [], unrecorded: [] };
46372
46511
  const live = new Set(registered.map(norm));
46373
46512
  const primary = registered[0] ? norm(registered[0]) : void 0;
@@ -46447,8 +46586,8 @@ function argvWantsJson2() {
46447
46586
  function hubRoot() {
46448
46587
  const fromPkg = (0, import_node_path44.join)(__dirname, "..", "..");
46449
46588
  const marker = "skills/bootstrap/seeds/manifest.json";
46450
- if ((0, import_node_fs45.existsSync)((0, import_node_path44.join)(fromPkg, marker))) return fromPkg;
46451
- if ((0, import_node_fs45.existsSync)((0, import_node_path44.join)(process.cwd(), marker))) return process.cwd();
46589
+ if ((0, import_node_fs46.existsSync)((0, import_node_path44.join)(fromPkg, marker))) return fromPkg;
46590
+ if ((0, import_node_fs46.existsSync)((0, import_node_path44.join)(process.cwd(), marker))) return process.cwd();
46452
46591
  return null;
46453
46592
  }
46454
46593
  function ciAuditDeps() {
@@ -46461,7 +46600,7 @@ function ciAuditDeps() {
46461
46600
  readSeedFile: (path2) => {
46462
46601
  if (!root) return null;
46463
46602
  const fullPath = (0, import_node_path44.join)(root, path2);
46464
- return (0, import_node_fs45.existsSync)(fullPath) ? (0, import_node_fs45.readFileSync)(fullPath, "utf8") : null;
46603
+ return (0, import_node_fs46.existsSync)(fullPath) ? (0, import_node_fs46.readFileSync)(fullPath, "utf8") : null;
46465
46604
  }
46466
46605
  };
46467
46606
  }
@@ -47225,10 +47364,10 @@ ${list}`);
47225
47364
  });
47226
47365
  async function listCiWorkflowPaths(cwd = process.cwd()) {
47227
47366
  const wfDir = (0, import_node_path44.join)(cwd, ".github", "workflows");
47228
- if (!(0, import_node_fs45.existsSync)(wfDir)) return [];
47229
- return (0, import_node_fs45.readdirSync)(wfDir).filter((name) => /\.(ya?ml)$/i.test(name)).filter((name) => {
47367
+ if (!(0, import_node_fs46.existsSync)(wfDir)) return [];
47368
+ return (0, import_node_fs46.readdirSync)(wfDir).filter((name) => /\.(ya?ml)$/i.test(name)).filter((name) => {
47230
47369
  try {
47231
- return workflowReportsPrChecks((0, import_node_fs45.readFileSync)((0, import_node_path44.join)(wfDir, name), "utf8"));
47370
+ return workflowReportsPrChecks((0, import_node_fs46.readFileSync)((0, import_node_path44.join)(wfDir, name), "utf8"));
47232
47371
  } catch {
47233
47372
  return true;
47234
47373
  }
@@ -47433,7 +47572,7 @@ ${list}`);
47433
47572
  jsonParity(pr.command("review-verdict <number>").description("post an explicit review verdict comment: computes the PR diff patch-id and head sha, renders the v1 contract body, and posts it as a PR comment").requiredOption("--repo <owner/repo>", "target repo").requiredOption("--verdict <verdict>", `one of ${REVIEW_VERDICTS.join("|")}`).requiredOption("--scope <text>", "one line: what was reviewed").requiredOption("--risk <text>", "one line: the residual risk").option("--unverified <text>", "a claim the reviewer could not verify (repeatable)", (v, acc) => [...acc, v], []).requiredOption("--reviewer <id>", "reviewer seat or model id").option("--findings-file <path>", "Markdown findings appended after the JSON block")).action(async (number, o) => {
47434
47573
  if (!isReviewVerdict(o.verdict)) return fail(`pr review-verdict: --verdict must be one of ${REVIEW_VERDICTS.join("|")} (got ${o.verdict})`);
47435
47574
  const verdict = o.verdict;
47436
- const findings = o.findingsFile ? (0, import_node_fs45.readFileSync)(o.findingsFile, "utf8") : void 0;
47575
+ const findings = o.findingsFile ? (0, import_node_fs46.readFileSync)(o.findingsFile, "utf8") : void 0;
47437
47576
  let patch;
47438
47577
  let head;
47439
47578
  try {
@@ -47689,7 +47828,7 @@ ${list}`);
47689
47828
  const cleanupMerged = async (r) => {
47690
47829
  if (opts.preserveWorktree) return "cleanup skipped (--preserve-worktree)";
47691
47830
  const ran = await execFileP(process.execPath, [process.argv[1], ...canonicalArgvFor(["pr", "merge", r.pr, "--repo", r.repo])], {
47692
- cwd: (0, import_node_fs45.existsSync)(cwd0) ? cwd0 : primaryRoot0,
47831
+ cwd: (0, import_node_fs46.existsSync)(cwd0) ? cwd0 : primaryRoot0,
47693
47832
  timeout: GH_MUTATION_TIMEOUT_MS * 3
47694
47833
  }).then((x) => ({ stdout: x.stdout, stderr: x.stderr }), (e) => ({ stdout: e.stdout ?? "", stderr: e.stderr ?? "" }));
47695
47834
  const json = ran.stdout.split("\n").reverse().find((l) => l.startsWith("{"));
@@ -47759,7 +47898,7 @@ ${list}`);
47759
47898
  const mergeSquashBody = squashBodyTextForMerge(
47760
47899
  closingGuardInput,
47761
47900
  method === "--squash",
47762
- o.squashBodyFile ? (0, import_node_fs45.readFileSync)(o.squashBodyFile, "utf8") : void 0
47901
+ o.squashBodyFile ? (0, import_node_fs46.readFileSync)(o.squashBodyFile, "utf8") : void 0
47763
47902
  );
47764
47903
  if (!o.squashBodyFile) warnSquashBodyClosingStrip("pr merge", closingGuardInput, mergeSquashBody);
47765
47904
  const closingGuardVerdict = evaluateClosingGuard(closingGuardInput, {
@@ -47910,7 +48049,7 @@ ${list}`);
47910
48049
  }
47911
48050
  if (!repoForPostCleanup) throw e;
47912
48051
  console.warn(`pr merge: gh GraphQL rate-limited \u2014 merging PR #${number} via REST PUT instead (#4588).`);
47913
- const commitMessage = bodyFile ? (0, import_node_fs45.readFileSync)(bodyFile, "utf8") : void 0;
48052
+ const commitMessage = bodyFile ? (0, import_node_fs46.readFileSync)(bodyFile, "utf8") : void 0;
47914
48053
  await defaultGitHubClient().rest("PUT", `repos/${repoForPostCleanup}/pulls/${number}/merge`, {
47915
48054
  body: { merge_method: method.slice(2), ...commitMessage ? { commit_message: commitMessage } : {} },
47916
48055
  timeoutMs: GH_MUTATION_TIMEOUT_MS
@@ -48043,7 +48182,7 @@ ${list}`);
48043
48182
  preserveWorktree: o.preserveWorktree,
48044
48183
  gcAcknowledged: o.gc,
48045
48184
  expectedHeadOid: headRefOid,
48046
- pathExists: (p) => (0, import_node_fs45.existsSync)(p),
48185
+ pathExists: (p) => (0, import_node_fs46.existsSync)(p),
48047
48186
  // #5899: pin cleanup git calls to the main checkout — the task worktree this process may be
48048
48187
  // standing in is removed mid-cleanup, so a cwd-relative invocation fails with
48049
48188
  // 'fatal: not a git repository' and leaves a spurious partial-cleanup exit.
@@ -49343,11 +49482,11 @@ function suiteTrainIo(root, summaryFile, memberSummaryFiles = {}, summaryFileTr,
49343
49482
  const checkout = async (repo) => {
49344
49483
  if (repo === SUITE_REPO) return root;
49345
49484
  const target = (0, import_node_path46.join)(base, repo.split("/")[1]);
49346
- if (!(0, import_node_fs46.existsSync)(target)) {
49347
- (0, import_node_fs46.mkdirSync)(base, { recursive: true });
49485
+ if (!(0, import_node_fs47.existsSync)(target)) {
49486
+ (0, import_node_fs47.mkdirSync)(base, { recursive: true });
49348
49487
  await exec("git", ["clone", "--quiet", "--branch", "development", `https://github.com/${repo}.git`, target], root, WATCH_TIMEOUT);
49349
49488
  }
49350
- if (!(0, import_node_fs46.existsSync)((0, import_node_path46.join)(target, ".git"))) throw new Error(`${repo}: suite checkout has no .git at ${target}; stop`);
49489
+ if (!(0, import_node_fs47.existsSync)((0, import_node_path46.join)(target, ".git"))) throw new Error(`${repo}: suite checkout has no .git at ${target}; stop`);
49351
49490
  const origin = await exec("git", ["remote", "get-url", "origin"], target);
49352
49491
  if (!origin.toLowerCase().endsWith(`/${repo.toLowerCase()}.git`) && !origin.toLowerCase().endsWith(`/${repo.toLowerCase()}`))
49353
49492
  throw new Error(`${repo}: suite checkout origin mismatch at ${target}; stop`);
@@ -49654,9 +49793,9 @@ function suiteTrainIo(root, summaryFile, memberSummaryFiles = {}, summaryFileTr,
49654
49793
  const body = await gh(["release", "view", leadTag, "--repo", SUITE_REPO, "--json", "body", "--jq", ".body"]);
49655
49794
  if (parseSuiteMapping(body)) return;
49656
49795
  const dir = suiteStateDir(root);
49657
- (0, import_node_fs46.mkdirSync)(dir, { recursive: true });
49796
+ (0, import_node_fs47.mkdirSync)(dir, { recursive: true });
49658
49797
  const file = (0, import_node_path46.join)(dir, `notes-${leadTag}.md`);
49659
- (0, import_node_fs46.writeFileSync)(file, `${body}
49798
+ (0, import_node_fs47.writeFileSync)(file, `${body}
49660
49799
 
49661
49800
  ${suiteMappingBlock(leadTag, mapping)}`);
49662
49801
  await gh(["release", "edit", leadTag, "--repo", SUITE_REPO, "--notes-file", file]);
@@ -49697,7 +49836,7 @@ ${suiteMappingBlock(leadTag, mapping)}`);
49697
49836
 
49698
49837
  // src/suite-commands.ts
49699
49838
  init_cli_shared();
49700
- var import_node_fs47 = require("node:fs");
49839
+ var import_node_fs48 = require("node:fs");
49701
49840
  function parseMemberSummaryFiles(entries) {
49702
49841
  const memberSummaryFiles = {};
49703
49842
  for (const entry of entries) {
@@ -49791,7 +49930,7 @@ function registerSuiteCommands(program3) {
49791
49930
  try {
49792
49931
  const io = suiteTrainIo(root);
49793
49932
  retired = await retireFailedLeadRcLedger({ ledgerPath: releaseLedgerPath(root), rcHead: () => io.head(SUITE_REPO, "rc").then((h) => h ?? void 0), markAbandoned: io.markAbandoned }, o.ownerGo === true);
49794
- if (retired && !(0, import_node_fs47.existsSync)(io.recordPath)) {
49933
+ if (retired && !(0, import_node_fs48.existsSync)(io.recordPath)) {
49795
49934
  console.log(o.json ? JSON.stringify({ retiredLeadRc: retired }, null, 2) : `suite abandon: retired the lead's failed, never-promoted rc candidate ${retired}; marked abandoned on origin (#7854)`);
49796
49935
  return;
49797
49936
  }
@@ -49980,7 +50119,7 @@ function suiteStatusDeps(github, registry2) {
49980
50119
 
49981
50120
  // src/packages-adopt-export.ts
49982
50121
  var import_node_child_process19 = require("node:child_process");
49983
- var import_node_fs48 = require("node:fs");
50122
+ var import_node_fs49 = require("node:fs");
49984
50123
  var import_node_os22 = require("node:os");
49985
50124
  var import_node_path47 = require("node:path");
49986
50125
  var import_node_util6 = require("node:util");
@@ -50604,36 +50743,36 @@ async function adoptExport(opts, deps) {
50604
50743
  if (!/^sha256:[0-9a-f]{64}$/.test(opts.digest)) throw new Error("--digest must be sha256:<64 hex>, from the export run summary");
50605
50744
  const packagePath = (0, import_node_path47.join)(opts.dir, "package.json");
50606
50745
  const lockPath = (0, import_node_path47.join)(opts.dir, "package-lock.json");
50607
- const packageText = (0, import_node_fs48.readFileSync)(packagePath, "utf8");
50608
- const lockText = (0, import_node_fs48.readFileSync)(lockPath, "utf8");
50609
- const work = (0, import_node_fs48.mkdtempSync)((0, import_node_path47.join)((0, import_node_os22.tmpdir)(), "mmi-adopt-export-"));
50746
+ const packageText = (0, import_node_fs49.readFileSync)(packagePath, "utf8");
50747
+ const lockText = (0, import_node_fs49.readFileSync)(lockPath, "utf8");
50748
+ const work = (0, import_node_fs49.mkdtempSync)((0, import_node_path47.join)((0, import_node_os22.tmpdir)(), "mmi-adopt-export-"));
50610
50749
  try {
50611
50750
  const run = JSON.parse((await deps.ghApi(`repos/${EXPORT_REPO}/actions/runs/${opts.run}`)).toString("utf8"));
50612
- (0, import_node_fs48.writeFileSync)((0, import_node_path47.join)(work, "expected.json"), JSON.stringify(expectedFromRun(run, opts)));
50613
- (0, import_node_fs48.writeFileSync)((0, import_node_path47.join)(work, "provider.json"), await deps.ghApi(`repos/${EXPORT_REPO}/actions/artifacts/${opts.artifact}`));
50614
- (0, import_node_fs48.writeFileSync)((0, import_node_path47.join)(work, "artifact.zip"), await deps.ghApi(`repos/${EXPORT_REPO}/actions/artifacts/${opts.artifact}/zip`));
50751
+ (0, import_node_fs49.writeFileSync)((0, import_node_path47.join)(work, "expected.json"), JSON.stringify(expectedFromRun(run, opts)));
50752
+ (0, import_node_fs49.writeFileSync)((0, import_node_path47.join)(work, "provider.json"), await deps.ghApi(`repos/${EXPORT_REPO}/actions/artifacts/${opts.artifact}`));
50753
+ (0, import_node_fs49.writeFileSync)((0, import_node_path47.join)(work, "artifact.zip"), await deps.ghApi(`repos/${EXPORT_REPO}/actions/artifacts/${opts.artifact}/zip`));
50615
50754
  const script = (0, import_node_path47.join)(work, "package_export.py");
50616
- (0, import_node_fs48.writeFileSync)(script, package_export_default);
50755
+ (0, import_node_fs49.writeFileSync)(script, package_export_default);
50617
50756
  await deps.python(script, ["verify", work, opts.ds, opts.screens]);
50618
50757
  const verified = (0, import_node_path47.join)(work, "verified");
50619
- const metadata = Object.fromEntries(PACKAGES.map(({ name, short: short3 }) => [name, JSON.parse((0, import_node_fs48.readFileSync)((0, import_node_path47.join)(verified, `${short3}.metadata.json`), "utf8"))]));
50758
+ const metadata = Object.fromEntries(PACKAGES.map(({ name, short: short3 }) => [name, JSON.parse((0, import_node_fs49.readFileSync)((0, import_node_path47.join)(verified, `${short3}.metadata.json`), "utf8"))]));
50620
50759
  const plan = planAdoption(packageText, lockText, metadata);
50621
50760
  for (const { name } of plan.result.adopted) {
50622
50761
  const short3 = PACKAGES.find((p) => p.name === name).short;
50623
50762
  await deps.npm(["cache", "add", (0, import_node_path47.join)(verified, `${short3}.tgz`)], opts.dir);
50624
50763
  }
50625
- (0, import_node_fs48.writeFileSync)(packagePath, plan.packageText);
50626
- (0, import_node_fs48.writeFileSync)(lockPath, plan.lockText);
50764
+ (0, import_node_fs49.writeFileSync)(packagePath, plan.packageText);
50765
+ (0, import_node_fs49.writeFileSync)(lockPath, plan.lockText);
50627
50766
  try {
50628
50767
  await deps.npm(["ci", "--offline", "--ignore-scripts", "--no-audit", "--no-fund"], opts.dir);
50629
50768
  } catch (error) {
50630
- (0, import_node_fs48.writeFileSync)(packagePath, packageText);
50631
- (0, import_node_fs48.writeFileSync)(lockPath, lockText);
50769
+ (0, import_node_fs49.writeFileSync)(packagePath, packageText);
50770
+ (0, import_node_fs49.writeFileSync)(lockPath, lockText);
50632
50771
  throw new Error(`npm ci --offline failed, package.json and package-lock.json restored: ${error.message}`);
50633
50772
  }
50634
50773
  return plan.result;
50635
50774
  } finally {
50636
- (0, import_node_fs48.rmSync)(work, { recursive: true, force: true });
50775
+ (0, import_node_fs49.rmSync)(work, { recursive: true, force: true });
50637
50776
  }
50638
50777
  }
50639
50778
  var execFileBuffer = (0, import_node_util6.promisify)(import_node_child_process19.execFile);
@@ -50698,12 +50837,12 @@ function registerPackagesCommands(program3) {
50698
50837
  init_cli_shared();
50699
50838
 
50700
50839
  // src/wave-status.ts
50701
- var import_node_fs49 = require("node:fs");
50840
+ var import_node_fs50 = require("node:fs");
50702
50841
  function readStageSummary(worktreePath) {
50703
50842
  const statePath = stageStatePath(worktreePath);
50704
- if (!(0, import_node_fs49.existsSync)(statePath)) return void 0;
50843
+ if (!(0, import_node_fs50.existsSync)(statePath)) return void 0;
50705
50844
  try {
50706
- const state = JSON.parse((0, import_node_fs49.readFileSync)(statePath, "utf8"));
50845
+ const state = JSON.parse((0, import_node_fs50.readFileSync)(statePath, "utf8"));
50707
50846
  const port = typeof state.port === "number" ? state.port : void 0;
50708
50847
  if (port == null || !Number.isInteger(port) || port <= 0) return void 0;
50709
50848
  return { port, url: typeof state.url === "string" ? state.url : void 0 };
@@ -50760,7 +50899,7 @@ async function collectWaveStatus(deps) {
50760
50899
  // src/discovery-commands.ts
50761
50900
  init_github_client();
50762
50901
  init_cli_shared();
50763
- var import_node_fs50 = require("node:fs");
50902
+ var import_node_fs51 = require("node:fs");
50764
50903
  var import_node_os23 = require("node:os");
50765
50904
  var import_node_path48 = require("node:path");
50766
50905
  var GC_GH_TIMEOUT_MS3 = 2e4;
@@ -50953,8 +51092,8 @@ async function collectOnboardStatus(opts = {}) {
50953
51092
  }
50954
51093
  const home = (0, import_node_os23.homedir)();
50955
51094
  const plugin = onboardPluginGate({
50956
- readKnown: () => readFileSyncSafe((0, import_node_path48.join)(home, ...KNOWN_MARKETPLACES_RELATIVE), import_node_fs50.readFileSync),
50957
- readSettings: () => readFileSyncSafe((0, import_node_path48.join)(home, ".claude", "settings.json"), import_node_fs50.readFileSync)
51095
+ readKnown: () => readFileSyncSafe((0, import_node_path48.join)(home, ...KNOWN_MARKETPLACES_RELATIVE), import_node_fs51.readFileSync),
51096
+ readSettings: () => readFileSyncSafe((0, import_node_path48.join)(home, ".claude", "settings.json"), import_node_fs51.readFileSync)
50958
51097
  });
50959
51098
  return {
50960
51099
  guide: "Read the MMI org-guide skill before project work; load only the relevant topic. Use mmi-help for a short introduction.",
@@ -53148,7 +53287,7 @@ function registerOrgHealthQuery(program3, deps = defaultOrgHealthQueryDeps()) {
53148
53287
  }
53149
53288
 
53150
53289
  // src/api-read.ts
53151
- var import_node_fs51 = require("node:fs");
53290
+ var import_node_fs52 = require("node:fs");
53152
53291
 
53153
53292
  // src/run-log-read.ts
53154
53293
  init_cli_shared();
@@ -53749,7 +53888,7 @@ function registerApiReadCommands(program3, overrides) {
53749
53888
  o.accept
53750
53889
  );
53751
53890
  if (zip) {
53752
- (0, import_node_fs51.writeFileSync)(o.out, body, "latin1");
53891
+ (0, import_node_fs52.writeFileSync)(o.out, body, "latin1");
53753
53892
  return;
53754
53893
  }
53755
53894
  } catch (e) {
@@ -54624,7 +54763,7 @@ function registerSessionReport(program3) {
54624
54763
  }
54625
54764
 
54626
54765
  // src/stage-commands.ts
54627
- var import_node_fs52 = require("node:fs");
54766
+ var import_node_fs53 = require("node:fs");
54628
54767
  var import_node_path49 = require("node:path");
54629
54768
  init_cli_shared();
54630
54769
  init_clean_exit();
@@ -54873,8 +55012,8 @@ function registerStageCommands(program3) {
54873
55012
  const repo = Array.isArray(project2?.repos) && typeof project2.repos[0] === "string" ? project2.repos[0] : slug;
54874
55013
  const resolution = decideStage({
54875
55014
  registry: { deployModel: project2?.deployModel, portRange, error: read.ok ? void 0 : read.error },
54876
- hasCompose: (0, import_node_fs52.existsSync)((0, import_node_path49.join)(process.cwd(), "docker-compose.yml")),
54877
- hasEnvExample: (0, import_node_fs52.existsSync)((0, import_node_path49.join)(process.cwd(), ".env.example")),
55015
+ hasCompose: (0, import_node_fs53.existsSync)((0, import_node_path49.join)(process.cwd(), "docker-compose.yml")),
55016
+ hasEnvExample: (0, import_node_fs53.existsSync)((0, import_node_path49.join)(process.cwd(), ".env.example")),
54878
55017
  repo
54879
55018
  });
54880
55019
  if (resolution.source === "derived" && resolution.derived) {
@@ -55167,14 +55306,14 @@ vercel preview (${preview.branch}): ${d.state}${d.url ? ` \u2014 ${d.url}` : ""}
55167
55306
 
55168
55307
  // src/tenant-artifact.ts
55169
55308
  var import_node_crypto17 = require("node:crypto");
55170
- var import_node_fs53 = require("node:fs");
55309
+ var import_node_fs54 = require("node:fs");
55171
55310
  var import_promises11 = require("node:fs/promises");
55172
55311
  var import_node_path50 = require("node:path");
55173
55312
  var ARTIFACT_ID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
55174
55313
  var MAX_BYTES2 = 5 * 1024 * 1024 * 1024;
55175
55314
  async function sha256File(path2) {
55176
55315
  const hash = (0, import_node_crypto17.createHash)("sha256");
55177
- for await (const chunk of (0, import_node_fs53.createReadStream)(path2)) hash.update(chunk);
55316
+ for await (const chunk of (0, import_node_fs54.createReadStream)(path2)) hash.update(chunk);
55178
55317
  return hash.digest("hex");
55179
55318
  }
55180
55319
  async function putTenantArtifact(repo, stage, inputPath, deps) {
@@ -55197,7 +55336,7 @@ async function putTenantArtifact(repo, stage, inputPath, deps) {
55197
55336
  return [key, value];
55198
55337
  }));
55199
55338
  headers["content-length"] = String(info.size);
55200
- const stream = (0, import_node_fs53.createReadStream)(path2);
55339
+ const stream = (0, import_node_fs54.createReadStream)(path2);
55201
55340
  let uploaded;
55202
55341
  try {
55203
55342
  uploaded = await fetch(body.uploadUrl, {
@@ -55336,7 +55475,7 @@ function renderVerifySecrets(body) {
55336
55475
  }
55337
55476
 
55338
55477
  // src/command-register-developer.ts
55339
- var import_node_fs57 = require("node:fs");
55478
+ var import_node_fs58 = require("node:fs");
55340
55479
  init_clean_exit();
55341
55480
  init_cli_shared();
55342
55481
  init_error_codes();
@@ -55404,13 +55543,13 @@ async function executeWaveLand(plan, deps) {
55404
55543
  // src/dist-drift.ts
55405
55544
  var import_node_child_process20 = require("node:child_process");
55406
55545
  var import_node_crypto19 = require("node:crypto");
55407
- var import_node_fs55 = require("node:fs");
55546
+ var import_node_fs56 = require("node:fs");
55408
55547
  var import_node_os24 = require("node:os");
55409
55548
  var import_node_path52 = require("node:path");
55410
55549
 
55411
55550
  // ../scripts/distribution-digest.mjs
55412
55551
  var import_node_crypto18 = require("node:crypto");
55413
- var import_node_fs54 = require("node:fs");
55552
+ var import_node_fs55 = require("node:fs");
55414
55553
  var import_node_path51 = require("node:path");
55415
55554
  var slash = (value) => value.replaceAll("\\", "/");
55416
55555
  function repoPath(root, declaredPath, label) {
@@ -55424,7 +55563,7 @@ function repoPath(root, declaredPath, label) {
55424
55563
  function digestFiles(files) {
55425
55564
  const hash = (0, import_node_crypto18.createHash)("sha256");
55426
55565
  for (const file of [...files].sort((a, b) => a.relative.localeCompare(b.relative))) {
55427
- const content = file.stat.isSymbolicLink() ? Buffer.from((0, import_node_fs54.readlinkSync)(file.absolute), "utf8") : (0, import_node_fs54.readFileSync)(file.absolute);
55566
+ const content = file.stat.isSymbolicLink() ? Buffer.from((0, import_node_fs55.readlinkSync)(file.absolute), "utf8") : (0, import_node_fs55.readFileSync)(file.absolute);
55428
55567
  hash.update(file.relative, "utf8");
55429
55568
  hash.update("\0");
55430
55569
  hash.update(file.stat.isSymbolicLink() ? "symlink" : "file", "utf8");
@@ -55439,8 +55578,8 @@ function digestFiles(files) {
55439
55578
  function digestPackedFiles(packageRoot, packedFiles) {
55440
55579
  return digestFiles(packedFiles.map((path2) => {
55441
55580
  const absolute = repoPath(packageRoot, path2, "packed artifact identity path");
55442
- if (!(0, import_node_fs54.existsSync)(absolute)) throw new Error(`packed artifact identity path ${path2} does not exist`);
55443
- return { absolute, relative: slash(path2), stat: (0, import_node_fs54.lstatSync)(absolute) };
55581
+ if (!(0, import_node_fs55.existsSync)(absolute)) throw new Error(`packed artifact identity path ${path2} does not exist`);
55582
+ return { absolute, relative: slash(path2), stat: (0, import_node_fs55.lstatSync)(absolute) };
55444
55583
  }));
55445
55584
  }
55446
55585
 
@@ -55525,12 +55664,12 @@ function renderDistDriftReceipt(receipt) {
55525
55664
  return lines2;
55526
55665
  }
55527
55666
  function readOrNull(path2) {
55528
- return (0, import_node_fs55.existsSync)(path2) ? (0, import_node_fs55.readFileSync)(path2) : null;
55667
+ return (0, import_node_fs56.existsSync)(path2) ? (0, import_node_fs56.readFileSync)(path2) : null;
55529
55668
  }
55530
55669
  function walkFiles(root) {
55531
55670
  const files = [];
55532
55671
  const walk2 = (directory) => {
55533
- for (const entry of (0, import_node_fs55.readdirSync)(directory, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
55672
+ for (const entry of (0, import_node_fs56.readdirSync)(directory, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
55534
55673
  const child2 = (0, import_node_path52.join)(directory, entry.name);
55535
55674
  if (entry.isDirectory()) walk2(child2);
55536
55675
  else files.push(child2);
@@ -55541,7 +55680,7 @@ function walkFiles(root) {
55541
55680
  }
55542
55681
  function bomPathFor(root) {
55543
55682
  try {
55544
- const registry2 = JSON.parse((0, import_node_fs55.readFileSync)((0, import_node_path52.join)(root, "surfaces.json"), "utf8"));
55683
+ const registry2 = JSON.parse((0, import_node_fs56.readFileSync)((0, import_node_path52.join)(root, "surfaces.json"), "utf8"));
55545
55684
  return (0, import_node_path52.join)(root, registry2?.sharedAgentCore?.releaseMetadata?.bomPath ?? "distribution-bom.json");
55546
55685
  } catch {
55547
55686
  return (0, import_node_path52.join)(root, "distribution-bom.json");
@@ -55557,7 +55696,7 @@ function rebuildTo(packageRoot, outDir) {
55557
55696
  });
55558
55697
  }
55559
55698
  function runDistStatus(root) {
55560
- const stage = (0, import_node_fs55.mkdtempSync)((0, import_node_path52.join)((0, import_node_os24.tmpdir)(), "mmi-dist-drift-"));
55699
+ const stage = (0, import_node_fs56.mkdtempSync)((0, import_node_path52.join)((0, import_node_os24.tmpdir)(), "mmi-dist-drift-"));
55561
55700
  let overlayCount = 0;
55562
55701
  try {
55563
55702
  const cliOut = (0, import_node_path52.join)(stage, "cli-dist");
@@ -55573,19 +55712,19 @@ function runDistStatus(root) {
55573
55712
  const tree = (path2) => readOrNull((0, import_node_path52.join)(root, path2));
55574
55713
  const distRoot = (0, import_node_path52.join)(root, "cli", "dist");
55575
55714
  const distTree = () => walkFiles(distRoot).map((absolute) => `cli/dist/${(0, import_node_path52.relative)(distRoot, absolute).replaceAll("\\", "/")}`);
55576
- const bom = JSON.parse((0, import_node_fs55.readFileSync)(bomPathFor(root), "utf8"));
55715
+ const bom = JSON.parse((0, import_node_fs56.readFileSync)(bomPathFor(root), "utf8"));
55577
55716
  const digest = (entries) => {
55578
55717
  const overlay = (0, import_node_path52.join)(stage, `overlay-${overlayCount++}`);
55579
55718
  for (const entry of entries) {
55580
55719
  const target = (0, import_node_path52.join)(overlay, entry.path);
55581
- (0, import_node_fs55.mkdirSync)((0, import_node_path52.dirname)(target), { recursive: true });
55582
- (0, import_node_fs55.writeFileSync)(target, entry.bytes);
55720
+ (0, import_node_fs56.mkdirSync)((0, import_node_path52.dirname)(target), { recursive: true });
55721
+ (0, import_node_fs56.writeFileSync)(target, entry.bytes);
55583
55722
  }
55584
55723
  return digestPackedFiles(overlay, entries.map((entry) => entry.path));
55585
55724
  };
55586
55725
  return computeDistDriftReceipt({ committed, tree, rebuilt, distTree, bom, digest });
55587
55726
  } finally {
55588
- (0, import_node_fs55.rmSync)(stage, { recursive: true, force: true });
55727
+ (0, import_node_fs56.rmSync)(stage, { recursive: true, force: true });
55589
55728
  }
55590
55729
  }
55591
55730
 
@@ -55915,7 +56054,7 @@ function registerSchedulesLiftCommand(program3, deps = {}) {
55915
56054
 
55916
56055
  // src/spawn-policy-core.ts
55917
56056
  var import_node_child_process22 = require("node:child_process");
55918
- var import_node_fs56 = require("node:fs");
56057
+ var import_node_fs57 = require("node:fs");
55919
56058
  var import_node_path55 = require("node:path");
55920
56059
  var SPAWNERS = ["spawn", "spawnSync", "exec", "execSync", "execFile", "execFileSync"];
55921
56060
  var CALL_SOURCE = String.raw`(^|[^.\w$])(${SPAWNERS.join("|")})\s*\(`;
@@ -56002,7 +56141,7 @@ function runSpawnPolicy(root) {
56002
56141
  for (const file of files) {
56003
56142
  let raw;
56004
56143
  try {
56005
- raw = (0, import_node_fs56.readFileSync)((0, import_node_path55.join)(root, file), "utf8");
56144
+ raw = (0, import_node_fs57.readFileSync)((0, import_node_path55.join)(root, file), "utf8");
56006
56145
  } catch {
56007
56146
  continue;
56008
56147
  }
@@ -56023,18 +56162,18 @@ function registerDeveloperCommands(program3) {
56023
56162
  const rules = program3.command("rules").description("org-managed .gitignore delivery");
56024
56163
  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) => {
56025
56164
  const path2 = (0, import_node_path56.join)(process.cwd(), ".gitignore");
56026
- const current = (0, import_node_fs57.existsSync)(path2) ? (0, import_node_fs57.readFileSync)(path2, "utf8") : null;
56165
+ const current = (0, import_node_fs58.existsSync)(path2) ? (0, import_node_fs58.readFileSync)(path2, "utf8") : null;
56027
56166
  const plan = planManagedGitignore(current);
56028
56167
  const drift = [...plan.added.map((l) => `+${l}`), ...plan.removed.map((l) => `-${l}`)].join(", ") || "block normalize";
56029
56168
  if (opts.json) {
56030
- if (opts.write && plan.changed) (0, import_node_fs57.writeFileSync)(path2, plan.content, "utf8");
56169
+ if (opts.write && plan.changed) (0, import_node_fs58.writeFileSync)(path2, plan.content, "utf8");
56031
56170
  console.log(JSON.stringify(plan, null, 2));
56032
56171
  if (!opts.write && plan.changed) process.exitCode = 1;
56033
56172
  return;
56034
56173
  }
56035
56174
  if (opts.write) {
56036
56175
  if (plan.changed) {
56037
- (0, import_node_fs57.writeFileSync)(path2, plan.content, "utf8");
56176
+ (0, import_node_fs58.writeFileSync)(path2, plan.content, "utf8");
56038
56177
  console.log(`mmi-cli devops org rules gitignore: updated .gitignore (${drift})`);
56039
56178
  } else {
56040
56179
  console.log("mmi-cli devops org rules gitignore: up to date");
@@ -56243,17 +56382,18 @@ function registerDeveloperCommands(program3) {
56243
56382
  }
56244
56383
  });
56245
56384
  const tests = program3.command("tests").description("a repo's test-policy.json \u2014 the opt-in test contract and its enforcement");
56246
- 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, policySource: { ref, sha, path }, root, changedCount, mandatoryCount, matchedMandatoryCount, matchedMandatoryGlobs, testCommandsAllowed, testCommandNote, commandClasses, findings[] }").option("--base <ref>", "comparison base (default: TEST_POLICY_BASE, then origin/development, then origin/main)").option("--policy-ref <commit>", "load test-policy.json from the exact fetched origin/development commit and audit its protected/satisfiedBy paths against that commit's tree, not this checkout; valid only with --base origin/main").addOption(new Option("--repo <owner/repo>", "not accepted \u2014 tests policy reads the current checkout").hideHelp()).action(async (o) => {
56385
+ 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", "compact machine-readable result: { ok, testCommandsAllowed, commandClasses, findings[] }").option("--verbose", "include the full policy result in --json output").option("--base <ref>", "comparison base (default: TEST_POLICY_BASE, then origin/development, then origin/main)").option("--policy-ref <commit>", "load test-policy.json from the exact fetched origin/development commit and audit its protected/satisfiedBy paths against that commit's tree, not this checkout; valid only with --base origin/main").addOption(new Option("--repo <owner/repo>", "not accepted \u2014 tests policy reads the current checkout").hideHelp()).action(async (o) => {
56247
56386
  try {
56248
56387
  if (o.repo) {
56249
- const rerun = `mmi-cli tests policy${o.base ? ` --base ${o.base}` : ""}${o.policyRef ? ` --policy-ref ${o.policyRef}` : ""}${o.json ? " --json" : ""}`;
56388
+ const rerun = `mmi-cli tests policy${o.base ? ` --base ${o.base}` : ""}${o.policyRef ? ` --policy-ref ${o.policyRef}` : ""}${o.json ? " --json" : ""}${o.verbose ? " --verbose" : ""}`;
56250
56389
  const guard = planTrainApplyRepoGuard(o.repo, await resolveRepo(), rerun, "tests policy");
56251
56390
  if (!guard.ok) return failGraceful(guard.message);
56252
56391
  }
56253
56392
  const root = await repoRoot();
56254
56393
  const result = runTestPolicy(root, { base: o.base, policyRef: o.policyRef });
56255
56394
  if (o.json) {
56256
- consoleIo.log(JSON.stringify(result, null, 2));
56395
+ const { ok, testCommandsAllowed, commandClasses, findings } = result;
56396
+ consoleIo.log(o.verbose ? JSON.stringify(result, null, 2) : JSON.stringify({ ok, testCommandsAllowed, commandClasses, findings }));
56257
56397
  if (!result.ok) process.exitCode = 1;
56258
56398
  return;
56259
56399
  }
@@ -56451,7 +56591,7 @@ function mmiDoctorDeps(opts = {}) {
56451
56591
  );
56452
56592
  const result = applyPluginCachePlan(
56453
56593
  plan,
56454
- (p) => (0, import_node_fs58.rmSync)(p, { recursive: true }),
56594
+ (p) => (0, import_node_fs59.rmSync)(p, { recursive: true }),
56455
56595
  stagingApplyFsGuard(configRoot)
56456
56596
  );
56457
56597
  return {
@@ -56486,7 +56626,7 @@ function mmiDoctorDeps(opts = {}) {
56486
56626
  // has no generated routing index would
56487
56627
  // get a permanent — demanding an artifact it never asked for.
56488
56628
  docsIndexState: (root) => {
56489
- if (!(0, import_node_fs58.existsSync)((0, import_node_path57.join)(root, DOCS_INDEX_PATH))) return void 0;
56629
+ if (!(0, import_node_fs59.existsSync)((0, import_node_path57.join)(root, DOCS_INDEX_PATH))) return void 0;
56490
56630
  const real = createDocsIndexDeps(root);
56491
56631
  let docs;
56492
56632
  const listDocs = () => docs ??= real.listDocs();
@@ -56495,7 +56635,7 @@ function mmiDoctorDeps(opts = {}) {
56495
56635
  },
56496
56636
  // #4168: working-tree heal — write if drifted, then re-check. Commit remains the operator's step.
56497
56637
  healDocsIndex: (root) => {
56498
- if (!(0, import_node_fs58.existsSync)((0, import_node_path57.join)(root, DOCS_INDEX_PATH))) return { drift: false, docCount: 0 };
56638
+ if (!(0, import_node_fs59.existsSync)((0, import_node_path57.join)(root, DOCS_INDEX_PATH))) return { drift: false, docCount: 0 };
56499
56639
  const real = createDocsIndexDeps(root);
56500
56640
  let docs;
56501
56641
  const listDocs = () => docs ??= real.listDocs();
@@ -56855,6 +56995,7 @@ function appActorDeps() {
56855
56995
  };
56856
56996
  }
56857
56997
  setPollTokenProvider(async () => activeAppToken() ?? pollTokenOrUndefined(appActorDeps()));
56998
+ setGhReadTokenProvider(pollToken);
56858
56999
  setStatusWriteTokenProvider(() => mintStatusWriteToken(appActorDeps()));
56859
57000
  var registerPreAction = Reflect.get(program2, ["h", "ook"].join(""));
56860
57001
  registerPreAction.call(program2, "preAction", async (_thisCommand, actionCommand) => {
@@ -56862,7 +57003,7 @@ registerPreAction.call(program2, "preAction", async (_thisCommand, actionCommand
56862
57003
  appActorCommand = commandPath3;
56863
57004
  emitCliCallTelemetry(commandPath3);
56864
57005
  try {
56865
- await activateAppActor(commandPath3, process.env, () => mintInstallationToken(appActorDeps()));
57006
+ await activateAppActor(commandPath3, process.env, () => APP_WRITE_COMMANDS.has(commandPath3) ? mintCommandWriteToken(appActorDeps(), commandPath3) : mintInstallationToken(appActorDeps()));
56866
57007
  } catch (e) {
56867
57008
  if (e instanceof AppActorError) return fail(e.message);
56868
57009
  throw e;
@@ -57220,7 +57361,7 @@ project.command("set [owner/repo]").description("upsert project META (idempotent
57220
57361
  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`);
57221
57362
  if (o.secretsFile) {
57222
57363
  try {
57223
- vars.push(`secrets=${(0, import_node_fs58.readFileSync)(o.secretsFile, "utf8")}`);
57364
+ vars.push(`secrets=${(0, import_node_fs59.readFileSync)(o.secretsFile, "utf8")}`);
57224
57365
  } catch (e) {
57225
57366
  return fail(`org project set: cannot read --secrets-file ${o.secretsFile}: ${e.message}`);
57226
57367
  }
@@ -57612,15 +57753,15 @@ function ciAuditDeps2() {
57612
57753
  readSeedFile: (path2) => {
57613
57754
  if (!root) return null;
57614
57755
  const fullPath = (0, import_node_path57.join)(root, path2);
57615
- return (0, import_node_fs58.existsSync)(fullPath) ? (0, import_node_fs58.readFileSync)(fullPath, "utf8") : null;
57756
+ return (0, import_node_fs59.existsSync)(fullPath) ? (0, import_node_fs59.readFileSync)(fullPath, "utf8") : null;
57616
57757
  }
57617
57758
  };
57618
57759
  }
57619
57760
  function hubRoot2() {
57620
57761
  const fromPkg = (0, import_node_path57.join)(__dirname, "..", "..");
57621
57762
  const marker = "skills/bootstrap/seeds/manifest.json";
57622
- if ((0, import_node_fs58.existsSync)((0, import_node_path57.join)(fromPkg, marker))) return fromPkg;
57623
- if ((0, import_node_fs58.existsSync)((0, import_node_path57.join)(process.cwd(), marker))) return process.cwd();
57763
+ if ((0, import_node_fs59.existsSync)((0, import_node_path57.join)(fromPkg, marker))) return fromPkg;
57764
+ if ((0, import_node_fs59.existsSync)((0, import_node_path57.join)(process.cwd(), marker))) return process.cwd();
57624
57765
  return null;
57625
57766
  }
57626
57767
  registerQueryCommands(program2);
@@ -57634,6 +57775,7 @@ registerDiscoveryCommands(program2);
57634
57775
  registerExplainCommand(program2);
57635
57776
  registerPrLifecycleCommands(program2);
57636
57777
  registerApiReadCommands(program2);
57778
+ registerGithubBudgetCommand(program2, appActorDeps);
57637
57779
  registerAppReadBrokerCommands(program2, async (repo) => requireRepo(repo));
57638
57780
  var prBrokerRoot = program2.commands.find((c) => c.name() === "pr");
57639
57781
  if (!prBrokerRoot) throw new Error("read broker: pr root must be registered before pr checks-required");
@@ -57750,10 +57892,10 @@ access.command("audit").description("audit collaborator roles + train-branch pus
57750
57892
  targets = resolution.targets;
57751
57893
  }
57752
57894
  const derivedMatrix = registryProjects ? accessMatrixFromProjects(registryProjects) : {};
57753
- const fileMatrix = (0, import_node_fs58.existsSync)("access-matrix.json") ? loadAccessMatrix((0, import_node_fs58.readFileSync)("access-matrix.json", "utf8")) : {};
57895
+ const fileMatrix = (0, import_node_fs59.existsSync)("access-matrix.json") ? loadAccessMatrix((0, import_node_fs59.readFileSync)("access-matrix.json", "utf8")) : {};
57754
57896
  const matrix = mergeAccessMatrix(fileMatrix, derivedMatrix);
57755
57897
  const dataAccess = registryProjects ? dataAccessContractsFromProjects(registryProjects) : { consumers: {} };
57756
- const sanctioned = (0, import_node_fs58.existsSync)("access-matrix.json") ? loadSanctionedAdmins((0, import_node_fs58.readFileSync)("access-matrix.json", "utf8")) : {};
57898
+ const sanctioned = (0, import_node_fs59.existsSync)("access-matrix.json") ? loadSanctionedAdmins((0, import_node_fs59.readFileSync)("access-matrix.json", "utf8")) : {};
57757
57899
  const report = await auditOrgAccess(targets, deps, matrix, dataAccess, sanctioned);
57758
57900
  console.log(o.json ? JSON.stringify(report, null, 2) : renderAccessReport(report));
57759
57901
  if (!report.ok) process.exitCode = 1;
@@ -57784,7 +57926,7 @@ function directoryBytes(path2) {
57784
57926
  let total = 0;
57785
57927
  let entries;
57786
57928
  try {
57787
- entries = (0, import_node_fs58.readdirSync)(path2, { withFileTypes: true });
57929
+ entries = (0, import_node_fs59.readdirSync)(path2, { withFileTypes: true });
57788
57930
  } catch {
57789
57931
  return 0;
57790
57932
  }
@@ -57793,7 +57935,7 @@ function directoryBytes(path2) {
57793
57935
  if (entry.isDirectory()) total += directoryBytes(child2);
57794
57936
  else {
57795
57937
  try {
57796
- total += (0, import_node_fs58.statSync)(child2).size;
57938
+ total += (0, import_node_fs59.statSync)(child2).size;
57797
57939
  } catch {
57798
57940
  }
57799
57941
  }
@@ -57801,25 +57943,25 @@ function directoryBytes(path2) {
57801
57943
  return total;
57802
57944
  }
57803
57945
  function listDirEntries(dir) {
57804
- return (0, import_node_fs58.readdirSync)(dir, { withFileTypes: true }).map((d) => ({ name: d.name, isDirectory: d.isDirectory() }));
57946
+ return (0, import_node_fs59.readdirSync)(dir, { withFileTypes: true }).map((d) => ({ name: d.name, isDirectory: d.isDirectory() }));
57805
57947
  }
57806
57948
  function readInstalledPluginRefs(configRoot) {
57807
57949
  const p = installedPluginsPathForConfig(configRoot);
57808
- if (!(0, import_node_fs58.existsSync)(p)) return [];
57950
+ if (!(0, import_node_fs59.existsSync)(p)) return [];
57809
57951
  try {
57810
- return installedPluginPaths((0, import_node_fs58.readFileSync)(p, "utf8"));
57952
+ return installedPluginPaths((0, import_node_fs59.readFileSync)(p, "utf8"));
57811
57953
  } catch {
57812
57954
  return null;
57813
57955
  }
57814
57956
  }
57815
57957
  function pluginCacheFsDeps(configRoot, dirBytes) {
57816
57958
  return {
57817
- exists: (p) => (0, import_node_fs58.existsSync)(p),
57818
- listVersionDirs: (root) => (0, import_node_fs58.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name),
57959
+ exists: (p) => (0, import_node_fs59.existsSync)(p),
57960
+ listVersionDirs: (root) => (0, import_node_fs59.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name),
57819
57961
  dirBytes,
57820
- listStagingDirs: (root) => (0, import_node_fs58.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => {
57962
+ listStagingDirs: (root) => (0, import_node_fs59.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => {
57821
57963
  try {
57822
- return { name: d.name, mtimeMs: newestMtimeMs((0, import_node_path57.join)(root, d.name), listDirEntries, (p) => (0, import_node_fs58.statSync)(p).mtimeMs) };
57964
+ return { name: d.name, mtimeMs: newestMtimeMs((0, import_node_path57.join)(root, d.name), listDirEntries, (p) => (0, import_node_fs59.statSync)(p).mtimeMs) };
57823
57965
  } catch {
57824
57966
  return { name: d.name, mtimeMs: Date.now() };
57825
57967
  }
@@ -57834,9 +57976,9 @@ function stagingApplyFsGuard(configRoot) {
57834
57976
  referencedPaths: () => readInstalledPluginRefs(configRoot),
57835
57977
  mtimeMs: (name) => {
57836
57978
  const p = (0, import_node_path57.join)(stagingRoot, name);
57837
- if (!(0, import_node_fs58.existsSync)(p)) return null;
57979
+ if (!(0, import_node_fs59.existsSync)(p)) return null;
57838
57980
  try {
57839
- return newestMtimeMs(p, listDirEntries, (q) => (0, import_node_fs58.statSync)(q).mtimeMs);
57981
+ return newestMtimeMs(p, listDirEntries, (q) => (0, import_node_fs59.statSync)(q).mtimeMs);
57840
57982
  } catch {
57841
57983
  return null;
57842
57984
  }
@@ -57862,7 +58004,7 @@ program2.command("plugin-prune").description(`prune stale cached MMI plugin vers
57862
58004
  { withBytes: true, configRoot, includeStaging: surface !== "codex" }
57863
58005
  );
57864
58006
  const anythingToDelete = plan.prune.length > 0 || plan.staging.length > 0;
57865
- const result = o.apply && anythingToDelete ? applyPluginCachePlan(plan, (p) => (0, import_node_fs58.rmSync)(p, { recursive: true, force: true }), stagingApplyFsGuard(configRoot)) : void 0;
58007
+ const result = o.apply && anythingToDelete ? applyPluginCachePlan(plan, (p) => (0, import_node_fs59.rmSync)(p, { recursive: true, force: true }), stagingApplyFsGuard(configRoot)) : void 0;
57866
58008
  const warnings = plan.prune.length > 0 ? [CONCURRENT_SESSION_WARNING] : [];
57867
58009
  if (o.json) console.log(JSON.stringify({ ...plan, warnings, applied: result ?? null }));
57868
58010
  else console.log(renderPluginCachePlan(plan, result));