@webskill/sdk 0.14.0 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/dist/agent.d.ts +3 -3
  2. package/dist/agent.js +2442 -3
  3. package/dist/{dist-Bfga1TmS.js → approval-BnLLCOG0.js} +235 -2932
  4. package/dist/browser.d.ts +106 -5
  5. package/dist/browser.js +364 -10
  6. package/dist/{openUiLibrary-BKXW7Iwx-DjvEnMlJ.js → dist-CTsxblSD.js} +496 -28
  7. package/dist/{echarts-De78wXqV.js → echarts-BE7oV_Dl.js} +1 -1
  8. package/dist/{env-8cY40DXB-CGnEVZby.js → env-Bj1MI2Ww.js} +1 -1
  9. package/dist/errors-BDZNpC13.js +22 -0
  10. package/dist/{eventTypes-FllCrX-Z-DNDeHWoG.js → eventTypes-Y07N8IAC.js} +14 -2
  11. package/dist/external-_ZRQe-V9.js +53 -0
  12. package/dist/governance.d.ts +15 -3
  13. package/dist/governance.js +86 -4
  14. package/dist/{index-DQwGvHAI.d.ts → index-CQYo4tcT.d.ts} +85 -6
  15. package/dist/{index-sd-gVKey.d.ts → index-CU2md8R1.d.ts} +26 -18
  16. package/dist/{index-CWoKOFBP.d.ts → index-Oc3H89TJ.d.ts} +159 -3
  17. package/dist/index.d.ts +4 -4
  18. package/dist/index.js +1001 -5
  19. package/dist/kind-DxgS8LM-.js +77 -0
  20. package/dist/linkedDocument-xNXF-z8n.js +94 -0
  21. package/dist/llm-B7lLH0ZI.js +1767 -0
  22. package/dist/mcp.d.ts +2 -2
  23. package/dist/mcp.js +41 -4
  24. package/dist/memoryArtifactStore-D6dLeY55.js +48 -0
  25. package/dist/miniChart-owdCdaw-.js +533 -0
  26. package/dist/node.d.ts +3 -3
  27. package/dist/node.js +106 -9
  28. package/dist/openUiLibrary-CY_ADoe0.js +30 -0
  29. package/dist/openUiSpecLang-DuOCdw9G.js +1849 -0
  30. package/dist/pathSecurity-B1owvJAF.js +65 -0
  31. package/dist/processSandboxEntry.js +5 -1
  32. package/dist/renderResult-D9Q-Vu2x.js +143 -0
  33. package/dist/{rolldown-runtime-BOF7iYI8.js → rolldown-runtime-BHkdefai.js} +1 -2
  34. package/dist/sandboxWorkerEntry.js +5 -1
  35. package/dist/{dist-D5YhlCdY.js → skill-CAJMsLod.js} +44 -372
  36. package/dist/{skillVersionStore-D-qHk9ZE-C0OFDTQY.d.ts → skillVersionStore-B24Jjjry-C4zomhMZ.d.ts} +14 -2
  37. package/dist/surface-DVGiCmwq.js +145 -0
  38. package/dist/testing.d.ts +1 -1
  39. package/dist/testing.js +64 -3
  40. package/dist/{types-C3V6lAeO-BgeOvc1Y.d.ts → types-C3V6lAeO-BIf7UB2e.d.ts} +17 -1
  41. package/dist/types-TUydnxaj.js +78 -0
  42. package/dist/ui-react.d.ts +12 -5
  43. package/dist/ui-react.js +128548 -4729
  44. package/dist/ui-vue.d.ts +1 -1
  45. package/dist/ui-vue.js +11 -2
  46. package/dist/ui.d.ts +3 -3
  47. package/dist/ui.js +1254 -3
  48. package/dist/urlSafety-CiSuCJvX.js +65 -0
  49. package/dist/webSkillApi-DOOyz2G5.js +106 -0
  50. package/dist/{webskillLitCatalog-D_zCqeQF-swXsWoAe.js → webskillLitCatalog-DSqVFQjK.js} +11 -3
  51. package/package.json +1 -1
  52. package/dist/catalogComponents-BgAJN0p8-Cr55ouOg.js +0 -124384
  53. package/dist/client-BCM6Z3yq-qUQNkKrK.js +0 -7787
  54. package/dist/dist-BnqAkSS6.js +0 -2384
  55. package/dist/dist-CiaDIqkV.js +0 -3509
  56. package/dist/dist-DxyxmXPU-DGC-dpXf.js +0 -5621
  57. package/dist/memoryArtifactStore-52Zn9npI-BxtUkrgV.js +0 -86
  58. package/dist/stdio-CFMoANJJ-BxrTeXh7.js +0 -31
  59. package/dist/testing-Cm8MseLF.js +0 -142
  60. package/dist/types-WovEf4ED-CZSDiiBU.js +0 -6215
