@capybara-hq/plugin-sdk 0.1.0-rc.7 → 0.1.0-rc.8
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/agent-docs/plugin-format.md +6 -2
- package/dist/index.d.ts +5 -1
- package/dist/index.js +5 -1
- package/dist/plugin-manifest.d.ts +10 -3
- package/dist/plugin-manifest.js +24 -5
- package/dist/theme-assets.d.ts +39 -0
- package/dist/theme-assets.js +449 -0
- package/dist/theme-readability.d.ts +37 -0
- package/dist/theme-readability.js +145 -0
- package/dist/theme-tokens.generated.d.ts +275 -0
- package/dist/theme-tokens.generated.js +167 -0
- package/dist/theme.d.ts +152 -0
- package/dist/theme.js +392 -0
- package/package.json +2 -1
- package/schemas/plugin.v1.schema.json +19 -0
- package/schemas/theme.v1.schema.json +225 -0
|
@@ -10,11 +10,12 @@ A plugin is a directory, packed into a `.tgz` with `capybara-plugin pack` (the p
|
|
|
10
10
|
skills/<name>/SKILL.md skills (scanned unless plugin.json lists them)
|
|
11
11
|
connectors/<id>.json connector templates (scanned unless listed)
|
|
12
12
|
agents/<name>.md agent templates (scanned unless listed)
|
|
13
|
+
themes/<id>.json themes (scanned unless listed)
|
|
13
14
|
src/index.ts the extension (optional; bundled by the packer)
|
|
14
15
|
migrations/*.sql, ui/** extension migrations and UI files (optional)
|
|
15
16
|
```
|
|
16
17
|
|
|
17
|
-
A plugin without `src/index.ts` is declarative: skills and
|
|
18
|
+
A plugin without `src/index.ts` is declarative: skills, templates and themes only, no code runs.
|
|
18
19
|
|
|
19
20
|
## plugin.json
|
|
20
21
|
|
|
@@ -37,6 +38,7 @@ file is strict: an unknown key is an error. Fields (agent templates are listed u
|
|
|
37
38
|
| `skills` | array of object | no |
|
|
38
39
|
| `connectorTemplates` | array of object | no |
|
|
39
40
|
| `agents` | array of object | no |
|
|
41
|
+
| `themes` | array of object | no |
|
|
40
42
|
| `setupGuides` | array of object | no |
|
|
41
43
|
| `extension` | object | no |
|
|
42
44
|
<!-- /generated -->
|
|
@@ -48,10 +50,12 @@ Rules that the schema cannot show:
|
|
|
48
50
|
release candidates, ranges on official packages are written `^0.1.0-rc.0`.
|
|
49
51
|
- `description` is a string or `{ en, zh? }`; `displayName` is `{ zh, en }`.
|
|
50
52
|
- `icon` is a `./` path to an `.svg` or `.png` inside the plugin.
|
|
51
|
-
- `skills`, `connectorTemplates`, `agents` list paths starting with `./` that stay inside the plugin.
|
|
53
|
+
- `skills`, `connectorTemplates`, `agents`, `themes` list paths starting with `./` that stay inside the plugin.
|
|
52
54
|
Omit them to scan the default folders. Names and ids are unique within the plugin.
|
|
53
55
|
- `dependencies`: plugin name plus semver range; no self-dependency.
|
|
54
56
|
- `agents`: at most 64 templates (see `agent-templates`).
|
|
57
|
+
- `themes`: at most 10 `<id>.json` files; the id is the file's base name. A theme file is checked
|
|
58
|
+
by `parseThemeFile` (schema `https://capybarahq.com/schemas/theme.v1.schema.json`).
|
|
55
59
|
- `setupGuides` (at most 8): setup material shown where a person configures what the plugin
|
|
56
60
|
brings. Each guide has an `id`, a `place` (`channel-connection`: 新建渠道 and the channel detail;
|
|
57
61
|
the plugin's extension must provide `channel@1`), a `title` and `steps` (`{ en, zh? }`, plain
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare const SDK_VERSION = "0.1.0-rc.
|
|
1
|
+
export declare const SDK_VERSION = "0.1.0-rc.8";
|
|
2
2
|
export * from "./agent-template.js";
|
|
3
3
|
export * from "./bootstrap.js";
|
|
4
4
|
export * from "./cards.js";
|
|
@@ -27,6 +27,10 @@ export * from "./setup-guide.js";
|
|
|
27
27
|
export * from "./skill.js";
|
|
28
28
|
export * from "./skill-invocation.js";
|
|
29
29
|
export * from "./storage.js";
|
|
30
|
+
export * from "./theme.js";
|
|
31
|
+
export * from "./theme-assets.js";
|
|
32
|
+
export * from "./theme-readability.js";
|
|
33
|
+
export * from "./theme-tokens.generated.js";
|
|
30
34
|
export * from "./tool.js";
|
|
31
35
|
export * from "./tool-key.js";
|
|
32
36
|
export * from "./ui.js";
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export const SDK_VERSION = "0.1.0-rc.
|
|
1
|
+
export const SDK_VERSION = "0.1.0-rc.8";
|
|
2
2
|
export * from "./agent-template.js";
|
|
3
3
|
export * from "./bootstrap.js";
|
|
4
4
|
export * from "./cards.js";
|
|
@@ -27,6 +27,10 @@ export * from "./setup-guide.js";
|
|
|
27
27
|
export * from "./skill.js";
|
|
28
28
|
export * from "./skill-invocation.js";
|
|
29
29
|
export * from "./storage.js";
|
|
30
|
+
export * from "./theme.js";
|
|
31
|
+
export * from "./theme-assets.js";
|
|
32
|
+
export * from "./theme-readability.js";
|
|
33
|
+
export * from "./theme-tokens.generated.js";
|
|
30
34
|
export * from "./tool.js";
|
|
31
35
|
export * from "./tool-key.js";
|
|
32
36
|
export * from "./ui.js";
|
|
@@ -2,9 +2,11 @@ import { z } from "zod";
|
|
|
2
2
|
import { type JsonSchema } from "./config-ui.js";
|
|
3
3
|
import { type ConnectorTemplateSpec, type LocalizedName, type StaticExtensionManifest } from "./plugin-package.js";
|
|
4
4
|
import { type PluginSetupGuide } from "./setup-guide.js";
|
|
5
|
+
import { type PluginThemeRef } from "./theme.js";
|
|
5
6
|
/**
|
|
6
7
|
* The plugin manifest `.capybara-plugin/plugin.json` (package ecosystem spec §4.1). A plugin is a
|
|
7
|
-
* bundle of at most one extension, skills
|
|
8
|
+
* bundle of at most one extension, skills, connector templates, agent templates and themes, packed as
|
|
9
|
+
* an npm-pack tgz:
|
|
8
10
|
*
|
|
9
11
|
* ```
|
|
10
12
|
* package/package.json npm metadata; version equals plugin.json version
|
|
@@ -12,13 +14,14 @@ import { type PluginSetupGuide } from "./setup-guide.js";
|
|
|
12
14
|
* package/skills/<name>/SKILL.md skills
|
|
13
15
|
* package/connectors/<id>.json connector templates ({@link ConnectorTemplateFile})
|
|
14
16
|
* package/agents/<name>.md agent templates (parsed by `parseAgentTemplate`)
|
|
17
|
+
* package/themes/<id>.json themes (parsed by `parseThemeFile`)
|
|
15
18
|
* package/dist/index.mjs extension entry (only with an extension)
|
|
16
19
|
* package/migrations/*.sql, package/ui/**
|
|
17
20
|
* ```
|
|
18
21
|
*
|
|
19
22
|
* Paths start with `./` and stay inside the plugin root. Omitting `skills` / `connectorTemplates`
|
|
20
|
-
* / `agents` means "scan `skills/*\/SKILL.md` / `connectors/*.json` / `agents/*.md`
|
|
21
|
-
* kernel when it reads the package). `extension` is written by the packer, never by hand.
|
|
23
|
+
* / `agents` / `themes` means "scan `skills/*\/SKILL.md` / `connectors/*.json` / `agents/*.md` /
|
|
24
|
+
* `themes/*.json`" (done by the kernel when it reads the package). `extension` is written by the packer, never by hand.
|
|
22
25
|
*
|
|
23
26
|
* The committed JSON Schema (`schemas/plugin.v1.schema.json`) is generated from
|
|
24
27
|
* {@link PluginManifestSchema} by `pnpm gen:package-schemas` and drift-checked by
|
|
@@ -40,6 +43,8 @@ export declare const PLUGIN_MANIFEST_LIMITS: {
|
|
|
40
43
|
readonly connectorTemplates: 20;
|
|
41
44
|
/** Agent templates ({@link AGENT_TEMPLATE_LIMITS}`.perPlugin`). */
|
|
42
45
|
readonly agents: 64;
|
|
46
|
+
/** Themes ({@link THEME_LIMITS}`.perPlugin`). */
|
|
47
|
+
readonly themes: 10;
|
|
43
48
|
readonly descriptionChars: 1024;
|
|
44
49
|
readonly publisherChars: 100;
|
|
45
50
|
readonly displayNameChars: 100;
|
|
@@ -124,6 +129,8 @@ export interface PluginManifest {
|
|
|
124
129
|
connectorTemplates?: PluginConnectorTemplateRef[];
|
|
125
130
|
/** Agent templates; omitted = scan `agents/*.md`. */
|
|
126
131
|
agents?: PluginAgentRef[];
|
|
132
|
+
/** Themes; omitted = scan `themes/*.json`. */
|
|
133
|
+
themes?: PluginThemeRef[];
|
|
127
134
|
/**
|
|
128
135
|
* Setup guides (spec `2026-11-08-plugin-setup-guides-design.md`): steps and template files the
|
|
129
136
|
* kernel renders for a place (`channel-connection`); see {@link PluginSetupGuide}.
|
package/dist/plugin-manifest.js
CHANGED
|
@@ -6,9 +6,11 @@ import { defineExtension, EXTENSION_NAME_RE } from "./define-extension.js";
|
|
|
6
6
|
import { CATALOG_ITEM_NAME_RE, CONNECTOR_TEMPLATE_LIMITS, isSafePackagePath, SEMVER_VERSION_RE, validateConnectorTemplate, } from "./plugin-package.js";
|
|
7
7
|
import { hasUpperBound } from "./semver-range.js";
|
|
8
8
|
import { SETUP_GUIDE_FILE_RE, SETUP_GUIDE_LANGUAGES, SETUP_GUIDE_LIMITS, SETUP_GUIDE_MODES, SETUP_GUIDE_PLACES, } from "./setup-guide.js";
|
|
9
|
+
import { THEME_LIMITS, themeIdOf } from "./theme.js";
|
|
9
10
|
/**
|
|
10
11
|
* The plugin manifest `.capybara-plugin/plugin.json` (package ecosystem spec §4.1). A plugin is a
|
|
11
|
-
* bundle of at most one extension, skills
|
|
12
|
+
* bundle of at most one extension, skills, connector templates, agent templates and themes, packed as
|
|
13
|
+
* an npm-pack tgz:
|
|
12
14
|
*
|
|
13
15
|
* ```
|
|
14
16
|
* package/package.json npm metadata; version equals plugin.json version
|
|
@@ -16,13 +18,14 @@ import { SETUP_GUIDE_FILE_RE, SETUP_GUIDE_LANGUAGES, SETUP_GUIDE_LIMITS, SETUP_G
|
|
|
16
18
|
* package/skills/<name>/SKILL.md skills
|
|
17
19
|
* package/connectors/<id>.json connector templates ({@link ConnectorTemplateFile})
|
|
18
20
|
* package/agents/<name>.md agent templates (parsed by `parseAgentTemplate`)
|
|
21
|
+
* package/themes/<id>.json themes (parsed by `parseThemeFile`)
|
|
19
22
|
* package/dist/index.mjs extension entry (only with an extension)
|
|
20
23
|
* package/migrations/*.sql, package/ui/**
|
|
21
24
|
* ```
|
|
22
25
|
*
|
|
23
26
|
* Paths start with `./` and stay inside the plugin root. Omitting `skills` / `connectorTemplates`
|
|
24
|
-
* / `agents` means "scan `skills/*\/SKILL.md` / `connectors/*.json` / `agents/*.md`
|
|
25
|
-
* kernel when it reads the package). `extension` is written by the packer, never by hand.
|
|
27
|
+
* / `agents` / `themes` means "scan `skills/*\/SKILL.md` / `connectors/*.json` / `agents/*.md` /
|
|
28
|
+
* `themes/*.json`" (done by the kernel when it reads the package). `extension` is written by the packer, never by hand.
|
|
26
29
|
*
|
|
27
30
|
* The committed JSON Schema (`schemas/plugin.v1.schema.json`) is generated from
|
|
28
31
|
* {@link PluginManifestSchema} by `pnpm gen:package-schemas` and drift-checked by
|
|
@@ -44,6 +47,8 @@ export const PLUGIN_MANIFEST_LIMITS = {
|
|
|
44
47
|
connectorTemplates: 20,
|
|
45
48
|
/** Agent templates ({@link AGENT_TEMPLATE_LIMITS}`.perPlugin`). */
|
|
46
49
|
agents: AGENT_TEMPLATE_LIMITS.perPlugin,
|
|
50
|
+
/** Themes ({@link THEME_LIMITS}`.perPlugin`). */
|
|
51
|
+
themes: THEME_LIMITS.perPlugin,
|
|
47
52
|
descriptionChars: 1024,
|
|
48
53
|
publisherChars: 100,
|
|
49
54
|
displayNameChars: 100,
|
|
@@ -196,6 +201,12 @@ const schema = z
|
|
|
196
201
|
}))
|
|
197
202
|
.max(L.agents)
|
|
198
203
|
.optional(),
|
|
204
|
+
themes: z
|
|
205
|
+
.array(z.strictObject({
|
|
206
|
+
path: dotPath("path").refine((p) => p.endsWith(".json") && CATALOG_ITEM_NAME_RE.test(themeIdOf(p)), { message: "path must be a <id>.json file with id matching ^[a-z0-9][a-z0-9-]{0,63}$" }),
|
|
207
|
+
}))
|
|
208
|
+
.max(L.themes)
|
|
209
|
+
.optional(),
|
|
199
210
|
setupGuides: z.array(setupGuide).max(SETUP_GUIDE_LIMITS.guides).optional(),
|
|
200
211
|
extension: extensionSection.optional(),
|
|
201
212
|
})
|
|
@@ -235,6 +246,13 @@ const schema = z
|
|
|
235
246
|
issue(["agents", i, "path"], `duplicate agent template path ${a.path}`);
|
|
236
247
|
agentPaths.add(a.path);
|
|
237
248
|
});
|
|
249
|
+
const themeIds = new Set();
|
|
250
|
+
m.themes?.forEach((t, i) => {
|
|
251
|
+
const id = themeIdOf(t.path);
|
|
252
|
+
if (themeIds.has(id))
|
|
253
|
+
issue(["themes", i, "path"], `duplicate theme id ${id}`);
|
|
254
|
+
themeIds.add(id);
|
|
255
|
+
});
|
|
238
256
|
const guideIds = new Set();
|
|
239
257
|
m.setupGuides?.forEach((g, i) => {
|
|
240
258
|
if (guideIds.has(g.id))
|
|
@@ -269,8 +287,9 @@ const schema = z
|
|
|
269
287
|
if (m.extension === undefined &&
|
|
270
288
|
m.skills?.length === 0 &&
|
|
271
289
|
m.connectorTemplates?.length === 0 &&
|
|
272
|
-
(m.agents === undefined || m.agents.length === 0)
|
|
273
|
-
|
|
290
|
+
(m.agents === undefined || m.agents.length === 0) &&
|
|
291
|
+
(m.themes === undefined || m.themes.length === 0)) {
|
|
292
|
+
issue([], "a plugin must contain an extension, a skill, a connector template, an agent template or a theme");
|
|
274
293
|
}
|
|
275
294
|
const ext = m.extension;
|
|
276
295
|
if (ext === undefined)
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { type ParsedTheme } from "./theme.js";
|
|
2
|
+
/**
|
|
3
|
+
* Parses a logo SVG (UTF-8, ≤ {@link THEME_LIMITS}`.svgBytes`) with a strict, namespace-aware
|
|
4
|
+
* XML parser and re-serializes it. The root must be an `svg` element in the SVG namespace with a
|
|
5
|
+
* numeric `viewBox`; its `width`, `height` and `class` are dropped. Rejected: a DOCTYPE (and so
|
|
6
|
+
* any entity declaration), processing instructions, a non-UTF-8 encoding, elements outside the
|
|
7
|
+
* SVG allowlist (`script`, `foreignObject`, `style`, …) or in the XHTML namespace, `style` and
|
|
8
|
+
* `on*` attributes, `href` / `xlink:href` not starting with `#`, `javascript:` / `vbscript:` in
|
|
9
|
+
* any value, quotes or a backslash in attribute values, any function other than `url(#id)`, colors
|
|
10
|
+
* (`rgb`, `rgba`, `hsl`, `hsla`) and transforms (`translate`, `rotate`, `scale`, `matrix`,
|
|
11
|
+
* `skewX`, `skewY`), a viewBox longer than 128 characters, and animation of `href`, `style` or event
|
|
12
|
+
* handlers. Comments, the XML declaration and elements / attributes in other namespaces (editor
|
|
13
|
+
* metadata) are dropped; CDATA becomes escaped text. Never throws.
|
|
14
|
+
*/
|
|
15
|
+
export declare function sanitizeThemeSvg(bytes: Uint8Array): {
|
|
16
|
+
svg: string;
|
|
17
|
+
} | {
|
|
18
|
+
error: string;
|
|
19
|
+
};
|
|
20
|
+
/** A woff2 font: the `wOF2` signature and at most {@link THEME_LIMITS}`.fontBytes`. */
|
|
21
|
+
export declare function checkWoff2(bytes: Uint8Array): string | undefined;
|
|
22
|
+
/**
|
|
23
|
+
* A PNG logo: the PNG signature, an `IHDR` first chunk with a height of at least
|
|
24
|
+
* {@link THEME_LIMITS}`.pngMinHeight` pixels, and at most {@link THEME_LIMITS}`.pngBytes`.
|
|
25
|
+
*/
|
|
26
|
+
export declare function checkPng(bytes: Uint8Array): string | undefined;
|
|
27
|
+
/**
|
|
28
|
+
* Resolves and checks the asset files of a parsed theme: each `fonts[].file` ({@link checkWoff2})
|
|
29
|
+
* and `logo.mark` / `logo.favicon` (`.svg` through {@link sanitizeThemeSvg}, `.png` through
|
|
30
|
+
* {@link checkPng}); the favicon must be square (SVG viewBox or PNG width = height). `files` holds the plugin's files keyed by their path without a leading
|
|
31
|
+
* `./`; the returned `assets` (the sanitized SVG bytes, the other files unchanged) use the same
|
|
32
|
+
* keys. Errors are `<field>: <reason>`, English; the total input size of the theme's distinct
|
|
33
|
+
* assets must stay within {@link THEME_LIMITS}`.assetsBytes`. That limit is per plugin, so a
|
|
34
|
+
* caller reading several themes also checks the sum over all of them (distinct paths).
|
|
35
|
+
*/
|
|
36
|
+
export declare function validateThemeAssets(theme: ParsedTheme, files: Map<string, Uint8Array>): {
|
|
37
|
+
assets: Map<string, Uint8Array>;
|
|
38
|
+
errors: string[];
|
|
39
|
+
};
|