@webskill/sdk 0.0.6 → 0.1.0

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 CHANGED
@@ -9,22 +9,25 @@ governance.
9
9
  ## Features
10
10
 
11
11
  - **Skill protocol** — Agent Skills compatible discovery, validation, cataloging
12
- (JSON / XML), and safe per-skill file access.
12
+ (JSON / XML), declarative `dependencies` and `allowed-tools`, skill packs
13
+ (multi-skill zip export/import with integrity digests).
13
14
  - **Agent loop** — multi-turn tool calling with structured errors fed back to
14
- the LLM, guardrails, lifecycle events, memory, and human interaction
15
- (missing-parameter forms, confirmations, ask-user).
16
- - **Script sandbox** — in-process Node executor plus a `worker_threads` sandbox;
17
- Web Worker sandbox for the browser. Timeouts kill runaway scripts.
18
- - **Streaming** — OpenAI-compatible SSE streaming end to end, with incremental
19
- UI updates.
15
+ the LLM, guardrails, lifecycle events, memory, human interaction
16
+ (missing-parameter forms, confirmations, authorization prompts), and
17
+ resumable interrupted runs.
18
+ - **Script sandbox** — `worker_threads` sandbox for Node, Web Worker sandbox for
19
+ the browser. Deny-by-default network policy, per-capability forced approval,
20
+ timeouts kill runaway scripts.
21
+ - **`navigator.webskill`** — a browser facade (`discover` / `read` / `validate` /
22
+ `run` / `install` / `uninstall`) assembled explicitly in one call.
20
23
  - **MCP** — call page-provided tools and consume page-declared dynamic skills
21
24
  over standard MCP transports (MessageChannel).
22
25
  - **Governance** — LLM-generated skill candidates with mandatory review,
23
26
  approval workflows, audit log, versioning/rollback, quarantine, evaluation,
24
27
  and scoring.
25
- - **UI** — framework-agnostic web forms, result rendering, generative UI
26
- adapters (Vercel AI SDK, OpenUI, A2UI), plus React and Vue component
27
- primitives.
28
+ - **UI** — framework-agnostic forms, result rendering (markdown, tables, SVG
29
+ charts), generative UI adapters (Vercel AI SDK, OpenUI, A2UI), plus React and
30
+ Vue component primitives.
28
31
 
29
32
  ## Installation
30
33
 
@@ -35,53 +38,184 @@ npm install @webskill/sdk
35
38
  React/Vue integrations require their respective peer dependencies
36
39
  (`react` + `react-dom`, or `vue`), which are optional.
37
40
 
41
+ ## Requirements
42
+
43
+ - Node.js >= 22.18 (native type stripping for `.ts` skill scripts)
44
+ - Modern browsers for the browser host (OPFS, Web Workers, ES modules)
45
+
38
46
  ## Quick start (Node)
39
47
 
40
- ```ts
41
- import { OpenAiCompatibleClient, WebSkillRuntime } from '@webskill/sdk';
42
- import { NodeFS, NodeScriptExecutor, FileArtifactStore } from '@webskill/sdk/node';
43
-
44
- const runtime = new WebSkillRuntime({
45
- fs: new NodeFS(),
46
- roots: ['./skills'],
47
- llm: new OpenAiCompatibleClient({
48
- baseUrl: 'https://your-llm-endpoint/v1',
49
- apiKey: process.env.LLM_API_KEY!,
50
- model: 'your-model'
51
- }),
52
- executor: new NodeScriptExecutor(new NodeFS()),
53
- artifactStore: new FileArtifactStore({ root: './.webskill/artifacts' })
54
- });
48
+ Runs as-is with the bundled mock LLM — see
49
+ [`examples/quickstart-node`](../examples/quickstart-node) for the full project.
50
+
51
+ ```js
52
+ import { WebSkillRuntime } from '@webskill/sdk';
53
+ import { NodeFS, SandboxedScriptExecutor } from '@webskill/sdk/node';
54
+ import { MockLlmClient } from '@webskill/sdk/testing';
55
+
56
+ const fs = new NodeFS();
57
+ const llm = new MockLlmClient([
58
+ { toolCalls: [{ id: 'c1', name: 'read_skill_file', arguments: { skillName: 'greeter' } }] },
59
+ { toolCalls: [{ id: 'c2', name: 'greeter__greet', arguments: { text: 'world' } }] },
60
+ { content: 'Greeted the world.' }
61
+ ]);
55
62
 
