@capybara-hq/plugin-sdk 0.1.0-rc.2 → 0.1.0-rc.3

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.
Files changed (51) hide show
  1. package/README.md +1 -1
  2. package/agent-docs/agent-templates.md +47 -0
  3. package/agent-docs/concepts.md +58 -0
  4. package/agent-docs/connector-templates.md +47 -0
  5. package/agent-docs/extension-points/channel.md +15 -0
  6. package/agent-docs/extension-points/config-source.md +15 -0
  7. package/agent-docs/extension-points/connector.md +15 -0
  8. package/agent-docs/extension-points/counter.md +15 -0
  9. package/agent-docs/extension-points/directory.md +15 -0
  10. package/agent-docs/extension-points/file-preview.md +15 -0
  11. package/agent-docs/extension-points/identity-source.md +15 -0
  12. package/agent-docs/extension-points/model-provider.md +15 -0
  13. package/agent-docs/extension-points/object-store.md +15 -0
  14. package/agent-docs/extension-points/sandbox.md +15 -0
  15. package/agent-docs/extension-points/secret-store.md +15 -0
  16. package/agent-docs/extension-points/web-fetch.md +15 -0
  17. package/agent-docs/extension-points/web-search.md +15 -0
  18. package/agent-docs/extensions.md +63 -0
  19. package/agent-docs/plugin-format.md +60 -0
  20. package/agent-docs/skills.md +44 -0
  21. package/agent-docs/tool-naming.md +21 -0
  22. package/dist/agent-template.d.ts +85 -0
  23. package/dist/agent-template.js +361 -2
  24. package/dist/config-ui.d.ts +2 -1
  25. package/dist/config-ui.js +25 -7
  26. package/dist/ctx.d.ts +3 -1
  27. package/dist/directory.d.ts +11 -2
  28. package/dist/extension-point.d.ts +4 -0
  29. package/dist/extension-point.js +16 -14
  30. package/dist/file-preview.d.ts +8 -0
  31. package/dist/hooks.d.ts +11 -2
  32. package/dist/index.d.ts +2 -1
  33. package/dist/index.js +2 -1
  34. package/dist/marketplace.d.ts +29 -2
  35. package/dist/marketplace.js +30 -2
  36. package/dist/org-access.d.ts +27 -0
  37. package/dist/org-access.js +35 -0
  38. package/dist/plugin-manifest.d.ts +15 -2
  39. package/dist/plugin-manifest.js +11 -1
  40. package/dist/sandbox.d.ts +140 -60
  41. package/dist/sandbox.js +30 -6
  42. package/dist/skill-invocation.d.ts +8 -5
  43. package/dist/skill-invocation.js +17 -8
  44. package/dist/skill.d.ts +20 -3
  45. package/dist/skill.js +28 -6
  46. package/dist/tool.d.ts +8 -0
  47. package/dist/ui.d.ts +8 -0
  48. package/dist/web.d.ts +30 -5
  49. package/package.json +4 -2
  50. package/schemas/marketplace.v1.schema.json +36 -0
  51. package/schemas/plugin.v1.schema.json +29 -4
package/dist/sandbox.js CHANGED
@@ -1,17 +1,23 @@
1
1
  /**
2
- * Sandbox contract `sandbox@1`: a single-select, brokered extension point (extensions may not
2
+ * Sandbox contract `sandbox@2`: a single-select, brokered extension point (extensions may not
3
3
  * `requires` it; the kernel's `SandboxService` consumes it). The provider implements only the
4
4
  * primitives below; the kernel builds `glob` / `grep` / `edit` from `exec` plus `readFile` /
5
5
  * `writeFile`.
6
+ *
7
+ * `@2` separates an environment's **file system** from its **instance**: the file system
8
+ * (`createFileSystem`) lives until the environment is deleted (`destroyFileSystem`); instances
9
+ * (`create`) attach to it and come and go (`destroy` drops the instance and keeps the files).
6
10
  */
7
11
  /** Sandbox extension point ref. */