package/dist/browser.js CHANGED
@@ -1,13 +1,21 @@
1
- import { $ as unzipWithLimits, B as messageOf, E as buildManifest, G as readSkillSignature, H as parseSkillMarkdown, I as isAtomicTempPath, L as isValidSkillName, M as detectSkillArchiveShapeFromFs, P as exportSkills, S as assertRemoteUrlAllowed, T as buildCatalog, U as parseSkillPackManifest, W as readResponseWithLimit, Y as resolveInsideRoot, _ as SkillDiscovery, b as WebSkillError, c as MANIFEST_EXCLUDED_FILES, d as SKILLS_LOCKFILE, et as validateSkills, f as SKILL_MANIFEST_FILE, h as SKILL_PACK_FILE, nt as verifySkillSignature, tt as verifyManifest, w as atomicWriteText } from "./dist-D5YhlCdY.js";
2
- import { $ as bridgeError, A as ProgressiveRouter, Ct as normalizeToolError, E as GoogleGenAiClient, St as normalizeToolContent, _t as mergeCatalogEntries, b as FsMemoryStore, c as AnthropicClient, k as OpenAiCompatibleClient, nt as createWebSkillApi, s as AgentLoop, u as CapabilityApproval, wt as parseBridgeRequest, x as FsRunSnapshotStore, y as FsArtifactStore, yt as networkPolicyLibSource } from "./dist-Bfga1TmS.js";
3
- import { A as frameLabel, M as toActionFrameScopes, N as toFrameScopes, j as frameSteps } from "./dist-BnqAkSS6.js";
4
- import { n as MockLlmClient } from "./testing-Cm8MseLF.js";
1
+ import { n as messageOf, t as WebSkillError } from "./errors-BDZNpC13.js";
2
+ import { A as SKILL_MANIFEST_FILE, D as verifySkillSignature, M as buildManifest, O as MANIFEST_EXCLUDED_FILES, P as verifyManifest, b as parseSkillMarkdown, c as unzipWithLimits, f as SKILL_PACK_FILE, i as buildCatalog, k as SKILLS_LOCKFILE, m as parseSkillPackManifest, n as SkillDiscovery, o as readResponseWithLimit, p as exportSkills, t as validateSkills, u as detectSkillArchiveShapeFromFs, w as readSkillSignature, y as isValidSkillName } from "./skill-CAJMsLod.js";
3
+ import { a as atomicWriteText, o as isAtomicTempPath, r as resolveInsideRoot } from "./pathSecurity-B1owvJAF.js";
4
+ import { t as assertRemoteUrlAllowed } from "./urlSafety-CiSuCJvX.js";
5
+ import { a as networkPolicyLibSource, c as bridgeError, d as FsMemoryStore, g as FsRunSnapshotStore, l as parseBridgeRequest, nt as ProgressiveRouter, p as AgentLoop, r as normalizeToolError, s as UPLOAD_FILES_UNAVAILABLE, t as CapabilityApproval, u as FsArtifactStore } from "./approval-BnLLCOG0.js";
6
+ import { a as GoogleGenAiClient, o as AnthropicClient, s as OpenAiCompatibleClient, t as MockLlmClient } from "./llm-B7lLH0ZI.js";
7
+ import { n as normalizeToolContent, t as mergeCatalogEntries } from "./external-_ZRQe-V9.js";
8
+ import { t as createWebSkillApi } from "./webSkillApi-DOOyz2G5.js";
9
+ import { a as frameSteps, i as frameLabel, n as toActionFrameScopes, r as toFrameScopes } from "./types-TUydnxaj.js";
5
10
 
6
- //#region ../browser/dist/index.js
11
+ //#region ../browser/src/fs/featureDetection.ts
7
12
  /** 检测当前环境是否可用 OPFS(navigator.storage.getDirectory) */
8
13
  function isOpfsAvailable(globalScope) {
9
14
  return typeof (globalScope ?? globalThis).navigator?.storage?.getDirectory === "function";
10
15
  }
16
+
17
+ //#endregion
18
+ //#region ../browser/src/fs/opfsProvider.ts
11
19
  const isDomException = (e, name) => e instanceof DOMException && e.name === name;
12
20
  const mapError = (e, path) => {
13
21
  if (isDomException(e, "NotFoundError")) return new WebSkillError("FS_NOT_FOUND", `Path not found: ${path}`);
@@ -174,6 +182,9 @@ var OpfsProvider = class {
174
182
  await this.remove(from);
175
183
  }
176
184
  };
185
+
186
+ //#endregion
187
+ //#region ../browser/src/executor/workerBootstrap.ts
177
188
  /**
178
189
  * Worker 引导源码(字符串 → Blob URL → new Worker(url, {type:'module'}))。
179
190
  * 注意:内容为纯 JS,不能含反引号与 ${ 占位(外层用模板字符串内嵌);
@@ -183,7 +194,7 @@ var OpfsProvider = class {
183
194
  *
184
195
  * 协议(宿主 ↔ Worker):
185
196
  * - 宿主 → Worker:{type:'load', id, source, networkPolicy?} 请求加载脚本定义
186
- * - 宿主 → Worker:{type:'execute', id, skillName, runId, source, args, networkPolicy?} 请求执行
197
+ * - 宿主 → Worker:{type:'execute', id, skillName, runId, source, args, networkPolicy?, documentSurface?} 请求执行
187
198
  * - Worker → 宿主:{type:'load-result', id, ok, definition?, error?}
188
199
  * - Worker → 宿主:{type:'execute-result', id, ok, value?, stdout, stderr, error?}
189
200
  * - Worker → 宿主:{type:'bridge', request} 能力桥 RPC(readReference/writeArtifact/confirm)
@@ -299,7 +310,7 @@ function callCapability(kind, payload) {
299
310
  }
300
311
 
301
312
  function makeContext(msg) {
302
- return {
313
+ var ctx = {
303
314
  skillName: msg.skillName,
304
315
  runId: msg.runId,
305
316
  readReference: function (path) {
@@ -329,6 +340,21 @@ function makeContext(msg) {
329
340
  return callCapability('confirm', { message: message });
330
341
  },
331
342
  };
343
+ // 能力位而非能力函数:其余能力无条件挂上去(拿不到时桥对面报错),
344
+ // documentSurface 是个供探测的布尔值,无条件挂上去就变成恒真谎言。
345
+ if (msg.documentSurface) ctx.documentSurface = true;
346
+ // 上传文件同理:宿主没接就不能给出「存在但必然失败」的假出口(分册 17 FR-17.1)
347
+ if (msg.uploadFiles) {
348
+ ctx.listUploadFiles = function () {
349
+ return callCapability('listUploadFiles', {});
350
+ };
351
+ ctx.readUploadFile = function (fileId) {
352
+ return callCapability('readUploadFile', { fileId: fileId }).then(function (bytes) {
353
+ return new Uint8Array(bytes);
354
+ });
355
+ };
356
+ }
357
+ return ctx;
332
358
  }
333
359
 
334
360
  self.onmessage = async function (event) {
@@ -404,6 +430,9 @@ self.onmessage = async function (event) {
404
430
  }
405
431
  };
406
432
  `;
433
+
434
+ //#endregion
435
+ //#region ../browser/src/executor/tsTranspiler.ts
407
436
  /** 按资源地址缓存,而不是全局单例:不同地址必须各自加载,否则先到的实例会顶替后来的配置 */
