@mutmutco/cli 4.3.36 → 4.3.38
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.
- package/dist/main.cjs +108 -22
- package/package.json +1 -1
package/dist/main.cjs
CHANGED
|
@@ -7648,7 +7648,7 @@ function whereLabel(v) {
|
|
|
7648
7648
|
function formatFindHits(intent, hits) {
|
|
7649
7649
|
if (!hits.length) return `no catalog match for "${intent}". Browse with \`mmi-cli vault secrets catalog\`, or run \`mmi-cli vault secrets doctor\` for drift.`;
|
|
7650
7650
|
const blocks = hits.map((h) => [`${h.key} (${whereLabel(h)}) \u2014 ${h.purpose}`, ` ${h.command}`].join("\n"));
|
|
7651
|
-
return [`${hits.length} match(es) for "${intent}" (names + meaning only \u2014 consume keyless with \`secrets use\`):`, "", ...blocks].join("\n");
|
|
7651
|
+
return [`${hits.length} match(es) for "${intent}" (names + meaning only \u2014 consume keyless with \`mmi-cli vault secrets use\`):`, "", ...blocks].join("\n");
|
|
7652
7652
|
}
|
|
7653
7653
|
function formatCatalog(r) {
|
|
7654
7654
|
const lines2 = [`catalog \u2014 ${r.count} secret(s) across ${r.groups.length} group(s):`, ""];
|
|
@@ -15617,10 +15617,10 @@ var rollout_plan_default = {
|
|
|
15617
15617
|
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)."
|
|
15618
15618
|
},
|
|
15619
15619
|
baseline: {
|
|
15620
|
-
version: "4.3.
|
|
15621
|
-
tag: "v4.3.
|
|
15622
|
-
commit: "
|
|
15623
|
-
npm: "@mutmutco/cli@4.3.
|
|
15620
|
+
version: "4.3.38",
|
|
15621
|
+
tag: "v4.3.38",
|
|
15622
|
+
commit: "da4541fdb81e",
|
|
15623
|
+
npm: "@mutmutco/cli@4.3.38"
|
|
15624
15624
|
},
|
|
15625
15625
|
exitCriterion: "fleet-n-of-n",
|
|
15626
15626
|
hubOnlyShortcut: "forbidden",
|
|
@@ -15637,14 +15637,14 @@ var rollout_plan_default = {
|
|
|
15637
15637
|
repo: "mutmutco/mmi-hub",
|
|
15638
15638
|
role: "canary",
|
|
15639
15639
|
schedule: "train",
|
|
15640
|
-
v3Target: "v4.3.
|
|
15640
|
+
v3Target: "v4.3.38"
|
|
15641
15641
|
}
|
|
15642
15642
|
],
|
|
15643
15643
|
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.",
|
|
15644
15644
|
rollback: {
|
|
15645
15645
|
independent: true,
|
|
15646
|
-
mechanism: "npm dist-tag latest -> 4.3.
|
|
15647
|
-
v3Target: "v4.3.
|
|
15646
|
+
mechanism: "npm dist-tag latest -> 4.3.38 and redeploy the Hub Lambda from tag v4.3.38 (da4541fdb81e); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
|
|
15647
|
+
v3Target: "v4.3.38 (@mutmutco/cli@4.3.38, tag commit da4541fdb81e \u2014 last known-good release carrying the repo-index v4-only contract)"
|
|
15648
15648
|
}
|
|
15649
15649
|
},
|
|
15650
15650
|
{
|
|
@@ -18112,6 +18112,50 @@ async function enqueueAlignmentAutoMerge(deps, ctx, prNumber, prUrl, openedNote)
|
|
|
18112
18112
|
}
|
|
18113
18113
|
return { ...base, note: manual };
|
|
18114
18114
|
}
|
|
18115
|
+
var ALIGNMENT_LAND_POLL_MS = 15e3;
|
|
18116
|
+
var ALIGNMENT_LAND_TIMEOUT_MS = 20 * 6e4;
|
|
18117
|
+
async function awaitAlignmentLanded(deps, ctx, leg, base, opts = {}) {
|
|
18118
|
+
if (leg.status !== "pr-pending" || !leg.autoMergeEnqueued || leg.prNumber === void 0) return leg;
|
|
18119
|
+
const sleep2 = resolveSleep(deps);
|
|
18120
|
+
const now = deps.now ?? Date.now;
|
|
18121
|
+
const startedAt = now();
|
|
18122
|
+
const timeoutMs = opts.timeoutMs ?? ALIGNMENT_LAND_TIMEOUT_MS;
|
|
18123
|
+
const n = leg.prNumber;
|
|
18124
|
+
deps.warn?.(`watching alignment PR #${n} (${ctx.repo}) until it lands on ${base}`);
|
|
18125
|
+
for (; ; ) {
|
|
18126
|
+
let view;
|
|
18127
|
+
try {
|
|
18128
|
+
view = JSON.parse(await deps.run("gh", ["pr", "view", String(n), "--repo", ctx.repo, "--json", "state,mergeCommit"]));
|
|
18129
|
+
} catch (e) {
|
|
18130
|
+
deps.warn?.(`alignment PR #${n}: read failed (${describeReadError(e)}) \u2014 retrying`);
|
|
18131
|
+
}
|
|
18132
|
+
if (view?.state === "MERGED") {
|
|
18133
|
+
const oid = typeof view.mergeCommit?.oid === "string" ? view.mergeCommit.oid : void 0;
|
|
18134
|
+
let parents;
|
|
18135
|
+
if (oid) {
|
|
18136
|
+
try {
|
|
18137
|
+
parents = Number(clean2(await deps.run("gh", ["api", `repos/${ctx.repo}/commits/${oid}`, "--jq", ".parents | length"])));
|
|
18138
|
+
} catch {
|
|
18139
|
+
parents = void 0;
|
|
18140
|
+
}
|
|
18141
|
+
}
|
|
18142
|
+
if (parents === 1) {
|
|
18143
|
+
const squashNote = `alignment PR #${n} landed as a SQUASH (${oid?.slice(0, 12)} has one parent), not the true merge the Merge floor requires \u2014 re-align ${base} by true merge before the next train`;
|
|
18144
|
+
deps.warn?.(squashNote);
|
|
18145
|
+
return { ...leg, note: `${leg.note} \u2014 ${squashNote}` };
|
|
18146
|
+
}
|
|
18147
|
+
return { status: "aligned", alignment: "already-merged", prNumber: n, ...leg.prUrl ? { prUrl: leg.prUrl } : {}, note: `alignment PR #${n} landed on ${base} by true merge (watched)` };
|
|
18148
|
+
}
|
|
18149
|
+
if (view?.state === "CLOSED") {
|
|
18150
|
+
return { ...leg, note: `${leg.note} \u2014 alignment PR #${n} was CLOSED without merging; rerun the roll-forward` };
|
|
18151
|
+
}
|
|
18152
|
+
if (now() - startedAt >= timeoutMs) {
|
|
18153
|
+
deps.warn?.(`alignment PR #${n} still open after ${Math.round(timeoutMs / 6e4)}m \u2014 leaving the alignment leg pending; fold it later with mmi-cli devops release --resume --watch`);
|
|
18154
|
+
return leg;
|
|
18155
|
+
}
|
|
18156
|
+
await sleep2(ALIGNMENT_LAND_POLL_MS);
|
|
18157
|
+
}
|
|
18158
|
+
}
|
|
18115
18159
|
async function alignRcForward(deps, ctx, tag) {
|
|
18116
18160
|
await runGitRemoteRead(deps, ["fetch", "origin", "main", "rc"]);
|
|
18117
18161
|
const required = await discoverRequiredCheckContexts(deps, ctx, "rc");
|
|
@@ -22484,7 +22528,7 @@ async function recordRcandDeployLegs(ledger, deps, anchors, deployModel, d, opts
|
|
|
22484
22528
|
await recordPhase(ledger, deps, anchors, "alignment", phaseEntry({ state: "skipped", sha, note: "rcand aligns no branch \u2014 alignment rides the release" }), { ...opts, landed });
|
|
22485
22529
|
return dispatch;
|
|
22486
22530
|
}
|
|
22487
|
-
async function completeMainRelease(deps, ctx, meta, deployModel, watch, options, tag, releaseSha, startBranch, preFold, tagProbe, branchHints, ledger) {
|
|
22531
|
+
async function completeMainRelease(deps, ctx, meta, deployModel, watch, options, tag, releaseSha, startBranch, preFold, tagProbe, branchHints, ledger, alignEarly) {
|
|
22488
22532
|
const resumeCommand = options.dev ? "mmi-cli devops release --dev --apply" : "mmi-cli devops release --apply";
|
|
22489
22533
|
const ledgerAnchors = { repo: ctx.repo, tag, tagSha: releaseSha };
|
|
22490
22534
|
try {
|
|
@@ -22589,6 +22633,7 @@ ${recovery.note}`), recoveryInput);
|
|
|
22589
22633
|
await verifyPublishedRelease(deps, ctx.repo, tag, "main", releaseSha);
|
|
22590
22634
|
await recordPhase(ledger, deps, ledgerAnchors, "githubRelease", phaseEntry({ state: "complete", sha: releaseSha, runUrl: releaseUrl, note: `verified GitHub Release ${tag} against ${releaseSha.slice(0, 12)}` }), { landed: "the immutable tag, the green required-check wall, and the origin/main fast-forward" });
|
|
22591
22635
|
const announceNote = deps.announce ? (await deps.announce({ repo: ctx.repo, tag, summaryFile: options.announceSummaryFile })).note : void 0;
|
|
22636
|
+
let alignment = alignEarly ? await alignEarly() : void 0;
|
|
22592
22637
|
const autoRunSince = (deps.now ?? Date.now)();
|
|
22593
22638
|
const deployDispatch0 = await dispatchDeploy(deps, ctx, "main", "main", deployModel, watch, autoRunSince, releaseSha, "report", meta.publishDir);
|
|
22594
22639
|
const deployRunRepo = releaseRunRepoFor(deployModel, ctx.repo);
|
|
@@ -22633,7 +22678,13 @@ ${recovery.note}`), recoveryInput);
|
|
|
22633
22678
|
});
|
|
22634
22679
|
let dispatch = appendPublishDispatch(deployDispatch, publishDispatch);
|
|
22635
22680
|
if (publishSkipNote) dispatch = { ...dispatch, note: `${dispatch.note}; tenant-publish.yml skipped (${publishSkipNote})` };
|
|
22636
|
-
|
|
22681
|
+
if (watch && alignment) {
|
|
22682
|
+
alignment = {
|
|
22683
|
+
dev: await awaitAlignmentLanded(deps, ctx, alignment.dev, "development"),
|
|
22684
|
+
...alignment.rc ? { rc: await awaitAlignmentLanded(deps, ctx, alignment.rc, "rc") } : {}
|
|
22685
|
+
};
|
|
22686
|
+
}
|
|
22687
|
+
return { checks, releaseUrl, announceNote, dispatch, ledgerAnchors, ...alignment ? { alignment } : {} };
|
|
22637
22688
|
}
|
|
22638
22689
|
function resumeStateOf(status) {
|
|
22639
22690
|
return status === "complete" ? "aligned" : status;
|
|
@@ -23021,6 +23072,8 @@ ${recovery.note}`), recoveryInput);
|
|
|
23021
23072
|
steps.push("verified the Release published against the tagged commit");
|
|
23022
23073
|
await recordPhase(ledger, deps, anchors, "githubRelease", phaseEntry({ state: "complete", sha: tagSha, runUrl: releaseUrl, note: "verified the Release published against the tagged commit" }), { strict: ledgerMode === "strict", landed: "the immutable tag, the re-proven wall, and the origin/main push" });
|
|
23023
23074
|
const announceNote = deps.announce ? (await deps.announce({ repo: ctx.repo, tag, summaryFile: options.announceSummaryFile })).note : void 0;
|
|
23075
|
+
let devRollForward = await rollDevelopmentForward(deps, ctx, tag);
|
|
23076
|
+
let rcAlignment = !directTrack && branchHints.hasRcBranch ? await alignRcForward(deps, ctx, tag) : void 0;
|
|
23024
23077
|
const autoRunSince = (deps.now ?? Date.now)();
|
|
23025
23078
|
const deployDispatch0 = await dispatchDeploy(deps, ctx, "main", "main", deployModel, watch, autoRunSince, tagSha, "report", meta.publishDir);
|
|
23026
23079
|
const recoveredDeployDispatch = await recoverFailedDispatchPhase(
|
|
@@ -23056,9 +23109,11 @@ ${recovery.note}`), recoveryInput);
|
|
|
23056
23109
|
landed: "the immutable tag, the re-proven wall, origin/main, the verified GitHub Release, and the dispatched deploy path"
|
|
23057
23110
|
});
|
|
23058
23111
|
const dispatch = appendPublishDispatch(deployDispatch, publishDispatch);
|
|
23059
|
-
|
|
23112
|
+
if (watch) {
|
|
23113
|
+
devRollForward = await awaitAlignmentLanded(deps, ctx, devRollForward, "development");
|
|
23114
|
+
if (rcAlignment) rcAlignment = await awaitAlignmentLanded(deps, ctx, rcAlignment, "rc");
|
|
23115
|
+
}
|
|
23060
23116
|
steps.push(`development roll-forward: ${devRollForward.status}`);
|
|
23061
|
-
const rcAlignment = !directTrack && branchHints.hasRcBranch ? await alignRcForward(deps, ctx, tag) : void 0;
|
|
23062
23117
|
if (rcAlignment) steps.push(`rc alignment: ${rcAlignment.status}`);
|
|
23063
23118
|
const followUp = deriveTrainFollowUpStatus({
|
|
23064
23119
|
projectInfo: "ok",
|
|
@@ -23399,9 +23454,25 @@ ${spent.note}`), rcandRecovery(tag2));
|
|
|
23399
23454
|
const releaseSha3 = requireValue(clean2(await deps.run("git", ["rev-parse", "main"])), "release sha");
|
|
23400
23455
|
return { versionFold: versionFold3, releaseSha: releaseSha3 };
|
|
23401
23456
|
});
|
|
23402
|
-
const { checks: checks2, releaseUrl: releaseUrl2, announceNote: announceNote2, dispatch: d2, ledgerAnchors: ledgerAnchors2 } = await completeMainRelease(
|
|
23403
|
-
|
|
23404
|
-
|
|
23457
|
+
const { checks: checks2, releaseUrl: releaseUrl2, announceNote: announceNote2, dispatch: d2, ledgerAnchors: ledgerAnchors2, alignment: alignment2 } = await completeMainRelease(
|
|
23458
|
+
deps,
|
|
23459
|
+
ctx,
|
|
23460
|
+
meta,
|
|
23461
|
+
deployModel2,
|
|
23462
|
+
watch,
|
|
23463
|
+
options,
|
|
23464
|
+
tag2,
|
|
23465
|
+
releaseSha2,
|
|
23466
|
+
"development",
|
|
23467
|
+
preFold2,
|
|
23468
|
+
tagProbe2,
|
|
23469
|
+
branchHints,
|
|
23470
|
+
ledger,
|
|
23471
|
+
// #6468: alignment PRs open before the publish wait; rc aligns only on the --dev lane of a repo that has one.
|
|
23472
|
+
async () => ({ dev: await rollDevelopmentForward(deps, ctx, tag2), ...!directTrack && hasRcBranch ? { rc: await alignRcForward(deps, ctx, tag2) } : {} })
|
|
23473
|
+
);
|
|
23474
|
+
const devRollForward2 = alignment2?.dev ?? await rollDevelopmentForward(deps, ctx, tag2);
|
|
23475
|
+
await recordPhase(ledger, deps, ledgerAnchors2, "alignment", phaseEntry(alignmentPhaseEntry(devRollForward2, alignment2?.rc)), { landed: "the immutable tag, the green wall, origin/main, the verified Release, and the deploy/publish path" });
|
|
23405
23476
|
const ledgerReport2 = releaseLedgerReport(await ledger?.load(ledgerAnchors2).catch(() => void 0), ledger?.path ?? "(no ledger)");
|
|
23406
23477
|
if (directTrack) {
|
|
23407
23478
|
return {
|
|
@@ -23430,8 +23501,7 @@ ${spent.note}`), rcandRecovery(tag2));
|
|
|
23430
23501
|
};
|
|
23431
23502
|
}
|
|
23432
23503
|
const retirement2 = hasRcBranch ? await retireRcRuntime(deps, ctx, deployModel2, d2.deployStatus, rcShaAtRelease) : { status: "not-applicable", note: "no origin/rc branch \u2014 rc runtime retirement skipped" };
|
|
23433
|
-
const rcAlignment2 =
|
|
23434
|
-
await recordPhase(ledger, deps, ledgerAnchors2, "alignment", phaseEntry(alignmentPhaseEntry(devRollForward2, rcAlignment2)), { landed: "the immutable tag, the green wall, origin/main, the verified Release, and the deploy/publish path" });
|
|
23504
|
+
const rcAlignment2 = alignment2?.rc;
|
|
23435
23505
|
const fullLedgerReport = releaseLedgerReport(await ledger?.load(ledgerAnchors2).catch(() => void 0), ledger?.path ?? "(no ledger)");
|
|
23436
23506
|
const environments2 = await buildEnvironments(deps, ctx, deployModel2, d2.deployStatus, retirement2);
|
|
23437
23507
|
return {
|
|
@@ -23493,10 +23563,26 @@ ${spent.note}`), rcandRecovery(tag2));
|
|
|
23493
23563
|
const releaseSha2 = requireValue(clean2(await deps.run("git", ["rev-parse", "main"])), "release sha");
|
|
23494
23564
|
return { versionFold: versionFold2, releaseSha: releaseSha2 };
|
|
23495
23565
|
});
|
|
23496
|
-
const { checks, releaseUrl, announceNote, dispatch: d, ledgerAnchors } = await completeMainRelease(
|
|
23566
|
+
const { checks, releaseUrl, announceNote, dispatch: d, ledgerAnchors, alignment } = await completeMainRelease(
|
|
23567
|
+
deps,
|
|
23568
|
+
ctx,
|
|
23569
|
+
meta,
|
|
23570
|
+
deployModel,
|
|
23571
|
+
watch,
|
|
23572
|
+
options,
|
|
23573
|
+
tag,
|
|
23574
|
+
releaseSha,
|
|
23575
|
+
"rc",
|
|
23576
|
+
preFold,
|
|
23577
|
+
tagProbe,
|
|
23578
|
+
branchHints,
|
|
23579
|
+
ledger,
|
|
23580
|
+
// #6468: both alignment PRs open before the publish wait.
|
|
23581
|
+
async () => ({ dev: await rollDevelopmentForward(deps, ctx, tag), rc: await alignRcForward(deps, ctx, tag) })
|
|
23582
|
+
);
|
|
23497
23583
|
const retirement = await retireRcRuntime(deps, ctx, deployModel, d.deployStatus, releasedRcSha);
|
|
23498
|
-
const devRollForward = await rollDevelopmentForward(deps, ctx, tag);
|
|
23499
|
-
const rcAlignment = await alignRcForward(deps, ctx, tag);
|
|
23584
|
+
const devRollForward = alignment?.dev ?? await rollDevelopmentForward(deps, ctx, tag);
|
|
23585
|
+
const rcAlignment = alignment?.rc ?? await alignRcForward(deps, ctx, tag);
|
|
23500
23586
|
await recordPhase(ledger, deps, ledgerAnchors, "alignment", phaseEntry(alignmentPhaseEntry(devRollForward, rcAlignment)), { landed: "the immutable tag, the green wall, origin/main, the verified Release, and the deploy/publish path" });
|
|
23501
23587
|
const ledgerReport = releaseLedgerReport(await ledger?.load(ledgerAnchors).catch(() => void 0), ledger?.path ?? "(no ledger)");
|
|
23502
23588
|
const environments = await buildEnvironments(deps, ctx, deployModel, d.deployStatus, retirement);
|
|
@@ -44922,7 +45008,7 @@ project.command("list").description("list all projects (identity + board, never
|
|
|
44922
45008
|
console.log(`${p.slug ?? "?"} - ${p.name ?? ""}${p.division ? ` [${p.division}]` : ""}${p.class ? ` (${p.class})` : ""}${p.projectType ? ` <${p.projectType}>` : ""}${p.deployModel ? ` {${p.deployModel}}` : ""}`);
|
|
44923
45009
|
}
|
|
44924
45010
|
});
|
|
44925
|
-
project.command("get [owner/repo]").description("a project's META (board ids + pointers) by repo or slug; defaults to the current repo \u2014 identity, NOT deploy coords").option("--json", "machine-readable output").action(async (repoOrSlug
|
|
45011
|
+
project.command("get [owner/repo]").description("a project's META (board ids + pointers) by repo or slug; defaults to the current repo \u2014 identity, NOT deploy coords").option("--json", "machine-readable output").action(async (repoOrSlug) => {
|
|
44926
45012
|
const cfg = await loadConfig();
|
|
44927
45013
|
let target;
|
|
44928
45014
|
try {
|
|
@@ -44938,7 +45024,7 @@ project.command("get [owner/repo]").description("a project's META (board ids + p
|
|
|
44938
45024
|
return failGraceful(`org project get: no registry META for ${target} (unknown or unbootstrapped)`);
|
|
44939
45025
|
}
|
|
44940
45026
|
console.log(JSON.stringify(read.project));
|
|
44941
|
-
if (!
|
|
45027
|
+
if (!rawFlag("--json")) {
|
|
44942
45028
|
const m = read.project;
|
|
44943
45029
|
const track = resolveReleaseTrack(m, void 0, target);
|
|
44944
45030
|
const stages = branchesForTrack(track).join(" -> ");
|
package/package.json
CHANGED