@webskill/sdk 0.7.0 → 0.8.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 (35) hide show
  1. package/dist/agent.d.ts +1 -1
  2. package/dist/agent.js +1 -1
  3. package/dist/browser.d.ts +151 -4
  4. package/dist/browser.js +250 -25
  5. package/dist/{catalogComponents-Dr5dFMAb-DKH_7VPI.js → catalogComponents-DfxxfUvn-D55Gbb2l.js} +3435 -437
  6. package/dist/{dist-8oQRa8Xz.js → dist-59XlqDuv.js} +93 -6
  7. package/dist/{dist-DnYG2-eY.js → dist-CJqQsIm9.js} +498 -118
  8. package/dist/{dist-D0qW6e40.js → dist-DmI5SBBF.js} +192 -17
  9. package/dist/{eventTypes-DjIQpt8Y-Bj3vghj4.js → eventTypes-g1BXL6x5-CibcOftR.js} +7 -2
  10. package/dist/governance.d.ts +16 -3
  11. package/dist/governance.js +24 -5
  12. package/dist/{index-DkbABR43.d.ts → index-K-eewlGL.d.ts} +138 -75
  13. package/dist/{index-BwsK9lGk.d.ts → index-P9J2LTfU.d.ts} +163 -6
  14. package/dist/{index-Ba3xFtfz.d.ts → index-fLskQfAS.d.ts} +2 -2
  15. package/dist/index.d.ts +3 -3
  16. package/dist/index.js +4 -4
  17. package/dist/mcp.d.ts +8 -2
  18. package/dist/mcp.js +12 -2
  19. package/dist/{memoryArtifactStore-52Zn9npI-BMPYwvoy.js → memoryArtifactStore-52Zn9npI-upv5OWYf.js} +1 -1
  20. package/dist/node.d.ts +3 -3
  21. package/dist/node.js +3 -3
  22. package/dist/{openUiLibrary-Bdrji9qK-D2LxmM-a.js → openUiLibrary-DURlAxjk-CU6AzfSW.js} +3 -3
  23. package/dist/{skillVersionStore-Bl-ElD45-CWPvGvoq.d.ts → skillVersionStore-Bl-ElD45-gRfSaAby.d.ts} +1 -1
  24. package/dist/{testing-CYTFqkDm.js → testing-BCUO5gZR.js} +2 -2
  25. package/dist/testing.d.ts +1 -1
  26. package/dist/testing.js +2 -2
  27. package/dist/{types-CcxRLdJG-DCXyw1US.d.ts → types-B3n0cMZu-BdcqQ35O.d.ts} +46 -6
  28. package/dist/ui-react.d.ts +13 -6
  29. package/dist/ui-react.js +153 -84
  30. package/dist/ui-vue.d.ts +1 -1
  31. package/dist/ui-vue.js +2 -2
  32. package/dist/ui.d.ts +4 -4
  33. package/dist/ui.js +3 -3
  34. package/dist/{webskillLitCatalog-_mugzRHx-B_54vxum.js → webskillLitCatalog-DwTwSBFt-DiXXpNZA.js} +22 -3
  35. package/package.json +2 -2
@@ -1,7 +1,69 @@
1
- import { A as parseSkillMarkdown, L as resolveInsideRoot, O as messageOf, P as renderAvailableSkillsXml, V as validateSkills, f as SkillDiscovery, g as assertSafePathSegment, m as WebSkillError, p as SkillReader, v as buildCatalog } from "./dist-8oQRa8Xz.js";
2
- import { a as textParts, i as rejectUnsupportedPart, n as partsToText, o as validateLlmMessages, r as promptText, t as MemoryArtifactStore } from "./memoryArtifactStore-52Zn9npI-BMPYwvoy.js";
1
+ import { A as messageOf, I as renderAvailableSkillsXml, M as parseSkillMarkdown, W as validateSkills, f as SkillDiscovery, g as assertSafePathSegment, m as WebSkillError, p as SkillReader, v as buildCatalog, z as resolveInsideRoot } from "./dist-59XlqDuv.js";
2
+ import { a as textParts, i as rejectUnsupportedPart, n as partsToText, o as validateLlmMessages, r as promptText, t as MemoryArtifactStore } from "./memoryArtifactStore-52Zn9npI-upv5OWYf.js";
3
3
 
4
4
  //#region ../runtime/dist/index.js
