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