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