@mutmutco/cli 4.5.123 → 4.5.125

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/main.cjs CHANGED
@@ -76,19 +76,19 @@ function hardExit(code) {
76
76
  process.exit(code);
77
77
  }
78
78
  function flushStream(stream) {
79
- return new Promise((resolve7) => {
79
+ return new Promise((resolve8) => {
80
80
  try {
81
- stream.write("", () => resolve7());
81
+ stream.write("", () => resolve8());
82
82
  } catch {
83
- resolve7();
83
+ resolve8();
84
84
  }
85
85
  });
86
86
  }
87
87
  async function flushStdio(timeoutMs = STDIO_FLUSH_TIMEOUT_MS) {
88
88
  await Promise.race([
89
89
  Promise.all([flushStream(process.stdout), flushStream(process.stderr)]),
90
- new Promise((resolve7) => {
91
- setTimeout(resolve7, timeoutMs).unref?.();
90
+ new Promise((resolve8) => {
91
+ setTimeout(resolve8, timeoutMs).unref?.();
92
92
  })
93
93
  ]);
94
94
  }
@@ -96,7 +96,7 @@ async function cleanExit(code) {
96
96
  process.exitCode = code;
97
97
  await closeHttpPool();
98
98
  await flushStdio();
99
- await new Promise((resolve7) => setImmediate(resolve7));
99
+ await new Promise((resolve8) => setImmediate(resolve8));
100
100
  return void 0;
101
101
  }
102
102
  async function finishCliRun(watchdogMs = CLI_EXIT_WATCHDOG_MS) {
@@ -644,7 +644,7 @@ function rateLimitedReceipt(opts) {
644
644
  };
645
645
  }
646
646
  async function runWithRateLimitBackoff(operation, opts) {
647
- const sleep2 = opts.sleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms)));
647
+ const sleep2 = opts.sleep ?? ((ms) => new Promise((resolve8) => setTimeout(resolve8, ms)));
648
648
  const now = opts.now ?? Date.now;
649
649
  const log = opts.log ?? ((message2) => console.warn(message2));
650
650
  const capMs = opts.capMs ?? RATE_LIMIT_WAIT_CAP_MS;
@@ -734,7 +734,7 @@ async function fetchWithRetry(fetchImpl, url, init, opts = {}) {
734
734
  const attempts = opts.attempts ?? 3;
735
735
  const baseDelayMs = opts.baseDelayMs ?? 250;
736
736
  const retryOn = opts.retryOn ?? ((res) => res.status >= 500);
737
- const sleep2 = opts.sleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms)));
737
+ const sleep2 = opts.sleep ?? ((ms) => new Promise((resolve8) => setTimeout(resolve8, ms)));
738
738
  let lastErr;
739
739
  for (let i = 0; i < attempts; i++) {
740
740
  const isLast = i === attempts - 1;
@@ -1057,8 +1057,8 @@ async function readStdin(opts = {}) {
1057
1057
  })().catch(() => {
1058
1058
  });
1059
1059
  let timer;
