@mutmutco/claude-plugin 4.6.24 → 4.6.25

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;
@@ -28166,10 +28166,10 @@ var rollout_plan_default = {
28166
28166
  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
28167
  },
28168
28168
  baseline: {
28169
- version: "4.6.24",
28170
- tag: "v4.6.24",
28171
- commit: "3632dffdf8a5",
28172
- npm: "@mutmutco/cli@4.6.24"
28169
+ version: "4.6.25",
28170
+ tag: "v4.6.25",
28171
+ commit: "8ca2371aca5a",
28172
+ npm: "@mutmutco/cli@4.6.25"
28173
28173
  },
28174
28174
  exitCriterion: "fleet-n-of-n",
28175
28175
  hubOnlyShortcut: "forbidden",
@@ -28186,14 +28186,14 @@ var rollout_plan_default = {
28186
28186
  repo: "mutmutco/mmi-hub",
28187
28187
  role: "canary",
28188
28188
  schedule: "train",
28189
- v3Target: "v4.6.24"
28189
+ v3Target: "v4.6.25"
28190
28190
  }
28191
28191
  ],
28192
28192
  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
28193
  rollback: {
28194
28194
  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)"
28195
+ mechanism: "npm dist-tag latest -> 4.6.25 and redeploy the Hub Lambda from tag v4.6.25 (8ca2371aca5a); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
28196
+ v3Target: "v4.6.25 (@mutmutco/cli@4.6.25, tag commit 8ca2371aca5a \u2014 last known-good release carrying the repo-index v4-only contract)"
28197
28197
  }
28198
28198
  },
28199
28199
  {
@@ -30288,7 +30288,7 @@ async function runMergeTreePreflight(deps, ours, theirs) {
30288
30288
  async function predictMergeConflicts(deps, ours, theirs) {
30289
30289
  return runMergeTreePreflight(deps, ours, theirs);
30290
30290
  }
30291
- async function mergeWithToleratedResolution(deps, sourceRef, label, resolve7, extraTolerated = []) {
30291
+ async function mergeWithToleratedResolution(deps, sourceRef, label, resolve8, extraTolerated = []) {
30292
30292
  try {
30293
30293
  await deps.run("git", ["merge", sourceRef, "--no-edit"]);
30294
30294
  return;
@@ -30302,7 +30302,7 @@ async function mergeWithToleratedResolution(deps, sourceRef, label, resolve7, ex
30302
30302
  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
30303
  );
30304
30304
  }
30305
- await deps.run("git", ["checkout", `--${resolve7}`, "--", ...unmerged]);
30305
+ await deps.run("git", ["checkout", `--${resolve8}`, "--", ...unmerged]);
30306
30306
  await deps.run("git", ["add", "--", ...unmerged]);
30307
30307
  await deps.run("git", ["commit", "--no-edit"]);
30308
30308
  }
@@ -30500,7 +30500,7 @@ var CORRELATE_SKEW_SLACK_MS = 1e4;
30500
30500
  var CORRELATE_PAGE_LIMIT = 50;
30501
30501
  var RUN_CONFIRM_ATTEMPTS = 3;
30502
30502
  var RUN_CONFIRM_DELAY_MS = 1e3;
30503
- var defaultSleep = (ms) => new Promise((resolve7) => setTimeout(resolve7, ms));
30503
+ var defaultSleep = (ms) => new Promise((resolve8) => setTimeout(resolve8, ms));
30504
30504
  function resolveSleep(deps) {
30505
30505
  return deps.sleep ?? defaultSleep;
30506
30506
  }
@@ -32391,7 +32391,7 @@ async function discoverShaWorkflowRuns(deps, repo, headSha, seenRunIds) {
32391
32391
  }
32392
32392
  return extra;
32393
32393
  }
32394
- async function dispatchDeploy(deps, ctx, stage, ref, model, watch, autoRunSince, autoRunHeadSha, dispatchFailure = "throw", publishDir) {
32394
+ async function dispatchDeploy(deps, ctx, stage, ref, model, watch, autoRunSince, autoRunHeadSha, dispatchFailure = "throw", publishDir, rollback = false) {
32395
32395
  if (validSuiteCutContext(ctx.repo, deps.suiteCut) && stage !== "dev") {
32396
32396
  return { note: "suite bundle-only: live backend not deployed", deployStatus: "success" };
32397
32397
  }
@@ -32399,7 +32399,7 @@ async function dispatchDeploy(deps, ctx, stage, ref, model, watch, autoRunSince,
32399
32399
  deps.warn?.("Release: Starting deployment");
32400
32400
  const since = (deps.now ?? Date.now)();
32401
32401
  try {
32402
- await dispatchTenantDeployWithRetry(deps, { repo: ctx.repo, slug: ctx.slug, ref, stage });
32402
+ await dispatchTenantDeployWithRetry(deps, { repo: ctx.repo, slug: ctx.slug, ref, stage, ...rollback ? { rollback: true } : {} });
32403
32403
  } catch (e) {
32404
32404
  if (dispatchFailure === "throw") throw e;
32405
32405
  const msg = e instanceof Error ? e.message : String(e);
@@ -32484,19 +32484,19 @@ async function buildEnvironments(deps, ctx, model, deployStatus, retirement) {
32484
32484
  const mainDomains = domains?.main;
32485
32485
  const rcDomains = domains?.rc;
32486
32486
  const healthStatus = deployStatus === "success" ? "success" : deployStatus === "failure" ? "failure" : "pending";
32487
- const main = { healthStatus };
32487
+ const main2 = { healthStatus };
32488
32488
  if (mainDomains?.length) {
32489
- main.domains = mainDomains;
32490
- main.healthUrl = `https://${mainDomains[0]}/`;
32489
+ main2.domains = mainDomains;
32490
+ main2.healthUrl = `https://${mainDomains[0]}/`;
32491
32491
  }
32492
32492
  const rc = { retirement: retirement.status };
32493
32493
  if (retirement.category) rc.retirementCategory = retirement.category;
32494
32494
  if (rcDomains?.length) rc.domains = rcDomains;
32495
32495
  if (domainsRead === "failed") {
32496
- main.domainsRead = "failed";
32496
+ main2.domainsRead = "failed";
32497
32497
  rc.domainsRead = "failed";
32498
32498
  }
32499
- return { main, rc };
32499
+ return { main: main2, rc };
32500
32500
  }
32501
32501
  var RETIRE_MAX_ATTEMPTS = 3;
32502
32502
  var RETIRE_BACKOFF_MS = 1500;
@@ -32577,14 +32577,27 @@ async function runTenantRedeploy(deps, options) {
32577
32577
  const meta = requireProjectMetaForTrain(await loadProjectMeta(deps, ctx), repo);
32578
32578
  const deployModel = requireDeployModel(meta, repo);
32579
32579
  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.`);
32580
+ if (options.rollback && !options.ref) throw new Error("--rollback requires --ref");
32581
+ const deployed = await deps.readDeployedSha?.(ctx.slug, stage).catch(() => void 0);
32582
+ let ref = options.ref ?? deployed ?? (stage === "dev" || singleTrackMain ? "development" : stage);
32583
+ if (!deployed) {
32584
+ deps.warn?.(`Serving DEPLOY#${stage} stamp unreadable or absent; falling back to ${ref}.`);
32585
+ } else if (options.ref) {
32586
+ if (!deps.compareDeployRef) throw new Error("Deploy ancestry comparison unavailable");
32587
+ const relation = await deps.compareDeployRef(repo, deployed, options.ref);
32588
+ if (!["ahead", "identical", "behind", "diverged"].includes(relation)) throw new Error("Invalid deploy ancestry comparison");
32589
+ if (relation === "behind") {
32590
+ if (options.rollback) deps.warn?.(`rolling back ${stage} from ${deployed} to ${options.ref}`);
32591
+ else {
32592
+ deps.warn?.(`${options.ref} is older than the serving release ${deployed}; redeploying the serving SHA instead (use --rollback for a deliberate rollback).`);
32593
+ ref = deployed;
32594
+ }
32595
+ }
32582
32596
  }
32583
- const ref = options.ref ?? (stage === "dev" || singleTrackMain ? "development" : stage);
32584
32597
  if (!isCentralDispatchModel(deployModel)) {
32585
32598
  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
32599
  }
32587
- const d = await dispatchDeploy(deps, ctx, stage, ref, deployModel, watch);
32600
+ const d = await dispatchDeploy(deps, ctx, stage, ref, deployModel, watch, void 0, void 0, "throw", void 0, options.rollback);
32588
32601
  return { ...ctx, command: "tenant-redeploy", stage, ref, deployModel, dispatch: d.note, runId: d.runId, runUrl: d.runUrl, workflowRuns: d.workflowRuns, deployStatus: d.deployStatus };
32589
32602
  }
32590
32603
  async function runTenantReconcile(deps, options) {
@@ -33804,7 +33817,7 @@ function lockTokenPid(token) {
33804
33817
  const m = /^(\d+)-/.exec(token);
33805
33818
  return m ? Number(m[1]) : void 0;
33806
33819
  }
33807
- var sleep = (ms) => new Promise((resolve7) => setTimeout(resolve7, ms));
33820
+ var sleep = (ms) => new Promise((resolve8) => setTimeout(resolve8, ms));
33808
33821
  var IMMEDIATE_RETRY_BUDGET = 3;
33809
33822
  var FileLockBusyError = class extends Error {
33810
33823
  lockPath;
@@ -34694,7 +34707,7 @@ async function defaultWatchRun(deps, runId, repo) {
34694
34707
  watchSaidSuccess = false;
34695
34708
  }
34696
34709
  for (let attempt = 0; attempt < RUN_CONFIRM_ATTEMPTS2; attempt++) {
34697
- if (attempt > 0) await new Promise((resolve7) => setTimeout(resolve7, RUN_CONFIRM_DELAY_MS2));
34710
+ if (attempt > 0) await new Promise((resolve8) => setTimeout(resolve8, RUN_CONFIRM_DELAY_MS2));
34698
34711
  try {
34699
34712
  const parsed = JSON.parse(await deps.run("gh", ["run", "view", String(runId), "--repo", repo, "--json", "status,conclusion"]));
34700
34713
  if (parsed.status === "completed") return parsed.conclusion === "success" ? "success" : "failure";
@@ -35758,11 +35771,11 @@ var defaultDeps = {
35758
35771
  // #5813: the caller supplies that command line. `process.argv` is NOT it — the house shim splices
35759
35772
  // the house root out in place, so re-reading it here re-ran the removed flat alias (`release …`
35760
35773
  // instead of `devops release …`) and the converged child refused with exit 2.
35761
- reexec: (argv) => new Promise((resolve7) => {
35774
+ reexec: (argv) => new Promise((resolve8) => {
35762
35775
  const args = [...argv];
35763
35776
  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));
35777
+ child2.on("exit", (code) => resolve8(code ?? 1));
35778
+ child2.on("error", () => resolve8(1));
35766
35779
  }),
35767
35780
  // stderr only — stdout may be carrying --json output.
35768
35781
  warn: (line) => console.error(line)
@@ -35919,7 +35932,7 @@ var defaultDeps2 = {
35919
35932
  }
35920
35933
  },
35921
35934
  registryWhoami: probeRegistryWhoami,
35922
- sleep: (ms) => new Promise((resolve7) => setTimeout(resolve7, ms)),
35935
+ sleep: (ms) => new Promise((resolve8) => setTimeout(resolve8, ms)),
35923
35936
  env: process.env
35924
35937
  };
35925
35938
  function message(e) {
@@ -41535,9 +41548,9 @@ function readCommonMistakes(cmd) {
41535
41548
  const notes = cmd[COMMON_MISTAKES];
41536
41549
  return Array.isArray(notes) && notes.length ? notes : void 0;
41537
41550
  }
41538
- function buildArgument(arg) {
41539
- const out = { name: arg.name(), required: arg.required, variadic: arg.variadic };
41540
- if (arg.description) out.description = arg.description;
41551
+ function buildArgument(arg2) {
41552
+ const out = { name: arg2.name(), required: arg2.required, variadic: arg2.variadic };
41553
+ if (arg2.description) out.description = arg2.description;
41541
41554
  return out;
41542
41555
  }
41543
41556
  function buildOption(opt) {
@@ -41767,9 +41780,9 @@ function buildDoorsCatalog(tree) {
41767
41780
  };
41768
41781
  });
41769
41782
  }
41770
- function argSignature(arg) {
41771
- const inner = arg.variadic ? `${arg.name}...` : arg.name;
41772
- return arg.required ? `<${inner}>` : `[${inner}]`;
41783
+ function argSignature(arg2) {
41784
+ const inner = arg2.variadic ? `${arg2.name}...` : arg2.name;
41785
+ return arg2.required ? `<${inner}>` : `[${inner}]`;
41773
41786
  }
41774
41787
  function formatManifestHuman(manifest, options = {}) {
41775
41788
  const root = options.all ? manifest.tree : manifest.primary_tree;
@@ -42190,7 +42203,7 @@ async function updatePrHeadFromBase(input) {
42190
42203
  } catch (e) {
42191
42204
  throw new Error(`GitHub could not update ${input.head} from ${input.base} (${e.message.trim()}) \u2014 ${remedy}`);
42192
42205
  }
42193
- const sleep2 = input.sleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms)));
42206
+ const sleep2 = input.sleep ?? ((ms) => new Promise((resolve8) => setTimeout(resolve8, ms)));
42194
42207
  for (let attempt = 0; attempt < PR_HEAD_UPDATE_API_READ_RETRIES; attempt++) {
42195
42208
  const to = await readHead2();
42196
42209
  if (to && to !== from) return { from, to, base: input.base, via: "update-branch-api" };
@@ -42213,7 +42226,7 @@ var PR_LAND_MERGE_RETRY_DELAY_MS = 3e4;
42213
42226
  async function mergeAutoWithTransientRetry(prNumber, repo, deps) {
42214
42227
  const now = deps.now ?? (() => Date.now());
42215
42228
  const deadline = now() + PR_LAND_ENQUEUE_TIMEOUT_MS;
42216
- const sleep2 = deps.sleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms)));
42229
+ const sleep2 = deps.sleep ?? ((ms) => new Promise((resolve8) => setTimeout(resolve8, ms)));
42217
42230
  const first = await deps.mergeAuto(prNumber, repo);
42218
42231
  let result = first;
42219
42232
  let transientRetried = false;
@@ -42252,7 +42265,7 @@ var AUTO_MERGE_CONFIRM_DELAY_MS = 15e3;
42252
42265
  async function confirmAutoMergeEnqueued(deps, options) {
42253
42266
  const retries = options?.retries ?? AUTO_MERGE_CONFIRM_RETRIES;
42254
42267
  const delayMs = options?.delayMs ?? AUTO_MERGE_CONFIRM_DELAY_MS;
42255
- const sleep2 = deps.sleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms)));
42268
+ const sleep2 = deps.sleep ?? ((ms) => new Promise((resolve8) => setTimeout(resolve8, ms)));
42256
42269
  for (let attempt = 0; attempt < retries; attempt++) {
42257
42270
  if (await deps.readMerged().catch(() => false)) return "merged";
42258
42271
  const stuck = await deps.readAutoMergeRequest().then((s) => s.trim()).catch(() => "");
@@ -42269,7 +42282,7 @@ async function confirmAutoMergeEnqueued(deps, options) {
42269
42282
  async function readGhPrStateWithRetry(fetchState, options) {
42270
42283
  const retries = options?.retries ?? PR_LAND_STATE_READ_RETRIES;
42271
42284
  const delayMs = options?.delayMs ?? PR_LAND_STATE_READ_DELAY_MS;
42272
- const sleep2 = options?.sleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms)));
42285
+ const sleep2 = options?.sleep ?? ((ms) => new Promise((resolve8) => setTimeout(resolve8, ms)));
42273
42286
  let lastError = "empty state";
42274
42287
  for (let attempt = 0; attempt < retries; attempt++) {
42275
42288
  try {
@@ -42421,7 +42434,7 @@ async function runPrLandOnce(prNumber, options, deps) {
42421
42434
  if (read.isInMergeQueue || read.state === "MERGED") confirmed = read;
42422
42435
  }
42423
42436
  if (!confirmed) {
42424
- await (deps.sleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms))))(deps.pollDelayMs?.(0) ?? PR_LAND_POLL_MS);
42437
+ await (deps.sleep ?? ((ms) => new Promise((resolve8) => setTimeout(resolve8, ms))))(deps.pollDelayMs?.(0) ?? PR_LAND_POLL_MS);
42425
42438
  }
42426
42439
  return pollPrMergeQueue(prNumber, options, deps, base, confirmed, deadline);
42427
42440
  }
@@ -42460,7 +42473,7 @@ function queueMerged(base, deps) {
42460
42473
  }
42461
42474
  async function pollPrMergeQueue(pr, options, deps, base, snapshot, deadlineMs) {
42462
42475
  const now = deps.now ?? (() => Date.now());
42463
- const sleep2 = deps.sleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms)));
42476
+ const sleep2 = deps.sleep ?? ((ms) => new Promise((resolve8) => setTimeout(resolve8, ms)));
42464
42477
  const timeoutMs = options.queueTimeoutMs ?? PR_LAND_QUEUE_TIMEOUT_MS;
42465
42478
  const deadline = deadlineMs ?? now() + timeoutMs;
42466
42479
  let attempt = 0;
@@ -43401,9 +43414,9 @@ function changedFilesSince(base, cwd, head) {
43401
43414
  const raw = git2(["diff", "--name-status", "-M", base, ...head ? [head] : [], "--"], cwd).trim();
43402
43415
  const changed = raw ? raw.split("\n").map((line) => {
43403
43416
  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]);
43417
+ const norm3 = (p) => p.replace(/\\/g, "/");
43418
+ const row = { status: parts[0][0], path: norm3(parts[parts.length - 1]) };
43419
+ if (parts.length > 2) row.from = norm3(parts[1]);
43407
43420
  return row;
43408
43421
  }) : [];
43409
43422
  if (head) return changed;
@@ -43681,7 +43694,7 @@ async function submitQueueAdmission(pr, repo, head, read, write, options, resume
43681
43694
  const rejected = (reason) => admissionRejected(reason, repo, pr);
43682
43695
  const reconcile = async (reason, recordEntry = false, resumingSaved = false) => {
43683
43696
  const maxReads = options.enqueueOnly ? 3 : 1;
43684
- const sleep3 = options.sleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms)));
43697
+ const sleep3 = options.sleep ?? ((ms) => new Promise((resolve8) => setTimeout(resolve8, ms)));
43685
43698
  for (let readAttempt = 0; readAttempt < maxReads; readAttempt++) {
43686
43699
  if (readAttempt) await sleep3(readAttempt * 1e3);
43687
43700
  try {
@@ -43836,7 +43849,7 @@ async function submitQueueAdmission(pr, repo, head, read, write, options, resume
43836
43849
  }
43837
43850
  receipt = { ...receipt, state: "pending", uuid: details.uuid };
43838
43851
  }
43839
- const sleep2 = options.sleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms)));
43852
+ const sleep2 = options.sleep ?? ((ms) => new Promise((resolve8) => setTimeout(resolve8, ms)));
43840
43853
  for (let attempt = 0; attempt < 3; attempt++) {
43841
43854
  if (attempt) await sleep2(attempt * 1e3);
43842
43855
  try {
@@ -44306,7 +44319,7 @@ function observeQueuedAdmission(repo, pr, snapshot, receiptDirectory) {
44306
44319
  var SETTLE_POLLS = 6;
44307
44320
  var SETTLE_MS = 5e3;
44308
44321
  async function settled(repo, id, deps) {
44309
- const sleep2 = deps.sleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms)));
44322
+ const sleep2 = deps.sleep ?? ((ms) => new Promise((resolve8) => setTimeout(resolve8, ms)));
44310
44323
  let status = "unknown";
44311
44324
  for (let poll = 0; poll < SETTLE_POLLS; poll++) {
44312
44325
  await sleep2(SETTLE_MS);
@@ -46051,8 +46064,14 @@ function registerBoardCommands(program3) {
46051
46064
  process.exitCode = e.exitCode;
46052
46065
  return;
46053
46066
  }
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)}`);
46067
+ const message2 = `board read failed: ${withDiscoverMissDetail(e.message)}`;
46068
+ if (o.json) {
46069
+ if (e && typeof e === "object" && "quota" in e && e.quota) console.log(JSON.stringify(e.quota));
46070
+ else console.log(formatErrorEnvelope(message2, {
46071
+ 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
46072
+ }));
46073
+ }
46074
+ return failGraceful(message2);
46056
46075
  }
46057
46076
  }
46058
46077
  function formatClaimHolder(holder) {
@@ -46346,9 +46365,9 @@ function registerBoardCommands(program3) {
46346
46365
  }
46347
46366
 
46348
46367
  // src/bootstrap-commands.ts
46349
- var import_node_fs39 = require("node:fs");
46368
+ var import_node_fs40 = require("node:fs");
46350
46369
  var import_node_os21 = require("node:os");
46351
- var import_node_path36 = require("node:path");
46370
+ var import_node_path37 = require("node:path");
46352
46371
  init_cli_shared();
46353
46372
  init_clean_exit();
46354
46373
 
@@ -46661,10 +46680,10 @@ async function assignPersistedPortRange(repo, slug, reg, opts) {
46661
46680
  }
46662
46681
 
46663
46682
  // src/box-commands.ts
46664
- var import_node_fs38 = require("node:fs");
46683
+ var import_node_fs39 = require("node:fs");
46665
46684
  var import_node_child_process12 = require("node:child_process");
46666
46685
  var import_node_os20 = require("node:os");
46667
- var import_node_path35 = require("node:path");
46686
+ var import_node_path36 = require("node:path");
46668
46687
 
46669
46688
  // src/box-control.ts
46670
46689
  var import_node_crypto16 = require("node:crypto");
@@ -47411,16 +47430,16 @@ function parseTenantTasksVar(raw) {
47411
47430
  const task = rawTask;
47412
47431
  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
47432
  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`);
47433
+ 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
47434
  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
47435
  const maxTimeout = task.secretOutput !== void 0 ? 3600 : 10800;
47417
47436
  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
47437
  const artifact = task.artifact ?? "none";
47419
47438
  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}"));
47439
+ const carriesPlaceholder = task.command.some((arg2) => arg2.includes("{artifact}"));
47421
47440
  if (artifact === "required" !== carriesPlaceholder) throw new Error(`org project set: tenantTasks.${name} must use {artifact} exactly when artifact is required`);
47422
47441
  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}"));
47442
+ const outputPlaceholder = task.command.some((arg2) => arg2.includes("{output}"));
47424
47443
  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
