@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.
Files changed (2) hide show
  1. package/dist/main.cjs +517 -389
  2. 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 = 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 createReadStream(path2, options) {
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, stat3) => {
1242
+ return fs2.stat(file, (err, stat4) => {
1243
1243
  if (err) {
1244
1244
  return callback(err);
1245
1245
  }
1246
- callback(null, stat3.mtime, cachedPrecision);
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, stat3) => {
1254
+ fs2.stat(file, (err2, stat4) => {
1255
1255
  if (err2) {
1256
1256
  return callback(err2);
1257
1257
  }
1258
- const precision = stat3.mtime.getTime() % 1e3 === 0 ? "s" : "ms";
1258
+ const precision = stat4.mtime.getTime() % 1e3 === 0 ? "s" : "ms";
1259
1259
  Object.defineProperty(fs2, cacheSymbol, { value: precision });
1260
- callback(null, stat3.mtime, precision);
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, stat3) => {
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(stat3, options)) {
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(stat3, options) {
1334
- return stat3.mtime.getTime() < Date.now() - options.stale;
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, stat3) => {
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() === stat3.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, stat3) => {
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(stat3, options));
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((resolve5, reject) => {
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
- resolve5(result);
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 import_promises11 = require("node:fs/promises");
5003
- var import_node_fs47 = require("node:fs");
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((resolve5) => {
5115
+ return new Promise((resolve6) => {
5116
5116
  try {
5117
- stream.write("", () => resolve5());
5117
+ stream.write("", () => resolve6());
5118
5118
  } catch {
5119
- resolve5();
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((resolve5) => {
5127
- setTimeout(resolve5, timeoutMs).unref?.();
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((resolve5) => setImmediate(resolve5));
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((resolve5) => setTimeout(resolve5, ms)));
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 stat3 = statFd();
5650
- if (stat3.isFIFO() || stat3.isFile()) return true;
5651
- if (stat3.isCharacterDevice()) return false;
5652
- if (stat3.isSocket()) return false;
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((resolve5) => {
5684
- timer = setTimeout(resolve5, timeoutMs);
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((resolve5, reject) => {
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 resolve5({ stdout: String(stdout), stderr: String(stderr) });
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, stat3) {
6237
+ function rootScratchDirSnapshot(root, readdir2, stat4) {
6238
6238
  try {
6239
- const rootStat = stat3(root);
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 = stat3(child2);
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 stat3 = deps.stat ?? import_node_fs6.statSync;
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, stat3);
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 = stat3(full);
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 = stat3(full);
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((resolve5) => setTimeout(resolve5, ms));
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((resolve5) => setTimeout(resolve5, ms));
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 import_node_path44 = require("node:path");
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((resolve5) => setTimeout(resolve5, ms)));
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((resolve5) => {
15140
- setTimeout(() => resolve5(false), PRE_SPAWN_DRAIN_TIMEOUT_MS).unref?.();
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.125.0",
15844
- tag: "v3.125.0",
15845
- commit: "2ffc8e9b6dc8",
15846
- npm: "@mutmutco/cli@3.125.0"
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.125.0"
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.125.0 and redeploy the Hub Lambda from tag v3.125.0 (2ffc8e9b6dc8); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
15870
- v3Target: "v3.125.0 (@mutmutco/cli@3.125.0, tag commit 2ffc8e9b6dc8 \u2014 the preserved latest-v3 distribution, D6b)"
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, resolve5, extraTolerated = []) {
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", `--${resolve5}`, "--", ...unmerged]);
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((resolve5) => setTimeout(resolve5, ms));
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((resolve5) => setTimeout(resolve5, ms)));
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((resolve5) => setTimeout(resolve5, ms)));
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((resolve5) => setTimeout(resolve5, ms)));
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((resolve5, reject) => {
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(resolve5), graceMs);
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((resolve5) => {
21795
+ return new Promise((resolve6) => {
21776
21796
  const srv = (0, import_node_net.createServer)();
21777
- srv.once("error", () => resolve5(false));
21778
- srv.once("listening", () => srv.close(() => resolve5(true)));
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((resolve5) => setTimeout(resolve5, 500));
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((resolve5) => setTimeout(resolve5, healthPollIntervalMs()));
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((resolve5) => setTimeout(resolve5, ms));
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, path2) {
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(path2);
24684
+ const house = houseForPath(flatPath);
24665
24685
  if (!house) {
24666
24686
  throw new Error(
24667
- `command-manifest: command '${path2}' 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).`
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: path2,
24694
+ path: canonical,
24695
+ flat_path: flatPath,
24674
24696
  ...aliases.length ? { aliases: [...aliases] } : {},
24675
24697
  house,
24676
- canonical: canonicalPathFor(path2) ?? path2,
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, path2 ? `${path2} ${child2.name()}` : child2.name())
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 (path2 && house !== "core") out.flat_removed = true;
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.path, canonical: node.canonical };
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((resolve5) => setTimeout(resolve5, ms)));
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 import_node_crypto4 = require("node:crypto");
27048
+ var import_node_crypto5 = require("node:crypto");
26976
27049
  var import_node_child_process13 = require("node:child_process");
26977
- var import_node_fs28 = require("node:fs");
26978
- var import_node_path26 = require("node:path");
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, import_node_path26.join)(cwd, ...rel.split("/"));
27104
- if (!(0, import_node_fs28.existsSync)(abs)) continue;
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, import_node_fs28.readFileSync)(abs, "utf8");
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(import_node_path26.sep).join("/");
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, import_node_path26.join)(cwd, ...rel.split("/"));
27143
- if (!(0, import_node_fs28.existsSync)(abs)) continue;
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, import_node_fs28.readFileSync)(abs, "utf8");
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, import_node_crypto4.createHash)("sha256").update(text).digest("hex").slice(0, 16);
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, import_node_fs28.mkdirSync)((0, import_node_path26.dirname)(store), { recursive: true });
27172
- (0, import_node_fs28.writeFileSync)(store, `${JSON.stringify(projection, null, 2)}
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, import_node_fs28.existsSync)(store)) return null;
27251
+ if (!(0, import_node_fs29.existsSync)(store)) return null;
27179
27252
  try {
27180
- const raw = JSON.parse((0, import_node_fs28.readFileSync)(store, "utf8"));
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, import_node_path26.basename)(cwd) || "local").toLowerCase();
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 import_node_fs29 = require("node:fs");
27465
+ var import_node_fs30 = require("node:fs");
27393
27466
  var import_node_os12 = require("node:os");
27394
- var import_node_path27 = require("node:path");
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, import_node_fs29.mkdtempSync)((0, import_node_path27.join)((0, import_node_os12.tmpdir)(), "mmi-repo-index-"));
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, import_node_fs29.rmSync)(dir, { recursive: true, force: true });
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 import_node_fs30 = require("node:fs");
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, import_node_fs30.readFileSync)(path2, "utf8");
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 import_node_fs31 = require("node:fs");
27694
- var import_node_path28 = require("node:path");
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, import_node_fs31.readFileSync)((0, import_node_path28.join)(root, file), "utf8");
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 import_node_fs32 = require("node:fs");
27799
- var import_node_path29 = require("node:path");
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, import_node_path29.join)(root, POLICY_FILE));
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, import_node_fs32.readFileSync)(path2, "utf8");
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, import_node_fs32.existsSync)(path2)) {
27890
- return (policy.protected ?? []).map((p) => p.path).filter((p) => !exists((0, import_node_path29.join)(root, p)));
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, import_node_fs32.existsSync)(path2)) {
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, import_node_path29.join)(root, p)));
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, import_node_fs32.existsSync)(path2));
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, import_node_path29.join)(root, path2));
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 import_node_fs33 = require("node:fs");
28121
- var import_node_path30 = require("node:path");
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, import_node_path30.join)(repoRoot2, "README.md");
28167
- if (!(0, import_node_fs33.existsSync)(readmePath)) throw new Error(`org project sync-info: ${targetRepo2} has no README.md`);
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, import_node_fs33.readFileSync)(readmePath, "utf8")) : `Shared work across ${new Intl.ListFormat("en", { type: "conjunction" }).format(entryNames)}.`;
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, import_node_fs33.existsSync)((0, import_node_path30.join)(repoRoot2, "docs", "org-readme.md")) ? `- [Org identity](${targetBase}/blob/${targetBranch}/docs/org-readme.md)` : "",
28193
- (0, import_node_fs33.existsSync)((0, import_node_path30.join)(repoRoot2, "docs", "org-architecture.md")) ? `- [Org architecture](${targetBase}/blob/${targetBranch}/docs/org-architecture.md)` : ""
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 import_node_fs34 = require("node:fs");
28979
- var import_node_path31 = require("node:path");
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, import_node_path31.resolve)(input.appDir ?? process.cwd());
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, import_node_path31.resolve)(appDir, credentialsFile);
29086
- const masterKeyPath = (0, import_node_path31.resolve)(appDir, masterKeyFile);
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, import_node_fs34.existsSync)(masterKeyPath)) {
29093
- env.RAILS_MASTER_KEY = (0, import_node_fs34.readFileSync)(masterKeyPath, "utf8").trim();
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, import_node_fs34.mkdtempSync)((0, import_node_path31.join)((0, import_node_os13.tmpdir)(), "mmi-rails-decrypt-"));
29104
- const scriptPath = (0, import_node_path31.join)(scriptDir, "decrypt.rb");
29105
- (0, import_node_fs34.writeFileSync)(scriptPath, script, "utf8");
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, import_node_fs34.rmSync)(scriptDir, { recursive: true, force: true });
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, import_node_fs34.readFileSync)((0, import_node_path31.resolve)(o.file), "utf8");
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, import_node_fs34.unlinkSync)((0, import_node_path31.resolve)(o.appDir ?? process.cwd(), path2))
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 import_node_crypto5 = require("node:crypto");
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, import_node_crypto5.createSign)("RSA-SHA256");
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 import_node_fs35 = require("node:fs");
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, stat3, key) => `${name.padEnd(nameW)} ${addr.padEnd(addrW)} ${proj.padEnd(projW)} ${stat3.padEnd(statW)} ${key}`;
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, import_node_fs35.writeFileSync)(o.script, sshRecipeScript(found), "utf8");
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 import_promises5 = require("node:fs/promises");
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((resolve5) => setTimeout(resolve5, AWS_RETRY_DELAY_MS));
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, import_promises5.readFile)(o.doc, "utf8");
30064
+ const docText = await (0, import_promises6.readFile)(o.doc, "utf8");
29951
30065
  const spliced = spliceDoc(docText, renderDocSection(entries, now.toISOString()));
29952
- await (0, import_promises5.writeFile)(o.doc, spliced, "utf8");
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 import_promises6 = require("node:fs/promises");
30039
- var import_node_path32 = require("node:path");
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, import_promises6.readdir)(dir);
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, import_promises6.readFile)((0, import_node_path32.join)(dir, name), "utf8") });
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 import_node_fs36 = require("node:fs");
30328
+ var import_node_fs37 = require("node:fs");
30215
30329
  var import_node_os14 = require("node:os");
30216
- var import_node_path33 = require("node:path");
30330
+ var import_node_path34 = require("node:path");
30217
30331
 
30218
30332
  // src/bootstrap-drift.ts
30219
- var import_node_crypto6 = require("node:crypto");
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, import_node_crypto6.createHash)("sha256").update(content.replace(/\r\n/g, "\n"), "utf8").digest("hex");
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, import_node_fs36.existsSync)(path2) ? (0, import_node_fs36.readFileSync)(path2, "utf8") : null,
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, import_node_fs36.existsSync)("access-matrix.json") ? entriesValueByCanonicalRepo(loadSanctionedAdmins((0, import_node_fs36.readFileSync)("access-matrix.json", "utf8")), repo) : void 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, import_node_fs36.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`);
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, import_node_fs36.readFileSync)(manifestPath, "utf8"));
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, import_node_fs36.existsSync)(s.target) ? (0, import_node_fs36.readFileSync)(s.target, "utf8") : null);
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, import_node_fs36.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`);
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, import_node_fs36.readFileSync)(manifestPath, "utf8"));
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, import_node_fs36.existsSync)(p) ? (0, import_node_fs36.readFileSync)(p, "utf8") : null;
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, import_node_path33.join)((0, import_node_os14.tmpdir)(), `mmi-seed-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
31259
- (0, import_node_fs36.writeFileSync)(tmp, JSON.stringify(contentPutBody(target, content, ref, sha)), "utf8");
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, import_node_fs36.unlinkSync)(tmp);
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, import_node_fs36.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`);
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, import_node_fs36.readFileSync)(manifestPath, "utf8"));
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, import_node_fs36.existsSync)(seed.target)) return fail(`bootstrap propagate: the Hub's own copy of '${seed.target}' is missing \u2014 nothing to propagate`);
31542
- const hubContent = (0, import_node_fs36.readFileSync)(seed.target, "utf8");
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, import_node_fs36.existsSync)("projects.json")) {
31665
+ if ((0, import_node_fs37.existsSync)("projects.json")) {
31552
31666
  try {
31553
- const local = JSON.parse((0, import_node_fs36.readFileSync)("projects.json", "utf8"));
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, import_node_path33.join)((0, import_node_os14.tmpdir)(), `mmi-propagate-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
31670
- (0, import_node_fs36.writeFileSync)(tmp, JSON.stringify(contentPutBody(seed.target, hubContent, branch, existingSha)), "utf8");
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, import_node_fs36.unlinkSync)(tmp);
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, import_node_fs36.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)`);
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, import_node_fs36.readFileSync)(manifestPath, "utf8"));
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, import_node_fs36.existsSync)(o.record)) return fail(`bootstrap rollback: --record '${o.record}' not found`);
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, import_node_fs36.readFileSync)(o.record, "utf8"));
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, import_node_path33.join)((0, import_node_os14.tmpdir)(), `mmi-rollback-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
31826
- (0, import_node_fs36.writeFileSync)(tmp, JSON.stringify(contentPutBody(seed.target, preSeedContent, plan.branch, existingSha)), "utf8");
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, import_node_fs36.unlinkSync)(tmp);
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 import_node_fs38 = require("node:fs");
31854
- var import_node_path35 = require("node:path");
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 import_node_fs37 = require("node:fs");
31858
- var import_node_path34 = require("node:path");
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, import_node_fs37.existsSync)(path2)) return {};
31873
- const raw = JSON.parse((0, import_node_fs37.readFileSync)(path2, "utf8"));
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, import_node_fs37.existsSync)(path2) ? JSON.parse((0, import_node_fs37.readFileSync)(path2, "utf8")) : {};
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, import_node_fs37.writeFileSync)(path2, JSON.stringify(raw, null, 2) + "\n", "utf8");
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, import_node_path34.join)(root, "infra", "port-ranges.json");
31912
- const ddbScriptPath = (0, import_node_path34.join)(root, "infra", "port-ddb.mjs");
31913
- if (!(0, import_node_fs37.existsSync)(registryPath) || !(0, import_node_fs37.existsSync)(ddbScriptPath)) return null;
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, import_node_path34.dirname)(dir)) {
31920
- const sibling = portRangeInfraAt((0, import_node_path34.join)(dir, "MMI-Hub"), "sibling-hub");
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, import_node_path34.dirname)(dir);
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, import_node_path34.join)(packageDir, "..", "..");
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, import_node_fs38.existsSync)((0, import_node_path35.join)(process.cwd(), "docker-compose.yml")),
32121
- hasEnvExample: (0, import_node_fs38.existsSync)((0, import_node_path35.join)(process.cwd(), ".env.example"))
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 import_node_fs39 = require("node:fs");
32614
- var import_promises8 = require("node:fs/promises");
32615
- var import_node_path37 = require("node:path");
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 import_promises7 = require("node:fs/promises");
32703
- var import_node_path36 = require("node:path");
32704
- var sleep2 = (ms) => new Promise((resolve5) => setTimeout(resolve5, ms));
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, import_promises7.writeFile)(tmp, contents, "utf8");
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, import_promises7.unlink)(tmp).catch(() => void 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, import_promises7.rename)(from, to);
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, import_promises7.readFile)(registryPath, "utf8");
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, import_promises7.readFile)(registryPath, "utf8"));
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, import_promises7.mkdir)((0, import_node_path36.dirname)(registryPath), { recursive: true });
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, import_promises7.mkdir)((0, import_node_path36.dirname)(registryPath), { recursive: true });
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, import_node_path37.dirname)((0, import_node_path37.dirname)(worktreeGitRoot)) : repoRoot2;
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, import_node_fs39.existsSync)(p),
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, import_node_fs39.realpathSync)(path2)
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, import_node_fs39.mkdtempSync)((0, import_node_path37.join)((0, import_node_os15.tmpdir)(), "mmi-squash-body-"));
33113
- const path2 = (0, import_node_path37.join)(dir, "body.txt");
33114
- (0, import_node_fs39.writeFileSync)(path2, `${body}
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, import_node_fs39.rmSync)(dir, { recursive: true, force: true });
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, import_node_fs39.lstatSync)(p);
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, import_node_fs39.readlinkSync)(p);
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, import_node_fs39.readdirSync)(p);
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, import_node_fs39.rmdirSync)(p);
33377
+ (0, import_node_fs40.rmdirSync)(p);
33264
33378
  } catch {
33265
- (0, import_node_fs39.unlinkSync)(p);
33379
+ (0, import_node_fs40.unlinkSync)(p);
33266
33380
  }