5
+ /** 与正常工具结果同构:模型读到的是「这次调用被中断了」,而不是一个凭空消失的调用 */
6
+ function interruptedToolResult(call, options = {}) {
7
+ const code = options.code ?? "RUN_INTERRUPTED";
8
+ const because = options.reason === void 0 ? "" : ` (${options.reason})`;
9
+ return {
10
+ ok: false,
11
+ content: [],
12
+ error: {
13
+ code,
14
+ message: `Tool call "${call.name}" produced no result: the run ended before it finished${because}.`
15
+ }
16
+ };
17
+ }
18
+ /** 尚无 `role:'tool'` 应答的工具调用,按消息顺序 */
19
+ function findUnpairedToolCalls(messages) {
20
+ const answered = new Set(messages.filter((m) => m.role === "tool").map((m) => m.toolCallId));
21
+ return messages.filter((m) => m.role === "assistant" && m.toolCalls?.length).flatMap((m) => m.toolCalls ?? []).filter((call) => !answered.has(call.id));
22
+ }
23
+ /**
24
+ * 为每个未应答的工具调用补一条结构化的中断说明。
25
+ *
26
+ * 补齐消息紧跟在该 assistant 已有的 tool 兄弟之后——供应商装配按相邻块分组,
27
+ * 插到序列末尾会让它归属到别的 assistant 消息上。
28
+ * 本函数**不改写入参**,也不写盘(AC-11.8)。
29
+ */
30
+ function sealToolCallPairs(messages, options = {}) {
31
+ const answered = new Set(messages.filter((m) => m.role === "tool").map((m) => m.toolCallId));
32
+ const code = options.code ?? "RUN_INTERRUPTED";
33
+ const sealed = [];
34
+ const out = [];
35
+ for (let i = 0; i < messages.length; i += 1) {
36
+ const message = messages[i];
37
+ out.push(message);
38
+ if (message.role !== "assistant" || !message.toolCalls?.length) continue;
39
+ const missing = message.toolCalls.filter((call) => !answered.has(call.id));
40
+ if (missing.length === 0) continue;
41
+ while (i + 1 < messages.length && messages[i + 1].role === "tool") {
42
+ out.push(messages[i + 1]);
43
+ i += 1;
44
+ }
45
+ for (const call of missing) {
46
+ out.push({
47
+ role: "tool",
48
+ toolCallId: call.id,
49
+ content: textParts(JSON.stringify(interruptedToolResult(call, {
50
+ ...options,
51
+ code
52
+ })))
53
+ });
54
+ answered.add(call.id);
55
+ sealed.push({
56
+ callId: call.id,
57
+ toolName: call.name,
58
+ code
59
+ });
60
+ }
61
+ }
62
+ return {
63
+ messages: sealed.length === 0 ? [...messages] : out,
64
+ sealed
65
+ };
66
+ }
5
67
  /**
6
68
  * $defs 必须与 type / properties 同级,位于每个工具 inputSchema 的根。
7
69
  * 已验证:放进 properties.spec 内层会得到同样的 "Unsupported ref: #" ——
@@ -1617,7 +1679,9 @@ function schemaToForm(schema, providedArgs) {
1617
1679
  function mapFieldType(prop) {
1618
1680
  if (Array.isArray(prop.enum)) return "select";
1619
1681
  switch (prop.type) {
1620
- case "string": return prop["format"] === "binary" || prop["contentEncoding"] === "base64" ? "file" : "text";
1682
+ case "string":
1683
+ if (prop["format"] === "binary" || prop["contentEncoding"] === "base64") return "file";
1684
+ return prop["format"] === "password" || prop["writeOnly"] === true ? "password" : "text";
1621
1685
  case "number":
1622
1686
  case "integer": return "number";
1623
1687
  case "boolean": return "boolean";
@@ -1965,7 +2029,7 @@ const DEFAULT_LOOP_LIMITS = {
1965
2029
  totalTimeoutMs: 12e4,
1966
2030
  toolTimeoutMs: 3e4
1967
2031
  };
1968
- const RUN_SNAPSHOT_SCHEMA_VERSION = 2;
2032
+ const RUN_SNAPSHOT_SCHEMA_VERSION = 3;
1969
2033
  /** @experimental */
