@icen.ai/ui 0.8.1 → 0.10.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 (335) hide show
  1. package/AGENTS.md +176 -75
  2. package/README.md +66 -88
  3. package/dist/base.css +208 -179
  4. package/dist/behaviors/accordion.mjs +8 -8
  5. package/dist/behaviors/ai-branch.d.mts +19 -0
  6. package/dist/behaviors/ai-branch.mjs +1133 -0
  7. package/dist/behaviors/ai-chat.d.mts +12 -10
  8. package/dist/behaviors/ai-chat.mjs +1125 -155
  9. package/dist/behaviors/ai-composer.d.mts +44 -12
  10. package/dist/behaviors/ai-composer.mjs +2084 -523
  11. package/dist/behaviors/ai-core.d.mts +1 -1
  12. package/dist/behaviors/ai-core.mjs +1016 -107
  13. package/dist/behaviors/ai-diff.mjs +1019 -127
  14. package/dist/behaviors/ai-feedback.d.mts +26 -0
  15. package/dist/behaviors/ai-feedback.mjs +1212 -0
  16. package/dist/behaviors/ai-panel.d.mts +21 -7
  17. package/dist/behaviors/ai-panel.mjs +1308 -264
  18. package/dist/behaviors/ai-provider.mjs +1003 -101
  19. package/dist/behaviors/ai-threads.d.mts +38 -0
  20. package/dist/behaviors/ai-threads.mjs +1233 -0
  21. package/dist/behaviors/ai-tool.d.mts +2 -2
  22. package/dist/behaviors/ai-tool.mjs +2042 -396
  23. package/dist/behaviors/ai-tools.d.mts +89 -16
  24. package/dist/behaviors/ai-tools.mjs +4453 -372
  25. package/dist/behaviors/autocomplete.d.mts +53 -0
  26. package/dist/behaviors/autocomplete.mjs +1600 -0
  27. package/dist/behaviors/back-top.d.mts +1 -1
  28. package/dist/behaviors/back-top.mjs +951 -14
  29. package/dist/behaviors/carousel.d.mts +1 -1
  30. package/dist/behaviors/carousel.mjs +906 -11
  31. package/dist/behaviors/cascader.d.mts +48 -0
  32. package/dist/behaviors/cascader.mjs +1853 -0
  33. package/dist/behaviors/charts.d.mts +174 -8
  34. package/dist/behaviors/charts.mjs +2632 -192
  35. package/dist/behaviors/code-block.d.mts +36 -0
  36. package/dist/behaviors/code-block.mjs +1611 -0
  37. package/dist/behaviors/command-palette.d.mts +9 -6
  38. package/dist/behaviors/command-palette.mjs +161 -59
  39. package/dist/behaviors/context-menu.d.mts +9 -8
  40. package/dist/behaviors/context-menu.mjs +1112 -44
  41. package/dist/behaviors/controls.d.mts +13 -13
  42. package/dist/behaviors/controls.mjs +989 -130
  43. package/dist/behaviors/copy.d.mts +21 -2
  44. package/dist/behaviors/copy.mjs +1206 -42
  45. package/dist/behaviors/datatable.d.mts +53 -3
  46. package/dist/behaviors/datatable.mjs +1963 -207
  47. package/dist/behaviors/date-picker.d.mts +0 -1
  48. package/dist/behaviors/date-picker.mjs +1340 -293
  49. package/dist/behaviors/design.d.mts +54 -0
  50. package/dist/behaviors/design.mjs +109 -0
  51. package/dist/behaviors/dropdown.d.mts +5 -6
  52. package/dist/behaviors/dropdown.mjs +262 -110
  53. package/dist/behaviors/events.d.mts +313 -3
  54. package/dist/behaviors/events.mjs +47 -2
  55. package/dist/behaviors/feedback.d.mts +30 -0
  56. package/dist/behaviors/feedback.mjs +296 -0
  57. package/dist/behaviors/focus.d.mts +8 -0
  58. package/dist/behaviors/focus.mjs +24 -0
  59. package/dist/behaviors/form-validate.d.mts +102 -0
  60. package/dist/behaviors/form-validate.mjs +6091 -0
  61. package/dist/behaviors/i18n.d.mts +789 -0
  62. package/dist/behaviors/i18n.mjs +1711 -0
  63. package/dist/behaviors/icons.d.mts +93 -0
  64. package/dist/behaviors/icons.mjs +113 -0
  65. package/dist/behaviors/input.d.mts +9 -1
  66. package/dist/behaviors/input.mjs +1056 -60
  67. package/dist/behaviors/kb-access.d.mts +34 -0
  68. package/dist/behaviors/kb-access.mjs +2459 -0
  69. package/dist/behaviors/kb-acl.d.mts +50 -0
  70. package/dist/behaviors/kb-acl.mjs +1345 -0
  71. package/dist/behaviors/kb-answer.d.mts +38 -0
  72. package/dist/behaviors/kb-answer.mjs +3707 -0
  73. package/dist/behaviors/kb-audit.d.mts +23 -0
  74. package/dist/behaviors/kb-audit.mjs +1297 -0
  75. package/dist/behaviors/kb-canvas.d.mts +44 -0
  76. package/dist/behaviors/kb-canvas.mjs +1512 -0
  77. package/dist/behaviors/kb-chain.d.mts +15 -0
  78. package/dist/behaviors/kb-chain.mjs +1192 -0
  79. package/dist/behaviors/kb-checkpoint.d.mts +16 -0
  80. package/dist/behaviors/kb-checkpoint.mjs +1492 -0
  81. package/dist/behaviors/kb-chunks.d.mts +31 -0
  82. package/dist/behaviors/kb-chunks.mjs +1414 -0
  83. package/dist/behaviors/kb-citation.d.mts +38 -0
  84. package/dist/behaviors/kb-citation.mjs +1699 -0
  85. package/dist/behaviors/kb-clarify.d.mts +20 -0
  86. package/dist/behaviors/kb-clarify.mjs +1176 -0
  87. package/dist/behaviors/kb-conflict.d.mts +22 -0
  88. package/dist/behaviors/kb-conflict.mjs +1206 -0
  89. package/dist/behaviors/kb-connector.d.mts +17 -0
  90. package/dist/behaviors/kb-connector.mjs +1303 -0
  91. package/dist/behaviors/kb-core.d.mts +534 -0
  92. package/dist/behaviors/kb-core.mjs +1805 -0
  93. package/dist/behaviors/kb-eval.d.mts +22 -0
  94. package/dist/behaviors/kb-eval.mjs +2235 -0
  95. package/dist/behaviors/kb-explain.d.mts +11 -0
  96. package/dist/behaviors/kb-explain.mjs +1165 -0
  97. package/dist/behaviors/kb-filter.d.mts +31 -0
  98. package/dist/behaviors/kb-filter.mjs +2417 -0
  99. package/dist/behaviors/kb-gap.d.mts +27 -0
  100. package/dist/behaviors/kb-gap.mjs +1195 -0
  101. package/dist/behaviors/kb-hittest.d.mts +34 -0
  102. package/dist/behaviors/kb-hittest.mjs +1352 -0
  103. package/dist/behaviors/kb-metadata.d.mts +29 -0
  104. package/dist/behaviors/kb-metadata.mjs +1248 -0
  105. package/dist/behaviors/kb-passage.d.mts +41 -0
  106. package/dist/behaviors/kb-passage.mjs +1469 -0
  107. package/dist/behaviors/kb-pipeline.d.mts +18 -0
  108. package/dist/behaviors/kb-pipeline.mjs +1301 -0
  109. package/dist/behaviors/kb-qa.d.mts +26 -0
  110. package/dist/behaviors/kb-qa.mjs +1260 -0
  111. package/dist/behaviors/kb-rerank.d.mts +20 -0
  112. package/dist/behaviors/kb-rerank.mjs +1248 -0
  113. package/dist/behaviors/kb-retrieval.d.mts +49 -0
  114. package/dist/behaviors/kb-retrieval.mjs +2585 -0
  115. package/dist/behaviors/kb-review.d.mts +44 -0
  116. package/dist/behaviors/kb-review.mjs +2282 -0
  117. package/dist/behaviors/kb-sandbox.d.mts +33 -0
  118. package/dist/behaviors/kb-sandbox.mjs +1247 -0
  119. package/dist/behaviors/kb-segment.d.mts +32 -0
  120. package/dist/behaviors/kb-segment.mjs +1431 -0
  121. package/dist/behaviors/kb-select.d.mts +24 -0
  122. package/dist/behaviors/kb-select.mjs +1989 -0
  123. package/dist/behaviors/kb-sources.d.mts +27 -0
  124. package/dist/behaviors/kb-sources.mjs +1287 -0
  125. package/dist/behaviors/kb-sql.d.mts +43 -0
  126. package/dist/behaviors/kb-sql.mjs +1865 -0
  127. package/dist/behaviors/kb-trace.d.mts +16 -0
  128. package/dist/behaviors/kb-trace.mjs +1328 -0
  129. package/dist/behaviors/kb-visibility.d.mts +44 -0
  130. package/dist/behaviors/kb-visibility.mjs +1331 -0
  131. package/dist/behaviors/kb-who-can.d.mts +32 -0
  132. package/dist/behaviors/kb-who-can.mjs +2216 -0
  133. package/dist/behaviors/mentions.d.mts +93 -0
  134. package/dist/behaviors/mentions.mjs +2152 -0
  135. package/dist/behaviors/modal.d.mts +4 -3
  136. package/dist/behaviors/modal.mjs +1055 -33
  137. package/dist/behaviors/nav.d.mts +1 -1
  138. package/dist/behaviors/nav.mjs +6 -6
  139. package/dist/behaviors/notification.d.mts +16 -8
  140. package/dist/behaviors/notification.mjs +1615 -265
  141. package/dist/behaviors/panel.d.mts +4 -0
  142. package/dist/behaviors/panel.mjs +994 -0
  143. package/dist/behaviors/popover.d.mts +28 -5
  144. package/dist/behaviors/popover.mjs +225 -24
  145. package/dist/behaviors/select.d.mts +5 -2
  146. package/dist/behaviors/select.mjs +1410 -117
  147. package/dist/behaviors/sidebar.d.mts +1 -1
  148. package/dist/behaviors/sidebar.mjs +13 -13
  149. package/dist/behaviors/slider.d.mts +1 -1
  150. package/dist/behaviors/slider.mjs +9 -9
  151. package/dist/behaviors/split-pane.d.mts +1 -1
  152. package/dist/behaviors/split-pane.mjs +7 -7
  153. package/dist/behaviors/suggestions.d.mts +27 -0
  154. package/dist/behaviors/suggestions.mjs +1089 -0
  155. package/dist/behaviors/svg-parse.d.mts +14 -0
  156. package/dist/behaviors/svg-parse.mjs +37 -0
  157. package/dist/behaviors/tabs.d.mts +2 -2
  158. package/dist/behaviors/tabs.mjs +25 -25
  159. package/dist/behaviors/tag-input.d.mts +23 -5
  160. package/dist/behaviors/tag-input.mjs +1359 -104
  161. package/dist/behaviors/theme-switcher.d.mts +24 -0
  162. package/dist/behaviors/theme-switcher.mjs +1981 -0
  163. package/dist/behaviors/theme.d.mts +15 -8
  164. package/dist/behaviors/theme.mjs +390 -28
  165. package/dist/behaviors/toast.d.mts +24 -25
  166. package/dist/behaviors/toast.mjs +1266 -88
  167. package/dist/behaviors/tooltip.d.mts +4 -0
  168. package/dist/behaviors/tooltip.mjs +378 -0
  169. package/dist/behaviors/tree-select.d.mts +69 -0
  170. package/dist/behaviors/tree-select.mjs +1907 -0
  171. package/dist/behaviors/tree.d.mts +1 -1
  172. package/dist/behaviors/tree.mjs +15 -15
  173. package/dist/behaviors/upload.d.mts +3 -2
  174. package/dist/behaviors/upload.mjs +1076 -66
  175. package/dist/cli.mjs +5 -6
  176. package/dist/components/ai-branch.mjs +3 -0
  177. package/dist/components/ai-chat.css +846 -458
  178. package/dist/components/ai-diff.css +153 -132
  179. package/dist/components/ai-feedback.mjs +3 -0
  180. package/dist/components/ai-panel.css +495 -270
  181. package/dist/components/ai-threads.mjs +3 -0
  182. package/dist/components/ai-tool.css +393 -238
  183. package/dist/components/autocomplete.css +61 -0
  184. package/dist/components/autocomplete.mjs +3 -0
  185. package/dist/components/back-top.css +34 -31
  186. package/dist/components/badge.css +44 -41
  187. package/dist/components/breadcrumb.css +67 -46
  188. package/dist/components/btn.css +80 -74
  189. package/dist/components/card.css +117 -106
  190. package/dist/components/cascader.css +311 -0
  191. package/dist/components/cascader.mjs +3 -0
  192. package/dist/components/chart-area.css +8 -2
  193. package/dist/components/chart-bar.css +95 -33
  194. package/dist/components/chart-gauge.css +14 -11
  195. package/dist/components/chart-graph.css +60 -0
  196. package/dist/components/chart-graph.mjs +4 -0
  197. package/dist/components/chart-heatmap.css +96 -90
  198. package/dist/components/chart-line.css +8 -3
  199. package/dist/components/chart-map.mjs +3 -0
  200. package/dist/components/chart-pie.css +9 -6
  201. package/dist/components/chart-radar.css +8 -5
  202. package/dist/components/chart-scatter.css +9 -6
  203. package/dist/components/chart-scatter.mjs +1 -1
  204. package/dist/components/chart-sparkline.css +5 -2
  205. package/dist/components/chart-stack.css +14 -11
  206. package/dist/components/charts.css +190 -67
  207. package/dist/components/charts.mjs +1 -0
  208. package/dist/components/code-block.css +418 -0
  209. package/dist/components/code-block.mjs +4 -0
  210. package/dist/components/command-palette.css +138 -117
  211. package/dist/components/content.css +257 -251
  212. package/dist/components/copy.css +72 -44
  213. package/dist/components/datatable.css +423 -181
  214. package/dist/components/date-picker.css +135 -104
  215. package/dist/components/empty.css +68 -65
  216. package/dist/components/feedback.css +201 -183
  217. package/dist/components/form-validate.css +120 -0
  218. package/dist/components/form-validate.mjs +3 -0
  219. package/dist/components/form.css +150 -127
  220. package/dist/components/icon.css +102 -0
  221. package/dist/components/icon.mjs +3 -0
  222. package/dist/components/input.css +159 -104
  223. package/dist/components/kb-access.mjs +4 -0
  224. package/dist/components/kb-acl.mjs +4 -0
  225. package/dist/components/kb-agent.css +496 -0
  226. package/dist/components/kb-answer.mjs +4 -0
  227. package/dist/components/kb-audit.mjs +4 -0
  228. package/dist/components/kb-canvas.mjs +4 -0
  229. package/dist/components/kb-chain.mjs +4 -0
  230. package/dist/components/kb-checkpoint.mjs +4 -0
  231. package/dist/components/kb-chunks.mjs +4 -0
  232. package/dist/components/kb-citation.mjs +4 -0
  233. package/dist/components/kb-clarify.mjs +4 -0
  234. package/dist/components/kb-conflict.mjs +4 -0
  235. package/dist/components/kb-connector.mjs +4 -0
  236. package/dist/components/kb-data.css +653 -0
  237. package/dist/components/kb-eval.mjs +4 -0
  238. package/dist/components/kb-explain.mjs +4 -0
  239. package/dist/components/kb-filter.mjs +4 -0
  240. package/dist/components/kb-gap.mjs +4 -0
  241. package/dist/components/kb-ground.css +578 -0
  242. package/dist/components/kb-hittest.mjs +4 -0
  243. package/dist/components/kb-ingest.css +882 -0
  244. package/dist/components/kb-metadata.mjs +4 -0
  245. package/dist/components/kb-ops.css +554 -0
  246. package/dist/components/kb-passage.mjs +4 -0
  247. package/dist/components/kb-perm.css +433 -0
  248. package/dist/components/kb-pipeline.mjs +4 -0
  249. package/dist/components/kb-qa.mjs +4 -0
  250. package/dist/components/kb-rerank.mjs +4 -0
  251. package/dist/components/kb-retrieval.mjs +4 -0
  252. package/dist/components/kb-review.mjs +4 -0
  253. package/dist/components/kb-sandbox.mjs +4 -0
  254. package/dist/components/kb-search.css +897 -0
  255. package/dist/components/kb-segment.mjs +4 -0
  256. package/dist/components/kb-sources.mjs +4 -0
  257. package/dist/components/kb-sql.mjs +4 -0
  258. package/dist/components/kb-trace.mjs +4 -0
  259. package/dist/components/kb-visibility.mjs +4 -0
  260. package/dist/components/kb-who-can.mjs +4 -0
  261. package/dist/components/kb.css +263 -0
  262. package/dist/components/kb.mjs +9 -0
  263. package/dist/components/layout.css +85 -82
  264. package/dist/components/material-chinese.css +73 -0
  265. package/dist/components/material-soviet.css +76 -0
  266. package/dist/components/material.css +275 -0
  267. package/dist/components/media.css +220 -166
  268. package/dist/components/mentions.css +189 -0
  269. package/dist/components/mentions.mjs +3 -0
  270. package/dist/components/menu.css +113 -105
  271. package/dist/components/modal.css +107 -112
  272. package/dist/components/nav.css +118 -115
  273. package/dist/components/notification.css +238 -174
  274. package/dist/components/pagination.css +56 -53
  275. package/dist/components/panel.css +66 -63
  276. package/dist/components/panel.mjs +1 -0
  277. package/dist/components/pill.css +81 -71
  278. package/dist/components/popover.css +67 -53
  279. package/dist/components/scroll-area.css +113 -110
  280. package/dist/components/segmented.css +146 -143
  281. package/dist/components/select.css +206 -186
  282. package/dist/components/sidebar.css +137 -127
  283. package/dist/components/slider.css +117 -114
  284. package/dist/components/split-pane.css +112 -109
  285. package/dist/components/stat.css +112 -106
  286. package/dist/components/steps.css +109 -103
  287. package/dist/components/switch.css +138 -134
  288. package/dist/components/table.css +131 -107
  289. package/dist/components/tabs.css +114 -108
  290. package/dist/components/tag-input.css +48 -133
  291. package/dist/components/tag.css +81 -71
  292. package/dist/components/theme-switcher.css +105 -0
  293. package/dist/components/theme-switcher.mjs +3 -0
  294. package/dist/components/toast.css +100 -86
  295. package/dist/components/toolbar.css +45 -42
  296. package/dist/components/tooltip.css +102 -43
  297. package/dist/components/tooltip.mjs +1 -0
  298. package/dist/components/tree-select.css +416 -0
  299. package/dist/components/tree-select.mjs +3 -0
  300. package/dist/components/upload.css +135 -92
  301. package/dist/fonts/LICENSES/ark-pixel/OFL.txt +96 -0
  302. package/dist/fonts/LICENSES/cubic-11/OFL.txt +108 -0
  303. package/dist/fonts/LICENSES/galmuri/LICENSE.txt +93 -0
  304. package/dist/fonts/OFL.txt +96 -0
  305. package/dist/fonts/README.md +14 -0
  306. package/dist/fonts/fusion-pixel-12px-zh-hans.woff2 +0 -0
  307. package/dist/index.d.mts +64 -15
  308. package/dist/index.mjs +28049 -8595
  309. package/dist/react.d.mts +91 -0
  310. package/dist/react.mjs +8208 -0
  311. package/dist/registry.json +454 -15
  312. package/dist/tokens/chinese.css +44 -0
  313. package/dist/tokens/colors.css +365 -1222
  314. package/dist/tokens/design.css +109 -0
  315. package/dist/tokens/dtcg.json +11198 -0
  316. package/dist/tokens/figma.variables.json +7017 -0
  317. package/dist/tokens/icon-masks.css +78 -0
  318. package/dist/tokens/pixel.css +50 -0
  319. package/dist/tokens/soviet.css +44 -0
  320. package/dist/tokens/style-profiles.css +36 -547
  321. package/dist/tokens/themes.json +308 -0
  322. package/dist/tokens/tokens-studio.json +6728 -0
  323. package/dist/tokens/typography.css +21 -18
  324. package/dist/tokens.css +1555 -1801
  325. package/dist/ui.css +16147 -8597
  326. package/dist/vue.d.mts +344 -0
  327. package/dist/vue.mjs +7781 -0
  328. package/docs/spec/ai-input-experience.md +75 -0
  329. package/docs/spec/ai-native.md +238 -147
  330. package/docs/spec/design-philosophy.md +189 -0
  331. package/docs/spec/design-primitives.md +196 -0
  332. package/docs/spec/kb-family.md +475 -0
  333. package/package.json +42 -7
  334. package/dist/retro-effects.css +0 -255
  335. package/dist/tokens/retro-effects.css +0 -255