408
437
  const esbuildCache = /* @__PURE__ */ new Map();
409
438
  async function loadEsbuild(options) {
@@ -466,12 +495,18 @@ var TsTranspiler = class {
466
495
  return code;
467
496
  }
468
497
  };
498
+
499
+ //#endregion
500
+ //#region ../browser/src/skillManagement/checksumWeb.ts
469
501
  /** WebCrypto sha256(浏览器/Worker 通用;Node 20+ 全局 crypto 同样可用) */
470
502
  async function sha256HexWeb(data) {
471
503
  const bytes = typeof data === "string" ? new TextEncoder().encode(data) : data;
472
504
  const digest = await crypto.subtle.digest("SHA-256", bytes);
473
505
  return [...new Uint8Array(digest)].map((b) => b.toString(16).padStart(2, "0")).join("");
474
506
  }
507
+
508
+ //#endregion
509
+ //#region ../browser/src/skillManagement/fsUtils.ts
475
510
  /** 递归拷贝目录(含子目录与二进制文件;原子写中断残留的 `.tmp-*` 不拷贝) */
476
511
  async function copyDir(fs, from, to) {
477
512
  await fs.mkdir(to);
@@ -498,6 +533,9 @@ async function removeDirQuiet(fs, dir) {
498
533
  if (await fs.exists(dir)) await fs.remove(dir, { recursive: true });
499
534
  } catch {}
500
535
  }
536
+
537
+ //#endregion
538
+ //#region ../browser/src/skillManagement/zipExtract.ts
501
539
  /**
502
540
  * zip 解包(fflate 流式,单条目/总解压体积上限,浏览器无依赖)。
503
541
  * 每个条目路径过 resolveInsideRoot:拒绝 `..` 段、绝对路径、反斜杠穿越(与 node 规则一致)。
@@ -509,6 +547,9 @@ async function extractZipWeb(fs, data, destRoot, limits) {
509
547
  else await fs.writeBinary(target, content);
510
548
  }
511
549
  }
550
+
551
+ //#endregion
552
+ //#region ../browser/src/skillManagement/browserSkillManager.ts
512
553
  /**
513
554
  * 验签失败不能被折叠成 INSTALL_FAILED:四种失败的宿主处置完全不同
514
555
  * (引导选策略 / 提示重下 / 引导添加密钥 / 安全事件),与 Node 侧同口径。
@@ -885,6 +926,9 @@ var BrowserSkillManager = class {
885
926
  await atomicWriteText(this.#fs, lockfilePath(this.#managedRoot), JSON.stringify(lockfile, null, 2));
886
927
  }
887
928
  };
929
+
930
+ //#endregion
931
+ //#region ../browser/src/executor/iframeSandbox.ts
888
932
  const ENVELOPE = "__webskill_sandbox__";
889
933
  let channelSeq = 0;
890
934
  /** 每实例 channelId(防同页伪造消息注入;crypto.randomUUID 优先,无则随机回退) */
@@ -1098,8 +1142,9 @@ function createIframeWorker(bootstrapSource, options = {}) {
1098
1142
  doc.body.appendChild(iframe);
1099
1143
  return worker;
1100
1144
  }
1145
+ const readyTimeoutMs = resolved.readyTimeoutMs ?? 1e4;
1101
1146
  const worker = new IframeWorkerLike(iframe, hostWindow, channelId, {
1102
- ms: resolved.readyTimeoutMs ?? 1e4,
1147
+ ms: readyTimeoutMs,
1103
1148
  documentUrl
1104
1149
  });
1105
1150
  iframe.addEventListener("load", () => {
@@ -1116,6 +1161,9 @@ function createIframeWorker(bootstrapSource, options = {}) {
1116
1161
  doc.body.appendChild(iframe);
1117
1162
  return worker;
1118
1163
  }
1164
+
1165
+ //#endregion
1166
+ //#region ../browser/src/executor/workerScriptExecutor.ts
1119
1167
  const blobWorkerFactory = () => {
1120
1168
  const blob = new Blob([WORKER_BOOTSTRAP_SOURCE], { type: "text/javascript" });
1121
1169
  const url = URL.createObjectURL(blob);
@@ -1228,7 +1276,9 @@ var BrowserWorkerScriptExecutor = class {
1228
1276
  runId: context.runId,
1229
1277
  source: script.source,
1230
1278
  args,
1231
- networkPolicy: this.#networkPolicy
1279
+ networkPolicy: this.#networkPolicy,
1280
+ ...context.documentSurface ? { documentSurface: true } : {},
1281
+ ...context.readUploadFile ? { uploadFiles: true } : {}
1232
1282
  }, timeoutMs, (bridgeRequest) => this.#handleBridge(bridgeRequest, context), (host) => context.onWarning?.(`Network request blocked by sandbox network policy: ${host}`));
1233
1283
  if (!response.ok) {
1234
1284
  const stderrSummary = response.stderr?.length ? ` | stderr: ${response.stderr.join(" | ").slice(0, 500)}` : "";
@@ -1377,12 +1427,29 @@ var BrowserWorkerScriptExecutor = class {
1377
1427
  value: await context.confirm(request.message)
1378
1428
  };
1379
1429
  }
1430
+ case "listUploadFiles":
1431
+ if (!context.listUploadFiles) return bridgeError(request.id, "TOOL_UNSUPPORTED", UPLOAD_FILES_UNAVAILABLE);
1432
+ return {
1433
+ id: request.id,
1434
+ ok: true,
1435
+ value: await context.listUploadFiles()
1436
+ };
1437
+ case "readUploadFile":
1438
+ if (!context.readUploadFile) return bridgeError(request.id, "TOOL_UNSUPPORTED", UPLOAD_FILES_UNAVAILABLE);
1439
+ return {
1440
+ id: request.id,
1441
+ ok: true,
1442
+ value: Array.from(await context.readUploadFile(request.fileId))
1443
+ };
1380
1444
  }
1381
1445
  } catch (e) {
1382
1446
  return bridgeError(request.id, e instanceof WebSkillError ? e.code : "TOOL_EXECUTION_FAILED", messageOf(e));
1383
1447
  }
1384
1448
  }
