@mutmutco/codex-plugin 4.5.93 → 4.5.95

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mmi",
3
- "version": "4.5.93",
3
+ "version": "4.5.95",
4
4
  "mmiCompat": "4.x",
5
5
  "description": "MMI workflow skills and org gates delivery.",
6
6
  "author": {
package/cli/dist/main.cjs CHANGED
@@ -6347,6 +6347,9 @@ async function pollRestPrChecks(prNumber, repo, gh2 = defaultGhApi, requiredCont
6347
6347
  const { relevant } = partitionByRequired(entries, requiredContexts);
6348
6348
  return derivePollState(relevant);
6349
6349
  }
6350
+ async function pollRestCommitChecks(sha, repo, gh2 = defaultGhApi) {
6351
+ return derivePollState(partitionByRequired(await fetchHeadCheckEntries(sha, repo, gh2), null).relevant);
6352
+ }
6350
6353
  async function pollRestPrMergeable(prNumber, repo, gh2 = defaultGhApi) {
6351
6354
  try {
6352
6355
  return (await fetchRestPrSnapshot(prNumber, repo, gh2)).mergeable;
@@ -17252,10 +17255,10 @@ var rollout_plan_default = {
17252
17255
  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)."
17253
17256
  },
17254
17257
  baseline: {
17255
- version: "4.5.93",
17256
- tag: "v4.5.93",
17257
- commit: "f0c54c59980d",
17258
- npm: "@mutmutco/cli@4.5.93"
17258
+ version: "4.5.95",
17259
+ tag: "v4.5.95",
17260
+ commit: "d6d4a135bce9",
17261
+ npm: "@mutmutco/cli@4.5.95"
17259
17262
  },
17260
17263
  exitCriterion: "fleet-n-of-n",
17261
17264
  hubOnlyShortcut: "forbidden",
@@ -17272,14 +17275,14 @@ var rollout_plan_default = {
17272
17275
  repo: "mutmutco/mmi-hub",
17273
17276
  role: "canary",
17274
17277
  schedule: "train",
17275
- v3Target: "v4.5.93"
17278
+ v3Target: "v4.5.95"
17276
17279
  }
17277
17280
  ],
17278
17281
  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.",
17279
17282
  rollback: {
17280
17283
  independent: true,
17281
- mechanism: "npm dist-tag latest -> 4.5.93 and redeploy the Hub Lambda from tag v4.5.93 (f0c54c59980d); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
17282
- v3Target: "v4.5.93 (@mutmutco/cli@4.5.93, tag commit f0c54c59980d \u2014 last known-good release carrying the repo-index v4-only contract)"
17284
+ mechanism: "npm dist-tag latest -> 4.5.95 and redeploy the Hub Lambda from tag v4.5.95 (d6d4a135bce9); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
17285
+ v3Target: "v4.5.95 (@mutmutco/cli@4.5.95, tag commit d6d4a135bce9 \u2014 last known-good release carrying the repo-index v4-only contract)"
17283
17286
  }
17284
17287
  },
