@mutmutco/cli 4.5.54 → 4.5.56

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 +52 -14
  2. package/package.json +1 -1
package/dist/main.cjs CHANGED
@@ -5516,7 +5516,7 @@ function isSnapshotShape(body) {
5516
5516
  const staleValid = b?.stale === void 0 || typeof b.stale === "object" && b.stale !== null && Number.isFinite(b.stale.ageMs) && b.stale.ageMs >= 0;
5517
5517
  const githubValid = b?.github === void 0 || b.github.credential === "app_installation" && (rate === void 0 || Number.isFinite(rate?.limit) && Number.isFinite(rate?.remaining) && Number.isFinite(rate?.cost) && typeof rate?.resetAt === "string");
5518
5518
  return Boolean(
5519
- b && typeof b === "object" && typeof b.project?.id === "string" && typeof b.project?.title === "string" && typeof b.viewer === "string" && b.viewer.length > 0 && Array.isArray(b.nodes) && Array.isArray(b.writableRepos) && Array.isArray(b.unreadableRepos) && Array.isArray(b.pullRequests) && Array.isArray(b.warnings) && typeof b.partial === "boolean" && (b.eventCursor === void 0 || Number.isInteger(b.eventCursor) && b.eventCursor >= 0) && githubValid && staleValid
5519
+ b && typeof b === "object" && typeof b.project?.id === "string" && typeof b.project?.title === "string" && typeof b.viewer === "string" && b.viewer.length > 0 && Array.isArray(b.nodes) && Array.isArray(b.writableRepos) && Array.isArray(b.unreadableRepos) && Array.isArray(b.pullRequests) && Array.isArray(b.warnings) && typeof b.partial === "boolean" && (b.source === void 0 || b.source === "live" || b.source === "cache") && (b.builtAt === void 0 || typeof b.builtAt === "string" && Number.isFinite(Date.parse(b.builtAt))) && (b.eventCursor === void 0 || Number.isInteger(b.eventCursor) && b.eventCursor >= 0) && githubValid && staleValid
5520
5520
  );
5521
5521
  }
