@webskill/sdk 0.5.0 → 0.6.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 +2 -2
  2. package/dist/agent.js +57 -15
  3. package/dist/browser.d.ts +101 -5
  4. package/dist/browser.js +421 -11
  5. package/dist/{catalogComponents-DV7cPpUm-C77AEEx9.js → catalogComponents-Dr5dFMAb-Dacibl1e.js} +126 -44
  6. package/dist/{dist-bewtXYlO.js → dist-DnYG2-eY.js} +53 -14
  7. package/dist/{dist-6C03DShK.js → dist-DusANsrn.js} +981 -185
  8. package/dist/{env--jJB-TSX-04klhTYi.js → env-8cY40DXB-CGnEVZby.js} +7 -6
  9. package/dist/{env-BPUBZCwJ-4jat_SVG.d.ts → env-AK3cSMEA-Dli6QU5E.d.ts} +4 -3
  10. package/dist/governance.d.ts +3 -3
  11. package/dist/governance.js +1 -1
  12. package/dist/{index-Bsqg4ftU.d.ts → index-BMocOEi0.d.ts} +13 -7
  13. package/dist/{index-D_7ZZjkl.d.ts → index-BuTpBMzr.d.ts} +69 -6
  14. package/dist/{index-vBz_FC9w.d.ts → index-C-KFAZoF.d.ts} +298 -52
  15. package/dist/index.d.ts +3 -3
  16. package/dist/index.js +3 -3
  17. package/dist/mcp.d.ts +39 -8
  18. package/dist/mcp.js +53 -19
  19. package/dist/{memoryArtifactStore-BtOeB_hm-tj3fC5ip.js → memoryArtifactStore-52Zn9npI-BMPYwvoy.js} +10 -2
  20. package/dist/node.d.ts +4 -4
  21. package/dist/node.js +9 -2
  22. package/dist/{openUiLibrary-W3Ce896k-ClFTRZFs.js → openUiLibrary-Bdrji9qK-DzAxRlTY.js} +3 -3
  23. package/dist/{skillVersionStore-BzLbzFOL-CxwIewHJ.d.ts → skillVersionStore-BzLbzFOL-CxdAFWO2.d.ts} +1 -1
  24. package/dist/{testing-DDCJWvgA.js → testing-CYTFqkDm.js} +1 -1
  25. package/dist/testing.d.ts +2 -2
  26. package/dist/testing.js +3 -3
  27. package/dist/{types-D_hoCri8-BnNPiZCi.d.ts → types-4pg-qp_I-Gq63X8Oa.d.ts} +33 -8
  28. package/dist/ui-react.d.ts +2 -2
  29. package/dist/ui-react.js +66 -23
  30. package/dist/ui-vue.d.ts +1 -1
  31. package/dist/ui-vue.js +13 -8
  32. package/dist/ui.d.ts +3 -3
  33. package/dist/ui.js +2 -2
  34. package/dist/{webskillLitCatalog-_mugzRHx-DiuJpCuf.js → webskillLitCatalog-_mugzRHx-B_54vxum.js} +1 -1
  35. package/package.json +1 -1
@@ -1,6 +1,6 @@
1
1
  import { a as __require, i as __reExport, n as __esmMin, o as __toCommonJS, r as __exportAll$2, s as __toESM$1, t as __commonJSMin$1 } from "./rolldown-runtime-BOF7iYI8.js";
2
2
  import { m as WebSkillError } from "./dist-8oQRa8Xz.js";
3
- import { M as qualifyFieldName, Q as chartSpecFromProps, et as mountEchart, v as collectFormScopes, y as collectScopedValues } from "./dist-bewtXYlO.js";
3
+ import { M as qualifyFieldName, Q as chartSpecFromProps, et as mountEchart, v as collectFormScopes, y as collectScopedValues } from "./dist-DnYG2-eY.js";
4
4
  import minpath$1 from "node:path";
5
5
  import { fileURLToPath as urlToPath$1 } from "node:url";
6
6
  import * as React$10 from "react";