17285
17288
  {
@@ -36124,6 +36127,21 @@ async function suiteMarkAbandoned(deps, ownerGo = false) {
36124
36127
  for (const t of tags) await deps.markAbandoned(t.repo, t.tag, t.sha);
36125
36128
  return tags.map((t) => `${t.repo}@${t.tag}`);
36126
36129
  }
36130
+ async function retireFailedLeadRcLedger(deps, ownerGo) {
36131
+ if (!(0, import_node_fs29.existsSync)(deps.ledgerPath)) return void 0;
36132
+ return withLedgerLock(deps.ledgerPath, async (fence) => {
36133
+ const ledger = parseReleaseLedger((0, import_node_fs29.readFileSync)(deps.ledgerPath, "utf8"));
36134
+ const states = Object.values(ledger.phases).map((p) => p.state);
36135
+ if (ledger.repo !== SUITE_REPO || ledger.lane !== "rcand" || ledger.phases.promotion.state === "complete" || !states.includes("failed")) return void 0;
36136
+ if (!ownerGo) throw new Error(`the lead's failed rcand ledger for ${ledger.tag} blocks every train; retire it with suite abandon --owner-go`);
36137
+ if ((await deps.rcHead())?.toLowerCase() === ledger.tagSha.toLowerCase()) throw new Error(`origin rc already points at ${ledger.tag}; it was promoted, so its ledger is not retired`);
36138
+ const archive = (0, import_node_path29.join)((0, import_node_path29.dirname)(deps.ledgerPath), `phases.archive-${ledger.tag}.json`);
36139
+ if ((0, import_node_fs29.existsSync)(archive)) throw new Error(`ledger archive already exists at ${archive}; inspect before retiring again`);
36140
+ await deps.markAbandoned(SUITE_REPO, ledger.tag, ledger.tagSha);
36141
+ await fence(() => (0, import_node_fs29.renameSync)(deps.ledgerPath, archive));
36142
+ return `${ledger.tag} (ledger archived to ${archive})`;
36143
+ });
36144
+ }
36127
36145
  function suiteAbandon(recordPath, ownerGo = false, now = /* @__PURE__ */ new Date()) {
36128
36146
  const record = abandonableCut(recordPath, ownerGo);
36129
36147
  const archive = `${recordPath}.abandoned-${record.leadDevelopment.slice(0, 12)}-${now.toISOString().replace(/[:.]/g, "")}.json`;
@@ -45202,6 +45220,30 @@ ${list}`);
45202
45220
  if (wait.checksUrl) lines2.push(`${context}: PR checks: ${wait.checksUrl}`);
45203
45221
  return lines2;
45204
45222
  }
45223
+ function printChecksWaitResult(label, result, json) {
45224
+ if (json) printLine(JSON.stringify(result));
45225
+ else if (result.status === "conflicting") {
45226
+ printLine(`${label}: conflicting \u2014 ${result.reason}`);
45227
+ } else if (result.status === "timeout") {
45228
+ const stuckQueuing = /no-checks-reported/i.test(result.detail ?? "");
45229
+ printLine(
45230
+ `${label}: timeout \u2014 waited ${Math.round((result.waitedMs ?? 0) / 6e4)}m, last state: ${result.detail ?? "pending"}. No check failed; re-run to keep waiting, or pass --timeout <minutes>.` + (stuckQueuing ? " Tip: check-runs never appeared \u2014 if `gh api repos/<owner>/<repo>/actions/runs?head_sha=<sha>` shows total_count=0, see docs/Guides/gh-runner-runbook.md \xA7 Zero workflow runs; otherwise mmi-live may be saturated or Actions may be failing before checkout (docs/Guides/gh-runner-runbook.md)." : "")
45231
+ );
45232
+ } else if (result.status === "rate-limited") {
45233
+ printLine(`${label}: rate-limited \u2014 ${result.reason ?? "REST pool below floor"}. No check failed; re-run after the pool resets.`);
45234
+ } else if (result.detail === "runner-infra") {
45235
+ printLine(`${label}: failure (runner infrastructure, NOT a test failure) \u2014 ${result.reason}`);
45236
+ } else if (result.detail === "stale-head") {
45237
+ printLine(`${label}: failure (stale PR head, NOT a test failure) \u2014 ${result.reason}`);
45238
+ } else if (result.detail === "zero-runs") {
45239
+ printLine(`${label}: failure (zero workflow runs delivered, NOT pending checks) \u2014 ${result.reason}`);
45240
+ } else {
45241
+ printLine(`${label}: ${result.status}${result.reason ? ` \u2014 ${result.reason}` : ""}${result.detail ? ` (${result.detail})` : ""}`);
45242
+ for (const line of failedChecksReceiptLines(label, result)) printLine(line);
45243
+ }
45244
+ if (result.status === "failure" || result.status === "conflicting") process.exitCode = 1;
45245
+ if (result.status === "timeout" || result.status === "rate-limited") process.exitCode = PR_CHECKS_TIMEOUT_EXIT_CODE;
45246
+ }
45205
45247
  async function waitLoopHeadWorkflowRunCount(label, prNumber, repo) {
45206
45248
  let snapshot;
45207
45249
  try {
@@ -45267,28 +45309,7 @@ ${list}`);
45267
45309
  // an agent harness kills it on its own (shorter) deadline before the verdict ever prints (#2940).
45268
45310
  progress: ({ state, elapsedMs, remainingMs }) => console.warn(`pr checks-wait: ${state} \u2014 ${Math.round(elapsedMs / 1e3)}s elapsed, ${Math.round(remainingMs / 6e4)}m left`)
45269
45311
  });