1385
1449
  };
1450
+
1451
+ //#endregion
1452
+ //#region ../browser/src/navigator.ts
1386
1453
  /**
1387
1454
  * navigator.webskill 显式装配:OPFS 默认存储 + BrowserWorkerScriptExecutor +
1388
1455
  * BrowserSkillManager → createWebSkillApi;target 提供时挂 target.navigator
@@ -1412,6 +1479,9 @@ function installWebSkillNavigator(config) {
1412
1479
  nav["webskill"] = api;
1413
1480
  return api;
1414
1481
  }
1482
+
1483
+ //#endregion
1484
+ //#region ../browser/src/llm/chromeBuiltinClient.ts
1415
1485
  function languageModel() {
1416
1486
  const candidate = globalThis.LanguageModel;
1417
1487
  return typeof candidate?.availability === "function" && typeof candidate.create === "function" ? candidate : void 0;
@@ -1547,6 +1617,9 @@ var ChromeBuiltinLlmClient = class {
1547
1617
  return (await probeChromeBuiltinAvailability()).available;
1548
1618
  }
1549
1619
  };
1620
+
1621
+ //#endregion
1622
+ //#region ../browser/src/llm/createLlmClient.ts
1550
1623
  /**
1551
1624
  * 配置 → `LlmClient`。收在 SDK 里是为了让下游只跟 `RuntimeConfigStore` 打交道,
1552
1625
  * 不必自己维护「provider → client 类」的映射(设计 04 §5)。
@@ -1578,6 +1651,9 @@ function createLlmClient(config) {
1578
1651
  model: config.model
1579
1652
  });
1580
1653
  }
1654
+
1655
+ //#endregion
1656
+ //#region ../browser/src/media/dictation.ts
1581
1657
  function recognitionCtor() {
1582
1658
  const scope = globalThis;
1583
1659
  return scope.SpeechRecognition ?? scope.webkitSpeechRecognition;
@@ -1653,6 +1729,9 @@ function startDictation(options) {
1653
1729
  recognition.stop();
1654
1730
  } };
1655
1731
  }
1732
+
1733
+ //#endregion
1734
+ //#region ../browser/src/media/compressImage.ts
1656
1735
  /** 动图无法在不丢帧的前提下走单帧编码管线,超限直接拒绝(裁决 D-2) */
1657
1736
  const UNCOMPRESSABLE_MIME_TYPES = /* @__PURE__ */ new Set(["image/gif"]);
1658
1737
  const QUALITY_STEPS = [
@@ -1720,6 +1799,9 @@ async function encode(bitmap, width, height, quality) {
1720
1799
  function formatBytes(bytes) {
1721
1800
  return `${(bytes / 1024 / 1024).toFixed(1)} MB`;
1722
1801
  }
1802
+
1803
+ //#endregion
1804
+ //#region ../browser/src/dom/imageCapture.ts
1723
1805
  /** @experimental */
1724
1806
  function isCaptureFailure(result) {
1725
1807
  return "reason" in result;
@@ -2049,6 +2131,9 @@ function describeError(e) {
2049
2131
  if (e instanceof TypeError) return "the request was blocked, most likely by CORS";
2050
2132
  return e instanceof Error ? e.message : String(e);
2051
2133
  }
2134
+
2135
+ //#endregion
2136
+ //#region ../browser/src/dom/promotion.ts
2052
2137
  /**
2053
2138
  * 非标可交互元素的识别与角色提升(0.14.0 分册 15)。
2054
2139
  *
@@ -2191,6 +2276,9 @@ function promoteRole(input) {
2191
2276
  href
2192
2277
  } : { role: "button" };
2193
2278
  }
2279
+
2280
+ //#endregion
2281
+ //#region ../browser/src/dom/perception.ts
2194
2282
  /** 值可能是凭据的输入类型:即便宿主忘了写进 exclude 也不读值。操作侧复用同一份,不另写 */
2195
2283
  const SECRET_INPUT_TYPES = /* @__PURE__ */ new Set(["password", "hidden"]);
2196
2284
  /** 可被操作的角色:只给这些节点发句柄,其余节点模型连提都提不出来 */
@@ -2871,6 +2959,9 @@ function createDomPerceptionReader(options = {}) {
2871
2959
  }
2872
2960
  }
2873
2961
  }
2962
+
2963
+ //#endregion
2964
+ //#region ../browser/src/dom/pageAction.ts
2874
2965
  const FILLABLE_TAGS = /* @__PURE__ */ new Set(["INPUT", "TEXTAREA"]);
2875
2966
  /** 只看显式声明,不看尺寸:jsdom 有 getComputedStyle 但没有布局 */
2876
2967
  function hidden(element) {
@@ -3168,6 +3259,9 @@ function createDomPageActionExecutor(options) {
3168
3259
  describe
3169
3260
  };
3170
3261
  }
3262
+
3263
+ //#endregion
3264
+ //#region ../browser/src/remote/registry.ts
3171
3265
  /** @experimental */
3172
3266
  function createRemoteTargetRegistry() {
3173
3267
  let table = /* @__PURE__ */ new Map();
@@ -3200,6 +3294,9 @@ function createRemoteTargetRegistry() {
3200
3294
  }
3201
3295
  };
3202
3296
  }
