@capybara-hq/plugin-tools 0.1.0-rc.0 → 0.1.0-rc.2
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/README.md +9 -9
- package/bin/capybara-plugin.mjs +1 -1
- package/dist/cli.js +0 -2
- package/dist/pack/cli.d.ts +3 -10
- package/dist/pack/cli.js +3 -40
- package/dist/pack/index.d.ts +0 -1
- package/dist/pack/index.js +0 -1
- package/package.json +3 -3
- package/dist/pack/bootstrap.d.ts +0 -25
- package/dist/pack/bootstrap.js +0 -70
package/README.md
CHANGED
|
@@ -14,8 +14,6 @@ npm install --save-dev @capybara-hq/plugin-tools
|
|
|
14
14
|
|
|
15
15
|
```bash
|
|
16
16
|
capybara-plugin pack [<dir>...] [--all <root>] [--out <dir>]
|
|
17
|
-
capybara-plugin pack --bootstrap <manifest> [--root <dir>] [--out <dir>] [--registry <url>]
|
|
18
|
-
[--npm-token <token>]
|
|
19
17
|
capybara-plugin check [--root <dir>] [--plugins <glob>] [--base <ref>]
|
|
20
18
|
capybara-plugin sync-versions [--root <dir>] [--plugins <glob>]
|
|
21
19
|
capybara-plugin marketplace --write|--check [--base <rev>] [--root <dir>] [--file <path>]
|
|
@@ -30,12 +28,8 @@ capybara-plugin release [--dry-run] [--provenance] [--out <dir>] [--auto] [--roo
|
|
|
30
28
|
manifest written into `plugin.json`, LICENSE / NOTICE and the bundled dependencies' notices
|
|
31
29
|
included. A plugin with an extension gets `"main"` and `"exports": { ".": "./dist/index.mjs" }`,
|
|
32
30
|
so once installed it resolves by package name (a test loads `@capybara-hq/plugin-model-fake`
|
|
33
|
-
from npm). `--all <root>` packs every plugin of a repository
|
|
34
|
-
a
|
|
35
|
-
`--registry`, default `CAPYBARA_PACKAGES__NPM_REGISTRY` or the public registry, with
|
|
36
|
-
`--npm-token` / `CAPYBARA_PACKAGES__NPM_TOKEN` sent to the registry origin only, tarballs capped
|
|
37
|
-
at 50 MiB) and checks them against their pinned sha512 and their `package.json` name and version.
|
|
38
|
-
Output: `artifacts/plugins`.
|
|
31
|
+
from npm). `--all <root>` packs every plugin of a repository. Output: `artifacts/plugins`. (The
|
|
32
|
+
bootstrap plugins a kernel pins are no longer packed here: a starting kernel downloads them.)
|
|
39
33
|
- **check**: every plugin check, on the plugins under `<root>/plugins/*` (or `--plugins <glob>`, or
|
|
40
34
|
the root itself when it is a plugin): the dependency boundary (a plugin depends only on
|
|
41
35
|
`@capybara-hq/plugin-sdk` and third-party packages), extension state under multiple replicas (no
|
|
@@ -93,9 +87,15 @@ export default defineConfig({
|
|
|
93
87
|
});
|
|
94
88
|
```
|
|
95
89
|
|
|
90
|
+
Dual-replica tests (`createDualReplicaHarness`) need nothing more: each replica is a child
|
|
91
|
+
process outside vitest, and `@capybara-hq/testing` runs it under its own tsx when an extension
|
|
92
|
+
entry is a TypeScript file (the plugin under test by path, `fakeExtensionEntry(...)`). Do not set
|
|
93
|
+
`NODE_OPTIONS: "--import tsx"` in the vitest config: it reaches every worker and child process
|
|
94
|
+
and hides packaging bugs.
|
|
95
|
+
|
|
96
96
|
## Library
|
|
97
97
|
|
|
98
|
-
The same code as functions: `packPlugin`, `
|
|
98
|
+
The same code as functions: `packPlugin`, `downloadPinnedNpmPackage`, `pluginChecks` / `runChecks` and each
|
|
99
99
|
check (`checkDeps`, `checkPluginState`, `checkPluginPermissions`, `checkPluginPack`,
|
|
100
100
|
`checkToolDesign`, `checkMigrations`, `checkAppliedMigrations`, `checkPluginTestImports`,
|
|
101
101
|
`checkPluginReleaseMetadata`), `syncPluginVersions` (after `changeset version`),
|
package/bin/capybara-plugin.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
// The `capybara-plugin` bin: runs the compiled CLI (dist/cli.js, built by `tsc -b`). In this
|
|
3
|
-
// repository, the root scripts (pnpm pack-plugin, pack-plugins,
|
|
3
|
+
// repository, the root scripts (pnpm pack-plugin, pack-plugins, release) run the
|
|
4
4
|
// TypeScript sources through tsx instead.
|
|
5
5
|
import { existsSync } from "node:fs";
|
|
6
6
|
|
package/dist/cli.js
CHANGED
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
* `capybara-plugin`: pack, check, sync the versions of and release Capybara plugins.
|
|
3
3
|
*
|
|
4
4
|
* capybara-plugin pack [<dir>...] [--all <root>] [--out <dir>]
|
|
5
|
-
* capybara-plugin pack --bootstrap <manifest> [--root <dir>] [--out <dir>] [--registry <url>]
|
|
6
|
-
* [--npm-token <token>]
|
|
7
5
|
* capybara-plugin check [--root <dir>] [--plugins <glob>] [--base <ref>]
|
|
8
6
|
* capybara-plugin sync-versions [--root <dir>] [--plugins <glob>]
|
|
9
7
|
* capybara-plugin marketplace --write|--check [--base <rev>] [--root <dir>] [--file <path>]
|
package/dist/pack/cli.d.ts
CHANGED
|
@@ -1,19 +1,12 @@
|
|
|
1
|
-
export declare const PACK_USAGE
|
|
1
|
+
export declare const PACK_USAGE = "capybara-plugin pack [<dir>...] [--all <root>] [--out <dir>]";
|
|
2
2
|
/**
|
|
3
3
|
* `capybara-plugin pack`: packs plugin directories into plugin tgz files.
|
|
4
4
|
*
|
|
5
5
|
* - `<dir>...`: the plugin directories to pack;
|
|
6
6
|
* - `--all <root>`: also every plugin of the repository at `<root>` (`<root>/plugins/*`, or `<root>`
|
|
7
7
|
* itself when it is a plugin);
|
|
8
|
-
* - `--
|
|
9
|
-
*
|
|
10
|
-
* relative to `--root`, default the current directory; npm entries are downloaded from
|
|
11
|
-
* `--registry`, default `CAPYBARA_PACKAGES__NPM_REGISTRY` (the kernel's `packages.npmRegistry`)
|
|
12
|
-
* or else the public npm registry, and must match their pinned sha512; `--npm-token`, default
|
|
13
|
-
* `CAPYBARA_PACKAGES__NPM_TOKEN` (the kernel's `packages.npmToken`), is sent as a Bearer token to
|
|
14
|
-
* the registry origin only);
|
|
15
|
-
* - `--out <dir>`: output directory, default `artifacts/plugins` (`artifacts/bootstrap` with
|
|
16
|
-
* `--bootstrap`) under the current directory. The last `--out` wins.
|
|
8
|
+
* - `--out <dir>`: output directory, default `artifacts/plugins` under the current directory. The
|
|
9
|
+
* last `--out` wins.
|
|
17
10
|
*
|
|
18
11
|
* Relative paths resolve against `cwd` (the current directory). Returns the exit code.
|
|
19
12
|
*/
|
package/dist/pack/cli.js
CHANGED
|
@@ -1,27 +1,16 @@
|
|
|
1
1
|
import { relative, resolve } from "node:path";
|
|
2
2
|
import { parseArgs } from "node:util";
|
|
3
3
|
import { discoverPlugins } from "../discover.js";
|
|
4
|
-
import { packBootstrap } from "./bootstrap.js";
|
|
5
|
-
import { DEFAULT_NPM_REGISTRY } from "./npm.js";
|
|
6
4
|
import { packPlugin } from "./pack.js";
|
|
7
|
-
export const PACK_USAGE = "capybara-plugin pack [<dir>...] [--all <root>] [--out <dir>]
|
|
8
|
-
" capybara-plugin pack --bootstrap <manifest> [--root <dir>] [--out <dir>] [--registry <url>]\n" +
|
|
9
|
-
" [--npm-token <token>]";
|
|
5
|
+
export const PACK_USAGE = "capybara-plugin pack [<dir>...] [--all <root>] [--out <dir>]";
|
|
10
6
|
/**
|
|
11
7
|
* `capybara-plugin pack`: packs plugin directories into plugin tgz files.
|
|
12
8
|
*
|
|
13
9
|
* - `<dir>...`: the plugin directories to pack;
|
|
14
10
|
* - `--all <root>`: also every plugin of the repository at `<root>` (`<root>/plugins/*`, or `<root>`
|
|
15
11
|
* itself when it is a plugin);
|
|
16
|
-
* - `--
|
|
17
|
-
*
|
|
18
|
-
* relative to `--root`, default the current directory; npm entries are downloaded from
|
|
19
|
-
* `--registry`, default `CAPYBARA_PACKAGES__NPM_REGISTRY` (the kernel's `packages.npmRegistry`)
|
|
20
|
-
* or else the public npm registry, and must match their pinned sha512; `--npm-token`, default
|
|
21
|
-
* `CAPYBARA_PACKAGES__NPM_TOKEN` (the kernel's `packages.npmToken`), is sent as a Bearer token to
|
|
22
|
-
* the registry origin only);
|
|
23
|
-
* - `--out <dir>`: output directory, default `artifacts/plugins` (`artifacts/bootstrap` with
|
|
24
|
-
* `--bootstrap`) under the current directory. The last `--out` wins.
|
|
12
|
+
* - `--out <dir>`: output directory, default `artifacts/plugins` under the current directory. The
|
|
13
|
+
* last `--out` wins.
|
|
25
14
|
*
|
|
26
15
|
* Relative paths resolve against `cwd` (the current directory). Returns the exit code.
|
|
27
16
|
*/
|
|
@@ -33,10 +22,6 @@ export async function packCommand(args, cwd) {
|
|
|
33
22
|
help: { type: "boolean", short: "h", default: false },
|
|
34
23
|
all: { type: "string" },
|
|
35
24
|
out: { type: "string" },
|
|
36
|
-
bootstrap: { type: "string" },
|
|
37
|
-
root: { type: "string" },
|
|
38
|
-
registry: { type: "string" },
|
|
39
|
-
"npm-token": { type: "string" },
|
|
40
25
|
},
|
|
41
26
|
});
|
|
42
27
|
if (values.help) {
|
|
@@ -48,28 +33,6 @@ export async function packCommand(args, cwd) {
|
|
|
48
33
|
const rel = relative(cwd, p);
|
|
49
34
|
return rel === "" ? "." : rel.startsWith("..") ? p : rel;
|
|
50
35
|
};
|
|
51
|
-
if (values.bootstrap !== undefined) {
|
|
52
|
-
if (values.all !== undefined || positionals.length > 0) {
|
|
53
|
-
return usage("--bootstrap takes no plugin directory");
|
|
54
|
-
}
|
|
55
|
-
try {
|
|
56
|
-
const root = values.root === undefined ? cwd : resolve(cwd, values.root);
|
|
57
|
-
const manifest = resolve(cwd, values.bootstrap);
|
|
58
|
-
const registry = values.registry ?? (process.env.CAPYBARA_PACKAGES__NPM_REGISTRY || DEFAULT_NPM_REGISTRY);
|
|
59
|
-
const token = values["npm-token"] ?? process.env.CAPYBARA_PACKAGES__NPM_TOKEN;
|
|
60
|
-
for (const p of await packBootstrap(manifest, root, outOf("artifacts/bootstrap"), {
|
|
61
|
-
registry,
|
|
62
|
-
...(token !== undefined && token !== "" && { token }),
|
|
63
|
-
})) {
|
|
64
|
-
console.log(`${shown(p.file)} ${p.integrity}`);
|
|
65
|
-
}
|
|
66
|
-
return 0;
|
|
67
|
-
}
|
|
68
|
-
catch (e) {
|
|
69
|
-
console.error(e instanceof Error ? e.message : String(e));
|
|
70
|
-
return 1;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
36
|
const plugins = positionals.map((d) => resolve(cwd, d));
|
|
74
37
|
if (values.all !== undefined) {
|
|
75
38
|
const root = resolve(cwd, values.all);
|
package/dist/pack/index.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
export { type BootstrapPack, packBootstrap } from "./bootstrap.js";
|
|
2
1
|
export { PACK_USAGE, packCommand } from "./cli.js";
|
|
3
2
|
export { assertNpmTarballLabel, DEFAULT_NPM_REGISTRY, downloadPinnedNpmPackage, fetchNpmTarball, NPM_TARBALL_MAX_BYTES, type NpmFetchOptions, NpmPackageError, type NpmPackageErrorKind, } from "./npm.js";
|
|
4
3
|
export { METADATA_FIELDS, NOTICES_FILE, type PackResult, packPlugin, STAGING_PREFIX, } from "./pack.js";
|
package/dist/pack/index.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
export { packBootstrap } from "./bootstrap.js";
|
|
2
1
|
export { PACK_USAGE, packCommand } from "./cli.js";
|
|
3
2
|
export { assertNpmTarballLabel, DEFAULT_NPM_REGISTRY, downloadPinnedNpmPackage, fetchNpmTarball, NPM_TARBALL_MAX_BYTES, NpmPackageError, } from "./npm.js";
|
|
4
3
|
export { METADATA_FIELDS, NOTICES_FILE, packPlugin, STAGING_PREFIX, } from "./pack.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@capybara-hq/plugin-tools",
|
|
3
|
-
"version": "0.1.0-rc.
|
|
3
|
+
"version": "0.1.0-rc.2",
|
|
4
4
|
"description": "Capybara plugin toolchain: the capybara-plugin CLI to pack, check and release Capybara plugins",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -51,12 +51,12 @@
|
|
|
51
51
|
"esbuild": "0.28.2",
|
|
52
52
|
"oxc-parser": "^0.154.0",
|
|
53
53
|
"tar-stream": "3.2.2",
|
|
54
|
-
"@capybara-hq/kernel": "^0.1.0-rc.
|
|
54
|
+
"@capybara-hq/kernel": "^0.1.0-rc.1",
|
|
55
55
|
"@capybara-hq/plugin-sdk": "^0.1.0-rc.0"
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
58
58
|
"zod": "^4.6.7",
|
|
59
|
-
"@capybara-hq/testing": "0.1.0-rc.
|
|
59
|
+
"@capybara-hq/testing": "0.1.0-rc.2"
|
|
60
60
|
},
|
|
61
61
|
"scripts": {
|
|
62
62
|
"build": "tsc -b"
|
package/dist/pack/bootstrap.d.ts
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { type NpmFetchOptions } from "./npm.js";
|
|
2
|
-
/** One package {@link packBootstrap} wrote. */
|
|
3
|
-
export interface BootstrapPack {
|
|
4
|
-
name: string;
|
|
5
|
-
version: string;
|
|
6
|
-
file: string;
|
|
7
|
-
integrity: string;
|
|
8
|
-
}
|
|
9
|
-
/**
|
|
10
|
-
* Produces the bootstrap directory the image bakes (package ecosystem spec §7): every entry of the
|
|
11
|
-
* bootstrap manifest (`packages/kernel/bootstrap.json`) as `<outDir>/<name>-<version>.tgz`. A
|
|
12
|
-
* `source: "workspace"` entry is packed from `<repoRoot>/<path>` with {@link packPlugin}
|
|
13
|
-
* (byte-reproducible) and must equal the entry: the plugin name, the version and the pinned sha512,
|
|
14
|
-
* otherwise this throws naming the plugin and writes nothing for it (the image build fails rather
|
|
15
|
-
* than baking a package `capybara bootstrap` would refuse). A `source: "npm"` entry is downloaded
|
|
16
|
-
* from `opts.registry` (default the public npm registry, the kernel's `packages.npmRegistry`
|
|
17
|
-
* default; `opts.token` goes to the registry origin only) and written only when its bytes match
|
|
18
|
-
* the pinned sha512 and its package.json names the entry's package and version; a tampered,
|
|
19
|
-
* mislabelled or oversized (`bootstrap.too_large`) tarball or an unpublished package or version
|
|
20
|
-
* throws naming the plugin. So npm entries need the network at
|
|
21
|
-
* build time only: init installs from the baked directory and never downloads.
|
|
22
|
-
*/
|
|
23
|
-
export declare function packBootstrap(manifestFile: string, repoRoot: string, outDir: string, opts?: {
|
|
24
|
-
registry?: string;
|
|
25
|
-
} & NpmFetchOptions): Promise<BootstrapPack[]>;
|
package/dist/pack/bootstrap.js
DELETED
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import { copyFile, mkdir, mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
|
|
2
|
-
import { tmpdir } from "node:os";
|
|
3
|
-
import { join } from "node:path";
|
|
4
|
-
import { bootstrapFileName, parseBootstrapManifest } from "@capybara-hq/plugin-sdk";
|
|
5
|
-
import { integrityOf } from "../integrity.js";
|
|
6
|
-
import { DEFAULT_NPM_REGISTRY, downloadPinnedNpmPackage } from "./npm.js";
|
|
7
|
-
import { packPlugin } from "./pack.js";
|
|
8
|
-
/**
|
|
9
|
-
* Produces the bootstrap directory the image bakes (package ecosystem spec §7): every entry of the
|
|
10
|
-
* bootstrap manifest (`packages/kernel/bootstrap.json`) as `<outDir>/<name>-<version>.tgz`. A
|
|
11
|
-
* `source: "workspace"` entry is packed from `<repoRoot>/<path>` with {@link packPlugin}
|
|
12
|
-
* (byte-reproducible) and must equal the entry: the plugin name, the version and the pinned sha512,
|
|
13
|
-
* otherwise this throws naming the plugin and writes nothing for it (the image build fails rather
|
|
14
|
-
* than baking a package `capybara bootstrap` would refuse). A `source: "npm"` entry is downloaded
|
|
15
|
-
* from `opts.registry` (default the public npm registry, the kernel's `packages.npmRegistry`
|
|
16
|
-
* default; `opts.token` goes to the registry origin only) and written only when its bytes match
|
|
17
|
-
* the pinned sha512 and its package.json names the entry's package and version; a tampered,
|
|
18
|
-
* mislabelled or oversized (`bootstrap.too_large`) tarball or an unpublished package or version
|
|
19
|
-
* throws naming the plugin. So npm entries need the network at
|
|
20
|
-
* build time only: init installs from the baked directory and never downloads.
|
|
21
|
-
*/
|
|
22
|
-
export async function packBootstrap(manifestFile, repoRoot, outDir, opts = {}) {
|
|
23
|
-
const parsed = parseBootstrapManifest(JSON.parse(await readFile(manifestFile, "utf8")));
|
|
24
|
-
if ("errors" in parsed) {
|
|
25
|
-
throw new Error(`invalid bootstrap manifest ${manifestFile}: ${parsed.errors.join("; ")}`);
|
|
26
|
-
}
|
|
27
|
-
await mkdir(outDir, { recursive: true });
|
|
28
|
-
const staging = await mkdtemp(join(tmpdir(), "pack-bootstrap-"));
|
|
29
|
-
const out = [];
|
|
30
|
-
try {
|
|
31
|
-
for (const e of parsed.plugins) {
|
|
32
|
-
if (e.source === "npm") {
|
|
33
|
-
let bytes;
|
|
34
|
-
try {
|
|
35
|
-
bytes = await downloadPinnedNpmPackage(e, opts.registry ?? DEFAULT_NPM_REGISTRY, {
|
|
36
|
-
...(opts.token !== undefined && { token: opts.token }),
|
|
37
|
-
...(opts.maxBytes !== undefined && { maxBytes: opts.maxBytes }),
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
catch (err) {
|
|
41
|
-
throw new Error(`${e.name}: ${err instanceof Error ? err.message : String(err)}`, {
|
|
42
|
-
cause: err,
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
const file = join(outDir, bootstrapFileName(e));
|
|
46
|
-
await writeFile(file, bytes);
|
|
47
|
-
out.push({ name: e.name, version: e.version, file, integrity: e.integrity });
|
|
48
|
-
continue;
|
|
49
|
-
}
|
|
50
|
-
const r = await packPlugin(join(repoRoot, e.path), staging);
|
|
51
|
-
const integrity = integrityOf(new Uint8Array(await readFile(r.file)));
|
|
52
|
-
const problems = [
|
|
53
|
-
r.manifest.name !== e.name && `${e.path} packs the plugin "${r.manifest.name}"`,
|
|
54
|
-
r.manifest.version !== e.version &&
|
|
55
|
-
`version is ${e.version} but ${e.path} packs ${r.manifest.version}`,
|
|
56
|
-
integrity !== e.integrity && `integrity is ${e.integrity} but ${e.path} packs ${integrity}`,
|
|
57
|
-
].filter((p) => typeof p === "string");
|
|
58
|
-
if (problems.length > 0) {
|
|
59
|
-
throw new Error(`${e.name}: ${problems.join("; ")}; the bootstrap manifest is stale (pnpm check:bootstrap --write)`);
|
|
60
|
-
}
|
|
61
|
-
const file = join(outDir, bootstrapFileName(e));
|
|
62
|
-
await copyFile(r.file, file);
|
|
63
|
-
out.push({ name: e.name, version: e.version, file, integrity });
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
finally {
|
|
67
|
-
await rm(staging, { recursive: true, force: true });
|
|
68
|
-
}
|
|
69
|
-
return out;
|
|
70
|
-
}
|