@mutmutco/claude-plugin 4.5.159 → 4.5.161

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();
@@ -7167,6 +7238,19 @@ async function readAppVaultSecret(read) {
7167
7238
  async function mintInstallationToken(deps) {
7168
7239
  return mintScopedInstallationToken(deps, APP_POLL_PERMISSIONS);
7169
7240
  }
7241
+ var APP_WRITE_COMMANDS = /* @__PURE__ */ new Map([
7242
+ ["issue comment", { metadata: "read", issues: "write", pull_requests: "write" }]
7243
+ ]);
7244
+ async function mintCommandWriteToken(deps, commandPath3) {
7245
+ const permissions = APP_WRITE_COMMANDS.get(commandPath3);
7246
+ if (!permissions) throw new AppActorError(`app actor: '${commandPath3}' has no App write profile`);
7247
+ try {
7248
+ return await mintFromMember(deps, permissions, APP_VAULT_KEYS);
7249
+ } catch (e) {
7250
+ if (e instanceof AppActorError) throw e;
7251
+ throw new AppActorError(`app actor: write token mint failed (${e?.constructor?.name ?? "Error"})`);
7252
+ }
7253
+ }
7170
7254
  async function mintStatusWriteToken(deps) {
7171
7255
  return mintScopedInstallationToken(deps, { metadata: "read", statuses: "write" });
7172
7256
  }
@@ -7227,6 +7311,9 @@ async function allowanceSpent(deps, token) {
7227
7311
  return false;
7228
7312
  }
7229
7313
  }
