@mutmutco/cli 4.5.132 → 4.5.134

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 +67 -17
  2. package/package.json +1 -1
package/dist/main.cjs CHANGED
@@ -18274,10 +18274,10 @@ var rollout_plan_default = {
18274
18274
  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)."
18275
18275
  },
18276
18276
  baseline: {
18277
- version: "4.5.132",
18278
- tag: "v4.5.132",
18279
- commit: "80a4c6f78d39",
18280
- npm: "@mutmutco/cli@4.5.132"
18277
+ version: "4.5.134",
18278
+ tag: "v4.5.134",
18279
+ commit: "f976ea4f8325",
18280
+ npm: "@mutmutco/cli@4.5.134"
18281
18281
  },
18282
18282
  exitCriterion: "fleet-n-of-n",
18283
18283
  hubOnlyShortcut: "forbidden",
@@ -18294,14 +18294,14 @@ var rollout_plan_default = {
18294
18294
  repo: "mutmutco/mmi-hub",
18295
18295
  role: "canary",
18296
18296
  schedule: "train",
18297
- v3Target: "v4.5.132"
18297
+ v3Target: "v4.5.134"
18298
18298
  }
18299
18299
  ],
18300
18300
  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.",
18301
18301
  rollback: {
18302
18302
  independent: true,
18303
- mechanism: "npm dist-tag latest -> 4.5.132 and redeploy the Hub Lambda from tag v4.5.132 (80a4c6f78d39); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
18304
- v3Target: "v4.5.132 (@mutmutco/cli@4.5.132, tag commit 80a4c6f78d39 \u2014 last known-good release carrying the repo-index v4-only contract)"
18303
+ mechanism: "npm dist-tag latest -> 4.5.134 and redeploy the Hub Lambda from tag v4.5.134 (f976ea4f8325); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
18304
+ v3Target: "v4.5.134 (@mutmutco/cli@4.5.134, tag commit f976ea4f8325 \u2014 last known-good release carrying the repo-index v4-only contract)"
18305
18305
  }
18306
18306
  },
