@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/events.ts
2
+ function emitIcen(source, type, detail) {
3
+ return source.dispatchEvent(
4
+ new CustomEvent(type, { detail, bubbles: true, composed: true, cancelable: true })
5
+ );
6
+ }
7
+
8
+ // src/behaviors/i18n.ts
9
+ var ICEN_LOCALE_ZH_CN = {
10
+ /* ── aiBranch ── */
11
+ "aiBranch.nextVersion": "\u4E0B\u4E00\u7248\u672C",
12
+ "aiBranch.prevVersion": "\u4E0A\u4E00\u7248\u672C",
13
+ "aiBranch.version": "\u5206\u652F\u7248\u672C",
14
+ /* ── aiChat ── */
15
+ "aiChat.backToBottom": "\u56DE\u5230\u5E95\u90E8",
16
+ "aiChat.backToBottomCount": "\u56DE\u5230\u5E95\u90E8 \xB7 {p0} \u6761\u65B0\u6D88\u606F",
17
+ "aiChat.continue": "\u7EE7\u7EED\u751F\u6210",
18
+ "aiChat.download": "\u4E0B\u8F7D",
19
+ "aiChat.file": "\u6587\u4EF6",
20
+ "aiChat.roleSystem": "\u7CFB",
21
+ "aiChat.roleTool": "\u5DE5",
22
+ "aiChat.roleUser": "\u6211",
23
+ "aiChat.thinking": "\u601D\u8003 {p0}",
24
+ "aiChat.thinkingNow": "\u6B63\u5728\u601D\u8003\u2026",
25
+ /* ── aiComposer ── */
26
+ "aiComposer.attachAgent": "\u4EE3\u7406",
27
+ "aiComposer.library": "\u6DFB\u52A0\u4E0A\u4E0B\u6587\u4E0E\u547D\u4EE4",
28
+ "aiComposer.searchLibrary": "\u641C\u7D22\u6280\u80FD\u3001\u5DE5\u5177\u3001\u6587\u4EF6\u4E0E\u547D\u4EE4",
29
+ "aiComposer.all": "\u5168\u90E8",
30
+ "aiComposer.skills": "\u6280\u80FD",
31
+ "aiComposer.tools": "\u5DE5\u5177",
32
+ "aiComposer.libraryHint": "\u4E0A\u4E0B\u6587\u968F\u6D88\u606F\u53D1\u9001 \xB7 \u547D\u4EE4\u5148\u586B\u5165\u8F93\u5165\u6846",
33
+ "aiComposer.commandHint": "\u2191 \u2193 \u6D4F\u89C8 \xB7 Enter \u6267\u884C \xB7 Esc \u8FD4\u56DE",
34
+ "aiComposer.refHint": "\u2191 \u2193 \u6D4F\u89C8 \xB7 Enter \u5F15\u7528 \xB7 Esc \u8FD4\u56DE",
35
+ "aiComposer.noLibraryMatch": "\u6CA1\u6709\u5339\u914D\u7684\u9879\u76EE\uFF0C\u8BD5\u8BD5\u5176\u4ED6\u5173\u952E\u8BCD",
36
+ "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",
37
+ "aiComposer.attachDoc": "\u6587\u6863",
38
+ "aiComposer.attachFile": "\u6587\u4EF6",
39
+ "aiComposer.attachFolder": "\u6587\u4EF6\u5939",
40
+ "aiComposer.cacheInvalidHint": "\u5207\u6362\u6A21\u578B\u4F1A\u4F7F prompt \u7F13\u5B58\u5931\u6548",
41
+ "aiComposer.commands": "\u547D\u4EE4",
42
+ "aiComposer.currentTodos": "\u5F53\u524D\u5F85\u529E",
43
+ "aiComposer.done": "\u5B8C\u6210",
44
+ "aiComposer.justNow": "\u521A\u521A \xB7 {p0}",
45
+ "aiComposer.modelAria": "\u6A21\u578B {p0}\uFF08{p1}\uFF09",
46
+ "aiComposer.noCommandMatch": "\u65E0\u5339\u914D\u547D\u4EE4",
47
+ "aiComposer.noModelMatch": "\u65E0\u5339\u914D\u6A21\u578B",
48
+ "aiComposer.noRefMatch": "\u65E0\u5339\u914D\u5F15\u7528",
49
+ "aiComposer.placeholder": "\u8F93\u5165\u6D88\u606F\uFF0C/ \u547D\u4EE4 \xB7 @ \u5F15\u7528 \xB7 Enter \u53D1\u9001",
50
+ "aiComposer.refs": "\u5F15\u7528",
51
+ "aiComposer.removeAttachment": "\u79FB\u9664\u9644\u4EF6 {p0}",
52
+ "aiComposer.removeQueued": "\u79FB\u9664\u6392\u961F\u6D88\u606F {p0}",
53
+ "aiComposer.removeRef": "\u79FB\u9664\u5F15\u7528 {p0}",
54
+ "aiComposer.searchModels": "\u641C\u7D22\u6A21\u578B",
55
+ "aiComposer.selectModel": "\u9009\u62E9\u6A21\u578B",
56
+ "aiComposer.send": "\u53D1\u9001",
57
+ "aiComposer.stop": "\u505C\u6B62\u751F\u6210",
58
+ "aiComposer.stopped": "\u5DF2\u505C\u6B62",
59
+ "aiComposer.todoChip": "\u5F53\u524D\u5F85\u529E {p0}/{p1}{p2}",
60
+ "aiComposer.todoHasError": "\uFF08\u6709\u5931\u8D25\u9879\uFF09",
61
+ /* ── aiCore ── */
62
+ "aiCore.kindBrowser": "\u6D4F\u89C8",
63
+ "aiCore.kindChart": "\u56FE\u8868",
64
+ "aiCore.kindDelete": "\u5220\u9664",
65
+ "aiCore.kindEdit": "\u7F16\u8F91",
66
+ "aiCore.kindFetch": "\u8BF7\u6C42",
67
+ "aiCore.kindGlob": "\u5339\u914D",
68
+ "aiCore.kindGrep": "\u641C\u7D22",
69
+ "aiCore.kindNote": "\u7B14\u8BB0",
70
+ "aiCore.kindPlan": "\u8BA1\u5212",
71
+ "aiCore.kindRead": "\u8BFB\u53D6",
72
+ "aiCore.kindSearch": "\u68C0\u7D22",
73
+ "aiCore.kindShell": "\u547D\u4EE4",
74
+ "aiCore.kindSkill": "\u6280\u80FD",
75
+ "aiCore.kindSubagent": "\u5B50\u4EE3\u7406",
76
+ "aiCore.kindTodo": "\u5F85\u529E",
77
+ "aiCore.kindWrite": "\u5199\u5165",
78
+ "aiCore.statusApproval": "\u5F85\u786E\u8BA4",
79
+ "aiCore.statusCancelled": "\u5DF2\u53D6\u6D88",
80
+ "aiCore.statusDone": "\u5B8C\u6210",
81
+ "aiCore.statusError": "\u5931\u8D25",
82
+ "aiCore.statusPending": "\u7B49\u5F85",
83
+ "aiCore.statusRunning": "\u6267\u884C\u4E2D",
84
+ "aiCore.statusStreaming": "\u6D41\u5F0F\u4E2D",
85
+ "aiCore.todoProgress": "{p0}/{p1} \u5B8C\u6210",
86
+ /* ── aiDiff ── */
87
+ "aiDiff.accepted": "\u5DF2\u63A5\u53D7",
88
+ "aiDiff.binary": "\u4E8C\u8FDB\u5236\u6587\u4EF6\uFF0C\u65E0\u6CD5\u663E\u793A\u6587\u672C\u5DEE\u5F02",
89
+ "aiDiff.empty": "\u65E0\u5DEE\u5F02\u5185\u5BB9",
90
+ "aiDiff.rejected": "\u5DF2\u62D2\u7EDD",
91
+ /* ── aiFeedback ── */
92
+ "aiFeedback.helpful": "\u6709\u5E2E\u52A9",
93
+ "aiFeedback.notHelpful": "\u65E0\u5E2E\u52A9",
94
+ "aiFeedback.reasonCitationMismatch": "\u5F15\u7528\u4E0D\u7B26",
95
+ "aiFeedback.reasonOutdated": "\u5185\u5BB9\u8FC7\u65F6",
96
+ "aiFeedback.reasonUnauthorized": "\u8D8A\u6743\u4FE1\u606F",
97
+ "aiFeedback.reasonUnsourced": "\u65E0\u5F15\u7528\u4F9D\u636E",
98
+ "aiFeedback.reasonWrong": "\u7B54\u6848\u6709\u8BEF",
99
+ "aiFeedback.thanks": "\u611F\u8C22\u53CD\u9988\uFF0C\u5DF2\u5173\u8054\u5230\u8BE5\u6761\u56DE\u7B54\u7684\u8FFD\u8E2A\u8BB0\u5F55",
100
+ /* ── aiPanel ── */
101
+ "aiPanel.audit": "\u5BA1\u8BA1",
102
+ "aiPanel.cacheRead": "\u7F13\u5B58\u8BFB",
103
+ "aiPanel.cacheWrite": "\u7F13\u5B58\u5199",
104
+ "aiPanel.callsTokens": "{p0} \u6B21 \xB7 {p1} tok{p2}",
105
+ "aiPanel.clearAudit": "\u6E05\u9664\u5BA1\u8BA1",
106
+ "aiPanel.context": "\u4E0A\u4E0B\u6587",
107
+ "aiPanel.contextWindow": "\u4E0A\u4E0B\u6587\u7A97\u53E3",
108
+ "aiPanel.errorsCount": "{p0} \u5931\u8D25",
109
+ "aiPanel.files": "\u6587\u4EF6 ({p0})",
110
+ "aiPanel.itemStatus": "{p0}\uFF0C\u72B6\u6001\uFF1A{p1}",
111
+ "aiPanel.noAudit": "\u6682\u65E0\u5BA1\u8BA1\u8BB0\u5F55",
112
+ "aiPanel.noUsage": "\u6682\u65E0\u7528\u91CF",
113
+ "aiPanel.reasoning": "\u63A8\u7406",
114
+ "aiPanel.requestsCount": "{p0} \u6B21\u8BF7\u6C42",
115
+ "aiPanel.ringPercent": "\u4E0A\u4E0B\u6587\u7A97\u53E3\u5360\u7528 {p0}%\uFF0C\u70B9\u51FB\u67E5\u770B\u8BE6\u60C5",
116
+ "aiPanel.ringUsed": "\u5DF2\u7528 {p0}\uFF0C\u70B9\u51FB\u67E5\u770B\u8BE6\u60C5",
117
+ "aiPanel.taskProgress": "\u4EFB\u52A1\u8FDB\u5EA6",
118
+ "aiPanel.toolsCount": "{p0} \u5DE5\u5177",
119
+ "aiPanel.usage": "\u7528\u91CF",
120
+ "aiPanel.usageAria": "\u7528\u91CF\uFF1A{p0}",
121
+ /* ── aiProvider ── */
122
+ "aiProvider.audioUrlOnly": "\u4EC5 URL \u7684\u97F3\u9891\uFF08input_audio \u9700 base64\uFF0C\u8BF7\u5148\u53D6\u56DE\u5185\u8054\uFF09",
123
+ "aiProvider.audioUrlOnlyAnthropic": "\u4EC5 URL \u7684\u97F3\u9891\uFF08audio \u5757\u9700 base64 source\uFF09",
124
+ "aiProvider.base64File": "base64 \u6587\u4EF6\uFF08file \u90E8\u4EF6\u9700 Files API file_id\uFF0C\u8BF7\u7F6E\u4E8E url \u69FD\uFF09",
125
+ "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",
126
+ "aiProvider.emptyResponse": "\u54CD\u5E94\u4E3A\u7A7A",
127
+ "aiProvider.glmLabel": "GLM\uFF08\u667A\u8C31\uFF09",
128
+ "aiProvider.invalidJson": "\u54CD\u5E94\u4E0D\u662F\u5408\u6CD5 JSON",
129
+ "aiProvider.kimiLabel": "Kimi\uFF08\u6708\u4E4B\u6697\u9762\uFF09",
130
+ "aiProvider.networkFailed": "\u7F51\u7EDC\u8BF7\u6C42\u5931\u8D25\uFF1A{p0}{p1}",
131
+ "aiProvider.nonPdfDocument": "\u975E PDF \u6587\u4EF6\u5757\uFF08document \u5757\u4E3A application/pdf\uFF0C\u6536\u5230 {p0}\uFF09",
132
+ "aiProvider.requestCancelled": "\u8BF7\u6C42\u5DF2\u53D6\u6D88",
133
+ "aiProvider.resourceRef": "[\u8D44\u6E90] {p0} ({p1})",
134
+ "aiProvider.streamError": "\u6D41\u5F0F\u54CD\u5E94\u9519\u8BEF",
135
+ "aiProvider.toolRoleNoCallId": "role 'tool' \u4E14\u7F3A toolCallId\uFF08openai \u65CF\u9700 tool_call_id\uFF09",
136
+ "aiProvider.toolRoleNoUseId": "role 'tool' \u4E14\u7F3A toolCallId\uFF08anthropic \u65CF\u6620\u5C04 tool_result \u9700 tool_use_id\uFF09",
137
+ "aiProvider.unsupported": "{p0} \u7EBF\u534F\u8BAE\u4E0D\u652F\u6301 {p1}",
138
+ "aiProvider.videoUnsupported": "video \u8F93\u5165\uFF08\u65E0\u4E3B\u6D41 chat API \u652F\u6301\uFF09",
139
+ "aiProvider.videoUnsupportedAnthropic": "video \u8F93\u5165",
140
+ /* ── aiThreads ── */
141
+ "aiThreads.actionsAria": "\u4F1A\u8BDD\u64CD\u4F5C",
142
+ "aiThreads.archived": "\u5DF2\u5F52\u6863",
143
+ /* ── aiTool ── */
144
+ "aiTool.allow": "\u5141\u8BB8",
145
+ "aiTool.reject": "\u62D2\u7EDD",
146
+ /* ── aiTools ── */
147
+ "aiTools.chart.area": "line \u591A\u7CFB\u5217\u586B\u5145\u9762\u79EF",
148
+ "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",
149
+ "aiTools.chart.dates": "\u8D21\u732E\u65E5\u5386 ISO \u65E5\u671F\uFF08\u4E0E values \u914D\u5BF9\uFF09",
150
+ "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",
151
+ "aiTools.chart.dims": "data[] \u7684\u5B57\u6BB5\u6620\u5C04\uFF1A{label?, series?, value?, x?, y?}",
152
+ "aiTools.chart.format": "\u6570\u503C\u683C\u5F0F\u5316\uFF1A{notation?: compact|percent|ms, unit?}",
153
+ "aiTools.chart.labels": "\u7C7B\u76EE\u8F74\uFF08line/vbar/hbar\uFF09",
154
+ "aiTools.chart.legend": "false = \u521D\u59CB\u9690\u85CF\u56FE\u4F8B",
155
+ "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",
156
+ "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",
157
+ "aiTools.chart.points": "\u6563\u70B9/\u6C14\u6CE1\uFF1A[{x,y,size?,label?}]",
158
+ "aiTools.chart.radarAxes": "\u96F7\u8FBE\u8F74\u540D",
159
+ "aiTools.chart.segments": "\u5360\u6BD4\u578B\uFF08donut/stack\uFF09\uFF1A[{label,value}]",
160
+ "aiTools.chart.series": "\u591A\u7CFB\u5217\uFF08line/vbar/radar\uFF09",
161
+ "aiTools.chart.stacked": "vbar \u591A\u7CFB\u5217\u5806\u53E0\uFF08\u9ED8\u8BA4\u5206\u7EC4\uFF09",
162
+ "aiTools.chart.title": "\u56FE\u8868\u6807\u9898\uFF08\u6E32\u67D3\u5728\u5934\u90E8\u884C\u5DE6\u4FA7\uFF09",
163
+ "aiTools.chart.tooltip": "false = \u5173\u95ED\u5185\u7F6E\u63D0\u793A",
164
+ "aiTools.chart.type": "\u56FE\u8868\u7C7B\u578B\uFF0C\u7F3A\u7701\u81EA\u52A8\u63A8\u65AD",
165
+ "aiTools.chart.values": "\u5355\u7CFB\u5217\u6570\u503C\uFF08\u4E0E labels \u914D\u5BF9\uFF09",
166
+ "aiTools.chart.zoom": "\u7F29\u653E\u4EA4\u4E92\uFF1A'x'=\u7C7B\u76EE\u8F74\u533A\u95F4\u7F29\u653E\uFF0C'brush'=\u5237\u9009\u7F29\u653E",
167
+ "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",
168
+ "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",
169
+ "aiTools.datatable.rows": "\u884C\u6570\u636E\u6570\u7EC4\uFF1A\u6BCF\u9879\u4E3A\u4E00\u4E2A\u5BF9\u8C61\uFF0C\u5B57\u6BB5\u540D\u5BF9\u9F50 columns[].key",
170
+ "aiTools.datatable.title": "\u8868\u683C\u6807\u9898\uFF08\u6E32\u67D3\u5728\u5DE5\u5177\u680F\u5DE6\u4FA7\uFF09",
171
+ "aiTools.execFailed": "\u5DE5\u5177\u6267\u884C\u5931\u8D25\uFF1A{p0}",
172
+ "aiTools.execTimeout": "\u6267\u884C\u8D85\u65F6\uFF08{p0}ms\uFF09",
173
+ "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",
174
+ "aiTools.missingRequired": "\u7F3A\u5C11\u5FC5\u586B\u5B57\u6BB5",
175
+ "aiTools.none": "\uFF08\u65E0\u5DF2\u6CE8\u518C\u7684 UI \u5DE5\u5177\uFF09",
176
+ "aiTools.notInEnum": "\u4E0D\u5728\u5141\u8BB8\u53D6\u503C\u5185\uFF08{p0}\uFF09",
177
+ "aiTools.numMax": "\u6570\u503C {p0} \u5927\u4E8E\u6700\u5927\u503C {p1}",
178
+ "aiTools.numMin": "\u6570\u503C {p0} \u5C0F\u4E8E\u6700\u5C0F\u503C {p1}",
179
+ "aiTools.removeMount": "\u79FB\u9664 {p0} \u6302\u8F7D",
180
+ "aiTools.strMax": "\u957F\u5EA6 {p0} \u8D85\u8FC7\u4E0A\u9650 {p1}",
181
+ "aiTools.strMin": "\u957F\u5EA6 {p0} \u5C0F\u4E8E\u4E0B\u9650 {p1}",
182
+ "aiTools.typeMismatch": "\u671F\u671B {p0}\uFF0C\u5B9E\u5F97 {p1}",
183
+ "aiTools.validationFailed": "\u53C2\u6570\u6821\u9A8C\u5931\u8D25\uFF08{p0} \u9879\uFF09",
184
+ /* ── autocomplete ── */
185
+ "suggestions.loading": "\u6B63\u5728\u67E5\u627E\u5EFA\u8BAE\u2026",
186
+ "suggestions.error": "\u6682\u65F6\u65E0\u6CD5\u52A0\u8F7D\u5EFA\u8BAE\uFF0C\u8BF7\u91CD\u8BD5\u3002",
187
+ "suggestions.options": "\u5EFA\u8BAE",
188
+ "suggestions.empty": "\u6CA1\u6709\u5339\u914D\u7684\u5EFA\u8BAE",
189
+ "autocomplete.empty": "\u65E0\u5339\u914D\u7ED3\u679C",
190
+ /* ── backTop ── */
191
+ "backTop.label": "\u56DE\u5230\u9876\u90E8",
192
+ /* ── carousel ── */
193
+ "carousel.item": "\u7B2C {p0} \u5F20",
194
+ "carousel.region": "\u8F6E\u64AD",
195
+ "carousel.slide": "\u5E7B\u706F\u7247",
196
+ "carousel.status": "\u7B2C {p0} / {p1} \u5F20",
197
+ /* ── charts ── */
198
+ "charts.calendarWeekdays": ["\u4E00", "", "\u4E09", "", "\u4E94", "", "\u65E5"],
199
+ "charts.few": "\u5C11",
200
+ "charts.hideLegend": "\u9690\u85CF\u56FE\u4F8B",
201
+ "charts.loading": "\u52A0\u8F7D\u4E2D",
202
+ "charts.many": "\u591A",
203
+ "charts.monthLabel": "{p0}\u6708",
204
+ "charts.noData": "\u6682\u65E0\u6570\u636E",
205
+ "charts.resetZoom": "\u91CD\u7F6E\u7F29\u653E",
206
+ "charts.sampled": "\u5DF2\u62BD\u6837 {p0}\u2192{p1} \u70B9",
207
+ "charts.type.area": "\u9762\u79EF\u56FE",
208
+ "charts.type.donut": "\u73AF\u5F62\u56FE",
209
+ "charts.type.gauge": "\u4EEA\u8868\u76D8",
210
+ "charts.type.graph": "\u77E5\u8BC6\u56FE\u8C31",
211
+ "charts.type.heatmap": "\u70ED\u529B\u56FE",
212
+ "charts.type.line": "\u6298\u7EBF\u56FE",
213
+ "charts.type.map": "\u5730\u56FE",
214
+ "charts.type.radar": "\u96F7\u8FBE\u56FE",
215
+ "charts.type.scatter": "\u6563\u70B9\u56FE",
216
+ "charts.type.sparkline": "\u8FF7\u4F60\u8D8B\u52BF",
217
+ "charts.seriesName": "\u7CFB\u5217{p0}",
218
+ "charts.showLegend": "\u663E\u793A\u56FE\u4F8B",
219
+ "charts.value": "\u6570\u503C",
220
+ /* ── themeSwitcher ── */
221
+ "themeSwitcher.appearance": "\u5916\u89C2",
222
+ "themeSwitcher.theme": "\u4E3B\u9898",
223
+ "themeSwitcher.primitive": "\u539F\u8BED",
224
+ "themeSwitcher.mode": "\u660E\u6697",
225
+ "themeSwitcher.light": "\u6D45\u8272",
226
+ "themeSwitcher.dark": "\u6DF1\u8272",
227
+ "themeSwitcher.modern": "\u73B0\u4EE3",
228
+ "themeSwitcher.dongyun": "\u4E1C\u97F5",
229
+ "themeSwitcher.jugou": "\u5DE8\u6784",
230
+ "themeSwitcher.piano": "\u94A2\u7434",
231
+ "themeSwitcher.monet": "\u83AB\u5948",
232
+ "themeSwitcher.vangogh": "\u68B5\u9AD8",
233
+ "themeSwitcher.chinese": "\u4E2D\u5F0F",
234
+ "themeSwitcher.soviet": "\u82CF\u5F0F",
235
+ "themeSwitcher.pixel": "\u50CF\u7D20",
236
+ /* ── codeBlock ── */
237
+ "codeBlock.collapse": "\u6536\u8D77",
238
+ "codeBlock.region": "\u4EE3\u7801\u5185\u5BB9",
239
+ "codeBlock.copyFailed": "\u672A\u80FD\u590D\u5236\uFF0C\u8BF7\u91CD\u8BD5\u3002",
240
+ "codeBlock.copyRetry": "\u91CD\u8BD5\u590D\u5236",
241
+ "codeBlock.copy": "\u590D\u5236",
242
+ "codeBlock.foldCollapse": "\u6298\u53E0\u4EE3\u7801",
243
+ "codeBlock.foldExpand": "\u5C55\u5F00\u4EE3\u7801",
244
+ "codeBlock.linesTotal": "\u5171 {p0} \u884C",
245
+ "codeBlock.numHide": "\u9690\u85CF\u884C\u53F7",
246
+ "codeBlock.numShow": "\u663E\u793A\u884C\u53F7",
247
+ "codeBlock.tailAria": "\u5C55\u5F00\u6216\u6536\u8D77\u4EE3\u7801",
248
+ "codeBlock.wrapOff": "\u5173\u95ED\u6362\u884C",
249
+ "codeBlock.wrapOn": "\u81EA\u52A8\u6362\u884C",
250
+ /* ── common ── */
251
+ "common.accept": "\u63A5\u53D7",
252
+ "common.add": "\u65B0\u589E",
253
+ "common.all": "\u5168\u90E8",
254
+ "common.approve": "\u6279\u51C6",
255
+ "common.cancel": "\u53D6\u6D88",
256
+ "common.actionFailed": "\u64CD\u4F5C\u672A\u5B8C\u6210\uFF0C\u8BF7\u91CD\u8BD5\u3002",
257
+ "common.close": "\u5173\u95ED",
258
+ "common.confirm": "\u786E\u8BA4",
259
+ "common.copied": "\u5DF2\u590D\u5236",
260
+ "common.copy": "\u590D\u5236",
261
+ "common.delete": "\u5220\u9664",
262
+ "common.enable": "\u542F\u7528",
263
+ "common.exportCsv": "\u5BFC\u51FA CSV",
264
+ "common.healthy": "\u6B63\u5E38",
265
+ "common.input": "\u8F93\u5165",
266
+ "common.loadingEllipsis": "\u52A0\u8F7D\u4E2D\u2026",
267
+ "common.official": "\u5B98\u65B9",
268
+ "common.output": "\u8F93\u51FA",
269
+ "common.page": "\u7B2C {p0} \u9875",
270
+ "common.reject": "\u62D2\u7EDD",
271
+ "common.remove": "\u79FB\u9664",
272
+ "common.requestAccess": "\u7533\u8BF7\u8BBF\u95EE",
273
+ "common.requestAccessFor": "\u7533\u8BF7\u8BBF\u95EE {p0}",
274
+ "common.restricted": "\u53D7\u9650",
275
+ "common.retry": "\u91CD\u8BD5",
276
+ "common.rows": "{p0} \u884C",
277
+ "common.run": "\u8FD0\u884C",
278
+ "common.steps": "{p0} \u6B65",
279
+ "common.submit": "\u63D0\u4EA4",
280
+ "common.unknown": "\u672A\u77E5",
281
+ /* ── contextMenu ── */
282
+ "contextMenu.back": "\u540E\u9000",
283
+ "contextMenu.copyPageLink": "\u590D\u5236\u9875\u9762\u94FE\u63A5",
284
+ "contextMenu.forward": "\u524D\u8FDB",
285
+ "contextMenu.refresh": "\u5237\u65B0",
286
+ /* ── copy ── */
287
+ "copy.copied": "\u5DF2\u590D\u5236",
288
+ "copy.failed": "\u672A\u80FD\u590D\u5236\uFF0C\u8BF7\u91CD\u8BD5\u3002",
289
+ "copy.denied": "clipboard API \u88AB\u62D2\uFF08{p0}\uFF09\u4E14\u56DE\u9000 execCommand \u5931\u8D25",
290
+ "copy.unavailable": "\u526A\u8D34\u677F\u4E0D\u53EF\u7528\uFF08\u65E0 clipboard API \u4E14 execCommand \u56DE\u9000\u5931\u8D25\uFF09",
291
+ "copy.unknown": "\u672A\u77E5\u9519\u8BEF",
292
+ /* ── datatable ── */
293
+ "datatable.clear": "\u6E05\u7A7A",
294
+ "datatable.collapseGroup": "\u6298\u53E0\u5206\u7EC4 {p0}",
295
+ "datatable.columnSettingsAria": "\u5217\u8BBE\u7F6E",
296
+ "datatable.countUnit": "{p0} \u6761",
297
+ "datatable.editHint": "\u7F16\u8F91\u300C{p0}\u300D\uFF1A\u53CC\u51FB\u6216\u6309 Enter",
298
+ "datatable.editHintWithValue": "{p0}\uFF08\u53CC\u51FB\u6216\u6309 Enter \u7F16\u8F91\u300C{p1}\u300D\uFF09",
299
+ "datatable.empty": "\u6682\u65E0\u6570\u636E",
300
+ "datatable.emptyValue": "\uFF08\u7A7A\uFF09",
301
+ "datatable.expandGroup": "\u5C55\u5F00\u5206\u7EC4 {p0}",
302
+ "datatable.expandRow": "\u5C55\u5F00\u884C",
303
+ "datatable.filterChipAria": "\u7B5B\u9009\u300C{p0}\u300D",
304
+ "datatable.pageSizeAria": "\u6BCF\u9875\u6761\u6570",
305
+ "datatable.paginationAria": "\u5206\u9875",
306
+ "datatable.reset": "\u91CD\u7F6E",
307
+ "datatable.resizeAria": "\u8C03\u6574\u300C{p0}\u300D\u5217\u5BBD",
308
+ "datatable.searchAria": "\u641C\u7D22\u8868\u683C",
309
+ "datatable.searchPlaceholder": "\u641C\u7D22\u2026",
310
+ "datatable.selectAll": "\u5168\u9009",
311
+ "datatable.selectRow": "\u9009\u62E9\u8BE5\u884C",
312
+ "datatable.selectedCount": "\u5DF2\u9009 {p0} \u9879",
313
+ "datatable.totalCount": "\u5171 {p0} \u6761",
314
+ "datatable.totalLabel": "\u5408\u8BA1",
315
+ /* ── datePicker ── */
316
+ "datePicker.noDates": "\u6CA1\u6709\u53EF\u9009\u65E5\u671F",
317
+ "datePicker.clear": "\u6E05\u9664",
318
+ "datePicker.nextMonth": "\u4E0B\u4E00\u6708",
319
+ "datePicker.prevMonth": "\u4E0A\u4E00\u6708",
320
+ "datePicker.selectDate": "\u9009\u62E9\u65E5\u671F",
321
+ "datePicker.today": "\u4ECA\u5929",
322
+ "datePicker.weekdays": ["\u4E00", "\u4E8C", "\u4E09", "\u56DB", "\u4E94", "\u516D", "\u65E5"],
323
+ "datePicker.weekdaysSunFirst": ["\u65E5", "\u4E00", "\u4E8C", "\u4E09", "\u56DB", "\u4E94", "\u516D"],
324
+ "datePicker.yearMonth": "{p0} \u5E74 {p1} \u6708",
325
+ /* ── formValidate ── */
326
+ "formValidate.email": "\u8BF7\u8F93\u5165\u6709\u6548\u7684\u90AE\u7BB1\u5730\u5740",
327
+ "formValidate.invalid": "\u8F93\u5165\u4E0D\u5408\u6CD5",
328
+ "formValidate.matches": "\u4E24\u6B21\u8F93\u5165\u4E0D\u4E00\u81F4",
329
+ "formValidate.max": "\u4E0D\u80FD\u5927\u4E8E {max}",
330
+ "formValidate.maxlength": "\u6700\u591A\u8F93\u5165 {max} \u4E2A\u5B57\u7B26",
331
+ "formValidate.min": "\u4E0D\u80FD\u5C0F\u4E8E {min}",
332
+ "formValidate.minlength": "\u81F3\u5C11\u8F93\u5165 {min} \u4E2A\u5B57\u7B26",
333
+ "formValidate.number": "\u8BF7\u8F93\u5165\u6709\u6548\u7684\u6570\u5B57",
334
+ "formValidate.pattern": "\u8F93\u5165\u683C\u5F0F\u4E0D\u6B63\u786E",
335
+ "formValidate.required": "\u6B64\u9879\u4E3A\u5FC5\u586B\u9879",
336
+ "formValidate.selectPlaceholder": "\u8BF7\u9009\u62E9",
337
+ "formValidate.step": "\u6570\u503C\u5FC5\u987B\u662F {step} \u7684\u500D\u6570",
338
+ "formValidate.summary": "\u8868\u5355\u6709 {p0} \u9879\u5185\u5BB9\u9700\u8981\u4FEE\u6B63\uFF0C\u8BF7\u4FEE\u6539\u540E\u91CD\u65B0\u63D0\u4EA4",
339
+ "formValidate.tool.description": "\u5411\u7528\u6237\u6E32\u67D3\u4E00\u4E2A\u7ED3\u6784\u5316\u8868\u5355\u6536\u96C6\u8F93\u5165",
340
+ "formValidate.tool.fields": "\u5B57\u6BB5\u5217\u8868",
341
+ "formValidate.tool.help": "\u5B57\u6BB5\u4E0B\u65B9\u7684\u5E2E\u52A9\u6587\u6848",
342
+ "formValidate.tool.label": "\u5B57\u6BB5\u6807\u7B7E",
343
+ "formValidate.tool.max": "\u6700\u5927\u503C\uFF08number \u7528\uFF09",
344
+ "formValidate.tool.min": "\u6700\u5C0F\u503C\uFF08number \u7528\uFF09",
345
+ "formValidate.tool.name": "\u5B57\u6BB5\u540D\uFF08\u63D0\u4EA4\u503C\u7684 key\uFF09",
346
+ "formValidate.tool.options": "select \u9009\u9879\uFF08\u5B57\u7B26\u4E32\u6216 {label,value}\uFF09",
347
+ "formValidate.tool.pattern": "\u6B63\u5219\u7EA6\u675F\uFF08HTML pattern \u8BED\u6CD5\uFF0C\u6574\u4E32\u5339\u914D\uFF09",
348
+ "formValidate.tool.required": "\u662F\u5426\u5FC5\u586B",
349
+ "formValidate.tool.submitText": "\u63D0\u4EA4\u6309\u94AE\u6587\u6848\uFF0C\u9ED8\u8BA4\u300C\u63D0\u4EA4\u300D",
350
+ "formValidate.tool.title": "\u8868\u5355\u6807\u9898\uFF08\u53EF\u9009\uFF09",
351
+ "formValidate.tool.type": "\u63A7\u4EF6\u7C7B\u578B\uFF0C\u9ED8\u8BA4 text",
352
+ "formValidate.url": "\u8BF7\u8F93\u5165\u6709\u6548\u7684\u94FE\u63A5\u5730\u5740",
353
+ /* ── input ── */
354
+ "input.clearSearch": "\u6E05\u7A7A\u641C\u7D22",
355
+ "input.hidePassword": "\u9690\u85CF\u5BC6\u7801",
356
+ "input.otpPosition": "\u7B2C {p0} \u4F4D\uFF0C\u5171 {p1} \u4F4D",
357
+ "panel.expand": "\u5C55\u5F00",
358
+ "panel.collapse": "\u6298\u53E0",
359
+ "input.showPassword": "\u663E\u793A\u5BC6\u7801",
360
+ /* ── kbAccess ── */
361
+ "kbAccess.approveTip": "\u6279\u51C6\u8BE5\u8BBF\u95EE\u7533\u8BF7",
362
+ "kbAccess.approvedBadge": "\u5DF2\u6279\u51C6 \xB7 {p0}",
363
+ "kbAccess.approverNotePlaceholder": "\u7ED9\u8BF7\u6C42\u4EBA\u7684\u7559\u8A00\uFF08\u53EF\u9009\uFF09",
364
+ "kbAccess.daysLeft": "{p0} \u5929\u540E",
365
+ "kbAccess.defaultSubject": "\u8BE5\u5185\u5BB9",
366
+ "kbAccess.deniedHint": "\u672A\u901A\u8FC7\u2014\u2014\u53EF\u8C03\u6574\u7406\u7531\u540E\u91CD\u65B0\u7533\u8BF7",
367
+ "kbAccess.denyNoteLabel": "\u62D2\u7EDD\u7559\u8A00\uFF08\u53EF\u9009\uFF09",
368
+ "kbAccess.duration30d": "30 \u5929",
369
+ "kbAccess.duration7d": "7 \u5929",
370
+ "kbAccess.durationForever": "\u6C38\u4E45",
371
+ "kbAccess.durationLabel": "\u8BBF\u95EE\u65F6\u957F",
372
+ "kbAccess.expired": "\u5DF2\u5230\u671F",
373
+ "kbAccess.expiresAt": "{p0}\u5230\u671F",
374
+ "kbAccess.grantAsPrefix": "\u6279\u51C6\u4E3A{p0}",
375
+ "kbAccess.grantRoleLabel": "\u6279\u51C6\u89D2\u8272",
376
+ "kbAccess.hoursLeft": "{p0} \u5C0F\u65F6\u540E",
377
+ "kbAccess.minutesLeft": "{p0} \u5206\u949F\u540E",
378
+ "kbAccess.ownerLabel": "\u5185\u5BB9\u8D1F\u8D23\u4EBA",
379
+ "kbAccess.ownerPrefix": "\u8D1F\u8D23\u4EBA\uFF1A{p0}",
380
+ "kbAccess.reapply": "\u91CD\u65B0\u7533\u8BF7",
381
+ "kbAccess.reasonLabel": "\u7533\u8BF7\u7406\u7531",
382
+ "kbAccess.reasonPlaceholder": "\u8BF4\u660E\u4E1A\u52A1\u539F\u56E0\uFF08\u5BA1\u6279\u4EBA\u53EF\u89C1\uFF09",
383
+ "kbAccess.rejectTip": "\u62D2\u7EDD\u8BE5\u8BBF\u95EE\u7533\u8BF7",
384
+ "kbAccess.requestRenewal": "\u7533\u8BF7\u7EED\u671F",
385
+ "kbAccess.requestToPrefix": "\u8BF7\u6C42\u5C06\u53D1\u9001\u7ED9\uFF1A{p0}",
386
+ "kbAccess.restrictedContent": "\u53D7\u9650\u5185\u5BB9",
387
+ "kbAccess.restrictedHint": "\u6B64\u5185\u5BB9\u4EC5\u5BF9\u6388\u6743\u8005\u5F00\u653E",
388
+ "kbAccess.revokedHint": "\u8BBF\u95EE\u5DF2\u88AB\u6536\u56DE",
389
+ "kbAccess.roleLabel": "\u7533\u8BF7\u89D2\u8272",
390
+ "kbAccess.submitRequest": "\u63D0\u4EA4\u7533\u8BF7",
391
+ "kbAccess.switchIdentity": "\u5207\u6362\u8EAB\u4EFD",
392
+ "kbAccess.switchIdentityTip": "\u5207\u6362\u8EAB\u4EFD\u540E\u91CD\u65B0\u68C0\u67E5\u6743\u9650",
393
+ "kbAccess.unknownRequester": "\u672A\u77E5\u8BF7\u6C42\u4EBA",
394
+ "kbAccess.waitingApproval": "\u7B49\u5F85 {p0} \u5BA1\u6279",
395
+ /* ── kbAcl ── */
396
+ "kbAcl.breakHint": "\u505C\u6B62\u4ECE\u7236\u7EA7\u7EE7\u627F\uFF0C\u6539\u4E3A\u72EC\u7ACB\u7BA1\u7406\u672C\u9879\u6743\u9650",
397
+ "kbAcl.breakInheritance": "\u505C\u6B62\u7EE7\u627F",
398
+ "kbAcl.brokenNotice": "\u5DF2\u505C\u6B62\u7EE7\u627F\u2014\u2014\u672C\u9879\u6743\u9650\u72EC\u7ACB\u4E8E\u7236\u7EA7",
399
+ "kbAcl.detachedChildren": "{p0}\uFF1A{p1} \u4E2A\u5B50\u9879\u5DF2\u8131\u79BB",
400
+ "kbAcl.directAccess": "\u76F4\u63A5\u8BBF\u95EE",
401
+ "kbAcl.exception": "\u4F8B\u5916",
402
+ "kbAcl.expiredOn": "\u5DF2\u8FC7\u671F\uFF08{p0}\uFF09",
403
+ "kbAcl.expiresIn": "{p0} \u5230\u671F",
404
+ "kbAcl.grantAccess": "\u6388\u4E88\u8BBF\u95EE",
405
+ "kbAcl.inheritedFrom": "\u7EE7\u627F\u81EA {p0}",
406
+ "kbAcl.inheritedFromLabel": "\u7EE7\u627F\u81EA",
407
+ "kbAcl.linkAccess": "\u94FE\u63A5\u8BBF\u95EE",
408
+ "kbAcl.noDirect": "\u6682\u65E0\u76F4\u63A5\u6388\u6743",
409
+ "kbAcl.noLinks": "\u65E0\u94FE\u63A5",
410
+ "kbAcl.removeEntry": "\u79FB\u9664 {p0}",
411
+ "kbAcl.restoreHint": "\u6062\u590D\u7EE7\u627F\u5C06\u4E22\u5F03\u672C\u9879\u81EA\u5B9A\u4E49\u7684\u6743\u9650",
412
+ "kbAcl.restoreInheritance": "\u6062\u590D\u7EE7\u627F",
413
+ "kbAcl.rootNotice": "\u6839\u7EA7\u8D44\u6E90\u2014\u2014\u65E0\u7236\u7EA7\u7EE7\u627F",
414
+ "kbAcl.systemBadge": "\u7CFB\u7EDF\u7BA1\u7406",
415
+ "kbAcl.systemNote": "\u7CFB\u7EDF\u81EA\u52A8\uFF0C\u4E0D\u53EF\u624B\u5DE5\u79FB\u9664",
416
+ "kbAcl.unnamedResource": "\u672A\u547D\u540D\u8D44\u6E90",
417
+ "kbAcl.visibleToCount": "\u5BF9 {p0} \u4EBA\u53EF\u89C1",
418
+ /* ── kbAnswer ── */
419
+ "kbAnswer.chartBar": "\u67F1\u72B6",
420
+ "kbAnswer.chartLine": "\u6298\u7EBF",
421
+ "kbAnswer.chartPie": "\u997C\u56FE",
422
+ "kbAnswer.exportNoun": "\u5BFC\u51FA {p0}",
423
+ "kbAnswer.filtered": "\u5DF2\u6309\u4F60\u7684\u6570\u636E\u6743\u9650\u8FC7\u6EE4",
424
+ "kbAnswer.filteredDetail": "\u5DF2\u6309\u4F60\u7684\u6570\u636E\u6743\u9650\u8FC7\u6EE4\uFF1A{p0}",
425
+ "kbAnswer.followups": "\u8FFD\u95EE\u5EFA\u8BAE",
426
+ "kbAnswer.hitAssets": "\u547D\u4E2D\u8D44\u4EA7\uFF1A{p0}",
427
+ "kbAnswer.kindCurated": "\u4EBA\u5DE5\u7B56\u5C55",
428
+ "kbAnswer.kindFunction": "\u51FD\u6570",
429
+ "kbAnswer.kindParameterized": "\u53C2\u6570\u5316\u67E5\u8BE2",
430
+ "kbAnswer.maskedPrefix": "\u5DF2\u8131\u654F\u5217\uFF1A",
431
+ "kbAnswer.rerunTip": "\u53C2\u6570\u53EF\u6539\u91CD\u8DD1",
432
+ "kbAnswer.truncated": "\u5DF2\u622A\u65AD\uFF1A\u663E\u793A {p0}/{p1} \u884C{p2}",
433
+ "kbAnswer.verifiedBadge": "\u8BA4\u8BC1\u7B54\u6848",
434
+ /* ── kbAudit ── */
435
+ "kbAudit.actionDetail": "\u5904\u7F6E\uFF1A{p0} \xB7 {p1}",
436
+ "kbAudit.actionLabel": "\u5904\u7F6E",
437
+ "kbAudit.alertedNote": "\u5DF2\u5B9E\u65F6\u544A\u8B66\u5B89\u5168\u56E2\u961F",
438
+ "kbAudit.channelFilterAria": "\u5BA1\u8BA1\u901A\u9053\u8FC7\u6EE4",
439
+ "kbAudit.channelPermission": "\u6743\u9650\u53D8\u66F4",
440
+ "kbAudit.channelRead": "\u8BFB\u53D6",
441
+ "kbAudit.channelRequest": "\u7533\u8BF7",
442
+ "kbAudit.channelSystem": "\u7CFB\u7EDF",
443
+ "kbAudit.empty": "\u6682\u65E0\u5BA1\u8BA1\u4E8B\u4EF6",
444
+ "kbAudit.exportTip": "\u5BFC\u51FA\u5F53\u524D\u8FC7\u6EE4\u89C6\u56FE\u4E3A CSV",
445
+ "kbAudit.hygieneLabel": "\u6743\u9650\u5F02\u5473",
446
+ "kbAudit.noHygiene": "\u672A\u53D1\u73B0\u6743\u9650\u5F02\u5473",
447
+ /* ── kbCanvas ── */
448
+ "kbCanvas.splitterAria": "\u8C03\u6574\u753B\u5E03\u53CC\u680F\u6BD4\u4F8B",
449
+ "kbCanvas.splitterTip": "\u62D6\u62FD\u8C03\u6574\u6BD4\u4F8B\uFF08\u2190/\u2192 \u5FAE\u8C03\uFF0C\u53CC\u51FB\u590D\u4F4D\uFF09",
450
+ /* ── kbCheckpoint ── */
451
+ "kbCheckpoint.chatAuditNote": "\u8BA8\u8BBA\u5386\u53F2\u6709\u5BA1\u8BA1\u4EF7\u503C",
452
+ "kbCheckpoint.label": "\u68C0\u67E5\u70B9",
453
+ "kbCheckpoint.restore": "\u6062\u590D\u68C0\u67E5\u70B9",
454
+ "kbCheckpoint.scopeBoth": "\u5185\u5BB9\u4E0E\u5BF9\u8BDD",
455
+ "kbCheckpoint.scopeChat": "\u4EC5\u5BF9\u8BDD",
456
+ "kbCheckpoint.scopeContent": "\u4EC5\u5185\u5BB9\uFF08\u4FDD\u7559\u5BF9\u8BDD\uFF09",
457
+ "kbCheckpoint.scopeMissing": "\u8BE5\u68C0\u67E5\u70B9\u672A\u5305\u542B\u6B64\u6062\u590D\u8303\u56F4",
458
+ /* ── kbChunks ── */
459
+ "kbChunks.addKeyword": "+ \u5173\u952E\u8BCD",
460
+ "kbChunks.chunkAddKeywordAria": "chunk {p0} \u65B0\u589E\u5173\u952E\u8BCD",
461
+ "kbChunks.chunkContentAria": "chunk {p0} \u5185\u5BB9",
462
+ "kbChunks.chunkEnableAria": "chunk {p0} \u542F\u7528",
463
+ "kbChunks.deleteChunkAria": "\u5220\u9664 chunk {p0}",
464
+ "kbChunks.disableNote": "\u5173\u95ED\u540E\u4E0D\u5220\u9664\uFF0C\u4EC5\u6392\u9664\u51FA\u68C0\u7D22",
465
+ "kbChunks.edited": "\u5DF2\u7F16\u8F91",
466
+ "kbChunks.empty": "\u6682\u65E0 chunk",
467
+ "kbChunks.modeFull": "\u5168\u6587",
468
+ "kbChunks.modeLabel": "\u641C\u7D22\u6A21\u5F0F",
469
+ "kbChunks.modeVector": "\u8BED\u4E49",
470
+ "kbChunks.removeKeyword": "\u79FB\u9664\u5173\u952E\u8BCD {p0}",
471
+ "kbChunks.searchAria": "\u641C\u7D22 chunk",
472
+ "kbChunks.searchFullPlaceholder": "\u5168\u6587\u641C\u7D22 chunk\u2026",
473
+ "kbChunks.searchVectorPlaceholder": "\u8BED\u4E49\u641C\u7D22 chunk\u2026",
474
+ /* ── kbCitation ── */
475
+ "kbCitation.sourceN": "\u6765\u6E90 {p0}",
476
+ "kbCitation.unavailable": "\u6765\u6E90\u5DF2\u4E0D\u53EF\u7528",
477
+ /* ── kbClarify ── */
478
+ "kbClarify.parsedPrefix": "\u5DF2\u89E3\u6790\uFF1A",
479
+ /* ── kbConflict ── */
480
+ "kbConflict.owner": "\u8D23\u4EFB\u4EBA {p0}",
481
+ /* ── kbConnector ── */
482
+ "kbConnector.changeRate": "\u53D8\u66F4\u7387",
483
+ "kbConnector.crawlRate": "\u6293\u53D6\u7387",
484
+ "kbConnector.credentials": "\u51ED\u8BC1",
485
+ "kbConnector.credentialsExpired": "\u51ED\u8BC1\u8FC7\u671F",
486
+ "kbConnector.editSchedule": "\u7F16\u8F91\u8BA1\u5212",
487
+ "kbConnector.empty": "\u6682\u65E0\u8FDE\u63A5\u5668",
488
+ "kbConnector.failing": "\u5F02\u5E38",
489
+ "kbConnector.lastSync": "\u6700\u8FD1\u540C\u6B65 {p0}",
490
+ "kbConnector.neverSynced": "\u4ECE\u672A\u540C\u6B65",
491
+ "kbConnector.notConfigured": "\u672A\u914D\u7F6E",
492
+ "kbConnector.off": "\u5DF2\u505C\u7528",
493
+ "kbConnector.perDay": "{p0}/\u5929",
494
+ "kbConnector.reauth": "\u91CD\u65B0\u6388\u6743",
495
+ "kbConnector.stale": "\u505C\u6EDE",
496
+ "kbConnector.syncNow": "\u7ACB\u5373\u540C\u6B65",
497
+ "kbConnector.synced": "\u5DF2\u540C\u6B65",
498
+ /* ── kbCore ── */
499
+ "kbCore.accessDenied": "\u672A\u901A\u8FC7",
500
+ "kbCore.accessExpired": "\u5DF2\u8FC7\u671F",
501
+ "kbCore.accessExpiring": "\u5373\u5C06\u5230\u671F",
502
+ "kbCore.accessGranted": "\u5DF2\u5F00\u901A",
503
+ "kbCore.accessNotRequested": "\u672A\u7533\u8BF7",
504
+ "kbCore.accessPending": "\u5F85\u5BA1\u6279",
505
+ "kbCore.accessRequested": "\u5DF2\u63D0\u4EA4",
506
+ "kbCore.accessRevoked": "\u5DF2\u6536\u56DE",
507
+ "kbCore.auditApprove": "\u6279\u51C6",
508
+ "kbCore.auditBreakGlass": "\u5E94\u6025\u8BBF\u95EE",
509
+ "kbCore.auditDelegation": "\u59D4\u6D3E",
510
+ "kbCore.auditDeny": "\u62D2\u7EDD",
511
+ "kbCore.auditGrant": "\u6388\u4E88",
512
+ "kbCore.auditPermissionChange": "\u6743\u9650\u53D8\u66F4",
513
+ "kbCore.auditPreview": "\u9884\u89C8",
514
+ "kbCore.auditRead": "\u8BFB\u53D6",
515
+ "kbCore.auditRequest": "\u7533\u8BF7",
516
+ "kbCore.auditRevoke": "\u6536\u56DE",
517
+ "kbCore.auditSync": "\u6743\u9650\u540C\u6B65",
518
+ "kbCore.daysAgo": "{p0} \u5929\u524D",
519
+ "kbCore.hoursAgo": "{p0} \u5C0F\u65F6\u524D",
520
+ "kbCore.hygieneBroadGroup": "\u8FC7\u5BBD\u7EC4\u6388\u6743",
521
+ "kbCore.hygieneBrokenInheritance": "\u65AD\u7EE7\u627F",
522
+ "kbCore.hygieneOrgWideLink": "\u7EC4\u7EC7\u7EA7\u94FE\u63A5",
523
+ "kbCore.hygieneOrphanedOwner": "\u8D1F\u8D23\u4EBA\u7F3A\u4F4D",
524
+ "kbCore.hygieneOverexposed": "\u8FC7\u5EA6\u66B4\u9732",
525
+ "kbCore.hygieneSensitiveMismatch": "\u654F\u611F\u5EA6\u9519\u914D",
526
+ "kbCore.justNow": "\u521A\u521A",
527
+ "kbCore.levelComment": "\u53EF\u8BC4\u8BBA",
528
+ "kbCore.levelEdit": "\u53EF\u7F16\u8F91",
529
+ "kbCore.levelNone": "\u65E0\u6743\u9650",
530
+ "kbCore.levelOwner": "\u8D1F\u8D23\u4EBA",
531
+ "kbCore.levelView": "\u53EF\u67E5\u770B",
532
+ "kbCore.minutesAgo": "{p0} \u5206\u949F\u524D",
533
+ "kbCore.runCancelled": "\u5DF2\u53D6\u6D88",
534
+ "kbCore.runDone": "\u5DF2\u5B8C\u6210",
535
+ "kbCore.runFailed": "\u5931\u8D25",
536
+ "kbCore.runQueued": "\u6392\u961F\u4E2D",
537
+ "kbCore.runRunning": "\u8FDB\u884C\u4E2D",
538
+ "kbCore.runUnstarted": "\u672A\u5F00\u59CB",
539
+ "kbCore.stageAgent": "\u4EE3\u7406",
540
+ "kbCore.stageChunk": "\u5207\u7247",
541
+ "kbCore.stageEmbed": "\u5411\u91CF\u5316",
542
+ "kbCore.stageGeneration": "\u751F\u6210",
543
+ "kbCore.stageGuard": "\u62A4\u680F",
544
+ "kbCore.stageQuery": "\u67E5\u8BE2",
545
+ "kbCore.stageRerank": "\u91CD\u6392",
546
+ "kbCore.stageRetrieval": "\u68C0\u7D22",
547
+ "kbCore.stageTool": "\u5DE5\u5177",
548
+ "kbCore.typeApi": "\u63A5\u53E3",
549
+ "kbCore.typeCode": "\u4EE3\u7801",
550
+ "kbCore.typeDatabase": "\u6570\u636E\u5E93",
551
+ "kbCore.typeDocument": "\u6587\u6863",
552
+ "kbCore.typeEmail": "\u90AE\u4EF6",
553
+ "kbCore.typeImage": "\u56FE\u7247",
554
+ "kbCore.typeKb": "\u77E5\u8BC6\u5E93",
555
+ "kbCore.typeTable": "\u8868\u683C",
556
+ "kbCore.typeTicket": "\u5DE5\u5355",
557
+ "kbCore.typeWebpage": "\u7F51\u9875",
558
+ "kbCore.unnamedSource": "\u672A\u547D\u540D\u6765\u6E90",
559
+ "kbCore.unnamedSubject": "\u672A\u547D\u540D\u4E3B\u4F53",
560
+ "kbCore.visHidden": "\u4E0D\u53EF\u89C1",
561
+ "kbCore.visMetadataOnly": "\u4EC5\u5143\u6570\u636E",
562
+ "kbCore.visSummaryOnly": "\u4EC5\u6458\u8981",
563
+ "kbCore.visVisible": "\u53EF\u89C1",
564
+ /* ── kbEval ── */
565
+ "kbEval.avgA": "A \u5747\u5206 {p0}",
566
+ "kbEval.avgB": "B \u5747\u5206 {p0}",
567
+ "kbEval.compare": "\u5BF9\u6BD4",
568
+ "kbEval.runSelectAria": "\u9009\u62E9\u5BF9\u6BD4\u8FD0\u884C",
569
+ "kbEval.expected": "\u671F\u671B",
570
+ "kbEval.gradeImprovement": "\u63D0\u5347",
571
+ "kbEval.gradeRegression": "\u56DE\u5F52",
572
+ "kbEval.gradeTie": "\u6301\u5E73",
573
+ "kbEval.gradeTradeoff": "\u6743\u8861",
574
+ "kbEval.noData": "\u6CA1\u6709\u5BF9\u6BD4\u6570\u636E",
575
+ "kbEval.onlyRegression": "\u4EC5\u770B\u56DE\u5F52",
576
+ "kbEval.outputA": "\u8F93\u51FA A",
577
+ "kbEval.outputB": "\u8F93\u51FA B",
578
+ "kbEval.outputN": "\u8F93\u51FA {p0}",
579
+ /* ── kbExplain ── */
580
+ "kbExplain.empty": "\u6682\u65E0\u53E3\u5F84\u4FE1\u606F",
581
+ "kbExplain.groupAgg": "\u805A\u5408",
582
+ "kbExplain.groupColumn": "\u5217",
583
+ "kbExplain.groupFilter": "\u7B5B\u9009",
584
+ "kbExplain.groupTable": "\u8868",
585
+ "kbExplain.trigger": "\u8FD9\u4E2A\u6570\u5B57\u662F\u600E\u4E48\u7B97\u51FA\u6765\u7684",
586
+ "kbExplain.viewDefinition": "\u67E5\u770B\u53E3\u5F84",
587
+ /* ── kbFilter ── */
588
+ "kbFilter.addGroup": "+ \u7EC4",
589
+ "kbFilter.addRule": "+ \u89C4\u5219",
590
+ "kbFilter.and": "\u4E14",
591
+ "kbFilter.combineMode": "\u7EC4\u5408\u65B9\u5F0F {p0}",
592
+ "kbFilter.copyDsl": "\u590D\u5236 DSL",
593
+ "kbFilter.deleteGroup": "\u5220\u9664\u7EC4",
594
+ "kbFilter.deleteRule": "\u5220\u9664\u89C4\u5219",
595
+ "kbFilter.fieldLabel": "\u5B57\u6BB5",
596
+ "kbFilter.fieldPlaceholder": "\u8FC7\u6EE4\u5B57\u6BB5",
597
+ "kbFilter.noValueNeeded": "\uFF08\u65E0\u9700\u503C\uFF09",
598
+ "kbFilter.none": "\uFF08\u65E0\u8FC7\u6EE4\uFF09",
599
+ "kbFilter.opContains": "\u5305\u542B",
600
+ "kbFilter.opEq": "\u7B49\u4E8E",
601
+ "kbFilter.opExists": "\u5B58\u5728",
602
+ "kbFilter.opGt": "\u5927\u4E8E",
603
+ "kbFilter.opGte": "\u5927\u4E8E\u7B49\u4E8E",
604
+ "kbFilter.opIn": "\u5C5E\u4E8E",
605
+ "kbFilter.opLt": "\u5C0F\u4E8E",
606
+ "kbFilter.opLte": "\u5C0F\u4E8E\u7B49\u4E8E",
607
+ "kbFilter.opNe": "\u4E0D\u7B49\u4E8E",
608
+ "kbFilter.operatorLabel": "\u64CD\u4F5C\u7B26",
609
+ "kbFilter.or": "\u6216",
610
+ "kbFilter.toggleAndOr": "\u5207\u6362 AND / OR",
611
+ "kbFilter.valueAria": "\u8FC7\u6EE4\u503C",
612
+ "kbFilter.valueLabel": "\u503C",
613
+ "kbFilter.valuePlaceholder": "\u503C 1, \u503C 2\uFF08\u9017\u53F7\u5206\u9694\uFF09",
614
+ /* ── kbGap ── */
615
+ "kbGap.addSynonym": "\u52A0\u540C\u4E49\u8BCD",
616
+ "kbGap.colCount": "\u6B21\u6570",
617
+ "kbGap.colLastSeen": "\u6700\u8FD1\u51FA\u73B0",
618
+ "kbGap.colQuery": "\u67E5\u8BE2",
619
+ "kbGap.colShare": "\u5360\u6BD4",
620
+ "kbGap.createDoc": "\u5EFA\u6587\u6863",
621
+ "kbGap.empty": "\u6CA1\u6709\u672A\u547D\u4E2D\u67E5\u8BE2\u2014\u2014\u8986\u76D6\u826F\u597D",
622
+ "kbGap.title": "\u672A\u547D\u4E2D\u67E5\u8BE2\u8D8B\u52BF",
623
+ "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",
624
+ "kbGap.zeroClickRate": "\u96F6\u70B9\u51FB\u7387",
625
+ "kbGap.zeroClickTitle": "\u96F6\u70B9\u51FB \u2260 \u5931\u8D25",
626
+ /* ── kbHittest ── */
627
+ "kbHittest.addAria": "\u65B0\u589E\u6D4B\u8BD5\u95EE\u9898",
628
+ "kbHittest.addPlaceholder": "\u65B0\u589E\u95EE\u9898\uFF0CEnter \u6DFB\u52A0",
629
+ "kbHittest.avgScore": "\u5747\u5206",
630
+ "kbHittest.deleteQuestion": "\u5220\u9664\u95EE\u9898",
631
+ "kbHittest.empty": "\u6682\u65E0\u6D4B\u8BD5\u95EE\u9898\u2014\u2014\u6DFB\u52A0\u7B2C\u4E00\u6761\uFF0C\u5F00\u59CB\u53EC\u56DE\u56DE\u5F52",
632
+ "kbHittest.expectHit": "\u671F\u671B\u547D\u4E2D\u5728\u524D\u6392\u547D\u4E2D\u4E2D",
633
+ "kbHittest.expectMiss": "\u671F\u671B\u672A\u547D\u4E2D",
634
+ "kbHittest.hitRate": "\u547D\u4E2D\u7387",
635
+ "kbHittest.noExpectation": "\u672A\u8BBE\u671F\u671B",
636
+ "kbHittest.notRun": "\u672A\u8FD0\u884C",
637
+ "kbHittest.pass": "\u901A\u8FC7",
638
+ "kbHittest.pin": "\u7F6E\u9876\u56FA\u5B9A",
639
+ "kbHittest.runAll": "\u8FD0\u884C\u5168\u90E8",
640
+ "kbHittest.sessionOnly": "\u53C2\u6570\u4EC5\u672C\u6B21\u4F1A\u8BDD\u751F\u6548",
641
+ "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",
642
+ "kbHittest.unpin": "\u53D6\u6D88\u7F6E\u9876",
643
+ /* ── kbMetadata ── */
644
+ "kbMetadata.addField": "\u65B0\u589E\u5B57\u6BB5",
645
+ "kbMetadata.builtIn": "\u5185\u7F6E",
646
+ "kbMetadata.colField": "\u5B57\u6BB5",
647
+ "kbMetadata.colType": "\u7C7B\u578B",
648
+ "kbMetadata.colValue": "\u503C",
649
+ "kbMetadata.empty": "\u6682\u65E0\u5143\u6570\u636E\u5B57\u6BB5",
650
+ "kbMetadata.nameLabel": "\u65B0\u5B57\u6BB5\u540D",
651
+ "kbMetadata.namePlaceholder": "\u5B57\u6BB5\u540D\uFF0C\u5982 department",
652
+ "kbMetadata.removeField": "\u79FB\u9664\u5B57\u6BB5 {p0}",
653
+ "kbMetadata.typeLabel": "\u65B0\u5B57\u6BB5\u7C7B\u578B",
654
+ "kbMetadata.valueOf": "{p0} \u7684\u503C",
655
+ /* ── kbPassage ── */
656
+ "kbPassage.blockRange": "\u5757 {p0}\u2013{p1}",
657
+ "kbPassage.close": "\u5173\u95ED\u539F\u6587",
658
+ "kbPassage.expandContext": "\u5C55\u5F00\u4E0A\u4E0B\u6587",
659
+ "kbPassage.locate": "\u539F\u6587\u5B9A\u4F4D",
660
+ "kbPassage.none": "\uFF08\u65E0\u539F\u6587\uFF09",
661
+ "kbPassage.pageRange": "\u7B2C {p0}\u2013{p1} \u9875",
662
+ "kbPassage.restricted": "\u5185\u5BB9\u53D7\u9650",
663
+ "kbPassage.unitByte": "\u5B57\u8282",
664
+ "kbPassage.unitChar": "\u5B57\u7B26",
665
+ /* ── kbPipeline ── */
666
+ "kbPipeline.empty": "\u6682\u65E0\u89E3\u6790\u4EFB\u52A1",
667
+ "kbPipeline.progress": "\u89E3\u6790\u8FDB\u5EA6",
668
+ "kbPipeline.rerun": "\u91CD\u8DD1",
669
+ "kbPipeline.unknownStage": "\u672A\u77E5\u9636\u6BB5",
670
+ /* ── kbQa ── */
671
+ "kbQa.colAnswer": "\u7B54\u6848",
672
+ "kbQa.colQuestion": "\u95EE\u9898",
673
+ "kbQa.csvHint": "CSV \u6A21\u677F\uFF1Aquestion,answer\uFF08\u6BCF\u884C\u4E00\u5BF9\uFF0CUTF-8\uFF09",
674
+ "kbQa.deleteRow": "\u5220\u9664\u7B2C {p0} \u884C",
675
+ "kbQa.empty": "\u6682\u65E0\u8BA4\u8BC1\u95EE\u7B54\u5BF9",
676
+ "kbQa.importCsv": "\u5BFC\u5165 CSV",
677
+ /* ── kbRerank ── */
678
+ "kbRerank.after": "\u91CD\u6392\u540E",
679
+ "kbRerank.before": "\u91CD\u6392\u524D",
680
+ "kbRerank.compareTitle": "\u91CD\u6392\u5BF9\u6BD4",
681
+ "kbRerank.down": "\u4E0B\u964D {p0} \u4F4D",
682
+ "kbRerank.dropped": "\u843D\u9009",
683
+ "kbRerank.empty": "\u4E24\u4FA7\u5747\u4E3A\u7A7A\u2014\u2014\u8FD0\u884C\u68C0\u7D22\u540E\u518D\u5BF9\u6BD4",
684
+ "kbRerank.enableCompare": "\u542F\u7528\u91CD\u6392\u5BF9\u6BD4",
685
+ "kbRerank.newIn": "\u65B0\u8FDB",
686
+ "kbRerank.unmarked": "\u672A\u6807",
687
+ "kbRerank.up": "\u4E0A\u5347 {p0} \u4F4D",
688
+ /* ── kbRetrieval ── */
689
+ "kbRetrieval.breakdown": "\u62C6\u89E3",
690
+ "kbRetrieval.copyParams": "\u590D\u5236\u53C2\u6570 JSON",
691
+ "kbRetrieval.decreaseTopK": "\u51CF\u5C11 topK",
692
+ "kbRetrieval.empty": "\u8F93\u5165\u95EE\u9898\u5E76\u8FD0\u884C\uFF0C\u547D\u4E2D\u7ED3\u679C\u5C06\u51FA\u73B0\u5728\u8FD9\u91CC",
693
+ "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",
694
+ "kbRetrieval.hybridWeight": "\u6DF7\u5408\u6743\u91CD\uFF08\u5DE6\u8BED\u4E49\u53F3\u5173\u952E\u8BCD\uFF09",
695
+ "kbRetrieval.identityLabel": "\u68C0\u7D22\u8EAB\u4EFD",
696
+ "kbRetrieval.identityShort": "\u8EAB\u4EFD",
697
+ "kbRetrieval.increaseTopK": "\u589E\u52A0 topK",
698
+ "kbRetrieval.keywordHint": "\u5173\u952E\u8BCD\uFF1A\u5927\u5E93\u5FEB\u901F\u7CBE\u786E",
699
+ "kbRetrieval.layerLabel": "\u8FC7\u6EE4\u5C42",
700
+ "kbRetrieval.layerNone": "none\uFF1Afail-open\uFF0C\u65E0\u8EAB\u4EFD\u8FC7\u6EE4\u8FD4\u56DE\u5168\u90E8\u2014\u2014\u5371\u9669\uFF0C\u4EC5\u6F14\u793A",
701
+ "kbRetrieval.layerPost": "post-filter\uFF1A\u5206\u6570\u5DF2\u53EF\u89C2\u5BDF\u2014\u2014\u7F3A\u9677\u5C42\uFF0C\u4EC5\u6F14\u793A",
702
+ "kbRetrieval.layerPre": "pre-filter\uFF1AACL \u5728\u68C0\u7D22\u6267\u884C\u4F53\u5185\u751F\u6548\u2014\u2014\u5B89\u5168\u57FA\u7EBF",
703
+ "kbRetrieval.leakNote": "\u5206\u6BCD\u672A\u8FC7\u6EE4\u524D\u8BA1\u6570\u5C5E\u6CC4\u9732\uFF0C\u4E0D\u663E\u793A",
704
+ "kbRetrieval.modeHybrid": "\u6DF7\u5408",
705
+ "kbRetrieval.modeKeyword": "\u5173\u952E\u8BCD",
706
+ "kbRetrieval.modeLabel": "\u68C0\u7D22\u6A21\u5F0F",
707
+ "kbRetrieval.modeVector": "\u5411\u91CF",
708
+ "kbRetrieval.postFilterNotice": "post-filter\uFF1A\u5206\u6570\u5DF2\u5728\u8FC7\u6EE4\u524D\u4EA7\u751F\uFF08\u7F3A\u9677\u5C42\u6F14\u793A\uFF09",
709
+ "kbRetrieval.queryLabel": "\u68C0\u7D22\u95EE\u9898",
710
+ "kbRetrieval.queryPlaceholder": "\u68C0\u7D22\u95EE\u9898\uFF0CEnter \u8FD0\u884C",
711
+ "kbRetrieval.rerankLabel": "\u91CD\u6392",
712
+ "kbRetrieval.rerankThresholdOff": "\u9608\u503C \u5173 \xB7 \u5B58\u6D3B {p0}",
713
+ "kbRetrieval.rerankThresholdOn": "\u9608\u503C {p0} \xB7 \u5B58\u6D3B {p1}",
714
+ "kbRetrieval.running": "\u8FD0\u884C\u4E2D\u2026",
715
+ "kbRetrieval.thresholdLabel": "\u5206\u6570\u9608\u503C",
716
+ "kbRetrieval.thresholdValue": "\u9608\u503C N/A",
717
+ "kbRetrieval.vectorHint": "\u8BED\u4E49\uFF1A\u8DE8\u8BED\u8A00/\u65E0\u7CBE\u786E\u8BCD",
718
+ "kbRetrieval.vectorPercent": "\u8BED\u4E49 {p0}",
719
+ "kbRetrieval.weightValue": "\u5411\u91CF {p0}% / \u5173\u952E\u8BCD {p1}%",
720
+ /* ── kbReview ── */
721
+ "kbReview.assignee": "\u5206\u914D\u4EBA",
722
+ "kbReview.doneNext": "\u5B8C\u6210\u5E76\u4E0B\u4E00\u6761",
723
+ "kbReview.empty": "\u6CA1\u6709\u5F85\u5BA1\u67E5\u6761\u76EE",
724
+ "kbReview.emptyAssignee": "\u8BE5\u5206\u914D\u4EBA\u4E0B\u6CA1\u6709\u6761\u76EE",
725
+ "kbReview.emptyQueue": "\u961F\u5217\u4E3A\u7A7A",
726
+ "kbReview.kbCloseHint": "\u5173\u95ED\u63D0\u793A",
727
+ "kbReview.kbSelectOption": "\u9009\u62E9\u9009\u9879",
728
+ "kbReview.kbSwitchItem": "\u5207\u6362\u6761\u76EE",
729
+ "kbReview.kbToggleHint": "\u663E\u793A/\u9690\u85CF\u672C\u63D0\u793A",
730
+ "kbReview.shortcuts": "? \u5FEB\u6377\u952E",
731
+ "kbReview.typeAnswer": "\u56DE\u7B54",
732
+ "kbReview.typeMessage": "\u6D88\u606F",
733
+ "kbReview.typeTrace": "\u8F68\u8FF9",
734
+ "kbReview.unassigned": "\u672A\u5206\u914D",
735
+ /* ── kbSandbox ── */
736
+ "kbSandbox.noResolver": "\u5BBF\u4E3B\u672A\u63D0\u4F9B ui:// \u89E3\u6790\u5668",
737
+ "kbSandbox.notReady": "kb-sandbox: \u5E94\u7528\u672A\u5C31\u7EEA",
738
+ "kbSandbox.resolveFailed": "ui:// \u89E3\u6790\u5931\u8D25\uFF1A{p0}",
739
+ "kbSandbox.timeout": "kb-sandbox: \u8C03\u7528\u8D85\u65F6\uFF08{p0}ms\uFF09",
740
+ "kbSandbox.title": "MCP App \u6C99\u7BB1",
741
+ /* ── kbSegment ── */
742
+ "kbSegment.avgLength": "\u5747\u957F {p0}",
743
+ "kbSegment.childNote": "\u5B50\u5206\u6BB5\u6309\u957F\u5EA6\u81EA\u52A8\u751F\u6210",
744
+ "kbSegment.cleanBlankLines": "\u5408\u5E76\u8FDE\u7EED\u7A7A\u884C",
745
+ "kbSegment.cleanEmails": "\u53BB\u9664\u90AE\u7BB1",
746
+ "kbSegment.cleanLinks": "\u53BB\u9664\u94FE\u63A5",
747
+ "kbSegment.empty": "\u6837\u672C\u4E3A\u7A7A\uFF0C\u6682\u65E0\u53EF\u9884\u89C8\u5206\u6BB5",
748
+ "kbSegment.maxLengthLabel": "\u6700\u5927\u957F\u5EA6",
749
+ "kbSegment.maxLengthPlaceholder": "\u5206\u6BB5\u6700\u5927\u957F\u5EA6",
750
+ "kbSegment.modeAuto": "\u81EA\u52A8",
751
+ "kbSegment.modeCustom": "\u81EA\u5B9A\u4E49",
752
+ "kbSegment.modeLabel": "\u5206\u6BB5\u6A21\u5F0F",
753
+ "kbSegment.modeNote": "\u5206\u6BB5\u6A21\u5F0F\u521B\u5EFA\u540E\u4E0D\u53EF\u66F4\u6539\uFF0C\u53C2\u6570\u53EF\u968F\u65F6\u8C03\u6574",
754
+ "kbSegment.modeParentChild": "\u7236\u5B50",
755
+ "kbSegment.overlapInvalid": "\u91CD\u53E0\u9700\u5C0F\u4E8E\u6700\u5927\u957F\u5EA6",
756
+ "kbSegment.overlapLabel": "\u91CD\u53E0",
757
+ "kbSegment.overlapPlaceholder": "\u5206\u6BB5\u91CD\u53E0",
758
+ "kbSegment.previewNote": "\u5171 {p0} \u6BB5\uFF0C\u4EC5\u9884\u89C8\u524D {p1} \u6BB5",
759
+ "kbSegment.segmentsCount": "{p0} \u6BB5",
760
+ "kbSegment.separatorLabel": "\u5206\u9694\u7B26",
761
+ "kbSegment.separatorPlaceholder": "\u5206\u6BB5\u5206\u9694\u7B26",
762
+ "kbSegment.toggleTip": "\u70B9\u51FB\u5C55\u5F00/\u6536\u8D77",
763
+ /* ── kbSources ── */
764
+ "kbSources.cited": "\u88AB\u5F15 \xD7{p0}",
765
+ "kbSources.empty": "\u4E0B\u4E00\u6761\u7B54\u6848\u5F15\u7528\u7684\u6BB5\u843D\u5C06\u51FA\u73B0\u5728\u8FD9\u91CC",
766
+ /* ── kbSql ── */
767
+ "kbSql.adminOnly": "\u4EC5\u7BA1\u7406\u5458\u53EF\u89C1",
768
+ "kbSql.applyFix": "\u5E94\u7528\u4FEE\u590D\u5E76\u91CD\u8DD1",
769
+ "kbSql.confirmRerun": "\u786E\u8BA4\u5E76\u91CD\u8DD1",
770
+ "kbSql.editRerun": "\u7F16\u8F91\u91CD\u8DD1",
771
+ "kbSql.fixReady": "\u68C0\u6D4B\u5230\u4E0A\u7248\u62A5\u9519\uFF0C\u4FEE\u590D\u5EFA\u8BAE\u5DF2\u5C31\u7EEA",
772
+ "kbSql.generated": "\u751F\u6210\u7684 SQL",
773
+ /* ── kbTrace ── */
774
+ "kbTrace.empty": "\u6682\u65E0\u8C03\u7528\u94FE\u6570\u636E",
775
+ "kbTrace.hits": "\u547D\u4E2D {p0}",
776
+ /* ── kbVisibility ── */
777
+ "kbVisibility.adminOnlyNote": "\u4EE5\u4E0A\u5BF9\u7167\u4EC5\u9650 admin \u5BA1\u8BA1",
778
+ "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",
779
+ "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",
780
+ "kbVisibility.focusColumn": "\u805A\u7126\u8EAB\u4EFD {p0} \u7684\u5217",
781
+ "kbVisibility.layerValue": "\u8FC7\u6EE4\u5C42\uFF1A{p0}",
782
+ "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",
783
+ "kbVisibility.postFilterNote": "post-filter\uFF1AtopK \u88AB\u65E0\u6743\u7ED3\u679C\u5360\u7528\u4E14\u76F8\u4F3C\u5EA6\u5206\u6570\u53EF\u88AB\u89C2\u5BDF",
784
+ "kbVisibility.queryLabel": "\u67E5\u8BE2\uFF1A{p0}",
785
+ "kbVisibility.safeCount": "\u5B89\u5168\u8BA1\u6570 {p0}",
786
+ "kbVisibility.sourceUnavailable": "\u539F\u6587\u4E0D\u53EF\u7528",
787
+ "kbVisibility.unnamedHit": "\u672A\u547D\u540D\u547D\u4E2D",
788
+ /* ── kbWhoCan ── */
789
+ "kbWhoCan.check": "\u68C0\u67E5",
790
+ "kbWhoCan.checkIdentity": "\u68C0\u67E5\u8EAB\u4EFD",
791
+ "kbWhoCan.daysUntil": "{p0} \u5929\u540E",
792
+ "kbWhoCan.deniedBy": "\u88AB\u7B56\u7565\u62D2\u7EDD\uFF1A{p0}",
793
+ "kbWhoCan.denyVeto": "\u88AB Deny \u4E00\u7968\u5426\u51B3",
794
+ "kbWhoCan.direct": "\u76F4\u63A5",
795
+ "kbWhoCan.expiresSoon": "\u6700\u8FD1\u5230\u671F {p0}",
796
+ "kbWhoCan.hoursUntil": "{p0} \u5C0F\u65F6\u540E",
797
+ "kbWhoCan.inherit": "\u7EE7\u627F",
798
+ "kbWhoCan.link": "\u94FE\u63A5",
799
+ "kbWhoCan.noDeny": "\u65E0 Deny \u751F\u6548",
800
+ "kbWhoCan.noIdentity": "\u672A\u63D0\u4F9B\u53EF\u68C0\u67E5\u7684\u8EAB\u4EFD",
801
+ "kbWhoCan.none": "\u672A\u547D\u4E2D\u4EFB\u4F55\u6388\u6743\u2014\u2014\u9ED8\u8BA4\u62D2\u7EDD",
802
+ "kbWhoCan.recheckTip": "\u91CD\u65B0\u68C0\u67E5\u5F53\u524D\u8EAB\u4EFD\u7684\u6709\u6548\u6743\u9650",
803
+ "kbWhoCan.stackRule": "\u53E0\u52A0\u89C4\u5219\uFF1A\u591A\u6765\u6E90\u5E76\u96C6 \u2192 {p0}\uFF1B{p1}",
804
+ /* ── mentions ── */
805
+ "mentions.create": "\u521B\u5EFA\u201C{p0}\u201D",
806
+ "mentions.customBadge": "\u81EA\u5B9A\u4E49",
807
+ "mentions.loading": "\u52A0\u8F7D\u4E2D\u2026",
808
+ /* ── notification ── */
809
+ "notification.groupBusy": "\u64CD\u4F5C\u7ED3\u675F\u540E\u53EF\u4EE5\u6536\u8D77\u8FD9\u7EC4\u901A\u77E5\u3002",
810
+ "notification.groupUnread": "{count} \u6761\u540C\u7EC4\u901A\u77E5\uFF0C{unread} \u6761\u672A\u8BFB",
811
+ "notification.groupCount": "{count} \u6761\u540C\u7EC4\u901A\u77E5",
812
+ "notification.groupExpanded": "\u6536\u8D77\u8FD9\u7EC4\u901A\u77E5",
813
+ "notification.ariaLabel": "\u901A\u77E5",
814
+ "notification.viewDetails": "\u67E5\u770B\u8BE6\u60C5",
815
+ /* ── pagination ── */
816
+ "pagination.next": "\u4E0B\u4E00\u9875",
817
+ "pagination.pageSize": "{p0} \u6761/\u9875",
818
+ "pagination.prev": "\u4E0A\u4E00\u9875",
819
+ /* ── select ── */
820
+ "select.fieldLabel": "\u9009\u62E9\u9009\u9879",
821
+ "select.noMatch": "\u65E0\u5339\u914D\u9879",
822
+ "select.remove": "\u79FB\u9664 {p0}",
823
+ "select.searchPlaceholder": "\u641C\u7D22\u2026",
824
+ /* ── cascader / tree-select ── */
825
+ "cascader.placeholder": "\u8BF7\u9009\u62E9",
826
+ "cascader.noMatch": "\u65E0\u5339\u914D",
827
+ "cascader.search": "\u641C\u7D22",
828
+ "treeSelect.placeholder": "\u8BF7\u9009\u62E9",
829
+ "treeSelect.noMatch": "\u65E0\u5339\u914D",
830
+ "treeSelect.search": "\u641C\u7D22",
831
+ /* ── tagInput ── */
832
+ "tagInput.ariaLabel": "\u6807\u7B7E\u8F93\u5165\uFF0C\u5171 {p0} \u4E2A",
833
+ "tagInput.remove": "\u79FB\u9664 {p0}",
834
+ "tagInput.field": "\u6DFB\u52A0\u6807\u7B7E",
835
+ "tagInput.added": "\u5DF2\u6DFB\u52A0 {p0} \u4E2A\u6807\u7B7E\u3002",
836
+ "tagInput.removed": "\u5DF2\u79FB\u9664 {p0}\u3002",
837
+ "tagInput.duplicate": "\u5DF2\u6709\u300C{p0}\u300D\uFF0C\u53EF\u4EE5\u7F16\u8F91\u540E\u91CD\u8BD5\u3002",
838
+ "tagInput.limit": "\u6700\u591A {p0} \u4E2A\u6807\u7B7E\uFF0C\u8BF7\u5148\u79FB\u9664\u4E00\u4E2A\u3002",
839
+ /* ── upload ── */
840
+ "upload.remove": "\u79FB\u9664 {p0}",
841
+ "upload.tooBig": "\u6587\u4EF6\u8D85\u8FC7 {p0}",
842
+ "upload.tooMany": "\u6700\u591A {p0} \u4E2A\u6587\u4EF6",
843
+ "upload.typeNotAllowed": "\u6587\u4EF6\u7C7B\u578B\u4E0D\u652F\u6301"
844
+ };
845
+ var current = { ...ICEN_LOCALE_ZH_CN };
846
+ function t(key, vars) {
847
+ const raw = current[key] ?? ICEN_LOCALE_ZH_CN[key];
848
+ if (vars == null || Array.isArray(raw)) return raw;
849
+ return raw.replace(/\{(\w+)\}/g, (m, name) => name in vars ? String(vars[name]) : m);
850
+ }
851
+
852
+ // src/behaviors/icons.ts
853
+ var ICON_PATHS = {
854
+ 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",
855
+ 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",
856
+ 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",
857
+ 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",
858
+ 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",
859
+ 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",
860
+ 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",
861
+ 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",
862
+ 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",
863
+ "line-numbers": "M3 5h2M3 10h2M3 15h2M8 5h9M8 10h9M8 15h9",
864
+ wrap: "M3 5h14M3 10h10a3 3 0 0 1 0 6h-3M12.5 13.5 10 16l2.5 2.5",
865
+ 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",
866
+ close: "M6 6l8 8M14 6l-8 8",
867
+ check: "M4.5 10.2l3.6 3.6 7.4-7.6",
868
+ "chevron-down": "M5.5 7.75 10 12.25l4.5-4.5",
869
+ "chevron-up": "M5.5 12.25 10 7.75l4.5 4.5",
870
+ "chevron-right": "M7.75 5.5 12.25 10l-4.5 4.5",
871
+ "chevron-left": "M12.25 5.5 7.75 10l4.5 4.5",
872
+ "arrow-right": "M3.5 10h13M11 4.5l5.5 5.5-5.5 5.5",
873
+ "arrow-left": "M16.5 10h-13M9 4.5 3.5 10 9 15.5",
874
+ "arrow-up": "M10 16.5v-13M4.5 9 10 3.5 15.5 9",
875
+ "arrow-down": "M10 3.5v13M4.5 11l5.5 5.5 5.5-5.5",
876
+ plus: "M10 4v12M4 10h12",
877
+ minus: "M4 10h12",
878
+ sort: "M6 15V4M3 7l3-3 3 3M14 5v11M11 13l3 3 3-3",
879
+ search: "M13.3 13.3 17 17M14.5 8.5a6 6 0 1 1-12 0 6 6 0 0 1 12 0",
880
+ 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",
881
+ 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",
882
+ 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",
883
+ pixel: "M3 3h5v5H3ZM12 3h5v5h-5ZM3 12h5v5H3ZM12 12h5v5h-5Z",
884
+ chinese: "M3 8c3 0 5-2 7-5 2 3 4 5 7 5M4 8h12M6 8v8m8-8v8M3 16h14M8 16v-5h4v5",
885
+ soviet: "M3 17h14M5 17V8h4v9m0-12h6v12M7 8V5h2m2 3h2m-2 3h2m-2 3h2M10 5V3h4v2",
886
+ more: "M4 9.9v.2M10 9.9v.2M16 9.9v.2",
887
+ 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",
888
+ 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",
889
+ 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",
890
+ trash: "M3.5 5.5h13M7 5.5V3h6v2.5M5 5.5l.7 11.5h8.6L15 5.5M8 9v5M12 9v5",
891
+ spinner: "M10 3a7 7 0 1 1-7 7",
892
+ "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",
893
+ "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",
894
+ "circle-info": "M18 10a8 8 0 1 1-16 0 8 8 0 0 1 16 0ZM10 9v5M10 6.1v.15",
895
+ "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",
896
+ 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",
897
+ 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",
898
+ 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",
899
+ settings: "M3.5 5.5h13M3.5 10h13M3.5 14.5h13M7 4v3M12.5 8.5v3M8 13v3",
900
+ 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",
901
+ 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",
902
+ "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",
903
+ 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",
904
+ 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",
905
+ 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",
906
+ activity: "M17 10h-2.6l-2 5.8L8 4.2 6 10H3",
907
+ "trend-up": "M3.5 14.5l4.2-4.2 2.8 2.8 5.9-5.9M12.4 7.2h4.2v4.2",
908
+ "trend-down": "M3.5 5.5l4.2 4.2 2.8-2.8 5.9 5.9M12.4 12.8h4.2V8.6",
909
+ 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",
910
+ bold: "M6.5 4h4.2a3 3 0 0 1 0 6H6.5M6.5 10h5a3 3 0 0 1 0 6H6.5M6.5 4v12",
911
+ italic: "M8.5 4.5h7M4.5 15.5h7M12.5 4.5l-5 11",
912
+ underline: "M6 4v5.5a4 4 0 0 0 8 0V4M4.5 16h11",
913
+ "align-left": "M3.5 4.5h13M3.5 10h8.5M3.5 15.5h11",
914
+ "align-center": "M3.5 4.5h13M5.75 10h8.5M4.5 15.5h11",
915
+ "align-right": "M3.5 4.5h13M8 10h8.5M5.5 15.5h11",
916
+ list: "M6.5 5h10M6.5 10h10M6.5 15h10M3.5 5h.01M3.5 10h.01M3.5 15h.01",
917
+ 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",
918
+ 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",
919
+ 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",
920
+ "chart-line": "M3.5 3.5v13h13M6.5 12l2.8-2.8 2.2 2.2 4-4.4",
921
+ 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",
922
+ box: "M17 6 10 3.2 3 6v8l7 2.8 7-2.8ZM3 6l7 2.8L17 6M10 9v7.8",
923
+ filter: "M4 4.5h12l-4.4 5.1v5l-3.2-1.6V9.6Z",
924
+ columns: "M3.5 4h13v12h-13ZM8.2 4v12M12.8 4v12",
925
+ 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"
926
+ };
927
+ var custom = /* @__PURE__ */ new Map();
928
+ var escape = (s) => s.replace(/[&<>"']/g, (c) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" })[c]);
929
+ function iconPath(name) {
930
+ return Object.hasOwn(ICON_PATHS, name) ? ICON_PATHS[name] : custom.get(name) ?? null;
931
+ }
932
+ function iconAttributes(o = {}) {
933
+ const size = Number.isFinite(o.size) && o.size > 0 ? o.size : 16;
934
+ 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" } };
935
+ }
936
+ function iconHTML(name, o = {}) {
937
+ const path = iconPath(name);
938
+ if (!path) return "";
939
+ return `<svg${Object.entries(iconAttributes(o)).map(([k, v]) => ` ${k}="${escape(v)}"`).join("")}><path d="${escape(path)}"></path></svg>`;
940
+ }
941
+ function createIcon(name, o = {}) {
942
+ if (typeof document === "undefined") return null;
943
+ const path = iconPath(name);
944
+ if (!path) return null;
945
+ const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
946
+ for (const [key, value] of Object.entries(iconAttributes(o))) svg.setAttribute(key, value);
947
+ const line = document.createElementNS(svg.namespaceURI, "path");
948
+ line.setAttribute("d", path);
949
+ svg.append(line);
950
+ return svg;
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 AI_STATUSES = [
3
990
  "pending",
@@ -10,64 +997,33 @@ var AI_STATUSES = [
10
997
  ];
11
998
  function aiStatusLabel(s) {
12
999
  const labels = {
13
- pending: "\u7B49\u5F85",
14
- running: "\u6267\u884C\u4E2D",
15
- streaming: "\u6D41\u5F0F\u4E2D",
16
- approval: "\u5F85\u786E\u8BA4",
17
- done: "\u5B8C\u6210",
18
- error: "\u5931\u8D25",
19
- cancelled: "\u5DF2\u53D6\u6D88"
1000
+ pending: t("aiCore.statusPending"),
1001
+ running: t("aiCore.statusRunning"),
1002
+ streaming: t("aiCore.statusStreaming"),
1003
+ approval: t("aiCore.statusApproval"),
1004
+ done: t("aiCore.statusDone"),
1005
+ error: t("aiCore.statusError"),
1006
+ cancelled: t("aiCore.statusCancelled")
20
1007
  };
21
1008
  return labels[s] ?? s;
22
1009
  }
23
- 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>`;
24
- var ICON_TERMINAL = svg('<path d="m4 17 6-6-6-6"/><path d="M12 19h8"/>');
25
- var ICON_FILE = svg(
26
- '<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"/>'
27
- );
28
- var ICON_FILE_PEN = svg(
29
- '<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"/>'
30
- );
31
- var ICON_FILE_PLUS = svg(
32
- '<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"/>'
33
- );
34
- var ICON_TRASH = svg(
35
- '<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"/>'
36
- );
37
- var ICON_SEARCH = svg('<circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/>');
38
- var ICON_FOLDER_SEARCH = svg(
39
- '<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"/>'
40
- );
41
- var ICON_SCAN_SEARCH = svg(
42
- '<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"/>'
43
- );
44
- var ICON_GLOBE = svg(
45
- '<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"/>'
46
- );
47
- var ICON_DOWNLOAD = svg(
48
- '<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"/>'
49
- );
50
- var ICON_BLOCKS = svg(
51
- '<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"/>'
52
- );
53
- var ICON_ZAP = svg(
54
- '<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"/>'
55
- );
56
- var ICON_LIST = svg(
57
- '<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"/>'
58
- );
59
- var ICON_LIST_CHECKS = svg(
60
- '<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"/>'
61
- );
62
- var ICON_BOT = svg(
63
- '<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"/>'
64
- );
65
- var ICON_CHART = svg(
66
- '<path d="M3 3v18h18"/><path d="M7 15l4-6 3 4 5-8"/>'
67
- );
68
- var ICON_FILE_TEXT = svg(
69
- '<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"/>'
70
- );
1010
+ var ICON_TERMINAL = iconHTML("terminal");
1011
+ var ICON_FILE = iconHTML("file");
1012
+ var ICON_FILE_PEN = iconHTML("edit");
1013
+ var ICON_FILE_PLUS = iconHTML("plus");
1014
+ var ICON_TRASH = iconHTML("trash");
1015
+ var ICON_SEARCH = iconHTML("search");
1016
+ var ICON_FOLDER_SEARCH = iconHTML("folder");
1017
+ var ICON_SCAN_SEARCH = iconHTML("search");
1018
+ var ICON_GLOBE = iconHTML("globe");
1019
+ var ICON_DOWNLOAD = iconHTML("download");
1020
+ var ICON_BLOCKS = iconHTML("server");
1021
+ var ICON_ZAP = iconHTML("sparkle");
1022
+ var ICON_LIST = iconHTML("list");
1023
+ var ICON_LIST_CHECKS = iconHTML("list");
1024
+ var ICON_BOT = iconHTML("agent");
1025
+ var ICON_CHART = iconHTML("chart-line");
1026
+ var ICON_FILE_TEXT = iconHTML("document");
71
1027
  function isObj(v) {
72
1028
  return typeof v === "object" && v !== null;
73
1029
  }
@@ -117,32 +1073,32 @@ var sum = (fn) => {
117
1073
  return (input) => fn(input) ?? "";
118
1074
  };
119
1075
  var BUILTIN_KINDS = {
120
- shell: { label: "\u547D\u4EE4", icon: ICON_TERMINAL, tint: "accent", summarize: sum(summarizeShell) },
121
- read: { label: "\u8BFB\u53D6", icon: ICON_FILE, tint: "info", summarize: sum(summarizeRead) },
122
- edit: { label: "\u7F16\u8F91", icon: ICON_FILE_PEN, tint: "warning", summarize: sum(summarizePath) },
123
- write: { label: "\u5199\u5165", icon: ICON_FILE_PLUS, tint: "warning", summarize: sum(summarizePath) },
124
- rm: { label: "\u5220\u9664", icon: ICON_TRASH, tint: "error", summarize: sum(summarizePath) },
125
- grep: { label: "\u641C\u7D22", icon: ICON_SEARCH, tint: "info", summarize: sum(summarizeGrep) },
126
- glob: { label: "\u5339\u914D", icon: ICON_FOLDER_SEARCH, tint: "info", summarize: sum((i) => pickStr(i, ["pattern", "glob", "path"])) },
127
- browser: { label: "\u6D4F\u89C8", icon: ICON_GLOBE, tint: "accent", summarize: sum((i) => pickStr(i, ["url", "uri", "target"])) },
128
- search: { label: "\u68C0\u7D22", icon: ICON_SCAN_SEARCH, tint: "accent", summarize: sum((i) => pickStr(i, ["query", "q", "pattern"])) },
129
- fetch: { label: "\u8BF7\u6C42", icon: ICON_DOWNLOAD, tint: "info", summarize: sum((i) => pickStr(i, ["url", "uri", "endpoint"])) },
1076
+ shell: { label: t("aiCore.kindShell"), icon: ICON_TERMINAL, tint: "accent", summarize: sum(summarizeShell) },
1077
+ read: { label: t("aiCore.kindRead"), icon: ICON_FILE, tint: "info", summarize: sum(summarizeRead) },
1078
+ edit: { label: t("aiCore.kindEdit"), icon: ICON_FILE_PEN, tint: "warning", summarize: sum(summarizePath) },
1079
+ write: { label: t("aiCore.kindWrite"), icon: ICON_FILE_PLUS, tint: "warning", summarize: sum(summarizePath) },
1080
+ rm: { label: t("aiCore.kindDelete"), icon: ICON_TRASH, tint: "error", summarize: sum(summarizePath) },
1081
+ grep: { label: t("aiCore.kindGrep"), icon: ICON_SEARCH, tint: "info", summarize: sum(summarizeGrep) },
1082
+ glob: { label: t("aiCore.kindGlob"), icon: ICON_FOLDER_SEARCH, tint: "info", summarize: sum((i) => pickStr(i, ["pattern", "glob", "path"])) },
1083
+ browser: { label: t("aiCore.kindBrowser"), icon: ICON_GLOBE, tint: "accent", summarize: sum((i) => pickStr(i, ["url", "uri", "target"])) },
1084
+ search: { label: t("aiCore.kindSearch"), icon: ICON_SCAN_SEARCH, tint: "accent", summarize: sum((i) => pickStr(i, ["query", "q", "pattern"])) },
1085
+ fetch: { label: t("aiCore.kindFetch"), icon: ICON_DOWNLOAD, tint: "info", summarize: sum((i) => pickStr(i, ["url", "uri", "endpoint"])) },
130
1086
  mcp: { label: "MCP", icon: ICON_BLOCKS, tint: "muted", summarize: sum((i) => pickStr(i, ["tool", "method", "name"])) },
131
- skill: { label: "\u6280\u80FD", icon: ICON_ZAP, tint: "accent", summarize: sum((i) => pickStr(i, ["skill", "name", "command"])) },
1087
+ skill: { label: t("aiCore.kindSkill"), icon: ICON_ZAP, tint: "accent", summarize: sum((i) => pickStr(i, ["skill", "name", "command"])) },
132
1088
  todo: {
133
- label: "\u5F85\u529E",
1089
+ label: t("aiCore.kindTodo"),
134
1090
  icon: ICON_LIST,
135
1091
  tint: "info",
136
1092
  summarize: sum((input) => {
137
1093
  const items = input && typeof input === "object" && Array.isArray(input.items) ? input.items : Array.isArray(input) ? input : [];
138
1094
  const done = items.filter((it) => it?.status === "done").length;
139
- return items.length > 0 ? `${done}/${items.length} \u5B8C\u6210` : "";
1095
+ return items.length > 0 ? t("aiCore.todoProgress", { p0: done, p1: items.length }) : "";
140
1096
  })
141
1097
  },
142
- plan: { label: "\u8BA1\u5212", icon: ICON_LIST_CHECKS, tint: "info" },
143
- subagent: { label: "\u5B50\u4EE3\u7406", icon: ICON_BOT, tint: "accent", summarize: sum((i) => pickStr(i, ["task", "description", "prompt", "message", "subagent_type"])) },
144
- note: { label: "\u7B14\u8BB0", icon: ICON_FILE_TEXT, tint: "muted" },
145
- chart: { label: "\u56FE\u8868", icon: ICON_CHART, tint: "info", summarize: sum((i) => pickStr(i, ["title", "name"])) }
1098
+ plan: { label: t("aiCore.kindPlan"), icon: ICON_LIST_CHECKS, tint: "info" },
1099
+ subagent: { label: t("aiCore.kindSubagent"), icon: ICON_BOT, tint: "accent", summarize: sum((i) => pickStr(i, ["task", "description", "prompt", "message", "subagent_type"])) },
1100
+ note: { label: t("aiCore.kindNote"), icon: ICON_FILE_TEXT, tint: "muted" },
1101
+ chart: { label: t("aiCore.kindChart"), icon: ICON_CHART, tint: "info", summarize: sum((i) => pickStr(i, ["title", "name"])) }
146
1102
  };
147
1103
  var kindRegistry = new Map(Object.entries(BUILTIN_KINDS));
148
1104
  function getAiKind(name) {
@@ -169,10 +1125,10 @@ function formatDuration(ms) {
169
1125
  var PART_TYPES = /* @__PURE__ */ new Set(["text", "image", "audio", "video", "file", "resource-link"]);
170
1126
  function isAiContentPart(v) {
171
1127
  if (!isObj(v)) return false;
172
- const t = v.type;
173
- if (typeof t !== "string" || !PART_TYPES.has(t)) return false;
174
- if (t === "text") return typeof v.text === "string";
175
- if (t === "resource-link") return typeof v.uri === "string";
1128
+ const t2 = v.type;
1129
+ if (typeof t2 !== "string" || !PART_TYPES.has(t2)) return false;
1130
+ if (t2 === "text") return typeof v.text === "string";
1131
+ if (t2 === "resource-link") return typeof v.uri === "string";
176
1132
  return typeof v.url === "string" || typeof v.data === "string" && typeof v.mimeType === "string";
177
1133
  }
178
1134
  function aiContentUrl(part) {
@@ -276,110 +1232,91 @@ function normalizeContentParts(raw) {
276
1232
  return out;
277
1233
  }
278
1234
  function h(tag, className, text) {
1235
+ 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");
279
1236
  const node = document.createElement(tag);
280
1237
  if (className) node.className = className;
281
1238
  if (text != null) node.textContent = text;
282
1239
  return node;
283
1240
  }
284
- function svgIcon(svg2) {
285
- if (typeof document === "undefined" || typeof DOMParser === "undefined") return null;
286
- let parsed;
287
- try {
288
- parsed = new DOMParser().parseFromString(svg2, "image/svg+xml");
289
- } catch {
290
- return null;
291
- }
292
- const root = parsed.documentElement;
293
- if (!root || root.tagName.toLowerCase() !== "svg" || parsed.querySelector("parsererror")) {
294
- return null;
295
- }
296
- const sanitize = (el) => {
297
- for (const attr of Array.from(el.attributes)) {
298
- const name = attr.name.toLowerCase();
299
- if (name.startsWith("on")) el.removeAttribute(attr.name);
300
- if ((name === "href" || name === "xlink:href") && attr.value.trim().toLowerCase().startsWith("javascript:")) {
301
- el.removeAttribute(attr.name);
302
- }
303
- }
304
- for (const child of Array.from(el.children)) {
305
- const tag = child.tagName.toLowerCase();
306
- if (tag === "script" || tag === "foreignobject") {
307
- child.remove();
308
- continue;
309
- }
310
- sanitize(child);
311
- }
312
- };
313
- sanitize(root);
314
- return document.importNode(root, true);
1241
+ function svgIcon(svg) {
1242
+ return parseSvg(svg);
315
1243
  }
316
1244
 
317
- // src/behaviors/events.ts
318
- function emitIcen(source, type, detail) {
319
- return source.dispatchEvent(
320
- new CustomEvent(type, { detail, bubbles: true, composed: true, cancelable: true })
321
- );
1245
+ // src/behaviors/url-safety.ts
1246
+ function safeUrl(uri) {
1247
+ const s = uri.replace(/[\t\n\r\0-\x1f\x7f]/g, "").trim().toLowerCase();
1248
+ if (!s) return void 0;
1249
+ if (s.startsWith("javascript:") || s.startsWith("vbscript:")) return void 0;
1250
+ if (/^data:\s*text\/html/.test(s)) return void 0;
1251
+ return uri;
322
1252
  }
323
1253
 
324
1254
  // src/behaviors/ai-chat.ts
325
- function safeHref(uri) {
326
- const s = uri.trim().toLowerCase();
327
- if (s.startsWith("javascript:") || s.startsWith("data:text/html")) return void 0;
328
- return uri;
1255
+ var ICON_COPY = iconHTML("copy");
1256
+ var ICON_RETRY = iconHTML("refresh");
1257
+ var ROLE_AVATAR = {
1258
+ user: t("aiChat.roleUser"),
1259
+ assistant: "AI",
1260
+ system: t("aiChat.roleSystem"),
1261
+ tool: t("aiChat.roleTool")
1262
+ };
1263
+ function safeContentUrl(part) {
1264
+ const src = aiContentUrl(part);
1265
+ return src ? safeUrl(src) : void 0;
329
1266
  }
330
1267
  function renderAiContentPart(part) {
331
1268
  if (part.type === "text") {
332
- const span = h("span", "ai-msg-text");
1269
+ const span = h("span", "icen-ai-msg-text");
333
1270
  span.textContent = part.text;
334
1271
  if (part.state === "streaming") span.classList.add("is-streaming");
335
1272
  return span;
336
1273
  }
337
1274
  if (part.type === "image") {
338
- const src = aiContentUrl(part);
1275
+ const src = safeContentUrl(part);
339
1276
  if (!src) return void 0;
340
1277
  const img = document.createElement("img");
341
- img.className = "ai-msg-media ai-msg-media--image";
1278
+ img.className = "icen-ai-msg-media icen-ai-msg-media--image";
342
1279
  img.alt = part.alt ?? "";
343
1280
  img.setAttribute("loading", "lazy");
344
1281
  img.setAttribute("src", src);
345
1282
  return img;
346
1283
  }
347
1284
  if (part.type === "audio") {
348
- const src = aiContentUrl(part);
1285
+ const src = safeContentUrl(part);
349
1286
  if (!src) return void 0;
350
1287
  const audio = document.createElement("audio");
351
- audio.className = "ai-msg-media ai-msg-media--audio";
1288
+ audio.className = "icen-ai-msg-media icen-ai-msg-media--audio";
352
1289
  audio.controls = true;
353
1290
  audio.setAttribute("src", src);
354
1291
  return audio;
355
1292
  }
356
1293
  if (part.type === "video") {
357
- const src = aiContentUrl(part);
1294
+ const src = safeContentUrl(part);
358
1295
  if (!src) return void 0;
359
1296
  const video = document.createElement("video");
360
- video.className = "ai-msg-media ai-msg-media--video";
1297
+ video.className = "icen-ai-msg-media icen-ai-msg-media--video";
361
1298
  video.controls = true;
362
1299
  video.setAttribute("playsinline", "");
363
1300
  video.setAttribute("src", src);
364
1301
  return video;
365
1302
  }
366
1303
  if (part.type === "file") {
367
- const chip = h("span", "ai-msg-file");
368
- chip.appendChild(h("span", "ai-msg-file-name", part.filename ?? "\u6587\u4EF6"));
369
- const href2 = part.url ? safeHref(part.url) : void 0;
1304
+ const chip = h("span", "icen-ai-msg-file");
1305
+ chip.appendChild(h("span", "ai-msg-file-name", part.filename ?? t("aiChat.file")));
1306
+ const href2 = part.url ? safeUrl(part.url) : void 0;
370
1307
  if (href2 && /^(https?:|data:)/i.test(href2)) {
371
1308
  const a2 = document.createElement("a");
372
- a2.className = "ai-msg-file-link";
1309
+ a2.className = "icen-ai-msg-file-link";
373
1310
  a2.href = href2;
374
1311
  a2.download = part.filename ?? "";
375
- a2.textContent = "\u4E0B\u8F7D";
1312
+ a2.textContent = t("aiChat.download");
376
1313
  chip.appendChild(a2);
377
1314
  }
378
1315
  return chip;
379
1316
  }
380
1317
  const a = document.createElement("a");
381
- a.className = "ai-msg-link";
382
- const href = safeHref(part.uri);
1318
+ a.className = "icen-ai-msg-link";
1319
+ const href = safeUrl(part.uri);
383
1320
  if (href) a.href = href;
384
1321
  a.textContent = part.name ?? part.uri;
385
1322
  a.title = part.uri;
@@ -394,16 +1331,16 @@ function toneVar(tone = "accent") {
394
1331
  if (registered) return registered;
395
1332
  switch (tone) {
396
1333
  case "success":
397
- return "var(--token-success)";
1334
+ return "var(--icen-token-success)";
398
1335
  case "warning":
399
- return "var(--token-warning)";
1336
+ return "var(--icen-token-warning)";
400
1337
  case "error":
401
- return "var(--token-error)";
1338
+ return "var(--icen-token-error)";
402
1339
  case "muted":
403
- return "var(--token-text-faint)";
1340
+ return "var(--icen-token-text-faint)";
404
1341
  case "accent":
405
1342
  default:
406
- return "var(--token-accent)";
1343
+ return "var(--icen-token-accent)";
407
1344
  }
408
1345
  }
409
1346
  function fmt(opts, value) {
@@ -414,13 +1351,66 @@ function maxOf(values) {
414
1351
  for (const v of values) if (v > max) max = v;
415
1352
  return max;
416
1353
  }
417
- function sampleLabels(labels, max = 7) {
418
- if (labels.length <= max) return labels;
419
- const out = [];
420
- for (let i = 0; i < max; i++) {
421
- out.push(labels[Math.round(i * (labels.length - 1) / (max - 1))] ?? "");
1354
+ function pointLabelsRow(labels, width, pad) {
1355
+ const row = document.createElement("div");
1356
+ row.className = "icen-chart-labels icen-chart-labels--points";
1357
+ const count = Math.min(labels.length, Math.max(2, Math.min(7, Math.floor(width / 64))));
1358
+ const step = count > 1 ? (width - 2 * pad) / (count - 1) : width;
1359
+ for (let tick = 0; tick < count; tick++) {
1360
+ const index = count <= 1 ? 0 : Math.round(tick * (labels.length - 1) / (count - 1));
1361
+ const x = labels.length <= 1 ? width / 2 : pad + index / (labels.length - 1) * (width - 2 * pad);
1362
+ const span = document.createElement("span");
1363
+ span.textContent = labels[index] ?? "";
1364
+ span.title = span.textContent;
1365
+ span.dir = "auto";
1366
+ span.dataset.icenChartIndex = String(index);
1367
+ span.style.left = `${x / width * 100}%`;
1368
+ span.style.width = `${Math.max(0, Math.min(step * 0.9, 2 * x, 2 * (width - x)))}px`;
1369
+ row.appendChild(span);
422
1370
  }
423
- return out;
1371
+ return row;
1372
+ }
1373
+ function clampNum(v, lo, hi) {
1374
+ return Math.min(hi, Math.max(lo, v));
1375
+ }
1376
+ function lttb(points, threshold, getX, getY) {
1377
+ const len = points.length;
1378
+ const n = Math.floor(threshold);
1379
+ if (!Number.isFinite(n) || n < 3 || n >= len || len <= 3) return points;
1380
+ const sampled = new Array(n);
1381
+ sampled[0] = points[0];
1382
+ sampled[n - 1] = points[len - 1];
1383
+ const every = (len - 2) / (n - 2);
1384
+ let a = 0;
1385
+ for (let i = 0; i < n - 2; i++) {
1386
+ const avgStart = Math.floor((i + 1) * every) + 1;
1387
+ const avgEnd = Math.min(Math.floor((i + 2) * every) + 1, len);
1388
+ let avgX = 0;
1389
+ let avgY = 0;
1390
+ for (let j = avgStart; j < avgEnd; j++) {
1391
+ avgX += getX(points[j]);
1392
+ avgY += getY(points[j]);
1393
+ }
1394
+ const avgLen = Math.max(1, avgEnd - avgStart);
1395
+ avgX /= avgLen;
1396
+ avgY /= avgLen;
1397
+ const rangeStart = Math.floor(i * every) + 1;
1398
+ const rangeEnd = Math.min(Math.floor((i + 1) * every) + 1, len);
1399
+ const ax = getX(points[a]);
1400
+ const ay = getY(points[a]);
1401
+ let maxArea = -1;
1402
+ let nextA = rangeStart;
1403
+ for (let j = rangeStart; j < rangeEnd; j++) {
1404
+ const area = Math.abs((ax - avgX) * (getY(points[j]) - ay) - (ax - getX(points[j])) * (avgY - ay)) * 0.5;
1405
+ if (area > maxArea) {
1406
+ maxArea = area;
1407
+ nextA = j;
1408
+ }
1409
+ }
1410
+ sampled[i + 1] = points[nextA];
1411
+ a = nextA;
1412
+ }
1413
+ return sampled;
424
1414
  }
425
1415
  function svgEl(tag, attrs) {
426
1416
  const el = document.createElementNS(SVG_NS, tag);
@@ -429,28 +1419,28 @@ function svgEl(tag, attrs) {
429
1419
  }
430
1420
  function renderEmpty(el, label) {
431
1421
  const box = document.createElement("div");
432
- box.className = "chart-empty";
433
- box.textContent = label ?? "\u6682\u65E0\u6570\u636E";
1422
+ box.className = "icen-chart-empty";
1423
+ box.textContent = label ?? t("charts.noData");
434
1424
  el.appendChild(box);
435
1425
  }
436
1426
  function legendItem(label, valueText, tone) {
437
1427
  const row = document.createElement("div");
438
- row.className = "chart-legend-item";
1428
+ row.className = "icen-chart-legend-item";
439
1429
  const dot = document.createElement("span");
440
- dot.className = "chart-legend-dot";
1430
+ dot.className = "icen-chart-legend-dot";
441
1431
  if (tone) dot.style.setProperty("--chart-tone", toneVar(tone));
442
1432
  const name = document.createElement("span");
443
- name.className = "chart-legend-label";
1433
+ name.className = "icen-chart-legend-label";
444
1434
  name.textContent = label;
445
1435
  const val = document.createElement("span");
446
- val.className = "chart-legend-value";
1436
+ val.className = "icen-chart-legend-value";
447
1437
  val.textContent = valueText;
448
1438
  row.append(dot, name, val);
449
1439
  return row;
450
1440
  }
451
1441
  function labelsRow(labels) {
452
1442
  const row = document.createElement("div");
453
- row.className = "chart-labels";
1443
+ row.className = "icen-chart-labels";
454
1444
  for (const label of labels) {
455
1445
  const span = document.createElement("span");
456
1446
  span.textContent = label;
@@ -465,110 +1455,123 @@ function normalizeSeriesInput(opts) {
465
1455
  function toneOf(tone, seriesIndex) {
466
1456
  if (typeof tone === "string") return toneVar(tone);
467
1457
  if (typeof tone === "number") return paletteVar(tone);
468
- return seriesIndex > 0 ? paletteVar((seriesIndex - 1) % 6 + 1) : void 0;
1458
+ return seriesIndex > 0 ? paletteVar(seriesIndex % 6 + 1) : void 0;
469
1459
  }
470
1460
  var PALETTE_VARS = [
471
- "var(--token-accent)",
472
- "var(--token-accent-cold)",
473
- "var(--token-success)",
474
- "var(--token-warning)",
475
- "var(--token-info)",
476
- "color-mix(in srgb, var(--token-text) 50%, transparent)"
1461
+ "var(--icen-token-accent)",
1462
+ "var(--icen-token-accent-cold)",
1463
+ "var(--icen-token-success)",
1464
+ "var(--icen-token-warning)",
1465
+ "var(--icen-token-info)",
1466
+ "color-mix(in srgb, var(--icen-token-text) 50%, transparent)"
477
1467
  ];
478
1468
  function paletteVar(index) {
479
1469
  const i = ((Math.floor(index) - 1) % 6 + 6) % 6;
480
1470
  return PALETTE_VARS[i];
481
1471
  }
482
1472
  function setMarkData(node, data) {
483
- node.setAttribute("data-chart-mark", "1");
484
- if (data.index != null) node.setAttribute("data-chart-index", String(data.index));
485
- if (data.seriesIndex != null) node.setAttribute("data-chart-series", String(data.seriesIndex));
486
- if (data.seriesName != null) node.setAttribute("data-chart-series-name", String(data.seriesName));
487
- if (data.label != null) node.setAttribute("data-chart-label", String(data.label));
488
- if (data.value != null) node.setAttribute("data-chart-value", String(data.value));
1473
+ node.setAttribute("data-icen-chart-mark", "1");
1474
+ if (data.index != null) node.setAttribute("data-icen-chart-index", String(data.index));
1475
+ if (data.seriesIndex != null) node.setAttribute("data-icen-chart-series", String(data.seriesIndex));
1476
+ if (data.seriesName != null) node.setAttribute("data-icen-chart-series-name", String(data.seriesName));
1477
+ if (data.label != null) node.setAttribute("data-icen-chart-label", String(data.label));
1478
+ if (data.value != null) node.setAttribute("data-icen-chart-value", String(data.value));
489
1479
  }
490
1480
  function copyMarkData(target, source) {
491
1481
  for (const attr of Array.from(source.attributes)) {
492
- if (attr.name.startsWith("data-chart-")) target.setAttribute(attr.name, attr.value);
493
- }
494
- }
495
- var CHART_EYE_SVG = '<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="M2.06 12.35a1 1 0 0 1 0-.7 10.75 10.75 0 0 1 19.88 0 1 1 0 0 1 0 .7 10.75 10.75 0 0 1-19.88 0"/><circle cx="12" cy="12" r="3"/></svg>';
496
- var CHART_EYE_OFF_SVG = '<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="M10.73 5.08A10.4 10.4 0 0 1 12 5c7 0 10 7 10 7a13.2 13.2 0 0 1-1.67 2.68"/><path d="M6.61 6.61A13.5 13.5 0 0 0 2 12s3 7 10 7a9.7 9.7 0 0 0 5.39-1.61"/><path d="M2 2l20 20"/><path d="M9.9 9.9a3 3 0 0 0 4.2 4.2"/></svg>';
497
- function parseChartSvg(svg2) {
498
- try {
499
- const doc = new DOMParser().parseFromString(svg2, "image/svg+xml");
500
- const el = doc.documentElement;
501
- return el && el.tagName.toLowerCase() === "svg" && !doc.querySelector("parsererror") ? document.importNode(el, true) : null;
502
- } catch {
503
- return null;
1482
+ if (attr.name.startsWith("data-icen-chart-")) target.setAttribute(attr.name, attr.value);
504
1483
  }
505
1484
  }
506
- function withChrome(el, opts, hasLegend, paint, state) {
507
- if (el.dataset.chartBody != null) {
1485
+ function withChrome(el, opts, hasLegend, paint, state, extras) {
1486
+ if (el.dataset.icenChartBody != null) {
508
1487
  el.textContent = "";
509
1488
  paint(el);
510
1489
  return;
511
1490
  }
512
1491
  el.textContent = "";
513
1492
  const body = document.createElement("div");
514
- body.className = "chart-body";
515
- body.dataset.chartBody = "";
516
- if (!opts.title && !hasLegend) {
1493
+ body.className = "icen-chart-body";
1494
+ body.dataset.icenChartBody = "";
1495
+ const note = extras?.note ?? null;
1496
+ const onZoomReset = extras?.onZoomReset ?? null;
1497
+ if (!opts.title && !hasLegend && note == null && !onZoomReset) {
517
1498
  el.appendChild(body);
518
1499
  paint(body);
519
1500
  return;
520
1501
  }
521
1502
  let hidden = state && state.hidden != null ? state.hidden : opts.legend === false;
522
1503
  if (state) state.hidden = hidden;
523
- el.setAttribute("data-legend-hidden", String(hidden));
1504
+ el.setAttribute("data-icen-legend-hidden", String(hidden));
524
1505
  const head = document.createElement("div");
525
- head.className = "chart-head";
1506
+ head.className = "icen-chart-head";
526
1507
  const title = document.createElement("div");
527
- title.className = "chart-title";
1508
+ title.className = "icen-chart-title";
528
1509
  title.textContent = opts.title ?? "";
529
1510
  if (!opts.title) title.setAttribute("aria-hidden", "true");
1511
+ if (note != null) {
1512
+ const noteEl = document.createElement("span");
1513
+ noteEl.className = "icen-chart-note";
1514
+ noteEl.textContent = note;
1515
+ head.appendChild(noteEl);
1516
+ }
1517
+ if (onZoomReset) {
1518
+ const chip = document.createElement("button");
1519
+ chip.type = "button";
1520
+ chip.className = "icen-chart-zoom-reset";
1521
+ chip.textContent = t("charts.resetZoom");
1522
+ chip.addEventListener("click", onZoomReset);
1523
+ head.appendChild(chip);
1524
+ }
530
1525
  const eye = document.createElement("button");
531
1526
  eye.type = "button";
532
- eye.className = "chart-legend-eye";
533
- eye.dataset.chartLegendEye = "";
1527
+ eye.className = "icen-chart-legend-eye";
1528
+ eye.dataset.icenChartLegendEye = "";
534
1529
  const syncEye = () => {
535
- const nowHidden = el.getAttribute("data-legend-hidden") === "true";
1530
+ const nowHidden = el.getAttribute("data-icen-legend-hidden") === "true";
536
1531
  eye.setAttribute("aria-pressed", String(!nowHidden));
537
- eye.setAttribute("aria-label", nowHidden ? "\u663E\u793A\u56FE\u4F8B" : "\u9690\u85CF\u56FE\u4F8B");
538
- eye.setAttribute("title", nowHidden ? "\u663E\u793A\u56FE\u4F8B" : "\u9690\u85CF\u56FE\u4F8B");
539
- const icon = parseChartSvg(nowHidden ? CHART_EYE_OFF_SVG : CHART_EYE_SVG);
1532
+ eye.setAttribute("aria-label", nowHidden ? t("charts.showLegend") : t("charts.hideLegend"));
1533
+ eye.setAttribute("title", nowHidden ? t("charts.showLegend") : t("charts.hideLegend"));
1534
+ const icon = createIcon(nowHidden ? "eye-off" : "eye");
540
1535
  if (icon) eye.replaceChildren(icon);
541
1536
  };
542
1537
  eye.addEventListener("click", () => {
543
- const nowHidden = el.getAttribute("data-legend-hidden") === "true";
1538
+ const nowHidden = el.getAttribute("data-icen-legend-hidden") === "true";
544
1539
  hidden = !nowHidden;
545
1540
  if (state) state.hidden = hidden;
546
- el.setAttribute("data-legend-hidden", String(hidden));
1541
+ el.setAttribute("data-icen-legend-hidden", String(hidden));
547
1542
  syncEye();
548
1543
  emitIcen(el, "icen:chart-legend-visibility", { visible: hidden ? false : true });
549
1544
  });
550
1545
  syncEye();
551
- head.append(title, eye);
1546
+ if (hasLegend) head.append(title, eye);
1547
+ else head.append(title);
552
1548
  el.append(head, body);
553
1549
  paint(body);
554
1550
  }
1551
+ var hiddenLegendKeys = /* @__PURE__ */ new WeakMap();
555
1552
  function toggleLegend(items, scope) {
556
1553
  const legend = document.createElement("div");
557
- legend.className = "chart-legend chart-legend--toggle";
1554
+ legend.className = "icen-chart-legend icen-chart-legend--toggle";
1555
+ const owner = scope instanceof Element ? scope.closest("[data-icen-chart-body]")?.parentElement ?? scope : null;
1556
+ const hidden = owner ? hiddenLegendKeys.get(owner) ?? /* @__PURE__ */ new Set() : /* @__PURE__ */ new Set();
1557
+ if (owner) hiddenLegendKeys.set(owner, hidden);
558
1558
  for (const item of items) {
559
1559
  const row = legendItem(item.label, "", item.tone);
560
- row.classList.add("chart-legend-toggle-item");
1560
+ row.classList.add("icen-chart-legend-toggle-item");
561
1561
  row.setAttribute("role", "button");
562
1562
  row.tabIndex = 0;
563
- row.setAttribute("aria-pressed", "true");
564
- row.dataset.chartKey = item.key;
565
- const dot = row.querySelector(".chart-legend-dot");
566
- const toneColor = toneOf(item.tone, item.si + 1);
1563
+ row.classList.toggle("is-off", hidden.has(item.key));
1564
+ row.setAttribute("aria-pressed", String(!hidden.has(item.key)));
1565
+ row.dataset.icenChartKey = item.key;
1566
+ const dot = row.querySelector(".icen-chart-legend-dot");
1567
+ const toneColor = toneOf(item.tone, item.si);
567
1568
  if (dot && toneColor) dot.style.setProperty("--chart-tone", toneColor);
568
1569
  const toggle = () => {
569
1570
  const off = row.classList.toggle("is-off");
1571
+ if (off) hidden.add(item.key);
1572
+ else hidden.delete(item.key);
570
1573
  row.setAttribute("aria-pressed", String(!off));
571
- scope.querySelectorAll(`[data-chart-key="${CSS.escape(item.key)}"]`).forEach((m) => {
1574
+ scope.querySelectorAll(`[data-icen-chart-key="${CSS.escape(item.key)}"]`).forEach((m) => {
572
1575
  m.classList.toggle("is-off", off);
573
1576
  });
574
1577
  emitIcen(legend, "icen:chart-legend-toggle", { key: item.key, seriesIndex: item.si, hidden: off });
@@ -583,8 +1586,9 @@ function toggleLegend(items, scope) {
583
1586
  legend.appendChild(row);
584
1587
  }
585
1588
  for (const item of items) {
586
- scope.querySelectorAll(`[data-chart-series="${item.si}"]`).forEach((m) => {
587
- if (!m.hasAttribute("data-chart-key")) m.setAttribute("data-chart-key", item.key);
1589
+ scope.querySelectorAll(`[data-icen-chart-series="${item.si}"]`).forEach((m) => {
1590
+ if (!m.hasAttribute("data-icen-chart-key")) m.setAttribute("data-icen-chart-key", item.key);
1591
+ m.classList.toggle("is-off", hidden.has(item.key));
588
1592
  });
589
1593
  }
590
1594
  return legend;
@@ -611,19 +1615,19 @@ function renderVBar(el, opts) {
611
1615
  for (const s of seriesList) max = Math.max(max, maxOf(s.values.slice(0, n)));
612
1616
  }
613
1617
  const wrap = document.createElement("div");
614
- wrap.className = "chart-vbar";
1618
+ wrap.className = "icen-chart-vbar";
615
1619
  if (opts.tone) wrap.style.setProperty("--chart-tone", toneVar(opts.tone));
616
1620
  for (let i = 0; i < n; i++) {
617
1621
  const track = document.createElement("div");
618
- track.className = "chart-vbar-track";
1622
+ track.className = "icen-chart-vbar-track";
619
1623
  if (seriesList.length > 1) {
620
- track.classList.add("chart-vbar-track--multi");
621
- if (opts.stacked) track.classList.add("chart-vbar-track--stacked");
1624
+ track.classList.add("icen-chart-vbar-track--multi");
1625
+ if (opts.stacked) track.classList.add("icen-chart-vbar-track--stacked");
622
1626
  }
623
1627
  seriesList.forEach((s, si) => {
624
1628
  const value = s.values[i] ?? 0;
625
1629
  const bar = document.createElement("div");
626
- bar.className = "chart-vbar-bar";
1630
+ bar.className = "icen-chart-vbar-bar";
627
1631
  const height = value > 0 ? Math.max(6, value / max * 100) : 0;
628
1632
  bar.style.height = `${height}%`;
629
1633
  const toneColor = toneOf(s.tone, si);
@@ -641,7 +1645,7 @@ function renderVBar(el, opts) {
641
1645
  wrap.appendChild(track);
642
1646
  }
643
1647
  body.append(wrap, labelsRow(labelsUsed));
644
- if (seriesList.length > 1) body.appendChild(toggleLegend(seriesList.map((s, si) => ({ key: s.name, label: s.name, tone: s.tone, si })), wrap));
1648
+ if (seriesList.length > 1) body.appendChild(toggleLegend(seriesList.map((s, si) => ({ key: `${si}:${s.name}`, label: s.name, tone: s.tone ?? (si === 0 ? opts.tone : void 0), si })), wrap));
645
1649
  });
646
1650
  attachChartInteraction(el, "vbar");
647
1651
  return el;
@@ -658,22 +1662,22 @@ function renderHBar(el, opts) {
658
1662
  const values = opts.values.slice(0, n);
659
1663
  const max = maxOf(values);
660
1664
  const wrap = document.createElement("div");
661
- wrap.className = "chart-hbar";
1665
+ wrap.className = "icen-chart-hbar";
662
1666
  if (opts.tone) wrap.style.setProperty("--chart-tone", toneVar(opts.tone));
663
1667
  values.forEach((value, i) => {
664
1668
  const row = document.createElement("div");
665
- row.className = "chart-hbar-row";
1669
+ row.className = "icen-chart-hbar-row";
666
1670
  const label = document.createElement("span");
667
- label.className = "chart-hbar-label";
1671
+ label.className = "icen-chart-hbar-label";
668
1672
  label.textContent = labels[i] ?? "";
669
1673
  const track = document.createElement("div");
670
- track.className = "chart-hbar-track";
1674
+ track.className = "icen-chart-hbar-track";
671
1675
  const bar = document.createElement("div");
672
- bar.className = "chart-hbar-bar";
1676
+ bar.className = "icen-chart-hbar-bar";
673
1677
  bar.style.width = value > 0 ? `${Math.max(2, value / max * 100)}%` : "0%";
674
1678
  setMarkData(bar, { index: i, label: labels[i] ?? "", value });
675
1679
  const val = document.createElement("span");
676
- val.className = "chart-hbar-value";
1680
+ val.className = "icen-chart-hbar-value";
677
1681
  val.textContent = fmt(opts, value);
678
1682
  track.appendChild(bar);
679
1683
  row.append(label, track, val);
@@ -693,10 +1697,10 @@ function renderStack(el, opts) {
693
1697
  return;
694
1698
  }
695
1699
  const bar = document.createElement("div");
696
- bar.className = "chart-stack";
1700
+ bar.className = "icen-chart-stack";
697
1701
  for (const [segIndex, seg] of opts.segments.entries()) {
698
1702
  const s = document.createElement("div");
699
- s.className = "chart-stack-seg";
1703
+ s.className = "icen-chart-stack-seg";
700
1704
  s.style.width = `${seg.value / total * 100}%`;
701
1705
  if (seg.tone) s.style.setProperty("--chart-tone", toneVar(seg.tone));
702
1706
  s.setAttribute("title", `${seg.label}: ${fmt(opts, seg.value)}`);
@@ -704,7 +1708,7 @@ function renderStack(el, opts) {
704
1708
  bar.appendChild(s);
705
1709
  }
706
1710
  const legend = document.createElement("div");
707
- legend.className = "chart-legend";
1711
+ legend.className = "icen-chart-legend";
708
1712
  for (const seg of opts.segments) {
709
1713
  legend.appendChild(legendItem(seg.label, fmt(opts, seg.value), seg.tone));
710
1714
  }
@@ -724,20 +1728,22 @@ function renderDonut(el, opts) {
724
1728
  const radius = 42;
725
1729
  const circumference = 2 * Math.PI * radius;
726
1730
  const wrap = document.createElement("div");
727
- wrap.className = "chart-donut";
728
- const svg2 = svgEl("svg", { viewBox: "0 0 120 120", role: "img" });
729
- svg2.style.transform = "rotate(-90deg)";
730
- svg2.appendChild(svgEl("circle", {
1731
+ wrap.className = "icen-chart-donut";
1732
+ const svg = svgEl("svg", { viewBox: "0 0 120 120", role: "img", "aria-label": chartAriaLabel(opts.title, t("charts.type.donut")) });
1733
+ svg.style.transform = "rotate(-90deg)";
1734
+ svg.appendChild(svgEl("circle", {
731
1735
  cx: "60",
732
1736
  cy: "60",
733
1737
  r: String(radius),
734
1738
  fill: "none",
735
- stroke: "var(--token-line-soft)",
1739
+ stroke: "var(--icen-token-line-soft)",
736
1740
  "stroke-width": "14"
737
1741
  }));
738
1742
  let offset = 0;
1743
+ const gap = opts.segments.length > 1 ? 2.5 : 0;
739
1744
  opts.segments.forEach((seg, segIndex) => {
740
- const dash = seg.value / total * circumference;
1745
+ const arcLength = Math.max(0, seg.value / total * circumference);
1746
+ const dash = arcLength - Math.min(gap, arcLength * 0.1);
741
1747
  const arc = svgEl("circle", {
742
1748
  cx: "60",
743
1749
  cy: "60",
@@ -750,15 +1756,15 @@ function renderDonut(el, opts) {
750
1756
  "stroke-linecap": "butt"
751
1757
  });
752
1758
  setMarkData(arc, { index: segIndex, label: seg.label, value: seg.value });
753
- svg2.appendChild(arc);
754
- offset += dash;
1759
+ svg.appendChild(arc);
1760
+ offset += arcLength;
755
1761
  });
756
1762
  const legend = document.createElement("div");
757
- legend.className = "chart-legend";
1763
+ legend.className = "icen-chart-legend";
758
1764
  for (const seg of opts.segments) {
759
1765
  legend.appendChild(legendItem(seg.label, `${Math.round(seg.value / total * 100)}%`, seg.tone));
760
1766
  }
761
- wrap.append(svg2, legend);
1767
+ wrap.append(svg, legend);
762
1768
  body.appendChild(wrap);
763
1769
  });
764
1770
  attachChartInteraction(el, "donut");
@@ -776,23 +1782,24 @@ function renderLine(el, opts) {
776
1782
  return;
777
1783
  }
778
1784
  const labelsUsed = labels.slice(0, n);
779
- const width = 360;
1785
+ const width = fluidWidth(body);
780
1786
  const height = 150;
781
1787
  const pad = 14;
782
1788
  let max = 1;
783
1789
  for (const s of seriesList) max = Math.max(max, maxOf(s.values.slice(0, n)));
784
1790
  const wrap = document.createElement("div");
785
- wrap.className = "chart-line";
786
- const svg2 = svgEl("svg", { viewBox: `0 0 ${width} ${height}`, role: "img" });
1791
+ wrap.className = "icen-chart-line";
1792
+ const svg = svgEl("svg", { viewBox: `0 0 ${width} ${height}`, role: "img", "aria-label": chartAriaLabel(opts.title, t("charts.type.line")) });
787
1793
  const defs = svgEl("defs", {});
788
1794
  for (let i = 0; i < 4; i++) {
789
- const y = pad + i * (height - pad * 2) / 3;
790
- svg2.appendChild(svgEl("line", {
1795
+ const y = Math.round(pad + i * (height - pad * 2) / 3) + 0.5;
1796
+ svg.appendChild(svgEl("line", {
1797
+ class: i === 3 ? "icen-chart-grid icen-chart-baseline" : "icen-chart-grid",
791
1798
  x1: String(pad),
792
1799
  x2: String(width - pad),
793
1800
  y1: String(y),
794
1801
  y2: String(y),
795
- stroke: "var(--token-line-soft)",
1802
+ stroke: "var(--icen-token-line-soft)",
796
1803
  "stroke-width": "1"
797
1804
  }));
798
1805
  }
@@ -822,7 +1829,7 @@ function renderLine(el, opts) {
822
1829
  if (seriesList.length > 1) {
823
1830
  setMarkData(areaPath, { seriesIndex: si, seriesName: s.name, label: s.name, value: values.reduce((a, b) => a + b, 0) });
824
1831
  }
825
- svg2.appendChild(areaPath);
1832
+ svg.appendChild(areaPath);
826
1833
  }
827
1834
  const linePath = svgEl("path", {
828
1835
  d: line,
@@ -833,16 +1840,16 @@ function renderLine(el, opts) {
833
1840
  "stroke-linejoin": "round"
834
1841
  });
835
1842
  const lineTitle = svgEl("title", {});
836
- lineTitle.textContent = s.name || "\u6570\u503C";
1843
+ lineTitle.textContent = s.name || t("charts.value");
837
1844
  linePath.appendChild(lineTitle);
838
1845
  setMarkData(linePath, { seriesIndex: si, seriesName: s.name, label: s.name, value: values[values.length - 1] ?? 0 });
839
- svg2.appendChild(linePath);
1846
+ svg.appendChild(linePath);
840
1847
  for (const p of points) {
841
1848
  const dot = svgEl("circle", {
842
1849
  cx: p.x.toFixed(1),
843
1850
  cy: p.y.toFixed(1),
844
1851
  r: "3",
845
- fill: "var(--token-card)",
1852
+ fill: "var(--icen-token-card)",
846
1853
  stroke: tone,
847
1854
  "stroke-width": "2"
848
1855
  });
@@ -856,23 +1863,24 @@ function renderLine(el, opts) {
856
1863
  label: p.label,
857
1864
  value: p.value
858
1865
  });
859
- svg2.appendChild(dot);
1866
+ svg.appendChild(dot);
860
1867
  const hit = svgEl("circle", {
861
1868
  cx: p.x.toFixed(1),
862
1869
  cy: p.y.toFixed(1),
863
1870
  r: "8",
864
1871
  fill: "transparent",
865
- "data-chart-hit": "1"
1872
+ "data-icen-chart-hit": "1"
866
1873
  });
867
1874
  copyMarkData(hit, dot);
868
- svg2.appendChild(hit);
1875
+ svg.appendChild(hit);
869
1876
  }
870
1877
  });
871
- if (defs.firstChild) svg2.insertBefore(defs, svg2.firstChild);
872
- wrap.append(svg2, labelsRow(sampleLabels(labelsUsed)));
1878
+ if (defs.firstChild) svg.insertBefore(defs, svg.firstChild);
1879
+ wrap.append(svg, pointLabelsRow(labelsUsed, width, pad));
873
1880
  body.appendChild(wrap);
874
- if (seriesList.length > 1) body.appendChild(toggleLegend(seriesList.map((s, si) => ({ key: s.name, label: s.name, tone: s.tone, si })), wrap));
1881
+ if (seriesList.length > 1) body.appendChild(toggleLegend(seriesList.map((s, si) => ({ key: `${si}:${s.name}`, label: s.name, tone: s.tone ?? (si === 0 ? opts.tone : void 0), si })), wrap));
875
1882
  });
1883
+ if (el.dataset.icenChartBody == null) observeFluidWidth(el, () => renderLine(el, opts));
876
1884
  attachChartInteraction(el, "line");
877
1885
  return el;
878
1886
  }
@@ -904,30 +1912,30 @@ function renderRadar(el, opts) {
904
1912
  y: cy + r * Math.sin(angleOf(i))
905
1913
  });
906
1914
  const wrap = document.createElement("div");
907
- wrap.className = "chart-radar";
908
- const svg2 = svgEl("svg", { viewBox: `0 0 ${size} ${size}`, role: "img" });
1915
+ wrap.className = "icen-chart-radar";
1916
+ const svg = svgEl("svg", { viewBox: `0 0 ${size} ${size}`, role: "img", "aria-label": chartAriaLabel(opts.title, t("charts.type.radar")) });
909
1917
  for (let lv = 1; lv <= levels; lv++) {
910
1918
  const r = radius * lv / levels;
911
1919
  const pts = Array.from({ length: n }, (_, i) => {
912
1920
  const p = pointAt(i, r);
913
1921
  return `${p.x.toFixed(1)},${p.y.toFixed(1)}`;
914
1922
  }).join(" ");
915
- svg2.appendChild(svgEl("polygon", {
1923
+ svg.appendChild(svgEl("polygon", {
916
1924
  points: pts,
917
1925
  fill: "none",
918
- stroke: "var(--token-line-soft)",
1926
+ stroke: "var(--icen-token-line-soft)",
919
1927
  "stroke-width": "1",
920
1928
  "stroke-dasharray": lv === levels ? "0" : "3 2"
921
1929
  }));
922
1930
  }
923
1931
  for (let i = 0; i < n; i++) {
924
1932
  const edge = pointAt(i, radius);
925
- svg2.appendChild(svgEl("line", {
1933
+ svg.appendChild(svgEl("line", {
926
1934
  x1: String(cx),
927
1935
  y1: String(cy),
928
1936
  x2: edge.x.toFixed(1),
929
1937
  y2: edge.y.toFixed(1),
930
- stroke: "var(--token-line-soft)",
1938
+ stroke: "var(--icen-token-line-soft)",
931
1939
  "stroke-width": "1"
932
1940
  }));
933
1941
  const labelP = pointAt(i, radius + 14);
@@ -937,14 +1945,14 @@ function renderRadar(el, opts) {
937
1945
  "text-anchor": "middle",
938
1946
  "dominant-baseline": "middle",
939
1947
  "font-size": "9",
940
- fill: "var(--token-text-muted)"
1948
+ fill: "var(--icen-token-text-muted)"
941
1949
  });
942
1950
  txt.textContent = axes[i] ?? "";
943
- svg2.appendChild(txt);
1951
+ svg.appendChild(txt);
944
1952
  }
945
1953
  const legendItems = [];
946
1954
  opts.series.forEach((s, si) => {
947
- const tone = toneVar(s.tone);
1955
+ const tone = toneOf(s.tone, si) ?? toneVar(s.tone);
948
1956
  const pts = Array.from({ length: n }, (_, i) => {
949
1957
  const v = Math.max(0, Math.min(maxVal, s.values[i] ?? 0));
950
1958
  const p = pointAt(i, v / maxVal * radius);
@@ -962,7 +1970,7 @@ function renderRadar(el, opts) {
962
1970
  title.textContent = `${s.name}: ${s.values.map((v) => fmt(opts, v)).join(" / ")}`;
963
1971
  polyFill.appendChild(title);
964
1972
  setMarkData(polyFill, { seriesIndex: si, seriesName: s.name || void 0, label: s.name, value: s.values.reduce((a, b) => a + (b || 0), 0) });
965
- svg2.appendChild(polyFill);
1973
+ svg.appendChild(polyFill);
966
1974
  for (let i = 0; i < n; i++) {
967
1975
  const v = Math.max(0, Math.min(maxVal, s.values[i] ?? 0));
968
1976
  const p = pointAt(i, v / maxVal * radius);
@@ -970,18 +1978,19 @@ function renderRadar(el, opts) {
970
1978
  cx: p.x.toFixed(1),
971
1979
  cy: p.y.toFixed(1),
972
1980
  r: "2.5",
973
- fill: "var(--token-card)",
1981
+ fill: "var(--icen-token-card)",
974
1982
  stroke: tone,
975
1983
  "stroke-width": "1.5"
976
1984
  });
977
1985
  setMarkData(dot, { index: i, seriesIndex: si, seriesName: s.name || void 0, label: axes[i] ?? "", value: s.values[i] ?? 0 });
978
- svg2.appendChild(dot);
1986
+ svg.appendChild(dot);
979
1987
  }
980
- legendItems.push({ key: s.name || `\u7CFB\u5217${si + 1}`, label: s.name || `\u7CFB\u5217${si + 1}`, tone: s.tone, si });
1988
+ legendItems.push({ key: `${si}:${s.name || t("charts.seriesName", { p0: si + 1 })}`, label: s.name || t("charts.seriesName", { p0: si + 1 }), tone: s.tone, si });
981
1989
  });
982
- const legend = opts.series.length > 1 ? toggleLegend(legendItems, wrap) : null;
983
- wrap.append(svg2, ...legend ? [legend] : []);
1990
+ wrap.appendChild(svg);
984
1991
  body.appendChild(wrap);
1992
+ const legend = opts.series.length > 1 ? toggleLegend(legendItems, wrap) : null;
1993
+ if (legend) wrap.appendChild(legend);
985
1994
  });
986
1995
  attachChartInteraction(el, "radar");
987
1996
  return el;
@@ -998,6 +2007,11 @@ function niceCeil(v) {
998
2007
  else nice = 10;
999
2008
  return nice * base;
1000
2009
  }
2010
+ function tickPrecision(min, max, steps) {
2011
+ const span = Math.abs(max - min);
2012
+ if (!Number.isFinite(span) || span <= 0) return 0;
2013
+ return Math.max(0, Math.ceil(-Math.log10(span / steps)));
2014
+ }
1001
2015
  function isoDate(d) {
1002
2016
  const m = String(d.getMonth() + 1).padStart(2, "0");
1003
2017
  const day = String(d.getDate()).padStart(2, "0");
@@ -1014,23 +2028,23 @@ function padFirstWeek(grid, firstDate, weekStart) {
1014
2028
  const pad = (first.getDay() + 7 - weekStart) % 7;
1015
2029
  for (let i = 0; i < pad; i++) {
1016
2030
  const blank = document.createElement("span");
1017
- blank.className = "chart-heatmap-cell is-blank";
2031
+ blank.className = "icen-chart-heatmap-cell is-blank";
1018
2032
  grid.appendChild(blank);
1019
2033
  }
1020
2034
  return pad;
1021
2035
  }
1022
2036
  function heatmapLegend(labels) {
1023
2037
  const legend = document.createElement("div");
1024
- legend.className = "chart-heatmap-legend";
2038
+ legend.className = "icen-chart-heatmap-legend";
1025
2039
  const less = document.createElement("span");
1026
- less.textContent = labels?.less ?? "\u5C11";
2040
+ less.textContent = labels?.less ?? t("charts.few");
1027
2041
  const more = document.createElement("span");
1028
- more.textContent = labels?.more ?? "\u591A";
2042
+ more.textContent = labels?.more ?? t("charts.many");
1029
2043
  legend.appendChild(less);
1030
2044
  for (let lv = 0; lv <= 4; lv++) {
1031
2045
  const cell = document.createElement("span");
1032
- cell.className = "chart-heatmap-cell";
1033
- cell.dataset.level = String(lv);
2046
+ cell.className = "icen-chart-heatmap-cell";
2047
+ cell.dataset.icenLevel = String(lv);
1034
2048
  legend.appendChild(cell);
1035
2049
  }
1036
2050
  legend.appendChild(more);
@@ -1057,16 +2071,17 @@ function renderHeatmap(el, opts) {
1057
2071
  if (entries.length > weeks * 7) entries = entries.slice(entries.length - weeks * 7);
1058
2072
  const max = maxOf(entries.map((e) => e.value));
1059
2073
  const wrap = document.createElement("div");
1060
- wrap.className = "chart-heatmap";
2074
+ wrap.className = "icen-chart-heatmap";
1061
2075
  if (opts.tone) wrap.style.setProperty("--chart-tone", toneVar(opts.tone));
1062
2076
  const grid = document.createElement("div");
1063
- grid.className = "chart-heatmap-grid";
2077
+ grid.className = "icen-chart-heatmap-grid";
1064
2078
  grid.setAttribute("role", "img");
2079
+ grid.setAttribute("aria-label", chartAriaLabel(opts.title, t("charts.type.heatmap")));
1065
2080
  padFirstWeek(grid, entries[0].date, opts.weekStart === 0 ? 0 : 1);
1066
2081
  for (const [i, entry] of entries.entries()) {
1067
2082
  const cell = document.createElement("span");
1068
- cell.className = "chart-heatmap-cell";
1069
- cell.dataset.level = String(levelOf(entry.value, max));
2083
+ cell.className = "icen-chart-heatmap-cell";
2084
+ cell.dataset.icenLevel = String(levelOf(entry.value, max));
1070
2085
  cell.setAttribute("title", `${entry.date}\uFF1A${fmt(opts, entry.value)}`);
1071
2086
  setMarkData(cell, { index: i, label: entry.date, value: entry.value });
1072
2087
  grid.appendChild(cell);
@@ -1092,7 +2107,8 @@ function renderSparkline(el, opts) {
1092
2107
  const tone = toneVar(opts.tone);
1093
2108
  const points = values.map((value, i) => ({
1094
2109
  x: values.length <= 1 ? width / 2 : pad + i / (values.length - 1) * (width - pad * 2),
1095
- y: height - pad - value / max * (height - pad * 2),
2110
+ /* 负值钳到基线(与折线图同口径):viewBox 仅 28 高,反向射出更刺眼 */
2111
+ y: height - pad - Math.max(0, value) / max * (height - pad * 2),
1096
2112
  value
1097
2113
  }));
1098
2114
  const line = points.map((p, i) => `${i === 0 ? "M" : "L"}${p.x.toFixed(1)},${p.y.toFixed(1)}`).join(" ");
@@ -1101,16 +2117,16 @@ function renderSparkline(el, opts) {
1101
2117
  const area = `${line} L${last.x.toFixed(1)},${height - pad} L${first.x.toFixed(1)},${height - pad} Z`;
1102
2118
  const gradientId = `icen-chart-line-${++lineGradientSeq}`;
1103
2119
  const wrap = document.createElement("div");
1104
- wrap.className = "chart-sparkline";
1105
- const svg2 = svgEl("svg", { viewBox: `0 0 ${width} ${height}`, role: "img" });
2120
+ wrap.className = "icen-chart-sparkline";
2121
+ const svg = svgEl("svg", { viewBox: `0 0 ${width} ${height}`, role: "img", "aria-label": chartAriaLabel(opts.title, t("charts.type.sparkline")) });
1106
2122
  const defs = svgEl("defs", {});
1107
2123
  const gradient = svgEl("linearGradient", { id: gradientId, x1: "0", x2: "0", y1: "0", y2: "1" });
1108
2124
  gradient.appendChild(svgEl("stop", { offset: "0%", "stop-color": tone, "stop-opacity": "0.28" }));
1109
2125
  gradient.appendChild(svgEl("stop", { offset: "100%", "stop-color": tone, "stop-opacity": "0.02" }));
1110
2126
  defs.appendChild(gradient);
1111
- svg2.appendChild(defs);
1112
- svg2.appendChild(svgEl("path", { d: area, fill: `url(#${gradientId})` }));
1113
- svg2.appendChild(svgEl("path", {
2127
+ svg.appendChild(defs);
2128
+ svg.appendChild(svgEl("path", { d: area, fill: `url(#${gradientId})` }));
2129
+ svg.appendChild(svgEl("path", {
1114
2130
  d: line,
1115
2131
  fill: "none",
1116
2132
  stroke: tone,
@@ -1122,15 +2138,15 @@ function renderSparkline(el, opts) {
1122
2138
  cx: last.x.toFixed(1),
1123
2139
  cy: last.y.toFixed(1),
1124
2140
  r: "2.4",
1125
- fill: "var(--token-card)",
2141
+ fill: "var(--icen-token-card)",
1126
2142
  stroke: tone,
1127
2143
  "stroke-width": "1.6"
1128
2144
  });
1129
2145
  const title = svgEl("title", {});
1130
2146
  title.textContent = fmt(opts, last.value);
1131
2147
  dot.appendChild(title);
1132
- svg2.appendChild(dot);
1133
- wrap.appendChild(svg2);
2148
+ svg.appendChild(dot);
2149
+ wrap.appendChild(svg);
1134
2150
  body.appendChild(wrap);
1135
2151
  });
1136
2152
  attachChartInteraction(el, "sparkline");
@@ -1144,20 +2160,20 @@ function renderGauge(el, opts) {
1144
2160
  const radius = 42;
1145
2161
  const circumference = 2 * Math.PI * radius;
1146
2162
  const wrap = document.createElement("div");
1147
- wrap.className = "chart-gauge";
2163
+ wrap.className = "icen-chart-gauge";
1148
2164
  if (opts.tone) wrap.style.setProperty("--chart-tone", toneVar(opts.tone));
1149
- const svg2 = svgEl("svg", { viewBox: "0 0 120 120", role: "img" });
1150
- svg2.style.transform = "rotate(-90deg)";
1151
- svg2.appendChild(svgEl("circle", {
2165
+ const svg = svgEl("svg", { viewBox: "0 0 120 120", role: "img", "aria-label": chartAriaLabel(opts.label, t("charts.type.gauge")) });
2166
+ svg.style.transform = "rotate(-90deg)";
2167
+ svg.appendChild(svgEl("circle", {
1152
2168
  cx: "60",
1153
2169
  cy: "60",
1154
2170
  r: String(radius),
1155
2171
  fill: "none",
1156
- stroke: "var(--token-line-soft)",
2172
+ stroke: "var(--icen-token-line-soft)",
1157
2173
  "stroke-width": "10"
1158
2174
  }));
1159
2175
  const dash = ratio * circumference;
1160
- svg2.appendChild(svgEl("circle", {
2176
+ svg.appendChild(svgEl("circle", {
1161
2177
  cx: "60",
1162
2178
  cy: "60",
1163
2179
  r: String(radius),
@@ -1168,18 +2184,18 @@ function renderGauge(el, opts) {
1168
2184
  "stroke-linecap": "round"
1169
2185
  }));
1170
2186
  const center = document.createElement("div");
1171
- center.className = "chart-gauge-center";
2187
+ center.className = "icen-chart-gauge-center";
1172
2188
  const val = document.createElement("span");
1173
- val.className = "chart-gauge-value";
2189
+ val.className = "icen-chart-gauge-value";
1174
2190
  val.textContent = opts.formatValue ? opts.formatValue(opts.value) : `${Math.round(ratio * 100)}%`;
1175
2191
  center.appendChild(val);
1176
2192
  if (opts.label) {
1177
2193
  const lab = document.createElement("span");
1178
- lab.className = "chart-gauge-label";
2194
+ lab.className = "icen-chart-gauge-label";
1179
2195
  lab.textContent = opts.label;
1180
2196
  center.appendChild(lab);
1181
2197
  }
1182
- wrap.append(svg2, center);
2198
+ wrap.append(svg, center);
1183
2199
  el.appendChild(wrap);
1184
2200
  attachChartInteraction(el, "gauge");
1185
2201
  return el;
@@ -1197,25 +2213,27 @@ function renderCalendar(el, opts) {
1197
2213
  return;
1198
2214
  }
1199
2215
  const wrap = document.createElement("div");
1200
- wrap.className = "chart-calendar";
2216
+ wrap.className = "icen-chart-calendar";
1201
2217
  if (opts.tone) wrap.style.setProperty("--chart-tone", toneVar(opts.tone));
1202
2218
  const weekStart = opts.weekStart === 0 ? 0 : 1;
1203
- const weekdayDefaults = ["\u4E00", "", "\u4E09", "", "\u4E94", "", "\u65E5"];
2219
+ const weekdayDefaults = t("charts.calendarWeekdays");
1204
2220
  const weekdayLabels = opts.labels?.weekdays ?? weekdayDefaults.map((_, i) => weekdayLabelAt(weekdayDefaults, (weekStart + i) % 7));
1205
- const monthLabel = (m) => opts.labels?.months?.[m] ?? `${m + 1}\u6708`;
2221
+ const monthLabel = (m) => opts.labels?.months?.[m] ?? t("charts.monthLabel", { p0: m + 1 });
1206
2222
  const grid = document.createElement("div");
1207
- grid.className = "chart-heatmap-grid";
2223
+ grid.className = "icen-chart-heatmap-grid";
1208
2224
  grid.setAttribute("role", "img");
2225
+ grid.setAttribute("aria-label", chartAriaLabel(opts.title, t("charts.type.heatmap")));
1209
2226
  const months = document.createElement("div");
1210
- months.className = "chart-calendar-months";
2227
+ months.className = "icen-chart-calendar-months";
1211
2228
  const weekdayRow = document.createElement("div");
1212
- weekdayRow.className = "chart-calendar-weekdays";
2229
+ weekdayRow.className = "icen-chart-calendar-weekdays";
1213
2230
  weekdayLabels.forEach((w) => {
1214
2231
  const s = document.createElement("span");
1215
2232
  s.textContent = w;
1216
2233
  weekdayRow.appendChild(s);
1217
2234
  });
1218
2235
  const max = maxOf(entries.map((e) => e.value));
2236
+ entries.sort((a, b) => a.date.localeCompare(b.date));
1219
2237
  const pad = padFirstWeek(grid, entries[0].date, weekStart);
1220
2238
  let lastMonth = -1;
1221
2239
  entries.forEach((entry, i) => {
@@ -1224,14 +2242,14 @@ function renderCalendar(el, opts) {
1224
2242
  if (d.getMonth() !== lastMonth) {
1225
2243
  lastMonth = d.getMonth();
1226
2244
  const label = document.createElement("span");
1227
- label.className = "chart-calendar-month";
2245
+ label.className = "icen-chart-calendar-month";
1228
2246
  label.textContent = monthLabel(d.getMonth());
1229
2247
  label.style.setProperty("--col", String(col));
1230
2248
  months.appendChild(label);
1231
2249
  }
1232
2250
  const cell = document.createElement("span");
1233
- cell.className = "chart-heatmap-cell";
1234
- cell.dataset.level = String(levelOf(entry.value, max));
2251
+ cell.className = "icen-chart-heatmap-cell";
2252
+ cell.dataset.icenLevel = String(levelOf(entry.value, max));
1235
2253
  cell.setAttribute("title", `${entry.date}\uFF1A${fmt(opts, entry.value)}`);
1236
2254
  setMarkData(cell, { index: i, label: entry.date, value: entry.value });
1237
2255
  grid.appendChild(cell);
@@ -1253,7 +2271,7 @@ function renderScatter(el, opts) {
1253
2271
  renderEmpty(body, opts.emptyLabel);
1254
2272
  return;
1255
2273
  }
1256
- const width = 360;
2274
+ const width = fluidWidth(body);
1257
2275
  const height = 220;
1258
2276
  const pad = 30;
1259
2277
  let xMin = Infinity, xMax = -Infinity, yMin = Infinity, yMax = -Infinity, sMax = 0;
@@ -1268,19 +2286,20 @@ function renderScatter(el, opts) {
1268
2286
  if (yMax === yMin) yMax = yMin + 1;
1269
2287
  const rOf = (size) => size && sMax > 0 ? 3 + size / sMax * 7 : 4;
1270
2288
  const wrap = document.createElement("div");
1271
- wrap.className = "chart-scatter";
2289
+ wrap.className = "icen-chart-scatter";
1272
2290
  const tone = toneVar(opts.tone);
1273
- const svg2 = svgEl("svg", { viewBox: `0 0 ${width} ${height}`, role: "img" });
2291
+ const svg = svgEl("svg", { viewBox: `0 0 ${width} ${height}`, role: "img", "aria-label": chartAriaLabel(opts.title, t("charts.type.scatter")) });
1274
2292
  const xAt = (x) => pad + (x - xMin) / (xMax - xMin) * (width - pad * 2);
1275
2293
  const yAt = (y) => height - pad - (y - yMin) / (yMax - yMin) * (height - pad * 2);
1276
2294
  for (let i = 0; i <= 3; i++) {
1277
- const y = pad + i * (height - pad * 2) / 3;
1278
- svg2.appendChild(svgEl("line", {
2295
+ const y = Math.round(pad + i * (height - pad * 2) / 3) + 0.5;
2296
+ svg.appendChild(svgEl("line", {
2297
+ class: i === 3 ? "icen-chart-grid icen-chart-baseline" : "icen-chart-grid",
1279
2298
  x1: String(pad),
1280
2299
  x2: String(width - pad),
1281
2300
  y1: String(y),
1282
2301
  y2: String(y),
1283
- stroke: "var(--token-line-soft)",
2302
+ stroke: "var(--icen-token-line-soft)",
1284
2303
  "stroke-width": "1"
1285
2304
  }));
1286
2305
  const tv = yMin + (yMax - yMin) * (3 - i) / 3;
@@ -1289,19 +2308,20 @@ function renderScatter(el, opts) {
1289
2308
  y: String(y + 3),
1290
2309
  "text-anchor": "end",
1291
2310
  "font-size": "8",
1292
- fill: "var(--token-text-faint)"
2311
+ fill: "var(--icen-token-text-faint)"
1293
2312
  });
1294
- txt.textContent = fmt(opts, Math.round(tv * 10) / 10);
1295
- svg2.appendChild(txt);
2313
+ txt.textContent = fmt(opts, +tv.toFixed(tickPrecision(yMin, yMax, 3)));
2314
+ svg.appendChild(txt);
1296
2315
  }
1297
2316
  for (let i = 0; i <= 4; i++) {
1298
- const x = pad + i * (width - pad * 2) / 4;
1299
- svg2.appendChild(svgEl("line", {
2317
+ const x = Math.round(pad + i * (width - pad * 2) / 4) + 0.5;
2318
+ svg.appendChild(svgEl("line", {
2319
+ class: i === 0 ? "icen-chart-grid icen-chart-grid--v icen-chart-axis" : "icen-chart-grid icen-chart-grid--v",
1300
2320
  x1: String(x),
1301
2321
  x2: String(x),
1302
2322
  y1: String(pad),
1303
2323
  y2: String(height - pad),
1304
- stroke: "var(--token-line-soft)",
2324
+ stroke: "var(--icen-token-line-soft)",
1305
2325
  "stroke-width": "1",
1306
2326
  "stroke-dasharray": "2 3"
1307
2327
  }));
@@ -1311,20 +2331,20 @@ function renderScatter(el, opts) {
1311
2331
  y: String(height - pad + 12),
1312
2332
  "text-anchor": "middle",
1313
2333
  "font-size": "8",
1314
- fill: "var(--token-text-faint)"
2334
+ fill: "var(--icen-token-text-faint)"
1315
2335
  });
1316
- txt.textContent = fmt(opts, Math.round(tv * 10) / 10);
1317
- svg2.appendChild(txt);
2336
+ txt.textContent = fmt(opts, +tv.toFixed(tickPrecision(xMin, xMax, 4)));
2337
+ svg.appendChild(txt);
1318
2338
  }
1319
2339
  if (opts.yLabel) {
1320
- const t = svgEl("text", { x: "10", y: String(pad - 10), "font-size": "8", fill: "var(--token-text-faint)" });
1321
- t.textContent = opts.yLabel;
1322
- svg2.appendChild(t);
2340
+ const t2 = svgEl("text", { x: "10", y: String(pad - 10), "font-size": "8", fill: "var(--icen-token-text-faint)" });
2341
+ t2.textContent = opts.yLabel;
2342
+ svg.appendChild(t2);
1323
2343
  }
1324
2344
  if (opts.xLabel) {
1325
- const t = svgEl("text", { x: String(width - pad), y: String(pad - 10), "text-anchor": "end", "font-size": "8", fill: "var(--token-text-faint)" });
1326
- t.textContent = opts.xLabel;
1327
- svg2.appendChild(t);
2345
+ const t2 = svgEl("text", { x: String(width - pad), y: String(pad - 10), "text-anchor": "end", "font-size": "8", fill: "var(--icen-token-text-faint)" });
2346
+ t2.textContent = opts.xLabel;
2347
+ svg.appendChild(t2);
1328
2348
  }
1329
2349
  pts.forEach((p, i) => {
1330
2350
  const c = svgEl("circle", {
@@ -1341,11 +2361,12 @@ function renderScatter(el, opts) {
1341
2361
  c.appendChild(title);
1342
2362
  setMarkData(c, { index: i, label: p.label ?? `#${i + 1}`, value: p.y });
1343
2363
  c.dataset.chartX = String(p.x);
1344
- svg2.appendChild(c);
2364
+ svg.appendChild(c);
1345
2365
  });
1346
- wrap.appendChild(svg2);
2366
+ wrap.appendChild(svg);
1347
2367
  body.appendChild(wrap);
1348
2368
  });
2369
+ if (el.dataset.icenChartBody == null) observeFluidWidth(el, () => renderScatter(el, opts));
1349
2370
  attachChartInteraction(el, "scatter");
1350
2371
  return el;
1351
2372
  }
@@ -1395,7 +2416,7 @@ function pivotData(spec) {
1395
2416
  const labels = [];
1396
2417
  const seenLabel = /* @__PURE__ */ new Set();
1397
2418
  const hasSeries = data.some((r) => r[seriesField] != null && r[seriesField] !== "");
1398
- const seriesNames = [];
2419
+ const seriesNames = hasSeries ? [] : [""];
1399
2420
  const seenSeries = /* @__PURE__ */ new Set();
1400
2421
  for (const r of data) {
1401
2422
  const l = str2(r[labelField]);
@@ -1484,8 +2505,8 @@ function normalizeChartSpec(raw) {
1484
2505
  const s = src;
1485
2506
  const spec = {};
1486
2507
  if (typeof s.type === "string") {
1487
- const t = s.type.trim().toLowerCase();
1488
- spec.type = CHART_TYPE_ALIASES[t] ?? t;
2508
+ const t2 = s.type.trim().toLowerCase();
2509
+ spec.type = CHART_TYPE_ALIASES[t2] ?? t2;
1489
2510
  }
1490
2511
  for (const k of ["title", "tone", "emptyLabel"]) {
1491
2512
  if (typeof s[k] === "string") spec[k] = s[k];
@@ -1507,7 +2528,7 @@ function normalizeChartSpec(raw) {
1507
2528
  if (Array.isArray(s.series)) {
1508
2529
  const series = s.series.filter((v) => !!v && typeof v === "object").map((v, i) => {
1509
2530
  const values = Array.isArray(v.values) ? v.values.map(toNum).filter((n) => n != null) : [];
1510
- const sv = { name: String(v.name ?? `\u7CFB\u5217${i + 1}`), values };
2531
+ const sv = { name: String(v.name ?? t("charts.seriesName", { p0: i + 1 })), values };
1511
2532
  const tone = v.tone;
1512
2533
  if (typeof tone === "string" || typeof tone === "number") sv.tone = tone;
1513
2534
  return sv;
@@ -1542,6 +2563,40 @@ function normalizeChartSpec(raw) {
1542
2563
  }
1543
2564
  spec.format = format;
1544
2565
  }
2566
+ if (typeof s.downsample === "boolean") spec.downsample = s.downsample;
2567
+ else {
2568
+ const n = toNum(s.downsample);
2569
+ if (n != null) spec.downsample = n;
2570
+ }
2571
+ if (s.zoom === "x" || s.zoom === "brush") spec.zoom = s.zoom;
2572
+ if (typeof s.loading === "boolean") spec.loading = s.loading;
2573
+ if (Array.isArray(s.marks)) {
2574
+ const marks = [];
2575
+ for (const raw2 of s.marks) {
2576
+ if (!raw2 || typeof raw2 !== "object" || Array.isArray(raw2)) continue;
2577
+ const m = raw2;
2578
+ if (m.type === "line") {
2579
+ if (m.axis !== "x" && m.axis !== "y") continue;
2580
+ if (typeof m.value !== "number" && typeof m.value !== "string") continue;
2581
+ const mark = { type: "line", axis: m.axis, value: m.value };
2582
+ if (typeof m.label === "string" && m.label !== "") mark.label = m.label;
2583
+ if (m.tone === "success" || m.tone === "warning" || m.tone === "error" || m.tone === "info") {
2584
+ mark.tone = m.tone;
2585
+ }
2586
+ marks.push(mark);
2587
+ } else if (m.type === "point") {
2588
+ if (typeof m.label !== "string" || m.label === "") continue;
2589
+ const mark = { type: "point", label: m.label };
2590
+ const si = toNum(m.seriesIndex);
2591
+ if (si != null && si >= 0) mark.seriesIndex = Math.floor(si);
2592
+ const v = toNum(m.value);
2593
+ if (v != null) mark.value = v;
2594
+ if (typeof m.text === "string") mark.text = m.text;
2595
+ marks.push(mark);
2596
+ }
2597
+ }
2598
+ if (marks.length > 0) spec.marks = marks;
2599
+ }
1545
2600
  const isDateRecords = spec.data?.length && spec.data[0] && "date" in spec.data[0];
1546
2601
  if (spec.data && spec.data.length > 0 && !isDateRecords && !spec.series && !spec.points && !spec.values && !spec.segments) {
1547
2602
  Object.assign(spec, pivotData(spec));
@@ -1581,6 +2636,392 @@ function inferChartType(spec) {
1581
2636
  if (typeof spec.max === "number" && spec.values && spec.values.length === 1) return "gauge";
1582
2637
  return "vbar";
1583
2638
  }
2639
+ var DOWNSAMPLE_DEFAULT_THRESHOLD = 1e3;
2640
+ var CHART_ZOOM_DRAG_MIN_PX = 5;
2641
+ var CHART_LINE_W = 360;
2642
+ var CHART_LINE_H = 150;
2643
+ var CHART_LINE_PAD = 14;
2644
+ function isDownsampleableType(type) {
2645
+ return type === "line" || type === "area" || type === "scatter";
2646
+ }
2647
+ function isZoomableType(type) {
2648
+ return type === "line" || type === "area" || type === "vbar";
2649
+ }
2650
+ function isStreamableType(type) {
2651
+ return type === "line" || type === "area" || type === "vbar";
2652
+ }
2653
+ function downsampleView(view, type) {
2654
+ const raw = view.downsample;
2655
+ if (raw == null || raw === false) return { view, note: null };
2656
+ const threshold = raw === true ? DOWNSAMPLE_DEFAULT_THRESHOLD : Math.floor(raw);
2657
+ if (!Number.isFinite(threshold)) return { view, note: null };
2658
+ if (type === "scatter") {
2659
+ const pts = view.points ?? [];
2660
+ if (pts.length === 0) return { view, note: null };
2661
+ const sampled2 = lttb(pts, threshold, (p) => p.x, (p) => p.y);
2662
+ if (sampled2.length === pts.length) return { view, note: null };
2663
+ return { view: { ...view, points: sampled2 }, note: t("charts.sampled", { p0: pts.length, p1: sampled2.length }) };
2664
+ }
2665
+ const labels = view.labels ?? [];
2666
+ if (labels.length === 0) return { view, note: null };
2667
+ const guide = view.series && view.series.length > 0 ? view.series[0]?.values ?? [] : view.values ?? [];
2668
+ const count = Math.min(labels.length, guide.length);
2669
+ if (count === 0) return { view, note: null };
2670
+ const indexed = guide.slice(0, count).map((v, i) => ({ i, v }));
2671
+ const sampled = lttb(indexed, threshold, (p) => p.i, (p) => p.v);
2672
+ if (sampled.length >= count) return { view, note: null };
2673
+ const idx = sampled.map((p) => p.i);
2674
+ return {
2675
+ view: {
2676
+ ...view,
2677
+ labels: idx.map((i) => labels[i] ?? ""),
2678
+ values: view.values ? idx.map((i) => view.values?.[i] ?? 0) : void 0,
2679
+ series: view.series?.map((s) => ({ ...s, values: idx.map((i) => s.values[i] ?? 0) }))
2680
+ },
2681
+ note: t("charts.sampled", { p0: count, p1: idx.length })
2682
+ };
2683
+ }
2684
+ function renderChartSkeleton(body) {
2685
+ const box = document.createElement("div");
2686
+ box.className = "icen-chart-skeleton";
2687
+ box.setAttribute("role", "status");
2688
+ box.setAttribute("aria-busy", "true");
2689
+ box.setAttribute("aria-label", t("charts.loading"));
2690
+ const widths = [100, 84, 92, 68, 76, 52];
2691
+ for (const w of widths) {
2692
+ const bar = document.createElement("div");
2693
+ bar.className = "icen-chart-skeleton-bar";
2694
+ bar.style.width = `${w}%`;
2695
+ box.appendChild(bar);
2696
+ }
2697
+ body.appendChild(box);
2698
+ }
2699
+ var CHART_MARK_ACCENT = "var(--icen-token-accent)";
2700
+ var CHART_MARK_ACCENT_TEXT = "var(--icen-token-accent-text)";
2701
+ function markToneVar(tone) {
2702
+ switch (tone) {
2703
+ case "success":
2704
+ return "var(--icen-token-success)";
2705
+ case "warning":
2706
+ return "var(--icen-token-warning)";
2707
+ case "error":
2708
+ return "var(--icen-token-error)";
2709
+ case "info":
2710
+ return "var(--icen-token-info)";
2711
+ default:
2712
+ return "var(--icen-token-text-faint)";
2713
+ }
2714
+ }
2715
+ function markWarnOnce(warned, mark, reason) {
2716
+ const key = JSON.stringify(mark);
2717
+ if (warned.has(key)) return;
2718
+ warned.add(key);
2719
+ console.warn(`[icen:chart] \u65E0\u6548\u6807\u8BB0\u5DF2\u8DF3\u8FC7\uFF08${reason}\uFF09`, mark);
2720
+ }
2721
+ function paintChartMarks(root, view, spec, formatValue, warned) {
2722
+ const marks = spec.marks;
2723
+ if (!marks || marks.length === 0) return;
2724
+ const type = spec.type;
2725
+ if (type === "line" || type === "area") paintSvgChartMarks(root, view, marks, formatValue, warned);
2726
+ else if (type === "vbar") paintVBarChartMarks(root, view, spec, marks, formatValue, warned);
2727
+ }
2728
+ function paintSvgChartMarks(root, view, marks, formatValue, warned) {
2729
+ const svg = root.querySelector(".icen-chart-line svg");
2730
+ if (!svg) return;
2731
+ const labels = view.labels ?? [];
2732
+ const n = labels.length;
2733
+ if (n === 0) return;
2734
+ const seriesList = view.series && view.series.length > 0 ? view.series : view.values ? [{ name: "", values: view.values }] : [];
2735
+ let max = 1;
2736
+ for (const s of seriesList) max = Math.max(max, maxOf(s.values.slice(0, n)));
2737
+ const dims = svgDimsOf(svg);
2738
+ const W = dims.w;
2739
+ const H = dims.h;
2740
+ const PAD = CHART_LINE_PAD;
2741
+ const xAt = (i) => n <= 1 ? W / 2 : PAD + i / (n - 1) * (W - PAD * 2);
2742
+ const yAt = (v) => H - PAD - Math.max(0, v) / max * (H - PAD * 2);
2743
+ for (const mark of marks) {
2744
+ if (mark.type === "line") {
2745
+ const color = markToneVar(mark.tone);
2746
+ if (mark.axis === "y") {
2747
+ const v = typeof mark.value === "number" ? mark.value : Number(mark.value);
2748
+ if (!Number.isFinite(v)) {
2749
+ markWarnOnce(warned, mark, "\u53C2\u8003\u7EBF\u6570\u503C NaN");
2750
+ continue;
2751
+ }
2752
+ const y = clampNum(yAt(v), CHART_LINE_PAD, H - PAD);
2753
+ svg.appendChild(svgEl("line", {
2754
+ class: "icen-chart-mark-line",
2755
+ x1: String(PAD),
2756
+ x2: String(W - PAD),
2757
+ y1: y.toFixed(1),
2758
+ y2: y.toFixed(1),
2759
+ stroke: color,
2760
+ "stroke-width": "1",
2761
+ "stroke-dasharray": "4 3"
2762
+ }));
2763
+ const label = svgEl("text", {
2764
+ class: "icen-chart-mark-label",
2765
+ x: String(W - PAD),
2766
+ y: String(clampNum(y - 4, 8, CHART_LINE_H - 4)),
2767
+ "text-anchor": "end",
2768
+ "font-size": "8",
2769
+ fill: color
2770
+ });
2771
+ label.textContent = mark.label ?? formatValue(v);
2772
+ svg.appendChild(label);
2773
+ } else {
2774
+ const idx = typeof mark.value === "number" ? Math.round(mark.value) : labels.indexOf(mark.value);
2775
+ if (idx < 0 || idx >= n) {
2776
+ markWarnOnce(warned, mark, "\u53C2\u8003\u7EBF\u7C7B\u76EE\u4E0D\u5B58\u5728");
2777
+ continue;
2778
+ }
2779
+ const x = xAt(idx);
2780
+ svg.appendChild(svgEl("line", {
2781
+ class: "icen-chart-mark-line",
2782
+ x1: x.toFixed(1),
2783
+ x2: x.toFixed(1),
2784
+ y1: String(PAD),
2785
+ y2: String(H - PAD),
2786
+ stroke: color,
2787
+ "stroke-width": "1",
2788
+ "stroke-dasharray": "4 3"
2789
+ }));
2790
+ const label = svgEl("text", {
2791
+ class: "icen-chart-mark-label",
2792
+ x: String(clampNum(x, 10, W - 10)),
2793
+ y: String(PAD + 8),
2794
+ "text-anchor": "middle",
2795
+ "font-size": "8",
2796
+ fill: color
2797
+ });
2798
+ label.textContent = mark.label ?? labels[idx] ?? "";
2799
+ svg.appendChild(label);
2800
+ }
2801
+ } else {
2802
+ const idx = labels.indexOf(mark.label);
2803
+ if (idx < 0 || idx >= n) {
2804
+ markWarnOnce(warned, mark, "\u6807\u8BB0\u70B9\u7C7B\u76EE\u4E0D\u5B58\u5728");
2805
+ continue;
2806
+ }
2807
+ const si = Math.max(0, Math.floor(mark.seriesIndex ?? 0));
2808
+ const s = seriesList[si];
2809
+ if (!s) {
2810
+ markWarnOnce(warned, mark, "\u6807\u8BB0\u70B9\u7CFB\u5217\u4E0D\u5B58\u5728");
2811
+ continue;
2812
+ }
2813
+ const v = mark.value ?? s.values[idx] ?? NaN;
2814
+ if (!Number.isFinite(v)) {
2815
+ markWarnOnce(warned, mark, "\u6807\u8BB0\u70B9\u6570\u503C NaN");
2816
+ continue;
2817
+ }
2818
+ const x = xAt(idx);
2819
+ const y = clampNum(yAt(v), CHART_LINE_PAD, H - PAD);
2820
+ const g = svgEl("g", { class: "icen-chart-mark-point" });
2821
+ g.appendChild(svgEl("circle", {
2822
+ cx: x.toFixed(1),
2823
+ cy: y.toFixed(1),
2824
+ r: "6",
2825
+ fill: "none",
2826
+ stroke: CHART_MARK_ACCENT,
2827
+ "stroke-width": "1.5"
2828
+ }));
2829
+ g.appendChild(svgEl("circle", { cx: x.toFixed(1), cy: y.toFixed(1), r: "2", fill: CHART_MARK_ACCENT }));
2830
+ const label = svgEl("text", {
2831
+ class: "icen-chart-mark-label",
2832
+ x: String(clampNum(x, 12, W - 12)),
2833
+ y: String(clampNum(y - 10, 8, CHART_LINE_H - 4)),
2834
+ "text-anchor": "middle",
2835
+ "font-size": "8",
2836
+ fill: CHART_MARK_ACCENT_TEXT
2837
+ });
2838
+ label.textContent = mark.text ?? mark.label;
2839
+ g.appendChild(label);
2840
+ svg.appendChild(g);
2841
+ }
2842
+ }
2843
+ }
2844
+ function paintVBarChartMarks(root, view, spec, marks, formatValue, warned) {
2845
+ const wrap = root.querySelector(".icen-chart-vbar");
2846
+ if (!wrap) return;
2847
+ const seriesList = view.series && view.series.length > 0 ? view.series : view.values ? [{ name: "", values: view.values }] : [];
2848
+ const labels = view.labels ?? [];
2849
+ const n = Math.min(labels.length, ...seriesList.map((s) => s.values.length));
2850
+ if (n === 0 || seriesList.length === 0) return;
2851
+ const multi = seriesList.length > 1;
2852
+ let max = 1;
2853
+ if (spec.stacked && multi) {
2854
+ for (let i = 0; i < n; i++) {
2855
+ let sum2 = 0;
2856
+ for (const s of seriesList) sum2 += Math.max(0, s.values[i] ?? 0);
2857
+ if (sum2 > max) max = sum2;
2858
+ }
2859
+ } else {
2860
+ for (const s of seriesList) max = Math.max(max, maxOf(s.values.slice(0, n)));
2861
+ }
2862
+ const centerPct = (i) => (i + 0.5) / n * 100;
2863
+ for (const mark of marks) {
2864
+ if (mark.type === "line") {
2865
+ if (mark.axis === "y") {
2866
+ const v = typeof mark.value === "number" ? mark.value : Number(mark.value);
2867
+ if (!Number.isFinite(v)) {
2868
+ markWarnOnce(warned, mark, "\u53C2\u8003\u7EBF\u6570\u503C NaN");
2869
+ continue;
2870
+ }
2871
+ const line = document.createElement("div");
2872
+ line.className = "icen-chart-mark-line icen-chart-mark-line--h";
2873
+ line.style.top = `${(clampNum(1 - Math.max(0, v) / max, 0.02, 0.98) * 100).toFixed(2)}%`;
2874
+ line.style.setProperty("--chart-mark-tone", markToneVar(mark.tone));
2875
+ const lab = document.createElement("span");
2876
+ lab.className = "icen-chart-mark-label";
2877
+ lab.textContent = mark.label ?? formatValue(v);
2878
+ line.appendChild(lab);
2879
+ wrap.appendChild(line);
2880
+ } else {
2881
+ const idx = typeof mark.value === "number" ? Math.round(mark.value) : labels.indexOf(mark.value);
2882
+ if (idx < 0 || idx >= n) {
2883
+ markWarnOnce(warned, mark, "\u53C2\u8003\u7EBF\u7C7B\u76EE\u4E0D\u5B58\u5728");
2884
+ continue;
2885
+ }
2886
+ const line = document.createElement("div");
2887
+ line.className = "icen-chart-mark-line icen-chart-mark-line--v";
2888
+ line.style.left = `${centerPct(idx).toFixed(2)}%`;
2889
+ line.style.setProperty("--chart-mark-tone", markToneVar(mark.tone));
2890
+ const lab = document.createElement("span");
2891
+ lab.className = "icen-chart-mark-label";
2892
+ lab.textContent = mark.label ?? labels[idx] ?? "";
2893
+ line.appendChild(lab);
2894
+ wrap.appendChild(line);
2895
+ }
2896
+ } else {
2897
+ const idx = labels.indexOf(mark.label);
2898
+ if (idx < 0 || idx >= n) {
2899
+ markWarnOnce(warned, mark, "\u6807\u8BB0\u70B9\u7C7B\u76EE\u4E0D\u5B58\u5728");
2900
+ continue;
2901
+ }
2902
+ const si = Math.max(0, Math.floor(mark.seriesIndex ?? 0));
2903
+ const s = seriesList[si];
2904
+ if (!s) {
2905
+ markWarnOnce(warned, mark, "\u6807\u8BB0\u70B9\u7CFB\u5217\u4E0D\u5B58\u5728");
2906
+ continue;
2907
+ }
2908
+ const v = mark.value ?? s.values[idx] ?? NaN;
2909
+ if (!Number.isFinite(v)) {
2910
+ markWarnOnce(warned, mark, "\u6807\u8BB0\u70B9\u6570\u503C NaN");
2911
+ continue;
2912
+ }
2913
+ const dot = document.createElement("div");
2914
+ dot.className = "icen-chart-mark-point";
2915
+ dot.style.left = `${centerPct(idx).toFixed(2)}%`;
2916
+ dot.style.bottom = `${(clampNum(Math.max(0, v) / max, 0, 1) * 100).toFixed(2)}%`;
2917
+ const lab = document.createElement("span");
2918
+ lab.className = "icen-chart-mark-label";
2919
+ lab.textContent = mark.text ?? mark.label;
2920
+ dot.appendChild(lab);
2921
+ wrap.appendChild(dot);
2922
+ }
2923
+ }
2924
+ }
2925
+ function chartAriaLabel(title, typeName) {
2926
+ return title ? `${typeName}\uFF1A${title}` : typeName;
2927
+ }
2928
+ function svgDimsOf(svg) {
2929
+ const vb = (svg.getAttribute("viewBox") ?? "").split(/\s+/).map(Number);
2930
+ const w = Number.isFinite(vb[2]) && (vb[2] ?? 0) > 0 ? vb[2] : CHART_LINE_W;
2931
+ const h2 = Number.isFinite(vb[3]) && (vb[3] ?? 0) > 0 ? vb[3] : CHART_LINE_H;
2932
+ return { w, h: h2 };
2933
+ }
2934
+ var fluidObservers = /* @__PURE__ */ new WeakMap();
2935
+ function fluidWidth(host) {
2936
+ const w = Math.round(host.getBoundingClientRect().width);
2937
+ return w > 0 ? Math.max(29, w) : 360;
2938
+ }
2939
+ function observeFluidWidth(el, rerender) {
2940
+ if (typeof ResizeObserver === "undefined") return;
2941
+ fluidObservers.get(el)?.disconnect();
2942
+ let last = Math.round(el.getBoundingClientRect().width);
2943
+ const ro = new ResizeObserver(() => {
2944
+ if (!el.isConnected) {
2945
+ ro.disconnect();
2946
+ fluidObservers.delete(el);
2947
+ return;
2948
+ }
2949
+ const w = Math.round(el.getBoundingClientRect().width);
2950
+ if (Math.abs(w - last) < 2) return;
2951
+ last = w;
2952
+ rerender();
2953
+ });
2954
+ ro.observe(el);
2955
+ fluidObservers.set(el, ro);
2956
+ }
2957
+ function releaseFluidWidth(el) {
2958
+ fluidObservers.get(el)?.disconnect();
2959
+ fluidObservers.delete(el);
2960
+ }
2961
+ function createChartToDataURL(root) {
2962
+ const cache = /* @__PURE__ */ new Map();
2963
+ return (opts) => {
2964
+ if (typeof document === "undefined") return void 0;
2965
+ const scale = clampNum(toNum(opts?.scale) ?? 2, 0.5, 4);
2966
+ const svgs = Array.from(root.querySelectorAll("svg"));
2967
+ if (svgs.length === 0) return void 0;
2968
+ const parts = [];
2969
+ for (const svg of svgs) {
2970
+ const { w, h: h2 } = svgDimsOf(svg);
2971
+ const clone = svg.cloneNode(true);
2972
+ clone.setAttribute("xmlns", SVG_NS);
2973
+ clone.setAttribute("width", String(w));
2974
+ clone.setAttribute("height", String(h2));
2975
+ let str2;
2976
+ try {
2977
+ str2 = new XMLSerializer().serializeToString(clone);
2978
+ } catch {
2979
+ return void 0;
2980
+ }
2981
+ parts.push({ src: `data:image/svg+xml;charset=utf-8,${encodeURIComponent(str2)}`, w, h: h2 });
2982
+ }
2983
+ const key = `${scale}|${parts.map((p) => p.src).join("")}`;
2984
+ const hit = cache.get(key);
2985
+ if (hit) return hit;
2986
+ const canvas = document.createElement("canvas");
2987
+ let ctx = null;
2988
+ try {
2989
+ ctx = canvas.getContext("2d");
2990
+ } catch {
2991
+ return void 0;
2992
+ }
2993
+ if (!ctx) return void 0;
2994
+ const context = ctx;
2995
+ const totalW = Math.max(...parts.map((p) => p.w));
2996
+ const totalH = parts.reduce((sum2, p) => sum2 + p.h, 0);
2997
+ canvas.width = Math.max(1, Math.round(totalW * scale));
2998
+ canvas.height = Math.max(1, Math.round(totalH * scale));
2999
+ let loaded = 0;
3000
+ let failed = false;
3001
+ let offsetY = 0;
3002
+ for (const part of parts) {
3003
+ const dy = offsetY;
3004
+ offsetY += part.h;
3005
+ const img = new Image();
3006
+ img.onload = () => {
3007
+ if (failed) return;
3008
+ context.drawImage(img, 0, dy * scale, part.w * scale, part.h * scale);
3009
+ loaded += 1;
3010
+ if (loaded === parts.length) {
3011
+ try {
3012
+ cache.set(key, canvas.toDataURL("image/png"));
3013
+ } catch {
3014
+ }
3015
+ }
3016
+ };
3017
+ img.onerror = () => {
3018
+ failed = true;
3019
+ };
3020
+ img.src = part.src;
3021
+ }
3022
+ return cache.get(key);
3023
+ };
3024
+ }
1584
3025
  function dispatchChartEvent(root, type, mark, chart, phase, pointer) {
1585
3026
  const read = (name) => mark.getAttribute(name) ?? void 0;
1586
3027
  const numOr = (v) => v == null ? void 0 : Number(v);
@@ -1588,11 +3029,11 @@ function dispatchChartEvent(root, type, mark, chart, phase, pointer) {
1588
3029
  type,
1589
3030
  phase,
1590
3031
  chart,
1591
- index: numOr(read("data-chart-index")),
1592
- seriesIndex: numOr(read("data-chart-series")),
1593
- seriesName: read("data-chart-series-name"),
1594
- label: read("data-chart-label"),
1595
- value: numOr(read("data-chart-value")),
3032
+ index: numOr(read("data-icen-chart-index")),
3033
+ seriesIndex: numOr(read("data-icen-chart-series")),
3034
+ seriesName: read("data-icen-chart-series-name"),
3035
+ label: read("data-icen-chart-label"),
3036
+ value: numOr(read("data-icen-chart-value")),
1596
3037
  target: mark,
1597
3038
  pointerX: pointer?.x,
1598
3039
  pointerY: pointer?.y
@@ -1603,7 +3044,7 @@ var tooltipEl = null;
1603
3044
  function chartTooltip() {
1604
3045
  if (!tooltipEl) {
1605
3046
  tooltipEl = document.createElement("div");
1606
- tooltipEl.className = "chart-tooltip";
3047
+ tooltipEl.className = "icen-chart-tooltip";
1607
3048
  tooltipEl.setAttribute("role", "tooltip");
1608
3049
  tooltipEl.hidden = true;
1609
3050
  document.body.appendChild(tooltipEl);
@@ -1612,14 +3053,14 @@ function chartTooltip() {
1612
3053
  }
1613
3054
  function applyTooltipSizing(host) {
1614
3055
  const tip = chartTooltip();
1615
- const raw = host?.closest(".chart, [data-chart-root]")?.getAttribute("data-panel-max") ?? null;
3056
+ const raw = host?.closest(".icen-chart, [data-icen-chart-root]")?.getAttribute("data-icen-panel-max") ?? null;
1616
3057
  const n = raw != null ? Number(raw) : NaN;
1617
3058
  tip.style.maxWidth = Number.isFinite(n) && n > 0 ? `${n}px` : "";
1618
3059
  }
1619
3060
  function tooltipText(mark) {
1620
- const label = mark.getAttribute("data-chart-label") ?? "";
1621
- const series = mark.getAttribute("data-chart-series-name");
1622
- const value = mark.getAttribute("data-chart-value");
3061
+ const label = mark.getAttribute("data-icen-chart-label") ?? "";
3062
+ const series = mark.getAttribute("data-icen-chart-series-name");
3063
+ const value = mark.getAttribute("data-icen-chart-value");
1623
3064
  const head = series ? label ? `${series} \xB7 ${label}` : series : label;
1624
3065
  return value != null ? `${head}\uFF1A${value}` : head;
1625
3066
  }
@@ -1651,8 +3092,8 @@ function bindChartEvents(root) {
1651
3092
  const typeNow = () => chartDelegateMeta.get(root)?.type() ?? "vbar";
1652
3093
  const tipEnabled = () => chartDelegateMeta.get(root)?.tooltip() ?? true;
1653
3094
  const markOf = (e) => {
1654
- const t = e.target;
1655
- return t instanceof Element ? t.closest("[data-chart-mark]") : null;
3095
+ const t2 = e.target;
3096
+ return t2 instanceof Element ? t2.closest("[data-icen-chart-mark]") : null;
1656
3097
  };
1657
3098
  let hoverMark = null;
1658
3099
  const enterMark = (mark, x, y) => {
@@ -1749,70 +3190,283 @@ function hasLegendOf(spec) {
1749
3190
  function renderChart(el, raw) {
1750
3191
  const noop = () => void 0;
1751
3192
  if (typeof document === "undefined") {
1752
- return { el, spec: {}, update: noop, on: () => noop, destroy: noop };
3193
+ return {
3194
+ el,
3195
+ spec: {},
3196
+ update: noop,
3197
+ append: noop,
3198
+ toDataURL: () => void 0,
3199
+ on: () => noop,
3200
+ destroy: noop
3201
+ };
1753
3202
  }
1754
3203
  const root = el;
1755
- let current = normalizeChartSpec(raw);
1756
- const typeOf = () => current.type ?? "vbar";
3204
+ let current2 = normalizeChartSpec(raw);
3205
+ const typeOf = () => current2.type ?? "vbar";
1757
3206
  const legendState = { hidden: null };
3207
+ let zoomWindow = null;
3208
+ const warnedMarks = /* @__PURE__ */ new Set();
3209
+ let warnedAppend = false;
3210
+ let zoomDragCleanup = null;
3211
+ const fullLength = () => {
3212
+ if (current2.type === "scatter") return current2.points?.length ?? 0;
3213
+ if (current2.series && current2.series.length > 0) {
3214
+ return Math.max(current2.labels?.length ?? 0, ...current2.series.map((s) => s.values.length));
3215
+ }
3216
+ return Math.max(current2.labels?.length ?? 0, current2.values?.length ?? 0);
3217
+ };
3218
+ const viewOf = () => {
3219
+ if (!zoomWindow) return current2;
3220
+ const { from, to } = zoomWindow;
3221
+ return {
3222
+ ...current2,
3223
+ labels: current2.labels?.slice(from, to + 1),
3224
+ values: current2.values?.slice(from, to + 1),
3225
+ series: current2.series?.map((s) => ({ ...s, values: s.values.slice(from, to + 1) })),
3226
+ points: current2.points?.slice(from, to + 1)
3227
+ };
3228
+ };
3229
+ const applyZoomSelection = (x0, x1) => {
3230
+ const len = fullLength();
3231
+ if (len < 2) return;
3232
+ const base = zoomWindow?.from ?? 0;
3233
+ const viewLen = zoomWindow ? zoomWindow.to - zoomWindow.from + 1 : len;
3234
+ const lo = Math.min(x0, x1);
3235
+ const hi = Math.max(x0, x1);
3236
+ let i0;
3237
+ let i1;
3238
+ const vbar = root.querySelector(".icen-chart-vbar");
3239
+ if (vbar) {
3240
+ const rect = vbar.getBoundingClientRect();
3241
+ const rel0 = rect.width > 0 ? Math.floor((lo - rect.left) / rect.width * viewLen) : 0;
3242
+ const rel1 = rect.width > 0 ? Math.max(rel0, Math.floor((hi - rect.left) / rect.width * viewLen)) : viewLen - 1;
3243
+ i0 = clampNum(rel0 + base, 0, len - 1);
3244
+ i1 = clampNum(rel1 + base, 0, len - 1);
3245
+ } else {
3246
+ const svg = root.querySelector(".icen-chart-line svg");
3247
+ if (!svg) return;
3248
+ const dims = svgDimsOf(svg);
3249
+ const p0 = svgClientPoint(svg, lo, 0, dims.w, dims.h);
3250
+ const p1 = svgClientPoint(svg, hi, 0, dims.w, dims.h);
3251
+ const rel0 = Math.round((p0.x - CHART_LINE_PAD) / (dims.w - CHART_LINE_PAD * 2) * (viewLen - 1));
3252
+ const rel1 = Math.round((p1.x - CHART_LINE_PAD) / (dims.w - CHART_LINE_PAD * 2) * (viewLen - 1));
3253
+ i0 = clampNum(rel0 + base, 0, len - 1);
3254
+ i1 = clampNum(rel1 + base, 0, len - 1);
3255
+ }
3256
+ if (i0 > i1) [i0, i1] = [i1, i0];
3257
+ if (i0 <= 0 && i1 >= len - 1) zoomWindow = null;
3258
+ else zoomWindow = { from: i0, to: Math.max(i1, i0) };
3259
+ render();
3260
+ emitIcen(root, "icen:chart-zoom", { chart: String(current2.type ?? ""), from: i0, to: Math.max(i1, i0) });
3261
+ };
3262
+ const bindZoomGesture = () => {
3263
+ if (current2.zoom !== "x" && current2.zoom !== "brush") return;
3264
+ const t2 = typeOf();
3265
+ if (!isZoomableType(t2) || fullLength() < 2) return;
3266
+ const plot = t2 === "vbar" ? root.querySelector(".icen-chart-vbar") : root.querySelector(".icen-chart-line svg");
3267
+ if (!plot) return;
3268
+ const on = (type, fn) => {
3269
+ plot.addEventListener(type, fn);
3270
+ };
3271
+ let drag = null;
3272
+ const onMove = (e) => {
3273
+ if (!drag) return;
3274
+ drag.x1 = e.clientX;
3275
+ drag.y1 = e.clientY;
3276
+ if (!drag.active && Math.hypot(drag.x1 - drag.x0, drag.y1 - drag.y0) >= CHART_ZOOM_DRAG_MIN_PX) {
3277
+ drag.active = true;
3278
+ const rect = document.createElement("div");
3279
+ rect.className = "icen-chart-zoom-rect";
3280
+ document.body.appendChild(rect);
3281
+ drag.rect = rect;
3282
+ }
3283
+ if (drag.active && drag.rect) {
3284
+ drag.rect.style.left = `${Math.round(Math.min(drag.x0, drag.x1))}px`;
3285
+ drag.rect.style.width = `${Math.round(Math.abs(drag.x1 - drag.x0))}px`;
3286
+ if (current2.zoom === "brush") {
3287
+ drag.rect.style.top = `${Math.round(Math.min(drag.y0, drag.y1))}px`;
3288
+ drag.rect.style.height = `${Math.round(Math.abs(drag.y1 - drag.y0))}px`;
3289
+ } else {
3290
+ const pr = plot.getBoundingClientRect();
3291
+ drag.rect.style.top = `${Math.round(pr.top)}px`;
3292
+ drag.rect.style.height = `${Math.round(pr.height)}px`;
3293
+ }
3294
+ }
3295
+ };
3296
+ const onUp = () => {
3297
+ window.removeEventListener("pointermove", onMove);
3298
+ window.removeEventListener("pointerup", onUp);
3299
+ window.removeEventListener("pointercancel", onUp);
3300
+ zoomDragCleanup = null;
3301
+ if (!drag) return;
3302
+ const d = drag;
3303
+ drag = null;
3304
+ d.rect?.remove();
3305
+ if (!d.active) return;
3306
+ applyZoomSelection(d.x0, d.x1);
3307
+ };
3308
+ const onDown = (e) => {
3309
+ if (e.button !== 0) return;
3310
+ drag = { x0: e.clientX, y0: e.clientY, x1: e.clientX, y1: e.clientY, active: false, rect: null };
3311
+ window.addEventListener("pointermove", onMove);
3312
+ window.addEventListener("pointerup", onUp);
3313
+ window.addEventListener("pointercancel", onUp);
3314
+ zoomDragCleanup = onUp;
3315
+ };
3316
+ on("pointerdown", onDown);
3317
+ on("dblclick", () => {
3318
+ if (!zoomWindow) return;
3319
+ zoomWindow = null;
3320
+ render();
3321
+ });
3322
+ };
1758
3323
  const render = () => {
1759
- if (!current.type) current = { ...current, type: inferChartType(current) };
1760
- const spec = current;
3324
+ if (!current2.type) current2 = { ...current2, type: inferChartType(current2) };
3325
+ const spec = current2;
3326
+ const type = spec.type;
1761
3327
  const formatValue = chartFormatValue(spec.format);
1762
3328
  if (spec.legend !== void 0) legendState.hidden = spec.legend === false;
3329
+ const loading = spec.loading === true;
3330
+ root.classList.toggle("is-loading", loading);
3331
+ let view = viewOf();
3332
+ let note = null;
3333
+ if (!loading && isDownsampleableType(type)) {
3334
+ const r = downsampleView(view, type);
3335
+ view = r.view;
3336
+ note = r.note;
3337
+ }
3338
+ const zoomReset = zoomWindow && (spec.zoom === "x" || spec.zoom === "brush") ? () => {
3339
+ zoomWindow = null;
3340
+ render();
3341
+ } : null;
1763
3342
  withChrome(root, spec, hasLegendOf(spec), (body) => {
1764
- switch (spec.type) {
3343
+ if (loading) {
3344
+ renderChartSkeleton(body);
3345
+ return;
3346
+ }
3347
+ switch (type) {
1765
3348
  case "line":
1766
- renderLine(body, { labels: spec.labels ?? [], values: spec.values ?? [], series: spec.series, tone: spec.tone, fill: spec.fill, formatValue, emptyLabel: spec.emptyLabel, title: spec.title, legend: spec.legend });
3349
+ renderLine(body, { labels: view.labels ?? [], values: view.values ?? [], series: view.series, tone: view.tone, fill: view.fill, formatValue, emptyLabel: view.emptyLabel, title: view.title, legend: view.legend });
1767
3350
  break;
1768
3351
  case "area":
1769
- renderLine(body, { labels: spec.labels ?? [], values: spec.values ?? [], series: spec.series, tone: spec.tone, fill: true, formatValue, emptyLabel: spec.emptyLabel, title: spec.title, legend: spec.legend });
3352
+ renderLine(body, { labels: view.labels ?? [], values: view.values ?? [], series: view.series, tone: view.tone, fill: true, formatValue, emptyLabel: view.emptyLabel, title: view.title, legend: view.legend });
1770
3353
  break;
1771
3354
  case "vbar":
1772
- renderVBar(body, { labels: spec.labels ?? [], values: spec.values ?? [], series: spec.series, stacked: spec.stacked, tone: spec.tone, formatValue, emptyLabel: spec.emptyLabel, title: spec.title, legend: spec.legend });
3355
+ renderVBar(body, { labels: view.labels ?? [], values: view.values ?? [], series: view.series, stacked: view.stacked, tone: view.tone, formatValue, emptyLabel: view.emptyLabel, title: view.title, legend: view.legend });
1773
3356
  break;
1774
3357
  case "hbar":
1775
- renderHBar(body, { labels: spec.labels ?? [], values: spec.values ?? [], tone: spec.tone, formatValue, emptyLabel: spec.emptyLabel, title: spec.title, legend: spec.legend });
3358
+ renderHBar(body, { labels: view.labels ?? [], values: view.values ?? [], tone: view.tone, formatValue, emptyLabel: view.emptyLabel, title: view.title, legend: view.legend });
1776
3359
  break;
1777
3360
  case "stack":
1778
- renderStack(body, { segments: spec.segments ?? [], formatValue, emptyLabel: spec.emptyLabel, title: spec.title, legend: spec.legend });
3361
+ renderStack(body, { segments: view.segments ?? [], formatValue, emptyLabel: view.emptyLabel, title: view.title, legend: view.legend });
1779
3362
  break;
1780
3363
  case "donut":
1781
- renderDonut(body, { segments: spec.segments ?? [], formatValue, emptyLabel: spec.emptyLabel, title: spec.title, legend: spec.legend });
3364
+ renderDonut(body, { segments: view.segments ?? [], formatValue, emptyLabel: view.emptyLabel, title: view.title, legend: view.legend });
1782
3365
  break;
1783
3366
  case "radar": {
1784
- const series = spec.series ? spec.series.map((s) => ({ name: s.name, values: s.values, tone: typeof s.tone === "string" ? s.tone : void 0 })) : spec.values ? [{ name: "", values: spec.values }] : [];
1785
- renderRadar(body, { axes: spec.axes ?? spec.labels ?? [], series, max: spec.max, levels: spec.levels, formatValue, emptyLabel: spec.emptyLabel, title: spec.title, legend: spec.legend });
3367
+ const series = view.series ? view.series.map((s) => ({ name: s.name, values: s.values, tone: typeof s.tone === "string" ? s.tone : void 0 })) : view.values ? [{ name: "", values: view.values }] : [];
3368
+ renderRadar(body, { axes: view.axes ?? view.labels ?? [], series, max: view.max, levels: view.levels, formatValue, emptyLabel: view.emptyLabel, title: view.title, legend: view.legend });
1786
3369
  break;
1787
3370
  }
1788
3371
  case "heatmap":
1789
- renderHeatmap(body, { values: spec.values, data: spec.data, weeks: spec.weeks, tone: spec.tone, formatValue, emptyLabel: spec.emptyLabel, title: spec.title, legend: spec.legend, weekStart: spec.i18n?.weekStart, labels: spec.i18n });
3372
+ renderHeatmap(body, { values: view.values, data: view.data, weeks: view.weeks, tone: view.tone, formatValue, emptyLabel: view.emptyLabel, title: view.title, legend: view.legend, weekStart: view.i18n?.weekStart, labels: view.i18n });
1790
3373
  break;
1791
3374
  case "calendar":
1792
- renderCalendar(body, { dates: spec.dates, values: spec.values, data: spec.data, tone: spec.tone, formatValue, emptyLabel: spec.emptyLabel, title: spec.title, legend: spec.legend, weekStart: spec.i18n?.weekStart, labels: spec.i18n });
3375
+ renderCalendar(body, { dates: view.dates, values: view.values, data: view.data, tone: view.tone, formatValue, emptyLabel: view.emptyLabel, title: view.title, legend: view.legend, weekStart: view.i18n?.weekStart, labels: view.i18n });
1793
3376
  break;
1794
3377
  case "sparkline":
1795
- renderSparkline(body, { labels: spec.labels ?? [], values: spec.values ?? [], tone: spec.tone, formatValue, emptyLabel: spec.emptyLabel, title: spec.title, legend: spec.legend });
3378
+ renderSparkline(body, { labels: view.labels ?? [], values: view.values ?? [], tone: view.tone, formatValue, emptyLabel: view.emptyLabel, title: view.title, legend: view.legend });
1796
3379
  break;
1797
3380
  case "gauge":
1798
- renderGauge(body, { value: spec.values?.[0] ?? 0, max: spec.max, tone: spec.tone, label: spec.labels?.[0], formatValue });
3381
+ renderGauge(body, { value: view.values?.[0] ?? 0, max: view.max, tone: view.tone, label: view.labels?.[0], formatValue });
1799
3382
  break;
1800
3383
  case "scatter":
1801
- renderScatter(body, { points: spec.points ?? [], tone: spec.tone, formatValue, emptyLabel: spec.emptyLabel, title: spec.title, legend: spec.legend });
3384
+ renderScatter(body, { points: view.points ?? [], tone: view.tone, formatValue, emptyLabel: view.emptyLabel, title: view.title, legend: view.legend });
1802
3385
  break;
1803
3386
  default:
1804
- renderEmpty(body, spec.emptyLabel);
3387
+ renderEmpty(body, view.emptyLabel);
1805
3388
  }
1806
- });
3389
+ }, legendState, { note, onZoomReset: zoomReset });
3390
+ if (!loading) {
3391
+ const graphic = root.querySelector('[role="img"]');
3392
+ if (graphic && !graphic.getAttribute("aria-label")) {
3393
+ graphic.setAttribute("aria-label", spec.title ? `${spec.title}\uFF08${type}\uFF09` : type);
3394
+ } else if (!graphic) {
3395
+ const dom = root.querySelector(".icen-chart-vbar, .icen-chart-hbar");
3396
+ if (dom) {
3397
+ dom.setAttribute("role", "img");
3398
+ dom.setAttribute("aria-label", spec.title ? `${spec.title}\uFF08${type}\uFF09` : type);
3399
+ }
3400
+ }
3401
+ }
3402
+ if (loading) return;
3403
+ paintChartMarks(root, view, spec, formatValue, warnedMarks);
3404
+ bindZoomGesture();
1807
3405
  };
1808
- chartDelegateMeta.set(root, { type: typeOf, tooltip: () => current.tooltip !== false });
3406
+ chartDelegateMeta.set(root, { type: typeOf, tooltip: () => current2.tooltip !== false });
1809
3407
  const unbindEvents = bindChartEvents(root);
1810
3408
  render();
3409
+ observeFluidWidth(root, render);
1811
3410
  return {
1812
3411
  el: root,
1813
- spec: current,
3412
+ /** 归一 + 推断后的当前规格(getter:update/append 换引用后永远读到最新) */
3413
+ get spec() {
3414
+ return current2;
3415
+ },
1814
3416
  update(next) {
1815
- current = normalizeChartSpec(next);
3417
+ const prev = current2;
3418
+ current2 = normalizeChartSpec(next);
3419
+ if (zoomWindow) {
3420
+ const sameLabels = JSON.stringify(prev.labels ?? null) === JSON.stringify(current2.labels ?? null);
3421
+ const t2 = current2.type ?? inferChartType(current2);
3422
+ const zoomable = isZoomableType(t2) && (current2.zoom === "x" || current2.zoom === "brush");
3423
+ if (!sameLabels || !zoomable) zoomWindow = null;
3424
+ else {
3425
+ const len = fullLength();
3426
+ if (len < 2) zoomWindow = null;
3427
+ else {
3428
+ const from = clampNum(zoomWindow.from, 0, len - 1);
3429
+ const to = clampNum(zoomWindow.to, 0, len - 1);
3430
+ zoomWindow = from <= to ? { from, to } : null;
3431
+ }
3432
+ }
3433
+ }
3434
+ render();
3435
+ },
3436
+ append(label, values, opts) {
3437
+ const t2 = current2.type ?? inferChartType(current2);
3438
+ if (!isStreamableType(t2)) {
3439
+ if (!warnedAppend) {
3440
+ warnedAppend = true;
3441
+ console.warn(`[icen:chart] append \u4EC5\u652F\u6301 line/area/vbar\uFF08\u5F53\u524D ${String(current2.type ?? t2)}\uFF09\uFF0C\u5DF2\u5FFD\u7565`);
3442
+ }
3443
+ return;
3444
+ }
3445
+ const labels = current2.labels ?? (current2.labels = []);
3446
+ labels.push(String(label ?? ""));
3447
+ const vals = Array.isArray(values) ? values : [];
3448
+ if (current2.series && current2.series.length > 0) {
3449
+ for (const [i, s] of current2.series.entries()) s.values.push(toNum(vals[i]) ?? 0);
3450
+ } else {
3451
+ const v = current2.values ?? (current2.values = []);
3452
+ v.push(toNum(vals[0]) ?? 0);
3453
+ }
3454
+ const maxPoints = opts?.maxPoints != null ? Math.max(1, Math.floor(toNum(opts.maxPoints) ?? 0)) : 0;
3455
+ let dropped = 0;
3456
+ if (maxPoints > 0) {
3457
+ while (labels.length > maxPoints) {
3458
+ labels.shift();
3459
+ if (current2.series) for (const s of current2.series) s.values.shift();
3460
+ else current2.values?.shift();
3461
+ dropped += 1;
3462
+ }
3463
+ }
3464
+ if (zoomWindow) {
3465
+ const len = Math.max(1, labels.length);
3466
+ const size = zoomWindow.to - zoomWindow.from + 1;
3467
+ const to = clampNum(zoomWindow.to - dropped + 1, 0, len - 1);
3468
+ zoomWindow = { from: Math.max(0, to - size + 1), to };
3469
+ }
1816
3470
  render();
1817
3471
  },
1818
3472
  on(name, listener) {
@@ -1822,13 +3476,29 @@ function renderChart(el, raw) {
1822
3476
  root.addEventListener(`icen:chart-${name}`, handler);
1823
3477
  return () => root.removeEventListener(`icen:chart-${name}`, handler);
1824
3478
  },
3479
+ toDataURL: createChartToDataURL(root),
1825
3480
  destroy() {
3481
+ releaseFluidWidth(root);
3482
+ hiddenLegendKeys.delete(root);
3483
+ zoomDragCleanup?.();
1826
3484
  root.textContent = "";
3485
+ root.classList.remove("is-loading");
1827
3486
  unbindEvents();
1828
3487
  chartTooltip().hidden = true;
1829
3488
  }
1830
3489
  };
1831
3490
  }
3491
+ function svgClientPoint(svg, clientX, clientY, viewBoxWidth, viewBoxHeight) {
3492
+ const rect = svg.getBoundingClientRect();
3493
+ const scale = Math.min(rect.width / viewBoxWidth, rect.height / viewBoxHeight);
3494
+ if (!Number.isFinite(scale) || scale <= 0) {
3495
+ return { x: viewBoxWidth / 2, y: viewBoxHeight / 2 };
3496
+ }
3497
+ return {
3498
+ x: (clientX - rect.left - (rect.width - viewBoxWidth * scale) / 2) / scale,
3499
+ y: (clientY - rect.top - (rect.height - viewBoxHeight * scale) / 2) / scale
3500
+ };
3501
+ }
1832
3502
  var GRAPH_W = 360;
1833
3503
  var GRAPH_H = 260;
1834
3504
  var GRAPH_PAD = 28;
@@ -1877,23 +3547,23 @@ function buildHead(headClass) {
1877
3547
  const head = h("button", headClass);
1878
3548
  head.type = "button";
1879
3549
  head.setAttribute("aria-expanded", "false");
1880
- const iconEl = h("span", "ai-item-icon");
3550
+ const iconEl = h("span", "icen-ai-item-icon");
1881
3551
  iconEl.setAttribute("aria-hidden", "true");
1882
- const main = h("span", "ai-item-main");
1883
- const titleEl = h("span", "ai-item-title");
1884
- const subEl = h("span", "ai-item-sub");
1885
- const statusEl = h("span", "ai-item-status");
3552
+ const main = h("span", "icen-ai-item-main");
3553
+ const titleEl = h("span", "icen-ai-item-title");
3554
+ const subEl = h("span", "icen-ai-item-sub");
3555
+ const statusEl = h("span", "icen-ai-item-status");
1886
3556
  statusEl.setAttribute("role", "img");
1887
- const metaEl = h("span", "ai-item-meta");
3557
+ const metaEl = h("span", "icen-ai-item-meta");
1888
3558
  main.append(titleEl, subEl);
1889
3559
  head.append(iconEl, main, statusEl, metaEl);
1890
3560
  return { head, iconEl, titleEl, subEl, statusEl, metaEl };
1891
3561
  }
1892
3562
  function buildIo(label) {
1893
- const root = h("div", "ai-tool-io");
1894
- root.append(h("div", "ai-tool-io-label", label));
1895
- const pre = h("pre", "ai-tool-io-content");
1896
- const media = h("div", "ai-tool-io-media");
3563
+ const root = h("div", "icen-ai-tool-io");
3564
+ root.append(h("div", "icen-ai-tool-io-label", label));
3565
+ const pre = h("pre", "icen-ai-tool-io-content");
3566
+ const media = h("div", "icen-ai-tool-io-media");
1897
3567
  media.hidden = true;
1898
3568
  root.append(pre, media);
1899
3569
  return { root, pre, media };
@@ -1902,9 +3572,9 @@ function chartSpecOf(value) {
1902
3572
  if (!value || typeof value !== "object" || Array.isArray(value)) return null;
1903
3573
  const v = value;
1904
3574
  if (v.type === "chart" && v.spec && typeof v.spec === "object") return v.spec;
1905
- const t = typeof v.type === "string" ? v.type : void 0;
3575
+ const t2 = typeof v.type === "string" ? v.type : void 0;
1906
3576
  const looksChart = Array.isArray(v.series) || Array.isArray(v.segments) || Array.isArray(v.points) || Array.isArray(v.dates) || Array.isArray(v.labels) && Array.isArray(v.values);
1907
- if (looksChart && (t === void 0 || typeof t === "string")) return v;
3577
+ if (looksChart && (t2 === void 0 || typeof t2 === "string")) return v;
1908
3578
  return null;
1909
3579
  }
1910
3580
  function setIo(io, value, allowChart = true) {
@@ -1914,7 +3584,7 @@ function setIo(io, value, allowChart = true) {
1914
3584
  io.pre.hidden = true;
1915
3585
  io.media.replaceChildren();
1916
3586
  const holder = document.createElement("div");
1917
- holder.className = "ai-tool-io-chart";
3587
+ holder.className = "icen-ai-tool-io-chart";
1918
3588
  io.media.appendChild(holder);
1919
3589
  renderChart(holder, chartSpec);
1920
3590
  io.media.hidden = false;
@@ -1950,29 +3620,33 @@ function defaultExpanded(m) {
1950
3620
  return false;
1951
3621
  }
1952
3622
  function buildApproval() {
1953
- const root = h("div", "ai-tool-approval");
1954
- const reason = h("div", "ai-tool-approval-reason");
3623
+ const root = h("div", "icen-ai-tool-approval");
3624
+ const reason = h("div", "icen-ai-tool-approval-reason");
1955
3625
  reason.hidden = true;
1956
- const allow = h("button", "btn btn-sm btn-primary", "\u5141\u8BB8");
3626
+ const allow = h("button", "icen-btn icen-btn-sm icen-btn-primary", t("aiTool.allow"));
1957
3627
  allow.type = "button";
1958
- allow.setAttribute("data-ai-approve", "");
1959
- const deny = h("button", "btn btn-sm", "\u62D2\u7EDD");
3628
+ allow.setAttribute("data-icen-ai-approve", "");
3629
+ const deny = h("button", "icen-btn icen-btn-sm", t("aiTool.reject"));
1960
3630
  deny.type = "button";
1961
- deny.setAttribute("data-ai-reject", "");
3631
+ deny.setAttribute("data-icen-ai-reject", "");
1962
3632
  root.append(reason, allow, deny);
1963
3633
  return { root, reason };
1964
3634
  }
1965
3635
  function applyTint(item, model) {
1966
3636
  const tint = getAiKind(model.kind).tint;
1967
- if (tint) item.style.setProperty("--ai-item-tint", `var(--token-${tint})`);
1968
- else item.style.removeProperty("--ai-item-tint");
3637
+ if (tint) {
3638
+ const slot = tint === "muted" ? "text-muted" : tint;
3639
+ item.style.setProperty("--ai-item-tint", `var(--icen-token-${slot})`);
3640
+ } else {
3641
+ item.style.removeProperty("--ai-item-tint");
3642
+ }
1969
3643
  }
1970
3644
  function applyKindVisual(parts, model) {
1971
3645
  const kind = getAiKind(model.kind);
1972
3646
  parts.titleEl.textContent = kind.label || model.name;
1973
3647
  parts.iconEl.replaceChildren();
1974
- const svg2 = svgIcon(kind.icon);
1975
- if (svg2) parts.iconEl.append(svg2);
3648
+ const svg = svgIcon(kind.icon);
3649
+ if (svg) parts.iconEl.append(svg);
1976
3650
  const sub = summarizeInput(model);
1977
3651
  parts.subEl.textContent = sub;
1978
3652
  parts.subEl.hidden = !sub;
@@ -1987,15 +3661,15 @@ function renderAiToolCall(el, model) {
1987
3661
  return { el, update: () => void 0 };
1988
3662
  }
1989
3663
  const item = el;
1990
- let current = model;
1991
- item.className = `ai-tool ai-tool--${model.kind}`;
1992
- item.dataset.aiId = model.id;
1993
- item.dataset.aiKind = model.kind;
1994
- const parts = buildHead("ai-tool-head");
1995
- const body = h("div", "ai-tool-body");
3664
+ let current2 = model;
3665
+ item.className = `icen-ai-tool icen-ai-tool--${model.kind}`;
3666
+ item.dataset.icenAiId = model.id;
3667
+ item.dataset.icenAiKind = model.kind;
3668
+ const parts = buildHead("icen-ai-tool-head");
3669
+ const body = h("div", "icen-ai-tool-body");
1996
3670
  body.hidden = true;
1997
- const inputIo = buildIo("\u8F93\u5165");
1998
- const outputIo = buildIo("\u8F93\u51FA");
3671
+ const inputIo = buildIo(t("common.input"));
3672
+ const outputIo = buildIo(t("common.output"));
1999
3673
  const approval = buildApproval();
2000
3674
  body.append(inputIo.root, outputIo.root, approval.root);
2001
3675
  item.append(parts.head, body);
@@ -2019,12 +3693,12 @@ function renderAiToolCall(el, model) {
2019
3693
  approval.reason.hidden = !reason;
2020
3694
  if (!item.dataset.aiUserToggled && defaultExpanded(m)) setOpen(true);
2021
3695
  };
2022
- apply(current);
3696
+ apply(current2);
2023
3697
  return {
2024
3698
  el: item,
2025
3699
  update(patch) {
2026
- current = { ...current, ...patch };
2027
- apply(current);
3700
+ current2 = { ...current2, ...patch };
3701
+ apply(current2);
2028
3702
  }
2029
3703
  };
2030
3704
  }
@@ -2033,15 +3707,15 @@ function renderAiSubagent(el, model) {
2033
3707
  return { el, update: () => void 0 };
2034
3708
  }
2035
3709
  const item = el;
2036
- let current = model;
2037
- item.className = "ai-subagent";
2038
- item.dataset.aiId = model.id;
2039
- item.dataset.aiKind = model.kind;
2040
- const parts = buildHead("ai-subagent-head");
2041
- const body = h("div", "ai-subagent-body");
3710
+ let current2 = model;
3711
+ item.className = "icen-ai-subagent";
3712
+ item.dataset.icenAiId = model.id;
3713
+ item.dataset.icenAiKind = model.kind;
3714
+ const parts = buildHead("icen-ai-subagent-head");
3715
+ const body = h("div", "icen-ai-subagent-body");
2042
3716
  body.hidden = true;
2043
- const stream = h("div", "ai-subagent-stream");
2044
- const result = h("div", "ai-subagent-result");
3717
+ const stream = h("div", "icen-ai-subagent-stream");
3718
+ const result = h("div", "icen-ai-subagent-result");
2045
3719
  result.hidden = true;
2046
3720
  body.append(stream, result);
2047
3721
  item.append(parts.head, body);
@@ -2081,7 +3755,7 @@ function renderAiSubagent(el, model) {
2081
3755
  applyTint(item, m);
2082
3756
  applyKindVisual(parts, m);
2083
3757
  const steps = m.activities?.length ?? 0;
2084
- const meta = [m.durationMs != null ? formatDuration(m.durationMs) : "", steps > 0 ? `${steps} \u6B65` : ""].filter(Boolean).join(" \xB7 ");
3758
+ const meta = [m.durationMs != null ? formatDuration(m.durationMs) : "", steps > 0 ? t("common.steps", { p0: steps }) : ""].filter(Boolean).join(" \xB7 ");
2085
3759
  applyStatusMeta(parts, m.status, meta);
2086
3760
  renderActivities(m.activities);
2087
3761
  const receipt = compactValue(m.output);
@@ -2089,12 +3763,12 @@ function renderAiSubagent(el, model) {
2089
3763
  result.hidden = !receipt;
2090
3764
  if (!item.dataset.aiUserToggled && defaultExpanded(m)) setOpen(true);
2091
3765
  };
2092
- apply(current);
3766
+ apply(current2);
2093
3767
  return {
2094
3768
  el: item,
2095
3769
  update(patch) {
2096
- current = { ...current, ...patch };
2097
- apply(current);
3770
+ current2 = { ...current2, ...patch };
3771
+ apply(current2);
2098
3772
  }
2099
3773
  };
2100
3774
  }
@@ -2103,8 +3777,8 @@ function setupItem(item, kind) {
2103
3777
  const flag = kind === "tool" ? "__icenAiToolInit" : "__icenAiSubagentInit";
2104
3778
  if (marked[flag]) return () => void 0;
2105
3779
  marked[flag] = true;
2106
- const headClass = kind === "tool" ? ".ai-tool-head" : ".ai-subagent-head";
2107
- const bodyClass = kind === "tool" ? ".ai-tool-body" : ".ai-subagent-body";
3780
+ const headClass = kind === "tool" ? ".icen-ai-tool-head" : ".icen-ai-subagent-head";
3781
+ const bodyClass = kind === "tool" ? ".icen-ai-tool-body" : ".icen-ai-subagent-body";
2108
3782
  const head = item.querySelector(`:scope > ${headClass}`);
2109
3783
  const body = item.querySelector(`:scope > ${bodyClass}`);
2110
3784
  const setOpen = (open, fire = true) => {
@@ -2117,25 +3791,25 @@ function setupItem(item, kind) {
2117
3791
  const onCardClick = (ev) => {
2118
3792
  const target = ev.target;
2119
3793
  if (!(target instanceof Element)) return;
2120
- const ownerOf = (node) => node.closest(".ai-tool, .ai-subagent");
2121
- const approveBtn = target.closest("[data-ai-approve]");
3794
+ const ownerOf = (node) => node.closest(".icen-ai-tool, .icen-ai-subagent");
3795
+ const approveBtn = target.closest("[data-icen-ai-approve]");
2122
3796
  if (approveBtn && ownerOf(approveBtn) === item) {
2123
- emitIcen(item, "icen:ai-approve", { id: item.dataset.aiId ?? "", kind: item.dataset.aiKind ?? "" });
3797
+ emitIcen(item, "icen:ai-approve", { id: item.dataset.icenAiId ?? "", kind: item.dataset.icenAiKind ?? "" });
2124
3798
  return;
2125
3799
  }
2126
- const rejectBtn = target.closest("[data-ai-reject]");
3800
+ const rejectBtn = target.closest("[data-icen-ai-reject]");
2127
3801
  if (rejectBtn && ownerOf(rejectBtn) === item) {
2128
- emitIcen(item, "icen:ai-reject", { id: item.dataset.aiId ?? "", kind: item.dataset.aiKind ?? "" });
3802
+ emitIcen(item, "icen:ai-reject", { id: item.dataset.icenAiId ?? "", kind: item.dataset.icenAiKind ?? "" });
2129
3803
  return;
2130
3804
  }
2131
- const headEl = target.closest(".ai-tool-head, .ai-subagent-head");
3805
+ const headEl = target.closest(".icen-ai-tool-head, .icen-ai-subagent-head");
2132
3806
  if (!headEl || ownerOf(headEl) !== item || !head) return;
2133
3807
  item.dataset.aiUserToggled = "1";
2134
3808
  setOpen(head.getAttribute("aria-expanded") !== "true");
2135
3809
  };
2136
3810
  item.addEventListener("click", onCardClick);
2137
3811
  if (body?.hidden) {
2138
- const kindName = item.dataset.aiKind ?? "";
3812
+ const kindName = item.dataset.icenAiKind ?? "";
2139
3813
  const isErr = item.classList.contains("is-error");
2140
3814
  const isApproval = item.classList.contains("is-approval");
2141
3815
  if (isErr || isApproval || kindName === "chart") {
@@ -2157,14 +3831,14 @@ function initItems(root, selector, kind) {
2157
3831
  return items.map((item) => setupItem(item, kind));
2158
3832
  }
2159
3833
  function initAiTool(root) {
2160
- const cleanups = initItems(root, ".ai-tool", "tool");
3834
+ const cleanups = initItems(root, ".icen-ai-tool", "tool");
2161
3835
  return () => {
2162
3836
  for (const fn of cleanups) fn();
2163
3837
  cleanups.length = 0;
2164
3838
  };
2165
3839
  }
2166
3840
  function initAiSubagent(root) {
2167
- const cleanups = initItems(root, ".ai-subagent", "subagent");
3841
+ const cleanups = initItems(root, ".icen-ai-subagent", "subagent");
2168
3842
  return () => {
2169
3843
  for (const fn of cleanups) fn();
2170
3844
  cleanups.length = 0;