@@ -3407,11 +3407,49 @@ const getDefaultConfig = () => {
3407
3407
  const twMerge = /*#__PURE__*/ createTailwindMerge(getDefaultConfig);
3408
3408
 
3409
3409
  //#endregion
3410
- //#region ../ui-kit/dist/cn-Dt6Yi1Qv.js
3410
+ //#region ../ui-kit/dist/useDarkAncestor-D41bzGNA.js
3411
3411
  /** shadcn 约定的类名合并:后写的 Tailwind 类覆盖先写的同族类。 */
3412
3412
  function cn(...inputs) {
3413
3413
  return twMerge(clsx(inputs));
3414
3414
  }
3415
+ /**
3416
+ * 声明了主题的祖先:`data-theme` 由 ThemeScope 挂(亮暗都挂),`.dark` 是宿主页面惯用的暗色类名。
3417
+ * 两者一起选,`closest` 才会停在**最近**的那一层,而不是越过亮色实例去命中外层的暗色宿主。
3418
+ */
3419
+ const THEME_ANCESTOR = "[data-theme], .dark";
3420
+ /**
3421
+ * 判定挂载点**最近的**主题祖先是否处于暗色(0.6.0 FR-20.4)。
3422
+ *
3423
+ * 不用 `document.querySelector('.dark')`:那是全局查询,宿主页面是暗色时,
3424
+ * 嵌在暗色宿主里的亮色 SDK 实例也会被判成暗色(反之亦然)。
3425
+ *
3426
+ * 返回 ref 回调而不是接受 ref 对象:ref 对象的赋值不触发渲染,拿不到「已挂载」这个时机。
3427
+ */
3428
+ function useDarkAncestor() {
3429
+ const [node, setNode] = useState(null);
3430
+ const [dark, setDark] = useState(false);
3431
+ useEffect(() => {
3432
+ if (!node) return;
3433
+ const update = () => {
3434
+ const scope = node.closest(THEME_ANCESTOR);
3435
+ if (!scope) {
3436
+ setDark(false);
3437
+ return;
3438
+ }
3439
+ const declared = scope.getAttribute("data-theme");
3440
+ setDark(declared === null ? true : declared === "dark");
3441
+ };
3442
+ update();
3443
+ const observer = new MutationObserver(update);
3444
+ observer.observe(document.documentElement, {
3445
+ attributes: true,
3446
+ attributeFilter: ["class", "data-theme"],
3447
+ subtree: true
3448
+ });
3449
+ return () => observer.disconnect();
3450
+ }, [node]);
3451
+ return [dark, setNode];
3452
+ }
3415
3453
 
3416
3454
  //#endregion
3417
3455
  //#region ../../node_modules/.pnpm/@radix-ui+react-compose-refs@1.1.5_@types+react@19.2.17_react@19.2.8/node_modules/@radix-ui/react-compose-refs/dist/index.mjs
@@ -99560,6 +99598,19 @@ const PanelLeft = createLucideIcon("panel-left", [["rect", {
99560
99598
  * This source code is licensed under the ISC license.
99561
99599
  * See the LICENSE file in the root directory of this source tree.
99562
99600
  */
99601
+ const Plus = createLucideIcon("plus", [["path", {
99602
+ d: "M5 12h14",
99603
+ key: "1ays0h"
99604
+ }], ["path", {
99605
+ d: "M12 5v14",
99606
+ key: "s699le"
99607
+ }]]);
99608
+ /**
99609
+ * @license lucide-react v1.27.0 - ISC
99610
+ *
99611
+ * This source code is licensed under the ISC license.
99612
+ * See the LICENSE file in the root directory of this source tree.
99613
+ */
99563
99614
  const Search = createLucideIcon("search", [["path", {
99564
99615
  d: "m21 21-4.34-4.34",
99565
99616
  key: "14j7rj"
@@ -99672,6 +99723,26 @@ function Switch({ className = "", label, ...props }) {
99672
99723
  })]
99673
99724
  });
99674
99725
  }
99726
+ /**
99727
+ * 一个 SDK 实例的主题作用域(0.6.0 FR-20.4)。
99728
+ *
99729
+ * 解决两件事:
99730
+ * 1. Radix 的 Portal 默认渲染到 `document.body`,会逃出主题子树 —— 这里在作用域**内部**
99731
+ * 提供一个 Portal 容器,浮层因此仍处在带主题类名的祖先链下;
99732
+ * 2. 原生 `<select>` 的下拉由浏览器按 `color-scheme` 绘制,类名管不到 —— 容器上的
99733
+ * `data-webskill-theme` 属性在 base.css 里显式声明了 `color-scheme`。
99734
+ *
99735
+ * 宿主页面自身的类名不被改动:作用域只作用于自己的子树。
99736
+ */
99737
+ const PortalContainerContext = createContext(void 0);
99738
+ /**
99739
+ * 当前实例的 Portal 容器;不在 `ThemeScope` 内时返回 `undefined`,
99740
+ * 调用方据此回落到 Radix 默认的 `document.body`。
99741
+ * @experimental
99742
+ */
99743
+ function usePortalContainer() {
99744
+ return useContext(PortalContainerContext);
99745
+ }
99675
99746
  const DropdownMenu = Root2;
99676
99747
  function DropdownMenuTrigger({ children, className = "", asChild, ...props }) {
99677
99748
  const triggerClass = asChild ? className : `inline-flex h-9 items-center justify-center rounded-md border border-border bg-surface px-3 text-sm font-medium text-ink shadow-xs outline-none transition-colors hover:bg-subtle focus-visible:border-ring focus-visible:ring-2 focus-visible:ring-ring/20 ${className}`;
@@ -99683,12 +99754,15 @@ function DropdownMenuTrigger({ children, className = "", asChild, ...props }) {
99683
99754
  });
99684
99755
  }
99685
99756
  function DropdownMenuContent({ children, className = "", sideOffset = 6, ...props }) {
99686
- return /* @__PURE__ */ jsx(Portal2, { children: /* @__PURE__ */ jsx(Content2, {
99687
- sideOffset,
99688
- className: `z-50 min-w-40 rounded-md border border-border bg-surface p-1 text-sm text-ink shadow-pop outline-none ${className}`,
99689
- ...props,
99690
- children
99691
- }) });
99757
+ return /* @__PURE__ */ jsx(Portal2, {
99758
+ container: usePortalContainer(),
99759
+ children: /* @__PURE__ */ jsx(Content2, {
99760
+ sideOffset,
99761
+ className: `z-50 min-w-40 rounded-md border border-border bg-surface p-1 text-sm text-ink shadow-pop outline-none ${className}`,
99762
+ ...props,
99763
+ children
99764
+ })
99765
+ });
99692
99766
  }
99693
99767
  function DropdownMenuCheckboxItem({ children, className = "", ...props }) {
99694
99768
  return /* @__PURE__ */ jsxs(CheckboxItem2, {
@@ -119889,29 +119963,11 @@ function resolveLanguage(raw) {
119889
119963
  if (raw in languages) return raw;
119890
119964
  return languageAliases[raw];
119891
119965
  }
119892
- /** 探测 .dark 祖先(class 策略):监听 documentElement/body 的 class 变化 */
119893
- function useDarkClass() {
119894
- const [dark, setDark] = useState(() => typeof document !== "undefined" && document.querySelector(".dark") !== null);
119895
- useEffect(() => {
119896
- const update = () => setDark(document.querySelector(".dark") !== null);
119897
- const observer = new MutationObserver(update);
119898
- observer.observe(document.documentElement, {
119899
- attributes: true,
119900
- attributeFilter: ["class"]
119901
- });
119902
- if (document.body) observer.observe(document.body, {
119903
- attributes: true,
119904
- attributeFilter: ["class"]
119905
- });
119906
- update();
119907
- return () => observer.disconnect();
119908
- }, []);
119909
- return dark;
119910
- }
119911
119966
  function CodeBlock({ node: _node, className, children, ...rest }) {
119912
- const dark = useDarkClass();
119967
+ const [dark, themeRef] = useDarkAncestor();
119913
119968
  const language = resolveLanguage(/language-(\w+)/.exec(className ?? "")?.[1]);
119914
119969
  if (language) return /* @__PURE__ */ jsxs("div", {
119970
+ ref: themeRef,
119915
119971
  className: "my-3 overflow-hidden rounded-card border border-border",
119916
119972
  children: [/* @__PURE__ */ jsx("div", {
119917
119973
  className: "border-b border-border bg-subtle px-3 py-1.5 font-mono text-xs text-muted",
@@ -120084,9 +120140,27 @@ const MarkdownText = memo(function MarkdownText({ className }) {
120084
120140
  defer: true
120085
120141
  });
120086
120142
  });
120143
+ /**
120144
+ * provider 相关的默认值与切换规则(0.6.0 FR-13.1)。
120145
+ * chatbot 设置面板与 console 的 `connections.models` 共用这一份——
120146
+ * 0.5.x 时两处各自硬编码,改一处漏一处。
120147
+ */
120148
+ /**
120149
+ * 各 provider 的官方默认端点。取值必须与客户端内部的 fallback 一致(T-03-2 断言):
120150
+ * 客户端的 fallback 保证「用户没填也能跑」,这张表只服务 UI 预填,两者说的是同一件事。
120151
+ * `openai-compatible` 与 `chrome-builtin` 无默认——前者端点任意,后者根本不走 HTTP。
120152
+ * @experimental
120153
+ */
120154
+ const PROVIDER_DEFAULT_BASE_URL = {
120155
+ "openai-compatible": void 0,
120156
+ anthropic: "https://api.anthropic.com",
120157
+ google: "https://generativelanguage.googleapis.com",
120158
+ "chrome-builtin": void 0
120159
+ };
120160
+ const KNOWN_DEFAULT_BASE_URLS = new Set(Object.values(PROVIDER_DEFAULT_BASE_URL).filter((url) => url !== void 0));
120087
120161
 
120088
120162
  //#endregion
120089
- //#region ../ui-react/dist/catalogComponents-DV7cPpUm.js
120163
+ //#region ../ui-react/dist/catalogComponents-Dr5dFMAb.js
120090
120164
  /** echarts 挂载点:surface 图表与 catalog 声明树的 Chart 节点共用,实现在 `@webskill/ui`,与 A2UI 档同一份 */
120091
120165
  function EChart({ chart }) {
120092
120166
  const containerRef = useRef(null);
@@ -120302,13 +120376,21 @@ function SurfaceField({ form, props, scope }) {
120302
120376
  suggestion !== void 0 && isBlank(value) ? /* @__PURE__ */ jsxs("span", {
120303
120377
  "data-webskill-suggestion": key,
120304
120378
  className: "flex items-center gap-2 text-xs text-muted",
120305
- children: [/* @__PURE__ */ jsxs("span", { children: ["Last entered: ", String(suggestion.value)] }), /* @__PURE__ */ jsx("button", {
120306
- type: "button",
120307
- "data-webskill-suggestion-use": key,
120308
- onClick: () => form.setValue(key, suggestion.value),
120309
- className: "rounded-md border border-border px-2 py-0.5 text-ink transition-colors hover:bg-accent",
120310
- children: "Use"
120311
- })]
120379
+ children: [
120380
+ /* @__PURE__ */ jsxs("span", { children: ["Suggested: ", String(suggestion.value)] }),
120381
+ suggestion.reason ? /* @__PURE__ */ jsxs("span", { children: [
120382
+ "(",
120383
+ suggestion.reason,
120384
+ ")"
120385
+ ] }) : null,
120386
+ /* @__PURE__ */ jsx("button", {
120387
+ type: "button",
120388
+ "data-webskill-suggestion-use": key,
120389
+ onClick: () => form.setValue(key, suggestion.value),
120390
+ className: "rounded-md border border-border px-2 py-0.5 text-ink transition-colors hover:bg-accent",
120391
+ children: "Use"
120392
+ })
120393
+ ]
120312
120394
  }) : null,
120313
120395
  props["description"] ? /* @__PURE__ */ jsx("span", {
120314
120396
  className: "text-xs text-muted",
@@ -120328,20 +120410,20 @@ function SurfaceFormButtons({ form, props, scope }) {
120328
120410
  const submitId = scope ? scope.submitActionId : form.resolveActionId("submit");
120329
120411
  const cancelId = scope ? scope.cancelActionId : form.resolveActionId("cancel");
120330
120412
  return /* @__PURE__ */ jsxs("div", {
120331
- className: "flex gap-2",
120332
- children: [/* @__PURE__ */ jsx(Button, {
120333
- type: "submit",
120334
- size: "sm",
120335
- "data-webskill-surface-action": submitId,
120336
- children: str(props, "submitLabel", "Submit")
120337
- }), props["cancelLabel"] ? /* @__PURE__ */ jsx(Button, {
120413
+ className: "flex flex-wrap items-center justify-end gap-2",
120414
+ children: [props["cancelLabel"] ? /* @__PURE__ */ jsx(Button, {
120338
120415
  type: "button",
120339
120416
  size: "sm",
120340
120417
  variant: "secondary",
120341
120418
  "data-webskill-surface-action": cancelId,
120342
120419
  onClick: () => form.emit(cancelId, scope),
120343
120420
  children: str(props, "cancelLabel")
120344
- }) : null]
120421
+ }) : null, /* @__PURE__ */ jsx(Button, {
120422
+ type: "submit",
120423
+ size: "sm",
120424
+ "data-webskill-surface-action": submitId,
120425
+ children: str(props, "submitLabel", "Submit")
120426
+ })]
120345
120427
  });
120346
120428
  }
120347
120429
  /** catalog `Button` 的唯一实现:submit 走带值提交,其余走裸动作 */
@@ -992,6 +992,7 @@ function shapeInteractionValue(model, values) {
992
992
  case "confirm": return values["confirmed"] === true;
993
993
  case "select": return values["selected"];
994
994
  case "authorize": return true;
995
+ case "file-pick": return values["file"];
995
996
  case "form": return values;
996
997
  }
997
998
  }
@@ -1005,7 +1006,8 @@ function interactionToFormModel(request) {
1005
1006
  name: "answer",
1006
1007
  label: request.message,
1007
1008
  control: "text",
1008
- required: true
1009
+ required: true,
1010
+ ...request.suggestion ? { suggestion: request.suggestion } : {}
1009
1011
  }],
1010
1012
  submitLabel: "Submit",
1011
1013
  cancelLabel: "Cancel"
@@ -1046,7 +1048,8 @@ function interactionToFormModel(request) {
1046
1048
  label: request.message,
1047
1049
  control: "select",
1048
1050
  required: true,
1049
- options: request.options
1051
+ options: request.options,
1052
+ ...request.suggestion ? { suggestion: request.suggestion } : {}
1050
1053
  }],
1051
1054
  submitLabel: "Select",
1052
1055
  cancelLabel: "Cancel"
@@ -1059,6 +1062,21 @@ function interactionToFormModel(request) {
1059
1062
  submitLabel: "Allow",
1060
1063
  cancelLabel: "Deny"
1061
1064
  };
1065
+ case "file-pick": return {
1066
+ kind: "file-pick",
1067
+ title: "File requested",
1068
+ message: request.message,
1069
+ controls: [{
1070
+ name: "file",
1071
+ label: request.field ?? "file",
1072
+ control: "file",
1073
+ required: true,
1074
+ ...request.accept ? { accept: request.accept } : {},
1075
+ ...request.multiple ? { multiple: true } : {}
1076
+ }],
1077
+ submitLabel: "Choose file",
1078
+ cancelLabel: "Decline"
1079
+ };
1062
1080
  }
1063
1081
  }
1064
1082
  const isEmpty = (v) => v === void 0 || v === "";
@@ -1133,7 +1151,10 @@ function applySuggestion(control, container) {
1133
1151
  * 全部经 doc.createElementNS 构建(内容来自技能输出,不拼 innerHTML)。
1134
1152
  */
1135
1153
  const SVG_NS = "http://www.w3.org/2000/svg";
1136
- /** 固定 8 色循环调色板 */
1154
+ /**
1155
+ * 固定 8 色循环调色板。这是**数据编码**(区分序列),不是主题色;
1156
+ * 图表的轴线与文字等“外壳”颜色走 currentColor,跟随宿主容器的主题。
1157
+ */
1137
1158
  const CHART_PALETTE = [
1138
1159
  "#4e79a7",
1139
1160
  "#f28e2b",
@@ -1156,7 +1177,8 @@ function text(doc, x, y, content, attrs = {}) {
1156
1177
  x: String(x),
1157
1178
  y: String(y),
1158
1179
  "font-size": "9",
1159
- fill: "#555",
1180
+ fill: "currentColor",
1181
+ "fill-opacity": "0.65",
1160
1182
  ...attrs
1161
1183
  });
1162
1184
  node.textContent = content;
@@ -1181,14 +1203,16 @@ function renderBar(chart, svg, doc) {
1181
1203
  y1: String(plot.y0),
1182
1204
  x2: String(plot.x0),
1183
1205
  y2: String(plot.y1),
1184
- stroke: "#999"
1206
+ stroke: "currentColor",
1207
+ "stroke-opacity": "0.35"
1185
1208
  }));
1186
1209
  svg.appendChild(el(doc, "line", {
1187
1210
  x1: String(plot.x0),
1188
1211
  y1: String(plot.y1),
1189
1212
  x2: String(plot.x1),
1190
1213
  y2: String(plot.y1),
1191
- stroke: "#999"
1214
+ stroke: "currentColor",
1215
+ "stroke-opacity": "0.35"
1192
1216
  }));
1193
1217
  if (max <= 0 || chart.labels.length === 0 || chart.series.length === 0) return;
1194
1218
  const groupWidth = (plot.x1 - plot.x0) / chart.labels.length;
@@ -1228,14 +1252,16 @@ function renderLine(chart, svg, doc) {
1228
1252
  y1: String(plot.y0),
1229
1253
  x2: String(plot.x0),
1230
1254
  y2: String(plot.y1),
1231
- stroke: "#999"
1255
+ stroke: "currentColor",
1256
+ "stroke-opacity": "0.35"
1232
1257
  }));
1233
1258
  svg.appendChild(el(doc, "line", {
1234
1259
  x1: String(plot.x0),
1235
1260
  y1: String(plot.y1),
1236
1261
  x2: String(plot.x1),
1237
1262
  y2: String(plot.y1),
1238
- stroke: "#999"
1263
+ stroke: "currentColor",
1264
+ "stroke-opacity": "0.35"
1239
1265
  }));
1240
1266
  if (max <= 0 || chart.labels.length === 0 || chart.series.length === 0) return;
1241
1267
  const step = chart.labels.length > 1 ? (plot.x1 - plot.x0) / (chart.labels.length - 1) : 0;
@@ -1315,7 +1341,8 @@ function renderMiniChart(chart, doc) {
1315
1341
  if (chart.title) svg.appendChild(text(doc, WIDTH / 2, 14, chart.title, {
1316
1342
  "text-anchor": "middle",
1317
1343
  "font-size": "11",
1318
- fill: "#333"
1344
+ fill: "currentColor",
1345
+ "fill-opacity": "1"
1319
1346
  }));
1320
1347
  switch (chart.kind) {
1321
1348
  case "bar":
@@ -1632,7 +1659,7 @@ var WebFormBridge = class {
1632
1659
  wrapper.appendChild(error);
1633
1660
  return wrapper;
1634
1661
  }
1635
- /** 历史值以**建议**形态出现(FR-5.9):控件初始值仍为空,点「使用」才写入 */
1662
+ /** 建议值以**建议**形态出现(FR-19.4):控件初始值仍为空,点「使用」才写入 */
1636
1663
  #renderSuggestion(control, container) {
1637
1664
  const doc = this.#doc;
1638
1665
  const row = doc.createElement("div");
@@ -1640,8 +1667,15 @@ var WebFormBridge = class {
1640
1667
  row.setAttribute("data-webskill-suggestion", control.name);
1641
1668
  const preview = doc.createElement("span");
1642
1669
  preview.className = "webskill-form__suggestion-value";
1643
- preview.textContent = `Last entered: ${String(control.suggestion?.value)}`;
1670
+ preview.textContent = `Suggested: ${String(control.suggestion?.value)}`;
1644
1671
  row.appendChild(preview);
1672
+ const reason = control.suggestion?.reason;
1673
+ if (reason !== void 0 && reason !== "") {
1674
+ const why = doc.createElement("span");
1675
+ why.className = "webskill-form__suggestion-reason";
1676
+ why.textContent = `(${reason})`;
1677
+ row.appendChild(why);
1678
+ }
1645
1679
  const use = doc.createElement("button");
1646
1680
  use.type = "button";
1647
1681
  use.className = "webskill-form__suggestion-use";
@@ -2016,7 +2050,8 @@ const FIELD_TYPE = {
2016
2050
  number: "number",
2017
2051
  boolean: "toggle",
2018
2052
  select: "select",
2019
- textarea: "textarea"
2053
+ textarea: "textarea",
2054
+ file: "file"
2020
2055
  };
2021
2056
  function toOptions(options) {
2022
2057
  return (options ?? []).map((option) => ({
@@ -2035,6 +2070,8 @@ function toField(control) {
2035
2070
  ...control.description ? { description: control.description } : {},
2036
2071
  ...control.defaultValue !== void 0 ? { defaultValue: control.defaultValue } : {},
2037
2072
  ...control.suggestion ? { suggestion: control.suggestion } : {},
2073
+ ...control.accept ? { accept: [...control.accept] } : {},
2074
+ ...control.multiple ? { multiple: true } : {},
2038
2075
  ...control.options ? { options: toOptions(control.options) } : {}
2039
2076
  }
2040
2077
  };
@@ -2087,6 +2124,8 @@ const INTENTS = /* @__PURE__ */ new Set([
2087
2124
  "download",
2088
2125
  "refresh"
2089
2126
  ]);
2127
+ /** 去重靠指纹兜底,但重复调用本身也浪费一轮,所以先在提示词里劝阻(FR-21.5) */
2128
+ const NO_DUPLICATE_RENDER = "If a skill has already rendered a surface for this request, do not call render_ui again with the same content.";
2090
2129
  function isIntent(value) {
2091
2130
  return typeof value === "string" && INTENTS.has(value);
2092
2131
  }
@@ -2167,7 +2206,7 @@ function createUiCatalogToolSource(options = {}) {
2167
2206
  });
2168
2207
  return {
2169
2208
  kind: "ui-catalog",
2170
- systemPrompt: () => Promise.resolve(catalog.toPrompt()),
2209
+ systemPrompt: () => Promise.resolve(`${catalog.toPrompt()}\n\n${NO_DUPLICATE_RENDER}`),
2171
2210
  listToolSpecs: () => Promise.resolve(presets.length > 0 ? [renderTool(), presetTool()] : [renderTool()]),
2172
2211
  canHandle: (name) => name === "render_ui" || presets.length > 0 && name === "describe_ui_preset",
2173
2212
  call: (name, args) => {
@@ -2452,7 +2491,7 @@ function fromA2uiSpecAction(event) {
2452
2491
  */
2453
2492
  async function loadWebSkillLitCatalog() {
2454
2493
  try {
2455
- const { webskillLitCatalog } = await import("./webskillLitCatalog-_mugzRHx-DiuJpCuf.js");
2494
+ const { webskillLitCatalog } = await import("./webskillLitCatalog-_mugzRHx-B_54vxum.js");
2456
2495
  return webskillLitCatalog();
2457
2496
  } catch (cause) {
2458
2497
  throw new WebSkillError("UI_UNAVAILABLE", "The WebSkill A2UI catalog is unavailable; install @a2ui/lit, @a2ui/web_core and lit to render catalog surfaces with A2UI", cause);