@webskill/sdk 0.2.2 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -0
- package/dist/browser.d.ts +7 -5
- package/dist/browser.js +49 -24
- package/dist/{dist-Cn9GpW6Q.js → dist-CvIMVwr3.js} +9 -4
- package/dist/{dist-DrySSQ5R.js → dist-NM4Mylx4.js} +13 -3
- package/dist/governance.d.ts +5 -3
- package/dist/governance.js +6 -4
- package/dist/{index-BmzysJX5.d.ts → index-iqcz3_NS.d.ts} +6 -2
- package/dist/index.js +1 -1
- package/dist/mcp.js +1 -1
- package/dist/node.d.ts +1 -1
- package/dist/node.js +2 -2
- package/dist/sandboxWorkerEntry.js +23 -2
- package/dist/ui.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -16,6 +16,7 @@ governance.
|
|
|
16
16
|
(missing-parameter forms, confirmations, authorization prompts), and
|
|
17
17
|
resumable interrupted runs.
|
|
18
18
|
- **Script sandbox** — two tiers. Isolation-grade: Node `ProcessSandboxExecutor`
|
|
19
|
+
(fork + `--permission`, real process isolation).
|
|
19
20
|
(`child_process.fork` + `--permission`, experimental; fs scoped to the skill
|
|
20
21
|
root, workers/child processes/addons denied by default — note the permission
|
|
21
22
|
model has NO network dimension, so `fetch`/`WebSocket` stay patch-enforced and
|
|
@@ -25,6 +26,9 @@ governance.
|
|
|
25
26
|
tier (NOT a security boundary): `SandboxedScriptExecutor` /
|
|
26
27
|
`BrowserWorkerScriptExecutor` in blob-Worker mode, with deny-by-default
|
|
27
28
|
network policy, builtin-module allowlist, forced approval, timeouts.
|
|
29
|
+
Known proactive escape hatches (`process.binding`, `dlopen`, `abort`, …) are
|
|
30
|
+
stripped in the worker entry (0.2.3); other host-shared surfaces are NOT
|
|
31
|
+
defended — use `ProcessSandboxExecutor` for untrusted skills.
|
|
28
32
|
- **`navigator.webskill`** — a browser facade (`discover` / `read` / `validate` /
|
|
29
33
|
`run` / `install` / `uninstall`) assembled explicitly in one call.
|
|
30
34
|
- **MCP** — call page-provided tools and consume page-declared dynamic skills
|
package/dist/browser.d.ts
CHANGED
|
@@ -164,14 +164,16 @@ declare class BrowserWorkerScriptExecutor implements ScriptExecutor {
|
|
|
164
164
|
//#region src/executor/iframeSandbox.d.ts
|
|
165
165
|
/**
|
|
166
166
|
* opaque origin 沙箱 iframe(sandbox="allow-scripts" srcdoc):
|
|
167
|
-
* iframe 内建
|
|
168
|
-
* opaque origin:沙箱内摸不到页面 DOM/localStorage/OPFS
|
|
169
|
-
*
|
|
167
|
+
* iframe 内建 classic Worker(Blob URL;module Worker 在 opaque origin 不可加载,实证),
|
|
168
|
+
* iframe window 作 postMessage 中继。opaque origin:沙箱内摸不到页面 DOM/localStorage/OPFS。
|
|
169
|
+
* 通道鉴别(P0-C):每实例 channelId 随消息携带,宿主校验 event.source 与 channelId,
|
|
170
|
+
* 同页伪造消息一律丢弃;terminate 摘除监听器。
|
|
170
171
|
*/
|
|
171
172
|
declare class IframeWorkerLike implements WorkerLike {
|
|
172
173
|
#private;
|
|
173
|
-
constructor(iframe: HTMLIFrameElement);
|
|
174
|
+
constructor(iframe: HTMLIFrameElement, hostWindow: Window, channelId: string);
|
|
174
175
|
get ready(): boolean;
|
|
176
|
+
get channelId(): string;
|
|
175
177
|
markReady(): void;
|
|
176
178
|
postMessage(data: unknown): void;
|
|
177
179
|
addEventListener(_type: 'message', listener: (event: {
|
|
@@ -181,7 +183,7 @@ declare class IframeWorkerLike implements WorkerLike {
|
|
|
181
183
|
terminate(): void;
|
|
182
184
|
}
|
|
183
185
|
/**
|
|
184
|
-
* 创建 opaque iframe 沙箱 Worker:sandbox="allow-scripts" srcdoc iframe 承载
|
|
186
|
+
* 创建 opaque iframe 沙箱 Worker:sandbox="allow-scripts" srcdoc iframe 承载 classic Worker。
|
|
185
187
|
* 返回 IframeWorkerLike(协议与 blob Worker 完全一致:load/execute/bridge/network-blocked)。
|
|
186
188
|
*/
|
|
187
189
|
declare function createIframeWorker(bootstrapSource: string, doc?: Document): IframeWorkerLike;
|
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-NM4Mylx4.js";
|
|
3
3
|
import { n as MockLlmClient } from "./testing-B4pq6JYa.js";
|
|
4
4
|
|
|
5
5
|
//#region ../browser/dist/index.js
|
|
@@ -714,22 +714,38 @@ var BrowserSkillManager = class {
|
|
|
714
714
|
}
|
|
715
715
|
};
|
|
716
716
|
const ENVELOPE = "__webskill_sandbox__";
|
|
717
|
+
let channelSeq = 0;
|
|
718
|
+
/** 每实例 channelId(防同页伪造消息注入;crypto.randomUUID 优先,无则随机回退) */
|
|
719
|
+
function nextChannelId() {
|
|
720
|
+
return globalThis.crypto?.randomUUID?.() ?? `ch-${Date.now()}-${Math.random().toString(36).slice(2, 10)}-${++channelSeq}`;
|
|
721
|
+
}
|
|
717
722
|
/**
|
|
718
723
|
* opaque origin 沙箱 iframe(sandbox="allow-scripts" srcdoc):
|
|
719
|
-
* iframe 内建
|
|
720
|
-
* opaque origin:沙箱内摸不到页面 DOM/localStorage/OPFS
|
|
721
|
-
*
|
|
724
|
+
* iframe 内建 classic Worker(Blob URL;module Worker 在 opaque origin 不可加载,实证),
|
|
725
|
+
* iframe window 作 postMessage 中继。opaque origin:沙箱内摸不到页面 DOM/localStorage/OPFS。
|
|
726
|
+
* 通道鉴别(P0-C):每实例 channelId 随消息携带,宿主校验 event.source 与 channelId,
|
|
727
|
+
* 同页伪造消息一律丢弃;terminate 摘除监听器。
|
|
722
728
|
*/
|
|
723
729
|
var IframeWorkerLike = class {
|
|
724
730
|
#iframe;
|
|
725
731
|
#ready = false;
|
|
726
732
|
#queue = [];
|
|
727
|
-
|
|
733
|
+
#channelId;
|
|
734
|
+
#hostWindow;
|
|
735
|
+
#hostListener;
|
|
736
|
+
constructor(iframe, hostWindow, channelId) {
|
|
728
737
|
this.#iframe = iframe;
|
|
738
|
+
this.#hostWindow = hostWindow;
|
|
739
|
+
this.#channelId = channelId;
|
|
740
|
+
this.#hostListener = (event) => this.#onMessage(event);
|
|
741
|
+
this.#hostWindow.addEventListener("message", this.#hostListener);
|
|
729
742
|
}
|
|
730
743
|
get ready() {
|
|
731
744
|
return this.#ready;
|
|
732
745
|
}
|
|
746
|
+
get channelId() {
|
|
747
|
+
return this.#channelId;
|
|
748
|
+
}
|
|
733
749
|
markReady() {
|
|
734
750
|
this.#ready = true;
|
|
735
751
|
for (const payload of this.#queue) this.#post(payload);
|
|
@@ -738,9 +754,21 @@ var IframeWorkerLike = class {
|
|
|
738
754
|
#post(payload) {
|
|
739
755
|
this.#iframe.contentWindow?.postMessage({
|
|
740
756
|
[ENVELOPE]: true,
|
|
757
|
+
channelId: this.#channelId,
|
|
741
758
|
payload
|
|
742
759
|
}, "*");
|
|
743
760
|
}
|
|
761
|
+
/** 通道鉴别:source 必须是本 iframe 的 contentWindow 且 channelId 匹配,否则丢弃 */
|
|
762
|
+
#onMessage(event) {
|
|
763
|
+
if (event.source !== this.#iframe.contentWindow) return;
|
|
764
|
+
const data = event.data;
|
|
765
|
+
if (!data || data[ENVELOPE] !== true || data.channelId !== this.#channelId) return;
|
|
766
|
+
if (data.payload && data.payload.type === "sandbox-ready") {
|
|
767
|
+
this.markReady();
|
|
768
|
+
return;
|
|
769
|
+
}
|
|
770
|
+
this.emit(data.payload);
|
|
771
|
+
}
|
|
744
772
|
postMessage(data) {
|
|
745
773
|
if (this.#ready) this.#post(data);
|
|
746
774
|
else this.#queue.push(data);
|
|
@@ -753,15 +781,17 @@ var IframeWorkerLike = class {
|
|
|
753
781
|
for (const listener of this.#listeners) listener({ data });
|
|
754
782
|
}
|
|
755
783
|
terminate() {
|
|
784
|
+
this.#hostWindow.removeEventListener("message", this.#hostListener);
|
|
756
785
|
this.#iframe.remove();
|
|
757
786
|
}
|
|
758
787
|
};
|
|
759
788
|
/** srcdoc 文档:内嵌 Worker 引导源码 + 双向中继(BOOTSTRAP 经 JSON 字符串注入,防 <\/script> 截断) */
|
|
760
|
-
function sandboxDocument(bootstrapSource) {
|
|
789
|
+
function sandboxDocument(bootstrapSource, channelId) {
|
|
761
790
|
const bootstrapJson = JSON.stringify(bootstrapSource).replace(/<\//g, "<\\/");
|
|
762
791
|
return `<!doctype html>
|
|
763
792
|
<html><head><meta charset="utf-8"></head><body><script>
|
|
764
793
|
const ENVELOPE = ${JSON.stringify(ENVELOPE)};
|
|
794
|
+
const CHANNEL_ID = ${JSON.stringify(channelId)};
|
|
765
795
|
const blob = new Blob([${bootstrapJson}], { type: 'text/javascript' });
|
|
766
796
|
const url = URL.createObjectURL(blob);
|
|
767
797
|
// 注意:opaque origin 下 module Worker 无法加载(实证),classic Worker + data: URL 动态导入可用
|
|
@@ -769,36 +799,29 @@ const worker = new Worker(url);
|
|
|
769
799
|
URL.revokeObjectURL(url);
|
|
770
800
|
window.addEventListener('message', (event) => {
|
|
771
801
|
const data = event.data;
|
|
772
|
-
|
|
802
|
+
// 中继同样校验 channelId(同页脚本无法伪造实例 id)
|
|
803
|
+
if (data && data[ENVELOPE] && data.channelId === CHANNEL_ID) worker.postMessage(data.payload);
|
|
773
804
|
});
|
|
774
805
|
worker.addEventListener('message', (event) => {
|
|
775
|
-
parent.postMessage({ [ENVELOPE]: true, payload: event.data }, '*');
|
|
806
|
+
parent.postMessage({ [ENVELOPE]: true, channelId: CHANNEL_ID, payload: event.data }, '*');
|
|
776
807
|
});
|
|
777
808
|
worker.addEventListener('error', (event) => {
|
|
778
|
-
parent.postMessage({ [ENVELOPE]: true, payload: { type: 'sandbox-worker-error', message: event.message } }, '*');
|
|
809
|
+
parent.postMessage({ [ENVELOPE]: true, channelId: CHANNEL_ID, payload: { type: 'sandbox-worker-error', message: event.message } }, '*');
|
|
779
810
|
});
|
|
780
|
-
parent.postMessage({ [ENVELOPE]: true, payload: { type: 'sandbox-ready' } }, '*');
|
|
811
|
+
parent.postMessage({ [ENVELOPE]: true, channelId: CHANNEL_ID, payload: { type: 'sandbox-ready' } }, '*');
|
|
781
812
|
<\/script></body></html>`;
|
|
782
813
|
}
|
|
783
814
|
/**
|
|
784
|
-
* 创建 opaque iframe 沙箱 Worker:sandbox="allow-scripts" srcdoc iframe 承载
|
|
815
|
+
* 创建 opaque iframe 沙箱 Worker:sandbox="allow-scripts" srcdoc iframe 承载 classic Worker。
|
|
785
816
|
* 返回 IframeWorkerLike(协议与 blob Worker 完全一致:load/execute/bridge/network-blocked)。
|
|
786
817
|
*/
|
|
787
818
|
function createIframeWorker(bootstrapSource, doc = document) {
|
|
819
|
+
const channelId = nextChannelId();
|
|
788
820
|
const iframe = doc.createElement("iframe");
|
|
789
821
|
iframe.setAttribute("sandbox", "allow-scripts");
|
|
790
822
|
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
|
-
});
|
|
823
|
+
iframe.srcdoc = sandboxDocument(bootstrapSource, channelId);
|
|
824
|
+
const worker = new IframeWorkerLike(iframe, doc.defaultView ?? window, channelId);
|
|
802
825
|
doc.body.appendChild(iframe);
|
|
803
826
|
return worker;
|
|
804
827
|
}
|
|
@@ -827,6 +850,8 @@ var BrowserWorkerScriptExecutor = class {
|
|
|
827
850
|
#networkPolicy;
|
|
828
851
|
#approval;
|
|
829
852
|
#transpiler;
|
|
853
|
+
/** 消息 id 唯一递增(多实例/多执行不串) */
|
|
854
|
+
#messageSeq = 0;
|
|
830
855
|
constructor(deps) {
|
|
831
856
|
this.#fs = deps.fs;
|
|
832
857
|
this.#workerFactory = deps.workerFactory ?? resolveWorkerFactory(deps.sandbox ?? "auto");
|
|
@@ -871,7 +896,7 @@ var BrowserWorkerScriptExecutor = class {
|
|
|
871
896
|
try {
|
|
872
897
|
const data = await this.#request(worker, {
|
|
873
898
|
type: "load",
|
|
874
|
-
id:
|
|
899
|
+
id: `load-${++this.#messageSeq}`,
|
|
875
900
|
source: script.source,
|
|
876
901
|
networkPolicy: this.#networkPolicy
|
|
877
902
|
});
|
|
@@ -906,7 +931,7 @@ var BrowserWorkerScriptExecutor = class {
|
|
|
906
931
|
try {
|
|
907
932
|
const response = await this.#request(worker, {
|
|
908
933
|
type: "execute",
|
|
909
|
-
id:
|
|
934
|
+
id: `exec-${++this.#messageSeq}`,
|
|
910
935
|
skillName: context.skillName,
|
|
911
936
|
runId: context.runId,
|
|
912
937
|
source: script.source,
|
|
@@ -1,5 +1,5 @@
|
|
|
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-NM4Mylx4.js";
|
|
3
3
|
import { createRequire } from "node:module";
|
|
4
4
|
import { unzipSync, zipSync } from "fflate";
|
|
5
5
|
import { existsSync, promises, realpathSync } from "node:fs";
|
|
@@ -303,8 +303,10 @@ function workerEntryPath() {
|
|
|
303
303
|
* 能力桥协议与浏览器同一来源(runtime/sandbox/bridgeProtocol)。
|
|
304
304
|
*
|
|
305
305
|
* 诚实标注:本执行器做的是**能力面收敛**(网络策略、模块 allowlist、资源限额、
|
|
306
|
-
* 超时强杀),**不是安全边界**——Worker
|
|
307
|
-
*
|
|
306
|
+
* 超时强杀),**不是安全边界**——Worker 内脚本与宿主共享进程;
|
|
307
|
+
* 已知主动逃逸面(process.binding/_linkedBinding/dlopen/openStdin/reallyExit/abort)
|
|
308
|
+
* 已在入口删除(0.2.3),常规 import 拦截之外不承诺防御其它宿主共享面;
|
|
309
|
+
* 禁止假定其可隔离不可信脚本(隔离级需求用 ProcessSandboxExecutor)。
|
|
308
310
|
*/
|
|
309
311
|
var SandboxedScriptExecutor = class {
|
|
310
312
|
#fs;
|
|
@@ -644,8 +646,11 @@ var ProcessSandboxExecutor = class {
|
|
|
644
646
|
...readAllow(artifactDir),
|
|
645
647
|
...writeAllow(artifactDir)
|
|
646
648
|
],
|
|
647
|
-
|
|
649
|
+
env: Object.fromEntries((this.#options.envWhitelist ?? []).filter((key) => process.env[key] !== void 0).map((key) => [key, process.env[key]])),
|
|
650
|
+
silent: true
|
|
648
651
|
});
|
|
652
|
+
child.stdout?.resume();
|
|
653
|
+
child.stderr?.resume();
|
|
649
654
|
child.unref();
|
|
650
655
|
child.channel?.unref();
|
|
651
656
|
return {
|
|
@@ -1402,7 +1402,7 @@ var AgentLoop = class {
|
|
|
1402
1402
|
state.messages.push({
|
|
1403
1403
|
role: "tool",
|
|
1404
1404
|
toolCallId: pendingCall.id,
|
|
1405
|
-
content:
|
|
1405
|
+
content: await this.#serializeToolResult(pendingCall, result, state)
|
|
1406
1406
|
});
|
|
1407
1407
|
} else if (pending.type === "ask" && pendingCall) {
|
|
1408
1408
|
const value = await this.#interact(state, pending, {
|
|
@@ -1423,14 +1423,24 @@ var AgentLoop = class {
|
|
|
1423
1423
|
state.messages.push({
|
|
1424
1424
|
role: "tool",
|
|
1425
1425
|
toolCallId: pendingCall.id,
|
|
1426
|
-
content:
|
|
1426
|
+
content: await this.#serializeToolResult(pendingCall, result, state)
|
|
1427
1427
|
});
|
|
1428
1428
|
} else if (pendingCall) {
|
|
1429
1429
|
const result = await this.#executeCall(pendingCall, state);
|
|
1430
1430
|
state.messages.push({
|
|
1431
1431
|
role: "tool",
|
|
1432
1432
|
toolCallId: pendingCall.id,
|
|
1433
|
-
content:
|
|
1433
|
+
content: await this.#serializeToolResult(pendingCall, result, state)
|
|
1434
|
+
});
|
|
1435
|
+
}
|
|
1436
|
+
for (;;) {
|
|
1437
|
+
const next = this.#findPendingToolCall(state.messages);
|
|
1438
|
+
if (!next) break;
|
|
1439
|
+
const result = await this.#executeCall(next, state);
|
|
1440
|
+
state.messages.push({
|
|
1441
|
+
role: "tool",
|
|
1442
|
+
toolCallId: next.id,
|
|
1443
|
+
content: await this.#serializeToolResult(next, result, state)
|
|
1434
1444
|
});
|
|
1435
1445
|
}
|
|
1436
1446
|
} catch (e) {
|
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
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-
|
|
3
|
+
import { d as SkillManager } from "./index-iqcz3_NS.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';
|
|
@@ -360,8 +360,10 @@ declare class EvaluationRunner {
|
|
|
360
360
|
//#region src/evaluation/evaluationRuntime.d.ts
|
|
361
361
|
/**
|
|
362
362
|
* 治理评估专用 runtime 装配(不可信技能试用路径):
|
|
363
|
-
* 默认注入 ProcessSandboxExecutor(fork + --permission
|
|
364
|
-
*
|
|
363
|
+
* 默认注入 ProcessSandboxExecutor(fork + --permission 真实进程隔离;子进程
|
|
364
|
+
* env 默认清空防密钥泄露,需透传时经 ProcessSandboxOptions.envWhitelist 显式放行)。
|
|
365
|
+
* 可配置 executor 切回 SandboxedScriptExecutor(worker_threads 能力面收敛形态,
|
|
366
|
+
* 非安全边界;envWhitelist 同样适用于该执行器)。
|
|
365
367
|
*/
|
|
366
368
|
declare function createEvaluationRuntime(deps: WebSkillRuntimeDeps & {
|
|
367
369
|
executor?: ScriptExecutor;
|
package/dist/governance.js
CHANGED
|
@@ -1,6 +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 { S as WebSkillRuntime } from "./dist-
|
|
3
|
-
import { i as NodeFS, s as ProcessSandboxExecutor, u as exportArchive } from "./dist-
|
|
2
|
+
import { S as WebSkillRuntime } from "./dist-NM4Mylx4.js";
|
|
3
|
+
import { i as NodeFS, s as ProcessSandboxExecutor, u as exportArchive } from "./dist-CvIMVwr3.js";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { tmpdir } from "node:os";
|
|
6
6
|
import { mkdtemp } from "node:fs/promises";
|
|
@@ -843,8 +843,10 @@ var EvaluationRunner = class {
|
|
|
843
843
|
};
|
|
844
844
|
/**
|
|
845
845
|
* 治理评估专用 runtime 装配(不可信技能试用路径):
|
|
846
|
-
* 默认注入 ProcessSandboxExecutor(fork + --permission
|
|
847
|
-
*
|
|
846
|
+
* 默认注入 ProcessSandboxExecutor(fork + --permission 真实进程隔离;子进程
|
|
847
|
+
* env 默认清空防密钥泄露,需透传时经 ProcessSandboxOptions.envWhitelist 显式放行)。
|
|
848
|
+
* 可配置 executor 切回 SandboxedScriptExecutor(worker_threads 能力面收敛形态,
|
|
849
|
+
* 非安全边界;envWhitelist 同样适用于该执行器)。
|
|
848
850
|
*/
|
|
849
851
|
function createEvaluationRuntime(deps) {
|
|
850
852
|
return new WebSkillRuntime({
|
|
@@ -72,8 +72,10 @@ interface SandboxOptions {
|
|
|
72
72
|
* 能力桥协议与浏览器同一来源(runtime/sandbox/bridgeProtocol)。
|
|
73
73
|
*
|
|
74
74
|
* 诚实标注:本执行器做的是**能力面收敛**(网络策略、模块 allowlist、资源限额、
|
|
75
|
-
* 超时强杀),**不是安全边界**——Worker
|
|
76
|
-
*
|
|
75
|
+
* 超时强杀),**不是安全边界**——Worker 内脚本与宿主共享进程;
|
|
76
|
+
* 已知主动逃逸面(process.binding/_linkedBinding/dlopen/openStdin/reallyExit/abort)
|
|
77
|
+
* 已在入口删除(0.2.3),常规 import 拦截之外不承诺防御其它宿主共享面;
|
|
78
|
+
* 禁止假定其可隔离不可信脚本(隔离级需求用 ProcessSandboxExecutor)。
|
|
77
79
|
*/
|
|
78
80
|
declare class SandboxedScriptExecutor implements ScriptExecutor {
|
|
79
81
|
#private;
|
|
@@ -92,6 +94,8 @@ declare class SandboxedScriptExecutor implements ScriptExecutor {
|
|
|
92
94
|
interface ProcessSandboxOptions {
|
|
93
95
|
/** 温池大小(并发上限;执行后 kill 并补位重生),默认 2 */
|
|
94
96
|
poolSize?: number;
|
|
97
|
+
/** 透传给子进程的环境变量白名单(默认 []:子进程 env 为空,防密钥泄露) */
|
|
98
|
+
envWhitelist?: string[];
|
|
95
99
|
capabilities?: BridgeCapabilities;
|
|
96
100
|
/** 网络策略:默认 'deny-all'(权限模型无网络维度,补丁兜底;node:net 裸模块为已知残余面) */
|
|
97
101
|
networkPolicy?: NetworkPolicy;
|
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-NM4Mylx4.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.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-NM4Mylx4.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
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 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-
|
|
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-iqcz3_NS.js";
|
|
5
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-NM4Mylx4.js";
|
|
3
3
|
import { i as probeLlmCapabilities } from "./env--jJB-TSX-04klhTYi.js";
|
|
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-
|
|
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-CvIMVwr3.js";
|
|
5
5
|
|
|
6
6
|
export { CliUiBridge, FileArtifactStore, FileMemoryStore, NodeFS, NodeScriptExecutor, OxcSchemaInferer, ProcessSandboxExecutor, SKILLS_LOCKFILE, SKILL_MANIFEST_FILE, SandboxedScriptExecutor, SkillManager, createScriptContext, exportArchive, probeLlmCapabilities, readArchiveManifest };
|
|
@@ -132,8 +132,29 @@ function setupNetworkGuards(task) {
|
|
|
132
132
|
};
|
|
133
133
|
register(`data:text/javascript,${encodeURIComponent(MODULE_HOOK_SOURCE.replace("%ALLOWED_MODULES%", JSON.stringify(task.allowedModules ?? [])))}`);
|
|
134
134
|
}
|
|
135
|
+
/**
|
|
136
|
+
* 加载用户代码前删除 native 逃逸面(P0-A):binding/_linkedBinding/dlopen/
|
|
137
|
+
* openStdin/reallyExit/abort——这些直达宿主进程 internals,防御面与
|
|
138
|
+
* 能力收敛语义一致(常规 import 拦截之外的主动逃逸项由此封闭)。
|
|
139
|
+
* 注意:process.exit() 内部依赖 reallyExit(per_thread.js),故删前捕获引用,
|
|
140
|
+
* 关闭路径直接调用 internalExit(不经 process.exit)。
|
|
141
|
+
*/
|
|
142
|
+
const internalExit = process.reallyExit.bind(process);
|
|
143
|
+
function stripProcessEscapeHatches() {
|
|
144
|
+
for (const key of [
|
|
145
|
+
"binding",
|
|
146
|
+
"_linkedBinding",
|
|
147
|
+
"dlopen",
|
|
148
|
+
"openStdin",
|
|
149
|
+
"reallyExit",
|
|
150
|
+
"abort"
|
|
151
|
+
]) try {
|
|
152
|
+
Reflect.deleteProperty(process, key);
|
|
153
|
+
} catch {}
|
|
154
|
+
}
|
|
135
155
|
async function main() {
|
|
136
156
|
const task = workerData;
|
|
157
|
+
stripProcessEscapeHatches();
|
|
137
158
|
setupNetworkGuards(task);
|
|
138
159
|
port.on("message", (msg) => {
|
|
139
160
|
if (msg?.type === "bridge-response" && msg.response?.id) {
|
|
@@ -222,9 +243,9 @@ async function main() {
|
|
|
222
243
|
console.error = originals.error;
|
|
223
244
|
}
|
|
224
245
|
}
|
|
225
|
-
main().then(() =>
|
|
246
|
+
main().then(() => internalExit(0), (e) => {
|
|
226
247
|
console.error(e);
|
|
227
|
-
|
|
248
|
+
internalExit(1);
|
|
228
249
|
});
|
|
229
250
|
|
|
230
251
|
//#endregion
|
package/dist/ui.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { w as buildRenderResult } from "./dist-
|
|
1
|
+
import { w as buildRenderResult } from "./dist-NM4Mylx4.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 };
|