@mutmutco/claude-plugin 4.5.228 → 4.5.229

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
@@ -13472,7 +13472,7 @@ function useColor() {
13472
13472
  var program = new Command();
13473
13473
 
13474
13474
  // src/command-composition.ts
13475
- var import_node_fs60 = require("node:fs");
13475
+ var import_node_fs61 = require("node:fs");
13476
13476
  init_clean_exit();
13477
13477
  init_cli_shared();
13478
13478
 
@@ -27210,10 +27210,10 @@ var rollout_plan_default = {
27210
27210
  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)."
27211
27211
  },
27212
27212
  baseline: {
27213
- version: "4.5.228",
27214
- tag: "v4.5.228",
27215
- commit: "097f7c9ad0e0",
27216
- npm: "@mutmutco/cli@4.5.228"
27213
+ version: "4.5.229",
27214
+ tag: "v4.5.229",
27215
+ commit: "15792605c6d9",
27216
+ npm: "@mutmutco/cli@4.5.229"
27217
27217
  },
27218
27218
  exitCriterion: "fleet-n-of-n",
27219
27219
  hubOnlyShortcut: "forbidden",
@@ -27230,14 +27230,14 @@ var rollout_plan_default = {
27230
27230
  repo: "mutmutco/mmi-hub",
27231
27231
  role: "canary",
27232
27232
  schedule: "train",
27233
- v3Target: "v4.5.228"
27233
+ v3Target: "v4.5.229"
27234
27234
  }
27235
27235
  ],
27236
27236
  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.",
27237
27237
  rollback: {
27238
27238
  independent: true,
27239
- mechanism: "npm dist-tag latest -> 4.5.228 and redeploy the Hub Lambda from tag v4.5.228 (097f7c9ad0e0); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
27240
- v3Target: "v4.5.228 (@mutmutco/cli@4.5.228, tag commit 097f7c9ad0e0 \u2014 last known-good release carrying the repo-index v4-only contract)"
27239
+ mechanism: "npm dist-tag latest -> 4.5.229 and redeploy the Hub Lambda from tag v4.5.229 (15792605c6d9); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
27240
+ v3Target: "v4.5.229 (@mutmutco/cli@4.5.229, tag commit 15792605c6d9 \u2014 last known-good release carrying the repo-index v4-only contract)"
27241
27241
  }
27242
27242
  },
27243
27243
  {
@@ -31784,7 +31784,7 @@ function renderTenantControl(r) {
31784
31784
  }
31785
31785
 
31786
31786
  // src/train-apply-phases.ts
31787
- var import_node_fs30 = require("node:fs");
31787
+ var import_node_fs31 = require("node:fs");
31788
31788
  var import_promises4 = require("node:fs/promises");
31789
31789
  var import_node_path28 = require("node:path");
31790
31790
 
@@ -32092,6 +32092,71 @@ Resume it: ${resumeCommand}
32092
32092
  );
32093
32093
  }
32094
32094
 
32095
+ // src/train-apply-pretag-hook.ts
32096
+ var import_node_fs25 = require("node:fs");
32097
+ var PRETAG_SCRIPT = "release:pretag";
32098
+ var PRETAG_TAIL_LINES = 40;
32099
+ function declaredScripts() {
32100
+ try {
32101
+ const parsed = JSON.parse((0, import_node_fs25.readFileSync)("package.json", "utf8"));
32102
+ return parsed.scripts ?? {};
32103
+ } catch {
32104
+ return null;
32105
+ }
32106
+ }
32107
+ function outputTail(error) {
32108
+ const e = error;
32109
+ const streams = [e?.stdout, e?.stderr].filter((s) => typeof s === "string" && s.trim() !== "");
32110
+ const text = streams.length > 0 ? streams.join("\n") : error instanceof Error ? error.message : String(error);
32111
+ const lines2 = text.replace(/\r\n/g, "\n").trimEnd().split("\n");
32112
+ return lines2.slice(-PRETAG_TAIL_LINES).join("\n");
32113
+ }
32114
+ function porcelainPaths(output) {
32115
+ return output.split("\n").map((line) => line.trimEnd()).filter(Boolean).map((line) => line.slice(3).trim().replace(/^"|"$/g, "").replaceAll("\\", "/"));
32116
+ }
32117
+ async function runPreTagHook(deps, input) {
32118
+ const command = `npm run ${PRETAG_SCRIPT}`;
32119
+ const shortSha = input.releaseSha.slice(0, 12);
32120
+ const scripts = declaredScripts();
32121
+ if (!scripts || !String(scripts[PRETAG_SCRIPT] ?? "").trim()) {
32122
+ const note = `no \`${PRETAG_SCRIPT}\` script in the repo's package.json: this release's refusable checks run only in CI, AFTER the tag is pushed \u2014 a late failure then leaves a public tag (and Release) on a version that never shipped (#9189). Declare "${PRETAG_SCRIPT}": "<the checks your publish/Release has refused before>" so the train can refuse before anything reaches origin.`;
32123
+ deps.warn?.(`Release: ${note}`);
32124
+ return { status: "missing", command, note };
32125
+ }
32126
+ const headBefore = clean2(await deps.run("git", ["rev-parse", "HEAD"]));
32127
+ if (headBefore !== input.releaseSha) {
32128
+ throw new Error(
32129
+ `pre-tag checks refused: the checkout is on ${headBefore.slice(0, 12)}, not the folded release commit ${shortSha} \u2014 \`${command}\` must prove the exact commit the tag would make immutable (#9189). Nothing was tagged, main was not pushed and no GitHub Release exists.`
32130
+ );
32131
+ }
32132
+ deps.warn?.(`Release: Running the repo's pre-tag checks (${command})`);
32133
+ try {
32134
+ await deps.run("npm", ["run", PRETAG_SCRIPT]);
32135
+ } catch (e) {
32136
+ throw new Error(
32137
+ `pre-tag checks refused: \`${command}\` failed on the folded release commit ${shortSha} \u2014 nothing was tagged, main was not pushed and no GitHub Release exists (#9189).
32138
+
32139
+ --- ${command} output (tail) ---
32140
+ ${outputTail(e)}
32141
+ --- end of ${command} output ---
32142
+ Remedy: fix the failing check in the release fold (or in the repo) and rerun the release. Never tag around it \u2014 the same check runs again on the v* tag, after the tag is public and un-removable without deleting a release.`
32143
+ );
32144
+ }
32145
+ const headAfter = clean2(await deps.run("git", ["rev-parse", "HEAD"]));
32146
+ if (headAfter !== input.releaseSha) {
32147
+ throw new Error(
32148
+ `pre-tag checks refused: \`${command}\` moved the checkout to ${headAfter.slice(0, 12)} (the release commit is ${shortSha}) \u2014 the hook must VERIFY the committed release bytes, never commit or check out. Anything it changed would ship unverified (#9189). Nothing was tagged, main was not pushed and no GitHub Release exists.`
32149
+ );
32150
+ }
32151
+ const dirty = porcelainPaths(await deps.run("git", ["status", "--porcelain=v1", "--untracked-files=no"]));
32152
+ if (dirty.length > 0) {
32153
+ throw new Error(
32154
+ `pre-tag checks refused: \`${command}\` modified tracked file(s) in the release checkout \u2014 ${dirty.join(", ")}. The train tags the COMMITTED fold commit, so an uncommitted regeneration would never ship and the check that produced it proves nothing (#9189). Commit the regenerated file into the fold (or make the hook read-only) and rerun: nothing was tagged, main was not pushed and no GitHub Release exists.`
32155
+ );
32156
+ }
32157
+ return { status: "passed", command, note: `\`${command}\` passed on ${shortSha} before the tag` };
32158
+ }
32159
+
32095
32160
  // src/pre-one-zero.ts
