@webskill/sdk 0.0.1
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/LICENSE +21 -0
- package/README.md +85 -0
- package/dist/browser.d.ts +219 -0
- package/dist/browser.js +856 -0
- package/dist/dist-9fczg9Pa.js +1122 -0
- package/dist/dist-B_ldNWwT.js +1975 -0
- package/dist/dist-RcqvzAGF.js +15382 -0
- package/dist/governance.d.ts +440 -0
- package/dist/governance.js +844 -0
- package/dist/index-88KNOnbr.d.ts +955 -0
- package/dist/index-Bq-bTWh3.d.ts +219 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +3 -0
- package/dist/mcp.d.ts +237 -0
- package/dist/mcp.js +513 -0
- package/dist/node.d.ts +3 -0
- package/dist/node.js +4 -0
- package/dist/ui-react.d.ts +40 -0
- package/dist/ui-react.js +239 -0
- package/dist/ui-vue.d.ts +72 -0
- package/dist/ui-vue.js +196 -0
- package/dist/ui.d.ts +171 -0
- package/dist/ui.js +4 -0
- package/package.json +91 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Chunhui Mo
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# @webskill/sdk
|
|
2
|
+
|
|
3
|
+
WebSkill is an agent skill runtime for Node.js and the browser. Skills are
|
|
4
|
+
self-contained directories (`SKILL.md` + `scripts/` + `references/` + `assets/`)
|
|
5
|
+
that an LLM agent discovers, reads, and executes through a multi-turn agent loop
|
|
6
|
+
with human-in-the-loop interaction, artifacts, tracing, MCP integration, and
|
|
7
|
+
governance.
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- **Skill protocol** — Agent Skills compatible discovery, validation, cataloging
|
|
12
|
+
(JSON / XML), and safe per-skill file access.
|
|
13
|
+
- **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.
|
|
20
|
+
- **MCP** — call page-provided tools and consume page-declared dynamic skills
|
|
21
|
+
over standard MCP transports (MessageChannel).
|
|
22
|
+
- **Governance** — LLM-generated skill candidates with mandatory review,
|
|
23
|
+
approval workflows, audit log, versioning/rollback, quarantine, evaluation,
|
|
24
|
+
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
|
+
|
|
29
|
+
## Installation
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
npm install @webskill/sdk
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
React/Vue integrations require their respective peer dependencies
|
|
36
|
+
(`react` + `react-dom`, or `vue`), which are optional.
|
|
37
|
+
|
|
38
|
+
## Quick start (Node)
|
|
39
|
+
|
|
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
|
+
});
|
|
55
|
+
|
|
56
|
+
// Discover skills and render the catalog
|
|
57
|
+
const { entries, issues } = await runtime.discover();
|
|
58
|
+
console.log(entries.map((e) => e.name), issues);
|
|
59
|
+
|
|
60
|
+
// Run the agent loop
|
|
61
|
+
const { output, run } = await runtime.run('Use the calculator skill to compute 2+3.');
|
|
62
|
+
console.log(output, run.status, run.trace.length);
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Subpath exports
|
|
66
|
+
|
|
67
|
+
| Subpath | Contents |
|
|
68
|
+
| --- | --- |
|
|
69
|
+
| `@webskill/sdk` | Core protocol + runtime engine (discovery, agent loop, LLM clients, routing, interaction, memory, artifacts, trace) |
|
|
70
|
+
| `@webskill/sdk/node` | Node host: NodeFS, script executors (in-process + sandboxed), file stores, skill manager, CLI UI bridge, env helpers |
|
|
71
|
+
| `@webskill/sdk/browser` | Browser host: OPFS provider, Web Worker script sandbox, worker runtime host/client |
|
|
72
|
+
| `@webskill/sdk/mcp` | MCP transports, endpoint registry, tool resolver, temporary skills, WebMCP adapter, runtime plugin |
|
|
73
|
+
| `@webskill/sdk/ui` | Framework-agnostic forms, result rendering, mini markdown, Vercel/OpenUI/A2UI adapters, A2UI Lit runtime |
|
|
74
|
+
| `@webskill/sdk/ui-react` | React bridge state + InteractionForm/ResultBlocks/StreamingText components |
|
|
75
|
+
| `@webskill/sdk/ui-vue` | Vue bridge state + equivalent components |
|
|
76
|
+
| `@webskill/sdk/governance` | Candidates, approval, audit, versioning, state policy, evaluation, scoring, documents |
|
|
77
|
+
|
|
78
|
+
## Requirements
|
|
79
|
+
|
|
80
|
+
- Node.js >= 22.18 (native type stripping for `.ts` skill scripts)
|
|
81
|
+
- Modern browsers for the browser host (OPFS, Web Workers, ES modules)
|
|
82
|
+
|
|
83
|
+
## License
|
|
84
|
+
|
|
85
|
+
MIT
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import { C as InteractionRequest, M as LlmResponse, Mt as FileSystemProvider, N as LlmStreamEvent, S as InteractionPolicy, X as RenderResultRequest, _t as bridgeError, ct as ToolResult, d as BridgeResponse, it as ScriptExecutor, jt as FileStat, k as LlmClient, l as BridgeCapabilities, m as ExternalToolSource, ot as ToolDefinition, p as ExternalSkillProvider, pt as UiBridge, rt as ScriptExecutionContext, u as BridgeRequest, w as InteractionResponse, wt as parseBridgeRequest } from "./index-88KNOnbr.js";
|
|
2
|
+
//#region ../browser/dist/index.d.ts
|
|
3
|
+
//#region src/fs/featureDetection.d.ts
|
|
4
|
+
/** 检测当前环境是否可用 OPFS(navigator.storage.getDirectory) */
|
|
5
|
+
declare function isOpfsAvailable(globalScope?: unknown): boolean;
|
|
6
|
+
//#endregion
|
|
7
|
+
//#region src/fs/opfsProvider.d.ts
|
|
8
|
+
/** 基于 navigator.storage.getDirectory() 的 FileSystemProvider(路径一律 POSIX 风格) */
|
|
9
|
+
declare class OpfsProvider implements FileSystemProvider {
|
|
10
|
+
#private;
|
|
11
|
+
readonly kind = "opfs";
|
|
12
|
+
constructor(deps?: {
|
|
13
|
+
rootName?: string;
|
|
14
|
+
});
|
|
15
|
+
readText(p: string): Promise<string>;
|
|
16
|
+
writeText(p: string, content: string): Promise<void>;
|
|
17
|
+
readBinary(p: string): Promise<Uint8Array>;
|
|
18
|
+
writeBinary(p: string, content: Uint8Array): Promise<void>;
|
|
19
|
+
exists(p: string): Promise<boolean>;
|
|
20
|
+
stat(p: string): Promise<FileStat>;
|
|
21
|
+
list(p: string): Promise<FileStat[]>;
|
|
22
|
+
mkdir(p: string): Promise<void>;
|
|
23
|
+
remove(p: string, options?: {
|
|
24
|
+
recursive?: boolean;
|
|
25
|
+
}): Promise<void>;
|
|
26
|
+
}
|
|
27
|
+
//#endregion
|
|
28
|
+
//#region src/executor/workerBootstrap.d.ts
|
|
29
|
+
/**
|
|
30
|
+
* Worker 引导源码(字符串 → Blob URL → new Worker(url, {type:'module'}))。
|
|
31
|
+
* 注意:内容为纯 JS,不能含反引号与 ${ 占位(外层用模板字符串内嵌)。
|
|
32
|
+
*
|
|
33
|
+
* 协议(宿主 ↔ Worker):
|
|
34
|
+
* - 宿主 → Worker:{type:'load', id, source} 请求加载脚本定义
|
|
35
|
+
* - 宿主 → Worker:{type:'execute', id, skillName, runId, source, args} 请求执行
|
|
36
|
+
* - Worker → 宿主:{type:'load-result', id, ok, definition?, error?}
|
|
37
|
+
* - Worker → 宿主:{type:'execute-result', id, ok, value?, stdout, stderr, error?}
|
|
38
|
+
* - Worker → 宿主:{type:'bridge', request} 能力桥 RPC(readReference/writeArtifact/confirm)
|
|
39
|
+
* - 宿主 → Worker:{type:'bridge-response', response}
|
|
40
|
+
*
|
|
41
|
+
* .js 源码经 data: URL 动态 import;主线程从不 import 技能脚本。
|
|
42
|
+
*/
|
|
43
|
+
declare const WORKER_BOOTSTRAP_SOURCE: string;
|
|
44
|
+
//#endregion
|
|
45
|
+
//#region src/executor/workerScriptExecutor.d.ts
|
|
46
|
+
/** 主线程持有的 Worker 最小接口(vitest 可用 loopback 替身) */
|
|
47
|
+
interface WorkerLike {
|
|
48
|
+
postMessage(data: unknown): void;
|
|
49
|
+
addEventListener(type: 'message', listener: (event: {
|
|
50
|
+
data: unknown;
|
|
51
|
+
}) => void): void;
|
|
52
|
+
terminate(): void;
|
|
53
|
+
}
|
|
54
|
+
type WorkerFactory = () => WorkerLike;
|
|
55
|
+
/**
|
|
56
|
+
* Web Worker 脚本沙箱执行器:loadDefinition 与 execute 都在 Worker 内完成,
|
|
57
|
+
* 主线程从不 import 技能脚本;每次执行独立 Worker;超时 terminate 强杀。
|
|
58
|
+
*/
|
|
59
|
+
declare class BrowserWorkerScriptExecutor implements ScriptExecutor {
|
|
60
|
+
#private;
|
|
61
|
+
constructor(deps: {
|
|
62
|
+
fs: FileSystemProvider;
|
|
63
|
+
workerFactory?: WorkerFactory;
|
|
64
|
+
capabilities?: BridgeCapabilities;
|
|
65
|
+
});
|
|
66
|
+
loadDefinition(skillRoot: string, scriptName: string): Promise<ToolDefinition>;
|
|
67
|
+
execute(input: {
|
|
68
|
+
skillRoot: string;
|
|
69
|
+
scriptName: string;
|
|
70
|
+
args: Record<string, unknown>;
|
|
71
|
+
context: ScriptExecutionContext;
|
|
72
|
+
timeoutMs: number;
|
|
73
|
+
}): Promise<ToolResult>;
|
|
74
|
+
}
|
|
75
|
+
//#endregion
|
|
76
|
+
//#region src/host/protocol.d.ts
|
|
77
|
+
/** 主线程 → Worker 的 LLM 配置;mockResponses 供 E2E/测试注入确定性 Mock */
|
|
78
|
+
interface LlmClientConfig {
|
|
79
|
+
baseUrl?: string;
|
|
80
|
+
apiKey?: string;
|
|
81
|
+
model?: string;
|
|
82
|
+
mockResponses?: Array<LlmResponse | {
|
|
83
|
+
stream: LlmStreamEvent[];
|
|
84
|
+
}>;
|
|
85
|
+
/** Mock 流式开关(E2E 流式场景) */
|
|
86
|
+
mockStreaming?: boolean;
|
|
87
|
+
}
|
|
88
|
+
type WorkerRequest = {
|
|
89
|
+
type: 'init';
|
|
90
|
+
id: string;
|
|
91
|
+
config: {
|
|
92
|
+
llm: LlmClientConfig;
|
|
93
|
+
interaction?: InteractionPolicy;
|
|
94
|
+
roots?: string[];
|
|
95
|
+
/** OPFS 根目录名(默认 'webskill');测试隔离用 */
|
|
96
|
+
opfsRootName?: string;
|
|
97
|
+
};
|
|
98
|
+
} | {
|
|
99
|
+
type: 'run';
|
|
100
|
+
id: string;
|
|
101
|
+
prompt: string;
|
|
102
|
+
runId?: string;
|
|
103
|
+
} | {
|
|
104
|
+
type: 'cancel';
|
|
105
|
+
id: string;
|
|
106
|
+
runId: string;
|
|
107
|
+
} | {
|
|
108
|
+
type: 'status';
|
|
109
|
+
id: string;
|
|
110
|
+
runId: string;
|
|
111
|
+
};
|
|
112
|
+
/** 主线程 → Worker 的交互应答 */
|
|
113
|
+
interface InteractionResponseMessage {
|
|
114
|
+
type: 'interaction-response';
|
|
115
|
+
workerMessageId: string;
|
|
116
|
+
response: InteractionResponse;
|
|
117
|
+
}
|
|
118
|
+
type MainToWorkerMessage = WorkerRequest | InteractionResponseMessage;
|
|
119
|
+
interface SerializedError {
|
|
120
|
+
code: string;
|
|
121
|
+
message: string;
|
|
122
|
+
}
|
|
123
|
+
/** Worker → 主线程 */
|
|
124
|
+
type WorkerEvent = {
|
|
125
|
+
type: 'ready';
|
|
126
|
+
id: string;
|
|
127
|
+
} | {
|
|
128
|
+
type: 'result';
|
|
129
|
+
id: string;
|
|
130
|
+
result?: unknown;
|
|
131
|
+
error?: SerializedError;
|
|
132
|
+
} | {
|
|
133
|
+
type: 'interaction';
|
|
134
|
+
id: string;
|
|
135
|
+
workerMessageId: string;
|
|
136
|
+
request: InteractionRequest;
|
|
137
|
+
} | {
|
|
138
|
+
type: 'render-result';
|
|
139
|
+
request: RenderResultRequest;
|
|
140
|
+
} | {
|
|
141
|
+
type: 'text-delta';
|
|
142
|
+
runId: string;
|
|
143
|
+
delta: string;
|
|
144
|
+
};
|
|
145
|
+
/** Worker 内全局作用域最小接口(postMessage + 消息监听) */
|
|
146
|
+
interface WorkerScopeLike {
|
|
147
|
+
postMessage(data: unknown): void;
|
|
148
|
+
addEventListener(type: 'message', listener: (event: {
|
|
149
|
+
data: unknown;
|
|
150
|
+
}) => void): void;
|
|
151
|
+
}
|
|
152
|
+
/** Worker 侧入站校验:非法消息返回 undefined(忽略) */
|
|
153
|
+
declare function parseMainMessage(data: unknown): MainToWorkerMessage | undefined;
|
|
154
|
+
/** 主线程侧入站校验 */
|
|
155
|
+
declare function parseWorkerEvent(data: unknown): WorkerEvent | undefined;
|
|
156
|
+
//#endregion
|
|
157
|
+
//#region src/host/workerRuntimeHost.d.ts
|
|
158
|
+
interface WorkerRuntimeHostOverrides {
|
|
159
|
+
/** 测试注入(loopback 用 MemoryFS);缺省 OpfsProvider */
|
|
160
|
+
fs?: FileSystemProvider;
|
|
161
|
+
/** 测试注入确定性 LLM;缺省按 config 构造 OpenAiCompatibleClient/MockLlmClient */
|
|
162
|
+
createLlm?: (config: LlmClientConfig) => LlmClient;
|
|
163
|
+
/** 脚本沙箱 Worker 工厂(测试可注入 loopback 替身) */
|
|
164
|
+
workerFactory?: WorkerFactory;
|
|
165
|
+
/** 外部工具来源(MCP 插件等) */
|
|
166
|
+
externalTools?: ExternalToolSource[];
|
|
167
|
+
/** 外部技能提供者(页面动态技能等) */
|
|
168
|
+
skillProviders?: ExternalSkillProvider[];
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Worker 内宿主(engine-in-worker):
|
|
172
|
+
* 组合 fs + FsArtifactStore/FsMemoryStore + LlmClient + AgentLoop + 沙箱执行器;
|
|
173
|
+
* UiBridge 经 interaction/interaction-response 消息桥接主线程。
|
|
174
|
+
*/
|
|
175
|
+
declare function startWorkerRuntimeHost(scope: WorkerScopeLike, overrides?: WorkerRuntimeHostOverrides): void;
|
|
176
|
+
//#endregion
|
|
177
|
+
//#region src/host/workerClient.d.ts
|
|
178
|
+
interface WorkerRuntimeClientDeps {
|
|
179
|
+
worker: WorkerLike;
|
|
180
|
+
/** 主线程真实 UiBridge:Worker 内 interaction 消息转发到这里 */
|
|
181
|
+
uiBridge?: UiBridge;
|
|
182
|
+
/** 单次请求超时(默认 120_000ms);超时返回结构化 error 响应(不 reject) */
|
|
183
|
+
timeoutMs?: number;
|
|
184
|
+
}
|
|
185
|
+
/** 主线程客户端:init/run/cancel/status/dispose 的 Promise API + 交互转发 */
|
|
186
|
+
declare class WorkerRuntimeClient {
|
|
187
|
+
#private;
|
|
188
|
+
constructor(deps: WorkerRuntimeClientDeps);
|
|
189
|
+
init(config: {
|
|
190
|
+
llm: LlmClientConfig;
|
|
191
|
+
interaction?: InteractionPolicy;
|
|
192
|
+
roots?: string[];
|
|
193
|
+
opfsRootName?: string;
|
|
194
|
+
}): Promise<WorkerEvent>;
|
|
195
|
+
run(prompt: string, runId?: string): Promise<WorkerEvent>;
|
|
196
|
+
status(runId: string): Promise<WorkerEvent>;
|
|
197
|
+
cancel(runId: string): Promise<WorkerEvent>;
|
|
198
|
+
dispose(): void;
|
|
199
|
+
}
|
|
200
|
+
//#endregion
|
|
201
|
+
//#region src/ui/workerUiBridge.d.ts
|
|
202
|
+
/**
|
|
203
|
+
* Worker 内 UiBridge:request → 'interaction' 消息到主线程,
|
|
204
|
+
* 挂起等待 'interaction-response' → resolve(行内 await 跨线程成立)。
|
|
205
|
+
* renderResult 为单向通知('render-result' 消息,主线程页面桥消费)。
|
|
206
|
+
*/
|
|
207
|
+
declare class WorkerUiBridge implements UiBridge {
|
|
208
|
+
#private;
|
|
209
|
+
constructor(scope: WorkerScopeLike);
|
|
210
|
+
/** 宿主转发主线程的 interaction-response */
|
|
211
|
+
handleInteractionResponse(workerMessageId: string, response: InteractionResponse): void;
|
|
212
|
+
/** 取消全部挂起请求(cancel 语义:视为用户取消) */
|
|
213
|
+
cancelAll(): void;
|
|
214
|
+
request(input: InteractionRequest): Promise<InteractionResponse>;
|
|
215
|
+
renderResult(input: RenderResultRequest): Promise<void>;
|
|
216
|
+
onTextDelta(runId: string, delta: string): Promise<void>;
|
|
217
|
+
}
|
|
218
|
+
//#endregion
|
|
219
|
+
export { type BridgeCapabilities, type BridgeRequest, type BridgeResponse, BrowserWorkerScriptExecutor, type LlmClientConfig, type MainToWorkerMessage, OpfsProvider, type SerializedError, WORKER_BOOTSTRAP_SOURCE, type WorkerEvent, type WorkerFactory, type WorkerLike, type WorkerRequest, WorkerRuntimeClient, type WorkerRuntimeClientDeps, type WorkerRuntimeHostOverrides, type WorkerScopeLike, WorkerUiBridge, bridgeError, isOpfsAvailable, parseBridgeRequest, parseMainMessage, parseWorkerEvent, startWorkerRuntimeHost };
|