3297
+
3298
+ //#endregion
3299
+ //#region ../browser/src/remote/transport.ts
3203
3300
  /** 缺省单次往返上限(FR-13.2 / FR-13.3) */
3204
3301
  const DEFAULT_PAGE_AGENT_TIMEOUT_MS = 1e4;
3205
3302
  /**
@@ -3230,6 +3327,9 @@ async function roundTrip(transport, request, expect, code, timeoutMs) {
3230
3327
  if (reply.type !== expect) throw new WebSkillError(code, `Page agent replied with "${reply.type}" to a "${request.type}" request; expected "${expect}".`);
3231
3328
  return reply;
3232
3329
  }
3330
+
3331
+ //#endregion
3332
+ //#region ../browser/src/remote/reader.ts
3233
3333
  /**
3234
3334
  * 跨上下文的页面感知(分册 13 / FR-13.2)。
3235
3335
  *
@@ -3249,6 +3349,9 @@ function createRemotePerceptionReader(options) {
3249
3349
  return reply.result;
3250
3350
  } };
3251
3351
  }
3352
+
3353
+ //#endregion
3354
+ //#region ../browser/src/remote/executor.ts
3252
3355
  /**
3253
3356
  * 跨上下文的页面操作执行器(分册 13 / FR-13.3)。
3254
3357
  * @experimental
@@ -3280,6 +3383,9 @@ function createRemotePageActionExecutor(options) {
3280
3383
  }
3281
3384
  };
3282
3385
  }
3386
+
3387
+ //#endregion
3388
+ //#region ../browser/src/remote/handler.ts
3283
3389
  /** 深度收集句柄;顺序即遍历序,便于与本地形态逐条比对 */
3284
3390
  function collectRefs(nodes, out = []) {
3285
3391
  for (const node of nodes) {
@@ -3344,6 +3450,205 @@ function createPageAgentHandler(options = {}) {
3344
3450
  }
3345
3451
  } };
3346
3452
  }
