@mutmutco/cli 4.3.15 → 4.3.16
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 +394 -173
- package/package.json +1 -1
package/dist/main.cjs
CHANGED
|
@@ -3416,7 +3416,7 @@ function useColor() {
|
|
|
3416
3416
|
var program = new Command();
|
|
3417
3417
|
|
|
3418
3418
|
// src/command-composition.ts
|
|
3419
|
-
var
|
|
3419
|
+
var import_node_fs50 = require("node:fs");
|
|
3420
3420
|
|
|
3421
3421
|
// src/clean-exit.ts
|
|
3422
3422
|
var UNDICI_GLOBAL_DISPATCHER_SYMBOL = Object.getOwnPropertySymbols(globalThis).find(
|
|
@@ -5226,8 +5226,8 @@ function unknownCommandDomainGuide(parentPath, token) {
|
|
|
5226
5226
|
}
|
|
5227
5227
|
|
|
5228
5228
|
// src/command-composition.ts
|
|
5229
|
-
var
|
|
5230
|
-
var
|
|
5229
|
+
var import_node_os22 = require("node:os");
|
|
5230
|
+
var import_node_path47 = require("node:path");
|
|
5231
5231
|
|
|
5232
5232
|
// src/board-read.ts
|
|
5233
5233
|
var import_node_fs13 = require("node:fs");
|
|
@@ -13706,7 +13706,7 @@ function createDocsIndexDeps(repoRoot2) {
|
|
|
13706
13706
|
}
|
|
13707
13707
|
|
|
13708
13708
|
// src/gate-budget.ts
|
|
13709
|
-
var BLESSED_RUN_WITH_BUDGET_SHA = "
|
|
13709
|
+
var BLESSED_RUN_WITH_BUDGET_SHA = "5ce541add569e54e7ca96de67a768577d3d604e4";
|
|
13710
13710
|
var BLESSED_RUNNER_GATE_SHA = "a6ee756d94fd95884451381e94408f0348eb11db";
|
|
13711
13711
|
var REMOTE_USE = /^mutmutco\/MMI-Hub\/\.github\/actions\/run-with-budget@(\S+)$/;
|
|
13712
13712
|
var LOCAL_USE = "./.github/actions/run-with-budget";
|
|
@@ -14044,6 +14044,8 @@ function gateSeedVars(cls, releaseTrack, runtime = "node", requiredCheckBranches
|
|
|
14044
14044
|
const runtimeVars = {
|
|
14045
14045
|
GATE_RUNTIME: runtime,
|
|
14046
14046
|
GATE_CMD: rt.cmd,
|
|
14047
|
+
// #6254: affected-only PR command; empty means "same as GATE_CMD" (withDerivedRepoVars fills it).
|
|
14048
|
+
GATE_AFFECTED_CMD: "",
|
|
14047
14049
|
GATE_INSTALL_CMD: rt.install,
|
|
14048
14050
|
GATE_WORKDIR: ".",
|
|
14049
14051
|
GATE_CACHE_DEP_PATH: "package-lock.json",
|
|
@@ -14091,6 +14093,7 @@ function withDerivedRepoVars(vars, parsed, cls, releaseTrack, requiredCheckBranc
|
|
|
14091
14093
|
for (const [key, value] of Object.entries(gateSeedVars(cls, track, runtime, requiredCheckBranches))) {
|
|
14092
14094
|
out[key] ??= value;
|
|
14093
14095
|
}
|
|
14096
|
+
if (!out.GATE_AFFECTED_CMD.trim()) out.GATE_AFFECTED_CMD = out.GATE_CMD;
|
|
14094
14097
|
return out;
|
|
14095
14098
|
}
|
|
14096
14099
|
function gateConfigToVars(gate) {
|
|
@@ -14098,6 +14101,7 @@ function gateConfigToVars(gate) {
|
|
|
14098
14101
|
if (!gate || typeof gate !== "object") return out;
|
|
14099
14102
|
if (gate.runtime === "node" || gate.runtime === "python") out.GATE_RUNTIME = gate.runtime;
|
|
14100
14103
|
if (typeof gate.cmd === "string" && gate.cmd.trim()) out.GATE_CMD = gate.cmd;
|
|
14104
|
+
if (typeof gate.affectedCmd === "string" && gate.affectedCmd.trim()) out.GATE_AFFECTED_CMD = gate.affectedCmd;
|
|
14101
14105
|
if (typeof gate.workdir === "string" && gate.workdir.trim()) out.GATE_WORKDIR = gate.workdir;
|
|
14102
14106
|
if (typeof gate.cacheDepPath === "string" && gate.cacheDepPath.trim()) out.GATE_CACHE_DEP_PATH = gate.cacheDepPath;
|
|
14103
14107
|
if (typeof gate.pyVersion === "string" && gate.pyVersion.trim()) out.GATE_PY_VERSION = gate.pyVersion;
|
|
@@ -15483,10 +15487,10 @@ var rollout_plan_default = {
|
|
|
15483
15487
|
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)."
|
|
15484
15488
|
},
|
|
15485
15489
|
baseline: {
|
|
15486
|
-
version: "4.3.
|
|
15487
|
-
tag: "v4.3.
|
|
15488
|
-
commit: "
|
|
15489
|
-
npm: "@mutmutco/cli@4.3.
|
|
15490
|
+
version: "4.3.16",
|
|
15491
|
+
tag: "v4.3.16",
|
|
15492
|
+
commit: "5a4b8e29fd1a",
|
|
15493
|
+
npm: "@mutmutco/cli@4.3.16"
|
|
15490
15494
|
},
|
|
15491
15495
|
exitCriterion: "fleet-n-of-n",
|
|
15492
15496
|
hubOnlyShortcut: "forbidden",
|
|
@@ -15503,14 +15507,14 @@ var rollout_plan_default = {
|
|
|
15503
15507
|
repo: "mutmutco/mmi-hub",
|
|
15504
15508
|
role: "canary",
|
|
15505
15509
|
schedule: "train",
|
|
15506
|
-
v3Target: "v4.3.
|
|
15510
|
+
v3Target: "v4.3.16"
|
|
15507
15511
|
}
|
|
15508
15512
|
],
|
|
15509
15513
|
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.",
|
|
15510
15514
|
rollback: {
|
|
15511
15515
|
independent: true,
|
|
15512
|
-
mechanism: "npm dist-tag latest -> 4.3.
|
|
15513
|
-
v3Target: "v4.3.
|
|
15516
|
+
mechanism: "npm dist-tag latest -> 4.3.16 and redeploy the Hub Lambda from tag v4.3.16 (5a4b8e29fd1a); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
|
|
15517
|
+
v3Target: "v4.3.16 (@mutmutco/cli@4.3.16, tag commit 5a4b8e29fd1a \u2014 last known-good release carrying the repo-index v4-only contract)"
|
|
15514
15518
|
}
|
|
15515
15519
|
},
|
|
15516
15520
|
{
|
|
@@ -28778,7 +28782,7 @@ function parseGateVar(raw) {
|
|
|
28778
28782
|
throw new Error('org project set: gate must be JSON, e.g. {"runtime":"python","cmd":"pytest","workdir":"app"}');
|
|
28779
28783
|
}
|
|
28780
28784
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
28781
|
-
throw new Error("org project set: gate must be a {runtime,cmd,workdir,cacheDepPath,pyVersion} object");
|
|
28785
|
+
throw new Error("org project set: gate must be a {runtime,cmd,affectedCmd,workdir,cacheDepPath,pyVersion} object");
|
|
28782
28786
|
}
|
|
28783
28787
|
const map = parsed;
|
|
28784
28788
|
const out = {};
|
|
@@ -28786,11 +28790,11 @@ function parseGateVar(raw) {
|
|
|
28786
28790
|
if (key === "runtime") {
|
|
28787
28791
|
if (value !== "node" && value !== "python") throw new Error('org project set: gate.runtime must be "node" or "python"');
|
|
28788
28792
|
out.runtime = value;
|
|
28789
|
-
} else if (key === "cmd" || key === "workdir" || key === "cacheDepPath" || key === "pyVersion") {
|
|
28793
|
+
} else if (key === "cmd" || key === "affectedCmd" || key === "workdir" || key === "cacheDepPath" || key === "pyVersion") {
|
|
28790
28794
|
if (typeof value !== "string" || !value.trim()) throw new Error(`org project set: gate.${key} must be a non-empty string`);
|
|
28791
28795
|
out[key] = value.trim();
|
|
28792
28796
|
} else {
|
|
28793
|
-
throw new Error(`org project set: gate key "${key}" \u2014 expected only runtime/cmd/workdir/cacheDepPath/pyVersion`);
|
|
28797
|
+
throw new Error(`org project set: gate key "${key}" \u2014 expected only runtime/cmd/affectedCmd/workdir/cacheDepPath/pyVersion`);
|
|
28794
28798
|
}
|
|
28795
28799
|
}
|
|
28796
28800
|
return out;
|
|
@@ -28891,7 +28895,7 @@ var SETTABLE_VAR_HINTS = {
|
|
|
28891
28895
|
requiredChecks: 'JSON array, e.g. ["gate"] or [] for no-ci',
|
|
28892
28896
|
requiredCheckBranches: "non-empty JSON branch-name array; exact product-ruleset scope (#5210)",
|
|
28893
28897
|
ciExemptReason: "non-empty string \u2014 declares this deployable repo has no CI surface (#4265)",
|
|
28894
|
-
gate: "JSON {runtime,cmd,workdir,cacheDepPath,pyVersion}"
|
|
28898
|
+
gate: "JSON {runtime,cmd,affectedCmd,workdir,cacheDepPath,pyVersion}"
|
|
28895
28899
|
};
|
|
28896
28900
|
function settableVarHelp() {
|
|
28897
28901
|
const keys = SETTABLE_VAR_KEYS.map((k) => {
|
|
@@ -35908,8 +35912,8 @@ function renderVerifySecrets(body) {
|
|
|
35908
35912
|
}
|
|
35909
35913
|
|
|
35910
35914
|
// src/command-register-collaboration.ts
|
|
35911
|
-
var
|
|
35912
|
-
var
|
|
35915
|
+
var import_node_child_process16 = require("node:child_process");
|
|
35916
|
+
var import_node_fs43 = require("node:fs");
|
|
35913
35917
|
var import_promises7 = require("node:fs/promises");
|
|
35914
35918
|
|
|
35915
35919
|
// src/session-runtime.ts
|
|
@@ -35929,7 +35933,7 @@ function spawnDetachedSelf(args, deps, opts = {}) {
|
|
|
35929
35933
|
}
|
|
35930
35934
|
|
|
35931
35935
|
// src/command-register-collaboration.ts
|
|
35932
|
-
var
|
|
35936
|
+
var import_node_path40 = require("node:path");
|
|
35933
35937
|
|
|
35934
35938
|
// src/attach-to-project.ts
|
|
35935
35939
|
function boardAttachRateLimitedReceipt(resetEpochSeconds) {
|
|
@@ -37581,15 +37585,193 @@ function postMergeReconWarnings(input) {
|
|
|
37581
37585
|
return lines2;
|
|
37582
37586
|
}
|
|
37583
37587
|
|
|
37584
|
-
// src/
|
|
37588
|
+
// src/review-verdict.ts
|
|
37585
37589
|
var import_node_child_process14 = require("node:child_process");
|
|
37590
|
+
var import_node_fs39 = require("node:fs");
|
|
37591
|
+
var import_node_os19 = require("node:os");
|
|
37592
|
+
var import_node_path36 = require("node:path");
|
|
37593
|
+
var REVIEW_VERDICT_MARKER = "<!-- zeroci-review v1 -->";
|
|
37594
|
+
var REVIEW_WAIVER_MARKER = "<!-- zeroci-review-waived v1 -->";
|
|
37595
|
+
var REVIEW_VERDICTS = ["PROCEED", "CORRECT", "ESCALATE"];
|
|
37596
|
+
function isReviewVerdict(value) {
|
|
37597
|
+
return typeof value === "string" && REVIEW_VERDICTS.includes(value);
|
|
37598
|
+
}
|
|
37599
|
+
function renderReviewVerdictComment(input) {
|
|
37600
|
+
const payload = {
|
|
37601
|
+
v: 1,
|
|
37602
|
+
patch: input.patch,
|
|
37603
|
+
head: input.head,
|
|
37604
|
+
verdict: input.verdict,
|
|
37605
|
+
scope: input.scope,
|
|
37606
|
+
risk: input.risk,
|
|
37607
|
+
unverified: input.unverified,
|
|
37608
|
+
reviewer: input.reviewer
|
|
37609
|
+
};
|
|
37610
|
+
const findings = input.findings?.trim();
|
|
37611
|
+
return `${REVIEW_VERDICT_MARKER}
|
|
37612
|
+
\`\`\`json
|
|
37613
|
+
${JSON.stringify(payload, null, 2)}
|
|
37614
|
+
\`\`\`
|
|
37615
|
+
${findings ? `
|
|
37616
|
+
${findings}
|
|
37617
|
+
` : ""}`;
|
|
37618
|
+
}
|
|
37619
|
+
function isReviewVerdictComment(body) {
|
|
37620
|
+
return body.trimStart().startsWith(REVIEW_VERDICT_MARKER);
|
|
37621
|
+
}
|
|
37622
|
+
var FENCE_RE = /^(?:`{3,}|~{3,})[^\n]*\n([\s\S]*?)\n(?:`{3,}|~{3,})\s*$/m;
|
|
37623
|
+
function parseReviewVerdictComment(body) {
|
|
37624
|
+
if (!isReviewVerdictComment(body)) return void 0;
|
|
37625
|
+
const rest = body.trimStart().slice(REVIEW_VERDICT_MARKER.length);
|
|
37626
|
+
const fence = FENCE_RE.exec(rest);
|
|
37627
|
+
if (!fence) return void 0;
|
|
37628
|
+
let parsed;
|
|
37629
|
+
try {
|
|
37630
|
+
parsed = JSON.parse(fence[1]);
|
|
37631
|
+
} catch {
|
|
37632
|
+
return void 0;
|
|
37633
|
+
}
|
|
37634
|
+
if (!parsed || typeof parsed !== "object") return void 0;
|
|
37635
|
+
const p = parsed;
|
|
37636
|
+
if (p.v !== 1 || !isReviewVerdict(p.verdict)) return void 0;
|
|
37637
|
+
if (typeof p.patch !== "string" || !/^[0-9a-f]{40}$/.test(p.patch)) return void 0;
|
|
37638
|
+
if (typeof p.head !== "string" || typeof p.scope !== "string" || typeof p.risk !== "string" || typeof p.reviewer !== "string") return void 0;
|
|
37639
|
+
const unverified = Array.isArray(p.unverified) ? p.unverified.filter((u) => typeof u === "string") : [];
|
|
37640
|
+
return { v: 1, patch: p.patch, head: p.head, verdict: p.verdict, scope: p.scope, risk: p.risk, unverified, reviewer: p.reviewer };
|
|
37641
|
+
}
|
|
37642
|
+
function evaluateReviewVerdict(comments, currentPatchId) {
|
|
37643
|
+
let latest;
|
|
37644
|
+
for (const c of comments) {
|
|
37645
|
+
if (!isReviewVerdictComment(c.body)) continue;
|
|
37646
|
+
if (!latest || c.createdAt >= latest.createdAt) latest = c;
|
|
37647
|
+
}
|
|
37648
|
+
if (!latest) return { ok: false, reason: "none" };
|
|
37649
|
+
const payload = parseReviewVerdictComment(latest.body);
|
|
37650
|
+
if (!payload) return { ok: false, reason: "malformed" };
|
|
37651
|
+
if (payload.verdict !== "PROCEED") return { ok: false, reason: "not-proceed", verdict: payload.verdict, patch: payload.patch };
|
|
37652
|
+
if (payload.patch !== currentPatchId) return { ok: false, reason: "stale", verdict: payload.verdict, patch: payload.patch };
|
|
37653
|
+
return { ok: true, reason: "proceed", verdict: payload.verdict, patch: payload.patch };
|
|
37654
|
+
}
|
|
37655
|
+
function reviewVerdictRemedyCommand(number, repo) {
|
|
37656
|
+
return `mmi-cli devops pr review-verdict ${number} --repo ${repo} --verdict PROCEED --scope "<one line>" --risk "<one line>" --reviewer <seat-or-model-id>`;
|
|
37657
|
+
}
|
|
37658
|
+
function reviewVerdictRefusalMessage(context, number, repo, evaluation, currentPatchId) {
|
|
37659
|
+
const why = {
|
|
37660
|
+
none: "no review verdict comment on the PR",
|
|
37661
|
+
stale: `the latest verdict is bound to patch ${evaluation.patch} but the PR's current diff is ${currentPatchId} \u2014 the content changed since the review`,
|
|
37662
|
+
"not-proceed": `the latest verdict is ${evaluation.verdict}, not PROCEED`,
|
|
37663
|
+
malformed: "the latest verdict comment is malformed (marker present, JSON block unreadable or wrong shape)",
|
|
37664
|
+
proceed: "proceed"
|
|
37665
|
+
}[evaluation.reason];
|
|
37666
|
+
return `${context}: REVIEW VERDICT REQUIRED (#6255) \u2014 ${why}. Review PR #${number} and post the verdict, then rerun:
|
|
37667
|
+
${reviewVerdictRemedyCommand(number, repo)}
|
|
37668
|
+
To land without a review, pass --without-review "<reason>" \u2014 it posts a waiver comment on the PR.`;
|
|
37669
|
+
}
|
|
37670
|
+
function renderReviewWaiverComment(reason, actor) {
|
|
37671
|
+
return `${REVIEW_WAIVER_MARKER}
|
|
37672
|
+
Review gate waived by @${actor}: ${reason.trim()}
|
|
37673
|
+
`;
|
|
37674
|
+
}
|
|
37675
|
+
function computePrPatchId(number, repo) {
|
|
37676
|
+
return new Promise((resolve7, reject) => {
|
|
37677
|
+
const gh = (0, import_node_child_process14.spawn)("gh", ["pr", "diff", number, "--repo", repo], { windowsHide: true, stdio: ["ignore", "pipe", "pipe"] });
|
|
37678
|
+
const git3 = (0, import_node_child_process14.spawn)("git", ["patch-id", "--stable"], { windowsHide: true, stdio: ["pipe", "pipe", "pipe"] });
|
|
37679
|
+
let out = "";
|
|
37680
|
+
let ghErr = "";
|
|
37681
|
+
let gitErr = "";
|
|
37682
|
+
const timer = setTimeout(() => {
|
|
37683
|
+
gh.kill();
|
|
37684
|
+
git3.kill();
|
|
37685
|
+
reject(new Error(`patch-id: timed out after ${GC_GH_TIMEOUT_MS4}ms`));
|
|
37686
|
+
}, GC_GH_TIMEOUT_MS4);
|
|
37687
|
+
gh.stdout.pipe(git3.stdin);
|
|
37688
|
+
gh.stderr.on("data", (d) => {
|
|
37689
|
+
ghErr += d.toString();
|
|
37690
|
+
});
|
|
37691
|
+
git3.stderr.on("data", (d) => {
|
|
37692
|
+
gitErr += d.toString();
|
|
37693
|
+
});
|
|
37694
|
+
git3.stdout.on("data", (d) => {
|
|
37695
|
+
out += d.toString();
|
|
37696
|
+
});
|
|
37697
|
+
gh.on("error", (e) => {
|
|
37698
|
+
clearTimeout(timer);
|
|
37699
|
+
reject(e);
|
|
37700
|
+
});
|
|
37701
|
+
git3.on("error", (e) => {
|
|
37702
|
+
clearTimeout(timer);
|
|
37703
|
+
reject(e);
|
|
37704
|
+
});
|
|
37705
|
+
let ghCode;
|
|
37706
|
+
gh.on("close", (code) => {
|
|
37707
|
+
ghCode = code;
|
|
37708
|
+
});
|
|
37709
|
+
git3.on("close", (code) => {
|
|
37710
|
+
clearTimeout(timer);
|
|
37711
|
+
if (ghCode) return reject(Object.assign(new Error(`gh pr diff ${number} --repo ${repo} exited ${ghCode}: ${ghErr.trim()}`), { stderr: ghErr }));
|
|
37712
|
+
if (code) return reject(new Error(`git patch-id --stable exited ${code}: ${gitErr.trim()}`));
|
|
37713
|
+
const id = out.trim().split(/\s+/)[0];
|
|
37714
|
+
if (!/^[0-9a-f]{40}$/.test(id ?? "")) return reject(new Error(`patch-id: PR #${number} diff is empty or unreadable (gh: ${ghErr.trim() || "no stderr"})`));
|
|
37715
|
+
resolve7(id);
|
|
37716
|
+
});
|
|
37717
|
+
});
|
|
37718
|
+
}
|
|
37719
|
+
async function readPrHeadSha(number, repo) {
|
|
37720
|
+
const { stdout } = await execFileP("gh", ["api", `repos/${repo}/pulls/${number}`, "--jq", ".head.sha"], { timeout: GC_GH_TIMEOUT_MS4 });
|
|
37721
|
+
const sha = stdout.trim();
|
|
37722
|
+
if (!/^[0-9a-f]{40}$/.test(sha)) throw new Error(`could not read PR #${number} head sha`);
|
|
37723
|
+
return sha;
|
|
37724
|
+
}
|
|
37725
|
+
async function readPrIssueComments(number, repo) {
|
|
37726
|
+
const { stdout } = await execFileP("gh", ["api", "--paginate", `repos/${repo}/issues/${number}/comments?per_page=100`, "--jq", ".[] | {body, createdAt: .created_at}"], { timeout: GC_GH_TIMEOUT_MS4 });
|
|
37727
|
+
return parseNdjsonLines(stdout);
|
|
37728
|
+
}
|
|
37729
|
+
async function postPrCommentFromFile(number, repo, body) {
|
|
37730
|
+
const dir = (0, import_node_fs39.mkdtempSync)((0, import_node_path36.join)((0, import_node_os19.tmpdir)(), "mmi-review-verdict-"));
|
|
37731
|
+
const path2 = (0, import_node_path36.join)(dir, "body.md");
|
|
37732
|
+
try {
|
|
37733
|
+
(0, import_node_fs39.writeFileSync)(path2, body, "utf8");
|
|
37734
|
+
const { stdout } = await execFileP("gh", ["pr", "comment", number, "--repo", repo, "--body-file", path2], { timeout: GH_MUTATION_TIMEOUT_MS });
|
|
37735
|
+
return stdout.trim();
|
|
37736
|
+
} finally {
|
|
37737
|
+
try {
|
|
37738
|
+
(0, import_node_fs39.rmSync)(dir, { recursive: true, force: true });
|
|
37739
|
+
} catch {
|
|
37740
|
+
}
|
|
37741
|
+
}
|
|
37742
|
+
}
|
|
37743
|
+
async function requireReviewVerdict(context, number, repo, opts) {
|
|
37744
|
+
if (opts.withoutReview !== void 0) {
|
|
37745
|
+
const reason = opts.withoutReview.trim();
|
|
37746
|
+
if (!reason) throw new Error(`${context}: --without-review needs a non-empty reason`);
|
|
37747
|
+
const actor = await execFileP("gh", ["api", "user", "--jq", ".login"], { timeout: GC_GH_TIMEOUT_MS4 }).then((r) => r.stdout.trim()).catch(() => "") || "unknown";
|
|
37748
|
+
await postPrCommentFromFile(number, repo, renderReviewWaiverComment(reason, actor));
|
|
37749
|
+
console.warn(`${context}: review gate WAIVED by @${actor} \u2014 ${reason} (waiver comment posted on PR #${number})`);
|
|
37750
|
+
return void 0;
|
|
37751
|
+
}
|
|
37752
|
+
let comments;
|
|
37753
|
+
let currentPatchId;
|
|
37754
|
+
try {
|
|
37755
|
+
[comments, currentPatchId] = await Promise.all([readPrIssueComments(number, repo), computePrPatchId(number, repo)]);
|
|
37756
|
+
} catch (e) {
|
|
37757
|
+
const detail = e.message || String(e);
|
|
37758
|
+
const limited = isGitHubRateLimitError(e) ? " (gh rate-limited \u2014 retry after the pool resets)" : "";
|
|
37759
|
+
throw new Error(`${context}: cannot read PR #${number}'s review verdict${limited} \u2014 ${detail}. Refusing to merge WITHOUT the review gate (#6255).`);
|
|
37760
|
+
}
|
|
37761
|
+
const evaluation = evaluateReviewVerdict(comments, currentPatchId);
|
|
37762
|
+
if (evaluation.ok) return void 0;
|
|
37763
|
+
return reviewVerdictRefusalMessage(context, number, repo, evaluation, currentPatchId);
|
|
37764
|
+
}
|
|
37765
|
+
|
|
37766
|
+
// src/pr-create-docs-check.ts
|
|
37767
|
+
var import_node_child_process15 = require("node:child_process");
|
|
37586
37768
|
var GIT_TIMEOUT_MS2 = 15e3;
|
|
37587
37769
|
function catFileBatch(root, ref, paths) {
|
|
37588
37770
|
if (paths.length === 0) return Promise.resolve([]);
|
|
37589
37771
|
return new Promise((resolve7) => {
|
|
37590
37772
|
const chunks = [];
|
|
37591
37773
|
let settled = false;
|
|
37592
|
-
const child2 = (0,
|
|
37774
|
+
const child2 = (0, import_node_child_process15.spawn)("git", ["-C", root, "cat-file", "--batch", "--buffer"], { windowsHide: true });
|
|
37593
37775
|
const finish = () => {
|
|
37594
37776
|
if (settled) return;
|
|
37595
37777
|
settled = true;
|
|
@@ -37759,26 +37941,26 @@ async function prCreateClaimRefusal(body, repoOption, deps = {}) {
|
|
|
37759
37941
|
}
|
|
37760
37942
|
|
|
37761
37943
|
// src/worktree-merge-cleanup.ts
|
|
37762
|
-
var
|
|
37763
|
-
var
|
|
37944
|
+
var import_node_fs42 = require("node:fs");
|
|
37945
|
+
var import_node_path39 = require("node:path");
|
|
37764
37946
|
|
|
37765
37947
|
// src/jervcode-node-modules-cleanup.ts
|
|
37766
|
-
var
|
|
37767
|
-
var
|
|
37768
|
-
var
|
|
37769
|
-
var JERVCODE_PACKAGE_ENTRY = (0,
|
|
37948
|
+
var import_node_fs40 = require("node:fs");
|
|
37949
|
+
var import_node_os20 = require("node:os");
|
|
37950
|
+
var import_node_path37 = require("node:path");
|
|
37951
|
+
var JERVCODE_PACKAGE_ENTRY = (0, import_node_path37.join)("node_modules", "@jervaise", "jervcode", "dist", "launcher-entry.js");
|
|
37770
37952
|
var WIN_NAMES2 = ["jervcode.cmd", "jervcode"];
|
|
37771
37953
|
var POSIX_NAMES2 = ["jervcode"];
|
|
37772
37954
|
var NODE_MODULES_CLEANUP_TIMEOUT_MS = 3e5;
|
|
37773
|
-
function jervcodeCandidatePaths(env = process.env, home = (0,
|
|
37955
|
+
function jervcodeCandidatePaths(env = process.env, home = (0, import_node_os20.homedir)(), platform2 = process.platform) {
|
|
37774
37956
|
const names = platform2 === "win32" ? WIN_NAMES2 : POSIX_NAMES2;
|
|
37775
37957
|
const out = [];
|
|
37776
37958
|
for (const dir of jervCliCandidateDirs(env, home, platform2)) {
|
|
37777
|
-
for (const name of names) out.push((0,
|
|
37959
|
+
for (const name of names) out.push((0, import_node_path37.join)(dir, name));
|
|
37778
37960
|
}
|
|
37779
37961
|
return out;
|
|
37780
37962
|
}
|
|
37781
|
-
function resolveJervcodePath(env = process.env, home = (0,
|
|
37963
|
+
function resolveJervcodePath(env = process.env, home = (0, import_node_os20.homedir)(), platform2 = process.platform, exists = import_node_fs40.existsSync) {
|
|
37782
37964
|
for (const candidate of jervcodeCandidatePaths(env, home, platform2)) {
|
|
37783
37965
|
if (exists(candidate)) return candidate;
|
|
37784
37966
|
}
|
|
@@ -37786,10 +37968,10 @@ function resolveJervcodePath(env = process.env, home = (0, import_node_os19.home
|
|
|
37786
37968
|
}
|
|
37787
37969
|
function jervcodeExecFileArgs(args, opts = {}) {
|
|
37788
37970
|
const platform2 = opts.platform ?? process.platform;
|
|
37789
|
-
const exists = opts.exists ??
|
|
37790
|
-
const resolved = resolveJervcodePath(opts.env ?? process.env, opts.home ?? (0,
|
|
37971
|
+
const exists = opts.exists ?? import_node_fs40.existsSync;
|
|
37972
|
+
const resolved = resolveJervcodePath(opts.env ?? process.env, opts.home ?? (0, import_node_os20.homedir)(), platform2, exists);
|
|
37791
37973
|
if (resolved) {
|
|
37792
|
-
const entry = (0,
|
|
37974
|
+
const entry = (0, import_node_path37.join)((0, import_node_path37.join)(resolved, ".."), JERVCODE_PACKAGE_ENTRY);
|
|
37793
37975
|
if (exists(entry)) {
|
|
37794
37976
|
return { file: opts.execPath ?? process.execPath, args: [entry, ...args], via: "node-entry" };
|
|
37795
37977
|
}
|
|
@@ -37820,8 +38002,8 @@ async function removeWorktreeNodeModulesViaHelper(wtPath, opts = {}) {
|
|
|
37820
38002
|
}
|
|
37821
38003
|
|
|
37822
38004
|
// src/worktree-evidence-archive.ts
|
|
37823
|
-
var
|
|
37824
|
-
var
|
|
38005
|
+
var import_node_fs41 = require("node:fs");
|
|
38006
|
+
var import_node_path38 = require("node:path");
|
|
37825
38007
|
var JERV_ARTIFACT_RUN_SCOPE_ENV_VARS = ["JERV_RUN_ID", ...SESSION_ID_ENV_VARS];
|
|
37826
38008
|
function sanitizeArchiveSegment(value, max = 80) {
|
|
37827
38009
|
const scrubbed = value.replace(/[^A-Za-z0-9._@+-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
@@ -37836,24 +38018,24 @@ function resolveArtifactRunScope(env = process.env) {
|
|
|
37836
38018
|
}
|
|
37837
38019
|
function defaultIsDirectory(path2) {
|
|
37838
38020
|
try {
|
|
37839
|
-
return (0,
|
|
38021
|
+
return (0, import_node_fs41.lstatSync)(path2).isDirectory();
|
|
37840
38022
|
} catch {
|
|
37841
38023
|
return false;
|
|
37842
38024
|
}
|
|
37843
38025
|
}
|
|
37844
38026
|
function archiveWorktreeJervArtifacts(args, deps = {}) {
|
|
37845
|
-
const exists = deps.exists ??
|
|
38027
|
+
const exists = deps.exists ?? import_node_fs41.existsSync;
|
|
37846
38028
|
const isDirectory = deps.isDirectory ?? defaultIsDirectory;
|
|
37847
|
-
const copyDir = deps.copyDir ?? ((from, to) => (0,
|
|
38029
|
+
const copyDir = deps.copyDir ?? ((from, to) => (0, import_node_fs41.cpSync)(from, to, { recursive: true, force: true }));
|
|
37848
38030
|
const mkdirp = deps.mkdirp ?? ((path2) => {
|
|
37849
|
-
(0,
|
|
38031
|
+
(0, import_node_fs41.mkdirSync)(path2, { recursive: true });
|
|
37850
38032
|
});
|
|
37851
38033
|
const env = deps.env ?? process.env;
|
|
37852
38034
|
const now = deps.now ?? (() => /* @__PURE__ */ new Date());
|
|
37853
38035
|
const resolveRoot = deps.resolveArchiveRoot ?? repoRuntimeStatePath;
|
|
37854
38036
|
if (!args.primaryRoot?.trim()) return { status: "skipped", reason: "missing-primary-root" };
|
|
37855
38037
|
if (!args.worktreePath?.trim()) return { status: "skipped", reason: "missing-worktree-path" };
|
|
37856
|
-
const source = (0,
|
|
38038
|
+
const source = (0, import_node_path38.join)(args.worktreePath, ".jerv");
|
|
37857
38039
|
if (!exists(source)) return { status: "absent" };
|
|
37858
38040
|
if (!isDirectory(source)) return { status: "skipped", reason: "jerv-not-a-directory" };
|
|
37859
38041
|
const runScope = resolveArtifactRunScope(env);
|
|
@@ -37861,7 +38043,7 @@ function archiveWorktreeJervArtifacts(args, deps = {}) {
|
|
|
37861
38043
|
const stamp = now().toISOString().replace(/[:.]/g, "-");
|
|
37862
38044
|
const dest = resolveRoot(args.primaryRoot, "jerv-artifacts", runScope, branchSlug, stamp, ".jerv");
|
|
37863
38045
|
try {
|
|
37864
|
-
mkdirp((0,
|
|
38046
|
+
mkdirp((0, import_node_path38.dirname)(dest));
|
|
37865
38047
|
copyDir(source, dest);
|
|
37866
38048
|
if (!exists(dest)) return { status: "failed", error: `archive write left no directory at ${dest}` };
|
|
37867
38049
|
return { status: "archived", path: dest, runScope };
|
|
@@ -37870,14 +38052,14 @@ function archiveWorktreeJervArtifacts(args, deps = {}) {
|
|
|
37870
38052
|
}
|
|
37871
38053
|
}
|
|
37872
38054
|
function defaultStat(path2) {
|
|
37873
|
-
const st = (0,
|
|
38055
|
+
const st = (0, import_node_fs41.statSync)(path2);
|
|
37874
38056
|
return { mtimeMs: st.mtimeMs, size: st.size, isDirectory: () => st.isDirectory() };
|
|
37875
38057
|
}
|
|
37876
38058
|
function scanWorktreeTmpEvidence(worktreePath, newerThanMs, deps = {}) {
|
|
37877
|
-
const exists = deps.exists ??
|
|
38059
|
+
const exists = deps.exists ?? import_node_fs41.existsSync;
|
|
37878
38060
|
const stat4 = deps.stat ?? defaultStat;
|
|
37879
|
-
const readdir2 = deps.readdir ??
|
|
37880
|
-
const tmpRoot = (0,
|
|
38061
|
+
const readdir2 = deps.readdir ?? import_node_fs41.readdirSync;
|
|
38062
|
+
const tmpRoot = (0, import_node_path38.join)(worktreePath, "tmp");
|
|
37881
38063
|
if (!exists(tmpRoot)) return [];
|
|
37882
38064
|
const entries = [];
|
|
37883
38065
|
const walk2 = (dir) => {
|
|
@@ -37888,14 +38070,14 @@ function scanWorktreeTmpEvidence(worktreePath, newerThanMs, deps = {}) {
|
|
|
37888
38070
|
return;
|
|
37889
38071
|
}
|
|
37890
38072
|
for (const name of names) {
|
|
37891
|
-
const full = (0,
|
|
38073
|
+
const full = (0, import_node_path38.join)(dir, name);
|
|
37892
38074
|
let st;
|
|
37893
38075
|
try {
|
|
37894
38076
|
st = stat4(full);
|
|
37895
38077
|
} catch {
|
|
37896
38078
|
continue;
|
|
37897
38079
|
}
|
|
37898
|
-
const relPath = (0,
|
|
38080
|
+
const relPath = (0, import_node_path38.relative)(worktreePath, full).replace(/\\/g, "/");
|
|
37899
38081
|
if (st.isDirectory()) {
|
|
37900
38082
|
if (st.mtimeMs > newerThanMs) entries.push({ relPath, bytes: 0, mtimeMs: st.mtimeMs });
|
|
37901
38083
|
walk2(full);
|
|
@@ -37909,10 +38091,10 @@ function scanWorktreeTmpEvidence(worktreePath, newerThanMs, deps = {}) {
|
|
|
37909
38091
|
return entries;
|
|
37910
38092
|
}
|
|
37911
38093
|
function archiveWorktreeTmpArtifacts(args, deps = {}) {
|
|
37912
|
-
const exists = deps.exists ??
|
|
37913
|
-
const copyDir = deps.copyDir ?? ((from, to) => (0,
|
|
38094
|
+
const exists = deps.exists ?? import_node_fs41.existsSync;
|
|
38095
|
+
const copyDir = deps.copyDir ?? ((from, to) => (0, import_node_fs41.cpSync)(from, to, { recursive: true, force: true }));
|
|
37914
38096
|
const mkdirp = deps.mkdirp ?? ((path2) => {
|
|
37915
|
-
(0,
|
|
38097
|
+
(0, import_node_fs41.mkdirSync)(path2, { recursive: true });
|
|
37916
38098
|
});
|
|
37917
38099
|
const env = deps.env ?? process.env;
|
|
37918
38100
|
const now = deps.now ?? (() => /* @__PURE__ */ new Date());
|
|
@@ -37920,7 +38102,7 @@ function archiveWorktreeTmpArtifacts(args, deps = {}) {
|
|
|
37920
38102
|
if (!args.primaryRoot?.trim()) return { status: "skipped", reason: "missing-primary-root" };
|
|
37921
38103
|
if (!args.worktreePath?.trim()) return { status: "skipped", reason: "missing-worktree-path" };
|
|
37922
38104
|
const scanned = scanWorktreeTmpEvidence(args.worktreePath, args.newerThanMs, deps);
|
|
37923
|
-
const source = (0,
|
|
38105
|
+
const source = (0, import_node_path38.join)(args.worktreePath, "tmp");
|
|
37924
38106
|
if (!scanned.length) return { status: "absent" };
|
|
37925
38107
|
if (!exists(source)) return { status: "absent" };
|
|
37926
38108
|
const runScope = resolveArtifactRunScope(env);
|
|
@@ -37928,7 +38110,7 @@ function archiveWorktreeTmpArtifacts(args, deps = {}) {
|
|
|
37928
38110
|
const stamp = now().toISOString().replace(/[:.]/g, "-");
|
|
37929
38111
|
const dest = resolveRoot(args.primaryRoot, "worktree-artifacts", runScope, branchSlug, stamp, "tmp");
|
|
37930
38112
|
try {
|
|
37931
|
-
mkdirp((0,
|
|
38113
|
+
mkdirp((0, import_node_path38.dirname)(dest));
|
|
37932
38114
|
copyDir(source, dest);
|
|
37933
38115
|
if (!exists(dest)) return { status: "failed", error: `archive write left no directory at ${dest}` };
|
|
37934
38116
|
const bytes = scanned.reduce((sum, e) => sum + e.bytes, 0);
|
|
@@ -37997,9 +38179,9 @@ function normPath2(p) {
|
|
|
37997
38179
|
return p.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
37998
38180
|
}
|
|
37999
38181
|
function unlinkNodeModulesJunction(wtPath) {
|
|
38000
|
-
const nm = (0,
|
|
38182
|
+
const nm = (0, import_node_path39.join)(wtPath, "node_modules");
|
|
38001
38183
|
try {
|
|
38002
|
-
if ((0,
|
|
38184
|
+
if ((0, import_node_fs42.lstatSync)(nm).isSymbolicLink()) (0, import_node_fs42.rmdirSync)(nm);
|
|
38003
38185
|
return { ok: true };
|
|
38004
38186
|
} catch (e) {
|
|
38005
38187
|
if (e.code === "ENOENT") return { ok: true };
|
|
@@ -38010,8 +38192,8 @@ function defaultSleep2(ms) {
|
|
|
38010
38192
|
return new Promise((resolve7) => setTimeout(resolve7, ms));
|
|
38011
38193
|
}
|
|
38012
38194
|
async function removeResidueDirectory(wtPath, options = {}) {
|
|
38013
|
-
const { sleep: sleep2 = defaultSleep2, removeEmptyDir =
|
|
38014
|
-
const removeRecursive = options.removeRecursive ?? ((path2) => (0,
|
|
38195
|
+
const { sleep: sleep2 = defaultSleep2, removeEmptyDir = import_node_fs42.rmdirSync, exists = import_node_fs42.existsSync } = options;
|
|
38196
|
+
const removeRecursive = options.removeRecursive ?? ((path2) => (0, import_node_fs42.rmSync)(path2, { recursive: true, force: true, maxRetries: 10, retryDelay: 100 }));
|
|
38015
38197
|
const junction = unlinkNodeModulesJunction(wtPath);
|
|
38016
38198
|
if (!junction.ok) return junction;
|
|
38017
38199
|
try {
|
|
@@ -38134,31 +38316,31 @@ async function preCleanWorktreeForRemoval(wtPath, execGit) {
|
|
|
38134
38316
|
}
|
|
38135
38317
|
async function listNestedIgnoredNodeModules(wtPath, execGit) {
|
|
38136
38318
|
const out = await execGit(["-C", wtPath, "ls-files", "--others", "--ignored", "--exclude-standard", "--directory"]).catch(() => "");
|
|
38137
|
-
return out.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.endsWith("node_modules/") && line !== "node_modules/").map((line) => (0,
|
|
38319
|
+
return out.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.endsWith("node_modules/") && line !== "node_modules/").map((line) => (0, import_node_path39.join)(wtPath, line.slice(0, -1)));
|
|
38138
38320
|
}
|
|
38139
38321
|
function safeRemoveTree(path2) {
|
|
38140
|
-
const stat4 = (0,
|
|
38322
|
+
const stat4 = (0, import_node_fs42.lstatSync)(path2);
|
|
38141
38323
|
if (stat4.isSymbolicLink()) {
|
|
38142
38324
|
try {
|
|
38143
|
-
(0,
|
|
38325
|
+
(0, import_node_fs42.rmdirSync)(path2);
|
|
38144
38326
|
} catch {
|
|
38145
|
-
(0,
|
|
38327
|
+
(0, import_node_fs42.unlinkSync)(path2);
|
|
38146
38328
|
}
|
|
38147
38329
|
return;
|
|
38148
38330
|
}
|
|
38149
38331
|
if (stat4.isDirectory()) {
|
|
38150
|
-
for (const entry of (0,
|
|
38151
|
-
(0,
|
|
38332
|
+
for (const entry of (0, import_node_fs42.readdirSync)(path2)) safeRemoveTree((0, import_node_path39.join)(path2, entry));
|
|
38333
|
+
(0, import_node_fs42.rmdirSync)(path2);
|
|
38152
38334
|
return;
|
|
38153
38335
|
}
|
|
38154
|
-
(0,
|
|
38336
|
+
(0, import_node_fs42.unlinkSync)(path2);
|
|
38155
38337
|
}
|
|
38156
38338
|
function errorMessage(e) {
|
|
38157
38339
|
return e instanceof Error ? e.message : String(e);
|
|
38158
38340
|
}
|
|
38159
38341
|
function resolvedOrRaw(path2) {
|
|
38160
38342
|
try {
|
|
38161
|
-
return normPath2((0,
|
|
38343
|
+
return normPath2((0, import_node_fs42.realpathSync)(path2));
|
|
38162
38344
|
} catch {
|
|
38163
38345
|
return normPath2(path2);
|
|
38164
38346
|
}
|
|
@@ -38166,10 +38348,10 @@ function resolvedOrRaw(path2) {
|
|
|
38166
38348
|
function unlinkEscapingReparsePoints(root, primaryRoot) {
|
|
38167
38349
|
let realRoot;
|
|
38168
38350
|
try {
|
|
38169
|
-
if ((0,
|
|
38351
|
+
if ((0, import_node_fs42.lstatSync)(root).isSymbolicLink()) {
|
|
38170
38352
|
return { ok: false, error: `delete root ${normPath2(root)} is a reparse point resolving to ${resolvedOrRaw(root)}` };
|
|
38171
38353
|
}
|
|
38172
|
-
realRoot = normPath2((0,
|
|
38354
|
+
realRoot = normPath2((0, import_node_fs42.realpathSync)(root));
|
|
38173
38355
|
} catch (e) {
|
|
38174
38356
|
if (e.code === "ENOENT") return { ok: true, unlinked: [] };
|
|
38175
38357
|
return { ok: false, error: `cannot resolve delete root ${normPath2(root)}: ${errorMessage(e)}` };
|
|
@@ -38185,16 +38367,16 @@ function unlinkEscapingReparsePoints(root, primaryRoot) {
|
|
|
38185
38367
|
const dir = stack.pop();
|
|
38186
38368
|
let entries;
|
|
38187
38369
|
try {
|
|
38188
|
-
entries = (0,
|
|
38370
|
+
entries = (0, import_node_fs42.readdirSync)(dir, { withFileTypes: true });
|
|
38189
38371
|
} catch (e) {
|
|
38190
38372
|
return { ok: false, error: `cannot scan ${normPath2(dir)} for reparse points: ${errorMessage(e)}` };
|
|
38191
38373
|
}
|
|
38192
38374
|
for (const entry of entries) {
|
|
38193
|
-
const child2 = (0,
|
|
38375
|
+
const child2 = (0, import_node_path39.join)(dir, entry.name);
|
|
38194
38376
|
if (entry.isSymbolicLink()) {
|
|
38195
38377
|
let target = "";
|
|
38196
38378
|
try {
|
|
38197
|
-
target = normPath2((0,
|
|
38379
|
+
target = normPath2((0, import_node_fs42.realpathSync)(child2));
|
|
38198
38380
|
} catch {
|
|
38199
38381
|
target = "";
|
|
38200
38382
|
}
|
|
@@ -38224,7 +38406,7 @@ async function describePreCleanFailure(wtPath, execGit, error) {
|
|
|
38224
38406
|
const more = remaining.length > 10 ? ` (+${remaining.length - 10} more)` : "";
|
|
38225
38407
|
const quote = (path2) => path2.replace(/'/g, "''");
|
|
38226
38408
|
const nested = remaining.find((path2) => path2.endsWith("node_modules/") && path2 !== "node_modules/");
|
|
38227
|
-
const remediation = remaining.includes("node_modules/") ? `jervcode worktree-node-modules-cleanup --worktree '${quote(wtPath)}'` : nested ? `Remove-Item -LiteralPath '${quote((0,
|
|
38409
|
+
const remediation = remaining.includes("node_modules/") ? `jervcode worktree-node-modules-cleanup --worktree '${quote(wtPath)}'` : nested ? `Remove-Item -LiteralPath '${quote((0, import_node_path39.join)(wtPath, nested.slice(0, -1)))}' -Recurse -Force` : void 0;
|
|
38228
38410
|
return { ok: false, error: `${error}; remaining ignored paths: ${shown}${more}`, ...remediation ? { remediation } : {} };
|
|
38229
38411
|
}
|
|
38230
38412
|
function formatWorktreeRemovalFailureDetail(options) {
|
|
@@ -38378,7 +38560,7 @@ async function cleanupPrMergeLocalBranch(branch, options) {
|
|
|
38378
38560
|
return report;
|
|
38379
38561
|
}
|
|
38380
38562
|
const execGit = options.execGit ?? (async (args) => (await execFileP("git", args, { timeout: GIT_TIMEOUT_MS })).stdout);
|
|
38381
|
-
const pathExists = options.pathExists ??
|
|
38563
|
+
const pathExists = options.pathExists ?? import_node_fs42.existsSync;
|
|
38382
38564
|
let afterWorktrees = [];
|
|
38383
38565
|
try {
|
|
38384
38566
|
afterWorktrees = parseGitWorktreePorcelain(await execGit(["worktree", "list", "--porcelain"]));
|
|
@@ -38518,7 +38700,7 @@ async function cleanupPrMergeLocalBranch(branch, options) {
|
|
|
38518
38700
|
const preHelperGuard = unlinkEscapingReparsePoints(wtPath, options.primaryRoot);
|
|
38519
38701
|
if (!preHelperGuard.ok) return refuseReparseEscape(preHelperGuard.error);
|
|
38520
38702
|
unlinkedReparsePoints.push(...preHelperGuard.unlinked);
|
|
38521
|
-
if (pathExists((0,
|
|
38703
|
+
if (pathExists((0, import_node_path39.join)(wtPath, "node_modules"))) {
|
|
38522
38704
|
const nmRemoved = await (options.removeRealNodeModules ?? ((p) => removeWorktreeNodeModulesViaHelper(p, { cwd: mainWorktreePath })))(wtPath);
|
|
38523
38705
|
if (!nmRemoved.ok) {
|
|
38524
38706
|
report.worktree = {
|
|
@@ -38685,10 +38867,10 @@ function argvWantsJson2() {
|
|
|
38685
38867
|
return process.argv.some((a) => a === "--json" || a.startsWith("--json="));
|
|
38686
38868
|
}
|
|
38687
38869
|
function hubRoot() {
|
|
38688
|
-
const fromPkg = (0,
|
|
38870
|
+
const fromPkg = (0, import_node_path40.join)(__dirname, "..", "..");
|
|
38689
38871
|
const marker = "skills/bootstrap/seeds/manifest.json";
|
|
38690
|
-
if ((0,
|
|
38691
|
-
if ((0,
|
|
38872
|
+
if ((0, import_node_fs43.existsSync)((0, import_node_path40.join)(fromPkg, marker))) return fromPkg;
|
|
38873
|
+
if ((0, import_node_fs43.existsSync)((0, import_node_path40.join)(process.cwd(), marker))) return process.cwd();
|
|
38692
38874
|
return null;
|
|
38693
38875
|
}
|
|
38694
38876
|
function ciAuditDeps() {
|
|
@@ -38700,8 +38882,8 @@ function ciAuditDeps() {
|
|
|
38700
38882
|
getProjectMeta: async (slug) => fetchProjectBySlug(slug, registryClientDeps(await cfgPromise)),
|
|
38701
38883
|
readSeedFile: (path2) => {
|
|
38702
38884
|
if (!root) return null;
|
|
38703
|
-
const fullPath = (0,
|
|
38704
|
-
return (0,
|
|
38885
|
+
const fullPath = (0, import_node_path40.join)(root, path2);
|
|
38886
|
+
return (0, import_node_fs43.existsSync)(fullPath) ? (0, import_node_fs43.readFileSync)(fullPath, "utf8") : null;
|
|
38705
38887
|
}
|
|
38706
38888
|
};
|
|
38707
38889
|
}
|
|
@@ -38783,7 +38965,7 @@ function scheduleRelatedDiscovery(o) {
|
|
|
38783
38965
|
try {
|
|
38784
38966
|
const args = ["issue", "discover-related", "--number", String(o.number), "--title", o.title, "--body", o.body, "--fail-soft"];
|
|
38785
38967
|
if (o.repo) args.push("--repo", o.repo);
|
|
38786
|
-
spawnDetachedSelf(args, { spawn:
|
|
38968
|
+
spawnDetachedSelf(args, { spawn: import_node_child_process16.spawn, execPath: process.execPath, scriptPath: process.argv[1] }, { cwd: process.cwd() });
|
|
38787
38969
|
} catch {
|
|
38788
38970
|
}
|
|
38789
38971
|
}
|
|
@@ -39344,11 +39526,11 @@ ${list}`);
|
|
|
39344
39526
|
}
|
|
39345
39527
|
});
|
|
39346
39528
|
async function listCiWorkflowPaths(cwd = process.cwd()) {
|
|
39347
|
-
const wfDir = (0,
|
|
39348
|
-
if (!(0,
|
|
39349
|
-
return (0,
|
|
39529
|
+
const wfDir = (0, import_node_path40.join)(cwd, ".github", "workflows");
|
|
39530
|
+
if (!(0, import_node_fs43.existsSync)(wfDir)) return [];
|
|
39531
|
+
return (0, import_node_fs43.readdirSync)(wfDir).filter((name) => /\.(ya?ml)$/i.test(name)).filter((name) => {
|
|
39350
39532
|
try {
|
|
39351
|
-
return workflowReportsPrChecks((0,
|
|
39533
|
+
return workflowReportsPrChecks((0, import_node_fs43.readFileSync)((0, import_node_path40.join)(wfDir, name), "utf8"));
|
|
39352
39534
|
} catch {
|
|
39353
39535
|
return true;
|
|
39354
39536
|
}
|
|
@@ -39536,7 +39718,28 @@ ${list}`);
|
|
|
39536
39718
|
if (result.status === "failure" || result.status === "conflicting") process.exitCode = 1;
|
|
39537
39719
|
if (result.status === "timeout" || result.status === "rate-limited") process.exitCode = PR_CHECKS_TIMEOUT_EXIT_CODE;
|
|
39538
39720
|
});
|
|
39539
|
-
pr.command("
|
|
39721
|
+
jsonParity(pr.command("review-verdict <number>").description("post the ZeroCI review verdict comment the merge helper requires (#6255): computes the PR diff patch-id and head sha itself, renders the v1 contract body, posts it as a PR comment. Only a PROCEED bound to the CURRENT diff lets `pr merge` / `pr land` merge").requiredOption("--repo <owner/repo>", "target repo").requiredOption("--verdict <verdict>", `one of ${REVIEW_VERDICTS.join("|")}`).requiredOption("--scope <text>", "one line: what was reviewed").requiredOption("--risk <text>", "one line: the residual risk").option("--unverified <text>", "a claim the reviewer could not verify (repeatable)", (v, acc) => [...acc, v], []).requiredOption("--reviewer <id>", "reviewer seat or model id").option("--findings-file <path>", "Markdown findings appended after the JSON block")).action(async (number, o) => {
|
|
39722
|
+
if (!isReviewVerdict(o.verdict)) return fail(`pr review-verdict: --verdict must be one of ${REVIEW_VERDICTS.join("|")} (got ${o.verdict})`);
|
|
39723
|
+
const verdict = o.verdict;
|
|
39724
|
+
const findings = o.findingsFile ? (0, import_node_fs43.readFileSync)(o.findingsFile, "utf8") : void 0;
|
|
39725
|
+
let patch;
|
|
39726
|
+
let head;
|
|
39727
|
+
try {
|
|
39728
|
+
[patch, head] = await Promise.all([computePrPatchId(number, o.repo), readPrHeadSha(number, o.repo)]);
|
|
39729
|
+
} catch (e) {
|
|
39730
|
+
return failGraceful(`pr review-verdict: ${e.message}`);
|
|
39731
|
+
}
|
|
39732
|
+
const body = renderReviewVerdictComment({ v: 1, patch, head, verdict, scope: o.scope, risk: o.risk, unverified: o.unverified, reviewer: o.reviewer, findings });
|
|
39733
|
+
let commentUrl;
|
|
39734
|
+
try {
|
|
39735
|
+
commentUrl = await postPrCommentFromFile(number, o.repo, body);
|
|
39736
|
+
} catch (e) {
|
|
39737
|
+
const err = e;
|
|
39738
|
+
return failGraceful(`pr review-verdict: ${(err.stderr || err.message || String(e)).trim()}`);
|
|
39739
|
+
}
|
|
39740
|
+
printLine(JSON.stringify({ number: Number(number), repo: o.repo, verdict, patch, head, commentUrl }));
|
|
39741
|
+
});
|
|
39742
|
+
pr.command("land <number>").description("agent merge path (#1440): train probe \u2014 checks-wait \u2014 merge --auto \u2014 poll enqueued \u2014 development PRs only").option("--json", "machine-readable output").option("--repo <owner/repo>", "target repo (defaults to the PR repo)").option("--no-require-train", "skip train-authority preflight (not recommended for autonomous agents)").option("--force", "acknowledge and land past a remaining prunable/severe scratch housekeeping block (advisory kept plans/ never blocks, #3012) or a negated-closing-keyword (#3718) or ambiguous-cross-repo-closing (#4279) refusal").option("--without-review <reason>", "land without a review verdict (#6255): posts a `zeroci-review-waived` comment carrying the reason and actor, then proceeds").action(async (number, o) => {
|
|
39540
39743
|
if (/^(?:[^/]+\/[^/]+)?#\d+$/.test(number.trim())) {
|
|
39541
39744
|
try {
|
|
39542
39745
|
const parsed = parseIssueRef(number, o.repo);
|
|
@@ -39571,6 +39774,15 @@ ${list}`);
|
|
|
39571
39774
|
return;
|
|
39572
39775
|
}
|
|
39573
39776
|
if (landClosingGuardVerdict.message) console.warn(landClosingGuardVerdict.message);
|
|
39777
|
+
{
|
|
39778
|
+
const gateRepo = landRepoForGuard ?? await requireRepo(o.repo);
|
|
39779
|
+
const refusal = await requireReviewVerdict("pr land", number, gateRepo, { withoutReview: o.withoutReview });
|
|
39780
|
+
if (refusal) {
|
|
39781
|
+
console.error(refusal);
|
|
39782
|
+
process.exitCode = 1;
|
|
39783
|
+
return;
|
|
39784
|
+
}
|
|
39785
|
+
}
|
|
39574
39786
|
const result = await runPrLand(number, { repo: o.repo, requireTrain: o.requireTrain !== false }, {
|
|
39575
39787
|
resolveRepo: async (prNumber, repoOpt) => {
|
|
39576
39788
|
const args = repoOpt ? ["--repo", repoOpt] : repoArgs;
|
|
@@ -39705,7 +39917,7 @@ ${list}`);
|
|
|
39705
39917
|
else printLine(`pr land: ${result.status}${result.error ? ` \u2014 ${result.error}` : ""}`);
|
|
39706
39918
|
if (result.status === "failed") process.exitCode = 1;
|
|
39707
39919
|
});
|
|
39708
|
-
jsonParity(pr.command("merge <number>").description("merge a PR (squash by default); archives gitignored tmp/** before worktree teardown; on no-ci repos run pr ci-policy / checks-wait first (#1432, #5679)").option("--squash", "squash merge (default)").option("--merge", "create a merge commit").option("--rebase", "rebase merge").option("--repo <owner/repo>", "target repo (defaults to the current repo); from a foreign checkout the remote probe/delete address this repo and local cleanup runs only in the verified sibling checkout ../<repo>, else localBranch reports skipped-foreign-cwd and the receipt carries foreignCwd: true (#6148)").option("--auto", "enable auto-merge \u2014 merge once the base-branch policy is satisfied (use for policy-gated repos)").addOption(new Option("--disable-auto", "disable a queued auto-merge without merging").conflicts(["auto", "wait", "squash", "merge", "rebase", "preserveWorktree", "gc", "squashBodyFile", "force"])).option("--wait", `wait for checks to reach a terminal passing verdict before merging (default budget ${PR_CHECKS_TIMEOUT_MS / 6e4}m) \u2014 run as a background/monitor task or under a shell timeout above that budget; a short foreground timeout (e.g. 120s) kills it after checks pass and leaves the PR open (#6027)`).option("--preserve-worktree", "after merge, keep the local PR worktree/branch for an active batch (#1888); also the merge settings-proof bypass when delete_branch_on_merge cannot be proven (#6210)").option("--gc", "acknowledge deleting unarchived gitignored tmp/** evidence newer than the branch base (#5679)").option("--squash-body-file <path>", "squash commit body (overrides GitHub COMMIT_MESSAGES); use when a pushed commit mentions close/fix/resolve + #N that must not close (#5723)").option("--force", "acknowledge and merge past a remaining prunable/severe scratch housekeeping block (advisory kept plans/ never blocks, #3012) or a negated-closing-keyword (#3718) or ambiguous-cross-repo-closing (#4279) refusal")).action(async (number, o) => {
|
|
39920
|
+
jsonParity(pr.command("merge <number>").description("merge a PR (squash by default); archives gitignored tmp/** before worktree teardown; on no-ci repos run pr ci-policy / checks-wait first (#1432, #5679)").option("--squash", "squash merge (default)").option("--merge", "create a merge commit").option("--rebase", "rebase merge").option("--repo <owner/repo>", "target repo (defaults to the current repo); from a foreign checkout the remote probe/delete address this repo and local cleanup runs only in the verified sibling checkout ../<repo>, else localBranch reports skipped-foreign-cwd and the receipt carries foreignCwd: true (#6148)").option("--auto", "enable auto-merge \u2014 merge once the base-branch policy is satisfied (use for policy-gated repos)").addOption(new Option("--disable-auto", "disable a queued auto-merge without merging").conflicts(["auto", "wait", "squash", "merge", "rebase", "preserveWorktree", "gc", "squashBodyFile", "force"])).option("--wait", `wait for checks to reach a terminal passing verdict before merging (default budget ${PR_CHECKS_TIMEOUT_MS / 6e4}m) \u2014 run as a background/monitor task or under a shell timeout above that budget; a short foreground timeout (e.g. 120s) kills it after checks pass and leaves the PR open (#6027)`).option("--preserve-worktree", "after merge, keep the local PR worktree/branch for an active batch (#1888); also the merge settings-proof bypass when delete_branch_on_merge cannot be proven (#6210)").option("--gc", "acknowledge deleting unarchived gitignored tmp/** evidence newer than the branch base (#5679)").option("--squash-body-file <path>", "squash commit body (overrides GitHub COMMIT_MESSAGES); use when a pushed commit mentions close/fix/resolve + #N that must not close (#5723)").option("--force", "acknowledge and merge past a remaining prunable/severe scratch housekeeping block (advisory kept plans/ never blocks, #3012) or a negated-closing-keyword (#3718) or ambiguous-cross-repo-closing (#4279) refusal").option("--without-review <reason>", "merge without a review verdict (#6255): posts a `zeroci-review-waived` comment carrying the reason and actor, then proceeds")).action(async (number, o) => {
|
|
39709
39921
|
const method = o.rebase ? "--rebase" : o.merge ? "--merge" : "--squash";
|
|
39710
39922
|
const repoArgs = o.repo ? ["--repo", o.repo] : [];
|
|
39711
39923
|
if (o.disableAuto) {
|
|
@@ -39743,7 +39955,7 @@ ${list}`);
|
|
|
39743
39955
|
const mergeSquashBody = squashBodyTextForMerge(
|
|
39744
39956
|
closingGuardInput,
|
|
39745
39957
|
method === "--squash",
|
|
39746
|
-
o.squashBodyFile ? (0,
|
|
39958
|
+
o.squashBodyFile ? (0, import_node_fs43.readFileSync)(o.squashBodyFile, "utf8") : void 0
|
|
39747
39959
|
);
|
|
39748
39960
|
if (!o.squashBodyFile) warnSquashBodyClosingStrip("pr merge", closingGuardInput, mergeSquashBody);
|
|
39749
39961
|
const closingGuardVerdict = evaluateClosingGuard(closingGuardInput, {
|
|
@@ -39757,6 +39969,15 @@ ${list}`);
|
|
|
39757
39969
|
return;
|
|
39758
39970
|
}
|
|
39759
39971
|
if (closingGuardVerdict.message) console.warn(closingGuardVerdict.message);
|
|
39972
|
+
if (prMeta.state !== "MERGED") {
|
|
39973
|
+
const gateRepo = repoForPostCleanup ?? await requireRepo(o.repo);
|
|
39974
|
+
const refusal = await requireReviewVerdict("pr merge", number, gateRepo, { withoutReview: o.withoutReview });
|
|
39975
|
+
if (refusal) {
|
|
39976
|
+
console.error(refusal);
|
|
39977
|
+
process.exitCode = 1;
|
|
39978
|
+
return;
|
|
39979
|
+
}
|
|
39980
|
+
}
|
|
39760
39981
|
if (prMeta.state !== "MERGED" && !o.preserveWorktree) {
|
|
39761
39982
|
if (!repoForPostCleanup) throw new Error("pr merge: repository is unreadable; cannot prove remote branch preservation");
|
|
39762
39983
|
const repoSettings = await fetchRestRepoMergeSettings(repoForPostCleanup);
|
|
@@ -39775,7 +39996,7 @@ ${list}`);
|
|
|
39775
39996
|
const remote = foreignCwd ? `https://github.com/${targetRepo2}.git` : "origin";
|
|
39776
39997
|
let foreignCheckout;
|
|
39777
39998
|
if (foreignCwd) {
|
|
39778
|
-
const sibling = (0,
|
|
39999
|
+
const sibling = (0, import_node_path40.join)((0, import_node_path40.dirname)(beforeWorktrees[0]?.path || startingPath || process.cwd()), targetRepo2.split("/")[1]);
|
|
39779
40000
|
const siblingRepo = repoFromRemoteUrl(await gitOut(["-C", sibling, "remote", "get-url", "origin"]).catch(() => ""));
|
|
39780
40001
|
if (siblingRepo?.toLowerCase() === targetRepo2.toLowerCase()) {
|
|
39781
40002
|
const siblingWorktrees = await execFileP("git", ["-C", sibling, "worktree", "list", "--porcelain"], { timeout: GIT_TIMEOUT_MS }).then((r) => parseGitWorktreePorcelain(r.stdout)).catch(() => void 0);
|
|
@@ -39867,7 +40088,7 @@ ${list}`);
|
|
|
39867
40088
|
}
|
|
39868
40089
|
if (!repoForPostCleanup) throw e;
|
|
39869
40090
|
console.warn(`pr merge: gh GraphQL rate-limited \u2014 merging PR #${number} via REST PUT instead (#4588).`);
|
|
39870
|
-
const commitMessage = bodyFile ? (0,
|
|
40091
|
+
const commitMessage = bodyFile ? (0, import_node_fs43.readFileSync)(bodyFile, "utf8") : void 0;
|
|
39871
40092
|
await defaultGitHubClient().rest("PUT", `repos/${repoForPostCleanup}/pulls/${number}/merge`, {
|
|
39872
40093
|
body: { merge_method: method.slice(2), ...commitMessage ? { commit_message: commitMessage } : {} },
|
|
39873
40094
|
timeoutMs: GH_MUTATION_TIMEOUT_MS
|
|
@@ -39973,7 +40194,7 @@ ${list}`);
|
|
|
39973
40194
|
preserveWorktree: o.preserveWorktree,
|
|
39974
40195
|
gcAcknowledged: o.gc,
|
|
39975
40196
|
expectedHeadOid: headRefOid,
|
|
39976
|
-
pathExists: (p) => (0,
|
|
40197
|
+
pathExists: (p) => (0, import_node_fs43.existsSync)(p),
|
|
39977
40198
|
// #5899: pin cleanup git calls to the main checkout — the task worktree this process may be
|
|
39978
40199
|
// standing in is removed mid-cleanup, so a cwd-relative invocation fails with
|
|
39979
40200
|
// 'fatal: not a git repository' and leaves a spurious partial-cleanup exit.
|
|
@@ -40094,7 +40315,7 @@ ${list}`);
|
|
|
40094
40315
|
}
|
|
40095
40316
|
|
|
40096
40317
|
// src/command-register-developer.ts
|
|
40097
|
-
var
|
|
40318
|
+
var import_node_fs48 = require("node:fs");
|
|
40098
40319
|
|
|
40099
40320
|
// src/whoami.ts
|
|
40100
40321
|
async function resolveWhoami(deps) {
|
|
@@ -40124,7 +40345,7 @@ async function resolveWhoami(deps) {
|
|
|
40124
40345
|
}
|
|
40125
40346
|
|
|
40126
40347
|
// src/command-register-developer.ts
|
|
40127
|
-
var
|
|
40348
|
+
var import_node_path45 = require("node:path");
|
|
40128
40349
|
|
|
40129
40350
|
// src/wave-land.ts
|
|
40130
40351
|
function planWaveLand(prs) {
|
|
@@ -40155,7 +40376,7 @@ async function executeWaveLand(plan, deps) {
|
|
|
40155
40376
|
}
|
|
40156
40377
|
|
|
40157
40378
|
// src/box-commands.ts
|
|
40158
|
-
var
|
|
40379
|
+
var import_node_fs44 = require("node:fs");
|
|
40159
40380
|
|
|
40160
40381
|
// src/box.ts
|
|
40161
40382
|
var BOX_KEYS = {
|
|
@@ -40357,7 +40578,7 @@ function registerBoxCommands(program3) {
|
|
|
40357
40578
|
return;
|
|
40358
40579
|
}
|
|
40359
40580
|
const wroteScript = o.ssh && o.script ? o.script : null;
|
|
40360
|
-
if (wroteScript) (0,
|
|
40581
|
+
if (wroteScript) (0, import_node_fs44.writeFileSync)(wroteScript, sshRecipeScript(found), "utf8");
|
|
40361
40582
|
if (o.json) {
|
|
40362
40583
|
console.log(JSON.stringify({
|
|
40363
40584
|
box: found,
|
|
@@ -40377,21 +40598,21 @@ ${SSH_RECIPE_AGENT_NOTE}`);
|
|
|
40377
40598
|
}
|
|
40378
40599
|
|
|
40379
40600
|
// src/dist-drift.ts
|
|
40380
|
-
var
|
|
40601
|
+
var import_node_child_process17 = require("node:child_process");
|
|
40381
40602
|
var import_node_crypto12 = require("node:crypto");
|
|
40382
|
-
var
|
|
40383
|
-
var
|
|
40384
|
-
var
|
|
40603
|
+
var import_node_fs46 = require("node:fs");
|
|
40604
|
+
var import_node_os21 = require("node:os");
|
|
40605
|
+
var import_node_path42 = require("node:path");
|
|
40385
40606
|
|
|
40386
40607
|
// ../scripts/distribution-digest.mjs
|
|
40387
40608
|
var import_node_crypto11 = require("node:crypto");
|
|
40388
|
-
var
|
|
40389
|
-
var
|
|
40609
|
+
var import_node_fs45 = require("node:fs");
|
|
40610
|
+
var import_node_path41 = require("node:path");
|
|
40390
40611
|
var slash = (value) => value.replaceAll("\\", "/");
|
|
40391
40612
|
function repoPath(root, declaredPath, label) {
|
|
40392
|
-
const absoluteRoot = (0,
|
|
40393
|
-
const target = (0,
|
|
40394
|
-
if (target !== absoluteRoot && !target.startsWith(`${absoluteRoot}${
|
|
40613
|
+
const absoluteRoot = (0, import_node_path41.resolve)(root);
|
|
40614
|
+
const target = (0, import_node_path41.resolve)(root, declaredPath);
|
|
40615
|
+
if (target !== absoluteRoot && !target.startsWith(`${absoluteRoot}${import_node_path41.sep}`)) {
|
|
40395
40616
|
throw new Error(`${label} ${declaredPath} escapes the repository root`);
|
|
40396
40617
|
}
|
|
40397
40618
|
return target;
|
|
@@ -40399,7 +40620,7 @@ function repoPath(root, declaredPath, label) {
|
|
|
40399
40620
|
function digestFiles(files) {
|
|
40400
40621
|
const hash = (0, import_node_crypto11.createHash)("sha256");
|
|
40401
40622
|
for (const file of [...files].sort((a, b) => a.relative.localeCompare(b.relative))) {
|
|
40402
|
-
const content = file.stat.isSymbolicLink() ? Buffer.from((0,
|
|
40623
|
+
const content = file.stat.isSymbolicLink() ? Buffer.from((0, import_node_fs45.readlinkSync)(file.absolute), "utf8") : (0, import_node_fs45.readFileSync)(file.absolute);
|
|
40403
40624
|
hash.update(file.relative, "utf8");
|
|
40404
40625
|
hash.update("\0");
|
|
40405
40626
|
hash.update(file.stat.isSymbolicLink() ? "symlink" : "file", "utf8");
|
|
@@ -40414,8 +40635,8 @@ function digestFiles(files) {
|
|
|
40414
40635
|
function digestPackedFiles(packageRoot, packedFiles) {
|
|
40415
40636
|
return digestFiles(packedFiles.map((path2) => {
|
|
40416
40637
|
const absolute = repoPath(packageRoot, path2, "packed artifact identity path");
|
|
40417
|
-
if (!(0,
|
|
40418
|
-
return { absolute, relative: slash(path2), stat: (0,
|
|
40638
|
+
if (!(0, import_node_fs45.existsSync)(absolute)) throw new Error(`packed artifact identity path ${path2} does not exist`);
|
|
40639
|
+
return { absolute, relative: slash(path2), stat: (0, import_node_fs45.lstatSync)(absolute) };
|
|
40419
40640
|
}));
|
|
40420
40641
|
}
|
|
40421
40642
|
|
|
@@ -40499,13 +40720,13 @@ function renderDistDriftReceipt(receipt) {
|
|
|
40499
40720
|
return lines2;
|
|
40500
40721
|
}
|
|
40501
40722
|
function readOrNull(path2) {
|
|
40502
|
-
return (0,
|
|
40723
|
+
return (0, import_node_fs46.existsSync)(path2) ? (0, import_node_fs46.readFileSync)(path2) : null;
|
|
40503
40724
|
}
|
|
40504
40725
|
function walkFiles(root) {
|
|
40505
40726
|
const files = [];
|
|
40506
40727
|
const walk2 = (directory) => {
|
|
40507
|
-
for (const entry of (0,
|
|
40508
|
-
const child2 = (0,
|
|
40728
|
+
for (const entry of (0, import_node_fs46.readdirSync)(directory, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
|
|
40729
|
+
const child2 = (0, import_node_path42.join)(directory, entry.name);
|
|
40509
40730
|
if (entry.isDirectory()) walk2(child2);
|
|
40510
40731
|
else files.push(child2);
|
|
40511
40732
|
}
|
|
@@ -40515,14 +40736,14 @@ function walkFiles(root) {
|
|
|
40515
40736
|
}
|
|
40516
40737
|
function bomPathFor(root) {
|
|
40517
40738
|
try {
|
|
40518
|
-
const registry2 = JSON.parse((0,
|
|
40519
|
-
return (0,
|
|
40739
|
+
const registry2 = JSON.parse((0, import_node_fs46.readFileSync)((0, import_node_path42.join)(root, "surfaces.json"), "utf8"));
|
|
40740
|
+
return (0, import_node_path42.join)(root, registry2?.sharedAgentCore?.releaseMetadata?.bomPath ?? "distribution-bom.json");
|
|
40520
40741
|
} catch {
|
|
40521
|
-
return (0,
|
|
40742
|
+
return (0, import_node_path42.join)(root, "distribution-bom.json");
|
|
40522
40743
|
}
|
|
40523
40744
|
}
|
|
40524
40745
|
function rebuildTo(packageRoot, outDir) {
|
|
40525
|
-
(0,
|
|
40746
|
+
(0, import_node_child_process17.execFileSync)(process.execPath, ["build.mjs"], {
|
|
40526
40747
|
cwd: packageRoot,
|
|
40527
40748
|
env: { ...process.env, MMI_DIST_OUTDIR: outDir },
|
|
40528
40749
|
windowsHide: true,
|
|
@@ -40531,35 +40752,35 @@ function rebuildTo(packageRoot, outDir) {
|
|
|
40531
40752
|
});
|
|
40532
40753
|
}
|
|
40533
40754
|
function runDistStatus(root) {
|
|
40534
|
-
const stage = (0,
|
|
40755
|
+
const stage = (0, import_node_fs46.mkdtempSync)((0, import_node_path42.join)((0, import_node_os21.tmpdir)(), "mmi-dist-drift-"));
|
|
40535
40756
|
let overlayCount = 0;
|
|
40536
40757
|
try {
|
|
40537
|
-
const cliOut = (0,
|
|
40538
|
-
const hubOut = (0,
|
|
40539
|
-
rebuildTo((0,
|
|
40540
|
-
rebuildTo((0,
|
|
40758
|
+
const cliOut = (0, import_node_path42.join)(stage, "cli-dist");
|
|
40759
|
+
const hubOut = (0, import_node_path42.join)(stage, "hub-dist");
|
|
40760
|
+
rebuildTo((0, import_node_path42.join)(root, "cli"), cliOut);
|
|
40761
|
+
rebuildTo((0, import_node_path42.join)(root, "updater"), hubOut);
|
|
40541
40762
|
const outDirFor = (packageDir) => packageDir === "cli" ? cliOut : hubOut;
|
|
40542
40763
|
const rebuilt = (path2) => {
|
|
40543
40764
|
const spec = DIST_ARTIFACTS.find((entry) => entry.path === path2);
|
|
40544
|
-
return spec ? readOrNull((0,
|
|
40765
|
+
return spec ? readOrNull((0, import_node_path42.join)(outDirFor(spec.packageDir), spec.output)) : null;
|
|
40545
40766
|
};
|
|
40546
|
-
const committed = (path2) => readOrNull((0,
|
|
40547
|
-
const tree = (path2) => readOrNull((0,
|
|
40548
|
-
const distRoot = (0,
|
|
40549
|
-
const distTree = () => walkFiles(distRoot).map((absolute) => `cli/dist/${(0,
|
|
40550
|
-
const bom = JSON.parse((0,
|
|
40767
|
+
const committed = (path2) => readOrNull((0, import_node_path42.join)(root, path2));
|
|
40768
|
+
const tree = (path2) => readOrNull((0, import_node_path42.join)(root, path2));
|
|
40769
|
+
const distRoot = (0, import_node_path42.join)(root, "cli", "dist");
|
|
40770
|
+
const distTree = () => walkFiles(distRoot).map((absolute) => `cli/dist/${(0, import_node_path42.relative)(distRoot, absolute).replaceAll("\\", "/")}`);
|
|
40771
|
+
const bom = JSON.parse((0, import_node_fs46.readFileSync)(bomPathFor(root), "utf8"));
|
|
40551
40772
|
const digest = (entries) => {
|
|
40552
|
-
const overlay = (0,
|
|
40773
|
+
const overlay = (0, import_node_path42.join)(stage, `overlay-${overlayCount++}`);
|
|
40553
40774
|
for (const entry of entries) {
|
|
40554
|
-
const target = (0,
|
|
40555
|
-
(0,
|
|
40556
|
-
(0,
|
|
40775
|
+
const target = (0, import_node_path42.join)(overlay, entry.path);
|
|
40776
|
+
(0, import_node_fs46.mkdirSync)((0, import_node_path42.dirname)(target), { recursive: true });
|
|
40777
|
+
(0, import_node_fs46.writeFileSync)(target, entry.bytes);
|
|
40557
40778
|
}
|
|
40558
40779
|
return digestPackedFiles(overlay, entries.map((entry) => entry.path));
|
|
40559
40780
|
};
|
|
40560
40781
|
return computeDistDriftReceipt({ committed, tree, rebuilt, distTree, bom, digest });
|
|
40561
40782
|
} finally {
|
|
40562
|
-
(0,
|
|
40783
|
+
(0, import_node_fs46.rmSync)(stage, { recursive: true, force: true });
|
|
40563
40784
|
}
|
|
40564
40785
|
}
|
|
40565
40786
|
|
|
@@ -40631,7 +40852,7 @@ function registerEdgeCommands(program3) {
|
|
|
40631
40852
|
|
|
40632
40853
|
// src/schedules-lift-command.ts
|
|
40633
40854
|
var import_promises8 = require("node:fs/promises");
|
|
40634
|
-
var
|
|
40855
|
+
var import_node_path43 = require("node:path");
|
|
40635
40856
|
var DEFAULT_WORKFLOWS_DIR = ".github/workflows";
|
|
40636
40857
|
var SCHEDULE_REPO_RE = /^[A-Za-z0-9_.-]+$/;
|
|
40637
40858
|
var SchedulesLiftUsageError = class extends Error {
|
|
@@ -40658,7 +40879,7 @@ async function readWorkflowFiles(dir) {
|
|
|
40658
40879
|
const files = [];
|
|
40659
40880
|
for (const name of names.sort()) {
|
|
40660
40881
|
if (!/\.ya?ml$/.test(name)) continue;
|
|
40661
|
-
files.push({ path: `.github/workflows/${name}`, text: await (0, import_promises8.readFile)((0,
|
|
40882
|
+
files.push({ path: `.github/workflows/${name}`, text: await (0, import_promises8.readFile)((0, import_node_path43.join)(dir, name), "utf8") });
|
|
40662
40883
|
}
|
|
40663
40884
|
return files;
|
|
40664
40885
|
}
|
|
@@ -40740,9 +40961,9 @@ function registerSchedulesLiftCommand(program3, deps = {}) {
|
|
|
40740
40961
|
}
|
|
40741
40962
|
|
|
40742
40963
|
// src/spawn-policy-core.ts
|
|
40743
|
-
var
|
|
40744
|
-
var
|
|
40745
|
-
var
|
|
40964
|
+
var import_node_child_process18 = require("node:child_process");
|
|
40965
|
+
var import_node_fs47 = require("node:fs");
|
|
40966
|
+
var import_node_path44 = require("node:path");
|
|
40746
40967
|
var SPAWNERS = ["spawn", "spawnSync", "exec", "execSync", "execFile", "execFileSync"];
|
|
40747
40968
|
var CALL_SOURCE = String.raw`(^|[^.\w$])(${SPAWNERS.join("|")})\s*\(`;
|
|
40748
40969
|
var SOURCE_EXT = /\.(ts|mts|cts|js|mjs|cjs)$/;
|
|
@@ -40811,7 +41032,7 @@ function findViolationsInSource(raw) {
|
|
|
40811
41032
|
return found;
|
|
40812
41033
|
}
|
|
40813
41034
|
function policedFiles(root) {
|
|
40814
|
-
const r = (0,
|
|
41035
|
+
const r = (0, import_node_child_process18.spawnSync)("git", ["ls-files", "-z", "--cached", "--others", "--exclude-standard"], {
|
|
40815
41036
|
cwd: root,
|
|
40816
41037
|
encoding: "utf8",
|
|
40817
41038
|
windowsHide: true,
|
|
@@ -40828,7 +41049,7 @@ function runSpawnPolicy(root) {
|
|
|
40828
41049
|
for (const file of files) {
|
|
40829
41050
|
let raw;
|
|
40830
41051
|
try {
|
|
40831
|
-
raw = (0,
|
|
41052
|
+
raw = (0, import_node_fs47.readFileSync)((0, import_node_path44.join)(root, file), "utf8");
|
|
40832
41053
|
} catch {
|
|
40833
41054
|
continue;
|
|
40834
41055
|
}
|
|
@@ -40848,19 +41069,19 @@ function runSpawnPolicy(root) {
|
|
|
40848
41069
|
function registerDeveloperCommands(program3) {
|
|
40849
41070
|
const rules = program3.command("rules").description("org-managed .gitignore delivery");
|
|
40850
41071
|
rules.command("gitignore").option("--write", "upsert the managed block into .gitignore (default: check only, non-zero exit on drift)").option("--json", "machine-readable output").description("verify (or --write) this repo's org-managed .gitignore block matches the SSOT").action((opts) => {
|
|
40851
|
-
const path2 = (0,
|
|
40852
|
-
const current = (0,
|
|
41072
|
+
const path2 = (0, import_node_path45.join)(process.cwd(), ".gitignore");
|
|
41073
|
+
const current = (0, import_node_fs48.existsSync)(path2) ? (0, import_node_fs48.readFileSync)(path2, "utf8") : null;
|
|
40853
41074
|
const plan = planManagedGitignore(current);
|
|
40854
41075
|
const drift = [...plan.added.map((l) => `+${l}`), ...plan.removed.map((l) => `-${l}`)].join(", ") || "block normalize";
|
|
40855
41076
|
if (opts.json) {
|
|
40856
|
-
if (opts.write && plan.changed) (0,
|
|
41077
|
+
if (opts.write && plan.changed) (0, import_node_fs48.writeFileSync)(path2, plan.content, "utf8");
|
|
40857
41078
|
console.log(JSON.stringify(plan, null, 2));
|
|
40858
41079
|
if (!opts.write && plan.changed) process.exitCode = 1;
|
|
40859
41080
|
return;
|
|
40860
41081
|
}
|
|
40861
41082
|
if (opts.write) {
|
|
40862
41083
|
if (plan.changed) {
|
|
40863
|
-
(0,
|
|
41084
|
+
(0, import_node_fs48.writeFileSync)(path2, plan.content, "utf8");
|
|
40864
41085
|
console.log(`mmi-cli devops org rules gitignore: updated .gitignore (${drift})`);
|
|
40865
41086
|
} else {
|
|
40866
41087
|
console.log("mmi-cli devops org rules gitignore: up to date");
|
|
@@ -42348,12 +42569,12 @@ async function findInFlightHotfixVersion(deps, ctx, latestMainTag, workflows = H
|
|
|
42348
42569
|
}
|
|
42349
42570
|
|
|
42350
42571
|
// src/hotfix-coverage.ts
|
|
42351
|
-
var
|
|
42572
|
+
var import_node_child_process19 = require("node:child_process");
|
|
42352
42573
|
var CHERRY_TRAILER = /\(cherry picked from commit ([0-9a-f]{7,40})\)/g;
|
|
42353
42574
|
function checkHotfixCoverage(options = {}) {
|
|
42354
42575
|
const { cwd = process.cwd(), mainRef = "origin/main", rcRef = "origin/rc", manifestPaths = [] } = options;
|
|
42355
42576
|
const ack = (options.ack ?? []).filter(Boolean);
|
|
42356
|
-
const git3 = options.git ?? ((args, opts) => (0,
|
|
42577
|
+
const git3 = options.git ?? ((args, opts) => (0, import_node_child_process19.execFileSync)("git", args, { cwd, encoding: "utf8", input: opts?.input, stdio: ["pipe", "pipe", "pipe"] }));
|
|
42357
42578
|
const revList = (range) => {
|
|
42358
42579
|
const out = git3(["rev-list", "--no-merges", range]).trim();
|
|
42359
42580
|
return out ? out.split("\n") : [];
|
|
@@ -42421,7 +42642,7 @@ function checkHotfixCoverage(options = {}) {
|
|
|
42421
42642
|
}
|
|
42422
42643
|
function checkHotfixCarries(options) {
|
|
42423
42644
|
const { cwd = process.cwd(), branch, baseRef, targets } = options;
|
|
42424
|
-
const git3 = options.git ?? ((args, opts) => (0,
|
|
42645
|
+
const git3 = options.git ?? ((args, opts) => (0, import_node_child_process19.execFileSync)("git", args, { cwd, encoding: "utf8", input: opts?.input, stdio: ["pipe", "pipe", "pipe"] }));
|
|
42425
42646
|
const isAncestor = (sha, ref) => {
|
|
42426
42647
|
try {
|
|
42427
42648
|
git3(["merge-base", "--is-ancestor", sha, ref]);
|
|
@@ -42453,8 +42674,8 @@ function checkHotfixCarries(options) {
|
|
|
42453
42674
|
}
|
|
42454
42675
|
|
|
42455
42676
|
// src/train-commands.ts
|
|
42456
|
-
var
|
|
42457
|
-
var
|
|
42677
|
+
var import_node_fs49 = require("node:fs");
|
|
42678
|
+
var import_node_path46 = require("node:path");
|
|
42458
42679
|
var INVOKED_ARGV = process.argv.slice(2);
|
|
42459
42680
|
var RELEASE_BUMP_INTENTS = ["major", "minor", "patch"];
|
|
42460
42681
|
function resolveReleaseBumpIntent(raw) {
|
|
@@ -42466,7 +42687,7 @@ function resolveReleaseBumpIntent(raw) {
|
|
|
42466
42687
|
}
|
|
42467
42688
|
function readRepoVersion() {
|
|
42468
42689
|
try {
|
|
42469
|
-
return JSON.parse((0,
|
|
42690
|
+
return JSON.parse((0, import_node_fs49.readFileSync)((0, import_node_path46.join)(process.cwd(), ".claude-plugin", "plugin.json"), "utf8")).version || void 0;
|
|
42470
42691
|
} catch {
|
|
42471
42692
|
return void 0;
|
|
42472
42693
|
}
|
|
@@ -43210,12 +43431,12 @@ ${r.stderr ?? ""}`).catch(() => "");
|
|
|
43210
43431
|
var ENV_HEAL_LOCK_STALE_MS = 10 * 6e4;
|
|
43211
43432
|
var ENV_HEAL_LOCK_MAX_WAIT_MS = 2 * 6e4;
|
|
43212
43433
|
function envHealLockPath(home) {
|
|
43213
|
-
return (0,
|
|
43434
|
+
return (0, import_node_path47.join)(home, ".claude", "plugins", ".mmi-env-heal.lock");
|
|
43214
43435
|
}
|
|
43215
43436
|
async function withEnvHealLock(what, run) {
|
|
43216
43437
|
try {
|
|
43217
43438
|
return await withFileLock(
|
|
43218
|
-
envHealLockPath((0,
|
|
43439
|
+
envHealLockPath((0, import_node_os22.homedir)()),
|
|
43219
43440
|
{ staleMs: ENV_HEAL_LOCK_STALE_MS, maxWaitMs: ENV_HEAL_LOCK_MAX_WAIT_MS, label: "mmi env-heal lock" },
|
|
43220
43441
|
run
|
|
43221
43442
|
);
|
|
@@ -43311,7 +43532,7 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
43311
43532
|
const configRoot = surfaceConfigRoot(surface);
|
|
43312
43533
|
const running = surface === "codex" ? installedActivePluginVersion(surface) : runningPluginVersion(process.env, resolveClientVersion());
|
|
43313
43534
|
const plan = buildPluginCachePlan(
|
|
43314
|
-
(0,
|
|
43535
|
+
(0, import_node_os22.homedir)(),
|
|
43315
43536
|
running,
|
|
43316
43537
|
pluginCacheFsDeps(configRoot, () => 0),
|
|
43317
43538
|
{ configRoot, includeStaging: surface !== "codex" }
|
|
@@ -43339,14 +43560,14 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
43339
43560
|
const running = surface === "codex" ? installedActivePluginVersion(surface) : runningPluginVersion(process.env, resolveClientVersion());
|
|
43340
43561
|
const installed = installedActivePluginVersion(surface);
|
|
43341
43562
|
const plan = buildPluginCachePlan(
|
|
43342
|
-
(0,
|
|
43563
|
+
(0, import_node_os22.homedir)(),
|
|
43343
43564
|
running,
|
|
43344
43565
|
pluginCacheFsDeps(configRoot, () => 0),
|
|
43345
43566
|
{ configRoot, includeStaging: surface !== "codex", installedVersion: installed }
|
|
43346
43567
|
);
|
|
43347
43568
|
const result = applyPluginCachePlan(
|
|
43348
43569
|
plan,
|
|
43349
|
-
(p) => (0,
|
|
43570
|
+
(p) => (0, import_node_fs50.rmSync)(p, { recursive: true }),
|
|
43350
43571
|
stagingApplyFsGuard(configRoot)
|
|
43351
43572
|
);
|
|
43352
43573
|
return {
|
|
@@ -43381,7 +43602,7 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
43381
43602
|
// has no generated routing index would
|
|
43382
43603
|
// get a permanent — demanding an artifact it never asked for.
|
|
43383
43604
|
docsIndexState: (root) => {
|
|
43384
|
-
if (!(0,
|
|
43605
|
+
if (!(0, import_node_fs50.existsSync)((0, import_node_path47.join)(root, DOCS_INDEX_PATH))) return void 0;
|
|
43385
43606
|
const real = createDocsIndexDeps(root);
|
|
43386
43607
|
let docs;
|
|
43387
43608
|
const listDocs = () => docs ??= real.listDocs();
|
|
@@ -43390,7 +43611,7 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
43390
43611
|
},
|
|
43391
43612
|
// #4168: working-tree heal — write if drifted, then re-check. Commit remains the operator's step.
|
|
43392
43613
|
healDocsIndex: (root) => {
|
|
43393
|
-
if (!(0,
|
|
43614
|
+
if (!(0, import_node_fs50.existsSync)((0, import_node_path47.join)(root, DOCS_INDEX_PATH))) return { drift: false, docCount: 0 };
|
|
43394
43615
|
const real = createDocsIndexDeps(root);
|
|
43395
43616
|
let docs;
|
|
43396
43617
|
const listDocs = () => docs ??= real.listDocs();
|
|
@@ -43949,7 +44170,7 @@ project.command("set [owner/repo]").description("upsert project META (idempotent
|
|
|
43949
44170
|
if (dupe) return fail(`org project set: KEY "${dupe}" was passed to both --var and --set; --set is an alias of --var, so pass each KEY once`);
|
|
43950
44171
|
if (o.secretsFile) {
|
|
43951
44172
|
try {
|
|
43952
|
-
vars.push(`secrets=${(0,
|
|
44173
|
+
vars.push(`secrets=${(0, import_node_fs50.readFileSync)(o.secretsFile, "utf8")}`);
|
|
43953
44174
|
} catch (e) {
|
|
43954
44175
|
return fail(`org project set: cannot read --secrets-file ${o.secretsFile}: ${e.message}`);
|
|
43955
44176
|
}
|
|
@@ -44262,16 +44483,16 @@ function ciAuditDeps2() {
|
|
|
44262
44483
|
// gate re-seed step is skipped gracefully rather than failing mid-run.
|
|
44263
44484
|
readSeedFile: (path2) => {
|
|
44264
44485
|
if (!root) return null;
|
|
44265
|
-
const fullPath = (0,
|
|
44266
|
-
return (0,
|
|
44486
|
+
const fullPath = (0, import_node_path47.join)(root, path2);
|
|
44487
|
+
return (0, import_node_fs50.existsSync)(fullPath) ? (0, import_node_fs50.readFileSync)(fullPath, "utf8") : null;
|
|
44267
44488
|
}
|
|
44268
44489
|
};
|
|
44269
44490
|
}
|
|
44270
44491
|
function hubRoot2() {
|
|
44271
|
-
const fromPkg = (0,
|
|
44492
|
+
const fromPkg = (0, import_node_path47.join)(__dirname, "..", "..");
|
|
44272
44493
|
const marker = "skills/bootstrap/seeds/manifest.json";
|
|
44273
|
-
if ((0,
|
|
44274
|
-
if ((0,
|
|
44494
|
+
if ((0, import_node_fs50.existsSync)((0, import_node_path47.join)(fromPkg, marker))) return fromPkg;
|
|
44495
|
+
if ((0, import_node_fs50.existsSync)((0, import_node_path47.join)(process.cwd(), marker))) return process.cwd();
|
|
44275
44496
|
return null;
|
|
44276
44497
|
}
|
|
44277
44498
|
registerQueryCommands(program2);
|
|
@@ -44371,10 +44592,10 @@ access.command("audit").description("audit collaborator roles + train-branch pus
|
|
|
44371
44592
|
targets = resolution.targets;
|
|
44372
44593
|
}
|
|
44373
44594
|
const derivedMatrix = registryProjects ? accessMatrixFromProjects(registryProjects) : {};
|
|
44374
|
-
const fileMatrix = (0,
|
|
44595
|
+
const fileMatrix = (0, import_node_fs50.existsSync)("access-matrix.json") ? loadAccessMatrix((0, import_node_fs50.readFileSync)("access-matrix.json", "utf8")) : {};
|
|
44375
44596
|
const matrix = mergeAccessMatrix(fileMatrix, derivedMatrix);
|
|
44376
44597
|
const dataAccess = registryProjects ? dataAccessContractsFromProjects(registryProjects) : { consumers: {} };
|
|
44377
|
-
const sanctioned = (0,
|
|
44598
|
+
const sanctioned = (0, import_node_fs50.existsSync)("access-matrix.json") ? loadSanctionedAdmins((0, import_node_fs50.readFileSync)("access-matrix.json", "utf8")) : {};
|
|
44378
44599
|
const report = await auditOrgAccess(targets, deps, matrix, dataAccess, sanctioned);
|
|
44379
44600
|
console.log(o.json ? JSON.stringify(report, null, 2) : renderAccessReport(report));
|
|
44380
44601
|
if (!report.ok) process.exitCode = 1;
|
|
@@ -44405,16 +44626,16 @@ function directoryBytes(path2) {
|
|
|
44405
44626
|
let total = 0;
|
|
44406
44627
|
let entries;
|
|
44407
44628
|
try {
|
|
44408
|
-
entries = (0,
|
|
44629
|
+
entries = (0, import_node_fs50.readdirSync)(path2, { withFileTypes: true });
|
|
44409
44630
|
} catch {
|
|
44410
44631
|
return 0;
|
|
44411
44632
|
}
|
|
44412
44633
|
for (const entry of entries) {
|
|
44413
|
-
const child2 = (0,
|
|
44634
|
+
const child2 = (0, import_node_path47.join)(path2, entry.name);
|
|
44414
44635
|
if (entry.isDirectory()) total += directoryBytes(child2);
|
|
44415
44636
|
else {
|
|
44416
44637
|
try {
|
|
44417
|
-
total += (0,
|
|
44638
|
+
total += (0, import_node_fs50.statSync)(child2).size;
|
|
44418
44639
|
} catch {
|
|
44419
44640
|
}
|
|
44420
44641
|
}
|
|
@@ -44422,25 +44643,25 @@ function directoryBytes(path2) {
|
|
|
44422
44643
|
return total;
|
|
44423
44644
|
}
|
|
44424
44645
|
function listDirEntries(dir) {
|
|
44425
|
-
return (0,
|
|
44646
|
+
return (0, import_node_fs50.readdirSync)(dir, { withFileTypes: true }).map((d) => ({ name: d.name, isDirectory: d.isDirectory() }));
|
|
44426
44647
|
}
|
|
44427
44648
|
function readInstalledPluginRefs(configRoot) {
|
|
44428
44649
|
const p = installedPluginsPathForConfig(configRoot);
|
|
44429
|
-
if (!(0,
|
|
44650
|
+
if (!(0, import_node_fs50.existsSync)(p)) return [];
|
|
44430
44651
|
try {
|
|
44431
|
-
return installedPluginPaths((0,
|
|
44652
|
+
return installedPluginPaths((0, import_node_fs50.readFileSync)(p, "utf8"));
|
|
44432
44653
|
} catch {
|
|
44433
44654
|
return null;
|
|
44434
44655
|
}
|
|
44435
44656
|
}
|
|
44436
44657
|
function pluginCacheFsDeps(configRoot, dirBytes) {
|
|
44437
44658
|
return {
|
|
44438
|
-
exists: (p) => (0,
|
|
44439
|
-
listVersionDirs: (root) => (0,
|
|
44659
|
+
exists: (p) => (0, import_node_fs50.existsSync)(p),
|
|
44660
|
+
listVersionDirs: (root) => (0, import_node_fs50.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name),
|
|
44440
44661
|
dirBytes,
|
|
44441
|
-
listStagingDirs: (root) => (0,
|
|
44662
|
+
listStagingDirs: (root) => (0, import_node_fs50.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => {
|
|
44442
44663
|
try {
|
|
44443
|
-
return { name: d.name, mtimeMs: newestMtimeMs((0,
|
|
44664
|
+
return { name: d.name, mtimeMs: newestMtimeMs((0, import_node_path47.join)(root, d.name), listDirEntries, (p) => (0, import_node_fs50.statSync)(p).mtimeMs) };
|
|
44444
44665
|
} catch {
|
|
44445
44666
|
return { name: d.name, mtimeMs: Date.now() };
|
|
44446
44667
|
}
|
|
@@ -44454,10 +44675,10 @@ function stagingApplyFsGuard(configRoot) {
|
|
|
44454
44675
|
return {
|
|
44455
44676
|
referencedPaths: () => readInstalledPluginRefs(configRoot),
|
|
44456
44677
|
mtimeMs: (name) => {
|
|
44457
|
-
const p = (0,
|
|
44458
|
-
if (!(0,
|
|
44678
|
+
const p = (0, import_node_path47.join)(stagingRoot, name);
|
|
44679
|
+
if (!(0, import_node_fs50.existsSync)(p)) return null;
|
|
44459
44680
|
try {
|
|
44460
|
-
return newestMtimeMs(p, listDirEntries, (q) => (0,
|
|
44681
|
+
return newestMtimeMs(p, listDirEntries, (q) => (0, import_node_fs50.statSync)(q).mtimeMs);
|
|
44461
44682
|
} catch {
|
|
44462
44683
|
return null;
|
|
44463
44684
|
}
|
|
@@ -44477,13 +44698,13 @@ program2.command("plugin-prune").description(`prune stale cached MMI plugin vers
|
|
|
44477
44698
|
return;
|
|
44478
44699
|
}
|
|
44479
44700
|
const plan = buildPluginCachePlan(
|
|
44480
|
-
(0,
|
|
44701
|
+
(0, import_node_os22.homedir)(),
|
|
44481
44702
|
running,
|
|
44482
44703
|
pluginCacheFsDeps(configRoot, directoryBytes),
|
|
44483
44704
|
{ withBytes: true, configRoot, includeStaging: surface !== "codex" }
|
|
44484
44705
|
);
|
|
44485
44706
|
const anythingToDelete = plan.prune.length > 0 || plan.staging.length > 0;
|
|
44486
|
-
const result = o.apply && anythingToDelete ? applyPluginCachePlan(plan, (p) => (0,
|
|
44707
|
+
const result = o.apply && anythingToDelete ? applyPluginCachePlan(plan, (p) => (0, import_node_fs50.rmSync)(p, { recursive: true, force: true }), stagingApplyFsGuard(configRoot)) : void 0;
|
|
44487
44708
|
const warnings = plan.prune.length > 0 ? [CONCURRENT_SESSION_WARNING] : [];
|
|
44488
44709
|
if (o.json) console.log(JSON.stringify({ ...plan, warnings, applied: result ?? null }));
|
|
44489
44710
|
else console.log(renderPluginCachePlan(plan, result));
|
package/package.json
CHANGED