@biffo/cli 0.303.3 → 0.304.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.
|
@@ -137,7 +137,7 @@ repository with its own independent `uv sync` / `uv.lock`, not inside
|
|
|
137
137
|
biffo-template's workspace. Once copied out, `uv sync && uv run pytest`
|
|
138
138
|
works standalone with no dependency on the rest of biffo-template.
|
|
139
139
|
|
|
140
|
-
## The `biffo-plugin-sdk` dependency: PyPI pin
|
|
140
|
+
## The `biffo-plugin-sdk` dependency: PyPI pin
|
|
141
141
|
|
|
142
142
|
`pyproject.toml` declares:
|
|
143
143
|
|
|
@@ -148,41 +148,30 @@ dependencies = [
|
|
|
148
148
|
]
|
|
149
149
|
```
|
|
150
150
|
|
|
151
|
-
This is a **PyPI-style version pin
|
|
152
|
-
|
|
151
|
+
This is a **PyPI-style version pin**: the SDK is published via
|
|
152
|
+
biffo-template's
|
|
153
153
|
[`.github/workflows/publish-sdk.yml`](https://github.com/keiranholloway/biffo-template/blob/main/.github/workflows/publish-sdk.yml)
|
|
154
|
-
|
|
155
|
-
|
|
154
|
+
(Trusted Publishing) on a pushed `sdk-v*` tag, and the first release has
|
|
155
|
+
already happened — this skeleton's own `uv.lock` resolves `biffo-plugin-sdk`
|
|
156
|
+
1.4.0 from `https://pypi.org/simple` (see its `biffo-plugin-sdk` entry).
|
|
157
|
+
`>=1.0,<2.0` matches the `"biffo-plugin-sdk": "^1.0"` that
|
|
156
158
|
`biffo.plugin.json` declares, and the SDK carries its own independent
|
|
157
159
|
semver — it is **not** tied to the template's core version, so a major
|
|
158
160
|
bump here means the plugin API broke and nothing else.
|
|
159
161
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
`
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
[tool.uv.sources]
|
|
174
|
-
biffo-plugin-sdk = { path = "../../packages/python-sdk", editable = true }
|
|
175
|
-
```
|
|
176
|
-
2. **Git dependency** (developing this plugin as a genuinely separate repo
|
|
177
|
-
against an unpublished SDK):
|
|
178
|
-
```toml
|
|
179
|
-
[tool.uv.sources]
|
|
180
|
-
biffo-plugin-sdk = { git = "https://github.com/keiranholloway/biffo-template", subdirectory = "packages/python-sdk" }
|
|
181
|
-
```
|
|
182
|
-
|
|
183
|
-
Either override goes in `[tool.uv.sources]` only — the PyPI-style
|
|
184
|
-
`dependencies` entry above stays as-is, so removing the override is the
|
|
185
|
-
only change needed once the SDK actually ships to PyPI.
|
|
162
|
+
`uv sync` in a freshly-copied plugin repo resolves this pin normally; no
|
|
163
|
+
`[tool.uv.sources]` override is needed. If you are developing this plugin
|
|
164
|
+
*inside* a `biffo-template` checkout (e.g. one you plan to upstream into
|
|
165
|
+
`services/`) and want to iterate against an unreleased SDK change before it
|
|
166
|
+
ships, a local override still works:
|
|
167
|
+
|
|
168
|
+
```toml
|
|
169
|
+
[tool.uv.sources]
|
|
170
|
+
biffo-plugin-sdk = { path = "../../packages/python-sdk", editable = true }
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Keep it local (uncommitted, or removed before committing) — the PyPI-style
|
|
174
|
+
`dependencies` entry above is what every scaffolded plugin repo ships with.
|
|
186
175
|
|
|
187
176
|
## Manifest validation: why CI doesn't hard-gate on `registry-schema.json`
|
|
188
177
|
|
|
@@ -4,22 +4,14 @@ version = "0.1.0"
|
|
|
4
4
|
description = "Example Biffo plugin — replace this with your own plugin's name and description"
|
|
5
5
|
requires-python = ">=3.13"
|
|
6
6
|
dependencies = [
|
|
7
|
-
# biffo-plugin-sdk has a real release path
|
|
8
|
-
# .github/workflows/publish-sdk.yml:
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
# `
|
|
14
|
-
#
|
|
15
|
-
# as before this comment was written, so nothing regressed here; what
|
|
16
|
-
# changed is that the fix is now one tag push away rather than unbuilt.
|
|
17
|
-
# Deliberately NOT worked around with a git/path source in the committed
|
|
18
|
-
# file: baking one in would mean every plugin repo forked from this
|
|
19
|
-
# skeleton silently keeps building against a moving git ref long after
|
|
20
|
-
# the real release exists. Use a local `[tool.uv.sources]` override until
|
|
21
|
-
# then — see the README's "biffo-plugin-sdk dependency" section, which
|
|
22
|
-
# documents both options and says which to delete once 1.0.0 is live.
|
|
7
|
+
# biffo-plugin-sdk has a real release path via biffo-template's
|
|
8
|
+
# .github/workflows/publish-sdk.yml: it publishes to PyPI (via Trusted
|
|
9
|
+
# Publishing) when an `sdk-v*` tag is pushed. That first publish has
|
|
10
|
+
# already happened — this skeleton's own uv.lock resolves biffo-plugin-sdk
|
|
11
|
+
# 1.4.0 from https://pypi.org/simple (see uv.lock's own `biffo-plugin-sdk`
|
|
12
|
+
# entry) — so `uv sync` in a freshly-copied plugin repo resolves this pin
|
|
13
|
+
# normally, with no `[tool.uv.sources]` override needed (biffo-template#1769
|
|
14
|
+
# side finding).
|
|
23
15
|
"biffo-plugin-sdk>=1.0,<2.0",
|
|
24
16
|
"aws-lambda-powertools[tracer]>=3.4.0",
|
|
25
17
|
"httpx>=0.28.1",
|
package/dist/index.js
CHANGED
|
@@ -4993,6 +4993,15 @@ var DnsSchema = z5.object({
|
|
|
4993
4993
|
mode: z5.enum(["managed-route53", "external", "none"]).default("managed-route53"),
|
|
4994
4994
|
domain: z5.string().min(1).optional()
|
|
4995
4995
|
});
|
|
4996
|
+
var DesignTokensSchema = z5.object({
|
|
4997
|
+
package: z5.string().min(1).describe(
|
|
4998
|
+
`npm package providing this instance's real type scale, e.g. "@tabsii-com/ui". Added as an apps/frontend dependency of every new sibling, alongside (not instead of) @biffo/design-tokens -- biffo-scale-guard's own bin still ships from there.`
|
|
4999
|
+
),
|
|
5000
|
+
version: z5.string().min(1).default("*").describe("Version range to pin `package` at in a new sibling's apps/frontend/package.json"),
|
|
5001
|
+
path: z5.string().min(1).describe(
|
|
5002
|
+
`Path to the CSS file declaring the --text-*/--space-* scale, relative to the package root (e.g. "dist/tokens.css"). Used for both the new sibling's globals.css @import and biffo-scale-guard's --tokens argument.`
|
|
5003
|
+
)
|
|
5004
|
+
});
|
|
4996
5005
|
var BiffoConfigSchema = z5.object({
|
|
4997
5006
|
$schema: z5.string().optional(),
|
|
4998
5007
|
project: z5.object({
|
|
@@ -5013,7 +5022,8 @@ var BiffoConfigSchema = z5.object({
|
|
|
5013
5022
|
schema_path: z5.string().nullable().default(null),
|
|
5014
5023
|
migrations_path: z5.string().default("services/api/migrations")
|
|
5015
5024
|
}).default({}),
|
|
5016
|
-
modules: ModulesSchema.default({})
|
|
5025
|
+
modules: ModulesSchema.default({}),
|
|
5026
|
+
design_tokens: DesignTokensSchema.optional()
|
|
5017
5027
|
}).superRefine((config, ctx) => {
|
|
5018
5028
|
const dns = resolveDnsConfig(config);
|
|
5019
5029
|
if (dns.mode !== "none" && !dns.domain) {
|
|
@@ -6997,6 +7007,9 @@ async function runSiblingCreateCommand(name, options) {
|
|
|
6997
7007
|
`
|
|
6998
7008
|
);
|
|
6999
7009
|
}
|
|
7010
|
+
async function defaultRelockFrontendDeps(cwd) {
|
|
7011
|
+
await execa("pnpm", ["install", "--lockfile-only"], { cwd });
|
|
7012
|
+
}
|
|
7000
7013
|
async function runSiblingCreate(github, aws, coreAws, git, config, session, options) {
|
|
7001
7014
|
const totalSteps = 9;
|
|
7002
7015
|
const { org, repo } = githubRepo(config);
|
|
@@ -7059,7 +7072,8 @@ async function runSiblingCreate(github, aws, coreAws, git, config, session, opti
|
|
|
7059
7072
|
cloneUrl,
|
|
7060
7073
|
config,
|
|
7061
7074
|
options.coreConfig,
|
|
7062
|
-
options.githubToken
|
|
7075
|
+
options.githubToken,
|
|
7076
|
+
options.relockFrontendDeps ?? defaultRelockFrontendDeps
|
|
7063
7077
|
);
|
|
7064
7078
|
}
|
|
7065
7079
|
markSiblingStepComplete(session, "push_skeleton");
|
|
@@ -7219,7 +7233,7 @@ async function resolveCoreIdentity(coreAws, coreConfig, environments) {
|
|
|
7219
7233
|
}
|
|
7220
7234
|
return coreIdentity;
|
|
7221
7235
|
}
|
|
7222
|
-
async function pushSkeleton(git, skeletonRoot, cloneUrl, config, coreConfig, githubToken) {
|
|
7236
|
+
async function pushSkeleton(git, skeletonRoot, cloneUrl, config, coreConfig, githubToken, relockFrontendDeps) {
|
|
7223
7237
|
const workDir = mkdtempSync4(join24(tmpdir4(), `biffo-sibling-${config.project.name}-`));
|
|
7224
7238
|
try {
|
|
7225
7239
|
writeSiblingTemplate(skeletonRoot, workDir, config, {
|
|
@@ -7228,8 +7242,12 @@ async function pushSkeleton(git, skeletonRoot, cloneUrl, config, coreConfig, git
|
|
|
7228
7242
|
// The core template's version at scaffold time (issue #567) — visibility
|
|
7229
7243
|
// only, mirroring how `biffo init` stamps `biffo.core.json`. See the
|
|
7230
7244
|
// `template_version` field doc on `SiblingMarker` (lib/sibling-teardown.ts).
|
|
7231
|
-
templateVersion: getLatestCoreVersion()
|
|
7245
|
+
templateVersion: getLatestCoreVersion(),
|
|
7246
|
+
designTokens: coreConfig.design_tokens
|
|
7232
7247
|
});
|
|
7248
|
+
if (coreConfig.design_tokens) {
|
|
7249
|
+
await relockFrontendDeps(join24(workDir, "apps", "frontend"));
|
|
7250
|
+
}
|
|
7233
7251
|
await git.init(workDir, "dev");
|
|
7234
7252
|
await git.addRemote(workDir, "origin", cloneUrl);
|
|
7235
7253
|
await git.add(workDir, ["."]);
|
|
@@ -7282,6 +7300,53 @@ function writeSiblingTemplate(templateRoot, targetDir, config, context) {
|
|
|
7282
7300
|
} catch (err) {
|
|
7283
7301
|
if (err.code !== "ENOENT") throw err;
|
|
7284
7302
|
}
|
|
7303
|
+
if (context.designTokens) {
|
|
7304
|
+
rewriteDesignTokens(targetDir, context.designTokens);
|
|
7305
|
+
}
|
|
7306
|
+
}
|
|
7307
|
+
function rewriteDesignTokens(targetDir, tokens) {
|
|
7308
|
+
const importSpecifier = `${tokens.package}/${tokens.path}`;
|
|
7309
|
+
const packageJsonPath = join24(targetDir, "apps", "frontend", "package.json");
|
|
7310
|
+
try {
|
|
7311
|
+
const pkg = JSON.parse(readFileSync17(packageJsonPath, "utf8"));
|
|
7312
|
+
pkg.dependencies = { ...pkg.dependencies, [tokens.package]: tokens.version };
|
|
7313
|
+
writeFileSync7(packageJsonPath, JSON.stringify(pkg, null, 2) + "\n");
|
|
7314
|
+
} catch (err) {
|
|
7315
|
+
if (err.code !== "ENOENT") throw err;
|
|
7316
|
+
}
|
|
7317
|
+
const globalsCssPath = join24(targetDir, "apps", "frontend", "src", "app", "globals.css");
|
|
7318
|
+
try {
|
|
7319
|
+
const css = readFileSync17(globalsCssPath, "utf8").replace(
|
|
7320
|
+
/^@import '@biffo\/design-tokens\/tokens\.css';$/m,
|
|
7321
|
+
`@import '${importSpecifier}';`
|
|
7322
|
+
);
|
|
7323
|
+
writeFileSync7(globalsCssPath, css);
|
|
7324
|
+
} catch (err) {
|
|
7325
|
+
if (err.code !== "ENOENT") throw err;
|
|
7326
|
+
}
|
|
7327
|
+
const ciYmlPath = join24(targetDir, ".github", "workflows", "ci.yml");
|
|
7328
|
+
try {
|
|
7329
|
+
let yml = readFileSync17(ciYmlPath, "utf8");
|
|
7330
|
+
yml = yml.replace(
|
|
7331
|
+
/^(\s*run: pnpm exec biffo-scale-guard)$/m,
|
|
7332
|
+
`$1 --tokens node_modules/${importSpecifier}`
|
|
7333
|
+
);
|
|
7334
|
+
yml = yml.replace(
|
|
7335
|
+
" timeout-minutes: 20\n defaults:\n run:\n working-directory: apps/frontend\n steps:",
|
|
7336
|
+
" timeout-minutes: 20\n permissions:\n contents: read\n packages: read\n defaults:\n run:\n working-directory: apps/frontend\n steps:"
|
|
7337
|
+
);
|
|
7338
|
+
yml = yml.replace(
|
|
7339
|
+
" continue-on-error: true\n defaults:\n run:\n working-directory: apps/frontend\n steps:",
|
|
7340
|
+
" continue-on-error: true\n permissions:\n contents: read\n packages: read\n defaults:\n run:\n working-directory: apps/frontend\n steps:"
|
|
7341
|
+
);
|
|
7342
|
+
yml = yml.replace(
|
|
7343
|
+
/( {6}- run: pnpm install --frozen-lockfile)\n(?! {8}env:)/g,
|
|
7344
|
+
"$1\n env:\n NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n"
|
|
7345
|
+
);
|
|
7346
|
+
writeFileSync7(ciYmlPath, yml);
|
|
7347
|
+
} catch (err) {
|
|
7348
|
+
if (err.code !== "ENOENT") throw err;
|
|
7349
|
+
}
|
|
7285
7350
|
}
|
|
7286
7351
|
async function configureSiblingGithub(github, config, coreConfig, session, coreIdentity) {
|
|
7287
7352
|
const { org, repo } = githubRepo(config);
|
|
@@ -8273,7 +8338,8 @@ import {
|
|
|
8273
8338
|
import { dirname as dirname7, join as join26 } from "path";
|
|
8274
8339
|
var STANDALONE_ONLY_ENTRIES = {
|
|
8275
8340
|
".github": "standalone-repo CI/release workflows \u2014 the host monorepo already runs lint/type/test/security over services/",
|
|
8276
|
-
"registry-schema.json": "the plugin-registry publishing schema, used when submitting a *published* plugin to the registry repo, not by an in-tree plugin"
|
|
8341
|
+
"registry-schema.json": "the plugin-registry publishing schema, used when submitting a *published* plugin to the registry repo, not by an in-tree plugin",
|
|
8342
|
+
"uv.lock": "a standalone repo's own lockfile, substituted like any other text file (issue #1769) \u2014 a nested lock inside a monorepo's services/ would be wrong there, since the host resolves its own dependency tree"
|
|
8277
8343
|
};
|
|
8278
8344
|
var NEVER_COPY = /* @__PURE__ */ new Set([
|
|
8279
8345
|
".git",
|
|
@@ -8284,7 +8350,6 @@ var NEVER_COPY = /* @__PURE__ */ new Set([
|
|
|
8284
8350
|
".pytest_cache",
|
|
8285
8351
|
".mypy_cache",
|
|
8286
8352
|
"dist",
|
|
8287
|
-
"uv.lock",
|
|
8288
8353
|
".DS_Store"
|
|
8289
8354
|
]);
|
|
8290
8355
|
var PLUGIN_NAME_PATTERN = /^[a-z][a-z0-9-]*$/;
|
|
@@ -8537,6 +8602,11 @@ async function runStandaloneCreate(names, options, deps) {
|
|
|
8537
8602
|
`
|
|
8538
8603
|
);
|
|
8539
8604
|
if (options.commit) {
|
|
8605
|
+
if (!existsSync27(join27(destDir, "uv.lock"))) {
|
|
8606
|
+
throw new Error(
|
|
8607
|
+
`Scaffolded plugin at ${destDir} has no uv.lock. The standalone layout must carry a substituted uv.lock (see plugin-scaffold.ts STANDALONE_ONLY_ENTRIES) so the first commit's CI run can satisfy 'uv sync --locked'. Refusing to commit a repo that would ship red on its very first push (issue #1769) \u2014 run 'uv lock' in ${destDir} first.`
|
|
8608
|
+
);
|
|
8609
|
+
}
|
|
8540
8610
|
await deps.git.init(destDir);
|
|
8541
8611
|
await deps.git.add(destDir, ["."]);
|
|
8542
8612
|
await deps.git.commit(destDir, `feat: scaffold ${names.slug} plugin`);
|