33267
33381
  },
33268
- removeTree: (p) => (0, import_promises8.rm)(p, { recursive: true, force: true, maxRetries: 5, retryDelay: 200 })
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((resolve5) => setTimeout(resolve5, ms)),
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, import_node_fs39.existsSync)(worktreePath)
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, import_node_fs39.existsSync)(statePath)) return false;
33414
+ if (!(0, import_node_fs40.existsSync)(statePath)) return false;
33301
33415
  try {
33302
- const state = JSON.parse((0, import_node_fs39.readFileSync)(statePath, "utf8"));
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((resolve5) => setTimeout(resolve5, ms)));
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 import_node_fs41 = require("node:fs");
33738
- var import_promises9 = require("node:fs/promises");
33739
- var import_node_path39 = require("node:path");
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 import_node_crypto7 = require("node:crypto");
33743
- var import_node_fs40 = require("node:fs");
33744
- var import_node_path38 = require("node:path");
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: import_node_fs40.existsSync,
33758
- readFile: (path2) => (0, import_node_fs40.readFileSync)(path2, "utf8"),
33759
- lstat: (path2) => (0, import_node_fs40.lstatSync)(path2),
33760
- copyDir: (from, to) => (0, import_node_fs40.cpSync)(from, to, { recursive: true, force: true }),
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, import_node_fs40.mkdirSync)(path2, { recursive: true });
33876
+ (0, import_node_fs41.mkdirSync)(path2, { recursive: true });
33763
33877
  },