@@ -1,3 +1,989 @@
1
+ // src/behaviors/icons.ts
2
+ var ICON_PATHS = {
3
+ file: "M6 2.5h5.5L16 7v9.5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1v-12a2 2 0 0 1 2-2ZM11.5 2.5V7H16",
4
+ folder: "M3 5a1.5 1.5 0 0 1 1.5-1.5H8l2 2h5.5A1.5 1.5 0 0 1 17 7v8a1.5 1.5 0 0 1-1.5 1.5h-11A1.5 1.5 0 0 1 3 15Z",
5
+ globe: "M17.5 10a7.5 7.5 0 1 1-15 0 7.5 7.5 0 0 1 15 0ZM2.5 10h15M10 2.5c-4 4-4 11 0 15 4-4 4-11 0-15Z",
6
+ document: "M6 2.5h5.5L16 7v9.5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1v-12a2 2 0 0 1 2-2ZM11.5 2.5V7H16M7 10.5h6M7 13.5h6",
7
+ agent: "M10 6V3M8 3h2M5 6h10a2 2 0 0 1 2 2v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2ZM1.5 10h1.5M17 10h1.5M7 10v2M13 10v2M8 14h4",
8
+ paperclip: "M14 7 8.3 12.7a1.6 1.6 0 0 1-2.3-2.3l6.3-6.3a3.2 3.2 0 0 1 4.5 4.5l-7 7a4.7 4.7 0 0 1-6.7-6.7l7-7",
9
+ stop: "M6.5 5h7A1.5 1.5 0 0 1 15 6.5v7a1.5 1.5 0 0 1-1.5 1.5h-7A1.5 1.5 0 0 1 5 13.5v-7A1.5 1.5 0 0 1 6.5 5Z",
10
+ terminal: "M5 3.5h10a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-9a2 2 0 0 1 2-2ZM6 7l3 3-3 3M11 13h3",
11
+ branch: "M6 6v8M14 6v2a4 4 0 0 1-4 4H6M8 4a2 2 0 1 1-4 0 2 2 0 0 1 4 0ZM8 16a2 2 0 1 1-4 0 2 2 0 0 1 4 0ZM16 4a2 2 0 1 1-4 0 2 2 0 0 1 4 0Z",
12
+ "line-numbers": "M3 5h2M3 10h2M3 15h2M8 5h9M8 10h9M8 15h9",
13
+ wrap: "M3 5h14M3 10h10a3 3 0 0 1 0 6h-3M12.5 13.5 10 16l2.5 2.5",
14
+ calendar: "M5.5 4h9A2.5 2.5 0 0 1 17 6.5v8a2.5 2.5 0 0 1-2.5 2.5h-9A2.5 2.5 0 0 1 3 14.5v-8A2.5 2.5 0 0 1 5.5 4ZM6.5 2.5v3M13.5 2.5v3M3 8h14M6.5 11h.1M10 11h.1M13.5 11h.1M6.5 14h.1M10 14h.1",
15
+ close: "M6 6l8 8M14 6l-8 8",
16
+ check: "M4.5 10.2l3.6 3.6 7.4-7.6",
17
+ "chevron-down": "M5.5 7.75 10 12.25l4.5-4.5",
18
+ "chevron-up": "M5.5 12.25 10 7.75l4.5 4.5",
19
+ "chevron-right": "M7.75 5.5 12.25 10l-4.5 4.5",
20
+ "chevron-left": "M12.25 5.5 7.75 10l4.5 4.5",
21
+ "arrow-right": "M3.5 10h13M11 4.5l5.5 5.5-5.5 5.5",
22
+ "arrow-left": "M16.5 10h-13M9 4.5 3.5 10 9 15.5",
23
+ "arrow-up": "M10 16.5v-13M4.5 9 10 3.5 15.5 9",
24
+ "arrow-down": "M10 3.5v13M4.5 11l5.5 5.5 5.5-5.5",
25
+ plus: "M10 4v12M4 10h12",
26
+ minus: "M4 10h12",
27
+ sort: "M6 15V4M3 7l3-3 3 3M14 5v11M11 13l3 3 3-3",
28
+ search: "M13.3 13.3 17 17M14.5 8.5a6 6 0 1 1-12 0 6 6 0 0 1 12 0",
29
+ sun: "M13.5 10a3.5 3.5 0 1 1-7 0 3.5 3.5 0 0 1 7 0M10 1.75v1.5M10 16.75v1.5M1.75 10h1.5M16.75 10h1.5M4.17 4.17l1.06 1.06M14.77 14.77l1.06 1.06M4.17 15.83l1.06-1.06M14.77 5.23l1.06-1.06",
30
+ moon: "M17.25 11.15A7.5 7.5 0 0 1 8.85 2.75a7.5 7.5 0 1 0 8.4 8.4Z",
31
+ modern: "M6.5 3h7A3.5 3.5 0 0 1 17 6.5v7a3.5 3.5 0 0 1-3.5 3.5h-7A3.5 3.5 0 0 1 3 13.5v-7A3.5 3.5 0 0 1 6.5 3ZM7 10l3-3 3 3-3 3Z",
32
+ pixel: "M3 3h5v5H3ZM12 3h5v5h-5ZM3 12h5v5H3ZM12 12h5v5h-5Z",
33
+ chinese: "M3 8c3 0 5-2 7-5 2 3 4 5 7 5M4 8h12M6 8v8m8-8v8M3 16h14M8 16v-5h4v5",
34
+ soviet: "M3 17h14M5 17V8h4v9m0-12h6v12M7 8V5h2m2 3h2m-2 3h2m-2 3h2M10 5V3h4v2",
35
+ more: "M4 9.9v.2M10 9.9v.2M16 9.9v.2",
36
+ copy: "M7 7h8a2 2 0 0 1 2 2v6a2 2 0 0 1-2 2H9a2 2 0 0 1-2-2V7ZM13 7V5a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2h2",
37
+ edit: "M11.5 4.5l4 4M4 12l9-9a1.4 1.4 0 0 1 2 0l2 2a1.4 1.4 0 0 1 0 2l-9 9-5 1Z",
38
+ link: "M8 6l2-2a4.2 4.2 0 0 1 6 6l-2 2M12 14l-2 2a4.2 4.2 0 0 1-6-6l2-2M7 13l6-6",
39
+ trash: "M3.5 5.5h13M7 5.5V3h6v2.5M5 5.5l.7 11.5h8.6L15 5.5M8 9v5M12 9v5",
40
+ spinner: "M10 3a7 7 0 1 1-7 7",
41
+ "circle-check": "M18 10a8 8 0 1 1-16 0 8 8 0 0 1 16 0ZM6 10l2.7 2.7 5.3-5.4",
42
+ "circle-error": "M18 10a8 8 0 1 1-16 0 8 8 0 0 1 16 0ZM7.2 7.2l5.6 5.6M12.8 7.2l-5.6 5.6",
43
+ "circle-info": "M18 10a8 8 0 1 1-16 0 8 8 0 0 1 16 0ZM10 9v5M10 6.1v.15",
44
+ "triangle-alert": "M8.7 3.5a1.5 1.5 0 0 1 2.6 0l6.4 11.3a1.5 1.5 0 0 1-1.3 2.2H3.6a1.5 1.5 0 0 1-1.3-2.2ZM10 7.2v4.4M10 14v.15",
45
+ refresh: "M16.5 7.2A7 7 0 0 0 4.3 5.9L2.5 8M2.5 3.5V8H7M3.5 12.8a7 7 0 0 0 12.2 1.3l1.8-2.1M13 12h4.5v4.5",
46
+ external: "M11.5 3H17v5.5M17 3l-8 8M8 3H5a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2v-3",
47
+ home: "M3.5 10.25 10 4l6.5 6.25M5.75 8.75v7a.75.75 0 0 0 .75.75h7.5a.75.75 0 0 0 .75-.75v-7",
48
+ settings: "M3.5 5.5h13M3.5 10h13M3.5 14.5h13M7 4v3M12.5 8.5v3M8 13v3",
49
+ star: "M10 2.5l2.4 5.1 5.6.4-4.2 3.7 1.3 5.5-5.1-3-5.1 3 1.3-5.5L1.8 8l5.6-.4Z",
50
+ eye: "M2.2 10s3-5.4 7.8-5.4S17.8 10 17.8 10s-3 5.4-7.8 5.4S2.2 10 2.2 10ZM10 12.4a2.4 2.4 0 1 0 0-4.8 2.4 2.4 0 0 0 0 4.8Z",
51
+ "eye-off": "M2.2 10s3-5.4 7.8-5.4S17.8 10 17.8 10s-3 5.4-7.8 5.4S2.2 10 2.2 10ZM10 12.4a2.4 2.4 0 1 0 0-4.8 2.4 2.4 0 0 0 0 4.8ZM3.5 3.5l13 13",
52
+ inbox: "M3.5 12.25h3.7l1.5 2.5h2.6l1.5-2.5h3.7M4.7 5.5l-1.2 6.75v3.25a1.5 1.5 0 0 0 1.5 1.5h10a1.5 1.5 0 0 0 1.5-1.5v-3.25L15.3 5.5a1.3 1.3 0 0 0-1.25-1H5.95a1.3 1.3 0 0 0-1.25 1Z",
53
+ bell: "M10 3.5a4.5 4.5 0 0 1 4.5 4.5c0 4.5 1.8 5.7 2.5 6.5H3c.7-.8 2.5-2 2.5-6.5A4.5 4.5 0 0 1 10 3.5ZM8.5 16.5a1.6 1.6 0 0 0 3 0",
54
+ users: "M13.8 16.5v-1.5a3.5 3.5 0 0 0-3.5-3.5H6.3a3.5 3.5 0 0 0-3.5 3.5v1.5M8.3 8.9a2.7 2.7 0 1 0 0-5.4 2.7 2.7 0 0 0 0 5.4ZM16.5 16.5v-1.3a3.3 3.3 0 0 0-2.3-3.1M12.3 3.7a2.7 2.7 0 0 1 0 5.2",
55
+ activity: "M17 10h-2.6l-2 5.8L8 4.2 6 10H3",
56
+ "trend-up": "M3.5 14.5l4.2-4.2 2.8 2.8 5.9-5.9M12.4 7.2h4.2v4.2",
57
+ "trend-down": "M3.5 5.5l4.2 4.2 2.8-2.8 5.9 5.9M12.4 12.8h4.2V8.6",
58
+ rocket: "M10 2.5c2 1.5 3.2 4 3.2 6.8 0 1.5-.3 2.9-.8 4.2H7.6c-.5-1.3-.8-2.7-.8-4.2 0-2.8 1.2-5.3 3.2-6.8ZM10 8.6a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3ZM7.6 12.5 5.6 15.4c-.9.3-1.6 1-2 2M12.4 12.5l2 2.9c.9.3 1.6 1 2 2M8.7 13.8c0 1.8.5 3.1 1.3 4.2.8-1.1 1.3-2.4 1.3-4.2",
59
+ bold: "M6.5 4h4.2a3 3 0 0 1 0 6H6.5M6.5 10h5a3 3 0 0 1 0 6H6.5M6.5 4v12",
60
+ italic: "M8.5 4.5h7M4.5 15.5h7M12.5 4.5l-5 11",
61
+ underline: "M6 4v5.5a4 4 0 0 0 8 0V4M4.5 16h11",
62
+ "align-left": "M3.5 4.5h13M3.5 10h8.5M3.5 15.5h11",
63
+ "align-center": "M3.5 4.5h13M5.75 10h8.5M4.5 15.5h11",
64
+ "align-right": "M3.5 4.5h13M8 10h8.5M5.5 15.5h11",
65
+ list: "M6.5 5h10M6.5 10h10M6.5 15h10M3.5 5h.01M3.5 10h.01M3.5 15h.01",
66
+ server: "M3 3h14a1.5 1.5 0 0 1 1.5 1.5v2A1.5 1.5 0 0 1 17 8H3a1.5 1.5 0 0 1-1.5-1.5v-2A1.5 1.5 0 0 1 3 3ZM3 12h14a1.5 1.5 0 0 1 1.5 1.5v2A1.5 1.5 0 0 1 17 17H3a1.5 1.5 0 0 1-1.5-1.5v-2A1.5 1.5 0 0 1 3 12ZM5 5.5h.01M5 14.5h.01",
67
+ sparkle: "M10 2.5l1.6 4.3 4.3 1.6-4.3 1.6L10 14.3l-1.6-4.3-4.3-1.6 4.3-1.6ZM15.5 12.5l.8 2.1 2.1.8-2.1.8-.8 2.1-.8-2.1-2.1-.8 2.1-.8Z",
68
+ play: "M6.5 4.8v10.4c0 .9 1 1.5 1.8 1l8.3-5.2a1.2 1.2 0 0 0 0-2L8.3 3.8a1.2 1.2 0 0 0-1.8 1Z",
69
+ "chart-line": "M3.5 3.5v13h13M6.5 12l2.8-2.8 2.2 2.2 4-4.4",
70
+ layers: "M10 3.2 3.6 6.5 10 9.8l6.4-3.3ZM4.5 10.4 10 13.2l5.5-2.8M4.5 13.6 10 16.4l5.5-2.8",
71
+ box: "M17 6 10 3.2 3 6v8l7 2.8 7-2.8ZM3 6l7 2.8L17 6M10 9v7.8",
72
+ filter: "M4 4.5h12l-4.4 5.1v5l-3.2-1.6V9.6Z",
73
+ columns: "M3.5 4h13v12h-13ZM8.2 4v12M12.8 4v12",
74
+ download: "M10 3.5v8M6.8 8.3 10 11.5l3.2-3.2M4 15v2.5a1.5 1.5 0 0 0 1.5 1.5h9a1.5 1.5 0 0 0 1.5-1.5V15"
75
+ };
76
+ var custom = /* @__PURE__ */ new Map();
77
+ var escape = (s) => s.replace(/[&<>"']/g, (c) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" })[c]);
78
+ function iconPath(name) {
79
+ return Object.hasOwn(ICON_PATHS, name) ? ICON_PATHS[name] : custom.get(name) ?? null;
80
+ }
81
+ function iconAttributes(o = {}) {
82
+ const size = Number.isFinite(o.size) && o.size > 0 ? o.size : 16;
83
+ return { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 20 20", width: String(size), height: String(size), fill: "none", stroke: "currentColor", "stroke-width": "1.6", "stroke-linecap": "round", "stroke-linejoin": "round", focusable: "false", class: ["icen-symbol", o.className].filter(Boolean).join(" "), ...o.label ? { role: "img", "aria-label": o.label } : { "aria-hidden": "true" } };
84
+ }
85
+ function iconHTML(name, o = {}) {
86
+ const path = iconPath(name);
87
+ if (!path) return "";
88
+ return `<svg${Object.entries(iconAttributes(o)).map(([k, v]) => ` ${k}="${escape(v)}"`).join("")}><path d="${escape(path)}"></path></svg>`;
89
+ }
90
+ function createIcon(name, o = {}) {
91
+ if (typeof document === "undefined") return null;
92
+ const path = iconPath(name);
93
+ if (!path) return null;
94
+ const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
95
+ for (const [key, value] of Object.entries(iconAttributes(o))) svg.setAttribute(key, value);
96
+ const line = document.createElementNS(svg.namespaceURI, "path");
97
+ line.setAttribute("d", path);
98
+ svg.append(line);
99
+ return svg;
100
+ }
101
+
102
+ // src/behaviors/events.ts
103
+ function emitIcen(source, type, detail) {
104
+ return source.dispatchEvent(
105
+ new CustomEvent(type, { detail, bubbles: true, composed: true, cancelable: true })
106
+ );
107
+ }
108
+
109
+ // src/behaviors/i18n.ts
110
+ var ICEN_LOCALE_ZH_CN = {
111
+ /* ── aiBranch ── */
112
+ "aiBranch.nextVersion": "\u4E0B\u4E00\u7248\u672C",
113
+ "aiBranch.prevVersion": "\u4E0A\u4E00\u7248\u672C",
114
+ "aiBranch.version": "\u5206\u652F\u7248\u672C",
115
+ /* ── aiChat ── */
116
+ "aiChat.backToBottom": "\u56DE\u5230\u5E95\u90E8",
117
+ "aiChat.backToBottomCount": "\u56DE\u5230\u5E95\u90E8 \xB7 {p0} \u6761\u65B0\u6D88\u606F",
118
+ "aiChat.continue": "\u7EE7\u7EED\u751F\u6210",
119
+ "aiChat.download": "\u4E0B\u8F7D",
120
+ "aiChat.file": "\u6587\u4EF6",
121
+ "aiChat.roleSystem": "\u7CFB",
122
+ "aiChat.roleTool": "\u5DE5",
123
+ "aiChat.roleUser": "\u6211",
124
+ "aiChat.thinking": "\u601D\u8003 {p0}",
125
+ /* ── aiComposer ── */
126
+ "aiComposer.attachAgent": "\u4EE3\u7406",
127
+ "aiComposer.library": "\u6DFB\u52A0\u4E0A\u4E0B\u6587\u4E0E\u547D\u4EE4",
128
+ "aiComposer.searchLibrary": "\u641C\u7D22\u6280\u80FD\u3001\u5DE5\u5177\u3001\u6587\u4EF6\u4E0E\u547D\u4EE4",
129
+ "aiComposer.all": "\u5168\u90E8",
130
+ "aiComposer.skills": "\u6280\u80FD",
131
+ "aiComposer.tools": "\u5DE5\u5177",
132
+ "aiComposer.libraryHint": "\u4E0A\u4E0B\u6587\u968F\u6D88\u606F\u53D1\u9001 \xB7 \u547D\u4EE4\u5148\u586B\u5165\u8F93\u5165\u6846",
133
+ "aiComposer.commandHint": "\u2191 \u2193 \u6D4F\u89C8 \xB7 Enter \u6267\u884C \xB7 Esc \u8FD4\u56DE",
134
+ "aiComposer.refHint": "\u2191 \u2193 \u6D4F\u89C8 \xB7 Enter \u5F15\u7528 \xB7 Esc \u8FD4\u56DE",
135
+ "aiComposer.noLibraryMatch": "\u6CA1\u6709\u5339\u914D\u7684\u9879\u76EE\uFF0C\u8BD5\u8BD5\u5176\u4ED6\u5173\u952E\u8BCD",
136
+ "aiComposer.filesNeedAdapter": "\u9644\u4EF6\u5C1A\u672A\u63A5\u901A\u4E0A\u4F20\u3002\u8BF7\u914D\u7F6E prepareMessage \u540E\u91CD\u8BD5\uFF0C\u6587\u4EF6\u4ECD\u4FDD\u7559\u5728\u6B64\u8BF7\u6C42\u4E2D\u3002",
137
+ "aiComposer.attachDoc": "\u6587\u6863",
138
+ "aiComposer.attachFile": "\u6587\u4EF6",
139
+ "aiComposer.attachFolder": "\u6587\u4EF6\u5939",
140
+ "aiComposer.cacheInvalidHint": "\u5207\u6362\u6A21\u578B\u4F1A\u4F7F prompt \u7F13\u5B58\u5931\u6548",
141
+ "aiComposer.commands": "\u547D\u4EE4",
142
+ "aiComposer.currentTodos": "\u5F53\u524D\u5F85\u529E",
143
+ "aiComposer.done": "\u5B8C\u6210",
144
+ "aiComposer.justNow": "\u521A\u521A \xB7 {p0}",
145
+ "aiComposer.modelAria": "\u6A21\u578B {p0}\uFF08{p1}\uFF09",
146
+ "aiComposer.noCommandMatch": "\u65E0\u5339\u914D\u547D\u4EE4",
147
+ "aiComposer.noModelMatch": "\u65E0\u5339\u914D\u6A21\u578B",
148
+ "aiComposer.noRefMatch": "\u65E0\u5339\u914D\u5F15\u7528",
149
+ "aiComposer.placeholder": "\u8F93\u5165\u6D88\u606F\uFF0C/ \u547D\u4EE4 \xB7 @ \u5F15\u7528 \xB7 Enter \u53D1\u9001",
150
+ "aiComposer.refs": "\u5F15\u7528",
151
+ "aiComposer.removeAttachment": "\u79FB\u9664\u9644\u4EF6 {p0}",
152
+ "aiComposer.removeQueued": "\u79FB\u9664\u6392\u961F\u6D88\u606F {p0}",
153
+ "aiComposer.removeRef": "\u79FB\u9664\u5F15\u7528 {p0}",
154
+ "aiComposer.searchModels": "\u641C\u7D22\u6A21\u578B",
155
+ "aiComposer.selectModel": "\u9009\u62E9\u6A21\u578B",
156
+ "aiComposer.send": "\u53D1\u9001",
157
+ "aiComposer.stop": "\u505C\u6B62\u751F\u6210",
158
+ "aiComposer.stopped": "\u5DF2\u505C\u6B62",
159
+ "aiComposer.todoChip": "\u5F53\u524D\u5F85\u529E {p0}/{p1}{p2}",
160
+ "aiComposer.todoHasError": "\uFF08\u6709\u5931\u8D25\u9879\uFF09",
161
+ /* ── aiCore ── */
162
+ "aiCore.kindBrowser": "\u6D4F\u89C8",
163
+ "aiCore.kindChart": "\u56FE\u8868",
164
+ "aiCore.kindDelete": "\u5220\u9664",
165
+ "aiCore.kindEdit": "\u7F16\u8F91",
166
+ "aiCore.kindFetch": "\u8BF7\u6C42",
167
+ "aiCore.kindGlob": "\u5339\u914D",
168
+ "aiCore.kindGrep": "\u641C\u7D22",
169
+ "aiCore.kindNote": "\u7B14\u8BB0",
170
+ "aiCore.kindPlan": "\u8BA1\u5212",
171
+ "aiCore.kindRead": "\u8BFB\u53D6",
172
+ "aiCore.kindSearch": "\u68C0\u7D22",
173
+ "aiCore.kindShell": "\u547D\u4EE4",
174
+ "aiCore.kindSkill": "\u6280\u80FD",
175
+ "aiCore.kindSubagent": "\u5B50\u4EE3\u7406",
176
+ "aiCore.kindTodo": "\u5F85\u529E",
177
+ "aiCore.kindWrite": "\u5199\u5165",
178
+ "aiCore.statusApproval": "\u5F85\u786E\u8BA4",
179
+ "aiCore.statusCancelled": "\u5DF2\u53D6\u6D88",
180
+ "aiCore.statusDone": "\u5B8C\u6210",
181
+ "aiCore.statusError": "\u5931\u8D25",
182
+ "aiCore.statusPending": "\u7B49\u5F85",
183
+ "aiCore.statusRunning": "\u6267\u884C\u4E2D",
184
+ "aiCore.statusStreaming": "\u6D41\u5F0F\u4E2D",
185
+ "aiCore.todoProgress": "{p0}/{p1} \u5B8C\u6210",
186
+ /* ── aiDiff ── */
187
+ "aiDiff.accepted": "\u5DF2\u63A5\u53D7",
188
+ "aiDiff.binary": "\u4E8C\u8FDB\u5236\u6587\u4EF6\uFF0C\u65E0\u6CD5\u663E\u793A\u6587\u672C\u5DEE\u5F02",
189
+ "aiDiff.empty": "\u65E0\u5DEE\u5F02\u5185\u5BB9",
190
+ "aiDiff.rejected": "\u5DF2\u62D2\u7EDD",
191
+ /* ── aiFeedback ── */
192
+ "aiFeedback.helpful": "\u6709\u5E2E\u52A9",
193
+ "aiFeedback.notHelpful": "\u65E0\u5E2E\u52A9",
194
+ "aiFeedback.reasonCitationMismatch": "\u5F15\u7528\u4E0D\u7B26",
195
+ "aiFeedback.reasonOutdated": "\u5185\u5BB9\u8FC7\u65F6",
196
+ "aiFeedback.reasonUnauthorized": "\u8D8A\u6743\u4FE1\u606F",
197
+ "aiFeedback.reasonUnsourced": "\u65E0\u5F15\u7528\u4F9D\u636E",
198
+ "aiFeedback.reasonWrong": "\u7B54\u6848\u6709\u8BEF",
199
+ "aiFeedback.thanks": "\u611F\u8C22\u53CD\u9988\uFF0C\u5DF2\u5173\u8054\u5230\u8BE5\u6761\u56DE\u7B54\u7684\u8FFD\u8E2A\u8BB0\u5F55",
200
+ /* ── aiPanel ── */
201
+ "aiPanel.audit": "\u5BA1\u8BA1",
202
+ "aiPanel.cacheRead": "\u7F13\u5B58\u8BFB",
203
+ "aiPanel.cacheWrite": "\u7F13\u5B58\u5199",
204
+ "aiPanel.callsTokens": "{p0} \u6B21 \xB7 {p1} tok{p2}",
205
+ "aiPanel.clearAudit": "\u6E05\u9664\u5BA1\u8BA1",
206
+ "aiPanel.context": "\u4E0A\u4E0B\u6587",
207
+ "aiPanel.contextWindow": "\u4E0A\u4E0B\u6587\u7A97\u53E3",
208
+ "aiPanel.errorsCount": "{p0} \u5931\u8D25",
209
+ "aiPanel.files": "\u6587\u4EF6 ({p0})",
210
+ "aiPanel.itemStatus": "{p0}\uFF0C\u72B6\u6001\uFF1A{p1}",
211
+ "aiPanel.noAudit": "\u6682\u65E0\u5BA1\u8BA1\u8BB0\u5F55",
212
+ "aiPanel.noUsage": "\u6682\u65E0\u7528\u91CF",
213
+ "aiPanel.reasoning": "\u63A8\u7406",
214
+ "aiPanel.requestsCount": "{p0} \u6B21\u8BF7\u6C42",
215
+ "aiPanel.ringPercent": "\u4E0A\u4E0B\u6587\u7A97\u53E3\u5360\u7528 {p0}%\uFF0C\u70B9\u51FB\u67E5\u770B\u8BE6\u60C5",
216
+ "aiPanel.ringUsed": "\u5DF2\u7528 {p0}\uFF0C\u70B9\u51FB\u67E5\u770B\u8BE6\u60C5",
217
+ "aiPanel.taskProgress": "\u4EFB\u52A1\u8FDB\u5EA6",
218
+ "aiPanel.toolsCount": "{p0} \u5DE5\u5177",
219
+ "aiPanel.usage": "\u7528\u91CF",
220
+ "aiPanel.usageAria": "\u7528\u91CF\uFF1A{p0}",
221
+ /* ── aiProvider ── */
222
+ "aiProvider.audioUrlOnly": "\u4EC5 URL \u7684\u97F3\u9891\uFF08input_audio \u9700 base64\uFF0C\u8BF7\u5148\u53D6\u56DE\u5185\u8054\uFF09",
223
+ "aiProvider.audioUrlOnlyAnthropic": "\u4EC5 URL \u7684\u97F3\u9891\uFF08audio \u5757\u9700 base64 source\uFF09",
224
+ "aiProvider.base64File": "base64 \u6587\u4EF6\uFF08file \u90E8\u4EF6\u9700 Files API file_id\uFF0C\u8BF7\u7F6E\u4E8E url \u69FD\uFF09",
225
+ "aiProvider.corsHint": "\uFF1B\u6D4F\u89C8\u5668\u76F4\u8FDE {p0}\uFF08{p1}\uFF09\u5F88\u53EF\u80FD\u88AB CORS \u62E6\u622A\uFF0C\u5EFA\u8BAE\u7ECF\u4EE3\u7406/\u81EA\u5EFA\u7F51\u5173\u8F6C\u53D1",
226
+ "aiProvider.emptyResponse": "\u54CD\u5E94\u4E3A\u7A7A",
227
+ "aiProvider.glmLabel": "GLM\uFF08\u667A\u8C31\uFF09",
228
+ "aiProvider.invalidJson": "\u54CD\u5E94\u4E0D\u662F\u5408\u6CD5 JSON",
229
+ "aiProvider.kimiLabel": "Kimi\uFF08\u6708\u4E4B\u6697\u9762\uFF09",
230
+ "aiProvider.networkFailed": "\u7F51\u7EDC\u8BF7\u6C42\u5931\u8D25\uFF1A{p0}{p1}",
231
+ "aiProvider.nonPdfDocument": "\u975E PDF \u6587\u4EF6\u5757\uFF08document \u5757\u4E3A application/pdf\uFF0C\u6536\u5230 {p0}\uFF09",
232
+ "aiProvider.requestCancelled": "\u8BF7\u6C42\u5DF2\u53D6\u6D88",
233
+ "aiProvider.resourceRef": "[\u8D44\u6E90] {p0} ({p1})",
234
+ "aiProvider.streamError": "\u6D41\u5F0F\u54CD\u5E94\u9519\u8BEF",
235
+ "aiProvider.toolRoleNoCallId": "role 'tool' \u4E14\u7F3A toolCallId\uFF08openai \u65CF\u9700 tool_call_id\uFF09",
236
+ "aiProvider.toolRoleNoUseId": "role 'tool' \u4E14\u7F3A toolCallId\uFF08anthropic \u65CF\u6620\u5C04 tool_result \u9700 tool_use_id\uFF09",
237
+ "aiProvider.unsupported": "{p0} \u7EBF\u534F\u8BAE\u4E0D\u652F\u6301 {p1}",
238
+ "aiProvider.videoUnsupported": "video \u8F93\u5165\uFF08\u65E0\u4E3B\u6D41 chat API \u652F\u6301\uFF09",
239
+ "aiProvider.videoUnsupportedAnthropic": "video \u8F93\u5165",
240
+ /* ── aiThreads ── */
241
+ "aiThreads.actionsAria": "\u4F1A\u8BDD\u64CD\u4F5C",
242
+ "aiThreads.archived": "\u5DF2\u5F52\u6863",
243
+ /* ── aiTool ── */
244
+ "aiTool.allow": "\u5141\u8BB8",
245
+ "aiTool.reject": "\u62D2\u7EDD",
246
+ /* ── aiTools ── */
247
+ "aiTools.chart.area": "line \u591A\u7CFB\u5217\u586B\u5145\u9762\u79EF",
248
+ "aiTools.chart.data": "\u4EFB\u610F\u7EF4\u5EA6\u539F\u59CB\u8BB0\u5F55 + dims \u5B57\u6BB5\u6620\u5C04\uFF08\u81EA\u52A8\u900F\u89C6\u6210 \u7C7B\u76EE \xD7 \u7CFB\u5217\uFF09",
249
+ "aiTools.chart.dates": "\u8D21\u732E\u65E5\u5386 ISO \u65E5\u671F\uFF08\u4E0E values \u914D\u5BF9\uFF09",
250
+ "aiTools.chart.description": "\u5728\u7528\u6237\u754C\u9762\u6E32\u67D3\u4E00\u5F20\u56FE\u8868\u53EF\u89C6\u5316\u3002\u8F93\u5165\u4E00\u4EFD\u56FE\u8868\u89C4\u683C\uFF08\u7EAF JSON\uFF09\uFF1Alabels+values\uFF08\u7C7B\u76EE\u6570\u503C\uFF09\u3001series\uFF08\u591A\u7CFB\u5217\uFF09\u3001segments\uFF08\u5360\u6BD4\uFF09\u3001points\uFF08\u6563\u70B9\u6C14\u6CE1\uFF09\u3001dates\uFF08\u8D21\u732E\u65E5\u5386\uFF09\u4EFB\u7ED9\u5176\u4E00\uFF1Btype \u7F3A\u7701\u65F6\u6309\u6570\u636E\u5F62\u6001\u81EA\u52A8\u9009\u578B\uFF08\u65F6\u95F4\u5E8F\u5217\u2192\u6298\u7EBF\u3001\u5360\u6BD4\u2192\u73AF\u5F62\u3001\u65E5\u671F\u2192\u8D21\u732E\u65E5\u5386\u3001\u5750\u6807\u70B9\u2192\u6563\u70B9\uFF09\u3002\u56FE\u8868\u5E26\u4EA4\u4E92\uFF08\u60AC\u505C\u63D0\u793A/\u70B9\u51FB/\u53F3\u952E\uFF09\u4E0E\u53EF\u9690\u85CF\u56FE\u4F8B\u3002",
251
+ "aiTools.chart.dims": "data[] \u7684\u5B57\u6BB5\u6620\u5C04\uFF1A{label?, series?, value?, x?, y?}",
252
+ "aiTools.chart.format": "\u6570\u503C\u683C\u5F0F\u5316\uFF1A{notation?: compact|percent|ms, unit?}",
253
+ "aiTools.chart.labels": "\u7C7B\u76EE\u8F74\uFF08line/vbar/hbar\uFF09",
254
+ "aiTools.chart.legend": "false = \u521D\u59CB\u9690\u85CF\u56FE\u4F8B",
255
+ "aiTools.chart.lttb": "\u5927\u6570\u636E\u91CF\u964D\u91C7\u6837\uFF1Atrue=\u81EA\u52A8\u4E0A\u9650\uFF0C\u6570\u5B57=\u6700\u5927\u4FDD\u7559\u70B9\u6570\uFF08\u6E32\u67D3\u5C42\u5951\u7EA6\uFF0C\u968F\u56FE\u8868\u91CD\u5EA6\u573A\u666F\u843D\u5730\uFF09",
256
+ "aiTools.chart.marks": "\u6807\u8BB0\u5C42\uFF08\u9608\u503C\u7EBF/\u53C2\u8003\u533A\u95F4/\u5F3A\u8C03\u70B9\uFF09\uFF0C\u5143\u7D20\u4E3A\u7EAF JSON \u63CF\u8FF0\u5B50\uFF08\u6E32\u67D3\u5C42\u5951\u7EA6\uFF0C\u968F\u56FE\u8868\u91CD\u5EA6\u573A\u666F\u843D\u5730\uFF09",
257
+ "aiTools.chart.points": "\u6563\u70B9/\u6C14\u6CE1\uFF1A[{x,y,size?,label?}]",
258
+ "aiTools.chart.radarAxes": "\u96F7\u8FBE\u8F74\u540D",
259
+ "aiTools.chart.segments": "\u5360\u6BD4\u578B\uFF08donut/stack\uFF09\uFF1A[{label,value}]",
260
+ "aiTools.chart.series": "\u591A\u7CFB\u5217\uFF08line/vbar/radar\uFF09",
261
+ "aiTools.chart.stacked": "vbar \u591A\u7CFB\u5217\u5806\u53E0\uFF08\u9ED8\u8BA4\u5206\u7EC4\uFF09",
262
+ "aiTools.chart.title": "\u56FE\u8868\u6807\u9898\uFF08\u6E32\u67D3\u5728\u5934\u90E8\u884C\u5DE6\u4FA7\uFF09",
263
+ "aiTools.chart.tooltip": "false = \u5173\u95ED\u5185\u7F6E\u63D0\u793A",
264
+ "aiTools.chart.type": "\u56FE\u8868\u7C7B\u578B\uFF0C\u7F3A\u7701\u81EA\u52A8\u63A8\u65AD",
265
+ "aiTools.chart.values": "\u5355\u7CFB\u5217\u6570\u503C\uFF08\u4E0E labels \u914D\u5BF9\uFF09",
266
+ "aiTools.chart.zoom": "\u7F29\u653E\u4EA4\u4E92\uFF1A'x'=\u7C7B\u76EE\u8F74\u533A\u95F4\u7F29\u653E\uFF0C'brush'=\u5237\u9009\u7F29\u653E",
267
+ "aiTools.datatable.columns": "\u5217\u5B9A\u4E49\u6570\u7EC4\uFF1A\u6BCF\u9879 { key, title, sortable?, filterable? }\uFF08key \u5BF9\u5E94 rows \u5143\u7D20\u5B57\u6BB5\u540D\uFF09",
268
+ "aiTools.datatable.description": "\u5728\u7528\u6237\u754C\u9762\u6E32\u67D3\u4E00\u4E2A\u53EF\u641C\u7D22\u3001\u5206\u9875\u3001\u53EF\u5BFC\u51FA CSV \u7684\u6570\u636E\u8868\u683C\u3002\u8F93\u5165\u7EAF JSON\uFF1Acolumns \u4E3A\u5217\u5B9A\u4E49\uFF08key/title \u5FC5\u586B\uFF09\uFF0Crows \u4E3A\u884C\u5BF9\u8C61\u6570\u7EC4\uFF08\u5B57\u6BB5\u540D\u5BF9\u9F50\u5217 key\uFF09\u3002\u8FD4\u56DE { title, rows: \u884C\u6570 } \u6458\u8981\u3002",
269
+ "aiTools.datatable.rows": "\u884C\u6570\u636E\u6570\u7EC4\uFF1A\u6BCF\u9879\u4E3A\u4E00\u4E2A\u5BF9\u8C61\uFF0C\u5B57\u6BB5\u540D\u5BF9\u9F50 columns[].key",
270
+ "aiTools.datatable.title": "\u8868\u683C\u6807\u9898\uFF08\u6E32\u67D3\u5728\u5DE5\u5177\u680F\u5DE6\u4FA7\uFF09",
271
+ "aiTools.execFailed": "\u5DE5\u5177\u6267\u884C\u5931\u8D25\uFF1A{p0}",
272
+ "aiTools.execTimeout": "\u6267\u884C\u8D85\u65F6\uFF08{p0}ms\uFF09",
273
+ "aiTools.manifestHeader": "\u53EF\u7528 UI \u5DE5\u5177\uFF08\u8C03\u7528\u540E\u5728\u7528\u6237\u754C\u9762\u6302\u8F7D\u53EF\u89C6\u5316\u7ED3\u679C\uFF09\uFF1A",
274
+ "aiTools.missingRequired": "\u7F3A\u5C11\u5FC5\u586B\u5B57\u6BB5",
275
+ "aiTools.none": "\uFF08\u65E0\u5DF2\u6CE8\u518C\u7684 UI \u5DE5\u5177\uFF09",
276
+ "aiTools.notInEnum": "\u4E0D\u5728\u5141\u8BB8\u53D6\u503C\u5185\uFF08{p0}\uFF09",
277
+ "aiTools.numMax": "\u6570\u503C {p0} \u5927\u4E8E\u6700\u5927\u503C {p1}",
278
+ "aiTools.numMin": "\u6570\u503C {p0} \u5C0F\u4E8E\u6700\u5C0F\u503C {p1}",
279
+ "aiTools.removeMount": "\u79FB\u9664 {p0} \u6302\u8F7D",
280
+ "aiTools.strMax": "\u957F\u5EA6 {p0} \u8D85\u8FC7\u4E0A\u9650 {p1}",
281
+ "aiTools.strMin": "\u957F\u5EA6 {p0} \u5C0F\u4E8E\u4E0B\u9650 {p1}",
282
+ "aiTools.typeMismatch": "\u671F\u671B {p0}\uFF0C\u5B9E\u5F97 {p1}",
283
+ "aiTools.validationFailed": "\u53C2\u6570\u6821\u9A8C\u5931\u8D25\uFF08{p0} \u9879\uFF09",
284
+ /* ── autocomplete ── */
285
+ "suggestions.loading": "\u6B63\u5728\u67E5\u627E\u5EFA\u8BAE\u2026",
286
+ "suggestions.error": "\u6682\u65F6\u65E0\u6CD5\u52A0\u8F7D\u5EFA\u8BAE\uFF0C\u8BF7\u91CD\u8BD5\u3002",
287
+ "suggestions.options": "\u5EFA\u8BAE",
288
+ "suggestions.empty": "\u6CA1\u6709\u5339\u914D\u7684\u5EFA\u8BAE",
289
+ "autocomplete.empty": "\u65E0\u5339\u914D\u7ED3\u679C",
290
+ /* ── backTop ── */
291
+ "backTop.label": "\u56DE\u5230\u9876\u90E8",
292
+ /* ── carousel ── */
293
+ "carousel.item": "\u7B2C {p0} \u5F20",
294
+ "carousel.region": "\u8F6E\u64AD",
295
+ "carousel.slide": "\u5E7B\u706F\u7247",
296
+ "carousel.status": "\u7B2C {p0} / {p1} \u5F20",
297
+ /* ── charts ── */
298
+ "charts.calendarWeekdays": ["\u4E00", "", "\u4E09", "", "\u4E94", "", "\u65E5"],
299
+ "charts.few": "\u5C11",
300
+ "charts.hideLegend": "\u9690\u85CF\u56FE\u4F8B",
301
+ "charts.loading": "\u52A0\u8F7D\u4E2D",
302
+ "charts.many": "\u591A",
303
+ "charts.monthLabel": "{p0}\u6708",
304
+ "charts.noData": "\u6682\u65E0\u6570\u636E",
305
+ "charts.resetZoom": "\u91CD\u7F6E\u7F29\u653E",
306
+ "charts.sampled": "\u5DF2\u62BD\u6837 {p0}\u2192{p1} \u70B9",
307
+ "charts.type.area": "\u9762\u79EF\u56FE",
308
+ "charts.type.donut": "\u73AF\u5F62\u56FE",
309
+ "charts.type.gauge": "\u4EEA\u8868\u76D8",
310
+ "charts.type.graph": "\u77E5\u8BC6\u56FE\u8C31",
311
+ "charts.type.heatmap": "\u70ED\u529B\u56FE",
312
+ "charts.type.line": "\u6298\u7EBF\u56FE",
313
+ "charts.type.map": "\u5730\u56FE",
314
+ "charts.type.radar": "\u96F7\u8FBE\u56FE",
315
+ "charts.type.scatter": "\u6563\u70B9\u56FE",
316
+ "charts.type.sparkline": "\u8FF7\u4F60\u8D8B\u52BF",
317
+ "charts.seriesName": "\u7CFB\u5217{p0}",
318
+ "charts.showLegend": "\u663E\u793A\u56FE\u4F8B",
319
+ "charts.value": "\u6570\u503C",
320
+ /* ── themeSwitcher ── */
321
+ "themeSwitcher.appearance": "\u5916\u89C2",
322
+ "themeSwitcher.theme": "\u4E3B\u9898",
323
+ "themeSwitcher.primitive": "\u539F\u8BED",
324
+ "themeSwitcher.mode": "\u660E\u6697",
325
+ "themeSwitcher.light": "\u6D45\u8272",
326
+ "themeSwitcher.dark": "\u6DF1\u8272",
327
+ "themeSwitcher.modern": "\u73B0\u4EE3",
328
+ "themeSwitcher.dongyun": "\u4E1C\u97F5",
329
+ "themeSwitcher.jugou": "\u5DE8\u6784",
330
+ "themeSwitcher.piano": "\u94A2\u7434",
331
+ "themeSwitcher.monet": "\u83AB\u5948",
332
+ "themeSwitcher.vangogh": "\u68B5\u9AD8",
333
+ "themeSwitcher.chinese": "\u4E2D\u5F0F",
334
+ "themeSwitcher.soviet": "\u82CF\u5F0F",
335
+ "themeSwitcher.pixel": "\u50CF\u7D20",
336
+ /* ── codeBlock ── */
337
+ "codeBlock.collapse": "\u6536\u8D77",
338
+ "codeBlock.region": "\u4EE3\u7801\u5185\u5BB9",
339
+ "codeBlock.copyFailed": "\u672A\u80FD\u590D\u5236\uFF0C\u8BF7\u91CD\u8BD5\u3002",
340
+ "codeBlock.copyRetry": "\u91CD\u8BD5\u590D\u5236",
341
+ "codeBlock.copy": "\u590D\u5236",
342
+ "codeBlock.foldCollapse": "\u6298\u53E0\u4EE3\u7801",
343
+ "codeBlock.foldExpand": "\u5C55\u5F00\u4EE3\u7801",
344
+ "codeBlock.linesTotal": "\u5171 {p0} \u884C",
345
+ "codeBlock.numHide": "\u9690\u85CF\u884C\u53F7",
346
+ "codeBlock.numShow": "\u663E\u793A\u884C\u53F7",
347
+ "codeBlock.tailAria": "\u5C55\u5F00\u6216\u6536\u8D77\u4EE3\u7801",
348
+ "codeBlock.wrapOff": "\u5173\u95ED\u6362\u884C",
349
+ "codeBlock.wrapOn": "\u81EA\u52A8\u6362\u884C",
350
+ /* ── common ── */
351
+ "common.accept": "\u63A5\u53D7",
352
+ "common.add": "\u65B0\u589E",
353
+ "common.all": "\u5168\u90E8",
354
+ "common.approve": "\u6279\u51C6",
355
+ "common.cancel": "\u53D6\u6D88",
356
+ "common.actionFailed": "\u64CD\u4F5C\u672A\u5B8C\u6210\uFF0C\u8BF7\u91CD\u8BD5\u3002",
357
+ "common.close": "\u5173\u95ED",
358
+ "common.confirm": "\u786E\u8BA4",
359
+ "common.copied": "\u5DF2\u590D\u5236",
360
+ "common.copy": "\u590D\u5236",
361
+ "common.delete": "\u5220\u9664",
362
+ "common.enable": "\u542F\u7528",
363
+ "common.exportCsv": "\u5BFC\u51FA CSV",
364
+ "common.healthy": "\u6B63\u5E38",
365
+ "common.input": "\u8F93\u5165",
366
+ "common.loadingEllipsis": "\u52A0\u8F7D\u4E2D\u2026",
367
+ "common.official": "\u5B98\u65B9",
368
+ "common.output": "\u8F93\u51FA",
369
+ "common.page": "\u7B2C {p0} \u9875",
370
+ "common.reject": "\u62D2\u7EDD",
371
+ "common.remove": "\u79FB\u9664",
372
+ "common.requestAccess": "\u7533\u8BF7\u8BBF\u95EE",
373
+ "common.requestAccessFor": "\u7533\u8BF7\u8BBF\u95EE {p0}",
374
+ "common.restricted": "\u53D7\u9650",
375
+ "common.retry": "\u91CD\u8BD5",
376
+ "common.rows": "{p0} \u884C",
377
+ "common.run": "\u8FD0\u884C",
378
+ "common.steps": "{p0} \u6B65",
379
+ "common.submit": "\u63D0\u4EA4",
380
+ "common.unknown": "\u672A\u77E5",
381
+ /* ── contextMenu ── */
382
+ "contextMenu.back": "\u540E\u9000",
383
+ "contextMenu.copyPageLink": "\u590D\u5236\u9875\u9762\u94FE\u63A5",
384
+ "contextMenu.forward": "\u524D\u8FDB",
385
+ "contextMenu.refresh": "\u5237\u65B0",
386
+ /* ── copy ── */
387
+ "copy.copied": "\u5DF2\u590D\u5236",
388
+ "copy.failed": "\u672A\u80FD\u590D\u5236\uFF0C\u8BF7\u91CD\u8BD5\u3002",
389
+ "copy.denied": "clipboard API \u88AB\u62D2\uFF08{p0}\uFF09\u4E14\u56DE\u9000 execCommand \u5931\u8D25",
390
+ "copy.unavailable": "\u526A\u8D34\u677F\u4E0D\u53EF\u7528\uFF08\u65E0 clipboard API \u4E14 execCommand \u56DE\u9000\u5931\u8D25\uFF09",
391
+ "copy.unknown": "\u672A\u77E5\u9519\u8BEF",
392
+ /* ── datatable ── */
393
+ "datatable.clear": "\u6E05\u7A7A",
394
+ "datatable.collapseGroup": "\u6298\u53E0\u5206\u7EC4 {p0}",
395
+ "datatable.columnSettingsAria": "\u5217\u8BBE\u7F6E",
396
+ "datatable.countUnit": "{p0} \u6761",
397
+ "datatable.editHint": "\u7F16\u8F91\u300C{p0}\u300D\uFF1A\u53CC\u51FB\u6216\u6309 Enter",
398
+ "datatable.editHintWithValue": "{p0}\uFF08\u53CC\u51FB\u6216\u6309 Enter \u7F16\u8F91\u300C{p1}\u300D\uFF09",
399
+ "datatable.empty": "\u6682\u65E0\u6570\u636E",
400
+ "datatable.emptyValue": "\uFF08\u7A7A\uFF09",
401
+ "datatable.expandGroup": "\u5C55\u5F00\u5206\u7EC4 {p0}",
402
+ "datatable.expandRow": "\u5C55\u5F00\u884C",
403
+ "datatable.filterChipAria": "\u7B5B\u9009\u300C{p0}\u300D",
404
+ "datatable.pageSizeAria": "\u6BCF\u9875\u6761\u6570",
405
+ "datatable.paginationAria": "\u5206\u9875",
406
+ "datatable.reset": "\u91CD\u7F6E",
407
+ "datatable.resizeAria": "\u8C03\u6574\u300C{p0}\u300D\u5217\u5BBD",
408
+ "datatable.searchAria": "\u641C\u7D22\u8868\u683C",
409
+ "datatable.searchPlaceholder": "\u641C\u7D22\u2026",
410
+ "datatable.selectAll": "\u5168\u9009",
411
+ "datatable.selectRow": "\u9009\u62E9\u8BE5\u884C",
412
+ "datatable.selectedCount": "\u5DF2\u9009 {p0} \u9879",
413
+ "datatable.totalCount": "\u5171 {p0} \u6761",
414
+ "datatable.totalLabel": "\u5408\u8BA1",
415
+ /* ── datePicker ── */
416
+ "datePicker.noDates": "\u6CA1\u6709\u53EF\u9009\u65E5\u671F",
417
+ "datePicker.clear": "\u6E05\u9664",
418
+ "datePicker.nextMonth": "\u4E0B\u4E00\u6708",
419
+ "datePicker.prevMonth": "\u4E0A\u4E00\u6708",
420
+ "datePicker.selectDate": "\u9009\u62E9\u65E5\u671F",
421
+ "datePicker.today": "\u4ECA\u5929",
422
+ "datePicker.weekdays": ["\u4E00", "\u4E8C", "\u4E09", "\u56DB", "\u4E94", "\u516D", "\u65E5"],
423
+ "datePicker.weekdaysSunFirst": ["\u65E5", "\u4E00", "\u4E8C", "\u4E09", "\u56DB", "\u4E94", "\u516D"],
424
+ "datePicker.yearMonth": "{p0} \u5E74 {p1} \u6708",
425
+ /* ── formValidate ── */
426
+ "formValidate.email": "\u8BF7\u8F93\u5165\u6709\u6548\u7684\u90AE\u7BB1\u5730\u5740",
427
+ "formValidate.invalid": "\u8F93\u5165\u4E0D\u5408\u6CD5",
428
+ "formValidate.matches": "\u4E24\u6B21\u8F93\u5165\u4E0D\u4E00\u81F4",
429
+ "formValidate.max": "\u4E0D\u80FD\u5927\u4E8E {max}",
430
+ "formValidate.maxlength": "\u6700\u591A\u8F93\u5165 {max} \u4E2A\u5B57\u7B26",
431
+ "formValidate.min": "\u4E0D\u80FD\u5C0F\u4E8E {min}",
432
+ "formValidate.minlength": "\u81F3\u5C11\u8F93\u5165 {min} \u4E2A\u5B57\u7B26",
433
+ "formValidate.number": "\u8BF7\u8F93\u5165\u6709\u6548\u7684\u6570\u5B57",
434
+ "formValidate.pattern": "\u8F93\u5165\u683C\u5F0F\u4E0D\u6B63\u786E",
435
+ "formValidate.required": "\u6B64\u9879\u4E3A\u5FC5\u586B\u9879",
436
+ "formValidate.selectPlaceholder": "\u8BF7\u9009\u62E9",
437
+ "formValidate.step": "\u6570\u503C\u5FC5\u987B\u662F {step} \u7684\u500D\u6570",
438
+ "formValidate.summary": "\u8868\u5355\u6709 {p0} \u9879\u5185\u5BB9\u9700\u8981\u4FEE\u6B63\uFF0C\u8BF7\u4FEE\u6539\u540E\u91CD\u65B0\u63D0\u4EA4",
439
+ "formValidate.tool.description": "\u5411\u7528\u6237\u6E32\u67D3\u4E00\u4E2A\u7ED3\u6784\u5316\u8868\u5355\u6536\u96C6\u8F93\u5165",
440
+ "formValidate.tool.fields": "\u5B57\u6BB5\u5217\u8868",
441
+ "formValidate.tool.help": "\u5B57\u6BB5\u4E0B\u65B9\u7684\u5E2E\u52A9\u6587\u6848",
442
+ "formValidate.tool.label": "\u5B57\u6BB5\u6807\u7B7E",
443
+ "formValidate.tool.max": "\u6700\u5927\u503C\uFF08number \u7528\uFF09",
444
+ "formValidate.tool.min": "\u6700\u5C0F\u503C\uFF08number \u7528\uFF09",
445
+ "formValidate.tool.name": "\u5B57\u6BB5\u540D\uFF08\u63D0\u4EA4\u503C\u7684 key\uFF09",
446
+ "formValidate.tool.options": "select \u9009\u9879\uFF08\u5B57\u7B26\u4E32\u6216 {label,value}\uFF09",
447
+ "formValidate.tool.pattern": "\u6B63\u5219\u7EA6\u675F\uFF08HTML pattern \u8BED\u6CD5\uFF0C\u6574\u4E32\u5339\u914D\uFF09",
448
+ "formValidate.tool.required": "\u662F\u5426\u5FC5\u586B",
449
+ "formValidate.tool.submitText": "\u63D0\u4EA4\u6309\u94AE\u6587\u6848\uFF0C\u9ED8\u8BA4\u300C\u63D0\u4EA4\u300D",
450
+ "formValidate.tool.title": "\u8868\u5355\u6807\u9898\uFF08\u53EF\u9009\uFF09",
451
+ "formValidate.tool.type": "\u63A7\u4EF6\u7C7B\u578B\uFF0C\u9ED8\u8BA4 text",
452
+ "formValidate.url": "\u8BF7\u8F93\u5165\u6709\u6548\u7684\u94FE\u63A5\u5730\u5740",
453
+ /* ── input ── */
454
+ "input.clearSearch": "\u6E05\u7A7A\u641C\u7D22",
455
+ "input.hidePassword": "\u9690\u85CF\u5BC6\u7801",
456
+ "input.otpPosition": "\u7B2C {p0} \u4F4D\uFF0C\u5171 {p1} \u4F4D",
457
+ "panel.expand": "\u5C55\u5F00",
458
+ "panel.collapse": "\u6298\u53E0",
459
+ "input.showPassword": "\u663E\u793A\u5BC6\u7801",
460
+ /* ── kbAccess ── */
461
+ "kbAccess.approveTip": "\u6279\u51C6\u8BE5\u8BBF\u95EE\u7533\u8BF7",
462
+ "kbAccess.approvedBadge": "\u5DF2\u6279\u51C6 \xB7 {p0}",
463
+ "kbAccess.approverNotePlaceholder": "\u7ED9\u8BF7\u6C42\u4EBA\u7684\u7559\u8A00\uFF08\u53EF\u9009\uFF09",
464
+ "kbAccess.daysLeft": "{p0} \u5929\u540E",
465
+ "kbAccess.defaultSubject": "\u8BE5\u5185\u5BB9",
466
+ "kbAccess.deniedHint": "\u672A\u901A\u8FC7\u2014\u2014\u53EF\u8C03\u6574\u7406\u7531\u540E\u91CD\u65B0\u7533\u8BF7",
467
+ "kbAccess.denyNoteLabel": "\u62D2\u7EDD\u7559\u8A00\uFF08\u53EF\u9009\uFF09",
468
+ "kbAccess.duration30d": "30 \u5929",
469
+ "kbAccess.duration7d": "7 \u5929",
470
+ "kbAccess.durationForever": "\u6C38\u4E45",
471
+ "kbAccess.durationLabel": "\u8BBF\u95EE\u65F6\u957F",
472
+ "kbAccess.expired": "\u5DF2\u5230\u671F",
473
+ "kbAccess.expiresAt": "{p0}\u5230\u671F",
474
+ "kbAccess.grantAsPrefix": "\u6279\u51C6\u4E3A{p0}",
475
+ "kbAccess.grantRoleLabel": "\u6279\u51C6\u89D2\u8272",
476
+ "kbAccess.hoursLeft": "{p0} \u5C0F\u65F6\u540E",
477
+ "kbAccess.minutesLeft": "{p0} \u5206\u949F\u540E",
478
+ "kbAccess.ownerLabel": "\u5185\u5BB9\u8D1F\u8D23\u4EBA",
479
+ "kbAccess.ownerPrefix": "\u8D1F\u8D23\u4EBA\uFF1A{p0}",
480
+ "kbAccess.reapply": "\u91CD\u65B0\u7533\u8BF7",
481
+ "kbAccess.reasonLabel": "\u7533\u8BF7\u7406\u7531",
482
+ "kbAccess.reasonPlaceholder": "\u8BF4\u660E\u4E1A\u52A1\u539F\u56E0\uFF08\u5BA1\u6279\u4EBA\u53EF\u89C1\uFF09",
483
+ "kbAccess.rejectTip": "\u62D2\u7EDD\u8BE5\u8BBF\u95EE\u7533\u8BF7",
484
+ "kbAccess.requestRenewal": "\u7533\u8BF7\u7EED\u671F",
485
+ "kbAccess.requestToPrefix": "\u8BF7\u6C42\u5C06\u53D1\u9001\u7ED9\uFF1A{p0}",
486
+ "kbAccess.restrictedContent": "\u53D7\u9650\u5185\u5BB9",
487
+ "kbAccess.restrictedHint": "\u6B64\u5185\u5BB9\u4EC5\u5BF9\u6388\u6743\u8005\u5F00\u653E",
488
+ "kbAccess.revokedHint": "\u8BBF\u95EE\u5DF2\u88AB\u6536\u56DE",
489
+ "kbAccess.roleLabel": "\u7533\u8BF7\u89D2\u8272",
490
+ "kbAccess.submitRequest": "\u63D0\u4EA4\u7533\u8BF7",
491
+ "kbAccess.switchIdentity": "\u5207\u6362\u8EAB\u4EFD",
492
+ "kbAccess.switchIdentityTip": "\u5207\u6362\u8EAB\u4EFD\u540E\u91CD\u65B0\u68C0\u67E5\u6743\u9650",
493
+ "kbAccess.unknownRequester": "\u672A\u77E5\u8BF7\u6C42\u4EBA",
494
+ "kbAccess.waitingApproval": "\u7B49\u5F85 {p0} \u5BA1\u6279",
495
+ /* ── kbAcl ── */
496
+ "kbAcl.breakHint": "\u505C\u6B62\u4ECE\u7236\u7EA7\u7EE7\u627F\uFF0C\u6539\u4E3A\u72EC\u7ACB\u7BA1\u7406\u672C\u9879\u6743\u9650",
497
+ "kbAcl.breakInheritance": "\u505C\u6B62\u7EE7\u627F",
498
+ "kbAcl.brokenNotice": "\u5DF2\u505C\u6B62\u7EE7\u627F\u2014\u2014\u672C\u9879\u6743\u9650\u72EC\u7ACB\u4E8E\u7236\u7EA7",
499
+ "kbAcl.detachedChildren": "{p0}\uFF1A{p1} \u4E2A\u5B50\u9879\u5DF2\u8131\u79BB",
500
+ "kbAcl.directAccess": "\u76F4\u63A5\u8BBF\u95EE",
501
+ "kbAcl.exception": "\u4F8B\u5916",
502
+ "kbAcl.expiredOn": "\u5DF2\u8FC7\u671F\uFF08{p0}\uFF09",
503
+ "kbAcl.expiresIn": "{p0} \u5230\u671F",
504
+ "kbAcl.grantAccess": "\u6388\u4E88\u8BBF\u95EE",
505
+ "kbAcl.inheritedFrom": "\u7EE7\u627F\u81EA {p0}",
506
+ "kbAcl.inheritedFromLabel": "\u7EE7\u627F\u81EA",
507
+ "kbAcl.linkAccess": "\u94FE\u63A5\u8BBF\u95EE",
508
+ "kbAcl.noDirect": "\u6682\u65E0\u76F4\u63A5\u6388\u6743",
509
+ "kbAcl.noLinks": "\u65E0\u94FE\u63A5",
510
+ "kbAcl.removeEntry": "\u79FB\u9664 {p0}",
511
+ "kbAcl.restoreHint": "\u6062\u590D\u7EE7\u627F\u5C06\u4E22\u5F03\u672C\u9879\u81EA\u5B9A\u4E49\u7684\u6743\u9650",
512
+ "kbAcl.restoreInheritance": "\u6062\u590D\u7EE7\u627F",
513
+ "kbAcl.rootNotice": "\u6839\u7EA7\u8D44\u6E90\u2014\u2014\u65E0\u7236\u7EA7\u7EE7\u627F",
514
+ "kbAcl.systemBadge": "\u7CFB\u7EDF\u7BA1\u7406",
515
+ "kbAcl.systemNote": "\u7CFB\u7EDF\u81EA\u52A8\uFF0C\u4E0D\u53EF\u624B\u5DE5\u79FB\u9664",
516
+ "kbAcl.unnamedResource": "\u672A\u547D\u540D\u8D44\u6E90",
517
+ "kbAcl.visibleToCount": "\u5BF9 {p0} \u4EBA\u53EF\u89C1",
518
+ /* ── kbAnswer ── */
519
+ "kbAnswer.chartBar": "\u67F1\u72B6",
520
+ "kbAnswer.chartLine": "\u6298\u7EBF",
521
+ "kbAnswer.chartPie": "\u997C\u56FE",
522
+ "kbAnswer.exportNoun": "\u5BFC\u51FA {p0}",
523
+ "kbAnswer.filtered": "\u5DF2\u6309\u4F60\u7684\u6570\u636E\u6743\u9650\u8FC7\u6EE4",
524
+ "kbAnswer.filteredDetail": "\u5DF2\u6309\u4F60\u7684\u6570\u636E\u6743\u9650\u8FC7\u6EE4\uFF1A{p0}",
525
+ "kbAnswer.followups": "\u8FFD\u95EE\u5EFA\u8BAE",
526
+ "kbAnswer.hitAssets": "\u547D\u4E2D\u8D44\u4EA7\uFF1A{p0}",
527
+ "kbAnswer.kindCurated": "\u4EBA\u5DE5\u7B56\u5C55",
528
+ "kbAnswer.kindFunction": "\u51FD\u6570",
529
+ "kbAnswer.kindParameterized": "\u53C2\u6570\u5316\u67E5\u8BE2",
530
+ "kbAnswer.maskedPrefix": "\u5DF2\u8131\u654F\u5217\uFF1A",
531
+ "kbAnswer.rerunTip": "\u53C2\u6570\u53EF\u6539\u91CD\u8DD1",
532
+ "kbAnswer.truncated": "\u5DF2\u622A\u65AD\uFF1A\u663E\u793A {p0}/{p1} \u884C{p2}",
533
+ "kbAnswer.verifiedBadge": "\u8BA4\u8BC1\u7B54\u6848",
534
+ /* ── kbAudit ── */
535
+ "kbAudit.actionDetail": "\u5904\u7F6E\uFF1A{p0} \xB7 {p1}",
536
+ "kbAudit.actionLabel": "\u5904\u7F6E",
537
+ "kbAudit.alertedNote": "\u5DF2\u5B9E\u65F6\u544A\u8B66\u5B89\u5168\u56E2\u961F",
538
+ "kbAudit.channelFilterAria": "\u5BA1\u8BA1\u901A\u9053\u8FC7\u6EE4",
539
+ "kbAudit.channelPermission": "\u6743\u9650\u53D8\u66F4",
540
+ "kbAudit.channelRead": "\u8BFB\u53D6",
541
+ "kbAudit.channelRequest": "\u7533\u8BF7",
542
+ "kbAudit.channelSystem": "\u7CFB\u7EDF",
543
+ "kbAudit.empty": "\u6682\u65E0\u5BA1\u8BA1\u4E8B\u4EF6",
544
+ "kbAudit.exportTip": "\u5BFC\u51FA\u5F53\u524D\u8FC7\u6EE4\u89C6\u56FE\u4E3A CSV",
545
+ "kbAudit.hygieneLabel": "\u6743\u9650\u5F02\u5473",
546
+ "kbAudit.noHygiene": "\u672A\u53D1\u73B0\u6743\u9650\u5F02\u5473",
547
+ /* ── kbCanvas ── */
548
+ "kbCanvas.splitterAria": "\u8C03\u6574\u753B\u5E03\u53CC\u680F\u6BD4\u4F8B",
549
+ "kbCanvas.splitterTip": "\u62D6\u62FD\u8C03\u6574\u6BD4\u4F8B\uFF08\u2190/\u2192 \u5FAE\u8C03\uFF0C\u53CC\u51FB\u590D\u4F4D\uFF09",
550
+ /* ── kbCheckpoint ── */
551
+ "kbCheckpoint.chatAuditNote": "\u8BA8\u8BBA\u5386\u53F2\u6709\u5BA1\u8BA1\u4EF7\u503C",
552
+ "kbCheckpoint.label": "\u68C0\u67E5\u70B9",
553
+ "kbCheckpoint.restore": "\u6062\u590D\u68C0\u67E5\u70B9",
554
+ "kbCheckpoint.scopeBoth": "\u5185\u5BB9\u4E0E\u5BF9\u8BDD",
555
+ "kbCheckpoint.scopeChat": "\u4EC5\u5BF9\u8BDD",
556
+ "kbCheckpoint.scopeContent": "\u4EC5\u5185\u5BB9\uFF08\u4FDD\u7559\u5BF9\u8BDD\uFF09",
557
+ "kbCheckpoint.scopeMissing": "\u8BE5\u68C0\u67E5\u70B9\u672A\u5305\u542B\u6B64\u6062\u590D\u8303\u56F4",
558
+ /* ── kbChunks ── */
559
+ "kbChunks.addKeyword": "+ \u5173\u952E\u8BCD",
560
+ "kbChunks.chunkAddKeywordAria": "chunk {p0} \u65B0\u589E\u5173\u952E\u8BCD",
561
+ "kbChunks.chunkContentAria": "chunk {p0} \u5185\u5BB9",
562
+ "kbChunks.chunkEnableAria": "chunk {p0} \u542F\u7528",
563
+ "kbChunks.deleteChunkAria": "\u5220\u9664 chunk {p0}",
564
+ "kbChunks.disableNote": "\u5173\u95ED\u540E\u4E0D\u5220\u9664\uFF0C\u4EC5\u6392\u9664\u51FA\u68C0\u7D22",
565
+ "kbChunks.edited": "\u5DF2\u7F16\u8F91",
566
+ "kbChunks.empty": "\u6682\u65E0 chunk",
567
+ "kbChunks.modeFull": "\u5168\u6587",
568
+ "kbChunks.modeLabel": "\u641C\u7D22\u6A21\u5F0F",
569
+ "kbChunks.modeVector": "\u8BED\u4E49",
570
+ "kbChunks.removeKeyword": "\u79FB\u9664\u5173\u952E\u8BCD {p0}",
571
+ "kbChunks.searchAria": "\u641C\u7D22 chunk",
572
+ "kbChunks.searchFullPlaceholder": "\u5168\u6587\u641C\u7D22 chunk\u2026",
573
+ "kbChunks.searchVectorPlaceholder": "\u8BED\u4E49\u641C\u7D22 chunk\u2026",
574
+ /* ── kbCitation ── */
575
+ "kbCitation.sourceN": "\u6765\u6E90 {p0}",
576
+ "kbCitation.unavailable": "\u6765\u6E90\u5DF2\u4E0D\u53EF\u7528",
577
+ /* ── kbClarify ── */
578
+ "kbClarify.parsedPrefix": "\u5DF2\u89E3\u6790\uFF1A",
579
+ /* ── kbConflict ── */
580
+ "kbConflict.owner": "\u8D23\u4EFB\u4EBA {p0}",
581
+ /* ── kbConnector ── */
582
+ "kbConnector.changeRate": "\u53D8\u66F4\u7387",
583
+ "kbConnector.crawlRate": "\u6293\u53D6\u7387",
584
+ "kbConnector.credentials": "\u51ED\u8BC1",
585
+ "kbConnector.credentialsExpired": "\u51ED\u8BC1\u8FC7\u671F",
586
+ "kbConnector.editSchedule": "\u7F16\u8F91\u8BA1\u5212",
587
+ "kbConnector.empty": "\u6682\u65E0\u8FDE\u63A5\u5668",
588
+ "kbConnector.failing": "\u5F02\u5E38",
589
+ "kbConnector.lastSync": "\u6700\u8FD1\u540C\u6B65 {p0}",
590
+ "kbConnector.neverSynced": "\u4ECE\u672A\u540C\u6B65",
591
+ "kbConnector.notConfigured": "\u672A\u914D\u7F6E",
592
+ "kbConnector.off": "\u5DF2\u505C\u7528",
593
+ "kbConnector.perDay": "{p0}/\u5929",
594
+ "kbConnector.reauth": "\u91CD\u65B0\u6388\u6743",
595
+ "kbConnector.stale": "\u505C\u6EDE",
596
+ "kbConnector.syncNow": "\u7ACB\u5373\u540C\u6B65",
597
+ "kbConnector.synced": "\u5DF2\u540C\u6B65",
598
+ /* ── kbCore ── */
599
+ "kbCore.accessDenied": "\u672A\u901A\u8FC7",
600
+ "kbCore.accessExpired": "\u5DF2\u8FC7\u671F",
601
+ "kbCore.accessExpiring": "\u5373\u5C06\u5230\u671F",
602
+ "kbCore.accessGranted": "\u5DF2\u5F00\u901A",
603
+ "kbCore.accessNotRequested": "\u672A\u7533\u8BF7",
604
+ "kbCore.accessPending": "\u5F85\u5BA1\u6279",
605
+ "kbCore.accessRequested": "\u5DF2\u63D0\u4EA4",
606
+ "kbCore.accessRevoked": "\u5DF2\u6536\u56DE",
607
+ "kbCore.auditApprove": "\u6279\u51C6",
608
+ "kbCore.auditBreakGlass": "\u5E94\u6025\u8BBF\u95EE",
609
+ "kbCore.auditDelegation": "\u59D4\u6D3E",
610
+ "kbCore.auditDeny": "\u62D2\u7EDD",
611
+ "kbCore.auditGrant": "\u6388\u4E88",
612
+ "kbCore.auditPermissionChange": "\u6743\u9650\u53D8\u66F4",
613
+ "kbCore.auditPreview": "\u9884\u89C8",
614
+ "kbCore.auditRead": "\u8BFB\u53D6",
615
+ "kbCore.auditRequest": "\u7533\u8BF7",
616
+ "kbCore.auditRevoke": "\u6536\u56DE",
617
+ "kbCore.auditSync": "\u6743\u9650\u540C\u6B65",
618
+ "kbCore.daysAgo": "{p0} \u5929\u524D",
619
+ "kbCore.hoursAgo": "{p0} \u5C0F\u65F6\u524D",
620
+ "kbCore.hygieneBroadGroup": "\u8FC7\u5BBD\u7EC4\u6388\u6743",
621
+ "kbCore.hygieneBrokenInheritance": "\u65AD\u7EE7\u627F",
622
+ "kbCore.hygieneOrgWideLink": "\u7EC4\u7EC7\u7EA7\u94FE\u63A5",
623
+ "kbCore.hygieneOrphanedOwner": "\u8D1F\u8D23\u4EBA\u7F3A\u4F4D",
624
+ "kbCore.hygieneOverexposed": "\u8FC7\u5EA6\u66B4\u9732",
625
+ "kbCore.hygieneSensitiveMismatch": "\u654F\u611F\u5EA6\u9519\u914D",
626
+ "kbCore.justNow": "\u521A\u521A",
627
+ "kbCore.levelComment": "\u53EF\u8BC4\u8BBA",
628
+ "kbCore.levelEdit": "\u53EF\u7F16\u8F91",
629
+ "kbCore.levelNone": "\u65E0\u6743\u9650",
630
+ "kbCore.levelOwner": "\u8D1F\u8D23\u4EBA",
631
+ "kbCore.levelView": "\u53EF\u67E5\u770B",
632
+ "kbCore.minutesAgo": "{p0} \u5206\u949F\u524D",
633
+ "kbCore.runCancelled": "\u5DF2\u53D6\u6D88",
634
+ "kbCore.runDone": "\u5DF2\u5B8C\u6210",
635
+ "kbCore.runFailed": "\u5931\u8D25",
636
+ "kbCore.runQueued": "\u6392\u961F\u4E2D",
637
+ "kbCore.runRunning": "\u8FDB\u884C\u4E2D",
638
+ "kbCore.runUnstarted": "\u672A\u5F00\u59CB",
639
+ "kbCore.stageAgent": "\u4EE3\u7406",
640
+ "kbCore.stageChunk": "\u5207\u7247",
641
+ "kbCore.stageEmbed": "\u5411\u91CF\u5316",
642
+ "kbCore.stageGeneration": "\u751F\u6210",
643
+ "kbCore.stageGuard": "\u62A4\u680F",
644
+ "kbCore.stageQuery": "\u67E5\u8BE2",
645
+ "kbCore.stageRerank": "\u91CD\u6392",
646
+ "kbCore.stageRetrieval": "\u68C0\u7D22",
647
+ "kbCore.stageTool": "\u5DE5\u5177",
648
+ "kbCore.typeApi": "\u63A5\u53E3",
649
+ "kbCore.typeCode": "\u4EE3\u7801",
650
+ "kbCore.typeDatabase": "\u6570\u636E\u5E93",
651
+ "kbCore.typeDocument": "\u6587\u6863",
652
+ "kbCore.typeEmail": "\u90AE\u4EF6",
653
+ "kbCore.typeImage": "\u56FE\u7247",
654
+ "kbCore.typeKb": "\u77E5\u8BC6\u5E93",
655
+ "kbCore.typeTable": "\u8868\u683C",
656
+ "kbCore.typeTicket": "\u5DE5\u5355",
657
+ "kbCore.typeWebpage": "\u7F51\u9875",
658
+ "kbCore.unnamedSource": "\u672A\u547D\u540D\u6765\u6E90",
659
+ "kbCore.unnamedSubject": "\u672A\u547D\u540D\u4E3B\u4F53",
660
+ "kbCore.visHidden": "\u4E0D\u53EF\u89C1",
661
+ "kbCore.visMetadataOnly": "\u4EC5\u5143\u6570\u636E",
662
+ "kbCore.visSummaryOnly": "\u4EC5\u6458\u8981",
663
+ "kbCore.visVisible": "\u53EF\u89C1",
664
+ /* ── kbEval ── */
665
+ "kbEval.avgA": "A \u5747\u5206 {p0}",
666
+ "kbEval.avgB": "B \u5747\u5206 {p0}",
667
+ "kbEval.compare": "\u5BF9\u6BD4",
668
+ "kbEval.runSelectAria": "\u9009\u62E9\u5BF9\u6BD4\u8FD0\u884C",
669
+ "kbEval.expected": "\u671F\u671B",
670
+ "kbEval.gradeImprovement": "\u63D0\u5347",
671
+ "kbEval.gradeRegression": "\u56DE\u5F52",
672
+ "kbEval.gradeTie": "\u6301\u5E73",
673
+ "kbEval.gradeTradeoff": "\u6743\u8861",
674
+ "kbEval.noData": "\u6CA1\u6709\u5BF9\u6BD4\u6570\u636E",
675
+ "kbEval.onlyRegression": "\u4EC5\u770B\u56DE\u5F52",
676
+ "kbEval.outputA": "\u8F93\u51FA A",
677
+ "kbEval.outputB": "\u8F93\u51FA B",
678
+ "kbEval.outputN": "\u8F93\u51FA {p0}",
679
+ /* ── kbExplain ── */
680
+ "kbExplain.empty": "\u6682\u65E0\u53E3\u5F84\u4FE1\u606F",
681
+ "kbExplain.groupAgg": "\u805A\u5408",
682
+ "kbExplain.groupColumn": "\u5217",
683
+ "kbExplain.groupFilter": "\u7B5B\u9009",
684
+ "kbExplain.groupTable": "\u8868",
685
+ "kbExplain.trigger": "\u8FD9\u4E2A\u6570\u5B57\u662F\u600E\u4E48\u7B97\u51FA\u6765\u7684",
686
+ "kbExplain.viewDefinition": "\u67E5\u770B\u53E3\u5F84",
687
+ /* ── kbFilter ── */
688
+ "kbFilter.addGroup": "+ \u7EC4",
689
+ "kbFilter.addRule": "+ \u89C4\u5219",
690
+ "kbFilter.and": "\u4E14",
691
+ "kbFilter.combineMode": "\u7EC4\u5408\u65B9\u5F0F {p0}",
692
+ "kbFilter.copyDsl": "\u590D\u5236 DSL",
693
+ "kbFilter.deleteGroup": "\u5220\u9664\u7EC4",
694
+ "kbFilter.deleteRule": "\u5220\u9664\u89C4\u5219",
695
+ "kbFilter.fieldLabel": "\u5B57\u6BB5",
696
+ "kbFilter.fieldPlaceholder": "\u8FC7\u6EE4\u5B57\u6BB5",
697
+ "kbFilter.noValueNeeded": "\uFF08\u65E0\u9700\u503C\uFF09",
698
+ "kbFilter.none": "\uFF08\u65E0\u8FC7\u6EE4\uFF09",
699
+ "kbFilter.opContains": "\u5305\u542B",
700
+ "kbFilter.opEq": "\u7B49\u4E8E",
701
+ "kbFilter.opExists": "\u5B58\u5728",
702
+ "kbFilter.opGt": "\u5927\u4E8E",
703
+ "kbFilter.opGte": "\u5927\u4E8E\u7B49\u4E8E",
704
+ "kbFilter.opIn": "\u5C5E\u4E8E",
705
+ "kbFilter.opLt": "\u5C0F\u4E8E",
706
+ "kbFilter.opLte": "\u5C0F\u4E8E\u7B49\u4E8E",
707
+ "kbFilter.opNe": "\u4E0D\u7B49\u4E8E",
708
+ "kbFilter.operatorLabel": "\u64CD\u4F5C\u7B26",
709
+ "kbFilter.or": "\u6216",
710
+ "kbFilter.toggleAndOr": "\u5207\u6362 AND / OR",
711
+ "kbFilter.valueAria": "\u8FC7\u6EE4\u503C",
712
+ "kbFilter.valueLabel": "\u503C",
713
+ "kbFilter.valuePlaceholder": "\u503C 1, \u503C 2\uFF08\u9017\u53F7\u5206\u9694\uFF09",
714
+ /* ── kbGap ── */
715
+ "kbGap.addSynonym": "\u52A0\u540C\u4E49\u8BCD",
716
+ "kbGap.colCount": "\u6B21\u6570",
717
+ "kbGap.colLastSeen": "\u6700\u8FD1\u51FA\u73B0",
718
+ "kbGap.colQuery": "\u67E5\u8BE2",
719
+ "kbGap.colShare": "\u5360\u6BD4",
720
+ "kbGap.createDoc": "\u5EFA\u6587\u6863",
721
+ "kbGap.empty": "\u6CA1\u6709\u672A\u547D\u4E2D\u67E5\u8BE2\u2014\u2014\u8986\u76D6\u826F\u597D",
722
+ "kbGap.title": "\u672A\u547D\u4E2D\u67E5\u8BE2\u8D8B\u52BF",
723
+ "kbGap.zeroClickHint": "\u7528\u6237\u53EF\u80FD\u5DF2\u4ECE\u5F15\u7528\u7247\u6BB5\u5F97\u5230\u7B54\u6848\uFF1B\u96F6\u70B9\u51FB\u9700\u4EBA\u5DE5\u5224\u8BFB\uFF0C\u4E0D\u76F4\u63A5\u89C6\u4E3A\u5931\u8D25",
724
+ "kbGap.zeroClickRate": "\u96F6\u70B9\u51FB\u7387",
725
+ "kbGap.zeroClickTitle": "\u96F6\u70B9\u51FB \u2260 \u5931\u8D25",
726
+ /* ── kbHittest ── */
727
+ "kbHittest.addAria": "\u65B0\u589E\u6D4B\u8BD5\u95EE\u9898",
728
+ "kbHittest.addPlaceholder": "\u65B0\u589E\u95EE\u9898\uFF0CEnter \u6DFB\u52A0",
729
+ "kbHittest.avgScore": "\u5747\u5206",
730
+ "kbHittest.deleteQuestion": "\u5220\u9664\u95EE\u9898",
731
+ "kbHittest.empty": "\u6682\u65E0\u6D4B\u8BD5\u95EE\u9898\u2014\u2014\u6DFB\u52A0\u7B2C\u4E00\u6761\uFF0C\u5F00\u59CB\u53EC\u56DE\u56DE\u5F52",
732
+ "kbHittest.expectHit": "\u671F\u671B\u547D\u4E2D\u5728\u524D\u6392\u547D\u4E2D\u4E2D",
733
+ "kbHittest.expectMiss": "\u671F\u671B\u672A\u547D\u4E2D",
734
+ "kbHittest.hitRate": "\u547D\u4E2D\u7387",
735
+ "kbHittest.noExpectation": "\u672A\u8BBE\u671F\u671B",
736
+ "kbHittest.notRun": "\u672A\u8FD0\u884C",
737
+ "kbHittest.pass": "\u901A\u8FC7",
738
+ "kbHittest.pin": "\u7F6E\u9876\u56FA\u5B9A",
739
+ "kbHittest.runAll": "\u8FD0\u884C\u5168\u90E8",
740
+ "kbHittest.sessionOnly": "\u53C2\u6570\u4EC5\u672C\u6B21\u4F1A\u8BDD\u751F\u6548",
741
+ "kbHittest.sessionOnlyHint": "\u6D4B\u8BD5\u8FD0\u884C\u7684\u68C0\u7D22\u53C2\u6570\uFF08topK/\u9608\u503C/\u91CD\u6392\uFF09\u4E0D\u843D\u5E93\uFF0C\u4EC5\u672C\u6B21\u4F1A\u8BDD\u751F\u6548",
742
+ "kbHittest.unpin": "\u53D6\u6D88\u7F6E\u9876",
743
+ /* ── kbMetadata ── */
744
+ "kbMetadata.addField": "\u65B0\u589E\u5B57\u6BB5",
745
+ "kbMetadata.builtIn": "\u5185\u7F6E",
746
+ "kbMetadata.colField": "\u5B57\u6BB5",
747
+ "kbMetadata.colType": "\u7C7B\u578B",
748
+ "kbMetadata.colValue": "\u503C",
749
+ "kbMetadata.empty": "\u6682\u65E0\u5143\u6570\u636E\u5B57\u6BB5",
750
+ "kbMetadata.nameLabel": "\u65B0\u5B57\u6BB5\u540D",
751
+ "kbMetadata.namePlaceholder": "\u5B57\u6BB5\u540D\uFF0C\u5982 department",
752
+ "kbMetadata.removeField": "\u79FB\u9664\u5B57\u6BB5 {p0}",
753
+ "kbMetadata.typeLabel": "\u65B0\u5B57\u6BB5\u7C7B\u578B",
754
+ "kbMetadata.valueOf": "{p0} \u7684\u503C",
755
+ /* ── kbPassage ── */
756
+ "kbPassage.blockRange": "\u5757 {p0}\u2013{p1}",
757
+ "kbPassage.close": "\u5173\u95ED\u539F\u6587",
758
+ "kbPassage.expandContext": "\u5C55\u5F00\u4E0A\u4E0B\u6587",
759
+ "kbPassage.locate": "\u539F\u6587\u5B9A\u4F4D",
760
+ "kbPassage.none": "\uFF08\u65E0\u539F\u6587\uFF09",
761
+ "kbPassage.pageRange": "\u7B2C {p0}\u2013{p1} \u9875",
762
+ "kbPassage.restricted": "\u5185\u5BB9\u53D7\u9650",
763
+ "kbPassage.unitByte": "\u5B57\u8282",
764
+ "kbPassage.unitChar": "\u5B57\u7B26",
765
+ /* ── kbPipeline ── */
766
+ "kbPipeline.empty": "\u6682\u65E0\u89E3\u6790\u4EFB\u52A1",
767
+ "kbPipeline.progress": "\u89E3\u6790\u8FDB\u5EA6",
768
+ "kbPipeline.rerun": "\u91CD\u8DD1",
769
+ "kbPipeline.unknownStage": "\u672A\u77E5\u9636\u6BB5",
770
+ /* ── kbQa ── */
771
+ "kbQa.colAnswer": "\u7B54\u6848",
772
+ "kbQa.colQuestion": "\u95EE\u9898",
773
+ "kbQa.csvHint": "CSV \u6A21\u677F\uFF1Aquestion,answer\uFF08\u6BCF\u884C\u4E00\u5BF9\uFF0CUTF-8\uFF09",
774
+ "kbQa.deleteRow": "\u5220\u9664\u7B2C {p0} \u884C",
775
+ "kbQa.empty": "\u6682\u65E0\u8BA4\u8BC1\u95EE\u7B54\u5BF9",
776
+ "kbQa.importCsv": "\u5BFC\u5165 CSV",
777
+ /* ── kbRerank ── */
778
+ "kbRerank.after": "\u91CD\u6392\u540E",
779
+ "kbRerank.before": "\u91CD\u6392\u524D",
780
+ "kbRerank.compareTitle": "\u91CD\u6392\u5BF9\u6BD4",
781
+ "kbRerank.down": "\u4E0B\u964D {p0} \u4F4D",
782
+ "kbRerank.dropped": "\u843D\u9009",
783
+ "kbRerank.empty": "\u4E24\u4FA7\u5747\u4E3A\u7A7A\u2014\u2014\u8FD0\u884C\u68C0\u7D22\u540E\u518D\u5BF9\u6BD4",
784
+ "kbRerank.enableCompare": "\u542F\u7528\u91CD\u6392\u5BF9\u6BD4",
785
+ "kbRerank.newIn": "\u65B0\u8FDB",
786
+ "kbRerank.unmarked": "\u672A\u6807",
787
+ "kbRerank.up": "\u4E0A\u5347 {p0} \u4F4D",
788
+ /* ── kbRetrieval ── */
789
+ "kbRetrieval.breakdown": "\u62C6\u89E3",
790
+ "kbRetrieval.copyParams": "\u590D\u5236\u53C2\u6570 JSON",
791
+ "kbRetrieval.decreaseTopK": "\u51CF\u5C11 topK",
792
+ "kbRetrieval.empty": "\u8F93\u5165\u95EE\u9898\u5E76\u8FD0\u884C\uFF0C\u547D\u4E2D\u7ED3\u679C\u5C06\u51FA\u73B0\u5728\u8FD9\u91CC",
793
+ "kbRetrieval.failOpenNotice": "fail-open\uFF1A\u5F53\u524D\u67E5\u8BE2\u672A\u643A\u5E26\u8EAB\u4EFD\u8FC7\u6EE4\uFF0C\u5C06\u8FD4\u56DE\u5168\u90E8\u5019\u9009\uFF08\u4EC5\u9650\u8C03\u8BD5\uFF09",
794
+ "kbRetrieval.hybridWeight": "\u6DF7\u5408\u6743\u91CD\uFF08\u5DE6\u8BED\u4E49\u53F3\u5173\u952E\u8BCD\uFF09",
795
+ "kbRetrieval.identityLabel": "\u68C0\u7D22\u8EAB\u4EFD",
796
+ "kbRetrieval.identityShort": "\u8EAB\u4EFD",
797
+ "kbRetrieval.increaseTopK": "\u589E\u52A0 topK",
798
+ "kbRetrieval.keywordHint": "\u5173\u952E\u8BCD\uFF1A\u5927\u5E93\u5FEB\u901F\u7CBE\u786E",
799
+ "kbRetrieval.layerLabel": "\u8FC7\u6EE4\u5C42",
800
+ "kbRetrieval.layerNone": "none\uFF1Afail-open\uFF0C\u65E0\u8EAB\u4EFD\u8FC7\u6EE4\u8FD4\u56DE\u5168\u90E8\u2014\u2014\u5371\u9669\uFF0C\u4EC5\u6F14\u793A",
801
+ "kbRetrieval.layerPost": "post-filter\uFF1A\u5206\u6570\u5DF2\u53EF\u89C2\u5BDF\u2014\u2014\u7F3A\u9677\u5C42\uFF0C\u4EC5\u6F14\u793A",
802
+ "kbRetrieval.layerPre": "pre-filter\uFF1AACL \u5728\u68C0\u7D22\u6267\u884C\u4F53\u5185\u751F\u6548\u2014\u2014\u5B89\u5168\u57FA\u7EBF",
803
+ "kbRetrieval.leakNote": "\u5206\u6BCD\u672A\u8FC7\u6EE4\u524D\u8BA1\u6570\u5C5E\u6CC4\u9732\uFF0C\u4E0D\u663E\u793A",
804
+ "kbRetrieval.modeHybrid": "\u6DF7\u5408",
805
+ "kbRetrieval.modeKeyword": "\u5173\u952E\u8BCD",
806
+ "kbRetrieval.modeLabel": "\u68C0\u7D22\u6A21\u5F0F",
807
+ "kbRetrieval.modeVector": "\u5411\u91CF",
808
+ "kbRetrieval.postFilterNotice": "post-filter\uFF1A\u5206\u6570\u5DF2\u5728\u8FC7\u6EE4\u524D\u4EA7\u751F\uFF08\u7F3A\u9677\u5C42\u6F14\u793A\uFF09",
809
+ "kbRetrieval.queryLabel": "\u68C0\u7D22\u95EE\u9898",
810
+ "kbRetrieval.queryPlaceholder": "\u68C0\u7D22\u95EE\u9898\uFF0CEnter \u8FD0\u884C",
811
+ "kbRetrieval.rerankLabel": "\u91CD\u6392",
812
+ "kbRetrieval.rerankThresholdOff": "\u9608\u503C \u5173 \xB7 \u5B58\u6D3B {p0}",
813
+ "kbRetrieval.rerankThresholdOn": "\u9608\u503C {p0} \xB7 \u5B58\u6D3B {p1}",
814
+ "kbRetrieval.running": "\u8FD0\u884C\u4E2D\u2026",
815
+ "kbRetrieval.thresholdLabel": "\u5206\u6570\u9608\u503C",
816
+ "kbRetrieval.thresholdValue": "\u9608\u503C N/A",
817
+ "kbRetrieval.vectorHint": "\u8BED\u4E49\uFF1A\u8DE8\u8BED\u8A00/\u65E0\u7CBE\u786E\u8BCD",
818
+ "kbRetrieval.vectorPercent": "\u8BED\u4E49 {p0}",
819
+ "kbRetrieval.weightValue": "\u5411\u91CF {p0}% / \u5173\u952E\u8BCD {p1}%",
820
+ /* ── kbReview ── */
821
+ "kbReview.assignee": "\u5206\u914D\u4EBA",
822
+ "kbReview.doneNext": "\u5B8C\u6210\u5E76\u4E0B\u4E00\u6761",
823
+ "kbReview.empty": "\u6CA1\u6709\u5F85\u5BA1\u67E5\u6761\u76EE",
824
+ "kbReview.emptyAssignee": "\u8BE5\u5206\u914D\u4EBA\u4E0B\u6CA1\u6709\u6761\u76EE",
825
+ "kbReview.emptyQueue": "\u961F\u5217\u4E3A\u7A7A",
826
+ "kbReview.kbCloseHint": "\u5173\u95ED\u63D0\u793A",
827
+ "kbReview.kbSelectOption": "\u9009\u62E9\u9009\u9879",
828
+ "kbReview.kbSwitchItem": "\u5207\u6362\u6761\u76EE",
829
+ "kbReview.kbToggleHint": "\u663E\u793A/\u9690\u85CF\u672C\u63D0\u793A",
830
+ "kbReview.shortcuts": "? \u5FEB\u6377\u952E",
831
+ "kbReview.typeAnswer": "\u56DE\u7B54",
832
+ "kbReview.typeMessage": "\u6D88\u606F",
833
+ "kbReview.typeTrace": "\u8F68\u8FF9",
834
+ "kbReview.unassigned": "\u672A\u5206\u914D",
835
+ /* ── kbSandbox ── */
836
+ "kbSandbox.noResolver": "\u5BBF\u4E3B\u672A\u63D0\u4F9B ui:// \u89E3\u6790\u5668",
837
+ "kbSandbox.notReady": "kb-sandbox: \u5E94\u7528\u672A\u5C31\u7EEA",
838
+ "kbSandbox.resolveFailed": "ui:// \u89E3\u6790\u5931\u8D25\uFF1A{p0}",
839
+ "kbSandbox.timeout": "kb-sandbox: \u8C03\u7528\u8D85\u65F6\uFF08{p0}ms\uFF09",
840
+ "kbSandbox.title": "MCP App \u6C99\u7BB1",
841
+ /* ── kbSegment ── */
842
+ "kbSegment.avgLength": "\u5747\u957F {p0}",
843
+ "kbSegment.childNote": "\u5B50\u5206\u6BB5\u6309\u957F\u5EA6\u81EA\u52A8\u751F\u6210",
844
+ "kbSegment.cleanBlankLines": "\u5408\u5E76\u8FDE\u7EED\u7A7A\u884C",
845
+ "kbSegment.cleanEmails": "\u53BB\u9664\u90AE\u7BB1",
846
+ "kbSegment.cleanLinks": "\u53BB\u9664\u94FE\u63A5",
847
+ "kbSegment.empty": "\u6837\u672C\u4E3A\u7A7A\uFF0C\u6682\u65E0\u53EF\u9884\u89C8\u5206\u6BB5",
848
+ "kbSegment.maxLengthLabel": "\u6700\u5927\u957F\u5EA6",
849
+ "kbSegment.maxLengthPlaceholder": "\u5206\u6BB5\u6700\u5927\u957F\u5EA6",
850
+ "kbSegment.modeAuto": "\u81EA\u52A8",
851
+ "kbSegment.modeCustom": "\u81EA\u5B9A\u4E49",
852
+ "kbSegment.modeLabel": "\u5206\u6BB5\u6A21\u5F0F",
853
+ "kbSegment.modeNote": "\u5206\u6BB5\u6A21\u5F0F\u521B\u5EFA\u540E\u4E0D\u53EF\u66F4\u6539\uFF0C\u53C2\u6570\u53EF\u968F\u65F6\u8C03\u6574",
854
+ "kbSegment.modeParentChild": "\u7236\u5B50",
855
+ "kbSegment.overlapInvalid": "\u91CD\u53E0\u9700\u5C0F\u4E8E\u6700\u5927\u957F\u5EA6",
856
+ "kbSegment.overlapLabel": "\u91CD\u53E0",
857
+ "kbSegment.overlapPlaceholder": "\u5206\u6BB5\u91CD\u53E0",
858
+ "kbSegment.previewNote": "\u5171 {p0} \u6BB5\uFF0C\u4EC5\u9884\u89C8\u524D {p1} \u6BB5",
859
+ "kbSegment.segmentsCount": "{p0} \u6BB5",
860
+ "kbSegment.separatorLabel": "\u5206\u9694\u7B26",
861
+ "kbSegment.separatorPlaceholder": "\u5206\u6BB5\u5206\u9694\u7B26",
862
+ "kbSegment.toggleTip": "\u70B9\u51FB\u5C55\u5F00/\u6536\u8D77",
863
+ /* ── kbSources ── */
864
+ "kbSources.cited": "\u88AB\u5F15 \xD7{p0}",
865
+ "kbSources.empty": "\u4E0B\u4E00\u6761\u7B54\u6848\u5F15\u7528\u7684\u6BB5\u843D\u5C06\u51FA\u73B0\u5728\u8FD9\u91CC",
866
+ /* ── kbSql ── */
867
+ "kbSql.adminOnly": "\u4EC5\u7BA1\u7406\u5458\u53EF\u89C1",
868
+ "kbSql.applyFix": "\u5E94\u7528\u4FEE\u590D\u5E76\u91CD\u8DD1",
869
+ "kbSql.confirmRerun": "\u786E\u8BA4\u5E76\u91CD\u8DD1",
870
+ "kbSql.editRerun": "\u7F16\u8F91\u91CD\u8DD1",
871
+ "kbSql.fixReady": "\u68C0\u6D4B\u5230\u4E0A\u7248\u62A5\u9519\uFF0C\u4FEE\u590D\u5EFA\u8BAE\u5DF2\u5C31\u7EEA",
872
+ "kbSql.generated": "\u751F\u6210\u7684 SQL",
873
+ /* ── kbTrace ── */
874
+ "kbTrace.empty": "\u6682\u65E0\u8C03\u7528\u94FE\u6570\u636E",
875
+ "kbTrace.hits": "\u547D\u4E2D {p0}",
876
+ /* ── kbVisibility ── */
877
+ "kbVisibility.adminOnlyNote": "\u4EE5\u4E0A\u5BF9\u7167\u4EC5\u9650 admin \u5BA1\u8BA1",
878
+ "kbVisibility.adminWarn": "admin \u5BA1\u8BA1\u89C6\u56FE\u2014\u2014\u547D\u4E2D\u5DEE\u5F02\u5BF9\u7167\u5BF9\u666E\u901A\u7528\u6237\u6784\u6210\u6CC4\u9732\uFF0C\u52FF\u5D4C\u5165\u7EC8\u7AEF\u7528\u6237\u754C\u9762",
879
+ "kbVisibility.failOpenNote": "fail-open\uFF1AKendra \u65E0\u8EAB\u4EFD\u4E0A\u4E0B\u6587\u8FD4\u56DE\u5168\u90E8\u6587\u6863\u2014\u2014\u68C0\u7D22\u5FC5\u987B\u643A\u5E26\u670D\u52A1\u7AEF\u8EAB\u4EFD",
880
+ "kbVisibility.focusColumn": "\u805A\u7126\u8EAB\u4EFD {p0} \u7684\u5217",
881
+ "kbVisibility.layerValue": "\u8FC7\u6EE4\u5C42\uFF1A{p0}",
882
+ "kbVisibility.leakageNote": "\u8BA1\u6570\u5DEE\u5F02\u5373 volume leakage\uFF1A\u5BF9\u666E\u901A\u7528\u6237\u53EA\u53EF\u7ED9\u300C\u5DF2\u6309\u6743\u9650\u8FC7\u6EE4\u300D\u6052\u5B9A\u6587\u6848\uFF0C\u7F13\u89E3\u53EA\u6709 padding \u53D6\u6574",
883
+ "kbVisibility.postFilterNote": "post-filter\uFF1AtopK \u88AB\u65E0\u6743\u7ED3\u679C\u5360\u7528\u4E14\u76F8\u4F3C\u5EA6\u5206\u6570\u53EF\u88AB\u89C2\u5BDF",
884
+ "kbVisibility.queryLabel": "\u67E5\u8BE2\uFF1A{p0}",
885
+ "kbVisibility.safeCount": "\u5B89\u5168\u8BA1\u6570 {p0}",
886
+ "kbVisibility.sourceUnavailable": "\u539F\u6587\u4E0D\u53EF\u7528",
887
+ "kbVisibility.unnamedHit": "\u672A\u547D\u540D\u547D\u4E2D",
888
+ /* ── kbWhoCan ── */
889
+ "kbWhoCan.check": "\u68C0\u67E5",
890
+ "kbWhoCan.checkIdentity": "\u68C0\u67E5\u8EAB\u4EFD",
891
+ "kbWhoCan.daysUntil": "{p0} \u5929\u540E",
892
+ "kbWhoCan.deniedBy": "\u88AB\u7B56\u7565\u62D2\u7EDD\uFF1A{p0}",
893
+ "kbWhoCan.denyVeto": "\u88AB Deny \u4E00\u7968\u5426\u51B3",
894
+ "kbWhoCan.direct": "\u76F4\u63A5",
895
+ "kbWhoCan.expiresSoon": "\u6700\u8FD1\u5230\u671F {p0}",
896
+ "kbWhoCan.hoursUntil": "{p0} \u5C0F\u65F6\u540E",
897
+ "kbWhoCan.inherit": "\u7EE7\u627F",
898
+ "kbWhoCan.link": "\u94FE\u63A5",
899
+ "kbWhoCan.noDeny": "\u65E0 Deny \u751F\u6548",
900
+ "kbWhoCan.noIdentity": "\u672A\u63D0\u4F9B\u53EF\u68C0\u67E5\u7684\u8EAB\u4EFD",
901
+ "kbWhoCan.none": "\u672A\u547D\u4E2D\u4EFB\u4F55\u6388\u6743\u2014\u2014\u9ED8\u8BA4\u62D2\u7EDD",
902
+ "kbWhoCan.recheckTip": "\u91CD\u65B0\u68C0\u67E5\u5F53\u524D\u8EAB\u4EFD\u7684\u6709\u6548\u6743\u9650",
903
+ "kbWhoCan.stackRule": "\u53E0\u52A0\u89C4\u5219\uFF1A\u591A\u6765\u6E90\u5E76\u96C6 \u2192 {p0}\uFF1B{p1}",
904
+ /* ── mentions ── */
905
+ "mentions.create": "\u521B\u5EFA\u201C{p0}\u201D",
906
+ "mentions.customBadge": "\u81EA\u5B9A\u4E49",
907
+ "mentions.loading": "\u52A0\u8F7D\u4E2D\u2026",
908
+ /* ── notification ── */
909
+ "notification.groupBusy": "\u64CD\u4F5C\u7ED3\u675F\u540E\u53EF\u4EE5\u6536\u8D77\u8FD9\u7EC4\u901A\u77E5\u3002",
910
+ "notification.groupUnread": "{count} \u6761\u540C\u7EC4\u901A\u77E5\uFF0C{unread} \u6761\u672A\u8BFB",
911
+ "notification.groupCount": "{count} \u6761\u540C\u7EC4\u901A\u77E5",
912
+ "notification.groupExpanded": "\u6536\u8D77\u8FD9\u7EC4\u901A\u77E5",
913
+ "notification.ariaLabel": "\u901A\u77E5",
914
+ "notification.viewDetails": "\u67E5\u770B\u8BE6\u60C5",
915
+ /* ── pagination ── */
916
+ "pagination.next": "\u4E0B\u4E00\u9875",
917
+ "pagination.pageSize": "{p0} \u6761/\u9875",
918
+ "pagination.prev": "\u4E0A\u4E00\u9875",
919
+ /* ── select ── */
920
+ "select.fieldLabel": "\u9009\u62E9\u9009\u9879",
921
+ "select.noMatch": "\u65E0\u5339\u914D\u9879",
922
+ "select.remove": "\u79FB\u9664 {p0}",
923
+ "select.searchPlaceholder": "\u641C\u7D22\u2026",
924
+ /* ── cascader / tree-select ── */
925
+ "cascader.placeholder": "\u8BF7\u9009\u62E9",
926
+ "cascader.noMatch": "\u65E0\u5339\u914D",
927
+ "cascader.search": "\u641C\u7D22",
928
+ "treeSelect.placeholder": "\u8BF7\u9009\u62E9",
929
+ "treeSelect.noMatch": "\u65E0\u5339\u914D",
930
+ "treeSelect.search": "\u641C\u7D22",
931
+ /* ── tagInput ── */
932
+ "tagInput.ariaLabel": "\u6807\u7B7E\u8F93\u5165\uFF0C\u5171 {p0} \u4E2A",
933
+ "tagInput.remove": "\u79FB\u9664 {p0}",
934
+ "tagInput.field": "\u6DFB\u52A0\u6807\u7B7E",
935
+ "tagInput.added": "\u5DF2\u6DFB\u52A0 {p0} \u4E2A\u6807\u7B7E\u3002",
936
+ "tagInput.removed": "\u5DF2\u79FB\u9664 {p0}\u3002",
937
+ "tagInput.duplicate": "\u5DF2\u6709\u300C{p0}\u300D\uFF0C\u53EF\u4EE5\u7F16\u8F91\u540E\u91CD\u8BD5\u3002",
938
+ "tagInput.limit": "\u6700\u591A {p0} \u4E2A\u6807\u7B7E\uFF0C\u8BF7\u5148\u79FB\u9664\u4E00\u4E2A\u3002",
939
+ /* ── upload ── */
940
+ "upload.remove": "\u79FB\u9664 {p0}",
941
+ "upload.tooBig": "\u6587\u4EF6\u8D85\u8FC7 {p0}",
942
+ "upload.tooMany": "\u6700\u591A {p0} \u4E2A\u6587\u4EF6",
943
+ "upload.typeNotAllowed": "\u6587\u4EF6\u7C7B\u578B\u4E0D\u652F\u6301"
944
+ };
945
+ var current = { ...ICEN_LOCALE_ZH_CN };
946
+ function t(key, vars) {
947
+ const raw = current[key] ?? ICEN_LOCALE_ZH_CN[key];
948
+ if (vars == null || Array.isArray(raw)) return raw;
949
+ return raw.replace(/\{(\w+)\}/g, (m, name) => name in vars ? String(vars[name]) : m);
950
+ }
951
+
952
+ // src/behaviors/svg-parse.ts
953
+ function parseSvg(source) {
954
+ if (typeof document === "undefined" || typeof DOMParser === "undefined") return null;
955
+ const trimmed = source.trimStart();
956
+ if (!trimmed.startsWith("<svg")) return null;
957
+ const src = /^<svg(?![^>]*\bxmlns[=:])/i.test(trimmed) ? trimmed.replace(/^<svg/i, '<svg xmlns="http://www.w3.org/2000/svg"') : trimmed;
958
+ let parsed;
959
+ try {
960
+ parsed = new DOMParser().parseFromString(src, "image/svg+xml");
961
+ } catch {
962
+ return null;
963
+ }
964
+ const root = parsed.documentElement;
965
+ if (!root || root.tagName.toLowerCase() !== "svg" || parsed.querySelector("parsererror")) return null;
966
+ const sanitize = (el) => {
967
+ for (const attr of Array.from(el.attributes)) {
968
+ const name = attr.name.toLowerCase();
969
+ if (name.startsWith("on")) el.removeAttribute(attr.name);
970
+ if ((name === "href" || name === "xlink:href") && attr.value.trim().toLowerCase().startsWith("javascript:")) {
971
+ el.removeAttribute(attr.name);
972
+ }
973
+ }
974
+ for (const child of Array.from(el.children)) {
975
+ const tag = child.tagName.toLowerCase();
976
+ if (tag === "script" || tag === "foreignobject") {
977
+ child.remove();
978
+ continue;
979
+ }
980
+ sanitize(child);
981
+ }
982
+ };
983
+ sanitize(root);
984
+ return document.importNode(root, true);
985
+ }
986
+
1
987
  // src/behaviors/ai-core.ts
2
988
  var USAGE_KEYS = ["input", "output", "cacheRead", "cacheWrite", "reasoning", "total"];
3
989
  function addUsage(sum2, u) {
@@ -8,54 +994,23 @@ function addUsage(sum2, u) {
8
994
  }
9
995
  return out;
10
996
  }
11
- var svg = (body) => `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">${body}</svg>`;
12
- var ICON_TERMINAL = svg('<path d="m4 17 6-6-6-6"/><path d="M12 19h8"/>');
13
- var ICON_FILE = svg(
14
- '<path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7z"/><path d="M14 2v4a2 2 0 0 0 2 2h4"/>'
15
- );
16
- var ICON_FILE_PEN = svg(
17
- '<path d="M12.5 22H6a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8l5 5v3.5"/><path d="M14 2v4a2 2 0 0 0 2 2h4"/><path d="M19 6.5 16.5 4"/><path d="M21.378 16.626a1 1 0 0 0-3.004-3.004l-4.01 4.012a2 2 0 0 0-.506.854l-.837 2.87a.5.5 0 0 0 .62.62l2.87-.837a2 2 0 0 0 .854-.506z"/>'
18
- );
19
- var ICON_FILE_PLUS = svg(
20
- '<path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7z"/><path d="M14 2v4a2 2 0 0 0 2 2h4"/><path d="M9 15h6"/><path d="M12 12v6"/>'
21
- );
22
- var ICON_TRASH = svg(
23
- '<path d="M3 6h18"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"/><path d="M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/><path d="M10 11v6"/><path d="M14 11v6"/>'
24
- );
25
- var ICON_SEARCH = svg('<circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/>');
26
- var ICON_FOLDER_SEARCH = svg(
27
- '<path d="M11 20H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3.9a2 2 0 0 1 1.69.9l.81 1.2a2 2 0 0 0 1.67.9H20a2 2 0 0 1 2 2v4"/><circle cx="17" cy="17" r="3"/><path d="m21 21-1.9-1.9"/>'
28
- );
29
- var ICON_SCAN_SEARCH = svg(
30
- '<path d="M3 7V5a2 2 0 0 1 2-2h2"/><path d="M17 3h2a2 2 0 0 1 2 2v2"/><path d="M21 17v2a2 2 0 0 1-2 2h-2"/><path d="M7 21H5a2 2 0 0 1-2-2v-2"/><circle cx="12" cy="12" r="3"/><path d="m16 16-1.9-1.9"/>'
31
- );
32
- var ICON_GLOBE = svg(
33
- '<circle cx="12" cy="12" r="10"/><path d="M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20"/><path d="M2 12h20"/>'
34
- );
35
- var ICON_DOWNLOAD = svg(
36
- '<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><path d="m7 10 5 5 5-5"/><path d="M12 15V3"/>'
37
- );
38
- var ICON_BLOCKS = svg(
39
- '<rect width="7" height="7" x="4" y="4" rx="1"/><rect width="7" height="7" x="13" y="4" rx="1"/><rect width="7" height="7" x="4" y="13" rx="1"/><rect width="7" height="7" x="13" y="13" rx="1"/>'
40
- );
41
- var ICON_ZAP = svg(
42
- '<path d="M4 14a1 1 0 0 1-.78-1.63l9.9-10.2a.5.5 0 0 1 .86.46l-1.92 6.02A1 1 0 0 0 13 10h7a1 1 0 0 1 .78 1.63l-9.9 10.2a.5.5 0 0 1-.86-.46l1.92-6.02A1 1 0 0 0 11 14z"/>'
43
- );
44
- var ICON_LIST = svg(
45
- '<path d="M3 12h.01"/><path d="M3 18h.01"/><path d="M3 6h.01"/><path d="M8 12h13"/><path d="M8 18h13"/><path d="M8 6h13"/>'
46
- );
47
- var ICON_LIST_CHECKS = svg(
48
- '<path d="m3 17 2 2 4-4"/><path d="m3 7 2 2 4-4"/><path d="M13 6h8"/><path d="M13 12h8"/><path d="M13 18h8"/>'
49
- );
50
- var ICON_BOT = svg(
51
- '<path d="M12 8V4H8"/><rect width="16" height="12" x="4" y="8" rx="2"/><path d="M2 14h2"/><path d="M20 14h2"/><path d="M15 13v2"/><path d="M9 13v2"/>'
52
- );
53
- var ICON_CHART = svg(
54
- '<path d="M3 3v18h18"/><path d="M7 15l4-6 3 4 5-8"/>'
55
- );
56
- var ICON_FILE_TEXT = svg(
57
- '<path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7z"/><path d="M14 2v4a2 2 0 0 0 2 2h4"/><path d="M10 9H8"/><path d="M16 13H8"/><path d="M16 17H8"/>'
58
- );
997
+ var ICON_TERMINAL = iconHTML("terminal");
998
+ var ICON_FILE = iconHTML("file");
999
+ var ICON_FILE_PEN = iconHTML("edit");
1000
+ var ICON_FILE_PLUS = iconHTML("plus");
1001
+ var ICON_TRASH = iconHTML("trash");
1002
+ var ICON_SEARCH = iconHTML("search");
1003
+ var ICON_FOLDER_SEARCH = iconHTML("folder");
1004
+ var ICON_SCAN_SEARCH = iconHTML("search");
1005
+ var ICON_GLOBE = iconHTML("globe");
1006
+ var ICON_DOWNLOAD = iconHTML("download");
1007
+ var ICON_BLOCKS = iconHTML("server");
1008
+ var ICON_ZAP = iconHTML("sparkle");
1009
+ var ICON_LIST = iconHTML("list");
1010
+ var ICON_LIST_CHECKS = iconHTML("list");
1011
+ var ICON_BOT = iconHTML("agent");
1012
+ var ICON_CHART = iconHTML("chart-line");
1013
+ var ICON_FILE_TEXT = iconHTML("document");
59
1014
  function isObj(v) {
60
1015
  return typeof v === "object" && v !== null;
61
1016
  }
@@ -105,32 +1060,32 @@ var sum = (fn) => {
105
1060
  return (input) => fn(input) ?? "";
106
1061
  };
107
1062
  var BUILTIN_KINDS = {
108
- shell: { label: "\u547D\u4EE4", icon: ICON_TERMINAL, tint: "accent", summarize: sum(summarizeShell) },
109
- read: { label: "\u8BFB\u53D6", icon: ICON_FILE, tint: "info", summarize: sum(summarizeRead) },
110
- edit: { label: "\u7F16\u8F91", icon: ICON_FILE_PEN, tint: "warning", summarize: sum(summarizePath) },
111
- write: { label: "\u5199\u5165", icon: ICON_FILE_PLUS, tint: "warning", summarize: sum(summarizePath) },
112
- rm: { label: "\u5220\u9664", icon: ICON_TRASH, tint: "error", summarize: sum(summarizePath) },
113
- grep: { label: "\u641C\u7D22", icon: ICON_SEARCH, tint: "info", summarize: sum(summarizeGrep) },
114
- glob: { label: "\u5339\u914D", icon: ICON_FOLDER_SEARCH, tint: "info", summarize: sum((i) => pickStr(i, ["pattern", "glob", "path"])) },
115
- browser: { label: "\u6D4F\u89C8", icon: ICON_GLOBE, tint: "accent", summarize: sum((i) => pickStr(i, ["url", "uri", "target"])) },
116
- search: { label: "\u68C0\u7D22", icon: ICON_SCAN_SEARCH, tint: "accent", summarize: sum((i) => pickStr(i, ["query", "q", "pattern"])) },
117
- fetch: { label: "\u8BF7\u6C42", icon: ICON_DOWNLOAD, tint: "info", summarize: sum((i) => pickStr(i, ["url", "uri", "endpoint"])) },
1063
+ shell: { label: t("aiCore.kindShell"), icon: ICON_TERMINAL, tint: "accent", summarize: sum(summarizeShell) },
1064
+ read: { label: t("aiCore.kindRead"), icon: ICON_FILE, tint: "info", summarize: sum(summarizeRead) },
1065
+ edit: { label: t("aiCore.kindEdit"), icon: ICON_FILE_PEN, tint: "warning", summarize: sum(summarizePath) },
1066
+ write: { label: t("aiCore.kindWrite"), icon: ICON_FILE_PLUS, tint: "warning", summarize: sum(summarizePath) },
1067
+ rm: { label: t("aiCore.kindDelete"), icon: ICON_TRASH, tint: "error", summarize: sum(summarizePath) },
1068
+ grep: { label: t("aiCore.kindGrep"), icon: ICON_SEARCH, tint: "info", summarize: sum(summarizeGrep) },
1069
+ glob: { label: t("aiCore.kindGlob"), icon: ICON_FOLDER_SEARCH, tint: "info", summarize: sum((i) => pickStr(i, ["pattern", "glob", "path"])) },
1070
+ browser: { label: t("aiCore.kindBrowser"), icon: ICON_GLOBE, tint: "accent", summarize: sum((i) => pickStr(i, ["url", "uri", "target"])) },
1071
+ search: { label: t("aiCore.kindSearch"), icon: ICON_SCAN_SEARCH, tint: "accent", summarize: sum((i) => pickStr(i, ["query", "q", "pattern"])) },
1072
+ fetch: { label: t("aiCore.kindFetch"), icon: ICON_DOWNLOAD, tint: "info", summarize: sum((i) => pickStr(i, ["url", "uri", "endpoint"])) },
118
1073
  mcp: { label: "MCP", icon: ICON_BLOCKS, tint: "muted", summarize: sum((i) => pickStr(i, ["tool", "method", "name"])) },
119
- skill: { label: "\u6280\u80FD", icon: ICON_ZAP, tint: "accent", summarize: sum((i) => pickStr(i, ["skill", "name", "command"])) },
1074
+ skill: { label: t("aiCore.kindSkill"), icon: ICON_ZAP, tint: "accent", summarize: sum((i) => pickStr(i, ["skill", "name", "command"])) },
120
1075
  todo: {
121
- label: "\u5F85\u529E",
1076
+ label: t("aiCore.kindTodo"),
122
1077
  icon: ICON_LIST,
123
1078
  tint: "info",
124
1079
  summarize: sum((input) => {
125
1080
  const items = input && typeof input === "object" && Array.isArray(input.items) ? input.items : Array.isArray(input) ? input : [];
126
1081
  const done = items.filter((it) => it?.status === "done").length;
127
- return items.length > 0 ? `${done}/${items.length} \u5B8C\u6210` : "";
1082
+ return items.length > 0 ? t("aiCore.todoProgress", { p0: done, p1: items.length }) : "";
128
1083
  })
129
1084
  },
130
- plan: { label: "\u8BA1\u5212", icon: ICON_LIST_CHECKS, tint: "info" },
131
- subagent: { label: "\u5B50\u4EE3\u7406", icon: ICON_BOT, tint: "accent", summarize: sum((i) => pickStr(i, ["task", "description", "prompt", "message", "subagent_type"])) },
132
- note: { label: "\u7B14\u8BB0", icon: ICON_FILE_TEXT, tint: "muted" },
133
- chart: { label: "\u56FE\u8868", icon: ICON_CHART, tint: "info", summarize: sum((i) => pickStr(i, ["title", "name"])) }
1085
+ plan: { label: t("aiCore.kindPlan"), icon: ICON_LIST_CHECKS, tint: "info" },
1086
+ subagent: { label: t("aiCore.kindSubagent"), icon: ICON_BOT, tint: "accent", summarize: sum((i) => pickStr(i, ["task", "description", "prompt", "message", "subagent_type"])) },
1087
+ note: { label: t("aiCore.kindNote"), icon: ICON_FILE_TEXT, tint: "muted" },
1088
+ chart: { label: t("aiCore.kindChart"), icon: ICON_CHART, tint: "info", summarize: sum((i) => pickStr(i, ["title", "name"])) }
134
1089
  };
135
1090
  var kindRegistry = new Map(Object.entries(BUILTIN_KINDS));
136
1091
  function normalizeUsage(raw) {
@@ -185,51 +1140,45 @@ function contextEstimate(usage) {
185
1140
  return (u.input ?? 0) + (u.cacheRead ?? 0) + (u.cacheWrite ?? 0) + (u.output ?? 0) + (u.reasoning ?? 0);
186
1141
  }
187
1142
  function h(tag, className, text) {
1143
+ if (typeof document === "undefined") throw new Error("h() \u4EC5\u6D4F\u89C8\u5668\u73AF\u5883\u53EF\u7528\uFF08SSR \u65F6\u7531\u8C03\u7528\u65B9\u5B88\u536B\uFF0C\u89C1\u6A21\u5757\u5934\u6CE8\u91CA\uFF09");
188
1144
  const node = document.createElement(tag);
189
1145
  if (className) node.className = className;
190
1146
  if (text != null) node.textContent = text;
191
1147
  return node;
192
1148
  }
193
- function svgIcon(svg2) {
194
- if (typeof document === "undefined" || typeof DOMParser === "undefined") return null;
195
- let parsed;
196
- try {
197
- parsed = new DOMParser().parseFromString(svg2, "image/svg+xml");
198
- } catch {
199
- return null;
200
- }
201
- const root = parsed.documentElement;
202
- if (!root || root.tagName.toLowerCase() !== "svg" || parsed.querySelector("parsererror")) {
203
- return null;
204
- }
205
- const sanitize = (el) => {
206
- for (const attr of Array.from(el.attributes)) {
207
- const name = attr.name.toLowerCase();
208
- if (name.startsWith("on")) el.removeAttribute(attr.name);
209
- if ((name === "href" || name === "xlink:href") && attr.value.trim().toLowerCase().startsWith("javascript:")) {
210
- el.removeAttribute(attr.name);
211
- }
212
- }
213
- for (const child of Array.from(el.children)) {
214
- const tag = child.tagName.toLowerCase();
215
- if (tag === "script" || tag === "foreignobject") {
216
- child.remove();
217
- continue;
218
- }
219
- sanitize(child);
220
- }
221
- };
222
- sanitize(root);
223
- return document.importNode(root, true);
1149
+ function svgIcon(svg) {
1150
+ return parseSvg(svg);
224
1151
  }
225
1152
 
226
1153
  // src/behaviors/popover.ts
1154
+ function revealPopoverItem(item, scrollport, opts = {}) {
1155
+ if (typeof document === "undefined") return;
1156
+ if (opts.focus) item.focus({ preventScroll: true });
1157
+ const rect = item.getBoundingClientRect(), bounds = scrollport.getBoundingClientRect();
1158
+ const style = getComputedStyle(scrollport);
1159
+ const inset = (value, extent) => {
1160
+ const amount = Number.parseFloat(value) || 0;
1161
+ return value.endsWith("%") ? amount * extent / 100 : amount;
1162
+ };
1163
+ if (opts.axis !== "inline") {
1164
+ const top = bounds.top + scrollport.clientTop + inset(style.scrollPaddingTop, scrollport.clientHeight);
1165
+ const bottom = bounds.top + scrollport.clientTop + scrollport.clientHeight - inset(style.scrollPaddingBottom, scrollport.clientHeight);
1166
+ if (rect.top < top) scrollport.scrollTop -= top - rect.top;
1167
+ else if (rect.bottom > bottom) scrollport.scrollTop += rect.bottom - bottom;
1168
+ }
1169
+ if (opts.axis === "inline" || opts.axis === "both") {
1170
+ const left = bounds.left + scrollport.clientLeft + inset(style.scrollPaddingLeft, scrollport.clientWidth);
1171
+ const right = bounds.left + scrollport.clientLeft + scrollport.clientWidth - inset(style.scrollPaddingRight, scrollport.clientWidth);
1172
+ if (rect.left < left) scrollport.scrollLeft -= left - rect.left;
1173
+ else if (rect.right > right) scrollport.scrollLeft += rect.right - right;
1174
+ }
1175
+ }
227
1176
  var PANEL_SIZING_ATTRS = {
228
- width: "data-panel-width",
229
- minWidth: "data-panel-min",
230
- maxWidth: "data-panel-max",
231
- minHeight: "data-panel-min-height",
232
- maxHeight: "data-panel-max-height"
1177
+ width: "data-icen-panel-width",
1178
+ minWidth: "data-icen-panel-min",
1179
+ maxWidth: "data-icen-panel-max",
1180
+ minHeight: "data-icen-panel-min-height",
1181
+ maxHeight: "data-icen-panel-max-height"
233
1182
  };
234
1183
  function readPanelSizing(el) {
235
1184
  const out = {};
@@ -289,10 +1238,10 @@ function computePopoverLayout(anchor, viewport, opts = {}) {
289
1238
  const preferredSide = opts.side ?? "top";
290
1239
  const align = opts.align ?? "start";
291
1240
  if (preferredSide === "left" || preferredSide === "right") {
1241
+ const minWidth2 = Math.max(1, opts.minWidth ?? DEFAULT_MIN_WIDTH);
292
1242
  const availableLeft = Math.max(0, anchor.left - margin - offset);
293
1243
  const availableRight = Math.max(0, viewport.width - anchor.right - margin - offset);
294
- const side2 = (preferredSide === "left" ? availableLeft : availableRight) >= DEFAULT_MIN_WIDTH ? preferredSide : preferredSide === "left" ? "right" : "left";
295
- const minWidth2 = Math.max(1, opts.minWidth ?? DEFAULT_MIN_WIDTH);
1244
+ const side2 = (preferredSide === "left" ? availableLeft : availableRight) >= minWidth2 ? preferredSide : preferredSide === "left" ? "right" : "left";
296
1245
  const maxWidth2 = Math.min(
297
1246
  Math.max(opts.maxWidth ?? DEFAULT_MAX_WIDTH, minWidth2),
298
1247
  side2 === "left" ? availableLeft : availableRight
@@ -321,7 +1270,7 @@ function computePopoverLayout(anchor, viewport, opts = {}) {
321
1270
  const minHeight = Math.min(Math.max(80, opts.minHeight ?? DEFAULT_MIN_HEIGHT), availableHeight);
322
1271
  const requestedMaxHeight = Math.max(minHeight, opts.maxHeight ?? DEFAULT_MAX_HEIGHT);
323
1272
  const fallbackHeight = Math.min(260, requestedMaxHeight);
324
- const contentHeight = Math.max(opts.contentHeightHint ?? 0, fallbackHeight);
1273
+ const contentHeight = opts.contentHeightHint != null && opts.contentHeightHint > 0 ? opts.contentHeightHint : fallbackHeight;
325
1274
  const desiredHeight = clamp(contentHeight, minHeight, Math.min(requestedMaxHeight, availableHeight));
326
1275
  const side = chooseSide(preferredSide, availableTop, availableBottom, desiredHeight);
327
1276
  const sideSpace = side === "top" ? availableTop : availableBottom;
@@ -338,6 +1287,9 @@ function computePopoverLayout(anchor, viewport, opts = {}) {
338
1287
  return { side, left, top, width, maxHeight };
339
1288
  }
340
1289
  var openPanels = /* @__PURE__ */ new Map();
1290
+ var closingPanels = /* @__PURE__ */ new Map();
1291
+ var EXIT_FALLBACK_MS = 240;
1292
+ var menuCloser = null;
341
1293
  function rectFromElement(el) {
342
1294
  const r = el.getBoundingClientRect();
343
1295
  return { left: r.left, top: r.top, right: r.right, bottom: r.bottom, width: r.width, height: r.height };
@@ -355,21 +1307,54 @@ function relayout(state) {
355
1307
  closePopover(state.panel);
356
1308
  return;
357
1309
  }
358
- const layout = computePopoverLayout(
1310
+ let layout = computePopoverLayout(
359
1311
  anchor,
360
1312
  { width: window.innerWidth, height: window.innerHeight },
361
1313
  state.opts
362
1314
  );
363
1315
  const { panel } = state;
1316
+ const scrollPositions = [panel, ...panel.querySelectorAll("*")].filter((node) => node.scrollTop !== 0 || node.scrollLeft !== 0).map((node) => ({ node, top: node.scrollTop, left: node.scrollLeft }));
1317
+ panel.style.width = `${layout.width}px`;
1318
+ if (state.opts.contentHeightHint == null && (layout.side === "top" || layout.side === "bottom")) {
1319
+ panel.style.maxHeight = `${Math.min(state.opts.maxHeight ?? DEFAULT_MAX_HEIGHT, Math.max(80, window.innerHeight - (state.opts.margin ?? 12) * 2))}px`;
1320
+ const measured = panel.offsetHeight;
1321
+ if (measured > 0) layout = computePopoverLayout(anchor, { width: window.innerWidth, height: window.innerHeight }, { ...state.opts, contentHeightHint: measured });
1322
+ }
364
1323
  panel.style.left = `${layout.left}px`;
365
- panel.style.top = `${layout.top}px`;
366
1324
  panel.style.width = `${layout.width}px`;
367
1325
  panel.style.maxHeight = `${layout.maxHeight}px`;
368
- panel.dataset.side = layout.side;
1326
+ let top = layout.top;
1327
+ const actualHeight = panel.offsetHeight;
1328
+ if (actualHeight > 0 && (layout.side === "top" || layout.side === "bottom")) {
1329
+ const desired = layout.side === "top" ? anchor.top - (state.opts.offset ?? 8) - actualHeight : anchor.bottom + (state.opts.offset ?? 8);
1330
+ const margin = state.opts.margin ?? 12;
1331
+ top = clamp(desired, margin, window.innerHeight - margin - actualHeight);
1332
+ }
1333
+ panel.style.top = `${top}px`;
1334
+ for (const pos of scrollPositions) {
1335
+ pos.node.scrollTop = pos.top;
1336
+ pos.node.scrollLeft = pos.left;
1337
+ }
1338
+ panel.dataset.icenSide = layout.side;
369
1339
  panel.style.visibility = state.prevVisibility;
370
1340
  }
371
- function onWindowChange() {
372
- openPanels.forEach(relayout);
1341
+ function observeOpenPanel(state) {
1342
+ if (typeof ResizeObserver === "undefined") return;
1343
+ state.resizeObserver = new ResizeObserver(() => {
1344
+ if (state.layoutFrame != null) return;
1345
+ state.layoutFrame = window.requestAnimationFrame(() => {
1346
+ state.layoutFrame = void 0;
1347
+ if (openPanels.get(state.panel) === state) relayout(state);
1348
+ });
1349
+ });
1350
+ state.resizeObserver.observe(state.panel);
1351
+ if (state.anchor instanceof Element) state.resizeObserver.observe(state.anchor);
1352
+ }
1353
+ function onWindowChange(event) {
1354
+ openPanels.forEach((state) => {
1355
+ if (event?.type === "scroll" && event.target instanceof Node && state.panel.contains(event.target)) return;
1356
+ relayout(state);
1357
+ });
373
1358
  }
374
1359
  function onOutsidePointerDown(e) {
375
1360
  const target = e.target;
@@ -381,18 +1366,40 @@ function onOutsidePointerDown(e) {
381
1366
  });
382
1367
  }
383
1368
  function onKeyDown(e) {
384
- if (e.key !== "Escape") return;
1369
+ if (e.key !== "Escape" || e.defaultPrevented || e.isComposing || e.keyCode === 229 || menuCloser) return;
385
1370
  const states = Array.from(openPanels.values());
386
1371
  const top = states[states.length - 1];
387
1372
  if (top) {
388
1373
  e.preventDefault();
1374
+ e.stopPropagation();
389
1375
  closePopover(top.panel);
390
1376
  }
391
1377
  }
392
1378
  function openPopover(panel, options) {
393
1379
  if (typeof document === "undefined") return;
1380
+ const pending = closingPanels.get(panel);
1381
+ if (pending) {
1382
+ window.clearTimeout(pending.timer);
1383
+ panel.removeEventListener("transitionend", pending.onEnd);
1384
+ closingPanels.delete(panel);
1385
+ delete panel.dataset.icenState;
1386
+ openPanels.set(panel, pending.state);
1387
+ panel.hidden = false;
1388
+ panel.style.visibility = "hidden";
1389
+ relayout(pending.state);
1390
+ observeOpenPanel(pending.state);
1391
+ if (openPanels.size === 1) {
1392
+ window.addEventListener("resize", onWindowChange);
1393
+ window.addEventListener("scroll", onWindowChange, true);
1394
+ document.addEventListener("pointerdown", onOutsidePointerDown, true);
1395
+ window.addEventListener("keydown", onKeyDown, true);
1396
+ }
1397
+ const ifs = options.initialFocus;
1398
+ if (ifs && panel.contains(ifs)) ifs.focus({ preventScroll: true });
1399
+ return;
1400
+ }
394
1401
  if (openPanels.has(panel)) closePopover(panel);
395
- const { anchor, onClose, sizing, ...rest } = options;
1402
+ const { anchor, onClose, sizing, initialFocus, restoreFocus, ...rest } = options;
396
1403
  const layoutOpts = sizingToLayout(resolvePanelSizing(panel, sizing), rest);
397
1404
  const placeholder = document.createComment("popover-anchor");
398
1405
  panel.parentNode?.insertBefore(placeholder, panel);
@@ -405,25 +1412,25 @@ function openPopover(panel, options) {
405
1412
  onClose,
406
1413
  placeholder,
407
1414
  wasHidden,
408
- prevVisibility
1415
+ prevVisibility,
1416
+ returnFocus: restoreFocus === false ? null : anchor instanceof HTMLElement ? anchor : document.activeElement instanceof HTMLElement ? document.activeElement : null
409
1417
  };
410
1418
  openPanels.set(panel, state);
411
1419
  document.body.appendChild(panel);
412
1420
  panel.hidden = false;
413
1421
  panel.style.visibility = "hidden";
414
1422
  relayout(state);
1423
+ observeOpenPanel(state);
1424
+ if (initialFocus && panel.contains(initialFocus)) initialFocus.focus({ preventScroll: true });
415
1425
  if (openPanels.size === 1) {
416
1426
  window.addEventListener("resize", onWindowChange);
417
1427
  window.addEventListener("scroll", onWindowChange, true);
418
1428
  document.addEventListener("pointerdown", onOutsidePointerDown, true);
419
- window.addEventListener("keydown", onKeyDown);
1429
+ window.addEventListener("keydown", onKeyDown, true);
420
1430
  }
421
1431
  }
422
- function closePopover(panel) {
423
- if (typeof document === "undefined") return;
424
- const state = openPanels.get(panel);
425
- if (!state) return;
426
- openPanels.delete(panel);
1432
+ function finalizeClose(panel, state) {
1433
+ delete panel.dataset.icenState;
427
1434
  panel.style.visibility = state.prevVisibility;
428
1435
  if (typeof state.wasHidden === "string") panel.setAttribute("hidden", state.wasHidden);
429
1436
  else panel.hidden = state.wasHidden;
@@ -431,55 +1438,90 @@ function closePopover(panel) {
431
1438
  panel.style.top = "";
432
1439
  panel.style.width = "";
433
1440
  panel.style.maxHeight = "";
434
- delete panel.dataset.side;
1441
+ delete panel.dataset.icenSide;
435
1442
  if (state.placeholder.parentNode) {
436
1443
  state.placeholder.parentNode.insertBefore(panel, state.placeholder);
437
1444
  state.placeholder.remove();
438
1445
  }
1446
+ }
1447
+ function closePopover(panel, opts) {
1448
+ if (typeof document === "undefined") return;
1449
+ const state = openPanels.get(panel);
1450
+ if (!state) return;
1451
+ openPanels.delete(panel);
1452
+ state.resizeObserver?.disconnect();
1453
+ if (state.layoutFrame != null) {
1454
+ window.cancelAnimationFrame(state.layoutFrame);
1455
+ state.layoutFrame = void 0;
1456
+ }
1457
+ const ownsFocus = panel.contains(document.activeElement);
1458
+ if (ownsFocus && state.returnFocus?.isConnected) state.returnFocus.focus({ preventScroll: true });
439
1459
  if (openPanels.size === 0) {
440
1460
  window.removeEventListener("resize", onWindowChange);
441
1461
  window.removeEventListener("scroll", onWindowChange, true);
442
1462
  document.removeEventListener("pointerdown", onOutsidePointerDown, true);
443
- window.removeEventListener("keydown", onKeyDown);
1463
+ window.removeEventListener("keydown", onKeyDown, true);
444
1464
  }
445
1465
  state.onClose?.();
446
- }
447
-
448
- // src/behaviors/events.ts
449
- function emitIcen(source, type, detail) {
450
- return source.dispatchEvent(
451
- new CustomEvent(type, { detail, bubbles: true, composed: true, cancelable: true })
452
- );
1466
+ const calm = opts?.immediate || typeof window !== "undefined" && typeof window.matchMedia === "function" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
1467
+ if (calm || !panel.isConnected) {
1468
+ finalizeClose(panel, state);
1469
+ return;
1470
+ }
1471
+ panel.dataset.icenState = "closing";
1472
+ const finalize = () => {
1473
+ const pending = closingPanels.get(panel);
1474
+ if (!pending || pending.state !== state) return;
1475
+ window.clearTimeout(pending.timer);
1476
+ panel.removeEventListener("transitionend", pending.onEnd);
1477
+ closingPanels.delete(panel);
1478
+ finalizeClose(panel, state);
1479
+ };
1480
+ const onEnd = (event) => {
1481
+ if (event.target === panel && event.propertyName === "opacity") finalize();
1482
+ };
1483
+ panel.addEventListener("transitionend", onEnd);
1484
+ closingPanels.set(panel, {
1485
+ state,
1486
+ timer: window.setTimeout(finalize, EXIT_FALLBACK_MS),
1487
+ onEnd
1488
+ });
453
1489
  }
454
1490
 
455
1491
  // src/behaviors/ai-panel.ts
456
1492
  function buildTodoHead(done, total) {
457
- const head = h("div", "ai-todo-head");
458
- head.appendChild(h("span", "ai-todo-progress", `${done}/${total}`));
459
- const bar = h("div", "ai-todo-bar");
1493
+ const head = h("div", "icen-ai-todo-head");
1494
+ head.appendChild(h("span", "icen-ai-todo-progress", `${done}/${total}`));
1495
+ const bar = h("div", "icen-ai-todo-bar");
460
1496
  bar.setAttribute("role", "progressbar");
461
1497
  bar.setAttribute("aria-valuemin", "0");
462
1498
  bar.setAttribute("aria-valuemax", String(total));
463
1499
  bar.setAttribute("aria-valuenow", String(done));
464
- bar.setAttribute("aria-label", "\u4EFB\u52A1\u8FDB\u5EA6");
1500
+ bar.setAttribute("aria-label", t("aiPanel.taskProgress"));
465
1501
  const fill = document.createElement("i");
466
1502
  fill.style.width = total > 0 ? `${Math.round(done / total * 100)}%` : "0%";
467
1503
  bar.appendChild(fill);
468
1504
  head.appendChild(bar);
469
1505
  return head;
470
1506
  }
1507
+ var ICON_TODO_CHECK = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="m3.5 12.5 5 5L20.5 6" pathLength="1"/></svg>';
471
1508
  function buildTodoItem(item, index) {
472
- const row = h("div", `ai-todo-item is-${item.status}`);
473
- row.dataset.index = String(index);
474
- row.appendChild(h("span", "ai-item-status"));
475
- row.appendChild(h("span", "ai-todo-text", item.content));
476
- row.appendChild(h("span", "ai-todo-active", item.activeForm ?? item.content));
1509
+ const row = h("div", `icen-ai-todo-item is-${item.status}`);
1510
+ row.dataset.icenIndex = String(index);
1511
+ row.appendChild(h("span", "icen-ai-item-status"));
1512
+ const check = h("span", "icen-ai-todo-check is-anim");
1513
+ check.setAttribute("aria-hidden", "true");
1514
+ const checkSvg = svgIcon(ICON_TODO_CHECK);
1515
+ if (checkSvg) check.appendChild(checkSvg);
1516
+ row.appendChild(check);
1517
+ row.appendChild(h("span", "icen-ai-todo-text", item.content));
1518
+ row.appendChild(h("span", "icen-ai-todo-active", item.activeForm ?? item.content));
477
1519
  return row;
478
1520
  }
479
1521
  function renderAiTodo(el, items) {
480
1522
  if (typeof document === "undefined") return el;
481
1523
  el.textContent = "";
482
- const root = h("div", "ai-todo");
1524
+ const root = h("div", "icen-ai-todo");
483
1525
  const list = Array.isArray(items) ? items : [];
484
1526
  const done = list.filter((i) => i.status === "done").length;
485
1527
  root.appendChild(buildTodoHead(done, list.length));
@@ -488,46 +1530,66 @@ function renderAiTodo(el, items) {
488
1530
  el.appendChild(root);
489
1531
  return el;
490
1532
  }
1533
+ function metricField(src, key) {
1534
+ return typeof src === "object" && src !== null ? src[key] : void 0;
1535
+ }
1536
+ function metricNum(v) {
1537
+ return typeof v === "number" && Number.isFinite(v) ? v : void 0;
1538
+ }
1539
+ function metricStr(v) {
1540
+ return typeof v === "string" && v ? v : void 0;
1541
+ }
1542
+ function trimNum(v) {
1543
+ return String(Math.round(v * 10) / 10);
1544
+ }
491
1545
  function renderAiUsage(el, usage, opts = {}) {
492
1546
  if (typeof document === "undefined") return el;
493
1547
  const u = normalizeUsage(usage);
494
1548
  const segs = [
495
- { key: "input", className: "ai-usage-seg--input", label: "\u8F93\u5165", value: u.input ?? 0 },
496
- { key: "output", className: "ai-usage-seg--output", label: "\u8F93\u51FA", value: u.output ?? 0 },
497
- { key: "cacheRead", className: "ai-usage-seg--cache-read", label: "\u7F13\u5B58\u8BFB", value: u.cacheRead ?? 0 },
498
- { key: "cacheWrite", className: "ai-usage-seg--cache-write", label: "\u7F13\u5B58\u5199", value: u.cacheWrite ?? 0 },
499
- { key: "reasoning", className: "ai-usage-seg--reasoning", label: "\u63A8\u7406", value: u.reasoning ?? 0 }
1549
+ { key: "input", className: "icen-ai-usage-seg--input", label: t("common.input"), value: u.input ?? 0 },
1550
+ { key: "output", className: "icen-ai-usage-seg--output", label: t("common.output"), value: u.output ?? 0 },
1551
+ { key: "cacheRead", className: "icen-ai-usage-seg--cache-read", label: t("aiPanel.cacheRead"), value: u.cacheRead ?? 0 },
1552
+ { key: "cacheWrite", className: "icen-ai-usage-seg--cache-write", label: t("aiPanel.cacheWrite"), value: u.cacheWrite ?? 0 },
1553
+ { key: "reasoning", className: "icen-ai-usage-seg--reasoning", label: t("aiPanel.reasoning"), value: u.reasoning ?? 0 }
500
1554
  ];
501
1555
  const activeSegs = segs.filter((s) => s.value > 0);
502
1556
  const sum2 = activeSegs.reduce((acc, s) => acc + s.value, 0);
503
1557
  const total = u.total ?? sum2;
504
1558
  el.textContent = "";
505
- const root = h("div", "ai-usage");
506
- const bar = h("div", "ai-usage-bar");
507
- const summary = activeSegs.length > 0 ? activeSegs.map((s) => `${s.label} ${formatTokens(s.value)}`).join("\uFF0C") : "\u6682\u65E0\u7528\u91CF";
1559
+ const root = h("div", "icen-ai-usage");
1560
+ const bar = h("div", "icen-ai-usage-bar");
1561
+ const summary = activeSegs.length > 0 ? activeSegs.map((s) => `${s.label} ${formatTokens(s.value)}`).join("\uFF0C") : t("aiPanel.noUsage");
508
1562
  bar.setAttribute("role", "img");
509
- bar.setAttribute("aria-label", `\u7528\u91CF\uFF1A${summary}`);
1563
+ bar.setAttribute("aria-label", t("aiPanel.usageAria", { p0: summary }));
510
1564
  for (const s of activeSegs) {
511
1565
  const seg = document.createElement("i");
512
- seg.className = `ai-usage-seg ${s.className}`;
1566
+ seg.className = `icen-ai-usage-seg ${s.className}`;
513
1567
  seg.style.width = sum2 > 0 ? `${s.value / sum2 * 100}%` : "0%";
514
1568
  bar.appendChild(seg);
515
1569
  }
516
1570
  root.appendChild(bar);
517
1571
  if (activeSegs.length > 0) {
518
- const legend = h("div", "ai-usage-legend");
1572
+ const legend = h("div", "icen-ai-usage-legend");
519
1573
  for (const s of activeSegs) {
520
- const item = h("span", "ai-usage-legend-item");
1574
+ const item = h("span", "icen-ai-usage-legend-item");
521
1575
  const dot = document.createElement("i");
522
- dot.className = `ai-usage-dot ${s.className}`;
1576
+ dot.className = `icen-ai-usage-dot ${s.className}`;
523
1577
  dot.setAttribute("aria-hidden", "true");
524
1578
  item.appendChild(dot);
525
- item.appendChild(h("span", "ai-usage-legend-label", s.label));
526
- item.appendChild(h("span", "ai-usage-legend-value", formatTokens(s.value)));
1579
+ item.appendChild(h("span", "icen-ai-usage-legend-label", s.label));
1580
+ item.appendChild(h("span", "icen-ai-usage-legend-value", formatTokens(s.value)));
527
1581
  legend.appendChild(item);
528
1582
  }
529
1583
  root.appendChild(legend);
530
1584
  }
1585
+ const ttft = metricNum(opts.metrics?.ttftMs) ?? metricNum(metricField(usage, "ttftMs"));
1586
+ const tps = metricNum(opts.metrics?.tokensPerSec) ?? metricNum(metricField(usage, "tokensPerSec"));
1587
+ const finish = metricStr(opts.metrics?.finishReason) ?? metricStr(metricField(usage, "finishReason"));
1588
+ const metricBits = [];
1589
+ if (ttft != null) metricBits.push(`TTFT ${formatDuration(ttft)}`);
1590
+ if (tps != null && tps > 0) metricBits.push(`${trimNum(tps)} tok/s`);
1591
+ if (finish) metricBits.push(`finish: ${finish}`);
1592
+ if (metricBits.length > 0) root.appendChild(h("div", "icen-ai-usage-metrics", metricBits.join(" \xB7 ")));
531
1593
  const totalParts = [formatTokens(total)];
532
1594
  if (typeof opts.total === "number" && opts.total > 0) {
533
1595
  const pct = Math.min(100, Math.round(total / opts.total * 100));
@@ -536,7 +1598,7 @@ function renderAiUsage(el, usage, opts = {}) {
536
1598
  if (typeof opts.cost === "number" && Number.isFinite(opts.cost)) {
537
1599
  totalParts.push(` \xB7 $${opts.cost.toFixed(4)}`);
538
1600
  }
539
- root.appendChild(h("div", "ai-usage-total", totalParts.join("")));
1601
+ root.appendChild(h("div", "icen-ai-usage-total", totalParts.join("")));
540
1602
  el.appendChild(root);
541
1603
  return el;
542
1604
  }
@@ -547,31 +1609,33 @@ function renderAiUsageRing(el, usage, opts = {}) {
547
1609
  const hasLimit = typeof opts.total === "number" && opts.total > 0;
548
1610
  const pct = hasLimit ? Math.min(100, Math.max(0, Math.round(used / opts.total * 100))) : 0;
549
1611
  el.textContent = "";
550
- const btn = h("button", "ai-usage-ring");
1612
+ const btn = h("button", "icen-ai-usage-ring");
551
1613
  btn.type = "button";
552
1614
  btn.classList.add(pct >= 85 ? "is-hot" : pct >= 60 ? "is-warn" : "is-ok");
553
1615
  btn.setAttribute("aria-haspopup", "true");
554
1616
  btn.setAttribute(
555
1617
  "aria-label",
556
- hasLimit ? `\u4E0A\u4E0B\u6587\u7A97\u53E3\u5360\u7528 ${pct}%\uFF0C\u70B9\u51FB\u67E5\u770B\u8BE6\u60C5` : `\u5DF2\u7528 ${formatTokens(used)}\uFF0C\u70B9\u51FB\u67E5\u770B\u8BE6\u60C5`
1618
+ hasLimit ? t("aiPanel.ringPercent", { p0: pct }) : t("aiPanel.ringUsed", { p0: formatTokens(used) })
557
1619
  );
558
1620
  const NS = "http://www.w3.org/2000/svg";
559
- const svg2 = document.createElementNS(NS, "svg");
560
- svg2.setAttribute("viewBox", "0 0 36 36");
561
- svg2.setAttribute("aria-hidden", "true");
1621
+ const svg = document.createElementNS(NS, "svg");
1622
+ svg.setAttribute("viewBox", "0 0 36 36");
1623
+ svg.setAttribute("width", "36");
1624
+ svg.setAttribute("height", "36");
1625
+ svg.setAttribute("aria-hidden", "true");
562
1626
  const track = document.createElementNS(NS, "circle");
563
- track.setAttribute("class", "ai-usage-ring-track");
1627
+ track.setAttribute("class", "icen-ai-usage-ring-track");
564
1628
  const fill = document.createElementNS(NS, "circle");
565
- fill.setAttribute("class", "ai-usage-ring-fill");
1629
+ fill.setAttribute("class", "icen-ai-usage-ring-fill");
566
1630
  fill.setAttribute("stroke-dasharray", `${pct} 100`);
567
1631
  for (const c of [track, fill]) {
568
1632
  c.setAttribute("cx", "18");
569
1633
  c.setAttribute("cy", "18");
570
1634
  c.setAttribute("r", "15.9155");
571
- svg2.appendChild(c);
1635
+ svg.appendChild(c);
572
1636
  }
573
- btn.appendChild(svg2);
574
- btn.appendChild(h("span", "ai-usage-ring-pct", hasLimit ? `${pct}%` : formatTokens(used)));
1637
+ btn.appendChild(svg);
1638
+ btn.appendChild(h("span", "icen-ai-usage-ring-pct", hasLimit ? `${pct}%` : formatTokens(used)));
575
1639
  let panel = null;
576
1640
  const closePanel = () => {
577
1641
  if (!panel) return;
@@ -585,9 +1649,9 @@ function renderAiUsageRing(el, usage, opts = {}) {
585
1649
  closePanel();
586
1650
  return;
587
1651
  }
588
- const p = h("div", "popover ai-usage-popover");
1652
+ const p = h("div", "icen-popover icen-ai-usage-popover");
589
1653
  p.hidden = true;
590
- p.appendChild(h("div", "ai-usage-popover-title", opts.title ?? "\u4E0A\u4E0B\u6587\u7A97\u53E3"));
1654
+ p.appendChild(h("div", "icen-ai-usage-popover-title", opts.title ?? t("aiPanel.contextWindow")));
591
1655
  const body = h("div", "ai-usage-popover-body");
592
1656
  renderAiUsage(body, usage, opts);
593
1657
  p.appendChild(body);
@@ -624,15 +1688,75 @@ var ICON_SPARKLES = svgWrap(
624
1688
  );
625
1689
 
626
1690
  // src/behaviors/ai-chat.ts
627
- var ICON_COPY = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="8" y="2" width="8" height="4" rx="1"/><path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"/></svg>';
628
- var ICON_RETRY = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/><path d="M3 3v5h5"/></svg>';
1691
+ var ICON_COPY = iconHTML("copy");
1692
+ var ICON_RETRY = iconHTML("refresh");
1693
+ function emit(target, name, detail) {
1694
+ emitIcen(target, name, detail);
1695
+ }
1696
+ var REASONING_AUTO_CLOSE_MS = 1e3;
1697
+ function setReasoningOpen(reasoning, open) {
1698
+ const head = reasoning.querySelector(".icen-ai-reasoning-head");
1699
+ const body = reasoning.querySelector(".icen-ai-reasoning-body");
1700
+ head?.setAttribute("aria-expanded", String(open));
1701
+ reasoning.classList.toggle("is-open", open);
1702
+ if (body) body.hidden = !open;
1703
+ }
1704
+ function clearContinueSlot(scope) {
1705
+ scope?.querySelectorAll(".icen-ai-msg-continue").forEach((n) => n.remove());
1706
+ }
629
1707
  function createAiStream(el) {
630
- const reasoning = el.closest(".ai-reasoning");
1708
+ const reasoning = el.closest(".icen-ai-reasoning");
1709
+ const msgBody = el.closest(".icen-ai-msg-body");
1710
+ const msg = el.closest(".icen-ai-msg");
631
1711
  const startedAt = Date.now();
632
1712
  let state = "streaming";
633
1713
  el.classList.add("is-streaming");
634
1714
  el.setAttribute("aria-busy", "true");
635
- reasoning?.classList.add("is-streaming");
1715
+ if (reasoning) {
1716
+ reasoning.classList.add("is-streaming");
1717
+ setReasoningOpen(reasoning, true);
1718
+ const head = reasoning.querySelector(".icen-ai-reasoning-head");
1719
+ if (head && head.dataset.icenReasoningStart == null) head.dataset.icenReasoningStart = String(startedAt);
1720
+ }
1721
+ clearContinueSlot(msg ?? msgBody ?? el);
1722
+ const fillReasoningTime = () => {
1723
+ if (!reasoning) return;
1724
+ const time = reasoning.querySelector(".icen-ai-reasoning-time");
1725
+ if (!time) return;
1726
+ const head = reasoning.querySelector(".icen-ai-reasoning-head");
1727
+ const raw = Number(head?.dataset.icenReasoningStart ?? "");
1728
+ const t0 = Number.isFinite(raw) && raw > 0 ? raw : startedAt;
1729
+ time.textContent = t("aiChat.thinking", { p0: formatDuration(Math.max(0, Date.now() - t0)) });
1730
+ };
1731
+ const scheduleReasoningAutoClose = () => {
1732
+ if (!reasoning) return;
1733
+ const r = reasoning;
1734
+ if (r.__icenReasonUserTouched || r.__icenReasonAutoClosed) return;
1735
+ const close = () => {
1736
+ if (r.__icenReasonUserTouched || r.__icenReasonAutoClosed) return;
1737
+ r.__icenReasonAutoClosed = true;
1738
+ setReasoningOpen(r, false);
1739
+ };
1740
+ if (typeof window === "undefined") {
1741
+ close();
1742
+ return;
1743
+ }
1744
+ window.setTimeout(close, REASONING_AUTO_CLOSE_MS);
1745
+ };
1746
+ const appendContinueSlot = () => {
1747
+ if (typeof document === "undefined") return;
1748
+ const mount = msgBody ?? msg ?? (el.parentElement instanceof HTMLElement ? el.parentElement : null);
1749
+ if (!mount || mount.querySelector(":scope > .icen-ai-msg-continue")) return;
1750
+ const btn = document.createElement("button");
1751
+ btn.type = "button";
1752
+ btn.className = "icen-ai-msg-continue";
1753
+ btn.textContent = t("aiChat.continue");
1754
+ btn.addEventListener("click", () => {
1755
+ const target = msg ?? btn;
1756
+ emit(target, "icen:ai-retry", { el: target });
1757
+ });
1758
+ mount.appendChild(btn);
1759
+ };
636
1760
  const settle = (finished) => {
637
1761
  if (state !== "streaming") return;
638
1762
  state = finished ? "done" : "cancelled";
@@ -641,12 +1765,8 @@ function createAiStream(el) {
641
1765
  if (!reasoning) return;
642
1766
  reasoning.classList.remove("is-streaming");
643
1767
  if (!finished) return;
644
- const head = reasoning.querySelector(".ai-reasoning-head");
645
- const body = reasoning.querySelector(".ai-reasoning-body");
646
- head?.setAttribute("aria-expanded", "false");
647
- if (body) body.hidden = true;
648
- const time = reasoning.querySelector(".ai-reasoning-time");
649
- if (time) time.textContent = formatDuration(Date.now() - startedAt);
1768
+ fillReasoningTime();
1769
+ scheduleReasoningAutoClose();
650
1770
  };
651
1771
  return {
652
1772
  append(text) {
@@ -658,6 +1778,7 @@ function createAiStream(el) {
658
1778
  },
659
1779
  cancel() {
660
1780
  settle(false);
1781
+ appendContinueSlot();
661
1782
  },
662
1783
  fail() {
663
1784
  if (state !== "streaming") return;
@@ -665,15 +1786,20 @@ function createAiStream(el) {
665
1786
  el.classList.remove("is-streaming");
666
1787
  el.removeAttribute("aria-busy");
667
1788
  el.classList.add("is-error");
668
- reasoning?.classList.remove("is-streaming");
1789
+ if (reasoning) {
1790
+ reasoning.classList.remove("is-streaming");
1791
+ fillReasoningTime();
1792
+ scheduleReasoningAutoClose();
1793
+ }
1794
+ appendContinueSlot();
669
1795
  }
670
1796
  };
671
1797
  }
672
1798
  var ROLE_AVATAR = {
673
- user: "\u6211",
1799
+ user: t("aiChat.roleUser"),
674
1800
  assistant: "AI",
675
- system: "\u7CFB",
676
- tool: "\u5DE5"
1801
+ system: t("aiChat.roleSystem"),
1802
+ tool: t("aiChat.roleTool")
677
1803
  };
678
1804
  function safeHref(uri) {
679
1805
  const s = uri.trim().toLowerCase();
@@ -682,7 +1808,7 @@ function safeHref(uri) {
682
1808
  }
683
1809
  function renderAiContentPart(part) {
684
1810
  if (part.type === "text") {
685
- const span = h("span", "ai-msg-text");
1811
+ const span = h("span", "icen-ai-msg-text");
686
1812
  span.textContent = part.text;
687
1813
  if (part.state === "streaming") span.classList.add("is-streaming");
688
1814
  return span;
@@ -691,7 +1817,7 @@ function renderAiContentPart(part) {
691
1817
  const src = aiContentUrl(part);
692
1818
  if (!src) return void 0;
693
1819
  const img = document.createElement("img");
694
- img.className = "ai-msg-media ai-msg-media--image";
1820
+ img.className = "icen-ai-msg-media icen-ai-msg-media--image";
695
1821
  img.alt = part.alt ?? "";
696
1822
  img.setAttribute("loading", "lazy");
697
1823
  img.setAttribute("src", src);
@@ -701,7 +1827,7 @@ function renderAiContentPart(part) {
701
1827
  const src = aiContentUrl(part);
702
1828
  if (!src) return void 0;
703
1829
  const audio = document.createElement("audio");
704
- audio.className = "ai-msg-media ai-msg-media--audio";
1830
+ audio.className = "icen-ai-msg-media icen-ai-msg-media--audio";
705
1831
  audio.controls = true;
706
1832
  audio.setAttribute("src", src);
707
1833
  return audio;
@@ -710,28 +1836,28 @@ function renderAiContentPart(part) {
710
1836
  const src = aiContentUrl(part);
711
1837
  if (!src) return void 0;
712
1838
  const video = document.createElement("video");
713
- video.className = "ai-msg-media ai-msg-media--video";
1839
+ video.className = "icen-ai-msg-media icen-ai-msg-media--video";
714
1840
  video.controls = true;
715
1841
  video.setAttribute("playsinline", "");
716
1842
  video.setAttribute("src", src);
717
1843
  return video;
718
1844
  }
719
1845
  if (part.type === "file") {
720
- const chip = h("span", "ai-msg-file");
721
- chip.appendChild(h("span", "ai-msg-file-name", part.filename ?? "\u6587\u4EF6"));
1846
+ const chip = h("span", "icen-ai-msg-file");
1847
+ chip.appendChild(h("span", "ai-msg-file-name", part.filename ?? t("aiChat.file")));
722
1848
  const href2 = part.url ? safeHref(part.url) : void 0;
723
1849
  if (href2 && /^(https?:|data:)/i.test(href2)) {
724
1850
  const a2 = document.createElement("a");
725
- a2.className = "ai-msg-file-link";
1851
+ a2.className = "icen-ai-msg-file-link";
726
1852
  a2.href = href2;
727
1853
  a2.download = part.filename ?? "";
728
- a2.textContent = "\u4E0B\u8F7D";
1854
+ a2.textContent = t("aiChat.download");
729
1855
  chip.appendChild(a2);
730
1856
  }
731
1857
  return chip;
732
1858
  }
733
1859
  const a = document.createElement("a");
734
- a.className = "ai-msg-link";
1860
+ a.className = "icen-ai-msg-link";
735
1861
  const href = safeHref(part.uri);
736
1862
  if (href) a.href = href;
737
1863
  a.textContent = part.name ?? part.uri;
@@ -748,9 +1874,9 @@ function renderAiMessage(scrollEl, model) {
748
1874
  stream: () => createAiStream(scrollEl)
749
1875
  };
750
1876
  }
751
- const row = h("div", `ai-msg ai-msg--${model.role}`);
752
- const avatar = h("span", "ai-msg-avatar", ROLE_AVATAR[model.role] ?? "");
753
- const body = h("div", "ai-msg-body");
1877
+ const row = h("div", `icen-ai-msg icen-ai-msg--${model.role}`);
1878
+ const avatar = h("span", "icen-ai-msg-avatar", ROLE_AVATAR[model.role] ?? "");
1879
+ const body = h("div", "icen-ai-msg-body");
754
1880
  row.appendChild(avatar);
755
1881
  row.appendChild(body);
756
1882
  const parts = typeof model.content === "string" ? [{ type: "text", text: model.content }] : model.content;
@@ -758,21 +1884,21 @@ function renderAiMessage(scrollEl, model) {
758
1884
  const node = renderAiContentPart(part);
759
1885
  if (node) body.appendChild(node);
760
1886
  }
761
- if (model.model) body.appendChild(h("span", "ai-msg-model", model.model));
762
- const metaEl = h("div", "ai-msg-meta");
1887
+ if (model.model) body.appendChild(h("span", "icen-ai-msg-model", model.model));
1888
+ const metaEl = h("div", "icen-ai-msg-meta");
763
1889
  if (model.meta != null) metaEl.textContent = model.meta;
764
1890
  row.appendChild(metaEl);
765
- const actions = h("div", "ai-msg-actions");
1891
+ const actions = h("div", "icen-ai-msg-actions");
766
1892
  const copyBtn = h("button", "ai-msg-action");
767
1893
  copyBtn.type = "button";
768
- copyBtn.setAttribute("data-ai-msg-action", "copy");
769
- copyBtn.setAttribute("aria-label", "\u590D\u5236");
1894
+ copyBtn.setAttribute("data-icen-ai-msg-action", "copy");
1895
+ copyBtn.setAttribute("aria-label", t("common.copy"));
770
1896
  const copyIcon = svgIcon(ICON_COPY);
771
1897
  if (copyIcon) copyBtn.appendChild(copyIcon);
772
1898
  const retryBtn = h("button", "ai-msg-action");
773
1899
  retryBtn.type = "button";
774
- retryBtn.setAttribute("data-ai-msg-action", "retry");
775
- retryBtn.setAttribute("aria-label", "\u91CD\u8BD5");
1900
+ retryBtn.setAttribute("data-icen-ai-msg-action", "retry");
1901
+ retryBtn.setAttribute("aria-label", t("common.retry"));
776
1902
  const retryIcon = svgIcon(ICON_RETRY);
777
1903
  if (retryIcon) retryBtn.appendChild(retryIcon);
778
1904
  actions.append(copyBtn, retryBtn);
@@ -784,10 +1910,11 @@ function renderAiMessage(scrollEl, model) {
784
1910
  metaEl.textContent = meta;
785
1911
  },
786
1912
  setError(message) {
787
- row.classList.add("ai-msg--error");
788
- let errEl = row.querySelector(".ai-msg-error-text");
1913
+ row.classList.add("icen-ai-msg--error");
1914
+ let errEl = row.querySelector(".icen-ai-msg-error-text");
789
1915
  if (!errEl) {
790
- errEl = h("div", "ai-msg-error-text");
1916
+ errEl = h("div", "icen-ai-msg-error-text");
1917
+ errEl.setAttribute("role", "status");
791
1918
  body.appendChild(errEl);
792
1919
  }
793
1920
  errEl.textContent = message;
@@ -804,34 +1931,102 @@ function renderAiMessage(scrollEl, model) {
804
1931
  return handle;
805
1932
  }
806
1933
 
1934
+ // src/behaviors/input.ts
1935
+ var searchFields = /* @__PURE__ */ new WeakMap();
1936
+ function enhanceSearchField(input) {
1937
+ if (typeof document === "undefined" || !input.parentElement) return { refresh() {
1938
+ }, destroy() {
1939
+ } };
1940
+ const previous = searchFields.get(input);
1941
+ if (previous) return previous;
1942
+ const host = input.parentElement;
1943
+ const wasFocused = document.activeElement === input;
1944
+ const hadHostClass = host.classList.contains("icen-search-field");
1945
+ const hadInputClass = input.classList.contains("icen-search-input");
1946
+ const hadStandardClass = input.classList.contains("icen-input");
1947
+ const ownedWrap = !host.classList.contains("icen-input-wrap");
1948
+ const next = input.nextSibling;
1949
+ const wrap = ownedWrap ? document.createElement("div") : host;
1950
+ if (ownedWrap) {
1951
+ wrap.className = "icen-input-wrap icen-input-wrap--sm icen-input-wrap--search icen-control";
1952
+ host.insertBefore(wrap, input);
1953
+ wrap.append(input);
1954
+ }
1955
+ const leading = wrap.querySelector(".icen-input-leading") ? null : document.createElement("span");
1956
+ if (leading) {
1957
+ leading.className = "icen-input-leading";
1958
+ leading.append(createIcon("search"));
1959
+ wrap.prepend(leading);
1960
+ }
1961
+ host.classList.add("icen-search-field");
1962
+ input.classList.add("icen-search-input", "icen-input");
1963
+ const clear = document.createElement("button");
1964
+ clear.type = "button";
1965
+ clear.className = "icen-input-clear icen-search-clear";
1966
+ clear.append(createIcon("close"));
1967
+ wrap.append(clear);
1968
+ const ac = new AbortController();
1969
+ let disposed = false;
1970
+ const refresh = () => {
1971
+ if (disposed) return;
1972
+ clear.hidden = !input.value || input.disabled || input.readOnly;
1973
+ clear.setAttribute("aria-label", t("input.clearSearch"));
1974
+ };
1975
+ clear.addEventListener("pointerdown", (event) => event.preventDefault(), { signal: ac.signal });
1976
+ clear.addEventListener("click", () => {
1977
+ if (input.disabled || input.readOnly) return;
1978
+ input.value = "";
1979
+ input.dispatchEvent(new Event("input", { bubbles: true }));
1980
+ input.focus({ preventScroll: true });
1981
+ refresh();
1982
+ }, { signal: ac.signal });
1983
+ for (const event of ["input", "change", "focus"]) input.addEventListener(event, refresh, { signal: ac.signal });
1984
+ document.addEventListener("icen:locale-change", refresh, { signal: ac.signal });
1985
+ const observer = new MutationObserver(refresh);
1986
+ observer.observe(input, { attributes: true, attributeFilter: ["disabled", "readonly"] });
1987
+ refresh();
1988
+ if (wasFocused) input.focus({ preventScroll: true });
1989
+ const handle = { refresh, destroy() {
1990
+ if (disposed) return;
1991
+ disposed = true;
1992
+ observer.disconnect();
1993
+ ac.abort();
1994
+ clear.remove();
1995
+ leading?.remove();
1996
+ searchFields.delete(input);
1997
+ const focused = document.activeElement === input;
1998
+ if (ownedWrap) {
1999
+ host.insertBefore(input, next?.parentNode === host ? next : null);
2000
+ wrap.remove();
2001
+ }
2002
+ if (focused) input.focus({ preventScroll: true });
2003
+ if (!hadHostClass) host.classList.remove("icen-search-field");
2004
+ if (!hadInputClass) input.classList.remove("icen-search-input");
2005
+ if (!hadStandardClass) input.classList.remove("icen-input");
2006
+ } };
2007
+ searchFields.set(input, handle);
2008
+ return handle;
2009
+ }
2010
+
807
2011
  // src/behaviors/ai-composer.ts
808
2012
  var MAX_ROWS_DEFAULT = 8;
809
2013
  var HISTORY_LIMIT = 50;
810
2014
  var CACHE_WARN_RATIO = 0.4;
811
- var SEND_ICON = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m22 2-7 20-4-9-9-4z"/><path d="M22 2 11 13"/></svg>';
812
- var STOP_ICON = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><rect x="6" y="6" width="12" height="12" rx="2"/></svg>';
813
- var ATTACH_ICON = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m21.44 11.05-9.19 9.19a6 6 0 0 1-8.49-8.49l8.57-8.57A4 4 0 1 1 18 8.84l-8.59 8.57a2 2 0 0 1-2.83-2.83l8.49-8.48"/></svg>';
814
- var svgWrap2 = (body) => `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">${body}</svg>`;
815
- var ICON_CHEVRON = svgWrap2('<path d="m6 9 6 6 6-6"/>');
816
- var ICON_CHECK = svgWrap2('<path d="M20 6 9 17l-5-5"/>');
817
- var ICON_INFO = svgWrap2('<circle cx="12" cy="12" r="10"/><path d="M12 16v-4"/><path d="M12 8h.01"/>');
818
- var ICON_FILE3 = svgWrap2(
819
- '<path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7z"/><path d="M14 2v4a2 2 0 0 0 2 2h4"/>'
820
- );
821
- var ICON_FOLDER = svgWrap2(
822
- '<path d="M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z"/>'
823
- );
824
- var ICON_DOC = svgWrap2(
825
- '<path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7z"/><path d="M14 2v4a2 2 0 0 0 2 2h4"/><path d="M16 13H8"/><path d="M16 17H8"/>'
826
- );
827
- var ICON_BOT2 = svgWrap2(
828
- '<path d="M12 8V4H8"/><rect width="16" height="12" x="4" y="8" rx="2"/><path d="M2 14h2"/><path d="M20 14h2"/><path d="M15 13v2"/><path d="M9 13v2"/>'
829
- );
2015
+ var SEND_ICON = iconHTML("arrow-up");
2016
+ var STOP_ICON = iconHTML("stop");
2017
+ var ATTACH_ICON = iconHTML("paperclip");
2018
+ var ICON_INFO = iconHTML("circle-info");
2019
+ var ICON_FILE3 = iconHTML("file");
2020
+ var ICON_FOLDER = iconHTML("folder");
2021
+ var ICON_DOC = iconHTML("document");
2022
+ var ICON_BOT2 = iconHTML("agent");
830
2023
  var REF_KIND_BUILTIN = {
831
- file: { label: "\u6587\u4EF6", icon: ICON_FILE3, order: 0 },
832
- folder: { label: "\u6587\u4EF6\u5939", icon: ICON_FOLDER, order: 1 },
833
- doc: { label: "\u6587\u6863", icon: ICON_DOC, order: 2 },
834
- agent: { label: "\u4EE3\u7406", icon: ICON_BOT2, order: 3 }
2024
+ skill: { label: t("aiComposer.skills"), icon: iconHTML("sparkle"), order: -2 },
2025
+ tool: { label: t("aiComposer.tools"), icon: iconHTML("box"), order: -1 },
2026
+ file: { label: t("aiComposer.attachFile"), icon: ICON_FILE3, order: 0 },
2027
+ folder: { label: t("aiComposer.attachFolder"), icon: ICON_FOLDER, order: 1 },
2028
+ doc: { label: t("aiComposer.attachDoc"), icon: ICON_DOC, order: 2 },
2029
+ agent: { label: t("aiComposer.attachAgent"), icon: ICON_BOT2, order: 3 }
835
2030
  };
836
2031
  var REF_KIND_ORDER_LAST = Number.MAX_SAFE_INTEGER;
837
2032
  var REF_KIND_REGISTRY = /* @__PURE__ */ new Map();
@@ -858,6 +2053,7 @@ function knownRefKinds(sources) {
858
2053
  }
859
2054
  var RUNNING = /* @__PURE__ */ new WeakMap();
860
2055
  var QUEUES = /* @__PURE__ */ new WeakMap();
2056
+ var FILES = /* @__PURE__ */ new WeakMap();
861
2057
  var MODELS = /* @__PURE__ */ new WeakMap();
862
2058
  var MODEL_CTX = /* @__PURE__ */ new WeakMap();
863
2059
  var COMMANDS = /* @__PURE__ */ new WeakMap();
@@ -872,18 +2068,18 @@ var POPUP_SIZING = /* @__PURE__ */ new WeakMap();
872
2068
  function isBrowser() {
873
2069
  return typeof document !== "undefined" && typeof window !== "undefined";
874
2070
  }
875
- function emit(target, name, detail) {
2071
+ function emit2(target, name, detail) {
876
2072
  emitIcen(target, name, detail);
877
2073
  }
878
2074
  function resolveComposer(el) {
879
- return el.closest("[data-ai-composer]");
2075
+ return el.closest("[data-icen-ai-composer]");
880
2076
  }
881
2077
  function getTextarea(composer) {
882
- return composer.querySelector(".ai-composer-input");
2078
+ return composer.querySelector(".icen-ai-composer-input");
883
2079
  }
884
2080
  function autosizeTa(ta) {
885
- const composer = ta.closest("[data-ai-composer]");
886
- const maxRows = Number(composer?.getAttribute("data-max-rows")) || MAX_ROWS_DEFAULT;
2081
+ const composer = ta.closest("[data-icen-ai-composer]");
2082
+ const maxRows = Number(composer?.getAttribute("data-icen-max-rows")) || MAX_ROWS_DEFAULT;
887
2083
  const cs = window.getComputedStyle(ta);
888
2084
  const lineHeight = parseFloat(cs.lineHeight) || 20;
889
2085
  const padY = (parseFloat(cs.paddingTop) || 0) + (parseFloat(cs.paddingBottom) || 0);
@@ -894,51 +2090,58 @@ function autosizeTa(ta) {
894
2090
  ta.style.height = `${Math.max(minH, Math.min(ta.scrollHeight, maxH))}px`;
895
2091
  }
896
2092
  function ensureIcons(composer) {
897
- const sendBtn = composer.querySelector("[data-ai-send]");
2093
+ const sendBtn = composer.querySelector("[data-icen-ai-send]");
898
2094
  if (sendBtn && !sendBtn.hasChildNodes()) {
899
2095
  const sendWrap = document.createElement("span");
900
- sendWrap.className = "ai-composer-send-icon";
901
- sendWrap.dataset.aiSendIcon = "send";
2096
+ sendWrap.className = "icen-ai-composer-send-icon";
2097
+ sendWrap.dataset.icenAiSendIcon = "send";
902
2098
  const stopWrap = document.createElement("span");
903
- stopWrap.className = "ai-composer-send-icon";
904
- stopWrap.dataset.aiSendIcon = "stop";
2099
+ stopWrap.className = "icen-ai-composer-send-icon";
2100
+ stopWrap.dataset.icenAiSendIcon = "stop";
905
2101
  const sendSvg = svgIcon(SEND_ICON);
906
2102
  const stopSvg = svgIcon(STOP_ICON);
907
2103
  if (sendSvg) sendWrap.appendChild(sendSvg);
908
2104
  if (stopSvg) stopWrap.appendChild(stopSvg);
909
2105
  sendBtn.append(sendWrap, stopWrap);
910
2106
  }
911
- const attachBtn = composer.querySelector("[data-ai-attach]");
2107
+ const attachBtn = composer.querySelector("[data-icen-ai-attach]");
912
2108
  if (attachBtn && !attachBtn.hasChildNodes()) {
913
2109
  const icon = svgIcon(ATTACH_ICON);
914
2110
  if (icon) attachBtn.appendChild(icon);
915
2111
  }
916
- const sendIcon = sendBtn?.querySelector('[data-ai-send-icon="send"]') ?? null;
917
- const stopIcon = sendBtn?.querySelector('[data-ai-send-icon="stop"]') ?? null;
2112
+ const sendIcon = sendBtn?.querySelector('[data-icen-ai-send-icon="send"]') ?? null;
2113
+ const stopIcon = sendBtn?.querySelector('[data-icen-ai-send-icon="stop"]') ?? null;
918
2114
  return { sendBtn, sendIcon, stopIcon };
919
2115
  }
920
- function makeChip(text, removable, ariaLabel) {
2116
+ function makeChip(text, removable, ariaLabel, icon) {
921
2117
  const chip = document.createElement("span");
922
- chip.className = "ai-composer-chip";
2118
+ chip.className = "icen-ai-composer-chip";
2119
+ if (icon) {
2120
+ const mark = document.createElement("span");
2121
+ mark.className = "icen-ai-composer-chip-icon";
2122
+ const svg = createIcon(icon);
2123
+ if (svg) mark.append(svg);
2124
+ chip.append(mark);
2125
+ }
923
2126
  const label = document.createElement("span");
924
- label.className = "ai-composer-chip-text";
2127
+ label.className = "icen-ai-composer-chip-text";
925
2128
  label.textContent = text;
926
2129
  chip.appendChild(label);
927
2130
  if (removable) {
928
2131
  const remove = document.createElement("button");
929
2132
  remove.type = "button";
930
- remove.className = "ai-composer-chip-remove";
2133
+ remove.className = "icen-ai-composer-chip-remove";
931
2134
  remove.setAttribute("aria-label", ariaLabel);
932
- remove.textContent = "\xD7";
2135
+ remove.replaceChildren(createIcon("close"));
933
2136
  chip.appendChild(remove);
934
2137
  }
935
2138
  return chip;
936
2139
  }
937
2140
  function renderQueueChips(composer) {
938
- const queueEl = composer.querySelector(".ai-composer-queue");
2141
+ const queueEl = composer.querySelector(".icen-ai-composer-queue");
939
2142
  if (!queueEl) return;
940
2143
  const queue = QUEUES.get(composer) ?? [];
941
- queueEl.replaceChildren(...queue.map((text, i) => makeChip(text, true, `\u79FB\u9664\u6392\u961F\u6D88\u606F ${i + 1}`)));
2144
+ queueEl.replaceChildren(...queue.map((draft, i) => makeChip(draft.text || [...draft.files?.map((f) => f.name) ?? [], ...draft.refs?.map((r) => r.label) ?? []].join(" \xB7 "), true, t("aiComposer.removeQueued", { p0: i + 1 }), "layers")));
942
2145
  queueEl.hidden = queue.length === 0;
943
2146
  }
944
2147
  function setComposerRunning(el, running) {
@@ -951,24 +2154,24 @@ function setComposerRunning(el, running) {
951
2154
  } else {
952
2155
  composer.removeAttribute("aria-busy");
953
2156
  }
954
- const sendBtn = composer.querySelector("[data-ai-send]");
2157
+ const sendBtn = composer.querySelector("[data-icen-ai-send]");
955
2158
  if (!sendBtn) return;
956
2159
  sendBtn.classList.toggle("is-stop", running);
957
- sendBtn.setAttribute("aria-label", running ? "\u505C\u6B62\u751F\u6210" : "\u53D1\u9001");
958
- const sendIcon = sendBtn.querySelector('[data-ai-send-icon="send"]');
959
- const stopIcon = sendBtn.querySelector('[data-ai-send-icon="stop"]');
2160
+ sendBtn.setAttribute("aria-label", running ? t("aiComposer.stop") : t("aiComposer.send"));
2161
+ const sendIcon = sendBtn.querySelector('[data-icen-ai-send-icon="send"]');
2162
+ const stopIcon = sendBtn.querySelector('[data-icen-ai-send-icon="stop"]');
960
2163
  if (sendIcon) sendIcon.hidden = running;
961
2164
  if (stopIcon) stopIcon.hidden = !running;
962
2165
  }
963
2166
  function providerMark(provider, badgeClass) {
964
2167
  const slot = document.createElement("span");
965
2168
  slot.className = badgeClass;
966
- const svg2 = provider.icon ? svgIcon(provider.icon) : null;
967
- if (svg2) {
968
- slot.appendChild(svg2);
2169
+ const svg = provider.icon ? svgIcon(provider.icon) : null;
2170
+ if (svg) {
2171
+ slot.appendChild(svg);
969
2172
  } else {
970
2173
  const badge = document.createElement("span");
971
- badge.className = "ai-composer-model-badge";
2174
+ badge.className = "icen-ai-composer-model-badge";
972
2175
  badge.textContent = (provider.label.trim()[0] ?? "?").toUpperCase();
973
2176
  slot.appendChild(badge);
974
2177
  }
@@ -977,8 +2180,8 @@ function providerMark(provider, badgeClass) {
977
2180
  function buildModelButton(composer) {
978
2181
  const btn = document.createElement("button");
979
2182
  btn.type = "button";
980
- btn.className = "ai-composer-model";
981
- btn.setAttribute("data-ai-model-open", "");
2183
+ btn.className = "icen-ai-composer-model";
2184
+ btn.setAttribute("data-icen-ai-model-open", "");
982
2185
  btn.setAttribute("aria-haspopup", "listbox");
983
2186
  btn.setAttribute("aria-expanded", "false");
984
2187
  btn.addEventListener("click", () => {
@@ -989,66 +2192,59 @@ function buildModelButton(composer) {
989
2192
  }
990
2193
  function updateModelButton(composer) {
991
2194
  const cfg = MODELS.get(composer);
992
- const btn = composer.querySelector("[data-ai-model-open]");
2195
+ const btn = composer.querySelector("[data-icen-ai-model-open]");
993
2196
  if (!cfg || !btn) return;
994
2197
  const provider = cfg.providers.find((p) => p.id === cfg.current.provider) ?? cfg.providers[0];
995
2198
  if (!provider) return;
996
2199
  const model = provider.models.find((m) => m.id === cfg.current.model) ?? provider.models[0];
997
2200
  if (!model) return;
998
- const iconSlot = btn.querySelector(".ai-composer-model-icon") ?? (() => {
2201
+ const iconSlot = btn.querySelector(".icen-ai-composer-model-icon") ?? (() => {
999
2202
  const slot = document.createElement("span");
1000
- slot.className = "ai-composer-model-icon";
2203
+ slot.className = "icen-ai-composer-model-icon";
1001
2204
  btn.prepend(slot);
1002
2205
  return slot;
1003
2206
  })();
1004
- iconSlot.replaceChildren(providerMark(provider, "ai-composer-model-provider-icon"));
1005
- let name = btn.querySelector(".ai-composer-model-name");
2207
+ iconSlot.replaceChildren(providerMark(provider, "icen-ai-composer-model-provider-icon"));
2208
+ let name = btn.querySelector(".icen-ai-composer-model-name");
1006
2209
  if (!name) {
1007
2210
  name = document.createElement("span");
1008
- name.className = "ai-composer-model-name";
1009
- btn.insertBefore(name, btn.querySelector(".ai-composer-model-chevron"));
2211
+ name.className = "icen-ai-composer-model-name";
2212
+ btn.insertBefore(name, btn.querySelector(".icen-ai-composer-model-chevron"));
1010
2213
  }
1011
2214
  name.textContent = model.label;
1012
- btn.setAttribute("aria-label", `\u6A21\u578B ${model.label}\uFF08${provider.label}\uFF09`);
1013
- if (!btn.querySelector(".ai-composer-model-chevron")) {
1014
- const chev = svgIcon(ICON_CHEVRON);
1015
- if (chev) {
1016
- const wrap = document.createElement("span");
1017
- wrap.className = "ai-composer-model-chevron";
1018
- wrap.appendChild(chev);
1019
- btn.appendChild(wrap);
1020
- }
1021
- }
2215
+ btn.setAttribute("aria-label", t("aiComposer.modelAria", { p0: model.label, p1: provider.label }));
2216
+ btn.querySelector(".icen-ai-composer-model-chevron")?.remove();
1022
2217
  }
1023
2218
  function syncToolbar(composer) {
1024
- const box = composer.querySelector(".ai-composer-box");
2219
+ const box = composer.querySelector(".icen-ai-composer-box");
1025
2220
  if (!box || !getTextarea(composer)) return;
1026
2221
  const modelsCfg = MODELS.get(composer);
1027
2222
  const usageCfg = USAGE.get(composer);
1028
- if (!modelsCfg && !usageCfg) return;
1029
- let bar = composer.querySelector(".ai-composer-toolbar");
1030
- let modelBtn = composer.querySelector("[data-ai-model-open]");
2223
+ const hasLibrary = !!(COMMANDS.get(composer)?.length || REF_SOURCES.get(composer)?.length);
2224
+ if (!modelsCfg && !usageCfg && !hasLibrary && !composer.querySelector(".icen-ai-composer-toolbar")) return;
2225
+ let bar = composer.querySelector(".icen-ai-composer-toolbar");
2226
+ let modelBtn = composer.querySelector("[data-icen-ai-model-open]");
1031
2227
  if (modelsCfg && !modelBtn) {
1032
2228
  modelBtn = buildModelButton(composer);
1033
- modelBtn.dataset.aiModelOpen = "auto";
2229
+ modelBtn.dataset.icenAiModelOpen = "auto";
1034
2230
  updateModelButton(composer);
1035
2231
  }
1036
- if (!modelsCfg && modelBtn?.dataset.aiModelOpen === "auto") {
2232
+ if (!modelsCfg && modelBtn?.dataset.icenAiModelOpen === "auto") {
1037
2233
  modelBtn.remove();
1038
2234
  modelBtn = null;
1039
2235
  }
1040
- let usageMount = composer.querySelector(".ai-composer-usage");
2236
+ let usageMount = composer.querySelector(".icen-ai-composer-usage");
1041
2237
  if (usageCfg && !usageMount) {
1042
2238
  usageMount = document.createElement("span");
1043
- usageMount.className = "ai-composer-usage";
1044
- usageMount.dataset.aiUsage = "auto";
2239
+ usageMount.className = "icen-ai-composer-usage";
2240
+ usageMount.dataset.icenAiUsage = "auto";
1045
2241
  }
1046
- if (!usageCfg && usageMount?.dataset.aiUsage === "auto") {
2242
+ if (!usageCfg && usageMount?.dataset.icenAiUsage === "auto") {
1047
2243
  usageMount.remove();
1048
2244
  usageMount = null;
1049
2245
  }
1050
- const attach = composer.querySelector("[data-ai-attach]");
1051
- const send = composer.querySelector("[data-ai-send]");
2246
+ const attach = composer.querySelector("[data-icen-ai-attach]");
2247
+ const send = composer.querySelector("[data-icen-ai-send]");
1052
2248
  if (bar) {
1053
2249
  if (modelBtn && modelBtn.parentElement !== bar) bar.insertBefore(modelBtn, bar.firstChild);
1054
2250
  if (usageMount && usageMount.parentElement !== bar) {
@@ -1056,24 +2252,36 @@ function syncToolbar(composer) {
1056
2252
  }
1057
2253
  } else {
1058
2254
  bar = document.createElement("div");
1059
- bar.className = "ai-composer-toolbar";
2255
+ bar.className = "icen-ai-composer-toolbar";
1060
2256
  bar.appendChild(modelBtn ?? document.createComment("model"));
1061
2257
  const spacer = document.createElement("span");
1062
- spacer.className = "ai-composer-spacer";
2258
+ spacer.className = "icen-ai-composer-spacer";
1063
2259
  bar.appendChild(spacer);
1064
2260
  if (usageMount) bar.appendChild(usageMount);
1065
2261
  if (attach) bar.appendChild(attach);
1066
2262
  if (send) bar.appendChild(send);
1067
2263
  box.appendChild(bar);
1068
2264
  }
1069
- const legacy = composer.querySelector(".ai-composer-actions");
1070
- if (legacy && legacy.childElementCount === 0 && !(legacy.textContent ?? "").trim()) {
1071
- legacy.remove();
1072
- }
2265
+ let library = composer.querySelector("[data-icen-ai-library]");
2266
+ if (hasLibrary && !library) {
2267
+ library = document.createElement("button");
2268
+ library.type = "button";
2269
+ library.className = "icen-ai-composer-btn icen-ai-composer-library";
2270
+ library.dataset.icenAiLibrary = "auto";
2271
+ library.setAttribute("aria-label", t("aiComposer.library"));
2272
+ library.setAttribute("aria-haspopup", "dialog");
2273
+ library.setAttribute("aria-expanded", "false");
2274
+ library.append(createIcon("plus"));
2275
+ library.addEventListener("click", () => {
2276
+ if (POPUP.get(composer)?.mode === "library") closePopup(composer);
2277
+ else openComposerLibrary(composer);
2278
+ });
2279
+ bar.prepend(library);
2280
+ } else if (!hasLibrary && library?.dataset.icenAiLibrary === "auto") library.remove();
1073
2281
  }
1074
2282
  function refreshUsageRing(composer) {
1075
2283
  const cfg = USAGE.get(composer);
1076
- const mount = composer.querySelector(".ai-composer-usage");
2284
+ const mount = composer.querySelector(".icen-ai-composer-usage");
1077
2285
  if (!cfg || !mount) return;
1078
2286
  const explicit = typeof cfg.opts.total === "number" && cfg.opts.total > 0;
1079
2287
  renderAiUsageRing(mount, cfg.usage, {
@@ -1081,18 +2289,21 @@ function refreshUsageRing(composer) {
1081
2289
  total: explicit ? cfg.opts.total : MODEL_CTX.get(composer)
1082
2290
  });
1083
2291
  }
1084
- var visibleOptions = (s) => s.options.filter((o) => !o.hidden);
2292
+ var visibleOptions = (s) => s.options.filter((o) => !o.hidden && o.getAttribute("aria-disabled") !== "true");
2293
+ var popupId = 0;
1085
2294
  function setPopupFocus(s, idx) {
1086
2295
  const vis = visibleOptions(s);
1087
2296
  s.options.forEach((o) => o.classList.remove("is-focused"));
1088
2297
  if (vis.length === 0) {
1089
2298
  s.focused = -1;
2299
+ s.control?.removeAttribute("aria-activedescendant");
1090
2300
  return;
1091
2301
  }
1092
2302
  s.focused = Math.max(0, Math.min(idx, vis.length - 1));
1093
2303
  const cur = vis[s.focused];
1094
2304
  cur.classList.add("is-focused");
1095
- cur.scrollIntoView({ block: "nearest" });
2305
+ s.control?.setAttribute("aria-activedescendant", cur.id);
2306
+ revealPopoverItem(cur, s.panel.querySelector(".icen-ai-composer-popup-list") ?? s.panel);
1096
2307
  }
1097
2308
  function movePopupFocus(s, delta) {
1098
2309
  const vis = visibleOptions(s);
@@ -1101,15 +2312,25 @@ function movePopupFocus(s, delta) {
1101
2312
  }
1102
2313
  function settlePopup(s) {
1103
2314
  for (const g of s.groups) {
1104
- g.hidden = !Array.from(g.querySelectorAll(".ai-composer-popup-option")).some((o) => !o.hidden);
2315
+ g.hidden = !Array.from(g.querySelectorAll(".icen-ai-composer-popup-option")).some((o) => !o.hidden);
1105
2316
  }
1106
- s.emptyEl.hidden = visibleOptions(s).length > 0;
2317
+ s.emptyEl.hidden = s.options.some((o) => !o.hidden);
1107
2318
  setPopupFocus(s, 0);
1108
2319
  }
1109
2320
  function filterPopupOptions(s, q) {
1110
2321
  const needle = q.trim().toLowerCase();
1111
2322
  for (const opt of s.options) {
1112
- opt.hidden = needle !== "" && !(opt.dataset.hay ?? "").includes(needle);
2323
+ opt.hidden = !!s.category && s.category !== "all" && opt.dataset.category !== s.category || needle !== "" && !(opt.dataset.hay ?? "").includes(needle);
2324
+ for (const label of opt.querySelectorAll("[data-icen-search-text]")) {
2325
+ const text = label.dataset.icenSearchText ?? "";
2326
+ const at = needle ? text.toLowerCase().indexOf(needle) : -1;
2327
+ if (at < 0) label.textContent = text;
2328
+ else {
2329
+ const mark = document.createElement("mark");
2330
+ mark.textContent = text.slice(at, at + needle.length);
2331
+ label.replaceChildren(document.createTextNode(text.slice(0, at)), mark, document.createTextNode(text.slice(at + needle.length)));
2332
+ }
2333
+ }
1113
2334
  }
1114
2335
  settlePopup(s);
1115
2336
  }
@@ -1126,6 +2347,9 @@ function popupKeydown(composer, s, e) {
1126
2347
  return;
1127
2348
  case "Enter":
1128
2349
  case "Tab": {
2350
+ if (e.key === "Tab" && (s.mode === "library" || s.mode === "model")) {
2351
+ return;
2352
+ }
1129
2353
  e.preventDefault();
1130
2354
  const vis = visibleOptions(s);
1131
2355
  const opt = vis[s.focused] ?? vis[0];
@@ -1133,10 +2357,18 @@ function popupKeydown(composer, s, e) {
1133
2357
  s.pick(opt);
1134
2358
  return;
1135
2359
  }
2360
+ if (s.mode === "library" || s.mode === "model") return;
1136
2361
  closePopup(composer, false);
1137
2362
  if (e.key === "Enter") SUBMITS.get(composer)?.();
1138
2363
  return;
1139
2364
  }
2365
+ case "Home":
2366
+ case "End":
2367
+ if (e.altKey || e.ctrlKey || e.metaKey) {
2368
+ e.preventDefault();
2369
+ setPopupFocus(s, e.key === "Home" ? 0 : visibleOptions(s).length - 1);
2370
+ }
2371
+ return;
1140
2372
  case "Escape":
1141
2373
  e.preventDefault();
1142
2374
  closePopup(composer);
@@ -1146,14 +2378,19 @@ function popupKeydown(composer, s, e) {
1146
2378
  function closePopup(composer, restoreFocus = true) {
1147
2379
  const s = POPUP.get(composer);
1148
2380
  if (!s) return;
2381
+ s.restoreFocus = restoreFocus;
1149
2382
  POPUP.delete(composer);
1150
2383
  if (s.searchInput && s.keydownHandler) {
1151
2384
  s.searchInput.removeEventListener("keydown", s.keydownHandler);
1152
2385
  }
1153
- if (s.mode === "model") {
1154
- composer.querySelector("[data-ai-model-open]")?.setAttribute("aria-expanded", "false");
2386
+ s.control?.removeAttribute("aria-activedescendant");
2387
+ s.control?.removeAttribute("aria-controls");
2388
+ if (s.mode === "library") {
2389
+ composer.querySelector("[data-icen-ai-library]")?.setAttribute("aria-expanded", "false");
2390
+ } else if (s.mode === "model") {
2391
+ composer.querySelector("[data-icen-ai-model-open]")?.setAttribute("aria-expanded", "false");
1155
2392
  } else {
1156
- getTextarea(composer)?.setAttribute("aria-expanded", "false");
2393
+ getTextarea(composer)?.removeAttribute("aria-expanded");
1157
2394
  }
1158
2395
  closePopover(s.panel);
1159
2396
  if (restoreFocus && s.returnFocus && s.returnFocus.isConnected) s.returnFocus.focus();
@@ -1165,7 +2402,9 @@ function resolvePopupSizing(composer, defaults) {
1165
2402
  function mountPopup(composer, init) {
1166
2403
  closePopup(composer, false);
1167
2404
  const panel = document.createElement("div");
1168
- panel.className = "ai-composer-popup";
2405
+ panel.className = "icen-ai-composer-popup";
2406
+ panel.dataset.icenMaterial = "floating";
2407
+ panel.dataset.icenMode = init.mode;
1169
2408
  panel.hidden = true;
1170
2409
  const session = {
1171
2410
  mode: init.mode,
@@ -1181,49 +2420,245 @@ function mountPopup(composer, init) {
1181
2420
  pick: init.pick
1182
2421
  };
1183
2422
  init.build(session);
2423
+ if (session.searchInput) session.searchField = enhanceSearchField(session.searchInput);
2424
+ const list = panel.querySelector('[role="listbox"]');
2425
+ if (list) {
2426
+ list.id = `icen-composer-list-${++popupId}`;
2427
+ session.options.forEach((o, i) => {
2428
+ o.id = `${list.id}-${i}`;
2429
+ o.tabIndex = -1;
2430
+ });
2431
+ session.control = session.searchInput ?? getTextarea(composer);
2432
+ session.control?.setAttribute("aria-controls", list.id);
2433
+ session.control?.setAttribute("aria-haspopup", "listbox");
2434
+ }
1184
2435
  openPopover(panel, {
1185
2436
  anchor: init.anchor,
1186
2437
  side: "top",
1187
2438
  align: "start",
1188
2439
  offset: 8,
1189
2440
  sizing: resolvePopupSizing(composer, init.sizing),
2441
+ restoreFocus: false,
1190
2442
  onClose: () => {
1191
2443
  if (POPUP.get(composer) === session) POPUP.delete(composer);
2444
+ session.control?.removeAttribute("aria-activedescendant");
2445
+ session.control?.removeAttribute("aria-controls");
2446
+ composer.querySelector("[data-icen-ai-library]")?.setAttribute("aria-expanded", "false");
2447
+ composer.querySelector("[data-icen-ai-model-open]")?.setAttribute("aria-expanded", "false");
2448
+ getTextarea(composer)?.removeAttribute("aria-expanded");
2449
+ if (session.restoreFocus !== false && panel.contains(document.activeElement) && session.returnFocus?.isConnected) {
2450
+ session.returnFocus.focus({ preventScroll: true });
2451
+ }
2452
+ session.searchField?.destroy();
1192
2453
  panel.remove();
1193
2454
  }
1194
2455
  });
1195
2456
  POPUP.set(composer, session);
1196
2457
  panel.addEventListener("click", (e) => {
1197
- const t = e.target;
1198
- if (!(t instanceof Element)) return;
1199
- const opt = t.closest(".ai-composer-popup-option");
1200
- if (opt && panel.contains(opt) && !opt.hidden) session.pick(opt);
2458
+ const t2 = e.target;
2459
+ if (!(t2 instanceof Element)) return;
2460
+ const opt = t2.closest(".icen-ai-composer-popup-option");
2461
+ if (opt && panel.contains(opt) && !opt.hidden && opt.getAttribute("aria-disabled") !== "true") session.pick(opt);
1201
2462
  });
1202
2463
  panel.addEventListener("mouseover", (e) => {
1203
- const t = e.target;
1204
- if (!(t instanceof Element)) return;
1205
- const opt = t.closest(".ai-composer-popup-option");
1206
- if (!opt || opt.hidden) return;
2464
+ const t2 = e.target;
2465
+ if (!(t2 instanceof Element)) return;
2466
+ const opt = t2.closest(".icen-ai-composer-popup-option");
2467
+ if (!opt || opt.hidden || opt.getAttribute("aria-disabled") === "true") return;
1207
2468
  const idx = visibleOptions(session).indexOf(opt);
1208
2469
  if (idx >= 0) setPopupFocus(session, idx);
1209
2470
  });
2471
+ panel.addEventListener("focusout", (e) => {
2472
+ const next = e.relatedTarget;
2473
+ if (next instanceof Node && !panel.contains(next) && next !== session.returnFocus) closePopup(composer, false);
2474
+ });
2475
+ panel.addEventListener("keydown", (e) => {
2476
+ if (e.key === "Escape" && !e.isComposing) {
2477
+ e.preventDefault();
2478
+ closePopup(composer);
2479
+ } else if (e.target instanceof Element && e.target.closest(".icen-ai-composer-popup-option") && ["ArrowUp", "ArrowDown"].includes(e.key)) {
2480
+ popupKeydown(composer, session, e);
2481
+ session.searchInput?.focus({ preventScroll: true });
2482
+ }
2483
+ });
1210
2484
  return session;
1211
2485
  }
1212
2486
  function appendPopupEmpty(s, text) {
1213
- s.emptyEl.className = "ai-composer-popup-empty";
2487
+ s.emptyEl.className = "icen-ai-composer-popup-empty";
1214
2488
  s.emptyEl.textContent = text;
1215
2489
  s.emptyEl.hidden = true;
1216
2490
  s.panel.appendChild(s.emptyEl);
1217
2491
  }
1218
2492
  function popupSizingFor(box) {
1219
2493
  const w = box.getBoundingClientRect().width;
1220
- return { minWidth: Math.min(Math.max(w, 200), 320), maxWidth: 360, maxHeight: 320 };
2494
+ return { width: Math.min(Math.max(w, 280), 440), maxWidth: 440, maxHeight: 400 };
2495
+ }
2496
+ function searchLeaf(text, className) {
2497
+ const el = document.createElement("span");
2498
+ el.className = className;
2499
+ el.textContent = text;
2500
+ el.dataset.icenSearchText = text;
2501
+ return el;
2502
+ }
2503
+ function resourceIcon(source) {
2504
+ const mark = document.createElement("span");
2505
+ mark.className = "icen-ai-composer-popup-option-icon";
2506
+ const svg = (source.icon ? createIcon(source.icon) : null) ?? svgIcon(getRefKindDef(source.kind).icon);
2507
+ if (svg) mark.append(svg);
2508
+ return mark;
2509
+ }
2510
+ function resourceOption(source) {
2511
+ const opt = document.createElement("button");
2512
+ opt.type = "button";
2513
+ opt.className = "icen-ai-composer-popup-option";
2514
+ opt.setAttribute("role", "option");
2515
+ opt.dataset.refId = source.id;
2516
+ opt.dataset.refKind = source.kind;
2517
+ opt.dataset.category = source.kind;
2518
+ opt.dataset.hay = [source.label, source.description, source.sub, getRefKindDef(source.kind).label, ...source.keywords ?? []].join(" ").toLowerCase();
2519
+ opt.setAttribute("aria-selected", "false");
2520
+ if (source.disabled) opt.setAttribute("aria-disabled", "true");
2521
+ const body = document.createElement("span");
2522
+ body.className = "icen-ai-composer-popup-option-copy";
2523
+ body.append(searchLeaf(source.label, "icen-ai-composer-popup-option-label"));
2524
+ if (source.description || source.sub) body.append(searchLeaf(source.description ?? source.sub ?? "", "icen-ai-composer-popup-option-sub"));
2525
+ opt.append(resourceIcon(source), body);
2526
+ return opt;
2527
+ }
2528
+ function commandOption(c) {
2529
+ const opt = document.createElement("button");
2530
+ opt.type = "button";
2531
+ opt.className = "icen-ai-composer-popup-option icen-ai-composer-popup-cmd";
2532
+ opt.setAttribute("role", "option");
2533
+ opt.setAttribute("aria-selected", "false");
2534
+ if (c.disabled) opt.setAttribute("aria-disabled", "true");
2535
+ opt.dataset.name = c.name;
2536
+ opt.dataset.category = "command";
2537
+ opt.dataset.hay = [c.name, c.label, c.description, c.group, ...c.keywords ?? []].join(" ").toLowerCase();
2538
+ const mark = document.createElement("span");
2539
+ mark.className = "icen-ai-composer-popup-option-icon";
2540
+ mark.append(createIcon(c.icon ?? "terminal") ?? createIcon("terminal"));
2541
+ const body = document.createElement("span");
2542
+ body.className = "icen-ai-composer-popup-option-copy";
2543
+ const line = document.createElement("span");
2544
+ line.className = "icen-ai-composer-popup-cmd-line";
2545
+ line.append(searchLeaf(c.label ?? `/${c.name}`, "icen-ai-composer-popup-option-label"));
2546
+ if (c.label) line.append(searchLeaf(`/${c.name}`, "icen-ai-composer-popup-cmd-name"));
2547
+ if (c.argsHint) line.append(searchLeaf(c.argsHint, "icen-ai-composer-popup-cmd-args"));
2548
+ body.append(line);
2549
+ if (c.description) body.append(searchLeaf(c.description, "icen-ai-composer-popup-option-sub"));
2550
+ opt.append(mark, body);
2551
+ return opt;
2552
+ }
2553
+ function popupFoot(s, text) {
2554
+ const foot = document.createElement("div");
2555
+ foot.className = "icen-ai-composer-popup-foot";
2556
+ foot.textContent = text;
2557
+ s.panel.append(foot);
2558
+ }
2559
+ function openComposerLibrary(el, category = "all") {
2560
+ if (!isBrowser()) return;
2561
+ const composer = resolveComposer(el);
2562
+ if (!composer) return;
2563
+ const ta = getTextarea(composer);
2564
+ if (!ta || ta.disabled || ta.readOnly) return;
2565
+ const anchor = composer.querySelector("[data-icen-ai-library]") ?? ta;
2566
+ const sources = REF_SOURCES.get(composer) ?? [], commands = COMMANDS.get(composer) ?? [];
2567
+ if (!sources.length && !commands.length) return;
2568
+ const session = mountPopup(composer, {
2569
+ mode: "library",
2570
+ anchor: composer,
2571
+ sizing: popupSizingFor(composer),
2572
+ returnFocus: anchor,
2573
+ pick: (opt) => {
2574
+ if (opt.dataset.name) {
2575
+ const draft = ta.value.replace(/^\/\S*\s?/, "");
2576
+ ta.value = `/${opt.dataset.name} ${draft}`;
2577
+ autosizeTa(ta);
2578
+ closePopup(composer, false);
2579
+ ta.focus();
2580
+ ta.setSelectionRange(ta.value.length, ta.value.length);
2581
+ return;
2582
+ }
2583
+ const source = sources.find((r) => r.id === opt.dataset.refId && r.kind === opt.dataset.refKind);
2584
+ if (!source) return;
2585
+ const active = (ACTIVE_REFS.get(composer) ?? []).some((r) => r.id === source.id && r.kind === source.kind);
2586
+ if (active) removeActiveRef(composer, source);
2587
+ else addActiveRef(composer, source);
2588
+ opt.setAttribute("aria-selected", String(!active));
2589
+ },
2590
+ build: (s) => {
2591
+ s.panel.setAttribute("role", "dialog");
2592
+ s.panel.setAttribute("aria-label", t("aiComposer.library"));
2593
+ const search = document.createElement("div");
2594
+ search.className = "icen-ai-composer-popup-search";
2595
+ const input = document.createElement("input");
2596
+ input.type = "search";
2597
+ input.className = "icen-ai-composer-popup-search-input";
2598
+ input.placeholder = t("aiComposer.searchLibrary");
2599
+ input.setAttribute("aria-label", t("aiComposer.searchLibrary"));
2600
+ search.append(input);
2601
+ s.searchInput = input;
2602
+ s.panel.append(search);
2603
+ const categories = [{ id: "all", label: t("aiComposer.all") }, ...knownRefKinds(sources).filter((k) => sources.some((r) => r.kind === k)).map((k) => ({ id: k, label: getRefKindDef(k).label })), ...commands.length ? [{ id: "command", label: t("aiComposer.commands") }] : []];
2604
+ s.category = categories.some((c) => c.id === category) ? category : "all";
2605
+ const filters = document.createElement("div");
2606
+ filters.className = "icen-ai-composer-popup-filters";
2607
+ filters.setAttribute("role", "group");
2608
+ filters.setAttribute("aria-label", t("aiComposer.refs"));
2609
+ for (const c of categories) {
2610
+ const b = document.createElement("button");
2611
+ b.type = "button";
2612
+ b.textContent = c.label;
2613
+ b.setAttribute("aria-pressed", String(c.id === s.category));
2614
+ b.addEventListener("click", () => {
2615
+ s.category = c.id;
2616
+ for (const node of filters.querySelectorAll("button")) node.setAttribute("aria-pressed", String(node === b));
2617
+ filterPopupOptions(s, input.value);
2618
+ });
2619
+ filters.append(b);
2620
+ }
2621
+ s.panel.append(filters);
2622
+ const list = document.createElement("div");
2623
+ list.className = "icen-ai-composer-popup-list";
2624
+ list.setAttribute("role", "listbox");
2625
+ list.setAttribute("aria-label", t("aiComposer.library"));
2626
+ list.setAttribute("aria-multiselectable", "true");
2627
+ const addGroup = (title, options) => {
2628
+ const g = document.createElement("div");
2629
+ g.className = "icen-ai-composer-popup-group";
2630
+ g.setAttribute("role", "group");
2631
+ g.setAttribute("aria-label", title);
2632
+ g.append(searchLeaf(title, "icen-ai-composer-popup-group-label"), ...options);
2633
+ list.append(g);
2634
+ s.groups.push(g);
2635
+ s.options.push(...options);
2636
+ };
2637
+ for (const kind of knownRefKinds(sources)) {
2638
+ const options = sources.filter((r) => r.kind === kind).map((r) => {
2639
+ const opt = resourceOption(r);
2640
+ opt.setAttribute("aria-selected", String((ACTIVE_REFS.get(composer) ?? []).some((a) => a.id === r.id && a.kind === r.kind)));
2641
+ return opt;
2642
+ });
2643
+ if (options.length) addGroup(getRefKindDef(kind).label, options);
2644
+ }
2645
+ for (const group of new Set(commands.map((c) => c.group ?? t("aiComposer.commands")))) addGroup(group, commands.filter((c) => (c.group ?? t("aiComposer.commands")) === group).map(commandOption));
2646
+ s.panel.append(list);
2647
+ appendPopupEmpty(s, t("aiComposer.noLibraryMatch"));
2648
+ popupFoot(s, t("aiComposer.libraryHint"));
2649
+ input.addEventListener("input", () => filterPopupOptions(s, input.value));
2650
+ input.addEventListener("keydown", (e) => popupKeydown(composer, s, e));
2651
+ }
2652
+ });
2653
+ anchor.setAttribute("aria-expanded", "true");
2654
+ filterPopupOptions(session, "");
2655
+ session.searchInput?.focus({ preventScroll: true });
1221
2656
  }
1222
2657
  function openModelPopup(composer) {
1223
2658
  const cfg = MODELS.get(composer);
1224
2659
  if (!cfg) return;
1225
- const btn = composer.querySelector("[data-ai-model-open]");
1226
- const anchor = btn ?? composer.querySelector(".ai-composer-box") ?? composer;
2660
+ const btn = composer.querySelector("[data-icen-ai-model-open]");
2661
+ const anchor = btn ?? composer.querySelector(".icen-ai-composer-box") ?? composer;
1227
2662
  const ta = getTextarea(composer);
1228
2663
  const session = mountPopup(composer, {
1229
2664
  mode: "model",
@@ -1233,7 +2668,7 @@ function openModelPopup(composer) {
1233
2668
  pick: (opt) => {
1234
2669
  const provider = opt.dataset.provider ?? "";
1235
2670
  const model = opt.dataset.model ?? "";
1236
- const label = opt.dataset.label ?? model;
2671
+ const label = opt.dataset.icenLabel ?? model;
1237
2672
  const context = typeof opt.dataset.context === "string" ? Number(opt.dataset.context) : void 0;
1238
2673
  MODELS.set(composer, { providers: cfg.providers, current: { provider, model } });
1239
2674
  if (typeof context === "number" && Number.isFinite(context) && context > 0) {
@@ -1242,31 +2677,31 @@ function openModelPopup(composer) {
1242
2677
  MODEL_CTX.delete(composer);
1243
2678
  }
1244
2679
  updateModelButton(composer);
1245
- emit(composer, "icen:ai-model-change", { provider, model, label, context });
2680
+ emit2(composer, "icen:ai-model-change", { provider, model, label, context });
1246
2681
  refreshUsageRing(composer);
1247
2682
  closePopup(composer);
1248
2683
  },
1249
2684
  build: (s) => {
1250
2685
  const search = document.createElement("div");
1251
- search.className = "ai-composer-popup-search";
2686
+ search.className = "icen-ai-composer-popup-search";
1252
2687
  const input = document.createElement("input");
1253
2688
  input.type = "search";
1254
- input.className = "ai-composer-popup-search-input";
1255
- input.placeholder = "\u641C\u7D22\u6A21\u578B";
1256
- input.setAttribute("aria-label", "\u641C\u7D22\u6A21\u578B");
2689
+ input.className = "icen-ai-composer-popup-search-input";
2690
+ input.placeholder = t("aiComposer.searchModels");
2691
+ input.setAttribute("aria-label", t("aiComposer.searchModels"));
1257
2692
  search.appendChild(input);
1258
2693
  s.panel.appendChild(search);
1259
2694
  s.searchInput = input;
1260
2695
  const list = document.createElement("div");
1261
- list.className = "ai-composer-popup-list";
2696
+ list.className = "icen-ai-composer-popup-list";
1262
2697
  list.setAttribute("role", "listbox");
1263
- list.setAttribute("aria-label", "\u9009\u62E9\u6A21\u578B");
2698
+ list.setAttribute("aria-label", t("aiComposer.selectModel"));
1264
2699
  for (const p of cfg.providers) {
1265
2700
  const group = document.createElement("div");
1266
- group.className = "ai-composer-popup-group";
2701
+ group.className = "icen-ai-composer-popup-group";
1267
2702
  const glabel = document.createElement("div");
1268
- glabel.className = "ai-composer-popup-group-label";
1269
- glabel.appendChild(providerMark(p, "ai-composer-popup-group-icon"));
2703
+ glabel.className = "icen-ai-composer-popup-group-label";
2704
+ glabel.appendChild(providerMark(p, "icen-ai-composer-popup-group-icon"));
1270
2705
  const gtext = document.createElement("span");
1271
2706
  gtext.textContent = p.label;
1272
2707
  glabel.appendChild(gtext);
@@ -1274,30 +2709,26 @@ function openModelPopup(composer) {
1274
2709
  for (const m of p.models) {
1275
2710
  const opt = document.createElement("button");
1276
2711
  opt.type = "button";
1277
- opt.className = "ai-composer-popup-option";
2712
+ opt.className = "icen-ai-composer-popup-option";
1278
2713
  opt.setAttribute("role", "option");
1279
2714
  opt.dataset.provider = p.id;
1280
2715
  opt.dataset.providerLabel = p.label;
1281
2716
  opt.dataset.model = m.id;
1282
- opt.dataset.label = m.label;
2717
+ opt.dataset.icenLabel = m.label;
1283
2718
  opt.dataset.hay = `${m.label} ${p.label}`.toLowerCase();
1284
2719
  if (typeof m.context === "number") opt.dataset.context = String(m.context);
1285
2720
  const selected = cfg.current.provider === p.id && cfg.current.model === m.id;
1286
2721
  opt.setAttribute("aria-selected", String(selected));
1287
2722
  const icon = document.createElement("span");
1288
- icon.className = "ai-composer-popup-option-icon";
2723
+ icon.className = "icen-ai-composer-popup-option-icon";
1289
2724
  icon.appendChild(providerMark(p, "ai-composer-popup-option-provider-icon"));
1290
2725
  const label = document.createElement("span");
1291
- label.className = "ai-composer-popup-option-label";
2726
+ label.className = "icen-ai-composer-popup-option-label";
1292
2727
  label.textContent = m.label;
1293
2728
  const meta = document.createElement("span");
1294
- meta.className = "ai-composer-popup-option-meta";
2729
+ meta.className = "icen-ai-composer-popup-option-meta";
1295
2730
  meta.textContent = typeof m.context === "number" ? formatTokens(m.context) : "";
1296
- const check = document.createElement("span");
1297
- check.className = "ai-composer-popup-option-check";
1298
- const checkSvg = svgIcon(ICON_CHECK);
1299
- if (checkSvg) check.appendChild(checkSvg);
1300
- opt.append(icon, label, meta, check);
2731
+ opt.append(icon, label, meta);
1301
2732
  group.appendChild(opt);
1302
2733
  s.options.push(opt);
1303
2734
  }
@@ -1305,9 +2736,9 @@ function openModelPopup(composer) {
1305
2736
  s.groups.push(group);
1306
2737
  }
1307
2738
  s.panel.appendChild(list);
1308
- appendPopupEmpty(s, "\u65E0\u5339\u914D\u6A21\u578B");
2739
+ appendPopupEmpty(s, t("aiComposer.noModelMatch"));
1309
2740
  const foot = document.createElement("div");
1310
- foot.className = "ai-composer-popup-foot";
2741
+ foot.className = "icen-ai-composer-popup-foot";
1311
2742
  const usageCfg = USAGE.get(composer);
1312
2743
  if (usageCfg) {
1313
2744
  const u = usageCfg.usage;
@@ -1319,7 +2750,7 @@ function openModelPopup(composer) {
1319
2750
  const info = svgIcon(ICON_INFO);
1320
2751
  if (info) foot.appendChild(info);
1321
2752
  const footText = document.createElement("span");
1322
- footText.textContent = "\u5207\u6362\u6A21\u578B\u4F1A\u4F7F prompt \u7F13\u5B58\u5931\u6548";
2753
+ footText.textContent = t("aiComposer.cacheInvalidHint");
1323
2754
  foot.appendChild(footText);
1324
2755
  s.panel.appendChild(foot);
1325
2756
  s.keydownHandler = (e) => popupKeydown(composer, s, e);
@@ -1332,10 +2763,21 @@ function openModelPopup(composer) {
1332
2763
  btn?.setAttribute("aria-expanded", "true");
1333
2764
  session.searchInput?.focus();
1334
2765
  }
2766
+ function runComposerCommand(composer, name) {
2767
+ const command = COMMANDS.get(composer)?.find((c) => c.name === name && !c.disabled);
2768
+ const ta = getTextarea(composer);
2769
+ if (!command || !ta || ta.disabled || ta.readOnly) return false;
2770
+ const args = /^\/\S*\s+([\s\S]*)$/.exec(ta.value)?.[1] ?? "";
2771
+ ta.value = "";
2772
+ autosizeTa(ta);
2773
+ emit2(composer, "icen:ai-command", { name: command.name, args });
2774
+ closePopup(composer);
2775
+ return true;
2776
+ }
1335
2777
  function openCommandPopup(composer, token) {
1336
2778
  const commands = COMMANDS.get(composer);
1337
2779
  if (!commands || commands.length === 0) return;
1338
- const box = composer.querySelector(".ai-composer-box") ?? composer;
2780
+ const box = composer.querySelector(".icen-ai-composer-box") ?? composer;
1339
2781
  const ta = getTextarea(composer);
1340
2782
  const session = mountPopup(composer, {
1341
2783
  mode: "command",
@@ -1343,59 +2785,27 @@ function openCommandPopup(composer, token) {
1343
2785
  sizing: popupSizingFor(box),
1344
2786
  returnFocus: ta,
1345
2787
  pick: (opt) => {
1346
- const name = opt.dataset.name ?? "";
1347
- const m = /^\/\S*\s+([\s\S]*)$/.exec(ta?.value ?? "");
1348
- const args = m ? m[1] : "";
1349
- if (ta) {
1350
- ta.value = "";
1351
- autosizeTa(ta);
1352
- }
1353
- emit(composer, "icen:ai-command", { name, args });
1354
- closePopup(composer);
2788
+ runComposerCommand(composer, opt.dataset.name ?? "");
1355
2789
  },
1356
2790
  build: (s) => {
1357
2791
  const list = document.createElement("div");
1358
- list.className = "ai-composer-popup-list";
2792
+ list.className = "icen-ai-composer-popup-list";
1359
2793
  list.setAttribute("role", "listbox");
1360
- list.setAttribute("aria-label", "\u547D\u4EE4");
2794
+ list.setAttribute("aria-label", t("aiComposer.commands"));
1361
2795
  const group = document.createElement("div");
1362
- group.className = "ai-composer-popup-group";
2796
+ group.className = "icen-ai-composer-popup-group";
1363
2797
  for (const c of commands) {
1364
- const opt = document.createElement("button");
1365
- opt.type = "button";
1366
- opt.className = "ai-composer-popup-option ai-composer-popup-cmd";
1367
- opt.setAttribute("role", "option");
1368
- opt.dataset.name = c.name;
1369
- opt.dataset.hay = `${c.name} ${c.description ?? ""}`.toLowerCase();
1370
- const line = document.createElement("span");
1371
- line.className = "ai-composer-popup-cmd-line";
1372
- const nameEl = document.createElement("span");
1373
- nameEl.className = "ai-composer-popup-cmd-name";
1374
- nameEl.textContent = `/${c.name}`;
1375
- line.appendChild(nameEl);
1376
- if (c.argsHint) {
1377
- const argsEl = document.createElement("span");
1378
- argsEl.className = "ai-composer-popup-cmd-args";
1379
- argsEl.textContent = c.argsHint;
1380
- line.appendChild(argsEl);
1381
- }
1382
- opt.appendChild(line);
1383
- if (c.description) {
1384
- opt.appendChild(Object.assign(document.createElement("span"), {
1385
- className: "ai-composer-popup-cmd-desc",
1386
- textContent: c.description
1387
- }));
1388
- }
2798
+ const opt = commandOption(c);
1389
2799
  group.appendChild(opt);
1390
2800
  s.options.push(opt);
1391
2801
  }
1392
2802
  list.appendChild(group);
1393
2803
  s.groups.push(group);
1394
2804
  s.panel.appendChild(list);
1395
- appendPopupEmpty(s, "\u65E0\u5339\u914D\u547D\u4EE4");
2805
+ appendPopupEmpty(s, t("aiComposer.noCommandMatch"));
2806
+ popupFoot(s, t("aiComposer.commandHint"));
1396
2807
  }
1397
2808
  });
1398
- ta?.setAttribute("aria-expanded", "true");
1399
2809
  filterPopupOptions(session, token);
1400
2810
  }
1401
2811
  function commandToken(value) {
@@ -1414,7 +2824,7 @@ function updateCommandPopup(composer, s) {
1414
2824
  function openRefPopup(composer, range, filter) {
1415
2825
  const sources = REF_SOURCES.get(composer);
1416
2826
  if (!sources || sources.length === 0) return;
1417
- const box = composer.querySelector(".ai-composer-box") ?? composer;
2827
+ const box = composer.querySelector(".icen-ai-composer-box") ?? composer;
1418
2828
  const ta = getTextarea(composer);
1419
2829
  const session = mountPopup(composer, {
1420
2830
  mode: "ref",
@@ -1423,7 +2833,7 @@ function openRefPopup(composer, range, filter) {
1423
2833
  returnFocus: ta,
1424
2834
  refRange: range,
1425
2835
  pick: (opt) => {
1426
- const source = (REF_SOURCES.get(composer) ?? []).find((r2) => r2.id === opt.dataset.refId);
2836
+ const source = (REF_SOURCES.get(composer) ?? []).find((r2) => r2.id === opt.dataset.refId && r2.kind === opt.dataset.refKind);
1427
2837
  const cur = POPUP.get(composer);
1428
2838
  const r = cur?.refRange ?? (ta ? findRefToken(ta) : null);
1429
2839
  if (source && ta && r) {
@@ -1439,41 +2849,23 @@ function openRefPopup(composer, range, filter) {
1439
2849
  },
1440
2850
  build: (s) => {
1441
2851
  const list = document.createElement("div");
1442
- list.className = "ai-composer-popup-list";
2852
+ list.className = "icen-ai-composer-popup-list";
1443
2853
  list.setAttribute("role", "listbox");
1444
- list.setAttribute("aria-label", "\u5F15\u7528");
2854
+ list.setAttribute("aria-label", t("aiComposer.refs"));
1445
2855
  for (const kind of knownRefKinds(sources)) {
1446
2856
  const def = getRefKindDef(kind);
1447
2857
  const items = sources.filter((r) => r.kind === kind);
1448
2858
  if (items.length === 0) continue;
1449
2859
  const group = document.createElement("div");
1450
- group.className = "ai-composer-popup-group";
1451
- group.dataset.kind = kind;
2860
+ group.className = "icen-ai-composer-popup-group";
2861
+ group.dataset.icenKind = kind;
1452
2862
  group.appendChild(Object.assign(document.createElement("div"), {
1453
- className: "ai-composer-popup-group-label",
2863
+ className: "icen-ai-composer-popup-group-label",
1454
2864
  textContent: def.label
1455
2865
  }));
1456
2866
  for (const r of items) {
1457
- const opt = document.createElement("button");
1458
- opt.type = "button";
1459
- opt.className = "ai-composer-popup-option";
1460
- opt.setAttribute("role", "option");
1461
- opt.dataset.refId = r.id;
1462
- opt.dataset.hay = `${r.label} ${r.sub ?? ""}`.toLowerCase();
1463
- const icon = document.createElement("span");
1464
- icon.className = "ai-composer-popup-option-icon";
1465
- const svg2 = svgIcon(def.icon);
1466
- if (svg2) icon.appendChild(svg2);
1467
- const label = document.createElement("span");
1468
- label.className = "ai-composer-popup-option-label";
1469
- label.textContent = r.label;
1470
- if (r.sub) {
1471
- const sub = document.createElement("span");
1472
- sub.className = "ai-composer-popup-option-sub";
1473
- sub.textContent = r.sub;
1474
- label.appendChild(sub);
1475
- }
1476
- opt.append(icon, label);
2867
+ const opt = resourceOption(r);
2868
+ opt.setAttribute("aria-selected", String((ACTIVE_REFS.get(composer) ?? []).some((a) => a.id === r.id && a.kind === r.kind)));
1477
2869
  group.appendChild(opt);
1478
2870
  s.options.push(opt);
1479
2871
  }
@@ -1481,22 +2873,22 @@ function openRefPopup(composer, range, filter) {
1481
2873
  s.groups.push(group);
1482
2874
  }
1483
2875
  s.panel.appendChild(list);
1484
- appendPopupEmpty(s, "\u65E0\u5339\u914D\u5F15\u7528");
2876
+ appendPopupEmpty(s, t("aiComposer.noRefMatch"));
2877
+ popupFoot(s, t("aiComposer.refHint"));
1485
2878
  }
1486
2879
  });
1487
- ta?.setAttribute("aria-expanded", "true");
1488
2880
  filterPopupOptions(session, filter);
1489
2881
  }
1490
2882
  function updateRefPopup(composer, s) {
1491
2883
  const ta = getTextarea(composer);
1492
- const t = ta ? findRefToken(ta) : null;
1493
- if (!t) {
2884
+ const t2 = ta ? findRefToken(ta) : null;
2885
+ if (!t2) {
1494
2886
  closePopup(composer, false);
1495
2887
  maybeOpenTriggerPopups(composer);
1496
2888
  return;
1497
2889
  }
1498
- s.refRange = { start: t.start, end: t.end };
1499
- filterPopupOptions(s, t.filter);
2890
+ s.refRange = { start: t2.start, end: t2.end };
2891
+ filterPopupOptions(s, t2.filter);
1500
2892
  }
1501
2893
  function findRefToken(ta) {
1502
2894
  const value = ta.value;
@@ -1518,30 +2910,34 @@ function maybeOpenTriggerPopups(composer) {
1518
2910
  }
1519
2911
  const sources = REF_SOURCES.get(composer);
1520
2912
  if (sources && sources.length > 0) {
1521
- const t = findRefToken(ta);
1522
- if (t) openRefPopup(composer, { start: t.start, end: t.end }, t.filter);
2913
+ const t2 = findRefToken(ta);
2914
+ if (t2) openRefPopup(composer, { start: t2.start, end: t2.end }, t2.filter);
1523
2915
  }
1524
2916
  }
1525
2917
  function ensureRefsRow(composer) {
1526
- const existing = composer.querySelector(".ai-composer-refs");
2918
+ const existing = composer.querySelector(".icen-ai-composer-refs");
1527
2919
  if (existing) return existing;
1528
2920
  const row = document.createElement("div");
1529
- row.className = "ai-composer-refs";
2921
+ row.className = "icen-ai-composer-refs";
1530
2922
  row.dataset.aiRefs = "auto";
1531
2923
  row.hidden = true;
1532
- const attach = composer.querySelector(".ai-composer-attach");
1533
- const box = composer.querySelector(".ai-composer-box");
2924
+ const attach = composer.querySelector(".icen-ai-composer-attach");
2925
+ const box = composer.querySelector(".icen-ai-composer-box");
1534
2926
  composer.insertBefore(row, attach ?? box ?? null);
1535
2927
  return row;
1536
2928
  }
1537
2929
  function renderRefs(composer) {
1538
- const row = composer.querySelector(".ai-composer-refs");
2930
+ const row = composer.querySelector(".icen-ai-composer-refs");
1539
2931
  const actives = ACTIVE_REFS.get(composer) ?? [];
1540
2932
  if (!row) return;
1541
2933
  row.replaceChildren(
1542
2934
  ...actives.map((src) => {
1543
- const chip = makeChip(src.label, true, `\u79FB\u9664\u5F15\u7528 ${src.label}`);
2935
+ const chip = makeChip(src.label, true, t("aiComposer.removeRef", { p0: src.label }));
2936
+ chip.prepend(resourceIcon(src));
2937
+ chip.dataset.icenKind = src.kind;
1544
2938
  chip.dataset.refId = src.id;
2939
+ chip.dataset.refKind = src.kind;
2940
+ chip.title = [src.label, src.description ?? src.sub].filter(Boolean).join(" \xB7 ");
1545
2941
  return chip;
1546
2942
  })
1547
2943
  );
@@ -1549,31 +2945,69 @@ function renderRefs(composer) {
1549
2945
  }
1550
2946
  function addActiveRef(composer, source) {
1551
2947
  const actives = ACTIVE_REFS.get(composer) ?? [];
1552
- if (actives.some((r) => r.id === source.id)) return;
2948
+ if (actives.some((r) => r.id === source.id && r.kind === source.kind)) return;
1553
2949
  actives.push(source);
1554
2950
  ACTIVE_REFS.set(composer, actives);
1555
2951
  renderRefs(composer);
1556
- emit(composer, "icen:ai-ref", { action: "add", ref: source });
2952
+ emit2(composer, "icen:ai-ref", { action: "add", ref: source });
1557
2953
  }
1558
2954
  function removeActiveRef(composer, source) {
1559
2955
  const actives = ACTIVE_REFS.get(composer) ?? [];
1560
- const idx = actives.findIndex((r) => r.id === source.id);
2956
+ const idx = actives.findIndex((r) => r.id === source.id && r.kind === source.kind);
1561
2957
  if (idx === -1) return;
1562
2958
  actives.splice(idx, 1);
1563
2959
  ACTIVE_REFS.set(composer, actives);
2960
+ const activeButton = document.activeElement;
2961
+ const restore = activeButton instanceof Element && !!activeButton.closest(".icen-ai-composer-refs");
1564
2962
  renderRefs(composer);
2963
+ if (restore) {
2964
+ const buttons = composer.querySelectorAll(".icen-ai-composer-refs .icen-ai-composer-chip-remove");
2965
+ (buttons[Math.min(idx, buttons.length - 1)] ?? getTextarea(composer))?.focus({ preventScroll: true });
2966
+ }
1565
2967
  const ta = getTextarea(composer);
1566
- if (ta) {
2968
+ if (ta && !actives.some((r) => r.label === source.label)) {
1567
2969
  const needle = `@${source.label}`;
1568
- const at = ta.value.indexOf(needle);
2970
+ let at = ta.value.indexOf(needle);
2971
+ while (at !== -1 && (at > 0 && !/\s/.test(ta.value[at - 1]) || ta.value[at + needle.length] !== void 0 && !/\s/.test(ta.value[at + needle.length]))) at = ta.value.indexOf(needle, at + needle.length);
1569
2972
  if (at !== -1) {
2973
+ const start = ta.selectionStart, end = ta.selectionEnd, direction = ta.selectionDirection;
1570
2974
  let endIdx = at + needle.length;
1571
2975
  if (ta.value[endIdx] === " ") endIdx += 1;
1572
2976
  ta.value = ta.value.slice(0, at) + ta.value.slice(endIdx);
2977
+ const shifted = (pos) => pos <= at ? pos : pos < endIdx ? at : pos - (endIdx - at);
2978
+ ta.setSelectionRange(shifted(start), shifted(end), direction);
1573
2979
  autosizeTa(ta);
1574
2980
  }
1575
2981
  }
1576
- emit(composer, "icen:ai-ref", { action: "remove", ref: source });
2982
+ emit2(composer, "icen:ai-ref", { action: "remove", ref: source });
2983
+ }
2984
+ function renderFiles(composer) {
2985
+ let row = composer.querySelector(".icen-ai-composer-attach");
2986
+ const files = FILES.get(composer) ?? [];
2987
+ if (!row && files.length) {
2988
+ row = document.createElement("div");
2989
+ row.className = "icen-ai-composer-attach";
2990
+ composer.insertBefore(row, composer.querySelector(".icen-ai-composer-box"));
2991
+ }
2992
+ if (!row) return;
2993
+ row.replaceChildren(...files.map((file, index) => {
2994
+ const chip = makeChip(file.name, true, t("aiComposer.removeAttachment", { p0: file.name }), "file");
2995
+ chip.dataset.icenFile = String(index);
2996
+ const size = document.createElement("span");
2997
+ size.className = "icen-ai-composer-chip-meta";
2998
+ size.textContent = file.size < 1024 ? `${file.size} B` : `${Math.ceil(file.size / 1024)} KB`;
2999
+ chip.insertBefore(size, chip.lastElementChild);
3000
+ chip.title = file.name;
3001
+ return chip;
3002
+ }));
3003
+ row.hidden = !files.length;
3004
+ }
3005
+ function getComposerDraft(el) {
3006
+ if (!isBrowser()) return { text: "" };
3007
+ const c = resolveComposer(el);
3008
+ if (!c) return { text: "" };
3009
+ const refs = ACTIVE_REFS.get(c) ?? [], files = FILES.get(c) ?? [];
3010
+ return { text: getTextarea(c)?.value ?? "", ...refs.length ? { refs: refs.map((r) => ({ ...r })) } : {}, ...files.length ? { files: [...files] } : {} };
1577
3011
  }
1578
3012
  function pushHistory(composer, text) {
1579
3013
  const h2 = HISTORIES.get(composer) ?? { items: [], index: -1 };
@@ -1593,31 +3027,35 @@ function setupComposer(composer) {
1593
3027
  el.__icenAiComposerInit = false;
1594
3028
  return void 0;
1595
3029
  }
1596
- const queueEl = composer.querySelector(".ai-composer-queue");
1597
- const attachEl = composer.querySelector(".ai-composer-attach");
3030
+ const queueEl = composer.querySelector(".icen-ai-composer-queue");
1598
3031
  const { sendBtn, sendIcon, stopIcon } = ensureIcons(composer);
1599
3032
  if (!ta.hasAttribute("placeholder")) {
1600
- ta.setAttribute("placeholder", "\u8F93\u5165\u6D88\u606F\uFF0C/ \u547D\u4EE4 \xB7 @ \u5F15\u7528 \xB7 Enter \u53D1\u9001");
3033
+ ta.setAttribute("placeholder", t("aiComposer.placeholder"));
1601
3034
  }
1602
3035
  const renderQueue = () => renderQueueChips(composer);
1603
- const enqueue = (text) => {
3036
+ const enqueue = (draft) => {
1604
3037
  const queue = QUEUES.get(composer) ?? [];
1605
- queue.push(text);
3038
+ queue.push({ ...draft, ...draft.refs ? { refs: draft.refs.map((r) => ({ ...r })) } : {}, ...draft.files ? { files: [...draft.files] } : {} });
1606
3039
  QUEUES.set(composer, queue);
1607
3040
  renderQueue();
1608
3041
  };
1609
3042
  const isRunning = () => RUNNING.get(composer) ?? false;
1610
3043
  const submit = () => {
1611
- const text = ta.value;
1612
- if (!text.trim()) return;
3044
+ if (ta.disabled || ta.readOnly || composing) return;
3045
+ const draft = getComposerDraft(composer);
3046
+ if (!draft.text.trim() && !draft.files?.length && !draft.refs?.length) return;
1613
3047
  ta.value = "";
1614
3048
  autosizeTa(ta);
3049
+ ACTIVE_REFS.set(composer, []);
3050
+ FILES.set(composer, []);
3051
+ renderRefs(composer);
3052
+ renderFiles(composer);
1615
3053
  if (isRunning()) {
1616
- enqueue(text);
1617
- emit(composer, "icen:ai-queue", { text });
3054
+ enqueue(draft);
3055
+ emit2(composer, "icen:ai-queue", draft);
1618
3056
  } else {
1619
- pushHistory(composer, text);
1620
- emit(composer, "icen:ai-send", { text });
3057
+ pushHistory(composer, draft.text);
3058
+ emit2(composer, "icen:ai-send", draft);
1621
3059
  }
1622
3060
  };
1623
3061
  SUBMITS.set(composer, submit);
@@ -1625,12 +3063,16 @@ function setupComposer(composer) {
1625
3063
  const queue = QUEUES.get(composer) ?? [];
1626
3064
  if (queue.length === 0) return;
1627
3065
  const index = queue.length - 1;
1628
- const text = queue.pop() ?? "";
3066
+ const draft = queue.pop();
1629
3067
  QUEUES.set(composer, queue);
1630
3068
  renderQueue();
1631
- ta.value = text;
3069
+ ta.value = draft.text;
3070
+ for (const ref of draft.refs ?? []) addActiveRef(composer, ref);
3071
+ const files = FILES.get(composer) ?? [];
3072
+ FILES.set(composer, Array.from(/* @__PURE__ */ new Set([...files, ...draft.files ?? []])));
3073
+ renderFiles(composer);
1632
3074
  autosizeTa(ta);
1633
- emit(composer, "icen:ai-dequeue", { index });
3075
+ emit2(composer, "icen:ai-dequeue", { index });
1634
3076
  };
1635
3077
  const browseHistory = (delta) => {
1636
3078
  const h2 = HISTORIES.get(composer);
@@ -1650,7 +3092,7 @@ function setupComposer(composer) {
1650
3092
  autosizeTa(ta);
1651
3093
  };
1652
3094
  const onKeydown = (e) => {
1653
- if (composing || e.isComposing) return;
3095
+ if (composing || e.isComposing || ta.disabled || ta.readOnly) return;
1654
3096
  const session = POPUP.get(composer);
1655
3097
  if (session) {
1656
3098
  popupKeydown(composer, session, e);
@@ -1658,6 +3100,7 @@ function setupComposer(composer) {
1658
3100
  }
1659
3101
  if (e.key === "Enter" && !e.shiftKey) {
1660
3102
  e.preventDefault();
3103
+ if (ta.value.startsWith("/") && runComposerCommand(composer, commandToken(ta.value))) return;
1661
3104
  submit();
1662
3105
  return;
1663
3106
  }
@@ -1665,7 +3108,7 @@ function setupComposer(composer) {
1665
3108
  const h2 = HISTORIES.get(composer);
1666
3109
  const browsing = (h2?.index ?? -1) >= 0;
1667
3110
  if (ta.value === "") {
1668
- if (isRunning() && (QUEUES.get(composer) ?? []).length > 0) {
3111
+ if ((QUEUES.get(composer) ?? []).length > 0) {
1669
3112
  e.preventDefault();
1670
3113
  takeBackLastQueued();
1671
3114
  return;
@@ -1690,6 +3133,7 @@ function setupComposer(composer) {
1690
3133
  };
1691
3134
  const onInput = () => {
1692
3135
  autosizeTa(ta);
3136
+ if (composing) return;
1693
3137
  const h2 = HISTORIES.get(composer);
1694
3138
  if (h2 && h2.index >= 0 && ta.value !== h2.items[h2.index]) h2.index = -1;
1695
3139
  const session = POPUP.get(composer);
@@ -1703,34 +3147,39 @@ function setupComposer(composer) {
1703
3147
  let composing = false;
1704
3148
  const onCompositionStart = () => {
1705
3149
  composing = true;
3150
+ closePopup(composer, false);
1706
3151
  };
1707
3152
  const onCompositionEnd = () => {
1708
3153
  composing = false;
3154
+ onInput();
1709
3155
  };
1710
3156
  const onSendClick = () => {
1711
3157
  if (isRunning()) {
1712
- emit(composer, "icen:ai-stop", {});
3158
+ emit2(composer, "icen:ai-stop", {});
1713
3159
  } else {
1714
3160
  submit();
1715
3161
  }
1716
3162
  };
1717
3163
  const onQueueClick = (e) => {
1718
- const btn = e.target instanceof Element ? e.target.closest(".ai-composer-chip-remove") : null;
3164
+ const btn = e.target instanceof Element ? e.target.closest(".icen-ai-composer-chip-remove") : null;
1719
3165
  if (!btn) return;
1720
- const index = Array.from(queueEl?.querySelectorAll(".ai-composer-chip-remove") ?? []).indexOf(btn);
3166
+ const index = Array.from(queueEl?.querySelectorAll(".icen-ai-composer-chip-remove") ?? []).indexOf(btn);
1721
3167
  const queue = QUEUES.get(composer) ?? [];
1722
3168
  if (index >= 0 && index < queue.length) {
1723
3169
  queue.splice(index, 1);
1724
3170
  QUEUES.set(composer, queue);
1725
3171
  renderQueue();
1726
- emit(composer, "icen:ai-dequeue", { index });
3172
+ const buttons = queueEl?.querySelectorAll(".icen-ai-composer-chip-remove");
3173
+ (buttons?.[Math.min(index, buttons.length - 1)] ?? ta).focus({ preventScroll: true });
3174
+ emit2(composer, "icen:ai-dequeue", { index });
1727
3175
  }
1728
3176
  };
1729
3177
  const onRefsClick = (e) => {
1730
- const btn = e.target instanceof Element ? e.target.closest(".ai-composer-chip-remove") : null;
1731
- if (!btn || !btn.closest(".ai-composer-refs")) return;
1732
- const id = btn.closest(".ai-composer-chip")?.dataset.refId;
1733
- const source = (ACTIVE_REFS.get(composer) ?? []).find((r) => r.id === id);
3178
+ const btn = e.target instanceof Element ? e.target.closest(".icen-ai-composer-chip-remove") : null;
3179
+ if (!btn || !btn.closest(".icen-ai-composer-refs")) return;
3180
+ const id = btn.closest(".icen-ai-composer-chip")?.dataset.refId;
3181
+ const kind = btn.closest(".icen-ai-composer-chip")?.dataset.refKind;
3182
+ const source = (ACTIVE_REFS.get(composer) ?? []).find((r) => r.id === id && r.kind === kind);
1734
3183
  if (source) removeActiveRef(composer, source);
1735
3184
  };
1736
3185
  const fileInput = document.createElement("input");
@@ -1739,20 +3188,32 @@ function setupComposer(composer) {
1739
3188
  fileInput.multiple = true;
1740
3189
  composer.appendChild(fileInput);
1741
3190
  const onAttachClick = () => {
1742
- fileInput.click();
3191
+ if (!ta.disabled && !ta.readOnly) fileInput.click();
1743
3192
  };
1744
3193
  const addFiles = (files) => {
1745
- if (files.length === 0) return;
1746
- if (attachEl) {
1747
- for (const f of files) {
1748
- const chip = makeChip(f.name, true, `\u79FB\u9664\u9644\u4EF6 ${f.name}`);
1749
- const remove = chip.querySelector(".ai-composer-chip-remove");
1750
- remove?.addEventListener("click", () => chip.remove(), { once: true });
1751
- attachEl.appendChild(chip);
1752
- }
1753
- attachEl.hidden = false;
3194
+ if (!files.length || ta.disabled || ta.readOnly) return;
3195
+ const current2 = FILES.get(composer) ?? [];
3196
+ const accepted = [];
3197
+ for (const file of files) {
3198
+ if (![...current2, ...accepted].some((c) => c.name === file.name && c.size === file.size && c.lastModified === file.lastModified && c.type === file.type)) accepted.push(file);
1754
3199
  }
1755
- emit(composer, "icen:ai-attach", { files });
3200
+ if (!accepted.length) return;
3201
+ FILES.set(composer, [...current2, ...accepted]);
3202
+ renderFiles(composer);
3203
+ emit2(composer, "icen:ai-attach", { files: accepted });
3204
+ };
3205
+ const onRemoveFile = (e) => {
3206
+ const button = e.target instanceof Element ? e.target.closest(".icen-ai-composer-attach .icen-ai-composer-chip-remove") : null;
3207
+ if (!button) return;
3208
+ const index = Number(button.closest("[data-icen-file]")?.dataset.icenFile);
3209
+ const files = FILES.get(composer) ?? [];
3210
+ if (!Number.isInteger(index) || index < 0 || index >= files.length) return;
3211
+ const [file] = files.splice(index, 1);
3212
+ FILES.set(composer, files);
3213
+ renderFiles(composer);
3214
+ const buttons = composer.querySelectorAll(".icen-ai-composer-attach .icen-ai-composer-chip-remove");
3215
+ (buttons[Math.min(index, buttons.length - 1)] ?? ta).focus({ preventScroll: true });
3216
+ emit2(composer, "icen:ai-attachment-remove", { file, files: [...files] });
1756
3217
  };
1757
3218
  const onFileChange = () => {
1758
3219
  const files = Array.from(fileInput.files ?? []);
@@ -1765,7 +3226,7 @@ function setupComposer(composer) {
1765
3226
  e.preventDefault();
1766
3227
  addFiles(files);
1767
3228
  };
1768
- const boxEl = composer.querySelector(".ai-composer-box");
3229
+ const boxEl = composer.querySelector(".icen-ai-composer-box");
1769
3230
  const onDragOver = (e) => {
1770
3231
  if (!e.dataTransfer?.types.includes("Files")) return;
1771
3232
  e.preventDefault();
@@ -1792,7 +3253,8 @@ function setupComposer(composer) {
1792
3253
  sendBtn?.addEventListener("click", onSendClick);
1793
3254
  queueEl?.addEventListener("click", onQueueClick);
1794
3255
  composer.addEventListener("click", onRefsClick);
1795
- composer.querySelector("[data-ai-attach]")?.addEventListener("click", onAttachClick);
3256
+ composer.addEventListener("click", onRemoveFile);
3257
+ composer.querySelector("[data-icen-ai-attach]")?.addEventListener("click", onAttachClick);
1796
3258
  fileInput.addEventListener("change", onFileChange);
1797
3259
  const initialRunning = RUNNING.get(composer) ?? composer.classList.contains("is-running");
1798
3260
  if (initialRunning) setComposerRunning(composer, true);
@@ -1803,6 +3265,7 @@ function setupComposer(composer) {
1803
3265
  autosizeTa(ta);
1804
3266
  renderQueue();
1805
3267
  renderRefs(composer);
3268
+ renderFiles(composer);
1806
3269
  return () => {
1807
3270
  closePopup(composer, false);
1808
3271
  ta.removeEventListener("keydown", onKeydown);
@@ -1816,7 +3279,8 @@ function setupComposer(composer) {
1816
3279
  sendBtn?.removeEventListener("click", onSendClick);
1817
3280
  queueEl?.removeEventListener("click", onQueueClick);
1818
3281
  composer.removeEventListener("click", onRefsClick);
1819
- composer.querySelector("[data-ai-attach]")?.removeEventListener("click", onAttachClick);
3282
+ composer.removeEventListener("click", onRemoveFile);
3283
+ composer.querySelector("[data-icen-ai-attach]")?.removeEventListener("click", onAttachClick);
1820
3284
  fileInput.removeEventListener("change", onFileChange);
1821
3285
  fileInput.remove();
1822
3286
  el.__icenAiComposerInit = false;
@@ -1827,10 +3291,10 @@ function initAiComposer(root) {
1827
3291
  if (isBrowser()) {
1828
3292
  const scope = root ?? document;
1829
3293
  const candidates = [];
1830
- if (scope instanceof Element && scope.matches("[data-ai-composer]")) {
3294
+ if (scope instanceof Element && scope.matches("[data-icen-ai-composer]")) {
1831
3295
  candidates.push(scope);
1832
3296
  }
1833
- candidates.push(...Array.from(scope.querySelectorAll("[data-ai-composer]")));
3297
+ candidates.push(...Array.from(scope.querySelectorAll("[data-icen-ai-composer]")));
1834
3298
  for (const composer of candidates) {
1835
3299
  const cleanup = setupComposer(composer);
1836
3300
  if (cleanup) cleanups.push(cleanup);
@@ -1841,7 +3305,7 @@ function initAiComposer(root) {
1841
3305
  cleanups.length = 0;
1842
3306
  };
1843
3307
  }
1844
- function setComposerModels(el, providers, current) {
3308
+ function setComposerModels(el, providers, current2) {
1845
3309
  if (!isBrowser()) return;
1846
3310
  const composer = resolveComposer(el);
1847
3311
  if (!composer) return;
@@ -1851,13 +3315,13 @@ function setComposerModels(el, providers, current) {
1851
3315
  if (list.length === 0) {
1852
3316
  MODELS.delete(composer);
1853
3317
  MODEL_CTX.delete(composer);
1854
- const btn = composer.querySelector("[data-ai-model-open]");
1855
- if (btn?.dataset.aiModelOpen === "auto") btn.remove();
3318
+ const btn = composer.querySelector("[data-icen-ai-model-open]");
3319
+ if (btn?.dataset.icenAiModelOpen === "auto") btn.remove();
1856
3320
  syncToolbar(composer);
1857
3321
  refreshUsageRing(composer);
1858
3322
  return;
1859
3323
  }
1860
- const cur = current ?? { provider: list[0].id, model: list[0].models[0].id };
3324
+ const cur = current2 ?? { provider: list[0].id, model: list[0].models[0].id };
1861
3325
  MODELS.set(composer, { providers: list, current: cur });
1862
3326
  const provider = list.find((p) => p.id === cur.provider) ?? list[0];
1863
3327
  const model = provider.models.find((m) => m.id === cur.model) ?? provider.models[0];
@@ -1878,10 +3342,13 @@ function setComposerCommands(el, commands) {
1878
3342
  if (list.length === 0) {
1879
3343
  COMMANDS.delete(composer);
1880
3344
  const session = POPUP.get(composer);
1881
- if (session?.mode === "command") closePopup(composer);
3345
+ if (session?.mode === "command" || session?.mode === "library") closePopup(composer);
3346
+ syncToolbar(composer);
1882
3347
  return;
1883
3348
  }
1884
3349
  COMMANDS.set(composer, list);
3350
+ syncToolbar(composer);
3351
+ if (POPUP.get(composer)) closePopup(composer);
1885
3352
  }
1886
3353
  function setComposerRefs(el, sources) {
1887
3354
  if (!isBrowser()) return;
@@ -1889,6 +3356,8 @@ function setComposerRefs(el, sources) {
1889
3356
  if (!composer) return;
1890
3357
  const list = (Array.isArray(sources) ? sources : []).filter((s) => s && typeof s.label === "string" && s.label);
1891
3358
  REF_SOURCES.set(composer, list);
3359
+ syncToolbar(composer);
3360
+ if (POPUP.get(composer)) closePopup(composer);
1892
3361
  if (list.length === 0) {
1893
3362
  const session = POPUP.get(composer);
1894
3363
  if (session?.mode === "ref") closePopup(composer);
@@ -1902,8 +3371,8 @@ function setComposerUsage(el, usage, opts = {}) {
1902
3371
  if (!composer) return;
1903
3372
  if (!usage) {
1904
3373
  USAGE.delete(composer);
1905
- const mount = composer.querySelector(".ai-composer-usage");
1906
- if (mount?.dataset.aiUsage === "auto") mount.remove();
3374
+ const mount = composer.querySelector(".icen-ai-composer-usage");
3375
+ if (mount?.dataset.icenAiUsage === "auto") mount.remove();
1907
3376
  syncToolbar(composer);
1908
3377
  return;
1909
3378
  }
@@ -1915,7 +3384,7 @@ function setComposerTodo(el, items) {
1915
3384
  if (!isBrowser()) return;
1916
3385
  const composer = resolveComposer(el);
1917
3386
  if (!composer) return;
1918
- let chip = composer.querySelector(".ai-composer-todo");
3387
+ let chip = composer.querySelector(".icen-ai-composer-todo");
1919
3388
  if (!items || items.length === 0) {
1920
3389
  TODO_STATES.delete(composer);
1921
3390
  chip?.remove();
@@ -1925,17 +3394,17 @@ function setComposerTodo(el, items) {
1925
3394
  if (!chip) {
1926
3395
  const btn = document.createElement("button");
1927
3396
  btn.type = "button";
1928
- btn.className = "ai-composer-todo";
3397
+ btn.className = "icen-ai-composer-todo";
1929
3398
  btn.setAttribute("aria-haspopup", "true");
1930
3399
  btn.addEventListener("click", () => {
1931
3400
  const cur = TODO_STATES.get(composer);
1932
3401
  if (!cur) return;
1933
3402
  const p = document.createElement("div");
1934
- p.className = "popover ai-composer-todo-pop";
3403
+ p.className = "icen-popover icen-ai-composer-todo-pop";
1935
3404
  p.hidden = true;
1936
3405
  const title = document.createElement("div");
1937
- title.className = "ai-usage-popover-title";
1938
- title.textContent = "\u5F53\u524D\u5F85\u529E";
3406
+ title.className = "icen-ai-usage-popover-title";
3407
+ title.textContent = t("aiComposer.currentTodos");
1939
3408
  const body = document.createElement("div");
1940
3409
  body.className = "ai-usage-popover-body";
1941
3410
  renderAiTodo(body, cur);
@@ -1953,39 +3422,42 @@ function setComposerTodo(el, items) {
1953
3422
  );
1954
3423
  if (icon) chip.appendChild(icon);
1955
3424
  chip.appendChild(document.createElement("span")).className = "ai-composer-todo-label";
1956
- const toolbar = composer.querySelector(".ai-composer-toolbar");
1957
- const usage = composer.querySelector(".ai-composer-usage");
3425
+ const toolbar = composer.querySelector(".icen-ai-composer-toolbar");
3426
+ const usage = composer.querySelector(".icen-ai-composer-usage");
1958
3427
  if (toolbar) toolbar.insertBefore(chip, usage ?? null);
1959
3428
  else {
1960
- const box = composer.querySelector(".ai-composer-box");
3429
+ const box = composer.querySelector(".icen-ai-composer-box");
1961
3430
  box?.before(chip);
1962
3431
  }
1963
3432
  }
1964
- const done = items.filter((t) => t.status === "done").length;
1965
- const failed = items.some((t) => t.status === "error" || t.status === "cancelled");
3433
+ const done = items.filter((t2) => t2.status === "done").length;
3434
+ const failed = items.some((t2) => t2.status === "error" || t2.status === "cancelled");
1966
3435
  chip.classList.toggle("is-done", done === items.length && !failed);
1967
3436
  chip.classList.toggle("is-error", failed);
1968
- chip.setAttribute("aria-label", `\u5F53\u524D\u5F85\u529E ${done}/${items.length}${failed ? "\uFF08\u6709\u5931\u8D25\u9879\uFF09" : ""}`);
3437
+ chip.setAttribute("aria-label", t("aiComposer.todoChip", { p0: done, p1: items.length, p2: failed ? t("aiComposer.todoHasError") : "" }));
1969
3438
  const label = chip.querySelector(".ai-composer-todo-label");
1970
3439
  if (label) label.textContent = `${done}/${items.length}`;
1971
3440
  }
1972
3441
  var BOUND = /* @__PURE__ */ new WeakSet();
1973
3442
  function bindComposer(el, opts = {}) {
1974
3443
  const noop = () => void 0;
1975
- if (!isBrowser()) return { unbind: noop };
3444
+ if (!isBrowser()) return { unbind: noop, retry: () => false };
1976
3445
  const composer = resolveComposer(el);
1977
- if (!composer) return { unbind: noop };
1978
- if (BOUND.has(composer)) return { unbind: noop };
3446
+ if (!composer) return { unbind: noop, retry: () => false };
3447
+ if (BOUND.has(composer)) return { unbind: noop, retry: () => false };
1979
3448
  BOUND.add(composer);
1980
3449
  if (opts.popoverSizing) POPUP_SIZING.set(composer, opts.popoverSizing);
1981
3450
  const disposers = [];
1982
3451
  const usageCfg = opts.usage;
1983
3452
  const manageRunning = opts.running ?? true;
3453
+ let bound = true;
3454
+ let retry = () => false;
3455
+ let updateUsage = (_detail) => {
3456
+ };
1984
3457
  if (usageCfg) {
1985
3458
  let cost = 0;
1986
3459
  let billing = {};
1987
- const onDone = (e) => {
1988
- const detail = e.detail;
3460
+ updateUsage = (detail) => {
1989
3461
  if (!detail?.usage) return;
1990
3462
  if (typeof detail.cost === "number") cost += detail.cost;
1991
3463
  let usage;
@@ -2010,8 +3482,12 @@ function bindComposer(el, opts = {}) {
2010
3482
  cost: cost > 0 ? Math.round(cost * 1e6) / 1e6 : void 0
2011
3483
  });
2012
3484
  };
2013
- document.addEventListener("icen:ai-done", onDone);
2014
- disposers.push(() => document.removeEventListener("icen:ai-done", onDone));
3485
+ if (!opts.client || !opts.messages) {
3486
+ const onDone = (e) => updateUsage(e.detail);
3487
+ const target = opts.eventTarget ?? document;
3488
+ target.addEventListener("icen:ai-done", onDone);
3489
+ disposers.push(() => target.removeEventListener("icen:ai-done", onDone));
3490
+ }
2015
3491
  }
2016
3492
  if (opts.client && !opts.messages) {
2017
3493
  console.warn("[ai-composer] client \u6A21\u5F0F\u9700\u8981 opts.messages\uFF0C\u5DF2\u964D\u7EA7\u4E3A\u7EAF\u72B6\u6001\u7ED1\u5B9A");
@@ -2020,81 +3496,164 @@ function bindComposer(el, opts = {}) {
2020
3496
  const client = opts.client;
2021
3497
  const messages = opts.messages;
2022
3498
  const history = [];
2023
- let session = null;
3499
+ let active = null;
3500
+ let retryable = null;
2024
3501
  const metaOf = (r) => {
2025
3502
  const tok = r.usage.total ?? 0;
2026
- const parts = [tok > 0 ? `${formatTokens(tok)} tok` : "\u5B8C\u6210"];
3503
+ const parts = [tok > 0 ? `${formatTokens(tok)} tok` : t("aiComposer.done")];
2027
3504
  if (typeof r.cost === "number") parts.push(`$${r.cost.toFixed(4)}`);
2028
- return `\u521A\u521A \xB7 ${parts.join(" \xB7 ")}`;
3505
+ return t("aiComposer.justNow", { p0: parts.join(" \xB7 ") });
2029
3506
  };
2030
- const startTurn = () => {
2031
- const assistant = renderAiMessage(messages, {
3507
+ const startTurn = (previous, draft) => {
3508
+ const assistant = previous?.assistant ?? renderAiMessage(messages, {
2032
3509
  role: "assistant",
2033
3510
  content: "",
2034
3511
  streaming: true,
2035
3512
  model: client.config.model
2036
3513
  });
3514
+ if (previous) {
3515
+ const restoreRetryFocus = assistant.body.contains(document.activeElement);
3516
+ previous.textNode?.remove();
3517
+ assistant.body.querySelectorAll(".icen-ai-msg-continue,.icen-ai-msg-error-text").forEach((node) => node.remove());
3518
+ assistant.el.classList.remove("icen-ai-msg--error");
3519
+ assistant.setMeta("");
3520
+ if (restoreRetryFocus) assistant.el.querySelector('[data-icen-ai-msg-action="retry"]')?.focus({ preventScroll: true });
3521
+ }
2037
3522
  const streamH = assistant.stream();
3523
+ assistant.el.classList.add("is-streaming");
3524
+ const turn = { assistant, stream: streamH, textNode: assistant.body.lastElementChild, request: [...history], session: null, text: "", draft: previous?.draft ?? draft, preparation: new AbortController() };
3525
+ active = turn;
3526
+ retryable = null;
2038
3527
  setComposerRunning(composer, true);
2039
- const s = client.stream({ messages: [...history] });
2040
- session = s;
2041
3528
  let failed = false;
2042
3529
  void (async () => {
2043
- for await (const chunk of s) {
2044
- if (chunk.type === "text") streamH.append(chunk.delta);
2045
- else if (chunk.type === "error") {
2046
- failed = true;
2047
- streamH.fail();
2048
- assistant.setError(chunk.message);
3530
+ try {
3531
+ if (turn.draft && opts.prepareMessage) {
3532
+ const content = await opts.prepareMessage(turn.draft, { signal: turn.preparation.signal });
3533
+ if (!bound || active !== turn) return;
3534
+ turn.request[turn.request.length - 1] = { role: "user", content };
3535
+ history.splice(0, history.length, ...turn.request);
3536
+ } else if (turn.draft?.files?.length) throw new Error(t("aiComposer.filesNeedAdapter"));
3537
+ const s = client.stream({ messages: turn.request });
3538
+ turn.session = s;
3539
+ void s.done.catch(() => {
3540
+ });
3541
+ for await (const chunk of s) {
3542
+ if (!bound || active !== turn) return;
3543
+ if (chunk.type === "text") {
3544
+ turn.text += chunk.delta;
3545
+ streamH.append(chunk.delta);
3546
+ } else if (chunk.type === "error") {
3547
+ failed = true;
3548
+ streamH.fail();
3549
+ assistant.setError(chunk.message);
3550
+ }
3551
+ }
3552
+ const result = await s.done;
3553
+ if (!bound || active !== turn) return;
3554
+ if (!failed) {
3555
+ streamH.done();
3556
+ assistant.setMeta(metaOf(result));
3557
+ updateUsage(result);
3558
+ }
3559
+ if (result.text) history.push({ role: "assistant", content: result.text });
3560
+ } catch (error) {
3561
+ if (!bound || active !== turn) return;
3562
+ failed = true;
3563
+ streamH.fail();
3564
+ assistant.setError(error instanceof Error ? error.message : String(error));
3565
+ } finally {
3566
+ if (!bound || active !== turn) return;
3567
+ active = null;
3568
+ assistant.el.classList.remove("is-streaming");
3569
+ setComposerRunning(composer, false);
3570
+ if (failed) {
3571
+ retryable = turn;
3572
+ return;
3573
+ }
3574
+ const queue = QUEUES.get(composer) ?? [];
3575
+ if (queue.length > 0) {
3576
+ const next = queue.shift();
3577
+ QUEUES.set(composer, queue);
3578
+ renderQueueChips(composer);
3579
+ emit2(composer, "icen:ai-dequeue", { index: 0 });
3580
+ if (bound) send(next);
2049
3581
  }
2050
- }
2051
- const result = await s.done;
2052
- session = null;
2053
- if (!failed) streamH.done();
2054
- assistant.setMeta(metaOf(result));
2055
- if (result.text) history.push({ role: "assistant", content: result.text });
2056
- setComposerRunning(composer, false);
2057
- const queue = QUEUES.get(composer) ?? [];
2058
- if (queue.length > 0) {
2059
- const next = queue.shift() ?? "";
2060
- QUEUES.set(composer, queue);
2061
- renderQueueChips(composer);
2062
- emit(composer, "icen:ai-dequeue", { index: 0 });
2063
- send(next);
2064
3582
  }
2065
3583
  })();
2066
3584
  };
2067
- const send = (text) => {
2068
- renderAiMessage(messages, { role: "user", content: text });
3585
+ const send = (draft) => {
3586
+ if (!bound || active) return;
3587
+ const missingRefs = (draft.refs ?? []).filter((r) => !draft.text.includes(`@${r.label}`));
3588
+ const text = [draft.text, ...missingRefs.map((r) => `@${r.label}`)].filter(Boolean).join("\n");
3589
+ const message = renderAiMessage(messages, { role: "user", content: draft.text });
3590
+ if (draft.refs?.length || draft.files?.length) {
3591
+ const context = document.createElement("div");
3592
+ context.className = "icen-ai-msg-context";
3593
+ for (const ref of draft.refs ?? []) {
3594
+ const chip = makeChip(ref.label, false, "");
3595
+ chip.prepend(resourceIcon(ref));
3596
+ context.append(chip);
3597
+ }
3598
+ for (const file of draft.files ?? []) context.append(makeChip(file.name, false, "", "file"));
3599
+ message.body.append(context);
3600
+ }
2069
3601
  history.push({ role: "user", content: text });
2070
- startTurn();
3602
+ startTurn(void 0, draft);
2071
3603
  };
2072
3604
  const onSend = (e) => {
2073
- const text = e.detail?.text;
2074
- if (typeof text === "string" && text) send(text);
3605
+ const draft = e.detail;
3606
+ if (typeof draft?.text === "string" && (draft.text || draft.files?.length || draft.refs?.length)) send(draft);
2075
3607
  };
2076
3608
  const onStop = () => {
2077
- session?.cancel();
3609
+ const turn = active;
3610
+ if (!turn) return;
3611
+ active = null;
3612
+ turn.preparation.abort();
3613
+ retryable = turn;
3614
+ turn.stream.cancel();
3615
+ turn.assistant.el.classList.remove("is-streaming");
3616
+ turn.assistant.setMeta(t("aiComposer.stopped"));
3617
+ if (turn.text) history.push({ role: "assistant", content: turn.text });
3618
+ setComposerRunning(composer, false);
3619
+ turn.session?.cancel();
3620
+ };
3621
+ retry = () => {
3622
+ if (!bound || active || !retryable) return false;
3623
+ const turn = retryable;
3624
+ history.splice(0, history.length, ...turn.request);
3625
+ startTurn(turn);
3626
+ return true;
3627
+ };
3628
+ const onRetry = (event) => {
3629
+ if (event.detail?.el === retryable?.assistant.el) retry();
2078
3630
  };
2079
3631
  composer.addEventListener("icen:ai-send", onSend);
2080
3632
  composer.addEventListener("icen:ai-stop", onStop);
3633
+ messages.addEventListener("icen:ai-retry", onRetry);
2081
3634
  disposers.push(() => {
2082
3635
  composer.removeEventListener("icen:ai-send", onSend);
2083
3636
  composer.removeEventListener("icen:ai-stop", onStop);
2084
- session?.cancel();
3637
+ messages.removeEventListener("icen:ai-retry", onRetry);
3638
+ onStop();
3639
+ retryable = null;
2085
3640
  });
2086
3641
  } else if (manageRunning) {
2087
3642
  const onSend = () => setComposerRunning(composer, true);
2088
3643
  const onDone = () => setComposerRunning(composer, false);
2089
3644
  composer.addEventListener("icen:ai-send", onSend);
2090
- document.addEventListener("icen:ai-done", onDone);
3645
+ const target = opts.eventTarget ?? document;
3646
+ target.addEventListener("icen:ai-done", onDone);
2091
3647
  disposers.push(() => {
2092
3648
  composer.removeEventListener("icen:ai-send", onSend);
2093
- document.removeEventListener("icen:ai-done", onDone);
3649
+ target.removeEventListener("icen:ai-done", onDone);
2094
3650
  });
2095
3651
  }
2096
3652
  return {
3653
+ retry: () => retry(),
2097
3654
  unbind() {
3655
+ if (!bound) return;
3656
+ bound = false;
2098
3657
  for (const dispose of disposers) dispose();
2099
3658
  disposers.length = 0;
2100
3659
  BOUND.delete(composer);
@@ -2103,7 +3662,9 @@ function bindComposer(el, opts = {}) {
2103
3662
  }
2104
3663
  export {
2105
3664
  bindComposer,
3665
+ getComposerDraft,
2106
3666
  initAiComposer,
3667
+ openComposerLibrary,
2107
3668
  registerRefKind,
2108
3669
  setComposerCommands,
2109
3670
  setComposerModels,