@mutmutco/cli 4.6.42 → 4.6.43

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 +54 -18
  2. package/package.json +1 -1
package/dist/main.cjs CHANGED
@@ -25273,6 +25273,31 @@ function missingPlaceholders(rendered) {
25273
25273
  for (const m of rendered.matchAll(PLACEHOLDER_RE)) out.add(m[1]);
25274
25274
  return [...out];
25275
25275
  }
25276
+ function seedMatchesReleaseTrack(seed, releaseTrack) {
25277
+ if (!seed.releaseTracks?.length) return true;
25278
+ return releaseTrack != null && seed.releaseTracks.includes(releaseTrack);
25279
+ }
25280
+ var TRAIN_ONLY_BEGIN = "mmi-train-only:start";
25281
+ var TRAIN_ONLY_END = "mmi-train-only:end";
25282
+ function renderSelfSeedForTrack(content, releaseTrack) {
25283
+ if (releaseTrack !== "single") return content;
25284
+ const lines2 = content.split(/(?<=\n)/);
25285
+ const out = [];
25286
+ let skipping = false;
25287
+ for (const line of lines2) {
25288
+ if (!skipping && line.includes(TRAIN_ONLY_BEGIN)) {
25289
+ skipping = true;
25290
+ continue;
25291
+ }
25292
+ if (skipping) {
25293
+ if (line.includes(TRAIN_ONLY_END)) skipping = false;
25294
+ continue;
25295
+ }
25296
+ out.push(line);
25297
+ }
25298
+ if (skipping) throw new Error(`unterminated ${TRAIN_ONLY_BEGIN} region`);
25299
+ return out.join("");
25300
+ }
25276
25301
  function isPropagatableSeed(seed) {
25277
25302
  return seed.ownership === "org" && seed.source === "self" || seed.managedBlock != null;
25278
25303
  }
@@ -26639,6 +26664,7 @@ function withDerivedRepoVars(vars, parsed, cls, releaseTrack, requiredCheckBranc
26639
26664
  out.CLASS ??= cls;
26640
26665
  out.PROJECT_OWNER ??= parsed.owner;
26641
26666
  const track = releaseTrack ?? resolveBootstrapReleaseTrack(cls);
26667
+ out.RELEASE_TRACK ??= track;
26642
26668
  const runtime = out.GATE_RUNTIME === "python" ? "python" : "node";
26643
26669
  for (const [key, value] of Object.entries(gateSeedVars(cls, track, runtime, requiredCheckBranches, requiredChecks))) {
26644
26670
  out[key] ??= value;
@@ -26998,7 +27024,10 @@ function renderBootstrapAncillaryPlan(labels, environments, exceptions = []) {
26998
27024
  ].join("\n");
26999
27025
  }
27000
27026
  function resolveSeedContent(seed, vars, readFile11) {
27001
- if (seed.source === "self") return readFile11(seed.target);
27027
+ if (seed.source === "self") {
27028
+ const own = readFile11(seed.target);
27029
+ return own == null ? null : renderSelfSeedForTrack(own, vars.RELEASE_TRACK);
27030
+ }
27002
27031
  if (seed.source.startsWith("seed:")) {
27003
27032
  const tmpl = readFile11(`skills/bootstrap/seeds/${seed.source.slice("seed:".length)}`);
27004
27033
  return tmpl == null ? null : renderSeed(tmpl, vars);
@@ -28527,10 +28556,10 @@ var rollout_plan_default = {
28527
28556
  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)."
28528
28557
  },
28529
28558
  baseline: {
28530
- version: "4.6.42",
28531
- tag: "v4.6.42",
28532
- commit: "cb451037f47d",
28533
- npm: "@mutmutco/cli@4.6.42"
28559
+ version: "4.6.43",
28560
+ tag: "v4.6.43",
28561
+ commit: "856f4651277d",
28562
+ npm: "@mutmutco/cli@4.6.43"
28534
28563
  },
28535
28564
  exitCriterion: "fleet-n-of-n",
28536
28565
  hubOnlyShortcut: "forbidden",
@@ -28547,14 +28576,14 @@ var rollout_plan_default = {
28547
28576
  repo: "mutmutco/mmi-hub",
28548
28577
  role: "canary",
28549
28578
  schedule: "train",
28550
- v3Target: "v4.6.42"
28579
+ v3Target: "v4.6.43"
28551
28580
  }
28552
28581
  ],
28553
28582
  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.",
28554
28583
  rollback: {
28555
28584
  independent: true,
28556
- mechanism: "npm dist-tag latest -> 4.6.42 and redeploy the Hub Lambda from tag v4.6.42 (cb451037f47d); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
28557
- v3Target: "v4.6.42 (@mutmutco/cli@4.6.42, tag commit cb451037f47d \u2014 last known-good release carrying the repo-index v4-only contract)"
28585
+ mechanism: "npm dist-tag latest -> 4.6.43 and redeploy the Hub Lambda from tag v4.6.43 (856f4651277d); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
28586
+ v3Target: "v4.6.43 (@mutmutco/cli@4.6.43, tag commit 856f4651277d \u2014 last known-good release carrying the repo-index v4-only contract)"
28558
28587
  }
28559
28588
  },
