@biffo/cli 0.303.2 → 0.303.4
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/_skeletons/plugin-template/README.md +20 -31
- package/_skeletons/plugin-template/pyproject.toml +8 -16
- package/dist/index.js +171 -113
- package/package.json +1 -1
|
@@ -137,7 +137,7 @@ repository with its own independent `uv sync` / `uv.lock`, not inside
|
|
|
137
137
|
biffo-template's workspace. Once copied out, `uv sync && uv run pytest`
|
|
138
138
|
works standalone with no dependency on the rest of biffo-template.
|
|
139
139
|
|
|
140
|
-
## The `biffo-plugin-sdk` dependency: PyPI pin
|
|
140
|
+
## The `biffo-plugin-sdk` dependency: PyPI pin
|
|
141
141
|
|
|
142
142
|
`pyproject.toml` declares:
|
|
143
143
|
|
|
@@ -148,41 +148,30 @@ dependencies = [
|
|
|
148
148
|
]
|
|
149
149
|
```
|
|
150
150
|
|
|
151
|
-
This is a **PyPI-style version pin
|
|
152
|
-
|
|
151
|
+
This is a **PyPI-style version pin**: the SDK is published via
|
|
152
|
+
biffo-template's
|
|
153
153
|
[`.github/workflows/publish-sdk.yml`](https://github.com/keiranholloway/biffo-template/blob/main/.github/workflows/publish-sdk.yml)
|
|
154
|
-
|
|
155
|
-
|
|
154
|
+
(Trusted Publishing) on a pushed `sdk-v*` tag, and the first release has
|
|
155
|
+
already happened — this skeleton's own `uv.lock` resolves `biffo-plugin-sdk`
|
|
156
|
+
1.4.0 from `https://pypi.org/simple` (see its `biffo-plugin-sdk` entry).
|
|
157
|
+
`>=1.0,<2.0` matches the `"biffo-plugin-sdk": "^1.0"` that
|
|
156
158
|
`biffo.plugin.json` declares, and the SDK carries its own independent
|
|
157
159
|
semver — it is **not** tied to the template's core version, so a major
|
|
158
160
|
bump here means the plugin API broke and nothing else.
|
|
159
161
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
`
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
[tool.uv.sources]
|
|
174
|
-
biffo-plugin-sdk = { path = "../../packages/python-sdk", editable = true }
|
|
175
|
-
```
|
|
176
|
-
2. **Git dependency** (developing this plugin as a genuinely separate repo
|
|
177
|
-
against an unpublished SDK):
|
|
178
|
-
```toml
|
|
179
|
-
[tool.uv.sources]
|
|
180
|
-
biffo-plugin-sdk = { git = "https://github.com/keiranholloway/biffo-template", subdirectory = "packages/python-sdk" }
|
|
181
|
-
```
|
|
182
|
-
|
|
183
|
-
Either override goes in `[tool.uv.sources]` only — the PyPI-style
|
|
184
|
-
`dependencies` entry above stays as-is, so removing the override is the
|
|
185
|
-
only change needed once the SDK actually ships to PyPI.
|
|
162
|
+
`uv sync` in a freshly-copied plugin repo resolves this pin normally; no
|
|
163
|
+
`[tool.uv.sources]` override is needed. If you are developing this plugin
|
|
164
|
+
*inside* a `biffo-template` checkout (e.g. one you plan to upstream into
|
|
165
|
+
`services/`) and want to iterate against an unreleased SDK change before it
|
|
166
|
+
ships, a local override still works:
|
|
167
|
+
|
|
168
|
+
```toml
|
|
169
|
+
[tool.uv.sources]
|
|
170
|
+
biffo-plugin-sdk = { path = "../../packages/python-sdk", editable = true }
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Keep it local (uncommitted, or removed before committing) — the PyPI-style
|
|
174
|
+
`dependencies` entry above is what every scaffolded plugin repo ships with.
|
|
186
175
|
|
|
187
176
|
## Manifest validation: why CI doesn't hard-gate on `registry-schema.json`
|
|
188
177
|
|
|
@@ -4,22 +4,14 @@ version = "0.1.0"
|
|
|
4
4
|
description = "Example Biffo plugin — replace this with your own plugin's name and description"
|
|
5
5
|
requires-python = ">=3.13"
|
|
6
6
|
dependencies = [
|
|
7
|
-
# biffo-plugin-sdk has a real release path
|
|
8
|
-
# .github/workflows/publish-sdk.yml:
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
# `
|
|
14
|
-
#
|
|
15
|
-
# as before this comment was written, so nothing regressed here; what
|
|
16
|
-
# changed is that the fix is now one tag push away rather than unbuilt.
|
|
17
|
-
# Deliberately NOT worked around with a git/path source in the committed
|
|
18
|
-
# file: baking one in would mean every plugin repo forked from this
|
|
19
|
-
# skeleton silently keeps building against a moving git ref long after
|
|
20
|
-
# the real release exists. Use a local `[tool.uv.sources]` override until
|
|
21
|
-
# then — see the README's "biffo-plugin-sdk dependency" section, which
|
|
22
|
-
# documents both options and says which to delete once 1.0.0 is live.
|
|
7
|
+
# biffo-plugin-sdk has a real release path via biffo-template's
|
|
8
|
+
# .github/workflows/publish-sdk.yml: it publishes to PyPI (via Trusted
|
|
9
|
+
# Publishing) when an `sdk-v*` tag is pushed. That first publish has
|
|
10
|
+
# already happened — this skeleton's own uv.lock resolves biffo-plugin-sdk
|
|
11
|
+
# 1.4.0 from https://pypi.org/simple (see uv.lock's own `biffo-plugin-sdk`
|
|
12
|
+
# entry) — so `uv sync` in a freshly-copied plugin repo resolves this pin
|
|
13
|
+
# normally, with no `[tool.uv.sources]` override needed (biffo-template#1769
|
|
14
|
+
# side finding).
|
|
23
15
|
"biffo-plugin-sdk>=1.0,<2.0",
|
|
24
16
|
"aws-lambda-powertools[tracer]>=3.4.0",
|
|
25
17
|
"httpx>=0.28.1",
|
package/dist/index.js
CHANGED
|
@@ -8273,7 +8273,8 @@ import {
|
|
|
8273
8273
|
import { dirname as dirname7, join as join26 } from "path";
|
|
8274
8274
|
var STANDALONE_ONLY_ENTRIES = {
|
|
8275
8275
|
".github": "standalone-repo CI/release workflows \u2014 the host monorepo already runs lint/type/test/security over services/",
|
|
8276
|
-
"registry-schema.json": "the plugin-registry publishing schema, used when submitting a *published* plugin to the registry repo, not by an in-tree plugin"
|
|
8276
|
+
"registry-schema.json": "the plugin-registry publishing schema, used when submitting a *published* plugin to the registry repo, not by an in-tree plugin",
|
|
8277
|
+
"uv.lock": "a standalone repo's own lockfile, substituted like any other text file (issue #1769) \u2014 a nested lock inside a monorepo's services/ would be wrong there, since the host resolves its own dependency tree"
|
|
8277
8278
|
};
|
|
8278
8279
|
var NEVER_COPY = /* @__PURE__ */ new Set([
|
|
8279
8280
|
".git",
|
|
@@ -8284,7 +8285,6 @@ var NEVER_COPY = /* @__PURE__ */ new Set([
|
|
|
8284
8285
|
".pytest_cache",
|
|
8285
8286
|
".mypy_cache",
|
|
8286
8287
|
"dist",
|
|
8287
|
-
"uv.lock",
|
|
8288
8288
|
".DS_Store"
|
|
8289
8289
|
]);
|
|
8290
8290
|
var PLUGIN_NAME_PATTERN = /^[a-z][a-z0-9-]*$/;
|
|
@@ -8537,6 +8537,11 @@ async function runStandaloneCreate(names, options, deps) {
|
|
|
8537
8537
|
`
|
|
8538
8538
|
);
|
|
8539
8539
|
if (options.commit) {
|
|
8540
|
+
if (!existsSync27(join27(destDir, "uv.lock"))) {
|
|
8541
|
+
throw new Error(
|
|
8542
|
+
`Scaffolded plugin at ${destDir} has no uv.lock. The standalone layout must carry a substituted uv.lock (see plugin-scaffold.ts STANDALONE_ONLY_ENTRIES) so the first commit's CI run can satisfy 'uv sync --locked'. Refusing to commit a repo that would ship red on its very first push (issue #1769) \u2014 run 'uv lock' in ${destDir} first.`
|
|
8543
|
+
);
|
|
8544
|
+
}
|
|
8540
8545
|
await deps.git.init(destDir);
|
|
8541
8546
|
await deps.git.add(destDir, ["."]);
|
|
8542
8547
|
await deps.git.commit(destDir, `feat: scaffold ${names.slug} plugin`);
|
|
@@ -11122,8 +11127,15 @@ async function runApiGatewayIntegrationCheck() {
|
|
|
11122
11127
|
try {
|
|
11123
11128
|
report = auditApiGatewayIntegrations(root);
|
|
11124
11129
|
} catch (err) {
|
|
11130
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
11131
|
+
if (message.includes("no .tf files found under")) {
|
|
11132
|
+
console.log(
|
|
11133
|
+
`\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.`
|
|
11134
|
+
);
|
|
11135
|
+
return;
|
|
11136
|
+
}
|
|
11125
11137
|
console.error("\u2717 API Gateway integration-qualifier guard: could not run\n");
|
|
11126
|
-
console.error(
|
|
11138
|
+
console.error(message);
|
|
11127
11139
|
process.exit(1);
|
|
11128
11140
|
}
|
|
11129
11141
|
console.log(`scanned ${report.filesScanned} .tf file(s) under ${root}`);
|
|
@@ -11653,6 +11665,10 @@ async function runCodeqlSuppressionCheck() {
|
|
|
11653
11665
|
console.log("\u2713 codeql-suppression guard: no dead `codeql[...]` suppression comment found");
|
|
11654
11666
|
}
|
|
11655
11667
|
|
|
11668
|
+
// src/scripts/check-cognito-invite-template.ts
|
|
11669
|
+
import { existsSync as existsSync42 } from "fs";
|
|
11670
|
+
import { join as join46 } from "path";
|
|
11671
|
+
|
|
11656
11672
|
// src/lib/cognito-invite-template-guard.ts
|
|
11657
11673
|
import { readdirSync as readdirSync19, readFileSync as readFileSync33, statSync as statSync11 } from "fs";
|
|
11658
11674
|
import { join as join45 } from "path";
|
|
@@ -11769,6 +11785,12 @@ async function runCognitoInviteTemplateCheck() {
|
|
|
11769
11785
|
const files = findModuleTerraformFiles(root);
|
|
11770
11786
|
console.log(`audited ${files.length} .tf file(s) under modules/ under ${root}`);
|
|
11771
11787
|
if (files.length === 0) {
|
|
11788
|
+
if (!existsSync42(join46(root, "modules"))) {
|
|
11789
|
+
console.log(
|
|
11790
|
+
`\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.`
|
|
11791
|
+
);
|
|
11792
|
+
return;
|
|
11793
|
+
}
|
|
11772
11794
|
console.error(
|
|
11773
11795
|
"\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
11796
|
);
|
|
@@ -11787,11 +11809,11 @@ async function runCognitoInviteTemplateCheck() {
|
|
|
11787
11809
|
}
|
|
11788
11810
|
|
|
11789
11811
|
// src/scripts/check-core-direct-paths.ts
|
|
11790
|
-
import { join as
|
|
11812
|
+
import { join as join48 } from "path";
|
|
11791
11813
|
|
|
11792
11814
|
// src/lib/core-direct-paths-audit.ts
|
|
11793
|
-
import { existsSync as
|
|
11794
|
-
import { join as
|
|
11815
|
+
import { existsSync as existsSync43, readFileSync as readFileSync34, readdirSync as readdirSync20, statSync as statSync12 } from "fs";
|
|
11816
|
+
import { join as join47 } from "path";
|
|
11795
11817
|
var EXTERNAL_BASE_IDENTIFIERS = ["CORE_API_URL"];
|
|
11796
11818
|
var API_ROUTE_PREFIX = "/api/v1";
|
|
11797
11819
|
var TEST_FILE_SUFFIXES = [".test.ts", ".test.tsx", ".spec.ts", ".spec.tsx"];
|
|
@@ -11955,7 +11977,7 @@ function walkFiles(root, accept, skipDir) {
|
|
|
11955
11977
|
return;
|
|
11956
11978
|
}
|
|
11957
11979
|
for (const entry of entries) {
|
|
11958
|
-
const p =
|
|
11980
|
+
const p = join47(dir, entry);
|
|
11959
11981
|
let st;
|
|
11960
11982
|
try {
|
|
11961
11983
|
st = statSync12(p);
|
|
@@ -12050,7 +12072,7 @@ function pathMatchesAnyCorePrefix(normalized, corePrefixes, apiRoutePrefix = API
|
|
|
12050
12072
|
}
|
|
12051
12073
|
function resolveSiblingCoreSrc(params) {
|
|
12052
12074
|
const { estateDir, sibling } = params;
|
|
12053
|
-
const configPath =
|
|
12075
|
+
const configPath = join47(estateDir, sibling, "biffo.sibling.json");
|
|
12054
12076
|
let raw;
|
|
12055
12077
|
try {
|
|
12056
12078
|
raw = readFileSync34(configPath, "utf8");
|
|
@@ -12073,8 +12095,8 @@ function resolveSiblingCoreSrc(params) {
|
|
|
12073
12095
|
`cannot resolve ${sibling}'s core: ${configPath} has no non-empty "core_project" field.`
|
|
12074
12096
|
);
|
|
12075
12097
|
}
|
|
12076
|
-
const coreApiSrcDir =
|
|
12077
|
-
if (!
|
|
12098
|
+
const coreApiSrcDir = join47(estateDir, coreProject, "services", "api", "src");
|
|
12099
|
+
if (!existsSync43(coreApiSrcDir)) {
|
|
12078
12100
|
throw new Error(
|
|
12079
12101
|
`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
12102
|
);
|
|
@@ -12117,7 +12139,7 @@ function auditSiblingCoreDirectPaths(params) {
|
|
|
12117
12139
|
async function runCoreDirectPathsCheck(opts = {}) {
|
|
12118
12140
|
const root = (await execa("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
|
|
12119
12141
|
const sibling = opts.sibling ?? "sibling-template (self-check)";
|
|
12120
|
-
const frontendSrcDir = opts.frontendSrc ??
|
|
12142
|
+
const frontendSrcDir = opts.frontendSrc ?? join48(root, "_skeletons", "sibling-template", "apps", "frontend", "src");
|
|
12121
12143
|
let coreApiSrcDir;
|
|
12122
12144
|
let coreProject = null;
|
|
12123
12145
|
if (opts.coreSrc) {
|
|
@@ -12133,7 +12155,7 @@ async function runCoreDirectPathsCheck(opts = {}) {
|
|
|
12133
12155
|
coreApiSrcDir = resolution.coreApiSrcDir;
|
|
12134
12156
|
coreProject = resolution.coreProject;
|
|
12135
12157
|
} else {
|
|
12136
|
-
coreApiSrcDir =
|
|
12158
|
+
coreApiSrcDir = join48(root, "services", "api", "src");
|
|
12137
12159
|
}
|
|
12138
12160
|
const report = auditSiblingCoreDirectPaths({ sibling, frontendSrcDir, coreApiSrcDir });
|
|
12139
12161
|
console.log(
|
|
@@ -12198,8 +12220,8 @@ async function runOwnershipCheck(argv) {
|
|
|
12198
12220
|
const { stdout } = await execa("git", ["diff", "--cached", "--name-status"], { cwd: root });
|
|
12199
12221
|
({ changed: changedFiles, deleted: deletedFiles } = parseNameStatus(stdout));
|
|
12200
12222
|
if (messageFile) {
|
|
12201
|
-
const { readFileSync: readFileSync47, existsSync:
|
|
12202
|
-
if (
|
|
12223
|
+
const { readFileSync: readFileSync47, existsSync: existsSync59 } = await import("fs");
|
|
12224
|
+
if (existsSync59(messageFile)) commitMessage = readFileSync47(messageFile, "utf8");
|
|
12203
12225
|
}
|
|
12204
12226
|
} else {
|
|
12205
12227
|
const base = process.env["GITHUB_BASE_REF"] ?? args[0];
|
|
@@ -12300,16 +12322,16 @@ ${BOLD}If the divergence is deliberate${OFF}
|
|
|
12300
12322
|
}
|
|
12301
12323
|
|
|
12302
12324
|
// src/scripts/check-distribution-inventory.ts
|
|
12303
|
-
import { existsSync as
|
|
12304
|
-
import { join as
|
|
12325
|
+
import { existsSync as existsSync45 } from "fs";
|
|
12326
|
+
import { join as join50 } from "path";
|
|
12305
12327
|
|
|
12306
12328
|
// src/lib/distribution-inventory.ts
|
|
12307
|
-
import { existsSync as
|
|
12308
|
-
import { join as
|
|
12329
|
+
import { existsSync as existsSync44, readFileSync as readFileSync35 } from "fs";
|
|
12330
|
+
import { join as join49 } from "path";
|
|
12309
12331
|
var INVENTORY_FILENAME = "distribution-inventory.json";
|
|
12310
12332
|
function loadDistributionInventory(root) {
|
|
12311
|
-
const path =
|
|
12312
|
-
if (!
|
|
12333
|
+
const path = join49(root, INVENTORY_FILENAME);
|
|
12334
|
+
if (!existsSync44(path)) {
|
|
12313
12335
|
throw new Error(
|
|
12314
12336
|
`${INVENTORY_FILENAME} not found at ${root} -- expected it beside core-manifest.json`
|
|
12315
12337
|
);
|
|
@@ -12474,7 +12496,7 @@ async function runDistributionInventoryCheck(root) {
|
|
|
12474
12496
|
);
|
|
12475
12497
|
return;
|
|
12476
12498
|
}
|
|
12477
|
-
if (!
|
|
12499
|
+
if (!existsSync45(join50(repoRoot, INVENTORY_FILENAME))) {
|
|
12478
12500
|
console.log(
|
|
12479
12501
|
`\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
12502
|
);
|
|
@@ -12500,7 +12522,7 @@ async function runDistributionInventoryCheck(root) {
|
|
|
12500
12522
|
}
|
|
12501
12523
|
|
|
12502
12524
|
// src/scripts/check-distribution-remote-state.ts
|
|
12503
|
-
import { join as
|
|
12525
|
+
import { join as join51 } from "path";
|
|
12504
12526
|
async function ghExecCommand(file, args) {
|
|
12505
12527
|
const result = await execa(file, args, { reject: false });
|
|
12506
12528
|
return { stdout: String(result.stdout ?? ""), exitCode: result.exitCode ?? null };
|
|
@@ -12515,7 +12537,7 @@ async function runDistributionRemoteStateCheck(root) {
|
|
|
12515
12537
|
}
|
|
12516
12538
|
}
|
|
12517
12539
|
console.log(
|
|
12518
|
-
`distribution-remote-state: examined ${assertions.length} remote content assertion(s) declared across ${inventory.entries.length} inventory entries (${
|
|
12540
|
+
`distribution-remote-state: examined ${assertions.length} remote content assertion(s) declared across ${inventory.entries.length} inventory entries (${join51(repoRoot, "distribution-inventory.json")})`
|
|
12519
12541
|
);
|
|
12520
12542
|
if (assertions.length === 0) {
|
|
12521
12543
|
console.log("\u2713 distribution-remote-state: nothing declared to check");
|
|
@@ -12561,7 +12583,7 @@ ${assertion.ref}`;
|
|
|
12561
12583
|
|
|
12562
12584
|
// src/lib/eventbridge-log-permission-guard.ts
|
|
12563
12585
|
import { readFileSync as readFileSync36, readdirSync as readdirSync21, statSync as statSync13 } from "fs";
|
|
12564
|
-
import { join as
|
|
12586
|
+
import { join as join52 } from "path";
|
|
12565
12587
|
var SKIP_DIRS3 = /* @__PURE__ */ new Set(["node_modules", ".git", ".terraform", ".worktrees", "dist"]);
|
|
12566
12588
|
var EVENT_TARGET_TYPE = "aws_cloudwatch_event_target";
|
|
12567
12589
|
var LOG_RESOURCE_POLICY_TYPE = "aws_cloudwatch_log_resource_policy";
|
|
@@ -12638,7 +12660,7 @@ function walkTerraformFiles2(root) {
|
|
|
12638
12660
|
return;
|
|
12639
12661
|
}
|
|
12640
12662
|
for (const entry of entries) {
|
|
12641
|
-
const p =
|
|
12663
|
+
const p = join52(dir, entry);
|
|
12642
12664
|
let st;
|
|
12643
12665
|
try {
|
|
12644
12666
|
st = statSync13(p);
|
|
@@ -12739,8 +12761,15 @@ async function runEventBridgeLogPermissionCheck() {
|
|
|
12739
12761
|
try {
|
|
12740
12762
|
report = auditEventBridgeLogPermissions(root);
|
|
12741
12763
|
} catch (err) {
|
|
12764
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
12765
|
+
if (message.includes("no .tf files found under")) {
|
|
12766
|
+
console.log(
|
|
12767
|
+
`\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.`
|
|
12768
|
+
);
|
|
12769
|
+
return;
|
|
12770
|
+
}
|
|
12742
12771
|
console.error("\u2717 EventBridge log permission guard: could not run\n");
|
|
12743
|
-
console.error(
|
|
12772
|
+
console.error(message);
|
|
12744
12773
|
process.exit(1);
|
|
12745
12774
|
}
|
|
12746
12775
|
console.log(`audited ${report.filesScanned} .tf file(s) under ${root}`);
|
|
@@ -12771,8 +12800,8 @@ async function runEventBridgeLogPermissionCheck() {
|
|
|
12771
12800
|
}
|
|
12772
12801
|
|
|
12773
12802
|
// src/scripts/check-instance-adoption.ts
|
|
12774
|
-
import { existsSync as
|
|
12775
|
-
import { join as
|
|
12803
|
+
import { existsSync as existsSync46 } from "fs";
|
|
12804
|
+
import { join as join53 } from "path";
|
|
12776
12805
|
async function runInstanceAdoptionCheck(opts = {}) {
|
|
12777
12806
|
if (!opts.instanceDir) {
|
|
12778
12807
|
console.error(
|
|
@@ -12780,7 +12809,7 @@ async function runInstanceAdoptionCheck(opts = {}) {
|
|
|
12780
12809
|
);
|
|
12781
12810
|
process.exit(2);
|
|
12782
12811
|
}
|
|
12783
|
-
if (!
|
|
12812
|
+
if (!existsSync46(opts.instanceDir)) {
|
|
12784
12813
|
console.error(
|
|
12785
12814
|
`\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
12815
|
);
|
|
@@ -12788,7 +12817,7 @@ async function runInstanceAdoptionCheck(opts = {}) {
|
|
|
12788
12817
|
}
|
|
12789
12818
|
const root = (await execa("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
|
|
12790
12819
|
const theirsDir = opts.theirsDir ?? root;
|
|
12791
|
-
const instanceLabel = opts.instance ??
|
|
12820
|
+
const instanceLabel = opts.instance ?? join53(opts.instanceDir).split("/").filter(Boolean).pop();
|
|
12792
12821
|
const report = checkInstanceAdoption(theirsDir, opts.instanceDir);
|
|
12793
12822
|
console.log(
|
|
12794
12823
|
`examined ${report.examinedInstances} instance (${instanceLabel}) against ${report.registeredPairs} registered pair(s), ${report.applicablePairs} applicable to this instance, against template tree ${theirsDir}`
|
|
@@ -12811,11 +12840,11 @@ async function runInstanceAdoptionCheck(opts = {}) {
|
|
|
12811
12840
|
|
|
12812
12841
|
// src/lib/lambda-output-guard.ts
|
|
12813
12842
|
import { readFileSync as readFileSync38 } from "fs";
|
|
12814
|
-
import { join as
|
|
12843
|
+
import { join as join55 } from "path";
|
|
12815
12844
|
|
|
12816
12845
|
// src/lib/terraform-input-guard.ts
|
|
12817
|
-
import { existsSync as
|
|
12818
|
-
import { join as
|
|
12846
|
+
import { existsSync as existsSync47, readdirSync as readdirSync22, readFileSync as readFileSync37, statSync as statSync14 } from "fs";
|
|
12847
|
+
import { join as join54 } from "path";
|
|
12819
12848
|
var GUARDED_SUBCOMMANDS = [
|
|
12820
12849
|
"init",
|
|
12821
12850
|
"plan",
|
|
@@ -12829,7 +12858,7 @@ function stripComments2(source) {
|
|
|
12829
12858
|
return source.split("\n").map((line) => line.replace(/(^|\s)#.*$/, "$1")).join("\n");
|
|
12830
12859
|
}
|
|
12831
12860
|
function vendoredPluginServiceDirs(repoRoot) {
|
|
12832
|
-
const servicesDir =
|
|
12861
|
+
const servicesDir = join54(repoRoot, "services");
|
|
12833
12862
|
const result = /* @__PURE__ */ new Set();
|
|
12834
12863
|
let entries;
|
|
12835
12864
|
try {
|
|
@@ -12838,9 +12867,9 @@ function vendoredPluginServiceDirs(repoRoot) {
|
|
|
12838
12867
|
return result;
|
|
12839
12868
|
}
|
|
12840
12869
|
for (const entry of entries) {
|
|
12841
|
-
const full =
|
|
12842
|
-
if (!
|
|
12843
|
-
if (
|
|
12870
|
+
const full = join54(servicesDir, entry);
|
|
12871
|
+
if (!existsSync47(full) || !statSync14(full).isDirectory()) continue;
|
|
12872
|
+
if (existsSync47(join54(full, "biffo.plugin.json"))) {
|
|
12844
12873
|
result.add(entry);
|
|
12845
12874
|
}
|
|
12846
12875
|
}
|
|
@@ -12862,7 +12891,7 @@ function findWorkflowFiles(repoRoot) {
|
|
|
12862
12891
|
if (entry === ".github" && relative11.startsWith("services/") && vendoredPluginDirs.has(relative11.slice("services/".length))) {
|
|
12863
12892
|
continue;
|
|
12864
12893
|
}
|
|
12865
|
-
const full =
|
|
12894
|
+
const full = join54(dir, entry);
|
|
12866
12895
|
const rel = relative11 ? `${relative11}/${entry}` : entry;
|
|
12867
12896
|
let isDir;
|
|
12868
12897
|
try {
|
|
@@ -12912,7 +12941,7 @@ function checkWorkflowSource(file, rawSource) {
|
|
|
12912
12941
|
}
|
|
12913
12942
|
function checkTerraformInput(repoRoot) {
|
|
12914
12943
|
return findWorkflowFiles(repoRoot).flatMap(
|
|
12915
|
-
(file) => checkWorkflowSource(file, readFileSync37(
|
|
12944
|
+
(file) => checkWorkflowSource(file, readFileSync37(join54(repoRoot, file), "utf8"))
|
|
12916
12945
|
);
|
|
12917
12946
|
}
|
|
12918
12947
|
|
|
@@ -12970,7 +12999,7 @@ function checkWorkflowSource2(file, rawSource) {
|
|
|
12970
12999
|
}
|
|
12971
13000
|
function checkLambdaOutput(repoRoot) {
|
|
12972
13001
|
return findWorkflowFiles(repoRoot).flatMap(
|
|
12973
|
-
(file) => checkWorkflowSource2(file, readFileSync38(
|
|
13002
|
+
(file) => checkWorkflowSource2(file, readFileSync38(join55(repoRoot, file), "utf8"))
|
|
12974
13003
|
);
|
|
12975
13004
|
}
|
|
12976
13005
|
|
|
@@ -12998,8 +13027,8 @@ async function runLambdaOutputCheck() {
|
|
|
12998
13027
|
}
|
|
12999
13028
|
|
|
13000
13029
|
// src/scripts/check-migration-body-change.ts
|
|
13001
|
-
import { existsSync as
|
|
13002
|
-
import { join as
|
|
13030
|
+
import { existsSync as existsSync48 } from "fs";
|
|
13031
|
+
import { join as join56 } from "path";
|
|
13003
13032
|
|
|
13004
13033
|
// src/lib/migration-body-change-guard.ts
|
|
13005
13034
|
function checkMigrationBodyChangeMarkers(diffs) {
|
|
@@ -13065,7 +13094,7 @@ async function runMigrationBodyChangeCheck(argv) {
|
|
|
13065
13094
|
);
|
|
13066
13095
|
return;
|
|
13067
13096
|
}
|
|
13068
|
-
if (!
|
|
13097
|
+
if (!existsSync48(join56(root, MIGRATIONS_VERSIONS_DIR))) {
|
|
13069
13098
|
console.log(`\u2713 migration body-change guard: no ${MIGRATIONS_VERSIONS_DIR} in this repo.`);
|
|
13070
13099
|
return;
|
|
13071
13100
|
}
|
|
@@ -13167,8 +13196,8 @@ ${BOLD2}What to do${OFF2}
|
|
|
13167
13196
|
}
|
|
13168
13197
|
|
|
13169
13198
|
// src/scripts/check-orphan-ratchet.ts
|
|
13170
|
-
import { existsSync as
|
|
13171
|
-
import { basename as basename3 } from "path";
|
|
13199
|
+
import { existsSync as existsSync49 } from "fs";
|
|
13200
|
+
import { basename as basename3, join as join57 } from "path";
|
|
13172
13201
|
function reportOrphan(entry, manifest) {
|
|
13173
13202
|
console.error(` ${entry.path}`);
|
|
13174
13203
|
const { templateOwnedMatch, nearestUserOwnedEntries } = explainOwnership(entry.path, manifest);
|
|
@@ -13190,7 +13219,7 @@ function reportOrphan(entry, manifest) {
|
|
|
13190
13219
|
}
|
|
13191
13220
|
}
|
|
13192
13221
|
async function runOrphanRatchetCheck(opts = {}) {
|
|
13193
|
-
if (opts.instanceDir !== void 0 && !
|
|
13222
|
+
if (opts.instanceDir !== void 0 && !existsSync49(opts.instanceDir)) {
|
|
13194
13223
|
console.error(
|
|
13195
13224
|
`\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
13225
|
);
|
|
@@ -13207,6 +13236,12 @@ async function runOrphanRatchetCheck(opts = {}) {
|
|
|
13207
13236
|
"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
13237
|
);
|
|
13209
13238
|
}
|
|
13239
|
+
if (!existsSync49(join57(theirsDir, CORE_MANIFEST_FILE))) {
|
|
13240
|
+
console.log(
|
|
13241
|
+
`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.`
|
|
13242
|
+
);
|
|
13243
|
+
return;
|
|
13244
|
+
}
|
|
13210
13245
|
const manifest = readCoreManifest(theirsDir);
|
|
13211
13246
|
const plan = await planCoreUpgrade({ baseDir, oursDir: instanceDir, theirsDir, manifest });
|
|
13212
13247
|
const baseline = readOrphanBaseline(instanceDir);
|
|
@@ -13233,7 +13268,7 @@ baseline was ${String(ratchet.baseline)}, now ${String(ratchet.count)}. See biff
|
|
|
13233
13268
|
|
|
13234
13269
|
// src/scripts/check-pipe-trap.ts
|
|
13235
13270
|
import { readFileSync as readFileSync39, readdirSync as readdirSync23 } from "fs";
|
|
13236
|
-
import { join as
|
|
13271
|
+
import { join as join58, relative as relative9 } from "path";
|
|
13237
13272
|
|
|
13238
13273
|
// src/lib/pipe-trap-guard.ts
|
|
13239
13274
|
var STATUS_BEARING = [
|
|
@@ -13329,7 +13364,7 @@ function findPipeTraps(source) {
|
|
|
13329
13364
|
function shellFiles(root) {
|
|
13330
13365
|
const out = [];
|
|
13331
13366
|
for (const dir of ["scripts", ".githooks"]) {
|
|
13332
|
-
const full =
|
|
13367
|
+
const full = join58(root, dir);
|
|
13333
13368
|
let entries;
|
|
13334
13369
|
try {
|
|
13335
13370
|
entries = readdirSync23(full, { withFileTypes: true });
|
|
@@ -13339,7 +13374,7 @@ function shellFiles(root) {
|
|
|
13339
13374
|
for (const entry of entries) {
|
|
13340
13375
|
if (!entry.isFile()) continue;
|
|
13341
13376
|
if (dir === "scripts" && !entry.name.endsWith(".sh")) continue;
|
|
13342
|
-
out.push(
|
|
13377
|
+
out.push(join58(full, entry.name));
|
|
13343
13378
|
}
|
|
13344
13379
|
}
|
|
13345
13380
|
return out;
|
|
@@ -13371,9 +13406,13 @@ async function runPipeTrapCheck() {
|
|
|
13371
13406
|
console.log(`\u2713 Pipe-trap guard: no status-bearing command is piped away`);
|
|
13372
13407
|
}
|
|
13373
13408
|
|
|
13409
|
+
// src/scripts/check-plugin-allowlist-convention.ts
|
|
13410
|
+
import { existsSync as existsSync50 } from "fs";
|
|
13411
|
+
import { join as join60 } from "path";
|
|
13412
|
+
|
|
13374
13413
|
// src/lib/plugin-allowlist-convention.ts
|
|
13375
13414
|
import { readFileSync as readFileSync40 } from "fs";
|
|
13376
|
-
import { join as
|
|
13415
|
+
import { join as join59 } from "path";
|
|
13377
13416
|
var COMPUTE_MAIN_TF = "modules/cloud/aws/compute/main.tf";
|
|
13378
13417
|
var PLUGIN_TEMPLATE_MAIN_TF = "modules/plugins/_template/main.tf";
|
|
13379
13418
|
var ALLOWLIST_MAIN_TF = "modules/cloud/aws/plugin-allowlist/main.tf";
|
|
@@ -13384,7 +13423,7 @@ var PLUGIN = "<plugin>";
|
|
|
13384
13423
|
var ACCOUNT = "<account>";
|
|
13385
13424
|
function read(repoRoot, relative11) {
|
|
13386
13425
|
try {
|
|
13387
|
-
return readFileSync40(
|
|
13426
|
+
return readFileSync40(join59(repoRoot, relative11), "utf8");
|
|
13388
13427
|
} catch {
|
|
13389
13428
|
throw new Error(`plugin-allowlist drift guard: cannot read ${relative11}`);
|
|
13390
13429
|
}
|
|
@@ -13479,8 +13518,21 @@ Plugins would be rejected by require_service_principal (ADR-0009). Fix the glob,
|
|
|
13479
13518
|
}
|
|
13480
13519
|
|
|
13481
13520
|
// src/scripts/check-plugin-allowlist-convention.ts
|
|
13521
|
+
var REQUIRED_SOURCES = [
|
|
13522
|
+
COMPUTE_MAIN_TF,
|
|
13523
|
+
PLUGIN_TEMPLATE_MAIN_TF,
|
|
13524
|
+
ALLOWLIST_MAIN_TF,
|
|
13525
|
+
ALLOWLIST_VARIABLES_TF
|
|
13526
|
+
];
|
|
13482
13527
|
async function runPluginAllowlistConventionCheck() {
|
|
13483
13528
|
const root = (await execa("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
|
|
13529
|
+
const missing = REQUIRED_SOURCES.filter((relative11) => !existsSync50(join60(root, relative11)));
|
|
13530
|
+
if (missing.length === REQUIRED_SOURCES.length) {
|
|
13531
|
+
console.log(
|
|
13532
|
+
`\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.`
|
|
13533
|
+
);
|
|
13534
|
+
return;
|
|
13535
|
+
}
|
|
13484
13536
|
let violations;
|
|
13485
13537
|
try {
|
|
13486
13538
|
violations = checkAllowlistConvention(root);
|
|
@@ -13505,32 +13557,32 @@ async function runPluginAllowlistConventionCheck() {
|
|
|
13505
13557
|
}
|
|
13506
13558
|
|
|
13507
13559
|
// src/scripts/check-plugin-collisions.ts
|
|
13508
|
-
import { existsSync as
|
|
13509
|
-
import { join as
|
|
13560
|
+
import { existsSync as existsSync52 } from "fs";
|
|
13561
|
+
import { join as join62 } from "path";
|
|
13510
13562
|
|
|
13511
13563
|
// src/lib/plugin-collision-guard.ts
|
|
13512
|
-
import { existsSync as
|
|
13513
|
-
import { join as
|
|
13564
|
+
import { existsSync as existsSync51, readdirSync as readdirSync24, statSync as statSync15 } from "fs";
|
|
13565
|
+
import { join as join61 } from "path";
|
|
13514
13566
|
var PYTEST_SPECIAL = /* @__PURE__ */ new Set(["conftest.py"]);
|
|
13515
13567
|
var IGNORED_DIRS = /* @__PURE__ */ new Set([".venv", "node_modules", "__pycache__", ".git", "dist", "build"]);
|
|
13516
13568
|
function subdirectories(dir) {
|
|
13517
|
-
if (!
|
|
13569
|
+
if (!existsSync51(dir)) return [];
|
|
13518
13570
|
return readdirSync24(dir).filter((entry) => {
|
|
13519
13571
|
if (IGNORED_DIRS.has(entry) || entry.startsWith(".")) return false;
|
|
13520
13572
|
try {
|
|
13521
|
-
return statSync15(
|
|
13573
|
+
return statSync15(join61(dir, entry)).isDirectory();
|
|
13522
13574
|
} catch {
|
|
13523
13575
|
return false;
|
|
13524
13576
|
}
|
|
13525
13577
|
});
|
|
13526
13578
|
}
|
|
13527
13579
|
function regularPackagesOf(pluginDir2) {
|
|
13528
|
-
return subdirectories(pluginDir2).filter((name) =>
|
|
13580
|
+
return subdirectories(pluginDir2).filter((name) => existsSync51(join61(pluginDir2, name, "__init__.py"))).sort();
|
|
13529
13581
|
}
|
|
13530
13582
|
function bareTestModulesOf(pluginDir2) {
|
|
13531
|
-
const testsDir =
|
|
13532
|
-
if (!
|
|
13533
|
-
if (
|
|
13583
|
+
const testsDir = join61(pluginDir2, "tests");
|
|
13584
|
+
if (!existsSync51(testsDir)) return [];
|
|
13585
|
+
if (existsSync51(join61(testsDir, "__init__.py"))) return [];
|
|
13534
13586
|
return readdirSync24(testsDir).filter((f) => f.endsWith(".py") && !PYTEST_SPECIAL.has(f)).sort();
|
|
13535
13587
|
}
|
|
13536
13588
|
function findCollisions(servicesDir, pluginDirs) {
|
|
@@ -13539,7 +13591,7 @@ function findCollisions(servicesDir, pluginDirs) {
|
|
|
13539
13591
|
const gather = (kind, namesOf) => {
|
|
13540
13592
|
const claims = /* @__PURE__ */ new Map();
|
|
13541
13593
|
for (const plugin of plugins) {
|
|
13542
|
-
for (const name of namesOf(
|
|
13594
|
+
for (const name of namesOf(join61(servicesDir, plugin))) {
|
|
13543
13595
|
claims.set(name, [...claims.get(name) ?? [], plugin]);
|
|
13544
13596
|
}
|
|
13545
13597
|
}
|
|
@@ -13577,8 +13629,8 @@ function formatCollisions(collisions) {
|
|
|
13577
13629
|
// src/scripts/check-plugin-collisions.ts
|
|
13578
13630
|
async function runPluginCollisionCheck() {
|
|
13579
13631
|
const root = (await execa("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
|
|
13580
|
-
const servicesDir =
|
|
13581
|
-
if (!
|
|
13632
|
+
const servicesDir = join62(root, "services");
|
|
13633
|
+
if (!existsSync52(servicesDir)) {
|
|
13582
13634
|
console.log("\u2713 plugin collision guard: no services/ directory \u2014 nothing to compare");
|
|
13583
13635
|
return;
|
|
13584
13636
|
}
|
|
@@ -13595,8 +13647,8 @@ async function runPluginCollisionCheck() {
|
|
|
13595
13647
|
}
|
|
13596
13648
|
|
|
13597
13649
|
// src/lib/plugin-terraform-guard.ts
|
|
13598
|
-
import { existsSync as
|
|
13599
|
-
import { dirname as dirname10, join as
|
|
13650
|
+
import { existsSync as existsSync53, readFileSync as readFileSync41, readdirSync as readdirSync25 } from "fs";
|
|
13651
|
+
import { dirname as dirname10, join as join63, relative as relative10, sep as sep4 } from "path";
|
|
13600
13652
|
var SKIP_DIRS4 = /* @__PURE__ */ new Set(["node_modules", ".git", ".worktrees", "dist", ".venv", "__pycache__"]);
|
|
13601
13653
|
var PLUGIN_MANIFEST_FILE2 = "biffo.plugin.json";
|
|
13602
13654
|
function findPluginManifests(root) {
|
|
@@ -13611,9 +13663,9 @@ function findPluginManifests(root) {
|
|
|
13611
13663
|
for (const entry of entries) {
|
|
13612
13664
|
if (entry.isDirectory()) {
|
|
13613
13665
|
if (SKIP_DIRS4.has(entry.name)) continue;
|
|
13614
|
-
walk2(
|
|
13666
|
+
walk2(join63(dir, entry.name));
|
|
13615
13667
|
} else if (entry.isFile() && entry.name === PLUGIN_MANIFEST_FILE2) {
|
|
13616
|
-
found.push(relative10(root,
|
|
13668
|
+
found.push(relative10(root, join63(dir, entry.name)).split(sep4).join("/"));
|
|
13617
13669
|
}
|
|
13618
13670
|
}
|
|
13619
13671
|
};
|
|
@@ -13638,14 +13690,14 @@ function readSubscriptions(absManifestPath) {
|
|
|
13638
13690
|
}
|
|
13639
13691
|
function checkPluginTerraform(root) {
|
|
13640
13692
|
const violations = [];
|
|
13641
|
-
const coreManifest =
|
|
13693
|
+
const coreManifest = existsSync53(join63(root, CORE_MANIFEST_FILE)) ? readCoreManifest(root) : null;
|
|
13642
13694
|
for (const manifest of findPluginManifests(root)) {
|
|
13643
13695
|
if (coreManifest && !isTemplateOwned(manifest, coreManifest)) continue;
|
|
13644
|
-
const absManifest =
|
|
13696
|
+
const absManifest = join63(root, manifest);
|
|
13645
13697
|
const subscriptions = readSubscriptions(absManifest);
|
|
13646
13698
|
if (subscriptions === null) continue;
|
|
13647
13699
|
const pluginDir2 = dirname10(absManifest);
|
|
13648
|
-
if (
|
|
13700
|
+
if (existsSync53(join63(pluginDir2, "terraform"))) continue;
|
|
13649
13701
|
const relPluginDir = relative10(root, pluginDir2).split(sep4).join("/");
|
|
13650
13702
|
violations.push({
|
|
13651
13703
|
manifest,
|
|
@@ -13676,12 +13728,12 @@ async function runPluginTerraformCheck() {
|
|
|
13676
13728
|
}
|
|
13677
13729
|
|
|
13678
13730
|
// src/scripts/check-plugin-tool-supply.ts
|
|
13679
|
-
import { existsSync as
|
|
13680
|
-
import { join as
|
|
13731
|
+
import { existsSync as existsSync55 } from "fs";
|
|
13732
|
+
import { join as join65 } from "path";
|
|
13681
13733
|
|
|
13682
13734
|
// src/lib/plugin-tool-supply-audit.ts
|
|
13683
|
-
import { existsSync as
|
|
13684
|
-
import { join as
|
|
13735
|
+
import { existsSync as existsSync54, readFileSync as readFileSync42, readdirSync as readdirSync26, statSync as statSync16 } from "fs";
|
|
13736
|
+
import { join as join64 } from "path";
|
|
13685
13737
|
|
|
13686
13738
|
// src/lib/openrouter-model-snapshot.ts
|
|
13687
13739
|
var OPENROUTER_MODEL_SNAPSHOT_FETCHED_AT = "2026-08-10T06:39:01Z";
|
|
@@ -14098,7 +14150,7 @@ function listDirs(root) {
|
|
|
14098
14150
|
}
|
|
14099
14151
|
return entries.filter((e) => {
|
|
14100
14152
|
try {
|
|
14101
|
-
return statSync16(
|
|
14153
|
+
return statSync16(join64(root, e)).isDirectory();
|
|
14102
14154
|
} catch {
|
|
14103
14155
|
return false;
|
|
14104
14156
|
}
|
|
@@ -14114,7 +14166,7 @@ function walkFiles2(root, accept, skipDir) {
|
|
|
14114
14166
|
return;
|
|
14115
14167
|
}
|
|
14116
14168
|
for (const entry of entries) {
|
|
14117
|
-
const p =
|
|
14169
|
+
const p = join64(dir, entry);
|
|
14118
14170
|
let st;
|
|
14119
14171
|
try {
|
|
14120
14172
|
st = statSync16(p);
|
|
@@ -14140,14 +14192,14 @@ function pluginPythonFiles(pluginDir2) {
|
|
|
14140
14192
|
);
|
|
14141
14193
|
}
|
|
14142
14194
|
function pluginTerraformFiles(pluginDir2) {
|
|
14143
|
-
const tfDir =
|
|
14195
|
+
const tfDir = join64(pluginDir2, "terraform");
|
|
14144
14196
|
let entries;
|
|
14145
14197
|
try {
|
|
14146
14198
|
entries = readdirSync26(tfDir);
|
|
14147
14199
|
} catch {
|
|
14148
14200
|
return [];
|
|
14149
14201
|
}
|
|
14150
|
-
return entries.filter((e) => e.endsWith(".tf")).map((e) =>
|
|
14202
|
+
return entries.filter((e) => e.endsWith(".tf")).map((e) => join64(tfDir, e)).sort();
|
|
14151
14203
|
}
|
|
14152
14204
|
function extractManifestTools(manifestText) {
|
|
14153
14205
|
let parsed;
|
|
@@ -14399,8 +14451,8 @@ function isSnapshotStale(fetchedAt, now) {
|
|
|
14399
14451
|
function normalizeModelId(id) {
|
|
14400
14452
|
return id.endsWith(":online") ? id.slice(0, -":online".length) : id;
|
|
14401
14453
|
}
|
|
14402
|
-
var CONFIG_PY_PATH =
|
|
14403
|
-
var ORCHESTRATION_SCHEMA_PATH =
|
|
14454
|
+
var CONFIG_PY_PATH = join64("services", "api", "src", "api", "config.py");
|
|
14455
|
+
var ORCHESTRATION_SCHEMA_PATH = join64(
|
|
14404
14456
|
"services",
|
|
14405
14457
|
"api",
|
|
14406
14458
|
"src",
|
|
@@ -14412,10 +14464,10 @@ function auditDeclaredModelIds(repoRoot, options = {}) {
|
|
|
14412
14464
|
const knownModelIds = options.knownModelIds ?? OPENROUTER_MODEL_IDS;
|
|
14413
14465
|
const snapshotFetchedAt = options.snapshotFetchedAt ?? OPENROUTER_MODEL_SNAPSHOT_FETCHED_AT;
|
|
14414
14466
|
const now = options.now ?? /* @__PURE__ */ new Date();
|
|
14415
|
-
const configPath =
|
|
14416
|
-
const orchestrationPath =
|
|
14417
|
-
const configMissing = !
|
|
14418
|
-
const orchestrationSchemaMissing = !
|
|
14467
|
+
const configPath = join64(repoRoot, CONFIG_PY_PATH);
|
|
14468
|
+
const orchestrationPath = join64(repoRoot, ORCHESTRATION_SCHEMA_PATH);
|
|
14469
|
+
const configMissing = !existsSync54(configPath);
|
|
14470
|
+
const orchestrationSchemaMissing = !existsSync54(orchestrationPath);
|
|
14419
14471
|
const knownSet = new Set(knownModelIds);
|
|
14420
14472
|
const snapshotEmpty = knownModelIds.length === 0;
|
|
14421
14473
|
const snapshotStale = isSnapshotStale(snapshotFetchedAt, now);
|
|
@@ -14486,7 +14538,7 @@ function auditDeclaredModelIds(repoRoot, options = {}) {
|
|
|
14486
14538
|
function discoverPluginDirs(pluginsRoot) {
|
|
14487
14539
|
return listDirs(pluginsRoot).filter((name) => {
|
|
14488
14540
|
try {
|
|
14489
|
-
return statSync16(
|
|
14541
|
+
return statSync16(join64(pluginsRoot, name, "biffo.plugin.json")).isFile();
|
|
14490
14542
|
} catch {
|
|
14491
14543
|
return false;
|
|
14492
14544
|
}
|
|
@@ -14499,8 +14551,8 @@ function auditPluginToolSupply(pluginsRoot) {
|
|
|
14499
14551
|
let terraformBlind = false;
|
|
14500
14552
|
let totalDeclaredTools = 0;
|
|
14501
14553
|
for (const name of pluginNames) {
|
|
14502
|
-
const pluginDir2 =
|
|
14503
|
-
const manifestText = readFileSync42(
|
|
14554
|
+
const pluginDir2 = join64(pluginsRoot, name);
|
|
14555
|
+
const manifestText = readFileSync42(join64(pluginDir2, "biffo.plugin.json"), "utf8");
|
|
14504
14556
|
const manifest = extractManifestTools(manifestText);
|
|
14505
14557
|
if (manifest.parseError) {
|
|
14506
14558
|
findings.push({
|
|
@@ -14598,7 +14650,7 @@ function auditPluginToolSupply(pluginsRoot) {
|
|
|
14598
14650
|
requiredEnvVars: envResult.envVars,
|
|
14599
14651
|
missingEnvVars: anyWired ? [] : envResult.envVars,
|
|
14600
14652
|
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 ${
|
|
14653
|
+
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
14654
|
});
|
|
14603
14655
|
}
|
|
14604
14656
|
}
|
|
@@ -14631,8 +14683,8 @@ function auditPluginToolSupply(pluginsRoot) {
|
|
|
14631
14683
|
async function runPluginToolSupplyCheck() {
|
|
14632
14684
|
const root = (await execa("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
|
|
14633
14685
|
let allOk = true;
|
|
14634
|
-
const pluginsRoot =
|
|
14635
|
-
if (!
|
|
14686
|
+
const pluginsRoot = join65(root, "services", "_plugins");
|
|
14687
|
+
if (!existsSync55(pluginsRoot)) {
|
|
14636
14688
|
console.log("\u2713 plugin tool-supply guard: no services/_plugins/ \u2014 nothing to audit");
|
|
14637
14689
|
} else {
|
|
14638
14690
|
const report = auditPluginToolSupply(pluginsRoot);
|
|
@@ -14662,8 +14714,8 @@ async function runPluginToolSupplyCheck() {
|
|
|
14662
14714
|
console.log(`\u2713 plugin tool-supply guard: ${report.summary}`);
|
|
14663
14715
|
}
|
|
14664
14716
|
}
|
|
14665
|
-
const servicesApiRoot =
|
|
14666
|
-
if (!
|
|
14717
|
+
const servicesApiRoot = join65(root, "services", "api");
|
|
14718
|
+
if (!existsSync55(servicesApiRoot)) {
|
|
14667
14719
|
console.log("\u2713 plugin model-id guard: no services/api/ \u2014 nothing to audit");
|
|
14668
14720
|
} else {
|
|
14669
14721
|
const modelReport = auditDeclaredModelIds(root);
|
|
@@ -15040,12 +15092,12 @@ async function runSharedFileReductionCheck(args) {
|
|
|
15040
15092
|
}
|
|
15041
15093
|
|
|
15042
15094
|
// src/scripts/check-skeleton-drift.ts
|
|
15043
|
-
import { existsSync as
|
|
15044
|
-
import { join as
|
|
15095
|
+
import { existsSync as existsSync56, readdirSync as readdirSync28 } from "fs";
|
|
15096
|
+
import { join as join67 } from "path";
|
|
15045
15097
|
|
|
15046
15098
|
// src/lib/skeleton-drift-guard.ts
|
|
15047
15099
|
import { readFileSync as readFileSync45, readdirSync as readdirSync27, statSync as statSync17 } from "fs";
|
|
15048
|
-
import { join as
|
|
15100
|
+
import { join as join66 } from "path";
|
|
15049
15101
|
var isWorkflow = (rel) => rel.startsWith(".github/workflows/") && (rel.endsWith(".yml") || rel.endsWith(".yaml"));
|
|
15050
15102
|
var isRootLayout = (rel) => rel.endsWith("src/app/layout.tsx");
|
|
15051
15103
|
var uncommented = (contents) => contents.split("\n").filter((line) => !/^\s*(\/\/|\/\*|\*)/.test(line)).join("\n");
|
|
@@ -15109,7 +15161,7 @@ function walk(dir, base = dir) {
|
|
|
15109
15161
|
}
|
|
15110
15162
|
for (const entry of entries) {
|
|
15111
15163
|
if (entry === ".venv" || entry === "node_modules" || entry === ".git") continue;
|
|
15112
|
-
const abs =
|
|
15164
|
+
const abs = join66(dir, entry);
|
|
15113
15165
|
let isDir;
|
|
15114
15166
|
try {
|
|
15115
15167
|
isDir = statSync17(abs).isDirectory();
|
|
@@ -15131,7 +15183,7 @@ function auditSkeleton(skeletonRoot, name, rules = SKELETON_RULES) {
|
|
|
15131
15183
|
if (!rule.appliesTo(rel)) continue;
|
|
15132
15184
|
let contents;
|
|
15133
15185
|
try {
|
|
15134
|
-
contents = readFileSync45(
|
|
15186
|
+
contents = readFileSync45(join66(skeletonRoot, rel), "utf8");
|
|
15135
15187
|
} catch {
|
|
15136
15188
|
continue;
|
|
15137
15189
|
}
|
|
@@ -15160,23 +15212,23 @@ function formatViolations2(violations) {
|
|
|
15160
15212
|
|
|
15161
15213
|
// src/scripts/check-skeleton-drift.ts
|
|
15162
15214
|
function discoverSkeletons(root) {
|
|
15163
|
-
const skeletonsDir =
|
|
15215
|
+
const skeletonsDir = join67(root, "_skeletons");
|
|
15164
15216
|
let entries;
|
|
15165
15217
|
try {
|
|
15166
15218
|
entries = readdirSync28(skeletonsDir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
|
|
15167
15219
|
} catch {
|
|
15168
15220
|
return [];
|
|
15169
15221
|
}
|
|
15170
|
-
return entries.filter((name) =>
|
|
15222
|
+
return entries.filter((name) => existsSync56(join67(skeletonsDir, name, ".github", "workflows", "ci.yml"))).sort();
|
|
15171
15223
|
}
|
|
15172
15224
|
async function runSkeletonDriftCheck() {
|
|
15173
15225
|
const root = (await execa("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
|
|
15174
15226
|
const skeletons = discoverSkeletons(root);
|
|
15175
15227
|
let filesConsidered = 0;
|
|
15176
15228
|
for (const name of skeletons) {
|
|
15177
|
-
const skeletonRoot =
|
|
15229
|
+
const skeletonRoot = join67(root, "_skeletons", name);
|
|
15178
15230
|
filesConsidered += findWorkflowFiles(skeletonRoot).length;
|
|
15179
|
-
if (
|
|
15231
|
+
if (existsSync56(join67(skeletonRoot, "apps", "frontend", "src", "app", "layout.tsx"))) {
|
|
15180
15232
|
filesConsidered += 1;
|
|
15181
15233
|
}
|
|
15182
15234
|
}
|
|
@@ -15184,13 +15236,19 @@ async function runSkeletonDriftCheck() {
|
|
|
15184
15236
|
`audited ${skeletons.length} skeleton(s) (${skeletons.join(", ") || "none"}), ${filesConsidered} file(s) considered, under ${root}/_skeletons`
|
|
15185
15237
|
);
|
|
15186
15238
|
if (skeletons.length === 0) {
|
|
15239
|
+
if (!existsSync56(join67(root, "_skeletons"))) {
|
|
15240
|
+
console.log(
|
|
15241
|
+
`\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.`
|
|
15242
|
+
);
|
|
15243
|
+
return;
|
|
15244
|
+
}
|
|
15187
15245
|
console.error(
|
|
15188
15246
|
"\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
15247
|
);
|
|
15190
15248
|
process.exit(1);
|
|
15191
15249
|
}
|
|
15192
15250
|
const violations = skeletons.flatMap(
|
|
15193
|
-
(name) => auditSkeleton(
|
|
15251
|
+
(name) => auditSkeleton(join67(root, "_skeletons", name), name)
|
|
15194
15252
|
);
|
|
15195
15253
|
if (violations.length > 0) {
|
|
15196
15254
|
console.error("\u2717 Skeleton-drift guard: drift found between this repo and its scaffolding\n");
|
|
@@ -15386,8 +15444,8 @@ function rawArgsAfter(subcommand) {
|
|
|
15386
15444
|
}
|
|
15387
15445
|
|
|
15388
15446
|
// src/commands/doctor.ts
|
|
15389
|
-
import { existsSync as
|
|
15390
|
-
import { join as
|
|
15447
|
+
import { existsSync as existsSync57, readFileSync as readFileSync46 } from "fs";
|
|
15448
|
+
import { join as join68, resolve as resolve20 } from "path";
|
|
15391
15449
|
import chalk21 from "chalk";
|
|
15392
15450
|
import { Command as Command25 } from "commander";
|
|
15393
15451
|
|
|
@@ -15782,8 +15840,8 @@ async function runDoctorFixBranches(cwd, facts, deps = { git: new GitAdapter(),
|
|
|
15782
15840
|
return reapAllBareBranches(cwd, facts.branches, facts.worktrees, facts.currentBranch, deps);
|
|
15783
15841
|
}
|
|
15784
15842
|
function readLocalCoreVersion(cwd) {
|
|
15785
|
-
const path =
|
|
15786
|
-
if (!
|
|
15843
|
+
const path = join68(cwd, INSTANCE_CORE_FILE);
|
|
15844
|
+
if (!existsSync57(path)) return null;
|
|
15787
15845
|
try {
|
|
15788
15846
|
return extractVersionField(readFileSync46(path, "utf8"));
|
|
15789
15847
|
} catch {
|
|
@@ -15805,8 +15863,8 @@ function extractVersionField(contents) {
|
|
|
15805
15863
|
return match?.[1] ?? null;
|
|
15806
15864
|
}
|
|
15807
15865
|
function readFossil(cwd) {
|
|
15808
|
-
const path =
|
|
15809
|
-
if (!
|
|
15866
|
+
const path = join68(cwd, CORE_VERSION_FILE);
|
|
15867
|
+
if (!existsSync57(path)) return null;
|
|
15810
15868
|
try {
|
|
15811
15869
|
const value = readFileSync46(path, "utf8").trim();
|
|
15812
15870
|
return value === "" ? null : value;
|
|
@@ -16337,13 +16395,13 @@ import { fileURLToPath as fileURLToPath6 } from "url";
|
|
|
16337
16395
|
import { Command as Command27 } from "commander";
|
|
16338
16396
|
|
|
16339
16397
|
// src/lib/packaged-scripts.ts
|
|
16340
|
-
import { existsSync as
|
|
16341
|
-
import { dirname as dirname11, join as
|
|
16398
|
+
import { existsSync as existsSync58 } from "fs";
|
|
16399
|
+
import { dirname as dirname11, join as join69 } from "path";
|
|
16342
16400
|
function findPackagedScript(startDir, relativePath) {
|
|
16343
16401
|
let dir = startDir;
|
|
16344
16402
|
for (; ; ) {
|
|
16345
|
-
const candidate =
|
|
16346
|
-
if (
|
|
16403
|
+
const candidate = join69(dir, relativePath);
|
|
16404
|
+
if (existsSync58(candidate)) return candidate;
|
|
16347
16405
|
const parent = dirname11(dir);
|
|
16348
16406
|
if (parent === dir) return null;
|
|
16349
16407
|
dir = parent;
|