@mutmutco/cli 3.126.0 → 3.127.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/main.cjs +513 -387
  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.126.0",
15844
- tag: "v3.126.0",
15845
- commit: "1ccba0834c2a",
15846
- npm: "@mutmutco/cli@3.126.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.126.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.126.0 and redeploy the Hub Lambda from tag v3.126.0 (1ccba0834c2a); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
15870
- v3Target: "v3.126.0 (@mutmutco/cli@3.126.0, tag commit 1ccba0834c2a \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);
@@ -39184,9 +39298,9 @@ function ghAccountCaveat(announcedLogin, accounts) {
39184
39298
  }
39185
39299
 
39186
39300
  // src/doctor-io.ts
39187
- var import_node_fs46 = require("node:fs");
39301
+ var import_node_fs47 = require("node:fs");
39188
39302
  var import_node_os18 = require("node:os");
39189
- var import_node_path43 = require("node:path");
39303
+ var import_node_path44 = require("node:path");
39190
39304
  var import_node_child_process19 = require("node:child_process");
39191
39305
  var import_node_util8 = require("node:util");
39192
39306
  var execFileP6 = (0, import_node_util8.promisify)(import_node_child_process19.execFile);
@@ -39194,7 +39308,7 @@ var MMI_PLUGIN_ID2 = "mmi@mutmutco";
39194
39308
  function installedClaudePluginVersion() {
39195
39309
  try {
39196
39310
  const file = JSON.parse(
39197
- (0, 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")
39198
39312
  );
39199
39313
  const versions = (file.plugins?.[MMI_PLUGIN_ID2] ?? []).map((r) => r.version).filter((v) => Boolean(v));
39200
39314
  if (versions.length === 0) return void 0;
@@ -39205,7 +39319,7 @@ function installedClaudePluginVersion() {
39205
39319
  }
39206
39320
  function manifestVersion(path2) {
39207
39321
  try {
39208
- const manifest = JSON.parse((0, import_node_fs46.readFileSync)(path2, "utf8"));
39322
+ const manifest = JSON.parse((0, import_node_fs47.readFileSync)(path2, "utf8"));
39209
39323
  return typeof manifest.version === "string" && manifest.version.trim() ? manifest.version.trim() : void 0;
39210
39324
  } catch {
39211
39325
  return void 0;
@@ -39215,22 +39329,22 @@ function installedSurfacePluginVersion(surface) {
39215
39329
  const token = surfaceToken(surface);
39216
39330
  if (token === "kilo") {
39217
39331
  try {
39218
- const stamp = (0, 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();
39219
39333
  return stamp || void 0;
39220
39334
  } catch {
39221
39335
  return void 0;
39222
39336
  }
39223
39337
  }
39224
39338
  if (token === "cursor") {
39225
- return manifestVersion((0, import_node_path43.join)(cursorLocalPluginRoot(), ".cursor-plugin", "plugin.json"));
39339
+ return manifestVersion((0, import_node_path44.join)(cursorLocalPluginRoot(), ".cursor-plugin", "plugin.json"));
39226
39340
  }
39227
39341
  if (token === "jervcode") {
39228
39342
  const entry = mmiPiWrapperEntry();
39229
39343
  if (!entry) return void 0;
39230
- return manifestVersion((0, import_node_path43.join)(decodeURIComponent(entry.replace(/^file:\/\/\/?/, "")), "package.json"));
39344
+ return manifestVersion((0, import_node_path44.join)(decodeURIComponent(entry.replace(/^file:\/\/\/?/, "")), "package.json"));
39231
39345
  }
39232
39346
  if (token === "kimi") {
39233
- return manifestVersion((0, 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"));
39234
39348
  }
39235
39349
  if (token === "claude") return installedClaudePluginVersion();
39236
39350
  if (token !== "codex") return void 0;
@@ -39268,13 +39382,13 @@ function worktreeRootSync() {
39268
39382
  }
39269
39383
  var gitignorePath = () => {
39270
39384
  const root = worktreeRootSync();
39271
- return root === null ? null : (0, import_node_path43.join)(root, ".gitignore");
39385
+ return root === null ? null : (0, import_node_path44.join)(root, ".gitignore");
39272
39386
  };
39273
39387
  function readGitignore() {
39274
39388
  const path2 = gitignorePath();
39275
39389
  if (path2 === null) return null;
39276
39390
  try {
39277
- return (0, import_node_fs46.readFileSync)(path2, "utf8");
39391
+ return (0, import_node_fs47.readFileSync)(path2, "utf8");
39278
39392
  } catch {
39279
39393
  return null;
39280
39394
  }
@@ -39283,7 +39397,7 @@ function writeGitignore(content) {
39283
39397
  const path2 = gitignorePath();
39284
39398
  if (path2 === null) return false;
39285
39399
  try {
39286
- (0, import_node_fs46.writeFileSync)(path2, content, "utf8");
39400
+ (0, import_node_fs47.writeFileSync)(path2, content, "utf8");
39287
39401
  return true;
39288
39402
  } catch {
39289
39403
  return false;
@@ -39302,7 +39416,7 @@ async function repoRoot() {
39302
39416
  }
39303
39417
  function hasRepoLocalWorktrees() {
39304
39418
  const root = worktreeRootSync();
39305
- return root !== null && (0, 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"));
39306
39420
  }
39307
39421
 
39308
39422
  // src/cross-repo-filing-issue.ts
@@ -39398,7 +39512,7 @@ function binaryOnPath(bin) {
39398
39512
  for (const dir of pathEnvEntries(process.env.PATH ?? "")) {
39399
39513
  for (const ext of exts) {
39400
39514
  try {
39401
- if ((0, 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;
39402
39516
  } catch {
39403
39517
  }
39404
39518
  }
@@ -39420,8 +39534,8 @@ ${r.stderr ?? ""}`).catch(() => "");
39420
39534
  function ghMultiAccountCaveat(announcedLogin) {
39421
39535
  try {
39422
39536
  const hostsPath = ghHostsConfigPath(process.env, process.platform);
39423
- if (!hostsPath || !(0, import_node_fs47.existsSync)(hostsPath)) return void 0;
39424
- 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")));
39425
39539
  } catch {
39426
39540
  return void 0;
39427
39541
  }
@@ -39429,7 +39543,7 @@ function ghMultiAccountCaveat(announcedLogin) {
39429
39543
  var ENV_HEAL_LOCK_STALE_MS = 10 * 6e4;
39430
39544
  var ENV_HEAL_LOCK_MAX_WAIT_MS = 2 * 6e4;
39431
39545
  function envHealLockPath(home) {
39432
- return (0, 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");
39433
39547
  }
39434
39548
  async function withEnvHealLock(what, run) {
39435
39549
  try {
@@ -39562,7 +39676,7 @@ function mmiDoctorDeps(opts = {}) {
39562
39676
  );
39563
39677
  const result = applyPluginCachePlan(
39564
39678
  plan,
39565
- (p) => (0, import_node_fs47.rmSync)(p, { recursive: true }),
39679
+ (p) => (0, import_node_fs48.rmSync)(p, { recursive: true }),
39566
39680
  stagingApplyFsGuard(configRoot)
39567
39681
  );
39568
39682
  return {
@@ -39634,7 +39748,7 @@ function mmiDoctorDeps(opts = {}) {
39634
39748
  disableAutoUpdate: () => {
39635
39749
  if (detectSurface(process.env) === "codex") return void 0;
39636
39750
  return disableOrgMarketplaceBackgroundUpdates(
39637
- (0, 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),
39638
39752
  [MMI_MARKETPLACE_NAME]
39639
39753
  );
39640
39754
  }
@@ -39648,7 +39762,7 @@ function mmiDoctorDeps(opts = {}) {
39648
39762
  // adopted the generated routing index (MMG-Unlive: `docs/Archive/**` only, no index, no gate.yml) would
39649
39763
  // get a permanent — demanding an artifact it never asked for.
39650
39764
  docsIndexState: (root) => {
39651
- if (!(0, 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;
39652
39766
  const real = createDocsIndexDeps(root);
39653
39767
  let docs2;
39654
39768
  const listDocs = () => docs2 ??= real.listDocs();
@@ -39657,7 +39771,7 @@ function mmiDoctorDeps(opts = {}) {
39657
39771
  },
39658
39772
  // #4168: working-tree heal — write if drifted, then re-check. Commit remains the operator's step.
39659
39773
  healDocsIndex: (root) => {
39660
- if (!(0, 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 };
39661
39775
  const real = createDocsIndexDeps(root);
39662
39776
  let docs2;
39663
39777
  const listDocs = () => docs2 ??= real.listDocs();
@@ -39695,8 +39809,8 @@ function mmiDoctorDeps(opts = {}) {
39695
39809
  });
39696
39810
  const raced = await Promise.race([
39697
39811
  work.then((r) => ({ ...r, timedOut: false })),
39698
- new Promise((resolve5) => {
39699
- 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);
39700
39814
  })
39701
39815
  ]);
39702
39816
  if (raced.timedOut) return { scanned: 0, findings: 0, fixed: 0, failed: 0, timedOut: true };
@@ -39729,8 +39843,8 @@ function mmiDoctorDeps(opts = {}) {
39729
39843
  incomplete: nb.incomplete,
39730
39844
  timedOut: false
39731
39845
  })),
39732
- new Promise((resolve5) => {
39733
- 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);
39734
39848
  })
39735
39849
  ]);
39736
39850
  if (!raced.timedOut && raced.incomplete.length === 0) writeSchedulesDriftCache(cachePath, raced.driftLines);
@@ -40023,19 +40137,19 @@ program2.hook("preAction", async (_thisCommand, actionCommand) => {
40023
40137
  });
40024
40138
  var rules = program2.command("rules").description("org-managed .gitignore delivery");
40025
40139
  rules.command("gitignore").option("--write", "upsert the managed block into .gitignore (default: check only, non-zero exit on drift)").option("--json", "machine-readable output").description("verify (or --write) this repo's org-managed .gitignore block matches the SSOT").action((opts) => {
40026
- const path2 = (0, import_node_path44.join)(process.cwd(), ".gitignore");
40027
- 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;
40028
40142
  const plan = planManagedGitignore(current);
40029
40143
  const drift = [...plan.added.map((l) => `+${l}`), ...plan.removed.map((l) => `-${l}`)].join(", ") || "block normalize";
40030
40144
  if (opts.json) {
40031
- if (opts.write && plan.changed) (0, import_node_fs47.writeFileSync)(path2, plan.content, "utf8");
40145
+ if (opts.write && plan.changed) (0, import_node_fs48.writeFileSync)(path2, plan.content, "utf8");
40032
40146
  console.log(JSON.stringify(plan, null, 2));
40033
40147
  if (!opts.write && plan.changed) process.exitCode = 1;
40034
40148
  return;
40035
40149
  }
40036
40150
  if (opts.write) {
40037
40151
  if (plan.changed) {
40038
- (0, import_node_fs47.writeFileSync)(path2, plan.content, "utf8");
40152
+ (0, import_node_fs48.writeFileSync)(path2, plan.content, "utf8");
40039
40153
  console.log(`mmi-cli devops org rules gitignore: updated .gitignore (${drift})`);
40040
40154
  } else {
40041
40155
  console.log("mmi-cli devops org rules gitignore: up to date");
@@ -40194,8 +40308,8 @@ gcCmd.option("--dry-run", "show what would be deleted (default)").option("--appl
40194
40308
  if (!Number.isFinite(limit) || limit < 1) return fail("worktree gc: --limit must be a positive integer");
40195
40309
  let root;
40196
40310
  if (o.root !== void 0) {
40197
- root = (0, import_node_path44.resolve)(o.root);
40198
- 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`);
40199
40313
  const gcRepoRoot = (await execFileP2("git", ["rev-parse", "--show-toplevel"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim() || process.cwd();
40200
40314
  if (isPathUnderDirectory2(gcRepoRoot, root)) {
40201
40315
  return fail(`worktree gc: --root ${root} contains this checkout \u2014 name a worktrees root, not the repo or an ancestor of it`);
@@ -40243,7 +40357,7 @@ function runWorktreeInstall(command, cwd, quiet, opts) {
40243
40357
  quiet ? "ignore" : "inherit",
40244
40358
  "pipe"
40245
40359
  ];
40246
- return new Promise((resolve5, reject) => {
40360
+ return new Promise((resolve6, reject) => {
40247
40361
  const child2 = opts?.shell ? (0, import_node_child_process20.spawn)(command, { cwd, stdio, windowsHide: true, shell: true }) : (() => {
40248
40362
  const [bin, ...args] = command.split(" ");
40249
40363
  const file = isWin2 ? "cmd.exe" : bin;
@@ -40270,7 +40384,7 @@ function runWorktreeInstall(command, cwd, quiet, opts) {
40270
40384
  });
40271
40385
  child2.on("exit", (code) => {
40272
40386
  clearTimeout(timer);
40273
- if (code === 0) return resolve5();
40387
+ if (code === 0) return resolve6();
40274
40388
  const tail = stderrTail.trim();
40275
40389
  reject(new Error(`${command} exited ${code} in ${cwd}${tail ? `
40276
40390
  ${tail}` : ""}`));
@@ -40292,7 +40406,7 @@ async function currentWorktreeRemovalContext(command, force) {
40292
40406
  };
40293
40407
  }
40294
40408
  async function unprovenWorktreeReason(wtPath, repoRoot2) {
40295
- if (!(0, 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`;
40296
40410
  const porcelain = (await execFileP2("git", ["-C", repoRoot2, "worktree", "list", "--porcelain"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout;
40297
40411
  const registered = parseWorktreePorcelainEntries(porcelain);
40298
40412
  if (!registered.length) {
@@ -40322,26 +40436,26 @@ function makeProvisionDeps(worktreeRoot, quiet, log) {
40322
40436
  function acquireWorktreeSetupLock(worktreeRoot) {
40323
40437
  const lockPath = repoRuntimeStatePath(worktreeRoot, "worktree-setup.lock");
40324
40438
  const take = () => {
40325
- const fd = (0, import_node_fs47.openSync)(lockPath, "wx");
40439
+ const fd = (0, import_node_fs48.openSync)(lockPath, "wx");
40326
40440
  try {
40327
- (0, import_node_fs47.writeSync)(fd, String(Date.now()));
40441
+ (0, import_node_fs48.writeSync)(fd, String(Date.now()));
40328
40442
  } finally {
40329
- (0, import_node_fs47.closeSync)(fd);
40443
+ (0, import_node_fs48.closeSync)(fd);
40330
40444
  }
40331
40445
  return () => {
40332
40446
  try {
40333
- (0, import_node_fs47.rmSync)(lockPath, { force: true });
40447
+ (0, import_node_fs48.rmSync)(lockPath, { force: true });
40334
40448
  } catch {
40335
40449
  }
40336
40450
  };
40337
40451
  };
40338
40452
  try {
40339
- (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 });
40340
40454
  return take();
40341
40455
  } catch {
40342
40456
  try {
40343
- if (Date.now() - (0, import_node_fs47.statSync)(lockPath).mtimeMs > WORKTREE_SETUP_LOCK_TTL_MS) {
40344
- (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 });
40345
40459
  return take();
40346
40460
  }
40347
40461
  } catch {
@@ -40457,7 +40571,7 @@ withExamples(mutating(
40457
40571
  }
40458
40572
  if (!resumed) {
40459
40573
  step = `git worktree add ${wtPath}`;
40460
- const wtPathPreExisted = (0, import_node_fs47.existsSync)(wtPath);
40574
+ const wtPathPreExisted = (0, import_node_fs48.existsSync)(wtPath);
40461
40575
  const partialRemove = worktreeRemoveDeps(async (args) => (await execFileP2("git", args, { timeout: GIT_TIMEOUT_MS })).stdout);
40462
40576
  await withWorktreeAddLock(repoRoot2, () => addWorktreeRobust(wtPath, branch, base, {
40463
40577
  // #4834: `-c core.longpaths=true` rides the add command itself — a Windows worktree path
@@ -40473,13 +40587,13 @@ withExamples(mutating(
40473
40587
  },
40474
40588
  deleteBranch: (b) => execFileP2("git", ["branch", "-D", b], { timeout: GIT_TIMEOUT_MS }).then(() => void 0),
40475
40589
  cleanupPartial: async () => {
40476
- if (wtPathPreExisted || !(0, import_node_fs47.existsSync)(wtPath)) return;
40590
+ if (wtPathPreExisted || !(0, import_node_fs48.existsSync)(wtPath)) return;
40477
40591
  partialRemove.detachReparsePoints(wtPath);
40478
40592
  await execFileP2("git", ["worktree", "remove", "--force", wtPath], { timeout: GIT_TIMEOUT_MS }).catch(() => partialRemove.removeWorktreeDir(wtPath).then(() => void 0));
40479
40593
  await execFileP2("git", ["worktree", "prune"], { timeout: GIT_TIMEOUT_MS }).catch(() => {
40480
40594
  });
40481
40595
  },
40482
- sleep: (ms) => new Promise((resolve5) => setTimeout(resolve5, ms)),
40596
+ sleep: (ms) => new Promise((resolve6) => setTimeout(resolve6, ms)),
40483
40597
  log: (m) => {
40484
40598
  if (!o.json) console.error(` ${m}`);
40485
40599
  }
@@ -40931,9 +41045,7 @@ docs.command("refs").description("deterministic doc reference gate: every backti
40931
41045
  try {
40932
41046
  const root = await repoRoot();
40933
41047
  const commandPaths = new Set(
40934
- buildCommandManifest(program2).index.map(
40935
- (entry) => entry.house && entry.house !== "core" ? `${entry.house} ${entry.path}` : entry.path
40936
- )
41048
+ buildCommandManifest(program2).index.map((entry) => entry.path)
40937
41049
  );
40938
41050
  const result = runDocRefs(root, { commandPaths });
40939
41051
  if (o.json) {
@@ -41016,7 +41128,7 @@ async function reportWrite(label, res) {
41016
41128
  return failGraceful(`${label}: HTTP ${res.status}${detail ? ` \u2014 ${detail}` : ""}`);
41017
41129
  }
41018
41130
  var tenant = program2.command("tenant").description("tenant runtime control through Hub authority");
41019
- tenant.command("control <owner/repo> <stage> <action>").description("bounded tenant control plus value-free vault/broker verification; project-admin own dev/rc, master main").option("--watch", "block on the dispatched run and report its conclusion (status/retire/verify-secrets/verify-broker/logs watch by default)").option("--lines <n>", "logs only: trailing lines of the tenant service to return (1-2000, default 200)").option("--json", "machine-readable output").action(async (repo, stage, action, o) => {
41131
+ tenant.command("control <owner/repo> <stage> <action>").description("bounded tenant control plus value-free vault/broker verification; project-admin own dev/rc, master main").option("--watch", "block on the dispatched run and report its conclusion (status/retire/verify-secrets/verify-broker/logs watch by default)").option("--lines <n>", "logs only: trailing lines of the tenant service to return (1-2000, default 200)").option("--task <name>", "run-task only: registry-declared task name (never a command)").option("--artifact <id>", "run-task only: opaque id returned by tenant artifact put").option("--json", "machine-readable output").action(async (repo, stage, action, o) => {
41020
41132
  try {
41021
41133
  let lines;
41022
41134
  if (o.lines !== void 0) {
@@ -41024,7 +41136,12 @@ tenant.command("control <owner/repo> <stage> <action>").description("bounded ten
41024
41136
  lines = Number(o.lines);
41025
41137
  if (!Number.isInteger(lines) || lines < 1 || lines > 2e3) return fail("runtime tenant control: --lines must be an integer between 1 and 2000");
41026
41138
  }
41027
- 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 });
41028
41145
  if (!o.json && action === "verify-secrets" && result.secrets) {
41029
41146
  const body = { ok: result.conclusion === "success", secrets: result.secrets, ssmStatus: result.conclusion === "success" ? "Success" : "Failed", raw: result.secretsRaw };
41030
41147
  const { lines: lines2, failure } = renderVerifySecrets(body);
@@ -41046,6 +41163,15 @@ tenant.command("control <owner/repo> <stage> <action>").description("bounded ten
41046
41163
  return failGraceful(`runtime tenant control: ${e.message}`);
41047
41164
  }
41048
41165
  });
41166
+ var tenantArtifact = tenant.command("artifact").description("private stage-bound inputs for declared tenant tasks");
41167
+ tenantArtifact.command("put <owner/repo> <stage> <path>").description("upload a private file through a short-lived Hub grant; prints only an opaque artifact id").option("--json", "machine-readable output").action(async (repo, stage, path2, o) => {
41168
+ try {
41169
+ const receipt = await putTenantArtifact(repo, stage, path2, registryClientDeps(await loadConfig()));
41170
+ printLine(o.json ? JSON.stringify(receipt, null, 2) : `tenant artifact ${receipt.artifactId} ready for ${repo} ${stage} until ${receipt.expiresAt}`);
41171
+ } catch (e) {
41172
+ return failGraceful(e.message);
41173
+ }
41174
+ });
41049
41175
  tenant.command("reconcile <owner/repo> <stage>").description("re-render this tenant stage's generated box assets from registry truth; project-admin own dev/rc, master main; watches by default").option("--watch", "wait for the tenant-reconcile.yml run (default)").option("--no-watch", "return after dispatch; do not redeploy until the reconcile run succeeds").option("--json", "machine-readable output").action(async (repo, stage, o) => {
41050
41176
  try {
41051
41177
  const result = await runTenantReconcile(trainApplyDeps(), { repo, stage, watch: o.watch });
@@ -41242,7 +41368,7 @@ project.command("set [owner/repo]").description("upsert project META (idempotent
41242
41368
  if (dupe) return fail(`org project set: KEY "${dupe}" was passed to both --var and --set; --set is an alias of --var, so pass each KEY once`);
41243
41369
  if (o.secretsFile) {
41244
41370
  try {
41245
- vars.push(`secrets=${(0, import_node_fs47.readFileSync)(o.secretsFile, "utf8")}`);
41371
+ vars.push(`secrets=${(0, import_node_fs48.readFileSync)(o.secretsFile, "utf8")}`);
41246
41372
  } catch (e) {
41247
41373
  return fail(`org project set: cannot read --secrets-file ${o.secretsFile}: ${e.message}`);
41248
41374
  }
@@ -41568,7 +41694,7 @@ withExamples(mutating(
41568
41694
  try {
41569
41695
  title = await resolveIssueTitle(
41570
41696
  { title: opts.title, titleFile: opts.titleFile },
41571
- { readFile: import_promises11.readFile, readStdin }
41697
+ { readFile: import_promises12.readFile, readStdin }
41572
41698
  );
41573
41699
  } catch (e) {
41574
41700
  return fail(
@@ -41610,8 +41736,8 @@ withExamples(mutating(
41610
41736
  let surfaceFlagLabel;
41611
41737
  try {
41612
41738
  issueType = resolveCreateType(o.type, "issue create", o.label);
41613
- title = await resolveIssueTitle({ title: o.title, titleFile: o.titleFile }, { readFile: import_promises11.readFile, readStdin });
41614
- 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 });
41615
41741
  if (o.idempotencyKey) body = appendIdempotencyMarker(body, o.idempotencyKey);
41616
41742
  priority = resolveCreatePriority(o.priority, "issue create");
41617
41743
  extraLabels = [...o.label ?? []];
@@ -41792,7 +41918,7 @@ jsonParity(issue.command("comment <ref>").description("post a Markdown comment t
41792
41918
  }
41793
41919
  let body;
41794
41920
  try {
41795
- body = await resolveIssueBody({ body: o.body, bodyFile: o.bodyFile }, { readFile: import_promises11.readFile, readStdin });
41921
+ body = await resolveIssueBody({ body: o.body, bodyFile: o.bodyFile }, { readFile: import_promises12.readFile, readStdin });
41796
41922
  } catch (e) {
41797
41923
  return fail(`issue comment: ${e.message}`);
41798
41924
  }
@@ -41852,8 +41978,8 @@ program2.command("report").description("file a friction report on the Hub board
41852
41978
  let title;
41853
41979
  const sourceRepo = o.repo ?? await resolveRepo(void 0);
41854
41980
  try {
41855
- title = await resolveIssueTitle({ title: o.title, titleFile: o.titleFile }, { readFile: import_promises11.readFile, readStdin });
41856
- 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 });
41857
41983
  priority = resolveCreatePriority(o.priority, "report");
41858
41984
  if (!ISSUE_TYPES.includes(o.type)) {
41859
41985
  throw new Error(`unknown issue type "${o.type}" \u2014 expected one of: ${ISSUE_TYPES.join(", ")}`);
@@ -41907,8 +42033,8 @@ program2.command("skill-lesson").description("file a skill-lesson on the Hub boa
41907
42033
  let args;
41908
42034
  try {
41909
42035
  skill = assertSkillName(o.skill);
41910
- rawBody = await resolveIssueBody({ body: o.body, bodyFile: o.bodyFile }, { readFile: import_promises11.readFile, readStdin });
41911
- 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 });
41912
42038
  title = buildSkillLessonTitle(skill, rawTitle);
41913
42039
  priority = resolveCreatePriority(o.priority, "skill-lesson");
41914
42040
  body = buildSkillLessonBody(rawBody, sourceRepo, pluginSha);
@@ -41967,8 +42093,8 @@ withExamples(pr.command("create").description("create a PR and print {number,url
41967
42093
  let body;
41968
42094
  let title;
41969
42095
  try {
41970
- title = await resolveIssueTitle({ title: o.title, titleFile: o.titleFile }, { readFile: import_promises11.readFile, readStdin });
41971
- 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 });
41972
42098
  } catch (e) {
41973
42099
  return fail(`pr create: ${e.message}`, e instanceof TextArgError ? { code: e.code, offending_flag: e.offendingFlag } : void 0);
41974
42100
  }
@@ -42010,11 +42136,11 @@ pr.command("view <number>").description("read a PR as structured JSON (merged st
42010
42136
  }
42011
42137
  });
42012
42138
  async function listCiWorkflowPaths(cwd = process.cwd()) {
42013
- const wfDir = (0, import_node_path44.join)(cwd, ".github", "workflows");
42014
- if (!(0, import_node_fs47.existsSync)(wfDir)) return [];
42015
- 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) => {
42016
42142
  try {
42017
- 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"));
42018
42144
  } catch {
42019
42145
  return true;
42020
42146
  }
@@ -42066,16 +42192,16 @@ function ciAuditDeps() {
42066
42192
  // gate re-seed step is skipped gracefully rather than failing mid-run.
42067
42193
  readSeedFile: (path2) => {
42068
42194
  if (!root) return null;
42069
- const fullPath = (0, import_node_path44.join)(root, path2);
42070
- 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;
42071
42197
  }
42072
42198
  };
42073
42199
  }
42074
42200
  function hubRoot() {
42075
- const fromPkg = (0, import_node_path44.join)(__dirname, "..", "..");
42201
+ const fromPkg = (0, import_node_path45.join)(__dirname, "..", "..");
42076
42202
  const marker = "skills/bootstrap/seeds/manifest.json";
42077
- if ((0, import_node_fs47.existsSync)((0, import_node_path44.join)(fromPkg, marker))) return fromPkg;
42078
- 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();
42079
42205
  return null;
42080
42206
  }
42081
42207
  async function waitLoopCorePool(label) {
@@ -42124,7 +42250,7 @@ pr.command("checks-wait <number>").description(`bounded wait for PR checks; skip
42124
42250
  // reading as "your tests failed". One call per failing run, only at the verdict.
42125
42251
  diagnoseFailure: () => waitLoopDiagnosis("pr checks-wait", number, repo),
42126
42252
  baseBranch,
42127
- sleep: (ms) => new Promise((resolve5) => setTimeout(resolve5, ms)),
42253
+ sleep: (ms) => new Promise((resolve6) => setTimeout(resolve6, ms)),
42128
42254
  log: (message) => console.warn(message),
42129
42255
  timeoutMs,
42130
42256
  // Liveness on stderr, one line per poll. A silent bounded wait is indistinguishable from a hang, and
@@ -42204,7 +42330,7 @@ pr.command("land <number>").description("agent merge path (#1440): train probe \
42204
42330
  // then read its own wall-clock kill as a broken diff.
42205
42331
  diagnoseFailure: () => waitLoopDiagnosis("pr land", prNumber, repo),
42206
42332
  baseBranch: "development",
42207
- sleep: (ms) => new Promise((resolve5) => setTimeout(resolve5, ms)),
42333
+ sleep: (ms) => new Promise((resolve6) => setTimeout(resolve6, ms)),
42208
42334
  log: (message) => console.warn(message),
42209
42335
  // `pr land` inherits the same (raised) checks budget, so it needs the same liveness — otherwise the
42210
42336
  // 30m wait is SILENT and reads exactly like the hang #2940 was filed about, only three times longer.
@@ -42247,7 +42373,7 @@ pr.command("land <number>").description("agent merge path (#1440): train probe \
42247
42373
  } else {
42248
42374
  lastFailure = void 0;
42249
42375
  }
42250
- await new Promise((resolve5) => setTimeout(resolve5, PR_LAND_POLL_MS));
42376
+ await new Promise((resolve6) => setTimeout(resolve6, PR_LAND_POLL_MS));
42251
42377
  }
42252
42378
  if (lastFailure) {
42253
42379
  throw new Error(
@@ -42347,7 +42473,7 @@ jsonParity(pr.command("merge <number>").description("merge a PR (squash by defau
42347
42473
  pollRateLimit: () => waitLoopCorePool("pr merge --wait"),
42348
42474
  diagnoseFailure: () => waitLoopDiagnosis("pr merge --wait", number, repo),
42349
42475
  baseBranch,
42350
- sleep: (ms) => new Promise((resolve5) => setTimeout(resolve5, ms)),
42476
+ sleep: (ms) => new Promise((resolve6) => setTimeout(resolve6, ms)),
42351
42477
  log: (message) => console.warn(message),
42352
42478
  progress: ({ state, elapsedMs, remainingMs }) => console.warn(`pr merge: --wait checks \u2014 ${state}, ${Math.round(elapsedMs / 1e3)}s elapsed, ${Math.round(remainingMs / 6e4)}m left`)
42353
42479
  });
@@ -42383,7 +42509,7 @@ jsonParity(pr.command("merge <number>").description("merge a PR (squash by defau
42383
42509
  }
42384
42510
  if (!repoForPostCleanup) throw e;
42385
42511
  console.warn(`pr merge: gh GraphQL rate-limited \u2014 merging PR #${number} via REST PUT instead (#4588).`);
42386
- const commitMessage = bodyFile ? (0, import_node_fs47.readFileSync)(bodyFile, "utf8") : void 0;
42512
+ const commitMessage = bodyFile ? (0, import_node_fs48.readFileSync)(bodyFile, "utf8") : void 0;
42387
42513
  await defaultGitHubClient().rest("PUT", `repos/${repoForPostCleanup}/pulls/${number}/merge`, {
42388
42514
  body: { merge_method: method.slice(2), ...commitMessage ? { commit_message: commitMessage } : {} },
42389
42515
  timeoutMs: GH_MUTATION_TIMEOUT_MS
@@ -42479,7 +42605,7 @@ jsonParity(pr.command("merge <number>").description("merge a PR (squash by defau
42479
42605
  localCleanup = await cleanupPrMergeLocalBranch(headRef, {
42480
42606
  beforeWorktrees,
42481
42607
  startingPath,
42482
- pathExists: (p) => (0, import_node_fs47.existsSync)(p),
42608
+ pathExists: (p) => (0, import_node_fs48.existsSync)(p),
42483
42609
  execGit: async (args) => (await execFileP2("git", args, { timeout: GIT_TIMEOUT_MS })).stdout,
42484
42610
  teardownWorktreeStage,
42485
42611
  deferredStore,
@@ -42580,8 +42706,8 @@ function trainApplyDeps() {
42580
42706
  // Hub-App-authority dispatch of the central tenant-control.yml (#1717) — the Hub fires the
42581
42707
  // workflow_dispatch with its App token. Never throws for an expected rejection: it returns the dispatch
42582
42708
  // outcome so runTenantControl can map a 5xx (transport-failed, retryable) vs a 4xx (rejected) vs ok.
42583
- dispatchTenantControl: async ({ repo, stage, action, lines }) => {
42584
- const res = await tenantControl({ repo, stage, action, ...lines != null ? { lines } : {} }, registryClientDeps(await loadConfig()));
42709
+ dispatchTenantControl: async ({ repo, stage, action, lines, task, artifact }) => {
42710
+ const res = await tenantControl({ repo, stage, action, ...lines != null ? { lines } : {}, ...task ? { task } : {}, ...artifact ? { artifact } : {} }, registryClientDeps(await loadConfig()));
42585
42711
  if (res.ok) return { ok: true };
42586
42712
  const body = res.body;
42587
42713
  return { ok: false, category: body?.category, error: body?.error ?? res.error };
@@ -42605,8 +42731,8 @@ function trainApplyDeps() {
42605
42731
  // Slack release announcement (#883): Hub-only + best-effort inside announceRelease itself.
42606
42732
  announce: (args) => announceRelease({
42607
42733
  run: async (file, cmdArgs) => (await execFileP2(file, cmdArgs, { timeout: GH_TRAIN_TIMEOUT_MS })).stdout,
42608
- readFile: (path2) => (0, import_promises11.readFile)(path2, "utf8"),
42609
- removeFile: (path2) => (0, import_promises11.unlink)(path2)
42734
+ readFile: (path2) => (0, import_promises12.readFile)(path2, "utf8"),
42735
+ removeFile: (path2) => (0, import_promises12.unlink)(path2)
42610
42736
  }, args),
42611
42737
  // #4713 (I/O-boundary census): `null` used to mean BOTH "this project configures no edge domains"
42612
42738
  // (a real answer) and "the registry read missed" — so a release verdict printed an environments block
@@ -42843,7 +42969,7 @@ for (const commandName of ["rcand", "release"]) {
42843
42969
  }
42844
42970
  let summaryLines;
42845
42971
  try {
42846
- summaryLines = summaryFileLines(await (0, import_promises11.readFile)(o.announceSummaryFile, "utf8"));
42972
+ summaryLines = summaryFileLines(await (0, import_promises12.readFile)(o.announceSummaryFile, "utf8"));
42847
42973
  } catch (e) {
42848
42974
  return fail(`release: could not read --announce-summary-file ${o.announceSummaryFile}: ${e.message}`);
42849
42975
  }
@@ -43083,12 +43209,12 @@ access.command("audit").description("audit collaborator roles + train-branch pus
43083
43209
  targets = resolution.targets;
43084
43210
  }
43085
43211
  const derivedMatrix = registryProjects ? accessMatrixFromProjects(registryProjects) : {};
43086
- const fileMatrix = (0, 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")) : {};
43087
43213
  const matrix = mergeAccessMatrix(fileMatrix, derivedMatrix);
43088
43214
  const derivedContracts = registryProjects ? dataAccessContractsFromProjects(registryProjects) : { consumers: {} };
43089
- 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: {} };
43090
43216
  const dataAccess = mergeDataAccessContracts(fileContracts, derivedContracts);
43091
- 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")) : {};
43092
43218
  const report = await auditOrgAccess(targets, deps, matrix, dataAccess, sanctioned);
43093
43219
  console.log(o.json ? JSON.stringify(report, null, 2) : renderAccessReport(report));
43094
43220
  if (!report.ok) process.exitCode = 1;
@@ -43126,16 +43252,16 @@ function directoryBytes(path2) {
43126
43252
  let total = 0;
43127
43253
  let entries;
43128
43254
  try {
43129
- entries = (0, import_node_fs47.readdirSync)(path2, { withFileTypes: true });
43255
+ entries = (0, import_node_fs48.readdirSync)(path2, { withFileTypes: true });
43130
43256
  } catch {
43131
43257
  return 0;
43132
43258
  }
43133
43259
  for (const entry of entries) {
43134
- const child2 = (0, import_node_path44.join)(path2, entry.name);
43260
+ const child2 = (0, import_node_path45.join)(path2, entry.name);
43135
43261
  if (entry.isDirectory()) total += directoryBytes(child2);
43136
43262
  else {
43137
43263
  try {
43138
- total += (0, import_node_fs47.statSync)(child2).size;
43264
+ total += (0, import_node_fs48.statSync)(child2).size;
43139
43265
  } catch {
43140
43266
  }
43141
43267
  }
@@ -43143,25 +43269,25 @@ function directoryBytes(path2) {
43143
43269
  return total;
43144
43270
  }
43145
43271
  function listDirEntries(dir) {
43146
- return (0, 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() }));
43147
43273
  }
43148
43274
  function readInstalledPluginRefs(configRoot) {
43149
43275
  const p = installedPluginsPathForConfig(configRoot);
43150
- if (!(0, import_node_fs47.existsSync)(p)) return [];
43276
+ if (!(0, import_node_fs48.existsSync)(p)) return [];
43151
43277
  try {
43152
- return installedPluginPaths((0, import_node_fs47.readFileSync)(p, "utf8"));
43278
+ return installedPluginPaths((0, import_node_fs48.readFileSync)(p, "utf8"));
43153
43279
  } catch {
43154
43280
  return null;
43155
43281
  }
43156
43282
  }
43157
43283
  function pluginCacheFsDeps(configRoot, dirBytes) {
43158
43284
  return {
43159
- exists: (p) => (0, import_node_fs47.existsSync)(p),
43160
- 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),
43161
43287
  dirBytes,
43162
- 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) => {
43163
43289
  try {
43164
- 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) };
43165
43291
  } catch {
43166
43292
  return { name: d.name, mtimeMs: Date.now() };
43167
43293
  }
@@ -43175,10 +43301,10 @@ function stagingApplyFsGuard(configRoot) {
43175
43301
  return {
43176
43302
  referencedPaths: () => readInstalledPluginRefs(configRoot),
43177
43303
  mtimeMs: (name) => {
43178
- const p = (0, import_node_path44.join)(stagingRoot, name);
43179
- 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;
43180
43306
  try {
43181
- 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);
43182
43308
  } catch {
43183
43309
  return null;
43184
43310
  }
@@ -43204,7 +43330,7 @@ program2.command("plugin-prune").description(`prune stale cached MMI plugin vers
43204
43330
  { withBytes: true, configRoot, includeStaging: surface !== "codex" }
43205
43331
  );
43206
43332
  const anythingToDelete = plan.prune.length > 0 || plan.staging.length > 0;
43207
- const result = o.apply && anythingToDelete ? applyPluginCachePlan(plan, (p) => (0, 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;
43208
43334
  const warnings = plan.prune.length > 0 ? [CONCURRENT_SESSION_WARNING] : [];
43209
43335
  if (o.json) console.log(JSON.stringify({ ...plan, warnings, applied: result ?? null }));
43210
43336
  else console.log(renderPluginCachePlan(plan, result));
@@ -43212,7 +43338,7 @@ program2.command("plugin-prune").description(`prune stale cached MMI plugin vers
43212
43338
  });
43213
43339
  function readReleaseCatchupState(path2) {
43214
43340
  try {
43215
- const parsed = JSON.parse((0, import_node_fs47.readFileSync)(path2, "utf8"));
43341
+ const parsed = JSON.parse((0, import_node_fs48.readFileSync)(path2, "utf8"));
43216
43342
  return typeof parsed?.checkedAt === "number" ? parsed : void 0;
43217
43343
  } catch {
43218
43344
  return void 0;
@@ -43220,8 +43346,8 @@ function readReleaseCatchupState(path2) {
43220
43346
  }
43221
43347
  function writeReleaseCatchupState(path2, state) {
43222
43348
  try {
43223
- (0, import_node_fs47.mkdirSync)((0, import_node_path44.dirname)(path2), { recursive: true });
43224
- (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)}
43225
43351
  `);
43226
43352
  } catch {
43227
43353
  }