@biffo/cli 0.163.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.
- package/dist/index.js +88 -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}`);
|