47444
  out[name] = {
47426
47445
  service: task.service,
@@ -48554,6 +48573,276 @@ ${formatSshRecipe(box, remoteCommand)}
48554
48573
  `;
48555
48574
  }
48556
48575
 
48576
+ // ../infra/hetzner/cloud-firewall.mjs
48577
+ var import_node_fs38 = require("node:fs");
48578
+ var import_node_url = require("node:url");
48579
+ var import_node_path35 = require("node:path");
48580
+ var import_meta = {};
48581
+ var HZ = "https://api.hetzner.cloud/v1";
48582
+ var APPLY = process.env.FIREWALL_APPLY === "1";
48583
+ var ANY = ["0.0.0.0/0", "::/0"];
48584
+ function arg(name) {
48585
+ const i = process.argv.indexOf(`--${name}`);
48586
+ return i >= 0 && i + 1 < process.argv.length ? process.argv[i + 1] : void 0;
48587
+ }
48588
+ async function hetzner(token, path2, init = {}) {
48589
+ if (!token) throw new Error("no Hetzner Cloud API token (inject it with mmi-cli vault secrets use ... --name HZ_TOKEN)");
48590
+ const res = await fetch(`${HZ}${path2}`, {
48591
+ ...init,
48592
+ headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json" },
48593
+ signal: AbortSignal.timeout(3e4)
48594
+ });
48595
+ const body = await res.json().catch(() => ({}));
48596
+ if (!res.ok) throw new Error(`Hetzner ${init.method ?? "GET"} ${path2.split("?")[0]} failed: ${res.status} ${body?.error?.code ?? ""} ${body?.error?.message ?? ""}`);
48597
+ return body;
48598
+ }
48599
+ async function hz(path2, init = {}) {
48600
+ return hetzner(process.env.HZ_TOKEN, path2, init);
48601
+ }
48602
+ function buildRules(cloudflare, extras = []) {
48603
+ const cf = [...cloudflare.ipv4, ...cloudflare.ipv6];
48604
+ if (!cloudflare.ipv4.length || !cloudflare.ipv6.length) throw new Error("refusing an empty Cloudflare range list (it would block every site)");
48605
+ const rules = [
48606
+ { direction: "in", protocol: "tcp", port: "22", source_ips: ANY, description: "SSH (deploy, reconcile, runner)" },
48607
+ { direction: "in", protocol: "icmp", source_ips: ANY, description: "ICMP" },
48608
+ { direction: "in", protocol: "tcp", port: "80", source_ips: cf, description: "HTTP from Cloudflare only" },
48609
+ { direction: "in", protocol: "tcp", port: "443", source_ips: cf, description: "HTTPS from Cloudflare only" }
48610
+ ];
48611
+ for (const e of extras) {
48612
+ if (!["tcp", "udp"].includes(e.protocol) || !/^\d{1,5}(-\d{1,5})?$/.test(String(e.port)) || !e.description) {
48613
+ throw new Error(`invalid firewall extra ${JSON.stringify(e)}: needs protocol tcp|udp, port N or N-M, description`);
48614
+ }
48615
+ rules.push({ direction: "in", protocol: e.protocol, port: String(e.port), source_ips: ANY, description: e.description.slice(0, 255) });
48616
+ }
48617
+ return rules;
48618
+ }
48619
+ async function cloudflareRanges() {
48620
+ const res = await fetch("https://api.cloudflare.com/client/v4/ips", { signal: AbortSignal.timeout(3e4) });
48621
+ const body = await res.json();
48622
+ if (!res.ok || !body?.success) throw new Error(`Cloudflare IP list unreadable: ${res.status}`);
48623
+ return { ipv4: body.result.ipv4_cidrs ?? [], ipv6: body.result.ipv6_cidrs ?? [] };
48624
+ }
48625
+ 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 })));
48626
+ function declaredExtras(box) {
48627
+ const extrasFile = JSON.parse((0, import_node_fs38.readFileSync)((0, import_node_url.fileURLToPath)(new URL("./firewall-extras.json", import_meta.url)), "utf8"));
48628
+ return Object.prototype.hasOwnProperty.call(extrasFile, box) ? extrasFile[box] : void 0;
48629
+ }
48630
+ async function main() {
48631
+ const box = arg("box");
48632
+ if (!box || !/^[a-z0-9-]+$/.test(box)) {
48633
+ console.error("cloud-firewall: --box <hetzner server name> is required");
48634
+ process.exit(64);
48635
+ }
48636
+ const detach2 = process.argv.includes("--detach");
48637
+ const name = `mmi-${box}`;
48638
+ const servers = (await hz(`/servers?name=${encodeURIComponent(box)}`)).servers ?? [];
48639
+ if (servers.length !== 1) throw new Error(`expected exactly one server named ${box} in this project, found ${servers.length}`);
48640
+ const server = servers[0];
48641
+ const existing = ((await hz(`/firewalls?name=${encodeURIComponent(name)}`)).firewalls ?? [])[0];
48642
+ const applied = Boolean(existing?.applied_to?.some((a) => a.server?.id === server.id));
48643
+ 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" : ""}`);
48644
+ if (detach2) {
48645
+ if (!existing || !applied) {
48646
+ console.log("cloud-firewall: not applied to this server \u2014 nothing to detach");
48647
+ return;
48648
+ }
48649
+ if (!APPLY) {
48650
+ console.log("cloud-firewall: dry-run (FIREWALL_APPLY=1 to detach)");
48651
+ return;
48652
+ }
48653
+ await hz(`/firewalls/${existing.id}/actions/remove_from_resources`, { method: "POST", body: JSON.stringify({ remove_from: [{ type: "server", server: { id: server.id } }] }) });
48654
+ console.log(`cloud-firewall: detached ${name} from ${box}`);
48655
+ return;
48656
+ }
48657
+ const extras = declaredExtras(box);
48658
+ if (extras === void 0) throw new Error(`${box} has no entry in firewall-extras.json; declare it (an empty list is fine) before applying`);
48659
+ const rules = buildRules(await cloudflareRanges(), extras);
48660
+ 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}`);
48661
+ const rulesChanged = !existing || norm(existing.rules) !== norm(rules);
48662
+ console.log(`cloud-firewall: rules ${rulesChanged ? "would change" : "unchanged"}; apply-to-server ${applied ? "already done" : "needed"}`);
48663
+ if (!APPLY) {
48664
+ console.log("cloud-firewall: dry-run (FIREWALL_APPLY=1 to write)");
48665
+ return;
48666
+ }
48667
+ let id = existing?.id;
48668
+ if (!existing) {
48669
+ id = (await hz("/firewalls", { method: "POST", body: JSON.stringify({ name, labels: { managed_by: "mmi-hub", box }, rules }) })).firewall.id;
48670
+ console.log(`cloud-firewall: created ${name}#${id}`);
48671
+ } else if (rulesChanged) {
48672
+ await hz(`/firewalls/${id}/actions/set_rules`, { method: "POST", body: JSON.stringify({ rules }) });
48673
+ console.log(`cloud-firewall: updated rules on ${name}#${id}`);
48674
+ }
48675
+ if (!applied) {
48676
+ await hz(`/firewalls/${id}/actions/apply_to_resources`, { method: "POST", body: JSON.stringify({ apply_to: [{ type: "server", server: { id: server.id } }] }) });
48677
+ console.log(`cloud-firewall: applied ${name} to ${box}`);
48678
+ }
48679
+ }
48680
+ if (process.argv[1] && (0, import_node_path35.basename)(process.argv[1]).toLowerCase() === "cloud-firewall.mjs") {
48681
+ main().catch((err) => {
48682
+ console.error(`cloud-firewall: failed: ${err.message}`);
48683
+ process.exit(1);
48684
+ });
48685
+ }
48686
+
48687
+ // ../infra/hetzner/firewall-extras.json
48688
+ var firewall_extras_default = {
48689
+ $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.",
48690
+ "mm-work": [
48691
+ { protocol: "tcp", port: "7881", description: "MM-Chat dev huddles LiveKit RTC over TCP (MMI-Hub#7353, owner-approved 2026-09-26)" },
48692
+ { protocol: "udp", port: "7882", description: "MM-Chat dev huddles LiveKit RTC over UDP (MMI-Hub#7353, owner-approved 2026-09-26)" },
48693
+ { protocol: "tcp", port: "7891", description: "MM-Chat main huddles LiveKit RTC over TCP (MMI-Hub#7907, owner-approved 2026-10-06)" },
48694
+ { protocol: "udp", port: "7892", description: "MM-Chat main huddles LiveKit RTC over UDP (MMI-Hub#7907, owner-approved 2026-10-06)" }
48695
+ ],
48696
+ "mm-central": [],
48697
+ "mm-recorder": [],
48698
+ "mmi-runner": [],
48699
+ "mmi-runner2": []
48700
+ };
48701
+
48702
+ // ../shared/runner-hosts.ts
48703
+ var RUNNER_HOSTS = ["mmi-runner", "mmi-runner2"];
48704
+
48705
+ // src/box-firewall.ts
48706
+ function declaredExtrasFromBundle(box) {
48707
+ const file = firewall_extras_default;
48708
+ return Object.prototype.hasOwnProperty.call(file, box) ? file[box] : void 0;
48709
+ }
48710
+ var FirewallRefusal = class extends Error {
48711
+ };
48712
+ var FIREWALL_NAME_PREFIX = "mmi-";
48713
+ var ACTION_POLL_MS = 2500;
48714
+ var ACTION_POLL_ATTEMPTS = 20;
48715
+ async function runBoxFirewall(boxName, mode, live, deps) {
48716
+ const runner = RUNNER_HOSTS.find((h) => h.toLowerCase() === boxName.toLowerCase());
48717
+ if (!runner) {
48718
+ throw new FirewallRefusal(
48719
+ `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)`
48720
+ );
48721
+ }
48722
+ const token = await deps.fetchToken();
48723
+ const firewallName = `${FIREWALL_NAME_PREFIX}${runner}`;
48724
+ if (live === false && mode !== "plan") {
48725
+ throw new FirewallRefusal(`box firewall: ${mode} is a mutation \u2014 it needs --apply`);
48726
+ }
48727
+ const servers = (await deps.hetzner(token, `/servers?name=${encodeURIComponent(runner)}`)).servers ?? [];
48728
+ if (servers.length !== 1) {
48729
+ throw new FirewallRefusal(`box firewall: expected exactly one server named ${runner} in the MM project, found ${servers.length} \u2014 refusing to guess the target`);
48730
+ }
48731
+ const server = servers[0];
48732
+ const observedAt = deps.now();
48733
+ const existing = ((await deps.hetzner(token, `/firewalls?name=${encodeURIComponent(firewallName)}`)).firewalls ?? [])[0];
48734
+ const applied = Boolean(existing?.applied_to?.some((a) => a.server?.id === server.id));
48735
+ const target = {
48736
+ operation: mode,
48737
+ live,
48738
+ box: runner,
48739
+ server: { id: server.id, name: server.name, ...server.public_net?.ipv4?.ip ? { ipv4: server.public_net.ipv4.ip } : {} },
48740
+ firewall: existing ? { id: existing.id, name: existing.name } : null,
48741
+ applied,
48742
+ rulesChanged: false,
48743
+ currentRules: existing?.rules ?? [],
48744
+ plannedRules: null,
48745
+ actions: [],
48746
+ readback: void 0,
48747
+ note: void 0,
48748
+ ambiguous: false,
48749
+ ok: false,
48750
+ observedAt
48751
+ };
48752
+ if (mode === "detach") {
48753
+ if (!existing || !applied) {
48754
+ return { ...target, ok: true, note: `firewall ${firewallName} is ${existing ? "not applied to" : "absent for"} this server \u2014 nothing to detach` };
48755
+ }
48756
+ const action = await actionPost(deps, token, existing.id, "remove_from_resources", { remove_from: [{ type: "server", server: { id: server.id } }] });
48757
+ const waited = await waitForAction(deps, token, action);
48758
+ target.actions.push(actionReceipt("remove_from_resources", waited));
48759
+ target.ambiguous = waited.ambiguous;
48760
+ const readback2 = await readbackState(deps, token, existing.id, server.id, null, deps.now());
48761
+ target.readback = readback2;
48762
+ target.ok = !waited.ambiguous && readback2.attached === false;
48763
+ if (target.ok) target.note = `detached ${firewallName} from ${runner}`;
48764
+ return target;
48765
+ }
48766
+ const extras = deps.declaredExtras(runner);
48767
+ if (extras === void 0) {
48768
+ 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`);
48769
+ }
48770
+ const planned = buildRules(await deps.cloudflareRanges(), extras);
48771
+ target.plannedRules = planned;
48772
+ const rulesChanged = !existing || norm(existing.rules ?? []) !== norm(planned);
48773
+ target.rulesChanged = rulesChanged;
48774
+ if (mode === "plan") {
48775
+ target.ok = !rulesChanged && applied;
48776
+ if (target.ok) target.note = `firewall ${firewallName}#${existing.id} matches the reviewed policy and is applied`;
48777
+ return target;
48778
+ }
48779
+ let firewallId = existing?.id;
48780
+ if (!existing) {
48781
+ const created = await deps.hetzner(token, "/firewalls", {
48782
+ method: "POST",
48783
+ body: JSON.stringify({ name: firewallName, labels: { managed_by: "mmi-hub", box: runner }, rules: planned })
48784
+ });
48785
+ firewallId = created.firewall.id;
48786
+ target.actions.push({ id: firewallId, kind: "create", status: "created" });
48787
+ } else if (rulesChanged) {
48788
+ const action = await actionPost(deps, token, firewallId, "set_rules", { rules: planned });
48789
+ const waited = await waitForAction(deps, token, action);
48790
+ target.actions.push(actionReceipt("set_rules", waited));
48791
+ target.ambiguous ||= waited.ambiguous;
48792
+ if (waited.ambiguous || waited.action.status === "error") {
48793
+ const readback2 = await readbackState(deps, token, firewallId, server.id, planned, deps.now());
48794
+ target.readback = readback2;
48795
+ return target;
48796
+ }
48797
+ }
48798
+ if (!applied) {
48799
+ const action = await actionPost(deps, token, firewallId, "apply_to_resources", { apply_to: [{ type: "server", server: { id: server.id } }] });
48800
+ const waited = await waitForAction(deps, token, action);
48801
+ target.actions.push(actionReceipt("apply_to_resources", waited));
48802
+ target.ambiguous ||= waited.ambiguous;
48803
+ if (waited.action.status === "error") {
48804
+ const readback2 = await readbackState(deps, token, firewallId, server.id, planned, deps.now());
48805
+ target.readback = readback2;
48806
+ return target;
48807
+ }
48808
+ }
48809
+ const readback = await readbackState(deps, token, firewallId, server.id, planned, deps.now());
48810
+ target.firewall = { id: firewallId, name: firewallName };
48811
+ target.readback = readback;
48812
+ target.ok = !target.ambiguous && readback.attached && readback.rulesMatch === true;
48813
+ if (target.ok) target.note = `firewall ${firewallName}#${firewallId} applied to ${runner} and read back independently`;
48814
+ return target;
48815
+ }
48816
+ async function actionPost(deps, token, firewallId, kind, body) {
48817
+ const res = await deps.hetzner(token, `/firewalls/${firewallId}/actions/${kind}`, { method: "POST", body: JSON.stringify(body) });
48818
+ return res.action;
48819
+ }
48820
+ async function waitForAction(deps, token, accepted) {
48821
+ let last = accepted;
48822
+ for (let attempt = 0; attempt < ACTION_POLL_ATTEMPTS; attempt += 1) {
48823
+ const res = await deps.hetzner(token, `/firewalls/actions/${accepted.id}`);
48824
+ last = res.action ?? last;
48825
+ if (last.status === "success" || last.status === "error") return { action: last, ambiguous: false };
48826
+ await deps.sleep(ACTION_POLL_MS);
48827
+ }
48828
+ return { action: last, ambiguous: true };
48829
+ }
48830
+ function actionReceipt(kind, waited) {
48831
+ return {
48832
+ id: waited.action.id,
48833
+ kind,
48834
+ status: waited.ambiguous ? "running (wait bound exhausted \u2014 ambiguous)" : waited.action.status,
48835
+ ...waited.action.error ? { error: { code: waited.action.error.code, message: waited.action.error.message } } : {}
48836
+ };
48837
+ }
48838
+ async function readbackState(deps, token, firewallId, serverId, planned, at) {
48839
+ const firewall = (await deps.hetzner(token, `/firewalls/${firewallId}`)).firewall;
48840
+ const server = (await deps.hetzner(token, `/servers/${serverId}`)).server;
48841
+ const attached = server != null && server.id === serverId && Boolean(firewall?.applied_to?.some((a) => a.server?.id === serverId));
48842
+ const rulesMatch = planned ? norm(firewall?.rules ?? []) === norm(planned) : null;
48843
+ return { observedAt: at, attached, rulesMatch };
48844
+ }
48845
+
48557
48846
  // src/box-commands.ts
48558
48847
  var HETZNER_API = "https://api.hetzner.cloud/v1/servers";
48559
48848
  var HETZNER_TIMEOUT_MS = 15e3;