33764
- writeFile: (path2, contents) => (0, import_node_fs40.writeFileSync)(path2, contents, "utf8"),
33878
+ writeFile: (path2, contents) => (0, import_node_fs41.writeFileSync)(path2, contents, "utf8"),
33765
33879
  rm: (path2) => {
33766
- (0, import_node_fs40.rmSync)(path2, { recursive: true, force: true });
33880
+ (0, import_node_fs41.rmSync)(path2, { recursive: true, force: true });
33767
33881
  }
33768
33882
  };
33769
33883
  function hashLockfileBytes(contents) {
33770
- return (0, import_node_crypto7.createHash)("sha256").update(contents).digest("hex");
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, import_node_path38.join)(packageDir, name);
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, import_node_path38.join)(root, MANIFEST),
33790
- nodeModulesPath: (0, import_node_path38.join)(root, NODE_MODULES2)
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, import_node_path38.join)(packageDir, NODE_MODULES2);
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, import_node_path38.join)(destPackageDir, NODE_MODULES2);
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, import_node_path38.join)(sourcePackageDir, NODE_MODULES2);
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, import_node_fs41.readdirSync)(root, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => (0, import_node_path39.join)(root, e.name));
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, import_node_path39.join)(wtPath, ".git");
34280
- const isLinked = (0, import_node_fs41.existsSync)(gitFile) && (0, import_node_fs41.statSync)(gitFile).isFile();
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, import_node_path39.dirname)(commonDir) : wtPath;
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, import_promises9.readFile)(p, "utf8") });
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, import_promises9.readFile)(p, "utf8") },
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, import_node_path39.dirname)((0, import_node_path39.dirname)(worktreeGitRoot)) : repoRoot2;
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, import_node_fs41.existsSync)(wtRoot)) {
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 import_node_fs42 = require("node:fs");
34599
- var import_node_crypto8 = require("node:crypto");
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, import_node_fs42.readFileSync)(p, e)), readStdin: () => Promise.resolve("") };
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, import_node_crypto8.createHash)("sha256").update(identity).digest("hex").slice(0, 16);
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, import_node_fs42.readFileSync)(opts.batch, "utf8");
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 import_node_fs43 = require("node:fs");
35297
- var import_node_path40 = require("node:path");
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, import_node_fs43.readFileSync)((0, import_node_path40.join)(process.cwd(), ".claude-plugin", "plugin.json"), "utf8")).version || void 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 import_node_fs44 = require("node:fs");
35579
+ var import_node_fs45 = require("node:fs");
35466
35580
  var import_node_os16 = require("node:os");
