@biffo/cli 0.283.3 → 0.283.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.
Files changed (2) hide show
  1. package/dist/index.js +138 -43
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -9693,6 +9693,7 @@ import { cpSync as cpSync6, existsSync as existsSync35, mkdirSync as mkdirSync12
9693
9693
  import { join as join37, relative as relative7, resolve as resolve17 } from "path";
9694
9694
  import chalk19 from "chalk";
9695
9695
  import { Command as Command20 } from "commander";
9696
+ import { execa as execa7 } from "execa";
9696
9697
  import inquirer7 from "inquirer";
9697
9698
  var pluginUpgradeCommand = new Command20("upgrade").description(
9698
9699
  "Upgrade an installed plugin to a new minor version (biffo plugin upgrade <name>@<new-minor>) or refresh it in place from a local, unpublished checkout (biffo plugin upgrade --local <path>)"
@@ -9794,6 +9795,7 @@ async function runPluginUpgrade(target, options, deps) {
9794
9795
  refuseIfModuleStillReferenced(options.cwd, modulesDir, entry.name);
9795
9796
  }
9796
9797
  const previousProvenance = readProvenance(targetDir);
9798
+ const previousPyproject = readPyprojectIfPresent(targetDir);
9797
9799
  rmSync10(targetDir, { recursive: true, force: true });
9798
9800
  mkdirSync12(targetDir, { recursive: true });
9799
9801
  cpSync6(tmpDir, targetDir, { recursive: true });
@@ -9804,6 +9806,7 @@ async function runPluginUpgrade(target, options, deps) {
9804
9806
  );
9805
9807
  writePluginProvenance(targetDir, reconcileProvenance(previousProvenance, nextProvenance));
9806
9808
  applyWorkspaceSources(targetDir, options.cwd, `services/${entry.name}`);
9809
+ const newPyproject = readPyprojectIfPresent(targetDir);
9807
9810
  const stagePaths = [`services/${entry.name}`];
9808
9811
  if (existsSync35(modulesDir)) {
9809
9812
  rmSync10(modulesDir, { recursive: true, force: true });
@@ -9835,12 +9838,29 @@ async function runPluginUpgrade(target, options, deps) {
9835
9838
  if (seedResult.vendored) {
9836
9839
  stagePaths.push(seedResult.stagedPath);
9837
9840
  }
9841
+ const lockOutcomes = await relockIfDependenciesChanged(
9842
+ options.cwd,
9843
+ `services/${entry.name}/pyproject.toml`,
9844
+ previousPyproject,
9845
+ newPyproject,
9846
+ deps
9847
+ );
9848
+ for (const outcome of lockOutcomes) {
9849
+ if (outcome.ok) stagePaths.push(outcome.trigger.lockfile);
9850
+ }
9838
9851
  const label = currentVersion ? `${entry.name} ${currentVersion} -> ${entry.version}` : `${entry.name} to ${entry.version}`;
9839
9852
  const commitMessage = `feat(plugins): upgrade ${label}`;
9840
9853
  await deps.git.add(options.cwd, stagePaths);
9841
9854
  await deps.git.commit(options.cwd, commitMessage);
9842
9855
  log.success(`Committed: ${commitMessage}`);
9843
- console.log(chalk19.bold("\n Plugin upgraded!\n"));
9856
+ const lockFailures = describeFailures(lockOutcomes);
9857
+ if (lockFailures.length > 0) {
9858
+ console.log(chalk19.yellow.bold("\n \u26A0 Plugin upgraded, but uv.lock needs attention\n"));
9859
+ for (const failure of lockFailures) console.log(chalk19.yellow(` ${failure}`));
9860
+ console.log();
9861
+ } else {
9862
+ console.log(chalk19.bold("\n Plugin upgraded!\n"));
9863
+ }
9844
9864
  console.log(` ${entry.name}@${entry.version} is committed at services/${entry.name}/`);
9845
9865
  console.log(" Push and redeploy to apply its updated tables and routes:");
9846
9866
  console.log(chalk19.dim(` git push`));
@@ -9889,6 +9909,7 @@ async function runLocalPluginRefresh(localPath, options, deps) {
9889
9909
  refuseIfModuleStillReferenced(options.cwd, modulesDir, source.name);
9890
9910
  }
9891
9911
  const previousProvenance = readProvenance(targetDir);
9912
+ const previousPyproject = readPyprojectIfPresent(targetDir);
9892
9913
  if (inTreeSource) {
9893
9914
  log.info(
9894
9915
  `services/${source.name}/ is already the local checkout \u2014 nothing to copy; re-syncing its Terraform module and checking for a migration.`
@@ -9902,6 +9923,7 @@ async function runLocalPluginRefresh(localPath, options, deps) {
9902
9923
  const nextProvenance = inTreeSource ? inTreePluginProvenance(`services/${source.name}`) : await resolveLocalProvenance(source.sourceDir, source.origin);
9903
9924
  writePluginProvenance(targetDir, reconcileProvenance(previousProvenance, nextProvenance));
9904
9925
  applyWorkspaceSources(targetDir, options.cwd, `services/${source.name}`);
9926
+ const newPyproject = readPyprojectIfPresent(targetDir);
9905
9927
  const stagePaths = [`services/${source.name}`];
9906
9928
  if (existsSync35(modulesDir)) {
9907
9929
  rmSync10(modulesDir, { recursive: true, force: true });
@@ -9935,6 +9957,16 @@ async function runLocalPluginRefresh(localPath, options, deps) {
9935
9957
  if (seedResult.vendored) {
9936
9958
  stagePaths.push(seedResult.stagedPath);
9937
9959
  }
9960
+ const lockOutcomes = await relockIfDependenciesChanged(
9961
+ options.cwd,
9962
+ `services/${source.name}/pyproject.toml`,
9963
+ previousPyproject,
9964
+ newPyproject,
9965
+ deps
9966
+ );
9967
+ for (const outcome of lockOutcomes) {
9968
+ if (outcome.ok) stagePaths.push(outcome.trigger.lockfile);
9969
+ }
9938
9970
  await deps.git.add(options.cwd, stagePaths);
9939
9971
  if (!await deps.git.hasUncommittedChanges(options.cwd)) {
9940
9972
  log.warn(`services/${source.name}/ already matches ${source.origin} \u2014 nothing to commit.`);
@@ -9943,7 +9975,14 @@ async function runLocalPluginRefresh(localPath, options, deps) {
9943
9975
  const commitMessage = `chore(plugins): refresh ${source.name} from local checkout`;
9944
9976
  await deps.git.commit(options.cwd, commitMessage);
9945
9977
  log.success(`Committed: ${commitMessage}`);
9946
- console.log(chalk19.bold("\n Plugin refreshed!\n"));
9978
+ const lockFailures = describeFailures(lockOutcomes);
9979
+ if (lockFailures.length > 0) {
9980
+ console.log(chalk19.yellow.bold("\n \u26A0 Plugin refreshed, but uv.lock needs attention\n"));
9981
+ for (const failure of lockFailures) console.log(chalk19.yellow(` ${failure}`));
9982
+ console.log();
9983
+ } else {
9984
+ console.log(chalk19.bold("\n Plugin refreshed!\n"));
9985
+ }
9947
9986
  console.log(` services/${source.name}/ now matches ${source.origin}`);
9948
9987
  console.log(" Push and redeploy to apply any updated tables and routes:");
9949
9988
  console.log(chalk19.dim(` git push`));
@@ -9964,6 +10003,62 @@ ${refList}
9964
10003
  A plugin repo without terraform/ is missing the directory, not declaring that the module should go, and a wrong destructive action here is worse than no action. Either remove the reference(s) above yourself, or run 'biffo plugin uninstall ${name}', which removes the module and unwires the reference together.`
9965
10004
  );
9966
10005
  }
10006
+ async function relockIfDependenciesChanged(cwd, relPyprojectPath, previousPyproject, newPyproject, deps) {
10007
+ if (!dependenciesChanged(previousPyproject, newPyproject)) return [];
10008
+ const triggers = lockfilesNeedingRefresh([relPyprojectPath], cwd);
10009
+ if (triggers.length === 0) return [];
10010
+ const run = deps.runCommand ?? defaultRunCommand2;
10011
+ const outcomes = await refreshLockfiles(cwd, triggers, run);
10012
+ const refreshed = outcomes.filter((o) => o.ok);
10013
+ if (refreshed.length > 0) {
10014
+ log.success(
10015
+ `Refreshed ${refreshed.map((o) => o.trigger.lockfile).join(", ")} \u2014 this refresh changed a dependency it locks.`
10016
+ );
10017
+ }
10018
+ for (const message of describeFailures(outcomes)) log.warn(message);
10019
+ return outcomes;
10020
+ }
10021
+ var defaultRunCommand2 = async (command, cwd) => {
10022
+ const [bin, ...args] = command;
10023
+ if (!bin) return { ok: false, error: "empty command" };
10024
+ try {
10025
+ await execa7(bin, args, { cwd });
10026
+ return { ok: true };
10027
+ } catch (err) {
10028
+ const cause = err;
10029
+ const detail = cause.stderr?.trim() || cause.shortMessage || cause.message || "failed";
10030
+ return { ok: false, error: detail.split("\n")[0] ?? "failed" };
10031
+ }
10032
+ };
10033
+ function readPyprojectIfPresent(targetDir) {
10034
+ const path = join37(targetDir, "pyproject.toml");
10035
+ return existsSync35(path) ? readFileSync26(path, "utf8") : null;
10036
+ }
10037
+ function dependenciesChanged(before, after) {
10038
+ if (before === after) return false;
10039
+ const beforeItems = before ? dependencySurface(before) : [];
10040
+ const afterItems = after ? dependencySurface(after) : [];
10041
+ return JSON.stringify(beforeItems) !== JSON.stringify(afterItems);
10042
+ }
10043
+ function dependencySurface(text) {
10044
+ const items = [...readTomlStringArray(text, "dependencies")];
10045
+ for (const header of ["dependency-groups", "project.optional-dependencies"]) {
10046
+ const body = tomlTableBody(text, header);
10047
+ if (!body) continue;
10048
+ for (const m of body.matchAll(/^([A-Za-z0-9_.-]+)\s*=\s*\[/gm)) {
10049
+ items.push(...readTomlStringArray(body, m[1]));
10050
+ }
10051
+ }
10052
+ return items.sort();
10053
+ }
10054
+ function tomlTableBody(text, header) {
10055
+ const escaped = header.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
10056
+ const headerMatch = new RegExp(`^\\[${escaped}\\]\\s*$`, "m").exec(text);
10057
+ if (!headerMatch) return null;
10058
+ const rest = text.slice(headerMatch.index + headerMatch[0].length);
10059
+ const nextHeader = /^\[/m.exec(rest);
10060
+ return nextHeader ? rest.slice(0, nextHeader.index) : rest;
10061
+ }
9967
10062
  function readInstalledVersion2(targetDir) {
9968
10063
  const manifestPath = join37(targetDir, "biffo.plugin.json");
9969
10064
  if (!existsSync35(manifestPath)) return void 0;
@@ -10314,7 +10409,7 @@ import { Command as Command24 } from "commander";
10314
10409
  // src/scripts/check-adr-numbering.ts
10315
10410
  import { existsSync as existsSync38 } from "fs";
10316
10411
  import { join as join39 } from "path";
10317
- import { execa as execa7 } from "execa";
10412
+ import { execa as execa8 } from "execa";
10318
10413
 
10319
10414
  // src/lib/adr-numbering-guard.ts
10320
10415
  import { existsSync as existsSync37, readdirSync as readdirSync15, readFileSync as readFileSync28 } from "fs";
@@ -10388,7 +10483,7 @@ function formatAdrReservedRangeViolations(violations, reservedUpTo = TEMPLATE_AD
10388
10483
 
10389
10484
  // src/scripts/check-adr-numbering.ts
10390
10485
  async function runAdrNumberingCheck() {
10391
- const root = (await execa7("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
10486
+ const root = (await execa8("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
10392
10487
  const adrDir = join39(root, "docs", "ADR");
10393
10488
  if (!existsSync38(adrDir)) {
10394
10489
  console.log("\u2713 ADR numbering guard: no docs/ADR/ directory \u2014 nothing to compare");
@@ -10429,7 +10524,7 @@ Already accepted? List it in docs/ADR/${ALLOWLIST_FILENAME} instead of leaving t
10429
10524
 
10430
10525
  // src/scripts/check-branch-protection.ts
10431
10526
  import { Octokit as Octokit2 } from "@octokit/rest";
10432
- import { execa as execa8 } from "execa";
10527
+ import { execa as execa9 } from "execa";
10433
10528
 
10434
10529
  // src/lib/branch-protection-apply.ts
10435
10530
  var CONTEXT_CONSISTENCY_THRESHOLD = 2 / 3;
@@ -10556,7 +10651,7 @@ async function resolveRepo(explicit) {
10556
10651
  }
10557
10652
  return { owner, repo };
10558
10653
  }
10559
- const { stdout } = await execa8("git", ["remote", "get-url", "origin"]);
10654
+ const { stdout } = await execa9("git", ["remote", "get-url", "origin"]);
10560
10655
  const m = /github\.com[:/]([^/]+)\/(.+?)(?:\.git)?$/.exec(stdout.trim());
10561
10656
  if (!m?.[1] || !m[2]) {
10562
10657
  console.error(
@@ -10690,7 +10785,7 @@ async function runBranchProtectionCheck(explicitRepo, options = {}) {
10690
10785
  // src/scripts/check-codeql-suppression.ts
10691
10786
  import { existsSync as existsSync39 } from "fs";
10692
10787
  import { join as join41, relative as relative8 } from "path";
10693
- import { execa as execa9 } from "execa";
10788
+ import { execa as execa10 } from "execa";
10694
10789
 
10695
10790
  // src/lib/codeql-suppression-guard.ts
10696
10791
  import { readdirSync as readdirSync16, readFileSync as readFileSync29, statSync as statSync9 } from "fs";
@@ -10761,7 +10856,7 @@ function sweepCodeqlSuppressionComments(root) {
10761
10856
 
10762
10857
  // src/scripts/check-codeql-suppression.ts
10763
10858
  async function runCodeqlSuppressionCheck() {
10764
- const root = (await execa9("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
10859
+ const root = (await execa10("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
10765
10860
  const scanRoot = join41(root, "cli", "src");
10766
10861
  if (!existsSync39(scanRoot)) {
10767
10862
  console.log(
@@ -10787,7 +10882,7 @@ async function runCodeqlSuppressionCheck() {
10787
10882
  }
10788
10883
 
10789
10884
  // src/scripts/check-cognito-invite-template.ts
10790
- import { execa as execa10 } from "execa";
10885
+ import { execa as execa11 } from "execa";
10791
10886
 
10792
10887
  // src/lib/cognito-invite-template-guard.ts
10793
10888
  import { readdirSync as readdirSync17, readFileSync as readFileSync30, statSync as statSync10 } from "fs";
@@ -10894,7 +10989,7 @@ function checkCognitoInviteTemplates(repoRoot) {
10894
10989
 
10895
10990
  // src/scripts/check-cognito-invite-template.ts
10896
10991
  async function runCognitoInviteTemplateCheck() {
10897
- const root = (await execa10("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
10992
+ const root = (await execa11("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
10898
10993
  const files = findModuleTerraformFiles(root);
10899
10994
  console.log(`audited ${files.length} .tf file(s) under modules/ under ${root}`);
10900
10995
  if (files.length === 0) {
@@ -10917,7 +11012,7 @@ async function runCognitoInviteTemplateCheck() {
10917
11012
 
10918
11013
  // src/scripts/check-core-direct-paths.ts
10919
11014
  import { join as join44 } from "path";
10920
- import { execa as execa11 } from "execa";
11015
+ import { execa as execa12 } from "execa";
10921
11016
 
10922
11017
  // src/lib/core-direct-paths-audit.ts
10923
11018
  import { existsSync as existsSync40, readFileSync as readFileSync31, readdirSync as readdirSync18, statSync as statSync11 } from "fs";
@@ -11245,7 +11340,7 @@ function auditSiblingCoreDirectPaths(params) {
11245
11340
 
11246
11341
  // src/scripts/check-core-direct-paths.ts
11247
11342
  async function runCoreDirectPathsCheck(opts = {}) {
11248
- const root = (await execa11("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
11343
+ const root = (await execa12("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
11249
11344
  const sibling = opts.sibling ?? "sibling-template (self-check)";
11250
11345
  const frontendSrcDir = opts.frontendSrc ?? join44(root, "_skeletons", "sibling-template", "apps", "frontend", "src");
11251
11346
  let coreApiSrcDir;
@@ -11299,7 +11394,7 @@ async function runCoreDirectPathsCheck(opts = {}) {
11299
11394
  }
11300
11395
 
11301
11396
  // src/scripts/check-core-ownership.ts
11302
- import { execa as execa12 } from "execa";
11397
+ import { execa as execa13 } from "execa";
11303
11398
  var BOLD = "\x1B[1m";
11304
11399
  var DIM = "\x1B[2m";
11305
11400
  var RED = "\x1B[31m";
@@ -11310,7 +11405,7 @@ async function runOwnershipCheck(argv) {
11310
11405
  const stagedFlag = args.indexOf("--staged");
11311
11406
  const staged = stagedFlag !== -1;
11312
11407
  const messageFile = staged ? args[stagedFlag + 1] : void 0;
11313
- const root = (await execa12("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
11408
+ const root = (await execa13("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
11314
11409
  const ownership = classifyRepoOwnership(root);
11315
11410
  if (ownership === "template") {
11316
11411
  console.log("\u2713 core ownership guard: skipped \u2014 this is the template, which owns these paths.");
@@ -11326,7 +11421,7 @@ async function runOwnershipCheck(argv) {
11326
11421
  let deletedFiles = [];
11327
11422
  let commitMessage = "";
11328
11423
  if (staged) {
11329
- const { stdout } = await execa12("git", ["diff", "--cached", "--name-status"], { cwd: root });
11424
+ const { stdout } = await execa13("git", ["diff", "--cached", "--name-status"], { cwd: root });
11330
11425
  ({ changed: changedFiles, deleted: deletedFiles } = parseNameStatus(stdout));
11331
11426
  if (messageFile) {
11332
11427
  const { readFileSync: readFileSync41, existsSync: existsSync50 } = await import("fs");
@@ -11338,18 +11433,18 @@ async function runOwnershipCheck(argv) {
11338
11433
  console.error("No base ref: set GITHUB_BASE_REF or pass a base branch as the first argument.");
11339
11434
  process.exit(2);
11340
11435
  }
11341
- await execa12("git", ["fetch", "--quiet", "origin", base], { cwd: root, reject: false });
11342
- const { stdout } = await execa12("git", ["diff", "--name-status", `origin/${base}...HEAD`], {
11436
+ await execa13("git", ["fetch", "--quiet", "origin", base], { cwd: root, reject: false });
11437
+ const { stdout } = await execa13("git", ["diff", "--name-status", `origin/${base}...HEAD`], {
11343
11438
  cwd: root
11344
11439
  });
11345
11440
  ({ changed: changedFiles, deleted: deletedFiles } = parseNameStatus(stdout));
11346
- const { stdout: log2 } = await execa12("git", ["log", "--format=%B", `origin/${base}..HEAD`], {
11441
+ const { stdout: log2 } = await execa13("git", ["log", "--format=%B", `origin/${base}..HEAD`], {
11347
11442
  cwd: root,
11348
11443
  reject: false
11349
11444
  });
11350
11445
  commitMessage = log2;
11351
11446
  }
11352
- const { stdout: gitBranch } = await execa12("git", ["rev-parse", "--abbrev-ref", "HEAD"], {
11447
+ const { stdout: gitBranch } = await execa13("git", ["rev-parse", "--abbrev-ref", "HEAD"], {
11353
11448
  cwd: root,
11354
11449
  reject: false
11355
11450
  });
@@ -11431,7 +11526,7 @@ ${BOLD}If the divergence is deliberate${OFF}
11431
11526
  }
11432
11527
 
11433
11528
  // src/scripts/check-eventbridge-log-permissions.ts
11434
- import { execa as execa13 } from "execa";
11529
+ import { execa as execa14 } from "execa";
11435
11530
 
11436
11531
  // src/lib/eventbridge-log-permission-guard.ts
11437
11532
  import { readFileSync as readFileSync32, readdirSync as readdirSync19, statSync as statSync12 } from "fs";
@@ -11608,7 +11703,7 @@ function auditEventBridgeLogPermissions(root) {
11608
11703
 
11609
11704
  // src/scripts/check-eventbridge-log-permissions.ts
11610
11705
  async function runEventBridgeLogPermissionCheck() {
11611
- const root = (await execa13("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
11706
+ const root = (await execa14("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
11612
11707
  let report;
11613
11708
  try {
11614
11709
  report = auditEventBridgeLogPermissions(root);
@@ -11645,7 +11740,7 @@ async function runEventBridgeLogPermissionCheck() {
11645
11740
  }
11646
11741
 
11647
11742
  // src/scripts/check-lambda-output.ts
11648
- import { execa as execa14 } from "execa";
11743
+ import { execa as execa15 } from "execa";
11649
11744
 
11650
11745
  // src/lib/lambda-output-guard.ts
11651
11746
  import { readFileSync as readFileSync34 } from "fs";
@@ -11807,7 +11902,7 @@ function checkLambdaOutput(repoRoot) {
11807
11902
 
11808
11903
  // src/scripts/check-lambda-output.ts
11809
11904
  async function runLambdaOutputCheck() {
11810
- const root = (await execa14("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
11905
+ const root = (await execa15("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
11811
11906
  const files = findWorkflowFiles(root);
11812
11907
  console.log(`audited ${files.length} workflow file(s) under ${root}`);
11813
11908
  if (files.length === 0) {
@@ -11831,7 +11926,7 @@ async function runLambdaOutputCheck() {
11831
11926
  // src/scripts/check-pipe-trap.ts
11832
11927
  import { readFileSync as readFileSync35, readdirSync as readdirSync21 } from "fs";
11833
11928
  import { join as join48, relative as relative9 } from "path";
11834
- import { execa as execa15 } from "execa";
11929
+ import { execa as execa16 } from "execa";
11835
11930
 
11836
11931
  // src/lib/pipe-trap-guard.ts
11837
11932
  var STATUS_BEARING = [
@@ -11943,7 +12038,7 @@ function shellFiles(root) {
11943
12038
  return out;
11944
12039
  }
11945
12040
  async function runPipeTrapCheck() {
11946
- const root = (await execa15("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
12041
+ const root = (await execa16("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
11947
12042
  const files = shellFiles(root);
11948
12043
  console.log(`audited ${files.length} shell file(s) under scripts/ and .githooks/ under ${root}`);
11949
12044
  if (files.length === 0) {
@@ -11970,7 +12065,7 @@ async function runPipeTrapCheck() {
11970
12065
  }
11971
12066
 
11972
12067
  // src/scripts/check-plugin-allowlist-convention.ts
11973
- import { execa as execa16 } from "execa";
12068
+ import { execa as execa17 } from "execa";
11974
12069
 
11975
12070
  // src/lib/plugin-allowlist-convention.ts
11976
12071
  import { readFileSync as readFileSync36 } from "fs";
@@ -12081,7 +12176,7 @@ Plugins would be rejected by require_service_principal (ADR-0009). Fix the glob,
12081
12176
 
12082
12177
  // src/scripts/check-plugin-allowlist-convention.ts
12083
12178
  async function runPluginAllowlistConventionCheck() {
12084
- const root = (await execa16("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
12179
+ const root = (await execa17("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
12085
12180
  let violations;
12086
12181
  try {
12087
12182
  violations = checkAllowlistConvention(root);
@@ -12108,7 +12203,7 @@ async function runPluginAllowlistConventionCheck() {
12108
12203
  // src/scripts/check-plugin-collisions.ts
12109
12204
  import { existsSync as existsSync43 } from "fs";
12110
12205
  import { join as join51 } from "path";
12111
- import { execa as execa17 } from "execa";
12206
+ import { execa as execa18 } from "execa";
12112
12207
 
12113
12208
  // src/lib/plugin-collision-guard.ts
12114
12209
  import { existsSync as existsSync42, readdirSync as readdirSync22, statSync as statSync14 } from "fs";
@@ -12178,7 +12273,7 @@ function formatCollisions(collisions) {
12178
12273
 
12179
12274
  // src/scripts/check-plugin-collisions.ts
12180
12275
  async function runPluginCollisionCheck() {
12181
- const root = (await execa17("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
12276
+ const root = (await execa18("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
12182
12277
  const servicesDir = join51(root, "services");
12183
12278
  if (!existsSync43(servicesDir)) {
12184
12279
  console.log("\u2713 plugin collision guard: no services/ directory \u2014 nothing to compare");
@@ -12197,7 +12292,7 @@ async function runPluginCollisionCheck() {
12197
12292
  }
12198
12293
 
12199
12294
  // src/scripts/check-plugin-terraform.ts
12200
- import { execa as execa18 } from "execa";
12295
+ import { execa as execa19 } from "execa";
12201
12296
 
12202
12297
  // src/lib/plugin-terraform-guard.ts
12203
12298
  import { existsSync as existsSync44, readFileSync as readFileSync37, readdirSync as readdirSync23 } from "fs";
@@ -12270,7 +12365,7 @@ function formatViolations(violations) {
12270
12365
 
12271
12366
  // src/scripts/check-plugin-terraform.ts
12272
12367
  async function runPluginTerraformCheck() {
12273
- const root = (await execa18("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
12368
+ const root = (await execa19("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
12274
12369
  const violations = checkPluginTerraform(root);
12275
12370
  if (violations.length > 0) {
12276
12371
  console.error("\u2717 plugin Terraform guard: event subscriptions with no infrastructure\n");
@@ -12283,7 +12378,7 @@ async function runPluginTerraformCheck() {
12283
12378
  // src/scripts/check-plugin-tool-supply.ts
12284
12379
  import { existsSync as existsSync46 } from "fs";
12285
12380
  import { join as join54 } from "path";
12286
- import { execa as execa19 } from "execa";
12381
+ import { execa as execa20 } from "execa";
12287
12382
 
12288
12383
  // src/lib/plugin-tool-supply-audit.ts
12289
12384
  import { existsSync as existsSync45, readFileSync as readFileSync38, readdirSync as readdirSync24, statSync as statSync15 } from "fs";
@@ -13235,7 +13330,7 @@ function auditPluginToolSupply(pluginsRoot) {
13235
13330
 
13236
13331
  // src/scripts/check-plugin-tool-supply.ts
13237
13332
  async function runPluginToolSupplyCheck() {
13238
- const root = (await execa19("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
13333
+ const root = (await execa20("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
13239
13334
  let allOk = true;
13240
13335
  const pluginsRoot = join54(root, "services", "_plugins");
13241
13336
  if (!existsSync46(pluginsRoot)) {
@@ -13315,7 +13410,7 @@ async function runPluginToolSupplyCheck() {
13315
13410
  }
13316
13411
 
13317
13412
  // src/scripts/check-release-subject.ts
13318
- import { execa as execa20 } from "execa";
13413
+ import { execa as execa21 } from "execa";
13319
13414
 
13320
13415
  // src/lib/release-version.ts
13321
13416
  var MINOR_TYPES = /* @__PURE__ */ new Set(["feat"]);
@@ -13352,7 +13447,7 @@ async function fetchPrTitleViaGh({
13352
13447
  PR_NUMBER,
13353
13448
  GH_REPO
13354
13449
  }) {
13355
- const { stdout } = await execa20(
13450
+ const { stdout } = await execa21(
13356
13451
  "gh",
13357
13452
  ["pr", "view", PR_NUMBER, "--repo", GH_REPO, "--json", "title", "--jq", ".title"],
13358
13453
  { env: { ...process.env, GH_TOKEN } }
@@ -13388,7 +13483,7 @@ async function resolveReleaseSubject({
13388
13483
  );
13389
13484
  }
13390
13485
  }
13391
- return (await execa20("git", ["log", "-1", "--format=%s"], { cwd })).stdout.trim();
13486
+ return (await execa21("git", ["log", "-1", "--format=%s"], { cwd })).stdout.trim();
13392
13487
  }
13393
13488
  async function runReleaseSubjectCheck(argv) {
13394
13489
  const base = process.env["GITHUB_BASE_REF"] ?? argv[0];
@@ -13396,9 +13491,9 @@ async function runReleaseSubjectCheck(argv) {
13396
13491
  console.error("No base ref: set GITHUB_BASE_REF or pass a base branch as the first argument.");
13397
13492
  process.exit(2);
13398
13493
  }
13399
- const root = (await execa20("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
13400
- await execa20("git", ["fetch", "--quiet", "origin", base], { cwd: root, reject: false });
13401
- const { stdout } = await execa20("git", ["diff", "--name-only", `origin/${base}...HEAD`], {
13494
+ const root = (await execa21("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
13495
+ await execa21("git", ["fetch", "--quiet", "origin", base], { cwd: root, reject: false });
13496
+ const { stdout } = await execa21("git", ["diff", "--name-only", `origin/${base}...HEAD`], {
13402
13497
  cwd: root
13403
13498
  });
13404
13499
  const changedFiles = stdout.split("\n").map((s) => s.trim()).filter(Boolean);
@@ -13448,7 +13543,7 @@ async function runReleaseSubjectCheck(argv) {
13448
13543
  // src/scripts/check-skeleton-drift.ts
13449
13544
  import { existsSync as existsSync47, readdirSync as readdirSync26 } from "fs";
13450
13545
  import { join as join56 } from "path";
13451
- import { execa as execa21 } from "execa";
13546
+ import { execa as execa22 } from "execa";
13452
13547
 
13453
13548
  // src/lib/skeleton-drift-guard.ts
13454
13549
  import { readFileSync as readFileSync39, readdirSync as readdirSync25, statSync as statSync16 } from "fs";
@@ -13577,7 +13672,7 @@ function discoverSkeletons(root) {
13577
13672
  return entries.filter((name) => existsSync47(join56(skeletonsDir, name, ".github", "workflows", "ci.yml"))).sort();
13578
13673
  }
13579
13674
  async function runSkeletonDriftCheck() {
13580
- const root = (await execa21("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
13675
+ const root = (await execa22("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
13581
13676
  const skeletons = discoverSkeletons(root);
13582
13677
  let filesConsidered = 0;
13583
13678
  for (const name of skeletons) {
@@ -13609,9 +13704,9 @@ async function runSkeletonDriftCheck() {
13609
13704
  }
13610
13705
 
13611
13706
  // src/scripts/check-terraform-input.ts
13612
- import { execa as execa22 } from "execa";
13707
+ import { execa as execa23 } from "execa";
13613
13708
  async function runTerraformInputCheck() {
13614
- const root = (await execa22("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
13709
+ const root = (await execa23("git", ["rev-parse", "--show-toplevel"])).stdout.trim();
13615
13710
  const files = findWorkflowFiles(root);
13616
13711
  console.log(`audited ${files.length} workflow file(s) under ${root}`);
13617
13712
  if (files.length === 0) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@biffo/cli",
3
- "version": "0.283.3",
3
+ "version": "0.283.4",
4
4
  "description": "Biffo project scaffolding CLI",
5
5
  "license": "MIT",
6
6
  "type": "module",