@biffo/cli 0.303.2 → 0.303.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +164 -111
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -11122,8 +11122,15 @@ async function runApiGatewayIntegrationCheck() {
11122
11122
  try {
11123
11123
  report = auditApiGatewayIntegrations(root);
11124
11124
  } catch (err) {
11125
+ const message = err instanceof Error ? err.message : String(err);
11126
+ if (message.includes("no .tf files found under")) {
11127
+ console.log(
11128
+ `\xB7 API Gateway integration-qualifier guard: not applicable \u2014 ${message} This repo carries no Terraform at all, which is expected for a non-instance satellite. Skipping.`
11129
+ );
11130
+ return;
11131
+ }
11125
11132
  console.error("\u2717 API Gateway integration-qualifier guard: could not run\n");
11126
- console.error(err instanceof Error ? err.message : String(err));
11133
+ console.error(message);
11127
11134
  process.exit(1);
11128
11135
  }
11129
11136
  console.log(`scanned ${report.filesScanned} .tf file(s) under ${root}`);
@@ -11653,6 +11660,10 @@ async function runCodeqlSuppressionCheck() {
11653
11660
  console.log("\u2713 codeql-suppression guard: no dead `codeql[...]` suppression comment found");
11654
11661
  }
11655
11662
 
11663
+ // src/scripts/check-cognito-invite-template.ts
11664
+ import { existsSync as existsSync42 } from "fs";
11665
+ import { join as join46 } from "path";
11666
+
11656
11667
  // src/lib/cognito-invite-template-guard.ts
11657
11668
  import { readdirSync as readdirSync19, readFileSync as readFileSync33, statSync as statSync11 } from "fs";
11658
11669
  import { join as join45 } from "path";
@@ -11769,6 +11780,12 @@ async function runCognitoInviteTemplateCheck() {
11769
11780
  const files = findModuleTerraformFiles(root);
11770
11781
  console.log(`audited ${files.length} .tf file(s) under modules/ under ${root}`);
11771
11782
  if (files.length === 0) {
11783
+ if (!existsSync42(join46(root, "modules"))) {
11784
+ console.log(
11785
+ `\xB7 Cognito invite template guard: not applicable \u2014 no modules/ directory under ${root} \u2014 this is not a template/instance tree (a satellite repo never carries the template-owned Terraform modules). Skipping.`
11786
+ );
11787
+ return;
11788
+ }
11772
11789
  console.error(
11773
11790
  "\u2717 Cognito invite template guard: found 0 .tf files under modules/ \u2014 this looks like a broken scan, not a clean repo. Refusing to report success over zero input."
11774
11791
  );
@@ -11787,11 +11804,11 @@ async function runCognitoInviteTemplateCheck() {
11787
11804
  }
11788
11805
 
11789
11806
  // src/scripts/check-core-direct-paths.ts
11790
- import { join as join47 } from "path";
11807
+ import { join as join48 } from "path";
11791
11808
 
11792
11809
  // src/lib/core-direct-paths-audit.ts
11793
- import { existsSync as existsSync42, readFileSync as readFileSync34, readdirSync as readdirSync20, statSync as statSync12 } from "fs";
11794
- import { join as join46 } from "path";
11810
+ import { existsSync as existsSync43, readFileSync as readFileSync34, readdirSync as readdirSync20, statSync as statSync12 } from "fs";
11811
+ import { join as join47 } from "path";
11795
11812
  var EXTERNAL_BASE_IDENTIFIERS = ["CORE_API_URL"];
11796
11813
  var API_ROUTE_PREFIX = "/api/v1";
11797
11814
  var TEST_FILE_SUFFIXES = [".test.ts", ".test.tsx", ".spec.ts", ".spec.tsx"];
@@ -11955,7 +11972,7 @@ function walkFiles(root, accept, skipDir) {
11955
11972
  return;
11956
11973
  }
11957
11974
  for (const entry of entries) {
11958
- const p = join46(dir, entry);
11975
+ const p = join47(dir, entry);
11959
11976
  let st;
11960
11977
  try {
11961
11978
  st = statSync12(p);
@@ -12050,7 +12067,7 @@ function pathMatchesAnyCorePrefix(normalized, corePrefixes, apiRoutePrefix = API
12050
12067
  }
12051
12068
  function resolveSiblingCoreSrc(params) {
12052
12069
  const { estateDir, sibling } = params;
12053
- const configPath = join46(estateDir, sibling, "biffo.sibling.json");
12070
+ const configPath = join47(estateDir, sibling, "biffo.sibling.json");
12054
12071
  let raw;
12055
12072
  try {
12056
12073
  raw = readFileSync34(configPath, "utf8");
@@ -12073,8 +12090,8 @@ function resolveSiblingCoreSrc(params) {
12073
12090
  `cannot resolve ${sibling}'s core: ${configPath} has no non-empty "core_project" field.`
12074
12091
  );
12075
12092
  }
12076
- const coreApiSrcDir = join46(estateDir, coreProject, "services", "api", "src");
12077
- if (!existsSync42(coreApiSrcDir)) {
12093
+ const coreApiSrcDir = join47(estateDir, coreProject, "services", "api", "src");
12094
+ if (!existsSync43(coreApiSrcDir)) {
12078
12095
  throw new Error(
12079
12096
  `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.`
12080
12097
  );
@@ -12117,7 +12134,7 @@ function auditSiblingCoreDirectPaths(params) {
12117
12134
  async function runCoreDirectPathsCheck(opts = {}) {
12118
12135
  const root = (await execa("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
12119
12136
  const sibling = opts.sibling ?? "sibling-template (self-check)";
12120
- const frontendSrcDir = opts.frontendSrc ?? join47(root, "_skeletons", "sibling-template", "apps", "frontend", "src");
12137
+ const frontendSrcDir = opts.frontendSrc ?? join48(root, "_skeletons", "sibling-template", "apps", "frontend", "src");
12121
12138
  let coreApiSrcDir;
12122
12139
  let coreProject = null;
12123
12140
  if (opts.coreSrc) {
@@ -12133,7 +12150,7 @@ async function runCoreDirectPathsCheck(opts = {}) {
12133
12150
  coreApiSrcDir = resolution.coreApiSrcDir;
12134
12151
  coreProject = resolution.coreProject;
12135
12152
  } else {
12136
- coreApiSrcDir = join47(root, "services", "api", "src");
12153
+ coreApiSrcDir = join48(root, "services", "api", "src");
12137
12154
  }
12138
12155
  const report = auditSiblingCoreDirectPaths({ sibling, frontendSrcDir, coreApiSrcDir });
12139
12156
  console.log(
@@ -12198,8 +12215,8 @@ async function runOwnershipCheck(argv) {
12198
12215
  const { stdout } = await execa("git", ["diff", "--cached", "--name-status"], { cwd: root });
12199
12216
  ({ changed: changedFiles, deleted: deletedFiles } = parseNameStatus(stdout));
12200
12217
  if (messageFile) {
12201
- const { readFileSync: readFileSync47, existsSync: existsSync57 } = await import("fs");
12202
- if (existsSync57(messageFile)) commitMessage = readFileSync47(messageFile, "utf8");
12218
+ const { readFileSync: readFileSync47, existsSync: existsSync59 } = await import("fs");
12219
+ if (existsSync59(messageFile)) commitMessage = readFileSync47(messageFile, "utf8");
12203
12220
  }
12204
12221
  } else {
12205
12222
  const base = process.env["GITHUB_BASE_REF"] ?? args[0];
@@ -12300,16 +12317,16 @@ ${BOLD}If the divergence is deliberate${OFF}
12300
12317
  }
12301
12318
 
12302
12319
  // src/scripts/check-distribution-inventory.ts
12303
- import { existsSync as existsSync44 } from "fs";
12304
- import { join as join49 } from "path";
12320
+ import { existsSync as existsSync45 } from "fs";
12321
+ import { join as join50 } from "path";
12305
12322
 
12306
12323
  // src/lib/distribution-inventory.ts
12307
- import { existsSync as existsSync43, readFileSync as readFileSync35 } from "fs";
12308
- import { join as join48 } from "path";
12324
+ import { existsSync as existsSync44, readFileSync as readFileSync35 } from "fs";
12325
+ import { join as join49 } from "path";
12309
12326
  var INVENTORY_FILENAME = "distribution-inventory.json";
12310
12327
  function loadDistributionInventory(root) {
12311
- const path = join48(root, INVENTORY_FILENAME);
12312
- if (!existsSync43(path)) {
12328
+ const path = join49(root, INVENTORY_FILENAME);
12329
+ if (!existsSync44(path)) {
12313
12330
  throw new Error(
12314
12331
  `${INVENTORY_FILENAME} not found at ${root} -- expected it beside core-manifest.json`
12315
12332
  );
@@ -12474,7 +12491,7 @@ async function runDistributionInventoryCheck(root) {
12474
12491
  );
12475
12492
  return;
12476
12493
  }
12477
- if (!existsSync44(join49(repoRoot, INVENTORY_FILENAME))) {
12494
+ if (!existsSync45(join50(repoRoot, INVENTORY_FILENAME))) {
12478
12495
  console.log(
12479
12496
  `\u2713 distribution-inventory: skipped \u2014 no ${INVENTORY_FILENAME} at ${repoRoot}. This is a template-only registry; a checkout that legitimately has none has nothing for this guard to check.`
12480
12497
  );
@@ -12500,7 +12517,7 @@ async function runDistributionInventoryCheck(root) {
12500
12517
  }
12501
12518
 
12502
12519
  // src/scripts/check-distribution-remote-state.ts
12503
- import { join as join50 } from "path";
12520
+ import { join as join51 } from "path";
12504
12521
  async function ghExecCommand(file, args) {
12505
12522
  const result = await execa(file, args, { reject: false });
12506
12523
  return { stdout: String(result.stdout ?? ""), exitCode: result.exitCode ?? null };
@@ -12515,7 +12532,7 @@ async function runDistributionRemoteStateCheck(root) {
12515
12532
  }
12516
12533
  }
12517
12534
  console.log(
12518
- `distribution-remote-state: examined ${assertions.length} remote content assertion(s) declared across ${inventory.entries.length} inventory entries (${join50(repoRoot, "distribution-inventory.json")})`
12535
+ `distribution-remote-state: examined ${assertions.length} remote content assertion(s) declared across ${inventory.entries.length} inventory entries (${join51(repoRoot, "distribution-inventory.json")})`
12519
12536
  );
12520
12537
  if (assertions.length === 0) {
12521
12538
  console.log("\u2713 distribution-remote-state: nothing declared to check");
@@ -12561,7 +12578,7 @@ ${assertion.ref}`;
12561
12578
 
12562
12579
  // src/lib/eventbridge-log-permission-guard.ts
12563
12580
  import { readFileSync as readFileSync36, readdirSync as readdirSync21, statSync as statSync13 } from "fs";
12564
- import { join as join51 } from "path";
12581
+ import { join as join52 } from "path";
12565
12582
  var SKIP_DIRS3 = /* @__PURE__ */ new Set(["node_modules", ".git", ".terraform", ".worktrees", "dist"]);
12566
12583
  var EVENT_TARGET_TYPE = "aws_cloudwatch_event_target";
12567
12584
  var LOG_RESOURCE_POLICY_TYPE = "aws_cloudwatch_log_resource_policy";
@@ -12638,7 +12655,7 @@ function walkTerraformFiles2(root) {
12638
12655
  return;
12639
12656
  }
12640
12657
  for (const entry of entries) {
12641
- const p = join51(dir, entry);
12658
+ const p = join52(dir, entry);
12642
12659
  let st;
12643
12660
  try {
12644
12661
  st = statSync13(p);
@@ -12739,8 +12756,15 @@ async function runEventBridgeLogPermissionCheck() {
12739
12756
  try {
12740
12757
  report = auditEventBridgeLogPermissions(root);
12741
12758
  } catch (err) {
12759
+ const message = err instanceof Error ? err.message : String(err);
12760
+ if (message.includes("no .tf files found under")) {
12761
+ console.log(
12762
+ `\xB7 EventBridge log permission guard: not applicable \u2014 ${message} This repo carries no Terraform at all, which is expected for a non-instance satellite. Skipping.`
12763
+ );
12764
+ return;
12765
+ }
12742
12766
  console.error("\u2717 EventBridge log permission guard: could not run\n");
12743
- console.error(err instanceof Error ? err.message : String(err));
12767
+ console.error(message);
12744
12768
  process.exit(1);
12745
12769
  }
12746
12770
  console.log(`audited ${report.filesScanned} .tf file(s) under ${root}`);
@@ -12771,8 +12795,8 @@ async function runEventBridgeLogPermissionCheck() {
12771
12795
  }
12772
12796
 
12773
12797
  // src/scripts/check-instance-adoption.ts
12774
- import { existsSync as existsSync45 } from "fs";
12775
- import { join as join52 } from "path";
12798
+ import { existsSync as existsSync46 } from "fs";
12799
+ import { join as join53 } from "path";
12776
12800
  async function runInstanceAdoptionCheck(opts = {}) {
12777
12801
  if (!opts.instanceDir) {
12778
12802
  console.error(
@@ -12780,7 +12804,7 @@ async function runInstanceAdoptionCheck(opts = {}) {
12780
12804
  );
12781
12805
  process.exit(2);
12782
12806
  }
12783
- if (!existsSync45(opts.instanceDir)) {
12807
+ if (!existsSync46(opts.instanceDir)) {
12784
12808
  console.error(
12785
12809
  `\u2717 instance-adoption guard: --instance-dir ${opts.instanceDir} does not exist \u2014 cannot tell whether it is adopted, and that is not the same as a clean pass.`
12786
12810
  );
@@ -12788,7 +12812,7 @@ async function runInstanceAdoptionCheck(opts = {}) {
12788
12812
  }
12789
12813
  const root = (await execa("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
12790
12814
  const theirsDir = opts.theirsDir ?? root;
12791
- const instanceLabel = opts.instance ?? join52(opts.instanceDir).split("/").filter(Boolean).pop();
12815
+ const instanceLabel = opts.instance ?? join53(opts.instanceDir).split("/").filter(Boolean).pop();
12792
12816
  const report = checkInstanceAdoption(theirsDir, opts.instanceDir);
12793
12817
  console.log(
12794
12818
  `examined ${report.examinedInstances} instance (${instanceLabel}) against ${report.registeredPairs} registered pair(s), ${report.applicablePairs} applicable to this instance, against template tree ${theirsDir}`
@@ -12811,11 +12835,11 @@ async function runInstanceAdoptionCheck(opts = {}) {
12811
12835
 
12812
12836
  // src/lib/lambda-output-guard.ts
12813
12837
  import { readFileSync as readFileSync38 } from "fs";
12814
- import { join as join54 } from "path";
12838
+ import { join as join55 } from "path";
12815
12839
 
12816
12840
  // src/lib/terraform-input-guard.ts
12817
- import { existsSync as existsSync46, readdirSync as readdirSync22, readFileSync as readFileSync37, statSync as statSync14 } from "fs";
12818
- import { join as join53 } from "path";
12841
+ import { existsSync as existsSync47, readdirSync as readdirSync22, readFileSync as readFileSync37, statSync as statSync14 } from "fs";
12842
+ import { join as join54 } from "path";
12819
12843
  var GUARDED_SUBCOMMANDS = [
12820
12844
  "init",
12821
12845
  "plan",
@@ -12829,7 +12853,7 @@ function stripComments2(source) {
12829
12853
  return source.split("\n").map((line) => line.replace(/(^|\s)#.*$/, "$1")).join("\n");
12830
12854
  }
12831
12855
  function vendoredPluginServiceDirs(repoRoot) {
12832
- const servicesDir = join53(repoRoot, "services");
12856
+ const servicesDir = join54(repoRoot, "services");
12833
12857
  const result = /* @__PURE__ */ new Set();
12834
12858
  let entries;
12835
12859
  try {
@@ -12838,9 +12862,9 @@ function vendoredPluginServiceDirs(repoRoot) {
12838
12862
  return result;
12839
12863
  }
12840
12864
  for (const entry of entries) {
12841
- const full = join53(servicesDir, entry);
12842
- if (!existsSync46(full) || !statSync14(full).isDirectory()) continue;
12843
- if (existsSync46(join53(full, "biffo.plugin.json"))) {
12865
+ const full = join54(servicesDir, entry);
12866
+ if (!existsSync47(full) || !statSync14(full).isDirectory()) continue;
12867
+ if (existsSync47(join54(full, "biffo.plugin.json"))) {
12844
12868
  result.add(entry);
12845
12869
  }
12846
12870
  }
@@ -12862,7 +12886,7 @@ function findWorkflowFiles(repoRoot) {
12862
12886
  if (entry === ".github" && relative11.startsWith("services/") && vendoredPluginDirs.has(relative11.slice("services/".length))) {
12863
12887
  continue;
12864
12888
  }
12865
- const full = join53(dir, entry);
12889
+ const full = join54(dir, entry);
12866
12890
  const rel = relative11 ? `${relative11}/${entry}` : entry;
12867
12891
  let isDir;
12868
12892
  try {
@@ -12912,7 +12936,7 @@ function checkWorkflowSource(file, rawSource) {
12912
12936
  }
12913
12937
  function checkTerraformInput(repoRoot) {
12914
12938
  return findWorkflowFiles(repoRoot).flatMap(
12915
- (file) => checkWorkflowSource(file, readFileSync37(join53(repoRoot, file), "utf8"))
12939
+ (file) => checkWorkflowSource(file, readFileSync37(join54(repoRoot, file), "utf8"))
12916
12940
  );
12917
12941
  }
12918
12942
 
@@ -12970,7 +12994,7 @@ function checkWorkflowSource2(file, rawSource) {
12970
12994
  }
12971
12995
  function checkLambdaOutput(repoRoot) {
12972
12996
  return findWorkflowFiles(repoRoot).flatMap(
12973
- (file) => checkWorkflowSource2(file, readFileSync38(join54(repoRoot, file), "utf8"))
12997
+ (file) => checkWorkflowSource2(file, readFileSync38(join55(repoRoot, file), "utf8"))
12974
12998
  );
12975
12999
  }
12976
13000
 
@@ -12998,8 +13022,8 @@ async function runLambdaOutputCheck() {
12998
13022
  }
12999
13023
 
13000
13024
  // src/scripts/check-migration-body-change.ts
13001
- import { existsSync as existsSync47 } from "fs";
13002
- import { join as join55 } from "path";
13025
+ import { existsSync as existsSync48 } from "fs";
13026
+ import { join as join56 } from "path";
13003
13027
 
13004
13028
  // src/lib/migration-body-change-guard.ts
13005
13029
  function checkMigrationBodyChangeMarkers(diffs) {
@@ -13065,7 +13089,7 @@ async function runMigrationBodyChangeCheck(argv) {
13065
13089
  );
13066
13090
  return;
13067
13091
  }
13068
- if (!existsSync47(join55(root, MIGRATIONS_VERSIONS_DIR))) {
13092
+ if (!existsSync48(join56(root, MIGRATIONS_VERSIONS_DIR))) {
13069
13093
  console.log(`\u2713 migration body-change guard: no ${MIGRATIONS_VERSIONS_DIR} in this repo.`);
13070
13094
  return;
13071
13095
  }
@@ -13167,8 +13191,8 @@ ${BOLD2}What to do${OFF2}
13167
13191
  }
13168
13192
 
13169
13193
  // src/scripts/check-orphan-ratchet.ts
13170
- import { existsSync as existsSync48 } from "fs";
13171
- import { basename as basename3 } from "path";
13194
+ import { existsSync as existsSync49 } from "fs";
13195
+ import { basename as basename3, join as join57 } from "path";
13172
13196
  function reportOrphan(entry, manifest) {
13173
13197
  console.error(` ${entry.path}`);
13174
13198
  const { templateOwnedMatch, nearestUserOwnedEntries } = explainOwnership(entry.path, manifest);
@@ -13190,7 +13214,7 @@ function reportOrphan(entry, manifest) {
13190
13214
  }
13191
13215
  }
13192
13216
  async function runOrphanRatchetCheck(opts = {}) {
13193
- if (opts.instanceDir !== void 0 && !existsSync48(opts.instanceDir)) {
13217
+ if (opts.instanceDir !== void 0 && !existsSync49(opts.instanceDir)) {
13194
13218
  console.error(
13195
13219
  `\u2717 orphan-ratchet guard: --instance-dir ${opts.instanceDir} does not exist \u2014 cannot tell whether it carries unsanctioned files, and that is not the same as a clean pass.`
13196
13220
  );
@@ -13207,6 +13231,12 @@ async function runOrphanRatchetCheck(opts = {}) {
13207
13231
  "self-check mode: --instance-dir was not given, so it defaulted to --theirs-dir (this repo's own root) alongside --base-dir \u2014 all three trees are the same, so this run can only ever find zero orphans by construction. See this script's doc comment. Pass a real instance tree with --instance-dir for a check that can actually find something. biffo-template#1714."
13208
13232
  );
13209
13233
  }
13234
+ if (!existsSync49(join57(theirsDir, CORE_MANIFEST_FILE))) {
13235
+ console.log(
13236
+ `orphan-ratchet guard (${label}): no ${CORE_MANIFEST_FILE} in ${theirsDir} \u2014 this is not a Biffo template/instance tree (a satellite repo never carries one), so there is no ownership manifest to classify paths against. Not applicable; skipping.`
13237
+ );
13238
+ return;
13239
+ }
13210
13240
  const manifest = readCoreManifest(theirsDir);
13211
13241
  const plan = await planCoreUpgrade({ baseDir, oursDir: instanceDir, theirsDir, manifest });
13212
13242
  const baseline = readOrphanBaseline(instanceDir);
@@ -13233,7 +13263,7 @@ baseline was ${String(ratchet.baseline)}, now ${String(ratchet.count)}. See biff
13233
13263
 
13234
13264
  // src/scripts/check-pipe-trap.ts
13235
13265
  import { readFileSync as readFileSync39, readdirSync as readdirSync23 } from "fs";
13236
- import { join as join56, relative as relative9 } from "path";
13266
+ import { join as join58, relative as relative9 } from "path";
13237
13267
 
13238
13268
  // src/lib/pipe-trap-guard.ts
13239
13269
  var STATUS_BEARING = [
@@ -13329,7 +13359,7 @@ function findPipeTraps(source) {
13329
13359
  function shellFiles(root) {
13330
13360
  const out = [];
13331
13361
  for (const dir of ["scripts", ".githooks"]) {
13332
- const full = join56(root, dir);
13362
+ const full = join58(root, dir);
13333
13363
  let entries;
13334
13364
  try {
13335
13365
  entries = readdirSync23(full, { withFileTypes: true });
@@ -13339,7 +13369,7 @@ function shellFiles(root) {
13339
13369
  for (const entry of entries) {
13340
13370
  if (!entry.isFile()) continue;
13341
13371
  if (dir === "scripts" && !entry.name.endsWith(".sh")) continue;
13342
- out.push(join56(full, entry.name));
13372
+ out.push(join58(full, entry.name));
13343
13373
  }
13344
13374
  }
13345
13375
  return out;
@@ -13371,9 +13401,13 @@ async function runPipeTrapCheck() {
13371
13401
  console.log(`\u2713 Pipe-trap guard: no status-bearing command is piped away`);
13372
13402
  }
13373
13403
 
13404
+ // src/scripts/check-plugin-allowlist-convention.ts
13405
+ import { existsSync as existsSync50 } from "fs";
13406
+ import { join as join60 } from "path";
13407
+
13374
13408
  // src/lib/plugin-allowlist-convention.ts
13375
13409
  import { readFileSync as readFileSync40 } from "fs";
13376
- import { join as join57 } from "path";
13410
+ import { join as join59 } from "path";
13377
13411
  var COMPUTE_MAIN_TF = "modules/cloud/aws/compute/main.tf";
13378
13412
  var PLUGIN_TEMPLATE_MAIN_TF = "modules/plugins/_template/main.tf";
13379
13413
  var ALLOWLIST_MAIN_TF = "modules/cloud/aws/plugin-allowlist/main.tf";
@@ -13384,7 +13418,7 @@ var PLUGIN = "<plugin>";
13384
13418
  var ACCOUNT = "<account>";
13385
13419
  function read(repoRoot, relative11) {
13386
13420
  try {
13387
- return readFileSync40(join57(repoRoot, relative11), "utf8");
13421
+ return readFileSync40(join59(repoRoot, relative11), "utf8");
13388
13422
  } catch {
13389
13423
  throw new Error(`plugin-allowlist drift guard: cannot read ${relative11}`);
13390
13424
  }
@@ -13479,8 +13513,21 @@ Plugins would be rejected by require_service_principal (ADR-0009). Fix the glob,
13479
13513
  }
13480
13514
 
13481
13515
  // src/scripts/check-plugin-allowlist-convention.ts
13516
+ var REQUIRED_SOURCES = [
13517
+ COMPUTE_MAIN_TF,
13518
+ PLUGIN_TEMPLATE_MAIN_TF,
13519
+ ALLOWLIST_MAIN_TF,
13520
+ ALLOWLIST_VARIABLES_TF
13521
+ ];
13482
13522
  async function runPluginAllowlistConventionCheck() {
13483
13523
  const root = (await execa("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
13524
+ const missing = REQUIRED_SOURCES.filter((relative11) => !existsSync50(join60(root, relative11)));
13525
+ if (missing.length === REQUIRED_SOURCES.length) {
13526
+ console.log(
13527
+ `\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.`
13528
+ );
13529
+ return;
13530
+ }
13484
13531
  let violations;
13485
13532
  try {
13486
13533
  violations = checkAllowlistConvention(root);
@@ -13505,32 +13552,32 @@ async function runPluginAllowlistConventionCheck() {
13505
13552
  }
13506
13553
 
13507
13554
  // src/scripts/check-plugin-collisions.ts
13508
- import { existsSync as existsSync50 } from "fs";
13509
- import { join as join59 } from "path";
13555
+ import { existsSync as existsSync52 } from "fs";
13556
+ import { join as join62 } from "path";
13510
13557
 
13511
13558
  // src/lib/plugin-collision-guard.ts
13512
- import { existsSync as existsSync49, readdirSync as readdirSync24, statSync as statSync15 } from "fs";
13513
- import { join as join58 } from "path";
13559
+ import { existsSync as existsSync51, readdirSync as readdirSync24, statSync as statSync15 } from "fs";
13560
+ import { join as join61 } from "path";
13514
13561
  var PYTEST_SPECIAL = /* @__PURE__ */ new Set(["conftest.py"]);
13515
13562
  var IGNORED_DIRS = /* @__PURE__ */ new Set([".venv", "node_modules", "__pycache__", ".git", "dist", "build"]);
13516
13563
  function subdirectories(dir) {
13517
- if (!existsSync49(dir)) return [];
13564
+ if (!existsSync51(dir)) return [];
13518
13565
  return readdirSync24(dir).filter((entry) => {
13519
13566
  if (IGNORED_DIRS.has(entry) || entry.startsWith(".")) return false;
13520
13567
  try {
13521
- return statSync15(join58(dir, entry)).isDirectory();
13568
+ return statSync15(join61(dir, entry)).isDirectory();
13522
13569
  } catch {
13523
13570
  return false;
13524
13571
  }
13525
13572
  });
13526
13573
  }
13527
13574
  function regularPackagesOf(pluginDir2) {
13528
- return subdirectories(pluginDir2).filter((name) => existsSync49(join58(pluginDir2, name, "__init__.py"))).sort();
13575
+ return subdirectories(pluginDir2).filter((name) => existsSync51(join61(pluginDir2, name, "__init__.py"))).sort();
13529
13576
  }
13530
13577
  function bareTestModulesOf(pluginDir2) {
13531
- const testsDir = join58(pluginDir2, "tests");
13532
- if (!existsSync49(testsDir)) return [];
13533
- if (existsSync49(join58(testsDir, "__init__.py"))) return [];
13578
+ const testsDir = join61(pluginDir2, "tests");
13579
+ if (!existsSync51(testsDir)) return [];
13580
+ if (existsSync51(join61(testsDir, "__init__.py"))) return [];
13534
13581
  return readdirSync24(testsDir).filter((f) => f.endsWith(".py") && !PYTEST_SPECIAL.has(f)).sort();
13535
13582
  }
13536
13583
  function findCollisions(servicesDir, pluginDirs) {
@@ -13539,7 +13586,7 @@ function findCollisions(servicesDir, pluginDirs) {
13539
13586
  const gather = (kind, namesOf) => {
13540
13587
  const claims = /* @__PURE__ */ new Map();
13541
13588
  for (const plugin of plugins) {
13542
- for (const name of namesOf(join58(servicesDir, plugin))) {
13589
+ for (const name of namesOf(join61(servicesDir, plugin))) {
13543
13590
  claims.set(name, [...claims.get(name) ?? [], plugin]);
13544
13591
  }
13545
13592
  }
@@ -13577,8 +13624,8 @@ function formatCollisions(collisions) {
13577
13624
  // src/scripts/check-plugin-collisions.ts
13578
13625
  async function runPluginCollisionCheck() {
13579
13626
  const root = (await execa("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
13580
- const servicesDir = join59(root, "services");
13581
- if (!existsSync50(servicesDir)) {
13627
+ const servicesDir = join62(root, "services");
13628
+ if (!existsSync52(servicesDir)) {
13582
13629
  console.log("\u2713 plugin collision guard: no services/ directory \u2014 nothing to compare");
13583
13630
  return;
13584
13631
  }
@@ -13595,8 +13642,8 @@ async function runPluginCollisionCheck() {
13595
13642
  }
13596
13643
 
13597
13644
  // src/lib/plugin-terraform-guard.ts
13598
- import { existsSync as existsSync51, readFileSync as readFileSync41, readdirSync as readdirSync25 } from "fs";
13599
- import { dirname as dirname10, join as join60, relative as relative10, sep as sep4 } from "path";
13645
+ import { existsSync as existsSync53, readFileSync as readFileSync41, readdirSync as readdirSync25 } from "fs";
13646
+ import { dirname as dirname10, join as join63, relative as relative10, sep as sep4 } from "path";
13600
13647
  var SKIP_DIRS4 = /* @__PURE__ */ new Set(["node_modules", ".git", ".worktrees", "dist", ".venv", "__pycache__"]);
13601
13648
  var PLUGIN_MANIFEST_FILE2 = "biffo.plugin.json";
13602
13649
  function findPluginManifests(root) {
@@ -13611,9 +13658,9 @@ function findPluginManifests(root) {
13611
13658
  for (const entry of entries) {
13612
13659
  if (entry.isDirectory()) {
13613
13660
  if (SKIP_DIRS4.has(entry.name)) continue;
13614
- walk2(join60(dir, entry.name));
13661
+ walk2(join63(dir, entry.name));
13615
13662
  } else if (entry.isFile() && entry.name === PLUGIN_MANIFEST_FILE2) {
13616
- found.push(relative10(root, join60(dir, entry.name)).split(sep4).join("/"));
13663
+ found.push(relative10(root, join63(dir, entry.name)).split(sep4).join("/"));
13617
13664
  }
13618
13665
  }
13619
13666
  };
@@ -13638,14 +13685,14 @@ function readSubscriptions(absManifestPath) {
13638
13685
  }
13639
13686
  function checkPluginTerraform(root) {
13640
13687
  const violations = [];
13641
- const coreManifest = existsSync51(join60(root, CORE_MANIFEST_FILE)) ? readCoreManifest(root) : null;
13688
+ const coreManifest = existsSync53(join63(root, CORE_MANIFEST_FILE)) ? readCoreManifest(root) : null;
13642
13689
  for (const manifest of findPluginManifests(root)) {
13643
13690
  if (coreManifest && !isTemplateOwned(manifest, coreManifest)) continue;
13644
- const absManifest = join60(root, manifest);
13691
+ const absManifest = join63(root, manifest);
13645
13692
  const subscriptions = readSubscriptions(absManifest);
13646
13693
  if (subscriptions === null) continue;
13647
13694
  const pluginDir2 = dirname10(absManifest);
13648
- if (existsSync51(join60(pluginDir2, "terraform"))) continue;
13695
+ if (existsSync53(join63(pluginDir2, "terraform"))) continue;
13649
13696
  const relPluginDir = relative10(root, pluginDir2).split(sep4).join("/");
13650
13697
  violations.push({
13651
13698
  manifest,
@@ -13676,12 +13723,12 @@ async function runPluginTerraformCheck() {
13676
13723
  }
13677
13724
 
13678
13725
  // src/scripts/check-plugin-tool-supply.ts
13679
- import { existsSync as existsSync53 } from "fs";
13680
- import { join as join62 } from "path";
13726
+ import { existsSync as existsSync55 } from "fs";
13727
+ import { join as join65 } from "path";
13681
13728
 
13682
13729
  // src/lib/plugin-tool-supply-audit.ts
13683
- import { existsSync as existsSync52, readFileSync as readFileSync42, readdirSync as readdirSync26, statSync as statSync16 } from "fs";
13684
- import { join as join61 } from "path";
13730
+ import { existsSync as existsSync54, readFileSync as readFileSync42, readdirSync as readdirSync26, statSync as statSync16 } from "fs";
13731
+ import { join as join64 } from "path";
13685
13732
 
13686
13733
  // src/lib/openrouter-model-snapshot.ts
13687
13734
  var OPENROUTER_MODEL_SNAPSHOT_FETCHED_AT = "2026-08-10T06:39:01Z";
@@ -14098,7 +14145,7 @@ function listDirs(root) {
14098
14145
  }
14099
14146
  return entries.filter((e) => {
14100
14147
  try {
14101
- return statSync16(join61(root, e)).isDirectory();
14148
+ return statSync16(join64(root, e)).isDirectory();
14102
14149
  } catch {
14103
14150
  return false;
14104
14151
  }
@@ -14114,7 +14161,7 @@ function walkFiles2(root, accept, skipDir) {
14114
14161
  return;
14115
14162
  }
14116
14163
  for (const entry of entries) {
14117
- const p = join61(dir, entry);
14164
+ const p = join64(dir, entry);
14118
14165
  let st;
14119
14166
  try {
14120
14167
  st = statSync16(p);
@@ -14140,14 +14187,14 @@ function pluginPythonFiles(pluginDir2) {
14140
14187
  );
14141
14188
  }
14142
14189
  function pluginTerraformFiles(pluginDir2) {
14143
- const tfDir = join61(pluginDir2, "terraform");
14190
+ const tfDir = join64(pluginDir2, "terraform");
14144
14191
  let entries;
14145
14192
  try {
14146
14193
  entries = readdirSync26(tfDir);
14147
14194
  } catch {
14148
14195
  return [];
14149
14196
  }
14150
- return entries.filter((e) => e.endsWith(".tf")).map((e) => join61(tfDir, e)).sort();
14197
+ return entries.filter((e) => e.endsWith(".tf")).map((e) => join64(tfDir, e)).sort();
14151
14198
  }
14152
14199
  function extractManifestTools(manifestText) {
14153
14200
  let parsed;
@@ -14399,8 +14446,8 @@ function isSnapshotStale(fetchedAt, now) {
14399
14446
  function normalizeModelId(id) {
14400
14447
  return id.endsWith(":online") ? id.slice(0, -":online".length) : id;
14401
14448
  }
14402
- var CONFIG_PY_PATH = join61("services", "api", "src", "api", "config.py");
14403
- var ORCHESTRATION_SCHEMA_PATH = join61(
14449
+ var CONFIG_PY_PATH = join64("services", "api", "src", "api", "config.py");
14450
+ var ORCHESTRATION_SCHEMA_PATH = join64(
14404
14451
  "services",
14405
14452
  "api",
14406
14453
  "src",
@@ -14412,10 +14459,10 @@ function auditDeclaredModelIds(repoRoot, options = {}) {
14412
14459
  const knownModelIds = options.knownModelIds ?? OPENROUTER_MODEL_IDS;
14413
14460
  const snapshotFetchedAt = options.snapshotFetchedAt ?? OPENROUTER_MODEL_SNAPSHOT_FETCHED_AT;
14414
14461
  const now = options.now ?? /* @__PURE__ */ new Date();
14415
- const configPath = join61(repoRoot, CONFIG_PY_PATH);
14416
- const orchestrationPath = join61(repoRoot, ORCHESTRATION_SCHEMA_PATH);
14417
- const configMissing = !existsSync52(configPath);
14418
- const orchestrationSchemaMissing = !existsSync52(orchestrationPath);
14462
+ const configPath = join64(repoRoot, CONFIG_PY_PATH);
14463
+ const orchestrationPath = join64(repoRoot, ORCHESTRATION_SCHEMA_PATH);
14464
+ const configMissing = !existsSync54(configPath);
14465
+ const orchestrationSchemaMissing = !existsSync54(orchestrationPath);
14419
14466
  const knownSet = new Set(knownModelIds);
14420
14467
  const snapshotEmpty = knownModelIds.length === 0;
14421
14468
  const snapshotStale = isSnapshotStale(snapshotFetchedAt, now);
@@ -14486,7 +14533,7 @@ function auditDeclaredModelIds(repoRoot, options = {}) {
14486
14533
  function discoverPluginDirs(pluginsRoot) {
14487
14534
  return listDirs(pluginsRoot).filter((name) => {
14488
14535
  try {
14489
- return statSync16(join61(pluginsRoot, name, "biffo.plugin.json")).isFile();
14536
+ return statSync16(join64(pluginsRoot, name, "biffo.plugin.json")).isFile();
14490
14537
  } catch {
14491
14538
  return false;
14492
14539
  }
@@ -14499,8 +14546,8 @@ function auditPluginToolSupply(pluginsRoot) {
14499
14546
  let terraformBlind = false;
14500
14547
  let totalDeclaredTools = 0;
14501
14548
  for (const name of pluginNames) {
14502
- const pluginDir2 = join61(pluginsRoot, name);
14503
- const manifestText = readFileSync42(join61(pluginDir2, "biffo.plugin.json"), "utf8");
14549
+ const pluginDir2 = join64(pluginsRoot, name);
14550
+ const manifestText = readFileSync42(join64(pluginDir2, "biffo.plugin.json"), "utf8");
14504
14551
  const manifest = extractManifestTools(manifestText);
14505
14552
  if (manifest.parseError) {
14506
14553
  findings.push({
@@ -14598,7 +14645,7 @@ function auditPluginToolSupply(pluginsRoot) {
14598
14645
  requiredEnvVars: envResult.envVars,
14599
14646
  missingEnvVars: anyWired ? [] : envResult.envVars,
14600
14647
  status: anyWired ? "ok" : "missing-env",
14601
- 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 ${join61(pluginDir2, "terraform")}, so this deployment can never supply it`
14648
+ 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`
14602
14649
  });
14603
14650
  }
14604
14651
  }
@@ -14631,8 +14678,8 @@ function auditPluginToolSupply(pluginsRoot) {
14631
14678
  async function runPluginToolSupplyCheck() {
14632
14679
  const root = (await execa("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
14633
14680
  let allOk = true;
14634
- const pluginsRoot = join62(root, "services", "_plugins");
14635
- if (!existsSync53(pluginsRoot)) {
14681
+ const pluginsRoot = join65(root, "services", "_plugins");
14682
+ if (!existsSync55(pluginsRoot)) {
14636
14683
  console.log("\u2713 plugin tool-supply guard: no services/_plugins/ \u2014 nothing to audit");
14637
14684
  } else {
14638
14685
  const report = auditPluginToolSupply(pluginsRoot);
@@ -14662,8 +14709,8 @@ async function runPluginToolSupplyCheck() {
14662
14709
  console.log(`\u2713 plugin tool-supply guard: ${report.summary}`);
14663
14710
  }
14664
14711
  }
14665
- const servicesApiRoot = join62(root, "services", "api");
14666
- if (!existsSync53(servicesApiRoot)) {
14712
+ const servicesApiRoot = join65(root, "services", "api");
14713
+ if (!existsSync55(servicesApiRoot)) {
14667
14714
  console.log("\u2713 plugin model-id guard: no services/api/ \u2014 nothing to audit");
14668
14715
  } else {
14669
14716
  const modelReport = auditDeclaredModelIds(root);
@@ -15040,12 +15087,12 @@ async function runSharedFileReductionCheck(args) {
15040
15087
  }
15041
15088
 
15042
15089
  // src/scripts/check-skeleton-drift.ts
15043
- import { existsSync as existsSync54, readdirSync as readdirSync28 } from "fs";
15044
- import { join as join64 } from "path";
15090
+ import { existsSync as existsSync56, readdirSync as readdirSync28 } from "fs";
15091
+ import { join as join67 } from "path";
15045
15092
 
15046
15093
  // src/lib/skeleton-drift-guard.ts
15047
15094
  import { readFileSync as readFileSync45, readdirSync as readdirSync27, statSync as statSync17 } from "fs";
15048
- import { join as join63 } from "path";
15095
+ import { join as join66 } from "path";
15049
15096
  var isWorkflow = (rel) => rel.startsWith(".github/workflows/") && (rel.endsWith(".yml") || rel.endsWith(".yaml"));
15050
15097
  var isRootLayout = (rel) => rel.endsWith("src/app/layout.tsx");
15051
15098
  var uncommented = (contents) => contents.split("\n").filter((line) => !/^\s*(\/\/|\/\*|\*)/.test(line)).join("\n");
@@ -15109,7 +15156,7 @@ function walk(dir, base = dir) {
15109
15156
  }
15110
15157
  for (const entry of entries) {
15111
15158
  if (entry === ".venv" || entry === "node_modules" || entry === ".git") continue;
15112
- const abs = join63(dir, entry);
15159
+ const abs = join66(dir, entry);
15113
15160
  let isDir;
15114
15161
  try {
15115
15162
  isDir = statSync17(abs).isDirectory();
@@ -15131,7 +15178,7 @@ function auditSkeleton(skeletonRoot, name, rules = SKELETON_RULES) {
15131
15178
  if (!rule.appliesTo(rel)) continue;
15132
15179
  let contents;
15133
15180
  try {
15134
- contents = readFileSync45(join63(skeletonRoot, rel), "utf8");
15181
+ contents = readFileSync45(join66(skeletonRoot, rel), "utf8");
15135
15182
  } catch {
15136
15183
  continue;
15137
15184
  }
@@ -15160,23 +15207,23 @@ function formatViolations2(violations) {
15160
15207
 
15161
15208
  // src/scripts/check-skeleton-drift.ts
15162
15209
  function discoverSkeletons(root) {
15163
- const skeletonsDir = join64(root, "_skeletons");
15210
+ const skeletonsDir = join67(root, "_skeletons");
15164
15211
  let entries;
15165
15212
  try {
15166
15213
  entries = readdirSync28(skeletonsDir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
15167
15214
  } catch {
15168
15215
  return [];
15169
15216
  }
15170
- return entries.filter((name) => existsSync54(join64(skeletonsDir, name, ".github", "workflows", "ci.yml"))).sort();
15217
+ return entries.filter((name) => existsSync56(join67(skeletonsDir, name, ".github", "workflows", "ci.yml"))).sort();
15171
15218
  }
15172
15219
  async function runSkeletonDriftCheck() {
15173
15220
  const root = (await execa("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
15174
15221
  const skeletons = discoverSkeletons(root);
15175
15222
  let filesConsidered = 0;
15176
15223
  for (const name of skeletons) {
15177
- const skeletonRoot = join64(root, "_skeletons", name);
15224
+ const skeletonRoot = join67(root, "_skeletons", name);
15178
15225
  filesConsidered += findWorkflowFiles(skeletonRoot).length;
15179
- if (existsSync54(join64(skeletonRoot, "apps", "frontend", "src", "app", "layout.tsx"))) {
15226
+ if (existsSync56(join67(skeletonRoot, "apps", "frontend", "src", "app", "layout.tsx"))) {
15180
15227
  filesConsidered += 1;
15181
15228
  }
15182
15229
  }
@@ -15184,13 +15231,19 @@ async function runSkeletonDriftCheck() {
15184
15231
  `audited ${skeletons.length} skeleton(s) (${skeletons.join(", ") || "none"}), ${filesConsidered} file(s) considered, under ${root}/_skeletons`
15185
15232
  );
15186
15233
  if (skeletons.length === 0) {
15234
+ if (!existsSync56(join67(root, "_skeletons"))) {
15235
+ console.log(
15236
+ `\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.`
15237
+ );
15238
+ return;
15239
+ }
15187
15240
  console.error(
15188
15241
  "\u2717 Skeleton-drift guard: found 0 repo skeletons under _skeletons/ \u2014 this looks like a broken scan, not a repo with no scaffolding. Refusing to report success over zero input."
15189
15242
  );
15190
15243
  process.exit(1);
15191
15244
  }
15192
15245
  const violations = skeletons.flatMap(
15193
- (name) => auditSkeleton(join64(root, "_skeletons", name), name)
15246
+ (name) => auditSkeleton(join67(root, "_skeletons", name), name)
15194
15247
  );
15195
15248
  if (violations.length > 0) {
15196
15249
  console.error("\u2717 Skeleton-drift guard: drift found between this repo and its scaffolding\n");
@@ -15386,8 +15439,8 @@ function rawArgsAfter(subcommand) {
15386
15439
  }
15387
15440
 
15388
15441
  // src/commands/doctor.ts
15389
- import { existsSync as existsSync55, readFileSync as readFileSync46 } from "fs";
15390
- import { join as join65, resolve as resolve20 } from "path";
15442
+ import { existsSync as existsSync57, readFileSync as readFileSync46 } from "fs";
15443
+ import { join as join68, resolve as resolve20 } from "path";
15391
15444
  import chalk21 from "chalk";
15392
15445
  import { Command as Command25 } from "commander";
15393
15446
 
@@ -15782,8 +15835,8 @@ async function runDoctorFixBranches(cwd, facts, deps = { git: new GitAdapter(),
15782
15835
  return reapAllBareBranches(cwd, facts.branches, facts.worktrees, facts.currentBranch, deps);
15783
15836
  }
15784
15837
  function readLocalCoreVersion(cwd) {
15785
- const path = join65(cwd, INSTANCE_CORE_FILE);
15786
- if (!existsSync55(path)) return null;
15838
+ const path = join68(cwd, INSTANCE_CORE_FILE);
15839
+ if (!existsSync57(path)) return null;
15787
15840
  try {
15788
15841
  return extractVersionField(readFileSync46(path, "utf8"));
15789
15842
  } catch {
@@ -15805,8 +15858,8 @@ function extractVersionField(contents) {
15805
15858
  return match?.[1] ?? null;
15806
15859
  }
15807
15860
  function readFossil(cwd) {
15808
- const path = join65(cwd, CORE_VERSION_FILE);
15809
- if (!existsSync55(path)) return null;
15861
+ const path = join68(cwd, CORE_VERSION_FILE);
15862
+ if (!existsSync57(path)) return null;
15810
15863
  try {
15811
15864
  const value = readFileSync46(path, "utf8").trim();
15812
15865
  return value === "" ? null : value;
@@ -16337,13 +16390,13 @@ import { fileURLToPath as fileURLToPath6 } from "url";
16337
16390
  import { Command as Command27 } from "commander";
16338
16391
 
16339
16392
  // src/lib/packaged-scripts.ts
16340
- import { existsSync as existsSync56 } from "fs";
16341
- import { dirname as dirname11, join as join66 } from "path";
16393
+ import { existsSync as existsSync58 } from "fs";
16394
+ import { dirname as dirname11, join as join69 } from "path";
16342
16395
  function findPackagedScript(startDir, relativePath) {
16343
16396
  let dir = startDir;
16344
16397
  for (; ; ) {
16345
- const candidate = join66(dir, relativePath);
16346
- if (existsSync56(candidate)) return candidate;
16398
+ const candidate = join69(dir, relativePath);
16399
+ if (existsSync58(candidate)) return candidate;
16347
16400
  const parent = dirname11(dir);
16348
16401
  if (parent === dir) return null;
16349
16402
  dir = parent;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@biffo/cli",
3
- "version": "0.303.2",
3
+ "version": "0.303.3",
4
4
  "description": "Biffo project scaffolding CLI",
5
5
  "license": "MIT",
6
6
  "type": "module",