35467
- var import_node_path41 = require("node:path");
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, import_node_path41.join)(home, ...KNOWN_MARKETPLACES_RELATIVE), import_node_fs44.readFileSync),
35658
- readSettings: () => readFileSyncSafe((0, import_node_path41.join)(home, ".claude", "settings.json"), import_node_fs44.readFileSync)
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) => canonicalPathFor(node.path) ?? node.path;
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 || canonicalPathFor(command.path) === commandPath3) return command;
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 import_promises10 = require("node:fs/promises");
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: import_promises10.readFile, readStdin });
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: import_promises10.readFile, readStdin });
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: import_promises10.readFile, readStdin });
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 import_node_fs45 = require("node:fs");
36794
- var import_node_path42 = require("node:path");
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, import_node_path42.join)((0, import_node_os17.homedir)(), "AppData", "Local");
36802
- return (0, import_node_path42.join)(base2, "MMI Future", "mmi-cli", "release-catchup.json");
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, import_node_path42.join)((0, import_node_os17.homedir)(), ".local", "state");
36805
- return (0, import_node_path42.join)(base, "mmi-cli", "release-catchup.json");
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, import_node_fs45.readdirSync)(pluginCacheRoot(home));
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, import_node_fs45.readFileSync)((0, import_node_path42.join)(home, ".claude", "plugins", "known_marketplaces.json"), "utf8"));
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, import_node_path42.join)(home, ".claude", "plugins", "marketplaces", "mutmutco");
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, import_node_fs45.readFileSync)((0, import_node_path42.join)(marketplaceClonePath(home), ".claude-plugin", "marketplace.json"), "utf8"));
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, import_node_fs45.readFileSync)((0, import_node_path42.join)(home, ".claude", "plugins", "installed_plugins.json"), "utf8"));
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, import_node_fs45.existsSync)(pluginCacheRoot(home))) {
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, import_node_path42.join)(pluginCacheRoot(home), latest, ".pi-plugin");
36902
- if (!installed || !(0, import_node_fs45.existsSync)(payload)) {
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 import_node_fs46 = require("node:fs");
39301
+ var import_node_fs47 = require("node:fs");
39186
39302
  var import_node_os18 = require("node:os");
39187
- var import_node_path43 = require("node:path");
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, import_node_fs46.readFileSync)((0, import_node_path43.join)((0, import_node_os18.homedir)(), ".claude", "plugins", "installed_plugins.json"), "utf8")
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, import_node_fs46.readFileSync)(path2, "utf8"));
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, import_node_fs46.readFileSync)((0, import_node_path43.join)((0, import_node_os18.homedir)(), ".kilo", ".mmi-kilo-version"), "utf8").trim();
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, import_node_path43.join)(cursorLocalPluginRoot(), ".cursor-plugin", "plugin.json"));
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, import_node_path43.join)(decodeURIComponent(entry.replace(/^file:\/\/\/?/, "")), "package.json"));
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, import_node_path43.join)(surfaceConfigRoot(surface), "plugins", "managed", "mmi", ".kimi-plugin", "plugin.json"));
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, import_node_path43.join)(root, ".gitignore");
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, import_node_fs46.readFileSync)(path2, "utf8");
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, import_node_fs46.writeFileSync)(path2, content, "utf8");
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, import_node_fs46.existsSync)((0, import_node_path43.join)(root, ".worktrees"));
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, import_node_fs47.existsSync)((0, import_node_path44.join)(dir, `${bin}${ext}`))) return true;
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, import_node_fs47.existsSync)(hostsPath)) return void 0;
39422
- return ghAccountCaveat(announcedLogin, parseGhHostsAccounts((0, import_node_fs47.readFileSync)(hostsPath, "utf8")));
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, import_node_path44.join)(home, ".claude", "plugins", ".mmi-env-heal.lock");
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, import_node_fs47.rmSync)(p, { recursive: true }),
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, import_node_path44.join)((0, import_node_os19.homedir)(), ...KNOWN_MARKETPLACES_RELATIVE),
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, import_node_fs47.existsSync)((0, import_node_path44.join)(root, DOCS_INDEX_PATH))) return void 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, import_node_fs47.existsSync)((0, import_node_path44.join)(root, DOCS_INDEX_PATH))) return { drift: false, docCount: 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((resolve5) => {
39697
- ceiling = setTimeout(() => resolve5({ timedOut: true, scanned: 0, findings: 0, fixed: 0, failed: 0 }), BOARD_DOCTOR_TIMEOUT_MS);
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((resolve5) => {
39731
- ceiling = setTimeout(() => resolve5({ driftLines: [], incomplete: [], timedOut: true }), SCHEDULES_DRIFT_TIMEOUT_MS);
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, import_node_path44.join)(process.cwd(), ".gitignore");
40025
- const current = (0, import_node_fs47.existsSync)(path2) ? (0, import_node_fs47.readFileSync)(path2, "utf8") : null;
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, import_node_fs47.writeFileSync)(path2, plan.content, "utf8");
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, import_node_fs47.writeFileSync)(path2, plan.content, "utf8");
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, import_node_path44.resolve)(o.root);
40196
- if (!(0, import_node_fs47.existsSync)(root) || !(0, import_node_fs47.statSync)(root).isDirectory()) return fail(`worktree gc: --root ${o.root} is not a directory`);
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((resolve5, reject) => {
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 resolve5();
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, import_node_fs47.existsSync)(wtPath)) return `${wtPath} does not exist on disk`;
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, import_node_fs47.openSync)(lockPath, "wx");
40439
+ const fd = (0, import_node_fs48.openSync)(lockPath, "wx");
40324
40440
  try {
40325
- (0, import_node_fs47.writeSync)(fd, String(Date.now()));
40441
+ (0, import_node_fs48.writeSync)(fd, String(Date.now()));
40326
40442
  } finally {
40327
- (0, import_node_fs47.closeSync)(fd);
40443
+ (0, import_node_fs48.closeSync)(fd);
40328
40444
  }