18307
18307
  {
@@ -22897,6 +22897,15 @@ Resume it: ${resumeCommand}
22897
22897
  function preOneZeroInForce(meta) {
22898
22898
  return !!meta?.suite && meta.preOneZero !== false;
22899
22899
  }
22900
+ function assertSuiteAutoVersion(repo, meta, env, namesRcCycle) {
22901
+ if (!meta?.suite) return;
22902
+ const intent = (env.MMI_BUMP_INTENT ?? "").trim();
22903
+ const target = (env.MMI_RELEASE_VERSION ?? "").trim();
22904
+ const hand = intent && intent !== "patch" ? `MMI_BUMP_INTENT=${intent}` : target && !namesRcCycle ? `MMI_RELEASE_VERSION=${target}` : "";
22905
+ if (hand) {
22906
+ throw new Error(`${repo} is a ${meta.suite} suite project: its versions auto-mint as the next patch and carry no meaning (#8224). Unset ${hand}. For a big change, release with \`suite release --owner-go --revamp ${repo}\`.`);
22907
+ }
22908
+ }
22900
22909
  function assertPreOneZero(repo, meta, tag) {
22901
22910
  if (preOneZeroInForce(meta) && /^v?[1-9]\d*\./.test(tag)) {
22902
22911
  throw new Error(`${repo} is a ${meta.suite} suite member held on 0.x.y; ${tag} would be major >= 1. Only the owner lifts this: set registry META preOneZero to false. If the tag came from a stale scripts/next-version.mjs, propagate the current seed first (#7699).`);
@@ -26378,10 +26387,42 @@ Cut by ${formatSessionIdentity(cutBy)}
26378
26387
  var PLAIN_WORDS_HEADING = "## In plain words";
26379
26388
  var PLAIN_WORDS_HEADING_TR = "## Sade s\xF6zlerle";
26380
26389
  var PLAIN_WORDS_MARKER = "<!-- mmi:big -->";
26381
- function buildPlainWordsSection(lines2, big, heading = PLAIN_WORDS_HEADING) {
26390
+ var REPORT_ID = /^[A-Za-z0-9_-]{1,64}$/;
26391
+ async function collectReleaseCredits(deps, repo, body) {
26392
+ try {
26393
+ const [owner, name] = repo.split("/");
26394
+ const prs = /* @__PURE__ */ new Set();
26395
+ let changes = false;
26396
+ for (const line of body.split(/\r?\n/)) {
26397
+ if (line.startsWith("## ")) changes = line === "## What's Changed";
26398
+ if (!changes) continue;
26399
+ const match = line.match(/\bin https:\/\/github\.com\/([^/]+\/[^/]+)\/pull\/(\d+)\s*$/);
26400
+ if (match?.[1]?.toLowerCase() === repo.toLowerCase()) prs.add(Number(match[2]));
26401
+ }
26402
+ const ids = /* @__PURE__ */ new Set();
26403
+ for (const number of [...prs].sort((a, b) => a - b)) {
26404
+ const query = "query($owner:String!,$name:String!,$number:Int!){repository(owner:$owner,name:$name){pullRequest(number:$number){closingIssuesReferences(first:100){nodes{body} pageInfo{hasNextPage}}}}}";
26405
+ const result = JSON.parse(clean2(await deps.run("gh", ["api", "graphql", "-f", `query=${query}`, "-f", `owner=${owner}`, "-f", `name=${name}`, "-F", `number=${number}`])));
26406
+ const refs = result.data?.repository?.pullRequest?.closingIssuesReferences;
26407
+ if (result.errors?.length || !Array.isArray(refs?.nodes) || refs.pageInfo?.hasNextPage !== false) throw new Error(`closing issues unavailable or truncated for PR #${number}`);
26408
+ for (const issue of refs.nodes) {
26409
+ if (typeof issue?.body !== "string") throw new Error(`issue body unavailable for PR #${number}`);
26410
+ const footer = issue.body.trim().match(/(?:^|\n)---\r?\nReported by a person in MM-Work \((?:dev|rc|main)\), module `[^`\r\n]+`, report `([A-Za-z0-9_-]{1,64})`\. Filed by the Hub \(#7389\)\.$/);
26411
+ if (footer?.[1]) ids.add(footer[1]);
26412
+ }
26413
+ }
26414
+ return [...ids].sort().slice(0, 20);
26415
+ } catch (e) {
26416
+ (deps.warn ?? console.warn)(`release credits omitted for ${repo}: ${e.message}`);
26417
+ return [];
26418
+ }
26419
+ }
26420
+ function buildPlainWordsSection(lines2, big, heading = PLAIN_WORDS_HEADING, credits = []) {
26382
26421
  const [title, ...notes] = lines2;
26383
26422
  const body = [heading, title ?? "", ...notes.slice(0, 5).map((n) => `- ${n}`)];
26384
26423
  if (big) body.push(PLAIN_WORDS_MARKER);
26424
+ const ids = [...new Set(credits.filter((id) => REPORT_ID.test(id)))].sort().slice(0, 20);
26425
+ if (ids.length) body.push(`<!-- mmi:credits ${ids.join(",")} -->`);
26385
26426
  return body.join("\n");
26386
26427
  }
26387
26428
  var SUMMARY_GUIDE = "https://github.com/mutmutco/MMI-Hub/blob/development/docs/Guides/train-troubleshooting.md#announce-summary-missing";
@@ -26453,13 +26494,15 @@ async function writePlainWordsIfSuiteMember(deps, args) {
26453
26494
  try {
26454
26495
  if (!args.summaryLines?.length) return;
26455
26496
  const lines2 = args.summaryLines;
26497
+ const body = clean2(await deps.run("gh", ["release", "view", args.tag, "--repo", args.repo, "--json", "body", "-q", ".body"]));
26498
+ const credits = await collectReleaseCredits(deps, args.repo, body);
26456
26499
  const section = [
26457
- buildPlainWordsSection(lines2, args.big === true),
26500
+ buildPlainWordsSection(lines2, args.big === true, PLAIN_WORDS_HEADING, credits),
26458
26501
  ...args.summaryLinesTr?.length ? [buildPlainWordsSection(args.summaryLinesTr, false, PLAIN_WORDS_HEADING_TR)] : []
26459
26502
  ].join("\n\n");
26460
- const body = clean2(await deps.run("gh", ["release", "view", args.tag, "--repo", args.repo, "--json", "body", "-q", ".body"]));
26461
26503
  await deps.run("gh", ["release", "edit", args.tag, "--repo", args.repo, "--notes", upsertPlainWordsSection(body, section)]);
26462
- } catch {
26504
+ } catch (e) {
26505
+ (deps.warn ?? console.warn)(`plain-words write failed for ${args.repo}@${args.tag}: ${e.message}`);
26463
26506
  }
26464
26507
  }
26465
26508
  async function writePlainWordsSection(deps, options, repo, meta, tag) {
@@ -28676,6 +28719,7 @@ async function runTrainApplyLocked(command, deps, options = {}) {
28676
28719
  const bumpIntent = await resolveTrainBumpIntent(deps, process.env, void 0, preOneZeroInForce(meta));
28677
28720
  const branchHints = await loadReleaseTrackBranchHints(deps);
28678
28721
  const directTrack = isHubControlRepo(ctx.repo) || resolveReleaseTrack(meta, branchHints) === "direct";
28722
+ assertSuiteAutoVersion(ctx.repo, meta, process.env, command === "release" && !directTrack);
28679
28723
  if (command === "release" && meta.suite === "mm-work") await requireSuiteReleaseSummary(deps, options.announceSummaryFile);
28680
28724
  const pipelineInput = { deps, ctx, command, meta, branchHints, watch, options, bumpIntent };
28681
28725
  if (command === "rcand") {
@@ -37539,10 +37583,13 @@ ${failures.join("\n")}`);
37539
37583
  await reapplyRulesets(deps, record, "rc");
37540
37584
  return { plan, record };
37541
37585
  }
37542
- async function suiteRelease(deps, ownerGo, big = false) {
37586
+ async function suiteRelease(deps, ownerGo, revamp = []) {
37543
37587
  if (!ownerGo) throw new Error("suite release requires --owner-go; nothing was written");
37544
37588
  const record = readSuiteCut(deps.recordPath);
37545
37589
  if (!record?.pinMerged || !record.leadRcTag) throw new Error("no completed suite rc cut and merged pin PR; release refused");
37590
+ const isRevamp = (repo) => revamp.some((r) => r.toLowerCase() === repo.toLowerCase());
37591
+ const unknown = revamp.filter((r) => r.toLowerCase() !== SUITE_REPO.toLowerCase() && !record.members.some((m) => m.repo.toLowerCase() === r.toLowerCase()));
37592
+ if (unknown.length) throw new Error(`--revamp names repos outside this cut: ${unknown.join(", ")}; nothing was written`);
37546
37593
  const members = trainModules(suiteMembers(await deps.registry()));
37547
37594
  const { active, held } = await holdSplit(deps, members);
37548
37595
  if (!heldMatches(record.heldMembers ?? [], held)) throw new Error("suite hold changed after the cut; release refused");
@@ -37596,7 +37643,7 @@ Each member's live release must serve <data>/main/module.js at its main pin path
37596
37643
  console.warn(`${member.repo}: released as ${member.releasedAs ?? suiteReleaseTag(member.tag)} and hotfixed to ${member.hotfixedTo}, which is live; recorded as released (#7482)`);
37597
37644
  } else {
37598
37645
  if (member.releasedAs && member.releasedAs !== suiteReleaseTag(member.tag)) console.warn(`${member.repo}: its rc already shipped as ${member.releasedAs}, not ${suiteReleaseTag(member.tag)}; finishing that release (#7464)`);
37599
- await deps.release(member.repo, member.releasedAs ?? suiteReleaseTag(member.tag), member.sha, { suiteTag: suiteReleaseTag(record.leadRcTag) });
37646
+ await deps.release(member.repo, member.releasedAs ?? suiteReleaseTag(member.tag), member.sha, { suiteTag: suiteReleaseTag(record.leadRcTag), ...isRevamp(member.repo) ? { big: true } : {} });
37600
37647
  }
37601
37648
  member.released = true;
37602
37649
  writeSuiteCut(deps.recordPath, record);
@@ -37609,7 +37656,7 @@ Each member's live release must serve <data>/main/module.js at its main pin path
37609
37656
  }
37610
37657
  await reapplyRulesets(deps, record, "main");
37611
37658
  if (!record.leadReleased) {
37612
- await deps.release(SUITE_REPO, suiteReleaseTag(record.leadRcTag), record.leadRcSha, { big });
37659
+ await deps.release(SUITE_REPO, suiteReleaseTag(record.leadRcTag), record.leadRcSha, { big: isRevamp(SUITE_REPO) });
37613
37660
  record.leadReleased = true;
37614
37661
  writeSuiteCut(deps.recordPath, record);
37615
37662
  }
@@ -47910,7 +47957,7 @@ function registerTrainOperationsCommands(program3, runProjectInfoSyncCallback) {
47910
47957
  { flags: "--supersede-deploy", description: "with --apply, master-approved closure of a content-caused failed deploy leg on a PUBLISHED release whose immutable tag can never deploy green \u2014 the next patch train then carries the fix (#6553); combined with --supersede-publish it closes BOTH content-caused legs in one approved closure (#6752)" },
47911
47958
  { flags: "--supersede-publish", description: "with --apply, master-approved closure of a content-caused failed publish leg on a fully PROMOTED release whose immutable tag can never publish green \u2014 a deferred Jerv-Hub operator-host Gateway deploy leg is run and verified as part of the closure \u2014 the next patch train then carries the fix (#6638/#6742); combined with --supersede-deploy it closes BOTH content-caused legs in one approved closure (#6752)" },
47912
47959
  { flags: "--retry-publish <run-id>", description: "with --apply, retry one proven failed or cancelled Hub publish release run (#3949/#5797)" },
47913
- { flags: "--big", description: "marks this release big for the mm-work suite `## In plain words` section even though its patch tag alone would not read as one (#7510); automatic for a minor/major bump \u2014 this is only for a patch a project-admin wants surfaced as big" }
47960
+ { flags: "--big", description: "marks this release an owner-approved revamp in the mm-work suite `## In plain words` section (#7510); the only big signal, since suite versions carry no meaning (#8224); requires --owner-go" }
47914
47961
  ];
47915
47962
  for (const f of RELEASE_ONLY_FLAGS) {
47916
47963
  if (commandName === "release") {
@@ -47945,6 +47992,9 @@ function registerTrainOperationsCommands(program3, runProjectInfoSyncCallback) {
47945
47992
  if (o.big && commandName !== "release") {
47946
47993
  return fail(`${commandName}: --big applies only to release \u2014 it marks the mm-work suite plain-words section, which only a Release carries. Run: mmi-cli devops release --big`);
47947
47994
  }
47995
+ if (o.big && !o.ownerGo) {
47996
+ return fail(`${commandName}: --big marks an owner-approved revamp and requires --owner-go (#8224)`);
47997
+ }
47948
47998
  if (o.abort && commandName !== "release") {
47949
47999
  return fail(`${commandName}: --abort applies only to release \u2014 it rolls back a proven unpublished release tag. Run: mmi-cli devops release --abort --apply`);
47950
48000
  }
@@ -48973,7 +49023,7 @@ function registerSuiteCommands(program3) {
48973
49023
  return fail(`suite abandon: ${e.message}`);
48974
49024
  }
48975
49025
  });
48976
- suite.command("release").description("verify the cut and unchanged live backends, ship members then MM-Work, announce once").option("--owner-go", "explicit owner approval to release the tested candidate").option("--announce-summary-file <path>", "curated suite announcement, posted once after the train; also this cut's plain-words summary for MM-Work itself").option("--member-summary-file <owner/repo=path>", "repeatable: required title + 2\u20135 notes for each member being released; carried members need none", (val, prev = []) => [...prev, val], []).option("--announce-summary-file-tr <path>", "Turkish plain-words summary for MM-Work itself").option("--member-summary-file-tr <owner/repo=path>", "repeatable: a member's own Turkish plain-words summary", (val, prev = []) => [...prev, val], []).option("--big", "marks MM-Work's own release big for the plain-words section (#7510); a member is never marked big through this flag \u2014 it is big only via the read route's automatic minor/major detection").option("--json", "structured receipt").action(async (o) => {
49026
+ suite.command("release").description("verify the cut and unchanged live backends, ship members then MM-Work, announce once").option("--owner-go", "explicit owner approval to release the tested candidate").option("--announce-summary-file <path>", "curated suite announcement, posted once after the train; also this cut's plain-words summary for MM-Work itself").option("--member-summary-file <owner/repo=path>", "repeatable: required title + 2\u20135 notes for each member being released; carried members need none", (val, prev = []) => [...prev, val], []).option("--announce-summary-file-tr <path>", "Turkish plain-words summary for MM-Work itself").option("--member-summary-file-tr <owner/repo=path>", "repeatable: a member's own Turkish plain-words summary", (val, prev = []) => [...prev, val], []).option("--revamp <owner/repo>", `repeatable: marks that repo's release an owner-approved revamp in the plain-words section \u2014 the only "big" signal; versions carry no meaning (#8224)`, (val, prev = []) => [...prev, val], []).option("--big", "alias for --revamp mutmutco/MM-Work (#7510)").option("--json", "structured receipt").action(async (o) => {
48977
49027
  try {
48978
49028
  if (!o.ownerGo) throw new Error("suite release requires --owner-go; nothing was written");
48979
49029
  const memberSummaryFiles = parseMemberSummaryFiles(o.memberSummaryFile ?? []);
@@ -48982,7 +49032,7 @@ function registerSuiteCommands(program3) {
48982
49032
  const unlock = await acquireTrainWriterLock(root, "suite release");
48983
49033
  let result;
48984
49034
  try {
48985
- result = await suiteRelease(suiteTrainIo(root, o.announceSummaryFile, memberSummaryFiles, o.announceSummaryFileTr, memberSummaryFilesTr), true, o.big === true);
49035
+ result = await suiteRelease(suiteTrainIo(root, o.announceSummaryFile, memberSummaryFiles, o.announceSummaryFileTr, memberSummaryFilesTr), true, [...o.revamp ?? [], ...o.big ? ["mutmutco/MM-Work"] : []]);
48986
49036
  } finally {
48987
49037
  await unlock();
48988
49038
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mutmutco/cli",
3
- "version": "4.5.132",
3
+ "version": "4.5.134",
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",