28560
28589
  {
@@ -31670,17 +31699,17 @@ function isBundleOnlySuiteMember(repo, suite) {
31670
31699
  if (!suite) return false;
31671
31700
  return repo.split("/")[1]?.toLowerCase() !== suite.toLowerCase();
31672
31701
  }
31702
+ var MM_GOES_LIVE = "MM-Work and its modules merge to development and it goes live; there is no release, rc or candidate stage.";
31673
31703
  function suiteMemberRefusal(repo, meta, lane, solo = false, cut) {
31674
31704
  const suite = meta?.suite;
31675
31705
  if (!suite) return null;
31676
31706
  if (!isBundleOnlySuiteMember(repo, suite)) {
31677
31707
  if (solo || cut?.token === SUITE_LEAD_TOKEN && cut.repo.toLowerCase() === repo.toLowerCase()) return null;
31678
- const route = lane === "hotfix" ? "hotfix the affected member from its own checkout, then run mmi-cli devops suite release --owner-go" : `run mmi-cli devops suite ${lane} --owner-go`;
31679
- return `${repo} is the ${suite} suite lead; a plain ${lane} would cut it without its members: ${route}. A lead-only ${lane} needs --suite-solo --owner-go.`;
31708
+ return `${repo} is the ${suite} suite lead; ${MM_GOES_LIVE} There is no ${lane} to run: land the change through a normal PR to development and state what landed.`;
31680
31709
  }
31681
31710
  if (authorisedSuiteCut(repo, meta, cut)) return null;
31682
31711
  if (lane !== "rcand" && solo) return null;
31683
- return `${repo} is part of the ${suite} suite; the cut comes from the suite lead ${suiteLeadRepo(repo, suite)}. A suite member never asks for, proposes or prompts an rc, release or hotfix: the suite orchestrator is the only voice that brings a cut to Jervaise, so state what landed and stop. --owner-go and --suite-solo are never self-authorized; only a backward-compatible solo backend release/hotfix with actual owner approval may pass --suite-solo --owner-go.`;
31712
+ return `${repo} is part of the ${suite} suite; ${MM_GOES_LIVE} A suite member never asks for, proposes or prompts an rc, release or hotfix: there is none, so state what landed and stop.`;
31684
31713
  }
31685
31714
 
31686
31715
  // src/tenant-control-parse.ts
@@ -51008,7 +51037,7 @@ async function verifyBootstrap(repo, repoClass, deps, releaseTrack) {
51008
51037
  detail: `expected: ${requiredProductRulesetRef} (apply as an active repo ruleset after bootstrap)`
51009
51038
  });
51010
51039
  }
