@mutmutco/cli 3.125.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 +517 -389
- 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);
|
|
@@ -36998,6 +37112,7 @@ var surfaces_default = {
|
|
|
36998
37112
|
surfaceId: "mmi-cli"
|
|
36999
37113
|
},
|
|
37000
37114
|
hookPolicy: {
|
|
37115
|
+
consoleLauncherPath: "bin/mmi-hook-console.cmd",
|
|
37001
37116
|
launcherPath: "bin/mmi-hook",
|
|
37002
37117
|
ownerPath: "scripts/hook-policy.mjs",
|
|
37003
37118
|
runnerPath: "scripts/hook-run.mjs",
|
|
@@ -37661,6 +37776,7 @@ var surfaces_default = {
|
|
|
37661
37776
|
"scripts/hook-trace.mjs",
|
|
37662
37777
|
"bin/mmi-hook",
|
|
37663
37778
|
"bin/mmi-hook.exe",
|
|
37779
|
+
"bin/mmi-hook-console.cmd",
|
|
37664
37780
|
"native/windows-hook-launcher.c",
|
|
37665
37781
|
"scripts/build-windows-hook-launcher.ps1",
|
|
37666
37782
|
"scripts/probe-windows-hook-window.ps1"
|
|
@@ -39182,9 +39298,9 @@ function ghAccountCaveat(announcedLogin, accounts) {
|
|
|
39182
39298
|
}
|
|
39183
39299
|
|
|
39184
39300
|
// src/doctor-io.ts
|
|
39185
|
-
var
|
|
39301
|
+
var import_node_fs47 = require("node:fs");
|
|
39186
39302
|
var import_node_os18 = require("node:os");
|
|
39187
|
-
var
|
|
39303
|
+
var import_node_path44 = require("node:path");
|
|
39188
39304
|
var import_node_child_process19 = require("node:child_process");
|
|
39189
39305
|
var import_node_util8 = require("node:util");
|
|
39190
39306
|
var execFileP6 = (0, import_node_util8.promisify)(import_node_child_process19.execFile);
|
|
@@ -39192,7 +39308,7 @@ var MMI_PLUGIN_ID2 = "mmi@mutmutco";
|
|
|
39192
39308
|
function installedClaudePluginVersion() {
|
|
39193
39309
|
try {
|
|
39194
39310
|
const file = JSON.parse(
|
|
39195
|
-
(0,
|
|
39311
|
+
(0, import_node_fs47.readFileSync)((0, import_node_path44.join)((0, import_node_os18.homedir)(), ".claude", "plugins", "installed_plugins.json"), "utf8")
|
|
39196
39312
|
);
|
|
39197
39313
|
const versions = (file.plugins?.[MMI_PLUGIN_ID2] ?? []).map((r) => r.version).filter((v) => Boolean(v));
|
|
39198
39314
|
if (versions.length === 0) return void 0;
|
|
@@ -39203,7 +39319,7 @@ function installedClaudePluginVersion() {
|
|
|
39203
39319
|
}
|
|
39204
39320
|
function manifestVersion(path2) {
|
|
39205
39321
|
try {
|
|
39206
|
-
const manifest = JSON.parse((0,
|
|
39322
|
+
const manifest = JSON.parse((0, import_node_fs47.readFileSync)(path2, "utf8"));
|
|
39207
39323
|
return typeof manifest.version === "string" && manifest.version.trim() ? manifest.version.trim() : void 0;
|
|
39208
39324
|
} catch {
|
|
39209
39325
|
return void 0;
|
|
@@ -39213,22 +39329,22 @@ function installedSurfacePluginVersion(surface) {
|
|
|
39213
39329
|
const token = surfaceToken(surface);
|
|
39214
39330
|
if (token === "kilo") {
|
|
39215
39331
|
try {
|
|
39216
|
-
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();
|
|
39217
39333
|
return stamp || void 0;
|
|
39218
39334
|
} catch {
|
|
39219
39335
|
return void 0;
|
|
39220
39336
|
}
|
|
39221
39337
|
}
|
|
39222
39338
|
if (token === "cursor") {
|
|
39223
|
-
return manifestVersion((0,
|
|
39339
|
+
return manifestVersion((0, import_node_path44.join)(cursorLocalPluginRoot(), ".cursor-plugin", "plugin.json"));
|
|
39224
39340
|
}
|
|
39225
39341
|
if (token === "jervcode") {
|
|
39226
39342
|
const entry = mmiPiWrapperEntry();
|
|
39227
39343
|
if (!entry) return void 0;
|
|
39228
|
-
return manifestVersion((0,
|
|
39344
|
+
return manifestVersion((0, import_node_path44.join)(decodeURIComponent(entry.replace(/^file:\/\/\/?/, "")), "package.json"));
|
|
39229
39345
|
}
|
|
39230
39346
|
if (token === "kimi") {
|
|
39231
|
-
return manifestVersion((0,
|
|
39347
|
+
return manifestVersion((0, import_node_path44.join)(surfaceConfigRoot(surface), "plugins", "managed", "mmi", ".kimi-plugin", "plugin.json"));
|
|
39232
39348
|
}
|
|
39233
39349
|
if (token === "claude") return installedClaudePluginVersion();
|
|
39234
39350
|
if (token !== "codex") return void 0;
|
|
@@ -39266,13 +39382,13 @@ function worktreeRootSync() {
|
|
|
39266
39382
|
}
|
|
39267
39383
|
var gitignorePath = () => {
|
|
39268
39384
|
const root = worktreeRootSync();
|
|
39269
|
-
return root === null ? null : (0,
|
|
39385
|
+
return root === null ? null : (0, import_node_path44.join)(root, ".gitignore");
|
|
39270
39386
|
};
|
|
39271
39387
|
function readGitignore() {
|
|
39272
39388
|
const path2 = gitignorePath();
|
|
39273
39389
|
if (path2 === null) return null;
|
|
39274
39390
|
try {
|
|
39275
|
-
return (0,
|
|
39391
|
+
return (0, import_node_fs47.readFileSync)(path2, "utf8");
|
|
39276
39392
|
} catch {
|
|
39277
39393
|
return null;
|
|
39278
39394
|
}
|
|
@@ -39281,7 +39397,7 @@ function writeGitignore(content) {
|
|
|
39281
39397
|
const path2 = gitignorePath();
|
|
39282
39398
|
if (path2 === null) return false;
|
|
39283
39399
|
try {
|
|
39284
|
-
(0,
|
|
39400
|
+
(0, import_node_fs47.writeFileSync)(path2, content, "utf8");
|
|
39285
39401
|
return true;
|
|
39286
39402
|
} catch {
|
|
39287
39403
|
return false;
|
|
@@ -39300,7 +39416,7 @@ async function repoRoot() {
|
|
|
39300
39416
|
}
|
|
39301
39417
|
function hasRepoLocalWorktrees() {
|
|
39302
39418
|
const root = worktreeRootSync();
|
|
39303
|
-
return root !== null && (0,
|
|
39419
|
+
return root !== null && (0, import_node_fs47.existsSync)((0, import_node_path44.join)(root, ".worktrees"));
|
|
39304
39420
|
}
|
|
39305
39421
|
|
|
39306
39422
|
// src/cross-repo-filing-issue.ts
|
|
@@ -39396,7 +39512,7 @@ function binaryOnPath(bin) {
|
|
|
39396
39512
|
for (const dir of pathEnvEntries(process.env.PATH ?? "")) {
|
|
39397
39513
|
for (const ext of exts) {
|
|
39398
39514
|
try {
|
|
39399
|
-
if ((0,
|
|
39515
|
+
if ((0, import_node_fs48.existsSync)((0, import_node_path45.join)(dir, `${bin}${ext}`))) return true;
|
|
39400
39516
|
} catch {
|
|
39401
39517
|
}
|
|
39402
39518
|
}
|
|
@@ -39418,8 +39534,8 @@ ${r.stderr ?? ""}`).catch(() => "");
|
|
|
39418
39534
|
function ghMultiAccountCaveat(announcedLogin) {
|
|
39419
39535
|
try {
|
|
39420
39536
|
const hostsPath = ghHostsConfigPath(process.env, process.platform);
|
|
39421
|
-
if (!hostsPath || !(0,
|
|
39422
|
-
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")));
|
|
39423
39539
|
} catch {
|
|
39424
39540
|
return void 0;
|
|
39425
39541
|
}
|
|
@@ -39427,7 +39543,7 @@ function ghMultiAccountCaveat(announcedLogin) {
|
|
|
39427
39543
|
var ENV_HEAL_LOCK_STALE_MS = 10 * 6e4;
|
|
39428
39544
|
var ENV_HEAL_LOCK_MAX_WAIT_MS = 2 * 6e4;
|
|
39429
39545
|
function envHealLockPath(home) {
|
|
39430
|
-
return (0,
|
|
39546
|
+
return (0, import_node_path45.join)(home, ".claude", "plugins", ".mmi-env-heal.lock");
|
|
39431
39547
|
}
|
|
39432
39548
|
async function withEnvHealLock(what, run) {
|
|
39433
39549
|
try {
|
|
@@ -39560,7 +39676,7 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
39560
39676
|
);
|
|
39561
39677
|
const result = applyPluginCachePlan(
|
|
39562
39678
|
plan,
|
|
39563
|
-
(p) => (0,
|
|
39679
|
+
(p) => (0, import_node_fs48.rmSync)(p, { recursive: true }),
|
|
39564
39680
|
stagingApplyFsGuard(configRoot)
|
|
39565
39681
|
);
|
|
39566
39682
|
return {
|
|
@@ -39632,7 +39748,7 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
39632
39748
|
disableAutoUpdate: () => {
|
|
39633
39749
|
if (detectSurface(process.env) === "codex") return void 0;
|
|
39634
39750
|
return disableOrgMarketplaceBackgroundUpdates(
|
|
39635
|
-
(0,
|
|
39751
|
+
(0, import_node_path45.join)((0, import_node_os19.homedir)(), ...KNOWN_MARKETPLACES_RELATIVE),
|
|
39636
39752
|
[MMI_MARKETPLACE_NAME]
|
|
39637
39753
|
);
|
|
39638
39754
|
}
|
|
@@ -39646,7 +39762,7 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
39646
39762
|
// adopted the generated routing index (MMG-Unlive: `docs/Archive/**` only, no index, no gate.yml) would
|
|
39647
39763
|
// get a permanent — demanding an artifact it never asked for.
|
|
39648
39764
|
docsIndexState: (root) => {
|
|
39649
|
-
if (!(0,
|
|
39765
|
+
if (!(0, import_node_fs48.existsSync)((0, import_node_path45.join)(root, DOCS_INDEX_PATH))) return void 0;
|
|
39650
39766
|
const real = createDocsIndexDeps(root);
|
|
39651
39767
|
let docs2;
|
|
39652
39768
|
const listDocs = () => docs2 ??= real.listDocs();
|
|
@@ -39655,7 +39771,7 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
39655
39771
|
},
|
|
39656
39772
|
// #4168: working-tree heal — write if drifted, then re-check. Commit remains the operator's step.
|
|
39657
39773
|
healDocsIndex: (root) => {
|
|
39658
|
-
if (!(0,
|
|
39774
|
+
if (!(0, import_node_fs48.existsSync)((0, import_node_path45.join)(root, DOCS_INDEX_PATH))) return { drift: false, docCount: 0 };
|
|
39659
39775
|
const real = createDocsIndexDeps(root);
|
|
39660
39776
|
let docs2;
|
|
39661
39777
|
const listDocs = () => docs2 ??= real.listDocs();
|
|
@@ -39693,8 +39809,8 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
39693
39809
|
});
|
|
39694
39810
|
const raced = await Promise.race([
|
|
39695
39811
|
work.then((r) => ({ ...r, timedOut: false })),
|
|
39696
|
-
new Promise((
|
|
39697
|
-
ceiling = setTimeout(() =>
|
|
39812
|
+
new Promise((resolve6) => {
|
|
39813
|
+
ceiling = setTimeout(() => resolve6({ timedOut: true, scanned: 0, findings: 0, fixed: 0, failed: 0 }), BOARD_DOCTOR_TIMEOUT_MS);
|
|
39698
39814
|
})
|
|
39699
39815
|
]);
|
|
39700
39816
|
if (raced.timedOut) return { scanned: 0, findings: 0, fixed: 0, failed: 0, timedOut: true };
|
|
@@ -39727,8 +39843,8 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
39727
39843
|
incomplete: nb.incomplete,
|
|
39728
39844
|
timedOut: false
|
|
39729
39845
|
})),
|
|
39730
|
-
new Promise((
|
|
39731
|
-
ceiling = setTimeout(() =>
|
|
39846
|
+
new Promise((resolve6) => {
|
|
39847
|
+
ceiling = setTimeout(() => resolve6({ driftLines: [], incomplete: [], timedOut: true }), SCHEDULES_DRIFT_TIMEOUT_MS);
|
|
39732
39848
|
})
|
|
39733
39849
|
]);
|
|
39734
39850
|
if (!raced.timedOut && raced.incomplete.length === 0) writeSchedulesDriftCache(cachePath, raced.driftLines);
|
|
@@ -40021,19 +40137,19 @@ program2.hook("preAction", async (_thisCommand, actionCommand) => {
|
|
|
40021
40137
|
});
|
|
40022
40138
|
var rules = program2.command("rules").description("org-managed .gitignore delivery");
|
|
40023
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) => {
|
|
40024
|
-
const path2 = (0,
|
|
40025
|
-
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;
|
|
40026
40142
|
const plan = planManagedGitignore(current);
|
|
40027
40143
|
const drift = [...plan.added.map((l) => `+${l}`), ...plan.removed.map((l) => `-${l}`)].join(", ") || "block normalize";
|
|
40028
40144
|
if (opts.json) {
|
|
40029
|
-
if (opts.write && plan.changed) (0,
|
|
40145
|
+
if (opts.write && plan.changed) (0, import_node_fs48.writeFileSync)(path2, plan.content, "utf8");
|
|
40030
40146
|
console.log(JSON.stringify(plan, null, 2));
|
|
40031
40147
|
if (!opts.write && plan.changed) process.exitCode = 1;
|
|
40032
40148
|
return;
|
|
40033
40149
|
}
|
|
40034
40150
|
if (opts.write) {
|
|
40035
40151
|
if (plan.changed) {
|
|
40036
|
-
(0,
|
|
40152
|
+
(0, import_node_fs48.writeFileSync)(path2, plan.content, "utf8");
|
|
40037
40153
|
console.log(`mmi-cli devops org rules gitignore: updated .gitignore (${drift})`);
|
|
40038
40154
|
} else {
|
|
40039
40155
|
console.log("mmi-cli devops org rules gitignore: up to date");
|
|
@@ -40192,8 +40308,8 @@ gcCmd.option("--dry-run", "show what would be deleted (default)").option("--appl
|
|
|
40192
40308
|
if (!Number.isFinite(limit) || limit < 1) return fail("worktree gc: --limit must be a positive integer");
|
|
40193
40309
|
let root;
|
|
40194
40310
|
if (o.root !== void 0) {
|
|
40195
|
-
root = (0,
|
|
40196
|
-
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`);
|
|
40197
40313
|
const gcRepoRoot = (await execFileP2("git", ["rev-parse", "--show-toplevel"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim() || process.cwd();
|
|
40198
40314
|
if (isPathUnderDirectory2(gcRepoRoot, root)) {
|
|
40199
40315
|
return fail(`worktree gc: --root ${root} contains this checkout \u2014 name a worktrees root, not the repo or an ancestor of it`);
|
|
@@ -40241,7 +40357,7 @@ function runWorktreeInstall(command, cwd, quiet, opts) {
|
|
|
40241
40357
|
quiet ? "ignore" : "inherit",
|
|
40242
40358
|
"pipe"
|
|
40243
40359
|
];
|
|
40244
|
-
return new Promise((
|
|
40360
|
+
return new Promise((resolve6, reject) => {
|
|
40245
40361
|
const child2 = opts?.shell ? (0, import_node_child_process20.spawn)(command, { cwd, stdio, windowsHide: true, shell: true }) : (() => {
|
|
40246
40362
|
const [bin, ...args] = command.split(" ");
|
|
40247
40363
|
const file = isWin2 ? "cmd.exe" : bin;
|
|
@@ -40268,7 +40384,7 @@ function runWorktreeInstall(command, cwd, quiet, opts) {
|
|
|
40268
40384
|
});
|
|
40269
40385
|
child2.on("exit", (code) => {
|
|
40270
40386
|
clearTimeout(timer);
|
|
40271
|
-
if (code === 0) return
|
|
40387
|
+
if (code === 0) return resolve6();
|
|
40272
40388
|
const tail = stderrTail.trim();
|
|
40273
40389
|
reject(new Error(`${command} exited ${code} in ${cwd}${tail ? `
|
|
40274
40390
|
${tail}` : ""}`));
|
|
@@ -40290,7 +40406,7 @@ async function currentWorktreeRemovalContext(command, force) {
|
|
|
40290
40406
|
};
|
|
40291
40407
|
}
|
|
40292
40408
|
async function unprovenWorktreeReason(wtPath, repoRoot2) {
|
|
40293
|
-
if (!(0,
|
|
40409
|
+
if (!(0, import_node_fs48.existsSync)(wtPath)) return `${wtPath} does not exist on disk`;
|
|
40294
40410
|
const porcelain = (await execFileP2("git", ["-C", repoRoot2, "worktree", "list", "--porcelain"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout;
|
|
40295
40411
|
const registered = parseWorktreePorcelainEntries(porcelain);
|
|
40296
40412
|
if (!registered.length) {
|
|
@@ -40320,26 +40436,26 @@ function makeProvisionDeps(worktreeRoot, quiet, log) {
|
|
|
40320
40436
|
function acquireWorktreeSetupLock(worktreeRoot) {
|
|
40321
40437
|
const lockPath = repoRuntimeStatePath(worktreeRoot, "worktree-setup.lock");
|
|
40322
40438
|
const take = () => {
|
|
40323
|
-
const fd = (0,
|
|
40439
|
+
const fd = (0, import_node_fs48.openSync)(lockPath, "wx");
|
|
40324
40440
|
try {
|
|
40325
|
-
(0,
|
|
40441
|
+
(0, import_node_fs48.writeSync)(fd, String(Date.now()));
|
|
40326
40442
|
} finally {
|
|
40327
|
-
(0,
|
|
40443
|
+
(0, import_node_fs48.closeSync)(fd);
|
|
40328
40444
|
}
|
|
40329
40445
|
return () => {
|
|
40330
40446
|
try {
|
|
40331
|
-
(0,
|
|
40447
|
+
(0, import_node_fs48.rmSync)(lockPath, { force: true });
|
|
40332
40448
|
} catch {
|
|
40333
40449
|
}
|
|
40334
40450
|
};
|
|
40335
40451
|
};
|
|
40336
40452
|
try {
|
|
40337
|
-
(0,
|
|
40453
|
+
(0, import_node_fs48.mkdirSync)((0, import_node_path45.dirname)(lockPath), { recursive: true });
|
|
40338
40454
|
return take();
|
|
40339
40455
|
} catch {
|
|
40340
40456
|
try {
|
|
40341
|
-
if (Date.now() - (0,
|
|
40342
|
-
(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 });
|
|
40343
40459
|
return take();
|
|
40344
40460
|
}
|
|
40345
40461
|
} catch {
|
|
@@ -40455,7 +40571,7 @@ withExamples(mutating(
|
|
|
40455
40571
|
}
|
|
40456
40572
|
if (!resumed) {
|
|
40457
40573
|
step = `git worktree add ${wtPath}`;
|
|
40458
|
-
const wtPathPreExisted = (0,
|
|
40574
|
+
const wtPathPreExisted = (0, import_node_fs48.existsSync)(wtPath);
|
|
40459
40575
|
const partialRemove = worktreeRemoveDeps(async (args) => (await execFileP2("git", args, { timeout: GIT_TIMEOUT_MS })).stdout);
|
|
40460
40576
|
await withWorktreeAddLock(repoRoot2, () => addWorktreeRobust(wtPath, branch, base, {
|
|
40461
40577
|
// #4834: `-c core.longpaths=true` rides the add command itself — a Windows worktree path
|
|
@@ -40471,13 +40587,13 @@ withExamples(mutating(
|
|
|
40471
40587
|
},
|
|
40472
40588
|
deleteBranch: (b) => execFileP2("git", ["branch", "-D", b], { timeout: GIT_TIMEOUT_MS }).then(() => void 0),
|
|
40473
40589
|
cleanupPartial: async () => {
|
|
40474
|
-
if (wtPathPreExisted || !(0,
|
|
40590
|
+
if (wtPathPreExisted || !(0, import_node_fs48.existsSync)(wtPath)) return;
|
|
40475
40591
|
partialRemove.detachReparsePoints(wtPath);
|
|
40476
40592
|
await execFileP2("git", ["worktree", "remove", "--force", wtPath], { timeout: GIT_TIMEOUT_MS }).catch(() => partialRemove.removeWorktreeDir(wtPath).then(() => void 0));
|
|
40477
40593
|
await execFileP2("git", ["worktree", "prune"], { timeout: GIT_TIMEOUT_MS }).catch(() => {
|
|
40478
40594
|
});
|
|
40479
40595
|
},
|
|
40480
|
-
sleep: (ms) => new Promise((
|
|
40596
|
+
sleep: (ms) => new Promise((resolve6) => setTimeout(resolve6, ms)),
|
|
40481
40597
|
log: (m) => {
|
|
40482
40598
|
if (!o.json) console.error(` ${m}`);
|
|
40483
40599
|
}
|
|
@@ -40929,9 +41045,7 @@ docs.command("refs").description("deterministic doc reference gate: every backti
|
|
|
40929
41045
|
try {
|
|
40930
41046
|
const root = await repoRoot();
|
|
40931
41047
|
const commandPaths = new Set(
|
|
40932
|
-
buildCommandManifest(program2).index.map(
|
|
40933
|
-
(entry) => entry.house && entry.house !== "core" ? `${entry.house} ${entry.path}` : entry.path
|
|
40934
|
-
)
|
|
41048
|
+
buildCommandManifest(program2).index.map((entry) => entry.path)
|
|
40935
41049
|
);
|
|
40936
41050
|
const result = runDocRefs(root, { commandPaths });
|
|
40937
41051
|
if (o.json) {
|
|
@@ -41014,7 +41128,7 @@ async function reportWrite(label, res) {
|
|
|
41014
41128
|
return failGraceful(`${label}: HTTP ${res.status}${detail ? ` \u2014 ${detail}` : ""}`);
|
|
41015
41129
|
}
|
|
41016
41130
|
var tenant = program2.command("tenant").description("tenant runtime control through Hub authority");
|
|
41017
|
-
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) => {
|
|
41018
41132
|
try {
|
|
41019
41133
|
let lines;
|
|
41020
41134
|
if (o.lines !== void 0) {
|
|
@@ -41022,7 +41136,12 @@ tenant.command("control <owner/repo> <stage> <action>").description("bounded ten
|
|
|
41022
41136
|
lines = Number(o.lines);
|
|
41023
41137
|
if (!Number.isInteger(lines) || lines < 1 || lines > 2e3) return fail("runtime tenant control: --lines must be an integer between 1 and 2000");
|
|
41024
41138
|
}
|
|
41025
|
-
|
|
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 });
|
|
41026
41145
|
if (!o.json && action === "verify-secrets" && result.secrets) {
|
|
41027
41146
|
const body = { ok: result.conclusion === "success", secrets: result.secrets, ssmStatus: result.conclusion === "success" ? "Success" : "Failed", raw: result.secretsRaw };
|
|
41028
41147
|
const { lines: lines2, failure } = renderVerifySecrets(body);
|
|
@@ -41044,6 +41163,15 @@ tenant.command("control <owner/repo> <stage> <action>").description("bounded ten
|
|
|
41044
41163
|
return failGraceful(`runtime tenant control: ${e.message}`);
|
|
41045
41164
|
}
|
|
41046
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
|
+
});
|
|
41047
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) => {
|
|
41048
41176
|
try {
|
|
41049
41177
|
const result = await runTenantReconcile(trainApplyDeps(), { repo, stage, watch: o.watch });
|
|
@@ -41189,10 +41317,10 @@ project.command("get [owner/repo]").description("a project's META (board ids + p
|
|
|
41189
41317
|
const track = resolveReleaseTrack(m, void 0, target);
|
|
41190
41318
|
const stages = branchesForTrack(track).join(" -> ");
|
|
41191
41319
|
const note = track === "direct" ? " (direct \u2014 no rc; /rcand refuses, /release ships development -> main)" : track === "trunk" ? " (trunk \u2014 main only)" : "";
|
|
41320
|
+
const deployNote = m.deployModel === "registry-publish" ? "\ndeploys are repository-owned publish workflows (registry-publish); no central tenant deploy runs for this repo." : "\ndeploys run centrally (tenant-deploy.yml); product repos carry no deploy files.";
|
|
41192
41321
|
console.error(
|
|
41193
41322
|
`${m.name ?? target} \u2014 class ${m.class ?? "?"} \u2014 deploy ${m.deployModel ?? "?"}
|
|
41194
|
-
release track: ${track} \u2014 stages: ${stages}${note}
|
|
41195
|
-
deploys run centrally (tenant-deploy.yml); product repos carry no deploy files. Inspect nonsecret DEPLOY facts with \`mmi-cli oracle org project deploy get\`; full coords remain OIDC-gated.`
|
|
41323
|
+
release track: ${track} \u2014 stages: ${stages}${note}` + deployNote + " Inspect nonsecret DEPLOY facts with `mmi-cli oracle org project deploy get`; full coords remain OIDC-gated."
|
|
41196
41324
|
);
|
|
41197
41325
|
}
|
|
41198
41326
|
});
|
|
@@ -41240,7 +41368,7 @@ project.command("set [owner/repo]").description("upsert project META (idempotent
|
|
|
41240
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`);
|
|
41241
41369
|
if (o.secretsFile) {
|
|
41242
41370
|
try {
|
|
41243
|
-
vars.push(`secrets=${(0,
|
|
41371
|
+
vars.push(`secrets=${(0, import_node_fs48.readFileSync)(o.secretsFile, "utf8")}`);
|
|
41244
41372
|
} catch (e) {
|
|
41245
41373
|
return fail(`org project set: cannot read --secrets-file ${o.secretsFile}: ${e.message}`);
|
|
41246
41374
|
}
|
|
@@ -41566,7 +41694,7 @@ withExamples(mutating(
|
|
|
41566
41694
|
try {
|
|
41567
41695
|
title = await resolveIssueTitle(
|
|
41568
41696
|
{ title: opts.title, titleFile: opts.titleFile },
|
|
41569
|
-
{ readFile:
|
|
41697
|
+
{ readFile: import_promises12.readFile, readStdin }
|
|
41570
41698
|
);
|
|
41571
41699
|
} catch (e) {
|
|
41572
41700
|
return fail(
|
|
@@ -41608,8 +41736,8 @@ withExamples(mutating(
|
|
|
41608
41736
|
let surfaceFlagLabel;
|
|
41609
41737
|
try {
|
|
41610
41738
|
issueType = resolveCreateType(o.type, "issue create", o.label);
|
|
41611
|
-
title = await resolveIssueTitle({ title: o.title, titleFile: o.titleFile }, { readFile:
|
|
41612
|
-
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 });
|
|
41613
41741
|
if (o.idempotencyKey) body = appendIdempotencyMarker(body, o.idempotencyKey);
|
|
41614
41742
|
priority = resolveCreatePriority(o.priority, "issue create");
|
|
41615
41743
|
extraLabels = [...o.label ?? []];
|
|
@@ -41790,7 +41918,7 @@ jsonParity(issue.command("comment <ref>").description("post a Markdown comment t
|
|
|
41790
41918
|
}
|
|
41791
41919
|
let body;
|
|
41792
41920
|
try {
|
|
41793
|
-
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 });
|
|
41794
41922
|
} catch (e) {
|
|
41795
41923
|
return fail(`issue comment: ${e.message}`);
|
|
41796
41924
|
}
|
|
@@ -41850,8 +41978,8 @@ program2.command("report").description("file a friction report on the Hub board
|
|
|
41850
41978
|
let title;
|
|
41851
41979
|
const sourceRepo = o.repo ?? await resolveRepo(void 0);
|
|
41852
41980
|
try {
|
|
41853
|
-
title = await resolveIssueTitle({ title: o.title, titleFile: o.titleFile }, { readFile:
|
|
41854
|
-
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 });
|
|
41855
41983
|
priority = resolveCreatePriority(o.priority, "report");
|
|
41856
41984
|
if (!ISSUE_TYPES.includes(o.type)) {
|
|
41857
41985
|
throw new Error(`unknown issue type "${o.type}" \u2014 expected one of: ${ISSUE_TYPES.join(", ")}`);
|
|
@@ -41905,8 +42033,8 @@ program2.command("skill-lesson").description("file a skill-lesson on the Hub boa
|
|
|
41905
42033
|
let args;
|
|
41906
42034
|
try {
|
|
41907
42035
|
skill = assertSkillName(o.skill);
|
|
41908
|
-
rawBody = await resolveIssueBody({ body: o.body, bodyFile: o.bodyFile }, { readFile:
|
|
41909
|
-
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 });
|
|
41910
42038
|
title = buildSkillLessonTitle(skill, rawTitle);
|
|
41911
42039
|
priority = resolveCreatePriority(o.priority, "skill-lesson");
|
|
41912
42040
|
body = buildSkillLessonBody(rawBody, sourceRepo, pluginSha);
|
|
@@ -41965,8 +42093,8 @@ withExamples(pr.command("create").description("create a PR and print {number,url
|
|
|
41965
42093
|
let body;
|
|
41966
42094
|
let title;
|
|
41967
42095
|
try {
|
|
41968
|
-
title = await resolveIssueTitle({ title: o.title, titleFile: o.titleFile }, { readFile:
|
|
41969
|
-
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 });
|
|
41970
42098
|
} catch (e) {
|
|
41971
42099
|
return fail(`pr create: ${e.message}`, e instanceof TextArgError ? { code: e.code, offending_flag: e.offendingFlag } : void 0);
|
|
41972
42100
|
}
|
|
@@ -42008,11 +42136,11 @@ pr.command("view <number>").description("read a PR as structured JSON (merged st
|
|
|
42008
42136
|
}
|
|
42009
42137
|
});
|
|
42010
42138
|
async function listCiWorkflowPaths(cwd = process.cwd()) {
|
|
42011
|
-
const wfDir = (0,
|
|
42012
|
-
if (!(0,
|
|
42013
|
-
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) => {
|
|
42014
42142
|
try {
|
|
42015
|
-
return workflowReportsPrChecks((0,
|
|
42143
|
+
return workflowReportsPrChecks((0, import_node_fs48.readFileSync)((0, import_node_path45.join)(wfDir, name), "utf8"));
|
|
42016
42144
|
} catch {
|
|
42017
42145
|
return true;
|
|
42018
42146
|
}
|
|
@@ -42064,16 +42192,16 @@ function ciAuditDeps() {
|
|
|
42064
42192
|
// gate re-seed step is skipped gracefully rather than failing mid-run.
|
|
42065
42193
|
readSeedFile: (path2) => {
|
|
42066
42194
|
if (!root) return null;
|
|
42067
|
-
const fullPath = (0,
|
|
42068
|
-
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;
|
|
42069
42197
|
}
|
|
42070
42198
|
};
|
|
42071
42199
|
}
|
|
42072
42200
|
function hubRoot() {
|
|
42073
|
-
const fromPkg = (0,
|
|
42201
|
+
const fromPkg = (0, import_node_path45.join)(__dirname, "..", "..");
|
|
42074
42202
|
const marker = "skills/bootstrap/seeds/manifest.json";
|
|
42075
|
-
if ((0,
|
|
42076
|
-
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();
|
|
42077
42205
|
return null;
|
|
42078
42206
|
}
|
|
42079
42207
|
async function waitLoopCorePool(label) {
|
|
@@ -42122,7 +42250,7 @@ pr.command("checks-wait <number>").description(`bounded wait for PR checks; skip
|
|
|
42122
42250
|
// reading as "your tests failed". One call per failing run, only at the verdict.
|
|
42123
42251
|
diagnoseFailure: () => waitLoopDiagnosis("pr checks-wait", number, repo),
|
|
42124
42252
|
baseBranch,
|
|
42125
|
-
sleep: (ms) => new Promise((
|
|
42253
|
+
sleep: (ms) => new Promise((resolve6) => setTimeout(resolve6, ms)),
|
|
42126
42254
|
log: (message) => console.warn(message),
|
|
42127
42255
|
timeoutMs,
|
|
42128
42256
|
// Liveness on stderr, one line per poll. A silent bounded wait is indistinguishable from a hang, and
|
|
@@ -42202,7 +42330,7 @@ pr.command("land <number>").description("agent merge path (#1440): train probe \
|
|
|
42202
42330
|
// then read its own wall-clock kill as a broken diff.
|
|
42203
42331
|
diagnoseFailure: () => waitLoopDiagnosis("pr land", prNumber, repo),
|
|
42204
42332
|
baseBranch: "development",
|
|
42205
|
-
sleep: (ms) => new Promise((
|
|
42333
|
+
sleep: (ms) => new Promise((resolve6) => setTimeout(resolve6, ms)),
|
|
42206
42334
|
log: (message) => console.warn(message),
|
|
42207
42335
|
// `pr land` inherits the same (raised) checks budget, so it needs the same liveness — otherwise the
|
|
42208
42336
|
// 30m wait is SILENT and reads exactly like the hang #2940 was filed about, only three times longer.
|
|
@@ -42245,7 +42373,7 @@ pr.command("land <number>").description("agent merge path (#1440): train probe \
|
|
|
42245
42373
|
} else {
|
|
42246
42374
|
lastFailure = void 0;
|
|
42247
42375
|
}
|
|
42248
|
-
await new Promise((
|
|
42376
|
+
await new Promise((resolve6) => setTimeout(resolve6, PR_LAND_POLL_MS));
|
|
42249
42377
|
}
|
|
42250
42378
|
if (lastFailure) {
|
|
42251
42379
|
throw new Error(
|
|
@@ -42345,7 +42473,7 @@ jsonParity(pr.command("merge <number>").description("merge a PR (squash by defau
|
|
|
42345
42473
|
pollRateLimit: () => waitLoopCorePool("pr merge --wait"),
|
|
42346
42474
|
diagnoseFailure: () => waitLoopDiagnosis("pr merge --wait", number, repo),
|
|
42347
42475
|
baseBranch,
|
|
42348
|
-
sleep: (ms) => new Promise((
|
|
42476
|
+
sleep: (ms) => new Promise((resolve6) => setTimeout(resolve6, ms)),
|
|
42349
42477
|
log: (message) => console.warn(message),
|
|
42350
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`)
|
|
42351
42479
|
});
|
|
@@ -42381,7 +42509,7 @@ jsonParity(pr.command("merge <number>").description("merge a PR (squash by defau
|
|
|
42381
42509
|
}
|
|
42382
42510
|
if (!repoForPostCleanup) throw e;
|
|
42383
42511
|
console.warn(`pr merge: gh GraphQL rate-limited \u2014 merging PR #${number} via REST PUT instead (#4588).`);
|
|
42384
|
-
const commitMessage = bodyFile ? (0,
|
|
42512
|
+
const commitMessage = bodyFile ? (0, import_node_fs48.readFileSync)(bodyFile, "utf8") : void 0;
|
|
42385
42513
|
await defaultGitHubClient().rest("PUT", `repos/${repoForPostCleanup}/pulls/${number}/merge`, {
|
|
42386
42514
|
body: { merge_method: method.slice(2), ...commitMessage ? { commit_message: commitMessage } : {} },
|
|
42387
42515
|
timeoutMs: GH_MUTATION_TIMEOUT_MS
|
|
@@ -42477,7 +42605,7 @@ jsonParity(pr.command("merge <number>").description("merge a PR (squash by defau
|
|
|
42477
42605
|
localCleanup = await cleanupPrMergeLocalBranch(headRef, {
|
|
42478
42606
|
beforeWorktrees,
|
|
42479
42607
|
startingPath,
|
|
42480
|
-
pathExists: (p) => (0,
|
|
42608
|
+
pathExists: (p) => (0, import_node_fs48.existsSync)(p),
|
|
42481
42609
|
execGit: async (args) => (await execFileP2("git", args, { timeout: GIT_TIMEOUT_MS })).stdout,
|
|
42482
42610
|
teardownWorktreeStage,
|
|
42483
42611
|
deferredStore,
|
|
@@ -42578,8 +42706,8 @@ function trainApplyDeps() {
|
|
|
42578
42706
|
// Hub-App-authority dispatch of the central tenant-control.yml (#1717) — the Hub fires the
|
|
42579
42707
|
// workflow_dispatch with its App token. Never throws for an expected rejection: it returns the dispatch
|
|
42580
42708
|
// outcome so runTenantControl can map a 5xx (transport-failed, retryable) vs a 4xx (rejected) vs ok.
|
|
42581
|
-
dispatchTenantControl: async ({ repo, stage, action, lines }) => {
|
|
42582
|
-
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()));
|
|
42583
42711
|
if (res.ok) return { ok: true };
|
|
42584
42712
|
const body = res.body;
|
|
42585
42713
|
return { ok: false, category: body?.category, error: body?.error ?? res.error };
|
|
@@ -42603,8 +42731,8 @@ function trainApplyDeps() {
|
|
|
42603
42731
|
// Slack release announcement (#883): Hub-only + best-effort inside announceRelease itself.
|
|
42604
42732
|
announce: (args) => announceRelease({
|
|
42605
42733
|
run: async (file, cmdArgs) => (await execFileP2(file, cmdArgs, { timeout: GH_TRAIN_TIMEOUT_MS })).stdout,
|
|
42606
|
-
readFile: (path2) => (0,
|
|
42607
|
-
removeFile: (path2) => (0,
|
|
42734
|
+
readFile: (path2) => (0, import_promises12.readFile)(path2, "utf8"),
|
|
42735
|
+
removeFile: (path2) => (0, import_promises12.unlink)(path2)
|
|
42608
42736
|
}, args),
|
|
42609
42737
|
// #4713 (I/O-boundary census): `null` used to mean BOTH "this project configures no edge domains"
|
|
42610
42738
|
// (a real answer) and "the registry read missed" — so a release verdict printed an environments block
|
|
@@ -42841,7 +42969,7 @@ for (const commandName of ["rcand", "release"]) {
|
|
|
42841
42969
|
}
|
|
42842
42970
|
let summaryLines;
|
|
42843
42971
|
try {
|
|
42844
|
-
summaryLines = summaryFileLines(await (0,
|
|
42972
|
+
summaryLines = summaryFileLines(await (0, import_promises12.readFile)(o.announceSummaryFile, "utf8"));
|
|
42845
42973
|
} catch (e) {
|
|
42846
42974
|
return fail(`release: could not read --announce-summary-file ${o.announceSummaryFile}: ${e.message}`);
|
|
42847
42975
|
}
|
|
@@ -43081,12 +43209,12 @@ access.command("audit").description("audit collaborator roles + train-branch pus
|
|
|
43081
43209
|
targets = resolution.targets;
|
|
43082
43210
|
}
|
|
43083
43211
|
const derivedMatrix = registryProjects ? accessMatrixFromProjects(registryProjects) : {};
|
|
43084
|
-
const fileMatrix = (0,
|
|
43212
|
+
const fileMatrix = (0, import_node_fs48.existsSync)("access-matrix.json") ? loadAccessMatrix((0, import_node_fs48.readFileSync)("access-matrix.json", "utf8")) : {};
|
|
43085
43213
|
const matrix = mergeAccessMatrix(fileMatrix, derivedMatrix);
|
|
43086
43214
|
const derivedContracts = registryProjects ? dataAccessContractsFromProjects(registryProjects) : { consumers: {} };
|
|
43087
|
-
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: {} };
|
|
43088
43216
|
const dataAccess = mergeDataAccessContracts(fileContracts, derivedContracts);
|
|
43089
|
-
const sanctioned = (0,
|
|
43217
|
+
const sanctioned = (0, import_node_fs48.existsSync)("access-matrix.json") ? loadSanctionedAdmins((0, import_node_fs48.readFileSync)("access-matrix.json", "utf8")) : {};
|
|
43090
43218
|
const report = await auditOrgAccess(targets, deps, matrix, dataAccess, sanctioned);
|
|
43091
43219
|
console.log(o.json ? JSON.stringify(report, null, 2) : renderAccessReport(report));
|
|
43092
43220
|
if (!report.ok) process.exitCode = 1;
|
|
@@ -43124,16 +43252,16 @@ function directoryBytes(path2) {
|
|
|
43124
43252
|
let total = 0;
|
|
43125
43253
|
let entries;
|
|
43126
43254
|
try {
|
|
43127
|
-
entries = (0,
|
|
43255
|
+
entries = (0, import_node_fs48.readdirSync)(path2, { withFileTypes: true });
|
|
43128
43256
|
} catch {
|
|
43129
43257
|
return 0;
|
|
43130
43258
|
}
|
|
43131
43259
|
for (const entry of entries) {
|
|
43132
|
-
const child2 = (0,
|
|
43260
|
+
const child2 = (0, import_node_path45.join)(path2, entry.name);
|
|
43133
43261
|
if (entry.isDirectory()) total += directoryBytes(child2);
|
|
43134
43262
|
else {
|
|
43135
43263
|
try {
|
|
43136
|
-
total += (0,
|
|
43264
|
+
total += (0, import_node_fs48.statSync)(child2).size;
|
|
43137
43265
|
} catch {
|
|
43138
43266
|
}
|
|
43139
43267
|
}
|
|
@@ -43141,25 +43269,25 @@ function directoryBytes(path2) {
|
|
|
43141
43269
|
return total;
|
|
43142
43270
|
}
|
|
43143
43271
|
function listDirEntries(dir) {
|
|
43144
|
-
return (0,
|
|
43272
|
+
return (0, import_node_fs48.readdirSync)(dir, { withFileTypes: true }).map((d) => ({ name: d.name, isDirectory: d.isDirectory() }));
|
|
43145
43273
|
}
|
|
43146
43274
|
function readInstalledPluginRefs(configRoot) {
|
|
43147
43275
|
const p = installedPluginsPathForConfig(configRoot);
|
|
43148
|
-
if (!(0,
|
|
43276
|
+
if (!(0, import_node_fs48.existsSync)(p)) return [];
|
|
43149
43277
|
try {
|
|
43150
|
-
return installedPluginPaths((0,
|
|
43278
|
+
return installedPluginPaths((0, import_node_fs48.readFileSync)(p, "utf8"));
|
|
43151
43279
|
} catch {
|
|
43152
43280
|
return null;
|
|
43153
43281
|
}
|
|
43154
43282
|
}
|
|
43155
43283
|
function pluginCacheFsDeps(configRoot, dirBytes) {
|
|
43156
43284
|
return {
|
|
43157
|
-
exists: (p) => (0,
|
|
43158
|
-
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),
|
|
43159
43287
|
dirBytes,
|
|
43160
|
-
listStagingDirs: (root) => (0,
|
|
43288
|
+
listStagingDirs: (root) => (0, import_node_fs48.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => {
|
|
43161
43289
|
try {
|
|
43162
|
-
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) };
|
|
43163
43291
|
} catch {
|
|
43164
43292
|
return { name: d.name, mtimeMs: Date.now() };
|
|
43165
43293
|
}
|
|
@@ -43173,10 +43301,10 @@ function stagingApplyFsGuard(configRoot) {
|
|
|
43173
43301
|
return {
|
|
43174
43302
|
referencedPaths: () => readInstalledPluginRefs(configRoot),
|
|
43175
43303
|
mtimeMs: (name) => {
|
|
43176
|
-
const p = (0,
|
|
43177
|
-
if (!(0,
|
|
43304
|
+
const p = (0, import_node_path45.join)(stagingRoot, name);
|
|
43305
|
+
if (!(0, import_node_fs48.existsSync)(p)) return null;
|
|
43178
43306
|
try {
|
|
43179
|
-
return newestMtimeMs(p, listDirEntries, (q) => (0,
|
|
43307
|
+
return newestMtimeMs(p, listDirEntries, (q) => (0, import_node_fs48.statSync)(q).mtimeMs);
|
|
43180
43308
|
} catch {
|
|
43181
43309
|
return null;
|
|
43182
43310
|
}
|
|
@@ -43202,7 +43330,7 @@ program2.command("plugin-prune").description(`prune stale cached MMI plugin vers
|
|
|
43202
43330
|
{ withBytes: true, configRoot, includeStaging: surface !== "codex" }
|
|
43203
43331
|
);
|
|
43204
43332
|
const anythingToDelete = plan.prune.length > 0 || plan.staging.length > 0;
|
|
43205
|
-
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;
|
|
43206
43334
|
const warnings = plan.prune.length > 0 ? [CONCURRENT_SESSION_WARNING] : [];
|
|
43207
43335
|
if (o.json) console.log(JSON.stringify({ ...plan, warnings, applied: result ?? null }));
|
|
43208
43336
|
else console.log(renderPluginCachePlan(plan, result));
|
|
@@ -43210,7 +43338,7 @@ program2.command("plugin-prune").description(`prune stale cached MMI plugin vers
|
|
|
43210
43338
|
});
|
|
43211
43339
|
function readReleaseCatchupState(path2) {
|
|
43212
43340
|
try {
|
|
43213
|
-
const parsed = JSON.parse((0,
|
|
43341
|
+
const parsed = JSON.parse((0, import_node_fs48.readFileSync)(path2, "utf8"));
|
|
43214
43342
|
return typeof parsed?.checkedAt === "number" ? parsed : void 0;
|
|
43215
43343
|
} catch {
|
|
43216
43344
|
return void 0;
|
|
@@ -43218,8 +43346,8 @@ function readReleaseCatchupState(path2) {
|
|
|
43218
43346
|
}
|
|
43219
43347
|
function writeReleaseCatchupState(path2, state) {
|
|
43220
43348
|
try {
|
|
43221
|
-
(0,
|
|
43222
|
-
(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)}
|
|
43223
43351
|
`);
|
|
43224
43352
|
} catch {
|
|
43225
43353
|
}
|