@webskill/sdk 0.22.0 → 0.24.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 (32) hide show
  1. package/dist/agent.d.ts +3 -3
  2. package/dist/agent.js +200 -54
  3. package/dist/{approval-DWQlDPbY.js → approval-7CuZS3Z4.js} +3 -3
  4. package/dist/browser.d.ts +52 -7
  5. package/dist/browser.js +615 -59
  6. package/dist/{geometry-wx5ZTYzi.js → geometry-CRhuySKV.js} +8 -1
  7. package/dist/governance.d.ts +22 -4
  8. package/dist/governance.js +112 -12
  9. package/dist/{index-CjwdZQOS.d.ts → index-B3rMAUWB.d.ts} +138 -19
  10. package/dist/{index-YPd8ZSEa.d.ts → index-Bq299VnF.d.ts} +6 -3
  11. package/dist/{index-BiO9_XRk.d.ts → index-mKgZU7cG.d.ts} +62 -5
  12. package/dist/index.d.ts +4 -4
  13. package/dist/index.js +10 -8
  14. package/dist/{linkedDocument-CIuh_Yp0.js → linkedDocument-CZZOl9cO.js} +44 -4
  15. package/dist/mcp.d.ts +2 -2
  16. package/dist/node.d.ts +3 -3
  17. package/dist/node.js +12 -5
  18. package/dist/{openUiLibrary-B7j3rLrm.js → openUiLibrary-CxtrnX54.js} +1 -1
  19. package/dist/{openUiSpecLang-BSYYnjay.js → openUiSpecLang-DIcLcybq.js} +148 -13
  20. package/dist/{pathSecurity-B1owvJAF.js → pathSecurity-CirkQwWP.js} +12 -1
  21. package/dist/{skill-CAJMsLod.js → skill-WSUDp6A1.js} +1 -1
  22. package/dist/{skillVersionStore-B24Jjjry-BY1H7Krp.d.ts → skillVersionStore-S4_HJ_Fl-Ds97pwm5.d.ts} +35 -4
  23. package/dist/testing.d.ts +1 -1
  24. package/dist/{types-CpDRZ0rA-BM5FI9oN.d.ts → types-CpDRZ0rA-CFQ-vdKz.d.ts} +12 -1
  25. package/dist/ui-react.d.ts +11 -4
  26. package/dist/ui-react.js +76 -25
  27. package/dist/ui-vue.d.ts +1 -1
  28. package/dist/ui.d.ts +4 -4
  29. package/dist/ui.js +6 -6
  30. package/dist/{webSkillApi-Dy-Zjv0y.js → webSkillApi-D5VMUnrv.js} +2 -2
  31. package/dist/{webskillLitCatalog-D5BCiMCU.js → webskillLitCatalog-BPyjYuRT.js} +1 -1
  32. package/package.json +1 -1
@@ -43,6 +43,13 @@ function toFrameScopes(scope) {
43
43
  ...scope.exclude ? { exclude: scope.exclude } : {}
44
44
  }];
45
45
  }
46
+ /** 四个方向的规范清单;工具层校验与文案生成都从这里取,不各写一份 */
47
+ const SCROLL_DIRECTIONS = [
48
+ "up",
49
+ "down",
50
+ "left",
51
+ "right"
52
+ ];
46
53
 
47
54
  //#endregion
48
55
  //#region ../agent/src/pageAction/types.ts
@@ -712,4 +719,4 @@ function readJpegSize(view, length) {
712
719
  }
713
720
 
714
721
  //#endregion
715
- export { DOCUMENT_READ_BUDGET as C, toFrameScopes as D, toActionFrameScopes as E, frameLabel as O, sniffDocumentFormat as S, PAGE_DOCUMENT_REF as T, defersImage as _, columnWidthToPixels as a, isPdfTextTrustworthy as b, isRangeTopLeft as c, rangeContains as d, readImageSize as f, asReadMode as g, createDocumentToolSource as h, MAX_DIGIT_WIDTH as i, frameSteps as k, parseCellAddress as l, READ_DOCUMENT_TOOL as m, EMU_PER_POINT as n, fitWithin as o, PDF_LARGE_IMAGE_RATIO as p, EMU_PER_TWIP as r, formatCellAddress as s, EMU_PER_PIXEL as t, parseCellRange as u, takesImage as v, PAGE_ACTION_KINDS as w, measurePdfTextQuality as x, PDF_GARBLED_RATIO as y };
722
+ export { frameSteps as A, DOCUMENT_READ_BUDGET as C, SCROLL_DIRECTIONS as D, toActionFrameScopes as E, toFrameScopes as O, sniffDocumentFormat as S, PAGE_DOCUMENT_REF as T, defersImage as _, columnWidthToPixels as a, isPdfTextTrustworthy as b, isRangeTopLeft as c, rangeContains as d, readImageSize as f, asReadMode as g, createDocumentToolSource as h, MAX_DIGIT_WIDTH as i, frameLabel as k, parseCellAddress as l, READ_DOCUMENT_TOOL as m, EMU_PER_POINT as n, fitWithin as o, PDF_LARGE_IMAGE_RATIO as p, EMU_PER_TWIP as r, formatCellAddress as s, EMU_PER_PIXEL as t, parseCellRange as u, takesImage as v, PAGE_ACTION_KINDS as w, measurePdfTextQuality as x, PDF_GARBLED_RATIO as y };
@@ -1,6 +1,6 @@
1
- import { K as FileSystemProvider, S as UiBridge, _t as SkillDocument, et as Page, f as LlmMessage, ht as SkillCatalogEntry, l as LlmClient, tt as PageQuery, xt as SkillManagerPort } from "./types-CpDRZ0rA-BM5FI9oN.js";
2
- import { Wt as RuntimeRun, dn as SkillIntegrityGuard, fn as SkillOutcomeReporter, gn as SkillStateGuard, hr as WebSkillRuntime, tt as IntegrityVerdict } from "./index-YPd8ZSEa.js";
3
- import { _ as SkillState, a as AuditLog, b as SkillVersionStore, c as CandidateFile, d as CandidateSkill, f as CandidateSource, g as SKILL_VERSION_PAGE_SIZE, h as CompositeApprovalPolicy, i as AuditEvent, l as CandidatePage, m as CandidateStore, n as ApprovalDecision, o as AuditQueryFilter, p as CandidateStatus, r as ApprovalPolicy, s as CANDIDATE_PAGE_SIZE, t as AlwaysHumanApprovalPolicy, u as CandidateRisk, v as SkillVersion, x as candidateToCatalogEntry, y as SkillVersionPage } from "./skillVersionStore-B24Jjjry-BY1H7Krp.js";
1
+ import { K as FileSystemProvider, S as UiBridge, _t as SkillDocument, et as Page, f as LlmMessage, ht as SkillCatalogEntry, l as LlmClient, tt as PageQuery, xt as SkillManagerPort } from "./types-CpDRZ0rA-CFQ-vdKz.js";
2
+ import { Wt as RuntimeRun, dn as SkillIntegrityGuard, fn as SkillOutcomeReporter, gn as SkillStateGuard, hr as WebSkillRuntime, tt as IntegrityVerdict } from "./index-Bq299VnF.js";
3
+ import { S as candidateToCatalogEntry, _ as SKILL_VERSION_PAGE_SIZE, a as AuditLog, b as SkillVersionPage, c as CandidateBinaryRef, d as CandidateRisk, f as CandidateSkill, g as CompositeApprovalPolicy, h as CandidateStore, i as AuditEvent, l as CandidateFile, m as CandidateStatus, n as ApprovalDecision, o as AuditQueryFilter, p as CandidateSource, r as ApprovalPolicy, s as CANDIDATE_PAGE_SIZE, t as AlwaysHumanApprovalPolicy, u as CandidatePage, v as SkillState, x as SkillVersionStore, y as SkillVersion } from "./skillVersionStore-S4_HJ_Fl-Ds97pwm5.js";
4
4
  //#region ../governance/dist/index.d.ts
5
5
  //#region src/candidate/candidateNormalizer.d.ts
6
6
  /** 剥 markdown fence 与 <think> 块、截取首尾 {};非对象 → CANDIDATE_INVALID */