8
- export const SANDBOX_EXTENSION_POINT = "sandbox@1";
9
- /** 沙箱内允许模型访问的根目录。 */
12
+ export const SANDBOX_EXTENSION_POINT = "sandbox@2";
13
+ /** The roots inside the sandbox the model may access. */
10
14
  export const SANDBOX_ROOTS = ["/workspace", "/skills", "/tmp"];
11
15
  const MAX_PATH_LENGTH = 4096;
12
16
  /**
13
- * 实例在提供方那边确定已经不在了(容器被删、E2B 沙箱过期)。`exec` / `readFile` / `writeFile` / `stat`
14
- * 发现实例不在时必须抛它(而不是普通 Error),内核据此重建沙箱并重试一次;只是暂时连不上时抛普通错误。
17
+ * The instance is definitely gone on the provider's side (container removed, E2B sandbox expired).
18
+ * `exec` / `readFile` / `writeFile` / `stat` must throw it (not a plain Error) when they find the
19
+ * instance gone; the kernel then rebuilds the instance and retries once. A transient connection
20
+ * failure throws a plain error.
15
21
  */
16
22
  export class SandboxGoneError extends Error {
17
23
  sandboxGone = true;
@@ -20,12 +26,30 @@ export class SandboxGoneError extends Error {
20
26
  this.name = "SandboxGoneError";
21
27
  }
22
28
  }
23
- /** 鸭子类型判断(不用 instanceof),兼容插件自带另一份 plugin-sdk 副本的情况。 */
29
+ /** Duck-typed check (not instanceof), so a plugin bundling another plugin-sdk copy still matches. */
24
30
  export function isSandboxGoneError(e) {
25
31
  return (e instanceof Error &&
26
32
  e.name === "SandboxGoneError" &&
27
33
  e.sandboxGone === true);
28
34
  }
35
+ /**
36
+ * The file system is definitely gone on the provider's side (volume removed, E2B sandbox killed).
37
+ * `create` throws it instead of attaching the instance to a new, empty file system; the kernel then
38
+ * reports the environment's files as lost rather than handing out a silently empty workspace.
39
+ */
40
+ export class FileSystemGoneError extends Error {
41
+ fileSystemGone = true;
42
+ constructor(message, opts) {
43
+ super(message, opts && "cause" in opts ? { cause: opts.cause } : undefined);
44
+ this.name = "FileSystemGoneError";
45
+ }
46
+ }
47
+ /** Duck-typed check (not instanceof), so a plugin bundling another plugin-sdk copy still matches. */
48
+ export function isFileSystemGoneError(e) {
49
+ return (e instanceof Error &&
50
+ e.name === "FileSystemGoneError" &&
51
+ e.fileSystemGone === true);
52
+ }
29
53
  /**
30
54
  * A holder tag (`exec` argument `tag`, {@link SandboxProvider.killTagged}): the kernel passes its
31
55
  * lease tokens (UUIDs). Providers check tags against it before putting them in a command line or a
@@ -26,13 +26,14 @@ export declare function skillInvocation(frontmatter: Readonly<Record<string, unk
26
26
  export declare function parseSkillArguments(args: string): string[];
27
27
  /**
28
28
  * A skill body with its arguments substituted (see the file header), without the wrapper.
29
- * `skillName` is the resolved skill's bare name: `${CLAUDE_SKILL_DIR}` becomes
30
- * `/skills/<skillName>` (a qualified `<plugin>:<name>` throws a `TypeError`). `args` is trimmed;
29
+ * `skillName` is the resolved skill's bare name and `digest` its version's `skillDigest`:
30
+ * `${CLAUDE_SKILL_DIR}` becomes `/skills/<skillName>@<digest>` (a qualified `<plugin>:<name>` or a
31
+ * digest that is not 12 lowercase hex digits throws a `TypeError`). `args` is trimmed;
31
32
  * more than {@link SKILL_INVOCATION_LIMITS.argumentsMaxChars} characters throw a `RangeError`, and
32
33
  * so does a result longer than {@link SKILL_INVOCATION_LIMITS.renderedMaxChars} (checked while
33
34
  * substituting, before the long string is built).
34
35
  */
35
- export declare function renderSkillBody(body: string, invocation: SkillInvocation, args: string, skillName: string): string;
36
+ export declare function renderSkillBody(body: string, invocation: SkillInvocation, args: string, skillName: string, digest: string): string;
36
37
  /** Input of {@link renderSkillInvocation}. */