3453
+
3454
+ //#endregion
3455
+ //#region ../browser/src/remote/frameRouter.ts
3456
+ /** @experimental */
3457
+ const DEFAULT_FRAME_BUDGET = {
3458
+ maxFrames: 12,
3459
+ maxNodes: 1500
3460
+ };
3461
+ function countNodes(nodes) {
3462
+ let total = 0;
3463
+ for (const node of nodes) total += 1 + countNodes(node.children ?? []);
3464
+ return total;
3465
+ }
3466
+ function note(name) {
3467
+ return {
3468
+ role: "note",
3469
+ name
3470
+ };
3471
+ }
3472
+ /**
3473
+ * 地址归一化:只比较 origin + path。
3474
+ *
3475
+ * 父页面写的 `src` 常带 `?t=123` 之类的缓存参数,甚至被框架改写过 hash。
3476
+ * 带上 query/hash 比对会把明明是同一帧的判成换了页,
3477
+ * 于是本该读到的内容变成一句「导航走了」——宁可粗一点也不能漏。
3478
+ */
3479
+ function frameKey(url) {
3480
+ try {
3481
+ const parsed = new URL(url);
3482
+ return `${parsed.origin}${parsed.pathname}`;
3483
+ } catch {
3484
+ return;
3485
+ }
3486
+ }
3487
+ /**
3488
+ * 确认卡与模型上下文里指称一帧的说法(分册 16 FR-16.6)。
3489
+ *
3490
+ * 带上 host 而不只用父页面写的 `hint`:用户要能一眼分清「页面主体里的那个按钮」
3491
+ * 和「某个第三方 iframe 里的按钮」,而 `hint` 来自被嵌一方决定不了、
3492
+ * 嵌入方随便写的属性——`title="账户设置"` 的 iframe 完全可以指向别人的域。
3493
+ */
3494
+ function frameLabelOf(nested) {
3495
+ try {
3496
+ return `${nested.hint} (${new URL(nested.url).host})`;
3497
+ } catch {
3498
+ return nested.hint;
3499
+ }
3500
+ }
3501
+ /** 与 SDK 单帧取像超限时的文案同源;两边改要一起改 */
3502
+ const IMAGE_LIMIT_NOTE = "Not captured: the per-message image limit was reached";
3503
+ /**
3504
+ * 深度重写节点:打帧标签,并把 `imageId` 换成汇总后的全局 id。
3505
+ *
3506
+ * 每帧的取像 id 都是自己从 `img-1` 数起的,直接合并会让不同帧的图撞成同一个 id。
3507
+ * 落选(超整页预算)的图必须**同时**抹掉节点上的 `imageId`,否则节点指向一张
3508
+ * 根本没下发的图,模型会以为自己看过了。
3509
+ */
3510
+ function relabel(nodes, frame, imageIds) {
3511
+ return nodes.map((node) => {
3512
+ const next = { ...node };
3513
+ if (frame !== void 0) next.frame = node.frame ?? frame;
3514
+ if (node.imageId !== void 0) {
3515
+ const mapped = imageIds.get(node.imageId);
3516
+ if (mapped === void 0) {
3517
+ delete next.imageId;
3518
+ next.imageNote = node.imageNote ?? IMAGE_LIMIT_NOTE;
3519
+ } else next.imageId = mapped;
3520
+ }
3521
+ if (node.children !== void 0) next.children = relabel(node.children, frame, imageIds);
3522
+ return next;
3523
+ });
3524
+ }
3525
+ /**
3526
+ * 逐帧下钻并汇总(分册 16 FR-16.2 / FR-16.3 / FR-16.4,分册 11 FR-11.2)。
3527
+ *
3528
+ * 编排本身与浏览器 API 无关:它只认 `PageAgentRequest` / `PageAgentReply`,
3529
+ * 寻址全压在宿主实现的 `FrameDispatcher` 里。因此这个模块可以在 Service Worker
3530
+ * 里实例化,也可以服务不按帧号寻址的宿主。
3531
+ * @experimental
3532
+ */
3533
+ function createFrameRouter(options) {
3534
+ const budget = {
3535
+ ...DEFAULT_FRAME_BUDGET,
3536
+ ...options.budget
3537
+ };
3538
+ /** ref → 发放它的那一帧。`execute` 必须投回原帧,投给别的帧要么查无此 ref 要么误点同名控件 */
3539
+ const refFrames = /* @__PURE__ */ new Map();
3540
+ async function perceive(request) {
3541
+ const mainAddress = await options.dispatcher.mainFrame();
3542
+ const nodes = [];
3543
+ const targets = [];
3544
+ const frameNotes = [];
3545
+ const main = await options.dispatcher.send(mainAddress, request);
3546
+ if (main.reply.type !== "perceive-result") return main.reply;
3547
+ const images = [];
3548
+ let imagesOmitted = 0;
3549
+ let imageFailures = 0;
3550
+ const imageBudget = request.capture?.images === true ? request.capture.maxImages : 0;
3551
+ const queue = [];
3552
+ const visited = [mainAddress];
3553
+ let nodeCount = 0;
3554
+ let framesRead = 0;
3555
+ let descended = 0;
3556
+ const skipped = [];
3557
+ const absorb = (reply, address, frame, imagePrefix) => {
3558
+ framesRead += 1;
3559
+ nodeCount += countNodes(reply.result.nodes);
3560
+ const imageIds = /* @__PURE__ */ new Map();
3561
+ for (const image of reply.result.images ?? []) {
3562
+ if (images.length >= imageBudget) {
3563
+ imagesOmitted += 1;
3564
+ continue;
3565
+ }
3566
+ const id = `${imagePrefix}${image.id}`;
3567
+ imageIds.set(image.id, id);
3568
+ images.push({
3569
+ ...image,
3570
+ id
3571
+ });
3572
+ }
3573
+ imagesOmitted += reply.result.imagesOmitted ?? 0;
3574
+ imageFailures += reply.result.imageFailures ?? 0;
3575
+ nodes.push(...relabel(reply.result.nodes, frame, imageIds));
3576
+ for (const target of reply.targets) {
3577
+ targets.push(frame === void 0 ? target : {
3578
+ ...target,
3579
+ frame: target.frame ?? frame
3580
+ });
3581
+ refFrames.set(target.ref, address);
3582
+ }
3583
+ if (reply.result.frameNotes !== void 0) frameNotes.push(...reply.result.frameNotes);
3584
+ for (const nested of reply.result.nestedFrames ?? []) queue.push({
3585
+ ...nested,
3586
+ parent: address
3587
+ });
3588
+ };
3589
+ absorb(main.reply, mainAddress, options.mainFrameLabel, "");
3590
+ while (queue.length > 0) {
3591
+ const next = queue.shift();
3592
+ if (framesRead >= budget.maxFrames || nodeCount >= budget.maxNodes) {
3593
+ skipped.push(next.hint);
3594
+ continue;
3595
+ }
3596
+ const address = await options.dispatcher.resolveNestedFrame(next, {
3597
+ parent: next.parent,
3598
+ visited
3599
+ });
3600
+ if (address === void 0) {
3601
+ nodes.push(note(`A nested frame "${next.hint}" (${next.url}) could not be addressed and was not read. It may have been removed, replaced, or it is out of reach for this host.`));
3602
+ continue;
3603
+ }
3604
+ visited.push(address);
3605
+ const answer = await options.dispatcher.send(address, request).catch((e) => {
3606
+ return {
3607
+ reply: {
3608
+ type: "error",
3609
+ code: "TOOL_EXECUTION_FAILED",
3610
+ message: e instanceof Error ? e.message : String(e)
3611
+ },
3612
+ documentUrl: ""
3613
+ };
3614
+ });
3615
+ if (answer.reply.type !== "perceive-result") {
3616
+ const reason = answer.reply.type === "error" ? answer.reply.message : "it returned an unexpected reply";
3617
+ nodes.push(note(`A nested frame "${next.hint}" (${next.url}) was not read: ${reason}`));
3618
+ continue;
3619
+ }
3620
+ if (frameKey(answer.documentUrl) !== frameKey(next.url)) {
3621
+ nodes.push(note(`A nested frame "${next.hint}" (${next.url}) navigated away while it was being read (it answered from ${answer.documentUrl}); its content was discarded.`));
3622
+ continue;
3623
+ }
3624
+ descended += 1;
3625
+ absorb(answer.reply, address, frameLabelOf(next), `f${descended}-`);
3626
+ }
3627
+ if (skipped.length > 0) nodes.push(note(`${skipped.length} nested frame(s) were not read because this page exceeds the per-perception budget (${budget.maxFrames} frames / ${budget.maxNodes} nodes): ${skipped.join(", ")}. The content above is complete for the frames that were read.`));
3628
+ return {
3629
+ type: "perceive-result",
3630
+ result: {
3631
+ nodes,
3632
+ ...images.length > 0 ? { images } : {},
3633
+ ...imagesOmitted > 0 ? { imagesOmitted } : {},
3634
+ ...imageFailures > 0 ? { imageFailures } : {},
3635
+ ...frameNotes.length > 0 ? { frameNotes } : {}
3636
+ },
3637
+ targets
3638
+ };
3639
+ }
3640
+ async function execute(request) {
3641
+ const address = refFrames.get(request.request.ref) ?? await options.dispatcher.mainFrame();
3642
+ return (await options.dispatcher.send(address, request)).reply;
3643
+ }
3644
+ return {
3645
+ perceive,
3646
+ execute
3647
+ };
3648
+ }
3649
+
3650
+ //#endregion
3651
+ //#region ../browser/src/host/protocol.ts
3347
3652
  const isRecord = (v) => typeof v === "object" && v !== null;
