@mutmutco/cli 4.5.137 → 4.5.138

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
@@ -18277,10 +18277,10 @@ var rollout_plan_default = {
18277
18277
  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)."
18278
18278
  },
18279
18279
  baseline: {
18280
- version: "4.5.137",
18281
- tag: "v4.5.137",
18282
- commit: "5d0403299d67",
18283
- npm: "@mutmutco/cli@4.5.137"
18280
+ version: "4.5.138",
18281
+ tag: "v4.5.138",
18282
+ commit: "2b2ba344f112",
18283
+ npm: "@mutmutco/cli@4.5.138"
18284
18284
  },
18285
18285
  exitCriterion: "fleet-n-of-n",
18286
18286
  hubOnlyShortcut: "forbidden",
@@ -18297,14 +18297,14 @@ var rollout_plan_default = {
18297
18297
  repo: "mutmutco/mmi-hub",
18298
18298
  role: "canary",
18299
18299
  schedule: "train",
18300
- v3Target: "v4.5.137"
18300
+ v3Target: "v4.5.138"
18301
18301
  }
18302
18302
  ],
18303
18303
  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.",
18304
18304
  rollback: {
18305
18305
  independent: true,
18306
- mechanism: "npm dist-tag latest -> 4.5.137 and redeploy the Hub Lambda from tag v4.5.137 (5d0403299d67); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
18307
- v3Target: "v4.5.137 (@mutmutco/cli@4.5.137, tag commit 5d0403299d67 \u2014 last known-good release carrying the repo-index v4-only contract)"
18306
+ mechanism: "npm dist-tag latest -> 4.5.138 and redeploy the Hub Lambda from tag v4.5.138 (2b2ba344f112); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
18307
+ v3Target: "v4.5.138 (@mutmutco/cli@4.5.138, tag commit 2b2ba344f112 \u2014 last known-good release carrying the repo-index v4-only contract)"
18308
18308
  }
18309
18309
  },
