@mutmutco/claude-plugin 4.5.158 → 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/cli/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();
@@ -7068,6 +7139,8 @@ var import_node_crypto5 = require("node:crypto");
7068
7139
  var APP_ACTOR_ENV = "MMI_ACTOR";
7069
7140
  var APP_VAULT_REPO = "mutmutco/MMI-Hub";
7070
7141
  var APP_VAULT_KEYS = ["GITHUB_APP_ID", "GITHUB_APP_INSTALLATION_ID", "GITHUB_APP_PRIVATE_KEY"];
7142
+ var APP2_VAULT_KEYS = ["GITHUB_APP2_ID", "GITHUB_APP2_INSTALLATION_ID", "GITHUB_APP2_PRIVATE_KEY"];
7143
+ var APP_POOL_MEMBERS = [APP_VAULT_KEYS, APP2_VAULT_KEYS];
7071
7144
  var APP_ELIGIBLE_COMMANDS = /* @__PURE__ */ new Set([
7072
7145
  "pr checks-wait",
7073
7146
  // #8042: App-native required-only read (`pr checks-required`) — REST check/status rows scoped by
@@ -7165,6 +7238,19 @@ async function readAppVaultSecret(read) {
7165
7238
  async function mintInstallationToken(deps) {
7166
7239
  return mintScopedInstallationToken(deps, APP_POLL_PERMISSIONS);
7167
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
+ }
7168
7254
  async function mintStatusWriteToken(deps) {
7169
7255
  return mintScopedInstallationToken(deps, { metadata: "read", statuses: "write" });
7170
7256
  }
@@ -7184,10 +7270,55 @@ async function fleetStatusWriteEnv(args) {
7184
7270
  }
7185
7271
  }
7186
7272
  async function mintScopedInstallationToken(deps, permissions) {
7187
- const [appId, installationId, privateKey] = await Promise.all(APP_VAULT_KEYS.map((k) => deps.fetchSecret(k)));
7273
+ const start = Math.floor((deps.random ?? Math.random)() * APP_POOL_MEMBERS.length) % APP_POOL_MEMBERS.length;
7274
+ const order = APP_POOL_MEMBERS.map((_, i) => APP_POOL_MEMBERS[(start + i) % APP_POOL_MEMBERS.length]);
7275
+ let firstError;
7276
+ let exhausted;
7277
+ let absent = 0;
7278
+ for (const [i, keys] of order.entries()) {
7279
+ try {
7280
+ const minted = await mintFromMember(deps, permissions, keys);
7281
+ if (i === order.length - 1 || !await allowanceSpent(deps, minted.token)) return minted;
7282
+ exhausted ??= minted;
7283
+ } catch (e) {
7284
+ if (e instanceof AppActorError && e.code === "vault-denied") {
7285
+ absent += 1;
7286
+ continue;
7287
+ }
7288
+ firstError ??= e;
7289
+ }
7290
+ }
7291
+ if (exhausted) return exhausted;
7292
+ if (firstError) throw firstError;
7293
+ if (absent === order.length) {
7294
+ throw new AppActorError(
7295
+ `app actor: vault denied all App credentials (${APP_VAULT_REPO} tier) \u2014 not an automation host, or no vault access`,
7296
+ "vault-denied"
7297
+ );
7298
+ }
7299
+ throw new AppActorError("app actor: no App pool member minted \u2014 automation fails closed");
7300
+ }
7301
+ async function allowanceSpent(deps, token) {
7302
+ try {
7303
+ const res = await deps.fetch("https://api.github.com/rate_limit", {
7304
+ method: "GET",
7305
+ headers: { authorization: `Bearer ${token}`, accept: "application/vnd.github+json", "user-agent": "mmi-cli-app-actor" }
7306
+ });
7307
+ if (!res.ok) return false;
7308
+ const body = await res.json();
7309
+ return body.resources?.core?.remaining === 0 || body.resources?.graphql?.remaining === 0;
7310
+ } catch {
7311
+ return false;
7312
+ }
7313
+ }
7314
+ function mintBudgetToken(deps, keys) {
7315
+ return mintFromMember(deps, { metadata: "read" }, keys);
7316
+ }
7317
+ async function mintFromMember(deps, permissions, keys) {
7318
+ const [appId, installationId, privateKey] = await Promise.all(keys.map((k) => deps.fetchSecret(k)));
7188
7319
  if (!appId || !installationId || !privateKey) {
7189
- const missing = APP_VAULT_KEYS.filter((_, i) => ![appId, installationId, privateKey][i]);
7190
- if (missing.length === APP_VAULT_KEYS.length) {
7320
+ const missing = keys.filter((_, i) => ![appId, installationId, privateKey][i]);
7321
+ if (missing.length === keys.length) {
7191
7322
  throw new AppActorError(
7192
7323
  `app actor: vault denied all App credentials (${APP_VAULT_REPO} tier) \u2014 not an automation host, or no vault access`,
7193
7324
  "vault-denied"
@@ -7250,7 +7381,7 @@ async function activateAppActor(commandPath3, env, mint, note = (line) => proces
7250
7381
  if (requested && requested !== "app") {
7251
7382
  throw new AppActorError(`app actor: unknown ${APP_ACTOR_ENV} value \u2014 only 'app' and 'personal' are supported; refusing to guess an identity`);
7252
7383
  }
7253
- if (!APP_ELIGIBLE_COMMANDS.has(commandPath3)) {
7384
+ if (!APP_ELIGIBLE_COMMANDS.has(commandPath3) && !APP_WRITE_COMMANDS.has(commandPath3)) {
7254
7385
  if (requested === "app" && !notedIneligibleCommand) {
7255
7386
  notedIneligibleCommand = true;
7256
7387
  note(`app actor: '${commandPath3}' is personal-only (viewer/@me/authorship) \u2014 running on the personal token despite ${APP_ACTOR_ENV}=app`);
@@ -11257,6 +11388,7 @@ init_clean_exit();
11257
11388
 
11258
11389
  // src/gh-create.ts
11259
11390
  var import_promises = require("node:fs/promises");
11391
+ var import_node_fs16 = require("node:fs");
11260
11392
  var import_node_os8 = require("node:os");
11261
11393
  var import_node_path13 = require("node:path");
11262
11394
  var import_node_crypto7 = require("node:crypto");
@@ -11522,18 +11654,23 @@ async function preflightPrCreateRemoteHead(args, deps) {
11522
11654
  if (compared !== "unknown" && compared.aheadBy <= 0) return emptyCompareMessage(base, head);
11523
11655
  return void 0;
11524
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
+ }
11525
11666
  function buildPrCreateRetryCommand(args) {
11526
11667
  const parts = ["mmi-cli", "devops", "pr", "create"];
11527
11668
  for (const flag of ["--repo", "--base", "--head", "--title"]) {
11528
11669
  const v = flagValue(args, flag);
11529
11670
  if (v !== void 0) parts.push(flag, shellQuote(v));
11530
11671
  }
11531
- const bodyFile = flagValue(args, "--body-file");
11672
+ const bodyFile = retryBodyFile(args);
11532
11673
  if (bodyFile !== void 0) parts.push("--body-file", shellQuote(bodyFile));
11533
- else {
11534
- const body = flagValue(args, "--body");
11535
- if (body !== void 0) parts.push("--body", shellQuote(body));
11536
- }
11537
11674
  if (args.includes("--draft")) parts.push("--draft");
11538
11675
  return parts.join(" ");
11539
11676
  }
@@ -11556,12 +11693,8 @@ function buildIssueCreateRetryCommand(args) {
11556
11693
  if (type) parts.push("--type", type);
11557
11694
  const title = flagValue(args, "--title");
11558
11695
  if (title !== void 0) parts.push("--title", shellQuote(title));
11559
- const bodyFile = flagValue(args, "--body-file");
11696
+ const bodyFile = retryBodyFile(args);
11560
11697
  if (bodyFile !== void 0) parts.push("--body-file", shellQuote(bodyFile));
11561
- else {
11562
- const body = flagValue(args, "--body");
11563
- if (body !== void 0) parts.push("--body", shellQuote(body));
11564
- }
11565
11698
  for (const label of labels) {
11566
11699
  if (label === type) continue;
11567
11700
  parts.push("--label", shellQuote(label));
@@ -14518,11 +14651,11 @@ function probeLocalClaimSession(marker, now = Date.now()) {
14518
14651
  const pending = [root];
14519
14652
  while (pending.length) {
14520
14653
  const dir = pending.pop();
14521
- 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 })) {
14522
14655
  const path2 = (0, import_node_path14.join)(dir, entry.name);
14523
14656
  if (entry.isDirectory()) pending.push(path2);
14524
14657
  else if (entry.isFile() && entry.name.toLowerCase() === wanted) {
14525
- 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");
14526
14659
  }
14527
14660
  }
14528
14661
  }
@@ -16027,12 +16160,12 @@ function planManagedGitignore(current) {
16027
16160
  }
16028
16161
 
16029
16162
  // src/docs-index-command.ts
16030
- var import_node_fs18 = require("node:fs");
16163
+ var import_node_fs19 = require("node:fs");
16031
16164
  var import_node_path16 = require("node:path");
16032
16165
 
16033
16166
  // src/doc-refs-core.ts
16034
16167
  var import_node_child_process6 = require("node:child_process");
16035
- var import_node_fs17 = require("node:fs");
16168
+ var import_node_fs18 = require("node:fs");
16036
16169
  var import_node_path15 = require("node:path");
16037
16170
  var PIN_RE = /<!--\s*pinned by\s+([^:]+?)\s*:\s*"([^"]+)"[^"]*-->/;
16038
16171
  var PIN_MENTION_RE = /<!--\s*pinned by\b/;
@@ -16405,12 +16538,12 @@ function checkSeedRunbookReview(root, base, readFile10, git3) {
16405
16538
  return findings;
16406
16539
  }
16407
16540
  function readFileOrNull(path2) {
16408
- 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;
16409
16542
  }
16410
16543
  function walk(dir, root, out) {
16411
- for (const entry of (0, import_node_fs17.readdirSync)(dir)) {
16544
+ for (const entry of (0, import_node_fs18.readdirSync)(dir)) {
16412
16545
  const full = (0, import_node_path15.join)(dir, entry);
16413
- 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);
16414
16547
  else if (entry.endsWith(".md")) out.push(full.slice(root.length + 1).replaceAll("\\", "/"));
16415
16548
  }
16416
16549
  return out;
@@ -16418,11 +16551,11 @@ function walk(dir, root, out) {
16418
16551
  function defaultListDocs(root) {
16419
16552
  const docs = ["docs", "skills/org-guide", "skills/mmi-help"].flatMap((path2) => {
16420
16553
  const directory = (0, import_node_path15.join)(root, path2);
16421
- return (0, import_node_fs17.existsSync)(directory) ? walk(directory, root, []) : [];
16554
+ return (0, import_node_fs18.existsSync)(directory) ? walk(directory, root, []) : [];
16422
16555
  }).filter(
16423
16556
  (rel) => !SKIP_WALK.some((skip) => rel.startsWith(skip))
16424
16557
  );
16425
- 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];
16426
16559
  }
16427
16560
  var CHECK_IGNORE_MAX_BUFFER = 32 * 1024 * 1024;
16428
16561
  function defaultIsIgnored(root, relPaths, exec3 = import_node_child_process6.execFileSync) {
@@ -16503,7 +16636,7 @@ function mergeGroupRunbookMessages(root, deps, readFile10, warnings) {
16503
16636
  }
16504
16637
  function runDocRefs(root, deps = {}) {
16505
16638
  const readFile10 = deps.readFile ?? readFileOrNull;
16506
- const exists = deps.exists ?? import_node_fs17.existsSync;
16639
+ const exists = deps.exists ?? import_node_fs18.existsSync;
16507
16640
  const listDocs = deps.listDocs ?? defaultListDocs;
16508
16641
  const isIgnored = deps.isIgnored ?? ((paths) => defaultIsIgnored(root, paths));
16509
16642
  const trackedFirstSegments = deps.trackedFirstSegments ?? ((segs) => defaultTrackedFirstSegments(root, segs));
@@ -16636,7 +16769,7 @@ function walkMarkdown(dir) {
16636
16769
  const stack = [dir];
16637
16770
  while (stack.length) {
16638
16771
  const current = stack.pop();
16639
- 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 })) {
16640
16773
  const full = (0, import_node_path16.join)(current, entry.name);
16641
16774
  if (entry.isDirectory()) {
16642
16775
  stack.push(full);
@@ -16652,15 +16785,15 @@ function createDocsIndexDeps(repoRoot2) {
16652
16785
  const indexPath = (0, import_node_path16.join)(repoRoot2, DOCS_INDEX_PATH);
16653
16786
  return {
16654
16787
  listDocs: () => {
16655
- if (!(0, import_node_fs18.existsSync)(docsDir)) return [];
16788
+ if (!(0, import_node_fs19.existsSync)(docsDir)) return [];
16656
16789
  const walked = walkMarkdown(docsDir).filter(isRoutableDocsPath);
16657
16790
  if (!walked.length) return [];
16658
16791
  const ignored = defaultIsIgnored(repoRoot2, walked.map((rel) => `docs/${rel}`));
16659
16792
  return walked.filter((rel) => !ignored.has(`docs/${rel}`)).sort();
16660
16793
  },
16661
- readDoc: (relPath) => (0, import_node_fs18.readFileSync)((0, import_node_path16.join)(docsDir, relPath), "utf8"),
16662
- readIndex: () => (0, import_node_fs18.existsSync)(indexPath) ? (0, import_node_fs18.readFileSync)(indexPath, "utf8") : null,
16663
- 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")
16664
16797
  };
16665
16798
  }
16666
16799
 
@@ -17579,7 +17712,7 @@ function contentPutInputArgs(repo, path2, inputFile) {
17579
17712
  }
17580
17713
 
17581
17714
  // src/train-apply-contracts.ts
17582
- var import_node_fs19 = require("node:fs");
17715
+ var import_node_fs20 = require("node:fs");
17583
17716
  var import_node_path17 = require("node:path");
17584
17717
  function reduceFollowUpOutcomes(outcomes) {
17585
17718
  if (outcomes.includes("failure")) return "failure";
@@ -17660,7 +17793,7 @@ async function resolveFoldPaths(deps, model) {
17660
17793
  if (model === "vercel") return [];
17661
17794
  const helper = "scripts/release-distribution.mjs";
17662
17795
  if (model === "hub-serverless" || model === "registry-publish") {
17663
- if ((0, import_node_fs19.existsSync)(helper)) {
17796
+ if ((0, import_node_fs20.existsSync)(helper)) {
17664
17797
  let out;
17665
17798
  try {
17666
17799
  out = await deps.run("node", [helper, "changed-files"]);
@@ -17809,7 +17942,7 @@ async function restoreMainNpmPackIdentities(deps, version) {
17809
17942
  if (mainBom.version !== version) return void 0;
17810
17943
  let localBom;
17811
17944
  try {
17812
- localBom = JSON.parse((0, import_node_fs19.readFileSync)(bomPath, "utf8"));
17945
+ localBom = JSON.parse((0, import_node_fs20.readFileSync)(bomPath, "utf8"));
17813
17946
  } catch (e) {
17814
17947
  throw new Error(
17815
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).`
@@ -17827,14 +17960,14 @@ async function restoreMainNpmPackIdentities(deps, version) {
17827
17960
  restored += 1;
17828
17961
  }
17829
17962
  if (restored === 0) return void 0;
17830
- (0, import_node_fs19.writeFileSync)(bomPath, `${JSON.stringify(localBom, null, 2)}
17963
+ (0, import_node_fs20.writeFileSync)(bomPath, `${JSON.stringify(localBom, null, 2)}
17831
17964
  `);
17832
17965
  return `restored ${restored} npm-pack BOM identit${restored === 1 ? "y" : "ies"} from origin/main (#4503)`;
17833
17966
  }
17834
17967
  function publishVisibilityFor(surfaceId) {
17835
17968
  let raw;
17836
17969
  try {
17837
- raw = (0, import_node_fs19.readFileSync)("surfaces.json", "utf8");
17970
+ raw = (0, import_node_fs20.readFileSync)("surfaces.json", "utf8");
17838
17971
  } catch (e) {
17839
17972
  if (e.code === "ENOENT") return "unknown";
17840
17973
  throw trainReadFailure(
@@ -17855,7 +17988,7 @@ function publishVisibilityFor(surfaceId) {
17855
17988
  }
17856
17989
  function npmPackArtifactName(packagePath) {
17857
17990
  try {
17858
- 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"));
17859
17992
  return pkg.name || void 0;
17860
17993
  } catch {
17861
17994
  return void 0;
@@ -17864,7 +17997,7 @@ function npmPackArtifactName(packagePath) {
17864
17997
  async function refuseDivergentPublishedNpmPack(deps, version) {
17865
17998
  let localBom;
17866
17999
  try {
17867
- 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"));
17868
18001
  } catch (e) {
17869
18002
  throw new Error(
17870
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).`
@@ -18009,7 +18142,7 @@ function assertGitBashOnWindowsForJervHubRelease(repo, platform2 = process.platf
18009
18142
  }
18010
18143
 
18011
18144
  // src/train-apply-correlation.ts
18012
- var import_node_fs21 = require("node:fs");
18145
+ var import_node_fs22 = require("node:fs");
18013
18146
  init_github_quota();
18014
18147
  var import_node_path19 = require("node:path");
18015
18148
 
@@ -18776,10 +18909,10 @@ var rollout_plan_default = {
18776
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)."
18777
18910
  },
18778
18911
  baseline: {
18779
- version: "4.5.158",
18780
- tag: "v4.5.158",
18781
- commit: "21733e84802e",
18782
- npm: "@mutmutco/cli@4.5.158"
18912
+ version: "4.5.160",
18913
+ tag: "v4.5.160",
18914
+ commit: "05c3cc8d56ee",
18915
+ npm: "@mutmutco/cli@4.5.160"
18783
18916
  },
18784
18917
  exitCriterion: "fleet-n-of-n",
18785
18918
  hubOnlyShortcut: "forbidden",
@@ -18796,14 +18929,14 @@ var rollout_plan_default = {
18796
18929
  repo: "mutmutco/mmi-hub",
18797
18930
  role: "canary",
18798
18931
  schedule: "train",
18799
- v3Target: "v4.5.158"
18932
+ v3Target: "v4.5.160"
18800
18933
  }
18801
18934
  ],
18802
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.",
18803
18936
  rollback: {
18804
18937
  independent: true,
18805
- mechanism: "npm dist-tag latest -> 4.5.158 and redeploy the Hub Lambda from tag v4.5.158 (21733e84802e); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
18806
- v3Target: "v4.5.158 (@mutmutco/cli@4.5.158, tag commit 21733e84802e \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)"
18807
18940
  }
18808
18941
  },
18809
18942
  {
@@ -19137,13 +19270,13 @@ function resolveIssueViewGhFields(normalized) {
19137
19270
  }
19138
19271
 
19139
19272
  // src/utf8-receipt.ts
19140
- var import_node_fs20 = require("node:fs");
19273
+ var import_node_fs21 = require("node:fs");
19141
19274
  var import_node_path18 = require("node:path");
19142
19275
  function writeUtf8Receipt(path2, text) {
19143
- (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 });
19144
19277
  const body = text.endsWith("\n") ? text : `${text}
19145
19278
  `;
19146
- (0, import_node_fs20.writeFileSync)(path2, body, "utf8");
19279
+ (0, import_node_fs21.writeFileSync)(path2, body, "utf8");
19147
19280
  return Buffer.byteLength(body, "utf8");
19148
19281
  }
19149
19282
 
@@ -21029,7 +21162,7 @@ function resolveReleaseAbortNpmPackage(meta, repo) {
21029
21162
  if (isHubControlRepo(repo)) return "@mutmutco/cli";
21030
21163
  const publishDir = typeof meta.publishDir === "string" && meta.publishDir.trim() ? meta.publishDir.trim() : ".";
21031
21164
  try {
21032
- 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"));
21033
21166
  const name = pkg.name?.trim();
21034
21167
  if (!name) throw new Error("missing name field");
21035
21168
  return name;
@@ -21965,7 +22098,7 @@ function parseVerifyBroker(stdout) {
21965
22098
  }
21966
22099
 
21967
22100
  // src/train-apply-deploy.ts
21968
- var import_node_fs22 = require("node:fs");
22101
+ var import_node_fs23 = require("node:fs");
21969
22102
  var import_node_os11 = require("node:os");
21970
22103
  var import_node_path20 = require("node:path");
21971
22104
 
@@ -22106,7 +22239,7 @@ function mmiGetRedeployCommand(repo) {
22106
22239
  }
22107
22240
  function readLocalLauncherVersion(root = process.cwd()) {
22108
22241
  try {
22109
- 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");
22110
22243
  const version = JSON.parse(raw).version;
22111
22244
  return typeof version === "string" && version.trim() ? version.trim() : null;
22112
22245
  } catch {
@@ -22115,7 +22248,7 @@ function readLocalLauncherVersion(root = process.cwd()) {
22115
22248
  }
22116
22249
  function readServedChannelUrl(product = HUB_SERVED_PRODUCT, root = process.cwd()) {
22117
22250
  try {
22118
- 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");
22119
22252
  const host = JSON.parse(raw).host;
22120
22253
  if (typeof host !== "string" || !host.trim()) return null;
22121
22254
  return `${host.trim().replace(/\/+$/, "")}/release/version`;
@@ -22549,13 +22682,13 @@ async function runTaggedJervGatewayLocalWrapper(deps, tag, tagSha) {
22549
22682
  const reason = error instanceof Error ? error.message : String(error);
22550
22683
  throw new Error(`could not extract ${JERV_GATEWAY_RELEASE_DEPLOY_SCRIPT} from tagged commit ${tagSha.slice(0, 12)}: ${reason}`);
22551
22684
  }
22552
- 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-"));
22553
22686
  const extracted = (0, import_node_path20.join)(dir, "jerv-gateway-release-deploy.sh");
22554
22687
  try {
22555
- (0, import_node_fs22.writeFileSync)(extracted, script, "utf8");
22688
+ (0, import_node_fs23.writeFileSync)(extracted, script, "utf8");
22556
22689
  return await deps.run("bash", [extracted, "--tag", tag]);
22557
22690
  } finally {
22558
- (0, import_node_fs22.rmSync)(dir, { recursive: true, force: true });
22691
+ (0, import_node_fs23.rmSync)(dir, { recursive: true, force: true });
22559
22692
  }
22560
22693
  }
22561
22694
  async function appendJervGatewayReleaseDeploy(deps, repo, tag, tagSha, dispatch) {
@@ -23131,7 +23264,7 @@ function renderTenantControl(r) {
23131
23264
  }
23132
23265
 
23133
23266
  // src/train-apply-phases.ts
23134
- var import_node_fs28 = require("node:fs");
23267
+ var import_node_fs29 = require("node:fs");
23135
23268
  var import_promises4 = require("node:fs/promises");
23136
23269
  var import_node_path27 = require("node:path");
23137
23270
 
@@ -23450,12 +23583,12 @@ function assertPreOneZero(repo, meta, tag) {
23450
23583
 
23451
23584
  // src/train-doctor.ts
23452
23585
  var import_node_child_process9 = require("node:child_process");
23453
- var import_node_fs26 = require("node:fs");
23586
+ var import_node_fs27 = require("node:fs");
23454
23587
  var import_node_os15 = require("node:os");
23455
23588
  var import_node_path26 = require("node:path");
23456
23589
 
23457
23590
  // src/doctor-io.ts
23458
- var import_node_fs23 = require("node:fs");
23591
+ var import_node_fs24 = require("node:fs");
23459
23592
  var import_node_os12 = require("node:os");
23460
23593
  var import_node_path21 = require("node:path");
23461
23594
  var import_node_child_process7 = require("node:child_process");
@@ -23470,8 +23603,8 @@ function nodeDiscardSinkPath(platform2 = process.platform) {
23470
23603
  var execFileP2 = (0, import_node_util4.promisify)(import_node_child_process7.execFile);
23471
23604
  function execFileCapture(file, args, opts = {}) {
23472
23605
  const sink = nodeDiscardSinkPath();
23473
- const inFd = (0, import_node_fs23.openSync)(sink, "r");
23474
- 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");
23475
23608
  try {
23476
23609
  return (0, import_node_child_process7.execFileSync)(file, args, {
23477
23610
  ...opts,
@@ -23479,17 +23612,17 @@ function execFileCapture(file, args, opts = {}) {
23479
23612
  stdio: [inFd, "pipe", errFd]
23480
23613
  });
23481
23614
  } finally {
23482
- (0, import_node_fs23.closeSync)(inFd);
23483
- (0, import_node_fs23.closeSync)(errFd);
23615
+ (0, import_node_fs24.closeSync)(inFd);
23616
+ (0, import_node_fs24.closeSync)(errFd);
23484
23617
  }
23485
23618
  }
23486
23619
  var MMI_PLUGIN_ID2 = "mmi@mutmutco";
23487
23620
  function stagedClaudePluginVersion() {
23488
23621
  try {
23489
23622
  const stagingRoot = (0, import_node_path21.join)((0, import_node_os12.homedir)(), ".claude", "plugins", "staging");
23490
- 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"));
23491
23624
  if (typeof record.target !== "string" || typeof record.incoming !== "string") return void 0;
23492
- 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"));
23493
23626
  if (typeof manifest.version !== "string") return void 0;
23494
23627
  return manifest.version === record.target ? record.target : void 0;
23495
23628
  } catch {
@@ -23499,7 +23632,7 @@ function stagedClaudePluginVersion() {
23499
23632
  function installedClaudePluginVersion() {
23500
23633
  try {
23501
23634
  const file = JSON.parse(
23502
- (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")
23503
23636
  );
23504
23637
  const versions = (file.plugins?.[MMI_PLUGIN_ID2] ?? []).map((r) => r.version).filter((v) => Boolean(v));
23505
23638
  if (versions.length === 0) return void 0;
@@ -23511,12 +23644,12 @@ function installedClaudePluginVersion() {
23511
23644
  function readHermesPluginEvidence(env = process.env) {
23512
23645
  const host = hermesConfigRoot(env);
23513
23646
  const root = hermesPluginRoot(env);
23514
- const installRecordPresent = (0, import_node_fs23.existsSync)(root);
23647
+ const installRecordPresent = (0, import_node_fs24.existsSync)(root);
23515
23648
  const manifestPath = (0, import_node_path21.join)(root, "plugin.yaml");
23516
23649
  let installedVersion;
23517
23650
  let manifest = "missing";
23518
23651
  try {
23519
- const text = (0, import_node_fs23.readFileSync)(manifestPath, "utf8");
23652
+ const text = (0, import_node_fs24.readFileSync)(manifestPath, "utf8");
23520
23653
  let version;
23521
23654
  try {
23522
23655
  const parsed = JSON.parse(text).version;
@@ -23530,25 +23663,25 @@ function readHermesPluginEvidence(env = process.env) {
23530
23663
  if (version) {
23531
23664
  installedVersion = version;
23532
23665
  manifest = "valid";
23533
- } else if ((0, import_node_fs23.existsSync)(manifestPath)) manifest = "invalid";
23666
+ } else if ((0, import_node_fs24.existsSync)(manifestPath)) manifest = "invalid";
23534
23667
  } catch {
23535
- if ((0, import_node_fs23.existsSync)(manifestPath)) manifest = "invalid";
23668
+ if ((0, import_node_fs24.existsSync)(manifestPath)) manifest = "invalid";
23536
23669
  }
23537
23670
  let skills = false;
23538
23671
  try {
23539
- 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();
23540
23673
  } catch {
23541
23674
  }
23542
23675
  let provisioned = false;
23543
23676
  const provisionedRoot = (0, import_node_path21.join)(host, "skills", "mmi");
23544
23677
  try {
23545
- 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();
23546
23679
  } catch {
23547
23680
  }
23548
- 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";
23549
23682
  const receipt = treeOk && !provisioned ? `hermes-skills-unprovisioned:${provisionedRoot}` : void 0;
23550
23683
  return {
23551
- hostPresent: (0, import_node_fs23.existsSync)(host),
23684
+ hostPresent: (0, import_node_fs24.existsSync)(host),
23552
23685
  installRecordPresent,
23553
23686
  manifest,
23554
23687
  payloadPresent: treeOk && provisioned,
@@ -23600,7 +23733,7 @@ function readGitignore() {
23600
23733
  const path2 = gitignorePath();
23601
23734
  if (path2 === null) return null;
23602
23735
  try {
23603
- return (0, import_node_fs23.readFileSync)(path2, "utf8");
23736
+ return (0, import_node_fs24.readFileSync)(path2, "utf8");
23604
23737
  } catch {
23605
23738
  return null;
23606
23739
  }
@@ -23609,14 +23742,14 @@ function writeGitignore(content) {
23609
23742
  const path2 = gitignorePath();
23610
23743
  if (path2 === null) return false;
23611
23744
  try {
23612
- (0, import_node_fs23.writeFileSync)(path2, content, "utf8");
23745
+ (0, import_node_fs24.writeFileSync)(path2, content, "utf8");
23613
23746
  return true;
23614
23747
  } catch {
23615
23748
  return false;
23616
23749
  }
23617
23750
  }
23618
23751
  function lineEndingState(root) {
23619
- 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"));
23620
23753
  try {
23621
23754
  const output = execFileCapture("git", ["-C", root, "ls-files", "--eol", "--", ":(glob)**/*.sh"], {
23622
23755
  windowsHide: true
@@ -23659,7 +23792,7 @@ function compatHolds(range, version) {
23659
23792
  }
23660
23793
 
23661
23794
  // src/claude-binary-doctor.ts
23662
- var import_node_fs24 = require("node:fs");
23795
+ var import_node_fs25 = require("node:fs");
23663
23796
  var import_node_os14 = require("node:os");
23664
23797
  var import_node_path23 = require("node:path");
23665
23798
 
@@ -23769,16 +23902,16 @@ function globalNodeModulesRoots(host) {
23769
23902
  function readHead(path2) {
23770
23903
  let fd;
23771
23904
  try {
23772
- fd = (0, import_node_fs24.openSync)(path2, "r");
23905
+ fd = (0, import_node_fs25.openSync)(path2, "r");
23773
23906
  const buffer = new Uint8Array(MAGIC_HEAD_BYTES);
23774
- 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);
23775
23908
  return buffer.subarray(0, read);
23776
23909
  } catch {
23777
23910
  return void 0;
23778
23911
  } finally {
23779
23912
  if (fd !== void 0) {
23780
23913
  try {
23781
- (0, import_node_fs24.closeSync)(fd);
23914
+ (0, import_node_fs25.closeSync)(fd);
23782
23915
  } catch {
23783
23916
  }
23784
23917
  }
@@ -23786,7 +23919,7 @@ function readHead(path2) {
23786
23919
  }
23787
23920
  function fileBytes(path2) {
23788
23921
  try {
23789
- return (0, import_node_fs24.statSync)(path2).size;
23922
+ return (0, import_node_fs25.statSync)(path2).size;
23790
23923
  } catch {
23791
23924
  return void 0;
23792
23925
  }
@@ -23800,13 +23933,13 @@ function readClaudeBinaryState(host = {}) {
23800
23933
  const arch = host.arch ?? process.arch;
23801
23934
  const magic = EXECUTABLE_MAGIC[platform2];
23802
23935
  if (!magic) return void 0;
23803
- 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")));
23804
23937
  if (!packageRoot) return void 0;
23805
23938
  const keys = platformPackageKeys(platform2, arch);
23806
23939
  const fallbackPackage = `${PACKAGE}-${keys[0]}`;
23807
23940
  let manifest;
23808
23941
  try {
23809
- 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"));
23810
23943
  } catch (e) {
23811
23944
  return {
23812
23945
  state: "unreadable",
@@ -23837,7 +23970,7 @@ function readClaudeBinaryState(host = {}) {
23837
23970
  (0, import_node_path23.join)(packageRoot, "node_modules", ...name.split("/"), binName),
23838
23971
  (0, import_node_path23.join)((0, import_node_path23.dirname)((0, import_node_path23.dirname)(packageRoot)), ...name.split("/"), binName)
23839
23972
  ];
23840
- 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);
23841
23974
  const platformPackage = found?.name ?? published[0];
23842
23975
  let source;
23843
23976
  let sourceProblem;
@@ -23848,7 +23981,7 @@ function readClaudeBinaryState(host = {}) {
23848
23981
  } else {
23849
23982
  source = { path: found.path, bytes: fileBytes(found.path) ?? 0 };
23850
23983
  }
23851
- if (!(0, import_node_fs24.existsSync)(binPath)) {
23984
+ if (!(0, import_node_fs25.existsSync)(binPath)) {
23852
23985
  return { state: "missing", binPath, expectedMagic: magic.name, platformPackage, ...source ? { source } : {}, ...sourceProblem ? { sourceProblem } : {} };
23853
23986
  }
23854
23987
  const head = readHead(binPath);
@@ -23891,9 +24024,9 @@ function healClaudeBinary(host = {}, onStep) {
23891
24024
  const platform2 = host.platform ?? process.platform;
23892
24025
  const aside = `${probe.binPath}.stub-${Date.now()}`;
23893
24026
  let renamed = false;
23894
- if ((0, import_node_fs24.existsSync)(probe.binPath)) {
24027
+ if ((0, import_node_fs25.existsSync)(probe.binPath)) {
23895
24028
  try {
23896
- (0, import_node_fs24.renameSync)(probe.binPath, aside);
24029
+ (0, import_node_fs25.renameSync)(probe.binPath, aside);
23897
24030
  renamed = true;
23898
24031
  onStep?.(`renamed the stub aside: ${aside}`);
23899
24032
  } catch (e) {
@@ -23902,12 +24035,12 @@ function healClaudeBinary(host = {}, onStep) {
23902
24035
  }
23903
24036
  try {
23904
24037
  onStep?.(`copying ${probe.source.path} \u2192 ${probe.binPath} (${(probe.source.bytes / 1e6).toFixed(0)} MB)`);
23905
- (0, import_node_fs24.copyFileSync)(probe.source.path, probe.binPath);
23906
- 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);
23907
24040
  } catch (e) {
23908
24041
  if (renamed) {
23909
24042
  try {
23910
- (0, import_node_fs24.renameSync)(aside, probe.binPath);
24043
+ (0, import_node_fs25.renameSync)(aside, probe.binPath);
23911
24044
  } catch {
23912
24045
  return { ok: false, detail: `copy failed (${e.message}) and the stub could not be restored \u2014 the original is at ${aside}` };
23913
24046
  }
@@ -23921,7 +24054,7 @@ function healClaudeBinary(host = {}, onStep) {
23921
24054
  let kept = false;
23922
24055
  if (renamed) {
23923
24056
  try {
23924
- (0, import_node_fs24.rmSync)(aside);
24057
+ (0, import_node_fs25.rmSync)(aside);
23925
24058
  } catch {
23926
24059
  kept = true;
23927
24060
  }
@@ -24280,7 +24413,7 @@ function checkLineEndings(probe) {
24280
24413
  }
24281
24414
 
24282
24415
  // src/release-ledger.ts
24283
- var import_node_fs25 = require("node:fs");
24416
+ var import_node_fs26 = require("node:fs");
24284
24417
  var import_node_path25 = require("node:path");
24285
24418
  var import_node_crypto9 = require("node:crypto");
24286
24419
 
@@ -24455,8 +24588,8 @@ function attachOutputNote(note, suffix) {
24455
24588
  }
24456
24589
  function writeFailingLegOutput(artifactPath, output) {
24457
24590
  const fileLines = lastNonEmptyLines(output, LEDGER_OUTPUT_FILE_LINES);
24458
- (0, import_node_fs25.mkdirSync)((0, import_node_path25.dirname)(artifactPath), { recursive: true });
24459
- (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")}
24460
24593
  `, "utf8");
24461
24594
  const tail = fileLines.slice(-LEDGER_OUTPUT_NOTE_LINES).join("\n");
24462
24595
  const noteSuffix = truncate(`failing-leg output: ${artifactPath}
@@ -24624,7 +24757,7 @@ function resolvePrimaryGitDir(cwd) {
24624
24757
  }
24625
24758
  let common;
24626
24759
  try {
24627
- 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();
24628
24761
  } catch (e) {
24629
24762
  if (e.code !== "ENOENT") {
24630
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)`);
@@ -24633,7 +24766,7 @@ function resolvePrimaryGitDir(cwd) {
24633
24766
  if (!common) return gitDir;
24634
24767
  const commonDir = (0, import_node_path25.isAbsolute)(common) ? common : (0, import_node_path25.resolve)(gitDir, common);
24635
24768
  try {
24636
- (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");
24637
24770
  } catch (e) {
24638
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`);
24639
24772
  }
@@ -24643,11 +24776,11 @@ function releaseLedgerPath(cwd) {
24643
24776
  return (0, import_node_path25.join)(resolvePrimaryGitDir(cwd), "mmi-runtime", "release", "phases.json");
24644
24777
  }
24645
24778
  function atomicWriteJson(path2, ledger) {
24646
- (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 });
24647
24780
  const tmp = `${path2}.tmp-${process.pid}-${(0, import_node_crypto9.randomBytes)(4).toString("hex")}`;
24648
- (0, import_node_fs25.writeFileSync)(tmp, `${JSON.stringify(ledger, null, 2)}
24781
+ (0, import_node_fs26.writeFileSync)(tmp, `${JSON.stringify(ledger, null, 2)}
24649
24782
  `, "utf8");
24650
- (0, import_node_fs25.renameSync)(tmp, path2);
24783
+ (0, import_node_fs26.renameSync)(tmp, path2);
24651
24784
  }
24652
24785
  var LEDGER_LOCK_OPTS = { label: "release ledger", staleMs: 18e4, deadHolderSteal: true };
24653
24786
  async function withLedgerLock(path2, fn, opts = {}) {
@@ -24694,7 +24827,7 @@ function describeTrainWriterToken(token) {
24694
24827
  function liveTrainWriterHolder(cwd) {
24695
24828
  let token;
24696
24829
  try {
24697
- token = (0, import_node_fs25.readFileSync)(trainWriterLockPath(cwd), "utf8");
24830
+ token = (0, import_node_fs26.readFileSync)(trainWriterLockPath(cwd), "utf8");
24698
24831
  } catch {
24699
24832
  return void 0;
24700
24833
  }
@@ -24716,7 +24849,7 @@ async function acquireTrainWriterLock(cwd, verb) {
24716
24849
  if (heldTrainWriter) heldTrainWriter.depth -= 1;
24717
24850
  };
24718
24851
  }
24719
- (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 });
24720
24853
  const opts = resolveFileLockOpts({ label: "train writer", staleMs: TRAIN_WRITER_STALE_MS, deadHolderSteal: true, maxWaitMs: 0, holder: verb });
24721
24854
  let guard;
24722
24855
  try {
@@ -24725,7 +24858,7 @@ async function acquireTrainWriterLock(cwd, verb) {
24725
24858
  if (!(e instanceof FileLockBusyError)) throw e;
24726
24859
  let token = "";
24727
24860
  try {
24728
- token = (0, import_node_fs25.readFileSync)(lockPath, "utf8");
24861
+ token = (0, import_node_fs26.readFileSync)(lockPath, "utf8");
24729
24862
  } catch {
24730
24863
  token = "";
24731
24864
  }
@@ -24760,7 +24893,7 @@ async function withReleaseLedger(path2, expected, fn, opts = {}) {
24760
24893
  let current;
24761
24894
  let raw;
24762
24895
  try {
24763
- raw = (0, import_node_fs25.readFileSync)(path2, "utf8");
24896
+ raw = (0, import_node_fs26.readFileSync)(path2, "utf8");
24764
24897
  } catch (e) {
24765
24898
  if (e.code !== "ENOENT") {
24766
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)`);
@@ -25429,7 +25562,7 @@ async function clearLedgerFile(path2, anchors, maxWaitMs) {
25429
25562
  return withLedgerLock(path2, async (fence) => {
25430
25563
  let raw;
25431
25564
  try {
25432
- raw = (0, import_node_fs25.readFileSync)(path2, "utf8");
25565
+ raw = (0, import_node_fs26.readFileSync)(path2, "utf8");
25433
25566
  } catch (e) {
25434
25567
  if (e.code === "ENOENT") return { cleared: false };
25435
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` };
@@ -25445,7 +25578,7 @@ async function clearLedgerFile(path2, anchors, maxWaitMs) {
25445
25578
  } catch (e) {
25446
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)})` };
25447
25580
  }
25448
- await fence(() => (0, import_node_fs25.unlinkSync)(path2));
25581
+ await fence(() => (0, import_node_fs26.unlinkSync)(path2));
25449
25582
  return { cleared: true, note: `cleared the release ledger at ${path2} for the live-proven aborted ${anchors.tag}` };
25450
25583
  }, { maxWaitMs });
25451
25584
  }
@@ -25605,7 +25738,7 @@ async function healStaleAlignmentLeg(deps, cwd, expected) {
25605
25738
  return withLedgerLock(path2, async (fence) => {
25606
25739
  let prior;
25607
25740
  try {
25608
- prior = parseReleaseLedger((0, import_node_fs25.readFileSync)(path2, "utf8"));
25741
+ prior = parseReleaseLedger((0, import_node_fs26.readFileSync)(path2, "utf8"));
25609
25742
  } catch {
25610
25743
  return void 0;
25611
25744
  }
@@ -25630,7 +25763,7 @@ async function healUnfoldedRunLegs(deps, cwd, model) {
25630
25763
  const path2 = releaseLedgerPath(cwd);
25631
25764
  let prior;
25632
25765
  try {
25633
- prior = parseReleaseLedger((0, import_node_fs25.readFileSync)(path2, "utf8"));
25766
+ prior = parseReleaseLedger((0, import_node_fs26.readFileSync)(path2, "utf8"));
25634
25767
  } catch {
25635
25768
  return void 0;
25636
25769
  }
@@ -25699,7 +25832,7 @@ async function supersedeContentCausedDeployLeg(deps, cwd) {
25699
25832
  return withLedgerLock(path2, async (fence) => {
25700
25833
  let prior;
25701
25834
  try {
25702
- prior = parseReleaseLedger((0, import_node_fs25.readFileSync)(path2, "utf8"));
25835
+ prior = parseReleaseLedger((0, import_node_fs26.readFileSync)(path2, "utf8"));
25703
25836
  } catch (e) {
25704
25837
  throw new ReleaseLedgerError(
25705
25838
  "unreadable",
@@ -25797,10 +25930,10 @@ async function proveOriginPromotionOrArchived(deps, prior, path2, label, ref, fe
25797
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})`);
25798
25931
  }
25799
25932
  const archivePath = (0, import_node_path25.join)((0, import_node_path25.dirname)(path2), `phases.archive-${prior.tag}.json`);
25800
- if ((0, import_node_fs25.existsSync)(archivePath)) {
25933
+ if ((0, import_node_fs26.existsSync)(archivePath)) {
25801
25934
  throw new Error(`${label}: archive already exists at ${archivePath} \u2014 preserving both ledger records; resolve the collision by hand; nothing was written (${ref})`);
25802
25935
  }
25803
- await fence(() => (0, import_node_fs25.renameSync)(path2, archivePath));
25936
+ await fence(() => (0, import_node_fs26.renameSync)(path2, archivePath));
25804
25937
  return "deleted";
25805
25938
  }
25806
25939
  async function supersedeContentCausedPublishLeg(deps, cwd) {
@@ -25808,7 +25941,7 @@ async function supersedeContentCausedPublishLeg(deps, cwd) {
25808
25941
  return withLedgerLock(path2, async (fence) => {
25809
25942
  let prior;
25810
25943
  try {
25811
- prior = parseReleaseLedger((0, import_node_fs25.readFileSync)(path2, "utf8"));
25944
+ prior = parseReleaseLedger((0, import_node_fs26.readFileSync)(path2, "utf8"));
25812
25945
  } catch (e) {
25813
25946
  throw new ReleaseLedgerError(
25814
25947
  "unreadable",
@@ -25890,7 +26023,7 @@ async function supersedeContentCausedDeployAndPublishLegs(deps, cwd) {
25890
26023
  return withLedgerLock(path2, async (fence) => {
25891
26024
  let prior;
25892
26025
  try {
25893
- prior = parseReleaseLedger((0, import_node_fs25.readFileSync)(path2, "utf8"));
26026
+ prior = parseReleaseLedger((0, import_node_fs26.readFileSync)(path2, "utf8"));
25894
26027
  } catch (e) {
25895
26028
  throw new ReleaseLedgerError(
25896
26029
  "unreadable",
@@ -25995,7 +26128,7 @@ async function supersedeContentCausedDeployAndPublishLegs(deps, cwd) {
25995
26128
  async function reverifyPriorRunLegs(deps, path2, targetTag) {
25996
26129
  let prior;
25997
26130
  try {
25998
- prior = parseReleaseLedger((0, import_node_fs25.readFileSync)(path2, "utf8"));
26131
+ prior = parseReleaseLedger((0, import_node_fs26.readFileSync)(path2, "utf8"));
25999
26132
  } catch {
26000
26133
  return;
26001
26134
  }
@@ -26015,7 +26148,7 @@ async function beginReleaseLedger(deps, cwd, targetTag) {
26015
26148
  return withLedgerLock(path2, async (fence) => {
26016
26149
  let raw;
26017
26150
  try {
26018
- raw = (0, import_node_fs25.readFileSync)(path2, "utf8");
26151
+ raw = (0, import_node_fs26.readFileSync)(path2, "utf8");
26019
26152
  } catch (e) {
26020
26153
  if (e.code === "ENOENT") return { ok: true };
26021
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)` };
@@ -26055,13 +26188,13 @@ async function beginReleaseLedger(deps, cwd, targetTag) {
26055
26188
  }
26056
26189
  const archivePath = (0, import_node_path25.join)((0, import_node_path25.dirname)(path2), `phases.archive-${prior.tag}.json`);
26057
26190
  try {
26058
- await fence(() => (0, import_node_fs25.unlinkSync)(archivePath));
26191
+ await fence(() => (0, import_node_fs26.unlinkSync)(archivePath));
26059
26192
  } catch (e) {
26060
26193
  if (e.code !== "ENOENT") {
26061
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)` };
26062
26195
  }
26063
26196
  }
26064
- await fence(() => (0, import_node_fs25.renameSync)(path2, archivePath));
26197
+ await fence(() => (0, import_node_fs26.renameSync)(path2, archivePath));
26065
26198
  return { ok: true, note: `archived the completed release ledger ${prior.tag} to ${archivePath} (live-proven at ${prior.tagSha.slice(0, 12)})` };
26066
26199
  });
26067
26200
  }
@@ -26089,7 +26222,7 @@ async function retryHotfixDeployLegs(deps, cwd, opts = {}) {
26089
26222
  return withLedgerLock(path2, async (fence) => {
26090
26223
  let prior;
26091
26224
  try {
26092
- prior = parseReleaseLedger((0, import_node_fs25.readFileSync)(path2, "utf8"));
26225
+ prior = parseReleaseLedger((0, import_node_fs26.readFileSync)(path2, "utf8"));
26093
26226
  } catch (e) {
26094
26227
  throw new ReleaseLedgerError(
26095
26228
  "unreadable",
@@ -26282,10 +26415,10 @@ function readOriginWorkflowsDefault(root, ref) {
26282
26415
  }
26283
26416
  var NPM_REGISTRY = "https://registry.npmjs.org";
26284
26417
  async function probeRegistryWhoami(train) {
26285
- 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-"));
26286
26419
  const rc = (0, import_node_path26.join)(dir, "npmrc");
26287
26420
  try {
26288
- (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");
26289
26422
  await train.runSelf(["secrets", "use", "npm/NPM_TOKEN", "--slug", "_org", "--", "npm", "whoami", "--registry", NPM_REGISTRY, "--userconfig", rc]);
26290
26423
  return { kind: "ok", detail: "the registry answered a login" };
26291
26424
  } catch (e) {
@@ -26296,7 +26429,7 @@ async function probeRegistryWhoami(train) {
26296
26429
  if (/\bE401\b|401 Unauthorized/.test(stderr)) return { kind: "rejected", detail: "npm whoami answered 401 Unauthorized" };
26297
26430
  return { kind: "unverified", detail: first };
26298
26431
  } finally {
26299
- (0, import_node_fs26.rmSync)(dir, { recursive: true, force: true });
26432
+ (0, import_node_fs27.rmSync)(dir, { recursive: true, force: true });
26300
26433
  }
26301
26434
  }
26302
26435
  var REGISTRY_TOKEN_ENV = /\b(NODE_AUTH_TOKEN|NPM_TOKEN)\b/;
@@ -26314,7 +26447,7 @@ var defaultDeps2 = {
26314
26447
  ledgerPath: releaseLedgerPath,
26315
26448
  readLedgerRaw: (path2) => {
26316
26449
  try {
26317
- return (0, import_node_fs26.readFileSync)(path2, "utf8");
26450
+ return (0, import_node_fs27.readFileSync)(path2, "utf8");
26318
26451
  } catch (e) {
26319
26452
  if (e.code === "ENOENT") return void 0;
26320
26453
  throw e;
@@ -26325,7 +26458,7 @@ var defaultDeps2 = {
26325
26458
  trainWriterHolder: liveTrainWriterHolder,
26326
26459
  readSurfacesRaw: (cwd) => {
26327
26460
  try {
26328
- 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");
26329
26462
  } catch {
26330
26463
  return void 0;
26331
26464
  }
@@ -26964,7 +27097,7 @@ function formatTrainDoctor(v) {
26964
27097
 
26965
27098
  // src/release-plain-words.ts
26966
27099
  var import_promises3 = require("node:fs/promises");
26967
- var import_node_fs27 = require("node:fs");
27100
+ var import_node_fs28 = require("node:fs");
26968
27101
  function releaseCutByNotes(cutBy) {
26969
27102
  return `## Internal
26970
27103
  Cut by ${formatSessionIdentity(cutBy)}
@@ -27070,7 +27203,7 @@ function validateSuiteReleaseSummary(path2, pathTr) {
27070
27203
  for (const [lang, file] of files) {
27071
27204
  let content;
27072
27205
  try {
27073
- content = (0, import_node_fs27.readFileSync)(file, "utf8");
27206
+ content = (0, import_node_fs28.readFileSync)(file, "utf8");
27074
27207
  } catch (e) {
27075
27208
  throw new Error(`could not read summary file ${file}: ${e.message} \u2014 see ${SUMMARY_GUIDE}`);
27076
27209
  }
@@ -27285,14 +27418,14 @@ function readLocalGateWorkflows() {
27285
27418
  const dir = (0, import_node_path27.join)(".github", "workflows");
27286
27419
  let names;
27287
27420
  try {
27288
- names = (0, import_node_fs28.readdirSync)(dir);
27421
+ names = (0, import_node_fs29.readdirSync)(dir);
27289
27422
  } catch {
27290
27423
  return null;
27291
27424
  }
27292
27425
  const files = [];
27293
27426
  for (const name of names.filter(isGateWorkflowPath)) {
27294
27427
  try {
27295
- 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") });
27296
27429
  } catch {
27297
27430
  }
27298
27431
  }
@@ -27302,14 +27435,14 @@ function readLocalWorkflows() {
27302
27435
  const dir = (0, import_node_path27.join)(".github", "workflows");
27303
27436
  let names;
27304
27437
  try {
27305
- names = (0, import_node_fs28.readdirSync)(dir);
27438
+ names = (0, import_node_fs29.readdirSync)(dir);
27306
27439
  } catch {
27307
27440
  return null;
27308
27441
  }
27309
27442
  const files = [];
27310
27443
  for (const name of names.filter((n) => /\.ya?ml$/i.test(n))) {
27311
27444
  try {
27312
- 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") });
27313
27446
  } catch {
27314
27447
  }
27315
27448
  }
@@ -28191,7 +28324,7 @@ async function activeRcandLedgerCandidate(deps, cwd) {
28191
28324
  }
28192
28325
  let prior;
28193
28326
  try {
28194
- prior = parseReleaseLedger((0, import_node_fs28.readFileSync)(path2, "utf8"));
28327
+ prior = parseReleaseLedger((0, import_node_fs29.readFileSync)(path2, "utf8"));
28195
28328
  } catch {
28196
28329
  return void 0;
28197
28330
  }
@@ -30807,7 +30940,7 @@ var PRIMARY_GROUPS = [
30807
30940
  ["Setup and support", ["bootstrap", "secrets", "docs", "tests", "spawn", "dist"]],
30808
30941
  ["Coordinate and improve", ["wave", "report", "skill-lesson", "closure-rate"]]
30809
30942
  ];
30810
- 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"]);
30811
30944
  var CAMPAIGN_ORCHESTRATOR_TOP_LEVEL = /* @__PURE__ */ new Set(["pickup", "read"]);
30812
30945
  var SUPPORT_PRIMARY = /* @__PURE__ */ new Set(["doctor", "whoami", "commands", "explain", "docs", "tests", "spawn", "dist", "wave", "report", "skill-lesson", "closure-rate"]);
30813
30946
  var TOP_LEVEL_ORDER = /* @__PURE__ */ new Map();
@@ -30848,6 +30981,7 @@ var COMMAND_OWNERSHIP = {
30848
30981
  stage: { module_owner: "cli/src/stage-commands.ts", consumer: "agent-workflow" },
30849
30982
  pr: { module_owner: "cli/src/pr-commands.ts", consumer: "agent-workflow" },
30850
30983
  api: { module_owner: "cli/src/api-read.ts", consumer: "agent-workflow" },
30984
+ github: { module_owner: "cli/src/github-budget.ts", consumer: "release-operator" },
30851
30985
  read: { module_owner: "cli/src/app-read-broker.ts", consumer: "agent-workflow" },
30852
30986
  ci: { module_owner: "cli/src/ci-audit.ts", consumer: "release-operator" },
30853
30987
  rcand: { module_owner: "cli/src/train-commands.ts", consumer: "release-operator" },
@@ -31587,6 +31721,55 @@ function renderPluginCachePlan(plan, applied) {
31587
31721
  return lines2.join("\n");
31588
31722
  }
31589
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
+
31590
31773
  // src/board-commands.ts
31591
31774
  init_cli_shared();
31592
31775
 
@@ -32088,7 +32271,7 @@ function registerBoardCommands(program3) {
32088
32271
  }
32089
32272
 
32090
32273
  // src/bootstrap-commands.ts
32091
- var import_node_fs32 = require("node:fs");
32274
+ var import_node_fs33 = require("node:fs");
32092
32275
  var import_node_os18 = require("node:os");
32093
32276
  var import_node_path31 = require("node:path");
32094
32277
  init_cli_shared();
@@ -32274,7 +32457,7 @@ init_github_client();
32274
32457
  init_cli_shared();
32275
32458
 
32276
32459
  // src/port-registry.ts
32277
- var import_node_fs29 = require("node:fs");
32460
+ var import_node_fs30 = require("node:fs");
32278
32461
  var import_node_path28 = require("node:path");
32279
32462
 
32280
32463
  // ../infra/port-geometry.mjs
@@ -32289,8 +32472,8 @@ function nextPortBlock(registry2) {
32289
32472
  return [base, base + PORT_SPAN];
32290
32473
  }
32291
32474
  function loadPortRegistry(path2) {
32292
- if (!(0, import_node_fs29.existsSync)(path2)) return {};
32293
- 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"));
32294
32477
  const out = {};
32295
32478
  for (const [key, value] of Object.entries(raw)) {
32296
32479
  if (Array.isArray(value) && value.length === 2 && value.every((n) => typeof n === "number")) {
@@ -32320,7 +32503,7 @@ function existingPortRange(repo, registry2) {
32320
32503
  function portRangeInfraAt(root, source) {
32321
32504
  const registryPath = (0, import_node_path28.join)(root, "infra", "port-ranges.json");
32322
32505
  const ddbScriptPath = (0, import_node_path28.join)(root, "infra", "port-ddb.mjs");
32323
- 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;
32324
32507
  return { root, source, registryPath, ddbScriptPath };
32325
32508
  }
32326
32509
  function resolvePortRangeInfra(cwd, packageDir) {
@@ -32402,7 +32585,7 @@ async function assignPersistedPortRange(repo, slug, reg, opts) {
32402
32585
  }
32403
32586
 
32404
32587
  // src/box-commands.ts
32405
- var import_node_fs31 = require("node:fs");
32588
+ var import_node_fs32 = require("node:fs");
32406
32589
  var import_node_child_process10 = require("node:child_process");
32407
32590
  var import_node_os17 = require("node:os");
32408
32591
  var import_node_path30 = require("node:path");
@@ -32536,7 +32719,7 @@ function applyRemoteScript(items, date) {
32536
32719
  init_clean_exit();
32537
32720
 
32538
32721
  // src/secrets-commands.ts
32539
- var import_node_fs30 = require("node:fs");
32722
+ var import_node_fs31 = require("node:fs");
32540
32723
  var import_node_path29 = require("node:path");
32541
32724
  var import_node_os16 = require("node:os");
32542
32725
  init_cli_shared();
@@ -33686,8 +33869,8 @@ async function decryptRailsCredentials(input) {
33686
33869
  MMI_RAILS_CREDENTIALS_FILE: credentialsPath,
33687
33870
  MMI_RAILS_MASTER_KEY_FILE: masterKeyPath
33688
33871
  };
33689
- if ((0, import_node_fs30.existsSync)(masterKeyPath)) {
33690
- 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();
33691
33874
  }
33692
33875
  const script = [
33693
33876
  'require "json"',
@@ -33697,9 +33880,9 @@ async function decryptRailsCredentials(input) {
33697
33880
  'config = ActiveSupport::EncryptedConfiguration.new(config_path: config_path, key_path: key_path, env_key: "RAILS_MASTER_KEY", raise_if_missing_key: true)',
33698
33881
  "puts JSON.generate(config.config)"
33699
33882
  ].join("\n");
33700
- 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-"));
33701
33884
  const scriptPath = (0, import_node_path29.join)(scriptDir, "decrypt.rb");
33702
- (0, import_node_fs30.writeFileSync)(scriptPath, script, "utf8");
33885
+ (0, import_node_fs31.writeFileSync)(scriptPath, script, "utf8");
33703
33886
  try {
33704
33887
  const args = ["exec", "ruby", scriptPath];
33705
33888
  const cmd = process.platform === "win32" ? "cmd.exe" : "bundle";
@@ -33711,7 +33894,7 @@ async function decryptRailsCredentials(input) {
33711
33894
  });
33712
33895
  return JSON.parse(stdout);
33713
33896
  } finally {
33714
- (0, import_node_fs30.rmSync)(scriptDir, { recursive: true, force: true });
33897
+ (0, import_node_fs31.rmSync)(scriptDir, { recursive: true, force: true });
33715
33898
  }
33716
33899
  }
33717
33900
  async function readSecretStdin() {
@@ -33801,7 +33984,7 @@ function registerSecretsCommands(program3) {
33801
33984
  let body;
33802
33985
  if (o.file) {
33803
33986
  try {
33804
- 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");
33805
33988
  } catch (e) {
33806
33989
  return fail(`secrets org-catalog: cannot read --file ${o.file}: ${e.message}`);
33807
33990
  }
@@ -33937,7 +34120,7 @@ function registerSecretsCommands(program3) {
33937
34120
  {
33938
34121
  ...d,
33939
34122
  decryptRailsCredentials,
33940
- 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))
33941
34124
  },
33942
34125
  {
33943
34126
  repo: o.repo,
@@ -34193,7 +34376,7 @@ function registerBoxCommands(program3) {
34193
34376
  }
34194
34377
  const remote = command && command.length ? command.join(" ") : void 0;
34195
34378
  const wroteScript = o.ssh && o.script ? o.script : null;
34196
- 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");
34197
34380
  if (o.json) {
34198
34381
  console.log(JSON.stringify({
34199
34382
  box: found,
@@ -34267,17 +34450,17 @@ function hubGitShow(ref) {
34267
34450
  return (path2) => git3(["show", `${ref}:${path2}`]);
34268
34451
  }
34269
34452
  function runOnBox(found, script) {
34270
- 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-"));
34271
34454
  try {
34272
34455
  const recipe = (0, import_node_path30.join)(dir, "recipe.sh");
34273
- (0, import_node_fs31.writeFileSync)(recipe, sshRecipeScript(found, "sh -s"), "utf8");
34456
+ (0, import_node_fs32.writeFileSync)(recipe, sshRecipeScript(found, "sh -s"), "utf8");
34274
34457
  const r = (0, import_node_child_process10.spawnSync)("bash", [recipe], { input: script, encoding: "utf8", maxBuffer: 16 * 1024 * 1024, timeout: 18e4, windowsHide: true });
34275
34458
  if (r.status !== 0) {
34276
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(" | ")}`);
34277
34460
  }
34278
34461
  return r.stdout;
34279
34462
  } finally {
34280
- (0, import_node_fs31.rmSync)(dir, { recursive: true, force: true });
34463
+ (0, import_node_fs32.rmSync)(dir, { recursive: true, force: true });
34281
34464
  }
34282
34465
  }
34283
34466
  function formatControl(mode, box, rows) {
@@ -35912,12 +36095,12 @@ async function verifyTargetedSeedPr(repo, number, plan, target, expected, client
35912
36095
  // src/bootstrap-commands.ts
35913
36096
  var execGitForSeedSource = async (args) => (await execFileP("git", args, { timeout: GIT_TIMEOUT_MS })).stdout;
35914
36097
  async function gateRenderDiff(current, rendered) {
35915
- 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-"));
35916
36099
  const before = (0, import_node_path31.join)(dir, "committed-gate.yml");
35917
36100
  const after = (0, import_node_path31.join)(dir, "registry-render.yml");
35918
36101
  try {
35919
- (0, import_node_fs32.writeFileSync)(before, current);
35920
- (0, import_node_fs32.writeFileSync)(after, rendered);
36102
+ (0, import_node_fs33.writeFileSync)(before, current);
36103
+ (0, import_node_fs33.writeFileSync)(after, rendered);
35921
36104
  try {
35922
36105
  return (await execFileP("git", ["diff", "--no-index", "--", before, after], { timeout: GIT_TIMEOUT_MS })).stdout;
35923
36106
  } catch (e) {
@@ -35926,7 +36109,7 @@ async function gateRenderDiff(current, rendered) {
35926
36109
  throw e;
35927
36110
  }
35928
36111
  } finally {
35929
- (0, import_node_fs32.rmSync)(dir, { recursive: true, force: true });
36112
+ (0, import_node_fs33.rmSync)(dir, { recursive: true, force: true });
35930
36113
  }
35931
36114
  }
35932
36115
  function bootstrapTrainDoctorDeps() {
@@ -35986,13 +36169,13 @@ function registerBootstrapCommands(program3) {
35986
36169
  })),
35987
36170
  pushAllowlistOwners: verifyOwners,
35988
36171
  pushAllowlistOwnersRead: verifyOwnersRead,
35989
- 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,
35990
36173
  // requiredGcpApis is stored as an array by a JSON write, but `org project set --var KEY=VALUE` stores a raw
35991
36174
  // comma-string — accept either so the seeded value verifies regardless of how it was written.
35992
36175
  // #3689: the same committed map the org access audit reads (#3664), so a sanctioned admin is not a
35993
36176
  // permanent bootstrap failure on one surface and an intended state on the other. Absent file → no
35994
36177
  // sanction, which is the pre-#3664 behaviour.
35995
- 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,
35996
36179
  requiredGcpApis: (() => {
35997
36180
  const v = meta?.requiredGcpApis;
35998
36181
  if (Array.isArray(v)) return v;
@@ -36070,14 +36253,14 @@ function registerBootstrapCommands(program3) {
36070
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 () => {
36071
36254
  const o = { repo: rawValue("--repo", ""), json: rawFlag("--json") };
36072
36255
  const manifestPath = "skills/bootstrap/seeds/manifest.json";
36073
- 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`);
36074
36257
  const seedSource = await resolveHubSeedSource(execGitForSeedSource);
36075
36258
  if (!seedSource.ok) return fail(`bootstrap drift: ${seedSource.reason}`);
36076
- const manifest = loadBootstrapSeeds((0, import_node_fs32.readFileSync)(manifestPath, "utf8"));
36259
+ const manifest = loadBootstrapSeeds((0, import_node_fs33.readFileSync)(manifestPath, "utf8"));
36077
36260
  const hubContents = /* @__PURE__ */ new Map();
36078
36261
  for (const s of manifest.seeds) {
36079
36262
  if (s.ownership !== "org" || s.source !== "self") continue;
36080
- 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);
36081
36264
  }
36082
36265
  let targets;
36083
36266
  let classOf = (_repo) => "deployable";
@@ -36285,24 +36468,24 @@ function registerBootstrapCommands(program3) {
36285
36468
  return;
36286
36469
  }
36287
36470
  const manifestPath = "skills/bootstrap/seeds/manifest.json";
36288
- 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`);
36289
36472
  const seedSource = await resolveHubSeedSource(execGitForSeedSource);
36290
36473
  if (!seedSource.ok) return fail(`bootstrap apply: ${seedSource.reason}`);
36291
- const manifest = loadBootstrapSeeds((0, import_node_fs32.readFileSync)(manifestPath, "utf8"));
36474
+ const manifest = loadBootstrapSeeds((0, import_node_fs33.readFileSync)(manifestPath, "utf8"));
36292
36475
  const baseBranch = o.class === "content" ? "main" : "development";
36293
36476
  const slug = parsedRepo.slug;
36294
36477
  const onlyTarget = o.fromConfig && o.only.trim() === "gate.yml" ? ".github/workflows/gate.yml" : o.only.trim();
36295
36478
  const gh2 = async (args) => execFileP("gh", args, { timeout: 2e4 });
36296
- 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;
36297
36480
  const enc = (p) => p.split("/").map(encodeURIComponent).join("/");
36298
36481
  const putSeed = async (target, content, ref, sha) => {
36299
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`);
36300
- (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");
36301
36484
  try {
36302
36485
  await gh2(contentPutInputArgs(repo, target, tmp));
36303
36486
  } finally {
36304
36487
  try {
36305
- (0, import_node_fs32.unlinkSync)(tmp);
36488
+ (0, import_node_fs33.unlinkSync)(tmp);
36306
36489
  } catch {
36307
36490
  }
36308
36491
  }
@@ -36938,10 +37121,10 @@ LIVE apply to ${repo}:
36938
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 () => {
36939
37122
  const o = { target: rawValue("--target", ""), execute: rawFlag("--execute"), json: rawFlag("--json") };
36940
37123
  const manifestPath = "skills/bootstrap/seeds/manifest.json";
36941
- 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`);
36942
37125
  const seedSource = await resolveHubSeedSource(execGitForSeedSource);
36943
37126
  if (!seedSource.ok) return fail(`bootstrap propagate: ${seedSource.reason}`);
36944
- const manifest = loadBootstrapSeeds((0, import_node_fs32.readFileSync)(manifestPath, "utf8"));
37127
+ const manifest = loadBootstrapSeeds((0, import_node_fs33.readFileSync)(manifestPath, "utf8"));
36945
37128
  const propagatable = manifest.seeds.filter(isPropagatableSeed);
36946
37129
  if (!o.target) {
36947
37130
  return fail(`bootstrap propagate: --target <path> is required \u2014 one of:
@@ -36950,9 +37133,9 @@ LIVE apply to ${repo}:
36950
37133
  const seed = propagatable.find((s) => s.target === o.target);
36951
37134
  if (!seed) return fail(`bootstrap propagate: --target '${o.target}' names no centrally propagatable seed in ${manifestPath}. Propagatable targets:
36952
37135
  ${propagatable.map((s) => s.target).join("\n ")}`);
36953
- 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`);
36954
- const hubContent = seed.managedBlock ? null : (0, import_node_fs32.readFileSync)(seed.target, "utf8");
36955
- 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;
36956
37139
  const isWorkflowSeed = seed.target.startsWith(".github/workflows/");
36957
37140
  const cfg = await loadConfig();
36958
37141
  const projects = await fetchProjectsList(registryClientDeps(cfg));
@@ -36961,9 +37144,9 @@ LIVE apply to ${repo}:
36961
37144
  }
36962
37145
  const rosterRepos = collectRegistryRepos(projects).filter((r) => r.toLowerCase() !== "mutmutco/mmi-hub");
36963
37146
  let independentCount = rosterRepos.length;
36964
- if ((0, import_node_fs32.existsSync)("projects.json")) {
37147
+ if ((0, import_node_fs33.existsSync)("projects.json")) {
36965
37148
  try {
36966
- 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"));
36967
37150
  const localRepos = /* @__PURE__ */ new Set();
36968
37151
  for (const p of local.projects ?? []) for (const r of p.repos ?? []) {
36969
37152
  const full = (r.includes("/") ? r : `mutmutco/${r}`).toLowerCase();
@@ -37113,7 +37296,7 @@ LIVE apply to ${repo}:
37113
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)");
37114
37297
  const headSha = seedSource.sha;
37115
37298
  const sourceBlob = (await execGitForSeedSource(["rev-parse", `${headSha}:${seedSourcePath(seed)}`])).trim();
37116
- 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;
37117
37300
  for (const rec of plan.records) {
37118
37301
  if (rec.action !== "open-pr") continue;
37119
37302
  const baseBranch = classOf(rec.repo) === "content" ? "main" : "development";
@@ -37138,12 +37321,12 @@ LIVE apply to ${repo}:
37138
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`);
37139
37322
  const desiredContent = desiredByRepo.get(rec.repo);
37140
37323
  if (desiredContent == null) return fail(`bootstrap propagate: no resolved content for ${rec.repo} ${seed.target} \u2014 refusing to write`);
37141
- (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");
37142
37325
  try {
37143
37326
  await gh2(contentPutInputArgs(rec.repo, seed.target, tmp));
37144
37327
  } finally {
37145
37328
  try {
37146
- (0, import_node_fs32.unlinkSync)(tmp);
37329
+ (0, import_node_fs33.unlinkSync)(tmp);
37147
37330
  } catch {
37148
37331
  }
37149
37332
  }
@@ -37212,10 +37395,10 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
37212
37395
  return fail(`bootstrap rollback: ${e.message}`);
37213
37396
  }
37214
37397
  const manifestPath = "skills/bootstrap/seeds/manifest.json";
37215
- 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)`);
37216
37399
  const seedSource = await resolveHubSeedSource(execGitForSeedSource);
37217
37400
  if (!seedSource.ok) return fail(`bootstrap rollback: ${seedSource.reason}`);
37218
- const manifest = loadBootstrapSeeds((0, import_node_fs32.readFileSync)(manifestPath, "utf8"));
37401
+ const manifest = loadBootstrapSeeds((0, import_node_fs33.readFileSync)(manifestPath, "utf8"));
37219
37402
  const propagatable = manifest.seeds.filter(isPropagatableSeed);
37220
37403
  if (!o.target) {
37221
37404
  return fail(`bootstrap rollback: --target <path> is required \u2014 one of:
@@ -37232,10 +37415,10 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
37232
37415
  const enc = (p) => p.split("/").map(encodeURIComponent).join("/");
37233
37416
  let candidates;
37234
37417
  if (o.record) {
37235
- 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`);
37236
37419
  let parsed;
37237
37420
  try {
37238
- parsed = JSON.parse((0, import_node_fs32.readFileSync)(o.record, "utf8"));
37421
+ parsed = JSON.parse((0, import_node_fs33.readFileSync)(o.record, "utf8"));
37239
37422
  } catch (e) {
37240
37423
  return fail(`bootstrap rollback: --record '${o.record}' is not valid JSON: ${e.message}`);
37241
37424
  }
@@ -37313,12 +37496,12 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
37313
37496
  existingSha = void 0;
37314
37497
  }
37315
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`);
37316
- (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");
37317
37500
  try {
37318
37501
  await gh2(contentPutInputArgs(repo, seed.target, tmp));
37319
37502
  } finally {
37320
37503
  try {
37321
- (0, import_node_fs32.unlinkSync)(tmp);
37504
+ (0, import_node_fs33.unlinkSync)(tmp);
37322
37505
  } catch {
37323
37506
  }
37324
37507
  }
@@ -37775,7 +37958,7 @@ async function waitSuiteDev(deps, opts) {
37775
37958
  }
37776
37959
 
37777
37960
  // src/suite-train.ts
37778
- var import_node_fs33 = require("node:fs");
37961
+ var import_node_fs34 = require("node:fs");
37779
37962
  var import_node_path32 = require("node:path");
37780
37963
  var import_node_crypto15 = require("node:crypto");
37781
37964
 
@@ -37862,7 +38045,7 @@ function suiteReleaseTag(rc) {
37862
38045
  function readSuiteCut(path2) {
37863
38046
  let raw;
37864
38047
  try {
37865
- raw = (0, import_node_fs33.readFileSync)(path2, "utf8");
38048
+ raw = (0, import_node_fs34.readFileSync)(path2, "utf8");
37866
38049
  } catch (e) {
37867
38050
  if (e.code === "ENOENT") return void 0;
37868
38051
  throw e;
@@ -37878,11 +38061,11 @@ function readSuiteCut(path2) {
37878
38061
  return record;
37879
38062
  }
37880
38063
  function writeSuiteCut(path2, record) {
37881
- (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 });
37882
38065
  const temp = `${path2}.${(0, import_node_crypto15.randomBytes)(8).toString("hex")}.tmp`;
37883
38066
  try {
37884
- (0, import_node_fs33.writeFileSync)(temp, JSON.stringify(record, null, 2), { flag: "wx" });
37885
- (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);
37886
38069
  } catch (e) {
37887
38070
  throw new Error(`suite cut record write failed at ${path2}: ${e.message}; stop, verify the file before retrying`);
37888
38071
  }
@@ -37931,25 +38114,25 @@ async function suiteMarkAbandoned(deps, ownerGo = false) {
37931
38114
  return tags.map((t) => `${t.repo}@${t.tag}`);
37932
38115
  }
37933
38116
  async function retireFailedLeadRcLedger(deps, ownerGo) {
37934
- if (!(0, import_node_fs33.existsSync)(deps.ledgerPath)) return void 0;
38117
+ if (!(0, import_node_fs34.existsSync)(deps.ledgerPath)) return void 0;
37935
38118
  return withLedgerLock(deps.ledgerPath, async (fence) => {
37936
- const ledger = parseReleaseLedger((0, import_node_fs33.readFileSync)(deps.ledgerPath, "utf8"));
38119
+ const ledger = parseReleaseLedger((0, import_node_fs34.readFileSync)(deps.ledgerPath, "utf8"));
37937
38120
  const states = Object.values(ledger.phases).map((p) => p.state);
37938
38121
  if (ledger.repo !== SUITE_REPO || ledger.lane !== "rcand" || ledger.phases.promotion.state === "complete" || !states.includes("failed")) return void 0;
37939
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`);
37940
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`);
37941
38124
  const archive = (0, import_node_path32.join)((0, import_node_path32.dirname)(deps.ledgerPath), `phases.archive-${ledger.tag}.json`);
37942
- 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`);
37943
38126
  await deps.markAbandoned(SUITE_REPO, ledger.tag, ledger.tagSha);
37944
- await fence(() => (0, import_node_fs33.renameSync)(deps.ledgerPath, archive));
38127
+ await fence(() => (0, import_node_fs34.renameSync)(deps.ledgerPath, archive));
37945
38128
  return `${ledger.tag} (ledger archived to ${archive})`;
37946
38129
  });
37947
38130
  }
37948
38131
  function suiteAbandon(recordPath, ownerGo = false, now = /* @__PURE__ */ new Date()) {
37949
38132
  const record = abandonableCut(recordPath, ownerGo);
37950
38133
  const archive = `${recordPath}.abandoned-${record.leadDevelopment.slice(0, 12)}-${now.toISOString().replace(/[:.]/g, "")}.json`;
37951
- if ((0, import_node_fs33.existsSync)(archive)) throw new Error(`abandoned-cut archive already exists at ${archive}; inspect before abandoning again`);
37952
- (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);
37953
38136
  return { archive, orphanTags: record.members.filter((m) => m.tag).map((m) => `${m.repo}@${m.tag}`) };
37954
38137
  }
37955
38138
  async function suiteRestoreMainPins(deps) {
@@ -38032,12 +38215,12 @@ async function suiteRcandRun(deps, opts) {
38032
38215
  }
38033
38216
  if ((record?.announcement === "sent" || record?.announcement === "skipped") && record.leadReleased) {
38034
38217
  const archive = `${deps.recordPath}.${record.leadRcTag}.json`;
38035
- if ((0, import_node_fs33.existsSync)(archive)) throw new Error(`suite cut archive already exists at ${archive}; inspect before a new cut`);
38036
- (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);
38037
38220
  record = void 0;
38038
38221
  }
38039
38222
  if (record && !record.pinPr && !record.leadRcTag && record.members.every((m) => !m.tag)) {
38040
- (0, import_node_fs33.rmSync)(deps.recordPath, { force: true });
38223
+ (0, import_node_fs34.rmSync)(deps.recordPath, { force: true });
38041
38224
  record = void 0;
38042
38225
  }
38043
38226
  if (!record) {
@@ -38091,7 +38274,7 @@ async function suiteRcandRun(deps, opts) {
38091
38274
  quiet.push(member);
38092
38275
  }
38093
38276
  if (record.members.every((m) => m.carried || quiet.includes(m)) && await deps.contains(SUITE_REPO, record.leadDevelopment, record.leadPreviousRc)) {
38094
- (0, import_node_fs33.rmSync)(deps.recordPath, { force: true });
38277
+ (0, import_node_fs34.rmSync)(deps.recordPath, { force: true });
38095
38278
  throw new Error("nothing to promote: neither MM-Work nor any module has new development commits since its rc; no suite cut started");
38096
38279
  }
38097
38280
  for (const member of quiet) {
@@ -38109,7 +38292,7 @@ async function suiteRcandRun(deps, opts) {
38109
38292
  }
38110
38293
  if (refusals.length) {
38111
38294
  const untouched = record.members.every((m) => !m.tag) && !record.pinPr;
38112
- if (untouched) (0, import_node_fs33.rmSync)(deps.recordPath, { force: true });
38295
+ if (untouched) (0, import_node_fs34.rmSync)(deps.recordPath, { force: true });
38113
38296
  throw new Error(`module rc serving is not ready; ${untouched ? "no suite cut started" : "no new tag was cut"}:
38114
38297
  ${refusals.join("\n")}
38115
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).`);
@@ -38305,7 +38488,7 @@ var hotfixRecordPath = (deps) => (0, import_node_path32.join)((0, import_node_pa
38305
38488
  function readSuiteHotfix(path2) {
38306
38489
  let raw;
38307
38490
  try {
38308
- raw = (0, import_node_fs33.readFileSync)(path2, "utf8");
38491
+ raw = (0, import_node_fs34.readFileSync)(path2, "utf8");
38309
38492
  } catch (e) {
38310
38493
  if (e.code === "ENOENT") return void 0;
38311
38494
  throw e;
@@ -38348,7 +38531,7 @@ async function suiteHotfix(deps, opts) {
38348
38531
  if (completed) record = void 0;
38349
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`);
38350
38533
  if (!record?.tag) await deps.validateHotfixSummary();
38351
- 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`);
38352
38535
  const rec = record ?? { schema: "mmi-suite-hotfix/v1", member: found.id, repo: found.repo, from: opts.from, ...opts.ack?.length ? { ack: opts.ack } : {} };
38353
38536
  const save = () => writeSuiteHotfix(path2, rec);
38354
38537
  save();
@@ -38617,7 +38800,7 @@ async function runRcDataSwitch(deps, opts) {
38617
38800
  // src/suite-train-io.ts
38618
38801
  var import_node_child_process18 = require("node:child_process");
38619
38802
  var import_node_path45 = require("node:path");
38620
- var import_node_fs46 = require("node:fs");
38803
+ var import_node_fs47 = require("node:fs");
38621
38804
  var import_node_path46 = require("node:path");
38622
38805
  init_cli_shared();
38623
38806
 
@@ -40294,7 +40477,7 @@ function checkHotfixCarries(options) {
40294
40477
  }
40295
40478
 
40296
40479
  // src/merge-cleanup.ts
40297
- var import_node_fs35 = require("node:fs");
40480
+ var import_node_fs36 = require("node:fs");
40298
40481
  var import_node_path34 = require("node:path");
40299
40482
  var import_node_os19 = require("node:os");
40300
40483
  init_cli_shared();
@@ -40723,7 +40906,7 @@ function renderPrLandTable(entries) {
40723
40906
 
40724
40907
  // src/test-policy-core.ts
40725
40908
  var import_node_child_process13 = require("node:child_process");
40726
- var import_node_fs34 = require("node:fs");
40909
+ var import_node_fs35 = require("node:fs");
40727
40910
  var import_node_path33 = require("node:path");
40728
40911
 
40729
40912
  // src/test-command-policy-shared.mjs
@@ -41293,7 +41476,7 @@ function loadPolicySource(root, explicitRef, diffBase) {
41293
41476
  }
41294
41477
  function readFileOrNull2(path2) {
41295
41478
  try {
41296
- return (0, import_node_fs34.readFileSync)(path2, "utf8");
41479
+ return (0, import_node_fs35.readFileSync)(path2, "utf8");
41297
41480
  } catch {
41298
41481
  return null;
41299
41482
  }
@@ -41321,10 +41504,10 @@ function classify(changed, policy, present = () => false) {
41321
41504
  const removedProtected = [...removed].filter((p) => protectedBy.has(p)).map((p) => ({ path: p, why: protectedBy.get(p) ?? "" }));
41322
41505
  return { mandatoryHits, untestedHits, testChanges, meaningfulTestChanges, addedTests, removedProtected };
41323
41506
  }
41324
- 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)) {
41325
41508
  return (policy.protected ?? []).map((p) => p.path).filter((p) => !exists((0, import_node_path33.join)(root, p)));
41326
41509
  }
41327
- 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)) {
41328
41511
  const declared = (policy.mandatory ?? []).flatMap((m) => m.satisfiedBy ?? []);
41329
41512
  return [...new Set(declared)].filter((p) => !exists((0, import_node_path33.join)(root, p)));
41330
41513
  }
@@ -41465,7 +41648,7 @@ function runTestPolicy(root, deps = {}) {
41465
41648
  }
41466
41649
  const loaded = deps.policy ? { policy: deps.policy, source: { ref: null, sha: null, path: POLICY_FILE } } : loadPolicySource(root, deps.policyRef, deps.base);
41467
41650
  const { policy, source: policySource } = loaded;
41468
- const exists = deps.exists ?? ((path2) => (0, import_node_fs34.existsSync)(path2));
41651
+ const exists = deps.exists ?? ((path2) => (0, import_node_fs35.existsSync)(path2));
41469
41652
  const counts = { mandatoryCount: (policy.mandatory ?? []).length, protectedCount: (policy.protected ?? []).length };
41470
41653
  const base = deps.changed ? "(injected)" : deps.policyRef ? resolveHotfixBase(root) : resolveBase(root, deps.base);
41471
41654
  const refusal = deps.changed ? null : untrustworthyRange(root, base);
@@ -41763,13 +41946,13 @@ function resolveSquashMergeBodyText(commits, allowedClosing, cwd) {
41763
41946
  return rewritten === base ? null : rewritten;
41764
41947
  }
41765
41948
  function writeSquashBodyFile(body) {
41766
- 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-"));
41767
41950
  const path2 = (0, import_node_path34.join)(dir, "body.txt");
41768
- (0, import_node_fs35.writeFileSync)(path2, body.endsWith("\n") ? body : `${body}
41951
+ (0, import_node_fs36.writeFileSync)(path2, body.endsWith("\n") ? body : `${body}
41769
41952
  `, "utf8");
41770
41953
  return { path: path2, cleanup: () => {
41771
41954
  try {
41772
- (0, import_node_fs35.rmSync)(dir, { recursive: true, force: true });
41955
+ (0, import_node_fs36.rmSync)(dir, { recursive: true, force: true });
41773
41956
  } catch {
41774
41957
  }
41775
41958
  } };
@@ -42058,7 +42241,7 @@ function prMergeQueueLine(result) {
42058
42241
  }
42059
42242
 
42060
42243
  // src/project-info-sync.ts
42061
- var import_node_fs36 = require("node:fs");
42244
+ var import_node_fs37 = require("node:fs");
42062
42245
  var import_node_path35 = require("node:path");
42063
42246
  var UPDATE_PROJECT_INFO = `mutation($projectId: ID!, $shortDescription: String!, $readme: String!) {
42064
42247
  updateProjectV2(input: { projectId: $projectId, shortDescription: $shortDescription, readme: $readme }) {
@@ -42107,13 +42290,13 @@ function sharedName(entries, fallback) {
42107
42290
  function buildProjectInfoSyncPlan(targetRepo2, project2, projects, repoRoot2) {
42108
42291
  if (!project2.projectId) throw new Error(`org project sync-info: ${targetRepo2} registry META has no projectId`);
42109
42292
  const readmePath = (0, import_node_path35.join)(repoRoot2, "README.md");
42110
- 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`);
42111
42294
  const entries = entriesFor(project2, projects);
42112
42295
  const memberRepos = [...new Set(entries.flatMap((entry) => entry.repos ?? []))].filter((repo) => /^[^/]+\/[^/]+$/.test(repo)).sort((a, b) => a.localeCompare(b));
42113
42296
  const projectName = sharedName(entries, project2.name?.trim() || targetRepo2.split("/").pop() || targetRepo2);
42114
42297
  if (!memberRepos.length) throw new Error(`org project sync-info: project ${projectName} has no registered member repos`);
42115
42298
  const entryNames = entries.map((entry) => entry.name?.trim()).filter((name) => Boolean(name));
42116
- 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)}.`;
42117
42300
  const lines2 = [
42118
42301
  `# ${projectName}`,
42119
42302
  "",
@@ -42132,8 +42315,8 @@ function buildProjectInfoSyncPlan(targetRepo2, project2, projects, repoRoot2) {
42132
42315
  const targetBase = `https://github.com/${targetRepo2}`;
42133
42316
  const targetBranch = branchFor(targetRepo2, projects);
42134
42317
  const orgDocs = [
42135
- (0, import_node_fs36.existsSync)((0, import_node_path35.join)(repoRoot2, "architecture.md")) ? `- [Hub architecture](${targetBase}/blob/${targetBranch}/architecture.md)` : "",
42136
- (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)` : ""
42137
42320
  ].filter(Boolean);
42138
42321
  if (orgDocs.length) lines2.push("", "## Organisation docs", "", ...orgDocs);
42139
42322
  return { projectId: project2.projectId, projectName, targetRepo: targetRepo2, memberRepos, shortDescription, readme: `${lines2.join("\n")}
@@ -42155,7 +42338,7 @@ async function syncProjectInfo(plan, client, apply) {
42155
42338
  }
42156
42339
 
42157
42340
  // src/train-commands.ts
42158
- var import_node_fs37 = require("node:fs");
42341
+ var import_node_fs38 = require("node:fs");
42159
42342
  var import_node_path36 = require("node:path");
42160
42343
  init_cli_shared();
42161
42344
  init_clean_exit();
@@ -42171,7 +42354,7 @@ function resolveReleaseBumpIntent(raw) {
42171
42354
  }
42172
42355
  function readRepoVersion() {
42173
42356
  try {
42174
- 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;
42175
42358
  } catch {
42176
42359
  return void 0;
42177
42360
  }
@@ -42536,7 +42719,7 @@ async function openSuitePinPr(deps, input) {
42536
42719
 
42537
42720
  // src/command-register-collaboration.ts
42538
42721
  var import_node_child_process17 = require("node:child_process");
42539
- var import_node_fs45 = require("node:fs");
42722
+ var import_node_fs46 = require("node:fs");
42540
42723
  var import_promises8 = require("node:fs/promises");
42541
42724
  init_clean_exit();
42542
42725
  init_cli_shared();
@@ -42670,7 +42853,7 @@ init_github_client();
42670
42853
  init_github_quota();
42671
42854
 
42672
42855
  // src/issue-commands.ts
42673
- var import_node_fs38 = require("node:fs");
42856
+ var import_node_fs39 = require("node:fs");
42674
42857
  var import_node_crypto16 = require("node:crypto");
42675
42858
  init_cli_shared();
42676
42859
  init_clean_exit();
@@ -42863,7 +43046,7 @@ async function editIssue(client, options, deps = {}) {
42863
43046
  const url = `https://github.com/${repo}/issues/${parsed.number}`;
42864
43047
  const patch = {};
42865
43048
  let bodyChanged = false;
42866
- 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("") };
42867
43050
  if (options.titleFile !== void 0) {
42868
43051
  patch.title = await resolveIssueTitle({ title: options.title, titleFile: options.titleFile }, textDeps());
42869
43052
  } else if (options.title !== void 0) {
@@ -43526,7 +43709,7 @@ function extendCreateCommand(issue, batchAttach) {
43526
43709
  if (opts.batch) {
43527
43710
  let specs;
43528
43711
  try {
43529
- const raw = (0, import_node_fs38.readFileSync)(opts.batch, "utf8");
43712
+ const raw = (0, import_node_fs39.readFileSync)(opts.batch, "utf8");
43530
43713
  specs = JSON.parse(raw);
43531
43714
  if (!Array.isArray(specs)) {
43532
43715
  const top = specs === null ? "null" : typeof specs === "object" ? `an object with keys: ${Object.keys(specs).join(", ") || "(none)"}` : `a ${typeof specs}`;
@@ -43603,7 +43786,7 @@ ${lines2}`, {
43603
43786
  }
43604
43787
 
43605
43788
  // src/post-merge-recon.ts
43606
- var import_node_fs39 = require("node:fs");
43789
+ var import_node_fs40 = require("node:fs");
43607
43790
  var import_node_path38 = require("node:path");
43608
43791
 
43609
43792
  // src/cross-repo-filing-issue.ts
@@ -43773,16 +43956,16 @@ function buildPostMergeReconRecovery(input) {
43773
43956
  }
43774
43957
  function writePostMergeReconRecovery(cwd, recovery) {
43775
43958
  const path2 = postMergeReconStatePath(cwd, recovery.repo, recovery.pr);
43776
- (0, import_node_fs39.mkdirSync)((0, import_node_path38.dirname)(path2), { recursive: true });
43777
- (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)}
43778
43961
  `, "utf8");
43779
43962
  return path2;
43780
43963
  }
43781
43964
  function clearPostMergeReconRecovery(cwd, repo, pr) {
43782
43965
  const path2 = postMergeReconStatePath(cwd, repo, pr);
43783
- if (!(0, import_node_fs39.existsSync)(path2)) return;
43966
+ if (!(0, import_node_fs40.existsSync)(path2)) return;
43784
43967
  try {
43785
- (0, import_node_fs39.unlinkSync)(path2);
43968
+ (0, import_node_fs40.unlinkSync)(path2);
43786
43969
  } catch {
43787
43970
  }
43788
43971
  }
@@ -44258,7 +44441,7 @@ function registerPrLifecycleCommands(program3) {
44258
44441
 
44259
44442
  // src/review-verdict.ts
44260
44443
  var import_node_child_process14 = require("node:child_process");
44261
- var import_node_fs40 = require("node:fs");
44444
+ var import_node_fs41 = require("node:fs");
44262
44445
  var import_node_os21 = require("node:os");
44263
44446
  var import_node_path39 = require("node:path");
44264
44447
  init_cli_shared();
@@ -44425,15 +44608,15 @@ async function readPrIssueComments(number, repo) {
44425
44608
  return comments;
44426
44609
  }
44427
44610
  async function postPrCommentFromFile(number, repo, body) {
44428
- 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-"));
44429
44612
  const path2 = (0, import_node_path39.join)(dir, "body.md");
44430
44613
  try {
44431
- (0, import_node_fs40.writeFileSync)(path2, body, "utf8");
44614
+ (0, import_node_fs41.writeFileSync)(path2, body, "utf8");
44432
44615
  const { stdout } = await execFileP("gh", ["pr", "comment", number, "--repo", repo, "--body-file", path2], { timeout: GH_MUTATION_TIMEOUT_MS });
44433
44616
  return stdout.trim();
44434
44617
  } finally {
44435
44618
  try {
44436
- (0, import_node_fs40.rmSync)(dir, { recursive: true, force: true });
44619
+ (0, import_node_fs41.rmSync)(dir, { recursive: true, force: true });
44437
44620
  } catch {
44438
44621
  }
44439
44622
  }
@@ -44667,17 +44850,17 @@ async function prCreateClaimRefusal(body, repoOption, deps = {}) {
44667
44850
  }
44668
44851
 
44669
44852
  // src/worktree-residue-sweep.ts
44670
- var import_node_fs44 = require("node:fs");
44853
+ var import_node_fs45 = require("node:fs");
44671
44854
  var import_node_path43 = require("node:path");
44672
44855
 
44673
44856
  // src/worktree-merge-cleanup.ts
44674
- var import_node_fs43 = require("node:fs");
44857
+ var import_node_fs44 = require("node:fs");
44675
44858
  var import_node_path42 = require("node:path");
44676
44859
  init_cli_shared();
44677
44860
 
44678
44861
  // src/stage-runner.ts
44679
44862
  var import_node_child_process16 = require("node:child_process");
44680
- var import_node_fs42 = require("node:fs");
44863
+ var import_node_fs43 = require("node:fs");
44681
44864
  var import_node_path41 = require("node:path");
44682
44865
  var import_node_net = require("node:net");
44683
44866
  var import_node_util5 = require("node:util");
@@ -44688,7 +44871,7 @@ function normalizeEol2(s) {
44688
44871
  }
44689
44872
 
44690
44873
  // src/env-detection.ts
44691
- var import_node_fs41 = require("node:fs");
44874
+ var import_node_fs42 = require("node:fs");
44692
44875
  var import_node_path40 = require("node:path");
44693
44876
  var SKIPPED_DIRS = /* @__PURE__ */ new Set([".git", "node_modules", "dist", ".jerv", ".pi", ".venv", "venv"]);
44694
44877
  function isEnvBaseName(name) {
@@ -44699,7 +44882,7 @@ function findEnvFiles(root) {
44699
44882
  const walk2 = (dir, rel) => {
44700
44883
  let entries;
44701
44884
  try {
44702
- entries = (0, import_node_fs41.readdirSync)(dir, { withFileTypes: true });
44885
+ entries = (0, import_node_fs42.readdirSync)(dir, { withFileTypes: true });
44703
44886
  } catch {
44704
44887
  return;
44705
44888
  }
@@ -44713,7 +44896,7 @@ function findEnvFiles(root) {
44713
44896
  if (isEnvBaseName(entry.name)) {
44714
44897
  let isDir = false;
44715
44898
  try {
44716
- 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();
44717
44900
  } catch {
44718
44901
  }
44719
44902
  if (!isDir) found.push(relPath);
@@ -44852,12 +45035,12 @@ var DOCKER_TIMEOUT_MS = 15e3;
44852
45035
  function stageBash() {
44853
45036
  if (process.platform !== "win32") return "bash";
44854
45037
  const configured = process.env.SHELL;
44855
- 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;
44856
45039
  const candidates = [
44857
45040
  (0, import_node_path41.join)(process.env.ProgramFiles || "C:\\Program Files", "Git", "bin", "bash.exe"),
44858
45041
  ...process.env.LOCALAPPDATA ? [(0, import_node_path41.join)(process.env.LOCALAPPDATA, "Programs", "Git", "bin", "bash.exe")] : []
44859
45042
  ];
44860
- const bash = candidates.find((path2) => (0, import_node_fs42.existsSync)(path2));
45043
+ const bash = candidates.find((path2) => (0, import_node_fs43.existsSync)(path2));
44861
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.");
44862
45045
  return bash;
44863
45046
  }
@@ -45213,7 +45396,7 @@ function stageProcessEnv(stagePort, extraEnv) {
45213
45396
  function composeResolvesPort(cwd) {
45214
45397
  if (process.env.PORT) return true;
45215
45398
  const envFile = (0, import_node_path41.join)(cwd, ".env");
45216
- 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");
45217
45400
  }
45218
45401
  function stageComposeEnv(config, stagePort, vaultEnvMerge, cwd) {
45219
45402
  const composeProject = config.env?.COMPOSE_PROJECT_NAME ?? vaultEnvMerge?.COMPOSE_PROJECT_NAME ?? stageComposeProjectName(cwd);
@@ -45228,13 +45411,13 @@ function stageComposeEnv(config, stagePort, vaultEnvMerge, cwd) {
45228
45411
  function stageComposeFiles(cwd) {
45229
45412
  const files = ["docker-compose.yml"];
45230
45413
  for (const conventional of ["docker-compose.override.yml", "docker-compose.override.yaml"]) {
45231
- 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);
45232
45415
  }
45233
45416
  return [...files, RUNTIME_ENV_OVERRIDE_RELPATH];
45234
45417
  }
45235
45418
  async function prepareRuntimeEnvPassthrough(cwd, composeEnv, vaultEnvMerge) {
45236
45419
  const keys = Object.keys(vaultEnvMerge ?? {});
45237
- 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 {};
45238
45421
  let configJson;
45239
45422
  try {
45240
45423
  const { stdout } = await execFileP3("docker", ["compose", "config", "--format", "json"], {
@@ -45251,20 +45434,20 @@ async function prepareRuntimeEnvPassthrough(cwd, composeEnv, vaultEnvMerge) {
45251
45434
  const body = renderRuntimeEnvOverride(runtimeEnvMarkedServices(configJson), keys, runtimeEnvExcludes(configJson), runtimeEnvSelects(configJson));
45252
45435
  if (!body) return {};
45253
45436
  const overridePath = (0, import_node_path41.join)(cwd, RUNTIME_ENV_OVERRIDE_RELPATH);
45254
- (0, import_node_fs42.mkdirSync)((0, import_node_path41.join)(cwd, "tmp", "stage"), { recursive: true });
45255
- (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");
45256
45439
  return stageComposeFileEnv(stageComposeFiles(cwd));
45257
45440
  }
45258
45441
  async function ensureStageRuntimeEnv(config, opts, cwd) {
45259
45442
  if (!config.ensureEnv) return;
45260
45443
  const target = (0, import_node_path41.join)(cwd, config.ensureEnv.target);
45261
45444
  const example = (0, import_node_path41.join)(cwd, config.ensureEnv.example);
45262
- if (!(0, import_node_fs42.existsSync)(target) && (0, import_node_fs42.existsSync)(example)) {
45263
- (0, import_node_fs42.copyFileSync)(example, target);
45264
- } else if ((0, import_node_fs42.existsSync)(target) && (0, import_node_fs42.existsSync)(example)) {
45265
- const stale = detectStaleEnvFile((0, import_node_fs42.readFileSync)(example, "utf8"), (0, import_node_fs42.readFileSync)(target, "utf8"), {
45266
- exampleMtimeMs: (0, import_node_fs42.statSync)(example).mtimeMs,
45267
- 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
45268
45451
  });
45269
45452
  if (stale) {
45270
45453
  const msg = `stale ${config.ensureEnv.target} (${stale}) \u2014 delete it or refresh from ${config.ensureEnv.example} before re-running /stage`;
@@ -45272,8 +45455,8 @@ async function ensureStageRuntimeEnv(config, opts, cwd) {
45272
45455
  console.error(`mmi-cli stage: ${msg} (allowed via --allow-stale-env)`);
45273
45456
  }
45274
45457
  }
45275
- if (opts.vaultEnvMerge && Object.keys(opts.vaultEnvMerge).length && (0, import_node_fs42.existsSync)(target)) {
45276
- (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");
45277
45460
  }
45278
45461
  }
45279
45462
  async function gitText(cwd, args) {
@@ -45303,20 +45486,20 @@ async function resolveGlobalStatePath(cwd, explicit) {
45303
45486
  return void 0;
45304
45487
  }
45305
45488
  function readState(path2) {
45306
- if (!(0, import_node_fs42.existsSync)(path2)) return null;
45489
+ if (!(0, import_node_fs43.existsSync)(path2)) return null;
45307
45490
  try {
45308
- return JSON.parse((0, import_node_fs42.readFileSync)(path2, "utf8"));
45491
+ return JSON.parse((0, import_node_fs43.readFileSync)(path2, "utf8"));
45309
45492
  } catch {
45310
45493
  return null;
45311
45494
  }
45312
45495
  }
45313
45496
  function mkdirFor(path2) {
45314
45497
  const dir = path2.slice(0, Math.max(path2.lastIndexOf("/"), path2.lastIndexOf("\\")));
45315
- (0, import_node_fs42.mkdirSync)(dir, { recursive: true });
45498
+ (0, import_node_fs43.mkdirSync)(dir, { recursive: true });
45316
45499
  }
45317
45500
  function writeState(path2, state) {
45318
45501
  mkdirFor(path2);
45319
- (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");
45320
45503
  }
45321
45504
  function writeStagePortReservation(port, cwd, statePath, globalStatePath, now) {
45322
45505
  const reservation = {
@@ -45345,7 +45528,7 @@ async function cleanupStageState(state, paths, timeoutMs, fallbackCwd, currentEn
45345
45528
  );
45346
45529
  }
45347
45530
  for (const path2 of [...new Set(paths.filter((p) => Boolean(p)))]) {
45348
- (0, import_node_fs42.rmSync)(path2, { force: true });
45531
+ (0, import_node_fs43.rmSync)(path2, { force: true });
45349
45532
  }
45350
45533
  }
45351
45534
  async function killTree(pid) {
@@ -45592,8 +45775,8 @@ async function runStage(config = {}, opts = {}) {
45592
45775
  });
45593
45776
  }
45594
45777
  } catch (e) {
45595
- (0, import_node_fs42.rmSync)(statePath, { force: true });
45596
- 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 });
45597
45780
  throw e;
45598
45781
  }
45599
45782
  const started = await startStage(config, {
@@ -45614,7 +45797,7 @@ function normPath2(p) {
45614
45797
  function unlinkNodeModulesJunction(wtPath) {
45615
45798
  const nm = (0, import_node_path42.join)(wtPath, "node_modules");
45616
45799
  try {
45617
- 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);
45618
45801
  return { ok: true };
45619
45802
  } catch (e) {
45620
45803
  if (e.code === "ENOENT") return { ok: true };
@@ -45625,8 +45808,8 @@ function defaultSleep2(ms) {
45625
45808
  return new Promise((resolve8) => setTimeout(resolve8, ms));
45626
45809
  }
45627
45810
  async function removeResidueDirectory(wtPath, options = {}) {
45628
- const { sleep: sleep2 = defaultSleep2, removeEmptyDir = import_node_fs43.rmdirSync, exists = import_node_fs43.existsSync } = options;
45629
- 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 }));
45630
45813
  const junction = unlinkNodeModulesJunction(wtPath);
45631
45814
  if (!junction.ok) return junction;
45632
45815
  try {
@@ -45752,21 +45935,21 @@ async function listNestedIgnoredNodeModules(wtPath, execGit) {
45752
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)));
45753
45936
  }
45754
45937
  function safeRemoveTree(path2) {
45755
- const stat4 = (0, import_node_fs43.lstatSync)(path2);
45938
+ const stat4 = (0, import_node_fs44.lstatSync)(path2);
45756
45939
  if (stat4.isSymbolicLink()) {
45757
45940
  try {
45758
- (0, import_node_fs43.rmdirSync)(path2);
45941
+ (0, import_node_fs44.rmdirSync)(path2);
45759
45942
  } catch {
45760
- (0, import_node_fs43.unlinkSync)(path2);
45943
+ (0, import_node_fs44.unlinkSync)(path2);
45761
45944
  }
45762
45945
  return;
45763
45946
  }
45764
45947
  if (stat4.isDirectory()) {
45765
- for (const entry of (0, import_node_fs43.readdirSync)(path2)) safeRemoveTree((0, import_node_path42.join)(path2, entry));
45766
- (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);
45767
45950
  return;
45768
45951
  }
45769
- (0, import_node_fs43.unlinkSync)(path2);
45952
+ (0, import_node_fs44.unlinkSync)(path2);
45770
45953
  }
45771
45954
  async function removeWorktreeNodeModules(wtPath) {
45772
45955
  try {
@@ -45782,7 +45965,7 @@ function errorMessage(e) {
45782
45965
  }
45783
45966
  function resolvedOrRaw(path2) {
45784
45967
  try {
45785
- return normPath2((0, import_node_fs43.realpathSync)(path2));
45968
+ return normPath2((0, import_node_fs44.realpathSync)(path2));
45786
45969
  } catch {
45787
45970
  return normPath2(path2);
45788
45971
  }
@@ -45790,10 +45973,10 @@ function resolvedOrRaw(path2) {
45790
45973
  function unlinkEscapingReparsePoints(root, primaryRoot) {
45791
45974
  let realRoot;
45792
45975
  try {
45793
- if ((0, import_node_fs43.lstatSync)(root).isSymbolicLink()) {
45976
+ if ((0, import_node_fs44.lstatSync)(root).isSymbolicLink()) {
45794
45977
  return { ok: false, error: `delete root ${normPath2(root)} is a reparse point resolving to ${resolvedOrRaw(root)}` };
45795
45978
  }
45796
- realRoot = normPath2((0, import_node_fs43.realpathSync)(root));
45979
+ realRoot = normPath2((0, import_node_fs44.realpathSync)(root));
45797
45980
  } catch (e) {
45798
45981
  if (e.code === "ENOENT") return { ok: true, unlinked: [] };
45799
45982
  return { ok: false, error: `cannot resolve delete root ${normPath2(root)}: ${errorMessage(e)}` };
@@ -45809,7 +45992,7 @@ function unlinkEscapingReparsePoints(root, primaryRoot) {
45809
45992
  const dir = stack.pop();
45810
45993
  let entries;
45811
45994
  try {
45812
- entries = (0, import_node_fs43.readdirSync)(dir, { withFileTypes: true });
45995
+ entries = (0, import_node_fs44.readdirSync)(dir, { withFileTypes: true });
45813
45996
  } catch (e) {
45814
45997
  if (e.code === "ENOENT") continue;
45815
45998
  return { ok: false, error: `cannot scan ${normPath2(dir)} for reparse points: ${errorMessage(e)}` };
@@ -45819,7 +46002,7 @@ function unlinkEscapingReparsePoints(root, primaryRoot) {
45819
46002
  if (entry.isSymbolicLink()) {
45820
46003
  let target = "";
45821
46004
  try {
45822
- target = normPath2((0, import_node_fs43.realpathSync)(child2));
46005
+ target = normPath2((0, import_node_fs44.realpathSync)(child2));
45823
46006
  } catch {
45824
46007
  target = "";
45825
46008
  }
@@ -46002,7 +46185,7 @@ async function cleanupPrMergeLocalBranch(branch, options) {
46002
46185
  return report;
46003
46186
  }
46004
46187
  const execGit = options.execGit ?? (async (args) => (await execFileP("git", args, { timeout: GIT_TIMEOUT_MS })).stdout);
46005
- const pathExists = options.pathExists ?? import_node_fs43.existsSync;
46188
+ const pathExists = options.pathExists ?? import_node_fs44.existsSync;
46006
46189
  let afterWorktrees = [];
46007
46190
  try {
46008
46191
  afterWorktrees = parseGitWorktreePorcelain(await execGit(["worktree", "list", "--porcelain"]));
@@ -46289,7 +46472,7 @@ function residueLedgerPath(gitCommonDir) {
46289
46472
  }
46290
46473
  function readPaths(file, deps) {
46291
46474
  try {
46292
- 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));
46293
46476
  return Array.isArray(parsed) ? parsed.filter((p) => typeof p === "string") : [];
46294
46477
  } catch {
46295
46478
  return [];
@@ -46298,8 +46481,8 @@ function readPaths(file, deps) {
46298
46481
  function writePaths(file, paths, deps) {
46299
46482
  try {
46300
46483
  const write = deps.writeLedger ?? ((f, t) => {
46301
- (0, import_node_fs44.mkdirSync)((0, import_node_path43.dirname)(f), { recursive: true });
46302
- (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");
46303
46486
  });
46304
46487
  write(file, `${JSON.stringify([...new Set(paths)], null, 1)}
46305
46488
  `);
@@ -46313,17 +46496,17 @@ function recordResidue(gitCommonDir, path2, deps = {}) {
46313
46496
  writePaths(file, paths, deps);
46314
46497
  }
46315
46498
  async function sweepWorktreeResidue(gitCommonDir, registered, deps = {}) {
46316
- const exists = deps.exists ?? import_node_fs44.existsSync;
46317
- 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));
46318
46501
  const isDir = deps.isDir ?? ((p) => {
46319
46502
  try {
46320
- return (0, import_node_fs44.statSync)(p).isDirectory();
46503
+ return (0, import_node_fs45.statSync)(p).isDirectory();
46321
46504
  } catch {
46322
46505
  return false;
46323
46506
  }
46324
46507
  });
46325
46508
  const removeRecorded = deps.removeRecorded ?? ((p) => removeResidueDirectory(p));
46326
- const removeEmpty = deps.removeEmpty ?? ((p) => (0, import_node_fs44.rmdirSync)(p));
46509
+ const removeEmpty = deps.removeEmpty ?? ((p) => (0, import_node_fs45.rmdirSync)(p));
46327
46510
  const report = { swept: [], kept: [], dropped: [], emptyRemoved: [], unrecorded: [] };
46328
46511
  const live = new Set(registered.map(norm));
46329
46512
  const primary = registered[0] ? norm(registered[0]) : void 0;
@@ -46403,8 +46586,8 @@ function argvWantsJson2() {
46403
46586
  function hubRoot() {
46404
46587
  const fromPkg = (0, import_node_path44.join)(__dirname, "..", "..");
46405
46588
  const marker = "skills/bootstrap/seeds/manifest.json";
46406
- if ((0, import_node_fs45.existsSync)((0, import_node_path44.join)(fromPkg, marker))) return fromPkg;
46407
- 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();
46408
46591
  return null;
46409
46592
  }
46410
46593
  function ciAuditDeps() {
@@ -46417,7 +46600,7 @@ function ciAuditDeps() {
46417
46600
  readSeedFile: (path2) => {
46418
46601
  if (!root) return null;
46419
46602
  const fullPath = (0, import_node_path44.join)(root, path2);
46420
- 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;
46421
46604
  }
46422
46605
  };
46423
46606
  }
@@ -47181,10 +47364,10 @@ ${list}`);
47181
47364
  });
47182
47365
  async function listCiWorkflowPaths(cwd = process.cwd()) {
47183
47366
  const wfDir = (0, import_node_path44.join)(cwd, ".github", "workflows");
47184
- if (!(0, import_node_fs45.existsSync)(wfDir)) return [];
47185
- 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) => {
47186
47369
  try {
47187
- 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"));
47188
47371
  } catch {
47189
47372
  return true;
47190
47373
  }
@@ -47389,7 +47572,7 @@ ${list}`);
47389
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) => {
47390
47573
  if (!isReviewVerdict(o.verdict)) return fail(`pr review-verdict: --verdict must be one of ${REVIEW_VERDICTS.join("|")} (got ${o.verdict})`);
47391
47574
  const verdict = o.verdict;
47392
- 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;
47393
47576
  let patch;
47394
47577
  let head;
47395
47578
  try {
@@ -47645,7 +47828,7 @@ ${list}`);
47645
47828
  const cleanupMerged = async (r) => {
47646
47829
  if (opts.preserveWorktree) return "cleanup skipped (--preserve-worktree)";
47647
47830
  const ran = await execFileP(process.execPath, [process.argv[1], ...canonicalArgvFor(["pr", "merge", r.pr, "--repo", r.repo])], {
47648
- cwd: (0, import_node_fs45.existsSync)(cwd0) ? cwd0 : primaryRoot0,
47831
+ cwd: (0, import_node_fs46.existsSync)(cwd0) ? cwd0 : primaryRoot0,
47649
47832
  timeout: GH_MUTATION_TIMEOUT_MS * 3
47650
47833
  }).then((x) => ({ stdout: x.stdout, stderr: x.stderr }), (e) => ({ stdout: e.stdout ?? "", stderr: e.stderr ?? "" }));
47651
47834
  const json = ran.stdout.split("\n").reverse().find((l) => l.startsWith("{"));
@@ -47715,7 +47898,7 @@ ${list}`);
47715
47898
  const mergeSquashBody = squashBodyTextForMerge(
47716
47899
  closingGuardInput,
47717
47900
  method === "--squash",
47718
- 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
47719
47902
  );
47720
47903
  if (!o.squashBodyFile) warnSquashBodyClosingStrip("pr merge", closingGuardInput, mergeSquashBody);
47721
47904
  const closingGuardVerdict = evaluateClosingGuard(closingGuardInput, {
@@ -47866,7 +48049,7 @@ ${list}`);
47866
48049
  }
47867
48050
  if (!repoForPostCleanup) throw e;
47868
48051
  console.warn(`pr merge: gh GraphQL rate-limited \u2014 merging PR #${number} via REST PUT instead (#4588).`);
47869
- 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;
47870
48053
  await defaultGitHubClient().rest("PUT", `repos/${repoForPostCleanup}/pulls/${number}/merge`, {
47871
48054
  body: { merge_method: method.slice(2), ...commitMessage ? { commit_message: commitMessage } : {} },
47872
48055
  timeoutMs: GH_MUTATION_TIMEOUT_MS
@@ -47999,7 +48182,7 @@ ${list}`);
47999
48182
  preserveWorktree: o.preserveWorktree,
48000
48183
  gcAcknowledged: o.gc,
48001
48184
  expectedHeadOid: headRefOid,
48002
- pathExists: (p) => (0, import_node_fs45.existsSync)(p),
48185
+ pathExists: (p) => (0, import_node_fs46.existsSync)(p),
48003
48186
  // #5899: pin cleanup git calls to the main checkout — the task worktree this process may be
48004
48187
  // standing in is removed mid-cleanup, so a cwd-relative invocation fails with
48005
48188
  // 'fatal: not a git repository' and leaves a spurious partial-cleanup exit.
@@ -49299,11 +49482,11 @@ function suiteTrainIo(root, summaryFile, memberSummaryFiles = {}, summaryFileTr,
49299
49482
  const checkout = async (repo) => {
49300
49483
  if (repo === SUITE_REPO) return root;
49301
49484
  const target = (0, import_node_path46.join)(base, repo.split("/")[1]);
49302
- if (!(0, import_node_fs46.existsSync)(target)) {
49303
- (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 });
49304
49487
  await exec("git", ["clone", "--quiet", "--branch", "development", `https://github.com/${repo}.git`, target], root, WATCH_TIMEOUT);
49305
49488
  }
49306
- 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`);
49307
49490
  const origin = await exec("git", ["remote", "get-url", "origin"], target);
49308
49491
  if (!origin.toLowerCase().endsWith(`/${repo.toLowerCase()}.git`) && !origin.toLowerCase().endsWith(`/${repo.toLowerCase()}`))
49309
49492
  throw new Error(`${repo}: suite checkout origin mismatch at ${target}; stop`);
@@ -49610,9 +49793,9 @@ function suiteTrainIo(root, summaryFile, memberSummaryFiles = {}, summaryFileTr,
49610
49793
  const body = await gh(["release", "view", leadTag, "--repo", SUITE_REPO, "--json", "body", "--jq", ".body"]);
49611
49794
  if (parseSuiteMapping(body)) return;
49612
49795
  const dir = suiteStateDir(root);
49613
- (0, import_node_fs46.mkdirSync)(dir, { recursive: true });
49796
+ (0, import_node_fs47.mkdirSync)(dir, { recursive: true });
49614
49797
  const file = (0, import_node_path46.join)(dir, `notes-${leadTag}.md`);
49615
- (0, import_node_fs46.writeFileSync)(file, `${body}
49798
+ (0, import_node_fs47.writeFileSync)(file, `${body}
49616
49799
 
49617
49800
  ${suiteMappingBlock(leadTag, mapping)}`);
49618
49801
  await gh(["release", "edit", leadTag, "--repo", SUITE_REPO, "--notes-file", file]);
@@ -49653,7 +49836,7 @@ ${suiteMappingBlock(leadTag, mapping)}`);
49653
49836
 
49654
49837
  // src/suite-commands.ts
49655
49838
  init_cli_shared();
49656
- var import_node_fs47 = require("node:fs");
49839
+ var import_node_fs48 = require("node:fs");
49657
49840
  function parseMemberSummaryFiles(entries) {
49658
49841
  const memberSummaryFiles = {};
49659
49842
  for (const entry of entries) {
@@ -49747,7 +49930,7 @@ function registerSuiteCommands(program3) {
49747
49930
  try {
49748
49931
  const io = suiteTrainIo(root);
49749
49932
  retired = await retireFailedLeadRcLedger({ ledgerPath: releaseLedgerPath(root), rcHead: () => io.head(SUITE_REPO, "rc").then((h) => h ?? void 0), markAbandoned: io.markAbandoned }, o.ownerGo === true);
49750
- if (retired && !(0, import_node_fs47.existsSync)(io.recordPath)) {
49933
+ if (retired && !(0, import_node_fs48.existsSync)(io.recordPath)) {
49751
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)`);
49752
49935
  return;
49753
49936
  }
@@ -49936,7 +50119,7 @@ function suiteStatusDeps(github, registry2) {
49936
50119
 
49937
50120
  // src/packages-adopt-export.ts
49938
50121
  var import_node_child_process19 = require("node:child_process");
49939
- var import_node_fs48 = require("node:fs");
50122
+ var import_node_fs49 = require("node:fs");
49940
50123
  var import_node_os22 = require("node:os");
49941
50124
  var import_node_path47 = require("node:path");
49942
50125
  var import_node_util6 = require("node:util");
@@ -50560,36 +50743,36 @@ async function adoptExport(opts, deps) {
50560
50743
  if (!/^sha256:[0-9a-f]{64}$/.test(opts.digest)) throw new Error("--digest must be sha256:<64 hex>, from the export run summary");
50561
50744
  const packagePath = (0, import_node_path47.join)(opts.dir, "package.json");
50562
50745
  const lockPath = (0, import_node_path47.join)(opts.dir, "package-lock.json");
50563
- const packageText = (0, import_node_fs48.readFileSync)(packagePath, "utf8");
50564
- const lockText = (0, import_node_fs48.readFileSync)(lockPath, "utf8");
50565
- 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-"));
50566
50749
  try {
50567
50750
  const run = JSON.parse((await deps.ghApi(`repos/${EXPORT_REPO}/actions/runs/${opts.run}`)).toString("utf8"));
50568
- (0, import_node_fs48.writeFileSync)((0, import_node_path47.join)(work, "expected.json"), JSON.stringify(expectedFromRun(run, opts)));
50569
- (0, import_node_fs48.writeFileSync)((0, import_node_path47.join)(work, "provider.json"), await deps.ghApi(`repos/${EXPORT_REPO}/actions/artifacts/${opts.artifact}`));
50570
- (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`));
50571
50754
  const script = (0, import_node_path47.join)(work, "package_export.py");
50572
- (0, import_node_fs48.writeFileSync)(script, package_export_default);
50755
+ (0, import_node_fs49.writeFileSync)(script, package_export_default);
50573
50756
  await deps.python(script, ["verify", work, opts.ds, opts.screens]);
50574
50757
  const verified = (0, import_node_path47.join)(work, "verified");
50575
- 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"))]));
50576
50759
  const plan = planAdoption(packageText, lockText, metadata);
50577
50760
  for (const { name } of plan.result.adopted) {
50578
50761
  const short3 = PACKAGES.find((p) => p.name === name).short;
50579
50762
  await deps.npm(["cache", "add", (0, import_node_path47.join)(verified, `${short3}.tgz`)], opts.dir);
50580
50763
  }
50581
- (0, import_node_fs48.writeFileSync)(packagePath, plan.packageText);
50582
- (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);
50583
50766
  try {
50584
50767
  await deps.npm(["ci", "--offline", "--ignore-scripts", "--no-audit", "--no-fund"], opts.dir);
50585
50768
  } catch (error) {
50586
- (0, import_node_fs48.writeFileSync)(packagePath, packageText);
50587
- (0, import_node_fs48.writeFileSync)(lockPath, lockText);
50769
+ (0, import_node_fs49.writeFileSync)(packagePath, packageText);
50770
+ (0, import_node_fs49.writeFileSync)(lockPath, lockText);
50588
50771
  throw new Error(`npm ci --offline failed, package.json and package-lock.json restored: ${error.message}`);
50589
50772
  }
50590
50773
  return plan.result;
50591
50774
  } finally {
50592
- (0, import_node_fs48.rmSync)(work, { recursive: true, force: true });
50775
+ (0, import_node_fs49.rmSync)(work, { recursive: true, force: true });
50593
50776
  }
50594
50777
  }
50595
50778
  var execFileBuffer = (0, import_node_util6.promisify)(import_node_child_process19.execFile);
@@ -50654,12 +50837,12 @@ function registerPackagesCommands(program3) {
50654
50837
  init_cli_shared();
50655
50838
 
50656
50839
  // src/wave-status.ts
50657
- var import_node_fs49 = require("node:fs");
50840
+ var import_node_fs50 = require("node:fs");
50658
50841
  function readStageSummary(worktreePath) {
50659
50842
  const statePath = stageStatePath(worktreePath);
50660
- if (!(0, import_node_fs49.existsSync)(statePath)) return void 0;
50843
+ if (!(0, import_node_fs50.existsSync)(statePath)) return void 0;
50661
50844
  try {
50662
- const state = JSON.parse((0, import_node_fs49.readFileSync)(statePath, "utf8"));
50845
+ const state = JSON.parse((0, import_node_fs50.readFileSync)(statePath, "utf8"));
50663
50846
  const port = typeof state.port === "number" ? state.port : void 0;
50664
50847
  if (port == null || !Number.isInteger(port) || port <= 0) return void 0;
50665
50848
  return { port, url: typeof state.url === "string" ? state.url : void 0 };
@@ -50716,7 +50899,7 @@ async function collectWaveStatus(deps) {
50716
50899
  // src/discovery-commands.ts
50717
50900
  init_github_client();
50718
50901
  init_cli_shared();
50719
- var import_node_fs50 = require("node:fs");
50902
+ var import_node_fs51 = require("node:fs");
50720
50903
  var import_node_os23 = require("node:os");
50721
50904
  var import_node_path48 = require("node:path");
50722
50905
  var GC_GH_TIMEOUT_MS3 = 2e4;
@@ -50909,8 +51092,8 @@ async function collectOnboardStatus(opts = {}) {
50909
51092
  }
50910
51093
  const home = (0, import_node_os23.homedir)();
50911
51094
  const plugin = onboardPluginGate({
50912
- readKnown: () => readFileSyncSafe((0, import_node_path48.join)(home, ...KNOWN_MARKETPLACES_RELATIVE), import_node_fs50.readFileSync),
50913
- 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)
50914
51097
  });
50915
51098
  return {
50916
51099
  guide: "Read the MMI org-guide skill before project work; load only the relevant topic. Use mmi-help for a short introduction.",
@@ -53104,7 +53287,7 @@ function registerOrgHealthQuery(program3, deps = defaultOrgHealthQueryDeps()) {
53104
53287
  }
53105
53288
 
53106
53289
  // src/api-read.ts
53107
- var import_node_fs51 = require("node:fs");
53290
+ var import_node_fs52 = require("node:fs");
53108
53291
 
53109
53292
  // src/run-log-read.ts
53110
53293
  init_cli_shared();
@@ -53705,7 +53888,7 @@ function registerApiReadCommands(program3, overrides) {
53705
53888
  o.accept
53706
53889
  );
53707
53890
  if (zip) {
53708
- (0, import_node_fs51.writeFileSync)(o.out, body, "latin1");
53891
+ (0, import_node_fs52.writeFileSync)(o.out, body, "latin1");
53709
53892
  return;
53710
53893
  }
53711
53894
  } catch (e) {
@@ -54580,7 +54763,7 @@ function registerSessionReport(program3) {
54580
54763
  }
54581
54764
 
54582
54765
  // src/stage-commands.ts
54583
- var import_node_fs52 = require("node:fs");
54766
+ var import_node_fs53 = require("node:fs");
54584
54767
  var import_node_path49 = require("node:path");
54585
54768
  init_cli_shared();
54586
54769
  init_clean_exit();
@@ -54829,8 +55012,8 @@ function registerStageCommands(program3) {
54829
55012
  const repo = Array.isArray(project2?.repos) && typeof project2.repos[0] === "string" ? project2.repos[0] : slug;
54830
55013
  const resolution = decideStage({
54831
55014
  registry: { deployModel: project2?.deployModel, portRange, error: read.ok ? void 0 : read.error },
54832
- hasCompose: (0, import_node_fs52.existsSync)((0, import_node_path49.join)(process.cwd(), "docker-compose.yml")),
54833
- 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")),
54834
55017
  repo
54835
55018
  });
54836
55019
  if (resolution.source === "derived" && resolution.derived) {
@@ -55123,14 +55306,14 @@ vercel preview (${preview.branch}): ${d.state}${d.url ? ` \u2014 ${d.url}` : ""}
55123
55306
 
55124
55307
  // src/tenant-artifact.ts
55125
55308
  var import_node_crypto17 = require("node:crypto");
55126
- var import_node_fs53 = require("node:fs");
55309
+ var import_node_fs54 = require("node:fs");
55127
55310
  var import_promises11 = require("node:fs/promises");
55128
55311
  var import_node_path50 = require("node:path");
55129
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}$/;
55130
55313
  var MAX_BYTES2 = 5 * 1024 * 1024 * 1024;
55131
55314
  async function sha256File(path2) {
55132
55315
  const hash = (0, import_node_crypto17.createHash)("sha256");
55133
- 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);
55134
55317
  return hash.digest("hex");
55135
55318
  }
55136
55319
  async function putTenantArtifact(repo, stage, inputPath, deps) {
@@ -55153,7 +55336,7 @@ async function putTenantArtifact(repo, stage, inputPath, deps) {
55153
55336
  return [key, value];
55154
55337
  }));
55155
55338
  headers["content-length"] = String(info.size);
55156
- const stream = (0, import_node_fs53.createReadStream)(path2);
55339
+ const stream = (0, import_node_fs54.createReadStream)(path2);
55157
55340
  let uploaded;
55158
55341
  try {
55159
55342
  uploaded = await fetch(body.uploadUrl, {
@@ -55292,7 +55475,7 @@ function renderVerifySecrets(body) {
55292
55475
  }
55293
55476
 
55294
55477
  // src/command-register-developer.ts
55295
- var import_node_fs57 = require("node:fs");
55478
+ var import_node_fs58 = require("node:fs");
55296
55479
  init_clean_exit();
55297
55480
  init_cli_shared();
55298
55481
  init_error_codes();
@@ -55360,13 +55543,13 @@ async function executeWaveLand(plan, deps) {
55360
55543
  // src/dist-drift.ts
55361
55544
  var import_node_child_process20 = require("node:child_process");
55362
55545
  var import_node_crypto19 = require("node:crypto");
55363
- var import_node_fs55 = require("node:fs");
55546
+ var import_node_fs56 = require("node:fs");
55364
55547
  var import_node_os24 = require("node:os");
55365
55548
  var import_node_path52 = require("node:path");
55366
55549
 
55367
55550
  // ../scripts/distribution-digest.mjs
55368
55551
  var import_node_crypto18 = require("node:crypto");
55369
- var import_node_fs54 = require("node:fs");
55552
+ var import_node_fs55 = require("node:fs");
55370
55553
  var import_node_path51 = require("node:path");
55371
55554
  var slash = (value) => value.replaceAll("\\", "/");
55372
55555
  function repoPath(root, declaredPath, label) {
@@ -55380,7 +55563,7 @@ function repoPath(root, declaredPath, label) {
55380
55563
  function digestFiles(files) {
55381
55564
  const hash = (0, import_node_crypto18.createHash)("sha256");
55382
55565
  for (const file of [...files].sort((a, b) => a.relative.localeCompare(b.relative))) {
55383
- 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);
55384
55567
  hash.update(file.relative, "utf8");
55385
55568
  hash.update("\0");
55386
55569
  hash.update(file.stat.isSymbolicLink() ? "symlink" : "file", "utf8");
@@ -55395,8 +55578,8 @@ function digestFiles(files) {
55395
55578
  function digestPackedFiles(packageRoot, packedFiles) {
55396
55579
  return digestFiles(packedFiles.map((path2) => {
55397
55580
  const absolute = repoPath(packageRoot, path2, "packed artifact identity path");
55398
- if (!(0, import_node_fs54.existsSync)(absolute)) throw new Error(`packed artifact identity path ${path2} does not exist`);
55399
- 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) };
55400
55583
  }));
55401
55584
  }
55402
55585
 
@@ -55481,12 +55664,12 @@ function renderDistDriftReceipt(receipt) {
55481
55664
  return lines2;
55482
55665
  }
55483
55666
  function readOrNull(path2) {
55484
- 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;
55485
55668
  }
55486
55669
  function walkFiles(root) {
55487
55670
  const files = [];
55488
55671
  const walk2 = (directory) => {
55489
- 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))) {
55490
55673
  const child2 = (0, import_node_path52.join)(directory, entry.name);
55491
55674
  if (entry.isDirectory()) walk2(child2);
55492
55675
  else files.push(child2);
@@ -55497,7 +55680,7 @@ function walkFiles(root) {
55497
55680
  }
55498
55681
  function bomPathFor(root) {
55499
55682
  try {
55500
- 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"));
55501
55684
  return (0, import_node_path52.join)(root, registry2?.sharedAgentCore?.releaseMetadata?.bomPath ?? "distribution-bom.json");
55502
55685
  } catch {
55503
55686
  return (0, import_node_path52.join)(root, "distribution-bom.json");
@@ -55513,7 +55696,7 @@ function rebuildTo(packageRoot, outDir) {
55513
55696
  });
55514
55697
  }
55515
55698
  function runDistStatus(root) {
55516
- 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-"));
55517
55700
  let overlayCount = 0;
55518
55701
  try {
55519
55702
  const cliOut = (0, import_node_path52.join)(stage, "cli-dist");
@@ -55529,19 +55712,19 @@ function runDistStatus(root) {
55529
55712
  const tree = (path2) => readOrNull((0, import_node_path52.join)(root, path2));
55530
55713
  const distRoot = (0, import_node_path52.join)(root, "cli", "dist");
55531
55714
  const distTree = () => walkFiles(distRoot).map((absolute) => `cli/dist/${(0, import_node_path52.relative)(distRoot, absolute).replaceAll("\\", "/")}`);
55532
- 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"));
55533
55716
  const digest = (entries) => {
55534
55717
  const overlay = (0, import_node_path52.join)(stage, `overlay-${overlayCount++}`);
55535
55718
  for (const entry of entries) {
55536
55719
  const target = (0, import_node_path52.join)(overlay, entry.path);
55537
- (0, import_node_fs55.mkdirSync)((0, import_node_path52.dirname)(target), { recursive: true });
55538
- (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);
55539
55722
  }
55540
55723
  return digestPackedFiles(overlay, entries.map((entry) => entry.path));
55541
55724
  };
55542
55725
  return computeDistDriftReceipt({ committed, tree, rebuilt, distTree, bom, digest });
55543
55726
  } finally {
55544
- (0, import_node_fs55.rmSync)(stage, { recursive: true, force: true });
55727
+ (0, import_node_fs56.rmSync)(stage, { recursive: true, force: true });
55545
55728
  }
55546
55729
  }
55547
55730
 
@@ -55871,7 +56054,7 @@ function registerSchedulesLiftCommand(program3, deps = {}) {
55871
56054
 
55872
56055
  // src/spawn-policy-core.ts
55873
56056
  var import_node_child_process22 = require("node:child_process");
55874
- var import_node_fs56 = require("node:fs");
56057
+ var import_node_fs57 = require("node:fs");
55875
56058
  var import_node_path55 = require("node:path");
55876
56059
  var SPAWNERS = ["spawn", "spawnSync", "exec", "execSync", "execFile", "execFileSync"];
55877
56060
  var CALL_SOURCE = String.raw`(^|[^.\w$])(${SPAWNERS.join("|")})\s*\(`;
@@ -55958,7 +56141,7 @@ function runSpawnPolicy(root) {
55958
56141
  for (const file of files) {
55959
56142
  let raw;
55960
56143
  try {
55961
- 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");
55962
56145
  } catch {
55963
56146
  continue;
55964
56147
  }
@@ -55979,18 +56162,18 @@ function registerDeveloperCommands(program3) {
55979
56162
  const rules = program3.command("rules").description("org-managed .gitignore delivery");
55980
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) => {
55981
56164
  const path2 = (0, import_node_path56.join)(process.cwd(), ".gitignore");
55982
- 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;
55983
56166
  const plan = planManagedGitignore(current);
55984
56167
  const drift = [...plan.added.map((l) => `+${l}`), ...plan.removed.map((l) => `-${l}`)].join(", ") || "block normalize";
55985
56168
  if (opts.json) {
55986
- 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");
55987
56170
  console.log(JSON.stringify(plan, null, 2));
55988
56171
  if (!opts.write && plan.changed) process.exitCode = 1;
55989
56172
  return;
55990
56173
  }
55991
56174
  if (opts.write) {
55992
56175
  if (plan.changed) {
55993
- (0, import_node_fs57.writeFileSync)(path2, plan.content, "utf8");
56176
+ (0, import_node_fs58.writeFileSync)(path2, plan.content, "utf8");
55994
56177
  console.log(`mmi-cli devops org rules gitignore: updated .gitignore (${drift})`);
55995
56178
  } else {
55996
56179
  console.log("mmi-cli devops org rules gitignore: up to date");
@@ -56199,17 +56382,18 @@ function registerDeveloperCommands(program3) {
56199
56382
  }
56200
56383
  });
56201
56384
  const tests = program3.command("tests").description("a repo's test-policy.json \u2014 the opt-in test contract and its enforcement");
56202
- 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) => {
56203
56386
  try {
56204
56387
  if (o.repo) {
56205
- 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" : ""}`;
56206
56389
  const guard = planTrainApplyRepoGuard(o.repo, await resolveRepo(), rerun, "tests policy");
56207
56390
  if (!guard.ok) return failGraceful(guard.message);
56208
56391
  }
56209
56392
  const root = await repoRoot();
56210
56393
  const result = runTestPolicy(root, { base: o.base, policyRef: o.policyRef });
56211
56394
  if (o.json) {
56212
- 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 }));
56213
56397
  if (!result.ok) process.exitCode = 1;
56214
56398
  return;
56215
56399
  }
@@ -56407,7 +56591,7 @@ function mmiDoctorDeps(opts = {}) {
56407
56591
  );
56408
56592
  const result = applyPluginCachePlan(
56409
56593
  plan,
56410
- (p) => (0, import_node_fs58.rmSync)(p, { recursive: true }),
56594
+ (p) => (0, import_node_fs59.rmSync)(p, { recursive: true }),
56411
56595
  stagingApplyFsGuard(configRoot)
56412
56596
  );
56413
56597
  return {
@@ -56442,7 +56626,7 @@ function mmiDoctorDeps(opts = {}) {
56442
56626
  // has no generated routing index would
56443
56627
  // get a permanent — demanding an artifact it never asked for.
56444
56628
  docsIndexState: (root) => {
56445
- 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;
56446
56630
  const real = createDocsIndexDeps(root);
56447
56631
  let docs;
56448
56632
  const listDocs = () => docs ??= real.listDocs();
@@ -56451,7 +56635,7 @@ function mmiDoctorDeps(opts = {}) {
56451
56635
  },
56452
56636
  // #4168: working-tree heal — write if drifted, then re-check. Commit remains the operator's step.
56453
56637
  healDocsIndex: (root) => {
56454
- 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 };
56455
56639
  const real = createDocsIndexDeps(root);
56456
56640
  let docs;
56457
56641
  const listDocs = () => docs ??= real.listDocs();
@@ -56811,6 +56995,7 @@ function appActorDeps() {
56811
56995
  };
56812
56996
  }
56813
56997
  setPollTokenProvider(async () => activeAppToken() ?? pollTokenOrUndefined(appActorDeps()));
56998
+ setGhReadTokenProvider(pollToken);
56814
56999
  setStatusWriteTokenProvider(() => mintStatusWriteToken(appActorDeps()));
56815
57000
  var registerPreAction = Reflect.get(program2, ["h", "ook"].join(""));
56816
57001
  registerPreAction.call(program2, "preAction", async (_thisCommand, actionCommand) => {
@@ -56818,7 +57003,7 @@ registerPreAction.call(program2, "preAction", async (_thisCommand, actionCommand
56818
57003
  appActorCommand = commandPath3;
56819
57004
  emitCliCallTelemetry(commandPath3);
56820
57005
  try {
56821
- await activateAppActor(commandPath3, process.env, () => mintInstallationToken(appActorDeps()));
57006
+ await activateAppActor(commandPath3, process.env, () => APP_WRITE_COMMANDS.has(commandPath3) ? mintCommandWriteToken(appActorDeps(), commandPath3) : mintInstallationToken(appActorDeps()));
56822
57007
  } catch (e) {
56823
57008
  if (e instanceof AppActorError) return fail(e.message);
56824
57009
  throw e;
@@ -57176,7 +57361,7 @@ project.command("set [owner/repo]").description("upsert project META (idempotent
57176
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`);
57177
57362
  if (o.secretsFile) {
57178
57363
  try {
57179
- vars.push(`secrets=${(0, import_node_fs58.readFileSync)(o.secretsFile, "utf8")}`);
57364
+ vars.push(`secrets=${(0, import_node_fs59.readFileSync)(o.secretsFile, "utf8")}`);
57180
57365
  } catch (e) {
57181
57366
  return fail(`org project set: cannot read --secrets-file ${o.secretsFile}: ${e.message}`);
57182
57367
  }
@@ -57568,15 +57753,15 @@ function ciAuditDeps2() {
57568
57753
  readSeedFile: (path2) => {
57569
57754
  if (!root) return null;
57570
57755
  const fullPath = (0, import_node_path57.join)(root, path2);
57571
- 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;
57572
57757
  }
57573
57758
  };
57574
57759
  }
57575
57760
  function hubRoot2() {
57576
57761
  const fromPkg = (0, import_node_path57.join)(__dirname, "..", "..");
57577
57762
  const marker = "skills/bootstrap/seeds/manifest.json";
57578
- if ((0, import_node_fs58.existsSync)((0, import_node_path57.join)(fromPkg, marker))) return fromPkg;
57579
- 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();
57580
57765
  return null;
57581
57766
  }
57582
57767
  registerQueryCommands(program2);
@@ -57590,6 +57775,7 @@ registerDiscoveryCommands(program2);
57590
57775
  registerExplainCommand(program2);
57591
57776
  registerPrLifecycleCommands(program2);
57592
57777
  registerApiReadCommands(program2);
57778
+ registerGithubBudgetCommand(program2, appActorDeps);
57593
57779
  registerAppReadBrokerCommands(program2, async (repo) => requireRepo(repo));
57594
57780
  var prBrokerRoot = program2.commands.find((c) => c.name() === "pr");
57595
57781
  if (!prBrokerRoot) throw new Error("read broker: pr root must be registered before pr checks-required");
@@ -57706,10 +57892,10 @@ access.command("audit").description("audit collaborator roles + train-branch pus
57706
57892
  targets = resolution.targets;
57707
57893
  }
57708
57894
  const derivedMatrix = registryProjects ? accessMatrixFromProjects(registryProjects) : {};
57709
- 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")) : {};
57710
57896
  const matrix = mergeAccessMatrix(fileMatrix, derivedMatrix);
57711
57897
  const dataAccess = registryProjects ? dataAccessContractsFromProjects(registryProjects) : { consumers: {} };
57712
- 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")) : {};
57713
57899
  const report = await auditOrgAccess(targets, deps, matrix, dataAccess, sanctioned);
57714
57900
  console.log(o.json ? JSON.stringify(report, null, 2) : renderAccessReport(report));
57715
57901
  if (!report.ok) process.exitCode = 1;
@@ -57740,7 +57926,7 @@ function directoryBytes(path2) {
57740
57926
  let total = 0;
57741
57927
  let entries;
57742
57928
  try {
57743
- entries = (0, import_node_fs58.readdirSync)(path2, { withFileTypes: true });
57929
+ entries = (0, import_node_fs59.readdirSync)(path2, { withFileTypes: true });
57744
57930
  } catch {
57745
57931
  return 0;
57746
57932
  }
@@ -57749,7 +57935,7 @@ function directoryBytes(path2) {
57749
57935
  if (entry.isDirectory()) total += directoryBytes(child2);
57750
57936
  else {
57751
57937
  try {
57752
- total += (0, import_node_fs58.statSync)(child2).size;
57938
+ total += (0, import_node_fs59.statSync)(child2).size;
57753
57939
  } catch {
57754
57940
  }
57755
57941
  }
@@ -57757,25 +57943,25 @@ function directoryBytes(path2) {
57757
57943
  return total;
57758
57944
  }
57759
57945
  function listDirEntries(dir) {
57760
- 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() }));
57761
57947
  }
57762
57948
  function readInstalledPluginRefs(configRoot) {
57763
57949
  const p = installedPluginsPathForConfig(configRoot);
57764
- if (!(0, import_node_fs58.existsSync)(p)) return [];
57950
+ if (!(0, import_node_fs59.existsSync)(p)) return [];
57765
57951
  try {
57766
- return installedPluginPaths((0, import_node_fs58.readFileSync)(p, "utf8"));
57952
+ return installedPluginPaths((0, import_node_fs59.readFileSync)(p, "utf8"));
57767
57953
  } catch {
57768
57954
  return null;
57769
57955
  }
57770
57956
  }
57771
57957
  function pluginCacheFsDeps(configRoot, dirBytes) {
57772
57958
  return {
57773
- exists: (p) => (0, import_node_fs58.existsSync)(p),
57774
- 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),
57775
57961
  dirBytes,
57776
- 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) => {
57777
57963
  try {
57778
- 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) };
57779
57965
  } catch {
57780
57966
  return { name: d.name, mtimeMs: Date.now() };
57781
57967
  }
@@ -57790,9 +57976,9 @@ function stagingApplyFsGuard(configRoot) {
57790
57976
  referencedPaths: () => readInstalledPluginRefs(configRoot),
57791
57977
  mtimeMs: (name) => {
57792
57978
  const p = (0, import_node_path57.join)(stagingRoot, name);
57793
- if (!(0, import_node_fs58.existsSync)(p)) return null;
57979
+ if (!(0, import_node_fs59.existsSync)(p)) return null;
57794
57980
  try {
57795
- 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);
57796
57982
  } catch {
57797
57983
  return null;
57798
57984
  }
@@ -57818,7 +58004,7 @@ program2.command("plugin-prune").description(`prune stale cached MMI plugin vers
57818
58004
  { withBytes: true, configRoot, includeStaging: surface !== "codex" }
57819
58005
  );
57820
58006
  const anythingToDelete = plan.prune.length > 0 || plan.staging.length > 0;
57821
- 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;
57822
58008
  const warnings = plan.prune.length > 0 ? [CONCURRENT_SESSION_WARNING] : [];
57823
58009
  if (o.json) console.log(JSON.stringify({ ...plan, warnings, applied: result ?? null }));
57824
58010
  else console.log(renderPluginCachePlan(plan, result));