51011
- if (repoClass === "deployable") {
51040
+ if (repoClass === "deployable" && effectiveTrack !== "single") {
51012
51041
  const trainScript = "scripts/next-version.mjs";
51013
51042
  checks.push({ ok: await contentExists2(deps, repo, baseBranch, trainScript), label: `train tooling script exists: ${trainScript}` });
51014
51043
  }
@@ -51734,7 +51763,9 @@ function registerBootstrapCommands(program3) {
51734
51763
  for (const repo of targets) {
51735
51764
  const cls = classOf(repo);
51736
51765
  const meta = metaOf(repo);
51737
- const seeds = byteComparableSeeds(manifest, cls);
51766
+ const track = resolveReleaseTrack(metaWithDeclaredClass(meta, cls), void 0, repo);
51767
+ const seeds = byteComparableSeeds(manifest, cls).filter((s) => seedMatchesReleaseTrack(s, track));
51768
+ const trackHubContents = new Map([...hubContents].map(([t, c]) => [t, c == null ? c : renderSelfSeedForTrack(c, track)]));
51738
51769
  seedsPerRepo = Math.max(seedsPerRepo, seeds.length);
51739
51770
  const baseBranch = cls === "content" ? "main" : "development";
51740
51771
  const reads = [];
@@ -51749,9 +51780,8 @@ function registerBootstrapCommands(program3) {
51749
51780
  }
51750
51781
  reads.push({ target: seed.target, content });
51751
51782
  }
51752
- findings.push(...auditRepoSeedDrift(repo, seeds, hubContents, reads));
51783
+ findings.push(...auditRepoSeedDrift(repo, seeds, trackHubContents, reads));
51753
51784
  findings.push(...declaredRenderWaivers(manifest, repo));
51754
- const track = resolveReleaseTrack(metaWithDeclaredClass(meta, cls), void 0, repo);
51755
51785
  const github = await readBootstrapGitHubFacts(repo, track, controlClient);
51756
51786
  const deployFacts = await fetchDeployFactsBySlug((repo.split("/").pop() ?? repo).toLowerCase(), registryClientDeps(await loadConfig()));
51757
51787
  const controlRows = planBootstrapControlPlane({
@@ -52176,6 +52206,7 @@ function registerBootstrapCommands(program3) {
52176
52206
  if (!seed.classes.includes(o.class)) continue;
52177
52207
  if (!seedMatchesDeployModel(seed, applyDeployModel)) continue;
52178
52208
  if (!seedMatchesProjectType(seed, applyProjectType)) continue;
52209
+ if (!seedMatchesReleaseTrack(seed, vars.RELEASE_TRACK)) continue;
52179
52210
  const waiver = seed.waivers?.[slug];
52180
52211
  if (waiver) {
52181
52212
  actions.push({ action: "skip", target: seed.target, ownership: seed.ownership, reason: `waived: ${waiver}` });
@@ -52670,7 +52701,12 @@ LIVE apply to ${repo}:
52670
52701
  const readSeedFile2 = (path2) => (0, import_node_fs40.existsSync)(path2) ? (0, import_node_fs40.readFileSync)(path2, "utf8") : null;
52671
52702
  const isWorkflowSeed = seed.target.startsWith(".github/workflows/");
52672
52703
  const { projects, classOf, inClassRepos, canarySlug, sourcePilot } = await propagationScope(seed.classes, `target '${seed.target}'`);
52673
- const repos = inClassRepos.map((repo) => {
52704
+ const trackOf = (repo) => resolveReleaseTrack(
52705
+ projects.find((p) => (p.repos ?? []).some((r) => r.toLowerCase() === repo.toLowerCase())),
52706
+ void 0,
52707
+ repo
52708
+ );
52709
+ const repos = inClassRepos.filter((repo) => seedMatchesReleaseTrack(seed, trackOf(repo))).map((repo) => {
52674
52710
  const slug = repo.split("/").pop().toLowerCase();
52675
52711
  const waiver = seed.waivers?.[slug];
52676
52712
  return { repo, slug, waiver };
@@ -52718,7 +52754,7 @@ LIVE apply to ${repo}:
52718
52754
  }
52719
52755
  desired = resolved.content;
52720
52756
  } else {
52721
- desired = hubContent;
52757
+ desired = renderSelfSeedForTrack(hubContent, trackOf(r.repo));
52722
52758
  }
52723
52759
  desiredByRepo.set(r.repo, desired);
52724
52760
  const drift = compareSeedBytes(desired, content);
@@ -59669,7 +59705,7 @@ function branchRulesReadHint(path2) {
59669
59705
  const match = new RegExp(`^repos/(${NAME})/(${NAME})/(?:rules/branches/[^/?#]+|branches/[^/?#]+/protection(?:/|$)|rulesets(?:/|$))`).exec(path2.split("?")[0]);
59670
59706
  if (!match) return "";
59671
59707
  const slug = `${match[1]}/${match[2]}`;
59672
- return ` No raw rules, rulesets or branch-protection read is on the App allowlist, so retrying path or query variants cannot work \u2014 inspect a PR's required status contexts with \`MMI_ACTOR=app mmi-cli devops pr checks-required <pr> --repo ${slug} --json\`, or verify repository ruleset and branch-protection health with \`mmi-cli devops bootstrap verify --repo ${slug} --json\` and \`mmi-cli devops ci audit --repo ${slug} --json\`.`;
59708
+ return ` No raw rules, rulesets or branch-protection read is on the App allowlist, so retrying path or query variants cannot work \u2014 inspect a PR's required status contexts with \`MMI_ACTOR=app mmi-cli devops pr checks-required <pr> --repo ${slug} --json\`, or verify repository ruleset and branch-protection health with \`mmi-cli devops bootstrap verify --repo ${slug} --json\` and \`mmi-cli devops ci audit --repo ${slug} --json\`. Stepping around it with a raw \`gh api repos/${slug}/rulesets/<id> > file\` is not a substitute \u2014 when that read fails it leaves an EMPTY file, and a later require/JSON.parse throws 'Unexpected end of JSON input' that looks like corrupt data while the real refusal is only on stderr; check the exit code and file size, or ask a human token holder for the raw ruleset body.`;
59673
59709
  }
59674
59710
  function commitsReadHint(path2) {
59675
59711
  const clean4 = path2.split("?")[0];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mutmutco/cli",
3
- "version": "4.6.42",
3
+ "version": "4.6.43",
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",