5522
5522
  async function fetchHubBoardSnapshot(request, deps) {
@@ -12358,7 +12358,7 @@ function renderBoardItem(item) {
12358
12358
  return lines2.join("\n");
12359
12359
  }
12360
12360
  function renderBoardReport(report) {
12361
- const lines2 = [`Board \xB7 ${report.project.title} \xB7 @${report.viewer}`, renderBoardSource()];
12361
+ const lines2 = [`Board \xB7 ${report.project.title} \xB7 @${report.viewer}`, report.source === "cache" ? "source: cache" : renderBoardSource()];
12362
12362
  if (report.github?.rateLimit) {
12363
12363
  const { limit, remaining, cost, resetAt } = report.github.rateLimit;
12364
12364
  lines2.push(`github: app installation \xB7 GraphQL ${remaining}/${limit} remaining \xB7 cost ${cost} \xB7 resets ${resetAt}`);
@@ -12631,7 +12631,8 @@ async function readBoard(options, deps = {}) {
12631
12631
  ...groups,
12632
12632
  warnings: collected.warnings,
12633
12633
  partial: collected.partial,
12634
- source: "live",
12634
+ source: snapshot?.source ?? "live",
12635
+ ...snapshot?.builtAt ? { builtAt: snapshot.builtAt } : {},
12635
12636
  ...pullRequests ? { pullRequests } : {},
12636
12637
  ...eventCursor !== void 0 ? { eventCursor } : {},
12637
12638
  ...github ? { github } : {}
@@ -17043,10 +17044,10 @@ var rollout_plan_default = {
17043
17044
  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)."
17044
17045
  },
17045
17046
  baseline: {
17046
- version: "4.5.54",
17047
- tag: "v4.5.54",
17048
- commit: "c3607021e1d1",
17049
- npm: "@mutmutco/cli@4.5.54"
17047
+ version: "4.5.56",
17048
+ tag: "v4.5.56",
17049
+ commit: "7502269d51cd",
17050
+ npm: "@mutmutco/cli@4.5.56"
17050
17051
  },
17051
17052
  exitCriterion: "fleet-n-of-n",
17052
17053
  hubOnlyShortcut: "forbidden",
@@ -17063,14 +17064,14 @@ var rollout_plan_default = {
17063
17064
  repo: "mutmutco/mmi-hub",
17064
17065
  role: "canary",
17065
17066
  schedule: "train",
17066
- v3Target: "v4.5.54"
17067
+ v3Target: "v4.5.56"
17067
17068
  }
17068
17069
  ],
17069
17070
  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.",
17070
17071
  rollback: {
17071
17072
  independent: true,
17072
- mechanism: "npm dist-tag latest -> 4.5.54 and redeploy the Hub Lambda from tag v4.5.54 (c3607021e1d1); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
17073
- v3Target: "v4.5.54 (@mutmutco/cli@4.5.54, tag commit c3607021e1d1 \u2014 last known-good release carrying the repo-index v4-only contract)"
17073
+ mechanism: "npm dist-tag latest -> 4.5.56 and redeploy the Hub Lambda from tag v4.5.56 (7502269d51cd); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
17074
+ v3Target: "v4.5.56 (@mutmutco/cli@4.5.56, tag commit 7502269d51cd \u2014 last known-good release carrying the repo-index v4-only contract)"
17074
17075
  }
17075
17076
  },
17076
17077
  {
@@ -35274,12 +35275,20 @@ async function suiteRelease(deps, ownerGo) {
35274
35275
  continue;
35275
35276
  }
35276
35277
  const [sha, live, rcHead] = await Promise.all([deps.tagSha(member.repo, member.tag), deps.backend({ repo: member.repo, id: member.id, bundles: {} }), deps.head(member.repo, "rc")]);
35277
- if (!member.released && !member.releasedAs && rcHead?.toLowerCase() !== member.sha?.toLowerCase()) {
35278
+ let rcAligned = false;
35279
+ if (!member.released && !member.releasedAs && rcHead && rcHead.toLowerCase() !== member.sha?.toLowerCase()) {
35278
35280
  const shipped = await deps.shippedTag(member.repo, member.sha);
35279
35281
  if (shipped) member.releasedAs = shipped;
35282
+ else rcAligned = await deps.sameContent(member.repo, member.sha, rcHead);
35280
35283
  }
35281
- if (!sha || sha.toLowerCase() !== member.sha?.toLowerCase() || !member.released && !member.releasedAs && rcHead?.toLowerCase() !== member.sha?.toLowerCase()) throw new Error(`${member.repo}: rc tag/branch ${member.tag} changed after the cut; release refused`);
35282
- const katipReleaseSha = member.id === "katip" ? await deps.tagSha(member.repo, member.releasedAs ?? suiteReleaseTag(member.tag)) : void 0;
35284
+ if (!sha || sha.toLowerCase() !== member.sha?.toLowerCase() || !member.released && !member.releasedAs && !rcAligned && rcHead?.toLowerCase() !== member.sha?.toLowerCase()) throw new Error(`${member.repo}: rc tag/branch ${member.tag} changed after the cut; release refused`);
35285
+ const planned = member.releasedAs ?? suiteReleaseTag(member.tag);
35286
+ if (!member.released && !member.hotfixedTo && live.version !== member.backend && await deps.tagSha(member.repo, planned)) {
35287
+ const hotfix = await deps.hotfixOver(member.repo, planned, live.version);
35288
+ if (hotfix) member.hotfixedTo = hotfix;
35289
+ }
35290
+ if (member.hotfixedTo && !member.released) continue;
35291
+ const katipReleaseSha = member.id === "katip" ? await deps.tagSha(member.repo, planned) : void 0;
35283
35292
  const expectedBackend = member.id === "katip" && member.released ? member.backendAfterRelease ?? katipReleaseSha : member.backend;
35284
35293
  if (live.version !== expectedBackend && !(member.id === "katip" && !member.released && katipReleaseSha && live.version === katipReleaseSha))
35285
35294
  throw new Error(`${member.repo}: live backend changed after the cut (${expectedBackend} \u2192 ${live.version}); release refused`);
@@ -35287,7 +35296,14 @@ async function suiteRelease(deps, ownerGo) {
35287
35296
  if ((await deps.tagSha(SUITE_REPO, record.leadRcTag))?.toLowerCase() !== record.leadRcSha?.toLowerCase()) throw new Error("MM-Work rc tag changed after the cut; release refused");
35288
35297
  for (const member of record.members) {
35289
35298
  if (member.released || member.carried) continue;
35290
- if (member.releasedAs) console.warn(`${member.repo}: its rc already shipped as ${member.releasedAs}, not ${suiteReleaseTag(member.tag)}; finishing that release (#7464)`);
35299
+ if (member.hotfixedTo) {
35300
+ console.warn(`${member.repo}: released as ${member.releasedAs ?? suiteReleaseTag(member.tag)} and hotfixed to ${member.hotfixedTo}, which is live; recorded as released (#7482)`);
35301
+ member.backendAfterRelease = (await deps.backend({ repo: member.repo, id: member.id, bundles: {} })).version;
35302
+ member.released = true;
35303
+ writeSuiteCut(deps.recordPath, record);
35304
+ continue;
35305
+ }
35306
+ 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)`);
35291
35307
  await deps.release(member.repo, member.releasedAs ?? suiteReleaseTag(member.tag), member.sha);
35292
35308
  if (member.id === "katip") {
35293
35309
  const expected = await deps.tagSha(member.repo, member.releasedAs ?? suiteReleaseTag(member.tag));
@@ -45353,6 +45369,26 @@ function suiteTrainIo(root, summaryFile) {
45353
45369
  await exec("git", ["fetch", "origin", "--tags"], target);
45354
45370
  return releaseTagsFrom(await exec("git", ["tag", "--contains", rcSha, "--list", "v*"], target))[0];
45355
45371
  };
45372
+ const sameContent2 = async (repo, candidate, head) => {
45373
+ const target = await checkout(repo);
45374
+ await exec("git", ["fetch", "origin", "--tags"], target);
45375
+ try {
45376
+ await exec("git", ["merge-base", "--is-ancestor", candidate, head], target);
45377
+ } catch {
45378
+ return false;
45379
+ }
45380
+ const [a, b] = (await exec("git", ["rev-parse", `${candidate}^{tree}`, `${head}^{tree}`], target)).trim().split(/\s+/);
45381
+ return !!a && a === b;
45382
+ };
45383
+ const hotfixOver = async (repo, planned, liveSha) => {
45384
+ const target = await checkout(repo);
45385
+ await exec("git", ["fetch", "origin", "--tags"], target);
45386
+ const later = releaseTagsFrom(await exec("git", ["tag", "--contains", planned, "--list", "v*"], target)).filter((t) => t !== planned);
45387
+ for (const tag of later) {
45388
+ if ((await exec("git", ["rev-parse", `${tag}^{commit}`], target)).trim().toLowerCase() === liveSha.toLowerCase()) return tag;
45389
+ }
45390
+ return void 0;
45391
+ };
45356
45392
  const rcRuns = async () => JSON.parse(await gh(["run", "list", "--repo", "mutmutco/MMI-Hub", "--workflow", "module-rc-publish.yml", "--event", "workflow_dispatch", "--limit", "100", "--json", "databaseId,displayTitle,conclusion,status,createdAt"]));
45357
45393
  const watchRcRun = async (title, fields, reuse) => {
45358
45394
  const since = Date.now() - 1e4;
@@ -45440,6 +45476,8 @@ function suiteTrainIo(root, summaryFile) {
45440
45476
  },
45441
45477
  release,
45442
45478
  shippedTag,
45479
+ sameContent: sameContent2,
45480
+ hotfixOver,
45443
45481
  announce: async (record) => {
45444
45482
  if (!summaryFile) throw new Error("suite announcement requires --announce-summary-file; outcome was not posted");
45445
45483
  const result = await trainApplyDeps().announce?.({ repo: SUITE_REPO, tag: record.leadRcTag.replace(/-rc\.\d+$/, ""), summaryFile });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mutmutco/cli",
3
- "version": "4.5.54",
3
+ "version": "4.5.56",
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",