@mutmutco/cli 4.5.226 → 4.5.227

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.
Files changed (2) hide show
  1. package/dist/main.cjs +74 -38
  2. package/package.json +1 -1
package/dist/main.cjs CHANGED
@@ -16032,6 +16032,9 @@ function partitionByRequired(entries, requiredContexts) {
16032
16032
  ignoredFailures.push(entry.name);
16033
16033
  }
16034
16034
  }
16035
+ if (relevant.length && [...requiredContexts].some((name) => !entries.some((entry) => entry.name === name))) {
16036
+ relevant.push("pending");
16037
+ }
16035
16038
  return { relevant, ignoredFailures };
16036
16039
  }
16037
16040
  function parseNdjsonLines(stdout) {
@@ -27088,10 +27091,10 @@ var rollout_plan_default = {
27088
27091
  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)."
27089
27092
  },
27090
27093
  baseline: {
27091
- version: "4.5.226",
27092
- tag: "v4.5.226",
27093
- commit: "360239dd3172",
27094
- npm: "@mutmutco/cli@4.5.226"
27094
+ version: "4.5.227",
27095
+ tag: "v4.5.227",
27096
+ commit: "9498ff4da322",
27097
+ npm: "@mutmutco/cli@4.5.227"
27095
27098
  },
27096
27099
  exitCriterion: "fleet-n-of-n",
27097
27100
  hubOnlyShortcut: "forbidden",
@@ -27108,14 +27111,14 @@ var rollout_plan_default = {
27108
27111
  repo: "mutmutco/mmi-hub",
27109
27112
  role: "canary",
27110
27113
  schedule: "train",
27111
- v3Target: "v4.5.226"
27114
+ v3Target: "v4.5.227"
27112
27115
  }
27113
27116
  ],
27114
27117
  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.",
27115
27118
  rollback: {
27116
27119
  independent: true,
27117
- mechanism: "npm dist-tag latest -> 4.5.226 and redeploy the Hub Lambda from tag v4.5.226 (360239dd3172); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
27118
- v3Target: "v4.5.226 (@mutmutco/cli@4.5.226, tag commit 360239dd3172 \u2014 last known-good release carrying the repo-index v4-only contract)"
27120
+ mechanism: "npm dist-tag latest -> 4.5.227 and redeploy the Hub Lambda from tag v4.5.227 (9498ff4da322); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
27121
+ v3Target: "v4.5.227 (@mutmutco/cli@4.5.227, tag commit 9498ff4da322 \u2014 last known-good release carrying the repo-index v4-only contract)"
27119
27122
  }
27120
27123
  },
27121
27124
  {
@@ -49623,15 +49626,40 @@ var PR_LAND_STATE_READ_RETRIES = 3;
49623
49626
  var PR_LAND_STATE_READ_DELAY_MS = 15e3;
49624
49627
  var PR_LAND_MERGE_RETRY_DELAY_MS = 3e4;
49625
49628
  async function mergeAutoWithTransientRetry(prNumber, repo, deps) {
49626
- const first = await deps.mergeAuto(prNumber, repo);
49627
- if (first.mergeStatus !== "failed") return first;
49628
- const ready = await deps.probeMergeReady(prNumber, repo).catch(() => ({ open: false, mergeable: false, checksPassing: false }));
49629
- if (!ready.open || !ready.mergeable || !ready.checksPassing) return first;
49629
+ const now = deps.now ?? (() => Date.now());
49630
+ const deadline = now() + PR_LAND_ENQUEUE_TIMEOUT_MS;
49630
49631
  const sleep2 = deps.sleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms)));
49631
- await sleep2(PR_LAND_MERGE_RETRY_DELAY_MS);
49632
- const retried = await deps.mergeAuto(prNumber, repo);
49633
- if (retried.mergeStatus !== "failed") return retried;
49634
- return { mergeStatus: "failed", error: `merge retry after transient failure also failed: ${retried.error ?? first.error ?? "unknown error"}` };
49632
+ const first = await deps.mergeAuto(prNumber, repo);
49633
+ let result = first;
49634
+ let transientRetried = false;
49635
+ while (result.mergeStatus === "failed") {
49636
+ const ready = await deps.probeMergeReady(prNumber, repo).catch(() => ({ open: false, mergeable: false, checksPassing: false, checksPending: false }));
49637
+ if (ready.open && ready.checksPending) {
49638
+ if (now() >= deadline) break;
49639
+ await sleep2(Math.min(PR_LAND_POLL_MS, deadline - now()));
49640
+ if (now() >= deadline) break;
49641
+ const checks = await deps.waitForChecks(prNumber, repo, deadline - now());
49642
+ if (checks.status !== "success" && checks.status !== "skipped") {
49643
+ return { mergeStatus: "failed", error: `${result.error ?? "merge failed"}
49644
+ registration wait: checks-wait ${checks.status}: ${checks.detail ?? checks.reason ?? "unknown"}` };
49645
+ }
49646
+ if (now() >= deadline) break;
49647
+ } else {
49648
+ if (!ready.open || !ready.mergeable || !ready.checksPassing || transientRetried) return result;
49649
+ transientRetried = true;
49650
+ if (now() >= deadline) break;
49651
+ await sleep2(Math.min(PR_LAND_MERGE_RETRY_DELAY_MS, deadline - now()));
49652
+ if (now() >= deadline) break;
49653
+ }
49654
+ const retried = await deps.mergeAuto(prNumber, repo);
49655
+ result = retried.mergeStatus !== "failed" ? retried : {
49656
+ mergeStatus: "failed",
49657
+ error: `merge retry after transient failure also failed: first attempt: ${first.error ?? "unknown error"}
49658
+ retry: ${retried.error ?? "unknown error"}`
49659
+ };
49660
+ }
49661
+ return result.mergeStatus === "failed" ? { ...result, error: `${result.error ?? "merge failed"}
49662
+ required-check registration did not settle within the enqueue deadline` } : result;
49635
49663
  }