3348
3653
  const isNonEmptyString = (v) => typeof v === "string" && v !== "";
3349
3654
  /** Worker 侧入站校验:非法消息返回 undefined(忽略) */
@@ -3431,6 +3736,9 @@ function parseWorkerEvent(data) {
3431
3736
  default: return;
3432
3737
  }
3433
3738
  }
3739
+
3740
+ //#endregion
3741
+ //#region ../browser/src/ui/workerUiBridge.ts
3434
3742
  /**
3435
3743
  * Worker 内 UiBridge:request → 'interaction' 消息到主线程,
3436
3744
  * 挂起等待 'interaction-response' → resolve(行内 await 跨线程成立)。
@@ -3485,6 +3793,9 @@ var WorkerUiBridge = class {
3485
3793
  });
3486
3794
  }
3487
3795
  };
3796
+
3797
+ //#endregion
3798
+ //#region ../browser/src/host/workerRuntimeHost.ts
3488
3799
  const serializeError = (e) => ({
3489
3800
  code: e instanceof WebSkillError ? e.code : "RUN_FAILED",
3490
3801
  message: e instanceof Error ? e.message : String(e)
@@ -3712,6 +4023,9 @@ function startWorkerRuntimeHost(scope, overrides = {}) {
3712
4023
  }
3713
4024
  });
3714
4025
  }
4026
+
4027
+ //#endregion
4028
+ //#region ../browser/src/host/workerClient.ts
3715
4029
  /** 主线程客户端:init/run/cancel/status/dispose 的 Promise API + 交互转发 */
3716
4030
  var WorkerRuntimeClient = class {
3717
4031
  #worker;
@@ -3857,6 +4171,9 @@ var WorkerRuntimeClient = class {
3857
4171
  }
3858
4172
  }
3859
4173
  };
4174
+
4175
+ //#endregion
4176
+ //#region ../browser/src/memory/encryptedMemoryStore.ts
3860
4177
  /**
3861
4178
  * 静态加密的 MemoryStore 包装(FR-19.5)。落盘形态:
3862
4179
  * `{ v: 1, iv: base64, ct: base64 }`;每次写入生成新的 12 字节随机 IV
@@ -4024,6 +4341,9 @@ async function deleteMemoryEncryptionKey(name = "user-profile") {
4024
4341
  db.close();
4025
4342
  }
4026
4343
  }
4344
+
4345
+ //#endregion
4346
+ //#region ../browser/src/host/portMatrix.ts
4027
4347
  /**
4028
4348
  * 端口 × 宿主类型的**唯一定义**(AC-17.4)。
4029
4349
  * About 页与装配工厂都读这一份;护栏 `port-matrix-single-source` 盯着不许再抄。
@@ -4173,6 +4493,9 @@ function inspectHostWiring(input) {
4173
4493
  function missingPorts(reports) {
4174
4494
  return reports.filter((report) => report.status === "missing");
4175
4495
  }
4496
+
4497
+ //#endregion
4498
+ //#region ../browser/src/host/createBrowserChatbotHost.ts
4176
4499
  function createBrowserChatbotHost(options) {
4177
4500
  const { fs, managedRoot, skillRoots, navigation, overrides } = options;
4178
4501
  const chatbotAdapter = {
@@ -4197,6 +4520,9 @@ function createBrowserChatbotHost(options) {
4197
4520
  connectFacade: overrides?.connectFacade ?? connectFacade
4198
4521
  };
4199
4522
  }
4523
+
4524
+ //#endregion
4525
+ //#region ../browser/src/net/fetchLinkedDocument.ts
4200
4526
  const DEFAULT_TIMEOUT_MS = 3e4;
4201
4527
  /**
4202
4528
  * 默认的链接文档读取实现(分册 22 §2.2)。
@@ -4227,6 +4553,9 @@ function createFetchLinkedDocumentReader(options = {}) {
4227
4553
  }
4228
4554
  };
4229
4555
  }
4556
+
4557
+ //#endregion
4558
+ //#region ../browser/src/document/docx.ts
4230
4559
  /**
4231
4560
  * docx 正文抽取(分册 22 §2.4 / FR-23.7)。
4232
4561
  *
@@ -4304,6 +4633,9 @@ async function extractDocxText(bytes) {
4304
4633
  }
4305
4634
  return blocks.join("\n").replace(/\n{3,}/g, "\n\n").trim();
4306
4635
  }
4636
+
4637
+ //#endregion
4638
+ //#region ../browser/src/document/xlsx.ts
4307
4639
  /**
4308
4640
  * xlsx 文本抽取(0.13.0 分册 12)。
4309
4641
  *
@@ -4553,6 +4885,9 @@ async function extractXlsxText(bytes) {
4553
4885
  }
4554
4886
  return sections.join("\n\n");
4555
4887
  }
4888
+
4889
+ //#endregion
4890
+ //#region ../browser/src/viewer/viewerCsp.ts
4556
4891
  /**
4557
4892
  * 文档投放面的 CSP 单一来源(0.11.0 分册 18 FR-18.3 / AC-G21)。
4558
4893
  *
@@ -4603,6 +4938,9 @@ function viewerCspHeader(options) {
4603
4938
  }
4604
4939
  /** 本版固定的 sandbox token(供判据与装配文档引用,避免第二份清单) */
4605
4940
  const VIEWER_SANDBOX_TOKENS = SANDBOX_TOKENS;
4941
+
4942
+ //#endregion
4943
+ //#region ../browser/src/viewer/documentSurface.ts
4606
4944
  const DEFAULT_MAX_VIEWER_PAYLOAD_BYTES = 2e6;
