@biffo/cli 0.273.7 → 0.273.9
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 +209 -174
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -8380,8 +8380,8 @@ function printEntry(entry) {
|
|
|
8380
8380
|
}
|
|
8381
8381
|
|
|
8382
8382
|
// src/commands/plugin-install.ts
|
|
8383
|
-
import { cpSync as
|
|
8384
|
-
import {
|
|
8383
|
+
import { cpSync as cpSync4, existsSync as existsSync28, mkdirSync as mkdirSync10, readFileSync as readFileSync21, statSync as statSync6 } from "fs";
|
|
8384
|
+
import { join as join30, relative as relative3, resolve as resolve12 } from "path";
|
|
8385
8385
|
import chalk15 from "chalk";
|
|
8386
8386
|
import { Command as Command15 } from "commander";
|
|
8387
8387
|
|
|
@@ -8427,9 +8427,61 @@ var PluginMigrationsAdapter = class {
|
|
|
8427
8427
|
}
|
|
8428
8428
|
};
|
|
8429
8429
|
|
|
8430
|
+
// src/lib/plugin-source-copy.ts
|
|
8431
|
+
import { copyFileSync as copyFileSync2, cpSync as cpSync3, mkdirSync as mkdirSync9 } from "fs";
|
|
8432
|
+
import { basename, dirname as dirname9, join as join28 } from "path";
|
|
8433
|
+
import { execa as execa5 } from "execa";
|
|
8434
|
+
var LOCAL_COPY_EXCLUDES = /* @__PURE__ */ new Set([
|
|
8435
|
+
".git",
|
|
8436
|
+
".venv",
|
|
8437
|
+
"node_modules",
|
|
8438
|
+
"__pycache__",
|
|
8439
|
+
".ruff_cache",
|
|
8440
|
+
".pytest_cache",
|
|
8441
|
+
".mypy_cache",
|
|
8442
|
+
"dist",
|
|
8443
|
+
".terraform"
|
|
8444
|
+
]);
|
|
8445
|
+
async function copyPluginSource(sourceDir, targetDir) {
|
|
8446
|
+
if (await isGitWorkingTree(sourceDir)) {
|
|
8447
|
+
const files = await listGitFiles(sourceDir);
|
|
8448
|
+
for (const relPath of files) {
|
|
8449
|
+
const destPath = join28(targetDir, relPath);
|
|
8450
|
+
mkdirSync9(dirname9(destPath), { recursive: true });
|
|
8451
|
+
copyFileSync2(join28(sourceDir, relPath), destPath);
|
|
8452
|
+
}
|
|
8453
|
+
return { usedGitIgnoreRules: true };
|
|
8454
|
+
}
|
|
8455
|
+
log.warn(
|
|
8456
|
+
`${sourceDir} is not a git working tree \u2014 cannot honour .gitignore. Falling back to a fixed exclude list (.git, .venv, node_modules, caches); anything else it does not know about (e.g. an unfamiliar cache directory) will be copied.`
|
|
8457
|
+
);
|
|
8458
|
+
mkdirSync9(targetDir, { recursive: true });
|
|
8459
|
+
cpSync3(sourceDir, targetDir, {
|
|
8460
|
+
recursive: true,
|
|
8461
|
+
filter: (src) => !LOCAL_COPY_EXCLUDES.has(basename(src))
|
|
8462
|
+
});
|
|
8463
|
+
return { usedGitIgnoreRules: false };
|
|
8464
|
+
}
|
|
8465
|
+
async function isGitWorkingTree(dir) {
|
|
8466
|
+
try {
|
|
8467
|
+
await execa5("git", ["rev-parse", "--is-inside-work-tree"], { cwd: dir });
|
|
8468
|
+
return true;
|
|
8469
|
+
} catch {
|
|
8470
|
+
return false;
|
|
8471
|
+
}
|
|
8472
|
+
}
|
|
8473
|
+
async function listGitFiles(dir) {
|
|
8474
|
+
const { stdout } = await execa5(
|
|
8475
|
+
"git",
|
|
8476
|
+
["ls-files", "--cached", "--others", "--exclude-standard", "-z"],
|
|
8477
|
+
{ cwd: dir }
|
|
8478
|
+
);
|
|
8479
|
+
return stdout.split("\0").filter((p) => p.length > 0);
|
|
8480
|
+
}
|
|
8481
|
+
|
|
8430
8482
|
// src/lib/plugin-workspace-sources.ts
|
|
8431
8483
|
import { existsSync as existsSync27, readdirSync as readdirSync12, readFileSync as readFileSync20, writeFileSync as writeFileSync10 } from "fs";
|
|
8432
|
-
import { join as
|
|
8484
|
+
import { join as join29 } from "path";
|
|
8433
8485
|
function readTomlStringArray(text, key) {
|
|
8434
8486
|
const open = new RegExp(`^${key}\\s*=\\s*\\[`, "m").exec(text);
|
|
8435
8487
|
if (!open) return [];
|
|
@@ -8473,7 +8525,7 @@ function readDependencyNames(text) {
|
|
|
8473
8525
|
return readTomlStringArray(text, "dependencies").map((dep) => /^\s*([A-Za-z0-9._-]+)/.exec(dep)?.[1] ?? "").filter(Boolean);
|
|
8474
8526
|
}
|
|
8475
8527
|
function workspaceMemberNames(instanceRoot) {
|
|
8476
|
-
const rootPyproject =
|
|
8528
|
+
const rootPyproject = join29(instanceRoot, "pyproject.toml");
|
|
8477
8529
|
if (!existsSync27(rootPyproject)) return /* @__PURE__ */ new Set();
|
|
8478
8530
|
const text = readFileSync20(rootPyproject, "utf8");
|
|
8479
8531
|
const members = readTomlStringArray(text, "members");
|
|
@@ -8484,7 +8536,7 @@ function workspaceMemberNames(instanceRoot) {
|
|
|
8484
8536
|
const base = member.slice(0, -2);
|
|
8485
8537
|
let entries;
|
|
8486
8538
|
try {
|
|
8487
|
-
entries = readdirSync12(
|
|
8539
|
+
entries = readdirSync12(join29(instanceRoot, base), { withFileTypes: true });
|
|
8488
8540
|
} catch {
|
|
8489
8541
|
continue;
|
|
8490
8542
|
}
|
|
@@ -8498,7 +8550,7 @@ function workspaceMemberNames(instanceRoot) {
|
|
|
8498
8550
|
}
|
|
8499
8551
|
const names = /* @__PURE__ */ new Set();
|
|
8500
8552
|
for (const dir of dirs) {
|
|
8501
|
-
const pp =
|
|
8553
|
+
const pp = join29(instanceRoot, dir, "pyproject.toml");
|
|
8502
8554
|
if (!existsSync27(pp)) continue;
|
|
8503
8555
|
const name = readProjectName(readFileSync20(pp, "utf8"));
|
|
8504
8556
|
if (name) names.add(name);
|
|
@@ -8536,7 +8588,7 @@ ${lines.join("\n")}
|
|
|
8536
8588
|
return toAdd;
|
|
8537
8589
|
}
|
|
8538
8590
|
function applyWorkspaceSources(targetDir, cwd, relTargetDir) {
|
|
8539
|
-
const pluginPyproject =
|
|
8591
|
+
const pluginPyproject = join29(targetDir, "pyproject.toml");
|
|
8540
8592
|
if (!existsSync27(pluginPyproject)) return;
|
|
8541
8593
|
const sourced = ensureWorkspaceSources(pluginPyproject, workspaceMemberNames(cwd));
|
|
8542
8594
|
if (sourced.length > 0) {
|
|
@@ -8576,17 +8628,6 @@ var pluginInstallCommand = new Command15("install").description(
|
|
|
8576
8628
|
}
|
|
8577
8629
|
}
|
|
8578
8630
|
);
|
|
8579
|
-
var LOCAL_COPY_EXCLUDES = /* @__PURE__ */ new Set([
|
|
8580
|
-
".git",
|
|
8581
|
-
".venv",
|
|
8582
|
-
"node_modules",
|
|
8583
|
-
"__pycache__",
|
|
8584
|
-
".ruff_cache",
|
|
8585
|
-
".pytest_cache",
|
|
8586
|
-
".mypy_cache",
|
|
8587
|
-
"dist",
|
|
8588
|
-
".terraform"
|
|
8589
|
-
]);
|
|
8590
8631
|
function resolveLocalPlugin(localPath) {
|
|
8591
8632
|
if (!existsSync28(localPath)) {
|
|
8592
8633
|
throw new Error(`--local path does not exist: ${localPath}`);
|
|
@@ -8594,7 +8635,7 @@ function resolveLocalPlugin(localPath) {
|
|
|
8594
8635
|
if (!statSync6(localPath).isDirectory()) {
|
|
8595
8636
|
throw new Error(`--local path is not a directory: ${localPath}`);
|
|
8596
8637
|
}
|
|
8597
|
-
const manifestPath =
|
|
8638
|
+
const manifestPath = join30(localPath, "biffo.plugin.json");
|
|
8598
8639
|
if (!existsSync28(manifestPath)) {
|
|
8599
8640
|
throw new Error(
|
|
8600
8641
|
`${localPath} does not contain a biffo.plugin.json manifest at its root \u2014 is it a plugin directory? (Scaffold one with \`biffo plugin create <name>\`.)`
|
|
@@ -8621,7 +8662,7 @@ function parsePluginTarget(target) {
|
|
|
8621
8662
|
async function cloneAndValidatePlugin(entry, git) {
|
|
8622
8663
|
const tmpDir = await git.cloneToTemp(entry.repo, `biffo-plugin-${entry.name}`);
|
|
8623
8664
|
try {
|
|
8624
|
-
const manifestPath =
|
|
8665
|
+
const manifestPath = join30(tmpDir, "biffo.plugin.json");
|
|
8625
8666
|
if (!existsSync28(manifestPath)) {
|
|
8626
8667
|
throw new Error(
|
|
8627
8668
|
`Plugin repo ${entry.repo} does not contain a biffo.plugin.json manifest at its root.`
|
|
@@ -8650,7 +8691,7 @@ async function runPluginInstall(target, options, deps) {
|
|
|
8650
8691
|
`Nothing to install. Pass a registry target (e.g. \`biffo plugin install acme-crm@1.0\`) or a local plugin directory (\`biffo plugin install --local services/acme-crm\`).`
|
|
8651
8692
|
);
|
|
8652
8693
|
}
|
|
8653
|
-
const servicesDir =
|
|
8694
|
+
const servicesDir = join30(options.cwd, "services");
|
|
8654
8695
|
if (!existsSync28(servicesDir)) {
|
|
8655
8696
|
throw new Error(
|
|
8656
8697
|
`${servicesDir} does not exist \u2014 is ${options.cwd} the root of a Biffo project checkout?`
|
|
@@ -8669,8 +8710,8 @@ async function runPluginInstall(target, options, deps) {
|
|
|
8669
8710
|
}
|
|
8670
8711
|
const pluginName = entry ? entry.name : source.name;
|
|
8671
8712
|
const relTargetDir = pluginDir(pluginName, "third-party");
|
|
8672
|
-
const targetDir =
|
|
8673
|
-
const modulesDir =
|
|
8713
|
+
const targetDir = join30(options.cwd, relTargetDir);
|
|
8714
|
+
const modulesDir = join30(options.cwd, "modules", "plugins", pluginName);
|
|
8674
8715
|
const inTreeSource = options.local !== void 0 && resolve12(options.local) === resolve12(targetDir);
|
|
8675
8716
|
if (existsSync28(targetDir) && !inTreeSource) {
|
|
8676
8717
|
throw new Error(
|
|
@@ -8707,19 +8748,16 @@ async function runPluginInstall(target, options, deps) {
|
|
|
8707
8748
|
if (inTreeSource) {
|
|
8708
8749
|
log.info(`${relTargetDir}/ is already in this checkout \u2014 installing in place.`);
|
|
8709
8750
|
} else {
|
|
8710
|
-
|
|
8711
|
-
|
|
8712
|
-
recursive: true,
|
|
8713
|
-
filter: (src) => !LOCAL_COPY_EXCLUDES.has(basename(src))
|
|
8714
|
-
});
|
|
8751
|
+
mkdirSync10(targetDir, { recursive: true });
|
|
8752
|
+
await copyPluginSource(source.sourceDir, targetDir);
|
|
8715
8753
|
log.success(`Installed plugin source at ${relTargetDir}/`);
|
|
8716
8754
|
}
|
|
8717
8755
|
applyWorkspaceSources(targetDir, options.cwd, relTargetDir);
|
|
8718
8756
|
const stagePaths = [relTargetDir];
|
|
8719
|
-
const tfSourceDir =
|
|
8757
|
+
const tfSourceDir = join30(targetDir, "terraform");
|
|
8720
8758
|
if (existsSync28(tfSourceDir)) {
|
|
8721
|
-
|
|
8722
|
-
|
|
8759
|
+
mkdirSync10(modulesDir, { recursive: true });
|
|
8760
|
+
cpSync4(tfSourceDir, modulesDir, { recursive: true });
|
|
8723
8761
|
stagePaths.push(`modules/plugins/${pluginName}`);
|
|
8724
8762
|
log.success(`Copied Terraform module to modules/plugins/${pluginName}/`);
|
|
8725
8763
|
const wiring = syncPluginTerraform(options.cwd);
|
|
@@ -8812,7 +8850,7 @@ function printDryRun4(entry, source, relTargetDir, inTreeSource) {
|
|
|
8812
8850
|
|
|
8813
8851
|
// src/commands/plugin-list.ts
|
|
8814
8852
|
import { existsSync as existsSync29, readFileSync as readFileSync22 } from "fs";
|
|
8815
|
-
import { join as
|
|
8853
|
+
import { join as join31, resolve as resolve13 } from "path";
|
|
8816
8854
|
import chalk16 from "chalk";
|
|
8817
8855
|
import { Command as Command16 } from "commander";
|
|
8818
8856
|
var pluginListCommand = new Command16("list").description("List plugins installed in this project checkout").option("--cwd <path>", "Project root to scan (defaults to the current directory)").action(async (options) => {
|
|
@@ -8825,7 +8863,7 @@ var pluginListCommand = new Command16("list").description("List plugins installe
|
|
|
8825
8863
|
}
|
|
8826
8864
|
});
|
|
8827
8865
|
async function runPluginList(options) {
|
|
8828
|
-
const servicesDir =
|
|
8866
|
+
const servicesDir = join31(options.cwd, "services");
|
|
8829
8867
|
if (!existsSync29(servicesDir)) {
|
|
8830
8868
|
throw new Error(
|
|
8831
8869
|
`${servicesDir} does not exist \u2014 is ${options.cwd} the root of a Biffo project checkout?`
|
|
@@ -8872,7 +8910,7 @@ async function runPluginList(options) {
|
|
|
8872
8910
|
|
|
8873
8911
|
// src/commands/plugin-sync-migrations.ts
|
|
8874
8912
|
import { existsSync as existsSync30 } from "fs";
|
|
8875
|
-
import { join as
|
|
8913
|
+
import { join as join32, relative as relative4, resolve as resolve14 } from "path";
|
|
8876
8914
|
import chalk17 from "chalk";
|
|
8877
8915
|
import { Command as Command17 } from "commander";
|
|
8878
8916
|
var pluginSyncMigrationsCommand = new Command17("sync-migrations").description(
|
|
@@ -8893,11 +8931,11 @@ var pluginSyncMigrationsCommand = new Command17("sync-migrations").description(
|
|
|
8893
8931
|
}
|
|
8894
8932
|
);
|
|
8895
8933
|
async function runPluginSyncMigrations(name, options, deps) {
|
|
8896
|
-
const servicesDir =
|
|
8934
|
+
const servicesDir = join32(options.cwd, "services");
|
|
8897
8935
|
if (!existsSync30(servicesDir)) {
|
|
8898
8936
|
throw new Error(`${servicesDir} does not exist \u2014 is ${options.cwd} a Biffo project checkout?`);
|
|
8899
8937
|
}
|
|
8900
|
-
if (name && !existsSync30(
|
|
8938
|
+
if (name && !existsSync30(join32(servicesDir, name, "biffo.plugin.json"))) {
|
|
8901
8939
|
throw new Error(`Plugin '${name}' is not installed at services/${name}/.`);
|
|
8902
8940
|
}
|
|
8903
8941
|
if (options.dryRun) {
|
|
@@ -8934,7 +8972,7 @@ async function runPluginSyncMigrations(name, options, deps) {
|
|
|
8934
8972
|
|
|
8935
8973
|
// src/commands/plugin-uninstall.ts
|
|
8936
8974
|
import { existsSync as existsSync31, readFileSync as readFileSync23, rmSync as rmSync8 } from "fs";
|
|
8937
|
-
import { join as
|
|
8975
|
+
import { join as join33, resolve as resolve15 } from "path";
|
|
8938
8976
|
import chalk18 from "chalk";
|
|
8939
8977
|
import { Command as Command18 } from "commander";
|
|
8940
8978
|
import inquirer6 from "inquirer";
|
|
@@ -8966,15 +9004,15 @@ async function runPluginUninstall(name, options, deps) {
|
|
|
8966
9004
|
if (!NAME_PATTERN2.test(name)) {
|
|
8967
9005
|
throw new Error(`Invalid plugin name '${name}'. Expected a lowercase kebab-case slug.`);
|
|
8968
9006
|
}
|
|
8969
|
-
const servicesDir =
|
|
9007
|
+
const servicesDir = join33(options.cwd, "services");
|
|
8970
9008
|
if (!existsSync31(servicesDir)) {
|
|
8971
9009
|
throw new Error(
|
|
8972
9010
|
`${servicesDir} does not exist \u2014 is ${options.cwd} the root of a Biffo project checkout?`
|
|
8973
9011
|
);
|
|
8974
9012
|
}
|
|
8975
|
-
const targetDir =
|
|
9013
|
+
const targetDir = join33(servicesDir, name);
|
|
8976
9014
|
if (!existsSync31(targetDir)) {
|
|
8977
|
-
const firstParty =
|
|
9015
|
+
const firstParty = join33(servicesDir, FIRST_PARTY_PLUGINS_DIR, name);
|
|
8978
9016
|
if (existsSync31(firstParty)) {
|
|
8979
9017
|
throw new Error(
|
|
8980
9018
|
`Plugin '${name}' is a first-party plugin at ${pluginDir(name, "first-party")}/, which is template-owned \u2014 \`biffo core upgrade\` would restore it on the next upgrade. Disable it instead by removing '${name}' from \`enabled_plugins\` in infra/environments/<env>/main.tf and re-applying.`
|
|
@@ -8983,7 +9021,7 @@ async function runPluginUninstall(name, options, deps) {
|
|
|
8983
9021
|
throw new Error(`Plugin '${name}' is not installed at services/${name}/.`);
|
|
8984
9022
|
}
|
|
8985
9023
|
const version = readInstalledVersion(targetDir);
|
|
8986
|
-
const modulesDir =
|
|
9024
|
+
const modulesDir = join33(options.cwd, "modules", "plugins", name);
|
|
8987
9025
|
const stagePaths = [`services/${name}`];
|
|
8988
9026
|
if (existsSync31(modulesDir)) {
|
|
8989
9027
|
stagePaths.push(`modules/plugins/${name}`);
|
|
@@ -9044,7 +9082,7 @@ async function runPluginUninstall(name, options, deps) {
|
|
|
9044
9082
|
}
|
|
9045
9083
|
}
|
|
9046
9084
|
function readInstalledVersion(targetDir) {
|
|
9047
|
-
const manifestPath =
|
|
9085
|
+
const manifestPath = join33(targetDir, "biffo.plugin.json");
|
|
9048
9086
|
if (!existsSync31(manifestPath)) return void 0;
|
|
9049
9087
|
try {
|
|
9050
9088
|
return validateManifest(JSON.parse(readFileSync23(manifestPath, "utf8"))).version;
|
|
@@ -9080,8 +9118,8 @@ function printDryRun5(name, version, stagePaths, keepData) {
|
|
|
9080
9118
|
}
|
|
9081
9119
|
|
|
9082
9120
|
// src/commands/plugin-upgrade.ts
|
|
9083
|
-
import { cpSync as
|
|
9084
|
-
import {
|
|
9121
|
+
import { cpSync as cpSync5, existsSync as existsSync32, mkdirSync as mkdirSync11, readFileSync as readFileSync24, rmSync as rmSync9 } from "fs";
|
|
9122
|
+
import { join as join34, relative as relative5, resolve as resolve16 } from "path";
|
|
9085
9123
|
import chalk19 from "chalk";
|
|
9086
9124
|
import { Command as Command19 } from "commander";
|
|
9087
9125
|
import inquirer7 from "inquirer";
|
|
@@ -9128,7 +9166,7 @@ async function runPluginUpgrade(target, options, deps) {
|
|
|
9128
9166
|
`Nothing to upgrade. Pass a registry target (e.g. \`biffo plugin upgrade acme-crm@1.1\`) or a local checkout to refresh from (\`biffo plugin upgrade --local ../acme-crm\`).`
|
|
9129
9167
|
);
|
|
9130
9168
|
}
|
|
9131
|
-
const servicesDir =
|
|
9169
|
+
const servicesDir = join34(options.cwd, "services");
|
|
9132
9170
|
if (!existsSync32(servicesDir)) {
|
|
9133
9171
|
throw new Error(
|
|
9134
9172
|
`${servicesDir} does not exist \u2014 is ${options.cwd} the root of a Biffo project checkout?`
|
|
@@ -9138,7 +9176,7 @@ async function runPluginUpgrade(target, options, deps) {
|
|
|
9138
9176
|
return runLocalPluginRefresh(options.local, options, deps);
|
|
9139
9177
|
}
|
|
9140
9178
|
const { name, minor } = parsePluginTarget(target);
|
|
9141
|
-
const targetDir =
|
|
9179
|
+
const targetDir = join34(servicesDir, name);
|
|
9142
9180
|
if (!existsSync32(targetDir)) {
|
|
9143
9181
|
throw new Error(
|
|
9144
9182
|
`Plugin '${name}' is not installed at services/${name}/. Use 'biffo plugin install ${name}@${minor}' instead.`
|
|
@@ -9153,7 +9191,7 @@ async function runPluginUpgrade(target, options, deps) {
|
|
|
9153
9191
|
`Plugin declares required_core_version '${entry.required_core_version}'. The CLI cannot verify this against your deployment \u2014 the Core API exposes no version endpoint and services/api/pyproject.toml's version is a static placeholder, not a real release marker. Confirm compatibility yourself before deploying.`
|
|
9154
9192
|
);
|
|
9155
9193
|
}
|
|
9156
|
-
const modulesDir =
|
|
9194
|
+
const modulesDir = join34(options.cwd, "modules", "plugins", entry.name);
|
|
9157
9195
|
if (options.dryRun) {
|
|
9158
9196
|
printDryRun6(entry, currentVersion);
|
|
9159
9197
|
return;
|
|
@@ -9182,18 +9220,18 @@ async function runPluginUpgrade(target, options, deps) {
|
|
|
9182
9220
|
`Manifest valid \u2014 ${manifest.tables.length} table(s), ${manifest.api_routes.length} route(s)`
|
|
9183
9221
|
);
|
|
9184
9222
|
rmSync9(targetDir, { recursive: true, force: true });
|
|
9185
|
-
|
|
9186
|
-
|
|
9223
|
+
mkdirSync11(targetDir, { recursive: true });
|
|
9224
|
+
cpSync5(tmpDir, targetDir, { recursive: true });
|
|
9187
9225
|
log.success(`Upgraded plugin source at services/${entry.name}/`);
|
|
9188
9226
|
applyWorkspaceSources(targetDir, options.cwd, `services/${entry.name}`);
|
|
9189
9227
|
const stagePaths = [`services/${entry.name}`];
|
|
9190
9228
|
if (existsSync32(modulesDir)) {
|
|
9191
9229
|
rmSync9(modulesDir, { recursive: true, force: true });
|
|
9192
9230
|
}
|
|
9193
|
-
const tfSourceDir =
|
|
9231
|
+
const tfSourceDir = join34(targetDir, "terraform");
|
|
9194
9232
|
if (existsSync32(tfSourceDir)) {
|
|
9195
|
-
|
|
9196
|
-
|
|
9233
|
+
mkdirSync11(modulesDir, { recursive: true });
|
|
9234
|
+
cpSync5(tfSourceDir, modulesDir, { recursive: true });
|
|
9197
9235
|
stagePaths.push(`modules/plugins/${entry.name}`);
|
|
9198
9236
|
log.success(`Copied Terraform module to modules/plugins/${entry.name}/`);
|
|
9199
9237
|
}
|
|
@@ -9227,8 +9265,8 @@ async function runPluginUpgrade(target, options, deps) {
|
|
|
9227
9265
|
async function runLocalPluginRefresh(localPath, options, deps) {
|
|
9228
9266
|
const source = resolveLocalPlugin(localPath);
|
|
9229
9267
|
log.success(`Resolved ${source.name}@${source.version} from ${source.origin}`);
|
|
9230
|
-
const servicesDir =
|
|
9231
|
-
const targetDir =
|
|
9268
|
+
const servicesDir = join34(options.cwd, "services");
|
|
9269
|
+
const targetDir = join34(servicesDir, source.name);
|
|
9232
9270
|
if (!existsSync32(targetDir)) {
|
|
9233
9271
|
throw new Error(
|
|
9234
9272
|
`Plugin '${source.name}' is not installed at services/${source.name}/. Use 'biffo plugin install --local ${localPath}' instead.`
|
|
@@ -9236,7 +9274,7 @@ async function runLocalPluginRefresh(localPath, options, deps) {
|
|
|
9236
9274
|
}
|
|
9237
9275
|
const inTreeSource = resolve16(source.sourceDir) === resolve16(targetDir);
|
|
9238
9276
|
const currentVersion = readInstalledVersion2(targetDir);
|
|
9239
|
-
const modulesDir =
|
|
9277
|
+
const modulesDir = join34(options.cwd, "modules", "plugins", source.name);
|
|
9240
9278
|
if (options.dryRun) {
|
|
9241
9279
|
printLocalDryRun(source, currentVersion, inTreeSource);
|
|
9242
9280
|
return;
|
|
@@ -9265,11 +9303,8 @@ async function runLocalPluginRefresh(localPath, options, deps) {
|
|
|
9265
9303
|
);
|
|
9266
9304
|
} else {
|
|
9267
9305
|
rmSync9(targetDir, { recursive: true, force: true });
|
|
9268
|
-
|
|
9269
|
-
|
|
9270
|
-
recursive: true,
|
|
9271
|
-
filter: (src) => !LOCAL_COPY_EXCLUDES.has(basename2(src))
|
|
9272
|
-
});
|
|
9306
|
+
mkdirSync11(targetDir, { recursive: true });
|
|
9307
|
+
await copyPluginSource(source.sourceDir, targetDir);
|
|
9273
9308
|
log.success(`Refreshed plugin source at services/${source.name}/ from ${source.origin}`);
|
|
9274
9309
|
}
|
|
9275
9310
|
applyWorkspaceSources(targetDir, options.cwd, `services/${source.name}`);
|
|
@@ -9277,10 +9312,10 @@ async function runLocalPluginRefresh(localPath, options, deps) {
|
|
|
9277
9312
|
if (existsSync32(modulesDir)) {
|
|
9278
9313
|
rmSync9(modulesDir, { recursive: true, force: true });
|
|
9279
9314
|
}
|
|
9280
|
-
const tfSourceDir =
|
|
9315
|
+
const tfSourceDir = join34(targetDir, "terraform");
|
|
9281
9316
|
if (existsSync32(tfSourceDir)) {
|
|
9282
|
-
|
|
9283
|
-
|
|
9317
|
+
mkdirSync11(modulesDir, { recursive: true });
|
|
9318
|
+
cpSync5(tfSourceDir, modulesDir, { recursive: true });
|
|
9284
9319
|
stagePaths.push(`modules/plugins/${source.name}`);
|
|
9285
9320
|
log.success(`Refreshed Terraform module at modules/plugins/${source.name}/`);
|
|
9286
9321
|
}
|
|
@@ -9319,7 +9354,7 @@ async function runLocalPluginRefresh(localPath, options, deps) {
|
|
|
9319
9354
|
}
|
|
9320
9355
|
}
|
|
9321
9356
|
function readInstalledVersion2(targetDir) {
|
|
9322
|
-
const manifestPath =
|
|
9357
|
+
const manifestPath = join34(targetDir, "biffo.plugin.json");
|
|
9323
9358
|
if (!existsSync32(manifestPath)) return void 0;
|
|
9324
9359
|
try {
|
|
9325
9360
|
return validateManifest(JSON.parse(readFileSync24(manifestPath, "utf8"))).version;
|
|
@@ -9656,17 +9691,17 @@ import { Command as Command23 } from "commander";
|
|
|
9656
9691
|
|
|
9657
9692
|
// src/scripts/check-adr-numbering.ts
|
|
9658
9693
|
import { existsSync as existsSync35 } from "fs";
|
|
9659
|
-
import { join as
|
|
9660
|
-
import { execa as
|
|
9694
|
+
import { join as join36 } from "path";
|
|
9695
|
+
import { execa as execa6 } from "execa";
|
|
9661
9696
|
|
|
9662
9697
|
// src/lib/adr-numbering-guard.ts
|
|
9663
9698
|
import { existsSync as existsSync34, readdirSync as readdirSync13, readFileSync as readFileSync26 } from "fs";
|
|
9664
|
-
import { join as
|
|
9699
|
+
import { join as join35 } from "path";
|
|
9665
9700
|
var ADR_FILENAME = /^(\d{4})-.+\.md$/;
|
|
9666
9701
|
var ALLOWLIST_FILENAME = ".numbering-allowlist";
|
|
9667
9702
|
var TEMPLATE_ADR_RESERVED_UPTO = "0099";
|
|
9668
9703
|
function readAdrNumberingAllowlist(adrDir) {
|
|
9669
|
-
const path =
|
|
9704
|
+
const path = join35(adrDir, ALLOWLIST_FILENAME);
|
|
9670
9705
|
if (!existsSync34(path)) return /* @__PURE__ */ new Set();
|
|
9671
9706
|
const numbers = /* @__PURE__ */ new Set();
|
|
9672
9707
|
for (const rawLine of readFileSync26(path, "utf8").split("\n")) {
|
|
@@ -9731,8 +9766,8 @@ function formatAdrReservedRangeViolations(violations, reservedUpTo = TEMPLATE_AD
|
|
|
9731
9766
|
|
|
9732
9767
|
// src/scripts/check-adr-numbering.ts
|
|
9733
9768
|
async function runAdrNumberingCheck() {
|
|
9734
|
-
const root = (await
|
|
9735
|
-
const adrDir =
|
|
9769
|
+
const root = (await execa6("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
|
|
9770
|
+
const adrDir = join36(root, "docs", "ADR");
|
|
9736
9771
|
if (!existsSync35(adrDir)) {
|
|
9737
9772
|
console.log("\u2713 ADR numbering guard: no docs/ADR/ directory \u2014 nothing to compare");
|
|
9738
9773
|
return;
|
|
@@ -9772,7 +9807,7 @@ Already accepted? List it in docs/ADR/${ALLOWLIST_FILENAME} instead of leaving t
|
|
|
9772
9807
|
|
|
9773
9808
|
// src/scripts/check-branch-protection.ts
|
|
9774
9809
|
import { Octokit as Octokit2 } from "@octokit/rest";
|
|
9775
|
-
import { execa as
|
|
9810
|
+
import { execa as execa7 } from "execa";
|
|
9776
9811
|
|
|
9777
9812
|
// src/lib/branch-protection-apply.ts
|
|
9778
9813
|
var CONTEXT_CONSISTENCY_THRESHOLD = 2 / 3;
|
|
@@ -9899,7 +9934,7 @@ async function resolveRepo(explicit) {
|
|
|
9899
9934
|
}
|
|
9900
9935
|
return { owner, repo };
|
|
9901
9936
|
}
|
|
9902
|
-
const { stdout } = await
|
|
9937
|
+
const { stdout } = await execa7("git", ["remote", "get-url", "origin"]);
|
|
9903
9938
|
const m = /github\.com[:/]([^/]+)\/(.+?)(?:\.git)?$/.exec(stdout.trim());
|
|
9904
9939
|
if (!m?.[1] || !m[2]) {
|
|
9905
9940
|
console.error(
|
|
@@ -10031,11 +10066,11 @@ async function runBranchProtectionCheck(explicitRepo, options = {}) {
|
|
|
10031
10066
|
}
|
|
10032
10067
|
|
|
10033
10068
|
// src/scripts/check-cognito-invite-template.ts
|
|
10034
|
-
import { execa as
|
|
10069
|
+
import { execa as execa8 } from "execa";
|
|
10035
10070
|
|
|
10036
10071
|
// src/lib/cognito-invite-template-guard.ts
|
|
10037
10072
|
import { readdirSync as readdirSync14, readFileSync as readFileSync27, statSync as statSync7 } from "fs";
|
|
10038
|
-
import { join as
|
|
10073
|
+
import { join as join37 } from "path";
|
|
10039
10074
|
var REQUIRED_INVITE_MEMBERS = ["email_subject", "email_message", "sms_message"];
|
|
10040
10075
|
var REQUIRED_INVITE_PLACEHOLDERS = ["{username}", "{####}"];
|
|
10041
10076
|
var PLACEHOLDER_MEMBERS = ["email_message", "sms_message"];
|
|
@@ -10118,7 +10153,7 @@ function findModuleTerraformFiles(repoRoot) {
|
|
|
10118
10153
|
}
|
|
10119
10154
|
for (const entry of entries) {
|
|
10120
10155
|
if (entry === "node_modules" || entry === ".git" || entry === ".worktrees") continue;
|
|
10121
|
-
const full =
|
|
10156
|
+
const full = join37(dir, entry);
|
|
10122
10157
|
const rel = `${relative8}/${entry}`;
|
|
10123
10158
|
if (statSync7(full).isDirectory()) {
|
|
10124
10159
|
walk2(full, rel);
|
|
@@ -10127,18 +10162,18 @@ function findModuleTerraformFiles(repoRoot) {
|
|
|
10127
10162
|
}
|
|
10128
10163
|
}
|
|
10129
10164
|
};
|
|
10130
|
-
walk2(
|
|
10165
|
+
walk2(join37(repoRoot, "modules"), "modules");
|
|
10131
10166
|
return found.sort();
|
|
10132
10167
|
}
|
|
10133
10168
|
function checkCognitoInviteTemplates(repoRoot) {
|
|
10134
10169
|
return findModuleTerraformFiles(repoRoot).flatMap(
|
|
10135
|
-
(file) => checkInviteTemplateSource(file, readFileSync27(
|
|
10170
|
+
(file) => checkInviteTemplateSource(file, readFileSync27(join37(repoRoot, file), "utf8"))
|
|
10136
10171
|
);
|
|
10137
10172
|
}
|
|
10138
10173
|
|
|
10139
10174
|
// src/scripts/check-cognito-invite-template.ts
|
|
10140
10175
|
async function runCognitoInviteTemplateCheck() {
|
|
10141
|
-
const root = (await
|
|
10176
|
+
const root = (await execa8("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
|
|
10142
10177
|
const files = findModuleTerraformFiles(root);
|
|
10143
10178
|
console.log(`audited ${files.length} .tf file(s) under modules/ under ${root}`);
|
|
10144
10179
|
if (files.length === 0) {
|
|
@@ -10160,12 +10195,12 @@ async function runCognitoInviteTemplateCheck() {
|
|
|
10160
10195
|
}
|
|
10161
10196
|
|
|
10162
10197
|
// src/scripts/check-core-direct-paths.ts
|
|
10163
|
-
import { join as
|
|
10164
|
-
import { execa as
|
|
10198
|
+
import { join as join39 } from "path";
|
|
10199
|
+
import { execa as execa9 } from "execa";
|
|
10165
10200
|
|
|
10166
10201
|
// src/lib/core-direct-paths-audit.ts
|
|
10167
10202
|
import { existsSync as existsSync36, readFileSync as readFileSync28, readdirSync as readdirSync15, statSync as statSync8 } from "fs";
|
|
10168
|
-
import { join as
|
|
10203
|
+
import { join as join38 } from "path";
|
|
10169
10204
|
var EXTERNAL_BASE_IDENTIFIERS = ["CORE_API_URL"];
|
|
10170
10205
|
var API_ROUTE_PREFIX = "/api/v1";
|
|
10171
10206
|
var TEST_FILE_SUFFIXES = [".test.ts", ".test.tsx", ".spec.ts", ".spec.tsx"];
|
|
@@ -10329,7 +10364,7 @@ function walkFiles(root, accept, skipDir) {
|
|
|
10329
10364
|
return;
|
|
10330
10365
|
}
|
|
10331
10366
|
for (const entry of entries) {
|
|
10332
|
-
const p =
|
|
10367
|
+
const p = join38(dir, entry);
|
|
10333
10368
|
let st;
|
|
10334
10369
|
try {
|
|
10335
10370
|
st = statSync8(p);
|
|
@@ -10424,7 +10459,7 @@ function pathMatchesAnyCorePrefix(normalized, corePrefixes, apiRoutePrefix = API
|
|
|
10424
10459
|
}
|
|
10425
10460
|
function resolveSiblingCoreSrc(params) {
|
|
10426
10461
|
const { estateDir, sibling } = params;
|
|
10427
|
-
const configPath =
|
|
10462
|
+
const configPath = join38(estateDir, sibling, "biffo.sibling.json");
|
|
10428
10463
|
let raw;
|
|
10429
10464
|
try {
|
|
10430
10465
|
raw = readFileSync28(configPath, "utf8");
|
|
@@ -10447,7 +10482,7 @@ function resolveSiblingCoreSrc(params) {
|
|
|
10447
10482
|
`cannot resolve ${sibling}'s core: ${configPath} has no non-empty "core_project" field.`
|
|
10448
10483
|
);
|
|
10449
10484
|
}
|
|
10450
|
-
const coreApiSrcDir =
|
|
10485
|
+
const coreApiSrcDir = join38(estateDir, coreProject, "services", "api", "src");
|
|
10451
10486
|
if (!existsSync36(coreApiSrcDir)) {
|
|
10452
10487
|
throw new Error(
|
|
10453
10488
|
`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.`
|
|
@@ -10489,9 +10524,9 @@ function auditSiblingCoreDirectPaths(params) {
|
|
|
10489
10524
|
|
|
10490
10525
|
// src/scripts/check-core-direct-paths.ts
|
|
10491
10526
|
async function runCoreDirectPathsCheck(opts = {}) {
|
|
10492
|
-
const root = (await
|
|
10527
|
+
const root = (await execa9("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
|
|
10493
10528
|
const sibling = opts.sibling ?? "sibling-template (self-check)";
|
|
10494
|
-
const frontendSrcDir = opts.frontendSrc ??
|
|
10529
|
+
const frontendSrcDir = opts.frontendSrc ?? join39(root, "_skeletons", "sibling-template", "apps", "frontend", "src");
|
|
10495
10530
|
let coreApiSrcDir;
|
|
10496
10531
|
let coreProject = null;
|
|
10497
10532
|
if (opts.coreSrc) {
|
|
@@ -10507,7 +10542,7 @@ async function runCoreDirectPathsCheck(opts = {}) {
|
|
|
10507
10542
|
coreApiSrcDir = resolution.coreApiSrcDir;
|
|
10508
10543
|
coreProject = resolution.coreProject;
|
|
10509
10544
|
} else {
|
|
10510
|
-
coreApiSrcDir =
|
|
10545
|
+
coreApiSrcDir = join39(root, "services", "api", "src");
|
|
10511
10546
|
}
|
|
10512
10547
|
const report = auditSiblingCoreDirectPaths({ sibling, frontendSrcDir, coreApiSrcDir });
|
|
10513
10548
|
console.log(
|
|
@@ -10543,7 +10578,7 @@ async function runCoreDirectPathsCheck(opts = {}) {
|
|
|
10543
10578
|
}
|
|
10544
10579
|
|
|
10545
10580
|
// src/scripts/check-core-ownership.ts
|
|
10546
|
-
import { execa as
|
|
10581
|
+
import { execa as execa10 } from "execa";
|
|
10547
10582
|
var BOLD = "\x1B[1m";
|
|
10548
10583
|
var DIM = "\x1B[2m";
|
|
10549
10584
|
var RED = "\x1B[31m";
|
|
@@ -10554,7 +10589,7 @@ async function runOwnershipCheck(argv) {
|
|
|
10554
10589
|
const stagedFlag = args.indexOf("--staged");
|
|
10555
10590
|
const staged = stagedFlag !== -1;
|
|
10556
10591
|
const messageFile = staged ? args[stagedFlag + 1] : void 0;
|
|
10557
|
-
const root = (await
|
|
10592
|
+
const root = (await execa10("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
|
|
10558
10593
|
const ownership = classifyRepoOwnership(root);
|
|
10559
10594
|
if (ownership === "template") {
|
|
10560
10595
|
console.log("\u2713 core ownership guard: skipped \u2014 this is the template, which owns these paths.");
|
|
@@ -10570,7 +10605,7 @@ async function runOwnershipCheck(argv) {
|
|
|
10570
10605
|
let deletedFiles = [];
|
|
10571
10606
|
let commitMessage = "";
|
|
10572
10607
|
if (staged) {
|
|
10573
|
-
const { stdout } = await
|
|
10608
|
+
const { stdout } = await execa10("git", ["diff", "--cached", "--name-status"], { cwd: root });
|
|
10574
10609
|
({ changed: changedFiles, deleted: deletedFiles } = parseNameStatus(stdout));
|
|
10575
10610
|
if (messageFile) {
|
|
10576
10611
|
const { readFileSync: readFileSync37, existsSync: existsSync45 } = await import("fs");
|
|
@@ -10582,18 +10617,18 @@ async function runOwnershipCheck(argv) {
|
|
|
10582
10617
|
console.error("No base ref: set GITHUB_BASE_REF or pass a base branch as the first argument.");
|
|
10583
10618
|
process.exit(2);
|
|
10584
10619
|
}
|
|
10585
|
-
await
|
|
10586
|
-
const { stdout } = await
|
|
10620
|
+
await execa10("git", ["fetch", "--quiet", "origin", base], { cwd: root, reject: false });
|
|
10621
|
+
const { stdout } = await execa10("git", ["diff", "--name-status", `origin/${base}...HEAD`], {
|
|
10587
10622
|
cwd: root
|
|
10588
10623
|
});
|
|
10589
10624
|
({ changed: changedFiles, deleted: deletedFiles } = parseNameStatus(stdout));
|
|
10590
|
-
const { stdout: log2 } = await
|
|
10625
|
+
const { stdout: log2 } = await execa10("git", ["log", "--format=%B", `origin/${base}..HEAD`], {
|
|
10591
10626
|
cwd: root,
|
|
10592
10627
|
reject: false
|
|
10593
10628
|
});
|
|
10594
10629
|
commitMessage = log2;
|
|
10595
10630
|
}
|
|
10596
|
-
const { stdout: gitBranch } = await
|
|
10631
|
+
const { stdout: gitBranch } = await execa10("git", ["rev-parse", "--abbrev-ref", "HEAD"], {
|
|
10597
10632
|
cwd: root,
|
|
10598
10633
|
reject: false
|
|
10599
10634
|
});
|
|
@@ -10675,11 +10710,11 @@ ${BOLD}If the divergence is deliberate${OFF}
|
|
|
10675
10710
|
}
|
|
10676
10711
|
|
|
10677
10712
|
// src/scripts/check-eventbridge-log-permissions.ts
|
|
10678
|
-
import { execa as
|
|
10713
|
+
import { execa as execa11 } from "execa";
|
|
10679
10714
|
|
|
10680
10715
|
// src/lib/eventbridge-log-permission-guard.ts
|
|
10681
10716
|
import { readFileSync as readFileSync29, readdirSync as readdirSync16, statSync as statSync9 } from "fs";
|
|
10682
|
-
import { join as
|
|
10717
|
+
import { join as join40 } from "path";
|
|
10683
10718
|
var SKIP_DIRS = /* @__PURE__ */ new Set(["node_modules", ".git", ".terraform", ".worktrees", "dist"]);
|
|
10684
10719
|
var EVENT_TARGET_TYPE = "aws_cloudwatch_event_target";
|
|
10685
10720
|
var LOG_RESOURCE_POLICY_TYPE = "aws_cloudwatch_log_resource_policy";
|
|
@@ -10756,7 +10791,7 @@ function walkTerraformFiles(root) {
|
|
|
10756
10791
|
return;
|
|
10757
10792
|
}
|
|
10758
10793
|
for (const entry of entries) {
|
|
10759
|
-
const p =
|
|
10794
|
+
const p = join40(dir, entry);
|
|
10760
10795
|
let st;
|
|
10761
10796
|
try {
|
|
10762
10797
|
st = statSync9(p);
|
|
@@ -10852,7 +10887,7 @@ function auditEventBridgeLogPermissions(root) {
|
|
|
10852
10887
|
|
|
10853
10888
|
// src/scripts/check-eventbridge-log-permissions.ts
|
|
10854
10889
|
async function runEventBridgeLogPermissionCheck() {
|
|
10855
|
-
const root = (await
|
|
10890
|
+
const root = (await execa11("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
|
|
10856
10891
|
let report;
|
|
10857
10892
|
try {
|
|
10858
10893
|
report = auditEventBridgeLogPermissions(root);
|
|
@@ -10889,15 +10924,15 @@ async function runEventBridgeLogPermissionCheck() {
|
|
|
10889
10924
|
}
|
|
10890
10925
|
|
|
10891
10926
|
// src/scripts/check-lambda-output.ts
|
|
10892
|
-
import { execa as
|
|
10927
|
+
import { execa as execa12 } from "execa";
|
|
10893
10928
|
|
|
10894
10929
|
// src/lib/lambda-output-guard.ts
|
|
10895
10930
|
import { readFileSync as readFileSync31 } from "fs";
|
|
10896
|
-
import { join as
|
|
10931
|
+
import { join as join42 } from "path";
|
|
10897
10932
|
|
|
10898
10933
|
// src/lib/terraform-input-guard.ts
|
|
10899
10934
|
import { readdirSync as readdirSync17, readFileSync as readFileSync30, statSync as statSync10 } from "fs";
|
|
10900
|
-
import { join as
|
|
10935
|
+
import { join as join41 } from "path";
|
|
10901
10936
|
var GUARDED_SUBCOMMANDS = [
|
|
10902
10937
|
"init",
|
|
10903
10938
|
"plan",
|
|
@@ -10921,7 +10956,7 @@ function findWorkflowFiles(repoRoot) {
|
|
|
10921
10956
|
}
|
|
10922
10957
|
for (const entry of entries) {
|
|
10923
10958
|
if (entry === "node_modules" || entry === ".git" || entry === ".worktrees") continue;
|
|
10924
|
-
const full =
|
|
10959
|
+
const full = join41(dir, entry);
|
|
10925
10960
|
const rel = relative8 ? `${relative8}/${entry}` : entry;
|
|
10926
10961
|
if (statSync10(full).isDirectory()) {
|
|
10927
10962
|
walk2(full, rel);
|
|
@@ -10965,7 +11000,7 @@ function checkWorkflowSource(file, rawSource) {
|
|
|
10965
11000
|
}
|
|
10966
11001
|
function checkTerraformInput(repoRoot) {
|
|
10967
11002
|
return findWorkflowFiles(repoRoot).flatMap(
|
|
10968
|
-
(file) => checkWorkflowSource(file, readFileSync30(
|
|
11003
|
+
(file) => checkWorkflowSource(file, readFileSync30(join41(repoRoot, file), "utf8"))
|
|
10969
11004
|
);
|
|
10970
11005
|
}
|
|
10971
11006
|
|
|
@@ -11023,13 +11058,13 @@ function checkWorkflowSource2(file, rawSource) {
|
|
|
11023
11058
|
}
|
|
11024
11059
|
function checkLambdaOutput(repoRoot) {
|
|
11025
11060
|
return findWorkflowFiles(repoRoot).flatMap(
|
|
11026
|
-
(file) => checkWorkflowSource2(file, readFileSync31(
|
|
11061
|
+
(file) => checkWorkflowSource2(file, readFileSync31(join42(repoRoot, file), "utf8"))
|
|
11027
11062
|
);
|
|
11028
11063
|
}
|
|
11029
11064
|
|
|
11030
11065
|
// src/scripts/check-lambda-output.ts
|
|
11031
11066
|
async function runLambdaOutputCheck() {
|
|
11032
|
-
const root = (await
|
|
11067
|
+
const root = (await execa12("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
|
|
11033
11068
|
const files = findWorkflowFiles(root);
|
|
11034
11069
|
console.log(`audited ${files.length} workflow file(s) under ${root}`);
|
|
11035
11070
|
if (files.length === 0) {
|
|
@@ -11052,8 +11087,8 @@ async function runLambdaOutputCheck() {
|
|
|
11052
11087
|
|
|
11053
11088
|
// src/scripts/check-pipe-trap.ts
|
|
11054
11089
|
import { readFileSync as readFileSync32, readdirSync as readdirSync18 } from "fs";
|
|
11055
|
-
import { join as
|
|
11056
|
-
import { execa as
|
|
11090
|
+
import { join as join43, relative as relative6 } from "path";
|
|
11091
|
+
import { execa as execa13 } from "execa";
|
|
11057
11092
|
|
|
11058
11093
|
// src/lib/pipe-trap-guard.ts
|
|
11059
11094
|
var STATUS_BEARING = [
|
|
@@ -11149,7 +11184,7 @@ function findPipeTraps(source) {
|
|
|
11149
11184
|
function shellFiles(root) {
|
|
11150
11185
|
const out = [];
|
|
11151
11186
|
for (const dir of ["scripts", ".githooks"]) {
|
|
11152
|
-
const full =
|
|
11187
|
+
const full = join43(root, dir);
|
|
11153
11188
|
let entries;
|
|
11154
11189
|
try {
|
|
11155
11190
|
entries = readdirSync18(full, { withFileTypes: true });
|
|
@@ -11159,13 +11194,13 @@ function shellFiles(root) {
|
|
|
11159
11194
|
for (const entry of entries) {
|
|
11160
11195
|
if (!entry.isFile()) continue;
|
|
11161
11196
|
if (dir === "scripts" && !entry.name.endsWith(".sh")) continue;
|
|
11162
|
-
out.push(
|
|
11197
|
+
out.push(join43(full, entry.name));
|
|
11163
11198
|
}
|
|
11164
11199
|
}
|
|
11165
11200
|
return out;
|
|
11166
11201
|
}
|
|
11167
11202
|
async function runPipeTrapCheck() {
|
|
11168
|
-
const root = (await
|
|
11203
|
+
const root = (await execa13("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
|
|
11169
11204
|
const files = shellFiles(root);
|
|
11170
11205
|
console.log(`audited ${files.length} shell file(s) under scripts/ and .githooks/ under ${root}`);
|
|
11171
11206
|
if (files.length === 0) {
|
|
@@ -11193,12 +11228,12 @@ async function runPipeTrapCheck() {
|
|
|
11193
11228
|
|
|
11194
11229
|
// src/scripts/check-plugin-collisions.ts
|
|
11195
11230
|
import { existsSync as existsSync38 } from "fs";
|
|
11196
|
-
import { join as
|
|
11197
|
-
import { execa as
|
|
11231
|
+
import { join as join45 } from "path";
|
|
11232
|
+
import { execa as execa14 } from "execa";
|
|
11198
11233
|
|
|
11199
11234
|
// src/lib/plugin-collision-guard.ts
|
|
11200
11235
|
import { existsSync as existsSync37, readdirSync as readdirSync19, statSync as statSync11 } from "fs";
|
|
11201
|
-
import { join as
|
|
11236
|
+
import { join as join44 } from "path";
|
|
11202
11237
|
var PYTEST_SPECIAL = /* @__PURE__ */ new Set(["conftest.py"]);
|
|
11203
11238
|
var IGNORED_DIRS = /* @__PURE__ */ new Set([".venv", "node_modules", "__pycache__", ".git", "dist", "build"]);
|
|
11204
11239
|
function subdirectories(dir) {
|
|
@@ -11206,19 +11241,19 @@ function subdirectories(dir) {
|
|
|
11206
11241
|
return readdirSync19(dir).filter((entry) => {
|
|
11207
11242
|
if (IGNORED_DIRS.has(entry) || entry.startsWith(".")) return false;
|
|
11208
11243
|
try {
|
|
11209
|
-
return statSync11(
|
|
11244
|
+
return statSync11(join44(dir, entry)).isDirectory();
|
|
11210
11245
|
} catch {
|
|
11211
11246
|
return false;
|
|
11212
11247
|
}
|
|
11213
11248
|
});
|
|
11214
11249
|
}
|
|
11215
11250
|
function regularPackagesOf(pluginDir2) {
|
|
11216
|
-
return subdirectories(pluginDir2).filter((name) => existsSync37(
|
|
11251
|
+
return subdirectories(pluginDir2).filter((name) => existsSync37(join44(pluginDir2, name, "__init__.py"))).sort();
|
|
11217
11252
|
}
|
|
11218
11253
|
function bareTestModulesOf(pluginDir2) {
|
|
11219
|
-
const testsDir =
|
|
11254
|
+
const testsDir = join44(pluginDir2, "tests");
|
|
11220
11255
|
if (!existsSync37(testsDir)) return [];
|
|
11221
|
-
if (existsSync37(
|
|
11256
|
+
if (existsSync37(join44(testsDir, "__init__.py"))) return [];
|
|
11222
11257
|
return readdirSync19(testsDir).filter((f) => f.endsWith(".py") && !PYTEST_SPECIAL.has(f)).sort();
|
|
11223
11258
|
}
|
|
11224
11259
|
function findCollisions(servicesDir, pluginDirs) {
|
|
@@ -11227,7 +11262,7 @@ function findCollisions(servicesDir, pluginDirs) {
|
|
|
11227
11262
|
const gather = (kind, namesOf) => {
|
|
11228
11263
|
const claims = /* @__PURE__ */ new Map();
|
|
11229
11264
|
for (const plugin of plugins) {
|
|
11230
|
-
for (const name of namesOf(
|
|
11265
|
+
for (const name of namesOf(join44(servicesDir, plugin))) {
|
|
11231
11266
|
claims.set(name, [...claims.get(name) ?? [], plugin]);
|
|
11232
11267
|
}
|
|
11233
11268
|
}
|
|
@@ -11264,8 +11299,8 @@ function formatCollisions(collisions) {
|
|
|
11264
11299
|
|
|
11265
11300
|
// src/scripts/check-plugin-collisions.ts
|
|
11266
11301
|
async function runPluginCollisionCheck() {
|
|
11267
|
-
const root = (await
|
|
11268
|
-
const servicesDir =
|
|
11302
|
+
const root = (await execa14("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
|
|
11303
|
+
const servicesDir = join45(root, "services");
|
|
11269
11304
|
if (!existsSync38(servicesDir)) {
|
|
11270
11305
|
console.log("\u2713 plugin collision guard: no services/ directory \u2014 nothing to compare");
|
|
11271
11306
|
return;
|
|
@@ -11283,11 +11318,11 @@ async function runPluginCollisionCheck() {
|
|
|
11283
11318
|
}
|
|
11284
11319
|
|
|
11285
11320
|
// src/scripts/check-plugin-terraform.ts
|
|
11286
|
-
import { execa as
|
|
11321
|
+
import { execa as execa15 } from "execa";
|
|
11287
11322
|
|
|
11288
11323
|
// src/lib/plugin-terraform-guard.ts
|
|
11289
11324
|
import { existsSync as existsSync39, readFileSync as readFileSync33, readdirSync as readdirSync20 } from "fs";
|
|
11290
|
-
import { dirname as
|
|
11325
|
+
import { dirname as dirname10, join as join46, relative as relative7, sep as sep3 } from "path";
|
|
11291
11326
|
var SKIP_DIRS2 = /* @__PURE__ */ new Set(["node_modules", ".git", ".worktrees", "dist", ".venv", "__pycache__"]);
|
|
11292
11327
|
var PLUGIN_MANIFEST_FILE2 = "biffo.plugin.json";
|
|
11293
11328
|
function findPluginManifests(root) {
|
|
@@ -11302,9 +11337,9 @@ function findPluginManifests(root) {
|
|
|
11302
11337
|
for (const entry of entries) {
|
|
11303
11338
|
if (entry.isDirectory()) {
|
|
11304
11339
|
if (SKIP_DIRS2.has(entry.name)) continue;
|
|
11305
|
-
walk2(
|
|
11340
|
+
walk2(join46(dir, entry.name));
|
|
11306
11341
|
} else if (entry.isFile() && entry.name === PLUGIN_MANIFEST_FILE2) {
|
|
11307
|
-
found.push(relative7(root,
|
|
11342
|
+
found.push(relative7(root, join46(dir, entry.name)).split(sep3).join("/"));
|
|
11308
11343
|
}
|
|
11309
11344
|
}
|
|
11310
11345
|
};
|
|
@@ -11329,14 +11364,14 @@ function readSubscriptions(absManifestPath) {
|
|
|
11329
11364
|
}
|
|
11330
11365
|
function checkPluginTerraform(root) {
|
|
11331
11366
|
const violations = [];
|
|
11332
|
-
const coreManifest = existsSync39(
|
|
11367
|
+
const coreManifest = existsSync39(join46(root, CORE_MANIFEST_FILE)) ? readCoreManifest(root) : null;
|
|
11333
11368
|
for (const manifest of findPluginManifests(root)) {
|
|
11334
11369
|
if (coreManifest && !isTemplateOwned(manifest, coreManifest)) continue;
|
|
11335
|
-
const absManifest =
|
|
11370
|
+
const absManifest = join46(root, manifest);
|
|
11336
11371
|
const subscriptions = readSubscriptions(absManifest);
|
|
11337
11372
|
if (subscriptions === null) continue;
|
|
11338
|
-
const pluginDir2 =
|
|
11339
|
-
if (existsSync39(
|
|
11373
|
+
const pluginDir2 = dirname10(absManifest);
|
|
11374
|
+
if (existsSync39(join46(pluginDir2, "terraform"))) continue;
|
|
11340
11375
|
const relPluginDir = relative7(root, pluginDir2).split(sep3).join("/");
|
|
11341
11376
|
violations.push({
|
|
11342
11377
|
manifest,
|
|
@@ -11356,7 +11391,7 @@ function formatViolations(violations) {
|
|
|
11356
11391
|
|
|
11357
11392
|
// src/scripts/check-plugin-terraform.ts
|
|
11358
11393
|
async function runPluginTerraformCheck() {
|
|
11359
|
-
const root = (await
|
|
11394
|
+
const root = (await execa15("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
|
|
11360
11395
|
const violations = checkPluginTerraform(root);
|
|
11361
11396
|
if (violations.length > 0) {
|
|
11362
11397
|
console.error("\u2717 plugin Terraform guard: event subscriptions with no infrastructure\n");
|
|
@@ -11368,12 +11403,12 @@ async function runPluginTerraformCheck() {
|
|
|
11368
11403
|
|
|
11369
11404
|
// src/scripts/check-plugin-tool-supply.ts
|
|
11370
11405
|
import { existsSync as existsSync41 } from "fs";
|
|
11371
|
-
import { join as
|
|
11372
|
-
import { execa as
|
|
11406
|
+
import { join as join48 } from "path";
|
|
11407
|
+
import { execa as execa16 } from "execa";
|
|
11373
11408
|
|
|
11374
11409
|
// src/lib/plugin-tool-supply-audit.ts
|
|
11375
11410
|
import { existsSync as existsSync40, readFileSync as readFileSync34, readdirSync as readdirSync21, statSync as statSync12 } from "fs";
|
|
11376
|
-
import { join as
|
|
11411
|
+
import { join as join47 } from "path";
|
|
11377
11412
|
|
|
11378
11413
|
// src/lib/openrouter-model-snapshot.ts
|
|
11379
11414
|
var OPENROUTER_MODEL_SNAPSHOT_FETCHED_AT = "2026-08-10T06:39:01Z";
|
|
@@ -11790,7 +11825,7 @@ function listDirs(root) {
|
|
|
11790
11825
|
}
|
|
11791
11826
|
return entries.filter((e) => {
|
|
11792
11827
|
try {
|
|
11793
|
-
return statSync12(
|
|
11828
|
+
return statSync12(join47(root, e)).isDirectory();
|
|
11794
11829
|
} catch {
|
|
11795
11830
|
return false;
|
|
11796
11831
|
}
|
|
@@ -11806,7 +11841,7 @@ function walkFiles2(root, accept, skipDir) {
|
|
|
11806
11841
|
return;
|
|
11807
11842
|
}
|
|
11808
11843
|
for (const entry of entries) {
|
|
11809
|
-
const p =
|
|
11844
|
+
const p = join47(dir, entry);
|
|
11810
11845
|
let st;
|
|
11811
11846
|
try {
|
|
11812
11847
|
st = statSync12(p);
|
|
@@ -11832,14 +11867,14 @@ function pluginPythonFiles(pluginDir2) {
|
|
|
11832
11867
|
);
|
|
11833
11868
|
}
|
|
11834
11869
|
function pluginTerraformFiles(pluginDir2) {
|
|
11835
|
-
const tfDir =
|
|
11870
|
+
const tfDir = join47(pluginDir2, "terraform");
|
|
11836
11871
|
let entries;
|
|
11837
11872
|
try {
|
|
11838
11873
|
entries = readdirSync21(tfDir);
|
|
11839
11874
|
} catch {
|
|
11840
11875
|
return [];
|
|
11841
11876
|
}
|
|
11842
|
-
return entries.filter((e) => e.endsWith(".tf")).map((e) =>
|
|
11877
|
+
return entries.filter((e) => e.endsWith(".tf")).map((e) => join47(tfDir, e)).sort();
|
|
11843
11878
|
}
|
|
11844
11879
|
function extractManifestTools(manifestText) {
|
|
11845
11880
|
let parsed;
|
|
@@ -12091,8 +12126,8 @@ function isSnapshotStale(fetchedAt, now) {
|
|
|
12091
12126
|
function normalizeModelId(id) {
|
|
12092
12127
|
return id.endsWith(":online") ? id.slice(0, -":online".length) : id;
|
|
12093
12128
|
}
|
|
12094
|
-
var CONFIG_PY_PATH =
|
|
12095
|
-
var ORCHESTRATION_SCHEMA_PATH =
|
|
12129
|
+
var CONFIG_PY_PATH = join47("services", "api", "src", "api", "config.py");
|
|
12130
|
+
var ORCHESTRATION_SCHEMA_PATH = join47(
|
|
12096
12131
|
"services",
|
|
12097
12132
|
"api",
|
|
12098
12133
|
"src",
|
|
@@ -12104,8 +12139,8 @@ function auditDeclaredModelIds(repoRoot, options = {}) {
|
|
|
12104
12139
|
const knownModelIds = options.knownModelIds ?? OPENROUTER_MODEL_IDS;
|
|
12105
12140
|
const snapshotFetchedAt = options.snapshotFetchedAt ?? OPENROUTER_MODEL_SNAPSHOT_FETCHED_AT;
|
|
12106
12141
|
const now = options.now ?? /* @__PURE__ */ new Date();
|
|
12107
|
-
const configPath =
|
|
12108
|
-
const orchestrationPath =
|
|
12142
|
+
const configPath = join47(repoRoot, CONFIG_PY_PATH);
|
|
12143
|
+
const orchestrationPath = join47(repoRoot, ORCHESTRATION_SCHEMA_PATH);
|
|
12109
12144
|
const configMissing = !existsSync40(configPath);
|
|
12110
12145
|
const orchestrationSchemaMissing = !existsSync40(orchestrationPath);
|
|
12111
12146
|
const knownSet = new Set(knownModelIds);
|
|
@@ -12178,7 +12213,7 @@ function auditDeclaredModelIds(repoRoot, options = {}) {
|
|
|
12178
12213
|
function discoverPluginDirs(pluginsRoot) {
|
|
12179
12214
|
return listDirs(pluginsRoot).filter((name) => {
|
|
12180
12215
|
try {
|
|
12181
|
-
return statSync12(
|
|
12216
|
+
return statSync12(join47(pluginsRoot, name, "biffo.plugin.json")).isFile();
|
|
12182
12217
|
} catch {
|
|
12183
12218
|
return false;
|
|
12184
12219
|
}
|
|
@@ -12191,8 +12226,8 @@ function auditPluginToolSupply(pluginsRoot) {
|
|
|
12191
12226
|
let terraformBlind = false;
|
|
12192
12227
|
let totalDeclaredTools = 0;
|
|
12193
12228
|
for (const name of pluginNames) {
|
|
12194
|
-
const pluginDir2 =
|
|
12195
|
-
const manifestText = readFileSync34(
|
|
12229
|
+
const pluginDir2 = join47(pluginsRoot, name);
|
|
12230
|
+
const manifestText = readFileSync34(join47(pluginDir2, "biffo.plugin.json"), "utf8");
|
|
12196
12231
|
const manifest = extractManifestTools(manifestText);
|
|
12197
12232
|
if (manifest.parseError) {
|
|
12198
12233
|
findings.push({
|
|
@@ -12290,7 +12325,7 @@ function auditPluginToolSupply(pluginsRoot) {
|
|
|
12290
12325
|
requiredEnvVars: envResult.envVars,
|
|
12291
12326
|
missingEnvVars: anyWired ? [] : envResult.envVars,
|
|
12292
12327
|
status: anyWired ? "ok" : "missing-env",
|
|
12293
|
-
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 ${
|
|
12328
|
+
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 ${join47(pluginDir2, "terraform")}, so this deployment can never supply it`
|
|
12294
12329
|
});
|
|
12295
12330
|
}
|
|
12296
12331
|
}
|
|
@@ -12321,9 +12356,9 @@ function auditPluginToolSupply(pluginsRoot) {
|
|
|
12321
12356
|
|
|
12322
12357
|
// src/scripts/check-plugin-tool-supply.ts
|
|
12323
12358
|
async function runPluginToolSupplyCheck() {
|
|
12324
|
-
const root = (await
|
|
12359
|
+
const root = (await execa16("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
|
|
12325
12360
|
let allOk = true;
|
|
12326
|
-
const pluginsRoot =
|
|
12361
|
+
const pluginsRoot = join48(root, "services", "_plugins");
|
|
12327
12362
|
if (!existsSync41(pluginsRoot)) {
|
|
12328
12363
|
console.log("\u2713 plugin tool-supply guard: no services/_plugins/ \u2014 nothing to audit");
|
|
12329
12364
|
} else {
|
|
@@ -12354,7 +12389,7 @@ async function runPluginToolSupplyCheck() {
|
|
|
12354
12389
|
console.log(`\u2713 plugin tool-supply guard: ${report.summary}`);
|
|
12355
12390
|
}
|
|
12356
12391
|
}
|
|
12357
|
-
const servicesApiRoot =
|
|
12392
|
+
const servicesApiRoot = join48(root, "services", "api");
|
|
12358
12393
|
if (!existsSync41(servicesApiRoot)) {
|
|
12359
12394
|
console.log("\u2713 plugin model-id guard: no services/api/ \u2014 nothing to audit");
|
|
12360
12395
|
} else {
|
|
@@ -12401,7 +12436,7 @@ async function runPluginToolSupplyCheck() {
|
|
|
12401
12436
|
}
|
|
12402
12437
|
|
|
12403
12438
|
// src/scripts/check-release-subject.ts
|
|
12404
|
-
import { execa as
|
|
12439
|
+
import { execa as execa17 } from "execa";
|
|
12405
12440
|
|
|
12406
12441
|
// src/lib/release-version.ts
|
|
12407
12442
|
var MINOR_TYPES = /* @__PURE__ */ new Set(["feat"]);
|
|
@@ -12438,7 +12473,7 @@ async function fetchPrTitleViaGh({
|
|
|
12438
12473
|
PR_NUMBER,
|
|
12439
12474
|
GH_REPO
|
|
12440
12475
|
}) {
|
|
12441
|
-
const { stdout } = await
|
|
12476
|
+
const { stdout } = await execa17(
|
|
12442
12477
|
"gh",
|
|
12443
12478
|
["pr", "view", PR_NUMBER, "--repo", GH_REPO, "--json", "title", "--jq", ".title"],
|
|
12444
12479
|
{ env: { ...process.env, GH_TOKEN } }
|
|
@@ -12474,7 +12509,7 @@ async function resolveReleaseSubject({
|
|
|
12474
12509
|
);
|
|
12475
12510
|
}
|
|
12476
12511
|
}
|
|
12477
|
-
return (await
|
|
12512
|
+
return (await execa17("git", ["log", "-1", "--format=%s"], { cwd })).stdout.trim();
|
|
12478
12513
|
}
|
|
12479
12514
|
async function runReleaseSubjectCheck(argv) {
|
|
12480
12515
|
const base = process.env["GITHUB_BASE_REF"] ?? argv[0];
|
|
@@ -12482,9 +12517,9 @@ async function runReleaseSubjectCheck(argv) {
|
|
|
12482
12517
|
console.error("No base ref: set GITHUB_BASE_REF or pass a base branch as the first argument.");
|
|
12483
12518
|
process.exit(2);
|
|
12484
12519
|
}
|
|
12485
|
-
const root = (await
|
|
12486
|
-
await
|
|
12487
|
-
const { stdout } = await
|
|
12520
|
+
const root = (await execa17("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
|
|
12521
|
+
await execa17("git", ["fetch", "--quiet", "origin", base], { cwd: root, reject: false });
|
|
12522
|
+
const { stdout } = await execa17("git", ["diff", "--name-only", `origin/${base}...HEAD`], {
|
|
12488
12523
|
cwd: root
|
|
12489
12524
|
});
|
|
12490
12525
|
const changedFiles = stdout.split("\n").map((s) => s.trim()).filter(Boolean);
|
|
@@ -12533,12 +12568,12 @@ async function runReleaseSubjectCheck(argv) {
|
|
|
12533
12568
|
|
|
12534
12569
|
// src/scripts/check-skeleton-drift.ts
|
|
12535
12570
|
import { existsSync as existsSync42, readdirSync as readdirSync23 } from "fs";
|
|
12536
|
-
import { join as
|
|
12537
|
-
import { execa as
|
|
12571
|
+
import { join as join50 } from "path";
|
|
12572
|
+
import { execa as execa18 } from "execa";
|
|
12538
12573
|
|
|
12539
12574
|
// src/lib/skeleton-drift-guard.ts
|
|
12540
12575
|
import { readFileSync as readFileSync35, readdirSync as readdirSync22, statSync as statSync13 } from "fs";
|
|
12541
|
-
import { join as
|
|
12576
|
+
import { join as join49 } from "path";
|
|
12542
12577
|
var isWorkflow = (rel) => rel.startsWith(".github/workflows/") && (rel.endsWith(".yml") || rel.endsWith(".yaml"));
|
|
12543
12578
|
var isRootLayout = (rel) => rel.endsWith("src/app/layout.tsx");
|
|
12544
12579
|
var uncommented = (contents) => contents.split("\n").filter((line) => !/^\s*(\/\/|\/\*|\*)/.test(line)).join("\n");
|
|
@@ -12602,7 +12637,7 @@ function walk(dir, base = dir) {
|
|
|
12602
12637
|
}
|
|
12603
12638
|
for (const entry of entries) {
|
|
12604
12639
|
if (entry === ".venv" || entry === "node_modules" || entry === ".git") continue;
|
|
12605
|
-
const abs =
|
|
12640
|
+
const abs = join49(dir, entry);
|
|
12606
12641
|
let isDir;
|
|
12607
12642
|
try {
|
|
12608
12643
|
isDir = statSync13(abs).isDirectory();
|
|
@@ -12624,7 +12659,7 @@ function auditSkeleton(skeletonRoot, name, rules = SKELETON_RULES) {
|
|
|
12624
12659
|
if (!rule.appliesTo(rel)) continue;
|
|
12625
12660
|
let contents;
|
|
12626
12661
|
try {
|
|
12627
|
-
contents = readFileSync35(
|
|
12662
|
+
contents = readFileSync35(join49(skeletonRoot, rel), "utf8");
|
|
12628
12663
|
} catch {
|
|
12629
12664
|
continue;
|
|
12630
12665
|
}
|
|
@@ -12653,23 +12688,23 @@ function formatViolations2(violations) {
|
|
|
12653
12688
|
|
|
12654
12689
|
// src/scripts/check-skeleton-drift.ts
|
|
12655
12690
|
function discoverSkeletons(root) {
|
|
12656
|
-
const skeletonsDir =
|
|
12691
|
+
const skeletonsDir = join50(root, "_skeletons");
|
|
12657
12692
|
let entries;
|
|
12658
12693
|
try {
|
|
12659
12694
|
entries = readdirSync23(skeletonsDir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
|
|
12660
12695
|
} catch {
|
|
12661
12696
|
return [];
|
|
12662
12697
|
}
|
|
12663
|
-
return entries.filter((name) => existsSync42(
|
|
12698
|
+
return entries.filter((name) => existsSync42(join50(skeletonsDir, name, ".github", "workflows", "ci.yml"))).sort();
|
|
12664
12699
|
}
|
|
12665
12700
|
async function runSkeletonDriftCheck() {
|
|
12666
|
-
const root = (await
|
|
12701
|
+
const root = (await execa18("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
|
|
12667
12702
|
const skeletons = discoverSkeletons(root);
|
|
12668
12703
|
let filesConsidered = 0;
|
|
12669
12704
|
for (const name of skeletons) {
|
|
12670
|
-
const skeletonRoot =
|
|
12705
|
+
const skeletonRoot = join50(root, "_skeletons", name);
|
|
12671
12706
|
filesConsidered += findWorkflowFiles(skeletonRoot).length;
|
|
12672
|
-
if (existsSync42(
|
|
12707
|
+
if (existsSync42(join50(skeletonRoot, "apps", "frontend", "src", "app", "layout.tsx"))) {
|
|
12673
12708
|
filesConsidered += 1;
|
|
12674
12709
|
}
|
|
12675
12710
|
}
|
|
@@ -12683,7 +12718,7 @@ async function runSkeletonDriftCheck() {
|
|
|
12683
12718
|
process.exit(1);
|
|
12684
12719
|
}
|
|
12685
12720
|
const violations = skeletons.flatMap(
|
|
12686
|
-
(name) => auditSkeleton(
|
|
12721
|
+
(name) => auditSkeleton(join50(root, "_skeletons", name), name)
|
|
12687
12722
|
);
|
|
12688
12723
|
if (violations.length > 0) {
|
|
12689
12724
|
console.error("\u2717 Skeleton-drift guard: drift found between this repo and its scaffolding\n");
|
|
@@ -12695,9 +12730,9 @@ async function runSkeletonDriftCheck() {
|
|
|
12695
12730
|
}
|
|
12696
12731
|
|
|
12697
12732
|
// src/scripts/check-terraform-input.ts
|
|
12698
|
-
import { execa as
|
|
12733
|
+
import { execa as execa19 } from "execa";
|
|
12699
12734
|
async function runTerraformInputCheck() {
|
|
12700
|
-
const root = (await
|
|
12735
|
+
const root = (await execa19("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
|
|
12701
12736
|
const files = findWorkflowFiles(root);
|
|
12702
12737
|
console.log(`audited ${files.length} workflow file(s) under ${root}`);
|
|
12703
12738
|
if (files.length === 0) {
|
|
@@ -12802,7 +12837,7 @@ function rawArgsAfter(subcommand) {
|
|
|
12802
12837
|
|
|
12803
12838
|
// src/commands/doctor.ts
|
|
12804
12839
|
import { existsSync as existsSync43, readFileSync as readFileSync36 } from "fs";
|
|
12805
|
-
import { join as
|
|
12840
|
+
import { join as join51, resolve as resolve18 } from "path";
|
|
12806
12841
|
import chalk21 from "chalk";
|
|
12807
12842
|
import { Command as Command24 } from "commander";
|
|
12808
12843
|
|
|
@@ -12977,7 +13012,7 @@ async function runDoctor(options, deps = { git: new GitAdapter() }) {
|
|
|
12977
13012
|
return runDoctorChecks(facts);
|
|
12978
13013
|
}
|
|
12979
13014
|
function readLocalCoreVersion(cwd) {
|
|
12980
|
-
const path =
|
|
13015
|
+
const path = join51(cwd, INSTANCE_CORE_FILE);
|
|
12981
13016
|
if (!existsSync43(path)) return null;
|
|
12982
13017
|
try {
|
|
12983
13018
|
return parseCoreRecord(readFileSync36(path, "utf8"));
|
|
@@ -12995,7 +13030,7 @@ function parseCoreRecord(contents) {
|
|
|
12995
13030
|
}
|
|
12996
13031
|
}
|
|
12997
13032
|
function readFossil(cwd) {
|
|
12998
|
-
const path =
|
|
13033
|
+
const path = join51(cwd, CORE_VERSION_FILE);
|
|
12999
13034
|
if (!existsSync43(path)) return null;
|
|
13000
13035
|
try {
|
|
13001
13036
|
const value = readFileSync36(path, "utf8").trim();
|
|
@@ -13442,19 +13477,19 @@ function resolveGithubToken4() {
|
|
|
13442
13477
|
|
|
13443
13478
|
// src/lib/packaged-script-command.ts
|
|
13444
13479
|
import { spawnSync } from "child_process";
|
|
13445
|
-
import { dirname as
|
|
13480
|
+
import { dirname as dirname12 } from "path";
|
|
13446
13481
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
13447
13482
|
import { Command as Command26 } from "commander";
|
|
13448
13483
|
|
|
13449
13484
|
// src/lib/packaged-scripts.ts
|
|
13450
13485
|
import { existsSync as existsSync44 } from "fs";
|
|
13451
|
-
import { dirname as
|
|
13486
|
+
import { dirname as dirname11, join as join52 } from "path";
|
|
13452
13487
|
function findPackagedScript(startDir, relativePath) {
|
|
13453
13488
|
let dir = startDir;
|
|
13454
13489
|
for (; ; ) {
|
|
13455
|
-
const candidate =
|
|
13490
|
+
const candidate = join52(dir, relativePath);
|
|
13456
13491
|
if (existsSync44(candidate)) return candidate;
|
|
13457
|
-
const parent =
|
|
13492
|
+
const parent = dirname11(dir);
|
|
13458
13493
|
if (parent === dir) return null;
|
|
13459
13494
|
dir = parent;
|
|
13460
13495
|
}
|
|
@@ -13476,7 +13511,7 @@ function packagedScriptCommand(spec) {
|
|
|
13476
13511
|
const command = new Command26(spec.name).description(spec.description).allowExcessArguments(true).allowUnknownOption(true);
|
|
13477
13512
|
if (spec.argument) command.argument(`<${spec.argument.name}>`, spec.argument.description);
|
|
13478
13513
|
return command.action(() => {
|
|
13479
|
-
const here =
|
|
13514
|
+
const here = dirname12(fileURLToPath6(import.meta.url));
|
|
13480
13515
|
const script = findPackagedScript(here, spec.script);
|
|
13481
13516
|
if (!script) {
|
|
13482
13517
|
process.stderr.write(`${packagedScriptMissing(spec.script)}
|