@mutmutco/codex-plugin 4.5.117 → 4.5.118
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/.codex-plugin/plugin.json +1 -1
- package/cli/dist/main.cjs +926 -730
- package/cli/package.json +1 -1
- package/package.json +1 -1
package/cli/dist/main.cjs
CHANGED
|
@@ -4751,7 +4751,7 @@ function useColor() {
|
|
|
4751
4751
|
var program = new Command();
|
|
4752
4752
|
|
|
4753
4753
|
// src/command-composition.ts
|
|
4754
|
-
var
|
|
4754
|
+
var import_node_fs57 = require("node:fs");
|
|
4755
4755
|
init_clean_exit();
|
|
4756
4756
|
init_cli_shared();
|
|
4757
4757
|
|
|
@@ -5653,13 +5653,13 @@ function resolveVerbAliasShim(argv) {
|
|
|
5653
5653
|
}
|
|
5654
5654
|
|
|
5655
5655
|
// src/command-composition.ts
|
|
5656
|
-
var
|
|
5657
|
-
var
|
|
5656
|
+
var import_node_os25 = require("node:os");
|
|
5657
|
+
var import_node_path54 = require("node:path");
|
|
5658
5658
|
|
|
5659
5659
|
// src/board-read.ts
|
|
5660
|
-
var
|
|
5661
|
-
var
|
|
5662
|
-
var
|
|
5660
|
+
var import_node_fs14 = require("node:fs");
|
|
5661
|
+
var import_node_os10 = require("node:os");
|
|
5662
|
+
var import_node_path12 = require("node:path");
|
|
5663
5663
|
init_cli_shared();
|
|
5664
5664
|
init_github_client();
|
|
5665
5665
|
|
|
@@ -5667,21 +5667,35 @@ init_github_client();
|
|
|
5667
5667
|
init_fetch_retry();
|
|
5668
5668
|
init_client_version();
|
|
5669
5669
|
var BOARD_SNAPSHOT_TIMEOUT_MS = 25e3;
|
|
5670
|
+
var BOARD_SNAPSHOT_EXIT_CODES = {
|
|
5671
|
+
"hub-unreachable": 20,
|
|
5672
|
+
"app-quota-exhausted": 21,
|
|
5673
|
+
refused: 22
|
|
5674
|
+
};
|
|
5675
|
+
var BoardSnapshotFailure = class extends Error {
|
|
5676
|
+
constructor(receipt) {
|
|
5677
|
+
super(receipt.reason);
|
|
5678
|
+
this.receipt = receipt;
|
|
5679
|
+
this.exitCode = BOARD_SNAPSHOT_EXIT_CODES[receipt.outcome];
|
|
5680
|
+
}
|
|
5681
|
+
receipt;
|
|
5682
|
+
exitCode;
|
|
5683
|
+
};
|
|
5670
5684
|
function isSnapshotShape(body) {
|
|
5671
5685
|
const b = body;
|
|
5672
5686
|
const rate = b?.github?.rateLimit;
|
|
5673
5687
|
const staleValid = b?.stale === void 0 || typeof b.stale === "object" && b.stale !== null && Number.isFinite(b.stale.ageMs) && b.stale.ageMs >= 0;
|
|
5674
|
-
const githubValid = b?.github === void 0 || b.github.credential === "app_installation" && (rate === void 0 || Number.isFinite(rate?.limit) && Number.isFinite(rate?.remaining) && Number.isFinite(rate?.cost) && typeof rate?.resetAt === "string");
|
|
5688
|
+
const githubValid = b?.github === void 0 || b.github !== null && typeof b.github === "object" && b.github.credential === "app_installation" && (rate === void 0 || Number.isFinite(rate?.limit) && Number.isFinite(rate?.remaining) && Number.isFinite(rate?.cost) && typeof rate?.resetAt === "string");
|
|
5675
5689
|
return Boolean(
|
|
5676
5690
|
b && typeof b === "object" && typeof b.project?.id === "string" && typeof b.project?.title === "string" && typeof b.viewer === "string" && b.viewer.length > 0 && Array.isArray(b.nodes) && Array.isArray(b.writableRepos) && Array.isArray(b.unreadableRepos) && Array.isArray(b.pullRequests) && Array.isArray(b.warnings) && typeof b.partial === "boolean" && (b.source === void 0 || b.source === "live" || b.source === "cache") && (b.builtAt === void 0 || typeof b.builtAt === "string" && Number.isFinite(Date.parse(b.builtAt))) && (b.eventCursor === void 0 || Number.isInteger(b.eventCursor) && b.eventCursor >= 0) && githubValid && staleValid
|
|
5677
5691
|
);
|
|
5678
5692
|
}
|
|
5679
5693
|
async function fetchHubBoardSnapshot(request, deps) {
|
|
5680
5694
|
if (!deps.baseUrl) return { state: "unavailable", reason: "no Hub API URL (set MMI_HUB_URL or use a current MMI CLI/plugin build)" };
|
|
5681
|
-
const token = await deps.token();
|
|
5682
|
-
if (!token) return { state: "unavailable", reason: "no Hub session token (run `gh auth login`)" };
|
|
5683
5695
|
let res;
|
|
5684
5696
|
try {
|
|
5697
|
+
const token = await deps.token();
|
|
5698
|
+
if (!token) return { state: "unavailable", reason: "no Hub session token (run `gh auth login`)" };
|
|
5685
5699
|
res = await fetchWithRetry(
|
|
5686
5700
|
deps.fetch ?? fetch,
|
|
5687
5701
|
`${deps.baseUrl.replace(/\/$/, "")}/board/snapshot`,
|
|
@@ -5715,10 +5729,26 @@ async function fetchHubBoardSnapshot(request, deps) {
|
|
|
5715
5729
|
return {
|
|
5716
5730
|
state: "unavailable",
|
|
5717
5731
|
reason: `GitHub App quota exhausted${reset}`,
|
|
5732
|
+
appQuotaExhausted: true,
|
|
5733
|
+
pool: "graphql",
|
|
5734
|
+
...typeof body2.resetAt === "string" ? { resetAt: body2.resetAt } : {},
|
|
5718
5735
|
...body2.github?.credential === "app_installation" && body2.github.resource === "graphql" && /^github-app-v1:[a-f0-9]{64}$/.test(body2.github.quotaScope ?? "") ? { quota: { status: "rate_limited", ...typeof body2.resetAt === "string" ? { resetAt: body2.resetAt } : {}, github: { credential: "app_installation", resource: "graphql", quotaScope: body2.github.quotaScope } } } : {}
|
|
5719
5736
|
};
|
|
5720
5737
|
}
|
|
5721
5738
|
}
|
|
5739
|
+
if (res.status === 503) {
|
|
5740
|
+
const body2 = await res.json().catch(() => null);
|
|
5741
|
+
if (body2?.code === "github-rate-limited") {
|
|
5742
|
+
const reset = typeof body2.resetAt === "string" ? `; resets ${body2.resetAt}` : "; reset time unavailable";
|
|
5743
|
+
return {
|
|
5744
|
+
state: "unavailable",
|
|
5745
|
+
reason: `GitHub App allowance exhausted${reset}`,
|
|
5746
|
+
appQuotaExhausted: true,
|
|
5747
|
+
pool: "rest",
|
|
5748
|
+
...typeof body2.resetAt === "string" ? { resetAt: body2.resetAt } : {}
|
|
5749
|
+
};
|
|
5750
|
+
}
|
|
5751
|
+
}
|
|
5722
5752
|
if (!res.ok) return { state: "unavailable", reason: `board snapshot HTTP ${res.status}` };
|
|
5723
5753
|
const body = await res.json().catch(() => null);
|
|
5724
5754
|
if (!isSnapshotShape(body)) return { state: "unavailable", reason: "malformed board snapshot response" };
|
|
@@ -5816,6 +5846,18 @@ var activeQuotaScope;
|
|
|
5816
5846
|
function activeAppQuotaScope() {
|
|
5817
5847
|
return activeQuotaScope;
|
|
5818
5848
|
}
|
|
5849
|
+
async function readAppVaultSecret(read) {
|
|
5850
|
+
try {
|
|
5851
|
+
return await read();
|
|
5852
|
+
} catch (e) {
|
|
5853
|
+
const reason = e.message;
|
|
5854
|
+
if (/^(Hub GitHub App allowance used up|rate limited)/.test(reason)) {
|
|
5855
|
+
throw new AppActorError(`app actor: the vault could not read the App credentials because GitHub is rate-limited, not a denial: ${reason}`, "mint-failed");
|
|
5856
|
+
}
|
|
5857
|
+
if (/^authority refused|\(HTTP 404\b/.test(reason)) return null;
|
|
5858
|
+
throw new AppActorError(`app actor: the vault read of the App credentials failed, not a denial: ${reason}`, "mint-failed");
|
|
5859
|
+
}
|
|
5860
|
+
}
|
|
5819
5861
|
async function mintInstallationToken(deps) {
|
|
5820
5862
|
const [appId, installationId, privateKey] = await Promise.all(APP_VAULT_KEYS.map((k) => deps.fetchSecret(k)));
|
|
5821
5863
|
if (!appId || !installationId || !privateKey) {
|
|
@@ -6298,6 +6340,93 @@ function isReleaseShaDeployEnumerationCandidate(row, nonDeployEvents) {
|
|
|
6298
6340
|
|
|
6299
6341
|
// src/pr-checks-rest.ts
|
|
6300
6342
|
init_github_quota();
|
|
6343
|
+
|
|
6344
|
+
// src/rest-etag-cache.ts
|
|
6345
|
+
var import_node_crypto5 = require("node:crypto");
|
|
6346
|
+
var import_node_fs11 = require("node:fs");
|
|
6347
|
+
var import_node_os4 = require("node:os");
|
|
6348
|
+
var import_node_path9 = require("node:path");
|
|
6349
|
+
var MAX_AGE_MS = 24 * 60 * 6e4;
|
|
6350
|
+
var MAX_ENTRIES = 256;
|
|
6351
|
+
var MAX_BYTES = 16 * 1024 * 1024;
|
|
6352
|
+
var MAX_ENTRY_BYTES = 1024 * 1024;
|
|
6353
|
+
function restEtagCacheDir() {
|
|
6354
|
+
if (process.env.MMI_REST_ETAG_CACHE_DIR) return process.env.MMI_REST_ETAG_CACHE_DIR;
|
|
6355
|
+
return process.platform === "win32" ? (0, import_node_path9.join)(process.env.LOCALAPPDATA || (0, import_node_path9.join)((0, import_node_os4.homedir)(), "AppData", "Local"), "MMI Future", "mmi-cli", "rest-etags") : (0, import_node_path9.join)(process.env.XDG_CACHE_HOME || (0, import_node_path9.join)((0, import_node_os4.homedir)(), ".cache"), "mmi-cli", "rest-etags");
|
|
6356
|
+
}
|
|
6357
|
+
function entryPath(dir, key) {
|
|
6358
|
+
return (0, import_node_path9.join)(dir, `${(0, import_node_crypto5.createHash)("sha256").update(key).digest("hex")}.json`);
|
|
6359
|
+
}
|
|
6360
|
+
function readRestEtag(key, dir = restEtagCacheDir()) {
|
|
6361
|
+
if (dir === "off") return void 0;
|
|
6362
|
+
try {
|
|
6363
|
+
const path2 = entryPath(dir, key);
|
|
6364
|
+
if ((0, import_node_fs11.statSync)(path2).size > MAX_ENTRY_BYTES) return void 0;
|
|
6365
|
+
const entry = JSON.parse((0, import_node_fs11.readFileSync)(path2, "utf8"));
|
|
6366
|
+
const age = Date.now() - entry.storedAt;
|
|
6367
|
+
if (typeof entry.etag === "string" && entry.etag && !/[\r\n]/.test(entry.etag) && typeof entry.body === "string" && Number.isFinite(entry.storedAt) && age >= 0 && age <= MAX_AGE_MS) return entry;
|
|
6368
|
+
} catch {
|
|
6369
|
+
}
|
|
6370
|
+
return void 0;
|
|
6371
|
+
}
|
|
6372
|
+
function deleteRestEtag(key, dir = restEtagCacheDir()) {
|
|
6373
|
+
if (dir === "off") return;
|
|
6374
|
+
try {
|
|
6375
|
+
(0, import_node_fs11.rmSync)(entryPath(dir, key), { force: true });
|
|
6376
|
+
} catch {
|
|
6377
|
+
}
|
|
6378
|
+
}
|
|
6379
|
+
function prune(dir) {
|
|
6380
|
+
const now = Date.now();
|
|
6381
|
+
const files = (0, import_node_fs11.readdirSync)(dir).filter((name) => /^[a-f0-9]{64}\.json(?:\.tmp-.+)?$/.test(name)).flatMap((name) => {
|
|
6382
|
+
try {
|
|
6383
|
+
const path2 = (0, import_node_path9.join)(dir, name);
|
|
6384
|
+
const stat4 = (0, import_node_fs11.statSync)(path2);
|
|
6385
|
+
if (now - stat4.mtimeMs > MAX_AGE_MS) {
|
|
6386
|
+
(0, import_node_fs11.rmSync)(path2, { force: true });
|
|
6387
|
+
return [];
|
|
6388
|
+
}
|
|
6389
|
+
return name.endsWith(".json") ? [{ path: path2, size: stat4.size, at: stat4.mtimeMs }] : [];
|
|
6390
|
+
} catch {
|
|
6391
|
+
return [];
|
|
6392
|
+
}
|
|
6393
|
+
}).sort((a, b) => a.at - b.at);
|
|
6394
|
+
let bytes = files.reduce((sum, f) => sum + f.size, 0);
|
|
6395
|
+
let count = files.length;
|
|
6396
|
+
for (const file of files) {
|
|
6397
|
+
if (count <= MAX_ENTRIES && bytes <= MAX_BYTES) break;
|
|
6398
|
+
try {
|
|
6399
|
+
(0, import_node_fs11.rmSync)(file.path, { force: true });
|
|
6400
|
+
bytes -= file.size;
|
|
6401
|
+
count--;
|
|
6402
|
+
} catch {
|
|
6403
|
+
}
|
|
6404
|
+
}
|
|
6405
|
+
}
|
|
6406
|
+
function writeRestEtag(key, entry, dir = restEtagCacheDir()) {
|
|
6407
|
+
if (dir === "off") return;
|
|
6408
|
+
const path2 = entryPath(dir, key);
|
|
6409
|
+
const tmp = `${path2}.tmp-${process.pid}-${(0, import_node_crypto5.randomUUID)()}`;
|
|
6410
|
+
try {
|
|
6411
|
+
const data = JSON.stringify({ etag: entry.etag, body: entry.body, storedAt: Date.now() });
|
|
6412
|
+
if (Buffer.byteLength(data) > MAX_ENTRY_BYTES) {
|
|
6413
|
+
deleteRestEtag(key, dir);
|
|
6414
|
+
return;
|
|
6415
|
+
}
|
|
6416
|
+
(0, import_node_fs11.mkdirSync)(dir, { recursive: true, mode: 448 });
|
|
6417
|
+
(0, import_node_fs11.writeFileSync)(tmp, data, { mode: 384, flag: "wx" });
|
|
6418
|
+
(0, import_node_fs11.renameSync)(tmp, path2);
|
|
6419
|
+
prune(dir);
|
|
6420
|
+
} catch {
|
|
6421
|
+
} finally {
|
|
6422
|
+
try {
|
|
6423
|
+
(0, import_node_fs11.rmSync)(tmp, { force: true });
|
|
6424
|
+
} catch {
|
|
6425
|
+
}
|
|
6426
|
+
}
|
|
6427
|
+
}
|
|
6428
|
+
|
|
6429
|
+
// src/pr-checks-rest.ts
|
|
6301
6430
|
var REST_GH_TIMEOUT_MS = 2e4;
|
|
6302
6431
|
var pollTokenProvider;
|
|
6303
6432
|
var pollTokenOnce;
|
|
@@ -6382,8 +6511,9 @@ function observedCorePool(source, nowMs) {
|
|
|
6382
6511
|
async function defaultGhApi(args, env = process.env) {
|
|
6383
6512
|
const appToken = await pollToken();
|
|
6384
6513
|
const source = appToken ? "app" : "user";
|
|
6385
|
-
const key = `${source}\0${args.join("\0")}`;
|
|
6386
|
-
const cached = etagCache.get(key);
|
|
6514
|
+
const key = `${source}\0${env.GH_HOST || "github.com"}\0${args.join("\0")}`;
|
|
6515
|
+
const cached = etagCache.get(key) ?? readRestEtag(key);
|
|
6516
|
+
if (cached) etagCache.set(key, cached);
|
|
6387
6517
|
let stdout;
|
|
6388
6518
|
try {
|
|
6389
6519
|
({ stdout } = await execFileP("gh", ["api", "--include", ...cached ? ["-H", `If-None-Match: ${cached.etag}`] : [], ...args], {
|
|
@@ -6397,31 +6527,37 @@ async function defaultGhApi(args, env = process.env) {
|
|
|
6397
6527
|
} catch (e) {
|
|
6398
6528
|
const out = e.stdout;
|
|
6399
6529
|
const errOut = typeof out === "string" ? out : void 0;
|
|
6400
|
-
const
|
|
6530
|
+
const status2 = errOut !== void 0 ? parseIncludedOutput(errOut).status : void 0;
|
|
6401
6531
|
if (errOut !== void 0) notePoolHeaders(source, errOut, Date.now());
|
|
6402
|
-
if (cached &&
|
|
6532
|
+
if (cached && status2 === 304) {
|
|
6403
6533
|
lastPollSource = source;
|
|
6404
6534
|
return cached.body;
|
|
6405
6535
|
}
|
|
6406
|
-
if (
|
|
6536
|
+
if (status2 === 403 || status2 === 429) {
|
|
6407
6537
|
const path2 = args.filter((a) => !a.startsWith("-")).join(" ") || args.join(" ");
|
|
6408
6538
|
const refusal = errOut !== void 0 ? describeRefusal(errOut) : "no rate-limit headers or message";
|
|
6409
|
-
if (
|
|
6539
|
+
if (status2 === 403 && /Resource not accessible by integration/i.test(refusal)) {
|
|
6410
6540
|
throw new Error(
|
|
6411
6541
|
`poll read refused: App token lacks permission for ${path2} (HTTP 403, response: ${refusal}) \u2014 reads never fall back to the owner's token (#8030); add the permission to APP_POLL_PERMISSIONS / the App installation`
|
|
6412
6542
|
);
|
|
6413
6543
|
}
|
|
6414
6544
|
throw Object.assign(new Error(
|
|
6415
|
-
`poll read refused on the ${source} pool (HTTP ${
|
|
6416
|
-
), { status, stdout: errOut, stderr: e.stderr });
|
|
6545
|
+
`poll read refused on the ${source} pool (HTTP ${status2}, response: ${refusal}) \u2014 reads stay on the ${source === "app" ? "App" : "ambient identity"} (#8030); the wait re-arms after reset`
|
|
6546
|
+
), { status: status2, stdout: errOut, stderr: e.stderr });
|
|
6417
6547
|
}
|
|
6418
6548
|
throw e;
|
|
6419
6549
|
}
|
|
6420
|
-
const { body, etag, pages } = parseIncludedOutput(stdout);
|
|
6550
|
+
const { body, status, etag, pages } = parseIncludedOutput(stdout);
|
|
6421
6551
|
notePoolHeaders(source, stdout, Date.now());
|
|
6422
6552
|
lastPollSource = source;
|
|
6423
|
-
if (
|
|
6424
|
-
|
|
6553
|
+
if (cached && status === 304) return cached.body;
|
|
6554
|
+
if (status === 200 && etag && pages === 1) {
|
|
6555
|
+
etagCache.set(key, { etag, body });
|
|
6556
|
+
writeRestEtag(key, { etag, body });
|
|
6557
|
+
} else {
|
|
6558
|
+
etagCache.delete(key);
|
|
6559
|
+
deleteRestEtag(key);
|
|
6560
|
+
}
|
|
6425
6561
|
return body;
|
|
6426
6562
|
}
|
|
6427
6563
|
function classifyCheckRun(run) {
|
|
@@ -8526,12 +8662,12 @@ async function fetchSchedulesList(deps) {
|
|
|
8526
8662
|
return null;
|
|
8527
8663
|
}
|
|
8528
8664
|
}
|
|
8529
|
-
async function fetchOrgConfig(deps) {
|
|
8665
|
+
async function fetchOrgConfig(deps, spendMinutes) {
|
|
8530
8666
|
if (!deps.baseUrl) return null;
|
|
8531
8667
|
const token = await deps.token();
|
|
8532
8668
|
if (!token) return null;
|
|
8533
8669
|
try {
|
|
8534
|
-
const res = await retriedFetch(deps, `${deps.baseUrl.replace(/\/$/, "")}${ORG_CONFIG_PATH}`, {
|
|
8670
|
+
const res = await retriedFetch(deps, `${deps.baseUrl.replace(/\/$/, "")}${ORG_CONFIG_PATH}${spendMinutes === void 0 ? "" : `?github-spend-minutes=${spendMinutes}`}`, {
|
|
8535
8671
|
method: "GET",
|
|
8536
8672
|
headers: { Authorization: `Bearer ${token}` }
|
|
8537
8673
|
});
|
|
@@ -9765,14 +9901,14 @@ async function secretsPreflight(deps, opts) {
|
|
|
9765
9901
|
|
|
9766
9902
|
// src/secrets-execution.ts
|
|
9767
9903
|
var import_node_child_process4 = require("node:child_process");
|
|
9768
|
-
var
|
|
9904
|
+
var import_node_os6 = require("node:os");
|
|
9769
9905
|
init_clean_exit();
|
|
9770
9906
|
|
|
9771
9907
|
// src/gh-create.ts
|
|
9772
9908
|
var import_promises = require("node:fs/promises");
|
|
9773
|
-
var
|
|
9774
|
-
var
|
|
9775
|
-
var
|
|
9909
|
+
var import_node_os5 = require("node:os");
|
|
9910
|
+
var import_node_path10 = require("node:path");
|
|
9911
|
+
var import_node_crypto6 = require("node:crypto");
|
|
9776
9912
|
|
|
9777
9913
|
// src/board-priority.ts
|
|
9778
9914
|
var BOARD_PRIORITY_NAMES = ["Urgent", "High", "Medium", "Low"];
|
|
@@ -9858,9 +9994,9 @@ async function bodyArgsViaFile(args, deps = {}) {
|
|
|
9858
9994
|
const write = deps.write ?? import_promises.writeFile;
|
|
9859
9995
|
const remove2 = deps.remove ?? import_promises.unlink;
|
|
9860
9996
|
const ensureDir = deps.ensureDir ?? import_promises.mkdir;
|
|
9861
|
-
const dir = deps.dir ?? (0,
|
|
9862
|
-
const file = (0,
|
|
9863
|
-
await ensureDir((0,
|
|
9997
|
+
const dir = deps.dir ?? (0, import_node_os5.tmpdir)();
|
|
9998
|
+
const file = (0, import_node_path10.join)(dir, `mmi-gh-body-${process.pid}-${(0, import_node_crypto6.randomBytes)(4).toString("hex")}.md`);
|
|
9999
|
+
await ensureDir((0, import_node_path10.dirname)(file), { recursive: true }).catch(() => {
|
|
9864
10000
|
});
|
|
9865
10001
|
await write(file, args[i + 1], "utf8");
|
|
9866
10002
|
return {
|
|
@@ -10188,8 +10324,8 @@ async function defaultRestCreatePr(exec2, input, deps = {}) {
|
|
|
10188
10324
|
const write = deps.write ?? import_promises.writeFile;
|
|
10189
10325
|
const remove2 = deps.remove ?? import_promises.unlink;
|
|
10190
10326
|
const ensureDir = deps.ensureDir ?? import_promises.mkdir;
|
|
10191
|
-
const dir = deps.dir ?? (0,
|
|
10192
|
-
const file = (0,
|
|
10327
|
+
const dir = deps.dir ?? (0, import_node_os5.tmpdir)();
|
|
10328
|
+
const file = (0, import_node_path10.join)(dir, `mmi-rest-pr-${process.pid}-${(0, import_node_crypto6.randomBytes)(4).toString("hex")}.json`);
|
|
10193
10329
|
const payload = {
|
|
10194
10330
|
title: input.title,
|
|
10195
10331
|
head: input.head,
|
|
@@ -10197,7 +10333,7 @@ async function defaultRestCreatePr(exec2, input, deps = {}) {
|
|
|
10197
10333
|
};
|
|
10198
10334
|
if (input.base) payload.base = input.base;
|
|
10199
10335
|
if (input.draft) payload.draft = true;
|
|
10200
|
-
await ensureDir((0,
|
|
10336
|
+
await ensureDir((0, import_node_path10.dirname)(file), { recursive: true }).catch(() => {
|
|
10201
10337
|
});
|
|
10202
10338
|
await write(file, JSON.stringify(payload), "utf8");
|
|
10203
10339
|
const args = [
|
|
@@ -11133,7 +11269,7 @@ function resolveSpawnTarget(command, args, platform2 = process.platform) {
|
|
|
11133
11269
|
}
|
|
11134
11270
|
function spawnExitCode(status, signal) {
|
|
11135
11271
|
if (status != null) return status;
|
|
11136
|
-
const signo = signal ?
|
|
11272
|
+
const signo = signal ? import_node_os6.constants.signals[signal] : void 0;
|
|
11137
11273
|
return signo ? 128 + signo : 1;
|
|
11138
11274
|
}
|
|
11139
11275
|
function defaultSpawn(command, args, env) {
|
|
@@ -11589,14 +11725,14 @@ function findDuplicateLesson(source, openLessons) {
|
|
|
11589
11725
|
}
|
|
11590
11726
|
|
|
11591
11727
|
// src/session-identity.ts
|
|
11592
|
-
var
|
|
11593
|
-
var
|
|
11728
|
+
var import_node_crypto7 = require("node:crypto");
|
|
11729
|
+
var import_node_os9 = require("node:os");
|
|
11594
11730
|
|
|
11595
11731
|
// src/plugin-guard-io.ts
|
|
11596
|
-
var
|
|
11732
|
+
var import_node_fs13 = require("node:fs");
|
|
11597
11733
|
var import_node_child_process5 = require("node:child_process");
|
|
11598
|
-
var
|
|
11599
|
-
var
|
|
11734
|
+
var import_node_path11 = require("node:path");
|
|
11735
|
+
var import_node_os8 = require("node:os");
|
|
11600
11736
|
|
|
11601
11737
|
// src/marketplace-autoupdate.ts
|
|
11602
11738
|
var KNOWN_MARKETPLACES_RELATIVE = [".claude", "plugins", "known_marketplaces.json"];
|
|
@@ -11740,8 +11876,8 @@ function buildPluginGuardLine(state, opts = {}) {
|
|
|
11740
11876
|
}
|
|
11741
11877
|
|
|
11742
11878
|
// src/host-doc-lock.ts
|
|
11743
|
-
var
|
|
11744
|
-
var
|
|
11879
|
+
var import_node_fs12 = require("node:fs");
|
|
11880
|
+
var import_node_os7 = require("node:os");
|
|
11745
11881
|
var SHARED_DOC_LOCK_STALE_MS = 3e4;
|
|
11746
11882
|
var SHARED_DOC_LOCK_ATTEMPTS = 50;
|
|
11747
11883
|
var SHARED_DOC_LOCK_INTERVAL_MS = 100;
|
|
@@ -11754,7 +11890,7 @@ function lockContent(options) {
|
|
|
11754
11890
|
}
|
|
11755
11891
|
function readHolder(lockPath) {
|
|
11756
11892
|
try {
|
|
11757
|
-
const parsed = JSON.parse((0,
|
|
11893
|
+
const parsed = JSON.parse((0, import_node_fs12.readFileSync)(lockPath, "utf8"));
|
|
11758
11894
|
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return null;
|
|
11759
11895
|
return parsed;
|
|
11760
11896
|
} catch {
|
|
@@ -11766,7 +11902,7 @@ function lockAgeMs(lockPath, now) {
|
|
|
11766
11902
|
const declared = typeof holder?.acquiredAt === "string" ? Date.parse(holder.acquiredAt) : Number.NaN;
|
|
11767
11903
|
if (!Number.isNaN(declared)) return Math.max(0, now - declared);
|
|
11768
11904
|
try {
|
|
11769
|
-
return Math.max(0, now - (0,
|
|
11905
|
+
return Math.max(0, now - (0, import_node_fs12.statSync)(lockPath).mtimeMs);
|
|
11770
11906
|
} catch {
|
|
11771
11907
|
return 0;
|
|
11772
11908
|
}
|
|
@@ -11781,7 +11917,7 @@ function acquireSharedDocLock(documentPath, options) {
|
|
|
11781
11917
|
const staleAfterMs = options.staleAfterMs ?? SHARED_DOC_LOCK_STALE_MS;
|
|
11782
11918
|
const attempts = options.attempts ?? SHARED_DOC_LOCK_ATTEMPTS;
|
|
11783
11919
|
const intervalMs = options.intervalMs ?? SHARED_DOC_LOCK_INTERVAL_MS;
|
|
11784
|
-
const identity = { owner: options.owner, pid: process.pid, host: options.host ?? (0,
|
|
11920
|
+
const identity = { owner: options.owner, pid: process.pid, host: options.host ?? (0, import_node_os7.hostname)(), acquiredAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
11785
11921
|
const content = lockContent(identity);
|
|
11786
11922
|
const sleep2 = (ms) => {
|
|
11787
11923
|
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
@@ -11789,9 +11925,9 @@ function acquireSharedDocLock(documentPath, options) {
|
|
|
11789
11925
|
for (let attempt = 0; attempt < attempts; attempt += 1) {
|
|
11790
11926
|
let fd;
|
|
11791
11927
|
try {
|
|
11792
|
-
fd = (0,
|
|
11793
|
-
(0,
|
|
11794
|
-
(0,
|
|
11928
|
+
fd = (0, import_node_fs12.openSync)(lockPath, "wx");
|
|
11929
|
+
(0, import_node_fs12.writeSync)(fd, content);
|
|
11930
|
+
(0, import_node_fs12.closeSync)(fd);
|
|
11795
11931
|
return {
|
|
11796
11932
|
documentPath,
|
|
11797
11933
|
lockPath,
|
|
@@ -11804,11 +11940,11 @@ function acquireSharedDocLock(documentPath, options) {
|
|
|
11804
11940
|
} catch (error) {
|
|
11805
11941
|
if (fd !== void 0) {
|
|
11806
11942
|
try {
|
|
11807
|
-
(0,
|
|
11943
|
+
(0, import_node_fs12.closeSync)(fd);
|
|
11808
11944
|
} catch {
|
|
11809
11945
|
}
|
|
11810
11946
|
try {
|
|
11811
|
-
(0,
|
|
11947
|
+
(0, import_node_fs12.unlinkSync)(lockPath);
|
|
11812
11948
|
} catch {
|
|
11813
11949
|
}
|
|
11814
11950
|
}
|
|
@@ -11817,12 +11953,12 @@ function acquireSharedDocLock(documentPath, options) {
|
|
|
11817
11953
|
if (lockAgeMs(lockPath, Date.now()) >= staleAfterMs) {
|
|
11818
11954
|
const aside = `${lockPath}.stale-${Date.now()}`;
|
|
11819
11955
|
try {
|
|
11820
|
-
(0,
|
|
11956
|
+
(0, import_node_fs12.renameSync)(lockPath, aside);
|
|
11821
11957
|
} catch {
|
|
11822
11958
|
continue;
|
|
11823
11959
|
}
|
|
11824
11960
|
try {
|
|
11825
|
-
(0,
|
|
11961
|
+
(0, import_node_fs12.rmSync)(aside, { force: true });
|
|
11826
11962
|
} catch {
|
|
11827
11963
|
}
|
|
11828
11964
|
continue;
|
|
@@ -11835,7 +11971,7 @@ function releaseSharedDocLock(handle) {
|
|
|
11835
11971
|
try {
|
|
11836
11972
|
const holder = readHolder(handle.lockPath);
|
|
11837
11973
|
if (holder && holder.owner === handle.owner && Number(holder.pid) === handle.pid) {
|
|
11838
|
-
(0,
|
|
11974
|
+
(0, import_node_fs12.unlinkSync)(handle.lockPath);
|
|
11839
11975
|
}
|
|
11840
11976
|
} catch {
|
|
11841
11977
|
}
|
|
@@ -11982,25 +12118,25 @@ function runHostBin(bin, args, opts) {
|
|
|
11982
12118
|
const argv = isWin ? ["/c", bin, ...args] : args;
|
|
11983
12119
|
return step ? execFileHard(file, argv, { ...shared, step }) : execFileP(file, argv, shared);
|
|
11984
12120
|
}
|
|
11985
|
-
function hermesConfigRoot(env = process.env, home = (0,
|
|
12121
|
+
function hermesConfigRoot(env = process.env, home = (0, import_node_os8.homedir)(), platform2 = process.platform) {
|
|
11986
12122
|
if (env.HERMES_HOME?.trim()) return env.HERMES_HOME.trim();
|
|
11987
|
-
if (platform2 === "win32") return (0,
|
|
11988
|
-
return (0,
|
|
12123
|
+
if (platform2 === "win32") return (0, import_node_path11.join)(env.LOCALAPPDATA?.trim() || (0, import_node_path11.join)(home, "AppData", "Local"), "hermes");
|
|
12124
|
+
return (0, import_node_path11.join)(home, ".hermes");
|
|
11989
12125
|
}
|
|
11990
|
-
function surfaceConfigRoot(surface, env = process.env, home = (0,
|
|
11991
|
-
if (surface === "codex") return env.CODEX_HOME?.trim() || (0,
|
|
12126
|
+
function surfaceConfigRoot(surface, env = process.env, home = (0, import_node_os8.homedir)()) {
|
|
12127
|
+
if (surface === "codex") return env.CODEX_HOME?.trim() || (0, import_node_path11.join)(home, ".codex");
|
|
11992
12128
|
if (surface === "hermes") return hermesConfigRoot(env, home);
|
|
11993
12129
|
if (surface === "jervcode") {
|
|
11994
|
-
return env.JERVCODE_CODING_AGENT_DIR?.trim() || env.PI_CODING_AGENT_DIR?.trim() || (0,
|
|
12130
|
+
return env.JERVCODE_CODING_AGENT_DIR?.trim() || env.PI_CODING_AGENT_DIR?.trim() || (0, import_node_path11.join)(home, ".jerv", "agent");
|
|
11995
12131
|
}
|
|
11996
|
-
return (0,
|
|
12132
|
+
return (0, import_node_path11.join)(home, ".claude");
|
|
11997
12133
|
}
|
|
11998
12134
|
var installedPluginsPath = (surface = detectSurface(process.env)) => {
|
|
11999
|
-
return (0,
|
|
12135
|
+
return (0, import_node_path11.join)(surfaceConfigRoot(surface), "plugins", "installed_plugins.json");
|
|
12000
12136
|
};
|
|
12001
12137
|
function readInstalledPlugins(surface = detectSurface(process.env)) {
|
|
12002
12138
|
try {
|
|
12003
|
-
return JSON.parse((0,
|
|
12139
|
+
return JSON.parse((0, import_node_fs13.readFileSync)(installedPluginsPath(surface), "utf8"));
|
|
12004
12140
|
} catch {
|
|
12005
12141
|
return null;
|
|
12006
12142
|
}
|
|
@@ -12009,15 +12145,15 @@ function marketplaceCloneCandidates(surface, home, env = process.env) {
|
|
|
12009
12145
|
if (surface === "codex") {
|
|
12010
12146
|
const root = surfaceConfigRoot(surface, env, home);
|
|
12011
12147
|
return [
|
|
12012
|
-
(0,
|
|
12013
|
-
(0,
|
|
12148
|
+
(0, import_node_path11.join)(root, ".tmp", "marketplaces", CODEX_MARKETPLACE),
|
|
12149
|
+
(0, import_node_path11.join)(root, "plugins", "marketplaces", CODEX_MARKETPLACE)
|
|
12014
12150
|
];
|
|
12015
12151
|
}
|
|
12016
12152
|
if (surface === "hermes") return [];
|
|
12017
12153
|
if (surface === "jervcode") return [];
|
|
12018
|
-
return [(0,
|
|
12154
|
+
return [(0, import_node_path11.join)(home, ".claude", "plugins", "marketplaces", "mutmutco")];
|
|
12019
12155
|
}
|
|
12020
|
-
function marketplaceClonePresent(surface, home, exists =
|
|
12156
|
+
function marketplaceClonePresent(surface, home, exists = import_node_fs13.existsSync, env = process.env) {
|
|
12021
12157
|
return marketplaceCloneCandidates(surface, home, env).some(exists);
|
|
12022
12158
|
}
|
|
12023
12159
|
function runHostBinSync(bin, args) {
|
|
@@ -12059,26 +12195,26 @@ async function fetchNpmReleasedVersion() {
|
|
|
12059
12195
|
}
|
|
12060
12196
|
}
|
|
12061
12197
|
var JERVCODE_NPM_PACKAGE = "@mutmutco/pi-plugin";
|
|
12062
|
-
function jervcodeAgentDirs(env = process.env, home = (0,
|
|
12198
|
+
function jervcodeAgentDirs(env = process.env, home = (0, import_node_os8.homedir)()) {
|
|
12063
12199
|
const primary = surfaceConfigRoot("jervcode", env, home);
|
|
12064
|
-
const legacy = (0,
|
|
12200
|
+
const legacy = (0, import_node_path11.join)(home, ".pi", "agent");
|
|
12065
12201
|
const dirs = [primary];
|
|
12066
12202
|
if (legacy !== primary) dirs.push(legacy);
|
|
12067
|
-
return dirs.filter((dir) => (0,
|
|
12203
|
+
return dirs.filter((dir) => (0, import_node_fs13.existsSync)(dir));
|
|
12068
12204
|
}
|
|
12069
12205
|
function readPiSettings(path2) {
|
|
12070
|
-
if (!(0,
|
|
12206
|
+
if (!(0, import_node_fs13.existsSync)(path2)) return void 0;
|
|
12071
12207
|
try {
|
|
12072
|
-
const parsed = JSON.parse((0,
|
|
12208
|
+
const parsed = JSON.parse((0, import_node_fs13.readFileSync)(path2, "utf8"));
|
|
12073
12209
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return null;
|
|
12074
12210
|
return parsed;
|
|
12075
12211
|
} catch {
|
|
12076
12212
|
return null;
|
|
12077
12213
|
}
|
|
12078
12214
|
}
|
|
12079
|
-
function mmiPiPackageEntry(env = process.env, home = (0,
|
|
12215
|
+
function mmiPiPackageEntry(env = process.env, home = (0, import_node_os8.homedir)()) {
|
|
12080
12216
|
for (const dir of jervcodeAgentDirs(env, home)) {
|
|
12081
|
-
const settings = readPiSettings((0,
|
|
12217
|
+
const settings = readPiSettings((0, import_node_path11.join)(dir, "settings.json"));
|
|
12082
12218
|
const entries = Array.isArray(settings?.packages) ? settings.packages : [];
|
|
12083
12219
|
for (const entry of entries) {
|
|
12084
12220
|
if (typeof entry !== "string") continue;
|
|
@@ -12088,10 +12224,10 @@ function mmiPiPackageEntry(env = process.env, home = (0, import_node_os7.homedir
|
|
|
12088
12224
|
return null;
|
|
12089
12225
|
}
|
|
12090
12226
|
var LEGACY_MMI_PI_PATH = /[/\\]mutmutco[/\\]mmi[/\\]\d+\.\d+\.\d+[/\\]\.pi-plugin[/\\]?$/i;
|
|
12091
|
-
function legacyMmiPiPathEntries(env = process.env, home = (0,
|
|
12227
|
+
function legacyMmiPiPathEntries(env = process.env, home = (0, import_node_os8.homedir)()) {
|
|
12092
12228
|
const found = [];
|
|
12093
12229
|
for (const dir of jervcodeAgentDirs(env, home)) {
|
|
12094
|
-
const settings = readPiSettings((0,
|
|
12230
|
+
const settings = readPiSettings((0, import_node_path11.join)(dir, "settings.json"));
|
|
12095
12231
|
const entries = Array.isArray(settings?.packages) ? settings.packages : [];
|
|
12096
12232
|
for (const entry of entries) {
|
|
12097
12233
|
if (typeof entry === "string" && LEGACY_MMI_PI_PATH.test(entry) && !found.includes(entry)) found.push(entry);
|
|
@@ -12099,37 +12235,37 @@ function legacyMmiPiPathEntries(env = process.env, home = (0, import_node_os7.ho
|
|
|
12099
12235
|
}
|
|
12100
12236
|
return found;
|
|
12101
12237
|
}
|
|
12102
|
-
function mmiPiPackageRoot(env = process.env, home = (0,
|
|
12238
|
+
function mmiPiPackageRoot(env = process.env, home = (0, import_node_os8.homedir)()) {
|
|
12103
12239
|
for (const dir of jervcodeAgentDirs(env, home)) {
|
|
12104
|
-
const root = (0,
|
|
12105
|
-
if ((0,
|
|
12240
|
+
const root = (0, import_node_path11.join)(dir, "npm", "node_modules", ...JERVCODE_NPM_PACKAGE.split("/"));
|
|
12241
|
+
if ((0, import_node_fs13.existsSync)((0, import_node_path11.join)(root, "package.json"))) return root;
|
|
12106
12242
|
}
|
|
12107
12243
|
return null;
|
|
12108
12244
|
}
|
|
12109
|
-
function installedJervCodePackageVersion(env = process.env, home = (0,
|
|
12245
|
+
function installedJervCodePackageVersion(env = process.env, home = (0, import_node_os8.homedir)()) {
|
|
12110
12246
|
const root = mmiPiPackageRoot(env, home);
|
|
12111
12247
|
if (!root) return void 0;
|
|
12112
12248
|
try {
|
|
12113
|
-
const manifest = JSON.parse((0,
|
|
12249
|
+
const manifest = JSON.parse((0, import_node_fs13.readFileSync)((0, import_node_path11.join)(root, "package.json"), "utf8"));
|
|
12114
12250
|
return typeof manifest.version === "string" ? manifest.version : void 0;
|
|
12115
12251
|
} catch {
|
|
12116
12252
|
return void 0;
|
|
12117
12253
|
}
|
|
12118
12254
|
}
|
|
12119
|
-
function mmiPiPackageHealthy(env = process.env, home = (0,
|
|
12255
|
+
function mmiPiPackageHealthy(env = process.env, home = (0, import_node_os8.homedir)()) {
|
|
12120
12256
|
const root = mmiPiPackageRoot(env, home);
|
|
12121
|
-
return Boolean(root && (0,
|
|
12257
|
+
return Boolean(root && (0, import_node_fs13.existsSync)((0, import_node_path11.join)(root, "skills", "bootstrap", "SKILL.md")));
|
|
12122
12258
|
}
|
|
12123
12259
|
function piDoctorEnv(agentDir) {
|
|
12124
12260
|
return { ...process.env, PI_CODING_AGENT_DIR: agentDir };
|
|
12125
12261
|
}
|
|
12126
|
-
function hermesPluginRoot(env = process.env, home = (0,
|
|
12127
|
-
return (0,
|
|
12262
|
+
function hermesPluginRoot(env = process.env, home = (0, import_node_os8.homedir)()) {
|
|
12263
|
+
return (0, import_node_path11.join)(hermesConfigRoot(env, home), "plugins", "mmi");
|
|
12128
12264
|
}
|
|
12129
|
-
function hermesPluginTreeHealthy(root, exists =
|
|
12130
|
-
if (!["plugin.yaml", "__init__.py"].every((file) => exists((0,
|
|
12265
|
+
function hermesPluginTreeHealthy(root, exists = import_node_fs13.existsSync) {
|
|
12266
|
+
if (!["plugin.yaml", "__init__.py"].every((file) => exists((0, import_node_path11.join)(root, file)))) return false;
|
|
12131
12267
|
try {
|
|
12132
|
-
return (0,
|
|
12268
|
+
return (0, import_node_fs13.statSync)((0, import_node_path11.join)(root, "skills")).isDirectory();
|
|
12133
12269
|
} catch {
|
|
12134
12270
|
return false;
|
|
12135
12271
|
}
|
|
@@ -12144,12 +12280,12 @@ function snapshotPluginGuardInput(surface = detectSurface(process.env), isOrgRep
|
|
|
12144
12280
|
// Codex's native projection is authoritative; its legacy installed_plugins.json may be empty
|
|
12145
12281
|
// while `plugin list --json` proves the managed plugin installed (#6111).
|
|
12146
12282
|
installRecordPresent: surface === "codex" ? codexStatus?.installed === true : hasUserInstallRecord(installed, MMI_PLUGIN_ID) || hasProjectInstallRecord(installed, MMI_PLUGIN_ID, process.cwd()) || // #4188: jervcode's install record is the settings-file packages[] entry itself.
|
|
12147
|
-
surface === "jervcode" && piEntry !== null || surface === "hermes" && (0,
|
|
12283
|
+
surface === "jervcode" && piEntry !== null || surface === "hermes" && (0, import_node_fs13.existsSync)(hermesPluginRoot()),
|
|
12148
12284
|
// JervCode's settings entry and native local surfaces have no marketplace clone.
|
|
12149
|
-
marketplaceClonePresent: surface === "jervcode" || surface === "hermes" ? true : marketplaceClonePresent(surface, (0,
|
|
12285
|
+
marketplaceClonePresent: surface === "jervcode" || surface === "hermes" ? true : marketplaceClonePresent(surface, (0, import_node_os8.homedir)()),
|
|
12150
12286
|
pluginCachePresent: surface === "jervcode" ? mmiPiPackageHealthy() : surface === "hermes" ? hermesPluginTreeHealthy(hermesPluginRoot()) : surface === "codex" ? Boolean(
|
|
12151
|
-
codexStatus?.installed && codexStatus.enabled && codexStatus.version && (0,
|
|
12152
|
-
) : (0,
|
|
12287
|
+
codexStatus?.installed && codexStatus.enabled && codexStatus.version && (0, import_node_fs13.existsSync)((0, import_node_path11.join)(root, "plugins", "cache", CODEX_MARKETPLACE, "mmi", codexStatus.version))
|
|
12288
|
+
) : (0, import_node_fs13.existsSync)((0, import_node_path11.join)(root, "plugins", "cache", "mutmutco", "mmi"))
|
|
12153
12289
|
};
|
|
12154
12290
|
}
|
|
12155
12291
|
async function runPluginCli(bin, args, log) {
|
|
@@ -12196,7 +12332,7 @@ async function runHealSteps(host, tableSteps, deps) {
|
|
|
12196
12332
|
const refSupported = needsRefProbe ? await marketplaceAddRefSupported(host) : true;
|
|
12197
12333
|
const { steps } = adaptHealStepsForRefSupport(tableSteps, refSupported);
|
|
12198
12334
|
if (deps.banner) log(deps.banner(refSupported));
|
|
12199
|
-
const pinsPath = (0,
|
|
12335
|
+
const pinsPath = (0, import_node_path11.join)((0, import_node_os8.homedir)(), ...KNOWN_MARKETPLACES_RELATIVE);
|
|
12200
12336
|
const pins = host === "claude" ? captureMarketplacePins(readKnownMarketplacesFile(pinsPath), [MMI_MARKETPLACE_NAME, JERV_MARKETPLACE_NAME]) : /* @__PURE__ */ new Map();
|
|
12201
12337
|
let failure;
|
|
12202
12338
|
try {
|
|
@@ -12307,7 +12443,7 @@ async function healActivePluginForDoctor(surface = detectSurface(process.env), o
|
|
|
12307
12443
|
}
|
|
12308
12444
|
function readKnownMarketplacesFile(path2) {
|
|
12309
12445
|
try {
|
|
12310
|
-
return (0,
|
|
12446
|
+
return (0, import_node_fs13.existsSync)(path2) ? (0, import_node_fs13.readFileSync)(path2, "utf8") : void 0;
|
|
12311
12447
|
} catch {
|
|
12312
12448
|
return void 0;
|
|
12313
12449
|
}
|
|
@@ -12341,11 +12477,11 @@ function writeMarketplacePinsOnDisk(path2, pins, succeeded, failedVerb, declineW
|
|
|
12341
12477
|
if (declined) return declined;
|
|
12342
12478
|
const tmp = `${path2}.tmp-${process.pid}`;
|
|
12343
12479
|
try {
|
|
12344
|
-
(0,
|
|
12345
|
-
(0,
|
|
12480
|
+
(0, import_node_fs13.writeFileSync)(tmp, next, "utf8");
|
|
12481
|
+
(0, import_node_fs13.renameSync)(tmp, path2);
|
|
12346
12482
|
} catch {
|
|
12347
12483
|
try {
|
|
12348
|
-
(0,
|
|
12484
|
+
(0, import_node_fs13.rmSync)(tmp, { force: true });
|
|
12349
12485
|
} catch {
|
|
12350
12486
|
}
|
|
12351
12487
|
return `could NOT ${failedVerb} ${[...pins.keys()].join(", ")} \u2014 set it by hand`;
|
|
@@ -12473,7 +12609,7 @@ function readSessionIdSource(env) {
|
|
|
12473
12609
|
var synthesizedSessionId;
|
|
12474
12610
|
function fallbackSessionId(surface) {
|
|
12475
12611
|
if (!synthesizedSessionId) {
|
|
12476
|
-
synthesizedSessionId = `${SYNTH_SESSION_PREFIX}${surface}-${process.pid}-${(0,
|
|
12612
|
+
synthesizedSessionId = `${SYNTH_SESSION_PREFIX}${surface}-${process.pid}-${(0, import_node_crypto7.randomBytes)(3).toString("hex")}`;
|
|
12477
12613
|
}
|
|
12478
12614
|
return synthesizedSessionId;
|
|
12479
12615
|
}
|
|
@@ -12482,7 +12618,7 @@ function describeSessionIdentity(env = process.env) {
|
|
|
12482
12618
|
return {
|
|
12483
12619
|
session: readSessionId(env) ?? fallbackSessionId(surface),
|
|
12484
12620
|
surface,
|
|
12485
|
-
host: (0,
|
|
12621
|
+
host: (0, import_node_os9.hostname)()
|
|
12486
12622
|
};
|
|
12487
12623
|
}
|
|
12488
12624
|
function formatSessionIdentity(identity) {
|
|
@@ -13182,7 +13318,7 @@ function renderBoardSource() {
|
|
|
13182
13318
|
return "source: live";
|
|
13183
13319
|
}
|
|
13184
13320
|
async function collectBoardPreferringSnapshot(cfg, options, deps) {
|
|
13185
|
-
if (options.snapshotOnly && !deps.snapshot) throw new
|
|
13321
|
+
if (options.snapshotOnly && !deps.snapshot) throw new BoardSnapshotFailure({ ok: false, outcome: "hub-unreachable", reason: "--snapshot-only needs the Hub snapshot transport (not with --direct)" });
|
|
13186
13322
|
const attempt = deps.snapshot ? await fetchHubBoardSnapshot(
|
|
13187
13323
|
{
|
|
13188
13324
|
owner: cfg.projectOwner,
|
|
@@ -13195,6 +13331,7 @@ async function collectBoardPreferringSnapshot(cfg, options, deps) {
|
|
|
13195
13331
|
deps.snapshot
|
|
13196
13332
|
) : void 0;
|
|
13197
13333
|
if (attempt?.state === "refused") {
|
|
13334
|
+
if (options.snapshotOnly) throw new BoardSnapshotFailure({ ok: false, outcome: "refused", reason: attempt.reason });
|
|
13198
13335
|
throw new Error(attempt.reason);
|
|
13199
13336
|
}
|
|
13200
13337
|
if (attempt?.state === "ok") {
|
|
@@ -13224,7 +13361,16 @@ async function collectBoardPreferringSnapshot(cfg, options, deps) {
|
|
|
13224
13361
|
};
|
|
13225
13362
|
}
|
|
13226
13363
|
if (options.snapshotOnly && attempt?.state === "unavailable") {
|
|
13227
|
-
throw Object.assign(new
|
|
13364
|
+
throw Object.assign(new BoardSnapshotFailure({
|
|
13365
|
+
ok: false,
|
|
13366
|
+
outcome: attempt.appQuotaExhausted ? "app-quota-exhausted" : "hub-unreachable",
|
|
13367
|
+
reason: `Hub board snapshot unavailable (${attempt.reason}) \u2014 --snapshot-only refuses the direct user-auth fallback`,
|
|
13368
|
+
...attempt.resetAt ? { resetAt: attempt.resetAt } : {},
|
|
13369
|
+
...attempt.pool ? { pool: attempt.pool } : {}
|
|
13370
|
+
}), { quota: attempt.quota });
|
|
13371
|
+
}
|
|
13372
|
+
if (attempt?.state === "unavailable" && attempt.appQuotaExhausted) {
|
|
13373
|
+
throw Object.assign(new Error(`Hub board snapshot unavailable (${attempt.reason}) \u2014 the personal-token fallback is refused while the org App allowance is exhausted; retry after the reset`), { quota: attempt.quota });
|
|
13228
13374
|
}
|
|
13229
13375
|
const collected = await collectBoardItems(cfg, { repo: options.repo, allowPartial: options.allowPartial, activeOnly: true }, deps);
|
|
13230
13376
|
if (attempt?.state === "unavailable") {
|
|
@@ -13907,7 +14053,7 @@ var CLAIM_SESSION_ACTIVITY_MS = 30 * 6e4;
|
|
|
13907
14053
|
var CLAIM_SESSION_PROBE_CACHE_MS = 6e4;
|
|
13908
14054
|
var claimSessionProbeCache = /* @__PURE__ */ new Map();
|
|
13909
14055
|
function probeLocalClaimSession(marker, now = Date.now()) {
|
|
13910
|
-
if (!marker.session || !marker.host || marker.host.toLowerCase() !== (0,
|
|
14056
|
+
if (!marker.session || !marker.host || marker.host.toLowerCase() !== (0, import_node_os10.hostname)().toLowerCase()) return void 0;
|
|
13911
14057
|
if (!marker.surface?.toLowerCase().startsWith("claude")) return void 0;
|
|
13912
14058
|
const cacheKey = `${marker.host.toLowerCase()}/${marker.session}`;
|
|
13913
14059
|
const cached = claimSessionProbeCache.get(cacheKey);
|
|
@@ -13916,17 +14062,17 @@ function probeLocalClaimSession(marker, now = Date.now()) {
|
|
|
13916
14062
|
claimSessionProbeCache.set(cacheKey, { checkedAt: now, state });
|
|
13917
14063
|
return state;
|
|
13918
14064
|
};
|
|
13919
|
-
const root = (0,
|
|
14065
|
+
const root = (0, import_node_path12.join)((0, import_node_os10.homedir)(), ".claude", "projects");
|
|
13920
14066
|
try {
|
|
13921
14067
|
const wanted = `${marker.session}.jsonl`.toLowerCase();
|
|
13922
14068
|
const pending = [root];
|
|
13923
14069
|
while (pending.length) {
|
|
13924
14070
|
const dir = pending.pop();
|
|
13925
|
-
for (const entry of (0,
|
|
13926
|
-
const path2 = (0,
|
|
14071
|
+
for (const entry of (0, import_node_fs14.readdirSync)(dir, { withFileTypes: true })) {
|
|
14072
|
+
const path2 = (0, import_node_path12.join)(dir, entry.name);
|
|
13927
14073
|
if (entry.isDirectory()) pending.push(path2);
|
|
13928
14074
|
else if (entry.isFile() && entry.name.toLowerCase() === wanted) {
|
|
13929
|
-
return remember(now - (0,
|
|
14075
|
+
return remember(now - (0, import_node_fs14.statSync)(path2).mtimeMs <= CLAIM_SESSION_ACTIVITY_MS ? "live" : "dead");
|
|
13930
14076
|
}
|
|
13931
14077
|
}
|
|
13932
14078
|
}
|
|
@@ -15179,7 +15325,7 @@ async function propagateMayAutoMerge(repo, repoClass, rest) {
|
|
|
15179
15325
|
}
|
|
15180
15326
|
|
|
15181
15327
|
// src/bootstrap-apply.ts
|
|
15182
|
-
var
|
|
15328
|
+
var import_node_crypto8 = require("node:crypto");
|
|
15183
15329
|
|
|
15184
15330
|
// src/bootstrap-seeds.ts
|
|
15185
15331
|
var PLACEHOLDER_RE = /\{\{([A-Z0-9_]+)\}\}/g;
|
|
@@ -15418,13 +15564,13 @@ function planManagedGitignore(current) {
|
|
|
15418
15564
|
}
|
|
15419
15565
|
|
|
15420
15566
|
// src/docs-index-command.ts
|
|
15421
|
-
var
|
|
15422
|
-
var
|
|
15567
|
+
var import_node_fs16 = require("node:fs");
|
|
15568
|
+
var import_node_path14 = require("node:path");
|
|
15423
15569
|
|
|
15424
15570
|
// src/doc-refs-core.ts
|
|
15425
15571
|
var import_node_child_process6 = require("node:child_process");
|
|
15426
|
-
var
|
|
15427
|
-
var
|
|
15572
|
+
var import_node_fs15 = require("node:fs");
|
|
15573
|
+
var import_node_path13 = require("node:path");
|
|
15428
15574
|
var PIN_RE = /<!--\s*pinned by\s+([^:]+?)\s*:\s*"([^"]+)"[^"]*-->/;
|
|
15429
15575
|
var PIN_MENTION_RE = /<!--\s*pinned by\b/;
|
|
15430
15576
|
var FWD_RE = /<!--\s*forward-ref:\s*(\S+?)\s*-->/;
|
|
@@ -15483,7 +15629,7 @@ function checkPins(root, readFile10, docs) {
|
|
|
15483
15629
|
findings.push({ kind: "malformed-pin", doc, line: pin.line, detail: pin.text });
|
|
15484
15630
|
continue;
|
|
15485
15631
|
}
|
|
15486
|
-
const source = readFile10((0,
|
|
15632
|
+
const source = readFile10((0, import_node_path13.join)(root, pin.file));
|
|
15487
15633
|
if (source == null) {
|
|
15488
15634
|
findings.push({ kind: "missing-test", doc, line: pin.line, detail: pin.file });
|
|
15489
15635
|
continue;
|
|
@@ -15546,11 +15692,11 @@ function checkRefs(root, deps, docs) {
|
|
|
15546
15692
|
for (const { ref } of extractRefs(markdown)) allFirstSegments.add(refFirstSegment(ref));
|
|
15547
15693
|
}
|
|
15548
15694
|
const tracked = allFirstSegments.size ? deps.trackedFirstSegments?.([...allFirstSegments]) ?? null : null;
|
|
15549
|
-
const firstVerifiable = (first) => tracked ? tracked.has(first) : exists((0,
|
|
15695
|
+
const firstVerifiable = (first) => tracked ? tracked.has(first) : exists((0, import_node_path13.join)(root, first));
|
|
15550
15696
|
const candidates = [];
|
|
15551
15697
|
const direct = [];
|
|
15552
15698
|
for (const [doc, markdown] of Object.entries(docs)) {
|
|
15553
|
-
const docDir =
|
|
15699
|
+
const docDir = import_node_path13.posix.dirname(doc);
|
|
15554
15700
|
const base = docDir === "." ? "" : docDir;
|
|
15555
15701
|
const covered = /* @__PURE__ */ new Set();
|
|
15556
15702
|
const markers = [];
|
|
@@ -15559,21 +15705,21 @@ function checkRefs(root, deps, docs) {
|
|
|
15559
15705
|
direct.push({ kind: "malformed-forward-ref", doc, line: fwd.line, detail: fwd.text });
|
|
15560
15706
|
continue;
|
|
15561
15707
|
}
|
|
15562
|
-
const docRel =
|
|
15563
|
-
const rootRel =
|
|
15708
|
+
const docRel = import_node_path13.posix.normalize(import_node_path13.posix.join(base, fwd.target));
|
|
15709
|
+
const rootRel = import_node_path13.posix.normalize(fwd.target.replace(/^\/+/, ""));
|
|
15564
15710
|
markers.push({ target: fwd.target, line: fwd.line, docRel, rootRel });
|
|
15565
15711
|
covered.add(docRel);
|
|
15566
15712
|
covered.add(rootRel);
|
|
15567
15713
|
}
|
|
15568
15714
|
const links = extractLinks(markdown).map(({ target, line }) => {
|
|
15569
|
-
const resolved =
|
|
15570
|
-
return { target, line, resolved, missing: !exists((0,
|
|
15715
|
+
const resolved = import_node_path13.posix.normalize(import_node_path13.posix.join(base, target));
|
|
15716
|
+
return { target, line, resolved, missing: !exists((0, import_node_path13.join)(root, resolved)) };
|
|
15571
15717
|
});
|
|
15572
15718
|
for (const marker of markers) {
|
|
15573
15719
|
const coversMissing = links.some(
|
|
15574
15720
|
(l) => l.missing && (l.resolved === marker.docRel || l.resolved === marker.rootRel)
|
|
15575
15721
|
);
|
|
15576
|
-
if (!coversMissing && (exists((0,
|
|
15722
|
+
if (!coversMissing && (exists((0, import_node_path13.join)(root, marker.docRel)) || exists((0, import_node_path13.join)(root, marker.rootRel)))) {
|
|
15577
15723
|
direct.push({
|
|
15578
15724
|
kind: "stale-forward-ref",
|
|
15579
15725
|
doc,
|
|
@@ -15584,7 +15730,7 @@ function checkRefs(root, deps, docs) {
|
|
|
15584
15730
|
}
|
|
15585
15731
|
for (const { ref, line } of extractRefs(markdown)) {
|
|
15586
15732
|
if (!firstVerifiable(refFirstSegment(ref))) continue;
|
|
15587
|
-
if (!exists((0,
|
|
15733
|
+
if (!exists((0, import_node_path13.join)(root, ref))) candidates.push({ kind: "missing-path", doc, line, detail: ref });
|
|
15588
15734
|
}
|
|
15589
15735
|
for (const { target, line, resolved, missing } of links) {
|
|
15590
15736
|
if (resolved.startsWith("..")) {
|
|
@@ -15632,24 +15778,24 @@ function checkCommands(docs, commandPaths) {
|
|
|
15632
15778
|
return { ok: findings.length === 0, findings, warnings: [] };
|
|
15633
15779
|
}
|
|
15634
15780
|
function readFileOrNull(path2) {
|
|
15635
|
-
return (0,
|
|
15781
|
+
return (0, import_node_fs15.existsSync)(path2) ? (0, import_node_fs15.readFileSync)(path2, "utf8") : null;
|
|
15636
15782
|
}
|
|
15637
15783
|
function walk(dir, root, out) {
|
|
15638
|
-
for (const entry of (0,
|
|
15639
|
-
const full = (0,
|
|
15640
|
-
if ((0,
|
|
15784
|
+
for (const entry of (0, import_node_fs15.readdirSync)(dir)) {
|
|
15785
|
+
const full = (0, import_node_path13.join)(dir, entry);
|
|
15786
|
+
if ((0, import_node_fs15.statSync)(full).isDirectory()) walk(full, root, out);
|
|
15641
15787
|
else if (entry.endsWith(".md")) out.push(full.slice(root.length + 1).replaceAll("\\", "/"));
|
|
15642
15788
|
}
|
|
15643
15789
|
return out;
|
|
15644
15790
|
}
|
|
15645
15791
|
function defaultListDocs(root) {
|
|
15646
15792
|
const docs = ["docs", "skills/org-guide", "skills/mmi-help"].flatMap((path2) => {
|
|
15647
|
-
const directory = (0,
|
|
15648
|
-
return (0,
|
|
15793
|
+
const directory = (0, import_node_path13.join)(root, path2);
|
|
15794
|
+
return (0, import_node_fs15.existsSync)(directory) ? walk(directory, root, []) : [];
|
|
15649
15795
|
}).filter(
|
|
15650
15796
|
(rel) => !SKIP_WALK.some((skip) => rel.startsWith(skip))
|
|
15651
15797
|
);
|
|
15652
|
-
return [...ROOT_DOCS.filter((rel) => (0,
|
|
15798
|
+
return [...ROOT_DOCS.filter((rel) => (0, import_node_fs15.existsSync)((0, import_node_path13.join)(root, rel))), ...docs];
|
|
15653
15799
|
}
|
|
15654
15800
|
var CHECK_IGNORE_MAX_BUFFER = 32 * 1024 * 1024;
|
|
15655
15801
|
function defaultIsIgnored(root, relPaths, exec2 = import_node_child_process6.execFileSync) {
|
|
@@ -15701,7 +15847,7 @@ function defaultTrackedFirstSegments(root, firstSegments, exec2 = import_node_ch
|
|
|
15701
15847
|
}
|
|
15702
15848
|
function runDocRefs(root, deps = {}) {
|
|
15703
15849
|
const readFile10 = deps.readFile ?? readFileOrNull;
|
|
15704
|
-
const exists = deps.exists ??
|
|
15850
|
+
const exists = deps.exists ?? import_node_fs15.existsSync;
|
|
15705
15851
|
const listDocs = deps.listDocs ?? defaultListDocs;
|
|
15706
15852
|
const isIgnored = deps.isIgnored ?? ((paths) => defaultIsIgnored(root, paths));
|
|
15707
15853
|
const trackedFirstSegments = deps.trackedFirstSegments ?? ((segs) => defaultTrackedFirstSegments(root, segs));
|
|
@@ -15709,7 +15855,7 @@ function runDocRefs(root, deps = {}) {
|
|
|
15709
15855
|
const walked = listDocs(root);
|
|
15710
15856
|
const ignoredDocs = walked.length ? isIgnored(walked) : /* @__PURE__ */ new Set();
|
|
15711
15857
|
const docs = Object.fromEntries(
|
|
15712
|
-
walked.filter((rel) => !ignoredDocs.has(rel)).map((rel) => [rel, readFile10((0,
|
|
15858
|
+
walked.filter((rel) => !ignoredDocs.has(rel)).map((rel) => [rel, readFile10((0, import_node_path13.join)(root, rel))]).filter(([, body]) => body != null)
|
|
15713
15859
|
);
|
|
15714
15860
|
const refResult = checkRefs(root, { exists, isIgnored, trackedFirstSegments }, docs);
|
|
15715
15861
|
const findings = [
|
|
@@ -15816,31 +15962,31 @@ function walkMarkdown(dir) {
|
|
|
15816
15962
|
const stack = [dir];
|
|
15817
15963
|
while (stack.length) {
|
|
15818
15964
|
const current = stack.pop();
|
|
15819
|
-
for (const entry of (0,
|
|
15820
|
-
const full = (0,
|
|
15965
|
+
for (const entry of (0, import_node_fs16.readdirSync)(current, { withFileTypes: true })) {
|
|
15966
|
+
const full = (0, import_node_path14.join)(current, entry.name);
|
|
15821
15967
|
if (entry.isDirectory()) {
|
|
15822
15968
|
stack.push(full);
|
|
15823
15969
|
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
15824
|
-
out.push((0,
|
|
15970
|
+
out.push((0, import_node_path14.relative)(dir, full).split(import_node_path14.sep).join("/"));
|
|
15825
15971
|
}
|
|
15826
15972
|
}
|
|
15827
15973
|
}
|
|
15828
15974
|
return out;
|
|
15829
15975
|
}
|
|
15830
15976
|
function createDocsIndexDeps(repoRoot2) {
|
|
15831
|
-
const docsDir = (0,
|
|
15832
|
-
const indexPath = (0,
|
|
15977
|
+
const docsDir = (0, import_node_path14.join)(repoRoot2, "docs");
|
|
15978
|
+
const indexPath = (0, import_node_path14.join)(repoRoot2, DOCS_INDEX_PATH);
|
|
15833
15979
|
return {
|
|
15834
15980
|
listDocs: () => {
|
|
15835
|
-
if (!(0,
|
|
15981
|
+
if (!(0, import_node_fs16.existsSync)(docsDir)) return [];
|
|
15836
15982
|
const walked = walkMarkdown(docsDir).filter(isRoutableDocsPath);
|
|
15837
15983
|
if (!walked.length) return [];
|
|
15838
15984
|
const ignored = defaultIsIgnored(repoRoot2, walked.map((rel) => `docs/${rel}`));
|
|
15839
15985
|
return walked.filter((rel) => !ignored.has(`docs/${rel}`)).sort();
|
|
15840
15986
|
},
|
|
15841
|
-
readDoc: (relPath) => (0,
|
|
15842
|
-
readIndex: () => (0,
|
|
15843
|
-
writeIndex: (content) => (0,
|
|
15987
|
+
readDoc: (relPath) => (0, import_node_fs16.readFileSync)((0, import_node_path14.join)(docsDir, relPath), "utf8"),
|
|
15988
|
+
readIndex: () => (0, import_node_fs16.existsSync)(indexPath) ? (0, import_node_fs16.readFileSync)(indexPath, "utf8") : null,
|
|
15989
|
+
writeIndex: (content) => (0, import_node_fs16.writeFileSync)(indexPath, content, "utf8")
|
|
15844
15990
|
};
|
|
15845
15991
|
}
|
|
15846
15992
|
|
|
@@ -16446,7 +16592,7 @@ function planSeedAction(seed, exists) {
|
|
|
16446
16592
|
return exists ? { target: seed.target, action: "update", ownership: "org", reason: "org-owned, refresh to current" } : { target: seed.target, action: "create", ownership: "org", reason: "org-owned, missing" };
|
|
16447
16593
|
}
|
|
16448
16594
|
var GATE_RENDER_NOTE = "# Rendered from the registry gate config by mmi-cli devops bootstrap apply <repo> --only gate.yml --from-config; edit the config, not this file.\n";
|
|
16449
|
-
var gateHash = (body) => (0,
|
|
16595
|
+
var gateHash = (body) => (0, import_node_crypto8.createHash)("sha256").update(body, "utf8").digest("hex");
|
|
16450
16596
|
function parseGateRenderStamp(content) {
|
|
16451
16597
|
const match = /^# mmi-gate-render: sha256=([a-f0-9]{64})\n/.exec(content);
|
|
16452
16598
|
return match ? { hash: match[1], body: content.slice(match[0].length) } : null;
|
|
@@ -16753,8 +16899,8 @@ function contentPutInputArgs(repo, path2, inputFile) {
|
|
|
16753
16899
|
}
|
|
16754
16900
|
|
|
16755
16901
|
// src/train-apply-contracts.ts
|
|
16756
|
-
var
|
|
16757
|
-
var
|
|
16902
|
+
var import_node_fs17 = require("node:fs");
|
|
16903
|
+
var import_node_path15 = require("node:path");
|
|
16758
16904
|
function reduceFollowUpOutcomes(outcomes) {
|
|
16759
16905
|
if (outcomes.includes("failure")) return "failure";
|
|
16760
16906
|
if (outcomes.includes("unresolved")) return "unresolved";
|
|
@@ -16834,7 +16980,7 @@ async function resolveFoldPaths(deps, model) {
|
|
|
16834
16980
|
if (model === "vercel") return [];
|
|
16835
16981
|
const helper = "scripts/release-distribution.mjs";
|
|
16836
16982
|
if (model === "hub-serverless" || model === "registry-publish") {
|
|
16837
|
-
if ((0,
|
|
16983
|
+
if ((0, import_node_fs17.existsSync)(helper)) {
|
|
16838
16984
|
let out;
|
|
16839
16985
|
try {
|
|
16840
16986
|
out = await deps.run("node", [helper, "changed-files"]);
|
|
@@ -16973,7 +17119,7 @@ async function restoreMainNpmPackIdentities(deps, version) {
|
|
|
16973
17119
|
if (mainBom.version !== version) return void 0;
|
|
16974
17120
|
let localBom;
|
|
16975
17121
|
try {
|
|
16976
|
-
localBom = JSON.parse((0,
|
|
17122
|
+
localBom = JSON.parse((0, import_node_fs17.readFileSync)(bomPath, "utf8"));
|
|
16977
17123
|
} catch (e) {
|
|
16978
17124
|
throw new Error(
|
|
16979
17125
|
`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).`
|
|
@@ -16991,14 +17137,14 @@ async function restoreMainNpmPackIdentities(deps, version) {
|
|
|
16991
17137
|
restored += 1;
|
|
16992
17138
|
}
|
|
16993
17139
|
if (restored === 0) return void 0;
|
|
16994
|
-
(0,
|
|
17140
|
+
(0, import_node_fs17.writeFileSync)(bomPath, `${JSON.stringify(localBom, null, 2)}
|
|
16995
17141
|
`);
|
|
16996
17142
|
return `restored ${restored} npm-pack BOM identit${restored === 1 ? "y" : "ies"} from origin/main (#4503)`;
|
|
16997
17143
|
}
|
|
16998
17144
|
function publishVisibilityFor(surfaceId) {
|
|
16999
17145
|
let raw;
|
|
17000
17146
|
try {
|
|
17001
|
-
raw = (0,
|
|
17147
|
+
raw = (0, import_node_fs17.readFileSync)("surfaces.json", "utf8");
|
|
17002
17148
|
} catch (e) {
|
|
17003
17149
|
if (e.code === "ENOENT") return "unknown";
|
|
17004
17150
|
throw trainReadFailure(
|
|
@@ -17019,7 +17165,7 @@ function publishVisibilityFor(surfaceId) {
|
|
|
17019
17165
|
}
|
|
17020
17166
|
function npmPackArtifactName(packagePath) {
|
|
17021
17167
|
try {
|
|
17022
|
-
const pkg = JSON.parse((0,
|
|
17168
|
+
const pkg = JSON.parse((0, import_node_fs17.readFileSync)((0, import_node_path15.join)(packagePath, "package.json"), "utf8"));
|
|
17023
17169
|
return pkg.name || void 0;
|
|
17024
17170
|
} catch {
|
|
17025
17171
|
return void 0;
|
|
@@ -17028,7 +17174,7 @@ function npmPackArtifactName(packagePath) {
|
|
|
17028
17174
|
async function refuseDivergentPublishedNpmPack(deps, version) {
|
|
17029
17175
|
let localBom;
|
|
17030
17176
|
try {
|
|
17031
|
-
localBom = JSON.parse((0,
|
|
17177
|
+
localBom = JSON.parse((0, import_node_fs17.readFileSync)("distribution-bom.json", "utf8"));
|
|
17032
17178
|
} catch (e) {
|
|
17033
17179
|
throw new Error(
|
|
17034
17180
|
`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).`
|
|
@@ -17173,8 +17319,8 @@ function assertGitBashOnWindowsForJervHubRelease(repo, platform2 = process.platf
|
|
|
17173
17319
|
}
|
|
17174
17320
|
|
|
17175
17321
|
// src/train-apply-correlation.ts
|
|
17176
|
-
var
|
|
17177
|
-
var
|
|
17322
|
+
var import_node_fs19 = require("node:fs");
|
|
17323
|
+
var import_node_path17 = require("node:path");
|
|
17178
17324
|
|
|
17179
17325
|
// src/fleet-lockstep-enforce.ts
|
|
17180
17326
|
init_github_client();
|
|
@@ -17939,10 +18085,10 @@ var rollout_plan_default = {
|
|
|
17939
18085
|
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)."
|
|
17940
18086
|
},
|
|
17941
18087
|
baseline: {
|
|
17942
|
-
version: "4.5.
|
|
17943
|
-
tag: "v4.5.
|
|
17944
|
-
commit: "
|
|
17945
|
-
npm: "@mutmutco/cli@4.5.
|
|
18088
|
+
version: "4.5.118",
|
|
18089
|
+
tag: "v4.5.118",
|
|
18090
|
+
commit: "4dc2fb2beb2b",
|
|
18091
|
+
npm: "@mutmutco/cli@4.5.118"
|
|
17946
18092
|
},
|
|
17947
18093
|
exitCriterion: "fleet-n-of-n",
|
|
17948
18094
|
hubOnlyShortcut: "forbidden",
|
|
@@ -17959,14 +18105,14 @@ var rollout_plan_default = {
|
|
|
17959
18105
|
repo: "mutmutco/mmi-hub",
|
|
17960
18106
|
role: "canary",
|
|
17961
18107
|
schedule: "train",
|
|
17962
|
-
v3Target: "v4.5.
|
|
18108
|
+
v3Target: "v4.5.118"
|
|
17963
18109
|
}
|
|
17964
18110
|
],
|
|
17965
18111
|
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.",
|
|
17966
18112
|
rollback: {
|
|
17967
18113
|
independent: true,
|
|
17968
|
-
mechanism: "npm dist-tag latest -> 4.5.
|
|
17969
|
-
v3Target: "v4.5.
|
|
18114
|
+
mechanism: "npm dist-tag latest -> 4.5.118 and redeploy the Hub Lambda from tag v4.5.118 (4dc2fb2beb2b); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
|
|
18115
|
+
v3Target: "v4.5.118 (@mutmutco/cli@4.5.118, tag commit 4dc2fb2beb2b \u2014 last known-good release carrying the repo-index v4-only contract)"
|
|
17970
18116
|
}
|
|
17971
18117
|
},
|
|
17972
18118
|
{
|
|
@@ -18300,13 +18446,13 @@ function resolveIssueViewGhFields(normalized) {
|
|
|
18300
18446
|
}
|
|
18301
18447
|
|
|
18302
18448
|
// src/utf8-receipt.ts
|
|
18303
|
-
var
|
|
18304
|
-
var
|
|
18449
|
+
var import_node_fs18 = require("node:fs");
|
|
18450
|
+
var import_node_path16 = require("node:path");
|
|
18305
18451
|
function writeUtf8Receipt(path2, text) {
|
|
18306
|
-
(0,
|
|
18452
|
+
(0, import_node_fs18.mkdirSync)((0, import_node_path16.dirname)(path2), { recursive: true });
|
|
18307
18453
|
const body = text.endsWith("\n") ? text : `${text}
|
|
18308
18454
|
`;
|
|
18309
|
-
(0,
|
|
18455
|
+
(0, import_node_fs18.writeFileSync)(path2, body, "utf8");
|
|
18310
18456
|
return Buffer.byteLength(body, "utf8");
|
|
18311
18457
|
}
|
|
18312
18458
|
|
|
@@ -20174,7 +20320,7 @@ function resolveReleaseAbortNpmPackage(meta, repo) {
|
|
|
20174
20320
|
if (isHubControlRepo(repo)) return "@mutmutco/cli";
|
|
20175
20321
|
const publishDir = typeof meta.publishDir === "string" && meta.publishDir.trim() ? meta.publishDir.trim() : ".";
|
|
20176
20322
|
try {
|
|
20177
|
-
const pkg = JSON.parse((0,
|
|
20323
|
+
const pkg = JSON.parse((0, import_node_fs19.readFileSync)((0, import_node_path17.join)(publishDir, "package.json"), "utf8"));
|
|
20178
20324
|
const name = pkg.name?.trim();
|
|
20179
20325
|
if (!name) throw new Error("missing name field");
|
|
20180
20326
|
return name;
|
|
@@ -21102,9 +21248,9 @@ function parseVerifyBroker(stdout) {
|
|
|
21102
21248
|
}
|
|
21103
21249
|
|
|
21104
21250
|
// src/train-apply-deploy.ts
|
|
21105
|
-
var
|
|
21106
|
-
var
|
|
21107
|
-
var
|
|
21251
|
+
var import_node_fs20 = require("node:fs");
|
|
21252
|
+
var import_node_os11 = require("node:os");
|
|
21253
|
+
var import_node_path18 = require("node:path");
|
|
21108
21254
|
|
|
21109
21255
|
// src/vercel-deployments.ts
|
|
21110
21256
|
var TERMINAL = /* @__PURE__ */ new Set(["success", "failure", "error", "inactive"]);
|
|
@@ -21243,7 +21389,7 @@ function mmiGetRedeployCommand(repo) {
|
|
|
21243
21389
|
}
|
|
21244
21390
|
function readLocalLauncherVersion(root = process.cwd()) {
|
|
21245
21391
|
try {
|
|
21246
|
-
const raw = (0,
|
|
21392
|
+
const raw = (0, import_node_fs20.readFileSync)((0, import_node_path18.join)(root, "cli", "package.json"), "utf8");
|
|
21247
21393
|
const version = JSON.parse(raw).version;
|
|
21248
21394
|
return typeof version === "string" && version.trim() ? version.trim() : null;
|
|
21249
21395
|
} catch {
|
|
@@ -21252,7 +21398,7 @@ function readLocalLauncherVersion(root = process.cwd()) {
|
|
|
21252
21398
|
}
|
|
21253
21399
|
function readServedChannelUrl(product = HUB_SERVED_PRODUCT, root = process.cwd()) {
|
|
21254
21400
|
try {
|
|
21255
|
-
const raw = (0,
|
|
21401
|
+
const raw = (0, import_node_fs20.readFileSync)((0, import_node_path18.join)(root, "config", `product.${product}.json`), "utf8");
|
|
21256
21402
|
const host = JSON.parse(raw).host;
|
|
21257
21403
|
if (typeof host !== "string" || !host.trim()) return null;
|
|
21258
21404
|
return `${host.trim().replace(/\/+$/, "")}/release/version`;
|
|
@@ -21686,13 +21832,13 @@ async function runTaggedJervGatewayLocalWrapper(deps, tag, tagSha) {
|
|
|
21686
21832
|
const reason = error instanceof Error ? error.message : String(error);
|
|
21687
21833
|
throw new Error(`could not extract ${JERV_GATEWAY_RELEASE_DEPLOY_SCRIPT} from tagged commit ${tagSha.slice(0, 12)}: ${reason}`);
|
|
21688
21834
|
}
|
|
21689
|
-
const dir = (0,
|
|
21690
|
-
const extracted = (0,
|
|
21835
|
+
const dir = (0, import_node_fs20.mkdtempSync)((0, import_node_path18.join)((0, import_node_os11.tmpdir)(), "jerv-gateway-release-deploy-"));
|
|
21836
|
+
const extracted = (0, import_node_path18.join)(dir, "jerv-gateway-release-deploy.sh");
|
|
21691
21837
|
try {
|
|
21692
|
-
(0,
|
|
21838
|
+
(0, import_node_fs20.writeFileSync)(extracted, script, "utf8");
|
|
21693
21839
|
return await deps.run("bash", [extracted, "--tag", tag]);
|
|
21694
21840
|
} finally {
|
|
21695
|
-
(0,
|
|
21841
|
+
(0, import_node_fs20.rmSync)(dir, { recursive: true, force: true });
|
|
21696
21842
|
}
|
|
21697
21843
|
}
|
|
21698
21844
|
async function appendJervGatewayReleaseDeploy(deps, repo, tag, tagSha, dispatch) {
|
|
@@ -22158,28 +22304,46 @@ async function runTenantControl(deps, options) {
|
|
|
22158
22304
|
const watch = options.watch ?? tenantControlWatches(action);
|
|
22159
22305
|
const base = { command: "tenant-control", repo, stage, action };
|
|
22160
22306
|
const since = (deps.now ?? Date.now)();
|
|
22161
|
-
|
|
22162
|
-
|
|
22163
|
-
|
|
22164
|
-
|
|
22165
|
-
|
|
22166
|
-
|
|
22167
|
-
|
|
22168
|
-
|
|
22169
|
-
|
|
22170
|
-
}
|
|
22171
|
-
|
|
22172
|
-
|
|
22173
|
-
|
|
22174
|
-
|
|
22175
|
-
|
|
22176
|
-
|
|
22177
|
-
|
|
22178
|
-
|
|
22179
|
-
|
|
22180
|
-
|
|
22307
|
+
let runId;
|
|
22308
|
+
let runUrl;
|
|
22309
|
+
if (options.resume != null) {
|
|
22310
|
+
if (action !== "run-task") throw new Error("runtime tenant control: --resume is valid only for run-task");
|
|
22311
|
+
let view;
|
|
22312
|
+
try {
|
|
22313
|
+
view = JSON.parse(await deps.run("gh", ["run", "view", String(options.resume), "--repo", HUB_REPO2, "--json", "workflowName,displayTitle,url"]));
|
|
22314
|
+
} catch (e) {
|
|
22315
|
+
throw new Error(`runtime tenant control: run ${options.resume} could not be READ: ${e.message}`);
|
|
22316
|
+
}
|
|
22317
|
+
const f = (view.displayTitle ?? "").split(" ");
|
|
22318
|
+
if (view.workflowName !== "tenant-control" || f[0] !== "tenant-control" || f[1] !== (repo.split("/")[1] ?? "").toLowerCase() || f[2] !== stage || f[3] !== "run-task") {
|
|
22319
|
+
throw new Error(`runtime tenant control: run ${options.resume} is not a tenant-control run-task run for ${repo} ${stage} (title: ${view.displayTitle ?? "unreadable"}) \u2014 refusing to resume it`);
|
|
22320
|
+
}
|
|
22321
|
+
runId = options.resume;
|
|
22322
|
+
runUrl = view.url;
|
|
22323
|
+
} else {
|
|
22324
|
+
const d = await deps.dispatchTenantControl({ repo, stage, action, lines: options.lines, edge: options.edge, since: options.logSince, until: options.logUntil, task: options.task, artifact: options.artifact, confirmDataLoss: options.confirmDataLoss });
|
|
22325
|
+
if (!d.ok) {
|
|
22326
|
+
const transport = d.category === "transport-failed";
|
|
22327
|
+
return {
|
|
22328
|
+
...base,
|
|
22329
|
+
dispatched: false,
|
|
22330
|
+
conclusion: "failure",
|
|
22331
|
+
category: action === "retire" ? transport ? "transport-failed" : "dispatch-rejected" : void 0,
|
|
22332
|
+
note: transport ? `runtime tenant control ${action} dispatch failed (transport) \u2014 safe to retry` : `runtime tenant control ${action} rejected: ${d.error ?? "request rejected by the Hub"}`
|
|
22333
|
+
};
|
|
22334
|
+
}
|
|
22335
|
+
const correlated = await correlateControlRun(deps, since, [stage, action, ...action === "run-task" && options.task ? [options.task] : []]);
|
|
22336
|
+
if (correlated.read === "failed") {
|
|
22337
|
+
return {
|
|
22338
|
+
...base,
|
|
22339
|
+
dispatched: true,
|
|
22340
|
+
conclusion: "failure",
|
|
22341
|
+
category: action === "retire" ? "wait-timeout" : void 0,
|
|
22342
|
+
note: `runtime tenant control ${action} dispatched, but its run could not be READ: ${correlated.error} \u2014 the run's outcome is unverified, not absent; check the Actions tab or retry once the read succeeds (#4713)`
|
|
22343
|
+
};
|
|
22344
|
+
}
|
|
22345
|
+
({ runId, runUrl } = correlated);
|
|
22181
22346
|
}
|
|
22182
|
-
const { runId, runUrl } = correlated;
|
|
22183
22347
|
const conclusion = watch ? await watchTenantRun(deps, runId) : "pending";
|
|
22184
22348
|
const result = { ...base, dispatched: true, runId, runUrl, conclusion, note: "" };
|
|
22185
22349
|
if (action === "retire") {
|
|
@@ -22213,6 +22377,9 @@ async function runTenantControl(deps, options) {
|
|
|
22213
22377
|
}
|
|
22214
22378
|
}
|
|
22215
22379
|
result.note = conclusion === "success" ? `tenant-control ${action} run succeeded` : conclusion === "failure" ? `tenant-control ${action} run failed \u2014 inspect the run` : runId == null ? `dispatched tenant-control.yml (${action}) \u2014 run not correlated; check the Actions tab` : `dispatched tenant-control.yml (${action}) \u2014 not watched`;
|
|
22380
|
+
if (conclusion === "pending" && runId != null && action === "run-task") {
|
|
22381
|
+
result.note += `; run ${runId} \u2014 resume without re-dispatching: mmi-cli devops runtime tenant control ${repo} ${stage} run-task --resume ${runId} --watch`;
|
|
22382
|
+
}
|
|
22216
22383
|
return result;
|
|
22217
22384
|
}
|
|
22218
22385
|
function renderTenantControl(r) {
|
|
@@ -22232,9 +22399,9 @@ function renderTenantControl(r) {
|
|
|
22232
22399
|
}
|
|
22233
22400
|
|
|
22234
22401
|
// src/train-apply-phases.ts
|
|
22235
|
-
var
|
|
22402
|
+
var import_node_fs26 = require("node:fs");
|
|
22236
22403
|
var import_promises4 = require("node:fs/promises");
|
|
22237
|
-
var
|
|
22404
|
+
var import_node_path25 = require("node:path");
|
|
22238
22405
|
|
|
22239
22406
|
// src/actions-billing-preflight.ts
|
|
22240
22407
|
var CANARY_WORKFLOW = "actions-job-start-canary.yml";
|
|
@@ -22542,14 +22709,14 @@ function assertPreOneZero(repo, meta, tag) {
|
|
|
22542
22709
|
|
|
22543
22710
|
// src/train-doctor.ts
|
|
22544
22711
|
var import_node_child_process9 = require("node:child_process");
|
|
22545
|
-
var
|
|
22546
|
-
var
|
|
22547
|
-
var
|
|
22712
|
+
var import_node_fs24 = require("node:fs");
|
|
22713
|
+
var import_node_os15 = require("node:os");
|
|
22714
|
+
var import_node_path24 = require("node:path");
|
|
22548
22715
|
|
|
22549
22716
|
// src/doctor-io.ts
|
|
22550
|
-
var
|
|
22551
|
-
var
|
|
22552
|
-
var
|
|
22717
|
+
var import_node_fs21 = require("node:fs");
|
|
22718
|
+
var import_node_os12 = require("node:os");
|
|
22719
|
+
var import_node_path19 = require("node:path");
|
|
22553
22720
|
var import_node_child_process7 = require("node:child_process");
|
|
22554
22721
|
var import_node_util4 = require("node:util");
|
|
22555
22722
|
|
|
@@ -22562,8 +22729,8 @@ function nodeDiscardSinkPath(platform2 = process.platform) {
|
|
|
22562
22729
|
var execFileP2 = (0, import_node_util4.promisify)(import_node_child_process7.execFile);
|
|
22563
22730
|
function execFileCapture(file, args, opts = {}) {
|
|
22564
22731
|
const sink = nodeDiscardSinkPath();
|
|
22565
|
-
const inFd = (0,
|
|
22566
|
-
const errFd = (0,
|
|
22732
|
+
const inFd = (0, import_node_fs21.openSync)(sink, "r");
|
|
22733
|
+
const errFd = (0, import_node_fs21.openSync)(sink, "w");
|
|
22567
22734
|
try {
|
|
22568
22735
|
return (0, import_node_child_process7.execFileSync)(file, args, {
|
|
22569
22736
|
...opts,
|
|
@@ -22571,17 +22738,17 @@ function execFileCapture(file, args, opts = {}) {
|
|
|
22571
22738
|
stdio: [inFd, "pipe", errFd]
|
|
22572
22739
|
});
|
|
22573
22740
|
} finally {
|
|
22574
|
-
(0,
|
|
22575
|
-
(0,
|
|
22741
|
+
(0, import_node_fs21.closeSync)(inFd);
|
|
22742
|
+
(0, import_node_fs21.closeSync)(errFd);
|
|
22576
22743
|
}
|
|
22577
22744
|
}
|
|
22578
22745
|
var MMI_PLUGIN_ID2 = "mmi@mutmutco";
|
|
22579
22746
|
function stagedClaudePluginVersion() {
|
|
22580
22747
|
try {
|
|
22581
|
-
const stagingRoot = (0,
|
|
22582
|
-
const record = JSON.parse((0,
|
|
22748
|
+
const stagingRoot = (0, import_node_path19.join)((0, import_node_os12.homedir)(), ".claude", "plugins", "staging");
|
|
22749
|
+
const record = JSON.parse((0, import_node_fs21.readFileSync)((0, import_node_path19.join)(stagingRoot, "launch-target.json"), "utf8"));
|
|
22583
22750
|
if (typeof record.target !== "string" || typeof record.incoming !== "string") return void 0;
|
|
22584
|
-
const manifest = JSON.parse((0,
|
|
22751
|
+
const manifest = JSON.parse((0, import_node_fs21.readFileSync)((0, import_node_path19.join)(record.incoming, ".claude-plugin", "plugin.json"), "utf8"));
|
|
22585
22752
|
if (typeof manifest.version !== "string") return void 0;
|
|
22586
22753
|
return manifest.version === record.target ? record.target : void 0;
|
|
22587
22754
|
} catch {
|
|
@@ -22591,7 +22758,7 @@ function stagedClaudePluginVersion() {
|
|
|
22591
22758
|
function installedClaudePluginVersion() {
|
|
22592
22759
|
try {
|
|
22593
22760
|
const file = JSON.parse(
|
|
22594
|
-
(0,
|
|
22761
|
+
(0, import_node_fs21.readFileSync)((0, import_node_path19.join)((0, import_node_os12.homedir)(), ".claude", "plugins", "installed_plugins.json"), "utf8")
|
|
22595
22762
|
);
|
|
22596
22763
|
const versions = (file.plugins?.[MMI_PLUGIN_ID2] ?? []).map((r) => r.version).filter((v) => Boolean(v));
|
|
22597
22764
|
if (versions.length === 0) return void 0;
|
|
@@ -22603,12 +22770,12 @@ function installedClaudePluginVersion() {
|
|
|
22603
22770
|
function readHermesPluginEvidence(env = process.env) {
|
|
22604
22771
|
const host = hermesConfigRoot(env);
|
|
22605
22772
|
const root = hermesPluginRoot(env);
|
|
22606
|
-
const installRecordPresent = (0,
|
|
22607
|
-
const manifestPath = (0,
|
|
22773
|
+
const installRecordPresent = (0, import_node_fs21.existsSync)(root);
|
|
22774
|
+
const manifestPath = (0, import_node_path19.join)(root, "plugin.yaml");
|
|
22608
22775
|
let installedVersion;
|
|
22609
22776
|
let manifest = "missing";
|
|
22610
22777
|
try {
|
|
22611
|
-
const text = (0,
|
|
22778
|
+
const text = (0, import_node_fs21.readFileSync)(manifestPath, "utf8");
|
|
22612
22779
|
let version;
|
|
22613
22780
|
try {
|
|
22614
22781
|
const parsed = JSON.parse(text).version;
|
|
@@ -22622,25 +22789,25 @@ function readHermesPluginEvidence(env = process.env) {
|
|
|
22622
22789
|
if (version) {
|
|
22623
22790
|
installedVersion = version;
|
|
22624
22791
|
manifest = "valid";
|
|
22625
|
-
} else if ((0,
|
|
22792
|
+
} else if ((0, import_node_fs21.existsSync)(manifestPath)) manifest = "invalid";
|
|
22626
22793
|
} catch {
|
|
22627
|
-
if ((0,
|
|
22794
|
+
if ((0, import_node_fs21.existsSync)(manifestPath)) manifest = "invalid";
|
|
22628
22795
|
}
|
|
22629
22796
|
let skills = false;
|
|
22630
22797
|
try {
|
|
22631
|
-
skills = (0,
|
|
22798
|
+
skills = (0, import_node_fs21.existsSync)((0, import_node_path19.join)(root, "skills")) && (0, import_node_fs21.statSync)((0, import_node_path19.join)(root, "skills")).isDirectory();
|
|
22632
22799
|
} catch {
|
|
22633
22800
|
}
|
|
22634
22801
|
let provisioned = false;
|
|
22635
|
-
const provisionedRoot = (0,
|
|
22802
|
+
const provisionedRoot = (0, import_node_path19.join)(host, "skills", "mmi");
|
|
22636
22803
|
try {
|
|
22637
|
-
provisioned = (0,
|
|
22804
|
+
provisioned = (0, import_node_fs21.existsSync)(provisionedRoot) && (0, import_node_fs21.statSync)(provisionedRoot).isDirectory();
|
|
22638
22805
|
} catch {
|
|
22639
22806
|
}
|
|
22640
|
-
const treeOk = (0,
|
|
22807
|
+
const treeOk = (0, import_node_fs21.existsSync)((0, import_node_path19.join)(root, "__init__.py")) && skills && manifest === "valid";
|
|
22641
22808
|
const receipt = treeOk && !provisioned ? `hermes-skills-unprovisioned:${provisionedRoot}` : void 0;
|
|
22642
22809
|
return {
|
|
22643
|
-
hostPresent: (0,
|
|
22810
|
+
hostPresent: (0, import_node_fs21.existsSync)(host),
|
|
22644
22811
|
installRecordPresent,
|
|
22645
22812
|
manifest,
|
|
22646
22813
|
payloadPresent: treeOk && provisioned,
|
|
@@ -22686,13 +22853,13 @@ function worktreeRootSync() {
|
|
|
22686
22853
|
}
|
|
22687
22854
|
var gitignorePath = () => {
|
|
22688
22855
|
const root = worktreeRootSync();
|
|
22689
|
-
return root === null ? null : (0,
|
|
22856
|
+
return root === null ? null : (0, import_node_path19.join)(root, ".gitignore");
|
|
22690
22857
|
};
|
|
22691
22858
|
function readGitignore() {
|
|
22692
22859
|
const path2 = gitignorePath();
|
|
22693
22860
|
if (path2 === null) return null;
|
|
22694
22861
|
try {
|
|
22695
|
-
return (0,
|
|
22862
|
+
return (0, import_node_fs21.readFileSync)(path2, "utf8");
|
|
22696
22863
|
} catch {
|
|
22697
22864
|
return null;
|
|
22698
22865
|
}
|
|
@@ -22701,14 +22868,14 @@ function writeGitignore(content) {
|
|
|
22701
22868
|
const path2 = gitignorePath();
|
|
22702
22869
|
if (path2 === null) return false;
|
|
22703
22870
|
try {
|
|
22704
|
-
(0,
|
|
22871
|
+
(0, import_node_fs21.writeFileSync)(path2, content, "utf8");
|
|
22705
22872
|
return true;
|
|
22706
22873
|
} catch {
|
|
22707
22874
|
return false;
|
|
22708
22875
|
}
|
|
22709
22876
|
}
|
|
22710
22877
|
function lineEndingState(root) {
|
|
22711
|
-
const attributesPresent = (0,
|
|
22878
|
+
const attributesPresent = (0, import_node_fs21.existsSync)((0, import_node_path19.join)(root, ".gitattributes"));
|
|
22712
22879
|
try {
|
|
22713
22880
|
const output = execFileCapture("git", ["-C", root, "ls-files", "--eol", "--", ":(glob)**/*.sh"], {
|
|
22714
22881
|
windowsHide: true
|
|
@@ -22751,18 +22918,18 @@ function compatHolds(range, version) {
|
|
|
22751
22918
|
}
|
|
22752
22919
|
|
|
22753
22920
|
// src/claude-binary-doctor.ts
|
|
22754
|
-
var
|
|
22755
|
-
var
|
|
22756
|
-
var
|
|
22921
|
+
var import_node_fs22 = require("node:fs");
|
|
22922
|
+
var import_node_os14 = require("node:os");
|
|
22923
|
+
var import_node_path21 = require("node:path");
|
|
22757
22924
|
|
|
22758
22925
|
// src/jerv-cli-spawn.ts
|
|
22759
|
-
var
|
|
22760
|
-
var
|
|
22926
|
+
var import_node_os13 = require("node:os");
|
|
22927
|
+
var import_node_path20 = require("node:path");
|
|
22761
22928
|
init_cli_shared();
|
|
22762
|
-
var JERV_CLI_ENTRY = (0,
|
|
22929
|
+
var JERV_CLI_ENTRY = (0, import_node_path20.join)("node_modules", "@jervaise", "jerv-cli", "dist", "index.cjs");
|
|
22763
22930
|
function pathEnvEntries(pathEnv, platform2 = process.platform) {
|
|
22764
22931
|
if (platform2 !== "win32") {
|
|
22765
|
-
return pathEnv.split(
|
|
22932
|
+
return pathEnv.split(import_node_path20.delimiter).map((e) => e.trim()).filter(Boolean);
|
|
22766
22933
|
}
|
|
22767
22934
|
if (pathEnv.includes(";")) {
|
|
22768
22935
|
return pathEnv.split(";").map((e) => e.trim()).filter(Boolean);
|
|
@@ -22781,7 +22948,7 @@ function normalizeSpawnPathEntry(entry, platform2 = process.platform) {
|
|
|
22781
22948
|
if (msys) return `${msys[1].toUpperCase()}:\\${msys[2].replace(/\//g, "\\")}`;
|
|
22782
22949
|
return trimmed;
|
|
22783
22950
|
}
|
|
22784
|
-
function jervCliCandidateDirs(env = process.env, home = (0,
|
|
22951
|
+
function jervCliCandidateDirs(env = process.env, home = (0, import_node_os13.homedir)(), platform2 = process.platform) {
|
|
22785
22952
|
const seen = /* @__PURE__ */ new Set();
|
|
22786
22953
|
const out = [];
|
|
22787
22954
|
const push = (dir) => {
|
|
@@ -22795,10 +22962,10 @@ function jervCliCandidateDirs(env = process.env, home = (0, import_node_os12.hom
|
|
|
22795
22962
|
push(normalizeSpawnPathEntry(entry, platform2));
|
|
22796
22963
|
}
|
|
22797
22964
|
if (platform2 === "win32") {
|
|
22798
|
-
if (env.APPDATA) push((0,
|
|
22799
|
-
if (env.LOCALAPPDATA) push((0,
|
|
22965
|
+
if (env.APPDATA) push((0, import_node_path20.join)(env.APPDATA, "npm"));
|
|
22966
|
+
if (env.LOCALAPPDATA) push((0, import_node_path20.join)(env.LOCALAPPDATA, "npm"));
|
|
22800
22967
|
} else {
|
|
22801
|
-
push((0,
|
|
22968
|
+
push((0, import_node_path20.join)(home, ".local", "bin"));
|
|
22802
22969
|
}
|
|
22803
22970
|
return out;
|
|
22804
22971
|
}
|
|
@@ -22851,26 +23018,26 @@ function globalNodeModulesRoots(host) {
|
|
|
22851
23018
|
out.push(dir);
|
|
22852
23019
|
};
|
|
22853
23020
|
const prefix = env.npm_config_prefix?.trim();
|
|
22854
|
-
if (prefix) push(platform2 === "win32" ? (0,
|
|
22855
|
-
for (const dir of jervCliCandidateDirs(env, host.home ?? (0,
|
|
22856
|
-
push((0,
|
|
22857
|
-
push((0,
|
|
23021
|
+
if (prefix) push(platform2 === "win32" ? (0, import_node_path21.join)(prefix, "node_modules") : (0, import_node_path21.join)(prefix, "lib", "node_modules"));
|
|
23022
|
+
for (const dir of jervCliCandidateDirs(env, host.home ?? (0, import_node_os14.homedir)(), platform2)) {
|
|
23023
|
+
push((0, import_node_path21.join)(dir, "node_modules"));
|
|
23024
|
+
push((0, import_node_path21.join)((0, import_node_path21.dirname)(dir), "lib", "node_modules"));
|
|
22858
23025
|
}
|
|
22859
23026
|
return out;
|
|
22860
23027
|
}
|
|
22861
23028
|
function readHead(path2) {
|
|
22862
23029
|
let fd;
|
|
22863
23030
|
try {
|
|
22864
|
-
fd = (0,
|
|
23031
|
+
fd = (0, import_node_fs22.openSync)(path2, "r");
|
|
22865
23032
|
const buffer = new Uint8Array(MAGIC_HEAD_BYTES);
|
|
22866
|
-
const read = (0,
|
|
23033
|
+
const read = (0, import_node_fs22.readSync)(fd, buffer, 0, MAGIC_HEAD_BYTES, 0);
|
|
22867
23034
|
return buffer.subarray(0, read);
|
|
22868
23035
|
} catch {
|
|
22869
23036
|
return void 0;
|
|
22870
23037
|
} finally {
|
|
22871
23038
|
if (fd !== void 0) {
|
|
22872
23039
|
try {
|
|
22873
|
-
(0,
|
|
23040
|
+
(0, import_node_fs22.closeSync)(fd);
|
|
22874
23041
|
} catch {
|
|
22875
23042
|
}
|
|
22876
23043
|
}
|
|
@@ -22878,7 +23045,7 @@ function readHead(path2) {
|
|
|
22878
23045
|
}
|
|
22879
23046
|
function fileBytes(path2) {
|
|
22880
23047
|
try {
|
|
22881
|
-
return (0,
|
|
23048
|
+
return (0, import_node_fs22.statSync)(path2).size;
|
|
22882
23049
|
} catch {
|
|
22883
23050
|
return void 0;
|
|
22884
23051
|
}
|
|
@@ -22892,17 +23059,17 @@ function readClaudeBinaryState(host = {}) {
|
|
|
22892
23059
|
const arch = host.arch ?? process.arch;
|
|
22893
23060
|
const magic = EXECUTABLE_MAGIC[platform2];
|
|
22894
23061
|
if (!magic) return void 0;
|
|
22895
|
-
const packageRoot = globalNodeModulesRoots(host).map((root) => (0,
|
|
23062
|
+
const packageRoot = globalNodeModulesRoots(host).map((root) => (0, import_node_path21.join)(root, ...PACKAGE.split("/"))).find((dir) => (0, import_node_fs22.existsSync)((0, import_node_path21.join)(dir, "package.json")));
|
|
22896
23063
|
if (!packageRoot) return void 0;
|
|
22897
23064
|
const keys = platformPackageKeys(platform2, arch);
|
|
22898
23065
|
const fallbackPackage = `${PACKAGE}-${keys[0]}`;
|
|
22899
23066
|
let manifest;
|
|
22900
23067
|
try {
|
|
22901
|
-
manifest = JSON.parse((0,
|
|
23068
|
+
manifest = JSON.parse((0, import_node_fs22.readFileSync)((0, import_node_path21.join)(packageRoot, "package.json"), "utf8"));
|
|
22902
23069
|
} catch (e) {
|
|
22903
23070
|
return {
|
|
22904
23071
|
state: "unreadable",
|
|
22905
|
-
binPath: (0,
|
|
23072
|
+
binPath: (0, import_node_path21.join)(packageRoot, "package.json"),
|
|
22906
23073
|
expectedMagic: magic.name,
|
|
22907
23074
|
platformPackage: fallbackPackage,
|
|
22908
23075
|
error: `package.json could not be read \u2014 ${e.message}`
|
|
@@ -22919,17 +23086,17 @@ function readClaudeBinaryState(host = {}) {
|
|
|
22919
23086
|
error: "package.json declares no `bin` entry \u2014 the executed file cannot be resolved"
|
|
22920
23087
|
};
|
|
22921
23088
|
}
|
|
22922
|
-
const binPath = (0,
|
|
22923
|
-
const binName = (0,
|
|
23089
|
+
const binPath = (0, import_node_path21.join)(packageRoot, binRelative);
|
|
23090
|
+
const binName = (0, import_node_path21.basename)(binRelative);
|
|
22924
23091
|
const optional = manifest.optionalDependencies;
|
|
22925
23092
|
const publishes = (name) => typeof optional === "object" && optional !== null && Object.prototype.hasOwnProperty.call(optional, name);
|
|
22926
23093
|
const published = keys.map((key) => `${PACKAGE}-${key}`).filter(publishes);
|
|
22927
23094
|
if (published.length === 0) return void 0;
|
|
22928
23095
|
const binIn = (name) => [
|
|
22929
|
-
(0,
|
|
22930
|
-
(0,
|
|
23096
|
+
(0, import_node_path21.join)(packageRoot, "node_modules", ...name.split("/"), binName),
|
|
23097
|
+
(0, import_node_path21.join)((0, import_node_path21.dirname)((0, import_node_path21.dirname)(packageRoot)), ...name.split("/"), binName)
|
|
22931
23098
|
];
|
|
22932
|
-
const found = published.map((name) => ({ name, path: binIn(name).find((file) => (0,
|
|
23099
|
+
const found = published.map((name) => ({ name, path: binIn(name).find((file) => (0, import_node_fs22.existsSync)(file)) })).find((c) => c.path);
|
|
22933
23100
|
const platformPackage = found?.name ?? published[0];
|
|
22934
23101
|
let source;
|
|
22935
23102
|
let sourceProblem;
|
|
@@ -22940,7 +23107,7 @@ function readClaudeBinaryState(host = {}) {
|
|
|
22940
23107
|
} else {
|
|
22941
23108
|
source = { path: found.path, bytes: fileBytes(found.path) ?? 0 };
|
|
22942
23109
|
}
|
|
22943
|
-
if (!(0,
|
|
23110
|
+
if (!(0, import_node_fs22.existsSync)(binPath)) {
|
|
22944
23111
|
return { state: "missing", binPath, expectedMagic: magic.name, platformPackage, ...source ? { source } : {}, ...sourceProblem ? { sourceProblem } : {} };
|
|
22945
23112
|
}
|
|
22946
23113
|
const head = readHead(binPath);
|
|
@@ -22983,9 +23150,9 @@ function healClaudeBinary(host = {}, onStep) {
|
|
|
22983
23150
|
const platform2 = host.platform ?? process.platform;
|
|
22984
23151
|
const aside = `${probe.binPath}.stub-${Date.now()}`;
|
|
22985
23152
|
let renamed = false;
|
|
22986
|
-
if ((0,
|
|
23153
|
+
if ((0, import_node_fs22.existsSync)(probe.binPath)) {
|
|
22987
23154
|
try {
|
|
22988
|
-
(0,
|
|
23155
|
+
(0, import_node_fs22.renameSync)(probe.binPath, aside);
|
|
22989
23156
|
renamed = true;
|
|
22990
23157
|
onStep?.(`renamed the stub aside: ${aside}`);
|
|
22991
23158
|
} catch (e) {
|
|
@@ -22994,12 +23161,12 @@ function healClaudeBinary(host = {}, onStep) {
|
|
|
22994
23161
|
}
|
|
22995
23162
|
try {
|
|
22996
23163
|
onStep?.(`copying ${probe.source.path} \u2192 ${probe.binPath} (${(probe.source.bytes / 1e6).toFixed(0)} MB)`);
|
|
22997
|
-
(0,
|
|
22998
|
-
if (platform2 !== "win32") (0,
|
|
23164
|
+
(0, import_node_fs22.copyFileSync)(probe.source.path, probe.binPath);
|
|
23165
|
+
if (platform2 !== "win32") (0, import_node_fs22.chmodSync)(probe.binPath, 493);
|
|
22999
23166
|
} catch (e) {
|
|
23000
23167
|
if (renamed) {
|
|
23001
23168
|
try {
|
|
23002
|
-
(0,
|
|
23169
|
+
(0, import_node_fs22.renameSync)(aside, probe.binPath);
|
|
23003
23170
|
} catch {
|
|
23004
23171
|
return { ok: false, detail: `copy failed (${e.message}) and the stub could not be restored \u2014 the original is at ${aside}` };
|
|
23005
23172
|
}
|
|
@@ -23013,7 +23180,7 @@ function healClaudeBinary(host = {}, onStep) {
|
|
|
23013
23180
|
let kept = false;
|
|
23014
23181
|
if (renamed) {
|
|
23015
23182
|
try {
|
|
23016
|
-
(0,
|
|
23183
|
+
(0, import_node_fs22.rmSync)(aside);
|
|
23017
23184
|
} catch {
|
|
23018
23185
|
kept = true;
|
|
23019
23186
|
}
|
|
@@ -23372,13 +23539,13 @@ function checkLineEndings(probe) {
|
|
|
23372
23539
|
}
|
|
23373
23540
|
|
|
23374
23541
|
// src/release-ledger.ts
|
|
23375
|
-
var
|
|
23376
|
-
var
|
|
23377
|
-
var
|
|
23542
|
+
var import_node_fs23 = require("node:fs");
|
|
23543
|
+
var import_node_path23 = require("node:path");
|
|
23544
|
+
var import_node_crypto9 = require("node:crypto");
|
|
23378
23545
|
|
|
23379
23546
|
// src/file-lock.ts
|
|
23380
23547
|
var import_promises2 = require("node:fs/promises");
|
|
23381
|
-
var
|
|
23548
|
+
var import_node_path22 = require("node:path");
|
|
23382
23549
|
function pidIsDead(pid) {
|
|
23383
23550
|
if (!Number.isInteger(pid) || pid <= 0) return false;
|
|
23384
23551
|
if (pid === process.pid) return false;
|
|
@@ -23496,7 +23663,7 @@ async function withFileLock(lockPath, opts, fn) {
|
|
|
23496
23663
|
}
|
|
23497
23664
|
async function withFencedFileLock(lockPath, opts, fn) {
|
|
23498
23665
|
const resolved = resolveFileLockOpts(opts);
|
|
23499
|
-
await (0, import_promises2.mkdir)((0,
|
|
23666
|
+
await (0, import_promises2.mkdir)((0, import_node_path22.dirname)(lockPath), { recursive: true }).catch(() => void 0);
|
|
23500
23667
|
const guard = await acquireFileLock(lockPath, resolved, Date.now() + resolved.maxWaitMs);
|
|
23501
23668
|
try {
|
|
23502
23669
|
return await fn(() => fileLockHeldBy(lockPath, guard.token));
|
|
@@ -23547,8 +23714,8 @@ function attachOutputNote(note, suffix) {
|
|
|
23547
23714
|
}
|
|
23548
23715
|
function writeFailingLegOutput(artifactPath, output) {
|
|
23549
23716
|
const fileLines = lastNonEmptyLines(output, LEDGER_OUTPUT_FILE_LINES);
|
|
23550
|
-
(0,
|
|
23551
|
-
(0,
|
|
23717
|
+
(0, import_node_fs23.mkdirSync)((0, import_node_path23.dirname)(artifactPath), { recursive: true });
|
|
23718
|
+
(0, import_node_fs23.writeFileSync)(artifactPath, `${fileLines.join("\n")}
|
|
23552
23719
|
`, "utf8");
|
|
23553
23720
|
const tail = fileLines.slice(-LEDGER_OUTPUT_NOTE_LINES).join("\n");
|
|
23554
23721
|
const noteSuffix = truncate(`failing-leg output: ${artifactPath}
|
|
@@ -23563,7 +23730,7 @@ function stampPhaseRecord(ledgerPath, tag, phase, entry, previousRetries, now) {
|
|
|
23563
23730
|
if (raw) {
|
|
23564
23731
|
try {
|
|
23565
23732
|
const persisted = writeFailingLegOutput(
|
|
23566
|
-
(0,
|
|
23733
|
+
(0, import_node_path23.join)((0, import_node_path23.dirname)((0, import_node_path23.dirname)(ledgerPath)), "ledger-output", `${tag}-${phase}.txt`),
|
|
23567
23734
|
raw
|
|
23568
23735
|
);
|
|
23569
23736
|
note = attachOutputNote(note, persisted.noteSuffix);
|
|
@@ -23716,30 +23883,30 @@ function resolvePrimaryGitDir(cwd) {
|
|
|
23716
23883
|
}
|
|
23717
23884
|
let common;
|
|
23718
23885
|
try {
|
|
23719
|
-
common = (0,
|
|
23886
|
+
common = (0, import_node_fs23.readFileSync)((0, import_node_path23.join)(gitDir, "commondir"), "utf8").trim();
|
|
23720
23887
|
} catch (e) {
|
|
23721
23888
|
if (e.code !== "ENOENT") {
|
|
23722
23889
|
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)`);
|
|
23723
23890
|
}
|
|
23724
23891
|
}
|
|
23725
23892
|
if (!common) return gitDir;
|
|
23726
|
-
const commonDir = (0,
|
|
23893
|
+
const commonDir = (0, import_node_path23.isAbsolute)(common) ? common : (0, import_node_path23.resolve)(gitDir, common);
|
|
23727
23894
|
try {
|
|
23728
|
-
(0,
|
|
23895
|
+
(0, import_node_fs23.readFileSync)((0, import_node_path23.join)(commonDir, "HEAD"), "utf8");
|
|
23729
23896
|
} catch (e) {
|
|
23730
23897
|
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`);
|
|
23731
23898
|
}
|
|
23732
23899
|
return commonDir;
|
|
23733
23900
|
}
|
|
23734
23901
|
function releaseLedgerPath(cwd) {
|
|
23735
|
-
return (0,
|
|
23902
|
+
return (0, import_node_path23.join)(resolvePrimaryGitDir(cwd), "mmi-runtime", "release", "phases.json");
|
|
23736
23903
|
}
|
|
23737
23904
|
function atomicWriteJson(path2, ledger) {
|
|
23738
|
-
(0,
|
|
23739
|
-
const tmp = `${path2}.tmp-${process.pid}-${(0,
|
|
23740
|
-
(0,
|
|
23905
|
+
(0, import_node_fs23.mkdirSync)((0, import_node_path23.dirname)(path2), { recursive: true });
|
|
23906
|
+
const tmp = `${path2}.tmp-${process.pid}-${(0, import_node_crypto9.randomBytes)(4).toString("hex")}`;
|
|
23907
|
+
(0, import_node_fs23.writeFileSync)(tmp, `${JSON.stringify(ledger, null, 2)}
|
|
23741
23908
|
`, "utf8");
|
|
23742
|
-
(0,
|
|
23909
|
+
(0, import_node_fs23.renameSync)(tmp, path2);
|
|
23743
23910
|
}
|
|
23744
23911
|
var LEDGER_LOCK_OPTS = { label: "release ledger", staleMs: 18e4, deadHolderSteal: true };
|
|
23745
23912
|
async function withLedgerLock(path2, fn, opts = {}) {
|
|
@@ -23751,16 +23918,16 @@ async function withLedgerLock(path2, fn, opts = {}) {
|
|
|
23751
23918
|
}));
|
|
23752
23919
|
}
|
|
23753
23920
|
function checkoutRootFrom(cwd) {
|
|
23754
|
-
let dir = (0,
|
|
23921
|
+
let dir = (0, import_node_path23.resolve)(cwd);
|
|
23755
23922
|
for (; ; ) {
|
|
23756
23923
|
if (resolveGitDir(dir)) return dir;
|
|
23757
|
-
const parent = (0,
|
|
23924
|
+
const parent = (0, import_node_path23.dirname)(dir);
|
|
23758
23925
|
if (parent === dir) throw new ReleaseLedgerError("no-checkout", `train writer lock: no git checkout found above ${cwd}`);
|
|
23759
23926
|
dir = parent;
|
|
23760
23927
|
}
|
|
23761
23928
|
}
|
|
23762
23929
|
function trainWriterLockPath(cwd) {
|
|
23763
|
-
return (0,
|
|
23930
|
+
return (0, import_node_path23.join)((0, import_node_path23.dirname)(releaseLedgerPath(checkoutRootFrom(cwd))), "train.lock");
|
|
23764
23931
|
}
|
|
23765
23932
|
var TrainWriterBusyError = class extends Error {
|
|
23766
23933
|
lockPath;
|
|
@@ -23786,7 +23953,7 @@ function describeTrainWriterToken(token) {
|
|
|
23786
23953
|
function liveTrainWriterHolder(cwd) {
|
|
23787
23954
|
let token;
|
|
23788
23955
|
try {
|
|
23789
|
-
token = (0,
|
|
23956
|
+
token = (0, import_node_fs23.readFileSync)(trainWriterLockPath(cwd), "utf8");
|
|
23790
23957
|
} catch {
|
|
23791
23958
|
return void 0;
|
|
23792
23959
|
}
|
|
@@ -23808,7 +23975,7 @@ async function acquireTrainWriterLock(cwd, verb) {
|
|
|
23808
23975
|
if (heldTrainWriter) heldTrainWriter.depth -= 1;
|
|
23809
23976
|
};
|
|
23810
23977
|
}
|
|
23811
|
-
(0,
|
|
23978
|
+
(0, import_node_fs23.mkdirSync)((0, import_node_path23.dirname)(lockPath), { recursive: true });
|
|
23812
23979
|
const opts = resolveFileLockOpts({ label: "train writer", staleMs: TRAIN_WRITER_STALE_MS, deadHolderSteal: true, maxWaitMs: 0, holder: verb });
|
|
23813
23980
|
let guard;
|
|
23814
23981
|
try {
|
|
@@ -23817,7 +23984,7 @@ async function acquireTrainWriterLock(cwd, verb) {
|
|
|
23817
23984
|
if (!(e instanceof FileLockBusyError)) throw e;
|
|
23818
23985
|
let token = "";
|
|
23819
23986
|
try {
|
|
23820
|
-
token = (0,
|
|
23987
|
+
token = (0, import_node_fs23.readFileSync)(lockPath, "utf8");
|
|
23821
23988
|
} catch {
|
|
23822
23989
|
token = "";
|
|
23823
23990
|
}
|
|
@@ -23852,7 +24019,7 @@ async function withReleaseLedger(path2, expected, fn, opts = {}) {
|
|
|
23852
24019
|
let current;
|
|
23853
24020
|
let raw;
|
|
23854
24021
|
try {
|
|
23855
|
-
raw = (0,
|
|
24022
|
+
raw = (0, import_node_fs23.readFileSync)(path2, "utf8");
|
|
23856
24023
|
} catch (e) {
|
|
23857
24024
|
if (e.code !== "ENOENT") {
|
|
23858
24025
|
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)`);
|
|
@@ -24521,7 +24688,7 @@ async function clearLedgerFile(path2, anchors, maxWaitMs) {
|
|
|
24521
24688
|
return withLedgerLock(path2, async (fence) => {
|
|
24522
24689
|
let raw;
|
|
24523
24690
|
try {
|
|
24524
|
-
raw = (0,
|
|
24691
|
+
raw = (0, import_node_fs23.readFileSync)(path2, "utf8");
|
|
24525
24692
|
} catch (e) {
|
|
24526
24693
|
if (e.code === "ENOENT") return { cleared: false };
|
|
24527
24694
|
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` };
|
|
@@ -24537,7 +24704,7 @@ async function clearLedgerFile(path2, anchors, maxWaitMs) {
|
|
|
24537
24704
|
} catch (e) {
|
|
24538
24705
|
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)})` };
|
|
24539
24706
|
}
|
|
24540
|
-
await fence(() => (0,
|
|
24707
|
+
await fence(() => (0, import_node_fs23.unlinkSync)(path2));
|
|
24541
24708
|
return { cleared: true, note: `cleared the release ledger at ${path2} for the live-proven aborted ${anchors.tag}` };
|
|
24542
24709
|
}, { maxWaitMs });
|
|
24543
24710
|
}
|
|
@@ -24697,7 +24864,7 @@ async function healStaleAlignmentLeg(deps, cwd, expected) {
|
|
|
24697
24864
|
return withLedgerLock(path2, async (fence) => {
|
|
24698
24865
|
let prior;
|
|
24699
24866
|
try {
|
|
24700
|
-
prior = parseReleaseLedger((0,
|
|
24867
|
+
prior = parseReleaseLedger((0, import_node_fs23.readFileSync)(path2, "utf8"));
|
|
24701
24868
|
} catch {
|
|
24702
24869
|
return void 0;
|
|
24703
24870
|
}
|
|
@@ -24722,7 +24889,7 @@ async function healUnfoldedRunLegs(deps, cwd, model) {
|
|
|
24722
24889
|
const path2 = releaseLedgerPath(cwd);
|
|
24723
24890
|
let prior;
|
|
24724
24891
|
try {
|
|
24725
|
-
prior = parseReleaseLedger((0,
|
|
24892
|
+
prior = parseReleaseLedger((0, import_node_fs23.readFileSync)(path2, "utf8"));
|
|
24726
24893
|
} catch {
|
|
24727
24894
|
return void 0;
|
|
24728
24895
|
}
|
|
@@ -24791,7 +24958,7 @@ async function supersedeContentCausedDeployLeg(deps, cwd) {
|
|
|
24791
24958
|
return withLedgerLock(path2, async (fence) => {
|
|
24792
24959
|
let prior;
|
|
24793
24960
|
try {
|
|
24794
|
-
prior = parseReleaseLedger((0,
|
|
24961
|
+
prior = parseReleaseLedger((0, import_node_fs23.readFileSync)(path2, "utf8"));
|
|
24795
24962
|
} catch (e) {
|
|
24796
24963
|
throw new ReleaseLedgerError(
|
|
24797
24964
|
"unreadable",
|
|
@@ -24888,11 +25055,11 @@ async function proveOriginPromotionOrArchived(deps, prior, path2, label, ref, fe
|
|
|
24888
25055
|
if (!releaseAbsent) {
|
|
24889
25056
|
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})`);
|
|
24890
25057
|
}
|
|
24891
|
-
const archivePath = (0,
|
|
24892
|
-
if ((0,
|
|
25058
|
+
const archivePath = (0, import_node_path23.join)((0, import_node_path23.dirname)(path2), `phases.archive-${prior.tag}.json`);
|
|
25059
|
+
if ((0, import_node_fs23.existsSync)(archivePath)) {
|
|
24893
25060
|
throw new Error(`${label}: archive already exists at ${archivePath} \u2014 preserving both ledger records; resolve the collision by hand; nothing was written (${ref})`);
|
|
24894
25061
|
}
|
|
24895
|
-
await fence(() => (0,
|
|
25062
|
+
await fence(() => (0, import_node_fs23.renameSync)(path2, archivePath));
|
|
24896
25063
|
return "deleted";
|
|
24897
25064
|
}
|
|
24898
25065
|
async function supersedeContentCausedPublishLeg(deps, cwd) {
|
|
@@ -24900,7 +25067,7 @@ async function supersedeContentCausedPublishLeg(deps, cwd) {
|
|
|
24900
25067
|
return withLedgerLock(path2, async (fence) => {
|
|
24901
25068
|
let prior;
|
|
24902
25069
|
try {
|
|
24903
|
-
prior = parseReleaseLedger((0,
|
|
25070
|
+
prior = parseReleaseLedger((0, import_node_fs23.readFileSync)(path2, "utf8"));
|
|
24904
25071
|
} catch (e) {
|
|
24905
25072
|
throw new ReleaseLedgerError(
|
|
24906
25073
|
"unreadable",
|
|
@@ -24982,7 +25149,7 @@ async function supersedeContentCausedDeployAndPublishLegs(deps, cwd) {
|
|
|
24982
25149
|
return withLedgerLock(path2, async (fence) => {
|
|
24983
25150
|
let prior;
|
|
24984
25151
|
try {
|
|
24985
|
-
prior = parseReleaseLedger((0,
|
|
25152
|
+
prior = parseReleaseLedger((0, import_node_fs23.readFileSync)(path2, "utf8"));
|
|
24986
25153
|
} catch (e) {
|
|
24987
25154
|
throw new ReleaseLedgerError(
|
|
24988
25155
|
"unreadable",
|
|
@@ -25087,7 +25254,7 @@ async function supersedeContentCausedDeployAndPublishLegs(deps, cwd) {
|
|
|
25087
25254
|
async function reverifyPriorRunLegs(deps, path2, targetTag) {
|
|
25088
25255
|
let prior;
|
|
25089
25256
|
try {
|
|
25090
|
-
prior = parseReleaseLedger((0,
|
|
25257
|
+
prior = parseReleaseLedger((0, import_node_fs23.readFileSync)(path2, "utf8"));
|
|
25091
25258
|
} catch {
|
|
25092
25259
|
return;
|
|
25093
25260
|
}
|
|
@@ -25107,7 +25274,7 @@ async function beginReleaseLedger(deps, cwd, targetTag) {
|
|
|
25107
25274
|
return withLedgerLock(path2, async (fence) => {
|
|
25108
25275
|
let raw;
|
|
25109
25276
|
try {
|
|
25110
|
-
raw = (0,
|
|
25277
|
+
raw = (0, import_node_fs23.readFileSync)(path2, "utf8");
|
|
25111
25278
|
} catch (e) {
|
|
25112
25279
|
if (e.code === "ENOENT") return { ok: true };
|
|
25113
25280
|
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)` };
|
|
@@ -25145,15 +25312,15 @@ async function beginReleaseLedger(deps, cwd, targetTag) {
|
|
|
25145
25312
|
if (liveSha.toLowerCase() !== prior.tagSha.toLowerCase()) {
|
|
25146
25313
|
return { ok: false, error: `the completed ${prior.tag} ledger says phases-green but origin reports ${liveSha.slice(0, 12) || "no tag"} \u2260 ${prior.tagSha.slice(0, 12)} \u2014 refusing to archive on unproven state; resolve by hand (#5987)` };
|
|
25147
25314
|
}
|
|
25148
|
-
const archivePath = (0,
|
|
25315
|
+
const archivePath = (0, import_node_path23.join)((0, import_node_path23.dirname)(path2), `phases.archive-${prior.tag}.json`);
|
|
25149
25316
|
try {
|
|
25150
|
-
await fence(() => (0,
|
|
25317
|
+
await fence(() => (0, import_node_fs23.unlinkSync)(archivePath));
|
|
25151
25318
|
} catch (e) {
|
|
25152
25319
|
if (e.code !== "ENOENT") {
|
|
25153
25320
|
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)` };
|
|
25154
25321
|
}
|
|
25155
25322
|
}
|
|
25156
|
-
await fence(() => (0,
|
|
25323
|
+
await fence(() => (0, import_node_fs23.renameSync)(path2, archivePath));
|
|
25157
25324
|
return { ok: true, note: `archived the completed release ledger ${prior.tag} to ${archivePath} (live-proven at ${prior.tagSha.slice(0, 12)})` };
|
|
25158
25325
|
});
|
|
25159
25326
|
}
|
|
@@ -25181,7 +25348,7 @@ async function retryHotfixDeployLegs(deps, cwd, opts = {}) {
|
|
|
25181
25348
|
return withLedgerLock(path2, async (fence) => {
|
|
25182
25349
|
let prior;
|
|
25183
25350
|
try {
|
|
25184
|
-
prior = parseReleaseLedger((0,
|
|
25351
|
+
prior = parseReleaseLedger((0, import_node_fs23.readFileSync)(path2, "utf8"));
|
|
25185
25352
|
} catch (e) {
|
|
25186
25353
|
throw new ReleaseLedgerError(
|
|
25187
25354
|
"unreadable",
|
|
@@ -25372,10 +25539,10 @@ function readOriginWorkflowsDefault(root, ref) {
|
|
|
25372
25539
|
}
|
|
25373
25540
|
var NPM_REGISTRY = "https://registry.npmjs.org";
|
|
25374
25541
|
async function probeRegistryWhoami(train) {
|
|
25375
|
-
const dir = (0,
|
|
25376
|
-
const rc = (0,
|
|
25542
|
+
const dir = (0, import_node_fs24.mkdtempSync)((0, import_node_path24.join)((0, import_node_os15.tmpdir)(), "mmi-npmrc-"));
|
|
25543
|
+
const rc = (0, import_node_path24.join)(dir, "npmrc");
|
|
25377
25544
|
try {
|
|
25378
|
-
(0,
|
|
25545
|
+
(0, import_node_fs24.writeFileSync)(rc, "//registry.npmjs.org/:_authToken=${NPM_TOKEN}\n");
|
|
25379
25546
|
await train.runSelf(["secrets", "use", "npm/NPM_TOKEN", "--slug", "_org", "--", "npm", "whoami", "--registry", NPM_REGISTRY, "--userconfig", rc]);
|
|
25380
25547
|
return { kind: "ok", detail: "the registry answered a login" };
|
|
25381
25548
|
} catch (e) {
|
|
@@ -25386,7 +25553,7 @@ async function probeRegistryWhoami(train) {
|
|
|
25386
25553
|
if (/\bE401\b|401 Unauthorized/.test(stderr)) return { kind: "rejected", detail: "npm whoami answered 401 Unauthorized" };
|
|
25387
25554
|
return { kind: "unverified", detail: first };
|
|
25388
25555
|
} finally {
|
|
25389
|
-
(0,
|
|
25556
|
+
(0, import_node_fs24.rmSync)(dir, { recursive: true, force: true });
|
|
25390
25557
|
}
|
|
25391
25558
|
}
|
|
25392
25559
|
var REGISTRY_TOKEN_ENV = /\b(NODE_AUTH_TOKEN|NPM_TOKEN)\b/;
|
|
@@ -25404,7 +25571,7 @@ var defaultDeps2 = {
|
|
|
25404
25571
|
ledgerPath: releaseLedgerPath,
|
|
25405
25572
|
readLedgerRaw: (path2) => {
|
|
25406
25573
|
try {
|
|
25407
|
-
return (0,
|
|
25574
|
+
return (0, import_node_fs24.readFileSync)(path2, "utf8");
|
|
25408
25575
|
} catch (e) {
|
|
25409
25576
|
if (e.code === "ENOENT") return void 0;
|
|
25410
25577
|
throw e;
|
|
@@ -25415,7 +25582,7 @@ var defaultDeps2 = {
|
|
|
25415
25582
|
trainWriterHolder: liveTrainWriterHolder,
|
|
25416
25583
|
readSurfacesRaw: (cwd) => {
|
|
25417
25584
|
try {
|
|
25418
|
-
return (0,
|
|
25585
|
+
return (0, import_node_fs24.readFileSync)((0, import_node_path24.join)(cwd, "surfaces.json"), "utf8");
|
|
25419
25586
|
} catch {
|
|
25420
25587
|
return void 0;
|
|
25421
25588
|
}
|
|
@@ -26005,7 +26172,7 @@ function formatTrainDoctor(v) {
|
|
|
26005
26172
|
|
|
26006
26173
|
// src/release-plain-words.ts
|
|
26007
26174
|
var import_promises3 = require("node:fs/promises");
|
|
26008
|
-
var
|
|
26175
|
+
var import_node_fs25 = require("node:fs");
|
|
26009
26176
|
function releaseCutByNotes(cutBy) {
|
|
26010
26177
|
return `## Internal
|
|
26011
26178
|
Cut by ${formatSessionIdentity(cutBy)}
|
|
@@ -26030,7 +26197,7 @@ function validateSuiteReleaseSummary(path2) {
|
|
|
26030
26197
|
if (!path2) throw new Error(`requires --announce-summary-file <path> before promoting any member \u2014 see ${SUMMARY_GUIDE}`);
|
|
26031
26198
|
let content;
|
|
26032
26199
|
try {
|
|
26033
|
-
content = (0,
|
|
26200
|
+
content = (0, import_node_fs25.readFileSync)(path2, "utf8");
|
|
26034
26201
|
} catch (e) {
|
|
26035
26202
|
throw new Error(`could not read summary file ${path2}: ${e.message} \u2014 see ${SUMMARY_GUIDE}`);
|
|
26036
26203
|
}
|
|
@@ -26237,34 +26404,34 @@ function vercelVersionEnvDeps(deps) {
|
|
|
26237
26404
|
// src/train-apply-phases.ts
|
|
26238
26405
|
var TRAIN_BUMP_INTENTS = ["major", "minor", "patch"];
|
|
26239
26406
|
function readLocalGateWorkflows() {
|
|
26240
|
-
const dir = (0,
|
|
26407
|
+
const dir = (0, import_node_path25.join)(".github", "workflows");
|
|
26241
26408
|
let names;
|
|
26242
26409
|
try {
|
|
26243
|
-
names = (0,
|
|
26410
|
+
names = (0, import_node_fs26.readdirSync)(dir);
|
|
26244
26411
|
} catch {
|
|
26245
26412
|
return null;
|
|
26246
26413
|
}
|
|
26247
26414
|
const files = [];
|
|
26248
26415
|
for (const name of names.filter(isGateWorkflowPath)) {
|
|
26249
26416
|
try {
|
|
26250
|
-
files.push({ path: `${dir}/${name}`.replace(/\\/g, "/"), body: (0,
|
|
26417
|
+
files.push({ path: `${dir}/${name}`.replace(/\\/g, "/"), body: (0, import_node_fs26.readFileSync)((0, import_node_path25.join)(dir, name), "utf8") });
|
|
26251
26418
|
} catch {
|
|
26252
26419
|
}
|
|
26253
26420
|
}
|
|
26254
26421
|
return files;
|
|
26255
26422
|
}
|
|
26256
26423
|
function readLocalWorkflows() {
|
|
26257
|
-
const dir = (0,
|
|
26424
|
+
const dir = (0, import_node_path25.join)(".github", "workflows");
|
|
26258
26425
|
let names;
|
|
26259
26426
|
try {
|
|
26260
|
-
names = (0,
|
|
26427
|
+
names = (0, import_node_fs26.readdirSync)(dir);
|
|
26261
26428
|
} catch {
|
|
26262
26429
|
return null;
|
|
26263
26430
|
}
|
|
26264
26431
|
const files = [];
|
|
26265
26432
|
for (const name of names.filter((n) => /\.ya?ml$/i.test(n))) {
|
|
26266
26433
|
try {
|
|
26267
|
-
files.push({ path: `${dir}/${name}`.replace(/\\/g, "/"), body: (0,
|
|
26434
|
+
files.push({ path: `${dir}/${name}`.replace(/\\/g, "/"), body: (0, import_node_fs26.readFileSync)((0, import_node_path25.join)(dir, name), "utf8") });
|
|
26268
26435
|
} catch {
|
|
26269
26436
|
}
|
|
26270
26437
|
}
|
|
@@ -27146,7 +27313,7 @@ async function activeRcandLedgerCandidate(deps, cwd) {
|
|
|
27146
27313
|
}
|
|
27147
27314
|
let prior;
|
|
27148
27315
|
try {
|
|
27149
|
-
prior = parseReleaseLedger((0,
|
|
27316
|
+
prior = parseReleaseLedger((0, import_node_fs26.readFileSync)(path2, "utf8"));
|
|
27150
27317
|
} catch {
|
|
27151
27318
|
return void 0;
|
|
27152
27319
|
}
|
|
@@ -30428,11 +30595,11 @@ function buildPluginCachePlan(home, running, deps, opts = {}) {
|
|
|
30428
30595
|
return absent;
|
|
30429
30596
|
}
|
|
30430
30597
|
const versions = names.filter(isVersionDirName);
|
|
30431
|
-
const
|
|
30432
|
-
const pruneSet = new Set(
|
|
30598
|
+
const prune2 = selectPrunablePluginVersions(versions, running, opts.installedVersion);
|
|
30599
|
+
const pruneSet = new Set(prune2);
|
|
30433
30600
|
const keep = [...versions].sort((a, b) => compareVersions(b, a)).filter((v) => !pruneSet.has(v));
|
|
30434
|
-
const bytes = opts.withBytes ?
|
|
30435
|
-
return { cacheRoot, present: true, keep, prune, bytes, running, ...stagingFields };
|
|
30601
|
+
const bytes = opts.withBytes ? prune2.reduce((sum, v) => sum + deps.dirBytes(`${cacheRoot}/${v}`), 0) : 0;
|
|
30602
|
+
return { cacheRoot, present: true, keep, prune: prune2, bytes, running, ...stagingFields };
|
|
30436
30603
|
}
|
|
30437
30604
|
function applyPluginCachePlan(plan, remove2, stagingGuard) {
|
|
30438
30605
|
const removed = [];
|
|
@@ -30741,6 +30908,12 @@ function registerBoardCommands(program3) {
|
|
|
30741
30908
|
if (!o.out) console.log(output);
|
|
30742
30909
|
else console.log(`Wrote board read to ${o.out} (UTF-8, ${writeUtf8Receipt(o.out, output)} bytes)`);
|
|
30743
30910
|
} catch (e) {
|
|
30911
|
+
if (e instanceof BoardSnapshotFailure) {
|
|
30912
|
+
if (o.json) console.log(JSON.stringify(e.receipt));
|
|
30913
|
+
console.error(`mmi-cli board read failed: ${e.message}`);
|
|
30914
|
+
process.exitCode = e.exitCode;
|
|
30915
|
+
return;
|
|
30916
|
+
}
|
|
30744
30917
|
if (o.json && e && typeof e === "object" && "quota" in e && e.quota) console.log(JSON.stringify(e.quota));
|
|
30745
30918
|
return failGraceful(`board read failed: ${withDiscoverMissDetail(e.message)}`);
|
|
30746
30919
|
}
|
|
@@ -30781,7 +30954,7 @@ function registerBoardCommands(program3) {
|
|
|
30781
30954
|
return `Claimed ${ref} for ${holder} - In Progress${reclaimed}`;
|
|
30782
30955
|
}
|
|
30783
30956
|
const board = program3.command("board").description("read, claim, show, and move Project v2 work items for the current repo");
|
|
30784
|
-
board.command("read", { isDefault: true }).alias("list").description("read the board and print user-owned, claimable, and taken items").option("--json", "machine-readable output").option("--repo <owner/repo>", "current repo (defaults to git origin)").option("--direct", "bypass the Hub snapshot and read the live board through direct GitHub GraphQL").option("--snapshot-only", "
|
|
30957
|
+
board.command("read", { isDefault: true }).alias("list").description("read the board and print user-owned, claimable, and taken items").option("--json", "machine-readable output").option("--repo <owner/repo>", "current repo (defaults to git origin)").option("--direct", "bypass the Hub snapshot and read the live board through direct GitHub GraphQL").option("--snapshot-only", "never fall back to your personal GraphQL pool; failure exits: 20 hub-unreachable, 21 app-quota-exhausted, 22 refused. With --json, stdout is {ok:false,outcome,reason[,resetAt,pool]} (pool is rest or graphql when known); success is unchanged").option("--min-cursor <n>", "board-event cursor (from `oracle board events`) the Hub snapshot must postdate; a cached snapshot older than that event is rebuilt (#7240)").option("--bundle-details", "fetch body/comments only for user-owned and claimable issues").option("--bodies", "fetch body/comments for EVERY scoped row, including taken and unowned in-flight ones \u2014 for consumers that scope by Status rather than ownership (#4861); implies --bundle-details and costs one extra read per row").option("--allow-partial", "return partial board results when later page/detail reads fail").option("--out <path>", "write the output to this file as UTF-8 (no BOM) instead of stdout \u2014 the shell-free receipt path (#5802)").addHelpText("after", "\nread is always the authoritative live GitHub Project v2 board (#4926).\n--direct skips the Hub snapshot and uses the existing direct GitHub GraphQL read immediately.\n--allow-partial applies to the paginated path and detail reads.\n\nWhen using Windows PowerShell 5.1, avoid shell redirects: PowerShell 5.1's `> file.json` is Out-File,\nwhich writes UTF-16LE with a BOM, and Node reading it as 'utf8' then fails JSON.parse at position 1\n(#5802). Use --out instead \u2014 the CLI writes the file itself as UTF-8:\n mmi-cli oracle board read --json --out .jerv/tmp/board.json\n").action((o) => runBoardRead(o));
|
|
30785
30958
|
board.command("events").description("content-free board/CI change records after a cursor, from the Hub event feed (no GitHub call) \u2014 for real-time sidebars (#7235)").option("--since <cursor>", "cursor from the previous answer; omit on first read (answers the head cursor with resync:true)").option("--wait <seconds>", "hold up to this long (max 120), polling every 2s, and return on the first event or resync", "0").option("--repo <owner/repo>", "repo whose Hub config to use (defaults to git origin)").option("--json", "machine-readable output (already the default)").addHelpText("after", "\nPrints {cursor, events, resync, more[, hidden]}. Pass the returned cursor as the next --since.\nresync:true means records were missed (retention ~1h, or a gap): re-read the board with\n`mmi-cli oracle board read --snapshot-only --json`.\n").action(async (o) => {
|
|
30786
30959
|
try {
|
|
30787
30960
|
if (o.since !== void 0 && !/^\d{1,15}$/.test(o.since)) throw new Error("--since must be a non-negative integer cursor");
|
|
@@ -31022,9 +31195,9 @@ function registerBoardCommands(program3) {
|
|
|
31022
31195
|
}
|
|
31023
31196
|
|
|
31024
31197
|
// src/bootstrap-commands.ts
|
|
31025
|
-
var
|
|
31026
|
-
var
|
|
31027
|
-
var
|
|
31198
|
+
var import_node_fs30 = require("node:fs");
|
|
31199
|
+
var import_node_os18 = require("node:os");
|
|
31200
|
+
var import_node_path29 = require("node:path");
|
|
31028
31201
|
init_cli_shared();
|
|
31029
31202
|
init_clean_exit();
|
|
31030
31203
|
|
|
@@ -31208,8 +31381,8 @@ init_github_client();
|
|
|
31208
31381
|
init_cli_shared();
|
|
31209
31382
|
|
|
31210
31383
|
// src/port-registry.ts
|
|
31211
|
-
var
|
|
31212
|
-
var
|
|
31384
|
+
var import_node_fs27 = require("node:fs");
|
|
31385
|
+
var import_node_path26 = require("node:path");
|
|
31213
31386
|
|
|
31214
31387
|
// ../infra/port-geometry.mjs
|
|
31215
31388
|
var PORT_BLOCK = 100;
|
|
@@ -31223,8 +31396,8 @@ function nextPortBlock(registry2) {
|
|
|
31223
31396
|
return [base, base + PORT_SPAN];
|
|
31224
31397
|
}
|
|
31225
31398
|
function loadPortRegistry(path2) {
|
|
31226
|
-
if (!(0,
|
|
31227
|
-
const raw = JSON.parse((0,
|
|
31399
|
+
if (!(0, import_node_fs27.existsSync)(path2)) return {};
|
|
31400
|
+
const raw = JSON.parse((0, import_node_fs27.readFileSync)(path2, "utf8"));
|
|
31228
31401
|
const out = {};
|
|
31229
31402
|
for (const [key, value] of Object.entries(raw)) {
|
|
31230
31403
|
if (Array.isArray(value) && value.length === 2 && value.every((n) => typeof n === "number")) {
|
|
@@ -31252,22 +31425,22 @@ function existingPortRange(repo, registry2) {
|
|
|
31252
31425
|
return registry2[repo] ?? null;
|
|
31253
31426
|
}
|
|
31254
31427
|
function portRangeInfraAt(root, source) {
|
|
31255
|
-
const registryPath = (0,
|
|
31256
|
-
const ddbScriptPath = (0,
|
|
31257
|
-
if (!(0,
|
|
31428
|
+
const registryPath = (0, import_node_path26.join)(root, "infra", "port-ranges.json");
|
|
31429
|
+
const ddbScriptPath = (0, import_node_path26.join)(root, "infra", "port-ddb.mjs");
|
|
31430
|
+
if (!(0, import_node_fs27.existsSync)(registryPath) || !(0, import_node_fs27.existsSync)(ddbScriptPath)) return null;
|
|
31258
31431
|
return { root, source, registryPath, ddbScriptPath };
|
|
31259
31432
|
}
|
|
31260
31433
|
function resolvePortRangeInfra(cwd, packageDir) {
|
|
31261
31434
|
const direct = portRangeInfraAt(cwd, "cwd");
|
|
31262
31435
|
if (direct) return direct;
|
|
31263
|
-
for (let dir = cwd; ; dir = (0,
|
|
31264
|
-
const sibling = portRangeInfraAt((0,
|
|
31436
|
+
for (let dir = cwd; ; dir = (0, import_node_path26.dirname)(dir)) {
|
|
31437
|
+
const sibling = portRangeInfraAt((0, import_node_path26.join)(dir, "MMI-Hub"), "sibling-hub");
|
|
31265
31438
|
if (sibling) return sibling;
|
|
31266
|
-
const parent = (0,
|
|
31439
|
+
const parent = (0, import_node_path26.dirname)(dir);
|
|
31267
31440
|
if (parent === dir) break;
|
|
31268
31441
|
}
|
|
31269
31442
|
if (packageDir) {
|
|
31270
|
-
const pkgRoot = (0,
|
|
31443
|
+
const pkgRoot = (0, import_node_path26.join)(packageDir, "..", "..");
|
|
31271
31444
|
const pkgFrom = portRangeInfraAt(pkgRoot, "pkg-root");
|
|
31272
31445
|
if (pkgFrom) return pkgFrom;
|
|
31273
31446
|
}
|
|
@@ -31284,7 +31457,7 @@ async function ensurePortRangeAtomic(repo, path2, allocate) {
|
|
|
31284
31457
|
} catch (e) {
|
|
31285
31458
|
const why = e.message;
|
|
31286
31459
|
const missing = /@aws-sdk\/[\w-]+/.exec(why)?.[0];
|
|
31287
|
-
throw new Error(`DDB port allocator failed for ${repo} \u2014 refusing to fall back to the frozen ${path2} (it would hand out a block the cursor already gave away). ` + (missing && /cannot find|not found|ERR_MODULE_NOT_FOUND/i.test(why) ? `Missing dependency ${missing}: run \`npm ci\` in ${(0,
|
|
31460
|
+
throw new Error(`DDB port allocator failed for ${repo} \u2014 refusing to fall back to the frozen ${path2} (it would hand out a block the cursor already gave away). ` + (missing && /cannot find|not found|ERR_MODULE_NOT_FOUND/i.test(why) ? `Missing dependency ${missing}: run \`npm ci\` in ${(0, import_node_path26.dirname)(path2)}, then retry.` : "Check AWS credentials and that the registry table is reachable, then retry.") + ` Cause: ${why}`);
|
|
31288
31461
|
}
|
|
31289
31462
|
}
|
|
31290
31463
|
|
|
@@ -31336,13 +31509,13 @@ async function assignPersistedPortRange(repo, slug, reg, opts) {
|
|
|
31336
31509
|
}
|
|
31337
31510
|
|
|
31338
31511
|
// src/box-commands.ts
|
|
31339
|
-
var
|
|
31512
|
+
var import_node_fs29 = require("node:fs");
|
|
31340
31513
|
var import_node_child_process10 = require("node:child_process");
|
|
31341
|
-
var
|
|
31342
|
-
var
|
|
31514
|
+
var import_node_os17 = require("node:os");
|
|
31515
|
+
var import_node_path28 = require("node:path");
|
|
31343
31516
|
|
|
31344
31517
|
// src/box-control.ts
|
|
31345
|
-
var
|
|
31518
|
+
var import_node_crypto10 = require("node:crypto");
|
|
31346
31519
|
var MANIFEST_PATH = "infra/box-control/manifest.json";
|
|
31347
31520
|
var ALLOWED_POST = /* @__PURE__ */ new Set(["systemctl daemon-reload"]);
|
|
31348
31521
|
function parseManifest(text) {
|
|
@@ -31389,7 +31562,7 @@ function filesForBox(files, box) {
|
|
|
31389
31562
|
return files.flatMap((file) => file.targets.filter((t) => t.box === box).map((t) => ({ file, dest: t.dest })));
|
|
31390
31563
|
}
|
|
31391
31564
|
function md5(content) {
|
|
31392
|
-
return (0,
|
|
31565
|
+
return (0, import_node_crypto10.createHash)("md5").update(content).digest("hex");
|
|
31393
31566
|
}
|
|
31394
31567
|
function planRemoteScript(dests) {
|
|
31395
31568
|
const lines2 = ["set -u"];
|
|
@@ -31468,9 +31641,9 @@ function applyRemoteScript(items, date) {
|
|
|
31468
31641
|
init_clean_exit();
|
|
31469
31642
|
|
|
31470
31643
|
// src/secrets-commands.ts
|
|
31471
|
-
var
|
|
31472
|
-
var
|
|
31473
|
-
var
|
|
31644
|
+
var import_node_fs28 = require("node:fs");
|
|
31645
|
+
var import_node_path27 = require("node:path");
|
|
31646
|
+
var import_node_os16 = require("node:os");
|
|
31474
31647
|
init_cli_shared();
|
|
31475
31648
|
init_hub_auth();
|
|
31476
31649
|
init_github_client();
|
|
@@ -32626,18 +32799,18 @@ function collectMap(value, previous = []) {
|
|
|
32626
32799
|
return [...previous, value];
|
|
32627
32800
|
}
|
|
32628
32801
|
async function decryptRailsCredentials(input) {
|
|
32629
|
-
const appDir = (0,
|
|
32802
|
+
const appDir = (0, import_node_path27.resolve)(input.appDir ?? process.cwd());
|
|
32630
32803
|
const credentialsFile = input.credentialsFile ?? DEFAULT_RAILS_CREDENTIALS_FILE;
|
|
32631
32804
|
const masterKeyFile = input.masterKeyFile ?? DEFAULT_RAILS_MASTER_KEY_FILE;
|
|
32632
|
-
const credentialsPath = (0,
|
|
32633
|
-
const masterKeyPath = (0,
|
|
32805
|
+
const credentialsPath = (0, import_node_path27.resolve)(appDir, credentialsFile);
|
|
32806
|
+
const masterKeyPath = (0, import_node_path27.resolve)(appDir, masterKeyFile);
|
|
32634
32807
|
const env = {
|
|
32635
32808
|
...process.env,
|
|
32636
32809
|
MMI_RAILS_CREDENTIALS_FILE: credentialsPath,
|
|
32637
32810
|
MMI_RAILS_MASTER_KEY_FILE: masterKeyPath
|
|
32638
32811
|
};
|
|
32639
|
-
if ((0,
|
|
32640
|
-
env.RAILS_MASTER_KEY = (0,
|
|
32812
|
+
if ((0, import_node_fs28.existsSync)(masterKeyPath)) {
|
|
32813
|
+
env.RAILS_MASTER_KEY = (0, import_node_fs28.readFileSync)(masterKeyPath, "utf8").trim();
|
|
32641
32814
|
}
|
|
32642
32815
|
const script = [
|
|
32643
32816
|
'require "json"',
|
|
@@ -32647,9 +32820,9 @@ async function decryptRailsCredentials(input) {
|
|
|
32647
32820
|
'config = ActiveSupport::EncryptedConfiguration.new(config_path: config_path, key_path: key_path, env_key: "RAILS_MASTER_KEY", raise_if_missing_key: true)',
|
|
32648
32821
|
"puts JSON.generate(config.config)"
|
|
32649
32822
|
].join("\n");
|
|
32650
|
-
const scriptDir = (0,
|
|
32651
|
-
const scriptPath = (0,
|
|
32652
|
-
(0,
|
|
32823
|
+
const scriptDir = (0, import_node_fs28.mkdtempSync)((0, import_node_path27.join)((0, import_node_os16.tmpdir)(), "mmi-rails-decrypt-"));
|
|
32824
|
+
const scriptPath = (0, import_node_path27.join)(scriptDir, "decrypt.rb");
|
|
32825
|
+
(0, import_node_fs28.writeFileSync)(scriptPath, script, "utf8");
|
|
32653
32826
|
try {
|
|
32654
32827
|
const args = ["exec", "ruby", scriptPath];
|
|
32655
32828
|
const cmd = process.platform === "win32" ? "cmd.exe" : "bundle";
|
|
@@ -32661,7 +32834,7 @@ async function decryptRailsCredentials(input) {
|
|
|
32661
32834
|
});
|
|
32662
32835
|
return JSON.parse(stdout);
|
|
32663
32836
|
} finally {
|
|
32664
|
-
(0,
|
|
32837
|
+
(0, import_node_fs28.rmSync)(scriptDir, { recursive: true, force: true });
|
|
32665
32838
|
}
|
|
32666
32839
|
}
|
|
32667
32840
|
async function readSecretStdin() {
|
|
@@ -32751,7 +32924,7 @@ function registerSecretsCommands(program3) {
|
|
|
32751
32924
|
let body;
|
|
32752
32925
|
if (o.file) {
|
|
32753
32926
|
try {
|
|
32754
|
-
body = (0,
|
|
32927
|
+
body = (0, import_node_fs28.readFileSync)((0, import_node_path27.resolve)(o.file), "utf8");
|
|
32755
32928
|
} catch (e) {
|
|
32756
32929
|
return fail(`secrets org-catalog: cannot read --file ${o.file}: ${e.message}`);
|
|
32757
32930
|
}
|
|
@@ -32887,7 +33060,7 @@ function registerSecretsCommands(program3) {
|
|
|
32887
33060
|
{
|
|
32888
33061
|
...d,
|
|
32889
33062
|
decryptRailsCredentials,
|
|
32890
|
-
removeFile: (path2) => (0,
|
|
33063
|
+
removeFile: (path2) => (0, import_node_fs28.unlinkSync)((0, import_node_path27.resolve)(o.appDir ?? process.cwd(), path2))
|
|
32891
33064
|
},
|
|
32892
33065
|
{
|
|
32893
33066
|
repo: o.repo,
|
|
@@ -33143,7 +33316,7 @@ function registerBoxCommands(program3) {
|
|
|
33143
33316
|
}
|
|
33144
33317
|
const remote = command && command.length ? command.join(" ") : void 0;
|
|
33145
33318
|
const wroteScript = o.ssh && o.script ? o.script : null;
|
|
33146
|
-
if (wroteScript) (0,
|
|
33319
|
+
if (wroteScript) (0, import_node_fs29.writeFileSync)(wroteScript, sshRecipeScript(found, remote), "utf8");
|
|
33147
33320
|
if (o.json) {
|
|
33148
33321
|
console.log(JSON.stringify({
|
|
33149
33322
|
box: found,
|
|
@@ -33217,17 +33390,17 @@ function hubGitShow(ref) {
|
|
|
33217
33390
|
return (path2) => git3(["show", `${ref}:${path2}`]);
|
|
33218
33391
|
}
|
|
33219
33392
|
function runOnBox(found, script) {
|
|
33220
|
-
const dir = (0,
|
|
33393
|
+
const dir = (0, import_node_fs29.mkdtempSync)((0, import_node_path28.join)((0, import_node_os17.tmpdir)(), "mmi-box-control-"));
|
|
33221
33394
|
try {
|
|
33222
|
-
const recipe = (0,
|
|
33223
|
-
(0,
|
|
33395
|
+
const recipe = (0, import_node_path28.join)(dir, "recipe.sh");
|
|
33396
|
+
(0, import_node_fs29.writeFileSync)(recipe, sshRecipeScript(found, "sh -s"), "utf8");
|
|
33224
33397
|
const r = (0, import_node_child_process10.spawnSync)("bash", [recipe], { input: script, encoding: "utf8", maxBuffer: 16 * 1024 * 1024, timeout: 18e4, windowsHide: true });
|
|
33225
33398
|
if (r.status !== 0) {
|
|
33226
33399
|
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(" | ")}`);
|
|
33227
33400
|
}
|
|
33228
33401
|
return r.stdout;
|
|
33229
33402
|
} finally {
|
|
33230
|
-
(0,
|
|
33403
|
+
(0, import_node_fs29.rmSync)(dir, { recursive: true, force: true });
|
|
33231
33404
|
}
|
|
33232
33405
|
}
|
|
33233
33406
|
function formatControl(mode, box, rows) {
|
|
@@ -33355,7 +33528,7 @@ function renderDeployPortDoctor(report) {
|
|
|
33355
33528
|
}
|
|
33356
33529
|
|
|
33357
33530
|
// src/bootstrap-drift.ts
|
|
33358
|
-
var
|
|
33531
|
+
var import_node_crypto11 = require("node:crypto");
|
|
33359
33532
|
function byteComparableSeeds(manifest, cls) {
|
|
33360
33533
|
return manifest.seeds.filter((s) => s.ownership === "org" && s.source === "self" && s.classes.includes(cls));
|
|
33361
33534
|
}
|
|
@@ -33375,7 +33548,7 @@ function compareSeedBytes(hubContent, repoContent) {
|
|
|
33375
33548
|
return normalize(hubContent) === normalize(repoContent) ? "match" : "drift";
|
|
33376
33549
|
}
|
|
33377
33550
|
function seedContentHash(content) {
|
|
33378
|
-
return (0,
|
|
33551
|
+
return (0, import_node_crypto11.createHash)("sha256").update(content.replace(/\r\n/g, "\n"), "utf8").digest("hex");
|
|
33379
33552
|
}
|
|
33380
33553
|
function auditRepoSeedDrift(repo, seeds, hubContents, repoReads) {
|
|
33381
33554
|
const byTarget = new Map(repoReads.map((r) => [r.target, r.content]));
|
|
@@ -33538,7 +33711,7 @@ function renderPropagationReport(plan) {
|
|
|
33538
33711
|
}
|
|
33539
33712
|
|
|
33540
33713
|
// src/bootstrap-propagation-identity.ts
|
|
33541
|
-
var
|
|
33714
|
+
var import_node_crypto12 = require("node:crypto");
|
|
33542
33715
|
var PROPAGATION_BRANCH_PREFIX = "seed-propagate-";
|
|
33543
33716
|
var TARGET_MARKER_NAME = "mmi-bootstrap-propagation-target";
|
|
33544
33717
|
function safeBranchPart(value, maxLength, fallback) {
|
|
@@ -33551,7 +33724,7 @@ function repoSlug2(repo) {
|
|
|
33551
33724
|
function propagationBranch(repo, target) {
|
|
33552
33725
|
const repoPart = safeBranchPart(repoSlug2(repo), 32, "repo");
|
|
33553
33726
|
const targetPart = safeBranchPart(target, 48, "target");
|
|
33554
|
-
const hash = (0,
|
|
33727
|
+
const hash = (0, import_node_crypto12.createHash)("sha256").update(repo.trim().toLowerCase()).update("\0").update(target).digest("hex").slice(0, 12);
|
|
33555
33728
|
return `${PROPAGATION_BRANCH_PREFIX}${repoPart}-${targetPart}-${hash}`;
|
|
33556
33729
|
}
|
|
33557
33730
|
function legacyPropagationBranch(repo) {
|
|
@@ -34763,7 +34936,7 @@ function renderBootstrapVerifyReport(report) {
|
|
|
34763
34936
|
}
|
|
34764
34937
|
|
|
34765
34938
|
// src/bootstrap-seed-delivery.ts
|
|
34766
|
-
var
|
|
34939
|
+
var import_node_crypto13 = require("node:crypto");
|
|
34767
34940
|
init_github_client();
|
|
34768
34941
|
var SHA = /^[a-f0-9]{40}$/;
|
|
34769
34942
|
async function readSeedFile(repo, target, ref, client) {
|
|
@@ -34796,7 +34969,7 @@ async function targetedSeedPlan(repo, slug, target, baseBranch, sourceSha, clien
|
|
|
34796
34969
|
}
|
|
34797
34970
|
const baseSha = base?.object?.sha;
|
|
34798
34971
|
if (!baseSha || !SHA.test(baseSha) || !SHA.test(sourceSha)) throw new Error("bootstrap apply: seed identity is unreadable");
|
|
34799
|
-
const identity = (0,
|
|
34972
|
+
const identity = (0, import_node_crypto13.createHash)("sha256").update(JSON.stringify([repo.toLowerCase(), target, baseSha, sourceSha])).digest("hex").slice(0, 24);
|
|
34800
34973
|
const delivery = planSeedDelivery(rules, slug, baseBranch, `bootstrap-seed-${identity}`);
|
|
34801
34974
|
const scoped = forcePr && delivery.mode === "direct" ? { mode: "pr", ref: `bootstrap-seed-${identity}-${slug}`, branch: `bootstrap-seed-${identity}-${slug}`, reason: "registry gate render requires review" } : delivery;
|
|
34802
34975
|
return { ...scoped, baseSha, baseBranch };
|
|
@@ -34862,12 +35035,12 @@ async function verifyTargetedSeedPr(repo, number, plan, target, expected, client
|
|
|
34862
35035
|
// src/bootstrap-commands.ts
|
|
34863
35036
|
var execGitForSeedSource = async (args) => (await execFileP("git", args, { timeout: GIT_TIMEOUT_MS })).stdout;
|
|
34864
35037
|
async function gateRenderDiff(current, rendered) {
|
|
34865
|
-
const dir = (0,
|
|
34866
|
-
const before = (0,
|
|
34867
|
-
const after = (0,
|
|
35038
|
+
const dir = (0, import_node_fs30.mkdtempSync)((0, import_node_path29.join)((0, import_node_os18.tmpdir)(), "mmi-gate-diff-"));
|
|
35039
|
+
const before = (0, import_node_path29.join)(dir, "committed-gate.yml");
|
|
35040
|
+
const after = (0, import_node_path29.join)(dir, "registry-render.yml");
|
|
34868
35041
|
try {
|
|
34869
|
-
(0,
|
|
34870
|
-
(0,
|
|
35042
|
+
(0, import_node_fs30.writeFileSync)(before, current);
|
|
35043
|
+
(0, import_node_fs30.writeFileSync)(after, rendered);
|
|
34871
35044
|
try {
|
|
34872
35045
|
return (await execFileP("git", ["diff", "--no-index", "--", before, after], { timeout: GIT_TIMEOUT_MS })).stdout;
|
|
34873
35046
|
} catch (e) {
|
|
@@ -34876,7 +35049,7 @@ async function gateRenderDiff(current, rendered) {
|
|
|
34876
35049
|
throw e;
|
|
34877
35050
|
}
|
|
34878
35051
|
} finally {
|
|
34879
|
-
(0,
|
|
35052
|
+
(0, import_node_fs30.rmSync)(dir, { recursive: true, force: true });
|
|
34880
35053
|
}
|
|
34881
35054
|
}
|
|
34882
35055
|
function bootstrapTrainDoctorDeps() {
|
|
@@ -34936,13 +35109,13 @@ function registerBootstrapCommands(program3) {
|
|
|
34936
35109
|
})),
|
|
34937
35110
|
pushAllowlistOwners: verifyOwners,
|
|
34938
35111
|
pushAllowlistOwnersRead: verifyOwnersRead,
|
|
34939
|
-
readLocalFile: (path2) => path2 === "projects.json" && apiProjects != null ? apiProjects : (0,
|
|
35112
|
+
readLocalFile: (path2) => path2 === "projects.json" && apiProjects != null ? apiProjects : (0, import_node_fs30.existsSync)(path2) ? (0, import_node_fs30.readFileSync)(path2, "utf8") : null,
|
|
34940
35113
|
// requiredGcpApis is stored as an array by a JSON write, but `org project set --var KEY=VALUE` stores a raw
|
|
34941
35114
|
// comma-string — accept either so the seeded value verifies regardless of how it was written.
|
|
34942
35115
|
// #3689: the same committed map the org access audit reads (#3664), so a sanctioned admin is not a
|
|
34943
35116
|
// permanent bootstrap failure on one surface and an intended state on the other. Absent file → no
|
|
34944
35117
|
// sanction, which is the pre-#3664 behaviour.
|
|
34945
|
-
sanctionedAdmins: (0,
|
|
35118
|
+
sanctionedAdmins: (0, import_node_fs30.existsSync)("access-matrix.json") ? entriesValueByCanonicalRepo(loadSanctionedAdmins((0, import_node_fs30.readFileSync)("access-matrix.json", "utf8")), repo) : void 0,
|
|
34946
35119
|
requiredGcpApis: (() => {
|
|
34947
35120
|
const v = meta?.requiredGcpApis;
|
|
34948
35121
|
if (Array.isArray(v)) return v;
|
|
@@ -35020,14 +35193,14 @@ function registerBootstrapCommands(program3) {
|
|
|
35020
35193
|
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 () => {
|
|
35021
35194
|
const o = { repo: rawValue("--repo", ""), json: rawFlag("--json") };
|
|
35022
35195
|
const manifestPath = "skills/bootstrap/seeds/manifest.json";
|
|
35023
|
-
if (!(0,
|
|
35196
|
+
if (!(0, import_node_fs30.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`);
|
|
35024
35197
|
const seedSource = await resolveHubSeedSource(execGitForSeedSource);
|
|
35025
35198
|
if (!seedSource.ok) return fail(`bootstrap drift: ${seedSource.reason}`);
|
|
35026
|
-
const manifest = loadBootstrapSeeds((0,
|
|
35199
|
+
const manifest = loadBootstrapSeeds((0, import_node_fs30.readFileSync)(manifestPath, "utf8"));
|
|
35027
35200
|
const hubContents = /* @__PURE__ */ new Map();
|
|
35028
35201
|
for (const s of manifest.seeds) {
|
|
35029
35202
|
if (s.ownership !== "org" || s.source !== "self") continue;
|
|
35030
|
-
hubContents.set(s.target, (0,
|
|
35203
|
+
hubContents.set(s.target, (0, import_node_fs30.existsSync)(s.target) ? (0, import_node_fs30.readFileSync)(s.target, "utf8") : null);
|
|
35031
35204
|
}
|
|
35032
35205
|
let targets;
|
|
35033
35206
|
let classOf = (_repo) => "deployable";
|
|
@@ -35235,24 +35408,24 @@ function registerBootstrapCommands(program3) {
|
|
|
35235
35408
|
return;
|
|
35236
35409
|
}
|
|
35237
35410
|
const manifestPath = "skills/bootstrap/seeds/manifest.json";
|
|
35238
|
-
if (!(0,
|
|
35411
|
+
if (!(0, import_node_fs30.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`);
|
|
35239
35412
|
const seedSource = await resolveHubSeedSource(execGitForSeedSource);
|
|
35240
35413
|
if (!seedSource.ok) return fail(`bootstrap apply: ${seedSource.reason}`);
|
|
35241
|
-
const manifest = loadBootstrapSeeds((0,
|
|
35414
|
+
const manifest = loadBootstrapSeeds((0, import_node_fs30.readFileSync)(manifestPath, "utf8"));
|
|
35242
35415
|
const baseBranch = o.class === "content" ? "main" : "development";
|
|
35243
35416
|
const slug = parsedRepo.slug;
|
|
35244
35417
|
const onlyTarget = o.fromConfig && o.only.trim() === "gate.yml" ? ".github/workflows/gate.yml" : o.only.trim();
|
|
35245
35418
|
const gh2 = async (args) => execFileP("gh", args, { timeout: 2e4 });
|
|
35246
|
-
const readFile10 = (p) => (0,
|
|
35419
|
+
const readFile10 = (p) => (0, import_node_fs30.existsSync)(p) ? (0, import_node_fs30.readFileSync)(p, "utf8") : null;
|
|
35247
35420
|
const enc = (p) => p.split("/").map(encodeURIComponent).join("/");
|
|
35248
35421
|
const putSeed = async (target, content, ref, sha) => {
|
|
35249
|
-
const tmp = (0,
|
|
35250
|
-
(0,
|
|
35422
|
+
const tmp = (0, import_node_path29.join)((0, import_node_os18.tmpdir)(), `mmi-seed-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
|
|
35423
|
+
(0, import_node_fs30.writeFileSync)(tmp, JSON.stringify(contentPutBody(target, content, ref, sha)), "utf8");
|
|
35251
35424
|
try {
|
|
35252
35425
|
await gh2(contentPutInputArgs(repo, target, tmp));
|
|
35253
35426
|
} finally {
|
|
35254
35427
|
try {
|
|
35255
|
-
(0,
|
|
35428
|
+
(0, import_node_fs30.unlinkSync)(tmp);
|
|
35256
35429
|
} catch {
|
|
35257
35430
|
}
|
|
35258
35431
|
}
|
|
@@ -35888,10 +36061,10 @@ LIVE apply to ${repo}:
|
|
|
35888
36061
|
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 () => {
|
|
35889
36062
|
const o = { target: rawValue("--target", ""), execute: rawFlag("--execute"), json: rawFlag("--json") };
|
|
35890
36063
|
const manifestPath = "skills/bootstrap/seeds/manifest.json";
|
|
35891
|
-
if (!(0,
|
|
36064
|
+
if (!(0, import_node_fs30.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`);
|
|
35892
36065
|
const seedSource = await resolveHubSeedSource(execGitForSeedSource);
|
|
35893
36066
|
if (!seedSource.ok) return fail(`bootstrap propagate: ${seedSource.reason}`);
|
|
35894
|
-
const manifest = loadBootstrapSeeds((0,
|
|
36067
|
+
const manifest = loadBootstrapSeeds((0, import_node_fs30.readFileSync)(manifestPath, "utf8"));
|
|
35895
36068
|
const propagatable = manifest.seeds.filter(isPropagatableSeed);
|
|
35896
36069
|
if (!o.target) {
|
|
35897
36070
|
return fail(`bootstrap propagate: --target <path> is required \u2014 one of:
|
|
@@ -35900,9 +36073,9 @@ LIVE apply to ${repo}:
|
|
|
35900
36073
|
const seed = propagatable.find((s) => s.target === o.target);
|
|
35901
36074
|
if (!seed) return fail(`bootstrap propagate: --target '${o.target}' names no centrally propagatable seed in ${manifestPath}. Propagatable targets:
|
|
35902
36075
|
${propagatable.map((s) => s.target).join("\n ")}`);
|
|
35903
|
-
if (!seed.managedBlock && !(0,
|
|
35904
|
-
const hubContent = seed.managedBlock ? null : (0,
|
|
35905
|
-
const readSeedFile2 = (path2) => (0,
|
|
36076
|
+
if (!seed.managedBlock && !(0, import_node_fs30.existsSync)(seed.target)) return fail(`bootstrap propagate: the Hub's own copy of '${seed.target}' is missing \u2014 nothing to propagate`);
|
|
36077
|
+
const hubContent = seed.managedBlock ? null : (0, import_node_fs30.readFileSync)(seed.target, "utf8");
|
|
36078
|
+
const readSeedFile2 = (path2) => (0, import_node_fs30.existsSync)(path2) ? (0, import_node_fs30.readFileSync)(path2, "utf8") : null;
|
|
35906
36079
|
const isWorkflowSeed = seed.target.startsWith(".github/workflows/");
|
|
35907
36080
|
const cfg = await loadConfig();
|
|
35908
36081
|
const projects = await fetchProjectsList(registryClientDeps(cfg));
|
|
@@ -35911,9 +36084,9 @@ LIVE apply to ${repo}:
|
|
|
35911
36084
|
}
|
|
35912
36085
|
const rosterRepos = collectRegistryRepos(projects).filter((r) => r.toLowerCase() !== "mutmutco/mmi-hub");
|
|
35913
36086
|
let independentCount = rosterRepos.length;
|
|
35914
|
-
if ((0,
|
|
36087
|
+
if ((0, import_node_fs30.existsSync)("projects.json")) {
|
|
35915
36088
|
try {
|
|
35916
|
-
const local = JSON.parse((0,
|
|
36089
|
+
const local = JSON.parse((0, import_node_fs30.readFileSync)("projects.json", "utf8"));
|
|
35917
36090
|
const localRepos = /* @__PURE__ */ new Set();
|
|
35918
36091
|
for (const p of local.projects ?? []) for (const r of p.repos ?? []) {
|
|
35919
36092
|
const full = (r.includes("/") ? r : `mutmutco/${r}`).toLowerCase();
|
|
@@ -36083,15 +36256,15 @@ LIVE apply to ${repo}:
|
|
|
36083
36256
|
} catch {
|
|
36084
36257
|
existingSha = void 0;
|
|
36085
36258
|
}
|
|
36086
|
-
const tmp = (0,
|
|
36259
|
+
const tmp = (0, import_node_path29.join)((0, import_node_os18.tmpdir)(), `mmi-propagate-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
|
|
36087
36260
|
const desiredContent = desiredByRepo.get(rec.repo);
|
|
36088
36261
|
if (desiredContent == null) return fail(`bootstrap propagate: no resolved content for ${rec.repo} ${seed.target} \u2014 refusing to write`);
|
|
36089
|
-
(0,
|
|
36262
|
+
(0, import_node_fs30.writeFileSync)(tmp, JSON.stringify(contentPutBody(seed.target, desiredContent, branch, existingSha)), "utf8");
|
|
36090
36263
|
try {
|
|
36091
36264
|
await gh2(contentPutInputArgs(rec.repo, seed.target, tmp));
|
|
36092
36265
|
} finally {
|
|
36093
36266
|
try {
|
|
36094
|
-
(0,
|
|
36267
|
+
(0, import_node_fs30.unlinkSync)(tmp);
|
|
36095
36268
|
} catch {
|
|
36096
36269
|
}
|
|
36097
36270
|
}
|
|
@@ -36160,10 +36333,10 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
|
|
|
36160
36333
|
return fail(`bootstrap rollback: ${e.message}`);
|
|
36161
36334
|
}
|
|
36162
36335
|
const manifestPath = "skills/bootstrap/seeds/manifest.json";
|
|
36163
|
-
if (!(0,
|
|
36336
|
+
if (!(0, import_node_fs30.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)`);
|
|
36164
36337
|
const seedSource = await resolveHubSeedSource(execGitForSeedSource);
|
|
36165
36338
|
if (!seedSource.ok) return fail(`bootstrap rollback: ${seedSource.reason}`);
|
|
36166
|
-
const manifest = loadBootstrapSeeds((0,
|
|
36339
|
+
const manifest = loadBootstrapSeeds((0, import_node_fs30.readFileSync)(manifestPath, "utf8"));
|
|
36167
36340
|
const propagatable = manifest.seeds.filter(isPropagatableSeed);
|
|
36168
36341
|
if (!o.target) {
|
|
36169
36342
|
return fail(`bootstrap rollback: --target <path> is required \u2014 one of:
|
|
@@ -36180,10 +36353,10 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
|
|
|
36180
36353
|
const enc = (p) => p.split("/").map(encodeURIComponent).join("/");
|
|
36181
36354
|
let candidates;
|
|
36182
36355
|
if (o.record) {
|
|
36183
|
-
if (!(0,
|
|
36356
|
+
if (!(0, import_node_fs30.existsSync)(o.record)) return fail(`bootstrap rollback: --record '${o.record}' not found`);
|
|
36184
36357
|
let parsed;
|
|
36185
36358
|
try {
|
|
36186
|
-
parsed = JSON.parse((0,
|
|
36359
|
+
parsed = JSON.parse((0, import_node_fs30.readFileSync)(o.record, "utf8"));
|
|
36187
36360
|
} catch (e) {
|
|
36188
36361
|
return fail(`bootstrap rollback: --record '${o.record}' is not valid JSON: ${e.message}`);
|
|
36189
36362
|
}
|
|
@@ -36260,13 +36433,13 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
|
|
|
36260
36433
|
} catch {
|
|
36261
36434
|
existingSha = void 0;
|
|
36262
36435
|
}
|
|
36263
|
-
const tmp = (0,
|
|
36264
|
-
(0,
|
|
36436
|
+
const tmp = (0, import_node_path29.join)((0, import_node_os18.tmpdir)(), `mmi-rollback-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
|
|
36437
|
+
(0, import_node_fs30.writeFileSync)(tmp, JSON.stringify(contentPutBody(seed.target, preSeedContent, plan.branch, existingSha)), "utf8");
|
|
36265
36438
|
try {
|
|
36266
36439
|
await gh2(contentPutInputArgs(repo, seed.target, tmp));
|
|
36267
36440
|
} finally {
|
|
36268
36441
|
try {
|
|
36269
|
-
(0,
|
|
36442
|
+
(0, import_node_fs30.unlinkSync)(tmp);
|
|
36270
36443
|
} catch {
|
|
36271
36444
|
}
|
|
36272
36445
|
}
|
|
@@ -36442,7 +36615,7 @@ init_github_client();
|
|
|
36442
36615
|
init_cli_shared();
|
|
36443
36616
|
|
|
36444
36617
|
// src/suite-status.ts
|
|
36445
|
-
var
|
|
36618
|
+
var import_node_crypto14 = require("node:crypto");
|
|
36446
36619
|
var SUITE_REPO = "mutmutco/MM-Work";
|
|
36447
36620
|
var REPOS = {
|
|
36448
36621
|
"mmi-scout": "mutmutco/MMI-Scout",
|
|
@@ -36470,7 +36643,7 @@ function parseSuiteMapping(body) {
|
|
|
36470
36643
|
return void 0;
|
|
36471
36644
|
}
|
|
36472
36645
|
}
|
|
36473
|
-
var sha256 = (b) => (0,
|
|
36646
|
+
var sha256 = (b) => (0, import_node_crypto14.createHash)("sha256").update(b).digest("hex");
|
|
36474
36647
|
async function proveBundle(url, tag, fetchUrl) {
|
|
36475
36648
|
const get = async (u) => {
|
|
36476
36649
|
try {
|
|
@@ -36723,9 +36896,9 @@ async function waitSuiteDev(deps, opts) {
|
|
|
36723
36896
|
}
|
|
36724
36897
|
|
|
36725
36898
|
// src/suite-train.ts
|
|
36726
|
-
var
|
|
36727
|
-
var
|
|
36728
|
-
var
|
|
36899
|
+
var import_node_fs31 = require("node:fs");
|
|
36900
|
+
var import_node_path30 = require("node:path");
|
|
36901
|
+
var import_node_crypto15 = require("node:crypto");
|
|
36729
36902
|
|
|
36730
36903
|
// src/kit-version.ts
|
|
36731
36904
|
var parse = (v) => /^(\d+)\.(\d+)\.(\d+)(-.+)?$/.exec(typeof v === "string" ? v.trim() : "");
|
|
@@ -36810,7 +36983,7 @@ function suiteReleaseTag(rc) {
|
|
|
36810
36983
|
function readSuiteCut(path2) {
|
|
36811
36984
|
let raw;
|
|
36812
36985
|
try {
|
|
36813
|
-
raw = (0,
|
|
36986
|
+
raw = (0, import_node_fs31.readFileSync)(path2, "utf8");
|
|
36814
36987
|
} catch (e) {
|
|
36815
36988
|
if (e.code === "ENOENT") return void 0;
|
|
36816
36989
|
throw e;
|
|
@@ -36826,11 +36999,11 @@ function readSuiteCut(path2) {
|
|
|
36826
36999
|
return record;
|
|
36827
37000
|
}
|
|
36828
37001
|
function writeSuiteCut(path2, record) {
|
|
36829
|
-
(0,
|
|
36830
|
-
const temp = `${path2}.${(0,
|
|
37002
|
+
(0, import_node_fs31.mkdirSync)((0, import_node_path30.dirname)(path2), { recursive: true });
|
|
37003
|
+
const temp = `${path2}.${(0, import_node_crypto15.randomBytes)(8).toString("hex")}.tmp`;
|
|
36831
37004
|
try {
|
|
36832
|
-
(0,
|
|
36833
|
-
(0,
|
|
37005
|
+
(0, import_node_fs31.writeFileSync)(temp, JSON.stringify(record, null, 2), { flag: "wx" });
|
|
37006
|
+
(0, import_node_fs31.renameSync)(temp, path2);
|
|
36834
37007
|
} catch (e) {
|
|
36835
37008
|
throw new Error(`suite cut record write failed at ${path2}: ${e.message}; stop, verify the file before retrying`);
|
|
36836
37009
|
}
|
|
@@ -36879,25 +37052,25 @@ async function suiteMarkAbandoned(deps, ownerGo = false) {
|
|
|
36879
37052
|
return tags.map((t) => `${t.repo}@${t.tag}`);
|
|
36880
37053
|
}
|
|
36881
37054
|
async function retireFailedLeadRcLedger(deps, ownerGo) {
|
|
36882
|
-
if (!(0,
|
|
37055
|
+
if (!(0, import_node_fs31.existsSync)(deps.ledgerPath)) return void 0;
|
|
36883
37056
|
return withLedgerLock(deps.ledgerPath, async (fence) => {
|
|
36884
|
-
const ledger = parseReleaseLedger((0,
|
|
37057
|
+
const ledger = parseReleaseLedger((0, import_node_fs31.readFileSync)(deps.ledgerPath, "utf8"));
|
|
36885
37058
|
const states = Object.values(ledger.phases).map((p) => p.state);
|
|
36886
37059
|
if (ledger.repo !== SUITE_REPO || ledger.lane !== "rcand" || ledger.phases.promotion.state === "complete" || !states.includes("failed")) return void 0;
|
|
36887
37060
|
if (!ownerGo) throw new Error(`the lead's failed rcand ledger for ${ledger.tag} blocks every train; retire it with suite abandon --owner-go`);
|
|
36888
37061
|
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`);
|
|
36889
|
-
const archive = (0,
|
|
36890
|
-
if ((0,
|
|
37062
|
+
const archive = (0, import_node_path30.join)((0, import_node_path30.dirname)(deps.ledgerPath), `phases.archive-${ledger.tag}.json`);
|
|
37063
|
+
if ((0, import_node_fs31.existsSync)(archive)) throw new Error(`ledger archive already exists at ${archive}; inspect before retiring again`);
|
|
36891
37064
|
await deps.markAbandoned(SUITE_REPO, ledger.tag, ledger.tagSha);
|
|
36892
|
-
await fence(() => (0,
|
|
37065
|
+
await fence(() => (0, import_node_fs31.renameSync)(deps.ledgerPath, archive));
|
|
36893
37066
|
return `${ledger.tag} (ledger archived to ${archive})`;
|
|
36894
37067
|
});
|
|
36895
37068
|
}
|
|
36896
37069
|
function suiteAbandon(recordPath, ownerGo = false, now = /* @__PURE__ */ new Date()) {
|
|
36897
37070
|
const record = abandonableCut(recordPath, ownerGo);
|
|
36898
37071
|
const archive = `${recordPath}.abandoned-${record.leadDevelopment.slice(0, 12)}-${now.toISOString().replace(/[:.]/g, "")}.json`;
|
|
36899
|
-
if ((0,
|
|
36900
|
-
(0,
|
|
37072
|
+
if ((0, import_node_fs31.existsSync)(archive)) throw new Error(`abandoned-cut archive already exists at ${archive}; inspect before abandoning again`);
|
|
37073
|
+
(0, import_node_fs31.renameSync)(recordPath, archive);
|
|
36901
37074
|
return { archive, orphanTags: record.members.filter((m) => m.tag).map((m) => `${m.repo}@${m.tag}`) };
|
|
36902
37075
|
}
|
|
36903
37076
|
async function suiteRestoreMainPins(deps) {
|
|
@@ -36963,12 +37136,12 @@ async function suiteRcand(deps, opts) {
|
|
|
36963
37136
|
}
|
|
36964
37137
|
if ((record?.announcement === "sent" || record?.announcement === "skipped") && record.leadReleased) {
|
|
36965
37138
|
const archive = `${deps.recordPath}.${record.leadRcTag}.json`;
|
|
36966
|
-
if ((0,
|
|
36967
|
-
(0,
|
|
37139
|
+
if ((0, import_node_fs31.existsSync)(archive)) throw new Error(`suite cut archive already exists at ${archive}; inspect before a new cut`);
|
|
37140
|
+
(0, import_node_fs31.renameSync)(deps.recordPath, archive);
|
|
36968
37141
|
record = void 0;
|
|
36969
37142
|
}
|
|
36970
37143
|
if (record && !record.pinPr && !record.leadRcTag && record.members.every((m) => !m.tag)) {
|
|
36971
|
-
(0,
|
|
37144
|
+
(0, import_node_fs31.rmSync)(deps.recordPath, { force: true });
|
|
36972
37145
|
record = void 0;
|
|
36973
37146
|
}
|
|
36974
37147
|
if (!record) {
|
|
@@ -37022,7 +37195,7 @@ async function suiteRcand(deps, opts) {
|
|
|
37022
37195
|
quiet.push(member);
|
|
37023
37196
|
}
|
|
37024
37197
|
if (record.members.every((m) => m.carried || quiet.includes(m)) && await deps.contains(SUITE_REPO, record.leadDevelopment, record.leadPreviousRc)) {
|
|
37025
|
-
(0,
|
|
37198
|
+
(0, import_node_fs31.rmSync)(deps.recordPath, { force: true });
|
|
37026
37199
|
throw new Error("nothing to promote: neither MM-Work nor any module has new development commits since its rc; no suite cut started");
|
|
37027
37200
|
}
|
|
37028
37201
|
for (const member of quiet) {
|
|
@@ -37040,7 +37213,7 @@ async function suiteRcand(deps, opts) {
|
|
|
37040
37213
|
}
|
|
37041
37214
|
if (refusals.length) {
|
|
37042
37215
|
const untouched = record.members.every((m) => !m.tag) && !record.pinPr;
|
|
37043
|
-
if (untouched) (0,
|
|
37216
|
+
if (untouched) (0, import_node_fs31.rmSync)(deps.recordPath, { force: true });
|
|
37044
37217
|
throw new Error(`module rc serving is not ready; ${untouched ? "no suite cut started" : "no new tag was cut"}:
|
|
37045
37218
|
${refusals.join("\n")}
|
|
37046
37219
|
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).`);
|
|
@@ -37197,11 +37370,11 @@ Each member's live release must serve <data>/main/module.js at its main pin path
|
|
|
37197
37370
|
}
|
|
37198
37371
|
return record;
|
|
37199
37372
|
}
|
|
37200
|
-
var hotfixRecordPath = (deps) => (0,
|
|
37373
|
+
var hotfixRecordPath = (deps) => (0, import_node_path30.join)((0, import_node_path30.dirname)(deps.recordPath), "hotfix.json");
|
|
37201
37374
|
function readSuiteHotfix(path2) {
|
|
37202
37375
|
let raw;
|
|
37203
37376
|
try {
|
|
37204
|
-
raw = (0,
|
|
37377
|
+
raw = (0, import_node_fs31.readFileSync)(path2, "utf8");
|
|
37205
37378
|
} catch (e) {
|
|
37206
37379
|
if (e.code === "ENOENT") return void 0;
|
|
37207
37380
|
throw e;
|
|
@@ -37244,7 +37417,7 @@ async function suiteHotfix(deps, opts) {
|
|
|
37244
37417
|
if (completed) record = void 0;
|
|
37245
37418
|
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`);
|
|
37246
37419
|
if (!record?.tag) await deps.validateHotfixSummary();
|
|
37247
|
-
if (completed) (0,
|
|
37420
|
+
if (completed) (0, import_node_fs31.renameSync)(path2, `${path2}.${completed.leadTag}.json`);
|
|
37248
37421
|
const rec = record ?? { schema: "mmi-suite-hotfix/v1", member: found.id, repo: found.repo, from: opts.from, ...opts.ack?.length ? { ack: opts.ack } : {} };
|
|
37249
37422
|
const save = () => writeSuiteHotfix(path2, rec);
|
|
37250
37423
|
save();
|
|
@@ -37511,8 +37684,8 @@ async function runRcDataSwitch(deps, opts) {
|
|
|
37511
37684
|
}
|
|
37512
37685
|
|
|
37513
37686
|
// src/suite-train-io.ts
|
|
37514
|
-
var
|
|
37515
|
-
var
|
|
37687
|
+
var import_node_fs45 = require("node:fs");
|
|
37688
|
+
var import_node_path44 = require("node:path");
|
|
37516
37689
|
init_cli_shared();
|
|
37517
37690
|
|
|
37518
37691
|
// src/command-register-train-operations.ts
|
|
@@ -37867,8 +38040,8 @@ async function preflightHotfixBatchPicks(deps, sources, pickTolerated) {
|
|
|
37867
38040
|
if (sources.length === 0) return { failures: [], skipped: [] };
|
|
37868
38041
|
const { mkdtemp: mkdtemp2, rm: rm2 } = await import("node:fs/promises");
|
|
37869
38042
|
const { tmpdir: tmpdir12 } = await import("node:os");
|
|
37870
|
-
const { join:
|
|
37871
|
-
const dir = await mkdtemp2(
|
|
38043
|
+
const { join: join48 } = await import("node:path");
|
|
38044
|
+
const dir = await mkdtemp2(join48(tmpdir12(), "mmi-hotfix-preflight-"));
|
|
37872
38045
|
const wt = { run: (file, args) => deps.run(file, file === "git" ? ["-C", dir, ...args] : args) };
|
|
37873
38046
|
const failures = [];
|
|
37874
38047
|
const skipped = [];
|
|
@@ -39189,9 +39362,9 @@ function checkHotfixCarries(options) {
|
|
|
39189
39362
|
}
|
|
39190
39363
|
|
|
39191
39364
|
// src/merge-cleanup.ts
|
|
39192
|
-
var
|
|
39193
|
-
var
|
|
39194
|
-
var
|
|
39365
|
+
var import_node_fs33 = require("node:fs");
|
|
39366
|
+
var import_node_path32 = require("node:path");
|
|
39367
|
+
var import_node_os19 = require("node:os");
|
|
39195
39368
|
init_cli_shared();
|
|
39196
39369
|
init_github_client();
|
|
39197
39370
|
|
|
@@ -39505,8 +39678,8 @@ async function runPrLand(prNumber, options, deps) {
|
|
|
39505
39678
|
|
|
39506
39679
|
// src/test-policy-core.ts
|
|
39507
39680
|
var import_node_child_process13 = require("node:child_process");
|
|
39508
|
-
var
|
|
39509
|
-
var
|
|
39681
|
+
var import_node_fs32 = require("node:fs");
|
|
39682
|
+
var import_node_path31 = require("node:path");
|
|
39510
39683
|
|
|
39511
39684
|
// src/test-command-policy-shared.mjs
|
|
39512
39685
|
var import_node_child_process12 = require("node:child_process");
|
|
@@ -39982,7 +40155,7 @@ function isMeaningfulRow(file) {
|
|
|
39982
40155
|
return file.meaningful !== false;
|
|
39983
40156
|
}
|
|
39984
40157
|
function loadPolicy(root, readFile10 = readFileOrNull2) {
|
|
39985
|
-
const raw = readFile10((0,
|
|
40158
|
+
const raw = readFile10((0, import_node_path31.join)(root, POLICY_FILE));
|
|
39986
40159
|
if (raw == null) return { mandatory: [], declared: false };
|
|
39987
40160
|
return parsePolicy(raw, POLICY_FILE);
|
|
39988
40161
|
}
|
|
@@ -40059,7 +40232,7 @@ function loadPolicySource(root, explicitRef, diffBase) {
|
|
|
40059
40232
|
}
|
|
40060
40233
|
function readFileOrNull2(path2) {
|
|
40061
40234
|
try {
|
|
40062
|
-
return (0,
|
|
40235
|
+
return (0, import_node_fs32.readFileSync)(path2, "utf8");
|
|
40063
40236
|
} catch {
|
|
40064
40237
|
return null;
|
|
40065
40238
|
}
|
|
@@ -40087,12 +40260,12 @@ function classify(changed, policy, present = () => false) {
|
|
|
40087
40260
|
const removedProtected = [...removed].filter((p) => protectedBy.has(p)).map((p) => ({ path: p, why: protectedBy.get(p) ?? "" }));
|
|
40088
40261
|
return { mandatoryHits, untestedHits, testChanges, meaningfulTestChanges, addedTests, removedProtected };
|
|
40089
40262
|
}
|
|
40090
|
-
function unresolvedProtectedEntries(policy, root, exists = (path2) => (0,
|
|
40091
|
-
return (policy.protected ?? []).map((p) => p.path).filter((p) => !exists((0,
|
|
40263
|
+
function unresolvedProtectedEntries(policy, root, exists = (path2) => (0, import_node_fs32.existsSync)(path2)) {
|
|
40264
|
+
return (policy.protected ?? []).map((p) => p.path).filter((p) => !exists((0, import_node_path31.join)(root, p)));
|
|
40092
40265
|
}
|
|
40093
|
-
function unresolvedSatisfiers(policy, root, exists = (path2) => (0,
|
|
40266
|
+
function unresolvedSatisfiers(policy, root, exists = (path2) => (0, import_node_fs32.existsSync)(path2)) {
|
|
40094
40267
|
const declared = (policy.mandatory ?? []).flatMap((m) => m.satisfiedBy ?? []);
|
|
40095
|
-
return [...new Set(declared)].filter((p) => !exists((0,
|
|
40268
|
+
return [...new Set(declared)].filter((p) => !exists((0, import_node_path31.join)(root, p)));
|
|
40096
40269
|
}
|
|
40097
40270
|
function evaluate(changed, policy, present = () => false) {
|
|
40098
40271
|
const { mandatoryHits, untestedHits, meaningfulTestChanges, addedTests, removedProtected } = classify(changed, policy, present);
|
|
@@ -40231,14 +40404,14 @@ function runTestPolicy(root, deps = {}) {
|
|
|
40231
40404
|
}
|
|
40232
40405
|
const loaded = deps.policy ? { policy: deps.policy, source: { ref: null, sha: null, path: POLICY_FILE } } : loadPolicySource(root, deps.policyRef, deps.base);
|
|
40233
40406
|
const { policy, source: policySource } = loaded;
|
|
40234
|
-
const exists = deps.exists ?? ((path2) => (0,
|
|
40407
|
+
const exists = deps.exists ?? ((path2) => (0, import_node_fs32.existsSync)(path2));
|
|
40235
40408
|
const counts = { mandatoryCount: (policy.mandatory ?? []).length, protectedCount: (policy.protected ?? []).length };
|
|
40236
40409
|
const base = deps.changed ? "(injected)" : deps.policyRef ? resolveHotfixBase(root) : resolveBase(root, deps.base);
|
|
40237
40410
|
const refusal = deps.changed ? null : untrustworthyRange(root, base);
|
|
40238
40411
|
const raw = deps.changed ?? (refusal ? [] : changedFilesSince(base, root));
|
|
40239
40412
|
const changed = deps.changed ? raw : annotateChangeMeaning(raw, policy, (path2) => ({
|
|
40240
40413
|
before: blobAt(base, path2, root),
|
|
40241
|
-
after: readFileOrNull2((0,
|
|
40414
|
+
after: readFileOrNull2((0, import_node_path31.join)(root, path2))
|
|
40242
40415
|
}));
|
|
40243
40416
|
const lookup = deps.override !== void 0 ? { override: deps.override, refusals: [] } : !deps.changed && !refusal ? readOverride2(base, root) : { override: null, refusals: [] };
|
|
40244
40417
|
const policyRefusals = policy.declared === false ? [{
|
|
@@ -40248,8 +40421,8 @@ function runTestPolicy(root, deps = {}) {
|
|
|
40248
40421
|
A gate with no policy cannot decide which test commands are required or permitted.
|
|
40249
40422
|
` + (deps.base === HOTFIX_DIFF_BASE ? ` Hotfix lane (--base ${HOTFIX_DIFF_BASE}): pass --policy-ref <exact-${HOTFIX_POLICY_REF}-commit> so the current policy is read from ${HOTFIX_POLICY_REF}.` : ` Restore ${POLICY_FILE} on this branch; the policy file belongs on every non-hotfix lane.`)
|
|
40250
40423
|
}] : [];
|
|
40251
|
-
const present = (path2) => exists((0,
|
|
40252
|
-
const policyTree = policySource.sha ? new Set(git2(["ls-tree", "-r", "-z", "--name-only", policySource.sha], root).split("\0").filter(Boolean).map((p) => (0,
|
|
40424
|
+
const present = (path2) => exists((0, import_node_path31.join)(root, path2));
|
|
40425
|
+
const policyTree = policySource.sha ? new Set(git2(["ls-tree", "-r", "-z", "--name-only", policySource.sha], root).split("\0").filter(Boolean).map((p) => (0, import_node_path31.join)(root, p))) : null;
|
|
40253
40426
|
const policyTreeExists = policyTree ? (abs) => policyTree.has(abs) : exists;
|
|
40254
40427
|
const where = policySource.sha ? `${policySource.ref}@${policySource.sha}` : "this worktree";
|
|
40255
40428
|
const removedByThisDiff = removedPaths(changed);
|
|
@@ -40529,13 +40702,13 @@ function resolveSquashMergeBodyText(commits, allowedClosing, cwd) {
|
|
|
40529
40702
|
return rewritten === base ? null : rewritten;
|
|
40530
40703
|
}
|
|
40531
40704
|
function writeSquashBodyFile(body) {
|
|
40532
|
-
const dir = (0,
|
|
40533
|
-
const path2 = (0,
|
|
40534
|
-
(0,
|
|
40705
|
+
const dir = (0, import_node_fs33.mkdtempSync)((0, import_node_path32.join)((0, import_node_os19.tmpdir)(), "mmi-squash-body-"));
|
|
40706
|
+
const path2 = (0, import_node_path32.join)(dir, "body.txt");
|
|
40707
|
+
(0, import_node_fs33.writeFileSync)(path2, body.endsWith("\n") ? body : `${body}
|
|
40535
40708
|
`, "utf8");
|
|
40536
40709
|
return { path: path2, cleanup: () => {
|
|
40537
40710
|
try {
|
|
40538
|
-
(0,
|
|
40711
|
+
(0, import_node_fs33.rmSync)(dir, { recursive: true, force: true });
|
|
40539
40712
|
} catch {
|
|
40540
40713
|
}
|
|
40541
40714
|
} };
|
|
@@ -40742,8 +40915,8 @@ async function deleteMergedRemoteBranch(options) {
|
|
|
40742
40915
|
}
|
|
40743
40916
|
|
|
40744
40917
|
// src/project-info-sync.ts
|
|
40745
|
-
var
|
|
40746
|
-
var
|
|
40918
|
+
var import_node_fs34 = require("node:fs");
|
|
40919
|
+
var import_node_path33 = require("node:path");
|
|
40747
40920
|
var UPDATE_PROJECT_INFO = `mutation($projectId: ID!, $shortDescription: String!, $readme: String!) {
|
|
40748
40921
|
updateProjectV2(input: { projectId: $projectId, shortDescription: $shortDescription, readme: $readme }) {
|
|
40749
40922
|
projectV2 { id }
|
|
@@ -40790,14 +40963,14 @@ function sharedName(entries, fallback) {
|
|
|
40790
40963
|
}
|
|
40791
40964
|
function buildProjectInfoSyncPlan(targetRepo2, project2, projects, repoRoot2) {
|
|
40792
40965
|
if (!project2.projectId) throw new Error(`org project sync-info: ${targetRepo2} registry META has no projectId`);
|
|
40793
|
-
const readmePath = (0,
|
|
40794
|
-
if (!(0,
|
|
40966
|
+
const readmePath = (0, import_node_path33.join)(repoRoot2, "README.md");
|
|
40967
|
+
if (!(0, import_node_fs34.existsSync)(readmePath)) throw new Error(`org project sync-info: ${targetRepo2} has no README.md`);
|
|
40795
40968
|
const entries = entriesFor(project2, projects);
|
|
40796
40969
|
const memberRepos = [...new Set(entries.flatMap((entry) => entry.repos ?? []))].filter((repo) => /^[^/]+\/[^/]+$/.test(repo)).sort((a, b) => a.localeCompare(b));
|
|
40797
40970
|
const projectName = sharedName(entries, project2.name?.trim() || targetRepo2.split("/").pop() || targetRepo2);
|
|
40798
40971
|
if (!memberRepos.length) throw new Error(`org project sync-info: project ${projectName} has no registered member repos`);
|
|
40799
40972
|
const entryNames = entries.map((entry) => entry.name?.trim()).filter((name) => Boolean(name));
|
|
40800
|
-
const shortDescription = memberRepos.length === 1 ? shortDescriptionFromReadme((0,
|
|
40973
|
+
const shortDescription = memberRepos.length === 1 ? shortDescriptionFromReadme((0, import_node_fs34.readFileSync)(readmePath, "utf8")) : `Shared work across ${new Intl.ListFormat("en", { type: "conjunction" }).format(entryNames)}.`;
|
|
40801
40974
|
const lines2 = [
|
|
40802
40975
|
`# ${projectName}`,
|
|
40803
40976
|
"",
|
|
@@ -40816,8 +40989,8 @@ function buildProjectInfoSyncPlan(targetRepo2, project2, projects, repoRoot2) {
|
|
|
40816
40989
|
const targetBase = `https://github.com/${targetRepo2}`;
|
|
40817
40990
|
const targetBranch = branchFor(targetRepo2, projects);
|
|
40818
40991
|
const orgDocs = [
|
|
40819
|
-
(0,
|
|
40820
|
-
(0,
|
|
40992
|
+
(0, import_node_fs34.existsSync)((0, import_node_path33.join)(repoRoot2, "architecture.md")) ? `- [Hub architecture](${targetBase}/blob/${targetBranch}/architecture.md)` : "",
|
|
40993
|
+
(0, import_node_fs34.existsSync)((0, import_node_path33.join)(repoRoot2, "docs", "Architecture", "agentic-dev-environment.md")) ? `- [Agentic development environment](${targetBase}/blob/${targetBranch}/docs/Architecture/agentic-dev-environment.md)` : ""
|
|
40821
40994
|
].filter(Boolean);
|
|
40822
40995
|
if (orgDocs.length) lines2.push("", "## Organisation docs", "", ...orgDocs);
|
|
40823
40996
|
return { projectId: project2.projectId, projectName, targetRepo: targetRepo2, memberRepos, shortDescription, readme: `${lines2.join("\n")}
|
|
@@ -40839,8 +41012,8 @@ async function syncProjectInfo(plan, client, apply) {
|
|
|
40839
41012
|
}
|
|
40840
41013
|
|
|
40841
41014
|
// src/train-commands.ts
|
|
40842
|
-
var
|
|
40843
|
-
var
|
|
41015
|
+
var import_node_fs35 = require("node:fs");
|
|
41016
|
+
var import_node_path34 = require("node:path");
|
|
40844
41017
|
init_cli_shared();
|
|
40845
41018
|
init_clean_exit();
|
|
40846
41019
|
init_client_version();
|
|
@@ -40855,7 +41028,7 @@ function resolveReleaseBumpIntent(raw) {
|
|
|
40855
41028
|
}
|
|
40856
41029
|
function readRepoVersion() {
|
|
40857
41030
|
try {
|
|
40858
|
-
return JSON.parse((0,
|
|
41031
|
+
return JSON.parse((0, import_node_fs35.readFileSync)((0, import_node_path34.join)(process.cwd(), ".claude-plugin", "plugin.json"), "utf8")).version || void 0;
|
|
40859
41032
|
} catch {
|
|
40860
41033
|
return void 0;
|
|
40861
41034
|
}
|
|
@@ -40966,7 +41139,7 @@ function releaseProgressVerdict(status, subject = "Release") {
|
|
|
40966
41139
|
|
|
40967
41140
|
// src/suite-pin.ts
|
|
40968
41141
|
var import_promises6 = require("node:fs/promises");
|
|
40969
|
-
var
|
|
41142
|
+
var import_node_path35 = require("node:path");
|
|
40970
41143
|
var SuitePinError = class _SuitePinError extends Error {
|
|
40971
41144
|
diagnostic;
|
|
40972
41145
|
constructor(repo, tag, error) {
|
|
@@ -41034,8 +41207,8 @@ async function openSuiteCutPinPr(deps, input) {
|
|
|
41034
41207
|
if (input.carriedOnly) return { status: "unchanged" };
|
|
41035
41208
|
throw new Error("pins already match without a merged cut PR \u2014 provenance unverified");
|
|
41036
41209
|
}
|
|
41037
|
-
await (0, import_promises6.mkdir)((0,
|
|
41038
|
-
scratch = await (0, import_promises6.mkdtemp)((0,
|
|
41210
|
+
await (0, import_promises6.mkdir)((0, import_node_path35.join)(deps.root, "tmp"), { recursive: true });
|
|
41211
|
+
scratch = await (0, import_promises6.mkdtemp)((0, import_node_path35.join)(deps.root, "tmp", "suite-pin-"));
|
|
41039
41212
|
const run = (file, args) => deps.run(file, args, scratch);
|
|
41040
41213
|
await run("git", ["clone", "--quiet", "--branch", prs.length ? branch : "development", "--single-branch", `https://github.com/${SUITE_REPO}.git`, "."]);
|
|
41041
41214
|
if (prs.length) {
|
|
@@ -41047,7 +41220,7 @@ async function openSuiteCutPinPr(deps, input) {
|
|
|
41047
41220
|
await run("git", ["switch", "-c", branch]);
|
|
41048
41221
|
}
|
|
41049
41222
|
for (const stage of ["rc", "main"]) {
|
|
41050
|
-
const path2 = (0,
|
|
41223
|
+
const path2 = (0, import_node_path35.join)(scratch, `${stage}-pins.json`);
|
|
41051
41224
|
await (0, import_promises6.writeFile)(path2, JSON.stringify(input.pins.map((p) => ({ module: p.module, url: p[stage] }))));
|
|
41052
41225
|
await run("node", ["scripts/pin-modules.mjs", "--stage", stage, "--pins", path2]);
|
|
41053
41226
|
}
|
|
@@ -41100,12 +41273,12 @@ async function openSuiteRestorePinPr(deps, input) {
|
|
|
41100
41273
|
}
|
|
41101
41274
|
});
|
|
41102
41275
|
if (!todo.length) return void 0;
|
|
41103
|
-
await (0, import_promises6.mkdir)((0,
|
|
41104
|
-
scratch = await (0, import_promises6.mkdtemp)((0,
|
|
41276
|
+
await (0, import_promises6.mkdir)((0, import_node_path35.join)(deps.root, "tmp"), { recursive: true });
|
|
41277
|
+
scratch = await (0, import_promises6.mkdtemp)((0, import_node_path35.join)(deps.root, "tmp", "suite-pin-"));
|
|
41105
41278
|
const run = (file, args) => deps.run(file, args, scratch);
|
|
41106
41279
|
await run("git", ["clone", "--quiet", "--branch", "development", "--single-branch", `https://github.com/${SUITE_REPO}.git`, "."]);
|
|
41107
41280
|
await run("git", ["switch", "-c", branch]);
|
|
41108
|
-
const path2 = (0,
|
|
41281
|
+
const path2 = (0, import_node_path35.join)(scratch, "main-pins.json");
|
|
41109
41282
|
await (0, import_promises6.writeFile)(path2, JSON.stringify(todo.map((p) => ({ module: p.module, url: p.prior }))));
|
|
41110
41283
|
await run("node", ["scripts/pin-modules.mjs", "--stage", "main", "--pins", path2]);
|
|
41111
41284
|
await run("git", ["add", "seed/modules.json"]);
|
|
@@ -41179,8 +41352,8 @@ async function openSuitePinPr(deps, input) {
|
|
|
41179
41352
|
if (newer.length) return { status: "superseded", pr: newer[0].url, url: pin };
|
|
41180
41353
|
const open2 = onBranch.find((p) => p.state === "OPEN");
|
|
41181
41354
|
if (open2 && tagOf(open2.title ?? "") === tag) return { status: "pending", pr: open2.url, url: pin };
|
|
41182
|
-
await (0, import_promises6.mkdir)((0,
|
|
41183
|
-
scratch = await (0, import_promises6.mkdtemp)((0,
|
|
41355
|
+
await (0, import_promises6.mkdir)((0, import_node_path35.join)(deps.root, "tmp"), { recursive: true });
|
|
41356
|
+
scratch = await (0, import_promises6.mkdtemp)((0, import_node_path35.join)(deps.root, "tmp", "suite-pin-"));
|
|
41184
41357
|
const run = (file, args) => deps.run(file, args, scratch);
|
|
41185
41358
|
await run("git", ["clone", "--quiet", "--branch", "development", "--single-branch", `https://github.com/${SUITE_REPO}.git`, "."]);
|
|
41186
41359
|
await run("git", ["switch", "-c", branch]);
|
|
@@ -41220,7 +41393,7 @@ async function openSuitePinPr(deps, input) {
|
|
|
41220
41393
|
|
|
41221
41394
|
// src/command-register-collaboration.ts
|
|
41222
41395
|
var import_node_child_process17 = require("node:child_process");
|
|
41223
|
-
var
|
|
41396
|
+
var import_node_fs44 = require("node:fs");
|
|
41224
41397
|
var import_promises8 = require("node:fs/promises");
|
|
41225
41398
|
init_clean_exit();
|
|
41226
41399
|
init_cli_shared();
|
|
@@ -41244,11 +41417,11 @@ function spawnDetachedSelf(args, deps, opts = {}) {
|
|
|
41244
41417
|
}
|
|
41245
41418
|
|
|
41246
41419
|
// src/command-register-collaboration.ts
|
|
41247
|
-
var
|
|
41420
|
+
var import_node_path43 = require("node:path");
|
|
41248
41421
|
init_house_map();
|
|
41249
41422
|
|
|
41250
41423
|
// src/issue-body.ts
|
|
41251
|
-
var
|
|
41424
|
+
var import_node_os20 = require("node:os");
|
|
41252
41425
|
init_error_codes();
|
|
41253
41426
|
var TextArgError = class extends Error {
|
|
41254
41427
|
constructor(message2, code, offendingFlag) {
|
|
@@ -41261,7 +41434,7 @@ var TextArgError = class extends Error {
|
|
|
41261
41434
|
offendingFlag;
|
|
41262
41435
|
};
|
|
41263
41436
|
function emptyStdinMessage(fileFlag) {
|
|
41264
|
-
if ((0,
|
|
41437
|
+
if ((0, import_node_os20.platform)() === "win32") {
|
|
41265
41438
|
return `${fileFlag} - read empty stdin (on Windows, ${fileFlag} - is unreliable through the npm .cmd shim \u2014 use ${fileFlag} <path>, or pipe to \`node cli/dist/index.cjs\` directly)`;
|
|
41266
41439
|
}
|
|
41267
41440
|
return `${fileFlag} - read empty stdin (nothing piped \u2014 pass a heredoc/pipe, or ${fileFlag} <path>)`;
|
|
@@ -41354,8 +41527,8 @@ init_github_client();
|
|
|
41354
41527
|
init_github_quota();
|
|
41355
41528
|
|
|
41356
41529
|
// src/issue-commands.ts
|
|
41357
|
-
var
|
|
41358
|
-
var
|
|
41530
|
+
var import_node_fs36 = require("node:fs");
|
|
41531
|
+
var import_node_crypto16 = require("node:crypto");
|
|
41359
41532
|
init_cli_shared();
|
|
41360
41533
|
init_clean_exit();
|
|
41361
41534
|
init_error_codes();
|
|
@@ -41547,7 +41720,7 @@ async function editIssue(client, options, deps = {}) {
|
|
|
41547
41720
|
const url = `https://github.com/${repo}/issues/${parsed.number}`;
|
|
41548
41721
|
const patch = {};
|
|
41549
41722
|
let bodyChanged = false;
|
|
41550
|
-
const textDeps = () => deps.textDeps ?? { readFile: (p, e) => Promise.resolve((0,
|
|
41723
|
+
const textDeps = () => deps.textDeps ?? { readFile: (p, e) => Promise.resolve((0, import_node_fs36.readFileSync)(p, e)), readStdin: () => Promise.resolve("") };
|
|
41551
41724
|
if (options.titleFile !== void 0) {
|
|
41552
41725
|
patch.title = await resolveIssueTitle({ title: options.title, titleFile: options.titleFile }, textDeps());
|
|
41553
41726
|
} else if (options.title !== void 0) {
|
|
@@ -41828,7 +42001,7 @@ function rowIdempotencyKey(batchKey, spec) {
|
|
|
41828
42001
|
const identity = `${spec.type}
|
|
41829
42002
|
${spec.title.trim()}
|
|
41830
42003
|
${spec.body ?? ""}`;
|
|
41831
|
-
const hash = (0,
|
|
42004
|
+
const hash = (0, import_node_crypto16.createHash)("sha256").update(identity).digest("hex").slice(0, 16);
|
|
41832
42005
|
return `${batchKey}:${hash}`;
|
|
41833
42006
|
}
|
|
41834
42007
|
var BATCH_SPEC_KEYS = /* @__PURE__ */ new Set(["type", "title", "body", "priority", "labels", "label", "parent", "repo", "surface"]);
|
|
@@ -42210,7 +42383,7 @@ function extendCreateCommand(issue, batchAttach) {
|
|
|
42210
42383
|
if (opts.batch) {
|
|
42211
42384
|
let specs;
|
|
42212
42385
|
try {
|
|
42213
|
-
const raw = (0,
|
|
42386
|
+
const raw = (0, import_node_fs36.readFileSync)(opts.batch, "utf8");
|
|
42214
42387
|
specs = JSON.parse(raw);
|
|
42215
42388
|
if (!Array.isArray(specs)) {
|
|
42216
42389
|
const top = specs === null ? "null" : typeof specs === "object" ? `an object with keys: ${Object.keys(specs).join(", ") || "(none)"}` : `a ${typeof specs}`;
|
|
@@ -42287,8 +42460,8 @@ ${lines2}`, {
|
|
|
42287
42460
|
}
|
|
42288
42461
|
|
|
42289
42462
|
// src/post-merge-recon.ts
|
|
42290
|
-
var
|
|
42291
|
-
var
|
|
42463
|
+
var import_node_fs37 = require("node:fs");
|
|
42464
|
+
var import_node_path36 = require("node:path");
|
|
42292
42465
|
|
|
42293
42466
|
// src/cross-repo-filing-issue.ts
|
|
42294
42467
|
init_github_client();
|
|
@@ -42457,16 +42630,16 @@ function buildPostMergeReconRecovery(input) {
|
|
|
42457
42630
|
}
|
|
42458
42631
|
function writePostMergeReconRecovery(cwd, recovery) {
|
|
42459
42632
|
const path2 = postMergeReconStatePath(cwd, recovery.repo, recovery.pr);
|
|
42460
|
-
(0,
|
|
42461
|
-
(0,
|
|
42633
|
+
(0, import_node_fs37.mkdirSync)((0, import_node_path36.dirname)(path2), { recursive: true });
|
|
42634
|
+
(0, import_node_fs37.writeFileSync)(path2, `${JSON.stringify(recovery, null, 2)}
|
|
42462
42635
|
`, "utf8");
|
|
42463
42636
|
return path2;
|
|
42464
42637
|
}
|
|
42465
42638
|
function clearPostMergeReconRecovery(cwd, repo, pr) {
|
|
42466
42639
|
const path2 = postMergeReconStatePath(cwd, repo, pr);
|
|
42467
|
-
if (!(0,
|
|
42640
|
+
if (!(0, import_node_fs37.existsSync)(path2)) return;
|
|
42468
42641
|
try {
|
|
42469
|
-
(0,
|
|
42642
|
+
(0, import_node_fs37.unlinkSync)(path2);
|
|
42470
42643
|
} catch {
|
|
42471
42644
|
}
|
|
42472
42645
|
}
|
|
@@ -42942,9 +43115,9 @@ function registerPrLifecycleCommands(program3) {
|
|
|
42942
43115
|
|
|
42943
43116
|
// src/review-verdict.ts
|
|
42944
43117
|
var import_node_child_process14 = require("node:child_process");
|
|
42945
|
-
var
|
|
42946
|
-
var
|
|
42947
|
-
var
|
|
43118
|
+
var import_node_fs38 = require("node:fs");
|
|
43119
|
+
var import_node_os21 = require("node:os");
|
|
43120
|
+
var import_node_path37 = require("node:path");
|
|
42948
43121
|
init_cli_shared();
|
|
42949
43122
|
var REVIEW_VERDICT_MARKER = "<!-- zeroci-review v1 -->";
|
|
42950
43123
|
var REVIEW_VERDICTS = ["PROCEED", "CORRECT", "ESCALATE"];
|
|
@@ -43109,15 +43282,15 @@ async function readPrIssueComments(number, repo) {
|
|
|
43109
43282
|
return comments;
|
|
43110
43283
|
}
|
|
43111
43284
|
async function postPrCommentFromFile(number, repo, body) {
|
|
43112
|
-
const dir = (0,
|
|
43113
|
-
const path2 = (0,
|
|
43285
|
+
const dir = (0, import_node_fs38.mkdtempSync)((0, import_node_path37.join)((0, import_node_os21.tmpdir)(), "mmi-review-verdict-"));
|
|
43286
|
+
const path2 = (0, import_node_path37.join)(dir, "body.md");
|
|
43114
43287
|
try {
|
|
43115
|
-
(0,
|
|
43288
|
+
(0, import_node_fs38.writeFileSync)(path2, body, "utf8");
|
|
43116
43289
|
const { stdout } = await execFileP("gh", ["pr", "comment", number, "--repo", repo, "--body-file", path2], { timeout: GH_MUTATION_TIMEOUT_MS });
|
|
43117
43290
|
return stdout.trim();
|
|
43118
43291
|
} finally {
|
|
43119
43292
|
try {
|
|
43120
|
-
(0,
|
|
43293
|
+
(0, import_node_fs38.rmSync)(dir, { recursive: true, force: true });
|
|
43121
43294
|
} catch {
|
|
43122
43295
|
}
|
|
43123
43296
|
}
|
|
@@ -43351,18 +43524,18 @@ async function prCreateClaimRefusal(body, repoOption, deps = {}) {
|
|
|
43351
43524
|
}
|
|
43352
43525
|
|
|
43353
43526
|
// src/worktree-residue-sweep.ts
|
|
43354
|
-
var
|
|
43355
|
-
var
|
|
43527
|
+
var import_node_fs43 = require("node:fs");
|
|
43528
|
+
var import_node_path42 = require("node:path");
|
|
43356
43529
|
|
|
43357
43530
|
// src/worktree-merge-cleanup.ts
|
|
43358
|
-
var
|
|
43359
|
-
var
|
|
43531
|
+
var import_node_fs42 = require("node:fs");
|
|
43532
|
+
var import_node_path41 = require("node:path");
|
|
43360
43533
|
init_cli_shared();
|
|
43361
43534
|
|
|
43362
43535
|
// src/stage-runner.ts
|
|
43363
43536
|
var import_node_child_process16 = require("node:child_process");
|
|
43364
|
-
var
|
|
43365
|
-
var
|
|
43537
|
+
var import_node_fs40 = require("node:fs");
|
|
43538
|
+
var import_node_path39 = require("node:path");
|
|
43366
43539
|
var import_node_net = require("node:net");
|
|
43367
43540
|
var import_node_util5 = require("node:util");
|
|
43368
43541
|
|
|
@@ -43372,8 +43545,8 @@ function normalizeEol2(s) {
|
|
|
43372
43545
|
}
|
|
43373
43546
|
|
|
43374
43547
|
// src/env-detection.ts
|
|
43375
|
-
var
|
|
43376
|
-
var
|
|
43548
|
+
var import_node_fs39 = require("node:fs");
|
|
43549
|
+
var import_node_path38 = require("node:path");
|
|
43377
43550
|
var SKIPPED_DIRS = /* @__PURE__ */ new Set([".git", "node_modules", "dist", ".jerv", ".pi", ".venv", "venv"]);
|
|
43378
43551
|
function isEnvBaseName(name) {
|
|
43379
43552
|
return name.toLowerCase() === ".env";
|
|
@@ -43383,7 +43556,7 @@ function findEnvFiles(root) {
|
|
|
43383
43556
|
const walk2 = (dir, rel) => {
|
|
43384
43557
|
let entries;
|
|
43385
43558
|
try {
|
|
43386
|
-
entries = (0,
|
|
43559
|
+
entries = (0, import_node_fs39.readdirSync)(dir, { withFileTypes: true });
|
|
43387
43560
|
} catch {
|
|
43388
43561
|
return;
|
|
43389
43562
|
}
|
|
@@ -43391,13 +43564,13 @@ function findEnvFiles(root) {
|
|
|
43391
43564
|
const relPath = rel ? `${rel}/${entry.name}` : entry.name;
|
|
43392
43565
|
if (entry.isDirectory()) {
|
|
43393
43566
|
if (SKIPPED_DIRS.has(entry.name)) continue;
|
|
43394
|
-
walk2((0,
|
|
43567
|
+
walk2((0, import_node_path38.join)(dir, entry.name), relPath);
|
|
43395
43568
|
continue;
|
|
43396
43569
|
}
|
|
43397
43570
|
if (isEnvBaseName(entry.name)) {
|
|
43398
43571
|
let isDir = false;
|
|
43399
43572
|
try {
|
|
43400
|
-
isDir = (0,
|
|
43573
|
+
isDir = (0, import_node_fs39.lstatSync)((0, import_node_path38.join)(dir, entry.name)).isDirectory();
|
|
43401
43574
|
} catch {
|
|
43402
43575
|
}
|
|
43403
43576
|
if (!isDir) found.push(relPath);
|
|
@@ -43536,12 +43709,12 @@ var DOCKER_TIMEOUT_MS = 15e3;
|
|
|
43536
43709
|
function stageBash() {
|
|
43537
43710
|
if (process.platform !== "win32") return "bash";
|
|
43538
43711
|
const configured = process.env.SHELL;
|
|
43539
|
-
if (configured && (0,
|
|
43712
|
+
if (configured && (0, import_node_path39.isAbsolute)(configured) && /[/\\]bash(?:\.exe)?$/i.test(configured) && !/[/\\](?:System32|Sysnative)[/\\]bash(?:\.exe)?$/i.test(configured) && (0, import_node_fs40.existsSync)(configured)) return configured;
|
|
43540
43713
|
const candidates = [
|
|
43541
|
-
(0,
|
|
43542
|
-
...process.env.LOCALAPPDATA ? [(0,
|
|
43714
|
+
(0, import_node_path39.join)(process.env.ProgramFiles || "C:\\Program Files", "Git", "bin", "bash.exe"),
|
|
43715
|
+
...process.env.LOCALAPPDATA ? [(0, import_node_path39.join)(process.env.LOCALAPPDATA, "Programs", "Git", "bin", "bash.exe")] : []
|
|
43543
43716
|
];
|
|
43544
|
-
const bash = candidates.find((path2) => (0,
|
|
43717
|
+
const bash = candidates.find((path2) => (0, import_node_fs40.existsSync)(path2));
|
|
43545
43718
|
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.");
|
|
43546
43719
|
return bash;
|
|
43547
43720
|
}
|
|
@@ -43679,7 +43852,7 @@ function appendForceRecreate(up) {
|
|
|
43679
43852
|
return `${up.trimEnd()} --force-recreate`;
|
|
43680
43853
|
}
|
|
43681
43854
|
function stageStatePath(cwd = process.cwd()) {
|
|
43682
|
-
return (0,
|
|
43855
|
+
return (0, import_node_path39.join)(cwd, "tmp", "stage", "state.json");
|
|
43683
43856
|
}
|
|
43684
43857
|
function normPath(path2) {
|
|
43685
43858
|
return path2.replace(/\\/g, "/").replace(/\/+$/, "").toLowerCase();
|
|
@@ -43896,8 +44069,8 @@ function stageProcessEnv(stagePort, extraEnv) {
|
|
|
43896
44069
|
}
|
|
43897
44070
|
function composeResolvesPort(cwd) {
|
|
43898
44071
|
if (process.env.PORT) return true;
|
|
43899
|
-
const envFile = (0,
|
|
43900
|
-
return (0,
|
|
44072
|
+
const envFile = (0, import_node_path39.join)(cwd, ".env");
|
|
44073
|
+
return (0, import_node_fs40.existsSync)(envFile) && envFileKeys((0, import_node_fs40.readFileSync)(envFile, "utf8")).has("PORT");
|
|
43901
44074
|
}
|
|
43902
44075
|
function stageComposeEnv(config, stagePort, vaultEnvMerge, cwd) {
|
|
43903
44076
|
const composeProject = config.env?.COMPOSE_PROJECT_NAME ?? vaultEnvMerge?.COMPOSE_PROJECT_NAME ?? stageComposeProjectName(cwd);
|
|
@@ -43912,13 +44085,13 @@ function stageComposeEnv(config, stagePort, vaultEnvMerge, cwd) {
|
|
|
43912
44085
|
function stageComposeFiles(cwd) {
|
|
43913
44086
|
const files = ["docker-compose.yml"];
|
|
43914
44087
|
for (const conventional of ["docker-compose.override.yml", "docker-compose.override.yaml"]) {
|
|
43915
|
-
if ((0,
|
|
44088
|
+
if ((0, import_node_fs40.existsSync)((0, import_node_path39.join)(cwd, conventional))) files.push(conventional);
|
|
43916
44089
|
}
|
|
43917
44090
|
return [...files, RUNTIME_ENV_OVERRIDE_RELPATH];
|
|
43918
44091
|
}
|
|
43919
44092
|
async function prepareRuntimeEnvPassthrough(cwd, composeEnv, vaultEnvMerge) {
|
|
43920
44093
|
const keys = Object.keys(vaultEnvMerge ?? {});
|
|
43921
|
-
if (!keys.length || !(0,
|
|
44094
|
+
if (!keys.length || !(0, import_node_fs40.existsSync)((0, import_node_path39.join)(cwd, "docker-compose.yml"))) return {};
|
|
43922
44095
|
let configJson;
|
|
43923
44096
|
try {
|
|
43924
44097
|
const { stdout } = await execFileP3("docker", ["compose", "config", "--format", "json"], {
|
|
@@ -43934,21 +44107,21 @@ async function prepareRuntimeEnvPassthrough(cwd, composeEnv, vaultEnvMerge) {
|
|
|
43934
44107
|
}
|
|
43935
44108
|
const body = renderRuntimeEnvOverride(runtimeEnvMarkedServices(configJson), keys, runtimeEnvExcludes(configJson), runtimeEnvSelects(configJson));
|
|
43936
44109
|
if (!body) return {};
|
|
43937
|
-
const overridePath = (0,
|
|
43938
|
-
(0,
|
|
43939
|
-
(0,
|
|
44110
|
+
const overridePath = (0, import_node_path39.join)(cwd, RUNTIME_ENV_OVERRIDE_RELPATH);
|
|
44111
|
+
(0, import_node_fs40.mkdirSync)((0, import_node_path39.join)(cwd, "tmp", "stage"), { recursive: true });
|
|
44112
|
+
(0, import_node_fs40.writeFileSync)(overridePath, body, "utf8");
|
|
43940
44113
|
return stageComposeFileEnv(stageComposeFiles(cwd));
|
|
43941
44114
|
}
|
|
43942
44115
|
async function ensureStageRuntimeEnv(config, opts, cwd) {
|
|
43943
44116
|
if (!config.ensureEnv) return;
|
|
43944
|
-
const target = (0,
|
|
43945
|
-
const example = (0,
|
|
43946
|
-
if (!(0,
|
|
43947
|
-
(0,
|
|
43948
|
-
} else if ((0,
|
|
43949
|
-
const stale = detectStaleEnvFile((0,
|
|
43950
|
-
exampleMtimeMs: (0,
|
|
43951
|
-
targetMtimeMs: (0,
|
|
44117
|
+
const target = (0, import_node_path39.join)(cwd, config.ensureEnv.target);
|
|
44118
|
+
const example = (0, import_node_path39.join)(cwd, config.ensureEnv.example);
|
|
44119
|
+
if (!(0, import_node_fs40.existsSync)(target) && (0, import_node_fs40.existsSync)(example)) {
|
|
44120
|
+
(0, import_node_fs40.copyFileSync)(example, target);
|
|
44121
|
+
} else if ((0, import_node_fs40.existsSync)(target) && (0, import_node_fs40.existsSync)(example)) {
|
|
44122
|
+
const stale = detectStaleEnvFile((0, import_node_fs40.readFileSync)(example, "utf8"), (0, import_node_fs40.readFileSync)(target, "utf8"), {
|
|
44123
|
+
exampleMtimeMs: (0, import_node_fs40.statSync)(example).mtimeMs,
|
|
44124
|
+
targetMtimeMs: (0, import_node_fs40.statSync)(target).mtimeMs
|
|
43952
44125
|
});
|
|
43953
44126
|
if (stale) {
|
|
43954
44127
|
const msg = `stale ${config.ensureEnv.target} (${stale}) \u2014 delete it or refresh from ${config.ensureEnv.example} before re-running /stage`;
|
|
@@ -43956,8 +44129,8 @@ async function ensureStageRuntimeEnv(config, opts, cwd) {
|
|
|
43956
44129
|
console.error(`mmi-cli stage: ${msg} (allowed via --allow-stale-env)`);
|
|
43957
44130
|
}
|
|
43958
44131
|
}
|
|
43959
|
-
if (opts.vaultEnvMerge && Object.keys(opts.vaultEnvMerge).length && (0,
|
|
43960
|
-
(0,
|
|
44132
|
+
if (opts.vaultEnvMerge && Object.keys(opts.vaultEnvMerge).length && (0, import_node_fs40.existsSync)(target)) {
|
|
44133
|
+
(0, import_node_fs40.writeFileSync)(target, mergeEnvSecretsIntoFile((0, import_node_fs40.readFileSync)(target, "utf8"), opts.vaultEnvMerge), "utf8");
|
|
43961
44134
|
}
|
|
43962
44135
|
}
|
|
43963
44136
|
async function gitText(cwd, args) {
|
|
@@ -43987,20 +44160,20 @@ async function resolveGlobalStatePath(cwd, explicit) {
|
|
|
43987
44160
|
return void 0;
|
|
43988
44161
|
}
|
|
43989
44162
|
function readState(path2) {
|
|
43990
|
-
if (!(0,
|
|
44163
|
+
if (!(0, import_node_fs40.existsSync)(path2)) return null;
|
|
43991
44164
|
try {
|
|
43992
|
-
return JSON.parse((0,
|
|
44165
|
+
return JSON.parse((0, import_node_fs40.readFileSync)(path2, "utf8"));
|
|
43993
44166
|
} catch {
|
|
43994
44167
|
return null;
|
|
43995
44168
|
}
|
|
43996
44169
|
}
|
|
43997
44170
|
function mkdirFor(path2) {
|
|
43998
44171
|
const dir = path2.slice(0, Math.max(path2.lastIndexOf("/"), path2.lastIndexOf("\\")));
|
|
43999
|
-
(0,
|
|
44172
|
+
(0, import_node_fs40.mkdirSync)(dir, { recursive: true });
|
|
44000
44173
|
}
|
|
44001
44174
|
function writeState(path2, state) {
|
|
44002
44175
|
mkdirFor(path2);
|
|
44003
|
-
(0,
|
|
44176
|
+
(0, import_node_fs40.writeFileSync)(path2, JSON.stringify(state, null, 2), "utf8");
|
|
44004
44177
|
}
|
|
44005
44178
|
function writeStagePortReservation(port, cwd, statePath, globalStatePath, now) {
|
|
44006
44179
|
const reservation = {
|
|
@@ -44029,7 +44202,7 @@ async function cleanupStageState(state, paths, timeoutMs, fallbackCwd, currentEn
|
|
|
44029
44202
|
);
|
|
44030
44203
|
}
|
|
44031
44204
|
for (const path2 of [...new Set(paths.filter((p) => Boolean(p)))]) {
|
|
44032
|
-
(0,
|
|
44205
|
+
(0, import_node_fs40.rmSync)(path2, { force: true });
|
|
44033
44206
|
}
|
|
44034
44207
|
}
|
|
44035
44208
|
async function killTree(pid) {
|
|
@@ -44276,8 +44449,8 @@ async function runStage(config = {}, opts = {}) {
|
|
|
44276
44449
|
});
|
|
44277
44450
|
}
|
|
44278
44451
|
} catch (e) {
|
|
44279
|
-
(0,
|
|
44280
|
-
if (globalStatePath && globalStatePath !== statePath) (0,
|
|
44452
|
+
(0, import_node_fs40.rmSync)(statePath, { force: true });
|
|
44453
|
+
if (globalStatePath && globalStatePath !== statePath) (0, import_node_fs40.rmSync)(globalStatePath, { force: true });
|
|
44281
44454
|
throw e;
|
|
44282
44455
|
}
|
|
44283
44456
|
const started = await startStage(config, {
|
|
@@ -44292,8 +44465,8 @@ async function runStage(config = {}, opts = {}) {
|
|
|
44292
44465
|
}
|
|
44293
44466
|
|
|
44294
44467
|
// src/worktree-evidence-archive.ts
|
|
44295
|
-
var
|
|
44296
|
-
var
|
|
44468
|
+
var import_node_fs41 = require("node:fs");
|
|
44469
|
+
var import_node_path40 = require("node:path");
|
|
44297
44470
|
var JERV_ARTIFACT_RUN_SCOPE_ENV_VARS = ["JERV_RUN_ID", ...SESSION_ID_ENV_VARS];
|
|
44298
44471
|
function sanitizeArchiveSegment(value, max = 80) {
|
|
44299
44472
|
const scrubbed = value.replace(/[^A-Za-z0-9._@+-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
@@ -44308,24 +44481,24 @@ function resolveArtifactRunScope(env = process.env) {
|
|
|
44308
44481
|
}
|
|
44309
44482
|
function defaultIsDirectory(path2) {
|
|
44310
44483
|
try {
|
|
44311
|
-
return (0,
|
|
44484
|
+
return (0, import_node_fs41.lstatSync)(path2).isDirectory();
|
|
44312
44485
|
} catch {
|
|
44313
44486
|
return false;
|
|
44314
44487
|
}
|
|
44315
44488
|
}
|
|
44316
44489
|
function archiveWorktreeJervArtifacts(args, deps = {}) {
|
|
44317
|
-
const exists = deps.exists ??
|
|
44490
|
+
const exists = deps.exists ?? import_node_fs41.existsSync;
|
|
44318
44491
|
const isDirectory = deps.isDirectory ?? defaultIsDirectory;
|
|
44319
|
-
const copyDir = deps.copyDir ?? ((from, to) => (0,
|
|
44492
|
+
const copyDir = deps.copyDir ?? ((from, to) => (0, import_node_fs41.cpSync)(from, to, { recursive: true, force: true }));
|
|
44320
44493
|
const mkdirp = deps.mkdirp ?? ((path2) => {
|
|
44321
|
-
(0,
|
|
44494
|
+
(0, import_node_fs41.mkdirSync)(path2, { recursive: true });
|
|
44322
44495
|
});
|
|
44323
44496
|
const env = deps.env ?? process.env;
|
|
44324
44497
|
const now = deps.now ?? (() => /* @__PURE__ */ new Date());
|
|
44325
44498
|
const resolveRoot = deps.resolveArchiveRoot ?? repoRuntimeStatePath;
|
|
44326
44499
|
if (!args.primaryRoot?.trim()) return { status: "skipped", reason: "missing-primary-root" };
|
|
44327
44500
|
if (!args.worktreePath?.trim()) return { status: "skipped", reason: "missing-worktree-path" };
|
|
44328
|
-
const source = (0,
|
|
44501
|
+
const source = (0, import_node_path40.join)(args.worktreePath, ".jerv");
|
|
44329
44502
|
if (!exists(source)) return { status: "absent" };
|
|
44330
44503
|
if (!isDirectory(source)) return { status: "skipped", reason: "jerv-not-a-directory" };
|
|
44331
44504
|
const runScope = resolveArtifactRunScope(env);
|
|
@@ -44333,7 +44506,7 @@ function archiveWorktreeJervArtifacts(args, deps = {}) {
|
|
|
44333
44506
|
const stamp = now().toISOString().replace(/[:.]/g, "-");
|
|
44334
44507
|
const dest = resolveRoot(args.primaryRoot, "jerv-artifacts", runScope, branchSlug, stamp, ".jerv");
|
|
44335
44508
|
try {
|
|
44336
|
-
mkdirp((0,
|
|
44509
|
+
mkdirp((0, import_node_path40.dirname)(dest));
|
|
44337
44510
|
copyDir(source, dest);
|
|
44338
44511
|
if (!exists(dest)) return { status: "failed", error: `archive write left no directory at ${dest}` };
|
|
44339
44512
|
return { status: "archived", path: dest, runScope };
|
|
@@ -44342,14 +44515,14 @@ function archiveWorktreeJervArtifacts(args, deps = {}) {
|
|
|
44342
44515
|
}
|
|
44343
44516
|
}
|
|
44344
44517
|
function defaultStat(path2) {
|
|
44345
|
-
const st = (0,
|
|
44518
|
+
const st = (0, import_node_fs41.statSync)(path2);
|
|
44346
44519
|
return { mtimeMs: st.mtimeMs, size: st.size, isDirectory: () => st.isDirectory() };
|
|
44347
44520
|
}
|
|
44348
44521
|
function scanWorktreeTmpEvidence(worktreePath, newerThanMs, deps = {}) {
|
|
44349
|
-
const exists = deps.exists ??
|
|
44522
|
+
const exists = deps.exists ?? import_node_fs41.existsSync;
|
|
44350
44523
|
const stat4 = deps.stat ?? defaultStat;
|
|
44351
|
-
const readdir2 = deps.readdir ??
|
|
44352
|
-
const tmpRoot = (0,
|
|
44524
|
+
const readdir2 = deps.readdir ?? import_node_fs41.readdirSync;
|
|
44525
|
+
const tmpRoot = (0, import_node_path40.join)(worktreePath, "tmp");
|
|
44353
44526
|
if (!exists(tmpRoot)) return [];
|
|
44354
44527
|
const entries = [];
|
|
44355
44528
|
const walk2 = (dir) => {
|
|
@@ -44360,14 +44533,14 @@ function scanWorktreeTmpEvidence(worktreePath, newerThanMs, deps = {}) {
|
|
|
44360
44533
|
return;
|
|
44361
44534
|
}
|
|
44362
44535
|
for (const name of names) {
|
|
44363
|
-
const full = (0,
|
|
44536
|
+
const full = (0, import_node_path40.join)(dir, name);
|
|
44364
44537
|
let st;
|
|
44365
44538
|
try {
|
|
44366
44539
|
st = stat4(full);
|
|
44367
44540
|
} catch {
|
|
44368
44541
|
continue;
|
|
44369
44542
|
}
|
|
44370
|
-
const relPath = (0,
|
|
44543
|
+
const relPath = (0, import_node_path40.relative)(worktreePath, full).replace(/\\/g, "/");
|
|
44371
44544
|
if (st.isDirectory()) {
|
|
44372
44545
|
if (st.mtimeMs > newerThanMs) entries.push({ relPath, bytes: 0, mtimeMs: st.mtimeMs });
|
|
44373
44546
|
walk2(full);
|
|
@@ -44381,10 +44554,10 @@ function scanWorktreeTmpEvidence(worktreePath, newerThanMs, deps = {}) {
|
|
|
44381
44554
|
return entries;
|
|
44382
44555
|
}
|
|
44383
44556
|
function archiveWorktreeTmpArtifacts(args, deps = {}) {
|
|
44384
|
-
const exists = deps.exists ??
|
|
44385
|
-
const copyDir = deps.copyDir ?? ((from, to) => (0,
|
|
44557
|
+
const exists = deps.exists ?? import_node_fs41.existsSync;
|
|
44558
|
+
const copyDir = deps.copyDir ?? ((from, to) => (0, import_node_fs41.cpSync)(from, to, { recursive: true, force: true }));
|
|
44386
44559
|
const mkdirp = deps.mkdirp ?? ((path2) => {
|
|
44387
|
-
(0,
|
|
44560
|
+
(0, import_node_fs41.mkdirSync)(path2, { recursive: true });
|
|
44388
44561
|
});
|
|
44389
44562
|
const env = deps.env ?? process.env;
|
|
44390
44563
|
const now = deps.now ?? (() => /* @__PURE__ */ new Date());
|
|
@@ -44392,7 +44565,7 @@ function archiveWorktreeTmpArtifacts(args, deps = {}) {
|
|
|
44392
44565
|
if (!args.primaryRoot?.trim()) return { status: "skipped", reason: "missing-primary-root" };
|
|
44393
44566
|
if (!args.worktreePath?.trim()) return { status: "skipped", reason: "missing-worktree-path" };
|
|
44394
44567
|
const scanned = scanWorktreeTmpEvidence(args.worktreePath, args.newerThanMs, deps);
|
|
44395
|
-
const source = (0,
|
|
44568
|
+
const source = (0, import_node_path40.join)(args.worktreePath, "tmp");
|
|
44396
44569
|
if (!scanned.length) return { status: "absent" };
|
|
44397
44570
|
if (!exists(source)) return { status: "absent" };
|
|
44398
44571
|
const runScope = resolveArtifactRunScope(env);
|
|
@@ -44400,7 +44573,7 @@ function archiveWorktreeTmpArtifacts(args, deps = {}) {
|
|
|
44400
44573
|
const stamp = now().toISOString().replace(/[:.]/g, "-");
|
|
44401
44574
|
const dest = resolveRoot(args.primaryRoot, "worktree-artifacts", runScope, branchSlug, stamp, "tmp");
|
|
44402
44575
|
try {
|
|
44403
|
-
mkdirp((0,
|
|
44576
|
+
mkdirp((0, import_node_path40.dirname)(dest));
|
|
44404
44577
|
copyDir(source, dest);
|
|
44405
44578
|
if (!exists(dest)) return { status: "failed", error: `archive write left no directory at ${dest}` };
|
|
44406
44579
|
const bytes = scanned.reduce((sum, e) => sum + e.bytes, 0);
|
|
@@ -44469,9 +44642,9 @@ function normPath2(p) {
|
|
|
44469
44642
|
return p.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
44470
44643
|
}
|
|
44471
44644
|
function unlinkNodeModulesJunction(wtPath) {
|
|
44472
|
-
const nm = (0,
|
|
44645
|
+
const nm = (0, import_node_path41.join)(wtPath, "node_modules");
|
|
44473
44646
|
try {
|
|
44474
|
-
if ((0,
|
|
44647
|
+
if ((0, import_node_fs42.lstatSync)(nm).isSymbolicLink()) (0, import_node_fs42.rmdirSync)(nm);
|
|
44475
44648
|
return { ok: true };
|
|
44476
44649
|
} catch (e) {
|
|
44477
44650
|
if (e.code === "ENOENT") return { ok: true };
|
|
@@ -44482,8 +44655,8 @@ function defaultSleep2(ms) {
|
|
|
44482
44655
|
return new Promise((resolve7) => setTimeout(resolve7, ms));
|
|
44483
44656
|
}
|
|
44484
44657
|
async function removeResidueDirectory(wtPath, options = {}) {
|
|
44485
|
-
const { sleep: sleep2 = defaultSleep2, removeEmptyDir =
|
|
44486
|
-
const removeRecursive = options.removeRecursive ?? ((path2) => (0,
|
|
44658
|
+
const { sleep: sleep2 = defaultSleep2, removeEmptyDir = import_node_fs42.rmdirSync, exists = import_node_fs42.existsSync } = options;
|
|
44659
|
+
const removeRecursive = options.removeRecursive ?? ((path2) => (0, import_node_fs42.rmSync)(path2, { recursive: true, force: true, maxRetries: 10, retryDelay: 100 }));
|
|
44487
44660
|
const junction = unlinkNodeModulesJunction(wtPath);
|
|
44488
44661
|
if (!junction.ok) return junction;
|
|
44489
44662
|
try {
|
|
@@ -44606,28 +44779,28 @@ async function preCleanWorktreeForRemoval(wtPath, execGit) {
|
|
|
44606
44779
|
}
|
|
44607
44780
|
async function listNestedIgnoredNodeModules(wtPath, execGit) {
|
|
44608
44781
|
const out = await execGit(["-C", wtPath, "ls-files", "--others", "--ignored", "--exclude-standard", "--directory"]).catch(() => "");
|
|
44609
|
-
return out.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.endsWith("node_modules/") && line !== "node_modules/").map((line) => (0,
|
|
44782
|
+
return out.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.endsWith("node_modules/") && line !== "node_modules/").map((line) => (0, import_node_path41.join)(wtPath, line.slice(0, -1)));
|
|
44610
44783
|
}
|
|
44611
44784
|
function safeRemoveTree(path2) {
|
|
44612
|
-
const stat4 = (0,
|
|
44785
|
+
const stat4 = (0, import_node_fs42.lstatSync)(path2);
|
|
44613
44786
|
if (stat4.isSymbolicLink()) {
|
|
44614
44787
|
try {
|
|
44615
|
-
(0,
|
|
44788
|
+
(0, import_node_fs42.rmdirSync)(path2);
|
|
44616
44789
|
} catch {
|
|
44617
|
-
(0,
|
|
44790
|
+
(0, import_node_fs42.unlinkSync)(path2);
|
|
44618
44791
|
}
|
|
44619
44792
|
return;
|
|
44620
44793
|
}
|
|
44621
44794
|
if (stat4.isDirectory()) {
|
|
44622
|
-
for (const entry of (0,
|
|
44623
|
-
(0,
|
|
44795
|
+
for (const entry of (0, import_node_fs42.readdirSync)(path2)) safeRemoveTree((0, import_node_path41.join)(path2, entry));
|
|
44796
|
+
(0, import_node_fs42.rmdirSync)(path2);
|
|
44624
44797
|
return;
|
|
44625
44798
|
}
|
|
44626
|
-
(0,
|
|
44799
|
+
(0, import_node_fs42.unlinkSync)(path2);
|
|
44627
44800
|
}
|
|
44628
44801
|
async function removeWorktreeNodeModules(wtPath) {
|
|
44629
44802
|
try {
|
|
44630
|
-
safeRemoveTree((0,
|
|
44803
|
+
safeRemoveTree((0, import_node_path41.join)(wtPath, "node_modules"));
|
|
44631
44804
|
return { ok: true };
|
|
44632
44805
|
} catch (e) {
|
|
44633
44806
|
if (e.code === "ENOENT") return { ok: true };
|
|
@@ -44639,7 +44812,7 @@ function errorMessage(e) {
|
|
|
44639
44812
|
}
|
|
44640
44813
|
function resolvedOrRaw(path2) {
|
|
44641
44814
|
try {
|
|
44642
|
-
return normPath2((0,
|
|
44815
|
+
return normPath2((0, import_node_fs42.realpathSync)(path2));
|
|
44643
44816
|
} catch {
|
|
44644
44817
|
return normPath2(path2);
|
|
44645
44818
|
}
|
|
@@ -44647,10 +44820,10 @@ function resolvedOrRaw(path2) {
|
|
|
44647
44820
|
function unlinkEscapingReparsePoints(root, primaryRoot) {
|
|
44648
44821
|
let realRoot;
|
|
44649
44822
|
try {
|
|
44650
|
-
if ((0,
|
|
44823
|
+
if ((0, import_node_fs42.lstatSync)(root).isSymbolicLink()) {
|
|
44651
44824
|
return { ok: false, error: `delete root ${normPath2(root)} is a reparse point resolving to ${resolvedOrRaw(root)}` };
|
|
44652
44825
|
}
|
|
44653
|
-
realRoot = normPath2((0,
|
|
44826
|
+
realRoot = normPath2((0, import_node_fs42.realpathSync)(root));
|
|
44654
44827
|
} catch (e) {
|
|
44655
44828
|
if (e.code === "ENOENT") return { ok: true, unlinked: [] };
|
|
44656
44829
|
return { ok: false, error: `cannot resolve delete root ${normPath2(root)}: ${errorMessage(e)}` };
|
|
@@ -44666,17 +44839,17 @@ function unlinkEscapingReparsePoints(root, primaryRoot) {
|
|
|
44666
44839
|
const dir = stack.pop();
|
|
44667
44840
|
let entries;
|
|
44668
44841
|
try {
|
|
44669
|
-
entries = (0,
|
|
44842
|
+
entries = (0, import_node_fs42.readdirSync)(dir, { withFileTypes: true });
|
|
44670
44843
|
} catch (e) {
|
|
44671
44844
|
if (e.code === "ENOENT") continue;
|
|
44672
44845
|
return { ok: false, error: `cannot scan ${normPath2(dir)} for reparse points: ${errorMessage(e)}` };
|
|
44673
44846
|
}
|
|
44674
44847
|
for (const entry of entries) {
|
|
44675
|
-
const child2 = (0,
|
|
44848
|
+
const child2 = (0, import_node_path41.join)(dir, entry.name);
|
|
44676
44849
|
if (entry.isSymbolicLink()) {
|
|
44677
44850
|
let target = "";
|
|
44678
44851
|
try {
|
|
44679
|
-
target = normPath2((0,
|
|
44852
|
+
target = normPath2((0, import_node_fs42.realpathSync)(child2));
|
|
44680
44853
|
} catch {
|
|
44681
44854
|
target = "";
|
|
44682
44855
|
}
|
|
@@ -44859,7 +45032,7 @@ async function cleanupPrMergeLocalBranch(branch, options) {
|
|
|
44859
45032
|
return report;
|
|
44860
45033
|
}
|
|
44861
45034
|
const execGit = options.execGit ?? (async (args) => (await execFileP("git", args, { timeout: GIT_TIMEOUT_MS })).stdout);
|
|
44862
|
-
const pathExists = options.pathExists ??
|
|
45035
|
+
const pathExists = options.pathExists ?? import_node_fs42.existsSync;
|
|
44863
45036
|
let afterWorktrees = [];
|
|
44864
45037
|
try {
|
|
44865
45038
|
afterWorktrees = parseGitWorktreePorcelain(await execGit(["worktree", "list", "--porcelain"]));
|
|
@@ -44999,7 +45172,7 @@ async function cleanupPrMergeLocalBranch(branch, options) {
|
|
|
44999
45172
|
const preHelperGuard = unlinkEscapingReparsePoints(wtPath, options.primaryRoot);
|
|
45000
45173
|
if (!preHelperGuard.ok) return refuseReparseEscape(preHelperGuard.error);
|
|
45001
45174
|
unlinkedReparsePoints.push(...preHelperGuard.unlinked);
|
|
45002
|
-
if (pathExists((0,
|
|
45175
|
+
if (pathExists((0, import_node_path41.join)(wtPath, "node_modules"))) {
|
|
45003
45176
|
const nmRemoved = await (options.removeRealNodeModules ?? removeWorktreeNodeModules)(wtPath);
|
|
45004
45177
|
if (!nmRemoved.ok) {
|
|
45005
45178
|
report.worktree = {
|
|
@@ -45135,18 +45308,18 @@ function renderPrMergeCleanupLines(cleanup) {
|
|
|
45135
45308
|
// src/worktree-residue-sweep.ts
|
|
45136
45309
|
var RESIDUE_LEDGER_FILE = "mmi-worktree-residue.json";
|
|
45137
45310
|
function canonicalWorktreeRoot(primary) {
|
|
45138
|
-
return (0,
|
|
45311
|
+
return (0, import_node_path42.join)((0, import_node_path42.dirname)(primary), "mmi-worktrees", (0, import_node_path42.basename)(primary));
|
|
45139
45312
|
}
|
|
45140
45313
|
function norm(p) {
|
|
45141
45314
|
const s = p.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
45142
45315
|
return process.platform === "win32" ? s.toLowerCase() : s;
|
|
45143
45316
|
}
|
|
45144
45317
|
function residueLedgerPath(gitCommonDir) {
|
|
45145
|
-
return (0,
|
|
45318
|
+
return (0, import_node_path42.join)(gitCommonDir, RESIDUE_LEDGER_FILE);
|
|
45146
45319
|
}
|
|
45147
45320
|
function readPaths(file, deps) {
|
|
45148
45321
|
try {
|
|
45149
|
-
const parsed = JSON.parse((deps.readLedger ?? ((f) => (0,
|
|
45322
|
+
const parsed = JSON.parse((deps.readLedger ?? ((f) => (0, import_node_fs43.readFileSync)(f, "utf8")))(file));
|
|
45150
45323
|
return Array.isArray(parsed) ? parsed.filter((p) => typeof p === "string") : [];
|
|
45151
45324
|
} catch {
|
|
45152
45325
|
return [];
|
|
@@ -45155,8 +45328,8 @@ function readPaths(file, deps) {
|
|
|
45155
45328
|
function writePaths(file, paths, deps) {
|
|
45156
45329
|
try {
|
|
45157
45330
|
const write = deps.writeLedger ?? ((f, t) => {
|
|
45158
|
-
(0,
|
|
45159
|
-
(0,
|
|
45331
|
+
(0, import_node_fs43.mkdirSync)((0, import_node_path42.dirname)(f), { recursive: true });
|
|
45332
|
+
(0, import_node_fs43.writeFileSync)(f, t, "utf8");
|
|
45160
45333
|
});
|
|
45161
45334
|
write(file, `${JSON.stringify([...new Set(paths)], null, 1)}
|
|
45162
45335
|
`);
|
|
@@ -45170,17 +45343,17 @@ function recordResidue(gitCommonDir, path2, deps = {}) {
|
|
|
45170
45343
|
writePaths(file, paths, deps);
|
|
45171
45344
|
}
|
|
45172
45345
|
async function sweepWorktreeResidue(gitCommonDir, registered, deps = {}) {
|
|
45173
|
-
const exists = deps.exists ??
|
|
45174
|
-
const readDir = deps.readDir ?? ((p) => (0,
|
|
45346
|
+
const exists = deps.exists ?? import_node_fs43.existsSync;
|
|
45347
|
+
const readDir = deps.readDir ?? ((p) => (0, import_node_fs43.readdirSync)(p));
|
|
45175
45348
|
const isDir = deps.isDir ?? ((p) => {
|
|
45176
45349
|
try {
|
|
45177
|
-
return (0,
|
|
45350
|
+
return (0, import_node_fs43.statSync)(p).isDirectory();
|
|
45178
45351
|
} catch {
|
|
45179
45352
|
return false;
|
|
45180
45353
|
}
|
|
45181
45354
|
});
|
|
45182
45355
|
const removeRecorded = deps.removeRecorded ?? ((p) => removeResidueDirectory(p));
|
|
45183
|
-
const removeEmpty = deps.removeEmpty ?? ((p) => (0,
|
|
45356
|
+
const removeEmpty = deps.removeEmpty ?? ((p) => (0, import_node_fs43.rmdirSync)(p));
|
|
45184
45357
|
const report = { swept: [], kept: [], dropped: [], emptyRemoved: [], unrecorded: [] };
|
|
45185
45358
|
const live = new Set(registered.map(norm));
|
|
45186
45359
|
const primary = registered[0] ? norm(registered[0]) : void 0;
|
|
@@ -45215,7 +45388,7 @@ async function sweepWorktreeResidue(gitCommonDir, registered, deps = {}) {
|
|
|
45215
45388
|
} catch {
|
|
45216
45389
|
}
|
|
45217
45390
|
for (const name of children) {
|
|
45218
|
-
const child2 = (0,
|
|
45391
|
+
const child2 = (0, import_node_path42.join)(root, name);
|
|
45219
45392
|
const key = norm(child2);
|
|
45220
45393
|
if (live.has(key) || key === primary || keptKeys.has(key) || !isDir(child2)) continue;
|
|
45221
45394
|
let entries;
|
|
@@ -45258,10 +45431,10 @@ function argvWantsJson2() {
|
|
|
45258
45431
|
return process.argv.some((a) => a === "--json" || a.startsWith("--json="));
|
|
45259
45432
|
}
|
|
45260
45433
|
function hubRoot() {
|
|
45261
|
-
const fromPkg = (0,
|
|
45434
|
+
const fromPkg = (0, import_node_path43.join)(__dirname, "..", "..");
|
|
45262
45435
|
const marker = "skills/bootstrap/seeds/manifest.json";
|
|
45263
|
-
if ((0,
|
|
45264
|
-
if ((0,
|
|
45436
|
+
if ((0, import_node_fs44.existsSync)((0, import_node_path43.join)(fromPkg, marker))) return fromPkg;
|
|
45437
|
+
if ((0, import_node_fs44.existsSync)((0, import_node_path43.join)(process.cwd(), marker))) return process.cwd();
|
|
45265
45438
|
return null;
|
|
45266
45439
|
}
|
|
45267
45440
|
function ciAuditDeps() {
|
|
@@ -45273,8 +45446,8 @@ function ciAuditDeps() {
|
|
|
45273
45446
|
getProjectMeta: async (slug) => fetchProjectBySlug(slug, registryClientDeps(await cfgPromise)),
|
|
45274
45447
|
readSeedFile: (path2) => {
|
|
45275
45448
|
if (!root) return null;
|
|
45276
|
-
const fullPath = (0,
|
|
45277
|
-
return (0,
|
|
45449
|
+
const fullPath = (0, import_node_path43.join)(root, path2);
|
|
45450
|
+
return (0, import_node_fs44.existsSync)(fullPath) ? (0, import_node_fs44.readFileSync)(fullPath, "utf8") : null;
|
|
45278
45451
|
}
|
|
45279
45452
|
};
|
|
45280
45453
|
}
|
|
@@ -46037,11 +46210,11 @@ ${list}`);
|
|
|
46037
46210
|
}
|
|
46038
46211
|
});
|
|
46039
46212
|
async function listCiWorkflowPaths(cwd = process.cwd()) {
|
|
46040
|
-
const wfDir = (0,
|
|
46041
|
-
if (!(0,
|
|
46042
|
-
return (0,
|
|
46213
|
+
const wfDir = (0, import_node_path43.join)(cwd, ".github", "workflows");
|
|
46214
|
+
if (!(0, import_node_fs44.existsSync)(wfDir)) return [];
|
|
46215
|
+
return (0, import_node_fs44.readdirSync)(wfDir).filter((name) => /\.(ya?ml)$/i.test(name)).filter((name) => {
|
|
46043
46216
|
try {
|
|
46044
|
-
return workflowReportsPrChecks((0,
|
|
46217
|
+
return workflowReportsPrChecks((0, import_node_fs44.readFileSync)((0, import_node_path43.join)(wfDir, name), "utf8"));
|
|
46045
46218
|
} catch {
|
|
46046
46219
|
return true;
|
|
46047
46220
|
}
|
|
@@ -46246,7 +46419,7 @@ ${list}`);
|
|
|
46246
46419
|
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) => {
|
|
46247
46420
|
if (!isReviewVerdict(o.verdict)) return fail(`pr review-verdict: --verdict must be one of ${REVIEW_VERDICTS.join("|")} (got ${o.verdict})`);
|
|
46248
46421
|
const verdict = o.verdict;
|
|
46249
|
-
const findings = o.findingsFile ? (0,
|
|
46422
|
+
const findings = o.findingsFile ? (0, import_node_fs44.readFileSync)(o.findingsFile, "utf8") : void 0;
|
|
46250
46423
|
let patch;
|
|
46251
46424
|
let head;
|
|
46252
46425
|
try {
|
|
@@ -46523,7 +46696,7 @@ ${list}`);
|
|
|
46523
46696
|
const mergeSquashBody = squashBodyTextForMerge(
|
|
46524
46697
|
closingGuardInput,
|
|
46525
46698
|
method === "--squash",
|
|
46526
|
-
o.squashBodyFile ? (0,
|
|
46699
|
+
o.squashBodyFile ? (0, import_node_fs44.readFileSync)(o.squashBodyFile, "utf8") : void 0
|
|
46527
46700
|
);
|
|
46528
46701
|
if (!o.squashBodyFile) warnSquashBodyClosingStrip("pr merge", closingGuardInput, mergeSquashBody);
|
|
46529
46702
|
const closingGuardVerdict = evaluateClosingGuard(closingGuardInput, {
|
|
@@ -46555,7 +46728,7 @@ ${list}`);
|
|
|
46555
46728
|
const remote = foreignCwd ? `https://github.com/${targetRepo2}.git` : "origin";
|
|
46556
46729
|
let foreignCheckout;
|
|
46557
46730
|
if (foreignCwd) {
|
|
46558
|
-
const sibling = (0,
|
|
46731
|
+
const sibling = (0, import_node_path43.join)((0, import_node_path43.dirname)(beforeWorktrees[0]?.path || startingPath || process.cwd()), targetRepo2.split("/")[1]);
|
|
46559
46732
|
const siblingRepo = repoFromRemoteUrl(await gitOut(["-C", sibling, "remote", "get-url", "origin"]).catch(() => ""));
|
|
46560
46733
|
if (siblingRepo?.toLowerCase() === targetRepo2.toLowerCase()) {
|
|
46561
46734
|
const siblingWorktrees = await execFileP("git", ["-C", sibling, "worktree", "list", "--porcelain"], { timeout: GIT_TIMEOUT_MS }).then((r) => parseGitWorktreePorcelain(r.stdout)).catch(() => void 0);
|
|
@@ -46653,7 +46826,7 @@ ${list}`);
|
|
|
46653
46826
|
}
|
|
46654
46827
|
if (!repoForPostCleanup) throw e;
|
|
46655
46828
|
console.warn(`pr merge: gh GraphQL rate-limited \u2014 merging PR #${number} via REST PUT instead (#4588).`);
|
|
46656
|
-
const commitMessage = bodyFile ? (0,
|
|
46829
|
+
const commitMessage = bodyFile ? (0, import_node_fs44.readFileSync)(bodyFile, "utf8") : void 0;
|
|
46657
46830
|
await defaultGitHubClient().rest("PUT", `repos/${repoForPostCleanup}/pulls/${number}/merge`, {
|
|
46658
46831
|
body: { merge_method: method.slice(2), ...commitMessage ? { commit_message: commitMessage } : {} },
|
|
46659
46832
|
timeoutMs: GH_MUTATION_TIMEOUT_MS
|
|
@@ -46767,7 +46940,7 @@ ${list}`);
|
|
|
46767
46940
|
let residueSweep;
|
|
46768
46941
|
if (!(foreignCwd && !foreignCheckout)) {
|
|
46769
46942
|
try {
|
|
46770
|
-
gitCommonDir = (0,
|
|
46943
|
+
gitCommonDir = (0, import_node_path43.resolve)(primaryRoot, (await execFileP("git", ["-C", primaryRoot, "rev-parse", "--git-common-dir"], { timeout: GIT_TIMEOUT_MS })).stdout.trim());
|
|
46771
46944
|
residueSweep = await sweepWorktreeResidue(gitCommonDir, beforeWorktrees.map((w) => w.path));
|
|
46772
46945
|
} catch {
|
|
46773
46946
|
}
|
|
@@ -46785,7 +46958,7 @@ ${list}`);
|
|
|
46785
46958
|
preserveWorktree: o.preserveWorktree,
|
|
46786
46959
|
gcAcknowledged: o.gc,
|
|
46787
46960
|
expectedHeadOid: headRefOid,
|
|
46788
|
-
pathExists: (p) => (0,
|
|
46961
|
+
pathExists: (p) => (0, import_node_fs44.existsSync)(p),
|
|
46789
46962
|
// #5899: pin cleanup git calls to the main checkout — the task worktree this process may be
|
|
46790
46963
|
// standing in is removed mid-cleanup, so a cwd-relative invocation fails with
|
|
46791
46964
|
// 'fatal: not a git repository' and leaves a spurious partial-cleanup exit.
|
|
@@ -48017,18 +48190,18 @@ function rcRunCauseFromLog(log) {
|
|
|
48017
48190
|
function memberAnnounceSummaryFile(repo, summaryFile, memberSummaryFiles) {
|
|
48018
48191
|
return repo === SUITE_REPO ? summaryFile : memberSummaryFiles[repo];
|
|
48019
48192
|
}
|
|
48020
|
-
var suiteStateDir = (root) => (0,
|
|
48193
|
+
var suiteStateDir = (root) => (0, import_node_path44.join)(resolvePrimaryGitDir(root), "mmi-runtime", "suite");
|
|
48021
48194
|
function suiteTrainIo(root, summaryFile, memberSummaryFiles = {}, summaryFileTr, memberSummaryFilesTr = {}) {
|
|
48022
|
-
const recordPath = (0,
|
|
48023
|
-
const base = (0,
|
|
48195
|
+
const recordPath = (0, import_node_path44.join)(suiteStateDir(root), "cut.json");
|
|
48196
|
+
const base = (0, import_node_path44.join)(suiteStateDir(root), "checkouts");
|
|
48024
48197
|
const checkout = async (repo) => {
|
|
48025
48198
|
if (repo === SUITE_REPO) return root;
|
|
48026
|
-
const target = (0,
|
|
48027
|
-
if (!(0,
|
|
48028
|
-
(0,
|
|
48199
|
+
const target = (0, import_node_path44.join)(base, repo.split("/")[1]);
|
|
48200
|
+
if (!(0, import_node_fs45.existsSync)(target)) {
|
|
48201
|
+
(0, import_node_fs45.mkdirSync)(base, { recursive: true });
|
|
48029
48202
|
await exec("git", ["clone", "--quiet", "--branch", "development", `https://github.com/${repo}.git`, target], root, WATCH_TIMEOUT);
|
|
48030
48203
|
}
|
|
48031
|
-
if (!(0,
|
|
48204
|
+
if (!(0, import_node_fs45.existsSync)((0, import_node_path44.join)(target, ".git"))) throw new Error(`${repo}: suite checkout has no .git at ${target}; stop`);
|
|
48032
48205
|
const origin = await exec("git", ["remote", "get-url", "origin"], target);
|
|
48033
48206
|
if (!origin.toLowerCase().endsWith(`/${repo.toLowerCase()}.git`) && !origin.toLowerCase().endsWith(`/${repo.toLowerCase()}`))
|
|
48034
48207
|
throw new Error(`${repo}: suite checkout origin mismatch at ${target}; stop`);
|
|
@@ -48351,9 +48524,9 @@ function suiteTrainIo(root, summaryFile, memberSummaryFiles = {}, summaryFileTr,
|
|
|
48351
48524
|
const body = await gh(["release", "view", leadTag, "--repo", SUITE_REPO, "--json", "body", "--jq", ".body"]);
|
|
48352
48525
|
if (parseSuiteMapping(body)) return;
|
|
48353
48526
|
const dir = suiteStateDir(root);
|
|
48354
|
-
(0,
|
|
48355
|
-
const file = (0,
|
|
48356
|
-
(0,
|
|
48527
|
+
(0, import_node_fs45.mkdirSync)(dir, { recursive: true });
|
|
48528
|
+
const file = (0, import_node_path44.join)(dir, `notes-${leadTag}.md`);
|
|
48529
|
+
(0, import_node_fs45.writeFileSync)(file, `${body}
|
|
48357
48530
|
|
|
48358
48531
|
${suiteMappingBlock(leadTag, mapping)}`);
|
|
48359
48532
|
await gh(["release", "edit", leadTag, "--repo", SUITE_REPO, "--notes-file", file]);
|
|
@@ -48394,7 +48567,7 @@ ${suiteMappingBlock(leadTag, mapping)}`);
|
|
|
48394
48567
|
|
|
48395
48568
|
// src/suite-commands.ts
|
|
48396
48569
|
init_cli_shared();
|
|
48397
|
-
var
|
|
48570
|
+
var import_node_fs46 = require("node:fs");
|
|
48398
48571
|
function parseMemberSummaryFiles(entries) {
|
|
48399
48572
|
const memberSummaryFiles = {};
|
|
48400
48573
|
for (const entry of entries) {
|
|
@@ -48476,7 +48649,7 @@ function registerSuiteCommands(program3) {
|
|
|
48476
48649
|
try {
|
|
48477
48650
|
const io = suiteTrainIo(root);
|
|
48478
48651
|
retired = await retireFailedLeadRcLedger({ ledgerPath: releaseLedgerPath(root), rcHead: () => io.head(SUITE_REPO, "rc").then((h) => h ?? void 0), markAbandoned: io.markAbandoned }, o.ownerGo === true);
|
|
48479
|
-
if (retired && !(0,
|
|
48652
|
+
if (retired && !(0, import_node_fs46.existsSync)(io.recordPath)) {
|
|
48480
48653
|
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)`);
|
|
48481
48654
|
return;
|
|
48482
48655
|
}
|
|
@@ -48665,9 +48838,9 @@ function suiteStatusDeps(github, registry2) {
|
|
|
48665
48838
|
|
|
48666
48839
|
// src/packages-adopt-export.ts
|
|
48667
48840
|
var import_node_child_process18 = require("node:child_process");
|
|
48668
|
-
var
|
|
48669
|
-
var
|
|
48670
|
-
var
|
|
48841
|
+
var import_node_fs47 = require("node:fs");
|
|
48842
|
+
var import_node_os22 = require("node:os");
|
|
48843
|
+
var import_node_path45 = require("node:path");
|
|
48671
48844
|
var import_node_util6 = require("node:util");
|
|
48672
48845
|
init_cli_shared();
|
|
48673
48846
|
|
|
@@ -49287,38 +49460,38 @@ function expectedFromRun(run, opts) {
|
|
|
49287
49460
|
}
|
|
49288
49461
|
async function adoptExport(opts, deps) {
|
|
49289
49462
|
if (!/^sha256:[0-9a-f]{64}$/.test(opts.digest)) throw new Error("--digest must be sha256:<64 hex>, from the export run summary");
|
|
49290
|
-
const packagePath = (0,
|
|
49291
|
-
const lockPath = (0,
|
|
49292
|
-
const packageText = (0,
|
|
49293
|
-
const lockText = (0,
|
|
49294
|
-
const work = (0,
|
|
49463
|
+
const packagePath = (0, import_node_path45.join)(opts.dir, "package.json");
|
|
49464
|
+
const lockPath = (0, import_node_path45.join)(opts.dir, "package-lock.json");
|
|
49465
|
+
const packageText = (0, import_node_fs47.readFileSync)(packagePath, "utf8");
|
|
49466
|
+
const lockText = (0, import_node_fs47.readFileSync)(lockPath, "utf8");
|
|
49467
|
+
const work = (0, import_node_fs47.mkdtempSync)((0, import_node_path45.join)((0, import_node_os22.tmpdir)(), "mmi-adopt-export-"));
|
|
49295
49468
|
try {
|
|
49296
49469
|
const run = JSON.parse((await deps.ghApi(`repos/${EXPORT_REPO}/actions/runs/${opts.run}`)).toString("utf8"));
|
|
49297
|
-
(0,
|
|
49298
|
-
(0,
|
|
49299
|
-
(0,
|
|
49300
|
-
const script = (0,
|
|
49301
|
-
(0,
|
|
49470
|
+
(0, import_node_fs47.writeFileSync)((0, import_node_path45.join)(work, "expected.json"), JSON.stringify(expectedFromRun(run, opts)));
|
|
49471
|
+
(0, import_node_fs47.writeFileSync)((0, import_node_path45.join)(work, "provider.json"), await deps.ghApi(`repos/${EXPORT_REPO}/actions/artifacts/${opts.artifact}`));
|
|
49472
|
+
(0, import_node_fs47.writeFileSync)((0, import_node_path45.join)(work, "artifact.zip"), await deps.ghApi(`repos/${EXPORT_REPO}/actions/artifacts/${opts.artifact}/zip`));
|
|
49473
|
+
const script = (0, import_node_path45.join)(work, "package_export.py");
|
|
49474
|
+
(0, import_node_fs47.writeFileSync)(script, package_export_default);
|
|
49302
49475
|
await deps.python(script, ["verify", work, opts.ds, opts.screens]);
|
|
49303
|
-
const verified = (0,
|
|
49304
|
-
const metadata = Object.fromEntries(PACKAGES.map(({ name, short: short3 }) => [name, JSON.parse((0,
|
|
49476
|
+
const verified = (0, import_node_path45.join)(work, "verified");
|
|
49477
|
+
const metadata = Object.fromEntries(PACKAGES.map(({ name, short: short3 }) => [name, JSON.parse((0, import_node_fs47.readFileSync)((0, import_node_path45.join)(verified, `${short3}.metadata.json`), "utf8"))]));
|
|
49305
49478
|
const plan = planAdoption(packageText, lockText, metadata);
|
|
49306
49479
|
for (const { name } of plan.result.adopted) {
|
|
49307
49480
|
const short3 = PACKAGES.find((p) => p.name === name).short;
|
|
49308
|
-
await deps.npm(["cache", "add", (0,
|
|
49481
|
+
await deps.npm(["cache", "add", (0, import_node_path45.join)(verified, `${short3}.tgz`)], opts.dir);
|
|
49309
49482
|
}
|
|
49310
|
-
(0,
|
|
49311
|
-
(0,
|
|
49483
|
+
(0, import_node_fs47.writeFileSync)(packagePath, plan.packageText);
|
|
49484
|
+
(0, import_node_fs47.writeFileSync)(lockPath, plan.lockText);
|
|
49312
49485
|
try {
|
|
49313
49486
|
await deps.npm(["ci", "--offline", "--ignore-scripts", "--no-audit", "--no-fund"], opts.dir);
|
|
49314
49487
|
} catch (error) {
|
|
49315
|
-
(0,
|
|
49316
|
-
(0,
|
|
49488
|
+
(0, import_node_fs47.writeFileSync)(packagePath, packageText);
|
|
49489
|
+
(0, import_node_fs47.writeFileSync)(lockPath, lockText);
|
|
49317
49490
|
throw new Error(`npm ci --offline failed, package.json and package-lock.json restored: ${error.message}`);
|
|
49318
49491
|
}
|
|
49319
49492
|
return plan.result;
|
|
49320
49493
|
} finally {
|
|
49321
|
-
(0,
|
|
49494
|
+
(0, import_node_fs47.rmSync)(work, { recursive: true, force: true });
|
|
49322
49495
|
}
|
|
49323
49496
|
}
|
|
49324
49497
|
var execFileBuffer = (0, import_node_util6.promisify)(import_node_child_process18.execFile);
|
|
@@ -49383,12 +49556,12 @@ function registerPackagesCommands(program3) {
|
|
|
49383
49556
|
init_cli_shared();
|
|
49384
49557
|
|
|
49385
49558
|
// src/wave-status.ts
|
|
49386
|
-
var
|
|
49559
|
+
var import_node_fs48 = require("node:fs");
|
|
49387
49560
|
function readStageSummary(worktreePath) {
|
|
49388
49561
|
const statePath = stageStatePath(worktreePath);
|
|
49389
|
-
if (!(0,
|
|
49562
|
+
if (!(0, import_node_fs48.existsSync)(statePath)) return void 0;
|
|
49390
49563
|
try {
|
|
49391
|
-
const state = JSON.parse((0,
|
|
49564
|
+
const state = JSON.parse((0, import_node_fs48.readFileSync)(statePath, "utf8"));
|
|
49392
49565
|
const port = typeof state.port === "number" ? state.port : void 0;
|
|
49393
49566
|
if (port == null || !Number.isInteger(port) || port <= 0) return void 0;
|
|
49394
49567
|
return { port, url: typeof state.url === "string" ? state.url : void 0 };
|
|
@@ -49445,9 +49618,9 @@ async function collectWaveStatus(deps) {
|
|
|
49445
49618
|
// src/discovery-commands.ts
|
|
49446
49619
|
init_github_client();
|
|
49447
49620
|
init_cli_shared();
|
|
49448
|
-
var
|
|
49449
|
-
var
|
|
49450
|
-
var
|
|
49621
|
+
var import_node_fs49 = require("node:fs");
|
|
49622
|
+
var import_node_os23 = require("node:os");
|
|
49623
|
+
var import_node_path46 = require("node:path");
|
|
49451
49624
|
var GC_GH_TIMEOUT_MS3 = 2e4;
|
|
49452
49625
|
async function collectStatus() {
|
|
49453
49626
|
const repo = await resolveRepo();
|
|
@@ -49636,10 +49809,10 @@ async function collectOnboardStatus(opts = {}) {
|
|
|
49636
49809
|
else if (top) nextCommand = `mmi-cli oracle board claim ${top.number} # ${top.title}`;
|
|
49637
49810
|
else nextCommand = "mmi-cli oracle board read \u2014 no claimable items found";
|
|
49638
49811
|
}
|
|
49639
|
-
const home = (0,
|
|
49812
|
+
const home = (0, import_node_os23.homedir)();
|
|
49640
49813
|
const plugin = onboardPluginGate({
|
|
49641
|
-
readKnown: () => readFileSyncSafe((0,
|
|
49642
|
-
readSettings: () => readFileSyncSafe((0,
|
|
49814
|
+
readKnown: () => readFileSyncSafe((0, import_node_path46.join)(home, ...KNOWN_MARKETPLACES_RELATIVE), import_node_fs49.readFileSync),
|
|
49815
|
+
readSettings: () => readFileSyncSafe((0, import_node_path46.join)(home, ".claude", "settings.json"), import_node_fs49.readFileSync)
|
|
49643
49816
|
});
|
|
49644
49817
|
return {
|
|
49645
49818
|
guide: "Read the MMI org-guide skill before project work; load only the relevant topic. Use mmi-help for a short introduction.",
|
|
@@ -51831,6 +52004,9 @@ function registerOrgHealthQuery(program3, deps = defaultOrgHealthQueryDeps()) {
|
|
|
51831
52004
|
});
|
|
51832
52005
|
}
|
|
51833
52006
|
|
|
52007
|
+
// src/api-read.ts
|
|
52008
|
+
var import_node_fs50 = require("node:fs");
|
|
52009
|
+
|
|
51834
52010
|
// src/app-read-broker.ts
|
|
51835
52011
|
init_cli_shared();
|
|
51836
52012
|
var OWNER_REPO_RE = /^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/;
|
|
@@ -52200,7 +52376,10 @@ var CONTENTS_QUERY_RE = /^ref=[^&\s]+$/;
|
|
|
52200
52376
|
var ACTIONS_RUNS_RE = new RegExp(`^repos/${NAME}/${NAME}/actions/runs$`);
|
|
52201
52377
|
var ACTIONS_RUN_RE = new RegExp(`^repos/${NAME}/${NAME}/actions/runs/\\d+$`);
|
|
52202
52378
|
var ACTIONS_JOBS_RE = new RegExp(`^repos/${NAME}/${NAME}/actions/runs/\\d+/jobs$`);
|
|
52203
|
-
var
|
|
52379
|
+
var ACTIONS_ARTIFACTS_RE = new RegExp(`^repos/${NAME}/${NAME}/actions/runs/\\d+/artifacts$`);
|
|
52380
|
+
var ACTIONS_ARTIFACT_ZIP_RE = new RegExp(`^repos/${NAME}/${NAME}/actions/artifacts/\\d+/zip$`);
|
|
52381
|
+
var ACTIONS_JOB_LOGS_RE = new RegExp(`^repos/${NAME}/${NAME}/actions/jobs/\\d+/logs$`);
|
|
52382
|
+
var API_GET_ALLOWED_SHAPES = "repos/{owner}/{repo}/pulls/{n}/files, repos/{owner}/{repo}/compare/{a}...{b}, repos/{owner}/{repo}/contents/{path}[?ref=<branch>], repos/{owner}/{repo}/actions/runs, repos/{owner}/{repo}/actions/runs/{id}, repos/{owner}/{repo}/actions/runs/{id}/jobs, repos/{owner}/{repo}/actions/runs/{id}/artifacts, repos/{owner}/{repo}/actions/artifacts/{id}/zip (needs --out <file>), repos/{owner}/{repo}/actions/jobs/{id}/logs (needs --out <file>)";
|
|
52204
52383
|
function parseApiGetPath(rawPath) {
|
|
52205
52384
|
const path2 = rawPath.trim();
|
|
52206
52385
|
const refuse = () => new Error(`api get: refusing '${rawPath}' \u2014 only these GET reads are allowed (#7219): ${API_GET_ALLOWED_SHAPES}`);
|
|
@@ -52210,6 +52389,9 @@ function parseApiGetPath(rawPath) {
|
|
|
52210
52389
|
if (ACTIONS_RUNS_RE.test(path2)) return { kind: "actions-runs", path: path2, paginate: true };
|
|
52211
52390
|
if (ACTIONS_RUN_RE.test(path2)) return { kind: "actions-run", path: path2, paginate: false };
|
|
52212
52391
|
if (ACTIONS_JOBS_RE.test(path2)) return { kind: "actions-jobs", path: path2, paginate: true };
|
|
52392
|
+
if (ACTIONS_ARTIFACTS_RE.test(path2)) return { kind: "actions-artifacts", path: path2, paginate: true };
|
|
52393
|
+
if (ACTIONS_ARTIFACT_ZIP_RE.test(path2)) return { kind: "actions-artifact-zip", path: path2, paginate: false };
|
|
52394
|
+
if (ACTIONS_JOB_LOGS_RE.test(path2)) return { kind: "actions-job-logs", path: path2, paginate: false };
|
|
52213
52395
|
const q = path2.indexOf("?");
|
|
52214
52396
|
const base = q === -1 ? path2 : path2.slice(0, q);
|
|
52215
52397
|
const query = q === -1 ? "" : path2.slice(q + 1);
|
|
@@ -52218,6 +52400,8 @@ function parseApiGetPath(rawPath) {
|
|
|
52218
52400
|
}
|
|
52219
52401
|
throw new Error(`api get: refusing '${rawPath}' \u2014 only these GET reads are allowed (#7219): ${API_GET_ALLOWED_SHAPES}`);
|
|
52220
52402
|
}
|
|
52403
|
+
var ZIP_TIMEOUT_MS = 12e4;
|
|
52404
|
+
var ZIP_MAX_BUFFER = 512 * 1024 * 1024;
|
|
52221
52405
|
function buildApiGetArgs(path2, accept) {
|
|
52222
52406
|
const req = parseApiGetPath(path2);
|
|
52223
52407
|
const args = ["api", req.path];
|
|
@@ -52230,22 +52414,28 @@ async function runApiGet(run, path2, accept) {
|
|
|
52230
52414
|
return run(buildApiGetArgs(path2, accept), GIT_TIMEOUT_MS);
|
|
52231
52415
|
}
|
|
52232
52416
|
function registerApiReadCommands(program3, overrides) {
|
|
52233
|
-
const spawn6 = overrides?.runner ?? (async (args, timeoutMs, env) => (await execFileP("gh", args, { timeout: timeoutMs, ...env ? { env } : {} })).stdout);
|
|
52234
|
-
const api = program3.command("api").description("bounded GitHub REST reads for automation \u2014 GET only, allowlisted paths (pull files, compare, contents, actions runs/jobs)");
|
|
52417
|
+
const spawn6 = overrides?.runner ?? (async (args, timeoutMs, env, binary) => (await execFileP("gh", args, { timeout: timeoutMs, ...binary ? { encoding: "latin1", maxBuffer: ZIP_MAX_BUFFER } : {}, ...env ? { env } : {} })).stdout);
|
|
52418
|
+
const api = program3.command("api").description("bounded GitHub REST reads for automation \u2014 GET only, allowlisted paths (pull files, compare, contents, actions runs/jobs/artifacts)");
|
|
52235
52419
|
api.command("get").description("GET one allowlisted REST path and print the response body to stdout (JSON, or raw file bytes with --accept raw); refuses everything outside the allowlist").option("--accept <type>", "response media type: json (default) or raw (file bytes)", (v) => {
|
|
52236
52420
|
acceptHeaderFor(v);
|
|
52237
52421
|
return v.trim().toLowerCase();
|
|
52238
|
-
}, "json").argument("<path>", "allowlisted GET path (shapes named on refusal)", (v) => parseApiGetPath(v)).action(async (req, o) => {
|
|
52422
|
+
}, "json").option("--out <file>", "write the response bytes to this file instead of stdout (required for, and only valid with, actions/artifacts/{id}/zip)").argument("<path>", "allowlisted GET path (shapes named on refusal)", (v) => parseApiGetPath(v)).action(async (req, o) => {
|
|
52423
|
+
const zip = req.kind === "actions-artifact-zip" || req.kind === "actions-job-logs";
|
|
52424
|
+
if (zip !== (o.out !== void 0)) return fail(`api get: --out <file> is required for, and only valid with, repos/{owner}/{repo}/actions/artifacts/{id}/zip and repos/{owner}/{repo}/actions/jobs/{id}/logs`);
|
|
52239
52425
|
const actionsRoute = req.kind.startsWith("actions-");
|
|
52240
52426
|
if (actionsRoute) requireBrokerApp("api get");
|
|
52241
52427
|
const env = actionsRoute || process.env.MMI_ACTOR === "app" ? brokerChildEnv() : void 0;
|
|
52242
52428
|
let body;
|
|
52243
52429
|
try {
|
|
52244
52430
|
body = await runApiGet(
|
|
52245
|
-
async (args, timeoutMs) => spawn6(args, timeoutMs, env),
|
|
52431
|
+
async (args, timeoutMs) => zip ? spawn6(args, ZIP_TIMEOUT_MS, env, true) : spawn6(args, timeoutMs, env),
|
|
52246
52432
|
req.path,
|
|
52247
52433
|
o.accept
|
|
52248
52434
|
);
|
|
52435
|
+
if (zip) {
|
|
52436
|
+
(0, import_node_fs50.writeFileSync)(o.out, body, "latin1");
|
|
52437
|
+
return;
|
|
52438
|
+
}
|
|
52249
52439
|
} catch (e) {
|
|
52250
52440
|
const err = e;
|
|
52251
52441
|
return fail(`api get: ${(err.stderr || err.message || String(e)).trim()}`);
|
|
@@ -53102,8 +53292,8 @@ function registerSessionReport(program3) {
|
|
|
53102
53292
|
}
|
|
53103
53293
|
|
|
53104
53294
|
// src/stage-commands.ts
|
|
53105
|
-
var
|
|
53106
|
-
var
|
|
53295
|
+
var import_node_fs51 = require("node:fs");
|
|
53296
|
+
var import_node_path47 = require("node:path");
|
|
53107
53297
|
init_cli_shared();
|
|
53108
53298
|
init_clean_exit();
|
|
53109
53299
|
|
|
@@ -53351,8 +53541,8 @@ function registerStageCommands(program3) {
|
|
|
53351
53541
|
const repo = Array.isArray(project2?.repos) && typeof project2.repos[0] === "string" ? project2.repos[0] : slug;
|
|
53352
53542
|
const resolution = decideStage({
|
|
53353
53543
|
registry: { deployModel: project2?.deployModel, portRange, error: read.ok ? void 0 : read.error },
|
|
53354
|
-
hasCompose: (0,
|
|
53355
|
-
hasEnvExample: (0,
|
|
53544
|
+
hasCompose: (0, import_node_fs51.existsSync)((0, import_node_path47.join)(process.cwd(), "docker-compose.yml")),
|
|
53545
|
+
hasEnvExample: (0, import_node_fs51.existsSync)((0, import_node_path47.join)(process.cwd(), ".env.example")),
|
|
53356
53546
|
repo
|
|
53357
53547
|
});
|
|
53358
53548
|
if (resolution.source === "derived" && resolution.derived) {
|
|
@@ -53644,23 +53834,23 @@ vercel preview (${preview.branch}): ${d.state}${d.url ? ` \u2014 ${d.url}` : ""}
|
|
|
53644
53834
|
}
|
|
53645
53835
|
|
|
53646
53836
|
// src/tenant-artifact.ts
|
|
53647
|
-
var
|
|
53648
|
-
var
|
|
53837
|
+
var import_node_crypto17 = require("node:crypto");
|
|
53838
|
+
var import_node_fs52 = require("node:fs");
|
|
53649
53839
|
var import_promises11 = require("node:fs/promises");
|
|
53650
|
-
var
|
|
53840
|
+
var import_node_path48 = require("node:path");
|
|
53651
53841
|
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}$/;
|
|
53652
|
-
var
|
|
53842
|
+
var MAX_BYTES2 = 5 * 1024 * 1024 * 1024;
|
|
53653
53843
|
async function sha256File(path2) {
|
|
53654
|
-
const hash = (0,
|
|
53655
|
-
for await (const chunk of (0,
|
|
53844
|
+
const hash = (0, import_node_crypto17.createHash)("sha256");
|
|
53845
|
+
for await (const chunk of (0, import_node_fs52.createReadStream)(path2)) hash.update(chunk);
|
|
53656
53846
|
return hash.digest("hex");
|
|
53657
53847
|
}
|
|
53658
53848
|
async function putTenantArtifact(repo, stage, inputPath, deps) {
|
|
53659
53849
|
if (!["dev", "rc", "main"].includes(stage)) throw new Error("tenant artifact put: <stage> must be dev, rc, or main");
|
|
53660
|
-
const path2 = (0,
|
|
53850
|
+
const path2 = (0, import_node_path48.resolve)(inputPath);
|
|
53661
53851
|
const info = await (0, import_promises11.stat)(path2);
|
|
53662
53852
|
if (!info.isFile()) throw new Error("tenant artifact put: input path must be a file");
|
|
53663
|
-
if (!Number.isSafeInteger(info.size) || info.size < 1 || info.size >
|
|
53853
|
+
if (!Number.isSafeInteger(info.size) || info.size < 1 || info.size > MAX_BYTES2) throw new Error(`tenant artifact put: file must be 1..${MAX_BYTES2} bytes`);
|
|
53664
53854
|
const sha2563 = await sha256File(path2);
|
|
53665
53855
|
const prepared = await tenantArtifactUpload({ repo, stage, size: info.size, sha256: sha2563 }, deps);
|
|
53666
53856
|
if (!prepared.ok) {
|
|
@@ -53675,7 +53865,7 @@ async function putTenantArtifact(repo, stage, inputPath, deps) {
|
|
|
53675
53865
|
return [key, value];
|
|
53676
53866
|
}));
|
|
53677
53867
|
headers["content-length"] = String(info.size);
|
|
53678
|
-
const stream = (0,
|
|
53868
|
+
const stream = (0, import_node_fs52.createReadStream)(path2);
|
|
53679
53869
|
let uploaded;
|
|
53680
53870
|
try {
|
|
53681
53871
|
uploaded = await fetch(body.uploadUrl, {
|
|
@@ -53814,7 +54004,7 @@ function renderVerifySecrets(body) {
|
|
|
53814
54004
|
}
|
|
53815
54005
|
|
|
53816
54006
|
// src/command-register-developer.ts
|
|
53817
|
-
var
|
|
54007
|
+
var import_node_fs56 = require("node:fs");
|
|
53818
54008
|
init_clean_exit();
|
|
53819
54009
|
init_cli_shared();
|
|
53820
54010
|
init_error_codes();
|
|
@@ -53847,7 +54037,7 @@ async function resolveWhoami(deps) {
|
|
|
53847
54037
|
}
|
|
53848
54038
|
|
|
53849
54039
|
// src/command-register-developer.ts
|
|
53850
|
-
var
|
|
54040
|
+
var import_node_path53 = require("node:path");
|
|
53851
54041
|
init_house_map();
|
|
53852
54042
|
init_hub_url();
|
|
53853
54043
|
|
|
@@ -53881,28 +54071,28 @@ async function executeWaveLand(plan, deps) {
|
|
|
53881
54071
|
|
|
53882
54072
|
// src/dist-drift.ts
|
|
53883
54073
|
var import_node_child_process19 = require("node:child_process");
|
|
53884
|
-
var
|
|
53885
|
-
var
|
|
53886
|
-
var
|
|
53887
|
-
var
|
|
54074
|
+
var import_node_crypto19 = require("node:crypto");
|
|
54075
|
+
var import_node_fs54 = require("node:fs");
|
|
54076
|
+
var import_node_os24 = require("node:os");
|
|
54077
|
+
var import_node_path50 = require("node:path");
|
|
53888
54078
|
|
|
53889
54079
|
// ../scripts/distribution-digest.mjs
|
|
53890
|
-
var
|
|
53891
|
-
var
|
|
53892
|
-
var
|
|
54080
|
+
var import_node_crypto18 = require("node:crypto");
|
|
54081
|
+
var import_node_fs53 = require("node:fs");
|
|
54082
|
+
var import_node_path49 = require("node:path");
|
|
53893
54083
|
var slash = (value) => value.replaceAll("\\", "/");
|
|
53894
54084
|
function repoPath(root, declaredPath, label) {
|
|
53895
|
-
const absoluteRoot = (0,
|
|
53896
|
-
const target = (0,
|
|
53897
|
-
if (target !== absoluteRoot && !target.startsWith(`${absoluteRoot}${
|
|
54085
|
+
const absoluteRoot = (0, import_node_path49.resolve)(root);
|
|
54086
|
+
const target = (0, import_node_path49.resolve)(root, declaredPath);
|
|
54087
|
+
if (target !== absoluteRoot && !target.startsWith(`${absoluteRoot}${import_node_path49.sep}`)) {
|
|
53898
54088
|
throw new Error(`${label} ${declaredPath} escapes the repository root`);
|
|
53899
54089
|
}
|
|
53900
54090
|
return target;
|
|
53901
54091
|
}
|
|
53902
54092
|
function digestFiles(files) {
|
|
53903
|
-
const hash = (0,
|
|
54093
|
+
const hash = (0, import_node_crypto18.createHash)("sha256");
|
|
53904
54094
|
for (const file of [...files].sort((a, b) => a.relative.localeCompare(b.relative))) {
|
|
53905
|
-
const content = file.stat.isSymbolicLink() ? Buffer.from((0,
|
|
54095
|
+
const content = file.stat.isSymbolicLink() ? Buffer.from((0, import_node_fs53.readlinkSync)(file.absolute), "utf8") : (0, import_node_fs53.readFileSync)(file.absolute);
|
|
53906
54096
|
hash.update(file.relative, "utf8");
|
|
53907
54097
|
hash.update("\0");
|
|
53908
54098
|
hash.update(file.stat.isSymbolicLink() ? "symlink" : "file", "utf8");
|
|
@@ -53917,8 +54107,8 @@ function digestFiles(files) {
|
|
|
53917
54107
|
function digestPackedFiles(packageRoot, packedFiles) {
|
|
53918
54108
|
return digestFiles(packedFiles.map((path2) => {
|
|
53919
54109
|
const absolute = repoPath(packageRoot, path2, "packed artifact identity path");
|
|
53920
|
-
if (!(0,
|
|
53921
|
-
return { absolute, relative: slash(path2), stat: (0,
|
|
54110
|
+
if (!(0, import_node_fs53.existsSync)(absolute)) throw new Error(`packed artifact identity path ${path2} does not exist`);
|
|
54111
|
+
return { absolute, relative: slash(path2), stat: (0, import_node_fs53.lstatSync)(absolute) };
|
|
53922
54112
|
}));
|
|
53923
54113
|
}
|
|
53924
54114
|
|
|
@@ -53930,7 +54120,7 @@ var DIST_ARTIFACTS = [
|
|
|
53930
54120
|
];
|
|
53931
54121
|
var BOM_DIST_TREE_ID = "mmi-cli-dist";
|
|
53932
54122
|
var ABSENT = "absent";
|
|
53933
|
-
var sha2562 = (bytes) => `sha256:${(0,
|
|
54123
|
+
var sha2562 = (bytes) => `sha256:${(0, import_node_crypto19.createHash)("sha256").update(bytes).digest("hex")}`;
|
|
53934
54124
|
function artifactDrift(path2, committedBytes, rebuiltBytes) {
|
|
53935
54125
|
const committed = committedBytes ? sha2562(committedBytes) : ABSENT;
|
|
53936
54126
|
const rebuiltExpected = rebuiltBytes ? sha2562(rebuiltBytes) : ABSENT;
|
|
@@ -54002,13 +54192,13 @@ function renderDistDriftReceipt(receipt) {
|
|
|
54002
54192
|
return lines2;
|
|
54003
54193
|
}
|
|
54004
54194
|
function readOrNull(path2) {
|
|
54005
|
-
return (0,
|
|
54195
|
+
return (0, import_node_fs54.existsSync)(path2) ? (0, import_node_fs54.readFileSync)(path2) : null;
|
|
54006
54196
|
}
|
|
54007
54197
|
function walkFiles(root) {
|
|
54008
54198
|
const files = [];
|
|
54009
54199
|
const walk2 = (directory) => {
|
|
54010
|
-
for (const entry of (0,
|
|
54011
|
-
const child2 = (0,
|
|
54200
|
+
for (const entry of (0, import_node_fs54.readdirSync)(directory, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
|
|
54201
|
+
const child2 = (0, import_node_path50.join)(directory, entry.name);
|
|
54012
54202
|
if (entry.isDirectory()) walk2(child2);
|
|
54013
54203
|
else files.push(child2);
|
|
54014
54204
|
}
|
|
@@ -54018,10 +54208,10 @@ function walkFiles(root) {
|
|
|
54018
54208
|
}
|
|
54019
54209
|
function bomPathFor(root) {
|
|
54020
54210
|
try {
|
|
54021
|
-
const registry2 = JSON.parse((0,
|
|
54022
|
-
return (0,
|
|
54211
|
+
const registry2 = JSON.parse((0, import_node_fs54.readFileSync)((0, import_node_path50.join)(root, "surfaces.json"), "utf8"));
|
|
54212
|
+
return (0, import_node_path50.join)(root, registry2?.sharedAgentCore?.releaseMetadata?.bomPath ?? "distribution-bom.json");
|
|
54023
54213
|
} catch {
|
|
54024
|
-
return (0,
|
|
54214
|
+
return (0, import_node_path50.join)(root, "distribution-bom.json");
|
|
54025
54215
|
}
|
|
54026
54216
|
}
|
|
54027
54217
|
function rebuildTo(packageRoot, outDir) {
|
|
@@ -54034,35 +54224,35 @@ function rebuildTo(packageRoot, outDir) {
|
|
|
54034
54224
|
});
|
|
54035
54225
|
}
|
|
54036
54226
|
function runDistStatus(root) {
|
|
54037
|
-
const stage = (0,
|
|
54227
|
+
const stage = (0, import_node_fs54.mkdtempSync)((0, import_node_path50.join)((0, import_node_os24.tmpdir)(), "mmi-dist-drift-"));
|
|
54038
54228
|
let overlayCount = 0;
|
|
54039
54229
|
try {
|
|
54040
|
-
const cliOut = (0,
|
|
54041
|
-
const hubOut = (0,
|
|
54042
|
-
rebuildTo((0,
|
|
54043
|
-
rebuildTo((0,
|
|
54230
|
+
const cliOut = (0, import_node_path50.join)(stage, "cli-dist");
|
|
54231
|
+
const hubOut = (0, import_node_path50.join)(stage, "hub-dist");
|
|
54232
|
+
rebuildTo((0, import_node_path50.join)(root, "cli"), cliOut);
|
|
54233
|
+
rebuildTo((0, import_node_path50.join)(root, "updater"), hubOut);
|
|
54044
54234
|
const outDirFor = (packageDir) => packageDir === "cli" ? cliOut : hubOut;
|
|
54045
54235
|
const rebuilt = (path2) => {
|
|
54046
54236
|
const spec = DIST_ARTIFACTS.find((entry) => entry.path === path2);
|
|
54047
|
-
return spec ? readOrNull((0,
|
|
54237
|
+
return spec ? readOrNull((0, import_node_path50.join)(outDirFor(spec.packageDir), spec.output)) : null;
|
|
54048
54238
|
};
|
|
54049
|
-
const committed = (path2) => readOrNull((0,
|
|
54050
|
-
const tree = (path2) => readOrNull((0,
|
|
54051
|
-
const distRoot = (0,
|
|
54052
|
-
const distTree = () => walkFiles(distRoot).map((absolute) => `cli/dist/${(0,
|
|
54053
|
-
const bom = JSON.parse((0,
|
|
54239
|
+
const committed = (path2) => readOrNull((0, import_node_path50.join)(root, path2));
|
|
54240
|
+
const tree = (path2) => readOrNull((0, import_node_path50.join)(root, path2));
|
|
54241
|
+
const distRoot = (0, import_node_path50.join)(root, "cli", "dist");
|
|
54242
|
+
const distTree = () => walkFiles(distRoot).map((absolute) => `cli/dist/${(0, import_node_path50.relative)(distRoot, absolute).replaceAll("\\", "/")}`);
|
|
54243
|
+
const bom = JSON.parse((0, import_node_fs54.readFileSync)(bomPathFor(root), "utf8"));
|
|
54054
54244
|
const digest = (entries) => {
|
|
54055
|
-
const overlay = (0,
|
|
54245
|
+
const overlay = (0, import_node_path50.join)(stage, `overlay-${overlayCount++}`);
|
|
54056
54246
|
for (const entry of entries) {
|
|
54057
|
-
const target = (0,
|
|
54058
|
-
(0,
|
|
54059
|
-
(0,
|
|
54247
|
+
const target = (0, import_node_path50.join)(overlay, entry.path);
|
|
54248
|
+
(0, import_node_fs54.mkdirSync)((0, import_node_path50.dirname)(target), { recursive: true });
|
|
54249
|
+
(0, import_node_fs54.writeFileSync)(target, entry.bytes);
|
|
54060
54250
|
}
|
|
54061
54251
|
return digestPackedFiles(overlay, entries.map((entry) => entry.path));
|
|
54062
54252
|
};
|
|
54063
54253
|
return computeDistDriftReceipt({ committed, tree, rebuilt, distTree, bom, digest });
|
|
54064
54254
|
} finally {
|
|
54065
|
-
(0,
|
|
54255
|
+
(0, import_node_fs54.rmSync)(stage, { recursive: true, force: true });
|
|
54066
54256
|
}
|
|
54067
54257
|
}
|
|
54068
54258
|
|
|
@@ -54163,7 +54353,7 @@ init_hub_auth();
|
|
|
54163
54353
|
|
|
54164
54354
|
// src/schedules-lift-command.ts
|
|
54165
54355
|
var import_promises12 = require("node:fs/promises");
|
|
54166
|
-
var
|
|
54356
|
+
var import_node_path51 = require("node:path");
|
|
54167
54357
|
init_clean_exit();
|
|
54168
54358
|
init_cli_shared();
|
|
54169
54359
|
var DEFAULT_WORKFLOWS_DIR = ".github/workflows";
|
|
@@ -54192,7 +54382,7 @@ async function readWorkflowFiles(dir) {
|
|
|
54192
54382
|
const files = [];
|
|
54193
54383
|
for (const name of names.sort()) {
|
|
54194
54384
|
if (!/\.ya?ml$/.test(name)) continue;
|
|
54195
|
-
files.push({ path: `.github/workflows/${name}`, text: await (0, import_promises12.readFile)((0,
|
|
54385
|
+
files.push({ path: `.github/workflows/${name}`, text: await (0, import_promises12.readFile)((0, import_node_path51.join)(dir, name), "utf8") });
|
|
54196
54386
|
}
|
|
54197
54387
|
return files;
|
|
54198
54388
|
}
|
|
@@ -54275,8 +54465,8 @@ function registerSchedulesLiftCommand(program3, deps = {}) {
|
|
|
54275
54465
|
|
|
54276
54466
|
// src/spawn-policy-core.ts
|
|
54277
54467
|
var import_node_child_process20 = require("node:child_process");
|
|
54278
|
-
var
|
|
54279
|
-
var
|
|
54468
|
+
var import_node_fs55 = require("node:fs");
|
|
54469
|
+
var import_node_path52 = require("node:path");
|
|
54280
54470
|
var SPAWNERS = ["spawn", "spawnSync", "exec", "execSync", "execFile", "execFileSync"];
|
|
54281
54471
|
var CALL_SOURCE = String.raw`(^|[^.\w$])(${SPAWNERS.join("|")})\s*\(`;
|
|
54282
54472
|
var SOURCE_EXT = /\.(ts|mts|cts|js|mjs|cjs)$/;
|
|
@@ -54362,7 +54552,7 @@ function runSpawnPolicy(root) {
|
|
|
54362
54552
|
for (const file of files) {
|
|
54363
54553
|
let raw;
|
|
54364
54554
|
try {
|
|
54365
|
-
raw = (0,
|
|
54555
|
+
raw = (0, import_node_fs55.readFileSync)((0, import_node_path52.join)(root, file), "utf8");
|
|
54366
54556
|
} catch {
|
|
54367
54557
|
continue;
|
|
54368
54558
|
}
|
|
@@ -54382,19 +54572,19 @@ function runSpawnPolicy(root) {
|
|
|
54382
54572
|
function registerDeveloperCommands(program3) {
|
|
54383
54573
|
const rules = program3.command("rules").description("org-managed .gitignore delivery");
|
|
54384
54574
|
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) => {
|
|
54385
|
-
const path2 = (0,
|
|
54386
|
-
const current = (0,
|
|
54575
|
+
const path2 = (0, import_node_path53.join)(process.cwd(), ".gitignore");
|
|
54576
|
+
const current = (0, import_node_fs56.existsSync)(path2) ? (0, import_node_fs56.readFileSync)(path2, "utf8") : null;
|
|
54387
54577
|
const plan = planManagedGitignore(current);
|
|
54388
54578
|
const drift = [...plan.added.map((l) => `+${l}`), ...plan.removed.map((l) => `-${l}`)].join(", ") || "block normalize";
|
|
54389
54579
|
if (opts.json) {
|
|
54390
|
-
if (opts.write && plan.changed) (0,
|
|
54580
|
+
if (opts.write && plan.changed) (0, import_node_fs56.writeFileSync)(path2, plan.content, "utf8");
|
|
54391
54581
|
console.log(JSON.stringify(plan, null, 2));
|
|
54392
54582
|
if (!opts.write && plan.changed) process.exitCode = 1;
|
|
54393
54583
|
return;
|
|
54394
54584
|
}
|
|
54395
54585
|
if (opts.write) {
|
|
54396
54586
|
if (plan.changed) {
|
|
54397
|
-
(0,
|
|
54587
|
+
(0, import_node_fs56.writeFileSync)(path2, plan.content, "utf8");
|
|
54398
54588
|
console.log(`mmi-cli devops org rules gitignore: updated .gitignore (${drift})`);
|
|
54399
54589
|
} else {
|
|
54400
54590
|
console.log("mmi-cli devops org rules gitignore: up to date");
|
|
@@ -54657,12 +54847,12 @@ ${r.stderr ?? ""}`).catch(() => "");
|
|
|
54657
54847
|
var ENV_HEAL_LOCK_STALE_MS = 10 * 6e4;
|
|
54658
54848
|
var ENV_HEAL_LOCK_MAX_WAIT_MS = 2 * 6e4;
|
|
54659
54849
|
function envHealLockPath(home) {
|
|
54660
|
-
return (0,
|
|
54850
|
+
return (0, import_node_path54.join)(home, ".claude", "plugins", ".mmi-env-heal.lock");
|
|
54661
54851
|
}
|
|
54662
54852
|
async function withEnvHealLock(what, run) {
|
|
54663
54853
|
try {
|
|
54664
54854
|
return await withFileLock(
|
|
54665
|
-
envHealLockPath((0,
|
|
54855
|
+
envHealLockPath((0, import_node_os25.homedir)()),
|
|
54666
54856
|
{ staleMs: ENV_HEAL_LOCK_STALE_MS, maxWaitMs: ENV_HEAL_LOCK_MAX_WAIT_MS, label: "mmi env-heal lock" },
|
|
54667
54857
|
run
|
|
54668
54858
|
);
|
|
@@ -54759,7 +54949,7 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
54759
54949
|
const configRoot = surfaceConfigRoot(surface);
|
|
54760
54950
|
const running = surface === "codex" ? installedActivePluginVersion(surface) : runningPluginVersion(process.env, resolveClientVersion());
|
|
54761
54951
|
const plan = buildPluginCachePlan(
|
|
54762
|
-
(0,
|
|
54952
|
+
(0, import_node_os25.homedir)(),
|
|
54763
54953
|
running,
|
|
54764
54954
|
pluginCacheFsDeps(configRoot, () => 0),
|
|
54765
54955
|
{ configRoot, includeStaging: surface !== "codex" }
|
|
@@ -54787,14 +54977,14 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
54787
54977
|
const running = surface === "codex" ? installedActivePluginVersion(surface) : runningPluginVersion(process.env, resolveClientVersion());
|
|
54788
54978
|
const installed = installedActivePluginVersion(surface);
|
|
54789
54979
|
const plan = buildPluginCachePlan(
|
|
54790
|
-
(0,
|
|
54980
|
+
(0, import_node_os25.homedir)(),
|
|
54791
54981
|
running,
|
|
54792
54982
|
pluginCacheFsDeps(configRoot, () => 0),
|
|
54793
54983
|
{ configRoot, includeStaging: surface !== "codex", installedVersion: installed }
|
|
54794
54984
|
);
|
|
54795
54985
|
const result = applyPluginCachePlan(
|
|
54796
54986
|
plan,
|
|
54797
|
-
(p) => (0,
|
|
54987
|
+
(p) => (0, import_node_fs57.rmSync)(p, { recursive: true }),
|
|
54798
54988
|
stagingApplyFsGuard(configRoot)
|
|
54799
54989
|
);
|
|
54800
54990
|
return {
|
|
@@ -54829,7 +55019,7 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
54829
55019
|
// has no generated routing index would
|
|
54830
55020
|
// get a permanent — demanding an artifact it never asked for.
|
|
54831
55021
|
docsIndexState: (root) => {
|
|
54832
|
-
if (!(0,
|
|
55022
|
+
if (!(0, import_node_fs57.existsSync)((0, import_node_path54.join)(root, DOCS_INDEX_PATH))) return void 0;
|
|
54833
55023
|
const real = createDocsIndexDeps(root);
|
|
54834
55024
|
let docs;
|
|
54835
55025
|
const listDocs = () => docs ??= real.listDocs();
|
|
@@ -54838,7 +55028,7 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
54838
55028
|
},
|
|
54839
55029
|
// #4168: working-tree heal — write if drifted, then re-check. Commit remains the operator's step.
|
|
54840
55030
|
healDocsIndex: (root) => {
|
|
54841
|
-
if (!(0,
|
|
55031
|
+
if (!(0, import_node_fs57.existsSync)((0, import_node_path54.join)(root, DOCS_INDEX_PATH))) return { drift: false, docCount: 0 };
|
|
54842
55032
|
const real = createDocsIndexDeps(root);
|
|
54843
55033
|
let docs;
|
|
54844
55034
|
const listDocs = () => docs ??= real.listDocs();
|
|
@@ -55187,10 +55377,13 @@ program2.addHelpText(
|
|
|
55187
55377
|
var appActorCommand = "poll";
|
|
55188
55378
|
function appActorDeps() {
|
|
55189
55379
|
return {
|
|
55190
|
-
fetchSecret: async (key) =>
|
|
55191
|
-
|
|
55192
|
-
|
|
55193
|
-
|
|
55380
|
+
fetchSecret: async (key) => {
|
|
55381
|
+
const deps = makeSecretsDeps(await loadConfig());
|
|
55382
|
+
return readAppVaultSecret(() => fetchSecretValue(deps, key, {
|
|
55383
|
+
repo: APP_VAULT_REPO,
|
|
55384
|
+
attribution: { command: appActorCommand, via: formatSessionIdentity(describeSessionIdentity()) }
|
|
55385
|
+
}, true));
|
|
55386
|
+
},
|
|
55194
55387
|
fetch: (url, init) => fetch(url, init)
|
|
55195
55388
|
};
|
|
55196
55389
|
}
|
|
@@ -55218,8 +55411,9 @@ async function reportWrite(label, res) {
|
|
|
55218
55411
|
return failGraceful(`${label}: HTTP ${res.status}${detail ? ` \u2014 ${detail}` : ""}`);
|
|
55219
55412
|
}
|
|
55220
55413
|
var tenant = program2.command("tenant").description("tenant runtime control through Hub authority");
|
|
55221
|
-
tenant.command("control <owner/repo> <stage> <action>").description("bounded tenant control plus value-free vault/broker verification; dev/main retire needs master and exact data-loss confirmation").option("--watch", "block on the dispatched run and report its conclusion (status/retire/verify-secrets/verify-broker/logs watch by default)").option("--lines <n>", "logs only: trailing lines of the tenant service to return (1-2000, default 200)").option("--since <utc>", "logs only: read the journal from this UTC time, e.g. 2026-10-07T13:10Z (includes replaced containers)").option("--until <utc>", "logs only: read the journal up to this UTC time").option("--edge", "logs only: Caddy journal for this stage\u2019s hosts (default window: last 15 minutes)").option("--task <name>", "run-task only: registry-declared task name (never a command)").option("--artifact <id>", "run-task only: opaque id returned by tenant artifact put").option("--confirm-data-loss <owner/repo/stage>", "dev/main retire only: exact target to decommission; without it show the dry-run plan").option("--json", "machine-readable output").action(async (repo, stage, action, o) => {
|
|
55414
|
+
tenant.command("control <owner/repo> <stage> <action>").description("bounded tenant control plus value-free vault/broker verification; dev/main retire needs master and exact data-loss confirmation").option("--watch", "block on the dispatched run and report its conclusion (status/retire/verify-secrets/verify-broker/logs watch by default)").option("--lines <n>", "logs only: trailing lines of the tenant service to return (1-2000, default 200)").option("--since <utc>", "logs only: read the journal from this UTC time, e.g. 2026-10-07T13:10Z (includes replaced containers)").option("--until <utc>", "logs only: read the journal up to this UTC time").option("--edge", "logs only: Caddy journal for this stage\u2019s hosts (default window: last 15 minutes)").option("--task <name>", "run-task only: registry-declared task name (never a command)").option("--artifact <id>", "run-task only: opaque id returned by tenant artifact put").option("--resume <run-id>", "run-task only: re-attach to an already-dispatched run (read-only, never re-dispatches) and print its receipt").option("--confirm-data-loss <owner/repo/stage>", "dev/main retire only: exact target to decommission; without it show the dry-run plan").option("--json", "machine-readable output").action(async (repo, stage, action, o) => {
|
|
55222
55415
|
try {
|
|
55416
|
+
if (o.resume !== void 0 && (action !== "run-task" || !/^\d+$/.test(o.resume) || o.task || o.artifact)) return fail("runtime tenant control: --resume <run-id> is run-task-only, takes a numeric run id, and cannot be combined with --task/--artifact");
|
|
55223
55417
|
if (o.confirmDataLoss !== void 0 && (action !== "retire" || stage === "rc")) return fail("runtime tenant control: --confirm-data-loss is dev/main retire-only");
|
|
55224
55418
|
if (action === "retire" && (stage === "dev" || stage === "main")) {
|
|
55225
55419
|
if (o.confirmDataLoss !== void 0 && o.confirmDataLoss !== `${repo}/${stage}`) return fail(`runtime tenant control: --confirm-data-loss must match ${repo}/${stage} exactly`);
|
|
@@ -55244,11 +55438,11 @@ Dry run: pass --confirm-data-loss ${repo}/${stage} to decommission.`);
|
|
|
55244
55438
|
if (!/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(:\d{2})?Z$/.test(value)) return fail(`runtime tenant control: ${flag} must be a UTC time like 2026-10-07T13:10Z`);
|
|
55245
55439
|
}
|
|
55246
55440
|
if (action === "run-task") {
|
|
55247
|
-
if (!o.task) return fail("runtime tenant control: run-task requires --task <declared-name>");
|
|
55441
|
+
if (!o.task && o.resume === void 0) return fail("runtime tenant control: run-task requires --task <declared-name>");
|
|
55248
55442
|
} else if (o.task || o.artifact) {
|
|
55249
55443
|
return fail("runtime tenant control: --task/--artifact are valid only for run-task");
|
|
55250
55444
|
}
|
|
55251
|
-
const result = await runTenantControl(trainApplyDeps(), { repo, stage, action, watch: o.watch, lines: lines2, edge: o.edge, logSince: o.since, logUntil: o.until, task: o.task, artifact: o.artifact, confirmDataLoss: o.confirmDataLoss });
|
|
55445
|
+
const result = await runTenantControl(trainApplyDeps(), { repo, stage, action, watch: o.watch, lines: lines2, edge: o.edge, logSince: o.since, logUntil: o.until, task: o.task, artifact: o.artifact, confirmDataLoss: o.confirmDataLoss, resume: o.resume === void 0 ? void 0 : Number(o.resume) });
|
|
55252
55446
|
if (!o.json && action === "verify-secrets" && result.secrets) {
|
|
55253
55447
|
const body = { ok: result.conclusion === "success", secrets: result.secrets, ssmStatus: result.conclusion === "success" ? "Success" : "Failed", raw: result.secretsRaw };
|
|
55254
55448
|
const { lines: lines3, failure } = renderVerifySecrets(body);
|
|
@@ -55552,7 +55746,7 @@ project.command("set [owner/repo]").description("upsert project META (idempotent
|
|
|
55552
55746
|
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`);
|
|
55553
55747
|
if (o.secretsFile) {
|
|
55554
55748
|
try {
|
|
55555
|
-
vars.push(`secrets=${(0,
|
|
55749
|
+
vars.push(`secrets=${(0, import_node_fs57.readFileSync)(o.secretsFile, "utf8")}`);
|
|
55556
55750
|
} catch (e) {
|
|
55557
55751
|
return fail(`org project set: cannot read --secrets-file ${o.secretsFile}: ${e.message}`);
|
|
55558
55752
|
}
|
|
@@ -55821,9 +56015,11 @@ projectTenantTasks.command("declare <name>").description("register a NEW tenant
|
|
|
55821
56015
|
if (!res.ok) process.exitCode = 1;
|
|
55822
56016
|
});
|
|
55823
56017
|
var registry = program2.command("registry").description("the DDB org registry \u2014 org-level constants");
|
|
55824
|
-
registry.command("org").description("the org config (account id, region, orgProjectId, sagaApiUrl)").option("--json", "machine-readable output").action(async (_o) => {
|
|
56018
|
+
registry.command("org").description("the org config (account id, region, orgProjectId, sagaApiUrl)").option("--json", "machine-readable output").option("--github-spend-minutes <minutes>", "master-only App spend by route, caller and pool over the last 1\u201360 minutes").action(async (_o) => {
|
|
56019
|
+
const minutes = _o.githubSpendMinutes === void 0 ? void 0 : Number(_o.githubSpendMinutes);
|
|
56020
|
+
if (minutes !== void 0 && (!Number.isInteger(minutes) || minutes < 1 || minutes > 60)) return fail("github-spend-minutes must be an integer from 1 to 60");
|
|
55825
56021
|
const cfg = await loadConfig();
|
|
55826
|
-
const org = await fetchOrgConfig(registryClientDeps(cfg));
|
|
56022
|
+
const org = await fetchOrgConfig(registryClientDeps(cfg), minutes);
|
|
55827
56023
|
if (!org) return failGraceful("org config get: Hub API unreachable, unseeded, or this repo is not bootstrapped");
|
|
55828
56024
|
console.log(JSON.stringify(org));
|
|
55829
56025
|
});
|
|
@@ -55940,16 +56136,16 @@ function ciAuditDeps2() {
|
|
|
55940
56136
|
// gate re-seed step is skipped gracefully rather than failing mid-run.
|
|
55941
56137
|
readSeedFile: (path2) => {
|
|
55942
56138
|
if (!root) return null;
|
|
55943
|
-
const fullPath = (0,
|
|
55944
|
-
return (0,
|
|
56139
|
+
const fullPath = (0, import_node_path54.join)(root, path2);
|
|
56140
|
+
return (0, import_node_fs57.existsSync)(fullPath) ? (0, import_node_fs57.readFileSync)(fullPath, "utf8") : null;
|
|
55945
56141
|
}
|
|
55946
56142
|
};
|
|
55947
56143
|
}
|
|
55948
56144
|
function hubRoot2() {
|
|
55949
|
-
const fromPkg = (0,
|
|
56145
|
+
const fromPkg = (0, import_node_path54.join)(__dirname, "..", "..");
|
|
55950
56146
|
const marker = "skills/bootstrap/seeds/manifest.json";
|
|
55951
|
-
if ((0,
|
|
55952
|
-
if ((0,
|
|
56147
|
+
if ((0, import_node_fs57.existsSync)((0, import_node_path54.join)(fromPkg, marker))) return fromPkg;
|
|
56148
|
+
if ((0, import_node_fs57.existsSync)((0, import_node_path54.join)(process.cwd(), marker))) return process.cwd();
|
|
55953
56149
|
return null;
|
|
55954
56150
|
}
|
|
55955
56151
|
registerQueryCommands(program2);
|
|
@@ -56079,10 +56275,10 @@ access.command("audit").description("audit collaborator roles + train-branch pus
|
|
|
56079
56275
|
targets = resolution.targets;
|
|
56080
56276
|
}
|
|
56081
56277
|
const derivedMatrix = registryProjects ? accessMatrixFromProjects(registryProjects) : {};
|
|
56082
|
-
const fileMatrix = (0,
|
|
56278
|
+
const fileMatrix = (0, import_node_fs57.existsSync)("access-matrix.json") ? loadAccessMatrix((0, import_node_fs57.readFileSync)("access-matrix.json", "utf8")) : {};
|
|
56083
56279
|
const matrix = mergeAccessMatrix(fileMatrix, derivedMatrix);
|
|
56084
56280
|
const dataAccess = registryProjects ? dataAccessContractsFromProjects(registryProjects) : { consumers: {} };
|
|
56085
|
-
const sanctioned = (0,
|
|
56281
|
+
const sanctioned = (0, import_node_fs57.existsSync)("access-matrix.json") ? loadSanctionedAdmins((0, import_node_fs57.readFileSync)("access-matrix.json", "utf8")) : {};
|
|
56086
56282
|
const report = await auditOrgAccess(targets, deps, matrix, dataAccess, sanctioned);
|
|
56087
56283
|
console.log(o.json ? JSON.stringify(report, null, 2) : renderAccessReport(report));
|
|
56088
56284
|
if (!report.ok) process.exitCode = 1;
|
|
@@ -56113,16 +56309,16 @@ function directoryBytes(path2) {
|
|
|
56113
56309
|
let total = 0;
|
|
56114
56310
|
let entries;
|
|
56115
56311
|
try {
|
|
56116
|
-
entries = (0,
|
|
56312
|
+
entries = (0, import_node_fs57.readdirSync)(path2, { withFileTypes: true });
|
|
56117
56313
|
} catch {
|
|
56118
56314
|
return 0;
|
|
56119
56315
|
}
|
|
56120
56316
|
for (const entry of entries) {
|
|
56121
|
-
const child2 = (0,
|
|
56317
|
+
const child2 = (0, import_node_path54.join)(path2, entry.name);
|
|
56122
56318
|
if (entry.isDirectory()) total += directoryBytes(child2);
|
|
56123
56319
|
else {
|
|
56124
56320
|
try {
|
|
56125
|
-
total += (0,
|
|
56321
|
+
total += (0, import_node_fs57.statSync)(child2).size;
|
|
56126
56322
|
} catch {
|
|
56127
56323
|
}
|
|
56128
56324
|
}
|
|
@@ -56130,25 +56326,25 @@ function directoryBytes(path2) {
|
|
|
56130
56326
|
return total;
|
|
56131
56327
|
}
|
|
56132
56328
|
function listDirEntries(dir) {
|
|
56133
|
-
return (0,
|
|
56329
|
+
return (0, import_node_fs57.readdirSync)(dir, { withFileTypes: true }).map((d) => ({ name: d.name, isDirectory: d.isDirectory() }));
|
|
56134
56330
|
}
|
|
56135
56331
|
function readInstalledPluginRefs(configRoot) {
|
|
56136
56332
|
const p = installedPluginsPathForConfig(configRoot);
|
|
56137
|
-
if (!(0,
|
|
56333
|
+
if (!(0, import_node_fs57.existsSync)(p)) return [];
|
|
56138
56334
|
try {
|
|
56139
|
-
return installedPluginPaths((0,
|
|
56335
|
+
return installedPluginPaths((0, import_node_fs57.readFileSync)(p, "utf8"));
|
|
56140
56336
|
} catch {
|
|
56141
56337
|
return null;
|
|
56142
56338
|
}
|
|
56143
56339
|
}
|
|
56144
56340
|
function pluginCacheFsDeps(configRoot, dirBytes) {
|
|
56145
56341
|
return {
|
|
56146
|
-
exists: (p) => (0,
|
|
56147
|
-
listVersionDirs: (root) => (0,
|
|
56342
|
+
exists: (p) => (0, import_node_fs57.existsSync)(p),
|
|
56343
|
+
listVersionDirs: (root) => (0, import_node_fs57.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name),
|
|
56148
56344
|
dirBytes,
|
|
56149
|
-
listStagingDirs: (root) => (0,
|
|
56345
|
+
listStagingDirs: (root) => (0, import_node_fs57.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => {
|
|
56150
56346
|
try {
|
|
56151
|
-
return { name: d.name, mtimeMs: newestMtimeMs((0,
|
|
56347
|
+
return { name: d.name, mtimeMs: newestMtimeMs((0, import_node_path54.join)(root, d.name), listDirEntries, (p) => (0, import_node_fs57.statSync)(p).mtimeMs) };
|
|
56152
56348
|
} catch {
|
|
56153
56349
|
return { name: d.name, mtimeMs: Date.now() };
|
|
56154
56350
|
}
|
|
@@ -56162,10 +56358,10 @@ function stagingApplyFsGuard(configRoot) {
|
|
|
56162
56358
|
return {
|
|
56163
56359
|
referencedPaths: () => readInstalledPluginRefs(configRoot),
|
|
56164
56360
|
mtimeMs: (name) => {
|
|
56165
|
-
const p = (0,
|
|
56166
|
-
if (!(0,
|
|
56361
|
+
const p = (0, import_node_path54.join)(stagingRoot, name);
|
|
56362
|
+
if (!(0, import_node_fs57.existsSync)(p)) return null;
|
|
56167
56363
|
try {
|
|
56168
|
-
return newestMtimeMs(p, listDirEntries, (q) => (0,
|
|
56364
|
+
return newestMtimeMs(p, listDirEntries, (q) => (0, import_node_fs57.statSync)(q).mtimeMs);
|
|
56169
56365
|
} catch {
|
|
56170
56366
|
return null;
|
|
56171
56367
|
}
|
|
@@ -56185,13 +56381,13 @@ program2.command("plugin-prune").description(`prune stale cached MMI plugin vers
|
|
|
56185
56381
|
return;
|
|
56186
56382
|
}
|
|
56187
56383
|
const plan = buildPluginCachePlan(
|
|
56188
|
-
(0,
|
|
56384
|
+
(0, import_node_os25.homedir)(),
|
|
56189
56385
|
running,
|
|
56190
56386
|
pluginCacheFsDeps(configRoot, directoryBytes),
|
|
56191
56387
|
{ withBytes: true, configRoot, includeStaging: surface !== "codex" }
|
|
56192
56388
|
);
|
|
56193
56389
|
const anythingToDelete = plan.prune.length > 0 || plan.staging.length > 0;
|
|
56194
|
-
const result = o.apply && anythingToDelete ? applyPluginCachePlan(plan, (p) => (0,
|
|
56390
|
+
const result = o.apply && anythingToDelete ? applyPluginCachePlan(plan, (p) => (0, import_node_fs57.rmSync)(p, { recursive: true, force: true }), stagingApplyFsGuard(configRoot)) : void 0;
|
|
56195
56391
|
const warnings = plan.prune.length > 0 ? [CONCURRENT_SESSION_WARNING] : [];
|
|
56196
56392
|
if (o.json) console.log(JSON.stringify({ ...plan, warnings, applied: result ?? null }));
|
|
56197
56393
|
else console.log(renderPluginCachePlan(plan, result));
|