32096
32161
  function preOneZeroInForce(meta) {
32097
32162
  return !!meta?.suite && meta.preOneZero !== false;
@@ -32114,12 +32179,12 @@ function assertPreOneZero(repo, meta, tag) {
32114
32179
 
32115
32180
  // src/train-doctor.ts
32116
32181
  var import_node_child_process9 = require("node:child_process");
32117
- var import_node_fs28 = require("node:fs");
32182
+ var import_node_fs29 = require("node:fs");
32118
32183
  var import_node_os16 = require("node:os");
32119
32184
  var import_node_path27 = require("node:path");
32120
32185
 
32121
32186
  // src/doctor-io.ts
32122
- var import_node_fs25 = require("node:fs");
32187
+ var import_node_fs26 = require("node:fs");
32123
32188
  var import_node_os13 = require("node:os");
32124
32189
  var import_node_path22 = require("node:path");
32125
32190
  var import_node_child_process7 = require("node:child_process");
@@ -32134,8 +32199,8 @@ function nodeDiscardSinkPath(platform2 = process.platform) {
32134
32199
  var execFileP2 = (0, import_node_util4.promisify)(import_node_child_process7.execFile);
32135
32200
  function execFileCapture(file, args, opts = {}) {
32136
32201
  const sink = nodeDiscardSinkPath();
32137
- const inFd = (0, import_node_fs25.openSync)(sink, "r");
32138
- const errFd = (0, import_node_fs25.openSync)(sink, "w");
32202
+ const inFd = (0, import_node_fs26.openSync)(sink, "r");
32203
+ const errFd = (0, import_node_fs26.openSync)(sink, "w");
32139
32204
  try {
32140
32205
  return (0, import_node_child_process7.execFileSync)(file, args, {
32141
32206
  ...opts,
@@ -32143,17 +32208,17 @@ function execFileCapture(file, args, opts = {}) {
32143
32208
  stdio: [inFd, "pipe", errFd]
32144
32209
  });
32145
32210
  } finally {
32146
- (0, import_node_fs25.closeSync)(inFd);
32147
- (0, import_node_fs25.closeSync)(errFd);
32211
+ (0, import_node_fs26.closeSync)(inFd);
32212
+ (0, import_node_fs26.closeSync)(errFd);
32148
32213
  }
32149
32214
  }
32150
32215
  var MMI_PLUGIN_ID2 = "mmi@mutmutco";
32151
32216
  function stagedClaudePluginVersion() {
32152
32217
  try {
32153
32218
  const stagingRoot = (0, import_node_path22.join)((0, import_node_os13.homedir)(), ".claude", "plugins", "staging");
32154
- const record2 = JSON.parse((0, import_node_fs25.readFileSync)((0, import_node_path22.join)(stagingRoot, "launch-target.json"), "utf8"));
32219
+ const record2 = JSON.parse((0, import_node_fs26.readFileSync)((0, import_node_path22.join)(stagingRoot, "launch-target.json"), "utf8"));
32155
32220
  if (typeof record2.target !== "string" || typeof record2.incoming !== "string") return void 0;
32156
- const manifest = JSON.parse((0, import_node_fs25.readFileSync)((0, import_node_path22.join)(record2.incoming, ".claude-plugin", "plugin.json"), "utf8"));
32221
+ const manifest = JSON.parse((0, import_node_fs26.readFileSync)((0, import_node_path22.join)(record2.incoming, ".claude-plugin", "plugin.json"), "utf8"));
32157
32222
  if (typeof manifest.version !== "string") return void 0;
32158
32223
  return manifest.version === record2.target ? record2.target : void 0;
32159
32224
  } catch {
@@ -32163,7 +32228,7 @@ function stagedClaudePluginVersion() {
32163
32228
  function installedClaudePluginVersion() {
32164
32229
  try {
32165
32230
  const file = JSON.parse(
32166
- (0, import_node_fs25.readFileSync)((0, import_node_path22.join)((0, import_node_os13.homedir)(), ".claude", "plugins", "installed_plugins.json"), "utf8")
32231
+ (0, import_node_fs26.readFileSync)((0, import_node_path22.join)((0, import_node_os13.homedir)(), ".claude", "plugins", "installed_plugins.json"), "utf8")
32167
32232
  );
32168
32233
  const versions = (file.plugins?.[MMI_PLUGIN_ID2] ?? []).map((r) => r.version).filter((v) => Boolean(v));
32169
32234
  if (versions.length === 0) return void 0;
@@ -32231,7 +32296,7 @@ function readGitignore() {
32231
32296
  const path2 = gitignorePath();
32232
32297
  if (path2 === null) return null;
32233
32298
  try {
32234
- return (0, import_node_fs25.readFileSync)(path2, "utf8");
32299
+ return (0, import_node_fs26.readFileSync)(path2, "utf8");
32235
32300
  } catch {
32236
32301
  return null;
32237
32302
  }
@@ -32240,14 +32305,14 @@ function writeGitignore(content) {
32240
32305
  const path2 = gitignorePath();
32241
32306
  if (path2 === null) return false;
32242
32307
  try {
32243
- (0, import_node_fs25.writeFileSync)(path2, content, "utf8");
32308
+ (0, import_node_fs26.writeFileSync)(path2, content, "utf8");
32244
32309
  return true;
32245
32310
  } catch {
32246
32311
  return false;
32247
32312
  }
32248
32313
  }
32249
32314
  function lineEndingState(root) {
32250
- const attributesPresent = (0, import_node_fs25.existsSync)((0, import_node_path22.join)(root, ".gitattributes"));
32315
+ const attributesPresent = (0, import_node_fs26.existsSync)((0, import_node_path22.join)(root, ".gitattributes"));
32251
32316
  try {
32252
32317
  const output = execFileCapture("git", ["-C", root, "ls-files", "--eol", "--", ":(glob)**/*.sh"], {
32253
32318
  windowsHide: true
@@ -32290,7 +32355,7 @@ function compatHolds(range, version) {
32290
32355
  }
32291
32356
 
32292
32357
  // src/claude-binary-doctor.ts
32293
- var import_node_fs26 = require("node:fs");
32358
+ var import_node_fs27 = require("node:fs");
32294
32359
  var import_node_os15 = require("node:os");
32295
32360
  var import_node_path24 = require("node:path");
32296
32361
 
@@ -32398,16 +32463,16 @@ function globalNodeModulesRoots(host) {
32398
32463
  function readHead(path2) {
32399
32464
  let fd;
32400
32465
  try {
32401
- fd = (0, import_node_fs26.openSync)(path2, "r");
32466
+ fd = (0, import_node_fs27.openSync)(path2, "r");
32402
32467
  const buffer = new Uint8Array(MAGIC_HEAD_BYTES);
32403
- const read = (0, import_node_fs26.readSync)(fd, buffer, 0, MAGIC_HEAD_BYTES, 0);
32468
+ const read = (0, import_node_fs27.readSync)(fd, buffer, 0, MAGIC_HEAD_BYTES, 0);
32404
32469
  return buffer.subarray(0, read);
32405
32470
  } catch {
32406
32471
  return void 0;
32407
32472
  } finally {
32408
32473
  if (fd !== void 0) {
32409
32474
  try {
32410
- (0, import_node_fs26.closeSync)(fd);
32475
+ (0, import_node_fs27.closeSync)(fd);
32411
32476
  } catch {
32412
32477
  }
32413
32478
  }
@@ -32415,7 +32480,7 @@ function readHead(path2) {
32415
32480
  }
32416
32481
  function fileBytes(path2) {
32417
32482
  try {
32418
- return (0, import_node_fs26.statSync)(path2).size;
32483
+ return (0, import_node_fs27.statSync)(path2).size;
32419
32484
  } catch {
32420
32485
  return void 0;
32421
32486
  }
@@ -32429,13 +32494,13 @@ function readClaudeBinaryState(host = {}) {
32429
32494
  const arch = host.arch ?? process.arch;
32430
32495
  const magic = EXECUTABLE_MAGIC[platform2];
32431
32496
  if (!magic) return void 0;
32432
- const packageRoot = globalNodeModulesRoots(host).map((root) => (0, import_node_path24.join)(root, ...PACKAGE.split("/"))).find((dir) => (0, import_node_fs26.existsSync)((0, import_node_path24.join)(dir, "package.json")));
32497
+ const packageRoot = globalNodeModulesRoots(host).map((root) => (0, import_node_path24.join)(root, ...PACKAGE.split("/"))).find((dir) => (0, import_node_fs27.existsSync)((0, import_node_path24.join)(dir, "package.json")));
32433
32498
  if (!packageRoot) return void 0;
32434
32499
  const keys = platformPackageKeys(platform2, arch);
32435
32500
  const fallbackPackage = `${PACKAGE}-${keys[0]}`;
32436
32501
  let manifest;
32437
32502
  try {
32438
- manifest = JSON.parse((0, import_node_fs26.readFileSync)((0, import_node_path24.join)(packageRoot, "package.json"), "utf8"));
32503
+ manifest = JSON.parse((0, import_node_fs27.readFileSync)((0, import_node_path24.join)(packageRoot, "package.json"), "utf8"));
32439
32504
  } catch (e) {
32440
32505
  return {
32441
32506
  state: "unreadable",
@@ -32466,7 +32531,7 @@ function readClaudeBinaryState(host = {}) {
32466
32531
  (0, import_node_path24.join)(packageRoot, "node_modules", ...name.split("/"), binName),
32467
32532
  (0, import_node_path24.join)((0, import_node_path24.dirname)((0, import_node_path24.dirname)(packageRoot)), ...name.split("/"), binName)
32468
32533
  ];
32469
- const found = published.map((name) => ({ name, path: binIn(name).find((file) => (0, import_node_fs26.existsSync)(file)) })).find((c) => c.path);
32534
+ const found = published.map((name) => ({ name, path: binIn(name).find((file) => (0, import_node_fs27.existsSync)(file)) })).find((c) => c.path);
32470
32535
  const platformPackage = found?.name ?? published[0];
32471
32536
  let source;
32472
32537
  let sourceProblem;
@@ -32477,7 +32542,7 @@ function readClaudeBinaryState(host = {}) {
32477
32542
  } else {
32478
32543
  source = { path: found.path, bytes: fileBytes(found.path) ?? 0 };
32479
32544
  }
32480
- if (!(0, import_node_fs26.existsSync)(binPath)) {
32545
+ if (!(0, import_node_fs27.existsSync)(binPath)) {
32481
32546
  return { state: "missing", binPath, expectedMagic: magic.name, platformPackage, ...source ? { source } : {}, ...sourceProblem ? { sourceProblem } : {} };
32482
32547
  }
32483
32548
  const head = readHead(binPath);
@@ -32520,9 +32585,9 @@ function healClaudeBinary(host = {}, onStep) {
32520
32585
  const platform2 = host.platform ?? process.platform;
32521
32586
  const aside = `${probe.binPath}.stub-${Date.now()}`;
32522
32587
  let renamed = false;
32523
- if ((0, import_node_fs26.existsSync)(probe.binPath)) {
32588
+ if ((0, import_node_fs27.existsSync)(probe.binPath)) {
32524
32589
  try {
32525
- (0, import_node_fs26.renameSync)(probe.binPath, aside);
32590
+ (0, import_node_fs27.renameSync)(probe.binPath, aside);
32526
32591
  renamed = true;
32527
32592
  onStep?.(`renamed the stub aside: ${aside}`);
32528
32593
  } catch (e) {
@@ -32531,12 +32596,12 @@ function healClaudeBinary(host = {}, onStep) {
32531
32596
  }
32532
32597
  try {
32533
32598
  onStep?.(`copying ${probe.source.path} \u2192 ${probe.binPath} (${(probe.source.bytes / 1e6).toFixed(0)} MB)`);
32534
- (0, import_node_fs26.copyFileSync)(probe.source.path, probe.binPath);
32535
- if (platform2 !== "win32") (0, import_node_fs26.chmodSync)(probe.binPath, 493);
32599
+ (0, import_node_fs27.copyFileSync)(probe.source.path, probe.binPath);
32600
+ if (platform2 !== "win32") (0, import_node_fs27.chmodSync)(probe.binPath, 493);
32536
32601
  } catch (e) {
32537
32602
  if (renamed) {
32538
32603
  try {
32539
- (0, import_node_fs26.renameSync)(aside, probe.binPath);
32604
+ (0, import_node_fs27.renameSync)(aside, probe.binPath);
32540
32605
  } catch {
32541
32606
  return { ok: false, detail: `copy failed (${e.message}) and the stub could not be restored \u2014 the original is at ${aside}` };
32542
32607
  }
@@ -32550,7 +32615,7 @@ function healClaudeBinary(host = {}, onStep) {
32550
32615
  let kept = false;
32551
32616
  if (renamed) {
32552
32617
  try {
32553
- (0, import_node_fs26.rmSync)(aside);
32618
+ (0, import_node_fs27.rmSync)(aside);
32554
32619
  } catch {
32555
32620
  kept = true;
32556
32621
  }
@@ -32909,7 +32974,7 @@ function checkLineEndings(probe) {
32909
32974
  }
32910
32975
 
32911
32976
  // src/release-ledger.ts
32912
- var import_node_fs27 = require("node:fs");
32977
+ var import_node_fs28 = require("node:fs");
32913
32978
  var import_node_path26 = require("node:path");
32914
32979
  var import_node_crypto9 = require("node:crypto");
32915
32980
 
@@ -33084,8 +33149,8 @@ function attachOutputNote(note, suffix) {
33084
33149
  }
33085
33150
  function writeFailingLegOutput(artifactPath, output) {
33086
33151
  const fileLines = lastNonEmptyLines(output, LEDGER_OUTPUT_FILE_LINES);
33087
- (0, import_node_fs27.mkdirSync)((0, import_node_path26.dirname)(artifactPath), { recursive: true });
33088
- (0, import_node_fs27.writeFileSync)(artifactPath, `${fileLines.join("\n")}
33152
+ (0, import_node_fs28.mkdirSync)((0, import_node_path26.dirname)(artifactPath), { recursive: true });
33153
+ (0, import_node_fs28.writeFileSync)(artifactPath, `${fileLines.join("\n")}
33089
33154
  `, "utf8");
33090
33155
  const tail = fileLines.slice(-LEDGER_OUTPUT_NOTE_LINES).join("\n");
33091
33156
  const noteSuffix = truncate(`failing-leg output: ${artifactPath}
@@ -33253,7 +33318,7 @@ function resolvePrimaryGitDir(cwd) {
33253
33318
  }
33254
33319
  let common;
33255
33320
  try {
33256
- common = (0, import_node_fs27.readFileSync)((0, import_node_path26.join)(gitDir, "commondir"), "utf8").trim();
33321
+ common = (0, import_node_fs28.readFileSync)((0, import_node_path26.join)(gitDir, "commondir"), "utf8").trim();
33257
33322
  } catch (e) {
33258
33323
  if (e.code !== "ENOENT") {
33259
33324
  throw new ReleaseLedgerError("unreadable", `release ledger: the worktree gitdir's commondir pointer could not be READ (${e instanceof Error ? e.message : String(e)}) \u2014 a failed read is unverified, not primary (#5987/#4713)`);
@@ -33262,7 +33327,7 @@ function resolvePrimaryGitDir(cwd) {
33262
33327
  if (!common) return gitDir;
33263
33328
  const commonDir = (0, import_node_path26.isAbsolute)(common) ? common : (0, import_node_path26.resolve)(gitDir, common);
33264
33329
  try {
33265
- (0, import_node_fs27.readFileSync)((0, import_node_path26.join)(commonDir, "HEAD"), "utf8");
33330
+ (0, import_node_fs28.readFileSync)((0, import_node_path26.join)(commonDir, "HEAD"), "utf8");
33266
33331
  } catch (e) {
33267
33332
  throw new ReleaseLedgerError("no-checkout", `release ledger: the worktree's commondir pointer names ${commonDir}, which has no readable HEAD (${e instanceof Error ? e.message : String(e)}) \u2014 the primary checkout may have been removed; refusing to write the ledger into a doomed location`);
33268
33333
  }
@@ -33272,11 +33337,11 @@ function releaseLedgerPath(cwd) {
33272
33337
  return (0, import_node_path26.join)(resolvePrimaryGitDir(cwd), "mmi-runtime", "release", "phases.json");
33273
33338
  }
33274
33339
  function atomicWriteJson(path2, ledger) {
33275
- (0, import_node_fs27.mkdirSync)((0, import_node_path26.dirname)(path2), { recursive: true });
33340
+ (0, import_node_fs28.mkdirSync)((0, import_node_path26.dirname)(path2), { recursive: true });
33276
33341
  const tmp = `${path2}.tmp-${process.pid}-${(0, import_node_crypto9.randomBytes)(4).toString("hex")}`;
33277
- (0, import_node_fs27.writeFileSync)(tmp, `${JSON.stringify(ledger, null, 2)}
33342
+ (0, import_node_fs28.writeFileSync)(tmp, `${JSON.stringify(ledger, null, 2)}
33278
33343
  `, "utf8");
33279
- (0, import_node_fs27.renameSync)(tmp, path2);
33344
+ (0, import_node_fs28.renameSync)(tmp, path2);
33280
33345
  }
33281
33346
  var LEDGER_LOCK_OPTS = { label: "release ledger", staleMs: 18e4, deadHolderSteal: true };
33282
33347
  async function withLedgerLock(path2, fn, opts = {}) {
@@ -33323,7 +33388,7 @@ function describeTrainWriterToken(token) {
33323
33388
  function liveTrainWriterHolder(cwd) {
33324
33389
  let token;
33325
33390
  try {
33326
- token = (0, import_node_fs27.readFileSync)(trainWriterLockPath(cwd), "utf8");
33391
+ token = (0, import_node_fs28.readFileSync)(trainWriterLockPath(cwd), "utf8");
33327
33392
  } catch {
33328
33393
  return void 0;
33329
33394
  }
@@ -33345,7 +33410,7 @@ async function acquireTrainWriterLock(cwd, verb) {
33345
33410
  if (heldTrainWriter) heldTrainWriter.depth -= 1;
33346
33411
  };
33347
33412
  }
33348
- (0, import_node_fs27.mkdirSync)((0, import_node_path26.dirname)(lockPath), { recursive: true });
33413
+ (0, import_node_fs28.mkdirSync)((0, import_node_path26.dirname)(lockPath), { recursive: true });
33349
33414
  const opts = resolveFileLockOpts({ label: "train writer", staleMs: TRAIN_WRITER_STALE_MS, deadHolderSteal: true, maxWaitMs: 0, holder: verb });
33350
33415
  let guard;
33351
33416
  try {
@@ -33354,7 +33419,7 @@ async function acquireTrainWriterLock(cwd, verb) {
33354
33419
  if (!(e instanceof FileLockBusyError)) throw e;
33355
33420
  let token = "";
33356
33421
  try {
33357
- token = (0, import_node_fs27.readFileSync)(lockPath, "utf8");
33422
+ token = (0, import_node_fs28.readFileSync)(lockPath, "utf8");
33358
33423
  } catch {
33359
33424
  token = "";
33360
33425
  }
@@ -33389,7 +33454,7 @@ async function withReleaseLedger(path2, expected, fn, opts = {}) {
33389
33454
  let current;
33390
33455
  let raw;
33391
33456
  try {
33392
- raw = (0, import_node_fs27.readFileSync)(path2, "utf8");
33457
+ raw = (0, import_node_fs28.readFileSync)(path2, "utf8");
33393
33458
  } catch (e) {
33394
33459
  if (e.code !== "ENOENT") {
33395
33460
  throw new ReleaseLedgerError("unreadable", `release ledger at ${path2} could not be READ (${e instanceof Error ? e.message : String(e)}) \u2014 a failed read is unverified, not absent (#5987)`);
@@ -34056,7 +34121,7 @@ async function clearLedgerFile(path2, anchors, maxWaitMs) {
34056
34121
  return withLedgerLock(path2, async (fence) => {
34057
34122
  let raw;
34058
34123
  try {
34059
- raw = (0, import_node_fs27.readFileSync)(path2, "utf8");
34124
+ raw = (0, import_node_fs28.readFileSync)(path2, "utf8");
34060
34125
  } catch (e) {
34061
34126
  if (e.code === "ENOENT") return { cleared: false };
34062
34127
  return { cleared: false, note: `release ledger at ${path2} could not be read for clearing (${e instanceof Error ? e.message : String(e)}) \u2014 left in place` };
@@ -34072,7 +34137,7 @@ async function clearLedgerFile(path2, anchors, maxWaitMs) {
34072
34137
  } catch (e) {
34073
34138
  return { cleared: false, note: `release ledger at ${path2} belongs to ${ledger.tag} @ ${ledger.tagSha.slice(0, 12)} \u2014 not this release; left in place (${e instanceof Error ? e.message : String(e)})` };
34074
34139
  }
34075
- await fence(() => (0, import_node_fs27.unlinkSync)(path2));
34140
+ await fence(() => (0, import_node_fs28.unlinkSync)(path2));
34076
34141
  return { cleared: true, note: `cleared the release ledger at ${path2} for the live-proven aborted ${anchors.tag}` };
34077
34142
  }, { maxWaitMs });
34078
34143
  }
@@ -34232,7 +34297,7 @@ async function healStaleAlignmentLeg(deps, cwd, expected) {
34232
34297
  return withLedgerLock(path2, async (fence) => {
34233
34298
  let prior;
34234
34299
  try {
34235
- prior = parseReleaseLedger((0, import_node_fs27.readFileSync)(path2, "utf8"));
34300
+ prior = parseReleaseLedger((0, import_node_fs28.readFileSync)(path2, "utf8"));
34236
34301
  } catch {
34237
34302
  return void 0;
34238
34303
  }
@@ -34257,7 +34322,7 @@ async function healUnfoldedRunLegs(deps, cwd, model) {
34257
34322
  const path2 = releaseLedgerPath(cwd);
34258
34323
  let prior;
34259
34324
  try {
34260
- prior = parseReleaseLedger((0, import_node_fs27.readFileSync)(path2, "utf8"));
34325
+ prior = parseReleaseLedger((0, import_node_fs28.readFileSync)(path2, "utf8"));
34261
34326
  } catch {
34262
34327
  return void 0;
34263
34328
  }
@@ -34326,7 +34391,7 @@ async function supersedeContentCausedDeployLeg(deps, cwd) {
34326
34391
  return withLedgerLock(path2, async (fence) => {
34327
34392
  let prior;
34328
34393
  try {
34329
- prior = parseReleaseLedger((0, import_node_fs27.readFileSync)(path2, "utf8"));
34394
+ prior = parseReleaseLedger((0, import_node_fs28.readFileSync)(path2, "utf8"));
34330
34395
  } catch (e) {
34331
34396
  throw new ReleaseLedgerError(
34332
34397
  "unreadable",
@@ -34440,10 +34505,10 @@ async function proveOriginPromotionOrArchived(deps, prior, path2, label, ref, fe
34440
34505
  throw new Error(`${label}: origin no longer has ${prior.tag} but its GitHub Release still exists \u2014 resolve the mixed external state before closing the ledger; nothing was written (${ref})`);
34441
34506
  }
34442
34507
  const archivePath = (0, import_node_path26.join)((0, import_node_path26.dirname)(path2), `phases.archive-${prior.tag}.json`);
34443
- if ((0, import_node_fs27.existsSync)(archivePath)) {
34508
+ if ((0, import_node_fs28.existsSync)(archivePath)) {
34444
34509
  throw new Error(`${label}: archive already exists at ${archivePath} \u2014 preserving both ledger records; resolve the collision by hand; nothing was written (${ref})`);
34445
34510
  }
34446
- await fence(() => (0, import_node_fs27.renameSync)(path2, archivePath));
34511
+ await fence(() => (0, import_node_fs28.renameSync)(path2, archivePath));
34447
34512
  return "deleted";
34448
34513
  }
34449
34514
  async function supersedeContentCausedPublishLeg(deps, cwd) {
@@ -34451,7 +34516,7 @@ async function supersedeContentCausedPublishLeg(deps, cwd) {
34451
34516
  return withLedgerLock(path2, async (fence) => {
34452
34517
  let prior;
34453
34518
  try {
34454
- prior = parseReleaseLedger((0, import_node_fs27.readFileSync)(path2, "utf8"));
34519
+ prior = parseReleaseLedger((0, import_node_fs28.readFileSync)(path2, "utf8"));
34455
34520
  } catch (e) {
34456
34521
  throw new ReleaseLedgerError(
34457
34522
  "unreadable",
@@ -34539,7 +34604,7 @@ async function supersedeContentCausedDeployAndPublishLegs(deps, cwd) {
34539
34604
  return withLedgerLock(path2, async (fence) => {
34540
34605
  let prior;
34541
34606
  try {
34542
- prior = parseReleaseLedger((0, import_node_fs27.readFileSync)(path2, "utf8"));
34607
+ prior = parseReleaseLedger((0, import_node_fs28.readFileSync)(path2, "utf8"));
34543
34608
  } catch (e) {
34544
34609
  throw new ReleaseLedgerError(
34545
34610
  "unreadable",
@@ -34648,7 +34713,7 @@ async function supersedeContentCausedDeployAndPublishLegs(deps, cwd) {
34648
34713
  async function reverifyPriorRunLegs(deps, path2, targetTag) {
34649
34714
  let prior;
34650
34715
  try {
34651
- prior = parseReleaseLedger((0, import_node_fs27.readFileSync)(path2, "utf8"));
34716
+ prior = parseReleaseLedger((0, import_node_fs28.readFileSync)(path2, "utf8"));
34652
34717
  } catch {
34653
34718
  return;
34654
34719
  }
@@ -34668,7 +34733,7 @@ async function beginReleaseLedger(deps, cwd, targetTag) {
34668
34733
  return withLedgerLock(path2, async (fence) => {
34669
34734
  let raw;
34670
34735
  try {
34671
- raw = (0, import_node_fs27.readFileSync)(path2, "utf8");
34736
+ raw = (0, import_node_fs28.readFileSync)(path2, "utf8");
34672
34737
  } catch (e) {
34673
34738
  if (e.code === "ENOENT") return { ok: true };
34674
34739
  return { ok: false, error: `the release ledger at ${path2} could not be READ (${e instanceof Error ? e.message : String(e)}) \u2014 a failed read is unverified, not absent (#5987/#4713)` };
@@ -34708,13 +34773,13 @@ async function beginReleaseLedger(deps, cwd, targetTag) {
34708
34773
  }
34709
34774
  const archivePath = (0, import_node_path26.join)((0, import_node_path26.dirname)(path2), `phases.archive-${prior.tag}.json`);
34710
34775
  try {
34711
- await fence(() => (0, import_node_fs27.unlinkSync)(archivePath));
34776
+ await fence(() => (0, import_node_fs28.unlinkSync)(archivePath));
34712
34777
  } catch (e) {
34713
34778
  if (e.code !== "ENOENT") {
34714
34779
  return { ok: false, error: `could not clear the stale archive at ${archivePath} (${e instanceof Error ? e.message : String(e)}) \u2014 the ledger for ${prior.tag} stays active (#5987)` };
34715
34780
  }
34716
34781
  }
34717
- await fence(() => (0, import_node_fs27.renameSync)(path2, archivePath));
34782
+ await fence(() => (0, import_node_fs28.renameSync)(path2, archivePath));
34718
34783
  return { ok: true, note: `archived the completed release ledger ${prior.tag} to ${archivePath} (live-proven at ${prior.tagSha.slice(0, 12)})` };
34719
34784
  });
34720
34785
  }
@@ -34742,7 +34807,7 @@ async function retryHotfixDeployLegs(deps, cwd, opts = {}) {
34742
34807
  return withLedgerLock(path2, async (fence) => {
34743
34808
  let prior;
34744
34809
  try {
34745
- prior = parseReleaseLedger((0, import_node_fs27.readFileSync)(path2, "utf8"));
34810
+ prior = parseReleaseLedger((0, import_node_fs28.readFileSync)(path2, "utf8"));
34746
34811
  } catch (e) {
34747
34812
  throw new ReleaseLedgerError(
34748
34813
  "unreadable",
@@ -34984,10 +35049,10 @@ function readOriginWorkflowsDefault(root, ref) {
34984
35049
  }
34985
35050
  var NPM_REGISTRY = "https://registry.npmjs.org";
34986
35051
  async function probeRegistryWhoami(train) {
34987
- const dir = (0, import_node_fs28.mkdtempSync)((0, import_node_path27.join)((0, import_node_os16.tmpdir)(), "mmi-npmrc-"));
35052
+ const dir = (0, import_node_fs29.mkdtempSync)((0, import_node_path27.join)((0, import_node_os16.tmpdir)(), "mmi-npmrc-"));
34988
35053
  const rc = (0, import_node_path27.join)(dir, "npmrc");
34989
35054
  try {
34990
- (0, import_node_fs28.writeFileSync)(rc, "//registry.npmjs.org/:_authToken=${NPM_TOKEN}\n");
35055
+ (0, import_node_fs29.writeFileSync)(rc, "//registry.npmjs.org/:_authToken=${NPM_TOKEN}\n");
34991
35056
  await train.runSelf(["secrets", "use", "npm/NPM_TOKEN", "--slug", "_org", "--", "npm", "whoami", "--registry", NPM_REGISTRY, "--userconfig", rc]);
34992
35057
  return { kind: "ok", detail: "the registry answered a login" };
34993
35058
  } catch (e) {
@@ -34998,7 +35063,7 @@ async function probeRegistryWhoami(train) {
34998
35063
  if (/\bE401\b|401 Unauthorized/.test(stderr)) return { kind: "rejected", detail: "npm whoami answered 401 Unauthorized" };
34999
35064
  return { kind: "unverified", detail: first };
35000
35065
  } finally {
35001
- (0, import_node_fs28.rmSync)(dir, { recursive: true, force: true });
35066
+ (0, import_node_fs29.rmSync)(dir, { recursive: true, force: true });
35002
35067
  }
35003
35068
  }
35004
35069
  var REGISTRY_TOKEN_ENV = /\b(NODE_AUTH_TOKEN|NPM_TOKEN)\b/;
@@ -35016,7 +35081,7 @@ var defaultDeps2 = {
35016
35081
  ledgerPath: releaseLedgerPath,
35017
35082
  readLedgerRaw: (path2) => {
35018
35083
  try {
35019
- return (0, import_node_fs28.readFileSync)(path2, "utf8");
35084
+ return (0, import_node_fs29.readFileSync)(path2, "utf8");
35020
35085
  } catch (e) {
35021
35086
  if (e.code === "ENOENT") return void 0;
35022
35087
  throw e;
@@ -35027,7 +35092,7 @@ var defaultDeps2 = {
35027
35092
  trainWriterHolder: liveTrainWriterHolder,
35028
35093
  readSurfacesRaw: (cwd) => {
35029
35094
  try {
35030
- return (0, import_node_fs28.readFileSync)((0, import_node_path27.join)(cwd, "surfaces.json"), "utf8");
35095
+ return (0, import_node_fs29.readFileSync)((0, import_node_path27.join)(cwd, "surfaces.json"), "utf8");
35031
35096
  } catch {
35032
35097
  return void 0;
35033
35098
  }
@@ -35677,7 +35742,7 @@ function formatTrainDoctor(v) {
35677
35742
 
35678
35743
  // src/release-plain-words.ts
35679
35744
  var import_promises3 = require("node:fs/promises");
35680
- var import_node_fs29 = require("node:fs");
35745
+ var import_node_fs30 = require("node:fs");
35681
35746
  function releaseCutByNotes(cutBy) {
35682
35747
  return `## Internal
35683
35748
  Cut by ${formatSessionIdentity(cutBy)}
@@ -35783,7 +35848,7 @@ function validateSuiteReleaseSummary(path2, pathTr) {
35783
35848
  for (const [lang, file] of files) {
35784
35849
  let content;
35785
35850
  try {
35786
- content = (0, import_node_fs29.readFileSync)(file, "utf8");
35851
+ content = (0, import_node_fs30.readFileSync)(file, "utf8");
35787
35852
  } catch (e) {
35788
35853
  throw new Error(`could not read summary file ${file}: ${e.message} \u2014 see ${SUMMARY_GUIDE}`);
35789
35854
  }
@@ -35998,14 +36063,14 @@ function readLocalGateWorkflows() {
35998
36063
  const dir = (0, import_node_path28.join)(".github", "workflows");
35999
36064
  let names;
36000
36065
  try {
36001
- names = (0, import_node_fs30.readdirSync)(dir);
36066
+ names = (0, import_node_fs31.readdirSync)(dir);
36002
36067
  } catch {
36003
36068
  return null;
36004
36069
  }
36005
36070
  const files = [];
36006
36071
  for (const name of names.filter(isGateWorkflowPath)) {
36007
36072
  try {
36008
- files.push({ path: `${dir}/${name}`.replace(/\\/g, "/"), body: (0, import_node_fs30.readFileSync)((0, import_node_path28.join)(dir, name), "utf8") });
36073
+ files.push({ path: `${dir}/${name}`.replace(/\\/g, "/"), body: (0, import_node_fs31.readFileSync)((0, import_node_path28.join)(dir, name), "utf8") });
36009
36074
  } catch {
36010
36075
  }
36011
36076
  }
@@ -36015,14 +36080,14 @@ function readLocalWorkflows() {
36015
36080
  const dir = (0, import_node_path28.join)(".github", "workflows");
36016
36081
  let names;
36017
36082
  try {
36018
- names = (0, import_node_fs30.readdirSync)(dir);
36083
+ names = (0, import_node_fs31.readdirSync)(dir);
36019
36084
  } catch {
36020
36085
  return null;
36021
36086
  }
36022
36087
  const files = [];
36023
36088
  for (const name of names.filter((n) => /\.ya?ml$/i.test(n))) {
36024
36089
  try {
36025
- files.push({ path: `${dir}/${name}`.replace(/\\/g, "/"), body: (0, import_node_fs30.readFileSync)((0, import_node_path28.join)(dir, name), "utf8") });
36090
+ files.push({ path: `${dir}/${name}`.replace(/\\/g, "/"), body: (0, import_node_fs31.readFileSync)((0, import_node_path28.join)(dir, name), "utf8") });
36026
36091
  } catch {
36027
36092
  }
36028
36093
  }
@@ -36694,6 +36759,12 @@ async function pushAfterVercelVersionEnv(deps, meta, stage, tag, pushArgs) {
36694
36759
  }
36695
36760
  async function completeMainRelease(deps, ctx, meta, deployModel, watch, options, tag, releaseSha, startBranch, preFold, tagProbe, branchHints, ledger, alignEarly) {
36696
36761
  const resumeCommand = options.dev ? "mmi-cli devops release --dev --apply" : "mmi-cli devops release --apply";
36762
+ let pretag;
36763
+ try {
36764
+ pretag = await runPreTagHook(deps, { releaseSha });
36765
+ } catch (e) {
36766
+ throw await recoverFailedFold(deps, e, startBranch, preFold.mainSha, resumeCommand);
36767
+ }
36697
36768
  const ledgerAnchors = { repo: ctx.repo, tag, tagSha: releaseSha };
36698
36769
  try {
36699
36770
  deps.warn?.("Release: Checking the package before publishing");
@@ -36869,7 +36940,7 @@ ${recovery.note}`), recoveryInput);
36869
36940
  });
36870
36941
  alignment = await aligning;
36871
36942
  const announceNote = annotateVersionEnvAnnounce(await announcing, versionEnv);
36872
- return { checks, releaseUrl, announceNote, localInstall, dispatch, ledgerAnchors, ...alignment ? { alignment } : {} };
36943
+ return { checks, releaseUrl, announceNote, localInstall, dispatch, ledgerAnchors, pretag, ...alignment ? { alignment } : {} };
36873
36944
  }
36874
36945
  function resumeStateOf(status) {
36875
36946
  return status === "complete" ? "aligned" : status;
@@ -36911,7 +36982,7 @@ async function activeRcandLedgerCandidate(deps, cwd) {
36911
36982
  }
36912
36983
  let prior;
36913
36984
  try {
36914
- prior = parseReleaseLedger((0, import_node_fs30.readFileSync)(path2, "utf8"));
36985
+ prior = parseReleaseLedger((0, import_node_fs31.readFileSync)(path2, "utf8"));
36915
36986
  } catch {
36916
36987
  return void 0;
36917
36988
  }
@@ -37848,7 +37919,7 @@ ${spent.note}`), rcandRecovery(tag2));
37848
37919
  const releaseSha3 = requireValue(clean2(await deps.run("git", ["rev-parse", "main"])), "release sha");
37849
37920
  return { versionFold: versionFold3, releaseSha: releaseSha3 };
37850
37921
  });
37851
- const { checks: checks2, releaseUrl: releaseUrl2, announceNote: announceNote2, localInstall: localInstall2, dispatch: d2, ledgerAnchors: ledgerAnchors2, alignment: alignment2 } = await completeMainRelease(
37922
+ const { checks: checks2, releaseUrl: releaseUrl2, announceNote: announceNote2, localInstall: localInstall2, dispatch: d2, ledgerAnchors: ledgerAnchors2, pretag: pretag2, alignment: alignment2 } = await completeMainRelease(
37852
37923
  deps,
37853
37924
  ctx,
37854
37925
  meta,
@@ -37880,6 +37951,7 @@ ${spent.note}`), rcandRecovery(tag2));
37880
37951
  promoted: true,
37881
37952
  checks: checks2,
37882
37953
  versionFold: versionFold2,
37954
+ pretag: pretag2,
37883
37955
  dispatch: d2.note,
37884
37956
  runId: d2.runId,
37885
37957
  runUrl: d2.runUrl,
@@ -37910,6 +37982,7 @@ ${spent.note}`), rcandRecovery(tag2));
37910
37982
  promoted: true,
37911
37983
  checks: checks2,
37912
37984
  versionFold: versionFold2,
37985
+ pretag: pretag2,
37913
37986
  dispatch: d2.note,
37914
37987
  runId: d2.runId,
37915
37988
  runUrl: d2.runUrl,
@@ -37959,7 +38032,7 @@ ${spent.note}`), rcandRecovery(tag2));
37959
38032
  const releaseSha2 = requireValue(clean2(await deps.run("git", ["rev-parse", "main"])), "release sha");
37960
38033
  return { versionFold: versionFold2, releaseSha: releaseSha2 };
37961
38034
  });
37962
- const { checks, releaseUrl, announceNote, localInstall, dispatch: d, ledgerAnchors, alignment } = await completeMainRelease(
38035
+ const { checks, releaseUrl, announceNote, localInstall, dispatch: d, ledgerAnchors, pretag, alignment } = await completeMainRelease(
37963
38036
  deps,
37964
38037
  ctx,
37965
38038
  meta,
@@ -37993,6 +38066,7 @@ ${spent.note}`), rcandRecovery(tag2));
37993
38066
  promoted: true,
37994
38067
  checks,
37995
38068
  versionFold,
38069
+ pretag,
37996
38070
  dispatch: d.note,
37997
38071
  runId: d.runId,
37998
38072
  runUrl: d.runUrl,
@@ -41164,7 +41238,7 @@ function registerBoardCommands(program3) {
41164
41238
  }
41165
41239
 
41166
41240
  // src/bootstrap-commands.ts
41167
- var import_node_fs34 = require("node:fs");
41241
+ var import_node_fs35 = require("node:fs");
41168
41242
  var import_node_os19 = require("node:os");
41169
41243
  var import_node_path32 = require("node:path");
41170
41244
  init_cli_shared();
@@ -41351,7 +41425,7 @@ init_github_client();
41351
41425
  init_cli_shared();
41352
41426
 
41353
41427
  // src/port-registry.ts
41354
- var import_node_fs31 = require("node:fs");
41428
+ var import_node_fs32 = require("node:fs");
41355
41429
  var import_node_path29 = require("node:path");
41356
41430
 
41357
41431
  // ../infra/port-geometry.mjs
@@ -41366,8 +41440,8 @@ function nextPortBlock(registry2) {
41366
41440
  return [base, base + PORT_SPAN];
41367
41441
  }
41368
41442
  function loadPortRegistry(path2) {
41369
- if (!(0, import_node_fs31.existsSync)(path2)) return {};
41370
- const raw = JSON.parse((0, import_node_fs31.readFileSync)(path2, "utf8"));
41443
+ if (!(0, import_node_fs32.existsSync)(path2)) return {};
41444
+ const raw = JSON.parse((0, import_node_fs32.readFileSync)(path2, "utf8"));
41371
41445
  const out = {};
41372
41446
  for (const [key, value] of Object.entries(raw)) {
41373
41447
  if (Array.isArray(value) && value.length === 2 && value.every((n) => typeof n === "number")) {
@@ -41397,7 +41471,7 @@ function existingPortRange(repo, registry2) {
41397
41471
  function portRangeInfraAt(root, source) {
41398
41472
  const registryPath = (0, import_node_path29.join)(root, "infra", "port-ranges.json");
41399
41473
  const ddbScriptPath = (0, import_node_path29.join)(root, "infra", "port-ddb.mjs");
41400
- if (!(0, import_node_fs31.existsSync)(registryPath) || !(0, import_node_fs31.existsSync)(ddbScriptPath)) return null;
41474
+ if (!(0, import_node_fs32.existsSync)(registryPath) || !(0, import_node_fs32.existsSync)(ddbScriptPath)) return null;
41401
41475
  return { root, source, registryPath, ddbScriptPath };
41402
41476
  }
41403
41477
  function resolvePortRangeInfra(cwd, packageDir) {
@@ -41479,7 +41553,7 @@ async function assignPersistedPortRange(repo, slug, reg, opts) {
41479
41553
  }
41480
41554
 
41481
41555
  // src/box-commands.ts
41482
- var import_node_fs33 = require("node:fs");
41556
+ var import_node_fs34 = require("node:fs");
41483
41557
  var import_node_child_process10 = require("node:child_process");
41484
41558
  var import_node_os18 = require("node:os");
41485
41559
  var import_node_path31 = require("node:path");
@@ -41652,7 +41726,7 @@ init_clean_exit();
41652
41726
  init_cli_shared();
41653
41727
 
41654
41728
  // src/secrets-commands.ts
41655
- var import_node_fs32 = require("node:fs");
41729
+ var import_node_fs33 = require("node:fs");
41656
41730
  var import_node_path30 = require("node:path");
41657
41731
  var import_node_os17 = require("node:os");
41658
41732
  init_cli_shared();
@@ -42860,8 +42934,8 @@ async function decryptRailsCredentials(input) {
42860
42934
  MMI_RAILS_CREDENTIALS_FILE: credentialsPath,
42861
42935
  MMI_RAILS_MASTER_KEY_FILE: masterKeyPath
42862
42936
  };
42863
- if ((0, import_node_fs32.existsSync)(masterKeyPath)) {
42864
- env.RAILS_MASTER_KEY = (0, import_node_fs32.readFileSync)(masterKeyPath, "utf8").trim();
42937
+ if ((0, import_node_fs33.existsSync)(masterKeyPath)) {
42938
+ env.RAILS_MASTER_KEY = (0, import_node_fs33.readFileSync)(masterKeyPath, "utf8").trim();
42865
42939
  }
42866
42940
  const script = [
42867
42941
  'require "json"',
@@ -42871,9 +42945,9 @@ async function decryptRailsCredentials(input) {
42871
42945
  'config = ActiveSupport::EncryptedConfiguration.new(config_path: config_path, key_path: key_path, env_key: "RAILS_MASTER_KEY", raise_if_missing_key: true)',
42872
42946
  "puts JSON.generate(config.config)"
42873
42947
  ].join("\n");
42874
- const scriptDir = (0, import_node_fs32.mkdtempSync)((0, import_node_path30.join)((0, import_node_os17.tmpdir)(), "mmi-rails-decrypt-"));
42948
+ const scriptDir = (0, import_node_fs33.mkdtempSync)((0, import_node_path30.join)((0, import_node_os17.tmpdir)(), "mmi-rails-decrypt-"));
42875
42949
  const scriptPath = (0, import_node_path30.join)(scriptDir, "decrypt.rb");
42876
- (0, import_node_fs32.writeFileSync)(scriptPath, script, "utf8");
42950
+ (0, import_node_fs33.writeFileSync)(scriptPath, script, "utf8");
42877
42951
  try {
42878
42952
  const args = ["exec", "ruby", scriptPath];
42879
42953
  const cmd = process.platform === "win32" ? "cmd.exe" : "bundle";
@@ -42885,7 +42959,7 @@ async function decryptRailsCredentials(input) {
42885
42959
  });
42886
42960
  return JSON.parse(stdout);
42887
42961
  } finally {
42888
- (0, import_node_fs32.rmSync)(scriptDir, { recursive: true, force: true });
42962
+ (0, import_node_fs33.rmSync)(scriptDir, { recursive: true, force: true });
42889
42963
  }
42890
42964
  }
42891
42965
  async function readSecretStdin() {
@@ -42975,7 +43049,7 @@ function registerSecretsCommands(program3) {
42975
43049
  let body;
42976
43050
  if (o.file) {
42977
43051
  try {
42978
- body = (0, import_node_fs32.readFileSync)((0, import_node_path30.resolve)(o.file), "utf8");
43052
+ body = (0, import_node_fs33.readFileSync)((0, import_node_path30.resolve)(o.file), "utf8");
42979
43053
  } catch (e) {
42980
43054
  return fail(`secrets org-catalog: cannot read --file ${o.file}: ${e.message}`);
42981
43055
  }
@@ -43111,7 +43185,7 @@ function registerSecretsCommands(program3) {
43111
43185
  {
43112
43186
  ...d,
43113
43187
  decryptRailsCredentials,
43114
- removeFile: (path2) => (0, import_node_fs32.unlinkSync)((0, import_node_path30.resolve)(o.appDir ?? process.cwd(), path2))
43188
+ removeFile: (path2) => (0, import_node_fs33.unlinkSync)((0, import_node_path30.resolve)(o.appDir ?? process.cwd(), path2))
43115
43189
  },
43116
43190
  {
43117
43191
  repo: o.repo,
@@ -43367,7 +43441,7 @@ function registerBoxCommands(program3) {
43367
43441
  }
43368
43442
  const remote = command && command.length ? command.join(" ") : void 0;
43369
43443
  const wroteScript = o.ssh && o.script ? o.script : null;
43370
- if (wroteScript) (0, import_node_fs33.writeFileSync)(wroteScript, sshRecipeScript(found, remote), "utf8");
43444
+ if (wroteScript) (0, import_node_fs34.writeFileSync)(wroteScript, sshRecipeScript(found, remote), "utf8");
43371
43445
  if (o.json) {
43372
43446
  console.log(JSON.stringify({
43373
43447
  box: found,
@@ -43491,17 +43565,17 @@ function hubGitShow(ref) {
43491
43565
  return (path2) => git3(["show", `${ref}:${path2}`]);
43492
43566
  }
43493
43567
  function runOnBox(found, script) {
43494
- const dir = (0, import_node_fs33.mkdtempSync)((0, import_node_path31.join)((0, import_node_os18.tmpdir)(), "mmi-box-control-"));
43568
+ const dir = (0, import_node_fs34.mkdtempSync)((0, import_node_path31.join)((0, import_node_os18.tmpdir)(), "mmi-box-control-"));
43495
43569
  try {
43496
43570
  const recipe = (0, import_node_path31.join)(dir, "recipe.sh");
43497
- (0, import_node_fs33.writeFileSync)(recipe, sshRecipeScript(found, "sh -s"), "utf8");
43571
+ (0, import_node_fs34.writeFileSync)(recipe, sshRecipeScript(found, "sh -s"), "utf8");
43498
43572
  const r = (0, import_node_child_process10.spawnSync)("bash", [recipe], { input: script, encoding: "utf8", maxBuffer: 16 * 1024 * 1024, timeout: 18e4, windowsHide: true });
43499
43573
  if (r.status !== 0) {
43500
43574
  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(" | ")}`);
43501
43575
  }
43502
43576
  return r.stdout;
43503
43577
  } finally {
43504
- (0, import_node_fs33.rmSync)(dir, { recursive: true, force: true });
43578
+ (0, import_node_fs34.rmSync)(dir, { recursive: true, force: true });
43505
43579
  }
43506
43580
  }
43507
43581
  function formatControl(mode, box, rows) {
@@ -45144,12 +45218,12 @@ async function verifyTargetedSeedPr(repo, number, plan, target, expected, client
45144
45218
  // src/bootstrap-commands.ts
45145
45219
  var execGitForSeedSource = async (args) => (await execFileP("git", args, { timeout: GIT_TIMEOUT_MS })).stdout;
45146
45220
  async function gateRenderDiff(current, rendered) {
45147
- const dir = (0, import_node_fs34.mkdtempSync)((0, import_node_path32.join)((0, import_node_os19.tmpdir)(), "mmi-gate-diff-"));
45221
+ const dir = (0, import_node_fs35.mkdtempSync)((0, import_node_path32.join)((0, import_node_os19.tmpdir)(), "mmi-gate-diff-"));
45148
45222
  const before = (0, import_node_path32.join)(dir, "committed-gate.yml");
45149
45223
  const after = (0, import_node_path32.join)(dir, "registry-render.yml");
45150
45224
  try {
45151
- (0, import_node_fs34.writeFileSync)(before, current);
45152
- (0, import_node_fs34.writeFileSync)(after, rendered);
45225
+ (0, import_node_fs35.writeFileSync)(before, current);
45226
+ (0, import_node_fs35.writeFileSync)(after, rendered);
45153
45227
  try {
45154
45228
  return (await execFileP("git", ["diff", "--no-index", "--", before, after], { timeout: GIT_TIMEOUT_MS })).stdout;
45155
45229
  } catch (e) {
@@ -45158,7 +45232,7 @@ async function gateRenderDiff(current, rendered) {
45158
45232
  throw e;
45159
45233
  }
45160
45234
  } finally {
45161
- (0, import_node_fs34.rmSync)(dir, { recursive: true, force: true });
45235
+ (0, import_node_fs35.rmSync)(dir, { recursive: true, force: true });
45162
45236
  }
45163
45237
  }
45164
45238
  function bootstrapTrainDoctorDeps() {
@@ -45218,13 +45292,13 @@ function registerBootstrapCommands(program3) {
45218
45292
  })),
45219
45293
  pushAllowlistOwners: verifyOwners,
45220
45294
  pushAllowlistOwnersRead: verifyOwnersRead,
45221
- readLocalFile: (path2) => path2 === "projects.json" && apiProjects != null ? apiProjects : (0, import_node_fs34.existsSync)(path2) ? (0, import_node_fs34.readFileSync)(path2, "utf8") : null,
45295
+ readLocalFile: (path2) => path2 === "projects.json" && apiProjects != null ? apiProjects : (0, import_node_fs35.existsSync)(path2) ? (0, import_node_fs35.readFileSync)(path2, "utf8") : null,
45222
45296
  // requiredGcpApis is stored as an array by a JSON write, but `org project set --var KEY=VALUE` stores a raw
45223
45297
  // comma-string — accept either so the seeded value verifies regardless of how it was written.
45224
45298
  // #3689: the same committed map the org access audit reads (#3664), so a sanctioned admin is not a
45225
45299
  // permanent bootstrap failure on one surface and an intended state on the other. Absent file → no
45226
45300
  // sanction, which is the pre-#3664 behaviour.
45227
- sanctionedAdmins: (0, import_node_fs34.existsSync)("access-matrix.json") ? entriesValueByCanonicalRepo(loadSanctionedAdmins((0, import_node_fs34.readFileSync)("access-matrix.json", "utf8")), repo) : void 0,
45301
+ sanctionedAdmins: (0, import_node_fs35.existsSync)("access-matrix.json") ? entriesValueByCanonicalRepo(loadSanctionedAdmins((0, import_node_fs35.readFileSync)("access-matrix.json", "utf8")), repo) : void 0,
45228
45302
  requiredGcpApis: (() => {
45229
45303
  const v = meta?.requiredGcpApis;
45230
45304
  if (Array.isArray(v)) return v;
@@ -45302,14 +45376,14 @@ function registerBootstrapCommands(program3) {
45302
45376
  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 () => {
45303
45377
  const o = { repo: rawValue("--repo", ""), json: rawFlag("--json") };
45304
45378
  const manifestPath = "skills/bootstrap/seeds/manifest.json";
45305
- if (!(0, import_node_fs34.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`);
45379
+ if (!(0, import_node_fs35.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`);
45306
45380
  const seedSource = await resolveHubSeedSource(execGitForSeedSource);
45307
45381
  if (!seedSource.ok) return fail(`bootstrap drift: ${seedSource.reason}`);
45308
- const manifest = loadBootstrapSeeds((0, import_node_fs34.readFileSync)(manifestPath, "utf8"));
45382
+ const manifest = loadBootstrapSeeds((0, import_node_fs35.readFileSync)(manifestPath, "utf8"));
45309
45383
  const hubContents = /* @__PURE__ */ new Map();
45310
45384
  for (const s of manifest.seeds) {
45311
45385
  if (s.ownership !== "org" || s.source !== "self") continue;
45312
- hubContents.set(s.target, (0, import_node_fs34.existsSync)(s.target) ? (0, import_node_fs34.readFileSync)(s.target, "utf8") : null);
45386
+ hubContents.set(s.target, (0, import_node_fs35.existsSync)(s.target) ? (0, import_node_fs35.readFileSync)(s.target, "utf8") : null);
45313
45387
  }
45314
45388
  let targets;
45315
45389
  let classOf = (_repo) => "deployable";
@@ -45517,24 +45591,24 @@ function registerBootstrapCommands(program3) {
45517
45591
  return;
45518
45592
  }
45519
45593
  const manifestPath = "skills/bootstrap/seeds/manifest.json";
45520
- if (!(0, import_node_fs34.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`);
45594
+ if (!(0, import_node_fs35.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`);
45521
45595
  const seedSource = await resolveHubSeedSource(execGitForSeedSource);
45522
45596
  if (!seedSource.ok) return fail(`bootstrap apply: ${seedSource.reason}`);
45523
- const manifest = loadBootstrapSeeds((0, import_node_fs34.readFileSync)(manifestPath, "utf8"));
45597
+ const manifest = loadBootstrapSeeds((0, import_node_fs35.readFileSync)(manifestPath, "utf8"));
45524
45598
  const baseBranch = o.class === "content" ? "main" : "development";
45525
45599
  const slug = parsedRepo.slug;
45526
45600
  const onlyTarget = o.fromConfig && o.only.trim() === "gate.yml" ? ".github/workflows/gate.yml" : o.only.trim();
45527
45601
  const gh2 = async (args) => execFileP("gh", args, { timeout: 2e4 });
45528
- const readFile10 = (p) => (0, import_node_fs34.existsSync)(p) ? (0, import_node_fs34.readFileSync)(p, "utf8") : null;
45602
+ const readFile10 = (p) => (0, import_node_fs35.existsSync)(p) ? (0, import_node_fs35.readFileSync)(p, "utf8") : null;
45529
45603
  const enc = (p) => p.split("/").map(encodeURIComponent).join("/");
45530
45604
  const putSeed = async (target, content, ref, sha) => {
45531
45605
  const tmp = (0, import_node_path32.join)((0, import_node_os19.tmpdir)(), `mmi-seed-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
45532
- (0, import_node_fs34.writeFileSync)(tmp, JSON.stringify(contentPutBody(target, content, ref, sha)), "utf8");
45606
+ (0, import_node_fs35.writeFileSync)(tmp, JSON.stringify(contentPutBody(target, content, ref, sha)), "utf8");
45533
45607
  try {
45534
45608
  await gh2(contentPutInputArgs(repo, target, tmp));
45535
45609
  } finally {
45536
45610
  try {
45537
- (0, import_node_fs34.unlinkSync)(tmp);
45611
+ (0, import_node_fs35.unlinkSync)(tmp);
45538
45612
  } catch {
45539
45613
  }
45540
45614
  }
@@ -46170,10 +46244,10 @@ LIVE apply to ${repo}:
46170
46244
  bootstrap.command("propagate").description("#4238: re-entrant canary\u2192wave tick \u2014 plan (or, with --execute, open) per-repo PRs fanning an org-owned seed out to the fleet").option("--target <path>", "the manifest target to propagate (an org-owned whole file or declared Hub-managed block)").option("--execute", "LIVE tick via gh (master-gated) \u2014 opens/reuses per-repo seed-propagate PRs; dry-run prints the plan only").option("--json", "machine-readable output").action(async () => {
46171
46245
  const o = { target: rawValue("--target", ""), execute: rawFlag("--execute"), json: rawFlag("--json") };
46172
46246
  const manifestPath = "skills/bootstrap/seeds/manifest.json";
46173
- if (!(0, import_node_fs34.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`);
46247
+ if (!(0, import_node_fs35.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`);
46174
46248
  const seedSource = await resolveHubSeedSource(execGitForSeedSource);
46175
46249
  if (!seedSource.ok) return fail(`bootstrap propagate: ${seedSource.reason}`);
46176
- const manifest = loadBootstrapSeeds((0, import_node_fs34.readFileSync)(manifestPath, "utf8"));
46250
+ const manifest = loadBootstrapSeeds((0, import_node_fs35.readFileSync)(manifestPath, "utf8"));
46177
46251
  const propagatable = manifest.seeds.filter(isPropagatableSeed);
46178
46252
  if (!o.target) {
46179
46253
  return fail(`bootstrap propagate: --target <path> is required \u2014 one of:
@@ -46182,9 +46256,9 @@ LIVE apply to ${repo}:
46182
46256
  const seed = propagatable.find((s) => s.target === o.target);
46183
46257
  if (!seed) return fail(`bootstrap propagate: --target '${o.target}' names no centrally propagatable seed in ${manifestPath}. Propagatable targets:
46184
46258
  ${propagatable.map((s) => s.target).join("\n ")}`);
46185
- if (!seed.managedBlock && !(0, import_node_fs34.existsSync)(seed.target)) return fail(`bootstrap propagate: the Hub's own copy of '${seed.target}' is missing \u2014 nothing to propagate`);
46186
- const hubContent = seed.managedBlock ? null : (0, import_node_fs34.readFileSync)(seed.target, "utf8");
46187
- const readSeedFile2 = (path2) => (0, import_node_fs34.existsSync)(path2) ? (0, import_node_fs34.readFileSync)(path2, "utf8") : null;
46259
+ if (!seed.managedBlock && !(0, import_node_fs35.existsSync)(seed.target)) return fail(`bootstrap propagate: the Hub's own copy of '${seed.target}' is missing \u2014 nothing to propagate`);
46260
+ const hubContent = seed.managedBlock ? null : (0, import_node_fs35.readFileSync)(seed.target, "utf8");
46261
+ const readSeedFile2 = (path2) => (0, import_node_fs35.existsSync)(path2) ? (0, import_node_fs35.readFileSync)(path2, "utf8") : null;
46188
46262
  const isWorkflowSeed = seed.target.startsWith(".github/workflows/");
46189
46263
  const cfg = await loadConfig();
46190
46264
  const projects = await fetchProjectsList(registryClientDeps(cfg));
@@ -46193,9 +46267,9 @@ LIVE apply to ${repo}:
46193
46267
  }
46194
46268
  const rosterRepos = collectRegistryRepos(projects).filter((r) => r.toLowerCase() !== "mutmutco/mmi-hub");
46195
46269
  let independentCount = rosterRepos.length;
46196
- if ((0, import_node_fs34.existsSync)("projects.json")) {
46270
+ if ((0, import_node_fs35.existsSync)("projects.json")) {
46197
46271
  try {
46198
- const local = JSON.parse((0, import_node_fs34.readFileSync)("projects.json", "utf8"));
46272
+ const local = JSON.parse((0, import_node_fs35.readFileSync)("projects.json", "utf8"));
46199
46273
  const localRepos = /* @__PURE__ */ new Set();
46200
46274
  for (const p of local.projects ?? []) for (const r of p.repos ?? []) {
46201
46275
  const full = (r.includes("/") ? r : `mutmutco/${r}`).toLowerCase();
@@ -46351,7 +46425,7 @@ LIVE apply to ${repo}:
46351
46425
  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)");
46352
46426
  const headSha = seedSource.sha;
46353
46427
  const sourceBlob = (await execGitForSeedSource(["rev-parse", `${headSha}:${seedSourcePath(seed)}`])).trim();
46354
- const runbookUnaffected = (0, import_node_fs34.existsSync)(RUNBOOK_UNAFFECTED_PATH) ? runbookUnaffectedReason(JSON.parse((0, import_node_fs34.readFileSync)(RUNBOOK_UNAFFECTED_PATH, "utf8")), seed.target, sourceBlob) : void 0;
46428
+ const runbookUnaffected = (0, import_node_fs35.existsSync)(RUNBOOK_UNAFFECTED_PATH) ? runbookUnaffectedReason(JSON.parse((0, import_node_fs35.readFileSync)(RUNBOOK_UNAFFECTED_PATH, "utf8")), seed.target, sourceBlob) : void 0;
46355
46429
  for (const rec of plan.records) {
46356
46430
  if (rec.action !== "open-pr") continue;
46357
46431
  const baseBranch = classOf(rec.repo) === "content" ? "main" : "development";
@@ -46376,12 +46450,12 @@ LIVE apply to ${repo}:
46376
46450
  const tmp = (0, import_node_path32.join)((0, import_node_os19.tmpdir)(), `mmi-propagate-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
46377
46451
  const desiredContent = desiredByRepo.get(rec.repo);
46378
46452
  if (desiredContent == null) return fail(`bootstrap propagate: no resolved content for ${rec.repo} ${seed.target} \u2014 refusing to write`);
46379
- (0, import_node_fs34.writeFileSync)(tmp, JSON.stringify(contentPutBody(seed.target, desiredContent, branch, existingSha, runbookUnaffected)), "utf8");
46453
+ (0, import_node_fs35.writeFileSync)(tmp, JSON.stringify(contentPutBody(seed.target, desiredContent, branch, existingSha, runbookUnaffected)), "utf8");
46380
46454
  try {
46381
46455
  await gh2(contentPutInputArgs(rec.repo, seed.target, tmp));
46382
46456
  } finally {
46383
46457
  try {
46384
- (0, import_node_fs34.unlinkSync)(tmp);
46458
+ (0, import_node_fs35.unlinkSync)(tmp);
46385
46459
  } catch {
46386
46460
  }
46387
46461
  }
@@ -46450,10 +46524,10 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
46450
46524
  return fail(`bootstrap rollback: ${e.message}`);
46451
46525
  }
46452
46526
  const manifestPath = "skills/bootstrap/seeds/manifest.json";
46453
- if (!(0, import_node_fs34.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)`);
46527
+ if (!(0, import_node_fs35.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)`);
46454
46528
  const seedSource = await resolveHubSeedSource(execGitForSeedSource);
46455
46529
  if (!seedSource.ok) return fail(`bootstrap rollback: ${seedSource.reason}`);
46456
- const manifest = loadBootstrapSeeds((0, import_node_fs34.readFileSync)(manifestPath, "utf8"));
46530
+ const manifest = loadBootstrapSeeds((0, import_node_fs35.readFileSync)(manifestPath, "utf8"));
46457
46531
  const propagatable = manifest.seeds.filter(isPropagatableSeed);
46458
46532
  if (!o.target) {
46459
46533
  return fail(`bootstrap rollback: --target <path> is required \u2014 one of:
@@ -46470,10 +46544,10 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
46470
46544
  const enc = (p) => p.split("/").map(encodeURIComponent).join("/");
46471
46545
  let candidates;
46472
46546
  if (o.record) {
46473
- if (!(0, import_node_fs34.existsSync)(o.record)) return fail(`bootstrap rollback: --record '${o.record}' not found`);
46547
+ if (!(0, import_node_fs35.existsSync)(o.record)) return fail(`bootstrap rollback: --record '${o.record}' not found`);
46474
46548
  let parsed;
46475
46549
  try {
46476
- parsed = JSON.parse((0, import_node_fs34.readFileSync)(o.record, "utf8"));
46550
+ parsed = JSON.parse((0, import_node_fs35.readFileSync)(o.record, "utf8"));
46477
46551
  } catch (e) {
46478
46552
  return fail(`bootstrap rollback: --record '${o.record}' is not valid JSON: ${e.message}`);
46479
46553
  }
@@ -46551,12 +46625,12 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
46551
46625
  existingSha = void 0;
46552
46626
  }
46553
46627
  const tmp = (0, import_node_path32.join)((0, import_node_os19.tmpdir)(), `mmi-rollback-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
46554
- (0, import_node_fs34.writeFileSync)(tmp, JSON.stringify(contentPutBody(seed.target, preSeedContent, plan.branch, existingSha)), "utf8");
46628
+ (0, import_node_fs35.writeFileSync)(tmp, JSON.stringify(contentPutBody(seed.target, preSeedContent, plan.branch, existingSha)), "utf8");
46555
46629
  try {
46556
46630
  await gh2(contentPutInputArgs(repo, seed.target, tmp));
46557
46631
  } finally {
46558
46632
  try {
46559
- (0, import_node_fs34.unlinkSync)(tmp);
46633
+ (0, import_node_fs35.unlinkSync)(tmp);
46560
46634
  } catch {
46561
46635
  }
46562
46636
  }
@@ -47028,7 +47102,7 @@ async function waitSuiteDev(deps, opts) {
47028
47102
  }
47029
47103
 
47030
47104
  // src/suite-train.ts
47031
- var import_node_fs35 = require("node:fs");
47105
+ var import_node_fs36 = require("node:fs");
47032
47106
  var import_node_path33 = require("node:path");
47033
47107
  var import_node_crypto15 = require("node:crypto");
47034
47108
 
@@ -47115,7 +47189,7 @@ function suiteReleaseTag(rc) {
47115
47189
  function readSuiteCut(path2) {
47116
47190
  let raw;
47117
47191
  try {
47118
- raw = (0, import_node_fs35.readFileSync)(path2, "utf8");
47192
+ raw = (0, import_node_fs36.readFileSync)(path2, "utf8");
47119
47193
  } catch (e) {
47120
47194
  if (e.code === "ENOENT") return void 0;
47121
47195
  throw e;
@@ -47131,11 +47205,11 @@ function readSuiteCut(path2) {
47131
47205
  return record2;
47132
47206
  }
47133
47207
  function writeSuiteCut(path2, record2) {
47134
- (0, import_node_fs35.mkdirSync)((0, import_node_path33.dirname)(path2), { recursive: true });
47208
+ (0, import_node_fs36.mkdirSync)((0, import_node_path33.dirname)(path2), { recursive: true });
47135
47209
  const temp = `${path2}.${(0, import_node_crypto15.randomBytes)(8).toString("hex")}.tmp`;
47136
47210
  try {
47137
- (0, import_node_fs35.writeFileSync)(temp, JSON.stringify(record2, null, 2), { flag: "wx" });
47138
- (0, import_node_fs35.renameSync)(temp, path2);
47211
+ (0, import_node_fs36.writeFileSync)(temp, JSON.stringify(record2, null, 2), { flag: "wx" });
47212
+ (0, import_node_fs36.renameSync)(temp, path2);
47139
47213
  } catch (e) {
47140
47214
  throw new Error(`suite cut record write failed at ${path2}: ${e.message}; stop, verify the file before retrying`);
47141
47215
  }
@@ -47184,25 +47258,25 @@ async function suiteMarkAbandoned(deps, ownerGo = false) {
47184
47258
  return tags.map((t) => `${t.repo}@${t.tag}`);
47185
47259
  }
47186
47260
  async function retireFailedLeadRcLedger(deps, ownerGo) {
47187
- if (!(0, import_node_fs35.existsSync)(deps.ledgerPath)) return void 0;
47261
+ if (!(0, import_node_fs36.existsSync)(deps.ledgerPath)) return void 0;
47188
47262
  return withLedgerLock(deps.ledgerPath, async (fence) => {
47189
- const ledger = parseReleaseLedger((0, import_node_fs35.readFileSync)(deps.ledgerPath, "utf8"));
47263
+ const ledger = parseReleaseLedger((0, import_node_fs36.readFileSync)(deps.ledgerPath, "utf8"));
47190
47264
  const states = Object.values(ledger.phases).map((p) => p.state);
47191
47265
  if (ledger.repo !== SUITE_REPO || ledger.lane !== "rcand" || ledger.phases.promotion.state === "complete" || !states.includes("failed")) return void 0;
47192
47266
  if (!ownerGo) throw new Error(`the lead's failed rcand ledger for ${ledger.tag} blocks every train; retire it with suite abandon --owner-go`);
47193
47267
  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`);
47194
47268
  const archive = (0, import_node_path33.join)((0, import_node_path33.dirname)(deps.ledgerPath), `phases.archive-${ledger.tag}.json`);
47195
- if ((0, import_node_fs35.existsSync)(archive)) throw new Error(`ledger archive already exists at ${archive}; inspect before retiring again`);
47269
+ if ((0, import_node_fs36.existsSync)(archive)) throw new Error(`ledger archive already exists at ${archive}; inspect before retiring again`);
47196
47270
  await deps.markAbandoned(SUITE_REPO, ledger.tag, ledger.tagSha);
47197
- await fence(() => (0, import_node_fs35.renameSync)(deps.ledgerPath, archive));
47271
+ await fence(() => (0, import_node_fs36.renameSync)(deps.ledgerPath, archive));
47198
47272
  return `${ledger.tag} (ledger archived to ${archive})`;
47199
47273
  });
47200
47274
  }
47201
47275
  function suiteAbandon(recordPath, ownerGo = false, now = /* @__PURE__ */ new Date()) {
47202
47276
  const record2 = abandonableCut(recordPath, ownerGo);
47203
47277
  const archive = `${recordPath}.abandoned-${record2.leadDevelopment.slice(0, 12)}-${now.toISOString().replace(/[:.]/g, "")}.json`;
47204
- if ((0, import_node_fs35.existsSync)(archive)) throw new Error(`abandoned-cut archive already exists at ${archive}; inspect before abandoning again`);
47205
- (0, import_node_fs35.renameSync)(recordPath, archive);
47278
+ if ((0, import_node_fs36.existsSync)(archive)) throw new Error(`abandoned-cut archive already exists at ${archive}; inspect before abandoning again`);
47279
+ (0, import_node_fs36.renameSync)(recordPath, archive);
47206
47280
  return { archive, orphanTags: record2.members.filter((m) => m.tag).map((m) => `${m.repo}@${m.tag}`) };
47207
47281
  }
47208
47282
  async function suiteRestoreMainPins(deps) {
@@ -47289,12 +47363,12 @@ async function suiteRcandRun(deps, opts) {
47289
47363
  }
47290
47364
  if ((record2?.announcement === "sent" || record2?.announcement === "skipped") && record2.leadReleased) {
47291
47365
  const archive = `${deps.recordPath}.${record2.leadRcTag}.json`;
47292
- if ((0, import_node_fs35.existsSync)(archive)) throw new Error(`suite cut archive already exists at ${archive}; inspect before a new cut`);
47293
- (0, import_node_fs35.renameSync)(deps.recordPath, archive);
47366
+ if ((0, import_node_fs36.existsSync)(archive)) throw new Error(`suite cut archive already exists at ${archive}; inspect before a new cut`);
47367
+ (0, import_node_fs36.renameSync)(deps.recordPath, archive);
47294
47368
  record2 = void 0;
47295
47369
  }
47296
47370
  if (record2 && !record2.pinPr && !record2.leadRcTag && record2.members.every((m) => !m.tag)) {
47297
- (0, import_node_fs35.rmSync)(deps.recordPath, { force: true });
47371
+ (0, import_node_fs36.rmSync)(deps.recordPath, { force: true });
47298
47372
  record2 = void 0;
47299
47373
  }
47300
47374
  if (!record2) {
@@ -47348,7 +47422,7 @@ async function suiteRcandRun(deps, opts) {
47348
47422
  quiet.push(member);
47349
47423
  }
47350
47424
  if (record2.members.every((m) => m.carried || quiet.includes(m)) && await deps.contains(SUITE_REPO, record2.leadDevelopment, record2.leadPreviousRc)) {
47351
- (0, import_node_fs35.rmSync)(deps.recordPath, { force: true });
47425
+ (0, import_node_fs36.rmSync)(deps.recordPath, { force: true });
47352
47426
  throw new Error("nothing to promote: neither MM-Work nor any module has new development commits since its rc; no suite cut started");
47353
47427
  }
47354
47428
  for (const member of quiet) {
@@ -47366,7 +47440,7 @@ async function suiteRcandRun(deps, opts) {
47366
47440
  }
47367
47441
  if (refusals.length) {
47368
47442
  const untouched = record2.members.every((m) => !m.tag) && !record2.pinPr;
47369
- if (untouched) (0, import_node_fs35.rmSync)(deps.recordPath, { force: true });
47443
+ if (untouched) (0, import_node_fs36.rmSync)(deps.recordPath, { force: true });
47370
47444
  throw new Error(`module rc serving is not ready; ${untouched ? "no suite cut started" : "no new tag was cut"}:
47371
47445
  ${refusals.join("\n")}
47372
47446
  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).`);
@@ -47562,7 +47636,7 @@ var hotfixRecordPath = (deps) => (0, import_node_path33.join)((0, import_node_pa
47562
47636
  function readSuiteHotfix(path2) {
47563
47637
  let raw;
47564
47638
  try {
47565
- raw = (0, import_node_fs35.readFileSync)(path2, "utf8");
47639
+ raw = (0, import_node_fs36.readFileSync)(path2, "utf8");
47566
47640
  } catch (e) {
47567
47641
  if (e.code === "ENOENT") return void 0;
47568
47642
  throw e;
@@ -47605,7 +47679,7 @@ async function suiteHotfix(deps, opts) {
47605
47679
  if (completed) record2 = void 0;
47606
47680
  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`);
47607
47681
  if (!record2?.tag) await deps.validateHotfixSummary();
47608
- if (completed) (0, import_node_fs35.renameSync)(path2, `${path2}.${completed.leadTag}.json`);
47682
+ if (completed) (0, import_node_fs36.renameSync)(path2, `${path2}.${completed.leadTag}.json`);
47609
47683
  const rec = record2 ?? { schema: "mmi-suite-hotfix/v1", member: found.id, repo: found.repo, from: opts.from, ...opts.ack?.length ? { ack: opts.ack } : {} };
47610
47684
  const save = () => writeSuiteHotfix(path2, rec);
47611
47685
  save();
@@ -47874,7 +47948,7 @@ async function runRcDataSwitch(deps, opts) {
47874
47948
  // src/suite-train-io.ts
47875
47949
  var import_node_child_process18 = require("node:child_process");
47876
47950
  var import_node_path46 = require("node:path");
47877
- var import_node_fs48 = require("node:fs");
47951
+ var import_node_fs49 = require("node:fs");
47878
47952
  var import_node_path47 = require("node:path");
47879
47953
  init_cli_shared();
47880
47954
 
@@ -48960,6 +49034,15 @@ async function runHotfixReleaseLocked(deps, versionInput, options, doctor) {
48960
49034
  const invented = announceSummaryFidelity(lines2, rangeLog);
48961
49035
  if (invented) throw new Error(invented);
48962
49036
  }
49037
+ try {
49038
+ await runPreTagHook(deps, { releaseSha: mergedSha });
49039
+ } catch (e) {
49040
+ throw new Error(
49041
+ `${e instanceof Error ? e.message : String(e)}
49042
+
49043
+ hotfix: origin/main already carries ${mergedSha.slice(0, 12)} (the hotfix PR merged), but nothing was tagged, no Release was created and nothing was published \u2014 fix the check above and rerun \`mmi-cli devops hotfix release ${tag}\`.`
49044
+ );
49045
+ }
48963
49046
  const anchors = { repo: ctx.repo, tag, tagSha: mergedSha };
48964
49047
  const start = await startReleaseLedger(ledger, anchors, { lane: "hotfix" });
48965
49048
  if (!start.ok) {
@@ -49558,7 +49641,7 @@ function checkHotfixCarries(options) {
49558
49641
  }
49559
49642
 
49560
49643
  // src/merge-cleanup.ts
49561
- var import_node_fs37 = require("node:fs");
49644
+ var import_node_fs38 = require("node:fs");
49562
49645
  var import_node_path35 = require("node:path");
49563
49646
  var import_node_os20 = require("node:os");
49564
49647
  init_cli_shared();
@@ -50047,7 +50130,7 @@ function renderPrLandTable(entries) {
50047
50130
 
50048
50131
  // src/test-policy-core.ts
50049
50132
  var import_node_child_process13 = require("node:child_process");
50050
- var import_node_fs36 = require("node:fs");
50133
+ var import_node_fs37 = require("node:fs");
50051
50134
  var import_node_path34 = require("node:path");
50052
50135
 
50053
50136
  // src/test-command-policy-shared.mjs
@@ -50617,7 +50700,7 @@ function loadPolicySource(root, explicitRef, diffBase) {
50617
50700
  }
50618
50701
  function readFileOrNull2(path2) {
50619
50702
  try {
50620
- return (0, import_node_fs36.readFileSync)(path2, "utf8");
50703
+ return (0, import_node_fs37.readFileSync)(path2, "utf8");
50621
50704
  } catch {
50622
50705
  return null;
50623
50706
  }
@@ -50645,10 +50728,10 @@ function classify(changed, policy, present = () => false) {
50645
50728
  const removedProtected = [...removed].filter((p) => protectedBy.has(p)).map((p) => ({ path: p, why: protectedBy.get(p) ?? "" }));
50646
50729
  return { mandatoryHits, untestedHits, testChanges, meaningfulTestChanges, addedTests, removedProtected };
50647
50730
  }
50648
- function unresolvedProtectedEntries(policy, root, exists = (path2) => (0, import_node_fs36.existsSync)(path2)) {
50731
+ function unresolvedProtectedEntries(policy, root, exists = (path2) => (0, import_node_fs37.existsSync)(path2)) {
50649
50732
  return (policy.protected ?? []).map((p) => p.path).filter((p) => !exists((0, import_node_path34.join)(root, p)));
50650
50733
  }
50651
- function unresolvedSatisfiers(policy, root, exists = (path2) => (0, import_node_fs36.existsSync)(path2)) {
50734
+ function unresolvedSatisfiers(policy, root, exists = (path2) => (0, import_node_fs37.existsSync)(path2)) {
50652
50735
  const declared = (policy.mandatory ?? []).flatMap((m) => m.satisfiedBy ?? []);
50653
50736
  return [...new Set(declared)].filter((p) => !exists((0, import_node_path34.join)(root, p)));
50654
50737
  }
@@ -50789,7 +50872,7 @@ function runTestPolicy(root, deps = {}) {
50789
50872
  }
50790
50873
  const loaded = deps.policy ? { policy: deps.policy, source: { ref: null, sha: null, path: POLICY_FILE } } : loadPolicySource(root, deps.policyRef, deps.base);
50791
50874
  const { policy, source: policySource } = loaded;
50792
- const exists = deps.exists ?? ((path2) => (0, import_node_fs36.existsSync)(path2));
50875
+ const exists = deps.exists ?? ((path2) => (0, import_node_fs37.existsSync)(path2));
50793
50876
  const counts = { mandatoryCount: (policy.mandatory ?? []).length, protectedCount: (policy.protected ?? []).length };
50794
50877
  const base = deps.changed ? "(injected)" : deps.policyRef ? resolveHotfixBase(root) : resolveBase(root, deps.base);
50795
50878
  const refusal = deps.changed ? null : untrustworthyRange(root, base);
@@ -51086,13 +51169,13 @@ function resolveSquashMergeBodyText(commits, allowedClosing, cwd) {
51086
51169
  return rewritten === base ? null : rewritten;
51087
51170
  }
51088
51171
  function writeSquashBodyFile(body) {
51089
- const dir = (0, import_node_fs37.mkdtempSync)((0, import_node_path35.join)((0, import_node_os20.tmpdir)(), "mmi-squash-body-"));
51172
+ const dir = (0, import_node_fs38.mkdtempSync)((0, import_node_path35.join)((0, import_node_os20.tmpdir)(), "mmi-squash-body-"));
51090
51173
  const path2 = (0, import_node_path35.join)(dir, "body.txt");
51091
- (0, import_node_fs37.writeFileSync)(path2, body.endsWith("\n") ? body : `${body}
51174
+ (0, import_node_fs38.writeFileSync)(path2, body.endsWith("\n") ? body : `${body}
51092
51175
  `, "utf8");
51093
51176
  return { path: path2, cleanup: () => {
51094
51177
  try {
51095
- (0, import_node_fs37.rmSync)(dir, { recursive: true, force: true });
51178
+ (0, import_node_fs38.rmSync)(dir, { recursive: true, force: true });
51096
51179
  } catch {
51097
51180
  }
51098
51181
  } };
@@ -51434,7 +51517,7 @@ function pinnedGitHubGetJson(token, fetchImpl = fetch) {
51434
51517
  var HUB_RELEASE_CI_ANNOUNCE_DEFERRED = "announcement deferred: the Hub cannot authorize a release-workflow session to post yet (#9138); the curated summary is in this run's step summary";
51435
51518
 
51436
51519
  // src/project-info-sync.ts
51437
- var import_node_fs38 = require("node:fs");
51520
+ var import_node_fs39 = require("node:fs");
51438
51521
  var import_node_path36 = require("node:path");
51439
51522
  var UPDATE_PROJECT_INFO = `mutation($projectId: ID!, $shortDescription: String!, $readme: String!) {
51440
51523
  updateProjectV2(input: { projectId: $projectId, shortDescription: $shortDescription, readme: $readme }) {
@@ -51483,13 +51566,13 @@ function sharedName(entries, fallback) {
51483
51566
  function buildProjectInfoSyncPlan(targetRepo2, project2, projects, repoRoot2) {
51484
51567
  if (!project2.projectId) throw new Error(`org project sync-info: ${targetRepo2} registry META has no projectId`);
51485
51568
  const readmePath = (0, import_node_path36.join)(repoRoot2, "README.md");
51486
- if (!(0, import_node_fs38.existsSync)(readmePath)) throw new Error(`org project sync-info: ${targetRepo2} has no README.md`);
51569
+ if (!(0, import_node_fs39.existsSync)(readmePath)) throw new Error(`org project sync-info: ${targetRepo2} has no README.md`);
51487
51570
  const entries = entriesFor(project2, projects);
51488
51571
  const memberRepos = [...new Set(entries.flatMap((entry) => entry.repos ?? []))].filter((repo) => /^[^/]+\/[^/]+$/.test(repo)).sort((a, b) => a.localeCompare(b));
51489
51572
  const projectName = sharedName(entries, project2.name?.trim() || targetRepo2.split("/").pop() || targetRepo2);
51490
51573
  if (!memberRepos.length) throw new Error(`org project sync-info: project ${projectName} has no registered member repos`);
51491
51574
  const entryNames = entries.map((entry) => entry.name?.trim()).filter((name) => Boolean(name));
51492
- const shortDescription = memberRepos.length === 1 ? shortDescriptionFromReadme((0, import_node_fs38.readFileSync)(readmePath, "utf8")) : `Shared work across ${new Intl.ListFormat("en", { type: "conjunction" }).format(entryNames)}.`;
51575
+ const shortDescription = memberRepos.length === 1 ? shortDescriptionFromReadme((0, import_node_fs39.readFileSync)(readmePath, "utf8")) : `Shared work across ${new Intl.ListFormat("en", { type: "conjunction" }).format(entryNames)}.`;
51493
51576
  const lines2 = [
51494
51577
  `# ${projectName}`,
51495
51578
  "",
@@ -51508,8 +51591,8 @@ function buildProjectInfoSyncPlan(targetRepo2, project2, projects, repoRoot2) {
51508
51591
  const targetBase = `https://github.com/${targetRepo2}`;
51509
51592
  const targetBranch = branchFor(targetRepo2, projects);
51510
51593
  const orgDocs = [
51511
- (0, import_node_fs38.existsSync)((0, import_node_path36.join)(repoRoot2, "architecture.md")) ? `- [Hub architecture](${targetBase}/blob/${targetBranch}/architecture.md)` : "",
51512
- (0, import_node_fs38.existsSync)((0, import_node_path36.join)(repoRoot2, "docs", "Architecture", "agentic-dev-environment.md")) ? `- [Agentic development environment](${targetBase}/blob/${targetBranch}/docs/Architecture/agentic-dev-environment.md)` : ""
51594
+ (0, import_node_fs39.existsSync)((0, import_node_path36.join)(repoRoot2, "architecture.md")) ? `- [Hub architecture](${targetBase}/blob/${targetBranch}/architecture.md)` : "",
51595
+ (0, import_node_fs39.existsSync)((0, import_node_path36.join)(repoRoot2, "docs", "Architecture", "agentic-dev-environment.md")) ? `- [Agentic development environment](${targetBase}/blob/${targetBranch}/docs/Architecture/agentic-dev-environment.md)` : ""
51513
51596
  ].filter(Boolean);
51514
51597
  if (orgDocs.length) lines2.push("", "## Organisation docs", "", ...orgDocs);
51515
51598
  return { projectId: project2.projectId, projectName, targetRepo: targetRepo2, memberRepos, shortDescription, readme: `${lines2.join("\n")}
@@ -51531,7 +51614,7 @@ async function syncProjectInfo(plan, client, apply) {
51531
51614
  }
51532
51615
 
51533
51616
  // src/train-commands.ts
51534
- var import_node_fs39 = require("node:fs");
51617
+ var import_node_fs40 = require("node:fs");
51535
51618
  var import_node_path37 = require("node:path");
51536
51619
  init_cli_shared();
51537
51620
  init_clean_exit();
@@ -51547,7 +51630,7 @@ function resolveReleaseBumpIntent(raw) {
51547
51630
  }
51548
51631
  function readRepoVersion() {
51549
51632
  try {
51550
- return JSON.parse((0, import_node_fs39.readFileSync)((0, import_node_path37.join)(process.cwd(), ".claude-plugin", "plugin.json"), "utf8")).version || void 0;
51633
+ return JSON.parse((0, import_node_fs40.readFileSync)((0, import_node_path37.join)(process.cwd(), ".claude-plugin", "plugin.json"), "utf8")).version || void 0;
51551
51634
  } catch {
51552
51635
  return void 0;
51553
51636
  }
@@ -51921,7 +52004,7 @@ function prTitleRefusal(title) {
51921
52004
 
51922
52005
  // src/command-register-collaboration.ts
51923
52006
  var import_node_child_process17 = require("node:child_process");
51924
- var import_node_fs47 = require("node:fs");
52007
+ var import_node_fs48 = require("node:fs");
51925
52008
  var import_promises8 = require("node:fs/promises");
51926
52009
  init_clean_exit();
51927
52010
  init_cli_shared();
@@ -52062,7 +52145,7 @@ init_github_client();
52062
52145
  init_github_quota();
52063
52146
 
52064
52147
  // src/issue-commands.ts
52065
- var import_node_fs40 = require("node:fs");
52148
+ var import_node_fs41 = require("node:fs");
52066
52149
  var import_node_crypto16 = require("node:crypto");
52067
52150
  init_cli_shared();
52068
52151
  init_clean_exit();
@@ -52255,7 +52338,7 @@ async function editIssue(client, options, deps = {}) {
52255
52338
  const url = `https://github.com/${repo}/issues/${parsed.number}`;
52256
52339
  const patch = {};
52257
52340
  let bodyChanged = false;
52258
- const textDeps = () => deps.textDeps ?? { readFile: (p, e) => Promise.resolve((0, import_node_fs40.readFileSync)(p, e)), readStdin: () => Promise.resolve("") };
52341
+ const textDeps = () => deps.textDeps ?? { readFile: (p, e) => Promise.resolve((0, import_node_fs41.readFileSync)(p, e)), readStdin: () => Promise.resolve("") };
52259
52342
  if (options.titleFile !== void 0) {
52260
52343
  patch.title = await resolveIssueTitle({ title: options.title, titleFile: options.titleFile }, textDeps());
52261
52344
  } else if (options.title !== void 0) {
@@ -52918,7 +53001,7 @@ function extendCreateCommand(issue, batchAttach) {
52918
53001
  if (opts.batch) {
52919
53002
  let specs;
52920
53003
  try {
52921
- const raw = (0, import_node_fs40.readFileSync)(opts.batch, "utf8");
53004
+ const raw = (0, import_node_fs41.readFileSync)(opts.batch, "utf8");
52922
53005
  specs = JSON.parse(raw);
52923
53006
  if (!Array.isArray(specs)) {
52924
53007
  const top = specs === null ? "null" : typeof specs === "object" ? `an object with keys: ${Object.keys(specs).join(", ") || "(none)"}` : `a ${typeof specs}`;
@@ -52995,7 +53078,7 @@ ${lines2}`, {
52995
53078
  }
52996
53079
 
52997
53080
  // src/post-merge-recon.ts
52998
- var import_node_fs41 = require("node:fs");
53081
+ var import_node_fs42 = require("node:fs");
52999
53082
  var import_node_path39 = require("node:path");
53000
53083
 
53001
53084
  // src/cross-repo-filing-issue.ts
@@ -53165,16 +53248,16 @@ function buildPostMergeReconRecovery(input) {
53165
53248
  }
53166
53249
  function writePostMergeReconRecovery(cwd, recovery) {
53167
53250
  const path2 = postMergeReconStatePath(cwd, recovery.repo, recovery.pr);
53168
- (0, import_node_fs41.mkdirSync)((0, import_node_path39.dirname)(path2), { recursive: true });
53169
- (0, import_node_fs41.writeFileSync)(path2, `${JSON.stringify(recovery, null, 2)}
53251
+ (0, import_node_fs42.mkdirSync)((0, import_node_path39.dirname)(path2), { recursive: true });
53252
+ (0, import_node_fs42.writeFileSync)(path2, `${JSON.stringify(recovery, null, 2)}
53170
53253
  `, "utf8");
53171
53254
  return path2;
53172
53255
  }
53173
53256
  function clearPostMergeReconRecovery(cwd, repo, pr) {
53174
53257
  const path2 = postMergeReconStatePath(cwd, repo, pr);
53175
- if (!(0, import_node_fs41.existsSync)(path2)) return;
53258
+ if (!(0, import_node_fs42.existsSync)(path2)) return;
53176
53259
  try {
53177
- (0, import_node_fs41.unlinkSync)(path2);
53260
+ (0, import_node_fs42.unlinkSync)(path2);
53178
53261
  } catch {
53179
53262
  }
53180
53263
  }
@@ -53650,7 +53733,7 @@ function registerPrLifecycleCommands(program3) {
53650
53733
 
53651
53734
  // src/review-verdict.ts
53652
53735
  var import_node_child_process14 = require("node:child_process");
53653
- var import_node_fs42 = require("node:fs");
53736
+ var import_node_fs43 = require("node:fs");
53654
53737
  var import_node_os22 = require("node:os");
53655
53738
  var import_node_path40 = require("node:path");
53656
53739
  init_cli_shared();
@@ -53817,15 +53900,15 @@ async function readPrIssueComments(number, repo) {
53817
53900
  return comments;
53818
53901
  }
53819
53902
  async function postPrCommentFromFile(number, repo, body) {
53820
- const dir = (0, import_node_fs42.mkdtempSync)((0, import_node_path40.join)((0, import_node_os22.tmpdir)(), "mmi-review-verdict-"));
53903
+ const dir = (0, import_node_fs43.mkdtempSync)((0, import_node_path40.join)((0, import_node_os22.tmpdir)(), "mmi-review-verdict-"));
53821
53904
  const path2 = (0, import_node_path40.join)(dir, "body.md");
53822
53905
  try {
53823
- (0, import_node_fs42.writeFileSync)(path2, body, "utf8");
53906
+ (0, import_node_fs43.writeFileSync)(path2, body, "utf8");
53824
53907
  const { stdout } = await execFileP("gh", ["pr", "comment", number, "--repo", repo, "--body-file", path2], { timeout: GH_MUTATION_TIMEOUT_MS });
53825
53908
  return stdout.trim();
53826
53909
  } finally {
53827
53910
  try {
53828
- (0, import_node_fs42.rmSync)(dir, { recursive: true, force: true });
53911
+ (0, import_node_fs43.rmSync)(dir, { recursive: true, force: true });
53829
53912
  } catch {
53830
53913
  }
53831
53914
  }
@@ -54063,17 +54146,17 @@ async function prCreateClaimRefusal(body, repoOption, deps = {}) {
54063
54146
  }
54064
54147
 
54065
54148
  // src/worktree-residue-sweep.ts
54066
- var import_node_fs46 = require("node:fs");
54149
+ var import_node_fs47 = require("node:fs");
54067
54150
  var import_node_path44 = require("node:path");
54068
54151
 
54069
54152
  // src/worktree-merge-cleanup.ts
54070
- var import_node_fs45 = require("node:fs");
54153
+ var import_node_fs46 = require("node:fs");
54071
54154
  var import_node_path43 = require("node:path");
54072
54155
  init_cli_shared();
54073
54156
 
54074
54157
  // src/stage-runner.ts
54075
54158
  var import_node_child_process16 = require("node:child_process");
54076
- var import_node_fs44 = require("node:fs");
54159
+ var import_node_fs45 = require("node:fs");
54077
54160
  var import_node_path42 = require("node:path");
54078
54161
  var import_node_net = require("node:net");
54079
54162
  var import_node_util5 = require("node:util");
@@ -54084,7 +54167,7 @@ function normalizeEol2(s) {
54084
54167
  }
54085
54168
 
54086
54169
  // src/env-detection.ts
54087
- var import_node_fs43 = require("node:fs");
54170
+ var import_node_fs44 = require("node:fs");
54088
54171
  var import_node_path41 = require("node:path");
54089
54172
  var SKIPPED_DIRS = /* @__PURE__ */ new Set([".git", "node_modules", "dist", ".jerv", ".pi", ".venv", "venv"]);
54090
54173
  function isEnvBaseName(name) {
@@ -54095,7 +54178,7 @@ function findEnvFiles(root) {
54095
54178
  const walk2 = (dir, rel) => {
54096
54179
  let entries;
54097
54180
  try {
54098
- entries = (0, import_node_fs43.readdirSync)(dir, { withFileTypes: true });
54181
+ entries = (0, import_node_fs44.readdirSync)(dir, { withFileTypes: true });
54099
54182
  } catch {
54100
54183
  return;
54101
54184
  }
@@ -54109,7 +54192,7 @@ function findEnvFiles(root) {
54109
54192
  if (isEnvBaseName(entry.name)) {
54110
54193
  let isDir = false;
54111
54194
  try {
54112
- isDir = (0, import_node_fs43.lstatSync)((0, import_node_path41.join)(dir, entry.name)).isDirectory();
54195
+ isDir = (0, import_node_fs44.lstatSync)((0, import_node_path41.join)(dir, entry.name)).isDirectory();
54113
54196
  } catch {
54114
54197
  }
54115
54198
  if (!isDir) found.push(relPath);
@@ -54248,12 +54331,12 @@ var DOCKER_TIMEOUT_MS = 15e3;
54248
54331
  function stageBash() {
54249
54332
  if (process.platform !== "win32") return "bash";
54250
54333
  const configured = process.env.SHELL;
54251
- if (configured && (0, import_node_path42.isAbsolute)(configured) && /[/\\]bash(?:\.exe)?$/i.test(configured) && !/[/\\](?:System32|Sysnative)[/\\]bash(?:\.exe)?$/i.test(configured) && (0, import_node_fs44.existsSync)(configured)) return configured;
54334
+ if (configured && (0, import_node_path42.isAbsolute)(configured) && /[/\\]bash(?:\.exe)?$/i.test(configured) && !/[/\\](?:System32|Sysnative)[/\\]bash(?:\.exe)?$/i.test(configured) && (0, import_node_fs45.existsSync)(configured)) return configured;
54252
54335
  const candidates = [
54253
54336
  (0, import_node_path42.join)(process.env.ProgramFiles || "C:\\Program Files", "Git", "bin", "bash.exe"),
54254
54337
  ...process.env.LOCALAPPDATA ? [(0, import_node_path42.join)(process.env.LOCALAPPDATA, "Programs", "Git", "bin", "bash.exe")] : []
54255
54338
  ];
54256
- const bash = candidates.find((path2) => (0, import_node_fs44.existsSync)(path2));
54339
+ const bash = candidates.find((path2) => (0, import_node_fs45.existsSync)(path2));
54257
54340
  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.");
54258
54341
  return bash;
54259
54342
  }
@@ -54609,7 +54692,7 @@ function stageProcessEnv(stagePort, extraEnv) {
54609
54692
  function composeResolvesPort(cwd) {
54610
54693
  if (process.env.PORT) return true;
54611
54694
  const envFile = (0, import_node_path42.join)(cwd, ".env");
54612
- return (0, import_node_fs44.existsSync)(envFile) && envFileKeys((0, import_node_fs44.readFileSync)(envFile, "utf8")).has("PORT");
54695
+ return (0, import_node_fs45.existsSync)(envFile) && envFileKeys((0, import_node_fs45.readFileSync)(envFile, "utf8")).has("PORT");
54613
54696
  }
54614
54697
  function stageComposeEnv(config, stagePort, vaultEnvMerge, cwd) {
54615
54698
  const composeProject = config.env?.COMPOSE_PROJECT_NAME ?? vaultEnvMerge?.COMPOSE_PROJECT_NAME ?? stageComposeProjectName(cwd);
@@ -54624,13 +54707,13 @@ function stageComposeEnv(config, stagePort, vaultEnvMerge, cwd) {
54624
54707
  function stageComposeFiles(cwd) {
54625
54708
  const files = ["docker-compose.yml"];
54626
54709
  for (const conventional of ["docker-compose.override.yml", "docker-compose.override.yaml"]) {
54627
- if ((0, import_node_fs44.existsSync)((0, import_node_path42.join)(cwd, conventional))) files.push(conventional);
54710
+ if ((0, import_node_fs45.existsSync)((0, import_node_path42.join)(cwd, conventional))) files.push(conventional);
54628
54711
  }
54629
54712
  return [...files, RUNTIME_ENV_OVERRIDE_RELPATH];
54630
54713
  }
54631
54714
  async function prepareRuntimeEnvPassthrough(cwd, composeEnv, vaultEnvMerge) {
54632
54715
  const keys = Object.keys(vaultEnvMerge ?? {});
54633
- if (!keys.length || !(0, import_node_fs44.existsSync)((0, import_node_path42.join)(cwd, "docker-compose.yml"))) return {};
54716
+ if (!keys.length || !(0, import_node_fs45.existsSync)((0, import_node_path42.join)(cwd, "docker-compose.yml"))) return {};
54634
54717
  let configJson;
54635
54718
  try {
54636
54719
  const { stdout } = await execFileP3("docker", ["compose", "config", "--format", "json"], {
@@ -54647,20 +54730,20 @@ async function prepareRuntimeEnvPassthrough(cwd, composeEnv, vaultEnvMerge) {
54647
54730
  const body = renderRuntimeEnvOverride(runtimeEnvMarkedServices(configJson), keys, runtimeEnvExcludes(configJson), runtimeEnvSelects(configJson));
54648
54731
  if (!body) return {};
54649
54732
  const overridePath = (0, import_node_path42.join)(cwd, RUNTIME_ENV_OVERRIDE_RELPATH);
54650
- (0, import_node_fs44.mkdirSync)((0, import_node_path42.join)(cwd, "tmp", "stage"), { recursive: true });
54651
- (0, import_node_fs44.writeFileSync)(overridePath, body, "utf8");
54733
+ (0, import_node_fs45.mkdirSync)((0, import_node_path42.join)(cwd, "tmp", "stage"), { recursive: true });
54734
+ (0, import_node_fs45.writeFileSync)(overridePath, body, "utf8");
54652
54735
  return stageComposeFileEnv(stageComposeFiles(cwd));
54653
54736
  }
54654
54737
  async function ensureStageRuntimeEnv(config, opts, cwd) {
54655
54738
  if (!config.ensureEnv) return;
54656
54739
  const target = (0, import_node_path42.join)(cwd, config.ensureEnv.target);
54657
54740
  const example = (0, import_node_path42.join)(cwd, config.ensureEnv.example);
54658
- if (!(0, import_node_fs44.existsSync)(target) && (0, import_node_fs44.existsSync)(example)) {
54659
- (0, import_node_fs44.copyFileSync)(example, target);
54660
- } else if ((0, import_node_fs44.existsSync)(target) && (0, import_node_fs44.existsSync)(example)) {
54661
- const stale = detectStaleEnvFile((0, import_node_fs44.readFileSync)(example, "utf8"), (0, import_node_fs44.readFileSync)(target, "utf8"), {
54662
- exampleMtimeMs: (0, import_node_fs44.statSync)(example).mtimeMs,
54663
- targetMtimeMs: (0, import_node_fs44.statSync)(target).mtimeMs
54741
+ if (!(0, import_node_fs45.existsSync)(target) && (0, import_node_fs45.existsSync)(example)) {
54742
+ (0, import_node_fs45.copyFileSync)(example, target);
54743
+ } else if ((0, import_node_fs45.existsSync)(target) && (0, import_node_fs45.existsSync)(example)) {
54744
+ const stale = detectStaleEnvFile((0, import_node_fs45.readFileSync)(example, "utf8"), (0, import_node_fs45.readFileSync)(target, "utf8"), {
54745
+ exampleMtimeMs: (0, import_node_fs45.statSync)(example).mtimeMs,
54746
+ targetMtimeMs: (0, import_node_fs45.statSync)(target).mtimeMs
54664
54747
  });
54665
54748
  if (stale) {
54666
54749
  const msg = `stale ${config.ensureEnv.target} (${stale}) \u2014 delete it or refresh from ${config.ensureEnv.example} before re-running mmi-cli stage`;
@@ -54668,8 +54751,8 @@ async function ensureStageRuntimeEnv(config, opts, cwd) {
54668
54751
  console.error(`mmi-cli stage: ${msg} (allowed via --allow-stale-env)`);
54669
54752
  }
54670
54753
  }
54671
- if (opts.vaultEnvMerge && Object.keys(opts.vaultEnvMerge).length && (0, import_node_fs44.existsSync)(target)) {
54672
- (0, import_node_fs44.writeFileSync)(target, mergeEnvSecretsIntoFile((0, import_node_fs44.readFileSync)(target, "utf8"), opts.vaultEnvMerge), "utf8");
54754
+ if (opts.vaultEnvMerge && Object.keys(opts.vaultEnvMerge).length && (0, import_node_fs45.existsSync)(target)) {
54755
+ (0, import_node_fs45.writeFileSync)(target, mergeEnvSecretsIntoFile((0, import_node_fs45.readFileSync)(target, "utf8"), opts.vaultEnvMerge), "utf8");
54673
54756
  }
54674
54757
  }
54675
54758
  async function gitText(cwd, args) {
@@ -54699,20 +54782,20 @@ async function resolveGlobalStatePath(cwd, explicit) {
54699
54782
  return void 0;
54700
54783
  }
54701
54784
  function readState(path2) {
54702
- if (!(0, import_node_fs44.existsSync)(path2)) return null;
54785
+ if (!(0, import_node_fs45.existsSync)(path2)) return null;
54703
54786
  try {
54704
- return JSON.parse((0, import_node_fs44.readFileSync)(path2, "utf8"));
54787
+ return JSON.parse((0, import_node_fs45.readFileSync)(path2, "utf8"));
54705
54788
  } catch {
54706
54789
  return null;
54707
54790
  }
54708
54791
  }
54709
54792
  function mkdirFor(path2) {
54710
54793
  const dir = path2.slice(0, Math.max(path2.lastIndexOf("/"), path2.lastIndexOf("\\")));
54711
- (0, import_node_fs44.mkdirSync)(dir, { recursive: true });
54794
+ (0, import_node_fs45.mkdirSync)(dir, { recursive: true });
54712
54795
  }
54713
54796
  function writeState(path2, state) {
54714
54797
  mkdirFor(path2);
54715
- (0, import_node_fs44.writeFileSync)(path2, JSON.stringify(state, null, 2), "utf8");
54798
+ (0, import_node_fs45.writeFileSync)(path2, JSON.stringify(state, null, 2), "utf8");
54716
54799
  }
54717
54800
  function writeStagePortReservation(port, cwd, statePath, globalStatePath, now) {
54718
54801
  const reservation = {
@@ -54741,7 +54824,7 @@ async function cleanupStageState(state, paths, timeoutMs, fallbackCwd, currentEn
54741
54824
  );
54742
54825
  }
54743
54826
  for (const path2 of [...new Set(paths.filter((p) => Boolean(p)))]) {
54744
- (0, import_node_fs44.rmSync)(path2, { force: true });
54827
+ (0, import_node_fs45.rmSync)(path2, { force: true });
54745
54828
  }
54746
54829
  }
54747
54830
  async function killTree(pid) {
@@ -54988,8 +55071,8 @@ async function runStage(config = {}, opts = {}) {
54988
55071
  });
54989
55072
  }
54990
55073
  } catch (e) {
54991
- (0, import_node_fs44.rmSync)(statePath, { force: true });
54992
- if (globalStatePath && globalStatePath !== statePath) (0, import_node_fs44.rmSync)(globalStatePath, { force: true });
55074
+ (0, import_node_fs45.rmSync)(statePath, { force: true });
55075
+ if (globalStatePath && globalStatePath !== statePath) (0, import_node_fs45.rmSync)(globalStatePath, { force: true });
54993
55076
  throw e;
54994
55077
  }
54995
55078
  const started = await startStage(config, {
@@ -55010,7 +55093,7 @@ function normPath2(p) {
55010
55093
  function unlinkNodeModulesJunction(wtPath) {
55011
55094
  const nm = (0, import_node_path43.join)(wtPath, "node_modules");
55012
55095
  try {
55013
- if ((0, import_node_fs45.lstatSync)(nm).isSymbolicLink()) (0, import_node_fs45.rmdirSync)(nm);
55096
+ if ((0, import_node_fs46.lstatSync)(nm).isSymbolicLink()) (0, import_node_fs46.rmdirSync)(nm);
55014
55097
  return { ok: true };
55015
55098
  } catch (e) {
55016
55099
  if (e.code === "ENOENT") return { ok: true };
@@ -55021,8 +55104,8 @@ function defaultSleep2(ms) {
55021
55104
  return new Promise((resolve7) => setTimeout(resolve7, ms));
55022
55105
  }
55023
55106
  async function removeResidueDirectory(wtPath, options = {}) {
55024
- const { sleep: sleep2 = defaultSleep2, removeEmptyDir = import_node_fs45.rmdirSync, exists = import_node_fs45.existsSync } = options;
55025
- const removeRecursive = options.removeRecursive ?? ((path2) => (0, import_node_fs45.rmSync)(path2, { recursive: true, force: true, maxRetries: 10, retryDelay: 100 }));
55107
+ const { sleep: sleep2 = defaultSleep2, removeEmptyDir = import_node_fs46.rmdirSync, exists = import_node_fs46.existsSync } = options;
55108
+ const removeRecursive = options.removeRecursive ?? ((path2) => (0, import_node_fs46.rmSync)(path2, { recursive: true, force: true, maxRetries: 10, retryDelay: 100 }));
55026
55109
  const junction = unlinkNodeModulesJunction(wtPath);
55027
55110
  if (!junction.ok) return junction;
55028
55111
  try {
@@ -55148,21 +55231,21 @@ async function listNestedIgnoredNodeModules(wtPath, execGit) {
55148
55231
  return out.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.endsWith("node_modules/") && line !== "node_modules/").map((line) => (0, import_node_path43.join)(wtPath, line.slice(0, -1)));
55149
55232
  }
55150
55233
  function safeRemoveTree(path2) {
55151
- const stat4 = (0, import_node_fs45.lstatSync)(path2);
55234
+ const stat4 = (0, import_node_fs46.lstatSync)(path2);
55152
55235
  if (stat4.isSymbolicLink()) {
55153
55236
  try {
55154
- (0, import_node_fs45.rmdirSync)(path2);
55237
+ (0, import_node_fs46.rmdirSync)(path2);
55155
55238
  } catch {
55156
- (0, import_node_fs45.unlinkSync)(path2);
55239
+ (0, import_node_fs46.unlinkSync)(path2);
55157
55240
  }
55158
55241
  return;
55159
55242
  }
55160
55243
  if (stat4.isDirectory()) {
55161
- for (const entry of (0, import_node_fs45.readdirSync)(path2)) safeRemoveTree((0, import_node_path43.join)(path2, entry));
55162
- (0, import_node_fs45.rmdirSync)(path2);
55244
+ for (const entry of (0, import_node_fs46.readdirSync)(path2)) safeRemoveTree((0, import_node_path43.join)(path2, entry));
55245
+ (0, import_node_fs46.rmdirSync)(path2);
55163
55246
  return;
55164
55247
  }
55165
- (0, import_node_fs45.unlinkSync)(path2);
55248
+ (0, import_node_fs46.unlinkSync)(path2);
55166
55249
  }
55167
55250
  async function removeWorktreeNodeModules(wtPath) {
55168
55251
  try {
@@ -55178,7 +55261,7 @@ function errorMessage(e) {
55178
55261
  }
55179
55262
  function resolvedOrRaw(path2) {
55180
55263
  try {
55181
- return normPath2((0, import_node_fs45.realpathSync)(path2));
55264
+ return normPath2((0, import_node_fs46.realpathSync)(path2));
55182
55265
  } catch {
55183
55266
  return normPath2(path2);
55184
55267
  }
@@ -55186,10 +55269,10 @@ function resolvedOrRaw(path2) {
55186
55269
  function unlinkEscapingReparsePoints(root, primaryRoot) {
55187
55270
  let realRoot;
55188
55271
  try {
55189
- if ((0, import_node_fs45.lstatSync)(root).isSymbolicLink()) {
55272
+ if ((0, import_node_fs46.lstatSync)(root).isSymbolicLink()) {
55190
55273
  return { ok: false, error: `delete root ${normPath2(root)} is a reparse point resolving to ${resolvedOrRaw(root)}` };
55191
55274
  }
55192
- realRoot = normPath2((0, import_node_fs45.realpathSync)(root));
55275
+ realRoot = normPath2((0, import_node_fs46.realpathSync)(root));
55193
55276
  } catch (e) {
55194
55277
  if (e.code === "ENOENT") return { ok: true, unlinked: [] };
55195
55278
  return { ok: false, error: `cannot resolve delete root ${normPath2(root)}: ${errorMessage(e)}` };
@@ -55205,7 +55288,7 @@ function unlinkEscapingReparsePoints(root, primaryRoot) {
55205
55288
  const dir = stack.pop();
55206
55289
  let entries;
55207
55290
  try {
55208
- entries = (0, import_node_fs45.readdirSync)(dir, { withFileTypes: true });
55291
+ entries = (0, import_node_fs46.readdirSync)(dir, { withFileTypes: true });
55209
55292
  } catch (e) {
55210
55293
  if (e.code === "ENOENT") continue;
55211
55294
  return { ok: false, error: `cannot scan ${normPath2(dir)} for reparse points: ${errorMessage(e)}` };
@@ -55215,7 +55298,7 @@ function unlinkEscapingReparsePoints(root, primaryRoot) {
55215
55298
  if (entry.isSymbolicLink()) {
55216
55299
  let target = "";
55217
55300
  try {
55218
- target = normPath2((0, import_node_fs45.realpathSync)(child2));
55301
+ target = normPath2((0, import_node_fs46.realpathSync)(child2));
55219
55302
  } catch {
55220
55303
  target = "";
55221
55304
  }
@@ -55398,7 +55481,7 @@ async function cleanupPrMergeLocalBranch(branch, options) {
55398
55481
  return report;
55399
55482
  }
55400
55483
  const execGit = options.execGit ?? (async (args) => (await execFileP("git", args, { timeout: GIT_TIMEOUT_MS })).stdout);
55401
- const pathExists = options.pathExists ?? import_node_fs45.existsSync;
55484
+ const pathExists = options.pathExists ?? import_node_fs46.existsSync;
55402
55485
  let afterWorktrees = [];
55403
55486
  try {
55404
55487
  afterWorktrees = parseGitWorktreePorcelain(await execGit(["worktree", "list", "--porcelain"]));
@@ -55685,7 +55768,7 @@ function residueLedgerPath(gitCommonDir) {
55685
55768
  }
55686
55769
  function readPaths(file, deps) {
55687
55770
  try {
55688
- const parsed = JSON.parse((deps.readLedger ?? ((f) => (0, import_node_fs46.readFileSync)(f, "utf8")))(file));
55771
+ const parsed = JSON.parse((deps.readLedger ?? ((f) => (0, import_node_fs47.readFileSync)(f, "utf8")))(file));
55689
55772
  return Array.isArray(parsed) ? parsed.filter((p) => typeof p === "string") : [];
55690
55773
  } catch {
55691
55774
  return [];
@@ -55694,8 +55777,8 @@ function readPaths(file, deps) {
55694
55777
  function writePaths(file, paths, deps) {
55695
55778
  try {
55696
55779
  const write = deps.writeLedger ?? ((f, t) => {
55697
- (0, import_node_fs46.mkdirSync)((0, import_node_path44.dirname)(f), { recursive: true });
55698
- (0, import_node_fs46.writeFileSync)(f, t, "utf8");
55780
+ (0, import_node_fs47.mkdirSync)((0, import_node_path44.dirname)(f), { recursive: true });
55781
+ (0, import_node_fs47.writeFileSync)(f, t, "utf8");
55699
55782
  });
55700
55783
  write(file, `${JSON.stringify([...new Set(paths)], null, 1)}
55701
55784
  `);
@@ -55709,17 +55792,17 @@ function recordResidue(gitCommonDir, path2, deps = {}) {
55709
55792
  writePaths(file, paths, deps);
55710
55793
  }
55711
55794
  async function sweepWorktreeResidue(gitCommonDir, registered, deps = {}) {
55712
- const exists = deps.exists ?? import_node_fs46.existsSync;
55713
- const readDir = deps.readDir ?? ((p) => (0, import_node_fs46.readdirSync)(p));
55795
+ const exists = deps.exists ?? import_node_fs47.existsSync;
55796
+ const readDir = deps.readDir ?? ((p) => (0, import_node_fs47.readdirSync)(p));
55714
55797
  const isDir = deps.isDir ?? ((p) => {
55715
55798
  try {
55716
- return (0, import_node_fs46.statSync)(p).isDirectory();
55799
+ return (0, import_node_fs47.statSync)(p).isDirectory();
55717
55800
  } catch {
55718
55801
  return false;
55719
55802
  }
55720
55803
  });
55721
55804
  const removeRecorded = deps.removeRecorded ?? ((p) => removeResidueDirectory(p));
55722
- const removeEmpty = deps.removeEmpty ?? ((p) => (0, import_node_fs46.rmdirSync)(p));
55805
+ const removeEmpty = deps.removeEmpty ?? ((p) => (0, import_node_fs47.rmdirSync)(p));
55723
55806
  const report = { swept: [], kept: [], dropped: [], emptyRemoved: [], unrecorded: [] };
55724
55807
  const live = new Set(registered.map(norm));
55725
55808
  const primary = registered[0] ? norm(registered[0]) : void 0;
@@ -55799,8 +55882,8 @@ function argvWantsJson2() {
55799
55882
  function hubRoot() {
55800
55883
  const fromPkg = (0, import_node_path45.join)(__dirname, "..", "..");
55801
55884
  const marker = "skills/bootstrap/seeds/manifest.json";
55802
- if ((0, import_node_fs47.existsSync)((0, import_node_path45.join)(fromPkg, marker))) return fromPkg;
55803
- if ((0, import_node_fs47.existsSync)((0, import_node_path45.join)(process.cwd(), marker))) return process.cwd();
55885
+ if ((0, import_node_fs48.existsSync)((0, import_node_path45.join)(fromPkg, marker))) return fromPkg;
55886
+ if ((0, import_node_fs48.existsSync)((0, import_node_path45.join)(process.cwd(), marker))) return process.cwd();
55804
55887
  return null;
55805
55888
  }
55806
55889
  function ciAuditDeps() {
@@ -55813,7 +55896,7 @@ function ciAuditDeps() {
55813
55896
  readSeedFile: (path2) => {
55814
55897
  if (!root) return null;
55815
55898
  const fullPath = (0, import_node_path45.join)(root, path2);
55816
- return (0, import_node_fs47.existsSync)(fullPath) ? (0, import_node_fs47.readFileSync)(fullPath, "utf8") : null;
55899
+ return (0, import_node_fs48.existsSync)(fullPath) ? (0, import_node_fs48.readFileSync)(fullPath, "utf8") : null;
55817
55900
  }
55818
55901
  };
55819
55902
  }
@@ -56627,10 +56710,10 @@ ${list}`);
56627
56710
  });
56628
56711
  async function listCiWorkflowPaths(cwd = process.cwd()) {
56629
56712
  const wfDir = (0, import_node_path45.join)(cwd, ".github", "workflows");
56630
- if (!(0, import_node_fs47.existsSync)(wfDir)) return [];
56631
- return (0, import_node_fs47.readdirSync)(wfDir).filter((name) => /\.(ya?ml)$/i.test(name)).filter((name) => {
56713
+ if (!(0, import_node_fs48.existsSync)(wfDir)) return [];
56714
+ return (0, import_node_fs48.readdirSync)(wfDir).filter((name) => /\.(ya?ml)$/i.test(name)).filter((name) => {
56632
56715
  try {
56633
- return workflowReportsPrChecks((0, import_node_fs47.readFileSync)((0, import_node_path45.join)(wfDir, name), "utf8"));
56716
+ return workflowReportsPrChecks((0, import_node_fs48.readFileSync)((0, import_node_path45.join)(wfDir, name), "utf8"));
56634
56717
  } catch {
56635
56718
  return true;
56636
56719
  }
@@ -56835,7 +56918,7 @@ ${list}`);
56835
56918
  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) => {
56836
56919
  if (!isReviewVerdict(o.verdict)) return fail(`pr review-verdict: --verdict must be one of ${REVIEW_VERDICTS.join("|")} (got ${o.verdict})`);
56837
56920
  const verdict = o.verdict;
56838
- const findings = o.findingsFile ? (0, import_node_fs47.readFileSync)(o.findingsFile, "utf8") : void 0;
56921
+ const findings = o.findingsFile ? (0, import_node_fs48.readFileSync)(o.findingsFile, "utf8") : void 0;
56839
56922
  let patch;
56840
56923
  let head;
56841
56924
  try {
@@ -57110,7 +57193,7 @@ ${list}`);
57110
57193
  const cleanupMerged = async (r) => {
57111
57194
  if (opts.preserveWorktree) return "cleanup skipped (--preserve-worktree)";
57112
57195
  const ran = await execFileP(process.execPath, [process.argv[1], ...canonicalArgvFor(["pr", "merge", r.pr, "--repo", r.repo])], {
57113
- cwd: (0, import_node_fs47.existsSync)(cwd0) ? cwd0 : primaryRoot0,
57196
+ cwd: (0, import_node_fs48.existsSync)(cwd0) ? cwd0 : primaryRoot0,
57114
57197
  timeout: GH_MUTATION_TIMEOUT_MS * 3
57115
57198
  }).then((x) => ({ stdout: x.stdout, stderr: x.stderr }), (e) => ({ stdout: e.stdout ?? "", stderr: e.stderr ?? "" }));
57116
57199
  const json = ran.stdout.split("\n").reverse().find((l) => l.startsWith("{"));
@@ -57180,7 +57263,7 @@ ${list}`);
57180
57263
  const mergeSquashBody = squashBodyTextForMerge(
57181
57264
  closingGuardInput,
57182
57265
  method === "--squash",
57183
- o.squashBodyFile ? (0, import_node_fs47.readFileSync)(o.squashBodyFile, "utf8") : void 0
57266
+ o.squashBodyFile ? (0, import_node_fs48.readFileSync)(o.squashBodyFile, "utf8") : void 0
57184
57267
  );
57185
57268
  if (!o.squashBodyFile) warnSquashBodyClosingStrip("pr merge", closingGuardInput, mergeSquashBody);
57186
57269
  const closingGuardVerdict = evaluateClosingGuard(closingGuardInput, {
@@ -57331,7 +57414,7 @@ ${list}`);
57331
57414
  }
57332
57415
  if (!repoForPostCleanup) throw e;
57333
57416
  console.warn(`pr merge: gh GraphQL rate-limited \u2014 merging PR #${number} via REST PUT instead (#4588).`);
57334
- const commitMessage = bodyFile ? (0, import_node_fs47.readFileSync)(bodyFile, "utf8") : void 0;
57417
+ const commitMessage = bodyFile ? (0, import_node_fs48.readFileSync)(bodyFile, "utf8") : void 0;
57335
57418
  await defaultGitHubClient().rest("PUT", `repos/${repoForPostCleanup}/pulls/${number}/merge`, {
57336
57419
  body: { merge_method: method.slice(2), ...commitMessage ? { commit_message: commitMessage } : {} },
57337
57420
  timeoutMs: GH_MUTATION_TIMEOUT_MS
@@ -57464,7 +57547,7 @@ ${list}`);
57464
57547
  preserveWorktree: o.preserveWorktree,
57465
57548
  gcAcknowledged: o.gc,
57466
57549
  expectedHeadOid: headRefOid,
57467
- pathExists: (p) => (0, import_node_fs47.existsSync)(p),
57550
+ pathExists: (p) => (0, import_node_fs48.existsSync)(p),
57468
57551
  // #5899: pin cleanup git calls to the main checkout — the task worktree this process may be
57469
57552
  // standing in is removed mid-cleanup, so a cwd-relative invocation fails with
57470
57553
  // 'fatal: not a git repository' and leaves a spurious partial-cleanup exit.
@@ -58779,11 +58862,11 @@ function suiteTrainIo(root, summaryFile, memberSummaryFiles = {}, summaryFileTr,
58779
58862
  const checkout = async (repo) => {
58780
58863
  if (repo === SUITE_REPO) return root;
58781
58864
  const target = (0, import_node_path47.join)(base, repo.split("/")[1]);
58782
- if (!(0, import_node_fs48.existsSync)(target)) {
58783
- (0, import_node_fs48.mkdirSync)(base, { recursive: true });
58865
+ if (!(0, import_node_fs49.existsSync)(target)) {
58866
+ (0, import_node_fs49.mkdirSync)(base, { recursive: true });
58784
58867
  await exec("git", ["clone", "--quiet", "--branch", "development", `https://github.com/${repo}.git`, target], root, WATCH_TIMEOUT);
58785
58868
  }
58786
- if (!(0, import_node_fs48.existsSync)((0, import_node_path47.join)(target, ".git"))) throw new Error(`${repo}: suite checkout has no .git at ${target}; stop`);
58869
+ if (!(0, import_node_fs49.existsSync)((0, import_node_path47.join)(target, ".git"))) throw new Error(`${repo}: suite checkout has no .git at ${target}; stop`);
58787
58870
  const origin = await exec("git", ["remote", "get-url", "origin"], target);
58788
58871
  if (!origin.toLowerCase().endsWith(`/${repo.toLowerCase()}.git`) && !origin.toLowerCase().endsWith(`/${repo.toLowerCase()}`))
58789
58872
  throw new Error(`${repo}: suite checkout origin mismatch at ${target}; stop`);
@@ -59090,9 +59173,9 @@ function suiteTrainIo(root, summaryFile, memberSummaryFiles = {}, summaryFileTr,
59090
59173
  const body = await gh(["release", "view", leadTag, "--repo", SUITE_REPO, "--json", "body", "--jq", ".body"]);
59091
59174
  if (parseSuiteMapping(body)) return;
59092
59175
  const dir = suiteStateDir(root);
59093
- (0, import_node_fs48.mkdirSync)(dir, { recursive: true });
59176
+ (0, import_node_fs49.mkdirSync)(dir, { recursive: true });
59094
59177
  const file = (0, import_node_path47.join)(dir, `notes-${leadTag}.md`);
59095
- (0, import_node_fs48.writeFileSync)(file, `${body}
59178
+ (0, import_node_fs49.writeFileSync)(file, `${body}
59096
59179
 
59097
59180
  ${suiteMappingBlock(leadTag, mapping)}`);
59098
59181
  await gh(["release", "edit", leadTag, "--repo", SUITE_REPO, "--notes-file", file]);
@@ -59133,7 +59216,7 @@ ${suiteMappingBlock(leadTag, mapping)}`);
59133
59216
 
59134
59217
  // src/suite-commands.ts
59135
59218
  init_cli_shared();
59136
- var import_node_fs49 = require("node:fs");
59219
+ var import_node_fs50 = require("node:fs");
59137
59220
  function parseMemberSummaryFiles(entries) {
59138
59221
  const memberSummaryFiles = {};
59139
59222
  for (const entry of entries) {
@@ -59227,7 +59310,7 @@ function registerSuiteCommands(program3) {
59227
59310
  try {
59228
59311
  const io = suiteTrainIo(root);
59229
59312
  retired = await retireFailedLeadRcLedger({ ledgerPath: releaseLedgerPath(root), rcHead: () => io.head(SUITE_REPO, "rc").then((h) => h ?? void 0), markAbandoned: io.markAbandoned }, o.ownerGo === true);
59230
- if (retired && !(0, import_node_fs49.existsSync)(io.recordPath)) {
59313
+ if (retired && !(0, import_node_fs50.existsSync)(io.recordPath)) {
59231
59314
  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)`);
59232
59315
  return;
59233
59316
  }
@@ -59421,7 +59504,7 @@ function suiteStatusDeps(github, registry2) {
59421
59504
 
59422
59505
  // src/packages-adopt-export.ts
59423
59506
  var import_node_child_process19 = require("node:child_process");
59424
- var import_node_fs50 = require("node:fs");
59507
+ var import_node_fs51 = require("node:fs");
59425
59508
  var import_node_os23 = require("node:os");
59426
59509
  var import_node_path48 = require("node:path");
59427
59510
  var import_node_util6 = require("node:util");
@@ -60045,36 +60128,36 @@ async function adoptExport(opts, deps) {
60045
60128
  if (!/^sha256:[0-9a-f]{64}$/.test(opts.digest)) throw new Error("--digest must be sha256:<64 hex>, from the export run summary");
60046
60129
  const packagePath = (0, import_node_path48.join)(opts.dir, "package.json");
60047
60130
  const lockPath = (0, import_node_path48.join)(opts.dir, "package-lock.json");
60048
- const packageText = (0, import_node_fs50.readFileSync)(packagePath, "utf8");
60049
- const lockText = (0, import_node_fs50.readFileSync)(lockPath, "utf8");
60050
- const work = (0, import_node_fs50.mkdtempSync)((0, import_node_path48.join)((0, import_node_os23.tmpdir)(), "mmi-adopt-export-"));
60131
+ const packageText = (0, import_node_fs51.readFileSync)(packagePath, "utf8");
60132
+ const lockText = (0, import_node_fs51.readFileSync)(lockPath, "utf8");
60133
+ const work = (0, import_node_fs51.mkdtempSync)((0, import_node_path48.join)((0, import_node_os23.tmpdir)(), "mmi-adopt-export-"));
60051
60134
  try {
60052
60135
  const run = JSON.parse((await deps.ghApi(`repos/${EXPORT_REPO}/actions/runs/${opts.run}`)).toString("utf8"));
60053
- (0, import_node_fs50.writeFileSync)((0, import_node_path48.join)(work, "expected.json"), JSON.stringify(expectedFromRun(run, opts)));
60054
- (0, import_node_fs50.writeFileSync)((0, import_node_path48.join)(work, "provider.json"), await deps.ghApi(`repos/${EXPORT_REPO}/actions/artifacts/${opts.artifact}`));
60055
- (0, import_node_fs50.writeFileSync)((0, import_node_path48.join)(work, "artifact.zip"), await deps.ghApi(`repos/${EXPORT_REPO}/actions/artifacts/${opts.artifact}/zip`));
60136
+ (0, import_node_fs51.writeFileSync)((0, import_node_path48.join)(work, "expected.json"), JSON.stringify(expectedFromRun(run, opts)));
60137
+ (0, import_node_fs51.writeFileSync)((0, import_node_path48.join)(work, "provider.json"), await deps.ghApi(`repos/${EXPORT_REPO}/actions/artifacts/${opts.artifact}`));
60138
+ (0, import_node_fs51.writeFileSync)((0, import_node_path48.join)(work, "artifact.zip"), await deps.ghApi(`repos/${EXPORT_REPO}/actions/artifacts/${opts.artifact}/zip`));
60056
60139
  const script = (0, import_node_path48.join)(work, "package_export.py");
60057
- (0, import_node_fs50.writeFileSync)(script, package_export_default);
60140
+ (0, import_node_fs51.writeFileSync)(script, package_export_default);
60058
60141
  await deps.python(script, ["verify", work, opts.ds, opts.screens]);
60059
60142
  const verified = (0, import_node_path48.join)(work, "verified");
60060
- const metadata = Object.fromEntries(PACKAGES.map(({ name, short: short3 }) => [name, JSON.parse((0, import_node_fs50.readFileSync)((0, import_node_path48.join)(verified, `${short3}.metadata.json`), "utf8"))]));
60143
+ const metadata = Object.fromEntries(PACKAGES.map(({ name, short: short3 }) => [name, JSON.parse((0, import_node_fs51.readFileSync)((0, import_node_path48.join)(verified, `${short3}.metadata.json`), "utf8"))]));
60061
60144
  const plan = planAdoption(packageText, lockText, metadata);
60062
60145
  for (const { name } of plan.result.adopted) {
60063
60146
  const short3 = PACKAGES.find((p) => p.name === name).short;
60064
60147
  await deps.npm(["cache", "add", (0, import_node_path48.join)(verified, `${short3}.tgz`)], opts.dir);
60065
60148
  }
60066
- (0, import_node_fs50.writeFileSync)(packagePath, plan.packageText);
60067
- (0, import_node_fs50.writeFileSync)(lockPath, plan.lockText);
60149
+ (0, import_node_fs51.writeFileSync)(packagePath, plan.packageText);
60150
+ (0, import_node_fs51.writeFileSync)(lockPath, plan.lockText);
60068
60151
  try {
60069
60152
  await deps.npm(["ci", "--offline", "--ignore-scripts", "--no-audit", "--no-fund"], opts.dir);
60070
60153
  } catch (error) {
60071
- (0, import_node_fs50.writeFileSync)(packagePath, packageText);
60072
- (0, import_node_fs50.writeFileSync)(lockPath, lockText);
60154
+ (0, import_node_fs51.writeFileSync)(packagePath, packageText);
60155
+ (0, import_node_fs51.writeFileSync)(lockPath, lockText);
60073
60156
  throw new Error(`npm ci --offline failed, package.json and package-lock.json restored: ${error.message}`);
60074
60157
  }
60075
60158
  return plan.result;
60076
60159
  } finally {
60077
- (0, import_node_fs50.rmSync)(work, { recursive: true, force: true });
60160
+ (0, import_node_fs51.rmSync)(work, { recursive: true, force: true });
60078
60161
  }
60079
60162
  }
60080
60163
  var execFileBuffer = (0, import_node_util6.promisify)(import_node_child_process19.execFile);
@@ -60139,12 +60222,12 @@ function registerPackagesCommands(program3) {
60139
60222
  init_cli_shared();
60140
60223
 
60141
60224
  // src/wave-status.ts
60142
- var import_node_fs51 = require("node:fs");
60225
+ var import_node_fs52 = require("node:fs");
60143
60226
  function readStageSummary(worktreePath) {
60144
60227
  const statePath = stageStatePath(worktreePath);
60145
- if (!(0, import_node_fs51.existsSync)(statePath)) return void 0;
60228
+ if (!(0, import_node_fs52.existsSync)(statePath)) return void 0;
60146
60229
  try {
60147
- const state = JSON.parse((0, import_node_fs51.readFileSync)(statePath, "utf8"));
60230
+ const state = JSON.parse((0, import_node_fs52.readFileSync)(statePath, "utf8"));
60148
60231
  const port = typeof state.port === "number" ? state.port : void 0;
60149
60232
  if (port == null || !Number.isInteger(port) || port <= 0) return void 0;
60150
60233
  return { port, url: typeof state.url === "string" ? state.url : void 0 };
@@ -60201,7 +60284,7 @@ async function collectWaveStatus(deps) {
60201
60284
  // src/discovery-commands.ts
60202
60285
  init_github_client();
60203
60286
  init_cli_shared();
60204
- var import_node_fs52 = require("node:fs");
60287
+ var import_node_fs53 = require("node:fs");
60205
60288
  var import_node_os24 = require("node:os");
60206
60289
  var import_node_path49 = require("node:path");
60207
60290
  var GC_GH_TIMEOUT_MS3 = 2e4;
@@ -60394,8 +60477,8 @@ async function collectOnboardStatus(opts = {}) {
60394
60477
  }
60395
60478
  const home = (0, import_node_os24.homedir)();
60396
60479
  const plugin = onboardPluginGate({
60397
- readKnown: () => readFileSyncSafe((0, import_node_path49.join)(home, ...KNOWN_MARKETPLACES_RELATIVE), import_node_fs52.readFileSync),
60398
- readSettings: () => readFileSyncSafe((0, import_node_path49.join)(home, ".claude", "settings.json"), import_node_fs52.readFileSync)
60480
+ readKnown: () => readFileSyncSafe((0, import_node_path49.join)(home, ...KNOWN_MARKETPLACES_RELATIVE), import_node_fs53.readFileSync),
60481
+ readSettings: () => readFileSyncSafe((0, import_node_path49.join)(home, ".claude", "settings.json"), import_node_fs53.readFileSync)
60399
60482
  });
60400
60483
  return {
60401
60484
  guide: "Read the MMI org-guide skill before project work; load only the relevant topic. Use mmi-help for a short introduction.",
@@ -62585,7 +62668,7 @@ function registerOrgHealthQuery(program3, deps = defaultOrgHealthQueryDeps()) {
62585
62668
  }
62586
62669
 
62587
62670
  // src/api-read.ts
62588
- var import_node_fs53 = require("node:fs");
62671
+ var import_node_fs54 = require("node:fs");
62589
62672
 
62590
62673
  // src/run-log-read.ts
62591
62674
  init_cli_shared();
@@ -63365,7 +63448,7 @@ function registerApiReadCommands(program3, overrides) {
63365
63448
  o.accept
63366
63449
  );
63367
63450
  if (zip) {
63368
- (0, import_node_fs53.writeFileSync)(o.out, body, "latin1");
63451
+ (0, import_node_fs54.writeFileSync)(o.out, body, "latin1");
63369
63452
  return;
63370
63453
  }
63371
63454
  } catch (e) {
@@ -64259,7 +64342,7 @@ function registerSessionReport(program3) {
64259
64342
  }
64260
64343
 
64261
64344
  // src/stage-commands.ts
64262
- var import_node_fs54 = require("node:fs");
64345
+ var import_node_fs55 = require("node:fs");
64263
64346
  var import_node_path50 = require("node:path");
64264
64347
  init_cli_shared();
64265
64348
  init_clean_exit();
@@ -64508,8 +64591,8 @@ function registerStageCommands(program3) {
64508
64591
  const repo = Array.isArray(project2?.repos) && typeof project2.repos[0] === "string" ? project2.repos[0] : slug;
64509
64592
  const resolution = decideStage({
64510
64593
  registry: { deployModel: project2?.deployModel, portRange, error: read.ok ? void 0 : read.error },
64511
- hasCompose: (0, import_node_fs54.existsSync)((0, import_node_path50.join)(process.cwd(), "docker-compose.yml")),
64512
- hasEnvExample: (0, import_node_fs54.existsSync)((0, import_node_path50.join)(process.cwd(), ".env.example")),
64594
+ hasCompose: (0, import_node_fs55.existsSync)((0, import_node_path50.join)(process.cwd(), "docker-compose.yml")),
64595
+ hasEnvExample: (0, import_node_fs55.existsSync)((0, import_node_path50.join)(process.cwd(), ".env.example")),
64513
64596
  repo
64514
64597
  });
64515
64598
  if (resolution.source === "derived" && resolution.derived) {
@@ -64802,14 +64885,14 @@ vercel preview (${preview.branch}): ${d.state}${d.url ? ` \u2014 ${d.url}` : ""}
64802
64885
 
64803
64886
  // src/tenant-artifact.ts
64804
64887
  var import_node_crypto17 = require("node:crypto");
64805
- var import_node_fs55 = require("node:fs");
64888
+ var import_node_fs56 = require("node:fs");
64806
64889
  var import_promises11 = require("node:fs/promises");
64807
64890
  var import_node_path51 = require("node:path");
64808
64891
  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}$/;
64809
64892
  var MAX_BYTES2 = 5 * 1024 * 1024 * 1024;
64810
64893
  async function sha256File(path2) {
64811
64894
  const hash = (0, import_node_crypto17.createHash)("sha256");
64812
- for await (const chunk of (0, import_node_fs55.createReadStream)(path2)) hash.update(chunk);
64895
+ for await (const chunk of (0, import_node_fs56.createReadStream)(path2)) hash.update(chunk);
64813
64896
  return hash.digest("hex");
64814
64897
  }
64815
64898
  async function putTenantArtifact(repo, stage, inputPath, deps) {
@@ -64832,7 +64915,7 @@ async function putTenantArtifact(repo, stage, inputPath, deps) {
64832
64915
  return [key, value];
64833
64916
  }));
64834
64917
  headers["content-length"] = String(info.size);
64835
- const stream = (0, import_node_fs55.createReadStream)(path2);
64918
+ const stream = (0, import_node_fs56.createReadStream)(path2);
64836
64919
  let uploaded;
64837
64920
  try {
64838
64921
  uploaded = await fetch(body.uploadUrl, {
@@ -64973,7 +65056,7 @@ function renderVerifySecrets(body) {
64973
65056
  }
64974
65057
 
64975
65058
  // src/command-register-developer.ts
64976
- var import_node_fs59 = require("node:fs");
65059
+ var import_node_fs60 = require("node:fs");
64977
65060
  init_clean_exit();
64978
65061
  init_cli_shared();
64979
65062
  init_error_codes();
@@ -65041,13 +65124,13 @@ async function executeWaveLand(plan, deps) {
65041
65124
  // src/dist-drift.ts
65042
65125
  var import_node_child_process21 = require("node:child_process");
65043
65126
  var import_node_crypto19 = require("node:crypto");
65044
- var import_node_fs57 = require("node:fs");
65127
+ var import_node_fs58 = require("node:fs");
65045
65128
  var import_node_os25 = require("node:os");
65046
65129
  var import_node_path53 = require("node:path");
65047
65130
 
65048
65131
  // ../scripts/distribution-digest.mjs
65049
65132
  var import_node_crypto18 = require("node:crypto");
65050
- var import_node_fs56 = require("node:fs");
65133
+ var import_node_fs57 = require("node:fs");
65051
65134
  var import_node_path52 = require("node:path");
65052
65135
  var slash = (value) => value.replaceAll("\\", "/");
65053
65136
  function repoPath(root, declaredPath, label) {
@@ -65061,7 +65144,7 @@ function repoPath(root, declaredPath, label) {
65061
65144
  function digestFiles(files) {
65062
65145
  const hash = (0, import_node_crypto18.createHash)("sha256");
65063
65146
  for (const file of [...files].sort((a, b) => a.relative.localeCompare(b.relative))) {
65064
- const content = file.stat.isSymbolicLink() ? Buffer.from((0, import_node_fs56.readlinkSync)(file.absolute), "utf8") : (0, import_node_fs56.readFileSync)(file.absolute);
65147
+ const content = file.stat.isSymbolicLink() ? Buffer.from((0, import_node_fs57.readlinkSync)(file.absolute), "utf8") : (0, import_node_fs57.readFileSync)(file.absolute);
65065
65148
  hash.update(file.relative, "utf8");
65066
65149
  hash.update("\0");
65067
65150
  hash.update(file.stat.isSymbolicLink() ? "symlink" : "file", "utf8");
@@ -65076,8 +65159,8 @@ function digestFiles(files) {
65076
65159
  function digestPackedFiles(packageRoot, packedFiles) {
65077
65160
  return digestFiles(packedFiles.map((path2) => {
65078
65161
  const absolute = repoPath(packageRoot, path2, "packed artifact identity path");
65079
- if (!(0, import_node_fs56.existsSync)(absolute)) throw new Error(`packed artifact identity path ${path2} does not exist`);
65080
- return { absolute, relative: slash(path2), stat: (0, import_node_fs56.lstatSync)(absolute) };
65162
+ if (!(0, import_node_fs57.existsSync)(absolute)) throw new Error(`packed artifact identity path ${path2} does not exist`);
65163
+ return { absolute, relative: slash(path2), stat: (0, import_node_fs57.lstatSync)(absolute) };
65081
65164
  }));
65082
65165
  }
65083
65166
 
@@ -65162,12 +65245,12 @@ function renderDistDriftReceipt(receipt) {
65162
65245
  return lines2;
65163
65246
  }
65164
65247
  function readOrNull(path2) {
65165
- return (0, import_node_fs57.existsSync)(path2) ? (0, import_node_fs57.readFileSync)(path2) : null;
65248
+ return (0, import_node_fs58.existsSync)(path2) ? (0, import_node_fs58.readFileSync)(path2) : null;
65166
65249
  }
65167
65250
  function walkFiles(root) {
65168
65251
  const files = [];
65169
65252
  const walk2 = (directory) => {
65170
- for (const entry of (0, import_node_fs57.readdirSync)(directory, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
65253
+ for (const entry of (0, import_node_fs58.readdirSync)(directory, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
65171
65254
  const child2 = (0, import_node_path53.join)(directory, entry.name);
65172
65255
  if (entry.isDirectory()) walk2(child2);
65173
65256
  else files.push(child2);
@@ -65178,7 +65261,7 @@ function walkFiles(root) {
65178
65261
  }
65179
65262
  function bomPathFor(root) {
65180
65263
  try {
65181
- const registry2 = JSON.parse((0, import_node_fs57.readFileSync)((0, import_node_path53.join)(root, "surfaces.json"), "utf8"));
65264
+ const registry2 = JSON.parse((0, import_node_fs58.readFileSync)((0, import_node_path53.join)(root, "surfaces.json"), "utf8"));
65182
65265
  return (0, import_node_path53.join)(root, registry2?.sharedAgentCore?.releaseMetadata?.bomPath ?? "distribution-bom.json");
65183
65266
  } catch {
65184
65267
  return (0, import_node_path53.join)(root, "distribution-bom.json");
@@ -65194,7 +65277,7 @@ function rebuildTo(packageRoot, outDir) {
65194
65277
  });
65195
65278
  }
65196
65279
  function runDistStatus(root) {
65197
- const stage = (0, import_node_fs57.mkdtempSync)((0, import_node_path53.join)((0, import_node_os25.tmpdir)(), "mmi-dist-drift-"));
65280
+ const stage = (0, import_node_fs58.mkdtempSync)((0, import_node_path53.join)((0, import_node_os25.tmpdir)(), "mmi-dist-drift-"));
65198
65281
  let overlayCount = 0;
65199
65282
  try {
65200
65283
  const cliOut = (0, import_node_path53.join)(stage, "cli-dist");
@@ -65210,19 +65293,19 @@ function runDistStatus(root) {
65210
65293
  const tree = (path2) => readOrNull((0, import_node_path53.join)(root, path2));
65211
65294
  const distRoot = (0, import_node_path53.join)(root, "cli", "dist");
65212
65295
  const distTree = () => walkFiles(distRoot).map((absolute) => `cli/dist/${(0, import_node_path53.relative)(distRoot, absolute).replaceAll("\\", "/")}`);
65213
- const bom = JSON.parse((0, import_node_fs57.readFileSync)(bomPathFor(root), "utf8"));
65296
+ const bom = JSON.parse((0, import_node_fs58.readFileSync)(bomPathFor(root), "utf8"));
65214
65297
  const digest = (entries) => {
65215
65298
  const overlay = (0, import_node_path53.join)(stage, `overlay-${overlayCount++}`);
65216
65299
  for (const entry of entries) {
65217
65300
  const target = (0, import_node_path53.join)(overlay, entry.path);
65218
- (0, import_node_fs57.mkdirSync)((0, import_node_path53.dirname)(target), { recursive: true });
65219
- (0, import_node_fs57.writeFileSync)(target, entry.bytes);
65301
+ (0, import_node_fs58.mkdirSync)((0, import_node_path53.dirname)(target), { recursive: true });
65302
+ (0, import_node_fs58.writeFileSync)(target, entry.bytes);
65220
65303
  }
65221
65304
  return digestPackedFiles(overlay, entries.map((entry) => entry.path));
65222
65305
  };
65223
65306
  return computeDistDriftReceipt({ committed, tree, rebuilt, distTree, bom, digest });
65224
65307
  } finally {
65225
- (0, import_node_fs57.rmSync)(stage, { recursive: true, force: true });
65308
+ (0, import_node_fs58.rmSync)(stage, { recursive: true, force: true });
65226
65309
  }
65227
65310
  }
65228
65311
 
@@ -65554,7 +65637,7 @@ function registerSchedulesLiftCommand(program3, deps = {}) {
65554
65637
 
65555
65638
  // src/spawn-policy-core.ts
65556
65639
  var import_node_child_process23 = require("node:child_process");
65557
- var import_node_fs58 = require("node:fs");
65640
+ var import_node_fs59 = require("node:fs");
65558
65641
  var import_node_path56 = require("node:path");
65559
65642
  var SPAWNERS = ["spawn", "spawnSync", "exec", "execSync", "execFile", "execFileSync"];
65560
65643
  var CALL_SOURCE = String.raw`(^|[^.\w$])(${SPAWNERS.join("|")})\s*\(`;
@@ -65641,7 +65724,7 @@ function runSpawnPolicy(root) {
65641
65724
  for (const file of files) {
65642
65725
  let raw;
65643
65726
  try {
65644
- raw = (0, import_node_fs58.readFileSync)((0, import_node_path56.join)(root, file), "utf8");
65727
+ raw = (0, import_node_fs59.readFileSync)((0, import_node_path56.join)(root, file), "utf8");
65645
65728
  } catch {
65646
65729
  continue;
65647
65730
  }
@@ -65662,18 +65745,18 @@ function registerDeveloperCommands(program3) {
65662
65745
  const rules = program3.command("rules").description("org-managed .gitignore delivery");
65663
65746
  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) => {
65664
65747
  const path2 = (0, import_node_path57.join)(process.cwd(), ".gitignore");
65665
- const current = (0, import_node_fs59.existsSync)(path2) ? (0, import_node_fs59.readFileSync)(path2, "utf8") : null;
65748
+ const current = (0, import_node_fs60.existsSync)(path2) ? (0, import_node_fs60.readFileSync)(path2, "utf8") : null;
65666
65749
  const plan = planManagedGitignore(current);
65667
65750
  const drift = [...plan.added.map((l) => `+${l}`), ...plan.removed.map((l) => `-${l}`)].join(", ") || "block normalize";
65668
65751
  if (opts.json) {
65669
- if (opts.write && plan.changed) (0, import_node_fs59.writeFileSync)(path2, plan.content, "utf8");
65752
+ if (opts.write && plan.changed) (0, import_node_fs60.writeFileSync)(path2, plan.content, "utf8");
65670
65753
  console.log(JSON.stringify(plan, null, 2));
65671
65754
  if (!opts.write && plan.changed) process.exitCode = 1;
65672
65755
  return;
65673
65756
  }
65674
65757
  if (opts.write) {
65675
65758
  if (plan.changed) {
65676
- (0, import_node_fs59.writeFileSync)(path2, plan.content, "utf8");
65759
+ (0, import_node_fs60.writeFileSync)(path2, plan.content, "utf8");
65677
65760
  console.log(`mmi-cli devops org rules gitignore: updated .gitignore (${drift})`);
65678
65761
  } else {
65679
65762
  console.log("mmi-cli devops org rules gitignore: up to date");
@@ -66092,7 +66175,7 @@ function mmiDoctorDeps(opts = {}) {
66092
66175
  );
66093
66176
  const result = applyPluginCachePlan(
66094
66177
  plan,
66095
- (p) => (0, import_node_fs60.rmSync)(p, { recursive: true }),
66178
+ (p) => (0, import_node_fs61.rmSync)(p, { recursive: true }),
66096
66179
  stagingApplyFsGuard(configRoot)
66097
66180
  );
66098
66181
  return {
@@ -66127,7 +66210,7 @@ function mmiDoctorDeps(opts = {}) {
66127
66210
  // has no generated routing index would
66128
66211
  // get a permanent — demanding an artifact it never asked for.
66129
66212
  docsIndexState: (root) => {
66130
- if (!(0, import_node_fs60.existsSync)((0, import_node_path58.join)(root, DOCS_INDEX_PATH))) return void 0;
66213
+ if (!(0, import_node_fs61.existsSync)((0, import_node_path58.join)(root, DOCS_INDEX_PATH))) return void 0;
66131
66214
  const real = createDocsIndexDeps(root);
66132
66215
  let docs;
66133
66216
  const listDocs = () => docs ??= real.listDocs();
@@ -66136,7 +66219,7 @@ function mmiDoctorDeps(opts = {}) {
66136
66219
  },
66137
66220
  // #4168: working-tree heal — write if drifted, then re-check. Commit remains the operator's step.
66138
66221
  healDocsIndex: (root) => {
66139
- if (!(0, import_node_fs60.existsSync)((0, import_node_path58.join)(root, DOCS_INDEX_PATH))) return { drift: false, docCount: 0 };
66222
+ if (!(0, import_node_fs61.existsSync)((0, import_node_path58.join)(root, DOCS_INDEX_PATH))) return { drift: false, docCount: 0 };
66140
66223
  const real = createDocsIndexDeps(root);
66141
66224
  let docs;
66142
66225
  const listDocs = () => docs ??= real.listDocs();
@@ -66891,7 +66974,7 @@ project.command("set [owner/repo]").description("upsert project META (idempotent
66891
66974
  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`);
66892
66975
  if (o.secretsFile) {
66893
66976
  try {
66894
- vars.push(`secrets=${(0, import_node_fs60.readFileSync)(o.secretsFile, "utf8")}`);
66977
+ vars.push(`secrets=${(0, import_node_fs61.readFileSync)(o.secretsFile, "utf8")}`);
66895
66978
  } catch (e) {
66896
66979
  return fail(`org project set: cannot read --secrets-file ${o.secretsFile}: ${e.message}`);
66897
66980
  }
@@ -67284,15 +67367,15 @@ function ciAuditDeps2() {
67284
67367
  readSeedFile: (path2) => {
67285
67368
  if (!root) return null;
67286
67369
  const fullPath = (0, import_node_path58.join)(root, path2);
67287
- return (0, import_node_fs60.existsSync)(fullPath) ? (0, import_node_fs60.readFileSync)(fullPath, "utf8") : null;
67370
+ return (0, import_node_fs61.existsSync)(fullPath) ? (0, import_node_fs61.readFileSync)(fullPath, "utf8") : null;
67288
67371
  }
67289
67372
  };
67290
67373
  }
67291
67374
  function hubRoot2() {
67292
67375
  const fromPkg = (0, import_node_path58.join)(__dirname, "..", "..");
67293
67376
  const marker = "skills/bootstrap/seeds/manifest.json";
67294
- if ((0, import_node_fs60.existsSync)((0, import_node_path58.join)(fromPkg, marker))) return fromPkg;
67295
- if ((0, import_node_fs60.existsSync)((0, import_node_path58.join)(process.cwd(), marker))) return process.cwd();
67377
+ if ((0, import_node_fs61.existsSync)((0, import_node_path58.join)(fromPkg, marker))) return fromPkg;
67378
+ if ((0, import_node_fs61.existsSync)((0, import_node_path58.join)(process.cwd(), marker))) return process.cwd();
67296
67379
  return null;
67297
67380
  }
67298
67381
  registerQueryCommands(program2);
@@ -67423,10 +67506,10 @@ access.command("audit").description("audit collaborator roles + train-branch pus
67423
67506
  targets = resolution.targets;
67424
67507
  }
67425
67508
  const derivedMatrix = registryProjects ? accessMatrixFromProjects(registryProjects) : {};
67426
- const fileMatrix = (0, import_node_fs60.existsSync)("access-matrix.json") ? loadAccessMatrix((0, import_node_fs60.readFileSync)("access-matrix.json", "utf8")) : {};
67509
+ const fileMatrix = (0, import_node_fs61.existsSync)("access-matrix.json") ? loadAccessMatrix((0, import_node_fs61.readFileSync)("access-matrix.json", "utf8")) : {};
67427
67510
  const matrix = mergeAccessMatrix(fileMatrix, derivedMatrix);
67428
67511
  const dataAccess = registryProjects ? dataAccessContractsFromProjects(registryProjects) : { consumers: {} };
67429
- const sanctioned = (0, import_node_fs60.existsSync)("access-matrix.json") ? loadSanctionedAdmins((0, import_node_fs60.readFileSync)("access-matrix.json", "utf8")) : {};
67512
+ const sanctioned = (0, import_node_fs61.existsSync)("access-matrix.json") ? loadSanctionedAdmins((0, import_node_fs61.readFileSync)("access-matrix.json", "utf8")) : {};
67430
67513
  const report = await auditOrgAccess(targets, deps, matrix, dataAccess, sanctioned);
67431
67514
  console.log(o.json ? JSON.stringify(report, null, 2) : renderAccessReport(report));
67432
67515
  if (!report.ok) process.exitCode = 1;
@@ -67457,7 +67540,7 @@ function directoryBytes(path2) {
67457
67540
  let total = 0;
67458
67541
  let entries;
67459
67542
  try {
67460
- entries = (0, import_node_fs60.readdirSync)(path2, { withFileTypes: true });
67543
+ entries = (0, import_node_fs61.readdirSync)(path2, { withFileTypes: true });
67461
67544
  } catch {
67462
67545
  return 0;
67463
67546
  }
@@ -67466,7 +67549,7 @@ function directoryBytes(path2) {
67466
67549
  if (entry.isDirectory()) total += directoryBytes(child2);
67467
67550
  else {
67468
67551
  try {
67469
- total += (0, import_node_fs60.statSync)(child2).size;
67552
+ total += (0, import_node_fs61.statSync)(child2).size;
67470
67553
  } catch {
67471
67554
  }
67472
67555
  }
@@ -67474,25 +67557,25 @@ function directoryBytes(path2) {
67474
67557
  return total;
67475
67558
  }
67476
67559
  function listDirEntries(dir) {
67477
- return (0, import_node_fs60.readdirSync)(dir, { withFileTypes: true }).map((d) => ({ name: d.name, isDirectory: d.isDirectory() }));
67560
+ return (0, import_node_fs61.readdirSync)(dir, { withFileTypes: true }).map((d) => ({ name: d.name, isDirectory: d.isDirectory() }));
67478
67561
  }
67479
67562
  function readInstalledPluginRefs(configRoot) {
67480
67563
  const p = installedPluginsPathForConfig(configRoot);
67481
- if (!(0, import_node_fs60.existsSync)(p)) return [];
67564
+ if (!(0, import_node_fs61.existsSync)(p)) return [];
67482
67565
  try {
67483
- return installedPluginPaths((0, import_node_fs60.readFileSync)(p, "utf8"));
67566
+ return installedPluginPaths((0, import_node_fs61.readFileSync)(p, "utf8"));
67484
67567
  } catch {
67485
67568
  return null;
67486
67569
  }
67487
67570
  }
67488
67571
  function pluginCacheFsDeps(configRoot, dirBytes) {
67489
67572
  return {
67490
- exists: (p) => (0, import_node_fs60.existsSync)(p),
67491
- listVersionDirs: (root) => (0, import_node_fs60.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name),
67573
+ exists: (p) => (0, import_node_fs61.existsSync)(p),
67574
+ listVersionDirs: (root) => (0, import_node_fs61.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name),
67492
67575
  dirBytes,
67493
- listStagingDirs: (root) => (0, import_node_fs60.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => {
67576
+ listStagingDirs: (root) => (0, import_node_fs61.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => {
67494
67577
  try {
67495
- return { name: d.name, mtimeMs: newestMtimeMs((0, import_node_path58.join)(root, d.name), listDirEntries, (p) => (0, import_node_fs60.statSync)(p).mtimeMs) };
67578
+ return { name: d.name, mtimeMs: newestMtimeMs((0, import_node_path58.join)(root, d.name), listDirEntries, (p) => (0, import_node_fs61.statSync)(p).mtimeMs) };
67496
67579
  } catch {
67497
67580
  return { name: d.name, mtimeMs: Date.now() };
67498
67581
  }
@@ -67507,9 +67590,9 @@ function stagingApplyFsGuard(configRoot) {
67507
67590
  referencedPaths: () => readInstalledPluginRefs(configRoot),
67508
67591
  mtimeMs: (name) => {
67509
67592
  const p = (0, import_node_path58.join)(stagingRoot, name);
67510
- if (!(0, import_node_fs60.existsSync)(p)) return null;
67593
+ if (!(0, import_node_fs61.existsSync)(p)) return null;
67511
67594
  try {
67512
- return newestMtimeMs(p, listDirEntries, (q) => (0, import_node_fs60.statSync)(q).mtimeMs);
67595
+ return newestMtimeMs(p, listDirEntries, (q) => (0, import_node_fs61.statSync)(q).mtimeMs);
67513
67596
  } catch {
67514
67597
  return null;
67515
67598
  }
@@ -67535,7 +67618,7 @@ program2.command("plugin-prune").description(`prune stale cached MMI plugin vers
67535
67618
  { withBytes: true, configRoot, includeStaging: surface !== "codex" }
67536
67619
  );
67537
67620
  const anythingToDelete = plan.prune.length > 0 || plan.staging.length > 0;
67538
- const result = o.apply && anythingToDelete ? applyPluginCachePlan(plan, (p) => (0, import_node_fs60.rmSync)(p, { recursive: true, force: true }), stagingApplyFsGuard(configRoot)) : void 0;
67621
+ const result = o.apply && anythingToDelete ? applyPluginCachePlan(plan, (p) => (0, import_node_fs61.rmSync)(p, { recursive: true, force: true }), stagingApplyFsGuard(configRoot)) : void 0;
67539
67622
  const warnings = plan.prune.length > 0 ? [CONCURRENT_SESSION_WARNING] : [];
67540
67623
  if (o.json) console.log(JSON.stringify({ ...plan, warnings, applied: result ?? null }));
67541
67624
  else console.log(renderPluginCachePlan(plan, result));