45270
- if (o.json) printLine(JSON.stringify(result));
45271
- else if (result.status === "conflicting") {
45272
- printLine(`pr checks-wait: conflicting \u2014 ${result.reason}`);
45273
- } else if (result.status === "timeout") {
45274
- const stuckQueuing = /no-checks-reported/i.test(result.detail ?? "");
45275
- printLine(
45276
- `pr checks-wait: timeout \u2014 waited ${Math.round((result.waitedMs ?? 0) / 6e4)}m, last state: ${result.detail ?? "pending"}. No check failed; re-run to keep waiting, or pass --timeout <minutes>.` + (stuckQueuing ? " Tip: check-runs never appeared \u2014 if `gh api repos/<owner>/<repo>/actions/runs?head_sha=<sha>` shows total_count=0, see docs/Guides/gh-runner-runbook.md \xA7 Zero workflow runs; otherwise mmi-live may be saturated or Actions may be failing before checkout (docs/Guides/gh-runner-runbook.md)." : "")
45277
- );
45278
- } else if (result.status === "rate-limited") {
45279
- printLine(`pr checks-wait: rate-limited \u2014 ${result.reason ?? "REST pool below floor"}. No check failed; re-run after the pool resets.`);
45280
- } else if (result.detail === "runner-infra") {
45281
- printLine(`pr checks-wait: failure (runner infrastructure, NOT a test failure) \u2014 ${result.reason}`);
45282
- } else if (result.detail === "stale-head") {
45283
- printLine(`pr checks-wait: failure (stale PR head, NOT a test failure) \u2014 ${result.reason}`);
45284
- } else if (result.detail === "zero-runs") {
45285
- printLine(`pr checks-wait: failure (zero workflow runs delivered, NOT pending checks) \u2014 ${result.reason}`);
45286
- } else {
45287
- printLine(`pr checks-wait: ${result.status}${result.reason ? ` \u2014 ${result.reason}` : ""}${result.detail ? ` (${result.detail})` : ""}`);
45288
- for (const line of failedChecksReceiptLines("pr checks-wait", result)) printLine(line);
45289
- }
45290
- if (result.status === "failure" || result.status === "conflicting") process.exitCode = 1;
45291
- if (result.status === "timeout" || result.status === "rate-limited") process.exitCode = PR_CHECKS_TIMEOUT_EXIT_CODE;
45312
+ printChecksWaitResult("pr checks-wait", result, o.json);
45292
45313
  });
45293
45314
  pr.command("review-check <number>").description("read-only trusted review verdict check for an exact PR head").requiredOption("--repo <owner/repo>", "target repository").requiredOption("--head <sha>", "exact expected head SHA").option("--json", "machine-readable output").action(async (number, o) => {
45294
45315
  const result = await checkPrReview(number, o.repo, o.head);
@@ -45950,6 +45971,37 @@ ${list}`);
45950
45971
  }
45951
45972
  process.exitCode = (partialCleanup.length ? 1 : void 0) ?? prMergeLocalCleanupExitCode(localCleanup) ?? postMergeReconExitCode({ boardAdvance, crossRepoFilingIssue }) ?? process.exitCode;
45952
45973
  });
45974
+ return (ci2) => {
45975
+ ci2.command("checks-wait").description(`bounded wait for ALL check runs and commit statuses on one commit SHA \u2014 replaces raw \`gh run watch\` / \`gh pr checks --watch\` loops, which charge a request per tick and exhausted the shared 5,000/hr token (#7843). REST-only polling with ETag-cached reads and a pool floor (#3024); fails early on a confirmed zero-workflow-runs commit (#5400). Default budget ${PR_CHECKS_TIMEOUT_MS / 6e4}m; --timeout raises it. Exit 1 = a check FAILED or GitHub delivered zero runs; exit ${PR_CHECKS_TIMEOUT_EXIT_CODE} = the wait window expired or the API pool ran dry (re-arm)`).requiredOption("--sha <sha>", "full 40-hex commit SHA to wait on").option("--json", "machine-readable output").option("--repo <owner/repo>", "target repo (defaults to the current repo)").option("--timeout <minutes>", `wait budget in minutes (default ${PR_CHECKS_TIMEOUT_MS / 6e4})`).action(async (o) => {
45976
+ if (!/^[0-9a-f]{40}$/i.test(o.sha)) return fail("ci checks-wait: --sha must be a full 40-hex commit SHA");
45977
+ let timeoutMs;
45978
+ if (o.timeout !== void 0) {
45979
+ const minutes = Number(o.timeout);
45980
+ if (!Number.isFinite(minutes) || minutes <= 0) return fail("ci checks-wait: --timeout must be a positive number of minutes");
45981
+ timeoutMs = Math.round(minutes * 6e4);
45982
+ }
45983
+ const repo = await requireRepo(o.repo);
45984
+ const sha = o.sha.toLowerCase();
45985
+ const result = await waitForPrChecks({
45986
+ resolvePolicy: () => resolveMergeCiPolicyForCheckout(o.repo),
45987
+ pollChecks: () => pollRestCommitChecks(sha, repo),
45988
+ pollRateLimit: () => waitLoopCorePool("ci checks-wait"),
45989
+ checksUrl: `https://github.com/${repo}/commit/${sha}/checks`,
45990
+ checksDiagnosticCommand: `gh api repos/${repo}/commits/${sha}/check-runs`,
45991
+ pollHeadWorkflowRunCount: async () => {
45992
+ const read = await countHeadWorkflowRuns(sha, repo);
45993
+ if (read.state === "ok") return read.count;
45994
+ console.warn(`ci checks-wait: zero-runs probe FAILED (${read.error}) \u2014 not treating as delivery failure this cycle`);
45995
+ return null;
45996
+ },
45997
+ sleep: (ms) => new Promise((resolve7) => setTimeout(resolve7, ms)),
45998
+ log: (message2) => console.warn(message2),
45999
+ timeoutMs: timeoutMs ?? PR_CHECKS_TIMEOUT_MS,
46000
+ progress: ({ state, elapsedMs, remainingMs }) => console.warn(`ci checks-wait: ${state} \u2014 ${Math.round(elapsedMs / 1e3)}s elapsed, ${Math.round(remainingMs / 6e4)}m left`)
46001
+ });
46002
+ printChecksWaitResult("ci checks-wait", result, o.json);
46003
+ });
46004
+ };
45953
46005
  }