1060
- const timeout = new Promise((resolve7) => {
1061
- timer = setTimeout(resolve7, timeoutMs);
1060
+ const timeout = new Promise((resolve8) => {
1061
+ timer = setTimeout(resolve8, timeoutMs);
1062
1062
  });
1063
1063
  try {
1064
1064
  await Promise.race([drain, timeout]);
@@ -1125,12 +1125,12 @@ function killProcessTree(pid) {
1125
1125
  function execFileHard(file, args, options) {
1126
1126
  const { timeout, step, ...rest } = options;
1127
1127
  const started = Date.now();
1128
- return new Promise((resolve7, reject) => {
1128
+ return new Promise((resolve8, reject) => {
1129
1129
  const child2 = (0, import_node_child_process2.execFile)(file, args, { encoding: "utf8", windowsHide: true, ...rest, timeout: 0 }, (error, stdout, stderr) => {
1130
1130
  clearTimeout(timer);
1131
1131
  if (expired) return;
1132
1132
  if (error) reject(error);
1133
- else resolve7({ stdout: String(stdout), stderr: String(stderr) });
1133
+ else resolve8({ stdout: String(stdout), stderr: String(stderr) });
1134
1134
  });
1135
1135
  let expired = false;
1136
1136
  const timer = setTimeout(() => {
@@ -5119,8 +5119,8 @@ function survivingFlagArgs(argv, rejectedFlag, ownFlags) {
5119
5119
  return out;
5120
5120
  }
5121
5121
  function formatPositionalTarget(commandPath3, argName, opts = {}) {
5122
- const concrete = opts.flag && opts.argv ? targetFlagValueFromArgv(opts.flag, opts.argv) : void 0;
5123
- const target = concrete ?? `<${argName}>`;
5122
+ const concrete2 = opts.flag && opts.argv ? targetFlagValueFromArgv(opts.flag, opts.argv) : void 0;
5123
+ const target = concrete2 ?? `<${argName}>`;
5124
5124
  const kept = opts.flag && opts.argv && opts.ownFlags ? survivingFlagArgs(opts.argv, opts.flag, opts.ownFlags) : [];
5125
5125
  return [`mmi-cli ${commandPath3}`, target, ...kept].join(" ");
5126
5126
  }
@@ -5656,7 +5656,7 @@ function resolveVerbAliasShim(argv) {
5656
5656
 
5657
5657
  // src/command-composition.ts
5658
5658
  var import_node_os25 = require("node:os");
5659
- var import_node_path54 = require("node:path");
5659
+ var import_node_path56 = require("node:path");
5660
5660
 
5661
5661
  // src/board-read.ts
5662
5662
  var import_node_fs14 = require("node:fs");
@@ -5789,6 +5789,8 @@ var APP_ELIGIBLE_COMMANDS = /* @__PURE__ */ new Set([
5789
5789
  "read run view",
5790
5790
  "read run list",
5791
5791
  "read run watch",
5792
+ "read run log",
5793
+ // #8136: bounded jobs/logs REST read, same polling credential.
5792
5794
  "read pr view",
5793
5795
  "read pr checks",
5794
5796
  "read issue view",
@@ -6733,7 +6735,7 @@ async function readRestPrSnapshotWithRetry(prNumber, repo, gh2 = defaultGhApi, o
6733
6735
  const retries = options?.retries ?? PR_SNAPSHOT_READ_RETRIES;
6734
6736
  const untilMs = options?.retryTransientUntilMs;
6735
6737
  const delayMs = options?.delayMs ?? (untilMs !== void 0 ? PR_CHECKS_POLL_MS : PR_SNAPSHOT_READ_DELAY_MS);
6736
- const sleep2 = options?.sleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms)));
6738
+ const sleep2 = options?.sleep ?? ((ms) => new Promise((resolve8) => setTimeout(resolve8, ms)));
6737
6739
  const now = options?.now ?? (() => Date.now());
6738
6740
  let lastError = "no attempt completed";
6739
6741
  let attempt = 0;
@@ -10108,18 +10110,18 @@ function isGhHttpNotFound(err) {
10108
10110
  function isForkStyleHead(head) {
10109
10111
  return head.includes(":");
10110
10112
  }
10111
- async function defaultReadRemoteHead(exec2, repo, head) {
10113
+ async function defaultReadRemoteHead(exec3, repo, head) {
10112
10114
  try {
10113
- await exec2("gh", ["api", `repos/${repo}/git/ref/heads/${encodeURIComponent(head)}`], { timeout: 15e3 });
10115
+ await exec3("gh", ["api", `repos/${repo}/git/ref/heads/${encodeURIComponent(head)}`], { timeout: 15e3 });
10114
10116
  return "present";
10115
10117
  } catch (e) {
10116
10118
  if (isGhHttpNotFound(e)) return "absent";
10117
10119
  return "unknown";
10118
10120
  }
10119
10121
  }
10120
- async function defaultCompareRefs(exec2, repo, base, head) {
10122
+ async function defaultCompareRefs(exec3, repo, base, head) {
10121
10123
  try {
10122
- const { stdout } = await exec2(
10124
+ const { stdout } = await exec3(
10123
10125
  "gh",
10124
10126
  ["api", `repos/${repo}/compare/${encodeURIComponent(base)}...${encodeURIComponent(head)}`],
10125
10127
  { timeout: 15e3 }
@@ -10130,11 +10132,11 @@ async function defaultCompareRefs(exec2, repo, base, head) {
10130
10132
  return "unknown";
10131
10133
  }
10132
10134
  }
10133
- async function publishAbsentPrHeadIfOwned(repo, head, exec2) {
10135
+ async function publishAbsentPrHeadIfOwned(repo, head, exec3) {
10134
10136
  if (isForkStyleHead(head)) return false;
10135
10137
  let originRepo;
10136
10138
  try {
10137
- const { stdout } = await exec2("git", ["remote", "get-url", "--push", "origin"], { timeout: GIT_TIMEOUT_MS });
10139
+ const { stdout } = await exec3("git", ["remote", "get-url", "--push", "origin"], { timeout: GIT_TIMEOUT_MS });
10138
10140
  originRepo = repoFromRemoteUrl(stdout.trim());
10139
10141
  } catch {
10140
10142
  return false;
@@ -10142,20 +10144,20 @@ async function publishAbsentPrHeadIfOwned(repo, head, exec2) {
10142
10144
  if (!originRepo || originRepo.toLowerCase() !== repo.toLowerCase()) return false;
10143
10145
  let currentBranch2;
10144
10146
  try {
10145
- currentBranch2 = (await exec2("git", ["symbolic-ref", "--quiet", "--short", "HEAD"], { timeout: GIT_TIMEOUT_MS })).stdout.trim();
10147
+ currentBranch2 = (await exec3("git", ["symbolic-ref", "--quiet", "--short", "HEAD"], { timeout: GIT_TIMEOUT_MS })).stdout.trim();
10146
10148
  } catch {
10147
10149
  return false;
10148
10150
  }
10149
10151
  if (!currentBranch2 || currentBranch2 !== head) return false;
10150
10152
  let commit;
10151
10153
  try {
10152
- commit = (await exec2("git", ["rev-parse", "--verify", "HEAD^{commit}"], { timeout: GIT_TIMEOUT_MS })).stdout.trim();
10154
+ commit = (await exec3("git", ["rev-parse", "--verify", "HEAD^{commit}"], { timeout: GIT_TIMEOUT_MS })).stdout.trim();
10153
10155
  } catch {
10154
10156
  return false;
10155
10157
  }
10156
10158
  if (!commit) return false;
10157
10159
  try {
10158
- await exec2("git", ["push", "origin", `${commit}:refs/heads/${head}`], { timeout: GH_MUTATION_TIMEOUT_MS });
10160
+ await exec3("git", ["push", "origin", `${commit}:refs/heads/${head}`], { timeout: GH_MUTATION_TIMEOUT_MS });
10159
10161
  return true;
10160
10162
  } catch {
10161
10163
  return false;
@@ -10285,22 +10287,22 @@ function upstreamFaultMessage(verb, stderr) {
10285
10287
  const advice = mayRetryCreate(verb) ? "Retrying is the right action" : "The write may have completed server-side before the error \u2014 VERIFY before retrying, or a retry will duplicate it";
10286
10288
  return `gh ${verb} create failed: GitHub's API is failing (server-side 5xx) \u2014 this is NOT a problem with your diff or arguments. GitHub request ID: ${requestId ?? "unavailable"}. ${advice}; note githubstatus.com may still read green while this is happening.`;
10287
10289
  }
10288
- async function resolveRepoForCreate(args, exec2) {
10290
+ async function resolveRepoForCreate(args, exec3) {
10289
10291
  const fromFlag = flagValue(args, "--repo");
10290
10292
  if (fromFlag) return fromFlag;
10291
10293
  try {
10292
- const { stdout } = await exec2("git", ["remote", "get-url", "origin"], { timeout: 1e4 });
10294
+ const { stdout } = await exec3("git", ["remote", "get-url", "origin"], { timeout: 1e4 });
10293
10295
  const fromOrigin = repoFromRemoteUrl(stdout.trim());
10294
10296
  if (fromOrigin) return fromOrigin;
10295
10297
  } catch {
10296
10298
  }
10297
10299
  return repoFromRemoteUrl(originUrlFromGitConfig() ?? "") || void 0;
10298
10300
  }
10299
- async function resolveHeadForCreate(args, exec2) {
10301
+ async function resolveHeadForCreate(args, exec3) {
10300
10302
  const fromFlag = flagValue(args, "--head");
10301
10303
  if (fromFlag) return fromFlag;
10302
10304
  try {
10303
- const { stdout } = await exec2("git", ["rev-parse", "--abbrev-ref", "HEAD"], { timeout: 1e4 });
10305
+ const { stdout } = await exec3("git", ["rev-parse", "--abbrev-ref", "HEAD"], { timeout: 1e4 });
10304
10306
  const head = stdout.trim();
10305
10307
  return head && head !== "HEAD" ? head : void 0;
10306
10308
  } catch {
@@ -10312,13 +10314,13 @@ async function resolveBodyForCreate(args, read) {
10312
10314
  if (bodyFile !== void 0) return read(bodyFile, "utf8");
10313
10315
  return flagValue(args, "--body") ?? "";
10314
10316
  }
10315
- async function defaultFindOpenPr(exec2, input) {
10317
+ async function defaultFindOpenPr(exec3, input) {
10316
10318
  const owner = input.repo.split("/")[0];
10317
10319
  if (!owner) return void 0;
10318
10320
  const qs = new URLSearchParams({ state: "open", head: `${owner}:${input.head}` });
10319
10321
  if (input.base) qs.set("base", input.base);
10320
10322
  try {
10321
- const { stdout } = await exec2("gh", ["api", `repos/${input.repo}/pulls?${qs.toString()}`], { timeout: GH_MUTATION_TIMEOUT_MS });
10323
+ const { stdout } = await exec3("gh", ["api", `repos/${input.repo}/pulls?${qs.toString()}`], { timeout: GH_MUTATION_TIMEOUT_MS });
10322
10324
  const rows = JSON.parse(stdout);
10323
10325
  const first = Array.isArray(rows) ? rows[0] : void 0;
10324
10326
  if (typeof first?.number === "number" && typeof first.html_url === "string") {
@@ -10328,7 +10330,7 @@ async function defaultFindOpenPr(exec2, input) {
10328
10330
  }
10329
10331
  return void 0;
10330
10332
  }
10331
- async function defaultRestCreatePr(exec2, input, deps = {}) {
10333
+ async function defaultRestCreatePr(exec3, input, deps = {}) {
10332
10334
  const write = deps.write ?? import_promises.writeFile;
10333
10335
  const remove2 = deps.remove ?? import_promises.unlink;
10334
10336
  const ensureDir = deps.ensureDir ?? import_promises.mkdir;
@@ -10353,7 +10355,7 @@ async function defaultRestCreatePr(exec2, input, deps = {}) {
10353
10355
  file
10354
10356
  ];
10355
10357
  try {
10356
- const { stdout } = await exec2("gh", args, { timeout: GH_MUTATION_TIMEOUT_MS });
10358
+ const { stdout } = await exec3("gh", args, { timeout: GH_MUTATION_TIMEOUT_MS });
10357
10359
  const parsed = JSON.parse(stdout);
10358
10360
  if (typeof parsed.number === "number" && typeof parsed.html_url === "string") {
10359
10361
  return { number: parsed.number, url: parsed.html_url };
@@ -10365,7 +10367,7 @@ async function defaultRestCreatePr(exec2, input, deps = {}) {
10365
10367
  const fromText = parseExistingPr(text);
10366
10368
  if (fromText) return { ...fromText, existing: true };
10367
10369
  if (/already exists/i.test(text)) {
10368
- const found = await defaultFindOpenPr(exec2, { repo: input.repo, head: input.head, base: input.base });
10370
+ const found = await defaultFindOpenPr(exec3, { repo: input.repo, head: input.head, base: input.base });
10369
10371
  if (found) return found;
10370
10372
  }
10371
10373
  throw e;
@@ -10376,7 +10378,7 @@ async function defaultRestCreatePr(exec2, input, deps = {}) {
10376
10378
  }
10377
10379
  }
10378
10380
  }
10379
- async function defaultRestCreateIssue(exec2, input) {
10381
+ async function defaultRestCreateIssue(exec3, input) {
10380
10382
  const args = [
10381
10383
  "api",
10382
10384
  "--method",
@@ -10391,7 +10393,7 @@ async function defaultRestCreateIssue(exec2, input) {
10391
10393
  args.push("-f", `labels[]=${label}`);
10392
10394
  }
10393
10395
  try {
10394
- const { stdout } = await exec2("gh", args, { timeout: GH_MUTATION_TIMEOUT_MS });
10396
+ const { stdout } = await exec3("gh", args, { timeout: GH_MUTATION_TIMEOUT_MS });
10395
10397
  const parsed = JSON.parse(stdout);
10396
10398
  if (typeof parsed.number === "number" && typeof parsed.html_url === "string") {
10397
10399
  return { number: parsed.number, url: parsed.html_url };
@@ -10410,9 +10412,9 @@ ${err.stdout ?? ""}`;
10410
10412
  throw e;
10411
10413
  }
10412
10414
  }
10413
- async function defaultReadRateLimit(exec2) {
10415
+ async function defaultReadRateLimit(exec3) {
10414
10416
  try {
10415
- const { stdout } = await exec2("gh", ["api", "rate_limit"], { timeout: 15e3 });
10417
+ const { stdout } = await exec3("gh", ["api", "rate_limit"], { timeout: 15e3 });
10416
10418
  return parseRateLimitPools(stdout);
10417
10419
  } catch {
10418
10420
  return {};
@@ -10585,17 +10587,17 @@ async function createPrViaRestFallback(args, swappedArgs, deps, knownPools) {
10585
10587
  }
10586
10588
  }
10587
10589
  async function ghCreate(args, deps = {}) {
10588
- const exec2 = deps.exec ?? execFileP;
10589
- const sleep2 = deps.sleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms)));
10590
+ const exec3 = deps.exec ?? execFileP;
10591
+ const sleep2 = deps.sleep ?? ((ms) => new Promise((resolve8) => setTimeout(resolve8, ms)));
10590
10592
  const now = deps.now ?? Date.now;
10591
10593
  const read = deps.readFile ?? import_promises.readFile;
10592
- const restCreatePr = deps.restCreatePr ?? ((input) => defaultRestCreatePr(exec2, input));
10593
- const restCreateIssue = deps.restCreateIssue ?? ((input) => defaultRestCreateIssue(exec2, input));
10594
- const findOpenPr = deps.findOpenPr ?? ((input) => defaultFindOpenPr(exec2, input));
10595
- const readRateLimit = deps.readRateLimit ?? (() => defaultReadRateLimit(exec2));
10594
+ const restCreatePr = deps.restCreatePr ?? ((input) => defaultRestCreatePr(exec3, input));
10595
+ const restCreateIssue = deps.restCreateIssue ?? ((input) => defaultRestCreateIssue(exec3, input));
10596
+ const findOpenPr = deps.findOpenPr ?? ((input) => defaultFindOpenPr(exec3, input));
10597
+ const readRateLimit = deps.readRateLimit ?? (() => defaultReadRateLimit(exec3));
10596
10598
  if (args[0] === "pr") {
10597
10599
  const refusal = await preflightPrCreateRemoteHead(args, {
10598
- exec: exec2,
10600
+ exec: exec3,
10599
10601
  readRemoteHead: deps.readRemoteHead,
10600
10602
  compareRefs: deps.compareRefs
10601
10603
  });
@@ -10603,7 +10605,7 @@ async function ghCreate(args, deps = {}) {
10603
10605
  }
10604
10606
  const swapped = await bodyArgsViaFile(args);
10605
10607
  const restDeps = {
10606
- exec: exec2,
10608
+ exec: exec3,
10607
10609
  sleep: sleep2,
10608
10610
  now,
10609
10611
  readFile: read,
@@ -10646,7 +10648,7 @@ async function ghCreate(args, deps = {}) {
10646
10648
  }
10647
10649
  for (let attempt = 1; attempt <= GH_CREATE_UPSTREAM_RETRIES; attempt++) {
10648
10650
  try {
10649
- const { stdout } = await exec2("gh", swapped.args, { timeout: GH_MUTATION_TIMEOUT_MS });
10651
+ const { stdout } = await exec3("gh", swapped.args, { timeout: GH_MUTATION_TIMEOUT_MS });
10650
10652
  return parseCreatedUrl(stdout);
10651
10653
  } catch (e) {
10652
10654
  const err = e;
@@ -10664,7 +10666,7 @@ async function ghCreate(args, deps = {}) {
10664
10666
  if (args[0] === "issue" && isGhRateLimitError(errText)) {
10665
10667
  try {
10666
10668
  const result = await createIssueViaRestFallback(args, swapped.args, {
10667
- exec: exec2,
10669
+ exec: exec3,
10668
10670
  sleep: sleep2,
10669
10671
  now,
10670
10672
  readFile: read,
@@ -11414,8 +11416,8 @@ var PRE_SPAWN_DRAIN_TIMEOUT_MS = 2e3;
11414
11416
  async function drainHttpPoolBeforeSpawn() {
11415
11417
  const drained = await Promise.race([
11416
11418
  closeHttpPool().then(() => true),
11417
- new Promise((resolve7) => {
11418
- setTimeout(() => resolve7(false), PRE_SPAWN_DRAIN_TIMEOUT_MS).unref?.();
11419
+ new Promise((resolve8) => {
11420
+ setTimeout(() => resolve8(false), PRE_SPAWN_DRAIN_TIMEOUT_MS).unref?.();
11419
11421
  })
11420
11422
  ]);
11421
11423
  if (!drained) destroyHttpPool();
@@ -15002,7 +15004,7 @@ async function setBoardItemPriority(client, cfg, itemId, priority) {
15002
15004
  await updateItemSingleSelect(client, cfg.projectId, itemId, cfg.priorityFieldId, optionId);
15003
15005
  return cliPriorityToFieldName(priority);
15004
15006
  }
15005
- var defaultRetrySleep = (ms) => new Promise((resolve7) => setTimeout(resolve7, ms));
15007
+ var defaultRetrySleep = (ms) => new Promise((resolve8) => setTimeout(resolve8, ms));
15006
15008
  async function resolveProjectItemIdWithRetry(client, cfg, selector, opts = {}) {
15007
15009
  const attempts = Math.max(1, opts.attempts ?? 5);
15008
15010
  const delayMs = opts.delayMs ?? 300;
@@ -15785,6 +15787,135 @@ function checkCommands(docs, commandPaths) {
15785
15787
  }
15786
15788
  return { ok: findings.length === 0, findings, warnings: [] };
15787
15789
  }
15790
+ function isRunbook(doc, body) {
15791
+ return doc === "docs/Guides/operator.md" || body.split(/\r?\n/).slice(0, 20).some((line) => line.includes("<!-- runbook -->"));
15792
+ }
15793
+ function shellClaims(body) {
15794
+ const claims = [];
15795
+ let fence = "";
15796
+ let enabled = false;
15797
+ body.split(/\r?\n/).forEach((text, index) => {
15798
+ const marker = /^\s*(`{3,}|~{3,})(.*)$/.exec(text);
15799
+ if (marker) {
15800
+ if (!fence) {
15801
+ fence = marker[1];
15802
+ enabled = /^(bash|sh|shell|console)?$/.test(marker[2].trim().toLowerCase());
15803
+ } else if (marker[1][0] === fence[0] && marker[1].length >= fence.length && !marker[2].trim()) {
15804
+ fence = "";
15805
+ enabled = false;
15806
+ }
15807
+ return;
15808
+ }
15809
+ if (!enabled || /^\s*#/.test(text)) return;
15810
+ const parts = text.replace(/^\s*\$ /, "").match(/(?:"[^"\n]*"|'[^'\n]*'|<[^>\n]*>|[^\s;&|])+|&&|\|\||[;|]/g) ?? [];
15811
+ let tokens2 = [];
15812
+ const emit = () => {
15813
+ while (/^[A-Za-z_][A-Za-z0-9_]*=/.test(tokens2[0] ?? "")) tokens2.shift();
15814
+ if (tokens2.length) claims.push({ tokens: tokens2, line: index + 1 });
15815
+ tokens2 = [];
15816
+ };
15817
+ for (const part of parts) {
15818
+ if (part.startsWith("#")) break;
15819
+ if (["&&", "||", ";", "|"].includes(part)) emit();
15820
+ else tokens2.push(part.replace(/^(["'])(.*)\1$/, "$2"));
15821
+ }
15822
+ emit();
15823
+ });
15824
+ return claims;
15825
+ }
15826
+ function checkRunbookClaims(root, docs, deps) {
15827
+ const findings = [];
15828
+ const placeholder = (token) => token.includes("<");
15829
+ const paths = deps.commandPaths ?? /* @__PURE__ */ new Set();
15830
+ for (const [doc, body] of Object.entries(docs)) {
15831
+ for (const { tokens: tokens2, line } of shellClaims(body)) {
15832
+ const [cmd, ...args] = tokens2;
15833
+ const report = (kind, detail) => {
15834
+ findings.push({ kind, doc, line, detail });
15835
+ };
15836
+ if (cmd === "mmi-cli" && deps.commandPaths) {
15837
+ let resolved = "";
15838
+ let unknown = false;
15839
+ for (const token of args) {
15840
+ if (token.startsWith("-") || placeholder(token)) break;
15841
+ const next = resolved ? `${resolved} ${token}` : token;
15842
+ if ([...paths].some((path2) => path2 === next || path2.startsWith(`${next} `))) resolved = next;
15843
+ else if (paths.has(resolved)) break;
15844
+ else {
15845
+ report("unknown-command", `mmi-cli ${next}`);
15846
+ unknown = true;
15847
+ break;
15848
+ }
15849
+ }
15850
+ for (const token of unknown ? [] : args) {
15851
+ if (token === "--") break;
15852
+ const flag = token.split("=")[0];
15853
+ if (/^--[\w-]+$/.test(flag) && flag !== "--help" && !placeholder(flag) && !deps.commandOptions?.get(resolved)?.has(flag)) {
15854
+ report("unknown-flag", `mmi-cli ${resolved}: ${flag}`);
15855
+ }
15856
+ }
15857
+ } else if (cmd === "npm") {
15858
+ const run = args.indexOf("run");
15859
+ if (run < 0) continue;
15860
+ const prefix = args.indexOf("--prefix");
15861
+ const dir = prefix >= 0 ? args[prefix + 1] : ".";
15862
+ const script = args.slice(run + 1).find((token, i, tail) => !token.startsWith("-") && tail[i - 1] !== "--prefix");
15863
+ if (!dir || !script || placeholder(dir) || placeholder(script)) continue;
15864
+ const manifest = deps.readFile((0, import_node_path13.join)(root, dir, "package.json"));
15865
+ const scripts = manifest ? JSON.parse(manifest).scripts : void 0;
15866
+ if (!scripts || !Object.hasOwn(scripts, script)) report("missing-script", `npm run ${script} (${dir}/package.json)`);
15867
+ } else if ((cmd === "python" || cmd === "python3") && args[0] === "-m") {
15868
+ const module2 = args[1];
15869
+ if (!module2 || placeholder(module2)) continue;
15870
+ const rel = module2.replaceAll(".", "/");
15871
+ const first = rel.split("/")[0];
15872
+ const tracked = deps.trackedFirstSegments([first, `${first}.py`, `src/${first}`, `src/${first}.py`]);
15873
+ const roots = ["", "src/"].filter((prefix) => {
15874
+ if (!prefix) return tracked ? tracked.has(first) || tracked.has(`${first}.py`) : deps.exists((0, import_node_path13.join)(root, first)) || deps.exists((0, import_node_path13.join)(root, `${first}.py`));
15875
+ return tracked ? tracked.has(`src/${first}`) || tracked.has(`src/${first}.py`) : deps.exists((0, import_node_path13.join)(root, "src", first)) || deps.exists((0, import_node_path13.join)(root, "src", `${first}.py`));
15876
+ });
15877
+ if (roots.length && !roots.some((prefix) => [".py", "/__init__.py", "/__main__.py"].some((suffix) => deps.exists((0, import_node_path13.join)(root, `${prefix}${rel}${suffix}`))))) {
15878
+ report("missing-module", module2);
15879
+ }
15880
+ } else if (["node", "bash", "sh"].includes(cmd)) {
15881
+ const rel = args[0];
15882
+ if (!rel || rel.startsWith("-") || placeholder(rel) || /^(\/|[A-Za-z]:|\.\.\/)/.test(rel)) continue;
15883
+ const first = refFirstSegment(rel);
15884
+ const tracked = deps.trackedFirstSegments([first]);
15885
+ if ((tracked ? tracked.has(first) : deps.exists((0, import_node_path13.join)(root, first))) && !deps.exists((0, import_node_path13.join)(root, rel)) && !deps.isIgnored([rel]).has(rel)) report("missing-path", rel);
15886
+ }
15887
+ }
15888
+ }
15889
+ return findings;
15890
+ }
15891
+ function checkRunbookCoverage(docs, base, git3) {
15892
+ const changed = git3(["diff", "--name-only", `${base}...HEAD`]).split(/\r?\n/).filter(Boolean);
15893
+ const findings = [];
15894
+ const matches = (glob, path2) => {
15895
+ const pattern = glob.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*\//g, "\0").replace(/\*\*/g, "").replace(/\*/g, "[^/]*").replace(/\?/g, "[^/]").replaceAll("\0", "(?:.*/)?").replaceAll("", ".*");
15896
+ return new RegExp(`^${pattern}$`).test(path2);
15897
+ };
15898
+ for (const [doc, body] of Object.entries(docs)) {
15899
+ const lines2 = stripFences(body);
15900
+ const headings = lines2.flatMap((text, i) => {
15901
+ const match = /^(#{1,6})\s+(.+)$/.exec(text);
15902
+ return match ? [{ level: match[1].length, title: match[2], start: i + 1 }] : [];
15903
+ });
15904
+ const diff = git3(["diff", "-U0", `${base}...HEAD`, "--", doc]);
15905
+ const ranges = [...diff.matchAll(/^@@ .*?\+(\d+)(?:,(\d+))? @@/gm)].map((m) => ({ start: Number(m[1]), count: m[2] === void 0 ? 1 : Number(m[2]) }));
15906
+ for (let i = 0; i < headings.length; i++) {
15907
+ const heading = headings[i];
15908
+ const end = headings.slice(i + 1).find((h) => h.level <= heading.level)?.start ?? lines2.length + 1;
15909
+ const markerEnd = headings[i + 1]?.start ?? end;
15910
+ const globs = lines2.slice(heading.start, markerEnd - 1).flatMap((text) => /<!--\s*runbook-covers:\s*(.*?)\s*-->/.exec(text)?.[1].split(",").map((s) => s.trim()) ?? []);
15911
+ const affected = changed.filter((path2) => globs.some((glob) => matches(glob, path2)));
15912
+ if (affected.length && !ranges.some((r) => r.count > 0 && r.start < end && r.start + r.count > heading.start)) {
15913
+ findings.push({ kind: "runbook-section-stale", doc, line: heading.start, detail: `${heading.title}: changed ${affected.join(", ")}; update this section or declare Runbook-Unaffected: <reason>` });
15914
+ }
15915
+ }
15916
+ }
15917
+ return findings;
15918
+ }
15788
15919
  function readFileOrNull(path2) {
15789
15920
  return (0, import_node_fs15.existsSync)(path2) ? (0, import_node_fs15.readFileSync)(path2, "utf8") : null;
15790
15921
  }
@@ -15806,11 +15937,11 @@ function defaultListDocs(root) {
15806
15937
  return [...ROOT_DOCS.filter((rel) => (0, import_node_fs15.existsSync)((0, import_node_path13.join)(root, rel))), ...docs];
15807
15938
  }
15808
15939
  var CHECK_IGNORE_MAX_BUFFER = 32 * 1024 * 1024;
15809
- function defaultIsIgnored(root, relPaths, exec2 = import_node_child_process6.execFileSync) {
15940
+ function defaultIsIgnored(root, relPaths, exec3 = import_node_child_process6.execFileSync) {
15810
15941
  const inRepo = relPaths.filter((p) => !p.startsWith(".."));
15811
15942
  if (inRepo.length === 0) return /* @__PURE__ */ new Set();
15812
15943
  try {
15813
- const out = exec2("git", ["check-ignore", "--stdin"], {
15944
+ const out = exec3("git", ["check-ignore", "--stdin"], {
15814
15945
  cwd: root,
15815
15946
  input: inRepo.join("\n"),
15816
15947
  encoding: "utf8",
@@ -15829,17 +15960,19 @@ function defaultIsIgnored(root, relPaths, exec2 = import_node_child_process6.exe
15829
15960
  throw error;
15830
15961
  }
15831
15962
  }
15832
- function defaultTrackedFirstSegments(root, firstSegments, exec2 = import_node_child_process6.execFileSync) {
15963
+ function defaultTrackedFirstSegments(root, firstSegments, exec3 = import_node_child_process6.execFileSync) {
15833
15964
  if (firstSegments.length === 0) return /* @__PURE__ */ new Set();
15834
15965
  try {
15835
- const out = exec2("git", ["ls-files", "-z", "--", ...firstSegments.map((s) => `:(literal)${s}`)], {
15966
+ const out = exec3("git", ["ls-files", "-z", "--", ...firstSegments.map((s) => `:(literal)${s}`)], {
15836
15967
  cwd: root,
15837
15968
  encoding: "utf8",
15838
15969
  maxBuffer: CHECK_IGNORE_MAX_BUFFER
15839
15970
  });
15840
15971
  const tracked = /* @__PURE__ */ new Set();
15841
15972
  for (const path2 of out.split("\0")) {
15842
- if (path2) tracked.add(path2.split("/")[0]);
15973
+ if (path2) for (const segment of firstSegments) {
15974
+ if (path2 === segment || path2.startsWith(`${segment}/`)) tracked.add(segment);
15975
+ }
15843
15976
  }
15844
15977
  return tracked;
15845
15978
  } catch (error) {
@@ -15863,7 +15996,7 @@ function runDocRefs(root, deps = {}) {
15863
15996
  const walked = listDocs(root);
15864
15997
  const ignoredDocs = walked.length ? isIgnored(walked) : /* @__PURE__ */ new Set();
15865
15998
  const docs = Object.fromEntries(
15866
- walked.filter((rel) => !ignoredDocs.has(rel)).map((rel) => [rel, readFile10((0, import_node_path13.join)(root, rel))]).filter(([, body]) => body != null)
15999
+ walked.filter((rel) => !ignoredDocs.has(rel)).map((rel) => [rel, readFile10((0, import_node_path13.join)(root, rel))]).filter(([rel, body]) => body != null && (!deps.runbooksOnly || isRunbook(rel, body)))
15867
16000
  );
15868
16001
  const refResult = checkRefs(root, { exists, isIgnored, trackedFirstSegments }, docs);
15869
16002
  const findings = [
@@ -15880,10 +16013,22 @@ function runDocRefs(root, deps = {}) {
15880
16013
  } else {
15881
16014
  findings.push(...checkCommands(docs, commandPaths).findings);
15882
16015
  }
16016
+ const runbooks = Object.fromEntries(Object.entries(docs).filter(([doc, body]) => isRunbook(doc, body)));
16017
+ findings.push(...checkRunbookClaims(root, runbooks, { readFile: readFile10, exists, isIgnored, trackedFirstSegments, commandPaths, commandOptions: deps.commandOptions }));
16018
+ const warnings = [...refResult.warnings];
16019
+ if (deps.runbooksOnly && !Object.keys(runbooks).length) {
16020
+ warnings.push({ kind: "runbook-missing", doc: "docs/Guides/operator.md", line: 0, detail: "no operator runbook or <!-- runbook --> document exists" });
16021
+ }
16022
+ if (deps.base) {
16023
+ const git3 = deps.git ?? ((args) => (0, import_node_child_process6.execFileSync)("git", args, { cwd: root, encoding: "utf8", maxBuffer: CHECK_IGNORE_MAX_BUFFER, windowsHide: true }));
16024
+ const stale = checkRunbookCoverage(runbooks, deps.base, git3);
16025
+ const override = /^Runbook-Unaffected:[ \t]*\S.*$/m.test(git3(["log", "--format=%B", `${deps.base}..HEAD`]));
16026
+ (override ? warnings : findings).push(...stale);
16027
+ }
15883
16028
  return {
15884
16029
  ok: findings.length === 0,
15885
16030
  findings,
15886
- warnings: refResult.warnings,
16031
+ warnings,
15887
16032
  docCount: Object.keys(docs).length
15888
16033
  };
15889
16034
  }
@@ -16001,6 +16146,7 @@ function createDocsIndexDeps(repoRoot2) {
16001
16146
  // src/gate-budget.ts
16002
16147
  var BLESSED_RUN_WITH_BUDGET_SHA = "5ce541add569e54e7ca96de67a768577d3d604e4";
16003
16148
  var BLESSED_RUNNER_GATE_SHA = "a19e9392e5ad9b0675f02e4304d68dd933fad60f";
16149
+ var BLESSED_RUNBOOK_GUARD_SHA = "e661e0aedc0e58b73c738bf6cdfeac65e5914584";
16004
16150
  var REMOTE_USE = /^mutmutco\/MMI-Hub\/\.github\/actions\/run-with-budget@(\S+)$/;
16005
16151
  var LOCAL_USE = "./.github/actions/run-with-budget";
16006
16152
  var FULL_SHA = /^[0-9a-f]{40}$/;
@@ -16375,6 +16521,8 @@ function gateSeedVars(cls, releaseTrack, runtime = "node", requiredCheckBranches
16375
16521
  // The pin is the CLI's blessed SHA, not an operator knob — one central place to bump (#3178).
16376
16522
  GATE_BUDGET_SHA: BLESSED_RUN_WITH_BUDGET_SHA,
16377
16523
  GATE_RUNNER_SHA: BLESSED_RUNNER_GATE_SHA,
16524
+ // #8129: the guard and its bundled CLI must come from the same immutable Hub revision.
16525
+ GATE_RUNBOOK_SHA: BLESSED_RUNBOOK_GUARD_SHA,
16378
16526
  // #7407: repo-declared service containers and extra check steps; empty renders today's gate byte-for-byte.
16379
16527
  GATE_SERVICES_YAML: "",
16380
16528
  GATE_EXTRA_STEPS_YAML: ""
@@ -16412,6 +16560,8 @@ function gateSeedVars(cls, releaseTrack, runtime = "node", requiredCheckBranches
16412
16560
  }
16413
16561
  function withDerivedRepoVars(vars, parsed, cls, releaseTrack, requiredCheckBranches, requiredChecks) {
16414
16562
  const out = { ...vars };
16563
+ out.OWNER ??= parsed.owner;
16564
+ out.REPO ??= parsed.name;
16415
16565
  out.REPO_NAME ??= parsed.name;
16416
16566
  out.REPO_SLUG ??= parsed.slug;
16417
16567
  out.CLASS ??= cls;
@@ -18093,10 +18243,10 @@ var rollout_plan_default = {
18093
18243
  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)."
18094
18244
  },
18095
18245
  baseline: {
18096
- version: "4.5.123",
18097
- tag: "v4.5.123",
18098
- commit: "056fe18dfd23",
18099
- npm: "@mutmutco/cli@4.5.123"
18246
+ version: "4.5.125",
18247
+ tag: "v4.5.125",
18248
+ commit: "00accba6d8e0",
18249
+ npm: "@mutmutco/cli@4.5.125"
18100
18250
  },
18101
18251
  exitCriterion: "fleet-n-of-n",
18102
18252
  hubOnlyShortcut: "forbidden",
@@ -18113,14 +18263,14 @@ var rollout_plan_default = {
18113
18263
  repo: "mutmutco/mmi-hub",
18114
18264
  role: "canary",
18115
18265
  schedule: "train",
18116
- v3Target: "v4.5.123"
18266
+ v3Target: "v4.5.125"
18117
18267
  }
18118
18268
  ],
18119
18269
  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.",
18120
18270
  rollback: {
18121
18271
  independent: true,
18122
- mechanism: "npm dist-tag latest -> 4.5.123 and redeploy the Hub Lambda from tag v4.5.123 (056fe18dfd23); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
18123
- v3Target: "v4.5.123 (@mutmutco/cli@4.5.123, tag commit 056fe18dfd23 \u2014 last known-good release carrying the repo-index v4-only contract)"
18272
+ mechanism: "npm dist-tag latest -> 4.5.125 and redeploy the Hub Lambda from tag v4.5.125 (00accba6d8e0); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
18273
+ v3Target: "v4.5.125 (@mutmutco/cli@4.5.125, tag commit 00accba6d8e0 \u2014 last known-good release carrying the repo-index v4-only contract)"
18124
18274
  }
18125
18275
  },
18126
18276
  {
@@ -20203,7 +20353,7 @@ async function runMergeTreePreflight(deps, ours, theirs) {
20203
20353
  async function predictMergeConflicts(deps, ours, theirs) {
20204
20354
  return runMergeTreePreflight(deps, ours, theirs);
20205
20355
  }
20206
- async function mergeWithToleratedResolution(deps, sourceRef, label, resolve7, extraTolerated = []) {
20356
+ async function mergeWithToleratedResolution(deps, sourceRef, label, resolve8, extraTolerated = []) {
20207
20357
  try {
20208
20358
  await deps.run("git", ["merge", sourceRef, "--no-edit"]);
20209
20359
  return;
@@ -20217,7 +20367,7 @@ async function mergeWithToleratedResolution(deps, sourceRef, label, resolve7, ex
20217
20367
  unmerged.length === 0 ? `${label} merge failed without conflicted paths \u2014 merge aborted; inspect the repo state and rerun` : `${label} merge conflicts on untolerated path(s): ${blocking.join(", ")} \u2014 merge aborted (the train is misaligned; reconcile the branches via an approved alignment PR, then rerun)`
20218
20368
  );
20219
20369
  }
20220
- await deps.run("git", ["checkout", `--${resolve7}`, "--", ...unmerged]);
20370
+ await deps.run("git", ["checkout", `--${resolve8}`, "--", ...unmerged]);
20221
20371
  await deps.run("git", ["add", "--", ...unmerged]);
20222
20372
  await deps.run("git", ["commit", "--no-edit"]);
20223
20373
  }
@@ -20397,7 +20547,7 @@ var CORRELATE_SKEW_SLACK_MS = 1e4;
20397
20547
  var CORRELATE_PAGE_LIMIT = 50;
20398
20548
  var RUN_CONFIRM_ATTEMPTS = 3;
20399
20549
  var RUN_CONFIRM_DELAY_MS = 1e3;
20400
- var defaultSleep = (ms) => new Promise((resolve7) => setTimeout(resolve7, ms));
20550
+ var defaultSleep = (ms) => new Promise((resolve8) => setTimeout(resolve8, ms));
20401
20551
  function resolveSleep(deps) {
20402
20552
  return deps.sleep ?? defaultSleep;
20403
20553
  }
@@ -20977,6 +21127,14 @@ async function isStrayUnreleasedTag(deps, tag, remoteSha, repo) {
20977
21127
  }
20978
21128
  return deps.run("gh", ["release", "view", tag, "--repo", repo, "--json", "tagName"]).then(() => false).catch((e) => /not found|HTTP 404/i.test(e instanceof Error ? e.message : String(e)));
20979
21129
  }
21130
+ async function isPromotedUnreleasedTag(deps, tag, remoteSha, repo) {
21131
+ try {
21132
+ await deps.run("git", ["merge-base", "--is-ancestor", remoteSha, "origin/main"]);
21133
+ } catch {
21134
+ return false;
21135
+ }
21136
+ return deps.run("gh", ["release", "view", tag, "--repo", repo, "--json", "tagName"]).then(() => false).catch((e) => /not found|HTTP 404/i.test(e instanceof Error ? e.message : String(e)));
21137
+ }
20980
21138
  function cmpReleaseTag(a, b) {
20981
21139
  const parse2 = (t) => {
20982
21140
  const m = /^v(\d+)\.(\d+)\.(\d+)$/.exec(t.trim());
@@ -23568,7 +23726,7 @@ function lockTokenPid(token) {
23568
23726
  const m = /^(\d+)-/.exec(token);
23569
23727
  return m ? Number(m[1]) : void 0;
23570
23728
  }
23571
- var sleep = (ms) => new Promise((resolve7) => setTimeout(resolve7, ms));
23729
+ var sleep = (ms) => new Promise((resolve8) => setTimeout(resolve8, ms));
23572
23730
  var IMMEDIATE_RETRY_BUDGET = 3;
23573
23731
  var FileLockBusyError = class extends Error {
23574
23732
  lockPath;
@@ -24444,7 +24602,7 @@ async function defaultWatchRun(deps, runId, repo) {
24444
24602
  }
24445
24603
  let confirmError;
24446
24604
  for (let attempt = 0; attempt < RUN_CONFIRM_ATTEMPTS2; attempt++) {
24447
- if (attempt > 0) await new Promise((resolve7) => setTimeout(resolve7, RUN_CONFIRM_DELAY_MS2));
24605
+ if (attempt > 0) await new Promise((resolve8) => setTimeout(resolve8, RUN_CONFIRM_DELAY_MS2));
24448
24606
  try {
24449
24607
  const parsed = JSON.parse(await deps.run("gh", ["run", "view", String(runId), "--repo", repo, "--json", "status,conclusion"]));
24450
24608
  if (parsed.status === "completed") return parsed.conclusion === "success" ? "success" : "failure";
@@ -25486,11 +25644,11 @@ var defaultDeps = {
25486
25644
  // #5813: the caller supplies that command line. `process.argv` is NOT it — the house shim splices
25487
25645
  // the house root out in place, so re-reading it here re-ran the removed flat alias (`release …`
25488
25646
  // instead of `devops release …`) and the converged child refused with exit 2.
25489
- reexec: (argv) => new Promise((resolve7) => {
25647
+ reexec: (argv) => new Promise((resolve8) => {
25490
25648
  const args = [...argv];
25491
25649
  const child2 = isWin2 ? (0, import_node_child_process8.spawn)("cmd.exe", ["/c", "mmi-cli", ...args], { stdio: "inherit", windowsHide: true }) : (0, import_node_child_process8.spawn)("mmi-cli", args, { stdio: "inherit", windowsHide: true });
25492
- child2.on("exit", (code) => resolve7(code ?? 1));
25493
- child2.on("error", () => resolve7(1));
25650
+ child2.on("exit", (code) => resolve8(code ?? 1));
25651
+ child2.on("error", () => resolve8(1));
25494
25652
  }),
25495
25653
  // stderr only — stdout may be carrying --json output.
25496
25654
  warn: (line) => console.error(line)
@@ -25596,7 +25754,7 @@ var defaultDeps2 = {
25596
25754
  }
25597
25755
  },
25598
25756
  registryWhoami: probeRegistryWhoami,
25599
- sleep: (ms) => new Promise((resolve7) => setTimeout(resolve7, ms)),
25757
+ sleep: (ms) => new Promise((resolve8) => setTimeout(resolve8, ms)),
25600
25758
  env: process.env
25601
25759
  };
25602
25760
  function message(e) {
@@ -27609,7 +27767,9 @@ Nothing was written. Inspect ${ledger.path} (or clear it only after proving the
27609
27767
  for (const note of reverifyNotes) deps.warn?.(`release ledger: ${note}`);
27610
27768
  }
27611
27769
  const ledgerMode = persisted ? "strict" : "migration";
27612
- const partialRelease = await isStrayUnreleasedTag(deps, tag, tagSha, ctx.repo);
27770
+ const preMainPartial = await isStrayUnreleasedTag(deps, tag, tagSha, ctx.repo);
27771
+ const promotedPartial = !preMainPartial && await isPromotedUnreleasedTag(deps, tag, tagSha, ctx.repo);
27772
+ const partialRelease = preMainPartial || promotedPartial;
27613
27773
  if (partialRelease && meta.suite === "mm-work") await requireSuiteReleaseSummary(deps, options.announceSummaryFile);
27614
27774
  if (!partialRelease) {
27615
27775
  try {
@@ -27726,7 +27886,7 @@ Nothing was written. Inspect ${ledger.path} (or clear it only after proving the
27726
27886
  note: state2 === "failed" ? `release ${tag} was already published, but its deploy/publish on the release SHA FAILED \u2014 re-run the failed job (do NOT re-tag); the protected alignment PRs were reused` : state2 === "pending" ? `release ${tag} was already published; reused its protected alignment PRs, but a deploy/publish or alignment follow-up is unresolved \u2014 watch it to completion` : `release ${tag} was already published; alignment is complete and the deploy on the release SHA is proven green`
27727
27887
  };
27728
27888
  }
27729
- if (!await probeAncestor(deps, "origin/main", tagSha, "release --resume: origin/main fast-forward ancestry")) {
27889
+ if (!promotedPartial && !await probeAncestor(deps, "origin/main", tagSha, "release --resume: origin/main fast-forward ancestry")) {
27730
27890
  throw new Error(
27731
27891
  `release --resume: origin/main is not an ancestor of ${tag} (${tagSha.slice(0, 12)}) \u2014 main has moved on since the partial release, so finishing it here would not be a fast-forward. Resolve by hand; nothing was written.`
27732
27892
  );
@@ -27772,9 +27932,9 @@ ${recovery.note}`), recoveryInput);
27772
27932
  }
27773
27933
  await recordPhase(ledger, deps, anchors, "ordinaryCi", phaseEntry({ state: "complete", sha: tagSha, note: "re-verified the required-check wall live on this resume" }), { strict: ledgerMode === "strict", landed: "the immutable tag on origin at the resumed SHA" });
27774
27934
  deps.warn?.("Release: Promoting the verified release");
27775
- const versionEnv = await pushAfterVercelVersionEnv(deps, meta, "main", tag, ["push", "origin", `${tagSha}:refs/heads/main`]);
27776
- steps.push(`pushed ${tagSha.slice(0, 12)} to origin/main`);
27777
- await recordPhase(ledger, deps, anchors, "promotion", phaseEntry({ state: "complete", sha: tagSha, note: `resumed: ${tagSha.slice(0, 12)} pushed to origin/main (tag preserved, never re-cut)` }), { strict: ledgerMode === "strict", landed: "the immutable tag and the re-proven required-check wall" });
27935
+ const versionEnv = promotedPartial ? { status: "skipped", note: "" } : await pushAfterVercelVersionEnv(deps, meta, "main", tag, ["push", "origin", `${tagSha}:refs/heads/main`]);
27936
+ steps.push(promotedPartial ? `origin/main already contains ${tagSha.slice(0, 12)} (the main push had landed): not pushed again` : `pushed ${tagSha.slice(0, 12)} to origin/main`);
27937
+ await recordPhase(ledger, deps, anchors, "promotion", phaseEntry({ state: "complete", sha: tagSha, note: promotedPartial ? "re-verified live: origin/main contains the immutable tag SHA (#8128)" : `resumed: ${tagSha.slice(0, 12)} pushed to origin/main (tag preserved, never re-cut)` }), { strict: ledgerMode === "strict", landed: "the immutable tag and the re-proven required-check wall" });
27778
27938
  deps.warn?.("Release: Creating the GitHub Release");
27779
27939
  const autoRunSince = (deps.now ?? Date.now)();
27780
27940
  const cutBy = (await ledger.load(anchors))?.cutBy ?? describeSessionIdentity();
@@ -37002,7 +37162,7 @@ function readSuiteCut(path2) {
37002
37162
  } catch {
37003
37163
  throw new Error(`suite cut record unreadable at ${path2}; repair it, never recut`);
37004
37164
  }
37005
- if (record.schema !== SCHEMA || record.lead !== SUITE_REPO || !SHA2.test(record.leadDevelopment) || !SHA2.test(record.leadPreviousRc) || !Array.isArray(record.members) || record.members.length === 0 || record.pinPr !== void 0 && (typeof record.pinPr !== "string" || !record.pinPr.startsWith("https://github.com/mutmutco/MM-Work/pull/")) || record.pinsUnchanged !== void 0 && (record.pinsUnchanged !== true || record.pinPr !== void 0) || record.pinMerged !== void 0 && (record.pinMerged !== true && record.pinMerged !== false || !record.pinPr && !record.pinsUnchanged) || record.leadRcTag !== void 0 && (!RC_TAG.test(record.leadRcTag) || !SHA2.test(record.leadRcSha ?? "") || !record.pinMerged) || record.leadReleased !== void 0 && (record.leadReleased !== true || !record.leadRcTag) || record.announcement !== void 0 && (!["pending", "sent", "skipped"].includes(record.announcement) || !record.leadReleased) || record.heldMembers !== void 0 && (!Array.isArray(record.heldMembers) || record.heldMembers.some((h) => !h.id || !h.repo || typeof h.reason !== "string" || !h.reason.trim() || h.since !== void 0 && typeof h.since !== "string" || record.members.some((m) => m.id === h.id))) || record.members.some((m) => !m.id || !m.repo || !m.backend || !m.host || !SHA2.test(m.development) || !SHA2.test(m.previousRc) || m.rcWasAbsent !== void 0 && m.rcWasAbsent !== true || m.tag !== void 0 && (!RC_TAG.test(m.tag) || !SHA2.test(m.sha ?? "")) || m.published !== void 0 && (m.published !== true || !m.tag) || m.released !== void 0 && (m.released !== true || !m.published) || m.mainPublished !== void 0 && (m.mainPublished !== true || !m.released || !!m.carried) || m.backendAfterRelease !== void 0 && (!m.released || typeof m.backendAfterRelease !== "string") || m.carried !== void 0 && (m.carried !== true || m.tag !== void 0 || m.published !== void 0 || !isPin(m.rcPin) || !isPin(m.mainPin)) || m.carried === void 0 && (m.rcPin !== void 0 || m.mainPin !== void 0) || m.ruleset !== void 0 && (!["rc", "main"].includes(m.ruleset.after) || typeof m.ruleset.ok !== "boolean" || !Array.isArray(m.ruleset.lines))))
37165
+ if (record.schema !== SCHEMA || record.lead !== SUITE_REPO || !SHA2.test(record.leadDevelopment) || !SHA2.test(record.leadPreviousRc) || !Array.isArray(record.members) || record.members.length === 0 || record.pinPr !== void 0 && (typeof record.pinPr !== "string" || !record.pinPr.startsWith("https://github.com/mutmutco/MM-Work/pull/")) || record.pinsUnchanged !== void 0 && (record.pinsUnchanged !== true || record.pinPr !== void 0) || record.pinMerged !== void 0 && (record.pinMerged !== true && record.pinMerged !== false || !record.pinPr && !record.pinsUnchanged) || record.leadRcTag !== void 0 && (!RC_TAG.test(record.leadRcTag) || !SHA2.test(record.leadRcSha ?? "") || !record.pinMerged) || record.leadReleased !== void 0 && (record.leadReleased !== true || !record.leadRcTag) || record.announcement !== void 0 && (!["pending", "sent", "skipped"].includes(record.announcement) || !record.leadReleased) || record.heldMembers !== void 0 && (!Array.isArray(record.heldMembers) || record.heldMembers.some((h) => !h.id || !h.repo || typeof h.reason !== "string" || !h.reason.trim() || h.since !== void 0 && typeof h.since !== "string" || record.members.some((m) => m.id === h.id))) || record.members.some((m) => !m.id || !m.repo || !m.backend || !m.host || !SHA2.test(m.development) || !SHA2.test(m.previousRc) || m.rcWasAbsent !== void 0 && m.rcWasAbsent !== true || m.tag !== void 0 && (!RC_TAG.test(m.tag) || !SHA2.test(m.sha ?? "")) || m.carriedPublished !== void 0 && (m.carriedPublished !== true || !m.carried) || m.published !== void 0 && (m.published !== true || !m.tag) || m.released !== void 0 && (m.released !== true || !m.published) || m.mainPublished !== void 0 && (m.mainPublished !== true || !m.released || !!m.carried) || m.backendAfterRelease !== void 0 && (!m.released || typeof m.backendAfterRelease !== "string") || m.carried !== void 0 && (m.carried !== true || m.tag !== void 0 || m.published !== void 0 || !isPin(m.rcPin) || !isPin(m.mainPin)) || m.carried === void 0 && (m.rcPin !== void 0 || m.mainPin !== void 0) || m.ruleset !== void 0 && (!["rc", "main"].includes(m.ruleset.after) || typeof m.ruleset.ok !== "boolean" || !Array.isArray(m.ruleset.lines))))
37006
37166
  throw new Error(`suite cut record has unknown or invalid state at ${path2}; repair it, never recut`);
37007
37167
  return record;
37008
37168
  }
@@ -37114,7 +37274,22 @@ async function pendingBackend(deps, m, dev) {
37114
37274
  const files = (await deps.changedPaths(m.repo, live, dev)).filter((f) => !NOT_BACKEND.test(f));
37115
37275
  return files.length ? `${files.length} backend file(s) changed since live ${version}, e.g. ${files[0]}` : "";
37116
37276
  }
37277
+ function existingCutDescription(record) {
37278
+ const tags = [...record.members.flatMap((m) => m.tag ? [m.tag] : []), ...record.leadRcTag ? [record.leadRcTag] : []];
37279
+ return `from ${record.leadDevelopment.slice(0, 12)}; tags: ${tags.join(", ") || "none"}; pin PR: ${record.pinPr ?? "none"}`;
37280
+ }
37117
37281
  async function suiteRcand(deps, opts) {
37282
+ const existing = readSuiteCut(deps.recordPath);
37283
+ try {
37284
+ return await suiteRcandRun(deps, opts);
37285
+ } catch (e) {
37286
+ if (existing && !opts.dryRun && opts.ownerGo && readSuiteCut(deps.recordPath))
37287
+ throw new Error(`${e.message}
37288
+ An existing cut record ${existingCutDescription(existing)} was resumed. mmi-cli devops suite abandon --owner-go retires it (subject to abandon safety checks).`);
37289
+ throw e;
37290
+ }
37291
+ }
37292
+ async function suiteRcandRun(deps, opts) {
37118
37293
  if (!opts.ownerGo && !opts.dryRun) throw new Error("suite rcand requires --owner-go (rc uses live data); nothing was written");
37119
37294
  const members = suiteMembers(await deps.registry());
37120
37295
  const modules = trainModules(members);
@@ -37128,6 +37303,8 @@ async function suiteRcand(deps, opts) {
37128
37303
  const lead = await deps.head(SUITE_REPO, "development");
37129
37304
  plan.push(await kitCheck(deps, lead, active.map((m) => ({ id: m.id, url: m.bundles.dev })), "dev bundles"));
37130
37305
  if (opts.dryRun) {
37306
+ const existing = readSuiteCut(deps.recordPath);
37307
+ if (existing) plan.push(`existing cut record: ${deps.recordPath} (${existingCutDescription(existing)})`);
37131
37308
  plan.push(...await Promise.all(modules.map(async (m) => `${m.repo}: ${heldById.has(m.id) ? "HELD" : await dryRunStatus(deps, m)}`)));
37132
37309
  return { plan };
37133
37310
  }
@@ -37212,7 +37389,7 @@ async function suiteRcand(deps, opts) {
37212
37389
  }
37213
37390
  const refusals = [];
37214
37391
  for (const member of record.members) {
37215
- if (member.published) continue;
37392
+ if (member.published || member.carriedPublished) continue;
37216
37393
  try {
37217
37394
  await deps.preflight(member.repo);
37218
37395
  } catch (e) {
@@ -37226,28 +37403,60 @@ async function suiteRcand(deps, opts) {
37226
37403
  ${refusals.join("\n")}
37227
37404
  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).`);
37228
37405
  }
37229
- for (const member of record.members) {
37230
- if ((await deps.head(member.repo, "development"))?.toLowerCase() !== member.development.toLowerCase())
37231
- throw new Error(`${member.repo}: development moved after the cut snapshot; refuse to add untested code`);
37232
- if (member.carried) {
37233
- await deps.publish(member.repo, pinVersion(member.rcPin));
37234
- continue;
37235
- }
37236
- if (!member.tag) {
37237
- const cut = await deps.rcand(member.repo, member.previousRc, member.rcWasAbsent);
37238
- if (!RC_TAG.test(cut.tag) || !SHA2.test(cut.sha) || cut.sha.toLowerCase() === member.previousRc.toLowerCase()) throw new Error(`${member.repo}: rcand did not return a new immutable rc tag/SHA`);
37239
- if (!await deps.contains(member.repo, member.development, cut.sha)) throw new Error(`${member.repo}: rc tag does not carry the snapshotted development SHA; refuse`);
37240
- member.tag = cut.tag;
37241
- member.sha = cut.sha;
37242
- writeSuiteCut(deps.recordPath, record);
37243
- }
37244
- if ((await deps.tagSha(member.repo, member.tag))?.toLowerCase() !== member.sha.toLowerCase()) throw new Error(`${member.repo}: rc tag ${member.tag} moved or is unreadable; stop`);
37245
- if (!member.published) {
37246
- await deps.publish(member.repo, member.tag);
37247
- member.published = true;
37248
- writeSuiteCut(deps.recordPath, record);
37406
+ const cutRecord = record;
37407
+ let writes = Promise.resolve();
37408
+ const persist = (mutate) => {
37409
+ const next = writes.then(() => {
37410
+ mutate();
37411
+ writeSuiteCut(deps.recordPath, cutRecord);
37412
+ });
37413
+ writes = next.catch(() => {
37414
+ });
37415
+ return next;
37416
+ };
37417
+ let running = 0;
37418
+ const waiting = [];
37419
+ const results = await Promise.allSettled(record.members.map(async (member) => {
37420
+ if (running >= 4) await new Promise((resolve8) => waiting.push(resolve8));
37421
+ else running++;
37422
+ try {
37423
+ if ((await deps.head(member.repo, "development"))?.toLowerCase() !== member.development.toLowerCase())
37424
+ throw new Error(`${member.repo}: development moved after the cut snapshot; refuse to add untested code`);
37425
+ if (member.carried) {
37426
+ if (!member.carriedPublished) {
37427
+ await deps.publish(member.repo, pinVersion(member.rcPin));
37428
+ await persist(() => {
37429
+ member.carriedPublished = true;
37430
+ });
37431
+ }
37432
+ return;
37433
+ }
37434
+ if (!member.tag) {
37435
+ const cut = await deps.rcand(member.repo, member.previousRc, member.rcWasAbsent);
37436
+ if (!RC_TAG.test(cut.tag) || !SHA2.test(cut.sha) || cut.sha.toLowerCase() === member.previousRc.toLowerCase()) throw new Error(`${member.repo}: rcand did not return a new immutable rc tag/SHA`);
37437
+ if (!await deps.contains(member.repo, member.development, cut.sha)) throw new Error(`${member.repo}: rc tag does not carry the snapshotted development SHA; refuse`);
37438
+ await persist(() => {
37439
+ member.tag = cut.tag;
37440
+ member.sha = cut.sha;
37441
+ });
37442
+ }
37443
+ const tag = member.tag;
37444
+ if ((await deps.tagSha(member.repo, tag))?.toLowerCase() !== member.sha.toLowerCase()) throw new Error(`${member.repo}: rc tag ${member.tag} moved or is unreadable; stop`);
37445
+ if (!member.published) {
37446
+ await deps.publish(member.repo, tag);
37447
+ await persist(() => {
37448
+ member.published = true;
37449
+ });
37450
+ }
37451
+ } finally {
37452
+ const next = waiting.shift();
37453
+ if (next) next();
37454
+ else running--;
37249
37455
  }
37250
- }
37456
+ }));
37457
+ const failures = results.flatMap((result, i) => result.status === "rejected" ? [`${record.members[i].repo}: ${result.reason instanceof Error ? result.reason.message : String(result.reason)}`] : []);
37458
+ if (failures.length) throw new Error(`suite member cuts failed:
37459
+ ${failures.join("\n")}`);
37251
37460
  for (const member of record.members) {
37252
37461
  const [live, devHead] = await Promise.all([
37253
37462
  deps.backend({ repo: member.repo, id: member.id, bundles: {} }),
@@ -37692,8 +37901,10 @@ async function runRcDataSwitch(deps, opts) {
37692
37901
  }
37693
37902
 
37694
37903
  // src/suite-train-io.ts
37695
- var import_node_fs45 = require("node:fs");
37904
+ var import_node_child_process18 = require("node:child_process");
37696
37905
  var import_node_path44 = require("node:path");
37906
+ var import_node_fs45 = require("node:fs");
37907
+ var import_node_path45 = require("node:path");
37697
37908
  init_cli_shared();
37698
37909
 
37699
37910
  // src/command-register-train-operations.ts
@@ -37875,7 +38086,7 @@ function clean3(out) {
37875
38086
  return out.trim();
37876
38087
  }
37877
38088
  function sleeper(deps) {
37878
- return deps.sleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms)));
38089
+ return deps.sleep ?? ((ms) => new Promise((resolve8) => setTimeout(resolve8, ms)));
37879
38090
  }
37880
38091
  function normalizeHotfixVersion(input) {
37881
38092
  const m = /^v?(\d+\.\d+\.\d+)$/.exec(input.trim());
@@ -38048,8 +38259,8 @@ async function preflightHotfixBatchPicks(deps, sources, pickTolerated) {
38048
38259
  if (sources.length === 0) return { failures: [], skipped: [] };
38049
38260
  const { mkdtemp: mkdtemp2, rm: rm2 } = await import("node:fs/promises");
38050
38261
  const { tmpdir: tmpdir12 } = await import("node:os");
38051
- const { join: join48 } = await import("node:path");
38052
- const dir = await mkdtemp2(join48(tmpdir12(), "mmi-hotfix-preflight-"));
38262
+ const { join: join49 } = await import("node:path");
38263
+ const dir = await mkdtemp2(join49(tmpdir12(), "mmi-hotfix-preflight-"));
38053
38264
  const wt = { run: (file, args) => deps.run(file, file === "git" ? ["-C", dir, ...args] : args) };
38054
38265
  const failures = [];
38055
38266
  const skipped = [];
@@ -39547,7 +39758,7 @@ async function updatePrHeadFromBase(input) {
39547
39758
  } catch (e) {
39548
39759
  throw new Error(`GitHub could not update ${input.head} from ${input.base} (${e.message.trim()}) \u2014 ${remedy}`);
39549
39760
  }
39550
- const sleep2 = input.sleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms)));
39761
+ const sleep2 = input.sleep ?? ((ms) => new Promise((resolve8) => setTimeout(resolve8, ms)));
39551
39762
  for (let attempt = 0; attempt < PR_HEAD_UPDATE_API_READ_RETRIES; attempt++) {
39552
39763
  const to = await readHead2();
39553
39764
  if (to && to !== from) return { from, to, base: input.base, via: "update-branch-api" };
@@ -39565,7 +39776,7 @@ async function mergeAutoWithTransientRetry(prNumber, repo, deps) {
39565
39776
  if (first.mergeStatus !== "failed") return first;
39566
39777
  const ready = await deps.probeMergeReady(prNumber, repo).catch(() => ({ open: false, mergeable: false, checksPassing: false }));
39567
39778
  if (!ready.open || !ready.mergeable || !ready.checksPassing) return first;
39568
- const sleep2 = deps.sleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms)));
39779
+ const sleep2 = deps.sleep ?? ((ms) => new Promise((resolve8) => setTimeout(resolve8, ms)));
39569
39780
  await sleep2(PR_LAND_MERGE_RETRY_DELAY_MS);
39570
39781
  const retried = await deps.mergeAuto(prNumber, repo);
39571
39782
  if (retried.mergeStatus !== "failed") return retried;
@@ -39576,7 +39787,7 @@ var AUTO_MERGE_CONFIRM_DELAY_MS = 15e3;
39576
39787
  async function confirmAutoMergeEnqueued(deps, options) {
39577
39788
  const retries = options?.retries ?? AUTO_MERGE_CONFIRM_RETRIES;
39578
39789
  const delayMs = options?.delayMs ?? AUTO_MERGE_CONFIRM_DELAY_MS;
39579
- const sleep2 = deps.sleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms)));
39790
+ const sleep2 = deps.sleep ?? ((ms) => new Promise((resolve8) => setTimeout(resolve8, ms)));
39580
39791
  for (let attempt = 0; attempt < retries; attempt++) {
39581
39792
  if (await deps.readMerged().catch(() => false)) return "merged";
39582
39793
  const stuck = await deps.readAutoMergeRequest().then((s) => s.trim()).catch(() => "");
@@ -39593,7 +39804,7 @@ async function confirmAutoMergeEnqueued(deps, options) {
39593
39804
  async function readGhPrStateWithRetry(fetchState, options) {
39594
39805
  const retries = options?.retries ?? PR_LAND_STATE_READ_RETRIES;
39595
39806
  const delayMs = options?.delayMs ?? PR_LAND_STATE_READ_DELAY_MS;
39596
- const sleep2 = options?.sleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms)));
39807
+ const sleep2 = options?.sleep ?? ((ms) => new Promise((resolve8) => setTimeout(resolve8, ms)));
39597
39808
  let lastError = "empty state";
39598
39809
  for (let attempt = 0; attempt < retries; attempt++) {
39599
39810
  try {
@@ -43221,7 +43432,7 @@ async function checkPrReview(number, repo, head, deps = {
43221
43432
  }
43222
43433
  }
43223
43434
  function computePrPatchId(number, repo) {
43224
- return new Promise((resolve7, reject) => {
43435
+ return new Promise((resolve8, reject) => {
43225
43436
  const gh2 = (0, import_node_child_process14.spawn)("gh", ["pr", "diff", number, "--repo", repo], { windowsHide: true, stdio: ["ignore", "pipe", "pipe"] });
43226
43437
  const git3 = (0, import_node_child_process14.spawn)("git", ["patch-id", "--stable"], { windowsHide: true, stdio: ["pipe", "pipe", "pipe"] });
43227
43438
  let out = "";
@@ -43259,7 +43470,7 @@ function computePrPatchId(number, repo) {
43259
43470
  if (gitCode !== 0) return reject(new Error(`git patch-id --stable exited ${gitCode}: ${gitErr.trim()}`));
43260
43471
  const id = out.trim().split(/\s+/)[0];
43261
43472
  if (!/^[0-9a-f]{40}$/.test(id ?? "")) return reject(new Error(`patch-id: PR #${number} diff is empty or unreadable (gh: ${ghErr.trim() || "no stderr"})`));
43262
- resolve7(id);
43473
+ resolve8(id);
43263
43474
  };
43264
43475
  gh2.on("close", (code) => {
43265
43476
  ghCode = code;
@@ -43310,7 +43521,7 @@ init_cli_shared();
43310
43521
  var GIT_TIMEOUT_MS2 = 15e3;
43311
43522
  function catFileBatch(root, ref, paths) {
43312
43523
  if (paths.length === 0) return Promise.resolve([]);
43313
- return new Promise((resolve7) => {
43524
+ return new Promise((resolve8) => {
43314
43525
  const chunks = [];
43315
43526
  let settled = false;
43316
43527
  const child2 = (0, import_node_child_process15.spawn)("git", ["-C", root, "cat-file", "--batch", "--buffer"], { windowsHide: true });
@@ -43318,7 +43529,7 @@ function catFileBatch(root, ref, paths) {
43318
43529
  if (settled) return;
43319
43530
  settled = true;
43320
43531
  clearTimeout(timer);
43321
- resolve7(parseCatFileBatch(Buffer.concat(chunks), paths.length));
43532
+ resolve8(parseCatFileBatch(Buffer.concat(chunks), paths.length));
43322
43533
  };
43323
43534
  const timer = setTimeout(() => {
43324
43535
  child2.kill("SIGKILL");
@@ -43743,7 +43954,7 @@ function healthPollIntervalMs() {
43743
43954
  return HEALTH_POLL_INTERVAL_MS;
43744
43955
  }
43745
43956
  function waitForProcessStability(child2, graceMs = earlyExitGraceMs()) {
43746
- return new Promise((resolve7, reject) => {
43957
+ return new Promise((resolve8, reject) => {
43747
43958
  let settled = false;
43748
43959
  const finish = (fn) => {
43749
43960
  if (settled) return;
@@ -43753,7 +43964,7 @@ function waitForProcessStability(child2, graceMs = earlyExitGraceMs()) {
43753
43964
  child2.removeAllListeners("exit");
43754
43965
  fn();
43755
43966
  };
43756
- const timer = setTimeout(() => finish(resolve7), graceMs);
43967
+ const timer = setTimeout(() => finish(resolve8), graceMs);
43757
43968
  child2.on("error", (err) => finish(() => reject(new Error(`stage process failed to start: ${err.message}`))));
43758
43969
  child2.on("exit", (code, signal) => {
43759
43970
  const detail = code != null ? `code ${code}` : signal ? `signal ${signal}` : "unknown reason";
@@ -43946,10 +44157,10 @@ function pickStagePort(range, isFree) {
43946
44157
  throw new Error(`no free stage port in range ${start}-${end} \u2014 every port is in use`);
43947
44158
  }
43948
44159
  function isPortFree(port) {
43949
- return new Promise((resolve7) => {
44160
+ return new Promise((resolve8) => {
43950
44161
  const srv = (0, import_node_net.createServer)();
43951
- srv.once("error", () => resolve7(false));
43952
- srv.once("listening", () => srv.close(() => resolve7(true)));
44162
+ srv.once("error", () => resolve8(false));
44163
+ srv.once("listening", () => srv.close(() => resolve8(true)));
43953
44164
  srv.listen(port, "127.0.0.1");
43954
44165
  });
43955
44166
  }
@@ -44227,7 +44438,7 @@ async function killTree(pid) {
44227
44438
  } catch {
44228
44439
  }
44229
44440
  }
44230
- await new Promise((resolve7) => setTimeout(resolve7, 500));
44441
+ await new Promise((resolve8) => setTimeout(resolve8, 500));
44231
44442
  try {
44232
44443
  process.kill(-pid, "SIGKILL");
44233
44444
  } catch {
@@ -44300,7 +44511,7 @@ async function waitForHealth(url, timeoutMs, anyStatus = false) {
44300
44511
  } catch (e) {
44301
44512
  last = e.message;
44302
44513
  }
44303
- await new Promise((resolve7) => setTimeout(resolve7, healthPollIntervalMs()));
44514
+ await new Promise((resolve8) => setTimeout(resolve8, healthPollIntervalMs()));
44304
44515
  }
44305
44516
  throw new Error(`stage health check timed out for ${url}${last ? ` (${last})` : ""}`);
44306
44517
  }
@@ -44660,7 +44871,7 @@ function unlinkNodeModulesJunction(wtPath) {
44660
44871
  }
44661
44872
  }
44662
44873
  function defaultSleep2(ms) {
44663
- return new Promise((resolve7) => setTimeout(resolve7, ms));
44874
+ return new Promise((resolve8) => setTimeout(resolve8, ms));
44664
44875
  }
44665
44876
  async function removeResidueDirectory(wtPath, options = {}) {
44666
44877
  const { sleep: sleep2 = defaultSleep2, removeEmptyDir = import_node_fs42.rmdirSync, exists = import_node_fs42.existsSync } = options;
@@ -46410,7 +46621,7 @@ ${list}`);
46410
46621
  // #5400: after grace, name "GitHub delivered zero runs" instead of burning the full budget as pending.
46411
46622
  pollHeadWorkflowRunCount: () => waitLoopHeadWorkflowRunCount("pr checks-wait", number, repo),
46412
46623
  baseBranch,
46413
- sleep: (ms) => new Promise((resolve7) => setTimeout(resolve7, ms)),
46624
+ sleep: (ms) => new Promise((resolve8) => setTimeout(resolve8, ms)),
46414
46625
  log: (message2) => console.warn(message2),
46415
46626
  timeoutMs: Math.max(1, budgetMs - (Date.now() - waitStarted)),
46416
46627
  // Liveness on stderr, one line per poll. A silent bounded wait is indistinguishable from a hang, and
@@ -46565,7 +46776,7 @@ ${list}`);
46565
46776
  // #5400: same zero-runs delivery probe as checks-wait — do not burn the land budget on silence.
46566
46777
  pollHeadWorkflowRunCount: () => waitLoopHeadWorkflowRunCount("pr land", prNumber, repo),
46567
46778
  baseBranch: "development",
46568
- sleep: (ms) => new Promise((resolve7) => setTimeout(resolve7, ms)),
46779
+ sleep: (ms) => new Promise((resolve8) => setTimeout(resolve8, ms)),
46569
46780
  log: (message2) => console.warn(message2),
46570
46781
  // `pr land` inherits the same (raised) checks budget, so it needs the same liveness — otherwise the
46571
46782
  // 30m wait is SILENT and reads exactly like the hang #2940 was filed about, only three times longer.
@@ -46616,7 +46827,7 @@ ${list}`);
46616
46827
  } else {
46617
46828
  lastFailure = void 0;
46618
46829
  }
46619
- await new Promise((resolve7) => setTimeout(resolve7, PR_LAND_POLL_MS));
46830
+ await new Promise((resolve8) => setTimeout(resolve8, PR_LAND_POLL_MS));
46620
46831
  }
46621
46832
  if (lastFailure) {
46622
46833
  throw new Error(
@@ -46774,7 +46985,7 @@ ${list}`);
46774
46985
  checksDiagnosticCommand: `gh pr checks ${number} --repo ${repo}`,
46775
46986
  pollHeadWorkflowRunCount: () => waitLoopHeadWorkflowRunCount("pr merge --wait", number, repo),
46776
46987
  baseBranch,
46777
- sleep: (ms) => new Promise((resolve7) => setTimeout(resolve7, ms)),
46988
+ sleep: (ms) => new Promise((resolve8) => setTimeout(resolve8, ms)),
46778
46989
  log: (message2) => console.warn(message2),
46779
46990
  timeoutMs: Math.max(1, budgetMs - (Date.now() - waitStarted)),
46780
46991
  progress: ({ state, elapsedMs, remainingMs }) => console.warn(`pr merge: --wait checks \u2014 ${state}, ${Math.round(elapsedMs / 1e3)}s elapsed, ${Math.round(remainingMs / 6e4)}m left`)
@@ -46843,7 +47054,7 @@ ${list}`);
46843
47054
  }
46844
47055
  if (!o.auto && mergeRejectedBaseBranchModified(message2)) {
46845
47056
  console.warn(`pr merge: the base branch was modified by a concurrent merge \u2014 waiting ${PR_MERGE_BASE_RACE_RETRY_DELAY_MS / 1e3}s and retrying PR #${number}'s merge once (#6052).`);
46846
- await new Promise((resolve7) => setTimeout(resolve7, PR_MERGE_BASE_RACE_RETRY_DELAY_MS));
47057
+ await new Promise((resolve8) => setTimeout(resolve8, PR_MERGE_BASE_RACE_RETRY_DELAY_MS));
46847
47058
  await execFileP("gh", buildPrMergeArgs({ number, repoArgs, method, auto: false, deleteBranch: false, bodyFile }), { timeout: GH_MUTATION_TIMEOUT_MS }).catch((e2) => {
46848
47059
  const m2 = String(e2.message || "");
46849
47060
  if (/already been merged/i.test(m2)) {
@@ -47104,7 +47315,7 @@ ${list}`);
47104
47315
  console.warn(`ci checks-wait: zero-runs probe FAILED (${read.error}) \u2014 not treating as delivery failure this cycle`);
47105
47316
  return null;
47106
47317
  },
47107
- sleep: (ms) => new Promise((resolve7) => setTimeout(resolve7, ms)),
47318
+ sleep: (ms) => new Promise((resolve8) => setTimeout(resolve8, ms)),
47108
47319
  log: (message2) => console.warn(message2),
47109
47320
  timeoutMs: timeoutMs ?? PR_CHECKS_TIMEOUT_MS,
47110
47321
  progress: ({ state, elapsedMs, remainingMs }) => console.warn(`ci checks-wait: ${state} \u2014 ${Math.round(elapsedMs / 1e3)}s elapsed, ${Math.round(remainingMs / 6e4)}m left`)
@@ -47469,7 +47680,7 @@ function hotfixFollowUpLegs(runs, foldPort, alignment, foldNote, deployNote) {
47469
47680
  }
47470
47681
  return legs;
47471
47682
  }
47472
- async function runProjectInfoSyncLeg(cb, repo, sleep2 = (ms) => new Promise((resolve7) => setTimeout(resolve7, ms))) {
47683
+ async function runProjectInfoSyncLeg(cb, repo, sleep2 = (ms) => new Promise((resolve8) => setTimeout(resolve8, ms))) {
47473
47684
  for (let attempt = 0; ; attempt++) {
47474
47685
  try {
47475
47686
  return await cb(repo, true);
@@ -48198,18 +48409,63 @@ function rcRunCauseFromLog(log) {
48198
48409
  function memberAnnounceSummaryFile(repo, summaryFile, memberSummaryFiles) {
48199
48410
  return repo === SUITE_REPO ? summaryFile : memberSummaryFiles[repo];
48200
48411
  }
48201
- var suiteStateDir = (root) => (0, import_node_path44.join)(resolvePrimaryGitDir(root), "mmi-runtime", "suite");
48412
+ var suiteStateDir = (root) => (0, import_node_path45.join)(resolvePrimaryGitDir(root), "mmi-runtime", "suite");
48413
+ async function runSuiteMemberRcand(repo, previousRc, rcWasAbsent) {
48414
+ const deps = trainApplyDeps();
48415
+ deps.suiteCut = suiteCutContext(repo, SUITE_REPO);
48416
+ deps.announce = async () => ({ status: "skipped", note: "suite announcement belongs to MM-Work" });
48417
+ return rcandInCheckout(repo, deps, previousRc, rcWasAbsent);
48418
+ }
48419
+ async function rcandInCheckout(repo, deps, previousRc, rcWasAbsent) {
48420
+ if (repo !== SUITE_REPO) await prepareDevelopmentCheckout((args) => deps.run("git", args), repo);
48421
+ await deps.run("git", ["fetch", "origin", "--tags"]);
48422
+ let rcNow;
48423
+ try {
48424
+ rcNow = (await deps.run("git", ["rev-parse", "--verify", "origin/rc"])).trim();
48425
+ } catch (e) {
48426
+ if (!rcWasAbsent || !previousRc || repo === SUITE_REPO) throw e;
48427
+ const slug = repo.split("/")[1].toLowerCase();
48428
+ const meta = await fetchProjectBySlugChecked(slug, registryClientDeps(await loadConfig()));
48429
+ if (!meta.ok || meta.project?.releaseTrack !== "full" || meta.project.suite !== "mm-work")
48430
+ throw new Error(`${repo}: first rc branch requires releaseTrack full and suite=mm-work in META; no branch created`);
48431
+ const main = (await deps.run("git", ["rev-parse", "origin/main"])).trim();
48432
+ if (main.toLowerCase() !== previousRc.toLowerCase()) throw new Error(`${repo}: main moved since the cut snapshot; no rc branch created`);
48433
+ await deps.run("git", ["push", "origin", `${previousRc}:refs/heads/rc`]);
48434
+ await deps.run("git", ["fetch", "origin", "rc"]);
48435
+ rcNow = (await deps.run("git", ["rev-parse", "origin/rc"])).trim();
48436
+ }
48437
+ if (!(await deps.run("git", ["branch", "--list", "rc"])).trim()) {
48438
+ await deps.run("git", ["switch", "-c", "rc", "--track", "origin/rc"]);
48439
+ await deps.run("git", ["switch", "development"]);
48440
+ }
48441
+ if (previousRc && rcNow.toLowerCase() !== previousRc.toLowerCase()) {
48442
+ const tags = (await deps.run("git", ["tag", "--points-at", rcNow, "--list", "v*-rc.*"])).trim().split("\n").filter(Boolean);
48443
+ if (tags.length !== 1) throw new Error(`${repo}: rc moved since cut start without exactly one candidate tag; stop`);
48444
+ return { tag: tags[0], sha: rcNow };
48445
+ }
48446
+ try {
48447
+ const result = await runTrainApply("rcand", deps, { watch: true });
48448
+ if (result.deployStatus !== "success") throw new Error(`${repo}: rcand deploy not green (${result.deployStatus})`);
48449
+ return { tag: result.tag, sha: (await deps.run("git", ["rev-parse", result.tag])).trim() };
48450
+ } catch (e) {
48451
+ const existing = (await deps.run("git", ["tag", "--list", "v*-rc.*"])).trim();
48452
+ if (!existing || !/resume|partial|ledger|tag.*pushed/i.test(e.message)) throw e;
48453
+ const result = await runRcandResume(deps, { watch: true });
48454
+ if (result.deployStatus !== "success") throw new Error(`${repo}: resumed rcand deploy not green (${result.deployStatus})`);
48455
+ return { tag: result.tag, sha: result.tagSha };
48456
+ }
48457
+ }
48202
48458
  function suiteTrainIo(root, summaryFile, memberSummaryFiles = {}, summaryFileTr, memberSummaryFilesTr = {}) {
48203
- const recordPath = (0, import_node_path44.join)(suiteStateDir(root), "cut.json");
48204
- const base = (0, import_node_path44.join)(suiteStateDir(root), "checkouts");
48459
+ const recordPath = (0, import_node_path45.join)(suiteStateDir(root), "cut.json");
48460
+ const base = (0, import_node_path45.join)(suiteStateDir(root), "checkouts");
48205
48461
  const checkout = async (repo) => {
48206
48462
  if (repo === SUITE_REPO) return root;
48207
- const target = (0, import_node_path44.join)(base, repo.split("/")[1]);
48463
+ const target = (0, import_node_path45.join)(base, repo.split("/")[1]);
48208
48464
  if (!(0, import_node_fs45.existsSync)(target)) {
48209
48465
  (0, import_node_fs45.mkdirSync)(base, { recursive: true });
48210
48466
  await exec("git", ["clone", "--quiet", "--branch", "development", `https://github.com/${repo}.git`, target], root, WATCH_TIMEOUT);
48211
48467
  }
48212
- if (!(0, import_node_fs45.existsSync)((0, import_node_path44.join)(target, ".git"))) throw new Error(`${repo}: suite checkout has no .git at ${target}; stop`);
48468
+ if (!(0, import_node_fs45.existsSync)((0, import_node_path45.join)(target, ".git"))) throw new Error(`${repo}: suite checkout has no .git at ${target}; stop`);
48213
48469
  const origin = await exec("git", ["remote", "get-url", "origin"], target);
48214
48470
  if (!origin.toLowerCase().endsWith(`/${repo.toLowerCase()}.git`) && !origin.toLowerCase().endsWith(`/${repo.toLowerCase()}`))
48215
48471
  throw new Error(`${repo}: suite checkout origin mismatch at ${target}; stop`);
@@ -48269,45 +48525,28 @@ function suiteTrainIo(root, summaryFile, memberSummaryFiles = {}, summaryFileTr,
48269
48525
  throw e;
48270
48526
  }
48271
48527
  };
48272
- const runRcand = async (repo, previousRc, rcWasAbsent) => inTrain(repo, async (deps) => {
48273
- if (repo !== SUITE_REPO) await prepareDevelopmentCheckout((args) => deps.run("git", args), repo);
48274
- await deps.run("git", ["fetch", "origin", "--tags"]);
48275
- let rcNow;
48276
- try {
48277
- rcNow = (await deps.run("git", ["rev-parse", "--verify", "origin/rc"])).trim();
48278
- } catch (e) {
48279
- if (!rcWasAbsent || !previousRc || repo === SUITE_REPO) throw e;
48280
- const slug = repo.split("/")[1].toLowerCase();
48281
- const meta = await fetchProjectBySlugChecked(slug, registryClientDeps(await loadConfig()));
48282
- if (!meta.ok || meta.project?.releaseTrack !== "full" || meta.project.suite !== "mm-work")
48283
- throw new Error(`${repo}: first rc branch requires releaseTrack full and suite=mm-work in META; no branch created`);
48284
- const main = (await deps.run("git", ["rev-parse", "origin/main"])).trim();
48285
- if (main.toLowerCase() !== previousRc.toLowerCase()) throw new Error(`${repo}: main moved since the cut snapshot; no rc branch created`);
48286
- await deps.run("git", ["push", "origin", `${previousRc}:refs/heads/rc`]);
48287
- await deps.run("git", ["fetch", "origin", "rc"]);
48288
- rcNow = (await deps.run("git", ["rev-parse", "origin/rc"])).trim();
48289
- }
48290
- if (!(await deps.run("git", ["branch", "--list", "rc"])).trim()) {
48291
- await deps.run("git", ["switch", "-c", "rc", "--track", "origin/rc"]);
48292
- await deps.run("git", ["switch", "development"]);
48293
- }
48294
- if (previousRc && rcNow.toLowerCase() !== previousRc.toLowerCase()) {
48295
- const tags = (await deps.run("git", ["tag", "--points-at", rcNow, "--list", "v*-rc.*"])).trim().split("\n").filter(Boolean);
48296
- if (tags.length !== 1) throw new Error(`${repo}: rc moved since cut start without exactly one candidate tag; stop`);
48297
- return { tag: tags[0], sha: rcNow };
48298
- }
48299
- try {
48300
- const result = await runTrainApply("rcand", deps, { watch: true });
48301
- if (result.deployStatus !== "success") throw new Error(`${repo}: rcand deploy not green (${result.deployStatus})`);
48302
- return { tag: result.tag, sha: (await deps.run("git", ["rev-parse", result.tag])).trim() };
48303
- } catch (e) {
48304
- const existing = (await deps.run("git", ["tag", "--list", "v*-rc.*"])).trim();
48305
- if (!existing || !/resume|partial|ledger|tag.*pushed/i.test(e.message)) throw e;
48306
- const result = await runRcandResume(deps, { watch: true });
48307
- if (result.deployStatus !== "success") throw new Error(`${repo}: resumed rcand deploy not green (${result.deployStatus})`);
48308
- return { tag: result.tag, sha: result.tagSha };
48309
- }
48310
- });
48528
+ const runRcand = async (repo, previousRc, rcWasAbsent) => {
48529
+ if (repo === SUITE_REPO) return inTrain(repo, (deps) => rcandInCheckout(repo, deps, previousRc, rcWasAbsent));
48530
+ const target = await checkout(repo);
48531
+ return new Promise((resolveResult, reject) => {
48532
+ const child2 = (0, import_node_child_process18.fork)((0, import_node_path44.resolve)(process.argv[1]), ["devops", "suite", "member-rcand-internal", repo, previousRc ?? "", ...rcWasAbsent ? ["--rc-was-absent"] : []], {
48533
+ cwd: target,
48534
+ stdio: ["ignore", "inherit", "inherit", "ipc"],
48535
+ execArgv: []
48536
+ });
48537
+ let result;
48538
+ let failure;
48539
+ child2.on("message", (message2) => {
48540
+ result = message2.result;
48541
+ failure = message2.error;
48542
+ });
48543
+ child2.on("error", reject);
48544
+ child2.on("exit", (code) => {
48545
+ if (code === 0 && result) resolveResult(result);
48546
+ else reject(new Error(failure ?? `${repo}: member rcand process exited ${code} without a result`));
48547
+ });
48548
+ });
48549
+ };
48311
48550
  const release = async (repo, expected, rcSha, opts) => inTrain(repo, async (deps) => {
48312
48551
  await prepareRcCheckout((args) => deps.run("git", args), repo);
48313
48552
  const plainWords = {
@@ -48362,7 +48601,7 @@ function suiteTrainIo(root, summaryFile, memberSummaryFiles = {}, summaryFileTr,
48362
48601
  if (!reuse) await gh(["workflow", "run", "module-rc-publish.yml", "--repo", "mutmutco/MMI-Hub", ...fields.flatMap((f) => ["--field", f])]);
48363
48602
  let candidate = reuse;
48364
48603
  for (let i = 0; !candidate && i < 25; i++) {
48365
- await new Promise((resolve7) => setTimeout(resolve7, 1e3));
48604
+ await new Promise((resolve8) => setTimeout(resolve8, 1e3));
48366
48605
  candidate = (await rcRuns()).find((r) => r.displayTitle === title && Date.parse(r.createdAt) >= since);
48367
48606
  }
48368
48607
  if (!candidate) throw new Error(`workflow dispatch outcome ambiguous for "${title}"; inspect Actions before retrying`);
@@ -48517,7 +48756,7 @@ function suiteTrainIo(root, summaryFile, memberSummaryFiles = {}, summaryFileTr,
48517
48756
  for (let i = 0; ; i++) {
48518
48757
  const pin = await openSuitePinPr({ root, run: (file, args, cwd) => exec(file, args, cwd, GIT_TIMEOUT_MS) }, { repo, tag, stage: "main" });
48519
48758
  if (pin.status !== "pending" || i >= 40) return pin;
48520
- await new Promise((resolve7) => setTimeout(resolve7, 3e4));
48759
+ await new Promise((resolve8) => setTimeout(resolve8, 3e4));
48521
48760
  }
48522
48761
  },
48523
48762
  suiteMapping: async (leadTag) => {
@@ -48533,7 +48772,7 @@ function suiteTrainIo(root, summaryFile, memberSummaryFiles = {}, summaryFileTr,
48533
48772
  if (parseSuiteMapping(body)) return;
48534
48773
  const dir = suiteStateDir(root);
48535
48774
  (0, import_node_fs45.mkdirSync)(dir, { recursive: true });
48536
- const file = (0, import_node_path44.join)(dir, `notes-${leadTag}.md`);
48775
+ const file = (0, import_node_path45.join)(dir, `notes-${leadTag}.md`);
48537
48776
  (0, import_node_fs45.writeFileSync)(file, `${body}
48538
48777
 
48539
48778
  ${suiteMappingBlock(leadTag, mapping)}`);
@@ -48599,11 +48838,23 @@ function suiteRcDataProdDeps() {
48599
48838
  const rc = facts.stages.rc;
48600
48839
  return rc?.present ? rc.substrate ?? "an unnamed substrate" : null;
48601
48840
  },
48602
- sleep: (ms) => new Promise((resolve7) => setTimeout(resolve7, ms))
48841
+ sleep: (ms) => new Promise((resolve8) => setTimeout(resolve8, ms))
48603
48842
  };
48604
48843
  }
48605
48844
  function registerSuiteCommands(program3) {
48606
48845
  const suite = program3.command("suite").description("MM-Work suite status, candidate cut and release (#7262/#7263)");
48846
+ suite.command("member-rcand-internal", { hidden: true }).argument("<repo>").argument("<previous-rc>").option("--rc-was-absent").action(async (repo, previousRc, o) => {
48847
+ if (!process.send) return fail("member rcand is an internal suite child operation");
48848
+ try {
48849
+ if (repo === SUITE_REPO || (await resolveRepo())?.toLowerCase() !== repo.toLowerCase())
48850
+ throw new Error(`${repo}: member rcand checkout mismatch; stop`);
48851
+ const result = await runSuiteMemberRcand(repo, previousRc || void 0, o.rcWasAbsent);
48852
+ process.send({ result }, () => process.disconnect());
48853
+ } catch (e) {
48854
+ process.exitCode = 1;
48855
+ process.send({ error: e.message }, () => process.disconnect());
48856
+ }
48857
+ });
48607
48858
  const leadRoot = async () => {
48608
48859
  const repo = await resolveRepo();
48609
48860
  if (repo?.toLowerCase() !== SUITE_REPO.toLowerCase()) throw new Error(`suite commands run only from ${SUITE_REPO} (got ${repo ?? "unknown"})`);
@@ -48845,10 +49096,10 @@ function suiteStatusDeps(github, registry2) {
48845
49096
  }
48846
49097
 
48847
49098
  // src/packages-adopt-export.ts
48848
- var import_node_child_process18 = require("node:child_process");
49099
+ var import_node_child_process19 = require("node:child_process");
48849
49100
  var import_node_fs47 = require("node:fs");
48850
49101
  var import_node_os22 = require("node:os");
48851
- var import_node_path45 = require("node:path");
49102
+ var import_node_path46 = require("node:path");
48852
49103
  var import_node_util6 = require("node:util");
48853
49104
  init_cli_shared();
48854
49105
 
@@ -49468,25 +49719,25 @@ function expectedFromRun(run, opts) {
49468
49719
  }
49469
49720
  async function adoptExport(opts, deps) {
49470
49721
  if (!/^sha256:[0-9a-f]{64}$/.test(opts.digest)) throw new Error("--digest must be sha256:<64 hex>, from the export run summary");
49471
- const packagePath = (0, import_node_path45.join)(opts.dir, "package.json");
49472
- const lockPath = (0, import_node_path45.join)(opts.dir, "package-lock.json");
49722
+ const packagePath = (0, import_node_path46.join)(opts.dir, "package.json");
49723
+ const lockPath = (0, import_node_path46.join)(opts.dir, "package-lock.json");
49473
49724
  const packageText = (0, import_node_fs47.readFileSync)(packagePath, "utf8");
49474
49725
  const lockText = (0, import_node_fs47.readFileSync)(lockPath, "utf8");
49475
- const work = (0, import_node_fs47.mkdtempSync)((0, import_node_path45.join)((0, import_node_os22.tmpdir)(), "mmi-adopt-export-"));
49726
+ const work = (0, import_node_fs47.mkdtempSync)((0, import_node_path46.join)((0, import_node_os22.tmpdir)(), "mmi-adopt-export-"));
49476
49727
  try {
49477
49728
  const run = JSON.parse((await deps.ghApi(`repos/${EXPORT_REPO}/actions/runs/${opts.run}`)).toString("utf8"));
49478
- (0, import_node_fs47.writeFileSync)((0, import_node_path45.join)(work, "expected.json"), JSON.stringify(expectedFromRun(run, opts)));
49479
- (0, import_node_fs47.writeFileSync)((0, import_node_path45.join)(work, "provider.json"), await deps.ghApi(`repos/${EXPORT_REPO}/actions/artifacts/${opts.artifact}`));
49480
- (0, import_node_fs47.writeFileSync)((0, import_node_path45.join)(work, "artifact.zip"), await deps.ghApi(`repos/${EXPORT_REPO}/actions/artifacts/${opts.artifact}/zip`));
49481
- const script = (0, import_node_path45.join)(work, "package_export.py");
49729
+ (0, import_node_fs47.writeFileSync)((0, import_node_path46.join)(work, "expected.json"), JSON.stringify(expectedFromRun(run, opts)));
49730
+ (0, import_node_fs47.writeFileSync)((0, import_node_path46.join)(work, "provider.json"), await deps.ghApi(`repos/${EXPORT_REPO}/actions/artifacts/${opts.artifact}`));
49731
+ (0, import_node_fs47.writeFileSync)((0, import_node_path46.join)(work, "artifact.zip"), await deps.ghApi(`repos/${EXPORT_REPO}/actions/artifacts/${opts.artifact}/zip`));
49732
+ const script = (0, import_node_path46.join)(work, "package_export.py");
49482
49733
  (0, import_node_fs47.writeFileSync)(script, package_export_default);
49483
49734
  await deps.python(script, ["verify", work, opts.ds, opts.screens]);
49484
- const verified = (0, import_node_path45.join)(work, "verified");
49485
- const metadata = Object.fromEntries(PACKAGES.map(({ name, short: short3 }) => [name, JSON.parse((0, import_node_fs47.readFileSync)((0, import_node_path45.join)(verified, `${short3}.metadata.json`), "utf8"))]));
49735
+ const verified = (0, import_node_path46.join)(work, "verified");
49736
+ const metadata = Object.fromEntries(PACKAGES.map(({ name, short: short3 }) => [name, JSON.parse((0, import_node_fs47.readFileSync)((0, import_node_path46.join)(verified, `${short3}.metadata.json`), "utf8"))]));
49486
49737
  const plan = planAdoption(packageText, lockText, metadata);
49487
49738
  for (const { name } of plan.result.adopted) {
49488
49739
  const short3 = PACKAGES.find((p) => p.name === name).short;
49489
- await deps.npm(["cache", "add", (0, import_node_path45.join)(verified, `${short3}.tgz`)], opts.dir);
49740
+ await deps.npm(["cache", "add", (0, import_node_path46.join)(verified, `${short3}.tgz`)], opts.dir);
49490
49741
  }
49491
49742
  (0, import_node_fs47.writeFileSync)(packagePath, plan.packageText);
49492
49743
  (0, import_node_fs47.writeFileSync)(lockPath, plan.lockText);
@@ -49502,7 +49753,7 @@ async function adoptExport(opts, deps) {
49502
49753
  (0, import_node_fs47.rmSync)(work, { recursive: true, force: true });
49503
49754
  }
49504
49755
  }
49505
- var execFileBuffer = (0, import_node_util6.promisify)(import_node_child_process18.execFile);
49756
+ var execFileBuffer = (0, import_node_util6.promisify)(import_node_child_process19.execFile);
49506
49757
  var MAX_OUTPUT = 200 * 1024 * 1024;
49507
49758
  async function findPython() {
49508
49759
  for (const bin of ["python3", "python"]) {
@@ -49628,7 +49879,7 @@ init_github_client();
49628
49879
  init_cli_shared();
49629
49880
  var import_node_fs49 = require("node:fs");
49630
49881
  var import_node_os23 = require("node:os");
49631
- var import_node_path46 = require("node:path");
49882
+ var import_node_path47 = require("node:path");
49632
49883
  var GC_GH_TIMEOUT_MS3 = 2e4;
49633
49884
  async function collectStatus() {
49634
49885
  const repo = await resolveRepo();
@@ -49819,8 +50070,8 @@ async function collectOnboardStatus(opts = {}) {
49819
50070
  }
49820
50071
  const home = (0, import_node_os23.homedir)();
49821
50072
  const plugin = onboardPluginGate({
49822
- readKnown: () => readFileSyncSafe((0, import_node_path46.join)(home, ...KNOWN_MARKETPLACES_RELATIVE), import_node_fs49.readFileSync),
49823
- readSettings: () => readFileSyncSafe((0, import_node_path46.join)(home, ".claude", "settings.json"), import_node_fs49.readFileSync)
50073
+ readKnown: () => readFileSyncSafe((0, import_node_path47.join)(home, ...KNOWN_MARKETPLACES_RELATIVE), import_node_fs49.readFileSync),
50074
+ readSettings: () => readFileSyncSafe((0, import_node_path47.join)(home, ".claude", "settings.json"), import_node_fs49.readFileSync)
49824
50075
  });
49825
50076
  return {
49826
50077
  guide: "Read the MMI org-guide skill before project work; load only the relevant topic. Use mmi-help for a short introduction.",
@@ -52015,6 +52266,65 @@ function registerOrgHealthQuery(program3, deps = defaultOrgHealthQueryDeps()) {
52015
52266
  // src/api-read.ts
52016
52267
  var import_node_fs50 = require("node:fs");
52017
52268
 
52269
+ // src/run-log-read.ts
52270
+ init_cli_shared();
52271
+ var FAILED2 = /* @__PURE__ */ new Set(["failure", "cancelled", "timed_out"]);
52272
+ function logRepo(raw) {
52273
+ const repo = parseBrokerRepo(raw, "--repo");
52274
+ if (repo.split("/").some((s) => s === "." || s === "..")) throw new Error("read run log: --repo refuses dot segments");
52275
+ return repo;
52276
+ }
52277
+ function logJob(raw) {
52278
+ if (!raw.trim() || /[\r\n\0]/.test(raw)) throw new Error("read run log: --job must be a non-empty job name");
52279
+ return raw;
52280
+ }
52281
+ function sliceRunLog(text, tail) {
52282
+ const lines2 = text.replace(/\r\n/g, "\n").split("\n");
52283
+ if (lines2.at(-1) === "") lines2.pop();
52284
+ const context = /* @__PURE__ */ new Set();
52285
+ lines2.forEach((line, i) => {
52286
+ if (line.includes("##[error]")) for (let j = Math.max(0, i - 3); j <= Math.min(lines2.length - 1, i + 3); j++) context.add(j);
52287
+ });
52288
+ return { errorLines: lines2.filter((_, i) => context.has(i)), tail: lines2.slice(-tail) };
52289
+ }
52290
+ async function readRunLog(id, o, runner) {
52291
+ const runId = parseBrokerId(id, "run id");
52292
+ const repo = logRepo(o.repo);
52293
+ const tail = parseBrokerInt(o.tail ?? "200", "--tail", 1, 2e3);
52294
+ const attempt = o.attempt === void 0 ? void 0 : parseBrokerInt(o.attempt, "--attempt", 1, 1e3);
52295
+ const jobName = o.job === void 0 ? void 0 : logJob(o.job);
52296
+ if (o.failed && jobName !== void 0) throw new Error("read run log: --failed and --job are mutually exclusive");
52297
+ const base = `repos/${repo}/actions/runs/${runId}`;
52298
+ const pages = JSON.parse(await readAppApi(`${base}${attempt === void 0 ? "" : `/attempts/${attempt}`}/jobs`, runner));
52299
+ const jobs = pages.flatMap((page) => page.jobs);
52300
+ const selected = jobs.filter((job) => jobName === void 0 ? FAILED2.has(job.conclusion ?? "") : job.name === jobName);
52301
+ const result = { runId, repo, jobs: [] };
52302
+ if (!selected.length) return { result, exitCode: 1, message: `read run log: no matching job for run ${runId} in ${repo}; conclusions seen: ${[...new Set(jobs.map((j) => j.conclusion ?? "pending"))].join(", ") || "none"}` };
52303
+ for (const job of selected) {
52304
+ const text = await readAppApi(`repos/${repo}/actions/jobs/${parseBrokerId(String(job.id), "job id")}/logs`, runner);
52305
+ result.jobs.push({ id: job.id, name: job.name, conclusion: job.conclusion, failedStep: job.steps?.find((s) => s.conclusion === "failure")?.name ?? null, ...sliceRunLog(text, tail) });
52306
+ }
52307
+ return { result, exitCode: 0 };
52308
+ }
52309
+ function registerRunLogRead(run, runner) {
52310
+ run.command("log").description("read workflow job logs on the App pool: error lines with \xB13 context and bounded tail (#8136); defaults to failed jobs, never personal").requiredOption("--repo <owner/repo>", "target repo on github.com", logRepo).addOption(new Option("--failed", "select failure/cancelled/timed_out jobs (default)").conflicts("job")).addOption(new Option("--job <name>", "select jobs with this exact name").argParser(logJob).conflicts("failed")).option("--tail <n>", "last lines per job (1-2000; default 200)", (v) => String(parseBrokerInt(v, "--tail", 1, 2e3)), "200").option("--attempt <n>", "run attempt (1-1000; default latest)", (v) => String(parseBrokerInt(v, "--attempt", 1, 1e3))).option("--json", "emit runId, repo and jobs with failedStep/errorLines/tail").argument("<runId>", "workflow run number", (v) => parseBrokerId(v, "run id")).action(async (id, o) => {
52311
+ requireBrokerApp("read run log");
52312
+ const env = brokerChildEnv();
52313
+ try {
52314
+ const { result, message: message2, exitCode } = await readRunLog(id, o, runner);
52315
+ if (message2) printLine(message2);
52316
+ else if (o.json) printLine(redactPrivateCredential(JSON.stringify(result), env));
52317
+ else for (const job of result.jobs) {
52318
+ printLine(redactPrivateCredential(`== ${job.name} (${job.id}) ${job.conclusion}: failing step "${job.failedStep ?? "none"}"`, env));
52319
+ for (const line of [...job.errorLines, ...job.tail]) printLine(redactPrivateCredential(line, env));
52320
+ }
52321
+ process.exitCode = exitCode;
52322
+ } catch (e) {
52323
+ return fail(redactPrivateCredential(`read run log: App-pool read failed (${e.message}) \u2014 re-run the same command; never falls back to personal`, env));
52324
+ }
52325
+ });
52326
+ }
52327
+
52018
52328
  // src/app-read-broker.ts
52019
52329
  init_cli_shared();
52020
52330
  var OWNER_REPO_RE = /^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/;
@@ -52301,7 +52611,8 @@ function registerAppReadBrokerCommands(program3, resolveRepo2, overrides) {
52301
52611
  const runStatusOpt = (v) => parseBrokerRunStatus(v);
52302
52612
  const assigneeOpt = (v) => parseBrokerAssignee(v);
52303
52613
  const read = program3.command("read").description(`closed typed GitHub reads on the App pool (${BROKER_JSON_FLAGS_NOTE})`);
52304
- const run = read.command("run").description("workflow-run reads (view/list/watch) \u2014 stdout and exit codes pass gh through verbatim");
52614
+ const run = read.command("run").description("workflow-run reads (view/list/watch pass gh through; log is a bounded App REST read)");
52615
+ registerRunLogRead(run, overrides?.apiRunner);
52305
52616
  run.command("view").description("read a workflow run (attempt/exit-status/json; formatters refused)").option("--repo <owner/repo>", "target repo (defaults to the current repo)", repoOpt).option("--json [fields]", "machine-readable output (comma-separated gh fields)", jsonOpt).option("--exit-status", "exit non-zero when the run failed").option("--attempt <n>", "the attempt number of the run (1-1000)", intOpt("--attempt", 1, 1e3)).argument("<id>", "workflow run number", idOpt("run id")).action(async (id, o) => {
52306
52617
  let spec;
52307
52618
  try {
@@ -52391,11 +52702,11 @@ var CONTENTS_BASE_RE = new RegExp(`^repos/${NAME}/${NAME}/contents/${FREE}$`);
52391
52702
  var CONTENTS_QUERY_RE = /^ref=[^&\s]+$/;
52392
52703
  var ACTIONS_RUNS_RE = new RegExp(`^repos/${NAME}/${NAME}/actions/runs$`);
52393
52704
  var ACTIONS_RUN_RE = new RegExp(`^repos/${NAME}/${NAME}/actions/runs/\\d+$`);
52394
- var ACTIONS_JOBS_RE = new RegExp(`^repos/${NAME}/${NAME}/actions/runs/\\d+/jobs$`);
52705
+ var ACTIONS_JOBS_RE = new RegExp(`^repos/${NAME}/${NAME}/actions/runs/\\d+(?:/attempts/\\d+)?/jobs$`);
52395
52706
  var ACTIONS_ARTIFACTS_RE = new RegExp(`^repos/${NAME}/${NAME}/actions/runs/\\d+/artifacts$`);
52396
52707
  var ACTIONS_ARTIFACT_ZIP_RE = new RegExp(`^repos/${NAME}/${NAME}/actions/artifacts/\\d+/zip$`);
52397
52708
  var ACTIONS_JOB_LOGS_RE = new RegExp(`^repos/${NAME}/${NAME}/actions/jobs/\\d+/logs$`);
52398
- var API_GET_ALLOWED_SHAPES = "repos/{owner}/{repo}/pulls/{n}/files, repos/{owner}/{repo}/compare/{a}...{b}, repos/{owner}/{repo}/contents/{path}[?ref=<branch>], repos/{owner}/{repo}/actions/runs, repos/{owner}/{repo}/actions/runs/{id}, repos/{owner}/{repo}/actions/runs/{id}/jobs, repos/{owner}/{repo}/actions/runs/{id}/artifacts, repos/{owner}/{repo}/actions/artifacts/{id}/zip (needs --out <file>), repos/{owner}/{repo}/actions/jobs/{id}/logs (needs --out <file>)";
52709
+ var API_GET_ALLOWED_SHAPES = "repos/{owner}/{repo}/pulls/{n}/files, repos/{owner}/{repo}/compare/{a}...{b}, repos/{owner}/{repo}/contents/{path}[?ref=<branch>], repos/{owner}/{repo}/actions/runs, repos/{owner}/{repo}/actions/runs/{id}, repos/{owner}/{repo}/actions/runs/{id}/jobs, repos/{owner}/{repo}/actions/runs/{id}/attempts/{n}/jobs, repos/{owner}/{repo}/actions/runs/{id}/artifacts, repos/{owner}/{repo}/actions/artifacts/{id}/zip (needs --out <file>), repos/{owner}/{repo}/actions/jobs/{id}/logs (needs --out <file>)";
52399
52710
  function parseApiGetPath(rawPath) {
52400
52711
  const path2 = rawPath.trim();
52401
52712
  const refuse = () => new Error(`api get: refusing '${rawPath}' \u2014 only these GET reads are allowed (#7219): ${API_GET_ALLOWED_SHAPES}`);
@@ -52429,8 +52740,16 @@ function buildApiGetArgs(path2, accept) {
52429
52740
  async function runApiGet(run, path2, accept) {
52430
52741
  return run(buildApiGetArgs(path2, accept), GIT_TIMEOUT_MS);
52431
52742
  }
52743
+ var apiReadRunner = async (args, timeoutMs, env, binary) => (await execFileP("gh", args, { timeout: timeoutMs, ...binary ? { encoding: "latin1", maxBuffer: ZIP_MAX_BUFFER } : {}, ...env ? { env } : {} })).stdout;
52744
+ async function readAppApi(path2, runner = apiReadRunner) {
52745
+ const req = parseApiGetPath(path2);
52746
+ requireBrokerApp("read run log");
52747
+ const log = req.kind === "actions-job-logs";
52748
+ const body = await runApiGet((args, timeout) => runner(req.kind === "actions-jobs" ? [...args, "--slurp"] : args, log ? ZIP_TIMEOUT_MS : timeout, brokerChildEnv(), log || void 0), path2);
52749
+ return log ? Buffer.from(body, "latin1").toString("utf8") : body;
52750
+ }
52432
52751
  function registerApiReadCommands(program3, overrides) {
52433
- const spawn6 = overrides?.runner ?? (async (args, timeoutMs, env, binary) => (await execFileP("gh", args, { timeout: timeoutMs, ...binary ? { encoding: "latin1", maxBuffer: ZIP_MAX_BUFFER } : {}, ...env ? { env } : {} })).stdout);
52752
+ const spawn6 = overrides?.runner ?? apiReadRunner;
52434
52753
  const api = program3.command("api").description("bounded GitHub REST reads for automation \u2014 GET only, allowlisted paths (pull files, compare, contents, actions runs/jobs/artifacts)");
52435
52754
  api.command("get").description("GET one allowlisted REST path and print the response body to stdout (JSON, or raw file bytes with --accept raw); refuses everything outside the allowlist").option("--accept <type>", "response media type: json (default) or raw (file bytes)", (v) => {
52436
52755
  acceptHeaderFor(v);
@@ -53309,7 +53628,7 @@ function registerSessionReport(program3) {
53309
53628
 
53310
53629
  // src/stage-commands.ts
53311
53630
  var import_node_fs51 = require("node:fs");
53312
- var import_node_path47 = require("node:path");
53631
+ var import_node_path48 = require("node:path");
53313
53632
  init_cli_shared();
53314
53633
  init_clean_exit();
53315
53634
 
@@ -53557,8 +53876,8 @@ function registerStageCommands(program3) {
53557
53876
  const repo = Array.isArray(project2?.repos) && typeof project2.repos[0] === "string" ? project2.repos[0] : slug;
53558
53877
  const resolution = decideStage({
53559
53878
  registry: { deployModel: project2?.deployModel, portRange, error: read.ok ? void 0 : read.error },
53560
- hasCompose: (0, import_node_fs51.existsSync)((0, import_node_path47.join)(process.cwd(), "docker-compose.yml")),
53561
- hasEnvExample: (0, import_node_fs51.existsSync)((0, import_node_path47.join)(process.cwd(), ".env.example")),
53879
+ hasCompose: (0, import_node_fs51.existsSync)((0, import_node_path48.join)(process.cwd(), "docker-compose.yml")),
53880
+ hasEnvExample: (0, import_node_fs51.existsSync)((0, import_node_path48.join)(process.cwd(), ".env.example")),
53562
53881
  repo
53563
53882
  });
53564
53883
  if (resolution.source === "derived" && resolution.derived) {
@@ -53853,7 +54172,7 @@ vercel preview (${preview.branch}): ${d.state}${d.url ? ` \u2014 ${d.url}` : ""}
53853
54172
  var import_node_crypto17 = require("node:crypto");
53854
54173
  var import_node_fs52 = require("node:fs");
53855
54174
  var import_promises11 = require("node:fs/promises");
53856
- var import_node_path48 = require("node:path");
54175
+ var import_node_path49 = require("node:path");
53857
54176
  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}$/;
53858
54177
  var MAX_BYTES2 = 5 * 1024 * 1024 * 1024;
53859
54178
  async function sha256File(path2) {
@@ -53863,7 +54182,7 @@ async function sha256File(path2) {
53863
54182
  }
53864
54183
  async function putTenantArtifact(repo, stage, inputPath, deps) {
53865
54184
  if (!["dev", "rc", "main"].includes(stage)) throw new Error("tenant artifact put: <stage> must be dev, rc, or main");
53866
- const path2 = (0, import_node_path48.resolve)(inputPath);
54185
+ const path2 = (0, import_node_path49.resolve)(inputPath);
53867
54186
  const info = await (0, import_promises11.stat)(path2);
53868
54187
  if (!info.isFile()) throw new Error("tenant artifact put: input path must be a file");
53869
54188
  if (!Number.isSafeInteger(info.size) || info.size < 1 || info.size > MAX_BYTES2) throw new Error(`tenant artifact put: file must be 1..${MAX_BYTES2} bytes`);
@@ -54053,7 +54372,7 @@ async function resolveWhoami(deps) {
54053
54372
  }
54054
54373
 
54055
54374
  // src/command-register-developer.ts
54056
- var import_node_path53 = require("node:path");
54375
+ var import_node_path55 = require("node:path");
54057
54376
  init_house_map();
54058
54377
  init_hub_url();
54059
54378
 
@@ -54086,21 +54405,21 @@ async function executeWaveLand(plan, deps) {
54086
54405
  }
54087
54406
 
54088
54407
  // src/dist-drift.ts
54089
- var import_node_child_process19 = require("node:child_process");
54408
+ var import_node_child_process20 = require("node:child_process");
54090
54409
  var import_node_crypto19 = require("node:crypto");
54091
54410
  var import_node_fs54 = require("node:fs");
54092
54411
  var import_node_os24 = require("node:os");
54093
- var import_node_path50 = require("node:path");
54412
+ var import_node_path51 = require("node:path");
54094
54413
 
54095
54414
  // ../scripts/distribution-digest.mjs
54096
54415
  var import_node_crypto18 = require("node:crypto");
54097
54416
  var import_node_fs53 = require("node:fs");
54098
- var import_node_path49 = require("node:path");
54417
+ var import_node_path50 = require("node:path");
54099
54418
  var slash = (value) => value.replaceAll("\\", "/");
54100
54419
  function repoPath(root, declaredPath, label) {
54101
- const absoluteRoot = (0, import_node_path49.resolve)(root);
54102
- const target = (0, import_node_path49.resolve)(root, declaredPath);
54103
- if (target !== absoluteRoot && !target.startsWith(`${absoluteRoot}${import_node_path49.sep}`)) {
54420
+ const absoluteRoot = (0, import_node_path50.resolve)(root);
54421
+ const target = (0, import_node_path50.resolve)(root, declaredPath);
54422
+ if (target !== absoluteRoot && !target.startsWith(`${absoluteRoot}${import_node_path50.sep}`)) {
54104
54423
  throw new Error(`${label} ${declaredPath} escapes the repository root`);
54105
54424
  }
54106
54425
  return target;
@@ -54132,6 +54451,7 @@ function digestPackedFiles(packageRoot, packedFiles) {
54132
54451
  var DIST_ARTIFACTS = [
54133
54452
  { path: "cli/dist/index.cjs", packageDir: "cli", output: "index.cjs" },
54134
54453
  { path: "cli/dist/main.cjs", packageDir: "cli", output: "main.cjs" },
54454
+ { path: "cli/dist/runbook-sweep.cjs", packageDir: "cli", output: "runbook-sweep.cjs" },
54135
54455
  { path: "updater/dist/index.cjs", packageDir: "updater", output: "index.cjs" }
54136
54456
  ];
54137
54457
  var BOM_DIST_TREE_ID = "mmi-cli-dist";
@@ -54214,7 +54534,7 @@ function walkFiles(root) {
54214
54534
  const files = [];
54215
54535
  const walk2 = (directory) => {
54216
54536
  for (const entry of (0, import_node_fs54.readdirSync)(directory, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
54217
- const child2 = (0, import_node_path50.join)(directory, entry.name);
54537
+ const child2 = (0, import_node_path51.join)(directory, entry.name);
54218
54538
  if (entry.isDirectory()) walk2(child2);
54219
54539
  else files.push(child2);
54220
54540
  }
@@ -54224,14 +54544,14 @@ function walkFiles(root) {
54224
54544
  }
54225
54545
  function bomPathFor(root) {
54226
54546
  try {
54227
- const registry2 = JSON.parse((0, import_node_fs54.readFileSync)((0, import_node_path50.join)(root, "surfaces.json"), "utf8"));
54228
- return (0, import_node_path50.join)(root, registry2?.sharedAgentCore?.releaseMetadata?.bomPath ?? "distribution-bom.json");
54547
+ const registry2 = JSON.parse((0, import_node_fs54.readFileSync)((0, import_node_path51.join)(root, "surfaces.json"), "utf8"));
54548
+ return (0, import_node_path51.join)(root, registry2?.sharedAgentCore?.releaseMetadata?.bomPath ?? "distribution-bom.json");
54229
54549
  } catch {
54230
- return (0, import_node_path50.join)(root, "distribution-bom.json");
54550
+ return (0, import_node_path51.join)(root, "distribution-bom.json");
54231
54551
  }
54232
54552
  }
54233
54553
  function rebuildTo(packageRoot, outDir) {
54234
- (0, import_node_child_process19.execFileSync)(process.execPath, ["build.mjs"], {
54554
+ (0, import_node_child_process20.execFileSync)(process.execPath, ["build.mjs"], {
54235
54555
  cwd: packageRoot,
54236
54556
  env: { ...process.env, MMI_DIST_OUTDIR: outDir },
54237
54557
  windowsHide: true,
@@ -54240,28 +54560,28 @@ function rebuildTo(packageRoot, outDir) {
54240
54560
  });
54241
54561
  }
54242
54562
  function runDistStatus(root) {
54243
- const stage = (0, import_node_fs54.mkdtempSync)((0, import_node_path50.join)((0, import_node_os24.tmpdir)(), "mmi-dist-drift-"));
54563
+ const stage = (0, import_node_fs54.mkdtempSync)((0, import_node_path51.join)((0, import_node_os24.tmpdir)(), "mmi-dist-drift-"));
54244
54564
  let overlayCount = 0;
54245
54565
  try {
54246
- const cliOut = (0, import_node_path50.join)(stage, "cli-dist");
54247
- const hubOut = (0, import_node_path50.join)(stage, "hub-dist");
54248
- rebuildTo((0, import_node_path50.join)(root, "cli"), cliOut);
54249
- rebuildTo((0, import_node_path50.join)(root, "updater"), hubOut);
54566
+ const cliOut = (0, import_node_path51.join)(stage, "cli-dist");
54567
+ const hubOut = (0, import_node_path51.join)(stage, "hub-dist");
54568
+ rebuildTo((0, import_node_path51.join)(root, "cli"), cliOut);
54569
+ rebuildTo((0, import_node_path51.join)(root, "updater"), hubOut);
54250
54570
  const outDirFor = (packageDir) => packageDir === "cli" ? cliOut : hubOut;
54251
54571
  const rebuilt = (path2) => {
54252
54572
  const spec = DIST_ARTIFACTS.find((entry) => entry.path === path2);
54253
- return spec ? readOrNull((0, import_node_path50.join)(outDirFor(spec.packageDir), spec.output)) : null;
54573
+ return spec ? readOrNull((0, import_node_path51.join)(outDirFor(spec.packageDir), spec.output)) : null;
54254
54574
  };
54255
- const committed = (path2) => readOrNull((0, import_node_path50.join)(root, path2));
54256
- const tree = (path2) => readOrNull((0, import_node_path50.join)(root, path2));
54257
- const distRoot = (0, import_node_path50.join)(root, "cli", "dist");
54258
- const distTree = () => walkFiles(distRoot).map((absolute) => `cli/dist/${(0, import_node_path50.relative)(distRoot, absolute).replaceAll("\\", "/")}`);
54575
+ const committed = (path2) => readOrNull((0, import_node_path51.join)(root, path2));
54576
+ const tree = (path2) => readOrNull((0, import_node_path51.join)(root, path2));
54577
+ const distRoot = (0, import_node_path51.join)(root, "cli", "dist");
54578
+ const distTree = () => walkFiles(distRoot).map((absolute) => `cli/dist/${(0, import_node_path51.relative)(distRoot, absolute).replaceAll("\\", "/")}`);
54259
54579
  const bom = JSON.parse((0, import_node_fs54.readFileSync)(bomPathFor(root), "utf8"));
54260
54580
  const digest = (entries) => {
54261
- const overlay = (0, import_node_path50.join)(stage, `overlay-${overlayCount++}`);
54581
+ const overlay = (0, import_node_path51.join)(stage, `overlay-${overlayCount++}`);
54262
54582
  for (const entry of entries) {
54263
- const target = (0, import_node_path50.join)(overlay, entry.path);
54264
- (0, import_node_fs54.mkdirSync)((0, import_node_path50.dirname)(target), { recursive: true });
54583
+ const target = (0, import_node_path51.join)(overlay, entry.path);
54584
+ (0, import_node_fs54.mkdirSync)((0, import_node_path51.dirname)(target), { recursive: true });
54265
54585
  (0, import_node_fs54.writeFileSync)(target, entry.bytes);
54266
54586
  }
54267
54587
  return digestPackedFiles(overlay, entries.map((entry) => entry.path));
@@ -54272,6 +54592,123 @@ function runDistStatus(root) {
54272
54592
  }
54273
54593
  }
54274
54594
 
54595
+ // src/doc-refs-live.ts
54596
+ var import_node_path52 = require("node:path");
54597
+ var concrete = (value) => !!value && !/[<>{}$]/.test(value);
54598
+ var liveOption = (tokens2, flag) => {
54599
+ const index = tokens2.indexOf(flag);
54600
+ return index >= 0 ? tokens2[index + 1] : tokens2.find((token) => token.startsWith(`${flag}=`))?.slice(flag.length + 1);
54601
+ };
54602
+ async function checkRunbookLive(docs, deps) {
54603
+ const findings = [];
54604
+ const warnings = [];
54605
+ const cache = /* @__PURE__ */ new Map();
54606
+ const names = (type, scope) => {
54607
+ const key = `${type}:${scope}`;
54608
+ if (!cache.has(key)) cache.set(key, Promise.resolve().then(() => deps[type](scope)));
54609
+ return cache.get(key);
54610
+ };
54611
+ for (const [doc, body] of Object.entries(docs)) {
54612
+ if (!isRunbook(doc, body)) continue;
54613
+ for (const { tokens: raw, line } of shellClaims(body)) {
54614
+ if (raw[0] !== "mmi-cli") continue;
54615
+ const end = raw.indexOf("--");
54616
+ const tokens2 = end < 0 ? raw : raw.slice(0, end);
54617
+ const task = liveOption(tokens2, "--task");
54618
+ const repo = liveOption(tokens2, "--repo") ?? tokens2.find((token) => /^[\w.-]+\/[\w.-]+$/.test(token));
54619
+ const key = liveOption(tokens2, "--key");
54620
+ const scope = liveOption(tokens2, "--repo") ?? (liveOption(tokens2, "--slug") === "_org" ? "_org" : void 0);
54621
+ const checks = [];
54622
+ if (tokens2.includes("run-task") && concrete(repo) && concrete(task)) checks.push({ type: "tasks", scope: repo, name: task, kind: "unknown-task" });
54623
+ if (tokens2[1] === "vault" && tokens2[2] === "secrets" && ["use", "set", "rm"].includes(tokens2[3]) && concrete(scope) && concrete(key)) checks.push({ type: "vaultKeys", scope, name: key, kind: "unknown-vault-key" });
54624
+ for (const check of checks) {
54625
+ const detail = `${check.scope}: ${check.name}`;
54626
+ try {
54627
+ if (!(await names(check.type, check.scope)).has(check.name)) findings.push({ kind: check.kind, doc, line, detail });
54628
+ } catch {
54629
+ warnings.push({ kind: "live-unverified", doc, line, detail: `${check.type} ${check.scope}: remote names unreadable (auth/transport or unsupported scope)` });
54630
+ }
54631
+ }
54632
+ }
54633
+ let fence = "";
54634
+ const seen = /* @__PURE__ */ new Set();
54635
+ for (const [index, text] of body.split(/\r?\n/).entries()) {
54636
+ const marker = /^\s*(`{3,}|~{3,})(.*)$/.exec(text);
54637
+ if (marker) {
54638
+ if (!fence) fence = marker[1];
54639
+ else if (marker[1][0] === fence[0] && marker[1].length >= fence.length && !marker[2].trim()) fence = "";
54640
+ continue;
54641
+ }
54642
+ const spans = fence ? [text] : [...text.matchAll(/`([^`]+)`/g)].map((match) => match[1]);
54643
+ for (const span of spans) for (const match of span.matchAll(/https:\/\/[^\s`"']+/g)) {
54644
+ const url = match[0].replace(/[),.;]+$/, "");
54645
+ if (!concrete(url) || seen.has(url)) continue;
54646
+ let host;
54647
+ try {
54648
+ host = new URL(url).hostname;
54649
+ } catch {
54650
+ continue;
54651
+ }
54652
+ if (/(^|\.)example\./i.test(host)) continue;
54653
+ seen.add(url);
54654
+ try {
54655
+ const status = await deps.endpoint(url);
54656
+ if (status >= 500) findings.push({ kind: "endpoint-down", doc, line: index + 1, detail: `${url}: HTTP ${status}` });
54657
+ } catch {
54658
+ findings.push({ kind: "endpoint-down", doc, line: index + 1, detail: `${url}: network error or 10s timeout` });
54659
+ }
54660
+ }
54661
+ }
54662
+ }
54663
+ return { findings, warnings };
54664
+ }
54665
+ async function runLiveDocRefs(root, deps, live) {
54666
+ const offline = runDocRefs(root, { ...deps, runbooksOnly: true });
54667
+ const read = deps.readFile ?? readFileOrNull;
54668
+ const docs = Object.fromEntries((deps.listDocs ?? defaultListDocs)(root).flatMap((doc) => {
54669
+ const body = read((0, import_node_path52.join)(root, doc));
54670
+ return body !== null && isRunbook(doc, body) && !deps.isIgnored?.([doc]).has(doc) ? [[doc, body]] : [];
54671
+ }));
54672
+ const remote = await checkRunbookLive(docs, live);
54673
+ const findings = [...offline.findings, ...remote.findings];
54674
+ return { ...offline, findings, warnings: [...offline.warnings, ...remote.warnings], ok: findings.length === 0 };
54675
+ }
54676
+
54677
+ // src/doc-refs-live-io.ts
54678
+ var import_node_child_process21 = require("node:child_process");
54679
+ var import_node_util7 = require("node:util");
54680
+ var exec2 = (0, import_node_util7.promisify)(import_node_child_process21.execFile);
54681
+ function createRunbookLiveDeps(cliBin) {
54682
+ const json = async (args) => {
54683
+ const { stdout } = await exec2(process.execPath, [cliBin, ...args, "--json"], { windowsHide: true, timeout: 3e4, maxBuffer: 4 * 1024 * 1024 });
54684
+ return JSON.parse(stdout);
54685
+ };
54686
+ return {
54687
+ tasks: async (repo) => {
54688
+ const project2 = await json(["oracle", "org", "project", "get", repo]);
54689
+ if (!project2 || typeof project2 !== "object" || Array.isArray(project2)) throw new Error("unreadable META");
54690
+ return new Set(Object.keys(project2.tenantTasks ?? {}));
54691
+ },
54692
+ vaultKeys: async (scope) => {
54693
+ if (scope === "_org") throw new Error("org names listing unsupported");
54694
+ const result = await json(["vault", "secrets", "list", "--repo", scope]);
54695
+ if (!Array.isArray(result?.secrets) || result.secrets.some((item) => typeof item.key !== "string")) throw new Error("unreadable names");
54696
+ return new Set(result.secrets.map((item) => item.key));
54697
+ },
54698
+ endpoint: async (url) => {
54699
+ const probe = async () => {
54700
+ const response = await fetch(url, { method: "GET", signal: AbortSignal.timeout(1e4) });
54701
+ await response.body?.cancel();
54702
+ return response.status;
54703
+ };
54704
+ const first = await probe().catch(() => 599);
54705
+ if (first < 500) return first;
54706
+ await new Promise((resolve8) => setTimeout(resolve8, 2e4));
54707
+ return probe();
54708
+ }
54709
+ };
54710
+ }
54711
+
54275
54712
  // src/edge-commands.ts
54276
54713
  init_cli_shared();
54277
54714
 
@@ -54369,7 +54806,7 @@ init_hub_auth();
54369
54806
 
54370
54807
  // src/schedules-lift-command.ts
54371
54808
  var import_promises12 = require("node:fs/promises");
54372
- var import_node_path51 = require("node:path");
54809
+ var import_node_path53 = require("node:path");
54373
54810
  init_clean_exit();
54374
54811
  init_cli_shared();
54375
54812
  var DEFAULT_WORKFLOWS_DIR = ".github/workflows";
@@ -54398,7 +54835,7 @@ async function readWorkflowFiles(dir) {
54398
54835
  const files = [];
54399
54836
  for (const name of names.sort()) {
54400
54837
  if (!/\.ya?ml$/.test(name)) continue;
54401
- files.push({ path: `.github/workflows/${name}`, text: await (0, import_promises12.readFile)((0, import_node_path51.join)(dir, name), "utf8") });
54838
+ files.push({ path: `.github/workflows/${name}`, text: await (0, import_promises12.readFile)((0, import_node_path53.join)(dir, name), "utf8") });
54402
54839
  }
54403
54840
  return files;
54404
54841
  }
@@ -54480,9 +54917,9 @@ function registerSchedulesLiftCommand(program3, deps = {}) {
54480
54917
  }
54481
54918
 
54482
54919
  // src/spawn-policy-core.ts
54483
- var import_node_child_process20 = require("node:child_process");
54920
+ var import_node_child_process22 = require("node:child_process");
54484
54921
  var import_node_fs55 = require("node:fs");
54485
- var import_node_path52 = require("node:path");
54922
+ var import_node_path54 = require("node:path");
54486
54923
  var SPAWNERS = ["spawn", "spawnSync", "exec", "execSync", "execFile", "execFileSync"];
54487
54924
  var CALL_SOURCE = String.raw`(^|[^.\w$])(${SPAWNERS.join("|")})\s*\(`;
54488
54925
  var SOURCE_EXT = /\.(ts|mts|cts|js|mjs|cjs)$/;
@@ -54551,7 +54988,7 @@ function findViolationsInSource(raw) {
54551
54988
  return found;
54552
54989
  }
54553
54990
  function policedFiles(root) {
54554
- const r = (0, import_node_child_process20.spawnSync)("git", ["ls-files", "-z", "--cached", "--others", "--exclude-standard"], {
54991
+ const r = (0, import_node_child_process22.spawnSync)("git", ["ls-files", "-z", "--cached", "--others", "--exclude-standard"], {
54555
54992
  cwd: root,
54556
54993
  encoding: "utf8",
54557
54994
  windowsHide: true,
@@ -54568,7 +55005,7 @@ function runSpawnPolicy(root) {
54568
55005
  for (const file of files) {
54569
55006
  let raw;
54570
55007
  try {
54571
- raw = (0, import_node_fs55.readFileSync)((0, import_node_path52.join)(root, file), "utf8");
55008
+ raw = (0, import_node_fs55.readFileSync)((0, import_node_path54.join)(root, file), "utf8");
54572
55009
  } catch {
54573
55010
  continue;
54574
55011
  }
@@ -54588,7 +55025,7 @@ function runSpawnPolicy(root) {
54588
55025
  function registerDeveloperCommands(program3) {
54589
55026
  const rules = program3.command("rules").description("org-managed .gitignore delivery");
54590
55027
  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) => {
54591
- const path2 = (0, import_node_path53.join)(process.cwd(), ".gitignore");
55028
+ const path2 = (0, import_node_path55.join)(process.cwd(), ".gitignore");
54592
55029
  const current = (0, import_node_fs56.existsSync)(path2) ? (0, import_node_fs56.readFileSync)(path2, "utf8") : null;
54593
55030
  const plan = planManagedGitignore(current);
54594
55031
  const drift = [...plan.added.map((l) => `+${l}`), ...plan.removed.map((l) => `-${l}`)].join(", ") || "block normalize";
@@ -54734,17 +55171,23 @@ function registerDeveloperCommands(program3) {
54734
55171
  await failGraceful(e.message);
54735
55172
  }
54736
55173
  });
54737
- docs.command("refs").description("deterministic doc reference gate: repo paths, markdown links, mmi-cli command refs, and pins across docs, org-guide, mmi-help, README and architecture must resolve, or exit 1").option("--json", "machine-readable findings list: { ok, docCount, findings[], warnings[] }").addOption(new Option("--repo <owner/repo>", "not accepted \u2014 docs refs reads the current checkout").hideHelp()).action(async (o) => {
55174
+ docs.command("refs").description("deterministic doc reference gate: repo paths, markdown links, mmi-cli command refs, and pins across docs, org-guide, mmi-help, README and architecture must resolve, or exit 1").option("--json", "machine-readable findings list: { ok, docCount, findings[], warnings[] }").addOption(new Option("--repo <owner/repo>", "not accepted \u2014 docs refs reads the current checkout").hideHelp()).option("--base <ref>", "require covered runbook sections to be touched against this merge base (#8126)").option("--runbooks-only", "check only operator runbooks (#8126)").option("--live", "check operator runbooks against registry tasks, vault names and HTTPS endpoints (implies --runbooks-only)").action(async (o) => {
54738
55175
  try {
54739
55176
  if (o.repo) {
54740
55177
  const guard = planTrainApplyRepoGuard(o.repo, await resolveRepo(), `mmi-cli oracle docs refs${o.json ? " --json" : ""}`, "docs refs");
54741
55178
  if (!guard.ok) return failGraceful(guard.message);
54742
55179
  }
54743
55180
  const root = await repoRoot();
54744
- const commandPaths = new Set(
54745
- buildCommandManifest(program3).index.map((entry) => entry.path)
54746
- );
54747
- const result = runDocRefs(root, { commandPaths });
55181
+ const manifest = buildCommandManifest(program3);
55182
+ const commandPaths = new Set(manifest.index.map((entry) => entry.path));
55183
+ const commandOptions = /* @__PURE__ */ new Map();
55184
+ const collect = (entry) => {
55185
+ commandOptions.set(entry.path, new Set(entry.options.flatMap((option) => option.flags.match(/--[\w-]+/g) ?? [])));
55186
+ entry.subcommands.forEach(collect);
55187
+ };
55188
+ collect(manifest.tree);
55189
+ const deps = { commandPaths, commandOptions, base: o.base, runbooksOnly: o.runbooksOnly };
55190
+ const result = o.live ? await runLiveDocRefs(root, deps, createRunbookLiveDeps(process.argv[1])) : runDocRefs(root, deps);
54748
55191
  if (o.json) {
54749
55192
  consoleIo.log(JSON.stringify({ ok: result.ok, docCount: result.docCount, findings: result.findings, warnings: result.warnings }, null, 2));
54750
55193
  if (!result.ok) process.exitCode = 1;
@@ -54863,7 +55306,7 @@ ${r.stderr ?? ""}`).catch(() => "");
54863
55306
  var ENV_HEAL_LOCK_STALE_MS = 10 * 6e4;
54864
55307
  var ENV_HEAL_LOCK_MAX_WAIT_MS = 2 * 6e4;
54865
55308
  function envHealLockPath(home) {
54866
- return (0, import_node_path54.join)(home, ".claude", "plugins", ".mmi-env-heal.lock");
55309
+ return (0, import_node_path56.join)(home, ".claude", "plugins", ".mmi-env-heal.lock");
54867
55310
  }
54868
55311
  async function withEnvHealLock(what, run) {
54869
55312
  try {
@@ -55035,7 +55478,7 @@ function mmiDoctorDeps(opts = {}) {
55035
55478
  // has no generated routing index would
55036
55479
  // get a permanent — demanding an artifact it never asked for.
55037
55480
  docsIndexState: (root) => {
55038
- if (!(0, import_node_fs57.existsSync)((0, import_node_path54.join)(root, DOCS_INDEX_PATH))) return void 0;
55481
+ if (!(0, import_node_fs57.existsSync)((0, import_node_path56.join)(root, DOCS_INDEX_PATH))) return void 0;
55039
55482
  const real = createDocsIndexDeps(root);
55040
55483
  let docs;
55041
55484
  const listDocs = () => docs ??= real.listDocs();
@@ -55044,7 +55487,7 @@ function mmiDoctorDeps(opts = {}) {
55044
55487
  },
55045
55488
  // #4168: working-tree heal — write if drifted, then re-check. Commit remains the operator's step.
55046
55489
  healDocsIndex: (root) => {
55047
- if (!(0, import_node_fs57.existsSync)((0, import_node_path54.join)(root, DOCS_INDEX_PATH))) return { drift: false, docCount: 0 };
55490
+ if (!(0, import_node_fs57.existsSync)((0, import_node_path56.join)(root, DOCS_INDEX_PATH))) return { drift: false, docCount: 0 };
55048
55491
  const real = createDocsIndexDeps(root);
55049
55492
  let docs;
55050
55493
  const listDocs = () => docs ??= real.listDocs();
@@ -55065,8 +55508,8 @@ function mmiDoctorDeps(opts = {}) {
55065
55508
  });
55066
55509
  const raced = await Promise.race([
55067
55510
  work.then((r) => ({ ...r, timedOut: false })),
55068
- new Promise((resolve7) => {
55069
- ceiling = setTimeout(() => resolve7({ timedOut: true, scanned: 0, findings: 0, fixed: 0, failed: 0 }), BOARD_DOCTOR_TIMEOUT_MS);
55511
+ new Promise((resolve8) => {
55512
+ ceiling = setTimeout(() => resolve8({ timedOut: true, scanned: 0, findings: 0, fixed: 0, failed: 0 }), BOARD_DOCTOR_TIMEOUT_MS);
55070
55513
  })
55071
55514
  ]);
55072
55515
  if (raced.timedOut) return { scanned: 0, findings: 0, fixed: 0, failed: 0, timedOut: true };
@@ -55099,8 +55542,8 @@ function mmiDoctorDeps(opts = {}) {
55099
55542
  incomplete: nb.incomplete,
55100
55543
  timedOut: false
55101
55544
  })),
55102
- new Promise((resolve7) => {
55103
- ceiling = setTimeout(() => resolve7({ driftLines: [], incomplete: [], timedOut: true }), SCHEDULES_DRIFT_TIMEOUT_MS);
55545
+ new Promise((resolve8) => {
55546
+ ceiling = setTimeout(() => resolve8({ driftLines: [], incomplete: [], timedOut: true }), SCHEDULES_DRIFT_TIMEOUT_MS);
55104
55547
  })
55105
55548
  ]);
55106
55549
  if (!raced.timedOut && raced.incomplete.length === 0) writeSchedulesDriftCache(cachePath, raced.driftLines);
@@ -56152,16 +56595,16 @@ function ciAuditDeps2() {
56152
56595
  // gate re-seed step is skipped gracefully rather than failing mid-run.
56153
56596
  readSeedFile: (path2) => {
56154
56597
  if (!root) return null;
56155
- const fullPath = (0, import_node_path54.join)(root, path2);
56598
+ const fullPath = (0, import_node_path56.join)(root, path2);
56156
56599
  return (0, import_node_fs57.existsSync)(fullPath) ? (0, import_node_fs57.readFileSync)(fullPath, "utf8") : null;
56157
56600
  }
56158
56601
  };
56159
56602
  }
56160
56603
  function hubRoot2() {
56161
- const fromPkg = (0, import_node_path54.join)(__dirname, "..", "..");
56604
+ const fromPkg = (0, import_node_path56.join)(__dirname, "..", "..");
56162
56605
  const marker = "skills/bootstrap/seeds/manifest.json";
56163
- if ((0, import_node_fs57.existsSync)((0, import_node_path54.join)(fromPkg, marker))) return fromPkg;
56164
- if ((0, import_node_fs57.existsSync)((0, import_node_path54.join)(process.cwd(), marker))) return process.cwd();
56606
+ if ((0, import_node_fs57.existsSync)((0, import_node_path56.join)(fromPkg, marker))) return fromPkg;
56607
+ if ((0, import_node_fs57.existsSync)((0, import_node_path56.join)(process.cwd(), marker))) return process.cwd();
56165
56608
  return null;
56166
56609
  }
56167
56610
  registerQueryCommands(program2);
@@ -56330,7 +56773,7 @@ function directoryBytes(path2) {
56330
56773
  return 0;
56331
56774
  }
56332
56775
  for (const entry of entries) {
56333
- const child2 = (0, import_node_path54.join)(path2, entry.name);
56776
+ const child2 = (0, import_node_path56.join)(path2, entry.name);
56334
56777
  if (entry.isDirectory()) total += directoryBytes(child2);
56335
56778
  else {
56336
56779
  try {
@@ -56360,7 +56803,7 @@ function pluginCacheFsDeps(configRoot, dirBytes) {
56360
56803
  dirBytes,
56361
56804
  listStagingDirs: (root) => (0, import_node_fs57.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => {
56362
56805
  try {
56363
- return { name: d.name, mtimeMs: newestMtimeMs((0, import_node_path54.join)(root, d.name), listDirEntries, (p) => (0, import_node_fs57.statSync)(p).mtimeMs) };
56806
+ return { name: d.name, mtimeMs: newestMtimeMs((0, import_node_path56.join)(root, d.name), listDirEntries, (p) => (0, import_node_fs57.statSync)(p).mtimeMs) };
56364
56807
  } catch {
56365
56808
  return { name: d.name, mtimeMs: Date.now() };
56366
56809
  }
@@ -56374,7 +56817,7 @@ function stagingApplyFsGuard(configRoot) {
56374
56817
  return {
56375
56818
  referencedPaths: () => readInstalledPluginRefs(configRoot),
56376
56819
  mtimeMs: (name) => {
56377
- const p = (0, import_node_path54.join)(stagingRoot, name);
56820
+ const p = (0, import_node_path56.join)(stagingRoot, name);
56378
56821
  if (!(0, import_node_fs57.existsSync)(p)) return null;
56379
56822
  try {
56380
56823
  return newestMtimeMs(p, listDirEntries, (q) => (0, import_node_fs57.statSync)(q).mtimeMs);