18310
18310
  {
@@ -22181,6 +22181,10 @@ async function announceShippedRelease(deps, args, model, legs, deferred) {
22181
22181
  return (await deps.announce(args)).note;
22182
22182
  }
22183
22183
  async function listTargetRun(deps, repo, target, headSha) {
22184
+ const { read: _read, ...run } = await readTargetRun(deps, repo, target, headSha);
22185
+ return run;
22186
+ }
22187
+ async function readTargetRun(deps, repo, target, headSha) {
22184
22188
  let rows;
22185
22189
  try {
22186
22190
  rows = JSON.parse(await deps.run("gh", [
@@ -22201,11 +22205,12 @@ async function listTargetRun(deps, repo, target, headSha) {
22201
22205
  ]));
22202
22206
  if (!Array.isArray(rows)) throw new Error("run list did not return an array");
22203
22207
  } catch {
22204
- return { workflow: `${target.workflow} (${target.event}) not listable`, event: target.event, conclusion: "pending" };
22208
+ return { workflow: `${target.workflow} (${target.event}) not listable`, event: target.event, conclusion: "pending", read: "failed" };
22205
22209
  }
22206
22210
  const row = rows.find((r) => typeof r.databaseId === "number" && r.event === target.event);
22207
- if (!row) return { workflow: `${target.workflow} (${target.event}) has not started`, event: target.event, conclusion: "pending" };
22211
+ if (!row) return { workflow: `${target.workflow} (${target.event}) has not started`, event: target.event, conclusion: "pending", read: "absent" };
22208
22212
  return {
22213
+ read: "found",
22209
22214
  workflow: target.workflow,
22210
22215
  runId: row.databaseId,
22211
22216
  runUrl: row.url,
@@ -25740,6 +25745,8 @@ var COMPOSE_GUARD_HARD_FAIL = /^secrets preflight: .*noEnvFile is (not )?true.*$
25740
25745
  var PREFLIGHT_TIMEOUT = /aborted due to timeout|TimeoutError|ETIMEDOUT|ESOCKETTIMEDOUT|UND_ERR_(?:HEADERS|CONNECT)_TIMEOUT/i;
25741
25746
  var PREFLIGHT_TIMEOUT_RETRIES = 2;
25742
25747
  var PREFLIGHT_RETRY_BASE_MS = 1e3;
25748
+ var CANDIDATE_PUSH_GATE_WAIT_MS = 20 * 6e4;
25749
+ var CANDIDATE_PUSH_GATE_POLL_MS = 3e4;
25743
25750
  function readOriginWorkflowsDefault(root, ref) {
25744
25751
  const git3 = (args) => (0, import_node_child_process9.execFileSync)("git", args, { cwd: root, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] });
25745
25752
  let paths;
@@ -26021,6 +26028,51 @@ async function runTrainDoctor(input) {
26021
26028
  if (workflows === null && !startBranchMissing) {
26022
26029
  add({ code: "workflows-unreadable", severity: "blocker", source: "local", title: `.github/workflows at ${workflowsRef} could not be read from ${cwd} \u2014 the tag-addressability (#5428) and npm-major (#5666) preflights did not run`, remedy: `run from a checkout whose git can read ${workflowsRef} (fetch origin first), then rerun; an unread workflow set is unverified, not green` });
26023
26030
  }
26031
+ if (lane === "release" && !startBranchMissing) {
26032
+ const required = meta?.requiredChecks?.length ? meta.requiredChecks : ["gate"];
26033
+ const emitters = (workflows ?? []).filter((f) => parseWorkflowJobIds(f.body).some((id) => required.some((context) => contextMatchesJobId(id, context))));
26034
+ const gateFiles = emitters.length ? emitters : (workflows ?? []).filter((f) => isGateWorkflowPath(f.path));
26035
+ const gates = gateFiles.length ? gateFiles.map((f) => f.path.split("/").pop()) : ["gate"];
26036
+ try {
26037
+ const tip = await git3(["rev-parse", "--verify", "--quiet", `refs/remotes/origin/${startBranch}`]);
26038
+ for (const workflow of gates) {
26039
+ let run = await readTargetRun(train, repo, { workflow, event: "push" }, tip);
26040
+ let lastUrl = run.runUrl;
26041
+ let elapsed = 0;
26042
+ const startedAt = Date.now();
26043
+ while (input.refuse && run.read === "found" && run.conclusion === "pending" && elapsed < CANDIDATE_PUSH_GATE_WAIT_MS) {
26044
+ train.warn?.(`candidate push gate ${run.runUrl} still running \u2014 ${elapsed / 1e3}s elapsed (20m bound)`);
26045
+ await deps.sleep(CANDIDATE_PUSH_GATE_POLL_MS);
26046
+ run = await readTargetRun(train, repo, { workflow, event: "push" }, tip);
26047
+ elapsed = Math.max(elapsed + CANDIDATE_PUSH_GATE_POLL_MS, Date.now() - startedAt);
26048
+ lastUrl = run.runUrl ?? lastUrl;
26049
+ }
26050
+ const url = run.runUrl ?? lastUrl ?? (run.runId ? `https://github.com/${repo}/actions/runs/${run.runId}` : "(no run URL)");
26051
+ if (run.read === "failed") {
26052
+ originUnverified = true;
26053
+ add({ code: "candidate-push-gate-unread", severity: "warning", source: "origin", title: `${workflow} push runs on ${startBranch}@${tip.slice(0, 12)} could not be read`, remedy: `repair the GitHub run-list read and rerun; unread is not a pass${elapsed ? ` \u2014 last observed run: ${url}` : ""}` });
26054
+ if (input.refuse && elapsed) throw new Error(`candidate push gate became unreadable while waiting \u2014 ${url}; nothing was tagged`);
26055
+ } else if (run.read === "absent") {
26056
+ add({ code: "candidate-push-gate-missing", severity: "warning", source: "origin", title: `no ${workflow} push run on ${startBranch}@${tip.slice(0, 12)}`, remedy: "no pre-tag push verdict is available; some repos intentionally run gate only on PRs and tags" });
26057
+ } else if (run.conclusion === "failure") {
26058
+ let jobs = "failed jobs unreadable";
26059
+ try {
26060
+ const rows = JSON.parse(await train.run("gh", ["run", "view", String(run.runId), "--repo", repo, "--json", "jobs"]));
26061
+ jobs = rows.jobs.filter((j) => !["success", "skipped", "neutral", ""].includes(j.conclusion)).map((j) => j.name).join(", ") || "no failed job names reported";
26062
+ } catch {
26063
+ }
26064
+ add({ code: "candidate-push-gate-red", severity: "blocker", source: "origin", title: `${workflow} push gate failed on ${startBranch}@${tip.slice(0, 12)} \u2014 ${url}`, remedy: `${url} \u2014 failed job(s): ${jobs}. Fix on development through a normal CI-gated PR and rerun; --heal never clears a red gate` });
26065
+ } else if (run.conclusion === "pending") {
26066
+ add({ code: "candidate-push-gate-running", severity: "warning", source: "origin", title: `${workflow} push gate still running \u2014 ${url}`, remedy: "wait for the run to conclude and rerun; apply waits up to 20 minutes before refusing" });
26067
+ if (input.refuse) throw new Error(`candidate push gate still running after 20 minutes \u2014 ${url}; nothing was tagged`);
26068
+ }
26069
+ }
26070
+ } catch (e) {
26071
+ if (input.refuse) throw e;
26072
+ originUnverified = true;
26073
+ add({ code: "candidate-push-gate-unread", severity: "warning", source: "origin", title: `candidate push gate could not be read: ${message(e)}`, remedy: "repair the candidate SHA / GitHub read and rerun; unread is not a pass" });
26074
+ }
26075
+ }
26024
26076
  if (!startBranchMissing) {
26025
26077
  try {
26026
26078
  const required = await discoverRequiredCheckContexts(train, ctx, stage);
@@ -4548,6 +4548,10 @@ function rcWindow(since) {
4548
4548
  return since === void 0 ? void 0 : since - 6e4;
4549
4549
  }
4550
4550
  async function listTargetRun(deps, repo, target, headSha) {
4551
+ const { read: _read, ...run } = await readTargetRun(deps, repo, target, headSha);
4552
+ return run;
4553
+ }
4554
+ async function readTargetRun(deps, repo, target, headSha) {
4551
4555
  let rows;
4552
4556
  try {
4553
4557
  rows = JSON.parse(await deps.run("gh", [
@@ -4568,11 +4572,12 @@ async function listTargetRun(deps, repo, target, headSha) {
4568
4572
  ]));
4569
4573
  if (!Array.isArray(rows)) throw new Error("run list did not return an array");
4570
4574
  } catch {
4571
- return { workflow: `${target.workflow} (${target.event}) not listable`, event: target.event, conclusion: "pending" };
4575
+ return { workflow: `${target.workflow} (${target.event}) not listable`, event: target.event, conclusion: "pending", read: "failed" };
4572
4576
  }
4573
4577
  const row = rows.find((r) => typeof r.databaseId === "number" && r.event === target.event);
4574
- if (!row) return { workflow: `${target.workflow} (${target.event}) has not started`, event: target.event, conclusion: "pending" };
4578
+ if (!row) return { workflow: `${target.workflow} (${target.event}) has not started`, event: target.event, conclusion: "pending", read: "absent" };
4575
4579
  return {
4580
+ read: "found",
4576
4581
  workflow: target.workflow,
4577
4582
  runId: row.databaseId,
4578
4583
  runUrl: row.url,
@@ -5444,6 +5449,7 @@ async function selfConvergeTrainCli(input) {
5444
5449
  // src/train-doctor.ts
5445
5450
  var TROUBLESHOOTING_GUIDE = "docs/Guides/train-troubleshooting.md";
5446
5451
  var TROUBLESHOOTING_GUIDE_URL = `https://github.com/mutmutco/MMI-Hub/blob/development/${TROUBLESHOOTING_GUIDE}`;
5452
+ var CANDIDATE_PUSH_GATE_WAIT_MS = 20 * 6e4;
5447
5453
  function readOriginWorkflowsDefault(root, ref) {
5448
5454
  const git = (args) => (0, import_node_child_process7.execFileSync)("git", args, { cwd: root, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] });
5449
5455
  let paths;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mutmutco/cli",
3
- "version": "4.5.137",
3
+ "version": "4.5.138",
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",