@webskill/sdk 0.2.3 → 0.2.5

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/dist/browser.d.ts CHANGED
@@ -1,5 +1,5 @@
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-gjFuBevI.js";
1
+ import { B as SkillManifest, C as FileStat, G as SkillsLockfile, L as SkillInstallSource, _ as RenderResultRequest, a as InteractionPolicy, c as LlmClient, d as LlmResponse, f as LlmStreamEvent, o as InteractionRequest, q as VerifyResult, s as InteractionResponse, v as UiBridge, w as FileSystemProvider, y as ArchiveLimits } from "./types-CKm5G_eQ-krKWW8WV.js";
2
+ import { Et as parseBridgeRequest, 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, y as ExternalToolSource } from "./index-DfINBEOy.js";
3
3
  //#region ../browser/dist/index.d.ts
4
4
  //#region src/fs/featureDetection.d.ts
5
5
  /** 检测当前环境是否可用 OPFS(navigator.storage.getDirectory) */
@@ -15,6 +15,7 @@ declare class OpfsProvider implements FileSystemProvider {
15
15
  });
16
16
  readText(p: string): Promise<string>;
17
17
  writeText(p: string, content: string): Promise<void>;
18
+ appendText(p: string, content: string): Promise<void>;
18
19
  readBinary(p: string): Promise<Uint8Array>;
19
20
  writeBinary(p: string, content: Uint8Array): Promise<void>;
20
21
  exists(p: string): Promise<boolean>;