@@ -48664,7 +48953,7 @@ function registerBoxCommands(program3) {
48664
48953
  const stdinSource = o.body ? `"${o.body}"` : "<body.sh>";
48665
48954
  const wroteScript = o.ssh && o.script ? o.script : null;
48666
48955
  const runLine = wroteScript ? useStdin ? `bash "${wroteScript}" < ${stdinSource}` : `bash "${wroteScript}"` : void 0;
48667
- if (wroteScript) (0, import_node_fs38.writeFileSync)(wroteScript, sshRecipeScript(found, remote), "utf8");
48956
+ if (wroteScript) (0, import_node_fs39.writeFileSync)(wroteScript, sshRecipeScript(found, remote), "utf8");
48668
48957
  if (o.json) {
48669
48958
  console.log(JSON.stringify({
48670
48959
  box: found,
@@ -48775,6 +49064,79 @@ ${SSH_RECIPE_AGENT_NOTE}`);
48775
49064
  process.exitCode = 2;
48776
49065
  }
48777
49066
  });
49067
+ 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) => {
49068
+ try {
49069
+ if (o.apply && o.plan) throw new UsageError("box firewall: --plan and --apply are exclusive");
49070
+ if (o.detach && !o.apply) throw new UsageError("box firewall: --detach is a mutation \u2014 it needs --apply");
49071
+ if (!o.apply && !o.plan) o.plan = true;
49072
+ const mode = o.detach ? "detach" : o.apply ? "apply" : "plan";
49073
+ const deps = firewallDeps();
49074
+ if (mode === "plan") {
49075
+ const receipt2 = await runBoxFirewall(name, mode, false, deps);
49076
+ renderFirewallReceipt(receipt2, o.json === true);
49077
+ process.exitCode = receipt2.ok ? 0 : 1;
49078
+ return;
49079
+ }
49080
+ const { boxes, incomplete } = await fetchInventory();
49081
+ const found = lookupBox(name, boxes, incomplete);
49082
+ if (found.kind !== "found") {
49083
+ const why = found.kind === "unknown" ? `the inventory is incomplete (${found.reasons.join("; ")})` : `no box named '${name}'`;
49084
+ throw new UnreadableError(`box firewall: ${why}`);
49085
+ }
49086
+ const receipt = await runBoxFirewall(found.box.name, mode, true, deps);
49087
+ if (!o.json) warnIncomplete(incomplete);
49088
+ renderFirewallReceipt(receipt, o.json === true);
49089
+ process.exitCode = receipt.ok ? 0 : 1;
49090
+ } catch (e) {
49091
+ const message2 = e instanceof FirewallRefusal ? e.message : e.message;
49092
+ if (o.json) console.log(JSON.stringify({ box: name, ok: false, refused: e instanceof FirewallRefusal, error: message2 }, null, 2));
49093
+ else console.error(message2);
49094
+ process.exitCode = 2;
49095
+ }
49096
+ });
49097
+ }
49098
+ function renderFirewallReceipt(r, json) {
49099
+ if (json) {
49100
+ console.log(JSON.stringify(r, null, 2));
49101
+ return;
49102
+ }
49103
+ const fw = r.firewall ? `${r.firewall.name}#${r.firewall.id}` : `mmi-${r.box} (absent)`;
49104
+ const lines2 = [
49105
+ `${r.box} \u2014 firewall ${r.operation}${r.live ? " (LIVE)" : " (dry-run)"}`,
49106
+ ` server: #${r.server.id}${r.server.ipv4 ? ` (${r.server.ipv4})` : ""}`,
49107
+ ` firewall: ${fw}, ${r.applied ? "attached to this server" : "not attached to this server"}`
49108
+ ];
49109
+ if (r.plannedRules) {
49110
+ lines2.push(` rules: ${r.rulesChanged ? "WOULD CHANGE \u2014 planned set differs from the provider" : "match the reviewed policy"}`);
49111
+ for (const rule of r.plannedRules) {
49112
+ const from = rule.source_ips.length > 2 ? `${rule.source_ips.length} Cloudflare ranges` : rule.source_ips.join(", ");
49113
+ lines2.push(` in ${rule.protocol}${rule.port ? `/${rule.port}` : ""} from ${from} \u2014 ${rule.description}`);
49114
+ }
49115
+ }
49116
+ for (const a of r.actions) lines2.push(` action ${a.kind} #${a.id}: ${a.status}${a.error ? ` \u2014 ${a.error.code ?? ""} ${a.error.message ?? ""}` : ""}`);
49117
+ if (r.readback) {
49118
+ lines2.push(` readback (independent, ${r.readback.observedAt}): attached=${r.readback.attached}${r.readback.rulesMatch === null ? "" : ` rulesMatch=${r.readback.rulesMatch}`}`);
49119
+ }
49120
+ 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");
49121
+ lines2.push(` ${r.ok ? "OK" : "NOT OK"}${r.note ? ` \u2014 ${r.note}` : ""} (observed ${r.observedAt})`);
49122
+ console.log(lines2.join("\n"));
49123
+ }
49124
+ function firewallDeps() {
49125
+ return {
49126
+ hetzner: (token, path2, init) => hetzner(token, path2, init),
49127
+ cloudflareRanges: () => cloudflareRanges(),
49128
+ declaredExtras: (boxName) => declaredExtrasFromBundle(boxName),
49129
+ fetchToken: async () => {
49130
+ let token = null;
49131
+ await withSecrets(async (secretsDeps) => {
49132
+ token = await fetchSecretValue(secretsDeps, PROJECT_API_TOKEN.MM, { slug: HETZNER_VAULT_SLUG }, true);
49133
+ });
49134
+ if (!token) throw new Error("box firewall: could not read the Hetzner MM API token from the vault (the value is never printed)");
49135
+ return token;
49136
+ },
49137
+ sleep: (ms) => new Promise((resolve8) => setTimeout(resolve8, ms)),
49138
+ now: () => (/* @__PURE__ */ new Date()).toISOString()
49139
+ };
48778
49140
  }
48779
49141
  var UsageError = class extends Error {
48780
49142
  };
@@ -48791,17 +49153,17 @@ function hubGitShow(ref) {
48791
49153
  return (path2) => git3(["show", `${ref}:${path2}`]);
48792
49154
  }
48793
49155
  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-"));
49156
+ const dir = (0, import_node_fs39.mkdtempSync)((0, import_node_path36.join)((0, import_node_os20.tmpdir)(), "mmi-box-control-"));
48795
49157
  try {
48796
- const recipe = (0, import_node_path35.join)(dir, "recipe.sh");
48797
- (0, import_node_fs38.writeFileSync)(recipe, sshRecipeScript(found, "sh -s"), "utf8");
49158
+ const recipe = (0, import_node_path36.join)(dir, "recipe.sh");
49159
+ (0, import_node_fs39.writeFileSync)(recipe, sshRecipeScript(found, "sh -s"), "utf8");
48798
49160
  const r = (0, import_node_child_process12.spawnSync)("bash", [recipe], { input: script, encoding: "utf8", maxBuffer: 16 * 1024 * 1024, timeout: 18e4, windowsHide: true });
48799
49161
  if (r.status !== 0) {
48800
49162
  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
49163
  }
48802
49164
  return r.stdout;
48803
49165
  } finally {
48804
- (0, import_node_fs38.rmSync)(dir, { recursive: true, force: true });
49166
+ (0, import_node_fs39.rmSync)(dir, { recursive: true, force: true });
48805
49167
  }
48806
49168
  }
48807
49169
  function formatControl(mode, box, rows) {
@@ -50302,12 +50664,12 @@ var declaredProjectAdmins = (meta) => {
50302
50664
  };
50303
50665
  var execGitForSeedSource = async (args) => (await execFileP("git", args, { timeout: GIT_TIMEOUT_MS })).stdout;
50304
50666
  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");
50667
+ const dir = (0, import_node_fs40.mkdtempSync)((0, import_node_path37.join)((0, import_node_os21.tmpdir)(), "mmi-gate-diff-"));
50668
+ const before = (0, import_node_path37.join)(dir, "committed-gate.yml");
50669
+ const after = (0, import_node_path37.join)(dir, "registry-render.yml");
50308
50670
  try {
50309
- (0, import_node_fs39.writeFileSync)(before, current);
50310
- (0, import_node_fs39.writeFileSync)(after, rendered);
50671
+ (0, import_node_fs40.writeFileSync)(before, current);
50672
+ (0, import_node_fs40.writeFileSync)(after, rendered);
50311
50673
  try {
50312
50674
  return (await execFileP("git", ["diff", "--no-index", "--", before, after], { timeout: GIT_TIMEOUT_MS })).stdout;
50313
50675
  } catch (e) {
@@ -50316,7 +50678,7 @@ async function gateRenderDiff(current, rendered) {
50316
50678
  throw e;
50317
50679
  }
50318
50680
  } finally {
50319
- (0, import_node_fs39.rmSync)(dir, { recursive: true, force: true });
50681
+ (0, import_node_fs40.rmSync)(dir, { recursive: true, force: true });
50320
50682
  }
50321
50683
  }
50322
50684
  function bootstrapTrainDoctorDeps() {
@@ -50337,9 +50699,9 @@ async function propagationScope(classes, what) {
50337
50699
  }
50338
50700
  const rosterRepos = collectRegistryRepos(projects).filter((r) => r.toLowerCase() !== "mutmutco/mmi-hub");
50339
50701
  let independentCount = rosterRepos.length;
50340
- if ((0, import_node_fs39.existsSync)("projects.json")) {
50702
+ if ((0, import_node_fs40.existsSync)("projects.json")) {
50341
50703
  try {
50342
- const local = JSON.parse((0, import_node_fs39.readFileSync)("projects.json", "utf8"));
50704
+ const local = JSON.parse((0, import_node_fs40.readFileSync)("projects.json", "utf8"));
50343
50705
  const localRepos = /* @__PURE__ */ new Set();
50344
50706
  for (const p of local.projects ?? []) for (const r of p.repos ?? []) {
50345
50707
  const full = (r.includes("/") ? r : `mutmutco/${r}`).toLowerCase();
@@ -50464,13 +50826,13 @@ function registerBootstrapCommands(program3) {
50464
50826
  })),
50465
50827
  pushAllowlistOwners: pushAllowlistAuthority(verifyOwners, declaredProjectAdmins(meta)),
50466
50828
  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,
50829
+ readLocalFile: (path2) => path2 === "projects.json" && apiProjects != null ? apiProjects : (0, import_node_fs40.existsSync)(path2) ? (0, import_node_fs40.readFileSync)(path2, "utf8") : null,
50468
50830
  // requiredGcpApis is stored as an array by a JSON write, but `org project set --var KEY=VALUE` stores a raw
50469
50831
  // comma-string — accept either so the seeded value verifies regardless of how it was written.
50470
50832
  // #3689: the same committed map the org access audit reads (#3664), so a sanctioned admin is not a
50471
50833
  // permanent bootstrap failure on one surface and an intended state on the other. Absent file → no
50472
50834
  // 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,
50835
+ sanctionedAdmins: (0, import_node_fs40.existsSync)("access-matrix.json") ? entriesValueByCanonicalRepo(loadSanctionedAdmins((0, import_node_fs40.readFileSync)("access-matrix.json", "utf8")), repo) : void 0,
50474
50836
  requiredGcpApis: (() => {
50475
50837
  const v = meta?.requiredGcpApis;
50476
50838
  if (Array.isArray(v)) return v;
@@ -50548,14 +50910,14 @@ function registerBootstrapCommands(program3) {
50548
50910
  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
50911
  const o = { repo: rawValue("--repo", ""), json: rawFlag("--json") };
50550
50912
  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`);
50913
+ 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
50914
  const seedSource = await resolveHubSeedSource(execGitForSeedSource);
50553
50915
  if (!seedSource.ok) return fail(`bootstrap drift: ${seedSource.reason}`);
50554
- const manifest = loadBootstrapSeeds((0, import_node_fs39.readFileSync)(manifestPath, "utf8"));
50916
+ const manifest = loadBootstrapSeeds((0, import_node_fs40.readFileSync)(manifestPath, "utf8"));
50555
50917
  const hubContents = /* @__PURE__ */ new Map();
50556
50918
  for (const s of manifest.seeds) {
50557
50919
  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);
50920
+ hubContents.set(s.target, (0, import_node_fs40.existsSync)(s.target) ? (0, import_node_fs40.readFileSync)(s.target, "utf8") : null);
50559
50921
  }
50560
50922
  let targets;
50561
50923
  let classOf = (_repo) => "deployable";
@@ -50811,24 +51173,24 @@ function registerBootstrapCommands(program3) {
50811
51173
  return;
50812
51174
  }
50813
51175
  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`);
51176
+ 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
51177
  const seedSource = await resolveHubSeedSource(execGitForSeedSource);
50816
51178
  if (!seedSource.ok) return fail(`bootstrap apply: ${seedSource.reason}`);
50817
- const manifest = loadBootstrapSeeds((0, import_node_fs39.readFileSync)(manifestPath, "utf8"));
51179
+ const manifest = loadBootstrapSeeds((0, import_node_fs40.readFileSync)(manifestPath, "utf8"));
50818
51180
  const baseBranch = o.class === "content" ? "main" : "development";
50819
51181
  const slug = parsedRepo.slug;
50820
51182
  const onlyTarget = o.fromConfig && o.only.trim() === "gate.yml" ? ".github/workflows/gate.yml" : o.only.trim();
50821
51183
  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;
51184
+ const readFile10 = (p) => (0, import_node_fs40.existsSync)(p) ? (0, import_node_fs40.readFileSync)(p, "utf8") : null;
50823
51185
  const enc = (p) => p.split("/").map(encodeURIComponent).join("/");
50824
51186
  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");
51187
+ 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`);
51188
+ (0, import_node_fs40.writeFileSync)(tmp, JSON.stringify(contentPutBody(target, content, ref, sha)), "utf8");
50827
51189
  try {
50828
51190
  await gh2(contentPutInputArgs(repo, target, tmp));
50829
51191
  } finally {
50830
51192
  try {
50831
- (0, import_node_fs39.unlinkSync)(tmp);
51193
+ (0, import_node_fs40.unlinkSync)(tmp);
50832
51194
  } catch {
50833
51195
  }
50834
51196
  }
@@ -51466,10 +51828,10 @@ LIVE apply to ${repo}:
51466
51828
  if (rawFlag("--pins")) return propagatePins(rawFlag("--apply"), rawFlag("--json"));
51467
51829
  const o = { target: rawValue("--target", ""), execute: rawFlag("--execute"), json: rawFlag("--json") };
51468
51830
  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`);
51831
+ 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
51832
  const seedSource = await resolveHubSeedSource(execGitForSeedSource);
51471
51833
  if (!seedSource.ok) return fail(`bootstrap propagate: ${seedSource.reason}`);
51472
- const manifest = loadBootstrapSeeds((0, import_node_fs39.readFileSync)(manifestPath, "utf8"));
51834
+ const manifest = loadBootstrapSeeds((0, import_node_fs40.readFileSync)(manifestPath, "utf8"));
51473
51835
  const propagatable = manifest.seeds.filter(isPropagatableSeed);
51474
51836
  if (!o.target) {
51475
51837
  return fail(`bootstrap propagate: --target <path> is required \u2014 one of:
@@ -51478,9 +51840,9 @@ LIVE apply to ${repo}:
51478
51840
  const seed = propagatable.find((s) => s.target === o.target);
51479
51841
  if (!seed) return fail(`bootstrap propagate: --target '${o.target}' names no centrally propagatable seed in ${manifestPath}. Propagatable targets:
51480
51842
  ${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;
51843
+ 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`);
51844
+ const hubContent = seed.managedBlock ? null : (0, import_node_fs40.readFileSync)(seed.target, "utf8");
51845
+ const readSeedFile2 = (path2) => (0, import_node_fs40.existsSync)(path2) ? (0, import_node_fs40.readFileSync)(path2, "utf8") : null;
51484
51846
  const isWorkflowSeed = seed.target.startsWith(".github/workflows/");
51485
51847
  const { projects, classOf, inClassRepos, canarySlug, sourcePilot } = await propagationScope(seed.classes, `target '${seed.target}'`);
51486
51848
  const repos = inClassRepos.map((repo) => {
@@ -51599,7 +51961,7 @@ LIVE apply to ${repo}:
51599
51961
  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
51962
  const headSha = seedSource.sha;
51601
51963
  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;
51964
+ 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
51965
  for (const rec of plan.records) {
51604
51966
  if (rec.action !== "open-pr") continue;
51605
51967
  const baseBranch = classOf(rec.repo) === "content" ? "main" : "development";
@@ -51621,15 +51983,15 @@ LIVE apply to ${repo}:
51621
51983
  } catch {
51622
51984
  existingSha = void 0;
51623
51985
  }
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`);
51986
+ 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
51987
  const desiredContent = desiredByRepo.get(rec.repo);
51626
51988
  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");
51989
+ (0, import_node_fs40.writeFileSync)(tmp, JSON.stringify(contentPutBody(seed.target, desiredContent, branch, existingSha, runbookUnaffected)), "utf8");
51628
51990
  try {
51629
51991
  await gh2(contentPutInputArgs(rec.repo, seed.target, tmp));
51630
51992
  } finally {
51631
51993
  try {
51632
- (0, import_node_fs39.unlinkSync)(tmp);
51994
+ (0, import_node_fs40.unlinkSync)(tmp);
51633
51995
  } catch {
51634
51996
  }
51635
51997
  }
@@ -51698,10 +52060,10 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
51698
52060
  return fail(`bootstrap rollback: ${e.message}`);
51699
52061
  }
51700
52062
  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)`);
52063
+ 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
52064
  const seedSource = await resolveHubSeedSource(execGitForSeedSource);
51703
52065
  if (!seedSource.ok) return fail(`bootstrap rollback: ${seedSource.reason}`);
51704
- const manifest = loadBootstrapSeeds((0, import_node_fs39.readFileSync)(manifestPath, "utf8"));
52066
+ const manifest = loadBootstrapSeeds((0, import_node_fs40.readFileSync)(manifestPath, "utf8"));
51705
52067
  const propagatable = manifest.seeds.filter(isPropagatableSeed);
51706
52068
  if (!o.target) {
51707
52069
  return fail(`bootstrap rollback: --target <path> is required \u2014 one of:
@@ -51718,10 +52080,10 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
51718
52080
  const enc = (p) => p.split("/").map(encodeURIComponent).join("/");
51719
52081
  let candidates;
51720
52082
  if (o.record) {
51721
- if (!(0, import_node_fs39.existsSync)(o.record)) return fail(`bootstrap rollback: --record '${o.record}' not found`);
52083
+ if (!(0, import_node_fs40.existsSync)(o.record)) return fail(`bootstrap rollback: --record '${o.record}' not found`);
51722
52084
  let parsed;
51723
52085
  try {
51724
- parsed = JSON.parse((0, import_node_fs39.readFileSync)(o.record, "utf8"));
52086
+ parsed = JSON.parse((0, import_node_fs40.readFileSync)(o.record, "utf8"));
51725
52087
  } catch (e) {
51726
52088
  return fail(`bootstrap rollback: --record '${o.record}' is not valid JSON: ${e.message}`);
51727
52089
  }
@@ -51798,13 +52160,13 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
51798
52160
  } catch {
51799
52161
  existingSha = void 0;
51800
52162
  }
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");
52163
+ 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`);
52164
+ (0, import_node_fs40.writeFileSync)(tmp, JSON.stringify(contentPutBody(seed.target, preSeedContent, plan.branch, existingSha)), "utf8");
51803
52165
  try {
51804
52166
  await gh2(contentPutInputArgs(repo, seed.target, tmp));
51805
52167
  } finally {
51806
52168
  try {
51807
- (0, import_node_fs39.unlinkSync)(tmp);
52169
+ (0, import_node_fs40.unlinkSync)(tmp);
51808
52170
  } catch {
51809
52171
  }
51810
52172
  }
@@ -52309,8 +52671,8 @@ function formatSuiteMarkdown(report) {
52309
52671
  const lines2 = ["| Member | dev | rc | main | Pinned by suite |", "| --- | --- | --- | --- | --- |"];
52310
52672
  if (report.lead) lines2.push(`| MM-Work (suite) | ${short(report.lead.dev)} | ${report.lead.rc} | ${report.lead.main} | - |`);
52311
52673
  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(", ") || "-"} |`);
52674
+ const [dev, rc, main2] = ["dev", "rc", "main"].map((s) => m.stages.find((x) => x.stage === s));
52675
+ lines2.push(`| ${m.repo.split("/")[1]} | ${cell(dev)} | ${cell(rc)} | ${cell(main2)} | ${[by(rc, "rc"), by(main2, "main")].filter(Boolean).join(", ") || "-"} |`);
52314
52676
  }
52315
52677
  return lines2.join("\n");
52316
52678
  }
@@ -52400,8 +52762,8 @@ async function waitSuiteDev(deps, opts) {
52400
52762
  }
52401
52763
 
52402
52764
  // src/suite-train.ts
52403
- var import_node_fs40 = require("node:fs");
52404
- var import_node_path37 = require("node:path");
52765
+ var import_node_fs41 = require("node:fs");
52766
+ var import_node_path38 = require("node:path");
52405
52767
  var import_node_crypto20 = require("node:crypto");
52406
52768
 
52407
52769
  // src/kit-version.ts
@@ -52487,7 +52849,7 @@ function suiteReleaseTag(rc) {
52487
52849
  function readSuiteCut(path2) {
52488
52850
  let raw;
52489
52851
  try {
52490
- raw = (0, import_node_fs40.readFileSync)(path2, "utf8");
52852
+ raw = (0, import_node_fs41.readFileSync)(path2, "utf8");
52491
52853
  } catch (e) {
52492
52854
  if (e.code === "ENOENT") return void 0;
52493
52855
  throw e;
@@ -52503,11 +52865,11 @@ function readSuiteCut(path2) {
52503
52865
  return record2;
52504
52866
  }
52505
52867
  function writeSuiteCut(path2, record2) {
52506
- (0, import_node_fs40.mkdirSync)((0, import_node_path37.dirname)(path2), { recursive: true });
52868
+ (0, import_node_fs41.mkdirSync)((0, import_node_path38.dirname)(path2), { recursive: true });
52507
52869
  const temp = `${path2}.${(0, import_node_crypto20.randomBytes)(8).toString("hex")}.tmp`;
52508
52870
  try {
52509
- (0, import_node_fs40.writeFileSync)(temp, JSON.stringify(record2, null, 2), { flag: "wx" });
52510
- (0, import_node_fs40.renameSync)(temp, path2);
52871
+ (0, import_node_fs41.writeFileSync)(temp, JSON.stringify(record2, null, 2), { flag: "wx" });
52872
+ (0, import_node_fs41.renameSync)(temp, path2);
52511
52873
  } catch (e) {
52512
52874
  throw new Error(`suite cut record write failed at ${path2}: ${e.message}; stop, verify the file before retrying`);
52513
52875
  }
@@ -52523,15 +52885,15 @@ function pinVersion(url) {
52523
52885
  }
52524
52886
  }
52525
52887
  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]) {
52888
+ const main2 = bundles.main;
52889
+ 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`);
52890
+ 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`);
52891
+ const mainPin = mainPinFor(new URL(main2).host, bundles, pinVersion(main2));
52892
+ for (const url of [bundles.rc, main2]) {
52531
52893
  const tag = pinVersion(url);
52532
52894
  if (!RC_TAG.test(tag) && !RELEASE_TAG.test(tag)) continue;
52533
52895
  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 };
52896
+ if (sha && await deps.contains(member.repo, member.development, sha)) return { rcPin: url === main2 ? mainPin : url, mainPin };
52535
52897
  }
52536
52898
  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
52899
  }
@@ -52556,25 +52918,25 @@ async function suiteMarkAbandoned(deps, ownerGo = false) {
52556
52918
  return tags.map((t) => `${t.repo}@${t.tag}`);
52557
52919
  }
52558
52920
  async function retireFailedLeadRcLedger(deps, ownerGo) {
52559
- if (!(0, import_node_fs40.existsSync)(deps.ledgerPath)) return void 0;
52921
+ if (!(0, import_node_fs41.existsSync)(deps.ledgerPath)) return void 0;
52560
52922
  return withLedgerLock(deps.ledgerPath, async (fence) => {
52561
- const ledger = parseReleaseLedger((0, import_node_fs40.readFileSync)(deps.ledgerPath, "utf8"));
52923
+ const ledger = parseReleaseLedger((0, import_node_fs41.readFileSync)(deps.ledgerPath, "utf8"));
52562
52924
  const states = Object.values(ledger.phases).map((p) => p.state);
52563
52925
  if (ledger.repo !== SUITE_REPO || ledger.lane !== "rcand" || ledger.phases.promotion.state === "complete" || !states.includes("failed")) return void 0;
52564
52926
  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
52927
  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`);
52928
+ const archive = (0, import_node_path38.join)((0, import_node_path38.dirname)(deps.ledgerPath), `phases.archive-${ledger.tag}.json`);
52929
+ if ((0, import_node_fs41.existsSync)(archive)) throw new Error(`ledger archive already exists at ${archive}; inspect before retiring again`);
52568
52930
  await deps.markAbandoned(SUITE_REPO, ledger.tag, ledger.tagSha);
52569
- await fence(() => (0, import_node_fs40.renameSync)(deps.ledgerPath, archive));
52931
+ await fence(() => (0, import_node_fs41.renameSync)(deps.ledgerPath, archive));
52570
52932
  return `${ledger.tag} (ledger archived to ${archive})`;
52571
52933
  });
52572
52934
  }
52573
52935
  function suiteAbandon(recordPath, ownerGo = false, now = /* @__PURE__ */ new Date()) {
52574
52936
  const record2 = abandonableCut(recordPath, ownerGo);
52575
52937
  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);
52938
+ if ((0, import_node_fs41.existsSync)(archive)) throw new Error(`abandoned-cut archive already exists at ${archive}; inspect before abandoning again`);
52939
+ (0, import_node_fs41.renameSync)(recordPath, archive);
52578
52940
  return { archive, orphanTags: record2.members.filter((m) => m.tag).map((m) => `${m.repo}@${m.tag}`) };
52579
52941
  }
52580
52942
  async function suiteRestoreMainPins(deps) {
@@ -52661,12 +53023,12 @@ async function suiteRcandRun(deps, opts) {
52661
53023
  }
52662
53024
  if ((record2?.announcement === "sent" || record2?.announcement === "skipped") && record2.leadReleased) {
52663
53025
  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);
53026
+ if ((0, import_node_fs41.existsSync)(archive)) throw new Error(`suite cut archive already exists at ${archive}; inspect before a new cut`);
53027
+ (0, import_node_fs41.renameSync)(deps.recordPath, archive);
52666
53028
  record2 = void 0;
52667
53029
  }
52668
53030
  if (record2 && !record2.pinPr && !record2.leadRcTag && record2.members.every((m) => !m.tag)) {
52669
- (0, import_node_fs40.rmSync)(deps.recordPath, { force: true });
53031
+ (0, import_node_fs41.rmSync)(deps.recordPath, { force: true });
52670
53032
  record2 = void 0;
52671
53033
  }
52672
53034
  if (!record2) {
@@ -52720,7 +53082,7 @@ async function suiteRcandRun(deps, opts) {
52720
53082
  quiet.push(member);
52721
53083
  }
52722
53084
  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 });
53085
+ (0, import_node_fs41.rmSync)(deps.recordPath, { force: true });
52724
53086
  throw new Error("nothing to promote: neither MM-Work nor any module has new development commits since its rc; no suite cut started");
52725
53087
  }
52726
53088
  for (const member of quiet) {
@@ -52738,7 +53100,7 @@ async function suiteRcandRun(deps, opts) {
52738
53100
  }
52739
53101
  if (refusals.length) {
52740
53102
  const untouched = record2.members.every((m) => !m.tag) && !record2.pinPr;
52741
- if (untouched) (0, import_node_fs40.rmSync)(deps.recordPath, { force: true });
53103
+ if (untouched) (0, import_node_fs41.rmSync)(deps.recordPath, { force: true });
52742
53104
  throw new Error(`module rc serving is not ready; ${untouched ? "no suite cut started" : "no new tag was cut"}:
52743
53105
  ${refusals.join("\n")}
52744
53106
  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 +53119,7 @@ Each module must ship a live release that bind-mounts <deployPath>/data read-onl
52757
53119
  let running = 0;
52758
53120
  const waiting = [];
52759
53121
  const results = await Promise.allSettled(record2.members.map(async (member) => {
52760
- if (running >= 4) await new Promise((resolve7) => waiting.push(resolve7));
53122
+ if (running >= 4) await new Promise((resolve8) => waiting.push(resolve8));
52761
53123
  else running++;
52762
53124
  try {
52763
53125
  if ((await deps.head(member.repo, "development"))?.toLowerCase() !== member.development.toLowerCase())
@@ -52930,11 +53292,11 @@ Each member's live release must serve <data>/main/module.js at its main pin path
52930
53292
  }
52931
53293
  return record2;
52932
53294
  }
52933
- var hotfixRecordPath = (deps) => (0, import_node_path37.join)((0, import_node_path37.dirname)(deps.recordPath), "hotfix.json");
53295
+ var hotfixRecordPath = (deps) => (0, import_node_path38.join)((0, import_node_path38.dirname)(deps.recordPath), "hotfix.json");
52934
53296
  function readSuiteHotfix(path2) {
52935
53297
  let raw;
52936
53298
  try {
52937
- raw = (0, import_node_fs40.readFileSync)(path2, "utf8");
53299
+ raw = (0, import_node_fs41.readFileSync)(path2, "utf8");
52938
53300
  } catch (e) {
52939
53301
  if (e.code === "ENOENT") return void 0;
52940
53302
  throw e;
@@ -52977,7 +53339,7 @@ async function suiteHotfix(deps, opts) {
52977
53339
  if (completed) record2 = void 0;
52978
53340
  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
53341
  if (!record2?.tag) await deps.validateHotfixSummary();
52980
- if (completed) (0, import_node_fs40.renameSync)(path2, `${path2}.${completed.leadTag}.json`);
53342
+ if (completed) (0, import_node_fs41.renameSync)(path2, `${path2}.${completed.leadTag}.json`);
52981
53343
  const rec = record2 ?? { schema: "mmi-suite-hotfix/v1", member: found.id, repo: found.repo, from: opts.from, ...opts.ack?.length ? { ack: opts.ack } : {} };
52982
53344
  const save = () => writeSuiteHotfix(path2, rec);
52983
53345
  save();
@@ -53245,9 +53607,9 @@ async function runRcDataSwitch(deps, opts) {
53245
53607
 
53246
53608
  // src/suite-train-io.ts
53247
53609
  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
53610
  var import_node_path51 = require("node:path");
53611
+ var import_node_fs55 = require("node:fs");
53612
+ var import_node_path52 = require("node:path");
53251
53613
  init_cli_shared();
53252
53614
 
53253
53615
  // src/command-register-train-operations.ts
@@ -53428,7 +53790,7 @@ function clean3(out) {
53428
53790
  return out.trim();
53429
53791
  }
53430
53792
  function sleeper(deps) {
53431
- return deps.sleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms)));
53793
+ return deps.sleep ?? ((ms) => new Promise((resolve8) => setTimeout(resolve8, ms)));
53432
53794
  }
53433
53795
  function normalizeHotfixVersion(input) {
53434
53796
  const m = /^v?(\d+\.\d+\.\d+)$/.exec(input.trim());
@@ -54939,8 +55301,8 @@ function checkHotfixCarries(options) {
54939
55301
  }
54940
55302
 
54941
55303
  // src/merge-cleanup.ts
54942
- var import_node_fs41 = require("node:fs");
54943
- var import_node_path38 = require("node:path");
55304
+ var import_node_fs42 = require("node:fs");
55305
+ var import_node_path39 = require("node:path");
54944
55306
  var import_node_os22 = require("node:os");
54945
55307
  init_cli_shared();
54946
55308
  init_github_client();
@@ -55348,13 +55710,13 @@ function resolveSquashMergeBodyText(commits, allowedClosing, cwd) {
55348
55710
  return rewritten === base ? null : rewritten;
55349
55711
  }
55350
55712
  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}
55713
+ const dir = (0, import_node_fs42.mkdtempSync)((0, import_node_path39.join)((0, import_node_os22.tmpdir)(), "mmi-squash-body-"));
55714
+ const path2 = (0, import_node_path39.join)(dir, "body.txt");
55715
+ (0, import_node_fs42.writeFileSync)(path2, body.endsWith("\n") ? body : `${body}
55354
55716
  `, "utf8");
55355
55717
  return { path: path2, cleanup: () => {
55356
55718
  try {
55357
- (0, import_node_fs41.rmSync)(dir, { recursive: true, force: true });
55719
+ (0, import_node_fs42.rmSync)(dir, { recursive: true, force: true });
55358
55720
  } catch {
55359
55721
  }
55360
55722
  } };
@@ -55606,8 +55968,8 @@ init_github_client();
55606
55968
 
55607
55969
  // src/release-custody.ts
55608
55970
  var import_node_crypto21 = require("node:crypto");
55609
- var import_node_fs42 = require("node:fs");
55610
- var import_node_path39 = require("node:path");
55971
+ var import_node_fs43 = require("node:fs");
55972
+ var import_node_path40 = require("node:path");
55611
55973
  init_github_client();
55612
55974
 
55613
55975
  // src/release-custody-bootstrap.ts
@@ -55740,9 +56102,9 @@ async function verifyCustodyBootstrap(value, api, controller, requiredContexts,
55740
56102
  if (legacy.length > 20) reject("local evidence exceeds the bounded migration limit");
55741
56103
  const root = `repos/${HUB_RELEASE_REPO}`;
55742
56104
  const tag = await api.rest("GET", `${root}/git/ref/tags/${input.tag}`);
55743
- const main = await api.rest("GET", `${root}/git/ref/heads/main`);
56105
+ const main2 = await api.rest("GET", `${root}/git/ref/heads/main`);
55744
56106
  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");
56107
+ 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
56108
  const observed = {};
55747
56109
  for (const name of ["gate", "publish", "deploy", "installer", "tenant"]) {
55748
56110
  const run = await runAttempt(api, input[name]);
@@ -56077,7 +56439,7 @@ function reclassifySupersededArchives(state) {
56077
56439
  }
56078
56440
  function localRaw(path2) {
56079
56441
  try {
56080
- return (0, import_node_fs42.readFileSync)(path2, "utf8");
56442
+ return (0, import_node_fs43.readFileSync)(path2, "utf8");
56081
56443
  } catch (e) {
56082
56444
  if (e.code === "ENOENT") return null;
56083
56445
  throw e;
@@ -56086,19 +56448,19 @@ function localRaw(path2) {
56086
56448
  function hydrateLocal(path2, raw) {
56087
56449
  const previous = localRaw(path2);
56088
56450
  if (previous === raw) return;
56089
- (0, import_node_fs42.mkdirSync)((0, import_node_path39.dirname)(path2), { recursive: true });
56451
+ (0, import_node_fs43.mkdirSync)((0, import_node_path40.dirname)(path2), { recursive: true });
56090
56452
  if (previous !== null) {
56091
56453
  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)}`);
56454
+ const archive = (0, import_node_path40.join)((0, import_node_path40.dirname)(path2), `phases.local-${ledger.tagSha}-${custodyDigest(previous)}.json`);
56455
+ if (!(0, import_node_fs43.existsSync)(archive)) (0, import_node_fs43.writeFileSync)(archive, previous, { flag: "wx" });
56456
+ if (raw === null) (0, import_node_fs43.renameSync)(path2, `${path2}.retired-${custodyDigest(previous)}`);
56095
56457
  }
56096
- if (raw !== null) (0, import_node_fs42.writeFileSync)(path2, raw, "utf8");
56458
+ if (raw !== null) (0, import_node_fs43.writeFileSync)(path2, raw, "utf8");
56097
56459
  }
56098
56460
  async function commandIdentity(file, args, run, repo) {
56099
56461
  if (file === "git" && args[0] === "push") {
56100
56462
  const deleting = args.includes("--delete");
56101
- const refs = args.slice(2).filter((arg) => !arg.startsWith("-"));
56463
+ const refs = args.slice(2).filter((arg2) => !arg2.startsWith("-"));
56102
56464
  const targets = [];
56103
56465
  for (const refspec of refs) {
56104
56466
  const [source, destination] = refspec.split(":");
@@ -56113,7 +56475,7 @@ async function commandIdentity(file, args, run, repo) {
56113
56475
  return { kind: "github-release", identity: { repo, tag, sha: (await run("git", ["rev-parse", `${tag}^{commit}`])).trim() } };
56114
56476
  }
56115
56477
  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)] : []));
56478
+ const fields = Object.fromEntries(args.flatMap((arg2, i) => ["-f", "--field", "-F", "--raw-field"].includes(arg2) ? [args[i + 1].split(/=(.*)/s).slice(0, 2)] : []));
56117
56479
  const ref = args.includes("--ref") ? args[args.indexOf("--ref") + 1] : "main";
56118
56480
  const sha = (await run("git", ["rev-parse", `origin/${ref}`])).trim();
56119
56481
  const before = JSON.parse(await run("gh", [
@@ -56130,7 +56492,7 @@ async function commandIdentity(file, args, run, repo) {
56130
56492
  return { kind: "workflow-rerun", identity: { repo, runId, attempt: prior.run_attempt + 1 } };
56131
56493
  }
56132
56494
  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")));
56495
+ 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
56496
  return write ? { kind: "github-write", identity: { repo, command: args } } : null;
56135
56497
  }
56136
56498
  function effectObserver(api) {
@@ -56283,8 +56645,8 @@ function withHubReleaseCustody(deps) {
56283
56645
  }
56284
56646
 
56285
56647
  // src/project-info-sync.ts
56286
- var import_node_fs43 = require("node:fs");
56287
- var import_node_path40 = require("node:path");
56648
+ var import_node_fs44 = require("node:fs");
56649
+ var import_node_path41 = require("node:path");
56288
56650
  var UPDATE_PROJECT_INFO = `mutation($projectId: ID!, $shortDescription: String!, $readme: String!) {
56289
56651
  updateProjectV2(input: { projectId: $projectId, shortDescription: $shortDescription, readme: $readme }) {
56290
56652
  projectV2 { id }
@@ -56331,14 +56693,14 @@ function sharedName(entries, fallback) {
56331
56693
  }
56332
56694
  function buildProjectInfoSyncPlan(targetRepo2, project2, projects, repoRoot2) {
56333
56695
  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`);
56696
+ const readmePath = (0, import_node_path41.join)(repoRoot2, "README.md");
56697
+ if (!(0, import_node_fs44.existsSync)(readmePath)) throw new Error(`org project sync-info: ${targetRepo2} has no README.md`);
56336
56698
  const entries = entriesFor(project2, projects);
56337
56699
  const memberRepos = [...new Set(entries.flatMap((entry) => entry.repos ?? []))].filter((repo) => /^[^/]+\/[^/]+$/.test(repo)).sort((a, b) => a.localeCompare(b));
56338
56700
  const projectName = sharedName(entries, project2.name?.trim() || targetRepo2.split("/").pop() || targetRepo2);
56339
56701
  if (!memberRepos.length) throw new Error(`org project sync-info: project ${projectName} has no registered member repos`);
56340
56702
  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)}.`;
56703
+ 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
56704
  const lines2 = [
56343
56705
  `# ${projectName}`,
56344
56706
  "",
@@ -56357,8 +56719,8 @@ function buildProjectInfoSyncPlan(targetRepo2, project2, projects, repoRoot2) {
56357
56719
  const targetBase = `https://github.com/${targetRepo2}`;
56358
56720
  const targetBranch = branchFor(targetRepo2, projects);
56359
56721
  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)` : ""
56722
+ (0, import_node_fs44.existsSync)((0, import_node_path41.join)(repoRoot2, "architecture.md")) ? `- [Hub architecture](${targetBase}/blob/${targetBranch}/architecture.md)` : "",
56723
+ (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
56724
  ].filter(Boolean);
56363
56725
  if (orgDocs.length) lines2.push("", "## Organisation docs", "", ...orgDocs);
56364
56726
  return { projectId: project2.projectId, projectName, targetRepo: targetRepo2, memberRepos, shortDescription, readme: `${lines2.join("\n")}
@@ -56380,8 +56742,8 @@ async function syncProjectInfo(plan, client, apply) {
56380
56742
  }
56381
56743
 
56382
56744
  // src/train-commands.ts
56383
- var import_node_fs44 = require("node:fs");
56384
- var import_node_path41 = require("node:path");
56745
+ var import_node_fs45 = require("node:fs");
56746
+ var import_node_path42 = require("node:path");
56385
56747
  init_cli_shared();
56386
56748
  init_clean_exit();
56387
56749
  init_client_version();
@@ -56396,7 +56758,7 @@ function resolveReleaseBumpIntent(raw) {
56396
56758
  }
56397
56759
  function readRepoVersion() {
56398
56760
  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;
56761
+ return JSON.parse((0, import_node_fs45.readFileSync)((0, import_node_path42.join)(process.cwd(), ".claude-plugin", "plugin.json"), "utf8")).version || void 0;
56400
56762
  } catch {
56401
56763
  return void 0;
56402
56764
  }
@@ -56507,7 +56869,7 @@ function releaseProgressVerdict(status, subject = "Release") {
56507
56869
 
56508
56870
  // src/suite-pin.ts
56509
56871
  var import_promises6 = require("node:fs/promises");
56510
- var import_node_path42 = require("node:path");
56872
+ var import_node_path43 = require("node:path");
56511
56873
  var SuitePinError = class _SuitePinError extends Error {
56512
56874
  diagnostic;
56513
56875
  constructor(repo, tag, error) {
@@ -56575,8 +56937,8 @@ async function openSuiteCutPinPr(deps, input) {
56575
56937
  if (input.carriedOnly) return { status: "unchanged" };
56576
56938
  throw new Error("pins already match without a merged cut PR \u2014 provenance unverified");
56577
56939
  }
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-"));
56940
+ await (0, import_promises6.mkdir)((0, import_node_path43.join)(deps.root, "tmp"), { recursive: true });
56941
+ scratch = await (0, import_promises6.mkdtemp)((0, import_node_path43.join)(deps.root, "tmp", "suite-pin-"));
56580
56942
  const run = (file, args) => deps.run(file, args, scratch);
56581
56943
  await run("git", ["clone", "--quiet", "--branch", prs.length ? branch : "development", "--single-branch", `https://github.com/${SUITE_REPO}.git`, "."]);
56582
56944
  if (prs.length) {
@@ -56588,7 +56950,7 @@ async function openSuiteCutPinPr(deps, input) {
56588
56950
  await run("git", ["switch", "-c", branch]);
56589
56951
  }
56590
56952
  for (const stage of ["rc", "main"]) {
56591
- const path2 = (0, import_node_path42.join)(scratch, `${stage}-pins.json`);
56953
+ const path2 = (0, import_node_path43.join)(scratch, `${stage}-pins.json`);
56592
56954
  await (0, import_promises6.writeFile)(path2, JSON.stringify(input.pins.map((p) => ({ module: p.module, url: p[stage] }))));
56593
56955
  await run("node", ["scripts/pin-modules.mjs", "--stage", stage, "--pins", path2]);
56594
56956
  }
@@ -56641,12 +57003,12 @@ async function openSuiteRestorePinPr(deps, input) {
56641
57003
  }
56642
57004
  });
56643
57005
  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-"));
57006
+ await (0, import_promises6.mkdir)((0, import_node_path43.join)(deps.root, "tmp"), { recursive: true });
57007
+ scratch = await (0, import_promises6.mkdtemp)((0, import_node_path43.join)(deps.root, "tmp", "suite-pin-"));
56646
57008
  const run = (file, args) => deps.run(file, args, scratch);
56647
57009
  await run("git", ["clone", "--quiet", "--branch", "development", "--single-branch", `https://github.com/${SUITE_REPO}.git`, "."]);
56648
57010
  await run("git", ["switch", "-c", branch]);
56649
- const path2 = (0, import_node_path42.join)(scratch, "main-pins.json");
57011
+ const path2 = (0, import_node_path43.join)(scratch, "main-pins.json");
56650
57012
  await (0, import_promises6.writeFile)(path2, JSON.stringify(todo.map((p) => ({ module: p.module, url: p.prior }))));
56651
57013
  await run("node", ["scripts/pin-modules.mjs", "--stage", "main", "--pins", path2]);
56652
57014
  await run("git", ["add", "seed/modules.json"]);
@@ -56720,8 +57082,8 @@ async function openSuitePinPr(deps, input) {
56720
57082
  if (newer.length) return { status: "superseded", pr: newer[0].url, url: pin };
56721
57083
  const open2 = onBranch.find((p) => p.state === "OPEN");
56722
57084
  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-"));
57085
+ await (0, import_promises6.mkdir)((0, import_node_path43.join)(deps.root, "tmp"), { recursive: true });
57086
+ scratch = await (0, import_promises6.mkdtemp)((0, import_node_path43.join)(deps.root, "tmp", "suite-pin-"));
56725
57087
  const run = (file, args) => deps.run(file, args, scratch);
56726
57088
  await run("git", ["clone", "--quiet", "--branch", "development", "--single-branch", `https://github.com/${SUITE_REPO}.git`, "."]);
56727
57089
  await run("git", ["switch", "-c", branch]);
@@ -56773,7 +57135,7 @@ function prTitleRefusal(title) {
56773
57135
 
56774
57136
  // src/command-register-collaboration.ts
56775
57137
  var import_node_child_process18 = require("node:child_process");
56776
- var import_node_fs53 = require("node:fs");
57138
+ var import_node_fs54 = require("node:fs");
56777
57139
  var import_promises8 = require("node:fs/promises");
56778
57140
  init_clean_exit();
56779
57141
  init_cli_shared();
@@ -56797,7 +57159,7 @@ function spawnDetachedSelf(args, deps, opts = {}) {
56797
57159
  }
56798
57160
 
56799
57161
  // src/command-register-collaboration.ts
56800
- var import_node_path49 = require("node:path");
57162
+ var import_node_path50 = require("node:path");
56801
57163
  init_house_map();
56802
57164
 
56803
57165
  // src/issue-body.ts
@@ -56914,7 +57276,7 @@ init_github_client();
56914
57276
  init_github_quota();
56915
57277
 
56916
57278
  // src/issue-commands.ts
56917
- var import_node_fs45 = require("node:fs");
57279
+ var import_node_fs46 = require("node:fs");
56918
57280
  var import_node_crypto22 = require("node:crypto");
56919
57281
  init_cli_shared();
56920
57282
  init_clean_exit();
@@ -57107,7 +57469,7 @@ async function editIssue(client, options, deps = {}) {
57107
57469
  const url = `https://github.com/${repo}/issues/${parsed.number}`;
57108
57470
  const patch = {};
57109
57471
  let bodyChanged = false;
57110
- const textDeps = () => deps.textDeps ?? { readFile: (p, e) => Promise.resolve((0, import_node_fs45.readFileSync)(p, e)), readStdin: () => Promise.resolve("") };
57472
+ const textDeps = () => deps.textDeps ?? { readFile: (p, e) => Promise.resolve((0, import_node_fs46.readFileSync)(p, e)), readStdin: () => Promise.resolve("") };
57111
57473
  if (options.titleFile !== void 0) {
57112
57474
  patch.title = await resolveIssueTitle({ title: options.title, titleFile: options.titleFile }, textDeps());
57113
57475
  } else if (options.title !== void 0) {
@@ -57774,7 +58136,7 @@ function extendCreateCommand(issue, batchAttach) {
57774
58136
  if (opts.batch) {
57775
58137
  let specs;
57776
58138
  try {
57777
- const raw = (0, import_node_fs45.readFileSync)(opts.batch, "utf8");
58139
+ const raw = (0, import_node_fs46.readFileSync)(opts.batch, "utf8");
57778
58140
  specs = JSON.parse(raw);
57779
58141
  if (!Array.isArray(specs)) {
57780
58142
  const top = specs === null ? "null" : typeof specs === "object" ? `an object with keys: ${Object.keys(specs).join(", ") || "(none)"}` : `a ${typeof specs}`;
@@ -57851,8 +58213,8 @@ ${lines2}`, {
57851
58213
  }
57852
58214
 
57853
58215
  // src/post-merge-recon.ts
57854
- var import_node_fs46 = require("node:fs");
57855
- var import_node_path43 = require("node:path");
58216
+ var import_node_fs47 = require("node:fs");
58217
+ var import_node_path44 = require("node:path");
57856
58218
 
57857
58219
  // src/cross-repo-filing-issue.ts
57858
58220
  init_github_client();
@@ -58022,16 +58384,16 @@ function buildPostMergeReconRecovery(input) {
58022
58384
  }
58023
58385
  function writePostMergeReconRecovery(cwd, recovery) {
58024
58386
  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)}
58387
+ (0, import_node_fs47.mkdirSync)((0, import_node_path44.dirname)(path2), { recursive: true });
58388
+ (0, import_node_fs47.writeFileSync)(path2, `${JSON.stringify(recovery, null, 2)}
58027
58389
  `, "utf8");
58028
58390
  return path2;
58029
58391
  }
58030
58392
  function clearPostMergeReconRecovery(cwd, repo, pr) {
58031
58393
  const path2 = postMergeReconStatePath(cwd, repo, pr);
58032
- if (!(0, import_node_fs46.existsSync)(path2)) return;
58394
+ if (!(0, import_node_fs47.existsSync)(path2)) return;
58033
58395
  try {
58034
- (0, import_node_fs46.unlinkSync)(path2);
58396
+ (0, import_node_fs47.unlinkSync)(path2);
58035
58397
  } catch {
58036
58398
  }
58037
58399
  }
@@ -58066,7 +58428,7 @@ var import_promises7 = require("node:fs/promises");
58066
58428
  init_cli_shared();
58067
58429
 
58068
58430
  // src/api-read.ts
58069
- var import_node_fs47 = require("node:fs");
58431
+ var import_node_fs48 = require("node:fs");
58070
58432
  init_cli_shared();
58071
58433
  var API_ACCEPT_HEADERS = {
58072
58434
  json: "application/vnd.github+json",
@@ -58331,7 +58693,7 @@ function registerApiReadCommands(program3, overrides) {
58331
58693
  if (req.workflowRuns) body = sliceWorkflowRunsPage(body, req.workflowRuns);
58332
58694
  if (o.jq !== void 0) body = await jqRun(o.jq, body, localJqEnv(), ...bindings.length ? [bindings] : []);
58333
58695
  if (zip) {
58334
- (0, import_node_fs47.writeFileSync)(o.out, body, "latin1");
58696
+ (0, import_node_fs48.writeFileSync)(o.out, body, "latin1");
58335
58697
  return;
58336
58698
  }
58337
58699
  } catch (e) {
@@ -59872,9 +60234,9 @@ function registerPrLifecycleCommands(program3) {
59872
60234
 
59873
60235
  // src/review-verdict.ts
59874
60236
  var import_node_child_process15 = require("node:child_process");
59875
- var import_node_fs48 = require("node:fs");
60237
+ var import_node_fs49 = require("node:fs");
59876
60238
  var import_node_os24 = require("node:os");
59877
- var import_node_path44 = require("node:path");
60239
+ var import_node_path45 = require("node:path");
59878
60240
  init_cli_shared();
59879
60241
  var REVIEW_VERDICT_MARKER = "<!-- zeroci-review v1 -->";
59880
60242
  var REVIEW_VERDICTS = ["PROCEED", "CORRECT", "ESCALATE"];
@@ -59970,7 +60332,7 @@ async function checkPrReview(number, repo, head, deps = {
59970
60332
  }
59971
60333
  }
59972
60334
  function computePrPatchId(number, repo) {
59973
- return new Promise((resolve7, reject2) => {
60335
+ return new Promise((resolve8, reject2) => {
59974
60336
  const gh2 = (0, import_node_child_process15.spawn)("gh", ["pr", "diff", number, "--repo", repo], { windowsHide: true, stdio: ["ignore", "pipe", "pipe"] });
59975
60337
  const git3 = (0, import_node_child_process15.spawn)("git", ["patch-id", "--stable"], { windowsHide: true, stdio: ["pipe", "pipe", "pipe"] });
59976
60338
  let out = "";
@@ -60008,7 +60370,7 @@ function computePrPatchId(number, repo) {
60008
60370
  if (gitCode !== 0) return reject2(new Error(`git patch-id --stable exited ${gitCode}: ${gitErr.trim()}`));
60009
60371
  const id = out.trim().split(/\s+/)[0];
60010
60372
  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);
60373
+ resolve8(id);
60012
60374
  };
60013
60375
  gh2.on("close", (code) => {
60014
60376
  ghCode = code;
@@ -60039,15 +60401,15 @@ async function readPrIssueComments(number, repo) {
60039
60401
  return comments;
60040
60402
  }
60041
60403
  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");
60404
+ const dir = (0, import_node_fs49.mkdtempSync)((0, import_node_path45.join)((0, import_node_os24.tmpdir)(), "mmi-review-verdict-"));
60405
+ const path2 = (0, import_node_path45.join)(dir, "body.md");
60044
60406
  try {
60045
- (0, import_node_fs48.writeFileSync)(path2, body, "utf8");
60407
+ (0, import_node_fs49.writeFileSync)(path2, body, "utf8");
60046
60408
  const { stdout } = await execFileP("gh", ["pr", "comment", number, "--repo", repo, "--body-file", path2], { timeout: GH_MUTATION_TIMEOUT_MS });
60047
60409
  return stdout.trim();
60048
60410
  } finally {
60049
60411
  try {
60050
- (0, import_node_fs48.rmSync)(dir, { recursive: true, force: true });
60412
+ (0, import_node_fs49.rmSync)(dir, { recursive: true, force: true });
60051
60413
  } catch {
60052
60414
  }
60053
60415
  }
@@ -60202,7 +60564,7 @@ init_cli_shared();
60202
60564
  var GIT_TIMEOUT_MS2 = 15e3;
60203
60565
  function catFileBatch(root, ref, paths) {
60204
60566
  if (paths.length === 0) return Promise.resolve([]);
60205
- return new Promise((resolve7) => {
60567
+ return new Promise((resolve8) => {
60206
60568
  const chunks = [];
60207
60569
  let settled2 = false;
60208
60570
  const child2 = (0, import_node_child_process16.spawn)("git", ["-C", root, "cat-file", "--batch", "--buffer"], { windowsHide: true });
@@ -60210,7 +60572,7 @@ function catFileBatch(root, ref, paths) {
60210
60572
  if (settled2) return;
60211
60573
  settled2 = true;
60212
60574
  clearTimeout(timer);
60213
- resolve7(ok ? parseCatFileBatch(Buffer.concat(chunks), paths.length) : []);
60575
+ resolve8(ok ? parseCatFileBatch(Buffer.concat(chunks), paths.length) : []);
60214
60576
  };
60215
60577
  const timer = setTimeout(() => {
60216
60578
  child2.kill("SIGKILL");
@@ -60460,18 +60822,18 @@ function createPreparationDeps(input, io = {}) {
60460
60822
  }
60461
60823
 
60462
60824
  // src/worktree-residue-sweep.ts
60463
- var import_node_fs52 = require("node:fs");
60464
- var import_node_path48 = require("node:path");
60825
+ var import_node_fs53 = require("node:fs");
60826
+ var import_node_path49 = require("node:path");
60465
60827
 
60466
60828
  // src/worktree-merge-cleanup.ts
60467
- var import_node_fs51 = require("node:fs");
60468
- var import_node_path47 = require("node:path");
60829
+ var import_node_fs52 = require("node:fs");
60830
+ var import_node_path48 = require("node:path");
60469
60831
  init_cli_shared();
60470
60832
 
60471
60833
  // src/stage-runner.ts
60472
60834
  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");
60835
+ var import_node_fs51 = require("node:fs");
60836
+ var import_node_path47 = require("node:path");
60475
60837
  var import_node_net = require("node:net");
60476
60838
  var import_node_util5 = require("node:util");
60477
60839
 
@@ -60481,8 +60843,8 @@ function normalizeEol2(s) {
60481
60843
  }
60482
60844
 
60483
60845
  // src/env-detection.ts
60484
- var import_node_fs49 = require("node:fs");
60485
- var import_node_path45 = require("node:path");
60846
+ var import_node_fs50 = require("node:fs");
60847
+ var import_node_path46 = require("node:path");
60486
60848
  var SKIPPED_DIRS = /* @__PURE__ */ new Set([".git", "node_modules", "dist", ".jerv", ".pi", ".venv", "venv"]);
60487
60849
  function isEnvBaseName(name) {
60488
60850
  return name.toLowerCase() === ".env";
@@ -60492,7 +60854,7 @@ function findEnvFiles(root) {
60492
60854
  const walk2 = (dir, rel) => {
60493
60855
  let entries;
60494
60856
  try {
60495
- entries = (0, import_node_fs49.readdirSync)(dir, { withFileTypes: true });
60857
+ entries = (0, import_node_fs50.readdirSync)(dir, { withFileTypes: true });
60496
60858
  } catch {
60497
60859
  return;
60498
60860
  }
@@ -60500,13 +60862,13 @@ function findEnvFiles(root) {
60500
60862
  const relPath = rel ? `${rel}/${entry.name}` : entry.name;
60501
60863
  if (entry.isDirectory()) {
60502
60864
  if (SKIPPED_DIRS.has(entry.name)) continue;
60503
- walk2((0, import_node_path45.join)(dir, entry.name), relPath);
60865
+ walk2((0, import_node_path46.join)(dir, entry.name), relPath);
60504
60866
  continue;
60505
60867
  }
60506
60868
  if (isEnvBaseName(entry.name)) {
60507
60869
  let isDir = false;
60508
60870
  try {
60509
- isDir = (0, import_node_fs49.lstatSync)((0, import_node_path45.join)(dir, entry.name)).isDirectory();
60871
+ isDir = (0, import_node_fs50.lstatSync)((0, import_node_path46.join)(dir, entry.name)).isDirectory();
60510
60872
  } catch {
60511
60873
  }
60512
60874
  if (!isDir) found.push(relPath);
@@ -60645,12 +61007,12 @@ var DOCKER_TIMEOUT_MS = 15e3;
60645
61007
  function stageBash() {
60646
61008
  if (process.platform !== "win32") return "bash";
60647
61009
  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;
61010
+ 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
61011
  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")] : []
61012
+ (0, import_node_path47.join)(process.env.ProgramFiles || "C:\\Program Files", "Git", "bin", "bash.exe"),
61013
+ ...process.env.LOCALAPPDATA ? [(0, import_node_path47.join)(process.env.LOCALAPPDATA, "Programs", "Git", "bin", "bash.exe")] : []
60652
61014
  ];
60653
- const bash = candidates.find((path2) => (0, import_node_fs50.existsSync)(path2));
61015
+ const bash = candidates.find((path2) => (0, import_node_fs51.existsSync)(path2));
60654
61016
  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
61017
  return bash;
60656
61018
  }
@@ -60671,7 +61033,7 @@ function healthPollIntervalMs() {
60671
61033
  return HEALTH_POLL_INTERVAL_MS;
60672
61034
  }
60673
61035
  function waitForProcessStability(child2, graceMs = earlyExitGraceMs()) {
60674
- return new Promise((resolve7, reject2) => {
61036
+ return new Promise((resolve8, reject2) => {
60675
61037
  let settled2 = false;
60676
61038
  const finish = (fn) => {
60677
61039
  if (settled2) return;
@@ -60681,7 +61043,7 @@ function waitForProcessStability(child2, graceMs = earlyExitGraceMs()) {
60681
61043
  child2.removeAllListeners("exit");
60682
61044
  fn();
60683
61045
  };
60684
- const timer = setTimeout(() => finish(resolve7), graceMs);
61046
+ const timer = setTimeout(() => finish(resolve8), graceMs);
60685
61047
  child2.on("error", (err) => finish(() => reject2(new Error(`stage process failed to start: ${err.message}`))));
60686
61048
  child2.on("exit", (code, signal) => {
60687
61049
  const detail = code != null ? `code ${code}` : signal ? `signal ${signal}` : "unknown reason";
@@ -60788,7 +61150,7 @@ function appendForceRecreate(up) {
60788
61150
  return `${up.trimEnd()} --force-recreate`;
60789
61151
  }
60790
61152
  function stageStatePath(cwd = process.cwd()) {
60791
- return (0, import_node_path46.join)(cwd, "tmp", "stage", "state.json");
61153
+ return (0, import_node_path47.join)(cwd, "tmp", "stage", "state.json");
60792
61154
  }
60793
61155
  function normPath(path2) {
60794
61156
  return path2.replace(/\\/g, "/").replace(/\/+$/, "").toLowerCase();
@@ -60874,10 +61236,10 @@ function pickStagePort(range, isFree) {
60874
61236
  throw new Error(`no free stage port in range ${start}-${end} \u2014 every port is in use`);
60875
61237
  }
60876
61238
  function isPortFree(port) {
60877
- return new Promise((resolve7) => {
61239
+ return new Promise((resolve8) => {
60878
61240
  const srv = (0, import_node_net.createServer)();
60879
- srv.once("error", () => resolve7(false));
60880
- srv.once("listening", () => srv.close(() => resolve7(true)));
61241
+ srv.once("error", () => resolve8(false));
61242
+ srv.once("listening", () => srv.close(() => resolve8(true)));
60881
61243
  srv.listen(port, "127.0.0.1");
60882
61244
  });
60883
61245
  }
@@ -61005,8 +61367,8 @@ function stageProcessEnv(stagePort, extraEnv) {
61005
61367
  }
61006
61368
  function composeResolvesPort(cwd) {
61007
61369
  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");
61370
+ const envFile = (0, import_node_path47.join)(cwd, ".env");
61371
+ return (0, import_node_fs51.existsSync)(envFile) && envFileKeys((0, import_node_fs51.readFileSync)(envFile, "utf8")).has("PORT");
61010
61372
  }
61011
61373
  function stageComposeEnv(config, stagePort, vaultEnvMerge, cwd) {
61012
61374
  const composeProject = config.env?.COMPOSE_PROJECT_NAME ?? vaultEnvMerge?.COMPOSE_PROJECT_NAME ?? stageComposeProjectName(cwd);
@@ -61021,13 +61383,13 @@ function stageComposeEnv(config, stagePort, vaultEnvMerge, cwd) {
61021
61383
  function stageComposeFiles(cwd) {
61022
61384
  const files = ["docker-compose.yml"];
61023
61385
  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);
61386
+ if ((0, import_node_fs51.existsSync)((0, import_node_path47.join)(cwd, conventional))) files.push(conventional);
61025
61387
  }
61026
61388
  return [...files, RUNTIME_ENV_OVERRIDE_RELPATH];
61027
61389
  }
61028
61390
  async function prepareRuntimeEnvPassthrough(cwd, composeEnv, vaultEnvMerge) {
61029
61391
  const keys = Object.keys(vaultEnvMerge ?? {});
61030
- if (!keys.length || !(0, import_node_fs50.existsSync)((0, import_node_path46.join)(cwd, "docker-compose.yml"))) return {};
61392
+ if (!keys.length || !(0, import_node_fs51.existsSync)((0, import_node_path47.join)(cwd, "docker-compose.yml"))) return {};
61031
61393
  let configJson;
61032
61394
  try {
61033
61395
  const { stdout } = await execFileP3("docker", ["compose", "config", "--format", "json"], {
@@ -61043,21 +61405,21 @@ async function prepareRuntimeEnvPassthrough(cwd, composeEnv, vaultEnvMerge) {
61043
61405
  }
61044
61406
  const body = renderRuntimeEnvOverride(runtimeEnvMarkedServices(configJson), keys, runtimeEnvExcludes(configJson), runtimeEnvSelects(configJson));
61045
61407
  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");
61408
+ const overridePath = (0, import_node_path47.join)(cwd, RUNTIME_ENV_OVERRIDE_RELPATH);
61409
+ (0, import_node_fs51.mkdirSync)((0, import_node_path47.join)(cwd, "tmp", "stage"), { recursive: true });
61410
+ (0, import_node_fs51.writeFileSync)(overridePath, body, "utf8");
61049
61411
  return stageComposeFileEnv(stageComposeFiles(cwd));
61050
61412
  }
61051
61413
  async function ensureStageRuntimeEnv(config, opts, cwd) {
61052
61414
  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
61415
+ const target = (0, import_node_path47.join)(cwd, config.ensureEnv.target);
61416
+ const example = (0, import_node_path47.join)(cwd, config.ensureEnv.example);
61417
+ if (!(0, import_node_fs51.existsSync)(target) && (0, import_node_fs51.existsSync)(example)) {
61418
+ (0, import_node_fs51.copyFileSync)(example, target);
61419
+ } else if ((0, import_node_fs51.existsSync)(target) && (0, import_node_fs51.existsSync)(example)) {
61420
+ const stale = detectStaleEnvFile((0, import_node_fs51.readFileSync)(example, "utf8"), (0, import_node_fs51.readFileSync)(target, "utf8"), {
61421
+ exampleMtimeMs: (0, import_node_fs51.statSync)(example).mtimeMs,
61422
+ targetMtimeMs: (0, import_node_fs51.statSync)(target).mtimeMs
61061
61423
  });
61062
61424
  if (stale) {
61063
61425
  const msg = `stale ${config.ensureEnv.target} (${stale}) \u2014 delete it or refresh from ${config.ensureEnv.example} before re-running mmi-cli stage`;
@@ -61065,8 +61427,8 @@ async function ensureStageRuntimeEnv(config, opts, cwd) {
61065
61427
  console.error(`mmi-cli stage: ${msg} (allowed via --allow-stale-env)`);
61066
61428
  }
61067
61429
  }
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");
61430
+ if (opts.vaultEnvMerge && Object.keys(opts.vaultEnvMerge).length && (0, import_node_fs51.existsSync)(target)) {
61431
+ (0, import_node_fs51.writeFileSync)(target, mergeEnvSecretsIntoFile((0, import_node_fs51.readFileSync)(target, "utf8"), opts.vaultEnvMerge), "utf8");
61070
61432
  }
61071
61433
  }
61072
61434
  async function gitText(cwd, args) {
@@ -61096,20 +61458,20 @@ async function resolveGlobalStatePath(cwd, explicit) {
61096
61458
  return void 0;
61097
61459
  }
61098
61460
  function readState(path2) {
61099
- if (!(0, import_node_fs50.existsSync)(path2)) return null;
61461
+ if (!(0, import_node_fs51.existsSync)(path2)) return null;
61100
61462
  try {
61101
- return JSON.parse((0, import_node_fs50.readFileSync)(path2, "utf8"));
61463
+ return JSON.parse((0, import_node_fs51.readFileSync)(path2, "utf8"));
61102
61464
  } catch {
61103
61465
  return null;
61104
61466
  }
61105
61467
  }
61106
61468
  function mkdirFor(path2) {
61107
61469
  const dir = path2.slice(0, Math.max(path2.lastIndexOf("/"), path2.lastIndexOf("\\")));
61108
- (0, import_node_fs50.mkdirSync)(dir, { recursive: true });
61470
+ (0, import_node_fs51.mkdirSync)(dir, { recursive: true });
61109
61471
  }
61110
61472
  function writeState(path2, state) {
61111
61473
  mkdirFor(path2);
61112
- (0, import_node_fs50.writeFileSync)(path2, JSON.stringify(state, null, 2), "utf8");
61474
+ (0, import_node_fs51.writeFileSync)(path2, JSON.stringify(state, null, 2), "utf8");
61113
61475
  }
61114
61476
  function writeStagePortReservation(port, cwd, statePath, globalStatePath, now) {
61115
61477
  const reservation = {
@@ -61138,7 +61500,7 @@ async function cleanupStageState(state, paths, timeoutMs, fallbackCwd, currentEn
61138
61500
  );
61139
61501
  }
61140
61502
  for (const path2 of [...new Set(paths.filter((p) => Boolean(p)))]) {
61141
- (0, import_node_fs50.rmSync)(path2, { force: true });
61503
+ (0, import_node_fs51.rmSync)(path2, { force: true });
61142
61504
  }
61143
61505
  }
61144
61506
  async function killTree(pid) {
@@ -61155,7 +61517,7 @@ async function killTree(pid) {
61155
61517
  } catch {
61156
61518
  }
61157
61519
  }
61158
- await new Promise((resolve7) => setTimeout(resolve7, 500));
61520
+ await new Promise((resolve8) => setTimeout(resolve8, 500));
61159
61521
  try {
61160
61522
  process.kill(-pid, "SIGKILL");
61161
61523
  } catch {
@@ -61228,7 +61590,7 @@ async function waitForHealth(url, timeoutMs, anyStatus = false) {
61228
61590
  } catch (e) {
61229
61591
  last = e.message;
61230
61592
  }
61231
- await new Promise((resolve7) => setTimeout(resolve7, healthPollIntervalMs()));
61593
+ await new Promise((resolve8) => setTimeout(resolve8, healthPollIntervalMs()));
61232
61594
  }
61233
61595
  throw new Error(`stage health check timed out for ${url}${last ? ` (${last})` : ""}`);
61234
61596
  }
@@ -61385,8 +61747,8 @@ async function runStage(config = {}, opts = {}) {
61385
61747
  });
61386
61748
  }
61387
61749
  } catch (e) {
61388
- (0, import_node_fs50.rmSync)(statePath, { force: true });
61389
- if (globalStatePath && globalStatePath !== statePath) (0, import_node_fs50.rmSync)(globalStatePath, { force: true });
61750
+ (0, import_node_fs51.rmSync)(statePath, { force: true });
61751
+ if (globalStatePath && globalStatePath !== statePath) (0, import_node_fs51.rmSync)(globalStatePath, { force: true });
61390
61752
  throw e;
61391
61753
  }
61392
61754
  const started = await startStage(config, {
@@ -61405,9 +61767,9 @@ function normPath2(p) {
61405
61767
  return p.replace(/\\/g, "/").replace(/\/+$/, "");
61406
61768
  }
61407
61769
  function unlinkNodeModulesJunction(wtPath) {
61408
- const nm = (0, import_node_path47.join)(wtPath, "node_modules");
61770
+ const nm = (0, import_node_path48.join)(wtPath, "node_modules");
61409
61771
  try {
61410
- if ((0, import_node_fs51.lstatSync)(nm).isSymbolicLink()) (0, import_node_fs51.rmdirSync)(nm);
61772
+ if ((0, import_node_fs52.lstatSync)(nm).isSymbolicLink()) (0, import_node_fs52.rmdirSync)(nm);
61411
61773
  return { ok: true };
61412
61774
  } catch (e) {
61413
61775
  if (e.code === "ENOENT") return { ok: true };
@@ -61415,11 +61777,11 @@ function unlinkNodeModulesJunction(wtPath) {
61415
61777
  }
61416
61778
  }
61417
61779
  function defaultSleep2(ms) {
61418
- return new Promise((resolve7) => setTimeout(resolve7, ms));
61780
+ return new Promise((resolve8) => setTimeout(resolve8, ms));
61419
61781
  }
61420
61782
  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 }));
61783
+ const { sleep: sleep2 = defaultSleep2, removeEmptyDir = import_node_fs52.rmdirSync, exists = import_node_fs52.existsSync } = options;
61784
+ const removeRecursive = options.removeRecursive ?? ((path2) => (0, import_node_fs52.rmSync)(path2, { recursive: true, force: true, maxRetries: 10, retryDelay: 100 }));
61423
61785
  const junction = unlinkNodeModulesJunction(wtPath);
61424
61786
  if (!junction.ok) return junction;
61425
61787
  try {
@@ -61542,28 +61904,28 @@ async function preCleanWorktreeForRemoval(wtPath, execGit) {
61542
61904
  }
61543
61905
  async function listNestedIgnoredNodeModules(wtPath, execGit) {
61544
61906
  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)));
61907
+ 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
61908
  }
61547
61909
  function safeRemoveTree(path2) {
61548
- const stat4 = (0, import_node_fs51.lstatSync)(path2);
61910
+ const stat4 = (0, import_node_fs52.lstatSync)(path2);
61549
61911
  if (stat4.isSymbolicLink()) {
61550
61912
  try {
61551
- (0, import_node_fs51.rmdirSync)(path2);
61913
+ (0, import_node_fs52.rmdirSync)(path2);
61552
61914
  } catch {
61553
- (0, import_node_fs51.unlinkSync)(path2);
61915
+ (0, import_node_fs52.unlinkSync)(path2);
61554
61916
  }
61555
61917
  return;
61556
61918
  }
61557
61919
  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);
61920
+ for (const entry of (0, import_node_fs52.readdirSync)(path2)) safeRemoveTree((0, import_node_path48.join)(path2, entry));
61921
+ (0, import_node_fs52.rmdirSync)(path2);
61560
61922
  return;
61561
61923
  }
61562
- (0, import_node_fs51.unlinkSync)(path2);
61924
+ (0, import_node_fs52.unlinkSync)(path2);
61563
61925
  }
61564
61926
  async function removeWorktreeNodeModules(wtPath) {
61565
61927
  try {
61566
- safeRemoveTree((0, import_node_path47.join)(wtPath, "node_modules"));
61928
+ safeRemoveTree((0, import_node_path48.join)(wtPath, "node_modules"));
61567
61929
  return { ok: true };
61568
61930
  } catch (e) {
61569
61931
  if (e.code === "ENOENT") return { ok: true };
@@ -61575,7 +61937,7 @@ function errorMessage(e) {
61575
61937
  }
61576
61938
  function resolvedOrRaw(path2) {
61577
61939
  try {
61578
- return normPath2((0, import_node_fs51.realpathSync)(path2));
61940
+ return normPath2((0, import_node_fs52.realpathSync)(path2));
61579
61941
  } catch {
61580
61942
  return normPath2(path2);
61581
61943
  }
@@ -61583,10 +61945,10 @@ function resolvedOrRaw(path2) {
61583
61945
  function unlinkEscapingReparsePoints(root, primaryRoot) {
61584
61946
  let realRoot;
61585
61947
  try {
61586
- if ((0, import_node_fs51.lstatSync)(root).isSymbolicLink()) {
61948
+ if ((0, import_node_fs52.lstatSync)(root).isSymbolicLink()) {
61587
61949
  return { ok: false, error: `delete root ${normPath2(root)} is a reparse point resolving to ${resolvedOrRaw(root)}` };
61588
61950
  }
61589
- realRoot = normPath2((0, import_node_fs51.realpathSync)(root));
61951
+ realRoot = normPath2((0, import_node_fs52.realpathSync)(root));
61590
61952
  } catch (e) {
61591
61953
  if (e.code === "ENOENT") return { ok: true, unlinked: [] };
61592
61954
  return { ok: false, error: `cannot resolve delete root ${normPath2(root)}: ${errorMessage(e)}` };
@@ -61602,17 +61964,17 @@ function unlinkEscapingReparsePoints(root, primaryRoot) {
61602
61964
  const dir = stack.pop();
61603
61965
  let entries;
61604
61966
  try {
61605
- entries = (0, import_node_fs51.readdirSync)(dir, { withFileTypes: true });
61967
+ entries = (0, import_node_fs52.readdirSync)(dir, { withFileTypes: true });
61606
61968
  } catch (e) {
61607
61969
  if (e.code === "ENOENT") continue;
61608
61970
  return { ok: false, error: `cannot scan ${normPath2(dir)} for reparse points: ${errorMessage(e)}` };
61609
61971
  }
61610
61972
  for (const entry of entries) {
61611
- const child2 = (0, import_node_path47.join)(dir, entry.name);
61973
+ const child2 = (0, import_node_path48.join)(dir, entry.name);
61612
61974
  if (entry.isSymbolicLink()) {
61613
61975
  let target = "";
61614
61976
  try {
61615
- target = normPath2((0, import_node_fs51.realpathSync)(child2));
61977
+ target = normPath2((0, import_node_fs52.realpathSync)(child2));
61616
61978
  } catch {
61617
61979
  target = "";
61618
61980
  }
@@ -61795,7 +62157,7 @@ async function cleanupPrMergeLocalBranch(branch, options) {
61795
62157
  return report;
61796
62158
  }
61797
62159
  const execGit = options.execGit ?? (async (args) => (await execFileP("git", args, { timeout: GIT_TIMEOUT_MS })).stdout);
61798
- const pathExists = options.pathExists ?? import_node_fs51.existsSync;
62160
+ const pathExists = options.pathExists ?? import_node_fs52.existsSync;
61799
62161
  let afterWorktrees = [];
61800
62162
  try {
61801
62163
  afterWorktrees = parseGitWorktreePorcelain(await execGit(["worktree", "list", "--porcelain"]));
@@ -61935,7 +62297,7 @@ async function cleanupPrMergeLocalBranch(branch, options) {
61935
62297
  const preHelperGuard = unlinkEscapingReparsePoints(wtPath, options.primaryRoot);
61936
62298
  if (!preHelperGuard.ok) return refuseReparseEscape(preHelperGuard.error);
61937
62299
  unlinkedReparsePoints.push(...preHelperGuard.unlinked);
61938
- if (pathExists((0, import_node_path47.join)(wtPath, "node_modules"))) {
62300
+ if (pathExists((0, import_node_path48.join)(wtPath, "node_modules"))) {
61939
62301
  const nmRemoved = await (options.removeRealNodeModules ?? removeWorktreeNodeModules)(wtPath);
61940
62302
  if (!nmRemoved.ok) {
61941
62303
  report.worktree = {
@@ -62071,18 +62433,18 @@ function renderPrMergeCleanupLines(cleanup) {
62071
62433
  // src/worktree-residue-sweep.ts
62072
62434
  var RESIDUE_LEDGER_FILE = "mmi-worktree-residue.json";
62073
62435
  function canonicalWorktreeRoot(primary) {
62074
- return (0, import_node_path48.join)((0, import_node_path48.dirname)(primary), "mmi-worktrees", (0, import_node_path48.basename)(primary));
62436
+ return (0, import_node_path49.join)((0, import_node_path49.dirname)(primary), "mmi-worktrees", (0, import_node_path49.basename)(primary));
62075
62437
  }
62076
- function norm(p) {
62438
+ function norm2(p) {
62077
62439
  const s = p.replace(/\\/g, "/").replace(/\/+$/, "");
62078
62440
  return process.platform === "win32" ? s.toLowerCase() : s;
62079
62441
  }
62080
62442
  function residueLedgerPath(gitCommonDir) {
62081
- return (0, import_node_path48.join)(gitCommonDir, RESIDUE_LEDGER_FILE);
62443
+ return (0, import_node_path49.join)(gitCommonDir, RESIDUE_LEDGER_FILE);
62082
62444
  }
62083
62445
  function readPaths(file, deps) {
62084
62446
  try {
62085
- const parsed = JSON.parse((deps.readLedger ?? ((f) => (0, import_node_fs52.readFileSync)(f, "utf8")))(file));
62447
+ const parsed = JSON.parse((deps.readLedger ?? ((f) => (0, import_node_fs53.readFileSync)(f, "utf8")))(file));
62086
62448
  return Array.isArray(parsed) ? parsed.filter((p) => typeof p === "string") : [];
62087
62449
  } catch {
62088
62450
  return [];
@@ -62091,8 +62453,8 @@ function readPaths(file, deps) {
62091
62453
  function writePaths(file, paths, deps) {
62092
62454
  try {
62093
62455
  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");
62456
+ (0, import_node_fs53.mkdirSync)((0, import_node_path49.dirname)(f), { recursive: true });
62457
+ (0, import_node_fs53.writeFileSync)(f, t, "utf8");
62096
62458
  });
62097
62459
  write(file, `${JSON.stringify([...new Set(paths)], null, 1)}
62098
62460
  `);
@@ -62102,29 +62464,29 @@ function writePaths(file, paths, deps) {
62102
62464
  function recordResidue(gitCommonDir, path2, deps = {}) {
62103
62465
  const file = residueLedgerPath(gitCommonDir);
62104
62466
  const paths = readPaths(file, deps);
62105
- if (!paths.some((p) => norm(p) === norm(path2))) paths.push(path2);
62467
+ if (!paths.some((p) => norm2(p) === norm2(path2))) paths.push(path2);
62106
62468
  writePaths(file, paths, deps);
62107
62469
  }
62108
62470
  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));
62471
+ const exists = deps.exists ?? import_node_fs53.existsSync;
62472
+ const readDir = deps.readDir ?? ((p) => (0, import_node_fs53.readdirSync)(p));
62111
62473
  const isDir = deps.isDir ?? ((p) => {
62112
62474
  try {
62113
- return (0, import_node_fs52.statSync)(p).isDirectory();
62475
+ return (0, import_node_fs53.statSync)(p).isDirectory();
62114
62476
  } catch {
62115
62477
  return false;
62116
62478
  }
62117
62479
  });
62118
62480
  const removeRecorded = deps.removeRecorded ?? ((p) => removeResidueDirectory(p));
62119
- const removeEmpty = deps.removeEmpty ?? ((p) => (0, import_node_fs52.rmdirSync)(p));
62481
+ const removeEmpty = deps.removeEmpty ?? ((p) => (0, import_node_fs53.rmdirSync)(p));
62120
62482
  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;
62483
+ const live = new Set(registered.map(norm2));
62484
+ const primary = registered[0] ? norm2(registered[0]) : void 0;
62123
62485
  const file = residueLedgerPath(gitCommonDir);
62124
62486
  const recorded = readPaths(file, deps);
62125
62487
  const remaining = [];
62126
62488
  for (const path2 of recorded) {
62127
- const key = norm(path2);
62489
+ const key = norm2(path2);
62128
62490
  if (live.has(key) || key === primary) {
62129
62491
  report.dropped.push(path2);
62130
62492
  continue;
@@ -62141,9 +62503,9 @@ async function sweepWorktreeResidue(gitCommonDir, registered, deps = {}) {
62141
62503
  }
62142
62504
  }
62143
62505
  if (recorded.length) writePaths(file, remaining, deps);
62144
- const keptKeys = new Set(remaining.map(norm));
62506
+ const keptKeys = new Set(remaining.map(norm2));
62145
62507
  const root = registered[0] ? canonicalWorktreeRoot(registered[0]) : void 0;
62146
- if (root && isDir(root) && !live.has(norm(root))) {
62508
+ if (root && isDir(root) && !live.has(norm2(root))) {
62147
62509
  report.root = root;
62148
62510
  let children = [];
62149
62511
  try {
@@ -62151,8 +62513,8 @@ async function sweepWorktreeResidue(gitCommonDir, registered, deps = {}) {
62151
62513
  } catch {
62152
62514
  }
62153
62515
  for (const name of children) {
62154
- const child2 = (0, import_node_path48.join)(root, name);
62155
- const key = norm(child2);
62516
+ const child2 = (0, import_node_path49.join)(root, name);
62517
+ const key = norm2(child2);
62156
62518
  if (live.has(key) || key === primary || keptKeys.has(key) || !isDir(child2)) continue;
62157
62519
  let entries;
62158
62520
  try {
@@ -62194,10 +62556,10 @@ function argvWantsJson2() {
62194
62556
  return process.argv.some((a) => a === "--json" || a.startsWith("--json="));
62195
62557
  }
62196
62558
  function hubRoot() {
62197
- const fromPkg = (0, import_node_path49.join)(__dirname, "..", "..");
62559
+ const fromPkg = (0, import_node_path50.join)(__dirname, "..", "..");
62198
62560
  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();
62561
+ if ((0, import_node_fs54.existsSync)((0, import_node_path50.join)(fromPkg, marker))) return fromPkg;
62562
+ if ((0, import_node_fs54.existsSync)((0, import_node_path50.join)(process.cwd(), marker))) return process.cwd();
62201
62563
  return null;
62202
62564
  }
62203
62565
  function ciAuditDeps() {
@@ -62209,8 +62571,8 @@ function ciAuditDeps() {
62209
62571
  getProjectMeta: async (slug) => fetchProjectBySlug(slug, registryClientDeps(await cfgPromise)),
62210
62572
  readSeedFile: (path2) => {
62211
62573
  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;
62574
+ const fullPath = (0, import_node_path50.join)(root, path2);
62575
+ return (0, import_node_fs54.existsSync)(fullPath) ? (0, import_node_fs54.readFileSync)(fullPath, "utf8") : null;
62214
62576
  }
62215
62577
  };
62216
62578
  }
@@ -63077,11 +63439,11 @@ ${preparation.findings.map((finding) => `[${finding.check}/${finding.state}] ${f
63077
63439
  }
63078
63440
  });
63079
63441
  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) => {
63442
+ const wfDir = (0, import_node_path50.join)(cwd, ".github", "workflows");
63443
+ if (!(0, import_node_fs54.existsSync)(wfDir)) return [];
63444
+ return (0, import_node_fs54.readdirSync)(wfDir).filter((name) => /\.(ya?ml)$/i.test(name)).filter((name) => {
63083
63445
  try {
63084
- return workflowReportsPrChecks((0, import_node_fs53.readFileSync)((0, import_node_path49.join)(wfDir, name), "utf8"));
63446
+ return workflowReportsPrChecks((0, import_node_fs54.readFileSync)((0, import_node_path50.join)(wfDir, name), "utf8"));
63085
63447
  } catch {
63086
63448
  return true;
63087
63449
  }
@@ -63269,7 +63631,7 @@ ${preparation.findings.map((finding) => `[${finding.check}/${finding.state}] ${f
63269
63631
  // #5400: after grace, name "GitHub delivered zero runs" instead of burning the full budget as pending.
63270
63632
  pollHeadWorkflowRunCount: () => waitLoopHeadWorkflowRunCount("pr checks-wait", number, repo),
63271
63633
  baseBranch,
63272
- sleep: (ms) => new Promise((resolve7) => setTimeout(resolve7, ms)),
63634
+ sleep: (ms) => new Promise((resolve8) => setTimeout(resolve8, ms)),
63273
63635
  log: (message2) => console.warn(message2),
63274
63636
  timeoutMs: Math.max(1, budgetMs - (Date.now() - waitStarted)),
63275
63637
  // Liveness on stderr, one line per poll. A silent bounded wait is indistinguishable from a hang, and
@@ -63286,7 +63648,7 @@ ${preparation.findings.map((finding) => `[${finding.check}/${finding.state}] ${f
63286
63648
  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
63649
  if (!isReviewVerdict(o.verdict)) return fail(`pr review-verdict: --verdict must be one of ${REVIEW_VERDICTS.join("|")} (got ${o.verdict})`);
63288
63650
  const verdict = o.verdict;
63289
- const findings = o.findingsFile ? (0, import_node_fs53.readFileSync)(o.findingsFile, "utf8") : void 0;
63651
+ const findings = o.findingsFile ? (0, import_node_fs54.readFileSync)(o.findingsFile, "utf8") : void 0;
63290
63652
  let patch;
63291
63653
  let head;
63292
63654
  try {
@@ -63449,7 +63811,7 @@ ${preparation.findings.map((finding) => `[${finding.check}/${finding.state}] ${f
63449
63811
  // #5400: same zero-runs delivery probe as checks-wait — do not burn the land budget on silence.
63450
63812
  pollHeadWorkflowRunCount: () => waitLoopHeadWorkflowRunCount("pr land", prNumber, repo),
63451
63813
  baseBranch: "development",
63452
- sleep: (ms) => new Promise((resolve7) => setTimeout(resolve7, ms)),
63814
+ sleep: (ms) => new Promise((resolve8) => setTimeout(resolve8, ms)),
63453
63815
  log: (message2) => console.warn(message2),
63454
63816
  // `pr land` inherits the same (raised) checks budget, so it needs the same liveness — otherwise the
63455
63817
  // 30m wait is SILENT and reads exactly like the hang #2940 was filed about, only three times longer.
@@ -63513,7 +63875,7 @@ ${preparation.findings.map((finding) => `[${finding.check}/${finding.state}] ${f
63513
63875
  } else {
63514
63876
  lastFailure2 = void 0;
63515
63877
  }
63516
- await new Promise((resolve7) => setTimeout(resolve7, PR_LAND_POLL_MS));
63878
+ await new Promise((resolve8) => setTimeout(resolve8, PR_LAND_POLL_MS));
63517
63879
  }
63518
63880
  if (lastFailure2) {
63519
63881
  throw new Error(
@@ -63564,7 +63926,7 @@ ${preparation.findings.map((finding) => `[${finding.check}/${finding.state}] ${f
63564
63926
  const cleanupMerged = async (r) => {
63565
63927
  if (opts.preserveWorktree) return "cleanup skipped (--preserve-worktree)";
63566
63928
  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,
63929
+ cwd: (0, import_node_fs54.existsSync)(cwd0) ? cwd0 : primaryRoot0,
63568
63930
  timeout: GH_MUTATION_TIMEOUT_MS * 3
63569
63931
  }).then((x) => ({ stdout: x.stdout, stderr: x.stderr }), (e) => ({ stdout: e.stdout ?? "", stderr: e.stderr ?? "" }));
63570
63932
  const json = ran.stdout.split("\n").reverse().find((l) => l.startsWith("{"));
@@ -63635,7 +63997,7 @@ ${preparation.findings.map((finding) => `[${finding.check}/${finding.state}] ${f
63635
63997
  const mergeSquashBody = squashBodyTextForMerge(
63636
63998
  closingGuardInput,
63637
63999
  method === "--squash",
63638
- o.squashBodyFile ? (0, import_node_fs53.readFileSync)(o.squashBodyFile, "utf8") : void 0
64000
+ o.squashBodyFile ? (0, import_node_fs54.readFileSync)(o.squashBodyFile, "utf8") : void 0
63639
64001
  );
63640
64002
  if (!o.squashBodyFile) warnSquashBodyClosingStrip("pr merge", closingGuardInput, mergeSquashBody);
63641
64003
  const closingGuardVerdict = evaluateClosingGuard(closingGuardInput, {
@@ -63667,7 +64029,7 @@ ${preparation.findings.map((finding) => `[${finding.check}/${finding.state}] ${f
63667
64029
  const remote = foreignCwd ? `https://github.com/${targetRepo2}.git` : "origin";
63668
64030
  let foreignCheckout;
63669
64031
  if (foreignCwd) {
63670
- const sibling = (0, import_node_path49.join)((0, import_node_path49.dirname)(beforeWorktrees[0]?.path || startingPath || process.cwd()), targetRepo2.split("/")[1]);
64032
+ const sibling = (0, import_node_path50.join)((0, import_node_path50.dirname)(beforeWorktrees[0]?.path || startingPath || process.cwd()), targetRepo2.split("/")[1]);
63671
64033
  const siblingRepo = repoFromRemoteUrl(await gitOut(["-C", sibling, "remote", "get-url", "origin"]).catch(() => ""));
63672
64034
  if (siblingRepo?.toLowerCase() === targetRepo2.toLowerCase()) {
63673
64035
  const siblingWorktrees = await execFileP("git", ["-C", sibling, "worktree", "list", "--porcelain"], { timeout: GIT_TIMEOUT_MS }).then((r) => parseGitWorktreePorcelain(r.stdout)).catch(() => void 0);
@@ -63705,7 +64067,7 @@ ${preparation.findings.map((finding) => `[${finding.check}/${finding.state}] ${f
63705
64067
  checksDiagnosticCommand: `gh pr checks ${number} --repo ${repo}`,
63706
64068
  pollHeadWorkflowRunCount: () => waitLoopHeadWorkflowRunCount("pr merge --wait", number, repo),
63707
64069
  baseBranch,
63708
- sleep: (ms) => new Promise((resolve7) => setTimeout(resolve7, ms)),
64070
+ sleep: (ms) => new Promise((resolve8) => setTimeout(resolve8, ms)),
63709
64071
  log: (message2) => console.warn(message2),
63710
64072
  timeoutMs: Math.max(1, budgetMs - (Date.now() - waitStarted)),
63711
64073
  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 +64148,7 @@ ${preparation.findings.map((finding) => `[${finding.check}/${finding.state}] ${f
63786
64148
  }
63787
64149
  if (!repoForPostCleanup) throw e;
63788
64150
  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;
64151
+ const commitMessage = bodyFile ? (0, import_node_fs54.readFileSync)(bodyFile, "utf8") : void 0;
63790
64152
  await defaultGitHubClient().rest("PUT", `repos/${repoForPostCleanup}/pulls/${number}/merge`, {
63791
64153
  body: { merge_method: method.slice(2), ...commitMessage ? { commit_message: commitMessage } : {} },
63792
64154
  timeoutMs: GH_MUTATION_TIMEOUT_MS
@@ -63795,7 +64157,7 @@ ${preparation.findings.map((finding) => `[${finding.check}/${finding.state}] ${f
63795
64157
  }
63796
64158
  if (!o.auto && mergeRejectedBaseBranchModified(message2)) {
63797
64159
  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));
64160
+ await new Promise((resolve8) => setTimeout(resolve8, PR_MERGE_BASE_RACE_RETRY_DELAY_MS));
63799
64161
  await execFileP("gh", buildPrMergeArgs({ number, repoArgs, method, auto: false, deleteBranch: false, bodyFile }), { timeout: GH_MUTATION_TIMEOUT_MS }).catch((e2) => {
63800
64162
  const m2 = String(e2.message || "");
63801
64163
  if (/already been merged/i.test(m2)) {
@@ -63901,7 +64263,7 @@ ${preparation.findings.map((finding) => `[${finding.check}/${finding.state}] ${f
63901
64263
  let residueSweep;
63902
64264
  if (!(foreignCwd && !foreignCheckout)) {
63903
64265
  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());
64266
+ gitCommonDir = (0, import_node_path50.resolve)(primaryRoot, (await execFileP("git", ["-C", primaryRoot, "rev-parse", "--git-common-dir"], { timeout: GIT_TIMEOUT_MS })).stdout.trim());
63905
64267
  residueSweep = await sweepWorktreeResidue(gitCommonDir, beforeWorktrees.map((w) => w.path));
63906
64268
  } catch {
63907
64269
  }
@@ -63919,7 +64281,7 @@ ${preparation.findings.map((finding) => `[${finding.check}/${finding.state}] ${f
63919
64281
  preserveWorktree: o.preserveWorktree,
63920
64282
  gcAcknowledged: o.gc,
63921
64283
  expectedHeadOid: headRefOid,
63922
- pathExists: (p) => (0, import_node_fs53.existsSync)(p),
64284
+ pathExists: (p) => (0, import_node_fs54.existsSync)(p),
63923
64285
  // #5899: pin cleanup git calls to the main checkout — the task worktree this process may be
63924
64286
  // standing in is removed mid-cleanup, so a cwd-relative invocation fails with
63925
64287
  // 'fatal: not a git repository' and leaves a spurious partial-cleanup exit.
@@ -64060,7 +64422,7 @@ ${preparation.findings.map((finding) => `[${finding.check}/${finding.state}] ${f
64060
64422
  console.warn(`ci checks-wait: zero-runs probe FAILED (${read.error}) \u2014 not treating as delivery failure this cycle`);
64061
64423
  return null;
64062
64424
  },
64063
- sleep: (ms) => new Promise((resolve7) => setTimeout(resolve7, ms)),
64425
+ sleep: (ms) => new Promise((resolve8) => setTimeout(resolve8, ms)),
64064
64426
  log: (message2) => console.warn(message2),
64065
64427
  timeoutMs: timeoutMs ?? PR_CHECKS_TIMEOUT_MS,
64066
64428
  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 +64559,14 @@ function trainApplyDeps() {
64197
64559
  },
64198
64560
  // Hub-App-authority dispatch of the central tenant deploy (#953) — the Hub fires the
64199
64561
  // 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()));
64562
+ readDeployedSha: async (slug, stage) => (await fetchDeployFactsBySlug(slug, registryClientDeps(await loadConfig())))?.stages[stage]?.deployedTag,
64563
+ compareDeployRef: async (repo, base, head) => (await defaultGitHubClient().rest(
64564
+ "GET",
64565
+ `repos/${repo}/compare/${encodeURIComponent(base)}...${encodeURIComponent(head)}?per_page=1`,
64566
+ { timeoutMs: GH_TRAIN_TIMEOUT_MS }
64567
+ )).status,
64568
+ dispatchTenantDeploy: async ({ repo, stage, ref, rollback }) => {
64569
+ const res = await tenantDeploy({ repo, stage, ref, ...rollback ? { rollback } : {} }, registryClientDeps(await loadConfig()));
64202
64570
  if (!res.ok) {
64203
64571
  const detail = res.body?.error ?? res.error ?? `HTTP ${res.status}`;
64204
64572
  throw new Error(`tenant deploy dispatch failed: ${detail}`);
@@ -64450,7 +64818,7 @@ function hotfixFollowUpLegs(runs2, foldPort, alignment, foldNote, deployNote) {
64450
64818
  }
64451
64819
  return legs;
64452
64820
  }
64453
- async function runProjectInfoSyncLeg(cb, repo, sleep2 = (ms) => new Promise((resolve7) => setTimeout(resolve7, ms))) {
64821
+ async function runProjectInfoSyncLeg(cb, repo, sleep2 = (ms) => new Promise((resolve8) => setTimeout(resolve8, ms))) {
64454
64822
  for (let attempt = 0; ; attempt++) {
64455
64823
  try {
64456
64824
  return await cb(repo, true);
@@ -65185,7 +65553,7 @@ function rcRunCauseFromLog(log) {
65185
65553
  function memberAnnounceSummaryFile(repo, summaryFile, memberSummaryFiles) {
65186
65554
  return repo === SUITE_REPO ? summaryFile : memberSummaryFiles[repo];
65187
65555
  }
65188
- var suiteStateDir = (root) => (0, import_node_path51.join)(resolvePrimaryGitDir(root), "mmi-runtime", "suite");
65556
+ var suiteStateDir = (root) => (0, import_node_path52.join)(resolvePrimaryGitDir(root), "mmi-runtime", "suite");
65189
65557
  async function runSuiteMemberRcand(repo, previousRc, rcWasAbsent) {
65190
65558
  const deps = trainApplyDeps();
65191
65559
  deps.suiteCut = suiteCutContext(repo, SUITE_REPO);
@@ -65204,8 +65572,8 @@ async function rcandInCheckout(repo, deps, previousRc, rcWasAbsent) {
65204
65572
  const meta = await fetchProjectBySlugChecked(slug, registryClientDeps(await loadConfig()));
65205
65573
  if (!meta.ok || meta.project?.releaseTrack !== "full" || meta.project.suite !== "mm-work")
65206
65574
  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`);
65575
+ const main2 = (await deps.run("git", ["rev-parse", "origin/main"])).trim();
65576
+ if (main2.toLowerCase() !== previousRc.toLowerCase()) throw new Error(`${repo}: main moved since the cut snapshot; no rc branch created`);
65209
65577
  await deps.run("git", ["push", "origin", `${previousRc}:refs/heads/rc`]);
65210
65578
  await deps.run("git", ["fetch", "origin", "rc"]);
65211
65579
  rcNow = (await deps.run("git", ["rev-parse", "origin/rc"])).trim();
@@ -65232,16 +65600,16 @@ async function rcandInCheckout(repo, deps, previousRc, rcWasAbsent) {
65232
65600
  }
65233
65601
  }
65234
65602
  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");
65603
+ const recordPath = (0, import_node_path52.join)(suiteStateDir(root), "cut.json");
65604
+ const base = (0, import_node_path52.join)(suiteStateDir(root), "checkouts");
65237
65605
  const checkout = async (repo) => {
65238
65606
  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 });
65607
+ const target = (0, import_node_path52.join)(base, repo.split("/")[1]);
65608
+ if (!(0, import_node_fs55.existsSync)(target)) {
65609
+ (0, import_node_fs55.mkdirSync)(base, { recursive: true });
65242
65610
  await exec("git", ["clone", "--quiet", "--branch", "development", `https://github.com/${repo}.git`, target], root, WATCH_TIMEOUT);
65243
65611
  }
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`);
65612
+ 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
65613
  const origin = await exec("git", ["remote", "get-url", "origin"], target);
65246
65614
  if (!origin.toLowerCase().endsWith(`/${repo.toLowerCase()}.git`) && !origin.toLowerCase().endsWith(`/${repo.toLowerCase()}`))
65247
65615
  throw new Error(`${repo}: suite checkout origin mismatch at ${target}; stop`);
@@ -65305,7 +65673,7 @@ function suiteTrainIo(root, summaryFile, memberSummaryFiles = {}, summaryFileTr,
65305
65673
  if (repo === SUITE_REPO) return inTrain(repo, (deps) => rcandInCheckout(repo, deps, previousRc, rcWasAbsent));
65306
65674
  const target = await checkout(repo);
65307
65675
  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"] : []], {
65676
+ 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
65677
  cwd: target,
65310
65678
  stdio: ["ignore", "inherit", "inherit", "ipc"],
65311
65679
  execArgv: []
@@ -65377,7 +65745,7 @@ function suiteTrainIo(root, summaryFile, memberSummaryFiles = {}, summaryFileTr,
65377
65745
  if (!reuse) await gh(["workflow", "run", "module-rc-publish.yml", "--repo", "mutmutco/MMI-Hub", ...fields.flatMap((f) => ["--field", f])]);
65378
65746
  let candidate = reuse;
65379
65747
  for (let i = 0; !candidate && i < 25; i++) {
65380
- await new Promise((resolve7) => setTimeout(resolve7, 1e3));
65748
+ await new Promise((resolve8) => setTimeout(resolve8, 1e3));
65381
65749
  candidate = (await rcRuns()).find((r) => r.displayTitle === title && Date.parse(r.createdAt) >= since);
65382
65750
  }
65383
65751
  if (!candidate) throw new Error(`workflow dispatch outcome ambiguous for "${title}"; inspect Actions before retrying`);
@@ -65533,7 +65901,7 @@ function suiteTrainIo(root, summaryFile, memberSummaryFiles = {}, summaryFileTr,
65533
65901
  for (let i = 0; ; i++) {
65534
65902
  const pin = await openSuitePinPr({ root, run: (file, args, cwd) => exec(file, args, cwd, GIT_TIMEOUT_MS) }, { repo, tag, stage: "main" });
65535
65903
  if (pin.status !== "pending" || i >= 40) return pin;
65536
- await new Promise((resolve7) => setTimeout(resolve7, 3e4));
65904
+ await new Promise((resolve8) => setTimeout(resolve8, 3e4));
65537
65905
  }
65538
65906
  },
65539
65907
  suiteMapping: async (leadTag) => {
@@ -65548,9 +65916,9 @@ function suiteTrainIo(root, summaryFile, memberSummaryFiles = {}, summaryFileTr,
65548
65916
  const body = await gh(["release", "view", leadTag, "--repo", SUITE_REPO, "--json", "body", "--jq", ".body"]);
65549
65917
  if (parseSuiteMapping(body)) return;
65550
65918
  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}
65919
+ (0, import_node_fs55.mkdirSync)(dir, { recursive: true });
65920
+ const file = (0, import_node_path52.join)(dir, `notes-${leadTag}.md`);
65921
+ (0, import_node_fs55.writeFileSync)(file, `${body}
65554
65922
 
65555
65923
  ${suiteMappingBlock(leadTag, mapping)}`);
65556
65924
  await gh(["release", "edit", leadTag, "--repo", SUITE_REPO, "--notes-file", file]);
@@ -65591,7 +65959,7 @@ ${suiteMappingBlock(leadTag, mapping)}`);
65591
65959
 
65592
65960
  // src/suite-commands.ts
65593
65961
  init_cli_shared();
65594
- var import_node_fs55 = require("node:fs");
65962
+ var import_node_fs56 = require("node:fs");
65595
65963
  function parseMemberSummaryFiles(entries) {
65596
65964
  const memberSummaryFiles = {};
65597
65965
  for (const entry of entries) {
@@ -65615,7 +65983,7 @@ function suiteRcDataProdDeps() {
65615
65983
  const rc = facts.stages.rc;
65616
65984
  return rc?.present ? rc.substrate ?? "an unnamed substrate" : null;
65617
65985
  },
65618
- sleep: (ms) => new Promise((resolve7) => setTimeout(resolve7, ms))
65986
+ sleep: (ms) => new Promise((resolve8) => setTimeout(resolve8, ms))
65619
65987
  };
65620
65988
  }
65621
65989
  function registerSuiteCommands(program3) {
@@ -65685,7 +66053,7 @@ function registerSuiteCommands(program3) {
65685
66053
  try {
65686
66054
  const io = suiteTrainIo(root);
65687
66055
  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)) {
66056
+ if (retired && !(0, import_node_fs56.existsSync)(io.recordPath)) {
65689
66057
  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
66058
  return;
65691
66059
  }
@@ -65925,9 +66293,9 @@ function registerJevCommands(program3) {
65925
66293
 
65926
66294
  // src/packages-adopt-export.ts
65927
66295
  var import_node_child_process20 = require("node:child_process");
65928
- var import_node_fs56 = require("node:fs");
66296
+ var import_node_fs57 = require("node:fs");
65929
66297
  var import_node_os25 = require("node:os");
65930
- var import_node_path52 = require("node:path");
66298
+ var import_node_path53 = require("node:path");
65931
66299
  var import_node_util6 = require("node:util");
65932
66300
  init_cli_shared();
65933
66301
 
@@ -66547,38 +66915,38 @@ function expectedFromRun(run, opts) {
66547
66915
  }
66548
66916
  async function adoptExport(opts, deps) {
66549
66917
  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-"));
66918
+ const packagePath = (0, import_node_path53.join)(opts.dir, "package.json");
66919
+ const lockPath = (0, import_node_path53.join)(opts.dir, "package-lock.json");
66920
+ const packageText = (0, import_node_fs57.readFileSync)(packagePath, "utf8");
66921
+ const lockText = (0, import_node_fs57.readFileSync)(lockPath, "utf8");
66922
+ const work = (0, import_node_fs57.mkdtempSync)((0, import_node_path53.join)((0, import_node_os25.tmpdir)(), "mmi-adopt-export-"));
66555
66923
  try {
66556
66924
  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);
66925
+ (0, import_node_fs57.writeFileSync)((0, import_node_path53.join)(work, "expected.json"), JSON.stringify(expectedFromRun(run, opts)));
66926
+ (0, import_node_fs57.writeFileSync)((0, import_node_path53.join)(work, "provider.json"), await deps.ghApi(`repos/${EXPORT_REPO}/actions/artifacts/${opts.artifact}`));
66927
+ (0, import_node_fs57.writeFileSync)((0, import_node_path53.join)(work, "artifact.zip"), await deps.ghApi(`repos/${EXPORT_REPO}/actions/artifacts/${opts.artifact}/zip`));
66928
+ const script = (0, import_node_path53.join)(work, "package_export.py");
66929
+ (0, import_node_fs57.writeFileSync)(script, package_export_default);
66562
66930
  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"))]));
66931
+ const verified = (0, import_node_path53.join)(work, "verified");
66932
+ 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
66933
  const plan = planAdoption(packageText, lockText, metadata);
66566
66934
  for (const { name } of plan.result.adopted) {
66567
66935
  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);
66936
+ await deps.npm(["cache", "add", (0, import_node_path53.join)(verified, `${short3}.tgz`)], opts.dir);
66569
66937
  }
66570
- (0, import_node_fs56.writeFileSync)(packagePath, plan.packageText);
66571
- (0, import_node_fs56.writeFileSync)(lockPath, plan.lockText);
66938
+ (0, import_node_fs57.writeFileSync)(packagePath, plan.packageText);
66939
+ (0, import_node_fs57.writeFileSync)(lockPath, plan.lockText);
66572
66940
  try {
66573
66941
  await deps.npm(["ci", "--offline", "--ignore-scripts", "--no-audit", "--no-fund"], opts.dir);
66574
66942
  } catch (error) {
66575
- (0, import_node_fs56.writeFileSync)(packagePath, packageText);
66576
- (0, import_node_fs56.writeFileSync)(lockPath, lockText);
66943
+ (0, import_node_fs57.writeFileSync)(packagePath, packageText);
66944
+ (0, import_node_fs57.writeFileSync)(lockPath, lockText);
66577
66945
  throw new Error(`npm ci --offline failed, package.json and package-lock.json restored: ${error.message}`);
66578
66946
  }
66579
66947
  return plan.result;
66580
66948
  } finally {
66581
- (0, import_node_fs56.rmSync)(work, { recursive: true, force: true });
66949
+ (0, import_node_fs57.rmSync)(work, { recursive: true, force: true });
66582
66950
  }
66583
66951
  }
66584
66952
  var execFileBuffer = (0, import_node_util6.promisify)(import_node_child_process20.execFile);
@@ -66682,12 +67050,12 @@ function registerPackagesCommands(program3) {
66682
67050
  init_cli_shared();
66683
67051
 
66684
67052
  // src/wave-status.ts
66685
- var import_node_fs57 = require("node:fs");
67053
+ var import_node_fs58 = require("node:fs");
66686
67054
  function observeStage(worktreePath) {
66687
67055
  const statePath = stageStatePath(worktreePath);
66688
67056
  let raw;
66689
67057
  try {
66690
- raw = (0, import_node_fs57.readFileSync)(statePath, "utf8");
67058
+ raw = (0, import_node_fs58.readFileSync)(statePath, "utf8");
66691
67059
  } catch (error) {
66692
67060
  if (error.code === "ENOENT") return { state: "ok", value: { running: false } };
66693
67061
  return { state: "unavailable", reason: "stage state could not be read" };
@@ -66754,9 +67122,9 @@ async function collectWaveStatus(deps) {
66754
67122
  // src/discovery-commands.ts
66755
67123
  init_github_client();
66756
67124
  init_cli_shared();
66757
- var import_node_fs58 = require("node:fs");
67125
+ var import_node_fs59 = require("node:fs");
66758
67126
  var import_node_os26 = require("node:os");
66759
- var import_node_path53 = require("node:path");
67127
+ var import_node_path54 = require("node:path");
66760
67128
  var GC_GH_TIMEOUT_MS3 = 2e4;
66761
67129
  var defaultStatusDeps = {
66762
67130
  repo: resolveRepo,
@@ -66977,8 +67345,8 @@ async function collectOnboardStatus(opts = {}) {
66977
67345
  }
66978
67346
  const home = (0, import_node_os26.homedir)();
66979
67347
  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)
67348
+ readKnown: () => readFileSyncSafe((0, import_node_path54.join)(home, ...KNOWN_MARKETPLACES_RELATIVE), import_node_fs59.readFileSync),
67349
+ readSettings: () => readFileSyncSafe((0, import_node_path54.join)(home, ".claude", "settings.json"), import_node_fs59.readFileSync)
66982
67350
  });
66983
67351
  return {
66984
67352
  guide: "Read the MMI org-guide skill before project work; load only the relevant topic. Use mmi-help for a short introduction.",
@@ -68679,9 +69047,9 @@ function formatExplainGroup(cmd, rootName) {
68679
69047
  lines2.push(...formatOwnDetail(cmd));
68680
69048
  lines2.push("Commands:");
68681
69049
  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}]`;
69050
+ const args = child2.arguments.map((arg2) => {
69051
+ const name = arg2.variadic ? `${arg2.name}...` : arg2.name;
69052
+ return arg2.required ? `<${name}>` : `[${name}]`;
68685
69053
  }).join(" ");
68686
69054
  lines2.push(` ${canonical(child2)}${args ? ` ${args}` : ""}${child2.description ? ` \u2014 ${child2.description}` : ""}`);
68687
69055
  }
@@ -68702,11 +69070,11 @@ function briefCommand(cmd) {
68702
69070
  return {
68703
69071
  path: cmd.path,
68704
69072
  ...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 } : {}
69073
+ arguments: cmd.arguments.map((arg2) => ({
69074
+ name: arg2.name,
69075
+ required: arg2.required,
69076
+ ...arg2.variadic ? { variadic: true } : {},
69077
+ ...arg2.description ? { description: arg2.description } : {}
68710
69078
  })),
68711
69079
  options: ownOptions(cmd).map((opt) => ({
68712
69080
  flags: opt.flags,
@@ -68729,15 +69097,15 @@ function explainBriefManifest(manifest, command) {
68729
69097
  }
68730
69098
  function formatExplainBrief(cmd, rootName) {
68731
69099
  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}` : ""}`);
69100
+ for (const arg2 of cmd.arguments) {
69101
+ const flag = arg2.required ? `<${arg2.name}>` : `[${arg2.name}]`;
69102
+ lines2.push(` ${flag} ${arg2.required ? "required" : "optional"}${arg2.description ? ` ${arg2.description}` : ""}`);
68735
69103
  }
68736
69104
  for (const opt of ownOptions(cmd)) {
68737
69105
  lines2.push(` ${opt.flags} ${opt.takesValue ? "takes-value" : "flag"}${opt.mandatory ? " required" : ""}${opt.description ? ` ${opt.description}` : ""}`);
68738
69106
  }
68739
69107
  for (const child2 of cmd.subcommands) {
68740
- const args = child2.arguments.map((arg) => arg.required ? `<${arg.name}>` : `[${arg.name}]`).join(" ");
69108
+ const args = child2.arguments.map((arg2) => arg2.required ? `<${arg2.name}>` : `[${arg2.name}]`).join(" ");
68741
69109
  lines2.push(`${child2.path}${args ? ` ${args}` : ""}${child2.description ? ` \u2014 ${child2.description}` : ""}`);
68742
69110
  for (const opt of ownOptions(child2)) {
68743
69111
  lines2.push(` ${opt.flags} ${opt.takesValue ? "takes-value" : "flag"}${opt.mandatory ? " required" : ""}${opt.description ? ` ${opt.description}` : ""}`);
@@ -69644,8 +70012,8 @@ async function repoWorkflowEntries(client, repo) {
69644
70012
  for (const wf of workflowsList) {
69645
70013
  if (typeof wf?.path !== "string" || !wf.path) continue;
69646
70014
  if (!wf.path.startsWith(".github/workflows/")) continue;
69647
- const basename5 = wf.path.split("/").pop() ?? wf.path;
69648
- const name = `${repo}/${basename5.replace(/\.ya?ml$/, "")}`;
70015
+ const basename6 = wf.path.split("/").pop() ?? wf.path;
70016
+ const name = `${repo}/${basename6.replace(/\.ya?ml$/, "")}`;
69649
70017
  if (wf.state !== "active") {
69650
70018
  disabled.push(name);
69651
70019
  continue;
@@ -70109,8 +70477,8 @@ function registerSessionReport(program3) {
70109
70477
  }
70110
70478
 
70111
70479
  // src/stage-commands.ts
70112
- var import_node_fs59 = require("node:fs");
70113
- var import_node_path54 = require("node:path");
70480
+ var import_node_fs60 = require("node:fs");
70481
+ var import_node_path55 = require("node:path");
70114
70482
  init_cli_shared();
70115
70483
  init_clean_exit();
70116
70484
 
@@ -70358,8 +70726,8 @@ function registerStageCommands(program3) {
70358
70726
  const repo = Array.isArray(project2?.repos) && typeof project2.repos[0] === "string" ? project2.repos[0] : slug;
70359
70727
  const resolution = decideStage({
70360
70728
  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")),
70729
+ hasCompose: (0, import_node_fs60.existsSync)((0, import_node_path55.join)(process.cwd(), "docker-compose.yml")),
70730
+ hasEnvExample: (0, import_node_fs60.existsSync)((0, import_node_path55.join)(process.cwd(), ".env.example")),
70363
70731
  repo
70364
70732
  });
70365
70733
  if (resolution.source === "derived" && resolution.derived) {
@@ -70652,19 +71020,19 @@ vercel preview (${preview.branch}): ${d.state}${d.url ? ` \u2014 ${d.url}` : ""}
70652
71020
 
70653
71021
  // src/tenant-artifact.ts
70654
71022
  var import_node_crypto23 = require("node:crypto");
70655
- var import_node_fs60 = require("node:fs");
71023
+ var import_node_fs61 = require("node:fs");
70656
71024
  var import_promises11 = require("node:fs/promises");
70657
- var import_node_path55 = require("node:path");
71025
+ var import_node_path56 = require("node:path");
70658
71026
  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
71027
  var MAX_BYTES2 = 5 * 1024 * 1024 * 1024;
70660
71028
  async function sha256File(path2) {
70661
71029
  const hash = (0, import_node_crypto23.createHash)("sha256");
70662
- for await (const chunk of (0, import_node_fs60.createReadStream)(path2)) hash.update(chunk);
71030
+ for await (const chunk of (0, import_node_fs61.createReadStream)(path2)) hash.update(chunk);
70663
71031
  return hash.digest("hex");
70664
71032
  }
70665
71033
  async function putTenantArtifact(repo, stage, inputPath, deps) {
70666
71034
  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);
71035
+ const path2 = (0, import_node_path56.resolve)(inputPath);
70668
71036
  const info = await (0, import_promises11.stat)(path2);
70669
71037
  if (!info.isFile()) throw new Error("tenant artifact put: input path must be a file");
70670
71038
  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 +71050,7 @@ async function putTenantArtifact(repo, stage, inputPath, deps) {
70682
71050
  return [key, value];
70683
71051
  }));
70684
71052
  headers["content-length"] = String(info.size);
70685
- const stream = (0, import_node_fs60.createReadStream)(path2);
71053
+ const stream = (0, import_node_fs61.createReadStream)(path2);
70686
71054
  let uploaded;
70687
71055
  try {
70688
71056
  uploaded = await fetch(body.uploadUrl, {
@@ -71036,7 +71404,7 @@ function renderVerifySecrets(body) {
71036
71404
  }
71037
71405
 
71038
71406
  // src/command-register-developer.ts
71039
- var import_node_fs65 = require("node:fs");
71407
+ var import_node_fs66 = require("node:fs");
71040
71408
  init_clean_exit();
71041
71409
  init_cli_shared();
71042
71410
  init_error_codes();
@@ -71069,12 +71437,13 @@ async function resolveWhoami(deps) {
71069
71437
  }
71070
71438
 
71071
71439
  // src/command-register-developer.ts
71072
- var import_node_path62 = require("node:path");
71440
+ var import_node_path63 = require("node:path");
71073
71441
 
71074
71442
  // src/doc-refs-command-source.ts
71075
71443
  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");
71444
+ var import_node_fs62 = require("node:fs");
71445
+ var import_node_path57 = require("node:path");
71446
+ var IN_PROCESS_SOURCE = "in-process";
71078
71447
  var BUNDLE_MANIFEST_TIMEOUT_MS = 12e4;
71079
71448
  var BUNDLE_MANIFEST_MAX_BUFFER = 64 * 1024 * 1024;
71080
71449
  var flagsOf = (options) => new Set((options ?? []).flatMap((option) => String(option?.flags ?? "").match(/--[\w-]+/g) ?? []));
@@ -71095,7 +71464,7 @@ function inventoryFromManifest(manifest, source) {
71095
71464
  function readBundleManifest(bundle, exec3 = import_node_child_process21.execFileSync) {
71096
71465
  try {
71097
71466
  const text = exec3(process.execPath, [bundle, "commands", "--all", "--json"], {
71098
- cwd: (0, import_node_path56.dirname)(bundle),
71467
+ cwd: (0, import_node_path57.dirname)(bundle),
71099
71468
  encoding: "utf8",
71100
71469
  windowsHide: true,
71101
71470
  timeout: BUNDLE_MANIFEST_TIMEOUT_MS,
@@ -71110,20 +71479,29 @@ function readBundleManifest(bundle, exec3 = import_node_child_process21.execFile
71110
71479
  }
71111
71480
  function isRunningBundle(bundle, argv1 = process.argv[1], platform2 = process.platform) {
71112
71481
  if (!argv1) return false;
71113
- const norm2 = (path2) => {
71114
- const absolute = (0, import_node_path56.resolve)(path2);
71482
+ const norm3 = (path2) => {
71483
+ const absolute = (0, import_node_path57.resolve)(path2);
71115
71484
  return platform2 === "win32" ? absolute.toLowerCase() : absolute;
71116
71485
  };
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));
71486
+ const running = norm3(argv1);
71487
+ if (!["main.cjs", "index.cjs"].includes((0, import_node_path57.basename)(running))) return false;
71488
+ return (0, import_node_path57.dirname)(running) === (0, import_node_path57.dirname)(norm3(bundle));
71489
+ }
71490
+ function nameUnknownCommandSources(findings, source, root) {
71491
+ const checkoutBundle = (0, import_node_path57.resolve)(root, "cli", "dist", "main.cjs");
71492
+ 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>`" : "";
71493
+ for (const finding of findings) {
71494
+ if (finding.kind !== "unknown-command") continue;
71495
+ finding.commandSource = source;
71496
+ finding.detail += ` (source: ${source}${recovery})`;
71497
+ }
71120
71498
  }
71121
71499
  function resolveCommandInventory(deps) {
71122
- const exists = deps.exists ?? import_node_fs61.existsSync;
71500
+ const exists = deps.exists ?? import_node_fs62.existsSync;
71123
71501
  const read = deps.read ?? ((bundle) => readBundleManifest(bundle));
71124
71502
  const warnings = [];
71125
71503
  if (deps.from) {
71126
- const bundle = (0, import_node_path56.isAbsolute)(deps.from) ? deps.from : (0, import_node_path56.resolve)(deps.root, deps.from);
71504
+ const bundle = (0, import_node_path57.isAbsolute)(deps.from) ? deps.from : (0, import_node_path57.resolve)(deps.root, deps.from);
71127
71505
  if (!exists(bundle)) {
71128
71506
  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
71507
  }
@@ -71133,10 +71511,13 @@ function resolveCommandInventory(deps) {
71133
71511
  }
71134
71512
  return { inventory: inventory2, warnings };
71135
71513
  }
71136
- const treeBundle = (0, import_node_path56.join)(deps.root, "cli", "dist", "main.cjs");
71137
- if (!exists(treeBundle) || isRunningBundle(treeBundle, deps.argv1, deps.platform)) {
71514
+ const treeBundle = (0, import_node_path57.join)(deps.root, "cli", "dist", "main.cjs");
71515
+ if (!exists(treeBundle)) {
71138
71516
  return { inventory: deps.inProcess(), warnings };
71139
71517
  }
71518
+ if (isRunningBundle(treeBundle, deps.argv1, deps.platform)) {
71519
+ return { inventory: { ...deps.inProcess(), source: treeBundle }, warnings };
71520
+ }
71140
71521
  const inventory = inventoryFromManifest(read(treeBundle), treeBundle);
71141
71522
  if (!inventory) {
71142
71523
  warnings.push({
@@ -71251,19 +71632,19 @@ async function executeWaveLand(plan, deps) {
71251
71632
  // src/dist-drift.ts
71252
71633
  var import_node_child_process22 = require("node:child_process");
71253
71634
  var import_node_crypto25 = require("node:crypto");
71254
- var import_node_fs63 = require("node:fs");
71635
+ var import_node_fs64 = require("node:fs");
71255
71636
  var import_node_os27 = require("node:os");
71256
- var import_node_path58 = require("node:path");
71637
+ var import_node_path59 = require("node:path");
71257
71638
 
71258
71639
  // ../scripts/distribution-digest.mjs
71259
71640
  var import_node_crypto24 = require("node:crypto");
71260
- var import_node_fs62 = require("node:fs");
71261
- var import_node_path57 = require("node:path");
71641
+ var import_node_fs63 = require("node:fs");
71642
+ var import_node_path58 = require("node:path");
71262
71643
  var slash = (value) => value.replaceAll("\\", "/");
71263
71644
  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}`)) {
71645
+ const absoluteRoot = (0, import_node_path58.resolve)(root);
71646
+ const target = (0, import_node_path58.resolve)(root, declaredPath);
71647
+ if (target !== absoluteRoot && !target.startsWith(`${absoluteRoot}${import_node_path58.sep}`)) {
71267
71648
  throw new Error(`${label} ${declaredPath} escapes the repository root`);
71268
71649
  }
71269
71650
  return target;
@@ -71271,7 +71652,7 @@ function repoPath(root, declaredPath, label) {
71271
71652
  function digestFiles(files) {
71272
71653
  const hash = (0, import_node_crypto24.createHash)("sha256");
71273
71654
  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);
71655
+ const content = file.stat.isSymbolicLink() ? Buffer.from((0, import_node_fs63.readlinkSync)(file.absolute), "utf8") : (0, import_node_fs63.readFileSync)(file.absolute);
71275
71656
  hash.update(file.relative, "utf8");
71276
71657
  hash.update("\0");
71277
71658
  hash.update(file.stat.isSymbolicLink() ? "symlink" : "file", "utf8");
@@ -71286,8 +71667,8 @@ function digestFiles(files) {
71286
71667
  function digestPackedFiles(packageRoot, packedFiles) {
71287
71668
  return digestFiles(packedFiles.map((path2) => {
71288
71669
  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) };
71670
+ if (!(0, import_node_fs63.existsSync)(absolute)) throw new Error(`packed artifact identity path ${path2} does not exist`);
71671
+ return { absolute, relative: slash(path2), stat: (0, import_node_fs63.lstatSync)(absolute) };
71291
71672
  }));
71292
71673
  }
71293
71674
 
@@ -71372,13 +71753,13 @@ function renderDistDriftReceipt(receipt) {
71372
71753
  return lines2;
71373
71754
  }
71374
71755
  function readOrNull(path2) {
71375
- return (0, import_node_fs63.existsSync)(path2) ? (0, import_node_fs63.readFileSync)(path2) : null;
71756
+ return (0, import_node_fs64.existsSync)(path2) ? (0, import_node_fs64.readFileSync)(path2) : null;
71376
71757
  }
71377
71758
  function walkFiles(root) {
71378
71759
  const files = [];
71379
71760
  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);
71761
+ for (const entry of (0, import_node_fs64.readdirSync)(directory, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
71762
+ const child2 = (0, import_node_path59.join)(directory, entry.name);
71382
71763
  if (entry.isDirectory()) walk2(child2);
71383
71764
  else files.push(child2);
71384
71765
  }
@@ -71388,10 +71769,10 @@ function walkFiles(root) {
71388
71769
  }
71389
71770
  function bomPathFor(root) {
71390
71771
  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");
71772
+ const registry2 = JSON.parse((0, import_node_fs64.readFileSync)((0, import_node_path59.join)(root, "surfaces.json"), "utf8"));
71773
+ return (0, import_node_path59.join)(root, registry2?.sharedAgentCore?.releaseMetadata?.bomPath ?? "distribution-bom.json");
71393
71774
  } catch {
71394
- return (0, import_node_path58.join)(root, "distribution-bom.json");
71775
+ return (0, import_node_path59.join)(root, "distribution-bom.json");
71395
71776
  }
71396
71777
  }
71397
71778
  function rebuildTo(packageRoot, outDir) {
@@ -71404,40 +71785,40 @@ function rebuildTo(packageRoot, outDir) {
71404
71785
  });
71405
71786
  }
71406
71787
  function runDistStatus(root) {
71407
- const stage = (0, import_node_fs63.mkdtempSync)((0, import_node_path58.join)((0, import_node_os27.tmpdir)(), "mmi-dist-drift-"));
71788
+ const stage = (0, import_node_fs64.mkdtempSync)((0, import_node_path59.join)((0, import_node_os27.tmpdir)(), "mmi-dist-drift-"));
71408
71789
  let overlayCount = 0;
71409
71790
  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);
71791
+ const cliOut = (0, import_node_path59.join)(stage, "cli-dist");
71792
+ const hubOut = (0, import_node_path59.join)(stage, "hub-dist");
71793
+ rebuildTo((0, import_node_path59.join)(root, "cli"), cliOut);
71794
+ rebuildTo((0, import_node_path59.join)(root, "updater"), hubOut);
71414
71795
  const outDirFor = (packageDir) => packageDir === "cli" ? cliOut : hubOut;
71415
71796
  const rebuilt = (path2) => {
71416
71797
  const spec = DIST_ARTIFACTS.find((entry) => entry.path === path2);
71417
- return spec ? readOrNull((0, import_node_path58.join)(outDirFor(spec.packageDir), spec.output)) : null;
71798
+ return spec ? readOrNull((0, import_node_path59.join)(outDirFor(spec.packageDir), spec.output)) : null;
71418
71799
  };
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"));
71800
+ const committed = (path2) => readOrNull((0, import_node_path59.join)(root, path2));
71801
+ const tree = (path2) => readOrNull((0, import_node_path59.join)(root, path2));
71802
+ const distRoot = (0, import_node_path59.join)(root, "cli", "dist");
71803
+ const distTree = () => walkFiles(distRoot).map((absolute) => `cli/dist/${(0, import_node_path59.relative)(distRoot, absolute).replaceAll("\\", "/")}`);
71804
+ const bom = JSON.parse((0, import_node_fs64.readFileSync)(bomPathFor(root), "utf8"));
71424
71805
  const digest = (entries) => {
71425
- const overlay = (0, import_node_path58.join)(stage, `overlay-${overlayCount++}`);
71806
+ const overlay = (0, import_node_path59.join)(stage, `overlay-${overlayCount++}`);
71426
71807
  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);
71808
+ const target = (0, import_node_path59.join)(overlay, entry.path);
71809
+ (0, import_node_fs64.mkdirSync)((0, import_node_path59.dirname)(target), { recursive: true });
71810
+ (0, import_node_fs64.writeFileSync)(target, entry.bytes);
71430
71811
  }
71431
71812
  return digestPackedFiles(overlay, entries.map((entry) => entry.path));
71432
71813
  };
71433
71814
  return computeDistDriftReceipt({ committed, tree, rebuilt, distTree, bom, digest });
71434
71815
  } finally {
71435
- (0, import_node_fs63.rmSync)(stage, { recursive: true, force: true });
71816
+ (0, import_node_fs64.rmSync)(stage, { recursive: true, force: true });
71436
71817
  }
71437
71818
  }
71438
71819
 
71439
71820
  // src/doc-refs-live.ts
71440
- var import_node_path59 = require("node:path");
71821
+ var import_node_path60 = require("node:path");
71441
71822
  var concrete = (value) => !!value && !/[<>{}$]/.test(value);
71442
71823
  var liveOption = (tokens2, flag) => {
71443
71824
  const index = tokens2.indexOf(flag);
@@ -71510,7 +71891,7 @@ async function runLiveDocRefs(root, deps, live) {
71510
71891
  const offline = runDocRefs(root, { ...deps, runbooksOnly: true });
71511
71892
  const read = deps.readFile ?? readFileOrNull;
71512
71893
  const docs = Object.fromEntries((deps.listDocs ?? defaultListDocs)(root).flatMap((doc) => {
71513
- const body = read((0, import_node_path59.join)(root, doc));
71894
+ const body = read((0, import_node_path60.join)(root, doc));
71514
71895
  return body !== null && isRunbook(doc, body) && !deps.isIgnored?.([doc]).has(doc) ? [[doc, body]] : [];
71515
71896
  }));
71516
71897
  const remote = await checkRunbookLive(docs, live);
@@ -71547,7 +71928,7 @@ function createRunbookLiveDeps(cliBin) {
71547
71928
  };
71548
71929
  const first = await probe().catch(() => 599);
71549
71930
  if (first < 500) return first;
71550
- await new Promise((resolve7) => setTimeout(resolve7, 2e4));
71931
+ await new Promise((resolve8) => setTimeout(resolve8, 2e4));
71551
71932
  return probe();
71552
71933
  }
71553
71934
  };
@@ -71721,7 +72102,7 @@ async function diagnoseHub(deps) {
71721
72102
 
71722
72103
  // src/schedules-lift-command.ts
71723
72104
  var import_promises12 = require("node:fs/promises");
71724
- var import_node_path60 = require("node:path");
72105
+ var import_node_path61 = require("node:path");
71725
72106
  init_clean_exit();
71726
72107
  init_cli_shared();
71727
72108
  var DEFAULT_WORKFLOWS_DIR = ".github/workflows";
@@ -71750,7 +72131,7 @@ async function readWorkflowFiles(dir) {
71750
72131
  const files = [];
71751
72132
  for (const name of names.sort()) {
71752
72133
  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") });
72134
+ files.push({ path: `.github/workflows/${name}`, text: await (0, import_promises12.readFile)((0, import_node_path61.join)(dir, name), "utf8") });
71754
72135
  }
71755
72136
  return files;
71756
72137
  }
@@ -71833,8 +72214,8 @@ function registerSchedulesLiftCommand(program3, deps = {}) {
71833
72214
 
71834
72215
  // src/spawn-policy-core.ts
71835
72216
  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");
72217
+ var import_node_fs65 = require("node:fs");
72218
+ var import_node_path62 = require("node:path");
71838
72219
  var SPAWNERS = ["spawn", "spawnSync", "exec", "execSync", "execFile", "execFileSync"];
71839
72220
  var CALL_SOURCE = String.raw`(^|[^.\w$])(${SPAWNERS.join("|")})\s*\(`;
71840
72221
  var SOURCE_EXT = /\.(ts|mts|cts|js|mjs|cjs)$/;
@@ -71920,7 +72301,7 @@ function runSpawnPolicy(root) {
71920
72301
  for (const file of files) {
71921
72302
  let raw;
71922
72303
  try {
71923
- raw = (0, import_node_fs64.readFileSync)((0, import_node_path61.join)(root, file), "utf8");
72304
+ raw = (0, import_node_fs65.readFileSync)((0, import_node_path62.join)(root, file), "utf8");
71924
72305
  } catch {
71925
72306
  continue;
71926
72307
  }
@@ -71940,19 +72321,19 @@ function runSpawnPolicy(root) {
71940
72321
  function registerDeveloperCommands(program3) {
71941
72322
  const rules = program3.command("rules").description("org-managed .gitignore delivery");
71942
72323
  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;
72324
+ const path2 = (0, import_node_path63.join)(process.cwd(), ".gitignore");
72325
+ const current = (0, import_node_fs66.existsSync)(path2) ? (0, import_node_fs66.readFileSync)(path2, "utf8") : null;
71945
72326
  const plan = planManagedGitignore(current);
71946
72327
  const drift = [...plan.added.map((l) => `+${l}`), ...plan.removed.map((l) => `-${l}`)].join(", ") || "block normalize";
71947
72328
  if (opts.json) {
71948
- if (opts.write && plan.changed) (0, import_node_fs65.writeFileSync)(path2, plan.content, "utf8");
72329
+ if (opts.write && plan.changed) (0, import_node_fs66.writeFileSync)(path2, plan.content, "utf8");
71949
72330
  console.log(JSON.stringify(plan, null, 2));
71950
72331
  if (!opts.write && plan.changed) process.exitCode = 1;
71951
72332
  return;
71952
72333
  }
71953
72334
  if (opts.write) {
71954
72335
  if (plan.changed) {
71955
- (0, import_node_fs65.writeFileSync)(path2, plan.content, "utf8");
72336
+ (0, import_node_fs66.writeFileSync)(path2, plan.content, "utf8");
71956
72337
  console.log(`mmi-cli devops org rules gitignore: updated .gitignore (${drift})`);
71957
72338
  } else {
71958
72339
  console.log("mmi-cli devops org rules gitignore: up to date");
@@ -72148,6 +72529,7 @@ function registerDeveloperCommands(program3) {
72148
72529
  const deps = { commandPaths, commandOptions, commandSource: source, base: o.base, runbooksOnly: o.runbooksOnly };
72149
72530
  const result = o.live ? await runLiveDocRefs(root, deps, createRunbookLiveDeps(process.argv[1])) : runDocRefs(root, deps);
72150
72531
  result.warnings.push(...resolved.warnings);
72532
+ nameUnknownCommandSources(result.findings, source, root);
72151
72533
  if (o.json) {
72152
72534
  consoleIo.log(JSON.stringify({ ok: result.ok, docCount: result.docCount, findings: result.findings, warnings: result.warnings }, null, 2));
72153
72535
  if (!result.ok) process.exitCode = 1;
@@ -72269,7 +72651,7 @@ ${r.stderr ?? ""}`).catch(() => "");
72269
72651
  var ENV_HEAL_LOCK_STALE_MS = 10 * 6e4;
72270
72652
  var ENV_HEAL_LOCK_MAX_WAIT_MS = 2 * 6e4;
72271
72653
  function envHealLockPath(home) {
72272
- return (0, import_node_path63.join)(home, ".claude", "plugins", ".mmi-env-heal.lock");
72654
+ return (0, import_node_path64.join)(home, ".claude", "plugins", ".mmi-env-heal.lock");
72273
72655
  }
72274
72656
  async function withEnvHealLock(what, run) {
72275
72657
  try {
@@ -72407,7 +72789,7 @@ function mmiDoctorDeps(opts = {}) {
72407
72789
  );
72408
72790
  const result = applyPluginCachePlan(
72409
72791
  plan,
72410
- (p) => (0, import_node_fs66.rmSync)(p, { recursive: true }),
72792
+ (p) => (0, import_node_fs67.rmSync)(p, { recursive: true }),
72411
72793
  stagingApplyFsGuard(configRoot)
72412
72794
  );
72413
72795
  return {
@@ -72442,7 +72824,7 @@ function mmiDoctorDeps(opts = {}) {
72442
72824
  // has no generated routing index would
72443
72825
  // get a permanent — demanding an artifact it never asked for.
72444
72826
  docsIndexState: (root) => {
72445
- if (!(0, import_node_fs66.existsSync)((0, import_node_path63.join)(root, DOCS_INDEX_PATH))) return void 0;
72827
+ if (!(0, import_node_fs67.existsSync)((0, import_node_path64.join)(root, DOCS_INDEX_PATH))) return void 0;
72446
72828
  const real = createDocsIndexDeps(root);
72447
72829
  let docs;
72448
72830
  const listDocs = () => docs ??= real.listDocs();
@@ -72451,7 +72833,7 @@ function mmiDoctorDeps(opts = {}) {
72451
72833
  },
72452
72834
  // #4168: working-tree heal — write if drifted, then re-check. Commit remains the operator's step.
72453
72835
  healDocsIndex: (root) => {
72454
- if (!(0, import_node_fs66.existsSync)((0, import_node_path63.join)(root, DOCS_INDEX_PATH))) return { drift: false, docCount: 0 };
72836
+ if (!(0, import_node_fs67.existsSync)((0, import_node_path64.join)(root, DOCS_INDEX_PATH))) return { drift: false, docCount: 0 };
72455
72837
  const real = createDocsIndexDeps(root);
72456
72838
  let docs;
72457
72839
  const listDocs = () => docs ??= real.listDocs();
@@ -72472,8 +72854,8 @@ function mmiDoctorDeps(opts = {}) {
72472
72854
  });
72473
72855
  const raced = await Promise.race([
72474
72856
  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);
72857
+ new Promise((resolve8) => {
72858
+ ceiling = setTimeout(() => resolve8({ timedOut: true, scanned: 0, findings: 0, fixed: 0, failed: 0 }), BOARD_DOCTOR_TIMEOUT_MS);
72477
72859
  })
72478
72860
  ]);
72479
72861
  if (raced.timedOut) return { scanned: 0, findings: 0, fixed: 0, failed: 0, timedOut: true };
@@ -72506,8 +72888,8 @@ function mmiDoctorDeps(opts = {}) {
72506
72888
  incomplete: nb.incomplete,
72507
72889
  timedOut: false
72508
72890
  })),
72509
- new Promise((resolve7) => {
72510
- ceiling = setTimeout(() => resolve7({ driftLines: [], incomplete: [], timedOut: true }), SCHEDULES_DRIFT_TIMEOUT_MS);
72891
+ new Promise((resolve8) => {
72892
+ ceiling = setTimeout(() => resolve8({ driftLines: [], incomplete: [], timedOut: true }), SCHEDULES_DRIFT_TIMEOUT_MS);
72511
72893
  })
72512
72894
  ]);
72513
72895
  if (!raced.timedOut && raced.incomplete.length === 0) writeSchedulesDriftCache(cachePath, raced.driftLines);
@@ -72991,10 +73373,10 @@ tenant.command("logs <owner/repo> <stage>").description("READ-ONLY: read a tenan
72991
73373
  return failGraceful(`runtime tenant logs: ${e.message}`);
72992
73374
  }
72993
73375
  });
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) => {
73376
+ 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
73377
  if (stage !== "dev" && stage !== "rc" && stage !== "main") return fail("runtime tenant redeploy: <stage> must be dev, rc, or main");
72996
73378
  try {
72997
- const raw = await runTenantRedeploy(trainApplyDeps(), { repo, stage, ref: o.ref, watch: o.watch });
73379
+ const raw = await runTenantRedeploy(trainApplyDeps(), { repo, stage, ref: o.ref, rollback: o.rollback, watch: o.watch });
72998
73380
  const result = raw.workflowRuns ? { ...raw, workflowRuns: raw.workflowRuns.map(workflowRunWithEvidence) } : raw;
72999
73381
  return printLine(o.json ? JSON.stringify(result, null, 2) : renderTenantRedeploy(result));
73000
73382
  } catch (e) {
@@ -73254,7 +73636,7 @@ project.command("set [owner/repo]").description("upsert project META (idempotent
73254
73636
  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
73637
  if (o.secretsFile) {
73256
73638
  try {
73257
- vars.push(`secrets=${(0, import_node_fs66.readFileSync)(o.secretsFile, "utf8")}`);
73639
+ vars.push(`secrets=${(0, import_node_fs67.readFileSync)(o.secretsFile, "utf8")}`);
73258
73640
  } catch (e) {
73259
73641
  return fail(`org project set: cannot read --secrets-file ${o.secretsFile}: ${e.message}`);
73260
73642
  }
@@ -73388,7 +73770,7 @@ fullTrack.command("readiness <owner/repo>").description("aggregate branch topolo
73388
73770
  const cfg = await loadConfig();
73389
73771
  const reg = registryClientDeps(cfg);
73390
73772
  const slug = slugOf(repo);
73391
- const [metaRead, deployFacts, authority, dev, rc, main] = await Promise.all([
73773
+ const [metaRead, deployFacts, authority, dev, rc, main2] = await Promise.all([
73392
73774
  fetchProjectBySlugChecked(slug, reg),
73393
73775
  fetchDeployFactsBySlug(slug, reg),
73394
73776
  fetchTrainAuthority(repo, reg),
@@ -73403,7 +73785,7 @@ fullTrack.command("readiness <owner/repo>").description("aggregate branch topolo
73403
73785
  meta: metaRead.project,
73404
73786
  deployFacts,
73405
73787
  trainAuthority: authority.ok ? authority.authority : void 0,
73406
- runtime: { dev, rc, main }
73788
+ runtime: { dev, rc, main: main2 }
73407
73789
  });
73408
73790
  console.log(JSON.stringify(report, null, 2));
73409
73791
  if (!report.rcand.canApply) process.exitCode = 1;
@@ -73646,16 +74028,16 @@ function ciAuditDeps2() {
73646
74028
  // gate re-seed step is skipped gracefully rather than failing mid-run.
73647
74029
  readSeedFile: (path2) => {
73648
74030
  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;
74031
+ const fullPath = (0, import_node_path64.join)(root, path2);
74032
+ return (0, import_node_fs67.existsSync)(fullPath) ? (0, import_node_fs67.readFileSync)(fullPath, "utf8") : null;
73651
74033
  }
73652
74034
  };
73653
74035
  }
73654
74036
  function hubRoot2() {
73655
- const fromPkg = (0, import_node_path63.join)(__dirname, "..", "..");
74037
+ const fromPkg = (0, import_node_path64.join)(__dirname, "..", "..");
73656
74038
  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();
74039
+ if ((0, import_node_fs67.existsSync)((0, import_node_path64.join)(fromPkg, marker))) return fromPkg;
74040
+ if ((0, import_node_fs67.existsSync)((0, import_node_path64.join)(process.cwd(), marker))) return process.cwd();
73659
74041
  return null;
73660
74042
  }
73661
74043
  registerQueryCommands(program2);
@@ -73812,10 +74194,10 @@ access.command("audit").description("audit collaborator roles + train-branch pus
73812
74194
  targets = resolution.targets;
73813
74195
  }
73814
74196
  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")) : {};
74197
+ const fileMatrix = (0, import_node_fs67.existsSync)("access-matrix.json") ? loadAccessMatrix((0, import_node_fs67.readFileSync)("access-matrix.json", "utf8")) : {};
73816
74198
  const matrix = mergeAccessMatrix(fileMatrix, derivedMatrix);
73817
74199
  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")) : {};
74200
+ const sanctioned = (0, import_node_fs67.existsSync)("access-matrix.json") ? loadSanctionedAdmins((0, import_node_fs67.readFileSync)("access-matrix.json", "utf8")) : {};
73819
74201
  const report = await auditOrgAccess(targets, deps, matrix, dataAccess, sanctioned);
73820
74202
  console.log(o.json ? JSON.stringify(report, null, 2) : renderAccessReport(report));
73821
74203
  if (!report.ok) process.exitCode = 1;
@@ -73852,16 +74234,16 @@ function directoryBytes(path2) {
73852
74234
  let total = 0;
73853
74235
  let entries;
73854
74236
  try {
73855
- entries = (0, import_node_fs66.readdirSync)(path2, { withFileTypes: true });
74237
+ entries = (0, import_node_fs67.readdirSync)(path2, { withFileTypes: true });
73856
74238
  } catch {
73857
74239
  return 0;
73858
74240
  }
73859
74241
  for (const entry of entries) {
73860
- const child2 = (0, import_node_path63.join)(path2, entry.name);
74242
+ const child2 = (0, import_node_path64.join)(path2, entry.name);
73861
74243
  if (entry.isDirectory()) total += directoryBytes(child2);
73862
74244
  else {
73863
74245
  try {
73864
- total += (0, import_node_fs66.statSync)(child2).size;
74246
+ total += (0, import_node_fs67.statSync)(child2).size;
73865
74247
  } catch {
73866
74248
  }
73867
74249
  }
@@ -73869,25 +74251,25 @@ function directoryBytes(path2) {
73869
74251
  return total;
73870
74252
  }
73871
74253
  function listDirEntries(dir) {
73872
- return (0, import_node_fs66.readdirSync)(dir, { withFileTypes: true }).map((d) => ({ name: d.name, isDirectory: d.isDirectory() }));
74254
+ return (0, import_node_fs67.readdirSync)(dir, { withFileTypes: true }).map((d) => ({ name: d.name, isDirectory: d.isDirectory() }));
73873
74255
  }
73874
74256
  function readInstalledPluginRefs(configRoot) {
73875
74257
  const p = installedPluginsPathForConfig(configRoot);
73876
- if (!(0, import_node_fs66.existsSync)(p)) return [];
74258
+ if (!(0, import_node_fs67.existsSync)(p)) return [];
73877
74259
  try {
73878
- return installedPluginPaths((0, import_node_fs66.readFileSync)(p, "utf8"));
74260
+ return installedPluginPaths((0, import_node_fs67.readFileSync)(p, "utf8"));
73879
74261
  } catch {
73880
74262
  return null;
73881
74263
  }
73882
74264
  }
73883
74265
  function pluginCacheFsDeps(configRoot, dirBytes) {
73884
74266
  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),
74267
+ exists: (p) => (0, import_node_fs67.existsSync)(p),
74268
+ listVersionDirs: (root) => (0, import_node_fs67.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name),
73887
74269
  dirBytes,
73888
- listStagingDirs: (root) => (0, import_node_fs66.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => {
74270
+ listStagingDirs: (root) => (0, import_node_fs67.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => {
73889
74271
  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) };
74272
+ return { name: d.name, mtimeMs: newestMtimeMs((0, import_node_path64.join)(root, d.name), listDirEntries, (p) => (0, import_node_fs67.statSync)(p).mtimeMs) };
73891
74273
  } catch {
73892
74274
  return { name: d.name, mtimeMs: Date.now() };
73893
74275
  }
@@ -73901,10 +74283,10 @@ function stagingApplyFsGuard(configRoot) {
73901
74283
  return {
73902
74284
  referencedPaths: () => readInstalledPluginRefs(configRoot),
73903
74285
  mtimeMs: (name) => {
73904
- const p = (0, import_node_path63.join)(stagingRoot, name);
73905
- if (!(0, import_node_fs66.existsSync)(p)) return null;
74286
+ const p = (0, import_node_path64.join)(stagingRoot, name);
74287
+ if (!(0, import_node_fs67.existsSync)(p)) return null;
73906
74288
  try {
73907
- return newestMtimeMs(p, listDirEntries, (q) => (0, import_node_fs66.statSync)(q).mtimeMs);
74289
+ return newestMtimeMs(p, listDirEntries, (q) => (0, import_node_fs67.statSync)(q).mtimeMs);
73908
74290
  } catch {
73909
74291
  return null;
73910
74292
  }
@@ -73930,7 +74312,7 @@ program2.command("plugin-prune").description(`prune stale cached MMI plugin vers
73930
74312
  { withBytes: true, configRoot, includeStaging: surface !== "codex" }
73931
74313
  );
73932
74314
  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;
74315
+ const result = o.apply && anythingToDelete ? applyPluginCachePlan(plan, (p) => (0, import_node_fs67.rmSync)(p, { recursive: true, force: true }), stagingApplyFsGuard(configRoot)) : void 0;
73934
74316
  const warnings = plan.prune.length > 0 ? [CONCURRENT_SESSION_WARNING] : [];
73935
74317
  if (o.json) console.log(JSON.stringify({ ...plan, warnings, applied: result ?? null }));
73936
74318
  else console.log(renderPluginCachePlan(plan, result));
@@ -73940,7 +74322,7 @@ program2.command("archive-prune").description("inventory worktree evidence archi
73940
74322
  let primary = o.repoRoot;
73941
74323
  if (!primary) {
73942
74324
  const common = await gitOut(["rev-parse", "--path-format=absolute", "--git-common-dir"]);
73943
- primary = common ? (0, import_node_path63.dirname)(common) : "";
74325
+ primary = common ? (0, import_node_path64.dirname)(common) : "";
73944
74326
  }
73945
74327
  if (!primary) {
73946
74328
  const detail = "archive-prune: not inside a git checkout (pass --repo-root <primary checkout>)";