@mutmutco/cli 4.5.159 → 4.5.160
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 +512 -370
- package/dist/runbook-sweep.cjs +71 -6
- package/package.json +1 -1
package/dist/main.cjs
CHANGED
|
@@ -589,6 +589,54 @@ var init_github_client = __esm({
|
|
|
589
589
|
}
|
|
590
590
|
});
|
|
591
591
|
|
|
592
|
+
// src/gh-read-route.ts
|
|
593
|
+
function isViewerFreeGhRead(args) {
|
|
594
|
+
if (args.some((a) => VIEWER.test(a))) return false;
|
|
595
|
+
const [group, verb] = args;
|
|
596
|
+
if (group === "api") return isReadOnlyApi(args.slice(1));
|
|
597
|
+
return Boolean(group && verb && READ_VERBS.get(group)?.has(verb));
|
|
598
|
+
}
|
|
599
|
+
function isReadOnlyApi(rest) {
|
|
600
|
+
let path2;
|
|
601
|
+
for (let i = 0; i < rest.length; i++) {
|
|
602
|
+
const a = rest[i];
|
|
603
|
+
if (a === "-X" || a === "--method") {
|
|
604
|
+
if ((rest[i + 1] ?? "").toUpperCase() !== "GET") return false;
|
|
605
|
+
i++;
|
|
606
|
+
} else if (/^--method=/.test(a)) {
|
|
607
|
+
if (a.slice(9).toUpperCase() !== "GET") return false;
|
|
608
|
+
} else if (a === "-f" || a === "-F" || a === "--field" || a === "--raw-field") {
|
|
609
|
+
const field = rest[i + 1] ?? "";
|
|
610
|
+
if (path2 !== "graphql" || !/^query=\s*(query\b|\{)/.test(field) || /projectV2|projectsV2/.test(field)) return false;
|
|
611
|
+
i++;
|
|
612
|
+
} else if (a === "--input" || a.startsWith("--input=")) {
|
|
613
|
+
return false;
|
|
614
|
+
} else if (a === "-H" || a === "--header" || a === "-q" || a === "--jq" || a === "-t" || a === "--template" || a === "--hostname" || a === "--cache") {
|
|
615
|
+
i++;
|
|
616
|
+
} else if (!a.startsWith("-") && path2 === void 0) {
|
|
617
|
+
path2 = a.replace(/^\//, "");
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
if (!path2) return false;
|
|
621
|
+
if (path2 === "graphql") return rest.some((a) => /^query=\s*(query\b|\{)/.test(a));
|
|
622
|
+
return !/^(user|users\/[^/]+\/|notifications|search\/|orgs\/[^/]+\/projectsV2|graphql)/.test(path2);
|
|
623
|
+
}
|
|
624
|
+
var READ_VERBS, VIEWER;
|
|
625
|
+
var init_gh_read_route = __esm({
|
|
626
|
+
"src/gh-read-route.ts"() {
|
|
627
|
+
"use strict";
|
|
628
|
+
READ_VERBS = /* @__PURE__ */ new Map([
|
|
629
|
+
["pr", /* @__PURE__ */ new Set(["view", "list", "checks", "diff"])],
|
|
630
|
+
["issue", /* @__PURE__ */ new Set(["view", "list"])],
|
|
631
|
+
["run", /* @__PURE__ */ new Set(["view", "list", "watch"])],
|
|
632
|
+
["label", /* @__PURE__ */ new Set(["list"])],
|
|
633
|
+
["release", /* @__PURE__ */ new Set(["view", "list"])],
|
|
634
|
+
["repo", /* @__PURE__ */ new Set(["view"])]
|
|
635
|
+
]);
|
|
636
|
+
VIEWER = /@me\b|viewer|project/i;
|
|
637
|
+
}
|
|
638
|
+
});
|
|
639
|
+
|
|
592
640
|
// src/github-quota.ts
|
|
593
641
|
function hubQuotaResetWaitMs(resetAt, nowMs, capMs = RATE_LIMIT_WAIT_CAP_MS, jitterMs = 0) {
|
|
594
642
|
if (typeof resetAt !== "string" || !resetAt) return void 0;
|
|
@@ -959,6 +1007,8 @@ var init_house_map = __esm({
|
|
|
959
1007
|
pr: "devops",
|
|
960
1008
|
read: "devops",
|
|
961
1009
|
// closed typed GitHub reads on the App pool (run/pr/issue broker, #8042)
|
|
1010
|
+
github: "devops",
|
|
1011
|
+
// personal and App allowance visibility
|
|
962
1012
|
api: "devops",
|
|
963
1013
|
// allowlisted GitHub REST GET reads for automation (pull files, compare, contents)
|
|
964
1014
|
ci: "devops",
|
|
@@ -1110,8 +1160,18 @@ __export(cli_shared_exports, {
|
|
|
1110
1160
|
rawValue: () => rawValue,
|
|
1111
1161
|
readStdin: () => readStdin,
|
|
1112
1162
|
repoProject: () => repoProject,
|
|
1163
|
+
setGhReadTokenProvider: () => setGhReadTokenProvider,
|
|
1113
1164
|
setInjectedStdin: () => setInjectedStdin
|
|
1114
1165
|
});
|
|
1166
|
+
function setGhReadTokenProvider(provider) {
|
|
1167
|
+
ghReadTokenProvider = provider;
|
|
1168
|
+
}
|
|
1169
|
+
async function ghReadAppEnv(file, args) {
|
|
1170
|
+
if (!ghReadTokenProvider || !/(^|[\\/])gh(\.exe)?$/i.test(file) || process.env.MMI_ACTOR?.trim() === "personal") return void 0;
|
|
1171
|
+
if (!isViewerFreeGhRead(args)) return void 0;
|
|
1172
|
+
const token = await ghReadTokenProvider().catch(() => void 0);
|
|
1173
|
+
return token ? { ...process.env, GH_TOKEN: token } : void 0;
|
|
1174
|
+
}
|
|
1115
1175
|
function killProcessTree(pid) {
|
|
1116
1176
|
try {
|
|
1117
1177
|
if (process.platform === "win32") {
|
|
@@ -1280,7 +1340,7 @@ function printLine(value) {
|
|
|
1280
1340
|
(0, import_node_fs5.writeSync)(1, `${value}
|
|
1281
1341
|
`);
|
|
1282
1342
|
}
|
|
1283
|
-
var import_node_child_process2, import_node_fs5, import_node_util3, rawExecFileP, DEFAULT_EXEC_TIMEOUT_MS, execFileP, GIT_TIMEOUT_MS, ExecDeadlineError, cachedGithubLogin, gitOut, consoleIo;
|
|
1343
|
+
var import_node_child_process2, import_node_fs5, import_node_util3, rawExecFileP, DEFAULT_EXEC_TIMEOUT_MS, execFileP, ghReadTokenProvider, GIT_TIMEOUT_MS, ExecDeadlineError, cachedGithubLogin, gitOut, consoleIo;
|
|
1284
1344
|
var init_cli_shared = __esm({
|
|
1285
1345
|
"src/cli-shared.ts"() {
|
|
1286
1346
|
"use strict";
|
|
@@ -1292,16 +1352,27 @@ var init_cli_shared = __esm({
|
|
|
1292
1352
|
init_clean_exit();
|
|
1293
1353
|
init_error_codes();
|
|
1294
1354
|
init_github_client();
|
|
1355
|
+
init_gh_read_route();
|
|
1295
1356
|
init_hub_auth();
|
|
1296
1357
|
init_house_map();
|
|
1297
1358
|
init_stdin_inject();
|
|
1298
1359
|
rawExecFileP = (0, import_node_util3.promisify)(import_node_child_process2.execFile);
|
|
1299
1360
|
DEFAULT_EXEC_TIMEOUT_MS = 1e4;
|
|
1300
|
-
execFileP = (file, args, options = {}) =>
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1361
|
+
execFileP = async (file, args, options = {}) => {
|
|
1362
|
+
const run = (env) => (
|
|
1363
|
+
// encoding 'utf8' guarantees string stdout/stderr at runtime; the cast pins the type because
|
|
1364
|
+
// promisify(execFile)'s overloads widen to string|Buffer when options is spread in.
|
|
1365
|
+
rawExecFileP(file, args, { encoding: "utf8", windowsHide: true, timeout: DEFAULT_EXEC_TIMEOUT_MS, killSignal: "SIGTERM", ...options, ...env ? { env } : {} })
|
|
1366
|
+
);
|
|
1367
|
+
const appEnv = options.env ? void 0 : await ghReadAppEnv(file, args);
|
|
1368
|
+
if (!appEnv) return run();
|
|
1369
|
+
try {
|
|
1370
|
+
return await run(appEnv);
|
|
1371
|
+
} catch (e) {
|
|
1372
|
+
if (/Resource not accessible by integration/i.test(String(e.stderr ?? ""))) return run();
|
|
1373
|
+
throw e;
|
|
1374
|
+
}
|
|
1375
|
+
};
|
|
1305
1376
|
GIT_TIMEOUT_MS = DEFAULT_EXEC_TIMEOUT_MS;
|
|
1306
1377
|
ExecDeadlineError = class extends Error {
|
|
1307
1378
|
constructor(step, timeoutMs, elapsedMs, killed) {
|
|
@@ -4755,7 +4826,7 @@ function useColor() {
|
|
|
4755
4826
|
var program = new Command();
|
|
4756
4827
|
|
|
4757
4828
|
// src/command-composition.ts
|
|
4758
|
-
var
|
|
4829
|
+
var import_node_fs59 = require("node:fs");
|
|
4759
4830
|
init_clean_exit();
|
|
4760
4831
|
init_cli_shared();
|
|
4761
4832
|
|
|
@@ -6949,7 +7020,7 @@ var import_node_os25 = require("node:os");
|
|
|
6949
7020
|
var import_node_path57 = require("node:path");
|
|
6950
7021
|
|
|
6951
7022
|
// src/board-read.ts
|
|
6952
|
-
var
|
|
7023
|
+
var import_node_fs17 = require("node:fs");
|
|
6953
7024
|
var import_node_os10 = require("node:os");
|
|
6954
7025
|
var import_node_path14 = require("node:path");
|
|
6955
7026
|
init_cli_shared();
|
|
@@ -7167,6 +7238,19 @@ async function readAppVaultSecret(read) {
|
|
|
7167
7238
|
async function mintInstallationToken(deps) {
|
|
7168
7239
|
return mintScopedInstallationToken(deps, APP_POLL_PERMISSIONS);
|
|
7169
7240
|
}
|
|
7241
|
+
var APP_WRITE_COMMANDS = /* @__PURE__ */ new Map([
|
|
7242
|
+
["issue comment", { metadata: "read", issues: "write", pull_requests: "write" }]
|
|
7243
|
+
]);
|
|
7244
|
+
async function mintCommandWriteToken(deps, commandPath3) {
|
|
7245
|
+
const permissions = APP_WRITE_COMMANDS.get(commandPath3);
|
|
7246
|
+
if (!permissions) throw new AppActorError(`app actor: '${commandPath3}' has no App write profile`);
|
|
7247
|
+
try {
|
|
7248
|
+
return await mintFromMember(deps, permissions, APP_VAULT_KEYS);
|
|
7249
|
+
} catch (e) {
|
|
7250
|
+
if (e instanceof AppActorError) throw e;
|
|
7251
|
+
throw new AppActorError(`app actor: write token mint failed (${e?.constructor?.name ?? "Error"})`);
|
|
7252
|
+
}
|
|
7253
|
+
}
|
|
7170
7254
|
async function mintStatusWriteToken(deps) {
|
|
7171
7255
|
return mintScopedInstallationToken(deps, { metadata: "read", statuses: "write" });
|
|
7172
7256
|
}
|
|
@@ -7227,6 +7311,9 @@ async function allowanceSpent(deps, token) {
|
|
|
7227
7311
|
return false;
|
|
7228
7312
|
}
|
|
7229
7313
|
}
|
|
7314
|
+
function mintBudgetToken(deps, keys) {
|
|
7315
|
+
return mintFromMember(deps, { metadata: "read" }, keys);
|
|
7316
|
+
}
|
|
7230
7317
|
async function mintFromMember(deps, permissions, keys) {
|
|
7231
7318
|
const [appId, installationId, privateKey] = await Promise.all(keys.map((k) => deps.fetchSecret(k)));
|
|
7232
7319
|
if (!appId || !installationId || !privateKey) {
|
|
@@ -7294,7 +7381,7 @@ async function activateAppActor(commandPath3, env, mint, note = (line) => proces
|
|
|
7294
7381
|
if (requested && requested !== "app") {
|
|
7295
7382
|
throw new AppActorError(`app actor: unknown ${APP_ACTOR_ENV} value \u2014 only 'app' and 'personal' are supported; refusing to guess an identity`);
|
|
7296
7383
|
}
|
|
7297
|
-
if (!APP_ELIGIBLE_COMMANDS.has(commandPath3)) {
|
|
7384
|
+
if (!APP_ELIGIBLE_COMMANDS.has(commandPath3) && !APP_WRITE_COMMANDS.has(commandPath3)) {
|
|
7298
7385
|
if (requested === "app" && !notedIneligibleCommand) {
|
|
7299
7386
|
notedIneligibleCommand = true;
|
|
7300
7387
|
note(`app actor: '${commandPath3}' is personal-only (viewer/@me/authorship) \u2014 running on the personal token despite ${APP_ACTOR_ENV}=app`);
|
|
@@ -11301,6 +11388,7 @@ init_clean_exit();
|
|
|
11301
11388
|
|
|
11302
11389
|
// src/gh-create.ts
|
|
11303
11390
|
var import_promises = require("node:fs/promises");
|
|
11391
|
+
var import_node_fs16 = require("node:fs");
|
|
11304
11392
|
var import_node_os8 = require("node:os");
|
|
11305
11393
|
var import_node_path13 = require("node:path");
|
|
11306
11394
|
var import_node_crypto7 = require("node:crypto");
|
|
@@ -11566,18 +11654,23 @@ async function preflightPrCreateRemoteHead(args, deps) {
|
|
|
11566
11654
|
if (compared !== "unknown" && compared.aheadBy <= 0) return emptyCompareMessage(base, head);
|
|
11567
11655
|
return void 0;
|
|
11568
11656
|
}
|
|
11657
|
+
function retryBodyFile(args) {
|
|
11658
|
+
const file = flagValue(args, "--body-file");
|
|
11659
|
+
if (file !== void 0) return file;
|
|
11660
|
+
const body = flagValue(args, "--body");
|
|
11661
|
+
if (body === void 0) return void 0;
|
|
11662
|
+
const path2 = (0, import_node_path13.join)((0, import_node_fs16.mkdtempSync)((0, import_node_path13.join)((0, import_node_os8.tmpdir)(), "mmi-create-retry-")), "body.md");
|
|
11663
|
+
(0, import_node_fs16.writeFileSync)(path2, body, "utf8");
|
|
11664
|
+
return path2;
|
|
11665
|
+
}
|
|
11569
11666
|
function buildPrCreateRetryCommand(args) {
|
|
11570
11667
|
const parts = ["mmi-cli", "devops", "pr", "create"];
|
|
11571
11668
|
for (const flag of ["--repo", "--base", "--head", "--title"]) {
|
|
11572
11669
|
const v = flagValue(args, flag);
|
|
11573
11670
|
if (v !== void 0) parts.push(flag, shellQuote(v));
|
|
11574
11671
|
}
|
|
11575
|
-
const bodyFile =
|
|
11672
|
+
const bodyFile = retryBodyFile(args);
|
|
11576
11673
|
if (bodyFile !== void 0) parts.push("--body-file", shellQuote(bodyFile));
|
|
11577
|
-
else {
|
|
11578
|
-
const body = flagValue(args, "--body");
|
|
11579
|
-
if (body !== void 0) parts.push("--body", shellQuote(body));
|
|
11580
|
-
}
|
|
11581
11674
|
if (args.includes("--draft")) parts.push("--draft");
|
|
11582
11675
|
return parts.join(" ");
|
|
11583
11676
|
}
|
|
@@ -11600,12 +11693,8 @@ function buildIssueCreateRetryCommand(args) {
|
|
|
11600
11693
|
if (type) parts.push("--type", type);
|
|
11601
11694
|
const title = flagValue(args, "--title");
|
|
11602
11695
|
if (title !== void 0) parts.push("--title", shellQuote(title));
|
|
11603
|
-
const bodyFile =
|
|
11696
|
+
const bodyFile = retryBodyFile(args);
|
|
11604
11697
|
if (bodyFile !== void 0) parts.push("--body-file", shellQuote(bodyFile));
|
|
11605
|
-
else {
|
|
11606
|
-
const body = flagValue(args, "--body");
|
|
11607
|
-
if (body !== void 0) parts.push("--body", shellQuote(body));
|
|
11608
|
-
}
|
|
11609
11698
|
for (const label of labels) {
|
|
11610
11699
|
if (label === type) continue;
|
|
11611
11700
|
parts.push("--label", shellQuote(label));
|
|
@@ -14562,11 +14651,11 @@ function probeLocalClaimSession(marker, now = Date.now()) {
|
|
|
14562
14651
|
const pending = [root];
|
|
14563
14652
|
while (pending.length) {
|
|
14564
14653
|
const dir = pending.pop();
|
|
14565
|
-
for (const entry of (0,
|
|
14654
|
+
for (const entry of (0, import_node_fs17.readdirSync)(dir, { withFileTypes: true })) {
|
|
14566
14655
|
const path2 = (0, import_node_path14.join)(dir, entry.name);
|
|
14567
14656
|
if (entry.isDirectory()) pending.push(path2);
|
|
14568
14657
|
else if (entry.isFile() && entry.name.toLowerCase() === wanted) {
|
|
14569
|
-
return remember(now - (0,
|
|
14658
|
+
return remember(now - (0, import_node_fs17.statSync)(path2).mtimeMs <= CLAIM_SESSION_ACTIVITY_MS ? "live" : "dead");
|
|
14570
14659
|
}
|
|
14571
14660
|
}
|
|
14572
14661
|
}
|
|
@@ -16071,12 +16160,12 @@ function planManagedGitignore(current) {
|
|
|
16071
16160
|
}
|
|
16072
16161
|
|
|
16073
16162
|
// src/docs-index-command.ts
|
|
16074
|
-
var
|
|
16163
|
+
var import_node_fs19 = require("node:fs");
|
|
16075
16164
|
var import_node_path16 = require("node:path");
|
|
16076
16165
|
|
|
16077
16166
|
// src/doc-refs-core.ts
|
|
16078
16167
|
var import_node_child_process6 = require("node:child_process");
|
|
16079
|
-
var
|
|
16168
|
+
var import_node_fs18 = require("node:fs");
|
|
16080
16169
|
var import_node_path15 = require("node:path");
|
|
16081
16170
|
var PIN_RE = /<!--\s*pinned by\s+([^:]+?)\s*:\s*"([^"]+)"[^"]*-->/;
|
|
16082
16171
|
var PIN_MENTION_RE = /<!--\s*pinned by\b/;
|
|
@@ -16449,12 +16538,12 @@ function checkSeedRunbookReview(root, base, readFile10, git3) {
|
|
|
16449
16538
|
return findings;
|
|
16450
16539
|
}
|
|
16451
16540
|
function readFileOrNull(path2) {
|
|
16452
|
-
return (0,
|
|
16541
|
+
return (0, import_node_fs18.existsSync)(path2) ? (0, import_node_fs18.readFileSync)(path2, "utf8") : null;
|
|
16453
16542
|
}
|
|
16454
16543
|
function walk(dir, root, out) {
|
|
16455
|
-
for (const entry of (0,
|
|
16544
|
+
for (const entry of (0, import_node_fs18.readdirSync)(dir)) {
|
|
16456
16545
|
const full = (0, import_node_path15.join)(dir, entry);
|
|
16457
|
-
if ((0,
|
|
16546
|
+
if ((0, import_node_fs18.statSync)(full).isDirectory()) walk(full, root, out);
|
|
16458
16547
|
else if (entry.endsWith(".md")) out.push(full.slice(root.length + 1).replaceAll("\\", "/"));
|
|
16459
16548
|
}
|
|
16460
16549
|
return out;
|
|
@@ -16462,11 +16551,11 @@ function walk(dir, root, out) {
|
|
|
16462
16551
|
function defaultListDocs(root) {
|
|
16463
16552
|
const docs = ["docs", "skills/org-guide", "skills/mmi-help"].flatMap((path2) => {
|
|
16464
16553
|
const directory = (0, import_node_path15.join)(root, path2);
|
|
16465
|
-
return (0,
|
|
16554
|
+
return (0, import_node_fs18.existsSync)(directory) ? walk(directory, root, []) : [];
|
|
16466
16555
|
}).filter(
|
|
16467
16556
|
(rel) => !SKIP_WALK.some((skip) => rel.startsWith(skip))
|
|
16468
16557
|
);
|
|
16469
|
-
return [...ROOT_DOCS.filter((rel) => (0,
|
|
16558
|
+
return [...ROOT_DOCS.filter((rel) => (0, import_node_fs18.existsSync)((0, import_node_path15.join)(root, rel))), ...docs];
|
|
16470
16559
|
}
|
|
16471
16560
|
var CHECK_IGNORE_MAX_BUFFER = 32 * 1024 * 1024;
|
|
16472
16561
|
function defaultIsIgnored(root, relPaths, exec3 = import_node_child_process6.execFileSync) {
|
|
@@ -16547,7 +16636,7 @@ function mergeGroupRunbookMessages(root, deps, readFile10, warnings) {
|
|
|
16547
16636
|
}
|
|
16548
16637
|
function runDocRefs(root, deps = {}) {
|
|
16549
16638
|
const readFile10 = deps.readFile ?? readFileOrNull;
|
|
16550
|
-
const exists = deps.exists ??
|
|
16639
|
+
const exists = deps.exists ?? import_node_fs18.existsSync;
|
|
16551
16640
|
const listDocs = deps.listDocs ?? defaultListDocs;
|
|
16552
16641
|
const isIgnored = deps.isIgnored ?? ((paths) => defaultIsIgnored(root, paths));
|
|
16553
16642
|
const trackedFirstSegments = deps.trackedFirstSegments ?? ((segs) => defaultTrackedFirstSegments(root, segs));
|
|
@@ -16680,7 +16769,7 @@ function walkMarkdown(dir) {
|
|
|
16680
16769
|
const stack = [dir];
|
|
16681
16770
|
while (stack.length) {
|
|
16682
16771
|
const current = stack.pop();
|
|
16683
|
-
for (const entry of (0,
|
|
16772
|
+
for (const entry of (0, import_node_fs19.readdirSync)(current, { withFileTypes: true })) {
|
|
16684
16773
|
const full = (0, import_node_path16.join)(current, entry.name);
|
|
16685
16774
|
if (entry.isDirectory()) {
|
|
16686
16775
|
stack.push(full);
|
|
@@ -16696,15 +16785,15 @@ function createDocsIndexDeps(repoRoot2) {
|
|
|
16696
16785
|
const indexPath = (0, import_node_path16.join)(repoRoot2, DOCS_INDEX_PATH);
|
|
16697
16786
|
return {
|
|
16698
16787
|
listDocs: () => {
|
|
16699
|
-
if (!(0,
|
|
16788
|
+
if (!(0, import_node_fs19.existsSync)(docsDir)) return [];
|
|
16700
16789
|
const walked = walkMarkdown(docsDir).filter(isRoutableDocsPath);
|
|
16701
16790
|
if (!walked.length) return [];
|
|
16702
16791
|
const ignored = defaultIsIgnored(repoRoot2, walked.map((rel) => `docs/${rel}`));
|
|
16703
16792
|
return walked.filter((rel) => !ignored.has(`docs/${rel}`)).sort();
|
|
16704
16793
|
},
|
|
16705
|
-
readDoc: (relPath) => (0,
|
|
16706
|
-
readIndex: () => (0,
|
|
16707
|
-
writeIndex: (content) => (0,
|
|
16794
|
+
readDoc: (relPath) => (0, import_node_fs19.readFileSync)((0, import_node_path16.join)(docsDir, relPath), "utf8"),
|
|
16795
|
+
readIndex: () => (0, import_node_fs19.existsSync)(indexPath) ? (0, import_node_fs19.readFileSync)(indexPath, "utf8") : null,
|
|
16796
|
+
writeIndex: (content) => (0, import_node_fs19.writeFileSync)(indexPath, content, "utf8")
|
|
16708
16797
|
};
|
|
16709
16798
|
}
|
|
16710
16799
|
|
|
@@ -17623,7 +17712,7 @@ function contentPutInputArgs(repo, path2, inputFile) {
|
|
|
17623
17712
|
}
|
|
17624
17713
|
|
|
17625
17714
|
// src/train-apply-contracts.ts
|
|
17626
|
-
var
|
|
17715
|
+
var import_node_fs20 = require("node:fs");
|
|
17627
17716
|
var import_node_path17 = require("node:path");
|
|
17628
17717
|
function reduceFollowUpOutcomes(outcomes) {
|
|
17629
17718
|
if (outcomes.includes("failure")) return "failure";
|
|
@@ -17704,7 +17793,7 @@ async function resolveFoldPaths(deps, model) {
|
|
|
17704
17793
|
if (model === "vercel") return [];
|
|
17705
17794
|
const helper = "scripts/release-distribution.mjs";
|
|
17706
17795
|
if (model === "hub-serverless" || model === "registry-publish") {
|
|
17707
|
-
if ((0,
|
|
17796
|
+
if ((0, import_node_fs20.existsSync)(helper)) {
|
|
17708
17797
|
let out;
|
|
17709
17798
|
try {
|
|
17710
17799
|
out = await deps.run("node", [helper, "changed-files"]);
|
|
@@ -17853,7 +17942,7 @@ async function restoreMainNpmPackIdentities(deps, version) {
|
|
|
17853
17942
|
if (mainBom.version !== version) return void 0;
|
|
17854
17943
|
let localBom;
|
|
17855
17944
|
try {
|
|
17856
|
-
localBom = JSON.parse((0,
|
|
17945
|
+
localBom = JSON.parse((0, import_node_fs20.readFileSync)(bomPath, "utf8"));
|
|
17857
17946
|
} catch (e) {
|
|
17858
17947
|
throw new Error(
|
|
17859
17948
|
`version fold refused: ${bomPath} written by this fold's prepare is unreadable (${describeReadError(e)}) \u2014 cannot restore the published ${version} npm-pack identities from origin/main (#4503/#4713).`
|
|
@@ -17871,14 +17960,14 @@ async function restoreMainNpmPackIdentities(deps, version) {
|
|
|
17871
17960
|
restored += 1;
|
|
17872
17961
|
}
|
|
17873
17962
|
if (restored === 0) return void 0;
|
|
17874
|
-
(0,
|
|
17963
|
+
(0, import_node_fs20.writeFileSync)(bomPath, `${JSON.stringify(localBom, null, 2)}
|
|
17875
17964
|
`);
|
|
17876
17965
|
return `restored ${restored} npm-pack BOM identit${restored === 1 ? "y" : "ies"} from origin/main (#4503)`;
|
|
17877
17966
|
}
|
|
17878
17967
|
function publishVisibilityFor(surfaceId) {
|
|
17879
17968
|
let raw;
|
|
17880
17969
|
try {
|
|
17881
|
-
raw = (0,
|
|
17970
|
+
raw = (0, import_node_fs20.readFileSync)("surfaces.json", "utf8");
|
|
17882
17971
|
} catch (e) {
|
|
17883
17972
|
if (e.code === "ENOENT") return "unknown";
|
|
17884
17973
|
throw trainReadFailure(
|
|
@@ -17899,7 +17988,7 @@ function publishVisibilityFor(surfaceId) {
|
|
|
17899
17988
|
}
|
|
17900
17989
|
function npmPackArtifactName(packagePath) {
|
|
17901
17990
|
try {
|
|
17902
|
-
const pkg = JSON.parse((0,
|
|
17991
|
+
const pkg = JSON.parse((0, import_node_fs20.readFileSync)((0, import_node_path17.join)(packagePath, "package.json"), "utf8"));
|
|
17903
17992
|
return pkg.name || void 0;
|
|
17904
17993
|
} catch {
|
|
17905
17994
|
return void 0;
|
|
@@ -17908,7 +17997,7 @@ function npmPackArtifactName(packagePath) {
|
|
|
17908
17997
|
async function refuseDivergentPublishedNpmPack(deps, version) {
|
|
17909
17998
|
let localBom;
|
|
17910
17999
|
try {
|
|
17911
|
-
localBom = JSON.parse((0,
|
|
18000
|
+
localBom = JSON.parse((0, import_node_fs20.readFileSync)("distribution-bom.json", "utf8"));
|
|
17912
18001
|
} catch (e) {
|
|
17913
18002
|
throw new Error(
|
|
17914
18003
|
`version fold refused: distribution-bom.json written by this fold's prepare is unreadable (${e instanceof Error ? e.message.split("\n")[0] : String(e)}) \u2014 cannot compare the same-PATCH ${version} npm-pack identities against published npm (#4503/#4662).`
|
|
@@ -18053,7 +18142,7 @@ function assertGitBashOnWindowsForJervHubRelease(repo, platform2 = process.platf
|
|
|
18053
18142
|
}
|
|
18054
18143
|
|
|
18055
18144
|
// src/train-apply-correlation.ts
|
|
18056
|
-
var
|
|
18145
|
+
var import_node_fs22 = require("node:fs");
|
|
18057
18146
|
init_github_quota();
|
|
18058
18147
|
var import_node_path19 = require("node:path");
|
|
18059
18148
|
|
|
@@ -18820,10 +18909,10 @@ var rollout_plan_default = {
|
|
|
18820
18909
|
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)."
|
|
18821
18910
|
},
|
|
18822
18911
|
baseline: {
|
|
18823
|
-
version: "4.5.
|
|
18824
|
-
tag: "v4.5.
|
|
18825
|
-
commit: "
|
|
18826
|
-
npm: "@mutmutco/cli@4.5.
|
|
18912
|
+
version: "4.5.160",
|
|
18913
|
+
tag: "v4.5.160",
|
|
18914
|
+
commit: "05c3cc8d56ee",
|
|
18915
|
+
npm: "@mutmutco/cli@4.5.160"
|
|
18827
18916
|
},
|
|
18828
18917
|
exitCriterion: "fleet-n-of-n",
|
|
18829
18918
|
hubOnlyShortcut: "forbidden",
|
|
@@ -18840,14 +18929,14 @@ var rollout_plan_default = {
|
|
|
18840
18929
|
repo: "mutmutco/mmi-hub",
|
|
18841
18930
|
role: "canary",
|
|
18842
18931
|
schedule: "train",
|
|
18843
|
-
v3Target: "v4.5.
|
|
18932
|
+
v3Target: "v4.5.160"
|
|
18844
18933
|
}
|
|
18845
18934
|
],
|
|
18846
18935
|
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.",
|
|
18847
18936
|
rollback: {
|
|
18848
18937
|
independent: true,
|
|
18849
|
-
mechanism: "npm dist-tag latest -> 4.5.
|
|
18850
|
-
v3Target: "v4.5.
|
|
18938
|
+
mechanism: "npm dist-tag latest -> 4.5.160 and redeploy the Hub Lambda from tag v4.5.160 (05c3cc8d56ee); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
|
|
18939
|
+
v3Target: "v4.5.160 (@mutmutco/cli@4.5.160, tag commit 05c3cc8d56ee \u2014 last known-good release carrying the repo-index v4-only contract)"
|
|
18851
18940
|
}
|
|
18852
18941
|
},
|
|
18853
18942
|
{
|
|
@@ -19181,13 +19270,13 @@ function resolveIssueViewGhFields(normalized) {
|
|
|
19181
19270
|
}
|
|
19182
19271
|
|
|
19183
19272
|
// src/utf8-receipt.ts
|
|
19184
|
-
var
|
|
19273
|
+
var import_node_fs21 = require("node:fs");
|
|
19185
19274
|
var import_node_path18 = require("node:path");
|
|
19186
19275
|
function writeUtf8Receipt(path2, text) {
|
|
19187
|
-
(0,
|
|
19276
|
+
(0, import_node_fs21.mkdirSync)((0, import_node_path18.dirname)(path2), { recursive: true });
|
|
19188
19277
|
const body = text.endsWith("\n") ? text : `${text}
|
|
19189
19278
|
`;
|
|
19190
|
-
(0,
|
|
19279
|
+
(0, import_node_fs21.writeFileSync)(path2, body, "utf8");
|
|
19191
19280
|
return Buffer.byteLength(body, "utf8");
|
|
19192
19281
|
}
|
|
19193
19282
|
|
|
@@ -21073,7 +21162,7 @@ function resolveReleaseAbortNpmPackage(meta, repo) {
|
|
|
21073
21162
|
if (isHubControlRepo(repo)) return "@mutmutco/cli";
|
|
21074
21163
|
const publishDir = typeof meta.publishDir === "string" && meta.publishDir.trim() ? meta.publishDir.trim() : ".";
|
|
21075
21164
|
try {
|
|
21076
|
-
const pkg = JSON.parse((0,
|
|
21165
|
+
const pkg = JSON.parse((0, import_node_fs22.readFileSync)((0, import_node_path19.join)(publishDir, "package.json"), "utf8"));
|
|
21077
21166
|
const name = pkg.name?.trim();
|
|
21078
21167
|
if (!name) throw new Error("missing name field");
|
|
21079
21168
|
return name;
|
|
@@ -22009,7 +22098,7 @@ function parseVerifyBroker(stdout) {
|
|
|
22009
22098
|
}
|
|
22010
22099
|
|
|
22011
22100
|
// src/train-apply-deploy.ts
|
|
22012
|
-
var
|
|
22101
|
+
var import_node_fs23 = require("node:fs");
|
|
22013
22102
|
var import_node_os11 = require("node:os");
|
|
22014
22103
|
var import_node_path20 = require("node:path");
|
|
22015
22104
|
|
|
@@ -22150,7 +22239,7 @@ function mmiGetRedeployCommand(repo) {
|
|
|
22150
22239
|
}
|
|
22151
22240
|
function readLocalLauncherVersion(root = process.cwd()) {
|
|
22152
22241
|
try {
|
|
22153
|
-
const raw = (0,
|
|
22242
|
+
const raw = (0, import_node_fs23.readFileSync)((0, import_node_path20.join)(root, "cli", "package.json"), "utf8");
|
|
22154
22243
|
const version = JSON.parse(raw).version;
|
|
22155
22244
|
return typeof version === "string" && version.trim() ? version.trim() : null;
|
|
22156
22245
|
} catch {
|
|
@@ -22159,7 +22248,7 @@ function readLocalLauncherVersion(root = process.cwd()) {
|
|
|
22159
22248
|
}
|
|
22160
22249
|
function readServedChannelUrl(product = HUB_SERVED_PRODUCT, root = process.cwd()) {
|
|
22161
22250
|
try {
|
|
22162
|
-
const raw = (0,
|
|
22251
|
+
const raw = (0, import_node_fs23.readFileSync)((0, import_node_path20.join)(root, "config", `product.${product}.json`), "utf8");
|
|
22163
22252
|
const host = JSON.parse(raw).host;
|
|
22164
22253
|
if (typeof host !== "string" || !host.trim()) return null;
|
|
22165
22254
|
return `${host.trim().replace(/\/+$/, "")}/release/version`;
|
|
@@ -22593,13 +22682,13 @@ async function runTaggedJervGatewayLocalWrapper(deps, tag, tagSha) {
|
|
|
22593
22682
|
const reason = error instanceof Error ? error.message : String(error);
|
|
22594
22683
|
throw new Error(`could not extract ${JERV_GATEWAY_RELEASE_DEPLOY_SCRIPT} from tagged commit ${tagSha.slice(0, 12)}: ${reason}`);
|
|
22595
22684
|
}
|
|
22596
|
-
const dir = (0,
|
|
22685
|
+
const dir = (0, import_node_fs23.mkdtempSync)((0, import_node_path20.join)((0, import_node_os11.tmpdir)(), "jerv-gateway-release-deploy-"));
|
|
22597
22686
|
const extracted = (0, import_node_path20.join)(dir, "jerv-gateway-release-deploy.sh");
|
|
22598
22687
|
try {
|
|
22599
|
-
(0,
|
|
22688
|
+
(0, import_node_fs23.writeFileSync)(extracted, script, "utf8");
|
|
22600
22689
|
return await deps.run("bash", [extracted, "--tag", tag]);
|
|
22601
22690
|
} finally {
|
|
22602
|
-
(0,
|
|
22691
|
+
(0, import_node_fs23.rmSync)(dir, { recursive: true, force: true });
|
|
22603
22692
|
}
|
|
22604
22693
|
}
|
|
22605
22694
|
async function appendJervGatewayReleaseDeploy(deps, repo, tag, tagSha, dispatch) {
|
|
@@ -23175,7 +23264,7 @@ function renderTenantControl(r) {
|
|
|
23175
23264
|
}
|
|
23176
23265
|
|
|
23177
23266
|
// src/train-apply-phases.ts
|
|
23178
|
-
var
|
|
23267
|
+
var import_node_fs29 = require("node:fs");
|
|
23179
23268
|
var import_promises4 = require("node:fs/promises");
|
|
23180
23269
|
var import_node_path27 = require("node:path");
|
|
23181
23270
|
|
|
@@ -23494,12 +23583,12 @@ function assertPreOneZero(repo, meta, tag) {
|
|
|
23494
23583
|
|
|
23495
23584
|
// src/train-doctor.ts
|
|
23496
23585
|
var import_node_child_process9 = require("node:child_process");
|
|
23497
|
-
var
|
|
23586
|
+
var import_node_fs27 = require("node:fs");
|
|
23498
23587
|
var import_node_os15 = require("node:os");
|
|
23499
23588
|
var import_node_path26 = require("node:path");
|
|
23500
23589
|
|
|
23501
23590
|
// src/doctor-io.ts
|
|
23502
|
-
var
|
|
23591
|
+
var import_node_fs24 = require("node:fs");
|
|
23503
23592
|
var import_node_os12 = require("node:os");
|
|
23504
23593
|
var import_node_path21 = require("node:path");
|
|
23505
23594
|
var import_node_child_process7 = require("node:child_process");
|
|
@@ -23514,8 +23603,8 @@ function nodeDiscardSinkPath(platform2 = process.platform) {
|
|
|
23514
23603
|
var execFileP2 = (0, import_node_util4.promisify)(import_node_child_process7.execFile);
|
|
23515
23604
|
function execFileCapture(file, args, opts = {}) {
|
|
23516
23605
|
const sink = nodeDiscardSinkPath();
|
|
23517
|
-
const inFd = (0,
|
|
23518
|
-
const errFd = (0,
|
|
23606
|
+
const inFd = (0, import_node_fs24.openSync)(sink, "r");
|
|
23607
|
+
const errFd = (0, import_node_fs24.openSync)(sink, "w");
|
|
23519
23608
|
try {
|
|
23520
23609
|
return (0, import_node_child_process7.execFileSync)(file, args, {
|
|
23521
23610
|
...opts,
|
|
@@ -23523,17 +23612,17 @@ function execFileCapture(file, args, opts = {}) {
|
|
|
23523
23612
|
stdio: [inFd, "pipe", errFd]
|
|
23524
23613
|
});
|
|
23525
23614
|
} finally {
|
|
23526
|
-
(0,
|
|
23527
|
-
(0,
|
|
23615
|
+
(0, import_node_fs24.closeSync)(inFd);
|
|
23616
|
+
(0, import_node_fs24.closeSync)(errFd);
|
|
23528
23617
|
}
|
|
23529
23618
|
}
|
|
23530
23619
|
var MMI_PLUGIN_ID2 = "mmi@mutmutco";
|
|
23531
23620
|
function stagedClaudePluginVersion() {
|
|
23532
23621
|
try {
|
|
23533
23622
|
const stagingRoot = (0, import_node_path21.join)((0, import_node_os12.homedir)(), ".claude", "plugins", "staging");
|
|
23534
|
-
const record = JSON.parse((0,
|
|
23623
|
+
const record = JSON.parse((0, import_node_fs24.readFileSync)((0, import_node_path21.join)(stagingRoot, "launch-target.json"), "utf8"));
|
|
23535
23624
|
if (typeof record.target !== "string" || typeof record.incoming !== "string") return void 0;
|
|
23536
|
-
const manifest = JSON.parse((0,
|
|
23625
|
+
const manifest = JSON.parse((0, import_node_fs24.readFileSync)((0, import_node_path21.join)(record.incoming, ".claude-plugin", "plugin.json"), "utf8"));
|
|
23537
23626
|
if (typeof manifest.version !== "string") return void 0;
|
|
23538
23627
|
return manifest.version === record.target ? record.target : void 0;
|
|
23539
23628
|
} catch {
|
|
@@ -23543,7 +23632,7 @@ function stagedClaudePluginVersion() {
|
|
|
23543
23632
|
function installedClaudePluginVersion() {
|
|
23544
23633
|
try {
|
|
23545
23634
|
const file = JSON.parse(
|
|
23546
|
-
(0,
|
|
23635
|
+
(0, import_node_fs24.readFileSync)((0, import_node_path21.join)((0, import_node_os12.homedir)(), ".claude", "plugins", "installed_plugins.json"), "utf8")
|
|
23547
23636
|
);
|
|
23548
23637
|
const versions = (file.plugins?.[MMI_PLUGIN_ID2] ?? []).map((r) => r.version).filter((v) => Boolean(v));
|
|
23549
23638
|
if (versions.length === 0) return void 0;
|
|
@@ -23555,12 +23644,12 @@ function installedClaudePluginVersion() {
|
|
|
23555
23644
|
function readHermesPluginEvidence(env = process.env) {
|
|
23556
23645
|
const host = hermesConfigRoot(env);
|
|
23557
23646
|
const root = hermesPluginRoot(env);
|
|
23558
|
-
const installRecordPresent = (0,
|
|
23647
|
+
const installRecordPresent = (0, import_node_fs24.existsSync)(root);
|
|
23559
23648
|
const manifestPath = (0, import_node_path21.join)(root, "plugin.yaml");
|
|
23560
23649
|
let installedVersion;
|
|
23561
23650
|
let manifest = "missing";
|
|
23562
23651
|
try {
|
|
23563
|
-
const text = (0,
|
|
23652
|
+
const text = (0, import_node_fs24.readFileSync)(manifestPath, "utf8");
|
|
23564
23653
|
let version;
|
|
23565
23654
|
try {
|
|
23566
23655
|
const parsed = JSON.parse(text).version;
|
|
@@ -23574,25 +23663,25 @@ function readHermesPluginEvidence(env = process.env) {
|
|
|
23574
23663
|
if (version) {
|
|
23575
23664
|
installedVersion = version;
|
|
23576
23665
|
manifest = "valid";
|
|
23577
|
-
} else if ((0,
|
|
23666
|
+
} else if ((0, import_node_fs24.existsSync)(manifestPath)) manifest = "invalid";
|
|
23578
23667
|
} catch {
|
|
23579
|
-
if ((0,
|
|
23668
|
+
if ((0, import_node_fs24.existsSync)(manifestPath)) manifest = "invalid";
|
|
23580
23669
|
}
|
|
23581
23670
|
let skills = false;
|
|
23582
23671
|
try {
|
|
23583
|
-
skills = (0,
|
|
23672
|
+
skills = (0, import_node_fs24.existsSync)((0, import_node_path21.join)(root, "skills")) && (0, import_node_fs24.statSync)((0, import_node_path21.join)(root, "skills")).isDirectory();
|
|
23584
23673
|
} catch {
|
|
23585
23674
|
}
|
|
23586
23675
|
let provisioned = false;
|
|
23587
23676
|
const provisionedRoot = (0, import_node_path21.join)(host, "skills", "mmi");
|
|
23588
23677
|
try {
|
|
23589
|
-
provisioned = (0,
|
|
23678
|
+
provisioned = (0, import_node_fs24.existsSync)(provisionedRoot) && (0, import_node_fs24.statSync)(provisionedRoot).isDirectory();
|
|
23590
23679
|
} catch {
|
|
23591
23680
|
}
|
|
23592
|
-
const treeOk = (0,
|
|
23681
|
+
const treeOk = (0, import_node_fs24.existsSync)((0, import_node_path21.join)(root, "__init__.py")) && skills && manifest === "valid";
|
|
23593
23682
|
const receipt = treeOk && !provisioned ? `hermes-skills-unprovisioned:${provisionedRoot}` : void 0;
|
|
23594
23683
|
return {
|
|
23595
|
-
hostPresent: (0,
|
|
23684
|
+
hostPresent: (0, import_node_fs24.existsSync)(host),
|
|
23596
23685
|
installRecordPresent,
|
|
23597
23686
|
manifest,
|
|
23598
23687
|
payloadPresent: treeOk && provisioned,
|
|
@@ -23644,7 +23733,7 @@ function readGitignore() {
|
|
|
23644
23733
|
const path2 = gitignorePath();
|
|
23645
23734
|
if (path2 === null) return null;
|
|
23646
23735
|
try {
|
|
23647
|
-
return (0,
|
|
23736
|
+
return (0, import_node_fs24.readFileSync)(path2, "utf8");
|
|
23648
23737
|
} catch {
|
|
23649
23738
|
return null;
|
|
23650
23739
|
}
|
|
@@ -23653,14 +23742,14 @@ function writeGitignore(content) {
|
|
|
23653
23742
|
const path2 = gitignorePath();
|
|
23654
23743
|
if (path2 === null) return false;
|
|
23655
23744
|
try {
|
|
23656
|
-
(0,
|
|
23745
|
+
(0, import_node_fs24.writeFileSync)(path2, content, "utf8");
|
|
23657
23746
|
return true;
|
|
23658
23747
|
} catch {
|
|
23659
23748
|
return false;
|
|
23660
23749
|
}
|
|
23661
23750
|
}
|
|
23662
23751
|
function lineEndingState(root) {
|
|
23663
|
-
const attributesPresent = (0,
|
|
23752
|
+
const attributesPresent = (0, import_node_fs24.existsSync)((0, import_node_path21.join)(root, ".gitattributes"));
|
|
23664
23753
|
try {
|
|
23665
23754
|
const output = execFileCapture("git", ["-C", root, "ls-files", "--eol", "--", ":(glob)**/*.sh"], {
|
|
23666
23755
|
windowsHide: true
|
|
@@ -23703,7 +23792,7 @@ function compatHolds(range, version) {
|
|
|
23703
23792
|
}
|
|
23704
23793
|
|
|
23705
23794
|
// src/claude-binary-doctor.ts
|
|
23706
|
-
var
|
|
23795
|
+
var import_node_fs25 = require("node:fs");
|
|
23707
23796
|
var import_node_os14 = require("node:os");
|
|
23708
23797
|
var import_node_path23 = require("node:path");
|
|
23709
23798
|
|
|
@@ -23813,16 +23902,16 @@ function globalNodeModulesRoots(host) {
|
|
|
23813
23902
|
function readHead(path2) {
|
|
23814
23903
|
let fd;
|
|
23815
23904
|
try {
|
|
23816
|
-
fd = (0,
|
|
23905
|
+
fd = (0, import_node_fs25.openSync)(path2, "r");
|
|
23817
23906
|
const buffer = new Uint8Array(MAGIC_HEAD_BYTES);
|
|
23818
|
-
const read = (0,
|
|
23907
|
+
const read = (0, import_node_fs25.readSync)(fd, buffer, 0, MAGIC_HEAD_BYTES, 0);
|
|
23819
23908
|
return buffer.subarray(0, read);
|
|
23820
23909
|
} catch {
|
|
23821
23910
|
return void 0;
|
|
23822
23911
|
} finally {
|
|
23823
23912
|
if (fd !== void 0) {
|
|
23824
23913
|
try {
|
|
23825
|
-
(0,
|
|
23914
|
+
(0, import_node_fs25.closeSync)(fd);
|
|
23826
23915
|
} catch {
|
|
23827
23916
|
}
|
|
23828
23917
|
}
|
|
@@ -23830,7 +23919,7 @@ function readHead(path2) {
|
|
|
23830
23919
|
}
|
|
23831
23920
|
function fileBytes(path2) {
|
|
23832
23921
|
try {
|
|
23833
|
-
return (0,
|
|
23922
|
+
return (0, import_node_fs25.statSync)(path2).size;
|
|
23834
23923
|
} catch {
|
|
23835
23924
|
return void 0;
|
|
23836
23925
|
}
|
|
@@ -23844,13 +23933,13 @@ function readClaudeBinaryState(host = {}) {
|
|
|
23844
23933
|
const arch = host.arch ?? process.arch;
|
|
23845
23934
|
const magic = EXECUTABLE_MAGIC[platform2];
|
|
23846
23935
|
if (!magic) return void 0;
|
|
23847
|
-
const packageRoot = globalNodeModulesRoots(host).map((root) => (0, import_node_path23.join)(root, ...PACKAGE.split("/"))).find((dir) => (0,
|
|
23936
|
+
const packageRoot = globalNodeModulesRoots(host).map((root) => (0, import_node_path23.join)(root, ...PACKAGE.split("/"))).find((dir) => (0, import_node_fs25.existsSync)((0, import_node_path23.join)(dir, "package.json")));
|
|
23848
23937
|
if (!packageRoot) return void 0;
|
|
23849
23938
|
const keys = platformPackageKeys(platform2, arch);
|
|
23850
23939
|
const fallbackPackage = `${PACKAGE}-${keys[0]}`;
|
|
23851
23940
|
let manifest;
|
|
23852
23941
|
try {
|
|
23853
|
-
manifest = JSON.parse((0,
|
|
23942
|
+
manifest = JSON.parse((0, import_node_fs25.readFileSync)((0, import_node_path23.join)(packageRoot, "package.json"), "utf8"));
|
|
23854
23943
|
} catch (e) {
|
|
23855
23944
|
return {
|
|
23856
23945
|
state: "unreadable",
|
|
@@ -23881,7 +23970,7 @@ function readClaudeBinaryState(host = {}) {
|
|
|
23881
23970
|
(0, import_node_path23.join)(packageRoot, "node_modules", ...name.split("/"), binName),
|
|
23882
23971
|
(0, import_node_path23.join)((0, import_node_path23.dirname)((0, import_node_path23.dirname)(packageRoot)), ...name.split("/"), binName)
|
|
23883
23972
|
];
|
|
23884
|
-
const found = published.map((name) => ({ name, path: binIn(name).find((file) => (0,
|
|
23973
|
+
const found = published.map((name) => ({ name, path: binIn(name).find((file) => (0, import_node_fs25.existsSync)(file)) })).find((c) => c.path);
|
|
23885
23974
|
const platformPackage = found?.name ?? published[0];
|
|
23886
23975
|
let source;
|
|
23887
23976
|
let sourceProblem;
|
|
@@ -23892,7 +23981,7 @@ function readClaudeBinaryState(host = {}) {
|
|
|
23892
23981
|
} else {
|
|
23893
23982
|
source = { path: found.path, bytes: fileBytes(found.path) ?? 0 };
|
|
23894
23983
|
}
|
|
23895
|
-
if (!(0,
|
|
23984
|
+
if (!(0, import_node_fs25.existsSync)(binPath)) {
|
|
23896
23985
|
return { state: "missing", binPath, expectedMagic: magic.name, platformPackage, ...source ? { source } : {}, ...sourceProblem ? { sourceProblem } : {} };
|
|
23897
23986
|
}
|
|
23898
23987
|
const head = readHead(binPath);
|
|
@@ -23935,9 +24024,9 @@ function healClaudeBinary(host = {}, onStep) {
|
|
|
23935
24024
|
const platform2 = host.platform ?? process.platform;
|
|
23936
24025
|
const aside = `${probe.binPath}.stub-${Date.now()}`;
|
|
23937
24026
|
let renamed = false;
|
|
23938
|
-
if ((0,
|
|
24027
|
+
if ((0, import_node_fs25.existsSync)(probe.binPath)) {
|
|
23939
24028
|
try {
|
|
23940
|
-
(0,
|
|
24029
|
+
(0, import_node_fs25.renameSync)(probe.binPath, aside);
|
|
23941
24030
|
renamed = true;
|
|
23942
24031
|
onStep?.(`renamed the stub aside: ${aside}`);
|
|
23943
24032
|
} catch (e) {
|
|
@@ -23946,12 +24035,12 @@ function healClaudeBinary(host = {}, onStep) {
|
|
|
23946
24035
|
}
|
|
23947
24036
|
try {
|
|
23948
24037
|
onStep?.(`copying ${probe.source.path} \u2192 ${probe.binPath} (${(probe.source.bytes / 1e6).toFixed(0)} MB)`);
|
|
23949
|
-
(0,
|
|
23950
|
-
if (platform2 !== "win32") (0,
|
|
24038
|
+
(0, import_node_fs25.copyFileSync)(probe.source.path, probe.binPath);
|
|
24039
|
+
if (platform2 !== "win32") (0, import_node_fs25.chmodSync)(probe.binPath, 493);
|
|
23951
24040
|
} catch (e) {
|
|
23952
24041
|
if (renamed) {
|
|
23953
24042
|
try {
|
|
23954
|
-
(0,
|
|
24043
|
+
(0, import_node_fs25.renameSync)(aside, probe.binPath);
|
|
23955
24044
|
} catch {
|
|
23956
24045
|
return { ok: false, detail: `copy failed (${e.message}) and the stub could not be restored \u2014 the original is at ${aside}` };
|
|
23957
24046
|
}
|
|
@@ -23965,7 +24054,7 @@ function healClaudeBinary(host = {}, onStep) {
|
|
|
23965
24054
|
let kept = false;
|
|
23966
24055
|
if (renamed) {
|
|
23967
24056
|
try {
|
|
23968
|
-
(0,
|
|
24057
|
+
(0, import_node_fs25.rmSync)(aside);
|
|
23969
24058
|
} catch {
|
|
23970
24059
|
kept = true;
|
|
23971
24060
|
}
|
|
@@ -24324,7 +24413,7 @@ function checkLineEndings(probe) {
|
|
|
24324
24413
|
}
|
|
24325
24414
|
|
|
24326
24415
|
// src/release-ledger.ts
|
|
24327
|
-
var
|
|
24416
|
+
var import_node_fs26 = require("node:fs");
|
|
24328
24417
|
var import_node_path25 = require("node:path");
|
|
24329
24418
|
var import_node_crypto9 = require("node:crypto");
|
|
24330
24419
|
|
|
@@ -24499,8 +24588,8 @@ function attachOutputNote(note, suffix) {
|
|
|
24499
24588
|
}
|
|
24500
24589
|
function writeFailingLegOutput(artifactPath, output) {
|
|
24501
24590
|
const fileLines = lastNonEmptyLines(output, LEDGER_OUTPUT_FILE_LINES);
|
|
24502
|
-
(0,
|
|
24503
|
-
(0,
|
|
24591
|
+
(0, import_node_fs26.mkdirSync)((0, import_node_path25.dirname)(artifactPath), { recursive: true });
|
|
24592
|
+
(0, import_node_fs26.writeFileSync)(artifactPath, `${fileLines.join("\n")}
|
|
24504
24593
|
`, "utf8");
|
|
24505
24594
|
const tail = fileLines.slice(-LEDGER_OUTPUT_NOTE_LINES).join("\n");
|
|
24506
24595
|
const noteSuffix = truncate(`failing-leg output: ${artifactPath}
|
|
@@ -24668,7 +24757,7 @@ function resolvePrimaryGitDir(cwd) {
|
|
|
24668
24757
|
}
|
|
24669
24758
|
let common;
|
|
24670
24759
|
try {
|
|
24671
|
-
common = (0,
|
|
24760
|
+
common = (0, import_node_fs26.readFileSync)((0, import_node_path25.join)(gitDir, "commondir"), "utf8").trim();
|
|
24672
24761
|
} catch (e) {
|
|
24673
24762
|
if (e.code !== "ENOENT") {
|
|
24674
24763
|
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)`);
|
|
@@ -24677,7 +24766,7 @@ function resolvePrimaryGitDir(cwd) {
|
|
|
24677
24766
|
if (!common) return gitDir;
|
|
24678
24767
|
const commonDir = (0, import_node_path25.isAbsolute)(common) ? common : (0, import_node_path25.resolve)(gitDir, common);
|
|
24679
24768
|
try {
|
|
24680
|
-
(0,
|
|
24769
|
+
(0, import_node_fs26.readFileSync)((0, import_node_path25.join)(commonDir, "HEAD"), "utf8");
|
|
24681
24770
|
} catch (e) {
|
|
24682
24771
|
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`);
|
|
24683
24772
|
}
|
|
@@ -24687,11 +24776,11 @@ function releaseLedgerPath(cwd) {
|
|
|
24687
24776
|
return (0, import_node_path25.join)(resolvePrimaryGitDir(cwd), "mmi-runtime", "release", "phases.json");
|
|
24688
24777
|
}
|
|
24689
24778
|
function atomicWriteJson(path2, ledger) {
|
|
24690
|
-
(0,
|
|
24779
|
+
(0, import_node_fs26.mkdirSync)((0, import_node_path25.dirname)(path2), { recursive: true });
|
|
24691
24780
|
const tmp = `${path2}.tmp-${process.pid}-${(0, import_node_crypto9.randomBytes)(4).toString("hex")}`;
|
|
24692
|
-
(0,
|
|
24781
|
+
(0, import_node_fs26.writeFileSync)(tmp, `${JSON.stringify(ledger, null, 2)}
|
|
24693
24782
|
`, "utf8");
|
|
24694
|
-
(0,
|
|
24783
|
+
(0, import_node_fs26.renameSync)(tmp, path2);
|
|
24695
24784
|
}
|
|
24696
24785
|
var LEDGER_LOCK_OPTS = { label: "release ledger", staleMs: 18e4, deadHolderSteal: true };
|
|
24697
24786
|
async function withLedgerLock(path2, fn, opts = {}) {
|
|
@@ -24738,7 +24827,7 @@ function describeTrainWriterToken(token) {
|
|
|
24738
24827
|
function liveTrainWriterHolder(cwd) {
|
|
24739
24828
|
let token;
|
|
24740
24829
|
try {
|
|
24741
|
-
token = (0,
|
|
24830
|
+
token = (0, import_node_fs26.readFileSync)(trainWriterLockPath(cwd), "utf8");
|
|
24742
24831
|
} catch {
|
|
24743
24832
|
return void 0;
|
|
24744
24833
|
}
|
|
@@ -24760,7 +24849,7 @@ async function acquireTrainWriterLock(cwd, verb) {
|
|
|
24760
24849
|
if (heldTrainWriter) heldTrainWriter.depth -= 1;
|
|
24761
24850
|
};
|
|
24762
24851
|
}
|
|
24763
|
-
(0,
|
|
24852
|
+
(0, import_node_fs26.mkdirSync)((0, import_node_path25.dirname)(lockPath), { recursive: true });
|
|
24764
24853
|
const opts = resolveFileLockOpts({ label: "train writer", staleMs: TRAIN_WRITER_STALE_MS, deadHolderSteal: true, maxWaitMs: 0, holder: verb });
|
|
24765
24854
|
let guard;
|
|
24766
24855
|
try {
|
|
@@ -24769,7 +24858,7 @@ async function acquireTrainWriterLock(cwd, verb) {
|
|
|
24769
24858
|
if (!(e instanceof FileLockBusyError)) throw e;
|
|
24770
24859
|
let token = "";
|
|
24771
24860
|
try {
|
|
24772
|
-
token = (0,
|
|
24861
|
+
token = (0, import_node_fs26.readFileSync)(lockPath, "utf8");
|
|
24773
24862
|
} catch {
|
|
24774
24863
|
token = "";
|
|
24775
24864
|
}
|
|
@@ -24804,7 +24893,7 @@ async function withReleaseLedger(path2, expected, fn, opts = {}) {
|
|
|
24804
24893
|
let current;
|
|
24805
24894
|
let raw;
|
|
24806
24895
|
try {
|
|
24807
|
-
raw = (0,
|
|
24896
|
+
raw = (0, import_node_fs26.readFileSync)(path2, "utf8");
|
|
24808
24897
|
} catch (e) {
|
|
24809
24898
|
if (e.code !== "ENOENT") {
|
|
24810
24899
|
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)`);
|
|
@@ -25473,7 +25562,7 @@ async function clearLedgerFile(path2, anchors, maxWaitMs) {
|
|
|
25473
25562
|
return withLedgerLock(path2, async (fence) => {
|
|
25474
25563
|
let raw;
|
|
25475
25564
|
try {
|
|
25476
|
-
raw = (0,
|
|
25565
|
+
raw = (0, import_node_fs26.readFileSync)(path2, "utf8");
|
|
25477
25566
|
} catch (e) {
|
|
25478
25567
|
if (e.code === "ENOENT") return { cleared: false };
|
|
25479
25568
|
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` };
|
|
@@ -25489,7 +25578,7 @@ async function clearLedgerFile(path2, anchors, maxWaitMs) {
|
|
|
25489
25578
|
} catch (e) {
|
|
25490
25579
|
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)})` };
|
|
25491
25580
|
}
|
|
25492
|
-
await fence(() => (0,
|
|
25581
|
+
await fence(() => (0, import_node_fs26.unlinkSync)(path2));
|
|
25493
25582
|
return { cleared: true, note: `cleared the release ledger at ${path2} for the live-proven aborted ${anchors.tag}` };
|
|
25494
25583
|
}, { maxWaitMs });
|
|
25495
25584
|
}
|
|
@@ -25649,7 +25738,7 @@ async function healStaleAlignmentLeg(deps, cwd, expected) {
|
|
|
25649
25738
|
return withLedgerLock(path2, async (fence) => {
|
|
25650
25739
|
let prior;
|
|
25651
25740
|
try {
|
|
25652
|
-
prior = parseReleaseLedger((0,
|
|
25741
|
+
prior = parseReleaseLedger((0, import_node_fs26.readFileSync)(path2, "utf8"));
|
|
25653
25742
|
} catch {
|
|
25654
25743
|
return void 0;
|
|
25655
25744
|
}
|
|
@@ -25674,7 +25763,7 @@ async function healUnfoldedRunLegs(deps, cwd, model) {
|
|
|
25674
25763
|
const path2 = releaseLedgerPath(cwd);
|
|
25675
25764
|
let prior;
|
|
25676
25765
|
try {
|
|
25677
|
-
prior = parseReleaseLedger((0,
|
|
25766
|
+
prior = parseReleaseLedger((0, import_node_fs26.readFileSync)(path2, "utf8"));
|
|
25678
25767
|
} catch {
|
|
25679
25768
|
return void 0;
|
|
25680
25769
|
}
|
|
@@ -25743,7 +25832,7 @@ async function supersedeContentCausedDeployLeg(deps, cwd) {
|
|
|
25743
25832
|
return withLedgerLock(path2, async (fence) => {
|
|
25744
25833
|
let prior;
|
|
25745
25834
|
try {
|
|
25746
|
-
prior = parseReleaseLedger((0,
|
|
25835
|
+
prior = parseReleaseLedger((0, import_node_fs26.readFileSync)(path2, "utf8"));
|
|
25747
25836
|
} catch (e) {
|
|
25748
25837
|
throw new ReleaseLedgerError(
|
|
25749
25838
|
"unreadable",
|
|
@@ -25841,10 +25930,10 @@ async function proveOriginPromotionOrArchived(deps, prior, path2, label, ref, fe
|
|
|
25841
25930
|
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})`);
|
|
25842
25931
|
}
|
|
25843
25932
|
const archivePath = (0, import_node_path25.join)((0, import_node_path25.dirname)(path2), `phases.archive-${prior.tag}.json`);
|
|
25844
|
-
if ((0,
|
|
25933
|
+
if ((0, import_node_fs26.existsSync)(archivePath)) {
|
|
25845
25934
|
throw new Error(`${label}: archive already exists at ${archivePath} \u2014 preserving both ledger records; resolve the collision by hand; nothing was written (${ref})`);
|
|
25846
25935
|
}
|
|
25847
|
-
await fence(() => (0,
|
|
25936
|
+
await fence(() => (0, import_node_fs26.renameSync)(path2, archivePath));
|
|
25848
25937
|
return "deleted";
|
|
25849
25938
|
}
|
|
25850
25939
|
async function supersedeContentCausedPublishLeg(deps, cwd) {
|
|
@@ -25852,7 +25941,7 @@ async function supersedeContentCausedPublishLeg(deps, cwd) {
|
|
|
25852
25941
|
return withLedgerLock(path2, async (fence) => {
|
|
25853
25942
|
let prior;
|
|
25854
25943
|
try {
|
|
25855
|
-
prior = parseReleaseLedger((0,
|
|
25944
|
+
prior = parseReleaseLedger((0, import_node_fs26.readFileSync)(path2, "utf8"));
|
|
25856
25945
|
} catch (e) {
|
|
25857
25946
|
throw new ReleaseLedgerError(
|
|
25858
25947
|
"unreadable",
|
|
@@ -25934,7 +26023,7 @@ async function supersedeContentCausedDeployAndPublishLegs(deps, cwd) {
|
|
|
25934
26023
|
return withLedgerLock(path2, async (fence) => {
|
|
25935
26024
|
let prior;
|
|
25936
26025
|
try {
|
|
25937
|
-
prior = parseReleaseLedger((0,
|
|
26026
|
+
prior = parseReleaseLedger((0, import_node_fs26.readFileSync)(path2, "utf8"));
|
|
25938
26027
|
} catch (e) {
|
|
25939
26028
|
throw new ReleaseLedgerError(
|
|
25940
26029
|
"unreadable",
|
|
@@ -26039,7 +26128,7 @@ async function supersedeContentCausedDeployAndPublishLegs(deps, cwd) {
|
|
|
26039
26128
|
async function reverifyPriorRunLegs(deps, path2, targetTag) {
|
|
26040
26129
|
let prior;
|
|
26041
26130
|
try {
|
|
26042
|
-
prior = parseReleaseLedger((0,
|
|
26131
|
+
prior = parseReleaseLedger((0, import_node_fs26.readFileSync)(path2, "utf8"));
|
|
26043
26132
|
} catch {
|
|
26044
26133
|
return;
|
|
26045
26134
|
}
|
|
@@ -26059,7 +26148,7 @@ async function beginReleaseLedger(deps, cwd, targetTag) {
|
|
|
26059
26148
|
return withLedgerLock(path2, async (fence) => {
|
|
26060
26149
|
let raw;
|
|
26061
26150
|
try {
|
|
26062
|
-
raw = (0,
|
|
26151
|
+
raw = (0, import_node_fs26.readFileSync)(path2, "utf8");
|
|
26063
26152
|
} catch (e) {
|
|
26064
26153
|
if (e.code === "ENOENT") return { ok: true };
|
|
26065
26154
|
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)` };
|
|
@@ -26099,13 +26188,13 @@ async function beginReleaseLedger(deps, cwd, targetTag) {
|
|
|
26099
26188
|
}
|
|
26100
26189
|
const archivePath = (0, import_node_path25.join)((0, import_node_path25.dirname)(path2), `phases.archive-${prior.tag}.json`);
|
|
26101
26190
|
try {
|
|
26102
|
-
await fence(() => (0,
|
|
26191
|
+
await fence(() => (0, import_node_fs26.unlinkSync)(archivePath));
|
|
26103
26192
|
} catch (e) {
|
|
26104
26193
|
if (e.code !== "ENOENT") {
|
|
26105
26194
|
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)` };
|
|
26106
26195
|
}
|
|
26107
26196
|
}
|
|
26108
|
-
await fence(() => (0,
|
|
26197
|
+
await fence(() => (0, import_node_fs26.renameSync)(path2, archivePath));
|
|
26109
26198
|
return { ok: true, note: `archived the completed release ledger ${prior.tag} to ${archivePath} (live-proven at ${prior.tagSha.slice(0, 12)})` };
|
|
26110
26199
|
});
|
|
26111
26200
|
}
|
|
@@ -26133,7 +26222,7 @@ async function retryHotfixDeployLegs(deps, cwd, opts = {}) {
|
|
|
26133
26222
|
return withLedgerLock(path2, async (fence) => {
|
|
26134
26223
|
let prior;
|
|
26135
26224
|
try {
|
|
26136
|
-
prior = parseReleaseLedger((0,
|
|
26225
|
+
prior = parseReleaseLedger((0, import_node_fs26.readFileSync)(path2, "utf8"));
|
|
26137
26226
|
} catch (e) {
|
|
26138
26227
|
throw new ReleaseLedgerError(
|
|
26139
26228
|
"unreadable",
|
|
@@ -26326,10 +26415,10 @@ function readOriginWorkflowsDefault(root, ref) {
|
|
|
26326
26415
|
}
|
|
26327
26416
|
var NPM_REGISTRY = "https://registry.npmjs.org";
|
|
26328
26417
|
async function probeRegistryWhoami(train) {
|
|
26329
|
-
const dir = (0,
|
|
26418
|
+
const dir = (0, import_node_fs27.mkdtempSync)((0, import_node_path26.join)((0, import_node_os15.tmpdir)(), "mmi-npmrc-"));
|
|
26330
26419
|
const rc = (0, import_node_path26.join)(dir, "npmrc");
|
|
26331
26420
|
try {
|
|
26332
|
-
(0,
|
|
26421
|
+
(0, import_node_fs27.writeFileSync)(rc, "//registry.npmjs.org/:_authToken=${NPM_TOKEN}\n");
|
|
26333
26422
|
await train.runSelf(["secrets", "use", "npm/NPM_TOKEN", "--slug", "_org", "--", "npm", "whoami", "--registry", NPM_REGISTRY, "--userconfig", rc]);
|
|
26334
26423
|
return { kind: "ok", detail: "the registry answered a login" };
|
|
26335
26424
|
} catch (e) {
|
|
@@ -26340,7 +26429,7 @@ async function probeRegistryWhoami(train) {
|
|
|
26340
26429
|
if (/\bE401\b|401 Unauthorized/.test(stderr)) return { kind: "rejected", detail: "npm whoami answered 401 Unauthorized" };
|
|
26341
26430
|
return { kind: "unverified", detail: first };
|
|
26342
26431
|
} finally {
|
|
26343
|
-
(0,
|
|
26432
|
+
(0, import_node_fs27.rmSync)(dir, { recursive: true, force: true });
|
|
26344
26433
|
}
|
|
26345
26434
|
}
|
|
26346
26435
|
var REGISTRY_TOKEN_ENV = /\b(NODE_AUTH_TOKEN|NPM_TOKEN)\b/;
|
|
@@ -26358,7 +26447,7 @@ var defaultDeps2 = {
|
|
|
26358
26447
|
ledgerPath: releaseLedgerPath,
|
|
26359
26448
|
readLedgerRaw: (path2) => {
|
|
26360
26449
|
try {
|
|
26361
|
-
return (0,
|
|
26450
|
+
return (0, import_node_fs27.readFileSync)(path2, "utf8");
|
|
26362
26451
|
} catch (e) {
|
|
26363
26452
|
if (e.code === "ENOENT") return void 0;
|
|
26364
26453
|
throw e;
|
|
@@ -26369,7 +26458,7 @@ var defaultDeps2 = {
|
|
|
26369
26458
|
trainWriterHolder: liveTrainWriterHolder,
|
|
26370
26459
|
readSurfacesRaw: (cwd) => {
|
|
26371
26460
|
try {
|
|
26372
|
-
return (0,
|
|
26461
|
+
return (0, import_node_fs27.readFileSync)((0, import_node_path26.join)(cwd, "surfaces.json"), "utf8");
|
|
26373
26462
|
} catch {
|
|
26374
26463
|
return void 0;
|
|
26375
26464
|
}
|
|
@@ -27008,7 +27097,7 @@ function formatTrainDoctor(v) {
|
|
|
27008
27097
|
|
|
27009
27098
|
// src/release-plain-words.ts
|
|
27010
27099
|
var import_promises3 = require("node:fs/promises");
|
|
27011
|
-
var
|
|
27100
|
+
var import_node_fs28 = require("node:fs");
|
|
27012
27101
|
function releaseCutByNotes(cutBy) {
|
|
27013
27102
|
return `## Internal
|
|
27014
27103
|
Cut by ${formatSessionIdentity(cutBy)}
|
|
@@ -27114,7 +27203,7 @@ function validateSuiteReleaseSummary(path2, pathTr) {
|
|
|
27114
27203
|
for (const [lang, file] of files) {
|
|
27115
27204
|
let content;
|
|
27116
27205
|
try {
|
|
27117
|
-
content = (0,
|
|
27206
|
+
content = (0, import_node_fs28.readFileSync)(file, "utf8");
|
|
27118
27207
|
} catch (e) {
|
|
27119
27208
|
throw new Error(`could not read summary file ${file}: ${e.message} \u2014 see ${SUMMARY_GUIDE}`);
|
|
27120
27209
|
}
|
|
@@ -27329,14 +27418,14 @@ function readLocalGateWorkflows() {
|
|
|
27329
27418
|
const dir = (0, import_node_path27.join)(".github", "workflows");
|
|
27330
27419
|
let names;
|
|
27331
27420
|
try {
|
|
27332
|
-
names = (0,
|
|
27421
|
+
names = (0, import_node_fs29.readdirSync)(dir);
|
|
27333
27422
|
} catch {
|
|
27334
27423
|
return null;
|
|
27335
27424
|
}
|
|
27336
27425
|
const files = [];
|
|
27337
27426
|
for (const name of names.filter(isGateWorkflowPath)) {
|
|
27338
27427
|
try {
|
|
27339
|
-
files.push({ path: `${dir}/${name}`.replace(/\\/g, "/"), body: (0,
|
|
27428
|
+
files.push({ path: `${dir}/${name}`.replace(/\\/g, "/"), body: (0, import_node_fs29.readFileSync)((0, import_node_path27.join)(dir, name), "utf8") });
|
|
27340
27429
|
} catch {
|
|
27341
27430
|
}
|
|
27342
27431
|
}
|
|
@@ -27346,14 +27435,14 @@ function readLocalWorkflows() {
|
|
|
27346
27435
|
const dir = (0, import_node_path27.join)(".github", "workflows");
|
|
27347
27436
|
let names;
|
|
27348
27437
|
try {
|
|
27349
|
-
names = (0,
|
|
27438
|
+
names = (0, import_node_fs29.readdirSync)(dir);
|
|
27350
27439
|
} catch {
|
|
27351
27440
|
return null;
|
|
27352
27441
|
}
|
|
27353
27442
|
const files = [];
|
|
27354
27443
|
for (const name of names.filter((n) => /\.ya?ml$/i.test(n))) {
|
|
27355
27444
|
try {
|
|
27356
|
-
files.push({ path: `${dir}/${name}`.replace(/\\/g, "/"), body: (0,
|
|
27445
|
+
files.push({ path: `${dir}/${name}`.replace(/\\/g, "/"), body: (0, import_node_fs29.readFileSync)((0, import_node_path27.join)(dir, name), "utf8") });
|
|
27357
27446
|
} catch {
|
|
27358
27447
|
}
|
|
27359
27448
|
}
|
|
@@ -28235,7 +28324,7 @@ async function activeRcandLedgerCandidate(deps, cwd) {
|
|
|
28235
28324
|
}
|
|
28236
28325
|
let prior;
|
|
28237
28326
|
try {
|
|
28238
|
-
prior = parseReleaseLedger((0,
|
|
28327
|
+
prior = parseReleaseLedger((0, import_node_fs29.readFileSync)(path2, "utf8"));
|
|
28239
28328
|
} catch {
|
|
28240
28329
|
return void 0;
|
|
28241
28330
|
}
|
|
@@ -30851,7 +30940,7 @@ var PRIMARY_GROUPS = [
|
|
|
30851
30940
|
["Setup and support", ["bootstrap", "secrets", "docs", "tests", "spawn", "dist"]],
|
|
30852
30941
|
["Coordinate and improve", ["wave", "report", "skill-lesson", "closure-rate"]]
|
|
30853
30942
|
];
|
|
30854
|
-
var OPERATIONAL_TOP_LEVEL = /* @__PURE__ */ new Set(["org", "runtime", "plugin", "packages", "archive-prune"]);
|
|
30943
|
+
var OPERATIONAL_TOP_LEVEL = /* @__PURE__ */ new Set(["org", "runtime", "plugin", "packages", "github", "archive-prune"]);
|
|
30855
30944
|
var CAMPAIGN_ORCHESTRATOR_TOP_LEVEL = /* @__PURE__ */ new Set(["pickup", "read"]);
|
|
30856
30945
|
var SUPPORT_PRIMARY = /* @__PURE__ */ new Set(["doctor", "whoami", "commands", "explain", "docs", "tests", "spawn", "dist", "wave", "report", "skill-lesson", "closure-rate"]);
|
|
30857
30946
|
var TOP_LEVEL_ORDER = /* @__PURE__ */ new Map();
|
|
@@ -30892,6 +30981,7 @@ var COMMAND_OWNERSHIP = {
|
|
|
30892
30981
|
stage: { module_owner: "cli/src/stage-commands.ts", consumer: "agent-workflow" },
|
|
30893
30982
|
pr: { module_owner: "cli/src/pr-commands.ts", consumer: "agent-workflow" },
|
|
30894
30983
|
api: { module_owner: "cli/src/api-read.ts", consumer: "agent-workflow" },
|
|
30984
|
+
github: { module_owner: "cli/src/github-budget.ts", consumer: "release-operator" },
|
|
30895
30985
|
read: { module_owner: "cli/src/app-read-broker.ts", consumer: "agent-workflow" },
|
|
30896
30986
|
ci: { module_owner: "cli/src/ci-audit.ts", consumer: "release-operator" },
|
|
30897
30987
|
rcand: { module_owner: "cli/src/train-commands.ts", consumer: "release-operator" },
|
|
@@ -31631,6 +31721,55 @@ function renderPluginCachePlan(plan, applied) {
|
|
|
31631
31721
|
return lines2.join("\n");
|
|
31632
31722
|
}
|
|
31633
31723
|
|
|
31724
|
+
// src/github-budget.ts
|
|
31725
|
+
init_cli_shared();
|
|
31726
|
+
function allowance(value) {
|
|
31727
|
+
const v = value;
|
|
31728
|
+
return v && [v.remaining, v.limit, v.reset].every((n) => typeof n === "number" && Number.isFinite(n)) ? { remaining: v.remaining, limit: v.limit, reset: v.reset } : null;
|
|
31729
|
+
}
|
|
31730
|
+
async function readGithubBudget(deps) {
|
|
31731
|
+
async function read(token) {
|
|
31732
|
+
try {
|
|
31733
|
+
const credential = await token();
|
|
31734
|
+
if (!credential) throw new Error("No identity");
|
|
31735
|
+
const res = await deps.fetch("https://api.github.com/rate_limit", {
|
|
31736
|
+
method: "GET",
|
|
31737
|
+
headers: { authorization: `Bearer ${credential}`, accept: "application/vnd.github+json", "user-agent": "mmi-cli" }
|
|
31738
|
+
});
|
|
31739
|
+
if (!res.ok) throw new Error("Unreadable");
|
|
31740
|
+
const body = await res.json();
|
|
31741
|
+
return { core: allowance(body.resources?.core), graphql: allowance(body.resources?.graphql) };
|
|
31742
|
+
} catch {
|
|
31743
|
+
return { core: null, graphql: null };
|
|
31744
|
+
}
|
|
31745
|
+
}
|
|
31746
|
+
const [personal, app1, app2] = await Promise.all([
|
|
31747
|
+
read(async () => {
|
|
31748
|
+
const env = { ...process.env };
|
|
31749
|
+
delete env.GH_TOKEN;
|
|
31750
|
+
delete env.GITHUB_TOKEN;
|
|
31751
|
+
return (await execFileP("gh", ["auth", "token"], { env })).stdout.trim();
|
|
31752
|
+
}),
|
|
31753
|
+
...APP_POOL_MEMBERS.map((keys) => read(async () => (await mintBudgetToken(deps, keys)).token))
|
|
31754
|
+
]);
|
|
31755
|
+
const pools = { personal, app1, app2 };
|
|
31756
|
+
const count = (v) => v ? `${v.remaining}/${v.limit}` : "unknown";
|
|
31757
|
+
const resets = [...new Set(Object.values(pools).flatMap((pool) => [pool.core, pool.graphql]).filter((v) => v !== null).map((v) => new Intl.DateTimeFormat("en-GB", {
|
|
31758
|
+
timeZone: "Europe/Istanbul",
|
|
31759
|
+
hour: "2-digit",
|
|
31760
|
+
minute: "2-digit",
|
|
31761
|
+
hourCycle: "h23"
|
|
31762
|
+
}).format(new Date(v.reset * 1e3))))].sort();
|
|
31763
|
+
const line = `GitHub budget \xB7 ${Object.entries(pools).map(([name, pool]) => `${name} core ${count(pool.core)} gql ${count(pool.graphql)}`).join(" \xB7 ")} \xB7 resets ${resets.join(", ") || "unknown"} (Istanbul)`;
|
|
31764
|
+
return { ...pools, line };
|
|
31765
|
+
}
|
|
31766
|
+
function registerGithubBudgetCommand(program3, deps) {
|
|
31767
|
+
program3.command("github").description("GitHub allowance visibility").command("budget").description("read personal and both App budgets (no allowance cost)").option("--json", "machine-readable output").action(async (options) => {
|
|
31768
|
+
const budget = await readGithubBudget(deps());
|
|
31769
|
+
console.log(options.json ? JSON.stringify(budget, null, 2) : budget.line);
|
|
31770
|
+
});
|
|
31771
|
+
}
|
|
31772
|
+
|
|
31634
31773
|
// src/board-commands.ts
|
|
31635
31774
|
init_cli_shared();
|
|
31636
31775
|
|
|
@@ -32132,7 +32271,7 @@ function registerBoardCommands(program3) {
|
|
|
32132
32271
|
}
|
|
32133
32272
|
|
|
32134
32273
|
// src/bootstrap-commands.ts
|
|
32135
|
-
var
|
|
32274
|
+
var import_node_fs33 = require("node:fs");
|
|
32136
32275
|
var import_node_os18 = require("node:os");
|
|
32137
32276
|
var import_node_path31 = require("node:path");
|
|
32138
32277
|
init_cli_shared();
|
|
@@ -32318,7 +32457,7 @@ init_github_client();
|
|
|
32318
32457
|
init_cli_shared();
|
|
32319
32458
|
|
|
32320
32459
|
// src/port-registry.ts
|
|
32321
|
-
var
|
|
32460
|
+
var import_node_fs30 = require("node:fs");
|
|
32322
32461
|
var import_node_path28 = require("node:path");
|
|
32323
32462
|
|
|
32324
32463
|
// ../infra/port-geometry.mjs
|
|
@@ -32333,8 +32472,8 @@ function nextPortBlock(registry2) {
|
|
|
32333
32472
|
return [base, base + PORT_SPAN];
|
|
32334
32473
|
}
|
|
32335
32474
|
function loadPortRegistry(path2) {
|
|
32336
|
-
if (!(0,
|
|
32337
|
-
const raw = JSON.parse((0,
|
|
32475
|
+
if (!(0, import_node_fs30.existsSync)(path2)) return {};
|
|
32476
|
+
const raw = JSON.parse((0, import_node_fs30.readFileSync)(path2, "utf8"));
|
|
32338
32477
|
const out = {};
|
|
32339
32478
|
for (const [key, value] of Object.entries(raw)) {
|
|
32340
32479
|
if (Array.isArray(value) && value.length === 2 && value.every((n) => typeof n === "number")) {
|
|
@@ -32364,7 +32503,7 @@ function existingPortRange(repo, registry2) {
|
|
|
32364
32503
|
function portRangeInfraAt(root, source) {
|
|
32365
32504
|
const registryPath = (0, import_node_path28.join)(root, "infra", "port-ranges.json");
|
|
32366
32505
|
const ddbScriptPath = (0, import_node_path28.join)(root, "infra", "port-ddb.mjs");
|
|
32367
|
-
if (!(0,
|
|
32506
|
+
if (!(0, import_node_fs30.existsSync)(registryPath) || !(0, import_node_fs30.existsSync)(ddbScriptPath)) return null;
|
|
32368
32507
|
return { root, source, registryPath, ddbScriptPath };
|
|
32369
32508
|
}
|
|
32370
32509
|
function resolvePortRangeInfra(cwd, packageDir) {
|
|
@@ -32446,7 +32585,7 @@ async function assignPersistedPortRange(repo, slug, reg, opts) {
|
|
|
32446
32585
|
}
|
|
32447
32586
|
|
|
32448
32587
|
// src/box-commands.ts
|
|
32449
|
-
var
|
|
32588
|
+
var import_node_fs32 = require("node:fs");
|
|
32450
32589
|
var import_node_child_process10 = require("node:child_process");
|
|
32451
32590
|
var import_node_os17 = require("node:os");
|
|
32452
32591
|
var import_node_path30 = require("node:path");
|
|
@@ -32580,7 +32719,7 @@ function applyRemoteScript(items, date) {
|
|
|
32580
32719
|
init_clean_exit();
|
|
32581
32720
|
|
|
32582
32721
|
// src/secrets-commands.ts
|
|
32583
|
-
var
|
|
32722
|
+
var import_node_fs31 = require("node:fs");
|
|
32584
32723
|
var import_node_path29 = require("node:path");
|
|
32585
32724
|
var import_node_os16 = require("node:os");
|
|
32586
32725
|
init_cli_shared();
|
|
@@ -33730,8 +33869,8 @@ async function decryptRailsCredentials(input) {
|
|
|
33730
33869
|
MMI_RAILS_CREDENTIALS_FILE: credentialsPath,
|
|
33731
33870
|
MMI_RAILS_MASTER_KEY_FILE: masterKeyPath
|
|
33732
33871
|
};
|
|
33733
|
-
if ((0,
|
|
33734
|
-
env.RAILS_MASTER_KEY = (0,
|
|
33872
|
+
if ((0, import_node_fs31.existsSync)(masterKeyPath)) {
|
|
33873
|
+
env.RAILS_MASTER_KEY = (0, import_node_fs31.readFileSync)(masterKeyPath, "utf8").trim();
|
|
33735
33874
|
}
|
|
33736
33875
|
const script = [
|
|
33737
33876
|
'require "json"',
|
|
@@ -33741,9 +33880,9 @@ async function decryptRailsCredentials(input) {
|
|
|
33741
33880
|
'config = ActiveSupport::EncryptedConfiguration.new(config_path: config_path, key_path: key_path, env_key: "RAILS_MASTER_KEY", raise_if_missing_key: true)',
|
|
33742
33881
|
"puts JSON.generate(config.config)"
|
|
33743
33882
|
].join("\n");
|
|
33744
|
-
const scriptDir = (0,
|
|
33883
|
+
const scriptDir = (0, import_node_fs31.mkdtempSync)((0, import_node_path29.join)((0, import_node_os16.tmpdir)(), "mmi-rails-decrypt-"));
|
|
33745
33884
|
const scriptPath = (0, import_node_path29.join)(scriptDir, "decrypt.rb");
|
|
33746
|
-
(0,
|
|
33885
|
+
(0, import_node_fs31.writeFileSync)(scriptPath, script, "utf8");
|
|
33747
33886
|
try {
|
|
33748
33887
|
const args = ["exec", "ruby", scriptPath];
|
|
33749
33888
|
const cmd = process.platform === "win32" ? "cmd.exe" : "bundle";
|
|
@@ -33755,7 +33894,7 @@ async function decryptRailsCredentials(input) {
|
|
|
33755
33894
|
});
|
|
33756
33895
|
return JSON.parse(stdout);
|
|
33757
33896
|
} finally {
|
|
33758
|
-
(0,
|
|
33897
|
+
(0, import_node_fs31.rmSync)(scriptDir, { recursive: true, force: true });
|
|
33759
33898
|
}
|
|
33760
33899
|
}
|
|
33761
33900
|
async function readSecretStdin() {
|
|
@@ -33845,7 +33984,7 @@ function registerSecretsCommands(program3) {
|
|
|
33845
33984
|
let body;
|
|
33846
33985
|
if (o.file) {
|
|
33847
33986
|
try {
|
|
33848
|
-
body = (0,
|
|
33987
|
+
body = (0, import_node_fs31.readFileSync)((0, import_node_path29.resolve)(o.file), "utf8");
|
|
33849
33988
|
} catch (e) {
|
|
33850
33989
|
return fail(`secrets org-catalog: cannot read --file ${o.file}: ${e.message}`);
|
|
33851
33990
|
}
|
|
@@ -33981,7 +34120,7 @@ function registerSecretsCommands(program3) {
|
|
|
33981
34120
|
{
|
|
33982
34121
|
...d,
|
|
33983
34122
|
decryptRailsCredentials,
|
|
33984
|
-
removeFile: (path2) => (0,
|
|
34123
|
+
removeFile: (path2) => (0, import_node_fs31.unlinkSync)((0, import_node_path29.resolve)(o.appDir ?? process.cwd(), path2))
|
|
33985
34124
|
},
|
|
33986
34125
|
{
|
|
33987
34126
|
repo: o.repo,
|
|
@@ -34237,7 +34376,7 @@ function registerBoxCommands(program3) {
|
|
|
34237
34376
|
}
|
|
34238
34377
|
const remote = command && command.length ? command.join(" ") : void 0;
|
|
34239
34378
|
const wroteScript = o.ssh && o.script ? o.script : null;
|
|
34240
|
-
if (wroteScript) (0,
|
|
34379
|
+
if (wroteScript) (0, import_node_fs32.writeFileSync)(wroteScript, sshRecipeScript(found, remote), "utf8");
|
|
34241
34380
|
if (o.json) {
|
|
34242
34381
|
console.log(JSON.stringify({
|
|
34243
34382
|
box: found,
|
|
@@ -34311,17 +34450,17 @@ function hubGitShow(ref) {
|
|
|
34311
34450
|
return (path2) => git3(["show", `${ref}:${path2}`]);
|
|
34312
34451
|
}
|
|
34313
34452
|
function runOnBox(found, script) {
|
|
34314
|
-
const dir = (0,
|
|
34453
|
+
const dir = (0, import_node_fs32.mkdtempSync)((0, import_node_path30.join)((0, import_node_os17.tmpdir)(), "mmi-box-control-"));
|
|
34315
34454
|
try {
|
|
34316
34455
|
const recipe = (0, import_node_path30.join)(dir, "recipe.sh");
|
|
34317
|
-
(0,
|
|
34456
|
+
(0, import_node_fs32.writeFileSync)(recipe, sshRecipeScript(found, "sh -s"), "utf8");
|
|
34318
34457
|
const r = (0, import_node_child_process10.spawnSync)("bash", [recipe], { input: script, encoding: "utf8", maxBuffer: 16 * 1024 * 1024, timeout: 18e4, windowsHide: true });
|
|
34319
34458
|
if (r.status !== 0) {
|
|
34320
34459
|
throw new UnreadableError(`box control: the ssh session to ${found.name} failed (exit ${r.status ?? r.signal}): ${(r.stderr || "").trim().split("\n").slice(-3).join(" | ")}`);
|
|
34321
34460
|
}
|
|
34322
34461
|
return r.stdout;
|
|
34323
34462
|
} finally {
|
|
34324
|
-
(0,
|
|
34463
|
+
(0, import_node_fs32.rmSync)(dir, { recursive: true, force: true });
|
|
34325
34464
|
}
|
|
34326
34465
|
}
|
|
34327
34466
|
function formatControl(mode, box, rows) {
|
|
@@ -35956,12 +36095,12 @@ async function verifyTargetedSeedPr(repo, number, plan, target, expected, client
|
|
|
35956
36095
|
// src/bootstrap-commands.ts
|
|
35957
36096
|
var execGitForSeedSource = async (args) => (await execFileP("git", args, { timeout: GIT_TIMEOUT_MS })).stdout;
|
|
35958
36097
|
async function gateRenderDiff(current, rendered) {
|
|
35959
|
-
const dir = (0,
|
|
36098
|
+
const dir = (0, import_node_fs33.mkdtempSync)((0, import_node_path31.join)((0, import_node_os18.tmpdir)(), "mmi-gate-diff-"));
|
|
35960
36099
|
const before = (0, import_node_path31.join)(dir, "committed-gate.yml");
|
|
35961
36100
|
const after = (0, import_node_path31.join)(dir, "registry-render.yml");
|
|
35962
36101
|
try {
|
|
35963
|
-
(0,
|
|
35964
|
-
(0,
|
|
36102
|
+
(0, import_node_fs33.writeFileSync)(before, current);
|
|
36103
|
+
(0, import_node_fs33.writeFileSync)(after, rendered);
|
|
35965
36104
|
try {
|
|
35966
36105
|
return (await execFileP("git", ["diff", "--no-index", "--", before, after], { timeout: GIT_TIMEOUT_MS })).stdout;
|
|
35967
36106
|
} catch (e) {
|
|
@@ -35970,7 +36109,7 @@ async function gateRenderDiff(current, rendered) {
|
|
|
35970
36109
|
throw e;
|
|
35971
36110
|
}
|
|
35972
36111
|
} finally {
|
|
35973
|
-
(0,
|
|
36112
|
+
(0, import_node_fs33.rmSync)(dir, { recursive: true, force: true });
|
|
35974
36113
|
}
|
|
35975
36114
|
}
|
|
35976
36115
|
function bootstrapTrainDoctorDeps() {
|
|
@@ -36030,13 +36169,13 @@ function registerBootstrapCommands(program3) {
|
|
|
36030
36169
|
})),
|
|
36031
36170
|
pushAllowlistOwners: verifyOwners,
|
|
36032
36171
|
pushAllowlistOwnersRead: verifyOwnersRead,
|
|
36033
|
-
readLocalFile: (path2) => path2 === "projects.json" && apiProjects != null ? apiProjects : (0,
|
|
36172
|
+
readLocalFile: (path2) => path2 === "projects.json" && apiProjects != null ? apiProjects : (0, import_node_fs33.existsSync)(path2) ? (0, import_node_fs33.readFileSync)(path2, "utf8") : null,
|
|
36034
36173
|
// requiredGcpApis is stored as an array by a JSON write, but `org project set --var KEY=VALUE` stores a raw
|
|
36035
36174
|
// comma-string — accept either so the seeded value verifies regardless of how it was written.
|
|
36036
36175
|
// #3689: the same committed map the org access audit reads (#3664), so a sanctioned admin is not a
|
|
36037
36176
|
// permanent bootstrap failure on one surface and an intended state on the other. Absent file → no
|
|
36038
36177
|
// sanction, which is the pre-#3664 behaviour.
|
|
36039
|
-
sanctionedAdmins: (0,
|
|
36178
|
+
sanctionedAdmins: (0, import_node_fs33.existsSync)("access-matrix.json") ? entriesValueByCanonicalRepo(loadSanctionedAdmins((0, import_node_fs33.readFileSync)("access-matrix.json", "utf8")), repo) : void 0,
|
|
36040
36179
|
requiredGcpApis: (() => {
|
|
36041
36180
|
const v = meta?.requiredGcpApis;
|
|
36042
36181
|
if (Array.isArray(v)) return v;
|
|
@@ -36114,14 +36253,14 @@ function registerBootstrapCommands(program3) {
|
|
|
36114
36253
|
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 () => {
|
|
36115
36254
|
const o = { repo: rawValue("--repo", ""), json: rawFlag("--json") };
|
|
36116
36255
|
const manifestPath = "skills/bootstrap/seeds/manifest.json";
|
|
36117
|
-
if (!(0,
|
|
36256
|
+
if (!(0, import_node_fs33.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`);
|
|
36118
36257
|
const seedSource = await resolveHubSeedSource(execGitForSeedSource);
|
|
36119
36258
|
if (!seedSource.ok) return fail(`bootstrap drift: ${seedSource.reason}`);
|
|
36120
|
-
const manifest = loadBootstrapSeeds((0,
|
|
36259
|
+
const manifest = loadBootstrapSeeds((0, import_node_fs33.readFileSync)(manifestPath, "utf8"));
|
|
36121
36260
|
const hubContents = /* @__PURE__ */ new Map();
|
|
36122
36261
|
for (const s of manifest.seeds) {
|
|
36123
36262
|
if (s.ownership !== "org" || s.source !== "self") continue;
|
|
36124
|
-
hubContents.set(s.target, (0,
|
|
36263
|
+
hubContents.set(s.target, (0, import_node_fs33.existsSync)(s.target) ? (0, import_node_fs33.readFileSync)(s.target, "utf8") : null);
|
|
36125
36264
|
}
|
|
36126
36265
|
let targets;
|
|
36127
36266
|
let classOf = (_repo) => "deployable";
|
|
@@ -36329,24 +36468,24 @@ function registerBootstrapCommands(program3) {
|
|
|
36329
36468
|
return;
|
|
36330
36469
|
}
|
|
36331
36470
|
const manifestPath = "skills/bootstrap/seeds/manifest.json";
|
|
36332
|
-
if (!(0,
|
|
36471
|
+
if (!(0, import_node_fs33.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`);
|
|
36333
36472
|
const seedSource = await resolveHubSeedSource(execGitForSeedSource);
|
|
36334
36473
|
if (!seedSource.ok) return fail(`bootstrap apply: ${seedSource.reason}`);
|
|
36335
|
-
const manifest = loadBootstrapSeeds((0,
|
|
36474
|
+
const manifest = loadBootstrapSeeds((0, import_node_fs33.readFileSync)(manifestPath, "utf8"));
|
|
36336
36475
|
const baseBranch = o.class === "content" ? "main" : "development";
|
|
36337
36476
|
const slug = parsedRepo.slug;
|
|
36338
36477
|
const onlyTarget = o.fromConfig && o.only.trim() === "gate.yml" ? ".github/workflows/gate.yml" : o.only.trim();
|
|
36339
36478
|
const gh2 = async (args) => execFileP("gh", args, { timeout: 2e4 });
|
|
36340
|
-
const readFile10 = (p) => (0,
|
|
36479
|
+
const readFile10 = (p) => (0, import_node_fs33.existsSync)(p) ? (0, import_node_fs33.readFileSync)(p, "utf8") : null;
|
|
36341
36480
|
const enc = (p) => p.split("/").map(encodeURIComponent).join("/");
|
|
36342
36481
|
const putSeed = async (target, content, ref, sha) => {
|
|
36343
36482
|
const tmp = (0, import_node_path31.join)((0, import_node_os18.tmpdir)(), `mmi-seed-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
|
|
36344
|
-
(0,
|
|
36483
|
+
(0, import_node_fs33.writeFileSync)(tmp, JSON.stringify(contentPutBody(target, content, ref, sha)), "utf8");
|
|
36345
36484
|
try {
|
|
36346
36485
|
await gh2(contentPutInputArgs(repo, target, tmp));
|
|
36347
36486
|
} finally {
|
|
36348
36487
|
try {
|
|
36349
|
-
(0,
|
|
36488
|
+
(0, import_node_fs33.unlinkSync)(tmp);
|
|
36350
36489
|
} catch {
|
|
36351
36490
|
}
|
|
36352
36491
|
}
|
|
@@ -36982,10 +37121,10 @@ LIVE apply to ${repo}:
|
|
|
36982
37121
|
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 () => {
|
|
36983
37122
|
const o = { target: rawValue("--target", ""), execute: rawFlag("--execute"), json: rawFlag("--json") };
|
|
36984
37123
|
const manifestPath = "skills/bootstrap/seeds/manifest.json";
|
|
36985
|
-
if (!(0,
|
|
37124
|
+
if (!(0, import_node_fs33.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`);
|
|
36986
37125
|
const seedSource = await resolveHubSeedSource(execGitForSeedSource);
|
|
36987
37126
|
if (!seedSource.ok) return fail(`bootstrap propagate: ${seedSource.reason}`);
|
|
36988
|
-
const manifest = loadBootstrapSeeds((0,
|
|
37127
|
+
const manifest = loadBootstrapSeeds((0, import_node_fs33.readFileSync)(manifestPath, "utf8"));
|
|
36989
37128
|
const propagatable = manifest.seeds.filter(isPropagatableSeed);
|
|
36990
37129
|
if (!o.target) {
|
|
36991
37130
|
return fail(`bootstrap propagate: --target <path> is required \u2014 one of:
|
|
@@ -36994,9 +37133,9 @@ LIVE apply to ${repo}:
|
|
|
36994
37133
|
const seed = propagatable.find((s) => s.target === o.target);
|
|
36995
37134
|
if (!seed) return fail(`bootstrap propagate: --target '${o.target}' names no centrally propagatable seed in ${manifestPath}. Propagatable targets:
|
|
36996
37135
|
${propagatable.map((s) => s.target).join("\n ")}`);
|
|
36997
|
-
if (!seed.managedBlock && !(0,
|
|
36998
|
-
const hubContent = seed.managedBlock ? null : (0,
|
|
36999
|
-
const readSeedFile2 = (path2) => (0,
|
|
37136
|
+
if (!seed.managedBlock && !(0, import_node_fs33.existsSync)(seed.target)) return fail(`bootstrap propagate: the Hub's own copy of '${seed.target}' is missing \u2014 nothing to propagate`);
|
|
37137
|
+
const hubContent = seed.managedBlock ? null : (0, import_node_fs33.readFileSync)(seed.target, "utf8");
|
|
37138
|
+
const readSeedFile2 = (path2) => (0, import_node_fs33.existsSync)(path2) ? (0, import_node_fs33.readFileSync)(path2, "utf8") : null;
|
|
37000
37139
|
const isWorkflowSeed = seed.target.startsWith(".github/workflows/");
|
|
37001
37140
|
const cfg = await loadConfig();
|
|
37002
37141
|
const projects = await fetchProjectsList(registryClientDeps(cfg));
|
|
@@ -37005,9 +37144,9 @@ LIVE apply to ${repo}:
|
|
|
37005
37144
|
}
|
|
37006
37145
|
const rosterRepos = collectRegistryRepos(projects).filter((r) => r.toLowerCase() !== "mutmutco/mmi-hub");
|
|
37007
37146
|
let independentCount = rosterRepos.length;
|
|
37008
|
-
if ((0,
|
|
37147
|
+
if ((0, import_node_fs33.existsSync)("projects.json")) {
|
|
37009
37148
|
try {
|
|
37010
|
-
const local = JSON.parse((0,
|
|
37149
|
+
const local = JSON.parse((0, import_node_fs33.readFileSync)("projects.json", "utf8"));
|
|
37011
37150
|
const localRepos = /* @__PURE__ */ new Set();
|
|
37012
37151
|
for (const p of local.projects ?? []) for (const r of p.repos ?? []) {
|
|
37013
37152
|
const full = (r.includes("/") ? r : `mutmutco/${r}`).toLowerCase();
|
|
@@ -37157,7 +37296,7 @@ LIVE apply to ${repo}:
|
|
|
37157
37296
|
if (plan.refusedNoCanary) return fail("bootstrap propagate --execute: no canary declared for this target \u2014 refusing to write (set seedCanary:true on exactly one registry repo)");
|
|
37158
37297
|
const headSha = seedSource.sha;
|
|
37159
37298
|
const sourceBlob = (await execGitForSeedSource(["rev-parse", `${headSha}:${seedSourcePath(seed)}`])).trim();
|
|
37160
|
-
const runbookUnaffected = (0,
|
|
37299
|
+
const runbookUnaffected = (0, import_node_fs33.existsSync)(RUNBOOK_UNAFFECTED_PATH) ? runbookUnaffectedReason(JSON.parse((0, import_node_fs33.readFileSync)(RUNBOOK_UNAFFECTED_PATH, "utf8")), seed.target, sourceBlob) : void 0;
|
|
37161
37300
|
for (const rec of plan.records) {
|
|
37162
37301
|
if (rec.action !== "open-pr") continue;
|
|
37163
37302
|
const baseBranch = classOf(rec.repo) === "content" ? "main" : "development";
|
|
@@ -37182,12 +37321,12 @@ LIVE apply to ${repo}:
|
|
|
37182
37321
|
const tmp = (0, import_node_path31.join)((0, import_node_os18.tmpdir)(), `mmi-propagate-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
|
|
37183
37322
|
const desiredContent = desiredByRepo.get(rec.repo);
|
|
37184
37323
|
if (desiredContent == null) return fail(`bootstrap propagate: no resolved content for ${rec.repo} ${seed.target} \u2014 refusing to write`);
|
|
37185
|
-
(0,
|
|
37324
|
+
(0, import_node_fs33.writeFileSync)(tmp, JSON.stringify(contentPutBody(seed.target, desiredContent, branch, existingSha, runbookUnaffected)), "utf8");
|
|
37186
37325
|
try {
|
|
37187
37326
|
await gh2(contentPutInputArgs(rec.repo, seed.target, tmp));
|
|
37188
37327
|
} finally {
|
|
37189
37328
|
try {
|
|
37190
|
-
(0,
|
|
37329
|
+
(0, import_node_fs33.unlinkSync)(tmp);
|
|
37191
37330
|
} catch {
|
|
37192
37331
|
}
|
|
37193
37332
|
}
|
|
@@ -37256,10 +37395,10 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
|
|
|
37256
37395
|
return fail(`bootstrap rollback: ${e.message}`);
|
|
37257
37396
|
}
|
|
37258
37397
|
const manifestPath = "skills/bootstrap/seeds/manifest.json";
|
|
37259
|
-
if (!(0,
|
|
37398
|
+
if (!(0, import_node_fs33.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)`);
|
|
37260
37399
|
const seedSource = await resolveHubSeedSource(execGitForSeedSource);
|
|
37261
37400
|
if (!seedSource.ok) return fail(`bootstrap rollback: ${seedSource.reason}`);
|
|
37262
|
-
const manifest = loadBootstrapSeeds((0,
|
|
37401
|
+
const manifest = loadBootstrapSeeds((0, import_node_fs33.readFileSync)(manifestPath, "utf8"));
|
|
37263
37402
|
const propagatable = manifest.seeds.filter(isPropagatableSeed);
|
|
37264
37403
|
if (!o.target) {
|
|
37265
37404
|
return fail(`bootstrap rollback: --target <path> is required \u2014 one of:
|
|
@@ -37276,10 +37415,10 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
|
|
|
37276
37415
|
const enc = (p) => p.split("/").map(encodeURIComponent).join("/");
|
|
37277
37416
|
let candidates;
|
|
37278
37417
|
if (o.record) {
|
|
37279
|
-
if (!(0,
|
|
37418
|
+
if (!(0, import_node_fs33.existsSync)(o.record)) return fail(`bootstrap rollback: --record '${o.record}' not found`);
|
|
37280
37419
|
let parsed;
|
|
37281
37420
|
try {
|
|
37282
|
-
parsed = JSON.parse((0,
|
|
37421
|
+
parsed = JSON.parse((0, import_node_fs33.readFileSync)(o.record, "utf8"));
|
|
37283
37422
|
} catch (e) {
|
|
37284
37423
|
return fail(`bootstrap rollback: --record '${o.record}' is not valid JSON: ${e.message}`);
|
|
37285
37424
|
}
|
|
@@ -37357,12 +37496,12 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
|
|
|
37357
37496
|
existingSha = void 0;
|
|
37358
37497
|
}
|
|
37359
37498
|
const tmp = (0, import_node_path31.join)((0, import_node_os18.tmpdir)(), `mmi-rollback-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
|
|
37360
|
-
(0,
|
|
37499
|
+
(0, import_node_fs33.writeFileSync)(tmp, JSON.stringify(contentPutBody(seed.target, preSeedContent, plan.branch, existingSha)), "utf8");
|
|
37361
37500
|
try {
|
|
37362
37501
|
await gh2(contentPutInputArgs(repo, seed.target, tmp));
|
|
37363
37502
|
} finally {
|
|
37364
37503
|
try {
|
|
37365
|
-
(0,
|
|
37504
|
+
(0, import_node_fs33.unlinkSync)(tmp);
|
|
37366
37505
|
} catch {
|
|
37367
37506
|
}
|
|
37368
37507
|
}
|
|
@@ -37819,7 +37958,7 @@ async function waitSuiteDev(deps, opts) {
|
|
|
37819
37958
|
}
|
|
37820
37959
|
|
|
37821
37960
|
// src/suite-train.ts
|
|
37822
|
-
var
|
|
37961
|
+
var import_node_fs34 = require("node:fs");
|
|
37823
37962
|
var import_node_path32 = require("node:path");
|
|
37824
37963
|
var import_node_crypto15 = require("node:crypto");
|
|
37825
37964
|
|
|
@@ -37906,7 +38045,7 @@ function suiteReleaseTag(rc) {
|
|
|
37906
38045
|
function readSuiteCut(path2) {
|
|
37907
38046
|
let raw;
|
|
37908
38047
|
try {
|
|
37909
|
-
raw = (0,
|
|
38048
|
+
raw = (0, import_node_fs34.readFileSync)(path2, "utf8");
|
|
37910
38049
|
} catch (e) {
|
|
37911
38050
|
if (e.code === "ENOENT") return void 0;
|
|
37912
38051
|
throw e;
|
|
@@ -37922,11 +38061,11 @@ function readSuiteCut(path2) {
|
|
|
37922
38061
|
return record;
|
|
37923
38062
|
}
|
|
37924
38063
|
function writeSuiteCut(path2, record) {
|
|
37925
|
-
(0,
|
|
38064
|
+
(0, import_node_fs34.mkdirSync)((0, import_node_path32.dirname)(path2), { recursive: true });
|
|
37926
38065
|
const temp = `${path2}.${(0, import_node_crypto15.randomBytes)(8).toString("hex")}.tmp`;
|
|
37927
38066
|
try {
|
|
37928
|
-
(0,
|
|
37929
|
-
(0,
|
|
38067
|
+
(0, import_node_fs34.writeFileSync)(temp, JSON.stringify(record, null, 2), { flag: "wx" });
|
|
38068
|
+
(0, import_node_fs34.renameSync)(temp, path2);
|
|
37930
38069
|
} catch (e) {
|
|
37931
38070
|
throw new Error(`suite cut record write failed at ${path2}: ${e.message}; stop, verify the file before retrying`);
|
|
37932
38071
|
}
|
|
@@ -37975,25 +38114,25 @@ async function suiteMarkAbandoned(deps, ownerGo = false) {
|
|
|
37975
38114
|
return tags.map((t) => `${t.repo}@${t.tag}`);
|
|
37976
38115
|
}
|
|
37977
38116
|
async function retireFailedLeadRcLedger(deps, ownerGo) {
|
|
37978
|
-
if (!(0,
|
|
38117
|
+
if (!(0, import_node_fs34.existsSync)(deps.ledgerPath)) return void 0;
|
|
37979
38118
|
return withLedgerLock(deps.ledgerPath, async (fence) => {
|
|
37980
|
-
const ledger = parseReleaseLedger((0,
|
|
38119
|
+
const ledger = parseReleaseLedger((0, import_node_fs34.readFileSync)(deps.ledgerPath, "utf8"));
|
|
37981
38120
|
const states = Object.values(ledger.phases).map((p) => p.state);
|
|
37982
38121
|
if (ledger.repo !== SUITE_REPO || ledger.lane !== "rcand" || ledger.phases.promotion.state === "complete" || !states.includes("failed")) return void 0;
|
|
37983
38122
|
if (!ownerGo) throw new Error(`the lead's failed rcand ledger for ${ledger.tag} blocks every train; retire it with suite abandon --owner-go`);
|
|
37984
38123
|
if ((await deps.rcHead())?.toLowerCase() === ledger.tagSha.toLowerCase()) throw new Error(`origin rc already points at ${ledger.tag}; it was promoted, so its ledger is not retired`);
|
|
37985
38124
|
const archive = (0, import_node_path32.join)((0, import_node_path32.dirname)(deps.ledgerPath), `phases.archive-${ledger.tag}.json`);
|
|
37986
|
-
if ((0,
|
|
38125
|
+
if ((0, import_node_fs34.existsSync)(archive)) throw new Error(`ledger archive already exists at ${archive}; inspect before retiring again`);
|
|
37987
38126
|
await deps.markAbandoned(SUITE_REPO, ledger.tag, ledger.tagSha);
|
|
37988
|
-
await fence(() => (0,
|
|
38127
|
+
await fence(() => (0, import_node_fs34.renameSync)(deps.ledgerPath, archive));
|
|
37989
38128
|
return `${ledger.tag} (ledger archived to ${archive})`;
|
|
37990
38129
|
});
|
|
37991
38130
|
}
|
|
37992
38131
|
function suiteAbandon(recordPath, ownerGo = false, now = /* @__PURE__ */ new Date()) {
|
|
37993
38132
|
const record = abandonableCut(recordPath, ownerGo);
|
|
37994
38133
|
const archive = `${recordPath}.abandoned-${record.leadDevelopment.slice(0, 12)}-${now.toISOString().replace(/[:.]/g, "")}.json`;
|
|
37995
|
-
if ((0,
|
|
37996
|
-
(0,
|
|
38134
|
+
if ((0, import_node_fs34.existsSync)(archive)) throw new Error(`abandoned-cut archive already exists at ${archive}; inspect before abandoning again`);
|
|
38135
|
+
(0, import_node_fs34.renameSync)(recordPath, archive);
|
|
37997
38136
|
return { archive, orphanTags: record.members.filter((m) => m.tag).map((m) => `${m.repo}@${m.tag}`) };
|
|
37998
38137
|
}
|
|
37999
38138
|
async function suiteRestoreMainPins(deps) {
|
|
@@ -38076,12 +38215,12 @@ async function suiteRcandRun(deps, opts) {
|
|
|
38076
38215
|
}
|
|
38077
38216
|
if ((record?.announcement === "sent" || record?.announcement === "skipped") && record.leadReleased) {
|
|
38078
38217
|
const archive = `${deps.recordPath}.${record.leadRcTag}.json`;
|
|
38079
|
-
if ((0,
|
|
38080
|
-
(0,
|
|
38218
|
+
if ((0, import_node_fs34.existsSync)(archive)) throw new Error(`suite cut archive already exists at ${archive}; inspect before a new cut`);
|
|
38219
|
+
(0, import_node_fs34.renameSync)(deps.recordPath, archive);
|
|
38081
38220
|
record = void 0;
|
|
38082
38221
|
}
|
|
38083
38222
|
if (record && !record.pinPr && !record.leadRcTag && record.members.every((m) => !m.tag)) {
|
|
38084
|
-
(0,
|
|
38223
|
+
(0, import_node_fs34.rmSync)(deps.recordPath, { force: true });
|
|
38085
38224
|
record = void 0;
|
|
38086
38225
|
}
|
|
38087
38226
|
if (!record) {
|
|
@@ -38135,7 +38274,7 @@ async function suiteRcandRun(deps, opts) {
|
|
|
38135
38274
|
quiet.push(member);
|
|
38136
38275
|
}
|
|
38137
38276
|
if (record.members.every((m) => m.carried || quiet.includes(m)) && await deps.contains(SUITE_REPO, record.leadDevelopment, record.leadPreviousRc)) {
|
|
38138
|
-
(0,
|
|
38277
|
+
(0, import_node_fs34.rmSync)(deps.recordPath, { force: true });
|
|
38139
38278
|
throw new Error("nothing to promote: neither MM-Work nor any module has new development commits since its rc; no suite cut started");
|
|
38140
38279
|
}
|
|
38141
38280
|
for (const member of quiet) {
|
|
@@ -38153,7 +38292,7 @@ async function suiteRcandRun(deps, opts) {
|
|
|
38153
38292
|
}
|
|
38154
38293
|
if (refusals.length) {
|
|
38155
38294
|
const untouched = record.members.every((m) => !m.tag) && !record.pinPr;
|
|
38156
|
-
if (untouched) (0,
|
|
38295
|
+
if (untouched) (0, import_node_fs34.rmSync)(deps.recordPath, { force: true });
|
|
38157
38296
|
throw new Error(`module rc serving is not ready; ${untouched ? "no suite cut started" : "no new tag was cut"}:
|
|
38158
38297
|
${refusals.join("\n")}
|
|
38159
38298
|
Each module must ship a live release that bind-mounts <deployPath>/data read-only and serves <data>/rc/module.js at /rc/module.js (docs/Guides/suite-trains.md).`);
|
|
@@ -38349,7 +38488,7 @@ var hotfixRecordPath = (deps) => (0, import_node_path32.join)((0, import_node_pa
|
|
|
38349
38488
|
function readSuiteHotfix(path2) {
|
|
38350
38489
|
let raw;
|
|
38351
38490
|
try {
|
|
38352
|
-
raw = (0,
|
|
38491
|
+
raw = (0, import_node_fs34.readFileSync)(path2, "utf8");
|
|
38353
38492
|
} catch (e) {
|
|
38354
38493
|
if (e.code === "ENOENT") return void 0;
|
|
38355
38494
|
throw e;
|
|
@@ -38392,7 +38531,7 @@ async function suiteHotfix(deps, opts) {
|
|
|
38392
38531
|
if (completed) record = void 0;
|
|
38393
38532
|
if (record && record.repo !== found.repo) throw new Error(`an unfinished suite hotfix for ${record.repo} is recorded; finish it (rerun with that member) first`);
|
|
38394
38533
|
if (!record?.tag) await deps.validateHotfixSummary();
|
|
38395
|
-
if (completed) (0,
|
|
38534
|
+
if (completed) (0, import_node_fs34.renameSync)(path2, `${path2}.${completed.leadTag}.json`);
|
|
38396
38535
|
const rec = record ?? { schema: "mmi-suite-hotfix/v1", member: found.id, repo: found.repo, from: opts.from, ...opts.ack?.length ? { ack: opts.ack } : {} };
|
|
38397
38536
|
const save = () => writeSuiteHotfix(path2, rec);
|
|
38398
38537
|
save();
|
|
@@ -38661,7 +38800,7 @@ async function runRcDataSwitch(deps, opts) {
|
|
|
38661
38800
|
// src/suite-train-io.ts
|
|
38662
38801
|
var import_node_child_process18 = require("node:child_process");
|
|
38663
38802
|
var import_node_path45 = require("node:path");
|
|
38664
|
-
var
|
|
38803
|
+
var import_node_fs47 = require("node:fs");
|
|
38665
38804
|
var import_node_path46 = require("node:path");
|
|
38666
38805
|
init_cli_shared();
|
|
38667
38806
|
|
|
@@ -40338,7 +40477,7 @@ function checkHotfixCarries(options) {
|
|
|
40338
40477
|
}
|
|
40339
40478
|
|
|
40340
40479
|
// src/merge-cleanup.ts
|
|
40341
|
-
var
|
|
40480
|
+
var import_node_fs36 = require("node:fs");
|
|
40342
40481
|
var import_node_path34 = require("node:path");
|
|
40343
40482
|
var import_node_os19 = require("node:os");
|
|
40344
40483
|
init_cli_shared();
|
|
@@ -40767,7 +40906,7 @@ function renderPrLandTable(entries) {
|
|
|
40767
40906
|
|
|
40768
40907
|
// src/test-policy-core.ts
|
|
40769
40908
|
var import_node_child_process13 = require("node:child_process");
|
|
40770
|
-
var
|
|
40909
|
+
var import_node_fs35 = require("node:fs");
|
|
40771
40910
|
var import_node_path33 = require("node:path");
|
|
40772
40911
|
|
|
40773
40912
|
// src/test-command-policy-shared.mjs
|
|
@@ -41337,7 +41476,7 @@ function loadPolicySource(root, explicitRef, diffBase) {
|
|
|
41337
41476
|
}
|
|
41338
41477
|
function readFileOrNull2(path2) {
|
|
41339
41478
|
try {
|
|
41340
|
-
return (0,
|
|
41479
|
+
return (0, import_node_fs35.readFileSync)(path2, "utf8");
|
|
41341
41480
|
} catch {
|
|
41342
41481
|
return null;
|
|
41343
41482
|
}
|
|
@@ -41365,10 +41504,10 @@ function classify(changed, policy, present = () => false) {
|
|
|
41365
41504
|
const removedProtected = [...removed].filter((p) => protectedBy.has(p)).map((p) => ({ path: p, why: protectedBy.get(p) ?? "" }));
|
|
41366
41505
|
return { mandatoryHits, untestedHits, testChanges, meaningfulTestChanges, addedTests, removedProtected };
|
|
41367
41506
|
}
|
|
41368
|
-
function unresolvedProtectedEntries(policy, root, exists = (path2) => (0,
|
|
41507
|
+
function unresolvedProtectedEntries(policy, root, exists = (path2) => (0, import_node_fs35.existsSync)(path2)) {
|
|
41369
41508
|
return (policy.protected ?? []).map((p) => p.path).filter((p) => !exists((0, import_node_path33.join)(root, p)));
|
|
41370
41509
|
}
|
|
41371
|
-
function unresolvedSatisfiers(policy, root, exists = (path2) => (0,
|
|
41510
|
+
function unresolvedSatisfiers(policy, root, exists = (path2) => (0, import_node_fs35.existsSync)(path2)) {
|
|
41372
41511
|
const declared = (policy.mandatory ?? []).flatMap((m) => m.satisfiedBy ?? []);
|
|
41373
41512
|
return [...new Set(declared)].filter((p) => !exists((0, import_node_path33.join)(root, p)));
|
|
41374
41513
|
}
|
|
@@ -41509,7 +41648,7 @@ function runTestPolicy(root, deps = {}) {
|
|
|
41509
41648
|
}
|
|
41510
41649
|
const loaded = deps.policy ? { policy: deps.policy, source: { ref: null, sha: null, path: POLICY_FILE } } : loadPolicySource(root, deps.policyRef, deps.base);
|
|
41511
41650
|
const { policy, source: policySource } = loaded;
|
|
41512
|
-
const exists = deps.exists ?? ((path2) => (0,
|
|
41651
|
+
const exists = deps.exists ?? ((path2) => (0, import_node_fs35.existsSync)(path2));
|
|
41513
41652
|
const counts = { mandatoryCount: (policy.mandatory ?? []).length, protectedCount: (policy.protected ?? []).length };
|
|
41514
41653
|
const base = deps.changed ? "(injected)" : deps.policyRef ? resolveHotfixBase(root) : resolveBase(root, deps.base);
|
|
41515
41654
|
const refusal = deps.changed ? null : untrustworthyRange(root, base);
|
|
@@ -41807,13 +41946,13 @@ function resolveSquashMergeBodyText(commits, allowedClosing, cwd) {
|
|
|
41807
41946
|
return rewritten === base ? null : rewritten;
|
|
41808
41947
|
}
|
|
41809
41948
|
function writeSquashBodyFile(body) {
|
|
41810
|
-
const dir = (0,
|
|
41949
|
+
const dir = (0, import_node_fs36.mkdtempSync)((0, import_node_path34.join)((0, import_node_os19.tmpdir)(), "mmi-squash-body-"));
|
|
41811
41950
|
const path2 = (0, import_node_path34.join)(dir, "body.txt");
|
|
41812
|
-
(0,
|
|
41951
|
+
(0, import_node_fs36.writeFileSync)(path2, body.endsWith("\n") ? body : `${body}
|
|
41813
41952
|
`, "utf8");
|
|
41814
41953
|
return { path: path2, cleanup: () => {
|
|
41815
41954
|
try {
|
|
41816
|
-
(0,
|
|
41955
|
+
(0, import_node_fs36.rmSync)(dir, { recursive: true, force: true });
|
|
41817
41956
|
} catch {
|
|
41818
41957
|
}
|
|
41819
41958
|
} };
|
|
@@ -42102,7 +42241,7 @@ function prMergeQueueLine(result) {
|
|
|
42102
42241
|
}
|
|
42103
42242
|
|
|
42104
42243
|
// src/project-info-sync.ts
|
|
42105
|
-
var
|
|
42244
|
+
var import_node_fs37 = require("node:fs");
|
|
42106
42245
|
var import_node_path35 = require("node:path");
|
|
42107
42246
|
var UPDATE_PROJECT_INFO = `mutation($projectId: ID!, $shortDescription: String!, $readme: String!) {
|
|
42108
42247
|
updateProjectV2(input: { projectId: $projectId, shortDescription: $shortDescription, readme: $readme }) {
|
|
@@ -42151,13 +42290,13 @@ function sharedName(entries, fallback) {
|
|
|
42151
42290
|
function buildProjectInfoSyncPlan(targetRepo2, project2, projects, repoRoot2) {
|
|
42152
42291
|
if (!project2.projectId) throw new Error(`org project sync-info: ${targetRepo2} registry META has no projectId`);
|
|
42153
42292
|
const readmePath = (0, import_node_path35.join)(repoRoot2, "README.md");
|
|
42154
|
-
if (!(0,
|
|
42293
|
+
if (!(0, import_node_fs37.existsSync)(readmePath)) throw new Error(`org project sync-info: ${targetRepo2} has no README.md`);
|
|
42155
42294
|
const entries = entriesFor(project2, projects);
|
|
42156
42295
|
const memberRepos = [...new Set(entries.flatMap((entry) => entry.repos ?? []))].filter((repo) => /^[^/]+\/[^/]+$/.test(repo)).sort((a, b) => a.localeCompare(b));
|
|
42157
42296
|
const projectName = sharedName(entries, project2.name?.trim() || targetRepo2.split("/").pop() || targetRepo2);
|
|
42158
42297
|
if (!memberRepos.length) throw new Error(`org project sync-info: project ${projectName} has no registered member repos`);
|
|
42159
42298
|
const entryNames = entries.map((entry) => entry.name?.trim()).filter((name) => Boolean(name));
|
|
42160
|
-
const shortDescription = memberRepos.length === 1 ? shortDescriptionFromReadme((0,
|
|
42299
|
+
const shortDescription = memberRepos.length === 1 ? shortDescriptionFromReadme((0, import_node_fs37.readFileSync)(readmePath, "utf8")) : `Shared work across ${new Intl.ListFormat("en", { type: "conjunction" }).format(entryNames)}.`;
|
|
42161
42300
|
const lines2 = [
|
|
42162
42301
|
`# ${projectName}`,
|
|
42163
42302
|
"",
|
|
@@ -42176,8 +42315,8 @@ function buildProjectInfoSyncPlan(targetRepo2, project2, projects, repoRoot2) {
|
|
|
42176
42315
|
const targetBase = `https://github.com/${targetRepo2}`;
|
|
42177
42316
|
const targetBranch = branchFor(targetRepo2, projects);
|
|
42178
42317
|
const orgDocs = [
|
|
42179
|
-
(0,
|
|
42180
|
-
(0,
|
|
42318
|
+
(0, import_node_fs37.existsSync)((0, import_node_path35.join)(repoRoot2, "architecture.md")) ? `- [Hub architecture](${targetBase}/blob/${targetBranch}/architecture.md)` : "",
|
|
42319
|
+
(0, import_node_fs37.existsSync)((0, import_node_path35.join)(repoRoot2, "docs", "Architecture", "agentic-dev-environment.md")) ? `- [Agentic development environment](${targetBase}/blob/${targetBranch}/docs/Architecture/agentic-dev-environment.md)` : ""
|
|
42181
42320
|
].filter(Boolean);
|
|
42182
42321
|
if (orgDocs.length) lines2.push("", "## Organisation docs", "", ...orgDocs);
|
|
42183
42322
|
return { projectId: project2.projectId, projectName, targetRepo: targetRepo2, memberRepos, shortDescription, readme: `${lines2.join("\n")}
|
|
@@ -42199,7 +42338,7 @@ async function syncProjectInfo(plan, client, apply) {
|
|
|
42199
42338
|
}
|
|
42200
42339
|
|
|
42201
42340
|
// src/train-commands.ts
|
|
42202
|
-
var
|
|
42341
|
+
var import_node_fs38 = require("node:fs");
|
|
42203
42342
|
var import_node_path36 = require("node:path");
|
|
42204
42343
|
init_cli_shared();
|
|
42205
42344
|
init_clean_exit();
|
|
@@ -42215,7 +42354,7 @@ function resolveReleaseBumpIntent(raw) {
|
|
|
42215
42354
|
}
|
|
42216
42355
|
function readRepoVersion() {
|
|
42217
42356
|
try {
|
|
42218
|
-
return JSON.parse((0,
|
|
42357
|
+
return JSON.parse((0, import_node_fs38.readFileSync)((0, import_node_path36.join)(process.cwd(), ".claude-plugin", "plugin.json"), "utf8")).version || void 0;
|
|
42219
42358
|
} catch {
|
|
42220
42359
|
return void 0;
|
|
42221
42360
|
}
|
|
@@ -42580,7 +42719,7 @@ async function openSuitePinPr(deps, input) {
|
|
|
42580
42719
|
|
|
42581
42720
|
// src/command-register-collaboration.ts
|
|
42582
42721
|
var import_node_child_process17 = require("node:child_process");
|
|
42583
|
-
var
|
|
42722
|
+
var import_node_fs46 = require("node:fs");
|
|
42584
42723
|
var import_promises8 = require("node:fs/promises");
|
|
42585
42724
|
init_clean_exit();
|
|
42586
42725
|
init_cli_shared();
|
|
@@ -42714,7 +42853,7 @@ init_github_client();
|
|
|
42714
42853
|
init_github_quota();
|
|
42715
42854
|
|
|
42716
42855
|
// src/issue-commands.ts
|
|
42717
|
-
var
|
|
42856
|
+
var import_node_fs39 = require("node:fs");
|
|
42718
42857
|
var import_node_crypto16 = require("node:crypto");
|
|
42719
42858
|
init_cli_shared();
|
|
42720
42859
|
init_clean_exit();
|
|
@@ -42907,7 +43046,7 @@ async function editIssue(client, options, deps = {}) {
|
|
|
42907
43046
|
const url = `https://github.com/${repo}/issues/${parsed.number}`;
|
|
42908
43047
|
const patch = {};
|
|
42909
43048
|
let bodyChanged = false;
|
|
42910
|
-
const textDeps = () => deps.textDeps ?? { readFile: (p, e) => Promise.resolve((0,
|
|
43049
|
+
const textDeps = () => deps.textDeps ?? { readFile: (p, e) => Promise.resolve((0, import_node_fs39.readFileSync)(p, e)), readStdin: () => Promise.resolve("") };
|
|
42911
43050
|
if (options.titleFile !== void 0) {
|
|
42912
43051
|
patch.title = await resolveIssueTitle({ title: options.title, titleFile: options.titleFile }, textDeps());
|
|
42913
43052
|
} else if (options.title !== void 0) {
|
|
@@ -43570,7 +43709,7 @@ function extendCreateCommand(issue, batchAttach) {
|
|
|
43570
43709
|
if (opts.batch) {
|
|
43571
43710
|
let specs;
|
|
43572
43711
|
try {
|
|
43573
|
-
const raw = (0,
|
|
43712
|
+
const raw = (0, import_node_fs39.readFileSync)(opts.batch, "utf8");
|
|
43574
43713
|
specs = JSON.parse(raw);
|
|
43575
43714
|
if (!Array.isArray(specs)) {
|
|
43576
43715
|
const top = specs === null ? "null" : typeof specs === "object" ? `an object with keys: ${Object.keys(specs).join(", ") || "(none)"}` : `a ${typeof specs}`;
|
|
@@ -43647,7 +43786,7 @@ ${lines2}`, {
|
|
|
43647
43786
|
}
|
|
43648
43787
|
|
|
43649
43788
|
// src/post-merge-recon.ts
|
|
43650
|
-
var
|
|
43789
|
+
var import_node_fs40 = require("node:fs");
|
|
43651
43790
|
var import_node_path38 = require("node:path");
|
|
43652
43791
|
|
|
43653
43792
|
// src/cross-repo-filing-issue.ts
|
|
@@ -43817,16 +43956,16 @@ function buildPostMergeReconRecovery(input) {
|
|
|
43817
43956
|
}
|
|
43818
43957
|
function writePostMergeReconRecovery(cwd, recovery) {
|
|
43819
43958
|
const path2 = postMergeReconStatePath(cwd, recovery.repo, recovery.pr);
|
|
43820
|
-
(0,
|
|
43821
|
-
(0,
|
|
43959
|
+
(0, import_node_fs40.mkdirSync)((0, import_node_path38.dirname)(path2), { recursive: true });
|
|
43960
|
+
(0, import_node_fs40.writeFileSync)(path2, `${JSON.stringify(recovery, null, 2)}
|
|
43822
43961
|
`, "utf8");
|
|
43823
43962
|
return path2;
|
|
43824
43963
|
}
|
|
43825
43964
|
function clearPostMergeReconRecovery(cwd, repo, pr) {
|
|
43826
43965
|
const path2 = postMergeReconStatePath(cwd, repo, pr);
|
|
43827
|
-
if (!(0,
|
|
43966
|
+
if (!(0, import_node_fs40.existsSync)(path2)) return;
|
|
43828
43967
|
try {
|
|
43829
|
-
(0,
|
|
43968
|
+
(0, import_node_fs40.unlinkSync)(path2);
|
|
43830
43969
|
} catch {
|
|
43831
43970
|
}
|
|
43832
43971
|
}
|
|
@@ -44302,7 +44441,7 @@ function registerPrLifecycleCommands(program3) {
|
|
|
44302
44441
|
|
|
44303
44442
|
// src/review-verdict.ts
|
|
44304
44443
|
var import_node_child_process14 = require("node:child_process");
|
|
44305
|
-
var
|
|
44444
|
+
var import_node_fs41 = require("node:fs");
|
|
44306
44445
|
var import_node_os21 = require("node:os");
|
|
44307
44446
|
var import_node_path39 = require("node:path");
|
|
44308
44447
|
init_cli_shared();
|
|
@@ -44469,15 +44608,15 @@ async function readPrIssueComments(number, repo) {
|
|
|
44469
44608
|
return comments;
|
|
44470
44609
|
}
|
|
44471
44610
|
async function postPrCommentFromFile(number, repo, body) {
|
|
44472
|
-
const dir = (0,
|
|
44611
|
+
const dir = (0, import_node_fs41.mkdtempSync)((0, import_node_path39.join)((0, import_node_os21.tmpdir)(), "mmi-review-verdict-"));
|
|
44473
44612
|
const path2 = (0, import_node_path39.join)(dir, "body.md");
|
|
44474
44613
|
try {
|
|
44475
|
-
(0,
|
|
44614
|
+
(0, import_node_fs41.writeFileSync)(path2, body, "utf8");
|
|
44476
44615
|
const { stdout } = await execFileP("gh", ["pr", "comment", number, "--repo", repo, "--body-file", path2], { timeout: GH_MUTATION_TIMEOUT_MS });
|
|
44477
44616
|
return stdout.trim();
|
|
44478
44617
|
} finally {
|
|
44479
44618
|
try {
|
|
44480
|
-
(0,
|
|
44619
|
+
(0, import_node_fs41.rmSync)(dir, { recursive: true, force: true });
|
|
44481
44620
|
} catch {
|
|
44482
44621
|
}
|
|
44483
44622
|
}
|
|
@@ -44711,17 +44850,17 @@ async function prCreateClaimRefusal(body, repoOption, deps = {}) {
|
|
|
44711
44850
|
}
|
|
44712
44851
|
|
|
44713
44852
|
// src/worktree-residue-sweep.ts
|
|
44714
|
-
var
|
|
44853
|
+
var import_node_fs45 = require("node:fs");
|
|
44715
44854
|
var import_node_path43 = require("node:path");
|
|
44716
44855
|
|
|
44717
44856
|
// src/worktree-merge-cleanup.ts
|
|
44718
|
-
var
|
|
44857
|
+
var import_node_fs44 = require("node:fs");
|
|
44719
44858
|
var import_node_path42 = require("node:path");
|
|
44720
44859
|
init_cli_shared();
|
|
44721
44860
|
|
|
44722
44861
|
// src/stage-runner.ts
|
|
44723
44862
|
var import_node_child_process16 = require("node:child_process");
|
|
44724
|
-
var
|
|
44863
|
+
var import_node_fs43 = require("node:fs");
|
|
44725
44864
|
var import_node_path41 = require("node:path");
|
|
44726
44865
|
var import_node_net = require("node:net");
|
|
44727
44866
|
var import_node_util5 = require("node:util");
|
|
@@ -44732,7 +44871,7 @@ function normalizeEol2(s) {
|
|
|
44732
44871
|
}
|
|
44733
44872
|
|
|
44734
44873
|
// src/env-detection.ts
|
|
44735
|
-
var
|
|
44874
|
+
var import_node_fs42 = require("node:fs");
|
|
44736
44875
|
var import_node_path40 = require("node:path");
|
|
44737
44876
|
var SKIPPED_DIRS = /* @__PURE__ */ new Set([".git", "node_modules", "dist", ".jerv", ".pi", ".venv", "venv"]);
|
|
44738
44877
|
function isEnvBaseName(name) {
|
|
@@ -44743,7 +44882,7 @@ function findEnvFiles(root) {
|
|
|
44743
44882
|
const walk2 = (dir, rel) => {
|
|
44744
44883
|
let entries;
|
|
44745
44884
|
try {
|
|
44746
|
-
entries = (0,
|
|
44885
|
+
entries = (0, import_node_fs42.readdirSync)(dir, { withFileTypes: true });
|
|
44747
44886
|
} catch {
|
|
44748
44887
|
return;
|
|
44749
44888
|
}
|
|
@@ -44757,7 +44896,7 @@ function findEnvFiles(root) {
|
|
|
44757
44896
|
if (isEnvBaseName(entry.name)) {
|
|
44758
44897
|
let isDir = false;
|
|
44759
44898
|
try {
|
|
44760
|
-
isDir = (0,
|
|
44899
|
+
isDir = (0, import_node_fs42.lstatSync)((0, import_node_path40.join)(dir, entry.name)).isDirectory();
|
|
44761
44900
|
} catch {
|
|
44762
44901
|
}
|
|
44763
44902
|
if (!isDir) found.push(relPath);
|
|
@@ -44896,12 +45035,12 @@ var DOCKER_TIMEOUT_MS = 15e3;
|
|
|
44896
45035
|
function stageBash() {
|
|
44897
45036
|
if (process.platform !== "win32") return "bash";
|
|
44898
45037
|
const configured = process.env.SHELL;
|
|
44899
|
-
if (configured && (0, import_node_path41.isAbsolute)(configured) && /[/\\]bash(?:\.exe)?$/i.test(configured) && !/[/\\](?:System32|Sysnative)[/\\]bash(?:\.exe)?$/i.test(configured) && (0,
|
|
45038
|
+
if (configured && (0, import_node_path41.isAbsolute)(configured) && /[/\\]bash(?:\.exe)?$/i.test(configured) && !/[/\\](?:System32|Sysnative)[/\\]bash(?:\.exe)?$/i.test(configured) && (0, import_node_fs43.existsSync)(configured)) return configured;
|
|
44900
45039
|
const candidates = [
|
|
44901
45040
|
(0, import_node_path41.join)(process.env.ProgramFiles || "C:\\Program Files", "Git", "bin", "bash.exe"),
|
|
44902
45041
|
...process.env.LOCALAPPDATA ? [(0, import_node_path41.join)(process.env.LOCALAPPDATA, "Programs", "Git", "bin", "bash.exe")] : []
|
|
44903
45042
|
];
|
|
44904
|
-
const bash = candidates.find((path2) => (0,
|
|
45043
|
+
const bash = candidates.find((path2) => (0, import_node_fs43.existsSync)(path2));
|
|
44905
45044
|
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.");
|
|
44906
45045
|
return bash;
|
|
44907
45046
|
}
|
|
@@ -45257,7 +45396,7 @@ function stageProcessEnv(stagePort, extraEnv) {
|
|
|
45257
45396
|
function composeResolvesPort(cwd) {
|
|
45258
45397
|
if (process.env.PORT) return true;
|
|
45259
45398
|
const envFile = (0, import_node_path41.join)(cwd, ".env");
|
|
45260
|
-
return (0,
|
|
45399
|
+
return (0, import_node_fs43.existsSync)(envFile) && envFileKeys((0, import_node_fs43.readFileSync)(envFile, "utf8")).has("PORT");
|
|
45261
45400
|
}
|
|
45262
45401
|
function stageComposeEnv(config, stagePort, vaultEnvMerge, cwd) {
|
|
45263
45402
|
const composeProject = config.env?.COMPOSE_PROJECT_NAME ?? vaultEnvMerge?.COMPOSE_PROJECT_NAME ?? stageComposeProjectName(cwd);
|
|
@@ -45272,13 +45411,13 @@ function stageComposeEnv(config, stagePort, vaultEnvMerge, cwd) {
|
|
|
45272
45411
|
function stageComposeFiles(cwd) {
|
|
45273
45412
|
const files = ["docker-compose.yml"];
|
|
45274
45413
|
for (const conventional of ["docker-compose.override.yml", "docker-compose.override.yaml"]) {
|
|
45275
|
-
if ((0,
|
|
45414
|
+
if ((0, import_node_fs43.existsSync)((0, import_node_path41.join)(cwd, conventional))) files.push(conventional);
|
|
45276
45415
|
}
|
|
45277
45416
|
return [...files, RUNTIME_ENV_OVERRIDE_RELPATH];
|
|
45278
45417
|
}
|
|
45279
45418
|
async function prepareRuntimeEnvPassthrough(cwd, composeEnv, vaultEnvMerge) {
|
|
45280
45419
|
const keys = Object.keys(vaultEnvMerge ?? {});
|
|
45281
|
-
if (!keys.length || !(0,
|
|
45420
|
+
if (!keys.length || !(0, import_node_fs43.existsSync)((0, import_node_path41.join)(cwd, "docker-compose.yml"))) return {};
|
|
45282
45421
|
let configJson;
|
|
45283
45422
|
try {
|
|
45284
45423
|
const { stdout } = await execFileP3("docker", ["compose", "config", "--format", "json"], {
|
|
@@ -45295,20 +45434,20 @@ async function prepareRuntimeEnvPassthrough(cwd, composeEnv, vaultEnvMerge) {
|
|
|
45295
45434
|
const body = renderRuntimeEnvOverride(runtimeEnvMarkedServices(configJson), keys, runtimeEnvExcludes(configJson), runtimeEnvSelects(configJson));
|
|
45296
45435
|
if (!body) return {};
|
|
45297
45436
|
const overridePath = (0, import_node_path41.join)(cwd, RUNTIME_ENV_OVERRIDE_RELPATH);
|
|
45298
|
-
(0,
|
|
45299
|
-
(0,
|
|
45437
|
+
(0, import_node_fs43.mkdirSync)((0, import_node_path41.join)(cwd, "tmp", "stage"), { recursive: true });
|
|
45438
|
+
(0, import_node_fs43.writeFileSync)(overridePath, body, "utf8");
|
|
45300
45439
|
return stageComposeFileEnv(stageComposeFiles(cwd));
|
|
45301
45440
|
}
|
|
45302
45441
|
async function ensureStageRuntimeEnv(config, opts, cwd) {
|
|
45303
45442
|
if (!config.ensureEnv) return;
|
|
45304
45443
|
const target = (0, import_node_path41.join)(cwd, config.ensureEnv.target);
|
|
45305
45444
|
const example = (0, import_node_path41.join)(cwd, config.ensureEnv.example);
|
|
45306
|
-
if (!(0,
|
|
45307
|
-
(0,
|
|
45308
|
-
} else if ((0,
|
|
45309
|
-
const stale = detectStaleEnvFile((0,
|
|
45310
|
-
exampleMtimeMs: (0,
|
|
45311
|
-
targetMtimeMs: (0,
|
|
45445
|
+
if (!(0, import_node_fs43.existsSync)(target) && (0, import_node_fs43.existsSync)(example)) {
|
|
45446
|
+
(0, import_node_fs43.copyFileSync)(example, target);
|
|
45447
|
+
} else if ((0, import_node_fs43.existsSync)(target) && (0, import_node_fs43.existsSync)(example)) {
|
|
45448
|
+
const stale = detectStaleEnvFile((0, import_node_fs43.readFileSync)(example, "utf8"), (0, import_node_fs43.readFileSync)(target, "utf8"), {
|
|
45449
|
+
exampleMtimeMs: (0, import_node_fs43.statSync)(example).mtimeMs,
|
|
45450
|
+
targetMtimeMs: (0, import_node_fs43.statSync)(target).mtimeMs
|
|
45312
45451
|
});
|
|
45313
45452
|
if (stale) {
|
|
45314
45453
|
const msg = `stale ${config.ensureEnv.target} (${stale}) \u2014 delete it or refresh from ${config.ensureEnv.example} before re-running /stage`;
|
|
@@ -45316,8 +45455,8 @@ async function ensureStageRuntimeEnv(config, opts, cwd) {
|
|
|
45316
45455
|
console.error(`mmi-cli stage: ${msg} (allowed via --allow-stale-env)`);
|
|
45317
45456
|
}
|
|
45318
45457
|
}
|
|
45319
|
-
if (opts.vaultEnvMerge && Object.keys(opts.vaultEnvMerge).length && (0,
|
|
45320
|
-
(0,
|
|
45458
|
+
if (opts.vaultEnvMerge && Object.keys(opts.vaultEnvMerge).length && (0, import_node_fs43.existsSync)(target)) {
|
|
45459
|
+
(0, import_node_fs43.writeFileSync)(target, mergeEnvSecretsIntoFile((0, import_node_fs43.readFileSync)(target, "utf8"), opts.vaultEnvMerge), "utf8");
|
|
45321
45460
|
}
|
|
45322
45461
|
}
|
|
45323
45462
|
async function gitText(cwd, args) {
|
|
@@ -45347,20 +45486,20 @@ async function resolveGlobalStatePath(cwd, explicit) {
|
|
|
45347
45486
|
return void 0;
|
|
45348
45487
|
}
|
|
45349
45488
|
function readState(path2) {
|
|
45350
|
-
if (!(0,
|
|
45489
|
+
if (!(0, import_node_fs43.existsSync)(path2)) return null;
|
|
45351
45490
|
try {
|
|
45352
|
-
return JSON.parse((0,
|
|
45491
|
+
return JSON.parse((0, import_node_fs43.readFileSync)(path2, "utf8"));
|
|
45353
45492
|
} catch {
|
|
45354
45493
|
return null;
|
|
45355
45494
|
}
|
|
45356
45495
|
}
|
|
45357
45496
|
function mkdirFor(path2) {
|
|
45358
45497
|
const dir = path2.slice(0, Math.max(path2.lastIndexOf("/"), path2.lastIndexOf("\\")));
|
|
45359
|
-
(0,
|
|
45498
|
+
(0, import_node_fs43.mkdirSync)(dir, { recursive: true });
|
|
45360
45499
|
}
|
|
45361
45500
|
function writeState(path2, state) {
|
|
45362
45501
|
mkdirFor(path2);
|
|
45363
|
-
(0,
|
|
45502
|
+
(0, import_node_fs43.writeFileSync)(path2, JSON.stringify(state, null, 2), "utf8");
|
|
45364
45503
|
}
|
|
45365
45504
|
function writeStagePortReservation(port, cwd, statePath, globalStatePath, now) {
|
|
45366
45505
|
const reservation = {
|
|
@@ -45389,7 +45528,7 @@ async function cleanupStageState(state, paths, timeoutMs, fallbackCwd, currentEn
|
|
|
45389
45528
|
);
|
|
45390
45529
|
}
|
|
45391
45530
|
for (const path2 of [...new Set(paths.filter((p) => Boolean(p)))]) {
|
|
45392
|
-
(0,
|
|
45531
|
+
(0, import_node_fs43.rmSync)(path2, { force: true });
|
|
45393
45532
|
}
|
|
45394
45533
|
}
|
|
45395
45534
|
async function killTree(pid) {
|
|
@@ -45636,8 +45775,8 @@ async function runStage(config = {}, opts = {}) {
|
|
|
45636
45775
|
});
|
|
45637
45776
|
}
|
|
45638
45777
|
} catch (e) {
|
|
45639
|
-
(0,
|
|
45640
|
-
if (globalStatePath && globalStatePath !== statePath) (0,
|
|
45778
|
+
(0, import_node_fs43.rmSync)(statePath, { force: true });
|
|
45779
|
+
if (globalStatePath && globalStatePath !== statePath) (0, import_node_fs43.rmSync)(globalStatePath, { force: true });
|
|
45641
45780
|
throw e;
|
|
45642
45781
|
}
|
|
45643
45782
|
const started = await startStage(config, {
|
|
@@ -45658,7 +45797,7 @@ function normPath2(p) {
|
|
|
45658
45797
|
function unlinkNodeModulesJunction(wtPath) {
|
|
45659
45798
|
const nm = (0, import_node_path42.join)(wtPath, "node_modules");
|
|
45660
45799
|
try {
|
|
45661
|
-
if ((0,
|
|
45800
|
+
if ((0, import_node_fs44.lstatSync)(nm).isSymbolicLink()) (0, import_node_fs44.rmdirSync)(nm);
|
|
45662
45801
|
return { ok: true };
|
|
45663
45802
|
} catch (e) {
|
|
45664
45803
|
if (e.code === "ENOENT") return { ok: true };
|
|
@@ -45669,8 +45808,8 @@ function defaultSleep2(ms) {
|
|
|
45669
45808
|
return new Promise((resolve8) => setTimeout(resolve8, ms));
|
|
45670
45809
|
}
|
|
45671
45810
|
async function removeResidueDirectory(wtPath, options = {}) {
|
|
45672
|
-
const { sleep: sleep2 = defaultSleep2, removeEmptyDir =
|
|
45673
|
-
const removeRecursive = options.removeRecursive ?? ((path2) => (0,
|
|
45811
|
+
const { sleep: sleep2 = defaultSleep2, removeEmptyDir = import_node_fs44.rmdirSync, exists = import_node_fs44.existsSync } = options;
|
|
45812
|
+
const removeRecursive = options.removeRecursive ?? ((path2) => (0, import_node_fs44.rmSync)(path2, { recursive: true, force: true, maxRetries: 10, retryDelay: 100 }));
|
|
45674
45813
|
const junction = unlinkNodeModulesJunction(wtPath);
|
|
45675
45814
|
if (!junction.ok) return junction;
|
|
45676
45815
|
try {
|
|
@@ -45796,21 +45935,21 @@ async function listNestedIgnoredNodeModules(wtPath, execGit) {
|
|
|
45796
45935
|
return out.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.endsWith("node_modules/") && line !== "node_modules/").map((line) => (0, import_node_path42.join)(wtPath, line.slice(0, -1)));
|
|
45797
45936
|
}
|
|
45798
45937
|
function safeRemoveTree(path2) {
|
|
45799
|
-
const stat4 = (0,
|
|
45938
|
+
const stat4 = (0, import_node_fs44.lstatSync)(path2);
|
|
45800
45939
|
if (stat4.isSymbolicLink()) {
|
|
45801
45940
|
try {
|
|
45802
|
-
(0,
|
|
45941
|
+
(0, import_node_fs44.rmdirSync)(path2);
|
|
45803
45942
|
} catch {
|
|
45804
|
-
(0,
|
|
45943
|
+
(0, import_node_fs44.unlinkSync)(path2);
|
|
45805
45944
|
}
|
|
45806
45945
|
return;
|
|
45807
45946
|
}
|
|
45808
45947
|
if (stat4.isDirectory()) {
|
|
45809
|
-
for (const entry of (0,
|
|
45810
|
-
(0,
|
|
45948
|
+
for (const entry of (0, import_node_fs44.readdirSync)(path2)) safeRemoveTree((0, import_node_path42.join)(path2, entry));
|
|
45949
|
+
(0, import_node_fs44.rmdirSync)(path2);
|
|
45811
45950
|
return;
|
|
45812
45951
|
}
|
|
45813
|
-
(0,
|
|
45952
|
+
(0, import_node_fs44.unlinkSync)(path2);
|
|
45814
45953
|
}
|
|
45815
45954
|
async function removeWorktreeNodeModules(wtPath) {
|
|
45816
45955
|
try {
|
|
@@ -45826,7 +45965,7 @@ function errorMessage(e) {
|
|
|
45826
45965
|
}
|
|
45827
45966
|
function resolvedOrRaw(path2) {
|
|
45828
45967
|
try {
|
|
45829
|
-
return normPath2((0,
|
|
45968
|
+
return normPath2((0, import_node_fs44.realpathSync)(path2));
|
|
45830
45969
|
} catch {
|
|
45831
45970
|
return normPath2(path2);
|
|
45832
45971
|
}
|
|
@@ -45834,10 +45973,10 @@ function resolvedOrRaw(path2) {
|
|
|
45834
45973
|
function unlinkEscapingReparsePoints(root, primaryRoot) {
|
|
45835
45974
|
let realRoot;
|
|
45836
45975
|
try {
|
|
45837
|
-
if ((0,
|
|
45976
|
+
if ((0, import_node_fs44.lstatSync)(root).isSymbolicLink()) {
|
|
45838
45977
|
return { ok: false, error: `delete root ${normPath2(root)} is a reparse point resolving to ${resolvedOrRaw(root)}` };
|
|
45839
45978
|
}
|
|
45840
|
-
realRoot = normPath2((0,
|
|
45979
|
+
realRoot = normPath2((0, import_node_fs44.realpathSync)(root));
|
|
45841
45980
|
} catch (e) {
|
|
45842
45981
|
if (e.code === "ENOENT") return { ok: true, unlinked: [] };
|
|
45843
45982
|
return { ok: false, error: `cannot resolve delete root ${normPath2(root)}: ${errorMessage(e)}` };
|
|
@@ -45853,7 +45992,7 @@ function unlinkEscapingReparsePoints(root, primaryRoot) {
|
|
|
45853
45992
|
const dir = stack.pop();
|
|
45854
45993
|
let entries;
|
|
45855
45994
|
try {
|
|
45856
|
-
entries = (0,
|
|
45995
|
+
entries = (0, import_node_fs44.readdirSync)(dir, { withFileTypes: true });
|
|
45857
45996
|
} catch (e) {
|
|
45858
45997
|
if (e.code === "ENOENT") continue;
|
|
45859
45998
|
return { ok: false, error: `cannot scan ${normPath2(dir)} for reparse points: ${errorMessage(e)}` };
|
|
@@ -45863,7 +46002,7 @@ function unlinkEscapingReparsePoints(root, primaryRoot) {
|
|
|
45863
46002
|
if (entry.isSymbolicLink()) {
|
|
45864
46003
|
let target = "";
|
|
45865
46004
|
try {
|
|
45866
|
-
target = normPath2((0,
|
|
46005
|
+
target = normPath2((0, import_node_fs44.realpathSync)(child2));
|
|
45867
46006
|
} catch {
|
|
45868
46007
|
target = "";
|
|
45869
46008
|
}
|
|
@@ -46046,7 +46185,7 @@ async function cleanupPrMergeLocalBranch(branch, options) {
|
|
|
46046
46185
|
return report;
|
|
46047
46186
|
}
|
|
46048
46187
|
const execGit = options.execGit ?? (async (args) => (await execFileP("git", args, { timeout: GIT_TIMEOUT_MS })).stdout);
|
|
46049
|
-
const pathExists = options.pathExists ??
|
|
46188
|
+
const pathExists = options.pathExists ?? import_node_fs44.existsSync;
|
|
46050
46189
|
let afterWorktrees = [];
|
|
46051
46190
|
try {
|
|
46052
46191
|
afterWorktrees = parseGitWorktreePorcelain(await execGit(["worktree", "list", "--porcelain"]));
|
|
@@ -46333,7 +46472,7 @@ function residueLedgerPath(gitCommonDir) {
|
|
|
46333
46472
|
}
|
|
46334
46473
|
function readPaths(file, deps) {
|
|
46335
46474
|
try {
|
|
46336
|
-
const parsed = JSON.parse((deps.readLedger ?? ((f) => (0,
|
|
46475
|
+
const parsed = JSON.parse((deps.readLedger ?? ((f) => (0, import_node_fs45.readFileSync)(f, "utf8")))(file));
|
|
46337
46476
|
return Array.isArray(parsed) ? parsed.filter((p) => typeof p === "string") : [];
|
|
46338
46477
|
} catch {
|
|
46339
46478
|
return [];
|
|
@@ -46342,8 +46481,8 @@ function readPaths(file, deps) {
|
|
|
46342
46481
|
function writePaths(file, paths, deps) {
|
|
46343
46482
|
try {
|
|
46344
46483
|
const write = deps.writeLedger ?? ((f, t) => {
|
|
46345
|
-
(0,
|
|
46346
|
-
(0,
|
|
46484
|
+
(0, import_node_fs45.mkdirSync)((0, import_node_path43.dirname)(f), { recursive: true });
|
|
46485
|
+
(0, import_node_fs45.writeFileSync)(f, t, "utf8");
|
|
46347
46486
|
});
|
|
46348
46487
|
write(file, `${JSON.stringify([...new Set(paths)], null, 1)}
|
|
46349
46488
|
`);
|
|
@@ -46357,17 +46496,17 @@ function recordResidue(gitCommonDir, path2, deps = {}) {
|
|
|
46357
46496
|
writePaths(file, paths, deps);
|
|
46358
46497
|
}
|
|
46359
46498
|
async function sweepWorktreeResidue(gitCommonDir, registered, deps = {}) {
|
|
46360
|
-
const exists = deps.exists ??
|
|
46361
|
-
const readDir = deps.readDir ?? ((p) => (0,
|
|
46499
|
+
const exists = deps.exists ?? import_node_fs45.existsSync;
|
|
46500
|
+
const readDir = deps.readDir ?? ((p) => (0, import_node_fs45.readdirSync)(p));
|
|
46362
46501
|
const isDir = deps.isDir ?? ((p) => {
|
|
46363
46502
|
try {
|
|
46364
|
-
return (0,
|
|
46503
|
+
return (0, import_node_fs45.statSync)(p).isDirectory();
|
|
46365
46504
|
} catch {
|
|
46366
46505
|
return false;
|
|
46367
46506
|
}
|
|
46368
46507
|
});
|
|
46369
46508
|
const removeRecorded = deps.removeRecorded ?? ((p) => removeResidueDirectory(p));
|
|
46370
|
-
const removeEmpty = deps.removeEmpty ?? ((p) => (0,
|
|
46509
|
+
const removeEmpty = deps.removeEmpty ?? ((p) => (0, import_node_fs45.rmdirSync)(p));
|
|
46371
46510
|
const report = { swept: [], kept: [], dropped: [], emptyRemoved: [], unrecorded: [] };
|
|
46372
46511
|
const live = new Set(registered.map(norm));
|
|
46373
46512
|
const primary = registered[0] ? norm(registered[0]) : void 0;
|
|
@@ -46447,8 +46586,8 @@ function argvWantsJson2() {
|
|
|
46447
46586
|
function hubRoot() {
|
|
46448
46587
|
const fromPkg = (0, import_node_path44.join)(__dirname, "..", "..");
|
|
46449
46588
|
const marker = "skills/bootstrap/seeds/manifest.json";
|
|
46450
|
-
if ((0,
|
|
46451
|
-
if ((0,
|
|
46589
|
+
if ((0, import_node_fs46.existsSync)((0, import_node_path44.join)(fromPkg, marker))) return fromPkg;
|
|
46590
|
+
if ((0, import_node_fs46.existsSync)((0, import_node_path44.join)(process.cwd(), marker))) return process.cwd();
|
|
46452
46591
|
return null;
|
|
46453
46592
|
}
|
|
46454
46593
|
function ciAuditDeps() {
|
|
@@ -46461,7 +46600,7 @@ function ciAuditDeps() {
|
|
|
46461
46600
|
readSeedFile: (path2) => {
|
|
46462
46601
|
if (!root) return null;
|
|
46463
46602
|
const fullPath = (0, import_node_path44.join)(root, path2);
|
|
46464
|
-
return (0,
|
|
46603
|
+
return (0, import_node_fs46.existsSync)(fullPath) ? (0, import_node_fs46.readFileSync)(fullPath, "utf8") : null;
|
|
46465
46604
|
}
|
|
46466
46605
|
};
|
|
46467
46606
|
}
|
|
@@ -47225,10 +47364,10 @@ ${list}`);
|
|
|
47225
47364
|
});
|
|
47226
47365
|
async function listCiWorkflowPaths(cwd = process.cwd()) {
|
|
47227
47366
|
const wfDir = (0, import_node_path44.join)(cwd, ".github", "workflows");
|
|
47228
|
-
if (!(0,
|
|
47229
|
-
return (0,
|
|
47367
|
+
if (!(0, import_node_fs46.existsSync)(wfDir)) return [];
|
|
47368
|
+
return (0, import_node_fs46.readdirSync)(wfDir).filter((name) => /\.(ya?ml)$/i.test(name)).filter((name) => {
|
|
47230
47369
|
try {
|
|
47231
|
-
return workflowReportsPrChecks((0,
|
|
47370
|
+
return workflowReportsPrChecks((0, import_node_fs46.readFileSync)((0, import_node_path44.join)(wfDir, name), "utf8"));
|
|
47232
47371
|
} catch {
|
|
47233
47372
|
return true;
|
|
47234
47373
|
}
|
|
@@ -47433,7 +47572,7 @@ ${list}`);
|
|
|
47433
47572
|
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) => {
|
|
47434
47573
|
if (!isReviewVerdict(o.verdict)) return fail(`pr review-verdict: --verdict must be one of ${REVIEW_VERDICTS.join("|")} (got ${o.verdict})`);
|
|
47435
47574
|
const verdict = o.verdict;
|
|
47436
|
-
const findings = o.findingsFile ? (0,
|
|
47575
|
+
const findings = o.findingsFile ? (0, import_node_fs46.readFileSync)(o.findingsFile, "utf8") : void 0;
|
|
47437
47576
|
let patch;
|
|
47438
47577
|
let head;
|
|
47439
47578
|
try {
|
|
@@ -47689,7 +47828,7 @@ ${list}`);
|
|
|
47689
47828
|
const cleanupMerged = async (r) => {
|
|
47690
47829
|
if (opts.preserveWorktree) return "cleanup skipped (--preserve-worktree)";
|
|
47691
47830
|
const ran = await execFileP(process.execPath, [process.argv[1], ...canonicalArgvFor(["pr", "merge", r.pr, "--repo", r.repo])], {
|
|
47692
|
-
cwd: (0,
|
|
47831
|
+
cwd: (0, import_node_fs46.existsSync)(cwd0) ? cwd0 : primaryRoot0,
|
|
47693
47832
|
timeout: GH_MUTATION_TIMEOUT_MS * 3
|
|
47694
47833
|
}).then((x) => ({ stdout: x.stdout, stderr: x.stderr }), (e) => ({ stdout: e.stdout ?? "", stderr: e.stderr ?? "" }));
|
|
47695
47834
|
const json = ran.stdout.split("\n").reverse().find((l) => l.startsWith("{"));
|
|
@@ -47759,7 +47898,7 @@ ${list}`);
|
|
|
47759
47898
|
const mergeSquashBody = squashBodyTextForMerge(
|
|
47760
47899
|
closingGuardInput,
|
|
47761
47900
|
method === "--squash",
|
|
47762
|
-
o.squashBodyFile ? (0,
|
|
47901
|
+
o.squashBodyFile ? (0, import_node_fs46.readFileSync)(o.squashBodyFile, "utf8") : void 0
|
|
47763
47902
|
);
|
|
47764
47903
|
if (!o.squashBodyFile) warnSquashBodyClosingStrip("pr merge", closingGuardInput, mergeSquashBody);
|
|
47765
47904
|
const closingGuardVerdict = evaluateClosingGuard(closingGuardInput, {
|
|
@@ -47910,7 +48049,7 @@ ${list}`);
|
|
|
47910
48049
|
}
|
|
47911
48050
|
if (!repoForPostCleanup) throw e;
|
|
47912
48051
|
console.warn(`pr merge: gh GraphQL rate-limited \u2014 merging PR #${number} via REST PUT instead (#4588).`);
|
|
47913
|
-
const commitMessage = bodyFile ? (0,
|
|
48052
|
+
const commitMessage = bodyFile ? (0, import_node_fs46.readFileSync)(bodyFile, "utf8") : void 0;
|
|
47914
48053
|
await defaultGitHubClient().rest("PUT", `repos/${repoForPostCleanup}/pulls/${number}/merge`, {
|
|
47915
48054
|
body: { merge_method: method.slice(2), ...commitMessage ? { commit_message: commitMessage } : {} },
|
|
47916
48055
|
timeoutMs: GH_MUTATION_TIMEOUT_MS
|
|
@@ -48043,7 +48182,7 @@ ${list}`);
|
|
|
48043
48182
|
preserveWorktree: o.preserveWorktree,
|
|
48044
48183
|
gcAcknowledged: o.gc,
|
|
48045
48184
|
expectedHeadOid: headRefOid,
|
|
48046
|
-
pathExists: (p) => (0,
|
|
48185
|
+
pathExists: (p) => (0, import_node_fs46.existsSync)(p),
|
|
48047
48186
|
// #5899: pin cleanup git calls to the main checkout — the task worktree this process may be
|
|
48048
48187
|
// standing in is removed mid-cleanup, so a cwd-relative invocation fails with
|
|
48049
48188
|
// 'fatal: not a git repository' and leaves a spurious partial-cleanup exit.
|
|
@@ -49343,11 +49482,11 @@ function suiteTrainIo(root, summaryFile, memberSummaryFiles = {}, summaryFileTr,
|
|
|
49343
49482
|
const checkout = async (repo) => {
|
|
49344
49483
|
if (repo === SUITE_REPO) return root;
|
|
49345
49484
|
const target = (0, import_node_path46.join)(base, repo.split("/")[1]);
|
|
49346
|
-
if (!(0,
|
|
49347
|
-
(0,
|
|
49485
|
+
if (!(0, import_node_fs47.existsSync)(target)) {
|
|
49486
|
+
(0, import_node_fs47.mkdirSync)(base, { recursive: true });
|
|
49348
49487
|
await exec("git", ["clone", "--quiet", "--branch", "development", `https://github.com/${repo}.git`, target], root, WATCH_TIMEOUT);
|
|
49349
49488
|
}
|
|
49350
|
-
if (!(0,
|
|
49489
|
+
if (!(0, import_node_fs47.existsSync)((0, import_node_path46.join)(target, ".git"))) throw new Error(`${repo}: suite checkout has no .git at ${target}; stop`);
|
|
49351
49490
|
const origin = await exec("git", ["remote", "get-url", "origin"], target);
|
|
49352
49491
|
if (!origin.toLowerCase().endsWith(`/${repo.toLowerCase()}.git`) && !origin.toLowerCase().endsWith(`/${repo.toLowerCase()}`))
|
|
49353
49492
|
throw new Error(`${repo}: suite checkout origin mismatch at ${target}; stop`);
|
|
@@ -49654,9 +49793,9 @@ function suiteTrainIo(root, summaryFile, memberSummaryFiles = {}, summaryFileTr,
|
|
|
49654
49793
|
const body = await gh(["release", "view", leadTag, "--repo", SUITE_REPO, "--json", "body", "--jq", ".body"]);
|
|
49655
49794
|
if (parseSuiteMapping(body)) return;
|
|
49656
49795
|
const dir = suiteStateDir(root);
|
|
49657
|
-
(0,
|
|
49796
|
+
(0, import_node_fs47.mkdirSync)(dir, { recursive: true });
|
|
49658
49797
|
const file = (0, import_node_path46.join)(dir, `notes-${leadTag}.md`);
|
|
49659
|
-
(0,
|
|
49798
|
+
(0, import_node_fs47.writeFileSync)(file, `${body}
|
|
49660
49799
|
|
|
49661
49800
|
${suiteMappingBlock(leadTag, mapping)}`);
|
|
49662
49801
|
await gh(["release", "edit", leadTag, "--repo", SUITE_REPO, "--notes-file", file]);
|
|
@@ -49697,7 +49836,7 @@ ${suiteMappingBlock(leadTag, mapping)}`);
|
|
|
49697
49836
|
|
|
49698
49837
|
// src/suite-commands.ts
|
|
49699
49838
|
init_cli_shared();
|
|
49700
|
-
var
|
|
49839
|
+
var import_node_fs48 = require("node:fs");
|
|
49701
49840
|
function parseMemberSummaryFiles(entries) {
|
|
49702
49841
|
const memberSummaryFiles = {};
|
|
49703
49842
|
for (const entry of entries) {
|
|
@@ -49791,7 +49930,7 @@ function registerSuiteCommands(program3) {
|
|
|
49791
49930
|
try {
|
|
49792
49931
|
const io = suiteTrainIo(root);
|
|
49793
49932
|
retired = await retireFailedLeadRcLedger({ ledgerPath: releaseLedgerPath(root), rcHead: () => io.head(SUITE_REPO, "rc").then((h) => h ?? void 0), markAbandoned: io.markAbandoned }, o.ownerGo === true);
|
|
49794
|
-
if (retired && !(0,
|
|
49933
|
+
if (retired && !(0, import_node_fs48.existsSync)(io.recordPath)) {
|
|
49795
49934
|
console.log(o.json ? JSON.stringify({ retiredLeadRc: retired }, null, 2) : `suite abandon: retired the lead's failed, never-promoted rc candidate ${retired}; marked abandoned on origin (#7854)`);
|
|
49796
49935
|
return;
|
|
49797
49936
|
}
|
|
@@ -49980,7 +50119,7 @@ function suiteStatusDeps(github, registry2) {
|
|
|
49980
50119
|
|
|
49981
50120
|
// src/packages-adopt-export.ts
|
|
49982
50121
|
var import_node_child_process19 = require("node:child_process");
|
|
49983
|
-
var
|
|
50122
|
+
var import_node_fs49 = require("node:fs");
|
|
49984
50123
|
var import_node_os22 = require("node:os");
|
|
49985
50124
|
var import_node_path47 = require("node:path");
|
|
49986
50125
|
var import_node_util6 = require("node:util");
|
|
@@ -50604,36 +50743,36 @@ async function adoptExport(opts, deps) {
|
|
|
50604
50743
|
if (!/^sha256:[0-9a-f]{64}$/.test(opts.digest)) throw new Error("--digest must be sha256:<64 hex>, from the export run summary");
|
|
50605
50744
|
const packagePath = (0, import_node_path47.join)(opts.dir, "package.json");
|
|
50606
50745
|
const lockPath = (0, import_node_path47.join)(opts.dir, "package-lock.json");
|
|
50607
|
-
const packageText = (0,
|
|
50608
|
-
const lockText = (0,
|
|
50609
|
-
const work = (0,
|
|
50746
|
+
const packageText = (0, import_node_fs49.readFileSync)(packagePath, "utf8");
|
|
50747
|
+
const lockText = (0, import_node_fs49.readFileSync)(lockPath, "utf8");
|
|
50748
|
+
const work = (0, import_node_fs49.mkdtempSync)((0, import_node_path47.join)((0, import_node_os22.tmpdir)(), "mmi-adopt-export-"));
|
|
50610
50749
|
try {
|
|
50611
50750
|
const run = JSON.parse((await deps.ghApi(`repos/${EXPORT_REPO}/actions/runs/${opts.run}`)).toString("utf8"));
|
|
50612
|
-
(0,
|
|
50613
|
-
(0,
|
|
50614
|
-
(0,
|
|
50751
|
+
(0, import_node_fs49.writeFileSync)((0, import_node_path47.join)(work, "expected.json"), JSON.stringify(expectedFromRun(run, opts)));
|
|
50752
|
+
(0, import_node_fs49.writeFileSync)((0, import_node_path47.join)(work, "provider.json"), await deps.ghApi(`repos/${EXPORT_REPO}/actions/artifacts/${opts.artifact}`));
|
|
50753
|
+
(0, import_node_fs49.writeFileSync)((0, import_node_path47.join)(work, "artifact.zip"), await deps.ghApi(`repos/${EXPORT_REPO}/actions/artifacts/${opts.artifact}/zip`));
|
|
50615
50754
|
const script = (0, import_node_path47.join)(work, "package_export.py");
|
|
50616
|
-
(0,
|
|
50755
|
+
(0, import_node_fs49.writeFileSync)(script, package_export_default);
|
|
50617
50756
|
await deps.python(script, ["verify", work, opts.ds, opts.screens]);
|
|
50618
50757
|
const verified = (0, import_node_path47.join)(work, "verified");
|
|
50619
|
-
const metadata = Object.fromEntries(PACKAGES.map(({ name, short: short3 }) => [name, JSON.parse((0,
|
|
50758
|
+
const metadata = Object.fromEntries(PACKAGES.map(({ name, short: short3 }) => [name, JSON.parse((0, import_node_fs49.readFileSync)((0, import_node_path47.join)(verified, `${short3}.metadata.json`), "utf8"))]));
|
|
50620
50759
|
const plan = planAdoption(packageText, lockText, metadata);
|
|
50621
50760
|
for (const { name } of plan.result.adopted) {
|
|
50622
50761
|
const short3 = PACKAGES.find((p) => p.name === name).short;
|
|
50623
50762
|
await deps.npm(["cache", "add", (0, import_node_path47.join)(verified, `${short3}.tgz`)], opts.dir);
|
|
50624
50763
|
}
|
|
50625
|
-
(0,
|
|
50626
|
-
(0,
|
|
50764
|
+
(0, import_node_fs49.writeFileSync)(packagePath, plan.packageText);
|
|
50765
|
+
(0, import_node_fs49.writeFileSync)(lockPath, plan.lockText);
|
|
50627
50766
|
try {
|
|
50628
50767
|
await deps.npm(["ci", "--offline", "--ignore-scripts", "--no-audit", "--no-fund"], opts.dir);
|
|
50629
50768
|
} catch (error) {
|
|
50630
|
-
(0,
|
|
50631
|
-
(0,
|
|
50769
|
+
(0, import_node_fs49.writeFileSync)(packagePath, packageText);
|
|
50770
|
+
(0, import_node_fs49.writeFileSync)(lockPath, lockText);
|
|
50632
50771
|
throw new Error(`npm ci --offline failed, package.json and package-lock.json restored: ${error.message}`);
|
|
50633
50772
|
}
|
|
50634
50773
|
return plan.result;
|
|
50635
50774
|
} finally {
|
|
50636
|
-
(0,
|
|
50775
|
+
(0, import_node_fs49.rmSync)(work, { recursive: true, force: true });
|
|
50637
50776
|
}
|
|
50638
50777
|
}
|
|
50639
50778
|
var execFileBuffer = (0, import_node_util6.promisify)(import_node_child_process19.execFile);
|
|
@@ -50698,12 +50837,12 @@ function registerPackagesCommands(program3) {
|
|
|
50698
50837
|
init_cli_shared();
|
|
50699
50838
|
|
|
50700
50839
|
// src/wave-status.ts
|
|
50701
|
-
var
|
|
50840
|
+
var import_node_fs50 = require("node:fs");
|
|
50702
50841
|
function readStageSummary(worktreePath) {
|
|
50703
50842
|
const statePath = stageStatePath(worktreePath);
|
|
50704
|
-
if (!(0,
|
|
50843
|
+
if (!(0, import_node_fs50.existsSync)(statePath)) return void 0;
|
|
50705
50844
|
try {
|
|
50706
|
-
const state = JSON.parse((0,
|
|
50845
|
+
const state = JSON.parse((0, import_node_fs50.readFileSync)(statePath, "utf8"));
|
|
50707
50846
|
const port = typeof state.port === "number" ? state.port : void 0;
|
|
50708
50847
|
if (port == null || !Number.isInteger(port) || port <= 0) return void 0;
|
|
50709
50848
|
return { port, url: typeof state.url === "string" ? state.url : void 0 };
|
|
@@ -50760,7 +50899,7 @@ async function collectWaveStatus(deps) {
|
|
|
50760
50899
|
// src/discovery-commands.ts
|
|
50761
50900
|
init_github_client();
|
|
50762
50901
|
init_cli_shared();
|
|
50763
|
-
var
|
|
50902
|
+
var import_node_fs51 = require("node:fs");
|
|
50764
50903
|
var import_node_os23 = require("node:os");
|
|
50765
50904
|
var import_node_path48 = require("node:path");
|
|
50766
50905
|
var GC_GH_TIMEOUT_MS3 = 2e4;
|
|
@@ -50953,8 +51092,8 @@ async function collectOnboardStatus(opts = {}) {
|
|
|
50953
51092
|
}
|
|
50954
51093
|
const home = (0, import_node_os23.homedir)();
|
|
50955
51094
|
const plugin = onboardPluginGate({
|
|
50956
|
-
readKnown: () => readFileSyncSafe((0, import_node_path48.join)(home, ...KNOWN_MARKETPLACES_RELATIVE),
|
|
50957
|
-
readSettings: () => readFileSyncSafe((0, import_node_path48.join)(home, ".claude", "settings.json"),
|
|
51095
|
+
readKnown: () => readFileSyncSafe((0, import_node_path48.join)(home, ...KNOWN_MARKETPLACES_RELATIVE), import_node_fs51.readFileSync),
|
|
51096
|
+
readSettings: () => readFileSyncSafe((0, import_node_path48.join)(home, ".claude", "settings.json"), import_node_fs51.readFileSync)
|
|
50958
51097
|
});
|
|
50959
51098
|
return {
|
|
50960
51099
|
guide: "Read the MMI org-guide skill before project work; load only the relevant topic. Use mmi-help for a short introduction.",
|
|
@@ -53148,7 +53287,7 @@ function registerOrgHealthQuery(program3, deps = defaultOrgHealthQueryDeps()) {
|
|
|
53148
53287
|
}
|
|
53149
53288
|
|
|
53150
53289
|
// src/api-read.ts
|
|
53151
|
-
var
|
|
53290
|
+
var import_node_fs52 = require("node:fs");
|
|
53152
53291
|
|
|
53153
53292
|
// src/run-log-read.ts
|
|
53154
53293
|
init_cli_shared();
|
|
@@ -53749,7 +53888,7 @@ function registerApiReadCommands(program3, overrides) {
|
|
|
53749
53888
|
o.accept
|
|
53750
53889
|
);
|
|
53751
53890
|
if (zip) {
|
|
53752
|
-
(0,
|
|
53891
|
+
(0, import_node_fs52.writeFileSync)(o.out, body, "latin1");
|
|
53753
53892
|
return;
|
|
53754
53893
|
}
|
|
53755
53894
|
} catch (e) {
|
|
@@ -54624,7 +54763,7 @@ function registerSessionReport(program3) {
|
|
|
54624
54763
|
}
|
|
54625
54764
|
|
|
54626
54765
|
// src/stage-commands.ts
|
|
54627
|
-
var
|
|
54766
|
+
var import_node_fs53 = require("node:fs");
|
|
54628
54767
|
var import_node_path49 = require("node:path");
|
|
54629
54768
|
init_cli_shared();
|
|
54630
54769
|
init_clean_exit();
|
|
@@ -54873,8 +55012,8 @@ function registerStageCommands(program3) {
|
|
|
54873
55012
|
const repo = Array.isArray(project2?.repos) && typeof project2.repos[0] === "string" ? project2.repos[0] : slug;
|
|
54874
55013
|
const resolution = decideStage({
|
|
54875
55014
|
registry: { deployModel: project2?.deployModel, portRange, error: read.ok ? void 0 : read.error },
|
|
54876
|
-
hasCompose: (0,
|
|
54877
|
-
hasEnvExample: (0,
|
|
55015
|
+
hasCompose: (0, import_node_fs53.existsSync)((0, import_node_path49.join)(process.cwd(), "docker-compose.yml")),
|
|
55016
|
+
hasEnvExample: (0, import_node_fs53.existsSync)((0, import_node_path49.join)(process.cwd(), ".env.example")),
|
|
54878
55017
|
repo
|
|
54879
55018
|
});
|
|
54880
55019
|
if (resolution.source === "derived" && resolution.derived) {
|
|
@@ -55167,14 +55306,14 @@ vercel preview (${preview.branch}): ${d.state}${d.url ? ` \u2014 ${d.url}` : ""}
|
|
|
55167
55306
|
|
|
55168
55307
|
// src/tenant-artifact.ts
|
|
55169
55308
|
var import_node_crypto17 = require("node:crypto");
|
|
55170
|
-
var
|
|
55309
|
+
var import_node_fs54 = require("node:fs");
|
|
55171
55310
|
var import_promises11 = require("node:fs/promises");
|
|
55172
55311
|
var import_node_path50 = require("node:path");
|
|
55173
55312
|
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}$/;
|
|
55174
55313
|
var MAX_BYTES2 = 5 * 1024 * 1024 * 1024;
|
|
55175
55314
|
async function sha256File(path2) {
|
|
55176
55315
|
const hash = (0, import_node_crypto17.createHash)("sha256");
|
|
55177
|
-
for await (const chunk of (0,
|
|
55316
|
+
for await (const chunk of (0, import_node_fs54.createReadStream)(path2)) hash.update(chunk);
|
|
55178
55317
|
return hash.digest("hex");
|
|
55179
55318
|
}
|
|
55180
55319
|
async function putTenantArtifact(repo, stage, inputPath, deps) {
|
|
@@ -55197,7 +55336,7 @@ async function putTenantArtifact(repo, stage, inputPath, deps) {
|
|
|
55197
55336
|
return [key, value];
|
|
55198
55337
|
}));
|
|
55199
55338
|
headers["content-length"] = String(info.size);
|
|
55200
|
-
const stream = (0,
|
|
55339
|
+
const stream = (0, import_node_fs54.createReadStream)(path2);
|
|
55201
55340
|
let uploaded;
|
|
55202
55341
|
try {
|
|
55203
55342
|
uploaded = await fetch(body.uploadUrl, {
|
|
@@ -55336,7 +55475,7 @@ function renderVerifySecrets(body) {
|
|
|
55336
55475
|
}
|
|
55337
55476
|
|
|
55338
55477
|
// src/command-register-developer.ts
|
|
55339
|
-
var
|
|
55478
|
+
var import_node_fs58 = require("node:fs");
|
|
55340
55479
|
init_clean_exit();
|
|
55341
55480
|
init_cli_shared();
|
|
55342
55481
|
init_error_codes();
|
|
@@ -55404,13 +55543,13 @@ async function executeWaveLand(plan, deps) {
|
|
|
55404
55543
|
// src/dist-drift.ts
|
|
55405
55544
|
var import_node_child_process20 = require("node:child_process");
|
|
55406
55545
|
var import_node_crypto19 = require("node:crypto");
|
|
55407
|
-
var
|
|
55546
|
+
var import_node_fs56 = require("node:fs");
|
|
55408
55547
|
var import_node_os24 = require("node:os");
|
|
55409
55548
|
var import_node_path52 = require("node:path");
|
|
55410
55549
|
|
|
55411
55550
|
// ../scripts/distribution-digest.mjs
|
|
55412
55551
|
var import_node_crypto18 = require("node:crypto");
|
|
55413
|
-
var
|
|
55552
|
+
var import_node_fs55 = require("node:fs");
|
|
55414
55553
|
var import_node_path51 = require("node:path");
|
|
55415
55554
|
var slash = (value) => value.replaceAll("\\", "/");
|
|
55416
55555
|
function repoPath(root, declaredPath, label) {
|
|
@@ -55424,7 +55563,7 @@ function repoPath(root, declaredPath, label) {
|
|
|
55424
55563
|
function digestFiles(files) {
|
|
55425
55564
|
const hash = (0, import_node_crypto18.createHash)("sha256");
|
|
55426
55565
|
for (const file of [...files].sort((a, b) => a.relative.localeCompare(b.relative))) {
|
|
55427
|
-
const content = file.stat.isSymbolicLink() ? Buffer.from((0,
|
|
55566
|
+
const content = file.stat.isSymbolicLink() ? Buffer.from((0, import_node_fs55.readlinkSync)(file.absolute), "utf8") : (0, import_node_fs55.readFileSync)(file.absolute);
|
|
55428
55567
|
hash.update(file.relative, "utf8");
|
|
55429
55568
|
hash.update("\0");
|
|
55430
55569
|
hash.update(file.stat.isSymbolicLink() ? "symlink" : "file", "utf8");
|
|
@@ -55439,8 +55578,8 @@ function digestFiles(files) {
|
|
|
55439
55578
|
function digestPackedFiles(packageRoot, packedFiles) {
|
|
55440
55579
|
return digestFiles(packedFiles.map((path2) => {
|
|
55441
55580
|
const absolute = repoPath(packageRoot, path2, "packed artifact identity path");
|
|
55442
|
-
if (!(0,
|
|
55443
|
-
return { absolute, relative: slash(path2), stat: (0,
|
|
55581
|
+
if (!(0, import_node_fs55.existsSync)(absolute)) throw new Error(`packed artifact identity path ${path2} does not exist`);
|
|
55582
|
+
return { absolute, relative: slash(path2), stat: (0, import_node_fs55.lstatSync)(absolute) };
|
|
55444
55583
|
}));
|
|
55445
55584
|
}
|
|
55446
55585
|
|
|
@@ -55525,12 +55664,12 @@ function renderDistDriftReceipt(receipt) {
|
|
|
55525
55664
|
return lines2;
|
|
55526
55665
|
}
|
|
55527
55666
|
function readOrNull(path2) {
|
|
55528
|
-
return (0,
|
|
55667
|
+
return (0, import_node_fs56.existsSync)(path2) ? (0, import_node_fs56.readFileSync)(path2) : null;
|
|
55529
55668
|
}
|
|
55530
55669
|
function walkFiles(root) {
|
|
55531
55670
|
const files = [];
|
|
55532
55671
|
const walk2 = (directory) => {
|
|
55533
|
-
for (const entry of (0,
|
|
55672
|
+
for (const entry of (0, import_node_fs56.readdirSync)(directory, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
|
|
55534
55673
|
const child2 = (0, import_node_path52.join)(directory, entry.name);
|
|
55535
55674
|
if (entry.isDirectory()) walk2(child2);
|
|
55536
55675
|
else files.push(child2);
|
|
@@ -55541,7 +55680,7 @@ function walkFiles(root) {
|
|
|
55541
55680
|
}
|
|
55542
55681
|
function bomPathFor(root) {
|
|
55543
55682
|
try {
|
|
55544
|
-
const registry2 = JSON.parse((0,
|
|
55683
|
+
const registry2 = JSON.parse((0, import_node_fs56.readFileSync)((0, import_node_path52.join)(root, "surfaces.json"), "utf8"));
|
|
55545
55684
|
return (0, import_node_path52.join)(root, registry2?.sharedAgentCore?.releaseMetadata?.bomPath ?? "distribution-bom.json");
|
|
55546
55685
|
} catch {
|
|
55547
55686
|
return (0, import_node_path52.join)(root, "distribution-bom.json");
|
|
@@ -55557,7 +55696,7 @@ function rebuildTo(packageRoot, outDir) {
|
|
|
55557
55696
|
});
|
|
55558
55697
|
}
|
|
55559
55698
|
function runDistStatus(root) {
|
|
55560
|
-
const stage = (0,
|
|
55699
|
+
const stage = (0, import_node_fs56.mkdtempSync)((0, import_node_path52.join)((0, import_node_os24.tmpdir)(), "mmi-dist-drift-"));
|
|
55561
55700
|
let overlayCount = 0;
|
|
55562
55701
|
try {
|
|
55563
55702
|
const cliOut = (0, import_node_path52.join)(stage, "cli-dist");
|
|
@@ -55573,19 +55712,19 @@ function runDistStatus(root) {
|
|
|
55573
55712
|
const tree = (path2) => readOrNull((0, import_node_path52.join)(root, path2));
|
|
55574
55713
|
const distRoot = (0, import_node_path52.join)(root, "cli", "dist");
|
|
55575
55714
|
const distTree = () => walkFiles(distRoot).map((absolute) => `cli/dist/${(0, import_node_path52.relative)(distRoot, absolute).replaceAll("\\", "/")}`);
|
|
55576
|
-
const bom = JSON.parse((0,
|
|
55715
|
+
const bom = JSON.parse((0, import_node_fs56.readFileSync)(bomPathFor(root), "utf8"));
|
|
55577
55716
|
const digest = (entries) => {
|
|
55578
55717
|
const overlay = (0, import_node_path52.join)(stage, `overlay-${overlayCount++}`);
|
|
55579
55718
|
for (const entry of entries) {
|
|
55580
55719
|
const target = (0, import_node_path52.join)(overlay, entry.path);
|
|
55581
|
-
(0,
|
|
55582
|
-
(0,
|
|
55720
|
+
(0, import_node_fs56.mkdirSync)((0, import_node_path52.dirname)(target), { recursive: true });
|
|
55721
|
+
(0, import_node_fs56.writeFileSync)(target, entry.bytes);
|
|
55583
55722
|
}
|
|
55584
55723
|
return digestPackedFiles(overlay, entries.map((entry) => entry.path));
|
|
55585
55724
|
};
|
|
55586
55725
|
return computeDistDriftReceipt({ committed, tree, rebuilt, distTree, bom, digest });
|
|
55587
55726
|
} finally {
|
|
55588
|
-
(0,
|
|
55727
|
+
(0, import_node_fs56.rmSync)(stage, { recursive: true, force: true });
|
|
55589
55728
|
}
|
|
55590
55729
|
}
|
|
55591
55730
|
|
|
@@ -55915,7 +56054,7 @@ function registerSchedulesLiftCommand(program3, deps = {}) {
|
|
|
55915
56054
|
|
|
55916
56055
|
// src/spawn-policy-core.ts
|
|
55917
56056
|
var import_node_child_process22 = require("node:child_process");
|
|
55918
|
-
var
|
|
56057
|
+
var import_node_fs57 = require("node:fs");
|
|
55919
56058
|
var import_node_path55 = require("node:path");
|
|
55920
56059
|
var SPAWNERS = ["spawn", "spawnSync", "exec", "execSync", "execFile", "execFileSync"];
|
|
55921
56060
|
var CALL_SOURCE = String.raw`(^|[^.\w$])(${SPAWNERS.join("|")})\s*\(`;
|
|
@@ -56002,7 +56141,7 @@ function runSpawnPolicy(root) {
|
|
|
56002
56141
|
for (const file of files) {
|
|
56003
56142
|
let raw;
|
|
56004
56143
|
try {
|
|
56005
|
-
raw = (0,
|
|
56144
|
+
raw = (0, import_node_fs57.readFileSync)((0, import_node_path55.join)(root, file), "utf8");
|
|
56006
56145
|
} catch {
|
|
56007
56146
|
continue;
|
|
56008
56147
|
}
|
|
@@ -56023,18 +56162,18 @@ function registerDeveloperCommands(program3) {
|
|
|
56023
56162
|
const rules = program3.command("rules").description("org-managed .gitignore delivery");
|
|
56024
56163
|
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) => {
|
|
56025
56164
|
const path2 = (0, import_node_path56.join)(process.cwd(), ".gitignore");
|
|
56026
|
-
const current = (0,
|
|
56165
|
+
const current = (0, import_node_fs58.existsSync)(path2) ? (0, import_node_fs58.readFileSync)(path2, "utf8") : null;
|
|
56027
56166
|
const plan = planManagedGitignore(current);
|
|
56028
56167
|
const drift = [...plan.added.map((l) => `+${l}`), ...plan.removed.map((l) => `-${l}`)].join(", ") || "block normalize";
|
|
56029
56168
|
if (opts.json) {
|
|
56030
|
-
if (opts.write && plan.changed) (0,
|
|
56169
|
+
if (opts.write && plan.changed) (0, import_node_fs58.writeFileSync)(path2, plan.content, "utf8");
|
|
56031
56170
|
console.log(JSON.stringify(plan, null, 2));
|
|
56032
56171
|
if (!opts.write && plan.changed) process.exitCode = 1;
|
|
56033
56172
|
return;
|
|
56034
56173
|
}
|
|
56035
56174
|
if (opts.write) {
|
|
56036
56175
|
if (plan.changed) {
|
|
56037
|
-
(0,
|
|
56176
|
+
(0, import_node_fs58.writeFileSync)(path2, plan.content, "utf8");
|
|
56038
56177
|
console.log(`mmi-cli devops org rules gitignore: updated .gitignore (${drift})`);
|
|
56039
56178
|
} else {
|
|
56040
56179
|
console.log("mmi-cli devops org rules gitignore: up to date");
|
|
@@ -56243,17 +56382,18 @@ function registerDeveloperCommands(program3) {
|
|
|
56243
56382
|
}
|
|
56244
56383
|
});
|
|
56245
56384
|
const tests = program3.command("tests").description("a repo's test-policy.json \u2014 the opt-in test contract and its enforcement");
|
|
56246
|
-
tests.command("policy").description("enforce this repo's test-policy.json against the diff: a mandatory-zone change must carry a test, an unrequested new test file is refused, a `protected` test file may not be deleted or renamed away, and a `protected` entry naming a missing file is refused. Override any of them with a `Test-Policy-Override: <reason>` commit trailer (#3605)").option("--json", "machine-readable result: { ok,
|
|
56385
|
+
tests.command("policy").description("enforce this repo's test-policy.json against the diff: a mandatory-zone change must carry a test, an unrequested new test file is refused, a `protected` test file may not be deleted or renamed away, and a `protected` entry naming a missing file is refused. Override any of them with a `Test-Policy-Override: <reason>` commit trailer (#3605)").option("--json", "compact machine-readable result: { ok, testCommandsAllowed, commandClasses, findings[] }").option("--verbose", "include the full policy result in --json output").option("--base <ref>", "comparison base (default: TEST_POLICY_BASE, then origin/development, then origin/main)").option("--policy-ref <commit>", "load test-policy.json from the exact fetched origin/development commit and audit its protected/satisfiedBy paths against that commit's tree, not this checkout; valid only with --base origin/main").addOption(new Option("--repo <owner/repo>", "not accepted \u2014 tests policy reads the current checkout").hideHelp()).action(async (o) => {
|
|
56247
56386
|
try {
|
|
56248
56387
|
if (o.repo) {
|
|
56249
|
-
const rerun = `mmi-cli tests policy${o.base ? ` --base ${o.base}` : ""}${o.policyRef ? ` --policy-ref ${o.policyRef}` : ""}${o.json ? " --json" : ""}`;
|
|
56388
|
+
const rerun = `mmi-cli tests policy${o.base ? ` --base ${o.base}` : ""}${o.policyRef ? ` --policy-ref ${o.policyRef}` : ""}${o.json ? " --json" : ""}${o.verbose ? " --verbose" : ""}`;
|
|
56250
56389
|
const guard = planTrainApplyRepoGuard(o.repo, await resolveRepo(), rerun, "tests policy");
|
|
56251
56390
|
if (!guard.ok) return failGraceful(guard.message);
|
|
56252
56391
|
}
|
|
56253
56392
|
const root = await repoRoot();
|
|
56254
56393
|
const result = runTestPolicy(root, { base: o.base, policyRef: o.policyRef });
|
|
56255
56394
|
if (o.json) {
|
|
56256
|
-
|
|
56395
|
+
const { ok, testCommandsAllowed, commandClasses, findings } = result;
|
|
56396
|
+
consoleIo.log(o.verbose ? JSON.stringify(result, null, 2) : JSON.stringify({ ok, testCommandsAllowed, commandClasses, findings }));
|
|
56257
56397
|
if (!result.ok) process.exitCode = 1;
|
|
56258
56398
|
return;
|
|
56259
56399
|
}
|
|
@@ -56451,7 +56591,7 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
56451
56591
|
);
|
|
56452
56592
|
const result = applyPluginCachePlan(
|
|
56453
56593
|
plan,
|
|
56454
|
-
(p) => (0,
|
|
56594
|
+
(p) => (0, import_node_fs59.rmSync)(p, { recursive: true }),
|
|
56455
56595
|
stagingApplyFsGuard(configRoot)
|
|
56456
56596
|
);
|
|
56457
56597
|
return {
|
|
@@ -56486,7 +56626,7 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
56486
56626
|
// has no generated routing index would
|
|
56487
56627
|
// get a permanent — demanding an artifact it never asked for.
|
|
56488
56628
|
docsIndexState: (root) => {
|
|
56489
|
-
if (!(0,
|
|
56629
|
+
if (!(0, import_node_fs59.existsSync)((0, import_node_path57.join)(root, DOCS_INDEX_PATH))) return void 0;
|
|
56490
56630
|
const real = createDocsIndexDeps(root);
|
|
56491
56631
|
let docs;
|
|
56492
56632
|
const listDocs = () => docs ??= real.listDocs();
|
|
@@ -56495,7 +56635,7 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
56495
56635
|
},
|
|
56496
56636
|
// #4168: working-tree heal — write if drifted, then re-check. Commit remains the operator's step.
|
|
56497
56637
|
healDocsIndex: (root) => {
|
|
56498
|
-
if (!(0,
|
|
56638
|
+
if (!(0, import_node_fs59.existsSync)((0, import_node_path57.join)(root, DOCS_INDEX_PATH))) return { drift: false, docCount: 0 };
|
|
56499
56639
|
const real = createDocsIndexDeps(root);
|
|
56500
56640
|
let docs;
|
|
56501
56641
|
const listDocs = () => docs ??= real.listDocs();
|
|
@@ -56855,6 +56995,7 @@ function appActorDeps() {
|
|
|
56855
56995
|
};
|
|
56856
56996
|
}
|
|
56857
56997
|
setPollTokenProvider(async () => activeAppToken() ?? pollTokenOrUndefined(appActorDeps()));
|
|
56998
|
+
setGhReadTokenProvider(pollToken);
|
|
56858
56999
|
setStatusWriteTokenProvider(() => mintStatusWriteToken(appActorDeps()));
|
|
56859
57000
|
var registerPreAction = Reflect.get(program2, ["h", "ook"].join(""));
|
|
56860
57001
|
registerPreAction.call(program2, "preAction", async (_thisCommand, actionCommand) => {
|
|
@@ -56862,7 +57003,7 @@ registerPreAction.call(program2, "preAction", async (_thisCommand, actionCommand
|
|
|
56862
57003
|
appActorCommand = commandPath3;
|
|
56863
57004
|
emitCliCallTelemetry(commandPath3);
|
|
56864
57005
|
try {
|
|
56865
|
-
await activateAppActor(commandPath3, process.env, () => mintInstallationToken(appActorDeps()));
|
|
57006
|
+
await activateAppActor(commandPath3, process.env, () => APP_WRITE_COMMANDS.has(commandPath3) ? mintCommandWriteToken(appActorDeps(), commandPath3) : mintInstallationToken(appActorDeps()));
|
|
56866
57007
|
} catch (e) {
|
|
56867
57008
|
if (e instanceof AppActorError) return fail(e.message);
|
|
56868
57009
|
throw e;
|
|
@@ -57220,7 +57361,7 @@ project.command("set [owner/repo]").description("upsert project META (idempotent
|
|
|
57220
57361
|
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`);
|
|
57221
57362
|
if (o.secretsFile) {
|
|
57222
57363
|
try {
|
|
57223
|
-
vars.push(`secrets=${(0,
|
|
57364
|
+
vars.push(`secrets=${(0, import_node_fs59.readFileSync)(o.secretsFile, "utf8")}`);
|
|
57224
57365
|
} catch (e) {
|
|
57225
57366
|
return fail(`org project set: cannot read --secrets-file ${o.secretsFile}: ${e.message}`);
|
|
57226
57367
|
}
|
|
@@ -57612,15 +57753,15 @@ function ciAuditDeps2() {
|
|
|
57612
57753
|
readSeedFile: (path2) => {
|
|
57613
57754
|
if (!root) return null;
|
|
57614
57755
|
const fullPath = (0, import_node_path57.join)(root, path2);
|
|
57615
|
-
return (0,
|
|
57756
|
+
return (0, import_node_fs59.existsSync)(fullPath) ? (0, import_node_fs59.readFileSync)(fullPath, "utf8") : null;
|
|
57616
57757
|
}
|
|
57617
57758
|
};
|
|
57618
57759
|
}
|
|
57619
57760
|
function hubRoot2() {
|
|
57620
57761
|
const fromPkg = (0, import_node_path57.join)(__dirname, "..", "..");
|
|
57621
57762
|
const marker = "skills/bootstrap/seeds/manifest.json";
|
|
57622
|
-
if ((0,
|
|
57623
|
-
if ((0,
|
|
57763
|
+
if ((0, import_node_fs59.existsSync)((0, import_node_path57.join)(fromPkg, marker))) return fromPkg;
|
|
57764
|
+
if ((0, import_node_fs59.existsSync)((0, import_node_path57.join)(process.cwd(), marker))) return process.cwd();
|
|
57624
57765
|
return null;
|
|
57625
57766
|
}
|
|
57626
57767
|
registerQueryCommands(program2);
|
|
@@ -57634,6 +57775,7 @@ registerDiscoveryCommands(program2);
|
|
|
57634
57775
|
registerExplainCommand(program2);
|
|
57635
57776
|
registerPrLifecycleCommands(program2);
|
|
57636
57777
|
registerApiReadCommands(program2);
|
|
57778
|
+
registerGithubBudgetCommand(program2, appActorDeps);
|
|
57637
57779
|
registerAppReadBrokerCommands(program2, async (repo) => requireRepo(repo));
|
|
57638
57780
|
var prBrokerRoot = program2.commands.find((c) => c.name() === "pr");
|
|
57639
57781
|
if (!prBrokerRoot) throw new Error("read broker: pr root must be registered before pr checks-required");
|
|
@@ -57750,10 +57892,10 @@ access.command("audit").description("audit collaborator roles + train-branch pus
|
|
|
57750
57892
|
targets = resolution.targets;
|
|
57751
57893
|
}
|
|
57752
57894
|
const derivedMatrix = registryProjects ? accessMatrixFromProjects(registryProjects) : {};
|
|
57753
|
-
const fileMatrix = (0,
|
|
57895
|
+
const fileMatrix = (0, import_node_fs59.existsSync)("access-matrix.json") ? loadAccessMatrix((0, import_node_fs59.readFileSync)("access-matrix.json", "utf8")) : {};
|
|
57754
57896
|
const matrix = mergeAccessMatrix(fileMatrix, derivedMatrix);
|
|
57755
57897
|
const dataAccess = registryProjects ? dataAccessContractsFromProjects(registryProjects) : { consumers: {} };
|
|
57756
|
-
const sanctioned = (0,
|
|
57898
|
+
const sanctioned = (0, import_node_fs59.existsSync)("access-matrix.json") ? loadSanctionedAdmins((0, import_node_fs59.readFileSync)("access-matrix.json", "utf8")) : {};
|
|
57757
57899
|
const report = await auditOrgAccess(targets, deps, matrix, dataAccess, sanctioned);
|
|
57758
57900
|
console.log(o.json ? JSON.stringify(report, null, 2) : renderAccessReport(report));
|
|
57759
57901
|
if (!report.ok) process.exitCode = 1;
|
|
@@ -57784,7 +57926,7 @@ function directoryBytes(path2) {
|
|
|
57784
57926
|
let total = 0;
|
|
57785
57927
|
let entries;
|
|
57786
57928
|
try {
|
|
57787
|
-
entries = (0,
|
|
57929
|
+
entries = (0, import_node_fs59.readdirSync)(path2, { withFileTypes: true });
|
|
57788
57930
|
} catch {
|
|
57789
57931
|
return 0;
|
|
57790
57932
|
}
|
|
@@ -57793,7 +57935,7 @@ function directoryBytes(path2) {
|
|
|
57793
57935
|
if (entry.isDirectory()) total += directoryBytes(child2);
|
|
57794
57936
|
else {
|
|
57795
57937
|
try {
|
|
57796
|
-
total += (0,
|
|
57938
|
+
total += (0, import_node_fs59.statSync)(child2).size;
|
|
57797
57939
|
} catch {
|
|
57798
57940
|
}
|
|
57799
57941
|
}
|
|
@@ -57801,25 +57943,25 @@ function directoryBytes(path2) {
|
|
|
57801
57943
|
return total;
|
|
57802
57944
|
}
|
|
57803
57945
|
function listDirEntries(dir) {
|
|
57804
|
-
return (0,
|
|
57946
|
+
return (0, import_node_fs59.readdirSync)(dir, { withFileTypes: true }).map((d) => ({ name: d.name, isDirectory: d.isDirectory() }));
|
|
57805
57947
|
}
|
|
57806
57948
|
function readInstalledPluginRefs(configRoot) {
|
|
57807
57949
|
const p = installedPluginsPathForConfig(configRoot);
|
|
57808
|
-
if (!(0,
|
|
57950
|
+
if (!(0, import_node_fs59.existsSync)(p)) return [];
|
|
57809
57951
|
try {
|
|
57810
|
-
return installedPluginPaths((0,
|
|
57952
|
+
return installedPluginPaths((0, import_node_fs59.readFileSync)(p, "utf8"));
|
|
57811
57953
|
} catch {
|
|
57812
57954
|
return null;
|
|
57813
57955
|
}
|
|
57814
57956
|
}
|
|
57815
57957
|
function pluginCacheFsDeps(configRoot, dirBytes) {
|
|
57816
57958
|
return {
|
|
57817
|
-
exists: (p) => (0,
|
|
57818
|
-
listVersionDirs: (root) => (0,
|
|
57959
|
+
exists: (p) => (0, import_node_fs59.existsSync)(p),
|
|
57960
|
+
listVersionDirs: (root) => (0, import_node_fs59.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name),
|
|
57819
57961
|
dirBytes,
|
|
57820
|
-
listStagingDirs: (root) => (0,
|
|
57962
|
+
listStagingDirs: (root) => (0, import_node_fs59.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => {
|
|
57821
57963
|
try {
|
|
57822
|
-
return { name: d.name, mtimeMs: newestMtimeMs((0, import_node_path57.join)(root, d.name), listDirEntries, (p) => (0,
|
|
57964
|
+
return { name: d.name, mtimeMs: newestMtimeMs((0, import_node_path57.join)(root, d.name), listDirEntries, (p) => (0, import_node_fs59.statSync)(p).mtimeMs) };
|
|
57823
57965
|
} catch {
|
|
57824
57966
|
return { name: d.name, mtimeMs: Date.now() };
|
|
57825
57967
|
}
|
|
@@ -57834,9 +57976,9 @@ function stagingApplyFsGuard(configRoot) {
|
|
|
57834
57976
|
referencedPaths: () => readInstalledPluginRefs(configRoot),
|
|
57835
57977
|
mtimeMs: (name) => {
|
|
57836
57978
|
const p = (0, import_node_path57.join)(stagingRoot, name);
|
|
57837
|
-
if (!(0,
|
|
57979
|
+
if (!(0, import_node_fs59.existsSync)(p)) return null;
|
|
57838
57980
|
try {
|
|
57839
|
-
return newestMtimeMs(p, listDirEntries, (q) => (0,
|
|
57981
|
+
return newestMtimeMs(p, listDirEntries, (q) => (0, import_node_fs59.statSync)(q).mtimeMs);
|
|
57840
57982
|
} catch {
|
|
57841
57983
|
return null;
|
|
57842
57984
|
}
|
|
@@ -57862,7 +58004,7 @@ program2.command("plugin-prune").description(`prune stale cached MMI plugin vers
|
|
|
57862
58004
|
{ withBytes: true, configRoot, includeStaging: surface !== "codex" }
|
|
57863
58005
|
);
|
|
57864
58006
|
const anythingToDelete = plan.prune.length > 0 || plan.staging.length > 0;
|
|
57865
|
-
const result = o.apply && anythingToDelete ? applyPluginCachePlan(plan, (p) => (0,
|
|
58007
|
+
const result = o.apply && anythingToDelete ? applyPluginCachePlan(plan, (p) => (0, import_node_fs59.rmSync)(p, { recursive: true, force: true }), stagingApplyFsGuard(configRoot)) : void 0;
|
|
57866
58008
|
const warnings = plan.prune.length > 0 ? [CONCURRENT_SESSION_WARNING] : [];
|
|
57867
58009
|
if (o.json) console.log(JSON.stringify({ ...plan, warnings, applied: result ?? null }));
|
|
57868
58010
|
else console.log(renderPluginCachePlan(plan, result));
|