56
- // Discover skills and render the catalog
57
- const { entries, issues } = await runtime.discover();
58
- console.log(
59
- entries.map((e) => e.name),
60
- issues
61
- );
63
+ const runtime = new WebSkillRuntime({ fs, roots: ['./skills'], llm, executor: new SandboxedScriptExecutor(fs) });
62
64
 
63
- // Run the agent loop
64
- const { output, run } = await runtime.run('Use the calculator skill to compute 2+3.');
65
+ const catalog = await runtime.discover();
66
+ console.log(catalog.entries.map((e) => e.name));
67
+
68
+ const { output, run } = await runtime.run('Greet the world.');
65
69
  console.log(output, run.status, run.trace.length);
66
70
  ```
67
71
 
72
+ For a real LLM, replace the mock with `OpenAiCompatibleClient`:
73
+
74
+ ```js
75
+ import { OpenAiCompatibleClient } from '@webskill/sdk';
76
+
77
+ const llm = new OpenAiCompatibleClient({
78
+ baseUrl: 'https://your-llm-endpoint/v1',
79
+ apiKey: process.env.LLM_API_KEY,
80
+ model: 'your-model'
81
+ });
82
+ ```
83
+
68
84
  ## Subpath exports
69
85
 
70
- | Subpath | Contents |
71
- | -------------------------- | -------------------------------------------------------------------------------------------------------------------- |
72
- | `@webskill/sdk` | Core protocol + runtime engine (discovery, agent loop, LLM clients, routing, interaction, memory, artifacts, trace) |
73
- | `@webskill/sdk/node` | Node host: NodeFS, script executors (in-process + sandboxed), file stores, skill manager, CLI UI bridge, env helpers |
74
- | `@webskill/sdk/browser` | Browser host: OPFS provider, Web Worker script sandbox, worker runtime host/client |
75
- | `@webskill/sdk/mcp` | MCP transports, endpoint registry, tool resolver, temporary skills, WebMCP adapter, runtime plugin |
76
- | `@webskill/sdk/ui` | Framework-agnostic forms, result rendering, mini markdown, Vercel/OpenUI/A2UI adapters, A2UI Lit runtime |
77
- | `@webskill/sdk/ui-react` | React bridge state + InteractionForm/ResultBlocks/StreamingText components |
78
- | `@webskill/sdk/ui-vue` | Vue bridge state + equivalent components |
79
- | `@webskill/sdk/governance` | Candidates, approval, audit, versioning, state policy, evaluation, scoring, documents |
86
+ ### `@webskill/sdk` (main entry)
80
87
 
81
- ## Requirements
88
+ Core protocol + runtime engine: discovery, catalog, validation, agent loop, LLM
89
+ clients, routing, interaction types, memory, artifacts, tracing, network policy,
90
+ capability approval, and the environment-agnostic `createWebSkillApi` facade.
82
91
 
83
- - Node.js >= 22.18 (native type stripping for `.ts` skill scripts)
84
- - Modern browsers for the browser host (OPFS, Web Workers, ES modules)
92
+ ```js
93
+ import { SkillDiscovery, validateSkills, createWebSkillApi } from '@webskill/sdk';
94
+
95
+ const api = createWebSkillApi({ fs, roots: ['./skills'], llm, skillManager });
96
+ const report = await api.validate('./skills');
97
+ const run = await api.run('Summarize the references of skill greeter.');
98
+ ```
99
+
100
+ ### `@webskill/sdk/node`
101
+
102
+ Node host: `NodeFS`, script executors (in-process + `worker_threads` sandbox),
103
+ file-backed stores, `SkillManager` (install/export incl. multi-skill packs),
104
+ CLI UI bridge, schema inference.
105
+
106
+ ```js
107
+ import { NodeFS, SkillManager } from '@webskill/sdk/node';
108
+
109
+ const manager = new SkillManager({ managedRoot: './.webskill/skills' });
110
+ await manager.install({ type: 'http', url: 'https://example.com/greeter.zip' });
111
+ await manager.exportPack(['greeter', 'calculator'], { outPath: './pack.zip' });
112
+ console.log((await manager.verifyIntegrity('greeter')).ok);
113
+ ```
114
+
115
+ ### `@webskill/sdk/browser`
116
+
117
+ Browser host: OPFS provider, Web Worker script sandbox (deny-by-default network
118
+ policy), worker runtime host/client, `BrowserSkillManager`, and the
119
+ `navigator.webskill` assembler. See
120
+ [`examples/quickstart-browser`](../examples/quickstart-browser).
121
+
122
+ ```js
123
+ import { installWebSkillNavigator } from '@webskill/browser';
124
+
125
+ const api = installWebSkillNavigator({ roots: ['/skills'], llm });
126
+ const catalog = await navigator.webskill.discover('/skills');
127
+ const run = await navigator.webskill.run('Greet the world.');
128
+ ```
129
+
130
+ ### `@webskill/sdk/mcp`
131
+
132
+ MCP integration: MessageChannel transport, endpoint registry, tool resolver,
133
+ temporary (page-declared) skills, WebMCP adapter, runtime plugin.
134
+
135
+ ```js
136
+ import { MessageChannelTransport, serveSkillAsMcp } from '@webskill/sdk/mcp';
137
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
138
+
139
+ const server = new McpServer({ name: 'page', version: '0.1.0' });
140
+ serveSkillAsMcp(server, { name: 'greeter', description: 'Greet someone', body: '# Greeter' });
141
+ await server.connect(new MessageChannelTransport(port));
142
+ ```
143
+
144
+ ### `@webskill/sdk/ui`
145
+
146
+ Framework-agnostic UI: form models + `WebFormBridge`, result rendering
147
+ (markdown / table / mini-chart SVG), mini markdown, generative UI adapters
148
+ (Vercel AI SDK, OpenUI, A2UI).
149
+
150
+ ```js
151
+ import { WebFormBridge } from '@webskill/sdk/ui';
152
+
153
+ const bridge = new WebFormBridge({ mount: document.querySelector('#ui') });
154
+ // pass as uiBridge to the runtime: forms, confirmations, and authorization
155
+ // prompts render as real DOM, results (incl. charts) render on completion.
156
+ ```
157
+
158
+ ### `@webskill/sdk/ui-react`
159
+
160
+ React bridge state + `InteractionForm` / `ResultBlocks` / `StreamingText`
161
+ components (requires `react` + `react-dom`).
162
+
163
+ ```jsx
164
+ import { ReactBridgeState, InteractionForm, ResultBlocks } from '@webskill/sdk/ui-react';
165
+
166
+ const bridge = new ReactBridgeState();
167
+ // <InteractionForm bridge={bridge} /> <ResultBlocks bridge={bridge} />
168
+ ```
169
+
170
+ ### `@webskill/sdk/ui-vue`
171
+
172
+ Vue bridge state + equivalent components (requires `vue`).
173
+
174
+ ```js
175
+ import { VueBridgeState, InteractionForm, ResultBlocks } from '@webskill/sdk/ui-vue';
176
+
177
+ const bridge = new VueBridgeState();
178
+ // <InteractionForm :bridge="bridge" /> <ResultBlocks :bridge="bridge" />
179
+ ```
180
+
181
+ ### `@webskill/sdk/governance`
182
+
183
+ Governance: skill candidates with mandatory review, approval workflows, audit
184
+ log, versioning/rollback, quarantine, evaluation, scoring, dependency graph.
185
+
186
+ ```js
187
+ import { DependencyGraph } from '@webskill/sdk/governance';
188
+
189
+ const graph = DependencyGraph.buildFromCatalog(catalog.entries, documents);
190
+ console.log(graph.dependenciesOf('greeter'));
191
+ ```
192
+
193
+ ### `@webskill/sdk/testing`
194
+
195
+ Test facilities (moved out of the main entry in 0.1.0): `MockLlmClient`,
196
+ `MockUiBridge`, `InMemoryStore`, `MemoryArtifactStore`.
197
+
198
+ ```js
199
+ import { MockLlmClient, MockUiBridge, InMemoryStore, MemoryArtifactStore } from '@webskill/sdk/testing';
200
+
201
+ const llm = new MockLlmClient([{ content: 'deterministic answer' }]);
202
+ ```
203
+
204
+ ## Stability
205
+
206
+ This package follows semver starting at 0.1.0. Public symbols carry JSDoc
207
+ stability tags:
208
+
209
+ - **`@stable`** — covered by the semver contract: bug fixes ship in patch,
210
+ backwards-compatible capabilities in minor, breaking changes only in major
211
+ (with release notes).
212
+ - **`@experimental`** — may change in minor/patch releases. Currently:
213
+ `ExperimentalWebMcpAdapter`, `resumeRun` and the `RunSnapshot` format,
214
+ the A2UI/OpenUI adapters, and the `authorize` interaction type.
215
+
216
+ The public API surface of every subpath is pinned by checked-in `.d.ts`
217
+ snapshots (`api-snapshots/`); any intentional change requires
218
+ `pnpm api:update` and is reviewable in the diff.
85
219
 
86
220
  ## License
87
221
 
package/dist/browser.d.ts CHANGED
@@ -1,4 +1,5 @@
1
- import { A as InteractionPolicy, B as LlmResponse, Et as UiBridge, Ht as parseBridgeRequest, L as LlmClient, M as InteractionResponse, Ot as WebSkillApi, V as LlmStreamEvent, Xt as FileSystemProvider, Yt as FileStat, Z as NetworkPolicy, _t as ScriptExecutor, b as ExternalToolSource, c as ApprovalScope, cn as SkillInstallSource, d as BridgeCapabilities, dn as SkillManifest, gn as SkillsLockfile, gt as ScriptExecutionContext, j as InteractionRequest, jt as bridgeError, m as BridgeResponse, ot as RenderResultRequest, p as BridgeRequest, vn as VerifyResult, xt as ToolResult, y as ExternalSkillProvider, yt as ToolDefinition } from "./index-DCifjtJx.js";
1
+ import { H as SkillsLockfile, L as SkillManifest, P as SkillInstallSource, S as FileSystemProvider, W as VerifyResult, _ as RenderResultRequest, a as InteractionPolicy, c as LlmClient, d as LlmResponse, f as LlmStreamEvent, o as InteractionRequest, s as InteractionResponse, v as UiBridge, x as FileStat } from "./types-CgNC-oQu-DCklnS0h.js";
2
+ import { K as ScriptExecutionContext, Y as ToolDefinition, Z as ToolResult, _ as ExternalToolSource, _t as parseBridgeRequest, c as ApprovalScope, d as BridgeRequest, f as BridgeResponse, g as ExternalSkillProvider, k as NetworkPolicy, l as BridgeCapabilities, ot as bridgeError, q as ScriptExecutor, rt as WebSkillApi } from "./index-S8uza3ld.js";
2
3
  //#region ../browser/dist/index.d.ts
3
4
  //#region src/fs/featureDetection.d.ts
4
5
  /** 检测当前环境是否可用 OPFS(navigator.storage.getDirectory) */
@@ -74,6 +75,7 @@ declare class TsTranspiler {
74
75
  * D5:浏览器技能安装(http(s) zip / ArrayBuffer;tar/git/npm → TOOL_UNSUPPORTED)。
75
76
  * 流程与 Node 对齐:staging → 解析 name → validateSkills(失败零残留)→ managed root →
76
77
  * manifest(WebCrypto sha256)→ skills.lock.json;zip-slip 防护;manifest/lockfile 与 Node 同格式。
78
+ * @stable
77
79
  */
78
80
  declare class BrowserSkillManager {
79
81
  #private;
@@ -119,6 +121,7 @@ type WorkerFactory = () => WorkerLike;
119
121
  /**
120
122
  * Web Worker 脚本沙箱执行器:loadDefinition 与 execute 都在 Worker 内完成,
121
123
  * 主线程从不 import 技能脚本;每次执行独立 Worker;超时 terminate 强杀。
124
+ * @stable
122
125
  */
123
126
  declare class BrowserWorkerScriptExecutor implements ScriptExecutor {
124
127
  #private;
@@ -157,6 +160,7 @@ declare global {
157
160
  * BrowserSkillManager → createWebSkillApi;target 提供时挂 target.navigator
158
161
  * (缺失则补空对象),否则挂真实 navigator.webskill。
159
162
  * target 可注入(测试);返回值即门面本体(挂载只是副作用)。
163
+ * @stable
160
164
  */
161
165
  declare function installWebSkillNavigator(config: {
162
166
  roots?: string[];
package/dist/browser.js CHANGED
@@ -1,4 +1,6 @@
1
- import { D as createWebSkillApi, F as parseBridgeRequest, G as SKILL_PACK_FILE, H as SKILL_MANIFEST_FILE, J as WebSkillError, K as SkillDiscovery, M as mergeCatalogEntries, N as networkUrlHost, P as normalizeToolContent, V as SKILLS_LOCKFILE, X as buildManifest, Y as buildCatalog, _ as ProgressiveRouter, a as CapabilityApproval, at as parseSkillMarkdown, c as FsMemoryStore, dt as verifyManifest, g as OpenAiCompatibleClient, i as AgentLoop, j as isNetworkAllowed, l as FsRunSnapshotStore, lt as resolveInsideRoot, m as MockLlmClient, nt as isValidSkillName, ot as parseSkillPackManifest, s as FsArtifactStore, tt as exportSkills, ut as validateSkills, w as bridgeError, x as RUN_SNAPSHOT_SCHEMA_VERSION } from "./dist-nXiR40hi.js";
1
+ import { D as verifyManifest, E as validateSkills, S as parseSkillPackManifest, T as resolveInsideRoot, _ as exportSkills, c as SkillDiscovery, d as buildCatalog, f as buildManifest, i as SKILL_MANIFEST_FILE, r as SKILLS_LOCKFILE, s as SKILL_PACK_FILE, u as WebSkillError, v as isValidSkillName, x as parseSkillMarkdown } from "./memoryArtifactStore-C9lFVqPF-U8nXvqL9.js";
2
+ import { A as normalizeToolContent, C as createWebSkillApi, D as isNetworkAllowed, O as mergeCatalogEntries, _ as RUN_SNAPSHOT_SCHEMA_VERSION, a as CapabilityApproval, b as bridgeError, c as FsMemoryStore, f as OpenAiCompatibleClient, i as AgentLoop, j as parseBridgeRequest, k as networkUrlHost, l as FsRunSnapshotStore, p as ProgressiveRouter, s as FsArtifactStore } from "./dist-CiYRkm71.js";
3
+ import { n as MockLlmClient } from "./testing-pn3NhXSV.js";
2
4
  import { unzipSync } from "fflate";
3
5
 
4
6
  //#region ../browser/dist/index.js
@@ -442,6 +444,7 @@ const lockfilePath = (root) => `${root}/${SKILLS_LOCKFILE}`;
442
444
  * D5:浏览器技能安装(http(s) zip / ArrayBuffer;tar/git/npm → TOOL_UNSUPPORTED)。
443
445
  * 流程与 Node 对齐:staging → 解析 name → validateSkills(失败零残留)→ managed root →
444
446
  * manifest(WebCrypto sha256)→ skills.lock.json;zip-slip 防护;manifest/lockfile 与 Node 同格式。
447
+ * @stable
445
448
  */
446
449
  var BrowserSkillManager = class {
447
450
  #fs;
@@ -685,6 +688,7 @@ const messageOf = (e) => e instanceof Error ? e.message : String(e);
685
688
  /**
686
689
  * Web Worker 脚本沙箱执行器:loadDefinition 与 execute 都在 Worker 内完成,
687
690
  * 主线程从不 import 技能脚本;每次执行独立 Worker;超时 terminate 强杀。
691
+ * @stable
688
692
  */
689
693
  var BrowserWorkerScriptExecutor = class {
690
694
  #fs;
@@ -910,6 +914,7 @@ var BrowserWorkerScriptExecutor = class {
910
914
  * BrowserSkillManager → createWebSkillApi;target 提供时挂 target.navigator
911
915
  * (缺失则补空对象),否则挂真实 navigator.webskill。
912
916
  * target 可注入(测试);返回值即门面本体(挂载只是副作用)。
917
+ * @stable
913
918
  */
914
919
  function installWebSkillNavigator(config) {
915
920
  const roots = config.roots ?? ["/skills"];
@@ -1132,7 +1137,7 @@ function startWorkerRuntimeHost(scope, overrides = {}) {
1132
1137
  return [];
1133
1138
  }
1134
1139
  }))).flat();
1135
- const catalog = providerEntries.length > 0 ? { skills: mergeCatalogEntries(buildCatalog(entries).skills, providerEntries) } : buildCatalog(entries);
1140
+ const catalog = providerEntries.length > 0 ? { entries: mergeCatalogEntries(buildCatalog(entries).entries, providerEntries) } : buildCatalog(entries);
1136
1141
  const route = await new ProgressiveRouter().route(catalog);
1137
1142
  const uiBridge = new WorkerUiBridge(scope);
1138
1143
  activeUiBridge = uiBridge;