@mutmutco/codex-plugin 4.6.24 → 4.6.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/cli/dist/main.cjs CHANGED
@@ -157,19 +157,19 @@ function hardExit(code) {
157
157
  process.exit(code);
158
158
  }
159
159
  function flushStream(stream) {
160
- return new Promise((resolve7) => {
160
+ return new Promise((resolve8) => {
161
161
  try {
162
- stream.write("", () => resolve7());
162
+ stream.write("", () => resolve8());
163
163
  } catch {
164
- resolve7();
164
+ resolve8();
165
165
  }
166
166
  });
167
167
  }
168
168
  async function flushStdio(timeoutMs = STDIO_FLUSH_TIMEOUT_MS) {
169
169
  await Promise.race([
170
170
  Promise.all([flushStream(process.stdout), flushStream(process.stderr)]),
171
- new Promise((resolve7) => {
172
- setTimeout(resolve7, timeoutMs).unref?.();
171
+ new Promise((resolve8) => {
172
+ setTimeout(resolve8, timeoutMs).unref?.();
173
173
  })
174
174
  ]);
175
175
  }
@@ -177,7 +177,7 @@ async function cleanExit(code) {
177
177
  process.exitCode = code;
178
178
  await closeHttpPool();
179
179
  await flushStdio();
180
- await new Promise((resolve7) => setImmediate(resolve7));
180
+ await new Promise((resolve8) => setImmediate(resolve8));
181
181
  return void 0;
182
182
  }
183
183
  async function finishCliRun(watchdogMs = CLI_EXIT_WATCHDOG_MS) {
@@ -454,9 +454,9 @@ var init_gh_read_route = __esm({
454
454
  function commandPath() {
455
455
  if (cachedCommand !== void 0) return cachedCommand;
456
456
  const words = [];
457
- for (const arg of process.argv.slice(2)) {
458
- if (arg.startsWith("-") || words.length === 3) break;
459
- words.push(arg);
457
+ for (const arg2 of process.argv.slice(2)) {
458
+ if (arg2.startsWith("-") || words.length === 3) break;
459
+ words.push(arg2);
460
460
  }
461
461
  return cachedCommand = words.join(" ") || "(none)";
462
462
  }
@@ -851,7 +851,7 @@ function rateLimitedReceipt(opts) {
851
851
  };
852
852
  }
853
853
  async function runWithRateLimitBackoff(operation, opts) {
854
- const sleep2 = opts.sleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms)));
854
+ const sleep2 = opts.sleep ?? ((ms) => new Promise((resolve8) => setTimeout(resolve8, ms)));
855
855
  const now = opts.now ?? Date.now;
856
856
  const log = opts.log ?? ((message2) => console.warn(message2));
857
857
  const capMs = opts.capMs ?? RATE_LIMIT_WAIT_CAP_MS;
@@ -941,7 +941,7 @@ async function fetchWithRetry(fetchImpl, url, init, opts = {}) {
941
941
  const attempts = opts.attempts ?? 3;
942
942
  const baseDelayMs = opts.baseDelayMs ?? 250;
943
943
  const retryOn = opts.retryOn ?? ((res) => res.status >= 500);
944
- const sleep2 = opts.sleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms)));
944
+ const sleep2 = opts.sleep ?? ((ms) => new Promise((resolve8) => setTimeout(resolve8, ms)));
945
945
  let lastErr;
946
946
  for (let i = 0; i < attempts; i++) {
947
947
  const isLast = i === attempts - 1;
@@ -1346,8 +1346,8 @@ async function readStdin(opts = {}) {
1346
1346
  })().catch(() => {
1347
1347
  });
1348
1348
  let timer;
1349
- const timeout = new Promise((resolve7) => {
1350
- timer = setTimeout(resolve7, timeoutMs);
1349
+ const timeout = new Promise((resolve8) => {
1350
+ timer = setTimeout(resolve8, timeoutMs);
1351
1351
  });
1352
1352
  try {
1353
1353
  await Promise.race([drain, timeout]);
@@ -1444,12 +1444,12 @@ function killProcessTree(pid) {
1444
1444
  function execFileHard(file, args, options) {
1445
1445
  const { timeout, step, ...rest } = options;
1446
1446
  const started = Date.now();
1447
- return new Promise((resolve7, reject2) => {
1447
+ return new Promise((resolve8, reject2) => {
1448
1448
  const child2 = (0, import_node_child_process.execFile)(file, args, { encoding: "utf8", windowsHide: true, ...rest, timeout: 0 }, (error, stdout, stderr) => {
1449
1449
  clearTimeout(timer);
1450
1450
  if (expired) return;
1451
1451
  if (error) reject2(error);
1452
- else resolve7({ stdout: String(stdout), stderr: String(stderr) });
1452
+ else resolve8({ stdout: String(stdout), stderr: String(stderr) });
1453
1453
  });
1454
1454
  let expired = false;
1455
1455
  const timer = setTimeout(() => {
@@ -1585,12 +1585,12 @@ function installBrokenPipeGuard(stream) {
1585
1585
  });
1586
1586
  }
1587
1587
  function rawFlag(flag) {
1588
- return process.argv.some((arg) => arg === flag || arg.startsWith(`${flag}=`));
1588
+ return process.argv.some((arg2) => arg2 === flag || arg2.startsWith(`${flag}=`));
1589
1589
  }
1590
1590
  function rawValue(flag, fallback) {
1591
1591
  const index = process.argv.indexOf(flag);
1592
1592
  if (index >= 0 && process.argv[index + 1]) return process.argv[index + 1];
1593
- const inline = process.argv.find((arg) => arg.startsWith(`${flag}=`));
1593
+ const inline = process.argv.find((arg2) => arg2.startsWith(`${flag}=`));
1594
1594
  return inline ? inline.slice(flag.length + 1) : fallback;
1595
1595
  }
1596
1596
  function printLine(value) {
@@ -2276,19 +2276,19 @@ var require_toJS = __commonJS({
2276
2276
  "node_modules/yaml/dist/nodes/toJS.js"(exports2) {
2277
2277
  "use strict";
2278
2278
  var identity = require_identity();
2279
- function toJS(value, arg, ctx) {
2279
+ function toJS(value, arg2, ctx) {
2280
2280
  if (Array.isArray(value))
2281
2281
  return value.map((v, i) => toJS(v, String(i), ctx));
2282
2282
  if (value && typeof value.toJSON === "function") {
2283
2283
  if (!ctx || !identity.hasAnchor(value))
2284
- return value.toJSON(arg, ctx);
2284
+ return value.toJSON(arg2, ctx);
2285
2285
  const data = { aliasCount: 0, count: 1, res: void 0 };
2286
2286
  ctx.anchors.set(value, data);
2287
2287
  ctx.onCreate = (res2) => {
2288
2288
  data.res = res2;
2289
2289
  delete ctx.onCreate;
2290
2290
  };
2291
- const res = value.toJSON(arg, ctx);
2291
+ const res = value.toJSON(arg2, ctx);
2292
2292
  if (ctx.onCreate)
2293
2293
  ctx.onCreate(res);
2294
2294
  return res;
@@ -2471,8 +2471,8 @@ var require_Scalar = __commonJS({
2471
2471
  super(identity.SCALAR);
2472
2472
  this.value = value;
2473
2473
  }
2474
- toJSON(arg, ctx) {
2475
- return ctx?.keep ? this.value : toJS.toJS(this.value, arg, ctx);
2474
+ toJSON(arg2, ctx) {
2475
+ return ctx?.keep ? this.value : toJS.toJS(this.value, arg2, ctx);
2476
2476
  }
2477
2477
  toString() {
2478
2478
  return String(this.value);
@@ -10271,16 +10271,16 @@ var Argument = class {
10271
10271
  */
10272
10272
  choices(values) {
10273
10273
  this.argChoices = values.slice();
10274
- this.parseArg = (arg, previous) => {
10275
- if (!this.argChoices.includes(arg)) {
10274
+ this.parseArg = (arg2, previous) => {
10275
+ if (!this.argChoices.includes(arg2)) {
10276
10276
  throw new InvalidArgumentError(
10277
10277
  `Allowed choices are ${this.argChoices.join(", ")}.`
10278
10278
  );
10279
10279
  }
10280
10280
  if (this.variadic) {
10281
- return this._collectValue(arg, previous);
10281
+ return this._collectValue(arg2, previous);
10282
10282
  }
10283
- return arg;
10283
+ return arg2;
10284
10284
  };
10285
10285
  return this;
10286
10286
  }
@@ -10303,9 +10303,9 @@ var Argument = class {
10303
10303
  return this;
10304
10304
  }
10305
10305
  };
10306
- function humanReadableArgName(arg) {
10307
- const nameOutput = arg.name() + (arg.variadic === true ? "..." : "");
10308
- return arg.required ? "<" + nameOutput + ">" : "[" + nameOutput + "]";
10306
+ function humanReadableArgName(arg2) {
10307
+ const nameOutput = arg2.name() + (arg2.variadic === true ? "..." : "");
10308
+ return arg2.required ? "<" + nameOutput + ">" : "[" + nameOutput + "]";
10309
10309
  }
10310
10310
 
10311
10311
  // node_modules/commander/lib/command.js
@@ -10442,7 +10442,7 @@ var Help = class {
10442
10442
  * @returns {string}
10443
10443
  */
10444
10444
  subcommandTerm(cmd) {
10445
- const args = cmd.registeredArguments.map((arg) => humanReadableArgName(arg)).join(" ");
10445
+ const args = cmd.registeredArguments.map((arg2) => humanReadableArgName(arg2)).join(" ");
10446
10446
  return cmd._name + (cmd._aliases[0] ? "|" + cmd._aliases[0] : "") + (cmd.options.length ? " [options]" : "") + // simplistic check for non-help option
10447
10447
  (args ? " " + args : "");
10448
10448
  }
@@ -10964,8 +10964,8 @@ var Option = class {
10964
10964
  * @param {*} arg
10965
10965
  * @return {Option}
10966
10966
  */
10967
- preset(arg) {
10968
- this.presetArg = arg;
10967
+ preset(arg2) {
10968
+ this.presetArg = arg2;
10969
10969
  return this;
10970
10970
  }
10971
10971
  /**
@@ -11065,16 +11065,16 @@ var Option = class {
11065
11065
  */
11066
11066
  choices(values) {
11067
11067
  this.argChoices = values.slice();
11068
- this.parseArg = (arg, previous) => {
11069
- if (!this.argChoices.includes(arg)) {
11068
+ this.parseArg = (arg2, previous) => {
11069
+ if (!this.argChoices.includes(arg2)) {
11070
11070
  throw new InvalidArgumentError(
11071
11071
  `Allowed choices are ${this.argChoices.join(", ")}.`
11072
11072
  );
11073
11073
  }
11074
11074
  if (this.variadic) {
11075
- return this._collectValue(arg, previous);
11075
+ return this._collectValue(arg2, previous);
11076
11076
  }
11077
- return arg;
11077
+ return arg2;
11078
11078
  };
11079
11079
  return this;
11080
11080
  }
@@ -11118,8 +11118,8 @@ var Option = class {
11118
11118
  * @return {boolean}
11119
11119
  * @package
11120
11120
  */
11121
- is(arg) {
11122
- return this.short === arg || this.long === arg;
11121
+ is(arg2) {
11122
+ return this.short === arg2 || this.long === arg2;
11123
11123
  }
11124
11124
  /**
11125
11125
  * Return whether a boolean option.
@@ -12455,9 +12455,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
12455
12455
  * @private
12456
12456
  */
12457
12457
  _checkNumberOfArguments() {
12458
- this.registeredArguments.forEach((arg, i) => {
12459
- if (arg.required && this.args[i] == null) {
12460
- this.missingArgument(arg.name());
12458
+ this.registeredArguments.forEach((arg2, i) => {
12459
+ if (arg2.required && this.args[i] == null) {
12460
+ this.missingArgument(arg2.name());
12461
12461
  }
12462
12462
  });
12463
12463
  if (this.registeredArguments.length > 0 && this.registeredArguments[this.registeredArguments.length - 1].variadic) {
@@ -12668,8 +12668,8 @@ Expecting one of '${allowedValues.join("', '")}'`);
12668
12668
  * @return {Option}
12669
12669
  * @package
12670
12670
  */
12671
- _findOption(arg) {
12672
- return this.options.find((option) => option.is(arg));
12671
+ _findOption(arg2) {
12672
+ return this.options.find((option) => option.is(arg2));
12673
12673
  }
12674
12674
  /**
12675
12675
  * Display an error message if a mandatory option does not have a value.
@@ -12743,11 +12743,11 @@ Expecting one of '${allowedValues.join("', '")}'`);
12743
12743
  const operands = [];
12744
12744
  const unknown = [];
12745
12745
  let dest = operands;
12746
- function maybeOption(arg) {
12747
- return arg.length > 1 && arg[0] === "-";
12746
+ function maybeOption(arg2) {
12747
+ return arg2.length > 1 && arg2[0] === "-";
12748
12748
  }
12749
- const negativeNumberArg = (arg) => {
12750
- if (!/^-(\d+|\d*\.\d+)(e[+-]?\d+)?$/.test(arg)) return false;
12749
+ const negativeNumberArg = (arg2) => {
12750
+ if (!/^-(\d+|\d*\.\d+)(e[+-]?\d+)?$/.test(arg2)) return false;
12751
12751
  return !this._getCommandAndAncestors().some(
12752
12752
  (cmd) => cmd.options.map((opt) => opt.short).some((short3) => /^-\d$/.test(short3))
12753
12753
  );
@@ -12756,20 +12756,20 @@ Expecting one of '${allowedValues.join("', '")}'`);
12756
12756
  let activeGroup = null;
12757
12757
  let i = 0;
12758
12758
  while (i < args.length || activeGroup) {
12759
- const arg = activeGroup ?? args[i++];
12759
+ const arg2 = activeGroup ?? args[i++];
12760
12760
  activeGroup = null;
12761
- if (arg === "--") {
12762
- if (dest === unknown) dest.push(arg);
12761
+ if (arg2 === "--") {
12762
+ if (dest === unknown) dest.push(arg2);
12763
12763
  dest.push(...args.slice(i));
12764
12764
  break;
12765
12765
  }
12766
- if (activeVariadicOption && (!maybeOption(arg) || negativeNumberArg(arg))) {
12767
- this.emit(`option:${activeVariadicOption.name()}`, arg);
12766
+ if (activeVariadicOption && (!maybeOption(arg2) || negativeNumberArg(arg2))) {
12767
+ this.emit(`option:${activeVariadicOption.name()}`, arg2);
12768
12768
  continue;
12769
12769
  }
12770
12770
  activeVariadicOption = null;
12771
- if (maybeOption(arg)) {
12772
- const option = this._findOption(arg);
12771
+ if (maybeOption(arg2)) {
12772
+ const option = this._findOption(arg2);
12773
12773
  if (option) {
12774
12774
  if (option.required) {
12775
12775
  const value = args[i++];
@@ -12788,47 +12788,47 @@ Expecting one of '${allowedValues.join("', '")}'`);
12788
12788
  continue;
12789
12789
  }
12790
12790
  }
12791
- if (arg.length > 2 && arg[0] === "-" && arg[1] !== "-") {
12792
- const option = this._findOption(`-${arg[1]}`);
12791
+ if (arg2.length > 2 && arg2[0] === "-" && arg2[1] !== "-") {
12792
+ const option = this._findOption(`-${arg2[1]}`);
12793
12793
  if (option) {
12794
12794
  if (option.required || option.optional && this._combineFlagAndOptionalValue) {
12795
- this.emit(`option:${option.name()}`, arg.slice(2));
12795
+ this.emit(`option:${option.name()}`, arg2.slice(2));
12796
12796
  } else {
12797
12797
  this.emit(`option:${option.name()}`);
12798
- activeGroup = `-${arg.slice(2)}`;
12798
+ activeGroup = `-${arg2.slice(2)}`;
12799
12799
  }
12800
12800
  continue;
12801
12801
  }
12802
12802
  }
12803
- if (/^--[^=]+=/.test(arg)) {
12804
- const index = arg.indexOf("=");
12805
- const option = this._findOption(arg.slice(0, index));
12803
+ if (/^--[^=]+=/.test(arg2)) {
12804
+ const index = arg2.indexOf("=");
12805
+ const option = this._findOption(arg2.slice(0, index));
12806
12806
  if (option && (option.required || option.optional)) {
12807
- this.emit(`option:${option.name()}`, arg.slice(index + 1));
12807
+ this.emit(`option:${option.name()}`, arg2.slice(index + 1));
12808
12808
  continue;
12809
12809
  }
12810
12810
  }
12811
- if (dest === operands && maybeOption(arg) && !(this.commands.length === 0 && negativeNumberArg(arg))) {
12811
+ if (dest === operands && maybeOption(arg2) && !(this.commands.length === 0 && negativeNumberArg(arg2))) {
12812
12812
  dest = unknown;
12813
12813
  }
12814
12814
  if ((this._enablePositionalOptions || this._passThroughOptions) && operands.length === 0 && unknown.length === 0) {
12815
- if (this._findCommand(arg)) {
12816
- operands.push(arg);
12815
+ if (this._findCommand(arg2)) {
12816
+ operands.push(arg2);
12817
12817
  unknown.push(...args.slice(i));
12818
12818
  break;
12819
- } else if (this._getHelpCommand() && arg === this._getHelpCommand().name()) {
12820
- operands.push(arg, ...args.slice(i));
12819
+ } else if (this._getHelpCommand() && arg2 === this._getHelpCommand().name()) {
12820
+ operands.push(arg2, ...args.slice(i));
12821
12821
  break;
12822
12822
  } else if (this._defaultCommandName) {
12823
- unknown.push(arg, ...args.slice(i));
12823
+ unknown.push(arg2, ...args.slice(i));
12824
12824
  break;
12825
12825
  }
12826
12826
  }
12827
12827
  if (this._passThroughOptions) {
12828
- dest.push(arg, ...args.slice(i));
12828
+ dest.push(arg2, ...args.slice(i));
12829
12829
  break;
12830
12830
  }
12831
- dest.push(arg);
12831
+ dest.push(arg2);
12832
12832
  }
12833
12833
  return { operands, unknown };
12834
12834
  }
@@ -13156,8 +13156,8 @@ Expecting one of '${allowedValues.join("', '")}'`);
13156
13156
  usage(str2) {
13157
13157
  if (str2 === void 0) {
13158
13158
  if (this._usage) return this._usage;
13159
- const args = this.registeredArguments.map((arg) => {
13160
- return humanReadableArgName(arg);
13159
+ const args = this.registeredArguments.map((arg2) => {
13160
+ return humanReadableArgName(arg2);
13161
13161
  });
13162
13162
  return [].concat(
13163
13163
  this.options.length || this._helpOption !== null ? "[options]" : [],
@@ -13479,7 +13479,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
13479
13479
  */
13480
13480
  _outputHelpIfRequested(args) {
13481
13481
  const helpOption = this._getHelpOption();
13482
- const helpRequested = helpOption && args.find((arg) => helpOption.is(arg));
13482
+ const helpRequested = helpOption && args.find((arg2) => helpOption.is(arg2));
13483
13483
  if (helpRequested) {
13484
13484
  this.outputHelp();
13485
13485
  this._exit(0, "commander.helpDisplayed", "(outputHelp)");
@@ -13487,24 +13487,24 @@ Expecting one of '${allowedValues.join("', '")}'`);
13487
13487
  }
13488
13488
  };
13489
13489
  function incrementNodeInspectorPort(args) {
13490
- return args.map((arg) => {
13491
- if (!arg.startsWith("--inspect")) {
13492
- return arg;
13490
+ return args.map((arg2) => {
13491
+ if (!arg2.startsWith("--inspect")) {
13492
+ return arg2;
13493
13493
  }
13494
13494
  let debugOption;
13495
13495
  let debugHost = "127.0.0.1";
13496
13496
  let debugPort = "9229";
13497
13497
  let match;
13498
- if ((match = arg.match(/^(--inspect(-brk)?)$/)) !== null) {
13498
+ if ((match = arg2.match(/^(--inspect(-brk)?)$/)) !== null) {
13499
13499
  debugOption = match[1];
13500
- } else if ((match = arg.match(/^(--inspect(-brk|-port)?)=([^:]+)$/)) !== null) {
13500
+ } else if ((match = arg2.match(/^(--inspect(-brk|-port)?)=([^:]+)$/)) !== null) {
13501
13501
  debugOption = match[1];
13502
13502
  if (/^\d+$/.test(match[3])) {
13503
13503
  debugPort = match[3];
13504
13504
  } else {
13505
13505
  debugHost = match[3];
13506
13506
  }
13507
- } else if ((match = arg.match(/^(--inspect(-brk|-port)?)=([^:]+):(\d+)$/)) !== null) {
13507
+ } else if ((match = arg2.match(/^(--inspect(-brk|-port)?)=([^:]+):(\d+)$/)) !== null) {
13508
13508
  debugOption = match[1];
13509
13509
  debugHost = match[3];
13510
13510
  debugPort = match[4];
@@ -13512,7 +13512,7 @@ function incrementNodeInspectorPort(args) {
13512
13512
  if (debugOption && debugPort !== "0") {
13513
13513
  return `${debugOption}=${debugHost}:${parseInt(debugPort) + 1}`;
13514
13514
  }
13515
- return arg;
13515
+ return arg2;
13516
13516
  });
13517
13517
  }
13518
13518
  function useColor() {
@@ -13527,7 +13527,7 @@ function useColor() {
13527
13527
  var program = new Command();
13528
13528
 
13529
13529
  // src/command-composition.ts
13530
- var import_node_fs66 = require("node:fs");
13530
+ var import_node_fs67 = require("node:fs");
13531
13531
  init_clean_exit();
13532
13532
  init_cli_shared();
13533
13533
 
@@ -15195,7 +15195,7 @@ function resolveVerbAliasShim(argv) {
15195
15195
 
15196
15196
  // src/command-composition.ts
15197
15197
  var import_node_os28 = require("node:os");
15198
- var import_node_path63 = require("node:path");
15198
+ var import_node_path64 = require("node:path");
15199
15199
 
15200
15200
  // src/board-read.ts
15201
15201
  var import_node_fs18 = require("node:fs");
@@ -15495,7 +15495,7 @@ function setStatusWriteTokenProvider(provider) {
15495
15495
  statusWriteTokenProvider = provider;
15496
15496
  }
15497
15497
  async function fleetStatusWriteEnv(args) {
15498
- if (args[0] !== "api" || args[1] !== "-X" || args[2] !== "POST" || !/^repos\/[^/]+\/[^/]+\/statuses\/[^/]+$/.test(args[3] ?? "") || !args.some((arg, i) => arg === "context=fleet-lockstep" && args[i - 1] === "-f")) return void 0;
15498
+ if (args[0] !== "api" || args[1] !== "-X" || args[2] !== "POST" || !/^repos\/[^/]+\/[^/]+\/statuses\/[^/]+$/.test(args[3] ?? "") || !args.some((arg2, i) => arg2 === "context=fleet-lockstep" && args[i - 1] === "-f")) return void 0;
15499
15499
  if (!statusWriteTokenProvider) throw new AppActorError("app actor: status-write provider not installed");
15500
15500
  try {
15501
15501
  const { token } = await statusWriteTokenProvider();
@@ -16482,7 +16482,7 @@ async function readRestPrSnapshotWithRetry(prNumber, repo, gh2 = defaultGhApi, o
16482
16482
  const retries = options?.retries ?? PR_SNAPSHOT_READ_RETRIES;
16483
16483
  const untilMs = options?.retryTransientUntilMs;
16484
16484
  const delayMs = options?.delayMs ?? (untilMs !== void 0 ? PR_CHECKS_POLL_MS : PR_SNAPSHOT_READ_DELAY_MS);
16485
- const sleep2 = options?.sleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms)));
16485
+ const sleep2 = options?.sleep ?? ((ms) => new Promise((resolve8) => setTimeout(resolve8, ms)));
16486
16486
  const now = options?.now ?? (() => Date.now());
16487
16487
  let lastError = "no attempt completed";
16488
16488
  let attempt = 0;
@@ -16512,7 +16512,7 @@ var PR_LAND_PINNED_HEAD_READ_BUDGET_MS = 6e4;
16512
16512
  var PR_LAND_PINNED_HEAD_READ_404_ATTEMPTS = 3;
16513
16513
  async function readPrLandPinnedHeadSha(prNumber, repo, gh2 = defaultGhApi, options) {
16514
16514
  const delayMs = options?.delayMs ?? PR_SNAPSHOT_READ_DELAY_MS;
16515
- const sleep2 = options?.sleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms)));
16515
+ const sleep2 = options?.sleep ?? ((ms) => new Promise((resolve8) => setTimeout(resolve8, ms)));
16516
16516
  let notFound = 0;
16517
16517
  for (; ; ) {
16518
16518
  const read = await readRestPrSnapshotWithRetry(prNumber, repo, gh2, {
@@ -18327,9 +18327,9 @@ function extractWorkflowCrons(yamlText) {
18327
18327
  function workflowEntry(repo, workflowPath, yamlText) {
18328
18328
  const crons = extractWorkflowCrons(yamlText);
18329
18329
  if (!crons.length) return null;
18330
- const basename5 = workflowPath.split("/").pop() ?? workflowPath;
18330
+ const basename6 = workflowPath.split("/").pop() ?? workflowPath;
18331
18331
  return {
18332
- name: `${repo}/${basename5.replace(/\.ya?ml$/, "")}`,
18332
+ name: `${repo}/${basename6.replace(/\.ya?ml$/, "")}`,
18333
18333
  cadence: crons.join(" + "),
18334
18334
  executor: "github-actions",
18335
18335
  llm: llmFromHeader(yamlText),
@@ -18663,8 +18663,8 @@ function scheduleRecordFromWorkflow(repo, workflowPath, yamlText) {
18663
18663
  const crons = extractWorkflowCrons(yamlText);
18664
18664
  const header = parseScheduleHeader(yamlText);
18665
18665
  if (!crons.length && !header.schedule) return null;
18666
- const basename5 = workflowPath.split("/").pop() ?? workflowPath;
18667
- const expectedId = `${repo}/${basename5.replace(/\.ya?ml$/, "")}`;
18666
+ const basename6 = workflowPath.split("/").pop() ?? workflowPath;
18667
+ const expectedId = `${repo}/${basename6.replace(/\.ya?ml$/, "")}`;
18668
18668
  if (isHarbourUnmanaged(yamlText)) return null;
18669
18669
  const missing = SCHEDULE_HEADER_FIELDS.filter((f) => !header[f]);
18670
18670
  if (missing.length) {
@@ -20851,7 +20851,7 @@ async function createPrViaRestFallback(args, swappedArgs, deps, knownPools) {
20851
20851
  }
20852
20852
  async function ghCreate(args, deps = {}) {
20853
20853
  const exec3 = deps.exec ?? execFileP;
20854
- const sleep2 = deps.sleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms)));
20854
+ const sleep2 = deps.sleep ?? ((ms) => new Promise((resolve8) => setTimeout(resolve8, ms)));
20855
20855
  const now = deps.now ?? Date.now;
20856
20856
  const read = deps.readFile ?? import_promises.readFile;
20857
20857
  const restCreatePr = deps.restCreatePr ?? ((input) => defaultRestCreatePr(exec3, input));
@@ -21660,8 +21660,8 @@ function resolveUseEnvNames(keys, name) {
21660
21660
  }
21661
21661
  return { ok: true, entries };
21662
21662
  }
21663
- function referencesDollarEnv(arg, name) {
21664
- return arg.includes(`\${${name}}`) || new RegExp(`\\$${name}(?![A-Za-z0-9_])`).test(arg);
21663
+ function referencesDollarEnv(arg2, name) {
21664
+ return arg2.includes(`\${${name}}`) || new RegExp(`\\$${name}(?![A-Za-z0-9_])`).test(arg2);
21665
21665
  }
21666
21666
  function isShellScriptCommand(command) {
21667
21667
  const exe = (command[0] ?? "").split(/[/\\]/).pop()?.toLowerCase().replace(/\.exe$/, "") ?? "";
@@ -21669,9 +21669,9 @@ function isShellScriptCommand(command) {
21669
21669
  }
21670
21670
  function secretsUseDollarHint(command, envNames) {
21671
21671
  if (isShellScriptCommand(command)) return null;
21672
- for (const arg of command) {
21672
+ for (const arg2 of command) {
21673
21673
  for (const name of envNames) {
21674
- if (!referencesDollarEnv(arg, name)) continue;
21674
+ if (!referencesDollarEnv(arg2, name)) continue;
21675
21675
  return `secrets use: ${command[0]} receives the literal text $${name} \u2014 the value is injected into the CHILD's env, and ${command[0]} does not expand variables in its arguments. Wrap the consumer in a shell so expansion happens inside: bash -c 'your-command "$${name}"'`;
21676
21676
  }
21677
21677
  }
@@ -21681,8 +21681,8 @@ var PRE_SPAWN_DRAIN_TIMEOUT_MS = 2e3;
21681
21681
  async function drainHttpPoolBeforeSpawn() {
21682
21682
  const drained = await Promise.race([
21683
21683
  closeHttpPool().then(() => true),
21684
- new Promise((resolve7) => {
21685
- setTimeout(() => resolve7(false), PRE_SPAWN_DRAIN_TIMEOUT_MS).unref?.();
21684
+ new Promise((resolve8) => {
21685
+ setTimeout(() => resolve8(false), PRE_SPAWN_DRAIN_TIMEOUT_MS).unref?.();
21686
21686
  })
21687
21687
  ]);
21688
21688
  if (!drained) destroyHttpPool();
@@ -24653,7 +24653,7 @@ async function setBoardItemPriority(client, cfg, itemId, priority) {
24653
24653
  await updateItemSingleSelect(client, cfg.projectId, itemId, cfg.priorityFieldId, optionId);
24654
24654
  return cliPriorityToFieldName(priority);
24655
24655
  }
24656
- var defaultRetrySleep = (ms) => new Promise((resolve7) => setTimeout(resolve7, ms));
24656
+ var defaultRetrySleep = (ms) => new Promise((resolve8) => setTimeout(resolve8, ms));
24657
24657
  async function resolveProjectItemIdWithRetry(client, cfg, selector, opts = {}) {
24658
24658
  const attempts = Math.max(1, opts.attempts ?? 5);
24659
24659
  const delayMs = opts.delayMs ?? 300;
@@ -25243,6 +25243,9 @@ var CMD_RE = /`mmi-cli ((?:[a-z][a-z-]*)(?: [a-z][a-z-]*){0,3})/g;
25243
25243
  var RETIRED_RE = /\b(retired|historical|removed|deleted|gone|no longer|superseded|legacy)\b/i;
25244
25244
  var ROOT_DOCS = ["README.md", "architecture.md"];
25245
25245
  var SKIP_WALK = ["docs/decisions/"];
25246
+ function formatDocRefFinding(finding) {
25247
+ return `${finding.doc}:${finding.line} [${finding.kind}] ${finding.detail}${finding.suggest?.length ? ` (did you mean ${finding.suggest[0]}?)` : ""}`;
25248
+ }
25246
25249
  function refFirstSegment(ref) {
25247
25250
  return ref.replace(/^(\.\/)+/, "").split("/")[0];
25248
25251
  }
@@ -25663,21 +25666,14 @@ function defaultIsIgnored(root, relPaths, exec3 = import_node_child_process6.exe
25663
25666
  throw error;
25664
25667
  }
25665
25668
  }
25666
- function defaultTrackedFirstSegments(root, firstSegments, exec3 = import_node_child_process6.execFileSync) {
25667
- if (firstSegments.length === 0) return /* @__PURE__ */ new Set();
25669
+ function defaultTrackedFiles(root, firstSegments, exec3 = import_node_child_process6.execFileSync) {
25668
25670
  try {
25669
25671
  const out = exec3("git", ["ls-files", "-z", "--", ...firstSegments.map((s) => `:(literal)${s}`)], {
25670
25672
  cwd: root,
25671
25673
  encoding: "utf8",
25672
25674
  maxBuffer: CHECK_IGNORE_MAX_BUFFER
25673
25675
  });
25674
- const tracked = /* @__PURE__ */ new Set();
25675
- for (const path2 of out.split("\0")) {
25676
- if (path2) for (const segment of firstSegments) {
25677
- if (path2 === segment || path2.startsWith(`${segment}/`)) tracked.add(segment);
25678
- }
25679
- }
25680
- return tracked;
25676
+ return out.split("\0").filter(Boolean);
25681
25677
  } catch (error) {
25682
25678
  if (error?.status === 128) return null;
25683
25679
  if (error?.code === "ENOENT") return null;
@@ -25721,7 +25717,12 @@ function runDocRefs(root, deps = {}) {
25721
25717
  const exists = deps.exists ?? import_node_fs19.existsSync;
25722
25718
  const listDocs = deps.listDocs ?? defaultListDocs;
25723
25719
  const isIgnored = deps.isIgnored ?? ((paths) => defaultIsIgnored(root, paths));
25724
- const trackedFirstSegments = deps.trackedFirstSegments ?? ((segs) => defaultTrackedFirstSegments(root, segs));
25720
+ let inventory;
25721
+ const trackedFiles = () => inventory === void 0 ? inventory = deps.trackedFiles ? deps.trackedFiles() : deps.trackedFirstSegments ? null : defaultTrackedFiles(root, []) : inventory;
25722
+ const trackedFirstSegments = deps.trackedFirstSegments ?? ((segs) => {
25723
+ const files = trackedFiles();
25724
+ return files == null ? null : new Set(segs.filter((seg) => files.some((path2) => path2 === seg || path2.startsWith(`${seg}/`))));
25725
+ });
25725
25726
  const commandPaths = deps.commandPaths ?? null;
25726
25727
  const walked = listDocs(root);
25727
25728
  const ignoredDocs = walked.length ? isIgnored(walked) : /* @__PURE__ */ new Set();
@@ -25761,6 +25762,18 @@ ${sourceMessages}`;
25761
25762
  (override ? warnings : findings).push(...stale);
25762
25763
  if (!/^Seed-Runbook-Affected:[ \t]*\S.*$/m.test(allMessages)) findings.push(...seedStale);
25763
25764
  }
25765
+ for (const finding of findings) {
25766
+ if (finding.kind !== "missing-path") continue;
25767
+ const directory = import_node_path16.posix.dirname(import_node_path16.posix.normalize(finding.detail)).split("/");
25768
+ const distance = (path2) => {
25769
+ const parts = import_node_path16.posix.dirname(path2).split("/");
25770
+ let common = 0;
25771
+ while (common < directory.length && common < parts.length && directory[common] === parts[common]) common += 1;
25772
+ return directory.length + parts.length - 2 * common;
25773
+ };
25774
+ const suggest = [...new Set(trackedFiles() ?? [])].filter((path2) => import_node_path16.posix.basename(path2) === import_node_path16.posix.basename(finding.detail) && exists((0, import_node_path16.join)(root, path2))).sort((a, b) => distance(a) - distance(b) || a.localeCompare(b)).slice(0, 3);
25775
+ if (suggest.length) finding.suggest = suggest;
25776
+ }
25764
25777
  return {
25765
25778
  ok: findings.length === 0,
25766
25779
  findings,
@@ -28166,10 +28179,10 @@ var rollout_plan_default = {
28166
28179
  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)."
28167
28180
  },
28168
28181
  baseline: {
28169
- version: "4.6.24",
28170
- tag: "v4.6.24",
28171
- commit: "3632dffdf8a5",
28172
- npm: "@mutmutco/cli@4.6.24"
28182
+ version: "4.6.26",
28183
+ tag: "v4.6.26",
28184
+ commit: "bab0b3157d41",
28185
+ npm: "@mutmutco/cli@4.6.26"
28173
28186
  },
28174
28187
  exitCriterion: "fleet-n-of-n",
28175
28188
  hubOnlyShortcut: "forbidden",
@@ -28186,14 +28199,14 @@ var rollout_plan_default = {
28186
28199
  repo: "mutmutco/mmi-hub",
28187
28200
  role: "canary",
28188
28201
  schedule: "train",
28189
- v3Target: "v4.6.24"
28202
+ v3Target: "v4.6.26"
28190
28203
  }
28191
28204
  ],
28192
28205
  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.",
28193
28206
  rollback: {
28194
28207
  independent: true,
28195
- mechanism: "npm dist-tag latest -> 4.6.24 and redeploy the Hub Lambda from tag v4.6.24 (3632dffdf8a5); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
28196
- v3Target: "v4.6.24 (@mutmutco/cli@4.6.24, tag commit 3632dffdf8a5 \u2014 last known-good release carrying the repo-index v4-only contract)"
28208
+ mechanism: "npm dist-tag latest -> 4.6.26 and redeploy the Hub Lambda from tag v4.6.26 (bab0b3157d41); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
28209
+ v3Target: "v4.6.26 (@mutmutco/cli@4.6.26, tag commit bab0b3157d41 \u2014 last known-good release carrying the repo-index v4-only contract)"
28197
28210
  }
28198
28211
  },
28199
28212
  {
@@ -30288,7 +30301,7 @@ async function runMergeTreePreflight(deps, ours, theirs) {
30288
30301
  async function predictMergeConflicts(deps, ours, theirs) {
30289
30302
  return runMergeTreePreflight(deps, ours, theirs);
30290
30303
  }
30291
- async function mergeWithToleratedResolution(deps, sourceRef, label, resolve7, extraTolerated = []) {
30304
+ async function mergeWithToleratedResolution(deps, sourceRef, label, resolve8, extraTolerated = []) {
30292
30305
  try {
30293
30306
  await deps.run("git", ["merge", sourceRef, "--no-edit"]);
30294
30307
  return;
@@ -30302,7 +30315,7 @@ async function mergeWithToleratedResolution(deps, sourceRef, label, resolve7, ex
30302
30315
  unmerged.length === 0 ? `${label} merge failed without conflicted paths \u2014 merge aborted; inspect the repo state and rerun` : `${label} merge conflicts on untolerated path(s): ${blocking.join(", ")} \u2014 merge aborted (the train is misaligned; reconcile the branches via an approved alignment PR, then rerun)`
30303
30316
  );
30304
30317
  }
30305
- await deps.run("git", ["checkout", `--${resolve7}`, "--", ...unmerged]);
30318
+ await deps.run("git", ["checkout", `--${resolve8}`, "--", ...unmerged]);
30306
30319
  await deps.run("git", ["add", "--", ...unmerged]);
30307
30320
  await deps.run("git", ["commit", "--no-edit"]);
30308
30321
  }
@@ -30500,7 +30513,7 @@ var CORRELATE_SKEW_SLACK_MS = 1e4;
30500
30513
  var CORRELATE_PAGE_LIMIT = 50;
30501
30514
  var RUN_CONFIRM_ATTEMPTS = 3;
30502
30515
  var RUN_CONFIRM_DELAY_MS = 1e3;
30503
- var defaultSleep = (ms) => new Promise((resolve7) => setTimeout(resolve7, ms));
30516
+ var defaultSleep = (ms) => new Promise((resolve8) => setTimeout(resolve8, ms));
30504
30517
  function resolveSleep(deps) {
30505
30518
  return deps.sleep ?? defaultSleep;
30506
30519
  }
@@ -32391,7 +32404,7 @@ async function discoverShaWorkflowRuns(deps, repo, headSha, seenRunIds) {
32391
32404
  }
32392
32405
  return extra;
32393
32406
  }
32394
- async function dispatchDeploy(deps, ctx, stage, ref, model, watch, autoRunSince, autoRunHeadSha, dispatchFailure = "throw", publishDir) {
32407
+ async function dispatchDeploy(deps, ctx, stage, ref, model, watch, autoRunSince, autoRunHeadSha, dispatchFailure = "throw", publishDir, rollback = false) {
32395
32408
  if (validSuiteCutContext(ctx.repo, deps.suiteCut) && stage !== "dev") {
32396
32409
  return { note: "suite bundle-only: live backend not deployed", deployStatus: "success" };
32397
32410
  }
@@ -32399,7 +32412,7 @@ async function dispatchDeploy(deps, ctx, stage, ref, model, watch, autoRunSince,
32399
32412
  deps.warn?.("Release: Starting deployment");
32400
32413
  const since = (deps.now ?? Date.now)();
32401
32414
  try {
32402
- await dispatchTenantDeployWithRetry(deps, { repo: ctx.repo, slug: ctx.slug, ref, stage });
32415
+ await dispatchTenantDeployWithRetry(deps, { repo: ctx.repo, slug: ctx.slug, ref, stage, ...rollback ? { rollback: true } : {} });
32403
32416
  } catch (e) {
32404
32417
  if (dispatchFailure === "throw") throw e;
32405
32418
  const msg = e instanceof Error ? e.message : String(e);
@@ -32484,19 +32497,19 @@ async function buildEnvironments(deps, ctx, model, deployStatus, retirement) {
32484
32497
  const mainDomains = domains?.main;
32485
32498
  const rcDomains = domains?.rc;
32486
32499
  const healthStatus = deployStatus === "success" ? "success" : deployStatus === "failure" ? "failure" : "pending";
32487
- const main = { healthStatus };
32500
+ const main2 = { healthStatus };
32488
32501
  if (mainDomains?.length) {
32489
- main.domains = mainDomains;
32490
- main.healthUrl = `https://${mainDomains[0]}/`;
32502
+ main2.domains = mainDomains;
32503
+ main2.healthUrl = `https://${mainDomains[0]}/`;
32491
32504
  }
32492
32505
  const rc = { retirement: retirement.status };
32493
32506
  if (retirement.category) rc.retirementCategory = retirement.category;
32494
32507
  if (rcDomains?.length) rc.domains = rcDomains;
32495
32508
  if (domainsRead === "failed") {
32496
- main.domainsRead = "failed";
32509
+ main2.domainsRead = "failed";
32497
32510
  rc.domainsRead = "failed";
32498
32511
  }
32499
- return { main, rc };
32512
+ return { main: main2, rc };
32500
32513
  }
32501
32514
  var RETIRE_MAX_ATTEMPTS = 3;
32502
32515
  var RETIRE_BACKOFF_MS = 1500;
@@ -32577,14 +32590,27 @@ async function runTenantRedeploy(deps, options) {
32577
32590
  const meta = requireProjectMetaForTrain(await loadProjectMeta(deps, ctx), repo);
32578
32591
  const deployModel = requireDeployModel(meta, repo);
32579
32592
  const singleTrackMain = stage === "main" && meta.releaseTrack === "single";
32580
- if (singleTrackMain && options.ref === "main") {
32581
- throw new Error(`${repo} is single-track: its \`main\` branch is stale, so --ref main would roll main back. Pin --ref <last good deployed SHA or development head>, or omit --ref to deploy development.`);
32593
+ if (options.rollback && !options.ref) throw new Error("--rollback requires --ref");
32594
+ const deployed = await deps.readDeployedSha?.(ctx.slug, stage).catch(() => void 0);
32595
+ let ref = options.ref ?? deployed ?? (stage === "dev" || singleTrackMain ? "development" : stage);
32596
+ if (!deployed) {
32597
+ deps.warn?.(`Serving DEPLOY#${stage} stamp unreadable or absent; falling back to ${ref}.`);
32598
+ } else if (options.ref) {
32599
+ if (!deps.compareDeployRef) throw new Error("Deploy ancestry comparison unavailable");
32600
+ const relation = await deps.compareDeployRef(repo, deployed, options.ref);
32601
+ if (!["ahead", "identical", "behind", "diverged"].includes(relation)) throw new Error("Invalid deploy ancestry comparison");
32602
+ if (relation === "behind") {
32603
+ if (options.rollback) deps.warn?.(`rolling back ${stage} from ${deployed} to ${options.ref}`);
32604
+ else {
32605
+ deps.warn?.(`${options.ref} is older than the serving release ${deployed}; redeploying the serving SHA instead (use --rollback for a deliberate rollback).`);
32606
+ ref = deployed;
32607
+ }
32608
+ }
32582
32609
  }
32583
- const ref = options.ref ?? (stage === "dev" || singleTrackMain ? "development" : stage);
32584
32610
  if (!isCentralDispatchModel(deployModel)) {
32585
32611
  throw new Error(`${repo} is ${deployModel}, not a centrally-dispatched model (tenant-container/solo-container/static-cdn) \u2014 there is no central tenant-deploy run to retry (its deploy fires from its own workflow)`);
32586
32612
  }
32587
- const d = await dispatchDeploy(deps, ctx, stage, ref, deployModel, watch);
32613
+ const d = await dispatchDeploy(deps, ctx, stage, ref, deployModel, watch, void 0, void 0, "throw", void 0, options.rollback);
32588
32614
  return { ...ctx, command: "tenant-redeploy", stage, ref, deployModel, dispatch: d.note, runId: d.runId, runUrl: d.runUrl, workflowRuns: d.workflowRuns, deployStatus: d.deployStatus };
32589
32615
  }
32590
32616
  async function runTenantReconcile(deps, options) {
@@ -33804,7 +33830,7 @@ function lockTokenPid(token) {
33804
33830
  const m = /^(\d+)-/.exec(token);
33805
33831
  return m ? Number(m[1]) : void 0;
33806
33832
  }
33807
- var sleep = (ms) => new Promise((resolve7) => setTimeout(resolve7, ms));
33833
+ var sleep = (ms) => new Promise((resolve8) => setTimeout(resolve8, ms));
33808
33834
  var IMMEDIATE_RETRY_BUDGET = 3;
33809
33835
  var FileLockBusyError = class extends Error {
33810
33836
  lockPath;
@@ -34694,7 +34720,7 @@ async function defaultWatchRun(deps, runId, repo) {
34694
34720
  watchSaidSuccess = false;
34695
34721
  }
34696
34722
  for (let attempt = 0; attempt < RUN_CONFIRM_ATTEMPTS2; attempt++) {
34697
- if (attempt > 0) await new Promise((resolve7) => setTimeout(resolve7, RUN_CONFIRM_DELAY_MS2));
34723
+ if (attempt > 0) await new Promise((resolve8) => setTimeout(resolve8, RUN_CONFIRM_DELAY_MS2));
34698
34724
  try {
34699
34725
  const parsed = JSON.parse(await deps.run("gh", ["run", "view", String(runId), "--repo", repo, "--json", "status,conclusion"]));
34700
34726
  if (parsed.status === "completed") return parsed.conclusion === "success" ? "success" : "failure";
@@ -35758,11 +35784,11 @@ var defaultDeps = {
35758
35784
  // #5813: the caller supplies that command line. `process.argv` is NOT it — the house shim splices
35759
35785
  // the house root out in place, so re-reading it here re-ran the removed flat alias (`release …`
35760
35786
  // instead of `devops release …`) and the converged child refused with exit 2.
35761
- reexec: (argv) => new Promise((resolve7) => {
35787
+ reexec: (argv) => new Promise((resolve8) => {
35762
35788
  const args = [...argv];
35763
35789
  const child2 = isWin2 ? (0, import_node_child_process8.spawn)("cmd.exe", ["/c", "mmi-cli", ...args], { stdio: "inherit", windowsHide: true }) : (0, import_node_child_process8.spawn)("mmi-cli", args, { stdio: "inherit", windowsHide: true });
35764
- child2.on("exit", (code) => resolve7(code ?? 1));
35765
- child2.on("error", () => resolve7(1));
35790
+ child2.on("exit", (code) => resolve8(code ?? 1));
35791
+ child2.on("error", () => resolve8(1));
35766
35792
  }),
35767
35793
  // stderr only — stdout may be carrying --json output.
35768
35794
  warn: (line) => console.error(line)
@@ -35919,7 +35945,7 @@ var defaultDeps2 = {
35919
35945
  }
35920
35946
  },
35921
35947
  registryWhoami: probeRegistryWhoami,
35922
- sleep: (ms) => new Promise((resolve7) => setTimeout(resolve7, ms)),
35948
+ sleep: (ms) => new Promise((resolve8) => setTimeout(resolve8, ms)),
35923
35949
  env: process.env
35924
35950
  };
35925
35951
  function message(e) {
@@ -41535,9 +41561,9 @@ function readCommonMistakes(cmd) {
41535
41561
  const notes = cmd[COMMON_MISTAKES];
41536
41562
  return Array.isArray(notes) && notes.length ? notes : void 0;
41537
41563
  }
41538
- function buildArgument(arg) {
41539
- const out = { name: arg.name(), required: arg.required, variadic: arg.variadic };
41540
- if (arg.description) out.description = arg.description;
41564
+ function buildArgument(arg2) {
41565
+ const out = { name: arg2.name(), required: arg2.required, variadic: arg2.variadic };
41566
+ if (arg2.description) out.description = arg2.description;
41541
41567
  return out;
41542
41568
  }
41543
41569
  function buildOption(opt) {
@@ -41767,9 +41793,9 @@ function buildDoorsCatalog(tree) {
41767
41793
  };
41768
41794
  });
41769
41795
  }
41770
- function argSignature(arg) {
41771
- const inner = arg.variadic ? `${arg.name}...` : arg.name;
41772
- return arg.required ? `<${inner}>` : `[${inner}]`;
41796
+ function argSignature(arg2) {
41797
+ const inner = arg2.variadic ? `${arg2.name}...` : arg2.name;
41798
+ return arg2.required ? `<${inner}>` : `[${inner}]`;
41773
41799
  }
41774
41800
  function formatManifestHuman(manifest, options = {}) {
41775
41801
  const root = options.all ? manifest.tree : manifest.primary_tree;
@@ -42190,7 +42216,7 @@ async function updatePrHeadFromBase(input) {
42190
42216
  } catch (e) {
42191
42217
  throw new Error(`GitHub could not update ${input.head} from ${input.base} (${e.message.trim()}) \u2014 ${remedy}`);
42192
42218
  }
42193
- const sleep2 = input.sleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms)));
42219
+ const sleep2 = input.sleep ?? ((ms) => new Promise((resolve8) => setTimeout(resolve8, ms)));
42194
42220
  for (let attempt = 0; attempt < PR_HEAD_UPDATE_API_READ_RETRIES; attempt++) {
42195
42221
  const to = await readHead2();
42196
42222
  if (to && to !== from) return { from, to, base: input.base, via: "update-branch-api" };
@@ -42213,7 +42239,7 @@ var PR_LAND_MERGE_RETRY_DELAY_MS = 3e4;
42213
42239
  async function mergeAutoWithTransientRetry(prNumber, repo, deps) {
42214
42240
  const now = deps.now ?? (() => Date.now());
42215
42241
  const deadline = now() + PR_LAND_ENQUEUE_TIMEOUT_MS;
42216
- const sleep2 = deps.sleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms)));
42242
+ const sleep2 = deps.sleep ?? ((ms) => new Promise((resolve8) => setTimeout(resolve8, ms)));
42217
42243
  const first = await deps.mergeAuto(prNumber, repo);
42218
42244
  let result = first;
42219
42245
  let transientRetried = false;
@@ -42252,7 +42278,7 @@ var AUTO_MERGE_CONFIRM_DELAY_MS = 15e3;
42252
42278
  async function confirmAutoMergeEnqueued(deps, options) {
42253
42279
  const retries = options?.retries ?? AUTO_MERGE_CONFIRM_RETRIES;
42254
42280
  const delayMs = options?.delayMs ?? AUTO_MERGE_CONFIRM_DELAY_MS;
42255
- const sleep2 = deps.sleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms)));
42281
+ const sleep2 = deps.sleep ?? ((ms) => new Promise((resolve8) => setTimeout(resolve8, ms)));
42256
42282
  for (let attempt = 0; attempt < retries; attempt++) {
42257
42283
  if (await deps.readMerged().catch(() => false)) return "merged";
42258
42284
  const stuck = await deps.readAutoMergeRequest().then((s) => s.trim()).catch(() => "");
@@ -42269,7 +42295,7 @@ async function confirmAutoMergeEnqueued(deps, options) {
42269
42295
  async function readGhPrStateWithRetry(fetchState, options) {
42270
42296
  const retries = options?.retries ?? PR_LAND_STATE_READ_RETRIES;
42271
42297
  const delayMs = options?.delayMs ?? PR_LAND_STATE_READ_DELAY_MS;
42272
- const sleep2 = options?.sleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms)));
42298
+ const sleep2 = options?.sleep ?? ((ms) => new Promise((resolve8) => setTimeout(resolve8, ms)));
42273
42299
  let lastError = "empty state";
42274
42300
  for (let attempt = 0; attempt < retries; attempt++) {
42275
42301
  try {
@@ -42421,7 +42447,7 @@ async function runPrLandOnce(prNumber, options, deps) {
42421
42447
  if (read.isInMergeQueue || read.state === "MERGED") confirmed = read;
42422
42448
  }
42423
42449
  if (!confirmed) {
42424
- await (deps.sleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms))))(deps.pollDelayMs?.(0) ?? PR_LAND_POLL_MS);
42450
+ await (deps.sleep ?? ((ms) => new Promise((resolve8) => setTimeout(resolve8, ms))))(deps.pollDelayMs?.(0) ?? PR_LAND_POLL_MS);
42425
42451
  }
42426
42452
  return pollPrMergeQueue(prNumber, options, deps, base, confirmed, deadline);
42427
42453
  }
@@ -42460,7 +42486,7 @@ function queueMerged(base, deps) {
42460
42486
  }
42461
42487
  async function pollPrMergeQueue(pr, options, deps, base, snapshot, deadlineMs) {
42462
42488
  const now = deps.now ?? (() => Date.now());
42463
- const sleep2 = deps.sleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms)));
42489
+ const sleep2 = deps.sleep ?? ((ms) => new Promise((resolve8) => setTimeout(resolve8, ms)));
42464
42490
  const timeoutMs = options.queueTimeoutMs ?? PR_LAND_QUEUE_TIMEOUT_MS;
42465
42491
  const deadline = deadlineMs ?? now() + timeoutMs;
42466
42492
  let attempt = 0;
@@ -43401,9 +43427,9 @@ function changedFilesSince(base, cwd, head) {
43401
43427
  const raw = git2(["diff", "--name-status", "-M", base, ...head ? [head] : [], "--"], cwd).trim();
43402
43428
  const changed = raw ? raw.split("\n").map((line) => {
43403
43429
  const parts = line.split(" ");
43404
- const norm2 = (p) => p.replace(/\\/g, "/");
43405
- const row = { status: parts[0][0], path: norm2(parts[parts.length - 1]) };
43406
- if (parts.length > 2) row.from = norm2(parts[1]);
43430
+ const norm3 = (p) => p.replace(/\\/g, "/");
43431
+ const row = { status: parts[0][0], path: norm3(parts[parts.length - 1]) };
43432
+ if (parts.length > 2) row.from = norm3(parts[1]);
43407
43433
  return row;
43408
43434
  }) : [];
43409
43435
  if (head) return changed;
@@ -43681,7 +43707,7 @@ async function submitQueueAdmission(pr, repo, head, read, write, options, resume
43681
43707
  const rejected = (reason) => admissionRejected(reason, repo, pr);
43682
43708
  const reconcile = async (reason, recordEntry = false, resumingSaved = false) => {
43683
43709
  const maxReads = options.enqueueOnly ? 3 : 1;
43684
- const sleep3 = options.sleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms)));
43710
+ const sleep3 = options.sleep ?? ((ms) => new Promise((resolve8) => setTimeout(resolve8, ms)));
43685
43711
  for (let readAttempt = 0; readAttempt < maxReads; readAttempt++) {
43686
43712
  if (readAttempt) await sleep3(readAttempt * 1e3);
43687
43713
  try {
@@ -43836,7 +43862,7 @@ async function submitQueueAdmission(pr, repo, head, read, write, options, resume
43836
43862
  }
43837
43863
  receipt = { ...receipt, state: "pending", uuid: details.uuid };
43838
43864
  }
43839
- const sleep2 = options.sleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms)));
43865
+ const sleep2 = options.sleep ?? ((ms) => new Promise((resolve8) => setTimeout(resolve8, ms)));
43840
43866
  for (let attempt = 0; attempt < 3; attempt++) {
43841
43867
  if (attempt) await sleep2(attempt * 1e3);
43842
43868
  try {
@@ -44306,7 +44332,7 @@ function observeQueuedAdmission(repo, pr, snapshot, receiptDirectory) {
44306
44332
  var SETTLE_POLLS = 6;
44307
44333
  var SETTLE_MS = 5e3;
44308
44334
  async function settled(repo, id, deps) {
44309
- const sleep2 = deps.sleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms)));
44335
+ const sleep2 = deps.sleep ?? ((ms) => new Promise((resolve8) => setTimeout(resolve8, ms)));
44310
44336
  let status = "unknown";
44311
44337
  for (let poll = 0; poll < SETTLE_POLLS; poll++) {
44312
44338
  await sleep2(SETTLE_MS);
@@ -46051,8 +46077,14 @@ function registerBoardCommands(program3) {
46051
46077
  process.exitCode = e.exitCode;
46052
46078
  return;
46053
46079
  }
46054
- if (o.json && e && typeof e === "object" && "quota" in e && e.quota) console.log(JSON.stringify(e.quota));
46055
- return failGraceful(`board read failed: ${withDiscoverMissDetail(e.message)}`);
46080
+ const message2 = `board read failed: ${withDiscoverMissDetail(e.message)}`;
46081
+ if (o.json) {
46082
+ if (e && typeof e === "object" && "quota" in e && e.quota) console.log(JSON.stringify(e.quota));
46083
+ else console.log(formatErrorEnvelope(message2, {
46084
+ code: /\b(401|403)\b|auth|credential|token/i.test(message2) ? ERROR_CODES.ERR_NO_AUTH : /no MMI project detected|\b404\b|not found/i.test(message2) ? ERROR_CODES.ERR_NOT_FOUND : ERROR_CODES.ERR_PARTIAL
46085
+ }));
46086
+ }
46087
+ return failGraceful(message2);
46056
46088
  }
46057
46089
  }
46058
46090
  function formatClaimHolder(holder) {
@@ -46346,9 +46378,9 @@ function registerBoardCommands(program3) {
46346
46378
  }
46347
46379
 
46348
46380
  // src/bootstrap-commands.ts
46349
- var import_node_fs39 = require("node:fs");
46381
+ var import_node_fs40 = require("node:fs");
46350
46382
  var import_node_os21 = require("node:os");
46351
- var import_node_path36 = require("node:path");
46383
+ var import_node_path37 = require("node:path");
46352
46384
  init_cli_shared();
46353
46385
  init_clean_exit();
46354
46386
 
@@ -46661,10 +46693,10 @@ async function assignPersistedPortRange(repo, slug, reg, opts) {
46661
46693
  }
46662
46694
 
46663
46695
  // src/box-commands.ts
46664
- var import_node_fs38 = require("node:fs");
46696
+ var import_node_fs39 = require("node:fs");
46665
46697
  var import_node_child_process12 = require("node:child_process");
46666
46698
  var import_node_os20 = require("node:os");
46667
- var import_node_path35 = require("node:path");
46699
+ var import_node_path36 = require("node:path");
46668
46700
 
46669
46701
  // src/box-control.ts
46670
46702
  var import_node_crypto16 = require("node:crypto");
@@ -47411,16 +47443,16 @@ function parseTenantTasksVar(raw) {
47411
47443
  const task = rawTask;
47412
47444
  if (Object.keys(task).some((key) => !["service", "command", "stages", "timeoutSeconds", "artifact", "output", "secretOutput"].includes(key))) throw new Error(`org project set: tenantTasks.${name} has an unknown field`);
47413
47445
  if (typeof task.service !== "string" || !serviceRe.test(task.service)) throw new Error(`org project set: tenantTasks.${name}.service has an unsafe shape`);
47414
- if (!Array.isArray(task.command) || task.command.length < 1 || task.command.length > 32 || task.command.some((arg) => typeof arg !== "string" || arg.length < 1 || arg.length > 256 || /[\u0000\r\n]/.test(arg))) throw new Error(`org project set: tenantTasks.${name}.command must be 1-32 bounded argv strings`);
47446
+ if (!Array.isArray(task.command) || task.command.length < 1 || task.command.length > 32 || task.command.some((arg2) => typeof arg2 !== "string" || arg2.length < 1 || arg2.length > 256 || /[\u0000\r\n]/.test(arg2))) throw new Error(`org project set: tenantTasks.${name}.command must be 1-32 bounded argv strings`);
47415
47447
  if (!Array.isArray(task.stages) || task.stages.length < 1 || task.stages.length > 3 || task.stages.some((stage) => typeof stage !== "string" || !validStages.has(stage)) || new Set(task.stages).size !== task.stages.length) throw new Error(`org project set: tenantTasks.${name}.stages must be unique dev/rc/main values`);
47416
47448
  const maxTimeout = task.secretOutput !== void 0 ? 3600 : 10800;
47417
47449
  if (task.timeoutSeconds !== void 0 && (!Number.isInteger(task.timeoutSeconds) || task.timeoutSeconds < 1 || task.timeoutSeconds > maxTimeout)) throw new Error(`org project set: tenantTasks.${name}.timeoutSeconds must be an integer 1..${maxTimeout}`);
47418
47450
  const artifact = task.artifact ?? "none";
47419
47451
  if (artifact !== "none" && artifact !== "required") throw new Error(`org project set: tenantTasks.${name}.artifact must be none or required`);
47420
- const carriesPlaceholder = task.command.some((arg) => arg.includes("{artifact}"));
47452
+ const carriesPlaceholder = task.command.some((arg2) => arg2.includes("{artifact}"));
47421
47453
  if (artifact === "required" !== carriesPlaceholder) throw new Error(`org project set: tenantTasks.${name} must use {artifact} exactly when artifact is required`);
47422
47454
  if (task.output !== void 0 && task.output !== "file") throw new Error(`org project set: tenantTasks.${name}.output must be file, use {output}, and cannot combine with secretOutput`);
47423
- const outputPlaceholder = task.command.some((arg) => arg.includes("{output}"));
47455
+ const outputPlaceholder = task.command.some((arg2) => arg2.includes("{output}"));
47424
47456
  if (task.output === "file" !== outputPlaceholder || task.output !== void 0 && task.secretOutput !== void 0) throw new Error(`org project set: tenantTasks.${name}.output must be file, use {output}, and cannot combine with secretOutput`);
47425
47457
  out[name] = {
47426
47458
  service: task.service,
@@ -48554,6 +48586,276 @@ ${formatSshRecipe(box, remoteCommand)}
48554
48586
  `;
48555
48587
  }
48556
48588
 
48589
+ // ../infra/hetzner/cloud-firewall.mjs
48590
+ var import_node_fs38 = require("node:fs");
48591
+ var import_node_url = require("node:url");
48592
+ var import_node_path35 = require("node:path");
48593
+ var import_meta = {};
48594
+ var HZ = "https://api.hetzner.cloud/v1";
48595
+ var APPLY = process.env.FIREWALL_APPLY === "1";
48596
+ var ANY = ["0.0.0.0/0", "::/0"];
48597
+ function arg(name) {
48598
+ const i = process.argv.indexOf(`--${name}`);
48599
+ return i >= 0 && i + 1 < process.argv.length ? process.argv[i + 1] : void 0;
48600
+ }
48601
+ async function hetzner(token, path2, init = {}) {
48602
+ if (!token) throw new Error("no Hetzner Cloud API token (inject it with mmi-cli vault secrets use ... --name HZ_TOKEN)");
48603
+ const res = await fetch(`${HZ}${path2}`, {
48604
+ ...init,
48605
+ headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json" },
48606
+ signal: AbortSignal.timeout(3e4)
48607
+ });
48608
+ const body = await res.json().catch(() => ({}));
48609
+ if (!res.ok) throw new Error(`Hetzner ${init.method ?? "GET"} ${path2.split("?")[0]} failed: ${res.status} ${body?.error?.code ?? ""} ${body?.error?.message ?? ""}`);
48610
+ return body;
48611
+ }
48612
+ async function hz(path2, init = {}) {
48613
+ return hetzner(process.env.HZ_TOKEN, path2, init);
48614
+ }
48615
+ function buildRules(cloudflare, extras = []) {
48616
+ const cf = [...cloudflare.ipv4, ...cloudflare.ipv6];
48617
+ if (!cloudflare.ipv4.length || !cloudflare.ipv6.length) throw new Error("refusing an empty Cloudflare range list (it would block every site)");
48618
+ const rules = [
48619
+ { direction: "in", protocol: "tcp", port: "22", source_ips: ANY, description: "SSH (deploy, reconcile, runner)" },
48620
+ { direction: "in", protocol: "icmp", source_ips: ANY, description: "ICMP" },
48621
+ { direction: "in", protocol: "tcp", port: "80", source_ips: cf, description: "HTTP from Cloudflare only" },
48622
+ { direction: "in", protocol: "tcp", port: "443", source_ips: cf, description: "HTTPS from Cloudflare only" }
48623
+ ];
48624
+ for (const e of extras) {
48625
+ if (!["tcp", "udp"].includes(e.protocol) || !/^\d{1,5}(-\d{1,5})?$/.test(String(e.port)) || !e.description) {
48626
+ throw new Error(`invalid firewall extra ${JSON.stringify(e)}: needs protocol tcp|udp, port N or N-M, description`);
48627
+ }
48628
+ rules.push({ direction: "in", protocol: e.protocol, port: String(e.port), source_ips: ANY, description: e.description.slice(0, 255) });
48629
+ }
48630
+ return rules;
48631
+ }
48632
+ async function cloudflareRanges() {
48633
+ const res = await fetch("https://api.cloudflare.com/client/v4/ips", { signal: AbortSignal.timeout(3e4) });
48634
+ const body = await res.json();
48635
+ if (!res.ok || !body?.success) throw new Error(`Cloudflare IP list unreadable: ${res.status}`);
48636
+ return { ipv4: body.result.ipv4_cidrs ?? [], ipv6: body.result.ipv6_cidrs ?? [] };
48637
+ }
48638
+ var norm = (rules) => JSON.stringify(rules.map((r) => ({ ...r, source_ips: [...r.source_ips ?? []].sort() })).map(({ direction, protocol, port, source_ips }) => ({ direction, protocol, port: port ?? null, source_ips })));
48639
+ function declaredExtras(box) {
48640
+ const extrasFile = JSON.parse((0, import_node_fs38.readFileSync)((0, import_node_url.fileURLToPath)(new URL("./firewall-extras.json", import_meta.url)), "utf8"));
48641
+ return Object.prototype.hasOwnProperty.call(extrasFile, box) ? extrasFile[box] : void 0;
48642
+ }
48643
+ async function main() {
48644
+ const box = arg("box");
48645
+ if (!box || !/^[a-z0-9-]+$/.test(box)) {
48646
+ console.error("cloud-firewall: --box <hetzner server name> is required");
48647
+ process.exit(64);
48648
+ }
48649
+ const detach2 = process.argv.includes("--detach");
48650
+ const name = `mmi-${box}`;
48651
+ const servers = (await hz(`/servers?name=${encodeURIComponent(box)}`)).servers ?? [];
48652
+ if (servers.length !== 1) throw new Error(`expected exactly one server named ${box} in this project, found ${servers.length}`);
48653
+ const server = servers[0];
48654
+ const existing = ((await hz(`/firewalls?name=${encodeURIComponent(name)}`)).firewalls ?? [])[0];
48655
+ const applied = Boolean(existing?.applied_to?.some((a) => a.server?.id === server.id));
48656
+ console.log(`cloud-firewall: box=${box} server=${server.id} ip=${server.public_net?.ipv4?.ip} firewall=${existing ? `${name}#${existing.id}` : `${name} (absent)`} applied=${applied} mode=${APPLY ? "LIVE" : "DRY-RUN"}${detach2 ? " action=detach" : ""}`);
48657
+ if (detach2) {
48658
+ if (!existing || !applied) {
48659
+ console.log("cloud-firewall: not applied to this server \u2014 nothing to detach");
48660
+ return;
48661
+ }
48662
+ if (!APPLY) {
48663
+ console.log("cloud-firewall: dry-run (FIREWALL_APPLY=1 to detach)");
48664
+ return;
48665
+ }
48666
+ await hz(`/firewalls/${existing.id}/actions/remove_from_resources`, { method: "POST", body: JSON.stringify({ remove_from: [{ type: "server", server: { id: server.id } }] }) });
48667
+ console.log(`cloud-firewall: detached ${name} from ${box}`);
48668
+ return;
48669
+ }
48670
+ const extras = declaredExtras(box);
48671
+ if (extras === void 0) throw new Error(`${box} has no entry in firewall-extras.json; declare it (an empty list is fine) before applying`);
48672
+ const rules = buildRules(await cloudflareRanges(), extras);
48673
+ for (const r of rules) console.log(` in ${r.protocol}${r.port ? `/${r.port}` : ""} from ${r.source_ips.length > 2 ? `${r.source_ips.length} Cloudflare ranges` : r.source_ips.join(",")} \u2014 ${r.description}`);
48674
+ const rulesChanged = !existing || norm(existing.rules) !== norm(rules);
48675
+ console.log(`cloud-firewall: rules ${rulesChanged ? "would change" : "unchanged"}; apply-to-server ${applied ? "already done" : "needed"}`);
48676
+ if (!APPLY) {
48677
+ console.log("cloud-firewall: dry-run (FIREWALL_APPLY=1 to write)");
48678
+ return;
48679
+ }
48680
+ let id = existing?.id;
48681
+ if (!existing) {
48682
+ id = (await hz("/firewalls", { method: "POST", body: JSON.stringify({ name, labels: { managed_by: "mmi-hub", box }, rules }) })).firewall.id;
48683
+ console.log(`cloud-firewall: created ${name}#${id}`);
48684
+ } else if (rulesChanged) {
48685
+ await hz(`/firewalls/${id}/actions/set_rules`, { method: "POST", body: JSON.stringify({ rules }) });
48686
+ console.log(`cloud-firewall: updated rules on ${name}#${id}`);
48687
+ }
48688
+ if (!applied) {
48689
+ await hz(`/firewalls/${id}/actions/apply_to_resources`, { method: "POST", body: JSON.stringify({ apply_to: [{ type: "server", server: { id: server.id } }] }) });
48690
+ console.log(`cloud-firewall: applied ${name} to ${box}`);
48691
+ }
48692
+ }
48693
+ if (process.argv[1] && (0, import_node_path35.basename)(process.argv[1]).toLowerCase() === "cloud-firewall.mjs") {
48694
+ main().catch((err) => {
48695
+ console.error(`cloud-firewall: failed: ${err.message}`);
48696
+ process.exit(1);
48697
+ });
48698
+ }
48699
+
48700
+ // ../infra/hetzner/firewall-extras.json
48701
+ var firewall_extras_default = {
48702
+ $comment: "#7356: per-box inbound exceptions to the Cloudflare-only Hetzner Cloud Firewall (cloud-firewall.mjs). Every entry names its owner and reason. Web traffic (80/443) is always Cloudflare-only and SSH (22) is always open; list only what must reach the box directly.",
48703
+ "mm-work": [
48704
+ { protocol: "tcp", port: "7881", description: "MM-Chat dev huddles LiveKit RTC over TCP (MMI-Hub#7353, owner-approved 2026-09-26)" },
48705
+ { protocol: "udp", port: "7882", description: "MM-Chat dev huddles LiveKit RTC over UDP (MMI-Hub#7353, owner-approved 2026-09-26)" },
48706
+ { protocol: "tcp", port: "7891", description: "MM-Chat main huddles LiveKit RTC over TCP (MMI-Hub#7907, owner-approved 2026-10-06)" },
48707
+ { protocol: "udp", port: "7892", description: "MM-Chat main huddles LiveKit RTC over UDP (MMI-Hub#7907, owner-approved 2026-10-06)" }
48708
+ ],
48709
+ "mm-central": [],
48710
+ "mm-recorder": [],
48711
+ "mmi-runner": [],
48712
+ "mmi-runner2": []
48713
+ };
48714
+
48715
+ // ../shared/runner-hosts.ts
48716
+ var RUNNER_HOSTS = ["mmi-runner", "mmi-runner2"];
48717
+
48718
+ // src/box-firewall.ts
48719
+ function declaredExtrasFromBundle(box) {
48720
+ const file = firewall_extras_default;
48721
+ return Object.prototype.hasOwnProperty.call(file, box) ? file[box] : void 0;
48722
+ }
48723
+ var FirewallRefusal = class extends Error {
48724
+ };
48725
+ var FIREWALL_NAME_PREFIX = "mmi-";
48726
+ var ACTION_POLL_MS = 2500;
48727
+ var ACTION_POLL_ATTEMPTS = 20;
48728
+ async function runBoxFirewall(boxName, mode, live, deps) {
48729
+ const runner = RUNNER_HOSTS.find((h) => h.toLowerCase() === boxName.toLowerCase());
48730
+ if (!runner) {
48731
+ throw new FirewallRefusal(
48732
+ `box firewall: '${boxName}' is not a registered runner box \u2014 this command manages only the firewalls of ${RUNNER_HOSTS.join(" and ")} (the reviewed runner policy does not cover any other box)`
48733
+ );
48734
+ }
48735
+ const token = await deps.fetchToken();
48736
+ const firewallName = `${FIREWALL_NAME_PREFIX}${runner}`;
48737
+ if (live === false && mode !== "plan") {
48738
+ throw new FirewallRefusal(`box firewall: ${mode} is a mutation \u2014 it needs --apply`);
48739
+ }
48740
+ const servers = (await deps.hetzner(token, `/servers?name=${encodeURIComponent(runner)}`)).servers ?? [];
48741
+ if (servers.length !== 1) {
48742
+ throw new FirewallRefusal(`box firewall: expected exactly one server named ${runner} in the MM project, found ${servers.length} \u2014 refusing to guess the target`);
48743
+ }
48744
+ const server = servers[0];
48745
+ const observedAt = deps.now();
48746
+ const existing = ((await deps.hetzner(token, `/firewalls?name=${encodeURIComponent(firewallName)}`)).firewalls ?? [])[0];
48747
+ const applied = Boolean(existing?.applied_to?.some((a) => a.server?.id === server.id));
48748
+ const target = {
48749
+ operation: mode,
48750
+ live,
48751
+ box: runner,
48752
+ server: { id: server.id, name: server.name, ...server.public_net?.ipv4?.ip ? { ipv4: server.public_net.ipv4.ip } : {} },
48753
+ firewall: existing ? { id: existing.id, name: existing.name } : null,
48754
+ applied,
48755
+ rulesChanged: false,
48756
+ currentRules: existing?.rules ?? [],
48757
+ plannedRules: null,
48758
+ actions: [],
48759
+ readback: void 0,
48760
+ note: void 0,
48761
+ ambiguous: false,
48762
+ ok: false,
48763
+ observedAt
48764
+ };
48765
+ if (mode === "detach") {
48766
+ if (!existing || !applied) {
48767
+ return { ...target, ok: true, note: `firewall ${firewallName} is ${existing ? "not applied to" : "absent for"} this server \u2014 nothing to detach` };
48768
+ }
48769
+ const action = await actionPost(deps, token, existing.id, "remove_from_resources", { remove_from: [{ type: "server", server: { id: server.id } }] });
48770
+ const waited = await waitForAction(deps, token, action);
48771
+ target.actions.push(actionReceipt("remove_from_resources", waited));
48772
+ target.ambiguous = waited.ambiguous;
48773
+ const readback2 = await readbackState(deps, token, existing.id, server.id, null, deps.now());
48774
+ target.readback = readback2;
48775
+ target.ok = !waited.ambiguous && readback2.attached === false;
48776
+ if (target.ok) target.note = `detached ${firewallName} from ${runner}`;
48777
+ return target;
48778
+ }
48779
+ const extras = deps.declaredExtras(runner);
48780
+ if (extras === void 0) {
48781
+ throw new FirewallRefusal(`box firewall: ${runner} has no entry in infra/hetzner/firewall-extras.json; declare it (an empty list is fine) before planning or applying`);
48782
+ }
48783
+ const planned = buildRules(await deps.cloudflareRanges(), extras);
48784
+ target.plannedRules = planned;
48785
+ const rulesChanged = !existing || norm(existing.rules ?? []) !== norm(planned);
48786
+ target.rulesChanged = rulesChanged;
48787
+ if (mode === "plan") {
48788
+ target.ok = !rulesChanged && applied;
48789
+ if (target.ok) target.note = `firewall ${firewallName}#${existing.id} matches the reviewed policy and is applied`;
48790
+ return target;
48791
+ }
48792
+ let firewallId = existing?.id;
48793
+ if (!existing) {
48794
+ const created = await deps.hetzner(token, "/firewalls", {
48795
+ method: "POST",
48796
+ body: JSON.stringify({ name: firewallName, labels: { managed_by: "mmi-hub", box: runner }, rules: planned })
48797
+ });
48798
+ firewallId = created.firewall.id;
48799
+ target.actions.push({ id: firewallId, kind: "create", status: "created" });
48800
+ } else if (rulesChanged) {
48801
+ const action = await actionPost(deps, token, firewallId, "set_rules", { rules: planned });
48802
+ const waited = await waitForAction(deps, token, action);
48803
+ target.actions.push(actionReceipt("set_rules", waited));
48804
+ target.ambiguous ||= waited.ambiguous;
48805
+ if (waited.ambiguous || waited.action.status === "error") {
48806
+ const readback2 = await readbackState(deps, token, firewallId, server.id, planned, deps.now());
48807
+ target.readback = readback2;
48808
+ return target;
48809
+ }
48810
+ }
48811
+ if (!applied) {
48812
+ const action = await actionPost(deps, token, firewallId, "apply_to_resources", { apply_to: [{ type: "server", server: { id: server.id } }] });
48813
+ const waited = await waitForAction(deps, token, action);
48814
+ target.actions.push(actionReceipt("apply_to_resources", waited));
48815
+ target.ambiguous ||= waited.ambiguous;
48816
+ if (waited.action.status === "error") {
48817
+ const readback2 = await readbackState(deps, token, firewallId, server.id, planned, deps.now());
48818
+ target.readback = readback2;
48819
+ return target;
48820
+ }
48821
+ }
48822
+ const readback = await readbackState(deps, token, firewallId, server.id, planned, deps.now());
48823
+ target.firewall = { id: firewallId, name: firewallName };
48824
+ target.readback = readback;
48825
+ target.ok = !target.ambiguous && readback.attached && readback.rulesMatch === true;
48826
+ if (target.ok) target.note = `firewall ${firewallName}#${firewallId} applied to ${runner} and read back independently`;
48827
+ return target;
48828
+ }
48829
+ async function actionPost(deps, token, firewallId, kind, body) {
48830
+ const res = await deps.hetzner(token, `/firewalls/${firewallId}/actions/${kind}`, { method: "POST", body: JSON.stringify(body) });
48831
+ return res.action;
48832
+ }
48833
+ async function waitForAction(deps, token, accepted) {
48834
+ let last = accepted;
48835
+ for (let attempt = 0; attempt < ACTION_POLL_ATTEMPTS; attempt += 1) {
48836
+ const res = await deps.hetzner(token, `/firewalls/actions/${accepted.id}`);
48837
+ last = res.action ?? last;
48838
+ if (last.status === "success" || last.status === "error") return { action: last, ambiguous: false };
48839
+ await deps.sleep(ACTION_POLL_MS);
48840
+ }
48841
+ return { action: last, ambiguous: true };
48842
+ }
48843
+ function actionReceipt(kind, waited) {
48844
+ return {
48845
+ id: waited.action.id,
48846
+ kind,
48847
+ status: waited.ambiguous ? "running (wait bound exhausted \u2014 ambiguous)" : waited.action.status,
48848
+ ...waited.action.error ? { error: { code: waited.action.error.code, message: waited.action.error.message } } : {}
48849
+ };
48850
+ }
48851
+ async function readbackState(deps, token, firewallId, serverId, planned, at) {
48852
+ const firewall = (await deps.hetzner(token, `/firewalls/${firewallId}`)).firewall;
48853
+ const server = (await deps.hetzner(token, `/servers/${serverId}`)).server;
48854
+ const attached = server != null && server.id === serverId && Boolean(firewall?.applied_to?.some((a) => a.server?.id === serverId));
48855
+ const rulesMatch = planned ? norm(firewall?.rules ?? []) === norm(planned) : null;
48856
+ return { observedAt: at, attached, rulesMatch };
48857
+ }
48858
+
48557
48859
  // src/box-commands.ts
48558
48860
  var HETZNER_API = "https://api.hetzner.cloud/v1/servers";
48559
48861
  var HETZNER_TIMEOUT_MS = 15e3;
@@ -48664,7 +48966,7 @@ function registerBoxCommands(program3) {
48664
48966
  const stdinSource = o.body ? `"${o.body}"` : "<body.sh>";
48665
48967
  const wroteScript = o.ssh && o.script ? o.script : null;
48666
48968
  const runLine = wroteScript ? useStdin ? `bash "${wroteScript}" < ${stdinSource}` : `bash "${wroteScript}"` : void 0;
48667
- if (wroteScript) (0, import_node_fs38.writeFileSync)(wroteScript, sshRecipeScript(found, remote), "utf8");
48969
+ if (wroteScript) (0, import_node_fs39.writeFileSync)(wroteScript, sshRecipeScript(found, remote), "utf8");
48668
48970
  if (o.json) {
48669
48971
  console.log(JSON.stringify({
48670
48972
  box: found,
@@ -48775,6 +49077,79 @@ ${SSH_RECIPE_AGENT_NOTE}`);
48775
49077
  process.exitCode = 2;
48776
49078
  }
48777
49079
  });
49080
+ box.command("firewall <box>").description("the registered runner boxes' Hetzner Cloud Firewall (#9786): --plan (default, read-only) reports the exact current rules and attachment against the reviewed policy; --apply writes it; --detach --apply is the rollback").option("--plan", "read-only: current firewall, attachment and exact rules, and the diff against the reviewed policy (the default)").option("--apply", "create/update the approved firewall (policy #7359, SSH stays world-open) and attach it to exactly this server; waits for each provider action, then re-reads the firewall and attachment independently").option("--detach", "with --apply: detach this exact firewall from this exact server (rollback; a route independent of SSH)").option("--json", "machine-readable receipt").action(async (name, o) => {
49081
+ try {
49082
+ if (o.apply && o.plan) throw new UsageError("box firewall: --plan and --apply are exclusive");
49083
+ if (o.detach && !o.apply) throw new UsageError("box firewall: --detach is a mutation \u2014 it needs --apply");
49084
+ if (!o.apply && !o.plan) o.plan = true;
49085
+ const mode = o.detach ? "detach" : o.apply ? "apply" : "plan";
49086
+ const deps = firewallDeps();
49087
+ if (mode === "plan") {
49088
+ const receipt2 = await runBoxFirewall(name, mode, false, deps);
49089
+ renderFirewallReceipt(receipt2, o.json === true);
49090
+ process.exitCode = receipt2.ok ? 0 : 1;
49091
+ return;
49092
+ }
49093
+ const { boxes, incomplete } = await fetchInventory();
49094
+ const found = lookupBox(name, boxes, incomplete);
49095
+ if (found.kind !== "found") {
49096
+ const why = found.kind === "unknown" ? `the inventory is incomplete (${found.reasons.join("; ")})` : `no box named '${name}'`;
49097
+ throw new UnreadableError(`box firewall: ${why}`);
49098
+ }
49099
+ const receipt = await runBoxFirewall(found.box.name, mode, true, deps);
49100
+ if (!o.json) warnIncomplete(incomplete);
49101
+ renderFirewallReceipt(receipt, o.json === true);
49102
+ process.exitCode = receipt.ok ? 0 : 1;
49103
+ } catch (e) {
49104
+ const message2 = e instanceof FirewallRefusal ? e.message : e.message;
49105
+ if (o.json) console.log(JSON.stringify({ box: name, ok: false, refused: e instanceof FirewallRefusal, error: message2 }, null, 2));
49106
+ else console.error(message2);
49107
+ process.exitCode = 2;
49108
+ }
49109
+ });
49110
+ }
49111
+ function renderFirewallReceipt(r, json) {
49112
+ if (json) {
49113
+ console.log(JSON.stringify(r, null, 2));
49114
+ return;
49115
+ }
49116
+ const fw = r.firewall ? `${r.firewall.name}#${r.firewall.id}` : `mmi-${r.box} (absent)`;
49117
+ const lines2 = [
49118
+ `${r.box} \u2014 firewall ${r.operation}${r.live ? " (LIVE)" : " (dry-run)"}`,
49119
+ ` server: #${r.server.id}${r.server.ipv4 ? ` (${r.server.ipv4})` : ""}`,
49120
+ ` firewall: ${fw}, ${r.applied ? "attached to this server" : "not attached to this server"}`
49121
+ ];
49122
+ if (r.plannedRules) {
49123
+ lines2.push(` rules: ${r.rulesChanged ? "WOULD CHANGE \u2014 planned set differs from the provider" : "match the reviewed policy"}`);
49124
+ for (const rule of r.plannedRules) {
49125
+ const from = rule.source_ips.length > 2 ? `${rule.source_ips.length} Cloudflare ranges` : rule.source_ips.join(", ");
49126
+ lines2.push(` in ${rule.protocol}${rule.port ? `/${rule.port}` : ""} from ${from} \u2014 ${rule.description}`);
49127
+ }
49128
+ }
49129
+ for (const a of r.actions) lines2.push(` action ${a.kind} #${a.id}: ${a.status}${a.error ? ` \u2014 ${a.error.code ?? ""} ${a.error.message ?? ""}` : ""}`);
49130
+ if (r.readback) {
49131
+ lines2.push(` readback (independent, ${r.readback.observedAt}): attached=${r.readback.attached}${r.readback.rulesMatch === null ? "" : ` rulesMatch=${r.readback.rulesMatch}`}`);
49132
+ }
49133
+ if (r.ambiguous) lines2.push(" AMBIGUOUS: a provider action never reached success/error \u2014 treat the outcome as unknown, do not blindly rerun the mutation");
49134
+ lines2.push(` ${r.ok ? "OK" : "NOT OK"}${r.note ? ` \u2014 ${r.note}` : ""} (observed ${r.observedAt})`);
49135
+ console.log(lines2.join("\n"));
49136
+ }
49137
+ function firewallDeps() {
49138
+ return {
49139
+ hetzner: (token, path2, init) => hetzner(token, path2, init),
49140
+ cloudflareRanges: () => cloudflareRanges(),
49141
+ declaredExtras: (boxName) => declaredExtrasFromBundle(boxName),
49142
+ fetchToken: async () => {
49143
+ let token = null;
49144
+ await withSecrets(async (secretsDeps) => {
49145
+ token = await fetchSecretValue(secretsDeps, PROJECT_API_TOKEN.MM, { slug: HETZNER_VAULT_SLUG }, true);
49146
+ });
49147
+ if (!token) throw new Error("box firewall: could not read the Hetzner MM API token from the vault (the value is never printed)");
49148
+ return token;
49149
+ },
49150
+ sleep: (ms) => new Promise((resolve8) => setTimeout(resolve8, ms)),
49151
+ now: () => (/* @__PURE__ */ new Date()).toISOString()
49152
+ };
48778
49153
  }
48779
49154
  var UsageError = class extends Error {
48780
49155
  };
@@ -48791,17 +49166,17 @@ function hubGitShow(ref) {
48791
49166
  return (path2) => git3(["show", `${ref}:${path2}`]);
48792
49167
  }
48793
49168
  function runOnBox(found, script) {
48794
- const dir = (0, import_node_fs38.mkdtempSync)((0, import_node_path35.join)((0, import_node_os20.tmpdir)(), "mmi-box-control-"));
49169
+ const dir = (0, import_node_fs39.mkdtempSync)((0, import_node_path36.join)((0, import_node_os20.tmpdir)(), "mmi-box-control-"));
48795
49170
  try {
48796
- const recipe = (0, import_node_path35.join)(dir, "recipe.sh");
48797
- (0, import_node_fs38.writeFileSync)(recipe, sshRecipeScript(found, "sh -s"), "utf8");
49171
+ const recipe = (0, import_node_path36.join)(dir, "recipe.sh");
49172
+ (0, import_node_fs39.writeFileSync)(recipe, sshRecipeScript(found, "sh -s"), "utf8");
48798
49173
  const r = (0, import_node_child_process12.spawnSync)("bash", [recipe], { input: script, encoding: "utf8", maxBuffer: 16 * 1024 * 1024, timeout: 18e4, windowsHide: true });
48799
49174
  if (r.status !== 0) {
48800
49175
  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(" | ")}`);
48801
49176
  }
48802
49177
  return r.stdout;
48803
49178
  } finally {
48804
- (0, import_node_fs38.rmSync)(dir, { recursive: true, force: true });
49179
+ (0, import_node_fs39.rmSync)(dir, { recursive: true, force: true });
48805
49180
  }
48806
49181
  }
48807
49182
  function formatControl(mode, box, rows) {
@@ -50302,12 +50677,12 @@ var declaredProjectAdmins = (meta) => {
50302
50677
  };
50303
50678
  var execGitForSeedSource = async (args) => (await execFileP("git", args, { timeout: GIT_TIMEOUT_MS })).stdout;
50304
50679
  async function gateRenderDiff(current, rendered) {
50305
- const dir = (0, import_node_fs39.mkdtempSync)((0, import_node_path36.join)((0, import_node_os21.tmpdir)(), "mmi-gate-diff-"));
50306
- const before = (0, import_node_path36.join)(dir, "committed-gate.yml");
50307
- const after = (0, import_node_path36.join)(dir, "registry-render.yml");
50680
+ const dir = (0, import_node_fs40.mkdtempSync)((0, import_node_path37.join)((0, import_node_os21.tmpdir)(), "mmi-gate-diff-"));
50681
+ const before = (0, import_node_path37.join)(dir, "committed-gate.yml");
50682
+ const after = (0, import_node_path37.join)(dir, "registry-render.yml");
50308
50683
  try {
50309
- (0, import_node_fs39.writeFileSync)(before, current);
50310
- (0, import_node_fs39.writeFileSync)(after, rendered);
50684
+ (0, import_node_fs40.writeFileSync)(before, current);
50685
+ (0, import_node_fs40.writeFileSync)(after, rendered);
50311
50686
  try {
50312
50687
  return (await execFileP("git", ["diff", "--no-index", "--", before, after], { timeout: GIT_TIMEOUT_MS })).stdout;
50313
50688
  } catch (e) {
@@ -50316,7 +50691,7 @@ async function gateRenderDiff(current, rendered) {
50316
50691
  throw e;
50317
50692
  }
50318
50693
  } finally {
50319
- (0, import_node_fs39.rmSync)(dir, { recursive: true, force: true });
50694
+ (0, import_node_fs40.rmSync)(dir, { recursive: true, force: true });
50320
50695
  }
50321
50696
  }
50322
50697
  function bootstrapTrainDoctorDeps() {
@@ -50337,9 +50712,9 @@ async function propagationScope(classes, what) {
50337
50712
  }
50338
50713
  const rosterRepos = collectRegistryRepos(projects).filter((r) => r.toLowerCase() !== "mutmutco/mmi-hub");
50339
50714
  let independentCount = rosterRepos.length;
50340
- if ((0, import_node_fs39.existsSync)("projects.json")) {
50715
+ if ((0, import_node_fs40.existsSync)("projects.json")) {
50341
50716
  try {
50342
- const local = JSON.parse((0, import_node_fs39.readFileSync)("projects.json", "utf8"));
50717
+ const local = JSON.parse((0, import_node_fs40.readFileSync)("projects.json", "utf8"));
50343
50718
  const localRepos = /* @__PURE__ */ new Set();
50344
50719
  for (const p of local.projects ?? []) for (const r of p.repos ?? []) {
50345
50720
  const full = (r.includes("/") ? r : `mutmutco/${r}`).toLowerCase();
@@ -50464,13 +50839,13 @@ function registerBootstrapCommands(program3) {
50464
50839
  })),
50465
50840
  pushAllowlistOwners: pushAllowlistAuthority(verifyOwners, declaredProjectAdmins(meta)),
50466
50841
  pushAllowlistOwnersRead: verifyOwnersRead,
50467
- readLocalFile: (path2) => path2 === "projects.json" && apiProjects != null ? apiProjects : (0, import_node_fs39.existsSync)(path2) ? (0, import_node_fs39.readFileSync)(path2, "utf8") : null,
50842
+ readLocalFile: (path2) => path2 === "projects.json" && apiProjects != null ? apiProjects : (0, import_node_fs40.existsSync)(path2) ? (0, import_node_fs40.readFileSync)(path2, "utf8") : null,
50468
50843
  // requiredGcpApis is stored as an array by a JSON write, but `org project set --var KEY=VALUE` stores a raw
50469
50844
  // comma-string — accept either so the seeded value verifies regardless of how it was written.
50470
50845
  // #3689: the same committed map the org access audit reads (#3664), so a sanctioned admin is not a
50471
50846
  // permanent bootstrap failure on one surface and an intended state on the other. Absent file → no
50472
50847
  // sanction, which is the pre-#3664 behaviour.
50473
- sanctionedAdmins: (0, import_node_fs39.existsSync)("access-matrix.json") ? entriesValueByCanonicalRepo(loadSanctionedAdmins((0, import_node_fs39.readFileSync)("access-matrix.json", "utf8")), repo) : void 0,
50848
+ sanctionedAdmins: (0, import_node_fs40.existsSync)("access-matrix.json") ? entriesValueByCanonicalRepo(loadSanctionedAdmins((0, import_node_fs40.readFileSync)("access-matrix.json", "utf8")), repo) : void 0,
50474
50849
  requiredGcpApis: (() => {
50475
50850
  const v = meta?.requiredGcpApis;
50476
50851
  if (Array.isArray(v)) return v;
@@ -50548,14 +50923,14 @@ function registerBootstrapCommands(program3) {
50548
50923
  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 () => {
50549
50924
  const o = { repo: rawValue("--repo", ""), json: rawFlag("--json") };
50550
50925
  const manifestPath = "skills/bootstrap/seeds/manifest.json";
50551
- if (!(0, import_node_fs39.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`);
50926
+ if (!(0, import_node_fs40.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`);
50552
50927
  const seedSource = await resolveHubSeedSource(execGitForSeedSource);
50553
50928
  if (!seedSource.ok) return fail(`bootstrap drift: ${seedSource.reason}`);
50554
- const manifest = loadBootstrapSeeds((0, import_node_fs39.readFileSync)(manifestPath, "utf8"));
50929
+ const manifest = loadBootstrapSeeds((0, import_node_fs40.readFileSync)(manifestPath, "utf8"));
50555
50930
  const hubContents = /* @__PURE__ */ new Map();
50556
50931
  for (const s of manifest.seeds) {
50557
50932
  if (s.ownership !== "org" || s.source !== "self") continue;
50558
- hubContents.set(s.target, (0, import_node_fs39.existsSync)(s.target) ? (0, import_node_fs39.readFileSync)(s.target, "utf8") : null);
50933
+ hubContents.set(s.target, (0, import_node_fs40.existsSync)(s.target) ? (0, import_node_fs40.readFileSync)(s.target, "utf8") : null);
50559
50934
  }
50560
50935
  let targets;
50561
50936
  let classOf = (_repo) => "deployable";
@@ -50811,24 +51186,24 @@ function registerBootstrapCommands(program3) {
50811
51186
  return;
50812
51187
  }
50813
51188
  const manifestPath = "skills/bootstrap/seeds/manifest.json";
50814
- if (!(0, import_node_fs39.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`);
51189
+ if (!(0, import_node_fs40.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`);
50815
51190
  const seedSource = await resolveHubSeedSource(execGitForSeedSource);
50816
51191
  if (!seedSource.ok) return fail(`bootstrap apply: ${seedSource.reason}`);
50817
- const manifest = loadBootstrapSeeds((0, import_node_fs39.readFileSync)(manifestPath, "utf8"));
51192
+ const manifest = loadBootstrapSeeds((0, import_node_fs40.readFileSync)(manifestPath, "utf8"));
50818
51193
  const baseBranch = o.class === "content" ? "main" : "development";
50819
51194
  const slug = parsedRepo.slug;
50820
51195
  const onlyTarget = o.fromConfig && o.only.trim() === "gate.yml" ? ".github/workflows/gate.yml" : o.only.trim();
50821
51196
  const gh2 = async (args) => execFileP("gh", args, { timeout: 2e4 });
50822
- const readFile10 = (p) => (0, import_node_fs39.existsSync)(p) ? (0, import_node_fs39.readFileSync)(p, "utf8") : null;
51197
+ const readFile10 = (p) => (0, import_node_fs40.existsSync)(p) ? (0, import_node_fs40.readFileSync)(p, "utf8") : null;
50823
51198
  const enc = (p) => p.split("/").map(encodeURIComponent).join("/");
50824
51199
  const putSeed = async (target, content, ref, sha) => {
50825
- const tmp = (0, import_node_path36.join)((0, import_node_os21.tmpdir)(), `mmi-seed-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
50826
- (0, import_node_fs39.writeFileSync)(tmp, JSON.stringify(contentPutBody(target, content, ref, sha)), "utf8");
51200
+ const tmp = (0, import_node_path37.join)((0, import_node_os21.tmpdir)(), `mmi-seed-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
51201
+ (0, import_node_fs40.writeFileSync)(tmp, JSON.stringify(contentPutBody(target, content, ref, sha)), "utf8");
50827
51202
  try {
50828
51203
  await gh2(contentPutInputArgs(repo, target, tmp));
50829
51204
  } finally {
50830
51205
  try {
50831
- (0, import_node_fs39.unlinkSync)(tmp);
51206
+ (0, import_node_fs40.unlinkSync)(tmp);
50832
51207
  } catch {
50833
51208
  }
50834
51209
  }
@@ -51466,10 +51841,10 @@ LIVE apply to ${repo}:
51466
51841
  if (rawFlag("--pins")) return propagatePins(rawFlag("--apply"), rawFlag("--json"));
51467
51842
  const o = { target: rawValue("--target", ""), execute: rawFlag("--execute"), json: rawFlag("--json") };
51468
51843
  const manifestPath = "skills/bootstrap/seeds/manifest.json";
51469
- if (!(0, import_node_fs39.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`);
51844
+ if (!(0, import_node_fs40.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`);
51470
51845
  const seedSource = await resolveHubSeedSource(execGitForSeedSource);
51471
51846
  if (!seedSource.ok) return fail(`bootstrap propagate: ${seedSource.reason}`);
51472
- const manifest = loadBootstrapSeeds((0, import_node_fs39.readFileSync)(manifestPath, "utf8"));
51847
+ const manifest = loadBootstrapSeeds((0, import_node_fs40.readFileSync)(manifestPath, "utf8"));
51473
51848
  const propagatable = manifest.seeds.filter(isPropagatableSeed);
51474
51849
  if (!o.target) {
51475
51850
  return fail(`bootstrap propagate: --target <path> is required \u2014 one of:
@@ -51478,9 +51853,9 @@ LIVE apply to ${repo}:
51478
51853
  const seed = propagatable.find((s) => s.target === o.target);
51479
51854
  if (!seed) return fail(`bootstrap propagate: --target '${o.target}' names no centrally propagatable seed in ${manifestPath}. Propagatable targets:
51480
51855
  ${propagatable.map((s) => s.target).join("\n ")}`);
51481
- if (!seed.managedBlock && !(0, import_node_fs39.existsSync)(seed.target)) return fail(`bootstrap propagate: the Hub's own copy of '${seed.target}' is missing \u2014 nothing to propagate`);
51482
- const hubContent = seed.managedBlock ? null : (0, import_node_fs39.readFileSync)(seed.target, "utf8");
51483
- const readSeedFile2 = (path2) => (0, import_node_fs39.existsSync)(path2) ? (0, import_node_fs39.readFileSync)(path2, "utf8") : null;
51856
+ if (!seed.managedBlock && !(0, import_node_fs40.existsSync)(seed.target)) return fail(`bootstrap propagate: the Hub's own copy of '${seed.target}' is missing \u2014 nothing to propagate`);
51857
+ const hubContent = seed.managedBlock ? null : (0, import_node_fs40.readFileSync)(seed.target, "utf8");
51858
+ const readSeedFile2 = (path2) => (0, import_node_fs40.existsSync)(path2) ? (0, import_node_fs40.readFileSync)(path2, "utf8") : null;
51484
51859
  const isWorkflowSeed = seed.target.startsWith(".github/workflows/");
51485
51860
  const { projects, classOf, inClassRepos, canarySlug, sourcePilot } = await propagationScope(seed.classes, `target '${seed.target}'`);
51486
51861
  const repos = inClassRepos.map((repo) => {
@@ -51599,7 +51974,7 @@ LIVE apply to ${repo}:
51599
51974
  if (plan.refusedNoCanary) return fail("bootstrap propagate --execute: no canary declared for this target \u2014 refusing to write (set seedCanary:true on exactly one registry repo)");
51600
51975
  const headSha = seedSource.sha;
51601
51976
  const sourceBlob = (await execGitForSeedSource(["rev-parse", `${headSha}:${seedSourcePath(seed)}`])).trim();
51602
- const runbookUnaffected = (0, import_node_fs39.existsSync)(RUNBOOK_UNAFFECTED_PATH) ? runbookUnaffectedReason(JSON.parse((0, import_node_fs39.readFileSync)(RUNBOOK_UNAFFECTED_PATH, "utf8")), seed.target, sourceBlob) : void 0;
51977
+ const runbookUnaffected = (0, import_node_fs40.existsSync)(RUNBOOK_UNAFFECTED_PATH) ? runbookUnaffectedReason(JSON.parse((0, import_node_fs40.readFileSync)(RUNBOOK_UNAFFECTED_PATH, "utf8")), seed.target, sourceBlob) : void 0;
51603
51978
  for (const rec of plan.records) {
51604
51979
  if (rec.action !== "open-pr") continue;
51605
51980
  const baseBranch = classOf(rec.repo) === "content" ? "main" : "development";
@@ -51621,15 +51996,15 @@ LIVE apply to ${repo}:
51621
51996
  } catch {
51622
51997
  existingSha = void 0;
51623
51998
  }
51624
- const tmp = (0, import_node_path36.join)((0, import_node_os21.tmpdir)(), `mmi-propagate-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
51999
+ const tmp = (0, import_node_path37.join)((0, import_node_os21.tmpdir)(), `mmi-propagate-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
51625
52000
  const desiredContent = desiredByRepo.get(rec.repo);
51626
52001
  if (desiredContent == null) return fail(`bootstrap propagate: no resolved content for ${rec.repo} ${seed.target} \u2014 refusing to write`);
51627
- (0, import_node_fs39.writeFileSync)(tmp, JSON.stringify(contentPutBody(seed.target, desiredContent, branch, existingSha, runbookUnaffected)), "utf8");
52002
+ (0, import_node_fs40.writeFileSync)(tmp, JSON.stringify(contentPutBody(seed.target, desiredContent, branch, existingSha, runbookUnaffected)), "utf8");
51628
52003
  try {
51629
52004
  await gh2(contentPutInputArgs(rec.repo, seed.target, tmp));
51630
52005
  } finally {
51631
52006
  try {
51632
- (0, import_node_fs39.unlinkSync)(tmp);
52007
+ (0, import_node_fs40.unlinkSync)(tmp);
51633
52008
  } catch {
51634
52009
  }
51635
52010
  }
@@ -51698,10 +52073,10 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
51698
52073
  return fail(`bootstrap rollback: ${e.message}`);
51699
52074
  }
51700
52075
  const manifestPath = "skills/bootstrap/seeds/manifest.json";
51701
- if (!(0, import_node_fs39.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)`);
52076
+ if (!(0, import_node_fs40.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)`);
51702
52077
  const seedSource = await resolveHubSeedSource(execGitForSeedSource);
51703
52078
  if (!seedSource.ok) return fail(`bootstrap rollback: ${seedSource.reason}`);
51704
- const manifest = loadBootstrapSeeds((0, import_node_fs39.readFileSync)(manifestPath, "utf8"));
52079
+ const manifest = loadBootstrapSeeds((0, import_node_fs40.readFileSync)(manifestPath, "utf8"));
51705
52080
  const propagatable = manifest.seeds.filter(isPropagatableSeed);
51706
52081
  if (!o.target) {
51707
52082
  return fail(`bootstrap rollback: --target <path> is required \u2014 one of:
@@ -51718,10 +52093,10 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
51718
52093
  const enc = (p) => p.split("/").map(encodeURIComponent).join("/");
51719
52094
  let candidates;
51720
52095
  if (o.record) {
51721
- if (!(0, import_node_fs39.existsSync)(o.record)) return fail(`bootstrap rollback: --record '${o.record}' not found`);
52096
+ if (!(0, import_node_fs40.existsSync)(o.record)) return fail(`bootstrap rollback: --record '${o.record}' not found`);
51722
52097
  let parsed;
51723
52098
  try {
51724
- parsed = JSON.parse((0, import_node_fs39.readFileSync)(o.record, "utf8"));
52099
+ parsed = JSON.parse((0, import_node_fs40.readFileSync)(o.record, "utf8"));
51725
52100
  } catch (e) {
51726
52101
  return fail(`bootstrap rollback: --record '${o.record}' is not valid JSON: ${e.message}`);
51727
52102
  }
@@ -51798,13 +52173,13 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
51798
52173
  } catch {
51799
52174
  existingSha = void 0;
51800
52175
  }
51801
- const tmp = (0, import_node_path36.join)((0, import_node_os21.tmpdir)(), `mmi-rollback-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
51802
- (0, import_node_fs39.writeFileSync)(tmp, JSON.stringify(contentPutBody(seed.target, preSeedContent, plan.branch, existingSha)), "utf8");
52176
+ const tmp = (0, import_node_path37.join)((0, import_node_os21.tmpdir)(), `mmi-rollback-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
52177
+ (0, import_node_fs40.writeFileSync)(tmp, JSON.stringify(contentPutBody(seed.target, preSeedContent, plan.branch, existingSha)), "utf8");
51803
52178
  try {
51804
52179
  await gh2(contentPutInputArgs(repo, seed.target, tmp));
51805
52180
  } finally {
51806
52181
  try {
51807
- (0, import_node_fs39.unlinkSync)(tmp);
52182
+ (0, import_node_fs40.unlinkSync)(tmp);
51808
52183
  } catch {
51809
52184
  }
51810
52185
  }
@@ -52309,8 +52684,8 @@ function formatSuiteMarkdown(report) {
52309
52684
  const lines2 = ["| Member | dev | rc | main | Pinned by suite |", "| --- | --- | --- | --- | --- |"];
52310
52685
  if (report.lead) lines2.push(`| MM-Work (suite) | ${short(report.lead.dev)} | ${report.lead.rc} | ${report.lead.main} | - |`);
52311
52686
  for (const m of report.members.slice(report.lead ? 1 : 0)) {
52312
- const [dev, rc, main] = ["dev", "rc", "main"].map((s) => m.stages.find((x) => x.stage === s));
52313
- lines2.push(`| ${m.repo.split("/")[1]} | ${cell(dev)} | ${cell(rc)} | ${cell(main)} | ${[by(rc, "rc"), by(main, "main")].filter(Boolean).join(", ") || "-"} |`);
52687
+ const [dev, rc, main2] = ["dev", "rc", "main"].map((s) => m.stages.find((x) => x.stage === s));
52688
+ lines2.push(`| ${m.repo.split("/")[1]} | ${cell(dev)} | ${cell(rc)} | ${cell(main2)} | ${[by(rc, "rc"), by(main2, "main")].filter(Boolean).join(", ") || "-"} |`);
52314
52689
  }
52315
52690
  return lines2.join("\n");
52316
52691
  }
@@ -52400,8 +52775,8 @@ async function waitSuiteDev(deps, opts) {
52400
52775
  }
52401
52776
 
52402
52777
  // src/suite-train.ts
52403
- var import_node_fs40 = require("node:fs");
52404
- var import_node_path37 = require("node:path");
52778
+ var import_node_fs41 = require("node:fs");
52779
+ var import_node_path38 = require("node:path");
52405
52780
  var import_node_crypto20 = require("node:crypto");
52406
52781
 
52407
52782
  // src/kit-version.ts
@@ -52487,7 +52862,7 @@ function suiteReleaseTag(rc) {
52487
52862
  function readSuiteCut(path2) {
52488
52863
  let raw;
52489
52864
  try {
52490
- raw = (0, import_node_fs40.readFileSync)(path2, "utf8");
52865
+ raw = (0, import_node_fs41.readFileSync)(path2, "utf8");
52491
52866
  } catch (e) {
52492
52867
  if (e.code === "ENOENT") return void 0;
52493
52868
  throw e;
@@ -52503,11 +52878,11 @@ function readSuiteCut(path2) {
52503
52878
  return record2;
52504
52879
  }
52505
52880
  function writeSuiteCut(path2, record2) {
52506
- (0, import_node_fs40.mkdirSync)((0, import_node_path37.dirname)(path2), { recursive: true });
52881
+ (0, import_node_fs41.mkdirSync)((0, import_node_path38.dirname)(path2), { recursive: true });
52507
52882
  const temp = `${path2}.${(0, import_node_crypto20.randomBytes)(8).toString("hex")}.tmp`;
52508
52883
  try {
52509
- (0, import_node_fs40.writeFileSync)(temp, JSON.stringify(record2, null, 2), { flag: "wx" });
52510
- (0, import_node_fs40.renameSync)(temp, path2);
52884
+ (0, import_node_fs41.writeFileSync)(temp, JSON.stringify(record2, null, 2), { flag: "wx" });
52885
+ (0, import_node_fs41.renameSync)(temp, path2);
52511
52886
  } catch (e) {
52512
52887
  throw new Error(`suite cut record write failed at ${path2}: ${e.message}; stop, verify the file before retrying`);
52513
52888
  }
@@ -52523,15 +52898,15 @@ function pinVersion(url) {
52523
52898
  }
52524
52899
  }
52525
52900
  async function carriedPins(deps, member, bundles) {
52526
- const main = bundles.main;
52527
- if (!main || !RELEASE_TAG.test(pinVersion(main))) throw new Error(`${member.repo}: nothing new since rc, but its MM-Work main pin ${main ?? "(none)"} has no ?v=vX.Y.Z release; pin it before the suite cut`);
52528
- if (!await deps.tagSha(member.repo, pinVersion(main))) throw new Error(`${member.repo}: nothing new since rc, but its MM-Work main pin names ${pinVersion(main)}, which was never released; release it or pin its live release before the suite cut`);
52529
- const mainPin = mainPinFor(new URL(main).host, bundles, pinVersion(main));
52530
- for (const url of [bundles.rc, main]) {
52901
+ const main2 = bundles.main;
52902
+ if (!main2 || !RELEASE_TAG.test(pinVersion(main2))) throw new Error(`${member.repo}: nothing new since rc, but its MM-Work main pin ${main2 ?? "(none)"} has no ?v=vX.Y.Z release; pin it before the suite cut`);
52903
+ if (!await deps.tagSha(member.repo, pinVersion(main2))) throw new Error(`${member.repo}: nothing new since rc, but its MM-Work main pin names ${pinVersion(main2)}, which was never released; release it or pin its live release before the suite cut`);
52904
+ const mainPin = mainPinFor(new URL(main2).host, bundles, pinVersion(main2));
52905
+ for (const url of [bundles.rc, main2]) {
52531
52906
  const tag = pinVersion(url);
52532
52907
  if (!RC_TAG.test(tag) && !RELEASE_TAG.test(tag)) continue;
52533
52908
  const sha = await deps.tagSha(member.repo, tag);
52534
- if (sha && await deps.contains(member.repo, member.development, sha)) return { rcPin: url === main ? mainPin : url, mainPin };
52909
+ if (sha && await deps.contains(member.repo, member.development, sha)) return { rcPin: url === main2 ? mainPin : url, mainPin };
52535
52910
  }
52536
52911
  throw new Error(`${member.repo}: nothing new since rc, but no pinned MM-Work bundle carries development ${member.development.slice(0, 12)}; pin it before the suite cut`);
52537
52912
  }
@@ -52556,25 +52931,25 @@ async function suiteMarkAbandoned(deps, ownerGo = false) {
52556
52931
  return tags.map((t) => `${t.repo}@${t.tag}`);
52557
52932
  }
52558
52933
  async function retireFailedLeadRcLedger(deps, ownerGo) {
52559
- if (!(0, import_node_fs40.existsSync)(deps.ledgerPath)) return void 0;
52934
+ if (!(0, import_node_fs41.existsSync)(deps.ledgerPath)) return void 0;
52560
52935
  return withLedgerLock(deps.ledgerPath, async (fence) => {
52561
- const ledger = parseReleaseLedger((0, import_node_fs40.readFileSync)(deps.ledgerPath, "utf8"));
52936
+ const ledger = parseReleaseLedger((0, import_node_fs41.readFileSync)(deps.ledgerPath, "utf8"));
52562
52937
  const states = Object.values(ledger.phases).map((p) => p.state);
52563
52938
  if (ledger.repo !== SUITE_REPO || ledger.lane !== "rcand" || ledger.phases.promotion.state === "complete" || !states.includes("failed")) return void 0;
52564
52939
  if (!ownerGo) throw new Error(`the lead's failed rcand ledger for ${ledger.tag} blocks every train; retire it with suite abandon --owner-go`);
52565
52940
  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`);
52566
- const archive = (0, import_node_path37.join)((0, import_node_path37.dirname)(deps.ledgerPath), `phases.archive-${ledger.tag}.json`);
52567
- if ((0, import_node_fs40.existsSync)(archive)) throw new Error(`ledger archive already exists at ${archive}; inspect before retiring again`);
52941
+ const archive = (0, import_node_path38.join)((0, import_node_path38.dirname)(deps.ledgerPath), `phases.archive-${ledger.tag}.json`);
52942
+ if ((0, import_node_fs41.existsSync)(archive)) throw new Error(`ledger archive already exists at ${archive}; inspect before retiring again`);
52568
52943
  await deps.markAbandoned(SUITE_REPO, ledger.tag, ledger.tagSha);
52569
- await fence(() => (0, import_node_fs40.renameSync)(deps.ledgerPath, archive));
52944
+ await fence(() => (0, import_node_fs41.renameSync)(deps.ledgerPath, archive));
52570
52945
  return `${ledger.tag} (ledger archived to ${archive})`;
52571
52946
  });
52572
52947
  }
52573
52948
  function suiteAbandon(recordPath, ownerGo = false, now = /* @__PURE__ */ new Date()) {
52574
52949
  const record2 = abandonableCut(recordPath, ownerGo);
52575
52950
  const archive = `${recordPath}.abandoned-${record2.leadDevelopment.slice(0, 12)}-${now.toISOString().replace(/[:.]/g, "")}.json`;
52576
- if ((0, import_node_fs40.existsSync)(archive)) throw new Error(`abandoned-cut archive already exists at ${archive}; inspect before abandoning again`);
52577
- (0, import_node_fs40.renameSync)(recordPath, archive);
52951
+ if ((0, import_node_fs41.existsSync)(archive)) throw new Error(`abandoned-cut archive already exists at ${archive}; inspect before abandoning again`);
52952
+ (0, import_node_fs41.renameSync)(recordPath, archive);
52578
52953
  return { archive, orphanTags: record2.members.filter((m) => m.tag).map((m) => `${m.repo}@${m.tag}`) };
52579
52954
  }
52580
52955
  async function suiteRestoreMainPins(deps) {
@@ -52661,12 +53036,12 @@ async function suiteRcandRun(deps, opts) {
52661
53036
  }
52662
53037
  if ((record2?.announcement === "sent" || record2?.announcement === "skipped") && record2.leadReleased) {
52663
53038
  const archive = `${deps.recordPath}.${record2.leadRcTag}.json`;
52664
- if ((0, import_node_fs40.existsSync)(archive)) throw new Error(`suite cut archive already exists at ${archive}; inspect before a new cut`);
52665
- (0, import_node_fs40.renameSync)(deps.recordPath, archive);
53039
+ if ((0, import_node_fs41.existsSync)(archive)) throw new Error(`suite cut archive already exists at ${archive}; inspect before a new cut`);
53040
+ (0, import_node_fs41.renameSync)(deps.recordPath, archive);
52666
53041
  record2 = void 0;
52667
53042
  }
52668
53043
  if (record2 && !record2.pinPr && !record2.leadRcTag && record2.members.every((m) => !m.tag)) {
52669
- (0, import_node_fs40.rmSync)(deps.recordPath, { force: true });
53044
+ (0, import_node_fs41.rmSync)(deps.recordPath, { force: true });
52670
53045
  record2 = void 0;
52671
53046
  }
52672
53047
  if (!record2) {
@@ -52720,7 +53095,7 @@ async function suiteRcandRun(deps, opts) {
52720
53095
  quiet.push(member);
52721
53096
  }
52722
53097
  if (record2.members.every((m) => m.carried || quiet.includes(m)) && await deps.contains(SUITE_REPO, record2.leadDevelopment, record2.leadPreviousRc)) {
52723
- (0, import_node_fs40.rmSync)(deps.recordPath, { force: true });
53098
+ (0, import_node_fs41.rmSync)(deps.recordPath, { force: true });
52724
53099
  throw new Error("nothing to promote: neither MM-Work nor any module has new development commits since its rc; no suite cut started");
52725
53100
  }
52726
53101
  for (const member of quiet) {
@@ -52738,7 +53113,7 @@ async function suiteRcandRun(deps, opts) {
52738
53113
  }
52739
53114
  if (refusals.length) {
52740
53115
  const untouched = record2.members.every((m) => !m.tag) && !record2.pinPr;
52741
- if (untouched) (0, import_node_fs40.rmSync)(deps.recordPath, { force: true });
53116
+ if (untouched) (0, import_node_fs41.rmSync)(deps.recordPath, { force: true });
52742
53117
  throw new Error(`module rc serving is not ready; ${untouched ? "no suite cut started" : "no new tag was cut"}:
52743
53118
  ${refusals.join("\n")}
52744
53119
  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).`);
@@ -52757,7 +53132,7 @@ Each module must ship a live release that bind-mounts <deployPath>/data read-onl
52757
53132
  let running = 0;
52758
53133
  const waiting = [];
52759
53134
  const results = await Promise.allSettled(record2.members.map(async (member) => {
52760
- if (running >= 4) await new Promise((resolve7) => waiting.push(resolve7));
53135
+ if (running >= 4) await new Promise((resolve8) => waiting.push(resolve8));
52761
53136
  else running++;
52762
53137
  try {
52763
53138
  if ((await deps.head(member.repo, "development"))?.toLowerCase() !== member.development.toLowerCase())
@@ -52930,11 +53305,11 @@ Each member's live release must serve <data>/main/module.js at its main pin path
52930
53305
  }
52931
53306
  return record2;
52932
53307
  }
52933
- var hotfixRecordPath = (deps) => (0, import_node_path37.join)((0, import_node_path37.dirname)(deps.recordPath), "hotfix.json");
53308
+ var hotfixRecordPath = (deps) => (0, import_node_path38.join)((0, import_node_path38.dirname)(deps.recordPath), "hotfix.json");
52934
53309
  function readSuiteHotfix(path2) {
52935
53310
  let raw;
52936
53311
  try {
52937
- raw = (0, import_node_fs40.readFileSync)(path2, "utf8");
53312
+ raw = (0, import_node_fs41.readFileSync)(path2, "utf8");
52938
53313
  } catch (e) {
52939
53314
  if (e.code === "ENOENT") return void 0;
52940
53315
  throw e;
@@ -52977,7 +53352,7 @@ async function suiteHotfix(deps, opts) {
52977
53352
  if (completed) record2 = void 0;
52978
53353
  if (record2 && record2.repo !== found.repo) throw new Error(`an unfinished suite hotfix for ${record2.repo} is recorded; finish it (rerun with that member) first`);
52979
53354
  if (!record2?.tag) await deps.validateHotfixSummary();
52980
- if (completed) (0, import_node_fs40.renameSync)(path2, `${path2}.${completed.leadTag}.json`);
53355
+ if (completed) (0, import_node_fs41.renameSync)(path2, `${path2}.${completed.leadTag}.json`);
52981
53356
  const rec = record2 ?? { schema: "mmi-suite-hotfix/v1", member: found.id, repo: found.repo, from: opts.from, ...opts.ack?.length ? { ack: opts.ack } : {} };
52982
53357
  const save = () => writeSuiteHotfix(path2, rec);
52983
53358
  save();
@@ -53245,9 +53620,9 @@ async function runRcDataSwitch(deps, opts) {
53245
53620
 
53246
53621
  // src/suite-train-io.ts
53247
53622
  var import_node_child_process19 = require("node:child_process");
53248
- var import_node_path50 = require("node:path");
53249
- var import_node_fs54 = require("node:fs");
53250
53623
  var import_node_path51 = require("node:path");
53624
+ var import_node_fs55 = require("node:fs");
53625
+ var import_node_path52 = require("node:path");
53251
53626
  init_cli_shared();
53252
53627
 
53253
53628
  // src/command-register-train-operations.ts
@@ -53428,7 +53803,7 @@ function clean3(out) {
53428
53803
  return out.trim();
53429
53804
  }
53430
53805
  function sleeper(deps) {
53431
- return deps.sleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms)));
53806
+ return deps.sleep ?? ((ms) => new Promise((resolve8) => setTimeout(resolve8, ms)));
53432
53807
  }
53433
53808
  function normalizeHotfixVersion(input) {
53434
53809
  const m = /^v?(\d+\.\d+\.\d+)$/.exec(input.trim());
@@ -54939,8 +55314,8 @@ function checkHotfixCarries(options) {
54939
55314
  }
54940
55315
 
54941
55316
  // src/merge-cleanup.ts
54942
- var import_node_fs41 = require("node:fs");
54943
- var import_node_path38 = require("node:path");
55317
+ var import_node_fs42 = require("node:fs");
55318
+ var import_node_path39 = require("node:path");
54944
55319
  var import_node_os22 = require("node:os");
54945
55320
  init_cli_shared();
54946
55321
  init_github_client();
@@ -55348,13 +55723,13 @@ function resolveSquashMergeBodyText(commits, allowedClosing, cwd) {
55348
55723
  return rewritten === base ? null : rewritten;
55349
55724
  }
55350
55725
  function writeSquashBodyFile(body) {
55351
- const dir = (0, import_node_fs41.mkdtempSync)((0, import_node_path38.join)((0, import_node_os22.tmpdir)(), "mmi-squash-body-"));
55352
- const path2 = (0, import_node_path38.join)(dir, "body.txt");
55353
- (0, import_node_fs41.writeFileSync)(path2, body.endsWith("\n") ? body : `${body}
55726
+ const dir = (0, import_node_fs42.mkdtempSync)((0, import_node_path39.join)((0, import_node_os22.tmpdir)(), "mmi-squash-body-"));
55727
+ const path2 = (0, import_node_path39.join)(dir, "body.txt");
55728
+ (0, import_node_fs42.writeFileSync)(path2, body.endsWith("\n") ? body : `${body}
55354
55729
  `, "utf8");
55355
55730
  return { path: path2, cleanup: () => {
55356
55731
  try {
55357
- (0, import_node_fs41.rmSync)(dir, { recursive: true, force: true });
55732
+ (0, import_node_fs42.rmSync)(dir, { recursive: true, force: true });
55358
55733
  } catch {
55359
55734
  }
55360
55735
  } };
@@ -55606,8 +55981,8 @@ init_github_client();
55606
55981
 
55607
55982
  // src/release-custody.ts
55608
55983
  var import_node_crypto21 = require("node:crypto");
55609
- var import_node_fs42 = require("node:fs");
55610
- var import_node_path39 = require("node:path");
55984
+ var import_node_fs43 = require("node:fs");
55985
+ var import_node_path40 = require("node:path");
55611
55986
  init_github_client();
55612
55987
 
55613
55988
  // src/release-custody-bootstrap.ts
@@ -55740,9 +56115,9 @@ async function verifyCustodyBootstrap(value, api, controller, requiredContexts,
55740
56115
  if (legacy.length > 20) reject("local evidence exceeds the bounded migration limit");
55741
56116
  const root = `repos/${HUB_RELEASE_REPO}`;
55742
56117
  const tag = await api.rest("GET", `${root}/git/ref/tags/${input.tag}`);
55743
- const main = await api.rest("GET", `${root}/git/ref/heads/main`);
56118
+ const main2 = await api.rest("GET", `${root}/git/ref/heads/main`);
55744
56119
  const release = await api.rest("GET", `${root}/releases/tags/${input.tag}`);
55745
- if (tag.object.sha !== input.tagSha || main.object.sha !== input.tagSha || release.tag_name !== input.tag || release.draft || release.prerelease || !Number.isFinite(Date.parse(release.published_at))) reject("tag, main and published Release do not identify one completed cut");
56120
+ if (tag.object.sha !== input.tagSha || main2.object.sha !== input.tagSha || release.tag_name !== input.tag || release.draft || release.prerelease || !Number.isFinite(Date.parse(release.published_at))) reject("tag, main and published Release do not identify one completed cut");
55746
56121
  const observed = {};
55747
56122
  for (const name of ["gate", "publish", "deploy", "installer", "tenant"]) {
55748
56123
  const run = await runAttempt(api, input[name]);
@@ -56077,7 +56452,7 @@ function reclassifySupersededArchives(state) {
56077
56452
  }
56078
56453
  function localRaw(path2) {
56079
56454
  try {
56080
- return (0, import_node_fs42.readFileSync)(path2, "utf8");
56455
+ return (0, import_node_fs43.readFileSync)(path2, "utf8");
56081
56456
  } catch (e) {
56082
56457
  if (e.code === "ENOENT") return null;
56083
56458
  throw e;
@@ -56086,19 +56461,19 @@ function localRaw(path2) {
56086
56461
  function hydrateLocal(path2, raw) {
56087
56462
  const previous = localRaw(path2);
56088
56463
  if (previous === raw) return;
56089
- (0, import_node_fs42.mkdirSync)((0, import_node_path39.dirname)(path2), { recursive: true });
56464
+ (0, import_node_fs43.mkdirSync)((0, import_node_path40.dirname)(path2), { recursive: true });
56090
56465
  if (previous !== null) {
56091
56466
  const ledger = parseReleaseLedger(previous);
56092
- const archive = (0, import_node_path39.join)((0, import_node_path39.dirname)(path2), `phases.local-${ledger.tagSha}-${custodyDigest(previous)}.json`);
56093
- if (!(0, import_node_fs42.existsSync)(archive)) (0, import_node_fs42.writeFileSync)(archive, previous, { flag: "wx" });
56094
- if (raw === null) (0, import_node_fs42.renameSync)(path2, `${path2}.retired-${custodyDigest(previous)}`);
56467
+ const archive = (0, import_node_path40.join)((0, import_node_path40.dirname)(path2), `phases.local-${ledger.tagSha}-${custodyDigest(previous)}.json`);
56468
+ if (!(0, import_node_fs43.existsSync)(archive)) (0, import_node_fs43.writeFileSync)(archive, previous, { flag: "wx" });
56469
+ if (raw === null) (0, import_node_fs43.renameSync)(path2, `${path2}.retired-${custodyDigest(previous)}`);
56095
56470
  }
56096
- if (raw !== null) (0, import_node_fs42.writeFileSync)(path2, raw, "utf8");
56471
+ if (raw !== null) (0, import_node_fs43.writeFileSync)(path2, raw, "utf8");
56097
56472
  }
56098
56473
  async function commandIdentity(file, args, run, repo) {
56099
56474
  if (file === "git" && args[0] === "push") {
56100
56475
  const deleting = args.includes("--delete");
56101
- const refs = args.slice(2).filter((arg) => !arg.startsWith("-"));
56476
+ const refs = args.slice(2).filter((arg2) => !arg2.startsWith("-"));
56102
56477
  const targets = [];
56103
56478
  for (const refspec of refs) {
56104
56479
  const [source, destination] = refspec.split(":");
@@ -56113,7 +56488,7 @@ async function commandIdentity(file, args, run, repo) {
56113
56488
  return { kind: "github-release", identity: { repo, tag, sha: (await run("git", ["rev-parse", `${tag}^{commit}`])).trim() } };
56114
56489
  }
56115
56490
  if (file === "gh" && args[0] === "workflow" && args[1] === "run") {
56116
- const fields = Object.fromEntries(args.flatMap((arg, i) => ["-f", "--field", "-F", "--raw-field"].includes(arg) ? [args[i + 1].split(/=(.*)/s).slice(0, 2)] : []));
56491
+ const fields = Object.fromEntries(args.flatMap((arg2, i) => ["-f", "--field", "-F", "--raw-field"].includes(arg2) ? [args[i + 1].split(/=(.*)/s).slice(0, 2)] : []));
56117
56492
  const ref = args.includes("--ref") ? args[args.indexOf("--ref") + 1] : "main";
56118
56493
  const sha = (await run("git", ["rev-parse", `origin/${ref}`])).trim();
56119
56494
  const before = JSON.parse(await run("gh", [
@@ -56130,7 +56505,7 @@ async function commandIdentity(file, args, run, repo) {
56130
56505
  return { kind: "workflow-rerun", identity: { repo, runId, attempt: prior.run_attempt + 1 } };
56131
56506
  }
56132
56507
  if (file === "gh" && !["run", "release", "pr", "api", "workflow"].includes(args[0])) return null;
56133
- const write = file === "gh" && (args[0] === "pr" && ["create", "merge", "close", "edit"].includes(args[1]) || args[0] === "release" && ["delete", "edit", "upload"].includes(args[1]) || args[0] === "api" && (args[1] === "graphql" ? args.some((arg) => /(?:^query=|^)\s*mutation\b/.test(arg)) : args.some((arg) => ["POST", "PUT", "PATCH", "DELETE"].includes(arg)) || args.includes("-f") || args.includes("-F") || args.includes("--input")));
56508
+ const write = file === "gh" && (args[0] === "pr" && ["create", "merge", "close", "edit"].includes(args[1]) || args[0] === "release" && ["delete", "edit", "upload"].includes(args[1]) || args[0] === "api" && (args[1] === "graphql" ? args.some((arg2) => /(?:^query=|^)\s*mutation\b/.test(arg2)) : args.some((arg2) => ["POST", "PUT", "PATCH", "DELETE"].includes(arg2)) || args.includes("-f") || args.includes("-F") || args.includes("--input")));
56134
56509
  return write ? { kind: "github-write", identity: { repo, command: args } } : null;
56135
56510
  }
56136
56511
  function effectObserver(api) {
@@ -56283,8 +56658,8 @@ function withHubReleaseCustody(deps) {
56283
56658
  }
56284
56659
 
56285
56660
  // src/project-info-sync.ts
56286
- var import_node_fs43 = require("node:fs");
56287
- var import_node_path40 = require("node:path");
56661
+ var import_node_fs44 = require("node:fs");
56662
+ var import_node_path41 = require("node:path");
56288
56663
  var UPDATE_PROJECT_INFO = `mutation($projectId: ID!, $shortDescription: String!, $readme: String!) {
56289
56664
  updateProjectV2(input: { projectId: $projectId, shortDescription: $shortDescription, readme: $readme }) {
56290
56665
  projectV2 { id }
@@ -56331,14 +56706,14 @@ function sharedName(entries, fallback) {
56331
56706
  }
56332
56707
  function buildProjectInfoSyncPlan(targetRepo2, project2, projects, repoRoot2) {
56333
56708
  if (!project2.projectId) throw new Error(`org project sync-info: ${targetRepo2} registry META has no projectId`);
56334
- const readmePath = (0, import_node_path40.join)(repoRoot2, "README.md");
56335
- if (!(0, import_node_fs43.existsSync)(readmePath)) throw new Error(`org project sync-info: ${targetRepo2} has no README.md`);
56709
+ const readmePath = (0, import_node_path41.join)(repoRoot2, "README.md");
56710
+ if (!(0, import_node_fs44.existsSync)(readmePath)) throw new Error(`org project sync-info: ${targetRepo2} has no README.md`);
56336
56711
  const entries = entriesFor(project2, projects);
56337
56712
  const memberRepos = [...new Set(entries.flatMap((entry) => entry.repos ?? []))].filter((repo) => /^[^/]+\/[^/]+$/.test(repo)).sort((a, b) => a.localeCompare(b));
56338
56713
  const projectName = sharedName(entries, project2.name?.trim() || targetRepo2.split("/").pop() || targetRepo2);
56339
56714
  if (!memberRepos.length) throw new Error(`org project sync-info: project ${projectName} has no registered member repos`);
56340
56715
  const entryNames = entries.map((entry) => entry.name?.trim()).filter((name) => Boolean(name));
56341
- const shortDescription = memberRepos.length === 1 ? shortDescriptionFromReadme((0, import_node_fs43.readFileSync)(readmePath, "utf8")) : `Shared work across ${new Intl.ListFormat("en", { type: "conjunction" }).format(entryNames)}.`;
56716
+ const shortDescription = memberRepos.length === 1 ? shortDescriptionFromReadme((0, import_node_fs44.readFileSync)(readmePath, "utf8")) : `Shared work across ${new Intl.ListFormat("en", { type: "conjunction" }).format(entryNames)}.`;
56342
56717
  const lines2 = [
56343
56718
  `# ${projectName}`,
56344
56719
  "",
@@ -56357,8 +56732,8 @@ function buildProjectInfoSyncPlan(targetRepo2, project2, projects, repoRoot2) {
56357
56732
  const targetBase = `https://github.com/${targetRepo2}`;
56358
56733
  const targetBranch = branchFor(targetRepo2, projects);
56359
56734
  const orgDocs = [
56360
- (0, import_node_fs43.existsSync)((0, import_node_path40.join)(repoRoot2, "architecture.md")) ? `- [Hub architecture](${targetBase}/blob/${targetBranch}/architecture.md)` : "",
56361
- (0, import_node_fs43.existsSync)((0, import_node_path40.join)(repoRoot2, "docs", "Architecture", "agentic-dev-environment.md")) ? `- [Agentic development environment](${targetBase}/blob/${targetBranch}/docs/Architecture/agentic-dev-environment.md)` : ""
56735
+ (0, import_node_fs44.existsSync)((0, import_node_path41.join)(repoRoot2, "architecture.md")) ? `- [Hub architecture](${targetBase}/blob/${targetBranch}/architecture.md)` : "",
56736
+ (0, import_node_fs44.existsSync)((0, import_node_path41.join)(repoRoot2, "docs", "Architecture", "agentic-dev-environment.md")) ? `- [Agentic development environment](${targetBase}/blob/${targetBranch}/docs/Architecture/agentic-dev-environment.md)` : ""
56362
56737
  ].filter(Boolean);
56363
56738
  if (orgDocs.length) lines2.push("", "## Organisation docs", "", ...orgDocs);
56364
56739
  return { projectId: project2.projectId, projectName, targetRepo: targetRepo2, memberRepos, shortDescription, readme: `${lines2.join("\n")}
@@ -56380,8 +56755,8 @@ async function syncProjectInfo(plan, client, apply) {
56380
56755
  }
56381
56756
 
56382
56757
  // src/train-commands.ts
56383
- var import_node_fs44 = require("node:fs");
56384
- var import_node_path41 = require("node:path");
56758
+ var import_node_fs45 = require("node:fs");
56759
+ var import_node_path42 = require("node:path");
56385
56760
  init_cli_shared();
56386
56761
  init_clean_exit();
56387
56762
  init_client_version();
@@ -56396,7 +56771,7 @@ function resolveReleaseBumpIntent(raw) {
56396
56771
  }
56397
56772
  function readRepoVersion() {
56398
56773
  try {
56399
- return JSON.parse((0, import_node_fs44.readFileSync)((0, import_node_path41.join)(process.cwd(), ".claude-plugin", "plugin.json"), "utf8")).version || void 0;
56774
+ return JSON.parse((0, import_node_fs45.readFileSync)((0, import_node_path42.join)(process.cwd(), ".claude-plugin", "plugin.json"), "utf8")).version || void 0;
56400
56775
  } catch {
56401
56776
  return void 0;
56402
56777
  }
@@ -56507,7 +56882,7 @@ function releaseProgressVerdict(status, subject = "Release") {
56507
56882
 
56508
56883
  // src/suite-pin.ts
56509
56884
  var import_promises6 = require("node:fs/promises");
56510
- var import_node_path42 = require("node:path");
56885
+ var import_node_path43 = require("node:path");
56511
56886
  var SuitePinError = class _SuitePinError extends Error {
56512
56887
  diagnostic;
56513
56888
  constructor(repo, tag, error) {
@@ -56575,8 +56950,8 @@ async function openSuiteCutPinPr(deps, input) {
56575
56950
  if (input.carriedOnly) return { status: "unchanged" };
56576
56951
  throw new Error("pins already match without a merged cut PR \u2014 provenance unverified");
56577
56952
  }
56578
- await (0, import_promises6.mkdir)((0, import_node_path42.join)(deps.root, "tmp"), { recursive: true });
56579
- scratch = await (0, import_promises6.mkdtemp)((0, import_node_path42.join)(deps.root, "tmp", "suite-pin-"));
56953
+ await (0, import_promises6.mkdir)((0, import_node_path43.join)(deps.root, "tmp"), { recursive: true });
56954
+ scratch = await (0, import_promises6.mkdtemp)((0, import_node_path43.join)(deps.root, "tmp", "suite-pin-"));
56580
56955
  const run = (file, args) => deps.run(file, args, scratch);
56581
56956
  await run("git", ["clone", "--quiet", "--branch", prs.length ? branch : "development", "--single-branch", `https://github.com/${SUITE_REPO}.git`, "."]);
56582
56957
  if (prs.length) {
@@ -56588,7 +56963,7 @@ async function openSuiteCutPinPr(deps, input) {
56588
56963
  await run("git", ["switch", "-c", branch]);
56589
56964
  }
56590
56965
  for (const stage of ["rc", "main"]) {
56591
- const path2 = (0, import_node_path42.join)(scratch, `${stage}-pins.json`);
56966
+ const path2 = (0, import_node_path43.join)(scratch, `${stage}-pins.json`);
56592
56967
  await (0, import_promises6.writeFile)(path2, JSON.stringify(input.pins.map((p) => ({ module: p.module, url: p[stage] }))));
56593
56968
  await run("node", ["scripts/pin-modules.mjs", "--stage", stage, "--pins", path2]);
56594
56969
  }
@@ -56641,12 +57016,12 @@ async function openSuiteRestorePinPr(deps, input) {
56641
57016
  }
56642
57017
  });
56643
57018
  if (!todo.length) return void 0;
56644
- await (0, import_promises6.mkdir)((0, import_node_path42.join)(deps.root, "tmp"), { recursive: true });
56645
- scratch = await (0, import_promises6.mkdtemp)((0, import_node_path42.join)(deps.root, "tmp", "suite-pin-"));
57019
+ await (0, import_promises6.mkdir)((0, import_node_path43.join)(deps.root, "tmp"), { recursive: true });
57020
+ scratch = await (0, import_promises6.mkdtemp)((0, import_node_path43.join)(deps.root, "tmp", "suite-pin-"));
56646
57021
  const run = (file, args) => deps.run(file, args, scratch);
56647
57022
  await run("git", ["clone", "--quiet", "--branch", "development", "--single-branch", `https://github.com/${SUITE_REPO}.git`, "."]);
56648
57023
  await run("git", ["switch", "-c", branch]);
56649
- const path2 = (0, import_node_path42.join)(scratch, "main-pins.json");
57024
+ const path2 = (0, import_node_path43.join)(scratch, "main-pins.json");
56650
57025
  await (0, import_promises6.writeFile)(path2, JSON.stringify(todo.map((p) => ({ module: p.module, url: p.prior }))));
56651
57026
  await run("node", ["scripts/pin-modules.mjs", "--stage", "main", "--pins", path2]);
56652
57027
  await run("git", ["add", "seed/modules.json"]);
@@ -56720,8 +57095,8 @@ async function openSuitePinPr(deps, input) {
56720
57095
  if (newer.length) return { status: "superseded", pr: newer[0].url, url: pin };
56721
57096
  const open2 = onBranch.find((p) => p.state === "OPEN");
56722
57097
  if (open2 && tagOf(open2.title ?? "") === tag) return { status: "pending", pr: open2.url, url: pin };
56723
- await (0, import_promises6.mkdir)((0, import_node_path42.join)(deps.root, "tmp"), { recursive: true });
56724
- scratch = await (0, import_promises6.mkdtemp)((0, import_node_path42.join)(deps.root, "tmp", "suite-pin-"));
57098
+ await (0, import_promises6.mkdir)((0, import_node_path43.join)(deps.root, "tmp"), { recursive: true });
57099
+ scratch = await (0, import_promises6.mkdtemp)((0, import_node_path43.join)(deps.root, "tmp", "suite-pin-"));
56725
57100
  const run = (file, args) => deps.run(file, args, scratch);
56726
57101
  await run("git", ["clone", "--quiet", "--branch", "development", "--single-branch", `https://github.com/${SUITE_REPO}.git`, "."]);
56727
57102
  await run("git", ["switch", "-c", branch]);
@@ -56773,7 +57148,7 @@ function prTitleRefusal(title) {
56773
57148
 
56774
57149
  // src/command-register-collaboration.ts
56775
57150
  var import_node_child_process18 = require("node:child_process");
56776
- var import_node_fs53 = require("node:fs");
57151
+ var import_node_fs54 = require("node:fs");
56777
57152
  var import_promises8 = require("node:fs/promises");
56778
57153
  init_clean_exit();
56779
57154
  init_cli_shared();
@@ -56797,7 +57172,7 @@ function spawnDetachedSelf(args, deps, opts = {}) {
56797
57172
  }
56798
57173
 
56799
57174
  // src/command-register-collaboration.ts
56800
- var import_node_path49 = require("node:path");
57175
+ var import_node_path50 = require("node:path");
56801
57176
  init_house_map();
56802
57177
 
56803
57178
  // src/issue-body.ts
@@ -56914,7 +57289,7 @@ init_github_client();
56914
57289
  init_github_quota();
56915
57290
 
56916
57291
  // src/issue-commands.ts
56917
- var import_node_fs45 = require("node:fs");
57292
+ var import_node_fs46 = require("node:fs");
56918
57293
  var import_node_crypto22 = require("node:crypto");
56919
57294
  init_cli_shared();
56920
57295
  init_clean_exit();
@@ -57107,7 +57482,7 @@ async function editIssue(client, options, deps = {}) {
57107
57482
  const url = `https://github.com/${repo}/issues/${parsed.number}`;
57108
57483
  const patch = {};
57109
57484
  let bodyChanged = false;
57110
- const textDeps = () => deps.textDeps ?? { readFile: (p, e) => Promise.resolve((0, import_node_fs45.readFileSync)(p, e)), readStdin: () => Promise.resolve("") };
57485
+ const textDeps = () => deps.textDeps ?? { readFile: (p, e) => Promise.resolve((0, import_node_fs46.readFileSync)(p, e)), readStdin: () => Promise.resolve("") };
57111
57486
  if (options.titleFile !== void 0) {
57112
57487
  patch.title = await resolveIssueTitle({ title: options.title, titleFile: options.titleFile }, textDeps());
57113
57488
  } else if (options.title !== void 0) {
@@ -57774,7 +58149,7 @@ function extendCreateCommand(issue, batchAttach) {
57774
58149
  if (opts.batch) {
57775
58150
  let specs;
57776
58151
  try {
57777
- const raw = (0, import_node_fs45.readFileSync)(opts.batch, "utf8");
58152
+ const raw = (0, import_node_fs46.readFileSync)(opts.batch, "utf8");
57778
58153
  specs = JSON.parse(raw);
57779
58154
  if (!Array.isArray(specs)) {
57780
58155
  const top = specs === null ? "null" : typeof specs === "object" ? `an object with keys: ${Object.keys(specs).join(", ") || "(none)"}` : `a ${typeof specs}`;
@@ -57851,8 +58226,8 @@ ${lines2}`, {
57851
58226
  }
57852
58227
 
57853
58228
  // src/post-merge-recon.ts
57854
- var import_node_fs46 = require("node:fs");
57855
- var import_node_path43 = require("node:path");
58229
+ var import_node_fs47 = require("node:fs");
58230
+ var import_node_path44 = require("node:path");
57856
58231
 
57857
58232
  // src/cross-repo-filing-issue.ts
57858
58233
  init_github_client();
@@ -58022,16 +58397,16 @@ function buildPostMergeReconRecovery(input) {
58022
58397
  }
58023
58398
  function writePostMergeReconRecovery(cwd, recovery) {
58024
58399
  const path2 = postMergeReconStatePath(cwd, recovery.repo, recovery.pr);
58025
- (0, import_node_fs46.mkdirSync)((0, import_node_path43.dirname)(path2), { recursive: true });
58026
- (0, import_node_fs46.writeFileSync)(path2, `${JSON.stringify(recovery, null, 2)}
58400
+ (0, import_node_fs47.mkdirSync)((0, import_node_path44.dirname)(path2), { recursive: true });
58401
+ (0, import_node_fs47.writeFileSync)(path2, `${JSON.stringify(recovery, null, 2)}
58027
58402
  `, "utf8");
58028
58403
  return path2;
58029
58404
  }
58030
58405
  function clearPostMergeReconRecovery(cwd, repo, pr) {
58031
58406
  const path2 = postMergeReconStatePath(cwd, repo, pr);
58032
- if (!(0, import_node_fs46.existsSync)(path2)) return;
58407
+ if (!(0, import_node_fs47.existsSync)(path2)) return;
58033
58408
  try {
58034
- (0, import_node_fs46.unlinkSync)(path2);
58409
+ (0, import_node_fs47.unlinkSync)(path2);
58035
58410
  } catch {
58036
58411
  }
58037
58412
  }
@@ -58066,7 +58441,7 @@ var import_promises7 = require("node:fs/promises");
58066
58441
  init_cli_shared();
58067
58442
 
58068
58443
  // src/api-read.ts
58069
- var import_node_fs47 = require("node:fs");
58444
+ var import_node_fs48 = require("node:fs");
58070
58445
  init_cli_shared();
58071
58446
  var API_ACCEPT_HEADERS = {
58072
58447
  json: "application/vnd.github+json",
@@ -58331,7 +58706,7 @@ function registerApiReadCommands(program3, overrides) {
58331
58706
  if (req.workflowRuns) body = sliceWorkflowRunsPage(body, req.workflowRuns);
58332
58707
  if (o.jq !== void 0) body = await jqRun(o.jq, body, localJqEnv(), ...bindings.length ? [bindings] : []);
58333
58708
  if (zip) {
58334
- (0, import_node_fs47.writeFileSync)(o.out, body, "latin1");
58709
+ (0, import_node_fs48.writeFileSync)(o.out, body, "latin1");
58335
58710
  return;
58336
58711
  }
58337
58712
  } catch (e) {
@@ -59872,9 +60247,9 @@ function registerPrLifecycleCommands(program3) {
59872
60247
 
59873
60248
  // src/review-verdict.ts
59874
60249
  var import_node_child_process15 = require("node:child_process");
59875
- var import_node_fs48 = require("node:fs");
60250
+ var import_node_fs49 = require("node:fs");
59876
60251
  var import_node_os24 = require("node:os");
59877
- var import_node_path44 = require("node:path");
60252
+ var import_node_path45 = require("node:path");
59878
60253
  init_cli_shared();
59879
60254
  var REVIEW_VERDICT_MARKER = "<!-- zeroci-review v1 -->";
59880
60255
  var REVIEW_VERDICTS = ["PROCEED", "CORRECT", "ESCALATE"];
@@ -59970,7 +60345,7 @@ async function checkPrReview(number, repo, head, deps = {
59970
60345
  }
59971
60346
  }
59972
60347
  function computePrPatchId(number, repo) {
59973
- return new Promise((resolve7, reject2) => {
60348
+ return new Promise((resolve8, reject2) => {
59974
60349
  const gh2 = (0, import_node_child_process15.spawn)("gh", ["pr", "diff", number, "--repo", repo], { windowsHide: true, stdio: ["ignore", "pipe", "pipe"] });
59975
60350
  const git3 = (0, import_node_child_process15.spawn)("git", ["patch-id", "--stable"], { windowsHide: true, stdio: ["pipe", "pipe", "pipe"] });
59976
60351
  let out = "";
@@ -60008,7 +60383,7 @@ function computePrPatchId(number, repo) {
60008
60383
  if (gitCode !== 0) return reject2(new Error(`git patch-id --stable exited ${gitCode}: ${gitErr.trim()}`));
60009
60384
  const id = out.trim().split(/\s+/)[0];
60010
60385
  if (!/^[0-9a-f]{40}$/.test(id ?? "")) return reject2(new Error(`patch-id: PR #${number} diff is empty or unreadable (gh: ${ghErr.trim() || "no stderr"})`));
60011
- resolve7(id);
60386
+ resolve8(id);
60012
60387
  };
60013
60388
  gh2.on("close", (code) => {
60014
60389
  ghCode = code;
@@ -60039,15 +60414,15 @@ async function readPrIssueComments(number, repo) {
60039
60414
  return comments;
60040
60415
  }
60041
60416
  async function postPrCommentFromFile(number, repo, body) {
60042
- const dir = (0, import_node_fs48.mkdtempSync)((0, import_node_path44.join)((0, import_node_os24.tmpdir)(), "mmi-review-verdict-"));
60043
- const path2 = (0, import_node_path44.join)(dir, "body.md");
60417
+ const dir = (0, import_node_fs49.mkdtempSync)((0, import_node_path45.join)((0, import_node_os24.tmpdir)(), "mmi-review-verdict-"));
60418
+ const path2 = (0, import_node_path45.join)(dir, "body.md");
60044
60419
  try {
60045
- (0, import_node_fs48.writeFileSync)(path2, body, "utf8");
60420
+ (0, import_node_fs49.writeFileSync)(path2, body, "utf8");
60046
60421
  const { stdout } = await execFileP("gh", ["pr", "comment", number, "--repo", repo, "--body-file", path2], { timeout: GH_MUTATION_TIMEOUT_MS });
60047
60422
  return stdout.trim();
60048
60423
  } finally {
60049
60424
  try {
60050
- (0, import_node_fs48.rmSync)(dir, { recursive: true, force: true });
60425
+ (0, import_node_fs49.rmSync)(dir, { recursive: true, force: true });
60051
60426
  } catch {
60052
60427
  }
60053
60428
  }
@@ -60202,7 +60577,7 @@ init_cli_shared();
60202
60577
  var GIT_TIMEOUT_MS2 = 15e3;
60203
60578
  function catFileBatch(root, ref, paths) {
60204
60579
  if (paths.length === 0) return Promise.resolve([]);
60205
- return new Promise((resolve7) => {
60580
+ return new Promise((resolve8) => {
60206
60581
  const chunks = [];
60207
60582
  let settled2 = false;
60208
60583
  const child2 = (0, import_node_child_process16.spawn)("git", ["-C", root, "cat-file", "--batch", "--buffer"], { windowsHide: true });
@@ -60210,7 +60585,7 @@ function catFileBatch(root, ref, paths) {
60210
60585
  if (settled2) return;
60211
60586
  settled2 = true;
60212
60587
  clearTimeout(timer);
60213
- resolve7(ok ? parseCatFileBatch(Buffer.concat(chunks), paths.length) : []);
60588
+ resolve8(ok ? parseCatFileBatch(Buffer.concat(chunks), paths.length) : []);
60214
60589
  };
60215
60590
  const timer = setTimeout(() => {
60216
60591
  child2.kill("SIGKILL");
@@ -60460,18 +60835,18 @@ function createPreparationDeps(input, io = {}) {
60460
60835
  }
60461
60836
 
60462
60837
  // src/worktree-residue-sweep.ts
60463
- var import_node_fs52 = require("node:fs");
60464
- var import_node_path48 = require("node:path");
60838
+ var import_node_fs53 = require("node:fs");
60839
+ var import_node_path49 = require("node:path");
60465
60840
 
60466
60841
  // src/worktree-merge-cleanup.ts
60467
- var import_node_fs51 = require("node:fs");
60468
- var import_node_path47 = require("node:path");
60842
+ var import_node_fs52 = require("node:fs");
60843
+ var import_node_path48 = require("node:path");
60469
60844
  init_cli_shared();
60470
60845
 
60471
60846
  // src/stage-runner.ts
60472
60847
  var import_node_child_process17 = require("node:child_process");
60473
- var import_node_fs50 = require("node:fs");
60474
- var import_node_path46 = require("node:path");
60848
+ var import_node_fs51 = require("node:fs");
60849
+ var import_node_path47 = require("node:path");
60475
60850
  var import_node_net = require("node:net");
60476
60851
  var import_node_util5 = require("node:util");
60477
60852
 
@@ -60481,8 +60856,8 @@ function normalizeEol2(s) {
60481
60856
  }
60482
60857
 
60483
60858
  // src/env-detection.ts
60484
- var import_node_fs49 = require("node:fs");
60485
- var import_node_path45 = require("node:path");
60859
+ var import_node_fs50 = require("node:fs");
60860
+ var import_node_path46 = require("node:path");
60486
60861
  var SKIPPED_DIRS = /* @__PURE__ */ new Set([".git", "node_modules", "dist", ".jerv", ".pi", ".venv", "venv"]);
60487
60862
  function isEnvBaseName(name) {
60488
60863
  return name.toLowerCase() === ".env";
@@ -60492,7 +60867,7 @@ function findEnvFiles(root) {
60492
60867
  const walk2 = (dir, rel) => {
60493
60868
  let entries;
60494
60869
  try {
60495
- entries = (0, import_node_fs49.readdirSync)(dir, { withFileTypes: true });
60870
+ entries = (0, import_node_fs50.readdirSync)(dir, { withFileTypes: true });
60496
60871
  } catch {
60497
60872
  return;
60498
60873
  }
@@ -60500,13 +60875,13 @@ function findEnvFiles(root) {
60500
60875
  const relPath = rel ? `${rel}/${entry.name}` : entry.name;
60501
60876
  if (entry.isDirectory()) {
60502
60877
  if (SKIPPED_DIRS.has(entry.name)) continue;
60503
- walk2((0, import_node_path45.join)(dir, entry.name), relPath);
60878
+ walk2((0, import_node_path46.join)(dir, entry.name), relPath);
60504
60879
  continue;
60505
60880
  }
60506
60881
  if (isEnvBaseName(entry.name)) {
60507
60882
  let isDir = false;
60508
60883
  try {
60509
- isDir = (0, import_node_fs49.lstatSync)((0, import_node_path45.join)(dir, entry.name)).isDirectory();
60884
+ isDir = (0, import_node_fs50.lstatSync)((0, import_node_path46.join)(dir, entry.name)).isDirectory();
60510
60885
  } catch {
60511
60886
  }
60512
60887
  if (!isDir) found.push(relPath);
@@ -60645,12 +61020,12 @@ var DOCKER_TIMEOUT_MS = 15e3;
60645
61020
  function stageBash() {
60646
61021
  if (process.platform !== "win32") return "bash";
60647
61022
  const configured = process.env.SHELL;
60648
- if (configured && (0, import_node_path46.isAbsolute)(configured) && /[/\\]bash(?:\.exe)?$/i.test(configured) && !/[/\\](?:System32|Sysnative)[/\\]bash(?:\.exe)?$/i.test(configured) && (0, import_node_fs50.existsSync)(configured)) return configured;
61023
+ if (configured && (0, import_node_path47.isAbsolute)(configured) && /[/\\]bash(?:\.exe)?$/i.test(configured) && !/[/\\](?:System32|Sysnative)[/\\]bash(?:\.exe)?$/i.test(configured) && (0, import_node_fs51.existsSync)(configured)) return configured;
60649
61024
  const candidates = [
60650
- (0, import_node_path46.join)(process.env.ProgramFiles || "C:\\Program Files", "Git", "bin", "bash.exe"),
60651
- ...process.env.LOCALAPPDATA ? [(0, import_node_path46.join)(process.env.LOCALAPPDATA, "Programs", "Git", "bin", "bash.exe")] : []
61025
+ (0, import_node_path47.join)(process.env.ProgramFiles || "C:\\Program Files", "Git", "bin", "bash.exe"),
61026
+ ...process.env.LOCALAPPDATA ? [(0, import_node_path47.join)(process.env.LOCALAPPDATA, "Programs", "Git", "bin", "bash.exe")] : []
60652
61027
  ];
60653
- const bash = candidates.find((path2) => (0, import_node_fs50.existsSync)(path2));
61028
+ const bash = candidates.find((path2) => (0, import_node_fs51.existsSync)(path2));
60654
61029
  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.");
60655
61030
  return bash;
60656
61031
  }
@@ -60671,7 +61046,7 @@ function healthPollIntervalMs() {
60671
61046
  return HEALTH_POLL_INTERVAL_MS;
60672
61047
  }
60673
61048
  function waitForProcessStability(child2, graceMs = earlyExitGraceMs()) {
60674
- return new Promise((resolve7, reject2) => {
61049
+ return new Promise((resolve8, reject2) => {
60675
61050
  let settled2 = false;
60676
61051
  const finish = (fn) => {
60677
61052
  if (settled2) return;
@@ -60681,7 +61056,7 @@ function waitForProcessStability(child2, graceMs = earlyExitGraceMs()) {
60681
61056
  child2.removeAllListeners("exit");
60682
61057
  fn();
60683
61058
  };
60684
- const timer = setTimeout(() => finish(resolve7), graceMs);
61059
+ const timer = setTimeout(() => finish(resolve8), graceMs);
60685
61060
  child2.on("error", (err) => finish(() => reject2(new Error(`stage process failed to start: ${err.message}`))));
60686
61061
  child2.on("exit", (code, signal) => {
60687
61062
  const detail = code != null ? `code ${code}` : signal ? `signal ${signal}` : "unknown reason";
@@ -60788,7 +61163,7 @@ function appendForceRecreate(up) {
60788
61163
  return `${up.trimEnd()} --force-recreate`;
60789
61164
  }
60790
61165
  function stageStatePath(cwd = process.cwd()) {
60791
- return (0, import_node_path46.join)(cwd, "tmp", "stage", "state.json");
61166
+ return (0, import_node_path47.join)(cwd, "tmp", "stage", "state.json");
60792
61167
  }
60793
61168
  function normPath(path2) {
60794
61169
  return path2.replace(/\\/g, "/").replace(/\/+$/, "").toLowerCase();
@@ -60874,10 +61249,10 @@ function pickStagePort(range, isFree) {
60874
61249
  throw new Error(`no free stage port in range ${start}-${end} \u2014 every port is in use`);
60875
61250
  }
60876
61251
  function isPortFree(port) {
60877
- return new Promise((resolve7) => {
61252
+ return new Promise((resolve8) => {
60878
61253
  const srv = (0, import_node_net.createServer)();
60879
- srv.once("error", () => resolve7(false));
60880
- srv.once("listening", () => srv.close(() => resolve7(true)));
61254
+ srv.once("error", () => resolve8(false));
61255
+ srv.once("listening", () => srv.close(() => resolve8(true)));
60881
61256
  srv.listen(port, "127.0.0.1");
60882
61257
  });
60883
61258
  }
@@ -61005,8 +61380,8 @@ function stageProcessEnv(stagePort, extraEnv) {
61005
61380
  }
61006
61381
  function composeResolvesPort(cwd) {
61007
61382
  if (process.env.PORT) return true;
61008
- const envFile = (0, import_node_path46.join)(cwd, ".env");
61009
- return (0, import_node_fs50.existsSync)(envFile) && envFileKeys((0, import_node_fs50.readFileSync)(envFile, "utf8")).has("PORT");
61383
+ const envFile = (0, import_node_path47.join)(cwd, ".env");
61384
+ return (0, import_node_fs51.existsSync)(envFile) && envFileKeys((0, import_node_fs51.readFileSync)(envFile, "utf8")).has("PORT");
61010
61385
  }
61011
61386
  function stageComposeEnv(config, stagePort, vaultEnvMerge, cwd) {
61012
61387
  const composeProject = config.env?.COMPOSE_PROJECT_NAME ?? vaultEnvMerge?.COMPOSE_PROJECT_NAME ?? stageComposeProjectName(cwd);
@@ -61021,13 +61396,13 @@ function stageComposeEnv(config, stagePort, vaultEnvMerge, cwd) {
61021
61396
  function stageComposeFiles(cwd) {
61022
61397
  const files = ["docker-compose.yml"];
61023
61398
  for (const conventional of ["docker-compose.override.yml", "docker-compose.override.yaml"]) {
61024
- if ((0, import_node_fs50.existsSync)((0, import_node_path46.join)(cwd, conventional))) files.push(conventional);
61399
+ if ((0, import_node_fs51.existsSync)((0, import_node_path47.join)(cwd, conventional))) files.push(conventional);
61025
61400
  }
61026
61401
  return [...files, RUNTIME_ENV_OVERRIDE_RELPATH];
61027
61402
  }
61028
61403
  async function prepareRuntimeEnvPassthrough(cwd, composeEnv, vaultEnvMerge) {
61029
61404
  const keys = Object.keys(vaultEnvMerge ?? {});
61030
- if (!keys.length || !(0, import_node_fs50.existsSync)((0, import_node_path46.join)(cwd, "docker-compose.yml"))) return {};
61405
+ if (!keys.length || !(0, import_node_fs51.existsSync)((0, import_node_path47.join)(cwd, "docker-compose.yml"))) return {};
61031
61406
  let configJson;
61032
61407
  try {
61033
61408
  const { stdout } = await execFileP3("docker", ["compose", "config", "--format", "json"], {
@@ -61043,21 +61418,21 @@ async function prepareRuntimeEnvPassthrough(cwd, composeEnv, vaultEnvMerge) {
61043
61418
  }
61044
61419
  const body = renderRuntimeEnvOverride(runtimeEnvMarkedServices(configJson), keys, runtimeEnvExcludes(configJson), runtimeEnvSelects(configJson));
61045
61420
  if (!body) return {};
61046
- const overridePath = (0, import_node_path46.join)(cwd, RUNTIME_ENV_OVERRIDE_RELPATH);
61047
- (0, import_node_fs50.mkdirSync)((0, import_node_path46.join)(cwd, "tmp", "stage"), { recursive: true });
61048
- (0, import_node_fs50.writeFileSync)(overridePath, body, "utf8");
61421
+ const overridePath = (0, import_node_path47.join)(cwd, RUNTIME_ENV_OVERRIDE_RELPATH);
61422
+ (0, import_node_fs51.mkdirSync)((0, import_node_path47.join)(cwd, "tmp", "stage"), { recursive: true });
61423
+ (0, import_node_fs51.writeFileSync)(overridePath, body, "utf8");
61049
61424
  return stageComposeFileEnv(stageComposeFiles(cwd));
61050
61425
  }
61051
61426
  async function ensureStageRuntimeEnv(config, opts, cwd) {
61052
61427
  if (!config.ensureEnv) return;
61053
- const target = (0, import_node_path46.join)(cwd, config.ensureEnv.target);
61054
- const example = (0, import_node_path46.join)(cwd, config.ensureEnv.example);
61055
- if (!(0, import_node_fs50.existsSync)(target) && (0, import_node_fs50.existsSync)(example)) {
61056
- (0, import_node_fs50.copyFileSync)(example, target);
61057
- } else if ((0, import_node_fs50.existsSync)(target) && (0, import_node_fs50.existsSync)(example)) {
61058
- const stale = detectStaleEnvFile((0, import_node_fs50.readFileSync)(example, "utf8"), (0, import_node_fs50.readFileSync)(target, "utf8"), {
61059
- exampleMtimeMs: (0, import_node_fs50.statSync)(example).mtimeMs,
61060
- targetMtimeMs: (0, import_node_fs50.statSync)(target).mtimeMs
61428
+ const target = (0, import_node_path47.join)(cwd, config.ensureEnv.target);
61429
+ const example = (0, import_node_path47.join)(cwd, config.ensureEnv.example);
61430
+ if (!(0, import_node_fs51.existsSync)(target) && (0, import_node_fs51.existsSync)(example)) {
61431
+ (0, import_node_fs51.copyFileSync)(example, target);
61432
+ } else if ((0, import_node_fs51.existsSync)(target) && (0, import_node_fs51.existsSync)(example)) {
61433
+ const stale = detectStaleEnvFile((0, import_node_fs51.readFileSync)(example, "utf8"), (0, import_node_fs51.readFileSync)(target, "utf8"), {
61434
+ exampleMtimeMs: (0, import_node_fs51.statSync)(example).mtimeMs,
61435
+ targetMtimeMs: (0, import_node_fs51.statSync)(target).mtimeMs
61061
61436
  });
61062
61437
  if (stale) {
61063
61438
  const msg = `stale ${config.ensureEnv.target} (${stale}) \u2014 delete it or refresh from ${config.ensureEnv.example} before re-running mmi-cli stage`;
@@ -61065,8 +61440,8 @@ async function ensureStageRuntimeEnv(config, opts, cwd) {
61065
61440
  console.error(`mmi-cli stage: ${msg} (allowed via --allow-stale-env)`);
61066
61441
  }
61067
61442
  }
61068
- if (opts.vaultEnvMerge && Object.keys(opts.vaultEnvMerge).length && (0, import_node_fs50.existsSync)(target)) {
61069
- (0, import_node_fs50.writeFileSync)(target, mergeEnvSecretsIntoFile((0, import_node_fs50.readFileSync)(target, "utf8"), opts.vaultEnvMerge), "utf8");
61443
+ if (opts.vaultEnvMerge && Object.keys(opts.vaultEnvMerge).length && (0, import_node_fs51.existsSync)(target)) {
61444
+ (0, import_node_fs51.writeFileSync)(target, mergeEnvSecretsIntoFile((0, import_node_fs51.readFileSync)(target, "utf8"), opts.vaultEnvMerge), "utf8");
61070
61445
  }
61071
61446
  }
61072
61447
  async function gitText(cwd, args) {
@@ -61096,20 +61471,20 @@ async function resolveGlobalStatePath(cwd, explicit) {
61096
61471
  return void 0;
61097
61472
  }
61098
61473
  function readState(path2) {
61099
- if (!(0, import_node_fs50.existsSync)(path2)) return null;
61474
+ if (!(0, import_node_fs51.existsSync)(path2)) return null;
61100
61475
  try {
61101
- return JSON.parse((0, import_node_fs50.readFileSync)(path2, "utf8"));
61476
+ return JSON.parse((0, import_node_fs51.readFileSync)(path2, "utf8"));
61102
61477
  } catch {
61103
61478
  return null;
61104
61479
  }
61105
61480
  }
61106
61481
  function mkdirFor(path2) {
61107
61482
  const dir = path2.slice(0, Math.max(path2.lastIndexOf("/"), path2.lastIndexOf("\\")));
61108
- (0, import_node_fs50.mkdirSync)(dir, { recursive: true });
61483
+ (0, import_node_fs51.mkdirSync)(dir, { recursive: true });
61109
61484
  }
61110
61485
  function writeState(path2, state) {
61111
61486
  mkdirFor(path2);
61112
- (0, import_node_fs50.writeFileSync)(path2, JSON.stringify(state, null, 2), "utf8");
61487
+ (0, import_node_fs51.writeFileSync)(path2, JSON.stringify(state, null, 2), "utf8");
61113
61488
  }
61114
61489
  function writeStagePortReservation(port, cwd, statePath, globalStatePath, now) {
61115
61490
  const reservation = {
@@ -61138,7 +61513,7 @@ async function cleanupStageState(state, paths, timeoutMs, fallbackCwd, currentEn
61138
61513
  );
61139
61514
  }
61140
61515
  for (const path2 of [...new Set(paths.filter((p) => Boolean(p)))]) {
61141
- (0, import_node_fs50.rmSync)(path2, { force: true });
61516
+ (0, import_node_fs51.rmSync)(path2, { force: true });
61142
61517
  }
61143
61518
  }
61144
61519
  async function killTree(pid) {
@@ -61155,7 +61530,7 @@ async function killTree(pid) {
61155
61530
  } catch {
61156
61531
  }
61157
61532
  }
61158
- await new Promise((resolve7) => setTimeout(resolve7, 500));
61533
+ await new Promise((resolve8) => setTimeout(resolve8, 500));
61159
61534
  try {
61160
61535
  process.kill(-pid, "SIGKILL");
61161
61536
  } catch {
@@ -61228,7 +61603,7 @@ async function waitForHealth(url, timeoutMs, anyStatus = false) {
61228
61603
  } catch (e) {
61229
61604
  last = e.message;
61230
61605
  }
61231
- await new Promise((resolve7) => setTimeout(resolve7, healthPollIntervalMs()));
61606
+ await new Promise((resolve8) => setTimeout(resolve8, healthPollIntervalMs()));
61232
61607
  }
61233
61608
  throw new Error(`stage health check timed out for ${url}${last ? ` (${last})` : ""}`);
61234
61609
  }
@@ -61385,8 +61760,8 @@ async function runStage(config = {}, opts = {}) {
61385
61760
  });
61386
61761
  }
61387
61762
  } catch (e) {
61388
- (0, import_node_fs50.rmSync)(statePath, { force: true });
61389
- if (globalStatePath && globalStatePath !== statePath) (0, import_node_fs50.rmSync)(globalStatePath, { force: true });
61763
+ (0, import_node_fs51.rmSync)(statePath, { force: true });
61764
+ if (globalStatePath && globalStatePath !== statePath) (0, import_node_fs51.rmSync)(globalStatePath, { force: true });
61390
61765
  throw e;
61391
61766
  }
61392
61767
  const started = await startStage(config, {
@@ -61405,9 +61780,9 @@ function normPath2(p) {
61405
61780
  return p.replace(/\\/g, "/").replace(/\/+$/, "");
61406
61781
  }
61407
61782
  function unlinkNodeModulesJunction(wtPath) {
61408
- const nm = (0, import_node_path47.join)(wtPath, "node_modules");
61783
+ const nm = (0, import_node_path48.join)(wtPath, "node_modules");
61409
61784
  try {
61410
- if ((0, import_node_fs51.lstatSync)(nm).isSymbolicLink()) (0, import_node_fs51.rmdirSync)(nm);
61785
+ if ((0, import_node_fs52.lstatSync)(nm).isSymbolicLink()) (0, import_node_fs52.rmdirSync)(nm);
61411
61786
  return { ok: true };
61412
61787
  } catch (e) {
61413
61788
  if (e.code === "ENOENT") return { ok: true };
@@ -61415,11 +61790,11 @@ function unlinkNodeModulesJunction(wtPath) {
61415
61790
  }
61416
61791
  }
61417
61792
  function defaultSleep2(ms) {
61418
- return new Promise((resolve7) => setTimeout(resolve7, ms));
61793
+ return new Promise((resolve8) => setTimeout(resolve8, ms));
61419
61794
  }
61420
61795
  async function removeResidueDirectory(wtPath, options = {}) {
61421
- const { sleep: sleep2 = defaultSleep2, removeEmptyDir = import_node_fs51.rmdirSync, exists = import_node_fs51.existsSync } = options;
61422
- const removeRecursive = options.removeRecursive ?? ((path2) => (0, import_node_fs51.rmSync)(path2, { recursive: true, force: true, maxRetries: 10, retryDelay: 100 }));
61796
+ const { sleep: sleep2 = defaultSleep2, removeEmptyDir = import_node_fs52.rmdirSync, exists = import_node_fs52.existsSync } = options;
61797
+ const removeRecursive = options.removeRecursive ?? ((path2) => (0, import_node_fs52.rmSync)(path2, { recursive: true, force: true, maxRetries: 10, retryDelay: 100 }));
61423
61798
  const junction = unlinkNodeModulesJunction(wtPath);
61424
61799
  if (!junction.ok) return junction;
61425
61800
  try {
@@ -61542,28 +61917,28 @@ async function preCleanWorktreeForRemoval(wtPath, execGit) {
61542
61917
  }
61543
61918
  async function listNestedIgnoredNodeModules(wtPath, execGit) {
61544
61919
  const out = await execGit(["-C", wtPath, "ls-files", "--others", "--ignored", "--exclude-standard", "--directory"]).catch(() => "");
61545
- return out.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.endsWith("node_modules/") && line !== "node_modules/").map((line) => (0, import_node_path47.join)(wtPath, line.slice(0, -1)));
61920
+ return out.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.endsWith("node_modules/") && line !== "node_modules/").map((line) => (0, import_node_path48.join)(wtPath, line.slice(0, -1)));
61546
61921
  }
61547
61922
  function safeRemoveTree(path2) {
61548
- const stat4 = (0, import_node_fs51.lstatSync)(path2);
61923
+ const stat4 = (0, import_node_fs52.lstatSync)(path2);
61549
61924
  if (stat4.isSymbolicLink()) {
61550
61925
  try {
61551
- (0, import_node_fs51.rmdirSync)(path2);
61926
+ (0, import_node_fs52.rmdirSync)(path2);
61552
61927
  } catch {
61553
- (0, import_node_fs51.unlinkSync)(path2);
61928
+ (0, import_node_fs52.unlinkSync)(path2);
61554
61929
  }
61555
61930
  return;
61556
61931
  }
61557
61932
  if (stat4.isDirectory()) {
61558
- for (const entry of (0, import_node_fs51.readdirSync)(path2)) safeRemoveTree((0, import_node_path47.join)(path2, entry));
61559
- (0, import_node_fs51.rmdirSync)(path2);
61933
+ for (const entry of (0, import_node_fs52.readdirSync)(path2)) safeRemoveTree((0, import_node_path48.join)(path2, entry));
61934
+ (0, import_node_fs52.rmdirSync)(path2);
61560
61935
  return;
61561
61936
  }
61562
- (0, import_node_fs51.unlinkSync)(path2);
61937
+ (0, import_node_fs52.unlinkSync)(path2);
61563
61938
  }
61564
61939
  async function removeWorktreeNodeModules(wtPath) {
61565
61940
  try {
61566
- safeRemoveTree((0, import_node_path47.join)(wtPath, "node_modules"));
61941
+ safeRemoveTree((0, import_node_path48.join)(wtPath, "node_modules"));
61567
61942
  return { ok: true };
61568
61943
  } catch (e) {
61569
61944
  if (e.code === "ENOENT") return { ok: true };
@@ -61575,7 +61950,7 @@ function errorMessage(e) {
61575
61950
  }
61576
61951
  function resolvedOrRaw(path2) {
61577
61952
  try {
61578
- return normPath2((0, import_node_fs51.realpathSync)(path2));
61953
+ return normPath2((0, import_node_fs52.realpathSync)(path2));
61579
61954
  } catch {
61580
61955
  return normPath2(path2);
61581
61956
  }
@@ -61583,10 +61958,10 @@ function resolvedOrRaw(path2) {
61583
61958
  function unlinkEscapingReparsePoints(root, primaryRoot) {
61584
61959
  let realRoot;
61585
61960
  try {
61586
- if ((0, import_node_fs51.lstatSync)(root).isSymbolicLink()) {
61961
+ if ((0, import_node_fs52.lstatSync)(root).isSymbolicLink()) {
61587
61962
  return { ok: false, error: `delete root ${normPath2(root)} is a reparse point resolving to ${resolvedOrRaw(root)}` };
61588
61963
  }
61589
- realRoot = normPath2((0, import_node_fs51.realpathSync)(root));
61964
+ realRoot = normPath2((0, import_node_fs52.realpathSync)(root));
61590
61965
  } catch (e) {
61591
61966
  if (e.code === "ENOENT") return { ok: true, unlinked: [] };
61592
61967
  return { ok: false, error: `cannot resolve delete root ${normPath2(root)}: ${errorMessage(e)}` };
@@ -61602,17 +61977,17 @@ function unlinkEscapingReparsePoints(root, primaryRoot) {
61602
61977
  const dir = stack.pop();
61603
61978
  let entries;
61604
61979
  try {
61605
- entries = (0, import_node_fs51.readdirSync)(dir, { withFileTypes: true });
61980
+ entries = (0, import_node_fs52.readdirSync)(dir, { withFileTypes: true });
61606
61981
  } catch (e) {
61607
61982
  if (e.code === "ENOENT") continue;
61608
61983
  return { ok: false, error: `cannot scan ${normPath2(dir)} for reparse points: ${errorMessage(e)}` };
61609
61984
  }
61610
61985
  for (const entry of entries) {
61611
- const child2 = (0, import_node_path47.join)(dir, entry.name);
61986
+ const child2 = (0, import_node_path48.join)(dir, entry.name);
61612
61987
  if (entry.isSymbolicLink()) {
61613
61988
  let target = "";
61614
61989
  try {
61615
- target = normPath2((0, import_node_fs51.realpathSync)(child2));
61990
+ target = normPath2((0, import_node_fs52.realpathSync)(child2));
61616
61991
  } catch {
61617
61992
  target = "";
61618
61993
  }
@@ -61795,7 +62170,7 @@ async function cleanupPrMergeLocalBranch(branch, options) {
61795
62170
  return report;
61796
62171
  }
61797
62172
  const execGit = options.execGit ?? (async (args) => (await execFileP("git", args, { timeout: GIT_TIMEOUT_MS })).stdout);
61798
- const pathExists = options.pathExists ?? import_node_fs51.existsSync;
62173
+ const pathExists = options.pathExists ?? import_node_fs52.existsSync;
61799
62174
  let afterWorktrees = [];
61800
62175
  try {
61801
62176
  afterWorktrees = parseGitWorktreePorcelain(await execGit(["worktree", "list", "--porcelain"]));
@@ -61935,7 +62310,7 @@ async function cleanupPrMergeLocalBranch(branch, options) {
61935
62310
  const preHelperGuard = unlinkEscapingReparsePoints(wtPath, options.primaryRoot);
61936
62311
  if (!preHelperGuard.ok) return refuseReparseEscape(preHelperGuard.error);
61937
62312
  unlinkedReparsePoints.push(...preHelperGuard.unlinked);
61938
- if (pathExists((0, import_node_path47.join)(wtPath, "node_modules"))) {
62313
+ if (pathExists((0, import_node_path48.join)(wtPath, "node_modules"))) {
61939
62314
  const nmRemoved = await (options.removeRealNodeModules ?? removeWorktreeNodeModules)(wtPath);
61940
62315
  if (!nmRemoved.ok) {
61941
62316
  report.worktree = {
@@ -62071,18 +62446,18 @@ function renderPrMergeCleanupLines(cleanup) {
62071
62446
  // src/worktree-residue-sweep.ts
62072
62447
  var RESIDUE_LEDGER_FILE = "mmi-worktree-residue.json";
62073
62448
  function canonicalWorktreeRoot(primary) {
62074
- return (0, import_node_path48.join)((0, import_node_path48.dirname)(primary), "mmi-worktrees", (0, import_node_path48.basename)(primary));
62449
+ return (0, import_node_path49.join)((0, import_node_path49.dirname)(primary), "mmi-worktrees", (0, import_node_path49.basename)(primary));
62075
62450
  }
62076
- function norm(p) {
62451
+ function norm2(p) {
62077
62452
  const s = p.replace(/\\/g, "/").replace(/\/+$/, "");
62078
62453
  return process.platform === "win32" ? s.toLowerCase() : s;
62079
62454
  }
62080
62455
  function residueLedgerPath(gitCommonDir) {
62081
- return (0, import_node_path48.join)(gitCommonDir, RESIDUE_LEDGER_FILE);
62456
+ return (0, import_node_path49.join)(gitCommonDir, RESIDUE_LEDGER_FILE);
62082
62457
  }
62083
62458
  function readPaths(file, deps) {
62084
62459
  try {
62085
- const parsed = JSON.parse((deps.readLedger ?? ((f) => (0, import_node_fs52.readFileSync)(f, "utf8")))(file));
62460
+ const parsed = JSON.parse((deps.readLedger ?? ((f) => (0, import_node_fs53.readFileSync)(f, "utf8")))(file));
62086
62461
  return Array.isArray(parsed) ? parsed.filter((p) => typeof p === "string") : [];
62087
62462
  } catch {
62088
62463
  return [];
@@ -62091,8 +62466,8 @@ function readPaths(file, deps) {
62091
62466
  function writePaths(file, paths, deps) {
62092
62467
  try {
62093
62468
  const write = deps.writeLedger ?? ((f, t) => {
62094
- (0, import_node_fs52.mkdirSync)((0, import_node_path48.dirname)(f), { recursive: true });
62095
- (0, import_node_fs52.writeFileSync)(f, t, "utf8");
62469
+ (0, import_node_fs53.mkdirSync)((0, import_node_path49.dirname)(f), { recursive: true });
62470
+ (0, import_node_fs53.writeFileSync)(f, t, "utf8");
62096
62471
  });
62097
62472
  write(file, `${JSON.stringify([...new Set(paths)], null, 1)}
62098
62473
  `);
@@ -62102,29 +62477,29 @@ function writePaths(file, paths, deps) {
62102
62477
  function recordResidue(gitCommonDir, path2, deps = {}) {
62103
62478
  const file = residueLedgerPath(gitCommonDir);
62104
62479
  const paths = readPaths(file, deps);
62105
- if (!paths.some((p) => norm(p) === norm(path2))) paths.push(path2);
62480
+ if (!paths.some((p) => norm2(p) === norm2(path2))) paths.push(path2);
62106
62481
  writePaths(file, paths, deps);
62107
62482
  }
62108
62483
  async function sweepWorktreeResidue(gitCommonDir, registered, deps = {}) {
62109
- const exists = deps.exists ?? import_node_fs52.existsSync;
62110
- const readDir = deps.readDir ?? ((p) => (0, import_node_fs52.readdirSync)(p));
62484
+ const exists = deps.exists ?? import_node_fs53.existsSync;
62485
+ const readDir = deps.readDir ?? ((p) => (0, import_node_fs53.readdirSync)(p));
62111
62486
  const isDir = deps.isDir ?? ((p) => {
62112
62487
  try {
62113
- return (0, import_node_fs52.statSync)(p).isDirectory();
62488
+ return (0, import_node_fs53.statSync)(p).isDirectory();
62114
62489
  } catch {
62115
62490
  return false;
62116
62491
  }
62117
62492
  });
62118
62493
  const removeRecorded = deps.removeRecorded ?? ((p) => removeResidueDirectory(p));
62119
- const removeEmpty = deps.removeEmpty ?? ((p) => (0, import_node_fs52.rmdirSync)(p));
62494
+ const removeEmpty = deps.removeEmpty ?? ((p) => (0, import_node_fs53.rmdirSync)(p));
62120
62495
  const report = { swept: [], kept: [], dropped: [], emptyRemoved: [], unrecorded: [] };
62121
- const live = new Set(registered.map(norm));
62122
- const primary = registered[0] ? norm(registered[0]) : void 0;
62496
+ const live = new Set(registered.map(norm2));
62497
+ const primary = registered[0] ? norm2(registered[0]) : void 0;
62123
62498
  const file = residueLedgerPath(gitCommonDir);
62124
62499
  const recorded = readPaths(file, deps);
62125
62500
  const remaining = [];
62126
62501
  for (const path2 of recorded) {
62127
- const key = norm(path2);
62502
+ const key = norm2(path2);
62128
62503
  if (live.has(key) || key === primary) {
62129
62504
  report.dropped.push(path2);
62130
62505
  continue;
@@ -62141,9 +62516,9 @@ async function sweepWorktreeResidue(gitCommonDir, registered, deps = {}) {
62141
62516
  }
62142
62517
  }
62143
62518
  if (recorded.length) writePaths(file, remaining, deps);
62144
- const keptKeys = new Set(remaining.map(norm));
62519
+ const keptKeys = new Set(remaining.map(norm2));
62145
62520
  const root = registered[0] ? canonicalWorktreeRoot(registered[0]) : void 0;
62146
- if (root && isDir(root) && !live.has(norm(root))) {
62521
+ if (root && isDir(root) && !live.has(norm2(root))) {
62147
62522
  report.root = root;
62148
62523
  let children = [];
62149
62524
  try {
@@ -62151,8 +62526,8 @@ async function sweepWorktreeResidue(gitCommonDir, registered, deps = {}) {
62151
62526
  } catch {
62152
62527
  }
62153
62528
  for (const name of children) {
62154
- const child2 = (0, import_node_path48.join)(root, name);
62155
- const key = norm(child2);
62529
+ const child2 = (0, import_node_path49.join)(root, name);
62530
+ const key = norm2(child2);
62156
62531
  if (live.has(key) || key === primary || keptKeys.has(key) || !isDir(child2)) continue;
62157
62532
  let entries;
62158
62533
  try {
@@ -62194,10 +62569,10 @@ function argvWantsJson2() {
62194
62569
  return process.argv.some((a) => a === "--json" || a.startsWith("--json="));
62195
62570
  }
62196
62571
  function hubRoot() {
62197
- const fromPkg = (0, import_node_path49.join)(__dirname, "..", "..");
62572
+ const fromPkg = (0, import_node_path50.join)(__dirname, "..", "..");
62198
62573
  const marker = "skills/bootstrap/seeds/manifest.json";
62199
- if ((0, import_node_fs53.existsSync)((0, import_node_path49.join)(fromPkg, marker))) return fromPkg;
62200
- if ((0, import_node_fs53.existsSync)((0, import_node_path49.join)(process.cwd(), marker))) return process.cwd();
62574
+ if ((0, import_node_fs54.existsSync)((0, import_node_path50.join)(fromPkg, marker))) return fromPkg;
62575
+ if ((0, import_node_fs54.existsSync)((0, import_node_path50.join)(process.cwd(), marker))) return process.cwd();
62201
62576
  return null;
62202
62577
  }
62203
62578
  function ciAuditDeps() {
@@ -62209,8 +62584,8 @@ function ciAuditDeps() {
62209
62584
  getProjectMeta: async (slug) => fetchProjectBySlug(slug, registryClientDeps(await cfgPromise)),
62210
62585
  readSeedFile: (path2) => {
62211
62586
  if (!root) return null;
62212
- const fullPath = (0, import_node_path49.join)(root, path2);
62213
- return (0, import_node_fs53.existsSync)(fullPath) ? (0, import_node_fs53.readFileSync)(fullPath, "utf8") : null;
62587
+ const fullPath = (0, import_node_path50.join)(root, path2);
62588
+ return (0, import_node_fs54.existsSync)(fullPath) ? (0, import_node_fs54.readFileSync)(fullPath, "utf8") : null;
62214
62589
  }
62215
62590
  };
62216
62591
  }
@@ -63077,11 +63452,11 @@ ${preparation.findings.map((finding) => `[${finding.check}/${finding.state}] ${f
63077
63452
  }
63078
63453
  });
63079
63454
  async function listCiWorkflowPaths(cwd = process.cwd()) {
63080
- const wfDir = (0, import_node_path49.join)(cwd, ".github", "workflows");
63081
- if (!(0, import_node_fs53.existsSync)(wfDir)) return [];
63082
- return (0, import_node_fs53.readdirSync)(wfDir).filter((name) => /\.(ya?ml)$/i.test(name)).filter((name) => {
63455
+ const wfDir = (0, import_node_path50.join)(cwd, ".github", "workflows");
63456
+ if (!(0, import_node_fs54.existsSync)(wfDir)) return [];
63457
+ return (0, import_node_fs54.readdirSync)(wfDir).filter((name) => /\.(ya?ml)$/i.test(name)).filter((name) => {
63083
63458
  try {
63084
- return workflowReportsPrChecks((0, import_node_fs53.readFileSync)((0, import_node_path49.join)(wfDir, name), "utf8"));
63459
+ return workflowReportsPrChecks((0, import_node_fs54.readFileSync)((0, import_node_path50.join)(wfDir, name), "utf8"));
63085
63460
  } catch {
63086
63461
  return true;
63087
63462
  }
@@ -63269,7 +63644,7 @@ ${preparation.findings.map((finding) => `[${finding.check}/${finding.state}] ${f
63269
63644
  // #5400: after grace, name "GitHub delivered zero runs" instead of burning the full budget as pending.
63270
63645
  pollHeadWorkflowRunCount: () => waitLoopHeadWorkflowRunCount("pr checks-wait", number, repo),
63271
63646
  baseBranch,
63272
- sleep: (ms) => new Promise((resolve7) => setTimeout(resolve7, ms)),
63647
+ sleep: (ms) => new Promise((resolve8) => setTimeout(resolve8, ms)),
63273
63648
  log: (message2) => console.warn(message2),
63274
63649
  timeoutMs: Math.max(1, budgetMs - (Date.now() - waitStarted)),
63275
63650
  // Liveness on stderr, one line per poll. A silent bounded wait is indistinguishable from a hang, and
@@ -63286,7 +63661,7 @@ ${preparation.findings.map((finding) => `[${finding.check}/${finding.state}] ${f
63286
63661
  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) => {
63287
63662
  if (!isReviewVerdict(o.verdict)) return fail(`pr review-verdict: --verdict must be one of ${REVIEW_VERDICTS.join("|")} (got ${o.verdict})`);
63288
63663
  const verdict = o.verdict;
63289
- const findings = o.findingsFile ? (0, import_node_fs53.readFileSync)(o.findingsFile, "utf8") : void 0;
63664
+ const findings = o.findingsFile ? (0, import_node_fs54.readFileSync)(o.findingsFile, "utf8") : void 0;
63290
63665
  let patch;
63291
63666
  let head;
63292
63667
  try {
@@ -63449,7 +63824,7 @@ ${preparation.findings.map((finding) => `[${finding.check}/${finding.state}] ${f
63449
63824
  // #5400: same zero-runs delivery probe as checks-wait — do not burn the land budget on silence.
63450
63825
  pollHeadWorkflowRunCount: () => waitLoopHeadWorkflowRunCount("pr land", prNumber, repo),
63451
63826
  baseBranch: "development",
63452
- sleep: (ms) => new Promise((resolve7) => setTimeout(resolve7, ms)),
63827
+ sleep: (ms) => new Promise((resolve8) => setTimeout(resolve8, ms)),
63453
63828
  log: (message2) => console.warn(message2),
63454
63829
  // `pr land` inherits the same (raised) checks budget, so it needs the same liveness — otherwise the
63455
63830
  // 30m wait is SILENT and reads exactly like the hang #2940 was filed about, only three times longer.
@@ -63513,7 +63888,7 @@ ${preparation.findings.map((finding) => `[${finding.check}/${finding.state}] ${f
63513
63888
  } else {
63514
63889
  lastFailure2 = void 0;
63515
63890
  }
63516
- await new Promise((resolve7) => setTimeout(resolve7, PR_LAND_POLL_MS));
63891
+ await new Promise((resolve8) => setTimeout(resolve8, PR_LAND_POLL_MS));
63517
63892
  }
63518
63893
  if (lastFailure2) {
63519
63894
  throw new Error(
@@ -63564,7 +63939,7 @@ ${preparation.findings.map((finding) => `[${finding.check}/${finding.state}] ${f
63564
63939
  const cleanupMerged = async (r) => {
63565
63940
  if (opts.preserveWorktree) return "cleanup skipped (--preserve-worktree)";
63566
63941
  const ran = await execFileP(process.execPath, [process.argv[1], ...canonicalArgvFor(["pr", "merge", r.pr, "--repo", r.repo])], {
63567
- cwd: (0, import_node_fs53.existsSync)(cwd0) ? cwd0 : primaryRoot0,
63942
+ cwd: (0, import_node_fs54.existsSync)(cwd0) ? cwd0 : primaryRoot0,
63568
63943
  timeout: GH_MUTATION_TIMEOUT_MS * 3
63569
63944
  }).then((x) => ({ stdout: x.stdout, stderr: x.stderr }), (e) => ({ stdout: e.stdout ?? "", stderr: e.stderr ?? "" }));
63570
63945
  const json = ran.stdout.split("\n").reverse().find((l) => l.startsWith("{"));
@@ -63635,7 +64010,7 @@ ${preparation.findings.map((finding) => `[${finding.check}/${finding.state}] ${f
63635
64010
  const mergeSquashBody = squashBodyTextForMerge(
63636
64011
  closingGuardInput,
63637
64012
  method === "--squash",
63638
- o.squashBodyFile ? (0, import_node_fs53.readFileSync)(o.squashBodyFile, "utf8") : void 0
64013
+ o.squashBodyFile ? (0, import_node_fs54.readFileSync)(o.squashBodyFile, "utf8") : void 0
63639
64014
  );
63640
64015
  if (!o.squashBodyFile) warnSquashBodyClosingStrip("pr merge", closingGuardInput, mergeSquashBody);
63641
64016
  const closingGuardVerdict = evaluateClosingGuard(closingGuardInput, {
@@ -63667,7 +64042,7 @@ ${preparation.findings.map((finding) => `[${finding.check}/${finding.state}] ${f
63667
64042
  const remote = foreignCwd ? `https://github.com/${targetRepo2}.git` : "origin";
63668
64043
  let foreignCheckout;
63669
64044
  if (foreignCwd) {
63670
- const sibling = (0, import_node_path49.join)((0, import_node_path49.dirname)(beforeWorktrees[0]?.path || startingPath || process.cwd()), targetRepo2.split("/")[1]);
64045
+ const sibling = (0, import_node_path50.join)((0, import_node_path50.dirname)(beforeWorktrees[0]?.path || startingPath || process.cwd()), targetRepo2.split("/")[1]);
63671
64046
  const siblingRepo = repoFromRemoteUrl(await gitOut(["-C", sibling, "remote", "get-url", "origin"]).catch(() => ""));
63672
64047
  if (siblingRepo?.toLowerCase() === targetRepo2.toLowerCase()) {
63673
64048
  const siblingWorktrees = await execFileP("git", ["-C", sibling, "worktree", "list", "--porcelain"], { timeout: GIT_TIMEOUT_MS }).then((r) => parseGitWorktreePorcelain(r.stdout)).catch(() => void 0);
@@ -63705,7 +64080,7 @@ ${preparation.findings.map((finding) => `[${finding.check}/${finding.state}] ${f
63705
64080
  checksDiagnosticCommand: `gh pr checks ${number} --repo ${repo}`,
63706
64081
  pollHeadWorkflowRunCount: () => waitLoopHeadWorkflowRunCount("pr merge --wait", number, repo),
63707
64082
  baseBranch,
63708
- sleep: (ms) => new Promise((resolve7) => setTimeout(resolve7, ms)),
64083
+ sleep: (ms) => new Promise((resolve8) => setTimeout(resolve8, ms)),
63709
64084
  log: (message2) => console.warn(message2),
63710
64085
  timeoutMs: Math.max(1, budgetMs - (Date.now() - waitStarted)),
63711
64086
  progress: ({ state, elapsedMs, remainingMs }) => console.warn(`pr merge: --wait checks \u2014 ${state}, ${Math.round(elapsedMs / 1e3)}s elapsed, ${Math.round(remainingMs / 6e4)}m left`)
@@ -63786,7 +64161,7 @@ ${preparation.findings.map((finding) => `[${finding.check}/${finding.state}] ${f
63786
64161
  }
63787
64162
  if (!repoForPostCleanup) throw e;
63788
64163
  console.warn(`pr merge: gh GraphQL rate-limited \u2014 merging PR #${number} via REST PUT instead (#4588).`);
63789
- const commitMessage = bodyFile ? (0, import_node_fs53.readFileSync)(bodyFile, "utf8") : void 0;
64164
+ const commitMessage = bodyFile ? (0, import_node_fs54.readFileSync)(bodyFile, "utf8") : void 0;
63790
64165
  await defaultGitHubClient().rest("PUT", `repos/${repoForPostCleanup}/pulls/${number}/merge`, {
63791
64166
  body: { merge_method: method.slice(2), ...commitMessage ? { commit_message: commitMessage } : {} },
63792
64167
  timeoutMs: GH_MUTATION_TIMEOUT_MS
@@ -63795,7 +64170,7 @@ ${preparation.findings.map((finding) => `[${finding.check}/${finding.state}] ${f
63795
64170
  }
63796
64171
  if (!o.auto && mergeRejectedBaseBranchModified(message2)) {
63797
64172
  console.warn(`pr merge: the base branch was modified by a concurrent merge \u2014 waiting ${PR_MERGE_BASE_RACE_RETRY_DELAY_MS / 1e3}s and retrying PR #${number}'s merge once (#6052).`);
63798
- await new Promise((resolve7) => setTimeout(resolve7, PR_MERGE_BASE_RACE_RETRY_DELAY_MS));
64173
+ await new Promise((resolve8) => setTimeout(resolve8, PR_MERGE_BASE_RACE_RETRY_DELAY_MS));
63799
64174
  await execFileP("gh", buildPrMergeArgs({ number, repoArgs, method, auto: false, deleteBranch: false, bodyFile }), { timeout: GH_MUTATION_TIMEOUT_MS }).catch((e2) => {
63800
64175
  const m2 = String(e2.message || "");
63801
64176
  if (/already been merged/i.test(m2)) {
@@ -63901,7 +64276,7 @@ ${preparation.findings.map((finding) => `[${finding.check}/${finding.state}] ${f
63901
64276
  let residueSweep;
63902
64277
  if (!(foreignCwd && !foreignCheckout)) {
63903
64278
  try {
63904
- gitCommonDir = (0, import_node_path49.resolve)(primaryRoot, (await execFileP("git", ["-C", primaryRoot, "rev-parse", "--git-common-dir"], { timeout: GIT_TIMEOUT_MS })).stdout.trim());
64279
+ gitCommonDir = (0, import_node_path50.resolve)(primaryRoot, (await execFileP("git", ["-C", primaryRoot, "rev-parse", "--git-common-dir"], { timeout: GIT_TIMEOUT_MS })).stdout.trim());
63905
64280
  residueSweep = await sweepWorktreeResidue(gitCommonDir, beforeWorktrees.map((w) => w.path));
63906
64281
  } catch {
63907
64282
  }
@@ -63919,7 +64294,7 @@ ${preparation.findings.map((finding) => `[${finding.check}/${finding.state}] ${f
63919
64294
  preserveWorktree: o.preserveWorktree,
63920
64295
  gcAcknowledged: o.gc,
63921
64296
  expectedHeadOid: headRefOid,
63922
- pathExists: (p) => (0, import_node_fs53.existsSync)(p),
64297
+ pathExists: (p) => (0, import_node_fs54.existsSync)(p),
63923
64298
  // #5899: pin cleanup git calls to the main checkout — the task worktree this process may be
63924
64299
  // standing in is removed mid-cleanup, so a cwd-relative invocation fails with
63925
64300
  // 'fatal: not a git repository' and leaves a spurious partial-cleanup exit.
@@ -64060,7 +64435,7 @@ ${preparation.findings.map((finding) => `[${finding.check}/${finding.state}] ${f
64060
64435
  console.warn(`ci checks-wait: zero-runs probe FAILED (${read.error}) \u2014 not treating as delivery failure this cycle`);
64061
64436
  return null;
64062
64437
  },
64063
- sleep: (ms) => new Promise((resolve7) => setTimeout(resolve7, ms)),
64438
+ sleep: (ms) => new Promise((resolve8) => setTimeout(resolve8, ms)),
64064
64439
  log: (message2) => console.warn(message2),
64065
64440
  timeoutMs: timeoutMs ?? PR_CHECKS_TIMEOUT_MS,
64066
64441
  progress: ({ state, elapsedMs, remainingMs, detail }) => console.warn(`ci checks-wait: ${detail && detail.startsWith("pending (") ? detail : state} \u2014 ${Math.round(elapsedMs / 1e3)}s elapsed, ${Math.round(remainingMs / 6e4)}m left`)
@@ -64197,8 +64572,14 @@ function trainApplyDeps() {
64197
64572
  },
64198
64573
  // Hub-App-authority dispatch of the central tenant deploy (#953) — the Hub fires the
64199
64574
  // workflow_dispatch with its App token, so the caller needs no MMI-Hub Actions write.
64200
- dispatchTenantDeploy: async ({ repo, stage, ref }) => {
64201
- const res = await tenantDeploy({ repo, stage, ref }, registryClientDeps(await loadConfig()));
64575
+ readDeployedSha: async (slug, stage) => (await fetchDeployFactsBySlug(slug, registryClientDeps(await loadConfig())))?.stages[stage]?.deployedTag,
64576
+ compareDeployRef: async (repo, base, head) => (await defaultGitHubClient().rest(
64577
+ "GET",
64578
+ `repos/${repo}/compare/${encodeURIComponent(base)}...${encodeURIComponent(head)}?per_page=1`,
64579
+ { timeoutMs: GH_TRAIN_TIMEOUT_MS }
64580
+ )).status,
64581
+ dispatchTenantDeploy: async ({ repo, stage, ref, rollback }) => {
64582
+ const res = await tenantDeploy({ repo, stage, ref, ...rollback ? { rollback } : {} }, registryClientDeps(await loadConfig()));
64202
64583
  if (!res.ok) {
64203
64584
  const detail = res.body?.error ?? res.error ?? `HTTP ${res.status}`;
64204
64585
  throw new Error(`tenant deploy dispatch failed: ${detail}`);
@@ -64450,7 +64831,7 @@ function hotfixFollowUpLegs(runs2, foldPort, alignment, foldNote, deployNote) {
64450
64831
  }
64451
64832
  return legs;
64452
64833
  }
64453
- async function runProjectInfoSyncLeg(cb, repo, sleep2 = (ms) => new Promise((resolve7) => setTimeout(resolve7, ms))) {
64834
+ async function runProjectInfoSyncLeg(cb, repo, sleep2 = (ms) => new Promise((resolve8) => setTimeout(resolve8, ms))) {
64454
64835
  for (let attempt = 0; ; attempt++) {
64455
64836
  try {
64456
64837
  return await cb(repo, true);
@@ -65185,7 +65566,7 @@ function rcRunCauseFromLog(log) {
65185
65566
  function memberAnnounceSummaryFile(repo, summaryFile, memberSummaryFiles) {
65186
65567
  return repo === SUITE_REPO ? summaryFile : memberSummaryFiles[repo];
65187
65568
  }
65188
- var suiteStateDir = (root) => (0, import_node_path51.join)(resolvePrimaryGitDir(root), "mmi-runtime", "suite");
65569
+ var suiteStateDir = (root) => (0, import_node_path52.join)(resolvePrimaryGitDir(root), "mmi-runtime", "suite");
65189
65570
  async function runSuiteMemberRcand(repo, previousRc, rcWasAbsent) {
65190
65571
  const deps = trainApplyDeps();
65191
65572
  deps.suiteCut = suiteCutContext(repo, SUITE_REPO);
@@ -65204,8 +65585,8 @@ async function rcandInCheckout(repo, deps, previousRc, rcWasAbsent) {
65204
65585
  const meta = await fetchProjectBySlugChecked(slug, registryClientDeps(await loadConfig()));
65205
65586
  if (!meta.ok || meta.project?.releaseTrack !== "full" || meta.project.suite !== "mm-work")
65206
65587
  throw new Error(`${repo}: first rc branch requires releaseTrack full and suite=mm-work in META; no branch created`);
65207
- const main = (await deps.run("git", ["rev-parse", "origin/main"])).trim();
65208
- if (main.toLowerCase() !== previousRc.toLowerCase()) throw new Error(`${repo}: main moved since the cut snapshot; no rc branch created`);
65588
+ const main2 = (await deps.run("git", ["rev-parse", "origin/main"])).trim();
65589
+ if (main2.toLowerCase() !== previousRc.toLowerCase()) throw new Error(`${repo}: main moved since the cut snapshot; no rc branch created`);
65209
65590
  await deps.run("git", ["push", "origin", `${previousRc}:refs/heads/rc`]);
65210
65591
  await deps.run("git", ["fetch", "origin", "rc"]);
65211
65592
  rcNow = (await deps.run("git", ["rev-parse", "origin/rc"])).trim();
@@ -65232,16 +65613,16 @@ async function rcandInCheckout(repo, deps, previousRc, rcWasAbsent) {
65232
65613
  }
65233
65614
  }
65234
65615
  function suiteTrainIo(root, summaryFile, memberSummaryFiles = {}, summaryFileTr, memberSummaryFilesTr = {}) {
65235
- const recordPath = (0, import_node_path51.join)(suiteStateDir(root), "cut.json");
65236
- const base = (0, import_node_path51.join)(suiteStateDir(root), "checkouts");
65616
+ const recordPath = (0, import_node_path52.join)(suiteStateDir(root), "cut.json");
65617
+ const base = (0, import_node_path52.join)(suiteStateDir(root), "checkouts");
65237
65618
  const checkout = async (repo) => {
65238
65619
  if (repo === SUITE_REPO) return root;
65239
- const target = (0, import_node_path51.join)(base, repo.split("/")[1]);
65240
- if (!(0, import_node_fs54.existsSync)(target)) {
65241
- (0, import_node_fs54.mkdirSync)(base, { recursive: true });
65620
+ const target = (0, import_node_path52.join)(base, repo.split("/")[1]);
65621
+ if (!(0, import_node_fs55.existsSync)(target)) {
65622
+ (0, import_node_fs55.mkdirSync)(base, { recursive: true });
65242
65623
  await exec("git", ["clone", "--quiet", "--branch", "development", `https://github.com/${repo}.git`, target], root, WATCH_TIMEOUT);
65243
65624
  }
65244
- if (!(0, import_node_fs54.existsSync)((0, import_node_path51.join)(target, ".git"))) throw new Error(`${repo}: suite checkout has no .git at ${target}; stop`);
65625
+ if (!(0, import_node_fs55.existsSync)((0, import_node_path52.join)(target, ".git"))) throw new Error(`${repo}: suite checkout has no .git at ${target}; stop`);
65245
65626
  const origin = await exec("git", ["remote", "get-url", "origin"], target);
65246
65627
  if (!origin.toLowerCase().endsWith(`/${repo.toLowerCase()}.git`) && !origin.toLowerCase().endsWith(`/${repo.toLowerCase()}`))
65247
65628
  throw new Error(`${repo}: suite checkout origin mismatch at ${target}; stop`);
@@ -65305,7 +65686,7 @@ function suiteTrainIo(root, summaryFile, memberSummaryFiles = {}, summaryFileTr,
65305
65686
  if (repo === SUITE_REPO) return inTrain(repo, (deps) => rcandInCheckout(repo, deps, previousRc, rcWasAbsent));
65306
65687
  const target = await checkout(repo);
65307
65688
  return new Promise((resolveResult, reject2) => {
65308
- const child2 = (0, import_node_child_process19.fork)((0, import_node_path50.resolve)(process.argv[1]), ["devops", "suite", "member-rcand-internal", repo, previousRc ?? "", ...rcWasAbsent ? ["--rc-was-absent"] : []], {
65689
+ const child2 = (0, import_node_child_process19.fork)((0, import_node_path51.resolve)(process.argv[1]), ["devops", "suite", "member-rcand-internal", repo, previousRc ?? "", ...rcWasAbsent ? ["--rc-was-absent"] : []], {
65309
65690
  cwd: target,
65310
65691
  stdio: ["ignore", "inherit", "inherit", "ipc"],
65311
65692
  execArgv: []
@@ -65377,7 +65758,7 @@ function suiteTrainIo(root, summaryFile, memberSummaryFiles = {}, summaryFileTr,
65377
65758
  if (!reuse) await gh(["workflow", "run", "module-rc-publish.yml", "--repo", "mutmutco/MMI-Hub", ...fields.flatMap((f) => ["--field", f])]);
65378
65759
  let candidate = reuse;
65379
65760
  for (let i = 0; !candidate && i < 25; i++) {
65380
- await new Promise((resolve7) => setTimeout(resolve7, 1e3));
65761
+ await new Promise((resolve8) => setTimeout(resolve8, 1e3));
65381
65762
  candidate = (await rcRuns()).find((r) => r.displayTitle === title && Date.parse(r.createdAt) >= since);
65382
65763
  }
65383
65764
  if (!candidate) throw new Error(`workflow dispatch outcome ambiguous for "${title}"; inspect Actions before retrying`);
@@ -65533,7 +65914,7 @@ function suiteTrainIo(root, summaryFile, memberSummaryFiles = {}, summaryFileTr,
65533
65914
  for (let i = 0; ; i++) {
65534
65915
  const pin = await openSuitePinPr({ root, run: (file, args, cwd) => exec(file, args, cwd, GIT_TIMEOUT_MS) }, { repo, tag, stage: "main" });
65535
65916
  if (pin.status !== "pending" || i >= 40) return pin;
65536
- await new Promise((resolve7) => setTimeout(resolve7, 3e4));
65917
+ await new Promise((resolve8) => setTimeout(resolve8, 3e4));
65537
65918
  }
65538
65919
  },
65539
65920
  suiteMapping: async (leadTag) => {
@@ -65548,9 +65929,9 @@ function suiteTrainIo(root, summaryFile, memberSummaryFiles = {}, summaryFileTr,
65548
65929
  const body = await gh(["release", "view", leadTag, "--repo", SUITE_REPO, "--json", "body", "--jq", ".body"]);
65549
65930
  if (parseSuiteMapping(body)) return;
65550
65931
  const dir = suiteStateDir(root);
65551
- (0, import_node_fs54.mkdirSync)(dir, { recursive: true });
65552
- const file = (0, import_node_path51.join)(dir, `notes-${leadTag}.md`);
65553
- (0, import_node_fs54.writeFileSync)(file, `${body}
65932
+ (0, import_node_fs55.mkdirSync)(dir, { recursive: true });
65933
+ const file = (0, import_node_path52.join)(dir, `notes-${leadTag}.md`);
65934
+ (0, import_node_fs55.writeFileSync)(file, `${body}
65554
65935
 
65555
65936
  ${suiteMappingBlock(leadTag, mapping)}`);
65556
65937
  await gh(["release", "edit", leadTag, "--repo", SUITE_REPO, "--notes-file", file]);
@@ -65591,7 +65972,7 @@ ${suiteMappingBlock(leadTag, mapping)}`);
65591
65972
 
65592
65973
  // src/suite-commands.ts
65593
65974
  init_cli_shared();
65594
- var import_node_fs55 = require("node:fs");
65975
+ var import_node_fs56 = require("node:fs");
65595
65976
  function parseMemberSummaryFiles(entries) {
65596
65977
  const memberSummaryFiles = {};
65597
65978
  for (const entry of entries) {
@@ -65615,7 +65996,7 @@ function suiteRcDataProdDeps() {
65615
65996
  const rc = facts.stages.rc;
65616
65997
  return rc?.present ? rc.substrate ?? "an unnamed substrate" : null;
65617
65998
  },
65618
- sleep: (ms) => new Promise((resolve7) => setTimeout(resolve7, ms))
65999
+ sleep: (ms) => new Promise((resolve8) => setTimeout(resolve8, ms))
65619
66000
  };
65620
66001
  }
65621
66002
  function registerSuiteCommands(program3) {
@@ -65685,7 +66066,7 @@ function registerSuiteCommands(program3) {
65685
66066
  try {
65686
66067
  const io = suiteTrainIo(root);
65687
66068
  retired = await retireFailedLeadRcLedger({ ledgerPath: releaseLedgerPath(root), rcHead: () => io.head(SUITE_REPO, "rc").then((h) => h ?? void 0), markAbandoned: io.markAbandoned }, o.ownerGo === true);
65688
- if (retired && !(0, import_node_fs55.existsSync)(io.recordPath)) {
66069
+ if (retired && !(0, import_node_fs56.existsSync)(io.recordPath)) {
65689
66070
  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)`);
65690
66071
  return;
65691
66072
  }
@@ -65925,9 +66306,9 @@ function registerJevCommands(program3) {
65925
66306
 
65926
66307
  // src/packages-adopt-export.ts
65927
66308
  var import_node_child_process20 = require("node:child_process");
65928
- var import_node_fs56 = require("node:fs");
66309
+ var import_node_fs57 = require("node:fs");
65929
66310
  var import_node_os25 = require("node:os");
65930
- var import_node_path52 = require("node:path");
66311
+ var import_node_path53 = require("node:path");
65931
66312
  var import_node_util6 = require("node:util");
65932
66313
  init_cli_shared();
65933
66314
 
@@ -66547,38 +66928,38 @@ function expectedFromRun(run, opts) {
66547
66928
  }
66548
66929
  async function adoptExport(opts, deps) {
66549
66930
  if (!/^sha256:[0-9a-f]{64}$/.test(opts.digest)) throw new Error("--digest must be sha256:<64 hex>, from the export run summary");
66550
- const packagePath = (0, import_node_path52.join)(opts.dir, "package.json");
66551
- const lockPath = (0, import_node_path52.join)(opts.dir, "package-lock.json");
66552
- const packageText = (0, import_node_fs56.readFileSync)(packagePath, "utf8");
66553
- const lockText = (0, import_node_fs56.readFileSync)(lockPath, "utf8");
66554
- const work = (0, import_node_fs56.mkdtempSync)((0, import_node_path52.join)((0, import_node_os25.tmpdir)(), "mmi-adopt-export-"));
66931
+ const packagePath = (0, import_node_path53.join)(opts.dir, "package.json");
66932
+ const lockPath = (0, import_node_path53.join)(opts.dir, "package-lock.json");
66933
+ const packageText = (0, import_node_fs57.readFileSync)(packagePath, "utf8");
66934
+ const lockText = (0, import_node_fs57.readFileSync)(lockPath, "utf8");
66935
+ const work = (0, import_node_fs57.mkdtempSync)((0, import_node_path53.join)((0, import_node_os25.tmpdir)(), "mmi-adopt-export-"));
66555
66936
  try {
66556
66937
  const run = JSON.parse((await deps.ghApi(`repos/${EXPORT_REPO}/actions/runs/${opts.run}`)).toString("utf8"));
66557
- (0, import_node_fs56.writeFileSync)((0, import_node_path52.join)(work, "expected.json"), JSON.stringify(expectedFromRun(run, opts)));
66558
- (0, import_node_fs56.writeFileSync)((0, import_node_path52.join)(work, "provider.json"), await deps.ghApi(`repos/${EXPORT_REPO}/actions/artifacts/${opts.artifact}`));
66559
- (0, import_node_fs56.writeFileSync)((0, import_node_path52.join)(work, "artifact.zip"), await deps.ghApi(`repos/${EXPORT_REPO}/actions/artifacts/${opts.artifact}/zip`));
66560
- const script = (0, import_node_path52.join)(work, "package_export.py");
66561
- (0, import_node_fs56.writeFileSync)(script, package_export_default);
66938
+ (0, import_node_fs57.writeFileSync)((0, import_node_path53.join)(work, "expected.json"), JSON.stringify(expectedFromRun(run, opts)));
66939
+ (0, import_node_fs57.writeFileSync)((0, import_node_path53.join)(work, "provider.json"), await deps.ghApi(`repos/${EXPORT_REPO}/actions/artifacts/${opts.artifact}`));
66940
+ (0, import_node_fs57.writeFileSync)((0, import_node_path53.join)(work, "artifact.zip"), await deps.ghApi(`repos/${EXPORT_REPO}/actions/artifacts/${opts.artifact}/zip`));
66941
+ const script = (0, import_node_path53.join)(work, "package_export.py");
66942
+ (0, import_node_fs57.writeFileSync)(script, package_export_default);
66562
66943
  await deps.python(script, ["verify", work, opts.ds, opts.screens]);
66563
- const verified = (0, import_node_path52.join)(work, "verified");
66564
- const metadata = Object.fromEntries(PACKAGES.map(({ name, short: short3 }) => [name, JSON.parse((0, import_node_fs56.readFileSync)((0, import_node_path52.join)(verified, `${short3}.metadata.json`), "utf8"))]));
66944
+ const verified = (0, import_node_path53.join)(work, "verified");
66945
+ const metadata = Object.fromEntries(PACKAGES.map(({ name, short: short3 }) => [name, JSON.parse((0, import_node_fs57.readFileSync)((0, import_node_path53.join)(verified, `${short3}.metadata.json`), "utf8"))]));
66565
66946
  const plan = planAdoption(packageText, lockText, metadata);
66566
66947
  for (const { name } of plan.result.adopted) {
66567
66948
  const short3 = PACKAGES.find((p) => p.name === name).short;
66568
- await deps.npm(["cache", "add", (0, import_node_path52.join)(verified, `${short3}.tgz`)], opts.dir);
66949
+ await deps.npm(["cache", "add", (0, import_node_path53.join)(verified, `${short3}.tgz`)], opts.dir);
66569
66950
  }
66570
- (0, import_node_fs56.writeFileSync)(packagePath, plan.packageText);
66571
- (0, import_node_fs56.writeFileSync)(lockPath, plan.lockText);
66951
+ (0, import_node_fs57.writeFileSync)(packagePath, plan.packageText);
66952
+ (0, import_node_fs57.writeFileSync)(lockPath, plan.lockText);
66572
66953
  try {
66573
66954
  await deps.npm(["ci", "--offline", "--ignore-scripts", "--no-audit", "--no-fund"], opts.dir);
66574
66955
  } catch (error) {
66575
- (0, import_node_fs56.writeFileSync)(packagePath, packageText);
66576
- (0, import_node_fs56.writeFileSync)(lockPath, lockText);
66956
+ (0, import_node_fs57.writeFileSync)(packagePath, packageText);
66957
+ (0, import_node_fs57.writeFileSync)(lockPath, lockText);
66577
66958
  throw new Error(`npm ci --offline failed, package.json and package-lock.json restored: ${error.message}`);
66578
66959
  }
66579
66960
  return plan.result;
66580
66961
  } finally {
66581
- (0, import_node_fs56.rmSync)(work, { recursive: true, force: true });
66962
+ (0, import_node_fs57.rmSync)(work, { recursive: true, force: true });
66582
66963
  }
66583
66964
  }
66584
66965
  var execFileBuffer = (0, import_node_util6.promisify)(import_node_child_process20.execFile);
@@ -66682,12 +67063,12 @@ function registerPackagesCommands(program3) {
66682
67063
  init_cli_shared();
66683
67064
 
66684
67065
  // src/wave-status.ts
66685
- var import_node_fs57 = require("node:fs");
67066
+ var import_node_fs58 = require("node:fs");
66686
67067
  function observeStage(worktreePath) {
66687
67068
  const statePath = stageStatePath(worktreePath);
66688
67069
  let raw;
66689
67070
  try {
66690
- raw = (0, import_node_fs57.readFileSync)(statePath, "utf8");
67071
+ raw = (0, import_node_fs58.readFileSync)(statePath, "utf8");
66691
67072
  } catch (error) {
66692
67073
  if (error.code === "ENOENT") return { state: "ok", value: { running: false } };
66693
67074
  return { state: "unavailable", reason: "stage state could not be read" };
@@ -66754,9 +67135,9 @@ async function collectWaveStatus(deps) {
66754
67135
  // src/discovery-commands.ts
66755
67136
  init_github_client();
66756
67137
  init_cli_shared();
66757
- var import_node_fs58 = require("node:fs");
67138
+ var import_node_fs59 = require("node:fs");
66758
67139
  var import_node_os26 = require("node:os");
66759
- var import_node_path53 = require("node:path");
67140
+ var import_node_path54 = require("node:path");
66760
67141
  var GC_GH_TIMEOUT_MS3 = 2e4;
66761
67142
  var defaultStatusDeps = {
66762
67143
  repo: resolveRepo,
@@ -66977,8 +67358,8 @@ async function collectOnboardStatus(opts = {}) {
66977
67358
  }
66978
67359
  const home = (0, import_node_os26.homedir)();
66979
67360
  const plugin = onboardPluginGate({
66980
- readKnown: () => readFileSyncSafe((0, import_node_path53.join)(home, ...KNOWN_MARKETPLACES_RELATIVE), import_node_fs58.readFileSync),
66981
- readSettings: () => readFileSyncSafe((0, import_node_path53.join)(home, ".claude", "settings.json"), import_node_fs58.readFileSync)
67361
+ readKnown: () => readFileSyncSafe((0, import_node_path54.join)(home, ...KNOWN_MARKETPLACES_RELATIVE), import_node_fs59.readFileSync),
67362
+ readSettings: () => readFileSyncSafe((0, import_node_path54.join)(home, ".claude", "settings.json"), import_node_fs59.readFileSync)
66982
67363
  });
66983
67364
  return {
66984
67365
  guide: "Read the MMI org-guide skill before project work; load only the relevant topic. Use mmi-help for a short introduction.",
@@ -68679,9 +69060,9 @@ function formatExplainGroup(cmd, rootName) {
68679
69060
  lines2.push(...formatOwnDetail(cmd));
68680
69061
  lines2.push("Commands:");
68681
69062
  for (const child2 of cmd.subcommands) {
68682
- const args = child2.arguments.map((arg) => {
68683
- const name = arg.variadic ? `${arg.name}...` : arg.name;
68684
- return arg.required ? `<${name}>` : `[${name}]`;
69063
+ const args = child2.arguments.map((arg2) => {
69064
+ const name = arg2.variadic ? `${arg2.name}...` : arg2.name;
69065
+ return arg2.required ? `<${name}>` : `[${name}]`;
68685
69066
  }).join(" ");
68686
69067
  lines2.push(` ${canonical(child2)}${args ? ` ${args}` : ""}${child2.description ? ` \u2014 ${child2.description}` : ""}`);
68687
69068
  }
@@ -68702,11 +69083,11 @@ function briefCommand(cmd) {
68702
69083
  return {
68703
69084
  path: cmd.path,
68704
69085
  ...cmd.description ? { description: cmd.description } : {},
68705
- arguments: cmd.arguments.map((arg) => ({
68706
- name: arg.name,
68707
- required: arg.required,
68708
- ...arg.variadic ? { variadic: true } : {},
68709
- ...arg.description ? { description: arg.description } : {}
69086
+ arguments: cmd.arguments.map((arg2) => ({
69087
+ name: arg2.name,
69088
+ required: arg2.required,
69089
+ ...arg2.variadic ? { variadic: true } : {},
69090
+ ...arg2.description ? { description: arg2.description } : {}
68710
69091
  })),
68711
69092
  options: ownOptions(cmd).map((opt) => ({
68712
69093
  flags: opt.flags,
@@ -68729,15 +69110,15 @@ function explainBriefManifest(manifest, command) {
68729
69110
  }
68730
69111
  function formatExplainBrief(cmd, rootName) {
68731
69112
  const lines2 = [`${rootName} ${cmd.path}${cmd.description ? ` \u2014 ${cmd.description}` : ""}`];
68732
- for (const arg of cmd.arguments) {
68733
- const flag = arg.required ? `<${arg.name}>` : `[${arg.name}]`;
68734
- lines2.push(` ${flag} ${arg.required ? "required" : "optional"}${arg.description ? ` ${arg.description}` : ""}`);
69113
+ for (const arg2 of cmd.arguments) {
69114
+ const flag = arg2.required ? `<${arg2.name}>` : `[${arg2.name}]`;
69115
+ lines2.push(` ${flag} ${arg2.required ? "required" : "optional"}${arg2.description ? ` ${arg2.description}` : ""}`);
68735
69116
  }
68736
69117
  for (const opt of ownOptions(cmd)) {
68737
69118
  lines2.push(` ${opt.flags} ${opt.takesValue ? "takes-value" : "flag"}${opt.mandatory ? " required" : ""}${opt.description ? ` ${opt.description}` : ""}`);
68738
69119
  }
68739
69120
  for (const child2 of cmd.subcommands) {
68740
- const args = child2.arguments.map((arg) => arg.required ? `<${arg.name}>` : `[${arg.name}]`).join(" ");
69121
+ const args = child2.arguments.map((arg2) => arg2.required ? `<${arg2.name}>` : `[${arg2.name}]`).join(" ");
68741
69122
  lines2.push(`${child2.path}${args ? ` ${args}` : ""}${child2.description ? ` \u2014 ${child2.description}` : ""}`);
68742
69123
  for (const opt of ownOptions(child2)) {
68743
69124
  lines2.push(` ${opt.flags} ${opt.takesValue ? "takes-value" : "flag"}${opt.mandatory ? " required" : ""}${opt.description ? ` ${opt.description}` : ""}`);
@@ -69644,8 +70025,8 @@ async function repoWorkflowEntries(client, repo) {
69644
70025
  for (const wf of workflowsList) {
69645
70026
  if (typeof wf?.path !== "string" || !wf.path) continue;
69646
70027
  if (!wf.path.startsWith(".github/workflows/")) continue;
69647
- const basename5 = wf.path.split("/").pop() ?? wf.path;
69648
- const name = `${repo}/${basename5.replace(/\.ya?ml$/, "")}`;
70028
+ const basename6 = wf.path.split("/").pop() ?? wf.path;
70029
+ const name = `${repo}/${basename6.replace(/\.ya?ml$/, "")}`;
69649
70030
  if (wf.state !== "active") {
69650
70031
  disabled.push(name);
69651
70032
  continue;
@@ -70109,8 +70490,8 @@ function registerSessionReport(program3) {
70109
70490
  }
70110
70491
 
70111
70492
  // src/stage-commands.ts
70112
- var import_node_fs59 = require("node:fs");
70113
- var import_node_path54 = require("node:path");
70493
+ var import_node_fs60 = require("node:fs");
70494
+ var import_node_path55 = require("node:path");
70114
70495
  init_cli_shared();
70115
70496
  init_clean_exit();
70116
70497
 
@@ -70358,8 +70739,8 @@ function registerStageCommands(program3) {
70358
70739
  const repo = Array.isArray(project2?.repos) && typeof project2.repos[0] === "string" ? project2.repos[0] : slug;
70359
70740
  const resolution = decideStage({
70360
70741
  registry: { deployModel: project2?.deployModel, portRange, error: read.ok ? void 0 : read.error },
70361
- hasCompose: (0, import_node_fs59.existsSync)((0, import_node_path54.join)(process.cwd(), "docker-compose.yml")),
70362
- hasEnvExample: (0, import_node_fs59.existsSync)((0, import_node_path54.join)(process.cwd(), ".env.example")),
70742
+ hasCompose: (0, import_node_fs60.existsSync)((0, import_node_path55.join)(process.cwd(), "docker-compose.yml")),
70743
+ hasEnvExample: (0, import_node_fs60.existsSync)((0, import_node_path55.join)(process.cwd(), ".env.example")),
70363
70744
  repo
70364
70745
  });
70365
70746
  if (resolution.source === "derived" && resolution.derived) {
@@ -70652,19 +71033,19 @@ vercel preview (${preview.branch}): ${d.state}${d.url ? ` \u2014 ${d.url}` : ""}
70652
71033
 
70653
71034
  // src/tenant-artifact.ts
70654
71035
  var import_node_crypto23 = require("node:crypto");
70655
- var import_node_fs60 = require("node:fs");
71036
+ var import_node_fs61 = require("node:fs");
70656
71037
  var import_promises11 = require("node:fs/promises");
70657
- var import_node_path55 = require("node:path");
71038
+ var import_node_path56 = require("node:path");
70658
71039
  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}$/;
70659
71040
  var MAX_BYTES2 = 5 * 1024 * 1024 * 1024;
70660
71041
  async function sha256File(path2) {
70661
71042
  const hash = (0, import_node_crypto23.createHash)("sha256");
70662
- for await (const chunk of (0, import_node_fs60.createReadStream)(path2)) hash.update(chunk);
71043
+ for await (const chunk of (0, import_node_fs61.createReadStream)(path2)) hash.update(chunk);
70663
71044
  return hash.digest("hex");
70664
71045
  }
70665
71046
  async function putTenantArtifact(repo, stage, inputPath, deps) {
70666
71047
  if (!["dev", "rc", "main"].includes(stage)) throw new Error("tenant artifact put: <stage> must be dev, rc, or main");
70667
- const path2 = (0, import_node_path55.resolve)(inputPath);
71048
+ const path2 = (0, import_node_path56.resolve)(inputPath);
70668
71049
  const info = await (0, import_promises11.stat)(path2);
70669
71050
  if (!info.isFile()) throw new Error("tenant artifact put: input path must be a file");
70670
71051
  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`);
@@ -70682,7 +71063,7 @@ async function putTenantArtifact(repo, stage, inputPath, deps) {
70682
71063
  return [key, value];
70683
71064
  }));
70684
71065
  headers["content-length"] = String(info.size);
70685
- const stream = (0, import_node_fs60.createReadStream)(path2);
71066
+ const stream = (0, import_node_fs61.createReadStream)(path2);
70686
71067
  let uploaded;
70687
71068
  try {
70688
71069
  uploaded = await fetch(body.uploadUrl, {
@@ -71036,7 +71417,7 @@ function renderVerifySecrets(body) {
71036
71417
  }
71037
71418
 
71038
71419
  // src/command-register-developer.ts
71039
- var import_node_fs65 = require("node:fs");
71420
+ var import_node_fs66 = require("node:fs");
71040
71421
  init_clean_exit();
71041
71422
  init_cli_shared();
71042
71423
  init_error_codes();
@@ -71069,12 +71450,13 @@ async function resolveWhoami(deps) {
71069
71450
  }
71070
71451
 
71071
71452
  // src/command-register-developer.ts
71072
- var import_node_path62 = require("node:path");
71453
+ var import_node_path63 = require("node:path");
71073
71454
 
71074
71455
  // src/doc-refs-command-source.ts
71075
71456
  var import_node_child_process21 = require("node:child_process");
71076
- var import_node_fs61 = require("node:fs");
71077
- var import_node_path56 = require("node:path");
71457
+ var import_node_fs62 = require("node:fs");
71458
+ var import_node_path57 = require("node:path");
71459
+ var IN_PROCESS_SOURCE = "in-process";
71078
71460
  var BUNDLE_MANIFEST_TIMEOUT_MS = 12e4;
71079
71461
  var BUNDLE_MANIFEST_MAX_BUFFER = 64 * 1024 * 1024;
71080
71462
  var flagsOf = (options) => new Set((options ?? []).flatMap((option) => String(option?.flags ?? "").match(/--[\w-]+/g) ?? []));
@@ -71095,7 +71477,7 @@ function inventoryFromManifest(manifest, source) {
71095
71477
  function readBundleManifest(bundle, exec3 = import_node_child_process21.execFileSync) {
71096
71478
  try {
71097
71479
  const text = exec3(process.execPath, [bundle, "commands", "--all", "--json"], {
71098
- cwd: (0, import_node_path56.dirname)(bundle),
71480
+ cwd: (0, import_node_path57.dirname)(bundle),
71099
71481
  encoding: "utf8",
71100
71482
  windowsHide: true,
71101
71483
  timeout: BUNDLE_MANIFEST_TIMEOUT_MS,
@@ -71110,20 +71492,29 @@ function readBundleManifest(bundle, exec3 = import_node_child_process21.execFile
71110
71492
  }
71111
71493
  function isRunningBundle(bundle, argv1 = process.argv[1], platform2 = process.platform) {
71112
71494
  if (!argv1) return false;
71113
- const norm2 = (path2) => {
71114
- const absolute = (0, import_node_path56.resolve)(path2);
71495
+ const norm3 = (path2) => {
71496
+ const absolute = (0, import_node_path57.resolve)(path2);
71115
71497
  return platform2 === "win32" ? absolute.toLowerCase() : absolute;
71116
71498
  };
71117
- const running = norm2(argv1);
71118
- if (!["main.cjs", "index.cjs"].includes((0, import_node_path56.basename)(running))) return false;
71119
- return (0, import_node_path56.dirname)(running) === (0, import_node_path56.dirname)(norm2(bundle));
71499
+ const running = norm3(argv1);
71500
+ if (!["main.cjs", "index.cjs"].includes((0, import_node_path57.basename)(running))) return false;
71501
+ return (0, import_node_path57.dirname)(running) === (0, import_node_path57.dirname)(norm3(bundle));
71502
+ }
71503
+ function nameUnknownCommandSources(findings, source, root) {
71504
+ const checkoutBundle = (0, import_node_path57.resolve)(root, "cli", "dist", "main.cjs");
71505
+ const recovery = source !== IN_PROCESS_SOURCE && (0, import_node_path57.resolve)(source) === checkoutBundle ? "; rebuild with `npm --prefix cli run build` and retry, or pass `--commands-from <bundle>`" : "";
71506
+ for (const finding of findings) {
71507
+ if (finding.kind !== "unknown-command") continue;
71508
+ finding.commandSource = source;
71509
+ finding.detail += ` (source: ${source}${recovery})`;
71510
+ }
71120
71511
  }
71121
71512
  function resolveCommandInventory(deps) {
71122
- const exists = deps.exists ?? import_node_fs61.existsSync;
71513
+ const exists = deps.exists ?? import_node_fs62.existsSync;
71123
71514
  const read = deps.read ?? ((bundle) => readBundleManifest(bundle));
71124
71515
  const warnings = [];
71125
71516
  if (deps.from) {
71126
- const bundle = (0, import_node_path56.isAbsolute)(deps.from) ? deps.from : (0, import_node_path56.resolve)(deps.root, deps.from);
71517
+ const bundle = (0, import_node_path57.isAbsolute)(deps.from) ? deps.from : (0, import_node_path57.resolve)(deps.root, deps.from);
71127
71518
  if (!exists(bundle)) {
71128
71519
  throw new Error(`docs refs --commands-from: ${bundle} does not exist \u2014 name the CLI bundle to read commands from (usually cli/dist/main.cjs)`);
71129
71520
  }
@@ -71133,10 +71524,13 @@ function resolveCommandInventory(deps) {
71133
71524
  }
71134
71525
  return { inventory: inventory2, warnings };
71135
71526
  }
71136
- const treeBundle = (0, import_node_path56.join)(deps.root, "cli", "dist", "main.cjs");
71137
- if (!exists(treeBundle) || isRunningBundle(treeBundle, deps.argv1, deps.platform)) {
71527
+ const treeBundle = (0, import_node_path57.join)(deps.root, "cli", "dist", "main.cjs");
71528
+ if (!exists(treeBundle)) {
71138
71529
  return { inventory: deps.inProcess(), warnings };
71139
71530
  }
71531
+ if (isRunningBundle(treeBundle, deps.argv1, deps.platform)) {
71532
+ return { inventory: { ...deps.inProcess(), source: treeBundle }, warnings };
71533
+ }
71140
71534
  const inventory = inventoryFromManifest(read(treeBundle), treeBundle);
71141
71535
  if (!inventory) {
71142
71536
  warnings.push({
@@ -71251,19 +71645,19 @@ async function executeWaveLand(plan, deps) {
71251
71645
  // src/dist-drift.ts
71252
71646
  var import_node_child_process22 = require("node:child_process");
71253
71647
  var import_node_crypto25 = require("node:crypto");
71254
- var import_node_fs63 = require("node:fs");
71648
+ var import_node_fs64 = require("node:fs");
71255
71649
  var import_node_os27 = require("node:os");
71256
- var import_node_path58 = require("node:path");
71650
+ var import_node_path59 = require("node:path");
71257
71651
 
71258
71652
  // ../scripts/distribution-digest.mjs
71259
71653
  var import_node_crypto24 = require("node:crypto");
71260
- var import_node_fs62 = require("node:fs");
71261
- var import_node_path57 = require("node:path");
71654
+ var import_node_fs63 = require("node:fs");
71655
+ var import_node_path58 = require("node:path");
71262
71656
  var slash = (value) => value.replaceAll("\\", "/");
71263
71657
  function repoPath(root, declaredPath, label) {
71264
- const absoluteRoot = (0, import_node_path57.resolve)(root);
71265
- const target = (0, import_node_path57.resolve)(root, declaredPath);
71266
- if (target !== absoluteRoot && !target.startsWith(`${absoluteRoot}${import_node_path57.sep}`)) {
71658
+ const absoluteRoot = (0, import_node_path58.resolve)(root);
71659
+ const target = (0, import_node_path58.resolve)(root, declaredPath);
71660
+ if (target !== absoluteRoot && !target.startsWith(`${absoluteRoot}${import_node_path58.sep}`)) {
71267
71661
  throw new Error(`${label} ${declaredPath} escapes the repository root`);
71268
71662
  }
71269
71663
  return target;
@@ -71271,7 +71665,7 @@ function repoPath(root, declaredPath, label) {
71271
71665
  function digestFiles(files) {
71272
71666
  const hash = (0, import_node_crypto24.createHash)("sha256");
71273
71667
  for (const file of [...files].sort((a, b) => a.relative.localeCompare(b.relative))) {
71274
- const content = file.stat.isSymbolicLink() ? Buffer.from((0, import_node_fs62.readlinkSync)(file.absolute), "utf8") : (0, import_node_fs62.readFileSync)(file.absolute);
71668
+ const content = file.stat.isSymbolicLink() ? Buffer.from((0, import_node_fs63.readlinkSync)(file.absolute), "utf8") : (0, import_node_fs63.readFileSync)(file.absolute);
71275
71669
  hash.update(file.relative, "utf8");
71276
71670
  hash.update("\0");
71277
71671
  hash.update(file.stat.isSymbolicLink() ? "symlink" : "file", "utf8");
@@ -71286,8 +71680,8 @@ function digestFiles(files) {
71286
71680
  function digestPackedFiles(packageRoot, packedFiles) {
71287
71681
  return digestFiles(packedFiles.map((path2) => {
71288
71682
  const absolute = repoPath(packageRoot, path2, "packed artifact identity path");
71289
- if (!(0, import_node_fs62.existsSync)(absolute)) throw new Error(`packed artifact identity path ${path2} does not exist`);
71290
- return { absolute, relative: slash(path2), stat: (0, import_node_fs62.lstatSync)(absolute) };
71683
+ if (!(0, import_node_fs63.existsSync)(absolute)) throw new Error(`packed artifact identity path ${path2} does not exist`);
71684
+ return { absolute, relative: slash(path2), stat: (0, import_node_fs63.lstatSync)(absolute) };
71291
71685
  }));
71292
71686
  }
71293
71687
 
@@ -71372,13 +71766,13 @@ function renderDistDriftReceipt(receipt) {
71372
71766
  return lines2;
71373
71767
  }
71374
71768
  function readOrNull(path2) {
71375
- return (0, import_node_fs63.existsSync)(path2) ? (0, import_node_fs63.readFileSync)(path2) : null;
71769
+ return (0, import_node_fs64.existsSync)(path2) ? (0, import_node_fs64.readFileSync)(path2) : null;
71376
71770
  }
71377
71771
  function walkFiles(root) {
71378
71772
  const files = [];
71379
71773
  const walk2 = (directory) => {
71380
- for (const entry of (0, import_node_fs63.readdirSync)(directory, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
71381
- const child2 = (0, import_node_path58.join)(directory, entry.name);
71774
+ for (const entry of (0, import_node_fs64.readdirSync)(directory, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
71775
+ const child2 = (0, import_node_path59.join)(directory, entry.name);
71382
71776
  if (entry.isDirectory()) walk2(child2);
71383
71777
  else files.push(child2);
71384
71778
  }
@@ -71388,10 +71782,10 @@ function walkFiles(root) {
71388
71782
  }
71389
71783
  function bomPathFor(root) {
71390
71784
  try {
71391
- const registry2 = JSON.parse((0, import_node_fs63.readFileSync)((0, import_node_path58.join)(root, "surfaces.json"), "utf8"));
71392
- return (0, import_node_path58.join)(root, registry2?.sharedAgentCore?.releaseMetadata?.bomPath ?? "distribution-bom.json");
71785
+ const registry2 = JSON.parse((0, import_node_fs64.readFileSync)((0, import_node_path59.join)(root, "surfaces.json"), "utf8"));
71786
+ return (0, import_node_path59.join)(root, registry2?.sharedAgentCore?.releaseMetadata?.bomPath ?? "distribution-bom.json");
71393
71787
  } catch {
71394
- return (0, import_node_path58.join)(root, "distribution-bom.json");
71788
+ return (0, import_node_path59.join)(root, "distribution-bom.json");
71395
71789
  }
71396
71790
  }
71397
71791
  function rebuildTo(packageRoot, outDir) {
@@ -71404,40 +71798,40 @@ function rebuildTo(packageRoot, outDir) {
71404
71798
  });
71405
71799
  }
71406
71800
  function runDistStatus(root) {
71407
- const stage = (0, import_node_fs63.mkdtempSync)((0, import_node_path58.join)((0, import_node_os27.tmpdir)(), "mmi-dist-drift-"));
71801
+ const stage = (0, import_node_fs64.mkdtempSync)((0, import_node_path59.join)((0, import_node_os27.tmpdir)(), "mmi-dist-drift-"));
71408
71802
  let overlayCount = 0;
71409
71803
  try {
71410
- const cliOut = (0, import_node_path58.join)(stage, "cli-dist");
71411
- const hubOut = (0, import_node_path58.join)(stage, "hub-dist");
71412
- rebuildTo((0, import_node_path58.join)(root, "cli"), cliOut);
71413
- rebuildTo((0, import_node_path58.join)(root, "updater"), hubOut);
71804
+ const cliOut = (0, import_node_path59.join)(stage, "cli-dist");
71805
+ const hubOut = (0, import_node_path59.join)(stage, "hub-dist");
71806
+ rebuildTo((0, import_node_path59.join)(root, "cli"), cliOut);
71807
+ rebuildTo((0, import_node_path59.join)(root, "updater"), hubOut);
71414
71808
  const outDirFor = (packageDir) => packageDir === "cli" ? cliOut : hubOut;
71415
71809
  const rebuilt = (path2) => {
71416
71810
  const spec = DIST_ARTIFACTS.find((entry) => entry.path === path2);
71417
- return spec ? readOrNull((0, import_node_path58.join)(outDirFor(spec.packageDir), spec.output)) : null;
71811
+ return spec ? readOrNull((0, import_node_path59.join)(outDirFor(spec.packageDir), spec.output)) : null;
71418
71812
  };
71419
- const committed = (path2) => readOrNull((0, import_node_path58.join)(root, path2));
71420
- const tree = (path2) => readOrNull((0, import_node_path58.join)(root, path2));
71421
- const distRoot = (0, import_node_path58.join)(root, "cli", "dist");
71422
- const distTree = () => walkFiles(distRoot).map((absolute) => `cli/dist/${(0, import_node_path58.relative)(distRoot, absolute).replaceAll("\\", "/")}`);
71423
- const bom = JSON.parse((0, import_node_fs63.readFileSync)(bomPathFor(root), "utf8"));
71813
+ const committed = (path2) => readOrNull((0, import_node_path59.join)(root, path2));
71814
+ const tree = (path2) => readOrNull((0, import_node_path59.join)(root, path2));
71815
+ const distRoot = (0, import_node_path59.join)(root, "cli", "dist");
71816
+ const distTree = () => walkFiles(distRoot).map((absolute) => `cli/dist/${(0, import_node_path59.relative)(distRoot, absolute).replaceAll("\\", "/")}`);
71817
+ const bom = JSON.parse((0, import_node_fs64.readFileSync)(bomPathFor(root), "utf8"));
71424
71818
  const digest = (entries) => {
71425
- const overlay = (0, import_node_path58.join)(stage, `overlay-${overlayCount++}`);
71819
+ const overlay = (0, import_node_path59.join)(stage, `overlay-${overlayCount++}`);
71426
71820
  for (const entry of entries) {
71427
- const target = (0, import_node_path58.join)(overlay, entry.path);
71428
- (0, import_node_fs63.mkdirSync)((0, import_node_path58.dirname)(target), { recursive: true });
71429
- (0, import_node_fs63.writeFileSync)(target, entry.bytes);
71821
+ const target = (0, import_node_path59.join)(overlay, entry.path);
71822
+ (0, import_node_fs64.mkdirSync)((0, import_node_path59.dirname)(target), { recursive: true });
71823
+ (0, import_node_fs64.writeFileSync)(target, entry.bytes);
71430
71824
  }
71431
71825
  return digestPackedFiles(overlay, entries.map((entry) => entry.path));
71432
71826
  };
71433
71827
  return computeDistDriftReceipt({ committed, tree, rebuilt, distTree, bom, digest });
71434
71828
  } finally {
71435
- (0, import_node_fs63.rmSync)(stage, { recursive: true, force: true });
71829
+ (0, import_node_fs64.rmSync)(stage, { recursive: true, force: true });
71436
71830
  }
71437
71831
  }
71438
71832
 
71439
71833
  // src/doc-refs-live.ts
71440
- var import_node_path59 = require("node:path");
71834
+ var import_node_path60 = require("node:path");
71441
71835
  var concrete = (value) => !!value && !/[<>{}$]/.test(value);
71442
71836
  var liveOption = (tokens2, flag) => {
71443
71837
  const index = tokens2.indexOf(flag);
@@ -71510,7 +71904,7 @@ async function runLiveDocRefs(root, deps, live) {
71510
71904
  const offline = runDocRefs(root, { ...deps, runbooksOnly: true });
71511
71905
  const read = deps.readFile ?? readFileOrNull;
71512
71906
  const docs = Object.fromEntries((deps.listDocs ?? defaultListDocs)(root).flatMap((doc) => {
71513
- const body = read((0, import_node_path59.join)(root, doc));
71907
+ const body = read((0, import_node_path60.join)(root, doc));
71514
71908
  return body !== null && isRunbook(doc, body) && !deps.isIgnored?.([doc]).has(doc) ? [[doc, body]] : [];
71515
71909
  }));
71516
71910
  const remote = await checkRunbookLive(docs, live);
@@ -71547,7 +71941,7 @@ function createRunbookLiveDeps(cliBin) {
71547
71941
  };
71548
71942
  const first = await probe().catch(() => 599);
71549
71943
  if (first < 500) return first;
71550
- await new Promise((resolve7) => setTimeout(resolve7, 2e4));
71944
+ await new Promise((resolve8) => setTimeout(resolve8, 2e4));
71551
71945
  return probe();
71552
71946
  }
71553
71947
  };
@@ -71721,7 +72115,7 @@ async function diagnoseHub(deps) {
71721
72115
 
71722
72116
  // src/schedules-lift-command.ts
71723
72117
  var import_promises12 = require("node:fs/promises");
71724
- var import_node_path60 = require("node:path");
72118
+ var import_node_path61 = require("node:path");
71725
72119
  init_clean_exit();
71726
72120
  init_cli_shared();
71727
72121
  var DEFAULT_WORKFLOWS_DIR = ".github/workflows";
@@ -71750,7 +72144,7 @@ async function readWorkflowFiles(dir) {
71750
72144
  const files = [];
71751
72145
  for (const name of names.sort()) {
71752
72146
  if (!/\.ya?ml$/.test(name)) continue;
71753
- files.push({ path: `.github/workflows/${name}`, text: await (0, import_promises12.readFile)((0, import_node_path60.join)(dir, name), "utf8") });
72147
+ files.push({ path: `.github/workflows/${name}`, text: await (0, import_promises12.readFile)((0, import_node_path61.join)(dir, name), "utf8") });
71754
72148
  }
71755
72149
  return files;
71756
72150
  }
@@ -71833,8 +72227,8 @@ function registerSchedulesLiftCommand(program3, deps = {}) {
71833
72227
 
71834
72228
  // src/spawn-policy-core.ts
71835
72229
  var import_node_child_process24 = require("node:child_process");
71836
- var import_node_fs64 = require("node:fs");
71837
- var import_node_path61 = require("node:path");
72230
+ var import_node_fs65 = require("node:fs");
72231
+ var import_node_path62 = require("node:path");
71838
72232
  var SPAWNERS = ["spawn", "spawnSync", "exec", "execSync", "execFile", "execFileSync"];
71839
72233
  var CALL_SOURCE = String.raw`(^|[^.\w$])(${SPAWNERS.join("|")})\s*\(`;
71840
72234
  var SOURCE_EXT = /\.(ts|mts|cts|js|mjs|cjs)$/;
@@ -71920,7 +72314,7 @@ function runSpawnPolicy(root) {
71920
72314
  for (const file of files) {
71921
72315
  let raw;
71922
72316
  try {
71923
- raw = (0, import_node_fs64.readFileSync)((0, import_node_path61.join)(root, file), "utf8");
72317
+ raw = (0, import_node_fs65.readFileSync)((0, import_node_path62.join)(root, file), "utf8");
71924
72318
  } catch {
71925
72319
  continue;
71926
72320
  }
@@ -71940,19 +72334,19 @@ function runSpawnPolicy(root) {
71940
72334
  function registerDeveloperCommands(program3) {
71941
72335
  const rules = program3.command("rules").description("org-managed .gitignore delivery");
71942
72336
  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) => {
71943
- const path2 = (0, import_node_path62.join)(process.cwd(), ".gitignore");
71944
- const current = (0, import_node_fs65.existsSync)(path2) ? (0, import_node_fs65.readFileSync)(path2, "utf8") : null;
72337
+ const path2 = (0, import_node_path63.join)(process.cwd(), ".gitignore");
72338
+ const current = (0, import_node_fs66.existsSync)(path2) ? (0, import_node_fs66.readFileSync)(path2, "utf8") : null;
71945
72339
  const plan = planManagedGitignore(current);
71946
72340
  const drift = [...plan.added.map((l) => `+${l}`), ...plan.removed.map((l) => `-${l}`)].join(", ") || "block normalize";
71947
72341
  if (opts.json) {
71948
- if (opts.write && plan.changed) (0, import_node_fs65.writeFileSync)(path2, plan.content, "utf8");
72342
+ if (opts.write && plan.changed) (0, import_node_fs66.writeFileSync)(path2, plan.content, "utf8");
71949
72343
  console.log(JSON.stringify(plan, null, 2));
71950
72344
  if (!opts.write && plan.changed) process.exitCode = 1;
71951
72345
  return;
71952
72346
  }
71953
72347
  if (opts.write) {
71954
72348
  if (plan.changed) {
71955
- (0, import_node_fs65.writeFileSync)(path2, plan.content, "utf8");
72349
+ (0, import_node_fs66.writeFileSync)(path2, plan.content, "utf8");
71956
72350
  console.log(`mmi-cli devops org rules gitignore: updated .gitignore (${drift})`);
71957
72351
  } else {
71958
72352
  console.log("mmi-cli devops org rules gitignore: up to date");
@@ -72148,12 +72542,13 @@ function registerDeveloperCommands(program3) {
72148
72542
  const deps = { commandPaths, commandOptions, commandSource: source, base: o.base, runbooksOnly: o.runbooksOnly };
72149
72543
  const result = o.live ? await runLiveDocRefs(root, deps, createRunbookLiveDeps(process.argv[1])) : runDocRefs(root, deps);
72150
72544
  result.warnings.push(...resolved.warnings);
72545
+ nameUnknownCommandSources(result.findings, source, root);
72151
72546
  if (o.json) {
72152
72547
  consoleIo.log(JSON.stringify({ ok: result.ok, docCount: result.docCount, findings: result.findings, warnings: result.warnings }, null, 2));
72153
72548
  if (!result.ok) process.exitCode = 1;
72154
72549
  return;
72155
72550
  }
72156
- for (const w of result.warnings) console.warn(`WARNING: ${w.doc}:${w.line} [${w.kind}] ${w.detail}`);
72551
+ for (const w of result.warnings) console.warn(`WARNING: ${formatDocRefFinding(w)}`);
72157
72552
  if (result.ok) {
72158
72553
  console.log(
72159
72554
  `doc refs: ${result.docCount} docs, every reference resolves` + (result.warnings.length ? ` (${result.warnings.length} warning(s))` : "")
@@ -72163,7 +72558,7 @@ function registerDeveloperCommands(program3) {
72163
72558
  const hasStale = result.findings.some((f) => f.kind === "runbook-section-stale" || f.kind === "seed-runbook-unreviewed");
72164
72559
  const hasRefs = result.findings.some((f) => f.kind !== "runbook-section-stale" && f.kind !== "seed-runbook-unreviewed");
72165
72560
  console.error(hasStale && !hasRefs ? "doc refs: stale runbook section(s)" : hasStale && hasRefs ? "doc refs: unresolved references and stale runbook section(s)" : "doc refs: unresolved references");
72166
- for (const f of result.findings) console.error(`- ${f.doc}:${f.line} [${f.kind}] ${f.detail}`);
72561
+ for (const f of result.findings) console.error(`- ${formatDocRefFinding(f)}`);
72167
72562
  process.exitCode = 1;
72168
72563
  } catch (e) {
72169
72564
  await failGraceful(e.message);
@@ -72269,7 +72664,7 @@ ${r.stderr ?? ""}`).catch(() => "");
72269
72664
  var ENV_HEAL_LOCK_STALE_MS = 10 * 6e4;
72270
72665
  var ENV_HEAL_LOCK_MAX_WAIT_MS = 2 * 6e4;
72271
72666
  function envHealLockPath(home) {
72272
- return (0, import_node_path63.join)(home, ".claude", "plugins", ".mmi-env-heal.lock");
72667
+ return (0, import_node_path64.join)(home, ".claude", "plugins", ".mmi-env-heal.lock");
72273
72668
  }
72274
72669
  async function withEnvHealLock(what, run) {
72275
72670
  try {
@@ -72407,7 +72802,7 @@ function mmiDoctorDeps(opts = {}) {
72407
72802
  );
72408
72803
  const result = applyPluginCachePlan(
72409
72804
  plan,
72410
- (p) => (0, import_node_fs66.rmSync)(p, { recursive: true }),
72805
+ (p) => (0, import_node_fs67.rmSync)(p, { recursive: true }),
72411
72806
  stagingApplyFsGuard(configRoot)
72412
72807
  );
72413
72808
  return {
@@ -72442,7 +72837,7 @@ function mmiDoctorDeps(opts = {}) {
72442
72837
  // has no generated routing index would
72443
72838
  // get a permanent — demanding an artifact it never asked for.
72444
72839
  docsIndexState: (root) => {
72445
- if (!(0, import_node_fs66.existsSync)((0, import_node_path63.join)(root, DOCS_INDEX_PATH))) return void 0;
72840
+ if (!(0, import_node_fs67.existsSync)((0, import_node_path64.join)(root, DOCS_INDEX_PATH))) return void 0;
72446
72841
  const real = createDocsIndexDeps(root);
72447
72842
  let docs;
72448
72843
  const listDocs = () => docs ??= real.listDocs();
@@ -72451,7 +72846,7 @@ function mmiDoctorDeps(opts = {}) {
72451
72846
  },
72452
72847
  // #4168: working-tree heal — write if drifted, then re-check. Commit remains the operator's step.
72453
72848
  healDocsIndex: (root) => {
72454
- if (!(0, import_node_fs66.existsSync)((0, import_node_path63.join)(root, DOCS_INDEX_PATH))) return { drift: false, docCount: 0 };
72849
+ if (!(0, import_node_fs67.existsSync)((0, import_node_path64.join)(root, DOCS_INDEX_PATH))) return { drift: false, docCount: 0 };
72455
72850
  const real = createDocsIndexDeps(root);
72456
72851
  let docs;
72457
72852
  const listDocs = () => docs ??= real.listDocs();
@@ -72472,8 +72867,8 @@ function mmiDoctorDeps(opts = {}) {
72472
72867
  });
72473
72868
  const raced = await Promise.race([
72474
72869
  work.then((r) => ({ ...r, timedOut: false })),
72475
- new Promise((resolve7) => {
72476
- ceiling = setTimeout(() => resolve7({ timedOut: true, scanned: 0, findings: 0, fixed: 0, failed: 0 }), BOARD_DOCTOR_TIMEOUT_MS);
72870
+ new Promise((resolve8) => {
72871
+ ceiling = setTimeout(() => resolve8({ timedOut: true, scanned: 0, findings: 0, fixed: 0, failed: 0 }), BOARD_DOCTOR_TIMEOUT_MS);
72477
72872
  })
72478
72873
  ]);
72479
72874
  if (raced.timedOut) return { scanned: 0, findings: 0, fixed: 0, failed: 0, timedOut: true };
@@ -72506,8 +72901,8 @@ function mmiDoctorDeps(opts = {}) {
72506
72901
  incomplete: nb.incomplete,
72507
72902
  timedOut: false
72508
72903
  })),
72509
- new Promise((resolve7) => {
72510
- ceiling = setTimeout(() => resolve7({ driftLines: [], incomplete: [], timedOut: true }), SCHEDULES_DRIFT_TIMEOUT_MS);
72904
+ new Promise((resolve8) => {
72905
+ ceiling = setTimeout(() => resolve8({ driftLines: [], incomplete: [], timedOut: true }), SCHEDULES_DRIFT_TIMEOUT_MS);
72511
72906
  })
72512
72907
  ]);
72513
72908
  if (!raced.timedOut && raced.incomplete.length === 0) writeSchedulesDriftCache(cachePath, raced.driftLines);
@@ -72991,10 +73386,10 @@ tenant.command("logs <owner/repo> <stage>").description("READ-ONLY: read a tenan
72991
73386
  return failGraceful(`runtime tenant logs: ${e.message}`);
72992
73387
  }
72993
73388
  });
72994
- tenant.command("redeploy <owner/repo> <stage>").description("re-dispatch the central tenant-deploy.yml for an already-promoted ref (no re-tag/merge); train-authority gated").option("--ref <ref>", "ref to deploy (defaults to the stage branch rc/main, or `development` for dev and for a single-track repo's main, where --ref main is refused)").option("--watch", "block on the dispatched run and report its outcome (gh run watch --exit-status)").option("--json", "machine-readable output").action(async (repo, stage, o) => {
73389
+ tenant.command("redeploy <owner/repo> <stage>").description("re-dispatch the central tenant-deploy.yml for an already-promoted ref (no re-tag/merge); train-authority gated").option("--ref <ref>", "ref to deploy (defaults to the currently serving SHA; older refs require --rollback)").option("--rollback", "allow deliberately deploying an older --ref").option("--watch", "block on the dispatched run and report its outcome (gh run watch --exit-status)").option("--json", "machine-readable output").action(async (repo, stage, o) => {
72995
73390
  if (stage !== "dev" && stage !== "rc" && stage !== "main") return fail("runtime tenant redeploy: <stage> must be dev, rc, or main");
72996
73391
  try {
72997
- const raw = await runTenantRedeploy(trainApplyDeps(), { repo, stage, ref: o.ref, watch: o.watch });
73392
+ const raw = await runTenantRedeploy(trainApplyDeps(), { repo, stage, ref: o.ref, rollback: o.rollback, watch: o.watch });
72998
73393
  const result = raw.workflowRuns ? { ...raw, workflowRuns: raw.workflowRuns.map(workflowRunWithEvidence) } : raw;
72999
73394
  return printLine(o.json ? JSON.stringify(result, null, 2) : renderTenantRedeploy(result));
73000
73395
  } catch (e) {
@@ -73254,7 +73649,7 @@ project.command("set [owner/repo]").description("upsert project META (idempotent
73254
73649
  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`);
73255
73650
  if (o.secretsFile) {
73256
73651
  try {
73257
- vars.push(`secrets=${(0, import_node_fs66.readFileSync)(o.secretsFile, "utf8")}`);
73652
+ vars.push(`secrets=${(0, import_node_fs67.readFileSync)(o.secretsFile, "utf8")}`);
73258
73653
  } catch (e) {
73259
73654
  return fail(`org project set: cannot read --secrets-file ${o.secretsFile}: ${e.message}`);
73260
73655
  }
@@ -73388,7 +73783,7 @@ fullTrack.command("readiness <owner/repo>").description("aggregate branch topolo
73388
73783
  const cfg = await loadConfig();
73389
73784
  const reg = registryClientDeps(cfg);
73390
73785
  const slug = slugOf(repo);
73391
- const [metaRead, deployFacts, authority, dev, rc, main] = await Promise.all([
73786
+ const [metaRead, deployFacts, authority, dev, rc, main2] = await Promise.all([
73392
73787
  fetchProjectBySlugChecked(slug, reg),
73393
73788
  fetchDeployFactsBySlug(slug, reg),
73394
73789
  fetchTrainAuthority(repo, reg),
@@ -73403,7 +73798,7 @@ fullTrack.command("readiness <owner/repo>").description("aggregate branch topolo
73403
73798
  meta: metaRead.project,
73404
73799
  deployFacts,
73405
73800
  trainAuthority: authority.ok ? authority.authority : void 0,
73406
- runtime: { dev, rc, main }
73801
+ runtime: { dev, rc, main: main2 }
73407
73802
  });
73408
73803
  console.log(JSON.stringify(report, null, 2));
73409
73804
  if (!report.rcand.canApply) process.exitCode = 1;
@@ -73646,16 +74041,16 @@ function ciAuditDeps2() {
73646
74041
  // gate re-seed step is skipped gracefully rather than failing mid-run.
73647
74042
  readSeedFile: (path2) => {
73648
74043
  if (!root) return null;
73649
- const fullPath = (0, import_node_path63.join)(root, path2);
73650
- return (0, import_node_fs66.existsSync)(fullPath) ? (0, import_node_fs66.readFileSync)(fullPath, "utf8") : null;
74044
+ const fullPath = (0, import_node_path64.join)(root, path2);
74045
+ return (0, import_node_fs67.existsSync)(fullPath) ? (0, import_node_fs67.readFileSync)(fullPath, "utf8") : null;
73651
74046
  }
73652
74047
  };
73653
74048
  }
73654
74049
  function hubRoot2() {
73655
- const fromPkg = (0, import_node_path63.join)(__dirname, "..", "..");
74050
+ const fromPkg = (0, import_node_path64.join)(__dirname, "..", "..");
73656
74051
  const marker = "skills/bootstrap/seeds/manifest.json";
73657
- if ((0, import_node_fs66.existsSync)((0, import_node_path63.join)(fromPkg, marker))) return fromPkg;
73658
- if ((0, import_node_fs66.existsSync)((0, import_node_path63.join)(process.cwd(), marker))) return process.cwd();
74052
+ if ((0, import_node_fs67.existsSync)((0, import_node_path64.join)(fromPkg, marker))) return fromPkg;
74053
+ if ((0, import_node_fs67.existsSync)((0, import_node_path64.join)(process.cwd(), marker))) return process.cwd();
73659
74054
  return null;
73660
74055
  }
73661
74056
  registerQueryCommands(program2);
@@ -73812,10 +74207,10 @@ access.command("audit").description("audit collaborator roles + train-branch pus
73812
74207
  targets = resolution.targets;
73813
74208
  }
73814
74209
  const derivedMatrix = registryProjects ? accessMatrixFromProjects(registryProjects) : {};
73815
- const fileMatrix = (0, import_node_fs66.existsSync)("access-matrix.json") ? loadAccessMatrix((0, import_node_fs66.readFileSync)("access-matrix.json", "utf8")) : {};
74210
+ const fileMatrix = (0, import_node_fs67.existsSync)("access-matrix.json") ? loadAccessMatrix((0, import_node_fs67.readFileSync)("access-matrix.json", "utf8")) : {};
73816
74211
  const matrix = mergeAccessMatrix(fileMatrix, derivedMatrix);
73817
74212
  const dataAccess = registryProjects ? dataAccessContractsFromProjects(registryProjects) : { consumers: {} };
73818
- const sanctioned = (0, import_node_fs66.existsSync)("access-matrix.json") ? loadSanctionedAdmins((0, import_node_fs66.readFileSync)("access-matrix.json", "utf8")) : {};
74213
+ const sanctioned = (0, import_node_fs67.existsSync)("access-matrix.json") ? loadSanctionedAdmins((0, import_node_fs67.readFileSync)("access-matrix.json", "utf8")) : {};
73819
74214
  const report = await auditOrgAccess(targets, deps, matrix, dataAccess, sanctioned);
73820
74215
  console.log(o.json ? JSON.stringify(report, null, 2) : renderAccessReport(report));
73821
74216
  if (!report.ok) process.exitCode = 1;
@@ -73852,16 +74247,16 @@ function directoryBytes(path2) {
73852
74247
  let total = 0;
73853
74248
  let entries;
73854
74249
  try {
73855
- entries = (0, import_node_fs66.readdirSync)(path2, { withFileTypes: true });
74250
+ entries = (0, import_node_fs67.readdirSync)(path2, { withFileTypes: true });
73856
74251
  } catch {
73857
74252
  return 0;
73858
74253
  }
73859
74254
  for (const entry of entries) {
73860
- const child2 = (0, import_node_path63.join)(path2, entry.name);
74255
+ const child2 = (0, import_node_path64.join)(path2, entry.name);
73861
74256
  if (entry.isDirectory()) total += directoryBytes(child2);
73862
74257
  else {
73863
74258
  try {
73864
- total += (0, import_node_fs66.statSync)(child2).size;
74259
+ total += (0, import_node_fs67.statSync)(child2).size;
73865
74260
  } catch {
73866
74261
  }
73867
74262
  }
@@ -73869,25 +74264,25 @@ function directoryBytes(path2) {
73869
74264
  return total;
73870
74265
  }
73871
74266
  function listDirEntries(dir) {
73872
- return (0, import_node_fs66.readdirSync)(dir, { withFileTypes: true }).map((d) => ({ name: d.name, isDirectory: d.isDirectory() }));
74267
+ return (0, import_node_fs67.readdirSync)(dir, { withFileTypes: true }).map((d) => ({ name: d.name, isDirectory: d.isDirectory() }));
73873
74268
  }
73874
74269
  function readInstalledPluginRefs(configRoot) {
73875
74270
  const p = installedPluginsPathForConfig(configRoot);
73876
- if (!(0, import_node_fs66.existsSync)(p)) return [];
74271
+ if (!(0, import_node_fs67.existsSync)(p)) return [];
73877
74272
  try {
73878
- return installedPluginPaths((0, import_node_fs66.readFileSync)(p, "utf8"));
74273
+ return installedPluginPaths((0, import_node_fs67.readFileSync)(p, "utf8"));
73879
74274
  } catch {
73880
74275
  return null;
73881
74276
  }
73882
74277
  }
73883
74278
  function pluginCacheFsDeps(configRoot, dirBytes) {
73884
74279
  return {
73885
- exists: (p) => (0, import_node_fs66.existsSync)(p),
73886
- listVersionDirs: (root) => (0, import_node_fs66.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name),
74280
+ exists: (p) => (0, import_node_fs67.existsSync)(p),
74281
+ listVersionDirs: (root) => (0, import_node_fs67.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name),
73887
74282
  dirBytes,
73888
- listStagingDirs: (root) => (0, import_node_fs66.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => {
74283
+ listStagingDirs: (root) => (0, import_node_fs67.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => {
73889
74284
  try {
73890
- return { name: d.name, mtimeMs: newestMtimeMs((0, import_node_path63.join)(root, d.name), listDirEntries, (p) => (0, import_node_fs66.statSync)(p).mtimeMs) };
74285
+ return { name: d.name, mtimeMs: newestMtimeMs((0, import_node_path64.join)(root, d.name), listDirEntries, (p) => (0, import_node_fs67.statSync)(p).mtimeMs) };
73891
74286
  } catch {
73892
74287
  return { name: d.name, mtimeMs: Date.now() };
73893
74288
  }
@@ -73901,10 +74296,10 @@ function stagingApplyFsGuard(configRoot) {
73901
74296
  return {
73902
74297
  referencedPaths: () => readInstalledPluginRefs(configRoot),
73903
74298
  mtimeMs: (name) => {
73904
- const p = (0, import_node_path63.join)(stagingRoot, name);
73905
- if (!(0, import_node_fs66.existsSync)(p)) return null;
74299
+ const p = (0, import_node_path64.join)(stagingRoot, name);
74300
+ if (!(0, import_node_fs67.existsSync)(p)) return null;
73906
74301
  try {
73907
- return newestMtimeMs(p, listDirEntries, (q) => (0, import_node_fs66.statSync)(q).mtimeMs);
74302
+ return newestMtimeMs(p, listDirEntries, (q) => (0, import_node_fs67.statSync)(q).mtimeMs);
73908
74303
  } catch {
73909
74304
  return null;
73910
74305
  }
@@ -73930,7 +74325,7 @@ program2.command("plugin-prune").description(`prune stale cached MMI plugin vers
73930
74325
  { withBytes: true, configRoot, includeStaging: surface !== "codex" }
73931
74326
  );
73932
74327
  const anythingToDelete = plan.prune.length > 0 || plan.staging.length > 0;
73933
- const result = o.apply && anythingToDelete ? applyPluginCachePlan(plan, (p) => (0, import_node_fs66.rmSync)(p, { recursive: true, force: true }), stagingApplyFsGuard(configRoot)) : void 0;
74328
+ const result = o.apply && anythingToDelete ? applyPluginCachePlan(plan, (p) => (0, import_node_fs67.rmSync)(p, { recursive: true, force: true }), stagingApplyFsGuard(configRoot)) : void 0;
73934
74329
  const warnings = plan.prune.length > 0 ? [CONCURRENT_SESSION_WARNING] : [];
73935
74330
  if (o.json) console.log(JSON.stringify({ ...plan, warnings, applied: result ?? null }));
73936
74331
  else console.log(renderPluginCachePlan(plan, result));
@@ -73940,7 +74335,7 @@ program2.command("archive-prune").description("inventory worktree evidence archi
73940
74335
  let primary = o.repoRoot;
73941
74336
  if (!primary) {
73942
74337
  const common = await gitOut(["rev-parse", "--path-format=absolute", "--git-common-dir"]);
73943
- primary = common ? (0, import_node_path63.dirname)(common) : "";
74338
+ primary = common ? (0, import_node_path64.dirname)(common) : "";
73944
74339
  }
73945
74340
  if (!primary) {
73946
74341
  const detail = "archive-prune: not inside a git checkout (pass --repo-root <primary checkout>)";