45954
46006
 
45955
46007
  // src/command-register-train-operations.ts
@@ -47443,8 +47495,14 @@ function registerSuiteCommands(program3) {
47443
47495
  let result;
47444
47496
  let restored;
47445
47497
  let marked;
47498
+ let retired;
47446
47499
  try {
47447
47500
  const io = suiteTrainIo(root);
47501
+ retired = await retireFailedLeadRcLedger({ ledgerPath: releaseLedgerPath(root), rcHead: () => io.head(SUITE_REPO, "rc").then((h) => h ?? void 0), markAbandoned: io.markAbandoned }, o.ownerGo === true);
47502
+ if (retired && !(0, import_node_fs44.existsSync)(io.recordPath)) {
47503
+ console.log(o.json ? JSON.stringify({ retiredLeadRc: retired }, null, 2) : `suite abandon: retired the lead's failed, never-promoted rc candidate ${retired}; marked abandoned on origin (#7854)`);
47504
+ return;
47505
+ }
47448
47506
  restored = o.ownerGo === true ? await suiteRestoreMainPins(io) : void 0;
47449
47507
  marked = await suiteMarkAbandoned(io, o.ownerGo === true);
47450
47508
  result = suiteAbandon(io.recordPath, o.ownerGo === true);
@@ -47455,6 +47513,7 @@ function registerSuiteCommands(program3) {
47455
47513
  `suite abandon: archived the cut record to ${result.archive}`,
47456
47514
  ...result.orphanTags.length ? [" member rc tags left in place (immutable; the next cut reuses one still unreleased on its rc head, #7450):", ...result.orphanTags.map((t) => ` - ${t}`)] : [" no member rc tag was minted"],
47457
47515
  ...restored ? [` main pins the cut planned for unreleased tags are restored by ${restored.pr} (${restored.status}, #7758)`] : [],
47516
+ ...retired ? [` retired the lead's failed, never-promoted rc candidate ${retired} (#7854)`] : [],
47458
47517
  ...marked.length ? [` marked abandoned on origin, so the hotfix guard stops counting them as active (#7801): ${marked.join(", ")}`] : [],
47459
47518
  " the next suite rcand --owner-go re-snapshots every member"
47460
47519
  ].join("\n"));
@@ -54494,7 +54553,7 @@ oauth.command("verify").description("probe Google authorize with an arbitrary po
54494
54553
  }
54495
54554
  if (mismatches.length) process.exitCode = 1;
54496
54555
  });
54497
- registerCollaborationCommands(program2);
54556
+ var registerCiChecksWait = registerCollaborationCommands(program2);
54498
54557
  function ciAuditDeps2() {
54499
54558
  const cfgPromise = loadConfig();
54500
54559
  const root = hubRoot2();
@@ -54546,6 +54605,7 @@ ci.command("audit").description("read-only fleet scan: gate workflow, ruleset co
54546
54605
  else console.log(renderCiAuditText(report));
54547
54606
  if (!report.ok) process.exitCode = 1;
54548
54607
  });
54608
+ registerCiChecksWait(ci);
54549
54609
  ci.command("reconcile").description("audit + optionally apply merge settings and product ruleset activation (master-admin)").option("--json", "machine-readable output").option("--repo <owner/repo>", "reconcile one repo instead of the full registry").option("--apply", "PATCH merge settings + activate product ruleset when missing (master role required); activation is skipped while the repo's gate has never passed (#3694)").option("--park-ruleset", "stop the product ruleset enforcing without deleting it \u2014 keeps its required contexts (master role required)").action(async (o) => {
54550
54610
  if (o.apply && o.parkRuleset) {
54551
54611
  return fail("ci reconcile: --apply and --park-ruleset ask for opposite things; pass one");
package/cli/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mutmutco/cli",
3
- "version": "4.5.93",
3
+ "version": "4.5.95",
4
4
  "description": "MMI Future CLI — the org dev toolbox and shared cross-IDE engine for every registry-declared MMI coding surface.",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mutmutco/codex-plugin",
3
- "version": "4.5.93",
3
+ "version": "4.5.95",
4
4
  "description": "MMI workflow skills and org gates delivery.",
5
5
  "author": {
6
6
  "name": "MMI Future",