@mutmutco/cli 4.3.11 → 4.3.12

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 +59 -11
  2. package/package.json +1 -1
package/dist/main.cjs CHANGED
@@ -12060,6 +12060,9 @@ function withPowerShellChainHint(message2, platform2 = process.platform) {
12060
12060
  return `${message2}
12061
12061
  note: in PowerShell a ';' chain runs every statement regardless of the previous exit code, so the chain ran past this refusal \u2014 rerun the refused write solo or chain gated writes with '&&'`;
12062
12062
  }
12063
+ function isArchivedItemRefusal(message2) {
12064
+ return /The item is archived and cannot be updated/i.test(message2);
12065
+ }
12063
12066
  async function moveBoardItem(options, deps = {}) {
12064
12067
  if (!BOARD_STATUSES.includes(options.status)) {
12065
12068
  throw new Error(`unknown status '${options.status}'; expected one of ${BOARD_STATUSES.join(", ")}`);
@@ -12077,6 +12080,17 @@ async function moveBoardItem(options, deps = {}) {
12077
12080
  try {
12078
12081
  await updateItemSingleSelect(client, cfg.projectId, item.itemId, cfg.statusFieldId, optionId);
12079
12082
  } catch (e) {
12083
+ if (options.status === "Done" && isArchivedItemRefusal(ghError(e))) {
12084
+ return {
12085
+ item,
12086
+ viewer: lookup.viewer,
12087
+ repo: currentRepo,
12088
+ status: item.status,
12089
+ partial: false,
12090
+ archived: true,
12091
+ warning: `${item.ref} is archived (already terminal \u2014 its close archived the card); no ${options.status} move was performed`
12092
+ };
12093
+ }
12080
12094
  const warning = `partial move: ${item.ref} status was not changed to ${options.status} (${ghError(e)})`;
12081
12095
  if (!options.allowPartial) throw new Error(warning);
12082
12096
  return { item, viewer: lookup.viewer, repo: currentRepo, status: item.status, partial: true, warning };
@@ -15462,10 +15476,10 @@ var rollout_plan_default = {
15462
15476
  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)."
15463
15477
  },
15464
15478
  baseline: {
15465
- version: "4.3.11",
15466
- tag: "v4.3.11",
15467
- commit: "c898259b41c3",
15468
- npm: "@mutmutco/cli@4.3.11"
15479
+ version: "4.3.12",
15480
+ tag: "v4.3.12",
15481
+ commit: "355e861fa08f",
15482
+ npm: "@mutmutco/cli@4.3.12"
15469
15483
  },
15470
15484
  exitCriterion: "fleet-n-of-n",
15471
15485
  hubOnlyShortcut: "forbidden",
@@ -15482,14 +15496,14 @@ var rollout_plan_default = {
15482
15496
  repo: "mutmutco/mmi-hub",
15483
15497
  role: "canary",
15484
15498
  schedule: "train",
15485
- v3Target: "v4.3.11"
15499
+ v3Target: "v4.3.12"
15486
15500
  }
15487
15501
  ],
15488
15502
  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.",
15489
15503
  rollback: {
15490
15504
  independent: true,
15491
- mechanism: "npm dist-tag latest -> 4.3.11 and redeploy the Hub Lambda from tag v4.3.11 (c898259b41c3); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
15492
- v3Target: "v4.3.11 (@mutmutco/cli@4.3.11, tag commit c898259b41c3 \u2014 last known-good release carrying the repo-index v4-only contract)"
15505
+ mechanism: "npm dist-tag latest -> 4.3.12 and redeploy the Hub Lambda from tag v4.3.12 (355e861fa08f); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
15506
+ v3Target: "v4.3.12 (@mutmutco/cli@4.3.12, tag commit 355e861fa08f \u2014 last known-good release carrying the repo-index v4-only contract)"
15493
15507
  }
15494
15508
  },
15495
15509
  {
@@ -25532,7 +25546,7 @@ function registerBoardCommands(program3) {
25532
25546
  const result = await moveBoardItem({ config: await loadConfigForBoardSelector2(issueRefs[0], o.repo), selector: issueRefs[0], status: canonicalStatus, repo: o.repo, allowPartial: o.allowPartial });
25533
25547
  invalidateStatuslineBoardCache();
25534
25548
  if (o.json) return console.log(JSON.stringify(result));
25535
- console.log(result.partial ? `Partially moved ${result.item.ref}: ${result.warning}` : `Moved ${result.item.ref} -> ${result.status}`);
25549
+ console.log(result.archived ? `Already terminal ${result.item.ref}: ${result.warning}` : result.partial ? `Partially moved ${result.item.ref}: ${result.warning}` : `Moved ${result.item.ref} -> ${result.status}`);
25536
25550
  } catch (e) {
25537
25551
  return failGraceful(`board move failed: ${e.message}`);
25538
25552
  }
@@ -33494,9 +33508,35 @@ async function fetchBranchTipSha(repo, ref, gh = defaultGhApi) {
33494
33508
  async function fetchRestPrSnapshot(prNumber, repo, gh = defaultGhApi) {
33495
33509
  return parseRestPrSnapshot(JSON.parse(await gh([`repos/${repo}/pulls/${prNumber}`])));
33496
33510
  }
33497
- async function fetchRestRepoMergeSettings(repo, gh = defaultGhApi) {
33498
- const payload = JSON.parse(await gh([`repos/${repo}`]));
33499
- return typeof payload.delete_branch_on_merge === "boolean" ? { deleteBranchOnMerge: payload.delete_branch_on_merge } : {};
33511
+ async function readRepoMergeSettingsOnce(repo, gh) {
33512
+ let raw;
33513
+ try {
33514
+ raw = await gh([`repos/${repo}`]);
33515
+ } catch (e) {
33516
+ return { proven: false, reason: `read failed: ${e.message}` };
33517
+ }
33518
+ let payload;
33519
+ try {
33520
+ payload = JSON.parse(raw);
33521
+ } catch {
33522
+ return { proven: false, reason: "payload was not JSON" };
33523
+ }
33524
+ if (typeof payload.delete_branch_on_merge === "boolean") {
33525
+ return { proven: true, deleteBranchOnMerge: payload.delete_branch_on_merge };
33526
+ }
33527
+ const apiMessage = typeof payload.message === "string" ? ` (${payload.message})` : "";
33528
+ return { proven: false, reason: `payload carried no delete_branch_on_merge${apiMessage}` };
33529
+ }
33530
+ async function ambientGhApi(args) {
33531
+ const { stdout } = await execFileP("gh", ["api", ...args], { timeout: REST_GH_TIMEOUT_MS });
33532
+ return stdout;
33533
+ }
33534
+ async function fetchRestRepoMergeSettings(repo, gh = defaultGhApi, ambientGh = ambientGhApi) {
33535
+ const primary = await readRepoMergeSettingsOnce(repo, gh);
33536
+ if (primary.proven) return primary;
33537
+ const fallback = await readRepoMergeSettingsOnce(repo, ambientGh);
33538
+ if (fallback.proven) return fallback;
33539
+ return { proven: false, reason: `${primary.reason}; ambient fallback: ${fallback.reason}` };
33500
33540
  }
33501
33541
  var PR_SNAPSHOT_READ_RETRIES = 3;
33502
33542
  var PR_SNAPSHOT_READ_DELAY_MS = 2e3;
@@ -36124,6 +36164,10 @@ async function advanceClosedIssuesToDone(deps) {
36124
36164
  const issue = `#${ref.number}`;
36125
36165
  try {
36126
36166
  const outcome = await deps.moveIssueToDone(issue);
36167
+ if (outcome.archived) {
36168
+ entries.push({ issue, moved: true, status: "archived-terminal" });
36169
+ continue;
36170
+ }
36127
36171
  if (!outcome.moved) {
36128
36172
  entries.push({ issue, moved: false, status: "failed", error: outcome.error });
36129
36173
  continue;
@@ -37031,6 +37075,7 @@ async function resolveBoardAdvanceForPr(prNumber, repoOption) {
37031
37075
  },
37032
37076
  moveIssueToDone: async (ref) => {
37033
37077
  const moved = await moveBoardItem({ config: await loadConfigForBoardSelector2(ref, repoOption), selector: ref, status: "Done", repo: repoOption, allowPartial: true });
37078
+ if (moved.archived) return { moved: true, archived: true };
37034
37079
  return moved.partial ? { moved: false, error: moved.warning } : { moved: true };
37035
37080
  },
37036
37081
  // #5317: after a successful move, re-read the board to verify Done actually holds — a move the API
@@ -39667,6 +39712,9 @@ ${list}`);
39667
39712
  if (prMeta.state !== "MERGED" && !o.preserveWorktree) {
39668
39713
  if (!repoForPostCleanup) throw new Error("pr merge: repository is unreadable; cannot prove remote branch preservation");
39669
39714
  const repoSettings = await fetchRestRepoMergeSettings(repoForPostCleanup);
39715
+ if (!repoSettings.proven) {
39716
+ throw new Error(`pr merge: ${repoForPostCleanup} cannot prove delete_branch_on_merge=false \u2014 ${repoSettings.reason}. Automatic deletion can irreversibly close stacked PRs (#5789).`);
39717
+ }
39670
39718
  assertRemoteBranchPreservedOnMerge(repoForPostCleanup, repoSettings.deleteBranchOnMerge);
39671
39719
  }
39672
39720
  const startingPath = (await execFileP("git", ["rev-parse", "--show-toplevel"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mutmutco/cli",
3
- "version": "4.3.11",
3
+ "version": "4.3.12",
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",