@mutmutco/cli 4.5.158 → 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 +559 -373
- 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();
|
|
@@ -7068,6 +7139,8 @@ var import_node_crypto5 = require("node:crypto");
|
|
|
7068
7139
|
var APP_ACTOR_ENV = "MMI_ACTOR";
|
|
7069
7140
|
var APP_VAULT_REPO = "mutmutco/MMI-Hub";
|
|
7070
7141
|
var APP_VAULT_KEYS = ["GITHUB_APP_ID", "GITHUB_APP_INSTALLATION_ID", "GITHUB_APP_PRIVATE_KEY"];
|
|
7142
|
+
var APP2_VAULT_KEYS = ["GITHUB_APP2_ID", "GITHUB_APP2_INSTALLATION_ID", "GITHUB_APP2_PRIVATE_KEY"];
|
|
7143
|
+
var APP_POOL_MEMBERS = [APP_VAULT_KEYS, APP2_VAULT_KEYS];
|
|
7071
7144
|
var APP_ELIGIBLE_COMMANDS = /* @__PURE__ */ new Set([
|
|
7072
7145
|
"pr checks-wait",
|
|
7073
7146
|
// #8042: App-native required-only read (`pr checks-required`) — REST check/status rows scoped by
|
|
@@ -7165,6 +7238,19 @@ async function readAppVaultSecret(read) {
|
|
|
7165
7238
|
async function mintInstallationToken(deps) {
|
|
7166
7239
|
return mintScopedInstallationToken(deps, APP_POLL_PERMISSIONS);
|
|
7167
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
|
+
}
|
|
7168
7254
|
async function mintStatusWriteToken(deps) {
|
|
7169
7255
|
return mintScopedInstallationToken(deps, { metadata: "read", statuses: "write" });
|
|
7170
7256
|
}
|
|
@@ -7184,10 +7270,55 @@ async function fleetStatusWriteEnv(args) {
|
|
|
7184
7270
|
}
|
|
7185
7271
|
}
|
|
7186
7272
|
async function mintScopedInstallationToken(deps, permissions) {
|
|
7187
|
-
const
|
|
7273
|
+
const start = Math.floor((deps.random ?? Math.random)() * APP_POOL_MEMBERS.length) % APP_POOL_MEMBERS.length;
|
|
7274
|
+
const order = APP_POOL_MEMBERS.map((_, i) => APP_POOL_MEMBERS[(start + i) % APP_POOL_MEMBERS.length]);
|
|
7275
|
+
let firstError;
|
|
7276
|
+
let exhausted;
|
|
7277
|
+
let absent = 0;
|
|
7278
|
+
for (const [i, keys] of order.entries()) {
|
|
7279
|
+
try {
|
|
7280
|
+
const minted = await mintFromMember(deps, permissions, keys);
|
|
7281
|
+
if (i === order.length - 1 || !await allowanceSpent(deps, minted.token)) return minted;
|
|
7282
|
+
exhausted ??= minted;
|
|
7283
|
+
} catch (e) {
|
|
7284
|
+
if (e instanceof AppActorError && e.code === "vault-denied") {
|
|
7285
|
+
absent += 1;
|
|
7286
|
+
continue;
|
|
7287
|
+
}
|
|
7288
|
+
firstError ??= e;
|
|
7289
|
+
}
|
|
7290
|
+
}
|
|
7291
|
+
if (exhausted) return exhausted;
|
|
7292
|
+
if (firstError) throw firstError;
|
|
7293
|
+
if (absent === order.length) {
|
|
7294
|
+
throw new AppActorError(
|
|
7295
|
+
`app actor: vault denied all App credentials (${APP_VAULT_REPO} tier) \u2014 not an automation host, or no vault access`,
|
|
7296
|
+
"vault-denied"
|
|
7297
|
+
);
|
|
7298
|
+
}
|
|
7299
|
+
throw new AppActorError("app actor: no App pool member minted \u2014 automation fails closed");
|
|
7300
|
+
}
|
|
7301
|
+
async function allowanceSpent(deps, token) {
|
|
7302
|
+
try {
|
|
7303
|
+
const res = await deps.fetch("https://api.github.com/rate_limit", {
|
|
7304
|
+
method: "GET",
|
|
7305
|
+
headers: { authorization: `Bearer ${token}`, accept: "application/vnd.github+json", "user-agent": "mmi-cli-app-actor" }
|
|
7306
|
+
});
|
|
7307
|
+
if (!res.ok) return false;
|
|
7308
|
+
const body = await res.json();
|
|
7309
|
+
return body.resources?.core?.remaining === 0 || body.resources?.graphql?.remaining === 0;
|
|
7310
|
+
} catch {
|
|
7311
|
+
return false;
|
|
7312
|
+
}
|
|
7313
|
+
}
|
|
7314
|
+
function mintBudgetToken(deps, keys) {
|
|
7315
|
+
return mintFromMember(deps, { metadata: "read" }, keys);
|
|
7316
|
+
}
|
|
7317
|
+
async function mintFromMember(deps, permissions, keys) {
|
|
7318
|
+
const [appId, installationId, privateKey] = await Promise.all(keys.map((k) => deps.fetchSecret(k)));
|
|
7188
7319
|
if (!appId || !installationId || !privateKey) {
|
|
7189
|
-
const missing =
|
|
7190
|
-
if (missing.length ===
|
|
7320
|
+
const missing = keys.filter((_, i) => ![appId, installationId, privateKey][i]);
|
|
7321
|
+
if (missing.length === keys.length) {
|
|
7191
7322
|
throw new AppActorError(
|
|
7192
7323
|
`app actor: vault denied all App credentials (${APP_VAULT_REPO} tier) \u2014 not an automation host, or no vault access`,
|
|
7193
7324
|
"vault-denied"
|
|
@@ -7250,7 +7381,7 @@ async function activateAppActor(commandPath3, env, mint, note = (line) => proces
|
|
|
7250
7381
|
if (requested && requested !== "app") {
|
|
7251
7382
|
throw new AppActorError(`app actor: unknown ${APP_ACTOR_ENV} value \u2014 only 'app' and 'personal' are supported; refusing to guess an identity`);
|
|
7252
7383
|
}
|
|
7253
|
-
if (!APP_ELIGIBLE_COMMANDS.has(commandPath3)) {
|
|
7384
|
+
if (!APP_ELIGIBLE_COMMANDS.has(commandPath3) && !APP_WRITE_COMMANDS.has(commandPath3)) {
|
|
7254
7385
|
if (requested === "app" && !notedIneligibleCommand) {
|
|
7255
7386
|
notedIneligibleCommand = true;
|
|
7256
7387
|
note(`app actor: '${commandPath3}' is personal-only (viewer/@me/authorship) \u2014 running on the personal token despite ${APP_ACTOR_ENV}=app`);
|
|
@@ -11257,6 +11388,7 @@ init_clean_exit();
|
|
|
11257
11388
|
|
|
11258
11389
|
// src/gh-create.ts
|
|
11259
11390
|
var import_promises = require("node:fs/promises");
|
|
11391
|
+
var import_node_fs16 = require("node:fs");
|
|
11260
11392
|
var import_node_os8 = require("node:os");
|
|
11261
11393
|
var import_node_path13 = require("node:path");
|
|
11262
11394
|
var import_node_crypto7 = require("node:crypto");
|
|
@@ -11522,18 +11654,23 @@ async function preflightPrCreateRemoteHead(args, deps) {
|
|
|
11522
11654
|
if (compared !== "unknown" && compared.aheadBy <= 0) return emptyCompareMessage(base, head);
|
|
11523
11655
|
return void 0;
|
|
11524
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
|
+
}
|
|
11525
11666
|
function buildPrCreateRetryCommand(args) {
|
|
11526
11667
|
const parts = ["mmi-cli", "devops", "pr", "create"];
|
|
11527
11668
|
for (const flag of ["--repo", "--base", "--head", "--title"]) {
|
|
11528
11669
|
const v = flagValue(args, flag);
|
|
11529
11670
|
if (v !== void 0) parts.push(flag, shellQuote(v));
|
|
11530
11671
|
}
|
|
11531
|
-
const bodyFile =
|
|
11672
|
+
const bodyFile = retryBodyFile(args);
|
|
11532
11673
|
if (bodyFile !== void 0) parts.push("--body-file", shellQuote(bodyFile));
|
|
11533
|
-
else {
|
|
11534
|
-
const body = flagValue(args, "--body");
|
|
11535
|
-
if (body !== void 0) parts.push("--body", shellQuote(body));
|
|
11536
|
-
}
|
|
11537
11674
|
if (args.includes("--draft")) parts.push("--draft");
|
|
11538
11675
|
return parts.join(" ");
|
|
11539
11676
|
}
|
|
@@ -11556,12 +11693,8 @@ function buildIssueCreateRetryCommand(args) {
|
|
|
11556
11693
|
if (type) parts.push("--type", type);
|
|
11557
11694
|
const title = flagValue(args, "--title");
|
|
11558
11695
|
if (title !== void 0) parts.push("--title", shellQuote(title));
|
|
11559
|
-
const bodyFile =
|
|
11696
|
+
const bodyFile = retryBodyFile(args);
|
|
11560
11697
|
if (bodyFile !== void 0) parts.push("--body-file", shellQuote(bodyFile));
|
|
11561
|
-
else {
|
|
11562
|
-
const body = flagValue(args, "--body");
|
|
11563
|
-
if (body !== void 0) parts.push("--body", shellQuote(body));
|
|
11564
|
-
}
|
|
11565
11698
|
for (const label of labels) {
|
|
11566
11699
|
if (label === type) continue;
|
|
11567
11700
|
parts.push("--label", shellQuote(label));
|
|
@@ -14518,11 +14651,11 @@ function probeLocalClaimSession(marker, now = Date.now()) {
|
|
|
14518
14651
|
const pending = [root];
|
|
14519
14652
|
while (pending.length) {
|
|
14520
14653
|
const dir = pending.pop();
|
|
14521
|
-
for (const entry of (0,
|
|
14654
|
+
for (const entry of (0, import_node_fs17.readdirSync)(dir, { withFileTypes: true })) {
|
|
14522
14655
|
const path2 = (0, import_node_path14.join)(dir, entry.name);
|
|
14523
14656
|
if (entry.isDirectory()) pending.push(path2);
|
|
14524
14657
|
else if (entry.isFile() && entry.name.toLowerCase() === wanted) {
|
|
14525
|
-
return remember(now - (0,
|
|
14658
|
+
return remember(now - (0, import_node_fs17.statSync)(path2).mtimeMs <= CLAIM_SESSION_ACTIVITY_MS ? "live" : "dead");
|
|
14526
14659
|
}
|
|
14527
14660
|
}
|
|
14528
14661
|
}
|
|
@@ -16027,12 +16160,12 @@ function planManagedGitignore(current) {
|
|
|
16027
16160
|
}
|
|
16028
16161
|
|
|
16029
16162
|
// src/docs-index-command.ts
|
|
16030
|
-
var
|
|
16163
|
+
var import_node_fs19 = require("node:fs");
|
|
16031
16164
|
var import_node_path16 = require("node:path");
|
|
16032
16165
|
|
|
16033
16166
|
// src/doc-refs-core.ts
|
|
16034
16167
|
var import_node_child_process6 = require("node:child_process");
|
|
16035
|
-
var
|
|
16168
|
+
var import_node_fs18 = require("node:fs");
|
|
16036
16169
|
var import_node_path15 = require("node:path");
|
|
16037
16170
|
var PIN_RE = /<!--\s*pinned by\s+([^:]+?)\s*:\s*"([^"]+)"[^"]*-->/;
|
|
16038
16171
|
var PIN_MENTION_RE = /<!--\s*pinned by\b/;
|
|
@@ -16405,12 +16538,12 @@ function checkSeedRunbookReview(root, base, readFile10, git3) {
|
|
|
16405
16538
|
return findings;
|
|
16406
16539
|
}
|
|
16407
16540
|
function readFileOrNull(path2) {
|
|
16408
|
-
return (0,
|
|
16541
|
+
return (0, import_node_fs18.existsSync)(path2) ? (0, import_node_fs18.readFileSync)(path2, "utf8") : null;
|
|
16409
16542
|
}
|
|
16410
16543
|
function walk(dir, root, out) {
|
|
16411
|
-
for (const entry of (0,
|
|
16544
|
+
for (const entry of (0, import_node_fs18.readdirSync)(dir)) {
|
|
16412
16545
|
const full = (0, import_node_path15.join)(dir, entry);
|
|
16413
|
-
if ((0,
|
|
16546
|
+
if ((0, import_node_fs18.statSync)(full).isDirectory()) walk(full, root, out);
|
|
16414
16547
|
else if (entry.endsWith(".md")) out.push(full.slice(root.length + 1).replaceAll("\\", "/"));
|
|
16415
16548
|
}
|
|
16416
16549
|
return out;
|
|
@@ -16418,11 +16551,11 @@ function walk(dir, root, out) {
|
|
|
16418
16551
|
function defaultListDocs(root) {
|
|
16419
16552
|
const docs = ["docs", "skills/org-guide", "skills/mmi-help"].flatMap((path2) => {
|
|
16420
16553
|
const directory = (0, import_node_path15.join)(root, path2);
|
|
16421
|
-
return (0,
|
|
16554
|
+
return (0, import_node_fs18.existsSync)(directory) ? walk(directory, root, []) : [];
|
|
16422
16555
|
}).filter(
|
|
16423
16556
|
(rel) => !SKIP_WALK.some((skip) => rel.startsWith(skip))
|
|
16424
16557
|
);
|
|
16425
|
-
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];
|
|
16426
16559
|
}
|
|
16427
16560
|
var CHECK_IGNORE_MAX_BUFFER = 32 * 1024 * 1024;
|
|
16428
16561
|
function defaultIsIgnored(root, relPaths, exec3 = import_node_child_process6.execFileSync) {
|
|
@@ -16503,7 +16636,7 @@ function mergeGroupRunbookMessages(root, deps, readFile10, warnings) {
|
|
|
16503
16636
|
}
|
|
16504
16637
|
function runDocRefs(root, deps = {}) {
|
|
16505
16638
|
const readFile10 = deps.readFile ?? readFileOrNull;
|
|
16506
|
-
const exists = deps.exists ??
|
|
16639
|
+
const exists = deps.exists ?? import_node_fs18.existsSync;
|
|
16507
16640
|
const listDocs = deps.listDocs ?? defaultListDocs;
|
|
16508
16641
|
const isIgnored = deps.isIgnored ?? ((paths) => defaultIsIgnored(root, paths));
|
|
16509
16642
|
const trackedFirstSegments = deps.trackedFirstSegments ?? ((segs) => defaultTrackedFirstSegments(root, segs));
|
|
@@ -16636,7 +16769,7 @@ function walkMarkdown(dir) {
|
|
|
16636
16769
|
const stack = [dir];
|
|
16637
16770
|
while (stack.length) {
|
|
16638
16771
|
const current = stack.pop();
|
|
16639
|
-
for (const entry of (0,
|
|
16772
|
+
for (const entry of (0, import_node_fs19.readdirSync)(current, { withFileTypes: true })) {
|
|
16640
16773
|
const full = (0, import_node_path16.join)(current, entry.name);
|
|
16641
16774
|
if (entry.isDirectory()) {
|
|
16642
16775
|
stack.push(full);
|
|
@@ -16652,15 +16785,15 @@ function createDocsIndexDeps(repoRoot2) {
|
|
|
16652
16785
|
const indexPath = (0, import_node_path16.join)(repoRoot2, DOCS_INDEX_PATH);
|
|
16653
16786
|
return {
|
|
16654
16787
|
listDocs: () => {
|
|
16655
|
-
if (!(0,
|
|
16788
|
+
if (!(0, import_node_fs19.existsSync)(docsDir)) return [];
|
|
16656
16789
|
const walked = walkMarkdown(docsDir).filter(isRoutableDocsPath);
|
|
16657
16790
|
if (!walked.length) return [];
|
|
16658
16791
|
const ignored = defaultIsIgnored(repoRoot2, walked.map((rel) => `docs/${rel}`));
|
|
16659
16792
|
return walked.filter((rel) => !ignored.has(`docs/${rel}`)).sort();
|
|
16660
16793
|
},
|
|
16661
|
-
readDoc: (relPath) => (0,
|
|
16662
|
-
readIndex: () => (0,
|
|
16663
|
-
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")
|
|
16664
16797
|
};
|
|
16665
16798
|
}
|
|
16666
16799
|
|
|
@@ -17579,7 +17712,7 @@ function contentPutInputArgs(repo, path2, inputFile) {
|
|
|
17579
17712
|
}
|
|
17580
17713
|
|
|
17581
17714
|
// src/train-apply-contracts.ts
|
|
17582
|
-
var
|
|
17715
|
+
var import_node_fs20 = require("node:fs");
|
|
17583
17716
|
var import_node_path17 = require("node:path");
|
|
17584
17717
|
function reduceFollowUpOutcomes(outcomes) {
|
|
17585
17718
|
if (outcomes.includes("failure")) return "failure";
|
|
@@ -17660,7 +17793,7 @@ async function resolveFoldPaths(deps, model) {
|
|
|
17660
17793
|
if (model === "vercel") return [];
|
|
17661
17794
|
const helper = "scripts/release-distribution.mjs";
|
|
17662
17795
|
if (model === "hub-serverless" || model === "registry-publish") {
|
|
17663
|
-
if ((0,
|
|
17796
|
+
if ((0, import_node_fs20.existsSync)(helper)) {
|
|
17664
17797
|
let out;
|
|
17665
17798
|
try {
|
|
17666
17799
|
out = await deps.run("node", [helper, "changed-files"]);
|
|
@@ -17809,7 +17942,7 @@ async function restoreMainNpmPackIdentities(deps, version) {
|
|
|
17809
17942
|
if (mainBom.version !== version) return void 0;
|
|
17810
17943
|
let localBom;
|
|
17811
17944
|
try {
|
|
17812
|
-
localBom = JSON.parse((0,
|
|
17945
|
+
localBom = JSON.parse((0, import_node_fs20.readFileSync)(bomPath, "utf8"));
|
|
17813
17946
|
} catch (e) {
|
|
17814
17947
|
throw new Error(
|
|
17815
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).`
|
|
@@ -17827,14 +17960,14 @@ async function restoreMainNpmPackIdentities(deps, version) {
|
|
|
17827
17960
|
restored += 1;
|
|
17828
17961
|
}
|
|
17829
17962
|
if (restored === 0) return void 0;
|
|
17830
|
-
(0,
|
|
17963
|
+
(0, import_node_fs20.writeFileSync)(bomPath, `${JSON.stringify(localBom, null, 2)}
|
|
17831
17964
|
`);
|
|
17832
17965
|
return `restored ${restored} npm-pack BOM identit${restored === 1 ? "y" : "ies"} from origin/main (#4503)`;
|
|
17833
17966
|
}
|
|
17834
17967
|
function publishVisibilityFor(surfaceId) {
|
|
17835
17968
|
let raw;
|
|
17836
17969
|
try {
|
|
17837
|
-
raw = (0,
|
|
17970
|
+
raw = (0, import_node_fs20.readFileSync)("surfaces.json", "utf8");
|
|
17838
17971
|
} catch (e) {
|
|
17839
17972
|
if (e.code === "ENOENT") return "unknown";
|
|
17840
17973
|
throw trainReadFailure(
|
|
@@ -17855,7 +17988,7 @@ function publishVisibilityFor(surfaceId) {
|
|
|
17855
17988
|
}
|
|
17856
17989
|
function npmPackArtifactName(packagePath) {
|
|
17857
17990
|
try {
|
|
17858
|
-
const pkg = JSON.parse((0,
|
|
17991
|
+
const pkg = JSON.parse((0, import_node_fs20.readFileSync)((0, import_node_path17.join)(packagePath, "package.json"), "utf8"));
|
|
17859
17992
|
return pkg.name || void 0;
|
|
17860
17993
|
} catch {
|
|
17861
17994
|
return void 0;
|
|
@@ -17864,7 +17997,7 @@ function npmPackArtifactName(packagePath) {
|
|
|
17864
17997
|
async function refuseDivergentPublishedNpmPack(deps, version) {
|
|
17865
17998
|
let localBom;
|
|
17866
17999
|
try {
|
|
17867
|
-
localBom = JSON.parse((0,
|
|
18000
|
+
localBom = JSON.parse((0, import_node_fs20.readFileSync)("distribution-bom.json", "utf8"));
|
|
17868
18001
|
} catch (e) {
|
|
17869
18002
|
throw new Error(
|
|
17870
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).`
|
|
@@ -18009,7 +18142,7 @@ function assertGitBashOnWindowsForJervHubRelease(repo, platform2 = process.platf
|
|
|
18009
18142
|
}
|
|
18010
18143
|
|
|
18011
18144
|
// src/train-apply-correlation.ts
|
|
18012
|
-
var
|
|
18145
|
+
var import_node_fs22 = require("node:fs");
|
|
18013
18146
|
init_github_quota();
|
|
18014
18147
|
var import_node_path19 = require("node:path");
|
|
18015
18148
|
|
|
@@ -18776,10 +18909,10 @@ var rollout_plan_default = {
|
|
|
18776
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)."
|
|
18777
18910
|
},
|
|
18778
18911
|
baseline: {
|
|
18779
|
-
version: "4.5.
|
|
18780
|
-
tag: "v4.5.
|
|
18781
|
-
commit: "
|
|
18782
|
-
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"
|
|
18783
18916
|
},
|
|
18784
18917
|
exitCriterion: "fleet-n-of-n",
|
|
18785
18918
|
hubOnlyShortcut: "forbidden",
|
|
@@ -18796,14 +18929,14 @@ var rollout_plan_default = {
|
|
|
18796
18929
|
repo: "mutmutco/mmi-hub",
|
|
18797
18930
|
role: "canary",
|
|
18798
18931
|
schedule: "train",
|
|
18799
|
-
v3Target: "v4.5.
|
|
18932
|
+
v3Target: "v4.5.160"
|
|
18800
18933
|
}
|
|
18801
18934
|
],
|
|
18802
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.",
|
|
18803
18936
|
rollback: {
|
|
18804
18937
|
independent: true,
|
|
18805
|
-
mechanism: "npm dist-tag latest -> 4.5.
|
|
18806
|
-
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)"
|
|
18807
18940
|
}
|
|
18808
18941
|
},
|
|
18809
18942
|
{
|
|
@@ -19137,13 +19270,13 @@ function resolveIssueViewGhFields(normalized) {
|
|
|
19137
19270
|
}
|
|
19138
19271
|
|
|
19139
19272
|
// src/utf8-receipt.ts
|
|
19140
|
-
var
|
|
19273
|
+
var import_node_fs21 = require("node:fs");
|
|
19141
19274
|
var import_node_path18 = require("node:path");
|
|
19142
19275
|
function writeUtf8Receipt(path2, text) {
|
|
19143
|
-
(0,
|
|
19276
|
+
(0, import_node_fs21.mkdirSync)((0, import_node_path18.dirname)(path2), { recursive: true });
|
|
19144
19277
|
const body = text.endsWith("\n") ? text : `${text}
|
|
19145
19278
|
`;
|
|
19146
|
-
(0,
|
|
19279
|
+
(0, import_node_fs21.writeFileSync)(path2, body, "utf8");
|
|
19147
19280
|
return Buffer.byteLength(body, "utf8");
|
|
19148
19281
|
}
|
|
19149
19282
|
|
|
@@ -21029,7 +21162,7 @@ function resolveReleaseAbortNpmPackage(meta, repo) {
|
|
|
21029
21162
|
if (isHubControlRepo(repo)) return "@mutmutco/cli";
|
|
21030
21163
|
const publishDir = typeof meta.publishDir === "string" && meta.publishDir.trim() ? meta.publishDir.trim() : ".";
|
|
21031
21164
|
try {
|
|
21032
|
-
const pkg = JSON.parse((0,
|
|
21165
|
+
const pkg = JSON.parse((0, import_node_fs22.readFileSync)((0, import_node_path19.join)(publishDir, "package.json"), "utf8"));
|
|
21033
21166
|
const name = pkg.name?.trim();
|
|
21034
21167
|
if (!name) throw new Error("missing name field");
|
|
21035
21168
|
return name;
|
|
@@ -21965,7 +22098,7 @@ function parseVerifyBroker(stdout) {
|
|
|
21965
22098
|
}
|
|
21966
22099
|
|
|
21967
22100
|
// src/train-apply-deploy.ts
|
|
21968
|
-
var
|
|
22101
|
+
var import_node_fs23 = require("node:fs");
|
|
21969
22102
|
var import_node_os11 = require("node:os");
|
|
21970
22103
|
var import_node_path20 = require("node:path");
|
|
21971
22104
|
|
|
@@ -22106,7 +22239,7 @@ function mmiGetRedeployCommand(repo) {
|
|
|
22106
22239
|
}
|
|
22107
22240
|
function readLocalLauncherVersion(root = process.cwd()) {
|
|
22108
22241
|
try {
|
|
22109
|
-
const raw = (0,
|
|
22242
|
+
const raw = (0, import_node_fs23.readFileSync)((0, import_node_path20.join)(root, "cli", "package.json"), "utf8");
|
|
22110
22243
|
const version = JSON.parse(raw).version;
|
|
22111
22244
|
return typeof version === "string" && version.trim() ? version.trim() : null;
|
|
22112
22245
|
} catch {
|
|
@@ -22115,7 +22248,7 @@ function readLocalLauncherVersion(root = process.cwd()) {
|
|
|
22115
22248
|
}
|
|
22116
22249
|
function readServedChannelUrl(product = HUB_SERVED_PRODUCT, root = process.cwd()) {
|
|
22117
22250
|
try {
|
|
22118
|
-
const raw = (0,
|
|
22251
|
+
const raw = (0, import_node_fs23.readFileSync)((0, import_node_path20.join)(root, "config", `product.${product}.json`), "utf8");
|
|
22119
22252
|
const host = JSON.parse(raw).host;
|
|
22120
22253
|
if (typeof host !== "string" || !host.trim()) return null;
|
|
22121
22254
|
return `${host.trim().replace(/\/+$/, "")}/release/version`;
|
|
@@ -22549,13 +22682,13 @@ async function runTaggedJervGatewayLocalWrapper(deps, tag, tagSha) {
|
|
|
22549
22682
|
const reason = error instanceof Error ? error.message : String(error);
|
|
22550
22683
|
throw new Error(`could not extract ${JERV_GATEWAY_RELEASE_DEPLOY_SCRIPT} from tagged commit ${tagSha.slice(0, 12)}: ${reason}`);
|
|
22551
22684
|
}
|
|
22552
|
-
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-"));
|
|
22553
22686
|
const extracted = (0, import_node_path20.join)(dir, "jerv-gateway-release-deploy.sh");
|
|
22554
22687
|
try {
|
|
22555
|
-
(0,
|
|
22688
|
+
(0, import_node_fs23.writeFileSync)(extracted, script, "utf8");
|
|
22556
22689
|
return await deps.run("bash", [extracted, "--tag", tag]);
|
|
22557
22690
|
} finally {
|
|
22558
|
-
(0,
|
|
22691
|
+
(0, import_node_fs23.rmSync)(dir, { recursive: true, force: true });
|
|
22559
22692
|
}
|
|
22560
22693
|
}
|
|
22561
22694
|
async function appendJervGatewayReleaseDeploy(deps, repo, tag, tagSha, dispatch) {
|
|
@@ -23131,7 +23264,7 @@ function renderTenantControl(r) {
|
|
|
23131
23264
|
}
|
|
23132
23265
|
|
|
23133
23266
|
// src/train-apply-phases.ts
|
|
23134
|
-
var
|
|
23267
|
+
var import_node_fs29 = require("node:fs");
|
|
23135
23268
|
var import_promises4 = require("node:fs/promises");
|
|
23136
23269
|
var import_node_path27 = require("node:path");
|
|
23137
23270
|
|
|
@@ -23450,12 +23583,12 @@ function assertPreOneZero(repo, meta, tag) {
|
|
|
23450
23583
|
|
|
23451
23584
|
// src/train-doctor.ts
|
|
23452
23585
|
var import_node_child_process9 = require("node:child_process");
|
|
23453
|
-
var
|
|
23586
|
+
var import_node_fs27 = require("node:fs");
|
|
23454
23587
|
var import_node_os15 = require("node:os");
|
|
23455
23588
|
var import_node_path26 = require("node:path");
|
|
23456
23589
|
|
|
23457
23590
|
// src/doctor-io.ts
|
|
23458
|
-
var
|
|
23591
|
+
var import_node_fs24 = require("node:fs");
|
|
23459
23592
|
var import_node_os12 = require("node:os");
|
|
23460
23593
|
var import_node_path21 = require("node:path");
|
|
23461
23594
|
var import_node_child_process7 = require("node:child_process");
|
|
@@ -23470,8 +23603,8 @@ function nodeDiscardSinkPath(platform2 = process.platform) {
|
|
|
23470
23603
|
var execFileP2 = (0, import_node_util4.promisify)(import_node_child_process7.execFile);
|
|
23471
23604
|
function execFileCapture(file, args, opts = {}) {
|
|
23472
23605
|
const sink = nodeDiscardSinkPath();
|
|
23473
|
-
const inFd = (0,
|
|
23474
|
-
const errFd = (0,
|
|
23606
|
+
const inFd = (0, import_node_fs24.openSync)(sink, "r");
|
|
23607
|
+
const errFd = (0, import_node_fs24.openSync)(sink, "w");
|
|
23475
23608
|
try {
|
|
23476
23609
|
return (0, import_node_child_process7.execFileSync)(file, args, {
|
|
23477
23610
|
...opts,
|
|
@@ -23479,17 +23612,17 @@ function execFileCapture(file, args, opts = {}) {
|
|
|
23479
23612
|
stdio: [inFd, "pipe", errFd]
|
|
23480
23613
|
});
|
|
23481
23614
|
} finally {
|
|
23482
|
-
(0,
|
|
23483
|
-
(0,
|
|
23615
|
+
(0, import_node_fs24.closeSync)(inFd);
|
|
23616
|
+
(0, import_node_fs24.closeSync)(errFd);
|
|
23484
23617
|
}
|
|
23485
23618
|
}
|
|
23486
23619
|
var MMI_PLUGIN_ID2 = "mmi@mutmutco";
|
|
23487
23620
|
function stagedClaudePluginVersion() {
|
|
23488
23621
|
try {
|
|
23489
23622
|
const stagingRoot = (0, import_node_path21.join)((0, import_node_os12.homedir)(), ".claude", "plugins", "staging");
|
|
23490
|
-
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"));
|
|
23491
23624
|
if (typeof record.target !== "string" || typeof record.incoming !== "string") return void 0;
|
|
23492
|
-
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"));
|
|
23493
23626
|
if (typeof manifest.version !== "string") return void 0;
|
|
23494
23627
|
return manifest.version === record.target ? record.target : void 0;
|
|
23495
23628
|
} catch {
|
|
@@ -23499,7 +23632,7 @@ function stagedClaudePluginVersion() {
|
|
|
23499
23632
|
function installedClaudePluginVersion() {
|
|
23500
23633
|
try {
|
|
23501
23634
|
const file = JSON.parse(
|
|
23502
|
-
(0,
|
|
23635
|
+
(0, import_node_fs24.readFileSync)((0, import_node_path21.join)((0, import_node_os12.homedir)(), ".claude", "plugins", "installed_plugins.json"), "utf8")
|
|
23503
23636
|
);
|
|
23504
23637
|
const versions = (file.plugins?.[MMI_PLUGIN_ID2] ?? []).map((r) => r.version).filter((v) => Boolean(v));
|
|
23505
23638
|
if (versions.length === 0) return void 0;
|
|
@@ -23511,12 +23644,12 @@ function installedClaudePluginVersion() {
|
|
|
23511
23644
|
function readHermesPluginEvidence(env = process.env) {
|
|
23512
23645
|
const host = hermesConfigRoot(env);
|
|
23513
23646
|
const root = hermesPluginRoot(env);
|
|
23514
|
-
const installRecordPresent = (0,
|
|
23647
|
+
const installRecordPresent = (0, import_node_fs24.existsSync)(root);
|
|
23515
23648
|
const manifestPath = (0, import_node_path21.join)(root, "plugin.yaml");
|
|
23516
23649
|
let installedVersion;
|
|
23517
23650
|
let manifest = "missing";
|
|
23518
23651
|
try {
|
|
23519
|
-
const text = (0,
|
|
23652
|
+
const text = (0, import_node_fs24.readFileSync)(manifestPath, "utf8");
|
|
23520
23653
|
let version;
|
|
23521
23654
|
try {
|
|
23522
23655
|
const parsed = JSON.parse(text).version;
|
|
@@ -23530,25 +23663,25 @@ function readHermesPluginEvidence(env = process.env) {
|
|
|
23530
23663
|
if (version) {
|
|
23531
23664
|
installedVersion = version;
|
|
23532
23665
|
manifest = "valid";
|
|
23533
|
-
} else if ((0,
|
|
23666
|
+
} else if ((0, import_node_fs24.existsSync)(manifestPath)) manifest = "invalid";
|
|
23534
23667
|
} catch {
|
|
23535
|
-
if ((0,
|
|
23668
|
+
if ((0, import_node_fs24.existsSync)(manifestPath)) manifest = "invalid";
|
|
23536
23669
|
}
|
|
23537
23670
|
let skills = false;
|
|
23538
23671
|
try {
|
|
23539
|
-
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();
|
|
23540
23673
|
} catch {
|
|
23541
23674
|
}
|
|
23542
23675
|
let provisioned = false;
|
|
23543
23676
|
const provisionedRoot = (0, import_node_path21.join)(host, "skills", "mmi");
|
|
23544
23677
|
try {
|
|
23545
|
-
provisioned = (0,
|
|
23678
|
+
provisioned = (0, import_node_fs24.existsSync)(provisionedRoot) && (0, import_node_fs24.statSync)(provisionedRoot).isDirectory();
|
|
23546
23679
|
} catch {
|
|
23547
23680
|
}
|
|
23548
|
-
const treeOk = (0,
|
|
23681
|
+
const treeOk = (0, import_node_fs24.existsSync)((0, import_node_path21.join)(root, "__init__.py")) && skills && manifest === "valid";
|
|
23549
23682
|
const receipt = treeOk && !provisioned ? `hermes-skills-unprovisioned:${provisionedRoot}` : void 0;
|
|
23550
23683
|
return {
|
|
23551
|
-
hostPresent: (0,
|
|
23684
|
+
hostPresent: (0, import_node_fs24.existsSync)(host),
|
|
23552
23685
|
installRecordPresent,
|
|
23553
23686
|
manifest,
|
|
23554
23687
|
payloadPresent: treeOk && provisioned,
|
|
@@ -23600,7 +23733,7 @@ function readGitignore() {
|
|
|
23600
23733
|
const path2 = gitignorePath();
|
|
23601
23734
|
if (path2 === null) return null;
|
|
23602
23735
|
try {
|
|
23603
|
-
return (0,
|
|
23736
|
+
return (0, import_node_fs24.readFileSync)(path2, "utf8");
|
|
23604
23737
|
} catch {
|
|
23605
23738
|
return null;
|
|
23606
23739
|
}
|
|
@@ -23609,14 +23742,14 @@ function writeGitignore(content) {
|
|
|
23609
23742
|
const path2 = gitignorePath();
|
|
23610
23743
|
if (path2 === null) return false;
|
|
23611
23744
|
try {
|
|
23612
|
-
(0,
|
|
23745
|
+
(0, import_node_fs24.writeFileSync)(path2, content, "utf8");
|
|
23613
23746
|
return true;
|
|
23614
23747
|
} catch {
|
|
23615
23748
|
return false;
|
|
23616
23749
|
}
|
|
23617
23750
|
}
|
|
23618
23751
|
function lineEndingState(root) {
|
|
23619
|
-
const attributesPresent = (0,
|
|
23752
|
+
const attributesPresent = (0, import_node_fs24.existsSync)((0, import_node_path21.join)(root, ".gitattributes"));
|
|
23620
23753
|
try {
|
|
23621
23754
|
const output = execFileCapture("git", ["-C", root, "ls-files", "--eol", "--", ":(glob)**/*.sh"], {
|
|
23622
23755
|
windowsHide: true
|
|
@@ -23659,7 +23792,7 @@ function compatHolds(range, version) {
|
|
|
23659
23792
|
}
|
|
23660
23793
|
|
|
23661
23794
|
// src/claude-binary-doctor.ts
|
|
23662
|
-
var
|
|
23795
|
+
var import_node_fs25 = require("node:fs");
|
|
23663
23796
|
var import_node_os14 = require("node:os");
|
|
23664
23797
|
var import_node_path23 = require("node:path");
|
|
23665
23798
|
|
|
@@ -23769,16 +23902,16 @@ function globalNodeModulesRoots(host) {
|
|
|
23769
23902
|
function readHead(path2) {
|
|
23770
23903
|
let fd;
|
|
23771
23904
|
try {
|
|
23772
|
-
fd = (0,
|
|
23905
|
+
fd = (0, import_node_fs25.openSync)(path2, "r");
|
|
23773
23906
|
const buffer = new Uint8Array(MAGIC_HEAD_BYTES);
|
|
23774
|
-
const read = (0,
|
|
23907
|
+
const read = (0, import_node_fs25.readSync)(fd, buffer, 0, MAGIC_HEAD_BYTES, 0);
|
|
23775
23908
|
return buffer.subarray(0, read);
|
|
23776
23909
|
} catch {
|
|
23777
23910
|
return void 0;
|
|
23778
23911
|
} finally {
|
|
23779
23912
|
if (fd !== void 0) {
|
|
23780
23913
|
try {
|
|
23781
|
-
(0,
|
|
23914
|
+
(0, import_node_fs25.closeSync)(fd);
|
|
23782
23915
|
} catch {
|
|
23783
23916
|
}
|
|
23784
23917
|
}
|
|
@@ -23786,7 +23919,7 @@ function readHead(path2) {
|
|
|
23786
23919
|
}
|
|
23787
23920
|
function fileBytes(path2) {
|
|
23788
23921
|
try {
|
|
23789
|
-
return (0,
|
|
23922
|
+
return (0, import_node_fs25.statSync)(path2).size;
|
|
23790
23923
|
} catch {
|
|
23791
23924
|
return void 0;
|
|
23792
23925
|
}
|
|
@@ -23800,13 +23933,13 @@ function readClaudeBinaryState(host = {}) {
|
|
|
23800
23933
|
const arch = host.arch ?? process.arch;
|
|
23801
23934
|
const magic = EXECUTABLE_MAGIC[platform2];
|
|
23802
23935
|
if (!magic) return void 0;
|
|
23803
|
-
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")));
|
|
23804
23937
|
if (!packageRoot) return void 0;
|
|
23805
23938
|
const keys = platformPackageKeys(platform2, arch);
|
|
23806
23939
|
const fallbackPackage = `${PACKAGE}-${keys[0]}`;
|
|
23807
23940
|
let manifest;
|
|
23808
23941
|
try {
|
|
23809
|
-
manifest = JSON.parse((0,
|
|
23942
|
+
manifest = JSON.parse((0, import_node_fs25.readFileSync)((0, import_node_path23.join)(packageRoot, "package.json"), "utf8"));
|
|
23810
23943
|
} catch (e) {
|
|
23811
23944
|
return {
|
|
23812
23945
|
state: "unreadable",
|
|
@@ -23837,7 +23970,7 @@ function readClaudeBinaryState(host = {}) {
|
|
|
23837
23970
|
(0, import_node_path23.join)(packageRoot, "node_modules", ...name.split("/"), binName),
|
|
23838
23971
|
(0, import_node_path23.join)((0, import_node_path23.dirname)((0, import_node_path23.dirname)(packageRoot)), ...name.split("/"), binName)
|
|
23839
23972
|
];
|
|
23840
|
-
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);
|
|
23841
23974
|
const platformPackage = found?.name ?? published[0];
|
|
23842
23975
|
let source;
|
|
23843
23976
|
let sourceProblem;
|
|
@@ -23848,7 +23981,7 @@ function readClaudeBinaryState(host = {}) {
|
|
|
23848
23981
|
} else {
|
|
23849
23982
|
source = { path: found.path, bytes: fileBytes(found.path) ?? 0 };
|
|
23850
23983
|
}
|
|
23851
|
-
if (!(0,
|
|
23984
|
+
if (!(0, import_node_fs25.existsSync)(binPath)) {
|
|
23852
23985
|
return { state: "missing", binPath, expectedMagic: magic.name, platformPackage, ...source ? { source } : {}, ...sourceProblem ? { sourceProblem } : {} };
|
|
23853
23986
|
}
|
|
23854
23987
|
const head = readHead(binPath);
|
|
@@ -23891,9 +24024,9 @@ function healClaudeBinary(host = {}, onStep) {
|
|
|
23891
24024
|
const platform2 = host.platform ?? process.platform;
|
|
23892
24025
|
const aside = `${probe.binPath}.stub-${Date.now()}`;
|
|
23893
24026
|
let renamed = false;
|
|
23894
|
-
if ((0,
|
|
24027
|
+
if ((0, import_node_fs25.existsSync)(probe.binPath)) {
|
|
23895
24028
|
try {
|
|
23896
|
-
(0,
|
|
24029
|
+
(0, import_node_fs25.renameSync)(probe.binPath, aside);
|
|
23897
24030
|
renamed = true;
|
|
23898
24031
|
onStep?.(`renamed the stub aside: ${aside}`);
|
|
23899
24032
|
} catch (e) {
|
|
@@ -23902,12 +24035,12 @@ function healClaudeBinary(host = {}, onStep) {
|
|
|
23902
24035
|
}
|
|
23903
24036
|
try {
|
|
23904
24037
|
onStep?.(`copying ${probe.source.path} \u2192 ${probe.binPath} (${(probe.source.bytes / 1e6).toFixed(0)} MB)`);
|
|
23905
|
-
(0,
|
|
23906
|
-
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);
|
|
23907
24040
|
} catch (e) {
|
|
23908
24041
|
if (renamed) {
|
|
23909
24042
|
try {
|
|
23910
|
-
(0,
|
|
24043
|
+
(0, import_node_fs25.renameSync)(aside, probe.binPath);
|
|
23911
24044
|
} catch {
|
|
23912
24045
|
return { ok: false, detail: `copy failed (${e.message}) and the stub could not be restored \u2014 the original is at ${aside}` };
|
|
23913
24046
|
}
|
|
@@ -23921,7 +24054,7 @@ function healClaudeBinary(host = {}, onStep) {
|
|
|
23921
24054
|
let kept = false;
|
|
23922
24055
|
if (renamed) {
|
|
23923
24056
|
try {
|
|
23924
|
-
(0,
|
|
24057
|
+
(0, import_node_fs25.rmSync)(aside);
|
|
23925
24058
|
} catch {
|
|
23926
24059
|
kept = true;
|
|
23927
24060
|
}
|
|
@@ -24280,7 +24413,7 @@ function checkLineEndings(probe) {
|
|
|
24280
24413
|
}
|
|
24281
24414
|
|
|
24282
24415
|
// src/release-ledger.ts
|
|
24283
|
-
var
|
|
24416
|
+
var import_node_fs26 = require("node:fs");
|
|
24284
24417
|
var import_node_path25 = require("node:path");
|
|
24285
24418
|
var import_node_crypto9 = require("node:crypto");
|
|
24286
24419
|
|
|
@@ -24455,8 +24588,8 @@ function attachOutputNote(note, suffix) {
|
|
|
24455
24588
|
}
|
|
24456
24589
|
function writeFailingLegOutput(artifactPath, output) {
|
|
24457
24590
|
const fileLines = lastNonEmptyLines(output, LEDGER_OUTPUT_FILE_LINES);
|
|
24458
|
-
(0,
|
|
24459
|
-
(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")}
|
|
24460
24593
|
`, "utf8");
|
|
24461
24594
|
const tail = fileLines.slice(-LEDGER_OUTPUT_NOTE_LINES).join("\n");
|
|
24462
24595
|
const noteSuffix = truncate(`failing-leg output: ${artifactPath}
|
|
@@ -24624,7 +24757,7 @@ function resolvePrimaryGitDir(cwd) {
|
|
|
24624
24757
|
}
|
|
24625
24758
|
let common;
|
|
24626
24759
|
try {
|
|
24627
|
-
common = (0,
|
|
24760
|
+
common = (0, import_node_fs26.readFileSync)((0, import_node_path25.join)(gitDir, "commondir"), "utf8").trim();
|
|
24628
24761
|
} catch (e) {
|
|
24629
24762
|
if (e.code !== "ENOENT") {
|
|
24630
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)`);
|
|
@@ -24633,7 +24766,7 @@ function resolvePrimaryGitDir(cwd) {
|
|
|
24633
24766
|
if (!common) return gitDir;
|
|
24634
24767
|
const commonDir = (0, import_node_path25.isAbsolute)(common) ? common : (0, import_node_path25.resolve)(gitDir, common);
|
|
24635
24768
|
try {
|
|
24636
|
-
(0,
|
|
24769
|
+
(0, import_node_fs26.readFileSync)((0, import_node_path25.join)(commonDir, "HEAD"), "utf8");
|
|
24637
24770
|
} catch (e) {
|
|
24638
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`);
|
|
24639
24772
|
}
|
|
@@ -24643,11 +24776,11 @@ function releaseLedgerPath(cwd) {
|
|
|
24643
24776
|
return (0, import_node_path25.join)(resolvePrimaryGitDir(cwd), "mmi-runtime", "release", "phases.json");
|
|
24644
24777
|
}
|
|
24645
24778
|
function atomicWriteJson(path2, ledger) {
|
|
24646
|
-
(0,
|
|
24779
|
+
(0, import_node_fs26.mkdirSync)((0, import_node_path25.dirname)(path2), { recursive: true });
|
|
24647
24780
|
const tmp = `${path2}.tmp-${process.pid}-${(0, import_node_crypto9.randomBytes)(4).toString("hex")}`;
|
|
24648
|
-
(0,
|
|
24781
|
+
(0, import_node_fs26.writeFileSync)(tmp, `${JSON.stringify(ledger, null, 2)}
|
|
24649
24782
|
`, "utf8");
|
|
24650
|
-
(0,
|
|
24783
|
+
(0, import_node_fs26.renameSync)(tmp, path2);
|
|
24651
24784
|
}
|
|
24652
24785
|
var LEDGER_LOCK_OPTS = { label: "release ledger", staleMs: 18e4, deadHolderSteal: true };
|
|
24653
24786
|
async function withLedgerLock(path2, fn, opts = {}) {
|
|
@@ -24694,7 +24827,7 @@ function describeTrainWriterToken(token) {
|
|
|
24694
24827
|
function liveTrainWriterHolder(cwd) {
|
|
24695
24828
|
let token;
|
|
24696
24829
|
try {
|
|
24697
|
-
token = (0,
|
|
24830
|
+
token = (0, import_node_fs26.readFileSync)(trainWriterLockPath(cwd), "utf8");
|
|
24698
24831
|
} catch {
|
|
24699
24832
|
return void 0;
|
|
24700
24833
|
}
|
|
@@ -24716,7 +24849,7 @@ async function acquireTrainWriterLock(cwd, verb) {
|
|
|
24716
24849
|
if (heldTrainWriter) heldTrainWriter.depth -= 1;
|
|
24717
24850
|
};
|
|
24718
24851
|
}
|
|
24719
|
-
(0,
|
|
24852
|
+
(0, import_node_fs26.mkdirSync)((0, import_node_path25.dirname)(lockPath), { recursive: true });
|
|
24720
24853
|
const opts = resolveFileLockOpts({ label: "train writer", staleMs: TRAIN_WRITER_STALE_MS, deadHolderSteal: true, maxWaitMs: 0, holder: verb });
|
|
24721
24854
|
let guard;
|
|
24722
24855
|
try {
|
|
@@ -24725,7 +24858,7 @@ async function acquireTrainWriterLock(cwd, verb) {
|
|
|
24725
24858
|
if (!(e instanceof FileLockBusyError)) throw e;
|
|
24726
24859
|
let token = "";
|
|
24727
24860
|
try {
|
|
24728
|
-
token = (0,
|
|
24861
|
+
token = (0, import_node_fs26.readFileSync)(lockPath, "utf8");
|
|
24729
24862
|
} catch {
|
|
24730
24863
|
token = "";
|
|
24731
24864
|
}
|
|
@@ -24760,7 +24893,7 @@ async function withReleaseLedger(path2, expected, fn, opts = {}) {
|
|
|
24760
24893
|
let current;
|
|
24761
24894
|
let raw;
|
|
24762
24895
|
try {
|
|
24763
|
-
raw = (0,
|
|
24896
|
+
raw = (0, import_node_fs26.readFileSync)(path2, "utf8");
|
|
24764
24897
|
} catch (e) {
|
|
24765
24898
|
if (e.code !== "ENOENT") {
|
|
24766
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)`);
|
|
@@ -25429,7 +25562,7 @@ async function clearLedgerFile(path2, anchors, maxWaitMs) {
|
|
|
25429
25562
|
return withLedgerLock(path2, async (fence) => {
|
|
25430
25563
|
let raw;
|
|
25431
25564
|
try {
|
|
25432
|
-
raw = (0,
|
|
25565
|
+
raw = (0, import_node_fs26.readFileSync)(path2, "utf8");
|
|
25433
25566
|
} catch (e) {
|
|
25434
25567
|
if (e.code === "ENOENT") return { cleared: false };
|
|
25435
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` };
|
|
@@ -25445,7 +25578,7 @@ async function clearLedgerFile(path2, anchors, maxWaitMs) {
|
|
|
25445
25578
|
} catch (e) {
|
|
25446
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)})` };
|
|
25447
25580
|
}
|
|
25448
|
-
await fence(() => (0,
|
|
25581
|
+
await fence(() => (0, import_node_fs26.unlinkSync)(path2));
|
|
25449
25582
|
return { cleared: true, note: `cleared the release ledger at ${path2} for the live-proven aborted ${anchors.tag}` };
|
|
25450
25583
|
}, { maxWaitMs });
|
|
25451
25584
|
}
|
|
@@ -25605,7 +25738,7 @@ async function healStaleAlignmentLeg(deps, cwd, expected) {
|
|
|
25605
25738
|
return withLedgerLock(path2, async (fence) => {
|
|
25606
25739
|
let prior;
|
|
25607
25740
|
try {
|
|
25608
|
-
prior = parseReleaseLedger((0,
|
|
25741
|
+
prior = parseReleaseLedger((0, import_node_fs26.readFileSync)(path2, "utf8"));
|
|
25609
25742
|
} catch {
|
|
25610
25743
|
return void 0;
|
|
25611
25744
|
}
|
|
@@ -25630,7 +25763,7 @@ async function healUnfoldedRunLegs(deps, cwd, model) {
|
|
|
25630
25763
|
const path2 = releaseLedgerPath(cwd);
|
|
25631
25764
|
let prior;
|
|
25632
25765
|
try {
|
|
25633
|
-
prior = parseReleaseLedger((0,
|
|
25766
|
+
prior = parseReleaseLedger((0, import_node_fs26.readFileSync)(path2, "utf8"));
|
|
25634
25767
|
} catch {
|
|
25635
25768
|
return void 0;
|
|
25636
25769
|
}
|
|
@@ -25699,7 +25832,7 @@ async function supersedeContentCausedDeployLeg(deps, cwd) {
|
|
|
25699
25832
|
return withLedgerLock(path2, async (fence) => {
|
|
25700
25833
|
let prior;
|
|
25701
25834
|
try {
|
|
25702
|
-
prior = parseReleaseLedger((0,
|
|
25835
|
+
prior = parseReleaseLedger((0, import_node_fs26.readFileSync)(path2, "utf8"));
|
|
25703
25836
|
} catch (e) {
|
|
25704
25837
|
throw new ReleaseLedgerError(
|
|
25705
25838
|
"unreadable",
|
|
@@ -25797,10 +25930,10 @@ async function proveOriginPromotionOrArchived(deps, prior, path2, label, ref, fe
|
|
|
25797
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})`);
|
|
25798
25931
|
}
|
|
25799
25932
|
const archivePath = (0, import_node_path25.join)((0, import_node_path25.dirname)(path2), `phases.archive-${prior.tag}.json`);
|
|
25800
|
-
if ((0,
|
|
25933
|
+
if ((0, import_node_fs26.existsSync)(archivePath)) {
|
|
25801
25934
|
throw new Error(`${label}: archive already exists at ${archivePath} \u2014 preserving both ledger records; resolve the collision by hand; nothing was written (${ref})`);
|
|
25802
25935
|
}
|
|
25803
|
-
await fence(() => (0,
|
|
25936
|
+
await fence(() => (0, import_node_fs26.renameSync)(path2, archivePath));
|
|
25804
25937
|
return "deleted";
|
|
25805
25938
|
}
|
|
25806
25939
|
async function supersedeContentCausedPublishLeg(deps, cwd) {
|
|
@@ -25808,7 +25941,7 @@ async function supersedeContentCausedPublishLeg(deps, cwd) {
|
|
|
25808
25941
|
return withLedgerLock(path2, async (fence) => {
|
|
25809
25942
|
let prior;
|
|
25810
25943
|
try {
|
|
25811
|
-
prior = parseReleaseLedger((0,
|
|
25944
|
+
prior = parseReleaseLedger((0, import_node_fs26.readFileSync)(path2, "utf8"));
|
|
25812
25945
|
} catch (e) {
|
|
25813
25946
|
throw new ReleaseLedgerError(
|
|
25814
25947
|
"unreadable",
|
|
@@ -25890,7 +26023,7 @@ async function supersedeContentCausedDeployAndPublishLegs(deps, cwd) {
|
|
|
25890
26023
|
return withLedgerLock(path2, async (fence) => {
|
|
25891
26024
|
let prior;
|
|
25892
26025
|
try {
|
|
25893
|
-
prior = parseReleaseLedger((0,
|
|
26026
|
+
prior = parseReleaseLedger((0, import_node_fs26.readFileSync)(path2, "utf8"));
|
|
25894
26027
|
} catch (e) {
|
|
25895
26028
|
throw new ReleaseLedgerError(
|
|
25896
26029
|
"unreadable",
|
|
@@ -25995,7 +26128,7 @@ async function supersedeContentCausedDeployAndPublishLegs(deps, cwd) {
|
|
|
25995
26128
|
async function reverifyPriorRunLegs(deps, path2, targetTag) {
|
|
25996
26129
|
let prior;
|
|
25997
26130
|
try {
|
|
25998
|
-
prior = parseReleaseLedger((0,
|
|
26131
|
+
prior = parseReleaseLedger((0, import_node_fs26.readFileSync)(path2, "utf8"));
|
|
25999
26132
|
} catch {
|
|
26000
26133
|
return;
|
|
26001
26134
|
}
|
|
@@ -26015,7 +26148,7 @@ async function beginReleaseLedger(deps, cwd, targetTag) {
|
|
|
26015
26148
|
return withLedgerLock(path2, async (fence) => {
|
|
26016
26149
|
let raw;
|
|
26017
26150
|
try {
|
|
26018
|
-
raw = (0,
|
|
26151
|
+
raw = (0, import_node_fs26.readFileSync)(path2, "utf8");
|
|
26019
26152
|
} catch (e) {
|
|
26020
26153
|
if (e.code === "ENOENT") return { ok: true };
|
|
26021
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)` };
|
|
@@ -26055,13 +26188,13 @@ async function beginReleaseLedger(deps, cwd, targetTag) {
|
|
|
26055
26188
|
}
|
|
26056
26189
|
const archivePath = (0, import_node_path25.join)((0, import_node_path25.dirname)(path2), `phases.archive-${prior.tag}.json`);
|
|
26057
26190
|
try {
|
|
26058
|
-
await fence(() => (0,
|
|
26191
|
+
await fence(() => (0, import_node_fs26.unlinkSync)(archivePath));
|
|
26059
26192
|
} catch (e) {
|
|
26060
26193
|
if (e.code !== "ENOENT") {
|
|
26061
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)` };
|
|
26062
26195
|
}
|
|
26063
26196
|
}
|
|
26064
|
-
await fence(() => (0,
|
|
26197
|
+
await fence(() => (0, import_node_fs26.renameSync)(path2, archivePath));
|
|
26065
26198
|
return { ok: true, note: `archived the completed release ledger ${prior.tag} to ${archivePath} (live-proven at ${prior.tagSha.slice(0, 12)})` };
|
|
26066
26199
|
});
|
|
26067
26200
|
}
|
|
@@ -26089,7 +26222,7 @@ async function retryHotfixDeployLegs(deps, cwd, opts = {}) {
|
|
|
26089
26222
|
return withLedgerLock(path2, async (fence) => {
|
|
26090
26223
|
let prior;
|
|
26091
26224
|
try {
|
|
26092
|
-
prior = parseReleaseLedger((0,
|
|
26225
|
+
prior = parseReleaseLedger((0, import_node_fs26.readFileSync)(path2, "utf8"));
|
|
26093
26226
|
} catch (e) {
|
|
26094
26227
|
throw new ReleaseLedgerError(
|
|
26095
26228
|
"unreadable",
|
|
@@ -26282,10 +26415,10 @@ function readOriginWorkflowsDefault(root, ref) {
|
|
|
26282
26415
|
}
|
|
26283
26416
|
var NPM_REGISTRY = "https://registry.npmjs.org";
|
|
26284
26417
|
async function probeRegistryWhoami(train) {
|
|
26285
|
-
const dir = (0,
|
|
26418
|
+
const dir = (0, import_node_fs27.mkdtempSync)((0, import_node_path26.join)((0, import_node_os15.tmpdir)(), "mmi-npmrc-"));
|
|
26286
26419
|
const rc = (0, import_node_path26.join)(dir, "npmrc");
|
|
26287
26420
|
try {
|
|
26288
|
-
(0,
|
|
26421
|
+
(0, import_node_fs27.writeFileSync)(rc, "//registry.npmjs.org/:_authToken=${NPM_TOKEN}\n");
|
|
26289
26422
|
await train.runSelf(["secrets", "use", "npm/NPM_TOKEN", "--slug", "_org", "--", "npm", "whoami", "--registry", NPM_REGISTRY, "--userconfig", rc]);
|
|
26290
26423
|
return { kind: "ok", detail: "the registry answered a login" };
|
|
26291
26424
|
} catch (e) {
|
|
@@ -26296,7 +26429,7 @@ async function probeRegistryWhoami(train) {
|
|
|
26296
26429
|
if (/\bE401\b|401 Unauthorized/.test(stderr)) return { kind: "rejected", detail: "npm whoami answered 401 Unauthorized" };
|
|
26297
26430
|
return { kind: "unverified", detail: first };
|
|
26298
26431
|
} finally {
|
|
26299
|
-
(0,
|
|
26432
|
+
(0, import_node_fs27.rmSync)(dir, { recursive: true, force: true });
|
|
26300
26433
|
}
|
|
26301
26434
|
}
|
|
26302
26435
|
var REGISTRY_TOKEN_ENV = /\b(NODE_AUTH_TOKEN|NPM_TOKEN)\b/;
|
|
@@ -26314,7 +26447,7 @@ var defaultDeps2 = {
|
|
|
26314
26447
|
ledgerPath: releaseLedgerPath,
|
|
26315
26448
|
readLedgerRaw: (path2) => {
|
|
26316
26449
|
try {
|
|
26317
|
-
return (0,
|
|
26450
|
+
return (0, import_node_fs27.readFileSync)(path2, "utf8");
|
|
26318
26451
|
} catch (e) {
|
|
26319
26452
|
if (e.code === "ENOENT") return void 0;
|
|
26320
26453
|
throw e;
|
|
@@ -26325,7 +26458,7 @@ var defaultDeps2 = {
|
|
|
26325
26458
|
trainWriterHolder: liveTrainWriterHolder,
|
|
26326
26459
|
readSurfacesRaw: (cwd) => {
|
|
26327
26460
|
try {
|
|
26328
|
-
return (0,
|
|
26461
|
+
return (0, import_node_fs27.readFileSync)((0, import_node_path26.join)(cwd, "surfaces.json"), "utf8");
|
|
26329
26462
|
} catch {
|
|
26330
26463
|
return void 0;
|
|
26331
26464
|
}
|
|
@@ -26964,7 +27097,7 @@ function formatTrainDoctor(v) {
|
|
|
26964
27097
|
|
|
26965
27098
|
// src/release-plain-words.ts
|
|
26966
27099
|
var import_promises3 = require("node:fs/promises");
|
|
26967
|
-
var
|
|
27100
|
+
var import_node_fs28 = require("node:fs");
|
|
26968
27101
|
function releaseCutByNotes(cutBy) {
|
|
26969
27102
|
return `## Internal
|
|
26970
27103
|
Cut by ${formatSessionIdentity(cutBy)}
|
|
@@ -27070,7 +27203,7 @@ function validateSuiteReleaseSummary(path2, pathTr) {
|
|
|
27070
27203
|
for (const [lang, file] of files) {
|
|
27071
27204
|
let content;
|
|
27072
27205
|
try {
|
|
27073
|
-
content = (0,
|
|
27206
|
+
content = (0, import_node_fs28.readFileSync)(file, "utf8");
|
|
27074
27207
|
} catch (e) {
|
|
27075
27208
|
throw new Error(`could not read summary file ${file}: ${e.message} \u2014 see ${SUMMARY_GUIDE}`);
|
|
27076
27209
|
}
|
|
@@ -27285,14 +27418,14 @@ function readLocalGateWorkflows() {
|
|
|
27285
27418
|
const dir = (0, import_node_path27.join)(".github", "workflows");
|
|
27286
27419
|
let names;
|
|
27287
27420
|
try {
|
|
27288
|
-
names = (0,
|
|
27421
|
+
names = (0, import_node_fs29.readdirSync)(dir);
|
|
27289
27422
|
} catch {
|
|
27290
27423
|
return null;
|
|
27291
27424
|
}
|
|
27292
27425
|
const files = [];
|
|
27293
27426
|
for (const name of names.filter(isGateWorkflowPath)) {
|
|
27294
27427
|
try {
|
|
27295
|
-
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") });
|
|
27296
27429
|
} catch {
|
|
27297
27430
|
}
|
|
27298
27431
|
}
|
|
@@ -27302,14 +27435,14 @@ function readLocalWorkflows() {
|
|
|
27302
27435
|
const dir = (0, import_node_path27.join)(".github", "workflows");
|
|
27303
27436
|
let names;
|
|
27304
27437
|
try {
|
|
27305
|
-
names = (0,
|
|
27438
|
+
names = (0, import_node_fs29.readdirSync)(dir);
|
|
27306
27439
|
} catch {
|
|
27307
27440
|
return null;
|
|
27308
27441
|
}
|
|
27309
27442
|
const files = [];
|
|
27310
27443
|
for (const name of names.filter((n) => /\.ya?ml$/i.test(n))) {
|
|
27311
27444
|
try {
|
|
27312
|
-
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") });
|
|
27313
27446
|
} catch {
|
|
27314
27447
|
}
|
|
27315
27448
|
}
|
|
@@ -28191,7 +28324,7 @@ async function activeRcandLedgerCandidate(deps, cwd) {
|
|
|
28191
28324
|
}
|
|
28192
28325
|
let prior;
|
|
28193
28326
|
try {
|
|
28194
|
-
prior = parseReleaseLedger((0,
|
|
28327
|
+
prior = parseReleaseLedger((0, import_node_fs29.readFileSync)(path2, "utf8"));
|
|
28195
28328
|
} catch {
|
|
28196
28329
|
return void 0;
|
|
28197
28330
|
}
|
|
@@ -30807,7 +30940,7 @@ var PRIMARY_GROUPS = [
|
|
|
30807
30940
|
["Setup and support", ["bootstrap", "secrets", "docs", "tests", "spawn", "dist"]],
|
|
30808
30941
|
["Coordinate and improve", ["wave", "report", "skill-lesson", "closure-rate"]]
|
|
30809
30942
|
];
|
|
30810
|
-
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"]);
|
|
30811
30944
|
var CAMPAIGN_ORCHESTRATOR_TOP_LEVEL = /* @__PURE__ */ new Set(["pickup", "read"]);
|
|
30812
30945
|
var SUPPORT_PRIMARY = /* @__PURE__ */ new Set(["doctor", "whoami", "commands", "explain", "docs", "tests", "spawn", "dist", "wave", "report", "skill-lesson", "closure-rate"]);
|
|
30813
30946
|
var TOP_LEVEL_ORDER = /* @__PURE__ */ new Map();
|
|
@@ -30848,6 +30981,7 @@ var COMMAND_OWNERSHIP = {
|
|
|
30848
30981
|
stage: { module_owner: "cli/src/stage-commands.ts", consumer: "agent-workflow" },
|
|
30849
30982
|
pr: { module_owner: "cli/src/pr-commands.ts", consumer: "agent-workflow" },
|
|
30850
30983
|
api: { module_owner: "cli/src/api-read.ts", consumer: "agent-workflow" },
|
|
30984
|
+
github: { module_owner: "cli/src/github-budget.ts", consumer: "release-operator" },
|
|
30851
30985
|
read: { module_owner: "cli/src/app-read-broker.ts", consumer: "agent-workflow" },
|
|
30852
30986
|
ci: { module_owner: "cli/src/ci-audit.ts", consumer: "release-operator" },
|
|
30853
30987
|
rcand: { module_owner: "cli/src/train-commands.ts", consumer: "release-operator" },
|
|
@@ -31587,6 +31721,55 @@ function renderPluginCachePlan(plan, applied) {
|
|
|
31587
31721
|
return lines2.join("\n");
|
|
31588
31722
|
}
|
|
31589
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
|
+
|
|
31590
31773
|
// src/board-commands.ts
|
|
31591
31774
|
init_cli_shared();
|
|
31592
31775
|
|
|
@@ -32088,7 +32271,7 @@ function registerBoardCommands(program3) {
|
|
|
32088
32271
|
}
|
|
32089
32272
|
|
|
32090
32273
|
// src/bootstrap-commands.ts
|
|
32091
|
-
var
|
|
32274
|
+
var import_node_fs33 = require("node:fs");
|
|
32092
32275
|
var import_node_os18 = require("node:os");
|
|
32093
32276
|
var import_node_path31 = require("node:path");
|
|
32094
32277
|
init_cli_shared();
|
|
@@ -32274,7 +32457,7 @@ init_github_client();
|
|
|
32274
32457
|
init_cli_shared();
|
|
32275
32458
|
|
|
32276
32459
|
// src/port-registry.ts
|
|
32277
|
-
var
|
|
32460
|
+
var import_node_fs30 = require("node:fs");
|
|
32278
32461
|
var import_node_path28 = require("node:path");
|
|
32279
32462
|
|
|
32280
32463
|
// ../infra/port-geometry.mjs
|
|
@@ -32289,8 +32472,8 @@ function nextPortBlock(registry2) {
|
|
|
32289
32472
|
return [base, base + PORT_SPAN];
|
|
32290
32473
|
}
|
|
32291
32474
|
function loadPortRegistry(path2) {
|
|
32292
|
-
if (!(0,
|
|
32293
|
-
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"));
|
|
32294
32477
|
const out = {};
|
|
32295
32478
|
for (const [key, value] of Object.entries(raw)) {
|
|
32296
32479
|
if (Array.isArray(value) && value.length === 2 && value.every((n) => typeof n === "number")) {
|
|
@@ -32320,7 +32503,7 @@ function existingPortRange(repo, registry2) {
|
|
|
32320
32503
|
function portRangeInfraAt(root, source) {
|
|
32321
32504
|
const registryPath = (0, import_node_path28.join)(root, "infra", "port-ranges.json");
|
|
32322
32505
|
const ddbScriptPath = (0, import_node_path28.join)(root, "infra", "port-ddb.mjs");
|
|
32323
|
-
if (!(0,
|
|
32506
|
+
if (!(0, import_node_fs30.existsSync)(registryPath) || !(0, import_node_fs30.existsSync)(ddbScriptPath)) return null;
|
|
32324
32507
|
return { root, source, registryPath, ddbScriptPath };
|
|
32325
32508
|
}
|
|
32326
32509
|
function resolvePortRangeInfra(cwd, packageDir) {
|
|
@@ -32402,7 +32585,7 @@ async function assignPersistedPortRange(repo, slug, reg, opts) {
|
|
|
32402
32585
|
}
|
|
32403
32586
|
|
|
32404
32587
|
// src/box-commands.ts
|
|
32405
|
-
var
|
|
32588
|
+
var import_node_fs32 = require("node:fs");
|
|
32406
32589
|
var import_node_child_process10 = require("node:child_process");
|
|
32407
32590
|
var import_node_os17 = require("node:os");
|
|
32408
32591
|
var import_node_path30 = require("node:path");
|
|
@@ -32536,7 +32719,7 @@ function applyRemoteScript(items, date) {
|
|
|
32536
32719
|
init_clean_exit();
|
|
32537
32720
|
|
|
32538
32721
|
// src/secrets-commands.ts
|
|
32539
|
-
var
|
|
32722
|
+
var import_node_fs31 = require("node:fs");
|
|
32540
32723
|
var import_node_path29 = require("node:path");
|
|
32541
32724
|
var import_node_os16 = require("node:os");
|
|
32542
32725
|
init_cli_shared();
|
|
@@ -33686,8 +33869,8 @@ async function decryptRailsCredentials(input) {
|
|
|
33686
33869
|
MMI_RAILS_CREDENTIALS_FILE: credentialsPath,
|
|
33687
33870
|
MMI_RAILS_MASTER_KEY_FILE: masterKeyPath
|
|
33688
33871
|
};
|
|
33689
|
-
if ((0,
|
|
33690
|
-
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();
|
|
33691
33874
|
}
|
|
33692
33875
|
const script = [
|
|
33693
33876
|
'require "json"',
|
|
@@ -33697,9 +33880,9 @@ async function decryptRailsCredentials(input) {
|
|
|
33697
33880
|
'config = ActiveSupport::EncryptedConfiguration.new(config_path: config_path, key_path: key_path, env_key: "RAILS_MASTER_KEY", raise_if_missing_key: true)',
|
|
33698
33881
|
"puts JSON.generate(config.config)"
|
|
33699
33882
|
].join("\n");
|
|
33700
|
-
const scriptDir = (0,
|
|
33883
|
+
const scriptDir = (0, import_node_fs31.mkdtempSync)((0, import_node_path29.join)((0, import_node_os16.tmpdir)(), "mmi-rails-decrypt-"));
|
|
33701
33884
|
const scriptPath = (0, import_node_path29.join)(scriptDir, "decrypt.rb");
|
|
33702
|
-
(0,
|
|
33885
|
+
(0, import_node_fs31.writeFileSync)(scriptPath, script, "utf8");
|
|
33703
33886
|
try {
|
|
33704
33887
|
const args = ["exec", "ruby", scriptPath];
|
|
33705
33888
|
const cmd = process.platform === "win32" ? "cmd.exe" : "bundle";
|
|
@@ -33711,7 +33894,7 @@ async function decryptRailsCredentials(input) {
|
|
|
33711
33894
|
});
|
|
33712
33895
|
return JSON.parse(stdout);
|
|
33713
33896
|
} finally {
|
|
33714
|
-
(0,
|
|
33897
|
+
(0, import_node_fs31.rmSync)(scriptDir, { recursive: true, force: true });
|
|
33715
33898
|
}
|
|
33716
33899
|
}
|
|
33717
33900
|
async function readSecretStdin() {
|
|
@@ -33801,7 +33984,7 @@ function registerSecretsCommands(program3) {
|
|
|
33801
33984
|
let body;
|
|
33802
33985
|
if (o.file) {
|
|
33803
33986
|
try {
|
|
33804
|
-
body = (0,
|
|
33987
|
+
body = (0, import_node_fs31.readFileSync)((0, import_node_path29.resolve)(o.file), "utf8");
|
|
33805
33988
|
} catch (e) {
|
|
33806
33989
|
return fail(`secrets org-catalog: cannot read --file ${o.file}: ${e.message}`);
|
|
33807
33990
|
}
|
|
@@ -33937,7 +34120,7 @@ function registerSecretsCommands(program3) {
|
|
|
33937
34120
|
{
|
|
33938
34121
|
...d,
|
|
33939
34122
|
decryptRailsCredentials,
|
|
33940
|
-
removeFile: (path2) => (0,
|
|
34123
|
+
removeFile: (path2) => (0, import_node_fs31.unlinkSync)((0, import_node_path29.resolve)(o.appDir ?? process.cwd(), path2))
|
|
33941
34124
|
},
|
|
33942
34125
|
{
|
|
33943
34126
|
repo: o.repo,
|
|
@@ -34193,7 +34376,7 @@ function registerBoxCommands(program3) {
|
|
|
34193
34376
|
}
|
|
34194
34377
|
const remote = command && command.length ? command.join(" ") : void 0;
|
|
34195
34378
|
const wroteScript = o.ssh && o.script ? o.script : null;
|
|
34196
|
-
if (wroteScript) (0,
|
|
34379
|
+
if (wroteScript) (0, import_node_fs32.writeFileSync)(wroteScript, sshRecipeScript(found, remote), "utf8");
|
|
34197
34380
|
if (o.json) {
|
|
34198
34381
|
console.log(JSON.stringify({
|
|
34199
34382
|
box: found,
|
|
@@ -34267,17 +34450,17 @@ function hubGitShow(ref) {
|
|
|
34267
34450
|
return (path2) => git3(["show", `${ref}:${path2}`]);
|
|
34268
34451
|
}
|
|
34269
34452
|
function runOnBox(found, script) {
|
|
34270
|
-
const dir = (0,
|
|
34453
|
+
const dir = (0, import_node_fs32.mkdtempSync)((0, import_node_path30.join)((0, import_node_os17.tmpdir)(), "mmi-box-control-"));
|
|
34271
34454
|
try {
|
|
34272
34455
|
const recipe = (0, import_node_path30.join)(dir, "recipe.sh");
|
|
34273
|
-
(0,
|
|
34456
|
+
(0, import_node_fs32.writeFileSync)(recipe, sshRecipeScript(found, "sh -s"), "utf8");
|
|
34274
34457
|
const r = (0, import_node_child_process10.spawnSync)("bash", [recipe], { input: script, encoding: "utf8", maxBuffer: 16 * 1024 * 1024, timeout: 18e4, windowsHide: true });
|
|
34275
34458
|
if (r.status !== 0) {
|
|
34276
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(" | ")}`);
|
|
34277
34460
|
}
|
|
34278
34461
|
return r.stdout;
|
|
34279
34462
|
} finally {
|
|
34280
|
-
(0,
|
|
34463
|
+
(0, import_node_fs32.rmSync)(dir, { recursive: true, force: true });
|
|
34281
34464
|
}
|
|
34282
34465
|
}
|
|
34283
34466
|
function formatControl(mode, box, rows) {
|
|
@@ -35912,12 +36095,12 @@ async function verifyTargetedSeedPr(repo, number, plan, target, expected, client
|
|
|
35912
36095
|
// src/bootstrap-commands.ts
|
|
35913
36096
|
var execGitForSeedSource = async (args) => (await execFileP("git", args, { timeout: GIT_TIMEOUT_MS })).stdout;
|
|
35914
36097
|
async function gateRenderDiff(current, rendered) {
|
|
35915
|
-
const dir = (0,
|
|
36098
|
+
const dir = (0, import_node_fs33.mkdtempSync)((0, import_node_path31.join)((0, import_node_os18.tmpdir)(), "mmi-gate-diff-"));
|
|
35916
36099
|
const before = (0, import_node_path31.join)(dir, "committed-gate.yml");
|
|
35917
36100
|
const after = (0, import_node_path31.join)(dir, "registry-render.yml");
|
|
35918
36101
|
try {
|
|
35919
|
-
(0,
|
|
35920
|
-
(0,
|
|
36102
|
+
(0, import_node_fs33.writeFileSync)(before, current);
|
|
36103
|
+
(0, import_node_fs33.writeFileSync)(after, rendered);
|
|
35921
36104
|
try {
|
|
35922
36105
|
return (await execFileP("git", ["diff", "--no-index", "--", before, after], { timeout: GIT_TIMEOUT_MS })).stdout;
|
|
35923
36106
|
} catch (e) {
|
|
@@ -35926,7 +36109,7 @@ async function gateRenderDiff(current, rendered) {
|
|
|
35926
36109
|
throw e;
|
|
35927
36110
|
}
|
|
35928
36111
|
} finally {
|
|
35929
|
-
(0,
|
|
36112
|
+
(0, import_node_fs33.rmSync)(dir, { recursive: true, force: true });
|
|
35930
36113
|
}
|
|
35931
36114
|
}
|
|
35932
36115
|
function bootstrapTrainDoctorDeps() {
|
|
@@ -35986,13 +36169,13 @@ function registerBootstrapCommands(program3) {
|
|
|
35986
36169
|
})),
|
|
35987
36170
|
pushAllowlistOwners: verifyOwners,
|
|
35988
36171
|
pushAllowlistOwnersRead: verifyOwnersRead,
|
|
35989
|
-
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,
|
|
35990
36173
|
// requiredGcpApis is stored as an array by a JSON write, but `org project set --var KEY=VALUE` stores a raw
|
|
35991
36174
|
// comma-string — accept either so the seeded value verifies regardless of how it was written.
|
|
35992
36175
|
// #3689: the same committed map the org access audit reads (#3664), so a sanctioned admin is not a
|
|
35993
36176
|
// permanent bootstrap failure on one surface and an intended state on the other. Absent file → no
|
|
35994
36177
|
// sanction, which is the pre-#3664 behaviour.
|
|
35995
|
-
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,
|
|
35996
36179
|
requiredGcpApis: (() => {
|
|
35997
36180
|
const v = meta?.requiredGcpApis;
|
|
35998
36181
|
if (Array.isArray(v)) return v;
|
|
@@ -36070,14 +36253,14 @@ function registerBootstrapCommands(program3) {
|
|
|
36070
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 () => {
|
|
36071
36254
|
const o = { repo: rawValue("--repo", ""), json: rawFlag("--json") };
|
|
36072
36255
|
const manifestPath = "skills/bootstrap/seeds/manifest.json";
|
|
36073
|
-
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`);
|
|
36074
36257
|
const seedSource = await resolveHubSeedSource(execGitForSeedSource);
|
|
36075
36258
|
if (!seedSource.ok) return fail(`bootstrap drift: ${seedSource.reason}`);
|
|
36076
|
-
const manifest = loadBootstrapSeeds((0,
|
|
36259
|
+
const manifest = loadBootstrapSeeds((0, import_node_fs33.readFileSync)(manifestPath, "utf8"));
|
|
36077
36260
|
const hubContents = /* @__PURE__ */ new Map();
|
|
36078
36261
|
for (const s of manifest.seeds) {
|
|
36079
36262
|
if (s.ownership !== "org" || s.source !== "self") continue;
|
|
36080
|
-
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);
|
|
36081
36264
|
}
|
|
36082
36265
|
let targets;
|
|
36083
36266
|
let classOf = (_repo) => "deployable";
|
|
@@ -36285,24 +36468,24 @@ function registerBootstrapCommands(program3) {
|
|
|
36285
36468
|
return;
|
|
36286
36469
|
}
|
|
36287
36470
|
const manifestPath = "skills/bootstrap/seeds/manifest.json";
|
|
36288
|
-
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`);
|
|
36289
36472
|
const seedSource = await resolveHubSeedSource(execGitForSeedSource);
|
|
36290
36473
|
if (!seedSource.ok) return fail(`bootstrap apply: ${seedSource.reason}`);
|
|
36291
|
-
const manifest = loadBootstrapSeeds((0,
|
|
36474
|
+
const manifest = loadBootstrapSeeds((0, import_node_fs33.readFileSync)(manifestPath, "utf8"));
|
|
36292
36475
|
const baseBranch = o.class === "content" ? "main" : "development";
|
|
36293
36476
|
const slug = parsedRepo.slug;
|
|
36294
36477
|
const onlyTarget = o.fromConfig && o.only.trim() === "gate.yml" ? ".github/workflows/gate.yml" : o.only.trim();
|
|
36295
36478
|
const gh2 = async (args) => execFileP("gh", args, { timeout: 2e4 });
|
|
36296
|
-
const readFile10 = (p) => (0,
|
|
36479
|
+
const readFile10 = (p) => (0, import_node_fs33.existsSync)(p) ? (0, import_node_fs33.readFileSync)(p, "utf8") : null;
|
|
36297
36480
|
const enc = (p) => p.split("/").map(encodeURIComponent).join("/");
|
|
36298
36481
|
const putSeed = async (target, content, ref, sha) => {
|
|
36299
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`);
|
|
36300
|
-
(0,
|
|
36483
|
+
(0, import_node_fs33.writeFileSync)(tmp, JSON.stringify(contentPutBody(target, content, ref, sha)), "utf8");
|
|
36301
36484
|
try {
|
|
36302
36485
|
await gh2(contentPutInputArgs(repo, target, tmp));
|
|
36303
36486
|
} finally {
|
|
36304
36487
|
try {
|
|
36305
|
-
(0,
|
|
36488
|
+
(0, import_node_fs33.unlinkSync)(tmp);
|
|
36306
36489
|
} catch {
|
|
36307
36490
|
}
|
|
36308
36491
|
}
|
|
@@ -36938,10 +37121,10 @@ LIVE apply to ${repo}:
|
|
|
36938
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 () => {
|
|
36939
37122
|
const o = { target: rawValue("--target", ""), execute: rawFlag("--execute"), json: rawFlag("--json") };
|
|
36940
37123
|
const manifestPath = "skills/bootstrap/seeds/manifest.json";
|
|
36941
|
-
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`);
|
|
36942
37125
|
const seedSource = await resolveHubSeedSource(execGitForSeedSource);
|
|
36943
37126
|
if (!seedSource.ok) return fail(`bootstrap propagate: ${seedSource.reason}`);
|
|
36944
|
-
const manifest = loadBootstrapSeeds((0,
|
|
37127
|
+
const manifest = loadBootstrapSeeds((0, import_node_fs33.readFileSync)(manifestPath, "utf8"));
|
|
36945
37128
|
const propagatable = manifest.seeds.filter(isPropagatableSeed);
|
|
36946
37129
|
if (!o.target) {
|
|
36947
37130
|
return fail(`bootstrap propagate: --target <path> is required \u2014 one of:
|
|
@@ -36950,9 +37133,9 @@ LIVE apply to ${repo}:
|
|
|
36950
37133
|
const seed = propagatable.find((s) => s.target === o.target);
|
|
36951
37134
|
if (!seed) return fail(`bootstrap propagate: --target '${o.target}' names no centrally propagatable seed in ${manifestPath}. Propagatable targets:
|
|
36952
37135
|
${propagatable.map((s) => s.target).join("\n ")}`);
|
|
36953
|
-
if (!seed.managedBlock && !(0,
|
|
36954
|
-
const hubContent = seed.managedBlock ? null : (0,
|
|
36955
|
-
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;
|
|
36956
37139
|
const isWorkflowSeed = seed.target.startsWith(".github/workflows/");
|
|
36957
37140
|
const cfg = await loadConfig();
|
|
36958
37141
|
const projects = await fetchProjectsList(registryClientDeps(cfg));
|
|
@@ -36961,9 +37144,9 @@ LIVE apply to ${repo}:
|
|
|
36961
37144
|
}
|
|
36962
37145
|
const rosterRepos = collectRegistryRepos(projects).filter((r) => r.toLowerCase() !== "mutmutco/mmi-hub");
|
|
36963
37146
|
let independentCount = rosterRepos.length;
|
|
36964
|
-
if ((0,
|
|
37147
|
+
if ((0, import_node_fs33.existsSync)("projects.json")) {
|
|
36965
37148
|
try {
|
|
36966
|
-
const local = JSON.parse((0,
|
|
37149
|
+
const local = JSON.parse((0, import_node_fs33.readFileSync)("projects.json", "utf8"));
|
|
36967
37150
|
const localRepos = /* @__PURE__ */ new Set();
|
|
36968
37151
|
for (const p of local.projects ?? []) for (const r of p.repos ?? []) {
|
|
36969
37152
|
const full = (r.includes("/") ? r : `mutmutco/${r}`).toLowerCase();
|
|
@@ -37113,7 +37296,7 @@ LIVE apply to ${repo}:
|
|
|
37113
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)");
|
|
37114
37297
|
const headSha = seedSource.sha;
|
|
37115
37298
|
const sourceBlob = (await execGitForSeedSource(["rev-parse", `${headSha}:${seedSourcePath(seed)}`])).trim();
|
|
37116
|
-
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;
|
|
37117
37300
|
for (const rec of plan.records) {
|
|
37118
37301
|
if (rec.action !== "open-pr") continue;
|
|
37119
37302
|
const baseBranch = classOf(rec.repo) === "content" ? "main" : "development";
|
|
@@ -37138,12 +37321,12 @@ LIVE apply to ${repo}:
|
|
|
37138
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`);
|
|
37139
37322
|
const desiredContent = desiredByRepo.get(rec.repo);
|
|
37140
37323
|
if (desiredContent == null) return fail(`bootstrap propagate: no resolved content for ${rec.repo} ${seed.target} \u2014 refusing to write`);
|
|
37141
|
-
(0,
|
|
37324
|
+
(0, import_node_fs33.writeFileSync)(tmp, JSON.stringify(contentPutBody(seed.target, desiredContent, branch, existingSha, runbookUnaffected)), "utf8");
|
|
37142
37325
|
try {
|
|
37143
37326
|
await gh2(contentPutInputArgs(rec.repo, seed.target, tmp));
|
|
37144
37327
|
} finally {
|
|
37145
37328
|
try {
|
|
37146
|
-
(0,
|
|
37329
|
+
(0, import_node_fs33.unlinkSync)(tmp);
|
|
37147
37330
|
} catch {
|
|
37148
37331
|
}
|
|
37149
37332
|
}
|
|
@@ -37212,10 +37395,10 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
|
|
|
37212
37395
|
return fail(`bootstrap rollback: ${e.message}`);
|
|
37213
37396
|
}
|
|
37214
37397
|
const manifestPath = "skills/bootstrap/seeds/manifest.json";
|
|
37215
|
-
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)`);
|
|
37216
37399
|
const seedSource = await resolveHubSeedSource(execGitForSeedSource);
|
|
37217
37400
|
if (!seedSource.ok) return fail(`bootstrap rollback: ${seedSource.reason}`);
|
|
37218
|
-
const manifest = loadBootstrapSeeds((0,
|
|
37401
|
+
const manifest = loadBootstrapSeeds((0, import_node_fs33.readFileSync)(manifestPath, "utf8"));
|
|
37219
37402
|
const propagatable = manifest.seeds.filter(isPropagatableSeed);
|
|
37220
37403
|
if (!o.target) {
|
|
37221
37404
|
return fail(`bootstrap rollback: --target <path> is required \u2014 one of:
|
|
@@ -37232,10 +37415,10 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
|
|
|
37232
37415
|
const enc = (p) => p.split("/").map(encodeURIComponent).join("/");
|
|
37233
37416
|
let candidates;
|
|
37234
37417
|
if (o.record) {
|
|
37235
|
-
if (!(0,
|
|
37418
|
+
if (!(0, import_node_fs33.existsSync)(o.record)) return fail(`bootstrap rollback: --record '${o.record}' not found`);
|
|
37236
37419
|
let parsed;
|
|
37237
37420
|
try {
|
|
37238
|
-
parsed = JSON.parse((0,
|
|
37421
|
+
parsed = JSON.parse((0, import_node_fs33.readFileSync)(o.record, "utf8"));
|
|
37239
37422
|
} catch (e) {
|
|
37240
37423
|
return fail(`bootstrap rollback: --record '${o.record}' is not valid JSON: ${e.message}`);
|
|
37241
37424
|
}
|
|
@@ -37313,12 +37496,12 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
|
|
|
37313
37496
|
existingSha = void 0;
|
|
37314
37497
|
}
|
|
37315
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`);
|
|
37316
|
-
(0,
|
|
37499
|
+
(0, import_node_fs33.writeFileSync)(tmp, JSON.stringify(contentPutBody(seed.target, preSeedContent, plan.branch, existingSha)), "utf8");
|
|
37317
37500
|
try {
|
|
37318
37501
|
await gh2(contentPutInputArgs(repo, seed.target, tmp));
|
|
37319
37502
|
} finally {
|
|
37320
37503
|
try {
|
|
37321
|
-
(0,
|
|
37504
|
+
(0, import_node_fs33.unlinkSync)(tmp);
|
|
37322
37505
|
} catch {
|
|
37323
37506
|
}
|
|
37324
37507
|
}
|
|
@@ -37775,7 +37958,7 @@ async function waitSuiteDev(deps, opts) {
|
|
|
37775
37958
|
}
|
|
37776
37959
|
|
|
37777
37960
|
// src/suite-train.ts
|
|
37778
|
-
var
|
|
37961
|
+
var import_node_fs34 = require("node:fs");
|
|
37779
37962
|
var import_node_path32 = require("node:path");
|
|
37780
37963
|
var import_node_crypto15 = require("node:crypto");
|
|
37781
37964
|
|
|
@@ -37862,7 +38045,7 @@ function suiteReleaseTag(rc) {
|
|
|
37862
38045
|
function readSuiteCut(path2) {
|
|
37863
38046
|
let raw;
|
|
37864
38047
|
try {
|
|
37865
|
-
raw = (0,
|
|
38048
|
+
raw = (0, import_node_fs34.readFileSync)(path2, "utf8");
|
|
37866
38049
|
} catch (e) {
|
|
37867
38050
|
if (e.code === "ENOENT") return void 0;
|
|
37868
38051
|
throw e;
|
|
@@ -37878,11 +38061,11 @@ function readSuiteCut(path2) {
|
|
|
37878
38061
|
return record;
|
|
37879
38062
|
}
|
|
37880
38063
|
function writeSuiteCut(path2, record) {
|
|
37881
|
-
(0,
|
|
38064
|
+
(0, import_node_fs34.mkdirSync)((0, import_node_path32.dirname)(path2), { recursive: true });
|
|
37882
38065
|
const temp = `${path2}.${(0, import_node_crypto15.randomBytes)(8).toString("hex")}.tmp`;
|
|
37883
38066
|
try {
|
|
37884
|
-
(0,
|
|
37885
|
-
(0,
|
|
38067
|
+
(0, import_node_fs34.writeFileSync)(temp, JSON.stringify(record, null, 2), { flag: "wx" });
|
|
38068
|
+
(0, import_node_fs34.renameSync)(temp, path2);
|
|
37886
38069
|
} catch (e) {
|
|
37887
38070
|
throw new Error(`suite cut record write failed at ${path2}: ${e.message}; stop, verify the file before retrying`);
|
|
37888
38071
|
}
|
|
@@ -37931,25 +38114,25 @@ async function suiteMarkAbandoned(deps, ownerGo = false) {
|
|
|
37931
38114
|
return tags.map((t) => `${t.repo}@${t.tag}`);
|
|
37932
38115
|
}
|
|
37933
38116
|
async function retireFailedLeadRcLedger(deps, ownerGo) {
|
|
37934
|
-
if (!(0,
|
|
38117
|
+
if (!(0, import_node_fs34.existsSync)(deps.ledgerPath)) return void 0;
|
|
37935
38118
|
return withLedgerLock(deps.ledgerPath, async (fence) => {
|
|
37936
|
-
const ledger = parseReleaseLedger((0,
|
|
38119
|
+
const ledger = parseReleaseLedger((0, import_node_fs34.readFileSync)(deps.ledgerPath, "utf8"));
|
|
37937
38120
|
const states = Object.values(ledger.phases).map((p) => p.state);
|
|
37938
38121
|
if (ledger.repo !== SUITE_REPO || ledger.lane !== "rcand" || ledger.phases.promotion.state === "complete" || !states.includes("failed")) return void 0;
|
|
37939
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`);
|
|
37940
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`);
|
|
37941
38124
|
const archive = (0, import_node_path32.join)((0, import_node_path32.dirname)(deps.ledgerPath), `phases.archive-${ledger.tag}.json`);
|
|
37942
|
-
if ((0,
|
|
38125
|
+
if ((0, import_node_fs34.existsSync)(archive)) throw new Error(`ledger archive already exists at ${archive}; inspect before retiring again`);
|
|
37943
38126
|
await deps.markAbandoned(SUITE_REPO, ledger.tag, ledger.tagSha);
|
|
37944
|
-
await fence(() => (0,
|
|
38127
|
+
await fence(() => (0, import_node_fs34.renameSync)(deps.ledgerPath, archive));
|
|
37945
38128
|
return `${ledger.tag} (ledger archived to ${archive})`;
|
|
37946
38129
|
});
|
|
37947
38130
|
}
|
|
37948
38131
|
function suiteAbandon(recordPath, ownerGo = false, now = /* @__PURE__ */ new Date()) {
|
|
37949
38132
|
const record = abandonableCut(recordPath, ownerGo);
|
|
37950
38133
|
const archive = `${recordPath}.abandoned-${record.leadDevelopment.slice(0, 12)}-${now.toISOString().replace(/[:.]/g, "")}.json`;
|
|
37951
|
-
if ((0,
|
|
37952
|
-
(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);
|
|
37953
38136
|
return { archive, orphanTags: record.members.filter((m) => m.tag).map((m) => `${m.repo}@${m.tag}`) };
|
|
37954
38137
|
}
|
|
37955
38138
|
async function suiteRestoreMainPins(deps) {
|
|
@@ -38032,12 +38215,12 @@ async function suiteRcandRun(deps, opts) {
|
|
|
38032
38215
|
}
|
|
38033
38216
|
if ((record?.announcement === "sent" || record?.announcement === "skipped") && record.leadReleased) {
|
|
38034
38217
|
const archive = `${deps.recordPath}.${record.leadRcTag}.json`;
|
|
38035
|
-
if ((0,
|
|
38036
|
-
(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);
|
|
38037
38220
|
record = void 0;
|
|
38038
38221
|
}
|
|
38039
38222
|
if (record && !record.pinPr && !record.leadRcTag && record.members.every((m) => !m.tag)) {
|
|
38040
|
-
(0,
|
|
38223
|
+
(0, import_node_fs34.rmSync)(deps.recordPath, { force: true });
|
|
38041
38224
|
record = void 0;
|
|
38042
38225
|
}
|
|
38043
38226
|
if (!record) {
|
|
@@ -38091,7 +38274,7 @@ async function suiteRcandRun(deps, opts) {
|
|
|
38091
38274
|
quiet.push(member);
|
|
38092
38275
|
}
|
|
38093
38276
|
if (record.members.every((m) => m.carried || quiet.includes(m)) && await deps.contains(SUITE_REPO, record.leadDevelopment, record.leadPreviousRc)) {
|
|
38094
|
-
(0,
|
|
38277
|
+
(0, import_node_fs34.rmSync)(deps.recordPath, { force: true });
|
|
38095
38278
|
throw new Error("nothing to promote: neither MM-Work nor any module has new development commits since its rc; no suite cut started");
|
|
38096
38279
|
}
|
|
38097
38280
|
for (const member of quiet) {
|
|
@@ -38109,7 +38292,7 @@ async function suiteRcandRun(deps, opts) {
|
|
|
38109
38292
|
}
|
|
38110
38293
|
if (refusals.length) {
|
|
38111
38294
|
const untouched = record.members.every((m) => !m.tag) && !record.pinPr;
|
|
38112
|
-
if (untouched) (0,
|
|
38295
|
+
if (untouched) (0, import_node_fs34.rmSync)(deps.recordPath, { force: true });
|
|
38113
38296
|
throw new Error(`module rc serving is not ready; ${untouched ? "no suite cut started" : "no new tag was cut"}:
|
|
38114
38297
|
${refusals.join("\n")}
|
|
38115
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).`);
|
|
@@ -38305,7 +38488,7 @@ var hotfixRecordPath = (deps) => (0, import_node_path32.join)((0, import_node_pa
|
|
|
38305
38488
|
function readSuiteHotfix(path2) {
|
|
38306
38489
|
let raw;
|
|
38307
38490
|
try {
|
|
38308
|
-
raw = (0,
|
|
38491
|
+
raw = (0, import_node_fs34.readFileSync)(path2, "utf8");
|
|
38309
38492
|
} catch (e) {
|
|
38310
38493
|
if (e.code === "ENOENT") return void 0;
|
|
38311
38494
|
throw e;
|
|
@@ -38348,7 +38531,7 @@ async function suiteHotfix(deps, opts) {
|
|
|
38348
38531
|
if (completed) record = void 0;
|
|
38349
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`);
|
|
38350
38533
|
if (!record?.tag) await deps.validateHotfixSummary();
|
|
38351
|
-
if (completed) (0,
|
|
38534
|
+
if (completed) (0, import_node_fs34.renameSync)(path2, `${path2}.${completed.leadTag}.json`);
|
|
38352
38535
|
const rec = record ?? { schema: "mmi-suite-hotfix/v1", member: found.id, repo: found.repo, from: opts.from, ...opts.ack?.length ? { ack: opts.ack } : {} };
|
|
38353
38536
|
const save = () => writeSuiteHotfix(path2, rec);
|
|
38354
38537
|
save();
|
|
@@ -38617,7 +38800,7 @@ async function runRcDataSwitch(deps, opts) {
|
|
|
38617
38800
|
// src/suite-train-io.ts
|
|
38618
38801
|
var import_node_child_process18 = require("node:child_process");
|
|
38619
38802
|
var import_node_path45 = require("node:path");
|
|
38620
|
-
var
|
|
38803
|
+
var import_node_fs47 = require("node:fs");
|
|
38621
38804
|
var import_node_path46 = require("node:path");
|
|
38622
38805
|
init_cli_shared();
|
|
38623
38806
|
|
|
@@ -40294,7 +40477,7 @@ function checkHotfixCarries(options) {
|
|
|
40294
40477
|
}
|
|
40295
40478
|
|
|
40296
40479
|
// src/merge-cleanup.ts
|
|
40297
|
-
var
|
|
40480
|
+
var import_node_fs36 = require("node:fs");
|
|
40298
40481
|
var import_node_path34 = require("node:path");
|
|
40299
40482
|
var import_node_os19 = require("node:os");
|
|
40300
40483
|
init_cli_shared();
|
|
@@ -40723,7 +40906,7 @@ function renderPrLandTable(entries) {
|
|
|
40723
40906
|
|
|
40724
40907
|
// src/test-policy-core.ts
|
|
40725
40908
|
var import_node_child_process13 = require("node:child_process");
|
|
40726
|
-
var
|
|
40909
|
+
var import_node_fs35 = require("node:fs");
|
|
40727
40910
|
var import_node_path33 = require("node:path");
|
|
40728
40911
|
|
|
40729
40912
|
// src/test-command-policy-shared.mjs
|
|
@@ -41293,7 +41476,7 @@ function loadPolicySource(root, explicitRef, diffBase) {
|
|
|
41293
41476
|
}
|
|
41294
41477
|
function readFileOrNull2(path2) {
|
|
41295
41478
|
try {
|
|
41296
|
-
return (0,
|
|
41479
|
+
return (0, import_node_fs35.readFileSync)(path2, "utf8");
|
|
41297
41480
|
} catch {
|
|
41298
41481
|
return null;
|
|
41299
41482
|
}
|
|
@@ -41321,10 +41504,10 @@ function classify(changed, policy, present = () => false) {
|
|
|
41321
41504
|
const removedProtected = [...removed].filter((p) => protectedBy.has(p)).map((p) => ({ path: p, why: protectedBy.get(p) ?? "" }));
|
|
41322
41505
|
return { mandatoryHits, untestedHits, testChanges, meaningfulTestChanges, addedTests, removedProtected };
|
|
41323
41506
|
}
|
|
41324
|
-
function unresolvedProtectedEntries(policy, root, exists = (path2) => (0,
|
|
41507
|
+
function unresolvedProtectedEntries(policy, root, exists = (path2) => (0, import_node_fs35.existsSync)(path2)) {
|
|
41325
41508
|
return (policy.protected ?? []).map((p) => p.path).filter((p) => !exists((0, import_node_path33.join)(root, p)));
|
|
41326
41509
|
}
|
|
41327
|
-
function unresolvedSatisfiers(policy, root, exists = (path2) => (0,
|
|
41510
|
+
function unresolvedSatisfiers(policy, root, exists = (path2) => (0, import_node_fs35.existsSync)(path2)) {
|
|
41328
41511
|
const declared = (policy.mandatory ?? []).flatMap((m) => m.satisfiedBy ?? []);
|
|
41329
41512
|
return [...new Set(declared)].filter((p) => !exists((0, import_node_path33.join)(root, p)));
|
|
41330
41513
|
}
|
|
@@ -41465,7 +41648,7 @@ function runTestPolicy(root, deps = {}) {
|
|
|
41465
41648
|
}
|
|
41466
41649
|
const loaded = deps.policy ? { policy: deps.policy, source: { ref: null, sha: null, path: POLICY_FILE } } : loadPolicySource(root, deps.policyRef, deps.base);
|
|
41467
41650
|
const { policy, source: policySource } = loaded;
|
|
41468
|
-
const exists = deps.exists ?? ((path2) => (0,
|
|
41651
|
+
const exists = deps.exists ?? ((path2) => (0, import_node_fs35.existsSync)(path2));
|
|
41469
41652
|
const counts = { mandatoryCount: (policy.mandatory ?? []).length, protectedCount: (policy.protected ?? []).length };
|
|
41470
41653
|
const base = deps.changed ? "(injected)" : deps.policyRef ? resolveHotfixBase(root) : resolveBase(root, deps.base);
|
|
41471
41654
|
const refusal = deps.changed ? null : untrustworthyRange(root, base);
|
|
@@ -41763,13 +41946,13 @@ function resolveSquashMergeBodyText(commits, allowedClosing, cwd) {
|
|
|
41763
41946
|
return rewritten === base ? null : rewritten;
|
|
41764
41947
|
}
|
|
41765
41948
|
function writeSquashBodyFile(body) {
|
|
41766
|
-
const dir = (0,
|
|
41949
|
+
const dir = (0, import_node_fs36.mkdtempSync)((0, import_node_path34.join)((0, import_node_os19.tmpdir)(), "mmi-squash-body-"));
|
|
41767
41950
|
const path2 = (0, import_node_path34.join)(dir, "body.txt");
|
|
41768
|
-
(0,
|
|
41951
|
+
(0, import_node_fs36.writeFileSync)(path2, body.endsWith("\n") ? body : `${body}
|
|
41769
41952
|
`, "utf8");
|
|
41770
41953
|
return { path: path2, cleanup: () => {
|
|
41771
41954
|
try {
|
|
41772
|
-
(0,
|
|
41955
|
+
(0, import_node_fs36.rmSync)(dir, { recursive: true, force: true });
|
|
41773
41956
|
} catch {
|
|
41774
41957
|
}
|
|
41775
41958
|
} };
|
|
@@ -42058,7 +42241,7 @@ function prMergeQueueLine(result) {
|
|
|
42058
42241
|
}
|
|
42059
42242
|
|
|
42060
42243
|
// src/project-info-sync.ts
|
|
42061
|
-
var
|
|
42244
|
+
var import_node_fs37 = require("node:fs");
|
|
42062
42245
|
var import_node_path35 = require("node:path");
|
|
42063
42246
|
var UPDATE_PROJECT_INFO = `mutation($projectId: ID!, $shortDescription: String!, $readme: String!) {
|
|
42064
42247
|
updateProjectV2(input: { projectId: $projectId, shortDescription: $shortDescription, readme: $readme }) {
|
|
@@ -42107,13 +42290,13 @@ function sharedName(entries, fallback) {
|
|
|
42107
42290
|
function buildProjectInfoSyncPlan(targetRepo2, project2, projects, repoRoot2) {
|
|
42108
42291
|
if (!project2.projectId) throw new Error(`org project sync-info: ${targetRepo2} registry META has no projectId`);
|
|
42109
42292
|
const readmePath = (0, import_node_path35.join)(repoRoot2, "README.md");
|
|
42110
|
-
if (!(0,
|
|
42293
|
+
if (!(0, import_node_fs37.existsSync)(readmePath)) throw new Error(`org project sync-info: ${targetRepo2} has no README.md`);
|
|
42111
42294
|
const entries = entriesFor(project2, projects);
|
|
42112
42295
|
const memberRepos = [...new Set(entries.flatMap((entry) => entry.repos ?? []))].filter((repo) => /^[^/]+\/[^/]+$/.test(repo)).sort((a, b) => a.localeCompare(b));
|
|
42113
42296
|
const projectName = sharedName(entries, project2.name?.trim() || targetRepo2.split("/").pop() || targetRepo2);
|
|
42114
42297
|
if (!memberRepos.length) throw new Error(`org project sync-info: project ${projectName} has no registered member repos`);
|
|
42115
42298
|
const entryNames = entries.map((entry) => entry.name?.trim()).filter((name) => Boolean(name));
|
|
42116
|
-
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)}.`;
|
|
42117
42300
|
const lines2 = [
|
|
42118
42301
|
`# ${projectName}`,
|
|
42119
42302
|
"",
|
|
@@ -42132,8 +42315,8 @@ function buildProjectInfoSyncPlan(targetRepo2, project2, projects, repoRoot2) {
|
|
|
42132
42315
|
const targetBase = `https://github.com/${targetRepo2}`;
|
|
42133
42316
|
const targetBranch = branchFor(targetRepo2, projects);
|
|
42134
42317
|
const orgDocs = [
|
|
42135
|
-
(0,
|
|
42136
|
-
(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)` : ""
|
|
42137
42320
|
].filter(Boolean);
|
|
42138
42321
|
if (orgDocs.length) lines2.push("", "## Organisation docs", "", ...orgDocs);
|
|
42139
42322
|
return { projectId: project2.projectId, projectName, targetRepo: targetRepo2, memberRepos, shortDescription, readme: `${lines2.join("\n")}
|
|
@@ -42155,7 +42338,7 @@ async function syncProjectInfo(plan, client, apply) {
|
|
|
42155
42338
|
}
|
|
42156
42339
|
|
|
42157
42340
|
// src/train-commands.ts
|
|
42158
|
-
var
|
|
42341
|
+
var import_node_fs38 = require("node:fs");
|
|
42159
42342
|
var import_node_path36 = require("node:path");
|
|
42160
42343
|
init_cli_shared();
|
|
42161
42344
|
init_clean_exit();
|
|
@@ -42171,7 +42354,7 @@ function resolveReleaseBumpIntent(raw) {
|
|
|
42171
42354
|
}
|
|
42172
42355
|
function readRepoVersion() {
|
|
42173
42356
|
try {
|
|
42174
|
-
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;
|
|
42175
42358
|
} catch {
|
|
42176
42359
|
return void 0;
|
|
42177
42360
|
}
|
|
@@ -42536,7 +42719,7 @@ async function openSuitePinPr(deps, input) {
|
|
|
42536
42719
|
|
|
42537
42720
|
// src/command-register-collaboration.ts
|
|
42538
42721
|
var import_node_child_process17 = require("node:child_process");
|
|
42539
|
-
var
|
|
42722
|
+
var import_node_fs46 = require("node:fs");
|
|
42540
42723
|
var import_promises8 = require("node:fs/promises");
|
|
42541
42724
|
init_clean_exit();
|
|
42542
42725
|
init_cli_shared();
|
|
@@ -42670,7 +42853,7 @@ init_github_client();
|
|
|
42670
42853
|
init_github_quota();
|
|
42671
42854
|
|
|
42672
42855
|
// src/issue-commands.ts
|
|
42673
|
-
var
|
|
42856
|
+
var import_node_fs39 = require("node:fs");
|
|
42674
42857
|
var import_node_crypto16 = require("node:crypto");
|
|
42675
42858
|
init_cli_shared();
|
|
42676
42859
|
init_clean_exit();
|
|
@@ -42863,7 +43046,7 @@ async function editIssue(client, options, deps = {}) {
|
|
|
42863
43046
|
const url = `https://github.com/${repo}/issues/${parsed.number}`;
|
|
42864
43047
|
const patch = {};
|
|
42865
43048
|
let bodyChanged = false;
|
|
42866
|
-
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("") };
|
|
42867
43050
|
if (options.titleFile !== void 0) {
|
|
42868
43051
|
patch.title = await resolveIssueTitle({ title: options.title, titleFile: options.titleFile }, textDeps());
|
|
42869
43052
|
} else if (options.title !== void 0) {
|
|
@@ -43526,7 +43709,7 @@ function extendCreateCommand(issue, batchAttach) {
|
|
|
43526
43709
|
if (opts.batch) {
|
|
43527
43710
|
let specs;
|
|
43528
43711
|
try {
|
|
43529
|
-
const raw = (0,
|
|
43712
|
+
const raw = (0, import_node_fs39.readFileSync)(opts.batch, "utf8");
|
|
43530
43713
|
specs = JSON.parse(raw);
|
|
43531
43714
|
if (!Array.isArray(specs)) {
|
|
43532
43715
|
const top = specs === null ? "null" : typeof specs === "object" ? `an object with keys: ${Object.keys(specs).join(", ") || "(none)"}` : `a ${typeof specs}`;
|
|
@@ -43603,7 +43786,7 @@ ${lines2}`, {
|
|
|
43603
43786
|
}
|
|
43604
43787
|
|
|
43605
43788
|
// src/post-merge-recon.ts
|
|
43606
|
-
var
|
|
43789
|
+
var import_node_fs40 = require("node:fs");
|
|
43607
43790
|
var import_node_path38 = require("node:path");
|
|
43608
43791
|
|
|
43609
43792
|
// src/cross-repo-filing-issue.ts
|
|
@@ -43773,16 +43956,16 @@ function buildPostMergeReconRecovery(input) {
|
|
|
43773
43956
|
}
|
|
43774
43957
|
function writePostMergeReconRecovery(cwd, recovery) {
|
|
43775
43958
|
const path2 = postMergeReconStatePath(cwd, recovery.repo, recovery.pr);
|
|
43776
|
-
(0,
|
|
43777
|
-
(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)}
|
|
43778
43961
|
`, "utf8");
|
|
43779
43962
|
return path2;
|
|
43780
43963
|
}
|
|
43781
43964
|
function clearPostMergeReconRecovery(cwd, repo, pr) {
|
|
43782
43965
|
const path2 = postMergeReconStatePath(cwd, repo, pr);
|
|
43783
|
-
if (!(0,
|
|
43966
|
+
if (!(0, import_node_fs40.existsSync)(path2)) return;
|
|
43784
43967
|
try {
|
|
43785
|
-
(0,
|
|
43968
|
+
(0, import_node_fs40.unlinkSync)(path2);
|
|
43786
43969
|
} catch {
|
|
43787
43970
|
}
|
|
43788
43971
|
}
|
|
@@ -44258,7 +44441,7 @@ function registerPrLifecycleCommands(program3) {
|
|
|
44258
44441
|
|
|
44259
44442
|
// src/review-verdict.ts
|
|
44260
44443
|
var import_node_child_process14 = require("node:child_process");
|
|
44261
|
-
var
|
|
44444
|
+
var import_node_fs41 = require("node:fs");
|
|
44262
44445
|
var import_node_os21 = require("node:os");
|
|
44263
44446
|
var import_node_path39 = require("node:path");
|
|
44264
44447
|
init_cli_shared();
|
|
@@ -44425,15 +44608,15 @@ async function readPrIssueComments(number, repo) {
|
|
|
44425
44608
|
return comments;
|
|
44426
44609
|
}
|
|
44427
44610
|
async function postPrCommentFromFile(number, repo, body) {
|
|
44428
|
-
const dir = (0,
|
|
44611
|
+
const dir = (0, import_node_fs41.mkdtempSync)((0, import_node_path39.join)((0, import_node_os21.tmpdir)(), "mmi-review-verdict-"));
|
|
44429
44612
|
const path2 = (0, import_node_path39.join)(dir, "body.md");
|
|
44430
44613
|
try {
|
|
44431
|
-
(0,
|
|
44614
|
+
(0, import_node_fs41.writeFileSync)(path2, body, "utf8");
|
|
44432
44615
|
const { stdout } = await execFileP("gh", ["pr", "comment", number, "--repo", repo, "--body-file", path2], { timeout: GH_MUTATION_TIMEOUT_MS });
|
|
44433
44616
|
return stdout.trim();
|
|
44434
44617
|
} finally {
|
|
44435
44618
|
try {
|
|
44436
|
-
(0,
|
|
44619
|
+
(0, import_node_fs41.rmSync)(dir, { recursive: true, force: true });
|
|
44437
44620
|
} catch {
|
|
44438
44621
|
}
|
|
44439
44622
|
}
|
|
@@ -44667,17 +44850,17 @@ async function prCreateClaimRefusal(body, repoOption, deps = {}) {
|
|
|
44667
44850
|
}
|
|
44668
44851
|
|
|
44669
44852
|
// src/worktree-residue-sweep.ts
|
|
44670
|
-
var
|
|
44853
|
+
var import_node_fs45 = require("node:fs");
|
|
44671
44854
|
var import_node_path43 = require("node:path");
|
|
44672
44855
|
|
|
44673
44856
|
// src/worktree-merge-cleanup.ts
|
|
44674
|
-
var
|
|
44857
|
+
var import_node_fs44 = require("node:fs");
|
|
44675
44858
|
var import_node_path42 = require("node:path");
|
|
44676
44859
|
init_cli_shared();
|
|
44677
44860
|
|
|
44678
44861
|
// src/stage-runner.ts
|
|
44679
44862
|
var import_node_child_process16 = require("node:child_process");
|
|
44680
|
-
var
|
|
44863
|
+
var import_node_fs43 = require("node:fs");
|
|
44681
44864
|
var import_node_path41 = require("node:path");
|
|
44682
44865
|
var import_node_net = require("node:net");
|
|
44683
44866
|
var import_node_util5 = require("node:util");
|
|
@@ -44688,7 +44871,7 @@ function normalizeEol2(s) {
|
|
|
44688
44871
|
}
|
|
44689
44872
|
|
|
44690
44873
|
// src/env-detection.ts
|
|
44691
|
-
var
|
|
44874
|
+
var import_node_fs42 = require("node:fs");
|
|
44692
44875
|
var import_node_path40 = require("node:path");
|
|
44693
44876
|
var SKIPPED_DIRS = /* @__PURE__ */ new Set([".git", "node_modules", "dist", ".jerv", ".pi", ".venv", "venv"]);
|
|
44694
44877
|
function isEnvBaseName(name) {
|
|
@@ -44699,7 +44882,7 @@ function findEnvFiles(root) {
|
|
|
44699
44882
|
const walk2 = (dir, rel) => {
|
|
44700
44883
|
let entries;
|
|
44701
44884
|
try {
|
|
44702
|
-
entries = (0,
|
|
44885
|
+
entries = (0, import_node_fs42.readdirSync)(dir, { withFileTypes: true });
|
|
44703
44886
|
} catch {
|
|
44704
44887
|
return;
|
|
44705
44888
|
}
|
|
@@ -44713,7 +44896,7 @@ function findEnvFiles(root) {
|
|
|
44713
44896
|
if (isEnvBaseName(entry.name)) {
|
|
44714
44897
|
let isDir = false;
|
|
44715
44898
|
try {
|
|
44716
|
-
isDir = (0,
|
|
44899
|
+
isDir = (0, import_node_fs42.lstatSync)((0, import_node_path40.join)(dir, entry.name)).isDirectory();
|
|
44717
44900
|
} catch {
|
|
44718
44901
|
}
|
|
44719
44902
|
if (!isDir) found.push(relPath);
|
|
@@ -44852,12 +45035,12 @@ var DOCKER_TIMEOUT_MS = 15e3;
|
|
|
44852
45035
|
function stageBash() {
|
|
44853
45036
|
if (process.platform !== "win32") return "bash";
|
|
44854
45037
|
const configured = process.env.SHELL;
|
|
44855
|
-
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;
|
|
44856
45039
|
const candidates = [
|
|
44857
45040
|
(0, import_node_path41.join)(process.env.ProgramFiles || "C:\\Program Files", "Git", "bin", "bash.exe"),
|
|
44858
45041
|
...process.env.LOCALAPPDATA ? [(0, import_node_path41.join)(process.env.LOCALAPPDATA, "Programs", "Git", "bin", "bash.exe")] : []
|
|
44859
45042
|
];
|
|
44860
|
-
const bash = candidates.find((path2) => (0,
|
|
45043
|
+
const bash = candidates.find((path2) => (0, import_node_fs43.existsSync)(path2));
|
|
44861
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.");
|
|
44862
45045
|
return bash;
|
|
44863
45046
|
}
|
|
@@ -45213,7 +45396,7 @@ function stageProcessEnv(stagePort, extraEnv) {
|
|
|
45213
45396
|
function composeResolvesPort(cwd) {
|
|
45214
45397
|
if (process.env.PORT) return true;
|
|
45215
45398
|
const envFile = (0, import_node_path41.join)(cwd, ".env");
|
|
45216
|
-
return (0,
|
|
45399
|
+
return (0, import_node_fs43.existsSync)(envFile) && envFileKeys((0, import_node_fs43.readFileSync)(envFile, "utf8")).has("PORT");
|
|
45217
45400
|
}
|
|
45218
45401
|
function stageComposeEnv(config, stagePort, vaultEnvMerge, cwd) {
|
|
45219
45402
|
const composeProject = config.env?.COMPOSE_PROJECT_NAME ?? vaultEnvMerge?.COMPOSE_PROJECT_NAME ?? stageComposeProjectName(cwd);
|
|
@@ -45228,13 +45411,13 @@ function stageComposeEnv(config, stagePort, vaultEnvMerge, cwd) {
|
|
|
45228
45411
|
function stageComposeFiles(cwd) {
|
|
45229
45412
|
const files = ["docker-compose.yml"];
|
|
45230
45413
|
for (const conventional of ["docker-compose.override.yml", "docker-compose.override.yaml"]) {
|
|
45231
|
-
if ((0,
|
|
45414
|
+
if ((0, import_node_fs43.existsSync)((0, import_node_path41.join)(cwd, conventional))) files.push(conventional);
|
|
45232
45415
|
}
|
|
45233
45416
|
return [...files, RUNTIME_ENV_OVERRIDE_RELPATH];
|
|
45234
45417
|
}
|
|
45235
45418
|
async function prepareRuntimeEnvPassthrough(cwd, composeEnv, vaultEnvMerge) {
|
|
45236
45419
|
const keys = Object.keys(vaultEnvMerge ?? {});
|
|
45237
|
-
if (!keys.length || !(0,
|
|
45420
|
+
if (!keys.length || !(0, import_node_fs43.existsSync)((0, import_node_path41.join)(cwd, "docker-compose.yml"))) return {};
|
|
45238
45421
|
let configJson;
|
|
45239
45422
|
try {
|
|
45240
45423
|
const { stdout } = await execFileP3("docker", ["compose", "config", "--format", "json"], {
|
|
@@ -45251,20 +45434,20 @@ async function prepareRuntimeEnvPassthrough(cwd, composeEnv, vaultEnvMerge) {
|
|
|
45251
45434
|
const body = renderRuntimeEnvOverride(runtimeEnvMarkedServices(configJson), keys, runtimeEnvExcludes(configJson), runtimeEnvSelects(configJson));
|
|
45252
45435
|
if (!body) return {};
|
|
45253
45436
|
const overridePath = (0, import_node_path41.join)(cwd, RUNTIME_ENV_OVERRIDE_RELPATH);
|
|
45254
|
-
(0,
|
|
45255
|
-
(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");
|
|
45256
45439
|
return stageComposeFileEnv(stageComposeFiles(cwd));
|
|
45257
45440
|
}
|
|
45258
45441
|
async function ensureStageRuntimeEnv(config, opts, cwd) {
|
|
45259
45442
|
if (!config.ensureEnv) return;
|
|
45260
45443
|
const target = (0, import_node_path41.join)(cwd, config.ensureEnv.target);
|
|
45261
45444
|
const example = (0, import_node_path41.join)(cwd, config.ensureEnv.example);
|
|
45262
|
-
if (!(0,
|
|
45263
|
-
(0,
|
|
45264
|
-
} else if ((0,
|
|
45265
|
-
const stale = detectStaleEnvFile((0,
|
|
45266
|
-
exampleMtimeMs: (0,
|
|
45267
|
-
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
|
|
45268
45451
|
});
|
|
45269
45452
|
if (stale) {
|
|
45270
45453
|
const msg = `stale ${config.ensureEnv.target} (${stale}) \u2014 delete it or refresh from ${config.ensureEnv.example} before re-running /stage`;
|
|
@@ -45272,8 +45455,8 @@ async function ensureStageRuntimeEnv(config, opts, cwd) {
|
|
|
45272
45455
|
console.error(`mmi-cli stage: ${msg} (allowed via --allow-stale-env)`);
|
|
45273
45456
|
}
|
|
45274
45457
|
}
|
|
45275
|
-
if (opts.vaultEnvMerge && Object.keys(opts.vaultEnvMerge).length && (0,
|
|
45276
|
-
(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");
|
|
45277
45460
|
}
|
|
45278
45461
|
}
|
|
45279
45462
|
async function gitText(cwd, args) {
|
|
@@ -45303,20 +45486,20 @@ async function resolveGlobalStatePath(cwd, explicit) {
|
|
|
45303
45486
|
return void 0;
|
|
45304
45487
|
}
|
|
45305
45488
|
function readState(path2) {
|
|
45306
|
-
if (!(0,
|
|
45489
|
+
if (!(0, import_node_fs43.existsSync)(path2)) return null;
|
|
45307
45490
|
try {
|
|
45308
|
-
return JSON.parse((0,
|
|
45491
|
+
return JSON.parse((0, import_node_fs43.readFileSync)(path2, "utf8"));
|
|
45309
45492
|
} catch {
|
|
45310
45493
|
return null;
|
|
45311
45494
|
}
|
|
45312
45495
|
}
|
|
45313
45496
|
function mkdirFor(path2) {
|
|
45314
45497
|
const dir = path2.slice(0, Math.max(path2.lastIndexOf("/"), path2.lastIndexOf("\\")));
|
|
45315
|
-
(0,
|
|
45498
|
+
(0, import_node_fs43.mkdirSync)(dir, { recursive: true });
|
|
45316
45499
|
}
|
|
45317
45500
|
function writeState(path2, state) {
|
|
45318
45501
|
mkdirFor(path2);
|
|
45319
|
-
(0,
|
|
45502
|
+
(0, import_node_fs43.writeFileSync)(path2, JSON.stringify(state, null, 2), "utf8");
|
|
45320
45503
|
}
|
|
45321
45504
|
function writeStagePortReservation(port, cwd, statePath, globalStatePath, now) {
|
|
45322
45505
|
const reservation = {
|
|
@@ -45345,7 +45528,7 @@ async function cleanupStageState(state, paths, timeoutMs, fallbackCwd, currentEn
|
|
|
45345
45528
|
);
|
|
45346
45529
|
}
|
|
45347
45530
|
for (const path2 of [...new Set(paths.filter((p) => Boolean(p)))]) {
|
|
45348
|
-
(0,
|
|
45531
|
+
(0, import_node_fs43.rmSync)(path2, { force: true });
|
|
45349
45532
|
}
|
|
45350
45533
|
}
|
|
45351
45534
|
async function killTree(pid) {
|
|
@@ -45592,8 +45775,8 @@ async function runStage(config = {}, opts = {}) {
|
|
|
45592
45775
|
});
|
|
45593
45776
|
}
|
|
45594
45777
|
} catch (e) {
|
|
45595
|
-
(0,
|
|
45596
|
-
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 });
|
|
45597
45780
|
throw e;
|
|
45598
45781
|
}
|
|
45599
45782
|
const started = await startStage(config, {
|
|
@@ -45614,7 +45797,7 @@ function normPath2(p) {
|
|
|
45614
45797
|
function unlinkNodeModulesJunction(wtPath) {
|
|
45615
45798
|
const nm = (0, import_node_path42.join)(wtPath, "node_modules");
|
|
45616
45799
|
try {
|
|
45617
|
-
if ((0,
|
|
45800
|
+
if ((0, import_node_fs44.lstatSync)(nm).isSymbolicLink()) (0, import_node_fs44.rmdirSync)(nm);
|
|
45618
45801
|
return { ok: true };
|
|
45619
45802
|
} catch (e) {
|
|
45620
45803
|
if (e.code === "ENOENT") return { ok: true };
|
|
@@ -45625,8 +45808,8 @@ function defaultSleep2(ms) {
|
|
|
45625
45808
|
return new Promise((resolve8) => setTimeout(resolve8, ms));
|
|
45626
45809
|
}
|
|
45627
45810
|
async function removeResidueDirectory(wtPath, options = {}) {
|
|
45628
|
-
const { sleep: sleep2 = defaultSleep2, removeEmptyDir =
|
|
45629
|
-
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 }));
|
|
45630
45813
|
const junction = unlinkNodeModulesJunction(wtPath);
|
|
45631
45814
|
if (!junction.ok) return junction;
|
|
45632
45815
|
try {
|
|
@@ -45752,21 +45935,21 @@ async function listNestedIgnoredNodeModules(wtPath, execGit) {
|
|
|
45752
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)));
|
|
45753
45936
|
}
|
|
45754
45937
|
function safeRemoveTree(path2) {
|
|
45755
|
-
const stat4 = (0,
|
|
45938
|
+
const stat4 = (0, import_node_fs44.lstatSync)(path2);
|
|
45756
45939
|
if (stat4.isSymbolicLink()) {
|
|
45757
45940
|
try {
|
|
45758
|
-
(0,
|
|
45941
|
+
(0, import_node_fs44.rmdirSync)(path2);
|
|
45759
45942
|
} catch {
|
|
45760
|
-
(0,
|
|
45943
|
+
(0, import_node_fs44.unlinkSync)(path2);
|
|
45761
45944
|
}
|
|
45762
45945
|
return;
|
|
45763
45946
|
}
|
|
45764
45947
|
if (stat4.isDirectory()) {
|
|
45765
|
-
for (const entry of (0,
|
|
45766
|
-
(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);
|
|
45767
45950
|
return;
|
|
45768
45951
|
}
|
|
45769
|
-
(0,
|
|
45952
|
+
(0, import_node_fs44.unlinkSync)(path2);
|
|
45770
45953
|
}
|
|
45771
45954
|
async function removeWorktreeNodeModules(wtPath) {
|
|
45772
45955
|
try {
|
|
@@ -45782,7 +45965,7 @@ function errorMessage(e) {
|
|
|
45782
45965
|
}
|
|
45783
45966
|
function resolvedOrRaw(path2) {
|
|
45784
45967
|
try {
|
|
45785
|
-
return normPath2((0,
|
|
45968
|
+
return normPath2((0, import_node_fs44.realpathSync)(path2));
|
|
45786
45969
|
} catch {
|
|
45787
45970
|
return normPath2(path2);
|
|
45788
45971
|
}
|
|
@@ -45790,10 +45973,10 @@ function resolvedOrRaw(path2) {
|
|
|
45790
45973
|
function unlinkEscapingReparsePoints(root, primaryRoot) {
|
|
45791
45974
|
let realRoot;
|
|
45792
45975
|
try {
|
|
45793
|
-
if ((0,
|
|
45976
|
+
if ((0, import_node_fs44.lstatSync)(root).isSymbolicLink()) {
|
|
45794
45977
|
return { ok: false, error: `delete root ${normPath2(root)} is a reparse point resolving to ${resolvedOrRaw(root)}` };
|
|
45795
45978
|
}
|
|
45796
|
-
realRoot = normPath2((0,
|
|
45979
|
+
realRoot = normPath2((0, import_node_fs44.realpathSync)(root));
|
|
45797
45980
|
} catch (e) {
|
|
45798
45981
|
if (e.code === "ENOENT") return { ok: true, unlinked: [] };
|
|
45799
45982
|
return { ok: false, error: `cannot resolve delete root ${normPath2(root)}: ${errorMessage(e)}` };
|
|
@@ -45809,7 +45992,7 @@ function unlinkEscapingReparsePoints(root, primaryRoot) {
|
|
|
45809
45992
|
const dir = stack.pop();
|
|
45810
45993
|
let entries;
|
|
45811
45994
|
try {
|
|
45812
|
-
entries = (0,
|
|
45995
|
+
entries = (0, import_node_fs44.readdirSync)(dir, { withFileTypes: true });
|
|
45813
45996
|
} catch (e) {
|
|
45814
45997
|
if (e.code === "ENOENT") continue;
|
|
45815
45998
|
return { ok: false, error: `cannot scan ${normPath2(dir)} for reparse points: ${errorMessage(e)}` };
|
|
@@ -45819,7 +46002,7 @@ function unlinkEscapingReparsePoints(root, primaryRoot) {
|
|
|
45819
46002
|
if (entry.isSymbolicLink()) {
|
|
45820
46003
|
let target = "";
|
|
45821
46004
|
try {
|
|
45822
|
-
target = normPath2((0,
|
|
46005
|
+
target = normPath2((0, import_node_fs44.realpathSync)(child2));
|
|
45823
46006
|
} catch {
|
|
45824
46007
|
target = "";
|
|
45825
46008
|
}
|
|
@@ -46002,7 +46185,7 @@ async function cleanupPrMergeLocalBranch(branch, options) {
|
|
|
46002
46185
|
return report;
|
|
46003
46186
|
}
|
|
46004
46187
|
const execGit = options.execGit ?? (async (args) => (await execFileP("git", args, { timeout: GIT_TIMEOUT_MS })).stdout);
|
|
46005
|
-
const pathExists = options.pathExists ??
|
|
46188
|
+
const pathExists = options.pathExists ?? import_node_fs44.existsSync;
|
|
46006
46189
|
let afterWorktrees = [];
|
|
46007
46190
|
try {
|
|
46008
46191
|
afterWorktrees = parseGitWorktreePorcelain(await execGit(["worktree", "list", "--porcelain"]));
|
|
@@ -46289,7 +46472,7 @@ function residueLedgerPath(gitCommonDir) {
|
|
|
46289
46472
|
}
|
|
46290
46473
|
function readPaths(file, deps) {
|
|
46291
46474
|
try {
|
|
46292
|
-
const parsed = JSON.parse((deps.readLedger ?? ((f) => (0,
|
|
46475
|
+
const parsed = JSON.parse((deps.readLedger ?? ((f) => (0, import_node_fs45.readFileSync)(f, "utf8")))(file));
|
|
46293
46476
|
return Array.isArray(parsed) ? parsed.filter((p) => typeof p === "string") : [];
|
|
46294
46477
|
} catch {
|
|
46295
46478
|
return [];
|
|
@@ -46298,8 +46481,8 @@ function readPaths(file, deps) {
|
|
|
46298
46481
|
function writePaths(file, paths, deps) {
|
|
46299
46482
|
try {
|
|
46300
46483
|
const write = deps.writeLedger ?? ((f, t) => {
|
|
46301
|
-
(0,
|
|
46302
|
-
(0,
|
|
46484
|
+
(0, import_node_fs45.mkdirSync)((0, import_node_path43.dirname)(f), { recursive: true });
|
|
46485
|
+
(0, import_node_fs45.writeFileSync)(f, t, "utf8");
|
|
46303
46486
|
});
|
|
46304
46487
|
write(file, `${JSON.stringify([...new Set(paths)], null, 1)}
|
|
46305
46488
|
`);
|
|
@@ -46313,17 +46496,17 @@ function recordResidue(gitCommonDir, path2, deps = {}) {
|
|
|
46313
46496
|
writePaths(file, paths, deps);
|
|
46314
46497
|
}
|
|
46315
46498
|
async function sweepWorktreeResidue(gitCommonDir, registered, deps = {}) {
|
|
46316
|
-
const exists = deps.exists ??
|
|
46317
|
-
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));
|
|
46318
46501
|
const isDir = deps.isDir ?? ((p) => {
|
|
46319
46502
|
try {
|
|
46320
|
-
return (0,
|
|
46503
|
+
return (0, import_node_fs45.statSync)(p).isDirectory();
|
|
46321
46504
|
} catch {
|
|
46322
46505
|
return false;
|
|
46323
46506
|
}
|
|
46324
46507
|
});
|
|
46325
46508
|
const removeRecorded = deps.removeRecorded ?? ((p) => removeResidueDirectory(p));
|
|
46326
|
-
const removeEmpty = deps.removeEmpty ?? ((p) => (0,
|
|
46509
|
+
const removeEmpty = deps.removeEmpty ?? ((p) => (0, import_node_fs45.rmdirSync)(p));
|
|
46327
46510
|
const report = { swept: [], kept: [], dropped: [], emptyRemoved: [], unrecorded: [] };
|
|
46328
46511
|
const live = new Set(registered.map(norm));
|
|
46329
46512
|
const primary = registered[0] ? norm(registered[0]) : void 0;
|
|
@@ -46403,8 +46586,8 @@ function argvWantsJson2() {
|
|
|
46403
46586
|
function hubRoot() {
|
|
46404
46587
|
const fromPkg = (0, import_node_path44.join)(__dirname, "..", "..");
|
|
46405
46588
|
const marker = "skills/bootstrap/seeds/manifest.json";
|
|
46406
|
-
if ((0,
|
|
46407
|
-
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();
|
|
46408
46591
|
return null;
|
|
46409
46592
|
}
|
|
46410
46593
|
function ciAuditDeps() {
|
|
@@ -46417,7 +46600,7 @@ function ciAuditDeps() {
|
|
|
46417
46600
|
readSeedFile: (path2) => {
|
|
46418
46601
|
if (!root) return null;
|
|
46419
46602
|
const fullPath = (0, import_node_path44.join)(root, path2);
|
|
46420
|
-
return (0,
|
|
46603
|
+
return (0, import_node_fs46.existsSync)(fullPath) ? (0, import_node_fs46.readFileSync)(fullPath, "utf8") : null;
|
|
46421
46604
|
}
|
|
46422
46605
|
};
|
|
46423
46606
|
}
|
|
@@ -47181,10 +47364,10 @@ ${list}`);
|
|
|
47181
47364
|
});
|
|
47182
47365
|
async function listCiWorkflowPaths(cwd = process.cwd()) {
|
|
47183
47366
|
const wfDir = (0, import_node_path44.join)(cwd, ".github", "workflows");
|
|
47184
|
-
if (!(0,
|
|
47185
|
-
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) => {
|
|
47186
47369
|
try {
|
|
47187
|
-
return workflowReportsPrChecks((0,
|
|
47370
|
+
return workflowReportsPrChecks((0, import_node_fs46.readFileSync)((0, import_node_path44.join)(wfDir, name), "utf8"));
|
|
47188
47371
|
} catch {
|
|
47189
47372
|
return true;
|
|
47190
47373
|
}
|
|
@@ -47389,7 +47572,7 @@ ${list}`);
|
|
|
47389
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) => {
|
|
47390
47573
|
if (!isReviewVerdict(o.verdict)) return fail(`pr review-verdict: --verdict must be one of ${REVIEW_VERDICTS.join("|")} (got ${o.verdict})`);
|
|
47391
47574
|
const verdict = o.verdict;
|
|
47392
|
-
const findings = o.findingsFile ? (0,
|
|
47575
|
+
const findings = o.findingsFile ? (0, import_node_fs46.readFileSync)(o.findingsFile, "utf8") : void 0;
|
|
47393
47576
|
let patch;
|
|
47394
47577
|
let head;
|
|
47395
47578
|
try {
|
|
@@ -47645,7 +47828,7 @@ ${list}`);
|
|
|
47645
47828
|
const cleanupMerged = async (r) => {
|
|
47646
47829
|
if (opts.preserveWorktree) return "cleanup skipped (--preserve-worktree)";
|
|
47647
47830
|
const ran = await execFileP(process.execPath, [process.argv[1], ...canonicalArgvFor(["pr", "merge", r.pr, "--repo", r.repo])], {
|
|
47648
|
-
cwd: (0,
|
|
47831
|
+
cwd: (0, import_node_fs46.existsSync)(cwd0) ? cwd0 : primaryRoot0,
|
|
47649
47832
|
timeout: GH_MUTATION_TIMEOUT_MS * 3
|
|
47650
47833
|
}).then((x) => ({ stdout: x.stdout, stderr: x.stderr }), (e) => ({ stdout: e.stdout ?? "", stderr: e.stderr ?? "" }));
|
|
47651
47834
|
const json = ran.stdout.split("\n").reverse().find((l) => l.startsWith("{"));
|
|
@@ -47715,7 +47898,7 @@ ${list}`);
|
|
|
47715
47898
|
const mergeSquashBody = squashBodyTextForMerge(
|
|
47716
47899
|
closingGuardInput,
|
|
47717
47900
|
method === "--squash",
|
|
47718
|
-
o.squashBodyFile ? (0,
|
|
47901
|
+
o.squashBodyFile ? (0, import_node_fs46.readFileSync)(o.squashBodyFile, "utf8") : void 0
|
|
47719
47902
|
);
|
|
47720
47903
|
if (!o.squashBodyFile) warnSquashBodyClosingStrip("pr merge", closingGuardInput, mergeSquashBody);
|
|
47721
47904
|
const closingGuardVerdict = evaluateClosingGuard(closingGuardInput, {
|
|
@@ -47866,7 +48049,7 @@ ${list}`);
|
|
|
47866
48049
|
}
|
|
47867
48050
|
if (!repoForPostCleanup) throw e;
|
|
47868
48051
|
console.warn(`pr merge: gh GraphQL rate-limited \u2014 merging PR #${number} via REST PUT instead (#4588).`);
|
|
47869
|
-
const commitMessage = bodyFile ? (0,
|
|
48052
|
+
const commitMessage = bodyFile ? (0, import_node_fs46.readFileSync)(bodyFile, "utf8") : void 0;
|
|
47870
48053
|
await defaultGitHubClient().rest("PUT", `repos/${repoForPostCleanup}/pulls/${number}/merge`, {
|
|
47871
48054
|
body: { merge_method: method.slice(2), ...commitMessage ? { commit_message: commitMessage } : {} },
|
|
47872
48055
|
timeoutMs: GH_MUTATION_TIMEOUT_MS
|
|
@@ -47999,7 +48182,7 @@ ${list}`);
|
|
|
47999
48182
|
preserveWorktree: o.preserveWorktree,
|
|
48000
48183
|
gcAcknowledged: o.gc,
|
|
48001
48184
|
expectedHeadOid: headRefOid,
|
|
48002
|
-
pathExists: (p) => (0,
|
|
48185
|
+
pathExists: (p) => (0, import_node_fs46.existsSync)(p),
|
|
48003
48186
|
// #5899: pin cleanup git calls to the main checkout — the task worktree this process may be
|
|
48004
48187
|
// standing in is removed mid-cleanup, so a cwd-relative invocation fails with
|
|
48005
48188
|
// 'fatal: not a git repository' and leaves a spurious partial-cleanup exit.
|
|
@@ -49299,11 +49482,11 @@ function suiteTrainIo(root, summaryFile, memberSummaryFiles = {}, summaryFileTr,
|
|
|
49299
49482
|
const checkout = async (repo) => {
|
|
49300
49483
|
if (repo === SUITE_REPO) return root;
|
|
49301
49484
|
const target = (0, import_node_path46.join)(base, repo.split("/")[1]);
|
|
49302
|
-
if (!(0,
|
|
49303
|
-
(0,
|
|
49485
|
+
if (!(0, import_node_fs47.existsSync)(target)) {
|
|
49486
|
+
(0, import_node_fs47.mkdirSync)(base, { recursive: true });
|
|
49304
49487
|
await exec("git", ["clone", "--quiet", "--branch", "development", `https://github.com/${repo}.git`, target], root, WATCH_TIMEOUT);
|
|
49305
49488
|
}
|
|
49306
|
-
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`);
|
|
49307
49490
|
const origin = await exec("git", ["remote", "get-url", "origin"], target);
|
|
49308
49491
|
if (!origin.toLowerCase().endsWith(`/${repo.toLowerCase()}.git`) && !origin.toLowerCase().endsWith(`/${repo.toLowerCase()}`))
|
|
49309
49492
|
throw new Error(`${repo}: suite checkout origin mismatch at ${target}; stop`);
|
|
@@ -49610,9 +49793,9 @@ function suiteTrainIo(root, summaryFile, memberSummaryFiles = {}, summaryFileTr,
|
|
|
49610
49793
|
const body = await gh(["release", "view", leadTag, "--repo", SUITE_REPO, "--json", "body", "--jq", ".body"]);
|
|
49611
49794
|
if (parseSuiteMapping(body)) return;
|
|
49612
49795
|
const dir = suiteStateDir(root);
|
|
49613
|
-
(0,
|
|
49796
|
+
(0, import_node_fs47.mkdirSync)(dir, { recursive: true });
|
|
49614
49797
|
const file = (0, import_node_path46.join)(dir, `notes-${leadTag}.md`);
|
|
49615
|
-
(0,
|
|
49798
|
+
(0, import_node_fs47.writeFileSync)(file, `${body}
|
|
49616
49799
|
|
|
49617
49800
|
${suiteMappingBlock(leadTag, mapping)}`);
|
|
49618
49801
|
await gh(["release", "edit", leadTag, "--repo", SUITE_REPO, "--notes-file", file]);
|
|
@@ -49653,7 +49836,7 @@ ${suiteMappingBlock(leadTag, mapping)}`);
|
|
|
49653
49836
|
|
|
49654
49837
|
// src/suite-commands.ts
|
|
49655
49838
|
init_cli_shared();
|
|
49656
|
-
var
|
|
49839
|
+
var import_node_fs48 = require("node:fs");
|
|
49657
49840
|
function parseMemberSummaryFiles(entries) {
|
|
49658
49841
|
const memberSummaryFiles = {};
|
|
49659
49842
|
for (const entry of entries) {
|
|
@@ -49747,7 +49930,7 @@ function registerSuiteCommands(program3) {
|
|
|
49747
49930
|
try {
|
|
49748
49931
|
const io = suiteTrainIo(root);
|
|
49749
49932
|
retired = await retireFailedLeadRcLedger({ ledgerPath: releaseLedgerPath(root), rcHead: () => io.head(SUITE_REPO, "rc").then((h) => h ?? void 0), markAbandoned: io.markAbandoned }, o.ownerGo === true);
|
|
49750
|
-
if (retired && !(0,
|
|
49933
|
+
if (retired && !(0, import_node_fs48.existsSync)(io.recordPath)) {
|
|
49751
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)`);
|
|
49752
49935
|
return;
|
|
49753
49936
|
}
|
|
@@ -49936,7 +50119,7 @@ function suiteStatusDeps(github, registry2) {
|
|
|
49936
50119
|
|
|
49937
50120
|
// src/packages-adopt-export.ts
|
|
49938
50121
|
var import_node_child_process19 = require("node:child_process");
|
|
49939
|
-
var
|
|
50122
|
+
var import_node_fs49 = require("node:fs");
|
|
49940
50123
|
var import_node_os22 = require("node:os");
|
|
49941
50124
|
var import_node_path47 = require("node:path");
|
|
49942
50125
|
var import_node_util6 = require("node:util");
|
|
@@ -50560,36 +50743,36 @@ async function adoptExport(opts, deps) {
|
|
|
50560
50743
|
if (!/^sha256:[0-9a-f]{64}$/.test(opts.digest)) throw new Error("--digest must be sha256:<64 hex>, from the export run summary");
|
|
50561
50744
|
const packagePath = (0, import_node_path47.join)(opts.dir, "package.json");
|
|
50562
50745
|
const lockPath = (0, import_node_path47.join)(opts.dir, "package-lock.json");
|
|
50563
|
-
const packageText = (0,
|
|
50564
|
-
const lockText = (0,
|
|
50565
|
-
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-"));
|
|
50566
50749
|
try {
|
|
50567
50750
|
const run = JSON.parse((await deps.ghApi(`repos/${EXPORT_REPO}/actions/runs/${opts.run}`)).toString("utf8"));
|
|
50568
|
-
(0,
|
|
50569
|
-
(0,
|
|
50570
|
-
(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`));
|
|
50571
50754
|
const script = (0, import_node_path47.join)(work, "package_export.py");
|
|
50572
|
-
(0,
|
|
50755
|
+
(0, import_node_fs49.writeFileSync)(script, package_export_default);
|
|
50573
50756
|
await deps.python(script, ["verify", work, opts.ds, opts.screens]);
|
|
50574
50757
|
const verified = (0, import_node_path47.join)(work, "verified");
|
|
50575
|
-
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"))]));
|
|
50576
50759
|
const plan = planAdoption(packageText, lockText, metadata);
|
|
50577
50760
|
for (const { name } of plan.result.adopted) {
|
|
50578
50761
|
const short3 = PACKAGES.find((p) => p.name === name).short;
|
|
50579
50762
|
await deps.npm(["cache", "add", (0, import_node_path47.join)(verified, `${short3}.tgz`)], opts.dir);
|
|
50580
50763
|
}
|
|
50581
|
-
(0,
|
|
50582
|
-
(0,
|
|
50764
|
+
(0, import_node_fs49.writeFileSync)(packagePath, plan.packageText);
|
|
50765
|
+
(0, import_node_fs49.writeFileSync)(lockPath, plan.lockText);
|
|
50583
50766
|
try {
|
|
50584
50767
|
await deps.npm(["ci", "--offline", "--ignore-scripts", "--no-audit", "--no-fund"], opts.dir);
|
|
50585
50768
|
} catch (error) {
|
|
50586
|
-
(0,
|
|
50587
|
-
(0,
|
|
50769
|
+
(0, import_node_fs49.writeFileSync)(packagePath, packageText);
|
|
50770
|
+
(0, import_node_fs49.writeFileSync)(lockPath, lockText);
|
|
50588
50771
|
throw new Error(`npm ci --offline failed, package.json and package-lock.json restored: ${error.message}`);
|
|
50589
50772
|
}
|
|
50590
50773
|
return plan.result;
|
|
50591
50774
|
} finally {
|
|
50592
|
-
(0,
|
|
50775
|
+
(0, import_node_fs49.rmSync)(work, { recursive: true, force: true });
|
|
50593
50776
|
}
|
|
50594
50777
|
}
|
|
50595
50778
|
var execFileBuffer = (0, import_node_util6.promisify)(import_node_child_process19.execFile);
|
|
@@ -50654,12 +50837,12 @@ function registerPackagesCommands(program3) {
|
|
|
50654
50837
|
init_cli_shared();
|
|
50655
50838
|
|
|
50656
50839
|
// src/wave-status.ts
|
|
50657
|
-
var
|
|
50840
|
+
var import_node_fs50 = require("node:fs");
|
|
50658
50841
|
function readStageSummary(worktreePath) {
|
|
50659
50842
|
const statePath = stageStatePath(worktreePath);
|
|
50660
|
-
if (!(0,
|
|
50843
|
+
if (!(0, import_node_fs50.existsSync)(statePath)) return void 0;
|
|
50661
50844
|
try {
|
|
50662
|
-
const state = JSON.parse((0,
|
|
50845
|
+
const state = JSON.parse((0, import_node_fs50.readFileSync)(statePath, "utf8"));
|
|
50663
50846
|
const port = typeof state.port === "number" ? state.port : void 0;
|
|
50664
50847
|
if (port == null || !Number.isInteger(port) || port <= 0) return void 0;
|
|
50665
50848
|
return { port, url: typeof state.url === "string" ? state.url : void 0 };
|
|
@@ -50716,7 +50899,7 @@ async function collectWaveStatus(deps) {
|
|
|
50716
50899
|
// src/discovery-commands.ts
|
|
50717
50900
|
init_github_client();
|
|
50718
50901
|
init_cli_shared();
|
|
50719
|
-
var
|
|
50902
|
+
var import_node_fs51 = require("node:fs");
|
|
50720
50903
|
var import_node_os23 = require("node:os");
|
|
50721
50904
|
var import_node_path48 = require("node:path");
|
|
50722
50905
|
var GC_GH_TIMEOUT_MS3 = 2e4;
|
|
@@ -50909,8 +51092,8 @@ async function collectOnboardStatus(opts = {}) {
|
|
|
50909
51092
|
}
|
|
50910
51093
|
const home = (0, import_node_os23.homedir)();
|
|
50911
51094
|
const plugin = onboardPluginGate({
|
|
50912
|
-
readKnown: () => readFileSyncSafe((0, import_node_path48.join)(home, ...KNOWN_MARKETPLACES_RELATIVE),
|
|
50913
|
-
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)
|
|
50914
51097
|
});
|
|
50915
51098
|
return {
|
|
50916
51099
|
guide: "Read the MMI org-guide skill before project work; load only the relevant topic. Use mmi-help for a short introduction.",
|
|
@@ -53104,7 +53287,7 @@ function registerOrgHealthQuery(program3, deps = defaultOrgHealthQueryDeps()) {
|
|
|
53104
53287
|
}
|
|
53105
53288
|
|
|
53106
53289
|
// src/api-read.ts
|
|
53107
|
-
var
|
|
53290
|
+
var import_node_fs52 = require("node:fs");
|
|
53108
53291
|
|
|
53109
53292
|
// src/run-log-read.ts
|
|
53110
53293
|
init_cli_shared();
|
|
@@ -53705,7 +53888,7 @@ function registerApiReadCommands(program3, overrides) {
|
|
|
53705
53888
|
o.accept
|
|
53706
53889
|
);
|
|
53707
53890
|
if (zip) {
|
|
53708
|
-
(0,
|
|
53891
|
+
(0, import_node_fs52.writeFileSync)(o.out, body, "latin1");
|
|
53709
53892
|
return;
|
|
53710
53893
|
}
|
|
53711
53894
|
} catch (e) {
|
|
@@ -54580,7 +54763,7 @@ function registerSessionReport(program3) {
|
|
|
54580
54763
|
}
|
|
54581
54764
|
|
|
54582
54765
|
// src/stage-commands.ts
|
|
54583
|
-
var
|
|
54766
|
+
var import_node_fs53 = require("node:fs");
|
|
54584
54767
|
var import_node_path49 = require("node:path");
|
|
54585
54768
|
init_cli_shared();
|
|
54586
54769
|
init_clean_exit();
|
|
@@ -54829,8 +55012,8 @@ function registerStageCommands(program3) {
|
|
|
54829
55012
|
const repo = Array.isArray(project2?.repos) && typeof project2.repos[0] === "string" ? project2.repos[0] : slug;
|
|
54830
55013
|
const resolution = decideStage({
|
|
54831
55014
|
registry: { deployModel: project2?.deployModel, portRange, error: read.ok ? void 0 : read.error },
|
|
54832
|
-
hasCompose: (0,
|
|
54833
|
-
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")),
|
|
54834
55017
|
repo
|
|
54835
55018
|
});
|
|
54836
55019
|
if (resolution.source === "derived" && resolution.derived) {
|
|
@@ -55123,14 +55306,14 @@ vercel preview (${preview.branch}): ${d.state}${d.url ? ` \u2014 ${d.url}` : ""}
|
|
|
55123
55306
|
|
|
55124
55307
|
// src/tenant-artifact.ts
|
|
55125
55308
|
var import_node_crypto17 = require("node:crypto");
|
|
55126
|
-
var
|
|
55309
|
+
var import_node_fs54 = require("node:fs");
|
|
55127
55310
|
var import_promises11 = require("node:fs/promises");
|
|
55128
55311
|
var import_node_path50 = require("node:path");
|
|
55129
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}$/;
|
|
55130
55313
|
var MAX_BYTES2 = 5 * 1024 * 1024 * 1024;
|
|
55131
55314
|
async function sha256File(path2) {
|
|
55132
55315
|
const hash = (0, import_node_crypto17.createHash)("sha256");
|
|
55133
|
-
for await (const chunk of (0,
|
|
55316
|
+
for await (const chunk of (0, import_node_fs54.createReadStream)(path2)) hash.update(chunk);
|
|
55134
55317
|
return hash.digest("hex");
|
|
55135
55318
|
}
|
|
55136
55319
|
async function putTenantArtifact(repo, stage, inputPath, deps) {
|
|
@@ -55153,7 +55336,7 @@ async function putTenantArtifact(repo, stage, inputPath, deps) {
|
|
|
55153
55336
|
return [key, value];
|
|
55154
55337
|
}));
|
|
55155
55338
|
headers["content-length"] = String(info.size);
|
|
55156
|
-
const stream = (0,
|
|
55339
|
+
const stream = (0, import_node_fs54.createReadStream)(path2);
|
|
55157
55340
|
let uploaded;
|
|
55158
55341
|
try {
|
|
55159
55342
|
uploaded = await fetch(body.uploadUrl, {
|
|
@@ -55292,7 +55475,7 @@ function renderVerifySecrets(body) {
|
|
|
55292
55475
|
}
|
|
55293
55476
|
|
|
55294
55477
|
// src/command-register-developer.ts
|
|
55295
|
-
var
|
|
55478
|
+
var import_node_fs58 = require("node:fs");
|
|
55296
55479
|
init_clean_exit();
|
|
55297
55480
|
init_cli_shared();
|
|
55298
55481
|
init_error_codes();
|
|
@@ -55360,13 +55543,13 @@ async function executeWaveLand(plan, deps) {
|
|
|
55360
55543
|
// src/dist-drift.ts
|
|
55361
55544
|
var import_node_child_process20 = require("node:child_process");
|
|
55362
55545
|
var import_node_crypto19 = require("node:crypto");
|
|
55363
|
-
var
|
|
55546
|
+
var import_node_fs56 = require("node:fs");
|
|
55364
55547
|
var import_node_os24 = require("node:os");
|
|
55365
55548
|
var import_node_path52 = require("node:path");
|
|
55366
55549
|
|
|
55367
55550
|
// ../scripts/distribution-digest.mjs
|
|
55368
55551
|
var import_node_crypto18 = require("node:crypto");
|
|
55369
|
-
var
|
|
55552
|
+
var import_node_fs55 = require("node:fs");
|
|
55370
55553
|
var import_node_path51 = require("node:path");
|
|
55371
55554
|
var slash = (value) => value.replaceAll("\\", "/");
|
|
55372
55555
|
function repoPath(root, declaredPath, label) {
|
|
@@ -55380,7 +55563,7 @@ function repoPath(root, declaredPath, label) {
|
|
|
55380
55563
|
function digestFiles(files) {
|
|
55381
55564
|
const hash = (0, import_node_crypto18.createHash)("sha256");
|
|
55382
55565
|
for (const file of [...files].sort((a, b) => a.relative.localeCompare(b.relative))) {
|
|
55383
|
-
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);
|
|
55384
55567
|
hash.update(file.relative, "utf8");
|
|
55385
55568
|
hash.update("\0");
|
|
55386
55569
|
hash.update(file.stat.isSymbolicLink() ? "symlink" : "file", "utf8");
|
|
@@ -55395,8 +55578,8 @@ function digestFiles(files) {
|
|
|
55395
55578
|
function digestPackedFiles(packageRoot, packedFiles) {
|
|
55396
55579
|
return digestFiles(packedFiles.map((path2) => {
|
|
55397
55580
|
const absolute = repoPath(packageRoot, path2, "packed artifact identity path");
|
|
55398
|
-
if (!(0,
|
|
55399
|
-
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) };
|
|
55400
55583
|
}));
|
|
55401
55584
|
}
|
|
55402
55585
|
|
|
@@ -55481,12 +55664,12 @@ function renderDistDriftReceipt(receipt) {
|
|
|
55481
55664
|
return lines2;
|
|
55482
55665
|
}
|
|
55483
55666
|
function readOrNull(path2) {
|
|
55484
|
-
return (0,
|
|
55667
|
+
return (0, import_node_fs56.existsSync)(path2) ? (0, import_node_fs56.readFileSync)(path2) : null;
|
|
55485
55668
|
}
|
|
55486
55669
|
function walkFiles(root) {
|
|
55487
55670
|
const files = [];
|
|
55488
55671
|
const walk2 = (directory) => {
|
|
55489
|
-
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))) {
|
|
55490
55673
|
const child2 = (0, import_node_path52.join)(directory, entry.name);
|
|
55491
55674
|
if (entry.isDirectory()) walk2(child2);
|
|
55492
55675
|
else files.push(child2);
|
|
@@ -55497,7 +55680,7 @@ function walkFiles(root) {
|
|
|
55497
55680
|
}
|
|
55498
55681
|
function bomPathFor(root) {
|
|
55499
55682
|
try {
|
|
55500
|
-
const registry2 = JSON.parse((0,
|
|
55683
|
+
const registry2 = JSON.parse((0, import_node_fs56.readFileSync)((0, import_node_path52.join)(root, "surfaces.json"), "utf8"));
|
|
55501
55684
|
return (0, import_node_path52.join)(root, registry2?.sharedAgentCore?.releaseMetadata?.bomPath ?? "distribution-bom.json");
|
|
55502
55685
|
} catch {
|
|
55503
55686
|
return (0, import_node_path52.join)(root, "distribution-bom.json");
|
|
@@ -55513,7 +55696,7 @@ function rebuildTo(packageRoot, outDir) {
|
|
|
55513
55696
|
});
|
|
55514
55697
|
}
|
|
55515
55698
|
function runDistStatus(root) {
|
|
55516
|
-
const stage = (0,
|
|
55699
|
+
const stage = (0, import_node_fs56.mkdtempSync)((0, import_node_path52.join)((0, import_node_os24.tmpdir)(), "mmi-dist-drift-"));
|
|
55517
55700
|
let overlayCount = 0;
|
|
55518
55701
|
try {
|
|
55519
55702
|
const cliOut = (0, import_node_path52.join)(stage, "cli-dist");
|
|
@@ -55529,19 +55712,19 @@ function runDistStatus(root) {
|
|
|
55529
55712
|
const tree = (path2) => readOrNull((0, import_node_path52.join)(root, path2));
|
|
55530
55713
|
const distRoot = (0, import_node_path52.join)(root, "cli", "dist");
|
|
55531
55714
|
const distTree = () => walkFiles(distRoot).map((absolute) => `cli/dist/${(0, import_node_path52.relative)(distRoot, absolute).replaceAll("\\", "/")}`);
|
|
55532
|
-
const bom = JSON.parse((0,
|
|
55715
|
+
const bom = JSON.parse((0, import_node_fs56.readFileSync)(bomPathFor(root), "utf8"));
|
|
55533
55716
|
const digest = (entries) => {
|
|
55534
55717
|
const overlay = (0, import_node_path52.join)(stage, `overlay-${overlayCount++}`);
|
|
55535
55718
|
for (const entry of entries) {
|
|
55536
55719
|
const target = (0, import_node_path52.join)(overlay, entry.path);
|
|
55537
|
-
(0,
|
|
55538
|
-
(0,
|
|
55720
|
+
(0, import_node_fs56.mkdirSync)((0, import_node_path52.dirname)(target), { recursive: true });
|
|
55721
|
+
(0, import_node_fs56.writeFileSync)(target, entry.bytes);
|
|
55539
55722
|
}
|
|
55540
55723
|
return digestPackedFiles(overlay, entries.map((entry) => entry.path));
|
|
55541
55724
|
};
|
|
55542
55725
|
return computeDistDriftReceipt({ committed, tree, rebuilt, distTree, bom, digest });
|
|
55543
55726
|
} finally {
|
|
55544
|
-
(0,
|
|
55727
|
+
(0, import_node_fs56.rmSync)(stage, { recursive: true, force: true });
|
|
55545
55728
|
}
|
|
55546
55729
|
}
|
|
55547
55730
|
|
|
@@ -55871,7 +56054,7 @@ function registerSchedulesLiftCommand(program3, deps = {}) {
|
|
|
55871
56054
|
|
|
55872
56055
|
// src/spawn-policy-core.ts
|
|
55873
56056
|
var import_node_child_process22 = require("node:child_process");
|
|
55874
|
-
var
|
|
56057
|
+
var import_node_fs57 = require("node:fs");
|
|
55875
56058
|
var import_node_path55 = require("node:path");
|
|
55876
56059
|
var SPAWNERS = ["spawn", "spawnSync", "exec", "execSync", "execFile", "execFileSync"];
|
|
55877
56060
|
var CALL_SOURCE = String.raw`(^|[^.\w$])(${SPAWNERS.join("|")})\s*\(`;
|
|
@@ -55958,7 +56141,7 @@ function runSpawnPolicy(root) {
|
|
|
55958
56141
|
for (const file of files) {
|
|
55959
56142
|
let raw;
|
|
55960
56143
|
try {
|
|
55961
|
-
raw = (0,
|
|
56144
|
+
raw = (0, import_node_fs57.readFileSync)((0, import_node_path55.join)(root, file), "utf8");
|
|
55962
56145
|
} catch {
|
|
55963
56146
|
continue;
|
|
55964
56147
|
}
|
|
@@ -55979,18 +56162,18 @@ function registerDeveloperCommands(program3) {
|
|
|
55979
56162
|
const rules = program3.command("rules").description("org-managed .gitignore delivery");
|
|
55980
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) => {
|
|
55981
56164
|
const path2 = (0, import_node_path56.join)(process.cwd(), ".gitignore");
|
|
55982
|
-
const current = (0,
|
|
56165
|
+
const current = (0, import_node_fs58.existsSync)(path2) ? (0, import_node_fs58.readFileSync)(path2, "utf8") : null;
|
|
55983
56166
|
const plan = planManagedGitignore(current);
|
|
55984
56167
|
const drift = [...plan.added.map((l) => `+${l}`), ...plan.removed.map((l) => `-${l}`)].join(", ") || "block normalize";
|
|
55985
56168
|
if (opts.json) {
|
|
55986
|
-
if (opts.write && plan.changed) (0,
|
|
56169
|
+
if (opts.write && plan.changed) (0, import_node_fs58.writeFileSync)(path2, plan.content, "utf8");
|
|
55987
56170
|
console.log(JSON.stringify(plan, null, 2));
|
|
55988
56171
|
if (!opts.write && plan.changed) process.exitCode = 1;
|
|
55989
56172
|
return;
|
|
55990
56173
|
}
|
|
55991
56174
|
if (opts.write) {
|
|
55992
56175
|
if (plan.changed) {
|
|
55993
|
-
(0,
|
|
56176
|
+
(0, import_node_fs58.writeFileSync)(path2, plan.content, "utf8");
|
|
55994
56177
|
console.log(`mmi-cli devops org rules gitignore: updated .gitignore (${drift})`);
|
|
55995
56178
|
} else {
|
|
55996
56179
|
console.log("mmi-cli devops org rules gitignore: up to date");
|
|
@@ -56199,17 +56382,18 @@ function registerDeveloperCommands(program3) {
|
|
|
56199
56382
|
}
|
|
56200
56383
|
});
|
|
56201
56384
|
const tests = program3.command("tests").description("a repo's test-policy.json \u2014 the opt-in test contract and its enforcement");
|
|
56202
|
-
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) => {
|
|
56203
56386
|
try {
|
|
56204
56387
|
if (o.repo) {
|
|
56205
|
-
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" : ""}`;
|
|
56206
56389
|
const guard = planTrainApplyRepoGuard(o.repo, await resolveRepo(), rerun, "tests policy");
|
|
56207
56390
|
if (!guard.ok) return failGraceful(guard.message);
|
|
56208
56391
|
}
|
|
56209
56392
|
const root = await repoRoot();
|
|
56210
56393
|
const result = runTestPolicy(root, { base: o.base, policyRef: o.policyRef });
|
|
56211
56394
|
if (o.json) {
|
|
56212
|
-
|
|
56395
|
+
const { ok, testCommandsAllowed, commandClasses, findings } = result;
|
|
56396
|
+
consoleIo.log(o.verbose ? JSON.stringify(result, null, 2) : JSON.stringify({ ok, testCommandsAllowed, commandClasses, findings }));
|
|
56213
56397
|
if (!result.ok) process.exitCode = 1;
|
|
56214
56398
|
return;
|
|
56215
56399
|
}
|
|
@@ -56407,7 +56591,7 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
56407
56591
|
);
|
|
56408
56592
|
const result = applyPluginCachePlan(
|
|
56409
56593
|
plan,
|
|
56410
|
-
(p) => (0,
|
|
56594
|
+
(p) => (0, import_node_fs59.rmSync)(p, { recursive: true }),
|
|
56411
56595
|
stagingApplyFsGuard(configRoot)
|
|
56412
56596
|
);
|
|
56413
56597
|
return {
|
|
@@ -56442,7 +56626,7 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
56442
56626
|
// has no generated routing index would
|
|
56443
56627
|
// get a permanent — demanding an artifact it never asked for.
|
|
56444
56628
|
docsIndexState: (root) => {
|
|
56445
|
-
if (!(0,
|
|
56629
|
+
if (!(0, import_node_fs59.existsSync)((0, import_node_path57.join)(root, DOCS_INDEX_PATH))) return void 0;
|
|
56446
56630
|
const real = createDocsIndexDeps(root);
|
|
56447
56631
|
let docs;
|
|
56448
56632
|
const listDocs = () => docs ??= real.listDocs();
|
|
@@ -56451,7 +56635,7 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
56451
56635
|
},
|
|
56452
56636
|
// #4168: working-tree heal — write if drifted, then re-check. Commit remains the operator's step.
|
|
56453
56637
|
healDocsIndex: (root) => {
|
|
56454
|
-
if (!(0,
|
|
56638
|
+
if (!(0, import_node_fs59.existsSync)((0, import_node_path57.join)(root, DOCS_INDEX_PATH))) return { drift: false, docCount: 0 };
|
|
56455
56639
|
const real = createDocsIndexDeps(root);
|
|
56456
56640
|
let docs;
|
|
56457
56641
|
const listDocs = () => docs ??= real.listDocs();
|
|
@@ -56811,6 +56995,7 @@ function appActorDeps() {
|
|
|
56811
56995
|
};
|
|
56812
56996
|
}
|
|
56813
56997
|
setPollTokenProvider(async () => activeAppToken() ?? pollTokenOrUndefined(appActorDeps()));
|
|
56998
|
+
setGhReadTokenProvider(pollToken);
|
|
56814
56999
|
setStatusWriteTokenProvider(() => mintStatusWriteToken(appActorDeps()));
|
|
56815
57000
|
var registerPreAction = Reflect.get(program2, ["h", "ook"].join(""));
|
|
56816
57001
|
registerPreAction.call(program2, "preAction", async (_thisCommand, actionCommand) => {
|
|
@@ -56818,7 +57003,7 @@ registerPreAction.call(program2, "preAction", async (_thisCommand, actionCommand
|
|
|
56818
57003
|
appActorCommand = commandPath3;
|
|
56819
57004
|
emitCliCallTelemetry(commandPath3);
|
|
56820
57005
|
try {
|
|
56821
|
-
await activateAppActor(commandPath3, process.env, () => mintInstallationToken(appActorDeps()));
|
|
57006
|
+
await activateAppActor(commandPath3, process.env, () => APP_WRITE_COMMANDS.has(commandPath3) ? mintCommandWriteToken(appActorDeps(), commandPath3) : mintInstallationToken(appActorDeps()));
|
|
56822
57007
|
} catch (e) {
|
|
56823
57008
|
if (e instanceof AppActorError) return fail(e.message);
|
|
56824
57009
|
throw e;
|
|
@@ -57176,7 +57361,7 @@ project.command("set [owner/repo]").description("upsert project META (idempotent
|
|
|
57176
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`);
|
|
57177
57362
|
if (o.secretsFile) {
|
|
57178
57363
|
try {
|
|
57179
|
-
vars.push(`secrets=${(0,
|
|
57364
|
+
vars.push(`secrets=${(0, import_node_fs59.readFileSync)(o.secretsFile, "utf8")}`);
|
|
57180
57365
|
} catch (e) {
|
|
57181
57366
|
return fail(`org project set: cannot read --secrets-file ${o.secretsFile}: ${e.message}`);
|
|
57182
57367
|
}
|
|
@@ -57568,15 +57753,15 @@ function ciAuditDeps2() {
|
|
|
57568
57753
|
readSeedFile: (path2) => {
|
|
57569
57754
|
if (!root) return null;
|
|
57570
57755
|
const fullPath = (0, import_node_path57.join)(root, path2);
|
|
57571
|
-
return (0,
|
|
57756
|
+
return (0, import_node_fs59.existsSync)(fullPath) ? (0, import_node_fs59.readFileSync)(fullPath, "utf8") : null;
|
|
57572
57757
|
}
|
|
57573
57758
|
};
|
|
57574
57759
|
}
|
|
57575
57760
|
function hubRoot2() {
|
|
57576
57761
|
const fromPkg = (0, import_node_path57.join)(__dirname, "..", "..");
|
|
57577
57762
|
const marker = "skills/bootstrap/seeds/manifest.json";
|
|
57578
|
-
if ((0,
|
|
57579
|
-
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();
|
|
57580
57765
|
return null;
|
|
57581
57766
|
}
|
|
57582
57767
|
registerQueryCommands(program2);
|
|
@@ -57590,6 +57775,7 @@ registerDiscoveryCommands(program2);
|
|
|
57590
57775
|
registerExplainCommand(program2);
|
|
57591
57776
|
registerPrLifecycleCommands(program2);
|
|
57592
57777
|
registerApiReadCommands(program2);
|
|
57778
|
+
registerGithubBudgetCommand(program2, appActorDeps);
|
|
57593
57779
|
registerAppReadBrokerCommands(program2, async (repo) => requireRepo(repo));
|
|
57594
57780
|
var prBrokerRoot = program2.commands.find((c) => c.name() === "pr");
|
|
57595
57781
|
if (!prBrokerRoot) throw new Error("read broker: pr root must be registered before pr checks-required");
|
|
@@ -57706,10 +57892,10 @@ access.command("audit").description("audit collaborator roles + train-branch pus
|
|
|
57706
57892
|
targets = resolution.targets;
|
|
57707
57893
|
}
|
|
57708
57894
|
const derivedMatrix = registryProjects ? accessMatrixFromProjects(registryProjects) : {};
|
|
57709
|
-
const fileMatrix = (0,
|
|
57895
|
+
const fileMatrix = (0, import_node_fs59.existsSync)("access-matrix.json") ? loadAccessMatrix((0, import_node_fs59.readFileSync)("access-matrix.json", "utf8")) : {};
|
|
57710
57896
|
const matrix = mergeAccessMatrix(fileMatrix, derivedMatrix);
|
|
57711
57897
|
const dataAccess = registryProjects ? dataAccessContractsFromProjects(registryProjects) : { consumers: {} };
|
|
57712
|
-
const sanctioned = (0,
|
|
57898
|
+
const sanctioned = (0, import_node_fs59.existsSync)("access-matrix.json") ? loadSanctionedAdmins((0, import_node_fs59.readFileSync)("access-matrix.json", "utf8")) : {};
|
|
57713
57899
|
const report = await auditOrgAccess(targets, deps, matrix, dataAccess, sanctioned);
|
|
57714
57900
|
console.log(o.json ? JSON.stringify(report, null, 2) : renderAccessReport(report));
|
|
57715
57901
|
if (!report.ok) process.exitCode = 1;
|
|
@@ -57740,7 +57926,7 @@ function directoryBytes(path2) {
|
|
|
57740
57926
|
let total = 0;
|
|
57741
57927
|
let entries;
|
|
57742
57928
|
try {
|
|
57743
|
-
entries = (0,
|
|
57929
|
+
entries = (0, import_node_fs59.readdirSync)(path2, { withFileTypes: true });
|
|
57744
57930
|
} catch {
|
|
57745
57931
|
return 0;
|
|
57746
57932
|
}
|
|
@@ -57749,7 +57935,7 @@ function directoryBytes(path2) {
|
|
|
57749
57935
|
if (entry.isDirectory()) total += directoryBytes(child2);
|
|
57750
57936
|
else {
|
|
57751
57937
|
try {
|
|
57752
|
-
total += (0,
|
|
57938
|
+
total += (0, import_node_fs59.statSync)(child2).size;
|
|
57753
57939
|
} catch {
|
|
57754
57940
|
}
|
|
57755
57941
|
}
|
|
@@ -57757,25 +57943,25 @@ function directoryBytes(path2) {
|
|
|
57757
57943
|
return total;
|
|
57758
57944
|
}
|
|
57759
57945
|
function listDirEntries(dir) {
|
|
57760
|
-
return (0,
|
|
57946
|
+
return (0, import_node_fs59.readdirSync)(dir, { withFileTypes: true }).map((d) => ({ name: d.name, isDirectory: d.isDirectory() }));
|
|
57761
57947
|
}
|
|
57762
57948
|
function readInstalledPluginRefs(configRoot) {
|
|
57763
57949
|
const p = installedPluginsPathForConfig(configRoot);
|
|
57764
|
-
if (!(0,
|
|
57950
|
+
if (!(0, import_node_fs59.existsSync)(p)) return [];
|
|
57765
57951
|
try {
|
|
57766
|
-
return installedPluginPaths((0,
|
|
57952
|
+
return installedPluginPaths((0, import_node_fs59.readFileSync)(p, "utf8"));
|
|
57767
57953
|
} catch {
|
|
57768
57954
|
return null;
|
|
57769
57955
|
}
|
|
57770
57956
|
}
|
|
57771
57957
|
function pluginCacheFsDeps(configRoot, dirBytes) {
|
|
57772
57958
|
return {
|
|
57773
|
-
exists: (p) => (0,
|
|
57774
|
-
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),
|
|
57775
57961
|
dirBytes,
|
|
57776
|
-
listStagingDirs: (root) => (0,
|
|
57962
|
+
listStagingDirs: (root) => (0, import_node_fs59.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => {
|
|
57777
57963
|
try {
|
|
57778
|
-
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) };
|
|
57779
57965
|
} catch {
|
|
57780
57966
|
return { name: d.name, mtimeMs: Date.now() };
|
|
57781
57967
|
}
|
|
@@ -57790,9 +57976,9 @@ function stagingApplyFsGuard(configRoot) {
|
|
|
57790
57976
|
referencedPaths: () => readInstalledPluginRefs(configRoot),
|
|
57791
57977
|
mtimeMs: (name) => {
|
|
57792
57978
|
const p = (0, import_node_path57.join)(stagingRoot, name);
|
|
57793
|
-
if (!(0,
|
|
57979
|
+
if (!(0, import_node_fs59.existsSync)(p)) return null;
|
|
57794
57980
|
try {
|
|
57795
|
-
return newestMtimeMs(p, listDirEntries, (q) => (0,
|
|
57981
|
+
return newestMtimeMs(p, listDirEntries, (q) => (0, import_node_fs59.statSync)(q).mtimeMs);
|
|
57796
57982
|
} catch {
|
|
57797
57983
|
return null;
|
|
57798
57984
|
}
|
|
@@ -57818,7 +58004,7 @@ program2.command("plugin-prune").description(`prune stale cached MMI plugin vers
|
|
|
57818
58004
|
{ withBytes: true, configRoot, includeStaging: surface !== "codex" }
|
|
57819
58005
|
);
|
|
57820
58006
|
const anythingToDelete = plan.prune.length > 0 || plan.staging.length > 0;
|
|
57821
|
-
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;
|
|
57822
58008
|
const warnings = plan.prune.length > 0 ? [CONCURRENT_SESSION_WARNING] : [];
|
|
57823
58009
|
if (o.json) console.log(JSON.stringify({ ...plan, warnings, applied: result ?? null }));
|
|
57824
58010
|
else console.log(renderPluginCachePlan(plan, result));
|