@webskill/sdk 0.13.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-ExSQky4C.js → approval-BnLLCOG0.js} +277 -2934
  4. package/dist/browser.d.ts +327 -8
  5. package/dist/browser.js +1017 -51
  6. package/dist/{openUiLibrary-BKXW7Iwx-CWWBVOkE.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-iBm9tJL_.d.ts → index-CQYo4tcT.d.ts} +469 -10
  15. package/dist/{index-C3XdItd_.d.ts → index-CU2md8R1.d.ts} +26 -18
  16. package/dist/{index-DkvBhJQy.d.ts → index-Oc3H89TJ.d.ts} +204 -4
  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 +56 -3
  23. package/dist/mcp.js +75 -5
  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 +110 -13
  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-Bev6i6Ip.js → skill-CAJMsLod.js} +44 -314
  36. package/dist/{skillVersionStore-D-qHk9ZE-DheTIwAB.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-DLctJep_-B5G4uk2u.d.ts → types-C3V6lAeO-BIf7UB2e.d.ts} +79 -4
  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-C9lrvvMr.js → webskillLitCatalog-DSqVFQjK.js} +11 -3
  51. package/package.json +1 -1
  52. package/dist/catalogComponents-BgAJN0p8-CYEXSk45.js +0 -124384
  53. package/dist/client-BCM6Z3yq-qUQNkKrK.js +0 -7787
  54. package/dist/dist-DqcL6jKO.js +0 -3509
  55. package/dist/dist-DxyxmXPU-DGC-dpXf.js +0 -5621
  56. package/dist/dist-GK6dtjRv.js +0 -1493
  57. package/dist/memoryArtifactStore-52Zn9npI-LbCQaqyx.js +0 -86
  58. package/dist/stdio-CFMoANJJ-BxrTeXh7.js +0 -31
  59. package/dist/testing-WPTyXQYt.js +0 -142
  60. package/dist/types-WovEf4ED-CZSDiiBU.js +0 -6215