1970
2034
  function isUnsupportedRunSnapshot(entry) {
1971
2035
  return entry.unsupported === true;
@@ -2010,7 +2074,7 @@ var FsRunSnapshotStore = class {
2010
2074
  throw new WebSkillError("RUN_SNAPSHOT_INCOMPATIBLE", `Snapshot for run "${runId}" has an unexpected shape and was deleted`);
2011
2075
  }
2012
2076
  const schemaVersion = typeof snapshot.schemaVersion === "number" ? snapshot.schemaVersion : 0;
2013
- if (schemaVersion !== 2) throw new WebSkillError("RUN_SNAPSHOT_SCHEMA_UNSUPPORTED", `Snapshot for run "${runId}" uses schema version ${schemaVersion}; this runtime reads version 2. The file was kept for read-only inspection.`);
2077
+ if (schemaVersion !== 3) throw new WebSkillError("RUN_SNAPSHOT_SCHEMA_UNSUPPORTED", `Snapshot for run "${runId}" uses schema version ${schemaVersion}; this runtime reads version 3. The file was kept for read-only inspection.`);
2014
2078
  if (snapshot.runId !== runId) {
2015
2079
  await this.#fs.remove(path).catch(() => void 0);
2016
2080
  throw new WebSkillError("RUN_SNAPSHOT_INCOMPATIBLE", `Snapshot for run "${runId}" has an unexpected shape and was deleted`);
@@ -2030,7 +2094,7 @@ var FsRunSnapshotStore = class {
2030
2094
  try {
2031
2095
  const parsed = JSON.parse(await this.#fs.readText(entry.path));
2032
2096
  const schemaVersion = typeof parsed.schemaVersion === "number" ? parsed.schemaVersion : 0;
2033
- if (schemaVersion === 2) {
2097
+ if (schemaVersion === 3) {
2034
2098
  out.push(parsed);
2035
2099
  continue;
2036
2100
  }
@@ -2143,6 +2207,21 @@ const redactFileValue = (value) => {
2143
2207
  return rest;
2144
2208
  };
2145
2209
  /**
2210
+ * 密码字段名集合(FR-23.7)。
2211
+ *
2212
+ * 既有的三处脱敏各有各的判别口径(看 request.type、看值是否标量、看值里有没有 data/mimeType),
2213
+ * 没有一处按**字段类型**判。行为记录那处尤其危险:它的安全假设是「标量是安全的」,
2214
+ * 而密码恰好是字符串标量——假设失效了。
2215
+ */
2216
+ const passwordFieldNames = (request) => new Set(request.type === "form" ? request.fields.filter((f) => f.type === "password").map((f) => f.name) : []);
2217
+ /** 去掉密码字段的值;不是掩码而是**不存**,掩码存下来仍然泄露长度与存在性 */
2218
+ const withoutPasswords = (value, passwords) => {
2219
+ if (passwords.size === 0 || typeof value !== "object" || value === null || Array.isArray(value)) return value;
2220
+ const out = {};
2221
+ for (const [key, entry] of Object.entries(value)) if (!passwords.has(key)) out[key] = entry;
2222
+ return out;
2223
+ };
2224
+ /**
2146
2225
  * 触顶失败的结构化细节(FR-21.2)。由终止原因推出上限字段,而不是在每个终止点各写一遍——
2147
2226
  * 终止点有四个,写四遍就迟早有一处对不上。
2148
2227
  */
@@ -2156,6 +2235,16 @@ const limitDetails = (state, reason) => {
2156
2235
  value: state.maxTurns
2157
2236
  };
2158
2237
  };
2238
+ /** 补齐消息里带的错误码:能说清「为什么没结果」的,就不要退化成 RUN_INTERRUPTED(设计 11 §2.5) */
2239
+ const sealCodeFor = (reason, errorCode) => {
2240
+ switch (reason) {
2241
+ case "interaction-timeout": return "RUN_INTERACTION_TIMEOUT";
2242
+ case "user-cancelled": return "RUN_CANCELLED";
2243
+ case "timeout": return "RUN_TIMEOUT";
2244
+ case "tool-resolution-exhausted": return "TOOL_RESOLUTION_EXHAUSTED";
2245
+ default: return errorCode ?? "RUN_INTERRUPTED";
2246
+ }
2247
+ };
2159
2248
  /**
2160
2249
  * 多轮 Agent 循环。
2161
2250
  * 工具失败一律转为 ToolResult{ok:false} 回喂 LLM 继续循环;
@@ -2487,6 +2576,7 @@ var AgentLoop = class {
2487
2576
  } catch (e) {
2488
2577
  trace.record("run.warning", { message: `Terminal lifecycle hook failed: ${messageOf(e)}` });
2489
2578
  }
2579
+ await this.#sealToolCalls(state, reason, errorCode);
2490
2580
  run.trace = trace.list();
2491
2581
  return {
2492
2582
  output,
@@ -2494,12 +2584,45 @@ var AgentLoop = class {
2494
2584
  messages: state.messages.map((m) => ({ ...m }))
2495
2585
  };
2496
2586
  }
2587
+ /**
2588
+ * S1 出口守卫(FR-11.1):中断留下的未应答工具调用在这里补齐。
2589
+ *
2590
+ * 放在 `#finish` 而不是四个早退点:它是唯一的汇流出口,写四遍就迟早漏一处。
2591
+ * 补齐产物只进 `LlmMessage[]`(下一轮请求装配用),不进 chatbot 的消息流(AC-11.2)。
2592
+ */
2593
+ async #sealToolCalls(state, reason, errorCode) {
2594
+ const pending = findUnpairedToolCalls(state.messages);
2595
+ if (pending.length === 0) return;
2596
+ const code = sealCodeFor(reason, errorCode);
2597
+ for (const call of pending) {
2598
+ const result = interruptedToolResult(call, {
2599
+ code,
2600
+ reason
2601
+ });
2602
+ state.messages.push({
2603
+ role: "tool",
2604
+ toolCallId: call.id,
2605
+ content: await this.#toolResultParts(call, result, state)
2606
+ });
2607
+ state.trace.record("run.warning", {
2608
+ message: `Sealed unanswered tool call "${call.name}": the run ended before it produced a result.`,
2609
+ data: {
2610
+ kind: "tool-call-sealed",
2611
+ callId: call.id,
2612
+ toolName: call.name,
2613
+ side: "write",
2614
+ reason,
2615
+ code
2616
+ }
2617
+ });
2618
+ }
2619
+ }
2497
2620
  /** D3 快照写入(含 pendingInteraction 与过期时间;写失败降级 run.warning) */
2498
2621
  async #saveSnapshot(state, pending) {
2499
2622
  const store = this.#deps.snapshotStore;
2500
2623
  if (!store) return;
2501
2624
  const snapshot = {
2502
- schemaVersion: 2,
2625
+ schemaVersion: 3,
2503
2626
  runId: state.runId,
2504
2627
  sessionId: state.run.sessionId,
2505
2628
  userPrompt: state.run.userPrompt,
@@ -2674,6 +2797,15 @@ var AgentLoop = class {
2674
2797
  throw e;
2675
2798
  }
2676
2799
  }
2800
+ /**
2801
+ * 工具的技能归属。内置工具与外部工具没有归属,返回 `undefined`——
2802
+ * 拿 `activated[0]` 顶替会把内置工具的失败栽给一个无关技能,比不归因更糟(设计 26 §2.3)。
2803
+ */
2804
+ #skillOf(call, state) {
2805
+ if (call.name === "read_skill_file" || call.name === "ask_user") return void 0;
2806
+ const resolution = resolveToolName(call.name, state.activated, state.activatedTools.keys());
2807
+ return resolution.kind === "script" ? resolution.skillName : void 0;
2808
+ }
2677
2809
  /** 最后一条 assistant 消息里第一个尚无 tool 响应的工具调用(即中断时正在处理的那个) */
2678
2810
  #findPendingToolCall(messages) {
2679
2811
  const lastAssistant = [...messages].reverse().find((m) => m.role === "assistant" && m.toolCalls?.length);
@@ -2864,11 +2996,14 @@ var AgentLoop = class {
2864
2996
  }
2865
2997
  async #executeCall(call, state) {
2866
2998
  const argsSummary = summarizeArgs(call.arguments);
2999
+ const owner = this.#skillOf(call, state);
3000
+ const attribution = owner === void 0 ? {} : { skillName: owner };
2867
3001
  const callStartMs = Date.parse(state.now());
2868
3002
  state.trace.record("tool.started", { data: {
2869
3003
  name: call.name,
2870
3004
  callId: call.id,
2871
- args: argsSummary
3005
+ args: argsSummary,
3006
+ ...attribution
2872
3007
  } });
2873
3008
  this.#emitTool(state, "started", call);
2874
3009
  let result;
@@ -2894,7 +3029,8 @@ var AgentLoop = class {
2894
3029
  name: call.name,
2895
3030
  callId: call.id,
2896
3031
  args: argsSummary,
2897
- durationMs
3032
+ durationMs,
3033
+ ...attribution
2898
3034
  } });
2899
3035
  this.#emitTool(state, "completed", call);
2900
3036
  for (const item of result.content) {
@@ -2928,7 +3064,8 @@ var AgentLoop = class {
2928
3064
  callId: call.id,
2929
3065
  code: result.error?.code,
2930
3066
  args: argsSummary,
2931
- durationMs
3067
+ durationMs,
3068
+ ...attribution
2932
3069
  }
2933
3070
  });
