@webskill/sdk 0.2.0 → 0.2.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/README.md +16 -10
- package/dist/browser.d.ts +35 -2
- package/dist/browser.js +97 -4
- package/dist/{dist-Dj6QjHBn.js → dist-BRGQcLqR.js} +355 -33
- package/dist/{dist-BS5OpedX.js → dist-DrySSQ5R.js} +4 -0
- package/dist/governance.d.ts +13 -3
- package/dist/governance.js +14 -2
- package/dist/{index-Vn63HJRO.d.ts → index-BmzysJX5.d.ts} +39 -2
- package/dist/{index-CySxIvRz.d.ts → index-gjFuBevI.d.ts} +2 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/mcp.d.ts +1 -1
- package/dist/mcp.js +1 -1
- package/dist/node.d.ts +3 -3
- package/dist/node.js +3 -3
- package/dist/processSandboxEntry.d.ts +1 -0
- package/dist/processSandboxEntry.js +202 -0
- package/dist/ui.d.ts +1 -1
- package/dist/ui.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -15,12 +15,16 @@ governance.
|
|
|
15
15
|
the LLM, guardrails, lifecycle events, memory, human interaction
|
|
16
16
|
(missing-parameter forms, confirmations, authorization prompts), and
|
|
17
17
|
resumable interrupted runs.
|
|
18
|
-
- **Script sandbox** —
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
18
|
+
- **Script sandbox** — two tiers. Isolation-grade: Node `ProcessSandboxExecutor`
|
|
19
|
+
(`child_process.fork` + `--permission`, experimental; fs scoped to the skill
|
|
20
|
+
root, workers/child processes/addons denied by default — note the permission
|
|
21
|
+
model has NO network dimension, so `fetch`/`WebSocket` stay patch-enforced and
|
|
22
|
+
bare `node:net` imports remain a documented residual), and the browser opaque
|
|
23
|
+
origin sandbox (`sandbox="allow-scripts"` iframe hosting a classic Worker —
|
|
24
|
+
`type:"module"` workers cannot load in opaque origins, verified). Capability
|
|
25
|
+
tier (NOT a security boundary): `SandboxedScriptExecutor` /
|
|
26
|
+
`BrowserWorkerScriptExecutor` in blob-Worker mode, with deny-by-default
|
|
27
|
+
network policy, builtin-module allowlist, forced approval, timeouts.
|
|
24
28
|
- **`navigator.webskill`** — a browser facade (`discover` / `read` / `validate` /
|
|
25
29
|
`run` / `install` / `uninstall`) assembled explicitly in one call.
|
|
26
30
|
- **MCP** — call page-provided tools and consume page-declared dynamic skills
|
|
@@ -102,7 +106,8 @@ const run = await api.run('Summarize the references of skill greeter.');
|
|
|
102
106
|
|
|
103
107
|
### `@webskill/sdk/node`
|
|
104
108
|
|
|
105
|
-
Node host: `NodeFS`, script executors (in-process
|
|
109
|
+
Node host: `NodeFS`, script executors (in-process, `worker_threads` sandbox, and
|
|
110
|
+
`ProcessSandboxExecutor` for real process isolation),
|
|
106
111
|
file-backed stores, `SkillManager` (install/export incl. multi-skill packs),
|
|
107
112
|
CLI UI bridge, schema inference.
|
|
108
113
|
|
|
@@ -117,9 +122,10 @@ console.log((await manager.verifyIntegrity('greeter')).ok);
|
|
|
117
122
|
|
|
118
123
|
### `@webskill/sdk/browser`
|
|
119
124
|
|
|
120
|
-
Browser host: OPFS provider,
|
|
121
|
-
|
|
122
|
-
|
|
125
|
+
Browser host: OPFS provider, opaque origin iframe script sandbox (default on
|
|
126
|
+
the main thread; engines running inside a Worker automatically fall back to the
|
|
127
|
+
blob Worker form — no iframe is available there, documented), worker runtime
|
|
128
|
+
host/client, `BrowserSkillManager`, and the `navigator.webskill` assembler. See
|
|
123
129
|
[`examples/quickstart-browser`](../examples/quickstart-browser).
|
|
124
130
|
|
|
125
131
|
```js
|
package/dist/browser.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { C as FileStat, I as SkillInstallSource, K as VerifyResult, W as SkillsLockfile, _ as RenderResultRequest, a as InteractionPolicy, c as LlmClient, d as LlmResponse, f as LlmStreamEvent, o as InteractionRequest, s as InteractionResponse, v as UiBridge, w as FileSystemProvider, y as ArchiveLimits, z as SkillManifest } from "./types-CKm5G_eQ-8W8FnP4u.js";
|
|
2
|
-
import { N as NetworkPolicy, Q as ScriptExecutor, Z as ScriptExecutionContext, d as BridgeCapabilities, it as ToolResult, m as BridgeResponse, nt as ToolDefinition, p as BridgeRequest, pt as bridgeError, u as ApprovalScope, ut as WebSkillApi, v as ExternalSkillProvider, wt as parseBridgeRequest, y as ExternalToolSource } from "./index-
|
|
2
|
+
import { N as NetworkPolicy, Q as ScriptExecutor, Z as ScriptExecutionContext, d as BridgeCapabilities, it as ToolResult, m as BridgeResponse, nt as ToolDefinition, p as BridgeRequest, pt as bridgeError, u as ApprovalScope, ut as WebSkillApi, v as ExternalSkillProvider, wt as parseBridgeRequest, y as ExternalToolSource } from "./index-gjFuBevI.js";
|
|
3
3
|
//#region ../browser/dist/index.d.ts
|
|
4
4
|
//#region src/fs/featureDetection.d.ts
|
|
5
5
|
/** 检测当前环境是否可用 OPFS(navigator.storage.getDirectory) */
|
|
@@ -123,6 +123,8 @@ interface WorkerLike {
|
|
|
123
123
|
terminate(): void;
|
|
124
124
|
}
|
|
125
125
|
type WorkerFactory = () => WorkerLike;
|
|
126
|
+
/** 沙箱形态:opaque iframe(默认,主线程可用 document 时)/ blob Worker(Worker 内引擎回退) */
|
|
127
|
+
type SandboxMode = 'iframe' | 'worker' | 'auto';
|
|
126
128
|
/**
|
|
127
129
|
* Web Worker 脚本沙箱执行器:loadDefinition 与 execute 都在 Worker 内完成,
|
|
128
130
|
* 主线程从不 import 技能脚本;每次执行独立 Worker;超时 terminate 强杀。
|
|
@@ -133,6 +135,12 @@ declare class BrowserWorkerScriptExecutor implements ScriptExecutor {
|
|
|
133
135
|
constructor(deps: {
|
|
134
136
|
fs: FileSystemProvider;
|
|
135
137
|
workerFactory?: WorkerFactory;
|
|
138
|
+
/**
|
|
139
|
+
* 沙箱形态:'auto'(默认)——主线程用 opaque origin iframe(sandbox=allow-scripts srcdoc,
|
|
140
|
+
* 真实隔离);Worker 内引擎自动回退 blob Worker(无 iframe 可用,文档明示)。
|
|
141
|
+
* 显式 'worker' 强制 blob Worker(0.1.x 旧形态)。
|
|
142
|
+
*/
|
|
143
|
+
sandbox?: SandboxMode;
|
|
136
144
|
capabilities?: BridgeCapabilities;
|
|
137
145
|
/** 网络策略:默认 'deny-all'(白名单见 runtime/sandbox/networkPolicy) */
|
|
138
146
|
networkPolicy?: NetworkPolicy;
|
|
@@ -153,6 +161,31 @@ declare class BrowserWorkerScriptExecutor implements ScriptExecutor {
|
|
|
153
161
|
}): Promise<ToolResult>;
|
|
154
162
|
}
|
|
155
163
|
//#endregion
|
|
164
|
+
//#region src/executor/iframeSandbox.d.ts
|
|
165
|
+
/**
|
|
166
|
+
* opaque origin 沙箱 iframe(sandbox="allow-scripts" srcdoc):
|
|
167
|
+
* iframe 内建 module Worker(Blob URL),iframe window 作 postMessage 中继。
|
|
168
|
+
* opaque origin:沙箱内摸不到页面 DOM/localStorage/OPFS(独立 storage 分区)。
|
|
169
|
+
* 就绪握手:iframe 加载完成发 sandbox-ready 后才放行出站消息(防丢失)。
|
|
170
|
+
*/
|
|
171
|
+
declare class IframeWorkerLike implements WorkerLike {
|
|
172
|
+
#private;
|
|
173
|
+
constructor(iframe: HTMLIFrameElement);
|
|
174
|
+
get ready(): boolean;
|
|
175
|
+
markReady(): void;
|
|
176
|
+
postMessage(data: unknown): void;
|
|
177
|
+
addEventListener(_type: 'message', listener: (event: {
|
|
178
|
+
data: unknown;
|
|
179
|
+
}) => void): void;
|
|
180
|
+
emit(data: unknown): void;
|
|
181
|
+
terminate(): void;
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* 创建 opaque iframe 沙箱 Worker:sandbox="allow-scripts" srcdoc iframe 承载 module Worker。
|
|
185
|
+
* 返回 IframeWorkerLike(协议与 blob Worker 完全一致:load/execute/bridge/network-blocked)。
|
|
186
|
+
*/
|
|
187
|
+
declare function createIframeWorker(bootstrapSource: string, doc?: Document): IframeWorkerLike;
|
|
188
|
+
//#endregion
|
|
156
189
|
//#region src/navigator.d.ts
|
|
157
190
|
declare global {
|
|
158
191
|
/** 0.0.6:installWebSkillNavigator 显式装配后可用(不自动挂全局) */
|
|
@@ -343,4 +376,4 @@ declare class WorkerUiBridge implements UiBridge {
|
|
|
343
376
|
onTextDelta(runId: string, delta: string): Promise<void>;
|
|
344
377
|
}
|
|
345
378
|
//#endregion
|
|
346
|
-
export { type BridgeCapabilities, type BridgeRequest, type BridgeResponse, BrowserSkillManager, BrowserWorkerScriptExecutor, type LlmClientConfig, type MainToWorkerMessage, OpfsProvider, type SerializedError, TsTranspiler, type TypeScriptSupportOptions, WORKER_BOOTSTRAP_SOURCE, type WorkerEvent, type WorkerFactory, type WorkerLike, type WorkerRequest, WorkerRuntimeClient, type WorkerRuntimeClientDeps, type WorkerRuntimeHostOverrides, type WorkerScopeLike, WorkerUiBridge, bridgeError, extractZipWeb, installWebSkillNavigator, isOpfsAvailable, parseBridgeRequest, parseMainMessage, parseWorkerEvent, sha256HexWeb, startWorkerRuntimeHost };
|
|
379
|
+
export { type BridgeCapabilities, type BridgeRequest, type BridgeResponse, BrowserSkillManager, BrowserWorkerScriptExecutor, IframeWorkerLike, type LlmClientConfig, type MainToWorkerMessage, OpfsProvider, type SandboxMode, type SerializedError, TsTranspiler, type TypeScriptSupportOptions, WORKER_BOOTSTRAP_SOURCE, type WorkerEvent, type WorkerFactory, type WorkerLike, type WorkerRequest, WorkerRuntimeClient, type WorkerRuntimeClientDeps, type WorkerRuntimeHostOverrides, type WorkerScopeLike, WorkerUiBridge, bridgeError, createIframeWorker, extractZipWeb, installWebSkillNavigator, isOpfsAvailable, parseBridgeRequest, parseMainMessage, parseWorkerEvent, sha256HexWeb, startWorkerRuntimeHost };
|
package/dist/browser.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { A as unzipWithLimits, C as parseSkillMarkdown, M as verifyManifest, T as readResponseWithLimit, b as isValidSkillName, c as SkillDiscovery, f as atomicWriteText, i as SKILL_MANIFEST_FILE, j as validateSkills, k as resolveInsideRoot, m as buildManifest, p as buildCatalog, r as SKILLS_LOCKFILE, s as SKILL_PACK_FILE, u as WebSkillError, w as parseSkillPackManifest, y as exportSkills } from "./dist-D0saNPi_.js";
|
|
2
|
-
import { A as isNetworkAllowed, C as bridgeError, E as createWebSkillApi, M as networkUrlHost, N as normalizeToolContent, P as parseBridgeRequest, c as FsArtifactStore, h as ProgressiveRouter, i as AgentLoop, j as mergeCatalogEntries, l as FsMemoryStore, m as OpenAiCompatibleClient, o as CapabilityApproval, u as FsRunSnapshotStore, y as RUN_SNAPSHOT_SCHEMA_VERSION } from "./dist-
|
|
2
|
+
import { A as isNetworkAllowed, C as bridgeError, E as createWebSkillApi, M as networkUrlHost, N as normalizeToolContent, P as parseBridgeRequest, c as FsArtifactStore, h as ProgressiveRouter, i as AgentLoop, j as mergeCatalogEntries, l as FsMemoryStore, m as OpenAiCompatibleClient, o as CapabilityApproval, u as FsRunSnapshotStore, y as RUN_SNAPSHOT_SCHEMA_VERSION } from "./dist-DrySSQ5R.js";
|
|
3
3
|
import { n as MockLlmClient } from "./testing-B4pq6JYa.js";
|
|
4
4
|
|
|
5
5
|
//#region ../browser/dist/index.js
|
|
@@ -713,13 +713,106 @@ var BrowserSkillManager = class {
|
|
|
713
713
|
await atomicWriteText(this.#fs, lockfilePath(this.#managedRoot), JSON.stringify(lockfile, null, 2));
|
|
714
714
|
}
|
|
715
715
|
};
|
|
716
|
-
const
|
|
716
|
+
const ENVELOPE = "__webskill_sandbox__";
|
|
717
|
+
/**
|
|
718
|
+
* opaque origin 沙箱 iframe(sandbox="allow-scripts" srcdoc):
|
|
719
|
+
* iframe 内建 module Worker(Blob URL),iframe window 作 postMessage 中继。
|
|
720
|
+
* opaque origin:沙箱内摸不到页面 DOM/localStorage/OPFS(独立 storage 分区)。
|
|
721
|
+
* 就绪握手:iframe 加载完成发 sandbox-ready 后才放行出站消息(防丢失)。
|
|
722
|
+
*/
|
|
723
|
+
var IframeWorkerLike = class {
|
|
724
|
+
#iframe;
|
|
725
|
+
#ready = false;
|
|
726
|
+
#queue = [];
|
|
727
|
+
constructor(iframe) {
|
|
728
|
+
this.#iframe = iframe;
|
|
729
|
+
}
|
|
730
|
+
get ready() {
|
|
731
|
+
return this.#ready;
|
|
732
|
+
}
|
|
733
|
+
markReady() {
|
|
734
|
+
this.#ready = true;
|
|
735
|
+
for (const payload of this.#queue) this.#post(payload);
|
|
736
|
+
this.#queue = [];
|
|
737
|
+
}
|
|
738
|
+
#post(payload) {
|
|
739
|
+
this.#iframe.contentWindow?.postMessage({
|
|
740
|
+
[ENVELOPE]: true,
|
|
741
|
+
payload
|
|
742
|
+
}, "*");
|
|
743
|
+
}
|
|
744
|
+
postMessage(data) {
|
|
745
|
+
if (this.#ready) this.#post(data);
|
|
746
|
+
else this.#queue.push(data);
|
|
747
|
+
}
|
|
748
|
+
addEventListener(_type, listener) {
|
|
749
|
+
this.#listeners.add(listener);
|
|
750
|
+
}
|
|
751
|
+
#listeners = /* @__PURE__ */ new Set();
|
|
752
|
+
emit(data) {
|
|
753
|
+
for (const listener of this.#listeners) listener({ data });
|
|
754
|
+
}
|
|
755
|
+
terminate() {
|
|
756
|
+
this.#iframe.remove();
|
|
757
|
+
}
|
|
758
|
+
};
|
|
759
|
+
/** srcdoc 文档:内嵌 Worker 引导源码 + 双向中继(BOOTSTRAP 经 JSON 字符串注入,防 <\/script> 截断) */
|
|
760
|
+
function sandboxDocument(bootstrapSource) {
|
|
761
|
+
const bootstrapJson = JSON.stringify(bootstrapSource).replace(/<\//g, "<\\/");
|
|
762
|
+
return `<!doctype html>
|
|
763
|
+
<html><head><meta charset="utf-8"></head><body><script>
|
|
764
|
+
const ENVELOPE = ${JSON.stringify(ENVELOPE)};
|
|
765
|
+
const blob = new Blob([${bootstrapJson}], { type: 'text/javascript' });
|
|
766
|
+
const url = URL.createObjectURL(blob);
|
|
767
|
+
// 注意:opaque origin 下 module Worker 无法加载(实证),classic Worker + data: URL 动态导入可用
|
|
768
|
+
const worker = new Worker(url);
|
|
769
|
+
URL.revokeObjectURL(url);
|
|
770
|
+
window.addEventListener('message', (event) => {
|
|
771
|
+
const data = event.data;
|
|
772
|
+
if (data && data[ENVELOPE]) worker.postMessage(data.payload);
|
|
773
|
+
});
|
|
774
|
+
worker.addEventListener('message', (event) => {
|
|
775
|
+
parent.postMessage({ [ENVELOPE]: true, payload: event.data }, '*');
|
|
776
|
+
});
|
|
777
|
+
worker.addEventListener('error', (event) => {
|
|
778
|
+
parent.postMessage({ [ENVELOPE]: true, payload: { type: 'sandbox-worker-error', message: event.message } }, '*');
|
|
779
|
+
});
|
|
780
|
+
parent.postMessage({ [ENVELOPE]: true, payload: { type: 'sandbox-ready' } }, '*');
|
|
781
|
+
<\/script></body></html>`;
|
|
782
|
+
}
|
|
783
|
+
/**
|
|
784
|
+
* 创建 opaque iframe 沙箱 Worker:sandbox="allow-scripts" srcdoc iframe 承载 module Worker。
|
|
785
|
+
* 返回 IframeWorkerLike(协议与 blob Worker 完全一致:load/execute/bridge/network-blocked)。
|
|
786
|
+
*/
|
|
787
|
+
function createIframeWorker(bootstrapSource, doc = document) {
|
|
788
|
+
const iframe = doc.createElement("iframe");
|
|
789
|
+
iframe.setAttribute("sandbox", "allow-scripts");
|
|
790
|
+
iframe.style.display = "none";
|
|
791
|
+
iframe.srcdoc = sandboxDocument(bootstrapSource);
|
|
792
|
+
const worker = new IframeWorkerLike(iframe);
|
|
793
|
+
(doc.defaultView ?? window).addEventListener("message", (event) => {
|
|
794
|
+
const data = event.data;
|
|
795
|
+
if (!data || data[ENVELOPE] !== true) return;
|
|
796
|
+
if (data.payload && data.payload.type === "sandbox-ready") {
|
|
797
|
+
worker.markReady();
|
|
798
|
+
return;
|
|
799
|
+
}
|
|
800
|
+
worker.emit(data.payload);
|
|
801
|
+
});
|
|
802
|
+
doc.body.appendChild(iframe);
|
|
803
|
+
return worker;
|
|
804
|
+
}
|
|
805
|
+
const blobWorkerFactory = () => {
|
|
717
806
|
const blob = new Blob([WORKER_BOOTSTRAP_SOURCE], { type: "text/javascript" });
|
|
718
807
|
const url = URL.createObjectURL(blob);
|
|
719
808
|
const worker = new Worker(url, { type: "module" });
|
|
720
809
|
URL.revokeObjectURL(url);
|
|
721
810
|
return worker;
|
|
722
811
|
};
|
|
812
|
+
const resolveWorkerFactory = (mode) => {
|
|
813
|
+
if (mode === "iframe" || mode === "auto" && typeof document !== "undefined") return () => createIframeWorker(WORKER_BOOTSTRAP_SOURCE);
|
|
814
|
+
return blobWorkerFactory;
|
|
815
|
+
};
|
|
723
816
|
const baseName = (p) => p.split("/").pop() ?? p;
|
|
724
817
|
const messageOf = (e) => e instanceof Error ? e.message : String(e);
|
|
725
818
|
/**
|
|
@@ -736,7 +829,7 @@ var BrowserWorkerScriptExecutor = class {
|
|
|
736
829
|
#transpiler;
|
|
737
830
|
constructor(deps) {
|
|
738
831
|
this.#fs = deps.fs;
|
|
739
|
-
this.#workerFactory = deps.workerFactory ??
|
|
832
|
+
this.#workerFactory = deps.workerFactory ?? resolveWorkerFactory(deps.sandbox ?? "auto");
|
|
740
833
|
this.#transpiler = deps.typescript ? new TsTranspiler({
|
|
741
834
|
fs: deps.fs,
|
|
742
835
|
options: deps.typescript
|
|
@@ -1483,4 +1576,4 @@ var WorkerRuntimeClient = class {
|
|
|
1483
1576
|
};
|
|
1484
1577
|
|
|
1485
1578
|
//#endregion
|
|
1486
|
-
export { BrowserSkillManager, BrowserWorkerScriptExecutor, OpfsProvider, TsTranspiler, WORKER_BOOTSTRAP_SOURCE, WorkerRuntimeClient, WorkerUiBridge, bridgeError, extractZipWeb, installWebSkillNavigator, isOpfsAvailable, parseBridgeRequest, parseMainMessage, parseWorkerEvent, sha256HexWeb, startWorkerRuntimeHost };
|
|
1579
|
+
export { BrowserSkillManager, BrowserWorkerScriptExecutor, IframeWorkerLike, OpfsProvider, TsTranspiler, WORKER_BOOTSTRAP_SOURCE, WorkerRuntimeClient, WorkerUiBridge, bridgeError, createIframeWorker, extractZipWeb, installWebSkillNavigator, isOpfsAvailable, parseBridgeRequest, parseMainMessage, parseWorkerEvent, sha256HexWeb, startWorkerRuntimeHost };
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import { A as unzipWithLimits, C as parseSkillMarkdown, M as verifyManifest, O as resolveArchiveLimits, T as readResponseWithLimit, b as isValidSkillName, f as atomicWriteText, i as SKILL_MANIFEST_FILE, j as validateSkills, k as resolveInsideRoot, m as buildManifest, r as SKILLS_LOCKFILE, s as SKILL_PACK_FILE, u as WebSkillError, w as parseSkillPackManifest, y as exportSkills } from "./dist-D0saNPi_.js";
|
|
2
|
-
import { A as isNetworkAllowed, C as bridgeError, M as networkUrlHost, N as normalizeToolContent, P as parseBridgeRequest, c as FsArtifactStore, l as FsMemoryStore, o as CapabilityApproval } from "./dist-
|
|
2
|
+
import { A as isNetworkAllowed, C as bridgeError, M as networkUrlHost, N as normalizeToolContent, P as parseBridgeRequest, c as FsArtifactStore, l as FsMemoryStore, o as CapabilityApproval } from "./dist-DrySSQ5R.js";
|
|
3
3
|
import { createRequire } from "node:module";
|
|
4
4
|
import { unzipSync, zipSync } from "fflate";
|
|
5
|
-
import { existsSync, promises } from "node:fs";
|
|
5
|
+
import { existsSync, promises, realpathSync } from "node:fs";
|
|
6
6
|
import path from "node:path";
|
|
7
7
|
import { tmpdir } from "node:os";
|
|
8
8
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
9
9
|
import { format, promisify } from "node:util";
|
|
10
10
|
import { Worker } from "node:worker_threads";
|
|
11
|
+
import { mkdtemp, rm } from "node:fs/promises";
|
|
12
|
+
import { execFile, fork } from "node:child_process";
|
|
11
13
|
import { createInterface } from "node:readline/promises";
|
|
12
|
-
import { mkdtemp } from "node:fs/promises";
|
|
13
|
-
import { execFile } from "node:child_process";
|
|
14
14
|
import { createHash } from "node:crypto";
|
|
15
15
|
|
|
16
16
|
//#region ../node/dist/index.js
|
|
17
|
-
const toPlatform$
|
|
17
|
+
const toPlatform$4 = (p) => p.split("/").join(path.sep);
|
|
18
18
|
const toPosix = (p) => p.split(path.sep).join("/");
|
|
19
19
|
const isEnoent = (e) => typeof e === "object" && e !== null && e.code === "ENOENT";
|
|
20
20
|
/** realpath 最近现存祖先并拼回剩余段(写入目标尚不存在时的等价判定) */
|
|
@@ -46,41 +46,41 @@ var NodeFS = class {
|
|
|
46
46
|
/** root 模式:目标 realpath 必须落在 root realpath 前缀内(符号链接逃逸防护) */
|
|
47
47
|
async #assertContained(p) {
|
|
48
48
|
if (!this.#root) return;
|
|
49
|
-
const rootReal = await promises.realpath(toPlatform$
|
|
50
|
-
const targetReal = await realpathNearest(toPlatform$
|
|
49
|
+
const rootReal = await promises.realpath(toPlatform$4(this.#root));
|
|
50
|
+
const targetReal = await realpathNearest(toPlatform$4(p));
|
|
51
51
|
if (targetReal !== rootReal && !targetReal.startsWith(rootReal + path.sep)) throw new WebSkillError("FS_PATH_OUTSIDE_ROOT", `Path escapes root via symbolic link: ${p} (resolves outside ${this.#root})`);
|
|
52
52
|
}
|
|
53
53
|
async readText(p) {
|
|
54
54
|
await this.#assertContained(p);
|
|
55
55
|
try {
|
|
56
|
-
return await promises.readFile(toPlatform$
|
|
56
|
+
return await promises.readFile(toPlatform$4(p), "utf8");
|
|
57
57
|
} catch (e) {
|
|
58
58
|
throw this.#mapError(e, p);
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
61
|
async writeText(p, content) {
|
|
62
62
|
await this.#assertContained(p);
|
|
63
|
-
const target = toPlatform$
|
|
63
|
+
const target = toPlatform$4(p);
|
|
64
64
|
await promises.mkdir(path.dirname(target), { recursive: true });
|
|
65
65
|
await promises.writeFile(target, content, "utf8");
|
|
66
66
|
}
|
|
67
67
|
async readBinary(p) {
|
|
68
68
|
await this.#assertContained(p);
|
|
69
69
|
try {
|
|
70
|
-
return await promises.readFile(toPlatform$
|
|
70
|
+
return await promises.readFile(toPlatform$4(p));
|
|
71
71
|
} catch (e) {
|
|
72
72
|
throw this.#mapError(e, p);
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
75
|
async writeBinary(p, content) {
|
|
76
76
|
await this.#assertContained(p);
|
|
77
|
-
const target = toPlatform$
|
|
77
|
+
const target = toPlatform$4(p);
|
|
78
78
|
await promises.mkdir(path.dirname(target), { recursive: true });
|
|
79
79
|
await promises.writeFile(target, content);
|
|
80
80
|
}
|
|
81
81
|
async exists(p) {
|
|
82
82
|
try {
|
|
83
|
-
await promises.access(toPlatform$
|
|
83
|
+
await promises.access(toPlatform$4(p));
|
|
84
84
|
return true;
|
|
85
85
|
} catch {
|
|
86
86
|
return false;
|
|
@@ -88,7 +88,7 @@ var NodeFS = class {
|
|
|
88
88
|
}
|
|
89
89
|
async stat(p) {
|
|
90
90
|
try {
|
|
91
|
-
const s = await promises.stat(toPlatform$
|
|
91
|
+
const s = await promises.stat(toPlatform$4(p));
|
|
92
92
|
return {
|
|
93
93
|
path: toPosix(p),
|
|
94
94
|
type: s.isDirectory() ? "directory" : "file",
|
|
@@ -102,29 +102,29 @@ var NodeFS = class {
|
|
|
102
102
|
async list(p) {
|
|
103
103
|
let dirents;
|
|
104
104
|
try {
|
|
105
|
-
dirents = await promises.readdir(toPlatform$
|
|
105
|
+
dirents = await promises.readdir(toPlatform$4(p), { withFileTypes: true });
|
|
106
106
|
} catch (e) {
|
|
107
107
|
throw this.#mapError(e, p);
|
|
108
108
|
}
|
|
109
109
|
return dirents.map((d) => ({
|
|
110
|
-
path: toPosix(path.join(toPlatform$
|
|
110
|
+
path: toPosix(path.join(toPlatform$4(p), d.name)),
|
|
111
111
|
type: d.isDirectory() ? "directory" : "file"
|
|
112
112
|
}));
|
|
113
113
|
}
|
|
114
114
|
async mkdir(p) {
|
|
115
|
-
await promises.mkdir(toPlatform$
|
|
115
|
+
await promises.mkdir(toPlatform$4(p), { recursive: true });
|
|
116
116
|
}
|
|
117
117
|
async remove(p, options) {
|
|
118
118
|
try {
|
|
119
|
-
await promises.rm(toPlatform$
|
|
119
|
+
await promises.rm(toPlatform$4(p), { recursive: options?.recursive ?? false });
|
|
120
120
|
} catch (e) {
|
|
121
121
|
throw this.#mapError(e, p);
|
|
122
122
|
}
|
|
123
123
|
}
|
|
124
124
|
async rename(from, to) {
|
|
125
|
-
await promises.mkdir(path.dirname(toPlatform$
|
|
125
|
+
await promises.mkdir(path.dirname(toPlatform$4(to)), { recursive: true });
|
|
126
126
|
try {
|
|
127
|
-
await promises.rename(toPlatform$
|
|
127
|
+
await promises.rename(toPlatform$4(from), toPlatform$4(to));
|
|
128
128
|
} catch (e) {
|
|
129
129
|
throw this.#mapError(e, from);
|
|
130
130
|
}
|
|
@@ -134,7 +134,7 @@ var NodeFS = class {
|
|
|
134
134
|
return e;
|
|
135
135
|
}
|
|
136
136
|
};
|
|
137
|
-
const baseName$
|
|
137
|
+
const baseName$2 = (p) => p.split("/").pop() ?? p;
|
|
138
138
|
/**
|
|
139
139
|
* 进程内脚本执行器。接口按沙箱语义设计(context 无隐式宿主访问),
|
|
140
140
|
* worker_threads 沙箱见 deferred-items D1。
|
|
@@ -173,7 +173,7 @@ var NodeScriptExecutor = class {
|
|
|
173
173
|
}
|
|
174
174
|
async loadDefinition(skillRoot, scriptName) {
|
|
175
175
|
const scriptPath = await this.#locateScript(skillRoot, scriptName);
|
|
176
|
-
const skillName = baseName$
|
|
176
|
+
const skillName = baseName$2(skillRoot);
|
|
177
177
|
let module;
|
|
178
178
|
try {
|
|
179
179
|
module = await this.#loadModule(scriptPath);
|
|
@@ -277,14 +277,14 @@ var NodeScriptExecutor = class {
|
|
|
277
277
|
};
|
|
278
278
|
}
|
|
279
279
|
};
|
|
280
|
-
const baseName = (p) => p.split("/").pop() ?? p;
|
|
281
|
-
const toPlatform$
|
|
282
|
-
const messageOf$
|
|
280
|
+
const baseName$1 = (p) => p.split("/").pop() ?? p;
|
|
281
|
+
const toPlatform$3 = (p) => p.split("/").join(path.sep);
|
|
282
|
+
const messageOf$6 = (e) => e instanceof Error ? e.message : String(e);
|
|
283
283
|
/**
|
|
284
284
|
* 网络策略判定函数源码(注入 Worker;匹配逻辑单一来源在
|
|
285
285
|
* runtime/sandbox/networkPolicy.ts,Worker 线程不走 vitest 别名故注入而非 import)
|
|
286
286
|
*/
|
|
287
|
-
const NETWORK_POLICY_LIB = `${isNetworkAllowed.toString()}\n${networkUrlHost.toString()}`;
|
|
287
|
+
const NETWORK_POLICY_LIB$1 = `${isNetworkAllowed.toString()}\n${networkUrlHost.toString()}`;
|
|
288
288
|
/** Worker 入口文件:src 为同目录 .ts;node dist 为 dist/executor/;sdk dist 为平铺 dist/ */
|
|
289
289
|
function workerEntryPath() {
|
|
290
290
|
const dir = path.dirname(fileURLToPath(import.meta.url));
|
|
@@ -336,10 +336,10 @@ var SandboxedScriptExecutor = class {
|
|
|
336
336
|
}
|
|
337
337
|
async loadDefinition(skillRoot, scriptName) {
|
|
338
338
|
const scriptPath = await this.#locateScript(skillRoot, scriptName);
|
|
339
|
-
const skillName = baseName(skillRoot);
|
|
339
|
+
const skillName = baseName$1(skillRoot);
|
|
340
340
|
const result = await this.#runWorker({
|
|
341
341
|
mode: "load",
|
|
342
|
-
scriptPath: toPlatform$
|
|
342
|
+
scriptPath: toPlatform$3(scriptPath),
|
|
343
343
|
scriptName,
|
|
344
344
|
scriptSource: await this.#fs.readText(scriptPath)
|
|
345
345
|
});
|
|
@@ -363,14 +363,14 @@ var SandboxedScriptExecutor = class {
|
|
|
363
363
|
content: [],
|
|
364
364
|
error: {
|
|
365
365
|
code: e instanceof WebSkillError ? e.code : "TOOL_EXECUTION_FAILED",
|
|
366
|
-
message: messageOf$
|
|
366
|
+
message: messageOf$6(e)
|
|
367
367
|
}
|
|
368
368
|
};
|
|
369
369
|
}
|
|
370
370
|
try {
|
|
371
371
|
const result = await this.#runWorker({
|
|
372
372
|
mode: "execute",
|
|
373
|
-
scriptPath: toPlatform$
|
|
373
|
+
scriptPath: toPlatform$3(scriptPath),
|
|
374
374
|
scriptName,
|
|
375
375
|
skillName: context.skillName,
|
|
376
376
|
runId: context.runId,
|
|
@@ -403,7 +403,7 @@ var SandboxedScriptExecutor = class {
|
|
|
403
403
|
content: [],
|
|
404
404
|
error: {
|
|
405
405
|
code: e instanceof WebSkillError ? e.code : "TOOL_EXECUTION_FAILED",
|
|
406
|
-
message: messageOf$
|
|
406
|
+
message: messageOf$6(e)
|
|
407
407
|
}
|
|
408
408
|
};
|
|
409
409
|
}
|
|
@@ -417,7 +417,7 @@ var SandboxedScriptExecutor = class {
|
|
|
417
417
|
workerData: {
|
|
418
418
|
...workerData,
|
|
419
419
|
networkPolicy: this.#networkPolicy,
|
|
420
|
-
networkPolicyLib: NETWORK_POLICY_LIB,
|
|
420
|
+
networkPolicyLib: NETWORK_POLICY_LIB$1,
|
|
421
421
|
allowedModules: this.#options.allowedModules ?? []
|
|
422
422
|
},
|
|
423
423
|
env,
|
|
@@ -454,7 +454,7 @@ var SandboxedScriptExecutor = class {
|
|
|
454
454
|
respond(bridgeError("unknown", "TOOL_EXECUTION_FAILED", "invalid bridge request"));
|
|
455
455
|
return;
|
|
456
456
|
}
|
|
457
|
-
onBridge(request).then(respond, (e) => respond(bridgeError(request.id, "TOOL_EXECUTION_FAILED", messageOf$
|
|
457
|
+
onBridge(request).then(respond, (e) => respond(bridgeError(request.id, "TOOL_EXECUTION_FAILED", messageOf$6(e))));
|
|
458
458
|
return;
|
|
459
459
|
}
|
|
460
460
|
if (msg?.type === "load-result" || msg?.type === "execute-result") done(() => resolve(msg));
|
|
@@ -466,6 +466,328 @@ var SandboxedScriptExecutor = class {
|
|
|
466
466
|
});
|
|
467
467
|
}
|
|
468
468
|
/** 能力桥宿主侧处理:能力关闭/授权拒绝即 TOOL_UNSUPPORTED;判定逻辑共用 runtime/sandbox/approval */
|
|
469
|
+
async #handleBridge(request, context) {
|
|
470
|
+
const gate = async (capability, message, details) => {
|
|
471
|
+
const decision = await this.#approval.authorize({
|
|
472
|
+
runId: context.runId,
|
|
473
|
+
capability,
|
|
474
|
+
mode: this.#capabilities[capability],
|
|
475
|
+
message,
|
|
476
|
+
...details !== void 0 ? { details } : {}
|
|
477
|
+
});
|
|
478
|
+
if (decision === "allowed") return void 0;
|
|
479
|
+
return bridgeError(request.id, "TOOL_UNSUPPORTED", decision === "disabled" ? `Capability "${capability}" is disabled` : `Capability "${capability}" was denied by the user`);
|
|
480
|
+
};
|
|
481
|
+
try {
|
|
482
|
+
switch (request.kind) {
|
|
483
|
+
case "readReference": {
|
|
484
|
+
const denied = await gate("readReference", `Script "${context.skillName}" wants to read reference "${request.path}"`, { path: request.path });
|
|
485
|
+
if (denied) return denied;
|
|
486
|
+
return {
|
|
487
|
+
id: request.id,
|
|
488
|
+
ok: true,
|
|
489
|
+
value: await context.readReference(request.path)
|
|
490
|
+
};
|
|
491
|
+
}
|
|
492
|
+
case "writeArtifact": {
|
|
493
|
+
const denied = await gate("writeArtifact", `Script "${context.skillName}" wants to write artifact "${request.path}"`, {
|
|
494
|
+
path: request.path,
|
|
495
|
+
mimeType: request.mimeType
|
|
496
|
+
});
|
|
497
|
+
if (denied) return denied;
|
|
498
|
+
const content = typeof request.content === "string" ? request.content : new Uint8Array(request.content);
|
|
499
|
+
const artifact = await context.writeArtifact(request.path, content, { ...request.mimeType ? { mimeType: request.mimeType } : {} });
|
|
500
|
+
return {
|
|
501
|
+
id: request.id,
|
|
502
|
+
ok: true,
|
|
503
|
+
value: artifact
|
|
504
|
+
};
|
|
505
|
+
}
|
|
506
|
+
case "confirm": {
|
|
507
|
+
if (!context.confirm) return bridgeError(request.id, "TOOL_UNSUPPORTED", "Capability \"confirm\" is disabled");
|
|
508
|
+
const denied = await gate("confirm", `Script "${context.skillName}" asks for confirmation: ${request.message}`);
|
|
509
|
+
if (denied) return denied;
|
|
510
|
+
return {
|
|
511
|
+
id: request.id,
|
|
512
|
+
ok: true,
|
|
513
|
+
value: await context.confirm(request.message)
|
|
514
|
+
};
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
} catch (e) {
|
|
518
|
+
return bridgeError(request.id, e instanceof WebSkillError ? e.code : "TOOL_EXECUTION_FAILED", messageOf$6(e));
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
};
|
|
522
|
+
const baseName = (p) => p.split("/").pop() ?? p;
|
|
523
|
+
const toPlatform$2 = (p) => p.split("/").join(path.sep);
|
|
524
|
+
const messageOf$5 = (e) => e instanceof Error ? e.message : String(e);
|
|
525
|
+
const NETWORK_POLICY_LIB = `${isNetworkAllowed.toString()}\n${networkUrlHost.toString()}`;
|
|
526
|
+
const readAllow = (p) => [`--allow-fs-read=${p}`, `--allow-fs-read=${realpathSync(p)}`];
|
|
527
|
+
const writeAllow = (p) => [`--allow-fs-write=${p}`, `--allow-fs-write=${realpathSync(p)}`];
|
|
528
|
+
/** 子进程入口文件:src 为同目录 .ts;node dist 为 dist/executor/;sdk dist 为平铺 dist/ */
|
|
529
|
+
function processEntryPath() {
|
|
530
|
+
const dir = path.dirname(fileURLToPath(import.meta.url));
|
|
531
|
+
const candidates = [
|
|
532
|
+
path.join(dir, "processSandboxEntry.js"),
|
|
533
|
+
path.join(dir, "processSandboxEntry.ts"),
|
|
534
|
+
path.join(dir, "executor", "processSandboxEntry.js")
|
|
535
|
+
];
|
|
536
|
+
for (const candidate of candidates) if (existsSync(candidate)) return candidate;
|
|
537
|
+
throw new WebSkillError("TOOL_EXECUTION_FAILED", `Process sandbox entry not found (tried: ${candidates.join(", ")})`);
|
|
538
|
+
}
|
|
539
|
+
/**
|
|
540
|
+
* child_process.fork + --permission 进程沙箱(真实进程隔离)。
|
|
541
|
+
* 每个子进程以 `--permission --allow-fs-read=<入口目录> --allow-fs-read=<skillRoot>
|
|
542
|
+
* --allow-fs-write=<artifactDir>` 启动:fs 维度由权限模型管控(experimental),
|
|
543
|
+
* 子进程/Worker/addons 默认禁;网络无权限维度仍靠 fetch/WebSocket patch。
|
|
544
|
+
* 能力桥协议与 worker_threads 沙箱同一形态(readReference/writeArtifact/confirm + 授权)。
|
|
545
|
+
* 温池(默认 2):同 skillRoot 复用子进程;执行后 kill 并补位重生;并发上限即池大小。
|
|
546
|
+
* 超时 kill(同步死循环可杀);非零退出码 → TOOL_EXECUTION_FAILED。
|
|
547
|
+
*/
|
|
548
|
+
var ProcessSandboxExecutor = class {
|
|
549
|
+
#fs;
|
|
550
|
+
#options;
|
|
551
|
+
#capabilities;
|
|
552
|
+
#networkPolicy;
|
|
553
|
+
#approval;
|
|
554
|
+
#slots = [];
|
|
555
|
+
#waiters = [];
|
|
556
|
+
constructor(fs, options = {}) {
|
|
557
|
+
this.#fs = fs;
|
|
558
|
+
this.#options = options;
|
|
559
|
+
this.#capabilities = {
|
|
560
|
+
readReference: options.capabilities?.readReference ?? true,
|
|
561
|
+
writeArtifact: options.capabilities?.writeArtifact ?? true,
|
|
562
|
+
confirm: options.capabilities?.confirm ?? true
|
|
563
|
+
};
|
|
564
|
+
this.#networkPolicy = options.networkPolicy ?? "deny-all";
|
|
565
|
+
this.#approval = new CapabilityApproval({
|
|
566
|
+
...options.uiBridge ? { uiBridge: options.uiBridge } : {},
|
|
567
|
+
...options.approvalScope ? { scope: options.approvalScope } : {}
|
|
568
|
+
});
|
|
569
|
+
}
|
|
570
|
+
get poolSize() {
|
|
571
|
+
return this.#options.poolSize ?? 2;
|
|
572
|
+
}
|
|
573
|
+
/** 池全部子进程销毁(测试收尾/进程退出前调用) */
|
|
574
|
+
async dispose() {
|
|
575
|
+
for (const slot of this.#slots) {
|
|
576
|
+
slot.child.kill();
|
|
577
|
+
await rm(slot.artifactDir, {
|
|
578
|
+
recursive: true,
|
|
579
|
+
force: true
|
|
580
|
+
}).catch(() => void 0);
|
|
581
|
+
}
|
|
582
|
+
this.#slots = [];
|
|
583
|
+
this.#waiters = [];
|
|
584
|
+
}
|
|
585
|
+
async #locateScript(skillRoot, scriptName) {
|
|
586
|
+
const tsPath = `${skillRoot}/scripts/${scriptName}.ts`;
|
|
587
|
+
const jsPath = `${skillRoot}/scripts/${scriptName}.js`;
|
|
588
|
+
const [hasTs, hasJs] = await Promise.all([this.#fs.exists(tsPath), this.#fs.exists(jsPath)]);
|
|
589
|
+
if (hasTs && hasJs) throw new WebSkillError("TOOL_EXECUTION_FAILED", `Script "${scriptName}" is ambiguous: both .ts and .js exist under ${skillRoot}/scripts`);
|
|
590
|
+
if (!hasTs && !hasJs) throw new WebSkillError("TOOL_NOT_FOUND", `Script "${scriptName}" not found under ${skillRoot}/scripts`);
|
|
591
|
+
return hasTs ? tsPath : jsPath;
|
|
592
|
+
}
|
|
593
|
+
/** 取一个可用子进程(同 key 复用 / 淘汰 idle 重生 / 扩容 / 排队) */
|
|
594
|
+
async #acquire(key) {
|
|
595
|
+
for (;;) {
|
|
596
|
+
const idle = this.#slots.filter((s) => !s.busy);
|
|
597
|
+
const match = idle.find((s) => s.key === key);
|
|
598
|
+
if (match) {
|
|
599
|
+
match.busy = true;
|
|
600
|
+
return match;
|
|
601
|
+
}
|
|
602
|
+
if (idle.length > 0) {
|
|
603
|
+
const victim = idle[0];
|
|
604
|
+
victim.child.kill();
|
|
605
|
+
await rm(victim.artifactDir, {
|
|
606
|
+
recursive: true,
|
|
607
|
+
force: true
|
|
608
|
+
}).catch(() => void 0);
|
|
609
|
+
this.#slots.splice(this.#slots.indexOf(victim), 1);
|
|
610
|
+
}
|
|
611
|
+
if (this.#slots.length < this.poolSize) {
|
|
612
|
+
const slot = await this.#spawnSlot(key);
|
|
613
|
+
slot.busy = true;
|
|
614
|
+
this.#slots.push(slot);
|
|
615
|
+
return slot;
|
|
616
|
+
}
|
|
617
|
+
await new Promise((resolve) => this.#waiters.push(resolve));
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
/** 执行后回收:kill 旧子进程,补位重生同 key 新子进程(温池保持),唤醒排队 */
|
|
621
|
+
#recycle(slot) {
|
|
622
|
+
slot.child.kill();
|
|
623
|
+
const index = this.#slots.indexOf(slot);
|
|
624
|
+
if (index >= 0) this.#slots.splice(index, 1);
|
|
625
|
+
rm(slot.artifactDir, {
|
|
626
|
+
recursive: true,
|
|
627
|
+
force: true
|
|
628
|
+
}).catch(() => void 0);
|
|
629
|
+
this.#spawnSlot(slot.key).then((fresh) => {
|
|
630
|
+
this.#slots.push(fresh);
|
|
631
|
+
}).catch(() => void 0).finally(() => {
|
|
632
|
+
const waiter = this.#waiters.shift();
|
|
633
|
+
if (waiter) waiter();
|
|
634
|
+
});
|
|
635
|
+
}
|
|
636
|
+
async #spawnSlot(key) {
|
|
637
|
+
const artifactDir = await mkdtemp(path.join(tmpdir(), "webskill-psbx-out-")).then((d) => d.split(path.sep).join("/"));
|
|
638
|
+
const entry = processEntryPath();
|
|
639
|
+
return {
|
|
640
|
+
key,
|
|
641
|
+
child: fork(entry, [], {
|
|
642
|
+
execArgv: [
|
|
643
|
+
"--permission",
|
|
644
|
+
...readAllow(path.dirname(entry)),
|
|
645
|
+
...readAllow(toPlatform$2(key)),
|
|
646
|
+
...readAllow(artifactDir),
|
|
647
|
+
...writeAllow(artifactDir)
|
|
648
|
+
],
|
|
649
|
+
silent: false
|
|
650
|
+
}),
|
|
651
|
+
busy: false,
|
|
652
|
+
artifactDir
|
|
653
|
+
};
|
|
654
|
+
}
|
|
655
|
+
async loadDefinition(skillRoot, scriptName) {
|
|
656
|
+
const scriptPath = await this.#locateScript(skillRoot, scriptName);
|
|
657
|
+
const skillName = baseName(skillRoot);
|
|
658
|
+
const slot = await this.#acquire(toPlatform$2(skillRoot));
|
|
659
|
+
try {
|
|
660
|
+
const response = await this.#runTask(slot, {
|
|
661
|
+
mode: "load",
|
|
662
|
+
scriptPath: toPlatform$2(scriptPath),
|
|
663
|
+
scriptName,
|
|
664
|
+
scriptSource: await this.#fs.readText(scriptPath),
|
|
665
|
+
scratchDir: slot.artifactDir
|
|
666
|
+
}, 3e4);
|
|
667
|
+
if (!response.ok) throw new WebSkillError("TOOL_EXECUTION_FAILED", `Failed to load script "${scriptName}": ${response.error?.message ?? "unknown error"}`);
|
|
668
|
+
return {
|
|
669
|
+
name: `${skillName}__${scriptName}`,
|
|
670
|
+
description: response.definition?.description,
|
|
671
|
+
inputSchema: response.definition?.inputSchema,
|
|
672
|
+
source: "script",
|
|
673
|
+
skillName
|
|
674
|
+
};
|
|
675
|
+
} finally {
|
|
676
|
+
this.#recycle(slot);
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
async execute(input) {
|
|
680
|
+
const { skillRoot, scriptName, args, context, timeoutMs } = input;
|
|
681
|
+
let scriptPath;
|
|
682
|
+
try {
|
|
683
|
+
scriptPath = await this.#locateScript(skillRoot, scriptName);
|
|
684
|
+
} catch (e) {
|
|
685
|
+
return {
|
|
686
|
+
ok: false,
|
|
687
|
+
content: [],
|
|
688
|
+
error: {
|
|
689
|
+
code: e instanceof WebSkillError ? e.code : "TOOL_EXECUTION_FAILED",
|
|
690
|
+
message: messageOf$5(e)
|
|
691
|
+
}
|
|
692
|
+
};
|
|
693
|
+
}
|
|
694
|
+
const slot = await this.#acquire(toPlatform$2(skillRoot));
|
|
695
|
+
try {
|
|
696
|
+
const result = await this.#runTask(slot, {
|
|
697
|
+
mode: "execute",
|
|
698
|
+
scriptPath: toPlatform$2(scriptPath),
|
|
699
|
+
scriptName,
|
|
700
|
+
skillName: context.skillName,
|
|
701
|
+
runId: context.runId,
|
|
702
|
+
args,
|
|
703
|
+
scriptSource: await this.#fs.readText(scriptPath),
|
|
704
|
+
scratchDir: slot.artifactDir
|
|
705
|
+
}, timeoutMs, (request) => this.#handleBridge(request, context), (host) => context.onWarning?.(`Network request blocked by sandbox network policy: ${host}`));
|
|
706
|
+
if (!result.ok) {
|
|
707
|
+
const stderrSummary = result.stderr?.length ? ` | stderr: ${result.stderr.join(" | ").slice(0, 500)}` : "";
|
|
708
|
+
return {
|
|
709
|
+
ok: false,
|
|
710
|
+
content: [],
|
|
711
|
+
error: {
|
|
712
|
+
code: result.error?.code ?? "TOOL_EXECUTION_FAILED",
|
|
713
|
+
message: `${result.error?.message ?? "script execution failed"}${stderrSummary}`
|
|
714
|
+
}
|
|
715
|
+
};
|
|
716
|
+
}
|
|
717
|
+
const content = normalizeToolContent(result.value);
|
|
718
|
+
if (result.stdout?.length) content.push({
|
|
719
|
+
type: "text",
|
|
720
|
+
text: result.stdout.join("\n")
|
|
721
|
+
});
|
|
722
|
+
return {
|
|
723
|
+
ok: true,
|
|
724
|
+
content
|
|
725
|
+
};
|
|
726
|
+
} catch (e) {
|
|
727
|
+
return {
|
|
728
|
+
ok: false,
|
|
729
|
+
content: [],
|
|
730
|
+
error: {
|
|
731
|
+
code: e instanceof WebSkillError ? e.code : "TOOL_EXECUTION_FAILED",
|
|
732
|
+
message: messageOf$5(e)
|
|
733
|
+
}
|
|
734
|
+
};
|
|
735
|
+
} finally {
|
|
736
|
+
this.#recycle(slot);
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
/** 在子进程上跑一个任务;超时 kill;非零退出码 → TOOL_EXECUTION_FAILED */
|
|
740
|
+
#runTask(slot, task, timeoutMs, onBridge, onNetworkBlocked) {
|
|
741
|
+
const { child } = slot;
|
|
742
|
+
return new Promise((resolve, reject) => {
|
|
743
|
+
let settled = false;
|
|
744
|
+
const timer = setTimeout(() => {
|
|
745
|
+
if (settled) return;
|
|
746
|
+
settled = true;
|
|
747
|
+
child.kill();
|
|
748
|
+
reject(new WebSkillError("RUN_TIMEOUT", `Process sandbox task timed out after ${timeoutMs}ms (child killed)`));
|
|
749
|
+
}, timeoutMs);
|
|
750
|
+
const done = (fn) => {
|
|
751
|
+
if (settled) return;
|
|
752
|
+
settled = true;
|
|
753
|
+
clearTimeout(timer);
|
|
754
|
+
fn();
|
|
755
|
+
};
|
|
756
|
+
child.on("message", (msg) => {
|
|
757
|
+
if (msg?.type === "network-blocked") {
|
|
758
|
+
if (typeof msg.host === "string") onNetworkBlocked?.(msg.host);
|
|
759
|
+
return;
|
|
760
|
+
}
|
|
761
|
+
if (msg?.type === "bridge" && onBridge) {
|
|
762
|
+
const request = parseBridgeRequest(msg.request);
|
|
763
|
+
const respond = (response) => child.send({
|
|
764
|
+
type: "bridge-response",
|
|
765
|
+
response
|
|
766
|
+
});
|
|
767
|
+
if (!request) {
|
|
768
|
+
respond(bridgeError("unknown", "TOOL_EXECUTION_FAILED", "invalid bridge request"));
|
|
769
|
+
return;
|
|
770
|
+
}
|
|
771
|
+
onBridge(request).then(respond, (e) => respond(bridgeError(request.id, "TOOL_EXECUTION_FAILED", messageOf$5(e))));
|
|
772
|
+
return;
|
|
773
|
+
}
|
|
774
|
+
if (msg?.type === "load-result" || msg?.type === "execute-result") done(() => resolve(msg));
|
|
775
|
+
});
|
|
776
|
+
child.on("error", (e) => done(() => reject(e)));
|
|
777
|
+
child.on("exit", (code) => {
|
|
778
|
+
if (!settled) done(() => reject(new WebSkillError("TOOL_EXECUTION_FAILED", `Sandbox child exited ${code === null ? "by signal" : `with code ${code}`} without producing a result`)));
|
|
779
|
+
});
|
|
780
|
+
child.send({
|
|
781
|
+
type: "task",
|
|
782
|
+
task: {
|
|
783
|
+
...task,
|
|
784
|
+
networkPolicy: this.#networkPolicy,
|
|
785
|
+
networkPolicyLib: NETWORK_POLICY_LIB
|
|
786
|
+
}
|
|
787
|
+
});
|
|
788
|
+
});
|
|
789
|
+
}
|
|
790
|
+
/** 能力桥宿主侧处理:与 worker_threads 沙箱同一判定(runtime/sandbox/approval 单一来源) */
|
|
469
791
|
async #handleBridge(request, context) {
|
|
470
792
|
const gate = async (capability, message, details) => {
|
|
471
793
|
const decision = await this.#approval.authorize({
|
|
@@ -1500,4 +1822,4 @@ var SkillManager = class {
|
|
|
1500
1822
|
};
|
|
1501
1823
|
|
|
1502
1824
|
//#endregion
|
|
1503
|
-
export { NodeScriptExecutor as a,
|
|
1825
|
+
export { NodeScriptExecutor as a, SandboxedScriptExecutor as c, readArchiveManifest as d, NodeFS as i, SkillManager as l, FileArtifactStore as n, OxcSchemaInferer as o, FileMemoryStore as r, ProcessSandboxExecutor as s, CliUiBridge as t, exportArchive as u };
|
|
@@ -2090,6 +2090,10 @@ var WebSkillRuntime = class {
|
|
|
2090
2090
|
get session() {
|
|
2091
2091
|
return this.#session;
|
|
2092
2092
|
}
|
|
2093
|
+
/** 当前装配的脚本执行器(治理默认执行器断言等只读场景) */
|
|
2094
|
+
get executor() {
|
|
2095
|
+
return this.#deps.executor;
|
|
2096
|
+
}
|
|
2093
2097
|
/** 生命周期事件总线(只读观测) */
|
|
2094
2098
|
get events() {
|
|
2095
2099
|
return this.#events;
|
package/dist/governance.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { F as SkillDocument, N as SkillCatalogEntry, c as LlmClient, u as LlmMessage, v as UiBridge, w as FileSystemProvider, z as SkillManifest } from "./types-CKm5G_eQ-8W8FnP4u.js";
|
|
2
|
-
import { dt as WebSkillRuntime, q as RuntimeRun, tt as SkillStateGuard } from "./index-
|
|
3
|
-
import {
|
|
2
|
+
import { Q as ScriptExecutor, dt as WebSkillRuntime, ft as WebSkillRuntimeDeps, q as RuntimeRun, tt as SkillStateGuard } from "./index-gjFuBevI.js";
|
|
3
|
+
import { d as SkillManager } from "./index-BmzysJX5.js";
|
|
4
4
|
//#region ../governance/dist/index.d.ts
|
|
5
5
|
//#region src/types.d.ts
|
|
6
6
|
type CandidateStatus = 'draft' | 'pending-review' | 'approved' | 'published' | 'rejected';
|
|
@@ -357,6 +357,16 @@ declare class EvaluationRunner {
|
|
|
357
357
|
run(tasks: EvaluationTask[]): Promise<EvaluationReport>;
|
|
358
358
|
}
|
|
359
359
|
//#endregion
|
|
360
|
+
//#region src/evaluation/evaluationRuntime.d.ts
|
|
361
|
+
/**
|
|
362
|
+
* 治理评估专用 runtime 装配(不可信技能试用路径):
|
|
363
|
+
* 默认注入 ProcessSandboxExecutor(fork + --permission 真实进程隔离);
|
|
364
|
+
* 可配置 executor 切回 SandboxedScriptExecutor(worker_threads 能力面收敛形态)。
|
|
365
|
+
*/
|
|
366
|
+
declare function createEvaluationRuntime(deps: WebSkillRuntimeDeps & {
|
|
367
|
+
executor?: ScriptExecutor;
|
|
368
|
+
}): WebSkillRuntime;
|
|
369
|
+
//#endregion
|
|
360
370
|
//#region src/evaluation/testSuggestion.d.ts
|
|
361
371
|
/** 失败 trace → 回归评估任务建议(prompt 复现 + expected 错误模式) */
|
|
362
372
|
declare function suggestFromFailedRun(run: RuntimeRun): EvaluationTask;
|
|
@@ -474,4 +484,4 @@ declare function createMissHook(deps: {
|
|
|
474
484
|
*/
|
|
475
485
|
declare function completeText(llm: LlmClient, messages: LlmMessage[]): Promise<string>;
|
|
476
486
|
//#endregion
|
|
477
|
-
export { AlwaysHumanApprovalPolicy, type ApprovalDecision, type ApprovalPolicy, ApprovalWorkflow, type AuditEvent, type AuditLog, type CandidateFile, type CandidateRisk, type CandidateSkill, type CandidateSource, type CandidateStatus, CandidateStore, CompositeApprovalPolicy, DependencyGraph, DocumentSkillExtractor, type EvaluationReport, type EvaluationResult, EvaluationRunner, type EvaluationTask, FailureAnalyzer, type FailureDiagnosis, FsAuditLog, LlmCandidateGenerator, type RepairOption, RepairPlanner, SCORING_WEIGHTS, type ScoreInput, SimilarityDetector, SkillScorer, type SkillState, SkillStatePolicy, type SkillVersion, SkillVersionStore, type SourceDocument, candidateToCatalogEntry, completeText, createMissHook, jaccardSimilarity, normalizeCandidate, normalizeCandidateFiles, normalizeRisk, parseJsonObject, readDocument, sanitizeCandidateName, suggestFromFailedRun, validateCandidate };
|
|
487
|
+
export { AlwaysHumanApprovalPolicy, type ApprovalDecision, type ApprovalPolicy, ApprovalWorkflow, type AuditEvent, type AuditLog, type CandidateFile, type CandidateRisk, type CandidateSkill, type CandidateSource, type CandidateStatus, CandidateStore, CompositeApprovalPolicy, DependencyGraph, DocumentSkillExtractor, type EvaluationReport, type EvaluationResult, EvaluationRunner, type EvaluationTask, FailureAnalyzer, type FailureDiagnosis, FsAuditLog, LlmCandidateGenerator, type RepairOption, RepairPlanner, SCORING_WEIGHTS, type ScoreInput, SimilarityDetector, SkillScorer, type SkillState, SkillStatePolicy, type SkillVersion, SkillVersionStore, type SourceDocument, candidateToCatalogEntry, completeText, createEvaluationRuntime, createMissHook, jaccardSimilarity, normalizeCandidate, normalizeCandidateFiles, normalizeRisk, parseJsonObject, readDocument, sanitizeCandidateName, suggestFromFailedRun, validateCandidate };
|
package/dist/governance.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { A as unzipWithLimits, b as isValidSkillName, d as assertSafePathSegment, j as validateSkills, k as resolveInsideRoot, u as WebSkillError } from "./dist-D0saNPi_.js";
|
|
2
|
-
import {
|
|
2
|
+
import { S as WebSkillRuntime } from "./dist-DrySSQ5R.js";
|
|
3
|
+
import { i as NodeFS, s as ProcessSandboxExecutor, u as exportArchive } from "./dist-BRGQcLqR.js";
|
|
3
4
|
import path from "node:path";
|
|
4
5
|
import { tmpdir } from "node:os";
|
|
5
6
|
import { mkdtemp } from "node:fs/promises";
|
|
@@ -840,6 +841,17 @@ var EvaluationRunner = class {
|
|
|
840
841
|
};
|
|
841
842
|
}
|
|
842
843
|
};
|
|
844
|
+
/**
|
|
845
|
+
* 治理评估专用 runtime 装配(不可信技能试用路径):
|
|
846
|
+
* 默认注入 ProcessSandboxExecutor(fork + --permission 真实进程隔离);
|
|
847
|
+
* 可配置 executor 切回 SandboxedScriptExecutor(worker_threads 能力面收敛形态)。
|
|
848
|
+
*/
|
|
849
|
+
function createEvaluationRuntime(deps) {
|
|
850
|
+
return new WebSkillRuntime({
|
|
851
|
+
...deps,
|
|
852
|
+
executor: deps.executor ?? new ProcessSandboxExecutor(deps.fs)
|
|
853
|
+
});
|
|
854
|
+
}
|
|
843
855
|
/** 失败 trace → 回归评估任务建议(prompt 复现 + expected 错误模式) */
|
|
844
856
|
function suggestFromFailedRun(run) {
|
|
845
857
|
const errorPatterns = run.trace.filter((e) => e.type === "tool.failed" || e.type === "run.failed").map((e) => String(e.data?.["code"] ?? e.message ?? "")).filter(Boolean);
|
|
@@ -1025,4 +1037,4 @@ function createMissHook(deps) {
|
|
|
1025
1037
|
}
|
|
1026
1038
|
|
|
1027
1039
|
//#endregion
|
|
1028
|
-
export { AlwaysHumanApprovalPolicy, ApprovalWorkflow, CandidateStore, CompositeApprovalPolicy, DependencyGraph, DocumentSkillExtractor, EvaluationRunner, FailureAnalyzer, FsAuditLog, LlmCandidateGenerator, RepairPlanner, SCORING_WEIGHTS, SimilarityDetector, SkillScorer, SkillStatePolicy, SkillVersionStore, candidateToCatalogEntry, completeText, createMissHook, jaccardSimilarity, normalizeCandidate, normalizeCandidateFiles, normalizeRisk, parseJsonObject, readDocument, sanitizeCandidateName, suggestFromFailedRun, validateCandidate };
|
|
1040
|
+
export { AlwaysHumanApprovalPolicy, ApprovalWorkflow, CandidateStore, CompositeApprovalPolicy, DependencyGraph, DocumentSkillExtractor, EvaluationRunner, FailureAnalyzer, FsAuditLog, LlmCandidateGenerator, RepairPlanner, SCORING_WEIGHTS, SimilarityDetector, SkillScorer, SkillStatePolicy, SkillVersionStore, candidateToCatalogEntry, completeText, createEvaluationRuntime, createMissHook, jaccardSimilarity, normalizeCandidate, normalizeCandidateFiles, normalizeRisk, parseJsonObject, readDocument, sanitizeCandidateName, suggestFromFailedRun, validateCandidate };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { C as FileStat, I as SkillInstallSource, K as VerifyResult, T as JsonSchema, W as SkillsLockfile, _ as RenderResultRequest, o as InteractionRequest, s as InteractionResponse, v as UiBridge, w as FileSystemProvider, y as ArchiveLimits, z as SkillManifest } from "./types-CKm5G_eQ-8W8FnP4u.js";
|
|
2
|
-
import { N as NetworkPolicy, Q as ScriptExecutor, X as SchemaInferer, Z as ScriptExecutionContext, b as FsArtifactStore, d as BridgeCapabilities, it as ToolResult, nt as ToolDefinition, u as ApprovalScope, x as FsMemoryStore } from "./index-
|
|
2
|
+
import { N as NetworkPolicy, Q as ScriptExecutor, X as SchemaInferer, Z as ScriptExecutionContext, b as FsArtifactStore, d as BridgeCapabilities, it as ToolResult, nt as ToolDefinition, u as ApprovalScope, x as FsMemoryStore } from "./index-gjFuBevI.js";
|
|
3
3
|
import { Readable, Writable } from "node:stream";
|
|
4
4
|
//#region ../node/dist/index.d.ts
|
|
5
5
|
//#region src/fs/nodeFs.d.ts
|
|
@@ -88,6 +88,43 @@ declare class SandboxedScriptExecutor implements ScriptExecutor {
|
|
|
88
88
|
}): Promise<ToolResult>;
|
|
89
89
|
}
|
|
90
90
|
//#endregion
|
|
91
|
+
//#region src/executor/processSandboxExecutor.d.ts
|
|
92
|
+
interface ProcessSandboxOptions {
|
|
93
|
+
/** 温池大小(并发上限;执行后 kill 并补位重生),默认 2 */
|
|
94
|
+
poolSize?: number;
|
|
95
|
+
capabilities?: BridgeCapabilities;
|
|
96
|
+
/** 网络策略:默认 'deny-all'(权限模型无网络维度,补丁兜底;node:net 裸模块为已知残余面) */
|
|
97
|
+
networkPolicy?: NetworkPolicy;
|
|
98
|
+
/** require-approval 模式的授权询问出口 */
|
|
99
|
+
uiBridge?: UiBridge;
|
|
100
|
+
/** 授权粒度:默认 'once-per-run' */
|
|
101
|
+
approvalScope?: ApprovalScope;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* child_process.fork + --permission 进程沙箱(真实进程隔离)。
|
|
105
|
+
* 每个子进程以 `--permission --allow-fs-read=<入口目录> --allow-fs-read=<skillRoot>
|
|
106
|
+
* --allow-fs-write=<artifactDir>` 启动:fs 维度由权限模型管控(experimental),
|
|
107
|
+
* 子进程/Worker/addons 默认禁;网络无权限维度仍靠 fetch/WebSocket patch。
|
|
108
|
+
* 能力桥协议与 worker_threads 沙箱同一形态(readReference/writeArtifact/confirm + 授权)。
|
|
109
|
+
* 温池(默认 2):同 skillRoot 复用子进程;执行后 kill 并补位重生;并发上限即池大小。
|
|
110
|
+
* 超时 kill(同步死循环可杀);非零退出码 → TOOL_EXECUTION_FAILED。
|
|
111
|
+
*/
|
|
112
|
+
declare class ProcessSandboxExecutor implements ScriptExecutor {
|
|
113
|
+
#private;
|
|
114
|
+
constructor(fs: FileSystemProvider, options?: ProcessSandboxOptions);
|
|
115
|
+
get poolSize(): number;
|
|
116
|
+
/** 池全部子进程销毁(测试收尾/进程退出前调用) */
|
|
117
|
+
dispose(): Promise<void>;
|
|
118
|
+
loadDefinition(skillRoot: string, scriptName: string): Promise<ToolDefinition>;
|
|
119
|
+
execute(input: {
|
|
120
|
+
skillRoot: string;
|
|
121
|
+
scriptName: string;
|
|
122
|
+
args: Record<string, unknown>;
|
|
123
|
+
context: ScriptExecutionContext;
|
|
124
|
+
timeoutMs: number;
|
|
125
|
+
}): Promise<ToolResult>;
|
|
126
|
+
}
|
|
127
|
+
//#endregion
|
|
91
128
|
//#region src/schema/oxcSchemaInferer.d.ts
|
|
92
129
|
/**
|
|
93
130
|
* D2 Schema 推导(OXC 静态文本分析,宿主侧执行,不进沙箱)。
|
|
@@ -191,4 +228,4 @@ declare function exportArchive(fs: FileSystemProvider, skillRoot: string, option
|
|
|
191
228
|
/** 只解出归档中的 webskill.skill-manifest.json 条目(安装前预览) */
|
|
192
229
|
declare function readArchiveManifest(fs: FileSystemProvider, archivePath: string): Promise<SkillManifest>;
|
|
193
230
|
//#endregion
|
|
194
|
-
export { NodeScriptExecutor as a,
|
|
231
|
+
export { NodeScriptExecutor as a, ProcessSandboxOptions as c, SkillManager as d, exportArchive as f, NodeFS as i, SandboxOptions as l, FileArtifactStore as n, OxcSchemaInferer as o, readArchiveManifest as p, FileMemoryStore as r, ProcessSandboxExecutor as s, CliUiBridge as t, SandboxedScriptExecutor as u };
|
|
@@ -778,6 +778,8 @@ declare class WebSkillRuntime {
|
|
|
778
778
|
#private;
|
|
779
779
|
constructor(deps: WebSkillRuntimeDeps);
|
|
780
780
|
get session(): RuntimeSession;
|
|
781
|
+
/** 当前装配的脚本执行器(治理默认执行器断言等只读场景) */
|
|
782
|
+
get executor(): ScriptExecutor | undefined;
|
|
781
783
|
/** 生命周期事件总线(只读观测) */
|
|
782
784
|
get events(): EventBus;
|
|
783
785
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { $ as checkDependencyCycles, A as SKILL_NAME_PATTERN, B as SkillMetadata, C as FileStat, D as SKILLS_LOCKFILE, E as MemoryFS, F as SkillDocument, G as ValidationReport, H as SkillReader, I as SkillInstallSource, J as WebSkillErrorCode, K as VerifyResult, L as SkillIssue, M as SkillCatalog, N as SkillCatalogEntry, O as SKILL_MANIFEST_FILE, P as SkillDiscovery, Q as buildManifest, R as SkillLocation, S as DiscoveryResult, T as JsonSchema, U as SkillSource, V as SkillPackManifest, W as SkillsLockfile, X as atomicWriteText, Y as assertSafePathSegment, Z as buildCatalog, _ as RenderResultRequest, _t as xmlRenderer, a as InteractionPolicy, at as jsonRenderer, b as CatalogRenderer, c as LlmClient, ct as parseSkillPackManifest, d as LlmResponse, dt as renderCatalogJson, et as checkSkillRules, f as LlmStreamEvent, ft as resolveArchiveLimits, g as RenderBlock, gt as verifyManifest, h as MemoryStore, ht as validateSkills, i as FormField, it as isValidSkillName, j as SKILL_PACK_FILE, k as SKILL_NAME_MAX_LENGTH, l as LlmCompleteInput, lt as readResponseWithLimit, m as LlmToolSpec, mt as unzipWithLimits, n as ArtifactStore, nt as escapeXml, o as InteractionRequest, ot as normalizePath, p as LlmToolCall, pt as resolveInsideRoot, q as WebSkillError, r as ChartSpec, rt as exportSkills, s as InteractionResponse, st as parseSkillMarkdown, t as Artifact, tt as computeDigest, u as LlmMessage, ut as renderAvailableSkillsXml, v as UiBridge, w as FileSystemProvider, x as DEFAULT_ARCHIVE_LIMITS, y as ArchiveLimits, z as SkillManifest } from "./types-CKm5G_eQ-8W8FnP4u.js";
|
|
2
|
-
import { $ as SerializingMemoryStore, A as LifecycleHook, B as RUN_SNAPSHOT_SCHEMA_VERSION, C as FullDisclosureRouter, Ct as normalizeToolContent, D as HookRunnerOptions, Dt as toLlmToolSpec, E as HookRunner, Et as schemaToForm, F as OpenAiCompatibleClientConfig, G as RunTerminationReason, H as RunResult, I as ProgressiveRouter, J as RuntimeSession, K as RuntimePhase, L as READ_SKILL_FILE_INPUT_SCHEMA, M as LifecycleListener, N as NetworkPolicy, O as InstalledSkillManifest, Ot as toVercelToolSpecs, P as OpenAiCompatibleClient, Q as ScriptExecutor, R as READ_SKILL_FILE_TOOL, S as FsRunSnapshotStore, St as networkUrlHost, T as GoogleGenAiClientConfig, Tt as resolveToolName, U as RunSnapshot, V as RouteResult, W as RunSnapshotStore, X as SchemaInferer, Y as RuntimeSessionHandle, Z as ScriptExecutionContext, _ as EventBus, _t as extractChartSpec, a as AgentLoopConfig, at as TraceClock, b as FsArtifactStore, bt as isNetworkAllowed, c as AnthropicClientConfig, ct as TraceRecorder, d as BridgeCapabilities, dt as WebSkillRuntime, et as SkillRouter, f as BridgeCapability, ft as WebSkillRuntimeDeps, g as CapabilityMode, gt as createWebSkillApi, h as CapabilityApproval, ht as createScriptContext, i as AgentLoop, it as ToolResult, j as LifecycleHookContext, k as LifecycleEvent, l as ApprovalDecision, lt as VercelToolSpec, m as BridgeResponse, mt as buildRenderResult, n as ASK_USER_TOOL, nt as ToolDefinition, o as AgentLoopDeps, ot as TraceEvent, p as BridgeRequest, pt as bridgeError, q as RuntimeRun, r as ASK_USER_TOOL_NAME, rt as ToolResolution, s as AnthropicClient, st as TraceEventType, t as ASK_USER_INPUT_SCHEMA, tt as SkillStateGuard, u as ApprovalScope, ut as WebSkillApi, v as ExternalSkillProvider, vt as fromVercelResult, w as GoogleGenAiClient, wt as parseBridgeRequest, x as FsMemoryStore, xt as mergeCatalogEntries, y as ExternalToolSource, yt as fromVercelStreamPart, z as READ_SKILL_FILE_TOOL_NAME } from "./index-
|
|
2
|
+
import { $ as SerializingMemoryStore, A as LifecycleHook, B as RUN_SNAPSHOT_SCHEMA_VERSION, C as FullDisclosureRouter, Ct as normalizeToolContent, D as HookRunnerOptions, Dt as toLlmToolSpec, E as HookRunner, Et as schemaToForm, F as OpenAiCompatibleClientConfig, G as RunTerminationReason, H as RunResult, I as ProgressiveRouter, J as RuntimeSession, K as RuntimePhase, L as READ_SKILL_FILE_INPUT_SCHEMA, M as LifecycleListener, N as NetworkPolicy, O as InstalledSkillManifest, Ot as toVercelToolSpecs, P as OpenAiCompatibleClient, Q as ScriptExecutor, R as READ_SKILL_FILE_TOOL, S as FsRunSnapshotStore, St as networkUrlHost, T as GoogleGenAiClientConfig, Tt as resolveToolName, U as RunSnapshot, V as RouteResult, W as RunSnapshotStore, X as SchemaInferer, Y as RuntimeSessionHandle, Z as ScriptExecutionContext, _ as EventBus, _t as extractChartSpec, a as AgentLoopConfig, at as TraceClock, b as FsArtifactStore, bt as isNetworkAllowed, c as AnthropicClientConfig, ct as TraceRecorder, d as BridgeCapabilities, dt as WebSkillRuntime, et as SkillRouter, f as BridgeCapability, ft as WebSkillRuntimeDeps, g as CapabilityMode, gt as createWebSkillApi, h as CapabilityApproval, ht as createScriptContext, i as AgentLoop, it as ToolResult, j as LifecycleHookContext, k as LifecycleEvent, l as ApprovalDecision, lt as VercelToolSpec, m as BridgeResponse, mt as buildRenderResult, n as ASK_USER_TOOL, nt as ToolDefinition, o as AgentLoopDeps, ot as TraceEvent, p as BridgeRequest, pt as bridgeError, q as RuntimeRun, r as ASK_USER_TOOL_NAME, rt as ToolResolution, s as AnthropicClient, st as TraceEventType, t as ASK_USER_INPUT_SCHEMA, tt as SkillStateGuard, u as ApprovalScope, ut as WebSkillApi, v as ExternalSkillProvider, vt as fromVercelResult, w as GoogleGenAiClient, wt as parseBridgeRequest, x as FsMemoryStore, xt as mergeCatalogEntries, y as ExternalToolSource, yt as fromVercelStreamPart, z as READ_SKILL_FILE_TOOL_NAME } from "./index-gjFuBevI.js";
|
|
3
3
|
export { ASK_USER_INPUT_SCHEMA, ASK_USER_TOOL, ASK_USER_TOOL_NAME, AgentLoop, type AgentLoopConfig, type AgentLoopDeps, AnthropicClient, type AnthropicClientConfig, type ApprovalDecision, type ApprovalScope, type ArchiveLimits, type Artifact, type ArtifactStore, type BridgeCapabilities, type BridgeCapability, type BridgeRequest, type BridgeResponse, CapabilityApproval, type CapabilityMode, type CatalogRenderer, type ChartSpec, DEFAULT_ARCHIVE_LIMITS, type DiscoveryResult, EventBus, type ExternalSkillProvider, type ExternalToolSource, type FileStat, type FileSystemProvider, type FormField, FsArtifactStore, FsMemoryStore, FsRunSnapshotStore, FullDisclosureRouter, GoogleGenAiClient, type GoogleGenAiClientConfig, HookRunner, type HookRunnerOptions, type InstalledSkillManifest, type InteractionPolicy, type InteractionRequest, type InteractionResponse, type JsonSchema, type LifecycleEvent, type LifecycleHook, type LifecycleHookContext, type LifecycleListener, type LlmClient, type LlmCompleteInput, type LlmMessage, type LlmResponse, type LlmStreamEvent, type LlmToolCall, type LlmToolSpec, MemoryFS, type MemoryStore, type NetworkPolicy, OpenAiCompatibleClient, type OpenAiCompatibleClientConfig, ProgressiveRouter, READ_SKILL_FILE_INPUT_SCHEMA, READ_SKILL_FILE_TOOL, READ_SKILL_FILE_TOOL_NAME, RUN_SNAPSHOT_SCHEMA_VERSION, type RenderBlock, type RenderResultRequest, type RouteResult, type RunResult, type RunSnapshot, type RunSnapshotStore, type RunTerminationReason, type RuntimePhase, type RuntimeRun, type RuntimeSession, type RuntimeSessionHandle, SKILLS_LOCKFILE, SKILL_MANIFEST_FILE, SKILL_NAME_MAX_LENGTH, SKILL_NAME_PATTERN, SKILL_PACK_FILE, type SchemaInferer, type ScriptExecutionContext, type ScriptExecutor, SerializingMemoryStore, type SkillCatalog, type SkillCatalogEntry, SkillDiscovery, type SkillDocument, type SkillInstallSource, type SkillIssue, type SkillLocation, type SkillManifest, type SkillMetadata, type SkillPackManifest, SkillReader, type SkillRouter, type SkillSource, type SkillStateGuard, type SkillsLockfile, type ToolDefinition, type ToolResolution, type ToolResult, type TraceClock, type TraceEvent, type TraceEventType, TraceRecorder, type UiBridge, type ValidationReport, type VercelToolSpec, type VerifyResult, type WebSkillApi, WebSkillError, type WebSkillErrorCode, WebSkillRuntime, type WebSkillRuntimeDeps, assertSafePathSegment, atomicWriteText, bridgeError, buildCatalog, buildManifest, buildRenderResult, checkDependencyCycles, checkSkillRules, computeDigest, createScriptContext, createWebSkillApi, escapeXml, exportSkills, extractChartSpec, fromVercelResult, fromVercelStreamPart, isNetworkAllowed, isValidSkillName, jsonRenderer, mergeCatalogEntries, networkUrlHost, normalizePath, normalizeToolContent, parseBridgeRequest, parseSkillMarkdown, parseSkillPackManifest, readResponseWithLimit, renderAvailableSkillsXml, renderCatalogJson, resolveArchiveLimits, resolveInsideRoot, resolveToolName, schemaToForm, toLlmToolSpec, toVercelToolSpecs, unzipWithLimits, validateSkills, verifyManifest, xmlRenderer };
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { A as unzipWithLimits, C as parseSkillMarkdown, D as renderCatalogJson, E as renderAvailableSkillsXml, M as verifyManifest, N as xmlRenderer, O as resolveArchiveLimits, S as normalizePath, T as readResponseWithLimit, _ as computeDigest, a as SKILL_NAME_MAX_LENGTH, b as isValidSkillName, c as SkillDiscovery, d as assertSafePathSegment, f as atomicWriteText, g as checkSkillRules, h as checkDependencyCycles, i as SKILL_MANIFEST_FILE, j as validateSkills, k as resolveInsideRoot, l as SkillReader, m as buildManifest, n as MemoryFS, o as SKILL_NAME_PATTERN, p as buildCatalog, r as SKILLS_LOCKFILE, s as SKILL_PACK_FILE, t as DEFAULT_ARCHIVE_LIMITS, u as WebSkillError, v as escapeXml, w as parseSkillPackManifest, x as jsonRenderer, y as exportSkills } from "./dist-D0saNPi_.js";
|
|
2
|
-
import { A as isNetworkAllowed, C as bridgeError, D as extractChartSpec, E as createWebSkillApi, F as resolveToolName, I as schemaToForm, L as toLlmToolSpec, M as networkUrlHost, N as normalizeToolContent, O as fromVercelResult, P as parseBridgeRequest, R as toVercelToolSpecs, S as WebSkillRuntime, T as createScriptContext, _ as READ_SKILL_FILE_TOOL, a as AnthropicClient, b as SerializingMemoryStore, c as FsArtifactStore, d as FullDisclosureRouter, f as GoogleGenAiClient, g as READ_SKILL_FILE_INPUT_SCHEMA, h as ProgressiveRouter, i as AgentLoop, j as mergeCatalogEntries, k as fromVercelStreamPart, l as FsMemoryStore, m as OpenAiCompatibleClient, n as ASK_USER_TOOL, o as CapabilityApproval, p as HookRunner, r as ASK_USER_TOOL_NAME, s as EventBus, t as ASK_USER_INPUT_SCHEMA, u as FsRunSnapshotStore, v as READ_SKILL_FILE_TOOL_NAME, w as buildRenderResult, x as TraceRecorder, y as RUN_SNAPSHOT_SCHEMA_VERSION } from "./dist-
|
|
2
|
+
import { A as isNetworkAllowed, C as bridgeError, D as extractChartSpec, E as createWebSkillApi, F as resolveToolName, I as schemaToForm, L as toLlmToolSpec, M as networkUrlHost, N as normalizeToolContent, O as fromVercelResult, P as parseBridgeRequest, R as toVercelToolSpecs, S as WebSkillRuntime, T as createScriptContext, _ as READ_SKILL_FILE_TOOL, a as AnthropicClient, b as SerializingMemoryStore, c as FsArtifactStore, d as FullDisclosureRouter, f as GoogleGenAiClient, g as READ_SKILL_FILE_INPUT_SCHEMA, h as ProgressiveRouter, i as AgentLoop, j as mergeCatalogEntries, k as fromVercelStreamPart, l as FsMemoryStore, m as OpenAiCompatibleClient, n as ASK_USER_TOOL, o as CapabilityApproval, p as HookRunner, r as ASK_USER_TOOL_NAME, s as EventBus, t as ASK_USER_INPUT_SCHEMA, u as FsRunSnapshotStore, v as READ_SKILL_FILE_TOOL_NAME, w as buildRenderResult, x as TraceRecorder, y as RUN_SNAPSHOT_SCHEMA_VERSION } from "./dist-DrySSQ5R.js";
|
|
3
3
|
|
|
4
4
|
export { ASK_USER_INPUT_SCHEMA, ASK_USER_TOOL, ASK_USER_TOOL_NAME, AgentLoop, AnthropicClient, CapabilityApproval, DEFAULT_ARCHIVE_LIMITS, EventBus, FsArtifactStore, FsMemoryStore, FsRunSnapshotStore, FullDisclosureRouter, GoogleGenAiClient, HookRunner, MemoryFS, OpenAiCompatibleClient, ProgressiveRouter, READ_SKILL_FILE_INPUT_SCHEMA, READ_SKILL_FILE_TOOL, READ_SKILL_FILE_TOOL_NAME, RUN_SNAPSHOT_SCHEMA_VERSION, SKILLS_LOCKFILE, SKILL_MANIFEST_FILE, SKILL_NAME_MAX_LENGTH, SKILL_NAME_PATTERN, SKILL_PACK_FILE, SerializingMemoryStore, SkillDiscovery, SkillReader, TraceRecorder, WebSkillError, WebSkillRuntime, assertSafePathSegment, atomicWriteText, bridgeError, buildCatalog, buildManifest, buildRenderResult, checkDependencyCycles, checkSkillRules, computeDigest, createScriptContext, createWebSkillApi, escapeXml, exportSkills, extractChartSpec, fromVercelResult, fromVercelStreamPart, isNetworkAllowed, isValidSkillName, jsonRenderer, mergeCatalogEntries, networkUrlHost, normalizePath, normalizeToolContent, parseBridgeRequest, parseSkillMarkdown, parseSkillPackManifest, readResponseWithLimit, renderAvailableSkillsXml, renderCatalogJson, resolveArchiveLimits, resolveInsideRoot, resolveToolName, schemaToForm, toLlmToolSpec, toVercelToolSpecs, unzipWithLimits, validateSkills, verifyManifest, xmlRenderer };
|
package/dist/mcp.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { F as SkillDocument, N as SkillCatalogEntry, T as JsonSchema, m as LlmToolSpec } from "./types-CKm5G_eQ-8W8FnP4u.js";
|
|
2
|
-
import { it as ToolResult, v as ExternalSkillProvider, xt as mergeCatalogEntries, y as ExternalToolSource } from "./index-
|
|
2
|
+
import { it as ToolResult, v as ExternalSkillProvider, xt as mergeCatalogEntries, y as ExternalToolSource } from "./index-gjFuBevI.js";
|
|
3
3
|
import { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
|
|
4
4
|
import { JSONRPCMessage } from "@modelcontextprotocol/sdk/types.js";
|
|
5
5
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
package/dist/mcp.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { u as WebSkillError } from "./dist-D0saNPi_.js";
|
|
2
|
-
import { N as normalizeToolContent, j as mergeCatalogEntries } from "./dist-
|
|
2
|
+
import { N as normalizeToolContent, j as mergeCatalogEntries } from "./dist-DrySSQ5R.js";
|
|
3
3
|
|
|
4
4
|
//#region ../mcp/dist/index.js
|
|
5
5
|
/**
|
package/dist/node.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { D as SKILLS_LOCKFILE, I as SkillInstallSource, K as VerifyResult, O as SKILL_MANIFEST_FILE, W as SkillsLockfile, z as SkillManifest } from "./types-CKm5G_eQ-8W8FnP4u.js";
|
|
2
|
-
import { ht as createScriptContext } from "./index-
|
|
2
|
+
import { ht as createScriptContext } from "./index-gjFuBevI.js";
|
|
3
3
|
import { n as LlmEnvConfig, s as probeLlmCapabilities, t as LlmCapabilities } from "./env-BPUBZCwJ-4jat_SVG.js";
|
|
4
|
-
import { a as NodeScriptExecutor, c as
|
|
5
|
-
export { CliUiBridge, FileArtifactStore, FileMemoryStore, type LlmCapabilities, type LlmEnvConfig, NodeFS, NodeScriptExecutor, OxcSchemaInferer, SKILLS_LOCKFILE, SKILL_MANIFEST_FILE, type SandboxOptions, SandboxedScriptExecutor, type SkillInstallSource, SkillManager, type SkillManifest, type SkillsLockfile, type VerifyResult, createScriptContext, exportArchive, probeLlmCapabilities, readArchiveManifest };
|
|
4
|
+
import { a as NodeScriptExecutor, c as ProcessSandboxOptions, d as SkillManager, f as exportArchive, i as NodeFS, l as SandboxOptions, n as FileArtifactStore, o as OxcSchemaInferer, p as readArchiveManifest, r as FileMemoryStore, s as ProcessSandboxExecutor, t as CliUiBridge, u as SandboxedScriptExecutor } from "./index-BmzysJX5.js";
|
|
5
|
+
export { CliUiBridge, FileArtifactStore, FileMemoryStore, type LlmCapabilities, type LlmEnvConfig, NodeFS, NodeScriptExecutor, OxcSchemaInferer, ProcessSandboxExecutor, type ProcessSandboxOptions, SKILLS_LOCKFILE, SKILL_MANIFEST_FILE, type SandboxOptions, SandboxedScriptExecutor, type SkillInstallSource, SkillManager, type SkillManifest, type SkillsLockfile, type VerifyResult, createScriptContext, exportArchive, probeLlmCapabilities, readArchiveManifest };
|
package/dist/node.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { i as SKILL_MANIFEST_FILE, r as SKILLS_LOCKFILE } from "./dist-D0saNPi_.js";
|
|
2
|
-
import { T as createScriptContext } from "./dist-
|
|
2
|
+
import { T as createScriptContext } from "./dist-DrySSQ5R.js";
|
|
3
3
|
import { i as probeLlmCapabilities } from "./env--jJB-TSX-04klhTYi.js";
|
|
4
|
-
import { a as NodeScriptExecutor, c as
|
|
4
|
+
import { a as NodeScriptExecutor, c as SandboxedScriptExecutor, d as readArchiveManifest, i as NodeFS, l as SkillManager, n as FileArtifactStore, o as OxcSchemaInferer, r as FileMemoryStore, s as ProcessSandboxExecutor, t as CliUiBridge, u as exportArchive } from "./dist-BRGQcLqR.js";
|
|
5
5
|
|
|
6
|
-
export { CliUiBridge, FileArtifactStore, FileMemoryStore, NodeFS, NodeScriptExecutor, OxcSchemaInferer, SKILLS_LOCKFILE, SKILL_MANIFEST_FILE, SandboxedScriptExecutor, SkillManager, createScriptContext, exportArchive, probeLlmCapabilities, readArchiveManifest };
|
|
6
|
+
export { CliUiBridge, FileArtifactStore, FileMemoryStore, NodeFS, NodeScriptExecutor, OxcSchemaInferer, ProcessSandboxExecutor, SKILLS_LOCKFILE, SKILL_MANIFEST_FILE, SandboxedScriptExecutor, SkillManager, createScriptContext, exportArchive, probeLlmCapabilities, readArchiveManifest };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { tmpdir } from "node:os";
|
|
3
|
+
import { pathToFileURL } from "node:url";
|
|
4
|
+
import { mkdtemp, rm, writeFile } from "node:fs/promises";
|
|
5
|
+
|
|
6
|
+
//#region ../node/dist/executor/processSandboxEntry.js
|
|
7
|
+
/**
|
|
8
|
+
* ProcessSandbox 子进程入口(child_process.fork + --permission)。
|
|
9
|
+
* 与 worker_threads 入口同构:任务经 workerData 等价的 argv[2] JSON 传入(fork 无 workerData,
|
|
10
|
+
* 经环境变量 PROCESS_SANDBOX_TASK 传 JSON);能力桥 RPC 经 process IPC。
|
|
11
|
+
*
|
|
12
|
+
* 权限模型(--permission,experimental)负责 fs 维度:读仅限 skillRoot(+入口目录),
|
|
13
|
+
* 写仅限 artifactDir;子进程/Worker/addons 默认禁(module.register 在其下不可用——
|
|
14
|
+
* 内部钩子线程同属 WorkerThreads,实证后已移除裸模块钩子)。网络无权限维度:
|
|
15
|
+
* 仍靠 globalThis.fetch/WebSocket patch(函数源码经任务 JSON 注入,单一来源在
|
|
16
|
+
* runtime/sandbox/networkPolicy.ts);node:net 裸模块为已知残余面(文档明示)。
|
|
17
|
+
* .js 走 data: URL 导入(permission 下实证可用);.ts 走中性临时目录 file URL。
|
|
18
|
+
*/
|
|
19
|
+
const send = (message) => {
|
|
20
|
+
process.send?.(message);
|
|
21
|
+
};
|
|
22
|
+
const pending = /* @__PURE__ */ new Map();
|
|
23
|
+
let bridgeSeq = 0;
|
|
24
|
+
function callCapability(kind, payload) {
|
|
25
|
+
const request = {
|
|
26
|
+
kind,
|
|
27
|
+
id: `br-${++bridgeSeq}`,
|
|
28
|
+
...payload
|
|
29
|
+
};
|
|
30
|
+
return new Promise((resolve, reject) => {
|
|
31
|
+
pending.set(request.id, {
|
|
32
|
+
resolve,
|
|
33
|
+
reject
|
|
34
|
+
});
|
|
35
|
+
send({
|
|
36
|
+
type: "bridge",
|
|
37
|
+
request
|
|
38
|
+
});
|
|
39
|
+
}).then((response) => {
|
|
40
|
+
const r = response;
|
|
41
|
+
if (!r.ok) {
|
|
42
|
+
const err = new Error(r.error?.message ?? "capability call failed");
|
|
43
|
+
err.code = r.error?.code ?? "TOOL_EXECUTION_FAILED";
|
|
44
|
+
throw err;
|
|
45
|
+
}
|
|
46
|
+
return r.value;
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
function blockedError(host) {
|
|
50
|
+
const err = /* @__PURE__ */ new Error(`Network request blocked by sandbox network policy: ${host}`);
|
|
51
|
+
err.code = "NETWORK_BLOCKED";
|
|
52
|
+
return err;
|
|
53
|
+
}
|
|
54
|
+
function setupNetworkGuards(task) {
|
|
55
|
+
const policy = task.networkPolicy ?? "deny-all";
|
|
56
|
+
if (!task.networkPolicyLib) return;
|
|
57
|
+
const { isNetworkAllowed, networkUrlHost } = new Function(`${task.networkPolicyLib}\nreturn { isNetworkAllowed: isNetworkAllowed, networkUrlHost: networkUrlHost };`)();
|
|
58
|
+
const gate = (rawUrl) => {
|
|
59
|
+
const url = String(rawUrl);
|
|
60
|
+
if (isNetworkAllowed(policy, url)) return null;
|
|
61
|
+
const host = networkUrlHost(url);
|
|
62
|
+
send({
|
|
63
|
+
type: "network-blocked",
|
|
64
|
+
host
|
|
65
|
+
});
|
|
66
|
+
return blockedError(host);
|
|
67
|
+
};
|
|
68
|
+
const originalFetch = globalThis["fetch"];
|
|
69
|
+
if (typeof originalFetch === "function") globalThis["fetch"] = (input, init) => {
|
|
70
|
+
const raw = typeof input === "string" ? input : input instanceof URL ? input.href : input?.url ?? String(input);
|
|
71
|
+
const blocked = gate(raw);
|
|
72
|
+
if (blocked) return Promise.reject(blocked);
|
|
73
|
+
return originalFetch(input, init);
|
|
74
|
+
};
|
|
75
|
+
const OriginalWebSocket = globalThis["WebSocket"];
|
|
76
|
+
if (typeof OriginalWebSocket === "function") globalThis["WebSocket"] = class extends OriginalWebSocket {
|
|
77
|
+
constructor(url, protocols) {
|
|
78
|
+
const blocked = gate(String(url));
|
|
79
|
+
if (blocked) throw blocked;
|
|
80
|
+
super(url, protocols);
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
let task_scratchDir;
|
|
85
|
+
async function loadModule(scriptPath, scriptSource) {
|
|
86
|
+
if (scriptPath.endsWith(".js") && scriptSource !== void 0) return await import(`data:text/javascript;charset=utf-8,${encodeURIComponent(`${scriptSource}\n//# ${Date.now()}`)}`);
|
|
87
|
+
if (scriptPath.endsWith(".ts") && scriptSource !== void 0) {
|
|
88
|
+
const base = task_scratchDir ?? await mkdtemp(path.join(tmpdir(), "webskill-psbx-ts-"));
|
|
89
|
+
const dir = await mkdtemp(path.join(base, "ts-"));
|
|
90
|
+
try {
|
|
91
|
+
const file = path.join(dir, "script.ts");
|
|
92
|
+
await writeFile(file, scriptSource);
|
|
93
|
+
return await import(`${pathToFileURL(file).href}?t=${Date.now()}`);
|
|
94
|
+
} finally {
|
|
95
|
+
await rm(dir, {
|
|
96
|
+
recursive: true,
|
|
97
|
+
force: true
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return await import(`${pathToFileURL(scriptPath).href}?t=${Date.now()}`);
|
|
102
|
+
}
|
|
103
|
+
async function main(task) {
|
|
104
|
+
task_scratchDir = task.scratchDir;
|
|
105
|
+
setupNetworkGuards(task);
|
|
106
|
+
process.on("message", (msg) => {
|
|
107
|
+
if (msg?.type === "bridge-response" && msg.response?.id) {
|
|
108
|
+
const entry = pending.get(msg.response.id);
|
|
109
|
+
if (entry) {
|
|
110
|
+
pending.delete(msg.response.id);
|
|
111
|
+
entry.resolve(msg.response);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
if (task.mode === "load") {
|
|
116
|
+
try {
|
|
117
|
+
const mod = await loadModule(task.scriptPath, task.scriptSource);
|
|
118
|
+
send({
|
|
119
|
+
type: "load-result",
|
|
120
|
+
ok: true,
|
|
121
|
+
definition: {
|
|
122
|
+
description: typeof mod["description"] === "string" ? mod["description"] : void 0,
|
|
123
|
+
inputSchema: mod["inputSchema"] !== void 0 ? mod["inputSchema"] : void 0,
|
|
124
|
+
hasRun: typeof mod["run"] === "function"
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
} catch (e) {
|
|
128
|
+
const err = e;
|
|
129
|
+
send({
|
|
130
|
+
type: "load-result",
|
|
131
|
+
ok: false,
|
|
132
|
+
error: {
|
|
133
|
+
code: err?.code ?? "TOOL_EXECUTION_FAILED",
|
|
134
|
+
message: String(err?.message ?? e)
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
const stdout = [];
|
|
141
|
+
const stderr = [];
|
|
142
|
+
const originals = {
|
|
143
|
+
log: console.log,
|
|
144
|
+
info: console.info,
|
|
145
|
+
debug: console.debug,
|
|
146
|
+
warn: console.warn,
|
|
147
|
+
error: console.error
|
|
148
|
+
};
|
|
149
|
+
console.log = console.info = console.debug = (...args) => stdout.push(args.map(String).join(" "));
|
|
150
|
+
console.warn = console.error = (...args) => stderr.push(args.map(String).join(" "));
|
|
151
|
+
try {
|
|
152
|
+
const mod = await loadModule(task.scriptPath, task.scriptSource);
|
|
153
|
+
if (typeof mod["run"] !== "function") throw new Error("Script does not export a run function");
|
|
154
|
+
const context = {
|
|
155
|
+
skillName: task.skillName ?? "",
|
|
156
|
+
runId: task.runId ?? "",
|
|
157
|
+
readReference: (path) => callCapability("readReference", { path }),
|
|
158
|
+
writeArtifact: (path, content, options) => callCapability("writeArtifact", {
|
|
159
|
+
path,
|
|
160
|
+
content: typeof content === "string" ? content : Array.from(content ?? []),
|
|
161
|
+
mimeType: options?.mimeType
|
|
162
|
+
}),
|
|
163
|
+
confirm: (message) => callCapability("confirm", { message })
|
|
164
|
+
};
|
|
165
|
+
const runFn = mod["run"];
|
|
166
|
+
const value = await runFn(task.args ?? {}, context);
|
|
167
|
+
send({
|
|
168
|
+
type: "execute-result",
|
|
169
|
+
ok: true,
|
|
170
|
+
value: value === void 0 ? null : value,
|
|
171
|
+
stdout,
|
|
172
|
+
stderr
|
|
173
|
+
});
|
|
174
|
+
} catch (e) {
|
|
175
|
+
const err = e;
|
|
176
|
+
send({
|
|
177
|
+
type: "execute-result",
|
|
178
|
+
ok: false,
|
|
179
|
+
error: {
|
|
180
|
+
code: err?.code ?? "TOOL_EXECUTION_FAILED",
|
|
181
|
+
message: String(err?.message ?? e)
|
|
182
|
+
},
|
|
183
|
+
stdout,
|
|
184
|
+
stderr
|
|
185
|
+
});
|
|
186
|
+
} finally {
|
|
187
|
+
console.log = originals.log;
|
|
188
|
+
console.info = originals.info;
|
|
189
|
+
console.debug = originals.debug;
|
|
190
|
+
console.warn = originals.warn;
|
|
191
|
+
console.error = originals.error;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
process.on("message", (msg) => {
|
|
195
|
+
if (msg?.type === "task" && msg.task) main(msg.task).then(() => process.exit(0), (e) => {
|
|
196
|
+
console.error(e);
|
|
197
|
+
process.exit(1);
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
//#endregion
|
|
202
|
+
export { };
|
package/dist/ui.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { _ as RenderResultRequest, g as RenderBlock, o as InteractionRequest, r as ChartSpec, s as InteractionResponse, v as UiBridge } from "./types-CKm5G_eQ-8W8FnP4u.js";
|
|
2
|
-
import { mt as buildRenderResult } from "./index-
|
|
2
|
+
import { mt as buildRenderResult } from "./index-gjFuBevI.js";
|
|
3
3
|
//#region ../ui/dist/index.d.ts
|
|
4
4
|
//#region src/model/formModel.d.ts
|
|
5
5
|
interface FormModel {
|
package/dist/ui.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { w as buildRenderResult } from "./dist-
|
|
1
|
+
import { w as buildRenderResult } from "./dist-DrySSQ5R.js";
|
|
2
2
|
import { C as renderRenderResult, D as toVercelToolInvocation, E as toOpenUiLang, S as renderMiniMarkdown, T as toA2uiMessages, _ as fromOpenUiAction, a as CHART_PALETTE, b as renderBlocks, c as OPENUI_SUBMIT_ACTION, d as WEBSKILL_STYLES_CSS, f as WebFormBridge, g as fromA2uiAction, h as ensureStyles, i as A2UI_VERSION, l as VERCEL_INTERACTION_TOOL_NAME, m as collectValues, n as A2UI_CANCEL_ACTION, o as LitRendererBridge, p as chartToTable, r as A2UI_SUBMIT_ACTION, s as OPENUI_CANCEL_ACTION, t as A2UI_BASIC_CATALOG_ID, u as VercelUiBridge, v as fromVercelToolResult, w as shapeInteractionValue, x as renderMiniChart, y as interactionToFormModel } from "./dist-BJobG0i-.js";
|
|
3
3
|
|
|
4
4
|
export { A2UI_BASIC_CATALOG_ID, A2UI_CANCEL_ACTION, A2UI_SUBMIT_ACTION, A2UI_VERSION, CHART_PALETTE, LitRendererBridge, OPENUI_CANCEL_ACTION, OPENUI_SUBMIT_ACTION, VERCEL_INTERACTION_TOOL_NAME, VercelUiBridge, WEBSKILL_STYLES_CSS, WebFormBridge, buildRenderResult, chartToTable, collectValues, ensureStyles, fromA2uiAction, fromOpenUiAction, fromVercelToolResult, interactionToFormModel, renderBlocks, renderMiniChart, renderMiniMarkdown, renderRenderResult, shapeInteractionValue, toA2uiMessages, toOpenUiLang, toVercelToolInvocation };
|