@capybara-hq/plugin-tools 0.1.0-rc.3 → 0.1.0-rc.5
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 +17 -10
- package/dist/check/applied-migrations.d.ts +23 -0
- package/dist/check/applied-migrations.js +86 -0
- package/dist/check/cli.d.ts +2 -1
- package/dist/check/cli.js +7 -3
- package/dist/check/config-forms.d.ts +13 -0
- package/dist/check/config-forms.js +71 -0
- package/dist/check/index.d.ts +3 -1
- package/dist/check/index.js +3 -1
- package/dist/check/migrations.d.ts +1 -1
- package/dist/check/migrations.js +30 -1
- package/dist/check/org-override.d.ts +10 -0
- package/dist/check/org-override.js +62 -0
- package/dist/check/plugin-permissions.d.ts +14 -0
- package/dist/check/plugin-permissions.js +28 -3
- package/dist/check/release-metadata.d.ts +5 -0
- package/dist/check/release-metadata.js +47 -0
- package/dist/check/report.d.ts +4 -3
- package/dist/check/report.js +13 -3
- package/dist/check/run.d.ts +1 -1
- package/dist/check/run.js +4 -0
- package/dist/check/source.d.ts +7 -0
- package/dist/check/source.js +2 -0
- package/dist/marketplace/cli.d.ts +9 -7
- package/dist/marketplace/cli.js +19 -10
- package/dist/marketplace/marketplace.d.ts +38 -24
- package/dist/marketplace/marketplace.js +206 -60
- package/dist/pack/config-schemas.d.ts +34 -0
- package/dist/pack/config-schemas.js +151 -0
- package/dist/pack/index.d.ts +2 -1
- package/dist/pack/index.js +2 -1
- package/dist/pack/pack.d.ts +7 -1
- package/dist/pack/pack.js +77 -35
- package/package.json +4 -4
package/dist/pack/pack.js
CHANGED
|
@@ -7,10 +7,11 @@ import { dirname, join, posix, relative, resolve } from "node:path";
|
|
|
7
7
|
import { pathToFileURL } from "node:url";
|
|
8
8
|
import { promisify } from "node:util";
|
|
9
9
|
import { gzip } from "node:zlib";
|
|
10
|
-
import { AGENT_TEMPLATE_LIMITS, checkEntryImports, defineExtension, HOST_PROVIDED_PACKAGES, PLUGIN_MANIFEST_FILE, parseAgentTemplate, parseConnectorTemplateFile, parsePluginManifest, SDK_VERSION, staticManifestOf, validatePluginPackageJsonFor, } from "@capybara-hq/plugin-sdk";
|
|
10
|
+
import { AGENT_TEMPLATE_LIMITS, checkEntryImports, defineExtension, HOST_PROVIDED_PACKAGES, PLUGIN_MANIFEST_FILE, PLUGIN_MANIFEST_LIMITS, parseAgentTemplate, parseConnectorTemplateFile, parsePluginManifest, SDK_VERSION, staticManifestOf, validatePluginPackageJsonFor, } from "@capybara-hq/plugin-sdk";
|
|
11
11
|
import { init as lexerInit, parse as lexerParse } from "es-module-lexer";
|
|
12
12
|
import { build } from "esbuild";
|
|
13
13
|
import { pack as tarPack } from "tar-stream";
|
|
14
|
+
import { extensionConfigSchemas, formatConfigSchemaProblem } from "./config-schemas.js";
|
|
14
15
|
/** The extension entry the packer writes (relative to the package root). */
|
|
15
16
|
const EXTENSION_ENTRY = "dist/index.mjs";
|
|
16
17
|
/**
|
|
@@ -363,6 +364,61 @@ async function contentFiles(dir, label, m) {
|
|
|
363
364
|
agents: agents.length,
|
|
364
365
|
};
|
|
365
366
|
}
|
|
367
|
+
/**
|
|
368
|
+
* Bundles `src/index.ts` into `<stage>/package/dist/index.mjs` (esbuild, single-file ESM), checks
|
|
369
|
+
* the bundle's imports, imports it and runs its default export through defineExtension. Returns the
|
|
370
|
+
* bundle, the defined manifest and the bundled inputs (for the notices).
|
|
371
|
+
*/
|
|
372
|
+
async function buildAndImport(dir, label, stage) {
|
|
373
|
+
await linkHostPackages(dir, stage);
|
|
374
|
+
const entryOut = join(stage, "package", EXTENSION_ENTRY);
|
|
375
|
+
const result = await build({
|
|
376
|
+
absWorkingDir: dir,
|
|
377
|
+
entryPoints: [join(dir, "src/index.ts")],
|
|
378
|
+
outfile: entryOut,
|
|
379
|
+
bundle: true,
|
|
380
|
+
platform: "node",
|
|
381
|
+
format: "esm",
|
|
382
|
+
target: "node24",
|
|
383
|
+
external: [...HOST_PROVIDED_PACKAGES],
|
|
384
|
+
plugins: [nodeBuiltins],
|
|
385
|
+
banner: { js: BANNER },
|
|
386
|
+
define: DEFINE,
|
|
387
|
+
charset: "utf8",
|
|
388
|
+
logLevel: "silent",
|
|
389
|
+
metafile: true,
|
|
390
|
+
// Notices of bundled dependencies go to THIRD-PARTY-NOTICES.txt (built from the metafile).
|
|
391
|
+
legalComments: "none",
|
|
392
|
+
});
|
|
393
|
+
if (result.errors.length > 0) {
|
|
394
|
+
throw new Error(`${label}: esbuild failed: ${result.errors.map((e) => e.text).join("; ")}`);
|
|
395
|
+
}
|
|
396
|
+
const code = await readFile(entryOut);
|
|
397
|
+
const issues = await importIssues(code.toString("utf8"));
|
|
398
|
+
if (issues.length > 0)
|
|
399
|
+
throw new Error(`${label}: ${issues.join("; ")}`);
|
|
400
|
+
const mod = await importBundle(entryOut);
|
|
401
|
+
if (typeof mod.default !== "object" || mod.default === null) {
|
|
402
|
+
throw new Error(`${label}: the bundle has no default export object`);
|
|
403
|
+
}
|
|
404
|
+
const m = defineExtension(mod.default);
|
|
405
|
+
return { code, m, inputs: Object.keys(result.metafile?.inputs ?? {}) };
|
|
406
|
+
}
|
|
407
|
+
/**
|
|
408
|
+
* The extension a plugin directory's `src/index.ts` defines, bundled and imported the way the
|
|
409
|
+
* packer does (in a `.capybara-pack-*` staging dir under the system temp dir, removed afterwards).
|
|
410
|
+
* For checks that need the module (config forms); throws what packing would throw.
|
|
411
|
+
*/
|
|
412
|
+
export async function importPluginExtension(pluginDir) {
|
|
413
|
+
const dir = resolve(pluginDir);
|
|
414
|
+
const stage = await realpath(await mkdtemp(join(tmpdir(), STAGING_PREFIX)));
|
|
415
|
+
try {
|
|
416
|
+
return (await buildAndImport(dir, dir, stage)).m;
|
|
417
|
+
}
|
|
418
|
+
finally {
|
|
419
|
+
await rm(stage, { recursive: true, force: true });
|
|
420
|
+
}
|
|
421
|
+
}
|
|
366
422
|
/**
|
|
367
423
|
* Bundles the extension `src/index.ts`:
|
|
368
424
|
* 1. esbuild bundles it into the single-file ESM `dist/index.mjs` (platform node, target node24),
|
|
@@ -371,6 +427,8 @@ async function contentFiles(dir, label, m) {
|
|
|
371
427
|
* 2. the bundle's imports are checked (allowlist, no non-literal dynamic import), the bundle is
|
|
372
428
|
* imported and its default export goes through defineExtension; `staticManifestOf` gives the
|
|
373
429
|
* static manifest, whose version must equal the package.json version;
|
|
430
|
+
* the config schemas become `extension.configSchemas` (`configJsonSchema`; refused when their
|
|
431
|
+
* hints have problems, {@link extensionConfigSchemas});
|
|
374
432
|
* 3. `migrations/` (when the manifest declares migrations, which must resolve to the plugin's
|
|
375
433
|
* `migrations/`), `ui/` (when present) and THIRD-PARTY-NOTICES.txt join the files.
|
|
376
434
|
*
|
|
@@ -379,41 +437,14 @@ async function contentFiles(dir, label, m) {
|
|
|
379
437
|
async function bundleExtension(dir, label, pkgVersion) {
|
|
380
438
|
const stage = await realpath(await mkdtemp(join(tmpdir(), STAGING_PREFIX)));
|
|
381
439
|
try {
|
|
382
|
-
await
|
|
383
|
-
const entryOut = join(stage, "package", EXTENSION_ENTRY);
|
|
384
|
-
const result = await build({
|
|
385
|
-
absWorkingDir: dir,
|
|
386
|
-
entryPoints: [join(dir, "src/index.ts")],
|
|
387
|
-
outfile: entryOut,
|
|
388
|
-
bundle: true,
|
|
389
|
-
platform: "node",
|
|
390
|
-
format: "esm",
|
|
391
|
-
target: "node24",
|
|
392
|
-
external: [...HOST_PROVIDED_PACKAGES],
|
|
393
|
-
plugins: [nodeBuiltins],
|
|
394
|
-
banner: { js: BANNER },
|
|
395
|
-
define: DEFINE,
|
|
396
|
-
charset: "utf8",
|
|
397
|
-
logLevel: "silent",
|
|
398
|
-
metafile: true,
|
|
399
|
-
// Notices of bundled dependencies go to THIRD-PARTY-NOTICES.txt (built from the metafile).
|
|
400
|
-
legalComments: "none",
|
|
401
|
-
});
|
|
402
|
-
if (result.errors.length > 0) {
|
|
403
|
-
throw new Error(`${label}: esbuild failed: ${result.errors.map((e) => e.text).join("; ")}`);
|
|
404
|
-
}
|
|
405
|
-
const code = await readFile(entryOut);
|
|
406
|
-
const issues = await importIssues(code.toString("utf8"));
|
|
407
|
-
if (issues.length > 0)
|
|
408
|
-
throw new Error(`${label}: ${issues.join("; ")}`);
|
|
409
|
-
const mod = await importBundle(entryOut);
|
|
410
|
-
if (typeof mod.default !== "object" || mod.default === null) {
|
|
411
|
-
throw new Error(`${label}: the bundle has no default export object`);
|
|
412
|
-
}
|
|
413
|
-
const m = defineExtension(mod.default);
|
|
440
|
+
const { code, m, inputs } = await buildAndImport(dir, label, stage);
|
|
414
441
|
if (m.version !== pkgVersion) {
|
|
415
442
|
throw new Error(`${label}: manifest version ${m.version} does not match package.json version ${String(pkgVersion)}`);
|
|
416
443
|
}
|
|
444
|
+
const config = extensionConfigSchemas(m.config);
|
|
445
|
+
if (config.problems.length > 0) {
|
|
446
|
+
throw new Error(`${label}: invalid config UI hints: ${config.problems.map(formatConfigSchemaProblem).join("; ")}`);
|
|
447
|
+
}
|
|
417
448
|
const files = new Map([[EXTENSION_ENTRY, code]]);
|
|
418
449
|
const extension = {
|
|
419
450
|
entry: `./${EXTENSION_ENTRY}`,
|
|
@@ -435,7 +466,10 @@ async function bundleExtension(dir, label, pkgVersion) {
|
|
|
435
466
|
}
|
|
436
467
|
extension.ui = "./ui";
|
|
437
468
|
}
|
|
438
|
-
|
|
469
|
+
if (config.schemas.deployment !== undefined || config.schemas.org !== undefined) {
|
|
470
|
+
extension.configSchemas = config.schemas;
|
|
471
|
+
}
|
|
472
|
+
const notices = await thirdPartyNotices(dir, inputs);
|
|
439
473
|
if (notices !== undefined)
|
|
440
474
|
files.set(NOTICES_FILE, Buffer.from(notices));
|
|
441
475
|
return { files, extension };
|
|
@@ -504,7 +538,15 @@ export async function packPlugin(pluginDir, outDir) {
|
|
|
504
538
|
if (pkgIssues.length > 0)
|
|
505
539
|
throw new Error(`${label}: ${pkgIssues.join("; ")}`);
|
|
506
540
|
files.set("package.json", Buffer.from(`${JSON.stringify(pkg, null, 2)}\n`));
|
|
507
|
-
|
|
541
|
+
// The packed text is pretty-printed while the config schema caps measure compact JSON: the text
|
|
542
|
+
// itself must stay under the reader's limit, or the kernel would refuse the package unread.
|
|
543
|
+
const manifestText = `${JSON.stringify(manifest, null, 2)}\n`;
|
|
544
|
+
if (manifestText.length > PLUGIN_MANIFEST_LIMITS.manifestChars) {
|
|
545
|
+
throw new Error(`${label}: packed ${PLUGIN_MANIFEST_FILE} is ${manifestText.length} characters, over the ` +
|
|
546
|
+
`${PLUGIN_MANIFEST_LIMITS.manifestChars} limit (PLUGIN_MANIFEST_LIMITS.manifestChars); ` +
|
|
547
|
+
"make the config schemas smaller");
|
|
548
|
+
}
|
|
549
|
+
files.set(PLUGIN_MANIFEST_FILE, Buffer.from(manifestText));
|
|
508
550
|
const tgz = await makeTgz(files);
|
|
509
551
|
await mkdir(outDir, { recursive: true });
|
|
510
552
|
const file = resolve(outDir, tgzName(String(srcPkg.name), String(srcPkg.version)));
|
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.5",
|
|
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.
|
|
55
|
-
"@capybara-hq/plugin-sdk": "^0.1.0-rc.
|
|
54
|
+
"@capybara-hq/kernel": "^0.1.0-rc.5",
|
|
55
|
+
"@capybara-hq/plugin-sdk": "^0.1.0-rc.3"
|
|
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.6"
|
|
60
60
|
},
|
|
61
61
|
"scripts": {
|
|
62
62
|
"build": "tsc -b"
|