37
38
  export interface RenderSkillInvocationInput {
38
39
  /**
@@ -41,10 +42,12 @@ export interface RenderSkillInvocationInput {
41
42
  */
42
43
  name: string;
43
44
  /**
44
- * The resolved skill's bare name (never `<plugin>:<name>`): its sandbox directory
45
- * `/skills/<skillName>/`, used for `${CLAUDE_SKILL_DIR}` and the files line.
45
+ * The resolved skill's bare name (never `<plugin>:<name>`): with `digest`, its sandbox
46
+ * directory `/skills/<skillName>@<digest>/`, used for `${CLAUDE_SKILL_DIR}` and the files line.
46
47
  */
47
48
  skillName: string;
49
+ /** The version's `skillDigest` (12 lowercase hex digits). */
50
+ digest: string;
48
51
  version: number;
49
52
  /** The SKILL.md body (after the frontmatter). */
50
53
  body: string;
@@ -6,12 +6,12 @@
6
6
  * The argument rules follow Claude Code (re-checked 2026-10-27): `$ARGUMENTS` is the whole argument
7
7
  * string, `$ARGUMENTS[N]` / `$N` are 0-based positional values (a missing one stays as written),
8
8
  * `$name` takes its value from frontmatter `arguments` (a missing one becomes empty), `\$` is a
9
- * literal `$`, `${CLAUDE_SKILL_DIR}` is `/skills/<name>` and every other `${…}` stays as written.
9
+ * literal `$`, `${CLAUDE_SKILL_DIR}` is `/skills/<name>@<digest>` and every other `${…}` stays as written.
10
10
  * When the body has no argument placeholder and the arguments are not empty, they are appended as
11
11
  * `ARGUMENTS: <args>`. Substituted text is never scanned again. Nothing is executed: shell
12
12
  * injections (`` !`cmd` ``) stay text, and the model is told how to run them.
13
13
  */
14
- import { isSkillName, SKILL_INVOCATION_LIMITS, SKILLS_SANDBOX_ROOT } from "./skill.js";
14
+ import { isSkillName, SKILL_INVOCATION_LIMITS, SKILLS_SANDBOX_ROOT, skillSandboxDir, } from "./skill.js";
15
15
  import { argumentHintText, SKILL_ARGUMENT_NAME_RE } from "./skill-keys.js";
16
16
  /**
17
17
  * The invocation metadata of a SKILL.md frontmatter. Values of the wrong type are ignored here
@@ -102,17 +102,26 @@ const checkSkillName = (skillName) => {
102
102
  throw new TypeError(`skillName must be a bare skill name (its directory under ${SKILLS_SANDBOX_ROOT}), got "${skillName}"`);
103
103
  }
104
104
  };
105
+ const DIGEST_RE = /^[0-9a-f]{12}$/;
106
+ const checkDigest = (digest) => {
107
+ if (typeof digest !== "string" || !DIGEST_RE.test(digest)) {
108
+ throw new TypeError(`digest must be 12 lowercase hex digits (skillDigest), got "${digest}"`);
109
+ }
110
+ };
105
111
  const tooLong = () => new RangeError(`the rendered skill must be at most ${SKILL_INVOCATION_LIMITS.renderedMaxChars} characters`);
106
112
  /**
107
113
  * A skill body with its arguments substituted (see the file header), without the wrapper.
108
- * `skillName` is the resolved skill's bare name: `${CLAUDE_SKILL_DIR}` becomes
109
- * `/skills/<skillName>` (a qualified `<plugin>:<name>` throws a `TypeError`). `args` is trimmed;
114
+ * `skillName` is the resolved skill's bare name and `digest` its version's `skillDigest`:
115
+ * `${CLAUDE_SKILL_DIR}` becomes `/skills/<skillName>@<digest>` (a qualified `<plugin>:<name>` or a
116
+ * digest that is not 12 lowercase hex digits throws a `TypeError`). `args` is trimmed;
110
117
  * more than {@link SKILL_INVOCATION_LIMITS.argumentsMaxChars} characters throw a `RangeError`, and
111
118
  * so does a result longer than {@link SKILL_INVOCATION_LIMITS.renderedMaxChars} (checked while
112
119
  * substituting, before the long string is built).
113
120
  */
114
- export function renderSkillBody(body, invocation, args, skillName) {
121
+ export function renderSkillBody(body, invocation, args, skillName, digest) {
115
122
  checkSkillName(skillName);
123
+ checkDigest(digest);
124
+ const dir = skillSandboxDir(skillName, digest);
116
125
  const all = trimmedArgs(args);
117
126
  const values = parseSkillArguments(all);
118
127
  const named = invocation.arguments ?? [];
@@ -125,7 +134,7 @@ export function renderSkillBody(body, invocation, args, skillName) {
125
134
  if (m === "\\$")
126
135
  return "$";
127
136
  if (m === "${CLAUDE_SKILL_DIR}")
128
- return `${SKILLS_SANDBOX_ROOT}/${skillName}`;
137
+ return dir;
129
138
  if (m === "$ARGUMENTS") {
130
139
  placeholder = true;
131
140
  return all;
@@ -173,14 +182,14 @@ const escapeAttr = (s) => s.replace(/&/g, "&amp;").replace(/"/g, "&quot;").repla
173
182
  */
174
183
  export function renderSkillInvocation(i) {
175
184
  const args = trimmedArgs(i.args);
176
- const body = renderSkillBody(i.body, i.invocation, args, i.skillName).replace(CLOSE_TAG_RE, "<\\/$1");
185
+ const body = renderSkillBody(i.body, i.invocation, args, i.skillName, i.digest).replace(CLOSE_TAG_RE, "<\\/$1");
177
186
  const parts = [];
178
187
  if (i.lead !== false) {
179
188
  parts.push(escapeTags(`The user invoked the skill "${i.name}" with /${i.name}${args === "" ? "" : ` ${args}`}. Follow its instructions for this request.`));
180
189
  }
181
190
  parts.push(`<skill_invocation name="${escapeAttr(i.name)}" version="${i.version}">\n${body}\n</skill_invocation>`);
182
191
  if (i.lines.files === "load") {
183
- parts.push(`Its files are not in the sandbox yet: call Skill with "${i.name}" to copy them to ${SKILLS_SANDBOX_ROOT}/${i.skillName}/ before running its scripts.`);
192
+ parts.push(`Its files are not in the sandbox yet: call Skill with "${i.name}" to copy them to ${skillSandboxDir(i.skillName, i.digest)}/ before running its scripts.`);
184
193
  }
185
194
  else if (i.lines.files === "unavailable") {
186
195
  parts.push("Its other files are not available in this conversation.");
package/dist/skill.d.ts CHANGED
@@ -30,12 +30,29 @@ export declare const SKILL_INVOCATION_LIMITS: {
30
30
  };
31
31
  /** 技能入口文件(包根目录,大小写敏感)。 */
32
32
  export declare const SKILL_ENTRY_FILE = "SKILL.md";
33
- /** 沙箱里放技能的根目录:每个技能在 `/skills/<name>/` 下(只读复制)。 */
33
+ /**
34
+ * The sandbox root for skills: each skill version is copied (read-only to commands) to
35
+ * `/skills/<name>@<digest>/` ({@link skillSandboxDir}).
36
+ */
34
37
  export declare const SKILLS_SANDBOX_ROOT = "/skills";
35
38
  /** 是否为合法的技能名(见文件头的规范说明)。 */
36
39
  export declare function isSkillName(s: unknown): s is string;
37
- /** 技能文件在沙箱里的路径:`/skills/<name>/<path>`。 */
38
- export declare function skillSandboxPath(name: string, path: string): string;
40
+ /**
41
+ * The digest of a skill version's file manifest: the first 12 hex digits of the sha256 of its
42
+ * files sorted by path (JavaScript string order), one `${path} ${size} ${sha256}\n` line each. Two
43
+ * versions with the same files get the same digest, so their sandbox directories coincide; any
44
+ * other change gives a different directory, so two versions of one skill never overwrite each
45
+ * other in a shared file system.
46
+ */
47
+ export declare function skillDigest(files: {
48
+ path: string;
49
+ size: number;
50
+ sha256: string;
51
+ }[]): string;
52
+ /** A skill version's directory in the sandbox: `/skills/<name>@<digest>` ({@link skillDigest}). */
53
+ export declare function skillSandboxDir(name: string, digest: string): string;
54
+ /** A skill file's path in the sandbox: `/skills/<name>@<digest>/<path>`. */
55
+ export declare function skillSandboxPath(name: string, digest: string, path: string): string;
39
56
  /** {@link parseSkillMd} 成功时的结果。 */
40
57
  export interface ParsedSkillMd {
41
58
  name: string;
package/dist/skill.js CHANGED
@@ -16,8 +16,9 @@
16
16
  * whose types are checked because the kernel uses them (`skillInvocation`, phase D). Matching the
17
17
  * directory name is not enforced: an uploaded zip's outer directory often has another name (GitHub's
18
18
  * `repo-main/`); the skill's name is always the frontmatter `name`, and its sandbox directory is
19
- * `/skills/<name>/`.
19
+ * `/skills/<name>@<digest>/` ({@link skillSandboxDir}, {@link skillDigest}).
20
20
  */
21
+ import { createHash } from "node:crypto";
21
22
  import { readFrontmatter } from "./frontmatter.js";
22
23
  import { hasControlChars } from "./model.js";
23
24
  import { validateSandboxPath } from "./sandbox.js";
@@ -54,7 +55,10 @@ export const SKILL_INVOCATION_LIMITS = {
54
55
  };
55
56
  /** 技能入口文件(包根目录,大小写敏感)。 */
56
57
  export const SKILL_ENTRY_FILE = "SKILL.md";
57
- /** 沙箱里放技能的根目录:每个技能在 `/skills/<name>/` 下(只读复制)。 */
58
+ /**
59
+ * The sandbox root for skills: each skill version is copied (read-only to commands) to
60
+ * `/skills/<name>@<digest>/` ({@link skillSandboxDir}).
61
+ */
58
62
  export const SKILLS_SANDBOX_ROOT = "/skills";
59
63
  const NAME_RE = /^[a-z0-9]+(-[a-z0-9]+)*$/;
60
64
  const XML_TAG_RE = /<\/?[A-Za-z][^<>]*>/;
@@ -63,9 +67,27 @@ const DRIVE_RE = /^[A-Za-z]:/;
63
67
  export function isSkillName(s) {
64
68
  return typeof s === "string" && s.length <= SKILL_LIMITS.nameMaxChars && NAME_RE.test(s);
65
69
  }
66
- /** 技能文件在沙箱里的路径:`/skills/<name>/<path>`。 */
67
- export function skillSandboxPath(name, path) {
68
- return `${SKILLS_SANDBOX_ROOT}/${name}/${path}`;
70
+ /**
71
+ * The digest of a skill version's file manifest: the first 12 hex digits of the sha256 of its
72
+ * files sorted by path (JavaScript string order), one `${path} ${size} ${sha256}\n` line each. Two
73
+ * versions with the same files get the same digest, so their sandbox directories coincide; any
74
+ * other change gives a different directory, so two versions of one skill never overwrite each
75
+ * other in a shared file system.
76
+ */
77
+ export function skillDigest(files) {
78
+ const lines = [...files]
79
+ .sort((a, b) => (a.path < b.path ? -1 : a.path > b.path ? 1 : 0))
80
+ .map((f) => `${f.path} ${f.size} ${f.sha256}\n`)
81
+ .join("");
82
+ return createHash("sha256").update(lines).digest("hex").slice(0, 12);
83
+ }
84
+ /** A skill version's directory in the sandbox: `/skills/<name>@<digest>` ({@link skillDigest}). */
85
+ export function skillSandboxDir(name, digest) {
86
+ return `${SKILLS_SANDBOX_ROOT}/${name}@${digest}`;
87
+ }
88
+ /** A skill file's path in the sandbox: `/skills/<name>@<digest>/<path>`. */
89
+ export function skillSandboxPath(name, digest, path) {
90
+ return `${skillSandboxDir(name, digest)}/${path}`;
69
91
  }
70
92
  const chars = (s) => [...s].length;
71
93
  /**
@@ -179,7 +201,7 @@ function pathProblem(p) {
179
201
  return "path must not contain '.' or '..' segments";
180
202
  }
181
203
  // 再按沙箱路径规则核一遍(百分号编码的 `..` 等)
182
- const errs = validateSandboxPath(skillSandboxPath("skill", p));
204
+ const errs = validateSandboxPath(skillSandboxPath("skill", "000000000000", p));
183
205
  return errs[0] ?? null;
184
206
  }
185
207
  /**
package/dist/tool.d.ts CHANGED
@@ -129,6 +129,14 @@ export interface ToolCallContext {
129
129
  state: unknown;
130
130
  answer: FormAnswer | null;
131
131
  };
132
+ /**
133
+ * The extension's effective deployment config for this org: the platform's deployment config
134
+ * with the org's copy applied to the overridable fields (`orgAccess(…, "override")`), or the
135
+ * platform's config (equal to `ctx.config`) while the org follows it. Use it, not `ctx.config`,
136
+ * for work done for this org. Optional in the type so older extensions compile; the kernel
137
+ * always passes it.
138
+ */
139
+ config?: unknown;
132
140
  }
133
141
  export type ToolHandler = (input: unknown, ctx: ToolCallContext) => Promise<ToolResult | InputRequired>;
134
142
  /**
package/dist/ui.d.ts CHANGED
@@ -175,6 +175,14 @@ export interface UiRenderArgs {
175
175
  callId: string;
176
176
  key?: string;
177
177
  };
178
+ /**
179
+ * The extension's effective deployment config for this org: the platform's deployment config
180
+ * with the org's copy applied to the overridable fields (`orgAccess(…, "override")`), or the
181
+ * platform's config (equal to `ctx.config`) while the org follows it. Use it, not `ctx.config`,
182
+ * for work done for this org. Optional in the type so older extensions compile; the kernel
183
+ * always passes it.
184
+ */
185
+ config?: unknown;
178
186
  }
179
187
  /** 视图里的按钮或表单提交:`actionId` 来自块;表单提交时带 `answer`。 */
180
188
  export interface UiActionArgs extends UiRenderArgs {
package/dist/web.d.ts CHANGED
@@ -12,10 +12,16 @@ export interface WebSearchResult {
12
12
  /** ISO 8601 date or datetime, when known. */
13
13
  publishedAt?: string;
14
14
  }
15
- /** A web search provider (`web-search@1`). The kernel passes the org's decrypted `orgConfig`. */
15
+ /**
16
+ * A web search provider (`web-search@1`). The kernel passes the org's decrypted `orgConfig` and the
17
+ * extension's effective deployment config for the org (`config`).
18
+ */
16
19
  export interface WebSearchProvider {
17
- /** False when this org's config lacks what the provider needs. */
18
- configured?(orgConfig: unknown): boolean;
20
+ /**
21
+ * False when this org's config lacks what the provider needs. `config` is the effective
22
+ * deployment config for the org (see `search`'s `config`).
23
+ */
24
+ configured?(orgConfig: unknown, config?: unknown): boolean;
19
25
  search(args: {
20
26
  query: string;
21
27
  /** Hints only: the kernel filters the results again. */
@@ -23,6 +29,14 @@ export interface WebSearchProvider {
23
29
  blockedDomains?: string[];
24
30
  maxResults: number;
25
31
  orgConfig: unknown;
32
+ /**
33
+ * The extension's effective deployment config for this org: the platform's deployment config
34
+ * with the org's copy applied to the overridable fields (`orgAccess(…, "override")`), or the
35
+ * platform's config (equal to `ctx.config`) while the org follows it. Use it, not `ctx.config`,
36
+ * for work done for this org. Optional in the type so older extensions compile; the kernel
37
+ * always passes it.
38
+ */
39
+ config?: unknown;
26
40
  signal: AbortSignal;
27
41
  }): Promise<{
28
42
  results: WebSearchResult[];
@@ -48,12 +62,23 @@ export interface WebFetchPage {
48
62
  * to (an IPv6 address in brackets, as in a URL).
49
63
  */
50
64
  export interface WebFetchProvider {
51
- /** False when this org's config lacks what the provider needs. */
52
- configured?(orgConfig: unknown): boolean;
65
+ /**
66
+ * False when this org's config lacks what the provider needs. `config` is the effective
67
+ * deployment config for the org (see `fetch`'s `config`).
68
+ */
69
+ configured?(orgConfig: unknown, config?: unknown): boolean;
53
70
  fetch(args: {
54
71
  /** Already validated and upgraded by the kernel. */
55
72
  url: string;
56
73
  orgConfig: unknown;
74
+ /**
75
+ * The extension's effective deployment config for this org: the platform's deployment config
76
+ * with the org's copy applied to the overridable fields (`orgAccess(…, "override")`), or the
77
+ * platform's config (equal to `ctx.config`) while the org follows it. Use it, not `ctx.config`,
78
+ * for work done for this org. Optional in the type so older extensions compile; the kernel
79
+ * always passes it.
80
+ */
81
+ config?: unknown;
57
82
  signal: AbortSignal;
58
83
  }): Promise<WebFetchPage>;
59
84
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capybara-hq/plugin-sdk",
3
- "version": "0.1.0-rc.2",
3
+ "version": "0.1.0-rc.3",
4
4
  "description": "Capybara plugin SDK: the types and pure functions plugins are written against",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -17,11 +17,13 @@
17
17
  "types": "./dist/index.d.ts",
18
18
  "import": "./dist/index.js",
19
19
  "default": "./dist/index.js"
20
- }
20
+ },
21
+ "./package.json": "./package.json"
21
22
  },
22
23
  "files": [
23
24
  "dist",
24
25
  "schemas",
26
+ "agent-docs",
25
27
  "README.md",
26
28
  "NOTICE"
27
29
  ],
@@ -68,6 +68,25 @@
68
68
  "en"
69
69
  ]
70
70
  },
71
+ "displayName": {
72
+ "type": "object",
73
+ "properties": {
74
+ "zh": {
75
+ "type": "string",
76
+ "minLength": 1,
77
+ "maxLength": 100
78
+ },
79
+ "en": {
80
+ "type": "string",
81
+ "minLength": 1,
82
+ "maxLength": 100
83
+ }
84
+ },
85
+ "required": [
86
+ "zh",
87
+ "en"
88
+ ]
89
+ },
71
90
  "version": {
72
91
  "type": "string",
73
92
  "maxLength": 256,
@@ -110,6 +129,23 @@
110
129
  "maxLength": 2000,
111
130
  "pattern": "^https:\\/\\/\\S+$"
112
131
  },
132
+ "deprecated": {
133
+ "anyOf": [
134
+ {
135
+ "type": "boolean"
136
+ },
137
+ {
138
+ "type": "object",
139
+ "properties": {
140
+ "reason": {
141
+ "type": "string",
142
+ "minLength": 1,
143
+ "maxLength": 280
144
+ }
145
+ }
146
+ }
147
+ ]
148
+ },
113
149
  "source": {
114
150
  "anyOf": [
115
151
  {
@@ -28,10 +28,35 @@
28
28
  "pattern": "\\S"
29
29
  },
30
30
  "description": {
31
- "type": "string",
32
- "minLength": 1,
33
- "maxLength": 1024,
34
- "pattern": "\\S"
31
+ "anyOf": [
32
+ {
33
+ "type": "string",
34
+ "minLength": 1,
35
+ "maxLength": 1024,
36
+ "pattern": "\\S"
37
+ },
38
+ {
39
+ "type": "object",
40
+ "properties": {
41
+ "en": {
42
+ "type": "string",
43
+ "minLength": 1,
44
+ "maxLength": 1024,
45
+ "pattern": "\\S"
46
+ },
47
+ "zh": {
48
+ "type": "string",
49
+ "minLength": 1,
50
+ "maxLength": 1024,
51
+ "pattern": "\\S"
52
+ }
53
+ },
54
+ "required": [
55
+ "en"
56
+ ],
57
+ "additionalProperties": false
58
+ }
59
+ ]
35
60
  },
36
61
  "displayName": {
37
62
  "type": "object",