@mutmutco/cli 3.83.0 → 3.85.0
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 +225 -107
- package/package.json +1 -1
package/dist/main.cjs
CHANGED
|
@@ -3415,7 +3415,7 @@ function useColor() {
|
|
|
3415
3415
|
var program = new Command();
|
|
3416
3416
|
|
|
3417
3417
|
// src/index.ts
|
|
3418
|
-
var
|
|
3418
|
+
var import_promises11 = require("node:fs/promises");
|
|
3419
3419
|
var import_node_fs36 = require("node:fs");
|
|
3420
3420
|
var import_node_child_process16 = require("node:child_process");
|
|
3421
3421
|
|
|
@@ -3982,10 +3982,10 @@ var import_node_fs4 = require("node:fs");
|
|
|
3982
3982
|
var injectedStdin;
|
|
3983
3983
|
function stdinHasPipedInput(statFd = () => (0, import_node_fs4.fstatSync)(0), getIsTTY = () => process.stdin.isTTY) {
|
|
3984
3984
|
try {
|
|
3985
|
-
const
|
|
3986
|
-
if (
|
|
3987
|
-
if (
|
|
3988
|
-
if (
|
|
3985
|
+
const stat3 = statFd();
|
|
3986
|
+
if (stat3.isFIFO() || stat3.isFile()) return true;
|
|
3987
|
+
if (stat3.isCharacterDevice()) return false;
|
|
3988
|
+
if (stat3.isSocket()) return false;
|
|
3989
3989
|
if (getIsTTY() === true) return false;
|
|
3990
3990
|
return true;
|
|
3991
3991
|
} catch {
|
|
@@ -4502,9 +4502,9 @@ function trackedPathStatus(c, realPath, repoAnchor) {
|
|
|
4502
4502
|
return null;
|
|
4503
4503
|
}
|
|
4504
4504
|
}
|
|
4505
|
-
function rootScratchDirSnapshot(root, readdir2,
|
|
4505
|
+
function rootScratchDirSnapshot(root, readdir2, stat3) {
|
|
4506
4506
|
try {
|
|
4507
|
-
const rootStat =
|
|
4507
|
+
const rootStat = stat3(root);
|
|
4508
4508
|
let mtimeMs = rootStat.mtimeMs;
|
|
4509
4509
|
let bytes = 0;
|
|
4510
4510
|
const stack = [root];
|
|
@@ -4518,7 +4518,7 @@ function rootScratchDirSnapshot(root, readdir2, stat2) {
|
|
|
4518
4518
|
return null;
|
|
4519
4519
|
} catch {
|
|
4520
4520
|
}
|
|
4521
|
-
const st =
|
|
4521
|
+
const st = stat3(child2);
|
|
4522
4522
|
mtimeMs = Math.max(mtimeMs, st.mtimeMs);
|
|
4523
4523
|
if (ent.isDirectory()) stack.push(child2);
|
|
4524
4524
|
else if (ent.isFile()) bytes += st.size;
|
|
@@ -4531,7 +4531,7 @@ function rootScratchDirSnapshot(root, readdir2, stat2) {
|
|
|
4531
4531
|
}
|
|
4532
4532
|
function collectScratchSnapshot(repoRoot2, deps = {}) {
|
|
4533
4533
|
const readdir2 = deps.readdir ?? import_node_fs6.readdirSync;
|
|
4534
|
-
const
|
|
4534
|
+
const stat3 = deps.stat ?? import_node_fs6.statSync;
|
|
4535
4535
|
const plansRoot = (0, import_node_path4.join)(repoRoot2, "plans");
|
|
4536
4536
|
const rootScratchFiles = [];
|
|
4537
4537
|
try {
|
|
@@ -4544,10 +4544,10 @@ function collectScratchSnapshot(repoRoot2, deps = {}) {
|
|
|
4544
4544
|
const full = (0, import_node_path4.join)(repoRoot2, ent.name);
|
|
4545
4545
|
try {
|
|
4546
4546
|
if (isDir) {
|
|
4547
|
-
const snap = rootScratchDirSnapshot(full, readdir2,
|
|
4547
|
+
const snap = rootScratchDirSnapshot(full, readdir2, stat3);
|
|
4548
4548
|
if (snap) rootScratchFiles.push({ path: full, dir: repoRoot2, name: ent.name, mtimeMs: snap.mtimeMs, bytes: snap.bytes, kind: "dir" });
|
|
4549
4549
|
} else {
|
|
4550
|
-
const st =
|
|
4550
|
+
const st = stat3(full);
|
|
4551
4551
|
rootScratchFiles.push({ path: full, dir: repoRoot2, name: ent.name, mtimeMs: st.mtimeMs, bytes: st.size, kind: "file" });
|
|
4552
4552
|
}
|
|
4553
4553
|
} catch {
|
|
@@ -4561,7 +4561,7 @@ function collectScratchSnapshot(repoRoot2, deps = {}) {
|
|
|
4561
4561
|
if (!ent.isFile() || !ent.name.endsWith(".md")) continue;
|
|
4562
4562
|
const full = (0, import_node_path4.join)(plansRoot, ent.name);
|
|
4563
4563
|
try {
|
|
4564
|
-
const st =
|
|
4564
|
+
const st = stat3(full);
|
|
4565
4565
|
planMdFiles.push({ path: full, dir: plansRoot, name: ent.name, mtimeMs: st.mtimeMs, bytes: st.size, kind: "file" });
|
|
4566
4566
|
} catch {
|
|
4567
4567
|
}
|
|
@@ -7978,6 +7978,7 @@ function parseVerifyBroker(stdout) {
|
|
|
7978
7978
|
|
|
7979
7979
|
// src/train-apply.ts
|
|
7980
7980
|
var import_node_fs13 = require("node:fs");
|
|
7981
|
+
var import_promises2 = require("node:fs/promises");
|
|
7981
7982
|
var import_node_path12 = require("node:path");
|
|
7982
7983
|
function resolveDeployModel2(meta, repo) {
|
|
7983
7984
|
const m = meta?.deployModel;
|
|
@@ -8624,16 +8625,33 @@ function partialTrainRecoveryError(cause, input) {
|
|
|
8624
8625
|
const resumeCommand = input.stage === "rc" ? "mmi-cli rcand --resume" : "mmi-cli release --resume";
|
|
8625
8626
|
const tenant2 = input.deployModel === "tenant-container";
|
|
8626
8627
|
const deployLine = tenant2 ? ` - deploy: dispatched by the train after the branch push; recover with \`mmi-cli runtime tenant redeploy ${input.repo} ${input.stage} --watch\` once the branch and release exist.` : ` - deploy: this repo is \`${input.deployModel ?? "not tenant-container"}\` \u2014 it has NO tenant runtime. Its own release/main-push workflows publish and deploy once the branch and Release exist. Do NOT run the tenant redeployer.`;
|
|
8627
|
-
|
|
8628
|
-
`${causeMessage}
|
|
8629
|
-
|
|
8630
|
-
partial train state for ${input.tag}:
|
|
8628
|
+
const stateBlock = `partial train state for ${input.tag}:
|
|
8631
8629
|
- tag ${input.tag}: PUSHED to origin
|
|
8632
8630
|
- origin/${branch}: NOT pushed
|
|
8633
8631
|
- ${releaseState}
|
|
8634
|
-
` + deployLine
|
|
8632
|
+
` + deployLine;
|
|
8633
|
+
const failedHubMainGate = input.stage === "main" && input.repo.toLowerCase() === HUB_REPO.toLowerCase() && /^required train check failed:/i.test(causeMessage);
|
|
8634
|
+
if (failedHubMainGate) {
|
|
8635
|
+
return new Error(
|
|
8636
|
+
`${causeMessage}
|
|
8637
|
+
|
|
8638
|
+
` + stateBlock + `
|
|
8639
|
+
|
|
8640
|
+
The tag is public and immutable, but it FAILED a required gate. Do not resume it unchanged: \`${resumeCommand}\` cannot alter tagged code or make the failed check pass.
|
|
8635
8641
|
|
|
8636
|
-
|
|
8642
|
+
Diagnose the failed check, then choose the proven recovery:
|
|
8643
|
+
- transient workflow failure: rerun the failed tag workflow; only after it passes, use \`${resumeCommand}\`.
|
|
8644
|
+
- tagged-code defect: obtain fresh destructive approval to remove ${input.tag}, run \`mmi-cli release --abort --apply\`, repair development, and cut the release again through the guarded train.
|
|
8645
|
+
|
|
8646
|
+
Do not push main or create the GitHub Release by hand.`
|
|
8647
|
+
);
|
|
8648
|
+
}
|
|
8649
|
+
return new Error(
|
|
8650
|
+
`${causeMessage}
|
|
8651
|
+
|
|
8652
|
+
` + stateBlock + `
|
|
8653
|
+
|
|
8654
|
+
The tag is public and immutable \u2014 do not delete or force-move it.
|
|
8637
8655
|
|
|
8638
8656
|
Resume it: ${resumeCommand}
|
|
8639
8657
|
|
|
@@ -8998,35 +9016,41 @@ async function executeMergeToMain(deps, sourceRef, mergeLabel, tolerated, predic
|
|
|
8998
9016
|
}
|
|
8999
9017
|
}
|
|
9000
9018
|
async function probeFoldFailureState(deps) {
|
|
9001
|
-
const branch = await currentBranch(deps);
|
|
9019
|
+
const branch = await currentBranch(deps).catch(() => "");
|
|
9002
9020
|
const mergeInProgress = await deps.run("git", ["rev-parse", "-q", "--verify", "MERGE_HEAD"]).then(() => true).catch(() => false);
|
|
9003
|
-
const
|
|
9021
|
+
const headSha = await deps.run("git", ["rev-parse", "HEAD"]).then(clean2).catch(() => "");
|
|
9022
|
+
const status = await deps.run("git", ["status", "--porcelain=v1"]).then(clean2).catch((e) => `(unavailable: ${e instanceof Error ? e.message : String(e)})`);
|
|
9004
9023
|
const mainSha = await deps.run("git", ["rev-parse", "main"]).then(clean2).catch(() => "");
|
|
9005
9024
|
const originMainSha = await deps.run("git", ["rev-parse", "origin/main"]).then(clean2).catch(() => "");
|
|
9006
9025
|
const originIsAncestorOfMain = Boolean(mainSha) && Boolean(originMainSha) ? await deps.run("git", ["merge-base", "--is-ancestor", "origin/main", "main"]).then(() => true).catch(() => false) : false;
|
|
9007
|
-
return { branch, mergeInProgress,
|
|
9026
|
+
return { branch, mergeInProgress, headSha, status, mainSha, originMainSha, originIsAncestorOfMain };
|
|
9008
9027
|
}
|
|
9009
9028
|
function shaLabel(sha) {
|
|
9010
9029
|
return sha ? sha.slice(0, 7) : "(unknown)";
|
|
9011
9030
|
}
|
|
9012
|
-
async function finishFoldAutoRestore(deps, causeMessage, startBranch, what) {
|
|
9031
|
+
async function finishFoldAutoRestore(deps, causeMessage, startBranch, preFoldMainSha, resumeCommand, what) {
|
|
9013
9032
|
try {
|
|
9014
9033
|
await deps.run("git", ["checkout", startBranch]);
|
|
9015
9034
|
} catch (e) {
|
|
9016
|
-
return
|
|
9035
|
+
return foldFailureGuidance(
|
|
9017
9036
|
`${causeMessage}
|
|
9018
9037
|
|
|
9019
|
-
fold failed; ${what}, but returning to ${startBranch} afterwards failed: ${e instanceof Error ? e.message : String(e)}
|
|
9038
|
+
fold failed; ${what}, but returning to ${startBranch} afterwards failed: ${e instanceof Error ? e.message : String(e)}.`,
|
|
9039
|
+
await probeFoldFailureState(deps),
|
|
9040
|
+
startBranch,
|
|
9041
|
+
preFoldMainSha,
|
|
9042
|
+
`git checkout ${startBranch}`,
|
|
9043
|
+
resumeCommand
|
|
9020
9044
|
);
|
|
9021
9045
|
}
|
|
9022
9046
|
return new Error(
|
|
9023
9047
|
`${causeMessage}
|
|
9024
9048
|
|
|
9025
|
-
fold failed; ${what} and the checkout was returned to ${startBranch}. Nothing was pushed to origin and no tag was created \u2014 rerun
|
|
9049
|
+
fold failed; ${what} and the checkout was returned to ${startBranch}. Nothing was pushed to origin and no tag was created \u2014 rerun with \`${resumeCommand}\` once the fold issue above is fixed.`
|
|
9026
9050
|
);
|
|
9027
9051
|
}
|
|
9028
|
-
function foldFailureGuidance(causeMessage, probe, startBranch, preFoldMainSha) {
|
|
9029
|
-
const steps = preFoldMainSha ? [
|
|
9052
|
+
function foldFailureGuidance(causeMessage, probe, startBranch, preFoldMainSha, nextCommand, resumeCommand = "mmi-cli release --apply", foldStarted = true) {
|
|
9053
|
+
const steps = !foldStarted ? [` 1. Resolve or wait out the git index lock`, ` 2. ${resumeCommand}`] : nextCommand === "git merge --abort" ? [` 1. git merge --abort`, ` 2. git checkout ${startBranch}`, ` 3. ${resumeCommand}`] : nextCommand === `git checkout ${startBranch}` ? [` 1. git checkout ${startBranch}`, ` 2. ${resumeCommand}`] : preFoldMainSha ? [
|
|
9030
9054
|
` 1. git status # inspect what is actually there`,
|
|
9031
9055
|
` 2. git log --oneline ${preFoldMainSha}..main # commits beyond the pre-fold main \u2014 confirm they are only this run's merge/fold attempt`,
|
|
9032
9056
|
` 3. git checkout main && git reset --hard ${preFoldMainSha} # back to the exact commit the fold built on`,
|
|
@@ -9036,14 +9060,60 @@ function foldFailureGuidance(causeMessage, probe, startBranch, preFoldMainSha) {
|
|
|
9036
9060
|
` 2. git log --oneline origin/main..main # this run never committed to main (it failed before the merge) \u2014 any commits here predate this run; preserve them`,
|
|
9037
9061
|
` 3. git checkout ${startBranch}`
|
|
9038
9062
|
];
|
|
9063
|
+
const exactNextCommand = nextCommand ?? "git status";
|
|
9039
9064
|
return new Error(
|
|
9040
9065
|
`${causeMessage}
|
|
9041
9066
|
|
|
9042
|
-
fold failed leaving the checkout in a state train --apply will not auto-restore (branch=${probe.branch || "(unknown)"},
|
|
9067
|
+
fold failed leaving the checkout in a state train --apply will not auto-restore (branch=${probe.branch || "(unknown)"}, main=${shaLabel(probe.mainSha)}, origin/main=${shaLabel(probe.originMainSha)}, pre-fold main=${preFoldMainSha ? shaLabel(preFoldMainSha) : "not captured"}, origin/main is${probe.originIsAncestorOfMain ? "" : " NOT"} an ancestor of main). Nothing was pushed to origin and no tag was created.
|
|
9068
|
+
Resumable state:
|
|
9069
|
+
current branch: ${probe.branch || "(unknown)"}
|
|
9070
|
+
HEAD: ${probe.headSha || "(unknown)"}
|
|
9071
|
+
pre-fold main: ${preFoldMainSha || "(not captured)"}
|
|
9072
|
+
index/worktree status:
|
|
9073
|
+
${probe.status || "(clean)"}
|
|
9074
|
+
Next command: ${exactNextCommand}
|
|
9075
|
+
Resume command after the checkout is clean: ${resumeCommand}
|
|
9043
9076
|
Recovery sequence:
|
|
9044
9077
|
${steps.join("\n")}`
|
|
9045
9078
|
);
|
|
9046
9079
|
}
|
|
9080
|
+
var GIT_INDEX_LOCK_WAIT_MS = 5e3;
|
|
9081
|
+
var GIT_INDEX_LOCK_POLL_MS = 100;
|
|
9082
|
+
async function waitForFoldIndexLock(deps, startBranch, resumeCommand) {
|
|
9083
|
+
const preFoldMainSha = await deps.run("git", ["rev-parse", "main"]).then(clean2).catch(() => void 0);
|
|
9084
|
+
const lockPath = requireValue(clean2(await deps.run("git", ["rev-parse", "--git-path", "index.lock"])), "git index lock path");
|
|
9085
|
+
const now = deps.now ?? Date.now;
|
|
9086
|
+
const sleep3 = resolveSleep(deps);
|
|
9087
|
+
const deadline = now() + GIT_INDEX_LOCK_WAIT_MS;
|
|
9088
|
+
for (; ; ) {
|
|
9089
|
+
try {
|
|
9090
|
+
await (0, import_promises2.stat)(lockPath);
|
|
9091
|
+
} catch (e) {
|
|
9092
|
+
if (e.code === "ENOENT") return;
|
|
9093
|
+
throw foldFailureGuidance(
|
|
9094
|
+
`release fold could not inspect git index lock ${lockPath}: ${e instanceof Error ? e.message : String(e)}`,
|
|
9095
|
+
await probeFoldFailureState(deps),
|
|
9096
|
+
startBranch,
|
|
9097
|
+
preFoldMainSha,
|
|
9098
|
+
resumeCommand,
|
|
9099
|
+
resumeCommand,
|
|
9100
|
+
false
|
|
9101
|
+
);
|
|
9102
|
+
}
|
|
9103
|
+
if (now() >= deadline) {
|
|
9104
|
+
throw foldFailureGuidance(
|
|
9105
|
+
`release fold waited ${GIT_INDEX_LOCK_WAIT_MS}ms for active git index lock ${lockPath}; it is still held. The fold did not start. Do not delete the lock; let its owning git process finish.`,
|
|
9106
|
+
await probeFoldFailureState(deps),
|
|
9107
|
+
startBranch,
|
|
9108
|
+
preFoldMainSha,
|
|
9109
|
+
resumeCommand,
|
|
9110
|
+
resumeCommand,
|
|
9111
|
+
false
|
|
9112
|
+
);
|
|
9113
|
+
}
|
|
9114
|
+
await sleep3(Math.min(GIT_INDEX_LOCK_POLL_MS, Math.max(1, deadline - now())));
|
|
9115
|
+
}
|
|
9116
|
+
}
|
|
9047
9117
|
async function recoverFailedRcand(deps, cause, preRcSha) {
|
|
9048
9118
|
const causeMessage = cause instanceof Error ? cause.message : String(cause);
|
|
9049
9119
|
const branch = await currentBranch(deps).catch(() => "");
|
|
@@ -9087,23 +9157,25 @@ Recovery sequence:
|
|
|
9087
9157
|
3. mmi-cli rcand --apply`
|
|
9088
9158
|
);
|
|
9089
9159
|
}
|
|
9090
|
-
async function recoverFailedFold(deps, cause, startBranch, preFoldMainSha) {
|
|
9160
|
+
async function recoverFailedFold(deps, cause, startBranch, preFoldMainSha, resumeCommand) {
|
|
9091
9161
|
const causeMessage = cause instanceof Error ? cause.message : String(cause);
|
|
9092
9162
|
const probe = await probeFoldFailureState(deps);
|
|
9093
9163
|
if (probe.mergeInProgress) {
|
|
9094
9164
|
try {
|
|
9095
9165
|
await deps.run("git", ["merge", "--abort"]);
|
|
9096
9166
|
} catch (e) {
|
|
9097
|
-
return
|
|
9167
|
+
return foldFailureGuidance(
|
|
9098
9168
|
`${causeMessage}
|
|
9099
9169
|
|
|
9100
|
-
fold failed with an in-progress merge
|
|
9101
|
-
|
|
9102
|
-
|
|
9103
|
-
|
|
9170
|
+
fold failed with an in-progress merge; automatic \`git merge --abort\` failed: ${e instanceof Error ? e.message : String(e)}.`,
|
|
9171
|
+
await probeFoldFailureState(deps),
|
|
9172
|
+
startBranch,
|
|
9173
|
+
preFoldMainSha,
|
|
9174
|
+
"git merge --abort",
|
|
9175
|
+
resumeCommand
|
|
9104
9176
|
);
|
|
9105
9177
|
}
|
|
9106
|
-
return finishFoldAutoRestore(deps, causeMessage, startBranch, "the in-progress merge was aborted");
|
|
9178
|
+
return finishFoldAutoRestore(deps, causeMessage, startBranch, preFoldMainSha, resumeCommand, "the in-progress merge was aborted");
|
|
9107
9179
|
}
|
|
9108
9180
|
if (probe.branch === "main" && preFoldMainSha) {
|
|
9109
9181
|
const mainDescendsFromPreFold = await deps.run("git", ["merge-base", "--is-ancestor", preFoldMainSha, "main"]).then(() => true).catch(() => false);
|
|
@@ -9111,13 +9183,15 @@ Recovery sequence:
|
|
|
9111
9183
|
try {
|
|
9112
9184
|
await deps.run("git", ["reset", "--hard", preFoldMainSha]);
|
|
9113
9185
|
} catch (e) {
|
|
9114
|
-
return
|
|
9186
|
+
return foldFailureGuidance(
|
|
9115
9187
|
`${causeMessage}
|
|
9116
9188
|
|
|
9117
|
-
fold failed after this run's merge/fold committed locally on main
|
|
9118
|
-
|
|
9119
|
-
|
|
9120
|
-
|
|
9189
|
+
fold failed after this run's merge/fold committed locally on main; automatic \`git reset --hard ${shaLabel(preFoldMainSha)}\` failed: ${e instanceof Error ? e.message : String(e)}.`,
|
|
9190
|
+
await probeFoldFailureState(deps),
|
|
9191
|
+
startBranch,
|
|
9192
|
+
preFoldMainSha,
|
|
9193
|
+
`git reset --hard ${preFoldMainSha}`,
|
|
9194
|
+
resumeCommand
|
|
9121
9195
|
);
|
|
9122
9196
|
}
|
|
9123
9197
|
const aheadNote = probe.originMainSha && preFoldMainSha !== probe.originMainSha ? `; local main carried commit(s) origin/main (${shaLabel(probe.originMainSha)}) does not have \u2014 they were preserved` : "";
|
|
@@ -9125,17 +9199,20 @@ Recovery sequence:
|
|
|
9125
9199
|
deps,
|
|
9126
9200
|
causeMessage,
|
|
9127
9201
|
startBranch,
|
|
9202
|
+
preFoldMainSha,
|
|
9203
|
+
resumeCommand,
|
|
9128
9204
|
`local main was reset to its pre-fold state ${shaLabel(preFoldMainSha)} (discarding only this run's merge/fold commit(s) at ${shaLabel(probe.mainSha)})${aheadNote}`
|
|
9129
9205
|
);
|
|
9130
9206
|
}
|
|
9131
9207
|
}
|
|
9132
|
-
return foldFailureGuidance(causeMessage, probe, startBranch, preFoldMainSha);
|
|
9208
|
+
return foldFailureGuidance(causeMessage, probe, startBranch, preFoldMainSha, void 0, resumeCommand);
|
|
9133
9209
|
}
|
|
9134
|
-
async function runFoldStage(deps, startBranch, preFold, fn) {
|
|
9210
|
+
async function runFoldStage(deps, startBranch, preFold, resumeCommand, fn) {
|
|
9211
|
+
await waitForFoldIndexLock(deps, startBranch, resumeCommand);
|
|
9135
9212
|
try {
|
|
9136
9213
|
return await fn();
|
|
9137
9214
|
} catch (e) {
|
|
9138
|
-
throw await recoverFailedFold(deps, e, startBranch, preFold.mainSha);
|
|
9215
|
+
throw await recoverFailedFold(deps, e, startBranch, preFold.mainSha, resumeCommand);
|
|
9139
9216
|
}
|
|
9140
9217
|
}
|
|
9141
9218
|
async function verifyPublishDryRun(deps, ctx, meta, deployModel) {
|
|
@@ -9194,30 +9271,31 @@ async function gateTrueMergeCommit(deps, ctx, tag, releaseSha, requiredChecks) {
|
|
|
9194
9271
|
}
|
|
9195
9272
|
}
|
|
9196
9273
|
async function completeMainRelease(deps, ctx, meta, deployModel, watch, options, tag, releaseSha, startBranch, preFold, tagProbe) {
|
|
9274
|
+
const resumeCommand = options.dev ? "mmi-cli release --dev --apply" : "mmi-cli release --apply";
|
|
9197
9275
|
try {
|
|
9198
9276
|
await verifyPublishDryRun(deps, ctx, meta, deployModel);
|
|
9199
9277
|
} catch (e) {
|
|
9200
|
-
throw await recoverFailedFold(deps, e, startBranch, preFold.mainSha);
|
|
9278
|
+
throw await recoverFailedFold(deps, e, startBranch, preFold.mainSha, resumeCommand);
|
|
9201
9279
|
}
|
|
9202
9280
|
let requiredChecks;
|
|
9203
9281
|
try {
|
|
9204
9282
|
requiredChecks = await discoverRequiredCheckContexts(deps, ctx, "main");
|
|
9205
9283
|
} catch (e) {
|
|
9206
|
-
throw await recoverFailedFold(deps, e, startBranch, preFold.mainSha);
|
|
9284
|
+
throw await recoverFailedFold(deps, e, startBranch, preFold.mainSha, resumeCommand);
|
|
9207
9285
|
}
|
|
9208
9286
|
let trueMergeGateNote;
|
|
9209
9287
|
if (preFold.isTrueMerge) {
|
|
9210
9288
|
try {
|
|
9211
9289
|
trueMergeGateNote = await gateTrueMergeCommit(deps, ctx, tag, releaseSha, requiredChecks);
|
|
9212
9290
|
} catch (e) {
|
|
9213
|
-
throw await recoverFailedFold(deps, e, startBranch, preFold.mainSha);
|
|
9291
|
+
throw await recoverFailedFold(deps, e, startBranch, preFold.mainSha, resumeCommand);
|
|
9214
9292
|
}
|
|
9215
9293
|
}
|
|
9216
9294
|
let tagPush;
|
|
9217
9295
|
try {
|
|
9218
9296
|
tagPush = await ensureTagPushed(deps, tag, releaseSha, tagProbe, ctx.repo);
|
|
9219
9297
|
} catch (e) {
|
|
9220
|
-
throw await recoverFailedFold(deps, e, startBranch, preFold.mainSha);
|
|
9298
|
+
throw await recoverFailedFold(deps, e, startBranch, preFold.mainSha, resumeCommand);
|
|
9221
9299
|
}
|
|
9222
9300
|
const tagPushSince = (deps.now ?? Date.now)();
|
|
9223
9301
|
let checks;
|
|
@@ -9623,7 +9701,8 @@ async function runTrainApplyPipeline(mode, input) {
|
|
|
9623
9701
|
);
|
|
9624
9702
|
const tagProbe2 = { remoteSha: await probeRemoteTag(deps, tag2) };
|
|
9625
9703
|
const preFold2 = {};
|
|
9626
|
-
const
|
|
9704
|
+
const resumeCommand = options.dev ? "mmi-cli release --dev --apply" : "mmi-cli release --apply";
|
|
9705
|
+
const { versionFold: versionFold2, releaseSha: releaseSha2 } = await runFoldStage(deps, "development", preFold2, resumeCommand, async () => {
|
|
9627
9706
|
await executeMergeToMain(deps, "development", "development -> main", tolerated2, predicted2, preFold2);
|
|
9628
9707
|
const versionFold3 = await foldReleaseVersion(deps, deployModel2, tag2, foldPaths2);
|
|
9629
9708
|
const releaseSha3 = requireValue(clean2(await deps.run("git", ["rev-parse", "main"])), "release sha");
|
|
@@ -9708,7 +9787,7 @@ async function runTrainApplyPipeline(mode, input) {
|
|
|
9708
9787
|
const tag = requireValue(clean2(await deps.run("node", ["scripts/next-version.mjs", "release"])), "release tag");
|
|
9709
9788
|
const tagProbe = { remoteSha: await probeRemoteTag(deps, tag) };
|
|
9710
9789
|
const preFold = {};
|
|
9711
|
-
const { versionFold, releaseSha } = await runFoldStage(deps, "rc", preFold, async () => {
|
|
9790
|
+
const { versionFold, releaseSha } = await runFoldStage(deps, "rc", preFold, "mmi-cli release --apply", async () => {
|
|
9712
9791
|
await executeMergeToMain(deps, "rc", "rc -> main", tolerated, predicted, preFold);
|
|
9713
9792
|
const versionFold2 = await foldReleaseVersion(deps, deployModel, tag, foldPaths);
|
|
9714
9793
|
const releaseSha2 = requireValue(clean2(await deps.run("git", ["rev-parse", "main"])), "release sha");
|
|
@@ -12186,7 +12265,7 @@ var import_node_child_process6 = require("node:child_process");
|
|
|
12186
12265
|
var import_node_os4 = require("node:os");
|
|
12187
12266
|
|
|
12188
12267
|
// src/gh-create.ts
|
|
12189
|
-
var
|
|
12268
|
+
var import_promises3 = require("node:fs/promises");
|
|
12190
12269
|
var import_node_os3 = require("node:os");
|
|
12191
12270
|
var import_node_path14 = require("node:path");
|
|
12192
12271
|
var import_node_crypto3 = require("node:crypto");
|
|
@@ -12238,9 +12317,9 @@ async function bodyArgsViaFile(args, deps = {}) {
|
|
|
12238
12317
|
const i = args.indexOf("--body");
|
|
12239
12318
|
if (i === -1 || i + 1 >= args.length) return { args, cleanup: async () => {
|
|
12240
12319
|
} };
|
|
12241
|
-
const write = deps.write ??
|
|
12242
|
-
const remove2 = deps.remove ??
|
|
12243
|
-
const ensureDir = deps.ensureDir ??
|
|
12320
|
+
const write = deps.write ?? import_promises3.writeFile;
|
|
12321
|
+
const remove2 = deps.remove ?? import_promises3.unlink;
|
|
12322
|
+
const ensureDir = deps.ensureDir ?? import_promises3.mkdir;
|
|
12244
12323
|
const dir = deps.dir ?? (0, import_node_os3.tmpdir)();
|
|
12245
12324
|
const file = (0, import_node_path14.join)(dir, `mmi-gh-body-${process.pid}-${(0, import_node_crypto3.randomBytes)(4).toString("hex")}.md`);
|
|
12246
12325
|
await ensureDir((0, import_node_path14.dirname)(file), { recursive: true }).catch(() => {
|
|
@@ -20987,7 +21066,7 @@ function formatBoxTable(boxes) {
|
|
|
20987
21066
|
const addrW = w((b) => b.address || "(no public ipv4)", "ADDRESS");
|
|
20988
21067
|
const projW = w((b) => b.project, "PROJECT");
|
|
20989
21068
|
const statW = w((b) => b.status, "STATUS");
|
|
20990
|
-
const row = (name, addr, proj,
|
|
21069
|
+
const row = (name, addr, proj, stat3, key) => `${name.padEnd(nameW)} ${addr.padEnd(addrW)} ${proj.padEnd(projW)} ${stat3.padEnd(statW)} ${key}`;
|
|
20991
21070
|
const lines = [row("BOX", "ADDRESS", "PROJECT", "STATUS", "SSH KEY (vault path)")];
|
|
20992
21071
|
for (const b of boxes) {
|
|
20993
21072
|
lines.push(row(b.name, b.address || "(no public ipv4)", b.project, b.status, b.sshKeyPath));
|
|
@@ -21125,7 +21204,7 @@ ${SSH_RECIPE_AGENT_NOTE}`);
|
|
|
21125
21204
|
}
|
|
21126
21205
|
|
|
21127
21206
|
// src/schedules-commands.ts
|
|
21128
|
-
var
|
|
21207
|
+
var import_promises4 = require("node:fs/promises");
|
|
21129
21208
|
var import_node_child_process13 = require("node:child_process");
|
|
21130
21209
|
var import_node_util7 = require("node:util");
|
|
21131
21210
|
|
|
@@ -21735,9 +21814,9 @@ function registerSchedulesCommands(program3) {
|
|
|
21735
21814
|
await failGraceful("org schedules --doc: refusing to regenerate the doc from an incomplete read (see warnings above).");
|
|
21736
21815
|
return;
|
|
21737
21816
|
}
|
|
21738
|
-
const docText = await (0,
|
|
21817
|
+
const docText = await (0, import_promises4.readFile)(o.doc, "utf8");
|
|
21739
21818
|
const spliced = spliceDoc(docText, renderDocSection(entries, (/* @__PURE__ */ new Date()).toISOString()));
|
|
21740
|
-
await (0,
|
|
21819
|
+
await (0, import_promises4.writeFile)(o.doc, spliced, "utf8");
|
|
21741
21820
|
reportDrift(drift);
|
|
21742
21821
|
console.log(`org schedules: wrote ${entries.length} entries into ${o.doc}`);
|
|
21743
21822
|
return;
|
|
@@ -21796,7 +21875,7 @@ function registerSchedulesCommands(program3) {
|
|
|
21796
21875
|
}
|
|
21797
21876
|
|
|
21798
21877
|
// src/file-lock.ts
|
|
21799
|
-
var
|
|
21878
|
+
var import_promises5 = require("node:fs/promises");
|
|
21800
21879
|
var import_node_path24 = require("node:path");
|
|
21801
21880
|
var sleep = (ms) => new Promise((resolve5) => setTimeout(resolve5, ms));
|
|
21802
21881
|
var IMMEDIATE_RETRY_BUDGET = 3;
|
|
@@ -21821,7 +21900,7 @@ async function acquireFileLock(lockPath, opts, deadline) {
|
|
|
21821
21900
|
for (; ; ) {
|
|
21822
21901
|
let handle;
|
|
21823
21902
|
try {
|
|
21824
|
-
handle = await (0,
|
|
21903
|
+
handle = await (0, import_promises5.open)(lockPath, "wx");
|
|
21825
21904
|
} catch (e) {
|
|
21826
21905
|
const code = e.code;
|
|
21827
21906
|
if (code !== "EEXIST" && code !== "EPERM" && code !== "EBUSY" && code !== "EACCES") throw e;
|
|
@@ -21830,10 +21909,10 @@ async function acquireFileLock(lockPath, opts, deadline) {
|
|
|
21830
21909
|
if (++immediateRetries > IMMEDIATE_RETRY_BUDGET) await sleep(opts.retryMs);
|
|
21831
21910
|
};
|
|
21832
21911
|
try {
|
|
21833
|
-
const age = Date.now() - (await (0,
|
|
21912
|
+
const age = Date.now() - (await (0, import_promises5.stat)(lockPath)).mtimeMs;
|
|
21834
21913
|
if (age > opts.staleMs) {
|
|
21835
21914
|
try {
|
|
21836
|
-
await (0,
|
|
21915
|
+
await (0, import_promises5.unlink)(lockPath);
|
|
21837
21916
|
await retryNow();
|
|
21838
21917
|
continue;
|
|
21839
21918
|
} catch (unlinkError) {
|
|
@@ -21869,7 +21948,7 @@ async function acquireFileLock(lockPath, opts, deadline) {
|
|
|
21869
21948
|
}
|
|
21870
21949
|
async function fileLockHeldBy(lockPath, token) {
|
|
21871
21950
|
try {
|
|
21872
|
-
return await (0,
|
|
21951
|
+
return await (0, import_promises5.readFile)(lockPath, "utf8") === token;
|
|
21873
21952
|
} catch {
|
|
21874
21953
|
return false;
|
|
21875
21954
|
}
|
|
@@ -21877,12 +21956,12 @@ async function fileLockHeldBy(lockPath, token) {
|
|
|
21877
21956
|
async function releaseFileLock(lockPath, guard) {
|
|
21878
21957
|
await guard.handle.close().catch(() => void 0);
|
|
21879
21958
|
if (await fileLockHeldBy(lockPath, guard.token)) {
|
|
21880
|
-
await (0,
|
|
21959
|
+
await (0, import_promises5.unlink)(lockPath).catch(() => void 0);
|
|
21881
21960
|
}
|
|
21882
21961
|
}
|
|
21883
21962
|
async function withFileLock(lockPath, opts, fn) {
|
|
21884
21963
|
const resolved = resolveFileLockOpts(opts);
|
|
21885
|
-
await (0,
|
|
21964
|
+
await (0, import_promises5.mkdir)((0, import_node_path24.dirname)(lockPath), { recursive: true }).catch(() => void 0);
|
|
21886
21965
|
const guard = await acquireFileLock(lockPath, resolved, Date.now() + resolved.maxWaitMs);
|
|
21887
21966
|
try {
|
|
21888
21967
|
return await fn();
|
|
@@ -21892,7 +21971,7 @@ async function withFileLock(lockPath, opts, fn) {
|
|
|
21892
21971
|
}
|
|
21893
21972
|
|
|
21894
21973
|
// src/schedules-lift-command.ts
|
|
21895
|
-
var
|
|
21974
|
+
var import_promises6 = require("node:fs/promises");
|
|
21896
21975
|
var import_node_path25 = require("node:path");
|
|
21897
21976
|
|
|
21898
21977
|
// src/schedules-lift.ts
|
|
@@ -21992,14 +22071,14 @@ var RegistryUnreachableError = class extends Error {
|
|
|
21992
22071
|
async function readWorkflowFiles(dir) {
|
|
21993
22072
|
let names;
|
|
21994
22073
|
try {
|
|
21995
|
-
names = await (0,
|
|
22074
|
+
names = await (0, import_promises6.readdir)(dir);
|
|
21996
22075
|
} catch {
|
|
21997
22076
|
return [];
|
|
21998
22077
|
}
|
|
21999
22078
|
const files = [];
|
|
22000
22079
|
for (const name of names.sort()) {
|
|
22001
22080
|
if (!/\.ya?ml$/.test(name)) continue;
|
|
22002
|
-
files.push({ path: `.github/workflows/${name}`, text: await (0,
|
|
22081
|
+
files.push({ path: `.github/workflows/${name}`, text: await (0, import_promises6.readFile)((0, import_node_path25.join)(dir, name), "utf8") });
|
|
22003
22082
|
}
|
|
22004
22083
|
return files;
|
|
22005
22084
|
}
|
|
@@ -23049,7 +23128,7 @@ function renderBootstrapVerifyReport(report) {
|
|
|
23049
23128
|
// src/bootstrap-org-ruleset.ts
|
|
23050
23129
|
var ORG_NO_AGENT_FILES_RULESET_NAME = "mmi-no-agent-files-org";
|
|
23051
23130
|
var ORG_LOGIN = "mutmutco";
|
|
23052
|
-
var ORG_NO_AGENT_FILES_EXCLUDED_REPOS = ["Jerv-PowerTools"];
|
|
23131
|
+
var ORG_NO_AGENT_FILES_EXCLUDED_REPOS = ["Jerv-PowerTools", "Jerv-JervCode"];
|
|
23053
23132
|
var NO_AGENT_FILES_GLOBS = [
|
|
23054
23133
|
"AGENTS.md",
|
|
23055
23134
|
"**/AGENTS.md",
|
|
@@ -23126,8 +23205,8 @@ OK \u2014 live ruleset matches the codified IaC (${NO_AGENT_FILES_GLOBS.length}
|
|
|
23126
23205
|
`${head}`,
|
|
23127
23206
|
verb,
|
|
23128
23207
|
...plan.drift.map((d) => ` - ${d}`),
|
|
23129
|
-
"
|
|
23130
|
-
"
|
|
23208
|
+
"Read-only preview \u2014 a master-admin may reconcile this exact desired state with",
|
|
23209
|
+
"`mmi-cli bootstrap org-ruleset --apply`."
|
|
23131
23210
|
].join("\n");
|
|
23132
23211
|
}
|
|
23133
23212
|
async function fetchOrgNoAgentFilesRuleset(client, org = ORG_LOGIN) {
|
|
@@ -23136,6 +23215,27 @@ async function fetchOrgNoAgentFilesRuleset(client, org = ORG_LOGIN) {
|
|
|
23136
23215
|
if (summary?.id == null) return null;
|
|
23137
23216
|
return await client.rest("GET", `orgs/${org}/rulesets/${summary.id}`, { timeoutMs: 2e4 }) ?? null;
|
|
23138
23217
|
}
|
|
23218
|
+
async function reconcileOrgNoAgentFilesRuleset(plan, client, org = ORG_LOGIN) {
|
|
23219
|
+
if (plan.action === "noop") {
|
|
23220
|
+
return { action: "noop", id: plan.id, verified: true, desired: plan.desired };
|
|
23221
|
+
}
|
|
23222
|
+
if (plan.action === "create") {
|
|
23223
|
+
await client.rest("POST", `orgs/${org}/rulesets`, { body: plan.desired, timeoutMs: 2e4 });
|
|
23224
|
+
} else {
|
|
23225
|
+
if (plan.id == null) throw new Error(`cannot update '${plan.desired.name}': live ruleset id is missing`);
|
|
23226
|
+
await client.rest("PUT", `orgs/${org}/rulesets/${plan.id}`, { body: plan.desired, timeoutMs: 2e4 });
|
|
23227
|
+
}
|
|
23228
|
+
const verified = planOrgNoAgentFilesRuleset(await fetchOrgNoAgentFilesRuleset(client, org));
|
|
23229
|
+
if (verified.action !== "noop") {
|
|
23230
|
+
throw new Error(`org ruleset reconcile did not settle: ${verified.drift.join("; ")}`);
|
|
23231
|
+
}
|
|
23232
|
+
return {
|
|
23233
|
+
action: plan.action === "create" ? "created" : "updated",
|
|
23234
|
+
id: verified.id,
|
|
23235
|
+
verified: true,
|
|
23236
|
+
desired: verified.desired
|
|
23237
|
+
};
|
|
23238
|
+
}
|
|
23139
23239
|
|
|
23140
23240
|
// src/bootstrap-commands.ts
|
|
23141
23241
|
function registerBootstrapCommands(program3) {
|
|
@@ -23190,13 +23290,28 @@ function registerBootstrapCommands(program3) {
|
|
|
23190
23290
|
console.log(o.json ? JSON.stringify(report, null, 2) : renderBootstrapVerifyReport(report));
|
|
23191
23291
|
if (!report.ok) process.exitCode = 1;
|
|
23192
23292
|
});
|
|
23193
|
-
bootstrap.command("org-ruleset").description("drift-check the codified org no-agent-files push ruleset
|
|
23293
|
+
bootstrap.command("org-ruleset").description("drift-check the codified org no-agent-files push ruleset; optionally reconcile it under master authority (#2196/#4001)").option("--json", "machine-readable output").option("--apply", "create or update the one named org ruleset to exact desired state (master-admin required)").action(async () => {
|
|
23194
23294
|
const json = rawFlag("--json");
|
|
23195
|
-
const
|
|
23295
|
+
const apply = rawFlag("--apply");
|
|
23296
|
+
const client = defaultGitHubClient();
|
|
23297
|
+
const live = await fetchOrgNoAgentFilesRuleset(client);
|
|
23196
23298
|
const plan = planOrgNoAgentFilesRuleset(live);
|
|
23197
|
-
if (
|
|
23198
|
-
|
|
23199
|
-
|
|
23299
|
+
if (!apply) {
|
|
23300
|
+
if (json) console.log(JSON.stringify({ action: plan.action, id: plan.id, drift: plan.drift, desired: plan.desired }, null, 2));
|
|
23301
|
+
else console.log(renderOrgRulesetDriftReport(plan));
|
|
23302
|
+
if (plan.action !== "noop") process.exitCode = 1;
|
|
23303
|
+
return;
|
|
23304
|
+
}
|
|
23305
|
+
const verdict = await fetchTrainAuthority("mutmutco/MMI-Hub", registryClientDeps(await loadConfig()));
|
|
23306
|
+
if (!verdict.ok || verdict.authority.role !== "master") {
|
|
23307
|
+
return fail("bootstrap org-ruleset --apply: master-admin required");
|
|
23308
|
+
}
|
|
23309
|
+
const result = await reconcileOrgNoAgentFilesRuleset(plan, client);
|
|
23310
|
+
if (json) console.log(JSON.stringify(result, null, 2));
|
|
23311
|
+
else {
|
|
23312
|
+
console.log(`mmi-cli bootstrap org-ruleset --apply: ${result.action}`);
|
|
23313
|
+
console.log(renderOrgRulesetDriftReport(planOrgNoAgentFilesRuleset(await fetchOrgNoAgentFilesRuleset(client))));
|
|
23314
|
+
}
|
|
23200
23315
|
});
|
|
23201
23316
|
bootstrap.command("drift").description("#3818: compare every org-owned whole-file seed against MMI-Hub's copy across the registry roster; read-only").option("--repo <owner/repo>", "audit one repo instead of the roster (never a fleet verdict)").option("--json", "machine-readable output").action(async () => {
|
|
23202
23317
|
const o = { repo: rawValue("--repo", ""), json: rawFlag("--json") };
|
|
@@ -24245,7 +24360,7 @@ function registerBoardCommands(program3) {
|
|
|
24245
24360
|
|
|
24246
24361
|
// src/merge-cleanup.ts
|
|
24247
24362
|
var import_node_fs30 = require("node:fs");
|
|
24248
|
-
var
|
|
24363
|
+
var import_promises8 = require("node:fs/promises");
|
|
24249
24364
|
var import_node_path30 = require("node:path");
|
|
24250
24365
|
var import_node_os11 = require("node:os");
|
|
24251
24366
|
var import_node_child_process14 = require("node:child_process");
|
|
@@ -24333,23 +24448,23 @@ function boardAdvanceFailureMessage(result) {
|
|
|
24333
24448
|
}
|
|
24334
24449
|
|
|
24335
24450
|
// src/deferred-registry-store.ts
|
|
24336
|
-
var
|
|
24451
|
+
var import_promises7 = require("node:fs/promises");
|
|
24337
24452
|
var import_node_path29 = require("node:path");
|
|
24338
24453
|
var sleep2 = (ms) => new Promise((resolve5) => setTimeout(resolve5, ms));
|
|
24339
24454
|
async function atomicWrite(target, contents) {
|
|
24340
24455
|
const tmp = `${target}.tmp-${process.pid}-${Math.random().toString(36).slice(2)}`;
|
|
24341
|
-
await (0,
|
|
24456
|
+
await (0, import_promises7.writeFile)(tmp, contents, "utf8");
|
|
24342
24457
|
try {
|
|
24343
24458
|
await renameWithRetry(tmp, target);
|
|
24344
24459
|
} catch (e) {
|
|
24345
|
-
await (0,
|
|
24460
|
+
await (0, import_promises7.unlink)(tmp).catch(() => void 0);
|
|
24346
24461
|
throw e;
|
|
24347
24462
|
}
|
|
24348
24463
|
}
|
|
24349
24464
|
async function renameWithRetry(from, to, attempts = 5, backoffMs = 20) {
|
|
24350
24465
|
for (let i = 0; ; i++) {
|
|
24351
24466
|
try {
|
|
24352
|
-
await (0,
|
|
24467
|
+
await (0, import_promises7.rename)(from, to);
|
|
24353
24468
|
return;
|
|
24354
24469
|
} catch (e) {
|
|
24355
24470
|
const code = e.code;
|
|
@@ -24361,7 +24476,7 @@ async function renameWithRetry(from, to, attempts = 5, backoffMs = 20) {
|
|
|
24361
24476
|
async function readStrict(registryPath) {
|
|
24362
24477
|
let text;
|
|
24363
24478
|
try {
|
|
24364
|
-
text = await (0,
|
|
24479
|
+
text = await (0, import_promises7.readFile)(registryPath, "utf8");
|
|
24365
24480
|
} catch (e) {
|
|
24366
24481
|
if (e.code === "ENOENT") return [];
|
|
24367
24482
|
throw e;
|
|
@@ -24378,19 +24493,19 @@ function makeDeferredWorktreeStore(registryPath, lockOpts = {}) {
|
|
|
24378
24493
|
// Lenient read for the sweep's initial fetch: any error (missing/corrupt) yields an empty queue.
|
|
24379
24494
|
read: async () => {
|
|
24380
24495
|
try {
|
|
24381
|
-
return parseDeferredWorktreesFile(await (0,
|
|
24496
|
+
return parseDeferredWorktreesFile(await (0, import_promises7.readFile)(registryPath, "utf8"));
|
|
24382
24497
|
} catch {
|
|
24383
24498
|
return [];
|
|
24384
24499
|
}
|
|
24385
24500
|
},
|
|
24386
24501
|
// Standalone atomic write — THROWS on failure (no best-effort swallow, #2846).
|
|
24387
24502
|
write: async (entries) => {
|
|
24388
|
-
await (0,
|
|
24503
|
+
await (0, import_promises7.mkdir)((0, import_node_path29.dirname)(registryPath), { recursive: true });
|
|
24389
24504
|
await atomicWrite(registryPath, serializeDeferredWorktrees(entries));
|
|
24390
24505
|
},
|
|
24391
24506
|
// Serialized read-modify-write under the repo-wide lock (#2846).
|
|
24392
24507
|
update: async (mutate) => {
|
|
24393
|
-
await (0,
|
|
24508
|
+
await (0, import_promises7.mkdir)((0, import_node_path29.dirname)(registryPath), { recursive: true });
|
|
24394
24509
|
const deadline = Date.now() + opts.maxWaitMs;
|
|
24395
24510
|
for (; ; ) {
|
|
24396
24511
|
const guard = await acquireLock(lockPath, opts, deadline);
|
|
@@ -24831,7 +24946,7 @@ var realWorktreeDirRemover = {
|
|
|
24831
24946
|
(0, import_node_fs30.unlinkSync)(p);
|
|
24832
24947
|
}
|
|
24833
24948
|
},
|
|
24834
|
-
removeTree: (p) => (0,
|
|
24949
|
+
removeTree: (p) => (0, import_promises8.rm)(p, { recursive: true, force: true, maxRetries: 5, retryDelay: 200 })
|
|
24835
24950
|
};
|
|
24836
24951
|
async function resolvePrimaryCheckout(execGit) {
|
|
24837
24952
|
try {
|
|
@@ -25088,7 +25203,7 @@ async function fetchRestCorePool(gh = defaultGhApi) {
|
|
|
25088
25203
|
|
|
25089
25204
|
// src/worktree-lifecycle-commands.ts
|
|
25090
25205
|
var import_node_fs31 = require("node:fs");
|
|
25091
|
-
var
|
|
25206
|
+
var import_promises9 = require("node:fs/promises");
|
|
25092
25207
|
var import_node_path31 = require("node:path");
|
|
25093
25208
|
var GH_TIMEOUT_MS = 2e4;
|
|
25094
25209
|
var DEFAULT_BASE = "origin/development";
|
|
@@ -25432,13 +25547,13 @@ function registerWorktreeCommands(program3) {
|
|
|
25432
25547
|
}
|
|
25433
25548
|
const landStatus = (await execFileP2("git", ["-C", wtPath, "status", "--porcelain"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "unreadable" }))).stdout || "";
|
|
25434
25549
|
const gitInWorktree = async (args) => (await execFileP2("git", ["-C", wtPath, ...args], { timeout: GIT_TIMEOUT_MS })).stdout;
|
|
25435
|
-
const orphanDirt = headBorn ? void 0 : await classifyOrphanWorktreeDirt(landStatus, { git: gitInWorktree, readTextFile: (p) => (0,
|
|
25550
|
+
const orphanDirt = headBorn ? void 0 : await classifyOrphanWorktreeDirt(landStatus, { git: gitInWorktree, readTextFile: (p) => (0, import_promises9.readFile)(p, "utf8") });
|
|
25436
25551
|
const landDirty = headBorn ? landStatus.trim().length > 0 : orphanDirt.dirt !== "clean";
|
|
25437
25552
|
if (landDirty) {
|
|
25438
25553
|
return fail(`worktree land: refusing to land '${branch}' \u2014 uncommitted changes in ${wtPath}; commit, stash, or remove the worktree manually`, { code: ERROR_CODES.ERR_BAD_ENUM });
|
|
25439
25554
|
}
|
|
25440
25555
|
const orphanTip = orphan.orphan ? orphanDirt?.tip ?? await readOrphanWorktreeTip(
|
|
25441
|
-
{ git: gitInWorktree, readTextFile: (p) => (0,
|
|
25556
|
+
{ git: gitInWorktree, readTextFile: (p) => (0, import_promises9.readFile)(p, "utf8") },
|
|
25442
25557
|
orphan.kind
|
|
25443
25558
|
) : void 0;
|
|
25444
25559
|
const lastCommit = orphanTip ? {
|
|
@@ -25622,10 +25737,13 @@ async function bestEffortGit(args, cwd, step, timeoutMs = GIT_TIMEOUT_MS) {
|
|
|
25622
25737
|
await execFileP2("git", fullArgs, { timeout: timeoutMs });
|
|
25623
25738
|
return { step, status: "done" };
|
|
25624
25739
|
} catch (e) {
|
|
25625
|
-
const
|
|
25626
|
-
|
|
25740
|
+
const err = e;
|
|
25741
|
+
const detail = `${err.message}
|
|
25742
|
+
${err.stderr ?? ""}`;
|
|
25743
|
+
if (/not found|already|no such|does not exist|not a valid|couldn't|unable to resolve/i.test(detail)) {
|
|
25627
25744
|
return { step, status: "already gone" };
|
|
25628
25745
|
}
|
|
25746
|
+
const msg = (err.stderr?.trim() || err.message).split("\n")[0];
|
|
25629
25747
|
return { step, status: `failed: ${msg}` };
|
|
25630
25748
|
}
|
|
25631
25749
|
}
|
|
@@ -26861,7 +26979,7 @@ function registerExplainCommand(program3) {
|
|
|
26861
26979
|
}
|
|
26862
26980
|
|
|
26863
26981
|
// src/pr-commands.ts
|
|
26864
|
-
var
|
|
26982
|
+
var import_promises10 = require("node:fs/promises");
|
|
26865
26983
|
var GC_GH_TIMEOUT_MS4 = 2e4;
|
|
26866
26984
|
var CHECKS_WATCH_POLL_MS = 15e3;
|
|
26867
26985
|
var CHECKS_WATCH_TIMEOUT_MS = 10 * 6e4;
|
|
@@ -27005,10 +27123,10 @@ function registerPrLifecycleCommands(program3) {
|
|
|
27005
27123
|
let body;
|
|
27006
27124
|
try {
|
|
27007
27125
|
if (o.title || o.titleFile) {
|
|
27008
|
-
title = await resolveIssueTitle({ title: o.title, titleFile: o.titleFile }, { readFile:
|
|
27126
|
+
title = await resolveIssueTitle({ title: o.title, titleFile: o.titleFile }, { readFile: import_promises10.readFile, readStdin });
|
|
27009
27127
|
}
|
|
27010
27128
|
if (o.body || o.bodyFile) {
|
|
27011
|
-
body = await resolveIssueBody({ body: o.body, bodyFile: o.bodyFile }, { readFile:
|
|
27129
|
+
body = await resolveIssueBody({ body: o.body, bodyFile: o.bodyFile }, { readFile: import_promises10.readFile, readStdin });
|
|
27012
27130
|
}
|
|
27013
27131
|
} catch (e) {
|
|
27014
27132
|
return fail(`pr edit: ${e.message}`);
|
|
@@ -27038,7 +27156,7 @@ function registerPrLifecycleCommands(program3) {
|
|
|
27038
27156
|
}
|
|
27039
27157
|
let body;
|
|
27040
27158
|
try {
|
|
27041
|
-
body = await resolveIssueBody({ body: o.body, bodyFile: o.bodyFile }, { readFile:
|
|
27159
|
+
body = await resolveIssueBody({ body: o.body, bodyFile: o.bodyFile }, { readFile: import_promises10.readFile, readStdin });
|
|
27042
27160
|
} catch (e) {
|
|
27043
27161
|
return fail(`pr comment: ${e.message}`);
|
|
27044
27162
|
}
|
|
@@ -30613,7 +30731,7 @@ withExamples(mutating(
|
|
|
30613
30731
|
try {
|
|
30614
30732
|
title = await resolveIssueTitle(
|
|
30615
30733
|
{ title: opts.title, titleFile: opts.titleFile },
|
|
30616
|
-
{ readFile:
|
|
30734
|
+
{ readFile: import_promises11.readFile, readStdin }
|
|
30617
30735
|
);
|
|
30618
30736
|
} catch (e) {
|
|
30619
30737
|
return fail(
|
|
@@ -30655,8 +30773,8 @@ withExamples(mutating(
|
|
|
30655
30773
|
let surfaceFlagLabel;
|
|
30656
30774
|
try {
|
|
30657
30775
|
issueType = resolveCreateType(o.type, "issue create", o.label);
|
|
30658
|
-
title = await resolveIssueTitle({ title: o.title, titleFile: o.titleFile }, { readFile:
|
|
30659
|
-
body = await resolveIssueBody({ body: o.body, bodyFile: o.bodyFile }, { readFile:
|
|
30776
|
+
title = await resolveIssueTitle({ title: o.title, titleFile: o.titleFile }, { readFile: import_promises11.readFile, readStdin });
|
|
30777
|
+
body = await resolveIssueBody({ body: o.body, bodyFile: o.bodyFile }, { readFile: import_promises11.readFile, readStdin });
|
|
30660
30778
|
if (o.idempotencyKey) body = appendIdempotencyMarker(body, o.idempotencyKey);
|
|
30661
30779
|
priority = resolveCreatePriority(o.priority, "issue create");
|
|
30662
30780
|
extraLabels = [...o.label ?? []];
|
|
@@ -30836,7 +30954,7 @@ jsonParity(issue.command("comment <ref>").description("post a Markdown comment t
|
|
|
30836
30954
|
}
|
|
30837
30955
|
let body;
|
|
30838
30956
|
try {
|
|
30839
|
-
body = await resolveIssueBody({ body: o.body, bodyFile: o.bodyFile }, { readFile:
|
|
30957
|
+
body = await resolveIssueBody({ body: o.body, bodyFile: o.bodyFile }, { readFile: import_promises11.readFile, readStdin });
|
|
30840
30958
|
} catch (e) {
|
|
30841
30959
|
return fail(`issue comment: ${e.message}`);
|
|
30842
30960
|
}
|
|
@@ -30896,8 +31014,8 @@ program2.command("report").description("file a friction report on the Hub board
|
|
|
30896
31014
|
let title;
|
|
30897
31015
|
const sourceRepo = o.repo ?? await resolveRepo(void 0);
|
|
30898
31016
|
try {
|
|
30899
|
-
title = await resolveIssueTitle({ title: o.title, titleFile: o.titleFile }, { readFile:
|
|
30900
|
-
body = await resolveIssueBody({ body: o.body, bodyFile: o.bodyFile }, { readFile:
|
|
31017
|
+
title = await resolveIssueTitle({ title: o.title, titleFile: o.titleFile }, { readFile: import_promises11.readFile, readStdin });
|
|
31018
|
+
body = await resolveIssueBody({ body: o.body, bodyFile: o.bodyFile }, { readFile: import_promises11.readFile, readStdin });
|
|
30901
31019
|
priority = resolveCreatePriority(o.priority, "report");
|
|
30902
31020
|
if (!ISSUE_TYPES.includes(o.type)) {
|
|
30903
31021
|
throw new Error(`unknown issue type "${o.type}" \u2014 expected one of: ${ISSUE_TYPES.join(", ")}`);
|
|
@@ -30949,8 +31067,8 @@ program2.command("skill-lesson").description("file a skill-lesson on the Hub boa
|
|
|
30949
31067
|
let args;
|
|
30950
31068
|
try {
|
|
30951
31069
|
skill = assertSkillName(o.skill);
|
|
30952
|
-
rawBody = await resolveIssueBody({ body: o.body, bodyFile: o.bodyFile }, { readFile:
|
|
30953
|
-
const rawTitle = await resolveIssueTitle({ title: o.title, titleFile: o.titleFile }, { readFile:
|
|
31070
|
+
rawBody = await resolveIssueBody({ body: o.body, bodyFile: o.bodyFile }, { readFile: import_promises11.readFile, readStdin });
|
|
31071
|
+
const rawTitle = await resolveIssueTitle({ title: o.title, titleFile: o.titleFile }, { readFile: import_promises11.readFile, readStdin });
|
|
30954
31072
|
title = buildSkillLessonTitle(skill, rawTitle);
|
|
30955
31073
|
priority = resolveCreatePriority(o.priority, "skill-lesson");
|
|
30956
31074
|
body = buildSkillLessonBody(rawBody, sourceRepo, pluginSha);
|
|
@@ -31009,8 +31127,8 @@ withExamples(pr.command("create").description("create a PR and print {number,url
|
|
|
31009
31127
|
let body;
|
|
31010
31128
|
let title;
|
|
31011
31129
|
try {
|
|
31012
|
-
title = await resolveIssueTitle({ title: o.title, titleFile: o.titleFile }, { readFile:
|
|
31013
|
-
body = await resolveIssueBody({ body: o.body, bodyFile: o.bodyFile }, { readFile:
|
|
31130
|
+
title = await resolveIssueTitle({ title: o.title, titleFile: o.titleFile }, { readFile: import_promises11.readFile, readStdin });
|
|
31131
|
+
body = await resolveIssueBody({ body: o.body, bodyFile: o.bodyFile }, { readFile: import_promises11.readFile, readStdin });
|
|
31014
31132
|
} catch (e) {
|
|
31015
31133
|
return fail(`pr create: ${e.message}`, e instanceof TextArgError ? { code: e.code, offending_flag: e.offendingFlag } : void 0);
|
|
31016
31134
|
}
|
|
@@ -31507,8 +31625,8 @@ function trainApplyDeps() {
|
|
|
31507
31625
|
// Slack release announcement (#883): Hub-only + best-effort inside announceRelease itself.
|
|
31508
31626
|
announce: (args) => announceRelease({
|
|
31509
31627
|
run: async (file, cmdArgs) => (await execFileP2(file, cmdArgs, { timeout: GH_TRAIN_TIMEOUT_MS })).stdout,
|
|
31510
|
-
readFile: (path2) => (0,
|
|
31511
|
-
removeFile: (path2) => (0,
|
|
31628
|
+
readFile: (path2) => (0, import_promises11.readFile)(path2, "utf8"),
|
|
31629
|
+
removeFile: (path2) => (0, import_promises11.unlink)(path2)
|
|
31512
31630
|
}, args),
|
|
31513
31631
|
fetchEdgeDomains: async (slug) => {
|
|
31514
31632
|
const proj = await fetchProjectBySlug(slug, registryClientDeps(await loadConfig()));
|
|
@@ -31691,7 +31809,7 @@ for (const commandName of ["rcand", "release"]) {
|
|
|
31691
31809
|
}
|
|
31692
31810
|
let summaryLines;
|
|
31693
31811
|
try {
|
|
31694
|
-
summaryLines = summaryFileLines(await (0,
|
|
31812
|
+
summaryLines = summaryFileLines(await (0, import_promises11.readFile)(o.announceSummaryFile, "utf8"));
|
|
31695
31813
|
} catch (e) {
|
|
31696
31814
|
return fail(`release: could not read --announce-summary-file ${o.announceSummaryFile}: ${e.message}`);
|
|
31697
31815
|
}
|
package/package.json
CHANGED