49636
49664
  var AUTO_MERGE_CONFIRM_RETRIES = 3;
49637
49665
  var AUTO_MERGE_CONFIRM_DELAY_MS = 15e3;
@@ -50025,15 +50053,15 @@ function invisibleTrailer(sha, line) {
50025
50053
  return {
50026
50054
  kind: "malformed-override-trailer",
50027
50055
  paths: [],
50028
- detail: `OVERRIDE TRAILER GIT CANNOT SEE \u2014 commit ${sha.slice(0, 8)} carries
50029
- ${line}
50030
- but \`git log --format='%(trailers:key=${TRAILER_KEY})'\` reports nothing for it, so the waiver would
50031
- exist only to the regex that granted it. The trailer was chosen over a flag because it can be
50032
- AUDITED, and a reason the auditor cannot see is not a reason this gate accepts (#3628).
50033
- Git reads trailers from the LAST paragraph only, and every line of that paragraph must be a
50034
- trailer or an indented continuation \u2014 one bare line such as \`Closes #123\` disqualifies the whole
50035
- block. Indent the continuation lines, and leave nothing but trailers in that paragraph.
50036
- This is fixable forward: push a LATER commit on this branch carrying a well-formed trailer.
50056
+ detail: `OVERRIDE TRAILER GIT CANNOT SEE \u2014 commit ${sha.slice(0, 8)}
50057
+ Recovery (trailer): create a LATER commit on this branch with \`${TRAILER_KEY}: <reason>\`
50058
+ in the final trailer block, separated from the body by a blank line. Use \`Key: value\` lines
50059
+ only in that block; indent continuation lines and keep prose such as \`Closes #123\` above it.
50060
+ Verify: \`git log -1 --format='%(trailers:key=${TRAILER_KEY})' HEAD\` must show the waiver.
50061
+ Then run \`mmi-cli tests policy --json --base origin/development\` from the selected worktree root
50062
+ to refresh its receipt before retrying the focused test. Changing location alone cannot fix this trailer.
50063
+ Rejected line: ${line}
50064
+ Git's trailer parser reports no waiver; a regex-only reason is not git-auditable (#3628).
50037
50065
  The nearest waiver wins, and it supersedes this one \u2014 no force-push, no re-filed branch.`
50038
50066
  };
50039
50067
  }
@@ -50911,9 +50939,8 @@ function ghFailureReason(e) {
50911
50939
  const err = e;
50912
50940
  const head = String(err?.message ?? "").split("\n")[0]?.trim() ?? "";
50913
50941
  const detail = `${err?.stderr ?? ""}
50914
- ${err?.stdout ?? ""}`.split("\n").map((line) => line.trim()).find((line) => line.length > 0);
50915
- if (detail && head) return `${head} \u2014 ${detail}`;
50916
- return detail || head || "unknown error";
50942
+ ${err?.stdout ?? ""}`.split("\n").map((line) => line.trim()).filter((line) => line.length > 0).join("\n");
50943
+ return (detail && head ? `${head} \u2014 ${detail}` : detail || head || "unknown error").replace(/\x1b\[[0-9;]*m/g, "").replace(/\b(?:gh[pousr]_|github_pat_|AKIA|sk-)[\w-]+/g, "[redacted]").replace(/\b(authorization:\s*)(?:[^\n]*)/gi, "$1[redacted]");
50917
50944
  }
50918
50945
  var defaultGhMergeAutoIo = {
50919
50946
  gh: async (args, timeoutMs) => (await execFileP("gh", args, { timeout: timeoutMs })).stdout
@@ -51066,13 +51093,7 @@ async function mergeAutoEnqueueWithBody(prNumber, args, method, io, bodyFile, me
51066
51093
  error: stateRead.ok ? message2.split("\n")[0] : `could not confirm PR state after local branch cleanup warning: ${stateRead.error}`
51067
51094
  };
51068
51095
  }
51069
- if (!basePolicyBlocksImmediateMerge(message2)) {
51070
- return { mergeStatus: "failed", error: ghFailureReason(e) };
51071
- }
51072
- return {
51073
- mergeStatus: "failed",
51074
- error: `${ghFailureReason(e)} \u2014 auto-merge could not be armed yet (the PR's required checks have not registered); re-run the same --auto merge once they appear`
51075
- };
51096
+ return { mergeStatus: "failed", error: ghFailureReason(e) };
51076
51097
  }
