@capybara-hq/plugin-tools 0.1.0-rc.5 → 0.1.0-rc.7
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/check/deps.d.ts
CHANGED
|
@@ -5,7 +5,9 @@ export type { Finding };
|
|
|
5
5
|
* - pluginDirs: each plugin directory (source imports and package.json); a violation is
|
|
6
6
|
* plugin-imports-kernel (a path leaving the plugin directory: plugin-imports-outside);
|
|
7
7
|
* - sdkDirs: the packages/plugin-sdk directory; any @capybara-hq/* package or path leaving the
|
|
8
|
-
* package directory is sdk-imports-internal
|
|
8
|
+
* package directory is sdk-imports-internal;
|
|
9
|
+
* - deviceDirs: the packages/device directory (source, tests and package.json); any @capybara-hq/*
|
|
10
|
+
* package other than plugin-sdk or path leaving the package directory is device-imports-internal.
|
|
9
11
|
*
|
|
10
12
|
* Covers: import / export from / export * / import type / dynamic import("literal or concatenated
|
|
11
13
|
* literals") / require("…") / import x = require() / import("x") types; package.json dependencies /
|
|
@@ -20,4 +22,4 @@ export type { Finding };
|
|
|
20
22
|
* `module.require` or `createRequire(...)`; `import.meta.resolve`; paths built at run time to read
|
|
21
23
|
* files; nested package.json files and TS `paths` mappings.
|
|
22
24
|
*/
|
|
23
|
-
export declare function checkDeps(pluginDirs: string[], sdkDirs?: string[]): Finding[];
|
|
25
|
+
export declare function checkDeps(pluginDirs: string[], sdkDirs?: string[], deviceDirs?: string[]): Finding[];
|
package/dist/check/deps.js
CHANGED
|
@@ -33,6 +33,13 @@ const SDK_RULES = {
|
|
|
33
33
|
outsideMessage: (what) => `packages/plugin-sdk must not reference files outside its package directory (${what})`,
|
|
34
34
|
allowed: () => false,
|
|
35
35
|
};
|
|
36
|
+
const DEVICE_RULES = {
|
|
37
|
+
pkgRule: "device-imports-internal",
|
|
38
|
+
outsideRule: "device-imports-internal",
|
|
39
|
+
pkgMessage: (what) => `packages/device runs on a person's machine and may depend only on ${SDK} and third-party npm packages, not on ${what}; the kernel is reached over HTTP and WebSocket only`,
|
|
40
|
+
outsideMessage: (what) => `packages/device must not reference files outside its package directory (${what})`,
|
|
41
|
+
allowed: (pkg) => pkg === SDK,
|
|
42
|
+
};
|
|
36
43
|
/** The violation a reference string (package name / relative path / file: URL / protocol dependency value) makes, if any. */
|
|
37
44
|
function judge(value, baseDir, rootDir, rules, where) {
|
|
38
45
|
const pkgs = [...value.matchAll(SCOPED_RE)].map((m) => `${SCOPE}${m[1]}`);
|
|
@@ -180,7 +187,9 @@ function sourceFindings(dir, rules, srcDir) {
|
|
|
180
187
|
* - pluginDirs: each plugin directory (source imports and package.json); a violation is
|
|
181
188
|
* plugin-imports-kernel (a path leaving the plugin directory: plugin-imports-outside);
|
|
182
189
|
* - sdkDirs: the packages/plugin-sdk directory; any @capybara-hq/* package or path leaving the
|
|
183
|
-
* package directory is sdk-imports-internal
|
|
190
|
+
* package directory is sdk-imports-internal;
|
|
191
|
+
* - deviceDirs: the packages/device directory (source, tests and package.json); any @capybara-hq/*
|
|
192
|
+
* package other than plugin-sdk or path leaving the package directory is device-imports-internal.
|
|
184
193
|
*
|
|
185
194
|
* Covers: import / export from / export * / import type / dynamic import("literal or concatenated
|
|
186
195
|
* literals") / require("…") / import x = require() / import("x") types; package.json dependencies /
|
|
@@ -195,7 +204,7 @@ function sourceFindings(dir, rules, srcDir) {
|
|
|
195
204
|
* `module.require` or `createRequire(...)`; `import.meta.resolve`; paths built at run time to read
|
|
196
205
|
* files; nested package.json files and TS `paths` mappings.
|
|
197
206
|
*/
|
|
198
|
-
export function checkDeps(pluginDirs, sdkDirs = []) {
|
|
207
|
+
export function checkDeps(pluginDirs, sdkDirs = [], deviceDirs = []) {
|
|
199
208
|
const findings = [];
|
|
200
209
|
for (const dir of pluginDirs) {
|
|
201
210
|
findings.push(...packageFindings(dir, PLUGIN_RULES), ...sourceFindings(dir, PLUGIN_RULES, dir));
|
|
@@ -203,5 +212,8 @@ export function checkDeps(pluginDirs, sdkDirs = []) {
|
|
|
203
212
|
for (const dir of sdkDirs) {
|
|
204
213
|
findings.push(...packageFindings(dir, SDK_RULES), ...sourceFindings(dir, SDK_RULES, join(dir, "src")));
|
|
205
214
|
}
|
|
215
|
+
for (const dir of deviceDirs) {
|
|
216
|
+
findings.push(...packageFindings(dir, DEVICE_RULES), ...sourceFindings(dir, DEVICE_RULES, dir));
|
|
217
|
+
}
|
|
206
218
|
return findings;
|
|
207
219
|
}
|
|
@@ -22,7 +22,9 @@ export interface ToolRegistration {
|
|
|
22
22
|
* - perm-hooks: the mount point of ctx.hooks.on(mount, …) is not in permissions.hooks (the mount
|
|
23
23
|
* point must be a string literal or a same-file const, like the names below), or the options are
|
|
24
24
|
* `{ mode: "policy" }` and the mount point is not in permissions.policyHooks;
|
|
25
|
-
* - perm-
|
|
25
|
+
* - perm-models: ctx.models is used but permissions.models is not declared (the purposes it may use
|
|
26
|
+
* are checked at run time);
|
|
27
|
+
* - perm-reserved: platform access that cannot be confirmed (a destructured ctx, a computed member).
|
|
26
28
|
* 路由路径、工具名、能力 ref、界面 id 须是字符串字面量或本文件的 const;动态的写法报「无法静态确认」,
|
|
27
29
|
* 豁免:`// capybara:allow-dynamic-permission <原因>`(行尾或紧邻上一行,原因必填)。
|
|
28
30
|
* ctx 会跟踪本地别名,以及按位置传给同文件函数的参数。
|
|
@@ -129,7 +129,11 @@ function readManifest(obj, decls) {
|
|
|
129
129
|
m.secrets = !!secrets && resolve(secrets.value, decls).value === true;
|
|
130
130
|
const storage = prop(pe, "storage");
|
|
131
131
|
m.storage = !!storage && resolve(storage.value, decls).value === true;
|
|
132
|
-
|
|
132
|
+
// an empty list declares nothing (ctx.models is gated on at least one purpose)
|
|
133
|
+
const models = prop(pe, "models");
|
|
134
|
+
const me = models ? resolve(models.value, decls) : undefined;
|
|
135
|
+
m.models =
|
|
136
|
+
me !== undefined && !(me.type === "ArrayExpression" && me.elements.length === 0);
|
|
133
137
|
for (const t of strings(prop(pe, "tools")?.value, decls))
|
|
134
138
|
m.tools.add(t);
|
|
135
139
|
for (const h of strings(prop(pe, "hooks")?.value, decls))
|
|
@@ -312,7 +316,9 @@ function scanSetup(f, m, decls, onTool, onCall) {
|
|
|
312
316
|
}
|
|
313
317
|
}
|
|
314
318
|
else if (name === "models") {
|
|
315
|
-
|
|
319
|
+
if (!m.models) {
|
|
320
|
+
add(n, "perm-models", "ctx.models is used but not declared; declare its purposes in permissions.models in the extension manifest");
|
|
321
|
+
}
|
|
316
322
|
}
|
|
317
323
|
else if (name === "http" ||
|
|
318
324
|
name === "tools" ||
|
|
@@ -376,7 +382,9 @@ function scanFile(f, onTool, onCall) {
|
|
|
376
382
|
* - perm-hooks: the mount point of ctx.hooks.on(mount, …) is not in permissions.hooks (the mount
|
|
377
383
|
* point must be a string literal or a same-file const, like the names below), or the options are
|
|
378
384
|
* `{ mode: "policy" }` and the mount point is not in permissions.policyHooks;
|
|
379
|
-
* - perm-
|
|
385
|
+
* - perm-models: ctx.models is used but permissions.models is not declared (the purposes it may use
|
|
386
|
+
* are checked at run time);
|
|
387
|
+
* - perm-reserved: platform access that cannot be confirmed (a destructured ctx, a computed member).
|
|
380
388
|
* 路由路径、工具名、能力 ref、界面 id 须是字符串字面量或本文件的 const;动态的写法报「无法静态确认」,
|
|
381
389
|
* 豁免:`// capybara:allow-dynamic-permission <原因>`(行尾或紧邻上一行,原因必填)。
|
|
382
390
|
* ctx 会跟踪本地别名,以及按位置传给同文件函数的参数。
|
package/dist/check/run.d.ts
CHANGED
|
@@ -14,6 +14,8 @@ export interface PluginCheckScope {
|
|
|
14
14
|
plugins: string[];
|
|
15
15
|
/** Package directories held to the SDK's boundary (core: `packages/plugin-sdk`). */
|
|
16
16
|
sdkDirs?: string[];
|
|
17
|
+
/** Package directories that may depend on `@capybara-hq/plugin-sdk` only (core: `packages/device`). */
|
|
18
|
+
deviceDirs?: string[];
|
|
17
19
|
/** More directories the tool design rules scan (core: the kernel's builtin tools). */
|
|
18
20
|
toolDesignDirs?: string[];
|
|
19
21
|
/** More migration directories (core: the kernel's migrations). */
|
package/dist/check/run.js
CHANGED
|
@@ -25,7 +25,10 @@ export function pluginChecks(scope) {
|
|
|
25
25
|
...plugins.map((p) => join(p, "migrations")),
|
|
26
26
|
]),
|
|
27
27
|
},
|
|
28
|
-
{
|
|
28
|
+
{
|
|
29
|
+
name: "Dependency boundary",
|
|
30
|
+
run: () => checkDeps(plugins, scope.sdkDirs ?? [], scope.deviceDirs ?? []),
|
|
31
|
+
},
|
|
29
32
|
{ name: "Extension state", run: () => checkPluginState(plugins) },
|
|
30
33
|
{ name: "Extension permissions", run: () => checkPluginPermissions(plugins) },
|
|
31
34
|
{ name: "Plugin pack", run: () => checkPluginPack(plugins) },
|
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.7",
|
|
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/
|
|
55
|
-
"@capybara-hq/
|
|
54
|
+
"@capybara-hq/plugin-sdk": "^0.1.0-rc.6",
|
|
55
|
+
"@capybara-hq/kernel": "^0.1.0-rc.9"
|
|
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.9"
|
|
60
60
|
},
|
|
61
61
|
"scripts": {
|
|
62
62
|
"build": "tsc -b"
|