package/dist/browser.js CHANGED
@@ -1,6 +1,6 @@
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-NM4Mylx4.js";
3
- import { n as MockLlmClient } from "./testing-B4pq6JYa.js";
1
+ import { C as messageOf, D as readResponseWithLimit, E as parseSkillPackManifest, M as unzipWithLimits, N as validateSkills, P as verifyManifest, T as parseSkillMarkdown, b as exportSkills, c as SkillDiscovery, d as assertRemoteUrlAllowed, h as buildManifest, i as SKILL_MANIFEST_FILE, j as resolveInsideRoot, m as buildCatalog, p as atomicWriteText, r as SKILLS_LOCKFILE, s as SKILL_PACK_FILE, u as WebSkillError, x as isValidSkillName } from "./dist-BQzncxXg.js";
2
+ import { A as isNetworkAllowed, C as bridgeError, E as createWebSkillApi, F as normalizeToolError, I as parseBridgeRequest, M as networkUrlHost, P as normalizeToolContent, 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-B77plHjw.js";
3
+ import { n as MockLlmClient } from "./testing-BUoXvm1u.js";
4
4
 
5
5
  //#region ../browser/dist/index.js
6
6
  /** 检测当前环境是否可用 OPFS(navigator.storage.getDirectory) */
@@ -57,6 +57,22 @@ var OpfsProvider = class {
57
57
  async writeText(p, content) {
58
58
  await this.writeBinary(p, new TextEncoder().encode(content));
59
59
  }
60
+ async appendText(p, content) {
61
+ await this.#wrap(p, async () => {
62
+ const segments = this.#segments(p);
63
+ const name = segments.pop();
64
+ if (!name) throw new WebSkillError("FS_NOT_FOUND", `Invalid file path: ${p}`);
65
+ const handle = await (await this.#walkDir(`/${segments.join("/")}`, true)).getFileHandle(name, { create: true });
66
+ const size = (await handle.getFile()).size;
67
+ const writable = await handle.createWritable({ keepExistingData: true });
68
+ await writable.write({
69
+ type: "write",
70
+ position: size,
71
+ data: content
72
+ });
73
+ await writable.close();
74
+ });
75
+ }
60
76
  async readBinary(p) {
61
77
  return this.#wrap(p, async () => {
62
78
  const handle = await this.#walkFile(p);
@@ -232,6 +248,16 @@ function loadModule(source) {
232
248
  return import(url);
233
249
  }
234
250
 
251
+ function assertSerializable(value) {
252
+ try {
253
+ structuredClone(value);
254
+ } catch (e) {
255
+ var err = new Error('Script returned a non-serializable value: ' + String((e && e.message) || e));
256
+ err.code = 'TOOL_EXECUTION_FAILED';
257
+ throw err;
258
+ }
259
+ }
260
+
235
261
  function postError(type, id, code, message, extra) {
236
262
  var msg = { type: type, id: id, ok: false, error: { code: code, message: message } };
237
263
  if (extra) Object.assign(msg, extra);
@@ -326,6 +352,7 @@ self.onmessage = async function (event) {
326
352
  throw new Error('Script does not export a run function');
327
353
  }
328
354
  var value = await mod2.run(msg.args, makeContext(msg));
355
+ assertSerializable(value);
329
356
  self.postMessage({
330
357
  type: 'execute-result', id: msg.id, ok: true,
331
358
  value: value === undefined ? null : value,
@@ -435,8 +462,7 @@ async function extractZipWeb(fs, data, destRoot, limits) {
435
462
  else await fs.writeBinary(target, content);
436
463
  }
437
464
  }
438
- const messageOf$1 = (e) => e instanceof Error ? e.message : String(e);
439
- const asInstallFailed = (e) => e instanceof WebSkillError && (e.code === "INSTALL_FAILED" || e.code === "TOOL_UNSUPPORTED") ? e : new WebSkillError("INSTALL_FAILED", `Install failed: ${messageOf$1(e)}`, e);
465
+ const asInstallFailed = (e) => e instanceof WebSkillError && (e.code === "INSTALL_FAILED" || e.code === "TOOL_UNSUPPORTED") ? e : new WebSkillError("INSTALL_FAILED", `Install failed: ${messageOf(e)}`, e);
440
466
  const lockfilePath = (root) => `${root}/${SKILLS_LOCKFILE}`;
441
467
  /**
442
468
  * D5:浏览器技能安装(http(s) zip / ArrayBuffer;tar/git/npm → TOOL_UNSUPPORTED)。
@@ -467,9 +493,15 @@ var BrowserSkillManager = class {
467
493
  if (source.type === "http") {
468
494
  let res;
469
495
  try {
470
- res = await (this.#fetchImpl ?? fetch)(source.url);
496
+ const absolute = new URL(source.url, typeof location !== "undefined" ? location.href : void 0).href;
497
+ const url = assertRemoteUrlAllowed(absolute, {
498
+ allowHttp: source.allowHttp ?? false,
499
+ allowPrivateHosts: source.allowPrivateHosts ?? false
500
+ });
501
+ res = await (this.#fetchImpl ?? fetch)(url.href);
471
502
  } catch (e) {
472
- throw new WebSkillError("INSTALL_FAILED", `Download failed: ${messageOf$1(e)}`, e);
503
+ if (e instanceof WebSkillError) throw e;
504
+ throw new WebSkillError("INSTALL_FAILED", `Download failed: ${messageOf(e)}`, e);
473
505
  }
474
506
  if (!res.ok) throw new WebSkillError("INSTALL_FAILED", `Download failed with HTTP ${res.status}`);
475
507
  data = await readResponseWithLimit(res, this.#archiveLimits);
@@ -499,7 +531,7 @@ var BrowserSkillManager = class {
499
531
  name = metadata.name;
500
532
  version = typeof metadata["version"] === "string" ? metadata["version"] : void 0;
501
533
  } catch (e) {
502
- throw new WebSkillError("INSTALL_FAILED", `Failed to read skill name from SKILL.md: ${messageOf$1(e)}`, e);
534
+ throw new WebSkillError("INSTALL_FAILED", `Failed to read skill name from SKILL.md: ${messageOf(e)}`, e);
503
535
  }
504
536
  if (!isValidSkillName(name)) throw new WebSkillError("INSTALL_FAILED", `Invalid skill name in SKILL.md (path traversal rejected): ${JSON.stringify(name)}`);
505
537
  const finalRoot = `${stagingRoot}/final`;
@@ -565,7 +597,7 @@ var BrowserSkillManager = class {
565
597
  name = metadata.name;
566
598
  versions.set(name, typeof metadata["version"] === "string" ? metadata["version"] : void 0);
567
599
  } catch (e) {
568
- throw new WebSkillError("INSTALL_FAILED", `Failed to read skill name from SKILL.md of pack entry "${entry.name}": ${messageOf$1(e)}`, e);
600
+ throw new WebSkillError("INSTALL_FAILED", `Failed to read skill name from SKILL.md of pack entry "${entry.name}": ${messageOf(e)}`, e);
569
601
  }
570
602
  if (name !== entry.name) throw new WebSkillError("INSTALL_FAILED", `Skill pack entry "${entry.name}" does not match the SKILL.md name "${name}"`);
571
603
  await copyDir(fs, skillDir, `${finalRoot}/${name}`);
@@ -647,7 +679,7 @@ var BrowserSkillManager = class {
647
679
  await this.#removeLockEntry(name);
648
680
  this.#onChanged?.();
649
681
  } catch (e) {
650
- throw new WebSkillError("UNINSTALL_FAILED", `Failed to uninstall "${name}": ${messageOf$1(e)}`, e);
682
+ throw new WebSkillError("UNINSTALL_FAILED", `Failed to uninstall "${name}": ${messageOf(e)}`, e);
651
683
  }
652
684
  }
653
685
  async verifyIntegrity(name) {
@@ -667,7 +699,7 @@ var BrowserSkillManager = class {
667
699
  try {
668
700
  return JSON.parse(await this.#fs.readText(path));
669
701
  } catch (e) {
670
- throw new WebSkillError("INTEGRITY_FAILED", `Skills lockfile at ${path} is corrupted: ${messageOf$1(e)}`, e);
702
+ throw new WebSkillError("INTEGRITY_FAILED", `Skills lockfile at ${path} is corrupted: ${messageOf(e)}`, e);
671
703
  }
672
704
  }
673
705
  async #createManifest(skillRoot, input) {
@@ -699,7 +731,7 @@ var BrowserSkillManager = class {
699
731
  try {
700
732
  return JSON.parse(await this.#fs.readText(path));
701
733
  } catch (e) {
702
- throw new WebSkillError("INTEGRITY_FAILED", `Skill manifest at ${path} is corrupted: ${messageOf$1(e)}`, e);
734
+ throw new WebSkillError("INTEGRITY_FAILED", `Skill manifest at ${path} is corrupted: ${messageOf(e)}`, e);
703
735
  }
704
736
  }
705
737
  async #upsertLockEntry(name, entry) {
@@ -837,7 +869,6 @@ const resolveWorkerFactory = (mode) => {
837
869
  return blobWorkerFactory;
838
870
  };
839
871
  const baseName = (p) => p.split("/").pop() ?? p;
840
- const messageOf = (e) => e instanceof Error ? e.message : String(e);
841
872
  /**
842
873
  * Web Worker 脚本沙箱执行器:loadDefinition 与 execute 都在 Worker 内完成,
843
874
  * 主线程从不 import 技能脚本;每次执行独立 Worker;超时 terminate 强杀。
@@ -940,12 +971,13 @@ var BrowserWorkerScriptExecutor = class {
940
971
  }, timeoutMs, (bridgeRequest) => this.#handleBridge(bridgeRequest, context), (host) => context.onWarning?.(`Network request blocked by sandbox network policy: ${host}`));
941
972
  if (!response.ok) {
942
973
  const stderrSummary = response.stderr?.length ? ` | stderr: ${response.stderr.join(" | ").slice(0, 500)}` : "";
974
+ const normalized = normalizeToolError(response.error?.code, response.error?.message ?? "script execution failed");
943
975
  return {
944
976
  ok: false,
945
977
  content: [],
946
978
  error: {
947
- code: response.error?.code ?? "TOOL_EXECUTION_FAILED",
948
- message: `${response.error?.message ?? "script execution failed"}${stderrSummary}`
979
+ code: normalized.code,
980
+ message: `${normalized.message}${stderrSummary}`
949
981
  }
950
982
  };
951
983
  }