@mutmutco/cli 2.3.0 → 2.5.1
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/index.cjs +44 -13
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -4255,6 +4255,26 @@ function parseWorktreePorcelain(stdout) {
|
|
|
4255
4255
|
}
|
|
4256
4256
|
return out;
|
|
4257
4257
|
}
|
|
4258
|
+
function samePath(a, b) {
|
|
4259
|
+
return a.replace(/\\/g, "/").replace(/\/+$/, "").toLowerCase() === b.replace(/\\/g, "/").replace(/\/+$/, "").toLowerCase();
|
|
4260
|
+
}
|
|
4261
|
+
function selectPrMergeCleanupWorktree(branch, before, after, startingPath) {
|
|
4262
|
+
if (!branch) return void 0;
|
|
4263
|
+
const current = after.find((w) => w.branch === branch)?.path;
|
|
4264
|
+
if (current) return current;
|
|
4265
|
+
const previous = before.find((w) => w.branch === branch)?.path;
|
|
4266
|
+
if (previous) return previous;
|
|
4267
|
+
if (startingPath && before.some((w) => w.branch === branch && samePath(w.path, startingPath))) return startingPath;
|
|
4268
|
+
return void 0;
|
|
4269
|
+
}
|
|
4270
|
+
function selectSafeWorktreeCwd(worktrees, targetPath) {
|
|
4271
|
+
if (!targetPath) return void 0;
|
|
4272
|
+
return worktrees.find((w) => !samePath(w.path, targetPath))?.path;
|
|
4273
|
+
}
|
|
4274
|
+
function branchMissingFromList(branch, stdout) {
|
|
4275
|
+
const names = stdout.split(/\r?\n/).map((line) => line.replace(/^\*\s*/, "").trim()).filter(Boolean);
|
|
4276
|
+
return !names.includes(branch);
|
|
4277
|
+
}
|
|
4258
4278
|
function formatGcPlan(plan2, apply) {
|
|
4259
4279
|
const lines = [`mmi-cli gc: ${apply ? "apply" : "dry-run"}`];
|
|
4260
4280
|
if (!plan2.branches.length && !plan2.trackingRefs.length) lines.push("nothing to clean");
|
|
@@ -4705,9 +4725,9 @@ function requireValue(value, label) {
|
|
|
4705
4725
|
function releaseTagFromRcTag(tag) {
|
|
4706
4726
|
return tag.replace(/-rc\.\d+$/, "");
|
|
4707
4727
|
}
|
|
4708
|
-
async function
|
|
4728
|
+
async function verifyHubDistributionVersion(deps, model, releaseTag) {
|
|
4709
4729
|
if (model !== "hub-serverless") return;
|
|
4710
|
-
await deps.run("node", ["scripts/release-distribution.mjs", "verify
|
|
4730
|
+
await deps.run("node", ["scripts/release-distribution.mjs", "verify", releaseTag, "--skip-npm-view"]);
|
|
4711
4731
|
}
|
|
4712
4732
|
function ensurePositiveCount(out, emptyMessage) {
|
|
4713
4733
|
const count = Number.parseInt(out.trim(), 10);
|
|
@@ -4792,7 +4812,7 @@ async function runTrainApply(command, deps) {
|
|
|
4792
4812
|
);
|
|
4793
4813
|
const deployModel2 = await preflight(deps, ctx, "rc");
|
|
4794
4814
|
const tag2 = requireValue(clean(await deps.run("node", ["scripts/next-version.mjs", "rc"])), "rc tag");
|
|
4795
|
-
await
|
|
4815
|
+
await verifyHubDistributionVersion(deps, deployModel2, releaseTagFromRcTag(tag2));
|
|
4796
4816
|
await deps.run("git", ["checkout", "rc"]);
|
|
4797
4817
|
await deps.run("git", ["pull", "--ff-only", "origin", "rc"]);
|
|
4798
4818
|
await deps.run("git", ["merge", "development", "--no-edit"]);
|
|
@@ -4812,7 +4832,7 @@ async function runTrainApply(command, deps) {
|
|
|
4812
4832
|
await deps.run("git", ["pull", "--ff-only", "origin", "main"]);
|
|
4813
4833
|
await deps.run("git", ["merge", "rc", "--no-edit"]);
|
|
4814
4834
|
const tag = requireValue(clean(await deps.run("node", ["scripts/next-version.mjs", "release"])), "release tag");
|
|
4815
|
-
await
|
|
4835
|
+
await verifyHubDistributionVersion(deps, deployModel, tag);
|
|
4816
4836
|
await deps.run("git", ["tag", tag]);
|
|
4817
4837
|
await deps.run("git", ["push", "origin", "main"]);
|
|
4818
4838
|
await deps.run("git", ["push", "origin", tag]);
|
|
@@ -6312,24 +6332,31 @@ async function applyGcPlan(plan2, remote) {
|
|
|
6312
6332
|
await execFileP3("git", ["worktree", "prune"], { timeout: GIT_TIMEOUT_MS });
|
|
6313
6333
|
}
|
|
6314
6334
|
}
|
|
6315
|
-
async function cleanupLocalBranch(branch) {
|
|
6335
|
+
async function cleanupLocalBranch(branch, before = {}) {
|
|
6316
6336
|
const result = { branchDeleted: false };
|
|
6317
6337
|
if (!branch) return result;
|
|
6318
6338
|
const { stdout } = await execFileP3("git", ["worktree", "list", "--porcelain"], { timeout: GIT_TIMEOUT_MS });
|
|
6319
|
-
const
|
|
6320
|
-
|
|
6321
|
-
|
|
6339
|
+
const afterWorktrees = parseWorktreePorcelain(stdout);
|
|
6340
|
+
const wtPath = selectPrMergeCleanupWorktree(branch, before.worktrees ?? [], afterWorktrees, before.startingPath);
|
|
6341
|
+
const safeCwd = selectSafeWorktreeCwd([...afterWorktrees, ...before.worktrees ?? []], wtPath);
|
|
6342
|
+
const git = (args) => safeCwd ? execFileP3("git", ["-C", safeCwd, ...args], { timeout: GIT_TIMEOUT_MS }) : execFileP3("git", args, { timeout: GIT_TIMEOUT_MS });
|
|
6343
|
+
if (wtPath) {
|
|
6344
|
+
await git(["worktree", "remove", "--force", wtPath]).catch(() => {
|
|
6322
6345
|
});
|
|
6323
|
-
result.worktreeRemoved =
|
|
6346
|
+
result.worktreeRemoved = wtPath;
|
|
6324
6347
|
}
|
|
6325
|
-
const current = await gitOut(["rev-parse", "--abbrev-ref", "HEAD"]) || "";
|
|
6348
|
+
const current = safeCwd ? ((await git(["rev-parse", "--abbrev-ref", "HEAD"]).catch(() => ({ stdout: "" }))).stdout || "").trim() : await gitOut(["rev-parse", "--abbrev-ref", "HEAD"]) || "";
|
|
6326
6349
|
if (branch !== current) {
|
|
6327
|
-
await
|
|
6350
|
+
await git(["branch", "-D", branch]).then(() => {
|
|
6328
6351
|
result.branchDeleted = true;
|
|
6329
6352
|
}).catch(() => {
|
|
6330
6353
|
});
|
|
6354
|
+
if (!result.branchDeleted) {
|
|
6355
|
+
const remaining = await git(["branch", "--list", branch]).catch(() => ({ stdout: "" }));
|
|
6356
|
+
result.branchDeleted = branchMissingFromList(branch, remaining.stdout || "");
|
|
6357
|
+
}
|
|
6331
6358
|
}
|
|
6332
|
-
if (
|
|
6359
|
+
if (wtPath) await git(["worktree", "prune"]).catch(() => {
|
|
6333
6360
|
});
|
|
6334
6361
|
return result;
|
|
6335
6362
|
}
|
|
@@ -7015,10 +7042,14 @@ pr.command("merge <number>").description("merge a PR (squash by default) and cle
|
|
|
7015
7042
|
const method = o.rebase ? "--rebase" : o.merge ? "--merge" : "--squash";
|
|
7016
7043
|
const repoArgs = o.repo ? ["--repo", o.repo] : [];
|
|
7017
7044
|
const headRef = (await execFileP3("gh", ["pr", "view", number, ...repoArgs, "--json", "headRefName", "--jq", ".headRefName"], { timeout: GC_GH_TIMEOUT_MS })).stdout.trim();
|
|
7045
|
+
const startingPath = (await execFileP3("git", ["rev-parse", "--show-toplevel"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim();
|
|
7046
|
+
const beforeWorktrees = parseWorktreePorcelain(
|
|
7047
|
+
(await execFileP3("git", ["worktree", "list", "--porcelain"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout
|
|
7048
|
+
);
|
|
7018
7049
|
await execFileP3("gh", ["pr", "merge", number, ...repoArgs, method, "--delete-branch"], { timeout: GC_GH_TIMEOUT_MS }).catch((e) => {
|
|
7019
7050
|
if (!/used by worktree|cannot delete branch|already been merged/i.test(String(e.message || ""))) throw e;
|
|
7020
7051
|
});
|
|
7021
|
-
const cleaned = repoArgs.length ? { branchDeleted: false } : await cleanupLocalBranch(headRef);
|
|
7052
|
+
const cleaned = repoArgs.length ? { branchDeleted: false } : await cleanupLocalBranch(headRef, { worktrees: beforeWorktrees, startingPath });
|
|
7022
7053
|
console.log(JSON.stringify({ merged: number, branch: headRef, method: method.slice(2), ...cleaned }));
|
|
7023
7054
|
});
|
|
7024
7055
|
async function runBoardRead(o) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mutmutco/cli",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.5.1",
|
|
4
4
|
"description": "MMI Future CLI — delivers the org rules (whole-file), plus saga and KB access. The cross-IDE engine the plugin's SessionStart hook drives.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "UNLICENSED",
|