@@ -10,10 +10,14 @@ declare function sanitizeCandidateName(raw: string): string;
10
10
  /**
11
11
  * 文件归一:补 SKILL.md;路径含 `..` / 以 `/` 开头 / 含 `\` → CANDIDATE_INVALID;
12
12
  * scripts/ 下必须是 .ts/.js。
13
+ *
14
+ * 路径校验对两种形态**一视同仁**(0.23.0 分册 20 FR-20.3):这套校验本来就与内容无关,
15
+ * 二进制条目走另一套校验等于给越界路径开第二道门。
13
16
  */
14
17
  declare function normalizeCandidateFiles(files: Array<{
15
18
  path: string;
16
19
  content: string;
20
+ binary?: CandidateBinaryRef;
17
21
  }>, name: string, description: string): CandidateFile[];
18
22
  /** 含脚本且 LLM 自报 low → 强制 medium 并追加"必须人工审批"原因 */
19
23
  declare function normalizeRisk(declared: unknown, files: CandidateFile[], reasons: string[]): {
@@ -53,6 +57,20 @@ interface GeneratedSkillSubmission {
53
57
  sessionId?: string;
54
58
  /** 用户确认的时刻(FR-9.7 的「用户确认事实」) */
55
59
  confirmedAt: string;
60
+ /**
61
+ * 已物化的二进制,键是 `draft.files[].path`(0.23.0 分册 20)。
62
+ * 字节由 agent 侧在用户确认之前取好——候选一旦生成就必须能脱离会话附件独立存活(FR-20.6)。
63
+ */
64
+ binaries?: ReadonlyMap<string, SubmittedBinary>;
65
+ }
66
+ /** 一份随候选提交的字节及其校验信息(0.23.0 分册 20) */
67
+ interface SubmittedBinary {
68
+ bytes: Uint8Array;
69
+ size: number;
70
+ /** 十六进制小写 */
71
+ sha256: string;
72
+ /** 上传时的原始文件名 */
73
+ sourceName: string;
56
74
  }
57
75
  interface CandidateSinkOptions {
58
76
  store: CandidateStore;
@@ -561,4 +579,4 @@ declare function createMissHook(deps: {
561
579
  */
562
580
  declare function completeText(llm: LlmClient, messages: LlmMessage[]): Promise<string>;
563
581
  //#endregion
564
- export { AUDIT_EVENT_TYPES, AUDIT_EVENT_TYPE_LIST, AUDIT_PAGE_SIZE, AlwaysHumanApprovalPolicy, type ApprovalDecision, type ApprovalPolicy, type AuditChainVerification, type AuditEvent, type AuditEventType, type AuditLog, type AuditPage, type AuditQueryFilter, CANDIDATE_PAGE_SIZE, type CandidateFile, type CandidatePage, type CandidateRisk, type CandidateSink, type CandidateSinkOptions, type CandidateSkill, type CandidateSource, type CandidateStatus, CandidateStore, CompositeApprovalPolicy, DependencyGraph, DocumentSkillExtractor, type EvaluationReport, type EvaluationResult, EvaluationRunner, type EvaluationTask, FailureAnalyzer, type FailureDiagnosis, FsAuditLog, type GeneratedSkillSubmission, LlmCandidateGenerator, POLICY_DENIAL_CODES, QUARANTINE_REASONS, type RepairOption, RepairPlanner, SCORING_WEIGHTS, SKILL_VERSION_PAGE_SIZE, type ScoreInput, SimilarityDetector, SkillScorer, type SkillState, SkillStatePolicy, type SkillVersion, type SkillVersionPage, SkillVersionStore, type SourceDocument, USER_CAUSED_CODES, candidateToCatalogEntry, completeText, createCandidateSink, createMissHook, jaccardSimilarity, normalizeCandidate, normalizeCandidateFiles, normalizeRisk, parseJsonObject, readDocument, sanitizeCandidateName, suggestFromFailedRun, validateCandidate };
582
+ export { AUDIT_EVENT_TYPES, AUDIT_EVENT_TYPE_LIST, AUDIT_PAGE_SIZE, AlwaysHumanApprovalPolicy, type ApprovalDecision, type ApprovalPolicy, type AuditChainVerification, type AuditEvent, type AuditEventType, type AuditLog, type AuditPage, type AuditQueryFilter, CANDIDATE_PAGE_SIZE, type CandidateBinaryRef, type CandidateFile, type CandidatePage, type CandidateRisk, type CandidateSink, type CandidateSinkOptions, type CandidateSkill, type CandidateSource, type CandidateStatus, CandidateStore, CompositeApprovalPolicy, DependencyGraph, DocumentSkillExtractor, type EvaluationReport, type EvaluationResult, EvaluationRunner, type EvaluationTask, FailureAnalyzer, type FailureDiagnosis, FsAuditLog, type GeneratedSkillSubmission, LlmCandidateGenerator, POLICY_DENIAL_CODES, QUARANTINE_REASONS, type RepairOption, RepairPlanner, SCORING_WEIGHTS, SKILL_VERSION_PAGE_SIZE, type ScoreInput, SimilarityDetector, SkillScorer, type SkillState, SkillStatePolicy, type SkillVersion, type SkillVersionPage, SkillVersionStore, type SourceDocument, type SubmittedBinary, USER_CAUSED_CODES, candidateToCatalogEntry, completeText, createCandidateSink, createMissHook, jaccardSimilarity, normalizeCandidate, normalizeCandidateFiles, normalizeRisk, parseJsonObject, readDocument, sanitizeCandidateName, suggestFromFailedRun, validateCandidate };
@@ -1,6 +1,6 @@
1
1
  import { n as messageOf, t as WebSkillError } from "./errors-BDZNpC13.js";
2
- import { y as isValidSkillName } from "./skill-CAJMsLod.js";
3
- import { a as atomicWriteText, t as assertSafePathSegment } from "./pathSecurity-B1owvJAF.js";
2
+ import { y as isValidSkillName } from "./skill-WSUDp6A1.js";
3
+ import { a as atomicWriteBinary, o as atomicWriteText, t as assertSafePathSegment } from "./pathSecurity-CirkQwWP.js";
4
4
  import { d as partsToText, p as textParts } from "./llm-eIQNO9tr.js";
5
5
  import { n as AUDIT_EVENT_TYPE_LIST, t as AUDIT_EVENT_TYPES } from "./eventTypes-DcTQXSV1.js";
6
6
 
@@ -36,8 +36,32 @@ const kindOf = (path) => {
36
36
  return "asset";
37
37
  };
38
38
  /**
39
+ * 二进制引用的形状校验(0.23.0 分册 20)。
40
+ *
41
+ * 这条管线的既定前提是「不信任全链路」,所以引用也要逐字段查过才收下:
42
+ * 一条字段缺失的引用会一路活到安装那一步,届时才表现为读不到字节的技能包。
43
+ * `file` 必须是单个文件名——带路径分隔符的值等于一条越出候选旁路目录的通路。
44
+ */
45
+ function readBinaryRef(raw) {
46
+ if (raw === void 0 || raw === null) return void 0;
47
+ if (typeof raw !== "object" || Array.isArray(raw)) return invalid("Candidate file \"binary\" must be an object");
48
+ const { file, size, sha256, sourceName } = raw;
49
+ if (typeof file !== "string" || file === "" || file.includes("/") || file.includes("\\") || file.includes("..")) return invalid(`Candidate binary file name is not allowed: ${JSON.stringify(file)}`);
50
+ if (typeof size !== "number" || !Number.isFinite(size) || size < 0) return invalid(`Candidate binary "${file}" has an invalid size`);
51
+ if (typeof sha256 !== "string" || !/^[0-9a-f]{64}$/.test(sha256)) return invalid(`Candidate binary "${file}" has an invalid sha256`);
52
+ return {
53
+ file,
54
+ size,
55
+ sha256,
56
+ sourceName: typeof sourceName === "string" ? sourceName : file
57
+ };
58
+ }
59
+ /**
39
60
  * 文件归一:补 SKILL.md;路径含 `..` / 以 `/` 开头 / 含 `\` → CANDIDATE_INVALID;
40
61
  * scripts/ 下必须是 .ts/.js。
62
+ *
63
+ * 路径校验对两种形态**一视同仁**(0.23.0 分册 20 FR-20.3):这套校验本来就与内容无关,
64
+ * 二进制条目走另一套校验等于给越界路径开第二道门。
41
65
  */
42
66
  function normalizeCandidateFiles(files, name, description) {
43
67
  const out = [];
@@ -49,7 +73,8 @@ function normalizeCandidateFiles(files, name, description) {
49
73
  out.push({
50
74
  path: p,
51
75
  kind,
52
- content: String(file.content ?? "")
76
+ content: String(file.content ?? ""),
77
+ ...file.binary !== void 0 ? { binary: file.binary } : {}
53
78
  });
54
79
  }
55
80
  if (!out.some((f) => f.kind === "skill-md")) out.unshift({
@@ -77,10 +102,15 @@ function normalizeCandidate(input) {
77
102
  const description = typeof raw["description"] === "string" ? raw["description"] : "";
78
103
  if (description.trim() === "") invalid("Candidate is missing a description");
79
104
  const name = sanitizeCandidateName(typeof raw["name"] === "string" ? raw["name"] : invalid("Candidate is missing a name"));
80
- const files = normalizeCandidateFiles((Array.isArray(raw["files"]) ? raw["files"] : []).map((f) => ({
81
- path: String(f?.["path"] ?? ""),
82
- content: String(f?.["content"] ?? "")
83
- })), name, description);
105
+ const files = normalizeCandidateFiles((Array.isArray(raw["files"]) ? raw["files"] : []).map((f) => {
106
+ const record = f ?? {};
107
+ const binary = readBinaryRef(record["binary"]);
108
+ return {
109
+ path: String(record["path"] ?? ""),
110
+ content: String(record["content"] ?? ""),
111
+ ...binary !== void 0 ? { binary } : {}
112
+ };
113
+ }), name, description);
84
114
  const declaredReasons = Array.isArray(raw["riskReasons"]) ? raw["riskReasons"].map(String) : [];
85
115
  const { risk, reasons } = normalizeRisk(raw["risk"], files, declaredReasons);
86
116
  const now = input.now?.() ?? (/* @__PURE__ */ new Date()).toISOString();
@@ -137,6 +167,8 @@ function takeTailPage(all, options, defaultLimit, what) {
137
167
  //#endregion
138
168
  //#region ../governance/src/candidate/candidateStore.ts
139
169
  const dirOf$1 = (root) => `${root}/.webskill/candidates`;
170
+ /** 候选的二进制旁路目录(0.23.0 分册 20 §3):与元数据 JSON 同级,整目录随候选一起删 */
171
+ const candidateBinaryDir = (root, id) => `${dirOf$1(root)}/${id}.files`;
140
172
  /** 候选列表的缺省页长。缺省属于实现,不属于调用方 */
141
173
  const CANDIDATE_PAGE_SIZE = 50;
142
174
  /** 逐文件持久化的候选存储:<managedRoot>/.webskill/candidates/<id>.json */
@@ -149,11 +181,37 @@ var CandidateStore = class {
149
181
  this.#fs = deps.fs;
150
182
  this.#isSkillInstalled = deps.isSkillInstalled;
151
183
  }
152
- async save(candidate) {
184
+ /**
185
+ * 存候选。`binaries` 的键是 `CandidateFile.binary.file`,缺省即本候选全是文本。
186
+ *
187
+ * 落盘顺序是**先字节、后 JSON**(0.23.0 分册 20 §3.2):反过来的话,
188
+ * 崩溃会留下一条指向不存在字节的元数据,而那种候选要到审批安装那一步才暴露——
189
+ * 正是 FR-20.6 要避免的那类「延迟到审批才失败」。
190
+ */
191
+ async save(candidate, binaries) {
153
192
  validateCandidate(candidate);
154
193
  assertSafePathSegment(candidate.id, "candidate id");
194
+ for (const file of candidate.files) {
195
+ if (file.binary === void 0) continue;
196
+ const bytes = binaries?.get(file.binary.file);
197
+ if (bytes === void 0) {
198
+ if (await this.#fs.exists(this.#binaryPath(candidate.id, file.binary.file))) continue;
199
+ throw new WebSkillError("CANDIDATE_INVALID", `Candidate "${candidate.name}" declares binary "${file.path}" but its bytes were not provided`);
200
+ }
201
+ assertSafePathSegment(file.binary.file, "candidate binary file");
202
+ await atomicWriteBinary(this.#fs, this.#binaryPath(candidate.id, file.binary.file), bytes);
203
+ }
155
204
  await atomicWriteText(this.#fs, `${dirOf$1(this.#root)}/${candidate.id}.json`, JSON.stringify(candidate, null, 2));
156
205
  }
206
+ /** 读回候选旁路里的一份字节(安装时按原样写进技能目录,0.23.0 分册 20 FR-20.8) */
207
+ readCandidateBinary(id, file) {
208
+ assertSafePathSegment(id, "candidate id");
209
+ assertSafePathSegment(file, "candidate binary file");
210
+ return this.#fs.readBinary(this.#binaryPath(id, file));
211
+ }
212
+ #binaryPath(id, file) {
213
+ return `${candidateBinaryDir(this.#root, id)}/${file}`;
214
+ }
157
215
  async get(id) {
158
216
  assertSafePathSegment(id, "candidate id");
159
217
  const path = `${dirOf$1(this.#root)}/${id}.json`;
@@ -202,6 +260,8 @@ var CandidateStore = class {
202
260
  if (candidate.status === "approved") throw new WebSkillError("GOVERNANCE_FAILED", `Candidate "${candidate.name}" cannot be removed from status "${candidate.status}"`);
203
261
  if (candidate.status === "published" && await this.#skillStillInstalled(candidate.name)) throw new WebSkillError("GOVERNANCE_FAILED", `Candidate "${candidate.name}" is the provenance record of an installed skill and cannot be removed; uninstall the skill first`);
204
262
  await this.#fs.remove(`${dirOf$1(this.#root)}/${id}.json`);
263
+ const binaryDir = candidateBinaryDir(this.#root, id);
264
+ if (await this.#fs.exists(binaryDir)) await this.#fs.remove(binaryDir, { recursive: true });
205
265
  }
206
266
  async #skillStillInstalled(name) {
207
267
  return this.#isSkillInstalled === void 0 ? true : await this.#isSkillInstalled(name);
@@ -224,6 +284,16 @@ function candidateToCatalogEntry(candidate) {
224
284
  //#endregion
225
285
  //#region ../governance/src/candidate/candidateSink.ts
226
286
  /**
287
+ * 旁路文件名:序号在前保证唯一,原名跟在后面是为了让人在文件管理器里也认得出
288
+ * 哪个是哪个(0.23.0 分册 20 §3)。直接拿技能内路径当文件名不行——
289
+ * 那是一个平铺目录,`references/a/t.xlsx` 与 `references/b/t.xlsx` 会撞在一起。
290
+ * 权威的原名记在 `sourceName` 里,这里只保留能安全落盘的那部分。
291
+ */
292
+ const binaryFileNameOf = (index, path) => {
293
+ const safe = (path.split("/").pop() ?? "").replace(/[^A-Za-z0-9._-]/g, "_").replace(/^\.+/, "");
294
+ return `${index}-${safe === "" ? "file" : safe}`;
295
+ };
296
+ /**
227
297
  * 把 agent 生成的技能草稿接进既有的候选管线(设计 02 §5)。
228
298
  *
229
299
  * 走的是与文档抽取、runtime-miss 完全相同的 `normalizeCandidate` → `CandidateStore.save`,
@@ -232,6 +302,26 @@ function candidateToCatalogEntry(candidate) {
232
302
  function createCandidateSink(options) {
233
303
  return { async submit(input) {
234
304
  const { draft } = input;
305
+ const bytes = /* @__PURE__ */ new Map();
306
+ const files = (draft.files ?? []).map((file, index) => {
307
+ const payload = input.binaries?.get(file.path);
308
+ if (payload === void 0) return {
309
+ path: file.path,
310
+ content: file.content
311
+ };
312
+ const name = binaryFileNameOf(index, file.path);
313
+ bytes.set(name, payload.bytes);
314
+ return {
315
+ path: file.path,
316
+ content: "",
317
+ binary: {
318
+ file: name,
319
+ size: payload.size,
320
+ sha256: payload.sha256,
321
+ sourceName: payload.sourceName
322
+ }
323
+ };
324
+ });
235
325
  const candidate = normalizeCandidate({
236
326
  raw: {
237
327
  name: draft.name,
@@ -239,7 +329,7 @@ function createCandidateSink(options) {
239
329
  files: [{
240
330
  path: "SKILL.md",
241
331
  content: draft.content
242
- }, ...draft.files ?? []]
332
+ }, ...files]
243
333
  },
244
334
  source: "generated",
245
335
  ...options.now ? { now: options.now } : {},
@@ -250,7 +340,7 @@ function createCandidateSink(options) {
250
340
  confirmedAt: input.confirmedAt,
251
341
  ...input.sessionId !== void 0 ? { sessionId: input.sessionId } : {}
252
342
  };
253
- await options.store.save(candidate);
343
+ await options.store.save(candidate, bytes);
254
344
  await options.audit?.append({
255
345
  type: AUDIT_EVENT_TYPES.candidateCreated,
256
346
  target: candidate.id,
@@ -816,7 +906,11 @@ const fileOf = (root) => `${root}/.webskill/states.json`;
816
906
  const POLICY_DENIAL_CODES = /* @__PURE__ */ new Set([
817
907
  "NETWORK_BLOCKED",
818
908
  "TOOL_NOT_ALLOWED",
819
- "FS_PERMISSION_DENIED"
909
+ "FS_PERMISSION_DENIED",
910
+ "PAGE_ACTION_OUT_OF_SCOPE",
911
+ "PERCEPTION_SUBTREE_OUT_OF_SCOPE",
912
+ "PERCEPTION_NOT_ENABLED",
913
+ "SKILL_GENERATION_DISABLED"
820
914
  ]);
821
915
  /**
822
916
  * 用户自身原因的错误码(0.10.0 UI-UX5 #49-2):交互等待超时(用户没处理)与
@@ -826,7 +920,13 @@ const POLICY_DENIAL_CODES = /* @__PURE__ */ new Set([
826
920
  * 是因为宿主执行器也可能把「等用户时被取消/超时」包成 ok:false 的失败结果交回来——
827
921
  * 「算不算技能的错」的判定口径必须在上报侧只有这一处。
828
922
  */
829
- const USER_CAUSED_CODES = /* @__PURE__ */ new Set(["RUN_INTERACTION_TIMEOUT", "RUN_CANCELLED"]);
923
+ const USER_CAUSED_CODES = /* @__PURE__ */ new Set([
924
+ "RUN_INTERACTION_TIMEOUT",
925
+ "RUN_CANCELLED",
926
+ "PAGE_ACTION_DECLINED",
927
+ "TOOL_DENIED",
928
+ "DOCUMENT_SURFACE_DECLINED"
929
+ ]);
830
930
  /** 自动隔离的原因判别式(FR-12.6);人工隔离仍写自由文本 */
831
931
  const QUARANTINE_REASONS = {
832
932
  integrity: "integrity",
@@ -1,5 +1,5 @@
1
- import { L as ChatAttachmentKind, Rt as WebSkillErrorCode, S as UiBridge, a as InteractionOrigin, c as InteractionResponse, nt as RemoteUrlPolicy, s as InteractionRequest, t as Artifact } from "./types-CpDRZ0rA-BM5FI9oN.js";
2
- import { B as ExternalToolSource, F as DocxTextExtractor, Fn as ToolStepReader, M as DataSourceInfo, kn as ToolCallContext, mt as PptxTextExtractor, pt as PdfTextExtractor, vr as XlsxTextExtractor, xn as SpreadsheetImageBytes } from "./index-YPd8ZSEa.js";
1
+ import { L as ChatAttachmentKind, Rt as WebSkillErrorCode, S as UiBridge, a as InteractionOrigin, c as InteractionResponse, nt as RemoteUrlPolicy, s as InteractionRequest, t as Artifact } from "./types-CpDRZ0rA-CFQ-vdKz.js";
2
+ import { B as ExternalToolSource, F as DocxTextExtractor, Fn as ToolStepReader, M as DataSourceInfo, kn as ToolCallContext, mt as PptxTextExtractor, pt as PdfTextExtractor, vr as XlsxTextExtractor, xn as SpreadsheetImageBytes } from "./index-Bq299VnF.js";
3
3
  //#region ../agent/dist/index.d.ts
4
4
  //#region src/todo/types.d.ts
5
5
  /** 待办条目状态:未开始 / 进行中 / 已完成(FR-3.1) */
@@ -48,11 +48,18 @@ declare class TodoStore {
48
48
  /**
49
49
  * 更新单条。置为 `in-progress` 时其余进行中条目降级为 `pending`,
50
50
  * 每条降级各发一次 `todo.updated`,事件序列与状态变化一一对应。
51
+ *
52
+ * `options.concurrent` 由**编排器**在并发委派时传(0.23.0 分册 19 FR-19.9):
53
+ * 几个子 agent 真的在同时跑,把别人降级回 `pending` 是在界面上说谎。
54
+ * 模型经 `manage_todo` 的写入不传它,仍维持「同时只有一条进行中」——
55
+ * 那条约束针对的是模型乱标(名义并行、实则一件事),不是真并发。
51
56
  */
52
57
  update(id: string, patch: {
53
58
  status?: TodoStatus;
54
59
  title?: string;
55
60
  delegatedTo?: string;
61
+ }, options?: {
62
+ concurrent?: boolean;
56
63
  }): TodoList;
57
64
  clear(): void;
58
65
  }
@@ -90,9 +97,14 @@ interface GeneratedSkillDraft {
90
97
  description: string;
91
98
  /** SKILL.md 全文,含 frontmatter */
92
99
  content: string;
100
+ /**
101
+ * 附带文件。`attachmentId` 在场即本条目的内容是**本会话已上传的那个附件的字节**,
102
+ * 此时 `content` 恒为空串——模型从没持有过那些字节,让它复述等于让它编(0.23.0 分册 20)。
103
+ */
93
104
  files?: readonly {
94
105
  path: string;
95
106
  content: string;
107
+ attachmentId?: string;
96
108
  }[];
97
109
  /**
98
110
  * 模型声称这个技能会执行的工具调用(分册 30 / FR-30.4)。
@@ -105,6 +117,30 @@ interface GeneratedSkillDraft {
105
117
  args?: Record<string, unknown>;
106
118
  }[];
107
119
  }
120
+ /**
121
+ * 一个被指认的附件的字节与身份(0.23.0 分册 20)。
122
+ * 由宿主的 `SkillGeneratorOptions.resolveAttachment` 交出。
123
+ */
124
+ interface SkillAttachmentBytes {
125
+ bytes: Uint8Array;
126
+ /** 上传时的原始文件名,供审核者辨认(FR-20.10) */
127
+ name: string;
128
+ contentType?: string;
129
+ }
130
+ /**
131
+ * 已物化的一份二进制:字节加上它的身份与校验信息(0.23.0 分册 20)。
132
+ *
133
+ * `sha256` 不是装饰——AC-20.1 的「逐字节相同」靠它判,
134
+ * 而本册要防的失败模式正是**悄悄损坏**:被 UTF-8 往返污染过的 `.xlsx`
135
+ * 仍能被宽容的解析器打开,却在用户手里丢数据。
136
+ */
137
+ interface SkillBinaryPayload {
138
+ bytes: Uint8Array;
139
+ size: number;
140
+ /** 十六进制小写 */
141
+ sha256: string;
142
+ sourceName: string;
143
+ }
108
144
  /**
109
145
  * 候选收货端口。实现由宿主注入——`@webskill/agent` 不依赖 `@webskill/governance`
110
146
  * (治理层要求宿主提供治理根与审计存储,是可选层)。
@@ -117,6 +153,11 @@ interface SkillCandidateSink {
117
153
  sessionId?: string;
118
154
  /** 用户确认的时刻(FR-9.7 要求审计能查到确认事实) */
119
155
  confirmedAt: string;
156
+ /**
157
+ * 已物化的二进制,键是 `draft.files[].path`。缺省即本次生成全是文本(0.23.0 分册 20)。
158
+ * 字节在这里就已经读出来了:候选必须能脱离会话附件独立存活(FR-20.6)。
159
+ */
160
+ binaries?: ReadonlyMap<string, SkillBinaryPayload>;
120
161
  }): Promise<{
121
162
  id: string;
122
163
  }>;
@@ -125,6 +166,10 @@ interface SkillCandidateSink {
125
166
  interface SkillGenerationPolicy {
126
167
  /** 单次会话内的生成次数上限,默认 3 */
127
168
  maxPerSession?: number;
169
+ /** 单个二进制条目的字节上限(0.23.0 分册 20 FR-20.12) */
170
+ maxBinaryBytes?: number;
171
+ /** 一个技能内所有二进制条目的字节总量上限(0.23.0 分册 20 FR-20.12) */
172
+ maxTotalBinaryBytes?: number;
128
173
  }
129
174
  type SkillGenerationOutcome = {
130
175
  status: 'submitted';
@@ -151,6 +196,16 @@ interface SkillGeneratorOptions {
151
196
  * 这既让本册可分步落地,也给 AC-30.14 的反向对照留了现成的造法。
152
197
  */
153
198
  steps?: ToolStepReader;
199
+ /**
200
+ * 按 id 取本会话已上传附件的字节(0.23.0 分册 20 FR-20.2)。
201
+ *
202
+ * **按 id 查而不是按路径取**是安全边界:路径入参等于给模型一条把宿主磁盘上
203
+ * 任意文件复制进技能包的通路;按 id 在本会话附件表里查,能被指认的集合
204
+ * 恰好等于「用户自己这次会话上传的东西」。查不到(含跨会话的 id)返回 `undefined`。
205
+ *
206
+ * 不注入即本宿主不支持指认附件,模型给了 `attachmentId` 也按拒绝处理。
207
+ */
208
+ resolveAttachment?: (id: string) => Promise<SkillAttachmentBytes | undefined>;
154
209
  }
155
210
  /** 生成器面向用户的文案;缺省全部为英文模板 */
156
211
  interface SkillGenerationMessages {
@@ -263,13 +318,21 @@ interface DelegationOrchestratorOptions {
263
318
  policy?: Partial<DelegationBudget>;
264
319
  /** 接上清单后委派关系在 UI 可见(FR-11.5) */
265
320
  todos?: TodoStore;
321
+ /**
322
+ * 同时在跑的子 agent 数上限(0.23.0 分册 19 FR-19.5/19.16)。
323
+ *
324
+ * 每次委派入口都会重新调用它:用户在确认卡里选的并发数是会话中途才定下来的,
325
+ * 装配期读一次就固化的话,那个旋钮永远停在默认值上。
326
+ * 缺省 1,即维持 0.22.x 之前的串行行为——只是超额的请求改为排队而不再报错。
327
+ */
328
+ concurrencyLimit?: () => number;
266
329
  }
267
330
  /**
268
- * 串行委派编排器(设计 03 §13–§16)。
331
+ * 委派编排器(设计 03 §13–§16,并发改造见 0.23.0 分册 19)。
269
332
  *
270
- * 严格串行由**内部互斥**保证而不是调用方自觉:并发委派会产生并发待决交互,
271
- * 而当前交互模型是单一待决 nonce,届时表现为「点了没反应」。
272
- * 放开并发必须显式改这里的守卫,不会悄悄发生。
333
+ * 并发放开的前提是**并行的是执行、不是提问**:待决交互仍然一次只呈现一张,
334
+ * `ReactBridgeState` / `specInteractionChannel` 的队列保证。
335
+ * 若要在别处复用本编排器,那两处的排队语义是它的前置条件。
273
336
  *
274
337
  * 上下文隔离靠回值形状达成:只有 `summary` 回到父 agent,
275
338
  * 子 agent 的消息历史根本不经过本对象。
@@ -278,7 +341,7 @@ interface DelegationOrchestratorOptions {
278
341
  declare class DelegationOrchestrator {
279
342
  #private;
280
343
  constructor(options: DelegationOrchestratorOptions);
281
- /** 当前正在执行的委派任务;无则 undefined */
344
+ /** 正在执行的委派任务之一;全部空闲则 undefined。仅供诊断 */
282
345
  get running(): string | undefined;
283
346
  delegate(request: DelegationRequest): Promise<DelegationResult>;
284
347
  }
@@ -313,10 +376,10 @@ declare function withDelegationOrigin(bridge: UiBridge, origin: InteractionOrigi
313
376
  //#endregion
314
377
  //#region src/prompts/delegation.d.ts
315
378
  /**
316
- * 串行委派的策略提示词(设计 03 §13)。
379
+ * 委派的策略提示词(设计 03 §13;并发改造见 0.23.0 分册 19)。
317
380
  *
318
- * 「一次只能有一个」是编排器的硬约束,这里写进提示词是为了让模型不去
319
- * 尝试并行委派——被拒绝的调用会浪费一轮,而不是产生并发。
381
+ * 并发数那两句是**建议**而非约束:真正拦住数量的是编排器的排队与宿主硬上限。
382
+ * 写在这里是为了让模型按任务真实需要给值,而不是一口气派出一大批。
320
383
  */
321
384
  declare const DELEGATION_SYSTEM_PROMPT: string;
322
385
  //#endregion
@@ -444,8 +507,23 @@ interface PerceivedNode {
444
507
  * 它的其余子节点在前一段或后一段里。缺省不带该字段。
445
508
  */
446
509
  continued?: boolean;
510
+ /**
511
+ * 此处还能往哪些方向滚(0.23.0 分册 22 FR-22.1)。只在该元素**自身**是可滚容器、
512
+ * 且该方向尚未到头时出现;两端都到头字段就消失。
513
+ *
514
+ * 不表达滚动量:给了数值模型就会算「还要滚几次」,而列虚拟化下 `scrollWidth`
515
+ * 随列的重建而变,那个算法必然算错(沿用 0.18.0 FR-10.2)。
516
+ *
517
+ * **出现该字段的节点必然带 `ref`**——标了能滚却给不出句柄,模型就处在
518
+ * 「知道能滚、够不着」的状态,正是 AC-G8 要禁的那种幽灵能力。
519
+ */
520
+ scrollable?: readonly ScrollDirection[];
447
521
  children?: readonly PerceivedNode[];
448
522
  }
523
+ /** 滚动方向(0.23.0 分册 22)。感知的 `scrollable` 与动作记录的 `direction` 共用,避免两处漂移 */
524
+ type ScrollDirection = 'up' | 'down' | 'left' | 'right';
525
+ /** 四个方向的规范清单;工具层校验与文案生成都从这里取,不各写一份 */
526
+ declare const SCROLL_DIRECTIONS: readonly ScrollDirection[];
449
527
  /** 随感知一起下发的一张图像(FR-12.1) @experimental */
450
528
  interface PerceivedImage {
451
529
  /** 与 `PerceivedNode.imageId` 对应 */
@@ -1274,9 +1352,11 @@ interface PageActionRecord {
1274
1352
  * 本次滚动的方向与实际位移(0.18.0 FR-10.8);非 `scroll` 动作不带。
1275
1353
  * 位移要进留痕:只记「滚了」而不记「滚了多少」,事后分不出
1276
1354
  * 「滚到底了」与「根本没滚动」。
1355
+ *
1356
+ * 0.23.0 分册 22 起方向扩到四向:横向滚动记成 `down` 会让留痕说谎。
1277
1357
  */
1278
1358
  scrolled?: {
1279
- direction: 'down' | 'up';
1359
+ direction: ScrollDirection;
1280
1360
  movedBy: number;
1281
1361
  atEnd: boolean;
1282
1362
  };
@@ -1488,12 +1568,6 @@ interface PageActionToolSourceOptions {
1488
1568
  declare function createPageActionToolSource(options: PageActionToolSourceOptions): ExternalToolSource;
1489
1569
  //#endregion
1490
1570
  //#region src/prompts/pageAction.d.ts
1491
- /**
1492
- * 页面操作的系统提示词(需求 23)。
1493
- *
1494
- * 措辞刻意保守:提示词里的鼓励性表述会直接抬高模型尝试操作的频率,
1495
- * 而每一次尝试都要打断用户去点确认。
1496
- */
1497
1571
  declare const PAGE_ACTION_SYSTEM_PROMPT: string;
1498
1572
  //#endregion
1499
1573
  //#region src/tabs/policy.d.ts
@@ -2088,6 +2162,12 @@ interface TemplateSheetSkeleton {
2088
2162
  readonly cells: readonly TemplateCellSkeleton[];
2089
2163
  readonly merges: readonly string[];
2090
2164
  readonly columnWidths: readonly number[];
2165
+ /** 空着、等着被填的格,压成矩形区间如 `B6:B8`(0.24.0 FR-17.1 / FR-17.3) */
2166
+ readonly blanks?: readonly string[];
2167
+ /** 被合并区吞掉的格(不含左上角),写进去不会显示(FR-17.4) */
2168
+ readonly covered?: readonly string[];
2169
+ /** 表头行,1 基(FR-17.5)。启发式推导,只用于警示 */
2170
+ readonly headerRows?: readonly number[];
2091
2171
  }
2092
2172
  /** @experimental */
2093
2173
  interface XlsxTemplateSkeleton {
@@ -2152,10 +2232,49 @@ interface DocxTemplateFillSpec {
2152
2232
  column?: number;
2153
2233
  } & TemplateImageBytes)[];
2154
2234
  }
2235
+ /**
2236
+ * 一条被挡回的填写(0.24.0 分册 17 · 设计 18 §4.2)。
2237
+ *
2238
+ * 挡是对的,整批抛不对:模型一次写四十格、其中一格撞上公式,
2239
+ * 另外三十九格不该跟着消失。
2240
+ * @experimental
2241
+ */
2242
+ interface TemplateFillRejection {
2243
+ readonly sheet: string;
2244
+ readonly address: string;
2245
+ readonly code: 'TEMPLATE_CELL_IS_FORMULA' | 'TEMPLATE_CELL_IS_COVERED';
2246
+ /** 面向模型的英文说明,含「那应该写哪儿」 */
2247
+ readonly reason: string;
2248
+ }
2249
+ /** 放行了,但值得说一句(表头写入)。判据是推导的,所以不挡 @experimental */
2250
+ interface TemplateFillWarning {
2251
+ readonly sheet: string;
2252
+ readonly address: string;
2253
+ readonly reason: string;
2254
+ }
2255
+ /** @experimental */
2256
+ interface TemplateSheetBlanks {
2257
+ readonly sheet: string;
2258
+ readonly ranges: readonly string[];
2259
+ }
2260
+ /**
2261
+ * 填充回执(FR-17.8 ~ FR-17.12)。
2262
+ *
2263
+ * `filled` 是**真正写进文件**的条数,不是请求条数——后者看不出漏填。
2264
+ * @experimental
2265
+ */
2266
+ interface XlsxFillOutcome {
2267
+ readonly bytes: Uint8Array;
2268
+ readonly filled: number;
2269
+ readonly rejected: readonly TemplateFillRejection[];
2270
+ readonly warnings: readonly TemplateFillWarning[];
2271
+ /** 填完之后仍空着的待填区,只统计这次动过的工作表 */
2272
+ readonly stillBlank: readonly TemplateSheetBlanks[];
2273
+ }
2155
2274
  /** @experimental */
2156
2275
  interface XlsxTemplateEngine {
2157
2276
  read(bytes: Uint8Array): Promise<XlsxTemplateSkeleton>;
2158
- fill(bytes: Uint8Array, spec: XlsxTemplateFillSpec): Promise<Uint8Array>;
2277
+ fill(bytes: Uint8Array, spec: XlsxTemplateFillSpec): Promise<XlsxFillOutcome>;
2159
2278
  }
2160
2279
  /** @experimental */
2161
2280
  interface DocxTemplateEngine {
@@ -2666,4 +2785,4 @@ declare function dwgViewsOf(doc: DwgDocumentContent): readonly DwgView[];
2666
2785
  /** 按 id 取视图;取不到就退回第一个,而不是什么都没有 */
2667
2786
  declare function dwgPickView(doc: DwgDocumentContent, viewId: string | undefined): DwgView;
2668
2787
  //#endregion
2669
- export { DownloadedFileEntry as $, SkillGenerationToolSourceOptions as $n, createPageImageToolSource as $r, PERCEPTION_PAGING_DEFAULTS as $t, DataSourceRecord as A, PerceptionAuditSink as An, TodoListener as Ar, FILL_TEMPLATE_TOOL as At, DocumentFileSource as B, READ_DOCUMENT_TOOL as Bn, XlsxTemplateEngine as Br, LIST_PAGE_TABS_TOOL as Bt, DataSourceCandidateRecord as C, toActionFrameScopes as Ci, ParentBudget as Cn, TemplateParagraphSkeleton as Cr, DwgView as Ct, DataSourcePolicy as D, PdfTextQuality as Dn, TodoEvent as Dr, EMU_PER_TWIP as Dt, DataSourceKind as E, PdfPageImage as En, TemplateToolSourceOptions as Er, EMU_PER_POINT as Et, DelegationRequest as F, PerceptionScope as Fn, WorksetTab as Fr, GeneratedSkillDraft as Ft, DocumentToolSourceOptions as G, RemoteImageToolSourceOptions as Gn, clampWorksetMax as Gr, OpenedTabSignal as Gt, DocumentImageRole as H, RemoteImageFetch as Hn, XlsxTemplateSkeleton as Hr, MAX_DIGIT_WIDTH as Ht, DelegationResult as I, PerceptionScopeInput as In, WorksetTabView as Ir, HttpDataSourceOptions as It, DocxTemplateEngine as J, Size as Jn, createDocumentToolSource as Jr, PAGE_ACTION_TOOL as Jt, DocxDocumentContent as K, RenderedImage as Kn, columnWidthToPixels as Kr, PAGE_ACTION_KINDS as Kt, DelegationToolSourceOptions as L, PptxDocumentContent as Ln, XlsxDocumentContent as Lr, INSPECT_TEMPLATE_TOOL as Lt, DelegationBudget as M, PerceptionPagingBudget as Mn, TodoStore as Mr, FrameNote as Mt, DelegationOrchestrator as N, PerceptionRecord as Nn, TodoToolSourceOptions as Nr, FrameScope as Nt, DataSourcePolicyOptions as O, PerceivedImage as On, TodoItem as Or, EXPORT_SPREADSHEET_TOOL as Ot, DelegationOrchestratorOptions as P, PerceptionResult as Pn, VIEW_DWG_TOOL as Pr, GENERATE_SKILL_TOOL as Pt, DownloadedFileConsent as Q, SkillGenerationPolicy as Qn, createPageActionToolSource as Qr, PERCEIVE_PAGE_TOOL as Qt, DocumentBlock as R, PptxDocumentReader as Rn, XlsxDocumentReader as Rr, ImageCaptureBudget as Rt, DataSourceCandidatePolicyOptions as S, takesImage as Si, PagePerceptionToolSourceOptions as Sn, TemplateImageResolver as Sr, DwgUnits as St, DataSourceDef as T, withDelegationOrigin as Ti, PdfDocumentReader as Tn, TemplateTableCellSkeleton as Tr, EMU_PER_PIXEL as Tt, DocumentReadBudget as U, RemoteImageFetchFailure as Un, asReadMode as Ur, NestedFrameRef as Ut, DocumentFormat as V, READ_DOWNLOADED_FILE_TOOL as Vn, XlsxTemplateFillSpec as Vr, MANAGE_TODO_TOOL as Vt, DocumentReadMode as W, RemoteImageResult as Wn, clampDownloadWaitMs as Wr, OpenedPageInfo as Wt, DocxTemplateSkeleton as X, SkillGenerationMessages as Xn, createDwgToolSource as Xr, PDF_GARBLED_RATIO as Xt, DocxTemplateFillSpec as Y, SkillCandidateSink as Yn, createDownloadedFileToolSource as Yr, PAGE_DOCUMENT_REF as Yt, DownloadedFileAction as Z, SkillGenerationOutcome as Zn, createHttpDataSourceTransport as Zr, PDF_LARGE_IMAGE_RATIO as Zt, DWG_MODEL_VIEW_ID as _, parseCellAddress as _i, PageImageResult as _n, TabWorksetPort as _r, DwgOmission as _t, ActionTabWindow as a, createTemplateToolSource as ai, PageActionPolicy as an, SubAgentRunInput as ar, DownloadedFileRecord as at, DataSourceCandidateAuditSink as b, readImageSize as bi, PagePerceptionPolicyOptions as bn, TemplateFileSource as br, DwgProjection as bt, CellAddress as c, dwgPickView as ci, PageActionRequest as cn, TAB_WORKSET_DEFAULT_MAX as cr, DwgComponent as ct, DELEGATE_TASK_TOOL as d, formatCellAddress as di, PageActionTarget as dn, TAB_WORKSET_SYSTEM_PROMPT as dr, DwgEntity as dt, createPagePerceptionToolSource as ei, PERCEPTION_SYSTEM_PROMPT as en, SkillGenerator as er, DownloadedFileListing as et, DELEGATION_SYSTEM_PROMPT as f, frameLabel as fi, PageActionToolSourceOptions as fn, TEMPLATE_INSPECT_BUDGET as fr, DwgFill as ft, DOWNLOAD_WAIT_MIN_MS as g, measurePdfTextQuality as gi, PageImageFailure as gn, TabWorksetPolicyOptions as gr, DwgLoadedDrawing as gt, DOWNLOAD_WAIT_MAX_MS as h, isRangeTopLeft as hi, PageImageCapture as hn, TabWorksetPolicy as hr, DwgLayer as ht, ActionTabWatcher as i, createTabWorksetToolSource as ii, PageActionOutcome as in, SpreadsheetToolSourceOptions as ir, DownloadedFileReader as it, DataSourceTransport as j, PerceptionCaptureOptions as jn, TodoStatus as jr, FOCUS_PAGE_TAB_TOOL as jt, DataSourceProvenance as k, PerceivedNode as kn, TodoList as kr, FETCH_REMOTE_IMAGE_TOOL as kt, CellRange as l, dwgViewsOf as li, PageActionScope as ln, TAB_WORKSET_MAX_MAX as lr, DwgDocumentContent as lt, DOWNLOAD_WAIT_DEFAULT_MS as m, isPdfTextTrustworthy as mi, PageAuditSink as mn, TabAdmission as mr, DwgGeometry as mt, ActionDownloadWindow as n, createSkillGenerationToolSource as ni, PageActionExecutor as nn, SkillTraceEvidence as nr, DownloadedFilePolicyOptions as nt, CAPTURE_PAGE_IMAGE_TOOL as o, createTodoToolSource as oi, PageActionPolicyOptions as on, SubAgentRunner as or, DownloadedFileToolSourceOptions as ot, DOCUMENT_READ_BUDGET as p, frameSteps as pi, PageActionUi as pn, TODO_SYSTEM_PROMPT as pr, DwgFont as pt, DocxDocumentReader as q, SKILL_GENERATION_SYSTEM_PROMPT as qn, createDelegationToolSource as qr, PAGE_ACTION_SYSTEM_PROMPT as qt, ActionFrameScope as r, createSpreadsheetToolSource as ri, PageActionKind as rn, SkillTraceEvidenceStep as rr, DownloadedFileReadResult as rt, CLOSE_PAGE_TAB_TOOL as s, defersImage as si, PageActionRecord as sn, SubtreeRejection as sr, DwgBounds as st, ActionDownloadWatcher as t, createRemoteImageToolSource as ti, PageActionConsent as tn, SkillGeneratorOptions as tr, DownloadedFilePolicy as tt, ConsentUi as u, fitWithin as ui, PageActionScopeInput as un, TAB_WORKSET_MIN_MAX as ur, DwgDocumentReader as ut, DataSourceAuditSink as v, parseCellRange as vi, PageImageToolSourceOptions as vn, TabWorksetToolSourceOptions as vr, DwgPoint as vt, DataSourceCandidateStore as w, toFrameScopes as wi, PdfDocumentHandle as wn, TemplateSheetSkeleton as wr, DwgViewport as wt, DataSourceCandidatePolicy as x, sniffDocumentFormat as xi, PagePerceptionReader as xn, TemplateImageBytes as xr, DwgToolSourceOptions as xt, DataSourceCandidate as y, rangeContains as yi, PagePerceptionPolicy as yn, TemplateCellSkeleton as yr, DwgProjectedDrawing as yt, DocumentFileBytes as z, PptxSlideContent as zn, XlsxSheetContent as zr, LIST_DOWNLOADED_FILES_TOOL as zt };
2788
+ export { DownloadedFileEntry as $, SkillCandidateSink as $n, clampWorksetMax as $r, PERCEPTION_PAGING_DEFAULTS as $t, DataSourceRecord as A, takesImage as Ai, PerceptionAuditSink as An, TemplateSheetBlanks as Ar, FILL_TEMPLATE_TOOL as At, DocumentFileSource as B, READ_DOCUMENT_TOOL as Bn, TodoToolSourceOptions as Br, LIST_PAGE_TABS_TOOL as Bt, DataSourceCandidateRecord as C, isRangeTopLeft as Ci, ParentBudget as Cn, TemplateCellSkeleton as Cr, DwgView as Ct, DataSourcePolicy as D, rangeContains as Di, PdfTextQuality as Dn, TemplateImageBytes as Dr, EMU_PER_TWIP as Dt, DataSourceKind as E, parseCellRange as Ei, PdfPageImage as En, TemplateFillWarning as Er, EMU_PER_POINT as Et, DelegationRequest as F, PerceptionScope as Fn, TodoItem as Fr, GeneratedSkillDraft as Ft, DocumentToolSourceOptions as G, RemoteImageToolSourceOptions as Gn, XlsxDocumentReader as Gr, OpenedTabSignal as Gt, DocumentImageRole as H, RemoteImageFetch as Hn, WorksetTab as Hr, MAX_DIGIT_WIDTH as Ht, DelegationResult as I, PerceptionScopeInput as In, TodoList as Ir, HttpDataSourceOptions as It, DocxTemplateEngine as J, SKILL_GENERATION_SYSTEM_PROMPT as Jn, XlsxTemplateEngine as Jr, PAGE_ACTION_TOOL as Jt, DocxDocumentContent as K, RenderedImage as Kn, XlsxFillOutcome as Kr, PAGE_ACTION_KINDS as Kt, DelegationToolSourceOptions as L, PptxDocumentContent as Ln, TodoListener as Lr, INSPECT_TEMPLATE_TOOL as Lt, DelegationBudget as M, toFrameScopes as Mi, PerceptionPagingBudget as Mn, TemplateTableCellSkeleton as Mr, FrameNote as Mt, DelegationOrchestrator as N, withDelegationOrigin as Ni, PerceptionRecord as Nn, TemplateToolSourceOptions as Nr, FrameScope as Nt, DataSourcePolicyOptions as O, readImageSize as Oi, PerceivedImage as On, TemplateImageResolver as Or, EXPORT_SPREADSHEET_TOOL as Ot, DelegationOrchestratorOptions as P, PerceptionResult as Pn, TodoEvent as Pr, GENERATE_SKILL_TOOL as Pt, DownloadedFileConsent as Q, SkillBinaryPayload as Qn, clampDownloadWaitMs as Qr, PERCEIVE_PAGE_TOOL as Qt, DocumentBlock as R, PptxDocumentReader as Rn, TodoStatus as Rr, ImageCaptureBudget as Rt, DataSourceCandidatePolicyOptions as S, isPdfTextTrustworthy as Si, PagePerceptionToolSourceOptions as Sn, TabWorksetToolSourceOptions as Sr, DwgUnits as St, DataSourceDef as T, parseCellAddress as Ti, PdfDocumentReader as Tn, TemplateFillRejection as Tr, EMU_PER_PIXEL as Tt, DocumentReadBudget as U, RemoteImageFetchFailure as Un, WorksetTabView as Ur, NestedFrameRef as Ut, DocumentFormat as V, READ_DOWNLOADED_FILE_TOOL as Vn, VIEW_DWG_TOOL as Vr, MANAGE_TODO_TOOL as Vt, DocumentReadMode as W, RemoteImageResult as Wn, XlsxDocumentContent as Wr, OpenedPageInfo as Wt, DocxTemplateSkeleton as X, Size as Xn, XlsxTemplateSkeleton as Xr, PDF_GARBLED_RATIO as Xt, DocxTemplateFillSpec as Y, ScrollDirection as Yn, XlsxTemplateFillSpec as Yr, PAGE_DOCUMENT_REF as Yt, DownloadedFileAction as Z, SkillAttachmentBytes as Zn, asReadMode as Zr, PDF_LARGE_IMAGE_RATIO as Zt, DWG_MODEL_VIEW_ID as _, dwgViewsOf as _i, PageImageResult as _n, TODO_SYSTEM_PROMPT as _r, DwgOmission as _t, ActionTabWindow as a, createHttpDataSourceTransport as ai, PageActionPolicy as an, SkillGeneratorOptions as ar, DownloadedFileRecord as at, DataSourceCandidateAuditSink as b, frameLabel as bi, PagePerceptionPolicyOptions as bn, TabWorksetPolicyOptions as br, DwgProjection as bt, CellAddress as c, createPagePerceptionToolSource as ci, PageActionRequest as cn, SpreadsheetToolSourceOptions as cr, DwgComponent as ct, DELEGATE_TASK_TOOL as d, createSpreadsheetToolSource as di, PageActionTarget as dn, SubtreeRejection as dr, DwgEntity as dt, columnWidthToPixels as ei, PERCEPTION_SYSTEM_PROMPT as en, SkillGenerationMessages as er, DownloadedFileListing as et, DELEGATION_SYSTEM_PROMPT as f, createTabWorksetToolSource as fi, PageActionToolSourceOptions as fn, TAB_WORKSET_DEFAULT_MAX as fr, DwgFill as ft, DOWNLOAD_WAIT_MIN_MS as g, dwgPickView as gi, PageImageFailure as gn, TEMPLATE_INSPECT_BUDGET as gr, DwgLoadedDrawing as gt, DOWNLOAD_WAIT_MAX_MS as h, defersImage as hi, PageImageCapture as hn, TAB_WORKSET_SYSTEM_PROMPT as hr, DwgLayer as ht, ActionTabWatcher as i, createDwgToolSource as ii, PageActionOutcome as in, SkillGenerator as ir, DownloadedFileReader as it, DataSourceTransport as j, toActionFrameScopes as ji, PerceptionCaptureOptions as jn, TemplateSheetSkeleton as jr, FOCUS_PAGE_TAB_TOOL as jt, DataSourceProvenance as k, sniffDocumentFormat as ki, PerceivedNode as kn, TemplateParagraphSkeleton as kr, FETCH_REMOTE_IMAGE_TOOL as kt, CellRange as l, createRemoteImageToolSource as li, PageActionScope as ln, SubAgentRunInput as lr, DwgDocumentContent as lt, DOWNLOAD_WAIT_DEFAULT_MS as m, createTodoToolSource as mi, PageAuditSink as mn, TAB_WORKSET_MIN_MAX as mr, DwgGeometry as mt, ActionDownloadWindow as n, createDocumentToolSource as ni, PageActionExecutor as nn, SkillGenerationPolicy as nr, DownloadedFilePolicyOptions as nt, CAPTURE_PAGE_IMAGE_TOOL as o, createPageActionToolSource as oi, PageActionPolicyOptions as on, SkillTraceEvidence as or, DownloadedFileToolSourceOptions as ot, DOCUMENT_READ_BUDGET as p, createTemplateToolSource as pi, PageActionUi as pn, TAB_WORKSET_MAX_MAX as pr, DwgFont as pt, DocxDocumentReader as q, SCROLL_DIRECTIONS as qn, XlsxSheetContent as qr, PAGE_ACTION_SYSTEM_PROMPT as qt, ActionFrameScope as r, createDownloadedFileToolSource as ri, PageActionKind as rn, SkillGenerationToolSourceOptions as rr, DownloadedFileReadResult as rt, CLOSE_PAGE_TAB_TOOL as s, createPageImageToolSource as si, PageActionRecord as sn, SkillTraceEvidenceStep as sr, DwgBounds as st, ActionDownloadWatcher as t, createDelegationToolSource as ti, PageActionConsent as tn, SkillGenerationOutcome as tr, DownloadedFilePolicy as tt, ConsentUi as u, createSkillGenerationToolSource as ui, PageActionScopeInput as un, SubAgentRunner as ur, DwgDocumentReader as ut, DataSourceAuditSink as v, fitWithin as vi, PageImageToolSourceOptions as vn, TabAdmission as vr, DwgPoint as vt, DataSourceCandidateStore as w, measurePdfTextQuality as wi, PdfDocumentHandle as wn, TemplateFileSource as wr, DwgViewport as wt, DataSourceCandidatePolicy as x, frameSteps as xi, PagePerceptionReader as xn, TabWorksetPort as xr, DwgToolSourceOptions as xt, DataSourceCandidate as y, formatCellAddress as yi, PagePerceptionPolicy as yn, TabWorksetPolicy as yr, DwgProjectedDrawing as yt, DocumentFileBytes as z, PptxSlideContent as zn, TodoStore as zr, LIST_DOWNLOADED_FILES_TOOL as zt };
@@ -1,4 +1,4 @@
1
- import { Ft as ValidationReport, H as DiscoveryResult, K as FileSystemProvider, Nt as UiSpecNode, O as UiSurfaceActionRequest, Rt as WebSkillErrorCode, S as UiBridge, St as SkillManifest, T as UiSpecEvent, X as JsonSchema, _ as LlmToolSpec, _t as SkillDocument, b as RenderResultRequest, d as LlmContentPart, et as Page, f as LlmMessage, g as LlmToolCall, gt as SkillDiscovery, h as LlmTokenUsage, ht as SkillCatalogEntry, i as FormField, l as LlmClient, m as LlmStreamEvent, mt as SkillCatalog, n as ArtifactStore, nt as RemoteUrlPolicy, o as InteractionPolicy, p as LlmResponse, r as ChartSpec, s as InteractionRequest, t as Artifact, tt as PageQuery, u as LlmCompleteInput, v as MemoryStore, vt as SkillInstallSource, w as UiSpecDrafts, y as RenderBlock } from "./types-CpDRZ0rA-BM5FI9oN.js";
1
+ import { Ft as ValidationReport, H as DiscoveryResult, K as FileSystemProvider, Nt as UiSpecNode, O as UiSurfaceActionRequest, Rt as WebSkillErrorCode, S as UiBridge, St as SkillManifest, T as UiSpecEvent, X as JsonSchema, _ as LlmToolSpec, _t as SkillDocument, b as RenderResultRequest, d as LlmContentPart, et as Page, f as LlmMessage, g as LlmToolCall, gt as SkillDiscovery, h as LlmTokenUsage, ht as SkillCatalogEntry, i as FormField, l as LlmClient, m as LlmStreamEvent, mt as SkillCatalog, n as ArtifactStore, nt as RemoteUrlPolicy, o as InteractionPolicy, p as LlmResponse, r as ChartSpec, s as InteractionRequest, t as Artifact, tt as PageQuery, u as LlmCompleteInput, v as MemoryStore, vt as SkillInstallSource, w as UiSpecDrafts, y as RenderBlock } from "./types-CpDRZ0rA-CFQ-vdKz.js";
2
2
  //#region ../runtime/dist/index.d.ts
3
3
  //#region src/llm/parts.d.ts
4
4
  /** 纯文本消息内容的构造快捷方式(引擎内部绝大多数消息仍是纯文本) */
@@ -1409,8 +1409,11 @@ declare class FsArtifactStore implements ArtifactStore {
1409
1409
  /**
1410
1410
  * 把表格规格编码为 xlsx 字节。
1411
1411
  *
1412
- * 纯函数——不认识产物、run 与工具,因此工具、脚本能力、测试三个消费面共用同一份
1413
- * 实现,AC-10.8「双消费面逐字节相同」是结构性成立的。
1412
+ * 纯函数——不认识产物、run 与工具,因此工具、脚本能力、测试三个消费面共用同一份实现。
1413
+ *
1414
+ * 「纯函数」只保证三个消费面走的是同一条代码路径,**不足以**保证输出逐字节相同:
1415
+ * 归档格式本身会把编码时刻写进字节。AC-10.8「双消费面逐字节相同」靠的是
1416
+ * `withFixedTimestamps()` 把那个时刻拿掉(0.23.0 分册 24)。
1414
1417
  *
1415
1418
  * `resolveImage` 是图片引用的解析出口(0.22.0 分册 20 FR-20.3)。它同样不破坏纯函数性:
1416
1419
  * 给定相同的规格与相同的解析结果,输出逐字节相同。规格里有图片却没给它,是