7314
+ function mintBudgetToken(deps, keys) {
7315
+ return mintFromMember(deps, { metadata: "read" }, keys);
7316
+ }
7230
7317
  async function mintFromMember(deps, permissions, keys) {
7231
7318
  const [appId, installationId, privateKey] = await Promise.all(keys.map((k) => deps.fetchSecret(k)));
7232
7319
  if (!appId || !installationId || !privateKey) {
@@ -7294,7 +7381,7 @@ async function activateAppActor(commandPath3, env, mint, note = (line) => proces
7294
7381
  if (requested && requested !== "app") {
7295
7382
  throw new AppActorError(`app actor: unknown ${APP_ACTOR_ENV} value \u2014 only 'app' and 'personal' are supported; refusing to guess an identity`);
7296
7383
  }
7297
- if (!APP_ELIGIBLE_COMMANDS.has(commandPath3)) {
7384
+ if (!APP_ELIGIBLE_COMMANDS.has(commandPath3) && !APP_WRITE_COMMANDS.has(commandPath3)) {
7298
7385
  if (requested === "app" && !notedIneligibleCommand) {
7299
7386
  notedIneligibleCommand = true;
7300
7387
  note(`app actor: '${commandPath3}' is personal-only (viewer/@me/authorship) \u2014 running on the personal token despite ${APP_ACTOR_ENV}=app`);
@@ -10225,7 +10312,7 @@ init_github_client();
10225
10312
  // src/project-model.ts
10226
10313
  var PROJECT_TYPES = ["web-app", "hub-service", "content", "desktop-app", "desktop-game", "mobile-app", "non-deployable", "cli-tool", "worker"];
10227
10314
  var DEPLOY_MODELS = ["hub-serverless", "serverless", "tenant-container", "solo-container", "static-cdn", "registry-publish", "content", "none", "vercel"];
10228
- var RELEASE_TRACKS = ["full", "direct", "trunk"];
10315
+ var RELEASE_TRACKS = ["full", "direct", "trunk", "single"];
10229
10316
  var REQUIRED_CHECK_BRANCHES = ["development", "rc", "main"];
10230
10317
  var PROJECT_TYPE_SET = new Set(PROJECT_TYPES);
10231
10318
  var DEPLOY_MODEL_SET = new Set(DEPLOY_MODELS);
@@ -10308,6 +10395,7 @@ function metaWithDeclaredClass(meta, declaredClass) {
10308
10395
  }
10309
10396
  function branchesForTrack(track) {
10310
10397
  if (track === "trunk") return ["main"];
10398
+ if (track === "single") return ["development"];
10311
10399
  if (track === "direct") return ["development", "main"];
10312
10400
  return ["development", "rc", "main"];
10313
10401
  }
@@ -10319,7 +10407,7 @@ function resolveRequiredCheckBranches(meta, repo) {
10319
10407
  return branchesForTrack(resolveReleaseTrack(meta, void 0, repo));
10320
10408
  }
10321
10409
  function promotionBranchesForTrack(track) {
10322
- if (track === "trunk") return [];
10410
+ if (track === "trunk" || track === "single") return [];
10323
10411
  if (track === "direct") return ["main"];
10324
10412
  return ["rc", "main"];
10325
10413
  }
@@ -11301,6 +11389,7 @@ init_clean_exit();
11301
11389
 
11302
11390
  // src/gh-create.ts
11303
11391
  var import_promises = require("node:fs/promises");
11392
+ var import_node_fs16 = require("node:fs");
11304
11393
  var import_node_os8 = require("node:os");
11305
11394
  var import_node_path13 = require("node:path");
11306
11395
  var import_node_crypto7 = require("node:crypto");
@@ -11566,18 +11655,23 @@ async function preflightPrCreateRemoteHead(args, deps) {
11566
11655
  if (compared !== "unknown" && compared.aheadBy <= 0) return emptyCompareMessage(base, head);
11567
11656
  return void 0;
11568
11657
  }
11658
+ function retryBodyFile(args) {
11659
+ const file = flagValue(args, "--body-file");
11660
+ if (file !== void 0) return file;
11661
+ const body = flagValue(args, "--body");
11662
+ if (body === void 0) return void 0;
11663
+ 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");
11664
+ (0, import_node_fs16.writeFileSync)(path2, body, "utf8");
11665
+ return path2;
11666
+ }
11569
11667
  function buildPrCreateRetryCommand(args) {
11570
11668
  const parts = ["mmi-cli", "devops", "pr", "create"];
11571
11669
  for (const flag of ["--repo", "--base", "--head", "--title"]) {
11572
11670
  const v = flagValue(args, flag);
11573
11671
  if (v !== void 0) parts.push(flag, shellQuote(v));
11574
11672
  }
11575
- const bodyFile = flagValue(args, "--body-file");
11673
+ const bodyFile = retryBodyFile(args);
11576
11674
  if (bodyFile !== void 0) parts.push("--body-file", shellQuote(bodyFile));
11577
- else {
11578
- const body = flagValue(args, "--body");
11579
- if (body !== void 0) parts.push("--body", shellQuote(body));
11580
- }
11581
11675
  if (args.includes("--draft")) parts.push("--draft");
11582
11676
  return parts.join(" ");
11583
11677
  }
@@ -11600,12 +11694,8 @@ function buildIssueCreateRetryCommand(args) {
11600
11694
  if (type) parts.push("--type", type);
11601
11695
  const title = flagValue(args, "--title");
11602
11696
  if (title !== void 0) parts.push("--title", shellQuote(title));
11603
- const bodyFile = flagValue(args, "--body-file");
11697
+ const bodyFile = retryBodyFile(args);
11604
11698
  if (bodyFile !== void 0) parts.push("--body-file", shellQuote(bodyFile));
11605
- else {
11606
- const body = flagValue(args, "--body");
11607
- if (body !== void 0) parts.push("--body", shellQuote(body));
11608
- }
11609
11699
  for (const label of labels) {
11610
11700
  if (label === type) continue;
11611
11701
  parts.push("--label", shellQuote(label));
@@ -14562,11 +14652,11 @@ function probeLocalClaimSession(marker, now = Date.now()) {
14562
14652
  const pending = [root];
14563
14653
  while (pending.length) {
14564
14654
  const dir = pending.pop();
14565
- for (const entry of (0, import_node_fs16.readdirSync)(dir, { withFileTypes: true })) {
14655
+ for (const entry of (0, import_node_fs17.readdirSync)(dir, { withFileTypes: true })) {
14566
14656
  const path2 = (0, import_node_path14.join)(dir, entry.name);
14567
14657
  if (entry.isDirectory()) pending.push(path2);
14568
14658
  else if (entry.isFile() && entry.name.toLowerCase() === wanted) {
14569
- return remember(now - (0, import_node_fs16.statSync)(path2).mtimeMs <= CLAIM_SESSION_ACTIVITY_MS ? "live" : "dead");
14659
+ return remember(now - (0, import_node_fs17.statSync)(path2).mtimeMs <= CLAIM_SESSION_ACTIVITY_MS ? "live" : "dead");
14570
14660
  }
14571
14661
  }
14572
14662
  }
@@ -16071,12 +16161,12 @@ function planManagedGitignore(current) {
16071
16161
  }
16072
16162
 
16073
16163
  // src/docs-index-command.ts
16074
- var import_node_fs18 = require("node:fs");
16164
+ var import_node_fs19 = require("node:fs");
16075
16165
  var import_node_path16 = require("node:path");
16076
16166
 
16077
16167
  // src/doc-refs-core.ts
16078
16168
  var import_node_child_process6 = require("node:child_process");
16079
- var import_node_fs17 = require("node:fs");
16169
+ var import_node_fs18 = require("node:fs");
16080
16170
  var import_node_path15 = require("node:path");
16081
16171
  var PIN_RE = /<!--\s*pinned by\s+([^:]+?)\s*:\s*"([^"]+)"[^"]*-->/;
16082
16172
  var PIN_MENTION_RE = /<!--\s*pinned by\b/;
@@ -16449,12 +16539,12 @@ function checkSeedRunbookReview(root, base, readFile10, git3) {
16449
16539
  return findings;
16450
16540
  }
16451
16541
  function readFileOrNull(path2) {
16452
- return (0, import_node_fs17.existsSync)(path2) ? (0, import_node_fs17.readFileSync)(path2, "utf8") : null;
16542
+ return (0, import_node_fs18.existsSync)(path2) ? (0, import_node_fs18.readFileSync)(path2, "utf8") : null;
16453
16543
  }
16454
16544
  function walk(dir, root, out) {
16455
- for (const entry of (0, import_node_fs17.readdirSync)(dir)) {
16545
+ for (const entry of (0, import_node_fs18.readdirSync)(dir)) {
16456
16546
  const full = (0, import_node_path15.join)(dir, entry);
16457
- if ((0, import_node_fs17.statSync)(full).isDirectory()) walk(full, root, out);
16547
+ if ((0, import_node_fs18.statSync)(full).isDirectory()) walk(full, root, out);
16458
16548
  else if (entry.endsWith(".md")) out.push(full.slice(root.length + 1).replaceAll("\\", "/"));
16459
16549
  }
16460
16550
  return out;
@@ -16462,11 +16552,11 @@ function walk(dir, root, out) {
16462
16552
  function defaultListDocs(root) {
16463
16553
  const docs = ["docs", "skills/org-guide", "skills/mmi-help"].flatMap((path2) => {
16464
16554
  const directory = (0, import_node_path15.join)(root, path2);
16465
- return (0, import_node_fs17.existsSync)(directory) ? walk(directory, root, []) : [];
16555
+ return (0, import_node_fs18.existsSync)(directory) ? walk(directory, root, []) : [];
16466
16556
  }).filter(
16467
16557
  (rel) => !SKIP_WALK.some((skip) => rel.startsWith(skip))
16468
16558
  );
16469
- return [...ROOT_DOCS.filter((rel) => (0, import_node_fs17.existsSync)((0, import_node_path15.join)(root, rel))), ...docs];
16559
+ return [...ROOT_DOCS.filter((rel) => (0, import_node_fs18.existsSync)((0, import_node_path15.join)(root, rel))), ...docs];
16470
16560
  }
16471
16561
  var CHECK_IGNORE_MAX_BUFFER = 32 * 1024 * 1024;
16472
16562
  function defaultIsIgnored(root, relPaths, exec3 = import_node_child_process6.execFileSync) {
@@ -16547,7 +16637,7 @@ function mergeGroupRunbookMessages(root, deps, readFile10, warnings) {
16547
16637
  }
16548
16638
  function runDocRefs(root, deps = {}) {
16549
16639
  const readFile10 = deps.readFile ?? readFileOrNull;
16550
- const exists = deps.exists ?? import_node_fs17.existsSync;
16640
+ const exists = deps.exists ?? import_node_fs18.existsSync;
16551
16641
  const listDocs = deps.listDocs ?? defaultListDocs;
16552
16642
  const isIgnored = deps.isIgnored ?? ((paths) => defaultIsIgnored(root, paths));
16553
16643
  const trackedFirstSegments = deps.trackedFirstSegments ?? ((segs) => defaultTrackedFirstSegments(root, segs));
@@ -16680,7 +16770,7 @@ function walkMarkdown(dir) {
16680
16770
  const stack = [dir];
16681
16771
  while (stack.length) {
16682
16772
  const current = stack.pop();
16683
- for (const entry of (0, import_node_fs18.readdirSync)(current, { withFileTypes: true })) {
16773
+ for (const entry of (0, import_node_fs19.readdirSync)(current, { withFileTypes: true })) {
16684
16774
  const full = (0, import_node_path16.join)(current, entry.name);
16685
16775
  if (entry.isDirectory()) {
16686
16776
  stack.push(full);
@@ -16696,15 +16786,15 @@ function createDocsIndexDeps(repoRoot2) {
16696
16786
  const indexPath = (0, import_node_path16.join)(repoRoot2, DOCS_INDEX_PATH);
16697
16787
  return {
16698
16788
  listDocs: () => {
16699
- if (!(0, import_node_fs18.existsSync)(docsDir)) return [];
16789
+ if (!(0, import_node_fs19.existsSync)(docsDir)) return [];
16700
16790
  const walked = walkMarkdown(docsDir).filter(isRoutableDocsPath);
16701
16791
  if (!walked.length) return [];
16702
16792
  const ignored = defaultIsIgnored(repoRoot2, walked.map((rel) => `docs/${rel}`));
16703
16793
  return walked.filter((rel) => !ignored.has(`docs/${rel}`)).sort();
16704
16794
  },
16705
- readDoc: (relPath) => (0, import_node_fs18.readFileSync)((0, import_node_path16.join)(docsDir, relPath), "utf8"),
16706
- readIndex: () => (0, import_node_fs18.existsSync)(indexPath) ? (0, import_node_fs18.readFileSync)(indexPath, "utf8") : null,
16707
- writeIndex: (content) => (0, import_node_fs18.writeFileSync)(indexPath, content, "utf8")
16795
+ readDoc: (relPath) => (0, import_node_fs19.readFileSync)((0, import_node_path16.join)(docsDir, relPath), "utf8"),
16796
+ readIndex: () => (0, import_node_fs19.existsSync)(indexPath) ? (0, import_node_fs19.readFileSync)(indexPath, "utf8") : null,
16797
+ writeIndex: (content) => (0, import_node_fs19.writeFileSync)(indexPath, content, "utf8")
16708
16798
  };
16709
16799
  }
16710
16800
 
@@ -17093,7 +17183,7 @@ function gateSeedVars(cls, releaseTrack, runtime = "node", requiredCheckBranches
17093
17183
  GATE_EXTRA_STEPS_YAML: ""
17094
17184
  };
17095
17185
  const track = releaseTrack ?? (cls === "content" ? "trunk" : "full");
17096
- const trackBranches = track === "trunk" ? ["main"] : track === "direct" ? ["development", "main"] : ["development", "rc", "main"];
17186
+ const trackBranches = track === "trunk" ? ["main"] : track === "single" ? ["development"] : track === "direct" ? ["development", "main"] : ["development", "rc", "main"];
17097
17187
  const rulesetBranches = requiredCheckBranches?.length ? [...requiredCheckBranches] : trackBranches;
17098
17188
  const rulesetRefs = JSON.stringify(rulesetBranches.map((branch) => `refs/heads/${branch}`));
17099
17189
  const rulesetContexts = JSON.stringify((requiredChecks?.length ? requiredChecks : ["gate"]).map((context) => ({ context })));
@@ -17106,6 +17196,15 @@ function gateSeedVars(cls, releaseTrack, runtime = "node", requiredCheckBranches
17106
17196
  GATE_RULESET_CONTEXTS_JSON: rulesetContexts
17107
17197
  };
17108
17198
  }
17199
+ if (track === "single") {
17200
+ return {
17201
+ ...runtimeVars,
17202
+ GATE_PUSH_BRANCHES_YAML: "[development]",
17203
+ GATE_FULL_RUN_BRANCH: "development",
17204
+ GATE_RULESET_BRANCH_REFS_JSON: rulesetRefs,
17205
+ GATE_RULESET_CONTEXTS_JSON: rulesetContexts
17206
+ };
17207
+ }
17109
17208
  if (track === "direct") {
17110
17209
  return {
17111
17210
  ...runtimeVars,
@@ -17430,7 +17529,7 @@ function buildRegisterPayload(repo, cls, vars, options = {}) {
17430
17529
  throw new Error(`deployModel must be one of: ${DEPLOY_MODELS.join(", ")}`);
17431
17530
  }
17432
17531
  if (options.releaseTrack && !isReleaseTrack(options.releaseTrack)) {
17433
- throw new Error("releaseTrack must be full, direct, or trunk");
17532
+ throw new Error("releaseTrack must be full, direct, trunk, or single");
17434
17533
  }
17435
17534
  const shape = {
17436
17535
  class: cls,
@@ -17623,7 +17722,7 @@ function contentPutInputArgs(repo, path2, inputFile) {
17623
17722
  }
17624
17723
 
17625
17724
  // src/train-apply-contracts.ts
17626
- var import_node_fs19 = require("node:fs");
17725
+ var import_node_fs20 = require("node:fs");
17627
17726
  var import_node_path17 = require("node:path");
17628
17727
  function reduceFollowUpOutcomes(outcomes) {
17629
17728
  if (outcomes.includes("failure")) return "failure";
@@ -17704,7 +17803,7 @@ async function resolveFoldPaths(deps, model) {
17704
17803
  if (model === "vercel") return [];
17705
17804
  const helper = "scripts/release-distribution.mjs";
17706
17805
  if (model === "hub-serverless" || model === "registry-publish") {
17707
- if ((0, import_node_fs19.existsSync)(helper)) {
17806
+ if ((0, import_node_fs20.existsSync)(helper)) {
17708
17807
  let out;
17709
17808
  try {
17710
17809
  out = await deps.run("node", [helper, "changed-files"]);
@@ -17853,7 +17952,7 @@ async function restoreMainNpmPackIdentities(deps, version) {
17853
17952
  if (mainBom.version !== version) return void 0;
17854
17953
  let localBom;
17855
17954
  try {
17856
- localBom = JSON.parse((0, import_node_fs19.readFileSync)(bomPath, "utf8"));
17955
+ localBom = JSON.parse((0, import_node_fs20.readFileSync)(bomPath, "utf8"));
17857
17956
  } catch (e) {
17858
17957
  throw new Error(
17859
17958
  `version fold refused: ${bomPath} written by this fold's prepare is unreadable (${describeReadError(e)}) \u2014 cannot restore the published ${version} npm-pack identities from origin/main (#4503/#4713).`
@@ -17871,14 +17970,14 @@ async function restoreMainNpmPackIdentities(deps, version) {
17871
17970
  restored += 1;
17872
17971
  }
17873
17972
  if (restored === 0) return void 0;
17874
- (0, import_node_fs19.writeFileSync)(bomPath, `${JSON.stringify(localBom, null, 2)}
17973
+ (0, import_node_fs20.writeFileSync)(bomPath, `${JSON.stringify(localBom, null, 2)}
17875
17974
  `);
17876
17975
  return `restored ${restored} npm-pack BOM identit${restored === 1 ? "y" : "ies"} from origin/main (#4503)`;
17877
17976
  }
17878
17977
  function publishVisibilityFor(surfaceId) {
17879
17978
  let raw;
17880
17979
  try {
17881
- raw = (0, import_node_fs19.readFileSync)("surfaces.json", "utf8");
17980
+ raw = (0, import_node_fs20.readFileSync)("surfaces.json", "utf8");
17882
17981
  } catch (e) {
17883
17982
  if (e.code === "ENOENT") return "unknown";
17884
17983
  throw trainReadFailure(
@@ -17899,7 +17998,7 @@ function publishVisibilityFor(surfaceId) {
17899
17998
  }
17900
17999
  function npmPackArtifactName(packagePath) {
17901
18000
  try {
17902
- const pkg = JSON.parse((0, import_node_fs19.readFileSync)((0, import_node_path17.join)(packagePath, "package.json"), "utf8"));
18001
+ const pkg = JSON.parse((0, import_node_fs20.readFileSync)((0, import_node_path17.join)(packagePath, "package.json"), "utf8"));
17903
18002
  return pkg.name || void 0;
17904
18003
  } catch {
17905
18004
  return void 0;
@@ -17908,7 +18007,7 @@ function npmPackArtifactName(packagePath) {
17908
18007
  async function refuseDivergentPublishedNpmPack(deps, version) {
17909
18008
  let localBom;
17910
18009
  try {
17911
- localBom = JSON.parse((0, import_node_fs19.readFileSync)("distribution-bom.json", "utf8"));
18010
+ localBom = JSON.parse((0, import_node_fs20.readFileSync)("distribution-bom.json", "utf8"));
17912
18011
  } catch (e) {
17913
18012
  throw new Error(
17914
18013
  `version fold refused: distribution-bom.json written by this fold's prepare is unreadable (${e instanceof Error ? e.message.split("\n")[0] : String(e)}) \u2014 cannot compare the same-PATCH ${version} npm-pack identities against published npm (#4503/#4662).`
@@ -18053,7 +18152,7 @@ function assertGitBashOnWindowsForJervHubRelease(repo, platform2 = process.platf
18053
18152
  }
18054
18153
 
18055
18154
  // src/train-apply-correlation.ts
18056
- var import_node_fs21 = require("node:fs");
18155
+ var import_node_fs22 = require("node:fs");
18057
18156
  init_github_quota();
18058
18157
  var import_node_path19 = require("node:path");
18059
18158
 
@@ -18558,7 +18657,7 @@ function classifyRow(row) {
18558
18657
  } else if (row.onboarding.status === "unknown") {
18559
18658
  reasons.add(`canonical onboarding link evidence unknown: ${row.onboarding.detail}`);
18560
18659
  }
18561
- const releaseRequired = row.track !== "trunk" && !row.classifications.includes("no-deploy-surface");
18660
+ const releaseRequired = row.track !== "trunk" && row.track !== "single" && !row.classifications.includes("no-deploy-surface");
18562
18661
  const tagIsVersion = Boolean(row.release.version) && row.unknowns.some((u) => u.startsWith(NO_VERSION_LOCK_PREFIX));
18563
18662
  for (const unknown of row.unknowns) {
18564
18663
  if (!releaseRequired && unknown === NO_RELEASE_UNKNOWN) continue;
@@ -18820,10 +18919,10 @@ var rollout_plan_default = {
18820
18919
  note: "The v4.0.0 stamp happens at cut time (D6e #4463); until then the candidate is the origin/development head artifacts (built cli/dist + npm pack), identity proven by dist content hash (D6a)."
18821
18920
  },
18822
18921
  baseline: {
18823
- version: "4.5.159",
18824
- tag: "v4.5.159",
18825
- commit: "daaf02084d87",
18826
- npm: "@mutmutco/cli@4.5.159"
18922
+ version: "4.5.161",
18923
+ tag: "v4.5.161",
18924
+ commit: "236dbfae4af2",
18925
+ npm: "@mutmutco/cli@4.5.161"
18827
18926
  },
18828
18927
  exitCriterion: "fleet-n-of-n",
18829
18928
  hubOnlyShortcut: "forbidden",
@@ -18840,14 +18939,14 @@ var rollout_plan_default = {
18840
18939
  repo: "mutmutco/mmi-hub",
18841
18940
  role: "canary",
18842
18941
  schedule: "train",
18843
- v3Target: "v4.5.159"
18942
+ v3Target: "v4.5.161"
18844
18943
  }
18845
18944
  ],
18846
18945
  rollbackTrigger: "Any red inside the post-contract soak window: `devops train gate` FAIL attributable to the v4 doors, Hub endpoint health probe failure, a pre-v4 client admitted instead of receiving actionable HTTP 426, or npm consumer install/doctor failure on the v4-only dist.",
18847
18946
  rollback: {
18848
18947
  independent: true,
18849
- mechanism: "npm dist-tag latest -> 4.5.159 and redeploy the Hub Lambda from tag v4.5.159 (daaf02084d87); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
18850
- v3Target: "v4.5.159 (@mutmutco/cli@4.5.159, tag commit daaf02084d87 \u2014 last known-good release carrying the repo-index v4-only contract)"
18948
+ mechanism: "npm dist-tag latest -> 4.5.161 and redeploy the Hub Lambda from tag v4.5.161 (236dbfae4af2); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
18949
+ v3Target: "v4.5.161 (@mutmutco/cli@4.5.161, tag commit 236dbfae4af2 \u2014 last known-good release carrying the repo-index v4-only contract)"
18851
18950
  }
18852
18951
  },
18853
18952
  {
@@ -19181,13 +19280,13 @@ function resolveIssueViewGhFields(normalized) {
19181
19280
  }
19182
19281
 
19183
19282
  // src/utf8-receipt.ts
19184
- var import_node_fs20 = require("node:fs");
19283
+ var import_node_fs21 = require("node:fs");
19185
19284
  var import_node_path18 = require("node:path");
19186
19285
  function writeUtf8Receipt(path2, text) {
19187
- (0, import_node_fs20.mkdirSync)((0, import_node_path18.dirname)(path2), { recursive: true });
19286
+ (0, import_node_fs21.mkdirSync)((0, import_node_path18.dirname)(path2), { recursive: true });
19188
19287
  const body = text.endsWith("\n") ? text : `${text}
19189
19288
  `;
19190
- (0, import_node_fs20.writeFileSync)(path2, body, "utf8");
19289
+ (0, import_node_fs21.writeFileSync)(path2, body, "utf8");
19191
19290
  return Buffer.byteLength(body, "utf8");
19192
19291
  }
19193
19292
 
@@ -20138,7 +20237,7 @@ function buildFleetTrackInventory(projects, releaseProbes, pluginProbes, generat
20138
20237
  unknowns
20139
20238
  };
20140
20239
  });
20141
- const tracks = { full: 0, direct: 0, trunk: 0 };
20240
+ const tracks = { full: 0, direct: 0, trunk: 0, single: 0 };
20142
20241
  for (const row of repos) tracks[row.track] += 1;
20143
20242
  return {
20144
20243
  generatedAt,
@@ -20331,13 +20430,13 @@ var FLEET_LOCKSTEP_REF_INCLUDE = ["refs/heads/rc", "refs/heads/main"];
20331
20430
  var STATUS_DESCRIPTION_MAX = 140;
20332
20431
  function classifyFleetEnrollment(rows) {
20333
20432
  return rows.map((row) => {
20334
- if (row.track === "trunk") {
20433
+ if (row.track === "trunk" || row.track === "single") {
20335
20434
  return {
20336
20435
  repo: row.repo,
20337
20436
  track: row.track,
20338
20437
  deployModel: row.deployModel,
20339
20438
  enrolled: false,
20340
- reason: "excluded: trunk track has no release train \u2014 no rc/main surface exists to gate (declared shape, not an exemption from conformance: the fleet verdict still counts this repo)"
20439
+ reason: "excluded: trunk/single track has no release train \u2014 no rc/main surface exists to gate (declared shape, not an exemption from conformance: the fleet verdict still counts this repo)"
20341
20440
  };
20342
20441
  }
20343
20442
  const noDeploy = row.classifications.includes("no-deploy-surface");
@@ -21073,7 +21172,7 @@ function resolveReleaseAbortNpmPackage(meta, repo) {
21073
21172
  if (isHubControlRepo(repo)) return "@mutmutco/cli";
21074
21173
  const publishDir = typeof meta.publishDir === "string" && meta.publishDir.trim() ? meta.publishDir.trim() : ".";
21075
21174
  try {
21076
- const pkg = JSON.parse((0, import_node_fs21.readFileSync)((0, import_node_path19.join)(publishDir, "package.json"), "utf8"));
21175
+ const pkg = JSON.parse((0, import_node_fs22.readFileSync)((0, import_node_path19.join)(publishDir, "package.json"), "utf8"));
21077
21176
  const name = pkg.name?.trim();
21078
21177
  if (!name) throw new Error("missing name field");
21079
21178
  return name;
@@ -22009,7 +22108,7 @@ function parseVerifyBroker(stdout) {
22009
22108
  }
22010
22109
 
22011
22110
  // src/train-apply-deploy.ts
22012
- var import_node_fs22 = require("node:fs");
22111
+ var import_node_fs23 = require("node:fs");
22013
22112
  var import_node_os11 = require("node:os");
22014
22113
  var import_node_path20 = require("node:path");
22015
22114
 
@@ -22150,7 +22249,7 @@ function mmiGetRedeployCommand(repo) {
22150
22249
  }
22151
22250
  function readLocalLauncherVersion(root = process.cwd()) {
22152
22251
  try {
22153
- const raw = (0, import_node_fs22.readFileSync)((0, import_node_path20.join)(root, "cli", "package.json"), "utf8");
22252
+ const raw = (0, import_node_fs23.readFileSync)((0, import_node_path20.join)(root, "cli", "package.json"), "utf8");
22154
22253
  const version = JSON.parse(raw).version;
22155
22254
  return typeof version === "string" && version.trim() ? version.trim() : null;
22156
22255
  } catch {
@@ -22159,7 +22258,7 @@ function readLocalLauncherVersion(root = process.cwd()) {
22159
22258
  }
22160
22259
  function readServedChannelUrl(product = HUB_SERVED_PRODUCT, root = process.cwd()) {
22161
22260
  try {
22162
- const raw = (0, import_node_fs22.readFileSync)((0, import_node_path20.join)(root, "config", `product.${product}.json`), "utf8");
22261
+ const raw = (0, import_node_fs23.readFileSync)((0, import_node_path20.join)(root, "config", `product.${product}.json`), "utf8");
22163
22262
  const host = JSON.parse(raw).host;
22164
22263
  if (typeof host !== "string" || !host.trim()) return null;
22165
22264
  return `${host.trim().replace(/\/+$/, "")}/release/version`;
@@ -22593,13 +22692,13 @@ async function runTaggedJervGatewayLocalWrapper(deps, tag, tagSha) {
22593
22692
  const reason = error instanceof Error ? error.message : String(error);
22594
22693
  throw new Error(`could not extract ${JERV_GATEWAY_RELEASE_DEPLOY_SCRIPT} from tagged commit ${tagSha.slice(0, 12)}: ${reason}`);
22595
22694
  }
22596
- const dir = (0, import_node_fs22.mkdtempSync)((0, import_node_path20.join)((0, import_node_os11.tmpdir)(), "jerv-gateway-release-deploy-"));
22695
+ const dir = (0, import_node_fs23.mkdtempSync)((0, import_node_path20.join)((0, import_node_os11.tmpdir)(), "jerv-gateway-release-deploy-"));
22597
22696
  const extracted = (0, import_node_path20.join)(dir, "jerv-gateway-release-deploy.sh");
22598
22697
  try {
22599
- (0, import_node_fs22.writeFileSync)(extracted, script, "utf8");
22698
+ (0, import_node_fs23.writeFileSync)(extracted, script, "utf8");
22600
22699
  return await deps.run("bash", [extracted, "--tag", tag]);
22601
22700
  } finally {
22602
- (0, import_node_fs22.rmSync)(dir, { recursive: true, force: true });
22701
+ (0, import_node_fs23.rmSync)(dir, { recursive: true, force: true });
22603
22702
  }
22604
22703
  }
22605
22704
  async function appendJervGatewayReleaseDeploy(deps, repo, tag, tagSha, dispatch) {
@@ -23175,7 +23274,7 @@ function renderTenantControl(r) {
23175
23274
  }
23176
23275
 
23177
23276
  // src/train-apply-phases.ts
23178
- var import_node_fs28 = require("node:fs");
23277
+ var import_node_fs29 = require("node:fs");
23179
23278
  var import_promises4 = require("node:fs/promises");
23180
23279
  var import_node_path27 = require("node:path");
23181
23280
 
@@ -23494,12 +23593,12 @@ function assertPreOneZero(repo, meta, tag) {
23494
23593
 
23495
23594
  // src/train-doctor.ts
23496
23595
  var import_node_child_process9 = require("node:child_process");
23497
- var import_node_fs26 = require("node:fs");
23596
+ var import_node_fs27 = require("node:fs");
23498
23597
  var import_node_os15 = require("node:os");
23499
23598
  var import_node_path26 = require("node:path");
23500
23599
 
23501
23600
  // src/doctor-io.ts
23502
- var import_node_fs23 = require("node:fs");
23601
+ var import_node_fs24 = require("node:fs");
23503
23602
  var import_node_os12 = require("node:os");
23504
23603
  var import_node_path21 = require("node:path");
23505
23604
  var import_node_child_process7 = require("node:child_process");
@@ -23514,8 +23613,8 @@ function nodeDiscardSinkPath(platform2 = process.platform) {
23514
23613
  var execFileP2 = (0, import_node_util4.promisify)(import_node_child_process7.execFile);
23515
23614
  function execFileCapture(file, args, opts = {}) {
23516
23615
  const sink = nodeDiscardSinkPath();
23517
- const inFd = (0, import_node_fs23.openSync)(sink, "r");
23518
- const errFd = (0, import_node_fs23.openSync)(sink, "w");
23616
+ const inFd = (0, import_node_fs24.openSync)(sink, "r");
23617
+ const errFd = (0, import_node_fs24.openSync)(sink, "w");
23519
23618
  try {
23520
23619
  return (0, import_node_child_process7.execFileSync)(file, args, {
23521
23620
  ...opts,
@@ -23523,17 +23622,17 @@ function execFileCapture(file, args, opts = {}) {
23523
23622
  stdio: [inFd, "pipe", errFd]
23524
23623
  });
23525
23624
  } finally {
23526
- (0, import_node_fs23.closeSync)(inFd);
23527
- (0, import_node_fs23.closeSync)(errFd);
23625
+ (0, import_node_fs24.closeSync)(inFd);
23626
+ (0, import_node_fs24.closeSync)(errFd);
23528
23627
  }
23529
23628
  }
23530
23629
  var MMI_PLUGIN_ID2 = "mmi@mutmutco";
23531
23630
  function stagedClaudePluginVersion() {
23532
23631
  try {
23533
23632
  const stagingRoot = (0, import_node_path21.join)((0, import_node_os12.homedir)(), ".claude", "plugins", "staging");
23534
- const record = JSON.parse((0, import_node_fs23.readFileSync)((0, import_node_path21.join)(stagingRoot, "launch-target.json"), "utf8"));
23633
+ const record = JSON.parse((0, import_node_fs24.readFileSync)((0, import_node_path21.join)(stagingRoot, "launch-target.json"), "utf8"));
23535
23634
  if (typeof record.target !== "string" || typeof record.incoming !== "string") return void 0;
23536
- const manifest = JSON.parse((0, import_node_fs23.readFileSync)((0, import_node_path21.join)(record.incoming, ".claude-plugin", "plugin.json"), "utf8"));
23635
+ const manifest = JSON.parse((0, import_node_fs24.readFileSync)((0, import_node_path21.join)(record.incoming, ".claude-plugin", "plugin.json"), "utf8"));
23537
23636
  if (typeof manifest.version !== "string") return void 0;
23538
23637
  return manifest.version === record.target ? record.target : void 0;
23539
23638
  } catch {
@@ -23543,7 +23642,7 @@ function stagedClaudePluginVersion() {
23543
23642
  function installedClaudePluginVersion() {
23544
23643
  try {
23545
23644
  const file = JSON.parse(
23546
- (0, import_node_fs23.readFileSync)((0, import_node_path21.join)((0, import_node_os12.homedir)(), ".claude", "plugins", "installed_plugins.json"), "utf8")
23645
+ (0, import_node_fs24.readFileSync)((0, import_node_path21.join)((0, import_node_os12.homedir)(), ".claude", "plugins", "installed_plugins.json"), "utf8")
23547
23646
  );
23548
23647
  const versions = (file.plugins?.[MMI_PLUGIN_ID2] ?? []).map((r) => r.version).filter((v) => Boolean(v));
23549
23648
  if (versions.length === 0) return void 0;
@@ -23555,12 +23654,12 @@ function installedClaudePluginVersion() {
23555
23654
  function readHermesPluginEvidence(env = process.env) {
23556
23655
  const host = hermesConfigRoot(env);
23557
23656
  const root = hermesPluginRoot(env);
23558
- const installRecordPresent = (0, import_node_fs23.existsSync)(root);
23657
+ const installRecordPresent = (0, import_node_fs24.existsSync)(root);
23559
23658
  const manifestPath = (0, import_node_path21.join)(root, "plugin.yaml");
23560
23659
  let installedVersion;
23561
23660
  let manifest = "missing";
23562
23661
  try {
23563
- const text = (0, import_node_fs23.readFileSync)(manifestPath, "utf8");
23662
+ const text = (0, import_node_fs24.readFileSync)(manifestPath, "utf8");
23564
23663
  let version;
23565
23664
  try {
23566
23665
  const parsed = JSON.parse(text).version;
@@ -23574,25 +23673,25 @@ function readHermesPluginEvidence(env = process.env) {
23574
23673
  if (version) {
23575
23674
  installedVersion = version;
23576
23675
  manifest = "valid";
23577
- } else if ((0, import_node_fs23.existsSync)(manifestPath)) manifest = "invalid";
23676
+ } else if ((0, import_node_fs24.existsSync)(manifestPath)) manifest = "invalid";
23578
23677
  } catch {
23579
- if ((0, import_node_fs23.existsSync)(manifestPath)) manifest = "invalid";
23678
+ if ((0, import_node_fs24.existsSync)(manifestPath)) manifest = "invalid";
23580
23679
  }
23581
23680
  let skills = false;
23582
23681
  try {
23583
- skills = (0, import_node_fs23.existsSync)((0, import_node_path21.join)(root, "skills")) && (0, import_node_fs23.statSync)((0, import_node_path21.join)(root, "skills")).isDirectory();
23682
+ skills = (0, import_node_fs24.existsSync)((0, import_node_path21.join)(root, "skills")) && (0, import_node_fs24.statSync)((0, import_node_path21.join)(root, "skills")).isDirectory();
23584
23683
  } catch {
23585
23684
  }
23586
23685
  let provisioned = false;
23587
23686
  const provisionedRoot = (0, import_node_path21.join)(host, "skills", "mmi");
23588
23687
  try {
23589
- provisioned = (0, import_node_fs23.existsSync)(provisionedRoot) && (0, import_node_fs23.statSync)(provisionedRoot).isDirectory();
23688
+ provisioned = (0, import_node_fs24.existsSync)(provisionedRoot) && (0, import_node_fs24.statSync)(provisionedRoot).isDirectory();
23590
23689
  } catch {
23591
23690
  }
23592
- const treeOk = (0, import_node_fs23.existsSync)((0, import_node_path21.join)(root, "__init__.py")) && skills && manifest === "valid";
23691
+ const treeOk = (0, import_node_fs24.existsSync)((0, import_node_path21.join)(root, "__init__.py")) && skills && manifest === "valid";
23593
23692
  const receipt = treeOk && !provisioned ? `hermes-skills-unprovisioned:${provisionedRoot}` : void 0;
23594
23693
  return {
23595
- hostPresent: (0, import_node_fs23.existsSync)(host),
23694
+ hostPresent: (0, import_node_fs24.existsSync)(host),
23596
23695
  installRecordPresent,
23597
23696
  manifest,
23598
23697
  payloadPresent: treeOk && provisioned,
@@ -23644,7 +23743,7 @@ function readGitignore() {
23644
23743
  const path2 = gitignorePath();
23645
23744
  if (path2 === null) return null;
23646
23745
  try {
23647
- return (0, import_node_fs23.readFileSync)(path2, "utf8");
23746
+ return (0, import_node_fs24.readFileSync)(path2, "utf8");
23648
23747
  } catch {
23649
23748
  return null;
23650
23749
  }
@@ -23653,14 +23752,14 @@ function writeGitignore(content) {
23653
23752
  const path2 = gitignorePath();
23654
23753
  if (path2 === null) return false;
23655
23754
  try {
23656
- (0, import_node_fs23.writeFileSync)(path2, content, "utf8");
23755
+ (0, import_node_fs24.writeFileSync)(path2, content, "utf8");
23657
23756
  return true;
23658
23757
  } catch {
23659
23758
  return false;
23660
23759
  }
23661
23760
  }
23662
23761
  function lineEndingState(root) {
23663
- const attributesPresent = (0, import_node_fs23.existsSync)((0, import_node_path21.join)(root, ".gitattributes"));
23762
+ const attributesPresent = (0, import_node_fs24.existsSync)((0, import_node_path21.join)(root, ".gitattributes"));
23664
23763
  try {
23665
23764
  const output = execFileCapture("git", ["-C", root, "ls-files", "--eol", "--", ":(glob)**/*.sh"], {
23666
23765
  windowsHide: true
@@ -23703,7 +23802,7 @@ function compatHolds(range, version) {
23703
23802
  }
23704
23803
 
23705
23804
  // src/claude-binary-doctor.ts
23706
- var import_node_fs24 = require("node:fs");
23805
+ var import_node_fs25 = require("node:fs");
23707
23806
  var import_node_os14 = require("node:os");
23708
23807
  var import_node_path23 = require("node:path");
23709
23808
 
@@ -23813,16 +23912,16 @@ function globalNodeModulesRoots(host) {
23813
23912
  function readHead(path2) {
23814
23913
  let fd;
23815
23914
  try {
23816
- fd = (0, import_node_fs24.openSync)(path2, "r");
23915
+ fd = (0, import_node_fs25.openSync)(path2, "r");
23817
23916
  const buffer = new Uint8Array(MAGIC_HEAD_BYTES);
23818
- const read = (0, import_node_fs24.readSync)(fd, buffer, 0, MAGIC_HEAD_BYTES, 0);
23917
+ const read = (0, import_node_fs25.readSync)(fd, buffer, 0, MAGIC_HEAD_BYTES, 0);
23819
23918
  return buffer.subarray(0, read);
23820
23919
  } catch {
23821
23920
  return void 0;
23822
23921
  } finally {
23823
23922
  if (fd !== void 0) {
23824
23923
  try {
23825
- (0, import_node_fs24.closeSync)(fd);
23924
+ (0, import_node_fs25.closeSync)(fd);
23826
23925
  } catch {
23827
23926
  }
23828
23927
  }
@@ -23830,7 +23929,7 @@ function readHead(path2) {
23830
23929
  }
23831
23930
  function fileBytes(path2) {
23832
23931
  try {
23833
- return (0, import_node_fs24.statSync)(path2).size;
23932
+ return (0, import_node_fs25.statSync)(path2).size;
23834
23933
  } catch {
23835
23934
  return void 0;
23836
23935
  }
@@ -23844,13 +23943,13 @@ function readClaudeBinaryState(host = {}) {
23844
23943
  const arch = host.arch ?? process.arch;
23845
23944
  const magic = EXECUTABLE_MAGIC[platform2];
23846
23945
  if (!magic) return void 0;
23847
- const packageRoot = globalNodeModulesRoots(host).map((root) => (0, import_node_path23.join)(root, ...PACKAGE.split("/"))).find((dir) => (0, import_node_fs24.existsSync)((0, import_node_path23.join)(dir, "package.json")));
23946
+ const packageRoot = globalNodeModulesRoots(host).map((root) => (0, import_node_path23.join)(root, ...PACKAGE.split("/"))).find((dir) => (0, import_node_fs25.existsSync)((0, import_node_path23.join)(dir, "package.json")));
23848
23947
  if (!packageRoot) return void 0;
23849
23948
  const keys = platformPackageKeys(platform2, arch);
23850
23949
  const fallbackPackage = `${PACKAGE}-${keys[0]}`;
23851
23950
  let manifest;
23852
23951
  try {
23853
- manifest = JSON.parse((0, import_node_fs24.readFileSync)((0, import_node_path23.join)(packageRoot, "package.json"), "utf8"));
23952
+ manifest = JSON.parse((0, import_node_fs25.readFileSync)((0, import_node_path23.join)(packageRoot, "package.json"), "utf8"));
23854
23953
  } catch (e) {
23855
23954
  return {
23856
23955
  state: "unreadable",
@@ -23881,7 +23980,7 @@ function readClaudeBinaryState(host = {}) {
23881
23980
  (0, import_node_path23.join)(packageRoot, "node_modules", ...name.split("/"), binName),
23882
23981
  (0, import_node_path23.join)((0, import_node_path23.dirname)((0, import_node_path23.dirname)(packageRoot)), ...name.split("/"), binName)
23883
23982
  ];
23884
- const found = published.map((name) => ({ name, path: binIn(name).find((file) => (0, import_node_fs24.existsSync)(file)) })).find((c) => c.path);
23983
+ const found = published.map((name) => ({ name, path: binIn(name).find((file) => (0, import_node_fs25.existsSync)(file)) })).find((c) => c.path);
23885
23984
  const platformPackage = found?.name ?? published[0];
23886
23985
  let source;
23887
23986
  let sourceProblem;
@@ -23892,7 +23991,7 @@ function readClaudeBinaryState(host = {}) {
23892
23991
  } else {
23893
23992
  source = { path: found.path, bytes: fileBytes(found.path) ?? 0 };
23894
23993
  }
23895
- if (!(0, import_node_fs24.existsSync)(binPath)) {
23994
+ if (!(0, import_node_fs25.existsSync)(binPath)) {
23896
23995
  return { state: "missing", binPath, expectedMagic: magic.name, platformPackage, ...source ? { source } : {}, ...sourceProblem ? { sourceProblem } : {} };
23897
23996
  }
23898
23997
  const head = readHead(binPath);
@@ -23935,9 +24034,9 @@ function healClaudeBinary(host = {}, onStep) {
23935
24034
  const platform2 = host.platform ?? process.platform;
23936
24035
  const aside = `${probe.binPath}.stub-${Date.now()}`;
23937
24036
  let renamed = false;
23938
- if ((0, import_node_fs24.existsSync)(probe.binPath)) {
24037
+ if ((0, import_node_fs25.existsSync)(probe.binPath)) {
23939
24038
  try {
23940
- (0, import_node_fs24.renameSync)(probe.binPath, aside);
24039
+ (0, import_node_fs25.renameSync)(probe.binPath, aside);
23941
24040
  renamed = true;
23942
24041
  onStep?.(`renamed the stub aside: ${aside}`);
23943
24042
  } catch (e) {
@@ -23946,12 +24045,12 @@ function healClaudeBinary(host = {}, onStep) {
23946
24045
  }
23947
24046
  try {
23948
24047
  onStep?.(`copying ${probe.source.path} \u2192 ${probe.binPath} (${(probe.source.bytes / 1e6).toFixed(0)} MB)`);
23949
- (0, import_node_fs24.copyFileSync)(probe.source.path, probe.binPath);
23950
- if (platform2 !== "win32") (0, import_node_fs24.chmodSync)(probe.binPath, 493);
24048
+ (0, import_node_fs25.copyFileSync)(probe.source.path, probe.binPath);
24049
+ if (platform2 !== "win32") (0, import_node_fs25.chmodSync)(probe.binPath, 493);
23951
24050
  } catch (e) {
23952
24051
  if (renamed) {
23953
24052
  try {
23954
- (0, import_node_fs24.renameSync)(aside, probe.binPath);
24053
+ (0, import_node_fs25.renameSync)(aside, probe.binPath);
23955
24054
  } catch {
23956
24055
  return { ok: false, detail: `copy failed (${e.message}) and the stub could not be restored \u2014 the original is at ${aside}` };
23957
24056
  }
@@ -23965,7 +24064,7 @@ function healClaudeBinary(host = {}, onStep) {
23965
24064
  let kept = false;
23966
24065
  if (renamed) {
23967
24066
  try {
23968
- (0, import_node_fs24.rmSync)(aside);
24067
+ (0, import_node_fs25.rmSync)(aside);
23969
24068
  } catch {
23970
24069
  kept = true;
23971
24070
  }
@@ -24324,7 +24423,7 @@ function checkLineEndings(probe) {
24324
24423
  }
24325
24424
 
24326
24425
  // src/release-ledger.ts
24327
- var import_node_fs25 = require("node:fs");
24426
+ var import_node_fs26 = require("node:fs");
24328
24427
  var import_node_path25 = require("node:path");
24329
24428
  var import_node_crypto9 = require("node:crypto");
24330
24429
 
@@ -24499,8 +24598,8 @@ function attachOutputNote(note, suffix) {
24499
24598
  }
24500
24599
  function writeFailingLegOutput(artifactPath, output) {
24501
24600
  const fileLines = lastNonEmptyLines(output, LEDGER_OUTPUT_FILE_LINES);
24502
- (0, import_node_fs25.mkdirSync)((0, import_node_path25.dirname)(artifactPath), { recursive: true });
24503
- (0, import_node_fs25.writeFileSync)(artifactPath, `${fileLines.join("\n")}
24601
+ (0, import_node_fs26.mkdirSync)((0, import_node_path25.dirname)(artifactPath), { recursive: true });
24602
+ (0, import_node_fs26.writeFileSync)(artifactPath, `${fileLines.join("\n")}
24504
24603
  `, "utf8");
24505
24604
  const tail = fileLines.slice(-LEDGER_OUTPUT_NOTE_LINES).join("\n");
24506
24605
  const noteSuffix = truncate(`failing-leg output: ${artifactPath}
@@ -24668,7 +24767,7 @@ function resolvePrimaryGitDir(cwd) {
24668
24767
  }
24669
24768
  let common;
24670
24769
  try {
24671
- common = (0, import_node_fs25.readFileSync)((0, import_node_path25.join)(gitDir, "commondir"), "utf8").trim();
24770
+ common = (0, import_node_fs26.readFileSync)((0, import_node_path25.join)(gitDir, "commondir"), "utf8").trim();
24672
24771
  } catch (e) {
24673
24772
  if (e.code !== "ENOENT") {
24674
24773
  throw new ReleaseLedgerError("unreadable", `release ledger: the worktree gitdir's commondir pointer could not be READ (${e instanceof Error ? e.message : String(e)}) \u2014 a failed read is unverified, not primary (#5987/#4713)`);
@@ -24677,7 +24776,7 @@ function resolvePrimaryGitDir(cwd) {
24677
24776
  if (!common) return gitDir;
24678
24777
  const commonDir = (0, import_node_path25.isAbsolute)(common) ? common : (0, import_node_path25.resolve)(gitDir, common);
24679
24778
  try {
24680
- (0, import_node_fs25.readFileSync)((0, import_node_path25.join)(commonDir, "HEAD"), "utf8");
24779
+ (0, import_node_fs26.readFileSync)((0, import_node_path25.join)(commonDir, "HEAD"), "utf8");
24681
24780
  } catch (e) {
24682
24781
  throw new ReleaseLedgerError("no-checkout", `release ledger: the worktree's commondir pointer names ${commonDir}, which has no readable HEAD (${e instanceof Error ? e.message : String(e)}) \u2014 the primary checkout may have been removed; refusing to write the ledger into a doomed location`);
24683
24782
  }
@@ -24687,11 +24786,11 @@ function releaseLedgerPath(cwd) {
24687
24786
  return (0, import_node_path25.join)(resolvePrimaryGitDir(cwd), "mmi-runtime", "release", "phases.json");
24688
24787
  }
24689
24788
  function atomicWriteJson(path2, ledger) {
24690
- (0, import_node_fs25.mkdirSync)((0, import_node_path25.dirname)(path2), { recursive: true });
24789
+ (0, import_node_fs26.mkdirSync)((0, import_node_path25.dirname)(path2), { recursive: true });
24691
24790
  const tmp = `${path2}.tmp-${process.pid}-${(0, import_node_crypto9.randomBytes)(4).toString("hex")}`;
24692
- (0, import_node_fs25.writeFileSync)(tmp, `${JSON.stringify(ledger, null, 2)}
24791
+ (0, import_node_fs26.writeFileSync)(tmp, `${JSON.stringify(ledger, null, 2)}
24693
24792
  `, "utf8");
24694
- (0, import_node_fs25.renameSync)(tmp, path2);
24793
+ (0, import_node_fs26.renameSync)(tmp, path2);
24695
24794
  }
24696
24795
  var LEDGER_LOCK_OPTS = { label: "release ledger", staleMs: 18e4, deadHolderSteal: true };
24697
24796
  async function withLedgerLock(path2, fn, opts = {}) {
@@ -24738,7 +24837,7 @@ function describeTrainWriterToken(token) {
24738
24837
  function liveTrainWriterHolder(cwd) {
24739
24838
  let token;
24740
24839
  try {
24741
- token = (0, import_node_fs25.readFileSync)(trainWriterLockPath(cwd), "utf8");
24840
+ token = (0, import_node_fs26.readFileSync)(trainWriterLockPath(cwd), "utf8");
24742
24841
  } catch {
24743
24842
  return void 0;
24744
24843
  }
@@ -24760,7 +24859,7 @@ async function acquireTrainWriterLock(cwd, verb) {
24760
24859
  if (heldTrainWriter) heldTrainWriter.depth -= 1;
24761
24860
  };
24762
24861
  }
24763
- (0, import_node_fs25.mkdirSync)((0, import_node_path25.dirname)(lockPath), { recursive: true });
24862
+ (0, import_node_fs26.mkdirSync)((0, import_node_path25.dirname)(lockPath), { recursive: true });
24764
24863
  const opts = resolveFileLockOpts({ label: "train writer", staleMs: TRAIN_WRITER_STALE_MS, deadHolderSteal: true, maxWaitMs: 0, holder: verb });
24765
24864
  let guard;
24766
24865
  try {
@@ -24769,7 +24868,7 @@ async function acquireTrainWriterLock(cwd, verb) {
24769
24868
  if (!(e instanceof FileLockBusyError)) throw e;
24770
24869
  let token = "";
24771
24870
  try {
24772
- token = (0, import_node_fs25.readFileSync)(lockPath, "utf8");
24871
+ token = (0, import_node_fs26.readFileSync)(lockPath, "utf8");
24773
24872
  } catch {
24774
24873
  token = "";
24775
24874
  }
@@ -24804,7 +24903,7 @@ async function withReleaseLedger(path2, expected, fn, opts = {}) {
24804
24903
  let current;
24805
24904
  let raw;
24806
24905
  try {
24807
- raw = (0, import_node_fs25.readFileSync)(path2, "utf8");
24906
+ raw = (0, import_node_fs26.readFileSync)(path2, "utf8");
24808
24907
  } catch (e) {
24809
24908
  if (e.code !== "ENOENT") {
24810
24909
  throw new ReleaseLedgerError("unreadable", `release ledger at ${path2} could not be READ (${e instanceof Error ? e.message : String(e)}) \u2014 a failed read is unverified, not absent (#5987)`);
@@ -25473,7 +25572,7 @@ async function clearLedgerFile(path2, anchors, maxWaitMs) {
25473
25572
  return withLedgerLock(path2, async (fence) => {
25474
25573
  let raw;
25475
25574
  try {
25476
- raw = (0, import_node_fs25.readFileSync)(path2, "utf8");
25575
+ raw = (0, import_node_fs26.readFileSync)(path2, "utf8");
25477
25576
  } catch (e) {
25478
25577
  if (e.code === "ENOENT") return { cleared: false };
25479
25578
  return { cleared: false, note: `release ledger at ${path2} could not be read for clearing (${e instanceof Error ? e.message : String(e)}) \u2014 left in place` };
@@ -25489,7 +25588,7 @@ async function clearLedgerFile(path2, anchors, maxWaitMs) {
25489
25588
  } catch (e) {
25490
25589
  return { cleared: false, note: `release ledger at ${path2} belongs to ${ledger.tag} @ ${ledger.tagSha.slice(0, 12)} \u2014 not this release; left in place (${e instanceof Error ? e.message : String(e)})` };
25491
25590
  }
25492
- await fence(() => (0, import_node_fs25.unlinkSync)(path2));
25591
+ await fence(() => (0, import_node_fs26.unlinkSync)(path2));
25493
25592
  return { cleared: true, note: `cleared the release ledger at ${path2} for the live-proven aborted ${anchors.tag}` };
25494
25593
  }, { maxWaitMs });
25495
25594
  }
@@ -25649,7 +25748,7 @@ async function healStaleAlignmentLeg(deps, cwd, expected) {
25649
25748
  return withLedgerLock(path2, async (fence) => {
25650
25749
  let prior;
25651
25750
  try {
25652
- prior = parseReleaseLedger((0, import_node_fs25.readFileSync)(path2, "utf8"));
25751
+ prior = parseReleaseLedger((0, import_node_fs26.readFileSync)(path2, "utf8"));
25653
25752
  } catch {
25654
25753
  return void 0;
25655
25754
  }
@@ -25674,7 +25773,7 @@ async function healUnfoldedRunLegs(deps, cwd, model) {
25674
25773
  const path2 = releaseLedgerPath(cwd);
25675
25774
  let prior;
25676
25775
  try {
25677
- prior = parseReleaseLedger((0, import_node_fs25.readFileSync)(path2, "utf8"));
25776
+ prior = parseReleaseLedger((0, import_node_fs26.readFileSync)(path2, "utf8"));
25678
25777
  } catch {
25679
25778
  return void 0;
25680
25779
  }
@@ -25743,7 +25842,7 @@ async function supersedeContentCausedDeployLeg(deps, cwd) {
25743
25842
  return withLedgerLock(path2, async (fence) => {
25744
25843
  let prior;
25745
25844
  try {
25746
- prior = parseReleaseLedger((0, import_node_fs25.readFileSync)(path2, "utf8"));
25845
+ prior = parseReleaseLedger((0, import_node_fs26.readFileSync)(path2, "utf8"));
25747
25846
  } catch (e) {
25748
25847
  throw new ReleaseLedgerError(
25749
25848
  "unreadable",
@@ -25841,10 +25940,10 @@ async function proveOriginPromotionOrArchived(deps, prior, path2, label, ref, fe
25841
25940
  throw new Error(`${label}: origin no longer has ${prior.tag} but its GitHub Release still exists \u2014 resolve the mixed external state before closing the ledger; nothing was written (${ref})`);
25842
25941
  }
25843
25942
  const archivePath = (0, import_node_path25.join)((0, import_node_path25.dirname)(path2), `phases.archive-${prior.tag}.json`);
25844
- if ((0, import_node_fs25.existsSync)(archivePath)) {
25943
+ if ((0, import_node_fs26.existsSync)(archivePath)) {
25845
25944
  throw new Error(`${label}: archive already exists at ${archivePath} \u2014 preserving both ledger records; resolve the collision by hand; nothing was written (${ref})`);
25846
25945
  }
25847
- await fence(() => (0, import_node_fs25.renameSync)(path2, archivePath));
25946
+ await fence(() => (0, import_node_fs26.renameSync)(path2, archivePath));
25848
25947
  return "deleted";
25849
25948
  }
25850
25949
  async function supersedeContentCausedPublishLeg(deps, cwd) {
@@ -25852,7 +25951,7 @@ async function supersedeContentCausedPublishLeg(deps, cwd) {
25852
25951
  return withLedgerLock(path2, async (fence) => {
25853
25952
  let prior;
25854
25953
  try {
25855
- prior = parseReleaseLedger((0, import_node_fs25.readFileSync)(path2, "utf8"));
25954
+ prior = parseReleaseLedger((0, import_node_fs26.readFileSync)(path2, "utf8"));
25856
25955
  } catch (e) {
25857
25956
  throw new ReleaseLedgerError(
25858
25957
  "unreadable",
@@ -25934,7 +26033,7 @@ async function supersedeContentCausedDeployAndPublishLegs(deps, cwd) {
25934
26033
  return withLedgerLock(path2, async (fence) => {
25935
26034
  let prior;
25936
26035
  try {
25937
- prior = parseReleaseLedger((0, import_node_fs25.readFileSync)(path2, "utf8"));
26036
+ prior = parseReleaseLedger((0, import_node_fs26.readFileSync)(path2, "utf8"));
25938
26037
  } catch (e) {
25939
26038
  throw new ReleaseLedgerError(
25940
26039
  "unreadable",
@@ -26039,7 +26138,7 @@ async function supersedeContentCausedDeployAndPublishLegs(deps, cwd) {
26039
26138
  async function reverifyPriorRunLegs(deps, path2, targetTag) {
26040
26139
  let prior;
26041
26140
  try {
26042
- prior = parseReleaseLedger((0, import_node_fs25.readFileSync)(path2, "utf8"));
26141
+ prior = parseReleaseLedger((0, import_node_fs26.readFileSync)(path2, "utf8"));
26043
26142
  } catch {
26044
26143
  return;
26045
26144
  }
@@ -26059,7 +26158,7 @@ async function beginReleaseLedger(deps, cwd, targetTag) {
26059
26158
  return withLedgerLock(path2, async (fence) => {
26060
26159
  let raw;
26061
26160
  try {
26062
- raw = (0, import_node_fs25.readFileSync)(path2, "utf8");
26161
+ raw = (0, import_node_fs26.readFileSync)(path2, "utf8");
26063
26162
  } catch (e) {
26064
26163
  if (e.code === "ENOENT") return { ok: true };
26065
26164
  return { ok: false, error: `the release ledger at ${path2} could not be READ (${e instanceof Error ? e.message : String(e)}) \u2014 a failed read is unverified, not absent (#5987/#4713)` };
@@ -26099,13 +26198,13 @@ async function beginReleaseLedger(deps, cwd, targetTag) {
26099
26198
  }
26100
26199
  const archivePath = (0, import_node_path25.join)((0, import_node_path25.dirname)(path2), `phases.archive-${prior.tag}.json`);
26101
26200
  try {
26102
- await fence(() => (0, import_node_fs25.unlinkSync)(archivePath));
26201
+ await fence(() => (0, import_node_fs26.unlinkSync)(archivePath));
26103
26202
  } catch (e) {
26104
26203
  if (e.code !== "ENOENT") {
26105
26204
  return { ok: false, error: `could not clear the stale archive at ${archivePath} (${e instanceof Error ? e.message : String(e)}) \u2014 the ledger for ${prior.tag} stays active (#5987)` };
26106
26205
  }
26107
26206
  }
26108
- await fence(() => (0, import_node_fs25.renameSync)(path2, archivePath));
26207
+ await fence(() => (0, import_node_fs26.renameSync)(path2, archivePath));
26109
26208
  return { ok: true, note: `archived the completed release ledger ${prior.tag} to ${archivePath} (live-proven at ${prior.tagSha.slice(0, 12)})` };
26110
26209
  });
26111
26210
  }
@@ -26133,7 +26232,7 @@ async function retryHotfixDeployLegs(deps, cwd, opts = {}) {
26133
26232
  return withLedgerLock(path2, async (fence) => {
26134
26233
  let prior;
26135
26234
  try {
26136
- prior = parseReleaseLedger((0, import_node_fs25.readFileSync)(path2, "utf8"));
26235
+ prior = parseReleaseLedger((0, import_node_fs26.readFileSync)(path2, "utf8"));
26137
26236
  } catch (e) {
26138
26237
  throw new ReleaseLedgerError(
26139
26238
  "unreadable",
@@ -26326,10 +26425,10 @@ function readOriginWorkflowsDefault(root, ref) {
26326
26425
  }
26327
26426
  var NPM_REGISTRY = "https://registry.npmjs.org";
26328
26427
  async function probeRegistryWhoami(train) {
26329
- const dir = (0, import_node_fs26.mkdtempSync)((0, import_node_path26.join)((0, import_node_os15.tmpdir)(), "mmi-npmrc-"));
26428
+ const dir = (0, import_node_fs27.mkdtempSync)((0, import_node_path26.join)((0, import_node_os15.tmpdir)(), "mmi-npmrc-"));
26330
26429
  const rc = (0, import_node_path26.join)(dir, "npmrc");
26331
26430
  try {
26332
- (0, import_node_fs26.writeFileSync)(rc, "//registry.npmjs.org/:_authToken=${NPM_TOKEN}\n");
26431
+ (0, import_node_fs27.writeFileSync)(rc, "//registry.npmjs.org/:_authToken=${NPM_TOKEN}\n");
26333
26432
  await train.runSelf(["secrets", "use", "npm/NPM_TOKEN", "--slug", "_org", "--", "npm", "whoami", "--registry", NPM_REGISTRY, "--userconfig", rc]);
26334
26433
  return { kind: "ok", detail: "the registry answered a login" };
26335
26434
  } catch (e) {
@@ -26340,7 +26439,7 @@ async function probeRegistryWhoami(train) {
26340
26439
  if (/\bE401\b|401 Unauthorized/.test(stderr)) return { kind: "rejected", detail: "npm whoami answered 401 Unauthorized" };
26341
26440
  return { kind: "unverified", detail: first };
26342
26441
  } finally {
26343
- (0, import_node_fs26.rmSync)(dir, { recursive: true, force: true });
26442
+ (0, import_node_fs27.rmSync)(dir, { recursive: true, force: true });
26344
26443
  }
26345
26444
  }
26346
26445
  var REGISTRY_TOKEN_ENV = /\b(NODE_AUTH_TOKEN|NPM_TOKEN)\b/;
@@ -26358,7 +26457,7 @@ var defaultDeps2 = {
26358
26457
  ledgerPath: releaseLedgerPath,
26359
26458
  readLedgerRaw: (path2) => {
26360
26459
  try {
26361
- return (0, import_node_fs26.readFileSync)(path2, "utf8");
26460
+ return (0, import_node_fs27.readFileSync)(path2, "utf8");
26362
26461
  } catch (e) {
26363
26462
  if (e.code === "ENOENT") return void 0;
26364
26463
  throw e;
@@ -26369,7 +26468,7 @@ var defaultDeps2 = {
26369
26468
  trainWriterHolder: liveTrainWriterHolder,
26370
26469
  readSurfacesRaw: (cwd) => {
26371
26470
  try {
26372
- return (0, import_node_fs26.readFileSync)((0, import_node_path26.join)(cwd, "surfaces.json"), "utf8");
26471
+ return (0, import_node_fs27.readFileSync)((0, import_node_path26.join)(cwd, "surfaces.json"), "utf8");
26373
26472
  } catch {
26374
26473
  return void 0;
26375
26474
  }
@@ -27008,7 +27107,7 @@ function formatTrainDoctor(v) {
27008
27107
 
27009
27108
  // src/release-plain-words.ts
27010
27109
  var import_promises3 = require("node:fs/promises");
27011
- var import_node_fs27 = require("node:fs");
27110
+ var import_node_fs28 = require("node:fs");
27012
27111
  function releaseCutByNotes(cutBy) {
27013
27112
  return `## Internal
27014
27113
  Cut by ${formatSessionIdentity(cutBy)}
@@ -27114,7 +27213,7 @@ function validateSuiteReleaseSummary(path2, pathTr) {
27114
27213
  for (const [lang, file] of files) {
27115
27214
  let content;
27116
27215
  try {
27117
- content = (0, import_node_fs27.readFileSync)(file, "utf8");
27216
+ content = (0, import_node_fs28.readFileSync)(file, "utf8");
27118
27217
  } catch (e) {
27119
27218
  throw new Error(`could not read summary file ${file}: ${e.message} \u2014 see ${SUMMARY_GUIDE}`);
27120
27219
  }
@@ -27329,14 +27428,14 @@ function readLocalGateWorkflows() {
27329
27428
  const dir = (0, import_node_path27.join)(".github", "workflows");
27330
27429
  let names;
27331
27430
  try {
27332
- names = (0, import_node_fs28.readdirSync)(dir);
27431
+ names = (0, import_node_fs29.readdirSync)(dir);
27333
27432
  } catch {
27334
27433
  return null;
27335
27434
  }
27336
27435
  const files = [];
27337
27436
  for (const name of names.filter(isGateWorkflowPath)) {
27338
27437
  try {
27339
- files.push({ path: `${dir}/${name}`.replace(/\\/g, "/"), body: (0, import_node_fs28.readFileSync)((0, import_node_path27.join)(dir, name), "utf8") });
27438
+ files.push({ path: `${dir}/${name}`.replace(/\\/g, "/"), body: (0, import_node_fs29.readFileSync)((0, import_node_path27.join)(dir, name), "utf8") });
27340
27439
  } catch {
27341
27440
  }
27342
27441
  }
@@ -27346,14 +27445,14 @@ function readLocalWorkflows() {
27346
27445
  const dir = (0, import_node_path27.join)(".github", "workflows");
27347
27446
  let names;
27348
27447
  try {
27349
- names = (0, import_node_fs28.readdirSync)(dir);
27448
+ names = (0, import_node_fs29.readdirSync)(dir);
27350
27449
  } catch {
27351
27450
  return null;
27352
27451
  }
27353
27452
  const files = [];
27354
27453
  for (const name of names.filter((n) => /\.ya?ml$/i.test(n))) {
27355
27454
  try {
27356
- files.push({ path: `${dir}/${name}`.replace(/\\/g, "/"), body: (0, import_node_fs28.readFileSync)((0, import_node_path27.join)(dir, name), "utf8") });
27455
+ files.push({ path: `${dir}/${name}`.replace(/\\/g, "/"), body: (0, import_node_fs29.readFileSync)((0, import_node_path27.join)(dir, name), "utf8") });
27357
27456
  } catch {
27358
27457
  }
27359
27458
  }
@@ -27390,6 +27489,7 @@ async function preflight(deps, ctx, stage, meta, lane) {
27390
27489
  if (model === "content") {
27391
27490
  throw new Error(`${ctx.repo} is a content repo (deployModel=content) \u2014 the release train does not apply (trunk-based; PR to main)`);
27392
27491
  }
27492
+ if (meta.releaseTrack === "single") throw new Error("single-track repos ship on merge; there is no release train");
27393
27493
  if (model === "none") {
27394
27494
  throw new Error(`${ctx.repo} is not Hub-deployed (deployModel=none) \u2014 the release train does not apply; use the project's own release path`);
27395
27495
  }
@@ -28235,7 +28335,7 @@ async function activeRcandLedgerCandidate(deps, cwd) {
28235
28335
  }
28236
28336
  let prior;
28237
28337
  try {
28238
- prior = parseReleaseLedger((0, import_node_fs28.readFileSync)(path2, "utf8"));
28338
+ prior = parseReleaseLedger((0, import_node_fs29.readFileSync)(path2, "utf8"));
28239
28339
  } catch {
28240
28340
  return void 0;
28241
28341
  }
@@ -29638,9 +29738,9 @@ function rulesetCoversReleaseBranches(payload, track) {
29638
29738
  const conditions = payload.conditions;
29639
29739
  const include = conditions?.ref_name?.include;
29640
29740
  if (!Array.isArray(include)) {
29641
- return track === "full" || track === "direct" || track === "trunk";
29741
+ return track === "full" || track === "direct" || track === "trunk" || track === "single";
29642
29742
  }
29643
- const releaseRefs = track === "full" ? ["refs/heads/rc", "refs/heads/main"] : ["refs/heads/main"];
29743
+ const releaseRefs = track === "full" ? ["refs/heads/rc", "refs/heads/main"] : track === "single" ? ["refs/heads/development"] : ["refs/heads/main"];
29644
29744
  return include.some((entry) => typeof entry === "string" && (entry === "~DEFAULT_BRANCH" ? track === "trunk" : releaseRefs.some((ref) => refPatternCovers(entry, ref))));
29645
29745
  }
29646
29746
  function releaseBranchRefsCovered(conditions, track) {
@@ -30851,7 +30951,7 @@ var PRIMARY_GROUPS = [
30851
30951
  ["Setup and support", ["bootstrap", "secrets", "docs", "tests", "spawn", "dist"]],
30852
30952
  ["Coordinate and improve", ["wave", "report", "skill-lesson", "closure-rate"]]
30853
30953
  ];
30854
- var OPERATIONAL_TOP_LEVEL = /* @__PURE__ */ new Set(["org", "runtime", "plugin", "packages", "archive-prune"]);
30954
+ var OPERATIONAL_TOP_LEVEL = /* @__PURE__ */ new Set(["org", "runtime", "plugin", "packages", "github", "archive-prune"]);
30855
30955
  var CAMPAIGN_ORCHESTRATOR_TOP_LEVEL = /* @__PURE__ */ new Set(["pickup", "read"]);
30856
30956
  var SUPPORT_PRIMARY = /* @__PURE__ */ new Set(["doctor", "whoami", "commands", "explain", "docs", "tests", "spawn", "dist", "wave", "report", "skill-lesson", "closure-rate"]);
30857
30957
  var TOP_LEVEL_ORDER = /* @__PURE__ */ new Map();
@@ -30892,6 +30992,7 @@ var COMMAND_OWNERSHIP = {
30892
30992
  stage: { module_owner: "cli/src/stage-commands.ts", consumer: "agent-workflow" },
30893
30993
  pr: { module_owner: "cli/src/pr-commands.ts", consumer: "agent-workflow" },
30894
30994
  api: { module_owner: "cli/src/api-read.ts", consumer: "agent-workflow" },
30995
+ github: { module_owner: "cli/src/github-budget.ts", consumer: "release-operator" },
30895
30996
  read: { module_owner: "cli/src/app-read-broker.ts", consumer: "agent-workflow" },
30896
30997
  ci: { module_owner: "cli/src/ci-audit.ts", consumer: "release-operator" },
30897
30998
  rcand: { module_owner: "cli/src/train-commands.ts", consumer: "release-operator" },
@@ -31631,6 +31732,55 @@ function renderPluginCachePlan(plan, applied) {
31631
31732
  return lines2.join("\n");
31632
31733
  }
31633
31734
 
31735
+ // src/github-budget.ts
31736
+ init_cli_shared();
31737
+ function allowance(value) {
31738
+ const v = value;
31739
+ 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;
31740
+ }
31741
+ async function readGithubBudget(deps) {
31742
+ async function read(token) {
31743
+ try {
31744
+ const credential = await token();
31745
+ if (!credential) throw new Error("No identity");
31746
+ const res = await deps.fetch("https://api.github.com/rate_limit", {
31747
+ method: "GET",
31748
+ headers: { authorization: `Bearer ${credential}`, accept: "application/vnd.github+json", "user-agent": "mmi-cli" }
31749
+ });
31750
+ if (!res.ok) throw new Error("Unreadable");
31751
+ const body = await res.json();
31752
+ return { core: allowance(body.resources?.core), graphql: allowance(body.resources?.graphql) };
31753
+ } catch {
31754
+ return { core: null, graphql: null };
31755
+ }
31756
+ }
31757
+ const [personal, app1, app2] = await Promise.all([
31758
+ read(async () => {
31759
+ const env = { ...process.env };
31760
+ delete env.GH_TOKEN;
31761
+ delete env.GITHUB_TOKEN;
31762
+ return (await execFileP("gh", ["auth", "token"], { env })).stdout.trim();
31763
+ }),
31764
+ ...APP_POOL_MEMBERS.map((keys) => read(async () => (await mintBudgetToken(deps, keys)).token))
31765
+ ]);
31766
+ const pools = { personal, app1, app2 };
31767
+ const count = (v) => v ? `${v.remaining}/${v.limit}` : "unknown";
31768
+ const resets = [...new Set(Object.values(pools).flatMap((pool) => [pool.core, pool.graphql]).filter((v) => v !== null).map((v) => new Intl.DateTimeFormat("en-GB", {
31769
+ timeZone: "Europe/Istanbul",
31770
+ hour: "2-digit",
31771
+ minute: "2-digit",
31772
+ hourCycle: "h23"
31773
+ }).format(new Date(v.reset * 1e3))))].sort();
31774
+ 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)`;
31775
+ return { ...pools, line };
31776
+ }
31777
+ function registerGithubBudgetCommand(program3, deps) {
31778
+ 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) => {
31779
+ const budget = await readGithubBudget(deps());
31780
+ console.log(options.json ? JSON.stringify(budget, null, 2) : budget.line);
31781
+ });
31782
+ }
31783
+
31634
31784
  // src/board-commands.ts
31635
31785
  init_cli_shared();
31636
31786
 
@@ -32132,7 +32282,7 @@ function registerBoardCommands(program3) {
32132
32282
  }
32133
32283
 
32134
32284
  // src/bootstrap-commands.ts
32135
- var import_node_fs32 = require("node:fs");
32285
+ var import_node_fs33 = require("node:fs");
32136
32286
  var import_node_os18 = require("node:os");
32137
32287
  var import_node_path31 = require("node:path");
32138
32288
  init_cli_shared();
@@ -32318,7 +32468,7 @@ init_github_client();
32318
32468
  init_cli_shared();
32319
32469
 
32320
32470
  // src/port-registry.ts
32321
- var import_node_fs29 = require("node:fs");
32471
+ var import_node_fs30 = require("node:fs");
32322
32472
  var import_node_path28 = require("node:path");
32323
32473
 
32324
32474
  // ../infra/port-geometry.mjs
@@ -32333,8 +32483,8 @@ function nextPortBlock(registry2) {
32333
32483
  return [base, base + PORT_SPAN];
32334
32484
  }
32335
32485
  function loadPortRegistry(path2) {
32336
- if (!(0, import_node_fs29.existsSync)(path2)) return {};
32337
- const raw = JSON.parse((0, import_node_fs29.readFileSync)(path2, "utf8"));
32486
+ if (!(0, import_node_fs30.existsSync)(path2)) return {};
32487
+ const raw = JSON.parse((0, import_node_fs30.readFileSync)(path2, "utf8"));
32338
32488
  const out = {};
32339
32489
  for (const [key, value] of Object.entries(raw)) {
32340
32490
  if (Array.isArray(value) && value.length === 2 && value.every((n) => typeof n === "number")) {
@@ -32364,7 +32514,7 @@ function existingPortRange(repo, registry2) {
32364
32514
  function portRangeInfraAt(root, source) {
32365
32515
  const registryPath = (0, import_node_path28.join)(root, "infra", "port-ranges.json");
32366
32516
  const ddbScriptPath = (0, import_node_path28.join)(root, "infra", "port-ddb.mjs");
32367
- if (!(0, import_node_fs29.existsSync)(registryPath) || !(0, import_node_fs29.existsSync)(ddbScriptPath)) return null;
32517
+ if (!(0, import_node_fs30.existsSync)(registryPath) || !(0, import_node_fs30.existsSync)(ddbScriptPath)) return null;
32368
32518
  return { root, source, registryPath, ddbScriptPath };
32369
32519
  }
32370
32520
  function resolvePortRangeInfra(cwd, packageDir) {
@@ -32446,7 +32596,7 @@ async function assignPersistedPortRange(repo, slug, reg, opts) {
32446
32596
  }
32447
32597
 
32448
32598
  // src/box-commands.ts
32449
- var import_node_fs31 = require("node:fs");
32599
+ var import_node_fs32 = require("node:fs");
32450
32600
  var import_node_child_process10 = require("node:child_process");
32451
32601
  var import_node_os17 = require("node:os");
32452
32602
  var import_node_path30 = require("node:path");
@@ -32580,7 +32730,7 @@ function applyRemoteScript(items, date) {
32580
32730
  init_clean_exit();
32581
32731
 
32582
32732
  // src/secrets-commands.ts
32583
- var import_node_fs30 = require("node:fs");
32733
+ var import_node_fs31 = require("node:fs");
32584
32734
  var import_node_path29 = require("node:path");
32585
32735
  var import_node_os16 = require("node:os");
32586
32736
  init_cli_shared();
@@ -33730,8 +33880,8 @@ async function decryptRailsCredentials(input) {
33730
33880
  MMI_RAILS_CREDENTIALS_FILE: credentialsPath,
33731
33881
  MMI_RAILS_MASTER_KEY_FILE: masterKeyPath
33732
33882
  };
33733
- if ((0, import_node_fs30.existsSync)(masterKeyPath)) {
33734
- env.RAILS_MASTER_KEY = (0, import_node_fs30.readFileSync)(masterKeyPath, "utf8").trim();
33883
+ if ((0, import_node_fs31.existsSync)(masterKeyPath)) {
33884
+ env.RAILS_MASTER_KEY = (0, import_node_fs31.readFileSync)(masterKeyPath, "utf8").trim();
33735
33885
  }
33736
33886
  const script = [
33737
33887
  'require "json"',
@@ -33741,9 +33891,9 @@ async function decryptRailsCredentials(input) {
33741
33891
  'config = ActiveSupport::EncryptedConfiguration.new(config_path: config_path, key_path: key_path, env_key: "RAILS_MASTER_KEY", raise_if_missing_key: true)',
33742
33892
  "puts JSON.generate(config.config)"
33743
33893
  ].join("\n");
33744
- const scriptDir = (0, import_node_fs30.mkdtempSync)((0, import_node_path29.join)((0, import_node_os16.tmpdir)(), "mmi-rails-decrypt-"));
33894
+ const scriptDir = (0, import_node_fs31.mkdtempSync)((0, import_node_path29.join)((0, import_node_os16.tmpdir)(), "mmi-rails-decrypt-"));
33745
33895
  const scriptPath = (0, import_node_path29.join)(scriptDir, "decrypt.rb");
33746
- (0, import_node_fs30.writeFileSync)(scriptPath, script, "utf8");
33896
+ (0, import_node_fs31.writeFileSync)(scriptPath, script, "utf8");
33747
33897
  try {
33748
33898
  const args = ["exec", "ruby", scriptPath];
33749
33899
  const cmd = process.platform === "win32" ? "cmd.exe" : "bundle";
@@ -33755,7 +33905,7 @@ async function decryptRailsCredentials(input) {
33755
33905
  });
33756
33906
  return JSON.parse(stdout);
33757
33907
  } finally {
33758
- (0, import_node_fs30.rmSync)(scriptDir, { recursive: true, force: true });
33908
+ (0, import_node_fs31.rmSync)(scriptDir, { recursive: true, force: true });
33759
33909
  }
33760
33910
  }
33761
33911
  async function readSecretStdin() {
@@ -33845,7 +33995,7 @@ function registerSecretsCommands(program3) {
33845
33995
  let body;
33846
33996
  if (o.file) {
33847
33997
  try {
33848
- body = (0, import_node_fs30.readFileSync)((0, import_node_path29.resolve)(o.file), "utf8");
33998
+ body = (0, import_node_fs31.readFileSync)((0, import_node_path29.resolve)(o.file), "utf8");
33849
33999
  } catch (e) {
33850
34000
  return fail(`secrets org-catalog: cannot read --file ${o.file}: ${e.message}`);
33851
34001
  }
@@ -33981,7 +34131,7 @@ function registerSecretsCommands(program3) {
33981
34131
  {
33982
34132
  ...d,
33983
34133
  decryptRailsCredentials,
33984
- removeFile: (path2) => (0, import_node_fs30.unlinkSync)((0, import_node_path29.resolve)(o.appDir ?? process.cwd(), path2))
34134
+ removeFile: (path2) => (0, import_node_fs31.unlinkSync)((0, import_node_path29.resolve)(o.appDir ?? process.cwd(), path2))
33985
34135
  },
33986
34136
  {
33987
34137
  repo: o.repo,
@@ -34237,7 +34387,7 @@ function registerBoxCommands(program3) {
34237
34387
  }
34238
34388
  const remote = command && command.length ? command.join(" ") : void 0;
34239
34389
  const wroteScript = o.ssh && o.script ? o.script : null;
34240
- if (wroteScript) (0, import_node_fs31.writeFileSync)(wroteScript, sshRecipeScript(found, remote), "utf8");
34390
+ if (wroteScript) (0, import_node_fs32.writeFileSync)(wroteScript, sshRecipeScript(found, remote), "utf8");
34241
34391
  if (o.json) {
34242
34392
  console.log(JSON.stringify({
34243
34393
  box: found,
@@ -34311,17 +34461,17 @@ function hubGitShow(ref) {
34311
34461
  return (path2) => git3(["show", `${ref}:${path2}`]);
34312
34462
  }
34313
34463
  function runOnBox(found, script) {
34314
- const dir = (0, import_node_fs31.mkdtempSync)((0, import_node_path30.join)((0, import_node_os17.tmpdir)(), "mmi-box-control-"));
34464
+ const dir = (0, import_node_fs32.mkdtempSync)((0, import_node_path30.join)((0, import_node_os17.tmpdir)(), "mmi-box-control-"));
34315
34465
  try {
34316
34466
  const recipe = (0, import_node_path30.join)(dir, "recipe.sh");
34317
- (0, import_node_fs31.writeFileSync)(recipe, sshRecipeScript(found, "sh -s"), "utf8");
34467
+ (0, import_node_fs32.writeFileSync)(recipe, sshRecipeScript(found, "sh -s"), "utf8");
34318
34468
  const r = (0, import_node_child_process10.spawnSync)("bash", [recipe], { input: script, encoding: "utf8", maxBuffer: 16 * 1024 * 1024, timeout: 18e4, windowsHide: true });
34319
34469
  if (r.status !== 0) {
34320
34470
  throw new UnreadableError(`box control: the ssh session to ${found.name} failed (exit ${r.status ?? r.signal}): ${(r.stderr || "").trim().split("\n").slice(-3).join(" | ")}`);
34321
34471
  }
34322
34472
  return r.stdout;
34323
34473
  } finally {
34324
- (0, import_node_fs31.rmSync)(dir, { recursive: true, force: true });
34474
+ (0, import_node_fs32.rmSync)(dir, { recursive: true, force: true });
34325
34475
  }
34326
34476
  }
34327
34477
  function formatControl(mode, box, rows) {
@@ -34766,6 +34916,10 @@ function classifyEnvironmentDrift(drift) {
34766
34916
  }
34767
34917
  var TRACK_ENVIRONMENT_EXCEPTIONS = {
34768
34918
  direct: { rc: "direct release track has no rc stage" },
34919
+ single: {
34920
+ rc: "single release track has no rc stage",
34921
+ main: "single release track has no main branch; merges deploy the one stage"
34922
+ },
34769
34923
  trunk: {
34770
34924
  dev: "trunk release track has no dev stage",
34771
34925
  rc: "trunk release track has no rc stage"
@@ -34934,6 +35088,7 @@ function branchProtectionPayload(current, owners, app = LOCKED_APP) {
34934
35088
  }
34935
35089
  function deployStagesForBootstrap(deployModel, track) {
34936
35090
  if (deployModel !== "tenant-container" && deployModel !== "solo-container") return [];
35091
+ if (track === "single") return ["main"];
34937
35092
  return branchesForTrack(track).map((branch) => branch === "development" ? "dev" : branch);
34938
35093
  }
34939
35094
  function bootstrapSetDeployCommand(repo, stage, deployModel) {
@@ -35956,12 +36111,12 @@ async function verifyTargetedSeedPr(repo, number, plan, target, expected, client
35956
36111
  // src/bootstrap-commands.ts
35957
36112
  var execGitForSeedSource = async (args) => (await execFileP("git", args, { timeout: GIT_TIMEOUT_MS })).stdout;
35958
36113
  async function gateRenderDiff(current, rendered) {
35959
- const dir = (0, import_node_fs32.mkdtempSync)((0, import_node_path31.join)((0, import_node_os18.tmpdir)(), "mmi-gate-diff-"));
36114
+ const dir = (0, import_node_fs33.mkdtempSync)((0, import_node_path31.join)((0, import_node_os18.tmpdir)(), "mmi-gate-diff-"));
35960
36115
  const before = (0, import_node_path31.join)(dir, "committed-gate.yml");
35961
36116
  const after = (0, import_node_path31.join)(dir, "registry-render.yml");
35962
36117
  try {
35963
- (0, import_node_fs32.writeFileSync)(before, current);
35964
- (0, import_node_fs32.writeFileSync)(after, rendered);
36118
+ (0, import_node_fs33.writeFileSync)(before, current);
36119
+ (0, import_node_fs33.writeFileSync)(after, rendered);
35965
36120
  try {
35966
36121
  return (await execFileP("git", ["diff", "--no-index", "--", before, after], { timeout: GIT_TIMEOUT_MS })).stdout;
35967
36122
  } catch (e) {
@@ -35970,7 +36125,7 @@ async function gateRenderDiff(current, rendered) {
35970
36125
  throw e;
35971
36126
  }
35972
36127
  } finally {
35973
- (0, import_node_fs32.rmSync)(dir, { recursive: true, force: true });
36128
+ (0, import_node_fs33.rmSync)(dir, { recursive: true, force: true });
35974
36129
  }
35975
36130
  }
35976
36131
  function bootstrapTrainDoctorDeps() {
@@ -36030,13 +36185,13 @@ function registerBootstrapCommands(program3) {
36030
36185
  })),
36031
36186
  pushAllowlistOwners: verifyOwners,
36032
36187
  pushAllowlistOwnersRead: verifyOwnersRead,
36033
- readLocalFile: (path2) => path2 === "projects.json" && apiProjects != null ? apiProjects : (0, import_node_fs32.existsSync)(path2) ? (0, import_node_fs32.readFileSync)(path2, "utf8") : null,
36188
+ readLocalFile: (path2) => path2 === "projects.json" && apiProjects != null ? apiProjects : (0, import_node_fs33.existsSync)(path2) ? (0, import_node_fs33.readFileSync)(path2, "utf8") : null,
36034
36189
  // requiredGcpApis is stored as an array by a JSON write, but `org project set --var KEY=VALUE` stores a raw
36035
36190
  // comma-string — accept either so the seeded value verifies regardless of how it was written.
36036
36191
  // #3689: the same committed map the org access audit reads (#3664), so a sanctioned admin is not a
36037
36192
  // permanent bootstrap failure on one surface and an intended state on the other. Absent file → no
36038
36193
  // sanction, which is the pre-#3664 behaviour.
36039
- sanctionedAdmins: (0, import_node_fs32.existsSync)("access-matrix.json") ? entriesValueByCanonicalRepo(loadSanctionedAdmins((0, import_node_fs32.readFileSync)("access-matrix.json", "utf8")), repo) : void 0,
36194
+ sanctionedAdmins: (0, import_node_fs33.existsSync)("access-matrix.json") ? entriesValueByCanonicalRepo(loadSanctionedAdmins((0, import_node_fs33.readFileSync)("access-matrix.json", "utf8")), repo) : void 0,
36040
36195
  requiredGcpApis: (() => {
36041
36196
  const v = meta?.requiredGcpApis;
36042
36197
  if (Array.isArray(v)) return v;
@@ -36114,14 +36269,14 @@ function registerBootstrapCommands(program3) {
36114
36269
  bootstrap.command("drift").description("#3818: compare every org-owned whole-file seed against MMI-Hub's copy across the registry roster; read-only").option("--repo <owner/repo>", "audit one repo instead of the roster (never a fleet verdict)").option("--json", "machine-readable output").action(async () => {
36115
36270
  const o = { repo: rawValue("--repo", ""), json: rawFlag("--json") };
36116
36271
  const manifestPath = "skills/bootstrap/seeds/manifest.json";
36117
- if (!(0, import_node_fs32.existsSync)(manifestPath)) return fail(`bootstrap drift: ${manifestPath} not found; run from the MMI-Hub repo root \u2014 the Hub's copies ARE the reference this compares against`);
36272
+ if (!(0, import_node_fs33.existsSync)(manifestPath)) return fail(`bootstrap drift: ${manifestPath} not found; run from the MMI-Hub repo root \u2014 the Hub's copies ARE the reference this compares against`);
36118
36273
  const seedSource = await resolveHubSeedSource(execGitForSeedSource);
36119
36274
  if (!seedSource.ok) return fail(`bootstrap drift: ${seedSource.reason}`);
36120
- const manifest = loadBootstrapSeeds((0, import_node_fs32.readFileSync)(manifestPath, "utf8"));
36275
+ const manifest = loadBootstrapSeeds((0, import_node_fs33.readFileSync)(manifestPath, "utf8"));
36121
36276
  const hubContents = /* @__PURE__ */ new Map();
36122
36277
  for (const s of manifest.seeds) {
36123
36278
  if (s.ownership !== "org" || s.source !== "self") continue;
36124
- hubContents.set(s.target, (0, import_node_fs32.existsSync)(s.target) ? (0, import_node_fs32.readFileSync)(s.target, "utf8") : null);
36279
+ hubContents.set(s.target, (0, import_node_fs33.existsSync)(s.target) ? (0, import_node_fs33.readFileSync)(s.target, "utf8") : null);
36125
36280
  }
36126
36281
  let targets;
36127
36282
  let classOf = (_repo) => "deployable";
@@ -36329,24 +36484,24 @@ function registerBootstrapCommands(program3) {
36329
36484
  return;
36330
36485
  }
36331
36486
  const manifestPath = "skills/bootstrap/seeds/manifest.json";
36332
- if (!(0, import_node_fs32.existsSync)(manifestPath)) return fail(`bootstrap apply: ${manifestPath} not found; bootstrap runs from the MMI-Hub repo root by design \u2014 it stamps org-level resources (Project, Ruleset, secrets, access) through the GitHub App, which is only authorized from the Hub checkout`);
36487
+ if (!(0, import_node_fs33.existsSync)(manifestPath)) return fail(`bootstrap apply: ${manifestPath} not found; bootstrap runs from the MMI-Hub repo root by design \u2014 it stamps org-level resources (Project, Ruleset, secrets, access) through the GitHub App, which is only authorized from the Hub checkout`);
36333
36488
  const seedSource = await resolveHubSeedSource(execGitForSeedSource);
36334
36489
  if (!seedSource.ok) return fail(`bootstrap apply: ${seedSource.reason}`);
36335
- const manifest = loadBootstrapSeeds((0, import_node_fs32.readFileSync)(manifestPath, "utf8"));
36490
+ const manifest = loadBootstrapSeeds((0, import_node_fs33.readFileSync)(manifestPath, "utf8"));
36336
36491
  const baseBranch = o.class === "content" ? "main" : "development";
36337
36492
  const slug = parsedRepo.slug;
36338
36493
  const onlyTarget = o.fromConfig && o.only.trim() === "gate.yml" ? ".github/workflows/gate.yml" : o.only.trim();
36339
36494
  const gh2 = async (args) => execFileP("gh", args, { timeout: 2e4 });
36340
- const readFile10 = (p) => (0, import_node_fs32.existsSync)(p) ? (0, import_node_fs32.readFileSync)(p, "utf8") : null;
36495
+ const readFile10 = (p) => (0, import_node_fs33.existsSync)(p) ? (0, import_node_fs33.readFileSync)(p, "utf8") : null;
36341
36496
  const enc = (p) => p.split("/").map(encodeURIComponent).join("/");
36342
36497
  const putSeed = async (target, content, ref, sha) => {
36343
36498
  const tmp = (0, import_node_path31.join)((0, import_node_os18.tmpdir)(), `mmi-seed-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
36344
- (0, import_node_fs32.writeFileSync)(tmp, JSON.stringify(contentPutBody(target, content, ref, sha)), "utf8");
36499
+ (0, import_node_fs33.writeFileSync)(tmp, JSON.stringify(contentPutBody(target, content, ref, sha)), "utf8");
36345
36500
  try {
36346
36501
  await gh2(contentPutInputArgs(repo, target, tmp));
36347
36502
  } finally {
36348
36503
  try {
36349
- (0, import_node_fs32.unlinkSync)(tmp);
36504
+ (0, import_node_fs33.unlinkSync)(tmp);
36350
36505
  } catch {
36351
36506
  }
36352
36507
  }
@@ -36982,10 +37137,10 @@ LIVE apply to ${repo}:
36982
37137
  bootstrap.command("propagate").description("#4238: re-entrant canary\u2192wave tick \u2014 plan (or, with --execute, open) per-repo PRs fanning an org-owned seed out to the fleet").option("--target <path>", "the manifest target to propagate (an org-owned whole file or declared Hub-managed block)").option("--execute", "LIVE tick via gh (master-gated) \u2014 opens/reuses per-repo seed-propagate PRs; dry-run prints the plan only").option("--json", "machine-readable output").action(async () => {
36983
37138
  const o = { target: rawValue("--target", ""), execute: rawFlag("--execute"), json: rawFlag("--json") };
36984
37139
  const manifestPath = "skills/bootstrap/seeds/manifest.json";
36985
- if (!(0, import_node_fs32.existsSync)(manifestPath)) return fail(`bootstrap propagate: ${manifestPath} not found; run from the MMI-Hub repo root \u2014 the Hub's copies ARE the desired state this tick propagates`);
37140
+ if (!(0, import_node_fs33.existsSync)(manifestPath)) return fail(`bootstrap propagate: ${manifestPath} not found; run from the MMI-Hub repo root \u2014 the Hub's copies ARE the desired state this tick propagates`);
36986
37141
  const seedSource = await resolveHubSeedSource(execGitForSeedSource);
36987
37142
  if (!seedSource.ok) return fail(`bootstrap propagate: ${seedSource.reason}`);
36988
- const manifest = loadBootstrapSeeds((0, import_node_fs32.readFileSync)(manifestPath, "utf8"));
37143
+ const manifest = loadBootstrapSeeds((0, import_node_fs33.readFileSync)(manifestPath, "utf8"));
36989
37144
  const propagatable = manifest.seeds.filter(isPropagatableSeed);
36990
37145
  if (!o.target) {
36991
37146
  return fail(`bootstrap propagate: --target <path> is required \u2014 one of:
@@ -36994,9 +37149,9 @@ LIVE apply to ${repo}:
36994
37149
  const seed = propagatable.find((s) => s.target === o.target);
36995
37150
  if (!seed) return fail(`bootstrap propagate: --target '${o.target}' names no centrally propagatable seed in ${manifestPath}. Propagatable targets:
36996
37151
  ${propagatable.map((s) => s.target).join("\n ")}`);
36997
- if (!seed.managedBlock && !(0, import_node_fs32.existsSync)(seed.target)) return fail(`bootstrap propagate: the Hub's own copy of '${seed.target}' is missing \u2014 nothing to propagate`);
36998
- const hubContent = seed.managedBlock ? null : (0, import_node_fs32.readFileSync)(seed.target, "utf8");
36999
- const readSeedFile2 = (path2) => (0, import_node_fs32.existsSync)(path2) ? (0, import_node_fs32.readFileSync)(path2, "utf8") : null;
37152
+ 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`);
37153
+ const hubContent = seed.managedBlock ? null : (0, import_node_fs33.readFileSync)(seed.target, "utf8");
37154
+ const readSeedFile2 = (path2) => (0, import_node_fs33.existsSync)(path2) ? (0, import_node_fs33.readFileSync)(path2, "utf8") : null;
37000
37155
  const isWorkflowSeed = seed.target.startsWith(".github/workflows/");
37001
37156
  const cfg = await loadConfig();
37002
37157
  const projects = await fetchProjectsList(registryClientDeps(cfg));
@@ -37005,9 +37160,9 @@ LIVE apply to ${repo}:
37005
37160
  }
37006
37161
  const rosterRepos = collectRegistryRepos(projects).filter((r) => r.toLowerCase() !== "mutmutco/mmi-hub");
37007
37162
  let independentCount = rosterRepos.length;
37008
- if ((0, import_node_fs32.existsSync)("projects.json")) {
37163
+ if ((0, import_node_fs33.existsSync)("projects.json")) {
37009
37164
  try {
37010
- const local = JSON.parse((0, import_node_fs32.readFileSync)("projects.json", "utf8"));
37165
+ const local = JSON.parse((0, import_node_fs33.readFileSync)("projects.json", "utf8"));
37011
37166
  const localRepos = /* @__PURE__ */ new Set();
37012
37167
  for (const p of local.projects ?? []) for (const r of p.repos ?? []) {
37013
37168
  const full = (r.includes("/") ? r : `mutmutco/${r}`).toLowerCase();
@@ -37157,7 +37312,7 @@ LIVE apply to ${repo}:
37157
37312
  if (plan.refusedNoCanary) return fail("bootstrap propagate --execute: no canary declared for this target \u2014 refusing to write (set seedCanary:true on exactly one registry repo)");
37158
37313
  const headSha = seedSource.sha;
37159
37314
  const sourceBlob = (await execGitForSeedSource(["rev-parse", `${headSha}:${seedSourcePath(seed)}`])).trim();
37160
- const runbookUnaffected = (0, import_node_fs32.existsSync)(RUNBOOK_UNAFFECTED_PATH) ? runbookUnaffectedReason(JSON.parse((0, import_node_fs32.readFileSync)(RUNBOOK_UNAFFECTED_PATH, "utf8")), seed.target, sourceBlob) : void 0;
37315
+ const runbookUnaffected = (0, import_node_fs33.existsSync)(RUNBOOK_UNAFFECTED_PATH) ? runbookUnaffectedReason(JSON.parse((0, import_node_fs33.readFileSync)(RUNBOOK_UNAFFECTED_PATH, "utf8")), seed.target, sourceBlob) : void 0;
37161
37316
  for (const rec of plan.records) {
37162
37317
  if (rec.action !== "open-pr") continue;
37163
37318
  const baseBranch = classOf(rec.repo) === "content" ? "main" : "development";
@@ -37182,12 +37337,12 @@ LIVE apply to ${repo}:
37182
37337
  const tmp = (0, import_node_path31.join)((0, import_node_os18.tmpdir)(), `mmi-propagate-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
37183
37338
  const desiredContent = desiredByRepo.get(rec.repo);
37184
37339
  if (desiredContent == null) return fail(`bootstrap propagate: no resolved content for ${rec.repo} ${seed.target} \u2014 refusing to write`);
37185
- (0, import_node_fs32.writeFileSync)(tmp, JSON.stringify(contentPutBody(seed.target, desiredContent, branch, existingSha, runbookUnaffected)), "utf8");
37340
+ (0, import_node_fs33.writeFileSync)(tmp, JSON.stringify(contentPutBody(seed.target, desiredContent, branch, existingSha, runbookUnaffected)), "utf8");
37186
37341
  try {
37187
37342
  await gh2(contentPutInputArgs(rec.repo, seed.target, tmp));
37188
37343
  } finally {
37189
37344
  try {
37190
- (0, import_node_fs32.unlinkSync)(tmp);
37345
+ (0, import_node_fs33.unlinkSync)(tmp);
37191
37346
  } catch {
37192
37347
  }
37193
37348
  }
@@ -37256,10 +37411,10 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
37256
37411
  return fail(`bootstrap rollback: ${e.message}`);
37257
37412
  }
37258
37413
  const manifestPath = "skills/bootstrap/seeds/manifest.json";
37259
- if (!(0, import_node_fs32.existsSync)(manifestPath)) return fail(`bootstrap rollback: ${manifestPath} not found; run from the MMI-Hub repo root \u2014 the manifest names which targets are org-owned and therefore propagated (and rollback-able)`);
37414
+ if (!(0, import_node_fs33.existsSync)(manifestPath)) return fail(`bootstrap rollback: ${manifestPath} not found; run from the MMI-Hub repo root \u2014 the manifest names which targets are org-owned and therefore propagated (and rollback-able)`);
37260
37415
  const seedSource = await resolveHubSeedSource(execGitForSeedSource);
37261
37416
  if (!seedSource.ok) return fail(`bootstrap rollback: ${seedSource.reason}`);
37262
- const manifest = loadBootstrapSeeds((0, import_node_fs32.readFileSync)(manifestPath, "utf8"));
37417
+ const manifest = loadBootstrapSeeds((0, import_node_fs33.readFileSync)(manifestPath, "utf8"));
37263
37418
  const propagatable = manifest.seeds.filter(isPropagatableSeed);
37264
37419
  if (!o.target) {
37265
37420
  return fail(`bootstrap rollback: --target <path> is required \u2014 one of:
@@ -37276,10 +37431,10 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
37276
37431
  const enc = (p) => p.split("/").map(encodeURIComponent).join("/");
37277
37432
  let candidates;
37278
37433
  if (o.record) {
37279
- if (!(0, import_node_fs32.existsSync)(o.record)) return fail(`bootstrap rollback: --record '${o.record}' not found`);
37434
+ if (!(0, import_node_fs33.existsSync)(o.record)) return fail(`bootstrap rollback: --record '${o.record}' not found`);
37280
37435
  let parsed;
37281
37436
  try {
37282
- parsed = JSON.parse((0, import_node_fs32.readFileSync)(o.record, "utf8"));
37437
+ parsed = JSON.parse((0, import_node_fs33.readFileSync)(o.record, "utf8"));
37283
37438
  } catch (e) {
37284
37439
  return fail(`bootstrap rollback: --record '${o.record}' is not valid JSON: ${e.message}`);
37285
37440
  }
@@ -37357,12 +37512,12 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
37357
37512
  existingSha = void 0;
37358
37513
  }
37359
37514
  const tmp = (0, import_node_path31.join)((0, import_node_os18.tmpdir)(), `mmi-rollback-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
37360
- (0, import_node_fs32.writeFileSync)(tmp, JSON.stringify(contentPutBody(seed.target, preSeedContent, plan.branch, existingSha)), "utf8");
37515
+ (0, import_node_fs33.writeFileSync)(tmp, JSON.stringify(contentPutBody(seed.target, preSeedContent, plan.branch, existingSha)), "utf8");
37361
37516
  try {
37362
37517
  await gh2(contentPutInputArgs(repo, seed.target, tmp));
37363
37518
  } finally {
37364
37519
  try {
37365
- (0, import_node_fs32.unlinkSync)(tmp);
37520
+ (0, import_node_fs33.unlinkSync)(tmp);
37366
37521
  } catch {
37367
37522
  }
37368
37523
  }
@@ -37819,7 +37974,7 @@ async function waitSuiteDev(deps, opts) {
37819
37974
  }
37820
37975
 
37821
37976
  // src/suite-train.ts
37822
- var import_node_fs33 = require("node:fs");
37977
+ var import_node_fs34 = require("node:fs");
37823
37978
  var import_node_path32 = require("node:path");
37824
37979
  var import_node_crypto15 = require("node:crypto");
37825
37980
 
@@ -37906,7 +38061,7 @@ function suiteReleaseTag(rc) {
37906
38061
  function readSuiteCut(path2) {
37907
38062
  let raw;
37908
38063
  try {
37909
- raw = (0, import_node_fs33.readFileSync)(path2, "utf8");
38064
+ raw = (0, import_node_fs34.readFileSync)(path2, "utf8");
37910
38065
  } catch (e) {
37911
38066
  if (e.code === "ENOENT") return void 0;
37912
38067
  throw e;
@@ -37922,11 +38077,11 @@ function readSuiteCut(path2) {
37922
38077
  return record;
37923
38078
  }
37924
38079
  function writeSuiteCut(path2, record) {
37925
- (0, import_node_fs33.mkdirSync)((0, import_node_path32.dirname)(path2), { recursive: true });
38080
+ (0, import_node_fs34.mkdirSync)((0, import_node_path32.dirname)(path2), { recursive: true });
37926
38081
  const temp = `${path2}.${(0, import_node_crypto15.randomBytes)(8).toString("hex")}.tmp`;
37927
38082
  try {
37928
- (0, import_node_fs33.writeFileSync)(temp, JSON.stringify(record, null, 2), { flag: "wx" });
37929
- (0, import_node_fs33.renameSync)(temp, path2);
38083
+ (0, import_node_fs34.writeFileSync)(temp, JSON.stringify(record, null, 2), { flag: "wx" });
38084
+ (0, import_node_fs34.renameSync)(temp, path2);
37930
38085
  } catch (e) {
37931
38086
  throw new Error(`suite cut record write failed at ${path2}: ${e.message}; stop, verify the file before retrying`);
37932
38087
  }
@@ -37975,25 +38130,25 @@ async function suiteMarkAbandoned(deps, ownerGo = false) {
37975
38130
  return tags.map((t) => `${t.repo}@${t.tag}`);
37976
38131
  }
37977
38132
  async function retireFailedLeadRcLedger(deps, ownerGo) {
37978
- if (!(0, import_node_fs33.existsSync)(deps.ledgerPath)) return void 0;
38133
+ if (!(0, import_node_fs34.existsSync)(deps.ledgerPath)) return void 0;
37979
38134
  return withLedgerLock(deps.ledgerPath, async (fence) => {
37980
- const ledger = parseReleaseLedger((0, import_node_fs33.readFileSync)(deps.ledgerPath, "utf8"));
38135
+ const ledger = parseReleaseLedger((0, import_node_fs34.readFileSync)(deps.ledgerPath, "utf8"));
37981
38136
  const states = Object.values(ledger.phases).map((p) => p.state);
37982
38137
  if (ledger.repo !== SUITE_REPO || ledger.lane !== "rcand" || ledger.phases.promotion.state === "complete" || !states.includes("failed")) return void 0;
37983
38138
  if (!ownerGo) throw new Error(`the lead's failed rcand ledger for ${ledger.tag} blocks every train; retire it with suite abandon --owner-go`);
37984
38139
  if ((await deps.rcHead())?.toLowerCase() === ledger.tagSha.toLowerCase()) throw new Error(`origin rc already points at ${ledger.tag}; it was promoted, so its ledger is not retired`);
37985
38140
  const archive = (0, import_node_path32.join)((0, import_node_path32.dirname)(deps.ledgerPath), `phases.archive-${ledger.tag}.json`);
37986
- if ((0, import_node_fs33.existsSync)(archive)) throw new Error(`ledger archive already exists at ${archive}; inspect before retiring again`);
38141
+ if ((0, import_node_fs34.existsSync)(archive)) throw new Error(`ledger archive already exists at ${archive}; inspect before retiring again`);
37987
38142
  await deps.markAbandoned(SUITE_REPO, ledger.tag, ledger.tagSha);
37988
- await fence(() => (0, import_node_fs33.renameSync)(deps.ledgerPath, archive));
38143
+ await fence(() => (0, import_node_fs34.renameSync)(deps.ledgerPath, archive));
37989
38144
  return `${ledger.tag} (ledger archived to ${archive})`;
37990
38145
  });
37991
38146
  }
37992
38147
  function suiteAbandon(recordPath, ownerGo = false, now = /* @__PURE__ */ new Date()) {
37993
38148
  const record = abandonableCut(recordPath, ownerGo);
37994
38149
  const archive = `${recordPath}.abandoned-${record.leadDevelopment.slice(0, 12)}-${now.toISOString().replace(/[:.]/g, "")}.json`;
37995
- if ((0, import_node_fs33.existsSync)(archive)) throw new Error(`abandoned-cut archive already exists at ${archive}; inspect before abandoning again`);
37996
- (0, import_node_fs33.renameSync)(recordPath, archive);
38150
+ if ((0, import_node_fs34.existsSync)(archive)) throw new Error(`abandoned-cut archive already exists at ${archive}; inspect before abandoning again`);
38151
+ (0, import_node_fs34.renameSync)(recordPath, archive);
37997
38152
  return { archive, orphanTags: record.members.filter((m) => m.tag).map((m) => `${m.repo}@${m.tag}`) };
37998
38153
  }
37999
38154
  async function suiteRestoreMainPins(deps) {
@@ -38076,12 +38231,12 @@ async function suiteRcandRun(deps, opts) {
38076
38231
  }
38077
38232
  if ((record?.announcement === "sent" || record?.announcement === "skipped") && record.leadReleased) {
38078
38233
  const archive = `${deps.recordPath}.${record.leadRcTag}.json`;
38079
- if ((0, import_node_fs33.existsSync)(archive)) throw new Error(`suite cut archive already exists at ${archive}; inspect before a new cut`);
38080
- (0, import_node_fs33.renameSync)(deps.recordPath, archive);
38234
+ if ((0, import_node_fs34.existsSync)(archive)) throw new Error(`suite cut archive already exists at ${archive}; inspect before a new cut`);
38235
+ (0, import_node_fs34.renameSync)(deps.recordPath, archive);
38081
38236
  record = void 0;
38082
38237
  }
38083
38238
  if (record && !record.pinPr && !record.leadRcTag && record.members.every((m) => !m.tag)) {
38084
- (0, import_node_fs33.rmSync)(deps.recordPath, { force: true });
38239
+ (0, import_node_fs34.rmSync)(deps.recordPath, { force: true });
38085
38240
  record = void 0;
38086
38241
  }
38087
38242
  if (!record) {
@@ -38135,7 +38290,7 @@ async function suiteRcandRun(deps, opts) {
38135
38290
  quiet.push(member);
38136
38291
  }
38137
38292
  if (record.members.every((m) => m.carried || quiet.includes(m)) && await deps.contains(SUITE_REPO, record.leadDevelopment, record.leadPreviousRc)) {
38138
- (0, import_node_fs33.rmSync)(deps.recordPath, { force: true });
38293
+ (0, import_node_fs34.rmSync)(deps.recordPath, { force: true });
38139
38294
  throw new Error("nothing to promote: neither MM-Work nor any module has new development commits since its rc; no suite cut started");
38140
38295
  }
38141
38296
  for (const member of quiet) {
@@ -38153,7 +38308,7 @@ async function suiteRcandRun(deps, opts) {
38153
38308
  }
38154
38309
  if (refusals.length) {
38155
38310
  const untouched = record.members.every((m) => !m.tag) && !record.pinPr;
38156
- if (untouched) (0, import_node_fs33.rmSync)(deps.recordPath, { force: true });
38311
+ if (untouched) (0, import_node_fs34.rmSync)(deps.recordPath, { force: true });
38157
38312
  throw new Error(`module rc serving is not ready; ${untouched ? "no suite cut started" : "no new tag was cut"}:
38158
38313
  ${refusals.join("\n")}
38159
38314
  Each module must ship a live release that bind-mounts <deployPath>/data read-only and serves <data>/rc/module.js at /rc/module.js (docs/Guides/suite-trains.md).`);
@@ -38349,7 +38504,7 @@ var hotfixRecordPath = (deps) => (0, import_node_path32.join)((0, import_node_pa
38349
38504
  function readSuiteHotfix(path2) {
38350
38505
  let raw;
38351
38506
  try {
38352
- raw = (0, import_node_fs33.readFileSync)(path2, "utf8");
38507
+ raw = (0, import_node_fs34.readFileSync)(path2, "utf8");
38353
38508
  } catch (e) {
38354
38509
  if (e.code === "ENOENT") return void 0;
38355
38510
  throw e;
@@ -38392,7 +38547,7 @@ async function suiteHotfix(deps, opts) {
38392
38547
  if (completed) record = void 0;
38393
38548
  if (record && record.repo !== found.repo) throw new Error(`an unfinished suite hotfix for ${record.repo} is recorded; finish it (rerun with that member) first`);
38394
38549
  if (!record?.tag) await deps.validateHotfixSummary();
38395
- if (completed) (0, import_node_fs33.renameSync)(path2, `${path2}.${completed.leadTag}.json`);
38550
+ if (completed) (0, import_node_fs34.renameSync)(path2, `${path2}.${completed.leadTag}.json`);
38396
38551
  const rec = record ?? { schema: "mmi-suite-hotfix/v1", member: found.id, repo: found.repo, from: opts.from, ...opts.ack?.length ? { ack: opts.ack } : {} };
38397
38552
  const save = () => writeSuiteHotfix(path2, rec);
38398
38553
  save();
@@ -38661,7 +38816,7 @@ async function runRcDataSwitch(deps, opts) {
38661
38816
  // src/suite-train-io.ts
38662
38817
  var import_node_child_process18 = require("node:child_process");
38663
38818
  var import_node_path45 = require("node:path");
38664
- var import_node_fs46 = require("node:fs");
38819
+ var import_node_fs47 = require("node:fs");
38665
38820
  var import_node_path46 = require("node:path");
38666
38821
  init_cli_shared();
38667
38822
 
@@ -40338,7 +40493,7 @@ function checkHotfixCarries(options) {
40338
40493
  }
40339
40494
 
40340
40495
  // src/merge-cleanup.ts
40341
- var import_node_fs35 = require("node:fs");
40496
+ var import_node_fs36 = require("node:fs");
40342
40497
  var import_node_path34 = require("node:path");
40343
40498
  var import_node_os19 = require("node:os");
40344
40499
  init_cli_shared();
@@ -40767,7 +40922,7 @@ function renderPrLandTable(entries) {
40767
40922
 
40768
40923
  // src/test-policy-core.ts
40769
40924
  var import_node_child_process13 = require("node:child_process");
40770
- var import_node_fs34 = require("node:fs");
40925
+ var import_node_fs35 = require("node:fs");
40771
40926
  var import_node_path33 = require("node:path");
40772
40927
 
40773
40928
  // src/test-command-policy-shared.mjs
@@ -41337,7 +41492,7 @@ function loadPolicySource(root, explicitRef, diffBase) {
41337
41492
  }
41338
41493
  function readFileOrNull2(path2) {
41339
41494
  try {
41340
- return (0, import_node_fs34.readFileSync)(path2, "utf8");
41495
+ return (0, import_node_fs35.readFileSync)(path2, "utf8");
41341
41496
  } catch {
41342
41497
  return null;
41343
41498
  }
@@ -41365,10 +41520,10 @@ function classify(changed, policy, present = () => false) {
41365
41520
  const removedProtected = [...removed].filter((p) => protectedBy.has(p)).map((p) => ({ path: p, why: protectedBy.get(p) ?? "" }));
41366
41521
  return { mandatoryHits, untestedHits, testChanges, meaningfulTestChanges, addedTests, removedProtected };
41367
41522
  }
41368
- function unresolvedProtectedEntries(policy, root, exists = (path2) => (0, import_node_fs34.existsSync)(path2)) {
41523
+ function unresolvedProtectedEntries(policy, root, exists = (path2) => (0, import_node_fs35.existsSync)(path2)) {
41369
41524
  return (policy.protected ?? []).map((p) => p.path).filter((p) => !exists((0, import_node_path33.join)(root, p)));
41370
41525
  }
41371
- function unresolvedSatisfiers(policy, root, exists = (path2) => (0, import_node_fs34.existsSync)(path2)) {
41526
+ function unresolvedSatisfiers(policy, root, exists = (path2) => (0, import_node_fs35.existsSync)(path2)) {
41372
41527
  const declared = (policy.mandatory ?? []).flatMap((m) => m.satisfiedBy ?? []);
41373
41528
  return [...new Set(declared)].filter((p) => !exists((0, import_node_path33.join)(root, p)));
41374
41529
  }
@@ -41509,7 +41664,7 @@ function runTestPolicy(root, deps = {}) {
41509
41664
  }
41510
41665
  const loaded = deps.policy ? { policy: deps.policy, source: { ref: null, sha: null, path: POLICY_FILE } } : loadPolicySource(root, deps.policyRef, deps.base);
41511
41666
  const { policy, source: policySource } = loaded;
41512
- const exists = deps.exists ?? ((path2) => (0, import_node_fs34.existsSync)(path2));
41667
+ const exists = deps.exists ?? ((path2) => (0, import_node_fs35.existsSync)(path2));
41513
41668
  const counts = { mandatoryCount: (policy.mandatory ?? []).length, protectedCount: (policy.protected ?? []).length };
41514
41669
  const base = deps.changed ? "(injected)" : deps.policyRef ? resolveHotfixBase(root) : resolveBase(root, deps.base);
41515
41670
  const refusal = deps.changed ? null : untrustworthyRange(root, base);
@@ -41807,13 +41962,13 @@ function resolveSquashMergeBodyText(commits, allowedClosing, cwd) {
41807
41962
  return rewritten === base ? null : rewritten;
41808
41963
  }
41809
41964
  function writeSquashBodyFile(body) {
41810
- const dir = (0, import_node_fs35.mkdtempSync)((0, import_node_path34.join)((0, import_node_os19.tmpdir)(), "mmi-squash-body-"));
41965
+ const dir = (0, import_node_fs36.mkdtempSync)((0, import_node_path34.join)((0, import_node_os19.tmpdir)(), "mmi-squash-body-"));
41811
41966
  const path2 = (0, import_node_path34.join)(dir, "body.txt");
41812
- (0, import_node_fs35.writeFileSync)(path2, body.endsWith("\n") ? body : `${body}
41967
+ (0, import_node_fs36.writeFileSync)(path2, body.endsWith("\n") ? body : `${body}
41813
41968
  `, "utf8");
41814
41969
  return { path: path2, cleanup: () => {
41815
41970
  try {
41816
- (0, import_node_fs35.rmSync)(dir, { recursive: true, force: true });
41971
+ (0, import_node_fs36.rmSync)(dir, { recursive: true, force: true });
41817
41972
  } catch {
41818
41973
  }
41819
41974
  } };
@@ -42052,6 +42207,7 @@ var readApi = async (args) => {
42052
42207
  const env = await ghReadEnv();
42053
42208
  return (await execFileP("gh", ["api", ...args], {
42054
42209
  timeout: 2e4,
42210
+ maxBuffer: 16 * 1024 * 1024,
42055
42211
  ...env ? { env } : {}
42056
42212
  })).stdout;
42057
42213
  };
@@ -42081,7 +42237,7 @@ async function readPrMergeQueue(pr, repo, gh2 = readApi) {
42081
42237
  return result.pullRequest;
42082
42238
  }
42083
42239
  async function findPrMergeGroupRun(pr, repo, base, gh2 = readApi) {
42084
- const pages = JSON.parse(await gh2([`repos/${repo}/actions/runs?event=merge_group&per_page=100`, "--paginate", "--slurp"]));
42240
+ const pages = [JSON.parse(await gh2([`repos/${repo}/actions/runs?event=merge_group&per_page=100&exclude_pull_requests=true`]))];
42085
42241
  const prefix = `gh-readonly-queue/${base}/pr-${pr}-`;
42086
42242
  const run = pages.flatMap((page) => page.workflow_runs).filter((run2) => run2.head_branch?.startsWith(prefix)).sort((a, b) => b.created_at.localeCompare(a.created_at) || b.id - a.id)[0];
42087
42243
  return run ? { id: run.id, url: run.html_url, conclusion: run.conclusion } : void 0;
@@ -42102,7 +42258,7 @@ function prMergeQueueLine(result) {
42102
42258
  }
42103
42259
 
42104
42260
  // src/project-info-sync.ts
42105
- var import_node_fs36 = require("node:fs");
42261
+ var import_node_fs37 = require("node:fs");
42106
42262
  var import_node_path35 = require("node:path");
42107
42263
  var UPDATE_PROJECT_INFO = `mutation($projectId: ID!, $shortDescription: String!, $readme: String!) {
42108
42264
  updateProjectV2(input: { projectId: $projectId, shortDescription: $shortDescription, readme: $readme }) {
@@ -42151,13 +42307,13 @@ function sharedName(entries, fallback) {
42151
42307
  function buildProjectInfoSyncPlan(targetRepo2, project2, projects, repoRoot2) {
42152
42308
  if (!project2.projectId) throw new Error(`org project sync-info: ${targetRepo2} registry META has no projectId`);
42153
42309
  const readmePath = (0, import_node_path35.join)(repoRoot2, "README.md");
42154
- if (!(0, import_node_fs36.existsSync)(readmePath)) throw new Error(`org project sync-info: ${targetRepo2} has no README.md`);
42310
+ if (!(0, import_node_fs37.existsSync)(readmePath)) throw new Error(`org project sync-info: ${targetRepo2} has no README.md`);
42155
42311
  const entries = entriesFor(project2, projects);
42156
42312
  const memberRepos = [...new Set(entries.flatMap((entry) => entry.repos ?? []))].filter((repo) => /^[^/]+\/[^/]+$/.test(repo)).sort((a, b) => a.localeCompare(b));
42157
42313
  const projectName = sharedName(entries, project2.name?.trim() || targetRepo2.split("/").pop() || targetRepo2);
42158
42314
  if (!memberRepos.length) throw new Error(`org project sync-info: project ${projectName} has no registered member repos`);
42159
42315
  const entryNames = entries.map((entry) => entry.name?.trim()).filter((name) => Boolean(name));
42160
- const shortDescription = memberRepos.length === 1 ? shortDescriptionFromReadme((0, import_node_fs36.readFileSync)(readmePath, "utf8")) : `Shared work across ${new Intl.ListFormat("en", { type: "conjunction" }).format(entryNames)}.`;
42316
+ const shortDescription = memberRepos.length === 1 ? shortDescriptionFromReadme((0, import_node_fs37.readFileSync)(readmePath, "utf8")) : `Shared work across ${new Intl.ListFormat("en", { type: "conjunction" }).format(entryNames)}.`;
42161
42317
  const lines2 = [
42162
42318
  `# ${projectName}`,
42163
42319
  "",
@@ -42176,8 +42332,8 @@ function buildProjectInfoSyncPlan(targetRepo2, project2, projects, repoRoot2) {
42176
42332
  const targetBase = `https://github.com/${targetRepo2}`;
42177
42333
  const targetBranch = branchFor(targetRepo2, projects);
42178
42334
  const orgDocs = [
42179
- (0, import_node_fs36.existsSync)((0, import_node_path35.join)(repoRoot2, "architecture.md")) ? `- [Hub architecture](${targetBase}/blob/${targetBranch}/architecture.md)` : "",
42180
- (0, import_node_fs36.existsSync)((0, import_node_path35.join)(repoRoot2, "docs", "Architecture", "agentic-dev-environment.md")) ? `- [Agentic development environment](${targetBase}/blob/${targetBranch}/docs/Architecture/agentic-dev-environment.md)` : ""
42335
+ (0, import_node_fs37.existsSync)((0, import_node_path35.join)(repoRoot2, "architecture.md")) ? `- [Hub architecture](${targetBase}/blob/${targetBranch}/architecture.md)` : "",
42336
+ (0, import_node_fs37.existsSync)((0, import_node_path35.join)(repoRoot2, "docs", "Architecture", "agentic-dev-environment.md")) ? `- [Agentic development environment](${targetBase}/blob/${targetBranch}/docs/Architecture/agentic-dev-environment.md)` : ""
42181
42337
  ].filter(Boolean);
42182
42338
  if (orgDocs.length) lines2.push("", "## Organisation docs", "", ...orgDocs);
42183
42339
  return { projectId: project2.projectId, projectName, targetRepo: targetRepo2, memberRepos, shortDescription, readme: `${lines2.join("\n")}
@@ -42199,7 +42355,7 @@ async function syncProjectInfo(plan, client, apply) {
42199
42355
  }
42200
42356
 
42201
42357
  // src/train-commands.ts
42202
- var import_node_fs37 = require("node:fs");
42358
+ var import_node_fs38 = require("node:fs");
42203
42359
  var import_node_path36 = require("node:path");
42204
42360
  init_cli_shared();
42205
42361
  init_clean_exit();
@@ -42215,7 +42371,7 @@ function resolveReleaseBumpIntent(raw) {
42215
42371
  }
42216
42372
  function readRepoVersion() {
42217
42373
  try {
42218
- return JSON.parse((0, import_node_fs37.readFileSync)((0, import_node_path36.join)(process.cwd(), ".claude-plugin", "plugin.json"), "utf8")).version || void 0;
42374
+ return JSON.parse((0, import_node_fs38.readFileSync)((0, import_node_path36.join)(process.cwd(), ".claude-plugin", "plugin.json"), "utf8")).version || void 0;
42219
42375
  } catch {
42220
42376
  return void 0;
42221
42377
  }
@@ -42580,7 +42736,7 @@ async function openSuitePinPr(deps, input) {
42580
42736
 
42581
42737
  // src/command-register-collaboration.ts
42582
42738
  var import_node_child_process17 = require("node:child_process");
42583
- var import_node_fs45 = require("node:fs");
42739
+ var import_node_fs46 = require("node:fs");
42584
42740
  var import_promises8 = require("node:fs/promises");
42585
42741
  init_clean_exit();
42586
42742
  init_cli_shared();
@@ -42714,7 +42870,7 @@ init_github_client();
42714
42870
  init_github_quota();
42715
42871
 
42716
42872
  // src/issue-commands.ts
42717
- var import_node_fs38 = require("node:fs");
42873
+ var import_node_fs39 = require("node:fs");
42718
42874
  var import_node_crypto16 = require("node:crypto");
42719
42875
  init_cli_shared();
42720
42876
  init_clean_exit();
@@ -42907,7 +43063,7 @@ async function editIssue(client, options, deps = {}) {
42907
43063
  const url = `https://github.com/${repo}/issues/${parsed.number}`;
42908
43064
  const patch = {};
42909
43065
  let bodyChanged = false;
42910
- const textDeps = () => deps.textDeps ?? { readFile: (p, e) => Promise.resolve((0, import_node_fs38.readFileSync)(p, e)), readStdin: () => Promise.resolve("") };
43066
+ const textDeps = () => deps.textDeps ?? { readFile: (p, e) => Promise.resolve((0, import_node_fs39.readFileSync)(p, e)), readStdin: () => Promise.resolve("") };
42911
43067
  if (options.titleFile !== void 0) {
42912
43068
  patch.title = await resolveIssueTitle({ title: options.title, titleFile: options.titleFile }, textDeps());
42913
43069
  } else if (options.title !== void 0) {
@@ -43570,7 +43726,7 @@ function extendCreateCommand(issue, batchAttach) {
43570
43726
  if (opts.batch) {
43571
43727
  let specs;
43572
43728
  try {
43573
- const raw = (0, import_node_fs38.readFileSync)(opts.batch, "utf8");
43729
+ const raw = (0, import_node_fs39.readFileSync)(opts.batch, "utf8");
43574
43730
  specs = JSON.parse(raw);
43575
43731
  if (!Array.isArray(specs)) {
43576
43732
  const top = specs === null ? "null" : typeof specs === "object" ? `an object with keys: ${Object.keys(specs).join(", ") || "(none)"}` : `a ${typeof specs}`;
@@ -43647,7 +43803,7 @@ ${lines2}`, {
43647
43803
  }
43648
43804
 
43649
43805
  // src/post-merge-recon.ts
43650
- var import_node_fs39 = require("node:fs");
43806
+ var import_node_fs40 = require("node:fs");
43651
43807
  var import_node_path38 = require("node:path");
43652
43808
 
43653
43809
  // src/cross-repo-filing-issue.ts
@@ -43817,16 +43973,16 @@ function buildPostMergeReconRecovery(input) {
43817
43973
  }
43818
43974
  function writePostMergeReconRecovery(cwd, recovery) {
43819
43975
  const path2 = postMergeReconStatePath(cwd, recovery.repo, recovery.pr);
43820
- (0, import_node_fs39.mkdirSync)((0, import_node_path38.dirname)(path2), { recursive: true });
43821
- (0, import_node_fs39.writeFileSync)(path2, `${JSON.stringify(recovery, null, 2)}
43976
+ (0, import_node_fs40.mkdirSync)((0, import_node_path38.dirname)(path2), { recursive: true });
43977
+ (0, import_node_fs40.writeFileSync)(path2, `${JSON.stringify(recovery, null, 2)}
43822
43978
  `, "utf8");
43823
43979
  return path2;
43824
43980
  }
43825
43981
  function clearPostMergeReconRecovery(cwd, repo, pr) {
43826
43982
  const path2 = postMergeReconStatePath(cwd, repo, pr);
43827
- if (!(0, import_node_fs39.existsSync)(path2)) return;
43983
+ if (!(0, import_node_fs40.existsSync)(path2)) return;
43828
43984
  try {
43829
- (0, import_node_fs39.unlinkSync)(path2);
43985
+ (0, import_node_fs40.unlinkSync)(path2);
43830
43986
  } catch {
43831
43987
  }
43832
43988
  }
@@ -44302,7 +44458,7 @@ function registerPrLifecycleCommands(program3) {
44302
44458
 
44303
44459
  // src/review-verdict.ts
44304
44460
  var import_node_child_process14 = require("node:child_process");
44305
- var import_node_fs40 = require("node:fs");
44461
+ var import_node_fs41 = require("node:fs");
44306
44462
  var import_node_os21 = require("node:os");
44307
44463
  var import_node_path39 = require("node:path");
44308
44464
  init_cli_shared();
@@ -44469,15 +44625,15 @@ async function readPrIssueComments(number, repo) {
44469
44625
  return comments;
44470
44626
  }
44471
44627
  async function postPrCommentFromFile(number, repo, body) {
44472
- const dir = (0, import_node_fs40.mkdtempSync)((0, import_node_path39.join)((0, import_node_os21.tmpdir)(), "mmi-review-verdict-"));
44628
+ const dir = (0, import_node_fs41.mkdtempSync)((0, import_node_path39.join)((0, import_node_os21.tmpdir)(), "mmi-review-verdict-"));
44473
44629
  const path2 = (0, import_node_path39.join)(dir, "body.md");
44474
44630
  try {
44475
- (0, import_node_fs40.writeFileSync)(path2, body, "utf8");
44631
+ (0, import_node_fs41.writeFileSync)(path2, body, "utf8");
44476
44632
  const { stdout } = await execFileP("gh", ["pr", "comment", number, "--repo", repo, "--body-file", path2], { timeout: GH_MUTATION_TIMEOUT_MS });
44477
44633
  return stdout.trim();
44478
44634
  } finally {
44479
44635
  try {
44480
- (0, import_node_fs40.rmSync)(dir, { recursive: true, force: true });
44636
+ (0, import_node_fs41.rmSync)(dir, { recursive: true, force: true });
44481
44637
  } catch {
44482
44638
  }
44483
44639
  }
@@ -44711,17 +44867,17 @@ async function prCreateClaimRefusal(body, repoOption, deps = {}) {
44711
44867
  }
44712
44868
 
44713
44869
  // src/worktree-residue-sweep.ts
44714
- var import_node_fs44 = require("node:fs");
44870
+ var import_node_fs45 = require("node:fs");
44715
44871
  var import_node_path43 = require("node:path");
44716
44872
 
44717
44873
  // src/worktree-merge-cleanup.ts
44718
- var import_node_fs43 = require("node:fs");
44874
+ var import_node_fs44 = require("node:fs");
44719
44875
  var import_node_path42 = require("node:path");
44720
44876
  init_cli_shared();
44721
44877
 
44722
44878
  // src/stage-runner.ts
44723
44879
  var import_node_child_process16 = require("node:child_process");
44724
- var import_node_fs42 = require("node:fs");
44880
+ var import_node_fs43 = require("node:fs");
44725
44881
  var import_node_path41 = require("node:path");
44726
44882
  var import_node_net = require("node:net");
44727
44883
  var import_node_util5 = require("node:util");
@@ -44732,7 +44888,7 @@ function normalizeEol2(s) {
44732
44888
  }
44733
44889
 
44734
44890
  // src/env-detection.ts
44735
- var import_node_fs41 = require("node:fs");
44891
+ var import_node_fs42 = require("node:fs");
44736
44892
  var import_node_path40 = require("node:path");
44737
44893
  var SKIPPED_DIRS = /* @__PURE__ */ new Set([".git", "node_modules", "dist", ".jerv", ".pi", ".venv", "venv"]);
44738
44894
  function isEnvBaseName(name) {
@@ -44743,7 +44899,7 @@ function findEnvFiles(root) {
44743
44899
  const walk2 = (dir, rel) => {
44744
44900
  let entries;
44745
44901
  try {
44746
- entries = (0, import_node_fs41.readdirSync)(dir, { withFileTypes: true });
44902
+ entries = (0, import_node_fs42.readdirSync)(dir, { withFileTypes: true });
44747
44903
  } catch {
44748
44904
  return;
44749
44905
  }
@@ -44757,7 +44913,7 @@ function findEnvFiles(root) {
44757
44913
  if (isEnvBaseName(entry.name)) {
44758
44914
  let isDir = false;
44759
44915
  try {
44760
- isDir = (0, import_node_fs41.lstatSync)((0, import_node_path40.join)(dir, entry.name)).isDirectory();
44916
+ isDir = (0, import_node_fs42.lstatSync)((0, import_node_path40.join)(dir, entry.name)).isDirectory();
44761
44917
  } catch {
44762
44918
  }
44763
44919
  if (!isDir) found.push(relPath);
@@ -44896,12 +45052,12 @@ var DOCKER_TIMEOUT_MS = 15e3;
44896
45052
  function stageBash() {
44897
45053
  if (process.platform !== "win32") return "bash";
44898
45054
  const configured = process.env.SHELL;
44899
- if (configured && (0, import_node_path41.isAbsolute)(configured) && /[/\\]bash(?:\.exe)?$/i.test(configured) && !/[/\\](?:System32|Sysnative)[/\\]bash(?:\.exe)?$/i.test(configured) && (0, import_node_fs42.existsSync)(configured)) return configured;
45055
+ if (configured && (0, import_node_path41.isAbsolute)(configured) && /[/\\]bash(?:\.exe)?$/i.test(configured) && !/[/\\](?:System32|Sysnative)[/\\]bash(?:\.exe)?$/i.test(configured) && (0, import_node_fs43.existsSync)(configured)) return configured;
44900
45056
  const candidates = [
44901
45057
  (0, import_node_path41.join)(process.env.ProgramFiles || "C:\\Program Files", "Git", "bin", "bash.exe"),
44902
45058
  ...process.env.LOCALAPPDATA ? [(0, import_node_path41.join)(process.env.LOCALAPPDATA, "Programs", "Git", "bin", "bash.exe")] : []
44903
45059
  ];
44904
- const bash = candidates.find((path2) => (0, import_node_fs42.existsSync)(path2));
45060
+ const bash = candidates.find((path2) => (0, import_node_fs43.existsSync)(path2));
44905
45061
  if (!bash) throw new Error("Local stages require Git Bash on Windows. Install Git for Windows or set SHELL to its absolute bash.exe path.");
44906
45062
  return bash;
44907
45063
  }
@@ -45257,7 +45413,7 @@ function stageProcessEnv(stagePort, extraEnv) {
45257
45413
  function composeResolvesPort(cwd) {
45258
45414
  if (process.env.PORT) return true;
45259
45415
  const envFile = (0, import_node_path41.join)(cwd, ".env");
45260
- return (0, import_node_fs42.existsSync)(envFile) && envFileKeys((0, import_node_fs42.readFileSync)(envFile, "utf8")).has("PORT");
45416
+ return (0, import_node_fs43.existsSync)(envFile) && envFileKeys((0, import_node_fs43.readFileSync)(envFile, "utf8")).has("PORT");
45261
45417
  }
45262
45418
  function stageComposeEnv(config, stagePort, vaultEnvMerge, cwd) {
45263
45419
  const composeProject = config.env?.COMPOSE_PROJECT_NAME ?? vaultEnvMerge?.COMPOSE_PROJECT_NAME ?? stageComposeProjectName(cwd);
@@ -45272,13 +45428,13 @@ function stageComposeEnv(config, stagePort, vaultEnvMerge, cwd) {
45272
45428
  function stageComposeFiles(cwd) {
45273
45429
  const files = ["docker-compose.yml"];
45274
45430
  for (const conventional of ["docker-compose.override.yml", "docker-compose.override.yaml"]) {
45275
- if ((0, import_node_fs42.existsSync)((0, import_node_path41.join)(cwd, conventional))) files.push(conventional);
45431
+ if ((0, import_node_fs43.existsSync)((0, import_node_path41.join)(cwd, conventional))) files.push(conventional);
45276
45432
  }
45277
45433
  return [...files, RUNTIME_ENV_OVERRIDE_RELPATH];
45278
45434
  }
45279
45435
  async function prepareRuntimeEnvPassthrough(cwd, composeEnv, vaultEnvMerge) {
45280
45436
  const keys = Object.keys(vaultEnvMerge ?? {});
45281
- if (!keys.length || !(0, import_node_fs42.existsSync)((0, import_node_path41.join)(cwd, "docker-compose.yml"))) return {};
45437
+ if (!keys.length || !(0, import_node_fs43.existsSync)((0, import_node_path41.join)(cwd, "docker-compose.yml"))) return {};
45282
45438
  let configJson;
45283
45439
  try {
45284
45440
  const { stdout } = await execFileP3("docker", ["compose", "config", "--format", "json"], {
@@ -45295,20 +45451,20 @@ async function prepareRuntimeEnvPassthrough(cwd, composeEnv, vaultEnvMerge) {
45295
45451
  const body = renderRuntimeEnvOverride(runtimeEnvMarkedServices(configJson), keys, runtimeEnvExcludes(configJson), runtimeEnvSelects(configJson));
45296
45452
  if (!body) return {};
45297
45453
  const overridePath = (0, import_node_path41.join)(cwd, RUNTIME_ENV_OVERRIDE_RELPATH);
45298
- (0, import_node_fs42.mkdirSync)((0, import_node_path41.join)(cwd, "tmp", "stage"), { recursive: true });
45299
- (0, import_node_fs42.writeFileSync)(overridePath, body, "utf8");
45454
+ (0, import_node_fs43.mkdirSync)((0, import_node_path41.join)(cwd, "tmp", "stage"), { recursive: true });
45455
+ (0, import_node_fs43.writeFileSync)(overridePath, body, "utf8");
45300
45456
  return stageComposeFileEnv(stageComposeFiles(cwd));
45301
45457
  }
45302
45458
  async function ensureStageRuntimeEnv(config, opts, cwd) {
45303
45459
  if (!config.ensureEnv) return;
45304
45460
  const target = (0, import_node_path41.join)(cwd, config.ensureEnv.target);
45305
45461
  const example = (0, import_node_path41.join)(cwd, config.ensureEnv.example);
45306
- if (!(0, import_node_fs42.existsSync)(target) && (0, import_node_fs42.existsSync)(example)) {
45307
- (0, import_node_fs42.copyFileSync)(example, target);
45308
- } else if ((0, import_node_fs42.existsSync)(target) && (0, import_node_fs42.existsSync)(example)) {
45309
- const stale = detectStaleEnvFile((0, import_node_fs42.readFileSync)(example, "utf8"), (0, import_node_fs42.readFileSync)(target, "utf8"), {
45310
- exampleMtimeMs: (0, import_node_fs42.statSync)(example).mtimeMs,
45311
- targetMtimeMs: (0, import_node_fs42.statSync)(target).mtimeMs
45462
+ if (!(0, import_node_fs43.existsSync)(target) && (0, import_node_fs43.existsSync)(example)) {
45463
+ (0, import_node_fs43.copyFileSync)(example, target);
45464
+ } else if ((0, import_node_fs43.existsSync)(target) && (0, import_node_fs43.existsSync)(example)) {
45465
+ const stale = detectStaleEnvFile((0, import_node_fs43.readFileSync)(example, "utf8"), (0, import_node_fs43.readFileSync)(target, "utf8"), {
45466
+ exampleMtimeMs: (0, import_node_fs43.statSync)(example).mtimeMs,
45467
+ targetMtimeMs: (0, import_node_fs43.statSync)(target).mtimeMs
45312
45468
  });
45313
45469
  if (stale) {
45314
45470
  const msg = `stale ${config.ensureEnv.target} (${stale}) \u2014 delete it or refresh from ${config.ensureEnv.example} before re-running /stage`;
@@ -45316,8 +45472,8 @@ async function ensureStageRuntimeEnv(config, opts, cwd) {
45316
45472
  console.error(`mmi-cli stage: ${msg} (allowed via --allow-stale-env)`);
45317
45473
  }
45318
45474
  }
45319
- if (opts.vaultEnvMerge && Object.keys(opts.vaultEnvMerge).length && (0, import_node_fs42.existsSync)(target)) {
45320
- (0, import_node_fs42.writeFileSync)(target, mergeEnvSecretsIntoFile((0, import_node_fs42.readFileSync)(target, "utf8"), opts.vaultEnvMerge), "utf8");
45475
+ if (opts.vaultEnvMerge && Object.keys(opts.vaultEnvMerge).length && (0, import_node_fs43.existsSync)(target)) {
45476
+ (0, import_node_fs43.writeFileSync)(target, mergeEnvSecretsIntoFile((0, import_node_fs43.readFileSync)(target, "utf8"), opts.vaultEnvMerge), "utf8");
45321
45477
  }
45322
45478
  }
45323
45479
  async function gitText(cwd, args) {
@@ -45347,20 +45503,20 @@ async function resolveGlobalStatePath(cwd, explicit) {
45347
45503
  return void 0;
45348
45504
  }
45349
45505
  function readState(path2) {
45350
- if (!(0, import_node_fs42.existsSync)(path2)) return null;
45506
+ if (!(0, import_node_fs43.existsSync)(path2)) return null;
45351
45507
  try {
45352
- return JSON.parse((0, import_node_fs42.readFileSync)(path2, "utf8"));
45508
+ return JSON.parse((0, import_node_fs43.readFileSync)(path2, "utf8"));
45353
45509
  } catch {
45354
45510
  return null;
45355
45511
  }
45356
45512
  }
45357
45513
  function mkdirFor(path2) {
45358
45514
  const dir = path2.slice(0, Math.max(path2.lastIndexOf("/"), path2.lastIndexOf("\\")));
45359
- (0, import_node_fs42.mkdirSync)(dir, { recursive: true });
45515
+ (0, import_node_fs43.mkdirSync)(dir, { recursive: true });
45360
45516
  }
45361
45517
  function writeState(path2, state) {
45362
45518
  mkdirFor(path2);
45363
- (0, import_node_fs42.writeFileSync)(path2, JSON.stringify(state, null, 2), "utf8");
45519
+ (0, import_node_fs43.writeFileSync)(path2, JSON.stringify(state, null, 2), "utf8");
45364
45520
  }
45365
45521
  function writeStagePortReservation(port, cwd, statePath, globalStatePath, now) {
45366
45522
  const reservation = {
@@ -45389,7 +45545,7 @@ async function cleanupStageState(state, paths, timeoutMs, fallbackCwd, currentEn
45389
45545
  );
45390
45546
  }
45391
45547
  for (const path2 of [...new Set(paths.filter((p) => Boolean(p)))]) {
45392
- (0, import_node_fs42.rmSync)(path2, { force: true });
45548
+ (0, import_node_fs43.rmSync)(path2, { force: true });
45393
45549
  }
45394
45550
  }
45395
45551
  async function killTree(pid) {
@@ -45636,8 +45792,8 @@ async function runStage(config = {}, opts = {}) {
45636
45792
  });
45637
45793
  }
45638
45794
  } catch (e) {
45639
- (0, import_node_fs42.rmSync)(statePath, { force: true });
45640
- if (globalStatePath && globalStatePath !== statePath) (0, import_node_fs42.rmSync)(globalStatePath, { force: true });
45795
+ (0, import_node_fs43.rmSync)(statePath, { force: true });
45796
+ if (globalStatePath && globalStatePath !== statePath) (0, import_node_fs43.rmSync)(globalStatePath, { force: true });
45641
45797
  throw e;
45642
45798
  }
45643
45799
  const started = await startStage(config, {
@@ -45658,7 +45814,7 @@ function normPath2(p) {
45658
45814
  function unlinkNodeModulesJunction(wtPath) {
45659
45815
  const nm = (0, import_node_path42.join)(wtPath, "node_modules");
45660
45816
  try {
45661
- if ((0, import_node_fs43.lstatSync)(nm).isSymbolicLink()) (0, import_node_fs43.rmdirSync)(nm);
45817
+ if ((0, import_node_fs44.lstatSync)(nm).isSymbolicLink()) (0, import_node_fs44.rmdirSync)(nm);
45662
45818
  return { ok: true };
45663
45819
  } catch (e) {
45664
45820
  if (e.code === "ENOENT") return { ok: true };
@@ -45669,8 +45825,8 @@ function defaultSleep2(ms) {
45669
45825
  return new Promise((resolve8) => setTimeout(resolve8, ms));
45670
45826
  }
45671
45827
  async function removeResidueDirectory(wtPath, options = {}) {
45672
- const { sleep: sleep2 = defaultSleep2, removeEmptyDir = import_node_fs43.rmdirSync, exists = import_node_fs43.existsSync } = options;
45673
- const removeRecursive = options.removeRecursive ?? ((path2) => (0, import_node_fs43.rmSync)(path2, { recursive: true, force: true, maxRetries: 10, retryDelay: 100 }));
45828
+ const { sleep: sleep2 = defaultSleep2, removeEmptyDir = import_node_fs44.rmdirSync, exists = import_node_fs44.existsSync } = options;
45829
+ const removeRecursive = options.removeRecursive ?? ((path2) => (0, import_node_fs44.rmSync)(path2, { recursive: true, force: true, maxRetries: 10, retryDelay: 100 }));
45674
45830
  const junction = unlinkNodeModulesJunction(wtPath);
45675
45831
  if (!junction.ok) return junction;
45676
45832
  try {
@@ -45796,21 +45952,21 @@ async function listNestedIgnoredNodeModules(wtPath, execGit) {
45796
45952
  return out.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.endsWith("node_modules/") && line !== "node_modules/").map((line) => (0, import_node_path42.join)(wtPath, line.slice(0, -1)));
45797
45953
  }
45798
45954
  function safeRemoveTree(path2) {
45799
- const stat4 = (0, import_node_fs43.lstatSync)(path2);
45955
+ const stat4 = (0, import_node_fs44.lstatSync)(path2);
45800
45956
  if (stat4.isSymbolicLink()) {
45801
45957
  try {
45802
- (0, import_node_fs43.rmdirSync)(path2);
45958
+ (0, import_node_fs44.rmdirSync)(path2);
45803
45959
  } catch {
45804
- (0, import_node_fs43.unlinkSync)(path2);
45960
+ (0, import_node_fs44.unlinkSync)(path2);
45805
45961
  }
45806
45962
  return;
45807
45963
  }
45808
45964
  if (stat4.isDirectory()) {
45809
- for (const entry of (0, import_node_fs43.readdirSync)(path2)) safeRemoveTree((0, import_node_path42.join)(path2, entry));
45810
- (0, import_node_fs43.rmdirSync)(path2);
45965
+ for (const entry of (0, import_node_fs44.readdirSync)(path2)) safeRemoveTree((0, import_node_path42.join)(path2, entry));
45966
+ (0, import_node_fs44.rmdirSync)(path2);
45811
45967
  return;
45812
45968
  }
45813
- (0, import_node_fs43.unlinkSync)(path2);
45969
+ (0, import_node_fs44.unlinkSync)(path2);
45814
45970
  }
45815
45971
  async function removeWorktreeNodeModules(wtPath) {
45816
45972
  try {
@@ -45826,7 +45982,7 @@ function errorMessage(e) {
45826
45982
  }
45827
45983
  function resolvedOrRaw(path2) {
45828
45984
  try {
45829
- return normPath2((0, import_node_fs43.realpathSync)(path2));
45985
+ return normPath2((0, import_node_fs44.realpathSync)(path2));
45830
45986
  } catch {
45831
45987
  return normPath2(path2);
45832
45988
  }
@@ -45834,10 +45990,10 @@ function resolvedOrRaw(path2) {
45834
45990
  function unlinkEscapingReparsePoints(root, primaryRoot) {
45835
45991
  let realRoot;
45836
45992
  try {
45837
- if ((0, import_node_fs43.lstatSync)(root).isSymbolicLink()) {
45993
+ if ((0, import_node_fs44.lstatSync)(root).isSymbolicLink()) {
45838
45994
  return { ok: false, error: `delete root ${normPath2(root)} is a reparse point resolving to ${resolvedOrRaw(root)}` };
45839
45995
  }
45840
- realRoot = normPath2((0, import_node_fs43.realpathSync)(root));
45996
+ realRoot = normPath2((0, import_node_fs44.realpathSync)(root));
45841
45997
  } catch (e) {
45842
45998
  if (e.code === "ENOENT") return { ok: true, unlinked: [] };
45843
45999
  return { ok: false, error: `cannot resolve delete root ${normPath2(root)}: ${errorMessage(e)}` };
@@ -45853,7 +46009,7 @@ function unlinkEscapingReparsePoints(root, primaryRoot) {
45853
46009
  const dir = stack.pop();
45854
46010
  let entries;
45855
46011
  try {
45856
- entries = (0, import_node_fs43.readdirSync)(dir, { withFileTypes: true });
46012
+ entries = (0, import_node_fs44.readdirSync)(dir, { withFileTypes: true });
45857
46013
  } catch (e) {
45858
46014
  if (e.code === "ENOENT") continue;
45859
46015
  return { ok: false, error: `cannot scan ${normPath2(dir)} for reparse points: ${errorMessage(e)}` };
@@ -45863,7 +46019,7 @@ function unlinkEscapingReparsePoints(root, primaryRoot) {
45863
46019
  if (entry.isSymbolicLink()) {
45864
46020
  let target = "";
45865
46021
  try {
45866
- target = normPath2((0, import_node_fs43.realpathSync)(child2));
46022
+ target = normPath2((0, import_node_fs44.realpathSync)(child2));
45867
46023
  } catch {
45868
46024
  target = "";
45869
46025
  }
@@ -46046,7 +46202,7 @@ async function cleanupPrMergeLocalBranch(branch, options) {
46046
46202
  return report;
46047
46203
  }
46048
46204
  const execGit = options.execGit ?? (async (args) => (await execFileP("git", args, { timeout: GIT_TIMEOUT_MS })).stdout);
46049
- const pathExists = options.pathExists ?? import_node_fs43.existsSync;
46205
+ const pathExists = options.pathExists ?? import_node_fs44.existsSync;
46050
46206
  let afterWorktrees = [];
46051
46207
  try {
46052
46208
  afterWorktrees = parseGitWorktreePorcelain(await execGit(["worktree", "list", "--porcelain"]));
@@ -46333,7 +46489,7 @@ function residueLedgerPath(gitCommonDir) {
46333
46489
  }
46334
46490
  function readPaths(file, deps) {
46335
46491
  try {
46336
- const parsed = JSON.parse((deps.readLedger ?? ((f) => (0, import_node_fs44.readFileSync)(f, "utf8")))(file));
46492
+ const parsed = JSON.parse((deps.readLedger ?? ((f) => (0, import_node_fs45.readFileSync)(f, "utf8")))(file));
46337
46493
  return Array.isArray(parsed) ? parsed.filter((p) => typeof p === "string") : [];
46338
46494
  } catch {
46339
46495
  return [];
@@ -46342,8 +46498,8 @@ function readPaths(file, deps) {
46342
46498
  function writePaths(file, paths, deps) {
46343
46499
  try {
46344
46500
  const write = deps.writeLedger ?? ((f, t) => {
46345
- (0, import_node_fs44.mkdirSync)((0, import_node_path43.dirname)(f), { recursive: true });
46346
- (0, import_node_fs44.writeFileSync)(f, t, "utf8");
46501
+ (0, import_node_fs45.mkdirSync)((0, import_node_path43.dirname)(f), { recursive: true });
46502
+ (0, import_node_fs45.writeFileSync)(f, t, "utf8");
46347
46503
  });
46348
46504
  write(file, `${JSON.stringify([...new Set(paths)], null, 1)}
46349
46505
  `);
@@ -46357,17 +46513,17 @@ function recordResidue(gitCommonDir, path2, deps = {}) {
46357
46513
  writePaths(file, paths, deps);
46358
46514
  }
46359
46515
  async function sweepWorktreeResidue(gitCommonDir, registered, deps = {}) {
46360
- const exists = deps.exists ?? import_node_fs44.existsSync;
46361
- const readDir = deps.readDir ?? ((p) => (0, import_node_fs44.readdirSync)(p));
46516
+ const exists = deps.exists ?? import_node_fs45.existsSync;
46517
+ const readDir = deps.readDir ?? ((p) => (0, import_node_fs45.readdirSync)(p));
46362
46518
  const isDir = deps.isDir ?? ((p) => {
46363
46519
  try {
46364
- return (0, import_node_fs44.statSync)(p).isDirectory();
46520
+ return (0, import_node_fs45.statSync)(p).isDirectory();
46365
46521
  } catch {
46366
46522
  return false;
46367
46523
  }
46368
46524
  });
46369
46525
  const removeRecorded = deps.removeRecorded ?? ((p) => removeResidueDirectory(p));
46370
- const removeEmpty = deps.removeEmpty ?? ((p) => (0, import_node_fs44.rmdirSync)(p));
46526
+ const removeEmpty = deps.removeEmpty ?? ((p) => (0, import_node_fs45.rmdirSync)(p));
46371
46527
  const report = { swept: [], kept: [], dropped: [], emptyRemoved: [], unrecorded: [] };
46372
46528
  const live = new Set(registered.map(norm));
46373
46529
  const primary = registered[0] ? norm(registered[0]) : void 0;
@@ -46447,8 +46603,8 @@ function argvWantsJson2() {
46447
46603
  function hubRoot() {
46448
46604
  const fromPkg = (0, import_node_path44.join)(__dirname, "..", "..");
46449
46605
  const marker = "skills/bootstrap/seeds/manifest.json";
46450
- if ((0, import_node_fs45.existsSync)((0, import_node_path44.join)(fromPkg, marker))) return fromPkg;
46451
- if ((0, import_node_fs45.existsSync)((0, import_node_path44.join)(process.cwd(), marker))) return process.cwd();
46606
+ if ((0, import_node_fs46.existsSync)((0, import_node_path44.join)(fromPkg, marker))) return fromPkg;
46607
+ if ((0, import_node_fs46.existsSync)((0, import_node_path44.join)(process.cwd(), marker))) return process.cwd();
46452
46608
  return null;
46453
46609
  }
46454
46610
  function ciAuditDeps() {
@@ -46461,7 +46617,7 @@ function ciAuditDeps() {
46461
46617
  readSeedFile: (path2) => {
46462
46618
  if (!root) return null;
46463
46619
  const fullPath = (0, import_node_path44.join)(root, path2);
46464
- return (0, import_node_fs45.existsSync)(fullPath) ? (0, import_node_fs45.readFileSync)(fullPath, "utf8") : null;
46620
+ return (0, import_node_fs46.existsSync)(fullPath) ? (0, import_node_fs46.readFileSync)(fullPath, "utf8") : null;
46465
46621
  }
46466
46622
  };
46467
46623
  }
@@ -47225,10 +47381,10 @@ ${list}`);
47225
47381
  });
47226
47382
  async function listCiWorkflowPaths(cwd = process.cwd()) {
47227
47383
  const wfDir = (0, import_node_path44.join)(cwd, ".github", "workflows");
47228
- if (!(0, import_node_fs45.existsSync)(wfDir)) return [];
47229
- return (0, import_node_fs45.readdirSync)(wfDir).filter((name) => /\.(ya?ml)$/i.test(name)).filter((name) => {
47384
+ if (!(0, import_node_fs46.existsSync)(wfDir)) return [];
47385
+ return (0, import_node_fs46.readdirSync)(wfDir).filter((name) => /\.(ya?ml)$/i.test(name)).filter((name) => {
47230
47386
  try {
47231
- return workflowReportsPrChecks((0, import_node_fs45.readFileSync)((0, import_node_path44.join)(wfDir, name), "utf8"));
47387
+ return workflowReportsPrChecks((0, import_node_fs46.readFileSync)((0, import_node_path44.join)(wfDir, name), "utf8"));
47232
47388
  } catch {
47233
47389
  return true;
47234
47390
  }
@@ -47433,7 +47589,7 @@ ${list}`);
47433
47589
  jsonParity(pr.command("review-verdict <number>").description("post an explicit review verdict comment: computes the PR diff patch-id and head sha, renders the v1 contract body, and posts it as a PR comment").requiredOption("--repo <owner/repo>", "target repo").requiredOption("--verdict <verdict>", `one of ${REVIEW_VERDICTS.join("|")}`).requiredOption("--scope <text>", "one line: what was reviewed").requiredOption("--risk <text>", "one line: the residual risk").option("--unverified <text>", "a claim the reviewer could not verify (repeatable)", (v, acc) => [...acc, v], []).requiredOption("--reviewer <id>", "reviewer seat or model id").option("--findings-file <path>", "Markdown findings appended after the JSON block")).action(async (number, o) => {
47434
47590
  if (!isReviewVerdict(o.verdict)) return fail(`pr review-verdict: --verdict must be one of ${REVIEW_VERDICTS.join("|")} (got ${o.verdict})`);
47435
47591
  const verdict = o.verdict;
47436
- const findings = o.findingsFile ? (0, import_node_fs45.readFileSync)(o.findingsFile, "utf8") : void 0;
47592
+ const findings = o.findingsFile ? (0, import_node_fs46.readFileSync)(o.findingsFile, "utf8") : void 0;
47437
47593
  let patch;
47438
47594
  let head;
47439
47595
  try {
@@ -47689,7 +47845,7 @@ ${list}`);
47689
47845
  const cleanupMerged = async (r) => {
47690
47846
  if (opts.preserveWorktree) return "cleanup skipped (--preserve-worktree)";
47691
47847
  const ran = await execFileP(process.execPath, [process.argv[1], ...canonicalArgvFor(["pr", "merge", r.pr, "--repo", r.repo])], {
47692
- cwd: (0, import_node_fs45.existsSync)(cwd0) ? cwd0 : primaryRoot0,
47848
+ cwd: (0, import_node_fs46.existsSync)(cwd0) ? cwd0 : primaryRoot0,
47693
47849
  timeout: GH_MUTATION_TIMEOUT_MS * 3
47694
47850
  }).then((x) => ({ stdout: x.stdout, stderr: x.stderr }), (e) => ({ stdout: e.stdout ?? "", stderr: e.stderr ?? "" }));
47695
47851
  const json = ran.stdout.split("\n").reverse().find((l) => l.startsWith("{"));
@@ -47759,7 +47915,7 @@ ${list}`);
47759
47915
  const mergeSquashBody = squashBodyTextForMerge(
47760
47916
  closingGuardInput,
47761
47917
  method === "--squash",
47762
- o.squashBodyFile ? (0, import_node_fs45.readFileSync)(o.squashBodyFile, "utf8") : void 0
47918
+ o.squashBodyFile ? (0, import_node_fs46.readFileSync)(o.squashBodyFile, "utf8") : void 0
47763
47919
  );
47764
47920
  if (!o.squashBodyFile) warnSquashBodyClosingStrip("pr merge", closingGuardInput, mergeSquashBody);
47765
47921
  const closingGuardVerdict = evaluateClosingGuard(closingGuardInput, {
@@ -47910,7 +48066,7 @@ ${list}`);
47910
48066
  }
47911
48067
  if (!repoForPostCleanup) throw e;
47912
48068
  console.warn(`pr merge: gh GraphQL rate-limited \u2014 merging PR #${number} via REST PUT instead (#4588).`);
47913
- const commitMessage = bodyFile ? (0, import_node_fs45.readFileSync)(bodyFile, "utf8") : void 0;
48069
+ const commitMessage = bodyFile ? (0, import_node_fs46.readFileSync)(bodyFile, "utf8") : void 0;
47914
48070
  await defaultGitHubClient().rest("PUT", `repos/${repoForPostCleanup}/pulls/${number}/merge`, {
47915
48071
  body: { merge_method: method.slice(2), ...commitMessage ? { commit_message: commitMessage } : {} },
47916
48072
  timeoutMs: GH_MUTATION_TIMEOUT_MS
@@ -48043,7 +48199,7 @@ ${list}`);
48043
48199
  preserveWorktree: o.preserveWorktree,
48044
48200
  gcAcknowledged: o.gc,
48045
48201
  expectedHeadOid: headRefOid,
48046
- pathExists: (p) => (0, import_node_fs45.existsSync)(p),
48202
+ pathExists: (p) => (0, import_node_fs46.existsSync)(p),
48047
48203
  // #5899: pin cleanup git calls to the main checkout — the task worktree this process may be
48048
48204
  // standing in is removed mid-cleanup, so a cwd-relative invocation fails with
48049
48205
  // 'fatal: not a git repository' and leaves a spurious partial-cleanup exit.
@@ -49343,11 +49499,11 @@ function suiteTrainIo(root, summaryFile, memberSummaryFiles = {}, summaryFileTr,
49343
49499
  const checkout = async (repo) => {
49344
49500
  if (repo === SUITE_REPO) return root;
49345
49501
  const target = (0, import_node_path46.join)(base, repo.split("/")[1]);
49346
- if (!(0, import_node_fs46.existsSync)(target)) {
49347
- (0, import_node_fs46.mkdirSync)(base, { recursive: true });
49502
+ if (!(0, import_node_fs47.existsSync)(target)) {
49503
+ (0, import_node_fs47.mkdirSync)(base, { recursive: true });
49348
49504
  await exec("git", ["clone", "--quiet", "--branch", "development", `https://github.com/${repo}.git`, target], root, WATCH_TIMEOUT);
49349
49505
  }
49350
- if (!(0, import_node_fs46.existsSync)((0, import_node_path46.join)(target, ".git"))) throw new Error(`${repo}: suite checkout has no .git at ${target}; stop`);
49506
+ if (!(0, import_node_fs47.existsSync)((0, import_node_path46.join)(target, ".git"))) throw new Error(`${repo}: suite checkout has no .git at ${target}; stop`);
49351
49507
  const origin = await exec("git", ["remote", "get-url", "origin"], target);
49352
49508
  if (!origin.toLowerCase().endsWith(`/${repo.toLowerCase()}.git`) && !origin.toLowerCase().endsWith(`/${repo.toLowerCase()}`))
49353
49509
  throw new Error(`${repo}: suite checkout origin mismatch at ${target}; stop`);
@@ -49654,9 +49810,9 @@ function suiteTrainIo(root, summaryFile, memberSummaryFiles = {}, summaryFileTr,
49654
49810
  const body = await gh(["release", "view", leadTag, "--repo", SUITE_REPO, "--json", "body", "--jq", ".body"]);
49655
49811
  if (parseSuiteMapping(body)) return;
49656
49812
  const dir = suiteStateDir(root);
49657
- (0, import_node_fs46.mkdirSync)(dir, { recursive: true });
49813
+ (0, import_node_fs47.mkdirSync)(dir, { recursive: true });
49658
49814
  const file = (0, import_node_path46.join)(dir, `notes-${leadTag}.md`);
49659
- (0, import_node_fs46.writeFileSync)(file, `${body}
49815
+ (0, import_node_fs47.writeFileSync)(file, `${body}
49660
49816
 
49661
49817
  ${suiteMappingBlock(leadTag, mapping)}`);
49662
49818
  await gh(["release", "edit", leadTag, "--repo", SUITE_REPO, "--notes-file", file]);
@@ -49697,7 +49853,7 @@ ${suiteMappingBlock(leadTag, mapping)}`);
49697
49853
 
49698
49854
  // src/suite-commands.ts
49699
49855
  init_cli_shared();
49700
- var import_node_fs47 = require("node:fs");
49856
+ var import_node_fs48 = require("node:fs");
49701
49857
  function parseMemberSummaryFiles(entries) {
49702
49858
  const memberSummaryFiles = {};
49703
49859
  for (const entry of entries) {
@@ -49791,7 +49947,7 @@ function registerSuiteCommands(program3) {
49791
49947
  try {
49792
49948
  const io = suiteTrainIo(root);
49793
49949
  retired = await retireFailedLeadRcLedger({ ledgerPath: releaseLedgerPath(root), rcHead: () => io.head(SUITE_REPO, "rc").then((h) => h ?? void 0), markAbandoned: io.markAbandoned }, o.ownerGo === true);
49794
- if (retired && !(0, import_node_fs47.existsSync)(io.recordPath)) {
49950
+ if (retired && !(0, import_node_fs48.existsSync)(io.recordPath)) {
49795
49951
  console.log(o.json ? JSON.stringify({ retiredLeadRc: retired }, null, 2) : `suite abandon: retired the lead's failed, never-promoted rc candidate ${retired}; marked abandoned on origin (#7854)`);
49796
49952
  return;
49797
49953
  }
@@ -49980,7 +50136,7 @@ function suiteStatusDeps(github, registry2) {
49980
50136
 
49981
50137
  // src/packages-adopt-export.ts
49982
50138
  var import_node_child_process19 = require("node:child_process");
49983
- var import_node_fs48 = require("node:fs");
50139
+ var import_node_fs49 = require("node:fs");
49984
50140
  var import_node_os22 = require("node:os");
49985
50141
  var import_node_path47 = require("node:path");
49986
50142
  var import_node_util6 = require("node:util");
@@ -50604,36 +50760,36 @@ async function adoptExport(opts, deps) {
50604
50760
  if (!/^sha256:[0-9a-f]{64}$/.test(opts.digest)) throw new Error("--digest must be sha256:<64 hex>, from the export run summary");
50605
50761
  const packagePath = (0, import_node_path47.join)(opts.dir, "package.json");
50606
50762
  const lockPath = (0, import_node_path47.join)(opts.dir, "package-lock.json");
50607
- const packageText = (0, import_node_fs48.readFileSync)(packagePath, "utf8");
50608
- const lockText = (0, import_node_fs48.readFileSync)(lockPath, "utf8");
50609
- const work = (0, import_node_fs48.mkdtempSync)((0, import_node_path47.join)((0, import_node_os22.tmpdir)(), "mmi-adopt-export-"));
50763
+ const packageText = (0, import_node_fs49.readFileSync)(packagePath, "utf8");
50764
+ const lockText = (0, import_node_fs49.readFileSync)(lockPath, "utf8");
50765
+ const work = (0, import_node_fs49.mkdtempSync)((0, import_node_path47.join)((0, import_node_os22.tmpdir)(), "mmi-adopt-export-"));
50610
50766
  try {
50611
50767
  const run = JSON.parse((await deps.ghApi(`repos/${EXPORT_REPO}/actions/runs/${opts.run}`)).toString("utf8"));
50612
- (0, import_node_fs48.writeFileSync)((0, import_node_path47.join)(work, "expected.json"), JSON.stringify(expectedFromRun(run, opts)));
50613
- (0, import_node_fs48.writeFileSync)((0, import_node_path47.join)(work, "provider.json"), await deps.ghApi(`repos/${EXPORT_REPO}/actions/artifacts/${opts.artifact}`));
50614
- (0, import_node_fs48.writeFileSync)((0, import_node_path47.join)(work, "artifact.zip"), await deps.ghApi(`repos/${EXPORT_REPO}/actions/artifacts/${opts.artifact}/zip`));
50768
+ (0, import_node_fs49.writeFileSync)((0, import_node_path47.join)(work, "expected.json"), JSON.stringify(expectedFromRun(run, opts)));
50769
+ (0, import_node_fs49.writeFileSync)((0, import_node_path47.join)(work, "provider.json"), await deps.ghApi(`repos/${EXPORT_REPO}/actions/artifacts/${opts.artifact}`));
50770
+ (0, import_node_fs49.writeFileSync)((0, import_node_path47.join)(work, "artifact.zip"), await deps.ghApi(`repos/${EXPORT_REPO}/actions/artifacts/${opts.artifact}/zip`));
50615
50771
  const script = (0, import_node_path47.join)(work, "package_export.py");
50616
- (0, import_node_fs48.writeFileSync)(script, package_export_default);
50772
+ (0, import_node_fs49.writeFileSync)(script, package_export_default);
50617
50773
  await deps.python(script, ["verify", work, opts.ds, opts.screens]);
50618
50774
  const verified = (0, import_node_path47.join)(work, "verified");
50619
- const metadata = Object.fromEntries(PACKAGES.map(({ name, short: short3 }) => [name, JSON.parse((0, import_node_fs48.readFileSync)((0, import_node_path47.join)(verified, `${short3}.metadata.json`), "utf8"))]));
50775
+ const metadata = Object.fromEntries(PACKAGES.map(({ name, short: short3 }) => [name, JSON.parse((0, import_node_fs49.readFileSync)((0, import_node_path47.join)(verified, `${short3}.metadata.json`), "utf8"))]));
50620
50776
  const plan = planAdoption(packageText, lockText, metadata);
50621
50777
  for (const { name } of plan.result.adopted) {
50622
50778
  const short3 = PACKAGES.find((p) => p.name === name).short;
50623
50779
  await deps.npm(["cache", "add", (0, import_node_path47.join)(verified, `${short3}.tgz`)], opts.dir);
50624
50780
  }
50625
- (0, import_node_fs48.writeFileSync)(packagePath, plan.packageText);
50626
- (0, import_node_fs48.writeFileSync)(lockPath, plan.lockText);
50781
+ (0, import_node_fs49.writeFileSync)(packagePath, plan.packageText);
50782
+ (0, import_node_fs49.writeFileSync)(lockPath, plan.lockText);
50627
50783
  try {
50628
50784
  await deps.npm(["ci", "--offline", "--ignore-scripts", "--no-audit", "--no-fund"], opts.dir);
50629
50785
  } catch (error) {
50630
- (0, import_node_fs48.writeFileSync)(packagePath, packageText);
50631
- (0, import_node_fs48.writeFileSync)(lockPath, lockText);
50786
+ (0, import_node_fs49.writeFileSync)(packagePath, packageText);
50787
+ (0, import_node_fs49.writeFileSync)(lockPath, lockText);
50632
50788
  throw new Error(`npm ci --offline failed, package.json and package-lock.json restored: ${error.message}`);
50633
50789
  }
50634
50790
  return plan.result;
50635
50791
  } finally {
50636
- (0, import_node_fs48.rmSync)(work, { recursive: true, force: true });
50792
+ (0, import_node_fs49.rmSync)(work, { recursive: true, force: true });
50637
50793
  }
50638
50794
  }
50639
50795
  var execFileBuffer = (0, import_node_util6.promisify)(import_node_child_process19.execFile);
@@ -50698,12 +50854,12 @@ function registerPackagesCommands(program3) {
50698
50854
  init_cli_shared();
50699
50855
 
50700
50856
  // src/wave-status.ts
50701
- var import_node_fs49 = require("node:fs");
50857
+ var import_node_fs50 = require("node:fs");
50702
50858
  function readStageSummary(worktreePath) {
50703
50859
  const statePath = stageStatePath(worktreePath);
50704
- if (!(0, import_node_fs49.existsSync)(statePath)) return void 0;
50860
+ if (!(0, import_node_fs50.existsSync)(statePath)) return void 0;
50705
50861
  try {
50706
- const state = JSON.parse((0, import_node_fs49.readFileSync)(statePath, "utf8"));
50862
+ const state = JSON.parse((0, import_node_fs50.readFileSync)(statePath, "utf8"));
50707
50863
  const port = typeof state.port === "number" ? state.port : void 0;
50708
50864
  if (port == null || !Number.isInteger(port) || port <= 0) return void 0;
50709
50865
  return { port, url: typeof state.url === "string" ? state.url : void 0 };
@@ -50760,7 +50916,7 @@ async function collectWaveStatus(deps) {
50760
50916
  // src/discovery-commands.ts
50761
50917
  init_github_client();
50762
50918
  init_cli_shared();
50763
- var import_node_fs50 = require("node:fs");
50919
+ var import_node_fs51 = require("node:fs");
50764
50920
  var import_node_os23 = require("node:os");
50765
50921
  var import_node_path48 = require("node:path");
50766
50922
  var GC_GH_TIMEOUT_MS3 = 2e4;
@@ -50953,8 +51109,8 @@ async function collectOnboardStatus(opts = {}) {
50953
51109
  }
50954
51110
  const home = (0, import_node_os23.homedir)();
50955
51111
  const plugin = onboardPluginGate({
50956
- readKnown: () => readFileSyncSafe((0, import_node_path48.join)(home, ...KNOWN_MARKETPLACES_RELATIVE), import_node_fs50.readFileSync),
50957
- readSettings: () => readFileSyncSafe((0, import_node_path48.join)(home, ".claude", "settings.json"), import_node_fs50.readFileSync)
51112
+ readKnown: () => readFileSyncSafe((0, import_node_path48.join)(home, ...KNOWN_MARKETPLACES_RELATIVE), import_node_fs51.readFileSync),
51113
+ readSettings: () => readFileSyncSafe((0, import_node_path48.join)(home, ".claude", "settings.json"), import_node_fs51.readFileSync)
50958
51114
  });
50959
51115
  return {
50960
51116
  guide: "Read the MMI org-guide skill before project work; load only the relevant topic. Use mmi-help for a short introduction.",
@@ -53148,7 +53304,7 @@ function registerOrgHealthQuery(program3, deps = defaultOrgHealthQueryDeps()) {
53148
53304
  }
53149
53305
 
53150
53306
  // src/api-read.ts
53151
- var import_node_fs51 = require("node:fs");
53307
+ var import_node_fs52 = require("node:fs");
53152
53308
 
53153
53309
  // src/run-log-read.ts
53154
53310
  init_cli_shared();
@@ -53749,7 +53905,7 @@ function registerApiReadCommands(program3, overrides) {
53749
53905
  o.accept
53750
53906
  );
53751
53907
  if (zip) {
53752
- (0, import_node_fs51.writeFileSync)(o.out, body, "latin1");
53908
+ (0, import_node_fs52.writeFileSync)(o.out, body, "latin1");
53753
53909
  return;
53754
53910
  }
53755
53911
  } catch (e) {
@@ -54624,7 +54780,7 @@ function registerSessionReport(program3) {
54624
54780
  }
54625
54781
 
54626
54782
  // src/stage-commands.ts
54627
- var import_node_fs52 = require("node:fs");
54783
+ var import_node_fs53 = require("node:fs");
54628
54784
  var import_node_path49 = require("node:path");
54629
54785
  init_cli_shared();
54630
54786
  init_clean_exit();
@@ -54873,8 +55029,8 @@ function registerStageCommands(program3) {
54873
55029
  const repo = Array.isArray(project2?.repos) && typeof project2.repos[0] === "string" ? project2.repos[0] : slug;
54874
55030
  const resolution = decideStage({
54875
55031
  registry: { deployModel: project2?.deployModel, portRange, error: read.ok ? void 0 : read.error },
54876
- hasCompose: (0, import_node_fs52.existsSync)((0, import_node_path49.join)(process.cwd(), "docker-compose.yml")),
54877
- hasEnvExample: (0, import_node_fs52.existsSync)((0, import_node_path49.join)(process.cwd(), ".env.example")),
55032
+ hasCompose: (0, import_node_fs53.existsSync)((0, import_node_path49.join)(process.cwd(), "docker-compose.yml")),
55033
+ hasEnvExample: (0, import_node_fs53.existsSync)((0, import_node_path49.join)(process.cwd(), ".env.example")),
54878
55034
  repo
54879
55035
  });
54880
55036
  if (resolution.source === "derived" && resolution.derived) {
@@ -55167,14 +55323,14 @@ vercel preview (${preview.branch}): ${d.state}${d.url ? ` \u2014 ${d.url}` : ""}
55167
55323
 
55168
55324
  // src/tenant-artifact.ts
55169
55325
  var import_node_crypto17 = require("node:crypto");
55170
- var import_node_fs53 = require("node:fs");
55326
+ var import_node_fs54 = require("node:fs");
55171
55327
  var import_promises11 = require("node:fs/promises");
55172
55328
  var import_node_path50 = require("node:path");
55173
55329
  var ARTIFACT_ID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
55174
55330
  var MAX_BYTES2 = 5 * 1024 * 1024 * 1024;
55175
55331
  async function sha256File(path2) {
55176
55332
  const hash = (0, import_node_crypto17.createHash)("sha256");
55177
- for await (const chunk of (0, import_node_fs53.createReadStream)(path2)) hash.update(chunk);
55333
+ for await (const chunk of (0, import_node_fs54.createReadStream)(path2)) hash.update(chunk);
55178
55334
  return hash.digest("hex");
55179
55335
  }
55180
55336
  async function putTenantArtifact(repo, stage, inputPath, deps) {
@@ -55197,7 +55353,7 @@ async function putTenantArtifact(repo, stage, inputPath, deps) {
55197
55353
  return [key, value];
55198
55354
  }));
55199
55355
  headers["content-length"] = String(info.size);
55200
- const stream = (0, import_node_fs53.createReadStream)(path2);
55356
+ const stream = (0, import_node_fs54.createReadStream)(path2);
55201
55357
  let uploaded;
55202
55358
  try {
55203
55359
  uploaded = await fetch(body.uploadUrl, {
@@ -55336,7 +55492,7 @@ function renderVerifySecrets(body) {
55336
55492
  }
55337
55493
 
55338
55494
  // src/command-register-developer.ts
55339
- var import_node_fs57 = require("node:fs");
55495
+ var import_node_fs58 = require("node:fs");
55340
55496
  init_clean_exit();
55341
55497
  init_cli_shared();
55342
55498
  init_error_codes();
@@ -55404,13 +55560,13 @@ async function executeWaveLand(plan, deps) {
55404
55560
  // src/dist-drift.ts
55405
55561
  var import_node_child_process20 = require("node:child_process");
55406
55562
  var import_node_crypto19 = require("node:crypto");
55407
- var import_node_fs55 = require("node:fs");
55563
+ var import_node_fs56 = require("node:fs");
55408
55564
  var import_node_os24 = require("node:os");
55409
55565
  var import_node_path52 = require("node:path");
55410
55566
 
55411
55567
  // ../scripts/distribution-digest.mjs
55412
55568
  var import_node_crypto18 = require("node:crypto");
55413
- var import_node_fs54 = require("node:fs");
55569
+ var import_node_fs55 = require("node:fs");
55414
55570
  var import_node_path51 = require("node:path");
55415
55571
  var slash = (value) => value.replaceAll("\\", "/");
55416
55572
  function repoPath(root, declaredPath, label) {
@@ -55424,7 +55580,7 @@ function repoPath(root, declaredPath, label) {
55424
55580
  function digestFiles(files) {
55425
55581
  const hash = (0, import_node_crypto18.createHash)("sha256");
55426
55582
  for (const file of [...files].sort((a, b) => a.relative.localeCompare(b.relative))) {
55427
- const content = file.stat.isSymbolicLink() ? Buffer.from((0, import_node_fs54.readlinkSync)(file.absolute), "utf8") : (0, import_node_fs54.readFileSync)(file.absolute);
55583
+ const content = file.stat.isSymbolicLink() ? Buffer.from((0, import_node_fs55.readlinkSync)(file.absolute), "utf8") : (0, import_node_fs55.readFileSync)(file.absolute);
55428
55584
  hash.update(file.relative, "utf8");
55429
55585
  hash.update("\0");
55430
55586
  hash.update(file.stat.isSymbolicLink() ? "symlink" : "file", "utf8");
@@ -55439,8 +55595,8 @@ function digestFiles(files) {
55439
55595
  function digestPackedFiles(packageRoot, packedFiles) {
55440
55596
  return digestFiles(packedFiles.map((path2) => {
55441
55597
  const absolute = repoPath(packageRoot, path2, "packed artifact identity path");
55442
- if (!(0, import_node_fs54.existsSync)(absolute)) throw new Error(`packed artifact identity path ${path2} does not exist`);
55443
- return { absolute, relative: slash(path2), stat: (0, import_node_fs54.lstatSync)(absolute) };
55598
+ if (!(0, import_node_fs55.existsSync)(absolute)) throw new Error(`packed artifact identity path ${path2} does not exist`);
55599
+ return { absolute, relative: slash(path2), stat: (0, import_node_fs55.lstatSync)(absolute) };
55444
55600
  }));
55445
55601
  }
55446
55602
 
@@ -55525,12 +55681,12 @@ function renderDistDriftReceipt(receipt) {
55525
55681
  return lines2;
55526
55682
  }
55527
55683
  function readOrNull(path2) {
55528
- return (0, import_node_fs55.existsSync)(path2) ? (0, import_node_fs55.readFileSync)(path2) : null;
55684
+ return (0, import_node_fs56.existsSync)(path2) ? (0, import_node_fs56.readFileSync)(path2) : null;
55529
55685
  }
55530
55686
  function walkFiles(root) {
55531
55687
  const files = [];
55532
55688
  const walk2 = (directory) => {
55533
- for (const entry of (0, import_node_fs55.readdirSync)(directory, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
55689
+ for (const entry of (0, import_node_fs56.readdirSync)(directory, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
55534
55690
  const child2 = (0, import_node_path52.join)(directory, entry.name);
55535
55691
  if (entry.isDirectory()) walk2(child2);
55536
55692
  else files.push(child2);
@@ -55541,7 +55697,7 @@ function walkFiles(root) {
55541
55697
  }
55542
55698
  function bomPathFor(root) {
55543
55699
  try {
55544
- const registry2 = JSON.parse((0, import_node_fs55.readFileSync)((0, import_node_path52.join)(root, "surfaces.json"), "utf8"));
55700
+ const registry2 = JSON.parse((0, import_node_fs56.readFileSync)((0, import_node_path52.join)(root, "surfaces.json"), "utf8"));
55545
55701
  return (0, import_node_path52.join)(root, registry2?.sharedAgentCore?.releaseMetadata?.bomPath ?? "distribution-bom.json");
55546
55702
  } catch {
55547
55703
  return (0, import_node_path52.join)(root, "distribution-bom.json");
@@ -55557,7 +55713,7 @@ function rebuildTo(packageRoot, outDir) {
55557
55713
  });
55558
55714
  }
55559
55715
  function runDistStatus(root) {
55560
- const stage = (0, import_node_fs55.mkdtempSync)((0, import_node_path52.join)((0, import_node_os24.tmpdir)(), "mmi-dist-drift-"));
55716
+ const stage = (0, import_node_fs56.mkdtempSync)((0, import_node_path52.join)((0, import_node_os24.tmpdir)(), "mmi-dist-drift-"));
55561
55717
  let overlayCount = 0;
55562
55718
  try {
55563
55719
  const cliOut = (0, import_node_path52.join)(stage, "cli-dist");
@@ -55573,19 +55729,19 @@ function runDistStatus(root) {
55573
55729
  const tree = (path2) => readOrNull((0, import_node_path52.join)(root, path2));
55574
55730
  const distRoot = (0, import_node_path52.join)(root, "cli", "dist");
55575
55731
  const distTree = () => walkFiles(distRoot).map((absolute) => `cli/dist/${(0, import_node_path52.relative)(distRoot, absolute).replaceAll("\\", "/")}`);
55576
- const bom = JSON.parse((0, import_node_fs55.readFileSync)(bomPathFor(root), "utf8"));
55732
+ const bom = JSON.parse((0, import_node_fs56.readFileSync)(bomPathFor(root), "utf8"));
55577
55733
  const digest = (entries) => {
55578
55734
  const overlay = (0, import_node_path52.join)(stage, `overlay-${overlayCount++}`);
55579
55735
  for (const entry of entries) {
55580
55736
  const target = (0, import_node_path52.join)(overlay, entry.path);
55581
- (0, import_node_fs55.mkdirSync)((0, import_node_path52.dirname)(target), { recursive: true });
55582
- (0, import_node_fs55.writeFileSync)(target, entry.bytes);
55737
+ (0, import_node_fs56.mkdirSync)((0, import_node_path52.dirname)(target), { recursive: true });
55738
+ (0, import_node_fs56.writeFileSync)(target, entry.bytes);
55583
55739
  }
55584
55740
  return digestPackedFiles(overlay, entries.map((entry) => entry.path));
55585
55741
  };
55586
55742
  return computeDistDriftReceipt({ committed, tree, rebuilt, distTree, bom, digest });
55587
55743
  } finally {
55588
- (0, import_node_fs55.rmSync)(stage, { recursive: true, force: true });
55744
+ (0, import_node_fs56.rmSync)(stage, { recursive: true, force: true });
55589
55745
  }
55590
55746
  }
55591
55747
 
@@ -55915,7 +56071,7 @@ function registerSchedulesLiftCommand(program3, deps = {}) {
55915
56071
 
55916
56072
  // src/spawn-policy-core.ts
55917
56073
  var import_node_child_process22 = require("node:child_process");
55918
- var import_node_fs56 = require("node:fs");
56074
+ var import_node_fs57 = require("node:fs");
55919
56075
  var import_node_path55 = require("node:path");
55920
56076
  var SPAWNERS = ["spawn", "spawnSync", "exec", "execSync", "execFile", "execFileSync"];
55921
56077
  var CALL_SOURCE = String.raw`(^|[^.\w$])(${SPAWNERS.join("|")})\s*\(`;
@@ -56002,7 +56158,7 @@ function runSpawnPolicy(root) {
56002
56158
  for (const file of files) {
56003
56159
  let raw;
56004
56160
  try {
56005
- raw = (0, import_node_fs56.readFileSync)((0, import_node_path55.join)(root, file), "utf8");
56161
+ raw = (0, import_node_fs57.readFileSync)((0, import_node_path55.join)(root, file), "utf8");
56006
56162
  } catch {
56007
56163
  continue;
56008
56164
  }
@@ -56023,18 +56179,18 @@ function registerDeveloperCommands(program3) {
56023
56179
  const rules = program3.command("rules").description("org-managed .gitignore delivery");
56024
56180
  rules.command("gitignore").option("--write", "upsert the managed block into .gitignore (default: check only, non-zero exit on drift)").option("--json", "machine-readable output").description("verify (or --write) this repo's org-managed .gitignore block matches the SSOT").action((opts) => {
56025
56181
  const path2 = (0, import_node_path56.join)(process.cwd(), ".gitignore");
56026
- const current = (0, import_node_fs57.existsSync)(path2) ? (0, import_node_fs57.readFileSync)(path2, "utf8") : null;
56182
+ const current = (0, import_node_fs58.existsSync)(path2) ? (0, import_node_fs58.readFileSync)(path2, "utf8") : null;
56027
56183
  const plan = planManagedGitignore(current);
56028
56184
  const drift = [...plan.added.map((l) => `+${l}`), ...plan.removed.map((l) => `-${l}`)].join(", ") || "block normalize";
56029
56185
  if (opts.json) {
56030
- if (opts.write && plan.changed) (0, import_node_fs57.writeFileSync)(path2, plan.content, "utf8");
56186
+ if (opts.write && plan.changed) (0, import_node_fs58.writeFileSync)(path2, plan.content, "utf8");
56031
56187
  console.log(JSON.stringify(plan, null, 2));
56032
56188
  if (!opts.write && plan.changed) process.exitCode = 1;
56033
56189
  return;
56034
56190
  }
56035
56191
  if (opts.write) {
56036
56192
  if (plan.changed) {
56037
- (0, import_node_fs57.writeFileSync)(path2, plan.content, "utf8");
56193
+ (0, import_node_fs58.writeFileSync)(path2, plan.content, "utf8");
56038
56194
  console.log(`mmi-cli devops org rules gitignore: updated .gitignore (${drift})`);
56039
56195
  } else {
56040
56196
  console.log("mmi-cli devops org rules gitignore: up to date");
@@ -56243,17 +56399,18 @@ function registerDeveloperCommands(program3) {
56243
56399
  }
56244
56400
  });
56245
56401
  const tests = program3.command("tests").description("a repo's test-policy.json \u2014 the opt-in test contract and its enforcement");
56246
- tests.command("policy").description("enforce this repo's test-policy.json against the diff: a mandatory-zone change must carry a test, an unrequested new test file is refused, a `protected` test file may not be deleted or renamed away, and a `protected` entry naming a missing file is refused. Override any of them with a `Test-Policy-Override: <reason>` commit trailer (#3605)").option("--json", "machine-readable result: { ok, base, policySource: { ref, sha, path }, root, changedCount, mandatoryCount, matchedMandatoryCount, matchedMandatoryGlobs, testCommandsAllowed, testCommandNote, commandClasses, findings[] }").option("--base <ref>", "comparison base (default: TEST_POLICY_BASE, then origin/development, then origin/main)").option("--policy-ref <commit>", "load test-policy.json from the exact fetched origin/development commit and audit its protected/satisfiedBy paths against that commit's tree, not this checkout; valid only with --base origin/main").addOption(new Option("--repo <owner/repo>", "not accepted \u2014 tests policy reads the current checkout").hideHelp()).action(async (o) => {
56402
+ tests.command("policy").description("enforce this repo's test-policy.json against the diff: a mandatory-zone change must carry a test, an unrequested new test file is refused, a `protected` test file may not be deleted or renamed away, and a `protected` entry naming a missing file is refused. Override any of them with a `Test-Policy-Override: <reason>` commit trailer (#3605)").option("--json", "compact machine-readable result: { ok, testCommandsAllowed, commandClasses, findings[] }").option("--verbose", "include the full policy result in --json output").option("--base <ref>", "comparison base (default: TEST_POLICY_BASE, then origin/development, then origin/main)").option("--policy-ref <commit>", "load test-policy.json from the exact fetched origin/development commit and audit its protected/satisfiedBy paths against that commit's tree, not this checkout; valid only with --base origin/main").addOption(new Option("--repo <owner/repo>", "not accepted \u2014 tests policy reads the current checkout").hideHelp()).action(async (o) => {
56247
56403
  try {
56248
56404
  if (o.repo) {
56249
- const rerun = `mmi-cli tests policy${o.base ? ` --base ${o.base}` : ""}${o.policyRef ? ` --policy-ref ${o.policyRef}` : ""}${o.json ? " --json" : ""}`;
56405
+ const rerun = `mmi-cli tests policy${o.base ? ` --base ${o.base}` : ""}${o.policyRef ? ` --policy-ref ${o.policyRef}` : ""}${o.json ? " --json" : ""}${o.verbose ? " --verbose" : ""}`;
56250
56406
  const guard = planTrainApplyRepoGuard(o.repo, await resolveRepo(), rerun, "tests policy");
56251
56407
  if (!guard.ok) return failGraceful(guard.message);
56252
56408
  }
56253
56409
  const root = await repoRoot();
56254
56410
  const result = runTestPolicy(root, { base: o.base, policyRef: o.policyRef });
56255
56411
  if (o.json) {
56256
- consoleIo.log(JSON.stringify(result, null, 2));
56412
+ const { ok, testCommandsAllowed, commandClasses, findings } = result;
56413
+ consoleIo.log(o.verbose ? JSON.stringify(result, null, 2) : JSON.stringify({ ok, testCommandsAllowed, commandClasses, findings }));
56257
56414
  if (!result.ok) process.exitCode = 1;
56258
56415
  return;
56259
56416
  }
@@ -56451,7 +56608,7 @@ function mmiDoctorDeps(opts = {}) {
56451
56608
  );
56452
56609
  const result = applyPluginCachePlan(
56453
56610
  plan,
56454
- (p) => (0, import_node_fs58.rmSync)(p, { recursive: true }),
56611
+ (p) => (0, import_node_fs59.rmSync)(p, { recursive: true }),
56455
56612
  stagingApplyFsGuard(configRoot)
56456
56613
  );
56457
56614
  return {
@@ -56486,7 +56643,7 @@ function mmiDoctorDeps(opts = {}) {
56486
56643
  // has no generated routing index would
56487
56644
  // get a permanent — demanding an artifact it never asked for.
56488
56645
  docsIndexState: (root) => {
56489
- if (!(0, import_node_fs58.existsSync)((0, import_node_path57.join)(root, DOCS_INDEX_PATH))) return void 0;
56646
+ if (!(0, import_node_fs59.existsSync)((0, import_node_path57.join)(root, DOCS_INDEX_PATH))) return void 0;
56490
56647
  const real = createDocsIndexDeps(root);
56491
56648
  let docs;
56492
56649
  const listDocs = () => docs ??= real.listDocs();
@@ -56495,7 +56652,7 @@ function mmiDoctorDeps(opts = {}) {
56495
56652
  },
56496
56653
  // #4168: working-tree heal — write if drifted, then re-check. Commit remains the operator's step.
56497
56654
  healDocsIndex: (root) => {
56498
- if (!(0, import_node_fs58.existsSync)((0, import_node_path57.join)(root, DOCS_INDEX_PATH))) return { drift: false, docCount: 0 };
56655
+ if (!(0, import_node_fs59.existsSync)((0, import_node_path57.join)(root, DOCS_INDEX_PATH))) return { drift: false, docCount: 0 };
56499
56656
  const real = createDocsIndexDeps(root);
56500
56657
  let docs;
56501
56658
  const listDocs = () => docs ??= real.listDocs();
@@ -56855,6 +57012,7 @@ function appActorDeps() {
56855
57012
  };
56856
57013
  }
56857
57014
  setPollTokenProvider(async () => activeAppToken() ?? pollTokenOrUndefined(appActorDeps()));
57015
+ setGhReadTokenProvider(pollToken);
56858
57016
  setStatusWriteTokenProvider(() => mintStatusWriteToken(appActorDeps()));
56859
57017
  var registerPreAction = Reflect.get(program2, ["h", "ook"].join(""));
56860
57018
  registerPreAction.call(program2, "preAction", async (_thisCommand, actionCommand) => {
@@ -56862,7 +57020,7 @@ registerPreAction.call(program2, "preAction", async (_thisCommand, actionCommand
56862
57020
  appActorCommand = commandPath3;
56863
57021
  emitCliCallTelemetry(commandPath3);
56864
57022
  try {
56865
- await activateAppActor(commandPath3, process.env, () => mintInstallationToken(appActorDeps()));
57023
+ await activateAppActor(commandPath3, process.env, () => APP_WRITE_COMMANDS.has(commandPath3) ? mintCommandWriteToken(appActorDeps(), commandPath3) : mintInstallationToken(appActorDeps()));
56866
57024
  } catch (e) {
56867
57025
  if (e instanceof AppActorError) return fail(e.message);
56868
57026
  throw e;
@@ -57220,7 +57378,7 @@ project.command("set [owner/repo]").description("upsert project META (idempotent
57220
57378
  if (dupe) return fail(`org project set: KEY "${dupe}" was passed to both --var and --set; --set is an alias of --var, so pass each KEY once`);
57221
57379
  if (o.secretsFile) {
57222
57380
  try {
57223
- vars.push(`secrets=${(0, import_node_fs58.readFileSync)(o.secretsFile, "utf8")}`);
57381
+ vars.push(`secrets=${(0, import_node_fs59.readFileSync)(o.secretsFile, "utf8")}`);
57224
57382
  } catch (e) {
57225
57383
  return fail(`org project set: cannot read --secrets-file ${o.secretsFile}: ${e.message}`);
57226
57384
  }
@@ -57612,15 +57770,15 @@ function ciAuditDeps2() {
57612
57770
  readSeedFile: (path2) => {
57613
57771
  if (!root) return null;
57614
57772
  const fullPath = (0, import_node_path57.join)(root, path2);
57615
- return (0, import_node_fs58.existsSync)(fullPath) ? (0, import_node_fs58.readFileSync)(fullPath, "utf8") : null;
57773
+ return (0, import_node_fs59.existsSync)(fullPath) ? (0, import_node_fs59.readFileSync)(fullPath, "utf8") : null;
57616
57774
  }
57617
57775
  };
57618
57776
  }
57619
57777
  function hubRoot2() {
57620
57778
  const fromPkg = (0, import_node_path57.join)(__dirname, "..", "..");
57621
57779
  const marker = "skills/bootstrap/seeds/manifest.json";
57622
- if ((0, import_node_fs58.existsSync)((0, import_node_path57.join)(fromPkg, marker))) return fromPkg;
57623
- if ((0, import_node_fs58.existsSync)((0, import_node_path57.join)(process.cwd(), marker))) return process.cwd();
57780
+ if ((0, import_node_fs59.existsSync)((0, import_node_path57.join)(fromPkg, marker))) return fromPkg;
57781
+ if ((0, import_node_fs59.existsSync)((0, import_node_path57.join)(process.cwd(), marker))) return process.cwd();
57624
57782
  return null;
57625
57783
  }
57626
57784
  registerQueryCommands(program2);
@@ -57634,6 +57792,7 @@ registerDiscoveryCommands(program2);
57634
57792
  registerExplainCommand(program2);
57635
57793
  registerPrLifecycleCommands(program2);
57636
57794
  registerApiReadCommands(program2);
57795
+ registerGithubBudgetCommand(program2, appActorDeps);
57637
57796
  registerAppReadBrokerCommands(program2, async (repo) => requireRepo(repo));
57638
57797
  var prBrokerRoot = program2.commands.find((c) => c.name() === "pr");
57639
57798
  if (!prBrokerRoot) throw new Error("read broker: pr root must be registered before pr checks-required");
@@ -57750,10 +57909,10 @@ access.command("audit").description("audit collaborator roles + train-branch pus
57750
57909
  targets = resolution.targets;
57751
57910
  }
57752
57911
  const derivedMatrix = registryProjects ? accessMatrixFromProjects(registryProjects) : {};
57753
- const fileMatrix = (0, import_node_fs58.existsSync)("access-matrix.json") ? loadAccessMatrix((0, import_node_fs58.readFileSync)("access-matrix.json", "utf8")) : {};
57912
+ const fileMatrix = (0, import_node_fs59.existsSync)("access-matrix.json") ? loadAccessMatrix((0, import_node_fs59.readFileSync)("access-matrix.json", "utf8")) : {};
57754
57913
  const matrix = mergeAccessMatrix(fileMatrix, derivedMatrix);
57755
57914
  const dataAccess = registryProjects ? dataAccessContractsFromProjects(registryProjects) : { consumers: {} };
57756
- const sanctioned = (0, import_node_fs58.existsSync)("access-matrix.json") ? loadSanctionedAdmins((0, import_node_fs58.readFileSync)("access-matrix.json", "utf8")) : {};
57915
+ const sanctioned = (0, import_node_fs59.existsSync)("access-matrix.json") ? loadSanctionedAdmins((0, import_node_fs59.readFileSync)("access-matrix.json", "utf8")) : {};
57757
57916
  const report = await auditOrgAccess(targets, deps, matrix, dataAccess, sanctioned);
57758
57917
  console.log(o.json ? JSON.stringify(report, null, 2) : renderAccessReport(report));
57759
57918
  if (!report.ok) process.exitCode = 1;
@@ -57784,7 +57943,7 @@ function directoryBytes(path2) {
57784
57943
  let total = 0;
57785
57944
  let entries;
57786
57945
  try {
57787
- entries = (0, import_node_fs58.readdirSync)(path2, { withFileTypes: true });
57946
+ entries = (0, import_node_fs59.readdirSync)(path2, { withFileTypes: true });
57788
57947
  } catch {
57789
57948
  return 0;
57790
57949
  }
@@ -57793,7 +57952,7 @@ function directoryBytes(path2) {
57793
57952
  if (entry.isDirectory()) total += directoryBytes(child2);
57794
57953
  else {
57795
57954
  try {
57796
- total += (0, import_node_fs58.statSync)(child2).size;
57955
+ total += (0, import_node_fs59.statSync)(child2).size;
57797
57956
  } catch {
57798
57957
  }
57799
57958
  }
@@ -57801,25 +57960,25 @@ function directoryBytes(path2) {
57801
57960
  return total;
57802
57961
  }
57803
57962
  function listDirEntries(dir) {
57804
- return (0, import_node_fs58.readdirSync)(dir, { withFileTypes: true }).map((d) => ({ name: d.name, isDirectory: d.isDirectory() }));
57963
+ return (0, import_node_fs59.readdirSync)(dir, { withFileTypes: true }).map((d) => ({ name: d.name, isDirectory: d.isDirectory() }));
57805
57964
  }
57806
57965
  function readInstalledPluginRefs(configRoot) {
57807
57966
  const p = installedPluginsPathForConfig(configRoot);
57808
- if (!(0, import_node_fs58.existsSync)(p)) return [];
57967
+ if (!(0, import_node_fs59.existsSync)(p)) return [];
57809
57968
  try {
57810
- return installedPluginPaths((0, import_node_fs58.readFileSync)(p, "utf8"));
57969
+ return installedPluginPaths((0, import_node_fs59.readFileSync)(p, "utf8"));
57811
57970
  } catch {
57812
57971
  return null;
57813
57972
  }
57814
57973
  }
57815
57974
  function pluginCacheFsDeps(configRoot, dirBytes) {
57816
57975
  return {
57817
- exists: (p) => (0, import_node_fs58.existsSync)(p),
57818
- listVersionDirs: (root) => (0, import_node_fs58.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name),
57976
+ exists: (p) => (0, import_node_fs59.existsSync)(p),
57977
+ listVersionDirs: (root) => (0, import_node_fs59.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name),
57819
57978
  dirBytes,
57820
- listStagingDirs: (root) => (0, import_node_fs58.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => {
57979
+ listStagingDirs: (root) => (0, import_node_fs59.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => {
57821
57980
  try {
57822
- return { name: d.name, mtimeMs: newestMtimeMs((0, import_node_path57.join)(root, d.name), listDirEntries, (p) => (0, import_node_fs58.statSync)(p).mtimeMs) };
57981
+ return { name: d.name, mtimeMs: newestMtimeMs((0, import_node_path57.join)(root, d.name), listDirEntries, (p) => (0, import_node_fs59.statSync)(p).mtimeMs) };
57823
57982
  } catch {
57824
57983
  return { name: d.name, mtimeMs: Date.now() };
57825
57984
  }
@@ -57834,9 +57993,9 @@ function stagingApplyFsGuard(configRoot) {
57834
57993
  referencedPaths: () => readInstalledPluginRefs(configRoot),
57835
57994
  mtimeMs: (name) => {
57836
57995
  const p = (0, import_node_path57.join)(stagingRoot, name);
57837
- if (!(0, import_node_fs58.existsSync)(p)) return null;
57996
+ if (!(0, import_node_fs59.existsSync)(p)) return null;
57838
57997
  try {
57839
- return newestMtimeMs(p, listDirEntries, (q) => (0, import_node_fs58.statSync)(q).mtimeMs);
57998
+ return newestMtimeMs(p, listDirEntries, (q) => (0, import_node_fs59.statSync)(q).mtimeMs);
57840
57999
  } catch {
57841
58000
  return null;
57842
58001
  }
@@ -57862,7 +58021,7 @@ program2.command("plugin-prune").description(`prune stale cached MMI plugin vers
57862
58021
  { withBytes: true, configRoot, includeStaging: surface !== "codex" }
57863
58022
  );
57864
58023
  const anythingToDelete = plan.prune.length > 0 || plan.staging.length > 0;
57865
- const result = o.apply && anythingToDelete ? applyPluginCachePlan(plan, (p) => (0, import_node_fs58.rmSync)(p, { recursive: true, force: true }), stagingApplyFsGuard(configRoot)) : void 0;
58024
+ const result = o.apply && anythingToDelete ? applyPluginCachePlan(plan, (p) => (0, import_node_fs59.rmSync)(p, { recursive: true, force: true }), stagingApplyFsGuard(configRoot)) : void 0;
57866
58025
  const warnings = plan.prune.length > 0 ? [CONCURRENT_SESSION_WARNING] : [];
57867
58026
  if (o.json) console.log(JSON.stringify({ ...plan, warnings, applied: result ?? null }));
57868
58027
  else console.log(renderPluginCachePlan(plan, result));