@biffo/cli 0.309.3 → 0.310.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
@@ -12503,6 +12503,16 @@ function auditSiblingCoreDirectPaths(params) {
12503
12503
  // src/scripts/check-core-direct-paths.ts
12504
12504
  async function runCoreDirectPathsCheck(opts = {}) {
12505
12505
  const root = (await execa("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
12506
+ const usingSelfCheckDefaults = !opts.sibling && !opts.frontendSrc && !opts.coreSrc;
12507
+ if (usingSelfCheckDefaults) {
12508
+ const ownership = classifyRepoOwnership(root);
12509
+ if (ownership === "satellite") {
12510
+ console.log(
12511
+ "\u2713 core-direct-paths guard: skipped \u2014 the self-check defaults compare this repo's own _skeletons/sibling-template scaffold against its own services/api/src, and a sibling/plugin repo has neither: no _skeletons/ at all, and its own services/api/ is an unrelated BFF, not core's route table. Pass --sibling/--frontend-src plus --estate (or --core-src) to audit a real sibling instead."
12512
+ );
12513
+ return;
12514
+ }
12515
+ }
12506
12516
  const sibling = opts.sibling ?? "sibling-template (self-check)";
12507
12517
  const frontendSrcDir = opts.frontendSrc ?? join48(root, "_skeletons", "sibling-template", "apps", "frontend", "src");
12508
12518
  let coreApiSrcDir;
@@ -12616,8 +12626,8 @@ async function runOwnershipCheck(argv) {
12616
12626
  const { stdout } = await execa("git", ["diff", "--cached", "--name-status"], { cwd: root });
12617
12627
  ({ changed: changedFiles, deleted: deletedFiles } = parseNameStatus(stdout));
12618
12628
  if (messageFile) {
12619
- const { readFileSync: readFileSync48, existsSync: existsSync59 } = await import("fs");
12620
- if (existsSync59(messageFile)) commitMessage = readFileSync48(messageFile, "utf8");
12629
+ const { readFileSync: readFileSync48, existsSync: existsSync58 } = await import("fs");
12630
+ if (existsSync58(messageFile)) commitMessage = readFileSync48(messageFile, "utf8");
12621
12631
  }
12622
12632
  } else {
12623
12633
  const base = process.env["GITHUB_BASE_REF"] ?? args[0];
@@ -14052,10 +14062,6 @@ async function runPipeTrapCheck() {
14052
14062
  console.log(`\u2713 Pipe-trap guard: no status-bearing command is piped away`);
14053
14063
  }
14054
14064
 
14055
- // src/scripts/check-plugin-allowlist-convention.ts
14056
- import { existsSync as existsSync50 } from "fs";
14057
- import { join as join61 } from "path";
14058
-
14059
14065
  // src/lib/plugin-allowlist-convention.ts
14060
14066
  import { readFileSync as readFileSync41 } from "fs";
14061
14067
  import { join as join60 } from "path";
@@ -14164,18 +14170,12 @@ Plugins would be rejected by require_service_principal (ADR-0009). Fix the glob,
14164
14170
  }
14165
14171
 
14166
14172
  // src/scripts/check-plugin-allowlist-convention.ts
14167
- var REQUIRED_SOURCES = [
14168
- COMPUTE_MAIN_TF,
14169
- PLUGIN_TEMPLATE_MAIN_TF,
14170
- ALLOWLIST_MAIN_TF,
14171
- ALLOWLIST_VARIABLES_TF
14172
- ];
14173
14173
  async function runPluginAllowlistConventionCheck() {
14174
14174
  const root = (await execa("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
14175
- const missing = REQUIRED_SOURCES.filter((relative11) => !existsSync50(join61(root, relative11)));
14176
- if (missing.length === REQUIRED_SOURCES.length) {
14175
+ const ownership = classifyRepoOwnership(root);
14176
+ if (ownership === "satellite") {
14177
14177
  console.log(
14178
- `\xB7 Plugin-allowlist convention guard: not applicable \u2014 ${missing.join(", ")} not found under ${root}. This is not a template/instance tree (a satellite repo never carries the plugin-allowlist Terraform modules). Skipping.`
14178
+ `\xB7 Plugin-allowlist convention guard: not applicable \u2014 this is not a template/instance tree (${root}), so there is no modules/plugins/_template or modules/cloud/aws/plugin-allowlist Terraform to audit. A sibling app may carry its own unrelated modules/cloud/aws/compute for its own BFF; that is not this guard's concern. Skipping.`
14179
14179
  );
14180
14180
  return;
14181
14181
  }
@@ -14203,32 +14203,32 @@ async function runPluginAllowlistConventionCheck() {
14203
14203
  }
14204
14204
 
14205
14205
  // src/scripts/check-plugin-collisions.ts
14206
- import { existsSync as existsSync52 } from "fs";
14207
- import { join as join63 } from "path";
14206
+ import { existsSync as existsSync51 } from "fs";
14207
+ import { join as join62 } from "path";
14208
14208
 
14209
14209
  // src/lib/plugin-collision-guard.ts
14210
- import { existsSync as existsSync51, readdirSync as readdirSync24, statSync as statSync15 } from "fs";
14211
- import { join as join62 } from "path";
14210
+ import { existsSync as existsSync50, readdirSync as readdirSync24, statSync as statSync15 } from "fs";
14211
+ import { join as join61 } from "path";
14212
14212
  var PYTEST_SPECIAL = /* @__PURE__ */ new Set(["conftest.py"]);
14213
14213
  var IGNORED_DIRS = /* @__PURE__ */ new Set([".venv", "node_modules", "__pycache__", ".git", "dist", "build"]);
14214
14214
  function subdirectories(dir) {
14215
- if (!existsSync51(dir)) return [];
14215
+ if (!existsSync50(dir)) return [];
14216
14216
  return readdirSync24(dir).filter((entry) => {
14217
14217
  if (IGNORED_DIRS.has(entry) || entry.startsWith(".")) return false;
14218
14218
  try {
14219
- return statSync15(join62(dir, entry)).isDirectory();
14219
+ return statSync15(join61(dir, entry)).isDirectory();
14220
14220
  } catch {
14221
14221
  return false;
14222
14222
  }
14223
14223
  });
14224
14224
  }
14225
14225
  function regularPackagesOf(pluginDir2) {
14226
- return subdirectories(pluginDir2).filter((name) => existsSync51(join62(pluginDir2, name, "__init__.py"))).sort();
14226
+ return subdirectories(pluginDir2).filter((name) => existsSync50(join61(pluginDir2, name, "__init__.py"))).sort();
14227
14227
  }
14228
14228
  function bareTestModulesOf(pluginDir2) {
14229
- const testsDir = join62(pluginDir2, "tests");
14230
- if (!existsSync51(testsDir)) return [];
14231
- if (existsSync51(join62(testsDir, "__init__.py"))) return [];
14229
+ const testsDir = join61(pluginDir2, "tests");
14230
+ if (!existsSync50(testsDir)) return [];
14231
+ if (existsSync50(join61(testsDir, "__init__.py"))) return [];
14232
14232
  return readdirSync24(testsDir).filter((f) => f.endsWith(".py") && !PYTEST_SPECIAL.has(f)).sort();
14233
14233
  }
14234
14234
  function findCollisions(servicesDir, pluginDirs) {
@@ -14237,7 +14237,7 @@ function findCollisions(servicesDir, pluginDirs) {
14237
14237
  const gather = (kind, namesOf) => {
14238
14238
  const claims = /* @__PURE__ */ new Map();
14239
14239
  for (const plugin of plugins) {
14240
- for (const name of namesOf(join62(servicesDir, plugin))) {
14240
+ for (const name of namesOf(join61(servicesDir, plugin))) {
14241
14241
  claims.set(name, [...claims.get(name) ?? [], plugin]);
14242
14242
  }
14243
14243
  }
@@ -14275,8 +14275,8 @@ function formatCollisions(collisions) {
14275
14275
  // src/scripts/check-plugin-collisions.ts
14276
14276
  async function runPluginCollisionCheck() {
14277
14277
  const root = (await execa("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
14278
- const servicesDir = join63(root, "services");
14279
- if (!existsSync52(servicesDir)) {
14278
+ const servicesDir = join62(root, "services");
14279
+ if (!existsSync51(servicesDir)) {
14280
14280
  console.log("\u2713 plugin collision guard: no services/ directory \u2014 nothing to compare");
14281
14281
  return;
14282
14282
  }
@@ -14293,8 +14293,8 @@ async function runPluginCollisionCheck() {
14293
14293
  }
14294
14294
 
14295
14295
  // src/lib/plugin-terraform-guard.ts
14296
- import { existsSync as existsSync53, readFileSync as readFileSync42, readdirSync as readdirSync25 } from "fs";
14297
- import { dirname as dirname10, join as join64, relative as relative10, sep as sep4 } from "path";
14296
+ import { existsSync as existsSync52, readFileSync as readFileSync42, readdirSync as readdirSync25 } from "fs";
14297
+ import { dirname as dirname10, join as join63, relative as relative10, sep as sep4 } from "path";
14298
14298
  var SKIP_DIRS4 = /* @__PURE__ */ new Set(["node_modules", ".git", ".worktrees", "dist", ".venv", "__pycache__"]);
14299
14299
  var PLUGIN_MANIFEST_FILE2 = "biffo.plugin.json";
14300
14300
  function findPluginManifests(root) {
@@ -14309,9 +14309,9 @@ function findPluginManifests(root) {
14309
14309
  for (const entry of entries) {
14310
14310
  if (entry.isDirectory()) {
14311
14311
  if (SKIP_DIRS4.has(entry.name)) continue;
14312
- walk2(join64(dir, entry.name));
14312
+ walk2(join63(dir, entry.name));
14313
14313
  } else if (entry.isFile() && entry.name === PLUGIN_MANIFEST_FILE2) {
14314
- found.push(relative10(root, join64(dir, entry.name)).split(sep4).join("/"));
14314
+ found.push(relative10(root, join63(dir, entry.name)).split(sep4).join("/"));
14315
14315
  }
14316
14316
  }
14317
14317
  };
@@ -14336,14 +14336,14 @@ function readSubscriptions(absManifestPath) {
14336
14336
  }
14337
14337
  function checkPluginTerraform(root) {
14338
14338
  const violations = [];
14339
- const coreManifest = existsSync53(join64(root, CORE_MANIFEST_FILE)) ? readCoreManifest(root) : null;
14339
+ const coreManifest = existsSync52(join63(root, CORE_MANIFEST_FILE)) ? readCoreManifest(root) : null;
14340
14340
  for (const manifest of findPluginManifests(root)) {
14341
14341
  if (coreManifest && !isTemplateOwned(manifest, coreManifest)) continue;
14342
- const absManifest = join64(root, manifest);
14342
+ const absManifest = join63(root, manifest);
14343
14343
  const subscriptions = readSubscriptions(absManifest);
14344
14344
  if (subscriptions === null) continue;
14345
14345
  const pluginDir2 = dirname10(absManifest);
14346
- if (existsSync53(join64(pluginDir2, "terraform"))) continue;
14346
+ if (existsSync52(join63(pluginDir2, "terraform"))) continue;
14347
14347
  const relPluginDir = relative10(root, pluginDir2).split(sep4).join("/");
14348
14348
  violations.push({
14349
14349
  manifest,
@@ -14374,12 +14374,12 @@ async function runPluginTerraformCheck() {
14374
14374
  }
14375
14375
 
14376
14376
  // src/scripts/check-plugin-tool-supply.ts
14377
- import { existsSync as existsSync55 } from "fs";
14378
- import { join as join66 } from "path";
14377
+ import { existsSync as existsSync54 } from "fs";
14378
+ import { join as join65 } from "path";
14379
14379
 
14380
14380
  // src/lib/plugin-tool-supply-audit.ts
14381
- import { existsSync as existsSync54, readFileSync as readFileSync43, readdirSync as readdirSync26, statSync as statSync16 } from "fs";
14382
- import { join as join65 } from "path";
14381
+ import { existsSync as existsSync53, readFileSync as readFileSync43, readdirSync as readdirSync26, statSync as statSync16 } from "fs";
14382
+ import { join as join64 } from "path";
14383
14383
 
14384
14384
  // src/lib/openrouter-model-snapshot.ts
14385
14385
  var OPENROUTER_MODEL_SNAPSHOT_FETCHED_AT = "2026-08-10T06:39:01Z";
@@ -14796,7 +14796,7 @@ function listDirs(root) {
14796
14796
  }
14797
14797
  return entries.filter((e) => {
14798
14798
  try {
14799
- return statSync16(join65(root, e)).isDirectory();
14799
+ return statSync16(join64(root, e)).isDirectory();
14800
14800
  } catch {
14801
14801
  return false;
14802
14802
  }
@@ -14812,7 +14812,7 @@ function walkFiles2(root, accept, skipDir) {
14812
14812
  return;
14813
14813
  }
14814
14814
  for (const entry of entries) {
14815
- const p = join65(dir, entry);
14815
+ const p = join64(dir, entry);
14816
14816
  let st;
14817
14817
  try {
14818
14818
  st = statSync16(p);
@@ -14838,14 +14838,14 @@ function pluginPythonFiles(pluginDir2) {
14838
14838
  );
14839
14839
  }
14840
14840
  function pluginTerraformFiles(pluginDir2) {
14841
- const tfDir = join65(pluginDir2, "terraform");
14841
+ const tfDir = join64(pluginDir2, "terraform");
14842
14842
  let entries;
14843
14843
  try {
14844
14844
  entries = readdirSync26(tfDir);
14845
14845
  } catch {
14846
14846
  return [];
14847
14847
  }
14848
- return entries.filter((e) => e.endsWith(".tf")).map((e) => join65(tfDir, e)).sort();
14848
+ return entries.filter((e) => e.endsWith(".tf")).map((e) => join64(tfDir, e)).sort();
14849
14849
  }
14850
14850
  function extractManifestTools(manifestText) {
14851
14851
  let parsed;
@@ -15097,8 +15097,8 @@ function isSnapshotStale(fetchedAt, now) {
15097
15097
  function normalizeModelId(id) {
15098
15098
  return id.endsWith(":online") ? id.slice(0, -":online".length) : id;
15099
15099
  }
15100
- var CONFIG_PY_PATH = join65("services", "api", "src", "api", "config.py");
15101
- var ORCHESTRATION_SCHEMA_PATH = join65(
15100
+ var CONFIG_PY_PATH = join64("services", "api", "src", "api", "config.py");
15101
+ var ORCHESTRATION_SCHEMA_PATH = join64(
15102
15102
  "services",
15103
15103
  "api",
15104
15104
  "src",
@@ -15110,10 +15110,10 @@ function auditDeclaredModelIds(repoRoot, options = {}) {
15110
15110
  const knownModelIds = options.knownModelIds ?? OPENROUTER_MODEL_IDS;
15111
15111
  const snapshotFetchedAt = options.snapshotFetchedAt ?? OPENROUTER_MODEL_SNAPSHOT_FETCHED_AT;
15112
15112
  const now = options.now ?? /* @__PURE__ */ new Date();
15113
- const configPath = join65(repoRoot, CONFIG_PY_PATH);
15114
- const orchestrationPath = join65(repoRoot, ORCHESTRATION_SCHEMA_PATH);
15115
- const configMissing = !existsSync54(configPath);
15116
- const orchestrationSchemaMissing = !existsSync54(orchestrationPath);
15113
+ const configPath = join64(repoRoot, CONFIG_PY_PATH);
15114
+ const orchestrationPath = join64(repoRoot, ORCHESTRATION_SCHEMA_PATH);
15115
+ const configMissing = !existsSync53(configPath);
15116
+ const orchestrationSchemaMissing = !existsSync53(orchestrationPath);
15117
15117
  const knownSet = new Set(knownModelIds);
15118
15118
  const snapshotEmpty = knownModelIds.length === 0;
15119
15119
  const snapshotStale = isSnapshotStale(snapshotFetchedAt, now);
@@ -15184,7 +15184,7 @@ function auditDeclaredModelIds(repoRoot, options = {}) {
15184
15184
  function discoverPluginDirs(pluginsRoot) {
15185
15185
  return listDirs(pluginsRoot).filter((name) => {
15186
15186
  try {
15187
- return statSync16(join65(pluginsRoot, name, "biffo.plugin.json")).isFile();
15187
+ return statSync16(join64(pluginsRoot, name, "biffo.plugin.json")).isFile();
15188
15188
  } catch {
15189
15189
  return false;
15190
15190
  }
@@ -15197,8 +15197,8 @@ function auditPluginToolSupply(pluginsRoot) {
15197
15197
  let terraformBlind = false;
15198
15198
  let totalDeclaredTools = 0;
15199
15199
  for (const name of pluginNames) {
15200
- const pluginDir2 = join65(pluginsRoot, name);
15201
- const manifestText = readFileSync43(join65(pluginDir2, "biffo.plugin.json"), "utf8");
15200
+ const pluginDir2 = join64(pluginsRoot, name);
15201
+ const manifestText = readFileSync43(join64(pluginDir2, "biffo.plugin.json"), "utf8");
15202
15202
  const manifest = extractManifestTools(manifestText);
15203
15203
  if (manifest.parseError) {
15204
15204
  findings.push({
@@ -15296,7 +15296,7 @@ function auditPluginToolSupply(pluginsRoot) {
15296
15296
  requiredEnvVars: envResult.envVars,
15297
15297
  missingEnvVars: anyWired ? [] : envResult.envVars,
15298
15298
  status: anyWired ? "ok" : "missing-env",
15299
- 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 ${join65(pluginDir2, "terraform")}, so this deployment can never supply it`
15299
+ 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 ${join64(pluginDir2, "terraform")}, so this deployment can never supply it`
15300
15300
  });
15301
15301
  }
15302
15302
  }
@@ -15328,9 +15328,16 @@ function auditPluginToolSupply(pluginsRoot) {
15328
15328
  // src/scripts/check-plugin-tool-supply.ts
15329
15329
  async function runPluginToolSupplyCheck() {
15330
15330
  const root = (await execa("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
15331
+ const ownership = classifyRepoOwnership(root);
15332
+ if (ownership === "satellite") {
15333
+ console.log(
15334
+ "\u2713 plugin tool-supply guard: skipped \u2014 this repo is not the template or an instance, so it holds no services/_plugins/ tool grants and no services/api/ model-id catalogue to audit (a sibling/plugin repo may carry an unrelated services/api/ of its own \u2014 a BFF, not the ADR-0002 Core API this guard checks)."
15335
+ );
15336
+ return;
15337
+ }
15331
15338
  let allOk = true;
15332
- const pluginsRoot = join66(root, "services", "_plugins");
15333
- if (!existsSync55(pluginsRoot)) {
15339
+ const pluginsRoot = join65(root, "services", "_plugins");
15340
+ if (!existsSync54(pluginsRoot)) {
15334
15341
  console.log("\u2713 plugin tool-supply guard: no services/_plugins/ \u2014 nothing to audit");
15335
15342
  } else {
15336
15343
  const report = auditPluginToolSupply(pluginsRoot);
@@ -15360,8 +15367,8 @@ async function runPluginToolSupplyCheck() {
15360
15367
  console.log(`\u2713 plugin tool-supply guard: ${report.summary}`);
15361
15368
  }
15362
15369
  }
15363
- const servicesApiRoot = join66(root, "services", "api");
15364
- if (!existsSync55(servicesApiRoot)) {
15370
+ const servicesApiRoot = join65(root, "services", "api");
15371
+ if (!existsSync54(servicesApiRoot)) {
15365
15372
  console.log("\u2713 plugin model-id guard: no services/api/ \u2014 nothing to audit");
15366
15373
  } else {
15367
15374
  const modelReport = auditDeclaredModelIds(root);
@@ -15738,12 +15745,12 @@ async function runSharedFileReductionCheck(args) {
15738
15745
  }
15739
15746
 
15740
15747
  // src/scripts/check-skeleton-drift.ts
15741
- import { existsSync as existsSync56, readdirSync as readdirSync28 } from "fs";
15742
- import { join as join68 } from "path";
15748
+ import { existsSync as existsSync55, readdirSync as readdirSync28 } from "fs";
15749
+ import { join as join67 } from "path";
15743
15750
 
15744
15751
  // src/lib/skeleton-drift-guard.ts
15745
15752
  import { readFileSync as readFileSync46, readdirSync as readdirSync27, statSync as statSync17 } from "fs";
15746
- import { join as join67 } from "path";
15753
+ import { join as join66 } from "path";
15747
15754
  var isWorkflow = (rel) => rel.startsWith(".github/workflows/") && (rel.endsWith(".yml") || rel.endsWith(".yaml"));
15748
15755
  var isRootLayout = (rel) => rel.endsWith("src/app/layout.tsx");
15749
15756
  var uncommented = (contents) => contents.split("\n").filter((line) => !/^\s*(\/\/|\/\*|\*)/.test(line)).join("\n");
@@ -15807,7 +15814,7 @@ function walk(dir, base = dir) {
15807
15814
  }
15808
15815
  for (const entry of entries) {
15809
15816
  if (entry === ".venv" || entry === "node_modules" || entry === ".git") continue;
15810
- const abs = join67(dir, entry);
15817
+ const abs = join66(dir, entry);
15811
15818
  let isDir;
15812
15819
  try {
15813
15820
  isDir = statSync17(abs).isDirectory();
@@ -15829,7 +15836,7 @@ function auditSkeleton(skeletonRoot, name, rules = SKELETON_RULES) {
15829
15836
  if (!rule.appliesTo(rel)) continue;
15830
15837
  let contents;
15831
15838
  try {
15832
- contents = readFileSync46(join67(skeletonRoot, rel), "utf8");
15839
+ contents = readFileSync46(join66(skeletonRoot, rel), "utf8");
15833
15840
  } catch {
15834
15841
  continue;
15835
15842
  }
@@ -15858,23 +15865,23 @@ function formatViolations2(violations) {
15858
15865
 
15859
15866
  // src/scripts/check-skeleton-drift.ts
15860
15867
  function discoverSkeletons(root) {
15861
- const skeletonsDir = join68(root, "_skeletons");
15868
+ const skeletonsDir = join67(root, "_skeletons");
15862
15869
  let entries;
15863
15870
  try {
15864
15871
  entries = readdirSync28(skeletonsDir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
15865
15872
  } catch {
15866
15873
  return [];
15867
15874
  }
15868
- return entries.filter((name) => existsSync56(join68(skeletonsDir, name, ".github", "workflows", "ci.yml"))).sort();
15875
+ return entries.filter((name) => existsSync55(join67(skeletonsDir, name, ".github", "workflows", "ci.yml"))).sort();
15869
15876
  }
15870
15877
  async function runSkeletonDriftCheck() {
15871
15878
  const root = (await execa("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
15872
15879
  const skeletons = discoverSkeletons(root);
15873
15880
  let filesConsidered = 0;
15874
15881
  for (const name of skeletons) {
15875
- const skeletonRoot = join68(root, "_skeletons", name);
15882
+ const skeletonRoot = join67(root, "_skeletons", name);
15876
15883
  filesConsidered += findWorkflowFiles(skeletonRoot).length;
15877
- if (existsSync56(join68(skeletonRoot, "apps", "frontend", "src", "app", "layout.tsx"))) {
15884
+ if (existsSync55(join67(skeletonRoot, "apps", "frontend", "src", "app", "layout.tsx"))) {
15878
15885
  filesConsidered += 1;
15879
15886
  }
15880
15887
  }
@@ -15882,7 +15889,7 @@ async function runSkeletonDriftCheck() {
15882
15889
  `audited ${skeletons.length} skeleton(s) (${skeletons.join(", ") || "none"}), ${filesConsidered} file(s) considered, under ${root}/_skeletons`
15883
15890
  );
15884
15891
  if (skeletons.length === 0) {
15885
- if (!existsSync56(join68(root, "_skeletons"))) {
15892
+ if (!existsSync55(join67(root, "_skeletons"))) {
15886
15893
  console.log(
15887
15894
  `\xB7 Skeleton-drift guard: no _skeletons/ directory under ${root} \u2014 this is not a repo that ships scaffolding (a satellite repo never carries one). Not applicable; skipping.`
15888
15895
  );
@@ -15894,7 +15901,7 @@ async function runSkeletonDriftCheck() {
15894
15901
  process.exit(1);
15895
15902
  }
15896
15903
  const violations = skeletons.flatMap(
15897
- (name) => auditSkeleton(join68(root, "_skeletons", name), name)
15904
+ (name) => auditSkeleton(join67(root, "_skeletons", name), name)
15898
15905
  );
15899
15906
  if (violations.length > 0) {
15900
15907
  console.error("\u2717 Skeleton-drift guard: drift found between this repo and its scaffolding\n");
@@ -16095,8 +16102,8 @@ function rawArgsAfter(subcommand) {
16095
16102
  }
16096
16103
 
16097
16104
  // src/commands/doctor.ts
16098
- import { existsSync as existsSync57, readFileSync as readFileSync47 } from "fs";
16099
- import { join as join69, resolve as resolve20 } from "path";
16105
+ import { existsSync as existsSync56, readFileSync as readFileSync47 } from "fs";
16106
+ import { join as join68, resolve as resolve20 } from "path";
16100
16107
  import chalk21 from "chalk";
16101
16108
  import { Command as Command25 } from "commander";
16102
16109
 
@@ -16517,8 +16524,8 @@ async function runDoctorFixBranches(cwd, facts, deps = { git: new GitAdapter(),
16517
16524
  );
16518
16525
  }
16519
16526
  function readLocalCoreVersion(cwd) {
16520
- const path = join69(cwd, INSTANCE_CORE_FILE);
16521
- if (!existsSync57(path)) return null;
16527
+ const path = join68(cwd, INSTANCE_CORE_FILE);
16528
+ if (!existsSync56(path)) return null;
16522
16529
  try {
16523
16530
  return extractVersionField(readFileSync47(path, "utf8"));
16524
16531
  } catch {
@@ -16540,8 +16547,8 @@ function extractVersionField(contents) {
16540
16547
  return match?.[1] ?? null;
16541
16548
  }
16542
16549
  function readFossil(cwd) {
16543
- const path = join69(cwd, CORE_VERSION_FILE);
16544
- if (!existsSync57(path)) return null;
16550
+ const path = join68(cwd, CORE_VERSION_FILE);
16551
+ if (!existsSync56(path)) return null;
16545
16552
  try {
16546
16553
  const value = readFileSync47(path, "utf8").trim();
16547
16554
  return value === "" ? null : value;
@@ -17080,13 +17087,13 @@ import { fileURLToPath as fileURLToPath6 } from "url";
17080
17087
  import { Command as Command27 } from "commander";
17081
17088
 
17082
17089
  // src/lib/packaged-scripts.ts
17083
- import { existsSync as existsSync58 } from "fs";
17084
- import { dirname as dirname11, join as join70 } from "path";
17090
+ import { existsSync as existsSync57 } from "fs";
17091
+ import { dirname as dirname11, join as join69 } from "path";
17085
17092
  function findPackagedScript(startDir, relativePath) {
17086
17093
  let dir = startDir;
17087
17094
  for (; ; ) {
17088
- const candidate = join70(dir, relativePath);
17089
- if (existsSync58(candidate)) return candidate;
17095
+ const candidate = join69(dir, relativePath);
17096
+ if (existsSync57(candidate)) return candidate;
17090
17097
  const parent = dirname11(dir);
17091
17098
  if (parent === dir) return null;
17092
17099
  dir = parent;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@biffo/cli",
3
- "version": "0.309.3",
3
+ "version": "0.310.0",
4
4
  "description": "Biffo project scaffolding CLI",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/scripts/verify.sh CHANGED
@@ -1455,11 +1455,30 @@ if [ -f scripts/biffo.sh ]; then
1455
1455
  # biffo.core.json's own version and compares against it -- but this repo
1456
1456
  # never carries biffo.core.json (it is the template, not an instance), so
1457
1457
  # the script itself detects that and exits 0 as a genuine skip (see its own
1458
- # doc comment) rather than attempting a comparison it has no tree for. Kept
1459
- # unconditional, exactly like the line above, for the same reason: ci.yml's
1460
- # exact command text must appear in `verify.sh --list`'s output or the
1461
- # parity test (verify-parity.test.ts, #1773) reports it uncategorised.
1462
- run_check orphan-ratchet-instance sh scripts/check-orphan-ratchet-instance.sh
1458
+ # doc comment) rather than attempting a comparison it has no tree for.
1459
+ #
1460
+ # Guarded with `[ -f ... ] &&`, unlike the line above, because this script
1461
+ # is a raw file path rather than a `scripts/biffo.sh check <name>` call
1462
+ # through the versioned CLI bridge -- every other check in this block goes
1463
+ # through that bridge, which resolves against the pinned, PACKAGED CLI and
1464
+ # so works from any repo. This one does not, and `scripts/
1465
+ # check-orphan-ratchet-instance.sh` is template-owned but never packaged
1466
+ # for a satellite: not in shared-files.json's `files` (never copied to a
1467
+ # sibling/plugin repo) and not in `PACKAGED_ROOT_ASSETS` (never bundled
1468
+ # into the npm tarball) -- it only ever reaches a real INSTANCE, via
1469
+ # `biffo core upgrade`'s ordinary three-way merge. A satellite running the
1470
+ # packaged `verify.sh` through `scripts/biffo.sh verify` therefore had no
1471
+ # such file on disk at all, and a bare `sh scripts/
1472
+ # check-orphan-ratchet-instance.sh` failed at the shell -- "cannot open
1473
+ # ... No such file" -- before the script's own biffo.core.json skip ever
1474
+ # got a chance to run (biffo-template#1943). The guard is true in every
1475
+ # checkout that actually carries the file (this repo, and any instance
1476
+ # that has upgraded far enough to have received it), so `verify.sh --list`'s
1477
+ # output here is unchanged and parity with ci.yml's own unconditional step
1478
+ # holds exactly as before; it is false only in a satellite, where this now
1479
+ # skips instead of crashing the rest of the gate.
1480
+ [ -f scripts/check-orphan-ratchet-instance.sh ] &&
1481
+ run_check orphan-ratchet-instance sh scripts/check-orphan-ratchet-instance.sh
1463
1482
  run_check cognito-invite sh scripts/biffo.sh check cognito-invite-template
1464
1483
  run_check lambda-output sh scripts/biffo.sh check lambda-output
1465
1484
  run_check pipe-trap sh scripts/biffo.sh check pipe-trap