@mutmutco/cli 4.4.8 → 4.4.10
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 +685 -393
- package/package.json +1 -1
package/dist/main.cjs
CHANGED
|
@@ -4534,7 +4534,7 @@ function useColor() {
|
|
|
4534
4534
|
var program = new Command();
|
|
4535
4535
|
|
|
4536
4536
|
// src/command-composition.ts
|
|
4537
|
-
var
|
|
4537
|
+
var import_node_fs49 = require("node:fs");
|
|
4538
4538
|
init_clean_exit();
|
|
4539
4539
|
init_cli_shared();
|
|
4540
4540
|
|
|
@@ -5437,7 +5437,7 @@ function resolveVerbAliasShim(argv) {
|
|
|
5437
5437
|
|
|
5438
5438
|
// src/command-composition.ts
|
|
5439
5439
|
var import_node_os21 = require("node:os");
|
|
5440
|
-
var
|
|
5440
|
+
var import_node_path47 = require("node:path");
|
|
5441
5441
|
|
|
5442
5442
|
// src/board-read.ts
|
|
5443
5443
|
var import_node_fs13 = require("node:fs");
|
|
@@ -15938,10 +15938,10 @@ var rollout_plan_default = {
|
|
|
15938
15938
|
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)."
|
|
15939
15939
|
},
|
|
15940
15940
|
baseline: {
|
|
15941
|
-
version: "4.4.
|
|
15942
|
-
tag: "v4.4.
|
|
15943
|
-
commit: "
|
|
15944
|
-
npm: "@mutmutco/cli@4.4.
|
|
15941
|
+
version: "4.4.10",
|
|
15942
|
+
tag: "v4.4.10",
|
|
15943
|
+
commit: "187ab08827c9",
|
|
15944
|
+
npm: "@mutmutco/cli@4.4.10"
|
|
15945
15945
|
},
|
|
15946
15946
|
exitCriterion: "fleet-n-of-n",
|
|
15947
15947
|
hubOnlyShortcut: "forbidden",
|
|
@@ -15958,14 +15958,14 @@ var rollout_plan_default = {
|
|
|
15958
15958
|
repo: "mutmutco/mmi-hub",
|
|
15959
15959
|
role: "canary",
|
|
15960
15960
|
schedule: "train",
|
|
15961
|
-
v3Target: "v4.4.
|
|
15961
|
+
v3Target: "v4.4.10"
|
|
15962
15962
|
}
|
|
15963
15963
|
],
|
|
15964
15964
|
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.",
|
|
15965
15965
|
rollback: {
|
|
15966
15966
|
independent: true,
|
|
15967
|
-
mechanism: "npm dist-tag latest -> 4.4.
|
|
15968
|
-
v3Target: "v4.4.
|
|
15967
|
+
mechanism: "npm dist-tag latest -> 4.4.10 and redeploy the Hub Lambda from tag v4.4.10 (187ab08827c9); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
|
|
15968
|
+
v3Target: "v4.4.10 (@mutmutco/cli@4.4.10, tag commit 187ab08827c9 \u2014 last known-good release carrying the repo-index v4-only contract)"
|
|
15969
15969
|
}
|
|
15970
15970
|
},
|
|
15971
15971
|
{
|
|
@@ -18259,6 +18259,9 @@ function correlateTenantRun(deps, since, titleIncludes) {
|
|
|
18259
18259
|
function correlatePublishRun(deps, since, titleIncludes) {
|
|
18260
18260
|
return correlateRun(deps, { workflow: "tenant-publish.yml", since, mode: "dispatch", titleIncludes });
|
|
18261
18261
|
}
|
|
18262
|
+
function correlateGetPublishRun(deps, since, product) {
|
|
18263
|
+
return correlateRun(deps, { workflow: "get-publish.yml", since, mode: "dispatch", titleIncludes: [product] });
|
|
18264
|
+
}
|
|
18262
18265
|
function correlateControlRun(deps, since, titleIncludes) {
|
|
18263
18266
|
return correlateRun(deps, { workflow: "tenant-control.yml", since, mode: "dispatch", titleIncludes });
|
|
18264
18267
|
}
|
|
@@ -18801,6 +18804,10 @@ function isReleaseShaDeployEnumerationCandidate(row, nonDeployEvents) {
|
|
|
18801
18804
|
return true;
|
|
18802
18805
|
}
|
|
18803
18806
|
|
|
18807
|
+
// src/train-apply-deploy.ts
|
|
18808
|
+
var import_node_fs19 = require("node:fs");
|
|
18809
|
+
var import_node_path17 = require("node:path");
|
|
18810
|
+
|
|
18804
18811
|
// src/vercel-deployments.ts
|
|
18805
18812
|
var TERMINAL = /* @__PURE__ */ new Set(["success", "failure", "error", "inactive"]);
|
|
18806
18813
|
function isTerminalVercelState(state) {
|
|
@@ -19009,6 +19016,189 @@ function appendPublishDispatch(deploy, publish) {
|
|
|
19009
19016
|
deployStatus: deploy.deployStatus === "failure" || publish.deployStatus === "failure" ? "failure" : deploy.deployStatus === "pending" || publish.deployStatus === "pending" ? "pending" : "success"
|
|
19010
19017
|
};
|
|
19011
19018
|
}
|
|
19019
|
+
var HUB_SERVED_PRODUCT = "mmi";
|
|
19020
|
+
function getPublishDispatchCommand(repo, product = HUB_SERVED_PRODUCT) {
|
|
19021
|
+
return `gh workflow run get-publish.yml --repo ${repo} --ref main -f product=${product}`;
|
|
19022
|
+
}
|
|
19023
|
+
var HUB_GET_SLUG = "mmi-get";
|
|
19024
|
+
var HUB_GET_STAGE = "main";
|
|
19025
|
+
function mmiGetRedeployCommand(repo) {
|
|
19026
|
+
return `gh workflow run tenant-deploy.yml --repo ${repo} --ref main -f slug=${HUB_GET_SLUG} -f repo=${repo} -f ref=${HUB_GET_STAGE} -f stage=${HUB_GET_STAGE}`;
|
|
19027
|
+
}
|
|
19028
|
+
function readLocalLauncherVersion(root = process.cwd()) {
|
|
19029
|
+
try {
|
|
19030
|
+
const raw = (0, import_node_fs19.readFileSync)((0, import_node_path17.join)(root, "installer", "launcher", "package.json"), "utf8");
|
|
19031
|
+
const version = JSON.parse(raw).version;
|
|
19032
|
+
return typeof version === "string" && version.trim() ? version.trim() : null;
|
|
19033
|
+
} catch {
|
|
19034
|
+
return null;
|
|
19035
|
+
}
|
|
19036
|
+
}
|
|
19037
|
+
function readServedChannelUrl(product = HUB_SERVED_PRODUCT, root = process.cwd()) {
|
|
19038
|
+
try {
|
|
19039
|
+
const raw = (0, import_node_fs19.readFileSync)((0, import_node_path17.join)(root, "config", `product.${product}.json`), "utf8");
|
|
19040
|
+
const host = JSON.parse(raw).host;
|
|
19041
|
+
if (typeof host !== "string" || !host.trim()) return null;
|
|
19042
|
+
return `${host.trim().replace(/\/+$/, "")}/release/version`;
|
|
19043
|
+
} catch {
|
|
19044
|
+
return null;
|
|
19045
|
+
}
|
|
19046
|
+
}
|
|
19047
|
+
async function fetchServedChannelVersion(url, fetchImpl = fetch) {
|
|
19048
|
+
try {
|
|
19049
|
+
const res = await fetchImpl(url, { method: "GET", redirect: "follow", signal: AbortSignal.timeout(15e3) });
|
|
19050
|
+
if (res.status !== 200) return { ok: false, status: res.status };
|
|
19051
|
+
const body = (await res.text()).slice(0, 4096);
|
|
19052
|
+
const version = JSON.parse(body).version;
|
|
19053
|
+
if (typeof version !== "string" || !version.trim()) return { ok: false, status: res.status, error: "pointer carried no version" };
|
|
19054
|
+
return { ok: true, version: version.trim(), status: res.status };
|
|
19055
|
+
} catch (e) {
|
|
19056
|
+
return { ok: false, error: e instanceof Error ? e.message : String(e) };
|
|
19057
|
+
}
|
|
19058
|
+
}
|
|
19059
|
+
async function appendMmiGetRedeploy(deps, input, dispatch) {
|
|
19060
|
+
if (!isHubControlRepo(input.repo)) return dispatch;
|
|
19061
|
+
const remedy = mmiGetRedeployCommand(input.repo);
|
|
19062
|
+
const withNote = (note, deployStatus) => ({
|
|
19063
|
+
...dispatch,
|
|
19064
|
+
note: `${dispatch.note}; ${note}`,
|
|
19065
|
+
...deployStatus ? { deployStatus } : {}
|
|
19066
|
+
});
|
|
19067
|
+
if (input.publishStatus !== "success") {
|
|
19068
|
+
return withNote(`mmi-get box NOT redeployed (publish did not succeed) \u2014 after the publish is green, run \`${remedy}\``);
|
|
19069
|
+
}
|
|
19070
|
+
const since = (deps.now ?? Date.now)();
|
|
19071
|
+
try {
|
|
19072
|
+
await deps.run("gh", [
|
|
19073
|
+
"workflow",
|
|
19074
|
+
"run",
|
|
19075
|
+
"tenant-deploy.yml",
|
|
19076
|
+
"--repo",
|
|
19077
|
+
input.repo,
|
|
19078
|
+
"--ref",
|
|
19079
|
+
"main",
|
|
19080
|
+
"-f",
|
|
19081
|
+
`slug=${HUB_GET_SLUG}`,
|
|
19082
|
+
"-f",
|
|
19083
|
+
`repo=${input.repo}`,
|
|
19084
|
+
"-f",
|
|
19085
|
+
`ref=${HUB_GET_STAGE}`,
|
|
19086
|
+
"-f",
|
|
19087
|
+
`stage=${HUB_GET_STAGE}`
|
|
19088
|
+
]);
|
|
19089
|
+
} catch (e) {
|
|
19090
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
19091
|
+
return withNote(`tenant-deploy dispatch FAILED: ${msg}. The release itself landed, but the MMI-GET BOX WAS NOT REDEPLOYED \u2014 recover with \`${remedy}\``, "failure");
|
|
19092
|
+
}
|
|
19093
|
+
const correlated = await correlateTenantRun(deps, since, [HUB_GET_SLUG, HUB_GET_STAGE]);
|
|
19094
|
+
if (correlated.read === "failed" || correlated.read === "absent") {
|
|
19095
|
+
const why = correlated.read === "failed" ? `its run could not be READ: ${correlated.error}` : "no matching run appeared";
|
|
19096
|
+
return withNote(`tenant-deploy dispatched (slug=${HUB_GET_SLUG}, stage=${HUB_GET_STAGE}) but ${why}. Check the Actions tab; if it never ran, recover with \`${remedy}\``, "failure");
|
|
19097
|
+
}
|
|
19098
|
+
const { runId, runUrl } = correlated;
|
|
19099
|
+
const runRow = { workflow: "tenant-deploy.yml", ...runId ? { runId } : {}, ...runUrl ? { runUrl } : {} };
|
|
19100
|
+
if (!input.watch) {
|
|
19101
|
+
return {
|
|
19102
|
+
...dispatch,
|
|
19103
|
+
note: `${dispatch.note}; dispatched tenant-deploy.yml (slug=${HUB_GET_SLUG}, ref=${HUB_GET_STAGE}, stage=${HUB_GET_STAGE}) \u2014 NOT watched, so the mmi-get box is not yet proven redeployed`,
|
|
19104
|
+
workflowRuns: [...dispatch.workflowRuns ?? [], { ...runRow, conclusion: "pending" }]
|
|
19105
|
+
};
|
|
19106
|
+
}
|
|
19107
|
+
const runStatus = await watchTenantRun(deps, runId, input.repo);
|
|
19108
|
+
if (runStatus !== "success") {
|
|
19109
|
+
return {
|
|
19110
|
+
...dispatch,
|
|
19111
|
+
note: `${dispatch.note}; tenant-deploy.yml ${runStatus} \u2014 the MMI-GET BOX WAS NOT REDEPLOYED; recover with \`${remedy}\``,
|
|
19112
|
+
workflowRuns: [...dispatch.workflowRuns ?? [], { ...runRow, conclusion: runStatus }],
|
|
19113
|
+
deployStatus: "failure"
|
|
19114
|
+
};
|
|
19115
|
+
}
|
|
19116
|
+
return {
|
|
19117
|
+
...dispatch,
|
|
19118
|
+
note: `${dispatch.note}; mmi-get box redeployed (tenant-deploy.yml slug=${HUB_GET_SLUG} stage=${HUB_GET_STAGE})`,
|
|
19119
|
+
workflowRuns: [...dispatch.workflowRuns ?? [], { ...runRow, conclusion: "success" }]
|
|
19120
|
+
};
|
|
19121
|
+
}
|
|
19122
|
+
async function appendServedChannelPublish(deps, input, dispatch) {
|
|
19123
|
+
if (!isHubControlRepo(input.repo)) return dispatch;
|
|
19124
|
+
const channelUrl = input.channelUrl ?? readServedChannelUrl();
|
|
19125
|
+
const remedy = getPublishDispatchCommand(input.repo);
|
|
19126
|
+
const withNote = (note, deployStatus) => ({
|
|
19127
|
+
...dispatch,
|
|
19128
|
+
note: `${dispatch.note}; ${note}`,
|
|
19129
|
+
...deployStatus ? { deployStatus } : {}
|
|
19130
|
+
});
|
|
19131
|
+
if (input.publishStatus !== "success") {
|
|
19132
|
+
return withNote(`served channel NOT moved (publish did not succeed) \u2014 after the publish is green, run \`${remedy}\``);
|
|
19133
|
+
}
|
|
19134
|
+
const since = (deps.now ?? Date.now)();
|
|
19135
|
+
try {
|
|
19136
|
+
await deps.run("gh", ["workflow", "run", "get-publish.yml", "--repo", input.repo, "--ref", "main", "-f", `product=${HUB_SERVED_PRODUCT}`]);
|
|
19137
|
+
} catch (e) {
|
|
19138
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
19139
|
+
return withNote(`get-publish dispatch FAILED: ${msg}. The release itself landed, but the SERVED CHANNEL IS UNCHANGED \u2014 recover with \`${remedy}\``, "failure");
|
|
19140
|
+
}
|
|
19141
|
+
const correlated = await correlateGetPublishRun(deps, since, HUB_SERVED_PRODUCT);
|
|
19142
|
+
if (correlated.read === "failed") {
|
|
19143
|
+
return withNote(`get-publish dispatched but its run could not be READ: ${correlated.error}. Check the Actions tab; if it never ran, recover with \`${remedy}\``, "failure");
|
|
19144
|
+
}
|
|
19145
|
+
const { runId, runUrl } = correlated;
|
|
19146
|
+
const runRow = { workflow: "get-publish.yml", ...runId ? { runId } : {}, ...runUrl ? { runUrl } : {} };
|
|
19147
|
+
if (!input.watch) {
|
|
19148
|
+
return {
|
|
19149
|
+
...dispatch,
|
|
19150
|
+
note: `${dispatch.note}; dispatched get-publish.yml (product=${HUB_SERVED_PRODUCT}) \u2014 NOT watched, so the served channel is not yet proven moved`,
|
|
19151
|
+
workflowRuns: [...dispatch.workflowRuns ?? [], { ...runRow, conclusion: "pending" }]
|
|
19152
|
+
};
|
|
19153
|
+
}
|
|
19154
|
+
const runStatus = await watchTenantRun(deps, runId, input.repo);
|
|
19155
|
+
if (runStatus !== "success") {
|
|
19156
|
+
return {
|
|
19157
|
+
...dispatch,
|
|
19158
|
+
note: `${dispatch.note}; get-publish.yml ${runStatus} \u2014 the SERVED CHANNEL IS UNCHANGED; recover with \`${remedy}\``,
|
|
19159
|
+
workflowRuns: [...dispatch.workflowRuns ?? [], { ...runRow, conclusion: runStatus }],
|
|
19160
|
+
deployStatus: "failure"
|
|
19161
|
+
};
|
|
19162
|
+
}
|
|
19163
|
+
const expected = (deps.readLauncherVersion ?? readLocalLauncherVersion)();
|
|
19164
|
+
const runs = [...dispatch.workflowRuns ?? [], { ...runRow, conclusion: "success" }];
|
|
19165
|
+
if (!channelUrl) {
|
|
19166
|
+
return {
|
|
19167
|
+
...dispatch,
|
|
19168
|
+
note: `${dispatch.note}; get-publish.yml succeeded but the channel URL could not be read from the product config \u2014 the move is unverified`,
|
|
19169
|
+
workflowRuns: runs
|
|
19170
|
+
};
|
|
19171
|
+
}
|
|
19172
|
+
const probe = await (deps.readServedChannelVersion ?? fetchServedChannelVersion)(channelUrl);
|
|
19173
|
+
if (!probe.ok) {
|
|
19174
|
+
const why = probe.error ?? `HTTP ${probe.status ?? "unknown"}`;
|
|
19175
|
+
return {
|
|
19176
|
+
...dispatch,
|
|
19177
|
+
note: `${dispatch.note}; get-publish.yml succeeded but the served channel version could NOT be read at ${channelUrl} (${why}) \u2014 the move is unverified`,
|
|
19178
|
+
workflowRuns: runs
|
|
19179
|
+
};
|
|
19180
|
+
}
|
|
19181
|
+
if (expected && probe.version !== expected) {
|
|
19182
|
+
return {
|
|
19183
|
+
...dispatch,
|
|
19184
|
+
note: `${dispatch.note}; get-publish.yml succeeded but the served channel still reports ${probe.version} (expected launcher ${expected}) \u2014 THE CHANNEL DID NOT MOVE; recover with \`${remedy}\``,
|
|
19185
|
+
workflowRuns: runs,
|
|
19186
|
+
deployStatus: "failure"
|
|
19187
|
+
};
|
|
19188
|
+
}
|
|
19189
|
+
if (!expected) {
|
|
19190
|
+
return {
|
|
19191
|
+
...dispatch,
|
|
19192
|
+
note: `${dispatch.note}; get-publish.yml succeeded and ${channelUrl} reports ${probe.version}, but the local launcher version could not be read \u2014 nothing was compared, so the move is unverified`,
|
|
19193
|
+
workflowRuns: runs
|
|
19194
|
+
};
|
|
19195
|
+
}
|
|
19196
|
+
return {
|
|
19197
|
+
...dispatch,
|
|
19198
|
+
note: `${dispatch.note}; served channel moved \u2014 ${channelUrl} now reports ${probe.version}`,
|
|
19199
|
+
workflowRuns: runs
|
|
19200
|
+
};
|
|
19201
|
+
}
|
|
19012
19202
|
var JERV_GATEWAY_RUN_URL_NOTE = "no run URL emitted \u2014 host health leg runs outside GitHub Actions";
|
|
19013
19203
|
async function appendJervGatewayReleaseDeploy(deps, repo, tag, tagSha, dispatch) {
|
|
19014
19204
|
if (!isJervHubRepo(repo)) return dispatch;
|
|
@@ -19523,9 +19713,9 @@ function renderTenantControl(r) {
|
|
|
19523
19713
|
}
|
|
19524
19714
|
|
|
19525
19715
|
// src/train-apply-phases.ts
|
|
19526
|
-
var
|
|
19716
|
+
var import_node_fs24 = require("node:fs");
|
|
19527
19717
|
var import_promises3 = require("node:fs/promises");
|
|
19528
|
-
var
|
|
19718
|
+
var import_node_path24 = require("node:path");
|
|
19529
19719
|
|
|
19530
19720
|
// src/actions-billing-preflight.ts
|
|
19531
19721
|
var CANARY_WORKFLOW = "actions-job-start-canary.yml";
|
|
@@ -19778,14 +19968,14 @@ Resume it: ${resumeCommand}
|
|
|
19778
19968
|
|
|
19779
19969
|
// src/train-doctor.ts
|
|
19780
19970
|
var import_node_child_process9 = require("node:child_process");
|
|
19781
|
-
var
|
|
19971
|
+
var import_node_fs23 = require("node:fs");
|
|
19782
19972
|
var import_node_os13 = require("node:os");
|
|
19783
|
-
var
|
|
19973
|
+
var import_node_path23 = require("node:path");
|
|
19784
19974
|
|
|
19785
19975
|
// src/doctor-io.ts
|
|
19786
|
-
var
|
|
19976
|
+
var import_node_fs20 = require("node:fs");
|
|
19787
19977
|
var import_node_os10 = require("node:os");
|
|
19788
|
-
var
|
|
19978
|
+
var import_node_path18 = require("node:path");
|
|
19789
19979
|
var import_node_child_process7 = require("node:child_process");
|
|
19790
19980
|
var import_node_util4 = require("node:util");
|
|
19791
19981
|
|
|
@@ -19798,8 +19988,8 @@ function nodeDiscardSinkPath(platform2 = process.platform) {
|
|
|
19798
19988
|
var execFileP2 = (0, import_node_util4.promisify)(import_node_child_process7.execFile);
|
|
19799
19989
|
function execFileCapture(file, args, opts = {}) {
|
|
19800
19990
|
const sink = nodeDiscardSinkPath();
|
|
19801
|
-
const inFd = (0,
|
|
19802
|
-
const errFd = (0,
|
|
19991
|
+
const inFd = (0, import_node_fs20.openSync)(sink, "r");
|
|
19992
|
+
const errFd = (0, import_node_fs20.openSync)(sink, "w");
|
|
19803
19993
|
try {
|
|
19804
19994
|
return (0, import_node_child_process7.execFileSync)(file, args, {
|
|
19805
19995
|
...opts,
|
|
@@ -19807,17 +19997,17 @@ function execFileCapture(file, args, opts = {}) {
|
|
|
19807
19997
|
stdio: [inFd, "pipe", errFd]
|
|
19808
19998
|
});
|
|
19809
19999
|
} finally {
|
|
19810
|
-
(0,
|
|
19811
|
-
(0,
|
|
20000
|
+
(0, import_node_fs20.closeSync)(inFd);
|
|
20001
|
+
(0, import_node_fs20.closeSync)(errFd);
|
|
19812
20002
|
}
|
|
19813
20003
|
}
|
|
19814
20004
|
var MMI_PLUGIN_ID2 = "mmi@mutmutco";
|
|
19815
20005
|
function stagedClaudePluginVersion() {
|
|
19816
20006
|
try {
|
|
19817
|
-
const stagingRoot = (0,
|
|
19818
|
-
const record = JSON.parse((0,
|
|
20007
|
+
const stagingRoot = (0, import_node_path18.join)((0, import_node_os10.homedir)(), ".claude", "plugins", "staging");
|
|
20008
|
+
const record = JSON.parse((0, import_node_fs20.readFileSync)((0, import_node_path18.join)(stagingRoot, "launch-target.json"), "utf8"));
|
|
19819
20009
|
if (typeof record.target !== "string" || typeof record.incoming !== "string") return void 0;
|
|
19820
|
-
const manifest = JSON.parse((0,
|
|
20010
|
+
const manifest = JSON.parse((0, import_node_fs20.readFileSync)((0, import_node_path18.join)(record.incoming, ".claude-plugin", "plugin.json"), "utf8"));
|
|
19821
20011
|
if (typeof manifest.version !== "string") return void 0;
|
|
19822
20012
|
return manifest.version === record.target ? record.target : void 0;
|
|
19823
20013
|
} catch {
|
|
@@ -19827,7 +20017,7 @@ function stagedClaudePluginVersion() {
|
|
|
19827
20017
|
function installedClaudePluginVersion() {
|
|
19828
20018
|
try {
|
|
19829
20019
|
const file = JSON.parse(
|
|
19830
|
-
(0,
|
|
20020
|
+
(0, import_node_fs20.readFileSync)((0, import_node_path18.join)((0, import_node_os10.homedir)(), ".claude", "plugins", "installed_plugins.json"), "utf8")
|
|
19831
20021
|
);
|
|
19832
20022
|
const versions = (file.plugins?.[MMI_PLUGIN_ID2] ?? []).map((r) => r.version).filter((v) => Boolean(v));
|
|
19833
20023
|
if (versions.length === 0) return void 0;
|
|
@@ -19838,7 +20028,7 @@ function installedClaudePluginVersion() {
|
|
|
19838
20028
|
}
|
|
19839
20029
|
function manifestVersion(path2) {
|
|
19840
20030
|
try {
|
|
19841
|
-
const manifest = JSON.parse((0,
|
|
20031
|
+
const manifest = JSON.parse((0, import_node_fs20.readFileSync)(path2, "utf8"));
|
|
19842
20032
|
return typeof manifest.version === "string" && manifest.version.trim() ? manifest.version.trim() : void 0;
|
|
19843
20033
|
} catch {
|
|
19844
20034
|
return void 0;
|
|
@@ -19847,12 +20037,12 @@ function manifestVersion(path2) {
|
|
|
19847
20037
|
function readHermesPluginEvidence(env = process.env) {
|
|
19848
20038
|
const host = hermesConfigRoot(env);
|
|
19849
20039
|
const root = hermesPluginRoot(env);
|
|
19850
|
-
const installRecordPresent = (0,
|
|
19851
|
-
const manifestPath = (0,
|
|
20040
|
+
const installRecordPresent = (0, import_node_fs20.existsSync)(root);
|
|
20041
|
+
const manifestPath = (0, import_node_path18.join)(root, "plugin.yaml");
|
|
19852
20042
|
let installedVersion;
|
|
19853
20043
|
let manifest = "missing";
|
|
19854
20044
|
try {
|
|
19855
|
-
const text = (0,
|
|
20045
|
+
const text = (0, import_node_fs20.readFileSync)(manifestPath, "utf8");
|
|
19856
20046
|
let version;
|
|
19857
20047
|
try {
|
|
19858
20048
|
const parsed = JSON.parse(text).version;
|
|
@@ -19866,25 +20056,25 @@ function readHermesPluginEvidence(env = process.env) {
|
|
|
19866
20056
|
if (version) {
|
|
19867
20057
|
installedVersion = version;
|
|
19868
20058
|
manifest = "valid";
|
|
19869
|
-
} else if ((0,
|
|
20059
|
+
} else if ((0, import_node_fs20.existsSync)(manifestPath)) manifest = "invalid";
|
|
19870
20060
|
} catch {
|
|
19871
|
-
if ((0,
|
|
20061
|
+
if ((0, import_node_fs20.existsSync)(manifestPath)) manifest = "invalid";
|
|
19872
20062
|
}
|
|
19873
20063
|
let skills = false;
|
|
19874
20064
|
try {
|
|
19875
|
-
skills = (0,
|
|
20065
|
+
skills = (0, import_node_fs20.existsSync)((0, import_node_path18.join)(root, "skills")) && (0, import_node_fs20.statSync)((0, import_node_path18.join)(root, "skills")).isDirectory();
|
|
19876
20066
|
} catch {
|
|
19877
20067
|
}
|
|
19878
20068
|
let provisioned = false;
|
|
19879
|
-
const provisionedRoot = (0,
|
|
20069
|
+
const provisionedRoot = (0, import_node_path18.join)(host, "skills", "mmi");
|
|
19880
20070
|
try {
|
|
19881
|
-
provisioned = (0,
|
|
20071
|
+
provisioned = (0, import_node_fs20.existsSync)(provisionedRoot) && (0, import_node_fs20.statSync)(provisionedRoot).isDirectory();
|
|
19882
20072
|
} catch {
|
|
19883
20073
|
}
|
|
19884
|
-
const treeOk = (0,
|
|
20074
|
+
const treeOk = (0, import_node_fs20.existsSync)((0, import_node_path18.join)(root, "__init__.py")) && skills && manifest === "valid";
|
|
19885
20075
|
const receipt = treeOk && !provisioned ? `hermes-skills-unprovisioned:${provisionedRoot}` : void 0;
|
|
19886
20076
|
return {
|
|
19887
|
-
hostPresent: (0,
|
|
20077
|
+
hostPresent: (0, import_node_fs20.existsSync)(host),
|
|
19888
20078
|
installRecordPresent,
|
|
19889
20079
|
manifest,
|
|
19890
20080
|
payloadPresent: treeOk && provisioned,
|
|
@@ -19896,7 +20086,7 @@ function installedSurfacePluginVersion(surface) {
|
|
|
19896
20086
|
const token = surfaceToken(surface);
|
|
19897
20087
|
if (token === "hermes") return readHermesPluginEvidence().installedVersion;
|
|
19898
20088
|
if (token === "cursor") {
|
|
19899
|
-
return manifestVersion((0,
|
|
20089
|
+
return manifestVersion((0, import_node_path18.join)(cursorLocalPluginRoot(), ".cursor-plugin", "plugin.json"));
|
|
19900
20090
|
}
|
|
19901
20091
|
if (token === "jervcode") {
|
|
19902
20092
|
return installedJervCodePackageVersion();
|
|
@@ -19933,13 +20123,13 @@ function worktreeRootSync() {
|
|
|
19933
20123
|
}
|
|
19934
20124
|
var gitignorePath = () => {
|
|
19935
20125
|
const root = worktreeRootSync();
|
|
19936
|
-
return root === null ? null : (0,
|
|
20126
|
+
return root === null ? null : (0, import_node_path18.join)(root, ".gitignore");
|
|
19937
20127
|
};
|
|
19938
20128
|
function readGitignore() {
|
|
19939
20129
|
const path2 = gitignorePath();
|
|
19940
20130
|
if (path2 === null) return null;
|
|
19941
20131
|
try {
|
|
19942
|
-
return (0,
|
|
20132
|
+
return (0, import_node_fs20.readFileSync)(path2, "utf8");
|
|
19943
20133
|
} catch {
|
|
19944
20134
|
return null;
|
|
19945
20135
|
}
|
|
@@ -19948,14 +20138,14 @@ function writeGitignore(content) {
|
|
|
19948
20138
|
const path2 = gitignorePath();
|
|
19949
20139
|
if (path2 === null) return false;
|
|
19950
20140
|
try {
|
|
19951
|
-
(0,
|
|
20141
|
+
(0, import_node_fs20.writeFileSync)(path2, content, "utf8");
|
|
19952
20142
|
return true;
|
|
19953
20143
|
} catch {
|
|
19954
20144
|
return false;
|
|
19955
20145
|
}
|
|
19956
20146
|
}
|
|
19957
20147
|
function lineEndingState(root) {
|
|
19958
|
-
const attributesPresent = (0,
|
|
20148
|
+
const attributesPresent = (0, import_node_fs20.existsSync)((0, import_node_path18.join)(root, ".gitattributes"));
|
|
19959
20149
|
try {
|
|
19960
20150
|
const output = execFileCapture("git", ["-C", root, "ls-files", "--eol", "--", ":(glob)**/*.sh"], {
|
|
19961
20151
|
windowsHide: true
|
|
@@ -19998,18 +20188,18 @@ function compatHolds(range, version) {
|
|
|
19998
20188
|
}
|
|
19999
20189
|
|
|
20000
20190
|
// src/claude-binary-doctor.ts
|
|
20001
|
-
var
|
|
20191
|
+
var import_node_fs21 = require("node:fs");
|
|
20002
20192
|
var import_node_os12 = require("node:os");
|
|
20003
|
-
var
|
|
20193
|
+
var import_node_path20 = require("node:path");
|
|
20004
20194
|
|
|
20005
20195
|
// src/jerv-cli-spawn.ts
|
|
20006
20196
|
var import_node_os11 = require("node:os");
|
|
20007
|
-
var
|
|
20197
|
+
var import_node_path19 = require("node:path");
|
|
20008
20198
|
init_cli_shared();
|
|
20009
|
-
var JERV_CLI_ENTRY = (0,
|
|
20199
|
+
var JERV_CLI_ENTRY = (0, import_node_path19.join)("node_modules", "@jervaise", "jerv-cli", "dist", "index.cjs");
|
|
20010
20200
|
function pathEnvEntries(pathEnv, platform2 = process.platform) {
|
|
20011
20201
|
if (platform2 !== "win32") {
|
|
20012
|
-
return pathEnv.split(
|
|
20202
|
+
return pathEnv.split(import_node_path19.delimiter).map((e) => e.trim()).filter(Boolean);
|
|
20013
20203
|
}
|
|
20014
20204
|
if (pathEnv.includes(";")) {
|
|
20015
20205
|
return pathEnv.split(";").map((e) => e.trim()).filter(Boolean);
|
|
@@ -20042,10 +20232,10 @@ function jervCliCandidateDirs(env = process.env, home = (0, import_node_os11.hom
|
|
|
20042
20232
|
push(normalizeSpawnPathEntry(entry, platform2));
|
|
20043
20233
|
}
|
|
20044
20234
|
if (platform2 === "win32") {
|
|
20045
|
-
if (env.APPDATA) push((0,
|
|
20046
|
-
if (env.LOCALAPPDATA) push((0,
|
|
20235
|
+
if (env.APPDATA) push((0, import_node_path19.join)(env.APPDATA, "npm"));
|
|
20236
|
+
if (env.LOCALAPPDATA) push((0, import_node_path19.join)(env.LOCALAPPDATA, "npm"));
|
|
20047
20237
|
} else {
|
|
20048
|
-
push((0,
|
|
20238
|
+
push((0, import_node_path19.join)(home, ".local", "bin"));
|
|
20049
20239
|
}
|
|
20050
20240
|
return out;
|
|
20051
20241
|
}
|
|
@@ -20098,26 +20288,26 @@ function globalNodeModulesRoots(host) {
|
|
|
20098
20288
|
out.push(dir);
|
|
20099
20289
|
};
|
|
20100
20290
|
const prefix = env.npm_config_prefix?.trim();
|
|
20101
|
-
if (prefix) push(platform2 === "win32" ? (0,
|
|
20291
|
+
if (prefix) push(platform2 === "win32" ? (0, import_node_path20.join)(prefix, "node_modules") : (0, import_node_path20.join)(prefix, "lib", "node_modules"));
|
|
20102
20292
|
for (const dir of jervCliCandidateDirs(env, host.home ?? (0, import_node_os12.homedir)(), platform2)) {
|
|
20103
|
-
push((0,
|
|
20104
|
-
push((0,
|
|
20293
|
+
push((0, import_node_path20.join)(dir, "node_modules"));
|
|
20294
|
+
push((0, import_node_path20.join)((0, import_node_path20.dirname)(dir), "lib", "node_modules"));
|
|
20105
20295
|
}
|
|
20106
20296
|
return out;
|
|
20107
20297
|
}
|
|
20108
20298
|
function readHead(path2) {
|
|
20109
20299
|
let fd;
|
|
20110
20300
|
try {
|
|
20111
|
-
fd = (0,
|
|
20301
|
+
fd = (0, import_node_fs21.openSync)(path2, "r");
|
|
20112
20302
|
const buffer = new Uint8Array(MAGIC_HEAD_BYTES);
|
|
20113
|
-
const read = (0,
|
|
20303
|
+
const read = (0, import_node_fs21.readSync)(fd, buffer, 0, MAGIC_HEAD_BYTES, 0);
|
|
20114
20304
|
return buffer.subarray(0, read);
|
|
20115
20305
|
} catch {
|
|
20116
20306
|
return void 0;
|
|
20117
20307
|
} finally {
|
|
20118
20308
|
if (fd !== void 0) {
|
|
20119
20309
|
try {
|
|
20120
|
-
(0,
|
|
20310
|
+
(0, import_node_fs21.closeSync)(fd);
|
|
20121
20311
|
} catch {
|
|
20122
20312
|
}
|
|
20123
20313
|
}
|
|
@@ -20125,7 +20315,7 @@ function readHead(path2) {
|
|
|
20125
20315
|
}
|
|
20126
20316
|
function fileBytes(path2) {
|
|
20127
20317
|
try {
|
|
20128
|
-
return (0,
|
|
20318
|
+
return (0, import_node_fs21.statSync)(path2).size;
|
|
20129
20319
|
} catch {
|
|
20130
20320
|
return void 0;
|
|
20131
20321
|
}
|
|
@@ -20139,17 +20329,17 @@ function readClaudeBinaryState(host = {}) {
|
|
|
20139
20329
|
const arch = host.arch ?? process.arch;
|
|
20140
20330
|
const magic = EXECUTABLE_MAGIC[platform2];
|
|
20141
20331
|
if (!magic) return void 0;
|
|
20142
|
-
const packageRoot = globalNodeModulesRoots(host).map((root) => (0,
|
|
20332
|
+
const packageRoot = globalNodeModulesRoots(host).map((root) => (0, import_node_path20.join)(root, ...PACKAGE.split("/"))).find((dir) => (0, import_node_fs21.existsSync)((0, import_node_path20.join)(dir, "package.json")));
|
|
20143
20333
|
if (!packageRoot) return void 0;
|
|
20144
20334
|
const keys = platformPackageKeys(platform2, arch);
|
|
20145
20335
|
const fallbackPackage = `${PACKAGE}-${keys[0]}`;
|
|
20146
20336
|
let manifest;
|
|
20147
20337
|
try {
|
|
20148
|
-
manifest = JSON.parse((0,
|
|
20338
|
+
manifest = JSON.parse((0, import_node_fs21.readFileSync)((0, import_node_path20.join)(packageRoot, "package.json"), "utf8"));
|
|
20149
20339
|
} catch (e) {
|
|
20150
20340
|
return {
|
|
20151
20341
|
state: "unreadable",
|
|
20152
|
-
binPath: (0,
|
|
20342
|
+
binPath: (0, import_node_path20.join)(packageRoot, "package.json"),
|
|
20153
20343
|
expectedMagic: magic.name,
|
|
20154
20344
|
platformPackage: fallbackPackage,
|
|
20155
20345
|
error: `package.json could not be read \u2014 ${e.message}`
|
|
@@ -20166,17 +20356,17 @@ function readClaudeBinaryState(host = {}) {
|
|
|
20166
20356
|
error: "package.json declares no `bin` entry \u2014 the executed file cannot be resolved"
|
|
20167
20357
|
};
|
|
20168
20358
|
}
|
|
20169
|
-
const binPath = (0,
|
|
20170
|
-
const binName = (0,
|
|
20359
|
+
const binPath = (0, import_node_path20.join)(packageRoot, binRelative);
|
|
20360
|
+
const binName = (0, import_node_path20.basename)(binRelative);
|
|
20171
20361
|
const optional = manifest.optionalDependencies;
|
|
20172
20362
|
const publishes = (name) => typeof optional === "object" && optional !== null && Object.prototype.hasOwnProperty.call(optional, name);
|
|
20173
20363
|
const published = keys.map((key) => `${PACKAGE}-${key}`).filter(publishes);
|
|
20174
20364
|
if (published.length === 0) return void 0;
|
|
20175
20365
|
const binIn = (name) => [
|
|
20176
|
-
(0,
|
|
20177
|
-
(0,
|
|
20366
|
+
(0, import_node_path20.join)(packageRoot, "node_modules", ...name.split("/"), binName),
|
|
20367
|
+
(0, import_node_path20.join)((0, import_node_path20.dirname)((0, import_node_path20.dirname)(packageRoot)), ...name.split("/"), binName)
|
|
20178
20368
|
];
|
|
20179
|
-
const found = published.map((name) => ({ name, path: binIn(name).find((file) => (0,
|
|
20369
|
+
const found = published.map((name) => ({ name, path: binIn(name).find((file) => (0, import_node_fs21.existsSync)(file)) })).find((c) => c.path);
|
|
20180
20370
|
const platformPackage = found?.name ?? published[0];
|
|
20181
20371
|
let source;
|
|
20182
20372
|
let sourceProblem;
|
|
@@ -20187,7 +20377,7 @@ function readClaudeBinaryState(host = {}) {
|
|
|
20187
20377
|
} else {
|
|
20188
20378
|
source = { path: found.path, bytes: fileBytes(found.path) ?? 0 };
|
|
20189
20379
|
}
|
|
20190
|
-
if (!(0,
|
|
20380
|
+
if (!(0, import_node_fs21.existsSync)(binPath)) {
|
|
20191
20381
|
return { state: "missing", binPath, expectedMagic: magic.name, platformPackage, ...source ? { source } : {}, ...sourceProblem ? { sourceProblem } : {} };
|
|
20192
20382
|
}
|
|
20193
20383
|
const head = readHead(binPath);
|
|
@@ -20230,9 +20420,9 @@ function healClaudeBinary(host = {}, onStep) {
|
|
|
20230
20420
|
const platform2 = host.platform ?? process.platform;
|
|
20231
20421
|
const aside = `${probe.binPath}.stub-${Date.now()}`;
|
|
20232
20422
|
let renamed = false;
|
|
20233
|
-
if ((0,
|
|
20423
|
+
if ((0, import_node_fs21.existsSync)(probe.binPath)) {
|
|
20234
20424
|
try {
|
|
20235
|
-
(0,
|
|
20425
|
+
(0, import_node_fs21.renameSync)(probe.binPath, aside);
|
|
20236
20426
|
renamed = true;
|
|
20237
20427
|
onStep?.(`renamed the stub aside: ${aside}`);
|
|
20238
20428
|
} catch (e) {
|
|
@@ -20241,12 +20431,12 @@ function healClaudeBinary(host = {}, onStep) {
|
|
|
20241
20431
|
}
|
|
20242
20432
|
try {
|
|
20243
20433
|
onStep?.(`copying ${probe.source.path} \u2192 ${probe.binPath} (${(probe.source.bytes / 1e6).toFixed(0)} MB)`);
|
|
20244
|
-
(0,
|
|
20245
|
-
if (platform2 !== "win32") (0,
|
|
20434
|
+
(0, import_node_fs21.copyFileSync)(probe.source.path, probe.binPath);
|
|
20435
|
+
if (platform2 !== "win32") (0, import_node_fs21.chmodSync)(probe.binPath, 493);
|
|
20246
20436
|
} catch (e) {
|
|
20247
20437
|
if (renamed) {
|
|
20248
20438
|
try {
|
|
20249
|
-
(0,
|
|
20439
|
+
(0, import_node_fs21.renameSync)(aside, probe.binPath);
|
|
20250
20440
|
} catch {
|
|
20251
20441
|
return { ok: false, detail: `copy failed (${e.message}) and the stub could not be restored \u2014 the original is at ${aside}` };
|
|
20252
20442
|
}
|
|
@@ -20260,7 +20450,7 @@ function healClaudeBinary(host = {}, onStep) {
|
|
|
20260
20450
|
let kept = false;
|
|
20261
20451
|
if (renamed) {
|
|
20262
20452
|
try {
|
|
20263
|
-
(0,
|
|
20453
|
+
(0, import_node_fs21.rmSync)(aside);
|
|
20264
20454
|
} catch {
|
|
20265
20455
|
kept = true;
|
|
20266
20456
|
}
|
|
@@ -20619,13 +20809,13 @@ function checkLineEndings(probe) {
|
|
|
20619
20809
|
}
|
|
20620
20810
|
|
|
20621
20811
|
// src/release-ledger.ts
|
|
20622
|
-
var
|
|
20623
|
-
var
|
|
20812
|
+
var import_node_fs22 = require("node:fs");
|
|
20813
|
+
var import_node_path22 = require("node:path");
|
|
20624
20814
|
var import_node_crypto5 = require("node:crypto");
|
|
20625
20815
|
|
|
20626
20816
|
// src/file-lock.ts
|
|
20627
20817
|
var import_promises2 = require("node:fs/promises");
|
|
20628
|
-
var
|
|
20818
|
+
var import_node_path21 = require("node:path");
|
|
20629
20819
|
var sleep = (ms) => new Promise((resolve7) => setTimeout(resolve7, ms));
|
|
20630
20820
|
var IMMEDIATE_RETRY_BUDGET = 3;
|
|
20631
20821
|
var FileLockBusyError = class extends Error {
|
|
@@ -20710,7 +20900,7 @@ async function releaseFileLock(lockPath, guard) {
|
|
|
20710
20900
|
}
|
|
20711
20901
|
async function withFileLock(lockPath, opts, fn) {
|
|
20712
20902
|
const resolved = resolveFileLockOpts(opts);
|
|
20713
|
-
await (0, import_promises2.mkdir)((0,
|
|
20903
|
+
await (0, import_promises2.mkdir)((0, import_node_path21.dirname)(lockPath), { recursive: true }).catch(() => void 0);
|
|
20714
20904
|
const guard = await acquireFileLock(lockPath, resolved, Date.now() + resolved.maxWaitMs);
|
|
20715
20905
|
try {
|
|
20716
20906
|
return await fn();
|
|
@@ -20879,37 +21069,37 @@ function resolvePrimaryGitDir(cwd) {
|
|
|
20879
21069
|
}
|
|
20880
21070
|
let common;
|
|
20881
21071
|
try {
|
|
20882
|
-
common = (0,
|
|
21072
|
+
common = (0, import_node_fs22.readFileSync)((0, import_node_path22.join)(gitDir, "commondir"), "utf8").trim();
|
|
20883
21073
|
} catch (e) {
|
|
20884
21074
|
if (e.code !== "ENOENT") {
|
|
20885
21075
|
throw new ReleaseLedgerError("unreadable", `release ledger: the worktree gitdir's commondir pointer could not be READ (${e instanceof Error ? e.message : String(e)}) \u2014 a failed read is unverified, not primary (#5987/#4713)`);
|
|
20886
21076
|
}
|
|
20887
21077
|
}
|
|
20888
21078
|
if (!common) return gitDir;
|
|
20889
|
-
const commonDir = (0,
|
|
21079
|
+
const commonDir = (0, import_node_path22.isAbsolute)(common) ? common : (0, import_node_path22.resolve)(gitDir, common);
|
|
20890
21080
|
try {
|
|
20891
|
-
(0,
|
|
21081
|
+
(0, import_node_fs22.readFileSync)((0, import_node_path22.join)(commonDir, "HEAD"), "utf8");
|
|
20892
21082
|
} catch (e) {
|
|
20893
21083
|
throw new ReleaseLedgerError("no-checkout", `release ledger: the worktree's commondir pointer names ${commonDir}, which has no readable HEAD (${e instanceof Error ? e.message : String(e)}) \u2014 the primary checkout may have been removed; refusing to write the ledger into a doomed location`);
|
|
20894
21084
|
}
|
|
20895
21085
|
return commonDir;
|
|
20896
21086
|
}
|
|
20897
21087
|
function releaseLedgerPath(cwd) {
|
|
20898
|
-
return (0,
|
|
21088
|
+
return (0, import_node_path22.join)(resolvePrimaryGitDir(cwd), "mmi-runtime", "release", "phases.json");
|
|
20899
21089
|
}
|
|
20900
21090
|
function atomicWriteJson(path2, ledger) {
|
|
20901
|
-
(0,
|
|
21091
|
+
(0, import_node_fs22.mkdirSync)((0, import_node_path22.dirname)(path2), { recursive: true });
|
|
20902
21092
|
const tmp = `${path2}.tmp-${process.pid}-${(0, import_node_crypto5.randomBytes)(4).toString("hex")}`;
|
|
20903
|
-
(0,
|
|
21093
|
+
(0, import_node_fs22.writeFileSync)(tmp, `${JSON.stringify(ledger, null, 2)}
|
|
20904
21094
|
`, "utf8");
|
|
20905
|
-
(0,
|
|
21095
|
+
(0, import_node_fs22.renameSync)(tmp, path2);
|
|
20906
21096
|
}
|
|
20907
21097
|
async function withReleaseLedger(path2, expected, fn, opts = {}) {
|
|
20908
21098
|
return withFileLock(`${path2}.lock`, { label: "release ledger", maxWaitMs: opts.maxWaitMs ?? 5e3 }, async () => {
|
|
20909
21099
|
let current;
|
|
20910
21100
|
let raw;
|
|
20911
21101
|
try {
|
|
20912
|
-
raw = (0,
|
|
21102
|
+
raw = (0, import_node_fs22.readFileSync)(path2, "utf8");
|
|
20913
21103
|
} catch (e) {
|
|
20914
21104
|
if (e.code !== "ENOENT") {
|
|
20915
21105
|
throw new ReleaseLedgerError("unreadable", `release ledger at ${path2} could not be READ (${e instanceof Error ? e.message : String(e)}) \u2014 a failed read is unverified, not absent (#5987)`);
|
|
@@ -21543,7 +21733,7 @@ async function clearLedgerFile(path2, anchors, maxWaitMs) {
|
|
|
21543
21733
|
return withFileLock(`${path2}.lock`, { label: "release ledger", maxWaitMs }, async () => {
|
|
21544
21734
|
let raw;
|
|
21545
21735
|
try {
|
|
21546
|
-
raw = (0,
|
|
21736
|
+
raw = (0, import_node_fs22.readFileSync)(path2, "utf8");
|
|
21547
21737
|
} catch (e) {
|
|
21548
21738
|
if (e.code === "ENOENT") return { cleared: false };
|
|
21549
21739
|
return { cleared: false, note: `release ledger at ${path2} could not be read for clearing (${e instanceof Error ? e.message : String(e)}) \u2014 left in place` };
|
|
@@ -21559,7 +21749,7 @@ async function clearLedgerFile(path2, anchors, maxWaitMs) {
|
|
|
21559
21749
|
} catch (e) {
|
|
21560
21750
|
return { cleared: false, note: `release ledger at ${path2} belongs to ${ledger.tag} @ ${ledger.tagSha.slice(0, 12)} \u2014 not this release; left in place (${e instanceof Error ? e.message : String(e)})` };
|
|
21561
21751
|
}
|
|
21562
|
-
(0,
|
|
21752
|
+
(0, import_node_fs22.unlinkSync)(path2);
|
|
21563
21753
|
return { cleared: true, note: `cleared the release ledger at ${path2} for the live-proven aborted ${anchors.tag}` };
|
|
21564
21754
|
});
|
|
21565
21755
|
}
|
|
@@ -21662,7 +21852,7 @@ async function healStaleAlignmentLeg(deps, cwd, expected) {
|
|
|
21662
21852
|
return withFileLock(`${path2}.lock`, { label: "release ledger" }, async () => {
|
|
21663
21853
|
let prior;
|
|
21664
21854
|
try {
|
|
21665
|
-
prior = parseReleaseLedger((0,
|
|
21855
|
+
prior = parseReleaseLedger((0, import_node_fs22.readFileSync)(path2, "utf8"));
|
|
21666
21856
|
} catch {
|
|
21667
21857
|
return void 0;
|
|
21668
21858
|
}
|
|
@@ -21687,7 +21877,7 @@ async function supersedeContentCausedDeployLeg(deps, cwd) {
|
|
|
21687
21877
|
return withFileLock(`${path2}.lock`, { label: "release ledger" }, async () => {
|
|
21688
21878
|
let prior;
|
|
21689
21879
|
try {
|
|
21690
|
-
prior = parseReleaseLedger((0,
|
|
21880
|
+
prior = parseReleaseLedger((0, import_node_fs22.readFileSync)(path2, "utf8"));
|
|
21691
21881
|
} catch (e) {
|
|
21692
21882
|
throw new ReleaseLedgerError(
|
|
21693
21883
|
"unreadable",
|
|
@@ -21783,11 +21973,11 @@ async function proveOriginPromotionOrArchived(deps, prior, path2, label, ref) {
|
|
|
21783
21973
|
if (!releaseAbsent) {
|
|
21784
21974
|
throw new Error(`${label}: origin no longer has ${prior.tag} but its GitHub Release still exists \u2014 resolve the mixed external state before closing the ledger; nothing was written (${ref})`);
|
|
21785
21975
|
}
|
|
21786
|
-
const archivePath = (0,
|
|
21787
|
-
if ((0,
|
|
21976
|
+
const archivePath = (0, import_node_path22.join)((0, import_node_path22.dirname)(path2), `phases.archive-${prior.tag}.json`);
|
|
21977
|
+
if ((0, import_node_fs22.existsSync)(archivePath)) {
|
|
21788
21978
|
throw new Error(`${label}: archive already exists at ${archivePath} \u2014 preserving both ledger records; resolve the collision by hand; nothing was written (${ref})`);
|
|
21789
21979
|
}
|
|
21790
|
-
(0,
|
|
21980
|
+
(0, import_node_fs22.renameSync)(path2, archivePath);
|
|
21791
21981
|
return "deleted";
|
|
21792
21982
|
}
|
|
21793
21983
|
async function supersedeContentCausedPublishLeg(deps, cwd) {
|
|
@@ -21795,7 +21985,7 @@ async function supersedeContentCausedPublishLeg(deps, cwd) {
|
|
|
21795
21985
|
return withFileLock(`${path2}.lock`, { label: "release ledger" }, async () => {
|
|
21796
21986
|
let prior;
|
|
21797
21987
|
try {
|
|
21798
|
-
prior = parseReleaseLedger((0,
|
|
21988
|
+
prior = parseReleaseLedger((0, import_node_fs22.readFileSync)(path2, "utf8"));
|
|
21799
21989
|
} catch (e) {
|
|
21800
21990
|
throw new ReleaseLedgerError(
|
|
21801
21991
|
"unreadable",
|
|
@@ -21877,7 +22067,7 @@ async function supersedeContentCausedDeployAndPublishLegs(deps, cwd) {
|
|
|
21877
22067
|
return withFileLock(`${path2}.lock`, { label: "release ledger" }, async () => {
|
|
21878
22068
|
let prior;
|
|
21879
22069
|
try {
|
|
21880
|
-
prior = parseReleaseLedger((0,
|
|
22070
|
+
prior = parseReleaseLedger((0, import_node_fs22.readFileSync)(path2, "utf8"));
|
|
21881
22071
|
} catch (e) {
|
|
21882
22072
|
throw new ReleaseLedgerError(
|
|
21883
22073
|
"unreadable",
|
|
@@ -21982,7 +22172,7 @@ async function supersedeContentCausedDeployAndPublishLegs(deps, cwd) {
|
|
|
21982
22172
|
async function reverifyPriorRunLegs(deps, path2, targetTag) {
|
|
21983
22173
|
let prior;
|
|
21984
22174
|
try {
|
|
21985
|
-
prior = parseReleaseLedger((0,
|
|
22175
|
+
prior = parseReleaseLedger((0, import_node_fs22.readFileSync)(path2, "utf8"));
|
|
21986
22176
|
} catch {
|
|
21987
22177
|
return;
|
|
21988
22178
|
}
|
|
@@ -22002,7 +22192,7 @@ async function beginReleaseLedger(deps, cwd, targetTag) {
|
|
|
22002
22192
|
return withFileLock(`${path2}.lock`, { label: "release ledger" }, async () => {
|
|
22003
22193
|
let raw;
|
|
22004
22194
|
try {
|
|
22005
|
-
raw = (0,
|
|
22195
|
+
raw = (0, import_node_fs22.readFileSync)(path2, "utf8");
|
|
22006
22196
|
} catch (e) {
|
|
22007
22197
|
if (e.code === "ENOENT") return { ok: true };
|
|
22008
22198
|
return { ok: false, error: `the release ledger at ${path2} could not be READ (${e instanceof Error ? e.message : String(e)}) \u2014 a failed read is unverified, not absent (#5987/#4713)` };
|
|
@@ -22039,15 +22229,15 @@ async function beginReleaseLedger(deps, cwd, targetTag) {
|
|
|
22039
22229
|
if (liveSha.toLowerCase() !== prior.tagSha.toLowerCase()) {
|
|
22040
22230
|
return { ok: false, error: `the completed ${prior.tag} ledger says phases-green but origin reports ${liveSha.slice(0, 12) || "no tag"} \u2260 ${prior.tagSha.slice(0, 12)} \u2014 refusing to archive on unproven state; resolve by hand (#5987)` };
|
|
22041
22231
|
}
|
|
22042
|
-
const archivePath = (0,
|
|
22232
|
+
const archivePath = (0, import_node_path22.join)((0, import_node_path22.dirname)(path2), `phases.archive-${prior.tag}.json`);
|
|
22043
22233
|
try {
|
|
22044
|
-
(0,
|
|
22234
|
+
(0, import_node_fs22.unlinkSync)(archivePath);
|
|
22045
22235
|
} catch (e) {
|
|
22046
22236
|
if (e.code !== "ENOENT") {
|
|
22047
22237
|
return { ok: false, error: `could not clear the stale archive at ${archivePath} (${e instanceof Error ? e.message : String(e)}) \u2014 the ledger for ${prior.tag} stays active (#5987)` };
|
|
22048
22238
|
}
|
|
22049
22239
|
}
|
|
22050
|
-
(0,
|
|
22240
|
+
(0, import_node_fs22.renameSync)(path2, archivePath);
|
|
22051
22241
|
return { ok: true, note: `archived the completed release ledger ${prior.tag} to ${archivePath} (live-proven at ${prior.tagSha.slice(0, 12)})` };
|
|
22052
22242
|
});
|
|
22053
22243
|
}
|
|
@@ -22148,10 +22338,10 @@ function readOriginWorkflowsDefault(root, ref) {
|
|
|
22148
22338
|
}
|
|
22149
22339
|
var NPM_REGISTRY = "https://registry.npmjs.org";
|
|
22150
22340
|
async function probeRegistryWhoami(train) {
|
|
22151
|
-
const dir = (0,
|
|
22152
|
-
const rc = (0,
|
|
22341
|
+
const dir = (0, import_node_fs23.mkdtempSync)((0, import_node_path23.join)((0, import_node_os13.tmpdir)(), "mmi-npmrc-"));
|
|
22342
|
+
const rc = (0, import_node_path23.join)(dir, "npmrc");
|
|
22153
22343
|
try {
|
|
22154
|
-
(0,
|
|
22344
|
+
(0, import_node_fs23.writeFileSync)(rc, "//registry.npmjs.org/:_authToken=${NPM_TOKEN}\n");
|
|
22155
22345
|
await train.runSelf(["secrets", "use", "npm/NPM_TOKEN", "--slug", "_org", "--", "npm", "whoami", "--registry", NPM_REGISTRY, "--userconfig", rc]);
|
|
22156
22346
|
return { kind: "ok", detail: "the registry answered a login" };
|
|
22157
22347
|
} catch (e) {
|
|
@@ -22162,7 +22352,7 @@ async function probeRegistryWhoami(train) {
|
|
|
22162
22352
|
if (/\bE401\b|401 Unauthorized/.test(stderr)) return { kind: "rejected", detail: "npm whoami answered 401 Unauthorized" };
|
|
22163
22353
|
return { kind: "unverified", detail: first };
|
|
22164
22354
|
} finally {
|
|
22165
|
-
(0,
|
|
22355
|
+
(0, import_node_fs23.rmSync)(dir, { recursive: true, force: true });
|
|
22166
22356
|
}
|
|
22167
22357
|
}
|
|
22168
22358
|
var REGISTRY_TOKEN_ENV = /\b(NODE_AUTH_TOKEN|NPM_TOKEN)\b/;
|
|
@@ -22180,7 +22370,7 @@ var defaultDeps2 = {
|
|
|
22180
22370
|
ledgerPath: releaseLedgerPath,
|
|
22181
22371
|
readLedgerRaw: (path2) => {
|
|
22182
22372
|
try {
|
|
22183
|
-
return (0,
|
|
22373
|
+
return (0, import_node_fs23.readFileSync)(path2, "utf8");
|
|
22184
22374
|
} catch (e) {
|
|
22185
22375
|
if (e.code === "ENOENT") return void 0;
|
|
22186
22376
|
throw e;
|
|
@@ -22189,7 +22379,7 @@ var defaultDeps2 = {
|
|
|
22189
22379
|
healAlignmentLeg: healStaleAlignmentLeg,
|
|
22190
22380
|
readSurfacesRaw: (cwd) => {
|
|
22191
22381
|
try {
|
|
22192
|
-
return (0,
|
|
22382
|
+
return (0, import_node_fs23.readFileSync)((0, import_node_path23.join)(cwd, "surfaces.json"), "utf8");
|
|
22193
22383
|
} catch {
|
|
22194
22384
|
return void 0;
|
|
22195
22385
|
}
|
|
@@ -22594,6 +22784,53 @@ async function runTrainDoctor(input) {
|
|
|
22594
22784
|
regenerate the projections (\`node scripts/check-skill-payload.mjs\`) and commit the canonical fix; never hand-edit a projection` });
|
|
22595
22785
|
}
|
|
22596
22786
|
}
|
|
22787
|
+
if (isHubControlRepo(repo)) {
|
|
22788
|
+
const verifyDeps = async () => {
|
|
22789
|
+
try {
|
|
22790
|
+
await train.run("node", [`${cwd}/scripts/release-distribution.mjs`, "verify-deps"]);
|
|
22791
|
+
return null;
|
|
22792
|
+
} catch (e) {
|
|
22793
|
+
return message(e);
|
|
22794
|
+
}
|
|
22795
|
+
};
|
|
22796
|
+
const failure = await verifyDeps();
|
|
22797
|
+
if (failure) {
|
|
22798
|
+
const firstDir = /in (cli|updater)\/node_modules/u.exec(failure)?.[1] ?? null;
|
|
22799
|
+
if (!heal || !firstDir) {
|
|
22800
|
+
add({
|
|
22801
|
+
code: "hub-build-deps",
|
|
22802
|
+
severity: "blocker",
|
|
22803
|
+
source: "local",
|
|
22804
|
+
title: `the Hub distribution build dependencies do not resolve${firstDir ? ` in ${firstDir}/node_modules` : ""} \u2014 the release refuses at preflight`,
|
|
22805
|
+
remedy: firstDir ? `run \`mmi-cli devops train doctor --heal\` (installs ${firstDir} from its lockfile), or \`npm --prefix ${firstDir} ci\`` : "run `npm --prefix cli ci` and `npm --prefix updater ci`, then rerun"
|
|
22806
|
+
});
|
|
22807
|
+
} else {
|
|
22808
|
+
const installed = [];
|
|
22809
|
+
let pending = firstDir;
|
|
22810
|
+
let outstanding = failure;
|
|
22811
|
+
let failed = null;
|
|
22812
|
+
while (pending && !installed.includes(pending)) {
|
|
22813
|
+
const dir = pending;
|
|
22814
|
+
try {
|
|
22815
|
+
await train.run("npm", ["--prefix", dir, "ci"]);
|
|
22816
|
+
} catch (e) {
|
|
22817
|
+
failed = { dir, detail: `\`npm --prefix ${dir} ci\` failed: ${message(e)}` };
|
|
22818
|
+
break;
|
|
22819
|
+
}
|
|
22820
|
+
installed.push(dir);
|
|
22821
|
+
outstanding = await verifyDeps();
|
|
22822
|
+
pending = outstanding ? /in (cli|updater)\/node_modules/u.exec(outstanding)?.[1] ?? null : null;
|
|
22823
|
+
}
|
|
22824
|
+
if (failed) {
|
|
22825
|
+
add({ code: "hub-build-deps", severity: "blocker", source: "local", title: failed.detail, remedy: `repair ${failed.dir}/node_modules by hand, then rerun` });
|
|
22826
|
+
} else if (outstanding) {
|
|
22827
|
+
add({ code: "hub-build-deps", severity: "blocker", source: "local", title: `installing ${installed.join(", ")} from ${installed.length === 1 ? "its lockfile" : "their lockfiles"} did not resolve the build dependencies`, remedy: outstanding });
|
|
22828
|
+
} else {
|
|
22829
|
+
add({ code: "hub-build-deps", severity: "healed", source: "local", title: `installed ${installed.join(", ")} from ${installed.length === 1 ? "its lockfile" : "their lockfiles"} \u2014 the Hub distribution build dependencies resolve`, remedy: "nothing \u2014 the release preflight passes" });
|
|
22830
|
+
}
|
|
22831
|
+
}
|
|
22832
|
+
}
|
|
22833
|
+
}
|
|
22597
22834
|
const branches = TRAIN_BRANCHES.filter((b) => b !== "rc" || track === "full");
|
|
22598
22835
|
if (heal) {
|
|
22599
22836
|
const sync = await syncLocalTrainBranches(train.run, { branches, fetch: false });
|
|
@@ -22689,34 +22926,34 @@ function formatTrainDoctor(v) {
|
|
|
22689
22926
|
// src/train-apply-phases.ts
|
|
22690
22927
|
var TRAIN_BUMP_INTENTS = ["major", "minor", "patch"];
|
|
22691
22928
|
function readLocalGateWorkflows() {
|
|
22692
|
-
const dir = (0,
|
|
22929
|
+
const dir = (0, import_node_path24.join)(".github", "workflows");
|
|
22693
22930
|
let names;
|
|
22694
22931
|
try {
|
|
22695
|
-
names = (0,
|
|
22932
|
+
names = (0, import_node_fs24.readdirSync)(dir);
|
|
22696
22933
|
} catch {
|
|
22697
22934
|
return null;
|
|
22698
22935
|
}
|
|
22699
22936
|
const files = [];
|
|
22700
22937
|
for (const name of names.filter(isGateWorkflowPath)) {
|
|
22701
22938
|
try {
|
|
22702
|
-
files.push({ path: `${dir}/${name}`.replace(/\\/g, "/"), body: (0,
|
|
22939
|
+
files.push({ path: `${dir}/${name}`.replace(/\\/g, "/"), body: (0, import_node_fs24.readFileSync)((0, import_node_path24.join)(dir, name), "utf8") });
|
|
22703
22940
|
} catch {
|
|
22704
22941
|
}
|
|
22705
22942
|
}
|
|
22706
22943
|
return files;
|
|
22707
22944
|
}
|
|
22708
22945
|
function readLocalWorkflows() {
|
|
22709
|
-
const dir = (0,
|
|
22946
|
+
const dir = (0, import_node_path24.join)(".github", "workflows");
|
|
22710
22947
|
let names;
|
|
22711
22948
|
try {
|
|
22712
|
-
names = (0,
|
|
22949
|
+
names = (0, import_node_fs24.readdirSync)(dir);
|
|
22713
22950
|
} catch {
|
|
22714
22951
|
return null;
|
|
22715
22952
|
}
|
|
22716
22953
|
const files = [];
|
|
22717
22954
|
for (const name of names.filter((n) => /\.ya?ml$/i.test(n))) {
|
|
22718
22955
|
try {
|
|
22719
|
-
files.push({ path: `${dir}/${name}`.replace(/\\/g, "/"), body: (0,
|
|
22956
|
+
files.push({ path: `${dir}/${name}`.replace(/\\/g, "/"), body: (0, import_node_fs24.readFileSync)((0, import_node_path24.join)(dir, name), "utf8") });
|
|
22720
22957
|
} catch {
|
|
22721
22958
|
}
|
|
22722
22959
|
}
|
|
@@ -23506,6 +23743,16 @@ ${recovery.note}`), recoveryInput);
|
|
|
23506
23743
|
});
|
|
23507
23744
|
let dispatch = appendPublishDispatch(deployDispatch, publishDispatch);
|
|
23508
23745
|
if (publishSkipNote) dispatch = { ...dispatch, note: `${dispatch.note}; tenant-publish.yml skipped (${publishSkipNote})` };
|
|
23746
|
+
dispatch = await appendMmiGetRedeploy(
|
|
23747
|
+
deps,
|
|
23748
|
+
{ repo: ctx.repo, publishStatus: publishLeg.state === "complete" ? "success" : "failure", watch },
|
|
23749
|
+
dispatch
|
|
23750
|
+
);
|
|
23751
|
+
dispatch = await appendServedChannelPublish(
|
|
23752
|
+
deps,
|
|
23753
|
+
{ repo: ctx.repo, publishStatus: publishLeg.state === "complete" ? "success" : "failure", watch },
|
|
23754
|
+
dispatch
|
|
23755
|
+
);
|
|
23509
23756
|
const announcing = announceShippedRelease(
|
|
23510
23757
|
deps,
|
|
23511
23758
|
{ repo: ctx.repo, tag, summaryFile: options.announceSummaryFile },
|
|
@@ -23562,7 +23809,7 @@ async function activeRcandLedgerCandidate(deps, cwd) {
|
|
|
23562
23809
|
}
|
|
23563
23810
|
let prior;
|
|
23564
23811
|
try {
|
|
23565
|
-
prior = parseReleaseLedger((0,
|
|
23812
|
+
prior = parseReleaseLedger((0, import_node_fs24.readFileSync)(path2, "utf8"));
|
|
23566
23813
|
} catch {
|
|
23567
23814
|
return void 0;
|
|
23568
23815
|
}
|
|
@@ -26988,9 +27235,9 @@ function registerBoardCommands(program3) {
|
|
|
26988
27235
|
}
|
|
26989
27236
|
|
|
26990
27237
|
// src/bootstrap-commands.ts
|
|
26991
|
-
var
|
|
27238
|
+
var import_node_fs26 = require("node:fs");
|
|
26992
27239
|
var import_node_os14 = require("node:os");
|
|
26993
|
-
var
|
|
27240
|
+
var import_node_path26 = require("node:path");
|
|
26994
27241
|
init_cli_shared();
|
|
26995
27242
|
init_clean_exit();
|
|
26996
27243
|
|
|
@@ -27170,8 +27417,8 @@ init_github_client();
|
|
|
27170
27417
|
init_cli_shared();
|
|
27171
27418
|
|
|
27172
27419
|
// src/port-registry.ts
|
|
27173
|
-
var
|
|
27174
|
-
var
|
|
27420
|
+
var import_node_fs25 = require("node:fs");
|
|
27421
|
+
var import_node_path25 = require("node:path");
|
|
27175
27422
|
|
|
27176
27423
|
// ../infra/port-geometry.mjs
|
|
27177
27424
|
var PORT_BLOCK = 100;
|
|
@@ -27185,8 +27432,8 @@ function nextPortBlock(registry2) {
|
|
|
27185
27432
|
return [base, base + PORT_SPAN];
|
|
27186
27433
|
}
|
|
27187
27434
|
function loadPortRegistry(path2) {
|
|
27188
|
-
if (!(0,
|
|
27189
|
-
const raw = JSON.parse((0,
|
|
27435
|
+
if (!(0, import_node_fs25.existsSync)(path2)) return {};
|
|
27436
|
+
const raw = JSON.parse((0, import_node_fs25.readFileSync)(path2, "utf8"));
|
|
27190
27437
|
const out = {};
|
|
27191
27438
|
for (const [key, value] of Object.entries(raw)) {
|
|
27192
27439
|
if (Array.isArray(value) && value.length === 2 && value.every((n) => typeof n === "number")) {
|
|
@@ -27200,9 +27447,9 @@ function ensurePortRange(repo, path2) {
|
|
|
27200
27447
|
const existing = registry2[repo];
|
|
27201
27448
|
if (existing) return existing;
|
|
27202
27449
|
const range = nextPortBlock(registry2);
|
|
27203
|
-
const raw = (0,
|
|
27450
|
+
const raw = (0, import_node_fs25.existsSync)(path2) ? JSON.parse((0, import_node_fs25.readFileSync)(path2, "utf8")) : {};
|
|
27204
27451
|
raw[repo] = range;
|
|
27205
|
-
(0,
|
|
27452
|
+
(0, import_node_fs25.writeFileSync)(path2, JSON.stringify(raw, null, 2) + "\n", "utf8");
|
|
27206
27453
|
return range;
|
|
27207
27454
|
}
|
|
27208
27455
|
function portCursorSeed(registry2) {
|
|
@@ -27224,22 +27471,22 @@ function existingPortRange(repo, registry2) {
|
|
|
27224
27471
|
return registry2[repo] ?? null;
|
|
27225
27472
|
}
|
|
27226
27473
|
function portRangeInfraAt(root, source) {
|
|
27227
|
-
const registryPath = (0,
|
|
27228
|
-
const ddbScriptPath = (0,
|
|
27229
|
-
if (!(0,
|
|
27474
|
+
const registryPath = (0, import_node_path25.join)(root, "infra", "port-ranges.json");
|
|
27475
|
+
const ddbScriptPath = (0, import_node_path25.join)(root, "infra", "port-ddb.mjs");
|
|
27476
|
+
if (!(0, import_node_fs25.existsSync)(registryPath) || !(0, import_node_fs25.existsSync)(ddbScriptPath)) return null;
|
|
27230
27477
|
return { root, source, registryPath, ddbScriptPath };
|
|
27231
27478
|
}
|
|
27232
27479
|
function resolvePortRangeInfra(cwd, packageDir) {
|
|
27233
27480
|
const direct = portRangeInfraAt(cwd, "cwd");
|
|
27234
27481
|
if (direct) return direct;
|
|
27235
|
-
for (let dir = cwd; ; dir = (0,
|
|
27236
|
-
const sibling = portRangeInfraAt((0,
|
|
27482
|
+
for (let dir = cwd; ; dir = (0, import_node_path25.dirname)(dir)) {
|
|
27483
|
+
const sibling = portRangeInfraAt((0, import_node_path25.join)(dir, "MMI-Hub"), "sibling-hub");
|
|
27237
27484
|
if (sibling) return sibling;
|
|
27238
|
-
const parent = (0,
|
|
27485
|
+
const parent = (0, import_node_path25.dirname)(dir);
|
|
27239
27486
|
if (parent === dir) break;
|
|
27240
27487
|
}
|
|
27241
27488
|
if (packageDir) {
|
|
27242
|
-
const pkgRoot = (0,
|
|
27489
|
+
const pkgRoot = (0, import_node_path25.join)(packageDir, "..", "..");
|
|
27243
27490
|
const pkgFrom = portRangeInfraAt(pkgRoot, "pkg-root");
|
|
27244
27491
|
if (pkgFrom) return pkgFrom;
|
|
27245
27492
|
}
|
|
@@ -28725,13 +28972,13 @@ function registerBootstrapCommands(program3) {
|
|
|
28725
28972
|
deployFactsRead: deployFacts !== null,
|
|
28726
28973
|
pushAllowlistOwners: verifyOwners,
|
|
28727
28974
|
pushAllowlistOwnersRead: verifyOwnersRead,
|
|
28728
|
-
readLocalFile: (path2) => path2 === "projects.json" && apiProjects != null ? apiProjects : (0,
|
|
28975
|
+
readLocalFile: (path2) => path2 === "projects.json" && apiProjects != null ? apiProjects : (0, import_node_fs26.existsSync)(path2) ? (0, import_node_fs26.readFileSync)(path2, "utf8") : null,
|
|
28729
28976
|
// requiredGcpApis is stored as an array by a JSON write, but `org project set --var KEY=VALUE` stores a raw
|
|
28730
28977
|
// comma-string — accept either so the seeded value verifies regardless of how it was written.
|
|
28731
28978
|
// #3689: the same committed map the org access audit reads (#3664), so a sanctioned admin is not a
|
|
28732
28979
|
// permanent bootstrap failure on one surface and an intended state on the other. Absent file → no
|
|
28733
28980
|
// sanction, which is the pre-#3664 behaviour.
|
|
28734
|
-
sanctionedAdmins: (0,
|
|
28981
|
+
sanctionedAdmins: (0, import_node_fs26.existsSync)("access-matrix.json") ? entriesValueByCanonicalRepo(loadSanctionedAdmins((0, import_node_fs26.readFileSync)("access-matrix.json", "utf8")), repo) : void 0,
|
|
28735
28982
|
requiredGcpApis: (() => {
|
|
28736
28983
|
const v = meta?.requiredGcpApis;
|
|
28737
28984
|
if (Array.isArray(v)) return v;
|
|
@@ -28809,14 +29056,14 @@ function registerBootstrapCommands(program3) {
|
|
|
28809
29056
|
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 () => {
|
|
28810
29057
|
const o = { repo: rawValue("--repo", ""), json: rawFlag("--json") };
|
|
28811
29058
|
const manifestPath = "skills/bootstrap/seeds/manifest.json";
|
|
28812
|
-
if (!(0,
|
|
29059
|
+
if (!(0, import_node_fs26.existsSync)(manifestPath)) return fail(`bootstrap drift: ${manifestPath} not found; run from the MMI-Hub repo root \u2014 the Hub's copies ARE the reference this compares against`);
|
|
28813
29060
|
const seedSource = await resolveHubSeedSource(execGitForSeedSource);
|
|
28814
29061
|
if (!seedSource.ok) return fail(`bootstrap drift: ${seedSource.reason}`);
|
|
28815
|
-
const manifest = loadBootstrapSeeds((0,
|
|
29062
|
+
const manifest = loadBootstrapSeeds((0, import_node_fs26.readFileSync)(manifestPath, "utf8"));
|
|
28816
29063
|
const hubContents = /* @__PURE__ */ new Map();
|
|
28817
29064
|
for (const s of manifest.seeds) {
|
|
28818
29065
|
if (s.ownership !== "org" || s.source !== "self") continue;
|
|
28819
|
-
hubContents.set(s.target, (0,
|
|
29066
|
+
hubContents.set(s.target, (0, import_node_fs26.existsSync)(s.target) ? (0, import_node_fs26.readFileSync)(s.target, "utf8") : null);
|
|
28820
29067
|
}
|
|
28821
29068
|
let targets;
|
|
28822
29069
|
let classOf = (_repo) => "deployable";
|
|
@@ -28979,10 +29226,10 @@ function registerBootstrapCommands(program3) {
|
|
|
28979
29226
|
return;
|
|
28980
29227
|
}
|
|
28981
29228
|
const manifestPath = "skills/bootstrap/seeds/manifest.json";
|
|
28982
|
-
if (!(0,
|
|
29229
|
+
if (!(0, import_node_fs26.existsSync)(manifestPath)) return fail(`bootstrap apply: ${manifestPath} not found; bootstrap runs from the MMI-Hub repo root by design \u2014 it stamps org-level resources (Project, Ruleset, secrets, access) through the GitHub App, which is only authorized from the Hub checkout`);
|
|
28983
29230
|
const seedSource = await resolveHubSeedSource(execGitForSeedSource);
|
|
28984
29231
|
if (!seedSource.ok) return fail(`bootstrap apply: ${seedSource.reason}`);
|
|
28985
|
-
const manifest = loadBootstrapSeeds((0,
|
|
29232
|
+
const manifest = loadBootstrapSeeds((0, import_node_fs26.readFileSync)(manifestPath, "utf8"));
|
|
28986
29233
|
const baseBranch = o.class === "content" ? "main" : "development";
|
|
28987
29234
|
const slug = parsedRepo.slug;
|
|
28988
29235
|
const onlyTarget = o.only.trim();
|
|
@@ -28994,16 +29241,16 @@ function registerBootstrapCommands(program3) {
|
|
|
28994
29241
|
}
|
|
28995
29242
|
const onlyManagedBlock = onlyTarget ? seedsToApply[0]?.managedBlock != null : false;
|
|
28996
29243
|
const gh = async (args) => execFileP("gh", args, { timeout: 2e4 });
|
|
28997
|
-
const readFile9 = (p) => (0,
|
|
29244
|
+
const readFile9 = (p) => (0, import_node_fs26.existsSync)(p) ? (0, import_node_fs26.readFileSync)(p, "utf8") : null;
|
|
28998
29245
|
const enc = (p) => p.split("/").map(encodeURIComponent).join("/");
|
|
28999
29246
|
const putSeed = async (target, content, ref, sha) => {
|
|
29000
|
-
const tmp = (0,
|
|
29001
|
-
(0,
|
|
29247
|
+
const tmp = (0, import_node_path26.join)((0, import_node_os14.tmpdir)(), `mmi-seed-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
|
|
29248
|
+
(0, import_node_fs26.writeFileSync)(tmp, JSON.stringify(contentPutBody(target, content, ref, sha)), "utf8");
|
|
29002
29249
|
try {
|
|
29003
29250
|
await gh(contentPutInputArgs(repo, target, tmp));
|
|
29004
29251
|
} finally {
|
|
29005
29252
|
try {
|
|
29006
|
-
(0,
|
|
29253
|
+
(0, import_node_fs26.unlinkSync)(tmp);
|
|
29007
29254
|
} catch {
|
|
29008
29255
|
}
|
|
29009
29256
|
}
|
|
@@ -29452,10 +29699,10 @@ LIVE apply to ${repo}:
|
|
|
29452
29699
|
bootstrap.command("propagate").description("#4238: re-entrant canary\u2192wave tick \u2014 plan (or, with --execute, open) per-repo PRs fanning an org-owned seed out to the fleet").option("--target <path>", "the manifest target to propagate (an org-owned whole file or declared Hub-managed block)").option("--execute", "LIVE tick via gh (master-gated) \u2014 opens/reuses per-repo seed-propagate PRs; dry-run prints the plan only").option("--json", "machine-readable output").action(async () => {
|
|
29453
29700
|
const o = { target: rawValue("--target", ""), execute: rawFlag("--execute"), json: rawFlag("--json") };
|
|
29454
29701
|
const manifestPath = "skills/bootstrap/seeds/manifest.json";
|
|
29455
|
-
if (!(0,
|
|
29702
|
+
if (!(0, import_node_fs26.existsSync)(manifestPath)) return fail(`bootstrap propagate: ${manifestPath} not found; run from the MMI-Hub repo root \u2014 the Hub's copies ARE the desired state this tick propagates`);
|
|
29456
29703
|
const seedSource = await resolveHubSeedSource(execGitForSeedSource);
|
|
29457
29704
|
if (!seedSource.ok) return fail(`bootstrap propagate: ${seedSource.reason}`);
|
|
29458
|
-
const manifest = loadBootstrapSeeds((0,
|
|
29705
|
+
const manifest = loadBootstrapSeeds((0, import_node_fs26.readFileSync)(manifestPath, "utf8"));
|
|
29459
29706
|
const propagatable = manifest.seeds.filter(isPropagatableSeed);
|
|
29460
29707
|
if (!o.target) {
|
|
29461
29708
|
return fail(`bootstrap propagate: --target <path> is required \u2014 one of:
|
|
@@ -29464,9 +29711,9 @@ LIVE apply to ${repo}:
|
|
|
29464
29711
|
const seed = propagatable.find((s) => s.target === o.target);
|
|
29465
29712
|
if (!seed) return fail(`bootstrap propagate: --target '${o.target}' names no centrally propagatable seed in ${manifestPath}. Propagatable targets:
|
|
29466
29713
|
${propagatable.map((s) => s.target).join("\n ")}`);
|
|
29467
|
-
if (!seed.managedBlock && !(0,
|
|
29468
|
-
const hubContent = seed.managedBlock ? null : (0,
|
|
29469
|
-
const readSeedFile2 = (path2) => (0,
|
|
29714
|
+
if (!seed.managedBlock && !(0, import_node_fs26.existsSync)(seed.target)) return fail(`bootstrap propagate: the Hub's own copy of '${seed.target}' is missing \u2014 nothing to propagate`);
|
|
29715
|
+
const hubContent = seed.managedBlock ? null : (0, import_node_fs26.readFileSync)(seed.target, "utf8");
|
|
29716
|
+
const readSeedFile2 = (path2) => (0, import_node_fs26.existsSync)(path2) ? (0, import_node_fs26.readFileSync)(path2, "utf8") : null;
|
|
29470
29717
|
const isWorkflowSeed = seed.target.startsWith(".github/workflows/");
|
|
29471
29718
|
const cfg = await loadConfig();
|
|
29472
29719
|
const projects = await fetchProjectsList(registryClientDeps(cfg));
|
|
@@ -29475,9 +29722,9 @@ LIVE apply to ${repo}:
|
|
|
29475
29722
|
}
|
|
29476
29723
|
const rosterRepos = collectRegistryRepos(projects).filter((r) => r.toLowerCase() !== "mutmutco/mmi-hub");
|
|
29477
29724
|
let independentCount = rosterRepos.length;
|
|
29478
|
-
if ((0,
|
|
29725
|
+
if ((0, import_node_fs26.existsSync)("projects.json")) {
|
|
29479
29726
|
try {
|
|
29480
|
-
const local = JSON.parse((0,
|
|
29727
|
+
const local = JSON.parse((0, import_node_fs26.readFileSync)("projects.json", "utf8"));
|
|
29481
29728
|
const localRepos = /* @__PURE__ */ new Set();
|
|
29482
29729
|
for (const p of local.projects ?? []) for (const r of p.repos ?? []) {
|
|
29483
29730
|
const full = (r.includes("/") ? r : `mutmutco/${r}`).toLowerCase();
|
|
@@ -29638,15 +29885,15 @@ LIVE apply to ${repo}:
|
|
|
29638
29885
|
} catch {
|
|
29639
29886
|
existingSha = void 0;
|
|
29640
29887
|
}
|
|
29641
|
-
const tmp = (0,
|
|
29888
|
+
const tmp = (0, import_node_path26.join)((0, import_node_os14.tmpdir)(), `mmi-propagate-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
|
|
29642
29889
|
const desiredContent = desiredByRepo.get(rec.repo);
|
|
29643
29890
|
if (desiredContent == null) return fail(`bootstrap propagate: no resolved content for ${rec.repo} ${seed.target} \u2014 refusing to write`);
|
|
29644
|
-
(0,
|
|
29891
|
+
(0, import_node_fs26.writeFileSync)(tmp, JSON.stringify(contentPutBody(seed.target, desiredContent, branch, existingSha)), "utf8");
|
|
29645
29892
|
try {
|
|
29646
29893
|
await gh(contentPutInputArgs(rec.repo, seed.target, tmp));
|
|
29647
29894
|
} finally {
|
|
29648
29895
|
try {
|
|
29649
|
-
(0,
|
|
29896
|
+
(0, import_node_fs26.unlinkSync)(tmp);
|
|
29650
29897
|
} catch {
|
|
29651
29898
|
}
|
|
29652
29899
|
}
|
|
@@ -29713,10 +29960,10 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
|
|
|
29713
29960
|
return fail(`bootstrap rollback: ${e.message}`);
|
|
29714
29961
|
}
|
|
29715
29962
|
const manifestPath = "skills/bootstrap/seeds/manifest.json";
|
|
29716
|
-
if (!(0,
|
|
29963
|
+
if (!(0, import_node_fs26.existsSync)(manifestPath)) return fail(`bootstrap rollback: ${manifestPath} not found; run from the MMI-Hub repo root \u2014 the manifest names which targets are org-owned and therefore propagated (and rollback-able)`);
|
|
29717
29964
|
const seedSource = await resolveHubSeedSource(execGitForSeedSource);
|
|
29718
29965
|
if (!seedSource.ok) return fail(`bootstrap rollback: ${seedSource.reason}`);
|
|
29719
|
-
const manifest = loadBootstrapSeeds((0,
|
|
29966
|
+
const manifest = loadBootstrapSeeds((0, import_node_fs26.readFileSync)(manifestPath, "utf8"));
|
|
29720
29967
|
const propagatable = manifest.seeds.filter(isPropagatableSeed);
|
|
29721
29968
|
if (!o.target) {
|
|
29722
29969
|
return fail(`bootstrap rollback: --target <path> is required \u2014 one of:
|
|
@@ -29733,10 +29980,10 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
|
|
|
29733
29980
|
const enc = (p) => p.split("/").map(encodeURIComponent).join("/");
|
|
29734
29981
|
let candidates;
|
|
29735
29982
|
if (o.record) {
|
|
29736
|
-
if (!(0,
|
|
29983
|
+
if (!(0, import_node_fs26.existsSync)(o.record)) return fail(`bootstrap rollback: --record '${o.record}' not found`);
|
|
29737
29984
|
let parsed;
|
|
29738
29985
|
try {
|
|
29739
|
-
parsed = JSON.parse((0,
|
|
29986
|
+
parsed = JSON.parse((0, import_node_fs26.readFileSync)(o.record, "utf8"));
|
|
29740
29987
|
} catch (e) {
|
|
29741
29988
|
return fail(`bootstrap rollback: --record '${o.record}' is not valid JSON: ${e.message}`);
|
|
29742
29989
|
}
|
|
@@ -29813,13 +30060,13 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
|
|
|
29813
30060
|
} catch {
|
|
29814
30061
|
existingSha = void 0;
|
|
29815
30062
|
}
|
|
29816
|
-
const tmp = (0,
|
|
29817
|
-
(0,
|
|
30063
|
+
const tmp = (0, import_node_path26.join)((0, import_node_os14.tmpdir)(), `mmi-rollback-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
|
|
30064
|
+
(0, import_node_fs26.writeFileSync)(tmp, JSON.stringify(contentPutBody(seed.target, preSeedContent, plan.branch, existingSha)), "utf8");
|
|
29818
30065
|
try {
|
|
29819
30066
|
await gh(contentPutInputArgs(repo, seed.target, tmp));
|
|
29820
30067
|
} finally {
|
|
29821
30068
|
try {
|
|
29822
|
-
(0,
|
|
30069
|
+
(0, import_node_fs26.unlinkSync)(tmp);
|
|
29823
30070
|
} catch {
|
|
29824
30071
|
}
|
|
29825
30072
|
}
|
|
@@ -30886,7 +31133,7 @@ function renderDeployPortDoctor(report) {
|
|
|
30886
31133
|
init_cli_shared();
|
|
30887
31134
|
|
|
30888
31135
|
// src/wave-status.ts
|
|
30889
|
-
var
|
|
31136
|
+
var import_node_fs29 = require("node:fs");
|
|
30890
31137
|
|
|
30891
31138
|
// src/git-worktree-observation.ts
|
|
30892
31139
|
function parseGitWorktreePorcelain(text) {
|
|
@@ -30917,8 +31164,8 @@ function deriveComposeProjectName(worktreePath) {
|
|
|
30917
31164
|
|
|
30918
31165
|
// src/stage-runner.ts
|
|
30919
31166
|
var import_node_child_process10 = require("node:child_process");
|
|
30920
|
-
var
|
|
30921
|
-
var
|
|
31167
|
+
var import_node_fs28 = require("node:fs");
|
|
31168
|
+
var import_node_path28 = require("node:path");
|
|
30922
31169
|
var import_node_net = require("node:net");
|
|
30923
31170
|
var import_node_util5 = require("node:util");
|
|
30924
31171
|
|
|
@@ -30928,8 +31175,8 @@ function normalizeEol2(s) {
|
|
|
30928
31175
|
}
|
|
30929
31176
|
|
|
30930
31177
|
// src/env-detection.ts
|
|
30931
|
-
var
|
|
30932
|
-
var
|
|
31178
|
+
var import_node_fs27 = require("node:fs");
|
|
31179
|
+
var import_node_path27 = require("node:path");
|
|
30933
31180
|
var SKIPPED_DIRS = /* @__PURE__ */ new Set([".git", "node_modules", "dist", ".jerv", ".pi", ".venv", "venv"]);
|
|
30934
31181
|
function isEnvBaseName(name) {
|
|
30935
31182
|
return name.toLowerCase() === ".env";
|
|
@@ -30939,7 +31186,7 @@ function findEnvFiles(root) {
|
|
|
30939
31186
|
const walk2 = (dir, rel) => {
|
|
30940
31187
|
let entries;
|
|
30941
31188
|
try {
|
|
30942
|
-
entries = (0,
|
|
31189
|
+
entries = (0, import_node_fs27.readdirSync)(dir, { withFileTypes: true });
|
|
30943
31190
|
} catch {
|
|
30944
31191
|
return;
|
|
30945
31192
|
}
|
|
@@ -30947,13 +31194,13 @@ function findEnvFiles(root) {
|
|
|
30947
31194
|
const relPath = rel ? `${rel}/${entry.name}` : entry.name;
|
|
30948
31195
|
if (entry.isDirectory()) {
|
|
30949
31196
|
if (SKIPPED_DIRS.has(entry.name)) continue;
|
|
30950
|
-
walk2((0,
|
|
31197
|
+
walk2((0, import_node_path27.join)(dir, entry.name), relPath);
|
|
30951
31198
|
continue;
|
|
30952
31199
|
}
|
|
30953
31200
|
if (isEnvBaseName(entry.name)) {
|
|
30954
31201
|
let isDir = false;
|
|
30955
31202
|
try {
|
|
30956
|
-
isDir = (0,
|
|
31203
|
+
isDir = (0, import_node_fs27.lstatSync)((0, import_node_path27.join)(dir, entry.name)).isDirectory();
|
|
30957
31204
|
} catch {
|
|
30958
31205
|
}
|
|
30959
31206
|
if (!isDir) found.push(relPath);
|
|
@@ -31015,12 +31262,12 @@ var DOCKER_TIMEOUT_MS = 15e3;
|
|
|
31015
31262
|
function stageBash() {
|
|
31016
31263
|
if (process.platform !== "win32") return "bash";
|
|
31017
31264
|
const configured = process.env.SHELL;
|
|
31018
|
-
if (configured && (0,
|
|
31265
|
+
if (configured && (0, import_node_path28.isAbsolute)(configured) && /[/\\]bash(?:\.exe)?$/i.test(configured) && !/[/\\](?:System32|Sysnative)[/\\]bash(?:\.exe)?$/i.test(configured) && (0, import_node_fs28.existsSync)(configured)) return configured;
|
|
31019
31266
|
const candidates = [
|
|
31020
|
-
(0,
|
|
31021
|
-
...process.env.LOCALAPPDATA ? [(0,
|
|
31267
|
+
(0, import_node_path28.join)(process.env.ProgramFiles || "C:\\Program Files", "Git", "bin", "bash.exe"),
|
|
31268
|
+
...process.env.LOCALAPPDATA ? [(0, import_node_path28.join)(process.env.LOCALAPPDATA, "Programs", "Git", "bin", "bash.exe")] : []
|
|
31022
31269
|
];
|
|
31023
|
-
const bash = candidates.find((path2) => (0,
|
|
31270
|
+
const bash = candidates.find((path2) => (0, import_node_fs28.existsSync)(path2));
|
|
31024
31271
|
if (!bash) throw new Error("Local stages require Git Bash on Windows. Install Git for Windows or set SHELL to its absolute bash.exe path.");
|
|
31025
31272
|
return bash;
|
|
31026
31273
|
}
|
|
@@ -31151,7 +31398,7 @@ function appendForceRecreate(up) {
|
|
|
31151
31398
|
return `${up.trimEnd()} --force-recreate`;
|
|
31152
31399
|
}
|
|
31153
31400
|
function stageStatePath(cwd = process.cwd()) {
|
|
31154
|
-
return (0,
|
|
31401
|
+
return (0, import_node_path28.join)(cwd, "tmp", "stage", "state.json");
|
|
31155
31402
|
}
|
|
31156
31403
|
function normPath(path2) {
|
|
31157
31404
|
return path2.replace(/\\/g, "/").replace(/\/+$/, "").toLowerCase();
|
|
@@ -31368,8 +31615,8 @@ function stageProcessEnv(stagePort, extraEnv) {
|
|
|
31368
31615
|
}
|
|
31369
31616
|
function composeResolvesPort(cwd) {
|
|
31370
31617
|
if (process.env.PORT) return true;
|
|
31371
|
-
const envFile = (0,
|
|
31372
|
-
return (0,
|
|
31618
|
+
const envFile = (0, import_node_path28.join)(cwd, ".env");
|
|
31619
|
+
return (0, import_node_fs28.existsSync)(envFile) && envFileKeys((0, import_node_fs28.readFileSync)(envFile, "utf8")).has("PORT");
|
|
31373
31620
|
}
|
|
31374
31621
|
function stageComposeEnv(config, stagePort, vaultEnvMerge, cwd) {
|
|
31375
31622
|
return {
|
|
@@ -31382,13 +31629,13 @@ function stageComposeEnv(config, stagePort, vaultEnvMerge, cwd) {
|
|
|
31382
31629
|
function stageComposeFiles(cwd) {
|
|
31383
31630
|
const files = ["docker-compose.yml"];
|
|
31384
31631
|
for (const conventional of ["docker-compose.override.yml", "docker-compose.override.yaml"]) {
|
|
31385
|
-
if ((0,
|
|
31632
|
+
if ((0, import_node_fs28.existsSync)((0, import_node_path28.join)(cwd, conventional))) files.push(conventional);
|
|
31386
31633
|
}
|
|
31387
31634
|
return [...files, RUNTIME_ENV_OVERRIDE_RELPATH];
|
|
31388
31635
|
}
|
|
31389
31636
|
async function prepareRuntimeEnvPassthrough(cwd, composeEnv, vaultEnvMerge) {
|
|
31390
31637
|
const keys = Object.keys(vaultEnvMerge ?? {});
|
|
31391
|
-
if (!keys.length || !(0,
|
|
31638
|
+
if (!keys.length || !(0, import_node_fs28.existsSync)((0, import_node_path28.join)(cwd, "docker-compose.yml"))) return {};
|
|
31392
31639
|
let configJson;
|
|
31393
31640
|
try {
|
|
31394
31641
|
const { stdout } = await execFileP3("docker", ["compose", "config", "--format", "json"], {
|
|
@@ -31404,21 +31651,21 @@ async function prepareRuntimeEnvPassthrough(cwd, composeEnv, vaultEnvMerge) {
|
|
|
31404
31651
|
}
|
|
31405
31652
|
const body = renderRuntimeEnvOverride(runtimeEnvMarkedServices(configJson), keys);
|
|
31406
31653
|
if (!body) return {};
|
|
31407
|
-
const overridePath = (0,
|
|
31408
|
-
(0,
|
|
31409
|
-
(0,
|
|
31654
|
+
const overridePath = (0, import_node_path28.join)(cwd, RUNTIME_ENV_OVERRIDE_RELPATH);
|
|
31655
|
+
(0, import_node_fs28.mkdirSync)((0, import_node_path28.join)(cwd, "tmp", "stage"), { recursive: true });
|
|
31656
|
+
(0, import_node_fs28.writeFileSync)(overridePath, body, "utf8");
|
|
31410
31657
|
return stageComposeFileEnv(stageComposeFiles(cwd));
|
|
31411
31658
|
}
|
|
31412
31659
|
async function ensureStageRuntimeEnv(config, opts, cwd) {
|
|
31413
31660
|
if (!config.ensureEnv) return;
|
|
31414
|
-
const target = (0,
|
|
31415
|
-
const example = (0,
|
|
31416
|
-
if (!(0,
|
|
31417
|
-
(0,
|
|
31418
|
-
} else if ((0,
|
|
31419
|
-
const stale = detectStaleEnvFile((0,
|
|
31420
|
-
exampleMtimeMs: (0,
|
|
31421
|
-
targetMtimeMs: (0,
|
|
31661
|
+
const target = (0, import_node_path28.join)(cwd, config.ensureEnv.target);
|
|
31662
|
+
const example = (0, import_node_path28.join)(cwd, config.ensureEnv.example);
|
|
31663
|
+
if (!(0, import_node_fs28.existsSync)(target) && (0, import_node_fs28.existsSync)(example)) {
|
|
31664
|
+
(0, import_node_fs28.copyFileSync)(example, target);
|
|
31665
|
+
} else if ((0, import_node_fs28.existsSync)(target) && (0, import_node_fs28.existsSync)(example)) {
|
|
31666
|
+
const stale = detectStaleEnvFile((0, import_node_fs28.readFileSync)(example, "utf8"), (0, import_node_fs28.readFileSync)(target, "utf8"), {
|
|
31667
|
+
exampleMtimeMs: (0, import_node_fs28.statSync)(example).mtimeMs,
|
|
31668
|
+
targetMtimeMs: (0, import_node_fs28.statSync)(target).mtimeMs
|
|
31422
31669
|
});
|
|
31423
31670
|
if (stale) {
|
|
31424
31671
|
const msg = `stale ${config.ensureEnv.target} (${stale}) \u2014 delete it or refresh from ${config.ensureEnv.example} before re-running /stage`;
|
|
@@ -31426,8 +31673,8 @@ async function ensureStageRuntimeEnv(config, opts, cwd) {
|
|
|
31426
31673
|
console.error(`mmi-cli stage: ${msg} (allowed via --allow-stale-env)`);
|
|
31427
31674
|
}
|
|
31428
31675
|
}
|
|
31429
|
-
if (opts.vaultEnvMerge && Object.keys(opts.vaultEnvMerge).length && (0,
|
|
31430
|
-
(0,
|
|
31676
|
+
if (opts.vaultEnvMerge && Object.keys(opts.vaultEnvMerge).length && (0, import_node_fs28.existsSync)(target)) {
|
|
31677
|
+
(0, import_node_fs28.writeFileSync)(target, mergeEnvSecretsIntoFile((0, import_node_fs28.readFileSync)(target, "utf8"), opts.vaultEnvMerge), "utf8");
|
|
31431
31678
|
}
|
|
31432
31679
|
}
|
|
31433
31680
|
async function gitText(cwd, args) {
|
|
@@ -31457,20 +31704,20 @@ async function resolveGlobalStatePath(cwd, explicit) {
|
|
|
31457
31704
|
return void 0;
|
|
31458
31705
|
}
|
|
31459
31706
|
function readState(path2) {
|
|
31460
|
-
if (!(0,
|
|
31707
|
+
if (!(0, import_node_fs28.existsSync)(path2)) return null;
|
|
31461
31708
|
try {
|
|
31462
|
-
return JSON.parse((0,
|
|
31709
|
+
return JSON.parse((0, import_node_fs28.readFileSync)(path2, "utf8"));
|
|
31463
31710
|
} catch {
|
|
31464
31711
|
return null;
|
|
31465
31712
|
}
|
|
31466
31713
|
}
|
|
31467
31714
|
function mkdirFor(path2) {
|
|
31468
31715
|
const dir = path2.slice(0, Math.max(path2.lastIndexOf("/"), path2.lastIndexOf("\\")));
|
|
31469
|
-
(0,
|
|
31716
|
+
(0, import_node_fs28.mkdirSync)(dir, { recursive: true });
|
|
31470
31717
|
}
|
|
31471
31718
|
function writeState(path2, state) {
|
|
31472
31719
|
mkdirFor(path2);
|
|
31473
|
-
(0,
|
|
31720
|
+
(0, import_node_fs28.writeFileSync)(path2, JSON.stringify(state, null, 2), "utf8");
|
|
31474
31721
|
}
|
|
31475
31722
|
function writeStagePortReservation(port, cwd, statePath, globalStatePath, now) {
|
|
31476
31723
|
const reservation = {
|
|
@@ -31499,7 +31746,7 @@ async function cleanupStageState(state, paths, timeoutMs, fallbackCwd, currentEn
|
|
|
31499
31746
|
);
|
|
31500
31747
|
}
|
|
31501
31748
|
for (const path2 of [...new Set(paths.filter((p) => Boolean(p)))]) {
|
|
31502
|
-
(0,
|
|
31749
|
+
(0, import_node_fs28.rmSync)(path2, { force: true });
|
|
31503
31750
|
}
|
|
31504
31751
|
}
|
|
31505
31752
|
async function killTree(pid) {
|
|
@@ -31686,8 +31933,8 @@ async function runStage(config = {}, opts = {}) {
|
|
|
31686
31933
|
});
|
|
31687
31934
|
}
|
|
31688
31935
|
} catch (e) {
|
|
31689
|
-
(0,
|
|
31690
|
-
if (globalStatePath && globalStatePath !== statePath) (0,
|
|
31936
|
+
(0, import_node_fs28.rmSync)(statePath, { force: true });
|
|
31937
|
+
if (globalStatePath && globalStatePath !== statePath) (0, import_node_fs28.rmSync)(globalStatePath, { force: true });
|
|
31691
31938
|
throw e;
|
|
31692
31939
|
}
|
|
31693
31940
|
const started = await startStage(config, {
|
|
@@ -31704,9 +31951,9 @@ async function runStage(config = {}, opts = {}) {
|
|
|
31704
31951
|
// src/wave-status.ts
|
|
31705
31952
|
function readStageSummary(worktreePath) {
|
|
31706
31953
|
const statePath = stageStatePath(worktreePath);
|
|
31707
|
-
if (!(0,
|
|
31954
|
+
if (!(0, import_node_fs29.existsSync)(statePath)) return void 0;
|
|
31708
31955
|
try {
|
|
31709
|
-
const state = JSON.parse((0,
|
|
31956
|
+
const state = JSON.parse((0, import_node_fs29.readFileSync)(statePath, "utf8"));
|
|
31710
31957
|
const port = typeof state.port === "number" ? state.port : void 0;
|
|
31711
31958
|
if (port == null || !Number.isInteger(port) || port <= 0) return void 0;
|
|
31712
31959
|
return { port, url: typeof state.url === "string" ? state.url : void 0 };
|
|
@@ -31763,9 +32010,9 @@ async function collectWaveStatus(deps) {
|
|
|
31763
32010
|
// src/discovery-commands.ts
|
|
31764
32011
|
init_github_client();
|
|
31765
32012
|
init_cli_shared();
|
|
31766
|
-
var
|
|
32013
|
+
var import_node_fs30 = require("node:fs");
|
|
31767
32014
|
var import_node_os15 = require("node:os");
|
|
31768
|
-
var
|
|
32015
|
+
var import_node_path29 = require("node:path");
|
|
31769
32016
|
var GC_GH_TIMEOUT_MS = 2e4;
|
|
31770
32017
|
async function collectStatus() {
|
|
31771
32018
|
const repo = await resolveRepo();
|
|
@@ -31955,8 +32202,8 @@ async function collectOnboardStatus(opts = {}) {
|
|
|
31955
32202
|
}
|
|
31956
32203
|
const home = (0, import_node_os15.homedir)();
|
|
31957
32204
|
const plugin = onboardPluginGate({
|
|
31958
|
-
readKnown: () => readFileSyncSafe((0,
|
|
31959
|
-
readSettings: () => readFileSyncSafe((0,
|
|
32205
|
+
readKnown: () => readFileSyncSafe((0, import_node_path29.join)(home, ...KNOWN_MARKETPLACES_RELATIVE), import_node_fs30.readFileSync),
|
|
32206
|
+
readSettings: () => readFileSyncSafe((0, import_node_path29.join)(home, ".claude", "settings.json"), import_node_fs30.readFileSync)
|
|
31960
32207
|
});
|
|
31961
32208
|
return {
|
|
31962
32209
|
guide: "Read the MMI org-guide skill before project work; load only the relevant topic. Use mmi-help for a short introduction.",
|
|
@@ -33973,7 +34220,7 @@ function parseOriginRepo(remoteUrl) {
|
|
|
33973
34220
|
init_github_client();
|
|
33974
34221
|
|
|
33975
34222
|
// src/issue-commands.ts
|
|
33976
|
-
var
|
|
34223
|
+
var import_node_fs31 = require("node:fs");
|
|
33977
34224
|
var import_node_crypto10 = require("node:crypto");
|
|
33978
34225
|
init_cli_shared();
|
|
33979
34226
|
init_clean_exit();
|
|
@@ -34230,7 +34477,7 @@ async function editIssue(client, options, deps = {}) {
|
|
|
34230
34477
|
const url = `https://github.com/${repo}/issues/${parsed.number}`;
|
|
34231
34478
|
const patch = {};
|
|
34232
34479
|
let bodyChanged = false;
|
|
34233
|
-
const textDeps = () => deps.textDeps ?? { readFile: (p, e) => Promise.resolve((0,
|
|
34480
|
+
const textDeps = () => deps.textDeps ?? { readFile: (p, e) => Promise.resolve((0, import_node_fs31.readFileSync)(p, e)), readStdin: () => Promise.resolve("") };
|
|
34234
34481
|
if (options.titleFile !== void 0) {
|
|
34235
34482
|
patch.title = await resolveIssueTitle({ title: options.title, titleFile: options.titleFile }, textDeps());
|
|
34236
34483
|
} else if (options.title !== void 0) {
|
|
@@ -34886,7 +35133,7 @@ function extendCreateCommand(issue, batchAttach) {
|
|
|
34886
35133
|
if (opts.batch) {
|
|
34887
35134
|
let specs;
|
|
34888
35135
|
try {
|
|
34889
|
-
const raw = (0,
|
|
35136
|
+
const raw = (0, import_node_fs31.readFileSync)(opts.batch, "utf8");
|
|
34890
35137
|
specs = JSON.parse(raw);
|
|
34891
35138
|
if (!Array.isArray(specs)) {
|
|
34892
35139
|
const top = specs === null ? "null" : typeof specs === "object" ? `an object with keys: ${Object.keys(specs).join(", ") || "(none)"}` : `a ${typeof specs}`;
|
|
@@ -36050,8 +36297,8 @@ function registerPrLifecycleCommands(program3) {
|
|
|
36050
36297
|
}
|
|
36051
36298
|
|
|
36052
36299
|
// src/project-info-sync.ts
|
|
36053
|
-
var
|
|
36054
|
-
var
|
|
36300
|
+
var import_node_fs32 = require("node:fs");
|
|
36301
|
+
var import_node_path30 = require("node:path");
|
|
36055
36302
|
var UPDATE_PROJECT_INFO = `mutation($projectId: ID!, $shortDescription: String!, $readme: String!) {
|
|
36056
36303
|
updateProjectV2(input: { projectId: $projectId, shortDescription: $shortDescription, readme: $readme }) {
|
|
36057
36304
|
projectV2 { id }
|
|
@@ -36098,14 +36345,14 @@ function sharedName(entries, fallback) {
|
|
|
36098
36345
|
}
|
|
36099
36346
|
function buildProjectInfoSyncPlan(targetRepo2, project2, projects, repoRoot2) {
|
|
36100
36347
|
if (!project2.projectId) throw new Error(`org project sync-info: ${targetRepo2} registry META has no projectId`);
|
|
36101
|
-
const readmePath = (0,
|
|
36102
|
-
if (!(0,
|
|
36348
|
+
const readmePath = (0, import_node_path30.join)(repoRoot2, "README.md");
|
|
36349
|
+
if (!(0, import_node_fs32.existsSync)(readmePath)) throw new Error(`org project sync-info: ${targetRepo2} has no README.md`);
|
|
36103
36350
|
const entries = entriesFor(project2, projects);
|
|
36104
36351
|
const memberRepos = [...new Set(entries.flatMap((entry) => entry.repos ?? []))].filter((repo) => /^[^/]+\/[^/]+$/.test(repo)).sort((a, b) => a.localeCompare(b));
|
|
36105
36352
|
const projectName = sharedName(entries, project2.name?.trim() || targetRepo2.split("/").pop() || targetRepo2);
|
|
36106
36353
|
if (!memberRepos.length) throw new Error(`org project sync-info: project ${projectName} has no registered member repos`);
|
|
36107
36354
|
const entryNames = entries.map((entry) => entry.name?.trim()).filter((name) => Boolean(name));
|
|
36108
|
-
const shortDescription = memberRepos.length === 1 ? shortDescriptionFromReadme((0,
|
|
36355
|
+
const shortDescription = memberRepos.length === 1 ? shortDescriptionFromReadme((0, import_node_fs32.readFileSync)(readmePath, "utf8")) : `Shared work across ${new Intl.ListFormat("en", { type: "conjunction" }).format(entryNames)}.`;
|
|
36109
36356
|
const lines2 = [
|
|
36110
36357
|
`# ${projectName}`,
|
|
36111
36358
|
"",
|
|
@@ -36124,8 +36371,8 @@ function buildProjectInfoSyncPlan(targetRepo2, project2, projects, repoRoot2) {
|
|
|
36124
36371
|
const targetBase = `https://github.com/${targetRepo2}`;
|
|
36125
36372
|
const targetBranch = branchFor(targetRepo2, projects);
|
|
36126
36373
|
const orgDocs = [
|
|
36127
|
-
(0,
|
|
36128
|
-
(0,
|
|
36374
|
+
(0, import_node_fs32.existsSync)((0, import_node_path30.join)(repoRoot2, "architecture.md")) ? `- [Hub architecture](${targetBase}/blob/${targetBranch}/architecture.md)` : "",
|
|
36375
|
+
(0, import_node_fs32.existsSync)((0, import_node_path30.join)(repoRoot2, "docs", "Architecture", "agentic-dev-environment.md")) ? `- [Agentic development environment](${targetBase}/blob/${targetBranch}/docs/Architecture/agentic-dev-environment.md)` : ""
|
|
36129
36376
|
].filter(Boolean);
|
|
36130
36377
|
if (orgDocs.length) lines2.push("", "## Organisation docs", "", ...orgDocs);
|
|
36131
36378
|
return { projectId: project2.projectId, projectName, targetRepo: targetRepo2, memberRepos, shortDescription, readme: `${lines2.join("\n")}
|
|
@@ -36507,8 +36754,8 @@ function registerSchedulesCommands(program3) {
|
|
|
36507
36754
|
}
|
|
36508
36755
|
|
|
36509
36756
|
// src/secrets-commands.ts
|
|
36510
|
-
var
|
|
36511
|
-
var
|
|
36757
|
+
var import_node_fs33 = require("node:fs");
|
|
36758
|
+
var import_node_path31 = require("node:path");
|
|
36512
36759
|
var import_node_os17 = require("node:os");
|
|
36513
36760
|
init_cli_shared();
|
|
36514
36761
|
init_hub_auth();
|
|
@@ -36614,18 +36861,18 @@ function collectMap(value, previous = []) {
|
|
|
36614
36861
|
return [...previous, value];
|
|
36615
36862
|
}
|
|
36616
36863
|
async function decryptRailsCredentials(input) {
|
|
36617
|
-
const appDir = (0,
|
|
36864
|
+
const appDir = (0, import_node_path31.resolve)(input.appDir ?? process.cwd());
|
|
36618
36865
|
const credentialsFile = input.credentialsFile ?? DEFAULT_RAILS_CREDENTIALS_FILE;
|
|
36619
36866
|
const masterKeyFile = input.masterKeyFile ?? DEFAULT_RAILS_MASTER_KEY_FILE;
|
|
36620
|
-
const credentialsPath = (0,
|
|
36621
|
-
const masterKeyPath = (0,
|
|
36867
|
+
const credentialsPath = (0, import_node_path31.resolve)(appDir, credentialsFile);
|
|
36868
|
+
const masterKeyPath = (0, import_node_path31.resolve)(appDir, masterKeyFile);
|
|
36622
36869
|
const env = {
|
|
36623
36870
|
...process.env,
|
|
36624
36871
|
MMI_RAILS_CREDENTIALS_FILE: credentialsPath,
|
|
36625
36872
|
MMI_RAILS_MASTER_KEY_FILE: masterKeyPath
|
|
36626
36873
|
};
|
|
36627
|
-
if ((0,
|
|
36628
|
-
env.RAILS_MASTER_KEY = (0,
|
|
36874
|
+
if ((0, import_node_fs33.existsSync)(masterKeyPath)) {
|
|
36875
|
+
env.RAILS_MASTER_KEY = (0, import_node_fs33.readFileSync)(masterKeyPath, "utf8").trim();
|
|
36629
36876
|
}
|
|
36630
36877
|
const script = [
|
|
36631
36878
|
'require "json"',
|
|
@@ -36635,9 +36882,9 @@ async function decryptRailsCredentials(input) {
|
|
|
36635
36882
|
'config = ActiveSupport::EncryptedConfiguration.new(config_path: config_path, key_path: key_path, env_key: "RAILS_MASTER_KEY", raise_if_missing_key: true)',
|
|
36636
36883
|
"puts JSON.generate(config.config)"
|
|
36637
36884
|
].join("\n");
|
|
36638
|
-
const scriptDir = (0,
|
|
36639
|
-
const scriptPath = (0,
|
|
36640
|
-
(0,
|
|
36885
|
+
const scriptDir = (0, import_node_fs33.mkdtempSync)((0, import_node_path31.join)((0, import_node_os17.tmpdir)(), "mmi-rails-decrypt-"));
|
|
36886
|
+
const scriptPath = (0, import_node_path31.join)(scriptDir, "decrypt.rb");
|
|
36887
|
+
(0, import_node_fs33.writeFileSync)(scriptPath, script, "utf8");
|
|
36641
36888
|
try {
|
|
36642
36889
|
const args = ["exec", "ruby", scriptPath];
|
|
36643
36890
|
const cmd = process.platform === "win32" ? "cmd.exe" : "bundle";
|
|
@@ -36649,7 +36896,7 @@ async function decryptRailsCredentials(input) {
|
|
|
36649
36896
|
});
|
|
36650
36897
|
return JSON.parse(stdout);
|
|
36651
36898
|
} finally {
|
|
36652
|
-
(0,
|
|
36899
|
+
(0, import_node_fs33.rmSync)(scriptDir, { recursive: true, force: true });
|
|
36653
36900
|
}
|
|
36654
36901
|
}
|
|
36655
36902
|
async function readSecretStdin() {
|
|
@@ -36739,7 +36986,7 @@ function registerSecretsCommands(program3) {
|
|
|
36739
36986
|
let body;
|
|
36740
36987
|
if (o.file) {
|
|
36741
36988
|
try {
|
|
36742
|
-
body = (0,
|
|
36989
|
+
body = (0, import_node_fs33.readFileSync)((0, import_node_path31.resolve)(o.file), "utf8");
|
|
36743
36990
|
} catch (e) {
|
|
36744
36991
|
return fail(`secrets org-catalog: cannot read --file ${o.file}: ${e.message}`);
|
|
36745
36992
|
}
|
|
@@ -36871,7 +37118,7 @@ function registerSecretsCommands(program3) {
|
|
|
36871
37118
|
{
|
|
36872
37119
|
...d,
|
|
36873
37120
|
decryptRailsCredentials,
|
|
36874
|
-
removeFile: (path2) => (0,
|
|
37121
|
+
removeFile: (path2) => (0, import_node_fs33.unlinkSync)((0, import_node_path31.resolve)(o.appDir ?? process.cwd(), path2))
|
|
36875
37122
|
},
|
|
36876
37123
|
{
|
|
36877
37124
|
repo: o.repo,
|
|
@@ -37034,8 +37281,8 @@ function registerSessionReport(program3) {
|
|
|
37034
37281
|
}
|
|
37035
37282
|
|
|
37036
37283
|
// src/stage-commands.ts
|
|
37037
|
-
var
|
|
37038
|
-
var
|
|
37284
|
+
var import_node_fs34 = require("node:fs");
|
|
37285
|
+
var import_node_path32 = require("node:path");
|
|
37039
37286
|
init_cli_shared();
|
|
37040
37287
|
init_clean_exit();
|
|
37041
37288
|
|
|
@@ -37281,8 +37528,8 @@ function registerStageCommands(program3) {
|
|
|
37281
37528
|
return {
|
|
37282
37529
|
resolution: decideStage({
|
|
37283
37530
|
registry: { deployModel: project2?.deployModel, portRange, error: read.ok ? void 0 : read.error },
|
|
37284
|
-
hasCompose: (0,
|
|
37285
|
-
hasEnvExample: (0,
|
|
37531
|
+
hasCompose: (0, import_node_fs34.existsSync)((0, import_node_path32.join)(process.cwd(), "docker-compose.yml")),
|
|
37532
|
+
hasEnvExample: (0, import_node_fs34.existsSync)((0, import_node_path32.join)(process.cwd(), ".env.example")),
|
|
37286
37533
|
repo
|
|
37287
37534
|
}),
|
|
37288
37535
|
project: project2,
|
|
@@ -37566,19 +37813,19 @@ vercel preview (${preview.branch}): ${d.state}${d.url ? ` \u2014 ${d.url}` : ""}
|
|
|
37566
37813
|
|
|
37567
37814
|
// src/tenant-artifact.ts
|
|
37568
37815
|
var import_node_crypto11 = require("node:crypto");
|
|
37569
|
-
var
|
|
37816
|
+
var import_node_fs35 = require("node:fs");
|
|
37570
37817
|
var import_promises6 = require("node:fs/promises");
|
|
37571
|
-
var
|
|
37818
|
+
var import_node_path33 = require("node:path");
|
|
37572
37819
|
var ARTIFACT_ID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
|
|
37573
37820
|
var MAX_BYTES = 5 * 1024 * 1024 * 1024;
|
|
37574
37821
|
async function sha256File(path2) {
|
|
37575
37822
|
const hash = (0, import_node_crypto11.createHash)("sha256");
|
|
37576
|
-
for await (const chunk of (0,
|
|
37823
|
+
for await (const chunk of (0, import_node_fs35.createReadStream)(path2)) hash.update(chunk);
|
|
37577
37824
|
return hash.digest("hex");
|
|
37578
37825
|
}
|
|
37579
37826
|
async function putTenantArtifact(repo, stage, inputPath, deps) {
|
|
37580
37827
|
if (!["dev", "rc", "main"].includes(stage)) throw new Error("tenant artifact put: <stage> must be dev, rc, or main");
|
|
37581
|
-
const path2 = (0,
|
|
37828
|
+
const path2 = (0, import_node_path33.resolve)(inputPath);
|
|
37582
37829
|
const info = await (0, import_promises6.stat)(path2);
|
|
37583
37830
|
if (!info.isFile()) throw new Error("tenant artifact put: input path must be a file");
|
|
37584
37831
|
if (!Number.isSafeInteger(info.size) || info.size < 1 || info.size > MAX_BYTES) throw new Error(`tenant artifact put: file must be 1..${MAX_BYTES} bytes`);
|
|
@@ -37596,7 +37843,7 @@ async function putTenantArtifact(repo, stage, inputPath, deps) {
|
|
|
37596
37843
|
return [key, value];
|
|
37597
37844
|
}));
|
|
37598
37845
|
headers["content-length"] = String(info.size);
|
|
37599
|
-
const stream = (0,
|
|
37846
|
+
const stream = (0, import_node_fs35.createReadStream)(path2);
|
|
37600
37847
|
let uploaded;
|
|
37601
37848
|
try {
|
|
37602
37849
|
uploaded = await fetch(body.uploadUrl, {
|
|
@@ -37736,7 +37983,7 @@ function renderVerifySecrets(body) {
|
|
|
37736
37983
|
|
|
37737
37984
|
// src/command-register-collaboration.ts
|
|
37738
37985
|
var import_node_child_process15 = require("node:child_process");
|
|
37739
|
-
var
|
|
37986
|
+
var import_node_fs42 = require("node:fs");
|
|
37740
37987
|
var import_promises7 = require("node:fs/promises");
|
|
37741
37988
|
init_clean_exit();
|
|
37742
37989
|
init_cli_shared();
|
|
@@ -37760,7 +38007,7 @@ function spawnDetachedSelf(args, deps, opts = {}) {
|
|
|
37760
38007
|
}
|
|
37761
38008
|
|
|
37762
38009
|
// src/command-register-collaboration.ts
|
|
37763
|
-
var
|
|
38010
|
+
var import_node_path40 = require("node:path");
|
|
37764
38011
|
|
|
37765
38012
|
// src/attach-to-project.ts
|
|
37766
38013
|
async function attachViaHubApp(cfg, contentNodeId) {
|
|
@@ -37851,6 +38098,9 @@ function prHeadBehindBase(input) {
|
|
|
37851
38098
|
function prHeadUpdateRemedy(head, base) {
|
|
37852
38099
|
return `git fetch origin ${base} && git merge origin/${base} (on ${head}), resolve the conflicts, push, then rerun \u2014 docs/Guides/train-troubleshooting.md#head-behind-base`;
|
|
37853
38100
|
}
|
|
38101
|
+
function prLandedBranchFinality(prNumber, base) {
|
|
38102
|
+
return `PR #${prNumber} is merged, and that is final \u2014 stopping a local waiter or monitor does not unmerge it. The head branch is now landed; further commits pushed to it reach nothing. If more work is needed, run \`git fetch origin ${base} && git switch -c <new-branch> origin/${base}\`, then cherry-pick anything already committed \u2014 docs/Guides/train-troubleshooting.md#merged-pr-head-reuse`;
|
|
38103
|
+
}
|
|
37854
38104
|
var PROTECTED_PR_HEAD_BRANCHES = ["main", "master", "development", "rc"];
|
|
37855
38105
|
function isProtectedPrHead(head) {
|
|
37856
38106
|
return PROTECTED_PR_HEAD_BRANCHES.includes(head);
|
|
@@ -37946,8 +38196,9 @@ async function readGhPrStateWithRetry(fetchState, options) {
|
|
|
37946
38196
|
return { ok: false, error: lastError };
|
|
37947
38197
|
}
|
|
37948
38198
|
async function runPrLand(prNumber, options, deps) {
|
|
37949
|
-
const
|
|
37950
|
-
const
|
|
38199
|
+
const resolved = await deps.resolveRepo(prNumber, options.repo);
|
|
38200
|
+
const { repo } = resolved;
|
|
38201
|
+
const base = { status: "failed", repo, pr: prNumber, base: resolved.base };
|
|
37951
38202
|
if (options.requireTrain !== false) {
|
|
37952
38203
|
const verdict = await deps.fetchTrainAuthority(repo);
|
|
37953
38204
|
if (!verdict.ok) {
|
|
@@ -37999,12 +38250,21 @@ async function runPrLand(prNumber, options, deps) {
|
|
|
37999
38250
|
return { ...base, error: merge.error ?? "merge failed" };
|
|
38000
38251
|
}
|
|
38001
38252
|
if (merge.mergeStatus === "merged") {
|
|
38002
|
-
return {
|
|
38253
|
+
return {
|
|
38254
|
+
...base,
|
|
38255
|
+
status: "merged",
|
|
38256
|
+
branchFinality: prLandedBranchFinality(prNumber, resolved.base)
|
|
38257
|
+
};
|
|
38003
38258
|
}
|
|
38004
38259
|
const now = deps.now ?? (() => Date.now());
|
|
38005
38260
|
const merged = await deps.pollMerged(prNumber, repo, now() + PR_LAND_ENQUEUE_TIMEOUT_MS);
|
|
38006
38261
|
if (merged) {
|
|
38007
|
-
return {
|
|
38262
|
+
return {
|
|
38263
|
+
...base,
|
|
38264
|
+
status: "auto-merge-enqueued-then-merged",
|
|
38265
|
+
mergeStatus: "merged",
|
|
38266
|
+
branchFinality: prLandedBranchFinality(prNumber, resolved.base)
|
|
38267
|
+
};
|
|
38008
38268
|
}
|
|
38009
38269
|
return {
|
|
38010
38270
|
...base,
|
|
@@ -38016,8 +38276,8 @@ async function runPrLand(prNumber, options, deps) {
|
|
|
38016
38276
|
init_github_client();
|
|
38017
38277
|
|
|
38018
38278
|
// src/merge-cleanup.ts
|
|
38019
|
-
var
|
|
38020
|
-
var
|
|
38279
|
+
var import_node_fs37 = require("node:fs");
|
|
38280
|
+
var import_node_path35 = require("node:path");
|
|
38021
38281
|
var import_node_os18 = require("node:os");
|
|
38022
38282
|
init_cli_shared();
|
|
38023
38283
|
init_github_client();
|
|
@@ -38126,8 +38386,8 @@ function boardAdvanceFailureMessage(result) {
|
|
|
38126
38386
|
|
|
38127
38387
|
// src/test-policy-core.ts
|
|
38128
38388
|
var import_node_child_process12 = require("node:child_process");
|
|
38129
|
-
var
|
|
38130
|
-
var
|
|
38389
|
+
var import_node_fs36 = require("node:fs");
|
|
38390
|
+
var import_node_path34 = require("node:path");
|
|
38131
38391
|
|
|
38132
38392
|
// src/test-command-policy-shared.mjs
|
|
38133
38393
|
var import_node_child_process11 = require("node:child_process");
|
|
@@ -38603,7 +38863,7 @@ function isMeaningfulRow(file) {
|
|
|
38603
38863
|
return file.meaningful !== false;
|
|
38604
38864
|
}
|
|
38605
38865
|
function loadPolicy(root, readFile9 = readFileOrNull2) {
|
|
38606
|
-
const raw = readFile9((0,
|
|
38866
|
+
const raw = readFile9((0, import_node_path34.join)(root, POLICY_FILE));
|
|
38607
38867
|
if (raw == null) return { mandatory: [], declared: false };
|
|
38608
38868
|
return parsePolicy(raw, POLICY_FILE);
|
|
38609
38869
|
}
|
|
@@ -38680,7 +38940,7 @@ function loadPolicySource(root, explicitRef, diffBase) {
|
|
|
38680
38940
|
}
|
|
38681
38941
|
function readFileOrNull2(path2) {
|
|
38682
38942
|
try {
|
|
38683
|
-
return (0,
|
|
38943
|
+
return (0, import_node_fs36.readFileSync)(path2, "utf8");
|
|
38684
38944
|
} catch {
|
|
38685
38945
|
return null;
|
|
38686
38946
|
}
|
|
@@ -38708,12 +38968,12 @@ function classify(changed, policy, present = () => false) {
|
|
|
38708
38968
|
const removedProtected = [...removed].filter((p) => protectedBy.has(p)).map((p) => ({ path: p, why: protectedBy.get(p) ?? "" }));
|
|
38709
38969
|
return { mandatoryHits, untestedHits, testChanges, meaningfulTestChanges, addedTests, removedProtected };
|
|
38710
38970
|
}
|
|
38711
|
-
function unresolvedProtectedEntries(policy, root, exists = (path2) => (0,
|
|
38712
|
-
return (policy.protected ?? []).map((p) => p.path).filter((p) => !exists((0,
|
|
38971
|
+
function unresolvedProtectedEntries(policy, root, exists = (path2) => (0, import_node_fs36.existsSync)(path2)) {
|
|
38972
|
+
return (policy.protected ?? []).map((p) => p.path).filter((p) => !exists((0, import_node_path34.join)(root, p)));
|
|
38713
38973
|
}
|
|
38714
|
-
function unresolvedSatisfiers(policy, root, exists = (path2) => (0,
|
|
38974
|
+
function unresolvedSatisfiers(policy, root, exists = (path2) => (0, import_node_fs36.existsSync)(path2)) {
|
|
38715
38975
|
const declared = (policy.mandatory ?? []).flatMap((m) => m.satisfiedBy ?? []);
|
|
38716
|
-
return [...new Set(declared)].filter((p) => !exists((0,
|
|
38976
|
+
return [...new Set(declared)].filter((p) => !exists((0, import_node_path34.join)(root, p)));
|
|
38717
38977
|
}
|
|
38718
38978
|
function evaluate(changed, policy, present = () => false) {
|
|
38719
38979
|
const { mandatoryHits, untestedHits, meaningfulTestChanges, addedTests, removedProtected } = classify(changed, policy, present);
|
|
@@ -38852,14 +39112,14 @@ function runTestPolicy(root, deps = {}) {
|
|
|
38852
39112
|
}
|
|
38853
39113
|
const loaded = deps.policy ? { policy: deps.policy, source: { ref: null, sha: null, path: POLICY_FILE } } : loadPolicySource(root, deps.policyRef, deps.base);
|
|
38854
39114
|
const { policy, source: policySource } = loaded;
|
|
38855
|
-
const exists = deps.exists ?? ((path2) => (0,
|
|
39115
|
+
const exists = deps.exists ?? ((path2) => (0, import_node_fs36.existsSync)(path2));
|
|
38856
39116
|
const counts = { mandatoryCount: (policy.mandatory ?? []).length, protectedCount: (policy.protected ?? []).length };
|
|
38857
39117
|
const base = deps.changed ? "(injected)" : deps.policyRef ? resolveHotfixBase(root) : resolveBase(root, deps.base);
|
|
38858
39118
|
const refusal = deps.changed ? null : untrustworthyRange(root, base);
|
|
38859
39119
|
const raw = deps.changed ?? (refusal ? [] : changedFilesSince(base, root));
|
|
38860
39120
|
const changed = deps.changed ? raw : annotateChangeMeaning(raw, policy, (path2) => ({
|
|
38861
39121
|
before: blobAt(base, path2, root),
|
|
38862
|
-
after: readFileOrNull2((0,
|
|
39122
|
+
after: readFileOrNull2((0, import_node_path34.join)(root, path2))
|
|
38863
39123
|
}));
|
|
38864
39124
|
const lookup = deps.override !== void 0 ? { override: deps.override, refusals: [] } : !deps.changed && !refusal ? readOverride2(base, root) : { override: null, refusals: [] };
|
|
38865
39125
|
const policyRefusals = policy.declared === false ? [{
|
|
@@ -38869,8 +39129,8 @@ function runTestPolicy(root, deps = {}) {
|
|
|
38869
39129
|
A gate with no policy cannot decide which test commands are required or permitted.
|
|
38870
39130
|
` + (deps.base === HOTFIX_DIFF_BASE ? ` Hotfix lane (--base ${HOTFIX_DIFF_BASE}): pass --policy-ref <exact-${HOTFIX_POLICY_REF}-commit> so the current policy is read from ${HOTFIX_POLICY_REF}.` : ` Restore ${POLICY_FILE} on this branch; the policy file belongs on every non-hotfix lane.`)
|
|
38871
39131
|
}] : [];
|
|
38872
|
-
const present = (path2) => exists((0,
|
|
38873
|
-
const policyTree = policySource.sha ? new Set(git2(["ls-tree", "-r", "-z", "--name-only", policySource.sha], root).split("\0").filter(Boolean).map((p) => (0,
|
|
39132
|
+
const present = (path2) => exists((0, import_node_path34.join)(root, path2));
|
|
39133
|
+
const policyTree = policySource.sha ? new Set(git2(["ls-tree", "-r", "-z", "--name-only", policySource.sha], root).split("\0").filter(Boolean).map((p) => (0, import_node_path34.join)(root, p))) : null;
|
|
38874
39134
|
const policyTreeExists = policyTree ? (abs) => policyTree.has(abs) : exists;
|
|
38875
39135
|
const where = policySource.sha ? `${policySource.ref}@${policySource.sha}` : "this worktree";
|
|
38876
39136
|
const removedByThisDiff = removedPaths(changed);
|
|
@@ -39088,13 +39348,13 @@ function resolveSquashMergeBodyText(commits, allowedClosing, cwd) {
|
|
|
39088
39348
|
return rewritten === base ? null : rewritten;
|
|
39089
39349
|
}
|
|
39090
39350
|
function writeSquashBodyFile(body) {
|
|
39091
|
-
const dir = (0,
|
|
39092
|
-
const path2 = (0,
|
|
39093
|
-
(0,
|
|
39351
|
+
const dir = (0, import_node_fs37.mkdtempSync)((0, import_node_path35.join)((0, import_node_os18.tmpdir)(), "mmi-squash-body-"));
|
|
39352
|
+
const path2 = (0, import_node_path35.join)(dir, "body.txt");
|
|
39353
|
+
(0, import_node_fs37.writeFileSync)(path2, body.endsWith("\n") ? body : `${body}
|
|
39094
39354
|
`, "utf8");
|
|
39095
39355
|
return { path: path2, cleanup: () => {
|
|
39096
39356
|
try {
|
|
39097
|
-
(0,
|
|
39357
|
+
(0, import_node_fs37.rmSync)(dir, { recursive: true, force: true });
|
|
39098
39358
|
} catch {
|
|
39099
39359
|
}
|
|
39100
39360
|
} };
|
|
@@ -39301,8 +39561,8 @@ async function deleteMergedRemoteBranch(options) {
|
|
|
39301
39561
|
}
|
|
39302
39562
|
|
|
39303
39563
|
// src/post-merge-recon.ts
|
|
39304
|
-
var
|
|
39305
|
-
var
|
|
39564
|
+
var import_node_fs38 = require("node:fs");
|
|
39565
|
+
var import_node_path36 = require("node:path");
|
|
39306
39566
|
|
|
39307
39567
|
// src/cross-repo-filing-issue.ts
|
|
39308
39568
|
init_github_client();
|
|
@@ -39469,16 +39729,16 @@ function buildPostMergeReconRecovery(input) {
|
|
|
39469
39729
|
}
|
|
39470
39730
|
function writePostMergeReconRecovery(cwd, recovery) {
|
|
39471
39731
|
const path2 = postMergeReconStatePath(cwd, recovery.repo, recovery.pr);
|
|
39472
|
-
(0,
|
|
39473
|
-
(0,
|
|
39732
|
+
(0, import_node_fs38.mkdirSync)((0, import_node_path36.dirname)(path2), { recursive: true });
|
|
39733
|
+
(0, import_node_fs38.writeFileSync)(path2, `${JSON.stringify(recovery, null, 2)}
|
|
39474
39734
|
`, "utf8");
|
|
39475
39735
|
return path2;
|
|
39476
39736
|
}
|
|
39477
39737
|
function clearPostMergeReconRecovery(cwd, repo, pr) {
|
|
39478
39738
|
const path2 = postMergeReconStatePath(cwd, repo, pr);
|
|
39479
|
-
if (!(0,
|
|
39739
|
+
if (!(0, import_node_fs38.existsSync)(path2)) return;
|
|
39480
39740
|
try {
|
|
39481
|
-
(0,
|
|
39741
|
+
(0, import_node_fs38.unlinkSync)(path2);
|
|
39482
39742
|
} catch {
|
|
39483
39743
|
}
|
|
39484
39744
|
}
|
|
@@ -39510,9 +39770,9 @@ function postMergeReconWarnings(input) {
|
|
|
39510
39770
|
|
|
39511
39771
|
// src/review-verdict.ts
|
|
39512
39772
|
var import_node_child_process13 = require("node:child_process");
|
|
39513
|
-
var
|
|
39773
|
+
var import_node_fs39 = require("node:fs");
|
|
39514
39774
|
var import_node_os19 = require("node:os");
|
|
39515
|
-
var
|
|
39775
|
+
var import_node_path37 = require("node:path");
|
|
39516
39776
|
init_cli_shared();
|
|
39517
39777
|
var REVIEW_VERDICT_MARKER = "<!-- zeroci-review v1 -->";
|
|
39518
39778
|
var REVIEW_VERDICTS = ["PROCEED", "CORRECT", "ESCALATE"];
|
|
@@ -39677,15 +39937,15 @@ async function readPrIssueComments(number, repo) {
|
|
|
39677
39937
|
return comments;
|
|
39678
39938
|
}
|
|
39679
39939
|
async function postPrCommentFromFile(number, repo, body) {
|
|
39680
|
-
const dir = (0,
|
|
39681
|
-
const path2 = (0,
|
|
39940
|
+
const dir = (0, import_node_fs39.mkdtempSync)((0, import_node_path37.join)((0, import_node_os19.tmpdir)(), "mmi-review-verdict-"));
|
|
39941
|
+
const path2 = (0, import_node_path37.join)(dir, "body.md");
|
|
39682
39942
|
try {
|
|
39683
|
-
(0,
|
|
39943
|
+
(0, import_node_fs39.writeFileSync)(path2, body, "utf8");
|
|
39684
39944
|
const { stdout } = await execFileP("gh", ["pr", "comment", number, "--repo", repo, "--body-file", path2], { timeout: GH_MUTATION_TIMEOUT_MS });
|
|
39685
39945
|
return stdout.trim();
|
|
39686
39946
|
} finally {
|
|
39687
39947
|
try {
|
|
39688
|
-
(0,
|
|
39948
|
+
(0, import_node_fs39.rmSync)(dir, { recursive: true, force: true });
|
|
39689
39949
|
} catch {
|
|
39690
39950
|
}
|
|
39691
39951
|
}
|
|
@@ -39839,6 +40099,32 @@ function withRateLimitRetry(client, seams = {}) {
|
|
|
39839
40099
|
throttledPaths
|
|
39840
40100
|
};
|
|
39841
40101
|
}
|
|
40102
|
+
async function prCreateMergedHeadWarning(input, deps = {}) {
|
|
40103
|
+
const guide = "docs/Guides/train-troubleshooting.md#merged-pr-head-reuse";
|
|
40104
|
+
if (!input.head) {
|
|
40105
|
+
return `pr create: WARNING \u2014 could not check whether the current head branch already landed (the current branch could not be resolved); continuing with PR creation \u2014 ${guide}`;
|
|
40106
|
+
}
|
|
40107
|
+
try {
|
|
40108
|
+
const repo = await requireRepo(input.repo);
|
|
40109
|
+
const owner = repo.split("/")[0];
|
|
40110
|
+
if (!owner) throw new Error(`invalid repository '${repo}'`);
|
|
40111
|
+
const qualifiedHead = input.head.includes(":") ? input.head : `${owner}:${input.head}`;
|
|
40112
|
+
const query = new URLSearchParams({ state: "closed", head: qualifiedHead, sort: "updated", direction: "desc" });
|
|
40113
|
+
const pulls = await (deps.client ?? defaultGitHubClient()).restPaginate(
|
|
40114
|
+
`repos/${repo}/pulls?${query.toString()}`
|
|
40115
|
+
);
|
|
40116
|
+
const merged = pulls.find((pull) => typeof pull.merged_at === "string" && pull.merged_at.length > 0);
|
|
40117
|
+
if (!merged) return void 0;
|
|
40118
|
+
if (typeof merged.number !== "number" || typeof merged.base?.ref !== "string" || !merged.base.ref) {
|
|
40119
|
+
throw new Error("GitHub returned a merged PR without its number or base branch");
|
|
40120
|
+
}
|
|
40121
|
+
const base = merged.base.ref;
|
|
40122
|
+
return `pr create: WARNING \u2014 head branch '${input.head}' already landed in merged PR #${merged.number}. If you meant to continue that landed work, cut a fresh branch from origin/${base}: \`git fetch origin ${base} && git switch -c <new-branch> origin/${base}\`, then cherry-pick anything already committed. Creating another PR from a deliberately reused branch name remains allowed \u2014 ${guide}`;
|
|
40123
|
+
} catch (e) {
|
|
40124
|
+
const detail = String(e.message || e).replace(/\s+/g, " ").slice(0, 240);
|
|
40125
|
+
return `pr create: WARNING \u2014 could not check whether head branch '${input.head}' already landed (${detail}); continuing with PR creation \u2014 ${guide}`;
|
|
40126
|
+
}
|
|
40127
|
+
}
|
|
39842
40128
|
async function prCreateClaimRefusal(body, repoOption, deps = {}) {
|
|
39843
40129
|
const issues = [...new Set(findClosingMentions(body).map((mention) => mention.issue))];
|
|
39844
40130
|
if (!issues.length) return void 0;
|
|
@@ -39871,13 +40157,13 @@ async function prCreateClaimRefusal(body, repoOption, deps = {}) {
|
|
|
39871
40157
|
}
|
|
39872
40158
|
|
|
39873
40159
|
// src/worktree-merge-cleanup.ts
|
|
39874
|
-
var
|
|
39875
|
-
var
|
|
40160
|
+
var import_node_fs41 = require("node:fs");
|
|
40161
|
+
var import_node_path39 = require("node:path");
|
|
39876
40162
|
init_cli_shared();
|
|
39877
40163
|
|
|
39878
40164
|
// src/worktree-evidence-archive.ts
|
|
39879
|
-
var
|
|
39880
|
-
var
|
|
40165
|
+
var import_node_fs40 = require("node:fs");
|
|
40166
|
+
var import_node_path38 = require("node:path");
|
|
39881
40167
|
var JERV_ARTIFACT_RUN_SCOPE_ENV_VARS = ["JERV_RUN_ID", ...SESSION_ID_ENV_VARS];
|
|
39882
40168
|
function sanitizeArchiveSegment(value, max = 80) {
|
|
39883
40169
|
const scrubbed = value.replace(/[^A-Za-z0-9._@+-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
@@ -39892,24 +40178,24 @@ function resolveArtifactRunScope(env = process.env) {
|
|
|
39892
40178
|
}
|
|
39893
40179
|
function defaultIsDirectory(path2) {
|
|
39894
40180
|
try {
|
|
39895
|
-
return (0,
|
|
40181
|
+
return (0, import_node_fs40.lstatSync)(path2).isDirectory();
|
|
39896
40182
|
} catch {
|
|
39897
40183
|
return false;
|
|
39898
40184
|
}
|
|
39899
40185
|
}
|
|
39900
40186
|
function archiveWorktreeJervArtifacts(args, deps = {}) {
|
|
39901
|
-
const exists = deps.exists ??
|
|
40187
|
+
const exists = deps.exists ?? import_node_fs40.existsSync;
|
|
39902
40188
|
const isDirectory = deps.isDirectory ?? defaultIsDirectory;
|
|
39903
|
-
const copyDir = deps.copyDir ?? ((from, to) => (0,
|
|
40189
|
+
const copyDir = deps.copyDir ?? ((from, to) => (0, import_node_fs40.cpSync)(from, to, { recursive: true, force: true }));
|
|
39904
40190
|
const mkdirp = deps.mkdirp ?? ((path2) => {
|
|
39905
|
-
(0,
|
|
40191
|
+
(0, import_node_fs40.mkdirSync)(path2, { recursive: true });
|
|
39906
40192
|
});
|
|
39907
40193
|
const env = deps.env ?? process.env;
|
|
39908
40194
|
const now = deps.now ?? (() => /* @__PURE__ */ new Date());
|
|
39909
40195
|
const resolveRoot = deps.resolveArchiveRoot ?? repoRuntimeStatePath;
|
|
39910
40196
|
if (!args.primaryRoot?.trim()) return { status: "skipped", reason: "missing-primary-root" };
|
|
39911
40197
|
if (!args.worktreePath?.trim()) return { status: "skipped", reason: "missing-worktree-path" };
|
|
39912
|
-
const source = (0,
|
|
40198
|
+
const source = (0, import_node_path38.join)(args.worktreePath, ".jerv");
|
|
39913
40199
|
if (!exists(source)) return { status: "absent" };
|
|
39914
40200
|
if (!isDirectory(source)) return { status: "skipped", reason: "jerv-not-a-directory" };
|
|
39915
40201
|
const runScope = resolveArtifactRunScope(env);
|
|
@@ -39917,7 +40203,7 @@ function archiveWorktreeJervArtifacts(args, deps = {}) {
|
|
|
39917
40203
|
const stamp = now().toISOString().replace(/[:.]/g, "-");
|
|
39918
40204
|
const dest = resolveRoot(args.primaryRoot, "jerv-artifacts", runScope, branchSlug, stamp, ".jerv");
|
|
39919
40205
|
try {
|
|
39920
|
-
mkdirp((0,
|
|
40206
|
+
mkdirp((0, import_node_path38.dirname)(dest));
|
|
39921
40207
|
copyDir(source, dest);
|
|
39922
40208
|
if (!exists(dest)) return { status: "failed", error: `archive write left no directory at ${dest}` };
|
|
39923
40209
|
return { status: "archived", path: dest, runScope };
|
|
@@ -39926,14 +40212,14 @@ function archiveWorktreeJervArtifacts(args, deps = {}) {
|
|
|
39926
40212
|
}
|
|
39927
40213
|
}
|
|
39928
40214
|
function defaultStat(path2) {
|
|
39929
|
-
const st = (0,
|
|
40215
|
+
const st = (0, import_node_fs40.statSync)(path2);
|
|
39930
40216
|
return { mtimeMs: st.mtimeMs, size: st.size, isDirectory: () => st.isDirectory() };
|
|
39931
40217
|
}
|
|
39932
40218
|
function scanWorktreeTmpEvidence(worktreePath, newerThanMs, deps = {}) {
|
|
39933
|
-
const exists = deps.exists ??
|
|
40219
|
+
const exists = deps.exists ?? import_node_fs40.existsSync;
|
|
39934
40220
|
const stat4 = deps.stat ?? defaultStat;
|
|
39935
|
-
const readdir2 = deps.readdir ??
|
|
39936
|
-
const tmpRoot = (0,
|
|
40221
|
+
const readdir2 = deps.readdir ?? import_node_fs40.readdirSync;
|
|
40222
|
+
const tmpRoot = (0, import_node_path38.join)(worktreePath, "tmp");
|
|
39937
40223
|
if (!exists(tmpRoot)) return [];
|
|
39938
40224
|
const entries = [];
|
|
39939
40225
|
const walk2 = (dir) => {
|
|
@@ -39944,14 +40230,14 @@ function scanWorktreeTmpEvidence(worktreePath, newerThanMs, deps = {}) {
|
|
|
39944
40230
|
return;
|
|
39945
40231
|
}
|
|
39946
40232
|
for (const name of names) {
|
|
39947
|
-
const full = (0,
|
|
40233
|
+
const full = (0, import_node_path38.join)(dir, name);
|
|
39948
40234
|
let st;
|
|
39949
40235
|
try {
|
|
39950
40236
|
st = stat4(full);
|
|
39951
40237
|
} catch {
|
|
39952
40238
|
continue;
|
|
39953
40239
|
}
|
|
39954
|
-
const relPath = (0,
|
|
40240
|
+
const relPath = (0, import_node_path38.relative)(worktreePath, full).replace(/\\/g, "/");
|
|
39955
40241
|
if (st.isDirectory()) {
|
|
39956
40242
|
if (st.mtimeMs > newerThanMs) entries.push({ relPath, bytes: 0, mtimeMs: st.mtimeMs });
|
|
39957
40243
|
walk2(full);
|
|
@@ -39965,10 +40251,10 @@ function scanWorktreeTmpEvidence(worktreePath, newerThanMs, deps = {}) {
|
|
|
39965
40251
|
return entries;
|
|
39966
40252
|
}
|
|
39967
40253
|
function archiveWorktreeTmpArtifacts(args, deps = {}) {
|
|
39968
|
-
const exists = deps.exists ??
|
|
39969
|
-
const copyDir = deps.copyDir ?? ((from, to) => (0,
|
|
40254
|
+
const exists = deps.exists ?? import_node_fs40.existsSync;
|
|
40255
|
+
const copyDir = deps.copyDir ?? ((from, to) => (0, import_node_fs40.cpSync)(from, to, { recursive: true, force: true }));
|
|
39970
40256
|
const mkdirp = deps.mkdirp ?? ((path2) => {
|
|
39971
|
-
(0,
|
|
40257
|
+
(0, import_node_fs40.mkdirSync)(path2, { recursive: true });
|
|
39972
40258
|
});
|
|
39973
40259
|
const env = deps.env ?? process.env;
|
|
39974
40260
|
const now = deps.now ?? (() => /* @__PURE__ */ new Date());
|
|
@@ -39976,7 +40262,7 @@ function archiveWorktreeTmpArtifacts(args, deps = {}) {
|
|
|
39976
40262
|
if (!args.primaryRoot?.trim()) return { status: "skipped", reason: "missing-primary-root" };
|
|
39977
40263
|
if (!args.worktreePath?.trim()) return { status: "skipped", reason: "missing-worktree-path" };
|
|
39978
40264
|
const scanned = scanWorktreeTmpEvidence(args.worktreePath, args.newerThanMs, deps);
|
|
39979
|
-
const source = (0,
|
|
40265
|
+
const source = (0, import_node_path38.join)(args.worktreePath, "tmp");
|
|
39980
40266
|
if (!scanned.length) return { status: "absent" };
|
|
39981
40267
|
if (!exists(source)) return { status: "absent" };
|
|
39982
40268
|
const runScope = resolveArtifactRunScope(env);
|
|
@@ -39984,7 +40270,7 @@ function archiveWorktreeTmpArtifacts(args, deps = {}) {
|
|
|
39984
40270
|
const stamp = now().toISOString().replace(/[:.]/g, "-");
|
|
39985
40271
|
const dest = resolveRoot(args.primaryRoot, "worktree-artifacts", runScope, branchSlug, stamp, "tmp");
|
|
39986
40272
|
try {
|
|
39987
|
-
mkdirp((0,
|
|
40273
|
+
mkdirp((0, import_node_path38.dirname)(dest));
|
|
39988
40274
|
copyDir(source, dest);
|
|
39989
40275
|
if (!exists(dest)) return { status: "failed", error: `archive write left no directory at ${dest}` };
|
|
39990
40276
|
const bytes = scanned.reduce((sum, e) => sum + e.bytes, 0);
|
|
@@ -40053,9 +40339,9 @@ function normPath2(p) {
|
|
|
40053
40339
|
return p.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
40054
40340
|
}
|
|
40055
40341
|
function unlinkNodeModulesJunction(wtPath) {
|
|
40056
|
-
const nm = (0,
|
|
40342
|
+
const nm = (0, import_node_path39.join)(wtPath, "node_modules");
|
|
40057
40343
|
try {
|
|
40058
|
-
if ((0,
|
|
40344
|
+
if ((0, import_node_fs41.lstatSync)(nm).isSymbolicLink()) (0, import_node_fs41.rmdirSync)(nm);
|
|
40059
40345
|
return { ok: true };
|
|
40060
40346
|
} catch (e) {
|
|
40061
40347
|
if (e.code === "ENOENT") return { ok: true };
|
|
@@ -40066,8 +40352,8 @@ function defaultSleep2(ms) {
|
|
|
40066
40352
|
return new Promise((resolve7) => setTimeout(resolve7, ms));
|
|
40067
40353
|
}
|
|
40068
40354
|
async function removeResidueDirectory(wtPath, options = {}) {
|
|
40069
|
-
const { sleep: sleep2 = defaultSleep2, removeEmptyDir =
|
|
40070
|
-
const removeRecursive = options.removeRecursive ?? ((path2) => (0,
|
|
40355
|
+
const { sleep: sleep2 = defaultSleep2, removeEmptyDir = import_node_fs41.rmdirSync, exists = import_node_fs41.existsSync } = options;
|
|
40356
|
+
const removeRecursive = options.removeRecursive ?? ((path2) => (0, import_node_fs41.rmSync)(path2, { recursive: true, force: true, maxRetries: 10, retryDelay: 100 }));
|
|
40071
40357
|
const junction = unlinkNodeModulesJunction(wtPath);
|
|
40072
40358
|
if (!junction.ok) return junction;
|
|
40073
40359
|
try {
|
|
@@ -40190,28 +40476,28 @@ async function preCleanWorktreeForRemoval(wtPath, execGit) {
|
|
|
40190
40476
|
}
|
|
40191
40477
|
async function listNestedIgnoredNodeModules(wtPath, execGit) {
|
|
40192
40478
|
const out = await execGit(["-C", wtPath, "ls-files", "--others", "--ignored", "--exclude-standard", "--directory"]).catch(() => "");
|
|
40193
|
-
return out.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.endsWith("node_modules/") && line !== "node_modules/").map((line) => (0,
|
|
40479
|
+
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)));
|
|
40194
40480
|
}
|
|
40195
40481
|
function safeRemoveTree(path2) {
|
|
40196
|
-
const stat4 = (0,
|
|
40482
|
+
const stat4 = (0, import_node_fs41.lstatSync)(path2);
|
|
40197
40483
|
if (stat4.isSymbolicLink()) {
|
|
40198
40484
|
try {
|
|
40199
|
-
(0,
|
|
40485
|
+
(0, import_node_fs41.rmdirSync)(path2);
|
|
40200
40486
|
} catch {
|
|
40201
|
-
(0,
|
|
40487
|
+
(0, import_node_fs41.unlinkSync)(path2);
|
|
40202
40488
|
}
|
|
40203
40489
|
return;
|
|
40204
40490
|
}
|
|
40205
40491
|
if (stat4.isDirectory()) {
|
|
40206
|
-
for (const entry of (0,
|
|
40207
|
-
(0,
|
|
40492
|
+
for (const entry of (0, import_node_fs41.readdirSync)(path2)) safeRemoveTree((0, import_node_path39.join)(path2, entry));
|
|
40493
|
+
(0, import_node_fs41.rmdirSync)(path2);
|
|
40208
40494
|
return;
|
|
40209
40495
|
}
|
|
40210
|
-
(0,
|
|
40496
|
+
(0, import_node_fs41.unlinkSync)(path2);
|
|
40211
40497
|
}
|
|
40212
40498
|
async function removeWorktreeNodeModules(wtPath) {
|
|
40213
40499
|
try {
|
|
40214
|
-
safeRemoveTree((0,
|
|
40500
|
+
safeRemoveTree((0, import_node_path39.join)(wtPath, "node_modules"));
|
|
40215
40501
|
return { ok: true };
|
|
40216
40502
|
} catch (e) {
|
|
40217
40503
|
if (e.code === "ENOENT") return { ok: true };
|
|
@@ -40223,7 +40509,7 @@ function errorMessage(e) {
|
|
|
40223
40509
|
}
|
|
40224
40510
|
function resolvedOrRaw(path2) {
|
|
40225
40511
|
try {
|
|
40226
|
-
return normPath2((0,
|
|
40512
|
+
return normPath2((0, import_node_fs41.realpathSync)(path2));
|
|
40227
40513
|
} catch {
|
|
40228
40514
|
return normPath2(path2);
|
|
40229
40515
|
}
|
|
@@ -40231,10 +40517,10 @@ function resolvedOrRaw(path2) {
|
|
|
40231
40517
|
function unlinkEscapingReparsePoints(root, primaryRoot) {
|
|
40232
40518
|
let realRoot;
|
|
40233
40519
|
try {
|
|
40234
|
-
if ((0,
|
|
40520
|
+
if ((0, import_node_fs41.lstatSync)(root).isSymbolicLink()) {
|
|
40235
40521
|
return { ok: false, error: `delete root ${normPath2(root)} is a reparse point resolving to ${resolvedOrRaw(root)}` };
|
|
40236
40522
|
}
|
|
40237
|
-
realRoot = normPath2((0,
|
|
40523
|
+
realRoot = normPath2((0, import_node_fs41.realpathSync)(root));
|
|
40238
40524
|
} catch (e) {
|
|
40239
40525
|
if (e.code === "ENOENT") return { ok: true, unlinked: [] };
|
|
40240
40526
|
return { ok: false, error: `cannot resolve delete root ${normPath2(root)}: ${errorMessage(e)}` };
|
|
@@ -40250,16 +40536,16 @@ function unlinkEscapingReparsePoints(root, primaryRoot) {
|
|
|
40250
40536
|
const dir = stack.pop();
|
|
40251
40537
|
let entries;
|
|
40252
40538
|
try {
|
|
40253
|
-
entries = (0,
|
|
40539
|
+
entries = (0, import_node_fs41.readdirSync)(dir, { withFileTypes: true });
|
|
40254
40540
|
} catch (e) {
|
|
40255
40541
|
return { ok: false, error: `cannot scan ${normPath2(dir)} for reparse points: ${errorMessage(e)}` };
|
|
40256
40542
|
}
|
|
40257
40543
|
for (const entry of entries) {
|
|
40258
|
-
const child2 = (0,
|
|
40544
|
+
const child2 = (0, import_node_path39.join)(dir, entry.name);
|
|
40259
40545
|
if (entry.isSymbolicLink()) {
|
|
40260
40546
|
let target = "";
|
|
40261
40547
|
try {
|
|
40262
|
-
target = normPath2((0,
|
|
40548
|
+
target = normPath2((0, import_node_fs41.realpathSync)(child2));
|
|
40263
40549
|
} catch {
|
|
40264
40550
|
target = "";
|
|
40265
40551
|
}
|
|
@@ -40442,7 +40728,7 @@ async function cleanupPrMergeLocalBranch(branch, options) {
|
|
|
40442
40728
|
return report;
|
|
40443
40729
|
}
|
|
40444
40730
|
const execGit = options.execGit ?? (async (args) => (await execFileP("git", args, { timeout: GIT_TIMEOUT_MS })).stdout);
|
|
40445
|
-
const pathExists = options.pathExists ??
|
|
40731
|
+
const pathExists = options.pathExists ?? import_node_fs41.existsSync;
|
|
40446
40732
|
let afterWorktrees = [];
|
|
40447
40733
|
try {
|
|
40448
40734
|
afterWorktrees = parseGitWorktreePorcelain(await execGit(["worktree", "list", "--porcelain"]));
|
|
@@ -40582,7 +40868,7 @@ async function cleanupPrMergeLocalBranch(branch, options) {
|
|
|
40582
40868
|
const preHelperGuard = unlinkEscapingReparsePoints(wtPath, options.primaryRoot);
|
|
40583
40869
|
if (!preHelperGuard.ok) return refuseReparseEscape(preHelperGuard.error);
|
|
40584
40870
|
unlinkedReparsePoints.push(...preHelperGuard.unlinked);
|
|
40585
|
-
if (pathExists((0,
|
|
40871
|
+
if (pathExists((0, import_node_path39.join)(wtPath, "node_modules"))) {
|
|
40586
40872
|
const nmRemoved = await (options.removeRealNodeModules ?? removeWorktreeNodeModules)(wtPath);
|
|
40587
40873
|
if (!nmRemoved.ok) {
|
|
40588
40874
|
report.worktree = {
|
|
@@ -40749,10 +41035,10 @@ function argvWantsJson2() {
|
|
|
40749
41035
|
return process.argv.some((a) => a === "--json" || a.startsWith("--json="));
|
|
40750
41036
|
}
|
|
40751
41037
|
function hubRoot() {
|
|
40752
|
-
const fromPkg = (0,
|
|
41038
|
+
const fromPkg = (0, import_node_path40.join)(__dirname, "..", "..");
|
|
40753
41039
|
const marker = "skills/bootstrap/seeds/manifest.json";
|
|
40754
|
-
if ((0,
|
|
40755
|
-
if ((0,
|
|
41040
|
+
if ((0, import_node_fs42.existsSync)((0, import_node_path40.join)(fromPkg, marker))) return fromPkg;
|
|
41041
|
+
if ((0, import_node_fs42.existsSync)((0, import_node_path40.join)(process.cwd(), marker))) return process.cwd();
|
|
40756
41042
|
return null;
|
|
40757
41043
|
}
|
|
40758
41044
|
function ciAuditDeps() {
|
|
@@ -40764,8 +41050,8 @@ function ciAuditDeps() {
|
|
|
40764
41050
|
getProjectMeta: async (slug) => fetchProjectBySlug(slug, registryClientDeps(await cfgPromise)),
|
|
40765
41051
|
readSeedFile: (path2) => {
|
|
40766
41052
|
if (!root) return null;
|
|
40767
|
-
const fullPath = (0,
|
|
40768
|
-
return (0,
|
|
41053
|
+
const fullPath = (0, import_node_path40.join)(root, path2);
|
|
41054
|
+
return (0, import_node_fs42.existsSync)(fullPath) ? (0, import_node_fs42.readFileSync)(fullPath, "utf8") : null;
|
|
40769
41055
|
}
|
|
40770
41056
|
};
|
|
40771
41057
|
}
|
|
@@ -41443,6 +41729,10 @@ ${list}`);
|
|
|
41443
41729
|
}
|
|
41444
41730
|
const claimRefusal = await prCreateClaimRefusal(body, o.repo);
|
|
41445
41731
|
if (claimRefusal) return fail(claimRefusal);
|
|
41732
|
+
const createHead = o.head ?? await gitOut(["symbolic-ref", "--quiet", "--short", "HEAD"]).catch(() => "");
|
|
41733
|
+
const mergedHeadWarning = await prCreateMergedHeadWarning({ head: createHead || void 0, repo: o.repo });
|
|
41734
|
+
if (mergedHeadWarning) process.stderr.write(`${mergedHeadWarning}
|
|
41735
|
+
`);
|
|
41446
41736
|
const created = await ghCreate(buildPrArgs({ title, body, base: o.base, head: o.head, repo: o.repo, draft: o.draft }));
|
|
41447
41737
|
if (isGhCreateRateLimited(created)) {
|
|
41448
41738
|
console.log(JSON.stringify(created));
|
|
@@ -41486,11 +41776,11 @@ ${list}`);
|
|
|
41486
41776
|
}
|
|
41487
41777
|
});
|
|
41488
41778
|
async function listCiWorkflowPaths(cwd = process.cwd()) {
|
|
41489
|
-
const wfDir = (0,
|
|
41490
|
-
if (!(0,
|
|
41491
|
-
return (0,
|
|
41779
|
+
const wfDir = (0, import_node_path40.join)(cwd, ".github", "workflows");
|
|
41780
|
+
if (!(0, import_node_fs42.existsSync)(wfDir)) return [];
|
|
41781
|
+
return (0, import_node_fs42.readdirSync)(wfDir).filter((name) => /\.(ya?ml)$/i.test(name)).filter((name) => {
|
|
41492
41782
|
try {
|
|
41493
|
-
return workflowReportsPrChecks((0,
|
|
41783
|
+
return workflowReportsPrChecks((0, import_node_fs42.readFileSync)((0, import_node_path40.join)(wfDir, name), "utf8"));
|
|
41494
41784
|
} catch {
|
|
41495
41785
|
return true;
|
|
41496
41786
|
}
|
|
@@ -41686,7 +41976,7 @@ ${list}`);
|
|
|
41686
41976
|
jsonParity(pr.command("review-verdict <number>").description("post an explicit review verdict comment: computes the PR diff patch-id and head sha, renders the v1 contract body, and posts it as a PR comment").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) => {
|
|
41687
41977
|
if (!isReviewVerdict(o.verdict)) return fail(`pr review-verdict: --verdict must be one of ${REVIEW_VERDICTS.join("|")} (got ${o.verdict})`);
|
|
41688
41978
|
const verdict = o.verdict;
|
|
41689
|
-
const findings = o.findingsFile ? (0,
|
|
41979
|
+
const findings = o.findingsFile ? (0, import_node_fs42.readFileSync)(o.findingsFile, "utf8") : void 0;
|
|
41690
41980
|
let patch;
|
|
41691
41981
|
let head;
|
|
41692
41982
|
try {
|
|
@@ -41801,7 +42091,7 @@ ${list}`);
|
|
|
41801
42091
|
const shape = track ? `${track} track` : "unresolved track \u2014 strict reading";
|
|
41802
42092
|
throw new Error(`pr land: base branch ${base} is a promotion target (${shape}) \u2014 promotion merges stay human-only`);
|
|
41803
42093
|
}
|
|
41804
|
-
return repo;
|
|
42094
|
+
return { repo, base };
|
|
41805
42095
|
},
|
|
41806
42096
|
fetchTrainAuthority: async (repo) => fetchTrainAuthority(repo, registryClientDeps(await loadConfig())),
|
|
41807
42097
|
resolveCiPolicy: (repo) => resolveRepoMergeCiPolicy(repo, ciAuditDeps()),
|
|
@@ -41916,7 +42206,9 @@ ${list}`);
|
|
|
41916
42206
|
}
|
|
41917
42207
|
const credential = await pollToken().catch(() => void 0) ? "app_installation" : "user";
|
|
41918
42208
|
if (o.json) printLine(JSON.stringify({ ...result, credential }));
|
|
41919
|
-
else printLine(
|
|
42209
|
+
else printLine(
|
|
42210
|
+
`pr land: ${result.status}${result.error ? ` \u2014 ${result.error}` : ""} (credential: ${credential})` + (result.branchFinality ? ` \u2014 ${result.branchFinality}` : "")
|
|
42211
|
+
);
|
|
41920
42212
|
if (result.status === "failed") process.exitCode = 1;
|
|
41921
42213
|
});
|
|
41922
42214
|
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>", "compatibility option; shared merge helpers do not require a review verdict")).action(async (number, o) => {
|
|
@@ -41958,7 +42250,7 @@ ${list}`);
|
|
|
41958
42250
|
const mergeSquashBody = squashBodyTextForMerge(
|
|
41959
42251
|
closingGuardInput,
|
|
41960
42252
|
method === "--squash",
|
|
41961
|
-
o.squashBodyFile ? (0,
|
|
42253
|
+
o.squashBodyFile ? (0, import_node_fs42.readFileSync)(o.squashBodyFile, "utf8") : void 0
|
|
41962
42254
|
);
|
|
41963
42255
|
if (!o.squashBodyFile) warnSquashBodyClosingStrip("pr merge", closingGuardInput, mergeSquashBody);
|
|
41964
42256
|
const closingGuardVerdict = evaluateClosingGuard(closingGuardInput, {
|
|
@@ -41990,7 +42282,7 @@ ${list}`);
|
|
|
41990
42282
|
const remote = foreignCwd ? `https://github.com/${targetRepo2}.git` : "origin";
|
|
41991
42283
|
let foreignCheckout;
|
|
41992
42284
|
if (foreignCwd) {
|
|
41993
|
-
const sibling = (0,
|
|
42285
|
+
const sibling = (0, import_node_path40.join)((0, import_node_path40.dirname)(beforeWorktrees[0]?.path || startingPath || process.cwd()), targetRepo2.split("/")[1]);
|
|
41994
42286
|
const siblingRepo = repoFromRemoteUrl(await gitOut(["-C", sibling, "remote", "get-url", "origin"]).catch(() => ""));
|
|
41995
42287
|
if (siblingRepo?.toLowerCase() === targetRepo2.toLowerCase()) {
|
|
41996
42288
|
const siblingWorktrees = await execFileP("git", ["-C", sibling, "worktree", "list", "--porcelain"], { timeout: GIT_TIMEOUT_MS }).then((r) => parseGitWorktreePorcelain(r.stdout)).catch(() => void 0);
|
|
@@ -42088,7 +42380,7 @@ ${list}`);
|
|
|
42088
42380
|
}
|
|
42089
42381
|
if (!repoForPostCleanup) throw e;
|
|
42090
42382
|
console.warn(`pr merge: gh GraphQL rate-limited \u2014 merging PR #${number} via REST PUT instead (#4588).`);
|
|
42091
|
-
const commitMessage = bodyFile ? (0,
|
|
42383
|
+
const commitMessage = bodyFile ? (0, import_node_fs42.readFileSync)(bodyFile, "utf8") : void 0;
|
|
42092
42384
|
await defaultGitHubClient().rest("PUT", `repos/${repoForPostCleanup}/pulls/${number}/merge`, {
|
|
42093
42385
|
body: { merge_method: method.slice(2), ...commitMessage ? { commit_message: commitMessage } : {} },
|
|
42094
42386
|
timeoutMs: GH_MUTATION_TIMEOUT_MS
|
|
@@ -42208,7 +42500,7 @@ ${list}`);
|
|
|
42208
42500
|
preserveWorktree: o.preserveWorktree,
|
|
42209
42501
|
gcAcknowledged: o.gc,
|
|
42210
42502
|
expectedHeadOid: headRefOid,
|
|
42211
|
-
pathExists: (p) => (0,
|
|
42503
|
+
pathExists: (p) => (0, import_node_fs42.existsSync)(p),
|
|
42212
42504
|
// #5899: pin cleanup git calls to the main checkout — the task worktree this process may be
|
|
42213
42505
|
// standing in is removed mid-cleanup, so a cwd-relative invocation fails with
|
|
42214
42506
|
// 'fatal: not a git repository' and leaves a spurious partial-cleanup exit.
|
|
@@ -42329,7 +42621,7 @@ ${list}`);
|
|
|
42329
42621
|
}
|
|
42330
42622
|
|
|
42331
42623
|
// src/command-register-developer.ts
|
|
42332
|
-
var
|
|
42624
|
+
var import_node_fs47 = require("node:fs");
|
|
42333
42625
|
init_clean_exit();
|
|
42334
42626
|
init_cli_shared();
|
|
42335
42627
|
init_error_codes();
|
|
@@ -42362,7 +42654,7 @@ async function resolveWhoami(deps) {
|
|
|
42362
42654
|
}
|
|
42363
42655
|
|
|
42364
42656
|
// src/command-register-developer.ts
|
|
42365
|
-
var
|
|
42657
|
+
var import_node_path45 = require("node:path");
|
|
42366
42658
|
init_house_map();
|
|
42367
42659
|
init_hub_url();
|
|
42368
42660
|
|
|
@@ -42395,7 +42687,7 @@ async function executeWaveLand(plan, deps) {
|
|
|
42395
42687
|
}
|
|
42396
42688
|
|
|
42397
42689
|
// src/box-commands.ts
|
|
42398
|
-
var
|
|
42690
|
+
var import_node_fs43 = require("node:fs");
|
|
42399
42691
|
init_clean_exit();
|
|
42400
42692
|
|
|
42401
42693
|
// src/box.ts
|
|
@@ -42607,7 +42899,7 @@ function registerBoxCommands(program3) {
|
|
|
42607
42899
|
}
|
|
42608
42900
|
const remote = command && command.length ? command.join(" ") : void 0;
|
|
42609
42901
|
const wroteScript = o.ssh && o.script ? o.script : null;
|
|
42610
|
-
if (wroteScript) (0,
|
|
42902
|
+
if (wroteScript) (0, import_node_fs43.writeFileSync)(wroteScript, sshRecipeScript(found, remote), "utf8");
|
|
42611
42903
|
if (o.json) {
|
|
42612
42904
|
console.log(JSON.stringify({
|
|
42613
42905
|
box: found,
|
|
@@ -42629,19 +42921,19 @@ ${SSH_RECIPE_AGENT_NOTE}`);
|
|
|
42629
42921
|
// src/dist-drift.ts
|
|
42630
42922
|
var import_node_child_process16 = require("node:child_process");
|
|
42631
42923
|
var import_node_crypto13 = require("node:crypto");
|
|
42632
|
-
var
|
|
42924
|
+
var import_node_fs45 = require("node:fs");
|
|
42633
42925
|
var import_node_os20 = require("node:os");
|
|
42634
|
-
var
|
|
42926
|
+
var import_node_path42 = require("node:path");
|
|
42635
42927
|
|
|
42636
42928
|
// ../scripts/distribution-digest.mjs
|
|
42637
42929
|
var import_node_crypto12 = require("node:crypto");
|
|
42638
|
-
var
|
|
42639
|
-
var
|
|
42930
|
+
var import_node_fs44 = require("node:fs");
|
|
42931
|
+
var import_node_path41 = require("node:path");
|
|
42640
42932
|
var slash = (value) => value.replaceAll("\\", "/");
|
|
42641
42933
|
function repoPath(root, declaredPath, label) {
|
|
42642
|
-
const absoluteRoot = (0,
|
|
42643
|
-
const target = (0,
|
|
42644
|
-
if (target !== absoluteRoot && !target.startsWith(`${absoluteRoot}${
|
|
42934
|
+
const absoluteRoot = (0, import_node_path41.resolve)(root);
|
|
42935
|
+
const target = (0, import_node_path41.resolve)(root, declaredPath);
|
|
42936
|
+
if (target !== absoluteRoot && !target.startsWith(`${absoluteRoot}${import_node_path41.sep}`)) {
|
|
42645
42937
|
throw new Error(`${label} ${declaredPath} escapes the repository root`);
|
|
42646
42938
|
}
|
|
42647
42939
|
return target;
|
|
@@ -42649,7 +42941,7 @@ function repoPath(root, declaredPath, label) {
|
|
|
42649
42941
|
function digestFiles(files) {
|
|
42650
42942
|
const hash = (0, import_node_crypto12.createHash)("sha256");
|
|
42651
42943
|
for (const file of [...files].sort((a, b) => a.relative.localeCompare(b.relative))) {
|
|
42652
|
-
const content = file.stat.isSymbolicLink() ? Buffer.from((0,
|
|
42944
|
+
const content = file.stat.isSymbolicLink() ? Buffer.from((0, import_node_fs44.readlinkSync)(file.absolute), "utf8") : (0, import_node_fs44.readFileSync)(file.absolute);
|
|
42653
42945
|
hash.update(file.relative, "utf8");
|
|
42654
42946
|
hash.update("\0");
|
|
42655
42947
|
hash.update(file.stat.isSymbolicLink() ? "symlink" : "file", "utf8");
|
|
@@ -42664,8 +42956,8 @@ function digestFiles(files) {
|
|
|
42664
42956
|
function digestPackedFiles(packageRoot, packedFiles) {
|
|
42665
42957
|
return digestFiles(packedFiles.map((path2) => {
|
|
42666
42958
|
const absolute = repoPath(packageRoot, path2, "packed artifact identity path");
|
|
42667
|
-
if (!(0,
|
|
42668
|
-
return { absolute, relative: slash(path2), stat: (0,
|
|
42959
|
+
if (!(0, import_node_fs44.existsSync)(absolute)) throw new Error(`packed artifact identity path ${path2} does not exist`);
|
|
42960
|
+
return { absolute, relative: slash(path2), stat: (0, import_node_fs44.lstatSync)(absolute) };
|
|
42669
42961
|
}));
|
|
42670
42962
|
}
|
|
42671
42963
|
|
|
@@ -42749,13 +43041,13 @@ function renderDistDriftReceipt(receipt) {
|
|
|
42749
43041
|
return lines2;
|
|
42750
43042
|
}
|
|
42751
43043
|
function readOrNull(path2) {
|
|
42752
|
-
return (0,
|
|
43044
|
+
return (0, import_node_fs45.existsSync)(path2) ? (0, import_node_fs45.readFileSync)(path2) : null;
|
|
42753
43045
|
}
|
|
42754
43046
|
function walkFiles(root) {
|
|
42755
43047
|
const files = [];
|
|
42756
43048
|
const walk2 = (directory) => {
|
|
42757
|
-
for (const entry of (0,
|
|
42758
|
-
const child2 = (0,
|
|
43049
|
+
for (const entry of (0, import_node_fs45.readdirSync)(directory, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
|
|
43050
|
+
const child2 = (0, import_node_path42.join)(directory, entry.name);
|
|
42759
43051
|
if (entry.isDirectory()) walk2(child2);
|
|
42760
43052
|
else files.push(child2);
|
|
42761
43053
|
}
|
|
@@ -42765,10 +43057,10 @@ function walkFiles(root) {
|
|
|
42765
43057
|
}
|
|
42766
43058
|
function bomPathFor(root) {
|
|
42767
43059
|
try {
|
|
42768
|
-
const registry2 = JSON.parse((0,
|
|
42769
|
-
return (0,
|
|
43060
|
+
const registry2 = JSON.parse((0, import_node_fs45.readFileSync)((0, import_node_path42.join)(root, "surfaces.json"), "utf8"));
|
|
43061
|
+
return (0, import_node_path42.join)(root, registry2?.sharedAgentCore?.releaseMetadata?.bomPath ?? "distribution-bom.json");
|
|
42770
43062
|
} catch {
|
|
42771
|
-
return (0,
|
|
43063
|
+
return (0, import_node_path42.join)(root, "distribution-bom.json");
|
|
42772
43064
|
}
|
|
42773
43065
|
}
|
|
42774
43066
|
function rebuildTo(packageRoot, outDir) {
|
|
@@ -42781,35 +43073,35 @@ function rebuildTo(packageRoot, outDir) {
|
|
|
42781
43073
|
});
|
|
42782
43074
|
}
|
|
42783
43075
|
function runDistStatus(root) {
|
|
42784
|
-
const stage = (0,
|
|
43076
|
+
const stage = (0, import_node_fs45.mkdtempSync)((0, import_node_path42.join)((0, import_node_os20.tmpdir)(), "mmi-dist-drift-"));
|
|
42785
43077
|
let overlayCount = 0;
|
|
42786
43078
|
try {
|
|
42787
|
-
const cliOut = (0,
|
|
42788
|
-
const hubOut = (0,
|
|
42789
|
-
rebuildTo((0,
|
|
42790
|
-
rebuildTo((0,
|
|
43079
|
+
const cliOut = (0, import_node_path42.join)(stage, "cli-dist");
|
|
43080
|
+
const hubOut = (0, import_node_path42.join)(stage, "hub-dist");
|
|
43081
|
+
rebuildTo((0, import_node_path42.join)(root, "cli"), cliOut);
|
|
43082
|
+
rebuildTo((0, import_node_path42.join)(root, "updater"), hubOut);
|
|
42791
43083
|
const outDirFor = (packageDir) => packageDir === "cli" ? cliOut : hubOut;
|
|
42792
43084
|
const rebuilt = (path2) => {
|
|
42793
43085
|
const spec = DIST_ARTIFACTS.find((entry) => entry.path === path2);
|
|
42794
|
-
return spec ? readOrNull((0,
|
|
43086
|
+
return spec ? readOrNull((0, import_node_path42.join)(outDirFor(spec.packageDir), spec.output)) : null;
|
|
42795
43087
|
};
|
|
42796
|
-
const committed = (path2) => readOrNull((0,
|
|
42797
|
-
const tree = (path2) => readOrNull((0,
|
|
42798
|
-
const distRoot = (0,
|
|
42799
|
-
const distTree = () => walkFiles(distRoot).map((absolute) => `cli/dist/${(0,
|
|
42800
|
-
const bom = JSON.parse((0,
|
|
43088
|
+
const committed = (path2) => readOrNull((0, import_node_path42.join)(root, path2));
|
|
43089
|
+
const tree = (path2) => readOrNull((0, import_node_path42.join)(root, path2));
|
|
43090
|
+
const distRoot = (0, import_node_path42.join)(root, "cli", "dist");
|
|
43091
|
+
const distTree = () => walkFiles(distRoot).map((absolute) => `cli/dist/${(0, import_node_path42.relative)(distRoot, absolute).replaceAll("\\", "/")}`);
|
|
43092
|
+
const bom = JSON.parse((0, import_node_fs45.readFileSync)(bomPathFor(root), "utf8"));
|
|
42801
43093
|
const digest = (entries) => {
|
|
42802
|
-
const overlay = (0,
|
|
43094
|
+
const overlay = (0, import_node_path42.join)(stage, `overlay-${overlayCount++}`);
|
|
42803
43095
|
for (const entry of entries) {
|
|
42804
|
-
const target = (0,
|
|
42805
|
-
(0,
|
|
42806
|
-
(0,
|
|
43096
|
+
const target = (0, import_node_path42.join)(overlay, entry.path);
|
|
43097
|
+
(0, import_node_fs45.mkdirSync)((0, import_node_path42.dirname)(target), { recursive: true });
|
|
43098
|
+
(0, import_node_fs45.writeFileSync)(target, entry.bytes);
|
|
42807
43099
|
}
|
|
42808
43100
|
return digestPackedFiles(overlay, entries.map((entry) => entry.path));
|
|
42809
43101
|
};
|
|
42810
43102
|
return computeDistDriftReceipt({ committed, tree, rebuilt, distTree, bom, digest });
|
|
42811
43103
|
} finally {
|
|
42812
|
-
(0,
|
|
43104
|
+
(0, import_node_fs45.rmSync)(stage, { recursive: true, force: true });
|
|
42813
43105
|
}
|
|
42814
43106
|
}
|
|
42815
43107
|
|
|
@@ -42888,7 +43180,7 @@ init_hub_auth();
|
|
|
42888
43180
|
|
|
42889
43181
|
// src/schedules-lift-command.ts
|
|
42890
43182
|
var import_promises8 = require("node:fs/promises");
|
|
42891
|
-
var
|
|
43183
|
+
var import_node_path43 = require("node:path");
|
|
42892
43184
|
init_clean_exit();
|
|
42893
43185
|
init_cli_shared();
|
|
42894
43186
|
var DEFAULT_WORKFLOWS_DIR = ".github/workflows";
|
|
@@ -42917,7 +43209,7 @@ async function readWorkflowFiles(dir) {
|
|
|
42917
43209
|
const files = [];
|
|
42918
43210
|
for (const name of names.sort()) {
|
|
42919
43211
|
if (!/\.ya?ml$/.test(name)) continue;
|
|
42920
|
-
files.push({ path: `.github/workflows/${name}`, text: await (0, import_promises8.readFile)((0,
|
|
43212
|
+
files.push({ path: `.github/workflows/${name}`, text: await (0, import_promises8.readFile)((0, import_node_path43.join)(dir, name), "utf8") });
|
|
42921
43213
|
}
|
|
42922
43214
|
return files;
|
|
42923
43215
|
}
|
|
@@ -43000,8 +43292,8 @@ function registerSchedulesLiftCommand(program3, deps = {}) {
|
|
|
43000
43292
|
|
|
43001
43293
|
// src/spawn-policy-core.ts
|
|
43002
43294
|
var import_node_child_process17 = require("node:child_process");
|
|
43003
|
-
var
|
|
43004
|
-
var
|
|
43295
|
+
var import_node_fs46 = require("node:fs");
|
|
43296
|
+
var import_node_path44 = require("node:path");
|
|
43005
43297
|
var SPAWNERS = ["spawn", "spawnSync", "exec", "execSync", "execFile", "execFileSync"];
|
|
43006
43298
|
var CALL_SOURCE = String.raw`(^|[^.\w$])(${SPAWNERS.join("|")})\s*\(`;
|
|
43007
43299
|
var SOURCE_EXT = /\.(ts|mts|cts|js|mjs|cjs)$/;
|
|
@@ -43087,7 +43379,7 @@ function runSpawnPolicy(root) {
|
|
|
43087
43379
|
for (const file of files) {
|
|
43088
43380
|
let raw;
|
|
43089
43381
|
try {
|
|
43090
|
-
raw = (0,
|
|
43382
|
+
raw = (0, import_node_fs46.readFileSync)((0, import_node_path44.join)(root, file), "utf8");
|
|
43091
43383
|
} catch {
|
|
43092
43384
|
continue;
|
|
43093
43385
|
}
|
|
@@ -43107,19 +43399,19 @@ function runSpawnPolicy(root) {
|
|
|
43107
43399
|
function registerDeveloperCommands(program3) {
|
|
43108
43400
|
const rules = program3.command("rules").description("org-managed .gitignore delivery");
|
|
43109
43401
|
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) => {
|
|
43110
|
-
const path2 = (0,
|
|
43111
|
-
const current = (0,
|
|
43402
|
+
const path2 = (0, import_node_path45.join)(process.cwd(), ".gitignore");
|
|
43403
|
+
const current = (0, import_node_fs47.existsSync)(path2) ? (0, import_node_fs47.readFileSync)(path2, "utf8") : null;
|
|
43112
43404
|
const plan = planManagedGitignore(current);
|
|
43113
43405
|
const drift = [...plan.added.map((l) => `+${l}`), ...plan.removed.map((l) => `-${l}`)].join(", ") || "block normalize";
|
|
43114
43406
|
if (opts.json) {
|
|
43115
|
-
if (opts.write && plan.changed) (0,
|
|
43407
|
+
if (opts.write && plan.changed) (0, import_node_fs47.writeFileSync)(path2, plan.content, "utf8");
|
|
43116
43408
|
console.log(JSON.stringify(plan, null, 2));
|
|
43117
43409
|
if (!opts.write && plan.changed) process.exitCode = 1;
|
|
43118
43410
|
return;
|
|
43119
43411
|
}
|
|
43120
43412
|
if (opts.write) {
|
|
43121
43413
|
if (plan.changed) {
|
|
43122
|
-
(0,
|
|
43414
|
+
(0, import_node_fs47.writeFileSync)(path2, plan.content, "utf8");
|
|
43123
43415
|
console.log(`mmi-cli devops org rules gitignore: updated .gitignore (${drift})`);
|
|
43124
43416
|
} else {
|
|
43125
43417
|
console.log("mmi-cli devops org rules gitignore: up to date");
|
|
@@ -44753,8 +45045,8 @@ function checkHotfixCarries(options) {
|
|
|
44753
45045
|
}
|
|
44754
45046
|
|
|
44755
45047
|
// src/train-commands.ts
|
|
44756
|
-
var
|
|
44757
|
-
var
|
|
45048
|
+
var import_node_fs48 = require("node:fs");
|
|
45049
|
+
var import_node_path46 = require("node:path");
|
|
44758
45050
|
init_cli_shared();
|
|
44759
45051
|
init_clean_exit();
|
|
44760
45052
|
init_client_version();
|
|
@@ -44769,7 +45061,7 @@ function resolveReleaseBumpIntent(raw) {
|
|
|
44769
45061
|
}
|
|
44770
45062
|
function readRepoVersion() {
|
|
44771
45063
|
try {
|
|
44772
|
-
return JSON.parse((0,
|
|
45064
|
+
return JSON.parse((0, import_node_fs48.readFileSync)((0, import_node_path46.join)(process.cwd(), ".claude-plugin", "plugin.json"), "utf8")).version || void 0;
|
|
44773
45065
|
} catch {
|
|
44774
45066
|
return void 0;
|
|
44775
45067
|
}
|
|
@@ -45735,7 +46027,7 @@ ${r.stderr ?? ""}`).catch(() => "");
|
|
|
45735
46027
|
var ENV_HEAL_LOCK_STALE_MS = 10 * 6e4;
|
|
45736
46028
|
var ENV_HEAL_LOCK_MAX_WAIT_MS = 2 * 6e4;
|
|
45737
46029
|
function envHealLockPath(home) {
|
|
45738
|
-
return (0,
|
|
46030
|
+
return (0, import_node_path47.join)(home, ".claude", "plugins", ".mmi-env-heal.lock");
|
|
45739
46031
|
}
|
|
45740
46032
|
async function withEnvHealLock(what, run) {
|
|
45741
46033
|
try {
|
|
@@ -45872,7 +46164,7 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
45872
46164
|
);
|
|
45873
46165
|
const result = applyPluginCachePlan(
|
|
45874
46166
|
plan,
|
|
45875
|
-
(p) => (0,
|
|
46167
|
+
(p) => (0, import_node_fs49.rmSync)(p, { recursive: true }),
|
|
45876
46168
|
stagingApplyFsGuard(configRoot)
|
|
45877
46169
|
);
|
|
45878
46170
|
return {
|
|
@@ -45907,7 +46199,7 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
45907
46199
|
// has no generated routing index would
|
|
45908
46200
|
// get a permanent — demanding an artifact it never asked for.
|
|
45909
46201
|
docsIndexState: (root) => {
|
|
45910
|
-
if (!(0,
|
|
46202
|
+
if (!(0, import_node_fs49.existsSync)((0, import_node_path47.join)(root, DOCS_INDEX_PATH))) return void 0;
|
|
45911
46203
|
const real = createDocsIndexDeps(root);
|
|
45912
46204
|
let docs;
|
|
45913
46205
|
const listDocs = () => docs ??= real.listDocs();
|
|
@@ -45916,7 +46208,7 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
45916
46208
|
},
|
|
45917
46209
|
// #4168: working-tree heal — write if drifted, then re-check. Commit remains the operator's step.
|
|
45918
46210
|
healDocsIndex: (root) => {
|
|
45919
|
-
if (!(0,
|
|
46211
|
+
if (!(0, import_node_fs49.existsSync)((0, import_node_path47.join)(root, DOCS_INDEX_PATH))) return { drift: false, docCount: 0 };
|
|
45920
46212
|
const real = createDocsIndexDeps(root);
|
|
45921
46213
|
let docs;
|
|
45922
46214
|
const listDocs = () => docs ??= real.listDocs();
|
|
@@ -46542,7 +46834,7 @@ project.command("set [owner/repo]").description("upsert project META (idempotent
|
|
|
46542
46834
|
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`);
|
|
46543
46835
|
if (o.secretsFile) {
|
|
46544
46836
|
try {
|
|
46545
|
-
vars.push(`secrets=${(0,
|
|
46837
|
+
vars.push(`secrets=${(0, import_node_fs49.readFileSync)(o.secretsFile, "utf8")}`);
|
|
46546
46838
|
} catch (e) {
|
|
46547
46839
|
return fail(`org project set: cannot read --secrets-file ${o.secretsFile}: ${e.message}`);
|
|
46548
46840
|
}
|
|
@@ -46875,16 +47167,16 @@ function ciAuditDeps2() {
|
|
|
46875
47167
|
// gate re-seed step is skipped gracefully rather than failing mid-run.
|
|
46876
47168
|
readSeedFile: (path2) => {
|
|
46877
47169
|
if (!root) return null;
|
|
46878
|
-
const fullPath = (0,
|
|
46879
|
-
return (0,
|
|
47170
|
+
const fullPath = (0, import_node_path47.join)(root, path2);
|
|
47171
|
+
return (0, import_node_fs49.existsSync)(fullPath) ? (0, import_node_fs49.readFileSync)(fullPath, "utf8") : null;
|
|
46880
47172
|
}
|
|
46881
47173
|
};
|
|
46882
47174
|
}
|
|
46883
47175
|
function hubRoot2() {
|
|
46884
|
-
const fromPkg = (0,
|
|
47176
|
+
const fromPkg = (0, import_node_path47.join)(__dirname, "..", "..");
|
|
46885
47177
|
const marker = "skills/bootstrap/seeds/manifest.json";
|
|
46886
|
-
if ((0,
|
|
46887
|
-
if ((0,
|
|
47178
|
+
if ((0, import_node_fs49.existsSync)((0, import_node_path47.join)(fromPkg, marker))) return fromPkg;
|
|
47179
|
+
if ((0, import_node_fs49.existsSync)((0, import_node_path47.join)(process.cwd(), marker))) return process.cwd();
|
|
46888
47180
|
return null;
|
|
46889
47181
|
}
|
|
46890
47182
|
registerQueryCommands(program2);
|
|
@@ -46984,10 +47276,10 @@ access.command("audit").description("audit collaborator roles + train-branch pus
|
|
|
46984
47276
|
targets = resolution.targets;
|
|
46985
47277
|
}
|
|
46986
47278
|
const derivedMatrix = registryProjects ? accessMatrixFromProjects(registryProjects) : {};
|
|
46987
|
-
const fileMatrix = (0,
|
|
47279
|
+
const fileMatrix = (0, import_node_fs49.existsSync)("access-matrix.json") ? loadAccessMatrix((0, import_node_fs49.readFileSync)("access-matrix.json", "utf8")) : {};
|
|
46988
47280
|
const matrix = mergeAccessMatrix(fileMatrix, derivedMatrix);
|
|
46989
47281
|
const dataAccess = registryProjects ? dataAccessContractsFromProjects(registryProjects) : { consumers: {} };
|
|
46990
|
-
const sanctioned = (0,
|
|
47282
|
+
const sanctioned = (0, import_node_fs49.existsSync)("access-matrix.json") ? loadSanctionedAdmins((0, import_node_fs49.readFileSync)("access-matrix.json", "utf8")) : {};
|
|
46991
47283
|
const report = await auditOrgAccess(targets, deps, matrix, dataAccess, sanctioned);
|
|
46992
47284
|
console.log(o.json ? JSON.stringify(report, null, 2) : renderAccessReport(report));
|
|
46993
47285
|
if (!report.ok) process.exitCode = 1;
|
|
@@ -47018,16 +47310,16 @@ function directoryBytes(path2) {
|
|
|
47018
47310
|
let total = 0;
|
|
47019
47311
|
let entries;
|
|
47020
47312
|
try {
|
|
47021
|
-
entries = (0,
|
|
47313
|
+
entries = (0, import_node_fs49.readdirSync)(path2, { withFileTypes: true });
|
|
47022
47314
|
} catch {
|
|
47023
47315
|
return 0;
|
|
47024
47316
|
}
|
|
47025
47317
|
for (const entry of entries) {
|
|
47026
|
-
const child2 = (0,
|
|
47318
|
+
const child2 = (0, import_node_path47.join)(path2, entry.name);
|
|
47027
47319
|
if (entry.isDirectory()) total += directoryBytes(child2);
|
|
47028
47320
|
else {
|
|
47029
47321
|
try {
|
|
47030
|
-
total += (0,
|
|
47322
|
+
total += (0, import_node_fs49.statSync)(child2).size;
|
|
47031
47323
|
} catch {
|
|
47032
47324
|
}
|
|
47033
47325
|
}
|
|
@@ -47035,25 +47327,25 @@ function directoryBytes(path2) {
|
|
|
47035
47327
|
return total;
|
|
47036
47328
|
}
|
|
47037
47329
|
function listDirEntries(dir) {
|
|
47038
|
-
return (0,
|
|
47330
|
+
return (0, import_node_fs49.readdirSync)(dir, { withFileTypes: true }).map((d) => ({ name: d.name, isDirectory: d.isDirectory() }));
|
|
47039
47331
|
}
|
|
47040
47332
|
function readInstalledPluginRefs(configRoot) {
|
|
47041
47333
|
const p = installedPluginsPathForConfig(configRoot);
|
|
47042
|
-
if (!(0,
|
|
47334
|
+
if (!(0, import_node_fs49.existsSync)(p)) return [];
|
|
47043
47335
|
try {
|
|
47044
|
-
return installedPluginPaths((0,
|
|
47336
|
+
return installedPluginPaths((0, import_node_fs49.readFileSync)(p, "utf8"));
|
|
47045
47337
|
} catch {
|
|
47046
47338
|
return null;
|
|
47047
47339
|
}
|
|
47048
47340
|
}
|
|
47049
47341
|
function pluginCacheFsDeps(configRoot, dirBytes) {
|
|
47050
47342
|
return {
|
|
47051
|
-
exists: (p) => (0,
|
|
47052
|
-
listVersionDirs: (root) => (0,
|
|
47343
|
+
exists: (p) => (0, import_node_fs49.existsSync)(p),
|
|
47344
|
+
listVersionDirs: (root) => (0, import_node_fs49.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name),
|
|
47053
47345
|
dirBytes,
|
|
47054
|
-
listStagingDirs: (root) => (0,
|
|
47346
|
+
listStagingDirs: (root) => (0, import_node_fs49.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => {
|
|
47055
47347
|
try {
|
|
47056
|
-
return { name: d.name, mtimeMs: newestMtimeMs((0,
|
|
47348
|
+
return { name: d.name, mtimeMs: newestMtimeMs((0, import_node_path47.join)(root, d.name), listDirEntries, (p) => (0, import_node_fs49.statSync)(p).mtimeMs) };
|
|
47057
47349
|
} catch {
|
|
47058
47350
|
return { name: d.name, mtimeMs: Date.now() };
|
|
47059
47351
|
}
|
|
@@ -47067,10 +47359,10 @@ function stagingApplyFsGuard(configRoot) {
|
|
|
47067
47359
|
return {
|
|
47068
47360
|
referencedPaths: () => readInstalledPluginRefs(configRoot),
|
|
47069
47361
|
mtimeMs: (name) => {
|
|
47070
|
-
const p = (0,
|
|
47071
|
-
if (!(0,
|
|
47362
|
+
const p = (0, import_node_path47.join)(stagingRoot, name);
|
|
47363
|
+
if (!(0, import_node_fs49.existsSync)(p)) return null;
|
|
47072
47364
|
try {
|
|
47073
|
-
return newestMtimeMs(p, listDirEntries, (q) => (0,
|
|
47365
|
+
return newestMtimeMs(p, listDirEntries, (q) => (0, import_node_fs49.statSync)(q).mtimeMs);
|
|
47074
47366
|
} catch {
|
|
47075
47367
|
return null;
|
|
47076
47368
|
}
|
|
@@ -47096,7 +47388,7 @@ program2.command("plugin-prune").description(`prune stale cached MMI plugin vers
|
|
|
47096
47388
|
{ withBytes: true, configRoot, includeStaging: surface !== "codex" }
|
|
47097
47389
|
);
|
|
47098
47390
|
const anythingToDelete = plan.prune.length > 0 || plan.staging.length > 0;
|
|
47099
|
-
const result = o.apply && anythingToDelete ? applyPluginCachePlan(plan, (p) => (0,
|
|
47391
|
+
const result = o.apply && anythingToDelete ? applyPluginCachePlan(plan, (p) => (0, import_node_fs49.rmSync)(p, { recursive: true, force: true }), stagingApplyFsGuard(configRoot)) : void 0;
|
|
47100
47392
|
const warnings = plan.prune.length > 0 ? [CONCURRENT_SESSION_WARNING] : [];
|
|
47101
47393
|
if (o.json) console.log(JSON.stringify({ ...plan, warnings, applied: result ?? null }));
|
|
47102
47394
|
else console.log(renderPluginCachePlan(plan, result));
|