@mutmutco/cli 4.3.30 → 4.3.32

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 +70 -26
  2. package/package.json +1 -1
package/dist/main.cjs CHANGED
@@ -12297,8 +12297,8 @@ async function claimOneBoardItem(ctx, selector, options) {
12297
12297
  if (options.check) {
12298
12298
  return { item, viewer: report.viewer, repo: report.repo, status: "In Progress", partial: false, ...heldReceipt(), alreadyClaimed: true, checked: true };
12299
12299
  }
12300
- await postClaimMarkerComment(client, item, ctx.session);
12301
- return { item, viewer: report.viewer, repo: report.repo, status: "In Progress", partial: false, ...heldReceipt(), alreadyClaimed: true };
12300
+ const renewed = await postClaimMarkerComment(client, item, ctx.session);
12301
+ return { item, viewer: report.viewer, repo: report.repo, status: "In Progress", partial: false, ...heldReceipt(), alreadyClaimed: true, renewed };
12302
12302
  }
12303
12303
  if (options.check) {
12304
12304
  return { item, viewer: report.viewer, repo: report.repo, status: item.status, partial: false, ...claimedReceipt(), checked: true };
@@ -12361,7 +12361,7 @@ async function claimBoardIssues(options, deps = {}) {
12361
12361
  const ref = `${selector.repo}#${selector.number}`;
12362
12362
  try {
12363
12363
  const result = await claimOneBoardItem(ctx, selector, { ...options, bulk: true });
12364
- results[index] = { ref: result.item.ref, claimed: true, item: result.item, status: result.status, partial: result.partial, warning: result.warning, outcome: result.outcome, holder: result.holder, previousHolder: result.previousHolder, resumeEvidence: result.resumeEvidence, reclaimedFrom: result.reclaimedFrom, alreadyClaimed: result.alreadyClaimed, checked: result.checked };
12364
+ results[index] = { ref: result.item.ref, claimed: true, item: result.item, status: result.status, partial: result.partial, warning: result.warning, outcome: result.outcome, holder: result.holder, previousHolder: result.previousHolder, resumeEvidence: result.resumeEvidence, reclaimedFrom: result.reclaimedFrom, alreadyClaimed: result.alreadyClaimed, renewed: result.renewed, checked: result.checked };
12365
12365
  } catch (e) {
12366
12366
  results[index] = { ref, claimed: false, reason: e.message };
12367
12367
  }
@@ -12551,9 +12551,11 @@ async function postClaimMarkerComment(client, item, actor = describeSessionIdent
12551
12551
 
12552
12552
  <!-- mmi-claim: ${JSON.stringify(marker)} -->`
12553
12553
  });
12554
+ return true;
12554
12555
  } catch (e) {
12555
12556
  process.stderr.write(`warning: ${item.ref} was claimed, but recording the claim marker comment failed: ${ghError(e)}
12556
12557
  `);
12558
+ return false;
12557
12559
  }
12558
12560
  }
12559
12561
 
@@ -15584,10 +15586,10 @@ var rollout_plan_default = {
15584
15586
  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)."
15585
15587
  },
15586
15588
  baseline: {
15587
- version: "4.3.30",
15588
- tag: "v4.3.30",
15589
- commit: "a8f898264f6e",
15590
- npm: "@mutmutco/cli@4.3.30"
15589
+ version: "4.3.32",
15590
+ tag: "v4.3.32",
15591
+ commit: "fe984ee06950",
15592
+ npm: "@mutmutco/cli@4.3.32"
15591
15593
  },
15592
15594
  exitCriterion: "fleet-n-of-n",
15593
15595
  hubOnlyShortcut: "forbidden",
@@ -15604,14 +15606,14 @@ var rollout_plan_default = {
15604
15606
  repo: "mutmutco/mmi-hub",
15605
15607
  role: "canary",
15606
15608
  schedule: "train",
15607
- v3Target: "v4.3.30"
15609
+ v3Target: "v4.3.32"
15608
15610
  }
15609
15611
  ],
15610
15612
  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.",
15611
15613
  rollback: {
15612
15614
  independent: true,
15613
- mechanism: "npm dist-tag latest -> 4.3.30 and redeploy the Hub Lambda from tag v4.3.30 (a8f898264f6e); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
15614
- v3Target: "v4.3.30 (@mutmutco/cli@4.3.30, tag commit a8f898264f6e \u2014 last known-good release carrying the repo-index v4-only contract)"
15615
+ mechanism: "npm dist-tag latest -> 4.3.32 and redeploy the Hub Lambda from tag v4.3.32 (fe984ee06950); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
15616
+ v3Target: "v4.3.32 (@mutmutco/cli@4.3.32, tag commit fe984ee06950 \u2014 last known-good release carrying the repo-index v4-only contract)"
15615
15617
  }
15616
15618
  },
15617
15619
  {
@@ -21306,6 +21308,9 @@ function troubleshootingAnchor(code) {
21306
21308
  }
21307
21309
  var SCRATCH_BRANCH_GLOBS = ["train/check/*", "hotfix-fold/*--port-*"];
21308
21310
  var COMPOSE_GUARD_HARD_FAIL = /^secrets preflight: .*noEnvFile is (not )?true.*$/m;
21311
+ var PREFLIGHT_TIMEOUT = /aborted due to timeout|TimeoutError|ETIMEDOUT|ESOCKETTIMEDOUT|UND_ERR_(?:HEADERS|CONNECT)_TIMEOUT/i;
21312
+ var PREFLIGHT_TIMEOUT_RETRIES = 2;
21313
+ var PREFLIGHT_RETRY_BASE_MS = 1e3;
21309
21314
  function readOriginWorkflowsDefault(root, ref) {
21310
21315
  const git3 = (args) => (0, import_node_child_process9.execFileSync)("git", args, { cwd: root, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] });
21311
21316
  let paths;
@@ -21372,6 +21377,7 @@ var defaultDeps2 = {
21372
21377
  }
21373
21378
  },
21374
21379
  registryWhoami: probeRegistryWhoami,
21380
+ sleep: (ms) => new Promise((resolve7) => setTimeout(resolve7, ms)),
21375
21381
  env: process.env
21376
21382
  };
21377
21383
  function message(e) {
@@ -21561,7 +21567,7 @@ async function runTrainDoctor(input) {
21561
21567
  } catch {
21562
21568
  linked = false;
21563
21569
  }
21564
- add(linked ? { code: "worktree-isolated", severity: "blocker", source: "local", title: `this is a linked worktree on ${currentBranch2 || "(detached)"}, not the lane's start branch ${startBranch} (#2770)`, remedy: `run the ${lane} lane from the primary checkout on ${startBranch}; a linked worktree never carries the train` } : { code: "branch-mismatch", severity: "blocker", source: "local", title: `on ${currentBranch2 || "(detached)"}; the ${lane} lane starts from ${startBranch}`, remedy: `git checkout ${startBranch}, then rerun` });
21570
+ add(linked ? { code: "worktree-isolated", severity: "blocker", source: "local", title: `this is a linked worktree on ${currentBranch2 || "(detached)"}, not the lane's start branch ${startBranch} (#2770)`, remedy: `run the ${lane} lane from the primary checkout on ${startBranch}; a linked worktree never carries the train` } : { code: "branch-mismatch", severity: "blocker", source: "local", title: `on ${currentBranch2 || "(detached)"}; the ${lane} lane starts from ${startBranch}`, remedy: `git checkout ${startBranch}, then rerun; --heal never switches branches \u2014 the branch you stand on names the lane you meant, and healing it would run the train off a branch you did not pick (#6432)` });
21565
21571
  }
21566
21572
  const stage = laneStage(lane);
21567
21573
  const workflowsRef = `origin/${startBranch ?? "main"}`;
@@ -21664,17 +21670,28 @@ async function runTrainDoctor(input) {
21664
21670
  unverified("the vault npm token (`npm whoami` through the `_org` npm/NPM_TOKEN hop)", probe.detail);
21665
21671
  }
21666
21672
  }
21667
- try {
21668
- await train.runSelf(["secrets", "preflight", "--stage", stage, "--repo", repo, ...lane === "hotfix" ? ["--lane", "hotfix"] : []]);
21669
- } catch (e) {
21670
- const err = e;
21671
- const text = [typeof err.stdout === "string" ? err.stdout : "", typeof err.stderr === "string" ? err.stderr : "", message(e)].join("\n");
21672
- if (/^missing /m.test(text)) {
21673
- add({ code: "secrets-missing", severity: "blocker", source: "origin", title: `required ${stage} secret name(s) are absent: ${clean2(text.match(/^missing .*$/m)?.[0] ?? "")}`, remedy: `provision them in the vault (\`mmi-cli vault secrets request <KEY> --repo ${repo}\`), then rerun \`mmi-cli vault secrets preflight --stage ${stage} --repo ${repo}${lane === "hotfix" ? " --lane hotfix" : ""}\`` });
21674
- } else if (COMPOSE_GUARD_HARD_FAIL.test(text)) {
21675
- add({ code: "compose-guard-mismatch", severity: "blocker", source: "origin", title: clean2(text.match(COMPOSE_GUARD_HARD_FAIL)?.[0] ?? text), remedy: `fix the compose/DEPLOY#${stage}.noEnvFile pair per the fileless-transition guide the preflight printed, then rerun \`mmi-cli vault secrets preflight --stage ${stage} --repo ${repo}${lane === "hotfix" ? " --lane hotfix" : ""}\`; --skip-compose-guard only after independent verification (#2813)` });
21676
- } else {
21677
- unverified(`the ${stage} secrets preflight`, clean2(text) || e);
21673
+ let preflightTimeouts = 0;
21674
+ for (; ; ) {
21675
+ try {
21676
+ await train.runSelf(["secrets", "preflight", "--stage", stage, "--repo", repo, ...lane === "hotfix" ? ["--lane", "hotfix"] : []]);
21677
+ break;
21678
+ } catch (e) {
21679
+ const err = e;
21680
+ const text = [typeof err.stdout === "string" ? err.stdout : "", typeof err.stderr === "string" ? err.stderr : "", message(e)].join("\n");
21681
+ if (PREFLIGHT_TIMEOUT.test(text) && preflightTimeouts < PREFLIGHT_TIMEOUT_RETRIES) {
21682
+ preflightTimeouts += 1;
21683
+ await deps.sleep(PREFLIGHT_RETRY_BASE_MS * 2 ** (preflightTimeouts - 1));
21684
+ continue;
21685
+ }
21686
+ if (/^missing /m.test(text)) {
21687
+ add({ code: "secrets-missing", severity: "blocker", source: "origin", title: `required ${stage} secret name(s) are absent: ${clean2(text.match(/^missing .*$/m)?.[0] ?? "")}`, remedy: `provision them in the vault (\`mmi-cli vault secrets request <KEY> --repo ${repo}\`), then rerun \`mmi-cli vault secrets preflight --stage ${stage} --repo ${repo}${lane === "hotfix" ? " --lane hotfix" : ""}\`` });
21688
+ } else if (COMPOSE_GUARD_HARD_FAIL.test(text)) {
21689
+ add({ code: "compose-guard-mismatch", severity: "blocker", source: "origin", title: clean2(text.match(COMPOSE_GUARD_HARD_FAIL)?.[0] ?? text), remedy: `fix the compose/DEPLOY#${stage}.noEnvFile pair per the fileless-transition guide the preflight printed, then rerun \`mmi-cli vault secrets preflight --stage ${stage} --repo ${repo}${lane === "hotfix" ? " --lane hotfix" : ""}\`; --skip-compose-guard only after independent verification (#2813)` });
21690
+ } else {
21691
+ const retried = preflightTimeouts ? ` (transient timeout, retried ${preflightTimeouts} times)` : "";
21692
+ unverified(`the ${stage} secrets preflight`, `${clean2(text) || message(e)}${retried}`);
21693
+ }
21694
+ break;
21678
21695
  }
21679
21696
  }
21680
21697
  if (ledgerRaw !== void 0 && ledgerPath) {
@@ -21713,8 +21730,10 @@ async function runTrainDoctor(input) {
21713
21730
  code: failed ? "ledger-failed" : "ledger-pending",
21714
21731
  severity: "blocker",
21715
21732
  source: "local",
21716
- title: `a prior release ledger for ${ledger.tag} is ${derived.phaseStatus} (${open2}) \u2014 a new train must not stack on it (#5987)`,
21717
- remedy: failed ? `diagnose the failed leg, then \`mmi-cli devops release --resume\` once its cause is fixed \u2014 or, only when proven unpublished and with fresh approval, \`mmi-cli devops release --abort --apply\`` : `finish it first: \`mmi-cli devops release --resume\` (alignment-only pending legs close themselves with \`train doctor --heal\` once the PR merges)`
21733
+ // #6429: each lane finishes its own run (#6068) an rcand-lane ledger named as a release
21734
+ // ledger, with `release --resume` as its remedy, sends the operator to a verb that refuses it.
21735
+ title: `a prior ${ledger.lane ?? "release"} ledger for ${ledger.tag} is ${derived.phaseStatus} (${open2}) \u2014 a new train must not stack on it (#5987)`,
21736
+ remedy: failed ? `diagnose the failed leg, then ${ledgerLaneResumeCommand(ledger)} once its cause is fixed (an abort only with fresh approval)` : `finish it first: ${ledgerLaneResumeCommand(ledger)} (alignment-only pending legs close themselves with \`train doctor --heal\` once the PR merges)`
21718
21737
  });
21719
21738
  }
21720
21739
  } catch (e) {
@@ -22605,6 +22624,29 @@ async function latestRemoteRcTag(deps) {
22605
22624
  const tag = [...tags.keys()].sort(compareRcTagsNewestFirst)[0];
22606
22625
  return tag ? { tag, sha: tags.get(tag) } : void 0;
22607
22626
  }
22627
+ async function activeRcandLedgerCandidate(deps, cwd) {
22628
+ let path2;
22629
+ try {
22630
+ path2 = releaseLedgerPath(cwd);
22631
+ } catch {
22632
+ return void 0;
22633
+ }
22634
+ let prior;
22635
+ try {
22636
+ prior = parseReleaseLedger((0, import_node_fs24.readFileSync)(path2, "utf8"));
22637
+ } catch {
22638
+ return void 0;
22639
+ }
22640
+ if (prior.lane !== "rcand") return void 0;
22641
+ let liveSha = "";
22642
+ try {
22643
+ liveSha = clean2(await runGitRemoteRead(deps, ["ls-remote", "origin", `refs/tags/${prior.tag}`])).split(/\s+/)[0] ?? "";
22644
+ } catch {
22645
+ return void 0;
22646
+ }
22647
+ if (liveSha.toLowerCase() !== prior.tagSha.toLowerCase()) return void 0;
22648
+ return { tag: prior.tag, sha: prior.tagSha };
22649
+ }
22608
22650
  async function probeAncestor(deps, ancestor, descendant, label) {
22609
22651
  try {
22610
22652
  await deps.run("git", ["merge-base", "--is-ancestor", ancestor, descendant]);
@@ -22628,7 +22670,7 @@ async function runRcandResume(deps, options = {}) {
22628
22670
  throw new Error("rcand --resume: origin/rc does not exist \u2014 there is no candidate branch to resume");
22629
22671
  }
22630
22672
  const deployModel = await preflight(deps, ctx, "rc", meta);
22631
- const candidate = await latestRemoteRcTag(deps);
22673
+ const candidate = await activeRcandLedgerCandidate(deps, process.cwd()) ?? await latestRemoteRcTag(deps);
22632
22674
  if (!candidate) {
22633
22675
  throw new Error("rcand --resume: no public v*-rc.* tag found on origin \u2014 there is no tagged candidate to resume");
22634
22676
  }
@@ -25669,7 +25711,9 @@ function registerBoardCommands(program3) {
25669
25711
  }
25670
25712
  if (result.outcome === "took-over") return `Took over ${ref} from ${previousHolder} for ${holder} - In Progress`;
25671
25713
  if (result.outcome === "resumed") return `Resumed ${ref} from ${previousHolder} for ${holder} - In Progress (${result.resumeEvidence})`;
25672
- if (result.outcome === "held") return `${ref} is held by ${holder} - In Progress`;
25714
+ if (result.outcome === "held") {
25715
+ return result.renewed ? `${ref} is held by ${holder} - In Progress, claim lease renewed` : `${ref} is held by ${holder} - In Progress, claim lease NOT renewed (marker comment failed)`;
25716
+ }
25673
25717
  return `Claimed ${ref} for ${holder} - In Progress${reclaimed}`;
25674
25718
  }
25675
25719
  const board = program3.command("board").description("read, claim, show, and move Project v2 work items for the current repo");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mutmutco/cli",
3
- "version": "4.3.30",
3
+ "version": "4.3.32",
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",