@mutmutco/cli 3.126.0 → 3.127.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/main.cjs +513 -387
- package/package.json +1 -1
package/dist/main.cjs
CHANGED
|
@@ -523,7 +523,7 @@ var require_graceful_fs = __commonJS({
|
|
|
523
523
|
function patch(fs3) {
|
|
524
524
|
polyfills(fs3);
|
|
525
525
|
fs3.gracefulify = patch;
|
|
526
|
-
fs3.createReadStream =
|
|
526
|
+
fs3.createReadStream = createReadStream2;
|
|
527
527
|
fs3.createWriteStream = createWriteStream;
|
|
528
528
|
var fs$readFile = fs3.readFile;
|
|
529
529
|
fs3.readFile = readFile9;
|
|
@@ -733,7 +733,7 @@ var require_graceful_fs = __commonJS({
|
|
|
733
733
|
}
|
|
734
734
|
});
|
|
735
735
|
}
|
|
736
|
-
function
|
|
736
|
+
function createReadStream2(path2, options) {
|
|
737
737
|
return new fs3.ReadStream(path2, options);
|
|
738
738
|
}
|
|
739
739
|
function createWriteStream(path2, options) {
|
|
@@ -1239,11 +1239,11 @@ var require_mtime_precision = __commonJS({
|
|
|
1239
1239
|
function probe(file, fs2, callback) {
|
|
1240
1240
|
const cachedPrecision = fs2[cacheSymbol];
|
|
1241
1241
|
if (cachedPrecision) {
|
|
1242
|
-
return fs2.stat(file, (err,
|
|
1242
|
+
return fs2.stat(file, (err, stat4) => {
|
|
1243
1243
|
if (err) {
|
|
1244
1244
|
return callback(err);
|
|
1245
1245
|
}
|
|
1246
|
-
callback(null,
|
|
1246
|
+
callback(null, stat4.mtime, cachedPrecision);
|
|
1247
1247
|
});
|
|
1248
1248
|
}
|
|
1249
1249
|
const mtime = new Date(Math.ceil(Date.now() / 1e3) * 1e3 + 5);
|
|
@@ -1251,13 +1251,13 @@ var require_mtime_precision = __commonJS({
|
|
|
1251
1251
|
if (err) {
|
|
1252
1252
|
return callback(err);
|
|
1253
1253
|
}
|
|
1254
|
-
fs2.stat(file, (err2,
|
|
1254
|
+
fs2.stat(file, (err2, stat4) => {
|
|
1255
1255
|
if (err2) {
|
|
1256
1256
|
return callback(err2);
|
|
1257
1257
|
}
|
|
1258
|
-
const precision =
|
|
1258
|
+
const precision = stat4.mtime.getTime() % 1e3 === 0 ? "s" : "ms";
|
|
1259
1259
|
Object.defineProperty(fs2, cacheSymbol, { value: precision });
|
|
1260
|
-
callback(null,
|
|
1260
|
+
callback(null, stat4.mtime, precision);
|
|
1261
1261
|
});
|
|
1262
1262
|
});
|
|
1263
1263
|
}
|
|
@@ -1311,14 +1311,14 @@ var require_lockfile = __commonJS({
|
|
|
1311
1311
|
if (options.stale <= 0) {
|
|
1312
1312
|
return callback(Object.assign(new Error("Lock file is already being held"), { code: "ELOCKED", file }));
|
|
1313
1313
|
}
|
|
1314
|
-
options.fs.stat(lockfilePath, (err2,
|
|
1314
|
+
options.fs.stat(lockfilePath, (err2, stat4) => {
|
|
1315
1315
|
if (err2) {
|
|
1316
1316
|
if (err2.code === "ENOENT") {
|
|
1317
1317
|
return acquireLock2(file, { ...options, stale: 0 }, callback);
|
|
1318
1318
|
}
|
|
1319
1319
|
return callback(err2);
|
|
1320
1320
|
}
|
|
1321
|
-
if (!isLockStale(
|
|
1321
|
+
if (!isLockStale(stat4, options)) {
|
|
1322
1322
|
return callback(Object.assign(new Error("Lock file is already being held"), { code: "ELOCKED", file }));
|
|
1323
1323
|
}
|
|
1324
1324
|
removeLock(file, options, (err3) => {
|
|
@@ -1330,8 +1330,8 @@ var require_lockfile = __commonJS({
|
|
|
1330
1330
|
});
|
|
1331
1331
|
});
|
|
1332
1332
|
}
|
|
1333
|
-
function isLockStale(
|
|
1334
|
-
return
|
|
1333
|
+
function isLockStale(stat4, options) {
|
|
1334
|
+
return stat4.mtime.getTime() < Date.now() - options.stale;
|
|
1335
1335
|
}
|
|
1336
1336
|
function removeLock(file, options, callback) {
|
|
1337
1337
|
options.fs.rmdir(getLockFile(file, options), (err) => {
|
|
@@ -1349,7 +1349,7 @@ var require_lockfile = __commonJS({
|
|
|
1349
1349
|
lock2.updateDelay = lock2.updateDelay || options.update;
|
|
1350
1350
|
lock2.updateTimeout = setTimeout(() => {
|
|
1351
1351
|
lock2.updateTimeout = null;
|
|
1352
|
-
options.fs.stat(lock2.lockfilePath, (err,
|
|
1352
|
+
options.fs.stat(lock2.lockfilePath, (err, stat4) => {
|
|
1353
1353
|
const isOverThreshold = lock2.lastUpdate + options.stale < Date.now();
|
|
1354
1354
|
if (err) {
|
|
1355
1355
|
if (err.code === "ENOENT" || isOverThreshold) {
|
|
@@ -1358,7 +1358,7 @@ var require_lockfile = __commonJS({
|
|
|
1358
1358
|
lock2.updateDelay = 1e3;
|
|
1359
1359
|
return updateLock(file, options);
|
|
1360
1360
|
}
|
|
1361
|
-
const isMtimeOurs = lock2.mtime.getTime() ===
|
|
1361
|
+
const isMtimeOurs = lock2.mtime.getTime() === stat4.mtime.getTime();
|
|
1362
1362
|
if (!isMtimeOurs) {
|
|
1363
1363
|
return setLockAsCompromised(
|
|
1364
1364
|
file,
|
|
@@ -1483,11 +1483,11 @@ var require_lockfile = __commonJS({
|
|
|
1483
1483
|
if (err) {
|
|
1484
1484
|
return callback(err);
|
|
1485
1485
|
}
|
|
1486
|
-
options.fs.stat(getLockFile(file2, options), (err2,
|
|
1486
|
+
options.fs.stat(getLockFile(file2, options), (err2, stat4) => {
|
|
1487
1487
|
if (err2) {
|
|
1488
1488
|
return err2.code === "ENOENT" ? callback(null, false) : callback(err2);
|
|
1489
1489
|
}
|
|
1490
|
-
return callback(null, !isLockStale(
|
|
1490
|
+
return callback(null, !isLockStale(stat4, options));
|
|
1491
1491
|
});
|
|
1492
1492
|
});
|
|
1493
1493
|
}
|
|
@@ -1533,12 +1533,12 @@ var require_adapter = __commonJS({
|
|
|
1533
1533
|
return newFs;
|
|
1534
1534
|
}
|
|
1535
1535
|
function toPromise(method) {
|
|
1536
|
-
return (...args) => new Promise((
|
|
1536
|
+
return (...args) => new Promise((resolve6, reject) => {
|
|
1537
1537
|
args.push((err, result) => {
|
|
1538
1538
|
if (err) {
|
|
1539
1539
|
reject(err);
|
|
1540
1540
|
} else {
|
|
1541
|
-
|
|
1541
|
+
resolve6(result);
|
|
1542
1542
|
}
|
|
1543
1543
|
});
|
|
1544
1544
|
method(...args);
|
|
@@ -4999,8 +4999,8 @@ function useColor() {
|
|
|
4999
4999
|
var program = new Command();
|
|
5000
5000
|
|
|
5001
5001
|
// src/index.ts
|
|
5002
|
-
var
|
|
5003
|
-
var
|
|
5002
|
+
var import_promises12 = require("node:fs/promises");
|
|
5003
|
+
var import_node_fs48 = require("node:fs");
|
|
5004
5004
|
var import_node_child_process20 = require("node:child_process");
|
|
5005
5005
|
|
|
5006
5006
|
// src/cli-shared.ts
|
|
@@ -5112,19 +5112,19 @@ function hardExit(code) {
|
|
|
5112
5112
|
}
|
|
5113
5113
|
var STDIO_FLUSH_TIMEOUT_MS = 2e3;
|
|
5114
5114
|
function flushStream(stream) {
|
|
5115
|
-
return new Promise((
|
|
5115
|
+
return new Promise((resolve6) => {
|
|
5116
5116
|
try {
|
|
5117
|
-
stream.write("", () =>
|
|
5117
|
+
stream.write("", () => resolve6());
|
|
5118
5118
|
} catch {
|
|
5119
|
-
|
|
5119
|
+
resolve6();
|
|
5120
5120
|
}
|
|
5121
5121
|
});
|
|
5122
5122
|
}
|
|
5123
5123
|
async function flushStdio(timeoutMs = STDIO_FLUSH_TIMEOUT_MS) {
|
|
5124
5124
|
await Promise.race([
|
|
5125
5125
|
Promise.all([flushStream(process.stdout), flushStream(process.stderr)]),
|
|
5126
|
-
new Promise((
|
|
5127
|
-
setTimeout(
|
|
5126
|
+
new Promise((resolve6) => {
|
|
5127
|
+
setTimeout(resolve6, timeoutMs).unref?.();
|
|
5128
5128
|
})
|
|
5129
5129
|
]);
|
|
5130
5130
|
}
|
|
@@ -5132,7 +5132,7 @@ async function cleanExit(code) {
|
|
|
5132
5132
|
process.exitCode = code;
|
|
5133
5133
|
await closeHttpPool();
|
|
5134
5134
|
await flushStdio();
|
|
5135
|
-
await new Promise((
|
|
5135
|
+
await new Promise((resolve6) => setImmediate(resolve6));
|
|
5136
5136
|
return void 0;
|
|
5137
5137
|
}
|
|
5138
5138
|
var CLI_EXIT_WATCHDOG_MS = (() => {
|
|
@@ -5519,7 +5519,7 @@ async function fetchWithRetry(fetchImpl, url, init, opts = {}) {
|
|
|
5519
5519
|
const attempts = opts.attempts ?? 3;
|
|
5520
5520
|
const baseDelayMs = opts.baseDelayMs ?? 250;
|
|
5521
5521
|
const retryOn = opts.retryOn ?? ((res) => res.status >= 500);
|
|
5522
|
-
const sleep3 = opts.sleep ?? ((ms) => new Promise((
|
|
5522
|
+
const sleep3 = opts.sleep ?? ((ms) => new Promise((resolve6) => setTimeout(resolve6, ms)));
|
|
5523
5523
|
let lastErr;
|
|
5524
5524
|
for (let i = 0; i < attempts; i++) {
|
|
5525
5525
|
const isLast = i === attempts - 1;
|
|
@@ -5646,10 +5646,10 @@ var import_node_fs4 = require("node:fs");
|
|
|
5646
5646
|
var injectedStdin;
|
|
5647
5647
|
function stdinHasPipedInput(statFd = () => (0, import_node_fs4.fstatSync)(0), getIsTTY = () => process.stdin.isTTY) {
|
|
5648
5648
|
try {
|
|
5649
|
-
const
|
|
5650
|
-
if (
|
|
5651
|
-
if (
|
|
5652
|
-
if (
|
|
5649
|
+
const stat4 = statFd();
|
|
5650
|
+
if (stat4.isFIFO() || stat4.isFile()) return true;
|
|
5651
|
+
if (stat4.isCharacterDevice()) return false;
|
|
5652
|
+
if (stat4.isSocket()) return false;
|
|
5653
5653
|
if (getIsTTY() === true) return false;
|
|
5654
5654
|
return true;
|
|
5655
5655
|
} catch {
|
|
@@ -5680,8 +5680,8 @@ async function readStdin(opts = {}) {
|
|
|
5680
5680
|
})().catch(() => {
|
|
5681
5681
|
});
|
|
5682
5682
|
let timer;
|
|
5683
|
-
const timeout = new Promise((
|
|
5684
|
-
timer = setTimeout(
|
|
5683
|
+
const timeout = new Promise((resolve6) => {
|
|
5684
|
+
timer = setTimeout(resolve6, timeoutMs);
|
|
5685
5685
|
});
|
|
5686
5686
|
try {
|
|
5687
5687
|
await Promise.race([drain, timeout]);
|
|
@@ -5735,12 +5735,12 @@ function killProcessTree(pid) {
|
|
|
5735
5735
|
function execFileHard(file, args, options) {
|
|
5736
5736
|
const { timeout, step, ...rest } = options;
|
|
5737
5737
|
const started = Date.now();
|
|
5738
|
-
return new Promise((
|
|
5738
|
+
return new Promise((resolve6, reject) => {
|
|
5739
5739
|
const child2 = (0, import_node_child_process3.execFile)(file, args, { encoding: "utf8", windowsHide: true, ...rest, timeout: 0 }, (error, stdout, stderr) => {
|
|
5740
5740
|
clearTimeout(timer);
|
|
5741
5741
|
if (expired) return;
|
|
5742
5742
|
if (error) reject(error);
|
|
5743
|
-
else
|
|
5743
|
+
else resolve6({ stdout: String(stdout), stderr: String(stderr) });
|
|
5744
5744
|
});
|
|
5745
5745
|
let expired = false;
|
|
5746
5746
|
const timer = setTimeout(() => {
|
|
@@ -6234,9 +6234,9 @@ function trackedPathStatus(c, realPath, repoAnchor) {
|
|
|
6234
6234
|
return null;
|
|
6235
6235
|
}
|
|
6236
6236
|
}
|
|
6237
|
-
function rootScratchDirSnapshot(root, readdir2,
|
|
6237
|
+
function rootScratchDirSnapshot(root, readdir2, stat4) {
|
|
6238
6238
|
try {
|
|
6239
|
-
const rootStat =
|
|
6239
|
+
const rootStat = stat4(root);
|
|
6240
6240
|
let mtimeMs = rootStat.mtimeMs;
|
|
6241
6241
|
let bytes = 0;
|
|
6242
6242
|
const stack = [root];
|
|
@@ -6250,7 +6250,7 @@ function rootScratchDirSnapshot(root, readdir2, stat3) {
|
|
|
6250
6250
|
return null;
|
|
6251
6251
|
} catch {
|
|
6252
6252
|
}
|
|
6253
|
-
const st =
|
|
6253
|
+
const st = stat4(child2);
|
|
6254
6254
|
mtimeMs = Math.max(mtimeMs, st.mtimeMs);
|
|
6255
6255
|
if (ent.isDirectory()) stack.push(child2);
|
|
6256
6256
|
else if (ent.isFile()) bytes += st.size;
|
|
@@ -6263,7 +6263,7 @@ function rootScratchDirSnapshot(root, readdir2, stat3) {
|
|
|
6263
6263
|
}
|
|
6264
6264
|
function collectScratchSnapshot(repoRoot2, deps = {}) {
|
|
6265
6265
|
const readdir2 = deps.readdir ?? import_node_fs6.readdirSync;
|
|
6266
|
-
const
|
|
6266
|
+
const stat4 = deps.stat ?? import_node_fs6.statSync;
|
|
6267
6267
|
const plansRoot = (0, import_node_path4.join)(repoRoot2, "plans");
|
|
6268
6268
|
const rootScratchFiles = [];
|
|
6269
6269
|
try {
|
|
@@ -6276,10 +6276,10 @@ function collectScratchSnapshot(repoRoot2, deps = {}) {
|
|
|
6276
6276
|
const full = (0, import_node_path4.join)(repoRoot2, ent.name);
|
|
6277
6277
|
try {
|
|
6278
6278
|
if (isDir) {
|
|
6279
|
-
const snap = rootScratchDirSnapshot(full, readdir2,
|
|
6279
|
+
const snap = rootScratchDirSnapshot(full, readdir2, stat4);
|
|
6280
6280
|
if (snap) rootScratchFiles.push({ path: full, dir: repoRoot2, name: ent.name, mtimeMs: snap.mtimeMs, bytes: snap.bytes, kind: "dir" });
|
|
6281
6281
|
} else {
|
|
6282
|
-
const st =
|
|
6282
|
+
const st = stat4(full);
|
|
6283
6283
|
rootScratchFiles.push({ path: full, dir: repoRoot2, name: ent.name, mtimeMs: st.mtimeMs, bytes: st.size, kind: "file" });
|
|
6284
6284
|
}
|
|
6285
6285
|
} catch {
|
|
@@ -6293,7 +6293,7 @@ function collectScratchSnapshot(repoRoot2, deps = {}) {
|
|
|
6293
6293
|
if (!ent.isFile() || !ent.name.endsWith(".md")) continue;
|
|
6294
6294
|
const full = (0, import_node_path4.join)(plansRoot, ent.name);
|
|
6295
6295
|
try {
|
|
6296
|
-
const st =
|
|
6296
|
+
const st = stat4(full);
|
|
6297
6297
|
planMdFiles.push({ path: full, dir: plansRoot, name: ent.name, mtimeMs: st.mtimeMs, bytes: st.size, kind: "file" });
|
|
6298
6298
|
} catch {
|
|
6299
6299
|
}
|
|
@@ -7405,7 +7405,7 @@ async function runWithSweepWatchdog(run, timeoutMs, onTimeout) {
|
|
|
7405
7405
|
clearTimeout(timer);
|
|
7406
7406
|
}
|
|
7407
7407
|
}
|
|
7408
|
-
var defaultSleep = (ms) => new Promise((
|
|
7408
|
+
var defaultSleep = (ms) => new Promise((resolve6) => setTimeout(resolve6, ms));
|
|
7409
7409
|
async function removeWorktreeWithRecovery(wtPath, deps) {
|
|
7410
7410
|
const maxAttempts = deps.maxAttempts ?? 3;
|
|
7411
7411
|
const backoff = deps.backoffMs ?? [250, 1e3];
|
|
@@ -10075,7 +10075,7 @@ var import_node_path15 = require("node:path");
|
|
|
10075
10075
|
// src/file-lock.ts
|
|
10076
10076
|
var import_promises2 = require("node:fs/promises");
|
|
10077
10077
|
var import_node_path14 = require("node:path");
|
|
10078
|
-
var sleep = (ms) => new Promise((
|
|
10078
|
+
var sleep = (ms) => new Promise((resolve6) => setTimeout(resolve6, ms));
|
|
10079
10079
|
var IMMEDIATE_RETRY_BUDGET = 3;
|
|
10080
10080
|
var FileLockBusyError = class extends Error {
|
|
10081
10081
|
lockPath;
|
|
@@ -10488,7 +10488,7 @@ function commandLadderHint() {
|
|
|
10488
10488
|
}
|
|
10489
10489
|
|
|
10490
10490
|
// src/index.ts
|
|
10491
|
-
var
|
|
10491
|
+
var import_node_path45 = require("node:path");
|
|
10492
10492
|
|
|
10493
10493
|
// src/merge-ci-policy.ts
|
|
10494
10494
|
function resolveMergeCiPolicy(input) {
|
|
@@ -12338,6 +12338,12 @@ function extractControlOutputFromLog(log) {
|
|
|
12338
12338
|
const slice = end < 0 ? lines.slice(start + 1) : lines.slice(start + 1, end);
|
|
12339
12339
|
return slice.map(logLinePayload).join("\n").trim();
|
|
12340
12340
|
}
|
|
12341
|
+
function clampTaskOutput(output, maxChars = 16384) {
|
|
12342
|
+
if (output.length <= maxChars) return output;
|
|
12343
|
+
const kept = output.slice(output.length - maxChars);
|
|
12344
|
+
return `[task output truncated by mmi-cli \u2014 last ${maxChars} of ${output.length} chars]
|
|
12345
|
+
${kept}`;
|
|
12346
|
+
}
|
|
12341
12347
|
function parseStatusSnippet(stdout) {
|
|
12342
12348
|
const t = stdout.toLowerCase();
|
|
12343
12349
|
const m = t.match(/service[:=]\s*(running|stopped|missing|up|down|absent)/);
|
|
@@ -13628,6 +13634,9 @@ async function postSchedulesUnpark(id, deps) {
|
|
|
13628
13634
|
async function tenantControl(payload, deps) {
|
|
13629
13635
|
return postJson("/tenant-control", payload, deps, "POST", { noRetry: true });
|
|
13630
13636
|
}
|
|
13637
|
+
async function tenantArtifactUpload(payload, deps) {
|
|
13638
|
+
return postJson("/tenant-control", { ...payload, action: "artifact-upload" }, deps, "POST", { noRetry: true });
|
|
13639
|
+
}
|
|
13631
13640
|
async function tenantReconcile(payload, deps) {
|
|
13632
13641
|
return postJson("/tenant-reconcile", payload, deps, "POST", { noRetry: true });
|
|
13633
13642
|
}
|
|
@@ -13930,7 +13939,7 @@ function upstreamFaultMessage(verb, stderr) {
|
|
|
13930
13939
|
}
|
|
13931
13940
|
async function ghCreate(args, deps = {}) {
|
|
13932
13941
|
const exec = deps.exec ?? execFileP2;
|
|
13933
|
-
const sleep3 = deps.sleep ?? ((ms) => new Promise((
|
|
13942
|
+
const sleep3 = deps.sleep ?? ((ms) => new Promise((resolve6) => setTimeout(resolve6, ms)));
|
|
13934
13943
|
const swapped = await bodyArgsViaFile(args);
|
|
13935
13944
|
try {
|
|
13936
13945
|
for (let attempt = 1; attempt <= GH_CREATE_UPSTREAM_RETRIES; attempt++) {
|
|
@@ -15136,8 +15145,8 @@ var PRE_SPAWN_DRAIN_TIMEOUT_MS = 2e3;
|
|
|
15136
15145
|
async function drainHttpPoolBeforeSpawn() {
|
|
15137
15146
|
const drained = await Promise.race([
|
|
15138
15147
|
closeHttpPool().then(() => true),
|
|
15139
|
-
new Promise((
|
|
15140
|
-
setTimeout(() =>
|
|
15148
|
+
new Promise((resolve6) => {
|
|
15149
|
+
setTimeout(() => resolve6(false), PRE_SPAWN_DRAIN_TIMEOUT_MS).unref?.();
|
|
15141
15150
|
})
|
|
15142
15151
|
]);
|
|
15143
15152
|
if (!drained) destroyHttpPool();
|
|
@@ -15840,10 +15849,10 @@ var rollout_plan_default = {
|
|
|
15840
15849
|
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)."
|
|
15841
15850
|
},
|
|
15842
15851
|
baseline: {
|
|
15843
|
-
version: "3.
|
|
15844
|
-
tag: "v3.
|
|
15845
|
-
commit: "
|
|
15846
|
-
npm: "@mutmutco/cli@3.
|
|
15852
|
+
version: "3.127.0",
|
|
15853
|
+
tag: "v3.127.0",
|
|
15854
|
+
commit: "2f170f4e63d4",
|
|
15855
|
+
npm: "@mutmutco/cli@3.127.0"
|
|
15847
15856
|
},
|
|
15848
15857
|
exitCriterion: "fleet-n-of-n",
|
|
15849
15858
|
hubOnlyShortcut: "forbidden",
|
|
@@ -15860,14 +15869,14 @@ var rollout_plan_default = {
|
|
|
15860
15869
|
repo: "mutmutco/mmi-hub",
|
|
15861
15870
|
role: "canary",
|
|
15862
15871
|
schedule: "train",
|
|
15863
|
-
v3Target: "v3.
|
|
15872
|
+
v3Target: "v3.127.0"
|
|
15864
15873
|
}
|
|
15865
15874
|
],
|
|
15866
15875
|
rollbackTrigger: "Any red inside the post-cut soak window: `devops train gate` FAIL attributable to the v4 doors, Hub endpoint health probe failure, a v3 client refused while the compat window must still admit it (SUPPORTED_MINOR_WINDOW=2, MIN_CLIENT_VERSION 0.0.0 \u2014 D6a), or npm consumer install/doctor failure on the v4 dist.",
|
|
15867
15876
|
rollback: {
|
|
15868
15877
|
independent: true,
|
|
15869
|
-
mechanism: "npm dist-tag latest -> 3.
|
|
15870
|
-
v3Target: "v3.
|
|
15878
|
+
mechanism: "npm dist-tag latest -> 3.127.0 and redeploy the Hub Lambda from tag v3.127.0 (2f170f4e63d4); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
|
|
15879
|
+
v3Target: "v3.127.0 (@mutmutco/cli@3.127.0, tag commit 2f170f4e63d4 \u2014 the preserved latest-v3 distribution, D6b)"
|
|
15871
15880
|
}
|
|
15872
15881
|
},
|
|
15873
15882
|
{
|
|
@@ -18274,7 +18283,7 @@ async function runMergeTreePreflight(deps, ours, theirs) {
|
|
|
18274
18283
|
async function predictMergeConflicts(deps, ours, theirs) {
|
|
18275
18284
|
return runMergeTreePreflight(deps, ours, theirs);
|
|
18276
18285
|
}
|
|
18277
|
-
async function mergeWithToleratedResolution(deps, sourceRef, label,
|
|
18286
|
+
async function mergeWithToleratedResolution(deps, sourceRef, label, resolve6, extraTolerated = []) {
|
|
18278
18287
|
try {
|
|
18279
18288
|
await deps.run("git", ["merge", sourceRef, "--no-edit"]);
|
|
18280
18289
|
return;
|
|
@@ -18288,7 +18297,7 @@ async function mergeWithToleratedResolution(deps, sourceRef, label, resolve5, ex
|
|
|
18288
18297
|
unmerged.length === 0 ? `${label} merge failed without conflicted paths \u2014 merge aborted; inspect the repo state and rerun` : `${label} merge conflicts on untolerated path(s): ${blocking.join(", ")} \u2014 merge aborted (the train is misaligned; reconcile the branches via an approved alignment PR, then rerun)`
|
|
18289
18298
|
);
|
|
18290
18299
|
}
|
|
18291
|
-
await deps.run("git", ["checkout", `--${
|
|
18300
|
+
await deps.run("git", ["checkout", `--${resolve6}`, "--", ...unmerged]);
|
|
18292
18301
|
await deps.run("git", ["add", "--", ...unmerged]);
|
|
18293
18302
|
await deps.run("git", ["commit", "--no-edit"]);
|
|
18294
18303
|
}
|
|
@@ -18499,7 +18508,7 @@ var CORRELATE_SKEW_SLACK_MS = 1e4;
|
|
|
18499
18508
|
var CORRELATE_PAGE_LIMIT = 50;
|
|
18500
18509
|
var RUN_CONFIRM_ATTEMPTS = 3;
|
|
18501
18510
|
var RUN_CONFIRM_DELAY_MS = 1e3;
|
|
18502
|
-
var defaultSleep2 = (ms) => new Promise((
|
|
18511
|
+
var defaultSleep2 = (ms) => new Promise((resolve6) => setTimeout(resolve6, ms));
|
|
18503
18512
|
function resolveSleep(deps) {
|
|
18504
18513
|
return deps.sleep ?? defaultSleep2;
|
|
18505
18514
|
}
|
|
@@ -20420,14 +20429,14 @@ async function runTenantReconcile(deps, options) {
|
|
|
20420
20429
|
};
|
|
20421
20430
|
}
|
|
20422
20431
|
function tenantControlWatches(action) {
|
|
20423
|
-
return action === "status" || action === "retire" || action === "verify-secrets" || action === "verify-broker" || action === "logs";
|
|
20432
|
+
return action === "status" || action === "retire" || action === "verify-secrets" || action === "verify-broker" || action === "logs" || action === "run-task";
|
|
20424
20433
|
}
|
|
20425
20434
|
async function runTenantControl(deps, options) {
|
|
20426
20435
|
const { repo, stage, action } = options;
|
|
20427
20436
|
const watch = options.watch ?? tenantControlWatches(action);
|
|
20428
20437
|
const base = { command: "tenant-control", repo, stage, action };
|
|
20429
20438
|
const since = (deps.now ?? Date.now)();
|
|
20430
|
-
const d = await deps.dispatchTenantControl({ repo, stage, action, lines: options.lines });
|
|
20439
|
+
const d = await deps.dispatchTenantControl({ repo, stage, action, lines: options.lines, task: options.task, artifact: options.artifact });
|
|
20431
20440
|
if (!d.ok) {
|
|
20432
20441
|
const transport = d.category === "transport-failed";
|
|
20433
20442
|
return {
|
|
@@ -20438,7 +20447,7 @@ async function runTenantControl(deps, options) {
|
|
|
20438
20447
|
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"}`
|
|
20439
20448
|
};
|
|
20440
20449
|
}
|
|
20441
|
-
const correlated = await correlateControlRun(deps, since, [stage, action]);
|
|
20450
|
+
const correlated = await correlateControlRun(deps, since, [stage, action, ...action === "run-task" && options.task ? [options.task] : []]);
|
|
20442
20451
|
if (correlated.read === "failed") {
|
|
20443
20452
|
return {
|
|
20444
20453
|
...base,
|
|
@@ -20474,6 +20483,13 @@ async function runTenantControl(deps, options) {
|
|
|
20474
20483
|
result.brokerRaw = output;
|
|
20475
20484
|
}
|
|
20476
20485
|
}
|
|
20486
|
+
if (watch && runId != null && action === "run-task" && (conclusion === "success" || conclusion === "failure")) {
|
|
20487
|
+
const fetched = await fetchControlRunLog(deps, runId);
|
|
20488
|
+
if (fetched.ok) {
|
|
20489
|
+
const output = extractControlOutputFromLog(fetched.log);
|
|
20490
|
+
if (output) result.taskOutput = clampTaskOutput(output);
|
|
20491
|
+
}
|
|
20492
|
+
}
|
|
20477
20493
|
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`;
|
|
20478
20494
|
return result;
|
|
20479
20495
|
}
|
|
@@ -20485,6 +20501,10 @@ function renderTenantControl(r) {
|
|
|
20485
20501
|
if (r.secrets?.length) {
|
|
20486
20502
|
for (const s of r.secrets) lines.push(` ${s.key}: ${s.status}`);
|
|
20487
20503
|
}
|
|
20504
|
+
if (r.taskOutput) {
|
|
20505
|
+
lines.push(" task output:");
|
|
20506
|
+
for (const l of r.taskOutput.split("\n")) lines.push(` ${l}`);
|
|
20507
|
+
}
|
|
20488
20508
|
lines.push(` ${r.note}`);
|
|
20489
20509
|
return lines.join("\n");
|
|
20490
20510
|
}
|
|
@@ -21417,7 +21437,7 @@ async function mergeAutoWithTransientRetry(prNumber, repo, deps) {
|
|
|
21417
21437
|
if (first.mergeStatus !== "failed") return first;
|
|
21418
21438
|
const ready = await deps.probeMergeReady(prNumber, repo).catch(() => ({ open: false, mergeable: false, checksPassing: false }));
|
|
21419
21439
|
if (!ready.open || !ready.mergeable || !ready.checksPassing) return first;
|
|
21420
|
-
const sleep3 = deps.sleep ?? ((ms) => new Promise((
|
|
21440
|
+
const sleep3 = deps.sleep ?? ((ms) => new Promise((resolve6) => setTimeout(resolve6, ms)));
|
|
21421
21441
|
await sleep3(PR_LAND_MERGE_RETRY_DELAY_MS);
|
|
21422
21442
|
const retried = await deps.mergeAuto(prNumber, repo);
|
|
21423
21443
|
if (retried.mergeStatus !== "failed") return retried;
|
|
@@ -21428,7 +21448,7 @@ var AUTO_MERGE_CONFIRM_DELAY_MS = 3e3;
|
|
|
21428
21448
|
async function confirmAutoMergeEnqueued(deps, options) {
|
|
21429
21449
|
const retries = options?.retries ?? AUTO_MERGE_CONFIRM_RETRIES;
|
|
21430
21450
|
const delayMs = options?.delayMs ?? AUTO_MERGE_CONFIRM_DELAY_MS;
|
|
21431
|
-
const sleep3 = deps.sleep ?? ((ms) => new Promise((
|
|
21451
|
+
const sleep3 = deps.sleep ?? ((ms) => new Promise((resolve6) => setTimeout(resolve6, ms)));
|
|
21432
21452
|
for (let attempt = 0; attempt < retries; attempt++) {
|
|
21433
21453
|
if (await deps.readMerged().catch(() => false)) return "merged";
|
|
21434
21454
|
const stuck = await deps.readAutoMergeRequest().then((s) => s.trim()).catch(() => "");
|
|
@@ -21445,7 +21465,7 @@ async function confirmAutoMergeEnqueued(deps, options) {
|
|
|
21445
21465
|
async function readGhPrStateWithRetry(fetchState, options) {
|
|
21446
21466
|
const retries = options?.retries ?? PR_LAND_STATE_READ_RETRIES;
|
|
21447
21467
|
const delayMs = options?.delayMs ?? PR_LAND_STATE_READ_DELAY_MS;
|
|
21448
|
-
const sleep3 = options?.sleep ?? ((ms) => new Promise((
|
|
21468
|
+
const sleep3 = options?.sleep ?? ((ms) => new Promise((resolve6) => setTimeout(resolve6, ms)));
|
|
21449
21469
|
let lastError = "empty state";
|
|
21450
21470
|
for (let attempt = 0; attempt < retries; attempt++) {
|
|
21451
21471
|
try {
|
|
@@ -21552,7 +21572,7 @@ function healthPollIntervalMs() {
|
|
|
21552
21572
|
return HEALTH_POLL_INTERVAL_MS;
|
|
21553
21573
|
}
|
|
21554
21574
|
function waitForProcessStability(child2, graceMs = earlyExitGraceMs()) {
|
|
21555
|
-
return new Promise((
|
|
21575
|
+
return new Promise((resolve6, reject) => {
|
|
21556
21576
|
let settled = false;
|
|
21557
21577
|
const finish = (fn) => {
|
|
21558
21578
|
if (settled) return;
|
|
@@ -21562,7 +21582,7 @@ function waitForProcessStability(child2, graceMs = earlyExitGraceMs()) {
|
|
|
21562
21582
|
child2.removeAllListeners("exit");
|
|
21563
21583
|
fn();
|
|
21564
21584
|
};
|
|
21565
|
-
const timer = setTimeout(() => finish(
|
|
21585
|
+
const timer = setTimeout(() => finish(resolve6), graceMs);
|
|
21566
21586
|
child2.on("error", (err) => finish(() => reject(new Error(`stage process failed to start: ${err.message}`))));
|
|
21567
21587
|
child2.on("exit", (code, signal) => {
|
|
21568
21588
|
const detail = code != null ? `code ${code}` : signal ? `signal ${signal}` : "unknown reason";
|
|
@@ -21772,10 +21792,10 @@ function pickStagePort(range, isFree) {
|
|
|
21772
21792
|
throw new Error(`no free stage port in range ${start}-${end} \u2014 every port is in use`);
|
|
21773
21793
|
}
|
|
21774
21794
|
function isPortFree(port) {
|
|
21775
|
-
return new Promise((
|
|
21795
|
+
return new Promise((resolve6) => {
|
|
21776
21796
|
const srv = (0, import_node_net.createServer)();
|
|
21777
|
-
srv.once("error", () =>
|
|
21778
|
-
srv.once("listening", () => srv.close(() =>
|
|
21797
|
+
srv.once("error", () => resolve6(false));
|
|
21798
|
+
srv.once("listening", () => srv.close(() => resolve6(true)));
|
|
21779
21799
|
srv.listen(port, "127.0.0.1");
|
|
21780
21800
|
});
|
|
21781
21801
|
}
|
|
@@ -21986,7 +22006,7 @@ async function killTree(pid) {
|
|
|
21986
22006
|
} catch {
|
|
21987
22007
|
}
|
|
21988
22008
|
}
|
|
21989
|
-
await new Promise((
|
|
22009
|
+
await new Promise((resolve6) => setTimeout(resolve6, 500));
|
|
21990
22010
|
try {
|
|
21991
22011
|
process.kill(-pid, "SIGKILL");
|
|
21992
22012
|
} catch {
|
|
@@ -22007,7 +22027,7 @@ async function waitForHealth(url, timeoutMs, anyStatus = false) {
|
|
|
22007
22027
|
} catch (e) {
|
|
22008
22028
|
last = e.message;
|
|
22009
22029
|
}
|
|
22010
|
-
await new Promise((
|
|
22030
|
+
await new Promise((resolve6) => setTimeout(resolve6, healthPollIntervalMs()));
|
|
22011
22031
|
}
|
|
22012
22032
|
throw new Error(`stage health check timed out for ${url}${last ? ` (${last})` : ""}`);
|
|
22013
22033
|
}
|
|
@@ -23542,7 +23562,7 @@ async function setBoardItemPriority(client, cfg, itemId, priority) {
|
|
|
23542
23562
|
await updateItemSingleSelect(client, cfg.projectId, itemId, cfg.priorityFieldId, optionId);
|
|
23543
23563
|
return cliPriorityToFieldName(priority);
|
|
23544
23564
|
}
|
|
23545
|
-
var defaultRetrySleep = (ms) => new Promise((
|
|
23565
|
+
var defaultRetrySleep = (ms) => new Promise((resolve6) => setTimeout(resolve6, ms));
|
|
23546
23566
|
async function resolveProjectItemIdWithRetry(client, cfg, selector, opts = {}) {
|
|
23547
23567
|
const attempts = Math.max(1, opts.attempts ?? 5);
|
|
23548
23568
|
const delayMs = opts.delayMs ?? 300;
|
|
@@ -24653,7 +24673,7 @@ function buildOption(opt) {
|
|
|
24653
24673
|
if (opt.hidden) out.discovery = "all-only";
|
|
24654
24674
|
return out;
|
|
24655
24675
|
}
|
|
24656
|
-
function buildCommand(cmd,
|
|
24676
|
+
function buildCommand(cmd, flatPath) {
|
|
24657
24677
|
const metadata = commandMetadata(cmd) ?? {
|
|
24658
24678
|
category: "core",
|
|
24659
24679
|
discovery: "primary",
|
|
@@ -24661,29 +24681,31 @@ function buildCommand(cmd, path2) {
|
|
|
24661
24681
|
module_owner: "unclassified",
|
|
24662
24682
|
consumer: "unclassified"
|
|
24663
24683
|
};
|
|
24664
|
-
const house = houseForPath(
|
|
24684
|
+
const house = houseForPath(flatPath);
|
|
24665
24685
|
if (!house) {
|
|
24666
24686
|
throw new Error(
|
|
24667
|
-
`command-manifest: command '${
|
|
24687
|
+
`command-manifest: command '${flatPath}' has no house assignment \u2014 add it to cli/src/house-map.ts (the six-house taxonomy; every top-level command maps to exactly one house).`
|
|
24668
24688
|
);
|
|
24669
24689
|
}
|
|
24670
24690
|
const aliases = cmd.aliases();
|
|
24691
|
+
const canonical = canonicalPathFor(flatPath) ?? flatPath;
|
|
24671
24692
|
const out = {
|
|
24672
24693
|
name: cmd.name(),
|
|
24673
|
-
path:
|
|
24694
|
+
path: canonical,
|
|
24695
|
+
flat_path: flatPath,
|
|
24674
24696
|
...aliases.length ? { aliases: [...aliases] } : {},
|
|
24675
24697
|
house,
|
|
24676
|
-
canonical
|
|
24698
|
+
canonical,
|
|
24677
24699
|
arguments: cmd.registeredArguments.map(buildArgument),
|
|
24678
24700
|
// A hand-parsed command registers no Commander options, so its declared set is merged in (#3682).
|
|
24679
24701
|
options: [...cmd.options.map(buildOption), ...readDeclaredOptions(cmd)],
|
|
24680
24702
|
subcommands: cmd.commands.map(
|
|
24681
|
-
(child2) => buildCommand(child2,
|
|
24703
|
+
(child2) => buildCommand(child2, flatPath ? `${flatPath} ${child2.name()}` : child2.name())
|
|
24682
24704
|
),
|
|
24683
24705
|
...metadata
|
|
24684
24706
|
};
|
|
24685
24707
|
if (cmd._allowUnknownOption) out.parses_own_argv = true;
|
|
24686
|
-
if (
|
|
24708
|
+
if (flatPath && house !== "core") out.flat_removed = true;
|
|
24687
24709
|
const description = cmd.description();
|
|
24688
24710
|
if (description) out.description = description;
|
|
24689
24711
|
const examples = readExamples(cmd);
|
|
@@ -24712,7 +24734,7 @@ function collectLeaves(node, acc) {
|
|
|
24712
24734
|
function buildHouses(tree) {
|
|
24713
24735
|
const collect = (node, parentHouse, root, out) => {
|
|
24714
24736
|
if (node.house === root && parentHouse !== root) {
|
|
24715
|
-
const entry = { path: node.
|
|
24737
|
+
const entry = { path: node.flat_path, canonical: node.canonical };
|
|
24716
24738
|
if (node.description) entry.description = node.description;
|
|
24717
24739
|
out.push(entry);
|
|
24718
24740
|
}
|
|
@@ -25875,6 +25897,57 @@ function renderVerifyBroker(input) {
|
|
|
25875
25897
|
};
|
|
25876
25898
|
}
|
|
25877
25899
|
|
|
25900
|
+
// src/tenant-artifact.ts
|
|
25901
|
+
var import_node_crypto4 = require("node:crypto");
|
|
25902
|
+
var import_node_fs28 = require("node:fs");
|
|
25903
|
+
var import_promises5 = require("node:fs/promises");
|
|
25904
|
+
var import_node_path26 = require("node:path");
|
|
25905
|
+
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}$/;
|
|
25906
|
+
var MAX_BYTES = 5 * 1024 * 1024 * 1024;
|
|
25907
|
+
async function sha256File(path2) {
|
|
25908
|
+
const hash = (0, import_node_crypto4.createHash)("sha256");
|
|
25909
|
+
for await (const chunk of (0, import_node_fs28.createReadStream)(path2)) hash.update(chunk);
|
|
25910
|
+
return hash.digest("hex");
|
|
25911
|
+
}
|
|
25912
|
+
async function putTenantArtifact(repo, stage, inputPath, deps) {
|
|
25913
|
+
if (!["dev", "rc", "main"].includes(stage)) throw new Error("tenant artifact put: <stage> must be dev, rc, or main");
|
|
25914
|
+
const path2 = (0, import_node_path26.resolve)(inputPath);
|
|
25915
|
+
const info = await (0, import_promises5.stat)(path2);
|
|
25916
|
+
if (!info.isFile()) throw new Error("tenant artifact put: input path must be a file");
|
|
25917
|
+
if (!Number.isSafeInteger(info.size) || info.size < 1 || info.size > MAX_BYTES) throw new Error(`tenant artifact put: file must be 1..${MAX_BYTES} bytes`);
|
|
25918
|
+
const sha256 = await sha256File(path2);
|
|
25919
|
+
const prepared = await tenantArtifactUpload({ repo, stage, size: info.size, sha256 }, deps);
|
|
25920
|
+
if (!prepared.ok) {
|
|
25921
|
+
const detail = prepared.body?.error ?? prepared.error ?? `HTTP ${prepared.status}`;
|
|
25922
|
+
throw new Error(`tenant artifact put: ${detail}`);
|
|
25923
|
+
}
|
|
25924
|
+
const body = prepared.body;
|
|
25925
|
+
if (!ARTIFACT_ID_RE.test(body.artifactId ?? "") || typeof body.uploadUrl !== "string" || !body.uploadUrl.startsWith("https://")) throw new Error("tenant artifact put: Hub returned an invalid upload grant");
|
|
25926
|
+
if (!body.headers || typeof body.headers !== "object" || Array.isArray(body.headers)) throw new Error("tenant artifact put: Hub returned invalid signed headers");
|
|
25927
|
+
const headers = Object.fromEntries(Object.entries(body.headers).map(([key, value]) => {
|
|
25928
|
+
if (typeof value !== "string" || /[\r\n]/.test(key + value)) throw new Error("tenant artifact put: Hub returned an unsafe signed header");
|
|
25929
|
+
return [key, value];
|
|
25930
|
+
}));
|
|
25931
|
+
headers["content-length"] = String(info.size);
|
|
25932
|
+
const stream = (0, import_node_fs28.createReadStream)(path2);
|
|
25933
|
+
let uploaded;
|
|
25934
|
+
try {
|
|
25935
|
+
uploaded = await fetch(body.uploadUrl, {
|
|
25936
|
+
method: "PUT",
|
|
25937
|
+
headers,
|
|
25938
|
+
body: stream,
|
|
25939
|
+
duplex: "half",
|
|
25940
|
+
signal: AbortSignal.timeout(60 * 60 * 1e3)
|
|
25941
|
+
});
|
|
25942
|
+
} catch (error) {
|
|
25943
|
+
stream.destroy();
|
|
25944
|
+
throw error;
|
|
25945
|
+
}
|
|
25946
|
+
if (!uploaded.ok) throw new Error(`tenant artifact put: object upload failed (HTTP ${uploaded.status})`);
|
|
25947
|
+
if (body.size !== info.size || body.sha256 !== sha256 || typeof body.expiresAt !== "string" || !Number.isFinite(Date.parse(body.expiresAt))) throw new Error("tenant artifact put: Hub returned inconsistent artifact metadata");
|
|
25948
|
+
return { artifactId: body.artifactId, repo, stage, size: info.size, sha256, expiresAt: body.expiresAt };
|
|
25949
|
+
}
|
|
25950
|
+
|
|
25878
25951
|
// src/hotfix-coverage.ts
|
|
25879
25952
|
var import_node_child_process12 = require("node:child_process");
|
|
25880
25953
|
var CHERRY_TRAILER = /\(cherry picked from commit ([0-9a-f]{7,40})\)/g;
|
|
@@ -26058,7 +26131,7 @@ function clean3(out) {
|
|
|
26058
26131
|
return out.trim();
|
|
26059
26132
|
}
|
|
26060
26133
|
function sleeper(deps) {
|
|
26061
|
-
return deps.sleep ?? ((ms) => new Promise((
|
|
26134
|
+
return deps.sleep ?? ((ms) => new Promise((resolve6) => setTimeout(resolve6, ms)));
|
|
26062
26135
|
}
|
|
26063
26136
|
function normalizeHotfixVersion(input) {
|
|
26064
26137
|
const m = /^v?(\d+\.\d+\.\d+)$/.exec(input.trim());
|
|
@@ -26972,10 +27045,10 @@ async function announceRelease(deps, args) {
|
|
|
26972
27045
|
}
|
|
26973
27046
|
|
|
26974
27047
|
// src/repo-index.ts
|
|
26975
|
-
var
|
|
27048
|
+
var import_node_crypto5 = require("node:crypto");
|
|
26976
27049
|
var import_node_child_process13 = require("node:child_process");
|
|
26977
|
-
var
|
|
26978
|
-
var
|
|
27050
|
+
var import_node_fs29 = require("node:fs");
|
|
27051
|
+
var import_node_path27 = require("node:path");
|
|
26979
27052
|
var REPO_INDEX_SCHEMA = 1;
|
|
26980
27053
|
var HARD_DENY = [
|
|
26981
27054
|
/(^|\/)\.env(\.|$)/i,
|
|
@@ -27100,11 +27173,11 @@ function loadReadmeHints(cwd, candidatePaths) {
|
|
|
27100
27173
|
}
|
|
27101
27174
|
for (const rel of readmes) {
|
|
27102
27175
|
if (isHardDeniedPath(rel)) continue;
|
|
27103
|
-
const abs = (0,
|
|
27104
|
-
if (!(0,
|
|
27176
|
+
const abs = (0, import_node_path27.join)(cwd, ...rel.split("/"));
|
|
27177
|
+
if (!(0, import_node_fs29.existsSync)(abs)) continue;
|
|
27105
27178
|
let text;
|
|
27106
27179
|
try {
|
|
27107
|
-
text = (0,
|
|
27180
|
+
text = (0, import_node_fs29.readFileSync)(abs, "utf8");
|
|
27108
27181
|
} catch {
|
|
27109
27182
|
continue;
|
|
27110
27183
|
}
|
|
@@ -27117,7 +27190,7 @@ function loadReadmeHints(cwd, candidatePaths) {
|
|
|
27117
27190
|
return hints;
|
|
27118
27191
|
}
|
|
27119
27192
|
function toPosix(p) {
|
|
27120
|
-
return p.split(
|
|
27193
|
+
return p.split(import_node_path27.sep).join("/");
|
|
27121
27194
|
}
|
|
27122
27195
|
function listCandidatePaths(cwd, exec = import_node_child_process13.execFileSync) {
|
|
27123
27196
|
try {
|
|
@@ -27139,16 +27212,16 @@ function rebuildRepoIndex(cwd, repoSlug2) {
|
|
|
27139
27212
|
for (const rel of candidates) {
|
|
27140
27213
|
if (ignored.has(rel)) continue;
|
|
27141
27214
|
if (isHardDeniedPath(rel)) continue;
|
|
27142
|
-
const abs = (0,
|
|
27143
|
-
if (!(0,
|
|
27215
|
+
const abs = (0, import_node_path27.join)(cwd, ...rel.split("/"));
|
|
27216
|
+
if (!(0, import_node_fs29.existsSync)(abs)) continue;
|
|
27144
27217
|
let text;
|
|
27145
27218
|
try {
|
|
27146
|
-
text = (0,
|
|
27219
|
+
text = (0, import_node_fs29.readFileSync)(abs, "utf8");
|
|
27147
27220
|
} catch {
|
|
27148
27221
|
continue;
|
|
27149
27222
|
}
|
|
27150
27223
|
if (text.length > 15e5) continue;
|
|
27151
|
-
const hash = (0,
|
|
27224
|
+
const hash = (0, import_node_crypto5.createHash)("sha256").update(text).digest("hex").slice(0, 16);
|
|
27152
27225
|
const symbols = extractSymbols(text);
|
|
27153
27226
|
const docBlurb = extractModuleBlurb(text);
|
|
27154
27227
|
const top = rel.includes("/") ? rel.split("/")[0] : "";
|
|
@@ -27168,16 +27241,16 @@ function rebuildRepoIndex(cwd, repoSlug2) {
|
|
|
27168
27241
|
entries
|
|
27169
27242
|
};
|
|
27170
27243
|
const store = repoIndexStorePath(cwd);
|
|
27171
|
-
(0,
|
|
27172
|
-
(0,
|
|
27244
|
+
(0, import_node_fs29.mkdirSync)((0, import_node_path27.dirname)(store), { recursive: true });
|
|
27245
|
+
(0, import_node_fs29.writeFileSync)(store, `${JSON.stringify(projection, null, 2)}
|
|
27173
27246
|
`, "utf8");
|
|
27174
27247
|
return projection;
|
|
27175
27248
|
}
|
|
27176
27249
|
function loadRepoIndex(cwd) {
|
|
27177
27250
|
const store = repoIndexStorePath(cwd);
|
|
27178
|
-
if (!(0,
|
|
27251
|
+
if (!(0, import_node_fs29.existsSync)(store)) return null;
|
|
27179
27252
|
try {
|
|
27180
|
-
const raw = JSON.parse((0,
|
|
27253
|
+
const raw = JSON.parse((0, import_node_fs29.readFileSync)(store, "utf8"));
|
|
27181
27254
|
if (raw?.schema !== REPO_INDEX_SCHEMA || !Array.isArray(raw.entries)) return null;
|
|
27182
27255
|
return raw;
|
|
27183
27256
|
} catch {
|
|
@@ -27249,7 +27322,7 @@ function inferRepoSlug(cwd, exec = import_node_child_process13.execFileSync) {
|
|
|
27249
27322
|
if (m?.[1]) return m[1].toLowerCase();
|
|
27250
27323
|
} catch {
|
|
27251
27324
|
}
|
|
27252
|
-
return ((0,
|
|
27325
|
+
return ((0, import_node_path27.basename)(cwd) || "local").toLowerCase();
|
|
27253
27326
|
}
|
|
27254
27327
|
|
|
27255
27328
|
// src/repo-index-cloud-client.ts
|
|
@@ -27389,9 +27462,9 @@ async function gcRepoIndexCloud(deps) {
|
|
|
27389
27462
|
}
|
|
27390
27463
|
|
|
27391
27464
|
// src/repo-index-sync.ts
|
|
27392
|
-
var
|
|
27465
|
+
var import_node_fs30 = require("node:fs");
|
|
27393
27466
|
var import_node_os12 = require("node:os");
|
|
27394
|
-
var
|
|
27467
|
+
var import_node_path28 = require("node:path");
|
|
27395
27468
|
var import_node_child_process14 = require("node:child_process");
|
|
27396
27469
|
var MAX_EMBED_BACKFILL_ROUNDS = 40;
|
|
27397
27470
|
function normalizeRepo(raw) {
|
|
@@ -27435,7 +27508,7 @@ async function syncEstateRepoIndex(opts) {
|
|
|
27435
27508
|
const failed = [];
|
|
27436
27509
|
const skipped = [];
|
|
27437
27510
|
for (const repo of repos) {
|
|
27438
|
-
const dir = (0,
|
|
27511
|
+
const dir = (0, import_node_fs30.mkdtempSync)((0, import_node_path28.join)((0, import_node_os12.tmpdir)(), "mmi-repo-index-"));
|
|
27439
27512
|
try {
|
|
27440
27513
|
shallowClone(repo, dir, opts.githubToken);
|
|
27441
27514
|
const built = rebuildRepoIndex(dir, repo);
|
|
@@ -27485,7 +27558,7 @@ async function syncEstateRepoIndex(opts) {
|
|
|
27485
27558
|
failed.push({ repo, error: e.message });
|
|
27486
27559
|
} finally {
|
|
27487
27560
|
try {
|
|
27488
|
-
(0,
|
|
27561
|
+
(0, import_node_fs30.rmSync)(dir, { recursive: true, force: true });
|
|
27489
27562
|
} catch {
|
|
27490
27563
|
}
|
|
27491
27564
|
}
|
|
@@ -27494,7 +27567,7 @@ async function syncEstateRepoIndex(opts) {
|
|
|
27494
27567
|
}
|
|
27495
27568
|
|
|
27496
27569
|
// src/repo-index-health.ts
|
|
27497
|
-
var
|
|
27570
|
+
var import_node_fs31 = require("node:fs");
|
|
27498
27571
|
|
|
27499
27572
|
// testdata/repo-index-golden-queries.json
|
|
27500
27573
|
var repo_index_golden_queries_default = {
|
|
@@ -27536,7 +27609,7 @@ function assertGoldenSuite(raw, source) {
|
|
|
27536
27609
|
function loadGoldenSuite(path2) {
|
|
27537
27610
|
let text;
|
|
27538
27611
|
try {
|
|
27539
|
-
text = (0,
|
|
27612
|
+
text = (0, import_node_fs31.readFileSync)(path2, "utf8");
|
|
27540
27613
|
} catch (e) {
|
|
27541
27614
|
throw new Error(`golden suite unreadable at ${path2}: ${e.message}`);
|
|
27542
27615
|
}
|
|
@@ -27690,8 +27763,8 @@ async function runRepoIndexHealth(opts) {
|
|
|
27690
27763
|
|
|
27691
27764
|
// src/spawn-policy-core.ts
|
|
27692
27765
|
var import_node_child_process15 = require("node:child_process");
|
|
27693
|
-
var
|
|
27694
|
-
var
|
|
27766
|
+
var import_node_fs32 = require("node:fs");
|
|
27767
|
+
var import_node_path29 = require("node:path");
|
|
27695
27768
|
var SPAWNERS = ["spawn", "spawnSync", "exec", "execSync", "execFile", "execFileSync"];
|
|
27696
27769
|
var CALL_SOURCE = String.raw`(^|[^.\w$])(${SPAWNERS.join("|")})\s*\(`;
|
|
27697
27770
|
var SOURCE_EXT = /\.(ts|mts|cts|js|mjs|cjs)$/;
|
|
@@ -27777,7 +27850,7 @@ function runSpawnPolicy(root) {
|
|
|
27777
27850
|
for (const file of files) {
|
|
27778
27851
|
let raw;
|
|
27779
27852
|
try {
|
|
27780
|
-
raw = (0,
|
|
27853
|
+
raw = (0, import_node_fs32.readFileSync)((0, import_node_path29.join)(root, file), "utf8");
|
|
27781
27854
|
} catch {
|
|
27782
27855
|
continue;
|
|
27783
27856
|
}
|
|
@@ -27795,8 +27868,8 @@ function runSpawnPolicy(root) {
|
|
|
27795
27868
|
|
|
27796
27869
|
// src/test-policy-core.ts
|
|
27797
27870
|
var import_node_child_process16 = require("node:child_process");
|
|
27798
|
-
var
|
|
27799
|
-
var
|
|
27871
|
+
var import_node_fs33 = require("node:fs");
|
|
27872
|
+
var import_node_path30 = require("node:path");
|
|
27800
27873
|
var POLICY_FILE = "test-policy.json";
|
|
27801
27874
|
var TEST_RE = /\.(?:test|spec)\.[cm]?[jt]sx?$/;
|
|
27802
27875
|
var PY_TEST_RE = /(?:^|\/)test_[^/]*\.py$|_test\.py$/;
|
|
@@ -27849,7 +27922,7 @@ function isTestPath(path2) {
|
|
|
27849
27922
|
return TEST_RE.test(path2) || PY_TEST_RE.test(path2);
|
|
27850
27923
|
}
|
|
27851
27924
|
function loadPolicy(root, readFile9 = readFileOrNull2) {
|
|
27852
|
-
const raw = readFile9((0,
|
|
27925
|
+
const raw = readFile9((0, import_node_path30.join)(root, POLICY_FILE));
|
|
27853
27926
|
if (raw == null) return { mandatory: [], declared: false };
|
|
27854
27927
|
try {
|
|
27855
27928
|
return { ...JSON.parse(raw), declared: true };
|
|
@@ -27859,7 +27932,7 @@ function loadPolicy(root, readFile9 = readFileOrNull2) {
|
|
|
27859
27932
|
}
|
|
27860
27933
|
function readFileOrNull2(path2) {
|
|
27861
27934
|
try {
|
|
27862
|
-
return (0,
|
|
27935
|
+
return (0, import_node_fs33.readFileSync)(path2, "utf8");
|
|
27863
27936
|
} catch {
|
|
27864
27937
|
return null;
|
|
27865
27938
|
}
|
|
@@ -27886,12 +27959,12 @@ function classify(changed, policy, present = () => false) {
|
|
|
27886
27959
|
const removedProtected = [...removed].filter((p) => protectedBy.has(p)).map((p) => ({ path: p, why: protectedBy.get(p) ?? "" }));
|
|
27887
27960
|
return { mandatoryHits, untestedHits, testChanges, addedTests, removedProtected };
|
|
27888
27961
|
}
|
|
27889
|
-
function unresolvedProtectedEntries(policy, root, exists = (path2) => (0,
|
|
27890
|
-
return (policy.protected ?? []).map((p) => p.path).filter((p) => !exists((0,
|
|
27962
|
+
function unresolvedProtectedEntries(policy, root, exists = (path2) => (0, import_node_fs33.existsSync)(path2)) {
|
|
27963
|
+
return (policy.protected ?? []).map((p) => p.path).filter((p) => !exists((0, import_node_path30.join)(root, p)));
|
|
27891
27964
|
}
|
|
27892
|
-
function unresolvedSatisfiers(policy, root, exists = (path2) => (0,
|
|
27965
|
+
function unresolvedSatisfiers(policy, root, exists = (path2) => (0, import_node_fs33.existsSync)(path2)) {
|
|
27893
27966
|
const declared = (policy.mandatory ?? []).flatMap((m) => m.satisfiedBy ?? []);
|
|
27894
|
-
return [...new Set(declared)].filter((p) => !exists((0,
|
|
27967
|
+
return [...new Set(declared)].filter((p) => !exists((0, import_node_path30.join)(root, p)));
|
|
27895
27968
|
}
|
|
27896
27969
|
function evaluate(changed, policy, present = () => false) {
|
|
27897
27970
|
const { mandatoryHits, untestedHits, testChanges, addedTests, removedProtected } = classify(changed, policy, present);
|
|
@@ -28073,13 +28146,13 @@ function changedFilesSince(base, cwd) {
|
|
|
28073
28146
|
}
|
|
28074
28147
|
function runTestPolicy(root, deps = {}) {
|
|
28075
28148
|
const policy = deps.policy ?? loadPolicy(root);
|
|
28076
|
-
const exists = deps.exists ?? ((path2) => (0,
|
|
28149
|
+
const exists = deps.exists ?? ((path2) => (0, import_node_fs33.existsSync)(path2));
|
|
28077
28150
|
const counts = { mandatoryCount: (policy.mandatory ?? []).length, protectedCount: (policy.protected ?? []).length };
|
|
28078
28151
|
const base = deps.changed ? "(injected)" : resolveBase(root, deps.base);
|
|
28079
28152
|
const refusal = deps.changed ? null : untrustworthyRange(root, base);
|
|
28080
28153
|
const changed = deps.changed ?? (refusal ? [] : changedFilesSince(base, root));
|
|
28081
28154
|
const lookup = deps.override !== void 0 ? { override: deps.override, refusals: [] } : !deps.changed && !refusal ? readOverride(base, root) : { override: null, refusals: [] };
|
|
28082
|
-
const present = (path2) => exists((0,
|
|
28155
|
+
const present = (path2) => exists((0, import_node_path30.join)(root, path2));
|
|
28083
28156
|
const removedByThisDiff = removedPaths(changed);
|
|
28084
28157
|
const staleFindings = [];
|
|
28085
28158
|
const unresolved = unresolvedProtectedEntries(policy, root, exists).filter((p) => !removedByThisDiff.has(p));
|
|
@@ -28117,8 +28190,8 @@ function runTestPolicy(root, deps = {}) {
|
|
|
28117
28190
|
}
|
|
28118
28191
|
|
|
28119
28192
|
// src/project-info-sync.ts
|
|
28120
|
-
var
|
|
28121
|
-
var
|
|
28193
|
+
var import_node_fs34 = require("node:fs");
|
|
28194
|
+
var import_node_path31 = require("node:path");
|
|
28122
28195
|
var UPDATE_PROJECT_INFO = `mutation($projectId: ID!, $shortDescription: String!, $readme: String!) {
|
|
28123
28196
|
updateProjectV2(input: { projectId: $projectId, shortDescription: $shortDescription, readme: $readme }) {
|
|
28124
28197
|
projectV2 { id }
|
|
@@ -28163,14 +28236,14 @@ function sharedName(entries, fallback) {
|
|
|
28163
28236
|
}
|
|
28164
28237
|
function buildProjectInfoSyncPlan(targetRepo2, project2, projects, repoRoot2) {
|
|
28165
28238
|
if (!project2.projectId) throw new Error(`org project sync-info: ${targetRepo2} registry META has no projectId`);
|
|
28166
|
-
const readmePath = (0,
|
|
28167
|
-
if (!(0,
|
|
28239
|
+
const readmePath = (0, import_node_path31.join)(repoRoot2, "README.md");
|
|
28240
|
+
if (!(0, import_node_fs34.existsSync)(readmePath)) throw new Error(`org project sync-info: ${targetRepo2} has no README.md`);
|
|
28168
28241
|
const entries = entriesFor(project2, projects);
|
|
28169
28242
|
const memberRepos = [...new Set(entries.flatMap((entry) => entry.repos ?? []))].filter((repo) => /^[^/]+\/[^/]+$/.test(repo)).sort((a, b) => a.localeCompare(b));
|
|
28170
28243
|
const projectName = sharedName(entries, project2.name?.trim() || targetRepo2.split("/").pop() || targetRepo2);
|
|
28171
28244
|
if (!memberRepos.length) throw new Error(`org project sync-info: project ${projectName} has no registered member repos`);
|
|
28172
28245
|
const entryNames = entries.map((entry) => entry.name?.trim()).filter((name) => Boolean(name));
|
|
28173
|
-
const shortDescription = memberRepos.length === 1 ? shortDescriptionFromReadme((0,
|
|
28246
|
+
const shortDescription = memberRepos.length === 1 ? shortDescriptionFromReadme((0, import_node_fs34.readFileSync)(readmePath, "utf8")) : `Shared work across ${new Intl.ListFormat("en", { type: "conjunction" }).format(entryNames)}.`;
|
|
28174
28247
|
const lines = [
|
|
28175
28248
|
`# ${projectName}`,
|
|
28176
28249
|
"",
|
|
@@ -28189,8 +28262,8 @@ function buildProjectInfoSyncPlan(targetRepo2, project2, projects, repoRoot2) {
|
|
|
28189
28262
|
const targetBase = `https://github.com/${targetRepo2}`;
|
|
28190
28263
|
const targetBranch = branchFor(targetRepo2, projects);
|
|
28191
28264
|
const orgDocs = [
|
|
28192
|
-
(0,
|
|
28193
|
-
(0,
|
|
28265
|
+
(0, import_node_fs34.existsSync)((0, import_node_path31.join)(repoRoot2, "docs", "org-readme.md")) ? `- [Org identity](${targetBase}/blob/${targetBranch}/docs/org-readme.md)` : "",
|
|
28266
|
+
(0, import_node_fs34.existsSync)((0, import_node_path31.join)(repoRoot2, "docs", "org-architecture.md")) ? `- [Org architecture](${targetBase}/blob/${targetBranch}/docs/org-architecture.md)` : ""
|
|
28194
28267
|
].filter(Boolean);
|
|
28195
28268
|
if (orgDocs.length) lines.push("", "## Organisation docs", "", ...orgDocs);
|
|
28196
28269
|
return { projectId: project2.projectId, projectName, targetRepo: targetRepo2, memberRepos, shortDescription, readme: `${lines.join("\n")}
|
|
@@ -28212,7 +28285,7 @@ async function syncProjectInfo(plan, client, apply) {
|
|
|
28212
28285
|
}
|
|
28213
28286
|
|
|
28214
28287
|
// src/project-set.ts
|
|
28215
|
-
var UNSET_KEYS = ["oauth", "requiredRuntimeSecrets", "requiredBuildSecrets", "secrets", "edgeDomains", "requiredGcpApis", "publishRequired", "publishDir", "dsManifestPath", "fofuEnabled", "consumesDesignSystem", "ci", "requiredChecks", "ciExemptReason", "gate", "seedCanary"];
|
|
28288
|
+
var UNSET_KEYS = ["oauth", "requiredRuntimeSecrets", "requiredBuildSecrets", "tenantTasks", "secrets", "edgeDomains", "requiredGcpApis", "publishRequired", "publishDir", "dsManifestPath", "fofuEnabled", "consumesDesignSystem", "ci", "requiredChecks", "ciExemptReason", "gate", "seedCanary"];
|
|
28216
28289
|
var UNSET_KEY_SET = new Set(UNSET_KEYS);
|
|
28217
28290
|
var RUNTIME_SECRET_STAGES = ["dev", "rc", "main"];
|
|
28218
28291
|
var SECRET_CONSUMERS = ["runtime", "build", "lambda", "actions", "agent", "box"];
|
|
@@ -28537,6 +28610,43 @@ function parseGateVar(raw) {
|
|
|
28537
28610
|
}
|
|
28538
28611
|
return out;
|
|
28539
28612
|
}
|
|
28613
|
+
function parseTenantTasksVar(raw) {
|
|
28614
|
+
let parsed;
|
|
28615
|
+
try {
|
|
28616
|
+
parsed = JSON.parse(raw);
|
|
28617
|
+
} catch {
|
|
28618
|
+
throw new Error("org project set: tenantTasks must be valid JSON");
|
|
28619
|
+
}
|
|
28620
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error("org project set: tenantTasks must be a JSON object");
|
|
28621
|
+
const entries = Object.entries(parsed);
|
|
28622
|
+
if (entries.length > 20) throw new Error("org project set: tenantTasks supports at most 20 declarations");
|
|
28623
|
+
const out = {};
|
|
28624
|
+
const nameRe = /^[a-z0-9][a-z0-9-]{0,62}$/;
|
|
28625
|
+
const serviceRe = /^[A-Za-z0-9][A-Za-z0-9_.-]{0,62}$/;
|
|
28626
|
+
const validStages = /* @__PURE__ */ new Set(["dev", "rc", "main"]);
|
|
28627
|
+
for (const [name, rawTask] of entries) {
|
|
28628
|
+
if (!nameRe.test(name)) throw new Error(`org project set: tenantTasks name ${JSON.stringify(name)} must be lowercase kebab-case`);
|
|
28629
|
+
if (!rawTask || typeof rawTask !== "object" || Array.isArray(rawTask)) throw new Error(`org project set: tenantTasks.${name} must be an object`);
|
|
28630
|
+
const task = rawTask;
|
|
28631
|
+
if (Object.keys(task).some((key) => !["service", "command", "stages", "timeoutSeconds", "artifact"].includes(key))) throw new Error(`org project set: tenantTasks.${name} has an unknown field`);
|
|
28632
|
+
if (typeof task.service !== "string" || !serviceRe.test(task.service)) throw new Error(`org project set: tenantTasks.${name}.service has an unsafe shape`);
|
|
28633
|
+
if (!Array.isArray(task.command) || task.command.length < 1 || task.command.length > 32 || task.command.some((arg) => typeof arg !== "string" || arg.length < 1 || arg.length > 256 || /[\u0000\r\n]/.test(arg))) throw new Error(`org project set: tenantTasks.${name}.command must be 1-32 bounded argv strings`);
|
|
28634
|
+
if (!Array.isArray(task.stages) || task.stages.length < 1 || task.stages.length > 3 || task.stages.some((stage) => typeof stage !== "string" || !validStages.has(stage)) || new Set(task.stages).size !== task.stages.length) throw new Error(`org project set: tenantTasks.${name}.stages must be unique dev/rc/main values`);
|
|
28635
|
+
if (task.timeoutSeconds !== void 0 && (!Number.isInteger(task.timeoutSeconds) || task.timeoutSeconds < 1 || task.timeoutSeconds > 3600)) throw new Error(`org project set: tenantTasks.${name}.timeoutSeconds must be an integer 1..3600`);
|
|
28636
|
+
const artifact = task.artifact ?? "none";
|
|
28637
|
+
if (artifact !== "none" && artifact !== "required") throw new Error(`org project set: tenantTasks.${name}.artifact must be none or required`);
|
|
28638
|
+
const carriesPlaceholder = task.command.some((arg) => arg.includes("{artifact}"));
|
|
28639
|
+
if (artifact === "required" !== carriesPlaceholder) throw new Error(`org project set: tenantTasks.${name} must use {artifact} exactly when artifact is required`);
|
|
28640
|
+
out[name] = {
|
|
28641
|
+
service: task.service,
|
|
28642
|
+
command: task.command,
|
|
28643
|
+
stages: task.stages,
|
|
28644
|
+
...task.timeoutSeconds !== void 0 ? { timeoutSeconds: task.timeoutSeconds } : {},
|
|
28645
|
+
...artifact !== "none" ? { artifact } : {}
|
|
28646
|
+
};
|
|
28647
|
+
}
|
|
28648
|
+
return out;
|
|
28649
|
+
}
|
|
28540
28650
|
var SETTABLE_VAR_KEYS = [
|
|
28541
28651
|
"name",
|
|
28542
28652
|
"division",
|
|
@@ -28556,6 +28666,7 @@ var SETTABLE_VAR_KEYS = [
|
|
|
28556
28666
|
"requiredGcpApis",
|
|
28557
28667
|
"requiredRuntimeSecrets",
|
|
28558
28668
|
"requiredBuildSecrets",
|
|
28669
|
+
"tenantTasks",
|
|
28559
28670
|
"edgeDomains",
|
|
28560
28671
|
"statusFieldId",
|
|
28561
28672
|
"statusOptions",
|
|
@@ -28584,6 +28695,7 @@ var SETTABLE_VAR_HINTS = {
|
|
|
28584
28695
|
requiredGcpApis: "comma-string",
|
|
28585
28696
|
requiredRuntimeSecrets: 'JSON stage map, e.g. {"dev":["KEY"],"rc":["KEY"],"main":["KEY"]}',
|
|
28586
28697
|
requiredBuildSecrets: 'JSON flat array, e.g. ["NODE_AUTH_TOKEN=@github-packages-token"]',
|
|
28698
|
+
tenantTasks: 'JSON map {name:{service,command[],stages[],timeoutSeconds?,artifact?:"required"}}; use {artifact} in argv when required',
|
|
28587
28699
|
secrets: "JSON catalog map keyed by KEY {key,purpose,group,owner,stages[],consumers[]} \u2014 merged per entry; clear with --unset secrets; prefer --secrets-file",
|
|
28588
28700
|
edgeDomains: "JSON {dev,rc,main} domain map",
|
|
28589
28701
|
statusOptions: "JSON name\u2192id map",
|
|
@@ -28656,6 +28768,8 @@ function buildProjectSetPatch(input) {
|
|
|
28656
28768
|
patch[key] = parseRuntimeSecretsVar(raw);
|
|
28657
28769
|
} else if (key === "requiredBuildSecrets") {
|
|
28658
28770
|
patch[key] = parseBuildSecretsVar(raw);
|
|
28771
|
+
} else if (key === "tenantTasks") {
|
|
28772
|
+
patch[key] = parseTenantTasksVar(raw);
|
|
28659
28773
|
} else if (key === "secrets") {
|
|
28660
28774
|
patch[key] = parseSecretsCatalogVar(raw);
|
|
28661
28775
|
} else if (key === "edgeDomains") {
|
|
@@ -28975,8 +29089,8 @@ function writeError(res) {
|
|
|
28975
29089
|
}
|
|
28976
29090
|
|
|
28977
29091
|
// src/secrets-commands.ts
|
|
28978
|
-
var
|
|
28979
|
-
var
|
|
29092
|
+
var import_node_fs35 = require("node:fs");
|
|
29093
|
+
var import_node_path32 = require("node:path");
|
|
28980
29094
|
var import_node_os13 = require("node:os");
|
|
28981
29095
|
|
|
28982
29096
|
// src/secrets-diff.ts
|
|
@@ -29079,18 +29193,18 @@ function collectMap(value, previous = []) {
|
|
|
29079
29193
|
return [...previous, value];
|
|
29080
29194
|
}
|
|
29081
29195
|
async function decryptRailsCredentials(input) {
|
|
29082
|
-
const appDir = (0,
|
|
29196
|
+
const appDir = (0, import_node_path32.resolve)(input.appDir ?? process.cwd());
|
|
29083
29197
|
const credentialsFile = input.credentialsFile ?? DEFAULT_RAILS_CREDENTIALS_FILE;
|
|
29084
29198
|
const masterKeyFile = input.masterKeyFile ?? DEFAULT_RAILS_MASTER_KEY_FILE;
|
|
29085
|
-
const credentialsPath = (0,
|
|
29086
|
-
const masterKeyPath = (0,
|
|
29199
|
+
const credentialsPath = (0, import_node_path32.resolve)(appDir, credentialsFile);
|
|
29200
|
+
const masterKeyPath = (0, import_node_path32.resolve)(appDir, masterKeyFile);
|
|
29087
29201
|
const env = {
|
|
29088
29202
|
...process.env,
|
|
29089
29203
|
MMI_RAILS_CREDENTIALS_FILE: credentialsPath,
|
|
29090
29204
|
MMI_RAILS_MASTER_KEY_FILE: masterKeyPath
|
|
29091
29205
|
};
|
|
29092
|
-
if ((0,
|
|
29093
|
-
env.RAILS_MASTER_KEY = (0,
|
|
29206
|
+
if ((0, import_node_fs35.existsSync)(masterKeyPath)) {
|
|
29207
|
+
env.RAILS_MASTER_KEY = (0, import_node_fs35.readFileSync)(masterKeyPath, "utf8").trim();
|
|
29094
29208
|
}
|
|
29095
29209
|
const script = [
|
|
29096
29210
|
'require "json"',
|
|
@@ -29100,9 +29214,9 @@ async function decryptRailsCredentials(input) {
|
|
|
29100
29214
|
'config = ActiveSupport::EncryptedConfiguration.new(config_path: config_path, key_path: key_path, env_key: "RAILS_MASTER_KEY", raise_if_missing_key: true)',
|
|
29101
29215
|
"puts JSON.generate(config.config)"
|
|
29102
29216
|
].join("\n");
|
|
29103
|
-
const scriptDir = (0,
|
|
29104
|
-
const scriptPath = (0,
|
|
29105
|
-
(0,
|
|
29217
|
+
const scriptDir = (0, import_node_fs35.mkdtempSync)((0, import_node_path32.join)((0, import_node_os13.tmpdir)(), "mmi-rails-decrypt-"));
|
|
29218
|
+
const scriptPath = (0, import_node_path32.join)(scriptDir, "decrypt.rb");
|
|
29219
|
+
(0, import_node_fs35.writeFileSync)(scriptPath, script, "utf8");
|
|
29106
29220
|
try {
|
|
29107
29221
|
const args = ["exec", "ruby", scriptPath];
|
|
29108
29222
|
const cmd = process.platform === "win32" ? "cmd.exe" : "bundle";
|
|
@@ -29114,7 +29228,7 @@ async function decryptRailsCredentials(input) {
|
|
|
29114
29228
|
});
|
|
29115
29229
|
return JSON.parse(stdout);
|
|
29116
29230
|
} finally {
|
|
29117
|
-
(0,
|
|
29231
|
+
(0, import_node_fs35.rmSync)(scriptDir, { recursive: true, force: true });
|
|
29118
29232
|
}
|
|
29119
29233
|
}
|
|
29120
29234
|
async function readSecretStdin() {
|
|
@@ -29204,7 +29318,7 @@ function registerSecretsCommands(program3) {
|
|
|
29204
29318
|
let body;
|
|
29205
29319
|
if (o.file) {
|
|
29206
29320
|
try {
|
|
29207
|
-
body = (0,
|
|
29321
|
+
body = (0, import_node_fs35.readFileSync)((0, import_node_path32.resolve)(o.file), "utf8");
|
|
29208
29322
|
} catch (e) {
|
|
29209
29323
|
return fail(`secrets org-catalog: cannot read --file ${o.file}: ${e.message}`);
|
|
29210
29324
|
}
|
|
@@ -29309,7 +29423,7 @@ function registerSecretsCommands(program3) {
|
|
|
29309
29423
|
{
|
|
29310
29424
|
...d,
|
|
29311
29425
|
decryptRailsCredentials,
|
|
29312
|
-
removeFile: (path2) => (0,
|
|
29426
|
+
removeFile: (path2) => (0, import_node_fs35.unlinkSync)((0, import_node_path32.resolve)(o.appDir ?? process.cwd(), path2))
|
|
29313
29427
|
},
|
|
29314
29428
|
{
|
|
29315
29429
|
repo: o.repo,
|
|
@@ -29354,7 +29468,7 @@ function registerSecretsCommands(program3) {
|
|
|
29354
29468
|
}
|
|
29355
29469
|
|
|
29356
29470
|
// src/app-actor.ts
|
|
29357
|
-
var
|
|
29471
|
+
var import_node_crypto6 = require("node:crypto");
|
|
29358
29472
|
var APP_ACTOR_ENV = "MMI_ACTOR";
|
|
29359
29473
|
var APP_VAULT_REPO = "mutmutco/MMI-Hub";
|
|
29360
29474
|
var APP_VAULT_KEYS = ["GITHUB_APP_ID", "GITHUB_APP_INSTALLATION_ID", "GITHUB_APP_PRIVATE_KEY"];
|
|
@@ -29398,7 +29512,7 @@ function mintAppJwt(appId, privateKeyPem, nowSec) {
|
|
|
29398
29512
|
exp: now + APP_JWT_TTL_S,
|
|
29399
29513
|
iss: appId
|
|
29400
29514
|
}));
|
|
29401
|
-
const signer = (0,
|
|
29515
|
+
const signer = (0, import_node_crypto6.createSign)("RSA-SHA256");
|
|
29402
29516
|
signer.update(`${header}.${payload}`);
|
|
29403
29517
|
return `${header}.${payload}.${signer.sign(privateKeyPem, "base64url")}`;
|
|
29404
29518
|
}
|
|
@@ -29514,7 +29628,7 @@ function emitCliCallTelemetry(command) {
|
|
|
29514
29628
|
}
|
|
29515
29629
|
|
|
29516
29630
|
// src/box-commands.ts
|
|
29517
|
-
var
|
|
29631
|
+
var import_node_fs36 = require("node:fs");
|
|
29518
29632
|
|
|
29519
29633
|
// src/box.ts
|
|
29520
29634
|
var BOX_KEYS = {
|
|
@@ -29593,7 +29707,7 @@ function formatBoxTable(boxes) {
|
|
|
29593
29707
|
const addrW = w((b) => b.address || "(no public ipv4)", "ADDRESS");
|
|
29594
29708
|
const projW = w((b) => b.project, "PROJECT");
|
|
29595
29709
|
const statW = w((b) => b.status, "STATUS");
|
|
29596
|
-
const row = (name, addr, proj,
|
|
29710
|
+
const row = (name, addr, proj, stat4, key) => `${name.padEnd(nameW)} ${addr.padEnd(addrW)} ${proj.padEnd(projW)} ${stat4.padEnd(statW)} ${key}`;
|
|
29597
29711
|
const lines = [row("BOX", "ADDRESS", "PROJECT", "STATUS", "SSH KEY (vault path)")];
|
|
29598
29712
|
for (const b of boxes) {
|
|
29599
29713
|
lines.push(row(b.name, b.address || "(no public ipv4)", b.project, b.status, b.sshKeyPath));
|
|
@@ -29717,7 +29831,7 @@ function registerBoxCommands(program3) {
|
|
|
29717
29831
|
}
|
|
29718
29832
|
if (o.json) console.log(JSON.stringify({ box: found, incomplete }, null, 2));
|
|
29719
29833
|
else if (o.ssh && o.script) {
|
|
29720
|
-
(0,
|
|
29834
|
+
(0, import_node_fs36.writeFileSync)(o.script, sshRecipeScript(found), "utf8");
|
|
29721
29835
|
console.log(`wrote ${o.script} \u2014 run: bash "${o.script}"`);
|
|
29722
29836
|
} else if (o.ssh) console.log(`${formatSshRecipe(found)}
|
|
29723
29837
|
${SSH_RECIPE_AGENT_NOTE}`);
|
|
@@ -29731,7 +29845,7 @@ ${SSH_RECIPE_AGENT_NOTE}`);
|
|
|
29731
29845
|
}
|
|
29732
29846
|
|
|
29733
29847
|
// src/schedules-commands.ts
|
|
29734
|
-
var
|
|
29848
|
+
var import_promises6 = require("node:fs/promises");
|
|
29735
29849
|
var import_node_child_process17 = require("node:child_process");
|
|
29736
29850
|
var import_node_util7 = require("node:util");
|
|
29737
29851
|
var execFileP5 = (0, import_node_util7.promisify)(import_node_child_process17.execFile);
|
|
@@ -29846,7 +29960,7 @@ async function awsJson(args) {
|
|
|
29846
29960
|
try {
|
|
29847
29961
|
return await run();
|
|
29848
29962
|
} catch {
|
|
29849
|
-
await new Promise((
|
|
29963
|
+
await new Promise((resolve6) => setTimeout(resolve6, AWS_RETRY_DELAY_MS));
|
|
29850
29964
|
return run();
|
|
29851
29965
|
}
|
|
29852
29966
|
}
|
|
@@ -29947,9 +30061,9 @@ function registerSchedulesCommands(program3) {
|
|
|
29947
30061
|
await failGraceful("org schedules --doc: refusing to regenerate the doc from an incomplete read (see warnings above).");
|
|
29948
30062
|
return;
|
|
29949
30063
|
}
|
|
29950
|
-
const docText = await (0,
|
|
30064
|
+
const docText = await (0, import_promises6.readFile)(o.doc, "utf8");
|
|
29951
30065
|
const spliced = spliceDoc(docText, renderDocSection(entries, now.toISOString()));
|
|
29952
|
-
await (0,
|
|
30066
|
+
await (0, import_promises6.writeFile)(o.doc, spliced, "utf8");
|
|
29953
30067
|
reportParked(parkedLines);
|
|
29954
30068
|
reportDrift(drift);
|
|
29955
30069
|
console.log(`org schedules: wrote ${entries.length} entries into ${o.doc}`);
|
|
@@ -30035,8 +30149,8 @@ function registerSchedulesCommands(program3) {
|
|
|
30035
30149
|
}
|
|
30036
30150
|
|
|
30037
30151
|
// src/schedules-lift-command.ts
|
|
30038
|
-
var
|
|
30039
|
-
var
|
|
30152
|
+
var import_promises7 = require("node:fs/promises");
|
|
30153
|
+
var import_node_path33 = require("node:path");
|
|
30040
30154
|
var DEFAULT_WORKFLOWS_DIR = ".github/workflows";
|
|
30041
30155
|
var SCHEDULE_REPO_RE = /^[A-Za-z0-9_.-]+$/;
|
|
30042
30156
|
var SchedulesLiftUsageError = class extends Error {
|
|
@@ -30056,14 +30170,14 @@ var RegistryUnreachableError = class extends Error {
|
|
|
30056
30170
|
async function readWorkflowFiles(dir) {
|
|
30057
30171
|
let names;
|
|
30058
30172
|
try {
|
|
30059
|
-
names = await (0,
|
|
30173
|
+
names = await (0, import_promises7.readdir)(dir);
|
|
30060
30174
|
} catch {
|
|
30061
30175
|
return [];
|
|
30062
30176
|
}
|
|
30063
30177
|
const files = [];
|
|
30064
30178
|
for (const name of names.sort()) {
|
|
30065
30179
|
if (!/\.ya?ml$/.test(name)) continue;
|
|
30066
|
-
files.push({ path: `.github/workflows/${name}`, text: await (0,
|
|
30180
|
+
files.push({ path: `.github/workflows/${name}`, text: await (0, import_promises7.readFile)((0, import_node_path33.join)(dir, name), "utf8") });
|
|
30067
30181
|
}
|
|
30068
30182
|
return files;
|
|
30069
30183
|
}
|
|
@@ -30211,12 +30325,12 @@ function registerEdgeCommands(program3) {
|
|
|
30211
30325
|
}
|
|
30212
30326
|
|
|
30213
30327
|
// src/bootstrap-commands.ts
|
|
30214
|
-
var
|
|
30328
|
+
var import_node_fs37 = require("node:fs");
|
|
30215
30329
|
var import_node_os14 = require("node:os");
|
|
30216
|
-
var
|
|
30330
|
+
var import_node_path34 = require("node:path");
|
|
30217
30331
|
|
|
30218
30332
|
// src/bootstrap-drift.ts
|
|
30219
|
-
var
|
|
30333
|
+
var import_node_crypto7 = require("node:crypto");
|
|
30220
30334
|
function byteComparableSeeds(manifest, cls) {
|
|
30221
30335
|
return manifest.seeds.filter((s) => s.ownership === "org" && s.source === "self" && s.classes.includes(cls));
|
|
30222
30336
|
}
|
|
@@ -30236,7 +30350,7 @@ function compareSeedBytes(hubContent, repoContent) {
|
|
|
30236
30350
|
return normalize(hubContent) === normalize(repoContent) ? "match" : "drift";
|
|
30237
30351
|
}
|
|
30238
30352
|
function seedContentHash(content) {
|
|
30239
|
-
return (0,
|
|
30353
|
+
return (0, import_node_crypto7.createHash)("sha256").update(content.replace(/\r\n/g, "\n"), "utf8").digest("hex");
|
|
30240
30354
|
}
|
|
30241
30355
|
function auditRepoSeedDrift(repo, seeds, hubContents, repoReads) {
|
|
30242
30356
|
const byTarget = new Map(repoReads.map((r) => [r.target, r.content]));
|
|
@@ -31093,13 +31207,13 @@ function registerBootstrapCommands(program3) {
|
|
|
31093
31207
|
client: defaultGitHubClient(),
|
|
31094
31208
|
projectMeta: meta,
|
|
31095
31209
|
deployModel: typeof meta?.deployModel === "string" ? meta.deployModel : void 0,
|
|
31096
|
-
readLocalFile: (path2) => path2 === "projects.json" && apiProjects != null ? apiProjects : (0,
|
|
31210
|
+
readLocalFile: (path2) => path2 === "projects.json" && apiProjects != null ? apiProjects : (0, import_node_fs37.existsSync)(path2) ? (0, import_node_fs37.readFileSync)(path2, "utf8") : null,
|
|
31097
31211
|
// requiredGcpApis is stored as an array by a JSON write, but `org project set --var KEY=VALUE` stores a raw
|
|
31098
31212
|
// comma-string — accept either so the seeded value verifies regardless of how it was written.
|
|
31099
31213
|
// #3689: the same committed map the org access audit reads (#3664), so a sanctioned admin is not a
|
|
31100
31214
|
// permanent bootstrap failure on one surface and an intended state on the other. Absent file → no
|
|
31101
31215
|
// sanction, which is the pre-#3664 behaviour.
|
|
31102
|
-
sanctionedAdmins: (0,
|
|
31216
|
+
sanctionedAdmins: (0, import_node_fs37.existsSync)("access-matrix.json") ? entriesValueByCanonicalRepo(loadSanctionedAdmins((0, import_node_fs37.readFileSync)("access-matrix.json", "utf8")), repo) : void 0,
|
|
31103
31217
|
requiredGcpApis: (() => {
|
|
31104
31218
|
const v = meta?.requiredGcpApis;
|
|
31105
31219
|
if (Array.isArray(v)) return v;
|
|
@@ -31152,14 +31266,14 @@ function registerBootstrapCommands(program3) {
|
|
|
31152
31266
|
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 () => {
|
|
31153
31267
|
const o = { repo: rawValue("--repo", ""), json: rawFlag("--json") };
|
|
31154
31268
|
const manifestPath = "skills/bootstrap/seeds/manifest.json";
|
|
31155
|
-
if (!(0,
|
|
31269
|
+
if (!(0, import_node_fs37.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`);
|
|
31156
31270
|
const seedSource = await resolveHubSeedSource(execGitForSeedSource);
|
|
31157
31271
|
if (!seedSource.ok) return fail(`bootstrap drift: ${seedSource.reason}`);
|
|
31158
|
-
const manifest = loadBootstrapSeeds((0,
|
|
31272
|
+
const manifest = loadBootstrapSeeds((0, import_node_fs37.readFileSync)(manifestPath, "utf8"));
|
|
31159
31273
|
const hubContents = /* @__PURE__ */ new Map();
|
|
31160
31274
|
for (const s of manifest.seeds) {
|
|
31161
31275
|
if (s.ownership !== "org" || s.source !== "self") continue;
|
|
31162
|
-
hubContents.set(s.target, (0,
|
|
31276
|
+
hubContents.set(s.target, (0, import_node_fs37.existsSync)(s.target) ? (0, import_node_fs37.readFileSync)(s.target, "utf8") : null);
|
|
31163
31277
|
}
|
|
31164
31278
|
let targets;
|
|
31165
31279
|
let classOf = (_repo) => "deployable";
|
|
@@ -31238,10 +31352,10 @@ function registerBootstrapCommands(program3) {
|
|
|
31238
31352
|
return fail(`bootstrap apply: ${e.message}`);
|
|
31239
31353
|
}
|
|
31240
31354
|
const manifestPath = "skills/bootstrap/seeds/manifest.json";
|
|
31241
|
-
if (!(0,
|
|
31355
|
+
if (!(0, import_node_fs37.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`);
|
|
31242
31356
|
const seedSource = await resolveHubSeedSource(execGitForSeedSource);
|
|
31243
31357
|
if (!seedSource.ok) return fail(`bootstrap apply: ${seedSource.reason}`);
|
|
31244
|
-
const manifest = loadBootstrapSeeds((0,
|
|
31358
|
+
const manifest = loadBootstrapSeeds((0, import_node_fs37.readFileSync)(manifestPath, "utf8"));
|
|
31245
31359
|
const baseBranch = o.class === "content" ? "main" : "development";
|
|
31246
31360
|
const slug = parsedRepo.slug;
|
|
31247
31361
|
const onlyTarget = o.only.trim();
|
|
@@ -31252,16 +31366,16 @@ function registerBootstrapCommands(program3) {
|
|
|
31252
31366
|
${known}`);
|
|
31253
31367
|
}
|
|
31254
31368
|
const gh = async (args) => execFileP2("gh", args, { timeout: 2e4 });
|
|
31255
|
-
const readFile9 = (p) => (0,
|
|
31369
|
+
const readFile9 = (p) => (0, import_node_fs37.existsSync)(p) ? (0, import_node_fs37.readFileSync)(p, "utf8") : null;
|
|
31256
31370
|
const enc = (p) => p.split("/").map(encodeURIComponent).join("/");
|
|
31257
31371
|
const putSeed = async (target, content, ref, sha) => {
|
|
31258
|
-
const tmp = (0,
|
|
31259
|
-
(0,
|
|
31372
|
+
const tmp = (0, import_node_path34.join)((0, import_node_os14.tmpdir)(), `mmi-seed-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
|
|
31373
|
+
(0, import_node_fs37.writeFileSync)(tmp, JSON.stringify(contentPutBody(target, content, ref, sha)), "utf8");
|
|
31260
31374
|
try {
|
|
31261
31375
|
await gh(contentPutInputArgs(repo, target, tmp));
|
|
31262
31376
|
} finally {
|
|
31263
31377
|
try {
|
|
31264
|
-
(0,
|
|
31378
|
+
(0, import_node_fs37.unlinkSync)(tmp);
|
|
31265
31379
|
} catch {
|
|
31266
31380
|
}
|
|
31267
31381
|
}
|
|
@@ -31526,10 +31640,10 @@ LIVE apply to ${repo}:
|
|
|
31526
31640
|
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 ownership:org + source:self seed, e.g. .github/workflows/agent-pr.yml)").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 () => {
|
|
31527
31641
|
const o = { target: rawValue("--target", ""), execute: rawFlag("--execute"), json: rawFlag("--json") };
|
|
31528
31642
|
const manifestPath = "skills/bootstrap/seeds/manifest.json";
|
|
31529
|
-
if (!(0,
|
|
31643
|
+
if (!(0, import_node_fs37.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`);
|
|
31530
31644
|
const seedSource = await resolveHubSeedSource(execGitForSeedSource);
|
|
31531
31645
|
if (!seedSource.ok) return fail(`bootstrap propagate: ${seedSource.reason}`);
|
|
31532
|
-
const manifest = loadBootstrapSeeds((0,
|
|
31646
|
+
const manifest = loadBootstrapSeeds((0, import_node_fs37.readFileSync)(manifestPath, "utf8"));
|
|
31533
31647
|
const propagatable = manifest.seeds.filter((s) => s.ownership === "org" && s.source === "self");
|
|
31534
31648
|
if (!o.target) {
|
|
31535
31649
|
return fail(`bootstrap propagate: --target <path> is required \u2014 one of:
|
|
@@ -31538,8 +31652,8 @@ LIVE apply to ${repo}:
|
|
|
31538
31652
|
const seed = propagatable.find((s) => s.target === o.target);
|
|
31539
31653
|
if (!seed) return fail(`bootstrap propagate: --target '${o.target}' names no ownership:org + source:self seed in ${manifestPath}. Propagatable targets:
|
|
31540
31654
|
${propagatable.map((s) => s.target).join("\n ")}`);
|
|
31541
|
-
if (!(0,
|
|
31542
|
-
const hubContent = (0,
|
|
31655
|
+
if (!(0, import_node_fs37.existsSync)(seed.target)) return fail(`bootstrap propagate: the Hub's own copy of '${seed.target}' is missing \u2014 nothing to propagate`);
|
|
31656
|
+
const hubContent = (0, import_node_fs37.readFileSync)(seed.target, "utf8");
|
|
31543
31657
|
const isWorkflowSeed = seed.target.startsWith(".github/workflows/");
|
|
31544
31658
|
const cfg = await loadConfig();
|
|
31545
31659
|
const projects = await fetchProjectsList(registryClientDeps(cfg));
|
|
@@ -31548,9 +31662,9 @@ LIVE apply to ${repo}:
|
|
|
31548
31662
|
}
|
|
31549
31663
|
const rosterRepos2 = collectRegistryRepos(projects).filter((r) => r.toLowerCase() !== "mutmutco/mmi-hub");
|
|
31550
31664
|
let independentCount = rosterRepos2.length;
|
|
31551
|
-
if ((0,
|
|
31665
|
+
if ((0, import_node_fs37.existsSync)("projects.json")) {
|
|
31552
31666
|
try {
|
|
31553
|
-
const local = JSON.parse((0,
|
|
31667
|
+
const local = JSON.parse((0, import_node_fs37.readFileSync)("projects.json", "utf8"));
|
|
31554
31668
|
const localRepos = /* @__PURE__ */ new Set();
|
|
31555
31669
|
for (const p of local.projects ?? []) for (const r of p.repos ?? []) {
|
|
31556
31670
|
const full = (r.includes("/") ? r : `mutmutco/${r}`).toLowerCase();
|
|
@@ -31666,13 +31780,13 @@ LIVE apply to ${repo}:
|
|
|
31666
31780
|
} catch {
|
|
31667
31781
|
existingSha = void 0;
|
|
31668
31782
|
}
|
|
31669
|
-
const tmp = (0,
|
|
31670
|
-
(0,
|
|
31783
|
+
const tmp = (0, import_node_path34.join)((0, import_node_os14.tmpdir)(), `mmi-propagate-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
|
|
31784
|
+
(0, import_node_fs37.writeFileSync)(tmp, JSON.stringify(contentPutBody(seed.target, hubContent, branch, existingSha)), "utf8");
|
|
31671
31785
|
try {
|
|
31672
31786
|
await gh(contentPutInputArgs(rec.repo, seed.target, tmp));
|
|
31673
31787
|
} finally {
|
|
31674
31788
|
try {
|
|
31675
|
-
(0,
|
|
31789
|
+
(0, import_node_fs37.unlinkSync)(tmp);
|
|
31676
31790
|
} catch {
|
|
31677
31791
|
}
|
|
31678
31792
|
}
|
|
@@ -31730,10 +31844,10 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
|
|
|
31730
31844
|
return fail(`bootstrap rollback: ${e.message}`);
|
|
31731
31845
|
}
|
|
31732
31846
|
const manifestPath = "skills/bootstrap/seeds/manifest.json";
|
|
31733
|
-
if (!(0,
|
|
31847
|
+
if (!(0, import_node_fs37.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)`);
|
|
31734
31848
|
const seedSource = await resolveHubSeedSource(execGitForSeedSource);
|
|
31735
31849
|
if (!seedSource.ok) return fail(`bootstrap rollback: ${seedSource.reason}`);
|
|
31736
|
-
const manifest = loadBootstrapSeeds((0,
|
|
31850
|
+
const manifest = loadBootstrapSeeds((0, import_node_fs37.readFileSync)(manifestPath, "utf8"));
|
|
31737
31851
|
const propagatable = manifest.seeds.filter((s) => s.ownership === "org" && s.source === "self");
|
|
31738
31852
|
if (!o.target) {
|
|
31739
31853
|
return fail(`bootstrap rollback: --target <path> is required \u2014 one of:
|
|
@@ -31750,10 +31864,10 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
|
|
|
31750
31864
|
const enc = (p) => p.split("/").map(encodeURIComponent).join("/");
|
|
31751
31865
|
let candidates;
|
|
31752
31866
|
if (o.record) {
|
|
31753
|
-
if (!(0,
|
|
31867
|
+
if (!(0, import_node_fs37.existsSync)(o.record)) return fail(`bootstrap rollback: --record '${o.record}' not found`);
|
|
31754
31868
|
let parsed;
|
|
31755
31869
|
try {
|
|
31756
|
-
parsed = JSON.parse((0,
|
|
31870
|
+
parsed = JSON.parse((0, import_node_fs37.readFileSync)(o.record, "utf8"));
|
|
31757
31871
|
} catch (e) {
|
|
31758
31872
|
return fail(`bootstrap rollback: --record '${o.record}' is not valid JSON: ${e.message}`);
|
|
31759
31873
|
}
|
|
@@ -31822,13 +31936,13 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
|
|
|
31822
31936
|
} catch {
|
|
31823
31937
|
existingSha = void 0;
|
|
31824
31938
|
}
|
|
31825
|
-
const tmp = (0,
|
|
31826
|
-
(0,
|
|
31939
|
+
const tmp = (0, import_node_path34.join)((0, import_node_os14.tmpdir)(), `mmi-rollback-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
|
|
31940
|
+
(0, import_node_fs37.writeFileSync)(tmp, JSON.stringify(contentPutBody(seed.target, preSeedContent, plan.branch, existingSha)), "utf8");
|
|
31827
31941
|
try {
|
|
31828
31942
|
await gh(contentPutInputArgs(repo, seed.target, tmp));
|
|
31829
31943
|
} finally {
|
|
31830
31944
|
try {
|
|
31831
|
-
(0,
|
|
31945
|
+
(0, import_node_fs37.unlinkSync)(tmp);
|
|
31832
31946
|
} catch {
|
|
31833
31947
|
}
|
|
31834
31948
|
}
|
|
@@ -31850,12 +31964,12 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
|
|
|
31850
31964
|
}
|
|
31851
31965
|
|
|
31852
31966
|
// src/stage-commands.ts
|
|
31853
|
-
var
|
|
31854
|
-
var
|
|
31967
|
+
var import_node_fs39 = require("node:fs");
|
|
31968
|
+
var import_node_path36 = require("node:path");
|
|
31855
31969
|
|
|
31856
31970
|
// src/port-registry.ts
|
|
31857
|
-
var
|
|
31858
|
-
var
|
|
31971
|
+
var import_node_fs38 = require("node:fs");
|
|
31972
|
+
var import_node_path35 = require("node:path");
|
|
31859
31973
|
|
|
31860
31974
|
// ../infra/port-geometry.mjs
|
|
31861
31975
|
var PORT_BLOCK = 100;
|
|
@@ -31869,8 +31983,8 @@ function nextPortBlock(registry2) {
|
|
|
31869
31983
|
return [base, base + PORT_SPAN];
|
|
31870
31984
|
}
|
|
31871
31985
|
function loadPortRegistry(path2) {
|
|
31872
|
-
if (!(0,
|
|
31873
|
-
const raw = JSON.parse((0,
|
|
31986
|
+
if (!(0, import_node_fs38.existsSync)(path2)) return {};
|
|
31987
|
+
const raw = JSON.parse((0, import_node_fs38.readFileSync)(path2, "utf8"));
|
|
31874
31988
|
const out = {};
|
|
31875
31989
|
for (const [key, value] of Object.entries(raw)) {
|
|
31876
31990
|
if (Array.isArray(value) && value.length === 2 && value.every((n) => typeof n === "number")) {
|
|
@@ -31884,9 +31998,9 @@ function ensurePortRange(repo, path2) {
|
|
|
31884
31998
|
const existing = registry2[repo];
|
|
31885
31999
|
if (existing) return existing;
|
|
31886
32000
|
const range = nextPortBlock(registry2);
|
|
31887
|
-
const raw = (0,
|
|
32001
|
+
const raw = (0, import_node_fs38.existsSync)(path2) ? JSON.parse((0, import_node_fs38.readFileSync)(path2, "utf8")) : {};
|
|
31888
32002
|
raw[repo] = range;
|
|
31889
|
-
(0,
|
|
32003
|
+
(0, import_node_fs38.writeFileSync)(path2, JSON.stringify(raw, null, 2) + "\n", "utf8");
|
|
31890
32004
|
return range;
|
|
31891
32005
|
}
|
|
31892
32006
|
function portCursorSeed(registry2) {
|
|
@@ -31908,22 +32022,22 @@ function existingPortRange(repo, registry2) {
|
|
|
31908
32022
|
return registry2[repo] ?? null;
|
|
31909
32023
|
}
|
|
31910
32024
|
function portRangeInfraAt(root, source) {
|
|
31911
|
-
const registryPath = (0,
|
|
31912
|
-
const ddbScriptPath = (0,
|
|
31913
|
-
if (!(0,
|
|
32025
|
+
const registryPath = (0, import_node_path35.join)(root, "infra", "port-ranges.json");
|
|
32026
|
+
const ddbScriptPath = (0, import_node_path35.join)(root, "infra", "port-ddb.mjs");
|
|
32027
|
+
if (!(0, import_node_fs38.existsSync)(registryPath) || !(0, import_node_fs38.existsSync)(ddbScriptPath)) return null;
|
|
31914
32028
|
return { root, source, registryPath, ddbScriptPath };
|
|
31915
32029
|
}
|
|
31916
32030
|
function resolvePortRangeInfra(cwd, packageDir) {
|
|
31917
32031
|
const direct = portRangeInfraAt(cwd, "cwd");
|
|
31918
32032
|
if (direct) return direct;
|
|
31919
|
-
for (let dir = cwd; ; dir = (0,
|
|
31920
|
-
const sibling = portRangeInfraAt((0,
|
|
32033
|
+
for (let dir = cwd; ; dir = (0, import_node_path35.dirname)(dir)) {
|
|
32034
|
+
const sibling = portRangeInfraAt((0, import_node_path35.join)(dir, "MMI-Hub"), "sibling-hub");
|
|
31921
32035
|
if (sibling) return sibling;
|
|
31922
|
-
const parent = (0,
|
|
32036
|
+
const parent = (0, import_node_path35.dirname)(dir);
|
|
31923
32037
|
if (parent === dir) break;
|
|
31924
32038
|
}
|
|
31925
32039
|
if (packageDir) {
|
|
31926
|
-
const pkgRoot = (0,
|
|
32040
|
+
const pkgRoot = (0, import_node_path35.join)(packageDir, "..", "..");
|
|
31927
32041
|
const pkgFrom = portRangeInfraAt(pkgRoot, "pkg-root");
|
|
31928
32042
|
if (pkgFrom) return pkgFrom;
|
|
31929
32043
|
}
|
|
@@ -32117,8 +32231,8 @@ function registerStageCommands(program3) {
|
|
|
32117
32231
|
const portRange = portRangeMeta && typeof portRangeMeta.start === "number" && typeof portRangeMeta.end === "number" ? [portRangeMeta.start, portRangeMeta.end] : void 0;
|
|
32118
32232
|
return decideStage({
|
|
32119
32233
|
registry: { deployModel: project2?.deployModel, portRange, error: read.ok ? void 0 : read.error },
|
|
32120
|
-
hasCompose: (0,
|
|
32121
|
-
hasEnvExample: (0,
|
|
32234
|
+
hasCompose: (0, import_node_fs39.existsSync)((0, import_node_path36.join)(process.cwd(), "docker-compose.yml")),
|
|
32235
|
+
hasEnvExample: (0, import_node_fs39.existsSync)((0, import_node_path36.join)(process.cwd(), ".env.example"))
|
|
32122
32236
|
});
|
|
32123
32237
|
}
|
|
32124
32238
|
async function fetchStageVaultEnvMerge() {
|
|
@@ -32610,9 +32724,9 @@ function registerBoardCommands(program3) {
|
|
|
32610
32724
|
}
|
|
32611
32725
|
|
|
32612
32726
|
// src/merge-cleanup.ts
|
|
32613
|
-
var
|
|
32614
|
-
var
|
|
32615
|
-
var
|
|
32727
|
+
var import_node_fs40 = require("node:fs");
|
|
32728
|
+
var import_promises9 = require("node:fs/promises");
|
|
32729
|
+
var import_node_path38 = require("node:path");
|
|
32616
32730
|
var import_node_os15 = require("node:os");
|
|
32617
32731
|
var import_node_child_process18 = require("node:child_process");
|
|
32618
32732
|
|
|
@@ -32699,23 +32813,23 @@ function boardAdvanceFailureMessage(result) {
|
|
|
32699
32813
|
}
|
|
32700
32814
|
|
|
32701
32815
|
// src/deferred-registry-store.ts
|
|
32702
|
-
var
|
|
32703
|
-
var
|
|
32704
|
-
var sleep2 = (ms) => new Promise((
|
|
32816
|
+
var import_promises8 = require("node:fs/promises");
|
|
32817
|
+
var import_node_path37 = require("node:path");
|
|
32818
|
+
var sleep2 = (ms) => new Promise((resolve6) => setTimeout(resolve6, ms));
|
|
32705
32819
|
async function atomicWrite(target, contents) {
|
|
32706
32820
|
const tmp = `${target}.tmp-${process.pid}-${Math.random().toString(36).slice(2)}`;
|
|
32707
|
-
await (0,
|
|
32821
|
+
await (0, import_promises8.writeFile)(tmp, contents, "utf8");
|
|
32708
32822
|
try {
|
|
32709
32823
|
await renameWithRetry(tmp, target);
|
|
32710
32824
|
} catch (e) {
|
|
32711
|
-
await (0,
|
|
32825
|
+
await (0, import_promises8.unlink)(tmp).catch(() => void 0);
|
|
32712
32826
|
throw e;
|
|
32713
32827
|
}
|
|
32714
32828
|
}
|
|
32715
32829
|
async function renameWithRetry(from, to, attempts = 5, backoffMs = 20) {
|
|
32716
32830
|
for (let i = 0; ; i++) {
|
|
32717
32831
|
try {
|
|
32718
|
-
await (0,
|
|
32832
|
+
await (0, import_promises8.rename)(from, to);
|
|
32719
32833
|
return;
|
|
32720
32834
|
} catch (e) {
|
|
32721
32835
|
const code = e.code;
|
|
@@ -32727,7 +32841,7 @@ async function renameWithRetry(from, to, attempts = 5, backoffMs = 20) {
|
|
|
32727
32841
|
async function readStrict(registryPath) {
|
|
32728
32842
|
let text;
|
|
32729
32843
|
try {
|
|
32730
|
-
text = await (0,
|
|
32844
|
+
text = await (0, import_promises8.readFile)(registryPath, "utf8");
|
|
32731
32845
|
} catch (e) {
|
|
32732
32846
|
if (e.code === "ENOENT") return [];
|
|
32733
32847
|
throw e;
|
|
@@ -32744,19 +32858,19 @@ function makeDeferredWorktreeStore(registryPath, lockOpts = {}) {
|
|
|
32744
32858
|
// Lenient read for the sweep's initial fetch: any error (missing/corrupt) yields an empty queue.
|
|
32745
32859
|
read: async () => {
|
|
32746
32860
|
try {
|
|
32747
|
-
return parseDeferredWorktreesFile(await (0,
|
|
32861
|
+
return parseDeferredWorktreesFile(await (0, import_promises8.readFile)(registryPath, "utf8"));
|
|
32748
32862
|
} catch {
|
|
32749
32863
|
return [];
|
|
32750
32864
|
}
|
|
32751
32865
|
},
|
|
32752
32866
|
// Standalone atomic write — THROWS on failure (no best-effort swallow, #2846).
|
|
32753
32867
|
write: async (entries) => {
|
|
32754
|
-
await (0,
|
|
32868
|
+
await (0, import_promises8.mkdir)((0, import_node_path37.dirname)(registryPath), { recursive: true });
|
|
32755
32869
|
await atomicWrite(registryPath, serializeDeferredWorktrees(entries));
|
|
32756
32870
|
},
|
|
32757
32871
|
// Serialized read-modify-write under the repo-wide lock (#2846).
|
|
32758
32872
|
update: async (mutate) => {
|
|
32759
|
-
await (0,
|
|
32873
|
+
await (0, import_promises8.mkdir)((0, import_node_path37.dirname)(registryPath), { recursive: true });
|
|
32760
32874
|
const deadline = Date.now() + opts.maxWaitMs;
|
|
32761
32875
|
for (; ; ) {
|
|
32762
32876
|
const guard = await acquireLock(lockPath, opts, deadline);
|
|
@@ -32927,7 +33041,7 @@ async function applyGcPlan(plan, remote, opts = {}) {
|
|
|
32927
33041
|
);
|
|
32928
33042
|
const repoRoot2 = (await execFileP2("git", ["rev-parse", "--show-toplevel"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim() || process.cwd();
|
|
32929
33043
|
const worktreeGitRoot = await currentRepoWorktreeGitRoot(repoRoot2);
|
|
32930
|
-
const primaryRepoRoot = worktreeGitRoot ? (0,
|
|
33044
|
+
const primaryRepoRoot = worktreeGitRoot ? (0, import_node_path38.dirname)((0, import_node_path38.dirname)(worktreeGitRoot)) : repoRoot2;
|
|
32931
33045
|
const gcActor = describeActor({ env: process.env, surface: detectSurface(process.env), cwd: process.cwd() });
|
|
32932
33046
|
const owners = readWorktreeOwners(primaryRepoRoot);
|
|
32933
33047
|
const removalNow = Date.now();
|
|
@@ -32984,7 +33098,7 @@ async function applyGcPlan(plan, remote, opts = {}) {
|
|
|
32984
33098
|
const cleanup = await cleanupPrMergeLocalBranch(branch.branch, {
|
|
32985
33099
|
beforeWorktrees,
|
|
32986
33100
|
startingPath: branch.worktreePath,
|
|
32987
|
-
pathExists: (p) => (0,
|
|
33101
|
+
pathExists: (p) => (0, import_node_fs40.existsSync)(p),
|
|
32988
33102
|
execGit: async (args) => (await execFileP2("git", args, { timeout: GIT_TIMEOUT_MS })).stdout,
|
|
32989
33103
|
teardownWorktreeStage,
|
|
32990
33104
|
deferredStore,
|
|
@@ -33022,7 +33136,7 @@ async function applyGcPlan(plan, remote, opts = {}) {
|
|
|
33022
33136
|
let removalAttempted = false;
|
|
33023
33137
|
try {
|
|
33024
33138
|
const cleanupTarget = resolveSafeSiblingWorktreeCleanupTarget(wt.path, cleanupRoots, {
|
|
33025
|
-
realpath: (path2) => (0,
|
|
33139
|
+
realpath: (path2) => (0, import_node_fs40.realpathSync)(path2)
|
|
33026
33140
|
});
|
|
33027
33141
|
if (!cleanupTarget.ok) {
|
|
33028
33142
|
result.failed.push(`${wt.path}: ${cleanupTarget.reason}`);
|
|
@@ -33109,13 +33223,13 @@ async function composeOverrideBodyFile(prNumber, repoArgs, gh) {
|
|
|
33109
33223
|
const commits = JSON.parse(raw).commits ?? [];
|
|
33110
33224
|
const body = squashBodyWithOverride(commits.map((c) => ({ headline: c.messageHeadline ?? "", body: c.messageBody ?? "" })), process.cwd());
|
|
33111
33225
|
if (!body) return void 0;
|
|
33112
|
-
const dir = (0,
|
|
33113
|
-
const path2 = (0,
|
|
33114
|
-
(0,
|
|
33226
|
+
const dir = (0, import_node_fs40.mkdtempSync)((0, import_node_path38.join)((0, import_node_os15.tmpdir)(), "mmi-squash-body-"));
|
|
33227
|
+
const path2 = (0, import_node_path38.join)(dir, "body.txt");
|
|
33228
|
+
(0, import_node_fs40.writeFileSync)(path2, `${body}
|
|
33115
33229
|
`, "utf8");
|
|
33116
33230
|
return { path: path2, cleanup: () => {
|
|
33117
33231
|
try {
|
|
33118
|
-
(0,
|
|
33232
|
+
(0, import_node_fs40.rmSync)(dir, { recursive: true, force: true });
|
|
33119
33233
|
} catch {
|
|
33120
33234
|
}
|
|
33121
33235
|
} };
|
|
@@ -33237,13 +33351,13 @@ var realWorktreeDirRemover = {
|
|
|
33237
33351
|
probe: (p) => {
|
|
33238
33352
|
let st;
|
|
33239
33353
|
try {
|
|
33240
|
-
st = (0,
|
|
33354
|
+
st = (0, import_node_fs40.lstatSync)(p);
|
|
33241
33355
|
} catch {
|
|
33242
33356
|
return null;
|
|
33243
33357
|
}
|
|
33244
33358
|
if (st.isSymbolicLink()) return "link";
|
|
33245
33359
|
try {
|
|
33246
|
-
(0,
|
|
33360
|
+
(0, import_node_fs40.readlinkSync)(p);
|
|
33247
33361
|
return "link";
|
|
33248
33362
|
} catch {
|
|
33249
33363
|
}
|
|
@@ -33251,7 +33365,7 @@ var realWorktreeDirRemover = {
|
|
|
33251
33365
|
},
|
|
33252
33366
|
readdir: (p) => {
|
|
33253
33367
|
try {
|
|
33254
|
-
return (0,
|
|
33368
|
+
return (0, import_node_fs40.readdirSync)(p);
|
|
33255
33369
|
} catch {
|
|
33256
33370
|
return [];
|
|
33257
33371
|
}
|
|
@@ -33260,12 +33374,12 @@ var realWorktreeDirRemover = {
|
|
|
33260
33374
|
// leaving the target); a file symlink with unlink. rmdir first, fall back to unlink.
|
|
33261
33375
|
detachLink: (p) => {
|
|
33262
33376
|
try {
|
|
33263
|
-
(0,
|
|
33377
|
+
(0, import_node_fs40.rmdirSync)(p);
|
|
33264
33378
|
} catch {
|
|
33265
|
-
(0,
|
|
33379
|
+
(0, import_node_fs40.unlinkSync)(p);
|
|
33266
33380
|
}
|
|
33267
33381
|
},
|
|
33268
|
-
removeTree: (p) => (0,
|
|
33382
|
+
removeTree: (p) => (0, import_promises9.rm)(p, { recursive: true, force: true, maxRetries: 5, retryDelay: 200 })
|
|
33269
33383
|
};
|
|
33270
33384
|
async function resolvePrimaryCheckout(execGit) {
|
|
33271
33385
|
try {
|
|
@@ -33277,13 +33391,13 @@ async function resolvePrimaryCheckout(execGit) {
|
|
|
33277
33391
|
function worktreeRemoveDeps(execGit) {
|
|
33278
33392
|
return {
|
|
33279
33393
|
git: execGit,
|
|
33280
|
-
sleep: (ms) => new Promise((
|
|
33394
|
+
sleep: (ms) => new Promise((resolve6) => setTimeout(resolve6, ms)),
|
|
33281
33395
|
// #3064: unlink any reparse point (esp. a `node_modules` junction to base) before the git-native
|
|
33282
33396
|
// `worktree remove --force`, which would otherwise recurse through it and empty the base checkout.
|
|
33283
33397
|
detachReparsePoints: (worktreePath) => detachReparsePoints(worktreePath, realWorktreeDirRemover),
|
|
33284
33398
|
removeWorktreeDir: async (worktreePath) => removeWorktreeTree(worktreePath, await resolvePrimaryCheckout(execGit), realWorktreeDirRemover),
|
|
33285
33399
|
// #4850: verify the directory is actually gone before any caller reports completion.
|
|
33286
|
-
pathExists: (worktreePath) => (0,
|
|
33400
|
+
pathExists: (worktreePath) => (0, import_node_fs40.existsSync)(worktreePath)
|
|
33287
33401
|
};
|
|
33288
33402
|
}
|
|
33289
33403
|
async function worktreeHasStageState(worktreePath) {
|
|
@@ -33297,9 +33411,9 @@ async function worktreeHasStageState(worktreePath) {
|
|
|
33297
33411
|
}
|
|
33298
33412
|
}
|
|
33299
33413
|
function stageStateFileBelongsToWorktree(statePath, worktreePath) {
|
|
33300
|
-
if (!(0,
|
|
33414
|
+
if (!(0, import_node_fs40.existsSync)(statePath)) return false;
|
|
33301
33415
|
try {
|
|
33302
|
-
const state = JSON.parse((0,
|
|
33416
|
+
const state = JSON.parse((0, import_node_fs40.readFileSync)(statePath, "utf8"));
|
|
33303
33417
|
const recordedCwd = typeof state.identity?.cwd === "string" ? state.identity.cwd : typeof state.cwd === "string" ? state.cwd : "";
|
|
33304
33418
|
return Boolean(recordedCwd && isPathUnderDirectory2(recordedCwd, worktreePath));
|
|
33305
33419
|
} catch {
|
|
@@ -33456,7 +33570,7 @@ var PR_SNAPSHOT_READ_DELAY_MS = 2e3;
|
|
|
33456
33570
|
async function readRestPrSnapshotWithRetry(prNumber, repo, gh = defaultGhApi, options) {
|
|
33457
33571
|
const retries = options?.retries ?? PR_SNAPSHOT_READ_RETRIES;
|
|
33458
33572
|
const delayMs = options?.delayMs ?? PR_SNAPSHOT_READ_DELAY_MS;
|
|
33459
|
-
const sleep3 = options?.sleep ?? ((ms) => new Promise((
|
|
33573
|
+
const sleep3 = options?.sleep ?? ((ms) => new Promise((resolve6) => setTimeout(resolve6, ms)));
|
|
33460
33574
|
let lastError = "no attempt completed";
|
|
33461
33575
|
for (let attempt = 0; attempt < retries; attempt++) {
|
|
33462
33576
|
try {
|
|
@@ -33734,14 +33848,14 @@ async function checkDocsIndexAtHead(opts, deps) {
|
|
|
33734
33848
|
}
|
|
33735
33849
|
|
|
33736
33850
|
// src/worktree-lifecycle-commands.ts
|
|
33737
|
-
var
|
|
33738
|
-
var
|
|
33739
|
-
var
|
|
33851
|
+
var import_node_fs42 = require("node:fs");
|
|
33852
|
+
var import_promises10 = require("node:fs/promises");
|
|
33853
|
+
var import_node_path40 = require("node:path");
|
|
33740
33854
|
|
|
33741
33855
|
// src/worktree-install-cache.ts
|
|
33742
|
-
var
|
|
33743
|
-
var
|
|
33744
|
-
var
|
|
33856
|
+
var import_node_crypto8 = require("node:crypto");
|
|
33857
|
+
var import_node_fs41 = require("node:fs");
|
|
33858
|
+
var import_node_path39 = require("node:path");
|
|
33745
33859
|
var CACHE_DIR = "worktree-install-cache";
|
|
33746
33860
|
var MANIFEST = "manifest.json";
|
|
33747
33861
|
var NODE_MODULES2 = "node_modules";
|
|
@@ -33754,24 +33868,24 @@ var LOCKFILE_NAMES = [
|
|
|
33754
33868
|
"package-lock.json"
|
|
33755
33869
|
];
|
|
33756
33870
|
var realWorktreeInstallCacheFs = {
|
|
33757
|
-
exists:
|
|
33758
|
-
readFile: (path2) => (0,
|
|
33759
|
-
lstat: (path2) => (0,
|
|
33760
|
-
copyDir: (from, to) => (0,
|
|
33871
|
+
exists: import_node_fs41.existsSync,
|
|
33872
|
+
readFile: (path2) => (0, import_node_fs41.readFileSync)(path2, "utf8"),
|
|
33873
|
+
lstat: (path2) => (0, import_node_fs41.lstatSync)(path2),
|
|
33874
|
+
copyDir: (from, to) => (0, import_node_fs41.cpSync)(from, to, { recursive: true, force: true }),
|
|
33761
33875
|
mkdirp: (path2) => {
|
|
33762
|
-
(0,
|
|
33876
|
+
(0, import_node_fs41.mkdirSync)(path2, { recursive: true });
|
|
33763
33877
|
},
|
|
33764
|
-
writeFile: (path2, contents) => (0,
|
|
33878
|
+
writeFile: (path2, contents) => (0, import_node_fs41.writeFileSync)(path2, contents, "utf8"),
|
|
33765
33879
|
rm: (path2) => {
|
|
33766
|
-
(0,
|
|
33880
|
+
(0, import_node_fs41.rmSync)(path2, { recursive: true, force: true });
|
|
33767
33881
|
}
|
|
33768
33882
|
};
|
|
33769
33883
|
function hashLockfileBytes(contents) {
|
|
33770
|
-
return (0,
|
|
33884
|
+
return (0, import_node_crypto8.createHash)("sha256").update(contents).digest("hex");
|
|
33771
33885
|
}
|
|
33772
33886
|
function resolveWorktreeInstallLockfile(packageDir, fs2 = realWorktreeInstallCacheFs) {
|
|
33773
33887
|
for (const name of LOCKFILE_NAMES) {
|
|
33774
|
-
const path2 = (0,
|
|
33888
|
+
const path2 = (0, import_node_path39.join)(packageDir, name);
|
|
33775
33889
|
if (!fs2.exists(path2)) continue;
|
|
33776
33890
|
try {
|
|
33777
33891
|
const hash = hashLockfileBytes(fs2.readFile(path2));
|
|
@@ -33786,8 +33900,8 @@ function worktreeInstallCacheEntry(primaryRoot, lockfileHash) {
|
|
|
33786
33900
|
const root = repoRuntimeStatePath(primaryRoot, CACHE_DIR, lockfileHash);
|
|
33787
33901
|
return {
|
|
33788
33902
|
root,
|
|
33789
|
-
manifestPath: (0,
|
|
33790
|
-
nodeModulesPath: (0,
|
|
33903
|
+
manifestPath: (0, import_node_path39.join)(root, MANIFEST),
|
|
33904
|
+
nodeModulesPath: (0, import_node_path39.join)(root, NODE_MODULES2)
|
|
33791
33905
|
};
|
|
33792
33906
|
}
|
|
33793
33907
|
function readWorktreeInstallCacheManifest(manifestPath, fs2 = realWorktreeInstallCacheFs) {
|
|
@@ -33827,7 +33941,7 @@ function invalidateWorktreeInstallCacheEntry(entry, fs2 = realWorktreeInstallCac
|
|
|
33827
33941
|
}
|
|
33828
33942
|
}
|
|
33829
33943
|
function removeMaterializedTree(packageDir, fs2) {
|
|
33830
|
-
const dest = (0,
|
|
33944
|
+
const dest = (0, import_node_path39.join)(packageDir, NODE_MODULES2);
|
|
33831
33945
|
if (!fs2.exists(dest)) return;
|
|
33832
33946
|
fs2.rm(dest);
|
|
33833
33947
|
if (fs2.exists(dest)) {
|
|
@@ -33835,7 +33949,7 @@ function removeMaterializedTree(packageDir, fs2) {
|
|
|
33835
33949
|
}
|
|
33836
33950
|
}
|
|
33837
33951
|
function materializeCachedNodeModules(entry, destPackageDir, fs2 = realWorktreeInstallCacheFs) {
|
|
33838
|
-
const dest = (0,
|
|
33952
|
+
const dest = (0, import_node_path39.join)(destPackageDir, NODE_MODULES2);
|
|
33839
33953
|
try {
|
|
33840
33954
|
if (fs2.exists(dest)) fs2.rm(dest);
|
|
33841
33955
|
fs2.mkdirp(destPackageDir);
|
|
@@ -33850,7 +33964,7 @@ function materializeCachedNodeModules(entry, destPackageDir, fs2 = realWorktreeI
|
|
|
33850
33964
|
}
|
|
33851
33965
|
}
|
|
33852
33966
|
async function storeWorktreeInstallCacheEntry(primaryRoot, lockfile3, command, sourcePackageDir, fs2 = realWorktreeInstallCacheFs, now = Date.now()) {
|
|
33853
|
-
const source = (0,
|
|
33967
|
+
const source = (0, import_node_path39.join)(sourcePackageDir, NODE_MODULES2);
|
|
33854
33968
|
if (!isMaterializableNodeModulesDir(source, fs2)) return;
|
|
33855
33969
|
const entry = worktreeInstallCacheEntry(primaryRoot, lockfile3.hash);
|
|
33856
33970
|
const manifest = {
|
|
@@ -34110,7 +34224,7 @@ function classifyStaleLeaks(input) {
|
|
|
34110
34224
|
var defaultOrphanDirScanDeps = {
|
|
34111
34225
|
listDirs: (root) => {
|
|
34112
34226
|
try {
|
|
34113
|
-
return (0,
|
|
34227
|
+
return (0, import_node_fs42.readdirSync)(root, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => (0, import_node_path40.join)(root, e.name));
|
|
34114
34228
|
} catch {
|
|
34115
34229
|
return [];
|
|
34116
34230
|
}
|
|
@@ -34276,13 +34390,13 @@ function registerWorktreeCommands(program3) {
|
|
|
34276
34390
|
const detached = headBorn && !symbolicBranch;
|
|
34277
34391
|
const branch = symbolicBranch || (detached ? "HEAD" : "");
|
|
34278
34392
|
if (!wtPath || !branch) return fail("worktree land: not inside a git worktree");
|
|
34279
|
-
const gitFile = (0,
|
|
34280
|
-
const isLinked = (0,
|
|
34393
|
+
const gitFile = (0, import_node_path40.join)(wtPath, ".git");
|
|
34394
|
+
const isLinked = (0, import_node_fs42.existsSync)(gitFile) && (0, import_node_fs42.statSync)(gitFile).isFile();
|
|
34281
34395
|
if (apply && !isLinked) {
|
|
34282
34396
|
return fail("worktree land: run from inside the linked worktree you want to land (this is the primary checkout)");
|
|
34283
34397
|
}
|
|
34284
34398
|
const commonDir = (await execFileP2("git", ["rev-parse", "--git-common-dir"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim();
|
|
34285
|
-
const primaryCheckout = commonDir ? (0,
|
|
34399
|
+
const primaryCheckout = commonDir ? (0, import_node_path40.dirname)(commonDir) : wtPath;
|
|
34286
34400
|
const localBranchNames = await execFileP2("git", ["-C", primaryCheckout, "for-each-ref", "--format=%(refname:short)", "refs/heads"], { timeout: GIT_TIMEOUT_MS }).then(({ stdout }) => new Set((stdout || "").split("\n").map((l) => l.trim()).filter(Boolean))).catch(() => void 0);
|
|
34287
34401
|
const orphan = classifyOrphanedWorktree({
|
|
34288
34402
|
branch,
|
|
@@ -34320,13 +34434,13 @@ function registerWorktreeCommands(program3) {
|
|
|
34320
34434
|
}
|
|
34321
34435
|
const landStatus = (await execFileP2("git", ["-C", wtPath, "status", "--porcelain"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "unreadable" }))).stdout || "";
|
|
34322
34436
|
const gitInWorktree = async (args) => (await execFileP2("git", ["-C", wtPath, ...args], { timeout: GIT_TIMEOUT_MS })).stdout;
|
|
34323
|
-
const orphanDirt = headBorn ? void 0 : await classifyOrphanWorktreeDirt(landStatus, { git: gitInWorktree, readTextFile: (p) => (0,
|
|
34437
|
+
const orphanDirt = headBorn ? void 0 : await classifyOrphanWorktreeDirt(landStatus, { git: gitInWorktree, readTextFile: (p) => (0, import_promises10.readFile)(p, "utf8") });
|
|
34324
34438
|
const landDirty = headBorn ? landStatus.trim().length > 0 : orphanDirt.dirt !== "clean";
|
|
34325
34439
|
if (landDirty) {
|
|
34326
34440
|
return fail(`worktree land: refusing to land '${branch}' \u2014 uncommitted changes in ${wtPath}; commit, stash, or remove the worktree manually`, { code: ERROR_CODES.ERR_BAD_ENUM });
|
|
34327
34441
|
}
|
|
34328
34442
|
const orphanTip = orphan.orphan ? orphanDirt?.tip ?? await readOrphanWorktreeTip(
|
|
34329
|
-
{ git: gitInWorktree, readTextFile: (p) => (0,
|
|
34443
|
+
{ git: gitInWorktree, readTextFile: (p) => (0, import_promises10.readFile)(p, "utf8") },
|
|
34330
34444
|
orphan.kind
|
|
34331
34445
|
) : void 0;
|
|
34332
34446
|
const lastCommit = orphanTip ? {
|
|
@@ -34556,10 +34670,10 @@ async function gatherWorktreeContext() {
|
|
|
34556
34670
|
if (s) stages.push({ path: wt.path, port: s.port });
|
|
34557
34671
|
}
|
|
34558
34672
|
const worktreeGitRoot = await currentRepoWorktreeGitRoot(repoRoot2);
|
|
34559
|
-
const primaryRepoRoot = worktreeGitRoot ? (0,
|
|
34673
|
+
const primaryRepoRoot = worktreeGitRoot ? (0, import_node_path40.dirname)((0, import_node_path40.dirname)(worktreeGitRoot)) : repoRoot2;
|
|
34560
34674
|
const wtRoot = siblingMmiWorktreesRoot(primaryRepoRoot);
|
|
34561
34675
|
let orphanDirs = [];
|
|
34562
|
-
if ((0,
|
|
34676
|
+
if ((0, import_node_fs42.existsSync)(wtRoot)) {
|
|
34563
34677
|
orphanDirs = scanOrphanDirs(wtRoot, worktreeGitRoot, {
|
|
34564
34678
|
...defaultOrphanDirScanDeps,
|
|
34565
34679
|
listDirs: (root) => worktreeScanDirs(root, primaryRepoRoot, defaultOrphanDirScanDeps.listDirs, isRepoCheckoutDir)
|
|
@@ -34595,8 +34709,8 @@ ${err.stderr ?? ""}`;
|
|
|
34595
34709
|
}
|
|
34596
34710
|
|
|
34597
34711
|
// src/issue-commands.ts
|
|
34598
|
-
var
|
|
34599
|
-
var
|
|
34712
|
+
var import_node_fs43 = require("node:fs");
|
|
34713
|
+
var import_node_crypto9 = require("node:crypto");
|
|
34600
34714
|
var ghRunner = async (args, timeoutMs) => (await execFileP2("gh", args, { timeout: timeoutMs })).stdout;
|
|
34601
34715
|
var ReparentConflictError = class extends Error {
|
|
34602
34716
|
constructor(message, payload) {
|
|
@@ -34613,7 +34727,7 @@ async function editIssue(client, options, deps = {}) {
|
|
|
34613
34727
|
const url = `https://github.com/${repo}/issues/${parsed.number}`;
|
|
34614
34728
|
const patch = {};
|
|
34615
34729
|
let bodyChanged = false;
|
|
34616
|
-
const textDeps = () => deps.textDeps ?? { readFile: (p, e) => Promise.resolve((0,
|
|
34730
|
+
const textDeps = () => deps.textDeps ?? { readFile: (p, e) => Promise.resolve((0, import_node_fs43.readFileSync)(p, e)), readStdin: () => Promise.resolve("") };
|
|
34617
34731
|
if (options.titleFile !== void 0) {
|
|
34618
34732
|
patch.title = await resolveIssueTitle({ title: options.title, titleFile: options.titleFile }, textDeps());
|
|
34619
34733
|
} else if (options.title !== void 0) {
|
|
@@ -34887,7 +35001,7 @@ function rowIdempotencyKey(batchKey, spec) {
|
|
|
34887
35001
|
const identity = `${spec.type}
|
|
34888
35002
|
${spec.title.trim()}
|
|
34889
35003
|
${spec.body ?? ""}`;
|
|
34890
|
-
const hash = (0,
|
|
35004
|
+
const hash = (0, import_node_crypto9.createHash)("sha256").update(identity).digest("hex").slice(0, 16);
|
|
34891
35005
|
return `${batchKey}:${hash}`;
|
|
34892
35006
|
}
|
|
34893
35007
|
var BATCH_SPEC_KEYS = /* @__PURE__ */ new Set(["type", "title", "body", "priority", "labels", "label", "parent", "repo", "surface"]);
|
|
@@ -35218,7 +35332,7 @@ function extendCreateCommand(issue2, batchAttach) {
|
|
|
35218
35332
|
if (opts.batch) {
|
|
35219
35333
|
let specs;
|
|
35220
35334
|
try {
|
|
35221
|
-
const raw = (0,
|
|
35335
|
+
const raw = (0, import_node_fs43.readFileSync)(opts.batch, "utf8");
|
|
35222
35336
|
specs = JSON.parse(raw);
|
|
35223
35337
|
if (!Array.isArray(specs)) throw new Error("batch file must contain a JSON array");
|
|
35224
35338
|
} catch (e) {
|
|
@@ -35293,8 +35407,8 @@ ${lines}`, {
|
|
|
35293
35407
|
}
|
|
35294
35408
|
|
|
35295
35409
|
// src/train-commands.ts
|
|
35296
|
-
var
|
|
35297
|
-
var
|
|
35410
|
+
var import_node_fs44 = require("node:fs");
|
|
35411
|
+
var import_node_path41 = require("node:path");
|
|
35298
35412
|
var RELEASE_BUMP_INTENTS = ["major", "minor", "patch"];
|
|
35299
35413
|
function resolveReleaseBumpIntent(raw) {
|
|
35300
35414
|
const intent = typeof raw === "string" ? raw.trim() : "";
|
|
@@ -35305,7 +35419,7 @@ function resolveReleaseBumpIntent(raw) {
|
|
|
35305
35419
|
}
|
|
35306
35420
|
function readRepoVersion() {
|
|
35307
35421
|
try {
|
|
35308
|
-
return JSON.parse((0,
|
|
35422
|
+
return JSON.parse((0, import_node_fs44.readFileSync)((0, import_node_path41.join)(process.cwd(), ".claude-plugin", "plugin.json"), "utf8")).version || void 0;
|
|
35309
35423
|
} catch {
|
|
35310
35424
|
return void 0;
|
|
35311
35425
|
}
|
|
@@ -35462,9 +35576,9 @@ function registerDeployCommands(program3) {
|
|
|
35462
35576
|
}
|
|
35463
35577
|
|
|
35464
35578
|
// src/discovery-commands.ts
|
|
35465
|
-
var
|
|
35579
|
+
var import_node_fs45 = require("node:fs");
|
|
35466
35580
|
var import_node_os16 = require("node:os");
|
|
35467
|
-
var
|
|
35581
|
+
var import_node_path42 = require("node:path");
|
|
35468
35582
|
var GC_GH_TIMEOUT_MS3 = 2e4;
|
|
35469
35583
|
async function collectStatus() {
|
|
35470
35584
|
const repo = await resolveRepo();
|
|
@@ -35654,8 +35768,8 @@ async function collectOnboardStatus(opts = {}) {
|
|
|
35654
35768
|
}
|
|
35655
35769
|
const home = (0, import_node_os16.homedir)();
|
|
35656
35770
|
const plugin = onboardPluginGate({
|
|
35657
|
-
readKnown: () => readFileSyncSafe((0,
|
|
35658
|
-
readSettings: () => readFileSyncSafe((0,
|
|
35771
|
+
readKnown: () => readFileSyncSafe((0, import_node_path42.join)(home, ...KNOWN_MARKETPLACES_RELATIVE), import_node_fs45.readFileSync),
|
|
35772
|
+
readSettings: () => readFileSyncSafe((0, import_node_path42.join)(home, ".claude", "settings.json"), import_node_fs45.readFileSync)
|
|
35659
35773
|
});
|
|
35660
35774
|
return { track, board, registry: registry2, secrets, plugin, estateCli, doors: opts.doors ?? [], nextCommand };
|
|
35661
35775
|
}
|
|
@@ -35815,7 +35929,7 @@ function formatExplainCommand(cmd, rootName) {
|
|
|
35815
35929
|
return lines.join("\n").trimEnd();
|
|
35816
35930
|
}
|
|
35817
35931
|
function formatExplainGroup(cmd, rootName) {
|
|
35818
|
-
const canonical = (node) =>
|
|
35932
|
+
const canonical = (node) => node.path;
|
|
35819
35933
|
const lines = [
|
|
35820
35934
|
`${rootName} ${canonical(cmd)}${cmd.description ? ` \u2014 ${cmd.description}` : ""}`,
|
|
35821
35935
|
`Category: ${cmd.category} \xB7 Discovery: ${cmd.discovery}`,
|
|
@@ -35841,7 +35955,7 @@ function formatExplainLoop(playbook) {
|
|
|
35841
35955
|
}
|
|
35842
35956
|
function findCommandInManifest(manifest, commandPath3) {
|
|
35843
35957
|
const visit = (command) => {
|
|
35844
|
-
if (command.path === commandPath3 ||
|
|
35958
|
+
if (command.path === commandPath3 || command.flat_path === commandPath3) return command;
|
|
35845
35959
|
for (const child2 of command.subcommands) {
|
|
35846
35960
|
const found = visit(child2);
|
|
35847
35961
|
if (found) return found;
|
|
@@ -35877,7 +35991,7 @@ function registerExplainCommand(program3) {
|
|
|
35877
35991
|
}
|
|
35878
35992
|
|
|
35879
35993
|
// src/pr-commands.ts
|
|
35880
|
-
var
|
|
35994
|
+
var import_promises11 = require("node:fs/promises");
|
|
35881
35995
|
var GC_GH_TIMEOUT_MS4 = 2e4;
|
|
35882
35996
|
var CHECKS_WATCH_POLL_MS = 15e3;
|
|
35883
35997
|
var CHECKS_WATCH_TIMEOUT_MS = 10 * 6e4;
|
|
@@ -36046,10 +36160,10 @@ function registerPrLifecycleCommands(program3) {
|
|
|
36046
36160
|
let body;
|
|
36047
36161
|
try {
|
|
36048
36162
|
if (o.title || o.titleFile) {
|
|
36049
|
-
title = await resolveIssueTitle({ title: o.title, titleFile: o.titleFile }, { readFile:
|
|
36163
|
+
title = await resolveIssueTitle({ title: o.title, titleFile: o.titleFile }, { readFile: import_promises11.readFile, readStdin });
|
|
36050
36164
|
}
|
|
36051
36165
|
if (o.body || o.bodyFile) {
|
|
36052
|
-
body = await resolveIssueBody({ body: o.body, bodyFile: o.bodyFile }, { readFile:
|
|
36166
|
+
body = await resolveIssueBody({ body: o.body, bodyFile: o.bodyFile }, { readFile: import_promises11.readFile, readStdin });
|
|
36053
36167
|
}
|
|
36054
36168
|
} catch (e) {
|
|
36055
36169
|
return fail(`pr edit: ${e.message}`);
|
|
@@ -36079,7 +36193,7 @@ function registerPrLifecycleCommands(program3) {
|
|
|
36079
36193
|
}
|
|
36080
36194
|
let body;
|
|
36081
36195
|
try {
|
|
36082
|
-
body = await resolveIssueBody({ body: o.body, bodyFile: o.bodyFile }, { readFile:
|
|
36196
|
+
body = await resolveIssueBody({ body: o.body, bodyFile: o.bodyFile }, { readFile: import_promises11.readFile, readStdin });
|
|
36083
36197
|
} catch (e) {
|
|
36084
36198
|
return fail(`pr comment: ${e.message}`);
|
|
36085
36199
|
}
|
|
@@ -36790,19 +36904,19 @@ function registerOrgHealthQuery(program3, deps = defaultOrgHealthQueryDeps()) {
|
|
|
36790
36904
|
}
|
|
36791
36905
|
|
|
36792
36906
|
// src/plugin-release-catchup.ts
|
|
36793
|
-
var
|
|
36794
|
-
var
|
|
36907
|
+
var import_node_fs46 = require("node:fs");
|
|
36908
|
+
var import_node_path43 = require("node:path");
|
|
36795
36909
|
var import_node_os17 = require("node:os");
|
|
36796
36910
|
var RELEASE_CATCHUP_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
36797
36911
|
var RELEASE_CATCHUP_DISABLE_ENV = "MMI_NO_RELEASE_CATCHUP";
|
|
36798
36912
|
function releaseCatchupStatePath(env = process.env) {
|
|
36799
36913
|
if (env.MMI_RELEASE_CATCHUP_STATE) return env.MMI_RELEASE_CATCHUP_STATE;
|
|
36800
36914
|
if (process.platform === "win32") {
|
|
36801
|
-
const base2 = env.LOCALAPPDATA || (0,
|
|
36802
|
-
return (0,
|
|
36915
|
+
const base2 = env.LOCALAPPDATA || (0, import_node_path43.join)((0, import_node_os17.homedir)(), "AppData", "Local");
|
|
36916
|
+
return (0, import_node_path43.join)(base2, "MMI Future", "mmi-cli", "release-catchup.json");
|
|
36803
36917
|
}
|
|
36804
|
-
const base = env.XDG_STATE_HOME || (0,
|
|
36805
|
-
return (0,
|
|
36918
|
+
const base = env.XDG_STATE_HOME || (0, import_node_path43.join)((0, import_node_os17.homedir)(), ".local", "state");
|
|
36919
|
+
return (0, import_node_path43.join)(base, "mmi-cli", "release-catchup.json");
|
|
36806
36920
|
}
|
|
36807
36921
|
function releaseCatchupDue(state, now, force = false) {
|
|
36808
36922
|
if (force) return true;
|
|
@@ -36812,7 +36926,7 @@ function releaseCatchupDue(state, now, force = false) {
|
|
|
36812
36926
|
function newestCachedPluginVersion(home) {
|
|
36813
36927
|
let names;
|
|
36814
36928
|
try {
|
|
36815
|
-
names = (0,
|
|
36929
|
+
names = (0, import_node_fs46.readdirSync)(pluginCacheRoot(home));
|
|
36816
36930
|
} catch {
|
|
36817
36931
|
return void 0;
|
|
36818
36932
|
}
|
|
@@ -36820,15 +36934,15 @@ function newestCachedPluginVersion(home) {
|
|
|
36820
36934
|
}
|
|
36821
36935
|
function marketplaceClonePath(home) {
|
|
36822
36936
|
try {
|
|
36823
|
-
const parsed = JSON.parse((0,
|
|
36937
|
+
const parsed = JSON.parse((0, import_node_fs46.readFileSync)((0, import_node_path43.join)(home, ".claude", "plugins", "known_marketplaces.json"), "utf8"));
|
|
36824
36938
|
if (parsed.mutmutco?.installLocation) return parsed.mutmutco.installLocation;
|
|
36825
36939
|
} catch {
|
|
36826
36940
|
}
|
|
36827
|
-
return (0,
|
|
36941
|
+
return (0, import_node_path43.join)(home, ".claude", "plugins", "marketplaces", "mutmutco");
|
|
36828
36942
|
}
|
|
36829
36943
|
function readCatalogVersion(home) {
|
|
36830
36944
|
try {
|
|
36831
|
-
const parsed = JSON.parse((0,
|
|
36945
|
+
const parsed = JSON.parse((0, import_node_fs46.readFileSync)((0, import_node_path43.join)(marketplaceClonePath(home), ".claude-plugin", "marketplace.json"), "utf8"));
|
|
36832
36946
|
return parsed.plugins?.find((p) => p.name === "mmi")?.version;
|
|
36833
36947
|
} catch {
|
|
36834
36948
|
return void 0;
|
|
@@ -36836,7 +36950,7 @@ function readCatalogVersion(home) {
|
|
|
36836
36950
|
}
|
|
36837
36951
|
function readMmiInstallRecord(home) {
|
|
36838
36952
|
try {
|
|
36839
|
-
const parsed = JSON.parse((0,
|
|
36953
|
+
const parsed = JSON.parse((0, import_node_fs46.readFileSync)((0, import_node_path43.join)(home, ".claude", "plugins", "installed_plugins.json"), "utf8"));
|
|
36840
36954
|
const record = parsed.plugins?.["mmi@mutmutco"]?.[0];
|
|
36841
36955
|
return record?.version ? { version: record.version, gitCommitSha: record.gitCommitSha } : void 0;
|
|
36842
36956
|
} catch {
|
|
@@ -36865,7 +36979,7 @@ async function runReleaseCatchup(home, env, deps, opts = {}) {
|
|
|
36865
36979
|
cliUpdated = true;
|
|
36866
36980
|
}
|
|
36867
36981
|
const cliUpdateDetail = cliUpdated ? `CLI ${runningCli} \u2192 ${latest}; the next mmi-cli invocation runs ${latest}` : `CLI ${runningCli} is current against released ${latest}`;
|
|
36868
|
-
if (!(0,
|
|
36982
|
+
if (!(0, import_node_fs46.existsSync)(pluginCacheRoot(home))) {
|
|
36869
36983
|
deps.writeState(statePath, { checkedAt: deps.now(), latest });
|
|
36870
36984
|
return {
|
|
36871
36985
|
ok: true,
|
|
@@ -36898,8 +37012,8 @@ async function runReleaseCatchup(home, env, deps, opts = {}) {
|
|
|
36898
37012
|
return { ok: false, detail: `${cliUpdateDetail}; plugin install record could not be cleared (still ${prior.version})` };
|
|
36899
37013
|
}
|
|
36900
37014
|
const installed = await deps.runClaude(["plugin", "install", "mmi@mutmutco"], "claude plugin install mmi@mutmutco");
|
|
36901
|
-
const payload = (0,
|
|
36902
|
-
if (!installed || !(0,
|
|
37015
|
+
const payload = (0, import_node_path43.join)(pluginCacheRoot(home), latest, ".pi-plugin");
|
|
37016
|
+
if (!installed || !(0, import_node_fs46.existsSync)(payload)) {
|
|
36903
37017
|
const why = installed ? `install of ${latest} did not produce a verifiable .pi-plugin payload` : `install of ${latest} failed`;
|
|
36904
37018
|
if (!prior) return { ok: false, detail: `${cliUpdateDetail}; ${why}; no prior record to restore` };
|
|
36905
37019
|
const rollback = await restorePriorRecord(home, prior, deps);
|
|
@@ -39184,9 +39298,9 @@ function ghAccountCaveat(announcedLogin, accounts) {
|
|
|
39184
39298
|
}
|
|
39185
39299
|
|
|
39186
39300
|
// src/doctor-io.ts
|
|
39187
|
-
var
|
|
39301
|
+
var import_node_fs47 = require("node:fs");
|
|
39188
39302
|
var import_node_os18 = require("node:os");
|
|
39189
|
-
var
|
|
39303
|
+
var import_node_path44 = require("node:path");
|
|
39190
39304
|
var import_node_child_process19 = require("node:child_process");
|
|
39191
39305
|
var import_node_util8 = require("node:util");
|
|
39192
39306
|
var execFileP6 = (0, import_node_util8.promisify)(import_node_child_process19.execFile);
|
|
@@ -39194,7 +39308,7 @@ var MMI_PLUGIN_ID2 = "mmi@mutmutco";
|
|
|
39194
39308
|
function installedClaudePluginVersion() {
|
|
39195
39309
|
try {
|
|
39196
39310
|
const file = JSON.parse(
|
|
39197
|
-
(0,
|
|
39311
|
+
(0, import_node_fs47.readFileSync)((0, import_node_path44.join)((0, import_node_os18.homedir)(), ".claude", "plugins", "installed_plugins.json"), "utf8")
|
|
39198
39312
|
);
|
|
39199
39313
|
const versions = (file.plugins?.[MMI_PLUGIN_ID2] ?? []).map((r) => r.version).filter((v) => Boolean(v));
|
|
39200
39314
|
if (versions.length === 0) return void 0;
|
|
@@ -39205,7 +39319,7 @@ function installedClaudePluginVersion() {
|
|
|
39205
39319
|
}
|
|
39206
39320
|
function manifestVersion(path2) {
|
|
39207
39321
|
try {
|
|
39208
|
-
const manifest = JSON.parse((0,
|
|
39322
|
+
const manifest = JSON.parse((0, import_node_fs47.readFileSync)(path2, "utf8"));
|
|
39209
39323
|
return typeof manifest.version === "string" && manifest.version.trim() ? manifest.version.trim() : void 0;
|
|
39210
39324
|
} catch {
|
|
39211
39325
|
return void 0;
|
|
@@ -39215,22 +39329,22 @@ function installedSurfacePluginVersion(surface) {
|
|
|
39215
39329
|
const token = surfaceToken(surface);
|
|
39216
39330
|
if (token === "kilo") {
|
|
39217
39331
|
try {
|
|
39218
|
-
const stamp = (0,
|
|
39332
|
+
const stamp = (0, import_node_fs47.readFileSync)((0, import_node_path44.join)((0, import_node_os18.homedir)(), ".kilo", ".mmi-kilo-version"), "utf8").trim();
|
|
39219
39333
|
return stamp || void 0;
|
|
39220
39334
|
} catch {
|
|
39221
39335
|
return void 0;
|
|
39222
39336
|
}
|
|
39223
39337
|
}
|
|
39224
39338
|
if (token === "cursor") {
|
|
39225
|
-
return manifestVersion((0,
|
|
39339
|
+
return manifestVersion((0, import_node_path44.join)(cursorLocalPluginRoot(), ".cursor-plugin", "plugin.json"));
|
|
39226
39340
|
}
|
|
39227
39341
|
if (token === "jervcode") {
|
|
39228
39342
|
const entry = mmiPiWrapperEntry();
|
|
39229
39343
|
if (!entry) return void 0;
|
|
39230
|
-
return manifestVersion((0,
|
|
39344
|
+
return manifestVersion((0, import_node_path44.join)(decodeURIComponent(entry.replace(/^file:\/\/\/?/, "")), "package.json"));
|
|
39231
39345
|
}
|
|
39232
39346
|
if (token === "kimi") {
|
|
39233
|
-
return manifestVersion((0,
|
|
39347
|
+
return manifestVersion((0, import_node_path44.join)(surfaceConfigRoot(surface), "plugins", "managed", "mmi", ".kimi-plugin", "plugin.json"));
|
|
39234
39348
|
}
|
|
39235
39349
|
if (token === "claude") return installedClaudePluginVersion();
|
|
39236
39350
|
if (token !== "codex") return void 0;
|
|
@@ -39268,13 +39382,13 @@ function worktreeRootSync() {
|
|
|
39268
39382
|
}
|
|
39269
39383
|
var gitignorePath = () => {
|
|
39270
39384
|
const root = worktreeRootSync();
|
|
39271
|
-
return root === null ? null : (0,
|
|
39385
|
+
return root === null ? null : (0, import_node_path44.join)(root, ".gitignore");
|
|
39272
39386
|
};
|
|
39273
39387
|
function readGitignore() {
|
|
39274
39388
|
const path2 = gitignorePath();
|
|
39275
39389
|
if (path2 === null) return null;
|
|
39276
39390
|
try {
|
|
39277
|
-
return (0,
|
|
39391
|
+
return (0, import_node_fs47.readFileSync)(path2, "utf8");
|
|
39278
39392
|
} catch {
|
|
39279
39393
|
return null;
|
|
39280
39394
|
}
|
|
@@ -39283,7 +39397,7 @@ function writeGitignore(content) {
|
|
|
39283
39397
|
const path2 = gitignorePath();
|
|
39284
39398
|
if (path2 === null) return false;
|
|
39285
39399
|
try {
|
|
39286
|
-
(0,
|
|
39400
|
+
(0, import_node_fs47.writeFileSync)(path2, content, "utf8");
|
|
39287
39401
|
return true;
|
|
39288
39402
|
} catch {
|
|
39289
39403
|
return false;
|
|
@@ -39302,7 +39416,7 @@ async function repoRoot() {
|
|
|
39302
39416
|
}
|
|
39303
39417
|
function hasRepoLocalWorktrees() {
|
|
39304
39418
|
const root = worktreeRootSync();
|
|
39305
|
-
return root !== null && (0,
|
|
39419
|
+
return root !== null && (0, import_node_fs47.existsSync)((0, import_node_path44.join)(root, ".worktrees"));
|
|
39306
39420
|
}
|
|
39307
39421
|
|
|
39308
39422
|
// src/cross-repo-filing-issue.ts
|
|
@@ -39398,7 +39512,7 @@ function binaryOnPath(bin) {
|
|
|
39398
39512
|
for (const dir of pathEnvEntries(process.env.PATH ?? "")) {
|
|
39399
39513
|
for (const ext of exts) {
|
|
39400
39514
|
try {
|
|
39401
|
-
if ((0,
|
|
39515
|
+
if ((0, import_node_fs48.existsSync)((0, import_node_path45.join)(dir, `${bin}${ext}`))) return true;
|
|
39402
39516
|
} catch {
|
|
39403
39517
|
}
|
|
39404
39518
|
}
|
|
@@ -39420,8 +39534,8 @@ ${r.stderr ?? ""}`).catch(() => "");
|
|
|
39420
39534
|
function ghMultiAccountCaveat(announcedLogin) {
|
|
39421
39535
|
try {
|
|
39422
39536
|
const hostsPath = ghHostsConfigPath(process.env, process.platform);
|
|
39423
|
-
if (!hostsPath || !(0,
|
|
39424
|
-
return ghAccountCaveat(announcedLogin, parseGhHostsAccounts((0,
|
|
39537
|
+
if (!hostsPath || !(0, import_node_fs48.existsSync)(hostsPath)) return void 0;
|
|
39538
|
+
return ghAccountCaveat(announcedLogin, parseGhHostsAccounts((0, import_node_fs48.readFileSync)(hostsPath, "utf8")));
|
|
39425
39539
|
} catch {
|
|
39426
39540
|
return void 0;
|
|
39427
39541
|
}
|
|
@@ -39429,7 +39543,7 @@ function ghMultiAccountCaveat(announcedLogin) {
|
|
|
39429
39543
|
var ENV_HEAL_LOCK_STALE_MS = 10 * 6e4;
|
|
39430
39544
|
var ENV_HEAL_LOCK_MAX_WAIT_MS = 2 * 6e4;
|
|
39431
39545
|
function envHealLockPath(home) {
|
|
39432
|
-
return (0,
|
|
39546
|
+
return (0, import_node_path45.join)(home, ".claude", "plugins", ".mmi-env-heal.lock");
|
|
39433
39547
|
}
|
|
39434
39548
|
async function withEnvHealLock(what, run) {
|
|
39435
39549
|
try {
|
|
@@ -39562,7 +39676,7 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
39562
39676
|
);
|
|
39563
39677
|
const result = applyPluginCachePlan(
|
|
39564
39678
|
plan,
|
|
39565
|
-
(p) => (0,
|
|
39679
|
+
(p) => (0, import_node_fs48.rmSync)(p, { recursive: true }),
|
|
39566
39680
|
stagingApplyFsGuard(configRoot)
|
|
39567
39681
|
);
|
|
39568
39682
|
return {
|
|
@@ -39634,7 +39748,7 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
39634
39748
|
disableAutoUpdate: () => {
|
|
39635
39749
|
if (detectSurface(process.env) === "codex") return void 0;
|
|
39636
39750
|
return disableOrgMarketplaceBackgroundUpdates(
|
|
39637
|
-
(0,
|
|
39751
|
+
(0, import_node_path45.join)((0, import_node_os19.homedir)(), ...KNOWN_MARKETPLACES_RELATIVE),
|
|
39638
39752
|
[MMI_MARKETPLACE_NAME]
|
|
39639
39753
|
);
|
|
39640
39754
|
}
|
|
@@ -39648,7 +39762,7 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
39648
39762
|
// adopted the generated routing index (MMG-Unlive: `docs/Archive/**` only, no index, no gate.yml) would
|
|
39649
39763
|
// get a permanent — demanding an artifact it never asked for.
|
|
39650
39764
|
docsIndexState: (root) => {
|
|
39651
|
-
if (!(0,
|
|
39765
|
+
if (!(0, import_node_fs48.existsSync)((0, import_node_path45.join)(root, DOCS_INDEX_PATH))) return void 0;
|
|
39652
39766
|
const real = createDocsIndexDeps(root);
|
|
39653
39767
|
let docs2;
|
|
39654
39768
|
const listDocs = () => docs2 ??= real.listDocs();
|
|
@@ -39657,7 +39771,7 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
39657
39771
|
},
|
|
39658
39772
|
// #4168: working-tree heal — write if drifted, then re-check. Commit remains the operator's step.
|
|
39659
39773
|
healDocsIndex: (root) => {
|
|
39660
|
-
if (!(0,
|
|
39774
|
+
if (!(0, import_node_fs48.existsSync)((0, import_node_path45.join)(root, DOCS_INDEX_PATH))) return { drift: false, docCount: 0 };
|
|
39661
39775
|
const real = createDocsIndexDeps(root);
|
|
39662
39776
|
let docs2;
|
|
39663
39777
|
const listDocs = () => docs2 ??= real.listDocs();
|
|
@@ -39695,8 +39809,8 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
39695
39809
|
});
|
|
39696
39810
|
const raced = await Promise.race([
|
|
39697
39811
|
work.then((r) => ({ ...r, timedOut: false })),
|
|
39698
|
-
new Promise((
|
|
39699
|
-
ceiling = setTimeout(() =>
|
|
39812
|
+
new Promise((resolve6) => {
|
|
39813
|
+
ceiling = setTimeout(() => resolve6({ timedOut: true, scanned: 0, findings: 0, fixed: 0, failed: 0 }), BOARD_DOCTOR_TIMEOUT_MS);
|
|
39700
39814
|
})
|
|
39701
39815
|
]);
|
|
39702
39816
|
if (raced.timedOut) return { scanned: 0, findings: 0, fixed: 0, failed: 0, timedOut: true };
|
|
@@ -39729,8 +39843,8 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
39729
39843
|
incomplete: nb.incomplete,
|
|
39730
39844
|
timedOut: false
|
|
39731
39845
|
})),
|
|
39732
|
-
new Promise((
|
|
39733
|
-
ceiling = setTimeout(() =>
|
|
39846
|
+
new Promise((resolve6) => {
|
|
39847
|
+
ceiling = setTimeout(() => resolve6({ driftLines: [], incomplete: [], timedOut: true }), SCHEDULES_DRIFT_TIMEOUT_MS);
|
|
39734
39848
|
})
|
|
39735
39849
|
]);
|
|
39736
39850
|
if (!raced.timedOut && raced.incomplete.length === 0) writeSchedulesDriftCache(cachePath, raced.driftLines);
|
|
@@ -40023,19 +40137,19 @@ program2.hook("preAction", async (_thisCommand, actionCommand) => {
|
|
|
40023
40137
|
});
|
|
40024
40138
|
var rules = program2.command("rules").description("org-managed .gitignore delivery");
|
|
40025
40139
|
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) => {
|
|
40026
|
-
const path2 = (0,
|
|
40027
|
-
const current = (0,
|
|
40140
|
+
const path2 = (0, import_node_path45.join)(process.cwd(), ".gitignore");
|
|
40141
|
+
const current = (0, import_node_fs48.existsSync)(path2) ? (0, import_node_fs48.readFileSync)(path2, "utf8") : null;
|
|
40028
40142
|
const plan = planManagedGitignore(current);
|
|
40029
40143
|
const drift = [...plan.added.map((l) => `+${l}`), ...plan.removed.map((l) => `-${l}`)].join(", ") || "block normalize";
|
|
40030
40144
|
if (opts.json) {
|
|
40031
|
-
if (opts.write && plan.changed) (0,
|
|
40145
|
+
if (opts.write && plan.changed) (0, import_node_fs48.writeFileSync)(path2, plan.content, "utf8");
|
|
40032
40146
|
console.log(JSON.stringify(plan, null, 2));
|
|
40033
40147
|
if (!opts.write && plan.changed) process.exitCode = 1;
|
|
40034
40148
|
return;
|
|
40035
40149
|
}
|
|
40036
40150
|
if (opts.write) {
|
|
40037
40151
|
if (plan.changed) {
|
|
40038
|
-
(0,
|
|
40152
|
+
(0, import_node_fs48.writeFileSync)(path2, plan.content, "utf8");
|
|
40039
40153
|
console.log(`mmi-cli devops org rules gitignore: updated .gitignore (${drift})`);
|
|
40040
40154
|
} else {
|
|
40041
40155
|
console.log("mmi-cli devops org rules gitignore: up to date");
|
|
@@ -40194,8 +40308,8 @@ gcCmd.option("--dry-run", "show what would be deleted (default)").option("--appl
|
|
|
40194
40308
|
if (!Number.isFinite(limit) || limit < 1) return fail("worktree gc: --limit must be a positive integer");
|
|
40195
40309
|
let root;
|
|
40196
40310
|
if (o.root !== void 0) {
|
|
40197
|
-
root = (0,
|
|
40198
|
-
if (!(0,
|
|
40311
|
+
root = (0, import_node_path45.resolve)(o.root);
|
|
40312
|
+
if (!(0, import_node_fs48.existsSync)(root) || !(0, import_node_fs48.statSync)(root).isDirectory()) return fail(`worktree gc: --root ${o.root} is not a directory`);
|
|
40199
40313
|
const gcRepoRoot = (await execFileP2("git", ["rev-parse", "--show-toplevel"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim() || process.cwd();
|
|
40200
40314
|
if (isPathUnderDirectory2(gcRepoRoot, root)) {
|
|
40201
40315
|
return fail(`worktree gc: --root ${root} contains this checkout \u2014 name a worktrees root, not the repo or an ancestor of it`);
|
|
@@ -40243,7 +40357,7 @@ function runWorktreeInstall(command, cwd, quiet, opts) {
|
|
|
40243
40357
|
quiet ? "ignore" : "inherit",
|
|
40244
40358
|
"pipe"
|
|
40245
40359
|
];
|
|
40246
|
-
return new Promise((
|
|
40360
|
+
return new Promise((resolve6, reject) => {
|
|
40247
40361
|
const child2 = opts?.shell ? (0, import_node_child_process20.spawn)(command, { cwd, stdio, windowsHide: true, shell: true }) : (() => {
|
|
40248
40362
|
const [bin, ...args] = command.split(" ");
|
|
40249
40363
|
const file = isWin2 ? "cmd.exe" : bin;
|
|
@@ -40270,7 +40384,7 @@ function runWorktreeInstall(command, cwd, quiet, opts) {
|
|
|
40270
40384
|
});
|
|
40271
40385
|
child2.on("exit", (code) => {
|
|
40272
40386
|
clearTimeout(timer);
|
|
40273
|
-
if (code === 0) return
|
|
40387
|
+
if (code === 0) return resolve6();
|
|
40274
40388
|
const tail = stderrTail.trim();
|
|
40275
40389
|
reject(new Error(`${command} exited ${code} in ${cwd}${tail ? `
|
|
40276
40390
|
${tail}` : ""}`));
|
|
@@ -40292,7 +40406,7 @@ async function currentWorktreeRemovalContext(command, force) {
|
|
|
40292
40406
|
};
|
|
40293
40407
|
}
|
|
40294
40408
|
async function unprovenWorktreeReason(wtPath, repoRoot2) {
|
|
40295
|
-
if (!(0,
|
|
40409
|
+
if (!(0, import_node_fs48.existsSync)(wtPath)) return `${wtPath} does not exist on disk`;
|
|
40296
40410
|
const porcelain = (await execFileP2("git", ["-C", repoRoot2, "worktree", "list", "--porcelain"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout;
|
|
40297
40411
|
const registered = parseWorktreePorcelainEntries(porcelain);
|
|
40298
40412
|
if (!registered.length) {
|
|
@@ -40322,26 +40436,26 @@ function makeProvisionDeps(worktreeRoot, quiet, log) {
|
|
|
40322
40436
|
function acquireWorktreeSetupLock(worktreeRoot) {
|
|
40323
40437
|
const lockPath = repoRuntimeStatePath(worktreeRoot, "worktree-setup.lock");
|
|
40324
40438
|
const take = () => {
|
|
40325
|
-
const fd = (0,
|
|
40439
|
+
const fd = (0, import_node_fs48.openSync)(lockPath, "wx");
|
|
40326
40440
|
try {
|
|
40327
|
-
(0,
|
|
40441
|
+
(0, import_node_fs48.writeSync)(fd, String(Date.now()));
|
|
40328
40442
|
} finally {
|
|
40329
|
-
(0,
|
|
40443
|
+
(0, import_node_fs48.closeSync)(fd);
|
|
40330
40444
|
}
|
|
40331
40445
|
return () => {
|
|
40332
40446
|
try {
|
|
40333
|
-
(0,
|
|
40447
|
+
(0, import_node_fs48.rmSync)(lockPath, { force: true });
|
|
40334
40448
|
} catch {
|
|
40335
40449
|
}
|
|
40336
40450
|
};
|
|
40337
40451
|
};
|
|
40338
40452
|
try {
|
|
40339
|
-
(0,
|
|
40453
|
+
(0, import_node_fs48.mkdirSync)((0, import_node_path45.dirname)(lockPath), { recursive: true });
|
|
40340
40454
|
return take();
|
|
40341
40455
|
} catch {
|
|
40342
40456
|
try {
|
|
40343
|
-
if (Date.now() - (0,
|
|
40344
|
-
(0,
|
|
40457
|
+
if (Date.now() - (0, import_node_fs48.statSync)(lockPath).mtimeMs > WORKTREE_SETUP_LOCK_TTL_MS) {
|
|
40458
|
+
(0, import_node_fs48.rmSync)(lockPath, { force: true });
|
|
40345
40459
|
return take();
|
|
40346
40460
|
}
|
|
40347
40461
|
} catch {
|
|
@@ -40457,7 +40571,7 @@ withExamples(mutating(
|
|
|
40457
40571
|
}
|
|
40458
40572
|
if (!resumed) {
|
|
40459
40573
|
step = `git worktree add ${wtPath}`;
|
|
40460
|
-
const wtPathPreExisted = (0,
|
|
40574
|
+
const wtPathPreExisted = (0, import_node_fs48.existsSync)(wtPath);
|
|
40461
40575
|
const partialRemove = worktreeRemoveDeps(async (args) => (await execFileP2("git", args, { timeout: GIT_TIMEOUT_MS })).stdout);
|
|
40462
40576
|
await withWorktreeAddLock(repoRoot2, () => addWorktreeRobust(wtPath, branch, base, {
|
|
40463
40577
|
// #4834: `-c core.longpaths=true` rides the add command itself — a Windows worktree path
|
|
@@ -40473,13 +40587,13 @@ withExamples(mutating(
|
|
|
40473
40587
|
},
|
|
40474
40588
|
deleteBranch: (b) => execFileP2("git", ["branch", "-D", b], { timeout: GIT_TIMEOUT_MS }).then(() => void 0),
|
|
40475
40589
|
cleanupPartial: async () => {
|
|
40476
|
-
if (wtPathPreExisted || !(0,
|
|
40590
|
+
if (wtPathPreExisted || !(0, import_node_fs48.existsSync)(wtPath)) return;
|
|
40477
40591
|
partialRemove.detachReparsePoints(wtPath);
|
|
40478
40592
|
await execFileP2("git", ["worktree", "remove", "--force", wtPath], { timeout: GIT_TIMEOUT_MS }).catch(() => partialRemove.removeWorktreeDir(wtPath).then(() => void 0));
|
|
40479
40593
|
await execFileP2("git", ["worktree", "prune"], { timeout: GIT_TIMEOUT_MS }).catch(() => {
|
|
40480
40594
|
});
|
|
40481
40595
|
},
|
|
40482
|
-
sleep: (ms) => new Promise((
|
|
40596
|
+
sleep: (ms) => new Promise((resolve6) => setTimeout(resolve6, ms)),
|
|
40483
40597
|
log: (m) => {
|
|
40484
40598
|
if (!o.json) console.error(` ${m}`);
|
|
40485
40599
|
}
|
|
@@ -40931,9 +41045,7 @@ docs.command("refs").description("deterministic doc reference gate: every backti
|
|
|
40931
41045
|
try {
|
|
40932
41046
|
const root = await repoRoot();
|
|
40933
41047
|
const commandPaths = new Set(
|
|
40934
|
-
buildCommandManifest(program2).index.map(
|
|
40935
|
-
(entry) => entry.house && entry.house !== "core" ? `${entry.house} ${entry.path}` : entry.path
|
|
40936
|
-
)
|
|
41048
|
+
buildCommandManifest(program2).index.map((entry) => entry.path)
|
|
40937
41049
|
);
|
|
40938
41050
|
const result = runDocRefs(root, { commandPaths });
|
|
40939
41051
|
if (o.json) {
|
|
@@ -41016,7 +41128,7 @@ async function reportWrite(label, res) {
|
|
|
41016
41128
|
return failGraceful(`${label}: HTTP ${res.status}${detail ? ` \u2014 ${detail}` : ""}`);
|
|
41017
41129
|
}
|
|
41018
41130
|
var tenant = program2.command("tenant").description("tenant runtime control through Hub authority");
|
|
41019
|
-
tenant.command("control <owner/repo> <stage> <action>").description("bounded tenant control plus value-free vault/broker verification; project-admin own dev/rc, master main").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("--json", "machine-readable output").action(async (repo, stage, action, o) => {
|
|
41131
|
+
tenant.command("control <owner/repo> <stage> <action>").description("bounded tenant control plus value-free vault/broker verification; project-admin own dev/rc, master main").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("--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("--json", "machine-readable output").action(async (repo, stage, action, o) => {
|
|
41020
41132
|
try {
|
|
41021
41133
|
let lines;
|
|
41022
41134
|
if (o.lines !== void 0) {
|
|
@@ -41024,7 +41136,12 @@ tenant.command("control <owner/repo> <stage> <action>").description("bounded ten
|
|
|
41024
41136
|
lines = Number(o.lines);
|
|
41025
41137
|
if (!Number.isInteger(lines) || lines < 1 || lines > 2e3) return fail("runtime tenant control: --lines must be an integer between 1 and 2000");
|
|
41026
41138
|
}
|
|
41027
|
-
|
|
41139
|
+
if (action === "run-task") {
|
|
41140
|
+
if (!o.task) return fail("runtime tenant control: run-task requires --task <declared-name>");
|
|
41141
|
+
} else if (o.task || o.artifact) {
|
|
41142
|
+
return fail("runtime tenant control: --task/--artifact are valid only for run-task");
|
|
41143
|
+
}
|
|
41144
|
+
const result = await runTenantControl(trainApplyDeps(), { repo, stage, action, watch: o.watch, lines, task: o.task, artifact: o.artifact });
|
|
41028
41145
|
if (!o.json && action === "verify-secrets" && result.secrets) {
|
|
41029
41146
|
const body = { ok: result.conclusion === "success", secrets: result.secrets, ssmStatus: result.conclusion === "success" ? "Success" : "Failed", raw: result.secretsRaw };
|
|
41030
41147
|
const { lines: lines2, failure } = renderVerifySecrets(body);
|
|
@@ -41046,6 +41163,15 @@ tenant.command("control <owner/repo> <stage> <action>").description("bounded ten
|
|
|
41046
41163
|
return failGraceful(`runtime tenant control: ${e.message}`);
|
|
41047
41164
|
}
|
|
41048
41165
|
});
|
|
41166
|
+
var tenantArtifact = tenant.command("artifact").description("private stage-bound inputs for declared tenant tasks");
|
|
41167
|
+
tenantArtifact.command("put <owner/repo> <stage> <path>").description("upload a private file through a short-lived Hub grant; prints only an opaque artifact id").option("--json", "machine-readable output").action(async (repo, stage, path2, o) => {
|
|
41168
|
+
try {
|
|
41169
|
+
const receipt = await putTenantArtifact(repo, stage, path2, registryClientDeps(await loadConfig()));
|
|
41170
|
+
printLine(o.json ? JSON.stringify(receipt, null, 2) : `tenant artifact ${receipt.artifactId} ready for ${repo} ${stage} until ${receipt.expiresAt}`);
|
|
41171
|
+
} catch (e) {
|
|
41172
|
+
return failGraceful(e.message);
|
|
41173
|
+
}
|
|
41174
|
+
});
|
|
41049
41175
|
tenant.command("reconcile <owner/repo> <stage>").description("re-render this tenant stage's generated box assets from registry truth; project-admin own dev/rc, master main; watches by default").option("--watch", "wait for the tenant-reconcile.yml run (default)").option("--no-watch", "return after dispatch; do not redeploy until the reconcile run succeeds").option("--json", "machine-readable output").action(async (repo, stage, o) => {
|
|
41050
41176
|
try {
|
|
41051
41177
|
const result = await runTenantReconcile(trainApplyDeps(), { repo, stage, watch: o.watch });
|
|
@@ -41242,7 +41368,7 @@ project.command("set [owner/repo]").description("upsert project META (idempotent
|
|
|
41242
41368
|
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`);
|
|
41243
41369
|
if (o.secretsFile) {
|
|
41244
41370
|
try {
|
|
41245
|
-
vars.push(`secrets=${(0,
|
|
41371
|
+
vars.push(`secrets=${(0, import_node_fs48.readFileSync)(o.secretsFile, "utf8")}`);
|
|
41246
41372
|
} catch (e) {
|
|
41247
41373
|
return fail(`org project set: cannot read --secrets-file ${o.secretsFile}: ${e.message}`);
|
|
41248
41374
|
}
|
|
@@ -41568,7 +41694,7 @@ withExamples(mutating(
|
|
|
41568
41694
|
try {
|
|
41569
41695
|
title = await resolveIssueTitle(
|
|
41570
41696
|
{ title: opts.title, titleFile: opts.titleFile },
|
|
41571
|
-
{ readFile:
|
|
41697
|
+
{ readFile: import_promises12.readFile, readStdin }
|
|
41572
41698
|
);
|
|
41573
41699
|
} catch (e) {
|
|
41574
41700
|
return fail(
|
|
@@ -41610,8 +41736,8 @@ withExamples(mutating(
|
|
|
41610
41736
|
let surfaceFlagLabel;
|
|
41611
41737
|
try {
|
|
41612
41738
|
issueType = resolveCreateType(o.type, "issue create", o.label);
|
|
41613
|
-
title = await resolveIssueTitle({ title: o.title, titleFile: o.titleFile }, { readFile:
|
|
41614
|
-
body = await resolveIssueBody({ body: o.body, bodyFile: o.bodyFile }, { readFile:
|
|
41739
|
+
title = await resolveIssueTitle({ title: o.title, titleFile: o.titleFile }, { readFile: import_promises12.readFile, readStdin });
|
|
41740
|
+
body = await resolveIssueBody({ body: o.body, bodyFile: o.bodyFile }, { readFile: import_promises12.readFile, readStdin });
|
|
41615
41741
|
if (o.idempotencyKey) body = appendIdempotencyMarker(body, o.idempotencyKey);
|
|
41616
41742
|
priority = resolveCreatePriority(o.priority, "issue create");
|
|
41617
41743
|
extraLabels = [...o.label ?? []];
|
|
@@ -41792,7 +41918,7 @@ jsonParity(issue.command("comment <ref>").description("post a Markdown comment t
|
|
|
41792
41918
|
}
|
|
41793
41919
|
let body;
|
|
41794
41920
|
try {
|
|
41795
|
-
body = await resolveIssueBody({ body: o.body, bodyFile: o.bodyFile }, { readFile:
|
|
41921
|
+
body = await resolveIssueBody({ body: o.body, bodyFile: o.bodyFile }, { readFile: import_promises12.readFile, readStdin });
|
|
41796
41922
|
} catch (e) {
|
|
41797
41923
|
return fail(`issue comment: ${e.message}`);
|
|
41798
41924
|
}
|
|
@@ -41852,8 +41978,8 @@ program2.command("report").description("file a friction report on the Hub board
|
|
|
41852
41978
|
let title;
|
|
41853
41979
|
const sourceRepo = o.repo ?? await resolveRepo(void 0);
|
|
41854
41980
|
try {
|
|
41855
|
-
title = await resolveIssueTitle({ title: o.title, titleFile: o.titleFile }, { readFile:
|
|
41856
|
-
body = await resolveIssueBody({ body: o.body, bodyFile: o.bodyFile }, { readFile:
|
|
41981
|
+
title = await resolveIssueTitle({ title: o.title, titleFile: o.titleFile }, { readFile: import_promises12.readFile, readStdin });
|
|
41982
|
+
body = await resolveIssueBody({ body: o.body, bodyFile: o.bodyFile }, { readFile: import_promises12.readFile, readStdin });
|
|
41857
41983
|
priority = resolveCreatePriority(o.priority, "report");
|
|
41858
41984
|
if (!ISSUE_TYPES.includes(o.type)) {
|
|
41859
41985
|
throw new Error(`unknown issue type "${o.type}" \u2014 expected one of: ${ISSUE_TYPES.join(", ")}`);
|
|
@@ -41907,8 +42033,8 @@ program2.command("skill-lesson").description("file a skill-lesson on the Hub boa
|
|
|
41907
42033
|
let args;
|
|
41908
42034
|
try {
|
|
41909
42035
|
skill = assertSkillName(o.skill);
|
|
41910
|
-
rawBody = await resolveIssueBody({ body: o.body, bodyFile: o.bodyFile }, { readFile:
|
|
41911
|
-
const rawTitle = await resolveIssueTitle({ title: o.title, titleFile: o.titleFile }, { readFile:
|
|
42036
|
+
rawBody = await resolveIssueBody({ body: o.body, bodyFile: o.bodyFile }, { readFile: import_promises12.readFile, readStdin });
|
|
42037
|
+
const rawTitle = await resolveIssueTitle({ title: o.title, titleFile: o.titleFile }, { readFile: import_promises12.readFile, readStdin });
|
|
41912
42038
|
title = buildSkillLessonTitle(skill, rawTitle);
|
|
41913
42039
|
priority = resolveCreatePriority(o.priority, "skill-lesson");
|
|
41914
42040
|
body = buildSkillLessonBody(rawBody, sourceRepo, pluginSha);
|
|
@@ -41967,8 +42093,8 @@ withExamples(pr.command("create").description("create a PR and print {number,url
|
|
|
41967
42093
|
let body;
|
|
41968
42094
|
let title;
|
|
41969
42095
|
try {
|
|
41970
|
-
title = await resolveIssueTitle({ title: o.title, titleFile: o.titleFile }, { readFile:
|
|
41971
|
-
body = await resolveIssueBody({ body: o.body, bodyFile: o.bodyFile }, { readFile:
|
|
42096
|
+
title = await resolveIssueTitle({ title: o.title, titleFile: o.titleFile }, { readFile: import_promises12.readFile, readStdin });
|
|
42097
|
+
body = await resolveIssueBody({ body: o.body, bodyFile: o.bodyFile }, { readFile: import_promises12.readFile, readStdin });
|
|
41972
42098
|
} catch (e) {
|
|
41973
42099
|
return fail(`pr create: ${e.message}`, e instanceof TextArgError ? { code: e.code, offending_flag: e.offendingFlag } : void 0);
|
|
41974
42100
|
}
|
|
@@ -42010,11 +42136,11 @@ pr.command("view <number>").description("read a PR as structured JSON (merged st
|
|
|
42010
42136
|
}
|
|
42011
42137
|
});
|
|
42012
42138
|
async function listCiWorkflowPaths(cwd = process.cwd()) {
|
|
42013
|
-
const wfDir = (0,
|
|
42014
|
-
if (!(0,
|
|
42015
|
-
return (0,
|
|
42139
|
+
const wfDir = (0, import_node_path45.join)(cwd, ".github", "workflows");
|
|
42140
|
+
if (!(0, import_node_fs48.existsSync)(wfDir)) return [];
|
|
42141
|
+
return (0, import_node_fs48.readdirSync)(wfDir).filter((name) => /\.(ya?ml)$/i.test(name)).filter((name) => {
|
|
42016
42142
|
try {
|
|
42017
|
-
return workflowReportsPrChecks((0,
|
|
42143
|
+
return workflowReportsPrChecks((0, import_node_fs48.readFileSync)((0, import_node_path45.join)(wfDir, name), "utf8"));
|
|
42018
42144
|
} catch {
|
|
42019
42145
|
return true;
|
|
42020
42146
|
}
|
|
@@ -42066,16 +42192,16 @@ function ciAuditDeps() {
|
|
|
42066
42192
|
// gate re-seed step is skipped gracefully rather than failing mid-run.
|
|
42067
42193
|
readSeedFile: (path2) => {
|
|
42068
42194
|
if (!root) return null;
|
|
42069
|
-
const fullPath = (0,
|
|
42070
|
-
return (0,
|
|
42195
|
+
const fullPath = (0, import_node_path45.join)(root, path2);
|
|
42196
|
+
return (0, import_node_fs48.existsSync)(fullPath) ? (0, import_node_fs48.readFileSync)(fullPath, "utf8") : null;
|
|
42071
42197
|
}
|
|
42072
42198
|
};
|
|
42073
42199
|
}
|
|
42074
42200
|
function hubRoot() {
|
|
42075
|
-
const fromPkg = (0,
|
|
42201
|
+
const fromPkg = (0, import_node_path45.join)(__dirname, "..", "..");
|
|
42076
42202
|
const marker = "skills/bootstrap/seeds/manifest.json";
|
|
42077
|
-
if ((0,
|
|
42078
|
-
if ((0,
|
|
42203
|
+
if ((0, import_node_fs48.existsSync)((0, import_node_path45.join)(fromPkg, marker))) return fromPkg;
|
|
42204
|
+
if ((0, import_node_fs48.existsSync)((0, import_node_path45.join)(process.cwd(), marker))) return process.cwd();
|
|
42079
42205
|
return null;
|
|
42080
42206
|
}
|
|
42081
42207
|
async function waitLoopCorePool(label) {
|
|
@@ -42124,7 +42250,7 @@ pr.command("checks-wait <number>").description(`bounded wait for PR checks; skip
|
|
|
42124
42250
|
// reading as "your tests failed". One call per failing run, only at the verdict.
|
|
42125
42251
|
diagnoseFailure: () => waitLoopDiagnosis("pr checks-wait", number, repo),
|
|
42126
42252
|
baseBranch,
|
|
42127
|
-
sleep: (ms) => new Promise((
|
|
42253
|
+
sleep: (ms) => new Promise((resolve6) => setTimeout(resolve6, ms)),
|
|
42128
42254
|
log: (message) => console.warn(message),
|
|
42129
42255
|
timeoutMs,
|
|
42130
42256
|
// Liveness on stderr, one line per poll. A silent bounded wait is indistinguishable from a hang, and
|
|
@@ -42204,7 +42330,7 @@ pr.command("land <number>").description("agent merge path (#1440): train probe \
|
|
|
42204
42330
|
// then read its own wall-clock kill as a broken diff.
|
|
42205
42331
|
diagnoseFailure: () => waitLoopDiagnosis("pr land", prNumber, repo),
|
|
42206
42332
|
baseBranch: "development",
|
|
42207
|
-
sleep: (ms) => new Promise((
|
|
42333
|
+
sleep: (ms) => new Promise((resolve6) => setTimeout(resolve6, ms)),
|
|
42208
42334
|
log: (message) => console.warn(message),
|
|
42209
42335
|
// `pr land` inherits the same (raised) checks budget, so it needs the same liveness — otherwise the
|
|
42210
42336
|
// 30m wait is SILENT and reads exactly like the hang #2940 was filed about, only three times longer.
|
|
@@ -42247,7 +42373,7 @@ pr.command("land <number>").description("agent merge path (#1440): train probe \
|
|
|
42247
42373
|
} else {
|
|
42248
42374
|
lastFailure = void 0;
|
|
42249
42375
|
}
|
|
42250
|
-
await new Promise((
|
|
42376
|
+
await new Promise((resolve6) => setTimeout(resolve6, PR_LAND_POLL_MS));
|
|
42251
42377
|
}
|
|
42252
42378
|
if (lastFailure) {
|
|
42253
42379
|
throw new Error(
|
|
@@ -42347,7 +42473,7 @@ jsonParity(pr.command("merge <number>").description("merge a PR (squash by defau
|
|
|
42347
42473
|
pollRateLimit: () => waitLoopCorePool("pr merge --wait"),
|
|
42348
42474
|
diagnoseFailure: () => waitLoopDiagnosis("pr merge --wait", number, repo),
|
|
42349
42475
|
baseBranch,
|
|
42350
|
-
sleep: (ms) => new Promise((
|
|
42476
|
+
sleep: (ms) => new Promise((resolve6) => setTimeout(resolve6, ms)),
|
|
42351
42477
|
log: (message) => console.warn(message),
|
|
42352
42478
|
progress: ({ state, elapsedMs, remainingMs }) => console.warn(`pr merge: --wait checks \u2014 ${state}, ${Math.round(elapsedMs / 1e3)}s elapsed, ${Math.round(remainingMs / 6e4)}m left`)
|
|
42353
42479
|
});
|
|
@@ -42383,7 +42509,7 @@ jsonParity(pr.command("merge <number>").description("merge a PR (squash by defau
|
|
|
42383
42509
|
}
|
|
42384
42510
|
if (!repoForPostCleanup) throw e;
|
|
42385
42511
|
console.warn(`pr merge: gh GraphQL rate-limited \u2014 merging PR #${number} via REST PUT instead (#4588).`);
|
|
42386
|
-
const commitMessage = bodyFile ? (0,
|
|
42512
|
+
const commitMessage = bodyFile ? (0, import_node_fs48.readFileSync)(bodyFile, "utf8") : void 0;
|
|
42387
42513
|
await defaultGitHubClient().rest("PUT", `repos/${repoForPostCleanup}/pulls/${number}/merge`, {
|
|
42388
42514
|
body: { merge_method: method.slice(2), ...commitMessage ? { commit_message: commitMessage } : {} },
|
|
42389
42515
|
timeoutMs: GH_MUTATION_TIMEOUT_MS
|
|
@@ -42479,7 +42605,7 @@ jsonParity(pr.command("merge <number>").description("merge a PR (squash by defau
|
|
|
42479
42605
|
localCleanup = await cleanupPrMergeLocalBranch(headRef, {
|
|
42480
42606
|
beforeWorktrees,
|
|
42481
42607
|
startingPath,
|
|
42482
|
-
pathExists: (p) => (0,
|
|
42608
|
+
pathExists: (p) => (0, import_node_fs48.existsSync)(p),
|
|
42483
42609
|
execGit: async (args) => (await execFileP2("git", args, { timeout: GIT_TIMEOUT_MS })).stdout,
|
|
42484
42610
|
teardownWorktreeStage,
|
|
42485
42611
|
deferredStore,
|
|
@@ -42580,8 +42706,8 @@ function trainApplyDeps() {
|
|
|
42580
42706
|
// Hub-App-authority dispatch of the central tenant-control.yml (#1717) — the Hub fires the
|
|
42581
42707
|
// workflow_dispatch with its App token. Never throws for an expected rejection: it returns the dispatch
|
|
42582
42708
|
// outcome so runTenantControl can map a 5xx (transport-failed, retryable) vs a 4xx (rejected) vs ok.
|
|
42583
|
-
dispatchTenantControl: async ({ repo, stage, action, lines }) => {
|
|
42584
|
-
const res = await tenantControl({ repo, stage, action, ...lines != null ? { lines } : {} }, registryClientDeps(await loadConfig()));
|
|
42709
|
+
dispatchTenantControl: async ({ repo, stage, action, lines, task, artifact }) => {
|
|
42710
|
+
const res = await tenantControl({ repo, stage, action, ...lines != null ? { lines } : {}, ...task ? { task } : {}, ...artifact ? { artifact } : {} }, registryClientDeps(await loadConfig()));
|
|
42585
42711
|
if (res.ok) return { ok: true };
|
|
42586
42712
|
const body = res.body;
|
|
42587
42713
|
return { ok: false, category: body?.category, error: body?.error ?? res.error };
|
|
@@ -42605,8 +42731,8 @@ function trainApplyDeps() {
|
|
|
42605
42731
|
// Slack release announcement (#883): Hub-only + best-effort inside announceRelease itself.
|
|
42606
42732
|
announce: (args) => announceRelease({
|
|
42607
42733
|
run: async (file, cmdArgs) => (await execFileP2(file, cmdArgs, { timeout: GH_TRAIN_TIMEOUT_MS })).stdout,
|
|
42608
|
-
readFile: (path2) => (0,
|
|
42609
|
-
removeFile: (path2) => (0,
|
|
42734
|
+
readFile: (path2) => (0, import_promises12.readFile)(path2, "utf8"),
|
|
42735
|
+
removeFile: (path2) => (0, import_promises12.unlink)(path2)
|
|
42610
42736
|
}, args),
|
|
42611
42737
|
// #4713 (I/O-boundary census): `null` used to mean BOTH "this project configures no edge domains"
|
|
42612
42738
|
// (a real answer) and "the registry read missed" — so a release verdict printed an environments block
|
|
@@ -42843,7 +42969,7 @@ for (const commandName of ["rcand", "release"]) {
|
|
|
42843
42969
|
}
|
|
42844
42970
|
let summaryLines;
|
|
42845
42971
|
try {
|
|
42846
|
-
summaryLines = summaryFileLines(await (0,
|
|
42972
|
+
summaryLines = summaryFileLines(await (0, import_promises12.readFile)(o.announceSummaryFile, "utf8"));
|
|
42847
42973
|
} catch (e) {
|
|
42848
42974
|
return fail(`release: could not read --announce-summary-file ${o.announceSummaryFile}: ${e.message}`);
|
|
42849
42975
|
}
|
|
@@ -43083,12 +43209,12 @@ access.command("audit").description("audit collaborator roles + train-branch pus
|
|
|
43083
43209
|
targets = resolution.targets;
|
|
43084
43210
|
}
|
|
43085
43211
|
const derivedMatrix = registryProjects ? accessMatrixFromProjects(registryProjects) : {};
|
|
43086
|
-
const fileMatrix = (0,
|
|
43212
|
+
const fileMatrix = (0, import_node_fs48.existsSync)("access-matrix.json") ? loadAccessMatrix((0, import_node_fs48.readFileSync)("access-matrix.json", "utf8")) : {};
|
|
43087
43213
|
const matrix = mergeAccessMatrix(fileMatrix, derivedMatrix);
|
|
43088
43214
|
const derivedContracts = registryProjects ? dataAccessContractsFromProjects(registryProjects) : { consumers: {} };
|
|
43089
|
-
const fileContracts = (0,
|
|
43215
|
+
const fileContracts = (0, import_node_fs48.existsSync)("data-access-contracts.json") ? loadDataAccessContracts((0, import_node_fs48.readFileSync)("data-access-contracts.json", "utf8")) : { consumers: {} };
|
|
43090
43216
|
const dataAccess = mergeDataAccessContracts(fileContracts, derivedContracts);
|
|
43091
|
-
const sanctioned = (0,
|
|
43217
|
+
const sanctioned = (0, import_node_fs48.existsSync)("access-matrix.json") ? loadSanctionedAdmins((0, import_node_fs48.readFileSync)("access-matrix.json", "utf8")) : {};
|
|
43092
43218
|
const report = await auditOrgAccess(targets, deps, matrix, dataAccess, sanctioned);
|
|
43093
43219
|
console.log(o.json ? JSON.stringify(report, null, 2) : renderAccessReport(report));
|
|
43094
43220
|
if (!report.ok) process.exitCode = 1;
|
|
@@ -43126,16 +43252,16 @@ function directoryBytes(path2) {
|
|
|
43126
43252
|
let total = 0;
|
|
43127
43253
|
let entries;
|
|
43128
43254
|
try {
|
|
43129
|
-
entries = (0,
|
|
43255
|
+
entries = (0, import_node_fs48.readdirSync)(path2, { withFileTypes: true });
|
|
43130
43256
|
} catch {
|
|
43131
43257
|
return 0;
|
|
43132
43258
|
}
|
|
43133
43259
|
for (const entry of entries) {
|
|
43134
|
-
const child2 = (0,
|
|
43260
|
+
const child2 = (0, import_node_path45.join)(path2, entry.name);
|
|
43135
43261
|
if (entry.isDirectory()) total += directoryBytes(child2);
|
|
43136
43262
|
else {
|
|
43137
43263
|
try {
|
|
43138
|
-
total += (0,
|
|
43264
|
+
total += (0, import_node_fs48.statSync)(child2).size;
|
|
43139
43265
|
} catch {
|
|
43140
43266
|
}
|
|
43141
43267
|
}
|
|
@@ -43143,25 +43269,25 @@ function directoryBytes(path2) {
|
|
|
43143
43269
|
return total;
|
|
43144
43270
|
}
|
|
43145
43271
|
function listDirEntries(dir) {
|
|
43146
|
-
return (0,
|
|
43272
|
+
return (0, import_node_fs48.readdirSync)(dir, { withFileTypes: true }).map((d) => ({ name: d.name, isDirectory: d.isDirectory() }));
|
|
43147
43273
|
}
|
|
43148
43274
|
function readInstalledPluginRefs(configRoot) {
|
|
43149
43275
|
const p = installedPluginsPathForConfig(configRoot);
|
|
43150
|
-
if (!(0,
|
|
43276
|
+
if (!(0, import_node_fs48.existsSync)(p)) return [];
|
|
43151
43277
|
try {
|
|
43152
|
-
return installedPluginPaths((0,
|
|
43278
|
+
return installedPluginPaths((0, import_node_fs48.readFileSync)(p, "utf8"));
|
|
43153
43279
|
} catch {
|
|
43154
43280
|
return null;
|
|
43155
43281
|
}
|
|
43156
43282
|
}
|
|
43157
43283
|
function pluginCacheFsDeps(configRoot, dirBytes) {
|
|
43158
43284
|
return {
|
|
43159
|
-
exists: (p) => (0,
|
|
43160
|
-
listVersionDirs: (root) => (0,
|
|
43285
|
+
exists: (p) => (0, import_node_fs48.existsSync)(p),
|
|
43286
|
+
listVersionDirs: (root) => (0, import_node_fs48.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name),
|
|
43161
43287
|
dirBytes,
|
|
43162
|
-
listStagingDirs: (root) => (0,
|
|
43288
|
+
listStagingDirs: (root) => (0, import_node_fs48.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => {
|
|
43163
43289
|
try {
|
|
43164
|
-
return { name: d.name, mtimeMs: newestMtimeMs((0,
|
|
43290
|
+
return { name: d.name, mtimeMs: newestMtimeMs((0, import_node_path45.join)(root, d.name), listDirEntries, (p) => (0, import_node_fs48.statSync)(p).mtimeMs) };
|
|
43165
43291
|
} catch {
|
|
43166
43292
|
return { name: d.name, mtimeMs: Date.now() };
|
|
43167
43293
|
}
|
|
@@ -43175,10 +43301,10 @@ function stagingApplyFsGuard(configRoot) {
|
|
|
43175
43301
|
return {
|
|
43176
43302
|
referencedPaths: () => readInstalledPluginRefs(configRoot),
|
|
43177
43303
|
mtimeMs: (name) => {
|
|
43178
|
-
const p = (0,
|
|
43179
|
-
if (!(0,
|
|
43304
|
+
const p = (0, import_node_path45.join)(stagingRoot, name);
|
|
43305
|
+
if (!(0, import_node_fs48.existsSync)(p)) return null;
|
|
43180
43306
|
try {
|
|
43181
|
-
return newestMtimeMs(p, listDirEntries, (q) => (0,
|
|
43307
|
+
return newestMtimeMs(p, listDirEntries, (q) => (0, import_node_fs48.statSync)(q).mtimeMs);
|
|
43182
43308
|
} catch {
|
|
43183
43309
|
return null;
|
|
43184
43310
|
}
|
|
@@ -43204,7 +43330,7 @@ program2.command("plugin-prune").description(`prune stale cached MMI plugin vers
|
|
|
43204
43330
|
{ withBytes: true, configRoot, includeStaging: surface !== "codex" }
|
|
43205
43331
|
);
|
|
43206
43332
|
const anythingToDelete = plan.prune.length > 0 || plan.staging.length > 0;
|
|
43207
|
-
const result = o.apply && anythingToDelete ? applyPluginCachePlan(plan, (p) => (0,
|
|
43333
|
+
const result = o.apply && anythingToDelete ? applyPluginCachePlan(plan, (p) => (0, import_node_fs48.rmSync)(p, { recursive: true, force: true }), stagingApplyFsGuard(configRoot)) : void 0;
|
|
43208
43334
|
const warnings = plan.prune.length > 0 ? [CONCURRENT_SESSION_WARNING] : [];
|
|
43209
43335
|
if (o.json) console.log(JSON.stringify({ ...plan, warnings, applied: result ?? null }));
|
|
43210
43336
|
else console.log(renderPluginCachePlan(plan, result));
|
|
@@ -43212,7 +43338,7 @@ program2.command("plugin-prune").description(`prune stale cached MMI plugin vers
|
|
|
43212
43338
|
});
|
|
43213
43339
|
function readReleaseCatchupState(path2) {
|
|
43214
43340
|
try {
|
|
43215
|
-
const parsed = JSON.parse((0,
|
|
43341
|
+
const parsed = JSON.parse((0, import_node_fs48.readFileSync)(path2, "utf8"));
|
|
43216
43342
|
return typeof parsed?.checkedAt === "number" ? parsed : void 0;
|
|
43217
43343
|
} catch {
|
|
43218
43344
|
return void 0;
|
|
@@ -43220,8 +43346,8 @@ function readReleaseCatchupState(path2) {
|
|
|
43220
43346
|
}
|
|
43221
43347
|
function writeReleaseCatchupState(path2, state) {
|
|
43222
43348
|
try {
|
|
43223
|
-
(0,
|
|
43224
|
-
(0,
|
|
43349
|
+
(0, import_node_fs48.mkdirSync)((0, import_node_path45.dirname)(path2), { recursive: true });
|
|
43350
|
+
(0, import_node_fs48.writeFileSync)(path2, `${JSON.stringify(state)}
|
|
43225
43351
|
`);
|
|
43226
43352
|
} catch {
|
|
43227
43353
|
}
|