@mutmutco/cli 2.5.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 +40 -9
- 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");
|
|
@@ -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.5.
|
|
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",
|