2934
3071
  this.#emitTool(state, "failed", call, result.error?.code);
@@ -3095,10 +3232,17 @@ var AgentLoop = class {
3095
3232
  async #replaySurfaceEvents(state) {
3096
3233
  const bridge = this.#deps.uiBridge;
3097
3234
  if (!bridge?.renderSurface || state.surfaceEvents.length === 0) return;
3098
- try {
3099
- for (const event of state.surfaceEvents) await bridge.renderSurface(structuredClone(event));
3235
+ for (const event of state.surfaceEvents) try {
3236
+ await bridge.renderSurface(structuredClone(event));
3100
3237
  } catch (e) {
3101
- state.trace.record("run.warning", { message: `Failed to replay UI surfaces: ${messageOf(e)}` });
3238
+ state.trace.record("ui.degraded", {
3239
+ message: `Failed to replay UI surface "${event.id}": ${messageOf(e)}`,
3240
+ data: {
3241
+ kind: "replay-failed",
3242
+ surfaceId: event.id,
3243
+ eventType: event.type
3244
+ }
3245
+ });
3102
3246
  }
3103
3247
  }
3104
3248
  /**
@@ -3662,7 +3806,8 @@ var AgentLoop = class {
3662
3806
  if (!this.#deps.memory) return;
3663
3807
  const scope = `session:${state.run.sessionId}`;
3664
3808
  const limit = this.#config.paramHistoryLimit;
3665
- const recorded = request.type === "file-pick" ? redactFileValue(value) : value;
3809
+ const passwords = passwordFieldNames(request);
3810
+ const recorded = request.type === "file-pick" ? redactFileValue(value) : withoutPasswords(value, passwords);
3666
3811
  await this.#memoryMutate(scope, "paramHistory", state, (current) => {
3667
3812
  const history = current ?? [];
3668
3813
  history.push({
@@ -3729,6 +3874,7 @@ var AgentLoop = class {
3729
3874
  else if (request.type === "form" && typeof value === "object" && value !== null) {
3730
3875
  const submitted = value;
3731
3876
  for (const field of request.fields) {
3877
+ if (field.type === "password") continue;
3732
3878
  const next = submitted[field.name];
3733
3879
  if (typeof next !== "string" && typeof next !== "number" && typeof next !== "boolean") continue;
3734
3880
  if (next === "") continue;
@@ -3882,6 +4028,7 @@ var WebSkillRuntime = class {
3882
4028
  if (!this.#catalogCache) await this.discover();
3883
4029
  const cache = this.#catalogCache;
3884
4030
  if (!cache) throw new Error("discover() did not populate the catalog cache");
4031
+ const sealedHistory = options.history ? sealToolCallPairs(options.history) : void 0;
3885
4032
  const providerFailures = [];
3886
4033
  const providerEntries = (await Promise.all((this.#deps.skillProviders ?? []).map(async (p) => {
3887
4034
  try {
@@ -3928,11 +4075,25 @@ var WebSkillRuntime = class {
3928
4075
  userPrompt,
3929
4076
  route,
3930
4077
  runId,
3931
- ...options.history ? { history: options.history } : {}
4078
+ ...sealedHistory ? { history: sealedHistory.messages } : {}
3932
4079
  });
3933
4080
  } finally {
3934
4081
  this.#loops.delete(runId);
3935
4082
  }
4083
+ for (const record of sealedHistory?.sealed ?? []) result.run.trace.push({
4084
+ id: `evt-seal-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
4085
+ runId: result.run.id,
4086
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
4087
+ type: "run.warning",
4088
+ message: `Sealed unanswered tool call "${record.toolName}" carried over from an earlier interrupted run.`,
4089
+ data: {
4090
+ kind: "tool-call-sealed",
4091
+ callId: record.callId,
4092
+ toolName: record.toolName,
4093
+ side: "read",
4094
+ code: record.code
4095
+ }
4096
+ });
3936
4097
  for (const failure of providerFailures) result.run.trace.push({
3937
4098
  id: `evt-provider-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
3938
4099
  runId: result.run.id,
@@ -4428,7 +4589,6 @@ function parseUserProfileExport(raw) {
4428
4589
  entries
4429
4590
  };
4430
4591
  }
4431
- /** 导入前给用户看的差异(FR-19.7):新增哪些、覆盖哪些 @experimental */
4432
4592
  function diffUserProfile(current, incoming) {
4433
4593
  const byId = new Map(current.entries.map((entry) => [entry.id, entry]));
4434
4594
  const added = [];
@@ -4990,6 +5150,7 @@ const toMeta = (record) => ({
4990
5150
  ...record.title !== void 0 ? { title: record.title } : {},
4991
5151
  ...record.titleLocked === true ? { titleLocked: true } : {},
4992
5152
  ...record.archived === true ? { archived: true } : {},
5153
+ ...record.modelId !== void 0 ? { modelId: record.modelId } : {},
4993
5154
  messageCount: record.messages.length
4994
5155
  });
4995
5156
  const newSessionId = () => `session-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
@@ -5036,6 +5197,7 @@ function parseSessionFile(raw, path) {
5036
5197
  ...typeof file.title === "string" ? { title: file.title } : {},
5037
5198
  ...file.titleLocked === true ? { titleLocked: true } : {},
5038
5199
  ...file.archived === true ? { archived: true } : {},
5200
+ ...typeof file.modelId === "string" ? { modelId: file.modelId } : {},
5039
5201
  messages: Array.isArray(file.messages) ? file.messages : [],
5040
5202
  messageCount: Array.isArray(file.messages) ? file.messages.length : 0
5041
5203
  };
@@ -5077,6 +5239,7 @@ var FsSessionStore = class {
5077
5239
  ...record.title !== void 0 ? { title: record.title } : {},
5078
5240
  ...record.titleLocked === true ? { titleLocked: true } : {},
5079
5241
  ...record.archived === true ? { archived: true } : {},
5242
+ ...record.modelId !== void 0 ? { modelId: record.modelId } : {},
5080
5243
  messages: record.messages
5081
5244
  };
5082
5245
  await this.#fs.writeText(this.#path(record.id), JSON.stringify(file, null, 2));
@@ -5170,6 +5333,18 @@ var FsSessionStore = class {
5170
5333
  await this.#write(record);
5171
5334
  });
5172
5335
  }
5336
+ async setModel(id, modelId) {
5337
+ await this.#serialize(id, async () => {
5338
+ const record = await this.#require(id);
5339
+ if (modelId === void 0) delete record.modelId;
5340
+ else record.modelId = modelId;
5341
+ await this.#write(record);
5342
+ });
5343
+ }
5344
+ async getMeta(id) {
5345
+ const record = await this.get(id);
5346
+ return record === void 0 ? void 0 : toMeta(record);
5347
+ }
5173
5348
  async delete(id) {
5174
5349
  await this.#serialize(id, async () => {
5175
5350
  const path = this.#path(id);
@@ -5179,4 +5354,4 @@ var FsSessionStore = class {
5179
5354
  };
5180
5355
 
5181
5356
  //#endregion
5182
- export { isNetworkAllowed as $, SerializingMemoryStore as A, bridgeError as B, ProgressiveRouter as C, toRecordDigests as Ct, RUN_SNAPSHOT_SCHEMA_VERSION as D, READ_SKILL_FILE_TOOL_NAME as E, validateUiSpecNode as Et, USER_PROFILE_PROMPT_HEADER as F, exportUserProfile as G, createScriptContext as H, USER_PROFILE_REFINE_PROMPT as I, extractTodoTraceEvents as J, extractChartSpec as K, WebSkillRuntime as L, USER_PROFILE_EXPORT_VERSION as M, USER_PROFILE_KEY as N, RUN_TRACE_SCHEMA_VERSION as O, USER_PROFILE_NO_INVENTION_RULE as P, fromVercelStreamPart as Q, appendBehaviorRecords as R, OpenAiCompatibleClient as S, toLlmToolSpec as St, READ_SKILL_FILE_TOOL as T, validateUiSpecEvent as Tt, createWebSkillApi as U, buildRenderResult as V, diffUserProfile as W, formatSkillScriptManifest as X, extractUiSpecEvents as Y, fromVercelResult as Z, FsRunTraceStore as _, sampleBehaviorRecords as _t, AgentLoop as a, networkUrlHost as at, GoogleGenAiClient as b, scriptToolName as bt, CapabilityApproval as c, normalizeToolError as ct, EMPTY_USER_PROFILE as d, readBehaviorRecords as dt, isUnsupportedRunSnapshot as et, EventBus as f, readProfileEntries as ft, FsRunSnapshotStore as g, resolveToolName as gt, FsMemoryStore as h, renderUserProfileContext as ht, ASK_USER_TOOL_NAME as i, networkPolicyLibSource as it, TraceRecorder as j, SESSION_SCHEMA_VERSION as k, DEFAULT_LOOP_LIMITS as l, parseBridgeRequest as lt, FsArtifactStore as m, refineUserProfile as mt, ASK_USER_INPUT_SCHEMA as n, mergeCatalogEntries as nt, AnthropicClient as o, normalizeErrorCode as ot, FS_SESSION_PAGE_SIZE as p, readUserProfile as pt, extractSkillCandidate as q, ASK_USER_TOOL as r, mergeProfileEntries as rt, BEHAVIOR_RECORDS_KEY as s, normalizeToolContent as st, ALLOWED_TOOLS_EXCLUSION_REASON as t, listSkillScripts as tt, DEFAULT_USER_PROFILE_LIMITS as u, parseUserProfileExport as ut, FsSessionStore as v, schemaSourceLabel as vt, READ_SKILL_FILE_INPUT_SCHEMA as w, toVercelToolSpecs as wt, HookRunner as x, summarizeToolCalls as xt, FullDisclosureRouter as y, schemaToForm as yt, applyUserProfileImport as z };
5357
+ export { fromVercelStreamPart as $, SerializingMemoryStore as A, bridgeError as B, ProgressiveRouter as C, sealToolCallPairs as Ct, RUN_SNAPSHOT_SCHEMA_VERSION as D, toVercelToolSpecs as Dt, READ_SKILL_FILE_TOOL_NAME as E, toRecordDigests as Et, USER_PROFILE_PROMPT_HEADER as F, exportUserProfile as G, createScriptContext as H, USER_PROFILE_REFINE_PROMPT as I, extractTodoTraceEvents as J, extractChartSpec as K, WebSkillRuntime as L, USER_PROFILE_EXPORT_VERSION as M, USER_PROFILE_KEY as N, RUN_TRACE_SCHEMA_VERSION as O, validateUiSpecEvent as Ot, USER_PROFILE_NO_INVENTION_RULE as P, fromVercelResult as Q, appendBehaviorRecords as R, OpenAiCompatibleClient as S, scriptToolName as St, READ_SKILL_FILE_TOOL as T, toLlmToolSpec as Tt, createWebSkillApi as U, buildRenderResult as V, diffUserProfile as W, findUnpairedToolCalls as X, extractUiSpecEvents as Y, formatSkillScriptManifest as Z, FsRunTraceStore as _, renderUserProfileContext as _t, AgentLoop as a, mergeProfileEntries as at, GoogleGenAiClient as b, schemaSourceLabel as bt, CapabilityApproval as c, normalizeErrorCode as ct, EMPTY_USER_PROFILE as d, parseBridgeRequest as dt, interruptedToolResult as et, EventBus as f, parseUserProfileExport as ft, FsRunSnapshotStore as g, refineUserProfile as gt, FsMemoryStore as h, readUserProfile as ht, ASK_USER_TOOL_NAME as i, mergeCatalogEntries as it, TraceRecorder as j, SESSION_SCHEMA_VERSION as k, validateUiSpecNode as kt, DEFAULT_LOOP_LIMITS as l, normalizeToolContent as lt, FsArtifactStore as m, readProfileEntries as mt, ASK_USER_INPUT_SCHEMA as n, isUnsupportedRunSnapshot as nt, AnthropicClient as o, networkPolicyLibSource as ot, FS_SESSION_PAGE_SIZE as p, readBehaviorRecords as pt, extractSkillCandidate as q, ASK_USER_TOOL as r, listSkillScripts as rt, BEHAVIOR_RECORDS_KEY as s, networkUrlHost as st, ALLOWED_TOOLS_EXCLUSION_REASON as t, isNetworkAllowed as tt, DEFAULT_USER_PROFILE_LIMITS as u, normalizeToolError as ut, FsSessionStore as v, resolveToolName as vt, READ_SKILL_FILE_INPUT_SCHEMA as w, summarizeToolCalls as wt, HookRunner as x, schemaToForm as xt, FullDisclosureRouter as y, sampleBehaviorRecords as yt, applyUserProfileImport as z };
@@ -1,4 +1,4 @@
1
- //#region ../governance/dist/eventTypes-DjIQpt8Y.js
1
+ //#region ../governance/dist/eventTypes-g1BXL6x5.js
2
2
  /**
3
3
  * 审计事件类型常量(FR-13.4)。
4
4
  *
@@ -21,9 +21,14 @@ const AUDIT_EVENT_TYPES = {
21
21
  trustKeyRemoved: "trust.key_removed",
22
22
  policyNetworkChanged: "policy.network_changed",
23
23
  policyPrivacyChanged: "policy.privacy_changed",
24
+ policySecurityChanged: "policy.security_changed",
25
+ policySandboxChanged: "policy.sandbox_changed",
26
+ policyAgentCapabilitiesChanged: "policy.agent_capabilities_changed",
27
+ profileChanged: "profile.changed",
24
28
  mcpEndpointChanged: "mcp.endpoint_changed",
25
29
  mcpPolicyRelaxed: "mcp.policy_relaxed",
26
- providerChanged: "provider.changed"
30
+ providerChanged: "provider.changed",
31
+ candidateGenerated: "candidate.generated"
27
32
  };
28
33
  /** 稳定展示序:筛选下拉与文档表格都从这里取,不各自维护一份顺序 */
29
34
  const AUDIT_EVENT_TYPE_LIST = Object.values(AUDIT_EVENT_TYPES);
@@ -1,6 +1,6 @@
1
- import { H as PageQuery, I as FileSystemProvider, V as Page, et as SkillCatalogEntry, f as LlmMessage, l as LlmClient, nt as SkillDocument, ot as SkillManagerPort, x as UiBridge } from "./types-CcxRLdJG-DCXyw1US.js";
2
- import { H as IntegrityVerdict, Nt as SkillIntegrityGuard, Pt as SkillOutcomeReporter, Rt as SkillStateGuard, bt as RuntimeRun, ln as WebSkillRuntime } from "./index-DkbABR43.js";
3
- import { _ as SkillVersion, a as AuditLog, c as CandidateFile, d as CandidateSource, f as CandidateStatus, g as SkillState, h as SKILL_VERSION_PAGE_SIZE, i as AuditEvent, l as CandidateRisk, m as CompositeApprovalPolicy, n as ApprovalDecision, o as AuditQueryFilter, p as CandidateStore, r as ApprovalPolicy, s as CANDIDATE_PAGE_SIZE, t as AlwaysHumanApprovalPolicy, u as CandidateSkill, v as SkillVersionStore, y as candidateToCatalogEntry } from "./skillVersionStore-Bl-ElD45-CWPvGvoq.js";
1
+ import { H as PageQuery, I as FileSystemProvider, V as Page, ct as SkillManagerPort, f as LlmMessage, it as SkillDocument, l as LlmClient, nt as SkillCatalogEntry, x as UiBridge } from "./types-B3n0cMZu-BdcqQ35O.js";
2
+ import { H as IntegrityVerdict, It as SkillIntegrityGuard, Lt as SkillOutcomeReporter, Vt as SkillStateGuard, bt as RuntimeRun, pn as WebSkillRuntime } from "./index-K-eewlGL.js";
3
+ import { _ as SkillVersion, a as AuditLog, c as CandidateFile, d as CandidateSource, f as CandidateStatus, g as SkillState, h as SKILL_VERSION_PAGE_SIZE, i as AuditEvent, l as CandidateRisk, m as CompositeApprovalPolicy, n as ApprovalDecision, o as AuditQueryFilter, p as CandidateStore, r as ApprovalPolicy, s as CANDIDATE_PAGE_SIZE, t as AlwaysHumanApprovalPolicy, u as CandidateSkill, v as SkillVersionStore, y as candidateToCatalogEntry } from "./skillVersionStore-Bl-ElD45-gRfSaAby.js";
4
4
  //#region ../governance/dist/index.d.ts
5
5
  //#region src/candidate/candidateNormalizer.d.ts
6
6
  /** 剥 markdown fence 与 <think> 块、截取首尾 {};非对象 → CANDIDATE_INVALID */
@@ -110,6 +110,14 @@ interface AuditChainVerification {
110
110
  interface AuditPage extends Page<AuditEvent> {
111
111
  chainBrokenAt?: number;
112
112
  chainReason?: string;
113
+ /**
114
+ * 解析失败的行。长度 > 0 即「读不动」,但已解析的记录仍在 `items` 里——
115
+ * 不给这个字段的话,坏行被吞掉后的返回值与「真的没有事件」完全一样(FR-18.3)。
116
+ */
117
+ malformed?: {
118
+ count: number;
119
+ firstLine: number;
120
+ };
113
121
  }
114
122
  /**
115
123
  * JSONL 追加式审计日志(<managedRoot>/.webskill/audit.jsonl):
@@ -171,9 +179,14 @@ declare const AUDIT_EVENT_TYPES: {
171
179
  readonly trustKeyRemoved: "trust.key_removed";
172
180
  readonly policyNetworkChanged: "policy.network_changed";
173
181
  readonly policyPrivacyChanged: "policy.privacy_changed";
182
+ readonly policySecurityChanged: "policy.security_changed";
183
+ readonly policySandboxChanged: "policy.sandbox_changed";
184
+ readonly policyAgentCapabilitiesChanged: "policy.agent_capabilities_changed";
185
+ readonly profileChanged: "profile.changed";
174
186
  readonly mcpEndpointChanged: "mcp.endpoint_changed";
175
187
  readonly mcpPolicyRelaxed: "mcp.policy_relaxed";
176
188
  readonly providerChanged: "provider.changed";
189
+ readonly candidateGenerated: "candidate.generated";
177
190
  };
178
191
  type AuditEventType = (typeof AUDIT_EVENT_TYPES)[keyof typeof AUDIT_EVENT_TYPES];
179
192
  /** 稳定展示序:筛选下拉与文档表格都从这里取,不各自维护一份顺序 */
@@ -1,6 +1,6 @@
1
- import { O as messageOf, T as isValidSkillName, g as assertSafePathSegment, m as WebSkillError } from "./dist-8oQRa8Xz.js";
2
- import { a as textParts, n as partsToText } from "./memoryArtifactStore-52Zn9npI-BMPYwvoy.js";
3
- import { n as AUDIT_EVENT_TYPE_LIST, t as AUDIT_EVENT_TYPES } from "./eventTypes-DjIQpt8Y-Bj3vghj4.js";
1
+ import { A as messageOf, D as isValidSkillName, g as assertSafePathSegment, m as WebSkillError } from "./dist-59XlqDuv.js";
2
+ import { a as textParts, n as partsToText } from "./memoryArtifactStore-52Zn9npI-upv5OWYf.js";
3
+ import { n as AUDIT_EVENT_TYPE_LIST, t as AUDIT_EVENT_TYPES } from "./eventTypes-g1BXL6x5-CibcOftR.js";
4
4
 
5
5
  //#region ../governance/dist/index.js
6
6
  const invalid = (message, details) => {
@@ -443,15 +443,21 @@ var FsAuditLog = class {
443
443
  /** 按文件行序保留(含解析失败的洞):链校验必须在文件行序上做,不能在筛选结果上做 */
444
444
  const records = [];
445
445
  let skippedLines = 0;
446
+ let firstMalformedLine = -1;
446
447
  for (const line of raw.split("\n")) {
447
448
  if (line.trim() === "") continue;
448
449
  try {
449
450
  records.push(JSON.parse(line));
450
451
  } catch {
452
+ if (firstMalformedLine < 0) firstMalformedLine = records.length;
451
453
  skippedLines += 1;
452
454
  records.push(void 0);
453
455
  }
454
456
  }
457
+ const malformed = skippedLines > 0 ? {
458
+ count: skippedLines,
459
+ firstLine: firstMalformedLine
460
+ } : void 0;
455
461
  if (skippedLines > 0) console.warn(`[webskill] Audit log at ${path} contains ${skippedLines} unparsable line(s) skipped by query; run verifyChain() to check integrity`);
456
462
  const matched = [];
457
463
  for (let i = 0; i < records.length; i++) {
@@ -493,7 +499,8 @@ var FsAuditLog = class {
493
499
  ...broken !== void 0 ? {
494
500
  chainBrokenAt: broken.at,
495
501
  chainReason: broken.reason
496
- } : {}
502
+ } : {},
503
+ ...malformed !== void 0 ? { malformed } : {}
497
504
  };
498
505
  }
499
506
  /** 单行的链自洽:本行 hash 重算相符,且 prevHash 指向前一行的 hash。自洽时返回 undefined */
@@ -1025,14 +1032,17 @@ var EvaluationRunner = class {
1025
1032
  /** 失败 trace → 回归评估任务建议(prompt 复现 + expected 错误模式) */
1026
1033
  function suggestFromFailedRun(run) {
1027
1034
  const errorPatterns = run.trace.filter((e) => e.type === "tool.failed" || e.type === "run.failed").map((e) => String(e.data?.["code"] ?? e.message ?? "")).filter(Boolean);
1035
+ const failedSkills = [...new Set(run.trace.filter((e) => e.type === "tool.failed").map((e) => e.data?.["skillName"]).filter((name) => typeof name === "string" && name !== ""))];
1028
1036
  return {
1029
1037
  id: `regression-${run.id}`,
1030
1038
  prompt: run.userPrompt,
1039
+ ...run.activeSkillNames.length > 0 ? { skillNames: [...run.activeSkillNames] } : {},
1031
1040
  expected: (output, rerun) => rerun.status === "completed" && !rerun.trace.some((e) => (e.type === "tool.failed" || e.type === "run.failed") && errorPatterns.includes(String(e.data?.["code"] ?? ""))),
1032
1041
  metadata: {
1033
1042
  source: "test-suggestion",
1034
1043
  failureReason: run.terminationReason ?? "unknown",
1035
- errorPatterns
1044
+ errorPatterns,
1045
+ failedSkills
1036
1046
  }
1037
1047
  };
1038
1048
  }
@@ -1208,6 +1218,15 @@ function createMissHook(deps) {
1208
1218
  source: "runtime-miss"
1209
1219
  });
1210
1220
  await deps.store.save(candidate);
1221
+ await deps.audit?.append({
1222
+ type: AUDIT_EVENT_TYPES.candidateGenerated,
1223
+ actor: "system",
1224
+ target: candidate.name,
1225
+ data: {
1226
+ source: "runtime-miss",
1227
+ candidateId: candidate.id
1228
+ }
1229
+ });
1211
1230
  };
1212
1231
  }
1213
1232