@mutmutco/cli 3.41.0 → 3.43.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/main.cjs +363 -136
  2. package/package.json +1 -1
package/dist/main.cjs CHANGED
@@ -3410,8 +3410,8 @@ var program = new Command();
3410
3410
 
3411
3411
  // src/index.ts
3412
3412
  var import_promises7 = require("node:fs/promises");
3413
- var import_node_fs28 = require("node:fs");
3414
- var import_node_child_process12 = require("node:child_process");
3413
+ var import_node_fs29 = require("node:fs");
3414
+ var import_node_child_process13 = require("node:child_process");
3415
3415
 
3416
3416
  // src/cli-shared.ts
3417
3417
  var import_node_child_process3 = require("node:child_process");
@@ -8949,7 +8949,7 @@ function commandLadderHint() {
8949
8949
  }
8950
8950
 
8951
8951
  // src/index.ts
8952
- var import_node_path25 = require("node:path");
8952
+ var import_node_path26 = require("node:path");
8953
8953
 
8954
8954
  // src/merge-ci-policy.ts
8955
8955
  function resolveMergeCiPolicy(input) {
@@ -15375,6 +15375,207 @@ function createDocsIndexDeps(repoRoot2) {
15375
15375
  };
15376
15376
  }
15377
15377
 
15378
+ // src/doc-refs-core.ts
15379
+ var import_node_child_process9 = require("node:child_process");
15380
+ var import_node_fs18 = require("node:fs");
15381
+ var import_node_path16 = require("node:path");
15382
+ var PIN_RE = /<!--\s*pinned by\s+([^:]+?)\s*:\s*"([^"]+)"[^"]*-->/;
15383
+ var PIN_MENTION_RE = /<!--\s*pinned by\b/;
15384
+ var REF_RE = /`([A-Za-z0-9_./-]+\.[A-Za-z0-9]+)(?::\d+)?`/g;
15385
+ var LINK_RE = /\]\(([^)#\s]+?\.md)(?:#[^)]*)?\)/g;
15386
+ var CMD_RE = /`mmi-cli ((?:[a-z][a-z-]*)(?: [a-z][a-z-]*){0,3})/g;
15387
+ var RETIRED_RE = /\b(retired|historical|removed|deleted|gone|no longer|superseded|legacy)\b/i;
15388
+ var ROOT_DOCS = ["README.md", "architecture.md"];
15389
+ var SKIP_WALK = ["docs/Archive/", "docs/incidents/"];
15390
+ function stripFences(markdown) {
15391
+ let inFence = false;
15392
+ return markdown.split(/\r?\n/).map((line) => {
15393
+ if (/^\s*```/.test(line)) {
15394
+ inFence = !inFence;
15395
+ return "";
15396
+ }
15397
+ return inFence ? "" : line;
15398
+ });
15399
+ }
15400
+ function isRetiredLine(text) {
15401
+ return RETIRED_RE.test(text);
15402
+ }
15403
+ function extractPins(markdown) {
15404
+ const pins = [];
15405
+ markdown.split(/\r?\n/).forEach((text, index) => {
15406
+ const match = PIN_RE.exec(text);
15407
+ if (match) {
15408
+ pins.push({ file: match[1].trim(), phrase: match[2], line: index + 1 });
15409
+ } else if (PIN_MENTION_RE.test(text.replace(/`[^`]*`/g, ""))) {
15410
+ pins.push({ malformed: true, line: index + 1, text: text.trim() });
15411
+ }
15412
+ });
15413
+ return pins;
15414
+ }
15415
+ function checkPins(root, readFile6, docs2) {
15416
+ const findings = [];
15417
+ for (const [doc, markdown] of Object.entries(docs2)) {
15418
+ for (const pin of extractPins(markdown)) {
15419
+ if ("malformed" in pin) {
15420
+ findings.push({ kind: "malformed-pin", doc, line: pin.line, detail: pin.text });
15421
+ continue;
15422
+ }
15423
+ const source = readFile6((0, import_node_path16.join)(root, pin.file));
15424
+ if (source == null) {
15425
+ findings.push({ kind: "missing-test", doc, line: pin.line, detail: pin.file });
15426
+ continue;
15427
+ }
15428
+ if (!source.includes(pin.phrase)) {
15429
+ findings.push({ kind: "unasserted-phrase", doc, line: pin.line, detail: pin.phrase });
15430
+ }
15431
+ }
15432
+ }
15433
+ return { ok: findings.length === 0, findings };
15434
+ }
15435
+ function isDomainLike(ref) {
15436
+ const first = ref.split("/")[0];
15437
+ return first.includes(".") && !first.startsWith(".");
15438
+ }
15439
+ function extractRefs(markdown) {
15440
+ const lines = stripFences(markdown);
15441
+ const refs = [];
15442
+ lines.forEach((text, index) => {
15443
+ if (isRetiredLine(text)) return;
15444
+ for (const match of text.matchAll(REF_RE)) {
15445
+ const ref = match[1];
15446
+ if (!ref.includes("/")) continue;
15447
+ if (ref.startsWith("/") || ref.startsWith(".git/")) continue;
15448
+ if (isDomainLike(ref)) continue;
15449
+ refs.push({ ref, line: index + 1 });
15450
+ }
15451
+ });
15452
+ return refs;
15453
+ }
15454
+ function extractLinks(markdown) {
15455
+ const lines = stripFences(markdown);
15456
+ const links = [];
15457
+ lines.forEach((text, index) => {
15458
+ if (isRetiredLine(text)) return;
15459
+ for (const match of text.matchAll(LINK_RE)) {
15460
+ const target = match[1];
15461
+ if (/^[a-z]+:/i.test(target)) continue;
15462
+ links.push({ target, line: index + 1 });
15463
+ }
15464
+ });
15465
+ return links;
15466
+ }
15467
+ function extractCommands(markdown) {
15468
+ const lines = stripFences(markdown);
15469
+ const commands = [];
15470
+ lines.forEach((text, index) => {
15471
+ if (isRetiredLine(text)) return;
15472
+ for (const match of text.matchAll(CMD_RE)) {
15473
+ commands.push({ command: match[1], line: index + 1 });
15474
+ }
15475
+ });
15476
+ return commands;
15477
+ }
15478
+ function checkRefs(root, deps, docs2) {
15479
+ const { exists, isIgnored = () => /* @__PURE__ */ new Set() } = deps;
15480
+ const candidates = [];
15481
+ for (const [doc, markdown] of Object.entries(docs2)) {
15482
+ for (const { ref, line } of extractRefs(markdown)) {
15483
+ const first = ref.split("/")[0];
15484
+ if (!exists((0, import_node_path16.join)(root, first))) continue;
15485
+ if (!exists((0, import_node_path16.join)(root, ref))) candidates.push({ kind: "missing-path", doc, line, detail: ref });
15486
+ }
15487
+ const docDir = import_node_path16.posix.dirname(doc);
15488
+ for (const { target, line } of extractLinks(markdown)) {
15489
+ const resolved = import_node_path16.posix.normalize(import_node_path16.posix.join(docDir === "." ? "" : docDir, target));
15490
+ if (!exists((0, import_node_path16.join)(root, resolved))) {
15491
+ candidates.push({ kind: "missing-link", doc, line, detail: target, resolved });
15492
+ }
15493
+ }
15494
+ }
15495
+ const ignored = candidates.length ? isIgnored(candidates.map((c) => c.kind === "missing-link" ? c.resolved : c.detail)) : /* @__PURE__ */ new Set();
15496
+ const findings = candidates.filter((c) => !ignored.has(c.kind === "missing-link" ? c.resolved : c.detail)).map(({ resolved, ...finding }) => finding);
15497
+ return { ok: findings.length === 0, findings };
15498
+ }
15499
+ function checkCommands(docs2, commandPaths) {
15500
+ const findings = [];
15501
+ const prefixesSome = (prefix) => {
15502
+ for (const path2 of commandPaths) {
15503
+ if (path2 === prefix || path2.startsWith(`${prefix} `)) return true;
15504
+ }
15505
+ return false;
15506
+ };
15507
+ for (const [doc, markdown] of Object.entries(docs2)) {
15508
+ for (const { command, line } of extractCommands(markdown)) {
15509
+ const tokens2 = command.split(" ");
15510
+ for (let i = 1; i <= tokens2.length; i += 1) {
15511
+ const prefix = tokens2.slice(0, i).join(" ");
15512
+ if (prefixesSome(prefix)) continue;
15513
+ const parent = tokens2.slice(0, i - 1).join(" ");
15514
+ if (i > 1 && commandPaths.has(parent)) break;
15515
+ findings.push({ kind: "unknown-command", doc, line, detail: `mmi-cli ${prefix}` });
15516
+ break;
15517
+ }
15518
+ }
15519
+ }
15520
+ return { ok: findings.length === 0, findings };
15521
+ }
15522
+ function readFileOrNull(path2) {
15523
+ return (0, import_node_fs18.existsSync)(path2) ? (0, import_node_fs18.readFileSync)(path2, "utf8") : null;
15524
+ }
15525
+ function walk(dir, root, out) {
15526
+ for (const entry of (0, import_node_fs18.readdirSync)(dir)) {
15527
+ const full = (0, import_node_path16.join)(dir, entry);
15528
+ if ((0, import_node_fs18.statSync)(full).isDirectory()) walk(full, root, out);
15529
+ else if (entry.endsWith(".md")) out.push(full.slice(root.length + 1).replaceAll("\\", "/"));
15530
+ }
15531
+ return out;
15532
+ }
15533
+ function defaultListDocs(root) {
15534
+ const docsDir = (0, import_node_path16.join)(root, "docs");
15535
+ const docs2 = ((0, import_node_fs18.existsSync)(docsDir) ? walk(docsDir, root, []) : []).filter(
15536
+ (rel) => !SKIP_WALK.some((skip) => rel.startsWith(skip))
15537
+ );
15538
+ return [...ROOT_DOCS.filter((rel) => (0, import_node_fs18.existsSync)((0, import_node_path16.join)(root, rel))), ...docs2];
15539
+ }
15540
+ function defaultIsIgnored(root, relPaths, exec = import_node_child_process9.execFileSync) {
15541
+ try {
15542
+ const out = exec("git", ["check-ignore", "--stdin"], {
15543
+ cwd: root,
15544
+ input: relPaths.join("\n"),
15545
+ encoding: "utf8"
15546
+ });
15547
+ return new Set(out.split(/\r?\n/).filter(Boolean));
15548
+ } catch (error) {
15549
+ if (error?.status === 1) return /* @__PURE__ */ new Set();
15550
+ throw error;
15551
+ }
15552
+ }
15553
+ function runDocRefs(root, deps = {}) {
15554
+ const readFile6 = deps.readFile ?? readFileOrNull;
15555
+ const exists = deps.exists ?? import_node_fs18.existsSync;
15556
+ const listDocs = deps.listDocs ?? defaultListDocs;
15557
+ const isIgnored = deps.isIgnored ?? ((paths) => defaultIsIgnored(root, paths));
15558
+ const commandPaths = deps.commandPaths ?? null;
15559
+ const docs2 = Object.fromEntries(
15560
+ listDocs(root).map((rel) => [rel, readFile6((0, import_node_path16.join)(root, rel))]).filter(([, body]) => body != null)
15561
+ );
15562
+ const findings = [
15563
+ ...checkPins(root, readFile6, docs2).findings,
15564
+ ...checkRefs(root, { exists, isIgnored }, docs2).findings
15565
+ ];
15566
+ if (commandPaths == null) {
15567
+ findings.push({
15568
+ kind: "command-manifest-unavailable",
15569
+ doc: "cli command manifest",
15570
+ line: 0,
15571
+ detail: "the CLI could not enumerate its own commands \u2014 command refs cannot be verified"
15572
+ });
15573
+ } else {
15574
+ findings.push(...checkCommands(docs2, commandPaths).findings);
15575
+ }
15576
+ return { ok: findings.length === 0, findings, docCount: Object.keys(docs2).length };
15577
+ }
15578
+
15378
15579
  // src/docs-audit-command.ts
15379
15580
  function serializeOutcome(outcome) {
15380
15581
  switch (outcome.kind) {
@@ -16298,8 +16499,8 @@ function writeError(res) {
16298
16499
  }
16299
16500
 
16300
16501
  // src/secrets-commands.ts
16301
- var import_node_fs18 = require("node:fs");
16302
- var import_node_path16 = require("node:path");
16502
+ var import_node_fs19 = require("node:fs");
16503
+ var import_node_path17 = require("node:path");
16303
16504
  var import_node_os5 = require("node:os");
16304
16505
 
16305
16506
  // src/project-runtime.ts
@@ -16423,18 +16624,18 @@ function collectMap(value, previous = []) {
16423
16624
  return [...previous, value];
16424
16625
  }
16425
16626
  async function decryptRailsCredentials(input) {
16426
- const appDir = (0, import_node_path16.resolve)(input.appDir ?? process.cwd());
16627
+ const appDir = (0, import_node_path17.resolve)(input.appDir ?? process.cwd());
16427
16628
  const credentialsFile = input.credentialsFile ?? DEFAULT_RAILS_CREDENTIALS_FILE;
16428
16629
  const masterKeyFile = input.masterKeyFile ?? DEFAULT_RAILS_MASTER_KEY_FILE;
16429
- const credentialsPath = (0, import_node_path16.resolve)(appDir, credentialsFile);
16430
- const masterKeyPath = (0, import_node_path16.resolve)(appDir, masterKeyFile);
16630
+ const credentialsPath = (0, import_node_path17.resolve)(appDir, credentialsFile);
16631
+ const masterKeyPath = (0, import_node_path17.resolve)(appDir, masterKeyFile);
16431
16632
  const env = {
16432
16633
  ...process.env,
16433
16634
  MMI_RAILS_CREDENTIALS_FILE: credentialsPath,
16434
16635
  MMI_RAILS_MASTER_KEY_FILE: masterKeyPath
16435
16636
  };
16436
- if ((0, import_node_fs18.existsSync)(masterKeyPath)) {
16437
- env.RAILS_MASTER_KEY = (0, import_node_fs18.readFileSync)(masterKeyPath, "utf8").trim();
16637
+ if ((0, import_node_fs19.existsSync)(masterKeyPath)) {
16638
+ env.RAILS_MASTER_KEY = (0, import_node_fs19.readFileSync)(masterKeyPath, "utf8").trim();
16438
16639
  }
16439
16640
  const script = [
16440
16641
  'require "json"',
@@ -16444,9 +16645,9 @@ async function decryptRailsCredentials(input) {
16444
16645
  'config = ActiveSupport::EncryptedConfiguration.new(config_path: config_path, key_path: key_path, env_key: "RAILS_MASTER_KEY", raise_if_missing_key: true)',
16445
16646
  "puts JSON.generate(config.config)"
16446
16647
  ].join("\n");
16447
- const scriptDir = (0, import_node_fs18.mkdtempSync)((0, import_node_path16.join)((0, import_node_os5.tmpdir)(), "mmi-rails-decrypt-"));
16448
- const scriptPath = (0, import_node_path16.join)(scriptDir, "decrypt.rb");
16449
- (0, import_node_fs18.writeFileSync)(scriptPath, script, "utf8");
16648
+ const scriptDir = (0, import_node_fs19.mkdtempSync)((0, import_node_path17.join)((0, import_node_os5.tmpdir)(), "mmi-rails-decrypt-"));
16649
+ const scriptPath = (0, import_node_path17.join)(scriptDir, "decrypt.rb");
16650
+ (0, import_node_fs19.writeFileSync)(scriptPath, script, "utf8");
16450
16651
  try {
16451
16652
  const args = ["exec", "ruby", scriptPath];
16452
16653
  const cmd = process.platform === "win32" ? "cmd.exe" : "bundle";
@@ -16458,7 +16659,7 @@ async function decryptRailsCredentials(input) {
16458
16659
  });
16459
16660
  return JSON.parse(stdout);
16460
16661
  } finally {
16461
- (0, import_node_fs18.rmSync)(scriptDir, { recursive: true, force: true });
16662
+ (0, import_node_fs19.rmSync)(scriptDir, { recursive: true, force: true });
16462
16663
  }
16463
16664
  }
16464
16665
  async function readSecretStdin() {
@@ -16548,7 +16749,7 @@ function registerSecretsCommands(program3) {
16548
16749
  let body;
16549
16750
  if (o.file) {
16550
16751
  try {
16551
- body = (0, import_node_fs18.readFileSync)((0, import_node_path16.resolve)(o.file), "utf8");
16752
+ body = (0, import_node_fs19.readFileSync)((0, import_node_path17.resolve)(o.file), "utf8");
16552
16753
  } catch (e) {
16553
16754
  return fail(`secrets org-catalog: cannot read --file ${o.file}: ${e.message}`);
16554
16755
  }
@@ -16653,7 +16854,7 @@ function registerSecretsCommands(program3) {
16653
16854
  {
16654
16855
  ...d,
16655
16856
  decryptRailsCredentials,
16656
- removeFile: (path2) => (0, import_node_fs18.unlinkSync)((0, import_node_path16.resolve)(o.appDir ?? process.cwd(), path2))
16857
+ removeFile: (path2) => (0, import_node_fs19.unlinkSync)((0, import_node_path17.resolve)(o.appDir ?? process.cwd(), path2))
16657
16858
  },
16658
16859
  {
16659
16860
  repo: o.repo,
@@ -17028,7 +17229,7 @@ function registerBoxCommands(program3) {
17028
17229
 
17029
17230
  // src/schedules-commands.ts
17030
17231
  var import_promises2 = require("node:fs/promises");
17031
- var import_node_child_process9 = require("node:child_process");
17232
+ var import_node_child_process10 = require("node:child_process");
17032
17233
  var import_node_util7 = require("node:util");
17033
17234
 
17034
17235
  // src/schedules.ts
@@ -17334,7 +17535,7 @@ function assembleReconciliation(githubEntries2, readRepos, registry2, activeWork
17334
17535
  }
17335
17536
 
17336
17537
  // src/schedules-commands.ts
17337
- var execFileP5 = (0, import_node_util7.promisify)(import_node_child_process9.execFile);
17538
+ var execFileP5 = (0, import_node_util7.promisify)(import_node_child_process10.execFile);
17338
17539
  var AWS_REGION = "eu-central-1";
17339
17540
  var AWS_TIMEOUT_MS = 3e4;
17340
17541
  var AWS_RETRY_DELAY_MS = 1500;
@@ -17570,14 +17771,14 @@ function registerSchedulesCommands(program3) {
17570
17771
 
17571
17772
  // src/schedules-lift-command.ts
17572
17773
  var import_promises3 = require("node:fs/promises");
17573
- var import_node_path17 = require("node:path");
17774
+ var import_node_path18 = require("node:path");
17574
17775
 
17575
17776
  // src/schedules-lift.ts
17576
17777
  var SCHEDULE_HEADER_FIELDS = ["schedule", "what", "owner", "cadence", "executor", "llm", "output", "breaks", "kill"];
17577
17778
  function parseScheduleHeader(yamlText) {
17578
17779
  const out = {};
17579
17780
  for (const rawLine of yamlText.split("\n")) {
17580
- const m = /^#\s*(schedule|what|owner|cadence|executor|llm|output|breaks|kill|target):\s*(.+?)\s*$/.exec(rawLine);
17781
+ const m = /^#\s*(schedule|what|owner|cadence|executor|llm|output|breaks|kill|target|model):\s*(.+?)\s*$/.exec(rawLine);
17581
17782
  if (m && out[m[1]] === void 0) out[m[1]] = m[2].trim();
17582
17783
  }
17583
17784
  return out;
@@ -17614,6 +17815,10 @@ function scheduleRecordFromWorkflow(repo, workflowPath, yamlText) {
17614
17815
  if (target !== void 0 && !/^mmi-fleet-[A-Za-z0-9_-]{1,130}$/.test(target)) {
17615
17816
  throw new Error(`schedules lift: ${expectedId} header \`target: ${target}\` must be a bare lambda function name in the reserved fleet namespace \`mmi-fleet-*\` (allowed after the prefix: A-Z a-z 0-9 _ -; total max 140). The dispatcher can only invoke mmi-fleet-* functions.`);
17616
17817
  }
17818
+ const model = header.model;
17819
+ if (model !== void 0 && !/^[a-z][a-z0-9-]{0,30}$/.test(model)) {
17820
+ throw new Error(`schedules lift: ${expectedId} header \`model: ${model}\` must be a model ROLE KEY (lowercase kebab, max 31 chars \u2014 e.g. janitor, arbiter), never a model id \u2014 ids resolve from the vault at dispatch.`);
17821
+ }
17617
17822
  return {
17618
17823
  id: expectedId,
17619
17824
  what: h.what,
@@ -17626,7 +17831,8 @@ function scheduleRecordFromWorkflow(repo, workflowPath, yamlText) {
17626
17831
  kill: h.kill,
17627
17832
  repo,
17628
17833
  sourcePath: workflowPath,
17629
- ...target !== void 0 ? { target } : {}
17834
+ ...target !== void 0 ? { target } : {},
17835
+ ...model !== void 0 ? { model } : {}
17630
17836
  };
17631
17837
  }
17632
17838
  function scheduleRecordsFromWorkflows(repo, files) {
@@ -17671,7 +17877,7 @@ async function readWorkflowFiles(dir) {
17671
17877
  const files = [];
17672
17878
  for (const name of names.sort()) {
17673
17879
  if (!/\.ya?ml$/.test(name)) continue;
17674
- files.push({ path: `.github/workflows/${name}`, text: await (0, import_promises3.readFile)((0, import_node_path17.join)(dir, name), "utf8") });
17880
+ files.push({ path: `.github/workflows/${name}`, text: await (0, import_promises3.readFile)((0, import_node_path18.join)(dir, name), "utf8") });
17675
17881
  }
17676
17882
  return files;
17677
17883
  }
@@ -18211,7 +18417,7 @@ function registerQueryCommands(program3) {
18211
18417
  }
18212
18418
 
18213
18419
  // src/bootstrap-commands.ts
18214
- var import_node_fs19 = require("node:fs");
18420
+ var import_node_fs20 = require("node:fs");
18215
18421
 
18216
18422
  // src/bootstrap-verify.ts
18217
18423
  var TRAIN_BRANCHES2 = ["development", "rc", "main"];
@@ -18759,7 +18965,7 @@ function registerBootstrapCommands(program3) {
18759
18965
  client: defaultGitHubClient(),
18760
18966
  projectMeta: meta,
18761
18967
  deployModel: typeof meta?.deployModel === "string" ? meta.deployModel : void 0,
18762
- readLocalFile: (path2) => path2 === "projects.json" && apiProjects != null ? apiProjects : (0, import_node_fs19.existsSync)(path2) ? (0, import_node_fs19.readFileSync)(path2, "utf8") : null,
18968
+ readLocalFile: (path2) => path2 === "projects.json" && apiProjects != null ? apiProjects : (0, import_node_fs20.existsSync)(path2) ? (0, import_node_fs20.readFileSync)(path2, "utf8") : null,
18763
18969
  // requiredGcpApis is stored as an array by a JSON write, but `org project set --var KEY=VALUE` stores a raw
18764
18970
  // comma-string — accept either so the seeded value verifies regardless of how it was written.
18765
18971
  requiredGcpApis: (() => {
@@ -18810,12 +19016,12 @@ function registerBootstrapCommands(program3) {
18810
19016
  return fail(`bootstrap apply: ${e.message}`);
18811
19017
  }
18812
19018
  const manifestPath = "skills/bootstrap/seeds/manifest.json";
18813
- if (!(0, import_node_fs19.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`);
18814
- const manifest = loadBootstrapSeeds((0, import_node_fs19.readFileSync)(manifestPath, "utf8"));
19019
+ if (!(0, import_node_fs20.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`);
19020
+ const manifest = loadBootstrapSeeds((0, import_node_fs20.readFileSync)(manifestPath, "utf8"));
18815
19021
  const baseBranch = o.class === "content" ? "main" : "development";
18816
19022
  const slug = parsedRepo.slug;
18817
19023
  const gh = async (args) => execFileP2("gh", args, { timeout: 2e4 });
18818
- const readFile6 = (p) => (0, import_node_fs19.existsSync)(p) ? (0, import_node_fs19.readFileSync)(p, "utf8") : null;
19024
+ const readFile6 = (p) => (0, import_node_fs20.existsSync)(p) ? (0, import_node_fs20.readFileSync)(p, "utf8") : null;
18819
19025
  const enc = (p) => p.split("/").map(encodeURIComponent).join("/");
18820
19026
  const rawVars = {};
18821
19027
  for (const value of cmdOpts.var ?? []) {
@@ -19011,12 +19217,12 @@ LIVE apply to ${repo}:
19011
19217
  }
19012
19218
 
19013
19219
  // src/stage-commands.ts
19014
- var import_node_fs21 = require("node:fs");
19015
- var import_node_path19 = require("node:path");
19220
+ var import_node_fs22 = require("node:fs");
19221
+ var import_node_path20 = require("node:path");
19016
19222
 
19017
19223
  // src/port-registry.ts
19018
- var import_node_fs20 = require("node:fs");
19019
- var import_node_path18 = require("node:path");
19224
+ var import_node_fs21 = require("node:fs");
19225
+ var import_node_path19 = require("node:path");
19020
19226
 
19021
19227
  // ../infra/port-geometry.mjs
19022
19228
  var PORT_BLOCK = 100;
@@ -19030,8 +19236,8 @@ function nextPortBlock(registry2) {
19030
19236
  return [base, base + PORT_SPAN];
19031
19237
  }
19032
19238
  function loadPortRegistry(path2) {
19033
- if (!(0, import_node_fs20.existsSync)(path2)) return {};
19034
- const raw = JSON.parse((0, import_node_fs20.readFileSync)(path2, "utf8"));
19239
+ if (!(0, import_node_fs21.existsSync)(path2)) return {};
19240
+ const raw = JSON.parse((0, import_node_fs21.readFileSync)(path2, "utf8"));
19035
19241
  const out = {};
19036
19242
  for (const [key, value] of Object.entries(raw)) {
19037
19243
  if (Array.isArray(value) && value.length === 2 && value.every((n) => typeof n === "number")) {
@@ -19045,9 +19251,9 @@ function ensurePortRange(repo, path2) {
19045
19251
  const existing = registry2[repo];
19046
19252
  if (existing) return existing;
19047
19253
  const range = nextPortBlock(registry2);
19048
- const raw = (0, import_node_fs20.existsSync)(path2) ? JSON.parse((0, import_node_fs20.readFileSync)(path2, "utf8")) : {};
19254
+ const raw = (0, import_node_fs21.existsSync)(path2) ? JSON.parse((0, import_node_fs21.readFileSync)(path2, "utf8")) : {};
19049
19255
  raw[repo] = range;
19050
- (0, import_node_fs20.writeFileSync)(path2, JSON.stringify(raw, null, 2) + "\n", "utf8");
19256
+ (0, import_node_fs21.writeFileSync)(path2, JSON.stringify(raw, null, 2) + "\n", "utf8");
19051
19257
  return range;
19052
19258
  }
19053
19259
  function portCursorSeed(registry2) {
@@ -19069,22 +19275,22 @@ function existingPortRange(repo, registry2) {
19069
19275
  return registry2[repo] ?? null;
19070
19276
  }
19071
19277
  function portRangeInfraAt(root, source) {
19072
- const registryPath = (0, import_node_path18.join)(root, "infra", "port-ranges.json");
19073
- const ddbScriptPath = (0, import_node_path18.join)(root, "infra", "port-ddb.mjs");
19074
- if (!(0, import_node_fs20.existsSync)(registryPath) || !(0, import_node_fs20.existsSync)(ddbScriptPath)) return null;
19278
+ const registryPath = (0, import_node_path19.join)(root, "infra", "port-ranges.json");
19279
+ const ddbScriptPath = (0, import_node_path19.join)(root, "infra", "port-ddb.mjs");
19280
+ if (!(0, import_node_fs21.existsSync)(registryPath) || !(0, import_node_fs21.existsSync)(ddbScriptPath)) return null;
19075
19281
  return { root, source, registryPath, ddbScriptPath };
19076
19282
  }
19077
19283
  function resolvePortRangeInfra(cwd, packageDir) {
19078
19284
  const direct = portRangeInfraAt(cwd, "cwd");
19079
19285
  if (direct) return direct;
19080
- for (let dir = cwd; ; dir = (0, import_node_path18.dirname)(dir)) {
19081
- const sibling = portRangeInfraAt((0, import_node_path18.join)(dir, "MMI-Hub"), "sibling-hub");
19286
+ for (let dir = cwd; ; dir = (0, import_node_path19.dirname)(dir)) {
19287
+ const sibling = portRangeInfraAt((0, import_node_path19.join)(dir, "MMI-Hub"), "sibling-hub");
19082
19288
  if (sibling) return sibling;
19083
- const parent = (0, import_node_path18.dirname)(dir);
19289
+ const parent = (0, import_node_path19.dirname)(dir);
19084
19290
  if (parent === dir) break;
19085
19291
  }
19086
19292
  if (packageDir) {
19087
- const pkgRoot = (0, import_node_path18.join)(packageDir, "..", "..");
19293
+ const pkgRoot = (0, import_node_path19.join)(packageDir, "..", "..");
19088
19294
  const pkgFrom = portRangeInfraAt(pkgRoot, "pkg-root");
19089
19295
  if (pkgFrom) return pkgFrom;
19090
19296
  }
@@ -19260,8 +19466,8 @@ function registerStageCommands(program3) {
19260
19466
  const portRange = portRangeMeta && typeof portRangeMeta.start === "number" && typeof portRangeMeta.end === "number" ? [portRangeMeta.start, portRangeMeta.end] : void 0;
19261
19467
  return decideStage({
19262
19468
  registry: { deployModel: project2?.deployModel, portRange, error: read.ok ? void 0 : read.error },
19263
- hasCompose: (0, import_node_fs21.existsSync)((0, import_node_path19.join)(process.cwd(), "docker-compose.yml")),
19264
- hasEnvExample: (0, import_node_fs21.existsSync)((0, import_node_path19.join)(process.cwd(), ".env.example"))
19469
+ hasCompose: (0, import_node_fs22.existsSync)((0, import_node_path20.join)(process.cwd(), "docker-compose.yml")),
19470
+ hasEnvExample: (0, import_node_fs22.existsSync)((0, import_node_path20.join)(process.cwd(), ".env.example"))
19265
19471
  });
19266
19472
  }
19267
19473
  async function fetchStageVaultEnvMerge() {
@@ -19696,9 +19902,9 @@ function registerBoardCommands(program3) {
19696
19902
  }
19697
19903
 
19698
19904
  // src/merge-cleanup.ts
19699
- var import_node_fs22 = require("node:fs");
19905
+ var import_node_fs23 = require("node:fs");
19700
19906
  var import_promises5 = require("node:fs/promises");
19701
- var import_node_child_process10 = require("node:child_process");
19907
+ var import_node_child_process11 = require("node:child_process");
19702
19908
 
19703
19909
  // src/board-advance.ts
19704
19910
  function repoOf2(ref) {
@@ -19784,7 +19990,7 @@ function boardAdvanceFailureMessage(result) {
19784
19990
 
19785
19991
  // src/deferred-registry-store.ts
19786
19992
  var import_promises4 = require("node:fs/promises");
19787
- var import_node_path20 = require("node:path");
19993
+ var import_node_path21 = require("node:path");
19788
19994
  var sleep = (ms) => new Promise((resolve5) => setTimeout(resolve5, ms));
19789
19995
  async function atomicWrite(target, contents) {
19790
19996
  const tmp = `${target}.tmp-${process.pid}-${Math.random().toString(36).slice(2)}`;
@@ -19888,12 +20094,12 @@ function makeDeferredWorktreeStore(registryPath, lockOpts = {}) {
19888
20094
  },
19889
20095
  // Standalone atomic write — THROWS on failure (no best-effort swallow, #2846).
19890
20096
  write: async (entries) => {
19891
- await (0, import_promises4.mkdir)((0, import_node_path20.dirname)(registryPath), { recursive: true });
20097
+ await (0, import_promises4.mkdir)((0, import_node_path21.dirname)(registryPath), { recursive: true });
19892
20098
  await atomicWrite(registryPath, serializeDeferredWorktrees(entries));
19893
20099
  },
19894
20100
  // Serialized read-modify-write under the repo-wide lock (#2846).
19895
20101
  update: async (mutate) => {
19896
- await (0, import_promises4.mkdir)((0, import_node_path20.dirname)(registryPath), { recursive: true });
20102
+ await (0, import_promises4.mkdir)((0, import_node_path21.dirname)(registryPath), { recursive: true });
19897
20103
  const deadline = Date.now() + opts.maxWaitMs;
19898
20104
  for (; ; ) {
19899
20105
  const guard = await acquireLock(lockPath, opts, deadline);
@@ -20020,7 +20226,7 @@ async function applyGcPlan(plan, remote) {
20020
20226
  return cleanupPrMergeLocalBranch(branch.branch, {
20021
20227
  beforeWorktrees,
20022
20228
  startingPath: branch.worktreePath,
20023
- pathExists: (p) => (0, import_node_fs22.existsSync)(p),
20229
+ pathExists: (p) => (0, import_node_fs23.existsSync)(p),
20024
20230
  execGit: async (args) => (await execFileP2("git", args, { timeout: GIT_TIMEOUT_MS })).stdout,
20025
20231
  teardownWorktreeStage,
20026
20232
  deferredStore,
@@ -20046,7 +20252,7 @@ async function applyGcPlan(plan, remote) {
20046
20252
  for (const wt of plan.worktreeDirs) {
20047
20253
  try {
20048
20254
  const cleanupTarget = resolveSafeSiblingWorktreeCleanupTarget(wt.path, siblingRoot, {
20049
- realpath: (path2) => (0, import_node_fs22.realpathSync)(path2)
20255
+ realpath: (path2) => (0, import_node_fs23.realpathSync)(path2)
20050
20256
  });
20051
20257
  if (!cleanupTarget.ok) {
20052
20258
  result.failed.push(`${wt.path}: ${cleanupTarget.reason}`);
@@ -20159,7 +20365,7 @@ async function remoteBranchExists2(branch, options = {}) {
20159
20365
  }
20160
20366
  var COMPOSE_TIMEOUT_MS = 12e4;
20161
20367
  function spawnDeferredGcSweep() {
20162
- spawnDetachedSelf(["worktree", "gc", "sweep-deferred", "--quiet"], { spawn: import_node_child_process10.spawn, execPath: process.execPath, scriptPath: process.argv[1] });
20368
+ spawnDetachedSelf(["worktree", "gc", "sweep-deferred", "--quiet"], { spawn: import_node_child_process11.spawn, execPath: process.execPath, scriptPath: process.argv[1] });
20163
20369
  }
20164
20370
  async function createDeferredWorktreeStore() {
20165
20371
  try {
@@ -20173,13 +20379,13 @@ var realWorktreeDirRemover = {
20173
20379
  probe: (p) => {
20174
20380
  let st;
20175
20381
  try {
20176
- st = (0, import_node_fs22.lstatSync)(p);
20382
+ st = (0, import_node_fs23.lstatSync)(p);
20177
20383
  } catch {
20178
20384
  return null;
20179
20385
  }
20180
20386
  if (st.isSymbolicLink()) return "link";
20181
20387
  try {
20182
- (0, import_node_fs22.readlinkSync)(p);
20388
+ (0, import_node_fs23.readlinkSync)(p);
20183
20389
  return "link";
20184
20390
  } catch {
20185
20391
  }
@@ -20187,7 +20393,7 @@ var realWorktreeDirRemover = {
20187
20393
  },
20188
20394
  readdir: (p) => {
20189
20395
  try {
20190
- return (0, import_node_fs22.readdirSync)(p);
20396
+ return (0, import_node_fs23.readdirSync)(p);
20191
20397
  } catch {
20192
20398
  return [];
20193
20399
  }
@@ -20196,9 +20402,9 @@ var realWorktreeDirRemover = {
20196
20402
  // leaving the target); a file symlink with unlink. rmdir first, fall back to unlink.
20197
20403
  detachLink: (p) => {
20198
20404
  try {
20199
- (0, import_node_fs22.rmdirSync)(p);
20405
+ (0, import_node_fs23.rmdirSync)(p);
20200
20406
  } catch {
20201
- (0, import_node_fs22.unlinkSync)(p);
20407
+ (0, import_node_fs23.unlinkSync)(p);
20202
20408
  }
20203
20409
  },
20204
20410
  removeTree: (p) => (0, import_promises5.rm)(p, { recursive: true, force: true, maxRetries: 5, retryDelay: 200 })
@@ -20231,9 +20437,9 @@ async function worktreeHasStageState(worktreePath) {
20231
20437
  }
20232
20438
  }
20233
20439
  function stageStateFileBelongsToWorktree(statePath, worktreePath) {
20234
- if (!(0, import_node_fs22.existsSync)(statePath)) return false;
20440
+ if (!(0, import_node_fs23.existsSync)(statePath)) return false;
20235
20441
  try {
20236
- const state = JSON.parse((0, import_node_fs22.readFileSync)(statePath, "utf8"));
20442
+ const state = JSON.parse((0, import_node_fs23.readFileSync)(statePath, "utf8"));
20237
20443
  const recordedCwd = typeof state.identity?.cwd === "string" ? state.identity.cwd : typeof state.cwd === "string" ? state.cwd : "";
20238
20444
  return Boolean(recordedCwd && isPathUnderDirectory(recordedCwd, worktreePath));
20239
20445
  } catch {
@@ -20361,8 +20567,8 @@ async function fetchRestCorePool(gh = defaultGhApi) {
20361
20567
  }
20362
20568
 
20363
20569
  // src/worktree-lifecycle-commands.ts
20364
- var import_node_fs23 = require("node:fs");
20365
- var import_node_path21 = require("node:path");
20570
+ var import_node_fs24 = require("node:fs");
20571
+ var import_node_path22 = require("node:path");
20366
20572
  var GH_TIMEOUT_MS = 2e4;
20367
20573
  var DEFAULT_BASE = "origin/development";
20368
20574
  var DEFAULT_REMOTE = "origin";
@@ -20499,13 +20705,13 @@ function registerWorktreeCommands(program3) {
20499
20705
  if (PROTECTED_BRANCHES2.has(branch)) {
20500
20706
  return fail(`worktree land: refusing to land protected branch '${branch}'`, { code: ERROR_CODES.ERR_BAD_ENUM });
20501
20707
  }
20502
- const gitFile = (0, import_node_path21.join)(wtPath, ".git");
20503
- const isLinked = (0, import_node_fs23.existsSync)(gitFile) && (0, import_node_fs23.statSync)(gitFile).isFile();
20708
+ const gitFile = (0, import_node_path22.join)(wtPath, ".git");
20709
+ const isLinked = (0, import_node_fs24.existsSync)(gitFile) && (0, import_node_fs24.statSync)(gitFile).isFile();
20504
20710
  if (apply && !isLinked) {
20505
20711
  return fail("worktree land: run from inside the linked worktree you want to land (this is the primary checkout)");
20506
20712
  }
20507
20713
  const commonDir = (await execFileP2("git", ["rev-parse", "--git-common-dir"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim();
20508
- const primaryCheckout = commonDir ? (0, import_node_path21.dirname)(commonDir) : wtPath;
20714
+ const primaryCheckout = commonDir ? (0, import_node_path22.dirname)(commonDir) : wtPath;
20509
20715
  const stageSummary = readStageSummary(wtPath);
20510
20716
  const hasStage = stageSummary != null;
20511
20717
  const steps = landSteps(branch, true, hasStage);
@@ -20617,10 +20823,10 @@ async function gatherWorktreeContext() {
20617
20823
  }
20618
20824
  const orphanDirs = [];
20619
20825
  const wtRoot = siblingMmiWorktreesRoot(repoRoot2);
20620
- if ((0, import_node_fs23.existsSync)(wtRoot)) {
20826
+ if ((0, import_node_fs24.existsSync)(wtRoot)) {
20621
20827
  let entries = [];
20622
20828
  try {
20623
- entries = (0, import_node_fs23.readdirSync)(wtRoot, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => (0, import_node_path21.join)(wtRoot, e.name));
20829
+ entries = (0, import_node_fs24.readdirSync)(wtRoot, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => (0, import_node_path22.join)(wtRoot, e.name));
20624
20830
  } catch {
20625
20831
  }
20626
20832
  const known = new Set(worktrees.map((w) => w.path));
@@ -20645,7 +20851,7 @@ async function bestEffortGit(args, cwd, step, timeoutMs = GIT_TIMEOUT_MS) {
20645
20851
  }
20646
20852
 
20647
20853
  // src/issue-commands.ts
20648
- var import_node_fs24 = require("node:fs");
20854
+ var import_node_fs25 = require("node:fs");
20649
20855
  var import_node_crypto5 = require("node:crypto");
20650
20856
  var ghRunner = async (args, timeoutMs) => (await execFileP2("gh", args, { timeout: timeoutMs })).stdout;
20651
20857
  async function editIssue(client, options, deps = {}) {
@@ -20659,7 +20865,7 @@ async function editIssue(client, options, deps = {}) {
20659
20865
  if (options.body !== void 0 || options.bodyFile !== void 0) {
20660
20866
  let body;
20661
20867
  if (options.bodyFile) {
20662
- const td = deps.textDeps ?? { readFile: (p, e) => Promise.resolve((0, import_node_fs24.readFileSync)(p, e)), readStdin: () => Promise.resolve("") };
20868
+ const td = deps.textDeps ?? { readFile: (p, e) => Promise.resolve((0, import_node_fs25.readFileSync)(p, e)), readStdin: () => Promise.resolve("") };
20663
20869
  body = await resolveIssueBody({ body: options.body, bodyFile: options.bodyFile }, td);
20664
20870
  } else {
20665
20871
  body = options.body ?? "";
@@ -21142,7 +21348,7 @@ function extendCreateCommand(issue2) {
21142
21348
  if (opts.batch) {
21143
21349
  let specs;
21144
21350
  try {
21145
- const raw = (0, import_node_fs24.readFileSync)(opts.batch, "utf8");
21351
+ const raw = (0, import_node_fs25.readFileSync)(opts.batch, "utf8");
21146
21352
  specs = JSON.parse(raw);
21147
21353
  if (!Array.isArray(specs)) throw new Error("batch file must contain a JSON array");
21148
21354
  } catch (e) {
@@ -21186,12 +21392,12 @@ ${lines}`);
21186
21392
  }
21187
21393
 
21188
21394
  // src/train-commands.ts
21189
- var import_node_fs26 = require("node:fs");
21190
- var import_node_path23 = require("node:path");
21395
+ var import_node_fs27 = require("node:fs");
21396
+ var import_node_path24 = require("node:path");
21191
21397
 
21192
21398
  // src/plugin-guard-io.ts
21193
- var import_node_fs25 = require("node:fs");
21194
- var import_node_path22 = require("node:path");
21399
+ var import_node_fs26 = require("node:fs");
21400
+ var import_node_path23 = require("node:path");
21195
21401
  var import_node_os6 = require("node:os");
21196
21402
 
21197
21403
  // src/plugin-guard.ts
@@ -21321,11 +21527,11 @@ function runHostBin(bin, args, opts) {
21321
21527
  }
21322
21528
  var installedPluginsPath2 = (surface = detectSurface(process.env)) => {
21323
21529
  const homeDir = surface === "codex" ? ".codex" : ".claude";
21324
- return (0, import_node_path22.join)((0, import_node_os6.homedir)(), homeDir, "plugins", "installed_plugins.json");
21530
+ return (0, import_node_path23.join)((0, import_node_os6.homedir)(), homeDir, "plugins", "installed_plugins.json");
21325
21531
  };
21326
21532
  function readInstalledPlugins(surface = detectSurface(process.env)) {
21327
21533
  try {
21328
- return JSON.parse((0, import_node_fs25.readFileSync)(installedPluginsPath2(surface), "utf8"));
21534
+ return JSON.parse((0, import_node_fs26.readFileSync)(installedPluginsPath2(surface), "utf8"));
21329
21535
  } catch {
21330
21536
  return null;
21331
21537
  }
@@ -21333,13 +21539,13 @@ function readInstalledPlugins(surface = detectSurface(process.env)) {
21333
21539
  function marketplaceCloneCandidates(surface, home) {
21334
21540
  if (surface === "codex") {
21335
21541
  return [
21336
- (0, import_node_path22.join)(home, ".codex", ".tmp", "marketplaces", "mutmutco"),
21337
- (0, import_node_path22.join)(home, ".codex", "plugins", "marketplaces", "mutmutco")
21542
+ (0, import_node_path23.join)(home, ".codex", ".tmp", "marketplaces", "mutmutco"),
21543
+ (0, import_node_path23.join)(home, ".codex", "plugins", "marketplaces", "mutmutco")
21338
21544
  ];
21339
21545
  }
21340
- return [(0, import_node_path22.join)(home, ".claude", "plugins", "marketplaces", "mutmutco")];
21546
+ return [(0, import_node_path23.join)(home, ".claude", "plugins", "marketplaces", "mutmutco")];
21341
21547
  }
21342
- function marketplaceClonePresent(surface, home, exists = import_node_fs25.existsSync) {
21548
+ function marketplaceClonePresent(surface, home, exists = import_node_fs26.existsSync) {
21343
21549
  return marketplaceCloneCandidates(surface, home).some(exists);
21344
21550
  }
21345
21551
  async function fetchNpmReleasedVersion() {
@@ -21366,7 +21572,7 @@ function snapshotPluginGuardInput(surface = detectSurface(process.env), isOrgRep
21366
21572
  isOrgRepo,
21367
21573
  installRecordPresent: hasUserInstallRecord(installed, MMI_PLUGIN_ID) || hasProjectInstallRecord(installed, MMI_PLUGIN_ID, process.cwd()),
21368
21574
  marketplaceClonePresent: marketplaceClonePresent(surface, (0, import_node_os6.homedir)()),
21369
- pluginCachePresent: (0, import_node_fs25.existsSync)((0, import_node_path22.join)((0, import_node_os6.homedir)(), homeDir, "plugins", "cache", "mutmutco", "mmi"))
21575
+ pluginCachePresent: (0, import_node_fs26.existsSync)((0, import_node_path23.join)((0, import_node_os6.homedir)(), homeDir, "plugins", "cache", "mutmutco", "mmi"))
21370
21576
  };
21371
21577
  }
21372
21578
  function claudePluginGuardState(isOrgRepo) {
@@ -21501,7 +21707,7 @@ function formatTrainStatus(r) {
21501
21707
  // src/train-commands.ts
21502
21708
  function readRepoVersion() {
21503
21709
  try {
21504
- return JSON.parse((0, import_node_fs26.readFileSync)((0, import_node_path23.join)(process.cwd(), ".claude-plugin", "plugin.json"), "utf8")).version || void 0;
21710
+ return JSON.parse((0, import_node_fs27.readFileSync)((0, import_node_path24.join)(process.cwd(), ".claude-plugin", "plugin.json"), "utf8")).version || void 0;
21505
21711
  } catch {
21506
21712
  return void 0;
21507
21713
  }
@@ -22953,17 +23159,17 @@ async function runDoctorClean(opts, io, deps) {
22953
23159
  }
22954
23160
 
22955
23161
  // src/doctor-io.ts
22956
- var import_node_fs27 = require("node:fs");
23162
+ var import_node_fs28 = require("node:fs");
22957
23163
  var import_node_os7 = require("node:os");
22958
- var import_node_path24 = require("node:path");
22959
- var import_node_child_process11 = require("node:child_process");
23164
+ var import_node_path25 = require("node:path");
23165
+ var import_node_child_process12 = require("node:child_process");
22960
23166
  var import_node_util8 = require("node:util");
22961
- var execFileP6 = (0, import_node_util8.promisify)(import_node_child_process11.execFile);
23167
+ var execFileP6 = (0, import_node_util8.promisify)(import_node_child_process12.execFile);
22962
23168
  var MMI_PLUGIN_ID2 = "mmi@mutmutco";
22963
23169
  function installedClaudePluginVersion() {
22964
23170
  try {
22965
23171
  const file = JSON.parse(
22966
- (0, import_node_fs27.readFileSync)((0, import_node_path24.join)((0, import_node_os7.homedir)(), ".claude", "plugins", "installed_plugins.json"), "utf8")
23172
+ (0, import_node_fs28.readFileSync)((0, import_node_path25.join)((0, import_node_os7.homedir)(), ".claude", "plugins", "installed_plugins.json"), "utf8")
22967
23173
  );
22968
23174
  const versions = (file.plugins?.[MMI_PLUGIN_ID2] ?? []).map((r) => r.version).filter((v) => Boolean(v));
22969
23175
  if (versions.length === 0) return void 0;
@@ -22974,7 +23180,7 @@ function installedClaudePluginVersion() {
22974
23180
  }
22975
23181
  function worktreeRootSync() {
22976
23182
  try {
22977
- const out = (0, import_node_child_process11.execFileSync)("git", ["rev-parse", "--show-toplevel"], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] });
23183
+ const out = (0, import_node_child_process12.execFileSync)("git", ["rev-parse", "--show-toplevel"], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] });
22978
23184
  let root = out.endsWith("\n") ? out.slice(0, -1) : out;
22979
23185
  if (process.platform === "win32" && root.endsWith("\r")) root = root.slice(0, -1);
22980
23186
  return root || null;
@@ -22984,13 +23190,13 @@ function worktreeRootSync() {
22984
23190
  }
22985
23191
  var gitignorePath = () => {
22986
23192
  const root = worktreeRootSync();
22987
- return root === null ? null : (0, import_node_path24.join)(root, ".gitignore");
23193
+ return root === null ? null : (0, import_node_path25.join)(root, ".gitignore");
22988
23194
  };
22989
23195
  function readGitignore() {
22990
23196
  const path2 = gitignorePath();
22991
23197
  if (path2 === null) return null;
22992
23198
  try {
22993
- return (0, import_node_fs27.readFileSync)(path2, "utf8");
23199
+ return (0, import_node_fs28.readFileSync)(path2, "utf8");
22994
23200
  } catch {
22995
23201
  return null;
22996
23202
  }
@@ -22999,7 +23205,7 @@ function writeGitignore(content) {
22999
23205
  const path2 = gitignorePath();
23000
23206
  if (path2 === null) return false;
23001
23207
  try {
23002
- (0, import_node_fs27.writeFileSync)(path2, content, "utf8");
23208
+ (0, import_node_fs28.writeFileSync)(path2, content, "utf8");
23003
23209
  return true;
23004
23210
  } catch {
23005
23211
  return false;
@@ -23023,7 +23229,7 @@ async function repoRoot() {
23023
23229
  }
23024
23230
  function hasRepoLocalWorktrees() {
23025
23231
  const root = worktreeRootSync();
23026
- return root !== null && (0, import_node_fs27.existsSync)((0, import_node_path24.join)(root, ".worktrees"));
23232
+ return root !== null && (0, import_node_fs28.existsSync)((0, import_node_path25.join)(root, ".worktrees"));
23027
23233
  }
23028
23234
 
23029
23235
  // src/index.ts
@@ -23141,16 +23347,16 @@ var cachedLongFlags;
23141
23347
  function allLongFlags() {
23142
23348
  if (cachedLongFlags) return cachedLongFlags;
23143
23349
  const acc = /* @__PURE__ */ new Set();
23144
- const walk = (node) => {
23350
+ const walk2 = (node) => {
23145
23351
  if (!isCanonicalSuggestion(node)) return;
23146
23352
  for (const opt of node.options) {
23147
23353
  if (opt.discovery) continue;
23148
23354
  const m = /--[\w-]+/.exec(opt.flags);
23149
23355
  if (m) acc.add(m[0]);
23150
23356
  }
23151
- for (const child2 of node.subcommands) walk(child2);
23357
+ for (const child2 of node.subcommands) walk2(child2);
23152
23358
  };
23153
- walk(buildCommandManifest(program2).tree);
23359
+ walk2(buildCommandManifest(program2).tree);
23154
23360
  cachedLongFlags = [...acc];
23155
23361
  return cachedLongFlags;
23156
23362
  }
@@ -23250,19 +23456,19 @@ program2.hook("preAction", async (_thisCommand, actionCommand) => {
23250
23456
  });
23251
23457
  var rules = program2.command("rules").description("org-managed .gitignore delivery");
23252
23458
  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) => {
23253
- const path2 = (0, import_node_path25.join)(process.cwd(), ".gitignore");
23254
- const current = (0, import_node_fs28.existsSync)(path2) ? (0, import_node_fs28.readFileSync)(path2, "utf8") : null;
23459
+ const path2 = (0, import_node_path26.join)(process.cwd(), ".gitignore");
23460
+ const current = (0, import_node_fs29.existsSync)(path2) ? (0, import_node_fs29.readFileSync)(path2, "utf8") : null;
23255
23461
  const plan = planManagedGitignore(current);
23256
23462
  const drift = [...plan.added.map((l) => `+${l}`), ...plan.removed.map((l) => `-${l}`)].join(", ") || "block normalize";
23257
23463
  if (opts.json) {
23258
- if (opts.write && plan.changed) (0, import_node_fs28.writeFileSync)(path2, plan.content, "utf8");
23464
+ if (opts.write && plan.changed) (0, import_node_fs29.writeFileSync)(path2, plan.content, "utf8");
23259
23465
  console.log(JSON.stringify(plan, null, 2));
23260
23466
  if (!opts.write && plan.changed) process.exitCode = 1;
23261
23467
  return;
23262
23468
  }
23263
23469
  if (opts.write) {
23264
23470
  if (plan.changed) {
23265
- (0, import_node_fs28.writeFileSync)(path2, plan.content, "utf8");
23471
+ (0, import_node_fs29.writeFileSync)(path2, plan.content, "utf8");
23266
23472
  console.log(`mmi-cli org rules gitignore: updated .gitignore (${drift})`);
23267
23473
  } else {
23268
23474
  console.log("mmi-cli org rules gitignore: up to date");
@@ -23420,7 +23626,7 @@ function runWorktreeInstall(command, cwd, quiet) {
23420
23626
  const file = isWin2 ? "cmd.exe" : bin;
23421
23627
  const spawnArgs = isWin2 ? ["/c", bin, ...args] : args;
23422
23628
  return new Promise((resolve5, reject) => {
23423
- const child2 = (0, import_node_child_process12.spawn)(file, spawnArgs, { cwd, stdio: quiet ? "ignore" : "inherit", windowsHide: true });
23629
+ const child2 = (0, import_node_child_process13.spawn)(file, spawnArgs, { cwd, stdio: quiet ? "ignore" : "inherit", windowsHide: true });
23424
23630
  const timer = setTimeout(() => {
23425
23631
  try {
23426
23632
  child2.kill();
@@ -23452,26 +23658,26 @@ function makeProvisionDeps(worktreeRoot, quiet, log) {
23452
23658
  function acquireWorktreeSetupLock(worktreeRoot) {
23453
23659
  const lockPath = repoRuntimeStatePath(worktreeRoot, "worktree-setup.lock");
23454
23660
  const take = () => {
23455
- const fd = (0, import_node_fs28.openSync)(lockPath, "wx");
23661
+ const fd = (0, import_node_fs29.openSync)(lockPath, "wx");
23456
23662
  try {
23457
- (0, import_node_fs28.writeSync)(fd, String(Date.now()));
23663
+ (0, import_node_fs29.writeSync)(fd, String(Date.now()));
23458
23664
  } finally {
23459
- (0, import_node_fs28.closeSync)(fd);
23665
+ (0, import_node_fs29.closeSync)(fd);
23460
23666
  }
23461
23667
  return () => {
23462
23668
  try {
23463
- (0, import_node_fs28.rmSync)(lockPath, { force: true });
23669
+ (0, import_node_fs29.rmSync)(lockPath, { force: true });
23464
23670
  } catch {
23465
23671
  }
23466
23672
  };
23467
23673
  };
23468
23674
  try {
23469
- (0, import_node_fs28.mkdirSync)((0, import_node_path25.dirname)(lockPath), { recursive: true });
23675
+ (0, import_node_fs29.mkdirSync)((0, import_node_path26.dirname)(lockPath), { recursive: true });
23470
23676
  return take();
23471
23677
  } catch {
23472
23678
  try {
23473
- if (Date.now() - (0, import_node_fs28.statSync)(lockPath).mtimeMs > WORKTREE_SETUP_LOCK_TTL_MS) {
23474
- (0, import_node_fs28.rmSync)(lockPath, { force: true });
23679
+ if (Date.now() - (0, import_node_fs29.statSync)(lockPath).mtimeMs > WORKTREE_SETUP_LOCK_TTL_MS) {
23680
+ (0, import_node_fs29.rmSync)(lockPath, { force: true });
23475
23681
  return take();
23476
23682
  }
23477
23683
  } catch {
@@ -23651,7 +23857,7 @@ function scheduleRelatedDiscovery(o) {
23651
23857
  try {
23652
23858
  const args = ["issue", "discover-related", "--number", String(o.number), "--title", o.title, "--body", o.body, "--fail-soft"];
23653
23859
  if (o.repo) args.push("--repo", o.repo);
23654
- spawnDetachedSelf(args, { spawn: import_node_child_process12.spawn, execPath: process.execPath, scriptPath: process.argv[1] }, { cwd: process.cwd() });
23860
+ spawnDetachedSelf(args, { spawn: import_node_child_process13.spawn, execPath: process.execPath, scriptPath: process.argv[1] }, { cwd: process.cwd() });
23655
23861
  } catch {
23656
23862
  }
23657
23863
  }
@@ -23677,6 +23883,27 @@ docs.command("index").description("regenerate docs/index.md from the docs/ tree
23677
23883
  await failGraceful(e.message);
23678
23884
  }
23679
23885
  });
23886
+ docs.command("refs").description("deterministic doc reference gate: every backticked repo path, relative .md link, `mmi-cli` command ref, and `<!-- pinned by \u2026 -->` comment across docs/** + README.md + architecture.md must resolve, or exit 1 (fleet-portable port of the Hub gate scripts/check-doc-refs.mjs, #3339)").option("--json", "machine-readable findings list: { ok, docCount, findings[] }").action(async (o) => {
23887
+ try {
23888
+ const root = await repoRoot();
23889
+ const commandPaths = new Set(buildCommandManifest(program2).index.map((entry) => entry.path));
23890
+ const result = runDocRefs(root, { commandPaths });
23891
+ if (o.json) {
23892
+ consoleIo.log(JSON.stringify({ ok: result.ok, docCount: result.docCount, findings: result.findings }, null, 2));
23893
+ if (!result.ok) process.exitCode = 1;
23894
+ return;
23895
+ }
23896
+ if (result.ok) {
23897
+ console.log(`doc refs: ${result.docCount} docs, every reference resolves`);
23898
+ return;
23899
+ }
23900
+ console.error("doc refs: unresolved references");
23901
+ for (const f of result.findings) console.error(`- ${f.doc}:${f.line} [${f.kind}] ${f.detail}`);
23902
+ process.exitCode = 1;
23903
+ } catch (e) {
23904
+ await failGraceful(e.message);
23905
+ }
23906
+ });
23680
23907
  var docsAudit = program2.command("docs-audit").description("the docs janitor verdict ledger \u2014 record a dated run verdict, or read the dead-man status back");
23681
23908
  docsAudit.command("record").description("write a dated janitor verdict for one repo to the registry ledger (master-only server-side)").option("--repo <owner/name>", "the repo the verdict is for (default: the current repo)").option("--date <YYYY-MM-DD>", "the ISO day the run examined (default: today)").requiredOption("--sha-range <a..b>", "the git range the janitor read (e.g. <lastVerdictSha>..HEAD)").requiredOption("--outcome <kind>", "clean | refreshed | failed").option("--count <n>", "docs refreshed (required when --outcome refreshed)").option("--reason <text>", "why the run failed (required when --outcome failed)").requiredOption("--checker-vendor <vendor>", "which vendor's model actually ran the check").action(async (o) => {
23682
23909
  try {
@@ -23892,7 +24119,7 @@ project.command("set [owner/repo]").description("upsert project META (idempotent
23892
24119
  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`);
23893
24120
  if (o.secretsFile) {
23894
24121
  try {
23895
- vars.push(`secrets=${(0, import_node_fs28.readFileSync)(o.secretsFile, "utf8")}`);
24122
+ vars.push(`secrets=${(0, import_node_fs29.readFileSync)(o.secretsFile, "utf8")}`);
23896
24123
  } catch (e) {
23897
24124
  return fail(`org project set: cannot read --secrets-file ${o.secretsFile}: ${e.message}`);
23898
24125
  }
@@ -24527,11 +24754,11 @@ pr.command("view <number>").description("read a PR as structured JSON (merged st
24527
24754
  }
24528
24755
  });
24529
24756
  async function listCiWorkflowPaths(cwd = process.cwd()) {
24530
- const wfDir = (0, import_node_path25.join)(cwd, ".github", "workflows");
24531
- if (!(0, import_node_fs28.existsSync)(wfDir)) return [];
24532
- return (0, import_node_fs28.readdirSync)(wfDir).filter((name) => /\.(ya?ml)$/i.test(name)).filter((name) => {
24757
+ const wfDir = (0, import_node_path26.join)(cwd, ".github", "workflows");
24758
+ if (!(0, import_node_fs29.existsSync)(wfDir)) return [];
24759
+ return (0, import_node_fs29.readdirSync)(wfDir).filter((name) => /\.(ya?ml)$/i.test(name)).filter((name) => {
24533
24760
  try {
24534
- return workflowReportsPrChecks((0, import_node_fs28.readFileSync)((0, import_node_path25.join)(wfDir, name), "utf8"));
24761
+ return workflowReportsPrChecks((0, import_node_fs29.readFileSync)((0, import_node_path26.join)(wfDir, name), "utf8"));
24535
24762
  } catch {
24536
24763
  return true;
24537
24764
  }
@@ -24558,16 +24785,16 @@ function ciAuditDeps() {
24558
24785
  // gate re-seed step is skipped gracefully rather than failing mid-run.
24559
24786
  readSeedFile: (path2) => {
24560
24787
  if (!root) return null;
24561
- const fullPath = (0, import_node_path25.join)(root, path2);
24562
- return (0, import_node_fs28.existsSync)(fullPath) ? (0, import_node_fs28.readFileSync)(fullPath, "utf8") : null;
24788
+ const fullPath = (0, import_node_path26.join)(root, path2);
24789
+ return (0, import_node_fs29.existsSync)(fullPath) ? (0, import_node_fs29.readFileSync)(fullPath, "utf8") : null;
24563
24790
  }
24564
24791
  };
24565
24792
  }
24566
24793
  function hubRoot() {
24567
- const fromPkg = (0, import_node_path25.join)(__dirname, "..", "..");
24794
+ const fromPkg = (0, import_node_path26.join)(__dirname, "..", "..");
24568
24795
  const marker = "skills/bootstrap/seeds/manifest.json";
24569
- if ((0, import_node_fs28.existsSync)((0, import_node_path25.join)(fromPkg, marker))) return fromPkg;
24570
- if ((0, import_node_fs28.existsSync)((0, import_node_path25.join)(process.cwd(), marker))) return process.cwd();
24796
+ if ((0, import_node_fs29.existsSync)((0, import_node_path26.join)(fromPkg, marker))) return fromPkg;
24797
+ if ((0, import_node_fs29.existsSync)((0, import_node_path26.join)(process.cwd(), marker))) return process.cwd();
24571
24798
  return null;
24572
24799
  }
24573
24800
  pr.command("ci-policy").description("report merge CI policy: wait-for-checks vs no-ci (for grind/build agents)").option("--json", "machine-readable output").option("--repo <owner/repo>", "target repo (defaults to the current checkout)").action(async (o) => {
@@ -24806,7 +25033,7 @@ pr.command("merge <number>").description("merge a PR (squash by default) and cle
24806
25033
  localCleanup = await cleanupPrMergeLocalBranch(headRef, {
24807
25034
  beforeWorktrees,
24808
25035
  startingPath,
24809
- pathExists: (p) => (0, import_node_fs28.existsSync)(p),
25036
+ pathExists: (p) => (0, import_node_fs29.existsSync)(p),
24810
25037
  execGit: async (args) => (await execFileP2("git", args, { timeout: GIT_TIMEOUT_MS })).stdout,
24811
25038
  teardownWorktreeStage,
24812
25039
  deferredStore,
@@ -25146,10 +25373,10 @@ access.command("audit").description("audit collaborator roles + train-branch pus
25146
25373
  targets = resolution.targets;
25147
25374
  }
25148
25375
  const derivedMatrix = registryProjects ? accessMatrixFromProjects(registryProjects) : {};
25149
- const fileMatrix = (0, import_node_fs28.existsSync)("access-matrix.json") ? loadAccessMatrix((0, import_node_fs28.readFileSync)("access-matrix.json", "utf8")) : {};
25376
+ const fileMatrix = (0, import_node_fs29.existsSync)("access-matrix.json") ? loadAccessMatrix((0, import_node_fs29.readFileSync)("access-matrix.json", "utf8")) : {};
25150
25377
  const matrix = mergeAccessMatrix(fileMatrix, derivedMatrix);
25151
25378
  const derivedContracts = registryProjects ? dataAccessContractsFromProjects(registryProjects) : { consumers: {} };
25152
- const fileContracts = (0, import_node_fs28.existsSync)("data-access-contracts.json") ? loadDataAccessContracts((0, import_node_fs28.readFileSync)("data-access-contracts.json", "utf8")) : { consumers: {} };
25379
+ const fileContracts = (0, import_node_fs29.existsSync)("data-access-contracts.json") ? loadDataAccessContracts((0, import_node_fs29.readFileSync)("data-access-contracts.json", "utf8")) : { consumers: {} };
25153
25380
  const dataAccess = mergeDataAccessContracts(fileContracts, derivedContracts);
25154
25381
  const report = await auditOrgAccess(targets, deps, matrix, dataAccess);
25155
25382
  console.log(o.json ? JSON.stringify(report, null, 2) : renderAccessReport(report));
@@ -25182,16 +25409,16 @@ function directoryBytes(path2) {
25182
25409
  let total = 0;
25183
25410
  let entries;
25184
25411
  try {
25185
- entries = (0, import_node_fs28.readdirSync)(path2, { withFileTypes: true });
25412
+ entries = (0, import_node_fs29.readdirSync)(path2, { withFileTypes: true });
25186
25413
  } catch {
25187
25414
  return 0;
25188
25415
  }
25189
25416
  for (const entry of entries) {
25190
- const child2 = (0, import_node_path25.join)(path2, entry.name);
25417
+ const child2 = (0, import_node_path26.join)(path2, entry.name);
25191
25418
  if (entry.isDirectory()) total += directoryBytes(child2);
25192
25419
  else {
25193
25420
  try {
25194
- total += (0, import_node_fs28.statSync)(child2).size;
25421
+ total += (0, import_node_fs29.statSync)(child2).size;
25195
25422
  } catch {
25196
25423
  }
25197
25424
  }
@@ -25199,25 +25426,25 @@ function directoryBytes(path2) {
25199
25426
  return total;
25200
25427
  }
25201
25428
  function listDirEntries(dir) {
25202
- return (0, import_node_fs28.readdirSync)(dir, { withFileTypes: true }).map((d) => ({ name: d.name, isDirectory: d.isDirectory() }));
25429
+ return (0, import_node_fs29.readdirSync)(dir, { withFileTypes: true }).map((d) => ({ name: d.name, isDirectory: d.isDirectory() }));
25203
25430
  }
25204
25431
  function readInstalledPluginRefs(home) {
25205
25432
  const p = installedPluginsPath(home);
25206
- if (!(0, import_node_fs28.existsSync)(p)) return [];
25433
+ if (!(0, import_node_fs29.existsSync)(p)) return [];
25207
25434
  try {
25208
- return installedPluginPaths((0, import_node_fs28.readFileSync)(p, "utf8"));
25435
+ return installedPluginPaths((0, import_node_fs29.readFileSync)(p, "utf8"));
25209
25436
  } catch {
25210
25437
  return null;
25211
25438
  }
25212
25439
  }
25213
25440
  function pluginCacheFsDeps(home, dirBytes) {
25214
25441
  return {
25215
- exists: (p) => (0, import_node_fs28.existsSync)(p),
25216
- listVersionDirs: (root) => (0, import_node_fs28.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name),
25442
+ exists: (p) => (0, import_node_fs29.existsSync)(p),
25443
+ listVersionDirs: (root) => (0, import_node_fs29.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name),
25217
25444
  dirBytes,
25218
- listStagingDirs: (root) => (0, import_node_fs28.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => {
25445
+ listStagingDirs: (root) => (0, import_node_fs29.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => {
25219
25446
  try {
25220
- return { name: d.name, mtimeMs: newestMtimeMs((0, import_node_path25.join)(root, d.name), listDirEntries, (p) => (0, import_node_fs28.statSync)(p).mtimeMs) };
25447
+ return { name: d.name, mtimeMs: newestMtimeMs((0, import_node_path26.join)(root, d.name), listDirEntries, (p) => (0, import_node_fs29.statSync)(p).mtimeMs) };
25221
25448
  } catch {
25222
25449
  return { name: d.name, mtimeMs: Date.now() };
25223
25450
  }
@@ -25231,10 +25458,10 @@ function stagingApplyFsGuard(home) {
25231
25458
  return {
25232
25459
  referencedPaths: () => readInstalledPluginRefs(home),
25233
25460
  mtimeMs: (name) => {
25234
- const p = (0, import_node_path25.join)(stagingRoot, name);
25235
- if (!(0, import_node_fs28.existsSync)(p)) return null;
25461
+ const p = (0, import_node_path26.join)(stagingRoot, name);
25462
+ if (!(0, import_node_fs29.existsSync)(p)) return null;
25236
25463
  try {
25237
- return newestMtimeMs(p, listDirEntries, (q) => (0, import_node_fs28.statSync)(q).mtimeMs);
25464
+ return newestMtimeMs(p, listDirEntries, (q) => (0, import_node_fs29.statSync)(q).mtimeMs);
25238
25465
  } catch {
25239
25466
  return null;
25240
25467
  }
@@ -25250,7 +25477,7 @@ program2.command("plugin-prune").description(`prune stale cached MMI plugin vers
25250
25477
  { withBytes: true }
25251
25478
  );
25252
25479
  const anythingToDelete = plan.prune.length > 0 || plan.staging.length > 0;
25253
- const result = o.apply && anythingToDelete ? applyPluginCachePlan(plan, (p) => (0, import_node_fs28.rmSync)(p, { recursive: true, force: true }), stagingApplyFsGuard((0, import_node_os8.homedir)())) : void 0;
25480
+ const result = o.apply && anythingToDelete ? applyPluginCachePlan(plan, (p) => (0, import_node_fs29.rmSync)(p, { recursive: true, force: true }), stagingApplyFsGuard((0, import_node_os8.homedir)())) : void 0;
25254
25481
  const warnings = plan.prune.length > 0 ? [CONCURRENT_SESSION_WARNING] : [];
25255
25482
  if (o.json) console.log(JSON.stringify({ ...plan, warnings, applied: result ?? null }));
25256
25483
  else console.log(renderPluginCachePlan(plan, result));
@@ -25283,7 +25510,7 @@ program2.command("session-start").description("run the SessionStart verbs (whoam
25283
25510
  readBoard,
25284
25511
  // #1813: warm the slice cache out-of-band (detached) so the ~20s live read
25285
25512
  // never costs banner time and next session's glance renders instantly within budget.
25286
- scheduleRefresh: () => spawnDetachedSelf(["board", "slice-refresh", "--quiet"], { spawn: import_node_child_process12.spawn, execPath: process.execPath, scriptPath: process.argv[1] })
25513
+ scheduleRefresh: () => spawnDetachedSelf(["board", "slice-refresh", "--quiet"], { spawn: import_node_child_process13.spawn, execPath: process.execPath, scriptPath: process.argv[1] })
25287
25514
  }),
25288
25515
  // command-ladder hint (#2609): compact gh→mmi-cli cheat sheet so agents reach for mmi-cli first,
25289
25516
  // not after a denied gh call. <1KB, pure in-memory — no network, no fs, fail-soft.
@@ -25314,7 +25541,7 @@ program2.command("session-start").description("run the SessionStart verbs (whoam
25314
25541
  for (const line of scratchGcLines(process.cwd())) consoleIo.log(line);
25315
25542
  const worktreeBanner = worktreeAutoProvisionBanner(process.cwd());
25316
25543
  if (worktreeBanner) {
25317
- spawnDetachedSelf(["worktree", "setup", "--quiet"], { spawn: import_node_child_process12.spawn, execPath: process.execPath, scriptPath: process.argv[1] });
25544
+ spawnDetachedSelf(["worktree", "setup", "--quiet"], { spawn: import_node_child_process13.spawn, execPath: process.execPath, scriptPath: process.argv[1] });
25318
25545
  consoleIo.log(worktreeBanner);
25319
25546
  }
25320
25547
  appendHookActivity(process.cwd(), { event: "SessionStart", script: "session-start", outcome: "ran", action: "session-start hook completed" });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mutmutco/cli",
3
- "version": "3.41.0",
3
+ "version": "3.43.0",
4
4
  "description": "MMI Future CLI — the org dev toolbox (board, registry, keyless secrets, release train, bootstrap, doctor) and the cross-IDE engine the plugin's session-start hook drives.",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",