@biffo/cli 0.281.0 → 0.283.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.
package/dist/index.js CHANGED
@@ -7744,6 +7744,10 @@ var UserIngressSchema = z7.object({
7744
7744
  required_group: z7.string().min(1, NON_EMPTY_GROUP),
7745
7745
  app: z7.string().regex(APP_REF, "must be an ASGI app reference '<module>:<attr>', e.g. 'ideation.app:app'")
7746
7746
  }).strict();
7747
+ var AdminIngressSchema = z7.object({
7748
+ required_group: z7.string().min(1, NON_EMPTY_GROUP),
7749
+ app: z7.string().regex(APP_REF, "must be an ASGI app reference '<module>:<attr>', e.g. 'ideation.admin:app'")
7750
+ }).strict();
7747
7751
  var UserFrontendSchema = z7.object({
7748
7752
  dir: z7.string().regex(
7749
7753
  REL_DIR,
@@ -7756,6 +7760,13 @@ var ToolDeclarationSchema = z7.object({
7756
7760
  description: z7.string(),
7757
7761
  parameters: z7.record(z7.string(), z7.unknown()).default({})
7758
7762
  });
7763
+ var SeedDeclarationSchema = z7.object({
7764
+ dir: z7.string().regex(
7765
+ REL_DIR,
7766
+ "must be a plugin-relative path with no leading slash or traversal, e.g. db/seed"
7767
+ ),
7768
+ baseline_tables: z7.array(z7.string()).default([])
7769
+ }).strict();
7759
7770
  var ChatAgentDeclarationSchema = z7.object({
7760
7771
  key: z7.string().regex(/^[a-z][a-z0-9-]*$/, "must be a lowercase kebab-case slug"),
7761
7772
  agent_name: z7.string().optional(),
@@ -7781,9 +7792,10 @@ var PluginManifestSchema = z7.object({
7781
7792
  // schema is the registry's, and this consumer only needs to count them.
7782
7793
  event_subscriptions: z7.array(z7.object({ source: z7.string(), detail_type: z7.string() }).passthrough()).default([]),
7783
7794
  required_core_version: z7.string().default(">=0.0.0"),
7784
- // ADR-0018 user-facing surfaces. Optional: a plugin without them is an
7785
- // ordinary (data/event/CRUD) plugin.
7795
+ // ADR-0018/0021 user-facing and admin-facing surfaces. Optional: a plugin
7796
+ // without them is an ordinary (data/event/CRUD) plugin.
7786
7797
  user_ingress: UserIngressSchema.optional(),
7798
+ admin_ingress: AdminIngressSchema.optional(),
7787
7799
  user_frontend: UserFrontendSchema.optional(),
7788
7800
  // Tools the plugin's runtime exposes to an agentic worker (ADR-0014 §7,
7789
7801
  // #569). Default empty — an ordinary plugin declares none. Parsing this
@@ -7794,7 +7806,11 @@ var PluginManifestSchema = z7.object({
7794
7806
  tools: z7.array(ToolDeclarationSchema).default([]),
7795
7807
  // Chat agents the plugin registers with Core (ADR-0017). Default empty — an
7796
7808
  // ordinary plugin declares none.
7797
- chat_agents: z7.array(ChatAgentDeclarationSchema).default([])
7809
+ chat_agents: z7.array(ChatAgentDeclarationSchema).default([]),
7810
+ // The plugin's tenant-scoped baseline-row seed (ADR-0005, biffo-template#1554).
7811
+ // Optional — a plugin with no baseline data omits this entirely, and
7812
+ // `biffo plugin install`/`upgrade` vendor nothing for it.
7813
+ seed: SeedDeclarationSchema.optional()
7798
7814
  }).superRefine((manifest, ctx) => {
7799
7815
  const tableNames = new Set(manifest.tables.map((t) => t.name));
7800
7816
  for (const route of manifest.api_routes) {
@@ -7805,6 +7821,16 @@ var PluginManifestSchema = z7.object({
7805
7821
  });
7806
7822
  }
7807
7823
  }
7824
+ if (manifest.seed) {
7825
+ for (const table of manifest.seed.baseline_tables) {
7826
+ if (!tableNames.has(table)) {
7827
+ ctx.addIssue({
7828
+ code: z7.ZodIssueCode.custom,
7829
+ message: `seed.baseline_tables references table '${table}', which is not declared in this manifest's 'tables' (${[...tableNames].sort().join(", ") || "none"})`
7830
+ });
7831
+ }
7832
+ }
7833
+ }
7808
7834
  });
7809
7835
  function validateManifest(raw) {
7810
7836
  const result = PluginManifestSchema.safeParse(raw);
@@ -8319,6 +8345,14 @@ var RegistryPluginEntrySchema = z8.object({
8319
8345
  description: z8.string().optional(),
8320
8346
  author: z8.string().optional(),
8321
8347
  tags: z8.array(z8.string()).optional(),
8348
+ // Summary-form mirror of the manifest's `seed.baseline_tables` (see
8349
+ // ../../lib/plugin-manifest.ts's SeedDeclarationSchema and
8350
+ // _skeletons/registry/registry-schema.json's `seed`, biffo-template#1554).
8351
+ // The registry entry only ever needs to know WHICH tables a plugin promises
8352
+ // baseline rows for, never the seed `dir` itself — that only matters to the
8353
+ // install/upgrade vendoring step, which reads it from the plugin's own
8354
+ // biffo.plugin.json after cloning, not from this summary.
8355
+ baseline_tables: z8.array(z8.string()).optional(),
8322
8356
  required_core_version: z8.string().optional(),
8323
8357
  infra_modules: z8.array(z8.string()).optional(),
8324
8358
  api_routes: z8.array(z8.string()).optional(),
@@ -8445,8 +8479,8 @@ function printEntry(entry) {
8445
8479
  }
8446
8480
 
8447
8481
  // src/commands/plugin-install.ts
8448
- import { cpSync as cpSync4, existsSync as existsSync29, mkdirSync as mkdirSync10, readFileSync as readFileSync22, statSync as statSync6 } from "fs";
8449
- import { join as join31, relative as relative3, resolve as resolve12 } from "path";
8482
+ import { cpSync as cpSync5, existsSync as existsSync30, mkdirSync as mkdirSync11, readFileSync as readFileSync22, statSync as statSync6 } from "fs";
8483
+ import { join as join32, relative as relative3, resolve as resolve12 } from "path";
8450
8484
  import chalk15 from "chalk";
8451
8485
  import { Command as Command15 } from "commander";
8452
8486
 
@@ -8572,9 +8606,48 @@ async function tryGit(cwd, args) {
8572
8606
  }
8573
8607
  }
8574
8608
 
8609
+ // src/lib/plugin-seed-vendor.ts
8610
+ import { cpSync as cpSync3, existsSync as existsSync28, mkdirSync as mkdirSync9, readdirSync as readdirSync12, rmSync as rmSync8 } from "fs";
8611
+ import { join as join29 } from "path";
8612
+ var VENDOR_PREFIX = "_plugin-";
8613
+ function pluginSeedImportDir(pluginName) {
8614
+ return `db/imports/${VENDOR_PREFIX}${pluginName}`;
8615
+ }
8616
+ function vendorPluginSeed(pluginSourceDir, manifest, cwd) {
8617
+ if (!manifest.seed) {
8618
+ return { vendored: false };
8619
+ }
8620
+ const sourceSeedDir = join29(pluginSourceDir, manifest.seed.dir);
8621
+ if (!existsSync28(sourceSeedDir)) {
8622
+ throw new Error(
8623
+ `${manifest.name}'s manifest declares seed.dir '${manifest.seed.dir}', but ${sourceSeedDir} does not exist in the plugin's source.`
8624
+ );
8625
+ }
8626
+ const sqlFiles = readdirSync12(sourceSeedDir).filter((f) => f.endsWith(".sql"));
8627
+ if (sqlFiles.length === 0) {
8628
+ throw new Error(
8629
+ `${manifest.name}'s manifest declares seed.dir '${manifest.seed.dir}', but ${sourceSeedDir} contains no *.sql files.`
8630
+ );
8631
+ }
8632
+ const relTargetDir = pluginSeedImportDir(manifest.name);
8633
+ const targetDir = join29(cwd, relTargetDir);
8634
+ rmSync8(targetDir, { recursive: true, force: true });
8635
+ mkdirSync9(targetDir, { recursive: true });
8636
+ for (const file of sqlFiles) {
8637
+ cpSync3(join29(sourceSeedDir, file), join29(targetDir, file));
8638
+ }
8639
+ log.success(
8640
+ `Vendored ${sqlFiles.length} seed file(s) to ${relTargetDir}/ (baseline_tables: ${manifest.seed.baseline_tables.join(", ") || "none declared"})`
8641
+ );
8642
+ log.info(
8643
+ `${relTargetDir}/*.sql are checksum-tracked once applied (ADR-0005 section 4) \u2014 a later version must ship a new, additively-numbered file for a changed seed, never edit one already released, or the next deploy fails loudly.`
8644
+ );
8645
+ return { vendored: true, stagedPath: relTargetDir };
8646
+ }
8647
+
8575
8648
  // src/lib/plugin-source-copy.ts
8576
- import { copyFileSync as copyFileSync2, cpSync as cpSync3, mkdirSync as mkdirSync9 } from "fs";
8577
- import { basename, dirname as dirname9, join as join29 } from "path";
8649
+ import { copyFileSync as copyFileSync2, cpSync as cpSync4, mkdirSync as mkdirSync10 } from "fs";
8650
+ import { basename, dirname as dirname9, join as join30 } from "path";
8578
8651
  import { execa as execa6 } from "execa";
8579
8652
  var LOCAL_COPY_EXCLUDES = /* @__PURE__ */ new Set([
8580
8653
  ".git",
@@ -8591,17 +8664,17 @@ async function copyPluginSource(sourceDir, targetDir) {
8591
8664
  if (await isGitWorkingTree2(sourceDir)) {
8592
8665
  const files = await listGitFiles(sourceDir);
8593
8666
  for (const relPath of files) {
8594
- const destPath = join29(targetDir, relPath);
8595
- mkdirSync9(dirname9(destPath), { recursive: true });
8596
- copyFileSync2(join29(sourceDir, relPath), destPath);
8667
+ const destPath = join30(targetDir, relPath);
8668
+ mkdirSync10(dirname9(destPath), { recursive: true });
8669
+ copyFileSync2(join30(sourceDir, relPath), destPath);
8597
8670
  }
8598
8671
  return { usedGitIgnoreRules: true };
8599
8672
  }
8600
8673
  log.warn(
8601
8674
  `${sourceDir} is not a git working tree \u2014 cannot honour .gitignore. Falling back to a fixed exclude list (.git, .venv, node_modules, caches); anything else it does not know about (e.g. an unfamiliar cache directory) will be copied.`
8602
8675
  );
8603
- mkdirSync9(targetDir, { recursive: true });
8604
- cpSync3(sourceDir, targetDir, {
8676
+ mkdirSync10(targetDir, { recursive: true });
8677
+ cpSync4(sourceDir, targetDir, {
8605
8678
  recursive: true,
8606
8679
  filter: (src) => !LOCAL_COPY_EXCLUDES.has(basename(src))
8607
8680
  });
@@ -8625,8 +8698,8 @@ async function listGitFiles(dir) {
8625
8698
  }
8626
8699
 
8627
8700
  // src/lib/plugin-workspace-sources.ts
8628
- import { existsSync as existsSync28, readdirSync as readdirSync12, readFileSync as readFileSync21, writeFileSync as writeFileSync11 } from "fs";
8629
- import { join as join30 } from "path";
8701
+ import { existsSync as existsSync29, readdirSync as readdirSync13, readFileSync as readFileSync21, writeFileSync as writeFileSync11 } from "fs";
8702
+ import { join as join31 } from "path";
8630
8703
  function readTomlStringArray(text, key) {
8631
8704
  const open = new RegExp(`^${key}\\s*=\\s*\\[`, "m").exec(text);
8632
8705
  if (!open) return [];
@@ -8670,8 +8743,8 @@ function readDependencyNames(text) {
8670
8743
  return readTomlStringArray(text, "dependencies").map((dep) => /^\s*([A-Za-z0-9._-]+)/.exec(dep)?.[1] ?? "").filter(Boolean);
8671
8744
  }
8672
8745
  function workspaceMemberNames(instanceRoot) {
8673
- const rootPyproject = join30(instanceRoot, "pyproject.toml");
8674
- if (!existsSync28(rootPyproject)) return /* @__PURE__ */ new Set();
8746
+ const rootPyproject = join31(instanceRoot, "pyproject.toml");
8747
+ if (!existsSync29(rootPyproject)) return /* @__PURE__ */ new Set();
8675
8748
  const text = readFileSync21(rootPyproject, "utf8");
8676
8749
  const members = readTomlStringArray(text, "members");
8677
8750
  const excluded = new Set(readTomlStringArray(text, "exclude"));
@@ -8681,7 +8754,7 @@ function workspaceMemberNames(instanceRoot) {
8681
8754
  const base = member.slice(0, -2);
8682
8755
  let entries;
8683
8756
  try {
8684
- entries = readdirSync12(join30(instanceRoot, base), { withFileTypes: true });
8757
+ entries = readdirSync13(join31(instanceRoot, base), { withFileTypes: true });
8685
8758
  } catch {
8686
8759
  continue;
8687
8760
  }
@@ -8695,8 +8768,8 @@ function workspaceMemberNames(instanceRoot) {
8695
8768
  }
8696
8769
  const names = /* @__PURE__ */ new Set();
8697
8770
  for (const dir of dirs) {
8698
- const pp = join30(instanceRoot, dir, "pyproject.toml");
8699
- if (!existsSync28(pp)) continue;
8771
+ const pp = join31(instanceRoot, dir, "pyproject.toml");
8772
+ if (!existsSync29(pp)) continue;
8700
8773
  const name = readProjectName(readFileSync21(pp, "utf8"));
8701
8774
  if (name) names.add(name);
8702
8775
  }
@@ -8708,7 +8781,7 @@ function existingWorkspaceSources(text) {
8708
8781
  );
8709
8782
  }
8710
8783
  function ensureWorkspaceSources(pluginPyprojectPath, memberNames) {
8711
- if (!existsSync28(pluginPyprojectPath) || memberNames.size === 0) return [];
8784
+ if (!existsSync29(pluginPyprojectPath) || memberNames.size === 0) return [];
8712
8785
  const text = readFileSync21(pluginPyprojectPath, "utf8");
8713
8786
  const already = existingWorkspaceSources(text);
8714
8787
  const toAdd = readDependencyNames(text).filter((n) => memberNames.has(n) && !already.has(n));
@@ -8733,8 +8806,8 @@ ${lines.join("\n")}
8733
8806
  return toAdd;
8734
8807
  }
8735
8808
  function applyWorkspaceSources(targetDir, cwd, relTargetDir) {
8736
- const pluginPyproject = join30(targetDir, "pyproject.toml");
8737
- if (!existsSync28(pluginPyproject)) return;
8809
+ const pluginPyproject = join31(targetDir, "pyproject.toml");
8810
+ if (!existsSync29(pluginPyproject)) return;
8738
8811
  const sourced = ensureWorkspaceSources(pluginPyproject, workspaceMemberNames(cwd));
8739
8812
  if (sourced.length > 0) {
8740
8813
  log.info(
@@ -8774,14 +8847,14 @@ var pluginInstallCommand = new Command15("install").description(
8774
8847
  }
8775
8848
  );
8776
8849
  function resolveLocalPlugin(localPath) {
8777
- if (!existsSync29(localPath)) {
8850
+ if (!existsSync30(localPath)) {
8778
8851
  throw new Error(`--local path does not exist: ${localPath}`);
8779
8852
  }
8780
8853
  if (!statSync6(localPath).isDirectory()) {
8781
8854
  throw new Error(`--local path is not a directory: ${localPath}`);
8782
8855
  }
8783
- const manifestPath = join31(localPath, "biffo.plugin.json");
8784
- if (!existsSync29(manifestPath)) {
8856
+ const manifestPath = join32(localPath, "biffo.plugin.json");
8857
+ if (!existsSync30(manifestPath)) {
8785
8858
  throw new Error(
8786
8859
  `${localPath} does not contain a biffo.plugin.json manifest at its root \u2014 is it a plugin directory? (Scaffold one with \`biffo plugin create <name>\`.)`
8787
8860
  );
@@ -8807,8 +8880,8 @@ function parsePluginTarget(target) {
8807
8880
  async function cloneAndValidatePlugin(entry, git) {
8808
8881
  const tmpDir = await git.cloneToTemp(entry.repo, `biffo-plugin-${entry.name}`);
8809
8882
  try {
8810
- const manifestPath = join31(tmpDir, "biffo.plugin.json");
8811
- if (!existsSync29(manifestPath)) {
8883
+ const manifestPath = join32(tmpDir, "biffo.plugin.json");
8884
+ if (!existsSync30(manifestPath)) {
8812
8885
  throw new Error(
8813
8886
  `Plugin repo ${entry.repo} does not contain a biffo.plugin.json manifest at its root.`
8814
8887
  );
@@ -8836,8 +8909,8 @@ async function runPluginInstall(target, options, deps) {
8836
8909
  `Nothing to install. Pass a registry target (e.g. \`biffo plugin install acme-crm@1.0\`) or a local plugin directory (\`biffo plugin install --local services/acme-crm\`).`
8837
8910
  );
8838
8911
  }
8839
- const servicesDir = join31(options.cwd, "services");
8840
- if (!existsSync29(servicesDir)) {
8912
+ const servicesDir = join32(options.cwd, "services");
8913
+ if (!existsSync30(servicesDir)) {
8841
8914
  throw new Error(
8842
8915
  `${servicesDir} does not exist \u2014 is ${options.cwd} the root of a Biffo project checkout?`
8843
8916
  );
@@ -8855,10 +8928,10 @@ async function runPluginInstall(target, options, deps) {
8855
8928
  }
8856
8929
  const pluginName = entry ? entry.name : source.name;
8857
8930
  const relTargetDir = pluginDir(pluginName, "third-party");
8858
- const targetDir = join31(options.cwd, relTargetDir);
8859
- const modulesDir = join31(options.cwd, "modules", "plugins", pluginName);
8931
+ const targetDir = join32(options.cwd, relTargetDir);
8932
+ const modulesDir = join32(options.cwd, "modules", "plugins", pluginName);
8860
8933
  const inTreeSource = options.local !== void 0 && resolve12(options.local) === resolve12(targetDir);
8861
- if (existsSync29(targetDir) && !inTreeSource) {
8934
+ if (existsSync30(targetDir) && !inTreeSource) {
8862
8935
  throw new Error(
8863
8936
  `Plugin '${pluginName}' is already installed at ${relTargetDir}/. Remove it first, or wait for a future 'biffo plugin upgrade' command.`
8864
8937
  );
@@ -8893,7 +8966,7 @@ async function runPluginInstall(target, options, deps) {
8893
8966
  if (inTreeSource) {
8894
8967
  log.info(`${relTargetDir}/ is already in this checkout \u2014 installing in place.`);
8895
8968
  } else {
8896
- mkdirSync10(targetDir, { recursive: true });
8969
+ mkdirSync11(targetDir, { recursive: true });
8897
8970
  await copyPluginSource(source.sourceDir, targetDir);
8898
8971
  log.success(`Installed plugin source at ${relTargetDir}/`);
8899
8972
  }
@@ -8902,10 +8975,10 @@ async function runPluginInstall(target, options, deps) {
8902
8975
  writePluginProvenance(targetDir, reconcileProvenance(previousProvenance, nextProvenance));
8903
8976
  applyWorkspaceSources(targetDir, options.cwd, relTargetDir);
8904
8977
  const stagePaths = [relTargetDir];
8905
- const tfSourceDir = join31(targetDir, "terraform");
8906
- if (existsSync29(tfSourceDir)) {
8907
- mkdirSync10(modulesDir, { recursive: true });
8908
- cpSync4(tfSourceDir, modulesDir, { recursive: true });
8978
+ const tfSourceDir = join32(targetDir, "terraform");
8979
+ if (existsSync30(tfSourceDir)) {
8980
+ mkdirSync11(modulesDir, { recursive: true });
8981
+ cpSync5(tfSourceDir, modulesDir, { recursive: true });
8909
8982
  stagePaths.push(`modules/plugins/${pluginName}`);
8910
8983
  log.success(`Copied Terraform module to modules/plugins/${pluginName}/`);
8911
8984
  const wiring = syncPluginTerraform(options.cwd);
@@ -8944,6 +9017,10 @@ async function runPluginInstall(target, options, deps) {
8944
9017
  } else {
8945
9018
  log.info(`${pluginName} declares no tables \u2014 nothing to migrate.`);
8946
9019
  }
9020
+ const seedResult = vendorPluginSeed(targetDir, manifest, options.cwd);
9021
+ if (seedResult.vendored) {
9022
+ stagePaths.push(seedResult.stagedPath);
9023
+ }
8947
9024
  const commitMessage = `feat(plugins): install ${pluginName}@${source.version}`;
8948
9025
  await deps.git.add(options.cwd, stagePaths);
8949
9026
  await deps.git.commit(options.cwd, commitMessage);
@@ -8992,13 +9069,18 @@ function printDryRun4(entry, source, relTargetDir, inTreeSource) {
8992
9069
  ` Would generate a migration for ${source.manifest.tables.length} table(s) into services/api/migrations/versions/`
8993
9070
  );
8994
9071
  }
9072
+ if (source && source.manifest.seed) {
9073
+ console.log(
9074
+ ` Would vendor seed DDL into: ${pluginSeedImportDir(name)}/ (baseline_tables: ${source.manifest.seed.baseline_tables.join(", ") || "none declared"})`
9075
+ );
9076
+ }
8995
9077
  console.log(` Would commit: feat(plugins): install ${name}@${version}
8996
9078
  `);
8997
9079
  }
8998
9080
 
8999
9081
  // src/commands/plugin-list.ts
9000
- import { existsSync as existsSync30, readFileSync as readFileSync23 } from "fs";
9001
- import { join as join32, resolve as resolve13 } from "path";
9082
+ import { existsSync as existsSync31, readFileSync as readFileSync23 } from "fs";
9083
+ import { join as join33, resolve as resolve13 } from "path";
9002
9084
  import chalk16 from "chalk";
9003
9085
  import { Command as Command16 } from "commander";
9004
9086
  var pluginListCommand = new Command16("list").description("List plugins installed in this project checkout").option("--cwd <path>", "Project root to scan (defaults to the current directory)").action(async (options) => {
@@ -9011,8 +9093,8 @@ var pluginListCommand = new Command16("list").description("List plugins installe
9011
9093
  }
9012
9094
  });
9013
9095
  async function runPluginList(options) {
9014
- const servicesDir = join32(options.cwd, "services");
9015
- if (!existsSync30(servicesDir)) {
9096
+ const servicesDir = join33(options.cwd, "services");
9097
+ if (!existsSync31(servicesDir)) {
9016
9098
  throw new Error(
9017
9099
  `${servicesDir} does not exist \u2014 is ${options.cwd} the root of a Biffo project checkout?`
9018
9100
  );
@@ -9061,14 +9143,14 @@ import { resolve as resolve14 } from "path";
9061
9143
  import { Command as Command17 } from "commander";
9062
9144
 
9063
9145
  // src/lib/plugin-staleness.ts
9064
- import { existsSync as existsSync31, readFileSync as readFileSync24, readdirSync as readdirSync13, statSync as statSync7 } from "fs";
9065
- import { join as join33, relative as relative4 } from "path";
9146
+ import { existsSync as existsSync32, readFileSync as readFileSync24, readdirSync as readdirSync14, statSync as statSync7 } from "fs";
9147
+ import { join as join34, relative as relative4 } from "path";
9066
9148
  function discoverVendoredPlugins(servicesDir) {
9067
- if (!existsSync31(servicesDir)) return [];
9068
- return readdirSync13(servicesDir, { withFileTypes: true }).filter((e) => e.isDirectory() && !e.name.startsWith("_") && e.name !== "api").map((e) => e.name).filter((name) => existsSync31(join33(servicesDir, name, "biffo.plugin.json"))).sort();
9149
+ if (!existsSync32(servicesDir)) return [];
9150
+ return readdirSync14(servicesDir, { withFileTypes: true }).filter((e) => e.isDirectory() && !e.name.startsWith("_") && e.name !== "api").map((e) => e.name).filter((name) => existsSync32(join34(servicesDir, name, "biffo.plugin.json"))).sort();
9069
9151
  }
9070
9152
  async function checkPluginStaleness(cwd, deps) {
9071
- const servicesDir = join33(cwd, "services");
9153
+ const servicesDir = join34(cwd, "services");
9072
9154
  const names = discoverVendoredPlugins(servicesDir);
9073
9155
  let registryRepoByName = null;
9074
9156
  const resolveRegistryRepo = async (name) => {
@@ -9084,7 +9166,7 @@ async function checkPluginStaleness(cwd, deps) {
9084
9166
  };
9085
9167
  const results = [];
9086
9168
  for (const name of names) {
9087
- results.push(await checkOnePlugin(join33(servicesDir, name), name, resolveRegistryRepo, deps.git));
9169
+ results.push(await checkOnePlugin(join34(servicesDir, name), name, resolveRegistryRepo, deps.git));
9088
9170
  }
9089
9171
  return results;
9090
9172
  }
@@ -9110,7 +9192,7 @@ async function checkOnePlugin(pluginDir2, name, resolveRegistryRepo, git) {
9110
9192
  if (record?.sha && isFetchableUrl(record.origin)) {
9111
9193
  return checkViaProvenance(name, record, record.origin, git);
9112
9194
  }
9113
- const localOrigin = record && !isFetchableUrl(record.origin) && existsSync31(record.origin) ? record.origin : null;
9195
+ const localOrigin = record && !isFetchableUrl(record.origin) && existsSync32(record.origin) ? record.origin : null;
9114
9196
  if (localOrigin) {
9115
9197
  return checkViaContentDiff(name, pluginDir2, localOrigin, { isLocalDir: true }, git);
9116
9198
  }
@@ -9244,8 +9326,8 @@ async function countDifferingFiles(sourceDir, pluginDir2) {
9244
9326
  differing++;
9245
9327
  continue;
9246
9328
  }
9247
- const a = readFileSync24(join33(sourceDir, relPath));
9248
- const b = readFileSync24(join33(pluginDir2, relPath));
9329
+ const a = readFileSync24(join34(sourceDir, relPath));
9330
+ const b = readFileSync24(join34(pluginDir2, relPath));
9249
9331
  if (!a.equals(b)) differing++;
9250
9332
  }
9251
9333
  return differing;
@@ -9260,11 +9342,11 @@ function vendorFileList(dir) {
9260
9342
  return new Set(walkExcluding(dir, dir, LOCAL_COPY_EXCLUDES));
9261
9343
  }
9262
9344
  function walkExcluding(root, dir, excludes) {
9263
- if (!existsSync31(dir)) return [];
9345
+ if (!existsSync32(dir)) return [];
9264
9346
  const out = [];
9265
- for (const entry of readdirSync13(dir)) {
9347
+ for (const entry of readdirSync14(dir)) {
9266
9348
  if (excludes.has(entry) || entry === ".git") continue;
9267
- const full = join33(dir, entry);
9349
+ const full = join34(dir, entry);
9268
9350
  const stat = statSync7(full);
9269
9351
  if (stat.isDirectory()) {
9270
9352
  out.push(...walkExcluding(root, full, excludes));
@@ -9316,8 +9398,8 @@ var pluginStalenessCommand = new Command17("staleness").description(
9316
9398
  });
9317
9399
 
9318
9400
  // src/commands/plugin-sync-migrations.ts
9319
- import { existsSync as existsSync32 } from "fs";
9320
- import { join as join34, relative as relative5, resolve as resolve15 } from "path";
9401
+ import { existsSync as existsSync33 } from "fs";
9402
+ import { join as join35, relative as relative5, resolve as resolve15 } from "path";
9321
9403
  import chalk17 from "chalk";
9322
9404
  import { Command as Command18 } from "commander";
9323
9405
  var pluginSyncMigrationsCommand = new Command18("sync-migrations").description(
@@ -9338,11 +9420,11 @@ var pluginSyncMigrationsCommand = new Command18("sync-migrations").description(
9338
9420
  }
9339
9421
  );
9340
9422
  async function runPluginSyncMigrations(name, options, deps) {
9341
- const servicesDir = join34(options.cwd, "services");
9342
- if (!existsSync32(servicesDir)) {
9423
+ const servicesDir = join35(options.cwd, "services");
9424
+ if (!existsSync33(servicesDir)) {
9343
9425
  throw new Error(`${servicesDir} does not exist \u2014 is ${options.cwd} a Biffo project checkout?`);
9344
9426
  }
9345
- if (name && !existsSync32(join34(servicesDir, name, "biffo.plugin.json"))) {
9427
+ if (name && !existsSync33(join35(servicesDir, name, "biffo.plugin.json"))) {
9346
9428
  throw new Error(`Plugin '${name}' is not installed at services/${name}/.`);
9347
9429
  }
9348
9430
  if (options.dryRun) {
@@ -9378,8 +9460,8 @@ async function runPluginSyncMigrations(name, options, deps) {
9378
9460
  }
9379
9461
 
9380
9462
  // src/commands/plugin-uninstall.ts
9381
- import { existsSync as existsSync33, readFileSync as readFileSync25, rmSync as rmSync8 } from "fs";
9382
- import { join as join35, resolve as resolve16 } from "path";
9463
+ import { existsSync as existsSync34, readFileSync as readFileSync25, rmSync as rmSync9 } from "fs";
9464
+ import { join as join36, resolve as resolve16 } from "path";
9383
9465
  import chalk18 from "chalk";
9384
9466
  import { Command as Command19 } from "commander";
9385
9467
  import inquirer6 from "inquirer";
@@ -9411,16 +9493,16 @@ async function runPluginUninstall(name, options, deps) {
9411
9493
  if (!NAME_PATTERN2.test(name)) {
9412
9494
  throw new Error(`Invalid plugin name '${name}'. Expected a lowercase kebab-case slug.`);
9413
9495
  }
9414
- const servicesDir = join35(options.cwd, "services");
9415
- if (!existsSync33(servicesDir)) {
9496
+ const servicesDir = join36(options.cwd, "services");
9497
+ if (!existsSync34(servicesDir)) {
9416
9498
  throw new Error(
9417
9499
  `${servicesDir} does not exist \u2014 is ${options.cwd} the root of a Biffo project checkout?`
9418
9500
  );
9419
9501
  }
9420
- const targetDir = join35(servicesDir, name);
9421
- if (!existsSync33(targetDir)) {
9422
- const firstParty = join35(servicesDir, FIRST_PARTY_PLUGINS_DIR, name);
9423
- if (existsSync33(firstParty)) {
9502
+ const targetDir = join36(servicesDir, name);
9503
+ if (!existsSync34(targetDir)) {
9504
+ const firstParty = join36(servicesDir, FIRST_PARTY_PLUGINS_DIR, name);
9505
+ if (existsSync34(firstParty)) {
9424
9506
  throw new Error(
9425
9507
  `Plugin '${name}' is a first-party plugin at ${pluginDir(name, "first-party")}/, which is template-owned \u2014 \`biffo core upgrade\` would restore it on the next upgrade. Disable it instead by removing '${name}' from \`enabled_plugins\` in infra/environments/<env>/main.tf and re-applying.`
9426
9508
  );
@@ -9428,9 +9510,9 @@ async function runPluginUninstall(name, options, deps) {
9428
9510
  throw new Error(`Plugin '${name}' is not installed at services/${name}/.`);
9429
9511
  }
9430
9512
  const version = readInstalledVersion(targetDir);
9431
- const modulesDir = join35(options.cwd, "modules", "plugins", name);
9513
+ const modulesDir = join36(options.cwd, "modules", "plugins", name);
9432
9514
  const stagePaths = [`services/${name}`];
9433
- if (existsSync33(modulesDir)) {
9515
+ if (existsSync34(modulesDir)) {
9434
9516
  stagePaths.push(`modules/plugins/${name}`);
9435
9517
  }
9436
9518
  if (options.dryRun) {
@@ -9450,10 +9532,10 @@ async function runPluginUninstall(name, options, deps) {
9450
9532
  `${options.cwd} is not a git repository \u2014 biffo plugin uninstall must be run from a Biffo project checkout.`
9451
9533
  );
9452
9534
  }
9453
- rmSync8(targetDir, { recursive: true, force: true });
9535
+ rmSync9(targetDir, { recursive: true, force: true });
9454
9536
  log.success(`Removed services/${name}/`);
9455
- if (existsSync33(modulesDir)) {
9456
- rmSync8(modulesDir, { recursive: true, force: true });
9537
+ if (existsSync34(modulesDir)) {
9538
+ rmSync9(modulesDir, { recursive: true, force: true });
9457
9539
  log.success(`Removed modules/plugins/${name}/`);
9458
9540
  const wiring = syncPluginTerraform(options.cwd);
9459
9541
  stagePaths.push(...wiring.changedPaths);
@@ -9487,10 +9569,15 @@ async function runPluginUninstall(name, options, deps) {
9487
9569
  "Any tables this plugin created remain in the database, and its migration file at services/api/migrations/versions/ is NOT removed (it is a permanent historical record \u2014 see notes). Dropping tables, if desired, requires a manual Alembic migration written against the Core API."
9488
9570
  );
9489
9571
  }
9572
+ if (existsSync34(join36(options.cwd, pluginSeedImportDir(name)))) {
9573
+ log.warn(
9574
+ `${pluginSeedImportDir(name)}/ (this plugin's vendored baseline-row seed, biffo-template#1554) was NOT removed either, for the same reason \u2014 see notes. Delete it by hand if you are certain the rows it applied should go too, but note nothing drops rows already applied to the database; that still needs a manual migration.`
9575
+ );
9576
+ }
9490
9577
  }
9491
9578
  function readInstalledVersion(targetDir) {
9492
- const manifestPath = join35(targetDir, "biffo.plugin.json");
9493
- if (!existsSync33(manifestPath)) return void 0;
9579
+ const manifestPath = join36(targetDir, "biffo.plugin.json");
9580
+ if (!existsSync34(manifestPath)) return void 0;
9494
9581
  try {
9495
9582
  return validateManifest(JSON.parse(readFileSync25(manifestPath, "utf8"))).version;
9496
9583
  } catch {
@@ -9525,8 +9612,8 @@ function printDryRun5(name, version, stagePaths, keepData) {
9525
9612
  }
9526
9613
 
9527
9614
  // src/commands/plugin-upgrade.ts
9528
- import { cpSync as cpSync5, existsSync as existsSync34, mkdirSync as mkdirSync11, readFileSync as readFileSync26, rmSync as rmSync9 } from "fs";
9529
- import { join as join36, relative as relative6, resolve as resolve17 } from "path";
9615
+ import { cpSync as cpSync6, existsSync as existsSync35, mkdirSync as mkdirSync12, readFileSync as readFileSync26, rmSync as rmSync10 } from "fs";
9616
+ import { join as join37, relative as relative6, resolve as resolve17 } from "path";
9530
9617
  import chalk19 from "chalk";
9531
9618
  import { Command as Command20 } from "commander";
9532
9619
  import inquirer7 from "inquirer";
@@ -9573,8 +9660,8 @@ async function runPluginUpgrade(target, options, deps) {
9573
9660
  `Nothing to upgrade. Pass a registry target (e.g. \`biffo plugin upgrade acme-crm@1.1\`) or a local checkout to refresh from (\`biffo plugin upgrade --local ../acme-crm\`).`
9574
9661
  );
9575
9662
  }
9576
- const servicesDir = join36(options.cwd, "services");
9577
- if (!existsSync34(servicesDir)) {
9663
+ const servicesDir = join37(options.cwd, "services");
9664
+ if (!existsSync35(servicesDir)) {
9578
9665
  throw new Error(
9579
9666
  `${servicesDir} does not exist \u2014 is ${options.cwd} the root of a Biffo project checkout?`
9580
9667
  );
@@ -9583,8 +9670,8 @@ async function runPluginUpgrade(target, options, deps) {
9583
9670
  return runLocalPluginRefresh(options.local, options, deps);
9584
9671
  }
9585
9672
  const { name, minor } = parsePluginTarget(target);
9586
- const targetDir = join36(servicesDir, name);
9587
- if (!existsSync34(targetDir)) {
9673
+ const targetDir = join37(servicesDir, name);
9674
+ if (!existsSync35(targetDir)) {
9588
9675
  throw new Error(
9589
9676
  `Plugin '${name}' is not installed at services/${name}/. Use 'biffo plugin install ${name}@${minor}' instead.`
9590
9677
  );
@@ -9598,7 +9685,7 @@ async function runPluginUpgrade(target, options, deps) {
9598
9685
  `Plugin declares required_core_version '${entry.required_core_version}'. The CLI cannot verify this against your deployment \u2014 the Core API exposes no version endpoint and services/api/pyproject.toml's version is a static placeholder, not a real release marker. Confirm compatibility yourself before deploying.`
9599
9686
  );
9600
9687
  }
9601
- const modulesDir = join36(options.cwd, "modules", "plugins", entry.name);
9688
+ const modulesDir = join37(options.cwd, "modules", "plugins", entry.name);
9602
9689
  if (options.dryRun) {
9603
9690
  printDryRun6(entry, currentVersion);
9604
9691
  return;
@@ -9627,9 +9714,9 @@ async function runPluginUpgrade(target, options, deps) {
9627
9714
  `Manifest valid \u2014 ${manifest.tables.length} table(s), ${manifest.api_routes.length} route(s)`
9628
9715
  );
9629
9716
  const previousProvenance = readProvenance(targetDir);
9630
- rmSync9(targetDir, { recursive: true, force: true });
9631
- mkdirSync11(targetDir, { recursive: true });
9632
- cpSync5(tmpDir, targetDir, { recursive: true });
9717
+ rmSync10(targetDir, { recursive: true, force: true });
9718
+ mkdirSync12(targetDir, { recursive: true });
9719
+ cpSync6(tmpDir, targetDir, { recursive: true });
9633
9720
  log.success(`Upgraded plugin source at services/${entry.name}/`);
9634
9721
  const nextProvenance = resolveRegistryProvenance(
9635
9722
  entry.repo,
@@ -9638,13 +9725,13 @@ async function runPluginUpgrade(target, options, deps) {
9638
9725
  writePluginProvenance(targetDir, reconcileProvenance(previousProvenance, nextProvenance));
9639
9726
  applyWorkspaceSources(targetDir, options.cwd, `services/${entry.name}`);
9640
9727
  const stagePaths = [`services/${entry.name}`];
9641
- if (existsSync34(modulesDir)) {
9642
- rmSync9(modulesDir, { recursive: true, force: true });
9728
+ if (existsSync35(modulesDir)) {
9729
+ rmSync10(modulesDir, { recursive: true, force: true });
9643
9730
  }
9644
- const tfSourceDir = join36(targetDir, "terraform");
9645
- if (existsSync34(tfSourceDir)) {
9646
- mkdirSync11(modulesDir, { recursive: true });
9647
- cpSync5(tfSourceDir, modulesDir, { recursive: true });
9731
+ const tfSourceDir = join37(targetDir, "terraform");
9732
+ if (existsSync35(tfSourceDir)) {
9733
+ mkdirSync12(modulesDir, { recursive: true });
9734
+ cpSync6(tfSourceDir, modulesDir, { recursive: true });
9648
9735
  stagePaths.push(`modules/plugins/${entry.name}`);
9649
9736
  log.success(`Copied Terraform module to modules/plugins/${entry.name}/`);
9650
9737
  }
@@ -9664,6 +9751,10 @@ async function runPluginUpgrade(target, options, deps) {
9664
9751
  );
9665
9752
  }
9666
9753
  }
9754
+ const seedResult = vendorPluginSeed(targetDir, manifest, options.cwd);
9755
+ if (seedResult.vendored) {
9756
+ stagePaths.push(seedResult.stagedPath);
9757
+ }
9667
9758
  const label = currentVersion ? `${entry.name} ${currentVersion} -> ${entry.version}` : `${entry.name} to ${entry.version}`;
9668
9759
  const commitMessage = `feat(plugins): upgrade ${label}`;
9669
9760
  await deps.git.add(options.cwd, stagePaths);
@@ -9682,16 +9773,16 @@ async function runPluginUpgrade(target, options, deps) {
9682
9773
  async function runLocalPluginRefresh(localPath, options, deps) {
9683
9774
  const source = resolveLocalPlugin(localPath);
9684
9775
  log.success(`Resolved ${source.name}@${source.version} from ${source.origin}`);
9685
- const servicesDir = join36(options.cwd, "services");
9686
- const targetDir = join36(servicesDir, source.name);
9687
- if (!existsSync34(targetDir)) {
9776
+ const servicesDir = join37(options.cwd, "services");
9777
+ const targetDir = join37(servicesDir, source.name);
9778
+ if (!existsSync35(targetDir)) {
9688
9779
  throw new Error(
9689
9780
  `Plugin '${source.name}' is not installed at services/${source.name}/. Use 'biffo plugin install --local ${localPath}' instead.`
9690
9781
  );
9691
9782
  }
9692
9783
  const inTreeSource = resolve17(source.sourceDir) === resolve17(targetDir);
9693
9784
  const currentVersion = readInstalledVersion2(targetDir);
9694
- const modulesDir = join36(options.cwd, "modules", "plugins", source.name);
9785
+ const modulesDir = join37(options.cwd, "modules", "plugins", source.name);
9695
9786
  if (options.dryRun) {
9696
9787
  printLocalDryRun(source, currentVersion, inTreeSource);
9697
9788
  return;
@@ -9720,8 +9811,8 @@ async function runLocalPluginRefresh(localPath, options, deps) {
9720
9811
  `services/${source.name}/ is already the local checkout \u2014 nothing to copy; re-syncing its Terraform module and checking for a migration.`
9721
9812
  );
9722
9813
  } else {
9723
- rmSync9(targetDir, { recursive: true, force: true });
9724
- mkdirSync11(targetDir, { recursive: true });
9814
+ rmSync10(targetDir, { recursive: true, force: true });
9815
+ mkdirSync12(targetDir, { recursive: true });
9725
9816
  await copyPluginSource(source.sourceDir, targetDir);
9726
9817
  log.success(`Refreshed plugin source at services/${source.name}/ from ${source.origin}`);
9727
9818
  }
@@ -9729,13 +9820,13 @@ async function runLocalPluginRefresh(localPath, options, deps) {
9729
9820
  writePluginProvenance(targetDir, reconcileProvenance(previousProvenance, nextProvenance));
9730
9821
  applyWorkspaceSources(targetDir, options.cwd, `services/${source.name}`);
9731
9822
  const stagePaths = [`services/${source.name}`];
9732
- if (existsSync34(modulesDir)) {
9733
- rmSync9(modulesDir, { recursive: true, force: true });
9823
+ if (existsSync35(modulesDir)) {
9824
+ rmSync10(modulesDir, { recursive: true, force: true });
9734
9825
  }
9735
- const tfSourceDir = join36(targetDir, "terraform");
9736
- if (existsSync34(tfSourceDir)) {
9737
- mkdirSync11(modulesDir, { recursive: true });
9738
- cpSync5(tfSourceDir, modulesDir, { recursive: true });
9826
+ const tfSourceDir = join37(targetDir, "terraform");
9827
+ if (existsSync35(tfSourceDir)) {
9828
+ mkdirSync12(modulesDir, { recursive: true });
9829
+ cpSync6(tfSourceDir, modulesDir, { recursive: true });
9739
9830
  stagePaths.push(`modules/plugins/${source.name}`);
9740
9831
  log.success(`Refreshed Terraform module at modules/plugins/${source.name}/`);
9741
9832
  }
@@ -9757,6 +9848,10 @@ async function runLocalPluginRefresh(localPath, options, deps) {
9757
9848
  } else {
9758
9849
  log.info(`${source.name} declares no tables \u2014 nothing to migrate.`);
9759
9850
  }
9851
+ const seedResult = vendorPluginSeed(targetDir, manifest, options.cwd);
9852
+ if (seedResult.vendored) {
9853
+ stagePaths.push(seedResult.stagedPath);
9854
+ }
9760
9855
  await deps.git.add(options.cwd, stagePaths);
9761
9856
  if (!await deps.git.hasUncommittedChanges(options.cwd)) {
9762
9857
  log.warn(`services/${source.name}/ already matches ${source.origin} \u2014 nothing to commit.`);
@@ -9776,8 +9871,8 @@ async function runLocalPluginRefresh(localPath, options, deps) {
9776
9871
  }
9777
9872
  }
9778
9873
  function readInstalledVersion2(targetDir) {
9779
- const manifestPath = join36(targetDir, "biffo.plugin.json");
9780
- if (!existsSync34(manifestPath)) return void 0;
9874
+ const manifestPath = join37(targetDir, "biffo.plugin.json");
9875
+ if (!existsSync35(manifestPath)) return void 0;
9781
9876
  try {
9782
9877
  return validateManifest(JSON.parse(readFileSync26(manifestPath, "utf8"))).version;
9783
9878
  } catch {
@@ -9814,6 +9909,11 @@ function printDryRun6(entry, currentVersion) {
9814
9909
  ` Would replace Terraform module at: modules/plugins/${entry.name}/ (if the repo has one)`
9815
9910
  );
9816
9911
  }
9912
+ if (entry.baseline_tables && entry.baseline_tables.length > 0) {
9913
+ console.log(
9914
+ ` Would re-vendor seed DDL into: ${pluginSeedImportDir(entry.name)}/ (baseline_tables: ${entry.baseline_tables.join(", ")})`
9915
+ );
9916
+ }
9817
9917
  console.log(` Would commit: feat(plugins): upgrade ${entry.name} to ${entry.version}
9818
9918
  `);
9819
9919
  }
@@ -9833,6 +9933,11 @@ function printLocalDryRun(source, currentVersion, inTreeSource) {
9833
9933
  ` Would check for a migration for ${source.manifest.tables.length} table(s) (generated for a new table or an added column on an already-migrated table; a removed/retyped/nullability-changed column stops the refresh instead \u2014 #1539)`
9834
9934
  );
9835
9935
  }
9936
+ if (source.manifest.seed) {
9937
+ console.log(
9938
+ ` Would re-vendor seed DDL into: ${pluginSeedImportDir(source.name)}/ (baseline_tables: ${source.manifest.seed.baseline_tables.join(", ") || "none declared"})`
9939
+ );
9940
+ }
9836
9941
  console.log(` Would commit: chore(plugins): refresh ${source.name} from local checkout
9837
9942
  `);
9838
9943
  }
@@ -9852,7 +9957,7 @@ pluginCommand.addCommand(pluginStalenessCommand);
9852
9957
  import { Command as Command23 } from "commander";
9853
9958
 
9854
9959
  // src/commands/sibling-check-identity.ts
9855
- import { existsSync as existsSync35, readFileSync as readFileSync27 } from "fs";
9960
+ import { existsSync as existsSync36, readFileSync as readFileSync27 } from "fs";
9856
9961
  import { resolve as resolve18 } from "path";
9857
9962
  import chalk20 from "chalk";
9858
9963
  import { Command as Command22 } from "commander";
@@ -10066,7 +10171,7 @@ async function resolveConfig4(options) {
10066
10171
  return cfg;
10067
10172
  }
10068
10173
  const localConfigPath = resolve18(process.cwd(), "biffo.config.json");
10069
- if (existsSync35(localConfigPath)) {
10174
+ if (existsSync36(localConfigPath)) {
10070
10175
  const raw = JSON.parse(readFileSync27(localConfigPath, "utf8"));
10071
10176
  const result = BiffoConfigSchema.safeParse(raw);
10072
10177
  if (result.success) return result.data;
@@ -10113,19 +10218,19 @@ siblingCommand.addCommand(siblingCheckIdentityCommand);
10113
10218
  import { Command as Command24 } from "commander";
10114
10219
 
10115
10220
  // src/scripts/check-adr-numbering.ts
10116
- import { existsSync as existsSync37 } from "fs";
10117
- import { join as join38 } from "path";
10221
+ import { existsSync as existsSync38 } from "fs";
10222
+ import { join as join39 } from "path";
10118
10223
  import { execa as execa7 } from "execa";
10119
10224
 
10120
10225
  // src/lib/adr-numbering-guard.ts
10121
- import { existsSync as existsSync36, readdirSync as readdirSync14, readFileSync as readFileSync28 } from "fs";
10122
- import { join as join37 } from "path";
10226
+ import { existsSync as existsSync37, readdirSync as readdirSync15, readFileSync as readFileSync28 } from "fs";
10227
+ import { join as join38 } from "path";
10123
10228
  var ADR_FILENAME = /^(\d{4})-.+\.md$/;
10124
10229
  var ALLOWLIST_FILENAME = ".numbering-allowlist";
10125
10230
  var TEMPLATE_ADR_RESERVED_UPTO = "0099";
10126
10231
  function readAdrNumberingAllowlist(adrDir) {
10127
- const path = join37(adrDir, ALLOWLIST_FILENAME);
10128
- if (!existsSync36(path)) return /* @__PURE__ */ new Set();
10232
+ const path = join38(adrDir, ALLOWLIST_FILENAME);
10233
+ if (!existsSync37(path)) return /* @__PURE__ */ new Set();
10129
10234
  const numbers = /* @__PURE__ */ new Set();
10130
10235
  for (const rawLine of readFileSync28(path, "utf8").split("\n")) {
10131
10236
  const line = rawLine.split("#")[0].trim();
@@ -10135,8 +10240,8 @@ function readAdrNumberingAllowlist(adrDir) {
10135
10240
  }
10136
10241
  function adrNumbersIn(adrDir) {
10137
10242
  const claims = /* @__PURE__ */ new Map();
10138
- if (!existsSync36(adrDir)) return claims;
10139
- for (const entry of readdirSync14(adrDir).sort()) {
10243
+ if (!existsSync37(adrDir)) return claims;
10244
+ for (const entry of readdirSync15(adrDir).sort()) {
10140
10245
  const match = ADR_FILENAME.exec(entry);
10141
10246
  if (!match) continue;
10142
10247
  const number = match[1];
@@ -10190,8 +10295,8 @@ function formatAdrReservedRangeViolations(violations, reservedUpTo = TEMPLATE_AD
10190
10295
  // src/scripts/check-adr-numbering.ts
10191
10296
  async function runAdrNumberingCheck() {
10192
10297
  const root = (await execa7("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
10193
- const adrDir = join38(root, "docs", "ADR");
10194
- if (!existsSync37(adrDir)) {
10298
+ const adrDir = join39(root, "docs", "ADR");
10299
+ if (!existsSync38(adrDir)) {
10195
10300
  console.log("\u2713 ADR numbering guard: no docs/ADR/ directory \u2014 nothing to compare");
10196
10301
  return;
10197
10302
  }
@@ -10489,13 +10594,13 @@ async function runBranchProtectionCheck(explicitRepo, options = {}) {
10489
10594
  }
10490
10595
 
10491
10596
  // src/scripts/check-codeql-suppression.ts
10492
- import { existsSync as existsSync38 } from "fs";
10493
- import { join as join40, relative as relative7 } from "path";
10597
+ import { existsSync as existsSync39 } from "fs";
10598
+ import { join as join41, relative as relative7 } from "path";
10494
10599
  import { execa as execa9 } from "execa";
10495
10600
 
10496
10601
  // src/lib/codeql-suppression-guard.ts
10497
- import { readdirSync as readdirSync15, readFileSync as readFileSync29, statSync as statSync8 } from "fs";
10498
- import { join as join39 } from "path";
10602
+ import { readdirSync as readdirSync16, readFileSync as readFileSync29, statSync as statSync8 } from "fs";
10603
+ import { join as join40 } from "path";
10499
10604
  var SKIP_DIRS = /* @__PURE__ */ new Set([
10500
10605
  ".git",
10501
10606
  ".worktrees",
@@ -10521,12 +10626,12 @@ function walkSourceFiles(root) {
10521
10626
  const walk2 = (dir) => {
10522
10627
  let entries;
10523
10628
  try {
10524
- entries = readdirSync15(dir);
10629
+ entries = readdirSync16(dir);
10525
10630
  } catch {
10526
10631
  return;
10527
10632
  }
10528
10633
  for (const entry of entries) {
10529
- const p = join39(dir, entry);
10634
+ const p = join40(dir, entry);
10530
10635
  let st;
10531
10636
  try {
10532
10637
  st = statSync8(p);
@@ -10563,8 +10668,8 @@ function sweepCodeqlSuppressionComments(root) {
10563
10668
  // src/scripts/check-codeql-suppression.ts
10564
10669
  async function runCodeqlSuppressionCheck() {
10565
10670
  const root = (await execa9("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
10566
- const scanRoot = join40(root, "cli", "src");
10567
- if (!existsSync38(scanRoot)) {
10671
+ const scanRoot = join41(root, "cli", "src");
10672
+ if (!existsSync39(scanRoot)) {
10568
10673
  console.log(
10569
10674
  "\u2014 codeql-suppression guard: skipped \u2014 no cli/src in this repo, so there is no CLI source to scan."
10570
10675
  );
@@ -10591,8 +10696,8 @@ async function runCodeqlSuppressionCheck() {
10591
10696
  import { execa as execa10 } from "execa";
10592
10697
 
10593
10698
  // src/lib/cognito-invite-template-guard.ts
10594
- import { readdirSync as readdirSync16, readFileSync as readFileSync30, statSync as statSync9 } from "fs";
10595
- import { join as join41 } from "path";
10699
+ import { readdirSync as readdirSync17, readFileSync as readFileSync30, statSync as statSync9 } from "fs";
10700
+ import { join as join42 } from "path";
10596
10701
  var REQUIRED_INVITE_MEMBERS = ["email_subject", "email_message", "sms_message"];
10597
10702
  var REQUIRED_INVITE_PLACEHOLDERS = ["{username}", "{####}"];
10598
10703
  var PLACEHOLDER_MEMBERS = ["email_message", "sms_message"];
@@ -10669,13 +10774,13 @@ function findModuleTerraformFiles(repoRoot) {
10669
10774
  const walk2 = (dir, relative10) => {
10670
10775
  let entries;
10671
10776
  try {
10672
- entries = readdirSync16(dir);
10777
+ entries = readdirSync17(dir);
10673
10778
  } catch {
10674
10779
  return;
10675
10780
  }
10676
10781
  for (const entry of entries) {
10677
10782
  if (entry === "node_modules" || entry === ".git" || entry === ".worktrees") continue;
10678
- const full = join41(dir, entry);
10783
+ const full = join42(dir, entry);
10679
10784
  const rel = `${relative10}/${entry}`;
10680
10785
  if (statSync9(full).isDirectory()) {
10681
10786
  walk2(full, rel);
@@ -10684,12 +10789,12 @@ function findModuleTerraformFiles(repoRoot) {
10684
10789
  }
10685
10790
  }
10686
10791
  };
10687
- walk2(join41(repoRoot, "modules"), "modules");
10792
+ walk2(join42(repoRoot, "modules"), "modules");
10688
10793
  return found.sort();
10689
10794
  }
10690
10795
  function checkCognitoInviteTemplates(repoRoot) {
10691
10796
  return findModuleTerraformFiles(repoRoot).flatMap(
10692
- (file) => checkInviteTemplateSource(file, readFileSync30(join41(repoRoot, file), "utf8"))
10797
+ (file) => checkInviteTemplateSource(file, readFileSync30(join42(repoRoot, file), "utf8"))
10693
10798
  );
10694
10799
  }
10695
10800
 
@@ -10717,12 +10822,12 @@ async function runCognitoInviteTemplateCheck() {
10717
10822
  }
10718
10823
 
10719
10824
  // src/scripts/check-core-direct-paths.ts
10720
- import { join as join43 } from "path";
10825
+ import { join as join44 } from "path";
10721
10826
  import { execa as execa11 } from "execa";
10722
10827
 
10723
10828
  // src/lib/core-direct-paths-audit.ts
10724
- import { existsSync as existsSync39, readFileSync as readFileSync31, readdirSync as readdirSync17, statSync as statSync10 } from "fs";
10725
- import { join as join42 } from "path";
10829
+ import { existsSync as existsSync40, readFileSync as readFileSync31, readdirSync as readdirSync18, statSync as statSync10 } from "fs";
10830
+ import { join as join43 } from "path";
10726
10831
  var EXTERNAL_BASE_IDENTIFIERS = ["CORE_API_URL"];
10727
10832
  var API_ROUTE_PREFIX = "/api/v1";
10728
10833
  var TEST_FILE_SUFFIXES = [".test.ts", ".test.tsx", ".spec.ts", ".spec.tsx"];
@@ -10881,12 +10986,12 @@ function walkFiles(root, accept, skipDir) {
10881
10986
  const walk2 = (dir) => {
10882
10987
  let entries;
10883
10988
  try {
10884
- entries = readdirSync17(dir);
10989
+ entries = readdirSync18(dir);
10885
10990
  } catch {
10886
10991
  return;
10887
10992
  }
10888
10993
  for (const entry of entries) {
10889
- const p = join42(dir, entry);
10994
+ const p = join43(dir, entry);
10890
10995
  let st;
10891
10996
  try {
10892
10997
  st = statSync10(p);
@@ -10981,7 +11086,7 @@ function pathMatchesAnyCorePrefix(normalized, corePrefixes, apiRoutePrefix = API
10981
11086
  }
10982
11087
  function resolveSiblingCoreSrc(params) {
10983
11088
  const { estateDir, sibling } = params;
10984
- const configPath = join42(estateDir, sibling, "biffo.sibling.json");
11089
+ const configPath = join43(estateDir, sibling, "biffo.sibling.json");
10985
11090
  let raw;
10986
11091
  try {
10987
11092
  raw = readFileSync31(configPath, "utf8");
@@ -11004,8 +11109,8 @@ function resolveSiblingCoreSrc(params) {
11004
11109
  `cannot resolve ${sibling}'s core: ${configPath} has no non-empty "core_project" field.`
11005
11110
  );
11006
11111
  }
11007
- const coreApiSrcDir = join42(estateDir, coreProject, "services", "api", "src");
11008
- if (!existsSync39(coreApiSrcDir)) {
11112
+ const coreApiSrcDir = join43(estateDir, coreProject, "services", "api", "src");
11113
+ if (!existsSync40(coreApiSrcDir)) {
11009
11114
  throw new Error(
11010
11115
  `cannot resolve ${sibling}'s core: biffo.sibling.json names core_project "${coreProject}", but ${coreApiSrcDir} does not exist -- the instance is missing from this estate checkout, not merely unmatched. Refusing to silently skip ${sibling} and shrink the audit's denominator.`
11011
11116
  );
@@ -11048,7 +11153,7 @@ function auditSiblingCoreDirectPaths(params) {
11048
11153
  async function runCoreDirectPathsCheck(opts = {}) {
11049
11154
  const root = (await execa11("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
11050
11155
  const sibling = opts.sibling ?? "sibling-template (self-check)";
11051
- const frontendSrcDir = opts.frontendSrc ?? join43(root, "_skeletons", "sibling-template", "apps", "frontend", "src");
11156
+ const frontendSrcDir = opts.frontendSrc ?? join44(root, "_skeletons", "sibling-template", "apps", "frontend", "src");
11052
11157
  let coreApiSrcDir;
11053
11158
  let coreProject = null;
11054
11159
  if (opts.coreSrc) {
@@ -11064,7 +11169,7 @@ async function runCoreDirectPathsCheck(opts = {}) {
11064
11169
  coreApiSrcDir = resolution.coreApiSrcDir;
11065
11170
  coreProject = resolution.coreProject;
11066
11171
  } else {
11067
- coreApiSrcDir = join43(root, "services", "api", "src");
11172
+ coreApiSrcDir = join44(root, "services", "api", "src");
11068
11173
  }
11069
11174
  const report = auditSiblingCoreDirectPaths({ sibling, frontendSrcDir, coreApiSrcDir });
11070
11175
  console.log(
@@ -11130,8 +11235,8 @@ async function runOwnershipCheck(argv) {
11130
11235
  const { stdout } = await execa12("git", ["diff", "--cached", "--name-status"], { cwd: root });
11131
11236
  ({ changed: changedFiles, deleted: deletedFiles } = parseNameStatus(stdout));
11132
11237
  if (messageFile) {
11133
- const { readFileSync: readFileSync41, existsSync: existsSync48 } = await import("fs");
11134
- if (existsSync48(messageFile)) commitMessage = readFileSync41(messageFile, "utf8");
11238
+ const { readFileSync: readFileSync41, existsSync: existsSync49 } = await import("fs");
11239
+ if (existsSync49(messageFile)) commitMessage = readFileSync41(messageFile, "utf8");
11135
11240
  }
11136
11241
  } else {
11137
11242
  const base = process.env["GITHUB_BASE_REF"] ?? args[0];
@@ -11235,8 +11340,8 @@ ${BOLD}If the divergence is deliberate${OFF}
11235
11340
  import { execa as execa13 } from "execa";
11236
11341
 
11237
11342
  // src/lib/eventbridge-log-permission-guard.ts
11238
- import { readFileSync as readFileSync32, readdirSync as readdirSync18, statSync as statSync11 } from "fs";
11239
- import { join as join44 } from "path";
11343
+ import { readFileSync as readFileSync32, readdirSync as readdirSync19, statSync as statSync11 } from "fs";
11344
+ import { join as join45 } from "path";
11240
11345
  var SKIP_DIRS2 = /* @__PURE__ */ new Set(["node_modules", ".git", ".terraform", ".worktrees", "dist"]);
11241
11346
  var EVENT_TARGET_TYPE = "aws_cloudwatch_event_target";
11242
11347
  var LOG_RESOURCE_POLICY_TYPE = "aws_cloudwatch_log_resource_policy";
@@ -11308,12 +11413,12 @@ function walkTerraformFiles(root) {
11308
11413
  const walk2 = (dir) => {
11309
11414
  let entries;
11310
11415
  try {
11311
- entries = readdirSync18(dir);
11416
+ entries = readdirSync19(dir);
11312
11417
  } catch {
11313
11418
  return;
11314
11419
  }
11315
11420
  for (const entry of entries) {
11316
- const p = join44(dir, entry);
11421
+ const p = join45(dir, entry);
11317
11422
  let st;
11318
11423
  try {
11319
11424
  st = statSync11(p);
@@ -11450,11 +11555,11 @@ import { execa as execa14 } from "execa";
11450
11555
 
11451
11556
  // src/lib/lambda-output-guard.ts
11452
11557
  import { readFileSync as readFileSync34 } from "fs";
11453
- import { join as join46 } from "path";
11558
+ import { join as join47 } from "path";
11454
11559
 
11455
11560
  // src/lib/terraform-input-guard.ts
11456
- import { readdirSync as readdirSync19, readFileSync as readFileSync33, statSync as statSync12 } from "fs";
11457
- import { join as join45 } from "path";
11561
+ import { readdirSync as readdirSync20, readFileSync as readFileSync33, statSync as statSync12 } from "fs";
11562
+ import { join as join46 } from "path";
11458
11563
  var GUARDED_SUBCOMMANDS = [
11459
11564
  "init",
11460
11565
  "plan",
@@ -11472,13 +11577,13 @@ function findWorkflowFiles(repoRoot) {
11472
11577
  const walk2 = (dir, relative10) => {
11473
11578
  let entries;
11474
11579
  try {
11475
- entries = readdirSync19(dir);
11580
+ entries = readdirSync20(dir);
11476
11581
  } catch {
11477
11582
  return;
11478
11583
  }
11479
11584
  for (const entry of entries) {
11480
11585
  if (entry === "node_modules" || entry === ".git" || entry === ".worktrees") continue;
11481
- const full = join45(dir, entry);
11586
+ const full = join46(dir, entry);
11482
11587
  const rel = relative10 ? `${relative10}/${entry}` : entry;
11483
11588
  if (statSync12(full).isDirectory()) {
11484
11589
  walk2(full, rel);
@@ -11522,7 +11627,7 @@ function checkWorkflowSource(file, rawSource) {
11522
11627
  }
11523
11628
  function checkTerraformInput(repoRoot) {
11524
11629
  return findWorkflowFiles(repoRoot).flatMap(
11525
- (file) => checkWorkflowSource(file, readFileSync33(join45(repoRoot, file), "utf8"))
11630
+ (file) => checkWorkflowSource(file, readFileSync33(join46(repoRoot, file), "utf8"))
11526
11631
  );
11527
11632
  }
11528
11633
 
@@ -11580,7 +11685,7 @@ function checkWorkflowSource2(file, rawSource) {
11580
11685
  }
11581
11686
  function checkLambdaOutput(repoRoot) {
11582
11687
  return findWorkflowFiles(repoRoot).flatMap(
11583
- (file) => checkWorkflowSource2(file, readFileSync34(join46(repoRoot, file), "utf8"))
11688
+ (file) => checkWorkflowSource2(file, readFileSync34(join47(repoRoot, file), "utf8"))
11584
11689
  );
11585
11690
  }
11586
11691
 
@@ -11608,8 +11713,8 @@ async function runLambdaOutputCheck() {
11608
11713
  }
11609
11714
 
11610
11715
  // src/scripts/check-pipe-trap.ts
11611
- import { readFileSync as readFileSync35, readdirSync as readdirSync20 } from "fs";
11612
- import { join as join47, relative as relative8 } from "path";
11716
+ import { readFileSync as readFileSync35, readdirSync as readdirSync21 } from "fs";
11717
+ import { join as join48, relative as relative8 } from "path";
11613
11718
  import { execa as execa15 } from "execa";
11614
11719
 
11615
11720
  // src/lib/pipe-trap-guard.ts
@@ -11706,17 +11811,17 @@ function findPipeTraps(source) {
11706
11811
  function shellFiles(root) {
11707
11812
  const out = [];
11708
11813
  for (const dir of ["scripts", ".githooks"]) {
11709
- const full = join47(root, dir);
11814
+ const full = join48(root, dir);
11710
11815
  let entries;
11711
11816
  try {
11712
- entries = readdirSync20(full, { withFileTypes: true });
11817
+ entries = readdirSync21(full, { withFileTypes: true });
11713
11818
  } catch {
11714
11819
  continue;
11715
11820
  }
11716
11821
  for (const entry of entries) {
11717
11822
  if (!entry.isFile()) continue;
11718
11823
  if (dir === "scripts" && !entry.name.endsWith(".sh")) continue;
11719
- out.push(join47(full, entry.name));
11824
+ out.push(join48(full, entry.name));
11720
11825
  }
11721
11826
  }
11722
11827
  return out;
@@ -11753,7 +11858,7 @@ import { execa as execa16 } from "execa";
11753
11858
 
11754
11859
  // src/lib/plugin-allowlist-convention.ts
11755
11860
  import { readFileSync as readFileSync36 } from "fs";
11756
- import { join as join48 } from "path";
11861
+ import { join as join49 } from "path";
11757
11862
  var COMPUTE_MAIN_TF = "modules/cloud/aws/compute/main.tf";
11758
11863
  var PLUGIN_TEMPLATE_MAIN_TF = "modules/plugins/_template/main.tf";
11759
11864
  var ALLOWLIST_MAIN_TF = "modules/cloud/aws/plugin-allowlist/main.tf";
@@ -11764,7 +11869,7 @@ var PLUGIN = "<plugin>";
11764
11869
  var ACCOUNT = "<account>";
11765
11870
  function read(repoRoot, relative10) {
11766
11871
  try {
11767
- return readFileSync36(join48(repoRoot, relative10), "utf8");
11872
+ return readFileSync36(join49(repoRoot, relative10), "utf8");
11768
11873
  } catch {
11769
11874
  throw new Error(`plugin-allowlist drift guard: cannot read ${relative10}`);
11770
11875
  }
@@ -11885,34 +11990,34 @@ async function runPluginAllowlistConventionCheck() {
11885
11990
  }
11886
11991
 
11887
11992
  // src/scripts/check-plugin-collisions.ts
11888
- import { existsSync as existsSync41 } from "fs";
11889
- import { join as join50 } from "path";
11993
+ import { existsSync as existsSync42 } from "fs";
11994
+ import { join as join51 } from "path";
11890
11995
  import { execa as execa17 } from "execa";
11891
11996
 
11892
11997
  // src/lib/plugin-collision-guard.ts
11893
- import { existsSync as existsSync40, readdirSync as readdirSync21, statSync as statSync13 } from "fs";
11894
- import { join as join49 } from "path";
11998
+ import { existsSync as existsSync41, readdirSync as readdirSync22, statSync as statSync13 } from "fs";
11999
+ import { join as join50 } from "path";
11895
12000
  var PYTEST_SPECIAL = /* @__PURE__ */ new Set(["conftest.py"]);
11896
12001
  var IGNORED_DIRS = /* @__PURE__ */ new Set([".venv", "node_modules", "__pycache__", ".git", "dist", "build"]);
11897
12002
  function subdirectories(dir) {
11898
- if (!existsSync40(dir)) return [];
11899
- return readdirSync21(dir).filter((entry) => {
12003
+ if (!existsSync41(dir)) return [];
12004
+ return readdirSync22(dir).filter((entry) => {
11900
12005
  if (IGNORED_DIRS.has(entry) || entry.startsWith(".")) return false;
11901
12006
  try {
11902
- return statSync13(join49(dir, entry)).isDirectory();
12007
+ return statSync13(join50(dir, entry)).isDirectory();
11903
12008
  } catch {
11904
12009
  return false;
11905
12010
  }
11906
12011
  });
11907
12012
  }
11908
12013
  function regularPackagesOf(pluginDir2) {
11909
- return subdirectories(pluginDir2).filter((name) => existsSync40(join49(pluginDir2, name, "__init__.py"))).sort();
12014
+ return subdirectories(pluginDir2).filter((name) => existsSync41(join50(pluginDir2, name, "__init__.py"))).sort();
11910
12015
  }
11911
12016
  function bareTestModulesOf(pluginDir2) {
11912
- const testsDir = join49(pluginDir2, "tests");
11913
- if (!existsSync40(testsDir)) return [];
11914
- if (existsSync40(join49(testsDir, "__init__.py"))) return [];
11915
- return readdirSync21(testsDir).filter((f) => f.endsWith(".py") && !PYTEST_SPECIAL.has(f)).sort();
12017
+ const testsDir = join50(pluginDir2, "tests");
12018
+ if (!existsSync41(testsDir)) return [];
12019
+ if (existsSync41(join50(testsDir, "__init__.py"))) return [];
12020
+ return readdirSync22(testsDir).filter((f) => f.endsWith(".py") && !PYTEST_SPECIAL.has(f)).sort();
11916
12021
  }
11917
12022
  function findCollisions(servicesDir, pluginDirs) {
11918
12023
  const plugins = (pluginDirs ?? subdirectories(servicesDir)).filter((name) => !name.startsWith("_")).filter((name) => name !== "api").sort();
@@ -11920,7 +12025,7 @@ function findCollisions(servicesDir, pluginDirs) {
11920
12025
  const gather = (kind, namesOf) => {
11921
12026
  const claims = /* @__PURE__ */ new Map();
11922
12027
  for (const plugin of plugins) {
11923
- for (const name of namesOf(join49(servicesDir, plugin))) {
12028
+ for (const name of namesOf(join50(servicesDir, plugin))) {
11924
12029
  claims.set(name, [...claims.get(name) ?? [], plugin]);
11925
12030
  }
11926
12031
  }
@@ -11958,8 +12063,8 @@ function formatCollisions(collisions) {
11958
12063
  // src/scripts/check-plugin-collisions.ts
11959
12064
  async function runPluginCollisionCheck() {
11960
12065
  const root = (await execa17("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
11961
- const servicesDir = join50(root, "services");
11962
- if (!existsSync41(servicesDir)) {
12066
+ const servicesDir = join51(root, "services");
12067
+ if (!existsSync42(servicesDir)) {
11963
12068
  console.log("\u2713 plugin collision guard: no services/ directory \u2014 nothing to compare");
11964
12069
  return;
11965
12070
  }
@@ -11979,8 +12084,8 @@ async function runPluginCollisionCheck() {
11979
12084
  import { execa as execa18 } from "execa";
11980
12085
 
11981
12086
  // src/lib/plugin-terraform-guard.ts
11982
- import { existsSync as existsSync42, readFileSync as readFileSync37, readdirSync as readdirSync22 } from "fs";
11983
- import { dirname as dirname10, join as join51, relative as relative9, sep as sep3 } from "path";
12087
+ import { existsSync as existsSync43, readFileSync as readFileSync37, readdirSync as readdirSync23 } from "fs";
12088
+ import { dirname as dirname10, join as join52, relative as relative9, sep as sep3 } from "path";
11984
12089
  var SKIP_DIRS3 = /* @__PURE__ */ new Set(["node_modules", ".git", ".worktrees", "dist", ".venv", "__pycache__"]);
11985
12090
  var PLUGIN_MANIFEST_FILE2 = "biffo.plugin.json";
11986
12091
  function findPluginManifests(root) {
@@ -11988,16 +12093,16 @@ function findPluginManifests(root) {
11988
12093
  const walk2 = (dir) => {
11989
12094
  let entries;
11990
12095
  try {
11991
- entries = readdirSync22(dir, { withFileTypes: true });
12096
+ entries = readdirSync23(dir, { withFileTypes: true });
11992
12097
  } catch {
11993
12098
  return;
11994
12099
  }
11995
12100
  for (const entry of entries) {
11996
12101
  if (entry.isDirectory()) {
11997
12102
  if (SKIP_DIRS3.has(entry.name)) continue;
11998
- walk2(join51(dir, entry.name));
12103
+ walk2(join52(dir, entry.name));
11999
12104
  } else if (entry.isFile() && entry.name === PLUGIN_MANIFEST_FILE2) {
12000
- found.push(relative9(root, join51(dir, entry.name)).split(sep3).join("/"));
12105
+ found.push(relative9(root, join52(dir, entry.name)).split(sep3).join("/"));
12001
12106
  }
12002
12107
  }
12003
12108
  };
@@ -12022,14 +12127,14 @@ function readSubscriptions(absManifestPath) {
12022
12127
  }
12023
12128
  function checkPluginTerraform(root) {
12024
12129
  const violations = [];
12025
- const coreManifest = existsSync42(join51(root, CORE_MANIFEST_FILE)) ? readCoreManifest(root) : null;
12130
+ const coreManifest = existsSync43(join52(root, CORE_MANIFEST_FILE)) ? readCoreManifest(root) : null;
12026
12131
  for (const manifest of findPluginManifests(root)) {
12027
12132
  if (coreManifest && !isTemplateOwned(manifest, coreManifest)) continue;
12028
- const absManifest = join51(root, manifest);
12133
+ const absManifest = join52(root, manifest);
12029
12134
  const subscriptions = readSubscriptions(absManifest);
12030
12135
  if (subscriptions === null) continue;
12031
12136
  const pluginDir2 = dirname10(absManifest);
12032
- if (existsSync42(join51(pluginDir2, "terraform"))) continue;
12137
+ if (existsSync43(join52(pluginDir2, "terraform"))) continue;
12033
12138
  const relPluginDir = relative9(root, pluginDir2).split(sep3).join("/");
12034
12139
  violations.push({
12035
12140
  manifest,
@@ -12060,13 +12165,13 @@ async function runPluginTerraformCheck() {
12060
12165
  }
12061
12166
 
12062
12167
  // src/scripts/check-plugin-tool-supply.ts
12063
- import { existsSync as existsSync44 } from "fs";
12064
- import { join as join53 } from "path";
12168
+ import { existsSync as existsSync45 } from "fs";
12169
+ import { join as join54 } from "path";
12065
12170
  import { execa as execa19 } from "execa";
12066
12171
 
12067
12172
  // src/lib/plugin-tool-supply-audit.ts
12068
- import { existsSync as existsSync43, readFileSync as readFileSync38, readdirSync as readdirSync23, statSync as statSync14 } from "fs";
12069
- import { join as join52 } from "path";
12173
+ import { existsSync as existsSync44, readFileSync as readFileSync38, readdirSync as readdirSync24, statSync as statSync14 } from "fs";
12174
+ import { join as join53 } from "path";
12070
12175
 
12071
12176
  // src/lib/openrouter-model-snapshot.ts
12072
12177
  var OPENROUTER_MODEL_SNAPSHOT_FETCHED_AT = "2026-08-10T06:39:01Z";
@@ -12477,13 +12582,13 @@ var OPENROUTER_MODEL_IDS = [
12477
12582
  function listDirs(root) {
12478
12583
  let entries;
12479
12584
  try {
12480
- entries = readdirSync23(root);
12585
+ entries = readdirSync24(root);
12481
12586
  } catch {
12482
12587
  return [];
12483
12588
  }
12484
12589
  return entries.filter((e) => {
12485
12590
  try {
12486
- return statSync14(join52(root, e)).isDirectory();
12591
+ return statSync14(join53(root, e)).isDirectory();
12487
12592
  } catch {
12488
12593
  return false;
12489
12594
  }
@@ -12494,12 +12599,12 @@ function walkFiles2(root, accept, skipDir) {
12494
12599
  const walk2 = (dir) => {
12495
12600
  let entries;
12496
12601
  try {
12497
- entries = readdirSync23(dir);
12602
+ entries = readdirSync24(dir);
12498
12603
  } catch {
12499
12604
  return;
12500
12605
  }
12501
12606
  for (const entry of entries) {
12502
- const p = join52(dir, entry);
12607
+ const p = join53(dir, entry);
12503
12608
  let st;
12504
12609
  try {
12505
12610
  st = statSync14(p);
@@ -12525,14 +12630,14 @@ function pluginPythonFiles(pluginDir2) {
12525
12630
  );
12526
12631
  }
12527
12632
  function pluginTerraformFiles(pluginDir2) {
12528
- const tfDir = join52(pluginDir2, "terraform");
12633
+ const tfDir = join53(pluginDir2, "terraform");
12529
12634
  let entries;
12530
12635
  try {
12531
- entries = readdirSync23(tfDir);
12636
+ entries = readdirSync24(tfDir);
12532
12637
  } catch {
12533
12638
  return [];
12534
12639
  }
12535
- return entries.filter((e) => e.endsWith(".tf")).map((e) => join52(tfDir, e)).sort();
12640
+ return entries.filter((e) => e.endsWith(".tf")).map((e) => join53(tfDir, e)).sort();
12536
12641
  }
12537
12642
  function extractManifestTools(manifestText) {
12538
12643
  let parsed;
@@ -12784,8 +12889,8 @@ function isSnapshotStale(fetchedAt, now) {
12784
12889
  function normalizeModelId(id) {
12785
12890
  return id.endsWith(":online") ? id.slice(0, -":online".length) : id;
12786
12891
  }
12787
- var CONFIG_PY_PATH = join52("services", "api", "src", "api", "config.py");
12788
- var ORCHESTRATION_SCHEMA_PATH = join52(
12892
+ var CONFIG_PY_PATH = join53("services", "api", "src", "api", "config.py");
12893
+ var ORCHESTRATION_SCHEMA_PATH = join53(
12789
12894
  "services",
12790
12895
  "api",
12791
12896
  "src",
@@ -12797,10 +12902,10 @@ function auditDeclaredModelIds(repoRoot, options = {}) {
12797
12902
  const knownModelIds = options.knownModelIds ?? OPENROUTER_MODEL_IDS;
12798
12903
  const snapshotFetchedAt = options.snapshotFetchedAt ?? OPENROUTER_MODEL_SNAPSHOT_FETCHED_AT;
12799
12904
  const now = options.now ?? /* @__PURE__ */ new Date();
12800
- const configPath = join52(repoRoot, CONFIG_PY_PATH);
12801
- const orchestrationPath = join52(repoRoot, ORCHESTRATION_SCHEMA_PATH);
12802
- const configMissing = !existsSync43(configPath);
12803
- const orchestrationSchemaMissing = !existsSync43(orchestrationPath);
12905
+ const configPath = join53(repoRoot, CONFIG_PY_PATH);
12906
+ const orchestrationPath = join53(repoRoot, ORCHESTRATION_SCHEMA_PATH);
12907
+ const configMissing = !existsSync44(configPath);
12908
+ const orchestrationSchemaMissing = !existsSync44(orchestrationPath);
12804
12909
  const knownSet = new Set(knownModelIds);
12805
12910
  const snapshotEmpty = knownModelIds.length === 0;
12806
12911
  const snapshotStale = isSnapshotStale(snapshotFetchedAt, now);
@@ -12871,7 +12976,7 @@ function auditDeclaredModelIds(repoRoot, options = {}) {
12871
12976
  function discoverPluginDirs(pluginsRoot) {
12872
12977
  return listDirs(pluginsRoot).filter((name) => {
12873
12978
  try {
12874
- return statSync14(join52(pluginsRoot, name, "biffo.plugin.json")).isFile();
12979
+ return statSync14(join53(pluginsRoot, name, "biffo.plugin.json")).isFile();
12875
12980
  } catch {
12876
12981
  return false;
12877
12982
  }
@@ -12884,8 +12989,8 @@ function auditPluginToolSupply(pluginsRoot) {
12884
12989
  let terraformBlind = false;
12885
12990
  let totalDeclaredTools = 0;
12886
12991
  for (const name of pluginNames) {
12887
- const pluginDir2 = join52(pluginsRoot, name);
12888
- const manifestText = readFileSync38(join52(pluginDir2, "biffo.plugin.json"), "utf8");
12992
+ const pluginDir2 = join53(pluginsRoot, name);
12993
+ const manifestText = readFileSync38(join53(pluginDir2, "biffo.plugin.json"), "utf8");
12889
12994
  const manifest = extractManifestTools(manifestText);
12890
12995
  if (manifest.parseError) {
12891
12996
  findings.push({
@@ -12983,7 +13088,7 @@ function auditPluginToolSupply(pluginsRoot) {
12983
13088
  requiredEnvVars: envResult.envVars,
12984
13089
  missingEnvVars: anyWired ? [] : envResult.envVars,
12985
13090
  status: anyWired ? "ok" : "missing-env",
12986
- detail: anyWired ? `${entry.predicate}() is satisfiable: at least one of ${JSON.stringify(envResult.envVars)} is wired in Terraform` : `${entry.predicate}() reads ${JSON.stringify(envResult.envVars)} \u2014 NONE of these are wired by any environment_variables block under ${join52(pluginDir2, "terraform")}, so this deployment can never supply it`
13091
+ detail: anyWired ? `${entry.predicate}() is satisfiable: at least one of ${JSON.stringify(envResult.envVars)} is wired in Terraform` : `${entry.predicate}() reads ${JSON.stringify(envResult.envVars)} \u2014 NONE of these are wired by any environment_variables block under ${join53(pluginDir2, "terraform")}, so this deployment can never supply it`
12987
13092
  });
12988
13093
  }
12989
13094
  }
@@ -13016,8 +13121,8 @@ function auditPluginToolSupply(pluginsRoot) {
13016
13121
  async function runPluginToolSupplyCheck() {
13017
13122
  const root = (await execa19("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
13018
13123
  let allOk = true;
13019
- const pluginsRoot = join53(root, "services", "_plugins");
13020
- if (!existsSync44(pluginsRoot)) {
13124
+ const pluginsRoot = join54(root, "services", "_plugins");
13125
+ if (!existsSync45(pluginsRoot)) {
13021
13126
  console.log("\u2713 plugin tool-supply guard: no services/_plugins/ \u2014 nothing to audit");
13022
13127
  } else {
13023
13128
  const report = auditPluginToolSupply(pluginsRoot);
@@ -13047,8 +13152,8 @@ async function runPluginToolSupplyCheck() {
13047
13152
  console.log(`\u2713 plugin tool-supply guard: ${report.summary}`);
13048
13153
  }
13049
13154
  }
13050
- const servicesApiRoot = join53(root, "services", "api");
13051
- if (!existsSync44(servicesApiRoot)) {
13155
+ const servicesApiRoot = join54(root, "services", "api");
13156
+ if (!existsSync45(servicesApiRoot)) {
13052
13157
  console.log("\u2713 plugin model-id guard: no services/api/ \u2014 nothing to audit");
13053
13158
  } else {
13054
13159
  const modelReport = auditDeclaredModelIds(root);
@@ -13225,13 +13330,13 @@ async function runReleaseSubjectCheck(argv) {
13225
13330
  }
13226
13331
 
13227
13332
  // src/scripts/check-skeleton-drift.ts
13228
- import { existsSync as existsSync45, readdirSync as readdirSync25 } from "fs";
13229
- import { join as join55 } from "path";
13333
+ import { existsSync as existsSync46, readdirSync as readdirSync26 } from "fs";
13334
+ import { join as join56 } from "path";
13230
13335
  import { execa as execa21 } from "execa";
13231
13336
 
13232
13337
  // src/lib/skeleton-drift-guard.ts
13233
- import { readFileSync as readFileSync39, readdirSync as readdirSync24, statSync as statSync15 } from "fs";
13234
- import { join as join54 } from "path";
13338
+ import { readFileSync as readFileSync39, readdirSync as readdirSync25, statSync as statSync15 } from "fs";
13339
+ import { join as join55 } from "path";
13235
13340
  var isWorkflow = (rel) => rel.startsWith(".github/workflows/") && (rel.endsWith(".yml") || rel.endsWith(".yaml"));
13236
13341
  var isRootLayout = (rel) => rel.endsWith("src/app/layout.tsx");
13237
13342
  var uncommented = (contents) => contents.split("\n").filter((line) => !/^\s*(\/\/|\/\*|\*)/.test(line)).join("\n");
@@ -13289,13 +13394,13 @@ function walk(dir, base = dir) {
13289
13394
  const out = [];
13290
13395
  let entries;
13291
13396
  try {
13292
- entries = readdirSync24(dir);
13397
+ entries = readdirSync25(dir);
13293
13398
  } catch {
13294
13399
  return out;
13295
13400
  }
13296
13401
  for (const entry of entries) {
13297
13402
  if (entry === ".venv" || entry === "node_modules" || entry === ".git") continue;
13298
- const abs = join54(dir, entry);
13403
+ const abs = join55(dir, entry);
13299
13404
  let isDir;
13300
13405
  try {
13301
13406
  isDir = statSync15(abs).isDirectory();
@@ -13317,7 +13422,7 @@ function auditSkeleton(skeletonRoot, name, rules = SKELETON_RULES) {
13317
13422
  if (!rule.appliesTo(rel)) continue;
13318
13423
  let contents;
13319
13424
  try {
13320
- contents = readFileSync39(join54(skeletonRoot, rel), "utf8");
13425
+ contents = readFileSync39(join55(skeletonRoot, rel), "utf8");
13321
13426
  } catch {
13322
13427
  continue;
13323
13428
  }
@@ -13346,23 +13451,23 @@ function formatViolations2(violations) {
13346
13451
 
13347
13452
  // src/scripts/check-skeleton-drift.ts
13348
13453
  function discoverSkeletons(root) {
13349
- const skeletonsDir = join55(root, "_skeletons");
13454
+ const skeletonsDir = join56(root, "_skeletons");
13350
13455
  let entries;
13351
13456
  try {
13352
- entries = readdirSync25(skeletonsDir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
13457
+ entries = readdirSync26(skeletonsDir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
13353
13458
  } catch {
13354
13459
  return [];
13355
13460
  }
13356
- return entries.filter((name) => existsSync45(join55(skeletonsDir, name, ".github", "workflows", "ci.yml"))).sort();
13461
+ return entries.filter((name) => existsSync46(join56(skeletonsDir, name, ".github", "workflows", "ci.yml"))).sort();
13357
13462
  }
13358
13463
  async function runSkeletonDriftCheck() {
13359
13464
  const root = (await execa21("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
13360
13465
  const skeletons = discoverSkeletons(root);
13361
13466
  let filesConsidered = 0;
13362
13467
  for (const name of skeletons) {
13363
- const skeletonRoot = join55(root, "_skeletons", name);
13468
+ const skeletonRoot = join56(root, "_skeletons", name);
13364
13469
  filesConsidered += findWorkflowFiles(skeletonRoot).length;
13365
- if (existsSync45(join55(skeletonRoot, "apps", "frontend", "src", "app", "layout.tsx"))) {
13470
+ if (existsSync46(join56(skeletonRoot, "apps", "frontend", "src", "app", "layout.tsx"))) {
13366
13471
  filesConsidered += 1;
13367
13472
  }
13368
13473
  }
@@ -13376,7 +13481,7 @@ async function runSkeletonDriftCheck() {
13376
13481
  process.exit(1);
13377
13482
  }
13378
13483
  const violations = skeletons.flatMap(
13379
- (name) => auditSkeleton(join55(root, "_skeletons", name), name)
13484
+ (name) => auditSkeleton(join56(root, "_skeletons", name), name)
13380
13485
  );
13381
13486
  if (violations.length > 0) {
13382
13487
  console.error("\u2717 Skeleton-drift guard: drift found between this repo and its scaffolding\n");
@@ -13514,8 +13619,8 @@ function rawArgsAfter(subcommand) {
13514
13619
  }
13515
13620
 
13516
13621
  // src/commands/doctor.ts
13517
- import { existsSync as existsSync46, readFileSync as readFileSync40 } from "fs";
13518
- import { join as join56, resolve as resolve20 } from "path";
13622
+ import { existsSync as existsSync47, readFileSync as readFileSync40 } from "fs";
13623
+ import { join as join57, resolve as resolve20 } from "path";
13519
13624
  import chalk21 from "chalk";
13520
13625
  import { Command as Command25 } from "commander";
13521
13626
 
@@ -13694,8 +13799,8 @@ async function runDoctor(options, deps = { git: new GitAdapter() }) {
13694
13799
  return runDoctorChecks(facts);
13695
13800
  }
13696
13801
  function readLocalCoreVersion(cwd) {
13697
- const path = join56(cwd, INSTANCE_CORE_FILE);
13698
- if (!existsSync46(path)) return null;
13802
+ const path = join57(cwd, INSTANCE_CORE_FILE);
13803
+ if (!existsSync47(path)) return null;
13699
13804
  try {
13700
13805
  return extractVersionField(readFileSync40(path, "utf8"));
13701
13806
  } catch {
@@ -13717,8 +13822,8 @@ function extractVersionField(contents) {
13717
13822
  return match?.[1] ?? null;
13718
13823
  }
13719
13824
  function readFossil(cwd) {
13720
- const path = join56(cwd, CORE_VERSION_FILE);
13721
- if (!existsSync46(path)) return null;
13825
+ const path = join57(cwd, CORE_VERSION_FILE);
13826
+ if (!existsSync47(path)) return null;
13722
13827
  try {
13723
13828
  const value = readFileSync40(path, "utf8").trim();
13724
13829
  return value === "" ? null : value;
@@ -14169,13 +14274,13 @@ import { fileURLToPath as fileURLToPath6 } from "url";
14169
14274
  import { Command as Command27 } from "commander";
14170
14275
 
14171
14276
  // src/lib/packaged-scripts.ts
14172
- import { existsSync as existsSync47 } from "fs";
14173
- import { dirname as dirname11, join as join57 } from "path";
14277
+ import { existsSync as existsSync48 } from "fs";
14278
+ import { dirname as dirname11, join as join58 } from "path";
14174
14279
  function findPackagedScript(startDir, relativePath) {
14175
14280
  let dir = startDir;
14176
14281
  for (; ; ) {
14177
- const candidate = join57(dir, relativePath);
14178
- if (existsSync47(candidate)) return candidate;
14282
+ const candidate = join58(dir, relativePath);
14283
+ if (existsSync48(candidate)) return candidate;
14179
14284
  const parent = dirname11(dir);
14180
14285
  if (parent === dir) return null;
14181
14286
  dir = parent;