@mutmutco/cli 4.5.117 → 4.5.119

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 +936 -732
  2. package/package.json +1 -1
package/dist/main.cjs CHANGED
@@ -1178,7 +1178,9 @@ function commandFromFailMessage(msg) {
1178
1178
  const head = msg.split(":", 1)[0].trim();
1179
1179
  if (!head || head.startsWith("-")) return "mmi-cli";
1180
1180
  if (!/^[a-z][a-z0-9-]*(?: [a-z][a-z0-9-]*){0,5}$/.test(head)) return "mmi-cli";
1181
- return canonicalPathFor(head) ?? head;
1181
+ const canonical = canonicalPathFor(head);
1182
+ if (canonical) return canonical;
1183
+ return HOUSE_ROOTS.includes(head.split(" ")[0]) ? head : "mmi-cli";
1182
1184
  }
1183
1185
  function canonicalFailMessage(msg) {
1184
1186
  const colon = msg.indexOf(":");
@@ -4751,7 +4753,7 @@ function useColor() {
4751
4753
  var program = new Command();
4752
4754
 
4753
4755
  // src/command-composition.ts
4754
- var import_node_fs55 = require("node:fs");
4756
+ var import_node_fs57 = require("node:fs");
4755
4757
  init_clean_exit();
4756
4758
  init_cli_shared();
4757
4759
 
@@ -5653,13 +5655,13 @@ function resolveVerbAliasShim(argv) {
5653
5655
  }
5654
5656
 
5655
5657
  // src/command-composition.ts
5656
- var import_node_os24 = require("node:os");
5657
- var import_node_path53 = require("node:path");
5658
+ var import_node_os25 = require("node:os");
5659
+ var import_node_path54 = require("node:path");
5658
5660
 
5659
5661
  // src/board-read.ts
5660
- var import_node_fs13 = require("node:fs");
5661
- var import_node_os9 = require("node:os");
5662
- var import_node_path11 = require("node:path");
5662
+ var import_node_fs14 = require("node:fs");
5663
+ var import_node_os10 = require("node:os");
5664
+ var import_node_path12 = require("node:path");
5663
5665
  init_cli_shared();
5664
5666
  init_github_client();
5665
5667
 
@@ -5667,21 +5669,35 @@ init_github_client();
5667
5669
  init_fetch_retry();
5668
5670
  init_client_version();
5669
5671
  var BOARD_SNAPSHOT_TIMEOUT_MS = 25e3;
5672
+ var BOARD_SNAPSHOT_EXIT_CODES = {
5673
+ "hub-unreachable": 20,
5674
+ "app-quota-exhausted": 21,
5675
+ refused: 22
5676
+ };
5677
+ var BoardSnapshotFailure = class extends Error {
5678
+ constructor(receipt) {
5679
+ super(receipt.reason);
5680
+ this.receipt = receipt;
5681
+ this.exitCode = BOARD_SNAPSHOT_EXIT_CODES[receipt.outcome];
5682
+ }
5683
+ receipt;
5684
+ exitCode;
5685
+ };
5670
5686
  function isSnapshotShape(body) {
5671
5687
  const b = body;
5672
5688
  const rate = b?.github?.rateLimit;
5673
5689
  const staleValid = b?.stale === void 0 || typeof b.stale === "object" && b.stale !== null && Number.isFinite(b.stale.ageMs) && b.stale.ageMs >= 0;
5674
- const githubValid = b?.github === void 0 || b.github.credential === "app_installation" && (rate === void 0 || Number.isFinite(rate?.limit) && Number.isFinite(rate?.remaining) && Number.isFinite(rate?.cost) && typeof rate?.resetAt === "string");
5690
+ const githubValid = b?.github === void 0 || b.github !== null && typeof b.github === "object" && b.github.credential === "app_installation" && (rate === void 0 || Number.isFinite(rate?.limit) && Number.isFinite(rate?.remaining) && Number.isFinite(rate?.cost) && typeof rate?.resetAt === "string");
5675
5691
  return Boolean(
5676
5692
  b && typeof b === "object" && typeof b.project?.id === "string" && typeof b.project?.title === "string" && typeof b.viewer === "string" && b.viewer.length > 0 && Array.isArray(b.nodes) && Array.isArray(b.writableRepos) && Array.isArray(b.unreadableRepos) && Array.isArray(b.pullRequests) && Array.isArray(b.warnings) && typeof b.partial === "boolean" && (b.source === void 0 || b.source === "live" || b.source === "cache") && (b.builtAt === void 0 || typeof b.builtAt === "string" && Number.isFinite(Date.parse(b.builtAt))) && (b.eventCursor === void 0 || Number.isInteger(b.eventCursor) && b.eventCursor >= 0) && githubValid && staleValid
5677
5693
  );
5678
5694
  }
5679
5695
  async function fetchHubBoardSnapshot(request, deps) {
5680
5696
  if (!deps.baseUrl) return { state: "unavailable", reason: "no Hub API URL (set MMI_HUB_URL or use a current MMI CLI/plugin build)" };
5681
- const token = await deps.token();
5682
- if (!token) return { state: "unavailable", reason: "no Hub session token (run `gh auth login`)" };
5683
5697
  let res;
5684
5698
  try {
5699
+ const token = await deps.token();
5700
+ if (!token) return { state: "unavailable", reason: "no Hub session token (run `gh auth login`)" };
5685
5701
  res = await fetchWithRetry(
5686
5702
  deps.fetch ?? fetch,
5687
5703
  `${deps.baseUrl.replace(/\/$/, "")}/board/snapshot`,
@@ -5715,10 +5731,26 @@ async function fetchHubBoardSnapshot(request, deps) {
5715
5731
  return {
5716
5732
  state: "unavailable",
5717
5733
  reason: `GitHub App quota exhausted${reset}`,
5734
+ appQuotaExhausted: true,
5735
+ pool: "graphql",
5736
+ ...typeof body2.resetAt === "string" ? { resetAt: body2.resetAt } : {},
5718
5737
  ...body2.github?.credential === "app_installation" && body2.github.resource === "graphql" && /^github-app-v1:[a-f0-9]{64}$/.test(body2.github.quotaScope ?? "") ? { quota: { status: "rate_limited", ...typeof body2.resetAt === "string" ? { resetAt: body2.resetAt } : {}, github: { credential: "app_installation", resource: "graphql", quotaScope: body2.github.quotaScope } } } : {}
5719
5738
  };
5720
5739
  }
5721
5740
  }
5741
+ if (res.status === 503) {
5742
+ const body2 = await res.json().catch(() => null);
5743
+ if (body2?.code === "github-rate-limited") {
5744
+ const reset = typeof body2.resetAt === "string" ? `; resets ${body2.resetAt}` : "; reset time unavailable";
5745
+ return {
5746
+ state: "unavailable",
5747
+ reason: `GitHub App allowance exhausted${reset}`,
5748
+ appQuotaExhausted: true,
5749
+ pool: "rest",
5750
+ ...typeof body2.resetAt === "string" ? { resetAt: body2.resetAt } : {}
5751
+ };
5752
+ }
5753
+ }
5722
5754
  if (!res.ok) return { state: "unavailable", reason: `board snapshot HTTP ${res.status}` };
5723
5755
  const body = await res.json().catch(() => null);
5724
5756
  if (!isSnapshotShape(body)) return { state: "unavailable", reason: "malformed board snapshot response" };
@@ -5816,6 +5848,22 @@ var activeQuotaScope;
5816
5848
  function activeAppQuotaScope() {
5817
5849
  return activeQuotaScope;
5818
5850
  }
5851
+ var activeToken;
5852
+ function activeAppToken() {
5853
+ return activeToken;
5854
+ }
5855
+ async function readAppVaultSecret(read) {
5856
+ try {
5857
+ return await read();
5858
+ } catch (e) {
5859
+ const reason = e.message;
5860
+ if (/^(Hub GitHub App allowance used up|rate limited)/.test(reason)) {
5861
+ throw new AppActorError(`app actor: the vault could not read the App credentials because GitHub is rate-limited, not a denial: ${reason}`, "mint-failed");
5862
+ }
5863
+ if (/^authority refused|\(HTTP 404\b/.test(reason)) return null;
5864
+ throw new AppActorError(`app actor: the vault read of the App credentials failed, not a denial: ${reason}`, "mint-failed");
5865
+ }
5866
+ }
5819
5867
  async function mintInstallationToken(deps) {
5820
5868
  const [appId, installationId, privateKey] = await Promise.all(APP_VAULT_KEYS.map((k) => deps.fetchSecret(k)));
5821
5869
  if (!appId || !installationId || !privateKey) {
@@ -5875,6 +5923,7 @@ var notedIneligibleCommand = false;
5875
5923
  async function activateAppActor(commandPath3, env, mint, note = (line) => process.stderr.write(`${line}
5876
5924
  `)) {
5877
5925
  activeQuotaScope = void 0;
5926
+ activeToken = void 0;
5878
5927
  const requested = (env[APP_ACTOR_ENV] ?? "").trim();
5879
5928
  if (!requested) return "personal";
5880
5929
  if (requested !== "app") {
@@ -5892,6 +5941,7 @@ async function activateAppActor(commandPath3, env, mint, note = (line) => proces
5892
5941
  const minted = await mint();
5893
5942
  env.GH_TOKEN = minted.token;
5894
5943
  activeQuotaScope = minted.quotaScope;
5944
+ activeToken = minted.token;
5895
5945
  return "app";
5896
5946
  }
5897
5947
 
@@ -6298,6 +6348,93 @@ function isReleaseShaDeployEnumerationCandidate(row, nonDeployEvents) {
6298
6348
 
6299
6349
  // src/pr-checks-rest.ts
6300
6350
  init_github_quota();
6351
+
6352
+ // src/rest-etag-cache.ts
6353
+ var import_node_crypto5 = require("node:crypto");
6354
+ var import_node_fs11 = require("node:fs");
6355
+ var import_node_os4 = require("node:os");
6356
+ var import_node_path9 = require("node:path");
6357
+ var MAX_AGE_MS = 24 * 60 * 6e4;
6358
+ var MAX_ENTRIES = 256;
6359
+ var MAX_BYTES = 16 * 1024 * 1024;
6360
+ var MAX_ENTRY_BYTES = 1024 * 1024;
6361
+ function restEtagCacheDir() {
6362
+ if (process.env.MMI_REST_ETAG_CACHE_DIR) return process.env.MMI_REST_ETAG_CACHE_DIR;
6363
+ return process.platform === "win32" ? (0, import_node_path9.join)(process.env.LOCALAPPDATA || (0, import_node_path9.join)((0, import_node_os4.homedir)(), "AppData", "Local"), "MMI Future", "mmi-cli", "rest-etags") : (0, import_node_path9.join)(process.env.XDG_CACHE_HOME || (0, import_node_path9.join)((0, import_node_os4.homedir)(), ".cache"), "mmi-cli", "rest-etags");
6364
+ }
6365
+ function entryPath(dir, key) {
6366
+ return (0, import_node_path9.join)(dir, `${(0, import_node_crypto5.createHash)("sha256").update(key).digest("hex")}.json`);
6367
+ }
6368
+ function readRestEtag(key, dir = restEtagCacheDir()) {
6369
+ if (dir === "off") return void 0;
6370
+ try {
6371
+ const path2 = entryPath(dir, key);
6372
+ if ((0, import_node_fs11.statSync)(path2).size > MAX_ENTRY_BYTES) return void 0;
6373
+ const entry = JSON.parse((0, import_node_fs11.readFileSync)(path2, "utf8"));
6374
+ const age = Date.now() - entry.storedAt;
6375
+ if (typeof entry.etag === "string" && entry.etag && !/[\r\n]/.test(entry.etag) && typeof entry.body === "string" && Number.isFinite(entry.storedAt) && age >= 0 && age <= MAX_AGE_MS) return entry;
6376
+ } catch {
6377
+ }
6378
+ return void 0;
6379
+ }
6380
+ function deleteRestEtag(key, dir = restEtagCacheDir()) {
6381
+ if (dir === "off") return;
6382
+ try {
6383
+ (0, import_node_fs11.rmSync)(entryPath(dir, key), { force: true });
6384
+ } catch {
6385
+ }
6386
+ }
6387
+ function prune(dir) {
6388
+ const now = Date.now();
6389
+ const files = (0, import_node_fs11.readdirSync)(dir).filter((name) => /^[a-f0-9]{64}\.json(?:\.tmp-.+)?$/.test(name)).flatMap((name) => {
6390
+ try {
6391
+ const path2 = (0, import_node_path9.join)(dir, name);
6392
+ const stat4 = (0, import_node_fs11.statSync)(path2);
6393
+ if (now - stat4.mtimeMs > MAX_AGE_MS) {
6394
+ (0, import_node_fs11.rmSync)(path2, { force: true });
6395
+ return [];
6396
+ }
6397
+ return name.endsWith(".json") ? [{ path: path2, size: stat4.size, at: stat4.mtimeMs }] : [];
6398
+ } catch {
6399
+ return [];
6400
+ }
6401
+ }).sort((a, b) => a.at - b.at);
6402
+ let bytes = files.reduce((sum, f) => sum + f.size, 0);
6403
+ let count = files.length;
6404
+ for (const file of files) {
6405
+ if (count <= MAX_ENTRIES && bytes <= MAX_BYTES) break;
6406
+ try {
6407
+ (0, import_node_fs11.rmSync)(file.path, { force: true });
6408
+ bytes -= file.size;
6409
+ count--;
6410
+ } catch {
6411
+ }
6412
+ }
6413
+ }
6414
+ function writeRestEtag(key, entry, dir = restEtagCacheDir()) {
6415
+ if (dir === "off") return;
6416
+ const path2 = entryPath(dir, key);
6417
+ const tmp = `${path2}.tmp-${process.pid}-${(0, import_node_crypto5.randomUUID)()}`;
6418
+ try {
6419
+ const data = JSON.stringify({ etag: entry.etag, body: entry.body, storedAt: Date.now() });
6420
+ if (Buffer.byteLength(data) > MAX_ENTRY_BYTES) {
6421
+ deleteRestEtag(key, dir);
6422
+ return;
6423
+ }
6424
+ (0, import_node_fs11.mkdirSync)(dir, { recursive: true, mode: 448 });
6425
+ (0, import_node_fs11.writeFileSync)(tmp, data, { mode: 384, flag: "wx" });
6426
+ (0, import_node_fs11.renameSync)(tmp, path2);
6427
+ prune(dir);
6428
+ } catch {
6429
+ } finally {
6430
+ try {
6431
+ (0, import_node_fs11.rmSync)(tmp, { force: true });
6432
+ } catch {
6433
+ }
6434
+ }
6435
+ }
6436
+
6437
+ // src/pr-checks-rest.ts
6301
6438
  var REST_GH_TIMEOUT_MS = 2e4;
6302
6439
  var pollTokenProvider;
6303
6440
  var pollTokenOnce;
@@ -6382,8 +6519,9 @@ function observedCorePool(source, nowMs) {
6382
6519
  async function defaultGhApi(args, env = process.env) {
6383
6520
  const appToken = await pollToken();
6384
6521
  const source = appToken ? "app" : "user";
6385
- const key = `${source}\0${args.join("\0")}`;
6386
- const cached = etagCache.get(key);
6522
+ const key = `${source}\0${env.GH_HOST || "github.com"}\0${args.join("\0")}`;
6523
+ const cached = etagCache.get(key) ?? readRestEtag(key);
6524
+ if (cached) etagCache.set(key, cached);
6387
6525
  let stdout;
6388
6526
  try {
6389
6527
  ({ stdout } = await execFileP("gh", ["api", "--include", ...cached ? ["-H", `If-None-Match: ${cached.etag}`] : [], ...args], {
@@ -6397,31 +6535,37 @@ async function defaultGhApi(args, env = process.env) {
6397
6535
  } catch (e) {
6398
6536
  const out = e.stdout;
6399
6537
  const errOut = typeof out === "string" ? out : void 0;
6400
- const status = errOut !== void 0 ? parseIncludedOutput(errOut).status : void 0;
6538
+ const status2 = errOut !== void 0 ? parseIncludedOutput(errOut).status : void 0;
6401
6539
  if (errOut !== void 0) notePoolHeaders(source, errOut, Date.now());
6402
- if (cached && status === 304) {
6540
+ if (cached && status2 === 304) {
6403
6541
  lastPollSource = source;
6404
6542
  return cached.body;
6405
6543
  }
6406
- if (status === 403 || status === 429) {
6544
+ if (status2 === 403 || status2 === 429) {
6407
6545
  const path2 = args.filter((a) => !a.startsWith("-")).join(" ") || args.join(" ");
6408
6546
  const refusal = errOut !== void 0 ? describeRefusal(errOut) : "no rate-limit headers or message";
6409
- if (status === 403 && /Resource not accessible by integration/i.test(refusal)) {
6547
+ if (status2 === 403 && /Resource not accessible by integration/i.test(refusal)) {
6410
6548
  throw new Error(
6411
6549
  `poll read refused: App token lacks permission for ${path2} (HTTP 403, response: ${refusal}) \u2014 reads never fall back to the owner's token (#8030); add the permission to APP_POLL_PERMISSIONS / the App installation`
6412
6550
  );
6413
6551
  }
6414
6552
  throw Object.assign(new Error(
6415
- `poll read refused on the ${source} pool (HTTP ${status}, response: ${refusal}) \u2014 reads stay on the ${source === "app" ? "App" : "ambient identity"} (#8030); the wait re-arms after reset`
6416
- ), { status, stdout: errOut, stderr: e.stderr });
6553
+ `poll read refused on the ${source} pool (HTTP ${status2}, response: ${refusal}) \u2014 reads stay on the ${source === "app" ? "App" : "ambient identity"} (#8030); the wait re-arms after reset`
6554
+ ), { status: status2, stdout: errOut, stderr: e.stderr });
6417
6555
  }
6418
6556
  throw e;
6419
6557
  }
6420
- const { body, etag, pages } = parseIncludedOutput(stdout);
6558
+ const { body, status, etag, pages } = parseIncludedOutput(stdout);
6421
6559
  notePoolHeaders(source, stdout, Date.now());
6422
6560
  lastPollSource = source;
6423
- if (etag && pages === 1) etagCache.set(key, { etag, body });
6424
- else etagCache.delete(key);
6561
+ if (cached && status === 304) return cached.body;
6562
+ if (status === 200 && etag && pages === 1) {
6563
+ etagCache.set(key, { etag, body });
6564
+ writeRestEtag(key, { etag, body });
6565
+ } else {
6566
+ etagCache.delete(key);
6567
+ deleteRestEtag(key);
6568
+ }
6425
6569
  return body;
6426
6570
  }
6427
6571
  function classifyCheckRun(run) {
@@ -8526,12 +8670,12 @@ async function fetchSchedulesList(deps) {
8526
8670
  return null;
8527
8671
  }
8528
8672
  }
8529
- async function fetchOrgConfig(deps) {
8673
+ async function fetchOrgConfig(deps, spendMinutes) {
8530
8674
  if (!deps.baseUrl) return null;
8531
8675
  const token = await deps.token();
8532
8676
  if (!token) return null;
8533
8677
  try {
8534
- const res = await retriedFetch(deps, `${deps.baseUrl.replace(/\/$/, "")}${ORG_CONFIG_PATH}`, {
8678
+ const res = await retriedFetch(deps, `${deps.baseUrl.replace(/\/$/, "")}${ORG_CONFIG_PATH}${spendMinutes === void 0 ? "" : `?github-spend-minutes=${spendMinutes}`}`, {
8535
8679
  method: "GET",
8536
8680
  headers: { Authorization: `Bearer ${token}` }
8537
8681
  });
@@ -9765,14 +9909,14 @@ async function secretsPreflight(deps, opts) {
9765
9909
 
9766
9910
  // src/secrets-execution.ts
9767
9911
  var import_node_child_process4 = require("node:child_process");
9768
- var import_node_os5 = require("node:os");
9912
+ var import_node_os6 = require("node:os");
9769
9913
  init_clean_exit();
9770
9914
 
9771
9915
  // src/gh-create.ts
9772
9916
  var import_promises = require("node:fs/promises");
9773
- var import_node_os4 = require("node:os");
9774
- var import_node_path9 = require("node:path");
9775
- var import_node_crypto5 = require("node:crypto");
9917
+ var import_node_os5 = require("node:os");
9918
+ var import_node_path10 = require("node:path");
9919
+ var import_node_crypto6 = require("node:crypto");
9776
9920
 
9777
9921
  // src/board-priority.ts
9778
9922
  var BOARD_PRIORITY_NAMES = ["Urgent", "High", "Medium", "Low"];
@@ -9858,9 +10002,9 @@ async function bodyArgsViaFile(args, deps = {}) {
9858
10002
  const write = deps.write ?? import_promises.writeFile;
9859
10003
  const remove2 = deps.remove ?? import_promises.unlink;
9860
10004
  const ensureDir = deps.ensureDir ?? import_promises.mkdir;
9861
- const dir = deps.dir ?? (0, import_node_os4.tmpdir)();
9862
- const file = (0, import_node_path9.join)(dir, `mmi-gh-body-${process.pid}-${(0, import_node_crypto5.randomBytes)(4).toString("hex")}.md`);
9863
- await ensureDir((0, import_node_path9.dirname)(file), { recursive: true }).catch(() => {
10005
+ const dir = deps.dir ?? (0, import_node_os5.tmpdir)();
10006
+ const file = (0, import_node_path10.join)(dir, `mmi-gh-body-${process.pid}-${(0, import_node_crypto6.randomBytes)(4).toString("hex")}.md`);
10007
+ await ensureDir((0, import_node_path10.dirname)(file), { recursive: true }).catch(() => {
9864
10008
  });
9865
10009
  await write(file, args[i + 1], "utf8");
9866
10010
  return {
@@ -10188,8 +10332,8 @@ async function defaultRestCreatePr(exec2, input, deps = {}) {
10188
10332
  const write = deps.write ?? import_promises.writeFile;
10189
10333
  const remove2 = deps.remove ?? import_promises.unlink;
10190
10334
  const ensureDir = deps.ensureDir ?? import_promises.mkdir;
10191
- const dir = deps.dir ?? (0, import_node_os4.tmpdir)();
10192
- const file = (0, import_node_path9.join)(dir, `mmi-rest-pr-${process.pid}-${(0, import_node_crypto5.randomBytes)(4).toString("hex")}.json`);
10335
+ const dir = deps.dir ?? (0, import_node_os5.tmpdir)();
10336
+ const file = (0, import_node_path10.join)(dir, `mmi-rest-pr-${process.pid}-${(0, import_node_crypto6.randomBytes)(4).toString("hex")}.json`);
10193
10337
  const payload = {
10194
10338
  title: input.title,
10195
10339
  head: input.head,
@@ -10197,7 +10341,7 @@ async function defaultRestCreatePr(exec2, input, deps = {}) {
10197
10341
  };
10198
10342
  if (input.base) payload.base = input.base;
10199
10343
  if (input.draft) payload.draft = true;
10200
- await ensureDir((0, import_node_path9.dirname)(file), { recursive: true }).catch(() => {
10344
+ await ensureDir((0, import_node_path10.dirname)(file), { recursive: true }).catch(() => {
10201
10345
  });
10202
10346
  await write(file, JSON.stringify(payload), "utf8");
10203
10347
  const args = [
@@ -11133,7 +11277,7 @@ function resolveSpawnTarget(command, args, platform2 = process.platform) {
11133
11277
  }
11134
11278
  function spawnExitCode(status, signal) {
11135
11279
  if (status != null) return status;
11136
- const signo = signal ? import_node_os5.constants.signals[signal] : void 0;
11280
+ const signo = signal ? import_node_os6.constants.signals[signal] : void 0;
11137
11281
  return signo ? 128 + signo : 1;
11138
11282
  }
11139
11283
  function defaultSpawn(command, args, env) {
@@ -11589,14 +11733,14 @@ function findDuplicateLesson(source, openLessons) {
11589
11733
  }
11590
11734
 
11591
11735
  // src/session-identity.ts
11592
- var import_node_crypto6 = require("node:crypto");
11593
- var import_node_os8 = require("node:os");
11736
+ var import_node_crypto7 = require("node:crypto");
11737
+ var import_node_os9 = require("node:os");
11594
11738
 
11595
11739
  // src/plugin-guard-io.ts
11596
- var import_node_fs12 = require("node:fs");
11740
+ var import_node_fs13 = require("node:fs");
11597
11741
  var import_node_child_process5 = require("node:child_process");
11598
- var import_node_path10 = require("node:path");
11599
- var import_node_os7 = require("node:os");
11742
+ var import_node_path11 = require("node:path");
11743
+ var import_node_os8 = require("node:os");
11600
11744
 
11601
11745
  // src/marketplace-autoupdate.ts
11602
11746
  var KNOWN_MARKETPLACES_RELATIVE = [".claude", "plugins", "known_marketplaces.json"];
@@ -11740,8 +11884,8 @@ function buildPluginGuardLine(state, opts = {}) {
11740
11884
  }
11741
11885
 
11742
11886
  // src/host-doc-lock.ts
11743
- var import_node_fs11 = require("node:fs");
11744
- var import_node_os6 = require("node:os");
11887
+ var import_node_fs12 = require("node:fs");
11888
+ var import_node_os7 = require("node:os");
11745
11889
  var SHARED_DOC_LOCK_STALE_MS = 3e4;
11746
11890
  var SHARED_DOC_LOCK_ATTEMPTS = 50;
11747
11891
  var SHARED_DOC_LOCK_INTERVAL_MS = 100;
@@ -11754,7 +11898,7 @@ function lockContent(options) {
11754
11898
  }
11755
11899
  function readHolder(lockPath) {
11756
11900
  try {
11757
- const parsed = JSON.parse((0, import_node_fs11.readFileSync)(lockPath, "utf8"));
11901
+ const parsed = JSON.parse((0, import_node_fs12.readFileSync)(lockPath, "utf8"));
11758
11902
  if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return null;
11759
11903
  return parsed;
11760
11904
  } catch {
@@ -11766,7 +11910,7 @@ function lockAgeMs(lockPath, now) {
11766
11910
  const declared = typeof holder?.acquiredAt === "string" ? Date.parse(holder.acquiredAt) : Number.NaN;
11767
11911
  if (!Number.isNaN(declared)) return Math.max(0, now - declared);
11768
11912
  try {
11769
- return Math.max(0, now - (0, import_node_fs11.statSync)(lockPath).mtimeMs);
11913
+ return Math.max(0, now - (0, import_node_fs12.statSync)(lockPath).mtimeMs);
11770
11914
  } catch {
11771
11915
  return 0;
11772
11916
  }
@@ -11781,7 +11925,7 @@ function acquireSharedDocLock(documentPath, options) {
11781
11925
  const staleAfterMs = options.staleAfterMs ?? SHARED_DOC_LOCK_STALE_MS;
11782
11926
  const attempts = options.attempts ?? SHARED_DOC_LOCK_ATTEMPTS;
11783
11927
  const intervalMs = options.intervalMs ?? SHARED_DOC_LOCK_INTERVAL_MS;
11784
- const identity = { owner: options.owner, pid: process.pid, host: options.host ?? (0, import_node_os6.hostname)(), acquiredAt: (/* @__PURE__ */ new Date()).toISOString() };
11928
+ const identity = { owner: options.owner, pid: process.pid, host: options.host ?? (0, import_node_os7.hostname)(), acquiredAt: (/* @__PURE__ */ new Date()).toISOString() };
11785
11929
  const content = lockContent(identity);
11786
11930
  const sleep2 = (ms) => {
11787
11931
  Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
@@ -11789,9 +11933,9 @@ function acquireSharedDocLock(documentPath, options) {
11789
11933
  for (let attempt = 0; attempt < attempts; attempt += 1) {
11790
11934
  let fd;
11791
11935
  try {
11792
- fd = (0, import_node_fs11.openSync)(lockPath, "wx");
11793
- (0, import_node_fs11.writeSync)(fd, content);
11794
- (0, import_node_fs11.closeSync)(fd);
11936
+ fd = (0, import_node_fs12.openSync)(lockPath, "wx");
11937
+ (0, import_node_fs12.writeSync)(fd, content);
11938
+ (0, import_node_fs12.closeSync)(fd);
11795
11939
  return {
11796
11940
  documentPath,
11797
11941
  lockPath,
@@ -11804,11 +11948,11 @@ function acquireSharedDocLock(documentPath, options) {
11804
11948
  } catch (error) {
11805
11949
  if (fd !== void 0) {
11806
11950
  try {
11807
- (0, import_node_fs11.closeSync)(fd);
11951
+ (0, import_node_fs12.closeSync)(fd);
11808
11952
  } catch {
11809
11953
  }
11810
11954
  try {
11811
- (0, import_node_fs11.unlinkSync)(lockPath);
11955
+ (0, import_node_fs12.unlinkSync)(lockPath);
11812
11956
  } catch {
11813
11957
  }
11814
11958
  }
@@ -11817,12 +11961,12 @@ function acquireSharedDocLock(documentPath, options) {
11817
11961
  if (lockAgeMs(lockPath, Date.now()) >= staleAfterMs) {
11818
11962
  const aside = `${lockPath}.stale-${Date.now()}`;
11819
11963
  try {
11820
- (0, import_node_fs11.renameSync)(lockPath, aside);
11964
+ (0, import_node_fs12.renameSync)(lockPath, aside);
11821
11965
  } catch {
11822
11966
  continue;
11823
11967
  }
11824
11968
  try {
11825
- (0, import_node_fs11.rmSync)(aside, { force: true });
11969
+ (0, import_node_fs12.rmSync)(aside, { force: true });
11826
11970
  } catch {
11827
11971
  }
11828
11972
  continue;
@@ -11835,7 +11979,7 @@ function releaseSharedDocLock(handle) {
11835
11979
  try {
11836
11980
  const holder = readHolder(handle.lockPath);
11837
11981
  if (holder && holder.owner === handle.owner && Number(holder.pid) === handle.pid) {
11838
- (0, import_node_fs11.unlinkSync)(handle.lockPath);
11982
+ (0, import_node_fs12.unlinkSync)(handle.lockPath);
11839
11983
  }
11840
11984
  } catch {
11841
11985
  }
@@ -11982,25 +12126,25 @@ function runHostBin(bin, args, opts) {
11982
12126
  const argv = isWin ? ["/c", bin, ...args] : args;
11983
12127
  return step ? execFileHard(file, argv, { ...shared, step }) : execFileP(file, argv, shared);
11984
12128
  }
11985
- function hermesConfigRoot(env = process.env, home = (0, import_node_os7.homedir)(), platform2 = process.platform) {
12129
+ function hermesConfigRoot(env = process.env, home = (0, import_node_os8.homedir)(), platform2 = process.platform) {
11986
12130
  if (env.HERMES_HOME?.trim()) return env.HERMES_HOME.trim();
11987
- if (platform2 === "win32") return (0, import_node_path10.join)(env.LOCALAPPDATA?.trim() || (0, import_node_path10.join)(home, "AppData", "Local"), "hermes");
11988
- return (0, import_node_path10.join)(home, ".hermes");
12131
+ if (platform2 === "win32") return (0, import_node_path11.join)(env.LOCALAPPDATA?.trim() || (0, import_node_path11.join)(home, "AppData", "Local"), "hermes");
12132
+ return (0, import_node_path11.join)(home, ".hermes");
11989
12133
  }
11990
- function surfaceConfigRoot(surface, env = process.env, home = (0, import_node_os7.homedir)()) {
11991
- if (surface === "codex") return env.CODEX_HOME?.trim() || (0, import_node_path10.join)(home, ".codex");
12134
+ function surfaceConfigRoot(surface, env = process.env, home = (0, import_node_os8.homedir)()) {
12135
+ if (surface === "codex") return env.CODEX_HOME?.trim() || (0, import_node_path11.join)(home, ".codex");
11992
12136
  if (surface === "hermes") return hermesConfigRoot(env, home);
11993
12137
  if (surface === "jervcode") {
11994
- return env.JERVCODE_CODING_AGENT_DIR?.trim() || env.PI_CODING_AGENT_DIR?.trim() || (0, import_node_path10.join)(home, ".jerv", "agent");
12138
+ return env.JERVCODE_CODING_AGENT_DIR?.trim() || env.PI_CODING_AGENT_DIR?.trim() || (0, import_node_path11.join)(home, ".jerv", "agent");
11995
12139
  }
11996
- return (0, import_node_path10.join)(home, ".claude");
12140
+ return (0, import_node_path11.join)(home, ".claude");
11997
12141
  }
11998
12142
  var installedPluginsPath = (surface = detectSurface(process.env)) => {
11999
- return (0, import_node_path10.join)(surfaceConfigRoot(surface), "plugins", "installed_plugins.json");
12143
+ return (0, import_node_path11.join)(surfaceConfigRoot(surface), "plugins", "installed_plugins.json");
12000
12144
  };
12001
12145
  function readInstalledPlugins(surface = detectSurface(process.env)) {
12002
12146
  try {
12003
- return JSON.parse((0, import_node_fs12.readFileSync)(installedPluginsPath(surface), "utf8"));
12147
+ return JSON.parse((0, import_node_fs13.readFileSync)(installedPluginsPath(surface), "utf8"));
12004
12148
  } catch {
12005
12149
  return null;
12006
12150
  }
@@ -12009,15 +12153,15 @@ function marketplaceCloneCandidates(surface, home, env = process.env) {
12009
12153
  if (surface === "codex") {
12010
12154
  const root = surfaceConfigRoot(surface, env, home);
12011
12155
  return [
12012
- (0, import_node_path10.join)(root, ".tmp", "marketplaces", CODEX_MARKETPLACE),
12013
- (0, import_node_path10.join)(root, "plugins", "marketplaces", CODEX_MARKETPLACE)
12156
+ (0, import_node_path11.join)(root, ".tmp", "marketplaces", CODEX_MARKETPLACE),
12157
+ (0, import_node_path11.join)(root, "plugins", "marketplaces", CODEX_MARKETPLACE)
12014
12158
  ];
12015
12159
  }
12016
12160
  if (surface === "hermes") return [];
12017
12161
  if (surface === "jervcode") return [];
12018
- return [(0, import_node_path10.join)(home, ".claude", "plugins", "marketplaces", "mutmutco")];
12162
+ return [(0, import_node_path11.join)(home, ".claude", "plugins", "marketplaces", "mutmutco")];
12019
12163
  }
12020
- function marketplaceClonePresent(surface, home, exists = import_node_fs12.existsSync, env = process.env) {
12164
+ function marketplaceClonePresent(surface, home, exists = import_node_fs13.existsSync, env = process.env) {
12021
12165
  return marketplaceCloneCandidates(surface, home, env).some(exists);
12022
12166
  }
12023
12167
  function runHostBinSync(bin, args) {
@@ -12059,26 +12203,26 @@ async function fetchNpmReleasedVersion() {
12059
12203
  }
12060
12204
  }
12061
12205
  var JERVCODE_NPM_PACKAGE = "@mutmutco/pi-plugin";
12062
- function jervcodeAgentDirs(env = process.env, home = (0, import_node_os7.homedir)()) {
12206
+ function jervcodeAgentDirs(env = process.env, home = (0, import_node_os8.homedir)()) {
12063
12207
  const primary = surfaceConfigRoot("jervcode", env, home);
12064
- const legacy = (0, import_node_path10.join)(home, ".pi", "agent");
12208
+ const legacy = (0, import_node_path11.join)(home, ".pi", "agent");
12065
12209
  const dirs = [primary];
12066
12210
  if (legacy !== primary) dirs.push(legacy);
12067
- return dirs.filter((dir) => (0, import_node_fs12.existsSync)(dir));
12211
+ return dirs.filter((dir) => (0, import_node_fs13.existsSync)(dir));
12068
12212
  }
12069
12213
  function readPiSettings(path2) {
12070
- if (!(0, import_node_fs12.existsSync)(path2)) return void 0;
12214
+ if (!(0, import_node_fs13.existsSync)(path2)) return void 0;
12071
12215
  try {
12072
- const parsed = JSON.parse((0, import_node_fs12.readFileSync)(path2, "utf8"));
12216
+ const parsed = JSON.parse((0, import_node_fs13.readFileSync)(path2, "utf8"));
12073
12217
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return null;
12074
12218
  return parsed;
12075
12219
  } catch {
12076
12220
  return null;
12077
12221
  }
12078
12222
  }
12079
- function mmiPiPackageEntry(env = process.env, home = (0, import_node_os7.homedir)()) {
12223
+ function mmiPiPackageEntry(env = process.env, home = (0, import_node_os8.homedir)()) {
12080
12224
  for (const dir of jervcodeAgentDirs(env, home)) {
12081
- const settings = readPiSettings((0, import_node_path10.join)(dir, "settings.json"));
12225
+ const settings = readPiSettings((0, import_node_path11.join)(dir, "settings.json"));
12082
12226
  const entries = Array.isArray(settings?.packages) ? settings.packages : [];
12083
12227
  for (const entry of entries) {
12084
12228
  if (typeof entry !== "string") continue;
@@ -12088,10 +12232,10 @@ function mmiPiPackageEntry(env = process.env, home = (0, import_node_os7.homedir
12088
12232
  return null;
12089
12233
  }
12090
12234
  var LEGACY_MMI_PI_PATH = /[/\\]mutmutco[/\\]mmi[/\\]\d+\.\d+\.\d+[/\\]\.pi-plugin[/\\]?$/i;
12091
- function legacyMmiPiPathEntries(env = process.env, home = (0, import_node_os7.homedir)()) {
12235
+ function legacyMmiPiPathEntries(env = process.env, home = (0, import_node_os8.homedir)()) {
12092
12236
  const found = [];
12093
12237
  for (const dir of jervcodeAgentDirs(env, home)) {
12094
- const settings = readPiSettings((0, import_node_path10.join)(dir, "settings.json"));
12238
+ const settings = readPiSettings((0, import_node_path11.join)(dir, "settings.json"));
12095
12239
  const entries = Array.isArray(settings?.packages) ? settings.packages : [];
12096
12240
  for (const entry of entries) {
12097
12241
  if (typeof entry === "string" && LEGACY_MMI_PI_PATH.test(entry) && !found.includes(entry)) found.push(entry);
@@ -12099,37 +12243,37 @@ function legacyMmiPiPathEntries(env = process.env, home = (0, import_node_os7.ho
12099
12243
  }
12100
12244
  return found;
12101
12245
  }
12102
- function mmiPiPackageRoot(env = process.env, home = (0, import_node_os7.homedir)()) {
12246
+ function mmiPiPackageRoot(env = process.env, home = (0, import_node_os8.homedir)()) {
12103
12247
  for (const dir of jervcodeAgentDirs(env, home)) {
12104
- const root = (0, import_node_path10.join)(dir, "npm", "node_modules", ...JERVCODE_NPM_PACKAGE.split("/"));
12105
- if ((0, import_node_fs12.existsSync)((0, import_node_path10.join)(root, "package.json"))) return root;
12248
+ const root = (0, import_node_path11.join)(dir, "npm", "node_modules", ...JERVCODE_NPM_PACKAGE.split("/"));
12249
+ if ((0, import_node_fs13.existsSync)((0, import_node_path11.join)(root, "package.json"))) return root;
12106
12250
  }
12107
12251
  return null;
12108
12252
  }
12109
- function installedJervCodePackageVersion(env = process.env, home = (0, import_node_os7.homedir)()) {
12253
+ function installedJervCodePackageVersion(env = process.env, home = (0, import_node_os8.homedir)()) {
12110
12254
  const root = mmiPiPackageRoot(env, home);
12111
12255
  if (!root) return void 0;
12112
12256
  try {
12113
- const manifest = JSON.parse((0, import_node_fs12.readFileSync)((0, import_node_path10.join)(root, "package.json"), "utf8"));
12257
+ const manifest = JSON.parse((0, import_node_fs13.readFileSync)((0, import_node_path11.join)(root, "package.json"), "utf8"));
12114
12258
  return typeof manifest.version === "string" ? manifest.version : void 0;
12115
12259
  } catch {
12116
12260
  return void 0;
12117
12261
  }
12118
12262
  }
12119
- function mmiPiPackageHealthy(env = process.env, home = (0, import_node_os7.homedir)()) {
12263
+ function mmiPiPackageHealthy(env = process.env, home = (0, import_node_os8.homedir)()) {
12120
12264
  const root = mmiPiPackageRoot(env, home);
12121
- return Boolean(root && (0, import_node_fs12.existsSync)((0, import_node_path10.join)(root, "skills", "bootstrap", "SKILL.md")));
12265
+ return Boolean(root && (0, import_node_fs13.existsSync)((0, import_node_path11.join)(root, "skills", "bootstrap", "SKILL.md")));
12122
12266
  }
12123
12267
  function piDoctorEnv(agentDir) {
12124
12268
  return { ...process.env, PI_CODING_AGENT_DIR: agentDir };
12125
12269
  }
12126
- function hermesPluginRoot(env = process.env, home = (0, import_node_os7.homedir)()) {
12127
- return (0, import_node_path10.join)(hermesConfigRoot(env, home), "plugins", "mmi");
12270
+ function hermesPluginRoot(env = process.env, home = (0, import_node_os8.homedir)()) {
12271
+ return (0, import_node_path11.join)(hermesConfigRoot(env, home), "plugins", "mmi");
12128
12272
  }
12129
- function hermesPluginTreeHealthy(root, exists = import_node_fs12.existsSync) {
12130
- if (!["plugin.yaml", "__init__.py"].every((file) => exists((0, import_node_path10.join)(root, file)))) return false;
12273
+ function hermesPluginTreeHealthy(root, exists = import_node_fs13.existsSync) {
12274
+ if (!["plugin.yaml", "__init__.py"].every((file) => exists((0, import_node_path11.join)(root, file)))) return false;
12131
12275
  try {
12132
- return (0, import_node_fs12.statSync)((0, import_node_path10.join)(root, "skills")).isDirectory();
12276
+ return (0, import_node_fs13.statSync)((0, import_node_path11.join)(root, "skills")).isDirectory();
12133
12277
  } catch {
12134
12278
  return false;
12135
12279
  }
@@ -12144,12 +12288,12 @@ function snapshotPluginGuardInput(surface = detectSurface(process.env), isOrgRep
12144
12288
  // Codex's native projection is authoritative; its legacy installed_plugins.json may be empty
12145
12289
  // while `plugin list --json` proves the managed plugin installed (#6111).
12146
12290
  installRecordPresent: surface === "codex" ? codexStatus?.installed === true : hasUserInstallRecord(installed, MMI_PLUGIN_ID) || hasProjectInstallRecord(installed, MMI_PLUGIN_ID, process.cwd()) || // #4188: jervcode's install record is the settings-file packages[] entry itself.
12147
- surface === "jervcode" && piEntry !== null || surface === "hermes" && (0, import_node_fs12.existsSync)(hermesPluginRoot()),
12291
+ surface === "jervcode" && piEntry !== null || surface === "hermes" && (0, import_node_fs13.existsSync)(hermesPluginRoot()),
12148
12292
  // JervCode's settings entry and native local surfaces have no marketplace clone.
12149
- marketplaceClonePresent: surface === "jervcode" || surface === "hermes" ? true : marketplaceClonePresent(surface, (0, import_node_os7.homedir)()),
12293
+ marketplaceClonePresent: surface === "jervcode" || surface === "hermes" ? true : marketplaceClonePresent(surface, (0, import_node_os8.homedir)()),
12150
12294
  pluginCachePresent: surface === "jervcode" ? mmiPiPackageHealthy() : surface === "hermes" ? hermesPluginTreeHealthy(hermesPluginRoot()) : surface === "codex" ? Boolean(
12151
- codexStatus?.installed && codexStatus.enabled && codexStatus.version && (0, import_node_fs12.existsSync)((0, import_node_path10.join)(root, "plugins", "cache", CODEX_MARKETPLACE, "mmi", codexStatus.version))
12152
- ) : (0, import_node_fs12.existsSync)((0, import_node_path10.join)(root, "plugins", "cache", "mutmutco", "mmi"))
12295
+ codexStatus?.installed && codexStatus.enabled && codexStatus.version && (0, import_node_fs13.existsSync)((0, import_node_path11.join)(root, "plugins", "cache", CODEX_MARKETPLACE, "mmi", codexStatus.version))
12296
+ ) : (0, import_node_fs13.existsSync)((0, import_node_path11.join)(root, "plugins", "cache", "mutmutco", "mmi"))
12153
12297
  };
12154
12298
  }
12155
12299
  async function runPluginCli(bin, args, log) {
@@ -12196,7 +12340,7 @@ async function runHealSteps(host, tableSteps, deps) {
12196
12340
  const refSupported = needsRefProbe ? await marketplaceAddRefSupported(host) : true;
12197
12341
  const { steps } = adaptHealStepsForRefSupport(tableSteps, refSupported);
12198
12342
  if (deps.banner) log(deps.banner(refSupported));
12199
- const pinsPath = (0, import_node_path10.join)((0, import_node_os7.homedir)(), ...KNOWN_MARKETPLACES_RELATIVE);
12343
+ const pinsPath = (0, import_node_path11.join)((0, import_node_os8.homedir)(), ...KNOWN_MARKETPLACES_RELATIVE);
12200
12344
  const pins = host === "claude" ? captureMarketplacePins(readKnownMarketplacesFile(pinsPath), [MMI_MARKETPLACE_NAME, JERV_MARKETPLACE_NAME]) : /* @__PURE__ */ new Map();
12201
12345
  let failure;
12202
12346
  try {
@@ -12307,7 +12451,7 @@ async function healActivePluginForDoctor(surface = detectSurface(process.env), o
12307
12451
  }
12308
12452
  function readKnownMarketplacesFile(path2) {
12309
12453
  try {
12310
- return (0, import_node_fs12.existsSync)(path2) ? (0, import_node_fs12.readFileSync)(path2, "utf8") : void 0;
12454
+ return (0, import_node_fs13.existsSync)(path2) ? (0, import_node_fs13.readFileSync)(path2, "utf8") : void 0;
12311
12455
  } catch {
12312
12456
  return void 0;
12313
12457
  }
@@ -12341,11 +12485,11 @@ function writeMarketplacePinsOnDisk(path2, pins, succeeded, failedVerb, declineW
12341
12485
  if (declined) return declined;
12342
12486
  const tmp = `${path2}.tmp-${process.pid}`;
12343
12487
  try {
12344
- (0, import_node_fs12.writeFileSync)(tmp, next, "utf8");
12345
- (0, import_node_fs12.renameSync)(tmp, path2);
12488
+ (0, import_node_fs13.writeFileSync)(tmp, next, "utf8");
12489
+ (0, import_node_fs13.renameSync)(tmp, path2);
12346
12490
  } catch {
12347
12491
  try {
12348
- (0, import_node_fs12.rmSync)(tmp, { force: true });
12492
+ (0, import_node_fs13.rmSync)(tmp, { force: true });
12349
12493
  } catch {
12350
12494
  }
12351
12495
  return `could NOT ${failedVerb} ${[...pins.keys()].join(", ")} \u2014 set it by hand`;
@@ -12473,7 +12617,7 @@ function readSessionIdSource(env) {
12473
12617
  var synthesizedSessionId;
12474
12618
  function fallbackSessionId(surface) {
12475
12619
  if (!synthesizedSessionId) {
12476
- synthesizedSessionId = `${SYNTH_SESSION_PREFIX}${surface}-${process.pid}-${(0, import_node_crypto6.randomBytes)(3).toString("hex")}`;
12620
+ synthesizedSessionId = `${SYNTH_SESSION_PREFIX}${surface}-${process.pid}-${(0, import_node_crypto7.randomBytes)(3).toString("hex")}`;
12477
12621
  }
12478
12622
  return synthesizedSessionId;
12479
12623
  }
@@ -12482,7 +12626,7 @@ function describeSessionIdentity(env = process.env) {
12482
12626
  return {
12483
12627
  session: readSessionId(env) ?? fallbackSessionId(surface),
12484
12628
  surface,
12485
- host: (0, import_node_os8.hostname)()
12629
+ host: (0, import_node_os9.hostname)()
12486
12630
  };
12487
12631
  }
12488
12632
  function formatSessionIdentity(identity) {
@@ -13182,7 +13326,7 @@ function renderBoardSource() {
13182
13326
  return "source: live";
13183
13327
  }
13184
13328
  async function collectBoardPreferringSnapshot(cfg, options, deps) {
13185
- if (options.snapshotOnly && !deps.snapshot) throw new Error("--snapshot-only needs the Hub snapshot transport (not with --direct)");
13329
+ if (options.snapshotOnly && !deps.snapshot) throw new BoardSnapshotFailure({ ok: false, outcome: "hub-unreachable", reason: "--snapshot-only needs the Hub snapshot transport (not with --direct)" });
13186
13330
  const attempt = deps.snapshot ? await fetchHubBoardSnapshot(
13187
13331
  {
13188
13332
  owner: cfg.projectOwner,
@@ -13195,6 +13339,7 @@ async function collectBoardPreferringSnapshot(cfg, options, deps) {
13195
13339
  deps.snapshot
13196
13340
  ) : void 0;
13197
13341
  if (attempt?.state === "refused") {
13342
+ if (options.snapshotOnly) throw new BoardSnapshotFailure({ ok: false, outcome: "refused", reason: attempt.reason });
13198
13343
  throw new Error(attempt.reason);
13199
13344
  }
13200
13345
  if (attempt?.state === "ok") {
@@ -13224,7 +13369,16 @@ async function collectBoardPreferringSnapshot(cfg, options, deps) {
13224
13369
  };
13225
13370
  }
13226
13371
  if (options.snapshotOnly && attempt?.state === "unavailable") {
13227
- throw Object.assign(new Error(`Hub board snapshot unavailable (${attempt.reason}) \u2014 --snapshot-only refuses the direct user-auth fallback`), { quota: attempt.quota });
13372
+ throw Object.assign(new BoardSnapshotFailure({
13373
+ ok: false,
13374
+ outcome: attempt.appQuotaExhausted ? "app-quota-exhausted" : "hub-unreachable",
13375
+ reason: `Hub board snapshot unavailable (${attempt.reason}) \u2014 --snapshot-only refuses the direct user-auth fallback`,
13376
+ ...attempt.resetAt ? { resetAt: attempt.resetAt } : {},
13377
+ ...attempt.pool ? { pool: attempt.pool } : {}
13378
+ }), { quota: attempt.quota });
13379
+ }
13380
+ if (attempt?.state === "unavailable" && attempt.appQuotaExhausted) {
13381
+ throw Object.assign(new Error(`Hub board snapshot unavailable (${attempt.reason}) \u2014 the personal-token fallback is refused while the org App allowance is exhausted; retry after the reset`), { quota: attempt.quota });
13228
13382
  }
13229
13383
  const collected = await collectBoardItems(cfg, { repo: options.repo, allowPartial: options.allowPartial, activeOnly: true }, deps);
13230
13384
  if (attempt?.state === "unavailable") {
@@ -13907,7 +14061,7 @@ var CLAIM_SESSION_ACTIVITY_MS = 30 * 6e4;
13907
14061
  var CLAIM_SESSION_PROBE_CACHE_MS = 6e4;
13908
14062
  var claimSessionProbeCache = /* @__PURE__ */ new Map();
13909
14063
  function probeLocalClaimSession(marker, now = Date.now()) {
13910
- if (!marker.session || !marker.host || marker.host.toLowerCase() !== (0, import_node_os9.hostname)().toLowerCase()) return void 0;
14064
+ if (!marker.session || !marker.host || marker.host.toLowerCase() !== (0, import_node_os10.hostname)().toLowerCase()) return void 0;
13911
14065
  if (!marker.surface?.toLowerCase().startsWith("claude")) return void 0;
13912
14066
  const cacheKey = `${marker.host.toLowerCase()}/${marker.session}`;
13913
14067
  const cached = claimSessionProbeCache.get(cacheKey);
@@ -13916,17 +14070,17 @@ function probeLocalClaimSession(marker, now = Date.now()) {
13916
14070
  claimSessionProbeCache.set(cacheKey, { checkedAt: now, state });
13917
14071
  return state;
13918
14072
  };
13919
- const root = (0, import_node_path11.join)((0, import_node_os9.homedir)(), ".claude", "projects");
14073
+ const root = (0, import_node_path12.join)((0, import_node_os10.homedir)(), ".claude", "projects");
13920
14074
  try {
13921
14075
  const wanted = `${marker.session}.jsonl`.toLowerCase();
13922
14076
  const pending = [root];
13923
14077
  while (pending.length) {
13924
14078
  const dir = pending.pop();
13925
- for (const entry of (0, import_node_fs13.readdirSync)(dir, { withFileTypes: true })) {
13926
- const path2 = (0, import_node_path11.join)(dir, entry.name);
14079
+ for (const entry of (0, import_node_fs14.readdirSync)(dir, { withFileTypes: true })) {
14080
+ const path2 = (0, import_node_path12.join)(dir, entry.name);
13927
14081
  if (entry.isDirectory()) pending.push(path2);
13928
14082
  else if (entry.isFile() && entry.name.toLowerCase() === wanted) {
13929
- return remember(now - (0, import_node_fs13.statSync)(path2).mtimeMs <= CLAIM_SESSION_ACTIVITY_MS ? "live" : "dead");
14083
+ return remember(now - (0, import_node_fs14.statSync)(path2).mtimeMs <= CLAIM_SESSION_ACTIVITY_MS ? "live" : "dead");
13930
14084
  }
13931
14085
  }
13932
14086
  }
@@ -15179,7 +15333,7 @@ async function propagateMayAutoMerge(repo, repoClass, rest) {
15179
15333
  }
15180
15334
 
15181
15335
  // src/bootstrap-apply.ts
15182
- var import_node_crypto7 = require("node:crypto");
15336
+ var import_node_crypto8 = require("node:crypto");
15183
15337
 
15184
15338
  // src/bootstrap-seeds.ts
15185
15339
  var PLACEHOLDER_RE = /\{\{([A-Z0-9_]+)\}\}/g;
@@ -15418,13 +15572,13 @@ function planManagedGitignore(current) {
15418
15572
  }
15419
15573
 
15420
15574
  // src/docs-index-command.ts
15421
- var import_node_fs15 = require("node:fs");
15422
- var import_node_path13 = require("node:path");
15575
+ var import_node_fs16 = require("node:fs");
15576
+ var import_node_path14 = require("node:path");
15423
15577
 
15424
15578
  // src/doc-refs-core.ts
15425
15579
  var import_node_child_process6 = require("node:child_process");
15426
- var import_node_fs14 = require("node:fs");
15427
- var import_node_path12 = require("node:path");
15580
+ var import_node_fs15 = require("node:fs");
15581
+ var import_node_path13 = require("node:path");
15428
15582
  var PIN_RE = /<!--\s*pinned by\s+([^:]+?)\s*:\s*"([^"]+)"[^"]*-->/;
15429
15583
  var PIN_MENTION_RE = /<!--\s*pinned by\b/;
15430
15584
  var FWD_RE = /<!--\s*forward-ref:\s*(\S+?)\s*-->/;
@@ -15483,7 +15637,7 @@ function checkPins(root, readFile10, docs) {
15483
15637
  findings.push({ kind: "malformed-pin", doc, line: pin.line, detail: pin.text });
15484
15638
  continue;
15485
15639
  }
15486
- const source = readFile10((0, import_node_path12.join)(root, pin.file));
15640
+ const source = readFile10((0, import_node_path13.join)(root, pin.file));
15487
15641
  if (source == null) {
15488
15642
  findings.push({ kind: "missing-test", doc, line: pin.line, detail: pin.file });
15489
15643
  continue;
@@ -15546,11 +15700,11 @@ function checkRefs(root, deps, docs) {
15546
15700
  for (const { ref } of extractRefs(markdown)) allFirstSegments.add(refFirstSegment(ref));
15547
15701
  }
15548
15702
  const tracked = allFirstSegments.size ? deps.trackedFirstSegments?.([...allFirstSegments]) ?? null : null;
15549
- const firstVerifiable = (first) => tracked ? tracked.has(first) : exists((0, import_node_path12.join)(root, first));
15703
+ const firstVerifiable = (first) => tracked ? tracked.has(first) : exists((0, import_node_path13.join)(root, first));
15550
15704
  const candidates = [];
15551
15705
  const direct = [];
15552
15706
  for (const [doc, markdown] of Object.entries(docs)) {
15553
- const docDir = import_node_path12.posix.dirname(doc);
15707
+ const docDir = import_node_path13.posix.dirname(doc);
15554
15708
  const base = docDir === "." ? "" : docDir;
15555
15709
  const covered = /* @__PURE__ */ new Set();
15556
15710
  const markers = [];
@@ -15559,21 +15713,21 @@ function checkRefs(root, deps, docs) {
15559
15713
  direct.push({ kind: "malformed-forward-ref", doc, line: fwd.line, detail: fwd.text });
15560
15714
  continue;
15561
15715
  }
15562
- const docRel = import_node_path12.posix.normalize(import_node_path12.posix.join(base, fwd.target));
15563
- const rootRel = import_node_path12.posix.normalize(fwd.target.replace(/^\/+/, ""));
15716
+ const docRel = import_node_path13.posix.normalize(import_node_path13.posix.join(base, fwd.target));
15717
+ const rootRel = import_node_path13.posix.normalize(fwd.target.replace(/^\/+/, ""));
15564
15718
  markers.push({ target: fwd.target, line: fwd.line, docRel, rootRel });
15565
15719
  covered.add(docRel);
15566
15720
  covered.add(rootRel);
15567
15721
  }
15568
15722
  const links = extractLinks(markdown).map(({ target, line }) => {
15569
- const resolved = import_node_path12.posix.normalize(import_node_path12.posix.join(base, target));
15570
- return { target, line, resolved, missing: !exists((0, import_node_path12.join)(root, resolved)) };
15723
+ const resolved = import_node_path13.posix.normalize(import_node_path13.posix.join(base, target));
15724
+ return { target, line, resolved, missing: !exists((0, import_node_path13.join)(root, resolved)) };
15571
15725
  });
15572
15726
  for (const marker of markers) {
15573
15727
  const coversMissing = links.some(
15574
15728
  (l) => l.missing && (l.resolved === marker.docRel || l.resolved === marker.rootRel)
15575
15729
  );
15576
- if (!coversMissing && (exists((0, import_node_path12.join)(root, marker.docRel)) || exists((0, import_node_path12.join)(root, marker.rootRel)))) {
15730
+ if (!coversMissing && (exists((0, import_node_path13.join)(root, marker.docRel)) || exists((0, import_node_path13.join)(root, marker.rootRel)))) {
15577
15731
  direct.push({
15578
15732
  kind: "stale-forward-ref",
15579
15733
  doc,
@@ -15584,7 +15738,7 @@ function checkRefs(root, deps, docs) {
15584
15738
  }
15585
15739
  for (const { ref, line } of extractRefs(markdown)) {
15586
15740
  if (!firstVerifiable(refFirstSegment(ref))) continue;
15587
- if (!exists((0, import_node_path12.join)(root, ref))) candidates.push({ kind: "missing-path", doc, line, detail: ref });
15741
+ if (!exists((0, import_node_path13.join)(root, ref))) candidates.push({ kind: "missing-path", doc, line, detail: ref });
15588
15742
  }
15589
15743
  for (const { target, line, resolved, missing } of links) {
15590
15744
  if (resolved.startsWith("..")) {
@@ -15632,24 +15786,24 @@ function checkCommands(docs, commandPaths) {
15632
15786
  return { ok: findings.length === 0, findings, warnings: [] };
15633
15787
  }
15634
15788
  function readFileOrNull(path2) {
15635
- return (0, import_node_fs14.existsSync)(path2) ? (0, import_node_fs14.readFileSync)(path2, "utf8") : null;
15789
+ return (0, import_node_fs15.existsSync)(path2) ? (0, import_node_fs15.readFileSync)(path2, "utf8") : null;
15636
15790
  }
15637
15791
  function walk(dir, root, out) {
15638
- for (const entry of (0, import_node_fs14.readdirSync)(dir)) {
15639
- const full = (0, import_node_path12.join)(dir, entry);
15640
- if ((0, import_node_fs14.statSync)(full).isDirectory()) walk(full, root, out);
15792
+ for (const entry of (0, import_node_fs15.readdirSync)(dir)) {
15793
+ const full = (0, import_node_path13.join)(dir, entry);
15794
+ if ((0, import_node_fs15.statSync)(full).isDirectory()) walk(full, root, out);
15641
15795
  else if (entry.endsWith(".md")) out.push(full.slice(root.length + 1).replaceAll("\\", "/"));
15642
15796
  }
15643
15797
  return out;
15644
15798
  }
15645
15799
  function defaultListDocs(root) {
15646
15800
  const docs = ["docs", "skills/org-guide", "skills/mmi-help"].flatMap((path2) => {
15647
- const directory = (0, import_node_path12.join)(root, path2);
15648
- return (0, import_node_fs14.existsSync)(directory) ? walk(directory, root, []) : [];
15801
+ const directory = (0, import_node_path13.join)(root, path2);
15802
+ return (0, import_node_fs15.existsSync)(directory) ? walk(directory, root, []) : [];
15649
15803
  }).filter(
15650
15804
  (rel) => !SKIP_WALK.some((skip) => rel.startsWith(skip))
15651
15805
  );
15652
- return [...ROOT_DOCS.filter((rel) => (0, import_node_fs14.existsSync)((0, import_node_path12.join)(root, rel))), ...docs];
15806
+ return [...ROOT_DOCS.filter((rel) => (0, import_node_fs15.existsSync)((0, import_node_path13.join)(root, rel))), ...docs];
15653
15807
  }
15654
15808
  var CHECK_IGNORE_MAX_BUFFER = 32 * 1024 * 1024;
15655
15809
  function defaultIsIgnored(root, relPaths, exec2 = import_node_child_process6.execFileSync) {
@@ -15701,7 +15855,7 @@ function defaultTrackedFirstSegments(root, firstSegments, exec2 = import_node_ch
15701
15855
  }
15702
15856
  function runDocRefs(root, deps = {}) {
15703
15857
  const readFile10 = deps.readFile ?? readFileOrNull;
15704
- const exists = deps.exists ?? import_node_fs14.existsSync;
15858
+ const exists = deps.exists ?? import_node_fs15.existsSync;
15705
15859
  const listDocs = deps.listDocs ?? defaultListDocs;
15706
15860
  const isIgnored = deps.isIgnored ?? ((paths) => defaultIsIgnored(root, paths));
15707
15861
  const trackedFirstSegments = deps.trackedFirstSegments ?? ((segs) => defaultTrackedFirstSegments(root, segs));
@@ -15709,7 +15863,7 @@ function runDocRefs(root, deps = {}) {
15709
15863
  const walked = listDocs(root);
15710
15864
  const ignoredDocs = walked.length ? isIgnored(walked) : /* @__PURE__ */ new Set();
15711
15865
  const docs = Object.fromEntries(
15712
- walked.filter((rel) => !ignoredDocs.has(rel)).map((rel) => [rel, readFile10((0, import_node_path12.join)(root, rel))]).filter(([, body]) => body != null)
15866
+ walked.filter((rel) => !ignoredDocs.has(rel)).map((rel) => [rel, readFile10((0, import_node_path13.join)(root, rel))]).filter(([, body]) => body != null)
15713
15867
  );
15714
15868
  const refResult = checkRefs(root, { exists, isIgnored, trackedFirstSegments }, docs);
15715
15869
  const findings = [
@@ -15816,31 +15970,31 @@ function walkMarkdown(dir) {
15816
15970
  const stack = [dir];
15817
15971
  while (stack.length) {
15818
15972
  const current = stack.pop();
15819
- for (const entry of (0, import_node_fs15.readdirSync)(current, { withFileTypes: true })) {
15820
- const full = (0, import_node_path13.join)(current, entry.name);
15973
+ for (const entry of (0, import_node_fs16.readdirSync)(current, { withFileTypes: true })) {
15974
+ const full = (0, import_node_path14.join)(current, entry.name);
15821
15975
  if (entry.isDirectory()) {
15822
15976
  stack.push(full);
15823
15977
  } else if (entry.isFile() && entry.name.endsWith(".md")) {
15824
- out.push((0, import_node_path13.relative)(dir, full).split(import_node_path13.sep).join("/"));
15978
+ out.push((0, import_node_path14.relative)(dir, full).split(import_node_path14.sep).join("/"));
15825
15979
  }
15826
15980
  }
15827
15981
  }
15828
15982
  return out;
15829
15983
  }
15830
15984
  function createDocsIndexDeps(repoRoot2) {
15831
- const docsDir = (0, import_node_path13.join)(repoRoot2, "docs");
15832
- const indexPath = (0, import_node_path13.join)(repoRoot2, DOCS_INDEX_PATH);
15985
+ const docsDir = (0, import_node_path14.join)(repoRoot2, "docs");
15986
+ const indexPath = (0, import_node_path14.join)(repoRoot2, DOCS_INDEX_PATH);
15833
15987
  return {
15834
15988
  listDocs: () => {
15835
- if (!(0, import_node_fs15.existsSync)(docsDir)) return [];
15989
+ if (!(0, import_node_fs16.existsSync)(docsDir)) return [];
15836
15990
  const walked = walkMarkdown(docsDir).filter(isRoutableDocsPath);
15837
15991
  if (!walked.length) return [];
15838
15992
  const ignored = defaultIsIgnored(repoRoot2, walked.map((rel) => `docs/${rel}`));
15839
15993
  return walked.filter((rel) => !ignored.has(`docs/${rel}`)).sort();
15840
15994
  },
15841
- readDoc: (relPath) => (0, import_node_fs15.readFileSync)((0, import_node_path13.join)(docsDir, relPath), "utf8"),
15842
- readIndex: () => (0, import_node_fs15.existsSync)(indexPath) ? (0, import_node_fs15.readFileSync)(indexPath, "utf8") : null,
15843
- writeIndex: (content) => (0, import_node_fs15.writeFileSync)(indexPath, content, "utf8")
15995
+ readDoc: (relPath) => (0, import_node_fs16.readFileSync)((0, import_node_path14.join)(docsDir, relPath), "utf8"),
15996
+ readIndex: () => (0, import_node_fs16.existsSync)(indexPath) ? (0, import_node_fs16.readFileSync)(indexPath, "utf8") : null,
15997
+ writeIndex: (content) => (0, import_node_fs16.writeFileSync)(indexPath, content, "utf8")
15844
15998
  };
15845
15999
  }
15846
16000
 
@@ -16446,7 +16600,7 @@ function planSeedAction(seed, exists) {
16446
16600
  return exists ? { target: seed.target, action: "update", ownership: "org", reason: "org-owned, refresh to current" } : { target: seed.target, action: "create", ownership: "org", reason: "org-owned, missing" };
16447
16601
  }
16448
16602
  var GATE_RENDER_NOTE = "# Rendered from the registry gate config by mmi-cli devops bootstrap apply <repo> --only gate.yml --from-config; edit the config, not this file.\n";
16449
- var gateHash = (body) => (0, import_node_crypto7.createHash)("sha256").update(body, "utf8").digest("hex");
16603
+ var gateHash = (body) => (0, import_node_crypto8.createHash)("sha256").update(body, "utf8").digest("hex");
16450
16604
  function parseGateRenderStamp(content) {
16451
16605
  const match = /^# mmi-gate-render: sha256=([a-f0-9]{64})\n/.exec(content);
16452
16606
  return match ? { hash: match[1], body: content.slice(match[0].length) } : null;
@@ -16753,8 +16907,8 @@ function contentPutInputArgs(repo, path2, inputFile) {
16753
16907
  }
16754
16908
 
16755
16909
  // src/train-apply-contracts.ts
16756
- var import_node_fs16 = require("node:fs");
16757
- var import_node_path14 = require("node:path");
16910
+ var import_node_fs17 = require("node:fs");
16911
+ var import_node_path15 = require("node:path");
16758
16912
  function reduceFollowUpOutcomes(outcomes) {
16759
16913
  if (outcomes.includes("failure")) return "failure";
16760
16914
  if (outcomes.includes("unresolved")) return "unresolved";
@@ -16834,7 +16988,7 @@ async function resolveFoldPaths(deps, model) {
16834
16988
  if (model === "vercel") return [];
16835
16989
  const helper = "scripts/release-distribution.mjs";
16836
16990
  if (model === "hub-serverless" || model === "registry-publish") {
16837
- if ((0, import_node_fs16.existsSync)(helper)) {
16991
+ if ((0, import_node_fs17.existsSync)(helper)) {
16838
16992
  let out;
16839
16993
  try {
16840
16994
  out = await deps.run("node", [helper, "changed-files"]);
@@ -16973,7 +17127,7 @@ async function restoreMainNpmPackIdentities(deps, version) {
16973
17127
  if (mainBom.version !== version) return void 0;
16974
17128
  let localBom;
16975
17129
  try {
16976
- localBom = JSON.parse((0, import_node_fs16.readFileSync)(bomPath, "utf8"));
17130
+ localBom = JSON.parse((0, import_node_fs17.readFileSync)(bomPath, "utf8"));
16977
17131
  } catch (e) {
16978
17132
  throw new Error(
16979
17133
  `version fold refused: ${bomPath} written by this fold's prepare is unreadable (${describeReadError(e)}) \u2014 cannot restore the published ${version} npm-pack identities from origin/main (#4503/#4713).`
@@ -16991,14 +17145,14 @@ async function restoreMainNpmPackIdentities(deps, version) {
16991
17145
  restored += 1;
16992
17146
  }
16993
17147
  if (restored === 0) return void 0;
16994
- (0, import_node_fs16.writeFileSync)(bomPath, `${JSON.stringify(localBom, null, 2)}
17148
+ (0, import_node_fs17.writeFileSync)(bomPath, `${JSON.stringify(localBom, null, 2)}
16995
17149
  `);
16996
17150
  return `restored ${restored} npm-pack BOM identit${restored === 1 ? "y" : "ies"} from origin/main (#4503)`;
16997
17151
  }
16998
17152
  function publishVisibilityFor(surfaceId) {
16999
17153
  let raw;
17000
17154
  try {
17001
- raw = (0, import_node_fs16.readFileSync)("surfaces.json", "utf8");
17155
+ raw = (0, import_node_fs17.readFileSync)("surfaces.json", "utf8");
17002
17156
  } catch (e) {
17003
17157
  if (e.code === "ENOENT") return "unknown";
17004
17158
  throw trainReadFailure(
@@ -17019,7 +17173,7 @@ function publishVisibilityFor(surfaceId) {
17019
17173
  }
17020
17174
  function npmPackArtifactName(packagePath) {
17021
17175
  try {
17022
- const pkg = JSON.parse((0, import_node_fs16.readFileSync)((0, import_node_path14.join)(packagePath, "package.json"), "utf8"));
17176
+ const pkg = JSON.parse((0, import_node_fs17.readFileSync)((0, import_node_path15.join)(packagePath, "package.json"), "utf8"));
17023
17177
  return pkg.name || void 0;
17024
17178
  } catch {
17025
17179
  return void 0;
@@ -17028,7 +17182,7 @@ function npmPackArtifactName(packagePath) {
17028
17182
  async function refuseDivergentPublishedNpmPack(deps, version) {
17029
17183
  let localBom;
17030
17184
  try {
17031
- localBom = JSON.parse((0, import_node_fs16.readFileSync)("distribution-bom.json", "utf8"));
17185
+ localBom = JSON.parse((0, import_node_fs17.readFileSync)("distribution-bom.json", "utf8"));
17032
17186
  } catch (e) {
17033
17187
  throw new Error(
17034
17188
  `version fold refused: distribution-bom.json written by this fold's prepare is unreadable (${e instanceof Error ? e.message.split("\n")[0] : String(e)}) \u2014 cannot compare the same-PATCH ${version} npm-pack identities against published npm (#4503/#4662).`
@@ -17173,8 +17327,8 @@ function assertGitBashOnWindowsForJervHubRelease(repo, platform2 = process.platf
17173
17327
  }
17174
17328
 
17175
17329
  // src/train-apply-correlation.ts
17176
- var import_node_fs18 = require("node:fs");
17177
- var import_node_path16 = require("node:path");
17330
+ var import_node_fs19 = require("node:fs");
17331
+ var import_node_path17 = require("node:path");
17178
17332
 
17179
17333
  // src/fleet-lockstep-enforce.ts
17180
17334
  init_github_client();
@@ -17939,10 +18093,10 @@ var rollout_plan_default = {
17939
18093
  note: "The v4.0.0 stamp happens at cut time (D6e #4463); until then the candidate is the origin/development head artifacts (built cli/dist + npm pack), identity proven by dist content hash (D6a)."
17940
18094
  },
17941
18095
  baseline: {
17942
- version: "4.5.117",
17943
- tag: "v4.5.117",
17944
- commit: "8ec1a0aa6b67",
17945
- npm: "@mutmutco/cli@4.5.117"
18096
+ version: "4.5.119",
18097
+ tag: "v4.5.119",
18098
+ commit: "1682b1bdb4b1",
18099
+ npm: "@mutmutco/cli@4.5.119"
17946
18100
  },
17947
18101
  exitCriterion: "fleet-n-of-n",
17948
18102
  hubOnlyShortcut: "forbidden",
@@ -17959,14 +18113,14 @@ var rollout_plan_default = {
17959
18113
  repo: "mutmutco/mmi-hub",
17960
18114
  role: "canary",
17961
18115
  schedule: "train",
17962
- v3Target: "v4.5.117"
18116
+ v3Target: "v4.5.119"
17963
18117
  }
17964
18118
  ],
17965
18119
  rollbackTrigger: "Any red inside the post-contract soak window: `devops train gate` FAIL attributable to the v4 doors, Hub endpoint health probe failure, a pre-v4 client admitted instead of receiving actionable HTTP 426, or npm consumer install/doctor failure on the v4-only dist.",
17966
18120
  rollback: {
17967
18121
  independent: true,
17968
- mechanism: "npm dist-tag latest -> 4.5.117 and redeploy the Hub Lambda from tag v4.5.117 (8ec1a0aa6b67); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
17969
- v3Target: "v4.5.117 (@mutmutco/cli@4.5.117, tag commit 8ec1a0aa6b67 \u2014 last known-good release carrying the repo-index v4-only contract)"
18122
+ mechanism: "npm dist-tag latest -> 4.5.119 and redeploy the Hub Lambda from tag v4.5.119 (1682b1bdb4b1); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
18123
+ v3Target: "v4.5.119 (@mutmutco/cli@4.5.119, tag commit 1682b1bdb4b1 \u2014 last known-good release carrying the repo-index v4-only contract)"
17970
18124
  }
17971
18125
  },
17972
18126
  {
@@ -18300,13 +18454,13 @@ function resolveIssueViewGhFields(normalized) {
18300
18454
  }
18301
18455
 
18302
18456
  // src/utf8-receipt.ts
18303
- var import_node_fs17 = require("node:fs");
18304
- var import_node_path15 = require("node:path");
18457
+ var import_node_fs18 = require("node:fs");
18458
+ var import_node_path16 = require("node:path");
18305
18459
  function writeUtf8Receipt(path2, text) {
18306
- (0, import_node_fs17.mkdirSync)((0, import_node_path15.dirname)(path2), { recursive: true });
18460
+ (0, import_node_fs18.mkdirSync)((0, import_node_path16.dirname)(path2), { recursive: true });
18307
18461
  const body = text.endsWith("\n") ? text : `${text}
18308
18462
  `;
18309
- (0, import_node_fs17.writeFileSync)(path2, body, "utf8");
18463
+ (0, import_node_fs18.writeFileSync)(path2, body, "utf8");
18310
18464
  return Buffer.byteLength(body, "utf8");
18311
18465
  }
18312
18466
 
@@ -20174,7 +20328,7 @@ function resolveReleaseAbortNpmPackage(meta, repo) {
20174
20328
  if (isHubControlRepo(repo)) return "@mutmutco/cli";
20175
20329
  const publishDir = typeof meta.publishDir === "string" && meta.publishDir.trim() ? meta.publishDir.trim() : ".";
20176
20330
  try {
20177
- const pkg = JSON.parse((0, import_node_fs18.readFileSync)((0, import_node_path16.join)(publishDir, "package.json"), "utf8"));
20331
+ const pkg = JSON.parse((0, import_node_fs19.readFileSync)((0, import_node_path17.join)(publishDir, "package.json"), "utf8"));
20178
20332
  const name = pkg.name?.trim();
20179
20333
  if (!name) throw new Error("missing name field");
20180
20334
  return name;
@@ -21102,9 +21256,9 @@ function parseVerifyBroker(stdout) {
21102
21256
  }
21103
21257
 
21104
21258
  // src/train-apply-deploy.ts
21105
- var import_node_fs19 = require("node:fs");
21106
- var import_node_os10 = require("node:os");
21107
- var import_node_path17 = require("node:path");
21259
+ var import_node_fs20 = require("node:fs");
21260
+ var import_node_os11 = require("node:os");
21261
+ var import_node_path18 = require("node:path");
21108
21262
 
21109
21263
  // src/vercel-deployments.ts
21110
21264
  var TERMINAL = /* @__PURE__ */ new Set(["success", "failure", "error", "inactive"]);
@@ -21243,7 +21397,7 @@ function mmiGetRedeployCommand(repo) {
21243
21397
  }
21244
21398
  function readLocalLauncherVersion(root = process.cwd()) {
21245
21399
  try {
21246
- const raw = (0, import_node_fs19.readFileSync)((0, import_node_path17.join)(root, "cli", "package.json"), "utf8");
21400
+ const raw = (0, import_node_fs20.readFileSync)((0, import_node_path18.join)(root, "cli", "package.json"), "utf8");
21247
21401
  const version = JSON.parse(raw).version;
21248
21402
  return typeof version === "string" && version.trim() ? version.trim() : null;
21249
21403
  } catch {
@@ -21252,7 +21406,7 @@ function readLocalLauncherVersion(root = process.cwd()) {
21252
21406
  }
21253
21407
  function readServedChannelUrl(product = HUB_SERVED_PRODUCT, root = process.cwd()) {
21254
21408
  try {
21255
- const raw = (0, import_node_fs19.readFileSync)((0, import_node_path17.join)(root, "config", `product.${product}.json`), "utf8");
21409
+ const raw = (0, import_node_fs20.readFileSync)((0, import_node_path18.join)(root, "config", `product.${product}.json`), "utf8");
21256
21410
  const host = JSON.parse(raw).host;
21257
21411
  if (typeof host !== "string" || !host.trim()) return null;
21258
21412
  return `${host.trim().replace(/\/+$/, "")}/release/version`;
@@ -21686,13 +21840,13 @@ async function runTaggedJervGatewayLocalWrapper(deps, tag, tagSha) {
21686
21840
  const reason = error instanceof Error ? error.message : String(error);
21687
21841
  throw new Error(`could not extract ${JERV_GATEWAY_RELEASE_DEPLOY_SCRIPT} from tagged commit ${tagSha.slice(0, 12)}: ${reason}`);
21688
21842
  }
21689
- const dir = (0, import_node_fs19.mkdtempSync)((0, import_node_path17.join)((0, import_node_os10.tmpdir)(), "jerv-gateway-release-deploy-"));
21690
- const extracted = (0, import_node_path17.join)(dir, "jerv-gateway-release-deploy.sh");
21843
+ const dir = (0, import_node_fs20.mkdtempSync)((0, import_node_path18.join)((0, import_node_os11.tmpdir)(), "jerv-gateway-release-deploy-"));
21844
+ const extracted = (0, import_node_path18.join)(dir, "jerv-gateway-release-deploy.sh");
21691
21845
  try {
21692
- (0, import_node_fs19.writeFileSync)(extracted, script, "utf8");
21846
+ (0, import_node_fs20.writeFileSync)(extracted, script, "utf8");
21693
21847
  return await deps.run("bash", [extracted, "--tag", tag]);
21694
21848
  } finally {
21695
- (0, import_node_fs19.rmSync)(dir, { recursive: true, force: true });
21849
+ (0, import_node_fs20.rmSync)(dir, { recursive: true, force: true });
21696
21850
  }
21697
21851
  }
21698
21852
  async function appendJervGatewayReleaseDeploy(deps, repo, tag, tagSha, dispatch) {
@@ -22158,28 +22312,46 @@ async function runTenantControl(deps, options) {
22158
22312
  const watch = options.watch ?? tenantControlWatches(action);
22159
22313
  const base = { command: "tenant-control", repo, stage, action };
22160
22314
  const since = (deps.now ?? Date.now)();
22161
- const d = await deps.dispatchTenantControl({ repo, stage, action, lines: options.lines, edge: options.edge, since: options.logSince, until: options.logUntil, task: options.task, artifact: options.artifact, confirmDataLoss: options.confirmDataLoss });
22162
- if (!d.ok) {
22163
- const transport = d.category === "transport-failed";
22164
- return {
22165
- ...base,
22166
- dispatched: false,
22167
- conclusion: "failure",
22168
- category: action === "retire" ? transport ? "transport-failed" : "dispatch-rejected" : void 0,
22169
- 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"}`
22170
- };
22171
- }
22172
- const correlated = await correlateControlRun(deps, since, [stage, action, ...action === "run-task" && options.task ? [options.task] : []]);
22173
- if (correlated.read === "failed") {
22174
- return {
22175
- ...base,
22176
- dispatched: true,
22177
- conclusion: "failure",
22178
- category: action === "retire" ? "wait-timeout" : void 0,
22179
- note: `runtime tenant control ${action} dispatched, but its run could not be READ: ${correlated.error} \u2014 the run's outcome is unverified, not absent; check the Actions tab or retry once the read succeeds (#4713)`
22180
- };
22315
+ let runId;
22316
+ let runUrl;
22317
+ if (options.resume != null) {
22318
+ if (action !== "run-task") throw new Error("runtime tenant control: --resume is valid only for run-task");
22319
+ let view;
22320
+ try {
22321
+ view = JSON.parse(await deps.run("gh", ["run", "view", String(options.resume), "--repo", HUB_REPO2, "--json", "workflowName,displayTitle,url"]));
22322
+ } catch (e) {
22323
+ throw new Error(`runtime tenant control: run ${options.resume} could not be READ: ${e.message}`);
22324
+ }
22325
+ const f = (view.displayTitle ?? "").split(" ");
22326
+ if (view.workflowName !== "tenant-control" || f[0] !== "tenant-control" || f[1] !== (repo.split("/")[1] ?? "").toLowerCase() || f[2] !== stage || f[3] !== "run-task") {
22327
+ throw new Error(`runtime tenant control: run ${options.resume} is not a tenant-control run-task run for ${repo} ${stage} (title: ${view.displayTitle ?? "unreadable"}) \u2014 refusing to resume it`);
22328
+ }
22329
+ runId = options.resume;
22330
+ runUrl = view.url;
22331
+ } else {
22332
+ const d = await deps.dispatchTenantControl({ repo, stage, action, lines: options.lines, edge: options.edge, since: options.logSince, until: options.logUntil, task: options.task, artifact: options.artifact, confirmDataLoss: options.confirmDataLoss });
22333
+ if (!d.ok) {
22334
+ const transport = d.category === "transport-failed";
22335
+ return {
22336
+ ...base,
22337
+ dispatched: false,
22338
+ conclusion: "failure",
22339
+ category: action === "retire" ? transport ? "transport-failed" : "dispatch-rejected" : void 0,
22340
+ 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"}`
22341
+ };
22342
+ }
22343
+ const correlated = await correlateControlRun(deps, since, [stage, action, ...action === "run-task" && options.task ? [options.task] : []]);
22344
+ if (correlated.read === "failed") {
22345
+ return {
22346
+ ...base,
22347
+ dispatched: true,
22348
+ conclusion: "failure",
22349
+ category: action === "retire" ? "wait-timeout" : void 0,
22350
+ note: `runtime tenant control ${action} dispatched, but its run could not be READ: ${correlated.error} \u2014 the run's outcome is unverified, not absent; check the Actions tab or retry once the read succeeds (#4713)`
22351
+ };
22352
+ }
22353
+ ({ runId, runUrl } = correlated);
22181
22354
  }
22182
- const { runId, runUrl } = correlated;
22183
22355
  const conclusion = watch ? await watchTenantRun(deps, runId) : "pending";
22184
22356
  const result = { ...base, dispatched: true, runId, runUrl, conclusion, note: "" };
22185
22357
  if (action === "retire") {
@@ -22213,6 +22385,9 @@ async function runTenantControl(deps, options) {
22213
22385
  }
22214
22386
  }
22215
22387
  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`;
22388
+ if (conclusion === "pending" && runId != null && action === "run-task") {
22389
+ result.note += `; run ${runId} \u2014 resume without re-dispatching: mmi-cli devops runtime tenant control ${repo} ${stage} run-task --resume ${runId} --watch`;
22390
+ }
22216
22391
  return result;
22217
22392
  }
22218
22393
  function renderTenantControl(r) {
@@ -22232,9 +22407,9 @@ function renderTenantControl(r) {
22232
22407
  }
22233
22408
 
22234
22409
  // src/train-apply-phases.ts
22235
- var import_node_fs25 = require("node:fs");
22410
+ var import_node_fs26 = require("node:fs");
22236
22411
  var import_promises4 = require("node:fs/promises");
22237
- var import_node_path24 = require("node:path");
22412
+ var import_node_path25 = require("node:path");
22238
22413
 
22239
22414
  // src/actions-billing-preflight.ts
22240
22415
  var CANARY_WORKFLOW = "actions-job-start-canary.yml";
@@ -22542,14 +22717,14 @@ function assertPreOneZero(repo, meta, tag) {
22542
22717
 
22543
22718
  // src/train-doctor.ts
22544
22719
  var import_node_child_process9 = require("node:child_process");
22545
- var import_node_fs23 = require("node:fs");
22546
- var import_node_os14 = require("node:os");
22547
- var import_node_path23 = require("node:path");
22720
+ var import_node_fs24 = require("node:fs");
22721
+ var import_node_os15 = require("node:os");
22722
+ var import_node_path24 = require("node:path");
22548
22723
 
22549
22724
  // src/doctor-io.ts
22550
- var import_node_fs20 = require("node:fs");
22551
- var import_node_os11 = require("node:os");
22552
- var import_node_path18 = require("node:path");
22725
+ var import_node_fs21 = require("node:fs");
22726
+ var import_node_os12 = require("node:os");
22727
+ var import_node_path19 = require("node:path");
22553
22728
  var import_node_child_process7 = require("node:child_process");
22554
22729
  var import_node_util4 = require("node:util");
22555
22730
 
@@ -22562,8 +22737,8 @@ function nodeDiscardSinkPath(platform2 = process.platform) {
22562
22737
  var execFileP2 = (0, import_node_util4.promisify)(import_node_child_process7.execFile);
22563
22738
  function execFileCapture(file, args, opts = {}) {
22564
22739
  const sink = nodeDiscardSinkPath();
22565
- const inFd = (0, import_node_fs20.openSync)(sink, "r");
22566
- const errFd = (0, import_node_fs20.openSync)(sink, "w");
22740
+ const inFd = (0, import_node_fs21.openSync)(sink, "r");
22741
+ const errFd = (0, import_node_fs21.openSync)(sink, "w");
22567
22742
  try {
22568
22743
  return (0, import_node_child_process7.execFileSync)(file, args, {
22569
22744
  ...opts,
@@ -22571,17 +22746,17 @@ function execFileCapture(file, args, opts = {}) {
22571
22746
  stdio: [inFd, "pipe", errFd]
22572
22747
  });
22573
22748
  } finally {
22574
- (0, import_node_fs20.closeSync)(inFd);
22575
- (0, import_node_fs20.closeSync)(errFd);
22749
+ (0, import_node_fs21.closeSync)(inFd);
22750
+ (0, import_node_fs21.closeSync)(errFd);
22576
22751
  }
22577
22752
  }
22578
22753
  var MMI_PLUGIN_ID2 = "mmi@mutmutco";
22579
22754
  function stagedClaudePluginVersion() {
22580
22755
  try {
22581
- const stagingRoot = (0, import_node_path18.join)((0, import_node_os11.homedir)(), ".claude", "plugins", "staging");
22582
- const record = JSON.parse((0, import_node_fs20.readFileSync)((0, import_node_path18.join)(stagingRoot, "launch-target.json"), "utf8"));
22756
+ const stagingRoot = (0, import_node_path19.join)((0, import_node_os12.homedir)(), ".claude", "plugins", "staging");
22757
+ const record = JSON.parse((0, import_node_fs21.readFileSync)((0, import_node_path19.join)(stagingRoot, "launch-target.json"), "utf8"));
22583
22758
  if (typeof record.target !== "string" || typeof record.incoming !== "string") return void 0;
22584
- const manifest = JSON.parse((0, import_node_fs20.readFileSync)((0, import_node_path18.join)(record.incoming, ".claude-plugin", "plugin.json"), "utf8"));
22759
+ const manifest = JSON.parse((0, import_node_fs21.readFileSync)((0, import_node_path19.join)(record.incoming, ".claude-plugin", "plugin.json"), "utf8"));
22585
22760
  if (typeof manifest.version !== "string") return void 0;
22586
22761
  return manifest.version === record.target ? record.target : void 0;
22587
22762
  } catch {
@@ -22591,7 +22766,7 @@ function stagedClaudePluginVersion() {
22591
22766
  function installedClaudePluginVersion() {
22592
22767
  try {
22593
22768
  const file = JSON.parse(
22594
- (0, import_node_fs20.readFileSync)((0, import_node_path18.join)((0, import_node_os11.homedir)(), ".claude", "plugins", "installed_plugins.json"), "utf8")
22769
+ (0, import_node_fs21.readFileSync)((0, import_node_path19.join)((0, import_node_os12.homedir)(), ".claude", "plugins", "installed_plugins.json"), "utf8")
22595
22770
  );
22596
22771
  const versions = (file.plugins?.[MMI_PLUGIN_ID2] ?? []).map((r) => r.version).filter((v) => Boolean(v));
22597
22772
  if (versions.length === 0) return void 0;
@@ -22603,12 +22778,12 @@ function installedClaudePluginVersion() {
22603
22778
  function readHermesPluginEvidence(env = process.env) {
22604
22779
  const host = hermesConfigRoot(env);
22605
22780
  const root = hermesPluginRoot(env);
22606
- const installRecordPresent = (0, import_node_fs20.existsSync)(root);
22607
- const manifestPath = (0, import_node_path18.join)(root, "plugin.yaml");
22781
+ const installRecordPresent = (0, import_node_fs21.existsSync)(root);
22782
+ const manifestPath = (0, import_node_path19.join)(root, "plugin.yaml");
22608
22783
  let installedVersion;
22609
22784
  let manifest = "missing";
22610
22785
  try {
22611
- const text = (0, import_node_fs20.readFileSync)(manifestPath, "utf8");
22786
+ const text = (0, import_node_fs21.readFileSync)(manifestPath, "utf8");
22612
22787
  let version;
22613
22788
  try {
22614
22789
  const parsed = JSON.parse(text).version;
@@ -22622,25 +22797,25 @@ function readHermesPluginEvidence(env = process.env) {
22622
22797
  if (version) {
22623
22798
  installedVersion = version;
22624
22799
  manifest = "valid";
22625
- } else if ((0, import_node_fs20.existsSync)(manifestPath)) manifest = "invalid";
22800
+ } else if ((0, import_node_fs21.existsSync)(manifestPath)) manifest = "invalid";
22626
22801
  } catch {
22627
- if ((0, import_node_fs20.existsSync)(manifestPath)) manifest = "invalid";
22802
+ if ((0, import_node_fs21.existsSync)(manifestPath)) manifest = "invalid";
22628
22803
  }
22629
22804
  let skills = false;
22630
22805
  try {
22631
- skills = (0, import_node_fs20.existsSync)((0, import_node_path18.join)(root, "skills")) && (0, import_node_fs20.statSync)((0, import_node_path18.join)(root, "skills")).isDirectory();
22806
+ skills = (0, import_node_fs21.existsSync)((0, import_node_path19.join)(root, "skills")) && (0, import_node_fs21.statSync)((0, import_node_path19.join)(root, "skills")).isDirectory();
22632
22807
  } catch {
22633
22808
  }
22634
22809
  let provisioned = false;
22635
- const provisionedRoot = (0, import_node_path18.join)(host, "skills", "mmi");
22810
+ const provisionedRoot = (0, import_node_path19.join)(host, "skills", "mmi");
22636
22811
  try {
22637
- provisioned = (0, import_node_fs20.existsSync)(provisionedRoot) && (0, import_node_fs20.statSync)(provisionedRoot).isDirectory();
22812
+ provisioned = (0, import_node_fs21.existsSync)(provisionedRoot) && (0, import_node_fs21.statSync)(provisionedRoot).isDirectory();
22638
22813
  } catch {
22639
22814
  }
22640
- const treeOk = (0, import_node_fs20.existsSync)((0, import_node_path18.join)(root, "__init__.py")) && skills && manifest === "valid";
22815
+ const treeOk = (0, import_node_fs21.existsSync)((0, import_node_path19.join)(root, "__init__.py")) && skills && manifest === "valid";
22641
22816
  const receipt = treeOk && !provisioned ? `hermes-skills-unprovisioned:${provisionedRoot}` : void 0;
22642
22817
  return {
22643
- hostPresent: (0, import_node_fs20.existsSync)(host),
22818
+ hostPresent: (0, import_node_fs21.existsSync)(host),
22644
22819
  installRecordPresent,
22645
22820
  manifest,
22646
22821
  payloadPresent: treeOk && provisioned,
@@ -22686,13 +22861,13 @@ function worktreeRootSync() {
22686
22861
  }
22687
22862
  var gitignorePath = () => {
22688
22863
  const root = worktreeRootSync();
22689
- return root === null ? null : (0, import_node_path18.join)(root, ".gitignore");
22864
+ return root === null ? null : (0, import_node_path19.join)(root, ".gitignore");
22690
22865
  };
22691
22866
  function readGitignore() {
22692
22867
  const path2 = gitignorePath();
22693
22868
  if (path2 === null) return null;
22694
22869
  try {
22695
- return (0, import_node_fs20.readFileSync)(path2, "utf8");
22870
+ return (0, import_node_fs21.readFileSync)(path2, "utf8");
22696
22871
  } catch {
22697
22872
  return null;
22698
22873
  }
@@ -22701,14 +22876,14 @@ function writeGitignore(content) {
22701
22876
  const path2 = gitignorePath();
22702
22877
  if (path2 === null) return false;
22703
22878
  try {
22704
- (0, import_node_fs20.writeFileSync)(path2, content, "utf8");
22879
+ (0, import_node_fs21.writeFileSync)(path2, content, "utf8");
22705
22880
  return true;
22706
22881
  } catch {
22707
22882
  return false;
22708
22883
  }
22709
22884
  }
22710
22885
  function lineEndingState(root) {
22711
- const attributesPresent = (0, import_node_fs20.existsSync)((0, import_node_path18.join)(root, ".gitattributes"));
22886
+ const attributesPresent = (0, import_node_fs21.existsSync)((0, import_node_path19.join)(root, ".gitattributes"));
22712
22887
  try {
22713
22888
  const output = execFileCapture("git", ["-C", root, "ls-files", "--eol", "--", ":(glob)**/*.sh"], {
22714
22889
  windowsHide: true
@@ -22751,18 +22926,18 @@ function compatHolds(range, version) {
22751
22926
  }
22752
22927
 
22753
22928
  // src/claude-binary-doctor.ts
22754
- var import_node_fs21 = require("node:fs");
22755
- var import_node_os13 = require("node:os");
22756
- var import_node_path20 = require("node:path");
22929
+ var import_node_fs22 = require("node:fs");
22930
+ var import_node_os14 = require("node:os");
22931
+ var import_node_path21 = require("node:path");
22757
22932
 
22758
22933
  // src/jerv-cli-spawn.ts
22759
- var import_node_os12 = require("node:os");
22760
- var import_node_path19 = require("node:path");
22934
+ var import_node_os13 = require("node:os");
22935
+ var import_node_path20 = require("node:path");
22761
22936
  init_cli_shared();
22762
- var JERV_CLI_ENTRY = (0, import_node_path19.join)("node_modules", "@jervaise", "jerv-cli", "dist", "index.cjs");
22937
+ var JERV_CLI_ENTRY = (0, import_node_path20.join)("node_modules", "@jervaise", "jerv-cli", "dist", "index.cjs");
22763
22938
  function pathEnvEntries(pathEnv, platform2 = process.platform) {
22764
22939
  if (platform2 !== "win32") {
22765
- return pathEnv.split(import_node_path19.delimiter).map((e) => e.trim()).filter(Boolean);
22940
+ return pathEnv.split(import_node_path20.delimiter).map((e) => e.trim()).filter(Boolean);
22766
22941
  }
22767
22942
  if (pathEnv.includes(";")) {
22768
22943
  return pathEnv.split(";").map((e) => e.trim()).filter(Boolean);
@@ -22781,7 +22956,7 @@ function normalizeSpawnPathEntry(entry, platform2 = process.platform) {
22781
22956
  if (msys) return `${msys[1].toUpperCase()}:\\${msys[2].replace(/\//g, "\\")}`;
22782
22957
  return trimmed;
22783
22958
  }
22784
- function jervCliCandidateDirs(env = process.env, home = (0, import_node_os12.homedir)(), platform2 = process.platform) {
22959
+ function jervCliCandidateDirs(env = process.env, home = (0, import_node_os13.homedir)(), platform2 = process.platform) {
22785
22960
  const seen = /* @__PURE__ */ new Set();
22786
22961
  const out = [];
22787
22962
  const push = (dir) => {
@@ -22795,10 +22970,10 @@ function jervCliCandidateDirs(env = process.env, home = (0, import_node_os12.hom
22795
22970
  push(normalizeSpawnPathEntry(entry, platform2));
22796
22971
  }
22797
22972
  if (platform2 === "win32") {
22798
- if (env.APPDATA) push((0, import_node_path19.join)(env.APPDATA, "npm"));
22799
- if (env.LOCALAPPDATA) push((0, import_node_path19.join)(env.LOCALAPPDATA, "npm"));
22973
+ if (env.APPDATA) push((0, import_node_path20.join)(env.APPDATA, "npm"));
22974
+ if (env.LOCALAPPDATA) push((0, import_node_path20.join)(env.LOCALAPPDATA, "npm"));
22800
22975
  } else {
22801
- push((0, import_node_path19.join)(home, ".local", "bin"));
22976
+ push((0, import_node_path20.join)(home, ".local", "bin"));
22802
22977
  }
22803
22978
  return out;
22804
22979
  }
@@ -22851,26 +23026,26 @@ function globalNodeModulesRoots(host) {
22851
23026
  out.push(dir);
22852
23027
  };
22853
23028
  const prefix = env.npm_config_prefix?.trim();
22854
- if (prefix) push(platform2 === "win32" ? (0, import_node_path20.join)(prefix, "node_modules") : (0, import_node_path20.join)(prefix, "lib", "node_modules"));
22855
- for (const dir of jervCliCandidateDirs(env, host.home ?? (0, import_node_os13.homedir)(), platform2)) {
22856
- push((0, import_node_path20.join)(dir, "node_modules"));
22857
- push((0, import_node_path20.join)((0, import_node_path20.dirname)(dir), "lib", "node_modules"));
23029
+ if (prefix) push(platform2 === "win32" ? (0, import_node_path21.join)(prefix, "node_modules") : (0, import_node_path21.join)(prefix, "lib", "node_modules"));
23030
+ for (const dir of jervCliCandidateDirs(env, host.home ?? (0, import_node_os14.homedir)(), platform2)) {
23031
+ push((0, import_node_path21.join)(dir, "node_modules"));
23032
+ push((0, import_node_path21.join)((0, import_node_path21.dirname)(dir), "lib", "node_modules"));
22858
23033
  }
22859
23034
  return out;
22860
23035
  }
22861
23036
  function readHead(path2) {
22862
23037
  let fd;
22863
23038
  try {
22864
- fd = (0, import_node_fs21.openSync)(path2, "r");
23039
+ fd = (0, import_node_fs22.openSync)(path2, "r");
22865
23040
  const buffer = new Uint8Array(MAGIC_HEAD_BYTES);
22866
- const read = (0, import_node_fs21.readSync)(fd, buffer, 0, MAGIC_HEAD_BYTES, 0);
23041
+ const read = (0, import_node_fs22.readSync)(fd, buffer, 0, MAGIC_HEAD_BYTES, 0);
22867
23042
  return buffer.subarray(0, read);
22868
23043
  } catch {
22869
23044
  return void 0;
22870
23045
  } finally {
22871
23046
  if (fd !== void 0) {
22872
23047
  try {
22873
- (0, import_node_fs21.closeSync)(fd);
23048
+ (0, import_node_fs22.closeSync)(fd);
22874
23049
  } catch {
22875
23050
  }
22876
23051
  }
@@ -22878,7 +23053,7 @@ function readHead(path2) {
22878
23053
  }
22879
23054
  function fileBytes(path2) {
22880
23055
  try {
22881
- return (0, import_node_fs21.statSync)(path2).size;
23056
+ return (0, import_node_fs22.statSync)(path2).size;
22882
23057
  } catch {
22883
23058
  return void 0;
22884
23059
  }
@@ -22892,17 +23067,17 @@ function readClaudeBinaryState(host = {}) {
22892
23067
  const arch = host.arch ?? process.arch;
22893
23068
  const magic = EXECUTABLE_MAGIC[platform2];
22894
23069
  if (!magic) return void 0;
22895
- const packageRoot = globalNodeModulesRoots(host).map((root) => (0, import_node_path20.join)(root, ...PACKAGE.split("/"))).find((dir) => (0, import_node_fs21.existsSync)((0, import_node_path20.join)(dir, "package.json")));
23070
+ const packageRoot = globalNodeModulesRoots(host).map((root) => (0, import_node_path21.join)(root, ...PACKAGE.split("/"))).find((dir) => (0, import_node_fs22.existsSync)((0, import_node_path21.join)(dir, "package.json")));
22896
23071
  if (!packageRoot) return void 0;
22897
23072
  const keys = platformPackageKeys(platform2, arch);
22898
23073
  const fallbackPackage = `${PACKAGE}-${keys[0]}`;
22899
23074
  let manifest;
22900
23075
  try {
22901
- manifest = JSON.parse((0, import_node_fs21.readFileSync)((0, import_node_path20.join)(packageRoot, "package.json"), "utf8"));
23076
+ manifest = JSON.parse((0, import_node_fs22.readFileSync)((0, import_node_path21.join)(packageRoot, "package.json"), "utf8"));
22902
23077
  } catch (e) {
22903
23078
  return {
22904
23079
  state: "unreadable",
22905
- binPath: (0, import_node_path20.join)(packageRoot, "package.json"),
23080
+ binPath: (0, import_node_path21.join)(packageRoot, "package.json"),
22906
23081
  expectedMagic: magic.name,
22907
23082
  platformPackage: fallbackPackage,
22908
23083
  error: `package.json could not be read \u2014 ${e.message}`
@@ -22919,17 +23094,17 @@ function readClaudeBinaryState(host = {}) {
22919
23094
  error: "package.json declares no `bin` entry \u2014 the executed file cannot be resolved"
22920
23095
  };
22921
23096
  }
22922
- const binPath = (0, import_node_path20.join)(packageRoot, binRelative);
22923
- const binName = (0, import_node_path20.basename)(binRelative);
23097
+ const binPath = (0, import_node_path21.join)(packageRoot, binRelative);
23098
+ const binName = (0, import_node_path21.basename)(binRelative);
22924
23099
  const optional = manifest.optionalDependencies;
22925
23100
  const publishes = (name) => typeof optional === "object" && optional !== null && Object.prototype.hasOwnProperty.call(optional, name);
22926
23101
  const published = keys.map((key) => `${PACKAGE}-${key}`).filter(publishes);
22927
23102
  if (published.length === 0) return void 0;
22928
23103
  const binIn = (name) => [
22929
- (0, import_node_path20.join)(packageRoot, "node_modules", ...name.split("/"), binName),
22930
- (0, import_node_path20.join)((0, import_node_path20.dirname)((0, import_node_path20.dirname)(packageRoot)), ...name.split("/"), binName)
23104
+ (0, import_node_path21.join)(packageRoot, "node_modules", ...name.split("/"), binName),
23105
+ (0, import_node_path21.join)((0, import_node_path21.dirname)((0, import_node_path21.dirname)(packageRoot)), ...name.split("/"), binName)
22931
23106
  ];
22932
- const found = published.map((name) => ({ name, path: binIn(name).find((file) => (0, import_node_fs21.existsSync)(file)) })).find((c) => c.path);
23107
+ const found = published.map((name) => ({ name, path: binIn(name).find((file) => (0, import_node_fs22.existsSync)(file)) })).find((c) => c.path);
22933
23108
  const platformPackage = found?.name ?? published[0];
22934
23109
  let source;
22935
23110
  let sourceProblem;
@@ -22940,7 +23115,7 @@ function readClaudeBinaryState(host = {}) {
22940
23115
  } else {
22941
23116
  source = { path: found.path, bytes: fileBytes(found.path) ?? 0 };
22942
23117
  }
22943
- if (!(0, import_node_fs21.existsSync)(binPath)) {
23118
+ if (!(0, import_node_fs22.existsSync)(binPath)) {
22944
23119
  return { state: "missing", binPath, expectedMagic: magic.name, platformPackage, ...source ? { source } : {}, ...sourceProblem ? { sourceProblem } : {} };
22945
23120
  }
22946
23121
  const head = readHead(binPath);
@@ -22983,9 +23158,9 @@ function healClaudeBinary(host = {}, onStep) {
22983
23158
  const platform2 = host.platform ?? process.platform;
22984
23159
  const aside = `${probe.binPath}.stub-${Date.now()}`;
22985
23160
  let renamed = false;
22986
- if ((0, import_node_fs21.existsSync)(probe.binPath)) {
23161
+ if ((0, import_node_fs22.existsSync)(probe.binPath)) {
22987
23162
  try {
22988
- (0, import_node_fs21.renameSync)(probe.binPath, aside);
23163
+ (0, import_node_fs22.renameSync)(probe.binPath, aside);
22989
23164
  renamed = true;
22990
23165
  onStep?.(`renamed the stub aside: ${aside}`);
22991
23166
  } catch (e) {
@@ -22994,12 +23169,12 @@ function healClaudeBinary(host = {}, onStep) {
22994
23169
  }
22995
23170
  try {
22996
23171
  onStep?.(`copying ${probe.source.path} \u2192 ${probe.binPath} (${(probe.source.bytes / 1e6).toFixed(0)} MB)`);
22997
- (0, import_node_fs21.copyFileSync)(probe.source.path, probe.binPath);
22998
- if (platform2 !== "win32") (0, import_node_fs21.chmodSync)(probe.binPath, 493);
23172
+ (0, import_node_fs22.copyFileSync)(probe.source.path, probe.binPath);
23173
+ if (platform2 !== "win32") (0, import_node_fs22.chmodSync)(probe.binPath, 493);
22999
23174
  } catch (e) {
23000
23175
  if (renamed) {
23001
23176
  try {
23002
- (0, import_node_fs21.renameSync)(aside, probe.binPath);
23177
+ (0, import_node_fs22.renameSync)(aside, probe.binPath);
23003
23178
  } catch {
23004
23179
  return { ok: false, detail: `copy failed (${e.message}) and the stub could not be restored \u2014 the original is at ${aside}` };
23005
23180
  }
@@ -23013,7 +23188,7 @@ function healClaudeBinary(host = {}, onStep) {
23013
23188
  let kept = false;
23014
23189
  if (renamed) {
23015
23190
  try {
23016
- (0, import_node_fs21.rmSync)(aside);
23191
+ (0, import_node_fs22.rmSync)(aside);
23017
23192
  } catch {
23018
23193
  kept = true;
23019
23194
  }
@@ -23372,13 +23547,13 @@ function checkLineEndings(probe) {
23372
23547
  }
23373
23548
 
23374
23549
  // src/release-ledger.ts
23375
- var import_node_fs22 = require("node:fs");
23376
- var import_node_path22 = require("node:path");
23377
- var import_node_crypto8 = require("node:crypto");
23550
+ var import_node_fs23 = require("node:fs");
23551
+ var import_node_path23 = require("node:path");
23552
+ var import_node_crypto9 = require("node:crypto");
23378
23553
 
23379
23554
  // src/file-lock.ts
23380
23555
  var import_promises2 = require("node:fs/promises");
23381
- var import_node_path21 = require("node:path");
23556
+ var import_node_path22 = require("node:path");
23382
23557
  function pidIsDead(pid) {
23383
23558
  if (!Number.isInteger(pid) || pid <= 0) return false;
23384
23559
  if (pid === process.pid) return false;
@@ -23496,7 +23671,7 @@ async function withFileLock(lockPath, opts, fn) {
23496
23671
  }
23497
23672
  async function withFencedFileLock(lockPath, opts, fn) {
23498
23673
  const resolved = resolveFileLockOpts(opts);
23499
- await (0, import_promises2.mkdir)((0, import_node_path21.dirname)(lockPath), { recursive: true }).catch(() => void 0);
23674
+ await (0, import_promises2.mkdir)((0, import_node_path22.dirname)(lockPath), { recursive: true }).catch(() => void 0);
23500
23675
  const guard = await acquireFileLock(lockPath, resolved, Date.now() + resolved.maxWaitMs);
23501
23676
  try {
23502
23677
  return await fn(() => fileLockHeldBy(lockPath, guard.token));
@@ -23547,8 +23722,8 @@ function attachOutputNote(note, suffix) {
23547
23722
  }
23548
23723
  function writeFailingLegOutput(artifactPath, output) {
23549
23724
  const fileLines = lastNonEmptyLines(output, LEDGER_OUTPUT_FILE_LINES);
23550
- (0, import_node_fs22.mkdirSync)((0, import_node_path22.dirname)(artifactPath), { recursive: true });
23551
- (0, import_node_fs22.writeFileSync)(artifactPath, `${fileLines.join("\n")}
23725
+ (0, import_node_fs23.mkdirSync)((0, import_node_path23.dirname)(artifactPath), { recursive: true });
23726
+ (0, import_node_fs23.writeFileSync)(artifactPath, `${fileLines.join("\n")}
23552
23727
  `, "utf8");
23553
23728
  const tail = fileLines.slice(-LEDGER_OUTPUT_NOTE_LINES).join("\n");
23554
23729
  const noteSuffix = truncate(`failing-leg output: ${artifactPath}
@@ -23563,7 +23738,7 @@ function stampPhaseRecord(ledgerPath, tag, phase, entry, previousRetries, now) {
23563
23738
  if (raw) {
23564
23739
  try {
23565
23740
  const persisted = writeFailingLegOutput(
23566
- (0, import_node_path22.join)((0, import_node_path22.dirname)((0, import_node_path22.dirname)(ledgerPath)), "ledger-output", `${tag}-${phase}.txt`),
23741
+ (0, import_node_path23.join)((0, import_node_path23.dirname)((0, import_node_path23.dirname)(ledgerPath)), "ledger-output", `${tag}-${phase}.txt`),
23567
23742
  raw
23568
23743
  );
23569
23744
  note = attachOutputNote(note, persisted.noteSuffix);
@@ -23716,30 +23891,30 @@ function resolvePrimaryGitDir(cwd) {
23716
23891
  }
23717
23892
  let common;
23718
23893
  try {
23719
- common = (0, import_node_fs22.readFileSync)((0, import_node_path22.join)(gitDir, "commondir"), "utf8").trim();
23894
+ common = (0, import_node_fs23.readFileSync)((0, import_node_path23.join)(gitDir, "commondir"), "utf8").trim();
23720
23895
  } catch (e) {
23721
23896
  if (e.code !== "ENOENT") {
23722
23897
  throw new ReleaseLedgerError("unreadable", `release ledger: the worktree gitdir's commondir pointer could not be READ (${e instanceof Error ? e.message : String(e)}) \u2014 a failed read is unverified, not primary (#5987/#4713)`);
23723
23898
  }
23724
23899
  }
23725
23900
  if (!common) return gitDir;
23726
- const commonDir = (0, import_node_path22.isAbsolute)(common) ? common : (0, import_node_path22.resolve)(gitDir, common);
23901
+ const commonDir = (0, import_node_path23.isAbsolute)(common) ? common : (0, import_node_path23.resolve)(gitDir, common);
23727
23902
  try {
23728
- (0, import_node_fs22.readFileSync)((0, import_node_path22.join)(commonDir, "HEAD"), "utf8");
23903
+ (0, import_node_fs23.readFileSync)((0, import_node_path23.join)(commonDir, "HEAD"), "utf8");
23729
23904
  } catch (e) {
23730
23905
  throw new ReleaseLedgerError("no-checkout", `release ledger: the worktree's commondir pointer names ${commonDir}, which has no readable HEAD (${e instanceof Error ? e.message : String(e)}) \u2014 the primary checkout may have been removed; refusing to write the ledger into a doomed location`);
23731
23906
  }
23732
23907
  return commonDir;
23733
23908
  }
23734
23909
  function releaseLedgerPath(cwd) {
23735
- return (0, import_node_path22.join)(resolvePrimaryGitDir(cwd), "mmi-runtime", "release", "phases.json");
23910
+ return (0, import_node_path23.join)(resolvePrimaryGitDir(cwd), "mmi-runtime", "release", "phases.json");
23736
23911
  }
23737
23912
  function atomicWriteJson(path2, ledger) {
23738
- (0, import_node_fs22.mkdirSync)((0, import_node_path22.dirname)(path2), { recursive: true });
23739
- const tmp = `${path2}.tmp-${process.pid}-${(0, import_node_crypto8.randomBytes)(4).toString("hex")}`;
23740
- (0, import_node_fs22.writeFileSync)(tmp, `${JSON.stringify(ledger, null, 2)}
23913
+ (0, import_node_fs23.mkdirSync)((0, import_node_path23.dirname)(path2), { recursive: true });
23914
+ const tmp = `${path2}.tmp-${process.pid}-${(0, import_node_crypto9.randomBytes)(4).toString("hex")}`;
23915
+ (0, import_node_fs23.writeFileSync)(tmp, `${JSON.stringify(ledger, null, 2)}
23741
23916
  `, "utf8");
23742
- (0, import_node_fs22.renameSync)(tmp, path2);
23917
+ (0, import_node_fs23.renameSync)(tmp, path2);
23743
23918
  }
23744
23919
  var LEDGER_LOCK_OPTS = { label: "release ledger", staleMs: 18e4, deadHolderSteal: true };
23745
23920
  async function withLedgerLock(path2, fn, opts = {}) {
@@ -23751,16 +23926,16 @@ async function withLedgerLock(path2, fn, opts = {}) {
23751
23926
  }));
23752
23927
  }
23753
23928
  function checkoutRootFrom(cwd) {
23754
- let dir = (0, import_node_path22.resolve)(cwd);
23929
+ let dir = (0, import_node_path23.resolve)(cwd);
23755
23930
  for (; ; ) {
23756
23931
  if (resolveGitDir(dir)) return dir;
23757
- const parent = (0, import_node_path22.dirname)(dir);
23932
+ const parent = (0, import_node_path23.dirname)(dir);
23758
23933
  if (parent === dir) throw new ReleaseLedgerError("no-checkout", `train writer lock: no git checkout found above ${cwd}`);
23759
23934
  dir = parent;
23760
23935
  }
23761
23936
  }
23762
23937
  function trainWriterLockPath(cwd) {
23763
- return (0, import_node_path22.join)((0, import_node_path22.dirname)(releaseLedgerPath(checkoutRootFrom(cwd))), "train.lock");
23938
+ return (0, import_node_path23.join)((0, import_node_path23.dirname)(releaseLedgerPath(checkoutRootFrom(cwd))), "train.lock");
23764
23939
  }
23765
23940
  var TrainWriterBusyError = class extends Error {
23766
23941
  lockPath;
@@ -23786,7 +23961,7 @@ function describeTrainWriterToken(token) {
23786
23961
  function liveTrainWriterHolder(cwd) {
23787
23962
  let token;
23788
23963
  try {
23789
- token = (0, import_node_fs22.readFileSync)(trainWriterLockPath(cwd), "utf8");
23964
+ token = (0, import_node_fs23.readFileSync)(trainWriterLockPath(cwd), "utf8");
23790
23965
  } catch {
23791
23966
  return void 0;
23792
23967
  }
@@ -23808,7 +23983,7 @@ async function acquireTrainWriterLock(cwd, verb) {
23808
23983
  if (heldTrainWriter) heldTrainWriter.depth -= 1;
23809
23984
  };
23810
23985
  }
23811
- (0, import_node_fs22.mkdirSync)((0, import_node_path22.dirname)(lockPath), { recursive: true });
23986
+ (0, import_node_fs23.mkdirSync)((0, import_node_path23.dirname)(lockPath), { recursive: true });
23812
23987
  const opts = resolveFileLockOpts({ label: "train writer", staleMs: TRAIN_WRITER_STALE_MS, deadHolderSteal: true, maxWaitMs: 0, holder: verb });
23813
23988
  let guard;
23814
23989
  try {
@@ -23817,7 +23992,7 @@ async function acquireTrainWriterLock(cwd, verb) {
23817
23992
  if (!(e instanceof FileLockBusyError)) throw e;
23818
23993
  let token = "";
23819
23994
  try {
23820
- token = (0, import_node_fs22.readFileSync)(lockPath, "utf8");
23995
+ token = (0, import_node_fs23.readFileSync)(lockPath, "utf8");
23821
23996
  } catch {
23822
23997
  token = "";
23823
23998
  }
@@ -23852,7 +24027,7 @@ async function withReleaseLedger(path2, expected, fn, opts = {}) {
23852
24027
  let current;
23853
24028
  let raw;
23854
24029
  try {
23855
- raw = (0, import_node_fs22.readFileSync)(path2, "utf8");
24030
+ raw = (0, import_node_fs23.readFileSync)(path2, "utf8");
23856
24031
  } catch (e) {
23857
24032
  if (e.code !== "ENOENT") {
23858
24033
  throw new ReleaseLedgerError("unreadable", `release ledger at ${path2} could not be READ (${e instanceof Error ? e.message : String(e)}) \u2014 a failed read is unverified, not absent (#5987)`);
@@ -24521,7 +24696,7 @@ async function clearLedgerFile(path2, anchors, maxWaitMs) {
24521
24696
  return withLedgerLock(path2, async (fence) => {
24522
24697
  let raw;
24523
24698
  try {
24524
- raw = (0, import_node_fs22.readFileSync)(path2, "utf8");
24699
+ raw = (0, import_node_fs23.readFileSync)(path2, "utf8");
24525
24700
  } catch (e) {
24526
24701
  if (e.code === "ENOENT") return { cleared: false };
24527
24702
  return { cleared: false, note: `release ledger at ${path2} could not be read for clearing (${e instanceof Error ? e.message : String(e)}) \u2014 left in place` };
@@ -24537,7 +24712,7 @@ async function clearLedgerFile(path2, anchors, maxWaitMs) {
24537
24712
  } catch (e) {
24538
24713
  return { cleared: false, note: `release ledger at ${path2} belongs to ${ledger.tag} @ ${ledger.tagSha.slice(0, 12)} \u2014 not this release; left in place (${e instanceof Error ? e.message : String(e)})` };
24539
24714
  }
24540
- await fence(() => (0, import_node_fs22.unlinkSync)(path2));
24715
+ await fence(() => (0, import_node_fs23.unlinkSync)(path2));
24541
24716
  return { cleared: true, note: `cleared the release ledger at ${path2} for the live-proven aborted ${anchors.tag}` };
24542
24717
  }, { maxWaitMs });
24543
24718
  }
@@ -24697,7 +24872,7 @@ async function healStaleAlignmentLeg(deps, cwd, expected) {
24697
24872
  return withLedgerLock(path2, async (fence) => {
24698
24873
  let prior;
24699
24874
  try {
24700
- prior = parseReleaseLedger((0, import_node_fs22.readFileSync)(path2, "utf8"));
24875
+ prior = parseReleaseLedger((0, import_node_fs23.readFileSync)(path2, "utf8"));
24701
24876
  } catch {
24702
24877
  return void 0;
24703
24878
  }
@@ -24722,7 +24897,7 @@ async function healUnfoldedRunLegs(deps, cwd, model) {
24722
24897
  const path2 = releaseLedgerPath(cwd);
24723
24898
  let prior;
24724
24899
  try {
24725
- prior = parseReleaseLedger((0, import_node_fs22.readFileSync)(path2, "utf8"));
24900
+ prior = parseReleaseLedger((0, import_node_fs23.readFileSync)(path2, "utf8"));
24726
24901
  } catch {
24727
24902
  return void 0;
24728
24903
  }
@@ -24791,7 +24966,7 @@ async function supersedeContentCausedDeployLeg(deps, cwd) {
24791
24966
  return withLedgerLock(path2, async (fence) => {
24792
24967
  let prior;
24793
24968
  try {
24794
- prior = parseReleaseLedger((0, import_node_fs22.readFileSync)(path2, "utf8"));
24969
+ prior = parseReleaseLedger((0, import_node_fs23.readFileSync)(path2, "utf8"));
24795
24970
  } catch (e) {
24796
24971
  throw new ReleaseLedgerError(
24797
24972
  "unreadable",
@@ -24888,11 +25063,11 @@ async function proveOriginPromotionOrArchived(deps, prior, path2, label, ref, fe
24888
25063
  if (!releaseAbsent) {
24889
25064
  throw new Error(`${label}: origin no longer has ${prior.tag} but its GitHub Release still exists \u2014 resolve the mixed external state before closing the ledger; nothing was written (${ref})`);
24890
25065
  }
24891
- const archivePath = (0, import_node_path22.join)((0, import_node_path22.dirname)(path2), `phases.archive-${prior.tag}.json`);
24892
- if ((0, import_node_fs22.existsSync)(archivePath)) {
25066
+ const archivePath = (0, import_node_path23.join)((0, import_node_path23.dirname)(path2), `phases.archive-${prior.tag}.json`);
25067
+ if ((0, import_node_fs23.existsSync)(archivePath)) {
24893
25068
  throw new Error(`${label}: archive already exists at ${archivePath} \u2014 preserving both ledger records; resolve the collision by hand; nothing was written (${ref})`);
24894
25069
  }
24895
- await fence(() => (0, import_node_fs22.renameSync)(path2, archivePath));
25070
+ await fence(() => (0, import_node_fs23.renameSync)(path2, archivePath));
24896
25071
  return "deleted";
24897
25072
  }
24898
25073
  async function supersedeContentCausedPublishLeg(deps, cwd) {
@@ -24900,7 +25075,7 @@ async function supersedeContentCausedPublishLeg(deps, cwd) {
24900
25075
  return withLedgerLock(path2, async (fence) => {
24901
25076
  let prior;
24902
25077
  try {
24903
- prior = parseReleaseLedger((0, import_node_fs22.readFileSync)(path2, "utf8"));
25078
+ prior = parseReleaseLedger((0, import_node_fs23.readFileSync)(path2, "utf8"));
24904
25079
  } catch (e) {
24905
25080
  throw new ReleaseLedgerError(
24906
25081
  "unreadable",
@@ -24982,7 +25157,7 @@ async function supersedeContentCausedDeployAndPublishLegs(deps, cwd) {
24982
25157
  return withLedgerLock(path2, async (fence) => {
24983
25158
  let prior;
24984
25159
  try {
24985
- prior = parseReleaseLedger((0, import_node_fs22.readFileSync)(path2, "utf8"));
25160
+ prior = parseReleaseLedger((0, import_node_fs23.readFileSync)(path2, "utf8"));
24986
25161
  } catch (e) {
24987
25162
  throw new ReleaseLedgerError(
24988
25163
  "unreadable",
@@ -25087,7 +25262,7 @@ async function supersedeContentCausedDeployAndPublishLegs(deps, cwd) {
25087
25262
  async function reverifyPriorRunLegs(deps, path2, targetTag) {
25088
25263
  let prior;
25089
25264
  try {
25090
- prior = parseReleaseLedger((0, import_node_fs22.readFileSync)(path2, "utf8"));
25265
+ prior = parseReleaseLedger((0, import_node_fs23.readFileSync)(path2, "utf8"));
25091
25266
  } catch {
25092
25267
  return;
25093
25268
  }
@@ -25107,7 +25282,7 @@ async function beginReleaseLedger(deps, cwd, targetTag) {
25107
25282
  return withLedgerLock(path2, async (fence) => {
25108
25283
  let raw;
25109
25284
  try {
25110
- raw = (0, import_node_fs22.readFileSync)(path2, "utf8");
25285
+ raw = (0, import_node_fs23.readFileSync)(path2, "utf8");
25111
25286
  } catch (e) {
25112
25287
  if (e.code === "ENOENT") return { ok: true };
25113
25288
  return { ok: false, error: `the release ledger at ${path2} could not be READ (${e instanceof Error ? e.message : String(e)}) \u2014 a failed read is unverified, not absent (#5987/#4713)` };
@@ -25145,15 +25320,15 @@ async function beginReleaseLedger(deps, cwd, targetTag) {
25145
25320
  if (liveSha.toLowerCase() !== prior.tagSha.toLowerCase()) {
25146
25321
  return { ok: false, error: `the completed ${prior.tag} ledger says phases-green but origin reports ${liveSha.slice(0, 12) || "no tag"} \u2260 ${prior.tagSha.slice(0, 12)} \u2014 refusing to archive on unproven state; resolve by hand (#5987)` };
25147
25322
  }
25148
- const archivePath = (0, import_node_path22.join)((0, import_node_path22.dirname)(path2), `phases.archive-${prior.tag}.json`);
25323
+ const archivePath = (0, import_node_path23.join)((0, import_node_path23.dirname)(path2), `phases.archive-${prior.tag}.json`);
25149
25324
  try {
25150
- await fence(() => (0, import_node_fs22.unlinkSync)(archivePath));
25325
+ await fence(() => (0, import_node_fs23.unlinkSync)(archivePath));
25151
25326
  } catch (e) {
25152
25327
  if (e.code !== "ENOENT") {
25153
25328
  return { ok: false, error: `could not clear the stale archive at ${archivePath} (${e instanceof Error ? e.message : String(e)}) \u2014 the ledger for ${prior.tag} stays active (#5987)` };
25154
25329
  }
25155
25330
  }
25156
- await fence(() => (0, import_node_fs22.renameSync)(path2, archivePath));
25331
+ await fence(() => (0, import_node_fs23.renameSync)(path2, archivePath));
25157
25332
  return { ok: true, note: `archived the completed release ledger ${prior.tag} to ${archivePath} (live-proven at ${prior.tagSha.slice(0, 12)})` };
25158
25333
  });
25159
25334
  }
@@ -25181,7 +25356,7 @@ async function retryHotfixDeployLegs(deps, cwd, opts = {}) {
25181
25356
  return withLedgerLock(path2, async (fence) => {
25182
25357
  let prior;
25183
25358
  try {
25184
- prior = parseReleaseLedger((0, import_node_fs22.readFileSync)(path2, "utf8"));
25359
+ prior = parseReleaseLedger((0, import_node_fs23.readFileSync)(path2, "utf8"));
25185
25360
  } catch (e) {
25186
25361
  throw new ReleaseLedgerError(
25187
25362
  "unreadable",
@@ -25372,10 +25547,10 @@ function readOriginWorkflowsDefault(root, ref) {
25372
25547
  }
25373
25548
  var NPM_REGISTRY = "https://registry.npmjs.org";
25374
25549
  async function probeRegistryWhoami(train) {
25375
- const dir = (0, import_node_fs23.mkdtempSync)((0, import_node_path23.join)((0, import_node_os14.tmpdir)(), "mmi-npmrc-"));
25376
- const rc = (0, import_node_path23.join)(dir, "npmrc");
25550
+ const dir = (0, import_node_fs24.mkdtempSync)((0, import_node_path24.join)((0, import_node_os15.tmpdir)(), "mmi-npmrc-"));
25551
+ const rc = (0, import_node_path24.join)(dir, "npmrc");
25377
25552
  try {
25378
- (0, import_node_fs23.writeFileSync)(rc, "//registry.npmjs.org/:_authToken=${NPM_TOKEN}\n");
25553
+ (0, import_node_fs24.writeFileSync)(rc, "//registry.npmjs.org/:_authToken=${NPM_TOKEN}\n");
25379
25554
  await train.runSelf(["secrets", "use", "npm/NPM_TOKEN", "--slug", "_org", "--", "npm", "whoami", "--registry", NPM_REGISTRY, "--userconfig", rc]);
25380
25555
  return { kind: "ok", detail: "the registry answered a login" };
25381
25556
  } catch (e) {
@@ -25386,7 +25561,7 @@ async function probeRegistryWhoami(train) {
25386
25561
  if (/\bE401\b|401 Unauthorized/.test(stderr)) return { kind: "rejected", detail: "npm whoami answered 401 Unauthorized" };
25387
25562
  return { kind: "unverified", detail: first };
25388
25563
  } finally {
25389
- (0, import_node_fs23.rmSync)(dir, { recursive: true, force: true });
25564
+ (0, import_node_fs24.rmSync)(dir, { recursive: true, force: true });
25390
25565
  }
25391
25566
  }
25392
25567
  var REGISTRY_TOKEN_ENV = /\b(NODE_AUTH_TOKEN|NPM_TOKEN)\b/;
@@ -25404,7 +25579,7 @@ var defaultDeps2 = {
25404
25579
  ledgerPath: releaseLedgerPath,
25405
25580
  readLedgerRaw: (path2) => {
25406
25581
  try {
25407
- return (0, import_node_fs23.readFileSync)(path2, "utf8");
25582
+ return (0, import_node_fs24.readFileSync)(path2, "utf8");
25408
25583
  } catch (e) {
25409
25584
  if (e.code === "ENOENT") return void 0;
25410
25585
  throw e;
@@ -25415,7 +25590,7 @@ var defaultDeps2 = {
25415
25590
  trainWriterHolder: liveTrainWriterHolder,
25416
25591
  readSurfacesRaw: (cwd) => {
25417
25592
  try {
25418
- return (0, import_node_fs23.readFileSync)((0, import_node_path23.join)(cwd, "surfaces.json"), "utf8");
25593
+ return (0, import_node_fs24.readFileSync)((0, import_node_path24.join)(cwd, "surfaces.json"), "utf8");
25419
25594
  } catch {
25420
25595
  return void 0;
25421
25596
  }
@@ -26005,7 +26180,7 @@ function formatTrainDoctor(v) {
26005
26180
 
26006
26181
  // src/release-plain-words.ts
26007
26182
  var import_promises3 = require("node:fs/promises");
26008
- var import_node_fs24 = require("node:fs");
26183
+ var import_node_fs25 = require("node:fs");
26009
26184
  function releaseCutByNotes(cutBy) {
26010
26185
  return `## Internal
26011
26186
  Cut by ${formatSessionIdentity(cutBy)}
@@ -26030,7 +26205,7 @@ function validateSuiteReleaseSummary(path2) {
26030
26205
  if (!path2) throw new Error(`requires --announce-summary-file <path> before promoting any member \u2014 see ${SUMMARY_GUIDE}`);
26031
26206
  let content;
26032
26207
  try {
26033
- content = (0, import_node_fs24.readFileSync)(path2, "utf8");
26208
+ content = (0, import_node_fs25.readFileSync)(path2, "utf8");
26034
26209
  } catch (e) {
26035
26210
  throw new Error(`could not read summary file ${path2}: ${e.message} \u2014 see ${SUMMARY_GUIDE}`);
26036
26211
  }
@@ -26237,34 +26412,34 @@ function vercelVersionEnvDeps(deps) {
26237
26412
  // src/train-apply-phases.ts
26238
26413
  var TRAIN_BUMP_INTENTS = ["major", "minor", "patch"];
26239
26414
  function readLocalGateWorkflows() {
26240
- const dir = (0, import_node_path24.join)(".github", "workflows");
26415
+ const dir = (0, import_node_path25.join)(".github", "workflows");
26241
26416
  let names;
26242
26417
  try {
26243
- names = (0, import_node_fs25.readdirSync)(dir);
26418
+ names = (0, import_node_fs26.readdirSync)(dir);
26244
26419
  } catch {
26245
26420
  return null;
26246
26421
  }
26247
26422
  const files = [];
26248
26423
  for (const name of names.filter(isGateWorkflowPath)) {
26249
26424
  try {
26250
- files.push({ path: `${dir}/${name}`.replace(/\\/g, "/"), body: (0, import_node_fs25.readFileSync)((0, import_node_path24.join)(dir, name), "utf8") });
26425
+ files.push({ path: `${dir}/${name}`.replace(/\\/g, "/"), body: (0, import_node_fs26.readFileSync)((0, import_node_path25.join)(dir, name), "utf8") });
26251
26426
  } catch {
26252
26427
  }
26253
26428
  }
26254
26429
  return files;
26255
26430
  }
26256
26431
  function readLocalWorkflows() {
26257
- const dir = (0, import_node_path24.join)(".github", "workflows");
26432
+ const dir = (0, import_node_path25.join)(".github", "workflows");
26258
26433
  let names;
26259
26434
  try {
26260
- names = (0, import_node_fs25.readdirSync)(dir);
26435
+ names = (0, import_node_fs26.readdirSync)(dir);
26261
26436
  } catch {
26262
26437
  return null;
26263
26438
  }
26264
26439
  const files = [];
26265
26440
  for (const name of names.filter((n) => /\.ya?ml$/i.test(n))) {
26266
26441
  try {
26267
- files.push({ path: `${dir}/${name}`.replace(/\\/g, "/"), body: (0, import_node_fs25.readFileSync)((0, import_node_path24.join)(dir, name), "utf8") });
26442
+ files.push({ path: `${dir}/${name}`.replace(/\\/g, "/"), body: (0, import_node_fs26.readFileSync)((0, import_node_path25.join)(dir, name), "utf8") });
26268
26443
  } catch {
26269
26444
  }
26270
26445
  }
@@ -27146,7 +27321,7 @@ async function activeRcandLedgerCandidate(deps, cwd) {
27146
27321
  }
27147
27322
  let prior;
27148
27323
  try {
27149
- prior = parseReleaseLedger((0, import_node_fs25.readFileSync)(path2, "utf8"));
27324
+ prior = parseReleaseLedger((0, import_node_fs26.readFileSync)(path2, "utf8"));
27150
27325
  } catch {
27151
27326
  return void 0;
27152
27327
  }
@@ -30428,11 +30603,11 @@ function buildPluginCachePlan(home, running, deps, opts = {}) {
30428
30603
  return absent;
30429
30604
  }
30430
30605
  const versions = names.filter(isVersionDirName);
30431
- const prune = selectPrunablePluginVersions(versions, running, opts.installedVersion);
30432
- const pruneSet = new Set(prune);
30606
+ const prune2 = selectPrunablePluginVersions(versions, running, opts.installedVersion);
30607
+ const pruneSet = new Set(prune2);
30433
30608
  const keep = [...versions].sort((a, b) => compareVersions(b, a)).filter((v) => !pruneSet.has(v));
30434
- const bytes = opts.withBytes ? prune.reduce((sum, v) => sum + deps.dirBytes(`${cacheRoot}/${v}`), 0) : 0;
30435
- return { cacheRoot, present: true, keep, prune, bytes, running, ...stagingFields };
30609
+ const bytes = opts.withBytes ? prune2.reduce((sum, v) => sum + deps.dirBytes(`${cacheRoot}/${v}`), 0) : 0;
30610
+ return { cacheRoot, present: true, keep, prune: prune2, bytes, running, ...stagingFields };
30436
30611
  }
30437
30612
  function applyPluginCachePlan(plan, remove2, stagingGuard) {
30438
30613
  const removed = [];
@@ -30741,6 +30916,12 @@ function registerBoardCommands(program3) {
30741
30916
  if (!o.out) console.log(output);
30742
30917
  else console.log(`Wrote board read to ${o.out} (UTF-8, ${writeUtf8Receipt(o.out, output)} bytes)`);
30743
30918
  } catch (e) {
30919
+ if (e instanceof BoardSnapshotFailure) {
30920
+ if (o.json) console.log(JSON.stringify(e.receipt));
30921
+ console.error(`mmi-cli board read failed: ${e.message}`);
30922
+ process.exitCode = e.exitCode;
30923
+ return;
30924
+ }
30744
30925
  if (o.json && e && typeof e === "object" && "quota" in e && e.quota) console.log(JSON.stringify(e.quota));
30745
30926
  return failGraceful(`board read failed: ${withDiscoverMissDetail(e.message)}`);
30746
30927
  }
@@ -30781,7 +30962,7 @@ function registerBoardCommands(program3) {
30781
30962
  return `Claimed ${ref} for ${holder} - In Progress${reclaimed}`;
30782
30963
  }
30783
30964
  const board = program3.command("board").description("read, claim, show, and move Project v2 work items for the current repo");
30784
- board.command("read", { isDefault: true }).alias("list").description("read the board and print user-owned, claimable, and taken items").option("--json", "machine-readable output").option("--repo <owner/repo>", "current repo (defaults to git origin)").option("--direct", "bypass the Hub snapshot and read the live board through direct GitHub GraphQL").option("--snapshot-only", "fail instead of falling back to your personal GraphQL pool when the Hub snapshot is unavailable \u2014 for ambient readers such as sidebars (#7203)").option("--min-cursor <n>", "board-event cursor (from `oracle board events`) the Hub snapshot must postdate; a cached snapshot older than that event is rebuilt (#7240)").option("--bundle-details", "fetch body/comments only for user-owned and claimable issues").option("--bodies", "fetch body/comments for EVERY scoped row, including taken and unowned in-flight ones \u2014 for consumers that scope by Status rather than ownership (#4861); implies --bundle-details and costs one extra read per row").option("--allow-partial", "return partial board results when later page/detail reads fail").option("--out <path>", "write the output to this file as UTF-8 (no BOM) instead of stdout \u2014 the shell-free receipt path (#5802)").addHelpText("after", "\nread is always the authoritative live GitHub Project v2 board (#4926).\n--direct skips the Hub snapshot and uses the existing direct GitHub GraphQL read immediately.\n--allow-partial applies to the paginated path and detail reads.\n\nWhen using Windows PowerShell 5.1, avoid shell redirects: PowerShell 5.1's `> file.json` is Out-File,\nwhich writes UTF-16LE with a BOM, and Node reading it as 'utf8' then fails JSON.parse at position 1\n(#5802). Use --out instead \u2014 the CLI writes the file itself as UTF-8:\n mmi-cli oracle board read --json --out .jerv/tmp/board.json\n").action((o) => runBoardRead(o));
30965
+ board.command("read", { isDefault: true }).alias("list").description("read the board and print user-owned, claimable, and taken items").option("--json", "machine-readable output").option("--repo <owner/repo>", "current repo (defaults to git origin)").option("--direct", "bypass the Hub snapshot and read the live board through direct GitHub GraphQL").option("--snapshot-only", "never fall back to your personal GraphQL pool; failure exits: 20 hub-unreachable, 21 app-quota-exhausted, 22 refused. With --json, stdout is {ok:false,outcome,reason[,resetAt,pool]} (pool is rest or graphql when known); success is unchanged").option("--min-cursor <n>", "board-event cursor (from `oracle board events`) the Hub snapshot must postdate; a cached snapshot older than that event is rebuilt (#7240)").option("--bundle-details", "fetch body/comments only for user-owned and claimable issues").option("--bodies", "fetch body/comments for EVERY scoped row, including taken and unowned in-flight ones \u2014 for consumers that scope by Status rather than ownership (#4861); implies --bundle-details and costs one extra read per row").option("--allow-partial", "return partial board results when later page/detail reads fail").option("--out <path>", "write the output to this file as UTF-8 (no BOM) instead of stdout \u2014 the shell-free receipt path (#5802)").addHelpText("after", "\nread is always the authoritative live GitHub Project v2 board (#4926).\n--direct skips the Hub snapshot and uses the existing direct GitHub GraphQL read immediately.\n--allow-partial applies to the paginated path and detail reads.\n\nWhen using Windows PowerShell 5.1, avoid shell redirects: PowerShell 5.1's `> file.json` is Out-File,\nwhich writes UTF-16LE with a BOM, and Node reading it as 'utf8' then fails JSON.parse at position 1\n(#5802). Use --out instead \u2014 the CLI writes the file itself as UTF-8:\n mmi-cli oracle board read --json --out .jerv/tmp/board.json\n").action((o) => runBoardRead(o));
30785
30966
  board.command("events").description("content-free board/CI change records after a cursor, from the Hub event feed (no GitHub call) \u2014 for real-time sidebars (#7235)").option("--since <cursor>", "cursor from the previous answer; omit on first read (answers the head cursor with resync:true)").option("--wait <seconds>", "hold up to this long (max 120), polling every 2s, and return on the first event or resync", "0").option("--repo <owner/repo>", "repo whose Hub config to use (defaults to git origin)").option("--json", "machine-readable output (already the default)").addHelpText("after", "\nPrints {cursor, events, resync, more[, hidden]}. Pass the returned cursor as the next --since.\nresync:true means records were missed (retention ~1h, or a gap): re-read the board with\n`mmi-cli oracle board read --snapshot-only --json`.\n").action(async (o) => {
30786
30967
  try {
30787
30968
  if (o.since !== void 0 && !/^\d{1,15}$/.test(o.since)) throw new Error("--since must be a non-negative integer cursor");
@@ -31022,9 +31203,9 @@ function registerBoardCommands(program3) {
31022
31203
  }
31023
31204
 
31024
31205
  // src/bootstrap-commands.ts
31025
- var import_node_fs29 = require("node:fs");
31026
- var import_node_os17 = require("node:os");
31027
- var import_node_path28 = require("node:path");
31206
+ var import_node_fs30 = require("node:fs");
31207
+ var import_node_os18 = require("node:os");
31208
+ var import_node_path29 = require("node:path");
31028
31209
  init_cli_shared();
31029
31210
  init_clean_exit();
31030
31211
 
@@ -31208,8 +31389,8 @@ init_github_client();
31208
31389
  init_cli_shared();
31209
31390
 
31210
31391
  // src/port-registry.ts
31211
- var import_node_fs26 = require("node:fs");
31212
- var import_node_path25 = require("node:path");
31392
+ var import_node_fs27 = require("node:fs");
31393
+ var import_node_path26 = require("node:path");
31213
31394
 
31214
31395
  // ../infra/port-geometry.mjs
31215
31396
  var PORT_BLOCK = 100;
@@ -31223,8 +31404,8 @@ function nextPortBlock(registry2) {
31223
31404
  return [base, base + PORT_SPAN];
31224
31405
  }
31225
31406
  function loadPortRegistry(path2) {
31226
- if (!(0, import_node_fs26.existsSync)(path2)) return {};
31227
- const raw = JSON.parse((0, import_node_fs26.readFileSync)(path2, "utf8"));
31407
+ if (!(0, import_node_fs27.existsSync)(path2)) return {};
31408
+ const raw = JSON.parse((0, import_node_fs27.readFileSync)(path2, "utf8"));
31228
31409
  const out = {};
31229
31410
  for (const [key, value] of Object.entries(raw)) {
31230
31411
  if (Array.isArray(value) && value.length === 2 && value.every((n) => typeof n === "number")) {
@@ -31252,22 +31433,22 @@ function existingPortRange(repo, registry2) {
31252
31433
  return registry2[repo] ?? null;
31253
31434
  }
31254
31435
  function portRangeInfraAt(root, source) {
31255
- const registryPath = (0, import_node_path25.join)(root, "infra", "port-ranges.json");
31256
- const ddbScriptPath = (0, import_node_path25.join)(root, "infra", "port-ddb.mjs");
31257
- if (!(0, import_node_fs26.existsSync)(registryPath) || !(0, import_node_fs26.existsSync)(ddbScriptPath)) return null;
31436
+ const registryPath = (0, import_node_path26.join)(root, "infra", "port-ranges.json");
31437
+ const ddbScriptPath = (0, import_node_path26.join)(root, "infra", "port-ddb.mjs");
31438
+ if (!(0, import_node_fs27.existsSync)(registryPath) || !(0, import_node_fs27.existsSync)(ddbScriptPath)) return null;
31258
31439
  return { root, source, registryPath, ddbScriptPath };
31259
31440
  }
31260
31441
  function resolvePortRangeInfra(cwd, packageDir) {
31261
31442
  const direct = portRangeInfraAt(cwd, "cwd");
31262
31443
  if (direct) return direct;
31263
- for (let dir = cwd; ; dir = (0, import_node_path25.dirname)(dir)) {
31264
- const sibling = portRangeInfraAt((0, import_node_path25.join)(dir, "MMI-Hub"), "sibling-hub");
31444
+ for (let dir = cwd; ; dir = (0, import_node_path26.dirname)(dir)) {
31445
+ const sibling = portRangeInfraAt((0, import_node_path26.join)(dir, "MMI-Hub"), "sibling-hub");
31265
31446
  if (sibling) return sibling;
31266
- const parent = (0, import_node_path25.dirname)(dir);
31447
+ const parent = (0, import_node_path26.dirname)(dir);
31267
31448
  if (parent === dir) break;
31268
31449
  }
31269
31450
  if (packageDir) {
31270
- const pkgRoot = (0, import_node_path25.join)(packageDir, "..", "..");
31451
+ const pkgRoot = (0, import_node_path26.join)(packageDir, "..", "..");
31271
31452
  const pkgFrom = portRangeInfraAt(pkgRoot, "pkg-root");
31272
31453
  if (pkgFrom) return pkgFrom;
31273
31454
  }
@@ -31284,7 +31465,7 @@ async function ensurePortRangeAtomic(repo, path2, allocate) {
31284
31465
  } catch (e) {
31285
31466
  const why = e.message;
31286
31467
  const missing = /@aws-sdk\/[\w-]+/.exec(why)?.[0];
31287
- throw new Error(`DDB port allocator failed for ${repo} \u2014 refusing to fall back to the frozen ${path2} (it would hand out a block the cursor already gave away). ` + (missing && /cannot find|not found|ERR_MODULE_NOT_FOUND/i.test(why) ? `Missing dependency ${missing}: run \`npm ci\` in ${(0, import_node_path25.dirname)(path2)}, then retry.` : "Check AWS credentials and that the registry table is reachable, then retry.") + ` Cause: ${why}`);
31468
+ throw new Error(`DDB port allocator failed for ${repo} \u2014 refusing to fall back to the frozen ${path2} (it would hand out a block the cursor already gave away). ` + (missing && /cannot find|not found|ERR_MODULE_NOT_FOUND/i.test(why) ? `Missing dependency ${missing}: run \`npm ci\` in ${(0, import_node_path26.dirname)(path2)}, then retry.` : "Check AWS credentials and that the registry table is reachable, then retry.") + ` Cause: ${why}`);
31288
31469
  }
31289
31470
  }
31290
31471
 
@@ -31336,13 +31517,13 @@ async function assignPersistedPortRange(repo, slug, reg, opts) {
31336
31517
  }
31337
31518
 
31338
31519
  // src/box-commands.ts
31339
- var import_node_fs28 = require("node:fs");
31520
+ var import_node_fs29 = require("node:fs");
31340
31521
  var import_node_child_process10 = require("node:child_process");
31341
- var import_node_os16 = require("node:os");
31342
- var import_node_path27 = require("node:path");
31522
+ var import_node_os17 = require("node:os");
31523
+ var import_node_path28 = require("node:path");
31343
31524
 
31344
31525
  // src/box-control.ts
31345
- var import_node_crypto9 = require("node:crypto");
31526
+ var import_node_crypto10 = require("node:crypto");
31346
31527
  var MANIFEST_PATH = "infra/box-control/manifest.json";
31347
31528
  var ALLOWED_POST = /* @__PURE__ */ new Set(["systemctl daemon-reload"]);
31348
31529
  function parseManifest(text) {
@@ -31389,7 +31570,7 @@ function filesForBox(files, box) {
31389
31570
  return files.flatMap((file) => file.targets.filter((t) => t.box === box).map((t) => ({ file, dest: t.dest })));
31390
31571
  }
31391
31572
  function md5(content) {
31392
- return (0, import_node_crypto9.createHash)("md5").update(content).digest("hex");
31573
+ return (0, import_node_crypto10.createHash)("md5").update(content).digest("hex");
31393
31574
  }
31394
31575
  function planRemoteScript(dests) {
31395
31576
  const lines2 = ["set -u"];
@@ -31468,9 +31649,9 @@ function applyRemoteScript(items, date) {
31468
31649
  init_clean_exit();
31469
31650
 
31470
31651
  // src/secrets-commands.ts
31471
- var import_node_fs27 = require("node:fs");
31472
- var import_node_path26 = require("node:path");
31473
- var import_node_os15 = require("node:os");
31652
+ var import_node_fs28 = require("node:fs");
31653
+ var import_node_path27 = require("node:path");
31654
+ var import_node_os16 = require("node:os");
31474
31655
  init_cli_shared();
31475
31656
  init_hub_auth();
31476
31657
  init_github_client();
@@ -32626,18 +32807,18 @@ function collectMap(value, previous = []) {
32626
32807
  return [...previous, value];
32627
32808
  }
32628
32809
  async function decryptRailsCredentials(input) {
32629
- const appDir = (0, import_node_path26.resolve)(input.appDir ?? process.cwd());
32810
+ const appDir = (0, import_node_path27.resolve)(input.appDir ?? process.cwd());
32630
32811
  const credentialsFile = input.credentialsFile ?? DEFAULT_RAILS_CREDENTIALS_FILE;
32631
32812
  const masterKeyFile = input.masterKeyFile ?? DEFAULT_RAILS_MASTER_KEY_FILE;
32632
- const credentialsPath = (0, import_node_path26.resolve)(appDir, credentialsFile);
32633
- const masterKeyPath = (0, import_node_path26.resolve)(appDir, masterKeyFile);
32813
+ const credentialsPath = (0, import_node_path27.resolve)(appDir, credentialsFile);
32814
+ const masterKeyPath = (0, import_node_path27.resolve)(appDir, masterKeyFile);
32634
32815
  const env = {
32635
32816
  ...process.env,
32636
32817
  MMI_RAILS_CREDENTIALS_FILE: credentialsPath,
32637
32818
  MMI_RAILS_MASTER_KEY_FILE: masterKeyPath
32638
32819
  };
32639
- if ((0, import_node_fs27.existsSync)(masterKeyPath)) {
32640
- env.RAILS_MASTER_KEY = (0, import_node_fs27.readFileSync)(masterKeyPath, "utf8").trim();
32820
+ if ((0, import_node_fs28.existsSync)(masterKeyPath)) {
32821
+ env.RAILS_MASTER_KEY = (0, import_node_fs28.readFileSync)(masterKeyPath, "utf8").trim();
32641
32822
  }
32642
32823
  const script = [
32643
32824
  'require "json"',
@@ -32647,9 +32828,9 @@ async function decryptRailsCredentials(input) {
32647
32828
  'config = ActiveSupport::EncryptedConfiguration.new(config_path: config_path, key_path: key_path, env_key: "RAILS_MASTER_KEY", raise_if_missing_key: true)',
32648
32829
  "puts JSON.generate(config.config)"
32649
32830
  ].join("\n");
32650
- const scriptDir = (0, import_node_fs27.mkdtempSync)((0, import_node_path26.join)((0, import_node_os15.tmpdir)(), "mmi-rails-decrypt-"));
32651
- const scriptPath = (0, import_node_path26.join)(scriptDir, "decrypt.rb");
32652
- (0, import_node_fs27.writeFileSync)(scriptPath, script, "utf8");
32831
+ const scriptDir = (0, import_node_fs28.mkdtempSync)((0, import_node_path27.join)((0, import_node_os16.tmpdir)(), "mmi-rails-decrypt-"));
32832
+ const scriptPath = (0, import_node_path27.join)(scriptDir, "decrypt.rb");
32833
+ (0, import_node_fs28.writeFileSync)(scriptPath, script, "utf8");
32653
32834
  try {
32654
32835
  const args = ["exec", "ruby", scriptPath];
32655
32836
  const cmd = process.platform === "win32" ? "cmd.exe" : "bundle";
@@ -32661,7 +32842,7 @@ async function decryptRailsCredentials(input) {
32661
32842
  });
32662
32843
  return JSON.parse(stdout);
32663
32844
  } finally {
32664
- (0, import_node_fs27.rmSync)(scriptDir, { recursive: true, force: true });
32845
+ (0, import_node_fs28.rmSync)(scriptDir, { recursive: true, force: true });
32665
32846
  }
32666
32847
  }
32667
32848
  async function readSecretStdin() {
@@ -32751,7 +32932,7 @@ function registerSecretsCommands(program3) {
32751
32932
  let body;
32752
32933
  if (o.file) {
32753
32934
  try {
32754
- body = (0, import_node_fs27.readFileSync)((0, import_node_path26.resolve)(o.file), "utf8");
32935
+ body = (0, import_node_fs28.readFileSync)((0, import_node_path27.resolve)(o.file), "utf8");
32755
32936
  } catch (e) {
32756
32937
  return fail(`secrets org-catalog: cannot read --file ${o.file}: ${e.message}`);
32757
32938
  }
@@ -32887,7 +33068,7 @@ function registerSecretsCommands(program3) {
32887
33068
  {
32888
33069
  ...d,
32889
33070
  decryptRailsCredentials,
32890
- removeFile: (path2) => (0, import_node_fs27.unlinkSync)((0, import_node_path26.resolve)(o.appDir ?? process.cwd(), path2))
33071
+ removeFile: (path2) => (0, import_node_fs28.unlinkSync)((0, import_node_path27.resolve)(o.appDir ?? process.cwd(), path2))
32891
33072
  },
32892
33073
  {
32893
33074
  repo: o.repo,
@@ -33143,7 +33324,7 @@ function registerBoxCommands(program3) {
33143
33324
  }
33144
33325
  const remote = command && command.length ? command.join(" ") : void 0;
33145
33326
  const wroteScript = o.ssh && o.script ? o.script : null;
33146
- if (wroteScript) (0, import_node_fs28.writeFileSync)(wroteScript, sshRecipeScript(found, remote), "utf8");
33327
+ if (wroteScript) (0, import_node_fs29.writeFileSync)(wroteScript, sshRecipeScript(found, remote), "utf8");
33147
33328
  if (o.json) {
33148
33329
  console.log(JSON.stringify({
33149
33330
  box: found,
@@ -33217,17 +33398,17 @@ function hubGitShow(ref) {
33217
33398
  return (path2) => git3(["show", `${ref}:${path2}`]);
33218
33399
  }
33219
33400
  function runOnBox(found, script) {
33220
- const dir = (0, import_node_fs28.mkdtempSync)((0, import_node_path27.join)((0, import_node_os16.tmpdir)(), "mmi-box-control-"));
33401
+ const dir = (0, import_node_fs29.mkdtempSync)((0, import_node_path28.join)((0, import_node_os17.tmpdir)(), "mmi-box-control-"));
33221
33402
  try {
33222
- const recipe = (0, import_node_path27.join)(dir, "recipe.sh");
33223
- (0, import_node_fs28.writeFileSync)(recipe, sshRecipeScript(found, "sh -s"), "utf8");
33403
+ const recipe = (0, import_node_path28.join)(dir, "recipe.sh");
33404
+ (0, import_node_fs29.writeFileSync)(recipe, sshRecipeScript(found, "sh -s"), "utf8");
33224
33405
  const r = (0, import_node_child_process10.spawnSync)("bash", [recipe], { input: script, encoding: "utf8", maxBuffer: 16 * 1024 * 1024, timeout: 18e4, windowsHide: true });
33225
33406
  if (r.status !== 0) {
33226
33407
  throw new UnreadableError(`box control: the ssh session to ${found.name} failed (exit ${r.status ?? r.signal}): ${(r.stderr || "").trim().split("\n").slice(-3).join(" | ")}`);
33227
33408
  }
33228
33409
  return r.stdout;
33229
33410
  } finally {
33230
- (0, import_node_fs28.rmSync)(dir, { recursive: true, force: true });
33411
+ (0, import_node_fs29.rmSync)(dir, { recursive: true, force: true });
33231
33412
  }
33232
33413
  }
33233
33414
  function formatControl(mode, box, rows) {
@@ -33355,7 +33536,7 @@ function renderDeployPortDoctor(report) {
33355
33536
  }
33356
33537
 
33357
33538
  // src/bootstrap-drift.ts
33358
- var import_node_crypto10 = require("node:crypto");
33539
+ var import_node_crypto11 = require("node:crypto");
33359
33540
  function byteComparableSeeds(manifest, cls) {
33360
33541
  return manifest.seeds.filter((s) => s.ownership === "org" && s.source === "self" && s.classes.includes(cls));
33361
33542
  }
@@ -33375,7 +33556,7 @@ function compareSeedBytes(hubContent, repoContent) {
33375
33556
  return normalize(hubContent) === normalize(repoContent) ? "match" : "drift";
33376
33557
  }
33377
33558
  function seedContentHash(content) {
33378
- return (0, import_node_crypto10.createHash)("sha256").update(content.replace(/\r\n/g, "\n"), "utf8").digest("hex");
33559
+ return (0, import_node_crypto11.createHash)("sha256").update(content.replace(/\r\n/g, "\n"), "utf8").digest("hex");
33379
33560
  }
33380
33561
  function auditRepoSeedDrift(repo, seeds, hubContents, repoReads) {
33381
33562
  const byTarget = new Map(repoReads.map((r) => [r.target, r.content]));
@@ -33538,7 +33719,7 @@ function renderPropagationReport(plan) {
33538
33719
  }
33539
33720
 
33540
33721
  // src/bootstrap-propagation-identity.ts
33541
- var import_node_crypto11 = require("node:crypto");
33722
+ var import_node_crypto12 = require("node:crypto");
33542
33723
  var PROPAGATION_BRANCH_PREFIX = "seed-propagate-";
33543
33724
  var TARGET_MARKER_NAME = "mmi-bootstrap-propagation-target";
33544
33725
  function safeBranchPart(value, maxLength, fallback) {
@@ -33551,7 +33732,7 @@ function repoSlug2(repo) {
33551
33732
  function propagationBranch(repo, target) {
33552
33733
  const repoPart = safeBranchPart(repoSlug2(repo), 32, "repo");
33553
33734
  const targetPart = safeBranchPart(target, 48, "target");
33554
- const hash = (0, import_node_crypto11.createHash)("sha256").update(repo.trim().toLowerCase()).update("\0").update(target).digest("hex").slice(0, 12);
33735
+ const hash = (0, import_node_crypto12.createHash)("sha256").update(repo.trim().toLowerCase()).update("\0").update(target).digest("hex").slice(0, 12);
33555
33736
  return `${PROPAGATION_BRANCH_PREFIX}${repoPart}-${targetPart}-${hash}`;
33556
33737
  }
33557
33738
  function legacyPropagationBranch(repo) {
@@ -34763,7 +34944,7 @@ function renderBootstrapVerifyReport(report) {
34763
34944
  }
34764
34945
 
34765
34946
  // src/bootstrap-seed-delivery.ts
34766
- var import_node_crypto12 = require("node:crypto");
34947
+ var import_node_crypto13 = require("node:crypto");
34767
34948
  init_github_client();
34768
34949
  var SHA = /^[a-f0-9]{40}$/;
34769
34950
  async function readSeedFile(repo, target, ref, client) {
@@ -34796,7 +34977,7 @@ async function targetedSeedPlan(repo, slug, target, baseBranch, sourceSha, clien
34796
34977
  }
34797
34978
  const baseSha = base?.object?.sha;
34798
34979
  if (!baseSha || !SHA.test(baseSha) || !SHA.test(sourceSha)) throw new Error("bootstrap apply: seed identity is unreadable");
34799
- const identity = (0, import_node_crypto12.createHash)("sha256").update(JSON.stringify([repo.toLowerCase(), target, baseSha, sourceSha])).digest("hex").slice(0, 24);
34980
+ const identity = (0, import_node_crypto13.createHash)("sha256").update(JSON.stringify([repo.toLowerCase(), target, baseSha, sourceSha])).digest("hex").slice(0, 24);
34800
34981
  const delivery = planSeedDelivery(rules, slug, baseBranch, `bootstrap-seed-${identity}`);
34801
34982
  const scoped = forcePr && delivery.mode === "direct" ? { mode: "pr", ref: `bootstrap-seed-${identity}-${slug}`, branch: `bootstrap-seed-${identity}-${slug}`, reason: "registry gate render requires review" } : delivery;
34802
34983
  return { ...scoped, baseSha, baseBranch };
@@ -34862,12 +35043,12 @@ async function verifyTargetedSeedPr(repo, number, plan, target, expected, client
34862
35043
  // src/bootstrap-commands.ts
34863
35044
  var execGitForSeedSource = async (args) => (await execFileP("git", args, { timeout: GIT_TIMEOUT_MS })).stdout;
34864
35045
  async function gateRenderDiff(current, rendered) {
34865
- const dir = (0, import_node_fs29.mkdtempSync)((0, import_node_path28.join)((0, import_node_os17.tmpdir)(), "mmi-gate-diff-"));
34866
- const before = (0, import_node_path28.join)(dir, "committed-gate.yml");
34867
- const after = (0, import_node_path28.join)(dir, "registry-render.yml");
35046
+ const dir = (0, import_node_fs30.mkdtempSync)((0, import_node_path29.join)((0, import_node_os18.tmpdir)(), "mmi-gate-diff-"));
35047
+ const before = (0, import_node_path29.join)(dir, "committed-gate.yml");
35048
+ const after = (0, import_node_path29.join)(dir, "registry-render.yml");
34868
35049
  try {
34869
- (0, import_node_fs29.writeFileSync)(before, current);
34870
- (0, import_node_fs29.writeFileSync)(after, rendered);
35050
+ (0, import_node_fs30.writeFileSync)(before, current);
35051
+ (0, import_node_fs30.writeFileSync)(after, rendered);
34871
35052
  try {
34872
35053
  return (await execFileP("git", ["diff", "--no-index", "--", before, after], { timeout: GIT_TIMEOUT_MS })).stdout;
34873
35054
  } catch (e) {
@@ -34876,7 +35057,7 @@ async function gateRenderDiff(current, rendered) {
34876
35057
  throw e;
34877
35058
  }
34878
35059
  } finally {
34879
- (0, import_node_fs29.rmSync)(dir, { recursive: true, force: true });
35060
+ (0, import_node_fs30.rmSync)(dir, { recursive: true, force: true });
34880
35061
  }
34881
35062
  }
34882
35063
  function bootstrapTrainDoctorDeps() {
@@ -34936,13 +35117,13 @@ function registerBootstrapCommands(program3) {
34936
35117
  })),
34937
35118
  pushAllowlistOwners: verifyOwners,
34938
35119
  pushAllowlistOwnersRead: verifyOwnersRead,
34939
- readLocalFile: (path2) => path2 === "projects.json" && apiProjects != null ? apiProjects : (0, import_node_fs29.existsSync)(path2) ? (0, import_node_fs29.readFileSync)(path2, "utf8") : null,
35120
+ readLocalFile: (path2) => path2 === "projects.json" && apiProjects != null ? apiProjects : (0, import_node_fs30.existsSync)(path2) ? (0, import_node_fs30.readFileSync)(path2, "utf8") : null,
34940
35121
  // requiredGcpApis is stored as an array by a JSON write, but `org project set --var KEY=VALUE` stores a raw
34941
35122
  // comma-string — accept either so the seeded value verifies regardless of how it was written.
34942
35123
  // #3689: the same committed map the org access audit reads (#3664), so a sanctioned admin is not a
34943
35124
  // permanent bootstrap failure on one surface and an intended state on the other. Absent file → no
34944
35125
  // sanction, which is the pre-#3664 behaviour.
34945
- sanctionedAdmins: (0, import_node_fs29.existsSync)("access-matrix.json") ? entriesValueByCanonicalRepo(loadSanctionedAdmins((0, import_node_fs29.readFileSync)("access-matrix.json", "utf8")), repo) : void 0,
35126
+ sanctionedAdmins: (0, import_node_fs30.existsSync)("access-matrix.json") ? entriesValueByCanonicalRepo(loadSanctionedAdmins((0, import_node_fs30.readFileSync)("access-matrix.json", "utf8")), repo) : void 0,
34946
35127
  requiredGcpApis: (() => {
34947
35128
  const v = meta?.requiredGcpApis;
34948
35129
  if (Array.isArray(v)) return v;
@@ -35020,14 +35201,14 @@ function registerBootstrapCommands(program3) {
35020
35201
  bootstrap.command("drift").description("#3818: compare every org-owned whole-file seed against MMI-Hub's copy across the registry roster; read-only").option("--repo <owner/repo>", "audit one repo instead of the roster (never a fleet verdict)").option("--json", "machine-readable output").action(async () => {
35021
35202
  const o = { repo: rawValue("--repo", ""), json: rawFlag("--json") };
35022
35203
  const manifestPath = "skills/bootstrap/seeds/manifest.json";
35023
- if (!(0, import_node_fs29.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`);
35204
+ if (!(0, import_node_fs30.existsSync)(manifestPath)) return fail(`bootstrap drift: ${manifestPath} not found; run from the MMI-Hub repo root \u2014 the Hub's copies ARE the reference this compares against`);
35024
35205
  const seedSource = await resolveHubSeedSource(execGitForSeedSource);
35025
35206
  if (!seedSource.ok) return fail(`bootstrap drift: ${seedSource.reason}`);
35026
- const manifest = loadBootstrapSeeds((0, import_node_fs29.readFileSync)(manifestPath, "utf8"));
35207
+ const manifest = loadBootstrapSeeds((0, import_node_fs30.readFileSync)(manifestPath, "utf8"));
35027
35208
  const hubContents = /* @__PURE__ */ new Map();
35028
35209
  for (const s of manifest.seeds) {
35029
35210
  if (s.ownership !== "org" || s.source !== "self") continue;
35030
- hubContents.set(s.target, (0, import_node_fs29.existsSync)(s.target) ? (0, import_node_fs29.readFileSync)(s.target, "utf8") : null);
35211
+ hubContents.set(s.target, (0, import_node_fs30.existsSync)(s.target) ? (0, import_node_fs30.readFileSync)(s.target, "utf8") : null);
35031
35212
  }
35032
35213
  let targets;
35033
35214
  let classOf = (_repo) => "deployable";
@@ -35235,24 +35416,24 @@ function registerBootstrapCommands(program3) {
35235
35416
  return;
35236
35417
  }
35237
35418
  const manifestPath = "skills/bootstrap/seeds/manifest.json";
35238
- if (!(0, import_node_fs29.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`);
35419
+ if (!(0, import_node_fs30.existsSync)(manifestPath)) return fail(`bootstrap apply: ${manifestPath} not found; bootstrap runs from the MMI-Hub repo root by design \u2014 it stamps org-level resources (Project, Ruleset, secrets, access) through the GitHub App, which is only authorized from the Hub checkout`);
35239
35420
  const seedSource = await resolveHubSeedSource(execGitForSeedSource);
35240
35421
  if (!seedSource.ok) return fail(`bootstrap apply: ${seedSource.reason}`);
35241
- const manifest = loadBootstrapSeeds((0, import_node_fs29.readFileSync)(manifestPath, "utf8"));
35422
+ const manifest = loadBootstrapSeeds((0, import_node_fs30.readFileSync)(manifestPath, "utf8"));
35242
35423
  const baseBranch = o.class === "content" ? "main" : "development";
35243
35424
  const slug = parsedRepo.slug;
35244
35425
  const onlyTarget = o.fromConfig && o.only.trim() === "gate.yml" ? ".github/workflows/gate.yml" : o.only.trim();
35245
35426
  const gh2 = async (args) => execFileP("gh", args, { timeout: 2e4 });
35246
- const readFile10 = (p) => (0, import_node_fs29.existsSync)(p) ? (0, import_node_fs29.readFileSync)(p, "utf8") : null;
35427
+ const readFile10 = (p) => (0, import_node_fs30.existsSync)(p) ? (0, import_node_fs30.readFileSync)(p, "utf8") : null;
35247
35428
  const enc = (p) => p.split("/").map(encodeURIComponent).join("/");
35248
35429
  const putSeed = async (target, content, ref, sha) => {
35249
- const tmp = (0, import_node_path28.join)((0, import_node_os17.tmpdir)(), `mmi-seed-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
35250
- (0, import_node_fs29.writeFileSync)(tmp, JSON.stringify(contentPutBody(target, content, ref, sha)), "utf8");
35430
+ const tmp = (0, import_node_path29.join)((0, import_node_os18.tmpdir)(), `mmi-seed-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
35431
+ (0, import_node_fs30.writeFileSync)(tmp, JSON.stringify(contentPutBody(target, content, ref, sha)), "utf8");
35251
35432
  try {
35252
35433
  await gh2(contentPutInputArgs(repo, target, tmp));
35253
35434
  } finally {
35254
35435
  try {
35255
- (0, import_node_fs29.unlinkSync)(tmp);
35436
+ (0, import_node_fs30.unlinkSync)(tmp);
35256
35437
  } catch {
35257
35438
  }
35258
35439
  }
@@ -35888,10 +36069,10 @@ LIVE apply to ${repo}:
35888
36069
  bootstrap.command("propagate").description("#4238: re-entrant canary\u2192wave tick \u2014 plan (or, with --execute, open) per-repo PRs fanning an org-owned seed out to the fleet").option("--target <path>", "the manifest target to propagate (an org-owned whole file or declared Hub-managed block)").option("--execute", "LIVE tick via gh (master-gated) \u2014 opens/reuses per-repo seed-propagate PRs; dry-run prints the plan only").option("--json", "machine-readable output").action(async () => {
35889
36070
  const o = { target: rawValue("--target", ""), execute: rawFlag("--execute"), json: rawFlag("--json") };
35890
36071
  const manifestPath = "skills/bootstrap/seeds/manifest.json";
35891
- if (!(0, import_node_fs29.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`);
36072
+ if (!(0, import_node_fs30.existsSync)(manifestPath)) return fail(`bootstrap propagate: ${manifestPath} not found; run from the MMI-Hub repo root \u2014 the Hub's copies ARE the desired state this tick propagates`);
35892
36073
  const seedSource = await resolveHubSeedSource(execGitForSeedSource);
35893
36074
  if (!seedSource.ok) return fail(`bootstrap propagate: ${seedSource.reason}`);
35894
- const manifest = loadBootstrapSeeds((0, import_node_fs29.readFileSync)(manifestPath, "utf8"));
36075
+ const manifest = loadBootstrapSeeds((0, import_node_fs30.readFileSync)(manifestPath, "utf8"));
35895
36076
  const propagatable = manifest.seeds.filter(isPropagatableSeed);
35896
36077
  if (!o.target) {
35897
36078
  return fail(`bootstrap propagate: --target <path> is required \u2014 one of:
@@ -35900,9 +36081,9 @@ LIVE apply to ${repo}:
35900
36081
  const seed = propagatable.find((s) => s.target === o.target);
35901
36082
  if (!seed) return fail(`bootstrap propagate: --target '${o.target}' names no centrally propagatable seed in ${manifestPath}. Propagatable targets:
35902
36083
  ${propagatable.map((s) => s.target).join("\n ")}`);
35903
- if (!seed.managedBlock && !(0, import_node_fs29.existsSync)(seed.target)) return fail(`bootstrap propagate: the Hub's own copy of '${seed.target}' is missing \u2014 nothing to propagate`);
35904
- const hubContent = seed.managedBlock ? null : (0, import_node_fs29.readFileSync)(seed.target, "utf8");
35905
- const readSeedFile2 = (path2) => (0, import_node_fs29.existsSync)(path2) ? (0, import_node_fs29.readFileSync)(path2, "utf8") : null;
36084
+ if (!seed.managedBlock && !(0, import_node_fs30.existsSync)(seed.target)) return fail(`bootstrap propagate: the Hub's own copy of '${seed.target}' is missing \u2014 nothing to propagate`);
36085
+ const hubContent = seed.managedBlock ? null : (0, import_node_fs30.readFileSync)(seed.target, "utf8");
36086
+ const readSeedFile2 = (path2) => (0, import_node_fs30.existsSync)(path2) ? (0, import_node_fs30.readFileSync)(path2, "utf8") : null;
35906
36087
  const isWorkflowSeed = seed.target.startsWith(".github/workflows/");
35907
36088
  const cfg = await loadConfig();
35908
36089
  const projects = await fetchProjectsList(registryClientDeps(cfg));
@@ -35911,9 +36092,9 @@ LIVE apply to ${repo}:
35911
36092
  }
35912
36093
  const rosterRepos = collectRegistryRepos(projects).filter((r) => r.toLowerCase() !== "mutmutco/mmi-hub");
35913
36094
  let independentCount = rosterRepos.length;
35914
- if ((0, import_node_fs29.existsSync)("projects.json")) {
36095
+ if ((0, import_node_fs30.existsSync)("projects.json")) {
35915
36096
  try {
35916
- const local = JSON.parse((0, import_node_fs29.readFileSync)("projects.json", "utf8"));
36097
+ const local = JSON.parse((0, import_node_fs30.readFileSync)("projects.json", "utf8"));
35917
36098
  const localRepos = /* @__PURE__ */ new Set();
35918
36099
  for (const p of local.projects ?? []) for (const r of p.repos ?? []) {
35919
36100
  const full = (r.includes("/") ? r : `mutmutco/${r}`).toLowerCase();
@@ -36083,15 +36264,15 @@ LIVE apply to ${repo}:
36083
36264
  } catch {
36084
36265
  existingSha = void 0;
36085
36266
  }
36086
- const tmp = (0, import_node_path28.join)((0, import_node_os17.tmpdir)(), `mmi-propagate-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
36267
+ const tmp = (0, import_node_path29.join)((0, import_node_os18.tmpdir)(), `mmi-propagate-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
36087
36268
  const desiredContent = desiredByRepo.get(rec.repo);
36088
36269
  if (desiredContent == null) return fail(`bootstrap propagate: no resolved content for ${rec.repo} ${seed.target} \u2014 refusing to write`);
36089
- (0, import_node_fs29.writeFileSync)(tmp, JSON.stringify(contentPutBody(seed.target, desiredContent, branch, existingSha)), "utf8");
36270
+ (0, import_node_fs30.writeFileSync)(tmp, JSON.stringify(contentPutBody(seed.target, desiredContent, branch, existingSha)), "utf8");
36090
36271
  try {
36091
36272
  await gh2(contentPutInputArgs(rec.repo, seed.target, tmp));
36092
36273
  } finally {
36093
36274
  try {
36094
- (0, import_node_fs29.unlinkSync)(tmp);
36275
+ (0, import_node_fs30.unlinkSync)(tmp);
36095
36276
  } catch {
36096
36277
  }
36097
36278
  }
@@ -36160,10 +36341,10 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
36160
36341
  return fail(`bootstrap rollback: ${e.message}`);
36161
36342
  }
36162
36343
  const manifestPath = "skills/bootstrap/seeds/manifest.json";
36163
- if (!(0, import_node_fs29.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)`);
36344
+ if (!(0, import_node_fs30.existsSync)(manifestPath)) return fail(`bootstrap rollback: ${manifestPath} not found; run from the MMI-Hub repo root \u2014 the manifest names which targets are org-owned and therefore propagated (and rollback-able)`);
36164
36345
  const seedSource = await resolveHubSeedSource(execGitForSeedSource);
36165
36346
  if (!seedSource.ok) return fail(`bootstrap rollback: ${seedSource.reason}`);
36166
- const manifest = loadBootstrapSeeds((0, import_node_fs29.readFileSync)(manifestPath, "utf8"));
36347
+ const manifest = loadBootstrapSeeds((0, import_node_fs30.readFileSync)(manifestPath, "utf8"));
36167
36348
  const propagatable = manifest.seeds.filter(isPropagatableSeed);
36168
36349
  if (!o.target) {
36169
36350
  return fail(`bootstrap rollback: --target <path> is required \u2014 one of:
@@ -36180,10 +36361,10 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
36180
36361
  const enc = (p) => p.split("/").map(encodeURIComponent).join("/");
36181
36362
  let candidates;
36182
36363
  if (o.record) {
36183
- if (!(0, import_node_fs29.existsSync)(o.record)) return fail(`bootstrap rollback: --record '${o.record}' not found`);
36364
+ if (!(0, import_node_fs30.existsSync)(o.record)) return fail(`bootstrap rollback: --record '${o.record}' not found`);
36184
36365
  let parsed;
36185
36366
  try {
36186
- parsed = JSON.parse((0, import_node_fs29.readFileSync)(o.record, "utf8"));
36367
+ parsed = JSON.parse((0, import_node_fs30.readFileSync)(o.record, "utf8"));
36187
36368
  } catch (e) {
36188
36369
  return fail(`bootstrap rollback: --record '${o.record}' is not valid JSON: ${e.message}`);
36189
36370
  }
@@ -36260,13 +36441,13 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
36260
36441
  } catch {
36261
36442
  existingSha = void 0;
36262
36443
  }
36263
- const tmp = (0, import_node_path28.join)((0, import_node_os17.tmpdir)(), `mmi-rollback-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
36264
- (0, import_node_fs29.writeFileSync)(tmp, JSON.stringify(contentPutBody(seed.target, preSeedContent, plan.branch, existingSha)), "utf8");
36444
+ const tmp = (0, import_node_path29.join)((0, import_node_os18.tmpdir)(), `mmi-rollback-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
36445
+ (0, import_node_fs30.writeFileSync)(tmp, JSON.stringify(contentPutBody(seed.target, preSeedContent, plan.branch, existingSha)), "utf8");
36265
36446
  try {
36266
36447
  await gh2(contentPutInputArgs(repo, seed.target, tmp));
36267
36448
  } finally {
36268
36449
  try {
36269
- (0, import_node_fs29.unlinkSync)(tmp);
36450
+ (0, import_node_fs30.unlinkSync)(tmp);
36270
36451
  } catch {
36271
36452
  }
36272
36453
  }
@@ -36442,7 +36623,7 @@ init_github_client();
36442
36623
  init_cli_shared();
36443
36624
 
36444
36625
  // src/suite-status.ts
36445
- var import_node_crypto13 = require("node:crypto");
36626
+ var import_node_crypto14 = require("node:crypto");
36446
36627
  var SUITE_REPO = "mutmutco/MM-Work";
36447
36628
  var REPOS = {
36448
36629
  "mmi-scout": "mutmutco/MMI-Scout",
@@ -36470,7 +36651,7 @@ function parseSuiteMapping(body) {
36470
36651
  return void 0;
36471
36652
  }
36472
36653
  }
36473
- var sha256 = (b) => (0, import_node_crypto13.createHash)("sha256").update(b).digest("hex");
36654
+ var sha256 = (b) => (0, import_node_crypto14.createHash)("sha256").update(b).digest("hex");
36474
36655
  async function proveBundle(url, tag, fetchUrl) {
36475
36656
  const get = async (u) => {
36476
36657
  try {
@@ -36723,9 +36904,9 @@ async function waitSuiteDev(deps, opts) {
36723
36904
  }
36724
36905
 
36725
36906
  // src/suite-train.ts
36726
- var import_node_fs30 = require("node:fs");
36727
- var import_node_path29 = require("node:path");
36728
- var import_node_crypto14 = require("node:crypto");
36907
+ var import_node_fs31 = require("node:fs");
36908
+ var import_node_path30 = require("node:path");
36909
+ var import_node_crypto15 = require("node:crypto");
36729
36910
 
36730
36911
  // src/kit-version.ts
36731
36912
  var parse = (v) => /^(\d+)\.(\d+)\.(\d+)(-.+)?$/.exec(typeof v === "string" ? v.trim() : "");
@@ -36810,7 +36991,7 @@ function suiteReleaseTag(rc) {
36810
36991
  function readSuiteCut(path2) {
36811
36992
  let raw;
36812
36993
  try {
36813
- raw = (0, import_node_fs30.readFileSync)(path2, "utf8");
36994
+ raw = (0, import_node_fs31.readFileSync)(path2, "utf8");
36814
36995
  } catch (e) {
36815
36996
  if (e.code === "ENOENT") return void 0;
36816
36997
  throw e;
@@ -36826,11 +37007,11 @@ function readSuiteCut(path2) {
36826
37007
  return record;
36827
37008
  }
36828
37009
  function writeSuiteCut(path2, record) {
36829
- (0, import_node_fs30.mkdirSync)((0, import_node_path29.dirname)(path2), { recursive: true });
36830
- const temp = `${path2}.${(0, import_node_crypto14.randomBytes)(8).toString("hex")}.tmp`;
37010
+ (0, import_node_fs31.mkdirSync)((0, import_node_path30.dirname)(path2), { recursive: true });
37011
+ const temp = `${path2}.${(0, import_node_crypto15.randomBytes)(8).toString("hex")}.tmp`;
36831
37012
  try {
36832
- (0, import_node_fs30.writeFileSync)(temp, JSON.stringify(record, null, 2), { flag: "wx" });
36833
- (0, import_node_fs30.renameSync)(temp, path2);
37013
+ (0, import_node_fs31.writeFileSync)(temp, JSON.stringify(record, null, 2), { flag: "wx" });
37014
+ (0, import_node_fs31.renameSync)(temp, path2);
36834
37015
  } catch (e) {
36835
37016
  throw new Error(`suite cut record write failed at ${path2}: ${e.message}; stop, verify the file before retrying`);
36836
37017
  }
@@ -36879,25 +37060,25 @@ async function suiteMarkAbandoned(deps, ownerGo = false) {
36879
37060
  return tags.map((t) => `${t.repo}@${t.tag}`);
36880
37061
  }
36881
37062
  async function retireFailedLeadRcLedger(deps, ownerGo) {
36882
- if (!(0, import_node_fs30.existsSync)(deps.ledgerPath)) return void 0;
37063
+ if (!(0, import_node_fs31.existsSync)(deps.ledgerPath)) return void 0;
36883
37064
  return withLedgerLock(deps.ledgerPath, async (fence) => {
36884
- const ledger = parseReleaseLedger((0, import_node_fs30.readFileSync)(deps.ledgerPath, "utf8"));
37065
+ const ledger = parseReleaseLedger((0, import_node_fs31.readFileSync)(deps.ledgerPath, "utf8"));
36885
37066
  const states = Object.values(ledger.phases).map((p) => p.state);
36886
37067
  if (ledger.repo !== SUITE_REPO || ledger.lane !== "rcand" || ledger.phases.promotion.state === "complete" || !states.includes("failed")) return void 0;
36887
37068
  if (!ownerGo) throw new Error(`the lead's failed rcand ledger for ${ledger.tag} blocks every train; retire it with suite abandon --owner-go`);
36888
37069
  if ((await deps.rcHead())?.toLowerCase() === ledger.tagSha.toLowerCase()) throw new Error(`origin rc already points at ${ledger.tag}; it was promoted, so its ledger is not retired`);
36889
- const archive = (0, import_node_path29.join)((0, import_node_path29.dirname)(deps.ledgerPath), `phases.archive-${ledger.tag}.json`);
36890
- if ((0, import_node_fs30.existsSync)(archive)) throw new Error(`ledger archive already exists at ${archive}; inspect before retiring again`);
37070
+ const archive = (0, import_node_path30.join)((0, import_node_path30.dirname)(deps.ledgerPath), `phases.archive-${ledger.tag}.json`);
37071
+ if ((0, import_node_fs31.existsSync)(archive)) throw new Error(`ledger archive already exists at ${archive}; inspect before retiring again`);
36891
37072
  await deps.markAbandoned(SUITE_REPO, ledger.tag, ledger.tagSha);
36892
- await fence(() => (0, import_node_fs30.renameSync)(deps.ledgerPath, archive));
37073
+ await fence(() => (0, import_node_fs31.renameSync)(deps.ledgerPath, archive));
36893
37074
  return `${ledger.tag} (ledger archived to ${archive})`;
36894
37075
  });
36895
37076
  }
36896
37077
  function suiteAbandon(recordPath, ownerGo = false, now = /* @__PURE__ */ new Date()) {
36897
37078
  const record = abandonableCut(recordPath, ownerGo);
36898
37079
  const archive = `${recordPath}.abandoned-${record.leadDevelopment.slice(0, 12)}-${now.toISOString().replace(/[:.]/g, "")}.json`;
36899
- if ((0, import_node_fs30.existsSync)(archive)) throw new Error(`abandoned-cut archive already exists at ${archive}; inspect before abandoning again`);
36900
- (0, import_node_fs30.renameSync)(recordPath, archive);
37080
+ if ((0, import_node_fs31.existsSync)(archive)) throw new Error(`abandoned-cut archive already exists at ${archive}; inspect before abandoning again`);
37081
+ (0, import_node_fs31.renameSync)(recordPath, archive);
36901
37082
  return { archive, orphanTags: record.members.filter((m) => m.tag).map((m) => `${m.repo}@${m.tag}`) };
36902
37083
  }
36903
37084
  async function suiteRestoreMainPins(deps) {
@@ -36963,12 +37144,12 @@ async function suiteRcand(deps, opts) {
36963
37144
  }
36964
37145
  if ((record?.announcement === "sent" || record?.announcement === "skipped") && record.leadReleased) {
36965
37146
  const archive = `${deps.recordPath}.${record.leadRcTag}.json`;
36966
- if ((0, import_node_fs30.existsSync)(archive)) throw new Error(`suite cut archive already exists at ${archive}; inspect before a new cut`);
36967
- (0, import_node_fs30.renameSync)(deps.recordPath, archive);
37147
+ if ((0, import_node_fs31.existsSync)(archive)) throw new Error(`suite cut archive already exists at ${archive}; inspect before a new cut`);
37148
+ (0, import_node_fs31.renameSync)(deps.recordPath, archive);
36968
37149
  record = void 0;
36969
37150
  }
36970
37151
  if (record && !record.pinPr && !record.leadRcTag && record.members.every((m) => !m.tag)) {
36971
- (0, import_node_fs30.rmSync)(deps.recordPath, { force: true });
37152
+ (0, import_node_fs31.rmSync)(deps.recordPath, { force: true });
36972
37153
  record = void 0;
36973
37154
  }
36974
37155
  if (!record) {
@@ -37022,7 +37203,7 @@ async function suiteRcand(deps, opts) {
37022
37203
  quiet.push(member);
37023
37204
  }
37024
37205
  if (record.members.every((m) => m.carried || quiet.includes(m)) && await deps.contains(SUITE_REPO, record.leadDevelopment, record.leadPreviousRc)) {
37025
- (0, import_node_fs30.rmSync)(deps.recordPath, { force: true });
37206
+ (0, import_node_fs31.rmSync)(deps.recordPath, { force: true });
37026
37207
  throw new Error("nothing to promote: neither MM-Work nor any module has new development commits since its rc; no suite cut started");
37027
37208
  }
37028
37209
  for (const member of quiet) {
@@ -37040,7 +37221,7 @@ async function suiteRcand(deps, opts) {
37040
37221
  }
37041
37222
  if (refusals.length) {
37042
37223
  const untouched = record.members.every((m) => !m.tag) && !record.pinPr;
37043
- if (untouched) (0, import_node_fs30.rmSync)(deps.recordPath, { force: true });
37224
+ if (untouched) (0, import_node_fs31.rmSync)(deps.recordPath, { force: true });
37044
37225
  throw new Error(`module rc serving is not ready; ${untouched ? "no suite cut started" : "no new tag was cut"}:
37045
37226
  ${refusals.join("\n")}
37046
37227
  Each module must ship a live release that bind-mounts <deployPath>/data read-only and serves <data>/rc/module.js at /rc/module.js (docs/Guides/suite-trains.md).`);
@@ -37197,11 +37378,11 @@ Each member's live release must serve <data>/main/module.js at its main pin path
37197
37378
  }
37198
37379
  return record;
37199
37380
  }
37200
- var hotfixRecordPath = (deps) => (0, import_node_path29.join)((0, import_node_path29.dirname)(deps.recordPath), "hotfix.json");
37381
+ var hotfixRecordPath = (deps) => (0, import_node_path30.join)((0, import_node_path30.dirname)(deps.recordPath), "hotfix.json");
37201
37382
  function readSuiteHotfix(path2) {
37202
37383
  let raw;
37203
37384
  try {
37204
- raw = (0, import_node_fs30.readFileSync)(path2, "utf8");
37385
+ raw = (0, import_node_fs31.readFileSync)(path2, "utf8");
37205
37386
  } catch (e) {
37206
37387
  if (e.code === "ENOENT") return void 0;
37207
37388
  throw e;
@@ -37244,7 +37425,7 @@ async function suiteHotfix(deps, opts) {
37244
37425
  if (completed) record = void 0;
37245
37426
  if (record && record.repo !== found.repo) throw new Error(`an unfinished suite hotfix for ${record.repo} is recorded; finish it (rerun with that member) first`);
37246
37427
  if (!record?.tag) await deps.validateHotfixSummary();
37247
- if (completed) (0, import_node_fs30.renameSync)(path2, `${path2}.${completed.leadTag}.json`);
37428
+ if (completed) (0, import_node_fs31.renameSync)(path2, `${path2}.${completed.leadTag}.json`);
37248
37429
  const rec = record ?? { schema: "mmi-suite-hotfix/v1", member: found.id, repo: found.repo, from: opts.from, ...opts.ack?.length ? { ack: opts.ack } : {} };
37249
37430
  const save = () => writeSuiteHotfix(path2, rec);
37250
37431
  save();
@@ -37511,8 +37692,8 @@ async function runRcDataSwitch(deps, opts) {
37511
37692
  }
37512
37693
 
37513
37694
  // src/suite-train-io.ts
37514
- var import_node_fs44 = require("node:fs");
37515
- var import_node_path43 = require("node:path");
37695
+ var import_node_fs45 = require("node:fs");
37696
+ var import_node_path44 = require("node:path");
37516
37697
  init_cli_shared();
37517
37698
 
37518
37699
  // src/command-register-train-operations.ts
@@ -37867,8 +38048,8 @@ async function preflightHotfixBatchPicks(deps, sources, pickTolerated) {
37867
38048
  if (sources.length === 0) return { failures: [], skipped: [] };
37868
38049
  const { mkdtemp: mkdtemp2, rm: rm2 } = await import("node:fs/promises");
37869
38050
  const { tmpdir: tmpdir12 } = await import("node:os");
37870
- const { join: join47 } = await import("node:path");
37871
- const dir = await mkdtemp2(join47(tmpdir12(), "mmi-hotfix-preflight-"));
38051
+ const { join: join48 } = await import("node:path");
38052
+ const dir = await mkdtemp2(join48(tmpdir12(), "mmi-hotfix-preflight-"));
37872
38053
  const wt = { run: (file, args) => deps.run(file, file === "git" ? ["-C", dir, ...args] : args) };
37873
38054
  const failures = [];
37874
38055
  const skipped = [];
@@ -39189,9 +39370,9 @@ function checkHotfixCarries(options) {
39189
39370
  }
39190
39371
 
39191
39372
  // src/merge-cleanup.ts
39192
- var import_node_fs32 = require("node:fs");
39193
- var import_node_path31 = require("node:path");
39194
- var import_node_os18 = require("node:os");
39373
+ var import_node_fs33 = require("node:fs");
39374
+ var import_node_path32 = require("node:path");
39375
+ var import_node_os19 = require("node:os");
39195
39376
  init_cli_shared();
39196
39377
  init_github_client();
39197
39378
 
@@ -39505,8 +39686,8 @@ async function runPrLand(prNumber, options, deps) {
39505
39686
 
39506
39687
  // src/test-policy-core.ts
39507
39688
  var import_node_child_process13 = require("node:child_process");
39508
- var import_node_fs31 = require("node:fs");
39509
- var import_node_path30 = require("node:path");
39689
+ var import_node_fs32 = require("node:fs");
39690
+ var import_node_path31 = require("node:path");
39510
39691
 
39511
39692
  // src/test-command-policy-shared.mjs
39512
39693
  var import_node_child_process12 = require("node:child_process");
@@ -39982,7 +40163,7 @@ function isMeaningfulRow(file) {
39982
40163
  return file.meaningful !== false;
39983
40164
  }
39984
40165
  function loadPolicy(root, readFile10 = readFileOrNull2) {
39985
- const raw = readFile10((0, import_node_path30.join)(root, POLICY_FILE));
40166
+ const raw = readFile10((0, import_node_path31.join)(root, POLICY_FILE));
39986
40167
  if (raw == null) return { mandatory: [], declared: false };
39987
40168
  return parsePolicy(raw, POLICY_FILE);
39988
40169
  }
@@ -40059,7 +40240,7 @@ function loadPolicySource(root, explicitRef, diffBase) {
40059
40240
  }
40060
40241
  function readFileOrNull2(path2) {
40061
40242
  try {
40062
- return (0, import_node_fs31.readFileSync)(path2, "utf8");
40243
+ return (0, import_node_fs32.readFileSync)(path2, "utf8");
40063
40244
  } catch {
40064
40245
  return null;
40065
40246
  }
@@ -40087,12 +40268,12 @@ function classify(changed, policy, present = () => false) {
40087
40268
  const removedProtected = [...removed].filter((p) => protectedBy.has(p)).map((p) => ({ path: p, why: protectedBy.get(p) ?? "" }));
40088
40269
  return { mandatoryHits, untestedHits, testChanges, meaningfulTestChanges, addedTests, removedProtected };
40089
40270
  }
40090
- function unresolvedProtectedEntries(policy, root, exists = (path2) => (0, import_node_fs31.existsSync)(path2)) {
40091
- return (policy.protected ?? []).map((p) => p.path).filter((p) => !exists((0, import_node_path30.join)(root, p)));
40271
+ function unresolvedProtectedEntries(policy, root, exists = (path2) => (0, import_node_fs32.existsSync)(path2)) {
40272
+ return (policy.protected ?? []).map((p) => p.path).filter((p) => !exists((0, import_node_path31.join)(root, p)));
40092
40273
  }
40093
- function unresolvedSatisfiers(policy, root, exists = (path2) => (0, import_node_fs31.existsSync)(path2)) {
40274
+ function unresolvedSatisfiers(policy, root, exists = (path2) => (0, import_node_fs32.existsSync)(path2)) {
40094
40275
  const declared = (policy.mandatory ?? []).flatMap((m) => m.satisfiedBy ?? []);
40095
- return [...new Set(declared)].filter((p) => !exists((0, import_node_path30.join)(root, p)));
40276
+ return [...new Set(declared)].filter((p) => !exists((0, import_node_path31.join)(root, p)));
40096
40277
  }
40097
40278
  function evaluate(changed, policy, present = () => false) {
40098
40279
  const { mandatoryHits, untestedHits, meaningfulTestChanges, addedTests, removedProtected } = classify(changed, policy, present);
@@ -40231,14 +40412,14 @@ function runTestPolicy(root, deps = {}) {
40231
40412
  }
40232
40413
  const loaded = deps.policy ? { policy: deps.policy, source: { ref: null, sha: null, path: POLICY_FILE } } : loadPolicySource(root, deps.policyRef, deps.base);
40233
40414
  const { policy, source: policySource } = loaded;
40234
- const exists = deps.exists ?? ((path2) => (0, import_node_fs31.existsSync)(path2));
40415
+ const exists = deps.exists ?? ((path2) => (0, import_node_fs32.existsSync)(path2));
40235
40416
  const counts = { mandatoryCount: (policy.mandatory ?? []).length, protectedCount: (policy.protected ?? []).length };
40236
40417
  const base = deps.changed ? "(injected)" : deps.policyRef ? resolveHotfixBase(root) : resolveBase(root, deps.base);
40237
40418
  const refusal = deps.changed ? null : untrustworthyRange(root, base);
40238
40419
  const raw = deps.changed ?? (refusal ? [] : changedFilesSince(base, root));
40239
40420
  const changed = deps.changed ? raw : annotateChangeMeaning(raw, policy, (path2) => ({
40240
40421
  before: blobAt(base, path2, root),
40241
- after: readFileOrNull2((0, import_node_path30.join)(root, path2))
40422
+ after: readFileOrNull2((0, import_node_path31.join)(root, path2))
40242
40423
  }));
40243
40424
  const lookup = deps.override !== void 0 ? { override: deps.override, refusals: [] } : !deps.changed && !refusal ? readOverride2(base, root) : { override: null, refusals: [] };
40244
40425
  const policyRefusals = policy.declared === false ? [{
@@ -40248,8 +40429,8 @@ function runTestPolicy(root, deps = {}) {
40248
40429
  A gate with no policy cannot decide which test commands are required or permitted.
40249
40430
  ` + (deps.base === HOTFIX_DIFF_BASE ? ` Hotfix lane (--base ${HOTFIX_DIFF_BASE}): pass --policy-ref <exact-${HOTFIX_POLICY_REF}-commit> so the current policy is read from ${HOTFIX_POLICY_REF}.` : ` Restore ${POLICY_FILE} on this branch; the policy file belongs on every non-hotfix lane.`)
40250
40431
  }] : [];
40251
- const present = (path2) => exists((0, import_node_path30.join)(root, path2));
40252
- const policyTree = policySource.sha ? new Set(git2(["ls-tree", "-r", "-z", "--name-only", policySource.sha], root).split("\0").filter(Boolean).map((p) => (0, import_node_path30.join)(root, p))) : null;
40432
+ const present = (path2) => exists((0, import_node_path31.join)(root, path2));
40433
+ const policyTree = policySource.sha ? new Set(git2(["ls-tree", "-r", "-z", "--name-only", policySource.sha], root).split("\0").filter(Boolean).map((p) => (0, import_node_path31.join)(root, p))) : null;
40253
40434
  const policyTreeExists = policyTree ? (abs) => policyTree.has(abs) : exists;
40254
40435
  const where = policySource.sha ? `${policySource.ref}@${policySource.sha}` : "this worktree";
40255
40436
  const removedByThisDiff = removedPaths(changed);
@@ -40529,13 +40710,13 @@ function resolveSquashMergeBodyText(commits, allowedClosing, cwd) {
40529
40710
  return rewritten === base ? null : rewritten;
40530
40711
  }
40531
40712
  function writeSquashBodyFile(body) {
40532
- const dir = (0, import_node_fs32.mkdtempSync)((0, import_node_path31.join)((0, import_node_os18.tmpdir)(), "mmi-squash-body-"));
40533
- const path2 = (0, import_node_path31.join)(dir, "body.txt");
40534
- (0, import_node_fs32.writeFileSync)(path2, body.endsWith("\n") ? body : `${body}
40713
+ const dir = (0, import_node_fs33.mkdtempSync)((0, import_node_path32.join)((0, import_node_os19.tmpdir)(), "mmi-squash-body-"));
40714
+ const path2 = (0, import_node_path32.join)(dir, "body.txt");
40715
+ (0, import_node_fs33.writeFileSync)(path2, body.endsWith("\n") ? body : `${body}
40535
40716
  `, "utf8");
40536
40717
  return { path: path2, cleanup: () => {
40537
40718
  try {
40538
- (0, import_node_fs32.rmSync)(dir, { recursive: true, force: true });
40719
+ (0, import_node_fs33.rmSync)(dir, { recursive: true, force: true });
40539
40720
  } catch {
40540
40721
  }
40541
40722
  } };
@@ -40742,8 +40923,8 @@ async function deleteMergedRemoteBranch(options) {
40742
40923
  }
40743
40924
 
40744
40925
  // src/project-info-sync.ts
40745
- var import_node_fs33 = require("node:fs");
40746
- var import_node_path32 = require("node:path");
40926
+ var import_node_fs34 = require("node:fs");
40927
+ var import_node_path33 = require("node:path");
40747
40928
  var UPDATE_PROJECT_INFO = `mutation($projectId: ID!, $shortDescription: String!, $readme: String!) {
40748
40929
  updateProjectV2(input: { projectId: $projectId, shortDescription: $shortDescription, readme: $readme }) {
40749
40930
  projectV2 { id }
@@ -40790,14 +40971,14 @@ function sharedName(entries, fallback) {
40790
40971
  }
40791
40972
  function buildProjectInfoSyncPlan(targetRepo2, project2, projects, repoRoot2) {
40792
40973
  if (!project2.projectId) throw new Error(`org project sync-info: ${targetRepo2} registry META has no projectId`);
40793
- const readmePath = (0, import_node_path32.join)(repoRoot2, "README.md");
40794
- if (!(0, import_node_fs33.existsSync)(readmePath)) throw new Error(`org project sync-info: ${targetRepo2} has no README.md`);
40974
+ const readmePath = (0, import_node_path33.join)(repoRoot2, "README.md");
40975
+ if (!(0, import_node_fs34.existsSync)(readmePath)) throw new Error(`org project sync-info: ${targetRepo2} has no README.md`);
40795
40976
  const entries = entriesFor(project2, projects);
40796
40977
  const memberRepos = [...new Set(entries.flatMap((entry) => entry.repos ?? []))].filter((repo) => /^[^/]+\/[^/]+$/.test(repo)).sort((a, b) => a.localeCompare(b));
40797
40978
  const projectName = sharedName(entries, project2.name?.trim() || targetRepo2.split("/").pop() || targetRepo2);
40798
40979
  if (!memberRepos.length) throw new Error(`org project sync-info: project ${projectName} has no registered member repos`);
40799
40980
  const entryNames = entries.map((entry) => entry.name?.trim()).filter((name) => Boolean(name));
40800
- const shortDescription = memberRepos.length === 1 ? shortDescriptionFromReadme((0, import_node_fs33.readFileSync)(readmePath, "utf8")) : `Shared work across ${new Intl.ListFormat("en", { type: "conjunction" }).format(entryNames)}.`;
40981
+ const shortDescription = memberRepos.length === 1 ? shortDescriptionFromReadme((0, import_node_fs34.readFileSync)(readmePath, "utf8")) : `Shared work across ${new Intl.ListFormat("en", { type: "conjunction" }).format(entryNames)}.`;
40801
40982
  const lines2 = [
40802
40983
  `# ${projectName}`,
40803
40984
  "",
@@ -40816,8 +40997,8 @@ function buildProjectInfoSyncPlan(targetRepo2, project2, projects, repoRoot2) {
40816
40997
  const targetBase = `https://github.com/${targetRepo2}`;
40817
40998
  const targetBranch = branchFor(targetRepo2, projects);
40818
40999
  const orgDocs = [
40819
- (0, import_node_fs33.existsSync)((0, import_node_path32.join)(repoRoot2, "architecture.md")) ? `- [Hub architecture](${targetBase}/blob/${targetBranch}/architecture.md)` : "",
40820
- (0, import_node_fs33.existsSync)((0, import_node_path32.join)(repoRoot2, "docs", "Architecture", "agentic-dev-environment.md")) ? `- [Agentic development environment](${targetBase}/blob/${targetBranch}/docs/Architecture/agentic-dev-environment.md)` : ""
41000
+ (0, import_node_fs34.existsSync)((0, import_node_path33.join)(repoRoot2, "architecture.md")) ? `- [Hub architecture](${targetBase}/blob/${targetBranch}/architecture.md)` : "",
41001
+ (0, import_node_fs34.existsSync)((0, import_node_path33.join)(repoRoot2, "docs", "Architecture", "agentic-dev-environment.md")) ? `- [Agentic development environment](${targetBase}/blob/${targetBranch}/docs/Architecture/agentic-dev-environment.md)` : ""
40821
41002
  ].filter(Boolean);
40822
41003
  if (orgDocs.length) lines2.push("", "## Organisation docs", "", ...orgDocs);
40823
41004
  return { projectId: project2.projectId, projectName, targetRepo: targetRepo2, memberRepos, shortDescription, readme: `${lines2.join("\n")}
@@ -40839,8 +41020,8 @@ async function syncProjectInfo(plan, client, apply) {
40839
41020
  }
40840
41021
 
40841
41022
  // src/train-commands.ts
40842
- var import_node_fs34 = require("node:fs");
40843
- var import_node_path33 = require("node:path");
41023
+ var import_node_fs35 = require("node:fs");
41024
+ var import_node_path34 = require("node:path");
40844
41025
  init_cli_shared();
40845
41026
  init_clean_exit();
40846
41027
  init_client_version();
@@ -40855,7 +41036,7 @@ function resolveReleaseBumpIntent(raw) {
40855
41036
  }
40856
41037
  function readRepoVersion() {
40857
41038
  try {
40858
- return JSON.parse((0, import_node_fs34.readFileSync)((0, import_node_path33.join)(process.cwd(), ".claude-plugin", "plugin.json"), "utf8")).version || void 0;
41039
+ return JSON.parse((0, import_node_fs35.readFileSync)((0, import_node_path34.join)(process.cwd(), ".claude-plugin", "plugin.json"), "utf8")).version || void 0;
40859
41040
  } catch {
40860
41041
  return void 0;
40861
41042
  }
@@ -40966,7 +41147,7 @@ function releaseProgressVerdict(status, subject = "Release") {
40966
41147
 
40967
41148
  // src/suite-pin.ts
40968
41149
  var import_promises6 = require("node:fs/promises");
40969
- var import_node_path34 = require("node:path");
41150
+ var import_node_path35 = require("node:path");
40970
41151
  var SuitePinError = class _SuitePinError extends Error {
40971
41152
  diagnostic;
40972
41153
  constructor(repo, tag, error) {
@@ -41034,8 +41215,8 @@ async function openSuiteCutPinPr(deps, input) {
41034
41215
  if (input.carriedOnly) return { status: "unchanged" };
41035
41216
  throw new Error("pins already match without a merged cut PR \u2014 provenance unverified");
41036
41217
  }
41037
- await (0, import_promises6.mkdir)((0, import_node_path34.join)(deps.root, "tmp"), { recursive: true });
41038
- scratch = await (0, import_promises6.mkdtemp)((0, import_node_path34.join)(deps.root, "tmp", "suite-pin-"));
41218
+ await (0, import_promises6.mkdir)((0, import_node_path35.join)(deps.root, "tmp"), { recursive: true });
41219
+ scratch = await (0, import_promises6.mkdtemp)((0, import_node_path35.join)(deps.root, "tmp", "suite-pin-"));
41039
41220
  const run = (file, args) => deps.run(file, args, scratch);
41040
41221
  await run("git", ["clone", "--quiet", "--branch", prs.length ? branch : "development", "--single-branch", `https://github.com/${SUITE_REPO}.git`, "."]);
41041
41222
  if (prs.length) {
@@ -41047,7 +41228,7 @@ async function openSuiteCutPinPr(deps, input) {
41047
41228
  await run("git", ["switch", "-c", branch]);
41048
41229
  }
41049
41230
  for (const stage of ["rc", "main"]) {
41050
- const path2 = (0, import_node_path34.join)(scratch, `${stage}-pins.json`);
41231
+ const path2 = (0, import_node_path35.join)(scratch, `${stage}-pins.json`);
41051
41232
  await (0, import_promises6.writeFile)(path2, JSON.stringify(input.pins.map((p) => ({ module: p.module, url: p[stage] }))));
41052
41233
  await run("node", ["scripts/pin-modules.mjs", "--stage", stage, "--pins", path2]);
41053
41234
  }
@@ -41100,12 +41281,12 @@ async function openSuiteRestorePinPr(deps, input) {
41100
41281
  }
41101
41282
  });
41102
41283
  if (!todo.length) return void 0;
41103
- await (0, import_promises6.mkdir)((0, import_node_path34.join)(deps.root, "tmp"), { recursive: true });
41104
- scratch = await (0, import_promises6.mkdtemp)((0, import_node_path34.join)(deps.root, "tmp", "suite-pin-"));
41284
+ await (0, import_promises6.mkdir)((0, import_node_path35.join)(deps.root, "tmp"), { recursive: true });
41285
+ scratch = await (0, import_promises6.mkdtemp)((0, import_node_path35.join)(deps.root, "tmp", "suite-pin-"));
41105
41286
  const run = (file, args) => deps.run(file, args, scratch);
41106
41287
  await run("git", ["clone", "--quiet", "--branch", "development", "--single-branch", `https://github.com/${SUITE_REPO}.git`, "."]);
41107
41288
  await run("git", ["switch", "-c", branch]);
41108
- const path2 = (0, import_node_path34.join)(scratch, "main-pins.json");
41289
+ const path2 = (0, import_node_path35.join)(scratch, "main-pins.json");
41109
41290
  await (0, import_promises6.writeFile)(path2, JSON.stringify(todo.map((p) => ({ module: p.module, url: p.prior }))));
41110
41291
  await run("node", ["scripts/pin-modules.mjs", "--stage", "main", "--pins", path2]);
41111
41292
  await run("git", ["add", "seed/modules.json"]);
@@ -41179,8 +41360,8 @@ async function openSuitePinPr(deps, input) {
41179
41360
  if (newer.length) return { status: "superseded", pr: newer[0].url, url: pin };
41180
41361
  const open2 = onBranch.find((p) => p.state === "OPEN");
41181
41362
  if (open2 && tagOf(open2.title ?? "") === tag) return { status: "pending", pr: open2.url, url: pin };
41182
- await (0, import_promises6.mkdir)((0, import_node_path34.join)(deps.root, "tmp"), { recursive: true });
41183
- scratch = await (0, import_promises6.mkdtemp)((0, import_node_path34.join)(deps.root, "tmp", "suite-pin-"));
41363
+ await (0, import_promises6.mkdir)((0, import_node_path35.join)(deps.root, "tmp"), { recursive: true });
41364
+ scratch = await (0, import_promises6.mkdtemp)((0, import_node_path35.join)(deps.root, "tmp", "suite-pin-"));
41184
41365
  const run = (file, args) => deps.run(file, args, scratch);
41185
41366
  await run("git", ["clone", "--quiet", "--branch", "development", "--single-branch", `https://github.com/${SUITE_REPO}.git`, "."]);
41186
41367
  await run("git", ["switch", "-c", branch]);
@@ -41220,7 +41401,7 @@ async function openSuitePinPr(deps, input) {
41220
41401
 
41221
41402
  // src/command-register-collaboration.ts
41222
41403
  var import_node_child_process17 = require("node:child_process");
41223
- var import_node_fs43 = require("node:fs");
41404
+ var import_node_fs44 = require("node:fs");
41224
41405
  var import_promises8 = require("node:fs/promises");
41225
41406
  init_clean_exit();
41226
41407
  init_cli_shared();
@@ -41244,11 +41425,11 @@ function spawnDetachedSelf(args, deps, opts = {}) {
41244
41425
  }
41245
41426
 
41246
41427
  // src/command-register-collaboration.ts
41247
- var import_node_path42 = require("node:path");
41428
+ var import_node_path43 = require("node:path");
41248
41429
  init_house_map();
41249
41430
 
41250
41431
  // src/issue-body.ts
41251
- var import_node_os19 = require("node:os");
41432
+ var import_node_os20 = require("node:os");
41252
41433
  init_error_codes();
41253
41434
  var TextArgError = class extends Error {
41254
41435
  constructor(message2, code, offendingFlag) {
@@ -41261,7 +41442,7 @@ var TextArgError = class extends Error {
41261
41442
  offendingFlag;
41262
41443
  };
41263
41444
  function emptyStdinMessage(fileFlag) {
41264
- if ((0, import_node_os19.platform)() === "win32") {
41445
+ if ((0, import_node_os20.platform)() === "win32") {
41265
41446
  return `${fileFlag} - read empty stdin (on Windows, ${fileFlag} - is unreliable through the npm .cmd shim \u2014 use ${fileFlag} <path>, or pipe to \`node cli/dist/index.cjs\` directly)`;
41266
41447
  }
41267
41448
  return `${fileFlag} - read empty stdin (nothing piped \u2014 pass a heredoc/pipe, or ${fileFlag} <path>)`;
@@ -41354,8 +41535,8 @@ init_github_client();
41354
41535
  init_github_quota();
41355
41536
 
41356
41537
  // src/issue-commands.ts
41357
- var import_node_fs35 = require("node:fs");
41358
- var import_node_crypto15 = require("node:crypto");
41538
+ var import_node_fs36 = require("node:fs");
41539
+ var import_node_crypto16 = require("node:crypto");
41359
41540
  init_cli_shared();
41360
41541
  init_clean_exit();
41361
41542
  init_error_codes();
@@ -41547,7 +41728,7 @@ async function editIssue(client, options, deps = {}) {
41547
41728
  const url = `https://github.com/${repo}/issues/${parsed.number}`;
41548
41729
  const patch = {};
41549
41730
  let bodyChanged = false;
41550
- const textDeps = () => deps.textDeps ?? { readFile: (p, e) => Promise.resolve((0, import_node_fs35.readFileSync)(p, e)), readStdin: () => Promise.resolve("") };
41731
+ const textDeps = () => deps.textDeps ?? { readFile: (p, e) => Promise.resolve((0, import_node_fs36.readFileSync)(p, e)), readStdin: () => Promise.resolve("") };
41551
41732
  if (options.titleFile !== void 0) {
41552
41733
  patch.title = await resolveIssueTitle({ title: options.title, titleFile: options.titleFile }, textDeps());
41553
41734
  } else if (options.title !== void 0) {
@@ -41828,7 +42009,7 @@ function rowIdempotencyKey(batchKey, spec) {
41828
42009
  const identity = `${spec.type}
41829
42010
  ${spec.title.trim()}
41830
42011
  ${spec.body ?? ""}`;
41831
- const hash = (0, import_node_crypto15.createHash)("sha256").update(identity).digest("hex").slice(0, 16);
42012
+ const hash = (0, import_node_crypto16.createHash)("sha256").update(identity).digest("hex").slice(0, 16);
41832
42013
  return `${batchKey}:${hash}`;
41833
42014
  }
41834
42015
  var BATCH_SPEC_KEYS = /* @__PURE__ */ new Set(["type", "title", "body", "priority", "labels", "label", "parent", "repo", "surface"]);
@@ -42210,7 +42391,7 @@ function extendCreateCommand(issue, batchAttach) {
42210
42391
  if (opts.batch) {
42211
42392
  let specs;
42212
42393
  try {
42213
- const raw = (0, import_node_fs35.readFileSync)(opts.batch, "utf8");
42394
+ const raw = (0, import_node_fs36.readFileSync)(opts.batch, "utf8");
42214
42395
  specs = JSON.parse(raw);
42215
42396
  if (!Array.isArray(specs)) {
42216
42397
  const top = specs === null ? "null" : typeof specs === "object" ? `an object with keys: ${Object.keys(specs).join(", ") || "(none)"}` : `a ${typeof specs}`;
@@ -42287,8 +42468,8 @@ ${lines2}`, {
42287
42468
  }
42288
42469
 
42289
42470
  // src/post-merge-recon.ts
42290
- var import_node_fs36 = require("node:fs");
42291
- var import_node_path35 = require("node:path");
42471
+ var import_node_fs37 = require("node:fs");
42472
+ var import_node_path36 = require("node:path");
42292
42473
 
42293
42474
  // src/cross-repo-filing-issue.ts
42294
42475
  init_github_client();
@@ -42457,16 +42638,16 @@ function buildPostMergeReconRecovery(input) {
42457
42638
  }
42458
42639
  function writePostMergeReconRecovery(cwd, recovery) {
42459
42640
  const path2 = postMergeReconStatePath(cwd, recovery.repo, recovery.pr);
42460
- (0, import_node_fs36.mkdirSync)((0, import_node_path35.dirname)(path2), { recursive: true });
42461
- (0, import_node_fs36.writeFileSync)(path2, `${JSON.stringify(recovery, null, 2)}
42641
+ (0, import_node_fs37.mkdirSync)((0, import_node_path36.dirname)(path2), { recursive: true });
42642
+ (0, import_node_fs37.writeFileSync)(path2, `${JSON.stringify(recovery, null, 2)}
42462
42643
  `, "utf8");
42463
42644
  return path2;
42464
42645
  }
42465
42646
  function clearPostMergeReconRecovery(cwd, repo, pr) {
42466
42647
  const path2 = postMergeReconStatePath(cwd, repo, pr);
42467
- if (!(0, import_node_fs36.existsSync)(path2)) return;
42648
+ if (!(0, import_node_fs37.existsSync)(path2)) return;
42468
42649
  try {
42469
- (0, import_node_fs36.unlinkSync)(path2);
42650
+ (0, import_node_fs37.unlinkSync)(path2);
42470
42651
  } catch {
42471
42652
  }
42472
42653
  }
@@ -42942,9 +43123,9 @@ function registerPrLifecycleCommands(program3) {
42942
43123
 
42943
43124
  // src/review-verdict.ts
42944
43125
  var import_node_child_process14 = require("node:child_process");
42945
- var import_node_fs37 = require("node:fs");
42946
- var import_node_os20 = require("node:os");
42947
- var import_node_path36 = require("node:path");
43126
+ var import_node_fs38 = require("node:fs");
43127
+ var import_node_os21 = require("node:os");
43128
+ var import_node_path37 = require("node:path");
42948
43129
  init_cli_shared();
42949
43130
  var REVIEW_VERDICT_MARKER = "<!-- zeroci-review v1 -->";
42950
43131
  var REVIEW_VERDICTS = ["PROCEED", "CORRECT", "ESCALATE"];
@@ -43109,15 +43290,15 @@ async function readPrIssueComments(number, repo) {
43109
43290
  return comments;
43110
43291
  }
43111
43292
  async function postPrCommentFromFile(number, repo, body) {
43112
- const dir = (0, import_node_fs37.mkdtempSync)((0, import_node_path36.join)((0, import_node_os20.tmpdir)(), "mmi-review-verdict-"));
43113
- const path2 = (0, import_node_path36.join)(dir, "body.md");
43293
+ const dir = (0, import_node_fs38.mkdtempSync)((0, import_node_path37.join)((0, import_node_os21.tmpdir)(), "mmi-review-verdict-"));
43294
+ const path2 = (0, import_node_path37.join)(dir, "body.md");
43114
43295
  try {
43115
- (0, import_node_fs37.writeFileSync)(path2, body, "utf8");
43296
+ (0, import_node_fs38.writeFileSync)(path2, body, "utf8");
43116
43297
  const { stdout } = await execFileP("gh", ["pr", "comment", number, "--repo", repo, "--body-file", path2], { timeout: GH_MUTATION_TIMEOUT_MS });
43117
43298
  return stdout.trim();
43118
43299
  } finally {
43119
43300
  try {
43120
- (0, import_node_fs37.rmSync)(dir, { recursive: true, force: true });
43301
+ (0, import_node_fs38.rmSync)(dir, { recursive: true, force: true });
43121
43302
  } catch {
43122
43303
  }
43123
43304
  }
@@ -43351,18 +43532,18 @@ async function prCreateClaimRefusal(body, repoOption, deps = {}) {
43351
43532
  }
43352
43533
 
43353
43534
  // src/worktree-residue-sweep.ts
43354
- var import_node_fs42 = require("node:fs");
43355
- var import_node_path41 = require("node:path");
43535
+ var import_node_fs43 = require("node:fs");
43536
+ var import_node_path42 = require("node:path");
43356
43537
 
43357
43538
  // src/worktree-merge-cleanup.ts
43358
- var import_node_fs41 = require("node:fs");
43359
- var import_node_path40 = require("node:path");
43539
+ var import_node_fs42 = require("node:fs");
43540
+ var import_node_path41 = require("node:path");
43360
43541
  init_cli_shared();
43361
43542
 
43362
43543
  // src/stage-runner.ts
43363
43544
  var import_node_child_process16 = require("node:child_process");
43364
- var import_node_fs39 = require("node:fs");
43365
- var import_node_path38 = require("node:path");
43545
+ var import_node_fs40 = require("node:fs");
43546
+ var import_node_path39 = require("node:path");
43366
43547
  var import_node_net = require("node:net");
43367
43548
  var import_node_util5 = require("node:util");
43368
43549
 
@@ -43372,8 +43553,8 @@ function normalizeEol2(s) {
43372
43553
  }
43373
43554
 
43374
43555
  // src/env-detection.ts
43375
- var import_node_fs38 = require("node:fs");
43376
- var import_node_path37 = require("node:path");
43556
+ var import_node_fs39 = require("node:fs");
43557
+ var import_node_path38 = require("node:path");
43377
43558
  var SKIPPED_DIRS = /* @__PURE__ */ new Set([".git", "node_modules", "dist", ".jerv", ".pi", ".venv", "venv"]);
43378
43559
  function isEnvBaseName(name) {
43379
43560
  return name.toLowerCase() === ".env";
@@ -43383,7 +43564,7 @@ function findEnvFiles(root) {
43383
43564
  const walk2 = (dir, rel) => {
43384
43565
  let entries;
43385
43566
  try {
43386
- entries = (0, import_node_fs38.readdirSync)(dir, { withFileTypes: true });
43567
+ entries = (0, import_node_fs39.readdirSync)(dir, { withFileTypes: true });
43387
43568
  } catch {
43388
43569
  return;
43389
43570
  }
@@ -43391,13 +43572,13 @@ function findEnvFiles(root) {
43391
43572
  const relPath = rel ? `${rel}/${entry.name}` : entry.name;
43392
43573
  if (entry.isDirectory()) {
43393
43574
  if (SKIPPED_DIRS.has(entry.name)) continue;
43394
- walk2((0, import_node_path37.join)(dir, entry.name), relPath);
43575
+ walk2((0, import_node_path38.join)(dir, entry.name), relPath);
43395
43576
  continue;
43396
43577
  }
43397
43578
  if (isEnvBaseName(entry.name)) {
43398
43579
  let isDir = false;
43399
43580
  try {
43400
- isDir = (0, import_node_fs38.lstatSync)((0, import_node_path37.join)(dir, entry.name)).isDirectory();
43581
+ isDir = (0, import_node_fs39.lstatSync)((0, import_node_path38.join)(dir, entry.name)).isDirectory();
43401
43582
  } catch {
43402
43583
  }
43403
43584
  if (!isDir) found.push(relPath);
@@ -43536,12 +43717,12 @@ var DOCKER_TIMEOUT_MS = 15e3;
43536
43717
  function stageBash() {
43537
43718
  if (process.platform !== "win32") return "bash";
43538
43719
  const configured = process.env.SHELL;
43539
- if (configured && (0, import_node_path38.isAbsolute)(configured) && /[/\\]bash(?:\.exe)?$/i.test(configured) && !/[/\\](?:System32|Sysnative)[/\\]bash(?:\.exe)?$/i.test(configured) && (0, import_node_fs39.existsSync)(configured)) return configured;
43720
+ if (configured && (0, import_node_path39.isAbsolute)(configured) && /[/\\]bash(?:\.exe)?$/i.test(configured) && !/[/\\](?:System32|Sysnative)[/\\]bash(?:\.exe)?$/i.test(configured) && (0, import_node_fs40.existsSync)(configured)) return configured;
43540
43721
  const candidates = [
43541
- (0, import_node_path38.join)(process.env.ProgramFiles || "C:\\Program Files", "Git", "bin", "bash.exe"),
43542
- ...process.env.LOCALAPPDATA ? [(0, import_node_path38.join)(process.env.LOCALAPPDATA, "Programs", "Git", "bin", "bash.exe")] : []
43722
+ (0, import_node_path39.join)(process.env.ProgramFiles || "C:\\Program Files", "Git", "bin", "bash.exe"),
43723
+ ...process.env.LOCALAPPDATA ? [(0, import_node_path39.join)(process.env.LOCALAPPDATA, "Programs", "Git", "bin", "bash.exe")] : []
43543
43724
  ];
43544
- const bash = candidates.find((path2) => (0, import_node_fs39.existsSync)(path2));
43725
+ const bash = candidates.find((path2) => (0, import_node_fs40.existsSync)(path2));
43545
43726
  if (!bash) throw new Error("Local stages require Git Bash on Windows. Install Git for Windows or set SHELL to its absolute bash.exe path.");
43546
43727
  return bash;
43547
43728
  }
@@ -43679,7 +43860,7 @@ function appendForceRecreate(up) {
43679
43860
  return `${up.trimEnd()} --force-recreate`;
43680
43861
  }
43681
43862
  function stageStatePath(cwd = process.cwd()) {
43682
- return (0, import_node_path38.join)(cwd, "tmp", "stage", "state.json");
43863
+ return (0, import_node_path39.join)(cwd, "tmp", "stage", "state.json");
43683
43864
  }
43684
43865
  function normPath(path2) {
43685
43866
  return path2.replace(/\\/g, "/").replace(/\/+$/, "").toLowerCase();
@@ -43896,8 +44077,8 @@ function stageProcessEnv(stagePort, extraEnv) {
43896
44077
  }
43897
44078
  function composeResolvesPort(cwd) {
43898
44079
  if (process.env.PORT) return true;
43899
- const envFile = (0, import_node_path38.join)(cwd, ".env");
43900
- return (0, import_node_fs39.existsSync)(envFile) && envFileKeys((0, import_node_fs39.readFileSync)(envFile, "utf8")).has("PORT");
44080
+ const envFile = (0, import_node_path39.join)(cwd, ".env");
44081
+ return (0, import_node_fs40.existsSync)(envFile) && envFileKeys((0, import_node_fs40.readFileSync)(envFile, "utf8")).has("PORT");
43901
44082
  }
43902
44083
  function stageComposeEnv(config, stagePort, vaultEnvMerge, cwd) {
43903
44084
  const composeProject = config.env?.COMPOSE_PROJECT_NAME ?? vaultEnvMerge?.COMPOSE_PROJECT_NAME ?? stageComposeProjectName(cwd);
@@ -43912,13 +44093,13 @@ function stageComposeEnv(config, stagePort, vaultEnvMerge, cwd) {
43912
44093
  function stageComposeFiles(cwd) {
43913
44094
  const files = ["docker-compose.yml"];
43914
44095
  for (const conventional of ["docker-compose.override.yml", "docker-compose.override.yaml"]) {
43915
- if ((0, import_node_fs39.existsSync)((0, import_node_path38.join)(cwd, conventional))) files.push(conventional);
44096
+ if ((0, import_node_fs40.existsSync)((0, import_node_path39.join)(cwd, conventional))) files.push(conventional);
43916
44097
  }
43917
44098
  return [...files, RUNTIME_ENV_OVERRIDE_RELPATH];
43918
44099
  }
43919
44100
  async function prepareRuntimeEnvPassthrough(cwd, composeEnv, vaultEnvMerge) {
43920
44101
  const keys = Object.keys(vaultEnvMerge ?? {});
43921
- if (!keys.length || !(0, import_node_fs39.existsSync)((0, import_node_path38.join)(cwd, "docker-compose.yml"))) return {};
44102
+ if (!keys.length || !(0, import_node_fs40.existsSync)((0, import_node_path39.join)(cwd, "docker-compose.yml"))) return {};
43922
44103
  let configJson;
43923
44104
  try {
43924
44105
  const { stdout } = await execFileP3("docker", ["compose", "config", "--format", "json"], {
@@ -43934,21 +44115,21 @@ async function prepareRuntimeEnvPassthrough(cwd, composeEnv, vaultEnvMerge) {
43934
44115
  }
43935
44116
  const body = renderRuntimeEnvOverride(runtimeEnvMarkedServices(configJson), keys, runtimeEnvExcludes(configJson), runtimeEnvSelects(configJson));
43936
44117
  if (!body) return {};
43937
- const overridePath = (0, import_node_path38.join)(cwd, RUNTIME_ENV_OVERRIDE_RELPATH);
43938
- (0, import_node_fs39.mkdirSync)((0, import_node_path38.join)(cwd, "tmp", "stage"), { recursive: true });
43939
- (0, import_node_fs39.writeFileSync)(overridePath, body, "utf8");
44118
+ const overridePath = (0, import_node_path39.join)(cwd, RUNTIME_ENV_OVERRIDE_RELPATH);
44119
+ (0, import_node_fs40.mkdirSync)((0, import_node_path39.join)(cwd, "tmp", "stage"), { recursive: true });
44120
+ (0, import_node_fs40.writeFileSync)(overridePath, body, "utf8");
43940
44121
  return stageComposeFileEnv(stageComposeFiles(cwd));
43941
44122
  }
43942
44123
  async function ensureStageRuntimeEnv(config, opts, cwd) {
43943
44124
  if (!config.ensureEnv) return;
43944
- const target = (0, import_node_path38.join)(cwd, config.ensureEnv.target);
43945
- const example = (0, import_node_path38.join)(cwd, config.ensureEnv.example);
43946
- if (!(0, import_node_fs39.existsSync)(target) && (0, import_node_fs39.existsSync)(example)) {
43947
- (0, import_node_fs39.copyFileSync)(example, target);
43948
- } else if ((0, import_node_fs39.existsSync)(target) && (0, import_node_fs39.existsSync)(example)) {
43949
- const stale = detectStaleEnvFile((0, import_node_fs39.readFileSync)(example, "utf8"), (0, import_node_fs39.readFileSync)(target, "utf8"), {
43950
- exampleMtimeMs: (0, import_node_fs39.statSync)(example).mtimeMs,
43951
- targetMtimeMs: (0, import_node_fs39.statSync)(target).mtimeMs
44125
+ const target = (0, import_node_path39.join)(cwd, config.ensureEnv.target);
44126
+ const example = (0, import_node_path39.join)(cwd, config.ensureEnv.example);
44127
+ if (!(0, import_node_fs40.existsSync)(target) && (0, import_node_fs40.existsSync)(example)) {
44128
+ (0, import_node_fs40.copyFileSync)(example, target);
44129
+ } else if ((0, import_node_fs40.existsSync)(target) && (0, import_node_fs40.existsSync)(example)) {
44130
+ const stale = detectStaleEnvFile((0, import_node_fs40.readFileSync)(example, "utf8"), (0, import_node_fs40.readFileSync)(target, "utf8"), {
44131
+ exampleMtimeMs: (0, import_node_fs40.statSync)(example).mtimeMs,
44132
+ targetMtimeMs: (0, import_node_fs40.statSync)(target).mtimeMs
43952
44133
  });
43953
44134
  if (stale) {
43954
44135
  const msg = `stale ${config.ensureEnv.target} (${stale}) \u2014 delete it or refresh from ${config.ensureEnv.example} before re-running /stage`;
@@ -43956,8 +44137,8 @@ async function ensureStageRuntimeEnv(config, opts, cwd) {
43956
44137
  console.error(`mmi-cli stage: ${msg} (allowed via --allow-stale-env)`);
43957
44138
  }
43958
44139
  }
43959
- if (opts.vaultEnvMerge && Object.keys(opts.vaultEnvMerge).length && (0, import_node_fs39.existsSync)(target)) {
43960
- (0, import_node_fs39.writeFileSync)(target, mergeEnvSecretsIntoFile((0, import_node_fs39.readFileSync)(target, "utf8"), opts.vaultEnvMerge), "utf8");
44140
+ if (opts.vaultEnvMerge && Object.keys(opts.vaultEnvMerge).length && (0, import_node_fs40.existsSync)(target)) {
44141
+ (0, import_node_fs40.writeFileSync)(target, mergeEnvSecretsIntoFile((0, import_node_fs40.readFileSync)(target, "utf8"), opts.vaultEnvMerge), "utf8");
43961
44142
  }
43962
44143
  }
43963
44144
  async function gitText(cwd, args) {
@@ -43987,20 +44168,20 @@ async function resolveGlobalStatePath(cwd, explicit) {
43987
44168
  return void 0;
43988
44169
  }
43989
44170
  function readState(path2) {
43990
- if (!(0, import_node_fs39.existsSync)(path2)) return null;
44171
+ if (!(0, import_node_fs40.existsSync)(path2)) return null;
43991
44172
  try {
43992
- return JSON.parse((0, import_node_fs39.readFileSync)(path2, "utf8"));
44173
+ return JSON.parse((0, import_node_fs40.readFileSync)(path2, "utf8"));
43993
44174
  } catch {
43994
44175
  return null;
43995
44176
  }
43996
44177
  }
43997
44178
  function mkdirFor(path2) {
43998
44179
  const dir = path2.slice(0, Math.max(path2.lastIndexOf("/"), path2.lastIndexOf("\\")));
43999
- (0, import_node_fs39.mkdirSync)(dir, { recursive: true });
44180
+ (0, import_node_fs40.mkdirSync)(dir, { recursive: true });
44000
44181
  }
44001
44182
  function writeState(path2, state) {
44002
44183
  mkdirFor(path2);
44003
- (0, import_node_fs39.writeFileSync)(path2, JSON.stringify(state, null, 2), "utf8");
44184
+ (0, import_node_fs40.writeFileSync)(path2, JSON.stringify(state, null, 2), "utf8");
44004
44185
  }
44005
44186
  function writeStagePortReservation(port, cwd, statePath, globalStatePath, now) {
44006
44187
  const reservation = {
@@ -44029,7 +44210,7 @@ async function cleanupStageState(state, paths, timeoutMs, fallbackCwd, currentEn
44029
44210
  );
44030
44211
  }
44031
44212
  for (const path2 of [...new Set(paths.filter((p) => Boolean(p)))]) {
44032
- (0, import_node_fs39.rmSync)(path2, { force: true });
44213
+ (0, import_node_fs40.rmSync)(path2, { force: true });
44033
44214
  }
44034
44215
  }
44035
44216
  async function killTree(pid) {
@@ -44276,8 +44457,8 @@ async function runStage(config = {}, opts = {}) {
44276
44457
  });
44277
44458
  }
44278
44459
  } catch (e) {
44279
- (0, import_node_fs39.rmSync)(statePath, { force: true });
44280
- if (globalStatePath && globalStatePath !== statePath) (0, import_node_fs39.rmSync)(globalStatePath, { force: true });
44460
+ (0, import_node_fs40.rmSync)(statePath, { force: true });
44461
+ if (globalStatePath && globalStatePath !== statePath) (0, import_node_fs40.rmSync)(globalStatePath, { force: true });
44281
44462
  throw e;
44282
44463
  }
44283
44464
  const started = await startStage(config, {
@@ -44292,8 +44473,8 @@ async function runStage(config = {}, opts = {}) {
44292
44473
  }
44293
44474
 
44294
44475
  // src/worktree-evidence-archive.ts
44295
- var import_node_fs40 = require("node:fs");
44296
- var import_node_path39 = require("node:path");
44476
+ var import_node_fs41 = require("node:fs");
44477
+ var import_node_path40 = require("node:path");
44297
44478
  var JERV_ARTIFACT_RUN_SCOPE_ENV_VARS = ["JERV_RUN_ID", ...SESSION_ID_ENV_VARS];
44298
44479
  function sanitizeArchiveSegment(value, max = 80) {
44299
44480
  const scrubbed = value.replace(/[^A-Za-z0-9._@+-]+/g, "-").replace(/^-+|-+$/g, "");
@@ -44308,24 +44489,24 @@ function resolveArtifactRunScope(env = process.env) {
44308
44489
  }
44309
44490
  function defaultIsDirectory(path2) {
44310
44491
  try {
44311
- return (0, import_node_fs40.lstatSync)(path2).isDirectory();
44492
+ return (0, import_node_fs41.lstatSync)(path2).isDirectory();
44312
44493
  } catch {
44313
44494
  return false;
44314
44495
  }
44315
44496
  }
44316
44497
  function archiveWorktreeJervArtifacts(args, deps = {}) {
44317
- const exists = deps.exists ?? import_node_fs40.existsSync;
44498
+ const exists = deps.exists ?? import_node_fs41.existsSync;
44318
44499
  const isDirectory = deps.isDirectory ?? defaultIsDirectory;
44319
- const copyDir = deps.copyDir ?? ((from, to) => (0, import_node_fs40.cpSync)(from, to, { recursive: true, force: true }));
44500
+ const copyDir = deps.copyDir ?? ((from, to) => (0, import_node_fs41.cpSync)(from, to, { recursive: true, force: true }));
44320
44501
  const mkdirp = deps.mkdirp ?? ((path2) => {
44321
- (0, import_node_fs40.mkdirSync)(path2, { recursive: true });
44502
+ (0, import_node_fs41.mkdirSync)(path2, { recursive: true });
44322
44503
  });
44323
44504
  const env = deps.env ?? process.env;
44324
44505
  const now = deps.now ?? (() => /* @__PURE__ */ new Date());
44325
44506
  const resolveRoot = deps.resolveArchiveRoot ?? repoRuntimeStatePath;
44326
44507
  if (!args.primaryRoot?.trim()) return { status: "skipped", reason: "missing-primary-root" };
44327
44508
  if (!args.worktreePath?.trim()) return { status: "skipped", reason: "missing-worktree-path" };
44328
- const source = (0, import_node_path39.join)(args.worktreePath, ".jerv");
44509
+ const source = (0, import_node_path40.join)(args.worktreePath, ".jerv");
44329
44510
  if (!exists(source)) return { status: "absent" };
44330
44511
  if (!isDirectory(source)) return { status: "skipped", reason: "jerv-not-a-directory" };
44331
44512
  const runScope = resolveArtifactRunScope(env);
@@ -44333,7 +44514,7 @@ function archiveWorktreeJervArtifacts(args, deps = {}) {
44333
44514
  const stamp = now().toISOString().replace(/[:.]/g, "-");
44334
44515
  const dest = resolveRoot(args.primaryRoot, "jerv-artifacts", runScope, branchSlug, stamp, ".jerv");
44335
44516
  try {
44336
- mkdirp((0, import_node_path39.dirname)(dest));
44517
+ mkdirp((0, import_node_path40.dirname)(dest));
44337
44518
  copyDir(source, dest);
44338
44519
  if (!exists(dest)) return { status: "failed", error: `archive write left no directory at ${dest}` };
44339
44520
  return { status: "archived", path: dest, runScope };
@@ -44342,14 +44523,14 @@ function archiveWorktreeJervArtifacts(args, deps = {}) {
44342
44523
  }
44343
44524
  }
44344
44525
  function defaultStat(path2) {
44345
- const st = (0, import_node_fs40.statSync)(path2);
44526
+ const st = (0, import_node_fs41.statSync)(path2);
44346
44527
  return { mtimeMs: st.mtimeMs, size: st.size, isDirectory: () => st.isDirectory() };
44347
44528
  }
44348
44529
  function scanWorktreeTmpEvidence(worktreePath, newerThanMs, deps = {}) {
44349
- const exists = deps.exists ?? import_node_fs40.existsSync;
44530
+ const exists = deps.exists ?? import_node_fs41.existsSync;
44350
44531
  const stat4 = deps.stat ?? defaultStat;
44351
- const readdir2 = deps.readdir ?? import_node_fs40.readdirSync;
44352
- const tmpRoot = (0, import_node_path39.join)(worktreePath, "tmp");
44532
+ const readdir2 = deps.readdir ?? import_node_fs41.readdirSync;
44533
+ const tmpRoot = (0, import_node_path40.join)(worktreePath, "tmp");
44353
44534
  if (!exists(tmpRoot)) return [];
44354
44535
  const entries = [];
44355
44536
  const walk2 = (dir) => {
@@ -44360,14 +44541,14 @@ function scanWorktreeTmpEvidence(worktreePath, newerThanMs, deps = {}) {
44360
44541
  return;
44361
44542
  }
44362
44543
  for (const name of names) {
44363
- const full = (0, import_node_path39.join)(dir, name);
44544
+ const full = (0, import_node_path40.join)(dir, name);
44364
44545
  let st;
44365
44546
  try {
44366
44547
  st = stat4(full);
44367
44548
  } catch {
44368
44549
  continue;
44369
44550
  }
44370
- const relPath = (0, import_node_path39.relative)(worktreePath, full).replace(/\\/g, "/");
44551
+ const relPath = (0, import_node_path40.relative)(worktreePath, full).replace(/\\/g, "/");
44371
44552
  if (st.isDirectory()) {
44372
44553
  if (st.mtimeMs > newerThanMs) entries.push({ relPath, bytes: 0, mtimeMs: st.mtimeMs });
44373
44554
  walk2(full);
@@ -44381,10 +44562,10 @@ function scanWorktreeTmpEvidence(worktreePath, newerThanMs, deps = {}) {
44381
44562
  return entries;
44382
44563
  }
44383
44564
  function archiveWorktreeTmpArtifacts(args, deps = {}) {
44384
- const exists = deps.exists ?? import_node_fs40.existsSync;
44385
- const copyDir = deps.copyDir ?? ((from, to) => (0, import_node_fs40.cpSync)(from, to, { recursive: true, force: true }));
44565
+ const exists = deps.exists ?? import_node_fs41.existsSync;
44566
+ const copyDir = deps.copyDir ?? ((from, to) => (0, import_node_fs41.cpSync)(from, to, { recursive: true, force: true }));
44386
44567
  const mkdirp = deps.mkdirp ?? ((path2) => {
44387
- (0, import_node_fs40.mkdirSync)(path2, { recursive: true });
44568
+ (0, import_node_fs41.mkdirSync)(path2, { recursive: true });
44388
44569
  });
44389
44570
  const env = deps.env ?? process.env;
44390
44571
  const now = deps.now ?? (() => /* @__PURE__ */ new Date());
@@ -44392,7 +44573,7 @@ function archiveWorktreeTmpArtifacts(args, deps = {}) {
44392
44573
  if (!args.primaryRoot?.trim()) return { status: "skipped", reason: "missing-primary-root" };
44393
44574
  if (!args.worktreePath?.trim()) return { status: "skipped", reason: "missing-worktree-path" };
44394
44575
  const scanned = scanWorktreeTmpEvidence(args.worktreePath, args.newerThanMs, deps);
44395
- const source = (0, import_node_path39.join)(args.worktreePath, "tmp");
44576
+ const source = (0, import_node_path40.join)(args.worktreePath, "tmp");
44396
44577
  if (!scanned.length) return { status: "absent" };
44397
44578
  if (!exists(source)) return { status: "absent" };
44398
44579
  const runScope = resolveArtifactRunScope(env);
@@ -44400,7 +44581,7 @@ function archiveWorktreeTmpArtifacts(args, deps = {}) {
44400
44581
  const stamp = now().toISOString().replace(/[:.]/g, "-");
44401
44582
  const dest = resolveRoot(args.primaryRoot, "worktree-artifacts", runScope, branchSlug, stamp, "tmp");
44402
44583
  try {
44403
- mkdirp((0, import_node_path39.dirname)(dest));
44584
+ mkdirp((0, import_node_path40.dirname)(dest));
44404
44585
  copyDir(source, dest);
44405
44586
  if (!exists(dest)) return { status: "failed", error: `archive write left no directory at ${dest}` };
44406
44587
  const bytes = scanned.reduce((sum, e) => sum + e.bytes, 0);
@@ -44469,9 +44650,9 @@ function normPath2(p) {
44469
44650
  return p.replace(/\\/g, "/").replace(/\/+$/, "");
44470
44651
  }
44471
44652
  function unlinkNodeModulesJunction(wtPath) {
44472
- const nm = (0, import_node_path40.join)(wtPath, "node_modules");
44653
+ const nm = (0, import_node_path41.join)(wtPath, "node_modules");
44473
44654
  try {
44474
- if ((0, import_node_fs41.lstatSync)(nm).isSymbolicLink()) (0, import_node_fs41.rmdirSync)(nm);
44655
+ if ((0, import_node_fs42.lstatSync)(nm).isSymbolicLink()) (0, import_node_fs42.rmdirSync)(nm);
44475
44656
  return { ok: true };
44476
44657
  } catch (e) {
44477
44658
  if (e.code === "ENOENT") return { ok: true };
@@ -44482,8 +44663,8 @@ function defaultSleep2(ms) {
44482
44663
  return new Promise((resolve7) => setTimeout(resolve7, ms));
44483
44664
  }
44484
44665
  async function removeResidueDirectory(wtPath, options = {}) {
44485
- const { sleep: sleep2 = defaultSleep2, removeEmptyDir = import_node_fs41.rmdirSync, exists = import_node_fs41.existsSync } = options;
44486
- const removeRecursive = options.removeRecursive ?? ((path2) => (0, import_node_fs41.rmSync)(path2, { recursive: true, force: true, maxRetries: 10, retryDelay: 100 }));
44666
+ const { sleep: sleep2 = defaultSleep2, removeEmptyDir = import_node_fs42.rmdirSync, exists = import_node_fs42.existsSync } = options;
44667
+ const removeRecursive = options.removeRecursive ?? ((path2) => (0, import_node_fs42.rmSync)(path2, { recursive: true, force: true, maxRetries: 10, retryDelay: 100 }));
44487
44668
  const junction = unlinkNodeModulesJunction(wtPath);
44488
44669
  if (!junction.ok) return junction;
44489
44670
  try {
@@ -44606,28 +44787,28 @@ async function preCleanWorktreeForRemoval(wtPath, execGit) {
44606
44787
  }
44607
44788
  async function listNestedIgnoredNodeModules(wtPath, execGit) {
44608
44789
  const out = await execGit(["-C", wtPath, "ls-files", "--others", "--ignored", "--exclude-standard", "--directory"]).catch(() => "");
44609
- return out.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.endsWith("node_modules/") && line !== "node_modules/").map((line) => (0, import_node_path40.join)(wtPath, line.slice(0, -1)));
44790
+ return out.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.endsWith("node_modules/") && line !== "node_modules/").map((line) => (0, import_node_path41.join)(wtPath, line.slice(0, -1)));
44610
44791
  }
44611
44792
  function safeRemoveTree(path2) {
44612
- const stat4 = (0, import_node_fs41.lstatSync)(path2);
44793
+ const stat4 = (0, import_node_fs42.lstatSync)(path2);
44613
44794
  if (stat4.isSymbolicLink()) {
44614
44795
  try {
44615
- (0, import_node_fs41.rmdirSync)(path2);
44796
+ (0, import_node_fs42.rmdirSync)(path2);
44616
44797
  } catch {
44617
- (0, import_node_fs41.unlinkSync)(path2);
44798
+ (0, import_node_fs42.unlinkSync)(path2);
44618
44799
  }
44619
44800
  return;
44620
44801
  }
44621
44802
  if (stat4.isDirectory()) {
44622
- for (const entry of (0, import_node_fs41.readdirSync)(path2)) safeRemoveTree((0, import_node_path40.join)(path2, entry));
44623
- (0, import_node_fs41.rmdirSync)(path2);
44803
+ for (const entry of (0, import_node_fs42.readdirSync)(path2)) safeRemoveTree((0, import_node_path41.join)(path2, entry));
44804
+ (0, import_node_fs42.rmdirSync)(path2);
44624
44805
  return;
44625
44806
  }
44626
- (0, import_node_fs41.unlinkSync)(path2);
44807
+ (0, import_node_fs42.unlinkSync)(path2);
44627
44808
  }
44628
44809
  async function removeWorktreeNodeModules(wtPath) {
44629
44810
  try {
44630
- safeRemoveTree((0, import_node_path40.join)(wtPath, "node_modules"));
44811
+ safeRemoveTree((0, import_node_path41.join)(wtPath, "node_modules"));
44631
44812
  return { ok: true };
44632
44813
  } catch (e) {
44633
44814
  if (e.code === "ENOENT") return { ok: true };
@@ -44639,7 +44820,7 @@ function errorMessage(e) {
44639
44820
  }
44640
44821
  function resolvedOrRaw(path2) {
44641
44822
  try {
44642
- return normPath2((0, import_node_fs41.realpathSync)(path2));
44823
+ return normPath2((0, import_node_fs42.realpathSync)(path2));
44643
44824
  } catch {
44644
44825
  return normPath2(path2);
44645
44826
  }
@@ -44647,10 +44828,10 @@ function resolvedOrRaw(path2) {
44647
44828
  function unlinkEscapingReparsePoints(root, primaryRoot) {
44648
44829
  let realRoot;
44649
44830
  try {
44650
- if ((0, import_node_fs41.lstatSync)(root).isSymbolicLink()) {
44831
+ if ((0, import_node_fs42.lstatSync)(root).isSymbolicLink()) {
44651
44832
  return { ok: false, error: `delete root ${normPath2(root)} is a reparse point resolving to ${resolvedOrRaw(root)}` };
44652
44833
  }
44653
- realRoot = normPath2((0, import_node_fs41.realpathSync)(root));
44834
+ realRoot = normPath2((0, import_node_fs42.realpathSync)(root));
44654
44835
  } catch (e) {
44655
44836
  if (e.code === "ENOENT") return { ok: true, unlinked: [] };
44656
44837
  return { ok: false, error: `cannot resolve delete root ${normPath2(root)}: ${errorMessage(e)}` };
@@ -44666,17 +44847,17 @@ function unlinkEscapingReparsePoints(root, primaryRoot) {
44666
44847
  const dir = stack.pop();
44667
44848
  let entries;
44668
44849
  try {
44669
- entries = (0, import_node_fs41.readdirSync)(dir, { withFileTypes: true });
44850
+ entries = (0, import_node_fs42.readdirSync)(dir, { withFileTypes: true });
44670
44851
  } catch (e) {
44671
44852
  if (e.code === "ENOENT") continue;
44672
44853
  return { ok: false, error: `cannot scan ${normPath2(dir)} for reparse points: ${errorMessage(e)}` };
44673
44854
  }
44674
44855
  for (const entry of entries) {
44675
- const child2 = (0, import_node_path40.join)(dir, entry.name);
44856
+ const child2 = (0, import_node_path41.join)(dir, entry.name);
44676
44857
  if (entry.isSymbolicLink()) {
44677
44858
  let target = "";
44678
44859
  try {
44679
- target = normPath2((0, import_node_fs41.realpathSync)(child2));
44860
+ target = normPath2((0, import_node_fs42.realpathSync)(child2));
44680
44861
  } catch {
44681
44862
  target = "";
44682
44863
  }
@@ -44859,7 +45040,7 @@ async function cleanupPrMergeLocalBranch(branch, options) {
44859
45040
  return report;
44860
45041
  }
44861
45042
  const execGit = options.execGit ?? (async (args) => (await execFileP("git", args, { timeout: GIT_TIMEOUT_MS })).stdout);
44862
- const pathExists = options.pathExists ?? import_node_fs41.existsSync;
45043
+ const pathExists = options.pathExists ?? import_node_fs42.existsSync;
44863
45044
  let afterWorktrees = [];
44864
45045
  try {
44865
45046
  afterWorktrees = parseGitWorktreePorcelain(await execGit(["worktree", "list", "--porcelain"]));
@@ -44999,7 +45180,7 @@ async function cleanupPrMergeLocalBranch(branch, options) {
44999
45180
  const preHelperGuard = unlinkEscapingReparsePoints(wtPath, options.primaryRoot);
45000
45181
  if (!preHelperGuard.ok) return refuseReparseEscape(preHelperGuard.error);
45001
45182
  unlinkedReparsePoints.push(...preHelperGuard.unlinked);
45002
- if (pathExists((0, import_node_path40.join)(wtPath, "node_modules"))) {
45183
+ if (pathExists((0, import_node_path41.join)(wtPath, "node_modules"))) {
45003
45184
  const nmRemoved = await (options.removeRealNodeModules ?? removeWorktreeNodeModules)(wtPath);
45004
45185
  if (!nmRemoved.ok) {
45005
45186
  report.worktree = {
@@ -45135,18 +45316,18 @@ function renderPrMergeCleanupLines(cleanup) {
45135
45316
  // src/worktree-residue-sweep.ts
45136
45317
  var RESIDUE_LEDGER_FILE = "mmi-worktree-residue.json";
45137
45318
  function canonicalWorktreeRoot(primary) {
45138
- return (0, import_node_path41.join)((0, import_node_path41.dirname)(primary), "mmi-worktrees", (0, import_node_path41.basename)(primary));
45319
+ return (0, import_node_path42.join)((0, import_node_path42.dirname)(primary), "mmi-worktrees", (0, import_node_path42.basename)(primary));
45139
45320
  }
45140
45321
  function norm(p) {
45141
45322
  const s = p.replace(/\\/g, "/").replace(/\/+$/, "");
45142
45323
  return process.platform === "win32" ? s.toLowerCase() : s;
45143
45324
  }
45144
45325
  function residueLedgerPath(gitCommonDir) {
45145
- return (0, import_node_path41.join)(gitCommonDir, RESIDUE_LEDGER_FILE);
45326
+ return (0, import_node_path42.join)(gitCommonDir, RESIDUE_LEDGER_FILE);
45146
45327
  }
45147
45328
  function readPaths(file, deps) {
45148
45329
  try {
45149
- const parsed = JSON.parse((deps.readLedger ?? ((f) => (0, import_node_fs42.readFileSync)(f, "utf8")))(file));
45330
+ const parsed = JSON.parse((deps.readLedger ?? ((f) => (0, import_node_fs43.readFileSync)(f, "utf8")))(file));
45150
45331
  return Array.isArray(parsed) ? parsed.filter((p) => typeof p === "string") : [];
45151
45332
  } catch {
45152
45333
  return [];
@@ -45155,8 +45336,8 @@ function readPaths(file, deps) {
45155
45336
  function writePaths(file, paths, deps) {
45156
45337
  try {
45157
45338
  const write = deps.writeLedger ?? ((f, t) => {
45158
- (0, import_node_fs42.mkdirSync)((0, import_node_path41.dirname)(f), { recursive: true });
45159
- (0, import_node_fs42.writeFileSync)(f, t, "utf8");
45339
+ (0, import_node_fs43.mkdirSync)((0, import_node_path42.dirname)(f), { recursive: true });
45340
+ (0, import_node_fs43.writeFileSync)(f, t, "utf8");
45160
45341
  });
45161
45342
  write(file, `${JSON.stringify([...new Set(paths)], null, 1)}
45162
45343
  `);
@@ -45170,17 +45351,17 @@ function recordResidue(gitCommonDir, path2, deps = {}) {
45170
45351
  writePaths(file, paths, deps);
45171
45352
  }
45172
45353
  async function sweepWorktreeResidue(gitCommonDir, registered, deps = {}) {
45173
- const exists = deps.exists ?? import_node_fs42.existsSync;
45174
- const readDir = deps.readDir ?? ((p) => (0, import_node_fs42.readdirSync)(p));
45354
+ const exists = deps.exists ?? import_node_fs43.existsSync;
45355
+ const readDir = deps.readDir ?? ((p) => (0, import_node_fs43.readdirSync)(p));
45175
45356
  const isDir = deps.isDir ?? ((p) => {
45176
45357
  try {
45177
- return (0, import_node_fs42.statSync)(p).isDirectory();
45358
+ return (0, import_node_fs43.statSync)(p).isDirectory();
45178
45359
  } catch {
45179
45360
  return false;
45180
45361
  }
45181
45362
  });
45182
45363
  const removeRecorded = deps.removeRecorded ?? ((p) => removeResidueDirectory(p));
45183
- const removeEmpty = deps.removeEmpty ?? ((p) => (0, import_node_fs42.rmdirSync)(p));
45364
+ const removeEmpty = deps.removeEmpty ?? ((p) => (0, import_node_fs43.rmdirSync)(p));
45184
45365
  const report = { swept: [], kept: [], dropped: [], emptyRemoved: [], unrecorded: [] };
45185
45366
  const live = new Set(registered.map(norm));
45186
45367
  const primary = registered[0] ? norm(registered[0]) : void 0;
@@ -45215,7 +45396,7 @@ async function sweepWorktreeResidue(gitCommonDir, registered, deps = {}) {
45215
45396
  } catch {
45216
45397
  }
45217
45398
  for (const name of children) {
45218
- const child2 = (0, import_node_path41.join)(root, name);
45399
+ const child2 = (0, import_node_path42.join)(root, name);
45219
45400
  const key = norm(child2);
45220
45401
  if (live.has(key) || key === primary || keptKeys.has(key) || !isDir(child2)) continue;
45221
45402
  let entries;
@@ -45258,10 +45439,10 @@ function argvWantsJson2() {
45258
45439
  return process.argv.some((a) => a === "--json" || a.startsWith("--json="));
45259
45440
  }
45260
45441
  function hubRoot() {
45261
- const fromPkg = (0, import_node_path42.join)(__dirname, "..", "..");
45442
+ const fromPkg = (0, import_node_path43.join)(__dirname, "..", "..");
45262
45443
  const marker = "skills/bootstrap/seeds/manifest.json";
45263
- if ((0, import_node_fs43.existsSync)((0, import_node_path42.join)(fromPkg, marker))) return fromPkg;
45264
- if ((0, import_node_fs43.existsSync)((0, import_node_path42.join)(process.cwd(), marker))) return process.cwd();
45444
+ if ((0, import_node_fs44.existsSync)((0, import_node_path43.join)(fromPkg, marker))) return fromPkg;
45445
+ if ((0, import_node_fs44.existsSync)((0, import_node_path43.join)(process.cwd(), marker))) return process.cwd();
45265
45446
  return null;
45266
45447
  }
45267
45448
  function ciAuditDeps() {
@@ -45273,8 +45454,8 @@ function ciAuditDeps() {
45273
45454
  getProjectMeta: async (slug) => fetchProjectBySlug(slug, registryClientDeps(await cfgPromise)),
45274
45455
  readSeedFile: (path2) => {
45275
45456
  if (!root) return null;
45276
- const fullPath = (0, import_node_path42.join)(root, path2);
45277
- return (0, import_node_fs43.existsSync)(fullPath) ? (0, import_node_fs43.readFileSync)(fullPath, "utf8") : null;
45457
+ const fullPath = (0, import_node_path43.join)(root, path2);
45458
+ return (0, import_node_fs44.existsSync)(fullPath) ? (0, import_node_fs44.readFileSync)(fullPath, "utf8") : null;
45278
45459
  }
45279
45460
  };
45280
45461
  }
@@ -46037,11 +46218,11 @@ ${list}`);
46037
46218
  }
46038
46219
  });
46039
46220
  async function listCiWorkflowPaths(cwd = process.cwd()) {
46040
- const wfDir = (0, import_node_path42.join)(cwd, ".github", "workflows");
46041
- if (!(0, import_node_fs43.existsSync)(wfDir)) return [];
46042
- return (0, import_node_fs43.readdirSync)(wfDir).filter((name) => /\.(ya?ml)$/i.test(name)).filter((name) => {
46221
+ const wfDir = (0, import_node_path43.join)(cwd, ".github", "workflows");
46222
+ if (!(0, import_node_fs44.existsSync)(wfDir)) return [];
46223
+ return (0, import_node_fs44.readdirSync)(wfDir).filter((name) => /\.(ya?ml)$/i.test(name)).filter((name) => {
46043
46224
  try {
46044
- return workflowReportsPrChecks((0, import_node_fs43.readFileSync)((0, import_node_path42.join)(wfDir, name), "utf8"));
46225
+ return workflowReportsPrChecks((0, import_node_fs44.readFileSync)((0, import_node_path43.join)(wfDir, name), "utf8"));
46045
46226
  } catch {
46046
46227
  return true;
46047
46228
  }
@@ -46246,7 +46427,7 @@ ${list}`);
46246
46427
  jsonParity(pr.command("review-verdict <number>").description("post an explicit review verdict comment: computes the PR diff patch-id and head sha, renders the v1 contract body, and posts it as a PR comment").requiredOption("--repo <owner/repo>", "target repo").requiredOption("--verdict <verdict>", `one of ${REVIEW_VERDICTS.join("|")}`).requiredOption("--scope <text>", "one line: what was reviewed").requiredOption("--risk <text>", "one line: the residual risk").option("--unverified <text>", "a claim the reviewer could not verify (repeatable)", (v, acc) => [...acc, v], []).requiredOption("--reviewer <id>", "reviewer seat or model id").option("--findings-file <path>", "Markdown findings appended after the JSON block")).action(async (number, o) => {
46247
46428
  if (!isReviewVerdict(o.verdict)) return fail(`pr review-verdict: --verdict must be one of ${REVIEW_VERDICTS.join("|")} (got ${o.verdict})`);
46248
46429
  const verdict = o.verdict;
46249
- const findings = o.findingsFile ? (0, import_node_fs43.readFileSync)(o.findingsFile, "utf8") : void 0;
46430
+ const findings = o.findingsFile ? (0, import_node_fs44.readFileSync)(o.findingsFile, "utf8") : void 0;
46250
46431
  let patch;
46251
46432
  let head;
46252
46433
  try {
@@ -46523,7 +46704,7 @@ ${list}`);
46523
46704
  const mergeSquashBody = squashBodyTextForMerge(
46524
46705
  closingGuardInput,
46525
46706
  method === "--squash",
46526
- o.squashBodyFile ? (0, import_node_fs43.readFileSync)(o.squashBodyFile, "utf8") : void 0
46707
+ o.squashBodyFile ? (0, import_node_fs44.readFileSync)(o.squashBodyFile, "utf8") : void 0
46527
46708
  );
46528
46709
  if (!o.squashBodyFile) warnSquashBodyClosingStrip("pr merge", closingGuardInput, mergeSquashBody);
46529
46710
  const closingGuardVerdict = evaluateClosingGuard(closingGuardInput, {
@@ -46555,7 +46736,7 @@ ${list}`);
46555
46736
  const remote = foreignCwd ? `https://github.com/${targetRepo2}.git` : "origin";
46556
46737
  let foreignCheckout;
46557
46738
  if (foreignCwd) {
46558
- const sibling = (0, import_node_path42.join)((0, import_node_path42.dirname)(beforeWorktrees[0]?.path || startingPath || process.cwd()), targetRepo2.split("/")[1]);
46739
+ const sibling = (0, import_node_path43.join)((0, import_node_path43.dirname)(beforeWorktrees[0]?.path || startingPath || process.cwd()), targetRepo2.split("/")[1]);
46559
46740
  const siblingRepo = repoFromRemoteUrl(await gitOut(["-C", sibling, "remote", "get-url", "origin"]).catch(() => ""));
46560
46741
  if (siblingRepo?.toLowerCase() === targetRepo2.toLowerCase()) {
46561
46742
  const siblingWorktrees = await execFileP("git", ["-C", sibling, "worktree", "list", "--porcelain"], { timeout: GIT_TIMEOUT_MS }).then((r) => parseGitWorktreePorcelain(r.stdout)).catch(() => void 0);
@@ -46653,7 +46834,7 @@ ${list}`);
46653
46834
  }
46654
46835
  if (!repoForPostCleanup) throw e;
46655
46836
  console.warn(`pr merge: gh GraphQL rate-limited \u2014 merging PR #${number} via REST PUT instead (#4588).`);
46656
- const commitMessage = bodyFile ? (0, import_node_fs43.readFileSync)(bodyFile, "utf8") : void 0;
46837
+ const commitMessage = bodyFile ? (0, import_node_fs44.readFileSync)(bodyFile, "utf8") : void 0;
46657
46838
  await defaultGitHubClient().rest("PUT", `repos/${repoForPostCleanup}/pulls/${number}/merge`, {
46658
46839
  body: { merge_method: method.slice(2), ...commitMessage ? { commit_message: commitMessage } : {} },
46659
46840
  timeoutMs: GH_MUTATION_TIMEOUT_MS
@@ -46767,7 +46948,7 @@ ${list}`);
46767
46948
  let residueSweep;
46768
46949
  if (!(foreignCwd && !foreignCheckout)) {
46769
46950
  try {
46770
- gitCommonDir = (0, import_node_path42.resolve)(primaryRoot, (await execFileP("git", ["-C", primaryRoot, "rev-parse", "--git-common-dir"], { timeout: GIT_TIMEOUT_MS })).stdout.trim());
46951
+ gitCommonDir = (0, import_node_path43.resolve)(primaryRoot, (await execFileP("git", ["-C", primaryRoot, "rev-parse", "--git-common-dir"], { timeout: GIT_TIMEOUT_MS })).stdout.trim());
46771
46952
  residueSweep = await sweepWorktreeResidue(gitCommonDir, beforeWorktrees.map((w) => w.path));
46772
46953
  } catch {
46773
46954
  }
@@ -46785,7 +46966,7 @@ ${list}`);
46785
46966
  preserveWorktree: o.preserveWorktree,
46786
46967
  gcAcknowledged: o.gc,
46787
46968
  expectedHeadOid: headRefOid,
46788
- pathExists: (p) => (0, import_node_fs43.existsSync)(p),
46969
+ pathExists: (p) => (0, import_node_fs44.existsSync)(p),
46789
46970
  // #5899: pin cleanup git calls to the main checkout — the task worktree this process may be
46790
46971
  // standing in is removed mid-cleanup, so a cwd-relative invocation fails with
46791
46972
  // 'fatal: not a git repository' and leaves a spurious partial-cleanup exit.
@@ -48017,18 +48198,18 @@ function rcRunCauseFromLog(log) {
48017
48198
  function memberAnnounceSummaryFile(repo, summaryFile, memberSummaryFiles) {
48018
48199
  return repo === SUITE_REPO ? summaryFile : memberSummaryFiles[repo];
48019
48200
  }
48020
- var suiteStateDir = (root) => (0, import_node_path43.join)(resolvePrimaryGitDir(root), "mmi-runtime", "suite");
48201
+ var suiteStateDir = (root) => (0, import_node_path44.join)(resolvePrimaryGitDir(root), "mmi-runtime", "suite");
48021
48202
  function suiteTrainIo(root, summaryFile, memberSummaryFiles = {}, summaryFileTr, memberSummaryFilesTr = {}) {
48022
- const recordPath = (0, import_node_path43.join)(suiteStateDir(root), "cut.json");
48023
- const base = (0, import_node_path43.join)(suiteStateDir(root), "checkouts");
48203
+ const recordPath = (0, import_node_path44.join)(suiteStateDir(root), "cut.json");
48204
+ const base = (0, import_node_path44.join)(suiteStateDir(root), "checkouts");
48024
48205
  const checkout = async (repo) => {
48025
48206
  if (repo === SUITE_REPO) return root;
48026
- const target = (0, import_node_path43.join)(base, repo.split("/")[1]);
48027
- if (!(0, import_node_fs44.existsSync)(target)) {
48028
- (0, import_node_fs44.mkdirSync)(base, { recursive: true });
48207
+ const target = (0, import_node_path44.join)(base, repo.split("/")[1]);
48208
+ if (!(0, import_node_fs45.existsSync)(target)) {
48209
+ (0, import_node_fs45.mkdirSync)(base, { recursive: true });
48029
48210
  await exec("git", ["clone", "--quiet", "--branch", "development", `https://github.com/${repo}.git`, target], root, WATCH_TIMEOUT);
48030
48211
  }
48031
- if (!(0, import_node_fs44.existsSync)((0, import_node_path43.join)(target, ".git"))) throw new Error(`${repo}: suite checkout has no .git at ${target}; stop`);
48212
+ if (!(0, import_node_fs45.existsSync)((0, import_node_path44.join)(target, ".git"))) throw new Error(`${repo}: suite checkout has no .git at ${target}; stop`);
48032
48213
  const origin = await exec("git", ["remote", "get-url", "origin"], target);
48033
48214
  if (!origin.toLowerCase().endsWith(`/${repo.toLowerCase()}.git`) && !origin.toLowerCase().endsWith(`/${repo.toLowerCase()}`))
48034
48215
  throw new Error(`${repo}: suite checkout origin mismatch at ${target}; stop`);
@@ -48351,9 +48532,9 @@ function suiteTrainIo(root, summaryFile, memberSummaryFiles = {}, summaryFileTr,
48351
48532
  const body = await gh(["release", "view", leadTag, "--repo", SUITE_REPO, "--json", "body", "--jq", ".body"]);
48352
48533
  if (parseSuiteMapping(body)) return;
48353
48534
  const dir = suiteStateDir(root);
48354
- (0, import_node_fs44.mkdirSync)(dir, { recursive: true });
48355
- const file = (0, import_node_path43.join)(dir, `notes-${leadTag}.md`);
48356
- (0, import_node_fs44.writeFileSync)(file, `${body}
48535
+ (0, import_node_fs45.mkdirSync)(dir, { recursive: true });
48536
+ const file = (0, import_node_path44.join)(dir, `notes-${leadTag}.md`);
48537
+ (0, import_node_fs45.writeFileSync)(file, `${body}
48357
48538
 
48358
48539
  ${suiteMappingBlock(leadTag, mapping)}`);
48359
48540
  await gh(["release", "edit", leadTag, "--repo", SUITE_REPO, "--notes-file", file]);
@@ -48394,7 +48575,7 @@ ${suiteMappingBlock(leadTag, mapping)}`);
48394
48575
 
48395
48576
  // src/suite-commands.ts
48396
48577
  init_cli_shared();
48397
- var import_node_fs45 = require("node:fs");
48578
+ var import_node_fs46 = require("node:fs");
48398
48579
  function parseMemberSummaryFiles(entries) {
48399
48580
  const memberSummaryFiles = {};
48400
48581
  for (const entry of entries) {
@@ -48476,7 +48657,7 @@ function registerSuiteCommands(program3) {
48476
48657
  try {
48477
48658
  const io = suiteTrainIo(root);
48478
48659
  retired = await retireFailedLeadRcLedger({ ledgerPath: releaseLedgerPath(root), rcHead: () => io.head(SUITE_REPO, "rc").then((h) => h ?? void 0), markAbandoned: io.markAbandoned }, o.ownerGo === true);
48479
- if (retired && !(0, import_node_fs45.existsSync)(io.recordPath)) {
48660
+ if (retired && !(0, import_node_fs46.existsSync)(io.recordPath)) {
48480
48661
  console.log(o.json ? JSON.stringify({ retiredLeadRc: retired }, null, 2) : `suite abandon: retired the lead's failed, never-promoted rc candidate ${retired}; marked abandoned on origin (#7854)`);
48481
48662
  return;
48482
48663
  }
@@ -48665,9 +48846,9 @@ function suiteStatusDeps(github, registry2) {
48665
48846
 
48666
48847
  // src/packages-adopt-export.ts
48667
48848
  var import_node_child_process18 = require("node:child_process");
48668
- var import_node_fs46 = require("node:fs");
48669
- var import_node_os21 = require("node:os");
48670
- var import_node_path44 = require("node:path");
48849
+ var import_node_fs47 = require("node:fs");
48850
+ var import_node_os22 = require("node:os");
48851
+ var import_node_path45 = require("node:path");
48671
48852
  var import_node_util6 = require("node:util");
48672
48853
  init_cli_shared();
48673
48854
 
@@ -49287,38 +49468,38 @@ function expectedFromRun(run, opts) {
49287
49468
  }
49288
49469
  async function adoptExport(opts, deps) {
49289
49470
  if (!/^sha256:[0-9a-f]{64}$/.test(opts.digest)) throw new Error("--digest must be sha256:<64 hex>, from the export run summary");
49290
- const packagePath = (0, import_node_path44.join)(opts.dir, "package.json");
49291
- const lockPath = (0, import_node_path44.join)(opts.dir, "package-lock.json");
49292
- const packageText = (0, import_node_fs46.readFileSync)(packagePath, "utf8");
49293
- const lockText = (0, import_node_fs46.readFileSync)(lockPath, "utf8");
49294
- const work = (0, import_node_fs46.mkdtempSync)((0, import_node_path44.join)((0, import_node_os21.tmpdir)(), "mmi-adopt-export-"));
49471
+ const packagePath = (0, import_node_path45.join)(opts.dir, "package.json");
49472
+ const lockPath = (0, import_node_path45.join)(opts.dir, "package-lock.json");
49473
+ const packageText = (0, import_node_fs47.readFileSync)(packagePath, "utf8");
49474
+ const lockText = (0, import_node_fs47.readFileSync)(lockPath, "utf8");
49475
+ const work = (0, import_node_fs47.mkdtempSync)((0, import_node_path45.join)((0, import_node_os22.tmpdir)(), "mmi-adopt-export-"));
49295
49476
  try {
49296
49477
  const run = JSON.parse((await deps.ghApi(`repos/${EXPORT_REPO}/actions/runs/${opts.run}`)).toString("utf8"));
49297
- (0, import_node_fs46.writeFileSync)((0, import_node_path44.join)(work, "expected.json"), JSON.stringify(expectedFromRun(run, opts)));
49298
- (0, import_node_fs46.writeFileSync)((0, import_node_path44.join)(work, "provider.json"), await deps.ghApi(`repos/${EXPORT_REPO}/actions/artifacts/${opts.artifact}`));
49299
- (0, import_node_fs46.writeFileSync)((0, import_node_path44.join)(work, "artifact.zip"), await deps.ghApi(`repos/${EXPORT_REPO}/actions/artifacts/${opts.artifact}/zip`));
49300
- const script = (0, import_node_path44.join)(work, "package_export.py");
49301
- (0, import_node_fs46.writeFileSync)(script, package_export_default);
49478
+ (0, import_node_fs47.writeFileSync)((0, import_node_path45.join)(work, "expected.json"), JSON.stringify(expectedFromRun(run, opts)));
49479
+ (0, import_node_fs47.writeFileSync)((0, import_node_path45.join)(work, "provider.json"), await deps.ghApi(`repos/${EXPORT_REPO}/actions/artifacts/${opts.artifact}`));
49480
+ (0, import_node_fs47.writeFileSync)((0, import_node_path45.join)(work, "artifact.zip"), await deps.ghApi(`repos/${EXPORT_REPO}/actions/artifacts/${opts.artifact}/zip`));
49481
+ const script = (0, import_node_path45.join)(work, "package_export.py");
49482
+ (0, import_node_fs47.writeFileSync)(script, package_export_default);
49302
49483
  await deps.python(script, ["verify", work, opts.ds, opts.screens]);
49303
- const verified = (0, import_node_path44.join)(work, "verified");
49304
- const metadata = Object.fromEntries(PACKAGES.map(({ name, short: short3 }) => [name, JSON.parse((0, import_node_fs46.readFileSync)((0, import_node_path44.join)(verified, `${short3}.metadata.json`), "utf8"))]));
49484
+ const verified = (0, import_node_path45.join)(work, "verified");
49485
+ const metadata = Object.fromEntries(PACKAGES.map(({ name, short: short3 }) => [name, JSON.parse((0, import_node_fs47.readFileSync)((0, import_node_path45.join)(verified, `${short3}.metadata.json`), "utf8"))]));
49305
49486
  const plan = planAdoption(packageText, lockText, metadata);
49306
49487
  for (const { name } of plan.result.adopted) {
49307
49488
  const short3 = PACKAGES.find((p) => p.name === name).short;
49308
- await deps.npm(["cache", "add", (0, import_node_path44.join)(verified, `${short3}.tgz`)], opts.dir);
49489
+ await deps.npm(["cache", "add", (0, import_node_path45.join)(verified, `${short3}.tgz`)], opts.dir);
49309
49490
  }
49310
- (0, import_node_fs46.writeFileSync)(packagePath, plan.packageText);
49311
- (0, import_node_fs46.writeFileSync)(lockPath, plan.lockText);
49491
+ (0, import_node_fs47.writeFileSync)(packagePath, plan.packageText);
49492
+ (0, import_node_fs47.writeFileSync)(lockPath, plan.lockText);
49312
49493
  try {
49313
49494
  await deps.npm(["ci", "--offline", "--ignore-scripts", "--no-audit", "--no-fund"], opts.dir);
49314
49495
  } catch (error) {
49315
- (0, import_node_fs46.writeFileSync)(packagePath, packageText);
49316
- (0, import_node_fs46.writeFileSync)(lockPath, lockText);
49496
+ (0, import_node_fs47.writeFileSync)(packagePath, packageText);
49497
+ (0, import_node_fs47.writeFileSync)(lockPath, lockText);
49317
49498
  throw new Error(`npm ci --offline failed, package.json and package-lock.json restored: ${error.message}`);
49318
49499
  }
49319
49500
  return plan.result;
49320
49501
  } finally {
49321
- (0, import_node_fs46.rmSync)(work, { recursive: true, force: true });
49502
+ (0, import_node_fs47.rmSync)(work, { recursive: true, force: true });
49322
49503
  }
49323
49504
  }
49324
49505
  var execFileBuffer = (0, import_node_util6.promisify)(import_node_child_process18.execFile);
@@ -49383,12 +49564,12 @@ function registerPackagesCommands(program3) {
49383
49564
  init_cli_shared();
49384
49565
 
49385
49566
  // src/wave-status.ts
49386
- var import_node_fs47 = require("node:fs");
49567
+ var import_node_fs48 = require("node:fs");
49387
49568
  function readStageSummary(worktreePath) {
49388
49569
  const statePath = stageStatePath(worktreePath);
49389
- if (!(0, import_node_fs47.existsSync)(statePath)) return void 0;
49570
+ if (!(0, import_node_fs48.existsSync)(statePath)) return void 0;
49390
49571
  try {
49391
- const state = JSON.parse((0, import_node_fs47.readFileSync)(statePath, "utf8"));
49572
+ const state = JSON.parse((0, import_node_fs48.readFileSync)(statePath, "utf8"));
49392
49573
  const port = typeof state.port === "number" ? state.port : void 0;
49393
49574
  if (port == null || !Number.isInteger(port) || port <= 0) return void 0;
49394
49575
  return { port, url: typeof state.url === "string" ? state.url : void 0 };
@@ -49445,9 +49626,9 @@ async function collectWaveStatus(deps) {
49445
49626
  // src/discovery-commands.ts
49446
49627
  init_github_client();
49447
49628
  init_cli_shared();
49448
- var import_node_fs48 = require("node:fs");
49449
- var import_node_os22 = require("node:os");
49450
- var import_node_path45 = require("node:path");
49629
+ var import_node_fs49 = require("node:fs");
49630
+ var import_node_os23 = require("node:os");
49631
+ var import_node_path46 = require("node:path");
49451
49632
  var GC_GH_TIMEOUT_MS3 = 2e4;
49452
49633
  async function collectStatus() {
49453
49634
  const repo = await resolveRepo();
@@ -49636,10 +49817,10 @@ async function collectOnboardStatus(opts = {}) {
49636
49817
  else if (top) nextCommand = `mmi-cli oracle board claim ${top.number} # ${top.title}`;
49637
49818
  else nextCommand = "mmi-cli oracle board read \u2014 no claimable items found";
49638
49819
  }
49639
- const home = (0, import_node_os22.homedir)();
49820
+ const home = (0, import_node_os23.homedir)();
49640
49821
  const plugin = onboardPluginGate({
49641
- readKnown: () => readFileSyncSafe((0, import_node_path45.join)(home, ...KNOWN_MARKETPLACES_RELATIVE), import_node_fs48.readFileSync),
49642
- readSettings: () => readFileSyncSafe((0, import_node_path45.join)(home, ".claude", "settings.json"), import_node_fs48.readFileSync)
49822
+ readKnown: () => readFileSyncSafe((0, import_node_path46.join)(home, ...KNOWN_MARKETPLACES_RELATIVE), import_node_fs49.readFileSync),
49823
+ readSettings: () => readFileSyncSafe((0, import_node_path46.join)(home, ".claude", "settings.json"), import_node_fs49.readFileSync)
49643
49824
  });
49644
49825
  return {
49645
49826
  guide: "Read the MMI org-guide skill before project work; load only the relevant topic. Use mmi-help for a short introduction.",
@@ -51831,6 +52012,9 @@ function registerOrgHealthQuery(program3, deps = defaultOrgHealthQueryDeps()) {
51831
52012
  });
51832
52013
  }
51833
52014
 
52015
+ // src/api-read.ts
52016
+ var import_node_fs50 = require("node:fs");
52017
+
51834
52018
  // src/app-read-broker.ts
51835
52019
  init_cli_shared();
51836
52020
  var OWNER_REPO_RE = /^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/;
@@ -52200,7 +52384,10 @@ var CONTENTS_QUERY_RE = /^ref=[^&\s]+$/;
52200
52384
  var ACTIONS_RUNS_RE = new RegExp(`^repos/${NAME}/${NAME}/actions/runs$`);
52201
52385
  var ACTIONS_RUN_RE = new RegExp(`^repos/${NAME}/${NAME}/actions/runs/\\d+$`);
52202
52386
  var ACTIONS_JOBS_RE = new RegExp(`^repos/${NAME}/${NAME}/actions/runs/\\d+/jobs$`);
52203
- var API_GET_ALLOWED_SHAPES = "repos/{owner}/{repo}/pulls/{n}/files, repos/{owner}/{repo}/compare/{a}...{b}, repos/{owner}/{repo}/contents/{path}[?ref=<branch>], repos/{owner}/{repo}/actions/runs, repos/{owner}/{repo}/actions/runs/{id}, repos/{owner}/{repo}/actions/runs/{id}/jobs";
52387
+ var ACTIONS_ARTIFACTS_RE = new RegExp(`^repos/${NAME}/${NAME}/actions/runs/\\d+/artifacts$`);
52388
+ var ACTIONS_ARTIFACT_ZIP_RE = new RegExp(`^repos/${NAME}/${NAME}/actions/artifacts/\\d+/zip$`);
52389
+ var ACTIONS_JOB_LOGS_RE = new RegExp(`^repos/${NAME}/${NAME}/actions/jobs/\\d+/logs$`);
52390
+ var API_GET_ALLOWED_SHAPES = "repos/{owner}/{repo}/pulls/{n}/files, repos/{owner}/{repo}/compare/{a}...{b}, repos/{owner}/{repo}/contents/{path}[?ref=<branch>], repos/{owner}/{repo}/actions/runs, repos/{owner}/{repo}/actions/runs/{id}, repos/{owner}/{repo}/actions/runs/{id}/jobs, repos/{owner}/{repo}/actions/runs/{id}/artifacts, repos/{owner}/{repo}/actions/artifacts/{id}/zip (needs --out <file>), repos/{owner}/{repo}/actions/jobs/{id}/logs (needs --out <file>)";
52204
52391
  function parseApiGetPath(rawPath) {
52205
52392
  const path2 = rawPath.trim();
52206
52393
  const refuse = () => new Error(`api get: refusing '${rawPath}' \u2014 only these GET reads are allowed (#7219): ${API_GET_ALLOWED_SHAPES}`);
@@ -52210,6 +52397,9 @@ function parseApiGetPath(rawPath) {
52210
52397
  if (ACTIONS_RUNS_RE.test(path2)) return { kind: "actions-runs", path: path2, paginate: true };
52211
52398
  if (ACTIONS_RUN_RE.test(path2)) return { kind: "actions-run", path: path2, paginate: false };
52212
52399
  if (ACTIONS_JOBS_RE.test(path2)) return { kind: "actions-jobs", path: path2, paginate: true };
52400
+ if (ACTIONS_ARTIFACTS_RE.test(path2)) return { kind: "actions-artifacts", path: path2, paginate: true };
52401
+ if (ACTIONS_ARTIFACT_ZIP_RE.test(path2)) return { kind: "actions-artifact-zip", path: path2, paginate: false };
52402
+ if (ACTIONS_JOB_LOGS_RE.test(path2)) return { kind: "actions-job-logs", path: path2, paginate: false };
52213
52403
  const q = path2.indexOf("?");
52214
52404
  const base = q === -1 ? path2 : path2.slice(0, q);
52215
52405
  const query = q === -1 ? "" : path2.slice(q + 1);
@@ -52218,6 +52408,8 @@ function parseApiGetPath(rawPath) {
52218
52408
  }
52219
52409
  throw new Error(`api get: refusing '${rawPath}' \u2014 only these GET reads are allowed (#7219): ${API_GET_ALLOWED_SHAPES}`);
52220
52410
  }
52411
+ var ZIP_TIMEOUT_MS = 12e4;
52412
+ var ZIP_MAX_BUFFER = 512 * 1024 * 1024;
52221
52413
  function buildApiGetArgs(path2, accept) {
52222
52414
  const req = parseApiGetPath(path2);
52223
52415
  const args = ["api", req.path];
@@ -52230,22 +52422,28 @@ async function runApiGet(run, path2, accept) {
52230
52422
  return run(buildApiGetArgs(path2, accept), GIT_TIMEOUT_MS);
52231
52423
  }
52232
52424
  function registerApiReadCommands(program3, overrides) {
52233
- const spawn6 = overrides?.runner ?? (async (args, timeoutMs, env) => (await execFileP("gh", args, { timeout: timeoutMs, ...env ? { env } : {} })).stdout);
52234
- const api = program3.command("api").description("bounded GitHub REST reads for automation \u2014 GET only, allowlisted paths (pull files, compare, contents, actions runs/jobs)");
52425
+ const spawn6 = overrides?.runner ?? (async (args, timeoutMs, env, binary) => (await execFileP("gh", args, { timeout: timeoutMs, ...binary ? { encoding: "latin1", maxBuffer: ZIP_MAX_BUFFER } : {}, ...env ? { env } : {} })).stdout);
52426
+ const api = program3.command("api").description("bounded GitHub REST reads for automation \u2014 GET only, allowlisted paths (pull files, compare, contents, actions runs/jobs/artifacts)");
52235
52427
  api.command("get").description("GET one allowlisted REST path and print the response body to stdout (JSON, or raw file bytes with --accept raw); refuses everything outside the allowlist").option("--accept <type>", "response media type: json (default) or raw (file bytes)", (v) => {
52236
52428
  acceptHeaderFor(v);
52237
52429
  return v.trim().toLowerCase();
52238
- }, "json").argument("<path>", "allowlisted GET path (shapes named on refusal)", (v) => parseApiGetPath(v)).action(async (req, o) => {
52430
+ }, "json").option("--out <file>", "write the response bytes to this file instead of stdout (required for, and only valid with, actions/artifacts/{id}/zip)").argument("<path>", "allowlisted GET path (shapes named on refusal)", (v) => parseApiGetPath(v)).action(async (req, o) => {
52431
+ const zip = req.kind === "actions-artifact-zip" || req.kind === "actions-job-logs";
52432
+ if (zip !== (o.out !== void 0)) return fail(`api get: --out <file> is required for, and only valid with, repos/{owner}/{repo}/actions/artifacts/{id}/zip and repos/{owner}/{repo}/actions/jobs/{id}/logs`);
52239
52433
  const actionsRoute = req.kind.startsWith("actions-");
52240
52434
  if (actionsRoute) requireBrokerApp("api get");
52241
52435
  const env = actionsRoute || process.env.MMI_ACTOR === "app" ? brokerChildEnv() : void 0;
52242
52436
  let body;
52243
52437
  try {
52244
52438
  body = await runApiGet(
52245
- async (args, timeoutMs) => spawn6(args, timeoutMs, env),
52439
+ async (args, timeoutMs) => zip ? spawn6(args, ZIP_TIMEOUT_MS, env, true) : spawn6(args, timeoutMs, env),
52246
52440
  req.path,
52247
52441
  o.accept
52248
52442
  );
52443
+ if (zip) {
52444
+ (0, import_node_fs50.writeFileSync)(o.out, body, "latin1");
52445
+ return;
52446
+ }
52249
52447
  } catch (e) {
52250
52448
  const err = e;
52251
52449
  return fail(`api get: ${(err.stderr || err.message || String(e)).trim()}`);
@@ -53102,8 +53300,8 @@ function registerSessionReport(program3) {
53102
53300
  }
53103
53301
 
53104
53302
  // src/stage-commands.ts
53105
- var import_node_fs49 = require("node:fs");
53106
- var import_node_path46 = require("node:path");
53303
+ var import_node_fs51 = require("node:fs");
53304
+ var import_node_path47 = require("node:path");
53107
53305
  init_cli_shared();
53108
53306
  init_clean_exit();
53109
53307
 
@@ -53351,8 +53549,8 @@ function registerStageCommands(program3) {
53351
53549
  const repo = Array.isArray(project2?.repos) && typeof project2.repos[0] === "string" ? project2.repos[0] : slug;
53352
53550
  const resolution = decideStage({
53353
53551
  registry: { deployModel: project2?.deployModel, portRange, error: read.ok ? void 0 : read.error },
53354
- hasCompose: (0, import_node_fs49.existsSync)((0, import_node_path46.join)(process.cwd(), "docker-compose.yml")),
53355
- hasEnvExample: (0, import_node_fs49.existsSync)((0, import_node_path46.join)(process.cwd(), ".env.example")),
53552
+ hasCompose: (0, import_node_fs51.existsSync)((0, import_node_path47.join)(process.cwd(), "docker-compose.yml")),
53553
+ hasEnvExample: (0, import_node_fs51.existsSync)((0, import_node_path47.join)(process.cwd(), ".env.example")),
53356
53554
  repo
53357
53555
  });
53358
53556
  if (resolution.source === "derived" && resolution.derived) {
@@ -53644,23 +53842,23 @@ vercel preview (${preview.branch}): ${d.state}${d.url ? ` \u2014 ${d.url}` : ""}
53644
53842
  }
53645
53843
 
53646
53844
  // src/tenant-artifact.ts
53647
- var import_node_crypto16 = require("node:crypto");
53648
- var import_node_fs50 = require("node:fs");
53845
+ var import_node_crypto17 = require("node:crypto");
53846
+ var import_node_fs52 = require("node:fs");
53649
53847
  var import_promises11 = require("node:fs/promises");
53650
- var import_node_path47 = require("node:path");
53848
+ var import_node_path48 = require("node:path");
53651
53849
  var ARTIFACT_ID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
53652
- var MAX_BYTES = 5 * 1024 * 1024 * 1024;
53850
+ var MAX_BYTES2 = 5 * 1024 * 1024 * 1024;
53653
53851
  async function sha256File(path2) {
53654
- const hash = (0, import_node_crypto16.createHash)("sha256");
53655
- for await (const chunk of (0, import_node_fs50.createReadStream)(path2)) hash.update(chunk);
53852
+ const hash = (0, import_node_crypto17.createHash)("sha256");
53853
+ for await (const chunk of (0, import_node_fs52.createReadStream)(path2)) hash.update(chunk);
53656
53854
  return hash.digest("hex");
53657
53855
  }
53658
53856
  async function putTenantArtifact(repo, stage, inputPath, deps) {
53659
53857
  if (!["dev", "rc", "main"].includes(stage)) throw new Error("tenant artifact put: <stage> must be dev, rc, or main");
53660
- const path2 = (0, import_node_path47.resolve)(inputPath);
53858
+ const path2 = (0, import_node_path48.resolve)(inputPath);
53661
53859
  const info = await (0, import_promises11.stat)(path2);
53662
53860
  if (!info.isFile()) throw new Error("tenant artifact put: input path must be a file");
53663
- if (!Number.isSafeInteger(info.size) || info.size < 1 || info.size > MAX_BYTES) throw new Error(`tenant artifact put: file must be 1..${MAX_BYTES} bytes`);
53861
+ if (!Number.isSafeInteger(info.size) || info.size < 1 || info.size > MAX_BYTES2) throw new Error(`tenant artifact put: file must be 1..${MAX_BYTES2} bytes`);
53664
53862
  const sha2563 = await sha256File(path2);
53665
53863
  const prepared = await tenantArtifactUpload({ repo, stage, size: info.size, sha256: sha2563 }, deps);
53666
53864
  if (!prepared.ok) {
@@ -53675,7 +53873,7 @@ async function putTenantArtifact(repo, stage, inputPath, deps) {
53675
53873
  return [key, value];
53676
53874
  }));
53677
53875
  headers["content-length"] = String(info.size);
53678
- const stream = (0, import_node_fs50.createReadStream)(path2);
53876
+ const stream = (0, import_node_fs52.createReadStream)(path2);
53679
53877
  let uploaded;
53680
53878
  try {
53681
53879
  uploaded = await fetch(body.uploadUrl, {
@@ -53814,7 +54012,7 @@ function renderVerifySecrets(body) {
53814
54012
  }
53815
54013
 
53816
54014
  // src/command-register-developer.ts
53817
- var import_node_fs54 = require("node:fs");
54015
+ var import_node_fs56 = require("node:fs");
53818
54016
  init_clean_exit();
53819
54017
  init_cli_shared();
53820
54018
  init_error_codes();
@@ -53847,7 +54045,7 @@ async function resolveWhoami(deps) {
53847
54045
  }
53848
54046
 
53849
54047
  // src/command-register-developer.ts
53850
- var import_node_path52 = require("node:path");
54048
+ var import_node_path53 = require("node:path");
53851
54049
  init_house_map();
53852
54050
  init_hub_url();
53853
54051
 
@@ -53881,28 +54079,28 @@ async function executeWaveLand(plan, deps) {
53881
54079
 
53882
54080
  // src/dist-drift.ts
53883
54081
  var import_node_child_process19 = require("node:child_process");
53884
- var import_node_crypto18 = require("node:crypto");
53885
- var import_node_fs52 = require("node:fs");
53886
- var import_node_os23 = require("node:os");
53887
- var import_node_path49 = require("node:path");
54082
+ var import_node_crypto19 = require("node:crypto");
54083
+ var import_node_fs54 = require("node:fs");
54084
+ var import_node_os24 = require("node:os");
54085
+ var import_node_path50 = require("node:path");
53888
54086
 
53889
54087
  // ../scripts/distribution-digest.mjs
53890
- var import_node_crypto17 = require("node:crypto");
53891
- var import_node_fs51 = require("node:fs");
53892
- var import_node_path48 = require("node:path");
54088
+ var import_node_crypto18 = require("node:crypto");
54089
+ var import_node_fs53 = require("node:fs");
54090
+ var import_node_path49 = require("node:path");
53893
54091
  var slash = (value) => value.replaceAll("\\", "/");
53894
54092
  function repoPath(root, declaredPath, label) {
53895
- const absoluteRoot = (0, import_node_path48.resolve)(root);
53896
- const target = (0, import_node_path48.resolve)(root, declaredPath);
53897
- if (target !== absoluteRoot && !target.startsWith(`${absoluteRoot}${import_node_path48.sep}`)) {
54093
+ const absoluteRoot = (0, import_node_path49.resolve)(root);
54094
+ const target = (0, import_node_path49.resolve)(root, declaredPath);
54095
+ if (target !== absoluteRoot && !target.startsWith(`${absoluteRoot}${import_node_path49.sep}`)) {
53898
54096
  throw new Error(`${label} ${declaredPath} escapes the repository root`);
53899
54097
  }
53900
54098
  return target;
53901
54099
  }
53902
54100
  function digestFiles(files) {
53903
- const hash = (0, import_node_crypto17.createHash)("sha256");
54101
+ const hash = (0, import_node_crypto18.createHash)("sha256");
53904
54102
  for (const file of [...files].sort((a, b) => a.relative.localeCompare(b.relative))) {
53905
- const content = file.stat.isSymbolicLink() ? Buffer.from((0, import_node_fs51.readlinkSync)(file.absolute), "utf8") : (0, import_node_fs51.readFileSync)(file.absolute);
54103
+ const content = file.stat.isSymbolicLink() ? Buffer.from((0, import_node_fs53.readlinkSync)(file.absolute), "utf8") : (0, import_node_fs53.readFileSync)(file.absolute);
53906
54104
  hash.update(file.relative, "utf8");
53907
54105
  hash.update("\0");
53908
54106
  hash.update(file.stat.isSymbolicLink() ? "symlink" : "file", "utf8");
@@ -53917,8 +54115,8 @@ function digestFiles(files) {
53917
54115
  function digestPackedFiles(packageRoot, packedFiles) {
53918
54116
  return digestFiles(packedFiles.map((path2) => {
53919
54117
  const absolute = repoPath(packageRoot, path2, "packed artifact identity path");
53920
- if (!(0, import_node_fs51.existsSync)(absolute)) throw new Error(`packed artifact identity path ${path2} does not exist`);
53921
- return { absolute, relative: slash(path2), stat: (0, import_node_fs51.lstatSync)(absolute) };
54118
+ if (!(0, import_node_fs53.existsSync)(absolute)) throw new Error(`packed artifact identity path ${path2} does not exist`);
54119
+ return { absolute, relative: slash(path2), stat: (0, import_node_fs53.lstatSync)(absolute) };
53922
54120
  }));
53923
54121
  }
53924
54122
 
@@ -53930,7 +54128,7 @@ var DIST_ARTIFACTS = [
53930
54128
  ];
53931
54129
  var BOM_DIST_TREE_ID = "mmi-cli-dist";
53932
54130
  var ABSENT = "absent";
53933
- var sha2562 = (bytes) => `sha256:${(0, import_node_crypto18.createHash)("sha256").update(bytes).digest("hex")}`;
54131
+ var sha2562 = (bytes) => `sha256:${(0, import_node_crypto19.createHash)("sha256").update(bytes).digest("hex")}`;
53934
54132
  function artifactDrift(path2, committedBytes, rebuiltBytes) {
53935
54133
  const committed = committedBytes ? sha2562(committedBytes) : ABSENT;
53936
54134
  const rebuiltExpected = rebuiltBytes ? sha2562(rebuiltBytes) : ABSENT;
@@ -54002,13 +54200,13 @@ function renderDistDriftReceipt(receipt) {
54002
54200
  return lines2;
54003
54201
  }
54004
54202
  function readOrNull(path2) {
54005
- return (0, import_node_fs52.existsSync)(path2) ? (0, import_node_fs52.readFileSync)(path2) : null;
54203
+ return (0, import_node_fs54.existsSync)(path2) ? (0, import_node_fs54.readFileSync)(path2) : null;
54006
54204
  }
54007
54205
  function walkFiles(root) {
54008
54206
  const files = [];
54009
54207
  const walk2 = (directory) => {
54010
- for (const entry of (0, import_node_fs52.readdirSync)(directory, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
54011
- const child2 = (0, import_node_path49.join)(directory, entry.name);
54208
+ for (const entry of (0, import_node_fs54.readdirSync)(directory, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
54209
+ const child2 = (0, import_node_path50.join)(directory, entry.name);
54012
54210
  if (entry.isDirectory()) walk2(child2);
54013
54211
  else files.push(child2);
54014
54212
  }
@@ -54018,10 +54216,10 @@ function walkFiles(root) {
54018
54216
  }
54019
54217
  function bomPathFor(root) {
54020
54218
  try {
54021
- const registry2 = JSON.parse((0, import_node_fs52.readFileSync)((0, import_node_path49.join)(root, "surfaces.json"), "utf8"));
54022
- return (0, import_node_path49.join)(root, registry2?.sharedAgentCore?.releaseMetadata?.bomPath ?? "distribution-bom.json");
54219
+ const registry2 = JSON.parse((0, import_node_fs54.readFileSync)((0, import_node_path50.join)(root, "surfaces.json"), "utf8"));
54220
+ return (0, import_node_path50.join)(root, registry2?.sharedAgentCore?.releaseMetadata?.bomPath ?? "distribution-bom.json");
54023
54221
  } catch {
54024
- return (0, import_node_path49.join)(root, "distribution-bom.json");
54222
+ return (0, import_node_path50.join)(root, "distribution-bom.json");
54025
54223
  }
54026
54224
  }
54027
54225
  function rebuildTo(packageRoot, outDir) {
@@ -54034,35 +54232,35 @@ function rebuildTo(packageRoot, outDir) {
54034
54232
  });
54035
54233
  }
54036
54234
  function runDistStatus(root) {
54037
- const stage = (0, import_node_fs52.mkdtempSync)((0, import_node_path49.join)((0, import_node_os23.tmpdir)(), "mmi-dist-drift-"));
54235
+ const stage = (0, import_node_fs54.mkdtempSync)((0, import_node_path50.join)((0, import_node_os24.tmpdir)(), "mmi-dist-drift-"));
54038
54236
  let overlayCount = 0;
54039
54237
  try {
54040
- const cliOut = (0, import_node_path49.join)(stage, "cli-dist");
54041
- const hubOut = (0, import_node_path49.join)(stage, "hub-dist");
54042
- rebuildTo((0, import_node_path49.join)(root, "cli"), cliOut);
54043
- rebuildTo((0, import_node_path49.join)(root, "updater"), hubOut);
54238
+ const cliOut = (0, import_node_path50.join)(stage, "cli-dist");
54239
+ const hubOut = (0, import_node_path50.join)(stage, "hub-dist");
54240
+ rebuildTo((0, import_node_path50.join)(root, "cli"), cliOut);
54241
+ rebuildTo((0, import_node_path50.join)(root, "updater"), hubOut);
54044
54242
  const outDirFor = (packageDir) => packageDir === "cli" ? cliOut : hubOut;
54045
54243
  const rebuilt = (path2) => {
54046
54244
  const spec = DIST_ARTIFACTS.find((entry) => entry.path === path2);
54047
- return spec ? readOrNull((0, import_node_path49.join)(outDirFor(spec.packageDir), spec.output)) : null;
54245
+ return spec ? readOrNull((0, import_node_path50.join)(outDirFor(spec.packageDir), spec.output)) : null;
54048
54246
  };
54049
- const committed = (path2) => readOrNull((0, import_node_path49.join)(root, path2));
54050
- const tree = (path2) => readOrNull((0, import_node_path49.join)(root, path2));
54051
- const distRoot = (0, import_node_path49.join)(root, "cli", "dist");
54052
- const distTree = () => walkFiles(distRoot).map((absolute) => `cli/dist/${(0, import_node_path49.relative)(distRoot, absolute).replaceAll("\\", "/")}`);
54053
- const bom = JSON.parse((0, import_node_fs52.readFileSync)(bomPathFor(root), "utf8"));
54247
+ const committed = (path2) => readOrNull((0, import_node_path50.join)(root, path2));
54248
+ const tree = (path2) => readOrNull((0, import_node_path50.join)(root, path2));
54249
+ const distRoot = (0, import_node_path50.join)(root, "cli", "dist");
54250
+ const distTree = () => walkFiles(distRoot).map((absolute) => `cli/dist/${(0, import_node_path50.relative)(distRoot, absolute).replaceAll("\\", "/")}`);
54251
+ const bom = JSON.parse((0, import_node_fs54.readFileSync)(bomPathFor(root), "utf8"));
54054
54252
  const digest = (entries) => {
54055
- const overlay = (0, import_node_path49.join)(stage, `overlay-${overlayCount++}`);
54253
+ const overlay = (0, import_node_path50.join)(stage, `overlay-${overlayCount++}`);
54056
54254
  for (const entry of entries) {
54057
- const target = (0, import_node_path49.join)(overlay, entry.path);
54058
- (0, import_node_fs52.mkdirSync)((0, import_node_path49.dirname)(target), { recursive: true });
54059
- (0, import_node_fs52.writeFileSync)(target, entry.bytes);
54255
+ const target = (0, import_node_path50.join)(overlay, entry.path);
54256
+ (0, import_node_fs54.mkdirSync)((0, import_node_path50.dirname)(target), { recursive: true });
54257
+ (0, import_node_fs54.writeFileSync)(target, entry.bytes);
54060
54258
  }
54061
54259
  return digestPackedFiles(overlay, entries.map((entry) => entry.path));
54062
54260
  };
54063
54261
  return computeDistDriftReceipt({ committed, tree, rebuilt, distTree, bom, digest });
54064
54262
  } finally {
54065
- (0, import_node_fs52.rmSync)(stage, { recursive: true, force: true });
54263
+ (0, import_node_fs54.rmSync)(stage, { recursive: true, force: true });
54066
54264
  }
54067
54265
  }
54068
54266
 
@@ -54163,7 +54361,7 @@ init_hub_auth();
54163
54361
 
54164
54362
  // src/schedules-lift-command.ts
54165
54363
  var import_promises12 = require("node:fs/promises");
54166
- var import_node_path50 = require("node:path");
54364
+ var import_node_path51 = require("node:path");
54167
54365
  init_clean_exit();
54168
54366
  init_cli_shared();
54169
54367
  var DEFAULT_WORKFLOWS_DIR = ".github/workflows";
@@ -54192,7 +54390,7 @@ async function readWorkflowFiles(dir) {
54192
54390
  const files = [];
54193
54391
  for (const name of names.sort()) {
54194
54392
  if (!/\.ya?ml$/.test(name)) continue;
54195
- files.push({ path: `.github/workflows/${name}`, text: await (0, import_promises12.readFile)((0, import_node_path50.join)(dir, name), "utf8") });
54393
+ files.push({ path: `.github/workflows/${name}`, text: await (0, import_promises12.readFile)((0, import_node_path51.join)(dir, name), "utf8") });
54196
54394
  }
54197
54395
  return files;
54198
54396
  }
@@ -54275,8 +54473,8 @@ function registerSchedulesLiftCommand(program3, deps = {}) {
54275
54473
 
54276
54474
  // src/spawn-policy-core.ts
54277
54475
  var import_node_child_process20 = require("node:child_process");
54278
- var import_node_fs53 = require("node:fs");
54279
- var import_node_path51 = require("node:path");
54476
+ var import_node_fs55 = require("node:fs");
54477
+ var import_node_path52 = require("node:path");
54280
54478
  var SPAWNERS = ["spawn", "spawnSync", "exec", "execSync", "execFile", "execFileSync"];
54281
54479
  var CALL_SOURCE = String.raw`(^|[^.\w$])(${SPAWNERS.join("|")})\s*\(`;
54282
54480
  var SOURCE_EXT = /\.(ts|mts|cts|js|mjs|cjs)$/;
@@ -54362,7 +54560,7 @@ function runSpawnPolicy(root) {
54362
54560
  for (const file of files) {
54363
54561
  let raw;
54364
54562
  try {
54365
- raw = (0, import_node_fs53.readFileSync)((0, import_node_path51.join)(root, file), "utf8");
54563
+ raw = (0, import_node_fs55.readFileSync)((0, import_node_path52.join)(root, file), "utf8");
54366
54564
  } catch {
54367
54565
  continue;
54368
54566
  }
@@ -54382,19 +54580,19 @@ function runSpawnPolicy(root) {
54382
54580
  function registerDeveloperCommands(program3) {
54383
54581
  const rules = program3.command("rules").description("org-managed .gitignore delivery");
54384
54582
  rules.command("gitignore").option("--write", "upsert the managed block into .gitignore (default: check only, non-zero exit on drift)").option("--json", "machine-readable output").description("verify (or --write) this repo's org-managed .gitignore block matches the SSOT").action((opts) => {
54385
- const path2 = (0, import_node_path52.join)(process.cwd(), ".gitignore");
54386
- const current = (0, import_node_fs54.existsSync)(path2) ? (0, import_node_fs54.readFileSync)(path2, "utf8") : null;
54583
+ const path2 = (0, import_node_path53.join)(process.cwd(), ".gitignore");
54584
+ const current = (0, import_node_fs56.existsSync)(path2) ? (0, import_node_fs56.readFileSync)(path2, "utf8") : null;
54387
54585
  const plan = planManagedGitignore(current);
54388
54586
  const drift = [...plan.added.map((l) => `+${l}`), ...plan.removed.map((l) => `-${l}`)].join(", ") || "block normalize";
54389
54587
  if (opts.json) {
54390
- if (opts.write && plan.changed) (0, import_node_fs54.writeFileSync)(path2, plan.content, "utf8");
54588
+ if (opts.write && plan.changed) (0, import_node_fs56.writeFileSync)(path2, plan.content, "utf8");
54391
54589
  console.log(JSON.stringify(plan, null, 2));
54392
54590
  if (!opts.write && plan.changed) process.exitCode = 1;
54393
54591
  return;
54394
54592
  }
54395
54593
  if (opts.write) {
54396
54594
  if (plan.changed) {
54397
- (0, import_node_fs54.writeFileSync)(path2, plan.content, "utf8");
54595
+ (0, import_node_fs56.writeFileSync)(path2, plan.content, "utf8");
54398
54596
  console.log(`mmi-cli devops org rules gitignore: updated .gitignore (${drift})`);
54399
54597
  } else {
54400
54598
  console.log("mmi-cli devops org rules gitignore: up to date");
@@ -54657,12 +54855,12 @@ ${r.stderr ?? ""}`).catch(() => "");
54657
54855
  var ENV_HEAL_LOCK_STALE_MS = 10 * 6e4;
54658
54856
  var ENV_HEAL_LOCK_MAX_WAIT_MS = 2 * 6e4;
54659
54857
  function envHealLockPath(home) {
54660
- return (0, import_node_path53.join)(home, ".claude", "plugins", ".mmi-env-heal.lock");
54858
+ return (0, import_node_path54.join)(home, ".claude", "plugins", ".mmi-env-heal.lock");
54661
54859
  }
54662
54860
  async function withEnvHealLock(what, run) {
54663
54861
  try {
54664
54862
  return await withFileLock(
54665
- envHealLockPath((0, import_node_os24.homedir)()),
54863
+ envHealLockPath((0, import_node_os25.homedir)()),
54666
54864
  { staleMs: ENV_HEAL_LOCK_STALE_MS, maxWaitMs: ENV_HEAL_LOCK_MAX_WAIT_MS, label: "mmi env-heal lock" },
54667
54865
  run
54668
54866
  );
@@ -54759,7 +54957,7 @@ function mmiDoctorDeps(opts = {}) {
54759
54957
  const configRoot = surfaceConfigRoot(surface);
54760
54958
  const running = surface === "codex" ? installedActivePluginVersion(surface) : runningPluginVersion(process.env, resolveClientVersion());
54761
54959
  const plan = buildPluginCachePlan(
54762
- (0, import_node_os24.homedir)(),
54960
+ (0, import_node_os25.homedir)(),
54763
54961
  running,
54764
54962
  pluginCacheFsDeps(configRoot, () => 0),
54765
54963
  { configRoot, includeStaging: surface !== "codex" }
@@ -54787,14 +54985,14 @@ function mmiDoctorDeps(opts = {}) {
54787
54985
  const running = surface === "codex" ? installedActivePluginVersion(surface) : runningPluginVersion(process.env, resolveClientVersion());
54788
54986
  const installed = installedActivePluginVersion(surface);
54789
54987
  const plan = buildPluginCachePlan(
54790
- (0, import_node_os24.homedir)(),
54988
+ (0, import_node_os25.homedir)(),
54791
54989
  running,
54792
54990
  pluginCacheFsDeps(configRoot, () => 0),
54793
54991
  { configRoot, includeStaging: surface !== "codex", installedVersion: installed }
54794
54992
  );
54795
54993
  const result = applyPluginCachePlan(
54796
54994
  plan,
54797
- (p) => (0, import_node_fs55.rmSync)(p, { recursive: true }),
54995
+ (p) => (0, import_node_fs57.rmSync)(p, { recursive: true }),
54798
54996
  stagingApplyFsGuard(configRoot)
54799
54997
  );
54800
54998
  return {
@@ -54829,7 +55027,7 @@ function mmiDoctorDeps(opts = {}) {
54829
55027
  // has no generated routing index would
54830
55028
  // get a permanent — demanding an artifact it never asked for.
54831
55029
  docsIndexState: (root) => {
54832
- if (!(0, import_node_fs55.existsSync)((0, import_node_path53.join)(root, DOCS_INDEX_PATH))) return void 0;
55030
+ if (!(0, import_node_fs57.existsSync)((0, import_node_path54.join)(root, DOCS_INDEX_PATH))) return void 0;
54833
55031
  const real = createDocsIndexDeps(root);
54834
55032
  let docs;
54835
55033
  const listDocs = () => docs ??= real.listDocs();
@@ -54838,7 +55036,7 @@ function mmiDoctorDeps(opts = {}) {
54838
55036
  },
54839
55037
  // #4168: working-tree heal — write if drifted, then re-check. Commit remains the operator's step.
54840
55038
  healDocsIndex: (root) => {
54841
- if (!(0, import_node_fs55.existsSync)((0, import_node_path53.join)(root, DOCS_INDEX_PATH))) return { drift: false, docCount: 0 };
55039
+ if (!(0, import_node_fs57.existsSync)((0, import_node_path54.join)(root, DOCS_INDEX_PATH))) return { drift: false, docCount: 0 };
54842
55040
  const real = createDocsIndexDeps(root);
54843
55041
  let docs;
54844
55042
  const listDocs = () => docs ??= real.listDocs();
@@ -55187,14 +55385,17 @@ program2.addHelpText(
55187
55385
  var appActorCommand = "poll";
55188
55386
  function appActorDeps() {
55189
55387
  return {
55190
- fetchSecret: async (key) => fetchSecretValue(makeSecretsDeps(await loadConfig()), key, {
55191
- repo: APP_VAULT_REPO,
55192
- attribution: { command: appActorCommand, via: formatSessionIdentity(describeSessionIdentity()) }
55193
- }),
55388
+ fetchSecret: async (key) => {
55389
+ const deps = makeSecretsDeps(await loadConfig());
55390
+ return readAppVaultSecret(() => fetchSecretValue(deps, key, {
55391
+ repo: APP_VAULT_REPO,
55392
+ attribution: { command: appActorCommand, via: formatSessionIdentity(describeSessionIdentity()) }
55393
+ }, true));
55394
+ },
55194
55395
  fetch: (url, init) => fetch(url, init)
55195
55396
  };
55196
55397
  }
55197
- setPollTokenProvider(() => pollTokenOrUndefined(appActorDeps()));
55398
+ setPollTokenProvider(async () => activeAppToken() ?? pollTokenOrUndefined(appActorDeps()));
55198
55399
  var registerPreAction = Reflect.get(program2, ["h", "ook"].join(""));
55199
55400
  registerPreAction.call(program2, "preAction", async (_thisCommand, actionCommand) => {
55200
55401
  const commandPath3 = commandPathOf(actionCommand);
@@ -55218,8 +55419,9 @@ async function reportWrite(label, res) {
55218
55419
  return failGraceful(`${label}: HTTP ${res.status}${detail ? ` \u2014 ${detail}` : ""}`);
55219
55420
  }
55220
55421
  var tenant = program2.command("tenant").description("tenant runtime control through Hub authority");
55221
- tenant.command("control <owner/repo> <stage> <action>").description("bounded tenant control plus value-free vault/broker verification; dev/main retire needs master and exact data-loss confirmation").option("--watch", "block on the dispatched run and report its conclusion (status/retire/verify-secrets/verify-broker/logs watch by default)").option("--lines <n>", "logs only: trailing lines of the tenant service to return (1-2000, default 200)").option("--since <utc>", "logs only: read the journal from this UTC time, e.g. 2026-10-07T13:10Z (includes replaced containers)").option("--until <utc>", "logs only: read the journal up to this UTC time").option("--edge", "logs only: Caddy journal for this stage\u2019s hosts (default window: last 15 minutes)").option("--task <name>", "run-task only: registry-declared task name (never a command)").option("--artifact <id>", "run-task only: opaque id returned by tenant artifact put").option("--confirm-data-loss <owner/repo/stage>", "dev/main retire only: exact target to decommission; without it show the dry-run plan").option("--json", "machine-readable output").action(async (repo, stage, action, o) => {
55422
+ tenant.command("control <owner/repo> <stage> <action>").description("bounded tenant control plus value-free vault/broker verification; dev/main retire needs master and exact data-loss confirmation").option("--watch", "block on the dispatched run and report its conclusion (status/retire/verify-secrets/verify-broker/logs watch by default)").option("--lines <n>", "logs only: trailing lines of the tenant service to return (1-2000, default 200)").option("--since <utc>", "logs only: read the journal from this UTC time, e.g. 2026-10-07T13:10Z (includes replaced containers)").option("--until <utc>", "logs only: read the journal up to this UTC time").option("--edge", "logs only: Caddy journal for this stage\u2019s hosts (default window: last 15 minutes)").option("--task <name>", "run-task only: registry-declared task name (never a command)").option("--artifact <id>", "run-task only: opaque id returned by tenant artifact put").option("--resume <run-id>", "run-task only: re-attach to an already-dispatched run (read-only, never re-dispatches) and print its receipt").option("--confirm-data-loss <owner/repo/stage>", "dev/main retire only: exact target to decommission; without it show the dry-run plan").option("--json", "machine-readable output").action(async (repo, stage, action, o) => {
55222
55423
  try {
55424
+ if (o.resume !== void 0 && (action !== "run-task" || !/^\d+$/.test(o.resume) || o.task || o.artifact)) return fail("runtime tenant control: --resume <run-id> is run-task-only, takes a numeric run id, and cannot be combined with --task/--artifact");
55223
55425
  if (o.confirmDataLoss !== void 0 && (action !== "retire" || stage === "rc")) return fail("runtime tenant control: --confirm-data-loss is dev/main retire-only");
55224
55426
  if (action === "retire" && (stage === "dev" || stage === "main")) {
55225
55427
  if (o.confirmDataLoss !== void 0 && o.confirmDataLoss !== `${repo}/${stage}`) return fail(`runtime tenant control: --confirm-data-loss must match ${repo}/${stage} exactly`);
@@ -55244,11 +55446,11 @@ Dry run: pass --confirm-data-loss ${repo}/${stage} to decommission.`);
55244
55446
  if (!/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(:\d{2})?Z$/.test(value)) return fail(`runtime tenant control: ${flag} must be a UTC time like 2026-10-07T13:10Z`);
55245
55447
  }
55246
55448
  if (action === "run-task") {
55247
- if (!o.task) return fail("runtime tenant control: run-task requires --task <declared-name>");
55449
+ if (!o.task && o.resume === void 0) return fail("runtime tenant control: run-task requires --task <declared-name>");
55248
55450
  } else if (o.task || o.artifact) {
55249
55451
  return fail("runtime tenant control: --task/--artifact are valid only for run-task");
55250
55452
  }
55251
- const result = await runTenantControl(trainApplyDeps(), { repo, stage, action, watch: o.watch, lines: lines2, edge: o.edge, logSince: o.since, logUntil: o.until, task: o.task, artifact: o.artifact, confirmDataLoss: o.confirmDataLoss });
55453
+ const result = await runTenantControl(trainApplyDeps(), { repo, stage, action, watch: o.watch, lines: lines2, edge: o.edge, logSince: o.since, logUntil: o.until, task: o.task, artifact: o.artifact, confirmDataLoss: o.confirmDataLoss, resume: o.resume === void 0 ? void 0 : Number(o.resume) });
55252
55454
  if (!o.json && action === "verify-secrets" && result.secrets) {
55253
55455
  const body = { ok: result.conclusion === "success", secrets: result.secrets, ssmStatus: result.conclusion === "success" ? "Success" : "Failed", raw: result.secretsRaw };
55254
55456
  const { lines: lines3, failure } = renderVerifySecrets(body);
@@ -55552,7 +55754,7 @@ project.command("set [owner/repo]").description("upsert project META (idempotent
55552
55754
  if (dupe) return fail(`org project set: KEY "${dupe}" was passed to both --var and --set; --set is an alias of --var, so pass each KEY once`);
55553
55755
  if (o.secretsFile) {
55554
55756
  try {
55555
- vars.push(`secrets=${(0, import_node_fs55.readFileSync)(o.secretsFile, "utf8")}`);
55757
+ vars.push(`secrets=${(0, import_node_fs57.readFileSync)(o.secretsFile, "utf8")}`);
55556
55758
  } catch (e) {
55557
55759
  return fail(`org project set: cannot read --secrets-file ${o.secretsFile}: ${e.message}`);
55558
55760
  }
@@ -55821,9 +56023,11 @@ projectTenantTasks.command("declare <name>").description("register a NEW tenant
55821
56023
  if (!res.ok) process.exitCode = 1;
55822
56024
  });
55823
56025
  var registry = program2.command("registry").description("the DDB org registry \u2014 org-level constants");
55824
- registry.command("org").description("the org config (account id, region, orgProjectId, sagaApiUrl)").option("--json", "machine-readable output").action(async (_o) => {
56026
+ registry.command("org").description("the org config (account id, region, orgProjectId, sagaApiUrl)").option("--json", "machine-readable output").option("--github-spend-minutes <minutes>", "master-only App spend by route, caller and pool over the last 1\u201360 minutes").action(async (_o) => {
56027
+ const minutes = _o.githubSpendMinutes === void 0 ? void 0 : Number(_o.githubSpendMinutes);
56028
+ if (minutes !== void 0 && (!Number.isInteger(minutes) || minutes < 1 || minutes > 60)) return fail("github-spend-minutes must be an integer from 1 to 60");
55825
56029
  const cfg = await loadConfig();
55826
- const org = await fetchOrgConfig(registryClientDeps(cfg));
56030
+ const org = await fetchOrgConfig(registryClientDeps(cfg), minutes);
55827
56031
  if (!org) return failGraceful("org config get: Hub API unreachable, unseeded, or this repo is not bootstrapped");
55828
56032
  console.log(JSON.stringify(org));
55829
56033
  });
@@ -55940,16 +56144,16 @@ function ciAuditDeps2() {
55940
56144
  // gate re-seed step is skipped gracefully rather than failing mid-run.
55941
56145
  readSeedFile: (path2) => {
55942
56146
  if (!root) return null;
55943
- const fullPath = (0, import_node_path53.join)(root, path2);
55944
- return (0, import_node_fs55.existsSync)(fullPath) ? (0, import_node_fs55.readFileSync)(fullPath, "utf8") : null;
56147
+ const fullPath = (0, import_node_path54.join)(root, path2);
56148
+ return (0, import_node_fs57.existsSync)(fullPath) ? (0, import_node_fs57.readFileSync)(fullPath, "utf8") : null;
55945
56149
  }
55946
56150
  };
55947
56151
  }
55948
56152
  function hubRoot2() {
55949
- const fromPkg = (0, import_node_path53.join)(__dirname, "..", "..");
56153
+ const fromPkg = (0, import_node_path54.join)(__dirname, "..", "..");
55950
56154
  const marker = "skills/bootstrap/seeds/manifest.json";
55951
- if ((0, import_node_fs55.existsSync)((0, import_node_path53.join)(fromPkg, marker))) return fromPkg;
55952
- if ((0, import_node_fs55.existsSync)((0, import_node_path53.join)(process.cwd(), marker))) return process.cwd();
56155
+ if ((0, import_node_fs57.existsSync)((0, import_node_path54.join)(fromPkg, marker))) return fromPkg;
56156
+ if ((0, import_node_fs57.existsSync)((0, import_node_path54.join)(process.cwd(), marker))) return process.cwd();
55953
56157
  return null;
55954
56158
  }
55955
56159
  registerQueryCommands(program2);
@@ -56079,10 +56283,10 @@ access.command("audit").description("audit collaborator roles + train-branch pus
56079
56283
  targets = resolution.targets;
56080
56284
  }
56081
56285
  const derivedMatrix = registryProjects ? accessMatrixFromProjects(registryProjects) : {};
56082
- const fileMatrix = (0, import_node_fs55.existsSync)("access-matrix.json") ? loadAccessMatrix((0, import_node_fs55.readFileSync)("access-matrix.json", "utf8")) : {};
56286
+ const fileMatrix = (0, import_node_fs57.existsSync)("access-matrix.json") ? loadAccessMatrix((0, import_node_fs57.readFileSync)("access-matrix.json", "utf8")) : {};
56083
56287
  const matrix = mergeAccessMatrix(fileMatrix, derivedMatrix);
56084
56288
  const dataAccess = registryProjects ? dataAccessContractsFromProjects(registryProjects) : { consumers: {} };
56085
- const sanctioned = (0, import_node_fs55.existsSync)("access-matrix.json") ? loadSanctionedAdmins((0, import_node_fs55.readFileSync)("access-matrix.json", "utf8")) : {};
56289
+ const sanctioned = (0, import_node_fs57.existsSync)("access-matrix.json") ? loadSanctionedAdmins((0, import_node_fs57.readFileSync)("access-matrix.json", "utf8")) : {};
56086
56290
  const report = await auditOrgAccess(targets, deps, matrix, dataAccess, sanctioned);
56087
56291
  console.log(o.json ? JSON.stringify(report, null, 2) : renderAccessReport(report));
56088
56292
  if (!report.ok) process.exitCode = 1;
@@ -56113,16 +56317,16 @@ function directoryBytes(path2) {
56113
56317
  let total = 0;
56114
56318
  let entries;
56115
56319
  try {
56116
- entries = (0, import_node_fs55.readdirSync)(path2, { withFileTypes: true });
56320
+ entries = (0, import_node_fs57.readdirSync)(path2, { withFileTypes: true });
56117
56321
  } catch {
56118
56322
  return 0;
56119
56323
  }
56120
56324
  for (const entry of entries) {
56121
- const child2 = (0, import_node_path53.join)(path2, entry.name);
56325
+ const child2 = (0, import_node_path54.join)(path2, entry.name);
56122
56326
  if (entry.isDirectory()) total += directoryBytes(child2);
56123
56327
  else {
56124
56328
  try {
56125
- total += (0, import_node_fs55.statSync)(child2).size;
56329
+ total += (0, import_node_fs57.statSync)(child2).size;
56126
56330
  } catch {
56127
56331
  }
56128
56332
  }
@@ -56130,25 +56334,25 @@ function directoryBytes(path2) {
56130
56334
  return total;
56131
56335
  }
56132
56336
  function listDirEntries(dir) {
56133
- return (0, import_node_fs55.readdirSync)(dir, { withFileTypes: true }).map((d) => ({ name: d.name, isDirectory: d.isDirectory() }));
56337
+ return (0, import_node_fs57.readdirSync)(dir, { withFileTypes: true }).map((d) => ({ name: d.name, isDirectory: d.isDirectory() }));
56134
56338
  }
56135
56339
  function readInstalledPluginRefs(configRoot) {
56136
56340
  const p = installedPluginsPathForConfig(configRoot);
56137
- if (!(0, import_node_fs55.existsSync)(p)) return [];
56341
+ if (!(0, import_node_fs57.existsSync)(p)) return [];
56138
56342
  try {
56139
- return installedPluginPaths((0, import_node_fs55.readFileSync)(p, "utf8"));
56343
+ return installedPluginPaths((0, import_node_fs57.readFileSync)(p, "utf8"));
56140
56344
  } catch {
56141
56345
  return null;
56142
56346
  }
56143
56347
  }
56144
56348
  function pluginCacheFsDeps(configRoot, dirBytes) {
56145
56349
  return {
56146
- exists: (p) => (0, import_node_fs55.existsSync)(p),
56147
- listVersionDirs: (root) => (0, import_node_fs55.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name),
56350
+ exists: (p) => (0, import_node_fs57.existsSync)(p),
56351
+ listVersionDirs: (root) => (0, import_node_fs57.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name),
56148
56352
  dirBytes,
56149
- listStagingDirs: (root) => (0, import_node_fs55.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => {
56353
+ listStagingDirs: (root) => (0, import_node_fs57.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => {
56150
56354
  try {
56151
- return { name: d.name, mtimeMs: newestMtimeMs((0, import_node_path53.join)(root, d.name), listDirEntries, (p) => (0, import_node_fs55.statSync)(p).mtimeMs) };
56355
+ return { name: d.name, mtimeMs: newestMtimeMs((0, import_node_path54.join)(root, d.name), listDirEntries, (p) => (0, import_node_fs57.statSync)(p).mtimeMs) };
56152
56356
  } catch {
56153
56357
  return { name: d.name, mtimeMs: Date.now() };
56154
56358
  }
@@ -56162,10 +56366,10 @@ function stagingApplyFsGuard(configRoot) {
56162
56366
  return {
56163
56367
  referencedPaths: () => readInstalledPluginRefs(configRoot),
56164
56368
  mtimeMs: (name) => {
56165
- const p = (0, import_node_path53.join)(stagingRoot, name);
56166
- if (!(0, import_node_fs55.existsSync)(p)) return null;
56369
+ const p = (0, import_node_path54.join)(stagingRoot, name);
56370
+ if (!(0, import_node_fs57.existsSync)(p)) return null;
56167
56371
  try {
56168
- return newestMtimeMs(p, listDirEntries, (q) => (0, import_node_fs55.statSync)(q).mtimeMs);
56372
+ return newestMtimeMs(p, listDirEntries, (q) => (0, import_node_fs57.statSync)(q).mtimeMs);
56169
56373
  } catch {
56170
56374
  return null;
56171
56375
  }
@@ -56185,13 +56389,13 @@ program2.command("plugin-prune").description(`prune stale cached MMI plugin vers
56185
56389
  return;
56186
56390
  }
56187
56391
  const plan = buildPluginCachePlan(
56188
- (0, import_node_os24.homedir)(),
56392
+ (0, import_node_os25.homedir)(),
56189
56393
  running,
56190
56394
  pluginCacheFsDeps(configRoot, directoryBytes),
56191
56395
  { withBytes: true, configRoot, includeStaging: surface !== "codex" }
56192
56396
  );
56193
56397
  const anythingToDelete = plan.prune.length > 0 || plan.staging.length > 0;
56194
- const result = o.apply && anythingToDelete ? applyPluginCachePlan(plan, (p) => (0, import_node_fs55.rmSync)(p, { recursive: true, force: true }), stagingApplyFsGuard(configRoot)) : void 0;
56398
+ const result = o.apply && anythingToDelete ? applyPluginCachePlan(plan, (p) => (0, import_node_fs57.rmSync)(p, { recursive: true, force: true }), stagingApplyFsGuard(configRoot)) : void 0;
56195
56399
  const warnings = plan.prune.length > 0 ? [CONCURRENT_SESSION_WARNING] : [];
56196
56400
  if (o.json) console.log(JSON.stringify({ ...plan, warnings, applied: result ?? null }));
56197
56401
  else console.log(renderPluginCachePlan(plan, result));