@biffo/cli 0.164.0 → 0.165.0

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 +88 -2
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -6661,7 +6661,8 @@ function applySubstitutions(text, names) {
6661
6661
  return out;
6662
6662
  }
6663
6663
  var BINARY_EXTENSIONS = /\.(png|jpe?g|gif|ico|woff2?|ttf|zip|gz)$/i;
6664
- function scaffoldPlugin(skeletonRoot, destDir, names) {
6664
+ function scaffoldPlugin(skeletonRoot, destDir, names, options = {}) {
6665
+ const layout = options.layout ?? "in-tree";
6665
6666
  if (!existsSync22(skeletonRoot)) {
6666
6667
  throw new Error(`Plugin skeleton not found at ${skeletonRoot}`);
6667
6668
  }
@@ -6678,7 +6679,7 @@ function scaffoldPlugin(skeletonRoot, destDir, names) {
6678
6679
  (a, b) => a.name.localeCompare(b.name)
6679
6680
  )) {
6680
6681
  if (NEVER_COPY.has(entry.name)) continue;
6681
- if (relDir === "" && entry.name in STANDALONE_ONLY_ENTRIES) {
6682
+ if (layout === "in-tree" && relDir === "" && entry.name in STANDALONE_ONLY_ENTRIES) {
6682
6683
  skipped.push({ entry: entry.name, reason: STANDALONE_ONLY_ENTRIES[entry.name] });
6683
6684
  continue;
6684
6685
  }
@@ -6724,6 +6725,9 @@ function findSkeletonRoot(startDir, skeleton) {
6724
6725
  var pluginCreateCommand = new Command13("create").description("Scaffold a new plugin from the Biffo plugin skeleton: biffo plugin create <name>").argument("<name>", "Plugin name \u2014 lowercase kebab-case, e.g. acme-crm").option(
6725
6726
  "--first-party",
6726
6727
  "Scaffold into the template-owned services/_plugins/ carve-out. Only valid in the biffo-template repo itself \u2014 see notes."
6728
+ ).option(
6729
+ "--standalone",
6730
+ "Scaffold a standalone plugin repo (ADR-0003 section 2) into ./biffo-plugin-<name>/ instead of into this checkout, keeping its own CI/CD workflows"
6727
6731
  ).option(
6728
6732
  "--skeleton <path>",
6729
6733
  "Path to the plugin skeleton (defaults to _skeletons/plugin-template)"
@@ -6735,6 +6739,7 @@ var pluginCreateCommand = new Command13("create").description("Scaffold a new pl
6735
6739
  name,
6736
6740
  {
6737
6741
  firstParty: options.firstParty ?? false,
6742
+ standalone: options.standalone ?? false,
6738
6743
  ...options.skeleton ? { skeletonRoot: resolve11(options.skeleton) } : {},
6739
6744
  dryRun: options.dryRun ?? false,
6740
6745
  commit: options.commit !== false,
@@ -6750,6 +6755,15 @@ var pluginCreateCommand = new Command13("create").description("Scaffold a new pl
6750
6755
  );
6751
6756
  async function runPluginCreate(name, options, deps) {
6752
6757
  const names = deriveNames(name);
6758
+ if (options.standalone) {
6759
+ if (options.firstParty) {
6760
+ throw new Error(
6761
+ "--standalone and --first-party are opposites: --first-party authors a plugin *inside* the template at services/_plugins/, while --standalone authors one in its own repository (ADR-0003 section 2). Pick one."
6762
+ );
6763
+ }
6764
+ await runStandaloneCreate(names, options, deps);
6765
+ return;
6766
+ }
6753
6767
  const isInstance = existsSync23(join23(options.cwd, INSTANCE_CORE_FILE));
6754
6768
  if (options.firstParty && isInstance) {
6755
6769
  throw new Error(
@@ -6808,6 +6822,78 @@ async function runPluginCreate(name, options, deps) {
6808
6822
  }
6809
6823
  printNextSteps(names, relDir, channel);
6810
6824
  }
6825
+ async function runStandaloneCreate(names, options, deps) {
6826
+ const destDir = join23(options.cwd, names.dist);
6827
+ if (existsSync23(destDir)) {
6828
+ throw new Error(`${names.dist}/ already exists. Choose a different name, or remove it first.`);
6829
+ }
6830
+ const skeletonRoot = resolveSkeletonRoot(options);
6831
+ if (options.dryRun) {
6832
+ console.log(chalk13.bold("\n Dry run \u2014 no changes will be made\n"));
6833
+ console.log(` Plugin: ${names.slug}`);
6834
+ console.log(" Channel: standalone repo");
6835
+ console.log(` Would scaffold: ${names.dist}/`);
6836
+ console.log(` From skeleton: ${skeletonRoot}`);
6837
+ console.log(` Python package: ${names.pkg} (dist: ${names.dist})`);
6838
+ console.log(" Would git init: yes, on branch dev, with an initial commit\n");
6839
+ return;
6840
+ }
6841
+ const { files } = scaffoldPlugin(skeletonRoot, destDir, names, { layout: "standalone" });
6842
+ restorePackagedDotfiles(destDir);
6843
+ log.success(`Scaffolded ${String(files.length)} file(s) into ${names.dist}/`);
6844
+ const manifest = validateManifest(
6845
+ JSON.parse(readFileSync17(join23(destDir, "biffo.plugin.json"), "utf8"))
6846
+ );
6847
+ if (manifest.name !== names.slug) {
6848
+ throw new Error(
6849
+ `Scaffolded manifest declares name '${manifest.name}', expected '${names.slug}'. The skeleton's manifest name may have diverged from 'example-plugin'.`
6850
+ );
6851
+ }
6852
+ log.success(
6853
+ `Manifest valid \u2014 ${String(manifest.tables.length)} table(s), ${String(manifest.api_routes.length)} route(s)`
6854
+ );
6855
+ if (options.commit) {
6856
+ await deps.git.init(destDir);
6857
+ await deps.git.add(destDir, ["."]);
6858
+ await deps.git.commit(destDir, `feat: scaffold ${names.slug} plugin`);
6859
+ log.success(`Initialised a git repo on dev with an initial commit`);
6860
+ }
6861
+ printStandaloneNextSteps(names, minorOf(manifest.version));
6862
+ }
6863
+ function minorOf(version) {
6864
+ const match = /^(\d+)\.(\d+)/.exec(version);
6865
+ return match ? `${match[1]}.${match[2]}` : version;
6866
+ }
6867
+ function printStandaloneNextSteps(names, minor) {
6868
+ console.log(chalk13.bold("\n Standalone plugin repo scaffolded!\n"));
6869
+ console.log(` ${names.dist}/ is a complete plugin repository: manifest, example table and`);
6870
+ console.log(" routes, terraform/ module, and its own CI, release and registry workflows.\n");
6871
+ console.log(" Next:");
6872
+ console.log(chalk13.dim(` 1. cd ${names.dist} && edit biffo.plugin.json`));
6873
+ console.log(
6874
+ chalk13.dim(" 2. Create the repo \u2014 plugin repos are dev-only (AGENTS.md section 2):")
6875
+ );
6876
+ console.log(chalk13.dim(` gh repo create <org>/${names.dist} --private --source=. --push`));
6877
+ console.log(
6878
+ chalk13.dim(" gh api -X PATCH repos/<org>/" + names.dist + " -f default_branch=dev")
6879
+ );
6880
+ console.log(chalk13.dim(" 3. Publish it to the registry so it appears in the plugin store:"));
6881
+ console.log(chalk13.dim(" see .github/workflows/publish-registry.yml in the new repo"));
6882
+ console.log(
6883
+ chalk13.dim(` 4. Consumers install it with: biffo plugin install ${names.slug}@${minor}
6884
+ `)
6885
+ );
6886
+ }
6887
+ function resolveSkeletonRoot(options) {
6888
+ const here = dirname8(fileURLToPath5(import.meta.url));
6889
+ const skeletonRoot = options.skeletonRoot ?? findSkeletonRoot(here, "plugin-template") ?? join23(options.cwd, "_skeletons", "plugin-template");
6890
+ if (!existsSync23(skeletonRoot)) {
6891
+ throw new Error(
6892
+ `Could not find the plugin skeleton (_skeletons/plugin-template/). Pass --skeleton <path> to point at it explicitly.`
6893
+ );
6894
+ }
6895
+ return skeletonRoot;
6896
+ }
6811
6897
  function printDryRun3(names, relDir, skeletonRoot, channel) {
6812
6898
  console.log(chalk13.bold("\n Dry run \u2014 no changes will be made\n"));
6813
6899
  console.log(` Plugin: ${names.slug}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@biffo/cli",
3
- "version": "0.164.0",
3
+ "version": "0.165.0",
4
4
  "description": "Biffo project scaffolding CLI",
5
5
  "license": "MIT",
6
6
  "type": "module",