@mutmutco/cli 4.1.11 → 4.1.12
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 +89 -14
- package/package.json +1 -1
package/dist/main.cjs
CHANGED
|
@@ -13152,10 +13152,10 @@ var rollout_plan_default = {
|
|
|
13152
13152
|
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)."
|
|
13153
13153
|
},
|
|
13154
13154
|
baseline: {
|
|
13155
|
-
version: "4.1.
|
|
13156
|
-
tag: "v4.1.
|
|
13157
|
-
commit: "
|
|
13158
|
-
npm: "@mutmutco/cli@4.1.
|
|
13155
|
+
version: "4.1.12",
|
|
13156
|
+
tag: "v4.1.12",
|
|
13157
|
+
commit: "306701c103b7",
|
|
13158
|
+
npm: "@mutmutco/cli@4.1.12"
|
|
13159
13159
|
},
|
|
13160
13160
|
exitCriterion: "fleet-n-of-n",
|
|
13161
13161
|
hubOnlyShortcut: "forbidden",
|
|
@@ -13172,14 +13172,14 @@ var rollout_plan_default = {
|
|
|
13172
13172
|
repo: "mutmutco/mmi-hub",
|
|
13173
13173
|
role: "canary",
|
|
13174
13174
|
schedule: "train",
|
|
13175
|
-
v3Target: "v4.1.
|
|
13175
|
+
v3Target: "v4.1.12"
|
|
13176
13176
|
}
|
|
13177
13177
|
],
|
|
13178
13178
|
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.",
|
|
13179
13179
|
rollback: {
|
|
13180
13180
|
independent: true,
|
|
13181
|
-
mechanism: "npm dist-tag latest -> 4.1.
|
|
13182
|
-
v3Target: "v4.1.
|
|
13181
|
+
mechanism: "npm dist-tag latest -> 4.1.12 and redeploy the Hub Lambda from tag v4.1.12 (306701c103b7); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
|
|
13182
|
+
v3Target: "v4.1.12 (@mutmutco/cli@4.1.12, tag commit 306701c103b7 \u2014 last known-good release carrying the repo-index v4-only contract)"
|
|
13183
13183
|
}
|
|
13184
13184
|
},
|
|
13185
13185
|
{
|
|
@@ -17338,6 +17338,9 @@ async function completeMainRelease(deps, ctx, meta, deployModel, watch, options,
|
|
|
17338
17338
|
let tagPush;
|
|
17339
17339
|
try {
|
|
17340
17340
|
await assertComputedReleaseTagStillNext(deps, tag);
|
|
17341
|
+
if (deployModel === "hub-serverless") {
|
|
17342
|
+
await deps.run("node", ["scripts/release-distribution.mjs", "assert-release-lineage", tag.replace(/^v/, ""), "--release-commit", releaseSha]);
|
|
17343
|
+
}
|
|
17341
17344
|
tagPush = await ensureTagPushed(deps, tag, releaseSha, tagProbe, ctx.repo);
|
|
17342
17345
|
} catch (e) {
|
|
17343
17346
|
throw await recoverFailedFold(deps, e, startBranch, preFold.mainSha, resumeCommand);
|
|
@@ -24450,6 +24453,9 @@ async function runHotfixRelease(deps, versionInput, options = {}) {
|
|
|
24450
24453
|
}
|
|
24451
24454
|
const required = await discoverRequiredCheckContexts(deps, ctx, "main");
|
|
24452
24455
|
assertTagAddressableRequiredContexts(deps, required, ctx.repo);
|
|
24456
|
+
if (deployModel === "hub-serverless") {
|
|
24457
|
+
await deps.run("node", ["scripts/release-distribution.mjs", "assert-release-lineage", version, "--release-commit", mergedSha]);
|
|
24458
|
+
}
|
|
24453
24459
|
const tagPush = await ensureTagPushed(deps, tag, mergedSha);
|
|
24454
24460
|
const tagPushSince = Date.now();
|
|
24455
24461
|
const tagNote = tagPush.note;
|
|
@@ -33658,6 +33664,27 @@ function selectSafeWorktreeCwd(worktrees, targetPath, options) {
|
|
|
33658
33664
|
const exists = options?.pathExists ?? (() => true);
|
|
33659
33665
|
return worktrees.find((w) => !samePath(w.path, targetPath) && exists(w.path))?.path;
|
|
33660
33666
|
}
|
|
33667
|
+
function formatGitCommandError(e) {
|
|
33668
|
+
if (!(e instanceof Error)) return String(e);
|
|
33669
|
+
const err = e;
|
|
33670
|
+
const stderr = typeof err.stderr === "string" ? err.stderr.trim() : "";
|
|
33671
|
+
const stdout = typeof err.stdout === "string" ? err.stdout.trim() : "";
|
|
33672
|
+
const message = err.message.trim();
|
|
33673
|
+
if (stderr) return stderr;
|
|
33674
|
+
if (message && !/^Command failed:/i.test(message)) return message;
|
|
33675
|
+
if (stdout) return stdout;
|
|
33676
|
+
return message || "git command failed";
|
|
33677
|
+
}
|
|
33678
|
+
function isWorktreePathRegistered(worktrees, wtPath) {
|
|
33679
|
+
return worktrees.some((w) => samePath(w.path, wtPath));
|
|
33680
|
+
}
|
|
33681
|
+
function isNotAWorkingTreeMessage(error) {
|
|
33682
|
+
return /is not a working tree/i.test(error);
|
|
33683
|
+
}
|
|
33684
|
+
function formatWorktreeRemovalFailureDetail(options) {
|
|
33685
|
+
const detail = options.removeError.trim() || "git worktree remove exited nonzero";
|
|
33686
|
+
return `${detail}; registered=${options.registered ? "yes" : "no"}; pathExists=${options.pathExists ? "yes" : "no"}; path=${options.wtPath}`;
|
|
33687
|
+
}
|
|
33661
33688
|
async function resolveMergeBaseTimestampMs(git3, baseRef, branch) {
|
|
33662
33689
|
try {
|
|
33663
33690
|
const mergeBase = (await git3(["merge-base", baseRef, branch])).trim();
|
|
@@ -33685,14 +33712,52 @@ async function teardownWorktreeStage(worktreePath) {
|
|
|
33685
33712
|
return { status: "failed", error: e instanceof Error ? e.message : String(e) };
|
|
33686
33713
|
}
|
|
33687
33714
|
}
|
|
33688
|
-
async function
|
|
33689
|
-
|
|
33690
|
-
|
|
33715
|
+
async function removeWorktreeWithReconcile(wtPath, git3, listWorktrees, pathExists) {
|
|
33716
|
+
const attemptRemove = async () => {
|
|
33717
|
+
try {
|
|
33718
|
+
await git3(["worktree", "remove", "--force", wtPath]);
|
|
33719
|
+
return void 0;
|
|
33720
|
+
} catch (e) {
|
|
33721
|
+
return formatGitCommandError(e);
|
|
33722
|
+
}
|
|
33723
|
+
};
|
|
33724
|
+
const firstError = await attemptRemove();
|
|
33725
|
+
if (!firstError) {
|
|
33691
33726
|
await git3(["worktree", "prune"]).catch(() => "");
|
|
33692
33727
|
return { status: "removed" };
|
|
33693
|
-
} catch (e) {
|
|
33694
|
-
return { status: "failed", error: e instanceof Error ? e.message : String(e) };
|
|
33695
33728
|
}
|
|
33729
|
+
let worktrees = await listWorktrees().catch(() => []);
|
|
33730
|
+
if (!isWorktreePathRegistered(worktrees, wtPath)) {
|
|
33731
|
+
await git3(["worktree", "prune"]).catch(() => "");
|
|
33732
|
+
return { status: "removed", reason: "reconciled-unregistered" };
|
|
33733
|
+
}
|
|
33734
|
+
const retryError = await attemptRemove();
|
|
33735
|
+
if (!retryError) {
|
|
33736
|
+
await git3(["worktree", "prune"]).catch(() => "");
|
|
33737
|
+
return { status: "removed", reason: "reconciled-after-retry" };
|
|
33738
|
+
}
|
|
33739
|
+
if (isNotAWorkingTreeMessage(retryError) || isNotAWorkingTreeMessage(firstError)) {
|
|
33740
|
+
worktrees = await listWorktrees().catch(() => worktrees);
|
|
33741
|
+
if (!isWorktreePathRegistered(worktrees, wtPath)) {
|
|
33742
|
+
await git3(["worktree", "prune"]).catch(() => "");
|
|
33743
|
+
return { status: "removed", reason: "reconciled-not-a-working-tree" };
|
|
33744
|
+
}
|
|
33745
|
+
}
|
|
33746
|
+
worktrees = await listWorktrees().catch(() => worktrees);
|
|
33747
|
+
const registered = isWorktreePathRegistered(worktrees, wtPath);
|
|
33748
|
+
if (!registered) {
|
|
33749
|
+
await git3(["worktree", "prune"]).catch(() => "");
|
|
33750
|
+
return { status: "removed", reason: "reconciled-unregistered" };
|
|
33751
|
+
}
|
|
33752
|
+
return {
|
|
33753
|
+
status: "failed",
|
|
33754
|
+
error: formatWorktreeRemovalFailureDetail({
|
|
33755
|
+
removeError: retryError || firstError,
|
|
33756
|
+
registered,
|
|
33757
|
+
pathExists: pathExists(wtPath),
|
|
33758
|
+
wtPath
|
|
33759
|
+
})
|
|
33760
|
+
};
|
|
33696
33761
|
}
|
|
33697
33762
|
async function cleanupPrMergeLocalBranch(branch, options) {
|
|
33698
33763
|
const report = { branch };
|
|
@@ -33797,7 +33862,12 @@ async function cleanupPrMergeLocalBranch(branch, options) {
|
|
|
33797
33862
|
report.localBranch = { name: branch, status: "not-attempted", reason: "archive-failed" };
|
|
33798
33863
|
return report;
|
|
33799
33864
|
}
|
|
33800
|
-
const removal = await
|
|
33865
|
+
const removal = await removeWorktreeWithReconcile(
|
|
33866
|
+
wtPath,
|
|
33867
|
+
git3,
|
|
33868
|
+
async () => parseGitWorktreePorcelain(await execGit(["worktree", "list", "--porcelain"])),
|
|
33869
|
+
pathExists
|
|
33870
|
+
);
|
|
33801
33871
|
if (removal.status === "failed") {
|
|
33802
33872
|
report.worktree = {
|
|
33803
33873
|
path: wtPath,
|
|
@@ -33813,6 +33883,7 @@ async function cleanupPrMergeLocalBranch(branch, options) {
|
|
|
33813
33883
|
report.worktree = {
|
|
33814
33884
|
path: wtPath,
|
|
33815
33885
|
status: "removed",
|
|
33886
|
+
...removal.reason ? { reason: removal.reason } : {},
|
|
33816
33887
|
artifactsArchive,
|
|
33817
33888
|
stageTeardown,
|
|
33818
33889
|
tmpEvidenceCount: tmpEvidence.length
|
|
@@ -33831,7 +33902,11 @@ function renderPrMergeCleanupLines(cleanup) {
|
|
|
33831
33902
|
if (!wt?.path) return [];
|
|
33832
33903
|
const lines = [];
|
|
33833
33904
|
if (wt.status === "removed") {
|
|
33834
|
-
|
|
33905
|
+
if (wt.reason?.startsWith("reconciled")) {
|
|
33906
|
+
lines.push(`pr merge: worktree ${wt.path} remove reported failure but git no longer registers it \u2014 deleted local branch`);
|
|
33907
|
+
} else {
|
|
33908
|
+
lines.push(`pr merge: removed worktree ${wt.path} \u2014 that directory is gone; cd elsewhere before your next command`);
|
|
33909
|
+
}
|
|
33835
33910
|
} else if (wt.status === "refused") {
|
|
33836
33911
|
lines.push(`pr merge: worktree ${wt.path} kept \u2014 ${wt.reason ?? "refused"}${wt.error ? `: ${wt.error}` : ""}`);
|
|
33837
33912
|
if (wt.tmpEvidenceCount) lines.push(`pr merge: ${wt.tmpEvidenceCount} tmp path(s) newer than branch base would have been destroyed`);
|
package/package.json
CHANGED