@biffo/cli 0.305.0 → 0.306.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
@@ -12335,8 +12335,8 @@ async function runOwnershipCheck(argv) {
12335
12335
  const { stdout } = await execa("git", ["diff", "--cached", "--name-status"], { cwd: root });
12336
12336
  ({ changed: changedFiles, deleted: deletedFiles } = parseNameStatus(stdout));
12337
12337
  if (messageFile) {
12338
- const { readFileSync: readFileSync47, existsSync: existsSync59 } = await import("fs");
12339
- if (existsSync59(messageFile)) commitMessage = readFileSync47(messageFile, "utf8");
12338
+ const { readFileSync: readFileSync48, existsSync: existsSync59 } = await import("fs");
12339
+ if (existsSync59(messageFile)) commitMessage = readFileSync48(messageFile, "utf8");
12340
12340
  }
12341
12341
  } else {
12342
12342
  const base = process.env["GITHUB_BASE_REF"] ?? args[0];
@@ -13396,9 +13396,244 @@ baseline was ${String(ratchet.baseline)}, now ${String(ratchet.count)}. See biff
13396
13396
  }
13397
13397
  }
13398
13398
 
13399
+ // src/lib/ownership-header-claim-guard.ts
13400
+ import { readFileSync as readFileSync39 } from "fs";
13401
+ import { join as join58 } from "path";
13402
+ var OWNERSHIP_HEADER_SWEEP_DIRS = [
13403
+ "scripts",
13404
+ ".githooks",
13405
+ ".github",
13406
+ "services",
13407
+ "cli",
13408
+ "infra"
13409
+ ];
13410
+ var STRICT_MARKER = /(?<!`)(?:INSTANCE-OWNED|NOT a template file)(?!`)/;
13411
+ var SELF_REFERENTIAL_CLAIM = /\b(?:[Tt]his|[Ii]t)\b(?:\s+\S+){0,3}\s+(?:is|are|stays|remains)\s+(?:\*\*)?(template-owned|user-owned)\b/;
13412
+ var EM_DASH_FIRST_LINE_CLAIM = /[—–]\s*(template-owned|user-owned)\b/;
13413
+ var MAX_HEADER_LINES = 10;
13414
+ function claimFor(matchedPhrase) {
13415
+ return /^template-owned$/i.test(matchedPhrase) ? "template" : "user";
13416
+ }
13417
+ function claimInText(text) {
13418
+ const candidates = [];
13419
+ const strict = STRICT_MARKER.exec(text);
13420
+ if (strict)
13421
+ candidates.push({ matchedPhrase: strict[0], claim: claimFor(strict[0]), index: strict.index });
13422
+ const grammatical = SELF_REFERENTIAL_CLAIM.exec(text);
13423
+ if (grammatical) {
13424
+ const phrase = grammatical[1];
13425
+ candidates.push({ matchedPhrase: phrase, claim: claimFor(phrase), index: grammatical.index });
13426
+ }
13427
+ const firstLine = text.split("\n", 1)[0] ?? "";
13428
+ const emDash = EM_DASH_FIRST_LINE_CLAIM.exec(firstLine);
13429
+ if (emDash) {
13430
+ const phrase = emDash[1];
13431
+ candidates.push({ matchedPhrase: phrase, claim: claimFor(phrase), index: emDash.index });
13432
+ }
13433
+ if (candidates.length === 0) return null;
13434
+ candidates.sort((a, b) => a.index - b.index);
13435
+ return candidates[0] ?? null;
13436
+ }
13437
+ function fileExtension(path) {
13438
+ const dot = path.lastIndexOf(".");
13439
+ const slash = path.lastIndexOf("/");
13440
+ return dot > slash ? path.slice(dot).toLowerCase() : "";
13441
+ }
13442
+ function isCommentLine(line) {
13443
+ return line.trim().startsWith("#");
13444
+ }
13445
+ function lineAt(lines, i) {
13446
+ return lines[i] ?? "";
13447
+ }
13448
+ function leadingHashCommentEnd(lines, start) {
13449
+ let i = start;
13450
+ while (i < lines.length) {
13451
+ if (isCommentLine(lineAt(lines, i))) {
13452
+ i++;
13453
+ continue;
13454
+ }
13455
+ if (lineAt(lines, i).trim() === "") {
13456
+ let j = i + 1;
13457
+ while (j < lines.length && lineAt(lines, j).trim() === "") j++;
13458
+ if (j < lines.length && isCommentLine(lineAt(lines, j))) {
13459
+ i = j;
13460
+ continue;
13461
+ }
13462
+ return i;
13463
+ }
13464
+ return i;
13465
+ }
13466
+ return i;
13467
+ }
13468
+ function defaultHeaderRange(lines) {
13469
+ const start = lineAt(lines, 0).startsWith("#!") ? 1 : 0;
13470
+ const end = leadingHashCommentEnd(lines, start);
13471
+ return end > start ? [start, end] : null;
13472
+ }
13473
+ function pythonHeaderRange(lines) {
13474
+ let i = lineAt(lines, 0).startsWith("#!") ? 1 : 0;
13475
+ while (i < lines.length && lineAt(lines, i).trim() === "") i++;
13476
+ if (i >= lines.length) return null;
13477
+ const first = lineAt(lines, i);
13478
+ const trimmed = first.trimStart();
13479
+ const quote = trimmed.startsWith('"""') ? '"""' : trimmed.startsWith("'''") ? "'''" : null;
13480
+ if (quote) {
13481
+ const afterOpen = first.slice(first.indexOf(quote) + 3);
13482
+ if (afterOpen.includes(quote)) return [i, i + 1];
13483
+ let j = i + 1;
13484
+ while (j < lines.length && !lineAt(lines, j).includes(quote)) j++;
13485
+ return [i, Math.min(j + 1, lines.length)];
13486
+ }
13487
+ const end = leadingHashCommentEnd(lines, i);
13488
+ return end > i ? [i, end] : null;
13489
+ }
13490
+ function jsHeaderRange(lines) {
13491
+ let i = 0;
13492
+ while (i < lines.length && (lineAt(lines, i).trim() === "" || lineAt(lines, i).trim().startsWith("import "))) {
13493
+ i++;
13494
+ }
13495
+ if (i >= lines.length) return null;
13496
+ const first = lineAt(lines, i).trim();
13497
+ if (first.startsWith("/*")) {
13498
+ let j = i;
13499
+ while (j < lines.length && !lineAt(lines, j).includes("*/")) j++;
13500
+ return [i, Math.min(j + 1, lines.length)];
13501
+ }
13502
+ if (first.startsWith("//")) {
13503
+ let j = i;
13504
+ while (j < lines.length && (lineAt(lines, j).trim().startsWith("//") || lineAt(lines, j).trim() === ""))
13505
+ j++;
13506
+ return [i, j];
13507
+ }
13508
+ return null;
13509
+ }
13510
+ function headerRange(path, lines) {
13511
+ const ext = fileExtension(path);
13512
+ let range;
13513
+ if (ext === ".py") range = pythonHeaderRange(lines);
13514
+ else if (ext === ".ts" || ext === ".tsx" || ext === ".js" || ext === ".mjs")
13515
+ range = jsHeaderRange(lines);
13516
+ else if (ext === ".md")
13517
+ range = [0, Math.min(15, lines.length)];
13518
+ else if (ext === ".json")
13519
+ return null;
13520
+ else range = defaultHeaderRange(lines);
13521
+ if (!range) return null;
13522
+ const [start, end] = range;
13523
+ return [start, Math.min(end, start + MAX_HEADER_LINES)];
13524
+ }
13525
+ function findJsonDescriptionClaim(path, content) {
13526
+ let data;
13527
+ try {
13528
+ data = JSON.parse(content);
13529
+ } catch {
13530
+ return null;
13531
+ }
13532
+ if (typeof data !== "object" || data === null) return null;
13533
+ const description = data["description"];
13534
+ if (typeof description !== "string") return null;
13535
+ const match = /INSTANCE-OWNED|NOT a template file|user-owned|template-owned/i.exec(description);
13536
+ if (!match) return null;
13537
+ const lineIndex = content.split("\n").findIndex((l) => l.includes('"description"'));
13538
+ return {
13539
+ path,
13540
+ claim: claimFor(match[0]),
13541
+ matchedPhrase: match[0],
13542
+ line: lineIndex === -1 ? 1 : lineIndex + 1
13543
+ };
13544
+ }
13545
+ function findHeaderClaim(path, content) {
13546
+ if (fileExtension(path) === ".json") return findJsonDescriptionClaim(path, content);
13547
+ const lines = content.split("\n");
13548
+ const range = headerRange(path, lines);
13549
+ if (!range) return null;
13550
+ const [start, end] = range;
13551
+ const windowText = lines.slice(start, end).join("\n");
13552
+ const found = claimInText(windowText);
13553
+ if (!found) return null;
13554
+ const line = start + windowText.slice(0, found.index).split("\n").length;
13555
+ return { path, claim: found.claim, matchedPhrase: found.matchedPhrase, line };
13556
+ }
13557
+ function sweepOwnershipHeaderClaims(root, options = {}) {
13558
+ const tracked = options.git ? gitTrackedFiles(root, options.git) : gitTrackedFiles(root);
13559
+ if (!tracked) return [];
13560
+ const files = [...tracked].filter((p) => OWNERSHIP_HEADER_SWEEP_DIRS.some((dir) => p === dir || p.startsWith(`${dir}/`))).sort();
13561
+ const hits = [];
13562
+ for (const rel of files) {
13563
+ let content;
13564
+ try {
13565
+ content = readFileSync39(join58(root, rel), "utf8");
13566
+ } catch {
13567
+ continue;
13568
+ }
13569
+ const hit = findHeaderClaim(rel, content);
13570
+ if (hit) hits.push(hit);
13571
+ }
13572
+ return hits;
13573
+ }
13574
+ function matchesReleased(relPath, manifest) {
13575
+ return (manifest.released ?? []).some((p) => relPath === p || relPath.startsWith(p));
13576
+ }
13577
+ function checkOwnershipHeaderClaims(hits, manifest) {
13578
+ const out = [];
13579
+ for (const hit of hits) {
13580
+ const manifestSaysTemplateOwned = isTemplateOwned(hit.path, manifest);
13581
+ const released = matchesReleased(hit.path, manifest);
13582
+ const agrees = hit.claim === "template" ? manifestSaysTemplateOwned || released : !manifestSaysTemplateOwned && !released;
13583
+ if (!agrees) {
13584
+ out.push({ ...hit, manifestSaysTemplateOwned });
13585
+ }
13586
+ }
13587
+ return out;
13588
+ }
13589
+
13590
+ // src/scripts/check-ownership-header-claim.ts
13591
+ async function runOwnershipHeaderClaimCheck() {
13592
+ const root = (await execa("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
13593
+ const ownership = classifyRepoOwnership(root);
13594
+ if (ownership === "satellite") {
13595
+ console.log(
13596
+ "\u2713 ownership-header-claim guard: skipped \u2014 this repo carries no core-manifest.json, so there is no ownership authority to check a header claim against."
13597
+ );
13598
+ return;
13599
+ }
13600
+ const manifest = readCoreManifest(root);
13601
+ const hits = sweepOwnershipHeaderClaims(root);
13602
+ console.log(
13603
+ `examined ${hits.length} file(s) carrying an ownership-style header claim under scripts/, .githooks/, .github/, services/, cli/, infra/`
13604
+ );
13605
+ if (hits.length === 0) {
13606
+ console.error(
13607
+ "\u2717 ownership-header-claim guard: swept zero files \u2014 refusing a false green rather than assuming every ownership-style header vanished."
13608
+ );
13609
+ process.exit(1);
13610
+ return;
13611
+ }
13612
+ const disagreements = checkOwnershipHeaderClaims(hits, manifest);
13613
+ if (disagreements.length > 0) {
13614
+ console.error(
13615
+ `\u2717 ownership-header-claim guard: ${disagreements.length} of ${hits.length} file(s) carry a header claim core-manifest.json disagrees with (#1911):
13616
+ `
13617
+ );
13618
+ for (const d of disagreements) {
13619
+ console.error(
13620
+ ` ${d.path}:${d.line} header says "${d.matchedPhrase}" (${d.claim}-owned), but core-manifest.json says ${d.manifestSaysTemplateOwned ? "template-owned" : "user-owned"}`
13621
+ );
13622
+ }
13623
+ console.error(
13624
+ "\nEither fix the header to match core-manifest.json, or fix core-manifest.json to match reality \u2014 never leave the two disagreeing."
13625
+ );
13626
+ process.exit(1);
13627
+ return;
13628
+ }
13629
+ console.log(
13630
+ `\u2713 ownership-header-claim guard: examined ${hits.length} file(s), all agree with core-manifest.json`
13631
+ );
13632
+ }
13633
+
13399
13634
  // src/scripts/check-pipe-trap.ts
13400
- import { readFileSync as readFileSync39, readdirSync as readdirSync23 } from "fs";
13401
- import { join as join58, relative as relative9 } from "path";
13635
+ import { readFileSync as readFileSync40, readdirSync as readdirSync23 } from "fs";
13636
+ import { join as join59, relative as relative9 } from "path";
13402
13637
 
13403
13638
  // src/lib/pipe-trap-guard.ts
13404
13639
  var STATUS_BEARING = [
@@ -13494,7 +13729,7 @@ function findPipeTraps(source) {
13494
13729
  function shellFiles(root) {
13495
13730
  const out = [];
13496
13731
  for (const dir of ["scripts", ".githooks"]) {
13497
- const full = join58(root, dir);
13732
+ const full = join59(root, dir);
13498
13733
  let entries;
13499
13734
  try {
13500
13735
  entries = readdirSync23(full, { withFileTypes: true });
@@ -13504,7 +13739,7 @@ function shellFiles(root) {
13504
13739
  for (const entry of entries) {
13505
13740
  if (!entry.isFile()) continue;
13506
13741
  if (dir === "scripts" && !entry.name.endsWith(".sh")) continue;
13507
- out.push(join58(full, entry.name));
13742
+ out.push(join59(full, entry.name));
13508
13743
  }
13509
13744
  }
13510
13745
  return out;
@@ -13520,7 +13755,7 @@ async function runPipeTrapCheck() {
13520
13755
  process.exit(1);
13521
13756
  }
13522
13757
  const findings = files.flatMap(
13523
- (file) => findPipeTraps(readFileSync39(file, "utf8")).map(
13758
+ (file) => findPipeTraps(readFileSync40(file, "utf8")).map(
13524
13759
  (t) => `${relative9(root, file)}:${t.line} ${t.text}
13525
13760
  ${t.reason}`
13526
13761
  )
@@ -13538,11 +13773,11 @@ async function runPipeTrapCheck() {
13538
13773
 
13539
13774
  // src/scripts/check-plugin-allowlist-convention.ts
13540
13775
  import { existsSync as existsSync50 } from "fs";
13541
- import { join as join60 } from "path";
13776
+ import { join as join61 } from "path";
13542
13777
 
13543
13778
  // src/lib/plugin-allowlist-convention.ts
13544
- import { readFileSync as readFileSync40 } from "fs";
13545
- import { join as join59 } from "path";
13779
+ import { readFileSync as readFileSync41 } from "fs";
13780
+ import { join as join60 } from "path";
13546
13781
  var COMPUTE_MAIN_TF = "modules/cloud/aws/compute/main.tf";
13547
13782
  var PLUGIN_TEMPLATE_MAIN_TF = "modules/plugins/_template/main.tf";
13548
13783
  var ALLOWLIST_MAIN_TF = "modules/cloud/aws/plugin-allowlist/main.tf";
@@ -13553,7 +13788,7 @@ var PLUGIN = "<plugin>";
13553
13788
  var ACCOUNT = "<account>";
13554
13789
  function read(repoRoot, relative11) {
13555
13790
  try {
13556
- return readFileSync40(join59(repoRoot, relative11), "utf8");
13791
+ return readFileSync41(join60(repoRoot, relative11), "utf8");
13557
13792
  } catch {
13558
13793
  throw new Error(`plugin-allowlist drift guard: cannot read ${relative11}`);
13559
13794
  }
@@ -13656,7 +13891,7 @@ var REQUIRED_SOURCES = [
13656
13891
  ];
13657
13892
  async function runPluginAllowlistConventionCheck() {
13658
13893
  const root = (await execa("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
13659
- const missing = REQUIRED_SOURCES.filter((relative11) => !existsSync50(join60(root, relative11)));
13894
+ const missing = REQUIRED_SOURCES.filter((relative11) => !existsSync50(join61(root, relative11)));
13660
13895
  if (missing.length === REQUIRED_SOURCES.length) {
13661
13896
  console.log(
13662
13897
  `\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.`
@@ -13688,11 +13923,11 @@ async function runPluginAllowlistConventionCheck() {
13688
13923
 
13689
13924
  // src/scripts/check-plugin-collisions.ts
13690
13925
  import { existsSync as existsSync52 } from "fs";
13691
- import { join as join62 } from "path";
13926
+ import { join as join63 } from "path";
13692
13927
 
13693
13928
  // src/lib/plugin-collision-guard.ts
13694
13929
  import { existsSync as existsSync51, readdirSync as readdirSync24, statSync as statSync15 } from "fs";
13695
- import { join as join61 } from "path";
13930
+ import { join as join62 } from "path";
13696
13931
  var PYTEST_SPECIAL = /* @__PURE__ */ new Set(["conftest.py"]);
13697
13932
  var IGNORED_DIRS = /* @__PURE__ */ new Set([".venv", "node_modules", "__pycache__", ".git", "dist", "build"]);
13698
13933
  function subdirectories(dir) {
@@ -13700,19 +13935,19 @@ function subdirectories(dir) {
13700
13935
  return readdirSync24(dir).filter((entry) => {
13701
13936
  if (IGNORED_DIRS.has(entry) || entry.startsWith(".")) return false;
13702
13937
  try {
13703
- return statSync15(join61(dir, entry)).isDirectory();
13938
+ return statSync15(join62(dir, entry)).isDirectory();
13704
13939
  } catch {
13705
13940
  return false;
13706
13941
  }
13707
13942
  });
13708
13943
  }
13709
13944
  function regularPackagesOf(pluginDir2) {
13710
- return subdirectories(pluginDir2).filter((name) => existsSync51(join61(pluginDir2, name, "__init__.py"))).sort();
13945
+ return subdirectories(pluginDir2).filter((name) => existsSync51(join62(pluginDir2, name, "__init__.py"))).sort();
13711
13946
  }
13712
13947
  function bareTestModulesOf(pluginDir2) {
13713
- const testsDir = join61(pluginDir2, "tests");
13948
+ const testsDir = join62(pluginDir2, "tests");
13714
13949
  if (!existsSync51(testsDir)) return [];
13715
- if (existsSync51(join61(testsDir, "__init__.py"))) return [];
13950
+ if (existsSync51(join62(testsDir, "__init__.py"))) return [];
13716
13951
  return readdirSync24(testsDir).filter((f) => f.endsWith(".py") && !PYTEST_SPECIAL.has(f)).sort();
13717
13952
  }
13718
13953
  function findCollisions(servicesDir, pluginDirs) {
@@ -13721,7 +13956,7 @@ function findCollisions(servicesDir, pluginDirs) {
13721
13956
  const gather = (kind, namesOf) => {
13722
13957
  const claims = /* @__PURE__ */ new Map();
13723
13958
  for (const plugin of plugins) {
13724
- for (const name of namesOf(join61(servicesDir, plugin))) {
13959
+ for (const name of namesOf(join62(servicesDir, plugin))) {
13725
13960
  claims.set(name, [...claims.get(name) ?? [], plugin]);
13726
13961
  }
13727
13962
  }
@@ -13759,7 +13994,7 @@ function formatCollisions(collisions) {
13759
13994
  // src/scripts/check-plugin-collisions.ts
13760
13995
  async function runPluginCollisionCheck() {
13761
13996
  const root = (await execa("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
13762
- const servicesDir = join62(root, "services");
13997
+ const servicesDir = join63(root, "services");
13763
13998
  if (!existsSync52(servicesDir)) {
13764
13999
  console.log("\u2713 plugin collision guard: no services/ directory \u2014 nothing to compare");
13765
14000
  return;
@@ -13777,8 +14012,8 @@ async function runPluginCollisionCheck() {
13777
14012
  }
13778
14013
 
13779
14014
  // src/lib/plugin-terraform-guard.ts
13780
- import { existsSync as existsSync53, readFileSync as readFileSync41, readdirSync as readdirSync25 } from "fs";
13781
- import { dirname as dirname10, join as join63, relative as relative10, sep as sep4 } from "path";
14015
+ import { existsSync as existsSync53, readFileSync as readFileSync42, readdirSync as readdirSync25 } from "fs";
14016
+ import { dirname as dirname10, join as join64, relative as relative10, sep as sep4 } from "path";
13782
14017
  var SKIP_DIRS4 = /* @__PURE__ */ new Set(["node_modules", ".git", ".worktrees", "dist", ".venv", "__pycache__"]);
13783
14018
  var PLUGIN_MANIFEST_FILE2 = "biffo.plugin.json";
13784
14019
  function findPluginManifests(root) {
@@ -13793,9 +14028,9 @@ function findPluginManifests(root) {
13793
14028
  for (const entry of entries) {
13794
14029
  if (entry.isDirectory()) {
13795
14030
  if (SKIP_DIRS4.has(entry.name)) continue;
13796
- walk2(join63(dir, entry.name));
14031
+ walk2(join64(dir, entry.name));
13797
14032
  } else if (entry.isFile() && entry.name === PLUGIN_MANIFEST_FILE2) {
13798
- found.push(relative10(root, join63(dir, entry.name)).split(sep4).join("/"));
14033
+ found.push(relative10(root, join64(dir, entry.name)).split(sep4).join("/"));
13799
14034
  }
13800
14035
  }
13801
14036
  };
@@ -13805,7 +14040,7 @@ function findPluginManifests(root) {
13805
14040
  function readSubscriptions(absManifestPath) {
13806
14041
  let parsed;
13807
14042
  try {
13808
- parsed = JSON.parse(readFileSync41(absManifestPath, "utf8"));
14043
+ parsed = JSON.parse(readFileSync42(absManifestPath, "utf8"));
13809
14044
  } catch {
13810
14045
  return null;
13811
14046
  }
@@ -13820,14 +14055,14 @@ function readSubscriptions(absManifestPath) {
13820
14055
  }
13821
14056
  function checkPluginTerraform(root) {
13822
14057
  const violations = [];
13823
- const coreManifest = existsSync53(join63(root, CORE_MANIFEST_FILE)) ? readCoreManifest(root) : null;
14058
+ const coreManifest = existsSync53(join64(root, CORE_MANIFEST_FILE)) ? readCoreManifest(root) : null;
13824
14059
  for (const manifest of findPluginManifests(root)) {
13825
14060
  if (coreManifest && !isTemplateOwned(manifest, coreManifest)) continue;
13826
- const absManifest = join63(root, manifest);
14061
+ const absManifest = join64(root, manifest);
13827
14062
  const subscriptions = readSubscriptions(absManifest);
13828
14063
  if (subscriptions === null) continue;
13829
14064
  const pluginDir2 = dirname10(absManifest);
13830
- if (existsSync53(join63(pluginDir2, "terraform"))) continue;
14065
+ if (existsSync53(join64(pluginDir2, "terraform"))) continue;
13831
14066
  const relPluginDir = relative10(root, pluginDir2).split(sep4).join("/");
13832
14067
  violations.push({
13833
14068
  manifest,
@@ -13859,11 +14094,11 @@ async function runPluginTerraformCheck() {
13859
14094
 
13860
14095
  // src/scripts/check-plugin-tool-supply.ts
13861
14096
  import { existsSync as existsSync55 } from "fs";
13862
- import { join as join65 } from "path";
14097
+ import { join as join66 } from "path";
13863
14098
 
13864
14099
  // src/lib/plugin-tool-supply-audit.ts
13865
- import { existsSync as existsSync54, readFileSync as readFileSync42, readdirSync as readdirSync26, statSync as statSync16 } from "fs";
13866
- import { join as join64 } from "path";
14100
+ import { existsSync as existsSync54, readFileSync as readFileSync43, readdirSync as readdirSync26, statSync as statSync16 } from "fs";
14101
+ import { join as join65 } from "path";
13867
14102
 
13868
14103
  // src/lib/openrouter-model-snapshot.ts
13869
14104
  var OPENROUTER_MODEL_SNAPSHOT_FETCHED_AT = "2026-08-10T06:39:01Z";
@@ -14280,7 +14515,7 @@ function listDirs(root) {
14280
14515
  }
14281
14516
  return entries.filter((e) => {
14282
14517
  try {
14283
- return statSync16(join64(root, e)).isDirectory();
14518
+ return statSync16(join65(root, e)).isDirectory();
14284
14519
  } catch {
14285
14520
  return false;
14286
14521
  }
@@ -14296,7 +14531,7 @@ function walkFiles2(root, accept, skipDir) {
14296
14531
  return;
14297
14532
  }
14298
14533
  for (const entry of entries) {
14299
- const p = join64(dir, entry);
14534
+ const p = join65(dir, entry);
14300
14535
  let st;
14301
14536
  try {
14302
14537
  st = statSync16(p);
@@ -14322,14 +14557,14 @@ function pluginPythonFiles(pluginDir2) {
14322
14557
  );
14323
14558
  }
14324
14559
  function pluginTerraformFiles(pluginDir2) {
14325
- const tfDir = join64(pluginDir2, "terraform");
14560
+ const tfDir = join65(pluginDir2, "terraform");
14326
14561
  let entries;
14327
14562
  try {
14328
14563
  entries = readdirSync26(tfDir);
14329
14564
  } catch {
14330
14565
  return [];
14331
14566
  }
14332
- return entries.filter((e) => e.endsWith(".tf")).map((e) => join64(tfDir, e)).sort();
14567
+ return entries.filter((e) => e.endsWith(".tf")).map((e) => join65(tfDir, e)).sort();
14333
14568
  }
14334
14569
  function extractManifestTools(manifestText) {
14335
14570
  let parsed;
@@ -14581,8 +14816,8 @@ function isSnapshotStale(fetchedAt, now) {
14581
14816
  function normalizeModelId(id) {
14582
14817
  return id.endsWith(":online") ? id.slice(0, -":online".length) : id;
14583
14818
  }
14584
- var CONFIG_PY_PATH = join64("services", "api", "src", "api", "config.py");
14585
- var ORCHESTRATION_SCHEMA_PATH = join64(
14819
+ var CONFIG_PY_PATH = join65("services", "api", "src", "api", "config.py");
14820
+ var ORCHESTRATION_SCHEMA_PATH = join65(
14586
14821
  "services",
14587
14822
  "api",
14588
14823
  "src",
@@ -14594,8 +14829,8 @@ function auditDeclaredModelIds(repoRoot, options = {}) {
14594
14829
  const knownModelIds = options.knownModelIds ?? OPENROUTER_MODEL_IDS;
14595
14830
  const snapshotFetchedAt = options.snapshotFetchedAt ?? OPENROUTER_MODEL_SNAPSHOT_FETCHED_AT;
14596
14831
  const now = options.now ?? /* @__PURE__ */ new Date();
14597
- const configPath = join64(repoRoot, CONFIG_PY_PATH);
14598
- const orchestrationPath = join64(repoRoot, ORCHESTRATION_SCHEMA_PATH);
14832
+ const configPath = join65(repoRoot, CONFIG_PY_PATH);
14833
+ const orchestrationPath = join65(repoRoot, ORCHESTRATION_SCHEMA_PATH);
14599
14834
  const configMissing = !existsSync54(configPath);
14600
14835
  const orchestrationSchemaMissing = !existsSync54(orchestrationPath);
14601
14836
  const knownSet = new Set(knownModelIds);
@@ -14615,13 +14850,13 @@ function auditDeclaredModelIds(repoRoot, options = {}) {
14615
14850
  };
14616
14851
  let settingsBlind = false;
14617
14852
  if (!configMissing) {
14618
- const settingsFields = extractSettingsModelFields(readFileSync42(configPath, "utf8"));
14853
+ const settingsFields = extractSettingsModelFields(readFileSync43(configPath, "utf8"));
14619
14854
  if (settingsFields.length === 0) settingsBlind = true;
14620
14855
  for (const { field, value } of settingsFields) record(`${CONFIG_PY_PATH}#${field}`, value);
14621
14856
  }
14622
14857
  let curatedFieldsBlind = false;
14623
14858
  if (!orchestrationSchemaMissing) {
14624
- const curated = extractCuratedModelFields(readFileSync42(orchestrationPath, "utf8"));
14859
+ const curated = extractCuratedModelFields(readFileSync43(orchestrationPath, "utf8"));
14625
14860
  if (curated.rawFieldCount > 0 && curated.fields.every((f) => f.defaultValue === null && f.optionValues.length === 0)) {
14626
14861
  curatedFieldsBlind = true;
14627
14862
  }
@@ -14668,7 +14903,7 @@ function auditDeclaredModelIds(repoRoot, options = {}) {
14668
14903
  function discoverPluginDirs(pluginsRoot) {
14669
14904
  return listDirs(pluginsRoot).filter((name) => {
14670
14905
  try {
14671
- return statSync16(join64(pluginsRoot, name, "biffo.plugin.json")).isFile();
14906
+ return statSync16(join65(pluginsRoot, name, "biffo.plugin.json")).isFile();
14672
14907
  } catch {
14673
14908
  return false;
14674
14909
  }
@@ -14681,8 +14916,8 @@ function auditPluginToolSupply(pluginsRoot) {
14681
14916
  let terraformBlind = false;
14682
14917
  let totalDeclaredTools = 0;
14683
14918
  for (const name of pluginNames) {
14684
- const pluginDir2 = join64(pluginsRoot, name);
14685
- const manifestText = readFileSync42(join64(pluginDir2, "biffo.plugin.json"), "utf8");
14919
+ const pluginDir2 = join65(pluginsRoot, name);
14920
+ const manifestText = readFileSync43(join65(pluginDir2, "biffo.plugin.json"), "utf8");
14686
14921
  const manifest = extractManifestTools(manifestText);
14687
14922
  if (manifest.parseError) {
14688
14923
  findings.push({
@@ -14700,13 +14935,13 @@ function auditPluginToolSupply(pluginsRoot) {
14700
14935
  totalDeclaredTools += manifest.tools.length;
14701
14936
  const pySources = pluginPythonFiles(pluginDir2).map((f) => ({
14702
14937
  file: f,
14703
- text: readFileSync42(f, "utf8")
14938
+ text: readFileSync43(f, "utf8")
14704
14939
  }));
14705
14940
  const resolver = buildSymbolResolver(pySources);
14706
14941
  const registry = extractToolRegistryEntries(pySources, resolver);
14707
14942
  if (registry.rawToolDefinitionCount > 0 && registry.entries.length === 0) registryBlind = true;
14708
14943
  const tfFiles = pluginTerraformFiles(pluginDir2);
14709
- const tfText = tfFiles.map((f) => readFileSync42(f, "utf8")).join("\n");
14944
+ const tfText = tfFiles.map((f) => readFileSync43(f, "utf8")).join("\n");
14710
14945
  const terraform = extractTerraformEnvKeys(tfText);
14711
14946
  if (terraform.rawMarkerCount > 0 && terraform.resolvedBlockCount === 0) terraformBlind = true;
14712
14947
  for (const toolName of manifest.tools) {
@@ -14780,7 +15015,7 @@ function auditPluginToolSupply(pluginsRoot) {
14780
15015
  requiredEnvVars: envResult.envVars,
14781
15016
  missingEnvVars: anyWired ? [] : envResult.envVars,
14782
15017
  status: anyWired ? "ok" : "missing-env",
14783
- 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`
15018
+ 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`
14784
15019
  });
14785
15020
  }
14786
15021
  }
@@ -14813,7 +15048,7 @@ function auditPluginToolSupply(pluginsRoot) {
14813
15048
  async function runPluginToolSupplyCheck() {
14814
15049
  const root = (await execa("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
14815
15050
  let allOk = true;
14816
- const pluginsRoot = join65(root, "services", "_plugins");
15051
+ const pluginsRoot = join66(root, "services", "_plugins");
14817
15052
  if (!existsSync55(pluginsRoot)) {
14818
15053
  console.log("\u2713 plugin tool-supply guard: no services/_plugins/ \u2014 nothing to audit");
14819
15054
  } else {
@@ -14844,7 +15079,7 @@ async function runPluginToolSupplyCheck() {
14844
15079
  console.log(`\u2713 plugin tool-supply guard: ${report.summary}`);
14845
15080
  }
14846
15081
  }
14847
- const servicesApiRoot = join65(root, "services", "api");
15082
+ const servicesApiRoot = join66(root, "services", "api");
14848
15083
  if (!existsSync55(servicesApiRoot)) {
14849
15084
  console.log("\u2713 plugin model-id guard: no services/api/ \u2014 nothing to audit");
14850
15085
  } else {
@@ -15019,10 +15254,10 @@ async function runReleaseSubjectCheck(argv) {
15019
15254
  }
15020
15255
 
15021
15256
  // src/scripts/check-shared-file-reduction.ts
15022
- import { readFileSync as readFileSync44 } from "fs";
15257
+ import { readFileSync as readFileSync45 } from "fs";
15023
15258
 
15024
15259
  // src/lib/shared-file-reduction-guard.ts
15025
- import { readFileSync as readFileSync43 } from "fs";
15260
+ import { readFileSync as readFileSync44 } from "fs";
15026
15261
  var LEAF_TEST_CALLS = /* @__PURE__ */ new Set(["it", "test"]);
15027
15262
  var SUITE_CALLS = /* @__PURE__ */ new Set(["describe", "suite"]);
15028
15263
  var TEST_FILE_PATTERN = /\.(test|spec)\.(ts|tsx|mts|cts|js|jsx|mjs|cjs)$/;
@@ -15149,7 +15384,7 @@ function formatReductionReport(report) {
15149
15384
  // src/scripts/check-shared-file-reduction.ts
15150
15385
  function readStdin() {
15151
15386
  try {
15152
- return readFileSync44(0, "utf8");
15387
+ return readFileSync45(0, "utf8");
15153
15388
  } catch {
15154
15389
  return "";
15155
15390
  }
@@ -15166,15 +15401,15 @@ function pairsFromTsv(tsv) {
15166
15401
  const [target, existingPath, incomingPath] = fields;
15167
15402
  pairs.push({
15168
15403
  target,
15169
- existing: readFileSync44(existingPath, "utf8"),
15170
- incoming: readFileSync44(incomingPath, "utf8")
15404
+ existing: readFileSync45(existingPath, "utf8"),
15405
+ incoming: readFileSync45(incomingPath, "utf8")
15171
15406
  });
15172
15407
  }
15173
15408
  return pairs;
15174
15409
  }
15175
15410
  function loadAccepted(manifestPath) {
15176
15411
  if (!manifestPath) return {};
15177
- const parsed = JSON.parse(readFileSync44(manifestPath, "utf8"));
15412
+ const parsed = JSON.parse(readFileSync45(manifestPath, "utf8"));
15178
15413
  return parsed.acceptedReductions ?? {};
15179
15414
  }
15180
15415
  async function runSharedFileReductionCheck(args) {
@@ -15182,13 +15417,13 @@ async function runSharedFileReductionCheck(args) {
15182
15417
  let accepted;
15183
15418
  try {
15184
15419
  if (args.pairs) {
15185
- pairs = pairsFromTsv(args.pairs === "-" ? readStdin() : readFileSync44(args.pairs, "utf8"));
15420
+ pairs = pairsFromTsv(args.pairs === "-" ? readStdin() : readFileSync45(args.pairs, "utf8"));
15186
15421
  } else if (args.target && args.existing && args.incoming) {
15187
15422
  pairs = [
15188
15423
  {
15189
15424
  target: args.target,
15190
- existing: readFileSync44(args.existing, "utf8"),
15191
- incoming: readFileSync44(args.incoming, "utf8")
15425
+ existing: readFileSync45(args.existing, "utf8"),
15426
+ incoming: readFileSync45(args.incoming, "utf8")
15192
15427
  }
15193
15428
  ];
15194
15429
  } else {
@@ -15223,11 +15458,11 @@ async function runSharedFileReductionCheck(args) {
15223
15458
 
15224
15459
  // src/scripts/check-skeleton-drift.ts
15225
15460
  import { existsSync as existsSync56, readdirSync as readdirSync28 } from "fs";
15226
- import { join as join67 } from "path";
15461
+ import { join as join68 } from "path";
15227
15462
 
15228
15463
  // src/lib/skeleton-drift-guard.ts
15229
- import { readFileSync as readFileSync45, readdirSync as readdirSync27, statSync as statSync17 } from "fs";
15230
- import { join as join66 } from "path";
15464
+ import { readFileSync as readFileSync46, readdirSync as readdirSync27, statSync as statSync17 } from "fs";
15465
+ import { join as join67 } from "path";
15231
15466
  var isWorkflow = (rel) => rel.startsWith(".github/workflows/") && (rel.endsWith(".yml") || rel.endsWith(".yaml"));
15232
15467
  var isRootLayout = (rel) => rel.endsWith("src/app/layout.tsx");
15233
15468
  var uncommented = (contents) => contents.split("\n").filter((line) => !/^\s*(\/\/|\/\*|\*)/.test(line)).join("\n");
@@ -15291,7 +15526,7 @@ function walk(dir, base = dir) {
15291
15526
  }
15292
15527
  for (const entry of entries) {
15293
15528
  if (entry === ".venv" || entry === "node_modules" || entry === ".git") continue;
15294
- const abs = join66(dir, entry);
15529
+ const abs = join67(dir, entry);
15295
15530
  let isDir;
15296
15531
  try {
15297
15532
  isDir = statSync17(abs).isDirectory();
@@ -15313,7 +15548,7 @@ function auditSkeleton(skeletonRoot, name, rules = SKELETON_RULES) {
15313
15548
  if (!rule.appliesTo(rel)) continue;
15314
15549
  let contents;
15315
15550
  try {
15316
- contents = readFileSync45(join66(skeletonRoot, rel), "utf8");
15551
+ contents = readFileSync46(join67(skeletonRoot, rel), "utf8");
15317
15552
  } catch {
15318
15553
  continue;
15319
15554
  }
@@ -15342,23 +15577,23 @@ function formatViolations2(violations) {
15342
15577
 
15343
15578
  // src/scripts/check-skeleton-drift.ts
15344
15579
  function discoverSkeletons(root) {
15345
- const skeletonsDir = join67(root, "_skeletons");
15580
+ const skeletonsDir = join68(root, "_skeletons");
15346
15581
  let entries;
15347
15582
  try {
15348
15583
  entries = readdirSync28(skeletonsDir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
15349
15584
  } catch {
15350
15585
  return [];
15351
15586
  }
15352
- return entries.filter((name) => existsSync56(join67(skeletonsDir, name, ".github", "workflows", "ci.yml"))).sort();
15587
+ return entries.filter((name) => existsSync56(join68(skeletonsDir, name, ".github", "workflows", "ci.yml"))).sort();
15353
15588
  }
15354
15589
  async function runSkeletonDriftCheck() {
15355
15590
  const root = (await execa("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
15356
15591
  const skeletons = discoverSkeletons(root);
15357
15592
  let filesConsidered = 0;
15358
15593
  for (const name of skeletons) {
15359
- const skeletonRoot = join67(root, "_skeletons", name);
15594
+ const skeletonRoot = join68(root, "_skeletons", name);
15360
15595
  filesConsidered += findWorkflowFiles(skeletonRoot).length;
15361
- if (existsSync56(join67(skeletonRoot, "apps", "frontend", "src", "app", "layout.tsx"))) {
15596
+ if (existsSync56(join68(skeletonRoot, "apps", "frontend", "src", "app", "layout.tsx"))) {
15362
15597
  filesConsidered += 1;
15363
15598
  }
15364
15599
  }
@@ -15366,7 +15601,7 @@ async function runSkeletonDriftCheck() {
15366
15601
  `audited ${skeletons.length} skeleton(s) (${skeletons.join(", ") || "none"}), ${filesConsidered} file(s) considered, under ${root}/_skeletons`
15367
15602
  );
15368
15603
  if (skeletons.length === 0) {
15369
- if (!existsSync56(join67(root, "_skeletons"))) {
15604
+ if (!existsSync56(join68(root, "_skeletons"))) {
15370
15605
  console.log(
15371
15606
  `\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.`
15372
15607
  );
@@ -15378,7 +15613,7 @@ async function runSkeletonDriftCheck() {
15378
15613
  process.exit(1);
15379
15614
  }
15380
15615
  const violations = skeletons.flatMap(
15381
- (name) => auditSkeleton(join67(root, "_skeletons", name), name)
15616
+ (name) => auditSkeleton(join68(root, "_skeletons", name), name)
15382
15617
  );
15383
15618
  if (violations.length > 0) {
15384
15619
  console.error("\u2717 Skeleton-drift guard: drift found between this repo and its scaffolding\n");
@@ -15414,7 +15649,7 @@ async function runTerraformInputCheck() {
15414
15649
 
15415
15650
  // src/commands/check.ts
15416
15651
  var checkCommand = new Command24("check").description(
15417
- "Repo guards (ownership, release subject, plugin terraform, plugin collisions, eventbridge-log-permissions, plugin-tool-supply, core-direct-paths, instance-adoption, orphan-ratchet, cognito-invite-template, lambda-output, pipe-trap, codeql-suppression, skeleton-drift, terraform-input, plugin-allowlist-convention, migration-body-change, distribution-inventory, distribution-remote-state, api-gateway-integration) run in CI and git hooks, plus out-of-band audits (branch protection, plugin-staleness)"
15652
+ "Repo guards (ownership, ownership-header-claim, release subject, plugin terraform, plugin collisions, eventbridge-log-permissions, plugin-tool-supply, core-direct-paths, instance-adoption, orphan-ratchet, cognito-invite-template, lambda-output, pipe-trap, codeql-suppression, skeleton-drift, terraform-input, plugin-allowlist-convention, migration-body-change, distribution-inventory, distribution-remote-state, api-gateway-integration) run in CI and git hooks, plus out-of-band audits (branch protection, plugin-staleness)"
15418
15653
  );
15419
15654
  checkCommand.command("ownership").description("Refuse changes to template-owned paths in an instance (#370)").argument("[base]", "Base branch to diff against; defaults to $GITHUB_BASE_REF").option("--staged <messageFile>", "Check staged changes instead of a branch diff (commit hook)").allowExcessArguments(true).action(async () => {
15420
15655
  await runOwnershipCheck(rawArgsAfter("ownership"));
@@ -15503,6 +15738,11 @@ checkCommand.command("orphan-ratchet").description(
15503
15738
  await runOrphanRatchetCheck(opts);
15504
15739
  }
15505
15740
  );
15741
+ checkCommand.command("ownership-header-claim").description(
15742
+ `Refuse a file whose own header comment claims INSTANCE-OWNED/template-owned/user-owned/"NOT a template file" while core-manifest.json's real longest-prefix-match answer disagrees (#1911) \u2014 scripts/verify-deployed.checks lived this exact gap (#1706/#1707) until a human happened to notice by hand; nothing else compared the two documents.`
15743
+ ).action(async () => {
15744
+ await runOwnershipHeaderClaimCheck();
15745
+ });
15506
15746
  checkCommand.command("cognito-invite-template").description(
15507
15747
  "Refuse a Cognito invite_message_template missing a required member or placeholder (#356) \u2014 terraform validate is silent on this, so a fresh deploy fails on its first apply"
15508
15748
  ).action(async () => {
@@ -15574,8 +15814,8 @@ function rawArgsAfter(subcommand) {
15574
15814
  }
15575
15815
 
15576
15816
  // src/commands/doctor.ts
15577
- import { existsSync as existsSync57, readFileSync as readFileSync46 } from "fs";
15578
- import { join as join68, resolve as resolve20 } from "path";
15817
+ import { existsSync as existsSync57, readFileSync as readFileSync47 } from "fs";
15818
+ import { join as join69, resolve as resolve20 } from "path";
15579
15819
  import chalk21 from "chalk";
15580
15820
  import { Command as Command25 } from "commander";
15581
15821
 
@@ -15970,10 +16210,10 @@ async function runDoctorFixBranches(cwd, facts, deps = { git: new GitAdapter(),
15970
16210
  return reapAllBareBranches(cwd, facts.branches, facts.worktrees, facts.currentBranch, deps);
15971
16211
  }
15972
16212
  function readLocalCoreVersion(cwd) {
15973
- const path = join68(cwd, INSTANCE_CORE_FILE);
16213
+ const path = join69(cwd, INSTANCE_CORE_FILE);
15974
16214
  if (!existsSync57(path)) return null;
15975
16215
  try {
15976
- return extractVersionField(readFileSync46(path, "utf8"));
16216
+ return extractVersionField(readFileSync47(path, "utf8"));
15977
16217
  } catch {
15978
16218
  return null;
15979
16219
  }
@@ -15993,10 +16233,10 @@ function extractVersionField(contents) {
15993
16233
  return match?.[1] ?? null;
15994
16234
  }
15995
16235
  function readFossil(cwd) {
15996
- const path = join68(cwd, CORE_VERSION_FILE);
16236
+ const path = join69(cwd, CORE_VERSION_FILE);
15997
16237
  if (!existsSync57(path)) return null;
15998
16238
  try {
15999
- const value = readFileSync46(path, "utf8").trim();
16239
+ const value = readFileSync47(path, "utf8").trim();
16000
16240
  return value === "" ? null : value;
16001
16241
  } catch {
16002
16242
  return null;
@@ -16526,11 +16766,11 @@ import { Command as Command27 } from "commander";
16526
16766
 
16527
16767
  // src/lib/packaged-scripts.ts
16528
16768
  import { existsSync as existsSync58 } from "fs";
16529
- import { dirname as dirname11, join as join69 } from "path";
16769
+ import { dirname as dirname11, join as join70 } from "path";
16530
16770
  function findPackagedScript(startDir, relativePath) {
16531
16771
  let dir = startDir;
16532
16772
  for (; ; ) {
16533
- const candidate = join69(dir, relativePath);
16773
+ const candidate = join70(dir, relativePath);
16534
16774
  if (existsSync58(candidate)) return candidate;
16535
16775
  const parent = dirname11(dir);
16536
16776
  if (parent === dir) return null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@biffo/cli",
3
- "version": "0.305.0",
3
+ "version": "0.306.0",
4
4
  "description": "Biffo project scaffolding CLI",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/scripts/verify.sh CHANGED
@@ -1449,6 +1449,7 @@ if [ -f scripts/biffo.sh ]; then
1449
1449
  run_check plugin-tool-supply sh scripts/biffo.sh check plugin-tool-supply
1450
1450
  run_check core-direct-paths sh scripts/biffo.sh check core-direct-paths
1451
1451
  run_check orphan-ratchet sh scripts/biffo.sh check orphan-ratchet
1452
+ run_check ownership-header-claim sh scripts/biffo.sh check ownership-header-claim
1452
1453
  # #1714 second remediation: the INSTANCE-mode caller, distinct from the
1453
1454
  # self-check above. It clones a real template tree pinned to
1454
1455
  # biffo.core.json's own version and compares against it -- but this repo