@mutmutco/claude-plugin 4.5.159 → 4.5.161
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/.claude-plugin/plugin.json +1 -1
- package/cli/dist/main.cjs +540 -381
- package/cli/package.json +1 -1
- package/package.json +1 -1
- package/skills/board/SKILL.md +1 -1
- package/skills/bootstrap/SKILL.md +1 -1
- package/skills/epic/SKILL.md +1 -1
- package/skills/hotfix/SKILL.md +1 -1
- package/skills/mmi-help/SKILL.md +1 -1
- package/skills/org-guide/SKILL.md +1 -1
- package/skills/org-guide/references/work-and-releases.md +2 -0
- package/skills/rcand/SKILL.md +1 -1
- package/skills/release/SKILL.md +2 -16
- package/skills/release/recovery.md +22 -0
- package/skills/secrets/SKILL.md +1 -1
- package/skills/stage/SKILL.md +1 -1
package/cli/dist/main.cjs
CHANGED
|
@@ -589,6 +589,54 @@ var init_github_client = __esm({
|
|
|
589
589
|
}
|
|
590
590
|
});
|
|
591
591
|
|
|
592
|
+
// src/gh-read-route.ts
|
|
593
|
+
function isViewerFreeGhRead(args) {
|
|
594
|
+
if (args.some((a) => VIEWER.test(a))) return false;
|
|
595
|
+
const [group, verb] = args;
|
|
596
|
+
if (group === "api") return isReadOnlyApi(args.slice(1));
|
|
597
|
+
return Boolean(group && verb && READ_VERBS.get(group)?.has(verb));
|
|
598
|
+
}
|
|
599
|
+
function isReadOnlyApi(rest) {
|
|
600
|
+
let path2;
|
|
601
|
+
for (let i = 0; i < rest.length; i++) {
|
|
602
|
+
const a = rest[i];
|
|
603
|
+
if (a === "-X" || a === "--method") {
|
|
604
|
+
if ((rest[i + 1] ?? "").toUpperCase() !== "GET") return false;
|
|
605
|
+
i++;
|
|
606
|
+
} else if (/^--method=/.test(a)) {
|
|
607
|
+
if (a.slice(9).toUpperCase() !== "GET") return false;
|
|
608
|
+
} else if (a === "-f" || a === "-F" || a === "--field" || a === "--raw-field") {
|
|
609
|
+
const field = rest[i + 1] ?? "";
|
|
610
|
+
if (path2 !== "graphql" || !/^query=\s*(query\b|\{)/.test(field) || /projectV2|projectsV2/.test(field)) return false;
|
|
611
|
+
i++;
|
|
612
|
+
} else if (a === "--input" || a.startsWith("--input=")) {
|
|
613
|
+
return false;
|
|
614
|
+
} else if (a === "-H" || a === "--header" || a === "-q" || a === "--jq" || a === "-t" || a === "--template" || a === "--hostname" || a === "--cache") {
|
|
615
|
+
i++;
|
|
616
|
+
} else if (!a.startsWith("-") && path2 === void 0) {
|
|
617
|
+
path2 = a.replace(/^\//, "");
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
if (!path2) return false;
|
|
621
|
+
if (path2 === "graphql") return rest.some((a) => /^query=\s*(query\b|\{)/.test(a));
|
|
622
|
+
return !/^(user|users\/[^/]+\/|notifications|search\/|orgs\/[^/]+\/projectsV2|graphql)/.test(path2);
|
|
623
|
+
}
|
|
624
|
+
var READ_VERBS, VIEWER;
|
|
625
|
+
var init_gh_read_route = __esm({
|
|
626
|
+
"src/gh-read-route.ts"() {
|
|
627
|
+
"use strict";
|
|
628
|
+
READ_VERBS = /* @__PURE__ */ new Map([
|
|
629
|
+
["pr", /* @__PURE__ */ new Set(["view", "list", "checks", "diff"])],
|
|
630
|
+
["issue", /* @__PURE__ */ new Set(["view", "list"])],
|
|
631
|
+
["run", /* @__PURE__ */ new Set(["view", "list", "watch"])],
|
|
632
|
+
["label", /* @__PURE__ */ new Set(["list"])],
|
|
633
|
+
["release", /* @__PURE__ */ new Set(["view", "list"])],
|
|
634
|
+
["repo", /* @__PURE__ */ new Set(["view"])]
|
|
635
|
+
]);
|
|
636
|
+
VIEWER = /@me\b|viewer|project/i;
|
|
637
|
+
}
|
|
638
|
+
});
|
|
639
|
+
|
|
592
640
|
// src/github-quota.ts
|
|
593
641
|
function hubQuotaResetWaitMs(resetAt, nowMs, capMs = RATE_LIMIT_WAIT_CAP_MS, jitterMs = 0) {
|
|
594
642
|
if (typeof resetAt !== "string" || !resetAt) return void 0;
|
|
@@ -959,6 +1007,8 @@ var init_house_map = __esm({
|
|
|
959
1007
|
pr: "devops",
|
|
960
1008
|
read: "devops",
|
|
961
1009
|
// closed typed GitHub reads on the App pool (run/pr/issue broker, #8042)
|
|
1010
|
+
github: "devops",
|
|
1011
|
+
// personal and App allowance visibility
|
|
962
1012
|
api: "devops",
|
|
963
1013
|
// allowlisted GitHub REST GET reads for automation (pull files, compare, contents)
|
|
964
1014
|
ci: "devops",
|
|
@@ -1110,8 +1160,18 @@ __export(cli_shared_exports, {
|
|
|
1110
1160
|
rawValue: () => rawValue,
|
|
1111
1161
|
readStdin: () => readStdin,
|
|
1112
1162
|
repoProject: () => repoProject,
|
|
1163
|
+
setGhReadTokenProvider: () => setGhReadTokenProvider,
|
|
1113
1164
|
setInjectedStdin: () => setInjectedStdin
|
|
1114
1165
|
});
|
|
1166
|
+
function setGhReadTokenProvider(provider) {
|
|
1167
|
+
ghReadTokenProvider = provider;
|
|
1168
|
+
}
|
|
1169
|
+
async function ghReadAppEnv(file, args) {
|
|
1170
|
+
if (!ghReadTokenProvider || !/(^|[\\/])gh(\.exe)?$/i.test(file) || process.env.MMI_ACTOR?.trim() === "personal") return void 0;
|
|
1171
|
+
if (!isViewerFreeGhRead(args)) return void 0;
|
|
1172
|
+
const token = await ghReadTokenProvider().catch(() => void 0);
|
|
1173
|
+
return token ? { ...process.env, GH_TOKEN: token } : void 0;
|
|
1174
|
+
}
|
|
1115
1175
|
function killProcessTree(pid) {
|
|
1116
1176
|
try {
|
|
1117
1177
|
if (process.platform === "win32") {
|
|
@@ -1280,7 +1340,7 @@ function printLine(value) {
|
|
|
1280
1340
|
(0, import_node_fs5.writeSync)(1, `${value}
|
|
1281
1341
|
`);
|
|
1282
1342
|
}
|
|
1283
|
-
var import_node_child_process2, import_node_fs5, import_node_util3, rawExecFileP, DEFAULT_EXEC_TIMEOUT_MS, execFileP, GIT_TIMEOUT_MS, ExecDeadlineError, cachedGithubLogin, gitOut, consoleIo;
|
|
1343
|
+
var import_node_child_process2, import_node_fs5, import_node_util3, rawExecFileP, DEFAULT_EXEC_TIMEOUT_MS, execFileP, ghReadTokenProvider, GIT_TIMEOUT_MS, ExecDeadlineError, cachedGithubLogin, gitOut, consoleIo;
|
|
1284
1344
|
var init_cli_shared = __esm({
|
|
1285
1345
|
"src/cli-shared.ts"() {
|
|
1286
1346
|
"use strict";
|
|
@@ -1292,16 +1352,27 @@ var init_cli_shared = __esm({
|
|
|
1292
1352
|
init_clean_exit();
|
|
1293
1353
|
init_error_codes();
|
|
1294
1354
|
init_github_client();
|
|
1355
|
+
init_gh_read_route();
|
|
1295
1356
|
init_hub_auth();
|
|
1296
1357
|
init_house_map();
|
|
1297
1358
|
init_stdin_inject();
|
|
1298
1359
|
rawExecFileP = (0, import_node_util3.promisify)(import_node_child_process2.execFile);
|
|
1299
1360
|
DEFAULT_EXEC_TIMEOUT_MS = 1e4;
|
|
1300
|
-
execFileP = (file, args, options = {}) =>
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1361
|
+
execFileP = async (file, args, options = {}) => {
|
|
1362
|
+
const run = (env) => (
|
|
1363
|
+
// encoding 'utf8' guarantees string stdout/stderr at runtime; the cast pins the type because
|
|
1364
|
+
// promisify(execFile)'s overloads widen to string|Buffer when options is spread in.
|
|
1365
|
+
rawExecFileP(file, args, { encoding: "utf8", windowsHide: true, timeout: DEFAULT_EXEC_TIMEOUT_MS, killSignal: "SIGTERM", ...options, ...env ? { env } : {} })
|
|
1366
|
+
);
|
|
1367
|
+
const appEnv = options.env ? void 0 : await ghReadAppEnv(file, args);
|
|
1368
|
+
if (!appEnv) return run();
|
|
1369
|
+
try {
|
|
1370
|
+
return await run(appEnv);
|
|
1371
|
+
} catch (e) {
|
|
1372
|
+
if (/Resource not accessible by integration/i.test(String(e.stderr ?? ""))) return run();
|
|
1373
|
+
throw e;
|
|
1374
|
+
}
|
|
1375
|
+
};
|
|
1305
1376
|
GIT_TIMEOUT_MS = DEFAULT_EXEC_TIMEOUT_MS;
|
|
1306
1377
|
ExecDeadlineError = class extends Error {
|
|
1307
1378
|
constructor(step, timeoutMs, elapsedMs, killed) {
|
|
@@ -4755,7 +4826,7 @@ function useColor() {
|
|
|
4755
4826
|
var program = new Command();
|
|
4756
4827
|
|
|
4757
4828
|
// src/command-composition.ts
|
|
4758
|
-
var
|
|
4829
|
+
var import_node_fs59 = require("node:fs");
|
|
4759
4830
|
init_clean_exit();
|
|
4760
4831
|
init_cli_shared();
|
|
4761
4832
|
|
|
@@ -6949,7 +7020,7 @@ var import_node_os25 = require("node:os");
|
|
|
6949
7020
|
var import_node_path57 = require("node:path");
|
|
6950
7021
|
|
|
6951
7022
|
// src/board-read.ts
|
|
6952
|
-
var
|
|
7023
|
+
var import_node_fs17 = require("node:fs");
|
|
6953
7024
|
var import_node_os10 = require("node:os");
|
|
6954
7025
|
var import_node_path14 = require("node:path");
|
|
6955
7026
|
init_cli_shared();
|
|
@@ -7167,6 +7238,19 @@ async function readAppVaultSecret(read) {
|
|
|
7167
7238
|
async function mintInstallationToken(deps) {
|
|
7168
7239
|
return mintScopedInstallationToken(deps, APP_POLL_PERMISSIONS);
|
|
7169
7240
|
}
|
|
7241
|
+
var APP_WRITE_COMMANDS = /* @__PURE__ */ new Map([
|
|
7242
|
+
["issue comment", { metadata: "read", issues: "write", pull_requests: "write" }]
|
|
7243
|
+
]);
|
|
7244
|
+
async function mintCommandWriteToken(deps, commandPath3) {
|
|
7245
|
+
const permissions = APP_WRITE_COMMANDS.get(commandPath3);
|
|
7246
|
+
if (!permissions) throw new AppActorError(`app actor: '${commandPath3}' has no App write profile`);
|
|
7247
|
+
try {
|
|
7248
|
+
return await mintFromMember(deps, permissions, APP_VAULT_KEYS);
|
|
7249
|
+
} catch (e) {
|
|
7250
|
+
if (e instanceof AppActorError) throw e;
|
|
7251
|
+
throw new AppActorError(`app actor: write token mint failed (${e?.constructor?.name ?? "Error"})`);
|
|
7252
|
+
}
|
|
7253
|
+
}
|
|
7170
7254
|
async function mintStatusWriteToken(deps) {
|
|
7171
7255
|
return mintScopedInstallationToken(deps, { metadata: "read", statuses: "write" });
|
|
7172
7256
|
}
|
|
@@ -7227,6 +7311,9 @@ async function allowanceSpent(deps, token) {
|
|
|
7227
7311
|
return false;
|
|
7228
7312
|
}
|
|
7229
7313
|
}
|
|
7314
|
+
function mintBudgetToken(deps, keys) {
|
|
7315
|
+
return mintFromMember(deps, { metadata: "read" }, keys);
|
|
7316
|
+
}
|
|
7230
7317
|
async function mintFromMember(deps, permissions, keys) {
|
|
7231
7318
|
const [appId, installationId, privateKey] = await Promise.all(keys.map((k) => deps.fetchSecret(k)));
|
|
7232
7319
|
if (!appId || !installationId || !privateKey) {
|
|
@@ -7294,7 +7381,7 @@ async function activateAppActor(commandPath3, env, mint, note = (line) => proces
|
|
|
7294
7381
|
if (requested && requested !== "app") {
|
|
7295
7382
|
throw new AppActorError(`app actor: unknown ${APP_ACTOR_ENV} value \u2014 only 'app' and 'personal' are supported; refusing to guess an identity`);
|
|
7296
7383
|
}
|
|
7297
|
-
if (!APP_ELIGIBLE_COMMANDS.has(commandPath3)) {
|
|
7384
|
+
if (!APP_ELIGIBLE_COMMANDS.has(commandPath3) && !APP_WRITE_COMMANDS.has(commandPath3)) {
|
|
7298
7385
|
if (requested === "app" && !notedIneligibleCommand) {
|
|
7299
7386
|
notedIneligibleCommand = true;
|
|
7300
7387
|
note(`app actor: '${commandPath3}' is personal-only (viewer/@me/authorship) \u2014 running on the personal token despite ${APP_ACTOR_ENV}=app`);
|
|
@@ -10225,7 +10312,7 @@ init_github_client();
|
|
|
10225
10312
|
// src/project-model.ts
|
|
10226
10313
|
var PROJECT_TYPES = ["web-app", "hub-service", "content", "desktop-app", "desktop-game", "mobile-app", "non-deployable", "cli-tool", "worker"];
|
|
10227
10314
|
var DEPLOY_MODELS = ["hub-serverless", "serverless", "tenant-container", "solo-container", "static-cdn", "registry-publish", "content", "none", "vercel"];
|
|
10228
|
-
var RELEASE_TRACKS = ["full", "direct", "trunk"];
|
|
10315
|
+
var RELEASE_TRACKS = ["full", "direct", "trunk", "single"];
|
|
10229
10316
|
var REQUIRED_CHECK_BRANCHES = ["development", "rc", "main"];
|
|
10230
10317
|
var PROJECT_TYPE_SET = new Set(PROJECT_TYPES);
|
|
10231
10318
|
var DEPLOY_MODEL_SET = new Set(DEPLOY_MODELS);
|
|
@@ -10308,6 +10395,7 @@ function metaWithDeclaredClass(meta, declaredClass) {
|
|
|
10308
10395
|
}
|
|
10309
10396
|
function branchesForTrack(track) {
|
|
10310
10397
|
if (track === "trunk") return ["main"];
|
|
10398
|
+
if (track === "single") return ["development"];
|
|
10311
10399
|
if (track === "direct") return ["development", "main"];
|
|
10312
10400
|
return ["development", "rc", "main"];
|
|
10313
10401
|
}
|
|
@@ -10319,7 +10407,7 @@ function resolveRequiredCheckBranches(meta, repo) {
|
|
|
10319
10407
|
return branchesForTrack(resolveReleaseTrack(meta, void 0, repo));
|
|
10320
10408
|
}
|
|
10321
10409
|
function promotionBranchesForTrack(track) {
|
|
10322
|
-
if (track === "trunk") return [];
|
|
10410
|
+
if (track === "trunk" || track === "single") return [];
|
|
10323
10411
|
if (track === "direct") return ["main"];
|
|
10324
10412
|
return ["rc", "main"];
|
|
10325
10413
|
}
|
|
@@ -11301,6 +11389,7 @@ init_clean_exit();
|
|
|
11301
11389
|
|
|
11302
11390
|
// src/gh-create.ts
|
|
11303
11391
|
var import_promises = require("node:fs/promises");
|
|
11392
|
+
var import_node_fs16 = require("node:fs");
|
|
11304
11393
|
var import_node_os8 = require("node:os");
|
|
11305
11394
|
var import_node_path13 = require("node:path");
|
|
11306
11395
|
var import_node_crypto7 = require("node:crypto");
|
|
@@ -11566,18 +11655,23 @@ async function preflightPrCreateRemoteHead(args, deps) {
|
|
|
11566
11655
|
if (compared !== "unknown" && compared.aheadBy <= 0) return emptyCompareMessage(base, head);
|
|
11567
11656
|
return void 0;
|
|
11568
11657
|
}
|
|
11658
|
+
function retryBodyFile(args) {
|
|
11659
|
+
const file = flagValue(args, "--body-file");
|
|
11660
|
+
if (file !== void 0) return file;
|
|
11661
|
+
const body = flagValue(args, "--body");
|
|
11662
|
+
if (body === void 0) return void 0;
|
|
11663
|
+
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");
|
|
11664
|
+
(0, import_node_fs16.writeFileSync)(path2, body, "utf8");
|
|
11665
|
+
return path2;
|
|
11666
|
+
}
|
|
11569
11667
|
function buildPrCreateRetryCommand(args) {
|
|
11570
11668
|
const parts = ["mmi-cli", "devops", "pr", "create"];
|
|
11571
11669
|
for (const flag of ["--repo", "--base", "--head", "--title"]) {
|
|
11572
11670
|
const v = flagValue(args, flag);
|
|
11573
11671
|
if (v !== void 0) parts.push(flag, shellQuote(v));
|
|
11574
11672
|
}
|
|
11575
|
-
const bodyFile =
|
|
11673
|
+
const bodyFile = retryBodyFile(args);
|
|
11576
11674
|
if (bodyFile !== void 0) parts.push("--body-file", shellQuote(bodyFile));
|
|
11577
|
-
else {
|
|
11578
|
-
const body = flagValue(args, "--body");
|
|
11579
|
-
if (body !== void 0) parts.push("--body", shellQuote(body));
|
|
11580
|
-
}
|
|
11581
11675
|
if (args.includes("--draft")) parts.push("--draft");
|
|
11582
11676
|
return parts.join(" ");
|
|
11583
11677
|
}
|
|
@@ -11600,12 +11694,8 @@ function buildIssueCreateRetryCommand(args) {
|
|
|
11600
11694
|
if (type) parts.push("--type", type);
|
|
11601
11695
|
const title = flagValue(args, "--title");
|
|
11602
11696
|
if (title !== void 0) parts.push("--title", shellQuote(title));
|
|
11603
|
-
const bodyFile =
|
|
11697
|
+
const bodyFile = retryBodyFile(args);
|
|
11604
11698
|
if (bodyFile !== void 0) parts.push("--body-file", shellQuote(bodyFile));
|
|
11605
|
-
else {
|
|
11606
|
-
const body = flagValue(args, "--body");
|
|
11607
|
-
if (body !== void 0) parts.push("--body", shellQuote(body));
|
|
11608
|
-
}
|
|
11609
11699
|
for (const label of labels) {
|
|
11610
11700
|
if (label === type) continue;
|
|
11611
11701
|
parts.push("--label", shellQuote(label));
|
|
@@ -14562,11 +14652,11 @@ function probeLocalClaimSession(marker, now = Date.now()) {
|
|
|
14562
14652
|
const pending = [root];
|
|
14563
14653
|
while (pending.length) {
|
|
14564
14654
|
const dir = pending.pop();
|
|
14565
|
-
for (const entry of (0,
|
|
14655
|
+
for (const entry of (0, import_node_fs17.readdirSync)(dir, { withFileTypes: true })) {
|
|
14566
14656
|
const path2 = (0, import_node_path14.join)(dir, entry.name);
|
|
14567
14657
|
if (entry.isDirectory()) pending.push(path2);
|
|
14568
14658
|
else if (entry.isFile() && entry.name.toLowerCase() === wanted) {
|
|
14569
|
-
return remember(now - (0,
|
|
14659
|
+
return remember(now - (0, import_node_fs17.statSync)(path2).mtimeMs <= CLAIM_SESSION_ACTIVITY_MS ? "live" : "dead");
|
|
14570
14660
|
}
|
|
14571
14661
|
}
|
|
14572
14662
|
}
|
|
@@ -16071,12 +16161,12 @@ function planManagedGitignore(current) {
|
|
|
16071
16161
|
}
|
|
16072
16162
|
|
|
16073
16163
|
// src/docs-index-command.ts
|
|
16074
|
-
var
|
|
16164
|
+
var import_node_fs19 = require("node:fs");
|
|
16075
16165
|
var import_node_path16 = require("node:path");
|
|
16076
16166
|
|
|
16077
16167
|
// src/doc-refs-core.ts
|
|
16078
16168
|
var import_node_child_process6 = require("node:child_process");
|
|
16079
|
-
var
|
|
16169
|
+
var import_node_fs18 = require("node:fs");
|
|
16080
16170
|
var import_node_path15 = require("node:path");
|
|
16081
16171
|
var PIN_RE = /<!--\s*pinned by\s+([^:]+?)\s*:\s*"([^"]+)"[^"]*-->/;
|
|
16082
16172
|
var PIN_MENTION_RE = /<!--\s*pinned by\b/;
|
|
@@ -16449,12 +16539,12 @@ function checkSeedRunbookReview(root, base, readFile10, git3) {
|
|
|
16449
16539
|
return findings;
|
|
16450
16540
|
}
|
|
16451
16541
|
function readFileOrNull(path2) {
|
|
16452
|
-
return (0,
|
|
16542
|
+
return (0, import_node_fs18.existsSync)(path2) ? (0, import_node_fs18.readFileSync)(path2, "utf8") : null;
|
|
16453
16543
|
}
|
|
16454
16544
|
function walk(dir, root, out) {
|
|
16455
|
-
for (const entry of (0,
|
|
16545
|
+
for (const entry of (0, import_node_fs18.readdirSync)(dir)) {
|
|
16456
16546
|
const full = (0, import_node_path15.join)(dir, entry);
|
|
16457
|
-
if ((0,
|
|
16547
|
+
if ((0, import_node_fs18.statSync)(full).isDirectory()) walk(full, root, out);
|
|
16458
16548
|
else if (entry.endsWith(".md")) out.push(full.slice(root.length + 1).replaceAll("\\", "/"));
|
|
16459
16549
|
}
|
|
16460
16550
|
return out;
|
|
@@ -16462,11 +16552,11 @@ function walk(dir, root, out) {
|
|
|
16462
16552
|
function defaultListDocs(root) {
|
|
16463
16553
|
const docs = ["docs", "skills/org-guide", "skills/mmi-help"].flatMap((path2) => {
|
|
16464
16554
|
const directory = (0, import_node_path15.join)(root, path2);
|
|
16465
|
-
return (0,
|
|
16555
|
+
return (0, import_node_fs18.existsSync)(directory) ? walk(directory, root, []) : [];
|
|
16466
16556
|
}).filter(
|
|
16467
16557
|
(rel) => !SKIP_WALK.some((skip) => rel.startsWith(skip))
|
|
16468
16558
|
);
|
|
16469
|
-
return [...ROOT_DOCS.filter((rel) => (0,
|
|
16559
|
+
return [...ROOT_DOCS.filter((rel) => (0, import_node_fs18.existsSync)((0, import_node_path15.join)(root, rel))), ...docs];
|
|
16470
16560
|
}
|
|
16471
16561
|
var CHECK_IGNORE_MAX_BUFFER = 32 * 1024 * 1024;
|
|
16472
16562
|
function defaultIsIgnored(root, relPaths, exec3 = import_node_child_process6.execFileSync) {
|
|
@@ -16547,7 +16637,7 @@ function mergeGroupRunbookMessages(root, deps, readFile10, warnings) {
|
|
|
16547
16637
|
}
|
|
16548
16638
|
function runDocRefs(root, deps = {}) {
|
|
16549
16639
|
const readFile10 = deps.readFile ?? readFileOrNull;
|
|
16550
|
-
const exists = deps.exists ??
|
|
16640
|
+
const exists = deps.exists ?? import_node_fs18.existsSync;
|
|
16551
16641
|
const listDocs = deps.listDocs ?? defaultListDocs;
|
|
16552
16642
|
const isIgnored = deps.isIgnored ?? ((paths) => defaultIsIgnored(root, paths));
|
|
16553
16643
|
const trackedFirstSegments = deps.trackedFirstSegments ?? ((segs) => defaultTrackedFirstSegments(root, segs));
|
|
@@ -16680,7 +16770,7 @@ function walkMarkdown(dir) {
|
|
|
16680
16770
|
const stack = [dir];
|
|
16681
16771
|
while (stack.length) {
|
|
16682
16772
|
const current = stack.pop();
|
|
16683
|
-
for (const entry of (0,
|
|
16773
|
+
for (const entry of (0, import_node_fs19.readdirSync)(current, { withFileTypes: true })) {
|
|
16684
16774
|
const full = (0, import_node_path16.join)(current, entry.name);
|
|
16685
16775
|
if (entry.isDirectory()) {
|
|
16686
16776
|
stack.push(full);
|
|
@@ -16696,15 +16786,15 @@ function createDocsIndexDeps(repoRoot2) {
|
|
|
16696
16786
|
const indexPath = (0, import_node_path16.join)(repoRoot2, DOCS_INDEX_PATH);
|
|
16697
16787
|
return {
|
|
16698
16788
|
listDocs: () => {
|
|
16699
|
-
if (!(0,
|
|
16789
|
+
if (!(0, import_node_fs19.existsSync)(docsDir)) return [];
|
|
16700
16790
|
const walked = walkMarkdown(docsDir).filter(isRoutableDocsPath);
|
|
16701
16791
|
if (!walked.length) return [];
|
|
16702
16792
|
const ignored = defaultIsIgnored(repoRoot2, walked.map((rel) => `docs/${rel}`));
|
|
16703
16793
|
return walked.filter((rel) => !ignored.has(`docs/${rel}`)).sort();
|
|
16704
16794
|
},
|
|
16705
|
-
readDoc: (relPath) => (0,
|
|
16706
|
-
readIndex: () => (0,
|
|
16707
|
-
writeIndex: (content) => (0,
|
|
16795
|
+
readDoc: (relPath) => (0, import_node_fs19.readFileSync)((0, import_node_path16.join)(docsDir, relPath), "utf8"),
|
|
16796
|
+
readIndex: () => (0, import_node_fs19.existsSync)(indexPath) ? (0, import_node_fs19.readFileSync)(indexPath, "utf8") : null,
|
|
16797
|
+
writeIndex: (content) => (0, import_node_fs19.writeFileSync)(indexPath, content, "utf8")
|
|
16708
16798
|
};
|
|
16709
16799
|
}
|
|
16710
16800
|
|
|
@@ -17093,7 +17183,7 @@ function gateSeedVars(cls, releaseTrack, runtime = "node", requiredCheckBranches
|
|
|
17093
17183
|
GATE_EXTRA_STEPS_YAML: ""
|
|
17094
17184
|
};
|
|
17095
17185
|
const track = releaseTrack ?? (cls === "content" ? "trunk" : "full");
|
|
17096
|
-
const trackBranches = track === "trunk" ? ["main"] : track === "direct" ? ["development", "main"] : ["development", "rc", "main"];
|
|
17186
|
+
const trackBranches = track === "trunk" ? ["main"] : track === "single" ? ["development"] : track === "direct" ? ["development", "main"] : ["development", "rc", "main"];
|
|
17097
17187
|
const rulesetBranches = requiredCheckBranches?.length ? [...requiredCheckBranches] : trackBranches;
|
|
17098
17188
|
const rulesetRefs = JSON.stringify(rulesetBranches.map((branch) => `refs/heads/${branch}`));
|
|
17099
17189
|
const rulesetContexts = JSON.stringify((requiredChecks?.length ? requiredChecks : ["gate"]).map((context) => ({ context })));
|
|
@@ -17106,6 +17196,15 @@ function gateSeedVars(cls, releaseTrack, runtime = "node", requiredCheckBranches
|
|
|
17106
17196
|
GATE_RULESET_CONTEXTS_JSON: rulesetContexts
|
|
17107
17197
|
};
|
|
17108
17198
|
}
|
|
17199
|
+
if (track === "single") {
|
|
17200
|
+
return {
|
|
17201
|
+
...runtimeVars,
|
|
17202
|
+
GATE_PUSH_BRANCHES_YAML: "[development]",
|
|
17203
|
+
GATE_FULL_RUN_BRANCH: "development",
|
|
17204
|
+
GATE_RULESET_BRANCH_REFS_JSON: rulesetRefs,
|
|
17205
|
+
GATE_RULESET_CONTEXTS_JSON: rulesetContexts
|
|
17206
|
+
};
|
|
17207
|
+
}
|
|
17109
17208
|
if (track === "direct") {
|
|
17110
17209
|
return {
|
|
17111
17210
|
...runtimeVars,
|
|
@@ -17430,7 +17529,7 @@ function buildRegisterPayload(repo, cls, vars, options = {}) {
|
|
|
17430
17529
|
throw new Error(`deployModel must be one of: ${DEPLOY_MODELS.join(", ")}`);
|
|
17431
17530
|
}
|
|
17432
17531
|
if (options.releaseTrack && !isReleaseTrack(options.releaseTrack)) {
|
|
17433
|
-
throw new Error("releaseTrack must be full, direct, or
|
|
17532
|
+
throw new Error("releaseTrack must be full, direct, trunk, or single");
|
|
17434
17533
|
}
|
|
17435
17534
|
const shape = {
|
|
17436
17535
|
class: cls,
|
|
@@ -17623,7 +17722,7 @@ function contentPutInputArgs(repo, path2, inputFile) {
|
|
|
17623
17722
|
}
|
|
17624
17723
|
|
|
17625
17724
|
// src/train-apply-contracts.ts
|
|
17626
|
-
var
|
|
17725
|
+
var import_node_fs20 = require("node:fs");
|
|
17627
17726
|
var import_node_path17 = require("node:path");
|
|
17628
17727
|
function reduceFollowUpOutcomes(outcomes) {
|
|
17629
17728
|
if (outcomes.includes("failure")) return "failure";
|
|
@@ -17704,7 +17803,7 @@ async function resolveFoldPaths(deps, model) {
|
|
|
17704
17803
|
if (model === "vercel") return [];
|
|
17705
17804
|
const helper = "scripts/release-distribution.mjs";
|
|
17706
17805
|
if (model === "hub-serverless" || model === "registry-publish") {
|
|
17707
|
-
if ((0,
|
|
17806
|
+
if ((0, import_node_fs20.existsSync)(helper)) {
|
|
17708
17807
|
let out;
|
|
17709
17808
|
try {
|
|
17710
17809
|
out = await deps.run("node", [helper, "changed-files"]);
|
|
@@ -17853,7 +17952,7 @@ async function restoreMainNpmPackIdentities(deps, version) {
|
|
|
17853
17952
|
if (mainBom.version !== version) return void 0;
|
|
17854
17953
|
let localBom;
|
|
17855
17954
|
try {
|
|
17856
|
-
localBom = JSON.parse((0,
|
|
17955
|
+
localBom = JSON.parse((0, import_node_fs20.readFileSync)(bomPath, "utf8"));
|
|
17857
17956
|
} catch (e) {
|
|
17858
17957
|
throw new Error(
|
|
17859
17958
|
`version fold refused: ${bomPath} written by this fold's prepare is unreadable (${describeReadError(e)}) \u2014 cannot restore the published ${version} npm-pack identities from origin/main (#4503/#4713).`
|
|
@@ -17871,14 +17970,14 @@ async function restoreMainNpmPackIdentities(deps, version) {
|
|
|
17871
17970
|
restored += 1;
|
|
17872
17971
|
}
|
|
17873
17972
|
if (restored === 0) return void 0;
|
|
17874
|
-
(0,
|
|
17973
|
+
(0, import_node_fs20.writeFileSync)(bomPath, `${JSON.stringify(localBom, null, 2)}
|
|
17875
17974
|
`);
|
|
17876
17975
|
return `restored ${restored} npm-pack BOM identit${restored === 1 ? "y" : "ies"} from origin/main (#4503)`;
|
|
17877
17976
|
}
|
|
17878
17977
|
function publishVisibilityFor(surfaceId) {
|
|
17879
17978
|
let raw;
|
|
17880
17979
|
try {
|
|
17881
|
-
raw = (0,
|
|
17980
|
+
raw = (0, import_node_fs20.readFileSync)("surfaces.json", "utf8");
|
|
17882
17981
|
} catch (e) {
|
|
17883
17982
|
if (e.code === "ENOENT") return "unknown";
|
|
17884
17983
|
throw trainReadFailure(
|
|
@@ -17899,7 +17998,7 @@ function publishVisibilityFor(surfaceId) {
|
|
|
17899
17998
|
}
|
|
17900
17999
|
function npmPackArtifactName(packagePath) {
|
|
17901
18000
|
try {
|
|
17902
|
-
const pkg = JSON.parse((0,
|
|
18001
|
+
const pkg = JSON.parse((0, import_node_fs20.readFileSync)((0, import_node_path17.join)(packagePath, "package.json"), "utf8"));
|
|
17903
18002
|
return pkg.name || void 0;
|
|
17904
18003
|
} catch {
|
|
17905
18004
|
return void 0;
|
|
@@ -17908,7 +18007,7 @@ function npmPackArtifactName(packagePath) {
|
|
|
17908
18007
|
async function refuseDivergentPublishedNpmPack(deps, version) {
|
|
17909
18008
|
let localBom;
|
|
17910
18009
|
try {
|
|
17911
|
-
localBom = JSON.parse((0,
|
|
18010
|
+
localBom = JSON.parse((0, import_node_fs20.readFileSync)("distribution-bom.json", "utf8"));
|
|
17912
18011
|
} catch (e) {
|
|
17913
18012
|
throw new Error(
|
|
17914
18013
|
`version fold refused: distribution-bom.json written by this fold's prepare is unreadable (${e instanceof Error ? e.message.split("\n")[0] : String(e)}) \u2014 cannot compare the same-PATCH ${version} npm-pack identities against published npm (#4503/#4662).`
|
|
@@ -18053,7 +18152,7 @@ function assertGitBashOnWindowsForJervHubRelease(repo, platform2 = process.platf
|
|
|
18053
18152
|
}
|
|
18054
18153
|
|
|
18055
18154
|
// src/train-apply-correlation.ts
|
|
18056
|
-
var
|
|
18155
|
+
var import_node_fs22 = require("node:fs");
|
|
18057
18156
|
init_github_quota();
|
|
18058
18157
|
var import_node_path19 = require("node:path");
|
|
18059
18158
|
|
|
@@ -18558,7 +18657,7 @@ function classifyRow(row) {
|
|
|
18558
18657
|
} else if (row.onboarding.status === "unknown") {
|
|
18559
18658
|
reasons.add(`canonical onboarding link evidence unknown: ${row.onboarding.detail}`);
|
|
18560
18659
|
}
|
|
18561
|
-
const releaseRequired = row.track !== "trunk" && !row.classifications.includes("no-deploy-surface");
|
|
18660
|
+
const releaseRequired = row.track !== "trunk" && row.track !== "single" && !row.classifications.includes("no-deploy-surface");
|
|
18562
18661
|
const tagIsVersion = Boolean(row.release.version) && row.unknowns.some((u) => u.startsWith(NO_VERSION_LOCK_PREFIX));
|
|
18563
18662
|
for (const unknown of row.unknowns) {
|
|
18564
18663
|
if (!releaseRequired && unknown === NO_RELEASE_UNKNOWN) continue;
|
|
@@ -18820,10 +18919,10 @@ var rollout_plan_default = {
|
|
|
18820
18919
|
note: "The v4.0.0 stamp happens at cut time (D6e #4463); until then the candidate is the origin/development head artifacts (built cli/dist + npm pack), identity proven by dist content hash (D6a)."
|
|
18821
18920
|
},
|
|
18822
18921
|
baseline: {
|
|
18823
|
-
version: "4.5.
|
|
18824
|
-
tag: "v4.5.
|
|
18825
|
-
commit: "
|
|
18826
|
-
npm: "@mutmutco/cli@4.5.
|
|
18922
|
+
version: "4.5.161",
|
|
18923
|
+
tag: "v4.5.161",
|
|
18924
|
+
commit: "236dbfae4af2",
|
|
18925
|
+
npm: "@mutmutco/cli@4.5.161"
|
|
18827
18926
|
},
|
|
18828
18927
|
exitCriterion: "fleet-n-of-n",
|
|
18829
18928
|
hubOnlyShortcut: "forbidden",
|
|
@@ -18840,14 +18939,14 @@ var rollout_plan_default = {
|
|
|
18840
18939
|
repo: "mutmutco/mmi-hub",
|
|
18841
18940
|
role: "canary",
|
|
18842
18941
|
schedule: "train",
|
|
18843
|
-
v3Target: "v4.5.
|
|
18942
|
+
v3Target: "v4.5.161"
|
|
18844
18943
|
}
|
|
18845
18944
|
],
|
|
18846
18945
|
rollbackTrigger: "Any red inside the post-contract soak window: `devops train gate` FAIL attributable to the v4 doors, Hub endpoint health probe failure, a pre-v4 client admitted instead of receiving actionable HTTP 426, or npm consumer install/doctor failure on the v4-only dist.",
|
|
18847
18946
|
rollback: {
|
|
18848
18947
|
independent: true,
|
|
18849
|
-
mechanism: "npm dist-tag latest -> 4.5.
|
|
18850
|
-
v3Target: "v4.5.
|
|
18948
|
+
mechanism: "npm dist-tag latest -> 4.5.161 and redeploy the Hub Lambda from tag v4.5.161 (236dbfae4af2); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
|
|
18949
|
+
v3Target: "v4.5.161 (@mutmutco/cli@4.5.161, tag commit 236dbfae4af2 \u2014 last known-good release carrying the repo-index v4-only contract)"
|
|
18851
18950
|
}
|
|
18852
18951
|
},
|
|
18853
18952
|
{
|
|
@@ -19181,13 +19280,13 @@ function resolveIssueViewGhFields(normalized) {
|
|
|
19181
19280
|
}
|
|
19182
19281
|
|
|
19183
19282
|
// src/utf8-receipt.ts
|
|
19184
|
-
var
|
|
19283
|
+
var import_node_fs21 = require("node:fs");
|
|
19185
19284
|
var import_node_path18 = require("node:path");
|
|
19186
19285
|
function writeUtf8Receipt(path2, text) {
|
|
19187
|
-
(0,
|
|
19286
|
+
(0, import_node_fs21.mkdirSync)((0, import_node_path18.dirname)(path2), { recursive: true });
|
|
19188
19287
|
const body = text.endsWith("\n") ? text : `${text}
|
|
19189
19288
|
`;
|
|
19190
|
-
(0,
|
|
19289
|
+
(0, import_node_fs21.writeFileSync)(path2, body, "utf8");
|
|
19191
19290
|
return Buffer.byteLength(body, "utf8");
|
|
19192
19291
|
}
|
|
19193
19292
|
|
|
@@ -20138,7 +20237,7 @@ function buildFleetTrackInventory(projects, releaseProbes, pluginProbes, generat
|
|
|
20138
20237
|
unknowns
|
|
20139
20238
|
};
|
|
20140
20239
|
});
|
|
20141
|
-
const tracks = { full: 0, direct: 0, trunk: 0 };
|
|
20240
|
+
const tracks = { full: 0, direct: 0, trunk: 0, single: 0 };
|
|
20142
20241
|
for (const row of repos) tracks[row.track] += 1;
|
|
20143
20242
|
return {
|
|
20144
20243
|
generatedAt,
|
|
@@ -20331,13 +20430,13 @@ var FLEET_LOCKSTEP_REF_INCLUDE = ["refs/heads/rc", "refs/heads/main"];
|
|
|
20331
20430
|
var STATUS_DESCRIPTION_MAX = 140;
|
|
20332
20431
|
function classifyFleetEnrollment(rows) {
|
|
20333
20432
|
return rows.map((row) => {
|
|
20334
|
-
if (row.track === "trunk") {
|
|
20433
|
+
if (row.track === "trunk" || row.track === "single") {
|
|
20335
20434
|
return {
|
|
20336
20435
|
repo: row.repo,
|
|
20337
20436
|
track: row.track,
|
|
20338
20437
|
deployModel: row.deployModel,
|
|
20339
20438
|
enrolled: false,
|
|
20340
|
-
reason: "excluded: trunk track has no release train \u2014 no rc/main surface exists to gate (declared shape, not an exemption from conformance: the fleet verdict still counts this repo)"
|
|
20439
|
+
reason: "excluded: trunk/single track has no release train \u2014 no rc/main surface exists to gate (declared shape, not an exemption from conformance: the fleet verdict still counts this repo)"
|
|
20341
20440
|
};
|
|
20342
20441
|
}
|
|
20343
20442
|
const noDeploy = row.classifications.includes("no-deploy-surface");
|
|
@@ -21073,7 +21172,7 @@ function resolveReleaseAbortNpmPackage(meta, repo) {
|
|
|
21073
21172
|
if (isHubControlRepo(repo)) return "@mutmutco/cli";
|
|
21074
21173
|
const publishDir = typeof meta.publishDir === "string" && meta.publishDir.trim() ? meta.publishDir.trim() : ".";
|
|
21075
21174
|
try {
|
|
21076
|
-
const pkg = JSON.parse((0,
|
|
21175
|
+
const pkg = JSON.parse((0, import_node_fs22.readFileSync)((0, import_node_path19.join)(publishDir, "package.json"), "utf8"));
|
|
21077
21176
|
const name = pkg.name?.trim();
|
|
21078
21177
|
if (!name) throw new Error("missing name field");
|
|
21079
21178
|
return name;
|
|
@@ -22009,7 +22108,7 @@ function parseVerifyBroker(stdout) {
|
|
|
22009
22108
|
}
|
|
22010
22109
|
|
|
22011
22110
|
// src/train-apply-deploy.ts
|
|
22012
|
-
var
|
|
22111
|
+
var import_node_fs23 = require("node:fs");
|
|
22013
22112
|
var import_node_os11 = require("node:os");
|
|
22014
22113
|
var import_node_path20 = require("node:path");
|
|
22015
22114
|
|
|
@@ -22150,7 +22249,7 @@ function mmiGetRedeployCommand(repo) {
|
|
|
22150
22249
|
}
|
|
22151
22250
|
function readLocalLauncherVersion(root = process.cwd()) {
|
|
22152
22251
|
try {
|
|
22153
|
-
const raw = (0,
|
|
22252
|
+
const raw = (0, import_node_fs23.readFileSync)((0, import_node_path20.join)(root, "cli", "package.json"), "utf8");
|
|
22154
22253
|
const version = JSON.parse(raw).version;
|
|
22155
22254
|
return typeof version === "string" && version.trim() ? version.trim() : null;
|
|
22156
22255
|
} catch {
|
|
@@ -22159,7 +22258,7 @@ function readLocalLauncherVersion(root = process.cwd()) {
|
|
|
22159
22258
|
}
|
|
22160
22259
|
function readServedChannelUrl(product = HUB_SERVED_PRODUCT, root = process.cwd()) {
|
|
22161
22260
|
try {
|
|
22162
|
-
const raw = (0,
|
|
22261
|
+
const raw = (0, import_node_fs23.readFileSync)((0, import_node_path20.join)(root, "config", `product.${product}.json`), "utf8");
|
|
22163
22262
|
const host = JSON.parse(raw).host;
|
|
22164
22263
|
if (typeof host !== "string" || !host.trim()) return null;
|
|
22165
22264
|
return `${host.trim().replace(/\/+$/, "")}/release/version`;
|
|
@@ -22593,13 +22692,13 @@ async function runTaggedJervGatewayLocalWrapper(deps, tag, tagSha) {
|
|
|
22593
22692
|
const reason = error instanceof Error ? error.message : String(error);
|
|
22594
22693
|
throw new Error(`could not extract ${JERV_GATEWAY_RELEASE_DEPLOY_SCRIPT} from tagged commit ${tagSha.slice(0, 12)}: ${reason}`);
|
|
22595
22694
|
}
|
|
22596
|
-
const dir = (0,
|
|
22695
|
+
const dir = (0, import_node_fs23.mkdtempSync)((0, import_node_path20.join)((0, import_node_os11.tmpdir)(), "jerv-gateway-release-deploy-"));
|
|
22597
22696
|
const extracted = (0, import_node_path20.join)(dir, "jerv-gateway-release-deploy.sh");
|
|
22598
22697
|
try {
|
|
22599
|
-
(0,
|
|
22698
|
+
(0, import_node_fs23.writeFileSync)(extracted, script, "utf8");
|
|
22600
22699
|
return await deps.run("bash", [extracted, "--tag", tag]);
|
|
22601
22700
|
} finally {
|
|
22602
|
-
(0,
|
|
22701
|
+
(0, import_node_fs23.rmSync)(dir, { recursive: true, force: true });
|
|
22603
22702
|
}
|
|
22604
22703
|
}
|
|
22605
22704
|
async function appendJervGatewayReleaseDeploy(deps, repo, tag, tagSha, dispatch) {
|
|
@@ -23175,7 +23274,7 @@ function renderTenantControl(r) {
|
|
|
23175
23274
|
}
|
|
23176
23275
|
|
|
23177
23276
|
// src/train-apply-phases.ts
|
|
23178
|
-
var
|
|
23277
|
+
var import_node_fs29 = require("node:fs");
|
|
23179
23278
|
var import_promises4 = require("node:fs/promises");
|
|
23180
23279
|
var import_node_path27 = require("node:path");
|
|
23181
23280
|
|
|
@@ -23494,12 +23593,12 @@ function assertPreOneZero(repo, meta, tag) {
|
|
|
23494
23593
|
|
|
23495
23594
|
// src/train-doctor.ts
|
|
23496
23595
|
var import_node_child_process9 = require("node:child_process");
|
|
23497
|
-
var
|
|
23596
|
+
var import_node_fs27 = require("node:fs");
|
|
23498
23597
|
var import_node_os15 = require("node:os");
|
|
23499
23598
|
var import_node_path26 = require("node:path");
|
|
23500
23599
|
|
|
23501
23600
|
// src/doctor-io.ts
|
|
23502
|
-
var
|
|
23601
|
+
var import_node_fs24 = require("node:fs");
|
|
23503
23602
|
var import_node_os12 = require("node:os");
|
|
23504
23603
|
var import_node_path21 = require("node:path");
|
|
23505
23604
|
var import_node_child_process7 = require("node:child_process");
|
|
@@ -23514,8 +23613,8 @@ function nodeDiscardSinkPath(platform2 = process.platform) {
|
|
|
23514
23613
|
var execFileP2 = (0, import_node_util4.promisify)(import_node_child_process7.execFile);
|
|
23515
23614
|
function execFileCapture(file, args, opts = {}) {
|
|
23516
23615
|
const sink = nodeDiscardSinkPath();
|
|
23517
|
-
const inFd = (0,
|
|
23518
|
-
const errFd = (0,
|
|
23616
|
+
const inFd = (0, import_node_fs24.openSync)(sink, "r");
|
|
23617
|
+
const errFd = (0, import_node_fs24.openSync)(sink, "w");
|
|
23519
23618
|
try {
|
|
23520
23619
|
return (0, import_node_child_process7.execFileSync)(file, args, {
|
|
23521
23620
|
...opts,
|
|
@@ -23523,17 +23622,17 @@ function execFileCapture(file, args, opts = {}) {
|
|
|
23523
23622
|
stdio: [inFd, "pipe", errFd]
|
|
23524
23623
|
});
|
|
23525
23624
|
} finally {
|
|
23526
|
-
(0,
|
|
23527
|
-
(0,
|
|
23625
|
+
(0, import_node_fs24.closeSync)(inFd);
|
|
23626
|
+
(0, import_node_fs24.closeSync)(errFd);
|
|
23528
23627
|
}
|
|
23529
23628
|
}
|
|
23530
23629
|
var MMI_PLUGIN_ID2 = "mmi@mutmutco";
|
|
23531
23630
|
function stagedClaudePluginVersion() {
|
|
23532
23631
|
try {
|
|
23533
23632
|
const stagingRoot = (0, import_node_path21.join)((0, import_node_os12.homedir)(), ".claude", "plugins", "staging");
|
|
23534
|
-
const record = JSON.parse((0,
|
|
23633
|
+
const record = JSON.parse((0, import_node_fs24.readFileSync)((0, import_node_path21.join)(stagingRoot, "launch-target.json"), "utf8"));
|
|
23535
23634
|
if (typeof record.target !== "string" || typeof record.incoming !== "string") return void 0;
|
|
23536
|
-
const manifest = JSON.parse((0,
|
|
23635
|
+
const manifest = JSON.parse((0, import_node_fs24.readFileSync)((0, import_node_path21.join)(record.incoming, ".claude-plugin", "plugin.json"), "utf8"));
|
|
23537
23636
|
if (typeof manifest.version !== "string") return void 0;
|
|
23538
23637
|
return manifest.version === record.target ? record.target : void 0;
|
|
23539
23638
|
} catch {
|
|
@@ -23543,7 +23642,7 @@ function stagedClaudePluginVersion() {
|
|
|
23543
23642
|
function installedClaudePluginVersion() {
|
|
23544
23643
|
try {
|
|
23545
23644
|
const file = JSON.parse(
|
|
23546
|
-
(0,
|
|
23645
|
+
(0, import_node_fs24.readFileSync)((0, import_node_path21.join)((0, import_node_os12.homedir)(), ".claude", "plugins", "installed_plugins.json"), "utf8")
|
|
23547
23646
|
);
|
|
23548
23647
|
const versions = (file.plugins?.[MMI_PLUGIN_ID2] ?? []).map((r) => r.version).filter((v) => Boolean(v));
|
|
23549
23648
|
if (versions.length === 0) return void 0;
|
|
@@ -23555,12 +23654,12 @@ function installedClaudePluginVersion() {
|
|
|
23555
23654
|
function readHermesPluginEvidence(env = process.env) {
|
|
23556
23655
|
const host = hermesConfigRoot(env);
|
|
23557
23656
|
const root = hermesPluginRoot(env);
|
|
23558
|
-
const installRecordPresent = (0,
|
|
23657
|
+
const installRecordPresent = (0, import_node_fs24.existsSync)(root);
|
|
23559
23658
|
const manifestPath = (0, import_node_path21.join)(root, "plugin.yaml");
|
|
23560
23659
|
let installedVersion;
|
|
23561
23660
|
let manifest = "missing";
|
|
23562
23661
|
try {
|
|
23563
|
-
const text = (0,
|
|
23662
|
+
const text = (0, import_node_fs24.readFileSync)(manifestPath, "utf8");
|
|
23564
23663
|
let version;
|
|
23565
23664
|
try {
|
|
23566
23665
|
const parsed = JSON.parse(text).version;
|
|
@@ -23574,25 +23673,25 @@ function readHermesPluginEvidence(env = process.env) {
|
|
|
23574
23673
|
if (version) {
|
|
23575
23674
|
installedVersion = version;
|
|
23576
23675
|
manifest = "valid";
|
|
23577
|
-
} else if ((0,
|
|
23676
|
+
} else if ((0, import_node_fs24.existsSync)(manifestPath)) manifest = "invalid";
|
|
23578
23677
|
} catch {
|
|
23579
|
-
if ((0,
|
|
23678
|
+
if ((0, import_node_fs24.existsSync)(manifestPath)) manifest = "invalid";
|
|
23580
23679
|
}
|
|
23581
23680
|
let skills = false;
|
|
23582
23681
|
try {
|
|
23583
|
-
skills = (0,
|
|
23682
|
+
skills = (0, import_node_fs24.existsSync)((0, import_node_path21.join)(root, "skills")) && (0, import_node_fs24.statSync)((0, import_node_path21.join)(root, "skills")).isDirectory();
|
|
23584
23683
|
} catch {
|
|
23585
23684
|
}
|
|
23586
23685
|
let provisioned = false;
|
|
23587
23686
|
const provisionedRoot = (0, import_node_path21.join)(host, "skills", "mmi");
|
|
23588
23687
|
try {
|
|
23589
|
-
provisioned = (0,
|
|
23688
|
+
provisioned = (0, import_node_fs24.existsSync)(provisionedRoot) && (0, import_node_fs24.statSync)(provisionedRoot).isDirectory();
|
|
23590
23689
|
} catch {
|
|
23591
23690
|
}
|
|
23592
|
-
const treeOk = (0,
|
|
23691
|
+
const treeOk = (0, import_node_fs24.existsSync)((0, import_node_path21.join)(root, "__init__.py")) && skills && manifest === "valid";
|
|
23593
23692
|
const receipt = treeOk && !provisioned ? `hermes-skills-unprovisioned:${provisionedRoot}` : void 0;
|
|
23594
23693
|
return {
|
|
23595
|
-
hostPresent: (0,
|
|
23694
|
+
hostPresent: (0, import_node_fs24.existsSync)(host),
|
|
23596
23695
|
installRecordPresent,
|
|
23597
23696
|
manifest,
|
|
23598
23697
|
payloadPresent: treeOk && provisioned,
|
|
@@ -23644,7 +23743,7 @@ function readGitignore() {
|
|
|
23644
23743
|
const path2 = gitignorePath();
|
|
23645
23744
|
if (path2 === null) return null;
|
|
23646
23745
|
try {
|
|
23647
|
-
return (0,
|
|
23746
|
+
return (0, import_node_fs24.readFileSync)(path2, "utf8");
|
|
23648
23747
|
} catch {
|
|
23649
23748
|
return null;
|
|
23650
23749
|
}
|
|
@@ -23653,14 +23752,14 @@ function writeGitignore(content) {
|
|
|
23653
23752
|
const path2 = gitignorePath();
|
|
23654
23753
|
if (path2 === null) return false;
|
|
23655
23754
|
try {
|
|
23656
|
-
(0,
|
|
23755
|
+
(0, import_node_fs24.writeFileSync)(path2, content, "utf8");
|
|
23657
23756
|
return true;
|
|
23658
23757
|
} catch {
|
|
23659
23758
|
return false;
|
|
23660
23759
|
}
|
|
23661
23760
|
}
|
|
23662
23761
|
function lineEndingState(root) {
|
|
23663
|
-
const attributesPresent = (0,
|
|
23762
|
+
const attributesPresent = (0, import_node_fs24.existsSync)((0, import_node_path21.join)(root, ".gitattributes"));
|
|
23664
23763
|
try {
|
|
23665
23764
|
const output = execFileCapture("git", ["-C", root, "ls-files", "--eol", "--", ":(glob)**/*.sh"], {
|
|
23666
23765
|
windowsHide: true
|
|
@@ -23703,7 +23802,7 @@ function compatHolds(range, version) {
|
|
|
23703
23802
|
}
|
|
23704
23803
|
|
|
23705
23804
|
// src/claude-binary-doctor.ts
|
|
23706
|
-
var
|
|
23805
|
+
var import_node_fs25 = require("node:fs");
|
|
23707
23806
|
var import_node_os14 = require("node:os");
|
|
23708
23807
|
var import_node_path23 = require("node:path");
|
|
23709
23808
|
|
|
@@ -23813,16 +23912,16 @@ function globalNodeModulesRoots(host) {
|
|
|
23813
23912
|
function readHead(path2) {
|
|
23814
23913
|
let fd;
|
|
23815
23914
|
try {
|
|
23816
|
-
fd = (0,
|
|
23915
|
+
fd = (0, import_node_fs25.openSync)(path2, "r");
|
|
23817
23916
|
const buffer = new Uint8Array(MAGIC_HEAD_BYTES);
|
|
23818
|
-
const read = (0,
|
|
23917
|
+
const read = (0, import_node_fs25.readSync)(fd, buffer, 0, MAGIC_HEAD_BYTES, 0);
|
|
23819
23918
|
return buffer.subarray(0, read);
|
|
23820
23919
|
} catch {
|
|
23821
23920
|
return void 0;
|
|
23822
23921
|
} finally {
|
|
23823
23922
|
if (fd !== void 0) {
|
|
23824
23923
|
try {
|
|
23825
|
-
(0,
|
|
23924
|
+
(0, import_node_fs25.closeSync)(fd);
|
|
23826
23925
|
} catch {
|
|
23827
23926
|
}
|
|
23828
23927
|
}
|
|
@@ -23830,7 +23929,7 @@ function readHead(path2) {
|
|
|
23830
23929
|
}
|
|
23831
23930
|
function fileBytes(path2) {
|
|
23832
23931
|
try {
|
|
23833
|
-
return (0,
|
|
23932
|
+
return (0, import_node_fs25.statSync)(path2).size;
|
|
23834
23933
|
} catch {
|
|
23835
23934
|
return void 0;
|
|
23836
23935
|
}
|
|
@@ -23844,13 +23943,13 @@ function readClaudeBinaryState(host = {}) {
|
|
|
23844
23943
|
const arch = host.arch ?? process.arch;
|
|
23845
23944
|
const magic = EXECUTABLE_MAGIC[platform2];
|
|
23846
23945
|
if (!magic) return void 0;
|
|
23847
|
-
const packageRoot = globalNodeModulesRoots(host).map((root) => (0, import_node_path23.join)(root, ...PACKAGE.split("/"))).find((dir) => (0,
|
|
23946
|
+
const packageRoot = globalNodeModulesRoots(host).map((root) => (0, import_node_path23.join)(root, ...PACKAGE.split("/"))).find((dir) => (0, import_node_fs25.existsSync)((0, import_node_path23.join)(dir, "package.json")));
|
|
23848
23947
|
if (!packageRoot) return void 0;
|
|
23849
23948
|
const keys = platformPackageKeys(platform2, arch);
|
|
23850
23949
|
const fallbackPackage = `${PACKAGE}-${keys[0]}`;
|
|
23851
23950
|
let manifest;
|
|
23852
23951
|
try {
|
|
23853
|
-
manifest = JSON.parse((0,
|
|
23952
|
+
manifest = JSON.parse((0, import_node_fs25.readFileSync)((0, import_node_path23.join)(packageRoot, "package.json"), "utf8"));
|
|
23854
23953
|
} catch (e) {
|
|
23855
23954
|
return {
|
|
23856
23955
|
state: "unreadable",
|
|
@@ -23881,7 +23980,7 @@ function readClaudeBinaryState(host = {}) {
|
|
|
23881
23980
|
(0, import_node_path23.join)(packageRoot, "node_modules", ...name.split("/"), binName),
|
|
23882
23981
|
(0, import_node_path23.join)((0, import_node_path23.dirname)((0, import_node_path23.dirname)(packageRoot)), ...name.split("/"), binName)
|
|
23883
23982
|
];
|
|
23884
|
-
const found = published.map((name) => ({ name, path: binIn(name).find((file) => (0,
|
|
23983
|
+
const found = published.map((name) => ({ name, path: binIn(name).find((file) => (0, import_node_fs25.existsSync)(file)) })).find((c) => c.path);
|
|
23885
23984
|
const platformPackage = found?.name ?? published[0];
|
|
23886
23985
|
let source;
|
|
23887
23986
|
let sourceProblem;
|
|
@@ -23892,7 +23991,7 @@ function readClaudeBinaryState(host = {}) {
|
|
|
23892
23991
|
} else {
|
|
23893
23992
|
source = { path: found.path, bytes: fileBytes(found.path) ?? 0 };
|
|
23894
23993
|
}
|
|
23895
|
-
if (!(0,
|
|
23994
|
+
if (!(0, import_node_fs25.existsSync)(binPath)) {
|
|
23896
23995
|
return { state: "missing", binPath, expectedMagic: magic.name, platformPackage, ...source ? { source } : {}, ...sourceProblem ? { sourceProblem } : {} };
|
|
23897
23996
|
}
|
|
23898
23997
|
const head = readHead(binPath);
|
|
@@ -23935,9 +24034,9 @@ function healClaudeBinary(host = {}, onStep) {
|
|
|
23935
24034
|
const platform2 = host.platform ?? process.platform;
|
|
23936
24035
|
const aside = `${probe.binPath}.stub-${Date.now()}`;
|
|
23937
24036
|
let renamed = false;
|
|
23938
|
-
if ((0,
|
|
24037
|
+
if ((0, import_node_fs25.existsSync)(probe.binPath)) {
|
|
23939
24038
|
try {
|
|
23940
|
-
(0,
|
|
24039
|
+
(0, import_node_fs25.renameSync)(probe.binPath, aside);
|
|
23941
24040
|
renamed = true;
|
|
23942
24041
|
onStep?.(`renamed the stub aside: ${aside}`);
|
|
23943
24042
|
} catch (e) {
|
|
@@ -23946,12 +24045,12 @@ function healClaudeBinary(host = {}, onStep) {
|
|
|
23946
24045
|
}
|
|
23947
24046
|
try {
|
|
23948
24047
|
onStep?.(`copying ${probe.source.path} \u2192 ${probe.binPath} (${(probe.source.bytes / 1e6).toFixed(0)} MB)`);
|
|
23949
|
-
(0,
|
|
23950
|
-
if (platform2 !== "win32") (0,
|
|
24048
|
+
(0, import_node_fs25.copyFileSync)(probe.source.path, probe.binPath);
|
|
24049
|
+
if (platform2 !== "win32") (0, import_node_fs25.chmodSync)(probe.binPath, 493);
|
|
23951
24050
|
} catch (e) {
|
|
23952
24051
|
if (renamed) {
|
|
23953
24052
|
try {
|
|
23954
|
-
(0,
|
|
24053
|
+
(0, import_node_fs25.renameSync)(aside, probe.binPath);
|
|
23955
24054
|
} catch {
|
|
23956
24055
|
return { ok: false, detail: `copy failed (${e.message}) and the stub could not be restored \u2014 the original is at ${aside}` };
|
|
23957
24056
|
}
|
|
@@ -23965,7 +24064,7 @@ function healClaudeBinary(host = {}, onStep) {
|
|
|
23965
24064
|
let kept = false;
|
|
23966
24065
|
if (renamed) {
|
|
23967
24066
|
try {
|
|
23968
|
-
(0,
|
|
24067
|
+
(0, import_node_fs25.rmSync)(aside);
|
|
23969
24068
|
} catch {
|
|
23970
24069
|
kept = true;
|
|
23971
24070
|
}
|
|
@@ -24324,7 +24423,7 @@ function checkLineEndings(probe) {
|
|
|
24324
24423
|
}
|
|
24325
24424
|
|
|
24326
24425
|
// src/release-ledger.ts
|
|
24327
|
-
var
|
|
24426
|
+
var import_node_fs26 = require("node:fs");
|
|
24328
24427
|
var import_node_path25 = require("node:path");
|
|
24329
24428
|
var import_node_crypto9 = require("node:crypto");
|
|
24330
24429
|
|
|
@@ -24499,8 +24598,8 @@ function attachOutputNote(note, suffix) {
|
|
|
24499
24598
|
}
|
|
24500
24599
|
function writeFailingLegOutput(artifactPath, output) {
|
|
24501
24600
|
const fileLines = lastNonEmptyLines(output, LEDGER_OUTPUT_FILE_LINES);
|
|
24502
|
-
(0,
|
|
24503
|
-
(0,
|
|
24601
|
+
(0, import_node_fs26.mkdirSync)((0, import_node_path25.dirname)(artifactPath), { recursive: true });
|
|
24602
|
+
(0, import_node_fs26.writeFileSync)(artifactPath, `${fileLines.join("\n")}
|
|
24504
24603
|
`, "utf8");
|
|
24505
24604
|
const tail = fileLines.slice(-LEDGER_OUTPUT_NOTE_LINES).join("\n");
|
|
24506
24605
|
const noteSuffix = truncate(`failing-leg output: ${artifactPath}
|
|
@@ -24668,7 +24767,7 @@ function resolvePrimaryGitDir(cwd) {
|
|
|
24668
24767
|
}
|
|
24669
24768
|
let common;
|
|
24670
24769
|
try {
|
|
24671
|
-
common = (0,
|
|
24770
|
+
common = (0, import_node_fs26.readFileSync)((0, import_node_path25.join)(gitDir, "commondir"), "utf8").trim();
|
|
24672
24771
|
} catch (e) {
|
|
24673
24772
|
if (e.code !== "ENOENT") {
|
|
24674
24773
|
throw new ReleaseLedgerError("unreadable", `release ledger: the worktree gitdir's commondir pointer could not be READ (${e instanceof Error ? e.message : String(e)}) \u2014 a failed read is unverified, not primary (#5987/#4713)`);
|
|
@@ -24677,7 +24776,7 @@ function resolvePrimaryGitDir(cwd) {
|
|
|
24677
24776
|
if (!common) return gitDir;
|
|
24678
24777
|
const commonDir = (0, import_node_path25.isAbsolute)(common) ? common : (0, import_node_path25.resolve)(gitDir, common);
|
|
24679
24778
|
try {
|
|
24680
|
-
(0,
|
|
24779
|
+
(0, import_node_fs26.readFileSync)((0, import_node_path25.join)(commonDir, "HEAD"), "utf8");
|
|
24681
24780
|
} catch (e) {
|
|
24682
24781
|
throw new ReleaseLedgerError("no-checkout", `release ledger: the worktree's commondir pointer names ${commonDir}, which has no readable HEAD (${e instanceof Error ? e.message : String(e)}) \u2014 the primary checkout may have been removed; refusing to write the ledger into a doomed location`);
|
|
24683
24782
|
}
|
|
@@ -24687,11 +24786,11 @@ function releaseLedgerPath(cwd) {
|
|
|
24687
24786
|
return (0, import_node_path25.join)(resolvePrimaryGitDir(cwd), "mmi-runtime", "release", "phases.json");
|
|
24688
24787
|
}
|
|
24689
24788
|
function atomicWriteJson(path2, ledger) {
|
|
24690
|
-
(0,
|
|
24789
|
+
(0, import_node_fs26.mkdirSync)((0, import_node_path25.dirname)(path2), { recursive: true });
|
|
24691
24790
|
const tmp = `${path2}.tmp-${process.pid}-${(0, import_node_crypto9.randomBytes)(4).toString("hex")}`;
|
|
24692
|
-
(0,
|
|
24791
|
+
(0, import_node_fs26.writeFileSync)(tmp, `${JSON.stringify(ledger, null, 2)}
|
|
24693
24792
|
`, "utf8");
|
|
24694
|
-
(0,
|
|
24793
|
+
(0, import_node_fs26.renameSync)(tmp, path2);
|
|
24695
24794
|
}
|
|
24696
24795
|
var LEDGER_LOCK_OPTS = { label: "release ledger", staleMs: 18e4, deadHolderSteal: true };
|
|
24697
24796
|
async function withLedgerLock(path2, fn, opts = {}) {
|
|
@@ -24738,7 +24837,7 @@ function describeTrainWriterToken(token) {
|
|
|
24738
24837
|
function liveTrainWriterHolder(cwd) {
|
|
24739
24838
|
let token;
|
|
24740
24839
|
try {
|
|
24741
|
-
token = (0,
|
|
24840
|
+
token = (0, import_node_fs26.readFileSync)(trainWriterLockPath(cwd), "utf8");
|
|
24742
24841
|
} catch {
|
|
24743
24842
|
return void 0;
|
|
24744
24843
|
}
|
|
@@ -24760,7 +24859,7 @@ async function acquireTrainWriterLock(cwd, verb) {
|
|
|
24760
24859
|
if (heldTrainWriter) heldTrainWriter.depth -= 1;
|
|
24761
24860
|
};
|
|
24762
24861
|
}
|
|
24763
|
-
(0,
|
|
24862
|
+
(0, import_node_fs26.mkdirSync)((0, import_node_path25.dirname)(lockPath), { recursive: true });
|
|
24764
24863
|
const opts = resolveFileLockOpts({ label: "train writer", staleMs: TRAIN_WRITER_STALE_MS, deadHolderSteal: true, maxWaitMs: 0, holder: verb });
|
|
24765
24864
|
let guard;
|
|
24766
24865
|
try {
|
|
@@ -24769,7 +24868,7 @@ async function acquireTrainWriterLock(cwd, verb) {
|
|
|
24769
24868
|
if (!(e instanceof FileLockBusyError)) throw e;
|
|
24770
24869
|
let token = "";
|
|
24771
24870
|
try {
|
|
24772
|
-
token = (0,
|
|
24871
|
+
token = (0, import_node_fs26.readFileSync)(lockPath, "utf8");
|
|
24773
24872
|
} catch {
|
|
24774
24873
|
token = "";
|
|
24775
24874
|
}
|
|
@@ -24804,7 +24903,7 @@ async function withReleaseLedger(path2, expected, fn, opts = {}) {
|
|
|
24804
24903
|
let current;
|
|
24805
24904
|
let raw;
|
|
24806
24905
|
try {
|
|
24807
|
-
raw = (0,
|
|
24906
|
+
raw = (0, import_node_fs26.readFileSync)(path2, "utf8");
|
|
24808
24907
|
} catch (e) {
|
|
24809
24908
|
if (e.code !== "ENOENT") {
|
|
24810
24909
|
throw new ReleaseLedgerError("unreadable", `release ledger at ${path2} could not be READ (${e instanceof Error ? e.message : String(e)}) \u2014 a failed read is unverified, not absent (#5987)`);
|
|
@@ -25473,7 +25572,7 @@ async function clearLedgerFile(path2, anchors, maxWaitMs) {
|
|
|
25473
25572
|
return withLedgerLock(path2, async (fence) => {
|
|
25474
25573
|
let raw;
|
|
25475
25574
|
try {
|
|
25476
|
-
raw = (0,
|
|
25575
|
+
raw = (0, import_node_fs26.readFileSync)(path2, "utf8");
|
|
25477
25576
|
} catch (e) {
|
|
25478
25577
|
if (e.code === "ENOENT") return { cleared: false };
|
|
25479
25578
|
return { cleared: false, note: `release ledger at ${path2} could not be read for clearing (${e instanceof Error ? e.message : String(e)}) \u2014 left in place` };
|
|
@@ -25489,7 +25588,7 @@ async function clearLedgerFile(path2, anchors, maxWaitMs) {
|
|
|
25489
25588
|
} catch (e) {
|
|
25490
25589
|
return { cleared: false, note: `release ledger at ${path2} belongs to ${ledger.tag} @ ${ledger.tagSha.slice(0, 12)} \u2014 not this release; left in place (${e instanceof Error ? e.message : String(e)})` };
|
|
25491
25590
|
}
|
|
25492
|
-
await fence(() => (0,
|
|
25591
|
+
await fence(() => (0, import_node_fs26.unlinkSync)(path2));
|
|
25493
25592
|
return { cleared: true, note: `cleared the release ledger at ${path2} for the live-proven aborted ${anchors.tag}` };
|
|
25494
25593
|
}, { maxWaitMs });
|
|
25495
25594
|
}
|
|
@@ -25649,7 +25748,7 @@ async function healStaleAlignmentLeg(deps, cwd, expected) {
|
|
|
25649
25748
|
return withLedgerLock(path2, async (fence) => {
|
|
25650
25749
|
let prior;
|
|
25651
25750
|
try {
|
|
25652
|
-
prior = parseReleaseLedger((0,
|
|
25751
|
+
prior = parseReleaseLedger((0, import_node_fs26.readFileSync)(path2, "utf8"));
|
|
25653
25752
|
} catch {
|
|
25654
25753
|
return void 0;
|
|
25655
25754
|
}
|
|
@@ -25674,7 +25773,7 @@ async function healUnfoldedRunLegs(deps, cwd, model) {
|
|
|
25674
25773
|
const path2 = releaseLedgerPath(cwd);
|
|
25675
25774
|
let prior;
|
|
25676
25775
|
try {
|
|
25677
|
-
prior = parseReleaseLedger((0,
|
|
25776
|
+
prior = parseReleaseLedger((0, import_node_fs26.readFileSync)(path2, "utf8"));
|
|
25678
25777
|
} catch {
|
|
25679
25778
|
return void 0;
|
|
25680
25779
|
}
|
|
@@ -25743,7 +25842,7 @@ async function supersedeContentCausedDeployLeg(deps, cwd) {
|
|
|
25743
25842
|
return withLedgerLock(path2, async (fence) => {
|
|
25744
25843
|
let prior;
|
|
25745
25844
|
try {
|
|
25746
|
-
prior = parseReleaseLedger((0,
|
|
25845
|
+
prior = parseReleaseLedger((0, import_node_fs26.readFileSync)(path2, "utf8"));
|
|
25747
25846
|
} catch (e) {
|
|
25748
25847
|
throw new ReleaseLedgerError(
|
|
25749
25848
|
"unreadable",
|
|
@@ -25841,10 +25940,10 @@ async function proveOriginPromotionOrArchived(deps, prior, path2, label, ref, fe
|
|
|
25841
25940
|
throw new Error(`${label}: origin no longer has ${prior.tag} but its GitHub Release still exists \u2014 resolve the mixed external state before closing the ledger; nothing was written (${ref})`);
|
|
25842
25941
|
}
|
|
25843
25942
|
const archivePath = (0, import_node_path25.join)((0, import_node_path25.dirname)(path2), `phases.archive-${prior.tag}.json`);
|
|
25844
|
-
if ((0,
|
|
25943
|
+
if ((0, import_node_fs26.existsSync)(archivePath)) {
|
|
25845
25944
|
throw new Error(`${label}: archive already exists at ${archivePath} \u2014 preserving both ledger records; resolve the collision by hand; nothing was written (${ref})`);
|
|
25846
25945
|
}
|
|
25847
|
-
await fence(() => (0,
|
|
25946
|
+
await fence(() => (0, import_node_fs26.renameSync)(path2, archivePath));
|
|
25848
25947
|
return "deleted";
|
|
25849
25948
|
}
|
|
25850
25949
|
async function supersedeContentCausedPublishLeg(deps, cwd) {
|
|
@@ -25852,7 +25951,7 @@ async function supersedeContentCausedPublishLeg(deps, cwd) {
|
|
|
25852
25951
|
return withLedgerLock(path2, async (fence) => {
|
|
25853
25952
|
let prior;
|
|
25854
25953
|
try {
|
|
25855
|
-
prior = parseReleaseLedger((0,
|
|
25954
|
+
prior = parseReleaseLedger((0, import_node_fs26.readFileSync)(path2, "utf8"));
|
|
25856
25955
|
} catch (e) {
|
|
25857
25956
|
throw new ReleaseLedgerError(
|
|
25858
25957
|
"unreadable",
|
|
@@ -25934,7 +26033,7 @@ async function supersedeContentCausedDeployAndPublishLegs(deps, cwd) {
|
|
|
25934
26033
|
return withLedgerLock(path2, async (fence) => {
|
|
25935
26034
|
let prior;
|
|
25936
26035
|
try {
|
|
25937
|
-
prior = parseReleaseLedger((0,
|
|
26036
|
+
prior = parseReleaseLedger((0, import_node_fs26.readFileSync)(path2, "utf8"));
|
|
25938
26037
|
} catch (e) {
|
|
25939
26038
|
throw new ReleaseLedgerError(
|
|
25940
26039
|
"unreadable",
|
|
@@ -26039,7 +26138,7 @@ async function supersedeContentCausedDeployAndPublishLegs(deps, cwd) {
|
|
|
26039
26138
|
async function reverifyPriorRunLegs(deps, path2, targetTag) {
|
|
26040
26139
|
let prior;
|
|
26041
26140
|
try {
|
|
26042
|
-
prior = parseReleaseLedger((0,
|
|
26141
|
+
prior = parseReleaseLedger((0, import_node_fs26.readFileSync)(path2, "utf8"));
|
|
26043
26142
|
} catch {
|
|
26044
26143
|
return;
|
|
26045
26144
|
}
|
|
@@ -26059,7 +26158,7 @@ async function beginReleaseLedger(deps, cwd, targetTag) {
|
|
|
26059
26158
|
return withLedgerLock(path2, async (fence) => {
|
|
26060
26159
|
let raw;
|
|
26061
26160
|
try {
|
|
26062
|
-
raw = (0,
|
|
26161
|
+
raw = (0, import_node_fs26.readFileSync)(path2, "utf8");
|
|
26063
26162
|
} catch (e) {
|
|
26064
26163
|
if (e.code === "ENOENT") return { ok: true };
|
|
26065
26164
|
return { ok: false, error: `the release ledger at ${path2} could not be READ (${e instanceof Error ? e.message : String(e)}) \u2014 a failed read is unverified, not absent (#5987/#4713)` };
|
|
@@ -26099,13 +26198,13 @@ async function beginReleaseLedger(deps, cwd, targetTag) {
|
|
|
26099
26198
|
}
|
|
26100
26199
|
const archivePath = (0, import_node_path25.join)((0, import_node_path25.dirname)(path2), `phases.archive-${prior.tag}.json`);
|
|
26101
26200
|
try {
|
|
26102
|
-
await fence(() => (0,
|
|
26201
|
+
await fence(() => (0, import_node_fs26.unlinkSync)(archivePath));
|
|
26103
26202
|
} catch (e) {
|
|
26104
26203
|
if (e.code !== "ENOENT") {
|
|
26105
26204
|
return { ok: false, error: `could not clear the stale archive at ${archivePath} (${e instanceof Error ? e.message : String(e)}) \u2014 the ledger for ${prior.tag} stays active (#5987)` };
|
|
26106
26205
|
}
|
|
26107
26206
|
}
|
|
26108
|
-
await fence(() => (0,
|
|
26207
|
+
await fence(() => (0, import_node_fs26.renameSync)(path2, archivePath));
|
|
26109
26208
|
return { ok: true, note: `archived the completed release ledger ${prior.tag} to ${archivePath} (live-proven at ${prior.tagSha.slice(0, 12)})` };
|
|
26110
26209
|
});
|
|
26111
26210
|
}
|
|
@@ -26133,7 +26232,7 @@ async function retryHotfixDeployLegs(deps, cwd, opts = {}) {
|
|
|
26133
26232
|
return withLedgerLock(path2, async (fence) => {
|
|
26134
26233
|
let prior;
|
|
26135
26234
|
try {
|
|
26136
|
-
prior = parseReleaseLedger((0,
|
|
26235
|
+
prior = parseReleaseLedger((0, import_node_fs26.readFileSync)(path2, "utf8"));
|
|
26137
26236
|
} catch (e) {
|
|
26138
26237
|
throw new ReleaseLedgerError(
|
|
26139
26238
|
"unreadable",
|
|
@@ -26326,10 +26425,10 @@ function readOriginWorkflowsDefault(root, ref) {
|
|
|
26326
26425
|
}
|
|
26327
26426
|
var NPM_REGISTRY = "https://registry.npmjs.org";
|
|
26328
26427
|
async function probeRegistryWhoami(train) {
|
|
26329
|
-
const dir = (0,
|
|
26428
|
+
const dir = (0, import_node_fs27.mkdtempSync)((0, import_node_path26.join)((0, import_node_os15.tmpdir)(), "mmi-npmrc-"));
|
|
26330
26429
|
const rc = (0, import_node_path26.join)(dir, "npmrc");
|
|
26331
26430
|
try {
|
|
26332
|
-
(0,
|
|
26431
|
+
(0, import_node_fs27.writeFileSync)(rc, "//registry.npmjs.org/:_authToken=${NPM_TOKEN}\n");
|
|
26333
26432
|
await train.runSelf(["secrets", "use", "npm/NPM_TOKEN", "--slug", "_org", "--", "npm", "whoami", "--registry", NPM_REGISTRY, "--userconfig", rc]);
|
|
26334
26433
|
return { kind: "ok", detail: "the registry answered a login" };
|
|
26335
26434
|
} catch (e) {
|
|
@@ -26340,7 +26439,7 @@ async function probeRegistryWhoami(train) {
|
|
|
26340
26439
|
if (/\bE401\b|401 Unauthorized/.test(stderr)) return { kind: "rejected", detail: "npm whoami answered 401 Unauthorized" };
|
|
26341
26440
|
return { kind: "unverified", detail: first };
|
|
26342
26441
|
} finally {
|
|
26343
|
-
(0,
|
|
26442
|
+
(0, import_node_fs27.rmSync)(dir, { recursive: true, force: true });
|
|
26344
26443
|
}
|
|
26345
26444
|
}
|
|
26346
26445
|
var REGISTRY_TOKEN_ENV = /\b(NODE_AUTH_TOKEN|NPM_TOKEN)\b/;
|
|
@@ -26358,7 +26457,7 @@ var defaultDeps2 = {
|
|
|
26358
26457
|
ledgerPath: releaseLedgerPath,
|
|
26359
26458
|
readLedgerRaw: (path2) => {
|
|
26360
26459
|
try {
|
|
26361
|
-
return (0,
|
|
26460
|
+
return (0, import_node_fs27.readFileSync)(path2, "utf8");
|
|
26362
26461
|
} catch (e) {
|
|
26363
26462
|
if (e.code === "ENOENT") return void 0;
|
|
26364
26463
|
throw e;
|
|
@@ -26369,7 +26468,7 @@ var defaultDeps2 = {
|
|
|
26369
26468
|
trainWriterHolder: liveTrainWriterHolder,
|
|
26370
26469
|
readSurfacesRaw: (cwd) => {
|
|
26371
26470
|
try {
|
|
26372
|
-
return (0,
|
|
26471
|
+
return (0, import_node_fs27.readFileSync)((0, import_node_path26.join)(cwd, "surfaces.json"), "utf8");
|
|
26373
26472
|
} catch {
|
|
26374
26473
|
return void 0;
|
|
26375
26474
|
}
|
|
@@ -27008,7 +27107,7 @@ function formatTrainDoctor(v) {
|
|
|
27008
27107
|
|
|
27009
27108
|
// src/release-plain-words.ts
|
|
27010
27109
|
var import_promises3 = require("node:fs/promises");
|
|
27011
|
-
var
|
|
27110
|
+
var import_node_fs28 = require("node:fs");
|
|
27012
27111
|
function releaseCutByNotes(cutBy) {
|
|
27013
27112
|
return `## Internal
|
|
27014
27113
|
Cut by ${formatSessionIdentity(cutBy)}
|
|
@@ -27114,7 +27213,7 @@ function validateSuiteReleaseSummary(path2, pathTr) {
|
|
|
27114
27213
|
for (const [lang, file] of files) {
|
|
27115
27214
|
let content;
|
|
27116
27215
|
try {
|
|
27117
|
-
content = (0,
|
|
27216
|
+
content = (0, import_node_fs28.readFileSync)(file, "utf8");
|
|
27118
27217
|
} catch (e) {
|
|
27119
27218
|
throw new Error(`could not read summary file ${file}: ${e.message} \u2014 see ${SUMMARY_GUIDE}`);
|
|
27120
27219
|
}
|
|
@@ -27329,14 +27428,14 @@ function readLocalGateWorkflows() {
|
|
|
27329
27428
|
const dir = (0, import_node_path27.join)(".github", "workflows");
|
|
27330
27429
|
let names;
|
|
27331
27430
|
try {
|
|
27332
|
-
names = (0,
|
|
27431
|
+
names = (0, import_node_fs29.readdirSync)(dir);
|
|
27333
27432
|
} catch {
|
|
27334
27433
|
return null;
|
|
27335
27434
|
}
|
|
27336
27435
|
const files = [];
|
|
27337
27436
|
for (const name of names.filter(isGateWorkflowPath)) {
|
|
27338
27437
|
try {
|
|
27339
|
-
files.push({ path: `${dir}/${name}`.replace(/\\/g, "/"), body: (0,
|
|
27438
|
+
files.push({ path: `${dir}/${name}`.replace(/\\/g, "/"), body: (0, import_node_fs29.readFileSync)((0, import_node_path27.join)(dir, name), "utf8") });
|
|
27340
27439
|
} catch {
|
|
27341
27440
|
}
|
|
27342
27441
|
}
|
|
@@ -27346,14 +27445,14 @@ function readLocalWorkflows() {
|
|
|
27346
27445
|
const dir = (0, import_node_path27.join)(".github", "workflows");
|
|
27347
27446
|
let names;
|
|
27348
27447
|
try {
|
|
27349
|
-
names = (0,
|
|
27448
|
+
names = (0, import_node_fs29.readdirSync)(dir);
|
|
27350
27449
|
} catch {
|
|
27351
27450
|
return null;
|
|
27352
27451
|
}
|
|
27353
27452
|
const files = [];
|
|
27354
27453
|
for (const name of names.filter((n) => /\.ya?ml$/i.test(n))) {
|
|
27355
27454
|
try {
|
|
27356
|
-
files.push({ path: `${dir}/${name}`.replace(/\\/g, "/"), body: (0,
|
|
27455
|
+
files.push({ path: `${dir}/${name}`.replace(/\\/g, "/"), body: (0, import_node_fs29.readFileSync)((0, import_node_path27.join)(dir, name), "utf8") });
|
|
27357
27456
|
} catch {
|
|
27358
27457
|
}
|
|
27359
27458
|
}
|
|
@@ -27390,6 +27489,7 @@ async function preflight(deps, ctx, stage, meta, lane) {
|
|
|
27390
27489
|
if (model === "content") {
|
|
27391
27490
|
throw new Error(`${ctx.repo} is a content repo (deployModel=content) \u2014 the release train does not apply (trunk-based; PR to main)`);
|
|
27392
27491
|
}
|
|
27492
|
+
if (meta.releaseTrack === "single") throw new Error("single-track repos ship on merge; there is no release train");
|
|
27393
27493
|
if (model === "none") {
|
|
27394
27494
|
throw new Error(`${ctx.repo} is not Hub-deployed (deployModel=none) \u2014 the release train does not apply; use the project's own release path`);
|
|
27395
27495
|
}
|
|
@@ -28235,7 +28335,7 @@ async function activeRcandLedgerCandidate(deps, cwd) {
|
|
|
28235
28335
|
}
|
|
28236
28336
|
let prior;
|
|
28237
28337
|
try {
|
|
28238
|
-
prior = parseReleaseLedger((0,
|
|
28338
|
+
prior = parseReleaseLedger((0, import_node_fs29.readFileSync)(path2, "utf8"));
|
|
28239
28339
|
} catch {
|
|
28240
28340
|
return void 0;
|
|
28241
28341
|
}
|
|
@@ -29638,9 +29738,9 @@ function rulesetCoversReleaseBranches(payload, track) {
|
|
|
29638
29738
|
const conditions = payload.conditions;
|
|
29639
29739
|
const include = conditions?.ref_name?.include;
|
|
29640
29740
|
if (!Array.isArray(include)) {
|
|
29641
|
-
return track === "full" || track === "direct" || track === "trunk";
|
|
29741
|
+
return track === "full" || track === "direct" || track === "trunk" || track === "single";
|
|
29642
29742
|
}
|
|
29643
|
-
const releaseRefs = track === "full" ? ["refs/heads/rc", "refs/heads/main"] : ["refs/heads/main"];
|
|
29743
|
+
const releaseRefs = track === "full" ? ["refs/heads/rc", "refs/heads/main"] : track === "single" ? ["refs/heads/development"] : ["refs/heads/main"];
|
|
29644
29744
|
return include.some((entry) => typeof entry === "string" && (entry === "~DEFAULT_BRANCH" ? track === "trunk" : releaseRefs.some((ref) => refPatternCovers(entry, ref))));
|
|
29645
29745
|
}
|
|
29646
29746
|
function releaseBranchRefsCovered(conditions, track) {
|
|
@@ -30851,7 +30951,7 @@ var PRIMARY_GROUPS = [
|
|
|
30851
30951
|
["Setup and support", ["bootstrap", "secrets", "docs", "tests", "spawn", "dist"]],
|
|
30852
30952
|
["Coordinate and improve", ["wave", "report", "skill-lesson", "closure-rate"]]
|
|
30853
30953
|
];
|
|
30854
|
-
var OPERATIONAL_TOP_LEVEL = /* @__PURE__ */ new Set(["org", "runtime", "plugin", "packages", "archive-prune"]);
|
|
30954
|
+
var OPERATIONAL_TOP_LEVEL = /* @__PURE__ */ new Set(["org", "runtime", "plugin", "packages", "github", "archive-prune"]);
|
|
30855
30955
|
var CAMPAIGN_ORCHESTRATOR_TOP_LEVEL = /* @__PURE__ */ new Set(["pickup", "read"]);
|
|
30856
30956
|
var SUPPORT_PRIMARY = /* @__PURE__ */ new Set(["doctor", "whoami", "commands", "explain", "docs", "tests", "spawn", "dist", "wave", "report", "skill-lesson", "closure-rate"]);
|
|
30857
30957
|
var TOP_LEVEL_ORDER = /* @__PURE__ */ new Map();
|
|
@@ -30892,6 +30992,7 @@ var COMMAND_OWNERSHIP = {
|
|
|
30892
30992
|
stage: { module_owner: "cli/src/stage-commands.ts", consumer: "agent-workflow" },
|
|
30893
30993
|
pr: { module_owner: "cli/src/pr-commands.ts", consumer: "agent-workflow" },
|
|
30894
30994
|
api: { module_owner: "cli/src/api-read.ts", consumer: "agent-workflow" },
|
|
30995
|
+
github: { module_owner: "cli/src/github-budget.ts", consumer: "release-operator" },
|
|
30895
30996
|
read: { module_owner: "cli/src/app-read-broker.ts", consumer: "agent-workflow" },
|
|
30896
30997
|
ci: { module_owner: "cli/src/ci-audit.ts", consumer: "release-operator" },
|
|
30897
30998
|
rcand: { module_owner: "cli/src/train-commands.ts", consumer: "release-operator" },
|
|
@@ -31631,6 +31732,55 @@ function renderPluginCachePlan(plan, applied) {
|
|
|
31631
31732
|
return lines2.join("\n");
|
|
31632
31733
|
}
|
|
31633
31734
|
|
|
31735
|
+
// src/github-budget.ts
|
|
31736
|
+
init_cli_shared();
|
|
31737
|
+
function allowance(value) {
|
|
31738
|
+
const v = value;
|
|
31739
|
+
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;
|
|
31740
|
+
}
|
|
31741
|
+
async function readGithubBudget(deps) {
|
|
31742
|
+
async function read(token) {
|
|
31743
|
+
try {
|
|
31744
|
+
const credential = await token();
|
|
31745
|
+
if (!credential) throw new Error("No identity");
|
|
31746
|
+
const res = await deps.fetch("https://api.github.com/rate_limit", {
|
|
31747
|
+
method: "GET",
|
|
31748
|
+
headers: { authorization: `Bearer ${credential}`, accept: "application/vnd.github+json", "user-agent": "mmi-cli" }
|
|
31749
|
+
});
|
|
31750
|
+
if (!res.ok) throw new Error("Unreadable");
|
|
31751
|
+
const body = await res.json();
|
|
31752
|
+
return { core: allowance(body.resources?.core), graphql: allowance(body.resources?.graphql) };
|
|
31753
|
+
} catch {
|
|
31754
|
+
return { core: null, graphql: null };
|
|
31755
|
+
}
|
|
31756
|
+
}
|
|
31757
|
+
const [personal, app1, app2] = await Promise.all([
|
|
31758
|
+
read(async () => {
|
|
31759
|
+
const env = { ...process.env };
|
|
31760
|
+
delete env.GH_TOKEN;
|
|
31761
|
+
delete env.GITHUB_TOKEN;
|
|
31762
|
+
return (await execFileP("gh", ["auth", "token"], { env })).stdout.trim();
|
|
31763
|
+
}),
|
|
31764
|
+
...APP_POOL_MEMBERS.map((keys) => read(async () => (await mintBudgetToken(deps, keys)).token))
|
|
31765
|
+
]);
|
|
31766
|
+
const pools = { personal, app1, app2 };
|
|
31767
|
+
const count = (v) => v ? `${v.remaining}/${v.limit}` : "unknown";
|
|
31768
|
+
const resets = [...new Set(Object.values(pools).flatMap((pool) => [pool.core, pool.graphql]).filter((v) => v !== null).map((v) => new Intl.DateTimeFormat("en-GB", {
|
|
31769
|
+
timeZone: "Europe/Istanbul",
|
|
31770
|
+
hour: "2-digit",
|
|
31771
|
+
minute: "2-digit",
|
|
31772
|
+
hourCycle: "h23"
|
|
31773
|
+
}).format(new Date(v.reset * 1e3))))].sort();
|
|
31774
|
+
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)`;
|
|
31775
|
+
return { ...pools, line };
|
|
31776
|
+
}
|
|
31777
|
+
function registerGithubBudgetCommand(program3, deps) {
|
|
31778
|
+
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) => {
|
|
31779
|
+
const budget = await readGithubBudget(deps());
|
|
31780
|
+
console.log(options.json ? JSON.stringify(budget, null, 2) : budget.line);
|
|
31781
|
+
});
|
|
31782
|
+
}
|
|
31783
|
+
|
|
31634
31784
|
// src/board-commands.ts
|
|
31635
31785
|
init_cli_shared();
|
|
31636
31786
|
|
|
@@ -32132,7 +32282,7 @@ function registerBoardCommands(program3) {
|
|
|
32132
32282
|
}
|
|
32133
32283
|
|
|
32134
32284
|
// src/bootstrap-commands.ts
|
|
32135
|
-
var
|
|
32285
|
+
var import_node_fs33 = require("node:fs");
|
|
32136
32286
|
var import_node_os18 = require("node:os");
|
|
32137
32287
|
var import_node_path31 = require("node:path");
|
|
32138
32288
|
init_cli_shared();
|
|
@@ -32318,7 +32468,7 @@ init_github_client();
|
|
|
32318
32468
|
init_cli_shared();
|
|
32319
32469
|
|
|
32320
32470
|
// src/port-registry.ts
|
|
32321
|
-
var
|
|
32471
|
+
var import_node_fs30 = require("node:fs");
|
|
32322
32472
|
var import_node_path28 = require("node:path");
|
|
32323
32473
|
|
|
32324
32474
|
// ../infra/port-geometry.mjs
|
|
@@ -32333,8 +32483,8 @@ function nextPortBlock(registry2) {
|
|
|
32333
32483
|
return [base, base + PORT_SPAN];
|
|
32334
32484
|
}
|
|
32335
32485
|
function loadPortRegistry(path2) {
|
|
32336
|
-
if (!(0,
|
|
32337
|
-
const raw = JSON.parse((0,
|
|
32486
|
+
if (!(0, import_node_fs30.existsSync)(path2)) return {};
|
|
32487
|
+
const raw = JSON.parse((0, import_node_fs30.readFileSync)(path2, "utf8"));
|
|
32338
32488
|
const out = {};
|
|
32339
32489
|
for (const [key, value] of Object.entries(raw)) {
|
|
32340
32490
|
if (Array.isArray(value) && value.length === 2 && value.every((n) => typeof n === "number")) {
|
|
@@ -32364,7 +32514,7 @@ function existingPortRange(repo, registry2) {
|
|
|
32364
32514
|
function portRangeInfraAt(root, source) {
|
|
32365
32515
|
const registryPath = (0, import_node_path28.join)(root, "infra", "port-ranges.json");
|
|
32366
32516
|
const ddbScriptPath = (0, import_node_path28.join)(root, "infra", "port-ddb.mjs");
|
|
32367
|
-
if (!(0,
|
|
32517
|
+
if (!(0, import_node_fs30.existsSync)(registryPath) || !(0, import_node_fs30.existsSync)(ddbScriptPath)) return null;
|
|
32368
32518
|
return { root, source, registryPath, ddbScriptPath };
|
|
32369
32519
|
}
|
|
32370
32520
|
function resolvePortRangeInfra(cwd, packageDir) {
|
|
@@ -32446,7 +32596,7 @@ async function assignPersistedPortRange(repo, slug, reg, opts) {
|
|
|
32446
32596
|
}
|
|
32447
32597
|
|
|
32448
32598
|
// src/box-commands.ts
|
|
32449
|
-
var
|
|
32599
|
+
var import_node_fs32 = require("node:fs");
|
|
32450
32600
|
var import_node_child_process10 = require("node:child_process");
|
|
32451
32601
|
var import_node_os17 = require("node:os");
|
|
32452
32602
|
var import_node_path30 = require("node:path");
|
|
@@ -32580,7 +32730,7 @@ function applyRemoteScript(items, date) {
|
|
|
32580
32730
|
init_clean_exit();
|
|
32581
32731
|
|
|
32582
32732
|
// src/secrets-commands.ts
|
|
32583
|
-
var
|
|
32733
|
+
var import_node_fs31 = require("node:fs");
|
|
32584
32734
|
var import_node_path29 = require("node:path");
|
|
32585
32735
|
var import_node_os16 = require("node:os");
|
|
32586
32736
|
init_cli_shared();
|
|
@@ -33730,8 +33880,8 @@ async function decryptRailsCredentials(input) {
|
|
|
33730
33880
|
MMI_RAILS_CREDENTIALS_FILE: credentialsPath,
|
|
33731
33881
|
MMI_RAILS_MASTER_KEY_FILE: masterKeyPath
|
|
33732
33882
|
};
|
|
33733
|
-
if ((0,
|
|
33734
|
-
env.RAILS_MASTER_KEY = (0,
|
|
33883
|
+
if ((0, import_node_fs31.existsSync)(masterKeyPath)) {
|
|
33884
|
+
env.RAILS_MASTER_KEY = (0, import_node_fs31.readFileSync)(masterKeyPath, "utf8").trim();
|
|
33735
33885
|
}
|
|
33736
33886
|
const script = [
|
|
33737
33887
|
'require "json"',
|
|
@@ -33741,9 +33891,9 @@ async function decryptRailsCredentials(input) {
|
|
|
33741
33891
|
'config = ActiveSupport::EncryptedConfiguration.new(config_path: config_path, key_path: key_path, env_key: "RAILS_MASTER_KEY", raise_if_missing_key: true)',
|
|
33742
33892
|
"puts JSON.generate(config.config)"
|
|
33743
33893
|
].join("\n");
|
|
33744
|
-
const scriptDir = (0,
|
|
33894
|
+
const scriptDir = (0, import_node_fs31.mkdtempSync)((0, import_node_path29.join)((0, import_node_os16.tmpdir)(), "mmi-rails-decrypt-"));
|
|
33745
33895
|
const scriptPath = (0, import_node_path29.join)(scriptDir, "decrypt.rb");
|
|
33746
|
-
(0,
|
|
33896
|
+
(0, import_node_fs31.writeFileSync)(scriptPath, script, "utf8");
|
|
33747
33897
|
try {
|
|
33748
33898
|
const args = ["exec", "ruby", scriptPath];
|
|
33749
33899
|
const cmd = process.platform === "win32" ? "cmd.exe" : "bundle";
|
|
@@ -33755,7 +33905,7 @@ async function decryptRailsCredentials(input) {
|
|
|
33755
33905
|
});
|
|
33756
33906
|
return JSON.parse(stdout);
|
|
33757
33907
|
} finally {
|
|
33758
|
-
(0,
|
|
33908
|
+
(0, import_node_fs31.rmSync)(scriptDir, { recursive: true, force: true });
|
|
33759
33909
|
}
|
|
33760
33910
|
}
|
|
33761
33911
|
async function readSecretStdin() {
|
|
@@ -33845,7 +33995,7 @@ function registerSecretsCommands(program3) {
|
|
|
33845
33995
|
let body;
|
|
33846
33996
|
if (o.file) {
|
|
33847
33997
|
try {
|
|
33848
|
-
body = (0,
|
|
33998
|
+
body = (0, import_node_fs31.readFileSync)((0, import_node_path29.resolve)(o.file), "utf8");
|
|
33849
33999
|
} catch (e) {
|
|
33850
34000
|
return fail(`secrets org-catalog: cannot read --file ${o.file}: ${e.message}`);
|
|
33851
34001
|
}
|
|
@@ -33981,7 +34131,7 @@ function registerSecretsCommands(program3) {
|
|
|
33981
34131
|
{
|
|
33982
34132
|
...d,
|
|
33983
34133
|
decryptRailsCredentials,
|
|
33984
|
-
removeFile: (path2) => (0,
|
|
34134
|
+
removeFile: (path2) => (0, import_node_fs31.unlinkSync)((0, import_node_path29.resolve)(o.appDir ?? process.cwd(), path2))
|
|
33985
34135
|
},
|
|
33986
34136
|
{
|
|
33987
34137
|
repo: o.repo,
|
|
@@ -34237,7 +34387,7 @@ function registerBoxCommands(program3) {
|
|
|
34237
34387
|
}
|
|
34238
34388
|
const remote = command && command.length ? command.join(" ") : void 0;
|
|
34239
34389
|
const wroteScript = o.ssh && o.script ? o.script : null;
|
|
34240
|
-
if (wroteScript) (0,
|
|
34390
|
+
if (wroteScript) (0, import_node_fs32.writeFileSync)(wroteScript, sshRecipeScript(found, remote), "utf8");
|
|
34241
34391
|
if (o.json) {
|
|
34242
34392
|
console.log(JSON.stringify({
|
|
34243
34393
|
box: found,
|
|
@@ -34311,17 +34461,17 @@ function hubGitShow(ref) {
|
|
|
34311
34461
|
return (path2) => git3(["show", `${ref}:${path2}`]);
|
|
34312
34462
|
}
|
|
34313
34463
|
function runOnBox(found, script) {
|
|
34314
|
-
const dir = (0,
|
|
34464
|
+
const dir = (0, import_node_fs32.mkdtempSync)((0, import_node_path30.join)((0, import_node_os17.tmpdir)(), "mmi-box-control-"));
|
|
34315
34465
|
try {
|
|
34316
34466
|
const recipe = (0, import_node_path30.join)(dir, "recipe.sh");
|
|
34317
|
-
(0,
|
|
34467
|
+
(0, import_node_fs32.writeFileSync)(recipe, sshRecipeScript(found, "sh -s"), "utf8");
|
|
34318
34468
|
const r = (0, import_node_child_process10.spawnSync)("bash", [recipe], { input: script, encoding: "utf8", maxBuffer: 16 * 1024 * 1024, timeout: 18e4, windowsHide: true });
|
|
34319
34469
|
if (r.status !== 0) {
|
|
34320
34470
|
throw new UnreadableError(`box control: the ssh session to ${found.name} failed (exit ${r.status ?? r.signal}): ${(r.stderr || "").trim().split("\n").slice(-3).join(" | ")}`);
|
|
34321
34471
|
}
|
|
34322
34472
|
return r.stdout;
|
|
34323
34473
|
} finally {
|
|
34324
|
-
(0,
|
|
34474
|
+
(0, import_node_fs32.rmSync)(dir, { recursive: true, force: true });
|
|
34325
34475
|
}
|
|
34326
34476
|
}
|
|
34327
34477
|
function formatControl(mode, box, rows) {
|
|
@@ -34766,6 +34916,10 @@ function classifyEnvironmentDrift(drift) {
|
|
|
34766
34916
|
}
|
|
34767
34917
|
var TRACK_ENVIRONMENT_EXCEPTIONS = {
|
|
34768
34918
|
direct: { rc: "direct release track has no rc stage" },
|
|
34919
|
+
single: {
|
|
34920
|
+
rc: "single release track has no rc stage",
|
|
34921
|
+
main: "single release track has no main branch; merges deploy the one stage"
|
|
34922
|
+
},
|
|
34769
34923
|
trunk: {
|
|
34770
34924
|
dev: "trunk release track has no dev stage",
|
|
34771
34925
|
rc: "trunk release track has no rc stage"
|
|
@@ -34934,6 +35088,7 @@ function branchProtectionPayload(current, owners, app = LOCKED_APP) {
|
|
|
34934
35088
|
}
|
|
34935
35089
|
function deployStagesForBootstrap(deployModel, track) {
|
|
34936
35090
|
if (deployModel !== "tenant-container" && deployModel !== "solo-container") return [];
|
|
35091
|
+
if (track === "single") return ["main"];
|
|
34937
35092
|
return branchesForTrack(track).map((branch) => branch === "development" ? "dev" : branch);
|
|
34938
35093
|
}
|
|
34939
35094
|
function bootstrapSetDeployCommand(repo, stage, deployModel) {
|
|
@@ -35956,12 +36111,12 @@ async function verifyTargetedSeedPr(repo, number, plan, target, expected, client
|
|
|
35956
36111
|
// src/bootstrap-commands.ts
|
|
35957
36112
|
var execGitForSeedSource = async (args) => (await execFileP("git", args, { timeout: GIT_TIMEOUT_MS })).stdout;
|
|
35958
36113
|
async function gateRenderDiff(current, rendered) {
|
|
35959
|
-
const dir = (0,
|
|
36114
|
+
const dir = (0, import_node_fs33.mkdtempSync)((0, import_node_path31.join)((0, import_node_os18.tmpdir)(), "mmi-gate-diff-"));
|
|
35960
36115
|
const before = (0, import_node_path31.join)(dir, "committed-gate.yml");
|
|
35961
36116
|
const after = (0, import_node_path31.join)(dir, "registry-render.yml");
|
|
35962
36117
|
try {
|
|
35963
|
-
(0,
|
|
35964
|
-
(0,
|
|
36118
|
+
(0, import_node_fs33.writeFileSync)(before, current);
|
|
36119
|
+
(0, import_node_fs33.writeFileSync)(after, rendered);
|
|
35965
36120
|
try {
|
|
35966
36121
|
return (await execFileP("git", ["diff", "--no-index", "--", before, after], { timeout: GIT_TIMEOUT_MS })).stdout;
|
|
35967
36122
|
} catch (e) {
|
|
@@ -35970,7 +36125,7 @@ async function gateRenderDiff(current, rendered) {
|
|
|
35970
36125
|
throw e;
|
|
35971
36126
|
}
|
|
35972
36127
|
} finally {
|
|
35973
|
-
(0,
|
|
36128
|
+
(0, import_node_fs33.rmSync)(dir, { recursive: true, force: true });
|
|
35974
36129
|
}
|
|
35975
36130
|
}
|
|
35976
36131
|
function bootstrapTrainDoctorDeps() {
|
|
@@ -36030,13 +36185,13 @@ function registerBootstrapCommands(program3) {
|
|
|
36030
36185
|
})),
|
|
36031
36186
|
pushAllowlistOwners: verifyOwners,
|
|
36032
36187
|
pushAllowlistOwnersRead: verifyOwnersRead,
|
|
36033
|
-
readLocalFile: (path2) => path2 === "projects.json" && apiProjects != null ? apiProjects : (0,
|
|
36188
|
+
readLocalFile: (path2) => path2 === "projects.json" && apiProjects != null ? apiProjects : (0, import_node_fs33.existsSync)(path2) ? (0, import_node_fs33.readFileSync)(path2, "utf8") : null,
|
|
36034
36189
|
// requiredGcpApis is stored as an array by a JSON write, but `org project set --var KEY=VALUE` stores a raw
|
|
36035
36190
|
// comma-string — accept either so the seeded value verifies regardless of how it was written.
|
|
36036
36191
|
// #3689: the same committed map the org access audit reads (#3664), so a sanctioned admin is not a
|
|
36037
36192
|
// permanent bootstrap failure on one surface and an intended state on the other. Absent file → no
|
|
36038
36193
|
// sanction, which is the pre-#3664 behaviour.
|
|
36039
|
-
sanctionedAdmins: (0,
|
|
36194
|
+
sanctionedAdmins: (0, import_node_fs33.existsSync)("access-matrix.json") ? entriesValueByCanonicalRepo(loadSanctionedAdmins((0, import_node_fs33.readFileSync)("access-matrix.json", "utf8")), repo) : void 0,
|
|
36040
36195
|
requiredGcpApis: (() => {
|
|
36041
36196
|
const v = meta?.requiredGcpApis;
|
|
36042
36197
|
if (Array.isArray(v)) return v;
|
|
@@ -36114,14 +36269,14 @@ function registerBootstrapCommands(program3) {
|
|
|
36114
36269
|
bootstrap.command("drift").description("#3818: compare every org-owned whole-file seed against MMI-Hub's copy across the registry roster; read-only").option("--repo <owner/repo>", "audit one repo instead of the roster (never a fleet verdict)").option("--json", "machine-readable output").action(async () => {
|
|
36115
36270
|
const o = { repo: rawValue("--repo", ""), json: rawFlag("--json") };
|
|
36116
36271
|
const manifestPath = "skills/bootstrap/seeds/manifest.json";
|
|
36117
|
-
if (!(0,
|
|
36272
|
+
if (!(0, import_node_fs33.existsSync)(manifestPath)) return fail(`bootstrap drift: ${manifestPath} not found; run from the MMI-Hub repo root \u2014 the Hub's copies ARE the reference this compares against`);
|
|
36118
36273
|
const seedSource = await resolveHubSeedSource(execGitForSeedSource);
|
|
36119
36274
|
if (!seedSource.ok) return fail(`bootstrap drift: ${seedSource.reason}`);
|
|
36120
|
-
const manifest = loadBootstrapSeeds((0,
|
|
36275
|
+
const manifest = loadBootstrapSeeds((0, import_node_fs33.readFileSync)(manifestPath, "utf8"));
|
|
36121
36276
|
const hubContents = /* @__PURE__ */ new Map();
|
|
36122
36277
|
for (const s of manifest.seeds) {
|
|
36123
36278
|
if (s.ownership !== "org" || s.source !== "self") continue;
|
|
36124
|
-
hubContents.set(s.target, (0,
|
|
36279
|
+
hubContents.set(s.target, (0, import_node_fs33.existsSync)(s.target) ? (0, import_node_fs33.readFileSync)(s.target, "utf8") : null);
|
|
36125
36280
|
}
|
|
36126
36281
|
let targets;
|
|
36127
36282
|
let classOf = (_repo) => "deployable";
|
|
@@ -36329,24 +36484,24 @@ function registerBootstrapCommands(program3) {
|
|
|
36329
36484
|
return;
|
|
36330
36485
|
}
|
|
36331
36486
|
const manifestPath = "skills/bootstrap/seeds/manifest.json";
|
|
36332
|
-
if (!(0,
|
|
36487
|
+
if (!(0, import_node_fs33.existsSync)(manifestPath)) return fail(`bootstrap apply: ${manifestPath} not found; bootstrap runs from the MMI-Hub repo root by design \u2014 it stamps org-level resources (Project, Ruleset, secrets, access) through the GitHub App, which is only authorized from the Hub checkout`);
|
|
36333
36488
|
const seedSource = await resolveHubSeedSource(execGitForSeedSource);
|
|
36334
36489
|
if (!seedSource.ok) return fail(`bootstrap apply: ${seedSource.reason}`);
|
|
36335
|
-
const manifest = loadBootstrapSeeds((0,
|
|
36490
|
+
const manifest = loadBootstrapSeeds((0, import_node_fs33.readFileSync)(manifestPath, "utf8"));
|
|
36336
36491
|
const baseBranch = o.class === "content" ? "main" : "development";
|
|
36337
36492
|
const slug = parsedRepo.slug;
|
|
36338
36493
|
const onlyTarget = o.fromConfig && o.only.trim() === "gate.yml" ? ".github/workflows/gate.yml" : o.only.trim();
|
|
36339
36494
|
const gh2 = async (args) => execFileP("gh", args, { timeout: 2e4 });
|
|
36340
|
-
const readFile10 = (p) => (0,
|
|
36495
|
+
const readFile10 = (p) => (0, import_node_fs33.existsSync)(p) ? (0, import_node_fs33.readFileSync)(p, "utf8") : null;
|
|
36341
36496
|
const enc = (p) => p.split("/").map(encodeURIComponent).join("/");
|
|
36342
36497
|
const putSeed = async (target, content, ref, sha) => {
|
|
36343
36498
|
const tmp = (0, import_node_path31.join)((0, import_node_os18.tmpdir)(), `mmi-seed-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
|
|
36344
|
-
(0,
|
|
36499
|
+
(0, import_node_fs33.writeFileSync)(tmp, JSON.stringify(contentPutBody(target, content, ref, sha)), "utf8");
|
|
36345
36500
|
try {
|
|
36346
36501
|
await gh2(contentPutInputArgs(repo, target, tmp));
|
|
36347
36502
|
} finally {
|
|
36348
36503
|
try {
|
|
36349
|
-
(0,
|
|
36504
|
+
(0, import_node_fs33.unlinkSync)(tmp);
|
|
36350
36505
|
} catch {
|
|
36351
36506
|
}
|
|
36352
36507
|
}
|
|
@@ -36982,10 +37137,10 @@ LIVE apply to ${repo}:
|
|
|
36982
37137
|
bootstrap.command("propagate").description("#4238: re-entrant canary\u2192wave tick \u2014 plan (or, with --execute, open) per-repo PRs fanning an org-owned seed out to the fleet").option("--target <path>", "the manifest target to propagate (an org-owned whole file or declared Hub-managed block)").option("--execute", "LIVE tick via gh (master-gated) \u2014 opens/reuses per-repo seed-propagate PRs; dry-run prints the plan only").option("--json", "machine-readable output").action(async () => {
|
|
36983
37138
|
const o = { target: rawValue("--target", ""), execute: rawFlag("--execute"), json: rawFlag("--json") };
|
|
36984
37139
|
const manifestPath = "skills/bootstrap/seeds/manifest.json";
|
|
36985
|
-
if (!(0,
|
|
37140
|
+
if (!(0, import_node_fs33.existsSync)(manifestPath)) return fail(`bootstrap propagate: ${manifestPath} not found; run from the MMI-Hub repo root \u2014 the Hub's copies ARE the desired state this tick propagates`);
|
|
36986
37141
|
const seedSource = await resolveHubSeedSource(execGitForSeedSource);
|
|
36987
37142
|
if (!seedSource.ok) return fail(`bootstrap propagate: ${seedSource.reason}`);
|
|
36988
|
-
const manifest = loadBootstrapSeeds((0,
|
|
37143
|
+
const manifest = loadBootstrapSeeds((0, import_node_fs33.readFileSync)(manifestPath, "utf8"));
|
|
36989
37144
|
const propagatable = manifest.seeds.filter(isPropagatableSeed);
|
|
36990
37145
|
if (!o.target) {
|
|
36991
37146
|
return fail(`bootstrap propagate: --target <path> is required \u2014 one of:
|
|
@@ -36994,9 +37149,9 @@ LIVE apply to ${repo}:
|
|
|
36994
37149
|
const seed = propagatable.find((s) => s.target === o.target);
|
|
36995
37150
|
if (!seed) return fail(`bootstrap propagate: --target '${o.target}' names no centrally propagatable seed in ${manifestPath}. Propagatable targets:
|
|
36996
37151
|
${propagatable.map((s) => s.target).join("\n ")}`);
|
|
36997
|
-
if (!seed.managedBlock && !(0,
|
|
36998
|
-
const hubContent = seed.managedBlock ? null : (0,
|
|
36999
|
-
const readSeedFile2 = (path2) => (0,
|
|
37152
|
+
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`);
|
|
37153
|
+
const hubContent = seed.managedBlock ? null : (0, import_node_fs33.readFileSync)(seed.target, "utf8");
|
|
37154
|
+
const readSeedFile2 = (path2) => (0, import_node_fs33.existsSync)(path2) ? (0, import_node_fs33.readFileSync)(path2, "utf8") : null;
|
|
37000
37155
|
const isWorkflowSeed = seed.target.startsWith(".github/workflows/");
|
|
37001
37156
|
const cfg = await loadConfig();
|
|
37002
37157
|
const projects = await fetchProjectsList(registryClientDeps(cfg));
|
|
@@ -37005,9 +37160,9 @@ LIVE apply to ${repo}:
|
|
|
37005
37160
|
}
|
|
37006
37161
|
const rosterRepos = collectRegistryRepos(projects).filter((r) => r.toLowerCase() !== "mutmutco/mmi-hub");
|
|
37007
37162
|
let independentCount = rosterRepos.length;
|
|
37008
|
-
if ((0,
|
|
37163
|
+
if ((0, import_node_fs33.existsSync)("projects.json")) {
|
|
37009
37164
|
try {
|
|
37010
|
-
const local = JSON.parse((0,
|
|
37165
|
+
const local = JSON.parse((0, import_node_fs33.readFileSync)("projects.json", "utf8"));
|
|
37011
37166
|
const localRepos = /* @__PURE__ */ new Set();
|
|
37012
37167
|
for (const p of local.projects ?? []) for (const r of p.repos ?? []) {
|
|
37013
37168
|
const full = (r.includes("/") ? r : `mutmutco/${r}`).toLowerCase();
|
|
@@ -37157,7 +37312,7 @@ LIVE apply to ${repo}:
|
|
|
37157
37312
|
if (plan.refusedNoCanary) return fail("bootstrap propagate --execute: no canary declared for this target \u2014 refusing to write (set seedCanary:true on exactly one registry repo)");
|
|
37158
37313
|
const headSha = seedSource.sha;
|
|
37159
37314
|
const sourceBlob = (await execGitForSeedSource(["rev-parse", `${headSha}:${seedSourcePath(seed)}`])).trim();
|
|
37160
|
-
const runbookUnaffected = (0,
|
|
37315
|
+
const runbookUnaffected = (0, import_node_fs33.existsSync)(RUNBOOK_UNAFFECTED_PATH) ? runbookUnaffectedReason(JSON.parse((0, import_node_fs33.readFileSync)(RUNBOOK_UNAFFECTED_PATH, "utf8")), seed.target, sourceBlob) : void 0;
|
|
37161
37316
|
for (const rec of plan.records) {
|
|
37162
37317
|
if (rec.action !== "open-pr") continue;
|
|
37163
37318
|
const baseBranch = classOf(rec.repo) === "content" ? "main" : "development";
|
|
@@ -37182,12 +37337,12 @@ LIVE apply to ${repo}:
|
|
|
37182
37337
|
const tmp = (0, import_node_path31.join)((0, import_node_os18.tmpdir)(), `mmi-propagate-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
|
|
37183
37338
|
const desiredContent = desiredByRepo.get(rec.repo);
|
|
37184
37339
|
if (desiredContent == null) return fail(`bootstrap propagate: no resolved content for ${rec.repo} ${seed.target} \u2014 refusing to write`);
|
|
37185
|
-
(0,
|
|
37340
|
+
(0, import_node_fs33.writeFileSync)(tmp, JSON.stringify(contentPutBody(seed.target, desiredContent, branch, existingSha, runbookUnaffected)), "utf8");
|
|
37186
37341
|
try {
|
|
37187
37342
|
await gh2(contentPutInputArgs(rec.repo, seed.target, tmp));
|
|
37188
37343
|
} finally {
|
|
37189
37344
|
try {
|
|
37190
|
-
(0,
|
|
37345
|
+
(0, import_node_fs33.unlinkSync)(tmp);
|
|
37191
37346
|
} catch {
|
|
37192
37347
|
}
|
|
37193
37348
|
}
|
|
@@ -37256,10 +37411,10 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
|
|
|
37256
37411
|
return fail(`bootstrap rollback: ${e.message}`);
|
|
37257
37412
|
}
|
|
37258
37413
|
const manifestPath = "skills/bootstrap/seeds/manifest.json";
|
|
37259
|
-
if (!(0,
|
|
37414
|
+
if (!(0, import_node_fs33.existsSync)(manifestPath)) return fail(`bootstrap rollback: ${manifestPath} not found; run from the MMI-Hub repo root \u2014 the manifest names which targets are org-owned and therefore propagated (and rollback-able)`);
|
|
37260
37415
|
const seedSource = await resolveHubSeedSource(execGitForSeedSource);
|
|
37261
37416
|
if (!seedSource.ok) return fail(`bootstrap rollback: ${seedSource.reason}`);
|
|
37262
|
-
const manifest = loadBootstrapSeeds((0,
|
|
37417
|
+
const manifest = loadBootstrapSeeds((0, import_node_fs33.readFileSync)(manifestPath, "utf8"));
|
|
37263
37418
|
const propagatable = manifest.seeds.filter(isPropagatableSeed);
|
|
37264
37419
|
if (!o.target) {
|
|
37265
37420
|
return fail(`bootstrap rollback: --target <path> is required \u2014 one of:
|
|
@@ -37276,10 +37431,10 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
|
|
|
37276
37431
|
const enc = (p) => p.split("/").map(encodeURIComponent).join("/");
|
|
37277
37432
|
let candidates;
|
|
37278
37433
|
if (o.record) {
|
|
37279
|
-
if (!(0,
|
|
37434
|
+
if (!(0, import_node_fs33.existsSync)(o.record)) return fail(`bootstrap rollback: --record '${o.record}' not found`);
|
|
37280
37435
|
let parsed;
|
|
37281
37436
|
try {
|
|
37282
|
-
parsed = JSON.parse((0,
|
|
37437
|
+
parsed = JSON.parse((0, import_node_fs33.readFileSync)(o.record, "utf8"));
|
|
37283
37438
|
} catch (e) {
|
|
37284
37439
|
return fail(`bootstrap rollback: --record '${o.record}' is not valid JSON: ${e.message}`);
|
|
37285
37440
|
}
|
|
@@ -37357,12 +37512,12 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
|
|
|
37357
37512
|
existingSha = void 0;
|
|
37358
37513
|
}
|
|
37359
37514
|
const tmp = (0, import_node_path31.join)((0, import_node_os18.tmpdir)(), `mmi-rollback-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
|
|
37360
|
-
(0,
|
|
37515
|
+
(0, import_node_fs33.writeFileSync)(tmp, JSON.stringify(contentPutBody(seed.target, preSeedContent, plan.branch, existingSha)), "utf8");
|
|
37361
37516
|
try {
|
|
37362
37517
|
await gh2(contentPutInputArgs(repo, seed.target, tmp));
|
|
37363
37518
|
} finally {
|
|
37364
37519
|
try {
|
|
37365
|
-
(0,
|
|
37520
|
+
(0, import_node_fs33.unlinkSync)(tmp);
|
|
37366
37521
|
} catch {
|
|
37367
37522
|
}
|
|
37368
37523
|
}
|
|
@@ -37819,7 +37974,7 @@ async function waitSuiteDev(deps, opts) {
|
|
|
37819
37974
|
}
|
|
37820
37975
|
|
|
37821
37976
|
// src/suite-train.ts
|
|
37822
|
-
var
|
|
37977
|
+
var import_node_fs34 = require("node:fs");
|
|
37823
37978
|
var import_node_path32 = require("node:path");
|
|
37824
37979
|
var import_node_crypto15 = require("node:crypto");
|
|
37825
37980
|
|
|
@@ -37906,7 +38061,7 @@ function suiteReleaseTag(rc) {
|
|
|
37906
38061
|
function readSuiteCut(path2) {
|
|
37907
38062
|
let raw;
|
|
37908
38063
|
try {
|
|
37909
|
-
raw = (0,
|
|
38064
|
+
raw = (0, import_node_fs34.readFileSync)(path2, "utf8");
|
|
37910
38065
|
} catch (e) {
|
|
37911
38066
|
if (e.code === "ENOENT") return void 0;
|
|
37912
38067
|
throw e;
|
|
@@ -37922,11 +38077,11 @@ function readSuiteCut(path2) {
|
|
|
37922
38077
|
return record;
|
|
37923
38078
|
}
|
|
37924
38079
|
function writeSuiteCut(path2, record) {
|
|
37925
|
-
(0,
|
|
38080
|
+
(0, import_node_fs34.mkdirSync)((0, import_node_path32.dirname)(path2), { recursive: true });
|
|
37926
38081
|
const temp = `${path2}.${(0, import_node_crypto15.randomBytes)(8).toString("hex")}.tmp`;
|
|
37927
38082
|
try {
|
|
37928
|
-
(0,
|
|
37929
|
-
(0,
|
|
38083
|
+
(0, import_node_fs34.writeFileSync)(temp, JSON.stringify(record, null, 2), { flag: "wx" });
|
|
38084
|
+
(0, import_node_fs34.renameSync)(temp, path2);
|
|
37930
38085
|
} catch (e) {
|
|
37931
38086
|
throw new Error(`suite cut record write failed at ${path2}: ${e.message}; stop, verify the file before retrying`);
|
|
37932
38087
|
}
|
|
@@ -37975,25 +38130,25 @@ async function suiteMarkAbandoned(deps, ownerGo = false) {
|
|
|
37975
38130
|
return tags.map((t) => `${t.repo}@${t.tag}`);
|
|
37976
38131
|
}
|
|
37977
38132
|
async function retireFailedLeadRcLedger(deps, ownerGo) {
|
|
37978
|
-
if (!(0,
|
|
38133
|
+
if (!(0, import_node_fs34.existsSync)(deps.ledgerPath)) return void 0;
|
|
37979
38134
|
return withLedgerLock(deps.ledgerPath, async (fence) => {
|
|
37980
|
-
const ledger = parseReleaseLedger((0,
|
|
38135
|
+
const ledger = parseReleaseLedger((0, import_node_fs34.readFileSync)(deps.ledgerPath, "utf8"));
|
|
37981
38136
|
const states = Object.values(ledger.phases).map((p) => p.state);
|
|
37982
38137
|
if (ledger.repo !== SUITE_REPO || ledger.lane !== "rcand" || ledger.phases.promotion.state === "complete" || !states.includes("failed")) return void 0;
|
|
37983
38138
|
if (!ownerGo) throw new Error(`the lead's failed rcand ledger for ${ledger.tag} blocks every train; retire it with suite abandon --owner-go`);
|
|
37984
38139
|
if ((await deps.rcHead())?.toLowerCase() === ledger.tagSha.toLowerCase()) throw new Error(`origin rc already points at ${ledger.tag}; it was promoted, so its ledger is not retired`);
|
|
37985
38140
|
const archive = (0, import_node_path32.join)((0, import_node_path32.dirname)(deps.ledgerPath), `phases.archive-${ledger.tag}.json`);
|
|
37986
|
-
if ((0,
|
|
38141
|
+
if ((0, import_node_fs34.existsSync)(archive)) throw new Error(`ledger archive already exists at ${archive}; inspect before retiring again`);
|
|
37987
38142
|
await deps.markAbandoned(SUITE_REPO, ledger.tag, ledger.tagSha);
|
|
37988
|
-
await fence(() => (0,
|
|
38143
|
+
await fence(() => (0, import_node_fs34.renameSync)(deps.ledgerPath, archive));
|
|
37989
38144
|
return `${ledger.tag} (ledger archived to ${archive})`;
|
|
37990
38145
|
});
|
|
37991
38146
|
}
|
|
37992
38147
|
function suiteAbandon(recordPath, ownerGo = false, now = /* @__PURE__ */ new Date()) {
|
|
37993
38148
|
const record = abandonableCut(recordPath, ownerGo);
|
|
37994
38149
|
const archive = `${recordPath}.abandoned-${record.leadDevelopment.slice(0, 12)}-${now.toISOString().replace(/[:.]/g, "")}.json`;
|
|
37995
|
-
if ((0,
|
|
37996
|
-
(0,
|
|
38150
|
+
if ((0, import_node_fs34.existsSync)(archive)) throw new Error(`abandoned-cut archive already exists at ${archive}; inspect before abandoning again`);
|
|
38151
|
+
(0, import_node_fs34.renameSync)(recordPath, archive);
|
|
37997
38152
|
return { archive, orphanTags: record.members.filter((m) => m.tag).map((m) => `${m.repo}@${m.tag}`) };
|
|
37998
38153
|
}
|
|
37999
38154
|
async function suiteRestoreMainPins(deps) {
|
|
@@ -38076,12 +38231,12 @@ async function suiteRcandRun(deps, opts) {
|
|
|
38076
38231
|
}
|
|
38077
38232
|
if ((record?.announcement === "sent" || record?.announcement === "skipped") && record.leadReleased) {
|
|
38078
38233
|
const archive = `${deps.recordPath}.${record.leadRcTag}.json`;
|
|
38079
|
-
if ((0,
|
|
38080
|
-
(0,
|
|
38234
|
+
if ((0, import_node_fs34.existsSync)(archive)) throw new Error(`suite cut archive already exists at ${archive}; inspect before a new cut`);
|
|
38235
|
+
(0, import_node_fs34.renameSync)(deps.recordPath, archive);
|
|
38081
38236
|
record = void 0;
|
|
38082
38237
|
}
|
|
38083
38238
|
if (record && !record.pinPr && !record.leadRcTag && record.members.every((m) => !m.tag)) {
|
|
38084
|
-
(0,
|
|
38239
|
+
(0, import_node_fs34.rmSync)(deps.recordPath, { force: true });
|
|
38085
38240
|
record = void 0;
|
|
38086
38241
|
}
|
|
38087
38242
|
if (!record) {
|
|
@@ -38135,7 +38290,7 @@ async function suiteRcandRun(deps, opts) {
|
|
|
38135
38290
|
quiet.push(member);
|
|
38136
38291
|
}
|
|
38137
38292
|
if (record.members.every((m) => m.carried || quiet.includes(m)) && await deps.contains(SUITE_REPO, record.leadDevelopment, record.leadPreviousRc)) {
|
|
38138
|
-
(0,
|
|
38293
|
+
(0, import_node_fs34.rmSync)(deps.recordPath, { force: true });
|
|
38139
38294
|
throw new Error("nothing to promote: neither MM-Work nor any module has new development commits since its rc; no suite cut started");
|
|
38140
38295
|
}
|
|
38141
38296
|
for (const member of quiet) {
|
|
@@ -38153,7 +38308,7 @@ async function suiteRcandRun(deps, opts) {
|
|
|
38153
38308
|
}
|
|
38154
38309
|
if (refusals.length) {
|
|
38155
38310
|
const untouched = record.members.every((m) => !m.tag) && !record.pinPr;
|
|
38156
|
-
if (untouched) (0,
|
|
38311
|
+
if (untouched) (0, import_node_fs34.rmSync)(deps.recordPath, { force: true });
|
|
38157
38312
|
throw new Error(`module rc serving is not ready; ${untouched ? "no suite cut started" : "no new tag was cut"}:
|
|
38158
38313
|
${refusals.join("\n")}
|
|
38159
38314
|
Each module must ship a live release that bind-mounts <deployPath>/data read-only and serves <data>/rc/module.js at /rc/module.js (docs/Guides/suite-trains.md).`);
|
|
@@ -38349,7 +38504,7 @@ var hotfixRecordPath = (deps) => (0, import_node_path32.join)((0, import_node_pa
|
|
|
38349
38504
|
function readSuiteHotfix(path2) {
|
|
38350
38505
|
let raw;
|
|
38351
38506
|
try {
|
|
38352
|
-
raw = (0,
|
|
38507
|
+
raw = (0, import_node_fs34.readFileSync)(path2, "utf8");
|
|
38353
38508
|
} catch (e) {
|
|
38354
38509
|
if (e.code === "ENOENT") return void 0;
|
|
38355
38510
|
throw e;
|
|
@@ -38392,7 +38547,7 @@ async function suiteHotfix(deps, opts) {
|
|
|
38392
38547
|
if (completed) record = void 0;
|
|
38393
38548
|
if (record && record.repo !== found.repo) throw new Error(`an unfinished suite hotfix for ${record.repo} is recorded; finish it (rerun with that member) first`);
|
|
38394
38549
|
if (!record?.tag) await deps.validateHotfixSummary();
|
|
38395
|
-
if (completed) (0,
|
|
38550
|
+
if (completed) (0, import_node_fs34.renameSync)(path2, `${path2}.${completed.leadTag}.json`);
|
|
38396
38551
|
const rec = record ?? { schema: "mmi-suite-hotfix/v1", member: found.id, repo: found.repo, from: opts.from, ...opts.ack?.length ? { ack: opts.ack } : {} };
|
|
38397
38552
|
const save = () => writeSuiteHotfix(path2, rec);
|
|
38398
38553
|
save();
|
|
@@ -38661,7 +38816,7 @@ async function runRcDataSwitch(deps, opts) {
|
|
|
38661
38816
|
// src/suite-train-io.ts
|
|
38662
38817
|
var import_node_child_process18 = require("node:child_process");
|
|
38663
38818
|
var import_node_path45 = require("node:path");
|
|
38664
|
-
var
|
|
38819
|
+
var import_node_fs47 = require("node:fs");
|
|
38665
38820
|
var import_node_path46 = require("node:path");
|
|
38666
38821
|
init_cli_shared();
|
|
38667
38822
|
|
|
@@ -40338,7 +40493,7 @@ function checkHotfixCarries(options) {
|
|
|
40338
40493
|
}
|
|
40339
40494
|
|
|
40340
40495
|
// src/merge-cleanup.ts
|
|
40341
|
-
var
|
|
40496
|
+
var import_node_fs36 = require("node:fs");
|
|
40342
40497
|
var import_node_path34 = require("node:path");
|
|
40343
40498
|
var import_node_os19 = require("node:os");
|
|
40344
40499
|
init_cli_shared();
|
|
@@ -40767,7 +40922,7 @@ function renderPrLandTable(entries) {
|
|
|
40767
40922
|
|
|
40768
40923
|
// src/test-policy-core.ts
|
|
40769
40924
|
var import_node_child_process13 = require("node:child_process");
|
|
40770
|
-
var
|
|
40925
|
+
var import_node_fs35 = require("node:fs");
|
|
40771
40926
|
var import_node_path33 = require("node:path");
|
|
40772
40927
|
|
|
40773
40928
|
// src/test-command-policy-shared.mjs
|
|
@@ -41337,7 +41492,7 @@ function loadPolicySource(root, explicitRef, diffBase) {
|
|
|
41337
41492
|
}
|
|
41338
41493
|
function readFileOrNull2(path2) {
|
|
41339
41494
|
try {
|
|
41340
|
-
return (0,
|
|
41495
|
+
return (0, import_node_fs35.readFileSync)(path2, "utf8");
|
|
41341
41496
|
} catch {
|
|
41342
41497
|
return null;
|
|
41343
41498
|
}
|
|
@@ -41365,10 +41520,10 @@ function classify(changed, policy, present = () => false) {
|
|
|
41365
41520
|
const removedProtected = [...removed].filter((p) => protectedBy.has(p)).map((p) => ({ path: p, why: protectedBy.get(p) ?? "" }));
|
|
41366
41521
|
return { mandatoryHits, untestedHits, testChanges, meaningfulTestChanges, addedTests, removedProtected };
|
|
41367
41522
|
}
|
|
41368
|
-
function unresolvedProtectedEntries(policy, root, exists = (path2) => (0,
|
|
41523
|
+
function unresolvedProtectedEntries(policy, root, exists = (path2) => (0, import_node_fs35.existsSync)(path2)) {
|
|
41369
41524
|
return (policy.protected ?? []).map((p) => p.path).filter((p) => !exists((0, import_node_path33.join)(root, p)));
|
|
41370
41525
|
}
|
|
41371
|
-
function unresolvedSatisfiers(policy, root, exists = (path2) => (0,
|
|
41526
|
+
function unresolvedSatisfiers(policy, root, exists = (path2) => (0, import_node_fs35.existsSync)(path2)) {
|
|
41372
41527
|
const declared = (policy.mandatory ?? []).flatMap((m) => m.satisfiedBy ?? []);
|
|
41373
41528
|
return [...new Set(declared)].filter((p) => !exists((0, import_node_path33.join)(root, p)));
|
|
41374
41529
|
}
|
|
@@ -41509,7 +41664,7 @@ function runTestPolicy(root, deps = {}) {
|
|
|
41509
41664
|
}
|
|
41510
41665
|
const loaded = deps.policy ? { policy: deps.policy, source: { ref: null, sha: null, path: POLICY_FILE } } : loadPolicySource(root, deps.policyRef, deps.base);
|
|
41511
41666
|
const { policy, source: policySource } = loaded;
|
|
41512
|
-
const exists = deps.exists ?? ((path2) => (0,
|
|
41667
|
+
const exists = deps.exists ?? ((path2) => (0, import_node_fs35.existsSync)(path2));
|
|
41513
41668
|
const counts = { mandatoryCount: (policy.mandatory ?? []).length, protectedCount: (policy.protected ?? []).length };
|
|
41514
41669
|
const base = deps.changed ? "(injected)" : deps.policyRef ? resolveHotfixBase(root) : resolveBase(root, deps.base);
|
|
41515
41670
|
const refusal = deps.changed ? null : untrustworthyRange(root, base);
|
|
@@ -41807,13 +41962,13 @@ function resolveSquashMergeBodyText(commits, allowedClosing, cwd) {
|
|
|
41807
41962
|
return rewritten === base ? null : rewritten;
|
|
41808
41963
|
}
|
|
41809
41964
|
function writeSquashBodyFile(body) {
|
|
41810
|
-
const dir = (0,
|
|
41965
|
+
const dir = (0, import_node_fs36.mkdtempSync)((0, import_node_path34.join)((0, import_node_os19.tmpdir)(), "mmi-squash-body-"));
|
|
41811
41966
|
const path2 = (0, import_node_path34.join)(dir, "body.txt");
|
|
41812
|
-
(0,
|
|
41967
|
+
(0, import_node_fs36.writeFileSync)(path2, body.endsWith("\n") ? body : `${body}
|
|
41813
41968
|
`, "utf8");
|
|
41814
41969
|
return { path: path2, cleanup: () => {
|
|
41815
41970
|
try {
|
|
41816
|
-
(0,
|
|
41971
|
+
(0, import_node_fs36.rmSync)(dir, { recursive: true, force: true });
|
|
41817
41972
|
} catch {
|
|
41818
41973
|
}
|
|
41819
41974
|
} };
|
|
@@ -42052,6 +42207,7 @@ var readApi = async (args) => {
|
|
|
42052
42207
|
const env = await ghReadEnv();
|
|
42053
42208
|
return (await execFileP("gh", ["api", ...args], {
|
|
42054
42209
|
timeout: 2e4,
|
|
42210
|
+
maxBuffer: 16 * 1024 * 1024,
|
|
42055
42211
|
...env ? { env } : {}
|
|
42056
42212
|
})).stdout;
|
|
42057
42213
|
};
|
|
@@ -42081,7 +42237,7 @@ async function readPrMergeQueue(pr, repo, gh2 = readApi) {
|
|
|
42081
42237
|
return result.pullRequest;
|
|
42082
42238
|
}
|
|
42083
42239
|
async function findPrMergeGroupRun(pr, repo, base, gh2 = readApi) {
|
|
42084
|
-
const pages = JSON.parse(await gh2([`repos/${repo}/actions/runs?event=merge_group&per_page=100
|
|
42240
|
+
const pages = [JSON.parse(await gh2([`repos/${repo}/actions/runs?event=merge_group&per_page=100&exclude_pull_requests=true`]))];
|
|
42085
42241
|
const prefix = `gh-readonly-queue/${base}/pr-${pr}-`;
|
|
42086
42242
|
const run = pages.flatMap((page) => page.workflow_runs).filter((run2) => run2.head_branch?.startsWith(prefix)).sort((a, b) => b.created_at.localeCompare(a.created_at) || b.id - a.id)[0];
|
|
42087
42243
|
return run ? { id: run.id, url: run.html_url, conclusion: run.conclusion } : void 0;
|
|
@@ -42102,7 +42258,7 @@ function prMergeQueueLine(result) {
|
|
|
42102
42258
|
}
|
|
42103
42259
|
|
|
42104
42260
|
// src/project-info-sync.ts
|
|
42105
|
-
var
|
|
42261
|
+
var import_node_fs37 = require("node:fs");
|
|
42106
42262
|
var import_node_path35 = require("node:path");
|
|
42107
42263
|
var UPDATE_PROJECT_INFO = `mutation($projectId: ID!, $shortDescription: String!, $readme: String!) {
|
|
42108
42264
|
updateProjectV2(input: { projectId: $projectId, shortDescription: $shortDescription, readme: $readme }) {
|
|
@@ -42151,13 +42307,13 @@ function sharedName(entries, fallback) {
|
|
|
42151
42307
|
function buildProjectInfoSyncPlan(targetRepo2, project2, projects, repoRoot2) {
|
|
42152
42308
|
if (!project2.projectId) throw new Error(`org project sync-info: ${targetRepo2} registry META has no projectId`);
|
|
42153
42309
|
const readmePath = (0, import_node_path35.join)(repoRoot2, "README.md");
|
|
42154
|
-
if (!(0,
|
|
42310
|
+
if (!(0, import_node_fs37.existsSync)(readmePath)) throw new Error(`org project sync-info: ${targetRepo2} has no README.md`);
|
|
42155
42311
|
const entries = entriesFor(project2, projects);
|
|
42156
42312
|
const memberRepos = [...new Set(entries.flatMap((entry) => entry.repos ?? []))].filter((repo) => /^[^/]+\/[^/]+$/.test(repo)).sort((a, b) => a.localeCompare(b));
|
|
42157
42313
|
const projectName = sharedName(entries, project2.name?.trim() || targetRepo2.split("/").pop() || targetRepo2);
|
|
42158
42314
|
if (!memberRepos.length) throw new Error(`org project sync-info: project ${projectName} has no registered member repos`);
|
|
42159
42315
|
const entryNames = entries.map((entry) => entry.name?.trim()).filter((name) => Boolean(name));
|
|
42160
|
-
const shortDescription = memberRepos.length === 1 ? shortDescriptionFromReadme((0,
|
|
42316
|
+
const shortDescription = memberRepos.length === 1 ? shortDescriptionFromReadme((0, import_node_fs37.readFileSync)(readmePath, "utf8")) : `Shared work across ${new Intl.ListFormat("en", { type: "conjunction" }).format(entryNames)}.`;
|
|
42161
42317
|
const lines2 = [
|
|
42162
42318
|
`# ${projectName}`,
|
|
42163
42319
|
"",
|
|
@@ -42176,8 +42332,8 @@ function buildProjectInfoSyncPlan(targetRepo2, project2, projects, repoRoot2) {
|
|
|
42176
42332
|
const targetBase = `https://github.com/${targetRepo2}`;
|
|
42177
42333
|
const targetBranch = branchFor(targetRepo2, projects);
|
|
42178
42334
|
const orgDocs = [
|
|
42179
|
-
(0,
|
|
42180
|
-
(0,
|
|
42335
|
+
(0, import_node_fs37.existsSync)((0, import_node_path35.join)(repoRoot2, "architecture.md")) ? `- [Hub architecture](${targetBase}/blob/${targetBranch}/architecture.md)` : "",
|
|
42336
|
+
(0, import_node_fs37.existsSync)((0, import_node_path35.join)(repoRoot2, "docs", "Architecture", "agentic-dev-environment.md")) ? `- [Agentic development environment](${targetBase}/blob/${targetBranch}/docs/Architecture/agentic-dev-environment.md)` : ""
|
|
42181
42337
|
].filter(Boolean);
|
|
42182
42338
|
if (orgDocs.length) lines2.push("", "## Organisation docs", "", ...orgDocs);
|
|
42183
42339
|
return { projectId: project2.projectId, projectName, targetRepo: targetRepo2, memberRepos, shortDescription, readme: `${lines2.join("\n")}
|
|
@@ -42199,7 +42355,7 @@ async function syncProjectInfo(plan, client, apply) {
|
|
|
42199
42355
|
}
|
|
42200
42356
|
|
|
42201
42357
|
// src/train-commands.ts
|
|
42202
|
-
var
|
|
42358
|
+
var import_node_fs38 = require("node:fs");
|
|
42203
42359
|
var import_node_path36 = require("node:path");
|
|
42204
42360
|
init_cli_shared();
|
|
42205
42361
|
init_clean_exit();
|
|
@@ -42215,7 +42371,7 @@ function resolveReleaseBumpIntent(raw) {
|
|
|
42215
42371
|
}
|
|
42216
42372
|
function readRepoVersion() {
|
|
42217
42373
|
try {
|
|
42218
|
-
return JSON.parse((0,
|
|
42374
|
+
return JSON.parse((0, import_node_fs38.readFileSync)((0, import_node_path36.join)(process.cwd(), ".claude-plugin", "plugin.json"), "utf8")).version || void 0;
|
|
42219
42375
|
} catch {
|
|
42220
42376
|
return void 0;
|
|
42221
42377
|
}
|
|
@@ -42580,7 +42736,7 @@ async function openSuitePinPr(deps, input) {
|
|
|
42580
42736
|
|
|
42581
42737
|
// src/command-register-collaboration.ts
|
|
42582
42738
|
var import_node_child_process17 = require("node:child_process");
|
|
42583
|
-
var
|
|
42739
|
+
var import_node_fs46 = require("node:fs");
|
|
42584
42740
|
var import_promises8 = require("node:fs/promises");
|
|
42585
42741
|
init_clean_exit();
|
|
42586
42742
|
init_cli_shared();
|
|
@@ -42714,7 +42870,7 @@ init_github_client();
|
|
|
42714
42870
|
init_github_quota();
|
|
42715
42871
|
|
|
42716
42872
|
// src/issue-commands.ts
|
|
42717
|
-
var
|
|
42873
|
+
var import_node_fs39 = require("node:fs");
|
|
42718
42874
|
var import_node_crypto16 = require("node:crypto");
|
|
42719
42875
|
init_cli_shared();
|
|
42720
42876
|
init_clean_exit();
|
|
@@ -42907,7 +43063,7 @@ async function editIssue(client, options, deps = {}) {
|
|
|
42907
43063
|
const url = `https://github.com/${repo}/issues/${parsed.number}`;
|
|
42908
43064
|
const patch = {};
|
|
42909
43065
|
let bodyChanged = false;
|
|
42910
|
-
const textDeps = () => deps.textDeps ?? { readFile: (p, e) => Promise.resolve((0,
|
|
43066
|
+
const textDeps = () => deps.textDeps ?? { readFile: (p, e) => Promise.resolve((0, import_node_fs39.readFileSync)(p, e)), readStdin: () => Promise.resolve("") };
|
|
42911
43067
|
if (options.titleFile !== void 0) {
|
|
42912
43068
|
patch.title = await resolveIssueTitle({ title: options.title, titleFile: options.titleFile }, textDeps());
|
|
42913
43069
|
} else if (options.title !== void 0) {
|
|
@@ -43570,7 +43726,7 @@ function extendCreateCommand(issue, batchAttach) {
|
|
|
43570
43726
|
if (opts.batch) {
|
|
43571
43727
|
let specs;
|
|
43572
43728
|
try {
|
|
43573
|
-
const raw = (0,
|
|
43729
|
+
const raw = (0, import_node_fs39.readFileSync)(opts.batch, "utf8");
|
|
43574
43730
|
specs = JSON.parse(raw);
|
|
43575
43731
|
if (!Array.isArray(specs)) {
|
|
43576
43732
|
const top = specs === null ? "null" : typeof specs === "object" ? `an object with keys: ${Object.keys(specs).join(", ") || "(none)"}` : `a ${typeof specs}`;
|
|
@@ -43647,7 +43803,7 @@ ${lines2}`, {
|
|
|
43647
43803
|
}
|
|
43648
43804
|
|
|
43649
43805
|
// src/post-merge-recon.ts
|
|
43650
|
-
var
|
|
43806
|
+
var import_node_fs40 = require("node:fs");
|
|
43651
43807
|
var import_node_path38 = require("node:path");
|
|
43652
43808
|
|
|
43653
43809
|
// src/cross-repo-filing-issue.ts
|
|
@@ -43817,16 +43973,16 @@ function buildPostMergeReconRecovery(input) {
|
|
|
43817
43973
|
}
|
|
43818
43974
|
function writePostMergeReconRecovery(cwd, recovery) {
|
|
43819
43975
|
const path2 = postMergeReconStatePath(cwd, recovery.repo, recovery.pr);
|
|
43820
|
-
(0,
|
|
43821
|
-
(0,
|
|
43976
|
+
(0, import_node_fs40.mkdirSync)((0, import_node_path38.dirname)(path2), { recursive: true });
|
|
43977
|
+
(0, import_node_fs40.writeFileSync)(path2, `${JSON.stringify(recovery, null, 2)}
|
|
43822
43978
|
`, "utf8");
|
|
43823
43979
|
return path2;
|
|
43824
43980
|
}
|
|
43825
43981
|
function clearPostMergeReconRecovery(cwd, repo, pr) {
|
|
43826
43982
|
const path2 = postMergeReconStatePath(cwd, repo, pr);
|
|
43827
|
-
if (!(0,
|
|
43983
|
+
if (!(0, import_node_fs40.existsSync)(path2)) return;
|
|
43828
43984
|
try {
|
|
43829
|
-
(0,
|
|
43985
|
+
(0, import_node_fs40.unlinkSync)(path2);
|
|
43830
43986
|
} catch {
|
|
43831
43987
|
}
|
|
43832
43988
|
}
|
|
@@ -44302,7 +44458,7 @@ function registerPrLifecycleCommands(program3) {
|
|
|
44302
44458
|
|
|
44303
44459
|
// src/review-verdict.ts
|
|
44304
44460
|
var import_node_child_process14 = require("node:child_process");
|
|
44305
|
-
var
|
|
44461
|
+
var import_node_fs41 = require("node:fs");
|
|
44306
44462
|
var import_node_os21 = require("node:os");
|
|
44307
44463
|
var import_node_path39 = require("node:path");
|
|
44308
44464
|
init_cli_shared();
|
|
@@ -44469,15 +44625,15 @@ async function readPrIssueComments(number, repo) {
|
|
|
44469
44625
|
return comments;
|
|
44470
44626
|
}
|
|
44471
44627
|
async function postPrCommentFromFile(number, repo, body) {
|
|
44472
|
-
const dir = (0,
|
|
44628
|
+
const dir = (0, import_node_fs41.mkdtempSync)((0, import_node_path39.join)((0, import_node_os21.tmpdir)(), "mmi-review-verdict-"));
|
|
44473
44629
|
const path2 = (0, import_node_path39.join)(dir, "body.md");
|
|
44474
44630
|
try {
|
|
44475
|
-
(0,
|
|
44631
|
+
(0, import_node_fs41.writeFileSync)(path2, body, "utf8");
|
|
44476
44632
|
const { stdout } = await execFileP("gh", ["pr", "comment", number, "--repo", repo, "--body-file", path2], { timeout: GH_MUTATION_TIMEOUT_MS });
|
|
44477
44633
|
return stdout.trim();
|
|
44478
44634
|
} finally {
|
|
44479
44635
|
try {
|
|
44480
|
-
(0,
|
|
44636
|
+
(0, import_node_fs41.rmSync)(dir, { recursive: true, force: true });
|
|
44481
44637
|
} catch {
|
|
44482
44638
|
}
|
|
44483
44639
|
}
|
|
@@ -44711,17 +44867,17 @@ async function prCreateClaimRefusal(body, repoOption, deps = {}) {
|
|
|
44711
44867
|
}
|
|
44712
44868
|
|
|
44713
44869
|
// src/worktree-residue-sweep.ts
|
|
44714
|
-
var
|
|
44870
|
+
var import_node_fs45 = require("node:fs");
|
|
44715
44871
|
var import_node_path43 = require("node:path");
|
|
44716
44872
|
|
|
44717
44873
|
// src/worktree-merge-cleanup.ts
|
|
44718
|
-
var
|
|
44874
|
+
var import_node_fs44 = require("node:fs");
|
|
44719
44875
|
var import_node_path42 = require("node:path");
|
|
44720
44876
|
init_cli_shared();
|
|
44721
44877
|
|
|
44722
44878
|
// src/stage-runner.ts
|
|
44723
44879
|
var import_node_child_process16 = require("node:child_process");
|
|
44724
|
-
var
|
|
44880
|
+
var import_node_fs43 = require("node:fs");
|
|
44725
44881
|
var import_node_path41 = require("node:path");
|
|
44726
44882
|
var import_node_net = require("node:net");
|
|
44727
44883
|
var import_node_util5 = require("node:util");
|
|
@@ -44732,7 +44888,7 @@ function normalizeEol2(s) {
|
|
|
44732
44888
|
}
|
|
44733
44889
|
|
|
44734
44890
|
// src/env-detection.ts
|
|
44735
|
-
var
|
|
44891
|
+
var import_node_fs42 = require("node:fs");
|
|
44736
44892
|
var import_node_path40 = require("node:path");
|
|
44737
44893
|
var SKIPPED_DIRS = /* @__PURE__ */ new Set([".git", "node_modules", "dist", ".jerv", ".pi", ".venv", "venv"]);
|
|
44738
44894
|
function isEnvBaseName(name) {
|
|
@@ -44743,7 +44899,7 @@ function findEnvFiles(root) {
|
|
|
44743
44899
|
const walk2 = (dir, rel) => {
|
|
44744
44900
|
let entries;
|
|
44745
44901
|
try {
|
|
44746
|
-
entries = (0,
|
|
44902
|
+
entries = (0, import_node_fs42.readdirSync)(dir, { withFileTypes: true });
|
|
44747
44903
|
} catch {
|
|
44748
44904
|
return;
|
|
44749
44905
|
}
|
|
@@ -44757,7 +44913,7 @@ function findEnvFiles(root) {
|
|
|
44757
44913
|
if (isEnvBaseName(entry.name)) {
|
|
44758
44914
|
let isDir = false;
|
|
44759
44915
|
try {
|
|
44760
|
-
isDir = (0,
|
|
44916
|
+
isDir = (0, import_node_fs42.lstatSync)((0, import_node_path40.join)(dir, entry.name)).isDirectory();
|
|
44761
44917
|
} catch {
|
|
44762
44918
|
}
|
|
44763
44919
|
if (!isDir) found.push(relPath);
|
|
@@ -44896,12 +45052,12 @@ var DOCKER_TIMEOUT_MS = 15e3;
|
|
|
44896
45052
|
function stageBash() {
|
|
44897
45053
|
if (process.platform !== "win32") return "bash";
|
|
44898
45054
|
const configured = process.env.SHELL;
|
|
44899
|
-
if (configured && (0, import_node_path41.isAbsolute)(configured) && /[/\\]bash(?:\.exe)?$/i.test(configured) && !/[/\\](?:System32|Sysnative)[/\\]bash(?:\.exe)?$/i.test(configured) && (0,
|
|
45055
|
+
if (configured && (0, import_node_path41.isAbsolute)(configured) && /[/\\]bash(?:\.exe)?$/i.test(configured) && !/[/\\](?:System32|Sysnative)[/\\]bash(?:\.exe)?$/i.test(configured) && (0, import_node_fs43.existsSync)(configured)) return configured;
|
|
44900
45056
|
const candidates = [
|
|
44901
45057
|
(0, import_node_path41.join)(process.env.ProgramFiles || "C:\\Program Files", "Git", "bin", "bash.exe"),
|
|
44902
45058
|
...process.env.LOCALAPPDATA ? [(0, import_node_path41.join)(process.env.LOCALAPPDATA, "Programs", "Git", "bin", "bash.exe")] : []
|
|
44903
45059
|
];
|
|
44904
|
-
const bash = candidates.find((path2) => (0,
|
|
45060
|
+
const bash = candidates.find((path2) => (0, import_node_fs43.existsSync)(path2));
|
|
44905
45061
|
if (!bash) throw new Error("Local stages require Git Bash on Windows. Install Git for Windows or set SHELL to its absolute bash.exe path.");
|
|
44906
45062
|
return bash;
|
|
44907
45063
|
}
|
|
@@ -45257,7 +45413,7 @@ function stageProcessEnv(stagePort, extraEnv) {
|
|
|
45257
45413
|
function composeResolvesPort(cwd) {
|
|
45258
45414
|
if (process.env.PORT) return true;
|
|
45259
45415
|
const envFile = (0, import_node_path41.join)(cwd, ".env");
|
|
45260
|
-
return (0,
|
|
45416
|
+
return (0, import_node_fs43.existsSync)(envFile) && envFileKeys((0, import_node_fs43.readFileSync)(envFile, "utf8")).has("PORT");
|
|
45261
45417
|
}
|
|
45262
45418
|
function stageComposeEnv(config, stagePort, vaultEnvMerge, cwd) {
|
|
45263
45419
|
const composeProject = config.env?.COMPOSE_PROJECT_NAME ?? vaultEnvMerge?.COMPOSE_PROJECT_NAME ?? stageComposeProjectName(cwd);
|
|
@@ -45272,13 +45428,13 @@ function stageComposeEnv(config, stagePort, vaultEnvMerge, cwd) {
|
|
|
45272
45428
|
function stageComposeFiles(cwd) {
|
|
45273
45429
|
const files = ["docker-compose.yml"];
|
|
45274
45430
|
for (const conventional of ["docker-compose.override.yml", "docker-compose.override.yaml"]) {
|
|
45275
|
-
if ((0,
|
|
45431
|
+
if ((0, import_node_fs43.existsSync)((0, import_node_path41.join)(cwd, conventional))) files.push(conventional);
|
|
45276
45432
|
}
|
|
45277
45433
|
return [...files, RUNTIME_ENV_OVERRIDE_RELPATH];
|
|
45278
45434
|
}
|
|
45279
45435
|
async function prepareRuntimeEnvPassthrough(cwd, composeEnv, vaultEnvMerge) {
|
|
45280
45436
|
const keys = Object.keys(vaultEnvMerge ?? {});
|
|
45281
|
-
if (!keys.length || !(0,
|
|
45437
|
+
if (!keys.length || !(0, import_node_fs43.existsSync)((0, import_node_path41.join)(cwd, "docker-compose.yml"))) return {};
|
|
45282
45438
|
let configJson;
|
|
45283
45439
|
try {
|
|
45284
45440
|
const { stdout } = await execFileP3("docker", ["compose", "config", "--format", "json"], {
|
|
@@ -45295,20 +45451,20 @@ async function prepareRuntimeEnvPassthrough(cwd, composeEnv, vaultEnvMerge) {
|
|
|
45295
45451
|
const body = renderRuntimeEnvOverride(runtimeEnvMarkedServices(configJson), keys, runtimeEnvExcludes(configJson), runtimeEnvSelects(configJson));
|
|
45296
45452
|
if (!body) return {};
|
|
45297
45453
|
const overridePath = (0, import_node_path41.join)(cwd, RUNTIME_ENV_OVERRIDE_RELPATH);
|
|
45298
|
-
(0,
|
|
45299
|
-
(0,
|
|
45454
|
+
(0, import_node_fs43.mkdirSync)((0, import_node_path41.join)(cwd, "tmp", "stage"), { recursive: true });
|
|
45455
|
+
(0, import_node_fs43.writeFileSync)(overridePath, body, "utf8");
|
|
45300
45456
|
return stageComposeFileEnv(stageComposeFiles(cwd));
|
|
45301
45457
|
}
|
|
45302
45458
|
async function ensureStageRuntimeEnv(config, opts, cwd) {
|
|
45303
45459
|
if (!config.ensureEnv) return;
|
|
45304
45460
|
const target = (0, import_node_path41.join)(cwd, config.ensureEnv.target);
|
|
45305
45461
|
const example = (0, import_node_path41.join)(cwd, config.ensureEnv.example);
|
|
45306
|
-
if (!(0,
|
|
45307
|
-
(0,
|
|
45308
|
-
} else if ((0,
|
|
45309
|
-
const stale = detectStaleEnvFile((0,
|
|
45310
|
-
exampleMtimeMs: (0,
|
|
45311
|
-
targetMtimeMs: (0,
|
|
45462
|
+
if (!(0, import_node_fs43.existsSync)(target) && (0, import_node_fs43.existsSync)(example)) {
|
|
45463
|
+
(0, import_node_fs43.copyFileSync)(example, target);
|
|
45464
|
+
} else if ((0, import_node_fs43.existsSync)(target) && (0, import_node_fs43.existsSync)(example)) {
|
|
45465
|
+
const stale = detectStaleEnvFile((0, import_node_fs43.readFileSync)(example, "utf8"), (0, import_node_fs43.readFileSync)(target, "utf8"), {
|
|
45466
|
+
exampleMtimeMs: (0, import_node_fs43.statSync)(example).mtimeMs,
|
|
45467
|
+
targetMtimeMs: (0, import_node_fs43.statSync)(target).mtimeMs
|
|
45312
45468
|
});
|
|
45313
45469
|
if (stale) {
|
|
45314
45470
|
const msg = `stale ${config.ensureEnv.target} (${stale}) \u2014 delete it or refresh from ${config.ensureEnv.example} before re-running /stage`;
|
|
@@ -45316,8 +45472,8 @@ async function ensureStageRuntimeEnv(config, opts, cwd) {
|
|
|
45316
45472
|
console.error(`mmi-cli stage: ${msg} (allowed via --allow-stale-env)`);
|
|
45317
45473
|
}
|
|
45318
45474
|
}
|
|
45319
|
-
if (opts.vaultEnvMerge && Object.keys(opts.vaultEnvMerge).length && (0,
|
|
45320
|
-
(0,
|
|
45475
|
+
if (opts.vaultEnvMerge && Object.keys(opts.vaultEnvMerge).length && (0, import_node_fs43.existsSync)(target)) {
|
|
45476
|
+
(0, import_node_fs43.writeFileSync)(target, mergeEnvSecretsIntoFile((0, import_node_fs43.readFileSync)(target, "utf8"), opts.vaultEnvMerge), "utf8");
|
|
45321
45477
|
}
|
|
45322
45478
|
}
|
|
45323
45479
|
async function gitText(cwd, args) {
|
|
@@ -45347,20 +45503,20 @@ async function resolveGlobalStatePath(cwd, explicit) {
|
|
|
45347
45503
|
return void 0;
|
|
45348
45504
|
}
|
|
45349
45505
|
function readState(path2) {
|
|
45350
|
-
if (!(0,
|
|
45506
|
+
if (!(0, import_node_fs43.existsSync)(path2)) return null;
|
|
45351
45507
|
try {
|
|
45352
|
-
return JSON.parse((0,
|
|
45508
|
+
return JSON.parse((0, import_node_fs43.readFileSync)(path2, "utf8"));
|
|
45353
45509
|
} catch {
|
|
45354
45510
|
return null;
|
|
45355
45511
|
}
|
|
45356
45512
|
}
|
|
45357
45513
|
function mkdirFor(path2) {
|
|
45358
45514
|
const dir = path2.slice(0, Math.max(path2.lastIndexOf("/"), path2.lastIndexOf("\\")));
|
|
45359
|
-
(0,
|
|
45515
|
+
(0, import_node_fs43.mkdirSync)(dir, { recursive: true });
|
|
45360
45516
|
}
|
|
45361
45517
|
function writeState(path2, state) {
|
|
45362
45518
|
mkdirFor(path2);
|
|
45363
|
-
(0,
|
|
45519
|
+
(0, import_node_fs43.writeFileSync)(path2, JSON.stringify(state, null, 2), "utf8");
|
|
45364
45520
|
}
|
|
45365
45521
|
function writeStagePortReservation(port, cwd, statePath, globalStatePath, now) {
|
|
45366
45522
|
const reservation = {
|
|
@@ -45389,7 +45545,7 @@ async function cleanupStageState(state, paths, timeoutMs, fallbackCwd, currentEn
|
|
|
45389
45545
|
);
|
|
45390
45546
|
}
|
|
45391
45547
|
for (const path2 of [...new Set(paths.filter((p) => Boolean(p)))]) {
|
|
45392
|
-
(0,
|
|
45548
|
+
(0, import_node_fs43.rmSync)(path2, { force: true });
|
|
45393
45549
|
}
|
|
45394
45550
|
}
|
|
45395
45551
|
async function killTree(pid) {
|
|
@@ -45636,8 +45792,8 @@ async function runStage(config = {}, opts = {}) {
|
|
|
45636
45792
|
});
|
|
45637
45793
|
}
|
|
45638
45794
|
} catch (e) {
|
|
45639
|
-
(0,
|
|
45640
|
-
if (globalStatePath && globalStatePath !== statePath) (0,
|
|
45795
|
+
(0, import_node_fs43.rmSync)(statePath, { force: true });
|
|
45796
|
+
if (globalStatePath && globalStatePath !== statePath) (0, import_node_fs43.rmSync)(globalStatePath, { force: true });
|
|
45641
45797
|
throw e;
|
|
45642
45798
|
}
|
|
45643
45799
|
const started = await startStage(config, {
|
|
@@ -45658,7 +45814,7 @@ function normPath2(p) {
|
|
|
45658
45814
|
function unlinkNodeModulesJunction(wtPath) {
|
|
45659
45815
|
const nm = (0, import_node_path42.join)(wtPath, "node_modules");
|
|
45660
45816
|
try {
|
|
45661
|
-
if ((0,
|
|
45817
|
+
if ((0, import_node_fs44.lstatSync)(nm).isSymbolicLink()) (0, import_node_fs44.rmdirSync)(nm);
|
|
45662
45818
|
return { ok: true };
|
|
45663
45819
|
} catch (e) {
|
|
45664
45820
|
if (e.code === "ENOENT") return { ok: true };
|
|
@@ -45669,8 +45825,8 @@ function defaultSleep2(ms) {
|
|
|
45669
45825
|
return new Promise((resolve8) => setTimeout(resolve8, ms));
|
|
45670
45826
|
}
|
|
45671
45827
|
async function removeResidueDirectory(wtPath, options = {}) {
|
|
45672
|
-
const { sleep: sleep2 = defaultSleep2, removeEmptyDir =
|
|
45673
|
-
const removeRecursive = options.removeRecursive ?? ((path2) => (0,
|
|
45828
|
+
const { sleep: sleep2 = defaultSleep2, removeEmptyDir = import_node_fs44.rmdirSync, exists = import_node_fs44.existsSync } = options;
|
|
45829
|
+
const removeRecursive = options.removeRecursive ?? ((path2) => (0, import_node_fs44.rmSync)(path2, { recursive: true, force: true, maxRetries: 10, retryDelay: 100 }));
|
|
45674
45830
|
const junction = unlinkNodeModulesJunction(wtPath);
|
|
45675
45831
|
if (!junction.ok) return junction;
|
|
45676
45832
|
try {
|
|
@@ -45796,21 +45952,21 @@ async function listNestedIgnoredNodeModules(wtPath, execGit) {
|
|
|
45796
45952
|
return out.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.endsWith("node_modules/") && line !== "node_modules/").map((line) => (0, import_node_path42.join)(wtPath, line.slice(0, -1)));
|
|
45797
45953
|
}
|
|
45798
45954
|
function safeRemoveTree(path2) {
|
|
45799
|
-
const stat4 = (0,
|
|
45955
|
+
const stat4 = (0, import_node_fs44.lstatSync)(path2);
|
|
45800
45956
|
if (stat4.isSymbolicLink()) {
|
|
45801
45957
|
try {
|
|
45802
|
-
(0,
|
|
45958
|
+
(0, import_node_fs44.rmdirSync)(path2);
|
|
45803
45959
|
} catch {
|
|
45804
|
-
(0,
|
|
45960
|
+
(0, import_node_fs44.unlinkSync)(path2);
|
|
45805
45961
|
}
|
|
45806
45962
|
return;
|
|
45807
45963
|
}
|
|
45808
45964
|
if (stat4.isDirectory()) {
|
|
45809
|
-
for (const entry of (0,
|
|
45810
|
-
(0,
|
|
45965
|
+
for (const entry of (0, import_node_fs44.readdirSync)(path2)) safeRemoveTree((0, import_node_path42.join)(path2, entry));
|
|
45966
|
+
(0, import_node_fs44.rmdirSync)(path2);
|
|
45811
45967
|
return;
|
|
45812
45968
|
}
|
|
45813
|
-
(0,
|
|
45969
|
+
(0, import_node_fs44.unlinkSync)(path2);
|
|
45814
45970
|
}
|
|
45815
45971
|
async function removeWorktreeNodeModules(wtPath) {
|
|
45816
45972
|
try {
|
|
@@ -45826,7 +45982,7 @@ function errorMessage(e) {
|
|
|
45826
45982
|
}
|
|
45827
45983
|
function resolvedOrRaw(path2) {
|
|
45828
45984
|
try {
|
|
45829
|
-
return normPath2((0,
|
|
45985
|
+
return normPath2((0, import_node_fs44.realpathSync)(path2));
|
|
45830
45986
|
} catch {
|
|
45831
45987
|
return normPath2(path2);
|
|
45832
45988
|
}
|
|
@@ -45834,10 +45990,10 @@ function resolvedOrRaw(path2) {
|
|
|
45834
45990
|
function unlinkEscapingReparsePoints(root, primaryRoot) {
|
|
45835
45991
|
let realRoot;
|
|
45836
45992
|
try {
|
|
45837
|
-
if ((0,
|
|
45993
|
+
if ((0, import_node_fs44.lstatSync)(root).isSymbolicLink()) {
|
|
45838
45994
|
return { ok: false, error: `delete root ${normPath2(root)} is a reparse point resolving to ${resolvedOrRaw(root)}` };
|
|
45839
45995
|
}
|
|
45840
|
-
realRoot = normPath2((0,
|
|
45996
|
+
realRoot = normPath2((0, import_node_fs44.realpathSync)(root));
|
|
45841
45997
|
} catch (e) {
|
|
45842
45998
|
if (e.code === "ENOENT") return { ok: true, unlinked: [] };
|
|
45843
45999
|
return { ok: false, error: `cannot resolve delete root ${normPath2(root)}: ${errorMessage(e)}` };
|
|
@@ -45853,7 +46009,7 @@ function unlinkEscapingReparsePoints(root, primaryRoot) {
|
|
|
45853
46009
|
const dir = stack.pop();
|
|
45854
46010
|
let entries;
|
|
45855
46011
|
try {
|
|
45856
|
-
entries = (0,
|
|
46012
|
+
entries = (0, import_node_fs44.readdirSync)(dir, { withFileTypes: true });
|
|
45857
46013
|
} catch (e) {
|
|
45858
46014
|
if (e.code === "ENOENT") continue;
|
|
45859
46015
|
return { ok: false, error: `cannot scan ${normPath2(dir)} for reparse points: ${errorMessage(e)}` };
|
|
@@ -45863,7 +46019,7 @@ function unlinkEscapingReparsePoints(root, primaryRoot) {
|
|
|
45863
46019
|
if (entry.isSymbolicLink()) {
|
|
45864
46020
|
let target = "";
|
|
45865
46021
|
try {
|
|
45866
|
-
target = normPath2((0,
|
|
46022
|
+
target = normPath2((0, import_node_fs44.realpathSync)(child2));
|
|
45867
46023
|
} catch {
|
|
45868
46024
|
target = "";
|
|
45869
46025
|
}
|
|
@@ -46046,7 +46202,7 @@ async function cleanupPrMergeLocalBranch(branch, options) {
|
|
|
46046
46202
|
return report;
|
|
46047
46203
|
}
|
|
46048
46204
|
const execGit = options.execGit ?? (async (args) => (await execFileP("git", args, { timeout: GIT_TIMEOUT_MS })).stdout);
|
|
46049
|
-
const pathExists = options.pathExists ??
|
|
46205
|
+
const pathExists = options.pathExists ?? import_node_fs44.existsSync;
|
|
46050
46206
|
let afterWorktrees = [];
|
|
46051
46207
|
try {
|
|
46052
46208
|
afterWorktrees = parseGitWorktreePorcelain(await execGit(["worktree", "list", "--porcelain"]));
|
|
@@ -46333,7 +46489,7 @@ function residueLedgerPath(gitCommonDir) {
|
|
|
46333
46489
|
}
|
|
46334
46490
|
function readPaths(file, deps) {
|
|
46335
46491
|
try {
|
|
46336
|
-
const parsed = JSON.parse((deps.readLedger ?? ((f) => (0,
|
|
46492
|
+
const parsed = JSON.parse((deps.readLedger ?? ((f) => (0, import_node_fs45.readFileSync)(f, "utf8")))(file));
|
|
46337
46493
|
return Array.isArray(parsed) ? parsed.filter((p) => typeof p === "string") : [];
|
|
46338
46494
|
} catch {
|
|
46339
46495
|
return [];
|
|
@@ -46342,8 +46498,8 @@ function readPaths(file, deps) {
|
|
|
46342
46498
|
function writePaths(file, paths, deps) {
|
|
46343
46499
|
try {
|
|
46344
46500
|
const write = deps.writeLedger ?? ((f, t) => {
|
|
46345
|
-
(0,
|
|
46346
|
-
(0,
|
|
46501
|
+
(0, import_node_fs45.mkdirSync)((0, import_node_path43.dirname)(f), { recursive: true });
|
|
46502
|
+
(0, import_node_fs45.writeFileSync)(f, t, "utf8");
|
|
46347
46503
|
});
|
|
46348
46504
|
write(file, `${JSON.stringify([...new Set(paths)], null, 1)}
|
|
46349
46505
|
`);
|
|
@@ -46357,17 +46513,17 @@ function recordResidue(gitCommonDir, path2, deps = {}) {
|
|
|
46357
46513
|
writePaths(file, paths, deps);
|
|
46358
46514
|
}
|
|
46359
46515
|
async function sweepWorktreeResidue(gitCommonDir, registered, deps = {}) {
|
|
46360
|
-
const exists = deps.exists ??
|
|
46361
|
-
const readDir = deps.readDir ?? ((p) => (0,
|
|
46516
|
+
const exists = deps.exists ?? import_node_fs45.existsSync;
|
|
46517
|
+
const readDir = deps.readDir ?? ((p) => (0, import_node_fs45.readdirSync)(p));
|
|
46362
46518
|
const isDir = deps.isDir ?? ((p) => {
|
|
46363
46519
|
try {
|
|
46364
|
-
return (0,
|
|
46520
|
+
return (0, import_node_fs45.statSync)(p).isDirectory();
|
|
46365
46521
|
} catch {
|
|
46366
46522
|
return false;
|
|
46367
46523
|
}
|
|
46368
46524
|
});
|
|
46369
46525
|
const removeRecorded = deps.removeRecorded ?? ((p) => removeResidueDirectory(p));
|
|
46370
|
-
const removeEmpty = deps.removeEmpty ?? ((p) => (0,
|
|
46526
|
+
const removeEmpty = deps.removeEmpty ?? ((p) => (0, import_node_fs45.rmdirSync)(p));
|
|
46371
46527
|
const report = { swept: [], kept: [], dropped: [], emptyRemoved: [], unrecorded: [] };
|
|
46372
46528
|
const live = new Set(registered.map(norm));
|
|
46373
46529
|
const primary = registered[0] ? norm(registered[0]) : void 0;
|
|
@@ -46447,8 +46603,8 @@ function argvWantsJson2() {
|
|
|
46447
46603
|
function hubRoot() {
|
|
46448
46604
|
const fromPkg = (0, import_node_path44.join)(__dirname, "..", "..");
|
|
46449
46605
|
const marker = "skills/bootstrap/seeds/manifest.json";
|
|
46450
|
-
if ((0,
|
|
46451
|
-
if ((0,
|
|
46606
|
+
if ((0, import_node_fs46.existsSync)((0, import_node_path44.join)(fromPkg, marker))) return fromPkg;
|
|
46607
|
+
if ((0, import_node_fs46.existsSync)((0, import_node_path44.join)(process.cwd(), marker))) return process.cwd();
|
|
46452
46608
|
return null;
|
|
46453
46609
|
}
|
|
46454
46610
|
function ciAuditDeps() {
|
|
@@ -46461,7 +46617,7 @@ function ciAuditDeps() {
|
|
|
46461
46617
|
readSeedFile: (path2) => {
|
|
46462
46618
|
if (!root) return null;
|
|
46463
46619
|
const fullPath = (0, import_node_path44.join)(root, path2);
|
|
46464
|
-
return (0,
|
|
46620
|
+
return (0, import_node_fs46.existsSync)(fullPath) ? (0, import_node_fs46.readFileSync)(fullPath, "utf8") : null;
|
|
46465
46621
|
}
|
|
46466
46622
|
};
|
|
46467
46623
|
}
|
|
@@ -47225,10 +47381,10 @@ ${list}`);
|
|
|
47225
47381
|
});
|
|
47226
47382
|
async function listCiWorkflowPaths(cwd = process.cwd()) {
|
|
47227
47383
|
const wfDir = (0, import_node_path44.join)(cwd, ".github", "workflows");
|
|
47228
|
-
if (!(0,
|
|
47229
|
-
return (0,
|
|
47384
|
+
if (!(0, import_node_fs46.existsSync)(wfDir)) return [];
|
|
47385
|
+
return (0, import_node_fs46.readdirSync)(wfDir).filter((name) => /\.(ya?ml)$/i.test(name)).filter((name) => {
|
|
47230
47386
|
try {
|
|
47231
|
-
return workflowReportsPrChecks((0,
|
|
47387
|
+
return workflowReportsPrChecks((0, import_node_fs46.readFileSync)((0, import_node_path44.join)(wfDir, name), "utf8"));
|
|
47232
47388
|
} catch {
|
|
47233
47389
|
return true;
|
|
47234
47390
|
}
|
|
@@ -47433,7 +47589,7 @@ ${list}`);
|
|
|
47433
47589
|
jsonParity(pr.command("review-verdict <number>").description("post an explicit review verdict comment: computes the PR diff patch-id and head sha, renders the v1 contract body, and posts it as a PR comment").requiredOption("--repo <owner/repo>", "target repo").requiredOption("--verdict <verdict>", `one of ${REVIEW_VERDICTS.join("|")}`).requiredOption("--scope <text>", "one line: what was reviewed").requiredOption("--risk <text>", "one line: the residual risk").option("--unverified <text>", "a claim the reviewer could not verify (repeatable)", (v, acc) => [...acc, v], []).requiredOption("--reviewer <id>", "reviewer seat or model id").option("--findings-file <path>", "Markdown findings appended after the JSON block")).action(async (number, o) => {
|
|
47434
47590
|
if (!isReviewVerdict(o.verdict)) return fail(`pr review-verdict: --verdict must be one of ${REVIEW_VERDICTS.join("|")} (got ${o.verdict})`);
|
|
47435
47591
|
const verdict = o.verdict;
|
|
47436
|
-
const findings = o.findingsFile ? (0,
|
|
47592
|
+
const findings = o.findingsFile ? (0, import_node_fs46.readFileSync)(o.findingsFile, "utf8") : void 0;
|
|
47437
47593
|
let patch;
|
|
47438
47594
|
let head;
|
|
47439
47595
|
try {
|
|
@@ -47689,7 +47845,7 @@ ${list}`);
|
|
|
47689
47845
|
const cleanupMerged = async (r) => {
|
|
47690
47846
|
if (opts.preserveWorktree) return "cleanup skipped (--preserve-worktree)";
|
|
47691
47847
|
const ran = await execFileP(process.execPath, [process.argv[1], ...canonicalArgvFor(["pr", "merge", r.pr, "--repo", r.repo])], {
|
|
47692
|
-
cwd: (0,
|
|
47848
|
+
cwd: (0, import_node_fs46.existsSync)(cwd0) ? cwd0 : primaryRoot0,
|
|
47693
47849
|
timeout: GH_MUTATION_TIMEOUT_MS * 3
|
|
47694
47850
|
}).then((x) => ({ stdout: x.stdout, stderr: x.stderr }), (e) => ({ stdout: e.stdout ?? "", stderr: e.stderr ?? "" }));
|
|
47695
47851
|
const json = ran.stdout.split("\n").reverse().find((l) => l.startsWith("{"));
|
|
@@ -47759,7 +47915,7 @@ ${list}`);
|
|
|
47759
47915
|
const mergeSquashBody = squashBodyTextForMerge(
|
|
47760
47916
|
closingGuardInput,
|
|
47761
47917
|
method === "--squash",
|
|
47762
|
-
o.squashBodyFile ? (0,
|
|
47918
|
+
o.squashBodyFile ? (0, import_node_fs46.readFileSync)(o.squashBodyFile, "utf8") : void 0
|
|
47763
47919
|
);
|
|
47764
47920
|
if (!o.squashBodyFile) warnSquashBodyClosingStrip("pr merge", closingGuardInput, mergeSquashBody);
|
|
47765
47921
|
const closingGuardVerdict = evaluateClosingGuard(closingGuardInput, {
|
|
@@ -47910,7 +48066,7 @@ ${list}`);
|
|
|
47910
48066
|
}
|
|
47911
48067
|
if (!repoForPostCleanup) throw e;
|
|
47912
48068
|
console.warn(`pr merge: gh GraphQL rate-limited \u2014 merging PR #${number} via REST PUT instead (#4588).`);
|
|
47913
|
-
const commitMessage = bodyFile ? (0,
|
|
48069
|
+
const commitMessage = bodyFile ? (0, import_node_fs46.readFileSync)(bodyFile, "utf8") : void 0;
|
|
47914
48070
|
await defaultGitHubClient().rest("PUT", `repos/${repoForPostCleanup}/pulls/${number}/merge`, {
|
|
47915
48071
|
body: { merge_method: method.slice(2), ...commitMessage ? { commit_message: commitMessage } : {} },
|
|
47916
48072
|
timeoutMs: GH_MUTATION_TIMEOUT_MS
|
|
@@ -48043,7 +48199,7 @@ ${list}`);
|
|
|
48043
48199
|
preserveWorktree: o.preserveWorktree,
|
|
48044
48200
|
gcAcknowledged: o.gc,
|
|
48045
48201
|
expectedHeadOid: headRefOid,
|
|
48046
|
-
pathExists: (p) => (0,
|
|
48202
|
+
pathExists: (p) => (0, import_node_fs46.existsSync)(p),
|
|
48047
48203
|
// #5899: pin cleanup git calls to the main checkout — the task worktree this process may be
|
|
48048
48204
|
// standing in is removed mid-cleanup, so a cwd-relative invocation fails with
|
|
48049
48205
|
// 'fatal: not a git repository' and leaves a spurious partial-cleanup exit.
|
|
@@ -49343,11 +49499,11 @@ function suiteTrainIo(root, summaryFile, memberSummaryFiles = {}, summaryFileTr,
|
|
|
49343
49499
|
const checkout = async (repo) => {
|
|
49344
49500
|
if (repo === SUITE_REPO) return root;
|
|
49345
49501
|
const target = (0, import_node_path46.join)(base, repo.split("/")[1]);
|
|
49346
|
-
if (!(0,
|
|
49347
|
-
(0,
|
|
49502
|
+
if (!(0, import_node_fs47.existsSync)(target)) {
|
|
49503
|
+
(0, import_node_fs47.mkdirSync)(base, { recursive: true });
|
|
49348
49504
|
await exec("git", ["clone", "--quiet", "--branch", "development", `https://github.com/${repo}.git`, target], root, WATCH_TIMEOUT);
|
|
49349
49505
|
}
|
|
49350
|
-
if (!(0,
|
|
49506
|
+
if (!(0, import_node_fs47.existsSync)((0, import_node_path46.join)(target, ".git"))) throw new Error(`${repo}: suite checkout has no .git at ${target}; stop`);
|
|
49351
49507
|
const origin = await exec("git", ["remote", "get-url", "origin"], target);
|
|
49352
49508
|
if (!origin.toLowerCase().endsWith(`/${repo.toLowerCase()}.git`) && !origin.toLowerCase().endsWith(`/${repo.toLowerCase()}`))
|
|
49353
49509
|
throw new Error(`${repo}: suite checkout origin mismatch at ${target}; stop`);
|
|
@@ -49654,9 +49810,9 @@ function suiteTrainIo(root, summaryFile, memberSummaryFiles = {}, summaryFileTr,
|
|
|
49654
49810
|
const body = await gh(["release", "view", leadTag, "--repo", SUITE_REPO, "--json", "body", "--jq", ".body"]);
|
|
49655
49811
|
if (parseSuiteMapping(body)) return;
|
|
49656
49812
|
const dir = suiteStateDir(root);
|
|
49657
|
-
(0,
|
|
49813
|
+
(0, import_node_fs47.mkdirSync)(dir, { recursive: true });
|
|
49658
49814
|
const file = (0, import_node_path46.join)(dir, `notes-${leadTag}.md`);
|
|
49659
|
-
(0,
|
|
49815
|
+
(0, import_node_fs47.writeFileSync)(file, `${body}
|
|
49660
49816
|
|
|
49661
49817
|
${suiteMappingBlock(leadTag, mapping)}`);
|
|
49662
49818
|
await gh(["release", "edit", leadTag, "--repo", SUITE_REPO, "--notes-file", file]);
|
|
@@ -49697,7 +49853,7 @@ ${suiteMappingBlock(leadTag, mapping)}`);
|
|
|
49697
49853
|
|
|
49698
49854
|
// src/suite-commands.ts
|
|
49699
49855
|
init_cli_shared();
|
|
49700
|
-
var
|
|
49856
|
+
var import_node_fs48 = require("node:fs");
|
|
49701
49857
|
function parseMemberSummaryFiles(entries) {
|
|
49702
49858
|
const memberSummaryFiles = {};
|
|
49703
49859
|
for (const entry of entries) {
|
|
@@ -49791,7 +49947,7 @@ function registerSuiteCommands(program3) {
|
|
|
49791
49947
|
try {
|
|
49792
49948
|
const io = suiteTrainIo(root);
|
|
49793
49949
|
retired = await retireFailedLeadRcLedger({ ledgerPath: releaseLedgerPath(root), rcHead: () => io.head(SUITE_REPO, "rc").then((h) => h ?? void 0), markAbandoned: io.markAbandoned }, o.ownerGo === true);
|
|
49794
|
-
if (retired && !(0,
|
|
49950
|
+
if (retired && !(0, import_node_fs48.existsSync)(io.recordPath)) {
|
|
49795
49951
|
console.log(o.json ? JSON.stringify({ retiredLeadRc: retired }, null, 2) : `suite abandon: retired the lead's failed, never-promoted rc candidate ${retired}; marked abandoned on origin (#7854)`);
|
|
49796
49952
|
return;
|
|
49797
49953
|
}
|
|
@@ -49980,7 +50136,7 @@ function suiteStatusDeps(github, registry2) {
|
|
|
49980
50136
|
|
|
49981
50137
|
// src/packages-adopt-export.ts
|
|
49982
50138
|
var import_node_child_process19 = require("node:child_process");
|
|
49983
|
-
var
|
|
50139
|
+
var import_node_fs49 = require("node:fs");
|
|
49984
50140
|
var import_node_os22 = require("node:os");
|
|
49985
50141
|
var import_node_path47 = require("node:path");
|
|
49986
50142
|
var import_node_util6 = require("node:util");
|
|
@@ -50604,36 +50760,36 @@ async function adoptExport(opts, deps) {
|
|
|
50604
50760
|
if (!/^sha256:[0-9a-f]{64}$/.test(opts.digest)) throw new Error("--digest must be sha256:<64 hex>, from the export run summary");
|
|
50605
50761
|
const packagePath = (0, import_node_path47.join)(opts.dir, "package.json");
|
|
50606
50762
|
const lockPath = (0, import_node_path47.join)(opts.dir, "package-lock.json");
|
|
50607
|
-
const packageText = (0,
|
|
50608
|
-
const lockText = (0,
|
|
50609
|
-
const work = (0,
|
|
50763
|
+
const packageText = (0, import_node_fs49.readFileSync)(packagePath, "utf8");
|
|
50764
|
+
const lockText = (0, import_node_fs49.readFileSync)(lockPath, "utf8");
|
|
50765
|
+
const work = (0, import_node_fs49.mkdtempSync)((0, import_node_path47.join)((0, import_node_os22.tmpdir)(), "mmi-adopt-export-"));
|
|
50610
50766
|
try {
|
|
50611
50767
|
const run = JSON.parse((await deps.ghApi(`repos/${EXPORT_REPO}/actions/runs/${opts.run}`)).toString("utf8"));
|
|
50612
|
-
(0,
|
|
50613
|
-
(0,
|
|
50614
|
-
(0,
|
|
50768
|
+
(0, import_node_fs49.writeFileSync)((0, import_node_path47.join)(work, "expected.json"), JSON.stringify(expectedFromRun(run, opts)));
|
|
50769
|
+
(0, import_node_fs49.writeFileSync)((0, import_node_path47.join)(work, "provider.json"), await deps.ghApi(`repos/${EXPORT_REPO}/actions/artifacts/${opts.artifact}`));
|
|
50770
|
+
(0, import_node_fs49.writeFileSync)((0, import_node_path47.join)(work, "artifact.zip"), await deps.ghApi(`repos/${EXPORT_REPO}/actions/artifacts/${opts.artifact}/zip`));
|
|
50615
50771
|
const script = (0, import_node_path47.join)(work, "package_export.py");
|
|
50616
|
-
(0,
|
|
50772
|
+
(0, import_node_fs49.writeFileSync)(script, package_export_default);
|
|
50617
50773
|
await deps.python(script, ["verify", work, opts.ds, opts.screens]);
|
|
50618
50774
|
const verified = (0, import_node_path47.join)(work, "verified");
|
|
50619
|
-
const metadata = Object.fromEntries(PACKAGES.map(({ name, short: short3 }) => [name, JSON.parse((0,
|
|
50775
|
+
const metadata = Object.fromEntries(PACKAGES.map(({ name, short: short3 }) => [name, JSON.parse((0, import_node_fs49.readFileSync)((0, import_node_path47.join)(verified, `${short3}.metadata.json`), "utf8"))]));
|
|
50620
50776
|
const plan = planAdoption(packageText, lockText, metadata);
|
|
50621
50777
|
for (const { name } of plan.result.adopted) {
|
|
50622
50778
|
const short3 = PACKAGES.find((p) => p.name === name).short;
|
|
50623
50779
|
await deps.npm(["cache", "add", (0, import_node_path47.join)(verified, `${short3}.tgz`)], opts.dir);
|
|
50624
50780
|
}
|
|
50625
|
-
(0,
|
|
50626
|
-
(0,
|
|
50781
|
+
(0, import_node_fs49.writeFileSync)(packagePath, plan.packageText);
|
|
50782
|
+
(0, import_node_fs49.writeFileSync)(lockPath, plan.lockText);
|
|
50627
50783
|
try {
|
|
50628
50784
|
await deps.npm(["ci", "--offline", "--ignore-scripts", "--no-audit", "--no-fund"], opts.dir);
|
|
50629
50785
|
} catch (error) {
|
|
50630
|
-
(0,
|
|
50631
|
-
(0,
|
|
50786
|
+
(0, import_node_fs49.writeFileSync)(packagePath, packageText);
|
|
50787
|
+
(0, import_node_fs49.writeFileSync)(lockPath, lockText);
|
|
50632
50788
|
throw new Error(`npm ci --offline failed, package.json and package-lock.json restored: ${error.message}`);
|
|
50633
50789
|
}
|
|
50634
50790
|
return plan.result;
|
|
50635
50791
|
} finally {
|
|
50636
|
-
(0,
|
|
50792
|
+
(0, import_node_fs49.rmSync)(work, { recursive: true, force: true });
|
|
50637
50793
|
}
|
|
50638
50794
|
}
|
|
50639
50795
|
var execFileBuffer = (0, import_node_util6.promisify)(import_node_child_process19.execFile);
|
|
@@ -50698,12 +50854,12 @@ function registerPackagesCommands(program3) {
|
|
|
50698
50854
|
init_cli_shared();
|
|
50699
50855
|
|
|
50700
50856
|
// src/wave-status.ts
|
|
50701
|
-
var
|
|
50857
|
+
var import_node_fs50 = require("node:fs");
|
|
50702
50858
|
function readStageSummary(worktreePath) {
|
|
50703
50859
|
const statePath = stageStatePath(worktreePath);
|
|
50704
|
-
if (!(0,
|
|
50860
|
+
if (!(0, import_node_fs50.existsSync)(statePath)) return void 0;
|
|
50705
50861
|
try {
|
|
50706
|
-
const state = JSON.parse((0,
|
|
50862
|
+
const state = JSON.parse((0, import_node_fs50.readFileSync)(statePath, "utf8"));
|
|
50707
50863
|
const port = typeof state.port === "number" ? state.port : void 0;
|
|
50708
50864
|
if (port == null || !Number.isInteger(port) || port <= 0) return void 0;
|
|
50709
50865
|
return { port, url: typeof state.url === "string" ? state.url : void 0 };
|
|
@@ -50760,7 +50916,7 @@ async function collectWaveStatus(deps) {
|
|
|
50760
50916
|
// src/discovery-commands.ts
|
|
50761
50917
|
init_github_client();
|
|
50762
50918
|
init_cli_shared();
|
|
50763
|
-
var
|
|
50919
|
+
var import_node_fs51 = require("node:fs");
|
|
50764
50920
|
var import_node_os23 = require("node:os");
|
|
50765
50921
|
var import_node_path48 = require("node:path");
|
|
50766
50922
|
var GC_GH_TIMEOUT_MS3 = 2e4;
|
|
@@ -50953,8 +51109,8 @@ async function collectOnboardStatus(opts = {}) {
|
|
|
50953
51109
|
}
|
|
50954
51110
|
const home = (0, import_node_os23.homedir)();
|
|
50955
51111
|
const plugin = onboardPluginGate({
|
|
50956
|
-
readKnown: () => readFileSyncSafe((0, import_node_path48.join)(home, ...KNOWN_MARKETPLACES_RELATIVE),
|
|
50957
|
-
readSettings: () => readFileSyncSafe((0, import_node_path48.join)(home, ".claude", "settings.json"),
|
|
51112
|
+
readKnown: () => readFileSyncSafe((0, import_node_path48.join)(home, ...KNOWN_MARKETPLACES_RELATIVE), import_node_fs51.readFileSync),
|
|
51113
|
+
readSettings: () => readFileSyncSafe((0, import_node_path48.join)(home, ".claude", "settings.json"), import_node_fs51.readFileSync)
|
|
50958
51114
|
});
|
|
50959
51115
|
return {
|
|
50960
51116
|
guide: "Read the MMI org-guide skill before project work; load only the relevant topic. Use mmi-help for a short introduction.",
|
|
@@ -53148,7 +53304,7 @@ function registerOrgHealthQuery(program3, deps = defaultOrgHealthQueryDeps()) {
|
|
|
53148
53304
|
}
|
|
53149
53305
|
|
|
53150
53306
|
// src/api-read.ts
|
|
53151
|
-
var
|
|
53307
|
+
var import_node_fs52 = require("node:fs");
|
|
53152
53308
|
|
|
53153
53309
|
// src/run-log-read.ts
|
|
53154
53310
|
init_cli_shared();
|
|
@@ -53749,7 +53905,7 @@ function registerApiReadCommands(program3, overrides) {
|
|
|
53749
53905
|
o.accept
|
|
53750
53906
|
);
|
|
53751
53907
|
if (zip) {
|
|
53752
|
-
(0,
|
|
53908
|
+
(0, import_node_fs52.writeFileSync)(o.out, body, "latin1");
|
|
53753
53909
|
return;
|
|
53754
53910
|
}
|
|
53755
53911
|
} catch (e) {
|
|
@@ -54624,7 +54780,7 @@ function registerSessionReport(program3) {
|
|
|
54624
54780
|
}
|
|
54625
54781
|
|
|
54626
54782
|
// src/stage-commands.ts
|
|
54627
|
-
var
|
|
54783
|
+
var import_node_fs53 = require("node:fs");
|
|
54628
54784
|
var import_node_path49 = require("node:path");
|
|
54629
54785
|
init_cli_shared();
|
|
54630
54786
|
init_clean_exit();
|
|
@@ -54873,8 +55029,8 @@ function registerStageCommands(program3) {
|
|
|
54873
55029
|
const repo = Array.isArray(project2?.repos) && typeof project2.repos[0] === "string" ? project2.repos[0] : slug;
|
|
54874
55030
|
const resolution = decideStage({
|
|
54875
55031
|
registry: { deployModel: project2?.deployModel, portRange, error: read.ok ? void 0 : read.error },
|
|
54876
|
-
hasCompose: (0,
|
|
54877
|
-
hasEnvExample: (0,
|
|
55032
|
+
hasCompose: (0, import_node_fs53.existsSync)((0, import_node_path49.join)(process.cwd(), "docker-compose.yml")),
|
|
55033
|
+
hasEnvExample: (0, import_node_fs53.existsSync)((0, import_node_path49.join)(process.cwd(), ".env.example")),
|
|
54878
55034
|
repo
|
|
54879
55035
|
});
|
|
54880
55036
|
if (resolution.source === "derived" && resolution.derived) {
|
|
@@ -55167,14 +55323,14 @@ vercel preview (${preview.branch}): ${d.state}${d.url ? ` \u2014 ${d.url}` : ""}
|
|
|
55167
55323
|
|
|
55168
55324
|
// src/tenant-artifact.ts
|
|
55169
55325
|
var import_node_crypto17 = require("node:crypto");
|
|
55170
|
-
var
|
|
55326
|
+
var import_node_fs54 = require("node:fs");
|
|
55171
55327
|
var import_promises11 = require("node:fs/promises");
|
|
55172
55328
|
var import_node_path50 = require("node:path");
|
|
55173
55329
|
var ARTIFACT_ID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
|
|
55174
55330
|
var MAX_BYTES2 = 5 * 1024 * 1024 * 1024;
|
|
55175
55331
|
async function sha256File(path2) {
|
|
55176
55332
|
const hash = (0, import_node_crypto17.createHash)("sha256");
|
|
55177
|
-
for await (const chunk of (0,
|
|
55333
|
+
for await (const chunk of (0, import_node_fs54.createReadStream)(path2)) hash.update(chunk);
|
|
55178
55334
|
return hash.digest("hex");
|
|
55179
55335
|
}
|
|
55180
55336
|
async function putTenantArtifact(repo, stage, inputPath, deps) {
|
|
@@ -55197,7 +55353,7 @@ async function putTenantArtifact(repo, stage, inputPath, deps) {
|
|
|
55197
55353
|
return [key, value];
|
|
55198
55354
|
}));
|
|
55199
55355
|
headers["content-length"] = String(info.size);
|
|
55200
|
-
const stream = (0,
|
|
55356
|
+
const stream = (0, import_node_fs54.createReadStream)(path2);
|
|
55201
55357
|
let uploaded;
|
|
55202
55358
|
try {
|
|
55203
55359
|
uploaded = await fetch(body.uploadUrl, {
|
|
@@ -55336,7 +55492,7 @@ function renderVerifySecrets(body) {
|
|
|
55336
55492
|
}
|
|
55337
55493
|
|
|
55338
55494
|
// src/command-register-developer.ts
|
|
55339
|
-
var
|
|
55495
|
+
var import_node_fs58 = require("node:fs");
|
|
55340
55496
|
init_clean_exit();
|
|
55341
55497
|
init_cli_shared();
|
|
55342
55498
|
init_error_codes();
|
|
@@ -55404,13 +55560,13 @@ async function executeWaveLand(plan, deps) {
|
|
|
55404
55560
|
// src/dist-drift.ts
|
|
55405
55561
|
var import_node_child_process20 = require("node:child_process");
|
|
55406
55562
|
var import_node_crypto19 = require("node:crypto");
|
|
55407
|
-
var
|
|
55563
|
+
var import_node_fs56 = require("node:fs");
|
|
55408
55564
|
var import_node_os24 = require("node:os");
|
|
55409
55565
|
var import_node_path52 = require("node:path");
|
|
55410
55566
|
|
|
55411
55567
|
// ../scripts/distribution-digest.mjs
|
|
55412
55568
|
var import_node_crypto18 = require("node:crypto");
|
|
55413
|
-
var
|
|
55569
|
+
var import_node_fs55 = require("node:fs");
|
|
55414
55570
|
var import_node_path51 = require("node:path");
|
|
55415
55571
|
var slash = (value) => value.replaceAll("\\", "/");
|
|
55416
55572
|
function repoPath(root, declaredPath, label) {
|
|
@@ -55424,7 +55580,7 @@ function repoPath(root, declaredPath, label) {
|
|
|
55424
55580
|
function digestFiles(files) {
|
|
55425
55581
|
const hash = (0, import_node_crypto18.createHash)("sha256");
|
|
55426
55582
|
for (const file of [...files].sort((a, b) => a.relative.localeCompare(b.relative))) {
|
|
55427
|
-
const content = file.stat.isSymbolicLink() ? Buffer.from((0,
|
|
55583
|
+
const content = file.stat.isSymbolicLink() ? Buffer.from((0, import_node_fs55.readlinkSync)(file.absolute), "utf8") : (0, import_node_fs55.readFileSync)(file.absolute);
|
|
55428
55584
|
hash.update(file.relative, "utf8");
|
|
55429
55585
|
hash.update("\0");
|
|
55430
55586
|
hash.update(file.stat.isSymbolicLink() ? "symlink" : "file", "utf8");
|
|
@@ -55439,8 +55595,8 @@ function digestFiles(files) {
|
|
|
55439
55595
|
function digestPackedFiles(packageRoot, packedFiles) {
|
|
55440
55596
|
return digestFiles(packedFiles.map((path2) => {
|
|
55441
55597
|
const absolute = repoPath(packageRoot, path2, "packed artifact identity path");
|
|
55442
|
-
if (!(0,
|
|
55443
|
-
return { absolute, relative: slash(path2), stat: (0,
|
|
55598
|
+
if (!(0, import_node_fs55.existsSync)(absolute)) throw new Error(`packed artifact identity path ${path2} does not exist`);
|
|
55599
|
+
return { absolute, relative: slash(path2), stat: (0, import_node_fs55.lstatSync)(absolute) };
|
|
55444
55600
|
}));
|
|
55445
55601
|
}
|
|
55446
55602
|
|
|
@@ -55525,12 +55681,12 @@ function renderDistDriftReceipt(receipt) {
|
|
|
55525
55681
|
return lines2;
|
|
55526
55682
|
}
|
|
55527
55683
|
function readOrNull(path2) {
|
|
55528
|
-
return (0,
|
|
55684
|
+
return (0, import_node_fs56.existsSync)(path2) ? (0, import_node_fs56.readFileSync)(path2) : null;
|
|
55529
55685
|
}
|
|
55530
55686
|
function walkFiles(root) {
|
|
55531
55687
|
const files = [];
|
|
55532
55688
|
const walk2 = (directory) => {
|
|
55533
|
-
for (const entry of (0,
|
|
55689
|
+
for (const entry of (0, import_node_fs56.readdirSync)(directory, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
|
|
55534
55690
|
const child2 = (0, import_node_path52.join)(directory, entry.name);
|
|
55535
55691
|
if (entry.isDirectory()) walk2(child2);
|
|
55536
55692
|
else files.push(child2);
|
|
@@ -55541,7 +55697,7 @@ function walkFiles(root) {
|
|
|
55541
55697
|
}
|
|
55542
55698
|
function bomPathFor(root) {
|
|
55543
55699
|
try {
|
|
55544
|
-
const registry2 = JSON.parse((0,
|
|
55700
|
+
const registry2 = JSON.parse((0, import_node_fs56.readFileSync)((0, import_node_path52.join)(root, "surfaces.json"), "utf8"));
|
|
55545
55701
|
return (0, import_node_path52.join)(root, registry2?.sharedAgentCore?.releaseMetadata?.bomPath ?? "distribution-bom.json");
|
|
55546
55702
|
} catch {
|
|
55547
55703
|
return (0, import_node_path52.join)(root, "distribution-bom.json");
|
|
@@ -55557,7 +55713,7 @@ function rebuildTo(packageRoot, outDir) {
|
|
|
55557
55713
|
});
|
|
55558
55714
|
}
|
|
55559
55715
|
function runDistStatus(root) {
|
|
55560
|
-
const stage = (0,
|
|
55716
|
+
const stage = (0, import_node_fs56.mkdtempSync)((0, import_node_path52.join)((0, import_node_os24.tmpdir)(), "mmi-dist-drift-"));
|
|
55561
55717
|
let overlayCount = 0;
|
|
55562
55718
|
try {
|
|
55563
55719
|
const cliOut = (0, import_node_path52.join)(stage, "cli-dist");
|
|
@@ -55573,19 +55729,19 @@ function runDistStatus(root) {
|
|
|
55573
55729
|
const tree = (path2) => readOrNull((0, import_node_path52.join)(root, path2));
|
|
55574
55730
|
const distRoot = (0, import_node_path52.join)(root, "cli", "dist");
|
|
55575
55731
|
const distTree = () => walkFiles(distRoot).map((absolute) => `cli/dist/${(0, import_node_path52.relative)(distRoot, absolute).replaceAll("\\", "/")}`);
|
|
55576
|
-
const bom = JSON.parse((0,
|
|
55732
|
+
const bom = JSON.parse((0, import_node_fs56.readFileSync)(bomPathFor(root), "utf8"));
|
|
55577
55733
|
const digest = (entries) => {
|
|
55578
55734
|
const overlay = (0, import_node_path52.join)(stage, `overlay-${overlayCount++}`);
|
|
55579
55735
|
for (const entry of entries) {
|
|
55580
55736
|
const target = (0, import_node_path52.join)(overlay, entry.path);
|
|
55581
|
-
(0,
|
|
55582
|
-
(0,
|
|
55737
|
+
(0, import_node_fs56.mkdirSync)((0, import_node_path52.dirname)(target), { recursive: true });
|
|
55738
|
+
(0, import_node_fs56.writeFileSync)(target, entry.bytes);
|
|
55583
55739
|
}
|
|
55584
55740
|
return digestPackedFiles(overlay, entries.map((entry) => entry.path));
|
|
55585
55741
|
};
|
|
55586
55742
|
return computeDistDriftReceipt({ committed, tree, rebuilt, distTree, bom, digest });
|
|
55587
55743
|
} finally {
|
|
55588
|
-
(0,
|
|
55744
|
+
(0, import_node_fs56.rmSync)(stage, { recursive: true, force: true });
|
|
55589
55745
|
}
|
|
55590
55746
|
}
|
|
55591
55747
|
|
|
@@ -55915,7 +56071,7 @@ function registerSchedulesLiftCommand(program3, deps = {}) {
|
|
|
55915
56071
|
|
|
55916
56072
|
// src/spawn-policy-core.ts
|
|
55917
56073
|
var import_node_child_process22 = require("node:child_process");
|
|
55918
|
-
var
|
|
56074
|
+
var import_node_fs57 = require("node:fs");
|
|
55919
56075
|
var import_node_path55 = require("node:path");
|
|
55920
56076
|
var SPAWNERS = ["spawn", "spawnSync", "exec", "execSync", "execFile", "execFileSync"];
|
|
55921
56077
|
var CALL_SOURCE = String.raw`(^|[^.\w$])(${SPAWNERS.join("|")})\s*\(`;
|
|
@@ -56002,7 +56158,7 @@ function runSpawnPolicy(root) {
|
|
|
56002
56158
|
for (const file of files) {
|
|
56003
56159
|
let raw;
|
|
56004
56160
|
try {
|
|
56005
|
-
raw = (0,
|
|
56161
|
+
raw = (0, import_node_fs57.readFileSync)((0, import_node_path55.join)(root, file), "utf8");
|
|
56006
56162
|
} catch {
|
|
56007
56163
|
continue;
|
|
56008
56164
|
}
|
|
@@ -56023,18 +56179,18 @@ function registerDeveloperCommands(program3) {
|
|
|
56023
56179
|
const rules = program3.command("rules").description("org-managed .gitignore delivery");
|
|
56024
56180
|
rules.command("gitignore").option("--write", "upsert the managed block into .gitignore (default: check only, non-zero exit on drift)").option("--json", "machine-readable output").description("verify (or --write) this repo's org-managed .gitignore block matches the SSOT").action((opts) => {
|
|
56025
56181
|
const path2 = (0, import_node_path56.join)(process.cwd(), ".gitignore");
|
|
56026
|
-
const current = (0,
|
|
56182
|
+
const current = (0, import_node_fs58.existsSync)(path2) ? (0, import_node_fs58.readFileSync)(path2, "utf8") : null;
|
|
56027
56183
|
const plan = planManagedGitignore(current);
|
|
56028
56184
|
const drift = [...plan.added.map((l) => `+${l}`), ...plan.removed.map((l) => `-${l}`)].join(", ") || "block normalize";
|
|
56029
56185
|
if (opts.json) {
|
|
56030
|
-
if (opts.write && plan.changed) (0,
|
|
56186
|
+
if (opts.write && plan.changed) (0, import_node_fs58.writeFileSync)(path2, plan.content, "utf8");
|
|
56031
56187
|
console.log(JSON.stringify(plan, null, 2));
|
|
56032
56188
|
if (!opts.write && plan.changed) process.exitCode = 1;
|
|
56033
56189
|
return;
|
|
56034
56190
|
}
|
|
56035
56191
|
if (opts.write) {
|
|
56036
56192
|
if (plan.changed) {
|
|
56037
|
-
(0,
|
|
56193
|
+
(0, import_node_fs58.writeFileSync)(path2, plan.content, "utf8");
|
|
56038
56194
|
console.log(`mmi-cli devops org rules gitignore: updated .gitignore (${drift})`);
|
|
56039
56195
|
} else {
|
|
56040
56196
|
console.log("mmi-cli devops org rules gitignore: up to date");
|
|
@@ -56243,17 +56399,18 @@ function registerDeveloperCommands(program3) {
|
|
|
56243
56399
|
}
|
|
56244
56400
|
});
|
|
56245
56401
|
const tests = program3.command("tests").description("a repo's test-policy.json \u2014 the opt-in test contract and its enforcement");
|
|
56246
|
-
tests.command("policy").description("enforce this repo's test-policy.json against the diff: a mandatory-zone change must carry a test, an unrequested new test file is refused, a `protected` test file may not be deleted or renamed away, and a `protected` entry naming a missing file is refused. Override any of them with a `Test-Policy-Override: <reason>` commit trailer (#3605)").option("--json", "machine-readable result: { ok,
|
|
56402
|
+
tests.command("policy").description("enforce this repo's test-policy.json against the diff: a mandatory-zone change must carry a test, an unrequested new test file is refused, a `protected` test file may not be deleted or renamed away, and a `protected` entry naming a missing file is refused. Override any of them with a `Test-Policy-Override: <reason>` commit trailer (#3605)").option("--json", "compact machine-readable result: { ok, testCommandsAllowed, commandClasses, findings[] }").option("--verbose", "include the full policy result in --json output").option("--base <ref>", "comparison base (default: TEST_POLICY_BASE, then origin/development, then origin/main)").option("--policy-ref <commit>", "load test-policy.json from the exact fetched origin/development commit and audit its protected/satisfiedBy paths against that commit's tree, not this checkout; valid only with --base origin/main").addOption(new Option("--repo <owner/repo>", "not accepted \u2014 tests policy reads the current checkout").hideHelp()).action(async (o) => {
|
|
56247
56403
|
try {
|
|
56248
56404
|
if (o.repo) {
|
|
56249
|
-
const rerun = `mmi-cli tests policy${o.base ? ` --base ${o.base}` : ""}${o.policyRef ? ` --policy-ref ${o.policyRef}` : ""}${o.json ? " --json" : ""}`;
|
|
56405
|
+
const rerun = `mmi-cli tests policy${o.base ? ` --base ${o.base}` : ""}${o.policyRef ? ` --policy-ref ${o.policyRef}` : ""}${o.json ? " --json" : ""}${o.verbose ? " --verbose" : ""}`;
|
|
56250
56406
|
const guard = planTrainApplyRepoGuard(o.repo, await resolveRepo(), rerun, "tests policy");
|
|
56251
56407
|
if (!guard.ok) return failGraceful(guard.message);
|
|
56252
56408
|
}
|
|
56253
56409
|
const root = await repoRoot();
|
|
56254
56410
|
const result = runTestPolicy(root, { base: o.base, policyRef: o.policyRef });
|
|
56255
56411
|
if (o.json) {
|
|
56256
|
-
|
|
56412
|
+
const { ok, testCommandsAllowed, commandClasses, findings } = result;
|
|
56413
|
+
consoleIo.log(o.verbose ? JSON.stringify(result, null, 2) : JSON.stringify({ ok, testCommandsAllowed, commandClasses, findings }));
|
|
56257
56414
|
if (!result.ok) process.exitCode = 1;
|
|
56258
56415
|
return;
|
|
56259
56416
|
}
|
|
@@ -56451,7 +56608,7 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
56451
56608
|
);
|
|
56452
56609
|
const result = applyPluginCachePlan(
|
|
56453
56610
|
plan,
|
|
56454
|
-
(p) => (0,
|
|
56611
|
+
(p) => (0, import_node_fs59.rmSync)(p, { recursive: true }),
|
|
56455
56612
|
stagingApplyFsGuard(configRoot)
|
|
56456
56613
|
);
|
|
56457
56614
|
return {
|
|
@@ -56486,7 +56643,7 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
56486
56643
|
// has no generated routing index would
|
|
56487
56644
|
// get a permanent — demanding an artifact it never asked for.
|
|
56488
56645
|
docsIndexState: (root) => {
|
|
56489
|
-
if (!(0,
|
|
56646
|
+
if (!(0, import_node_fs59.existsSync)((0, import_node_path57.join)(root, DOCS_INDEX_PATH))) return void 0;
|
|
56490
56647
|
const real = createDocsIndexDeps(root);
|
|
56491
56648
|
let docs;
|
|
56492
56649
|
const listDocs = () => docs ??= real.listDocs();
|
|
@@ -56495,7 +56652,7 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
56495
56652
|
},
|
|
56496
56653
|
// #4168: working-tree heal — write if drifted, then re-check. Commit remains the operator's step.
|
|
56497
56654
|
healDocsIndex: (root) => {
|
|
56498
|
-
if (!(0,
|
|
56655
|
+
if (!(0, import_node_fs59.existsSync)((0, import_node_path57.join)(root, DOCS_INDEX_PATH))) return { drift: false, docCount: 0 };
|
|
56499
56656
|
const real = createDocsIndexDeps(root);
|
|
56500
56657
|
let docs;
|
|
56501
56658
|
const listDocs = () => docs ??= real.listDocs();
|
|
@@ -56855,6 +57012,7 @@ function appActorDeps() {
|
|
|
56855
57012
|
};
|
|
56856
57013
|
}
|
|
56857
57014
|
setPollTokenProvider(async () => activeAppToken() ?? pollTokenOrUndefined(appActorDeps()));
|
|
57015
|
+
setGhReadTokenProvider(pollToken);
|
|
56858
57016
|
setStatusWriteTokenProvider(() => mintStatusWriteToken(appActorDeps()));
|
|
56859
57017
|
var registerPreAction = Reflect.get(program2, ["h", "ook"].join(""));
|
|
56860
57018
|
registerPreAction.call(program2, "preAction", async (_thisCommand, actionCommand) => {
|
|
@@ -56862,7 +57020,7 @@ registerPreAction.call(program2, "preAction", async (_thisCommand, actionCommand
|
|
|
56862
57020
|
appActorCommand = commandPath3;
|
|
56863
57021
|
emitCliCallTelemetry(commandPath3);
|
|
56864
57022
|
try {
|
|
56865
|
-
await activateAppActor(commandPath3, process.env, () => mintInstallationToken(appActorDeps()));
|
|
57023
|
+
await activateAppActor(commandPath3, process.env, () => APP_WRITE_COMMANDS.has(commandPath3) ? mintCommandWriteToken(appActorDeps(), commandPath3) : mintInstallationToken(appActorDeps()));
|
|
56866
57024
|
} catch (e) {
|
|
56867
57025
|
if (e instanceof AppActorError) return fail(e.message);
|
|
56868
57026
|
throw e;
|
|
@@ -57220,7 +57378,7 @@ project.command("set [owner/repo]").description("upsert project META (idempotent
|
|
|
57220
57378
|
if (dupe) return fail(`org project set: KEY "${dupe}" was passed to both --var and --set; --set is an alias of --var, so pass each KEY once`);
|
|
57221
57379
|
if (o.secretsFile) {
|
|
57222
57380
|
try {
|
|
57223
|
-
vars.push(`secrets=${(0,
|
|
57381
|
+
vars.push(`secrets=${(0, import_node_fs59.readFileSync)(o.secretsFile, "utf8")}`);
|
|
57224
57382
|
} catch (e) {
|
|
57225
57383
|
return fail(`org project set: cannot read --secrets-file ${o.secretsFile}: ${e.message}`);
|
|
57226
57384
|
}
|
|
@@ -57612,15 +57770,15 @@ function ciAuditDeps2() {
|
|
|
57612
57770
|
readSeedFile: (path2) => {
|
|
57613
57771
|
if (!root) return null;
|
|
57614
57772
|
const fullPath = (0, import_node_path57.join)(root, path2);
|
|
57615
|
-
return (0,
|
|
57773
|
+
return (0, import_node_fs59.existsSync)(fullPath) ? (0, import_node_fs59.readFileSync)(fullPath, "utf8") : null;
|
|
57616
57774
|
}
|
|
57617
57775
|
};
|
|
57618
57776
|
}
|
|
57619
57777
|
function hubRoot2() {
|
|
57620
57778
|
const fromPkg = (0, import_node_path57.join)(__dirname, "..", "..");
|
|
57621
57779
|
const marker = "skills/bootstrap/seeds/manifest.json";
|
|
57622
|
-
if ((0,
|
|
57623
|
-
if ((0,
|
|
57780
|
+
if ((0, import_node_fs59.existsSync)((0, import_node_path57.join)(fromPkg, marker))) return fromPkg;
|
|
57781
|
+
if ((0, import_node_fs59.existsSync)((0, import_node_path57.join)(process.cwd(), marker))) return process.cwd();
|
|
57624
57782
|
return null;
|
|
57625
57783
|
}
|
|
57626
57784
|
registerQueryCommands(program2);
|
|
@@ -57634,6 +57792,7 @@ registerDiscoveryCommands(program2);
|
|
|
57634
57792
|
registerExplainCommand(program2);
|
|
57635
57793
|
registerPrLifecycleCommands(program2);
|
|
57636
57794
|
registerApiReadCommands(program2);
|
|
57795
|
+
registerGithubBudgetCommand(program2, appActorDeps);
|
|
57637
57796
|
registerAppReadBrokerCommands(program2, async (repo) => requireRepo(repo));
|
|
57638
57797
|
var prBrokerRoot = program2.commands.find((c) => c.name() === "pr");
|
|
57639
57798
|
if (!prBrokerRoot) throw new Error("read broker: pr root must be registered before pr checks-required");
|
|
@@ -57750,10 +57909,10 @@ access.command("audit").description("audit collaborator roles + train-branch pus
|
|
|
57750
57909
|
targets = resolution.targets;
|
|
57751
57910
|
}
|
|
57752
57911
|
const derivedMatrix = registryProjects ? accessMatrixFromProjects(registryProjects) : {};
|
|
57753
|
-
const fileMatrix = (0,
|
|
57912
|
+
const fileMatrix = (0, import_node_fs59.existsSync)("access-matrix.json") ? loadAccessMatrix((0, import_node_fs59.readFileSync)("access-matrix.json", "utf8")) : {};
|
|
57754
57913
|
const matrix = mergeAccessMatrix(fileMatrix, derivedMatrix);
|
|
57755
57914
|
const dataAccess = registryProjects ? dataAccessContractsFromProjects(registryProjects) : { consumers: {} };
|
|
57756
|
-
const sanctioned = (0,
|
|
57915
|
+
const sanctioned = (0, import_node_fs59.existsSync)("access-matrix.json") ? loadSanctionedAdmins((0, import_node_fs59.readFileSync)("access-matrix.json", "utf8")) : {};
|
|
57757
57916
|
const report = await auditOrgAccess(targets, deps, matrix, dataAccess, sanctioned);
|
|
57758
57917
|
console.log(o.json ? JSON.stringify(report, null, 2) : renderAccessReport(report));
|
|
57759
57918
|
if (!report.ok) process.exitCode = 1;
|
|
@@ -57784,7 +57943,7 @@ function directoryBytes(path2) {
|
|
|
57784
57943
|
let total = 0;
|
|
57785
57944
|
let entries;
|
|
57786
57945
|
try {
|
|
57787
|
-
entries = (0,
|
|
57946
|
+
entries = (0, import_node_fs59.readdirSync)(path2, { withFileTypes: true });
|
|
57788
57947
|
} catch {
|
|
57789
57948
|
return 0;
|
|
57790
57949
|
}
|
|
@@ -57793,7 +57952,7 @@ function directoryBytes(path2) {
|
|
|
57793
57952
|
if (entry.isDirectory()) total += directoryBytes(child2);
|
|
57794
57953
|
else {
|
|
57795
57954
|
try {
|
|
57796
|
-
total += (0,
|
|
57955
|
+
total += (0, import_node_fs59.statSync)(child2).size;
|
|
57797
57956
|
} catch {
|
|
57798
57957
|
}
|
|
57799
57958
|
}
|
|
@@ -57801,25 +57960,25 @@ function directoryBytes(path2) {
|
|
|
57801
57960
|
return total;
|
|
57802
57961
|
}
|
|
57803
57962
|
function listDirEntries(dir) {
|
|
57804
|
-
return (0,
|
|
57963
|
+
return (0, import_node_fs59.readdirSync)(dir, { withFileTypes: true }).map((d) => ({ name: d.name, isDirectory: d.isDirectory() }));
|
|
57805
57964
|
}
|
|
57806
57965
|
function readInstalledPluginRefs(configRoot) {
|
|
57807
57966
|
const p = installedPluginsPathForConfig(configRoot);
|
|
57808
|
-
if (!(0,
|
|
57967
|
+
if (!(0, import_node_fs59.existsSync)(p)) return [];
|
|
57809
57968
|
try {
|
|
57810
|
-
return installedPluginPaths((0,
|
|
57969
|
+
return installedPluginPaths((0, import_node_fs59.readFileSync)(p, "utf8"));
|
|
57811
57970
|
} catch {
|
|
57812
57971
|
return null;
|
|
57813
57972
|
}
|
|
57814
57973
|
}
|
|
57815
57974
|
function pluginCacheFsDeps(configRoot, dirBytes) {
|
|
57816
57975
|
return {
|
|
57817
|
-
exists: (p) => (0,
|
|
57818
|
-
listVersionDirs: (root) => (0,
|
|
57976
|
+
exists: (p) => (0, import_node_fs59.existsSync)(p),
|
|
57977
|
+
listVersionDirs: (root) => (0, import_node_fs59.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name),
|
|
57819
57978
|
dirBytes,
|
|
57820
|
-
listStagingDirs: (root) => (0,
|
|
57979
|
+
listStagingDirs: (root) => (0, import_node_fs59.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => {
|
|
57821
57980
|
try {
|
|
57822
|
-
return { name: d.name, mtimeMs: newestMtimeMs((0, import_node_path57.join)(root, d.name), listDirEntries, (p) => (0,
|
|
57981
|
+
return { name: d.name, mtimeMs: newestMtimeMs((0, import_node_path57.join)(root, d.name), listDirEntries, (p) => (0, import_node_fs59.statSync)(p).mtimeMs) };
|
|
57823
57982
|
} catch {
|
|
57824
57983
|
return { name: d.name, mtimeMs: Date.now() };
|
|
57825
57984
|
}
|
|
@@ -57834,9 +57993,9 @@ function stagingApplyFsGuard(configRoot) {
|
|
|
57834
57993
|
referencedPaths: () => readInstalledPluginRefs(configRoot),
|
|
57835
57994
|
mtimeMs: (name) => {
|
|
57836
57995
|
const p = (0, import_node_path57.join)(stagingRoot, name);
|
|
57837
|
-
if (!(0,
|
|
57996
|
+
if (!(0, import_node_fs59.existsSync)(p)) return null;
|
|
57838
57997
|
try {
|
|
57839
|
-
return newestMtimeMs(p, listDirEntries, (q) => (0,
|
|
57998
|
+
return newestMtimeMs(p, listDirEntries, (q) => (0, import_node_fs59.statSync)(q).mtimeMs);
|
|
57840
57999
|
} catch {
|
|
57841
58000
|
return null;
|
|
57842
58001
|
}
|
|
@@ -57862,7 +58021,7 @@ program2.command("plugin-prune").description(`prune stale cached MMI plugin vers
|
|
|
57862
58021
|
{ withBytes: true, configRoot, includeStaging: surface !== "codex" }
|
|
57863
58022
|
);
|
|
57864
58023
|
const anythingToDelete = plan.prune.length > 0 || plan.staging.length > 0;
|
|
57865
|
-
const result = o.apply && anythingToDelete ? applyPluginCachePlan(plan, (p) => (0,
|
|
58024
|
+
const result = o.apply && anythingToDelete ? applyPluginCachePlan(plan, (p) => (0, import_node_fs59.rmSync)(p, { recursive: true, force: true }), stagingApplyFsGuard(configRoot)) : void 0;
|
|
57866
58025
|
const warnings = plan.prune.length > 0 ? [CONCURRENT_SESSION_WARNING] : [];
|
|
57867
58026
|
if (o.json) console.log(JSON.stringify({ ...plan, warnings, applied: result ?? null }));
|
|
57868
58027
|
else console.log(renderPluginCachePlan(plan, result));
|