@@ -0,0 +1,533 @@
1
+ //#region ../ui/src/model/formModel.ts
2
+ const DEFAULT_INTERACTION_TEXTS = {
3
+ submit: "Submit",
4
+ cancel: "Cancel",
5
+ confirm: "Confirm",
6
+ select: "Select",
7
+ allow: "Allow",
8
+ deny: "Deny",
9
+ chooseFile: "Choose file",
10
+ decline: "Decline",
11
+ required: "This field is required",
12
+ suggested: "Suggested:",
13
+ useSuggestion: "Use"
14
+ };
15
+ function resolveInteractionTexts(texts) {
16
+ return texts ? {
17
+ ...DEFAULT_INTERACTION_TEXTS,
18
+ ...texts
19
+ } : DEFAULT_INTERACTION_TEXTS;
20
+ }
21
+ /** 可复用的部分取自 DEFAULT_INTERACTION_TEXTS,不另抄一份(AC-G10) */
22
+ const DEFAULT_SURFACE_FORM_TEXTS = {
23
+ required: DEFAULT_INTERACTION_TEXTS.required,
24
+ submit: DEFAULT_INTERACTION_TEXTS.submit,
25
+ cancel: DEFAULT_INTERACTION_TEXTS.cancel,
26
+ addItem: "Add",
27
+ removeItem: "Remove",
28
+ arrayFirstItemOnly: "This renderer shows only the first item of a repeatable group.",
29
+ readOnlySnapshot: "This is a saved record — its actions are no longer available.",
30
+ suggested: DEFAULT_INTERACTION_TEXTS.suggested,
31
+ useSuggestion: DEFAULT_INTERACTION_TEXTS.useSuggestion,
32
+ openDocument: "Open document"
33
+ };
34
+ function resolveSurfaceFormTexts(texts) {
35
+ return texts ? {
36
+ ...DEFAULT_SURFACE_FORM_TEXTS,
37
+ ...texts
38
+ } : DEFAULT_SURFACE_FORM_TEXTS;
39
+ }
40
+ const DEFAULT_SURFACE_HOST_CONTROL_TEXTS = {
41
+ previousPage: "Previous page",
42
+ previous: "Previous",
43
+ nextPage: "Next page",
44
+ next: "Next",
45
+ carousel: "Carousel"
46
+ };
47
+ function resolveSurfaceHostControlTexts(texts) {
48
+ return texts ? {
49
+ ...DEFAULT_SURFACE_HOST_CONTROL_TEXTS,
50
+ ...texts
51
+ } : DEFAULT_SURFACE_HOST_CONTROL_TEXTS;
52
+ }
53
+ /** 提交值按请求类型归形(WebFormBridge 与框架组件库共享单一来源) */
54
+ function shapeInteractionValue(model, values) {
55
+ switch (model.kind) {
56
+ case "ask": return values["answer"];
57
+ case "confirm": return values["confirmed"] === true;
58
+ case "select": return values["selected"];
59
+ case "authorize": return true;
60
+ case "file-pick": return values["file"];
61
+ case "form": return values;
62
+ }
63
+ }
64
+ /** 五类 InteractionRequest → 统一中间模型(框架无关) */
65
+ function interactionToFormModel(request, texts) {
66
+ const t = resolveInteractionTexts(texts);
67
+ switch (request.type) {
68
+ case "ask": return {
69
+ kind: "ask",
70
+ message: request.message,
71
+ controls: [{
72
+ name: "answer",
73
+ label: request.message,
74
+ control: "text",
75
+ required: true,
76
+ ...request.suggestion ? { suggestion: request.suggestion } : {}
77
+ }],
78
+ submitLabel: t.submit,
79
+ cancelLabel: t.cancel
80
+ };
81
+ case "confirm": return {
82
+ kind: "confirm",
83
+ message: request.message,
84
+ controls: [{
85
+ name: "confirmed",
86
+ label: request.message,
87
+ control: "boolean",
88
+ defaultValue: request.defaultValue ?? true
89
+ }],
90
+ submitLabel: t.confirm,
91
+ cancelLabel: t.cancel
92
+ };
93
+ case "form": return {
94
+ kind: "form",
95
+ ...request.title ? { title: request.title } : {},
96
+ controls: request.fields.map((f) => ({
97
+ name: f.name,
98
+ label: f.label,
99
+ control: f.type,
100
+ ...f.required ? { required: true } : {},
101
+ ...f.description ? { description: f.description } : {},
102
+ ...f.defaultValue !== void 0 ? { defaultValue: f.defaultValue } : {},
103
+ ...f.suggestion ? { suggestion: f.suggestion } : {},
104
+ ...f.options ? { options: f.options } : {}
105
+ })),
106
+ submitLabel: t.submit,
107
+ cancelLabel: t.cancel
108
+ };
109
+ case "select": return {
110
+ kind: "select",
111
+ message: request.message,
112
+ controls: [{
113
+ name: "selected",
114
+ label: request.message,
115
+ control: "select",
116
+ required: true,
117
+ options: request.options,
118
+ ...request.suggestion ? { suggestion: request.suggestion } : {}
119
+ }],
120
+ submitLabel: t.select,
121
+ cancelLabel: t.cancel
122
+ };
123
+ case "authorize": return {
124
+ kind: "authorize",
125
+ title: "Authorization required",
126
+ message: request.message,
127
+ controls: [],
128
+ submitLabel: t.allow,
129
+ cancelLabel: t.deny
130
+ };
131
+ case "file-pick": return {
132
+ kind: "file-pick",
133
+ title: "File requested",
134
+ message: request.message,
135
+ controls: [{
136
+ name: "file",
137
+ label: request.field ?? "file",
138
+ control: "file",
139
+ required: true,
140
+ ...request.accept ? { accept: request.accept } : {},
141
+ ...request.multiple ? { multiple: true } : {}
142
+ }],
143
+ submitLabel: t.chooseFile,
144
+ cancelLabel: t.decline
145
+ };
146
+ }
147
+ }
148
+
149
+ //#endregion
150
+ //#region ../ui/src/model/collectValues.ts
151
+ const isEmpty = (v) => v === void 0 || v === "";
152
+ /**
153
+ * 控件名 → 属性选择器:优先 CSS.escape(标识符形式,免引号转义);
154
+ * 无 CSS.escape 的环境退化为引号包裹 + 转义反斜杠/双引号(防选择器注入崩溃)
155
+ */
156
+ function controlSelector(name) {
157
+ if (typeof CSS !== "undefined" && typeof CSS.escape === "function") return `[data-webskill-control=${CSS.escape(name)}]`;
158
+ return `[data-webskill-control="${name.replace(/\\/g, "\\\\").replace(/"/g, "\\\"")}"]`;
159
+ }
160
+ /**
161
+ * 严格类型化控件值收集:
162
+ * - number 空串 → undefined(非 0);非数值输入(NaN)按缺失处理(required 时入 missingRequired)
163
+ * - select 用 option 值本身经 JSON 编码比对命中(对象值可正确命中)
164
+ * - required 空值列入 missingRequired(由调用方阻止提交并标记)
165
+ */
166
+ function collectValues(controls, container) {
167
+ const values = {};
168
+ const missingRequired = [];
169
+ for (const control of controls) {
170
+ const el = container.querySelector(controlSelector(control.name));
171
+ let value;
172
+ if (el === null) value = void 0;
173
+ else if (control.control === "boolean") value = el.checked;
174
+ else if (control.control === "number") {
175
+ const raw = el.value.trim();
176
+ if (raw === "") value = void 0;
177
+ else {
178
+ const n = Number(raw);
179
+ value = Number.isNaN(n) ? void 0 : n;
180
+ }
181
+ } else if (control.control === "select") {
182
+ const attr = el.value;
183
+ const hit = control.options?.find((o) => JSON.stringify(o.value) === attr);
184
+ value = hit ? hit.value : attr === "" ? void 0 : attr;
185
+ } else {
186
+ const raw = el.value;
187
+ value = raw === "" ? void 0 : raw;
188
+ }
189
+ values[control.name] = value;
190
+ if (control.required && isEmpty(value)) missingRequired.push(control.name);
191
+ }
192
+ return {
193
+ values,
194
+ missingRequired
195
+ };
196
+ }
197
+ /**
198
+ * 采纳建议值(FR-5.9):把 `control.suggestion` 写进已渲染的控件。
199
+ * 与 `collectValues` 共用同一套选择器与编码约定——两边分开实现的话,
200
+ * select 的 JSON 编码值迟早会对不上。
201
+ * @experimental
202
+ */
203
+ function applySuggestion(control, container) {
204
+ if (control.suggestion === void 0) return;
205
+ const el = container.querySelector(controlSelector(control.name));
206
+ if (el === null) return;
207
+ const { value } = control.suggestion;
208
+ if (control.control === "boolean") {
209
+ el.checked = value === true;
210
+ return;
211
+ }
212
+ if (control.control === "select") {
213
+ el.value = JSON.stringify(value);
214
+ return;
215
+ }
216
+ el.value = value === void 0 || value === null ? "" : String(value);
217
+ }
218
+
219
+ //#endregion
220
+ //#region ../ui/src/markdown/miniMarkdown.ts
221
+ /**
222
+ * 最小子集 markdown → DOM:标题(#..###)、无序列表、代码块(```)、加粗、链接。
223
+ * 全部内容经 textContent 写入,用户内容天然转义防 HTML 注入。
224
+ */
225
+ const INLINE_RE = /\*\*([^*]+)\*\*|\[([^\]]+)\]\(([^)\s]+)\)/g;
226
+ function appendInline(container, text, doc) {
227
+ let last = 0;
228
+ for (const match of text.matchAll(INLINE_RE)) {
229
+ const index = match.index ?? 0;
230
+ if (index > last) container.appendChild(doc.createTextNode(text.slice(last, index)));
231
+ if (match[1] !== void 0) {
232
+ const strong = doc.createElement("strong");
233
+ strong.textContent = match[1];
234
+ container.appendChild(strong);
235
+ } else {
236
+ const label = match[2] ?? "";
237
+ const url = match[3] ?? "";
238
+ if (/^https?:\/\//.test(url)) {
239
+ const a = doc.createElement("a");
240
+ a.href = url;
241
+ a.textContent = label;
242
+ a.rel = "noopener noreferrer";
243
+ container.appendChild(a);
244
+ } else container.appendChild(doc.createTextNode(match[0]));
245
+ }
246
+ last = index + match[0].length;
247
+ }
248
+ if (last < text.length) container.appendChild(doc.createTextNode(text.slice(last)));
249
+ }
250
+ function renderMiniMarkdown(text, doc) {
251
+ const root = doc.createElement("div");
252
+ root.className = "webskill-md";
253
+ const lines = text.split(/\r?\n/);
254
+ let i = 0;
255
+ while (i < lines.length) {
256
+ const line = lines[i] ?? "";
257
+ if (line.trimStart().startsWith("```")) {
258
+ const codeLines = [];
259
+ i++;
260
+ while (i < lines.length && !(lines[i] ?? "").trimStart().startsWith("```")) {
261
+ codeLines.push(lines[i] ?? "");
262
+ i++;
263
+ }
264
+ i++;
265
+ const pre = doc.createElement("pre");
266
+ const code = doc.createElement("code");
267
+ code.textContent = codeLines.join("\n");
268
+ pre.appendChild(code);
269
+ root.appendChild(pre);
270
+ continue;
271
+ }
272
+ const heading = /^(#{1,3})\s+(.*)$/.exec(line);
273
+ if (heading) {
274
+ const level = heading[1].length;
275
+ const h = doc.createElement(`h${level}`);
276
+ appendInline(h, heading[2] ?? "", doc);
277
+ root.appendChild(h);
278
+ i++;
279
+ continue;
280
+ }
281
+ if (/^\s*[-*]\s+/.test(line)) {
282
+ const ul = doc.createElement("ul");
283
+ while (i < lines.length && /^\s*[-*]\s+/.test(lines[i] ?? "")) {
284
+ const li = doc.createElement("li");
285
+ appendInline(li, (lines[i] ?? "").replace(/^\s*[-*]\s+/, ""), doc);
286
+ ul.appendChild(li);
287
+ i++;
288
+ }
289
+ root.appendChild(ul);
290
+ continue;
291
+ }
292
+ if (line.trim() === "") {
293
+ i++;
294
+ continue;
295
+ }
296
+ const p = doc.createElement("p");
297
+ appendInline(p, line, doc);
298
+ root.appendChild(p);
299
+ i++;
300
+ }
301
+ return root;
302
+ }
303
+
304
+ //#endregion
305
+ //#region ../ui/src/chart/miniChart.ts
306
+ /**
307
+ * 轻量 SVG 图表自绘(bar/line/pie,零依赖,三端复用单一来源)。
308
+ * 全部经 doc.createElementNS 构建(内容来自技能输出,不拼 innerHTML)。
309
+ */
310
+ const SVG_NS = "http://www.w3.org/2000/svg";
311
+ /**
312
+ * 固定 8 色循环调色板。这是**数据编码**(区分序列),不是主题色;
313
+ * 图表的轴线与文字等“外壳”颜色走 currentColor,跟随宿主容器的主题。
314
+ */
315
+ const CHART_PALETTE = [
316
+ "#4e79a7",
317
+ "#f28e2b",
318
+ "#e15759",
319
+ "#76b7b2",
320
+ "#59a14f",
321
+ "#edc948",
322
+ "#b07aa1",
323
+ "#ff9da7"
324
+ ];
325
+ const WIDTH = 320;
326
+ const HEIGHT = 200;
327
+ function el(doc, name, attrs) {
328
+ const node = doc.createElementNS(SVG_NS, name);
329
+ for (const [key, value] of Object.entries(attrs)) node.setAttribute(key, value);
330
+ return node;
331
+ }
332
+ function text(doc, x, y, content, attrs = {}) {
333
+ const node = el(doc, "text", {
334
+ x: String(x),
335
+ y: String(y),
336
+ "font-size": "9",
337
+ fill: "currentColor",
338
+ "fill-opacity": "0.65",
339
+ ...attrs
340
+ });
341
+ node.textContent = content;
342
+ return node;
343
+ }
344
+ const fmt = (n) => Number.isInteger(n) ? String(n) : n.toFixed(1);
345
+ function maxValue(chart) {
346
+ let max = 0;
347
+ for (const s of chart.series) for (const v of s.data) if (v > max) max = v;
348
+ return max;
349
+ }
350
+ function renderBar(chart, svg, doc) {
351
+ const plot = {
352
+ x0: 30,
353
+ y0: 24,
354
+ x1: 312,
355
+ y1: 164
356
+ };
357
+ const max = maxValue(chart);
358
+ svg.appendChild(el(doc, "line", {
359
+ x1: String(plot.x0),
360
+ y1: String(plot.y0),
361
+ x2: String(plot.x0),
362
+ y2: String(plot.y1),
363
+ stroke: "currentColor",
364
+ "stroke-opacity": "0.35"
365
+ }));
366
+ svg.appendChild(el(doc, "line", {
367
+ x1: String(plot.x0),
368
+ y1: String(plot.y1),
369
+ x2: String(plot.x1),
370
+ y2: String(plot.y1),
371
+ stroke: "currentColor",
372
+ "stroke-opacity": "0.35"
373
+ }));
374
+ if (max <= 0 || chart.labels.length === 0 || chart.series.length === 0) return;
375
+ const groupWidth = (plot.x1 - plot.x0) / chart.labels.length;
376
+ const barWidth = Math.max(1, groupWidth / chart.series.length * .7);
377
+ chart.series.forEach((series, si) => {
378
+ const color = CHART_PALETTE[si % CHART_PALETTE.length];
379
+ series.data.forEach((value, li) => {
380
+ if (li >= chart.labels.length) return;
381
+ const height = (plot.y1 - plot.y0) * value / max;
382
+ const x = plot.x0 + li * groupWidth + (groupWidth - barWidth * chart.series.length) / 2 + si * barWidth;
383
+ const y = plot.y1 - height;
384
+ svg.appendChild(el(doc, "rect", {
385
+ x: String(x),
386
+ y: String(y),
387
+ width: String(barWidth),
388
+ height: String(height),
389
+ fill: color,
390
+ "data-series": series.name ?? String(si)
391
+ }));
392
+ if (chart.series.length === 1) svg.appendChild(text(doc, x + barWidth / 2, y - 2, fmt(value), { "text-anchor": "middle" }));
393
+ });
394
+ });
395
+ chart.labels.forEach((label, li) => {
396
+ svg.appendChild(text(doc, plot.x0 + li * groupWidth + groupWidth / 2, plot.y1 + 12, label, { "text-anchor": "middle" }));
397
+ });
398
+ }
399
+ function renderLine(chart, svg, doc) {
400
+ const plot = {
401
+ x0: 30,
402
+ y0: 24,
403
+ x1: 312,
404
+ y1: 164
405
+ };
406
+ const max = maxValue(chart);
407
+ svg.appendChild(el(doc, "line", {
408
+ x1: String(plot.x0),
409
+ y1: String(plot.y0),
410
+ x2: String(plot.x0),
411
+ y2: String(plot.y1),
412
+ stroke: "currentColor",
413
+ "stroke-opacity": "0.35"
414
+ }));
415
+ svg.appendChild(el(doc, "line", {
416
+ x1: String(plot.x0),
417
+ y1: String(plot.y1),
418
+ x2: String(plot.x1),
419
+ y2: String(plot.y1),
420
+ stroke: "currentColor",
421
+ "stroke-opacity": "0.35"
422
+ }));
423
+ if (max <= 0 || chart.labels.length === 0 || chart.series.length === 0) return;
424
+ const step = chart.labels.length > 1 ? (plot.x1 - plot.x0) / (chart.labels.length - 1) : 0;
425
+ const px = (li) => chart.labels.length > 1 ? plot.x0 + li * step : (plot.x0 + plot.x1) / 2;
426
+ const py = (v) => plot.y1 - (plot.y1 - plot.y0) * v / max;
427
+ chart.series.forEach((series, si) => {
428
+ const color = CHART_PALETTE[si % CHART_PALETTE.length];
429
+ const points = series.data.slice(0, chart.labels.length).map((v, li) => `${px(li)},${py(v)}`).join(" ");
430
+ if (points !== "") svg.appendChild(el(doc, "polyline", {
431
+ points,
432
+ fill: "none",
433
+ stroke: color,
434
+ "stroke-width": "1.5"
435
+ }));
436
+ series.data.slice(0, chart.labels.length).forEach((v, li) => {
437
+ svg.appendChild(el(doc, "circle", {
438
+ cx: String(px(li)),
439
+ cy: String(py(v)),
440
+ r: "2",
441
+ fill: color
442
+ }));
443
+ });
444
+ });
445
+ chart.labels.forEach((label, li) => {
446
+ svg.appendChild(text(doc, px(li), plot.y1 + 12, label, { "text-anchor": "middle" }));
447
+ });
448
+ }
449
+ function renderPie(chart, svg, doc) {
450
+ const data = (chart.series[0]?.data ?? []).slice(0, chart.labels.length);
451
+ const total = data.reduce((sum, v) => sum + (v > 0 ? v : 0), 0);
452
+ const cx = 90;
453
+ const cy = 104;
454
+ const r = 72;
455
+ if (total <= 0) {
456
+ svg.appendChild(text(doc, cx, cy, "No data", { "text-anchor": "middle" }));
457
+ return;
458
+ }
459
+ let angle = -Math.PI / 2;
460
+ data.forEach((value, i) => {
461
+ const label = chart.labels[i] ?? String(i);
462
+ const color = CHART_PALETTE[i % CHART_PALETTE.length];
463
+ const slice = Math.max(value, 0) / total * Math.PI * 2;
464
+ const x0 = cx + r * Math.cos(angle);
465
+ const y0 = cy + r * Math.sin(angle);
466
+ const x1 = cx + r * Math.cos(angle + slice);
467
+ const y1 = cy + r * Math.sin(angle + slice);
468
+ const path = el(doc, "path", {
469
+ d: `M ${cx} ${cy} L ${x0} ${y0} A ${r} ${r} 0 ${slice > Math.PI ? "1" : "0"} 1 ${x1} ${y1} Z`,
470
+ fill: color,
471
+ "data-label": label
472
+ });
473
+ svg.appendChild(path);
474
+ angle += slice;
475
+ const ly = 40 + i * 14;
476
+ svg.appendChild(el(doc, "rect", {
477
+ x: "190",
478
+ y: String(ly - 7),
479
+ width: "8",
480
+ height: "8",
481
+ fill: color
482
+ }));
483
+ svg.appendChild(text(doc, 202, ly, `${label} (${fmt(value)})`));
484
+ });
485
+ }
486
+ /**
487
+ * ChartSpec → SVG(bar 等宽柱 + 值标签;line 折线 + 点;pie 扇形 + 图例;空数据容错)。
488
+ * mini 档只有这三种画法,其余类型走最接近的一种并在图内注明是近似呈现。
489
+ * @stable
490
+ */
491
+ function renderMiniChart(chart, doc) {
492
+ const svg = el(doc, "svg", {
493
+ viewBox: `0 0 ${WIDTH} ${HEIGHT}`,
494
+ width: String(WIDTH),
495
+ height: String(HEIGHT),
496
+ class: `webskill-chart webskill-chart--${chart.kind}`,
497
+ role: "img"
498
+ });
499
+ if (chart.title) svg.appendChild(text(doc, WIDTH / 2, 14, chart.title, {
500
+ "text-anchor": "middle",
501
+ "font-size": "11",
502
+ fill: "currentColor",
503
+ "fill-opacity": "1"
504
+ }));
505
+ switch (chart.kind) {
506
+ case "bar":
507
+ case "stacked-bar":
508
+ renderBar(chart, svg, doc);
509
+ break;
510
+ case "line":
511
+ renderLine(chart, svg, doc);
512
+ break;
513
+ case "pie":
514
+ renderPie(chart, svg, doc);
515
+ break;
516
+ default:
517
+ renderLine(chart, svg, doc);
518
+ break;
519
+ }
520
+ if (chart.kind !== "bar" && chart.kind !== "line" && chart.kind !== "pie") svg.appendChild(text(doc, WIDTH / 2, HEIGHT - 4, `Approximate rendering of "${chart.kind}"`, { "text-anchor": "middle" }));
521
+ return svg;
522
+ }
523
+ /** A2UI/OpenUI 降级:chart → table(labels 为首列,series 各为一列) */
524
+ function chartToTable(chart) {
525
+ return {
526
+ type: "table",
527
+ columns: ["label", ...chart.series.map((s, i) => s.name ?? `series ${i + 1}`)],
528
+ rows: chart.labels.map((label, li) => [label, ...chart.series.map((s) => s.data[li] ?? null)])
529
+ };
530
+ }
531
+
532
+ //#endregion
533
+ export { applySuggestion as a, DEFAULT_SURFACE_FORM_TEXTS as c, resolveInteractionTexts as d, resolveSurfaceFormTexts as f, renderMiniMarkdown as i, DEFAULT_SURFACE_HOST_CONTROL_TEXTS as l, shapeInteractionValue as m, chartToTable as n, collectValues as o, resolveSurfaceHostControlTexts as p, renderMiniChart as r, DEFAULT_INTERACTION_TEXTS as s, CHART_PALETTE as t, interactionToFormModel as u };
package/dist/node.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { $ as SignatureAuditSink, B as JsonSchema, Ct as VerifyResult, J as SKILL_MANIFEST_FILE, L as FileStat, M as ArchiveLimits, R as FileSystemProvider, S as UiBridge, _t as SkillsLockfile, b as RenderResultRequest, c as InteractionResponse, dt as SkillManifest, q as SKILLS_LOCKFILE, s as InteractionRequest, st as SkillInstallSource, ut as SkillManagerPort, xt as UnsignedPolicy, yt as TrustedKeyStore } from "./types-DLctJep_-B5G4uk2u.js";
2
- import { Bt as SchemaInferer, Ht as ScriptExecutor, In as WebSkillRuntime, L as FsArtifactStore, Ln as WebSkillRuntimeDeps, R as FsMemoryStore, Un as createScriptContext, Vt as ScriptExecutionContext, it as NetworkPolicy, m as ApprovalScope, pn as ToolResult, un as ToolDefinition, y as BridgeCapabilities } from "./index-DkvBhJQy.js";
3
- import { a as AuditLog, b as SkillVersionStore, d as CandidateSkill, m as CandidateStore, r as ApprovalPolicy } from "./skillVersionStore-D-qHk9ZE-DheTIwAB.js";
1
+ import { $ as SKILLS_LOCKFILE, Ct as SkillsLockfile, Et as TrustedKeyStore, H as FileStat, K as JsonSchema, N as ArchiveLimits, S as UiBridge, U as FileSystemProvider, _t as SkillManifest, at as SignatureAuditSink, b as RenderResultRequest, c as InteractionResponse, et as SKILL_MANIFEST_FILE, gt as SkillManagerPort, jt as VerifyResult, kt as UnsignedPolicy, pt as SkillInstallSource, s as InteractionRequest } from "./types-C3V6lAeO-BIf7UB2e.js";
2
+ import { Gn as WebSkillRuntimeDeps, Gt as SchemaInferer, H as FsMemoryStore, Kt as ScriptExecutionContext, V as FsArtifactStore, Wn as WebSkillRuntime, Zn as createScriptContext, ct as NetworkPolicy, gn as ToolDefinition, m as ApprovalScope, qt as ScriptExecutor, y as BridgeCapabilities, yn as ToolResult } from "./index-Oc3H89TJ.js";
3
+ import { a as AuditLog, b as SkillVersionStore, d as CandidateSkill, m as CandidateStore, r as ApprovalPolicy } from "./skillVersionStore-B24Jjjry-C4zomhMZ.js";
4
4
  import { n as LlmEnvConfig, s as probeLlmCapabilities, t as LlmCapabilities } from "./env-AK3cSMEA-Dli6QU5E.js";
5
5
  import { Readable, Writable } from "node:stream";
6
6
  //#region ../node/dist/index.d.ts