51077
51098
  return confirmEnqueueOutcome();
51078
51099
  }
@@ -56773,9 +56794,10 @@ ${list}`);
56773
56794
  },
56774
56795
  fetchTrainAuthority: async (repo) => fetchTrainAuthority(repo, registryClientDeps(await loadConfig())),
56775
56796
  resolveCiPolicy: (repo) => resolveRepoMergeCiPolicy(repo, ciAuditDeps()),
56776
- waitForChecks: async (prNumber, repo) => {
56797
+ waitForChecks: async (prNumber, repo, timeoutMs) => {
56777
56798
  const requiredContexts = await fetchRequiredCheckContexts(repo, "development").catch(() => null);
56778
56799
  return waitForPrChecks({
56800
+ timeoutMs,
56779
56801
  resolvePolicy: () => resolveRepoMergeCiPolicy(repo, ciAuditDeps()),
56780
56802
  // #3024: REST-only wait loop — runPrLand's resolveRepo already guarantees `repo` is set.
56781
56803
  pollChecks: () => pollRestPrChecks(prNumber, repo, void 0, requiredContexts),
@@ -56817,7 +56839,8 @@ ${list}`);
56817
56839
  return {
56818
56840
  open: snapshot?.state === "open",
56819
56841
  mergeable: snapshot?.mergeable === "MERGEABLE",
56820
- checksPassing: checks === "success" || checks === "no-checks-reported"
56842
+ checksPassing: checks === "success",
56843
+ checksPending: checks === "pending" || checks === "failing" || checks === "no-checks-reported"
56821
56844
  };
56822
56845
  },
56823
56846
  readPrState: async (prNumber, repo) => {
@@ -62732,19 +62755,32 @@ function ghExitCodeOf(error) {
62732
62755
  }
62733
62756
  async function runBrokerGh(run, spec, write = (chunk) => process.stdout.write(chunk)) {
62734
62757
  const env = brokerChildEnv();
62758
+ let output;
62735
62759
  try {
62736
- write(redactPrivateCredential(await run(spec.args, { timeoutMs: spec.timeoutMs, env }), env));
62737
- return 0;
62760
+ output = redactPrivateCredential(await run(spec.args, { timeoutMs: spec.timeoutMs, env }), env);
62738
62761
  } catch (e) {
62739
62762
  const err = e;
62740
62763
  if (typeof err.stdout === "string" && err.stdout) process.stderr.write(redactPrivateCredential(err.stdout, env));
62741
62764
  const code = ghExitCodeOf(e);
62742
62765
  if (code !== null) {
62743
62766
  if (typeof err.stderr === "string" && err.stderr) process.stderr.write(redactPrivateCredential(err.stderr, env));
62767
+ process.stderr.write(`read: gh ${spec.args.slice(0, 2).join(" ")} failed on the App pool (exit ${code}) \u2014 inspect stderr; retry the same typed read and only parse stdout after success
62768
+ `);
62744
62769
  return code;
62745
62770
  }
62746
62771
  throw new Error(`read: gh ${spec.args.slice(0, 2).join(" ")} did not finish on the App pool (${err.message ?? e}) \u2014 re-run the same command to refresh (same custody); reads never fall back to personal`);
62747
62772
  }
62773
+ if (spec.args.includes("--json")) {
62774
+ try {
62775
+ JSON.parse(output);
62776
+ } catch {
62777
+ process.stderr.write(`read: gh ${spec.args.slice(0, 2).join(" ")} returned ${output.trim() ? "invalid" : "empty"} JSON on the App pool \u2014 retry the same typed read; only parse stdout after success
62778
+ `);
62779
+ return 1;
62780
+ }
62781
+ }
62782
+ write(output);
62783
+ return 0;
62748
62784
  }
62749
62785
  async function runBrokerRestChecks(deps, spec, resolveRepo2) {
62750
62786
  const repo = await resolveRepo2(spec.repo);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mutmutco/cli",
3
- "version": "4.5.226",
3
+ "version": "4.5.227",
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",