@mutmutco/cli 3.105.7 → 3.105.8
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 +92 -17
- package/package.json +1 -1
package/dist/main.cjs
CHANGED
|
@@ -11392,11 +11392,11 @@ async function installAppFoldDeps(deps) {
|
|
|
11392
11392
|
const hasLock = await deps.run("git", ["cat-file", "-e", "HEAD:package-lock.json"]).then(() => true).catch(() => false);
|
|
11393
11393
|
await deps.run("npm", hasLock ? ["ci"] : ["install"]);
|
|
11394
11394
|
}
|
|
11395
|
-
async function foldReleaseVersion(deps, model, tag, foldPaths) {
|
|
11395
|
+
async function foldReleaseVersion(deps, model, tag, foldPaths, sourceCommit = "HEAD") {
|
|
11396
11396
|
if (foldPaths.length === 0) return "no version manifest to fold \u2014 the tag is the version";
|
|
11397
11397
|
const version = tag.replace(/^v/, "");
|
|
11398
11398
|
if (model === "hub-serverless") {
|
|
11399
|
-
await deps.run("node", ["scripts/release-distribution.mjs", "prepare", version, "--source-commit",
|
|
11399
|
+
await deps.run("node", ["scripts/release-distribution.mjs", "prepare", version, "--source-commit", sourceCommit]);
|
|
11400
11400
|
} else {
|
|
11401
11401
|
await installAppFoldDeps(deps);
|
|
11402
11402
|
await deps.run("npm", ["version", version, "--no-git-tag-version", "--allow-same-version"]);
|
|
@@ -20516,7 +20516,14 @@ async function runHotfixStart(deps, options) {
|
|
|
20516
20516
|
notes.push(`deleted stale origin/${branch} left by the incomplete train`);
|
|
20517
20517
|
}
|
|
20518
20518
|
}
|
|
20519
|
-
const
|
|
20519
|
+
const specs = splitCarrySpecs([options.from]);
|
|
20520
|
+
if (specs.length === 0) throw new Error("hotfix start: --from named no PR or SHA");
|
|
20521
|
+
const sources = [];
|
|
20522
|
+
for (const spec of specs) {
|
|
20523
|
+
const resolved = await resolveHotfixSource(deps, ctx, spec);
|
|
20524
|
+
if (!sources.some((s) => s.sha === resolved.sha)) sources.push(resolved);
|
|
20525
|
+
}
|
|
20526
|
+
const label = sources.map((s) => s.label).join(", ");
|
|
20520
20527
|
const foldPaths = deployModel === "hub-serverless" || deployModel === "registry-publish" ? await resolveFoldPaths(deps, deployModel) : [];
|
|
20521
20528
|
const pickTolerated = deployModel === "hub-serverless" ? [...foldPaths, ...HOTFIX_SKILL_TOLERATED_ROOTS] : foldPaths;
|
|
20522
20529
|
if (deployModel === "hub-serverless") {
|
|
@@ -20532,9 +20539,11 @@ async function runHotfixStart(deps, options) {
|
|
|
20532
20539
|
const preexistingLocal = clean3(await deps.run("git", ["branch", "--list", branch]));
|
|
20533
20540
|
await deps.run("git", ["checkout", "-B", branch, "origin/main"]);
|
|
20534
20541
|
try {
|
|
20535
|
-
const
|
|
20536
|
-
|
|
20537
|
-
|
|
20542
|
+
for (const source of sources) {
|
|
20543
|
+
const autoResolved = await cherryPickWithToleratedPaths(deps, source.sha, pickTolerated);
|
|
20544
|
+
if (autoResolved.length > 0) {
|
|
20545
|
+
notes.push(`auto-resolved regenerable cherry-pick conflict(s) for ${source.label}: ${autoResolved.join(", ")} (regenerated in bump step)`);
|
|
20546
|
+
}
|
|
20538
20547
|
}
|
|
20539
20548
|
} catch (e) {
|
|
20540
20549
|
const recovery = await restoreAfterFailedPort(deps, { startBranch, branch, created: !preexistingLocal });
|
|
@@ -20575,10 +20584,12 @@ async function runHotfixStart(deps, options) {
|
|
|
20575
20584
|
branch,
|
|
20576
20585
|
"--title",
|
|
20577
20586
|
`[hotfix] ${tag}`,
|
|
20587
|
+
// Every picked sha goes in the marker (#4411) — `hotfix release` reads it when --carries is omitted,
|
|
20588
|
+
// so a multi-fix cycle proves ALL of its targets present before tagging, not just the first.
|
|
20578
20589
|
"--body",
|
|
20579
20590
|
`Hotfix ${tag}: cherry-pick of ${label} onto origin/main${bumpNote}.
|
|
20580
20591
|
|
|
20581
|
-
<!-- mmi-hotfix-carries: ${sha} -->
|
|
20592
|
+
<!-- mmi-hotfix-carries: ${sources.map((s) => s.sha).join(",")} -->
|
|
20582
20593
|
|
|
20583
20594
|
Merge this PR (human-initiated), then run \`mmi-cli hotfix release ${tag}\`.`
|
|
20584
20595
|
]));
|
|
@@ -20621,6 +20632,61 @@ async function watchReleaseRun(deps, ctx, workflow, sha) {
|
|
|
20621
20632
|
}
|
|
20622
20633
|
return { workflow, conclusion: "not-found" };
|
|
20623
20634
|
}
|
|
20635
|
+
function devFoldBranch(tag) {
|
|
20636
|
+
return `hotfix-fold/${tag}`;
|
|
20637
|
+
}
|
|
20638
|
+
async function portFoldToDevelopment(deps, ctx, deployModel, tag) {
|
|
20639
|
+
const foldPaths = deployModel === "hub-serverless" || deployModel === "registry-publish" ? await resolveFoldPaths(deps, deployModel) : [];
|
|
20640
|
+
if (foldPaths.length === 0) return `fold port skipped (deployModel=${deployModel} folds no version manifest)`;
|
|
20641
|
+
const branch = devFoldBranch(tag);
|
|
20642
|
+
const listed = await deps.run("gh", [
|
|
20643
|
+
"pr",
|
|
20644
|
+
"list",
|
|
20645
|
+
"--repo",
|
|
20646
|
+
ctx.repo,
|
|
20647
|
+
"--head",
|
|
20648
|
+
branch,
|
|
20649
|
+
"--base",
|
|
20650
|
+
"development",
|
|
20651
|
+
"--state",
|
|
20652
|
+
"all",
|
|
20653
|
+
"--limit",
|
|
20654
|
+
"10",
|
|
20655
|
+
"--json",
|
|
20656
|
+
"number,state,url"
|
|
20657
|
+
]);
|
|
20658
|
+
const existing = JSON.parse(listed || "[]").filter((r) => r.state === "OPEN" || r.state === "MERGED").sort((a, b) => (b.number ?? 0) - (a.number ?? 0))[0];
|
|
20659
|
+
if (existing) return `development fold PR #${existing.number} for ${tag} is ${existing.state} \u2014 reused`;
|
|
20660
|
+
const previousRef = clean3(await deps.run("git", ["rev-parse", "--abbrev-ref", "HEAD"]));
|
|
20661
|
+
try {
|
|
20662
|
+
await deps.run("git", ["fetch", "origin", "development"]);
|
|
20663
|
+
await deps.run("git", ["checkout", "-B", branch, "origin/development"]);
|
|
20664
|
+
const durableSource = clean3(await deps.run("git", ["merge-base", "HEAD", "origin/development"]));
|
|
20665
|
+
const foldNote = await foldReleaseVersion(deps, deployModel, tag, foldPaths, durableSource);
|
|
20666
|
+
const committed = clean3(await deps.run("git", ["rev-list", "--count", "origin/development..HEAD"]));
|
|
20667
|
+
if (committed === "0") return `development already carries ${tag} \u2014 no fold PR needed (${foldNote})`;
|
|
20668
|
+
await deps.run("git", ["push", "-u", "origin", branch]);
|
|
20669
|
+
const prUrl = clean3(await deps.run("gh", [
|
|
20670
|
+
"pr",
|
|
20671
|
+
"create",
|
|
20672
|
+
"--repo",
|
|
20673
|
+
ctx.repo,
|
|
20674
|
+
"--base",
|
|
20675
|
+
"development",
|
|
20676
|
+
"--head",
|
|
20677
|
+
branch,
|
|
20678
|
+
"--title",
|
|
20679
|
+
`chore(release): port the ${tag} version fold to development`,
|
|
20680
|
+
"--body",
|
|
20681
|
+
`Regenerated version fold for ${tag} (#4410). \`main\` carries the released version; without this development declares the previous one and every PR into it fails catalog-lockstep.
|
|
20682
|
+
|
|
20683
|
+
Generated by \`mmi-cli hotfix release\` \u2014 no main-parented commit is merged in, so the squash parents stay clean (#4365/#4371).`
|
|
20684
|
+
]));
|
|
20685
|
+
return `opened development fold PR ${prUrl} (${foldNote})`;
|
|
20686
|
+
} finally {
|
|
20687
|
+
if (previousRef && previousRef !== "HEAD") await deps.run("git", ["checkout", previousRef]).catch(() => void 0);
|
|
20688
|
+
}
|
|
20689
|
+
}
|
|
20624
20690
|
async function runHotfixRelease(deps, versionInput, options = {}) {
|
|
20625
20691
|
const ctx = await buildTrainApplyContext(deps);
|
|
20626
20692
|
const deployModel = await resolveHotfixDeployModel(deps, ctx);
|
|
@@ -20746,6 +20812,12 @@ async function runHotfixRelease(deps, versionInput, options = {}) {
|
|
|
20746
20812
|
} else {
|
|
20747
20813
|
verifyNote = `distribution verify skipped (deployModel=${deployModel}, Hub-only step)`;
|
|
20748
20814
|
}
|
|
20815
|
+
let foldNote;
|
|
20816
|
+
try {
|
|
20817
|
+
foldNote = await portFoldToDevelopment(deps, ctx, deployModel, tag);
|
|
20818
|
+
} catch (e) {
|
|
20819
|
+
foldNote = `development fold port FAILED: ${e.message ?? e} \u2014 the release stands; port it by hand: git checkout -B ${devFoldBranch(tag)} origin/development && node scripts/release-distribution.mjs prepare ${version}, then open a development-base PR`;
|
|
20820
|
+
}
|
|
20749
20821
|
return {
|
|
20750
20822
|
...ctx,
|
|
20751
20823
|
command: "hotfix-release",
|
|
@@ -20758,6 +20830,7 @@ async function runHotfixRelease(deps, versionInput, options = {}) {
|
|
|
20758
20830
|
runs,
|
|
20759
20831
|
deployNote,
|
|
20760
20832
|
verifyNote,
|
|
20833
|
+
foldNote,
|
|
20761
20834
|
announceNote
|
|
20762
20835
|
};
|
|
20763
20836
|
}
|
|
@@ -31099,8 +31172,8 @@ var LOOP_PLAYBOOKS = {
|
|
|
31099
31172
|
{ label: "Read the next board item", command: "mmi-cli board read" },
|
|
31100
31173
|
{ label: "Claim it and create an isolated worktree", command: "mmi-cli worktree create <issue-number> --claim --from origin/development" },
|
|
31101
31174
|
{ label: "Build and test in the touched package", command: "npm test && npm run build" },
|
|
31102
|
-
{ label: "Publish the branch", command: "git push
|
|
31103
|
-
{ label: "Open the development-base PR", command: 'mmi-cli pr create --title "<title>" --body-file PR_BODY.md --base development' },
|
|
31175
|
+
{ label: "Publish the branch", command: "git push origin <branch>:<branch>" },
|
|
31176
|
+
{ label: "Open the development-base PR", command: 'mmi-cli pr create --title "<title>" --body-file .jerv/PR_BODY.md --base development' },
|
|
31104
31177
|
{ label: "Wait for checks and land to development", command: "mmi-cli pr checks-wait <PR-number> && mmi-cli pr land <PR-number>" },
|
|
31105
31178
|
{ label: "Release only after the gated train is authorized", command: "mmi-cli release --apply" }
|
|
31106
31179
|
]
|
|
@@ -31117,8 +31190,8 @@ var LOOP_PLAYBOOKS = {
|
|
|
31117
31190
|
"ship-pr": {
|
|
31118
31191
|
title: "Ship PR",
|
|
31119
31192
|
steps: [
|
|
31120
|
-
{ label: "Publish the branch", command: "git push
|
|
31121
|
-
{ label: "Open the development-base PR", command: 'mmi-cli pr create --title "<title>" --body-file PR_BODY.md --base development' },
|
|
31193
|
+
{ label: "Publish the branch", command: "git push origin <branch>:<branch>" },
|
|
31194
|
+
{ label: "Open the development-base PR", command: 'mmi-cli pr create --title "<title>" --body-file .jerv/PR_BODY.md --base development' },
|
|
31122
31195
|
{ label: "Wait for CI checks", command: "mmi-cli pr checks-wait <PR-number>" },
|
|
31123
31196
|
{ label: "Land the PR (merge to development)", command: "mmi-cli pr land <PR-number>" }
|
|
31124
31197
|
]
|
|
@@ -31126,9 +31199,9 @@ var LOOP_PLAYBOOKS = {
|
|
|
31126
31199
|
"hotfix": {
|
|
31127
31200
|
title: "Hotfix",
|
|
31128
31201
|
steps: [
|
|
31129
|
-
{ label: "Create the main-base hotfix PR from
|
|
31202
|
+
{ label: "Create the main-base hotfix PR from every already-merged fix this cycle carries", command: "mmi-cli hotfix start --from <pr#|sha>[,<pr#|sha>...]" },
|
|
31130
31203
|
{ label: "Wait for the hotfix PR checks", command: "mmi-cli pr checks-wait <PR-number>" },
|
|
31131
|
-
{ label: "After the PR is merged, run the gated release", command: "mmi-cli hotfix release <vX.Y.Z> --carries <pr#|sha>" }
|
|
31204
|
+
{ label: "After the PR is merged, run the gated release", command: "mmi-cli hotfix release <vX.Y.Z> --carries <pr#|sha>[,<pr#|sha>...]" }
|
|
31132
31205
|
]
|
|
31133
31206
|
}
|
|
31134
31207
|
};
|
|
@@ -36747,10 +36820,11 @@ withExamples(pr.command("create").description("create a PR and print {number,url
|
|
|
36747
36820
|
console.log(JSON.stringify(created));
|
|
36748
36821
|
}), [
|
|
36749
36822
|
'mmi-cli pr create --title "Add the schema" --body "Closes #2680"',
|
|
36750
|
-
'mmi-cli pr create --title "Add the schema" --body-file PR_BODY.md --draft'
|
|
36823
|
+
'mmi-cli pr create --title "Add the schema" --body-file .jerv/PR_BODY.md --draft'
|
|
36751
36824
|
], [
|
|
36752
36825
|
"--head and --base default to the current branch and the repo default; only pass them to override.",
|
|
36753
|
-
"Use --body-file for multiline PR bodies instead of shell-escaped inline markdown."
|
|
36826
|
+
"Use --body-file for multiline PR bodies instead of shell-escaped inline markdown.",
|
|
36827
|
+
"Write that file under .jerv/ inside a worktree (#4405): any other untracked path makes `worktree land` refuse cleanup as untracked-files."
|
|
36754
36828
|
]);
|
|
36755
36829
|
pr.command("view <number>").description("read a PR as structured JSON (merged state, head/base, URL, merge commit) ? the mmi-cli read path (#2347). --comments folds in every comment; --context also adds linkedIssues (the issues it closes/references, #2894)").option("--repo <owner/repo>", "target repo (defaults to the current repo)").option("--json [fields...]", 'gh --json field list (overrides the default field set). Accepts commas, spaces, or repeated --json flags ? in PowerShell an unquoted comma list is an array literal, so QUOTE it: --json "state,baseRefName,mergeCommit"').option("--comments", "include every comment (body + comments in one call) ? read the whole PR before landing it (#2894)").option("--context", "full working context in one call: implies --comments and also adds linkedIssues (the issues the PR closes/references) (#2894)").action(async (number, o) => {
|
|
36756
36830
|
const n = Number(number);
|
|
@@ -37515,7 +37589,8 @@ function renderHotfixRelease(r) {
|
|
|
37515
37589
|
...r.runs.map((run) => ` - ${run.workflow}: ${run.conclusion}${run.url ? ` (${run.url})` : ""}`),
|
|
37516
37590
|
` - ${r.verifyNote}`,
|
|
37517
37591
|
...r.announceNote ? [` - announce: ${r.announceNote}`] : [],
|
|
37518
|
-
` -
|
|
37592
|
+
` - fold: ${r.foldNote}`,
|
|
37593
|
+
` - next: mmi-cli hotfix status ${r.tag} (no back-merge of the FIX ? development already has it; the version fold above is ported for you, #4410)`
|
|
37519
37594
|
].join("\n");
|
|
37520
37595
|
}
|
|
37521
37596
|
function renderHotfixStatus(r) {
|
|
@@ -37547,7 +37622,7 @@ var hotfixCmd = program2.command("hotfix").description("stepwise hotfix orchestr
|
|
|
37547
37622
|
const steps = trainPlan("hotfix");
|
|
37548
37623
|
console.log(o.json ? JSON.stringify({ command: "hotfix", steps }, null, 2) : renderSteps("mmi-cli hotfix: dry-run plan", steps));
|
|
37549
37624
|
});
|
|
37550
|
-
hotfixCmd.command("start").description("cherry-pick
|
|
37625
|
+
hotfixCmd.command("start").description("cherry-pick one or more merged development PRs (or SHAs) onto hotfix/vX.Y.Z from origin/main, bump the distribution, open the main-base PR").requiredOption("--from <pr#|sha[,pr#|sha...]>", "merged development PR number(s) or commit SHA(s) to cherry-pick, in pick order \u2014 one hotfix cycle carries as many fixes as you name (#4411)").option("--json", "machine-readable output").action(async (o) => runHotfixSub("start", () => runHotfixStart(trainApplyDeps(), { from: o.from }), o.json, renderHotfixStart));
|
|
37551
37626
|
hotfixCmd.command("release <version>").description("after the hotfix PR is merged + checks green: tag, GitHub Release, watch deploy/publish, verify distribution (idempotent)").option("--json", "machine-readable output").option("--announce-summary-file <path>", "agent-curated summary lines for the Hub Slack announcement (#883)").option("--carries <pr#|sha[,pr#|sha...]>", "declared fix target(s) this hotfix must carry; each must be proven present before tagging (#3056)").action(async (version, o) => runHotfixSub("release", () => runHotfixRelease(trainApplyDeps(), version, { announceSummaryFile: o.announceSummaryFile, carries: o.carries ? [o.carries] : [] }), o.json, renderHotfixRelease));
|
|
37552
37627
|
hotfixCmd.command("status [version]").description("derive the full hotfix pipeline state from live git/gh reads and name the exact next subcommand").option("--json", "machine-readable output").action(async (version, o) => runHotfixSub("status", () => runHotfixStatus(trainApplyDeps(), version), o.json, renderHotfixStatus));
|
|
37553
37628
|
var ci = program2.command("ci").description("org CI + merge-readiness audit and reconcile");
|
package/package.json
CHANGED