4607
4945
  const DEFAULT_HANDSHAKE_TIMEOUT_MS = 1e4;
4608
4946
  /** hello 的重发间隔:viewer 脚本加载完之前投出去的消息全部丢失 */
@@ -4674,6 +5012,16 @@ async function openDocumentSurface(input, options) {
4674
5012
  function defaultOpen(url, target) {
4675
5013
  return globalThis.open?.(url, target) ?? null;
4676
5014
  }
5015
+ /**
5016
+ * 把 `openDocumentSurface` 柯里化成 `DocumentSurfaceHost`(0.15.0 分册 13 FR-13.3)。
5017
+ *
5018
+ * **只绑定选项,不新增任何逻辑**:体积上限、握手超时、`DOCUMENT_SURFACE_DECLINED`
5019
+ * 与审计事件全部沿用上面那一份实现(FR-13.5「逐条不变」的实现基础)。
5020
+ * @experimental
5021
+ */
5022
+ function createDocumentSurfaceHost(options) {
5023
+ return { open: async (input) => void await openDocumentSurface(input, options) };
5024
+ }
4677
5025
  /** viewer 是 opaque origin,`postMessage` 的 targetOrigin 只能是 `*` —— 用 channelId 做配对校验 */
4678
5026
  function viewerOrigin(_options) {
4679
5027
  return "*";
@@ -4732,6 +5080,9 @@ async function audit(options, input, data) {
4732
5080
  }
4733
5081
  }).catch(() => void 0);
4734
5082
  }
5083
+
5084
+ //#endregion
5085
+ //#region ../browser/src/viewer/shell.ts
4735
5086
  /**
4736
5087
  * 启动外壳:等主应用的 hello → 回报 ready → 收文档 → 写进 DOM。
4737
5088
  *
@@ -4764,6 +5115,9 @@ function startViewerShell(host, mount, onData) {
4764
5115
  host.removeEventListener("message", onMessage);
4765
5116
  } };
4766
5117
  }
5118
+
5119
+ //#endregion
5120
+ //#region ../browser/src/viewer/blockedResources.ts
4767
5121
  /**
4768
5122
  * 监听 CSP 违规并把被拦资源汇总成一句话。
4769
5123
  *
@@ -4797,4 +5151,4 @@ function originOf(blockedURI) {
4797
5151
  }
4798
5152
 
4799
5153
  //#endregion
4800
- export { BrowserSkillManager, BrowserWorkerScriptExecutor, ChromeBuiltinLlmClient, DEFAULT_MAX_VIEWER_PAYLOAD_BYTES, DOCUMENT_SURFACE_AUDIT_EVENT, DOCX_UNEXTRACTED, HOST_PORT_MATRIX, IframeWorkerLike, OpfsProvider, SANDBOX_PAGE_SCRIPT_SOURCE, TsTranspiler, VIEWER_SANDBOX_TOKENS, WORKER_BOOTSTRAP_SOURCE, WorkerRuntimeClient, WorkerUiBridge, XLSX_UNEXTRACTED, blockedMessage, bridgeError, captureElementImage, checkDictationAvailability, compressImageToBudget, createBrowserChatbotHost, createDomPageActionExecutor, createDomPerceptionReader, createEncryptedMemoryStore, createFetchLinkedDocumentReader, createIframeWorker, createLlmClient, createPageAgentHandler, createRemotePageActionExecutor, createRemotePerceptionReader, createRemoteTargetRegistry, deleteMemoryEncryptionKey, extractDocxText, extractXlsxText, extractZipWeb, generateMemoryEncryptionKey, inspectHostWiring, installWebSkillNavigator, isCapturableElement, isCaptureFailure, isEncryptedMemoryValue, isOpfsAvailable, missingPorts, openDocumentSurface, openMemoryEncryptionKey, parseBridgeRequest, parseMainMessage, parseWorkerEvent, probeChromeBuiltinAvailability, sha256HexWeb, startDictation, startViewerShell, startWorkerRuntimeHost, viewerCspHeader, watchBlockedResources };
5154
+ export { BrowserSkillManager, BrowserWorkerScriptExecutor, ChromeBuiltinLlmClient, DEFAULT_FRAME_BUDGET, DEFAULT_MAX_VIEWER_PAYLOAD_BYTES, DOCUMENT_SURFACE_AUDIT_EVENT, DOCX_UNEXTRACTED, HOST_PORT_MATRIX, IframeWorkerLike, OpfsProvider, SANDBOX_PAGE_SCRIPT_SOURCE, TsTranspiler, VIEWER_SANDBOX_TOKENS, WORKER_BOOTSTRAP_SOURCE, WorkerRuntimeClient, WorkerUiBridge, XLSX_UNEXTRACTED, blockedMessage, bridgeError, captureElementImage, checkDictationAvailability, compressImageToBudget, createBrowserChatbotHost, createDocumentSurfaceHost, createDomPageActionExecutor, createDomPerceptionReader, createEncryptedMemoryStore, createFetchLinkedDocumentReader, createFrameRouter, createIframeWorker, createLlmClient, createPageAgentHandler, createRemotePageActionExecutor, createRemotePerceptionReader, createRemoteTargetRegistry, deleteMemoryEncryptionKey, extractDocxText, extractXlsxText, extractZipWeb, generateMemoryEncryptionKey, inspectHostWiring, installWebSkillNavigator, isCapturableElement, isCaptureFailure, isEncryptedMemoryValue, isOpfsAvailable, missingPorts, openDocumentSurface, openMemoryEncryptionKey, parseBridgeRequest, parseMainMessage, parseWorkerEvent, probeChromeBuiltinAvailability, sha256HexWeb, startDictation, startViewerShell, startWorkerRuntimeHost, viewerCspHeader, watchBlockedResources };