@biffo/cli 0.282.0 → 0.283.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +56 -29
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -7744,6 +7744,10 @@ var UserIngressSchema = z7.object({
7744
7744
  required_group: z7.string().min(1, NON_EMPTY_GROUP),
7745
7745
  app: z7.string().regex(APP_REF, "must be an ASGI app reference '<module>:<attr>', e.g. 'ideation.app:app'")
7746
7746
  }).strict();
7747
+ var AdminIngressSchema = z7.object({
7748
+ required_group: z7.string().min(1, NON_EMPTY_GROUP),
7749
+ app: z7.string().regex(APP_REF, "must be an ASGI app reference '<module>:<attr>', e.g. 'ideation.admin:app'")
7750
+ }).strict();
7747
7751
  var UserFrontendSchema = z7.object({
7748
7752
  dir: z7.string().regex(
7749
7753
  REL_DIR,
@@ -7788,9 +7792,10 @@ var PluginManifestSchema = z7.object({
7788
7792
  // schema is the registry's, and this consumer only needs to count them.
7789
7793
  event_subscriptions: z7.array(z7.object({ source: z7.string(), detail_type: z7.string() }).passthrough()).default([]),
7790
7794
  required_core_version: z7.string().default(">=0.0.0"),
7791
- // ADR-0018 user-facing surfaces. Optional: a plugin without them is an
7792
- // ordinary (data/event/CRUD) plugin.
7795
+ // ADR-0018/0021 user-facing and admin-facing surfaces. Optional: a plugin
7796
+ // without them is an ordinary (data/event/CRUD) plugin.
7793
7797
  user_ingress: UserIngressSchema.optional(),
7798
+ admin_ingress: AdminIngressSchema.optional(),
7794
7799
  user_frontend: UserFrontendSchema.optional(),
7795
7800
  // Tools the plugin's runtime exposes to an agentic worker (ADR-0014 §7,
7796
7801
  // #569). Default empty — an ordinary plugin declares none. Parsing this
@@ -11230,8 +11235,8 @@ async function runOwnershipCheck(argv) {
11230
11235
  const { stdout } = await execa12("git", ["diff", "--cached", "--name-status"], { cwd: root });
11231
11236
  ({ changed: changedFiles, deleted: deletedFiles } = parseNameStatus(stdout));
11232
11237
  if (messageFile) {
11233
- const { readFileSync: readFileSync41, existsSync: existsSync49 } = await import("fs");
11234
- if (existsSync49(messageFile)) commitMessage = readFileSync41(messageFile, "utf8");
11238
+ const { readFileSync: readFileSync41, existsSync: existsSync50 } = await import("fs");
11239
+ if (existsSync50(messageFile)) commitMessage = readFileSync41(messageFile, "utf8");
11235
11240
  }
11236
11241
  } else {
11237
11242
  const base = process.env["GITHUB_BASE_REF"] ?? args[0];
@@ -11553,7 +11558,7 @@ import { readFileSync as readFileSync34 } from "fs";
11553
11558
  import { join as join47 } from "path";
11554
11559
 
11555
11560
  // src/lib/terraform-input-guard.ts
11556
- import { readdirSync as readdirSync20, readFileSync as readFileSync33, statSync as statSync12 } from "fs";
11561
+ import { existsSync as existsSync41, readdirSync as readdirSync20, readFileSync as readFileSync33, statSync as statSync12 } from "fs";
11557
11562
  import { join as join46 } from "path";
11558
11563
  var GUARDED_SUBCOMMANDS = [
11559
11564
  "init",
@@ -11567,8 +11572,27 @@ var IGNORED_SUBCOMMANDS = ["output", "state", "fmt", "validate", "version", "wor
11567
11572
  function stripComments2(source) {
11568
11573
  return source.split("\n").map((line) => line.replace(/(^|\s)#.*$/, "$1")).join("\n");
11569
11574
  }
11575
+ function vendoredPluginServiceDirs(repoRoot) {
11576
+ const servicesDir = join46(repoRoot, "services");
11577
+ const result = /* @__PURE__ */ new Set();
11578
+ let entries;
11579
+ try {
11580
+ entries = readdirSync20(servicesDir);
11581
+ } catch {
11582
+ return result;
11583
+ }
11584
+ for (const entry of entries) {
11585
+ const full = join46(servicesDir, entry);
11586
+ if (!existsSync41(full) || !statSync12(full).isDirectory()) continue;
11587
+ if (existsSync41(join46(full, "biffo.plugin.json"))) {
11588
+ result.add(entry);
11589
+ }
11590
+ }
11591
+ return result;
11592
+ }
11570
11593
  function findWorkflowFiles(repoRoot) {
11571
11594
  const found = [];
11595
+ const vendoredPluginDirs = vendoredPluginServiceDirs(repoRoot);
11572
11596
  const walk2 = (dir, relative10) => {
11573
11597
  let entries;
11574
11598
  try {
@@ -11578,6 +11602,9 @@ function findWorkflowFiles(repoRoot) {
11578
11602
  }
11579
11603
  for (const entry of entries) {
11580
11604
  if (entry === "node_modules" || entry === ".git" || entry === ".worktrees") continue;
11605
+ if (entry === ".github" && relative10.startsWith("services/") && vendoredPluginDirs.has(relative10.slice("services/".length))) {
11606
+ continue;
11607
+ }
11581
11608
  const full = join46(dir, entry);
11582
11609
  const rel = relative10 ? `${relative10}/${entry}` : entry;
11583
11610
  if (statSync12(full).isDirectory()) {
@@ -11985,17 +12012,17 @@ async function runPluginAllowlistConventionCheck() {
11985
12012
  }
11986
12013
 
11987
12014
  // src/scripts/check-plugin-collisions.ts
11988
- import { existsSync as existsSync42 } from "fs";
12015
+ import { existsSync as existsSync43 } from "fs";
11989
12016
  import { join as join51 } from "path";
11990
12017
  import { execa as execa17 } from "execa";
11991
12018
 
11992
12019
  // src/lib/plugin-collision-guard.ts
11993
- import { existsSync as existsSync41, readdirSync as readdirSync22, statSync as statSync13 } from "fs";
12020
+ import { existsSync as existsSync42, readdirSync as readdirSync22, statSync as statSync13 } from "fs";
11994
12021
  import { join as join50 } from "path";
11995
12022
  var PYTEST_SPECIAL = /* @__PURE__ */ new Set(["conftest.py"]);
11996
12023
  var IGNORED_DIRS = /* @__PURE__ */ new Set([".venv", "node_modules", "__pycache__", ".git", "dist", "build"]);
11997
12024
  function subdirectories(dir) {
11998
- if (!existsSync41(dir)) return [];
12025
+ if (!existsSync42(dir)) return [];
11999
12026
  return readdirSync22(dir).filter((entry) => {
12000
12027
  if (IGNORED_DIRS.has(entry) || entry.startsWith(".")) return false;
12001
12028
  try {
@@ -12006,12 +12033,12 @@ function subdirectories(dir) {
12006
12033
  });
12007
12034
  }
12008
12035
  function regularPackagesOf(pluginDir2) {
12009
- return subdirectories(pluginDir2).filter((name) => existsSync41(join50(pluginDir2, name, "__init__.py"))).sort();
12036
+ return subdirectories(pluginDir2).filter((name) => existsSync42(join50(pluginDir2, name, "__init__.py"))).sort();
12010
12037
  }
12011
12038
  function bareTestModulesOf(pluginDir2) {
12012
12039
  const testsDir = join50(pluginDir2, "tests");
12013
- if (!existsSync41(testsDir)) return [];
12014
- if (existsSync41(join50(testsDir, "__init__.py"))) return [];
12040
+ if (!existsSync42(testsDir)) return [];
12041
+ if (existsSync42(join50(testsDir, "__init__.py"))) return [];
12015
12042
  return readdirSync22(testsDir).filter((f) => f.endsWith(".py") && !PYTEST_SPECIAL.has(f)).sort();
12016
12043
  }
12017
12044
  function findCollisions(servicesDir, pluginDirs) {
@@ -12059,7 +12086,7 @@ function formatCollisions(collisions) {
12059
12086
  async function runPluginCollisionCheck() {
12060
12087
  const root = (await execa17("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
12061
12088
  const servicesDir = join51(root, "services");
12062
- if (!existsSync42(servicesDir)) {
12089
+ if (!existsSync43(servicesDir)) {
12063
12090
  console.log("\u2713 plugin collision guard: no services/ directory \u2014 nothing to compare");
12064
12091
  return;
12065
12092
  }
@@ -12079,7 +12106,7 @@ async function runPluginCollisionCheck() {
12079
12106
  import { execa as execa18 } from "execa";
12080
12107
 
12081
12108
  // src/lib/plugin-terraform-guard.ts
12082
- import { existsSync as existsSync43, readFileSync as readFileSync37, readdirSync as readdirSync23 } from "fs";
12109
+ import { existsSync as existsSync44, readFileSync as readFileSync37, readdirSync as readdirSync23 } from "fs";
12083
12110
  import { dirname as dirname10, join as join52, relative as relative9, sep as sep3 } from "path";
12084
12111
  var SKIP_DIRS3 = /* @__PURE__ */ new Set(["node_modules", ".git", ".worktrees", "dist", ".venv", "__pycache__"]);
12085
12112
  var PLUGIN_MANIFEST_FILE2 = "biffo.plugin.json";
@@ -12122,14 +12149,14 @@ function readSubscriptions(absManifestPath) {
12122
12149
  }
12123
12150
  function checkPluginTerraform(root) {
12124
12151
  const violations = [];
12125
- const coreManifest = existsSync43(join52(root, CORE_MANIFEST_FILE)) ? readCoreManifest(root) : null;
12152
+ const coreManifest = existsSync44(join52(root, CORE_MANIFEST_FILE)) ? readCoreManifest(root) : null;
12126
12153
  for (const manifest of findPluginManifests(root)) {
12127
12154
  if (coreManifest && !isTemplateOwned(manifest, coreManifest)) continue;
12128
12155
  const absManifest = join52(root, manifest);
12129
12156
  const subscriptions = readSubscriptions(absManifest);
12130
12157
  if (subscriptions === null) continue;
12131
12158
  const pluginDir2 = dirname10(absManifest);
12132
- if (existsSync43(join52(pluginDir2, "terraform"))) continue;
12159
+ if (existsSync44(join52(pluginDir2, "terraform"))) continue;
12133
12160
  const relPluginDir = relative9(root, pluginDir2).split(sep3).join("/");
12134
12161
  violations.push({
12135
12162
  manifest,
@@ -12160,12 +12187,12 @@ async function runPluginTerraformCheck() {
12160
12187
  }
12161
12188
 
12162
12189
  // src/scripts/check-plugin-tool-supply.ts
12163
- import { existsSync as existsSync45 } from "fs";
12190
+ import { existsSync as existsSync46 } from "fs";
12164
12191
  import { join as join54 } from "path";
12165
12192
  import { execa as execa19 } from "execa";
12166
12193
 
12167
12194
  // src/lib/plugin-tool-supply-audit.ts
12168
- import { existsSync as existsSync44, readFileSync as readFileSync38, readdirSync as readdirSync24, statSync as statSync14 } from "fs";
12195
+ import { existsSync as existsSync45, readFileSync as readFileSync38, readdirSync as readdirSync24, statSync as statSync14 } from "fs";
12169
12196
  import { join as join53 } from "path";
12170
12197
 
12171
12198
  // src/lib/openrouter-model-snapshot.ts
@@ -12899,8 +12926,8 @@ function auditDeclaredModelIds(repoRoot, options = {}) {
12899
12926
  const now = options.now ?? /* @__PURE__ */ new Date();
12900
12927
  const configPath = join53(repoRoot, CONFIG_PY_PATH);
12901
12928
  const orchestrationPath = join53(repoRoot, ORCHESTRATION_SCHEMA_PATH);
12902
- const configMissing = !existsSync44(configPath);
12903
- const orchestrationSchemaMissing = !existsSync44(orchestrationPath);
12929
+ const configMissing = !existsSync45(configPath);
12930
+ const orchestrationSchemaMissing = !existsSync45(orchestrationPath);
12904
12931
  const knownSet = new Set(knownModelIds);
12905
12932
  const snapshotEmpty = knownModelIds.length === 0;
12906
12933
  const snapshotStale = isSnapshotStale(snapshotFetchedAt, now);
@@ -13117,7 +13144,7 @@ async function runPluginToolSupplyCheck() {
13117
13144
  const root = (await execa19("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
13118
13145
  let allOk = true;
13119
13146
  const pluginsRoot = join54(root, "services", "_plugins");
13120
- if (!existsSync45(pluginsRoot)) {
13147
+ if (!existsSync46(pluginsRoot)) {
13121
13148
  console.log("\u2713 plugin tool-supply guard: no services/_plugins/ \u2014 nothing to audit");
13122
13149
  } else {
13123
13150
  const report = auditPluginToolSupply(pluginsRoot);
@@ -13148,7 +13175,7 @@ async function runPluginToolSupplyCheck() {
13148
13175
  }
13149
13176
  }
13150
13177
  const servicesApiRoot = join54(root, "services", "api");
13151
- if (!existsSync45(servicesApiRoot)) {
13178
+ if (!existsSync46(servicesApiRoot)) {
13152
13179
  console.log("\u2713 plugin model-id guard: no services/api/ \u2014 nothing to audit");
13153
13180
  } else {
13154
13181
  const modelReport = auditDeclaredModelIds(root);
@@ -13325,7 +13352,7 @@ async function runReleaseSubjectCheck(argv) {
13325
13352
  }
13326
13353
 
13327
13354
  // src/scripts/check-skeleton-drift.ts
13328
- import { existsSync as existsSync46, readdirSync as readdirSync26 } from "fs";
13355
+ import { existsSync as existsSync47, readdirSync as readdirSync26 } from "fs";
13329
13356
  import { join as join56 } from "path";
13330
13357
  import { execa as execa21 } from "execa";
13331
13358
 
@@ -13453,7 +13480,7 @@ function discoverSkeletons(root) {
13453
13480
  } catch {
13454
13481
  return [];
13455
13482
  }
13456
- return entries.filter((name) => existsSync46(join56(skeletonsDir, name, ".github", "workflows", "ci.yml"))).sort();
13483
+ return entries.filter((name) => existsSync47(join56(skeletonsDir, name, ".github", "workflows", "ci.yml"))).sort();
13457
13484
  }
13458
13485
  async function runSkeletonDriftCheck() {
13459
13486
  const root = (await execa21("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
@@ -13462,7 +13489,7 @@ async function runSkeletonDriftCheck() {
13462
13489
  for (const name of skeletons) {
13463
13490
  const skeletonRoot = join56(root, "_skeletons", name);
13464
13491
  filesConsidered += findWorkflowFiles(skeletonRoot).length;
13465
- if (existsSync46(join56(skeletonRoot, "apps", "frontend", "src", "app", "layout.tsx"))) {
13492
+ if (existsSync47(join56(skeletonRoot, "apps", "frontend", "src", "app", "layout.tsx"))) {
13466
13493
  filesConsidered += 1;
13467
13494
  }
13468
13495
  }
@@ -13614,7 +13641,7 @@ function rawArgsAfter(subcommand) {
13614
13641
  }
13615
13642
 
13616
13643
  // src/commands/doctor.ts
13617
- import { existsSync as existsSync47, readFileSync as readFileSync40 } from "fs";
13644
+ import { existsSync as existsSync48, readFileSync as readFileSync40 } from "fs";
13618
13645
  import { join as join57, resolve as resolve20 } from "path";
13619
13646
  import chalk21 from "chalk";
13620
13647
  import { Command as Command25 } from "commander";
@@ -13795,7 +13822,7 @@ async function runDoctor(options, deps = { git: new GitAdapter() }) {
13795
13822
  }
13796
13823
  function readLocalCoreVersion(cwd) {
13797
13824
  const path = join57(cwd, INSTANCE_CORE_FILE);
13798
- if (!existsSync47(path)) return null;
13825
+ if (!existsSync48(path)) return null;
13799
13826
  try {
13800
13827
  return extractVersionField(readFileSync40(path, "utf8"));
13801
13828
  } catch {
@@ -13818,7 +13845,7 @@ function extractVersionField(contents) {
13818
13845
  }
13819
13846
  function readFossil(cwd) {
13820
13847
  const path = join57(cwd, CORE_VERSION_FILE);
13821
- if (!existsSync47(path)) return null;
13848
+ if (!existsSync48(path)) return null;
13822
13849
  try {
13823
13850
  const value = readFileSync40(path, "utf8").trim();
13824
13851
  return value === "" ? null : value;
@@ -14269,13 +14296,13 @@ import { fileURLToPath as fileURLToPath6 } from "url";
14269
14296
  import { Command as Command27 } from "commander";
14270
14297
 
14271
14298
  // src/lib/packaged-scripts.ts
14272
- import { existsSync as existsSync48 } from "fs";
14299
+ import { existsSync as existsSync49 } from "fs";
14273
14300
  import { dirname as dirname11, join as join58 } from "path";
14274
14301
  function findPackagedScript(startDir, relativePath) {
14275
14302
  let dir = startDir;
14276
14303
  for (; ; ) {
14277
14304
  const candidate = join58(dir, relativePath);
14278
- if (existsSync48(candidate)) return candidate;
14305
+ if (existsSync49(candidate)) return candidate;
14279
14306
  const parent = dirname11(dir);
14280
14307
  if (parent === dir) return null;
14281
14308
  dir = parent;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@biffo/cli",
3
- "version": "0.282.0",
3
+ "version": "0.283.1",
4
4
  "description": "Biffo project scaffolding CLI",
5
5
  "license": "MIT",
6
6
  "type": "module",