40329
40445
  return () => {
40330
40446
  try {
40331
- (0, import_node_fs47.rmSync)(lockPath, { force: true });
40447
+ (0, import_node_fs48.rmSync)(lockPath, { force: true });
40332
40448
  } catch {
40333
40449
  }
40334
40450
  };
40335
40451
  };
40336
40452
  try {
40337
- (0, import_node_fs47.mkdirSync)((0, import_node_path44.dirname)(lockPath), { recursive: true });
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, import_node_fs47.statSync)(lockPath).mtimeMs > WORKTREE_SETUP_LOCK_TTL_MS) {
40342
- (0, import_node_fs47.rmSync)(lockPath, { force: true });
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, import_node_fs47.existsSync)(wtPath);
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, import_node_fs47.existsSync)(wtPath)) return;
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((resolve5) => setTimeout(resolve5, ms)),
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
- const result = await runTenantControl(trainApplyDeps(), { repo, stage, action, watch: o.watch, lines });
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, import_node_fs47.readFileSync)(o.secretsFile, "utf8")}`);
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: import_promises11.readFile, readStdin }
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: import_promises11.readFile, readStdin });
41612
- body = await resolveIssueBody({ body: o.body, bodyFile: o.bodyFile }, { readFile: import_promises11.readFile, readStdin });
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: import_promises11.readFile, readStdin });
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: import_promises11.readFile, readStdin });
41854
- body = await resolveIssueBody({ body: o.body, bodyFile: o.bodyFile }, { readFile: import_promises11.readFile, readStdin });
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: import_promises11.readFile, readStdin });
41909
- const rawTitle = await resolveIssueTitle({ title: o.title, titleFile: o.titleFile }, { readFile: import_promises11.readFile, readStdin });
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: import_promises11.readFile, readStdin });
41969
- body = await resolveIssueBody({ body: o.body, bodyFile: o.bodyFile }, { readFile: import_promises11.readFile, readStdin });
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, import_node_path44.join)(cwd, ".github", "workflows");
42012
- if (!(0, import_node_fs47.existsSync)(wfDir)) return [];
42013
- return (0, import_node_fs47.readdirSync)(wfDir).filter((name) => /\.(ya?ml)$/i.test(name)).filter((name) => {
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, import_node_fs47.readFileSync)((0, import_node_path44.join)(wfDir, name), "utf8"));
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, import_node_path44.join)(root, path2);
42068
- return (0, import_node_fs47.existsSync)(fullPath) ? (0, import_node_fs47.readFileSync)(fullPath, "utf8") : null;
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, import_node_path44.join)(__dirname, "..", "..");
42201
+ const fromPkg = (0, import_node_path45.join)(__dirname, "..", "..");
42074
42202
  const marker = "skills/bootstrap/seeds/manifest.json";
42075
- if ((0, import_node_fs47.existsSync)((0, import_node_path44.join)(fromPkg, marker))) return fromPkg;
42076
- if ((0, import_node_fs47.existsSync)((0, import_node_path44.join)(process.cwd(), marker))) return process.cwd();
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((resolve5) => setTimeout(resolve5, ms)),
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((resolve5) => setTimeout(resolve5, ms)),
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((resolve5) => setTimeout(resolve5, PR_LAND_POLL_MS));
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((resolve5) => setTimeout(resolve5, ms)),
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, import_node_fs47.readFileSync)(bodyFile, "utf8") : void 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, import_node_fs47.existsSync)(p),
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, import_promises11.readFile)(path2, "utf8"),
42607
- removeFile: (path2) => (0, import_promises11.unlink)(path2)
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, import_promises11.readFile)(o.announceSummaryFile, "utf8"));
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, import_node_fs47.existsSync)("access-matrix.json") ? loadAccessMatrix((0, import_node_fs47.readFileSync)("access-matrix.json", "utf8")) : {};
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, import_node_fs47.existsSync)("data-access-contracts.json") ? loadDataAccessContracts((0, import_node_fs47.readFileSync)("data-access-contracts.json", "utf8")) : { consumers: {} };
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, import_node_fs47.existsSync)("access-matrix.json") ? loadSanctionedAdmins((0, import_node_fs47.readFileSync)("access-matrix.json", "utf8")) : {};
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, import_node_fs47.readdirSync)(path2, { withFileTypes: true });
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, import_node_path44.join)(path2, entry.name);
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, import_node_fs47.statSync)(child2).size;
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, import_node_fs47.readdirSync)(dir, { withFileTypes: true }).map((d) => ({ name: d.name, isDirectory: d.isDirectory() }));
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, import_node_fs47.existsSync)(p)) return [];
43276
+ if (!(0, import_node_fs48.existsSync)(p)) return [];
43149
43277
  try {
43150
- return installedPluginPaths((0, import_node_fs47.readFileSync)(p, "utf8"));
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, import_node_fs47.existsSync)(p),
43158
- listVersionDirs: (root) => (0, import_node_fs47.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name),
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, import_node_fs47.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => {
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, import_node_path44.join)(root, d.name), listDirEntries, (p) => (0, import_node_fs47.statSync)(p).mtimeMs) };
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, import_node_path44.join)(stagingRoot, name);
43177
- if (!(0, import_node_fs47.existsSync)(p)) return null;
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, import_node_fs47.statSync)(q).mtimeMs);
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, import_node_fs47.rmSync)(p, { recursive: true, force: true }), stagingApplyFsGuard(configRoot)) : void 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, import_node_fs47.readFileSync)(path2, "utf8"));
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, import_node_fs47.mkdirSync)((0, import_node_path44.dirname)(path2), { recursive: true });
43222
- (0, import_node_fs47.writeFileSync)(path2, `${JSON.stringify(state)}
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
  }