@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,52 +1,1008 @@
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
- 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>`;
3
- var ICON_TERMINAL = svg('<path d="m4 17 6-6-6-6"/><path d="M12 19h8"/>');
4
- var ICON_FILE = svg(
5
- '<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"/>'
6
- );
7
- var ICON_FILE_PEN = svg(
8
- '<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"/>'
9
- );
10
- var ICON_FILE_PLUS = svg(
11
- '<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"/>'
12
- );
13
- var ICON_TRASH = svg(
14
- '<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"/>'
15
- );
16
- var ICON_SEARCH = svg('<circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/>');
17
- var ICON_FOLDER_SEARCH = svg(
18
- '<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"/>'
19
- );
20
- var ICON_SCAN_SEARCH = svg(
21
- '<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"/>'
22
- );
23
- var ICON_GLOBE = svg(
24
- '<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"/>'
25
- );
26
- var ICON_DOWNLOAD = svg(
27
- '<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"/>'
28
- );
29
- var ICON_BLOCKS = svg(
30
- '<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"/>'
31
- );
32
- var ICON_ZAP = svg(
33
- '<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"/>'
34
- );
35
- var ICON_LIST = svg(
36
- '<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"/>'
37
- );
38
- var ICON_LIST_CHECKS = svg(
39
- '<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"/>'
40
- );
41
- var ICON_BOT = svg(
42
- '<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"/>'
43
- );
44
- var ICON_CHART = svg(
45
- '<path d="M3 3v18h18"/><path d="M7 15l4-6 3 4 5-8"/>'
46
- );
47
- var ICON_FILE_TEXT = svg(
48
- '<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"/>'
49
- );
989
+ var ICON_TERMINAL = iconHTML("terminal");
990
+ var ICON_FILE = iconHTML("file");
991
+ var ICON_FILE_PEN = iconHTML("edit");
992
+ var ICON_FILE_PLUS = iconHTML("plus");
993
+ var ICON_TRASH = iconHTML("trash");
994
+ var ICON_SEARCH = iconHTML("search");
995
+ var ICON_FOLDER_SEARCH = iconHTML("folder");
996
+ var ICON_SCAN_SEARCH = iconHTML("search");
997
+ var ICON_GLOBE = iconHTML("globe");
998
+ var ICON_DOWNLOAD = iconHTML("download");
999
+ var ICON_BLOCKS = iconHTML("server");
1000
+ var ICON_ZAP = iconHTML("sparkle");
1001
+ var ICON_LIST = iconHTML("list");
1002
+ var ICON_LIST_CHECKS = iconHTML("list");
1003
+ var ICON_BOT = iconHTML("agent");
1004
+ var ICON_CHART = iconHTML("chart-line");
1005
+ var ICON_FILE_TEXT = iconHTML("document");
50
1006
  function isObj(v) {
51
1007
  return typeof v === "object" && v !== null;
52
1008
  }
@@ -96,86 +1052,58 @@ var sum = (fn) => {
96
1052
  return (input) => fn(input) ?? "";
97
1053
  };
98
1054
  var BUILTIN_KINDS = {
99
- shell: { label: "\u547D\u4EE4", icon: ICON_TERMINAL, tint: "accent", summarize: sum(summarizeShell) },
100
- read: { label: "\u8BFB\u53D6", icon: ICON_FILE, tint: "info", summarize: sum(summarizeRead) },
101
- edit: { label: "\u7F16\u8F91", icon: ICON_FILE_PEN, tint: "warning", summarize: sum(summarizePath) },
102
- write: { label: "\u5199\u5165", icon: ICON_FILE_PLUS, tint: "warning", summarize: sum(summarizePath) },
103
- rm: { label: "\u5220\u9664", icon: ICON_TRASH, tint: "error", summarize: sum(summarizePath) },
104
- grep: { label: "\u641C\u7D22", icon: ICON_SEARCH, tint: "info", summarize: sum(summarizeGrep) },
105
- glob: { label: "\u5339\u914D", icon: ICON_FOLDER_SEARCH, tint: "info", summarize: sum((i) => pickStr(i, ["pattern", "glob", "path"])) },
106
- browser: { label: "\u6D4F\u89C8", icon: ICON_GLOBE, tint: "accent", summarize: sum((i) => pickStr(i, ["url", "uri", "target"])) },
107
- search: { label: "\u68C0\u7D22", icon: ICON_SCAN_SEARCH, tint: "accent", summarize: sum((i) => pickStr(i, ["query", "q", "pattern"])) },
108
- fetch: { label: "\u8BF7\u6C42", icon: ICON_DOWNLOAD, tint: "info", summarize: sum((i) => pickStr(i, ["url", "uri", "endpoint"])) },
1055
+ shell: { label: t("aiCore.kindShell"), icon: ICON_TERMINAL, tint: "accent", summarize: sum(summarizeShell) },
1056
+ read: { label: t("aiCore.kindRead"), icon: ICON_FILE, tint: "info", summarize: sum(summarizeRead) },
1057
+ edit: { label: t("aiCore.kindEdit"), icon: ICON_FILE_PEN, tint: "warning", summarize: sum(summarizePath) },
1058
+ write: { label: t("aiCore.kindWrite"), icon: ICON_FILE_PLUS, tint: "warning", summarize: sum(summarizePath) },
1059
+ rm: { label: t("aiCore.kindDelete"), icon: ICON_TRASH, tint: "error", summarize: sum(summarizePath) },
1060
+ grep: { label: t("aiCore.kindGrep"), icon: ICON_SEARCH, tint: "info", summarize: sum(summarizeGrep) },
1061
+ glob: { label: t("aiCore.kindGlob"), icon: ICON_FOLDER_SEARCH, tint: "info", summarize: sum((i) => pickStr(i, ["pattern", "glob", "path"])) },
1062
+ browser: { label: t("aiCore.kindBrowser"), icon: ICON_GLOBE, tint: "accent", summarize: sum((i) => pickStr(i, ["url", "uri", "target"])) },
1063
+ search: { label: t("aiCore.kindSearch"), icon: ICON_SCAN_SEARCH, tint: "accent", summarize: sum((i) => pickStr(i, ["query", "q", "pattern"])) },
1064
+ fetch: { label: t("aiCore.kindFetch"), icon: ICON_DOWNLOAD, tint: "info", summarize: sum((i) => pickStr(i, ["url", "uri", "endpoint"])) },
109
1065
  mcp: { label: "MCP", icon: ICON_BLOCKS, tint: "muted", summarize: sum((i) => pickStr(i, ["tool", "method", "name"])) },
110
- skill: { label: "\u6280\u80FD", icon: ICON_ZAP, tint: "accent", summarize: sum((i) => pickStr(i, ["skill", "name", "command"])) },
1066
+ skill: { label: t("aiCore.kindSkill"), icon: ICON_ZAP, tint: "accent", summarize: sum((i) => pickStr(i, ["skill", "name", "command"])) },
111
1067
  todo: {
112
- label: "\u5F85\u529E",
1068
+ label: t("aiCore.kindTodo"),
113
1069
  icon: ICON_LIST,
114
1070
  tint: "info",
115
1071
  summarize: sum((input) => {
116
1072
  const items = input && typeof input === "object" && Array.isArray(input.items) ? input.items : Array.isArray(input) ? input : [];
117
1073
  const done = items.filter((it) => it?.status === "done").length;
118
- return items.length > 0 ? `${done}/${items.length} \u5B8C\u6210` : "";
1074
+ return items.length > 0 ? t("aiCore.todoProgress", { p0: done, p1: items.length }) : "";
119
1075
  })
120
1076
  },
121
- plan: { label: "\u8BA1\u5212", icon: ICON_LIST_CHECKS, tint: "info" },
122
- subagent: { label: "\u5B50\u4EE3\u7406", icon: ICON_BOT, tint: "accent", summarize: sum((i) => pickStr(i, ["task", "description", "prompt", "message", "subagent_type"])) },
123
- note: { label: "\u7B14\u8BB0", icon: ICON_FILE_TEXT, tint: "muted" },
124
- chart: { label: "\u56FE\u8868", icon: ICON_CHART, tint: "info", summarize: sum((i) => pickStr(i, ["title", "name"])) }
1077
+ plan: { label: t("aiCore.kindPlan"), icon: ICON_LIST_CHECKS, tint: "info" },
1078
+ subagent: { label: t("aiCore.kindSubagent"), icon: ICON_BOT, tint: "accent", summarize: sum((i) => pickStr(i, ["task", "description", "prompt", "message", "subagent_type"])) },
1079
+ note: { label: t("aiCore.kindNote"), icon: ICON_FILE_TEXT, tint: "muted" },
1080
+ chart: { label: t("aiCore.kindChart"), icon: ICON_CHART, tint: "info", summarize: sum((i) => pickStr(i, ["title", "name"])) }
125
1081
  };
126
1082
  var kindRegistry = new Map(Object.entries(BUILTIN_KINDS));
127
1083
  function h(tag, className, text) {
1084
+ 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");
128
1085
  const node = document.createElement(tag);
129
1086
  if (className) node.className = className;
130
1087
  if (text != null) node.textContent = text;
131
1088
  return node;
132
1089
  }
133
- function svgIcon(svg2) {
134
- if (typeof document === "undefined" || typeof DOMParser === "undefined") return null;
135
- let parsed;
136
- try {
137
- parsed = new DOMParser().parseFromString(svg2, "image/svg+xml");
138
- } catch {
139
- return null;
140
- }
141
- const root = parsed.documentElement;
142
- if (!root || root.tagName.toLowerCase() !== "svg" || parsed.querySelector("parsererror")) {
143
- return null;
144
- }
145
- const sanitize = (el) => {
146
- for (const attr of Array.from(el.attributes)) {
147
- const name = attr.name.toLowerCase();
148
- if (name.startsWith("on")) el.removeAttribute(attr.name);
149
- if ((name === "href" || name === "xlink:href") && attr.value.trim().toLowerCase().startsWith("javascript:")) {
150
- el.removeAttribute(attr.name);
151
- }
152
- }
153
- for (const child of Array.from(el.children)) {
154
- const tag = child.tagName.toLowerCase();
155
- if (tag === "script" || tag === "foreignobject") {
156
- child.remove();
157
- continue;
158
- }
159
- sanitize(child);
160
- }
161
- };
162
- sanitize(root);
163
- return document.importNode(root, true);
1090
+ function svgIcon(svg) {
1091
+ return parseSvg(svg);
164
1092
  }
165
1093
 
166
1094
  // src/behaviors/kb-core.ts
167
1095
  var ic = (label, d) => ({ label, icon: `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">${d}</svg>` });
168
1096
  var BUILTIN_SOURCE_TYPES = {
169
- doc: ic("\u6587\u6863", '<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><path d="M14 2v6h6"/>'),
170
- web: ic("\u7F51\u9875", '<circle cx="12" cy="12" r="10"/><path d="M2 12h20"/><path d="M12 2a15 15 0 0 1 0 20 15 15 0 0 1 0-20z"/>'),
171
- wiki: ic("\u77E5\u8BC6\u5E93", '<path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/>'),
172
- sheet: ic("\u8868\u683C", '<rect x="3" y="3" width="18" height="18" rx="2"/><path d="M3 9h18M3 15h18M9 3v18M15 3v18"/>'),
173
- db: ic("\u6570\u636E\u5E93", '<ellipse cx="12" cy="5" rx="9" ry="3"/><path d="M3 5v14c0 1.7 4 3 9 3s9-1.3 9-3V5"/><path d="M3 12c0 1.7 4 3 9 3s9-1.3 9-3"/>'),
174
- ticket: ic("\u5DE5\u5355", '<path d="M3 9V7a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2v2a2 2 0 0 0 0 6v2a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-2a2 2 0 0 0 0-6z"/><path d="M13 5v14"/>'),
175
- code: ic("\u4EE3\u7801", '<path d="m16 18 6-6-6-6"/><path d="m8 6-6 6 6 6"/>'),
176
- api: ic("\u63A5\u53E3", '<path d="M4 7a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v3a2 2 0 0 0 0 4v3a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2v-3a2 2 0 0 0 0-4z"/>'),
177
- image: ic("\u56FE\u7247", '<rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="9" cy="9" r="2"/><path d="m21 15-4.6-4.6a2 2 0 0 0-2.8 0L3 21"/>'),
178
- mail: ic("\u90AE\u4EF6", '<rect x="2" y="4" width="20" height="16" rx="2"/><path d="m22 7-10 7L2 7"/>')
1097
+ doc: ic(t("kbCore.typeDocument"), '<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><path d="M14 2v6h6"/>'),
1098
+ web: ic(t("kbCore.typeWebpage"), '<circle cx="12" cy="12" r="10"/><path d="M2 12h20"/><path d="M12 2a15 15 0 0 1 0 20 15 15 0 0 1 0-20z"/>'),
1099
+ wiki: ic(t("kbCore.typeKb"), '<path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/>'),
1100
+ sheet: ic(t("kbCore.typeTable"), '<rect x="3" y="3" width="18" height="18" rx="2"/><path d="M3 9h18M3 15h18M9 3v18M15 3v18"/>'),
1101
+ db: ic(t("kbCore.typeDatabase"), '<ellipse cx="12" cy="5" rx="9" ry="3"/><path d="M3 5v14c0 1.7 4 3 9 3s9-1.3 9-3V5"/><path d="M3 12c0 1.7 4 3 9 3s9-1.3 9-3"/>'),
1102
+ ticket: ic(t("kbCore.typeTicket"), '<path d="M3 9V7a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2v2a2 2 0 0 0 0 6v2a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-2a2 2 0 0 0 0-6z"/><path d="M13 5v14"/>'),
1103
+ code: ic(t("kbCore.typeCode"), '<path d="m16 18 6-6-6-6"/><path d="m8 6-6 6 6 6"/>'),
1104
+ api: ic(t("kbCore.typeApi"), '<path d="M4 7a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v3a2 2 0 0 0 0 4v3a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2v-3a2 2 0 0 0 0-4z"/>'),
1105
+ image: ic(t("kbCore.typeImage"), '<rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="9" cy="9" r="2"/><path d="m21 15-4.6-4.6a2 2 0 0 0-2.8 0L3 21"/>'),
1106
+ mail: ic(t("kbCore.typeEmail"), '<rect x="2" y="4" width="20" height="16" rx="2"/><path d="m22 7-10 7L2 7"/>')
179
1107
  };
180
1108
  var sourceTypeRegistry = new Map(Object.entries(BUILTIN_SOURCE_TYPES));
181
1109
  var CITE_RE = /\[(\d{1,3})\]/g;
@@ -193,6 +1121,14 @@ function parseInlineCitations(text) {
193
1121
  if (last < text.length) out.push({ text: text.slice(last) });
194
1122
  return out;
195
1123
  }
1124
+ var RUN_LABELS = {
1125
+ unstart: t("kbCore.runUnstarted"),
1126
+ queued: t("kbCore.runQueued"),
1127
+ running: t("kbCore.runRunning"),
1128
+ cancel: t("kbCore.runCancelled"),
1129
+ done: t("kbCore.runDone"),
1130
+ fail: t("kbCore.runFailed")
1131
+ };
196
1132
  function normalizeQueryResult(raw) {
197
1133
  const columns = Array.isArray(raw.columns) ? raw.columns.map((c) => typeof c === "string" ? { name: c } : { name: String(c.name ?? ""), type: c.type }) : [];
198
1134
  return {
@@ -206,19 +1142,23 @@ function normalizeQueryResult(raw) {
206
1142
  exportFormats: Array.isArray(raw.exportFormats) ? raw.exportFormats.map(String) : void 0
207
1143
  };
208
1144
  }
1145
+ var SPAN_LABELS = {
1146
+ retrieval: t("kbCore.stageRetrieval"),
1147
+ generation: t("kbCore.stageGeneration"),
1148
+ rerank: t("kbCore.stageRerank"),
1149
+ embed: t("kbCore.stageEmbed"),
1150
+ tool: t("kbCore.stageTool"),
1151
+ guard: t("kbCore.stageGuard"),
1152
+ chunk: t("kbCore.stageChunk"),
1153
+ query: t("kbCore.stageQuery"),
1154
+ agent: t("kbCore.stageAgent")
1155
+ };
209
1156
  function formatCount(n) {
210
1157
  if (n == null || !Number.isFinite(n)) return "\u2014";
211
1158
  if (Math.abs(n) >= 1e4) return `${(n / 1e3).toFixed(1)}k`;
212
1159
  return n.toLocaleString("en-US");
213
1160
  }
214
1161
 
215
- // src/behaviors/events.ts
216
- function emitIcen(source, type, detail) {
217
- return source.dispatchEvent(
218
- new CustomEvent(type, { detail, bubbles: true, composed: true, cancelable: true })
219
- );
220
- }
221
-
222
1162
  // src/behaviors/kb-clarify.ts
223
1163
  var ICON_HELP = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M9.1 9a3 3 0 0 1 5.8 1c0 2-3 2.4-3 4"/><path d="M12 17.5h.01"/></svg>';
224
1164
  function toClarification(raw) {
@@ -235,48 +1175,57 @@ function renderKbClarify(el, c, opts) {
235
1175
  if (typeof document === "undefined") return el;
236
1176
  const clar = toClarification(c);
237
1177
  el.textContent = "";
238
- const root = h("div", "kb-clarify");
239
- if (clar.id) root.dataset.clarifyId = clar.id;
240
- const q = h("div", "kb-clarify-q");
241
- const iconBox = h("span", "kb-clarify-qicon");
242
- const svg2 = svgIcon(ICON_HELP);
243
- if (svg2) iconBox.appendChild(svg2);
1178
+ const root = h("div", "icen-kb-clarify");
1179
+ if (clar.id) root.dataset.icenClarifyId = clar.id;
1180
+ const q = h("div", "icen-kb-clarify-q");
1181
+ const iconBox = h("span", "icen-kb-clarify-qicon");
1182
+ const svg = svgIcon(ICON_HELP);
1183
+ if (svg) iconBox.appendChild(svg);
244
1184
  q.appendChild(iconBox);
245
- q.appendChild(h("span", "kb-clarify-qtext", clar.question));
1185
+ q.appendChild(h("span", "icen-kb-clarify-qtext", clar.question));
246
1186
  root.appendChild(q);
247
- const optsWrap = h("div", "kb-clarify-opts");
248
- const resolved = h("div", "kb-clarify-resolved");
1187
+ const optsWrap = h("div", "icen-kb-clarify-opts");
1188
+ const resolved = h("div", "icen-kb-clarify-resolved");
249
1189
  resolved.hidden = true;
250
1190
  const pick = (btn) => {
251
1191
  if (root.classList.contains("is-answered")) return;
252
1192
  root.classList.add("is-answered");
253
1193
  btn.classList.add("is-picked");
254
- Array.from(optsWrap.querySelectorAll(".kb-clarify-opt")).forEach((b) => {
1194
+ Array.from(optsWrap.querySelectorAll(".icen-kb-clarify-opt")).forEach((b) => {
255
1195
  if (b !== btn) b.disabled = true;
256
1196
  });
257
1197
  resolved.textContent = "";
258
- resolved.appendChild(document.createTextNode("\u5DF2\u89E3\u6790\uFF1A"));
259
- resolved.appendChild(h("b", "kb-clarify-picked", btn.dataset.label ?? ""));
1198
+ resolved.appendChild(document.createTextNode(t("kbClarify.parsedPrefix")));
1199
+ resolved.appendChild(h("b", "icen-kb-clarify-picked", btn.dataset.icenLabel ?? ""));
260
1200
  resolved.hidden = false;
261
- const answer = { id: clar.id, value: btn.dataset.value ?? "", label: btn.dataset.label ?? "" };
1201
+ const answer = { id: clar.id, value: btn.dataset.icenValue ?? "", label: btn.dataset.icenLabel ?? "" };
262
1202
  emitIcen(btn, "icen:kb-clarify-answer", answer);
263
1203
  opts?.onAnswer?.(answer);
264
1204
  };
265
1205
  for (const o of clar.options) {
266
- const btn = h("button", "kb-clarify-opt", o.label);
1206
+ const btn = h("button", "icen-kb-clarify-opt", o.label);
267
1207
  btn.type = "button";
268
- btn.dataset.value = o.value;
269
- btn.dataset.label = o.label;
1208
+ btn.dataset.icenValue = o.value;
1209
+ btn.dataset.icenLabel = o.label;
270
1210
  btn.addEventListener("click", () => pick(btn));
271
1211
  optsWrap.appendChild(btn);
272
1212
  }
273
1213
  if (optsWrap.children.length > 0) root.appendChild(optsWrap);
274
1214
  root.appendChild(resolved);
275
- if (clar.reason) root.appendChild(h("div", "kb-clarify-reason", clar.reason));
1215
+ if (clar.reason) root.appendChild(h("div", "icen-kb-clarify-reason", clar.reason));
276
1216
  el.appendChild(root);
277
1217
  return el;
278
1218
  }
279
1219
 
1220
+ // src/behaviors/url-safety.ts
1221
+ function safeUrl(uri) {
1222
+ const s = uri.replace(/[\t\n\r\0-\x1f\x7f]/g, "").trim().toLowerCase();
1223
+ if (!s) return void 0;
1224
+ if (s.startsWith("javascript:") || s.startsWith("vbscript:")) return void 0;
1225
+ if (/^data:\s*text\/html/.test(s)) return void 0;
1226
+ return uri;
1227
+ }
1228
+
280
1229
  // src/behaviors/kb-explain.ts
281
1230
  function toExplainFact(raw) {
282
1231
  const r = raw ?? {};
@@ -299,47 +1248,48 @@ function toExplainFact(raw) {
299
1248
  }
300
1249
  function renderGroup(label, items) {
301
1250
  if (!items?.length) return null;
302
- const group = h("div", "kb-explain-group");
303
- group.appendChild(h("span", "kb-explain-group-label", label));
304
- for (const item of items) group.appendChild(h("span", "kb-chip", item));
1251
+ const group = h("div", "icen-kb-explain-group");
1252
+ group.appendChild(h("span", "icen-kb-explain-group-label", label));
1253
+ for (const item of items) group.appendChild(h("span", "icen-kb-chip", item));
305
1254
  return group;
306
1255
  }
307
1256
  function renderKbExplain(el, fact) {
308
1257
  if (typeof document === "undefined") return el;
309
1258
  const f = toExplainFact(fact);
310
1259
  el.textContent = "";
311
- const root = h("div", "kb-explain");
312
- root.dataset.kbExplain = "";
1260
+ const root = h("div", "icen-kb-explain");
1261
+ root.dataset.icenKbExplain = "";
313
1262
  const count = (f.tables?.length ?? 0) + (f.columns?.length ?? 0) + (f.filters?.length ?? 0) + (f.aggregates?.length ?? 0) + (f.metrics?.length ?? 0);
314
- const head = h("button", "kb-fold-head kb-explain-head");
1263
+ const head = h("button", "icen-kb-fold-head icen-kb-explain-head");
315
1264
  head.type = "button";
316
1265
  head.setAttribute("aria-expanded", "false");
317
- head.appendChild(h("span", "kb-fold-caret", "\u25B8"));
318
- head.appendChild(h("span", "kb-explain-title", "\u8FD9\u4E2A\u6570\u5B57\u662F\u600E\u4E48\u7B97\u51FA\u6765\u7684"));
1266
+ head.appendChild(h("span", "icen-kb-fold-caret", "\u25B8"));
1267
+ head.appendChild(h("span", "icen-kb-explain-title", t("kbExplain.trigger")));
319
1268
  if (count > 0) {
320
- const countBox = h("span", "kb-num kb-explain-count", String(count));
321
- countBox.classList.add("kb-fold-count");
1269
+ const countBox = h("span", "icen-kb-num icen-kb-explain-count", String(count));
1270
+ countBox.classList.add("icen-kb-fold-count");
322
1271
  head.appendChild(countBox);
323
1272
  }
324
1273
  root.appendChild(head);
325
- const body = h("div", "kb-explain-body");
1274
+ const body = h("div", "icen-kb-explain-body");
326
1275
  body.hidden = true;
327
1276
  const groups = [
328
- renderGroup("\u8868", f.tables),
329
- renderGroup("\u5217", f.columns),
330
- renderGroup("\u7B5B\u9009", f.filters),
331
- renderGroup("\u805A\u5408", f.aggregates)
1277
+ renderGroup(t("kbExplain.groupTable"), f.tables),
1278
+ renderGroup(t("kbExplain.groupColumn"), f.columns),
1279
+ renderGroup(t("kbExplain.groupFilter"), f.filters),
1280
+ renderGroup(t("kbExplain.groupAgg"), f.aggregates)
332
1281
  ];
333
1282
  for (const g of groups) if (g) body.appendChild(g);
334
1283
  if (f.metrics?.length) {
335
- const metrics = h("div", "kb-explain-metrics");
1284
+ const metrics = h("div", "icen-kb-explain-metrics");
336
1285
  for (const m of f.metrics) {
337
- const row = h("div", "kb-explain-metric");
338
- row.appendChild(h("span", "kb-explain-metric-name", m.name));
1286
+ const row = h("div", "icen-kb-explain-metric");
1287
+ row.appendChild(h("span", "icen-kb-explain-metric-name", m.name));
339
1288
  if (m.ref) {
340
- if (!/^\s*(javascript|data|vbscript)\s*:/i.test(m.ref)) {
341
- const a = h("a", "kb-explain-metric-ref", "\u67E5\u770B\u53E3\u5F84");
342
- a.href = m.ref;
1289
+ const href = safeUrl(m.ref);
1290
+ if (href) {
1291
+ const a = h("a", "icen-kb-explain-metric-ref", t("kbExplain.viewDefinition"));
1292
+ a.href = href;
343
1293
  a.rel = "noopener";
344
1294
  row.appendChild(a);
345
1295
  }
@@ -349,7 +1299,7 @@ function renderKbExplain(el, fact) {
349
1299
  body.appendChild(metrics);
350
1300
  }
351
1301
  if (body.children.length === 0) {
352
- body.appendChild(h("div", "kb-empty", "\u6682\u65E0\u53E3\u5F84\u4FE1\u606F"));
1302
+ body.appendChild(h("div", "icen-kb-empty", t("kbExplain.empty")));
353
1303
  }
354
1304
  root.appendChild(body);
355
1305
  head.addEventListener("click", () => {
@@ -370,16 +1320,16 @@ function toneVar(tone = "accent") {
370
1320
  if (registered) return registered;
371
1321
  switch (tone) {
372
1322
  case "success":
373
- return "var(--token-success)";
1323
+ return "var(--icen-token-success)";
374
1324
  case "warning":
375
- return "var(--token-warning)";
1325
+ return "var(--icen-token-warning)";
376
1326
  case "error":
377
- return "var(--token-error)";
1327
+ return "var(--icen-token-error)";
378
1328
  case "muted":
379
- return "var(--token-text-faint)";
1329
+ return "var(--icen-token-text-faint)";
380
1330
  case "accent":
381
1331
  default:
382
- return "var(--token-accent)";
1332
+ return "var(--icen-token-accent)";
383
1333
  }
384
1334
  }
385
1335
  function fmt(opts, value) {
@@ -390,13 +1340,66 @@ function maxOf(values) {
390
1340
  for (const v of values) if (v > max) max = v;
391
1341
  return max;
392
1342
  }
393
- function sampleLabels(labels, max = 7) {
394
- if (labels.length <= max) return labels;
395
- const out = [];
396
- for (let i = 0; i < max; i++) {
397
- out.push(labels[Math.round(i * (labels.length - 1) / (max - 1))] ?? "");
1343
+ function pointLabelsRow(labels, width, pad) {
1344
+ const row = document.createElement("div");
1345
+ row.className = "icen-chart-labels icen-chart-labels--points";
1346
+ const count = Math.min(labels.length, Math.max(2, Math.min(7, Math.floor(width / 64))));
1347
+ const step = count > 1 ? (width - 2 * pad) / (count - 1) : width;
1348
+ for (let tick = 0; tick < count; tick++) {
1349
+ const index = count <= 1 ? 0 : Math.round(tick * (labels.length - 1) / (count - 1));
1350
+ const x = labels.length <= 1 ? width / 2 : pad + index / (labels.length - 1) * (width - 2 * pad);
1351
+ const span = document.createElement("span");
1352
+ span.textContent = labels[index] ?? "";
1353
+ span.title = span.textContent;
1354
+ span.dir = "auto";
1355
+ span.dataset.icenChartIndex = String(index);
1356
+ span.style.left = `${x / width * 100}%`;
1357
+ span.style.width = `${Math.max(0, Math.min(step * 0.9, 2 * x, 2 * (width - x)))}px`;
1358
+ row.appendChild(span);
398
1359
  }
399
- return out;
1360
+ return row;
1361
+ }
1362
+ function clampNum(v, lo, hi) {
1363
+ return Math.min(hi, Math.max(lo, v));
1364
+ }
1365
+ function lttb(points, threshold, getX, getY) {
1366
+ const len = points.length;
1367
+ const n = Math.floor(threshold);
1368
+ if (!Number.isFinite(n) || n < 3 || n >= len || len <= 3) return points;
1369
+ const sampled = new Array(n);
1370
+ sampled[0] = points[0];
1371
+ sampled[n - 1] = points[len - 1];
1372
+ const every = (len - 2) / (n - 2);
1373
+ let a = 0;
1374
+ for (let i = 0; i < n - 2; i++) {
1375
+ const avgStart = Math.floor((i + 1) * every) + 1;
1376
+ const avgEnd = Math.min(Math.floor((i + 2) * every) + 1, len);
1377
+ let avgX = 0;
1378
+ let avgY = 0;
1379
+ for (let j = avgStart; j < avgEnd; j++) {
1380
+ avgX += getX(points[j]);
1381
+ avgY += getY(points[j]);
1382
+ }
1383
+ const avgLen = Math.max(1, avgEnd - avgStart);
1384
+ avgX /= avgLen;
1385
+ avgY /= avgLen;
1386
+ const rangeStart = Math.floor(i * every) + 1;
1387
+ const rangeEnd = Math.min(Math.floor((i + 1) * every) + 1, len);
1388
+ const ax = getX(points[a]);
1389
+ const ay = getY(points[a]);
1390
+ let maxArea = -1;
1391
+ let nextA = rangeStart;
1392
+ for (let j = rangeStart; j < rangeEnd; j++) {
1393
+ const area = Math.abs((ax - avgX) * (getY(points[j]) - ay) - (ax - getX(points[j])) * (avgY - ay)) * 0.5;
1394
+ if (area > maxArea) {
1395
+ maxArea = area;
1396
+ nextA = j;
1397
+ }
1398
+ }
1399
+ sampled[i + 1] = points[nextA];
1400
+ a = nextA;
1401
+ }
1402
+ return sampled;
400
1403
  }
401
1404
  function svgEl(tag, attrs) {
402
1405
  const el = document.createElementNS(SVG_NS, tag);
@@ -405,28 +1408,28 @@ function svgEl(tag, attrs) {
405
1408
  }
406
1409
  function renderEmpty(el, label) {
407
1410
  const box = document.createElement("div");
408
- box.className = "chart-empty";
409
- box.textContent = label ?? "\u6682\u65E0\u6570\u636E";
1411
+ box.className = "icen-chart-empty";
1412
+ box.textContent = label ?? t("charts.noData");
410
1413
  el.appendChild(box);
411
1414
  }
412
1415
  function legendItem(label, valueText, tone) {
413
1416
  const row = document.createElement("div");
414
- row.className = "chart-legend-item";
1417
+ row.className = "icen-chart-legend-item";
415
1418
  const dot = document.createElement("span");
416
- dot.className = "chart-legend-dot";
1419
+ dot.className = "icen-chart-legend-dot";
417
1420
  if (tone) dot.style.setProperty("--chart-tone", toneVar(tone));
418
1421
  const name = document.createElement("span");
419
- name.className = "chart-legend-label";
1422
+ name.className = "icen-chart-legend-label";
420
1423
  name.textContent = label;
421
1424
  const val = document.createElement("span");
422
- val.className = "chart-legend-value";
1425
+ val.className = "icen-chart-legend-value";
423
1426
  val.textContent = valueText;
424
1427
  row.append(dot, name, val);
425
1428
  return row;
426
1429
  }
427
1430
  function labelsRow(labels) {
428
1431
  const row = document.createElement("div");
429
- row.className = "chart-labels";
1432
+ row.className = "icen-chart-labels";
430
1433
  for (const label of labels) {
431
1434
  const span = document.createElement("span");
432
1435
  span.textContent = label;
@@ -441,110 +1444,123 @@ function normalizeSeriesInput(opts) {
441
1444
  function toneOf(tone, seriesIndex) {
442
1445
  if (typeof tone === "string") return toneVar(tone);
443
1446
  if (typeof tone === "number") return paletteVar(tone);
444
- return seriesIndex > 0 ? paletteVar((seriesIndex - 1) % 6 + 1) : void 0;
1447
+ return seriesIndex > 0 ? paletteVar(seriesIndex % 6 + 1) : void 0;
445
1448
  }
446
1449
  var PALETTE_VARS = [
447
- "var(--token-accent)",
448
- "var(--token-accent-cold)",
449
- "var(--token-success)",
450
- "var(--token-warning)",
451
- "var(--token-info)",
452
- "color-mix(in srgb, var(--token-text) 50%, transparent)"
1450
+ "var(--icen-token-accent)",
1451
+ "var(--icen-token-accent-cold)",
1452
+ "var(--icen-token-success)",
1453
+ "var(--icen-token-warning)",
1454
+ "var(--icen-token-info)",
1455
+ "color-mix(in srgb, var(--icen-token-text) 50%, transparent)"
453
1456
  ];
454
1457
  function paletteVar(index) {
455
1458
  const i = ((Math.floor(index) - 1) % 6 + 6) % 6;
456
1459
  return PALETTE_VARS[i];
457
1460
  }
458
1461
  function setMarkData(node, data) {
459
- node.setAttribute("data-chart-mark", "1");
460
- if (data.index != null) node.setAttribute("data-chart-index", String(data.index));
461
- if (data.seriesIndex != null) node.setAttribute("data-chart-series", String(data.seriesIndex));
462
- if (data.seriesName != null) node.setAttribute("data-chart-series-name", String(data.seriesName));
463
- if (data.label != null) node.setAttribute("data-chart-label", String(data.label));
464
- if (data.value != null) node.setAttribute("data-chart-value", String(data.value));
1462
+ node.setAttribute("data-icen-chart-mark", "1");
1463
+ if (data.index != null) node.setAttribute("data-icen-chart-index", String(data.index));
1464
+ if (data.seriesIndex != null) node.setAttribute("data-icen-chart-series", String(data.seriesIndex));
1465
+ if (data.seriesName != null) node.setAttribute("data-icen-chart-series-name", String(data.seriesName));
1466
+ if (data.label != null) node.setAttribute("data-icen-chart-label", String(data.label));
1467
+ if (data.value != null) node.setAttribute("data-icen-chart-value", String(data.value));
465
1468
  }
466
1469
  function copyMarkData(target, source) {
467
1470
  for (const attr of Array.from(source.attributes)) {
468
- if (attr.name.startsWith("data-chart-")) target.setAttribute(attr.name, attr.value);
1471
+ if (attr.name.startsWith("data-icen-chart-")) target.setAttribute(attr.name, attr.value);
469
1472
  }
470
1473
  }
471
- 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>';
472
- 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>';
473
- function parseChartSvg(svg2) {
474
- try {
475
- const doc = new DOMParser().parseFromString(svg2, "image/svg+xml");
476
- const el = doc.documentElement;
477
- return el && el.tagName.toLowerCase() === "svg" && !doc.querySelector("parsererror") ? document.importNode(el, true) : null;
478
- } catch {
479
- return null;
480
- }
481
- }
482
- function withChrome(el, opts, hasLegend, paint, state) {
483
- if (el.dataset.chartBody != null) {
1474
+ function withChrome(el, opts, hasLegend, paint, state, extras) {
1475
+ if (el.dataset.icenChartBody != null) {
484
1476
  el.textContent = "";
485
1477
  paint(el);
486
1478
  return;
487
1479
  }
488
1480
  el.textContent = "";
489
1481
  const body = document.createElement("div");
490
- body.className = "chart-body";
491
- body.dataset.chartBody = "";
492
- if (!opts.title && !hasLegend) {
1482
+ body.className = "icen-chart-body";
1483
+ body.dataset.icenChartBody = "";
1484
+ const note = extras?.note ?? null;
1485
+ const onZoomReset = extras?.onZoomReset ?? null;
1486
+ if (!opts.title && !hasLegend && note == null && !onZoomReset) {
493
1487
  el.appendChild(body);
494
1488
  paint(body);
495
1489
  return;
496
1490
  }
497
1491
  let hidden = state && state.hidden != null ? state.hidden : opts.legend === false;
498
1492
  if (state) state.hidden = hidden;
499
- el.setAttribute("data-legend-hidden", String(hidden));
1493
+ el.setAttribute("data-icen-legend-hidden", String(hidden));
500
1494
  const head = document.createElement("div");
501
- head.className = "chart-head";
1495
+ head.className = "icen-chart-head";
502
1496
  const title = document.createElement("div");
503
- title.className = "chart-title";
1497
+ title.className = "icen-chart-title";
504
1498
  title.textContent = opts.title ?? "";
505
1499
  if (!opts.title) title.setAttribute("aria-hidden", "true");
1500
+ if (note != null) {
1501
+ const noteEl = document.createElement("span");
1502
+ noteEl.className = "icen-chart-note";
1503
+ noteEl.textContent = note;
1504
+ head.appendChild(noteEl);
1505
+ }
1506
+ if (onZoomReset) {
1507
+ const chip = document.createElement("button");
1508
+ chip.type = "button";
1509
+ chip.className = "icen-chart-zoom-reset";
1510
+ chip.textContent = t("charts.resetZoom");
1511
+ chip.addEventListener("click", onZoomReset);
1512
+ head.appendChild(chip);
1513
+ }
506
1514
  const eye = document.createElement("button");
507
1515
  eye.type = "button";
508
- eye.className = "chart-legend-eye";
509
- eye.dataset.chartLegendEye = "";
1516
+ eye.className = "icen-chart-legend-eye";
1517
+ eye.dataset.icenChartLegendEye = "";
510
1518
  const syncEye = () => {
511
- const nowHidden = el.getAttribute("data-legend-hidden") === "true";
1519
+ const nowHidden = el.getAttribute("data-icen-legend-hidden") === "true";
512
1520
  eye.setAttribute("aria-pressed", String(!nowHidden));
513
- eye.setAttribute("aria-label", nowHidden ? "\u663E\u793A\u56FE\u4F8B" : "\u9690\u85CF\u56FE\u4F8B");
514
- eye.setAttribute("title", nowHidden ? "\u663E\u793A\u56FE\u4F8B" : "\u9690\u85CF\u56FE\u4F8B");
515
- const icon = parseChartSvg(nowHidden ? CHART_EYE_OFF_SVG : CHART_EYE_SVG);
1521
+ eye.setAttribute("aria-label", nowHidden ? t("charts.showLegend") : t("charts.hideLegend"));
1522
+ eye.setAttribute("title", nowHidden ? t("charts.showLegend") : t("charts.hideLegend"));
1523
+ const icon = createIcon(nowHidden ? "eye-off" : "eye");
516
1524
  if (icon) eye.replaceChildren(icon);
517
1525
  };
518
1526
  eye.addEventListener("click", () => {
519
- const nowHidden = el.getAttribute("data-legend-hidden") === "true";
1527
+ const nowHidden = el.getAttribute("data-icen-legend-hidden") === "true";
520
1528
  hidden = !nowHidden;
521
1529
  if (state) state.hidden = hidden;
522
- el.setAttribute("data-legend-hidden", String(hidden));
1530
+ el.setAttribute("data-icen-legend-hidden", String(hidden));
523
1531
  syncEye();
524
1532
  emitIcen(el, "icen:chart-legend-visibility", { visible: hidden ? false : true });
525
1533
  });
526
1534
  syncEye();
527
- head.append(title, eye);
1535
+ if (hasLegend) head.append(title, eye);
1536
+ else head.append(title);
528
1537
  el.append(head, body);
529
1538
  paint(body);
530
1539
  }
1540
+ var hiddenLegendKeys = /* @__PURE__ */ new WeakMap();
531
1541
  function toggleLegend(items, scope) {
532
1542
  const legend = document.createElement("div");
533
- legend.className = "chart-legend chart-legend--toggle";
1543
+ legend.className = "icen-chart-legend icen-chart-legend--toggle";
1544
+ const owner = scope instanceof Element ? scope.closest("[data-icen-chart-body]")?.parentElement ?? scope : null;
1545
+ const hidden = owner ? hiddenLegendKeys.get(owner) ?? /* @__PURE__ */ new Set() : /* @__PURE__ */ new Set();
1546
+ if (owner) hiddenLegendKeys.set(owner, hidden);
534
1547
  for (const item of items) {
535
1548
  const row = legendItem(item.label, "", item.tone);
536
- row.classList.add("chart-legend-toggle-item");
1549
+ row.classList.add("icen-chart-legend-toggle-item");
537
1550
  row.setAttribute("role", "button");
538
1551
  row.tabIndex = 0;
539
- row.setAttribute("aria-pressed", "true");
540
- row.dataset.chartKey = item.key;
541
- const dot = row.querySelector(".chart-legend-dot");
542
- const toneColor = toneOf(item.tone, item.si + 1);
1552
+ row.classList.toggle("is-off", hidden.has(item.key));
1553
+ row.setAttribute("aria-pressed", String(!hidden.has(item.key)));
1554
+ row.dataset.icenChartKey = item.key;
1555
+ const dot = row.querySelector(".icen-chart-legend-dot");
1556
+ const toneColor = toneOf(item.tone, item.si);
543
1557
  if (dot && toneColor) dot.style.setProperty("--chart-tone", toneColor);
544
1558
  const toggle = () => {
545
1559
  const off = row.classList.toggle("is-off");
1560
+ if (off) hidden.add(item.key);
1561
+ else hidden.delete(item.key);
546
1562
  row.setAttribute("aria-pressed", String(!off));
547
- scope.querySelectorAll(`[data-chart-key="${CSS.escape(item.key)}"]`).forEach((m) => {
1563
+ scope.querySelectorAll(`[data-icen-chart-key="${CSS.escape(item.key)}"]`).forEach((m) => {
548
1564
  m.classList.toggle("is-off", off);
549
1565
  });
550
1566
  emitIcen(legend, "icen:chart-legend-toggle", { key: item.key, seriesIndex: item.si, hidden: off });
@@ -559,8 +1575,9 @@ function toggleLegend(items, scope) {
559
1575
  legend.appendChild(row);
560
1576
  }
561
1577
  for (const item of items) {
562
- scope.querySelectorAll(`[data-chart-series="${item.si}"]`).forEach((m) => {
563
- if (!m.hasAttribute("data-chart-key")) m.setAttribute("data-chart-key", item.key);
1578
+ scope.querySelectorAll(`[data-icen-chart-series="${item.si}"]`).forEach((m) => {
1579
+ if (!m.hasAttribute("data-icen-chart-key")) m.setAttribute("data-icen-chart-key", item.key);
1580
+ m.classList.toggle("is-off", hidden.has(item.key));
564
1581
  });
565
1582
  }
566
1583
  return legend;
@@ -587,19 +1604,19 @@ function renderVBar(el, opts) {
587
1604
  for (const s of seriesList) max = Math.max(max, maxOf(s.values.slice(0, n)));
588
1605
  }
589
1606
  const wrap = document.createElement("div");
590
- wrap.className = "chart-vbar";
1607
+ wrap.className = "icen-chart-vbar";
591
1608
  if (opts.tone) wrap.style.setProperty("--chart-tone", toneVar(opts.tone));
592
1609
  for (let i = 0; i < n; i++) {
593
1610
  const track = document.createElement("div");
594
- track.className = "chart-vbar-track";
1611
+ track.className = "icen-chart-vbar-track";
595
1612
  if (seriesList.length > 1) {
596
- track.classList.add("chart-vbar-track--multi");
597
- if (opts.stacked) track.classList.add("chart-vbar-track--stacked");
1613
+ track.classList.add("icen-chart-vbar-track--multi");
1614
+ if (opts.stacked) track.classList.add("icen-chart-vbar-track--stacked");
598
1615
  }
599
1616
  seriesList.forEach((s, si) => {
600
1617
  const value = s.values[i] ?? 0;
601
1618
  const bar = document.createElement("div");
602
- bar.className = "chart-vbar-bar";
1619
+ bar.className = "icen-chart-vbar-bar";
603
1620
  const height = value > 0 ? Math.max(6, value / max * 100) : 0;
604
1621
  bar.style.height = `${height}%`;
605
1622
  const toneColor = toneOf(s.tone, si);
@@ -617,7 +1634,7 @@ function renderVBar(el, opts) {
617
1634
  wrap.appendChild(track);
618
1635
  }
619
1636
  body.append(wrap, labelsRow(labelsUsed));
620
- if (seriesList.length > 1) body.appendChild(toggleLegend(seriesList.map((s, si) => ({ key: s.name, label: s.name, tone: s.tone, si })), wrap));
1637
+ 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));
621
1638
  });
622
1639
  attachChartInteraction(el, "vbar");
623
1640
  return el;
@@ -634,22 +1651,22 @@ function renderHBar(el, opts) {
634
1651
  const values = opts.values.slice(0, n);
635
1652
  const max = maxOf(values);
636
1653
  const wrap = document.createElement("div");
637
- wrap.className = "chart-hbar";
1654
+ wrap.className = "icen-chart-hbar";
638
1655
  if (opts.tone) wrap.style.setProperty("--chart-tone", toneVar(opts.tone));
639
1656
  values.forEach((value, i) => {
640
1657
  const row = document.createElement("div");
641
- row.className = "chart-hbar-row";
1658
+ row.className = "icen-chart-hbar-row";
642
1659
  const label = document.createElement("span");
643
- label.className = "chart-hbar-label";
1660
+ label.className = "icen-chart-hbar-label";
644
1661
  label.textContent = labels[i] ?? "";
645
1662
  const track = document.createElement("div");
646
- track.className = "chart-hbar-track";
1663
+ track.className = "icen-chart-hbar-track";
647
1664
  const bar = document.createElement("div");
648
- bar.className = "chart-hbar-bar";
1665
+ bar.className = "icen-chart-hbar-bar";
649
1666
  bar.style.width = value > 0 ? `${Math.max(2, value / max * 100)}%` : "0%";
650
1667
  setMarkData(bar, { index: i, label: labels[i] ?? "", value });
651
1668
  const val = document.createElement("span");
652
- val.className = "chart-hbar-value";
1669
+ val.className = "icen-chart-hbar-value";
653
1670
  val.textContent = fmt(opts, value);
654
1671
  track.appendChild(bar);
655
1672
  row.append(label, track, val);
@@ -669,10 +1686,10 @@ function renderStack(el, opts) {
669
1686
  return;
670
1687
  }
671
1688
  const bar = document.createElement("div");
672
- bar.className = "chart-stack";
1689
+ bar.className = "icen-chart-stack";
673
1690
  for (const [segIndex, seg] of opts.segments.entries()) {
674
1691
  const s = document.createElement("div");
675
- s.className = "chart-stack-seg";
1692
+ s.className = "icen-chart-stack-seg";
676
1693
  s.style.width = `${seg.value / total * 100}%`;
677
1694
  if (seg.tone) s.style.setProperty("--chart-tone", toneVar(seg.tone));
678
1695
  s.setAttribute("title", `${seg.label}: ${fmt(opts, seg.value)}`);
@@ -680,7 +1697,7 @@ function renderStack(el, opts) {
680
1697
  bar.appendChild(s);
681
1698
  }
682
1699
  const legend = document.createElement("div");
683
- legend.className = "chart-legend";
1700
+ legend.className = "icen-chart-legend";
684
1701
  for (const seg of opts.segments) {
685
1702
  legend.appendChild(legendItem(seg.label, fmt(opts, seg.value), seg.tone));
686
1703
  }
@@ -700,20 +1717,22 @@ function renderDonut(el, opts) {
700
1717
  const radius = 42;
701
1718
  const circumference = 2 * Math.PI * radius;
702
1719
  const wrap = document.createElement("div");
703
- wrap.className = "chart-donut";
704
- const svg2 = svgEl("svg", { viewBox: "0 0 120 120", role: "img" });
705
- svg2.style.transform = "rotate(-90deg)";
706
- svg2.appendChild(svgEl("circle", {
1720
+ wrap.className = "icen-chart-donut";
1721
+ const svg = svgEl("svg", { viewBox: "0 0 120 120", role: "img", "aria-label": chartAriaLabel(opts.title, t("charts.type.donut")) });
1722
+ svg.style.transform = "rotate(-90deg)";
1723
+ svg.appendChild(svgEl("circle", {
707
1724
  cx: "60",
708
1725
  cy: "60",
709
1726
  r: String(radius),
710
1727
  fill: "none",
711
- stroke: "var(--token-line-soft)",
1728
+ stroke: "var(--icen-token-line-soft)",
712
1729
  "stroke-width": "14"
713
1730
  }));
714
1731
  let offset = 0;
1732
+ const gap = opts.segments.length > 1 ? 2.5 : 0;
715
1733
  opts.segments.forEach((seg, segIndex) => {
716
- const dash = seg.value / total * circumference;
1734
+ const arcLength = Math.max(0, seg.value / total * circumference);
1735
+ const dash = arcLength - Math.min(gap, arcLength * 0.1);
717
1736
  const arc = svgEl("circle", {
718
1737
  cx: "60",
719
1738
  cy: "60",
@@ -726,15 +1745,15 @@ function renderDonut(el, opts) {
726
1745
  "stroke-linecap": "butt"
727
1746
  });
728
1747
  setMarkData(arc, { index: segIndex, label: seg.label, value: seg.value });
729
- svg2.appendChild(arc);
730
- offset += dash;
1748
+ svg.appendChild(arc);
1749
+ offset += arcLength;
731
1750
  });
732
1751
  const legend = document.createElement("div");
733
- legend.className = "chart-legend";
1752
+ legend.className = "icen-chart-legend";
734
1753
  for (const seg of opts.segments) {
735
1754
  legend.appendChild(legendItem(seg.label, `${Math.round(seg.value / total * 100)}%`, seg.tone));
736
1755
  }
737
- wrap.append(svg2, legend);
1756
+ wrap.append(svg, legend);
738
1757
  body.appendChild(wrap);
739
1758
  });
740
1759
  attachChartInteraction(el, "donut");
@@ -752,23 +1771,24 @@ function renderLine(el, opts) {
752
1771
  return;
753
1772
  }
754
1773
  const labelsUsed = labels.slice(0, n);
755
- const width = 360;
1774
+ const width = fluidWidth(body);
756
1775
  const height = 150;
757
1776
  const pad = 14;
758
1777
  let max = 1;
759
1778
  for (const s of seriesList) max = Math.max(max, maxOf(s.values.slice(0, n)));
760
1779
  const wrap = document.createElement("div");
761
- wrap.className = "chart-line";
762
- const svg2 = svgEl("svg", { viewBox: `0 0 ${width} ${height}`, role: "img" });
1780
+ wrap.className = "icen-chart-line";
1781
+ const svg = svgEl("svg", { viewBox: `0 0 ${width} ${height}`, role: "img", "aria-label": chartAriaLabel(opts.title, t("charts.type.line")) });
763
1782
  const defs = svgEl("defs", {});
764
1783
  for (let i = 0; i < 4; i++) {
765
- const y = pad + i * (height - pad * 2) / 3;
766
- svg2.appendChild(svgEl("line", {
1784
+ const y = Math.round(pad + i * (height - pad * 2) / 3) + 0.5;
1785
+ svg.appendChild(svgEl("line", {
1786
+ class: i === 3 ? "icen-chart-grid icen-chart-baseline" : "icen-chart-grid",
767
1787
  x1: String(pad),
768
1788
  x2: String(width - pad),
769
1789
  y1: String(y),
770
1790
  y2: String(y),
771
- stroke: "var(--token-line-soft)",
1791
+ stroke: "var(--icen-token-line-soft)",
772
1792
  "stroke-width": "1"
773
1793
  }));
774
1794
  }
@@ -798,7 +1818,7 @@ function renderLine(el, opts) {
798
1818
  if (seriesList.length > 1) {
799
1819
  setMarkData(areaPath, { seriesIndex: si, seriesName: s.name, label: s.name, value: values.reduce((a, b) => a + b, 0) });
800
1820
  }
801
- svg2.appendChild(areaPath);
1821
+ svg.appendChild(areaPath);
802
1822
  }
803
1823
  const linePath = svgEl("path", {
804
1824
  d: line,
@@ -809,16 +1829,16 @@ function renderLine(el, opts) {
809
1829
  "stroke-linejoin": "round"
810
1830
  });
811
1831
  const lineTitle = svgEl("title", {});
812
- lineTitle.textContent = s.name || "\u6570\u503C";
1832
+ lineTitle.textContent = s.name || t("charts.value");
813
1833
  linePath.appendChild(lineTitle);
814
1834
  setMarkData(linePath, { seriesIndex: si, seriesName: s.name, label: s.name, value: values[values.length - 1] ?? 0 });
815
- svg2.appendChild(linePath);
1835
+ svg.appendChild(linePath);
816
1836
  for (const p of points) {
817
1837
  const dot = svgEl("circle", {
818
1838
  cx: p.x.toFixed(1),
819
1839
  cy: p.y.toFixed(1),
820
1840
  r: "3",
821
- fill: "var(--token-card)",
1841
+ fill: "var(--icen-token-card)",
822
1842
  stroke: tone,
823
1843
  "stroke-width": "2"
824
1844
  });
@@ -832,23 +1852,24 @@ function renderLine(el, opts) {
832
1852
  label: p.label,
833
1853
  value: p.value
834
1854
  });
835
- svg2.appendChild(dot);
1855
+ svg.appendChild(dot);
836
1856
  const hit = svgEl("circle", {
837
1857
  cx: p.x.toFixed(1),
838
1858
  cy: p.y.toFixed(1),
839
1859
  r: "8",
840
1860
  fill: "transparent",
841
- "data-chart-hit": "1"
1861
+ "data-icen-chart-hit": "1"
842
1862
  });
843
1863
  copyMarkData(hit, dot);
844
- svg2.appendChild(hit);
1864
+ svg.appendChild(hit);
845
1865
  }
846
1866
  });
847
- if (defs.firstChild) svg2.insertBefore(defs, svg2.firstChild);
848
- wrap.append(svg2, labelsRow(sampleLabels(labelsUsed)));
1867
+ if (defs.firstChild) svg.insertBefore(defs, svg.firstChild);
1868
+ wrap.append(svg, pointLabelsRow(labelsUsed, width, pad));
849
1869
  body.appendChild(wrap);
850
- if (seriesList.length > 1) body.appendChild(toggleLegend(seriesList.map((s, si) => ({ key: s.name, label: s.name, tone: s.tone, si })), wrap));
1870
+ 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));
851
1871
  });
1872
+ if (el.dataset.icenChartBody == null) observeFluidWidth(el, () => renderLine(el, opts));
852
1873
  attachChartInteraction(el, "line");
853
1874
  return el;
854
1875
  }
@@ -880,30 +1901,30 @@ function renderRadar(el, opts) {
880
1901
  y: cy + r * Math.sin(angleOf(i))
881
1902
  });
882
1903
  const wrap = document.createElement("div");
883
- wrap.className = "chart-radar";
884
- const svg2 = svgEl("svg", { viewBox: `0 0 ${size} ${size}`, role: "img" });
1904
+ wrap.className = "icen-chart-radar";
1905
+ const svg = svgEl("svg", { viewBox: `0 0 ${size} ${size}`, role: "img", "aria-label": chartAriaLabel(opts.title, t("charts.type.radar")) });
885
1906
  for (let lv = 1; lv <= levels; lv++) {
886
1907
  const r = radius * lv / levels;
887
1908
  const pts = Array.from({ length: n }, (_, i) => {
888
1909
  const p = pointAt(i, r);
889
1910
  return `${p.x.toFixed(1)},${p.y.toFixed(1)}`;
890
1911
  }).join(" ");
891
- svg2.appendChild(svgEl("polygon", {
1912
+ svg.appendChild(svgEl("polygon", {
892
1913
  points: pts,
893
1914
  fill: "none",
894
- stroke: "var(--token-line-soft)",
1915
+ stroke: "var(--icen-token-line-soft)",
895
1916
  "stroke-width": "1",
896
1917
  "stroke-dasharray": lv === levels ? "0" : "3 2"
897
1918
  }));
898
1919
  }
899
1920
  for (let i = 0; i < n; i++) {
900
1921
  const edge = pointAt(i, radius);
901
- svg2.appendChild(svgEl("line", {
1922
+ svg.appendChild(svgEl("line", {
902
1923
  x1: String(cx),
903
1924
  y1: String(cy),
904
1925
  x2: edge.x.toFixed(1),
905
1926
  y2: edge.y.toFixed(1),
906
- stroke: "var(--token-line-soft)",
1927
+ stroke: "var(--icen-token-line-soft)",
907
1928
  "stroke-width": "1"
908
1929
  }));
909
1930
  const labelP = pointAt(i, radius + 14);
@@ -913,14 +1934,14 @@ function renderRadar(el, opts) {
913
1934
  "text-anchor": "middle",
914
1935
  "dominant-baseline": "middle",
915
1936
  "font-size": "9",
916
- fill: "var(--token-text-muted)"
1937
+ fill: "var(--icen-token-text-muted)"
917
1938
  });
918
1939
  txt.textContent = axes[i] ?? "";
919
- svg2.appendChild(txt);
1940
+ svg.appendChild(txt);
920
1941
  }
921
1942
  const legendItems = [];
922
1943
  opts.series.forEach((s, si) => {
923
- const tone = toneVar(s.tone);
1944
+ const tone = toneOf(s.tone, si) ?? toneVar(s.tone);
924
1945
  const pts = Array.from({ length: n }, (_, i) => {
925
1946
  const v = Math.max(0, Math.min(maxVal, s.values[i] ?? 0));
926
1947
  const p = pointAt(i, v / maxVal * radius);
@@ -938,7 +1959,7 @@ function renderRadar(el, opts) {
938
1959
  title.textContent = `${s.name}: ${s.values.map((v) => fmt(opts, v)).join(" / ")}`;
939
1960
  polyFill.appendChild(title);
940
1961
  setMarkData(polyFill, { seriesIndex: si, seriesName: s.name || void 0, label: s.name, value: s.values.reduce((a, b) => a + (b || 0), 0) });
941
- svg2.appendChild(polyFill);
1962
+ svg.appendChild(polyFill);
942
1963
  for (let i = 0; i < n; i++) {
943
1964
  const v = Math.max(0, Math.min(maxVal, s.values[i] ?? 0));
944
1965
  const p = pointAt(i, v / maxVal * radius);
@@ -946,18 +1967,19 @@ function renderRadar(el, opts) {
946
1967
  cx: p.x.toFixed(1),
947
1968
  cy: p.y.toFixed(1),
948
1969
  r: "2.5",
949
- fill: "var(--token-card)",
1970
+ fill: "var(--icen-token-card)",
950
1971
  stroke: tone,
951
1972
  "stroke-width": "1.5"
952
1973
  });
953
1974
  setMarkData(dot, { index: i, seriesIndex: si, seriesName: s.name || void 0, label: axes[i] ?? "", value: s.values[i] ?? 0 });
954
- svg2.appendChild(dot);
1975
+ svg.appendChild(dot);
955
1976
  }
956
- legendItems.push({ key: s.name || `\u7CFB\u5217${si + 1}`, label: s.name || `\u7CFB\u5217${si + 1}`, tone: s.tone, si });
1977
+ 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 });
957
1978
  });
958
- const legend = opts.series.length > 1 ? toggleLegend(legendItems, wrap) : null;
959
- wrap.append(svg2, ...legend ? [legend] : []);
1979
+ wrap.appendChild(svg);
960
1980
  body.appendChild(wrap);
1981
+ const legend = opts.series.length > 1 ? toggleLegend(legendItems, wrap) : null;
1982
+ if (legend) wrap.appendChild(legend);
961
1983
  });
962
1984
  attachChartInteraction(el, "radar");
963
1985
  return el;
@@ -974,6 +1996,11 @@ function niceCeil(v) {
974
1996
  else nice = 10;
975
1997
  return nice * base;
976
1998
  }
1999
+ function tickPrecision(min, max, steps) {
2000
+ const span = Math.abs(max - min);
2001
+ if (!Number.isFinite(span) || span <= 0) return 0;
2002
+ return Math.max(0, Math.ceil(-Math.log10(span / steps)));
2003
+ }
977
2004
  function isoDate(d) {
978
2005
  const m = String(d.getMonth() + 1).padStart(2, "0");
979
2006
  const day = String(d.getDate()).padStart(2, "0");
@@ -990,23 +2017,23 @@ function padFirstWeek(grid, firstDate, weekStart) {
990
2017
  const pad = (first.getDay() + 7 - weekStart) % 7;
991
2018
  for (let i = 0; i < pad; i++) {
992
2019
  const blank = document.createElement("span");
993
- blank.className = "chart-heatmap-cell is-blank";
2020
+ blank.className = "icen-chart-heatmap-cell is-blank";
994
2021
  grid.appendChild(blank);
995
2022
  }
996
2023
  return pad;
997
2024
  }
998
2025
  function heatmapLegend(labels) {
999
2026
  const legend = document.createElement("div");
1000
- legend.className = "chart-heatmap-legend";
2027
+ legend.className = "icen-chart-heatmap-legend";
1001
2028
  const less = document.createElement("span");
1002
- less.textContent = labels?.less ?? "\u5C11";
2029
+ less.textContent = labels?.less ?? t("charts.few");
1003
2030
  const more = document.createElement("span");
1004
- more.textContent = labels?.more ?? "\u591A";
2031
+ more.textContent = labels?.more ?? t("charts.many");
1005
2032
  legend.appendChild(less);
1006
2033
  for (let lv = 0; lv <= 4; lv++) {
1007
2034
  const cell = document.createElement("span");
1008
- cell.className = "chart-heatmap-cell";
1009
- cell.dataset.level = String(lv);
2035
+ cell.className = "icen-chart-heatmap-cell";
2036
+ cell.dataset.icenLevel = String(lv);
1010
2037
  legend.appendChild(cell);
1011
2038
  }
1012
2039
  legend.appendChild(more);
@@ -1033,16 +2060,17 @@ function renderHeatmap(el, opts) {
1033
2060
  if (entries.length > weeks * 7) entries = entries.slice(entries.length - weeks * 7);
1034
2061
  const max = maxOf(entries.map((e) => e.value));
1035
2062
  const wrap = document.createElement("div");
1036
- wrap.className = "chart-heatmap";
2063
+ wrap.className = "icen-chart-heatmap";
1037
2064
  if (opts.tone) wrap.style.setProperty("--chart-tone", toneVar(opts.tone));
1038
2065
  const grid = document.createElement("div");
1039
- grid.className = "chart-heatmap-grid";
2066
+ grid.className = "icen-chart-heatmap-grid";
1040
2067
  grid.setAttribute("role", "img");
2068
+ grid.setAttribute("aria-label", chartAriaLabel(opts.title, t("charts.type.heatmap")));
1041
2069
  padFirstWeek(grid, entries[0].date, opts.weekStart === 0 ? 0 : 1);
1042
2070
  for (const [i, entry] of entries.entries()) {
1043
2071
  const cell = document.createElement("span");
1044
- cell.className = "chart-heatmap-cell";
1045
- cell.dataset.level = String(levelOf(entry.value, max));
2072
+ cell.className = "icen-chart-heatmap-cell";
2073
+ cell.dataset.icenLevel = String(levelOf(entry.value, max));
1046
2074
  cell.setAttribute("title", `${entry.date}\uFF1A${fmt(opts, entry.value)}`);
1047
2075
  setMarkData(cell, { index: i, label: entry.date, value: entry.value });
1048
2076
  grid.appendChild(cell);
@@ -1068,7 +2096,8 @@ function renderSparkline(el, opts) {
1068
2096
  const tone = toneVar(opts.tone);
1069
2097
  const points = values.map((value, i) => ({
1070
2098
  x: values.length <= 1 ? width / 2 : pad + i / (values.length - 1) * (width - pad * 2),
1071
- y: height - pad - value / max * (height - pad * 2),
2099
+ /* 负值钳到基线(与折线图同口径):viewBox 仅 28 高,反向射出更刺眼 */
2100
+ y: height - pad - Math.max(0, value) / max * (height - pad * 2),
1072
2101
  value
1073
2102
  }));
1074
2103
  const line = points.map((p, i) => `${i === 0 ? "M" : "L"}${p.x.toFixed(1)},${p.y.toFixed(1)}`).join(" ");
@@ -1077,16 +2106,16 @@ function renderSparkline(el, opts) {
1077
2106
  const area = `${line} L${last.x.toFixed(1)},${height - pad} L${first.x.toFixed(1)},${height - pad} Z`;
1078
2107
  const gradientId = `icen-chart-line-${++lineGradientSeq}`;
1079
2108
  const wrap = document.createElement("div");
1080
- wrap.className = "chart-sparkline";
1081
- const svg2 = svgEl("svg", { viewBox: `0 0 ${width} ${height}`, role: "img" });
2109
+ wrap.className = "icen-chart-sparkline";
2110
+ const svg = svgEl("svg", { viewBox: `0 0 ${width} ${height}`, role: "img", "aria-label": chartAriaLabel(opts.title, t("charts.type.sparkline")) });
1082
2111
  const defs = svgEl("defs", {});
1083
2112
  const gradient = svgEl("linearGradient", { id: gradientId, x1: "0", x2: "0", y1: "0", y2: "1" });
1084
2113
  gradient.appendChild(svgEl("stop", { offset: "0%", "stop-color": tone, "stop-opacity": "0.28" }));
1085
2114
  gradient.appendChild(svgEl("stop", { offset: "100%", "stop-color": tone, "stop-opacity": "0.02" }));
1086
2115
  defs.appendChild(gradient);
1087
- svg2.appendChild(defs);
1088
- svg2.appendChild(svgEl("path", { d: area, fill: `url(#${gradientId})` }));
1089
- svg2.appendChild(svgEl("path", {
2116
+ svg.appendChild(defs);
2117
+ svg.appendChild(svgEl("path", { d: area, fill: `url(#${gradientId})` }));
2118
+ svg.appendChild(svgEl("path", {
1090
2119
  d: line,
1091
2120
  fill: "none",
1092
2121
  stroke: tone,
@@ -1098,15 +2127,15 @@ function renderSparkline(el, opts) {
1098
2127
  cx: last.x.toFixed(1),
1099
2128
  cy: last.y.toFixed(1),
1100
2129
  r: "2.4",
1101
- fill: "var(--token-card)",
2130
+ fill: "var(--icen-token-card)",
1102
2131
  stroke: tone,
1103
2132
  "stroke-width": "1.6"
1104
2133
  });
1105
2134
  const title = svgEl("title", {});
1106
2135
  title.textContent = fmt(opts, last.value);
1107
2136
  dot.appendChild(title);
1108
- svg2.appendChild(dot);
1109
- wrap.appendChild(svg2);
2137
+ svg.appendChild(dot);
2138
+ wrap.appendChild(svg);
1110
2139
  body.appendChild(wrap);
1111
2140
  });
1112
2141
  attachChartInteraction(el, "sparkline");
@@ -1120,20 +2149,20 @@ function renderGauge(el, opts) {
1120
2149
  const radius = 42;
1121
2150
  const circumference = 2 * Math.PI * radius;
1122
2151
  const wrap = document.createElement("div");
1123
- wrap.className = "chart-gauge";
2152
+ wrap.className = "icen-chart-gauge";
1124
2153
  if (opts.tone) wrap.style.setProperty("--chart-tone", toneVar(opts.tone));
1125
- const svg2 = svgEl("svg", { viewBox: "0 0 120 120", role: "img" });
1126
- svg2.style.transform = "rotate(-90deg)";
1127
- svg2.appendChild(svgEl("circle", {
2154
+ const svg = svgEl("svg", { viewBox: "0 0 120 120", role: "img", "aria-label": chartAriaLabel(opts.label, t("charts.type.gauge")) });
2155
+ svg.style.transform = "rotate(-90deg)";
2156
+ svg.appendChild(svgEl("circle", {
1128
2157
  cx: "60",
1129
2158
  cy: "60",
1130
2159
  r: String(radius),
1131
2160
  fill: "none",
1132
- stroke: "var(--token-line-soft)",
2161
+ stroke: "var(--icen-token-line-soft)",
1133
2162
  "stroke-width": "10"
1134
2163
  }));
1135
2164
  const dash = ratio * circumference;
1136
- svg2.appendChild(svgEl("circle", {
2165
+ svg.appendChild(svgEl("circle", {
1137
2166
  cx: "60",
1138
2167
  cy: "60",
1139
2168
  r: String(radius),
@@ -1144,18 +2173,18 @@ function renderGauge(el, opts) {
1144
2173
  "stroke-linecap": "round"
1145
2174
  }));
1146
2175
  const center = document.createElement("div");
1147
- center.className = "chart-gauge-center";
2176
+ center.className = "icen-chart-gauge-center";
1148
2177
  const val = document.createElement("span");
1149
- val.className = "chart-gauge-value";
2178
+ val.className = "icen-chart-gauge-value";
1150
2179
  val.textContent = opts.formatValue ? opts.formatValue(opts.value) : `${Math.round(ratio * 100)}%`;
1151
2180
  center.appendChild(val);
1152
2181
  if (opts.label) {
1153
2182
  const lab = document.createElement("span");
1154
- lab.className = "chart-gauge-label";
2183
+ lab.className = "icen-chart-gauge-label";
1155
2184
  lab.textContent = opts.label;
1156
2185
  center.appendChild(lab);
1157
2186
  }
1158
- wrap.append(svg2, center);
2187
+ wrap.append(svg, center);
1159
2188
  el.appendChild(wrap);
1160
2189
  attachChartInteraction(el, "gauge");
1161
2190
  return el;
@@ -1173,25 +2202,27 @@ function renderCalendar(el, opts) {
1173
2202
  return;
1174
2203
  }
1175
2204
  const wrap = document.createElement("div");
1176
- wrap.className = "chart-calendar";
2205
+ wrap.className = "icen-chart-calendar";
1177
2206
  if (opts.tone) wrap.style.setProperty("--chart-tone", toneVar(opts.tone));
1178
2207
  const weekStart = opts.weekStart === 0 ? 0 : 1;
1179
- const weekdayDefaults = ["\u4E00", "", "\u4E09", "", "\u4E94", "", "\u65E5"];
2208
+ const weekdayDefaults = t("charts.calendarWeekdays");
1180
2209
  const weekdayLabels = opts.labels?.weekdays ?? weekdayDefaults.map((_, i) => weekdayLabelAt(weekdayDefaults, (weekStart + i) % 7));
1181
- const monthLabel = (m) => opts.labels?.months?.[m] ?? `${m + 1}\u6708`;
2210
+ const monthLabel = (m) => opts.labels?.months?.[m] ?? t("charts.monthLabel", { p0: m + 1 });
1182
2211
  const grid = document.createElement("div");
1183
- grid.className = "chart-heatmap-grid";
2212
+ grid.className = "icen-chart-heatmap-grid";
1184
2213
  grid.setAttribute("role", "img");
2214
+ grid.setAttribute("aria-label", chartAriaLabel(opts.title, t("charts.type.heatmap")));
1185
2215
  const months = document.createElement("div");
1186
- months.className = "chart-calendar-months";
2216
+ months.className = "icen-chart-calendar-months";
1187
2217
  const weekdayRow = document.createElement("div");
1188
- weekdayRow.className = "chart-calendar-weekdays";
2218
+ weekdayRow.className = "icen-chart-calendar-weekdays";
1189
2219
  weekdayLabels.forEach((w) => {
1190
2220
  const s = document.createElement("span");
1191
2221
  s.textContent = w;
1192
2222
  weekdayRow.appendChild(s);
1193
2223
  });
1194
2224
  const max = maxOf(entries.map((e) => e.value));
2225
+ entries.sort((a, b) => a.date.localeCompare(b.date));
1195
2226
  const pad = padFirstWeek(grid, entries[0].date, weekStart);
1196
2227
  let lastMonth = -1;
1197
2228
  entries.forEach((entry, i) => {
@@ -1200,14 +2231,14 @@ function renderCalendar(el, opts) {
1200
2231
  if (d.getMonth() !== lastMonth) {
1201
2232
  lastMonth = d.getMonth();
1202
2233
  const label = document.createElement("span");
1203
- label.className = "chart-calendar-month";
2234
+ label.className = "icen-chart-calendar-month";
1204
2235
  label.textContent = monthLabel(d.getMonth());
1205
2236
  label.style.setProperty("--col", String(col));
1206
2237
  months.appendChild(label);
1207
2238
  }
1208
2239
  const cell = document.createElement("span");
1209
- cell.className = "chart-heatmap-cell";
1210
- cell.dataset.level = String(levelOf(entry.value, max));
2240
+ cell.className = "icen-chart-heatmap-cell";
2241
+ cell.dataset.icenLevel = String(levelOf(entry.value, max));
1211
2242
  cell.setAttribute("title", `${entry.date}\uFF1A${fmt(opts, entry.value)}`);
1212
2243
  setMarkData(cell, { index: i, label: entry.date, value: entry.value });
1213
2244
  grid.appendChild(cell);
@@ -1229,7 +2260,7 @@ function renderScatter(el, opts) {
1229
2260
  renderEmpty(body, opts.emptyLabel);
1230
2261
  return;
1231
2262
  }
1232
- const width = 360;
2263
+ const width = fluidWidth(body);
1233
2264
  const height = 220;
1234
2265
  const pad = 30;
1235
2266
  let xMin = Infinity, xMax = -Infinity, yMin = Infinity, yMax = -Infinity, sMax = 0;
@@ -1244,19 +2275,20 @@ function renderScatter(el, opts) {
1244
2275
  if (yMax === yMin) yMax = yMin + 1;
1245
2276
  const rOf = (size) => size && sMax > 0 ? 3 + size / sMax * 7 : 4;
1246
2277
  const wrap = document.createElement("div");
1247
- wrap.className = "chart-scatter";
2278
+ wrap.className = "icen-chart-scatter";
1248
2279
  const tone = toneVar(opts.tone);
1249
- const svg2 = svgEl("svg", { viewBox: `0 0 ${width} ${height}`, role: "img" });
2280
+ const svg = svgEl("svg", { viewBox: `0 0 ${width} ${height}`, role: "img", "aria-label": chartAriaLabel(opts.title, t("charts.type.scatter")) });
1250
2281
  const xAt = (x) => pad + (x - xMin) / (xMax - xMin) * (width - pad * 2);
1251
2282
  const yAt = (y) => height - pad - (y - yMin) / (yMax - yMin) * (height - pad * 2);
1252
2283
  for (let i = 0; i <= 3; i++) {
1253
- const y = pad + i * (height - pad * 2) / 3;
1254
- svg2.appendChild(svgEl("line", {
2284
+ const y = Math.round(pad + i * (height - pad * 2) / 3) + 0.5;
2285
+ svg.appendChild(svgEl("line", {
2286
+ class: i === 3 ? "icen-chart-grid icen-chart-baseline" : "icen-chart-grid",
1255
2287
  x1: String(pad),
1256
2288
  x2: String(width - pad),
1257
2289
  y1: String(y),
1258
2290
  y2: String(y),
1259
- stroke: "var(--token-line-soft)",
2291
+ stroke: "var(--icen-token-line-soft)",
1260
2292
  "stroke-width": "1"
1261
2293
  }));
1262
2294
  const tv = yMin + (yMax - yMin) * (3 - i) / 3;
@@ -1265,19 +2297,20 @@ function renderScatter(el, opts) {
1265
2297
  y: String(y + 3),
1266
2298
  "text-anchor": "end",
1267
2299
  "font-size": "8",
1268
- fill: "var(--token-text-faint)"
2300
+ fill: "var(--icen-token-text-faint)"
1269
2301
  });
1270
- txt.textContent = fmt(opts, Math.round(tv * 10) / 10);
1271
- svg2.appendChild(txt);
2302
+ txt.textContent = fmt(opts, +tv.toFixed(tickPrecision(yMin, yMax, 3)));
2303
+ svg.appendChild(txt);
1272
2304
  }
1273
2305
  for (let i = 0; i <= 4; i++) {
1274
- const x = pad + i * (width - pad * 2) / 4;
1275
- svg2.appendChild(svgEl("line", {
2306
+ const x = Math.round(pad + i * (width - pad * 2) / 4) + 0.5;
2307
+ svg.appendChild(svgEl("line", {
2308
+ class: i === 0 ? "icen-chart-grid icen-chart-grid--v icen-chart-axis" : "icen-chart-grid icen-chart-grid--v",
1276
2309
  x1: String(x),
1277
2310
  x2: String(x),
1278
2311
  y1: String(pad),
1279
2312
  y2: String(height - pad),
1280
- stroke: "var(--token-line-soft)",
2313
+ stroke: "var(--icen-token-line-soft)",
1281
2314
  "stroke-width": "1",
1282
2315
  "stroke-dasharray": "2 3"
1283
2316
  }));
@@ -1287,20 +2320,20 @@ function renderScatter(el, opts) {
1287
2320
  y: String(height - pad + 12),
1288
2321
  "text-anchor": "middle",
1289
2322
  "font-size": "8",
1290
- fill: "var(--token-text-faint)"
2323
+ fill: "var(--icen-token-text-faint)"
1291
2324
  });
1292
- txt.textContent = fmt(opts, Math.round(tv * 10) / 10);
1293
- svg2.appendChild(txt);
2325
+ txt.textContent = fmt(opts, +tv.toFixed(tickPrecision(xMin, xMax, 4)));
2326
+ svg.appendChild(txt);
1294
2327
  }
1295
2328
  if (opts.yLabel) {
1296
- const t = svgEl("text", { x: "10", y: String(pad - 10), "font-size": "8", fill: "var(--token-text-faint)" });
1297
- t.textContent = opts.yLabel;
1298
- svg2.appendChild(t);
2329
+ const t2 = svgEl("text", { x: "10", y: String(pad - 10), "font-size": "8", fill: "var(--icen-token-text-faint)" });
2330
+ t2.textContent = opts.yLabel;
2331
+ svg.appendChild(t2);
1299
2332
  }
1300
2333
  if (opts.xLabel) {
1301
- const t = svgEl("text", { x: String(width - pad), y: String(pad - 10), "text-anchor": "end", "font-size": "8", fill: "var(--token-text-faint)" });
1302
- t.textContent = opts.xLabel;
1303
- svg2.appendChild(t);
2334
+ const t2 = svgEl("text", { x: String(width - pad), y: String(pad - 10), "text-anchor": "end", "font-size": "8", fill: "var(--icen-token-text-faint)" });
2335
+ t2.textContent = opts.xLabel;
2336
+ svg.appendChild(t2);
1304
2337
  }
1305
2338
  pts.forEach((p, i) => {
1306
2339
  const c = svgEl("circle", {
@@ -1317,11 +2350,12 @@ function renderScatter(el, opts) {
1317
2350
  c.appendChild(title);
1318
2351
  setMarkData(c, { index: i, label: p.label ?? `#${i + 1}`, value: p.y });
1319
2352
  c.dataset.chartX = String(p.x);
1320
- svg2.appendChild(c);
2353
+ svg.appendChild(c);
1321
2354
  });
1322
- wrap.appendChild(svg2);
2355
+ wrap.appendChild(svg);
1323
2356
  body.appendChild(wrap);
1324
2357
  });
2358
+ if (el.dataset.icenChartBody == null) observeFluidWidth(el, () => renderScatter(el, opts));
1325
2359
  attachChartInteraction(el, "scatter");
1326
2360
  return el;
1327
2361
  }
@@ -1371,7 +2405,7 @@ function pivotData(spec) {
1371
2405
  const labels = [];
1372
2406
  const seenLabel = /* @__PURE__ */ new Set();
1373
2407
  const hasSeries = data.some((r) => r[seriesField] != null && r[seriesField] !== "");
1374
- const seriesNames = [];
2408
+ const seriesNames = hasSeries ? [] : [""];
1375
2409
  const seenSeries = /* @__PURE__ */ new Set();
1376
2410
  for (const r of data) {
1377
2411
  const l = str(r[labelField]);
@@ -1460,8 +2494,8 @@ function normalizeChartSpec(raw) {
1460
2494
  const s = src;
1461
2495
  const spec = {};
1462
2496
  if (typeof s.type === "string") {
1463
- const t = s.type.trim().toLowerCase();
1464
- spec.type = CHART_TYPE_ALIASES[t] ?? t;
2497
+ const t2 = s.type.trim().toLowerCase();
2498
+ spec.type = CHART_TYPE_ALIASES[t2] ?? t2;
1465
2499
  }
1466
2500
  for (const k of ["title", "tone", "emptyLabel"]) {
1467
2501
  if (typeof s[k] === "string") spec[k] = s[k];
@@ -1483,7 +2517,7 @@ function normalizeChartSpec(raw) {
1483
2517
  if (Array.isArray(s.series)) {
1484
2518
  const series = s.series.filter((v) => !!v && typeof v === "object").map((v, i) => {
1485
2519
  const values = Array.isArray(v.values) ? v.values.map(toNum).filter((n) => n != null) : [];
1486
- const sv = { name: String(v.name ?? `\u7CFB\u5217${i + 1}`), values };
2520
+ const sv = { name: String(v.name ?? t("charts.seriesName", { p0: i + 1 })), values };
1487
2521
  const tone = v.tone;
1488
2522
  if (typeof tone === "string" || typeof tone === "number") sv.tone = tone;
1489
2523
  return sv;
@@ -1518,6 +2552,40 @@ function normalizeChartSpec(raw) {
1518
2552
  }
1519
2553
  spec.format = format;
1520
2554
  }
2555
+ if (typeof s.downsample === "boolean") spec.downsample = s.downsample;
2556
+ else {
2557
+ const n = toNum(s.downsample);
2558
+ if (n != null) spec.downsample = n;
2559
+ }
2560
+ if (s.zoom === "x" || s.zoom === "brush") spec.zoom = s.zoom;
2561
+ if (typeof s.loading === "boolean") spec.loading = s.loading;
2562
+ if (Array.isArray(s.marks)) {
2563
+ const marks = [];
2564
+ for (const raw2 of s.marks) {
2565
+ if (!raw2 || typeof raw2 !== "object" || Array.isArray(raw2)) continue;
2566
+ const m = raw2;
2567
+ if (m.type === "line") {
2568
+ if (m.axis !== "x" && m.axis !== "y") continue;
2569
+ if (typeof m.value !== "number" && typeof m.value !== "string") continue;
2570
+ const mark = { type: "line", axis: m.axis, value: m.value };
2571
+ if (typeof m.label === "string" && m.label !== "") mark.label = m.label;
2572
+ if (m.tone === "success" || m.tone === "warning" || m.tone === "error" || m.tone === "info") {
2573
+ mark.tone = m.tone;
2574
+ }
2575
+ marks.push(mark);
2576
+ } else if (m.type === "point") {
2577
+ if (typeof m.label !== "string" || m.label === "") continue;
2578
+ const mark = { type: "point", label: m.label };
2579
+ const si = toNum(m.seriesIndex);
2580
+ if (si != null && si >= 0) mark.seriesIndex = Math.floor(si);
2581
+ const v = toNum(m.value);
2582
+ if (v != null) mark.value = v;
2583
+ if (typeof m.text === "string") mark.text = m.text;
2584
+ marks.push(mark);
2585
+ }
2586
+ }
2587
+ if (marks.length > 0) spec.marks = marks;
2588
+ }
1521
2589
  const isDateRecords = spec.data?.length && spec.data[0] && "date" in spec.data[0];
1522
2590
  if (spec.data && spec.data.length > 0 && !isDateRecords && !spec.series && !spec.points && !spec.values && !spec.segments) {
1523
2591
  Object.assign(spec, pivotData(spec));
@@ -1557,6 +2625,392 @@ function inferChartType(spec) {
1557
2625
  if (typeof spec.max === "number" && spec.values && spec.values.length === 1) return "gauge";
1558
2626
  return "vbar";
1559
2627
  }
2628
+ var DOWNSAMPLE_DEFAULT_THRESHOLD = 1e3;
2629
+ var CHART_ZOOM_DRAG_MIN_PX = 5;
2630
+ var CHART_LINE_W = 360;
2631
+ var CHART_LINE_H = 150;
2632
+ var CHART_LINE_PAD = 14;
2633
+ function isDownsampleableType(type) {
2634
+ return type === "line" || type === "area" || type === "scatter";
2635
+ }
2636
+ function isZoomableType(type) {
2637
+ return type === "line" || type === "area" || type === "vbar";
2638
+ }
2639
+ function isStreamableType(type) {
2640
+ return type === "line" || type === "area" || type === "vbar";
2641
+ }
2642
+ function downsampleView(view, type) {
2643
+ const raw = view.downsample;
2644
+ if (raw == null || raw === false) return { view, note: null };
2645
+ const threshold = raw === true ? DOWNSAMPLE_DEFAULT_THRESHOLD : Math.floor(raw);
2646
+ if (!Number.isFinite(threshold)) return { view, note: null };
2647
+ if (type === "scatter") {
2648
+ const pts = view.points ?? [];
2649
+ if (pts.length === 0) return { view, note: null };
2650
+ const sampled2 = lttb(pts, threshold, (p) => p.x, (p) => p.y);
2651
+ if (sampled2.length === pts.length) return { view, note: null };
2652
+ return { view: { ...view, points: sampled2 }, note: t("charts.sampled", { p0: pts.length, p1: sampled2.length }) };
2653
+ }
2654
+ const labels = view.labels ?? [];
2655
+ if (labels.length === 0) return { view, note: null };
2656
+ const guide = view.series && view.series.length > 0 ? view.series[0]?.values ?? [] : view.values ?? [];
2657
+ const count = Math.min(labels.length, guide.length);
2658
+ if (count === 0) return { view, note: null };
2659
+ const indexed = guide.slice(0, count).map((v, i) => ({ i, v }));
2660
+ const sampled = lttb(indexed, threshold, (p) => p.i, (p) => p.v);
2661
+ if (sampled.length >= count) return { view, note: null };
2662
+ const idx = sampled.map((p) => p.i);
2663
+ return {
2664
+ view: {
2665
+ ...view,
2666
+ labels: idx.map((i) => labels[i] ?? ""),
2667
+ values: view.values ? idx.map((i) => view.values?.[i] ?? 0) : void 0,
2668
+ series: view.series?.map((s) => ({ ...s, values: idx.map((i) => s.values[i] ?? 0) }))
2669
+ },
2670
+ note: t("charts.sampled", { p0: count, p1: idx.length })
2671
+ };
2672
+ }
2673
+ function renderChartSkeleton(body) {
2674
+ const box = document.createElement("div");
2675
+ box.className = "icen-chart-skeleton";
2676
+ box.setAttribute("role", "status");
2677
+ box.setAttribute("aria-busy", "true");
2678
+ box.setAttribute("aria-label", t("charts.loading"));
2679
+ const widths = [100, 84, 92, 68, 76, 52];
2680
+ for (const w of widths) {
2681
+ const bar = document.createElement("div");
2682
+ bar.className = "icen-chart-skeleton-bar";
2683
+ bar.style.width = `${w}%`;
2684
+ box.appendChild(bar);
2685
+ }
2686
+ body.appendChild(box);
2687
+ }
2688
+ var CHART_MARK_ACCENT = "var(--icen-token-accent)";
2689
+ var CHART_MARK_ACCENT_TEXT = "var(--icen-token-accent-text)";
2690
+ function markToneVar(tone) {
2691
+ switch (tone) {
2692
+ case "success":
2693
+ return "var(--icen-token-success)";
2694
+ case "warning":
2695
+ return "var(--icen-token-warning)";
2696
+ case "error":
2697
+ return "var(--icen-token-error)";
2698
+ case "info":
2699
+ return "var(--icen-token-info)";
2700
+ default:
2701
+ return "var(--icen-token-text-faint)";
2702
+ }
2703
+ }
2704
+ function markWarnOnce(warned, mark, reason) {
2705
+ const key = JSON.stringify(mark);
2706
+ if (warned.has(key)) return;
2707
+ warned.add(key);
2708
+ console.warn(`[icen:chart] \u65E0\u6548\u6807\u8BB0\u5DF2\u8DF3\u8FC7\uFF08${reason}\uFF09`, mark);
2709
+ }
2710
+ function paintChartMarks(root, view, spec, formatValue, warned) {
2711
+ const marks = spec.marks;
2712
+ if (!marks || marks.length === 0) return;
2713
+ const type = spec.type;
2714
+ if (type === "line" || type === "area") paintSvgChartMarks(root, view, marks, formatValue, warned);
2715
+ else if (type === "vbar") paintVBarChartMarks(root, view, spec, marks, formatValue, warned);
2716
+ }
2717
+ function paintSvgChartMarks(root, view, marks, formatValue, warned) {
2718
+ const svg = root.querySelector(".icen-chart-line svg");
2719
+ if (!svg) return;
2720
+ const labels = view.labels ?? [];
2721
+ const n = labels.length;
2722
+ if (n === 0) return;
2723
+ const seriesList = view.series && view.series.length > 0 ? view.series : view.values ? [{ name: "", values: view.values }] : [];
2724
+ let max = 1;
2725
+ for (const s of seriesList) max = Math.max(max, maxOf(s.values.slice(0, n)));
2726
+ const dims = svgDimsOf(svg);
2727
+ const W = dims.w;
2728
+ const H = dims.h;
2729
+ const PAD = CHART_LINE_PAD;
2730
+ const xAt = (i) => n <= 1 ? W / 2 : PAD + i / (n - 1) * (W - PAD * 2);
2731
+ const yAt = (v) => H - PAD - Math.max(0, v) / max * (H - PAD * 2);
2732
+ for (const mark of marks) {
2733
+ if (mark.type === "line") {
2734
+ const color = markToneVar(mark.tone);
2735
+ if (mark.axis === "y") {
2736
+ const v = typeof mark.value === "number" ? mark.value : Number(mark.value);
2737
+ if (!Number.isFinite(v)) {
2738
+ markWarnOnce(warned, mark, "\u53C2\u8003\u7EBF\u6570\u503C NaN");
2739
+ continue;
2740
+ }
2741
+ const y = clampNum(yAt(v), CHART_LINE_PAD, H - PAD);
2742
+ svg.appendChild(svgEl("line", {
2743
+ class: "icen-chart-mark-line",
2744
+ x1: String(PAD),
2745
+ x2: String(W - PAD),
2746
+ y1: y.toFixed(1),
2747
+ y2: y.toFixed(1),
2748
+ stroke: color,
2749
+ "stroke-width": "1",
2750
+ "stroke-dasharray": "4 3"
2751
+ }));
2752
+ const label = svgEl("text", {
2753
+ class: "icen-chart-mark-label",
2754
+ x: String(W - PAD),
2755
+ y: String(clampNum(y - 4, 8, CHART_LINE_H - 4)),
2756
+ "text-anchor": "end",
2757
+ "font-size": "8",
2758
+ fill: color
2759
+ });
2760
+ label.textContent = mark.label ?? formatValue(v);
2761
+ svg.appendChild(label);
2762
+ } else {
2763
+ const idx = typeof mark.value === "number" ? Math.round(mark.value) : labels.indexOf(mark.value);
2764
+ if (idx < 0 || idx >= n) {
2765
+ markWarnOnce(warned, mark, "\u53C2\u8003\u7EBF\u7C7B\u76EE\u4E0D\u5B58\u5728");
2766
+ continue;
2767
+ }
2768
+ const x = xAt(idx);
2769
+ svg.appendChild(svgEl("line", {
2770
+ class: "icen-chart-mark-line",
2771
+ x1: x.toFixed(1),
2772
+ x2: x.toFixed(1),
2773
+ y1: String(PAD),
2774
+ y2: String(H - PAD),
2775
+ stroke: color,
2776
+ "stroke-width": "1",
2777
+ "stroke-dasharray": "4 3"
2778
+ }));
2779
+ const label = svgEl("text", {
2780
+ class: "icen-chart-mark-label",
2781
+ x: String(clampNum(x, 10, W - 10)),
2782
+ y: String(PAD + 8),
2783
+ "text-anchor": "middle",
2784
+ "font-size": "8",
2785
+ fill: color
2786
+ });
2787
+ label.textContent = mark.label ?? labels[idx] ?? "";
2788
+ svg.appendChild(label);
2789
+ }
2790
+ } else {
2791
+ const idx = labels.indexOf(mark.label);
2792
+ if (idx < 0 || idx >= n) {
2793
+ markWarnOnce(warned, mark, "\u6807\u8BB0\u70B9\u7C7B\u76EE\u4E0D\u5B58\u5728");
2794
+ continue;
2795
+ }
2796
+ const si = Math.max(0, Math.floor(mark.seriesIndex ?? 0));
2797
+ const s = seriesList[si];
2798
+ if (!s) {
2799
+ markWarnOnce(warned, mark, "\u6807\u8BB0\u70B9\u7CFB\u5217\u4E0D\u5B58\u5728");
2800
+ continue;
2801
+ }
2802
+ const v = mark.value ?? s.values[idx] ?? NaN;
2803
+ if (!Number.isFinite(v)) {
2804
+ markWarnOnce(warned, mark, "\u6807\u8BB0\u70B9\u6570\u503C NaN");
2805
+ continue;
2806
+ }
2807
+ const x = xAt(idx);
2808
+ const y = clampNum(yAt(v), CHART_LINE_PAD, H - PAD);
2809
+ const g = svgEl("g", { class: "icen-chart-mark-point" });
2810
+ g.appendChild(svgEl("circle", {
2811
+ cx: x.toFixed(1),
2812
+ cy: y.toFixed(1),
2813
+ r: "6",
2814
+ fill: "none",
2815
+ stroke: CHART_MARK_ACCENT,
2816
+ "stroke-width": "1.5"
2817
+ }));
2818
+ g.appendChild(svgEl("circle", { cx: x.toFixed(1), cy: y.toFixed(1), r: "2", fill: CHART_MARK_ACCENT }));
2819
+ const label = svgEl("text", {
2820
+ class: "icen-chart-mark-label",
2821
+ x: String(clampNum(x, 12, W - 12)),
2822
+ y: String(clampNum(y - 10, 8, CHART_LINE_H - 4)),
2823
+ "text-anchor": "middle",
2824
+ "font-size": "8",
2825
+ fill: CHART_MARK_ACCENT_TEXT
2826
+ });
2827
+ label.textContent = mark.text ?? mark.label;
2828
+ g.appendChild(label);
2829
+ svg.appendChild(g);
2830
+ }
2831
+ }
2832
+ }
2833
+ function paintVBarChartMarks(root, view, spec, marks, formatValue, warned) {
2834
+ const wrap = root.querySelector(".icen-chart-vbar");
2835
+ if (!wrap) return;
2836
+ const seriesList = view.series && view.series.length > 0 ? view.series : view.values ? [{ name: "", values: view.values }] : [];
2837
+ const labels = view.labels ?? [];
2838
+ const n = Math.min(labels.length, ...seriesList.map((s) => s.values.length));
2839
+ if (n === 0 || seriesList.length === 0) return;
2840
+ const multi = seriesList.length > 1;
2841
+ let max = 1;
2842
+ if (spec.stacked && multi) {
2843
+ for (let i = 0; i < n; i++) {
2844
+ let sum2 = 0;
2845
+ for (const s of seriesList) sum2 += Math.max(0, s.values[i] ?? 0);
2846
+ if (sum2 > max) max = sum2;
2847
+ }
2848
+ } else {
2849
+ for (const s of seriesList) max = Math.max(max, maxOf(s.values.slice(0, n)));
2850
+ }
2851
+ const centerPct = (i) => (i + 0.5) / n * 100;
2852
+ for (const mark of marks) {
2853
+ if (mark.type === "line") {
2854
+ if (mark.axis === "y") {
2855
+ const v = typeof mark.value === "number" ? mark.value : Number(mark.value);
2856
+ if (!Number.isFinite(v)) {
2857
+ markWarnOnce(warned, mark, "\u53C2\u8003\u7EBF\u6570\u503C NaN");
2858
+ continue;
2859
+ }
2860
+ const line = document.createElement("div");
2861
+ line.className = "icen-chart-mark-line icen-chart-mark-line--h";
2862
+ line.style.top = `${(clampNum(1 - Math.max(0, v) / max, 0.02, 0.98) * 100).toFixed(2)}%`;
2863
+ line.style.setProperty("--chart-mark-tone", markToneVar(mark.tone));
2864
+ const lab = document.createElement("span");
2865
+ lab.className = "icen-chart-mark-label";
2866
+ lab.textContent = mark.label ?? formatValue(v);
2867
+ line.appendChild(lab);
2868
+ wrap.appendChild(line);
2869
+ } else {
2870
+ const idx = typeof mark.value === "number" ? Math.round(mark.value) : labels.indexOf(mark.value);
2871
+ if (idx < 0 || idx >= n) {
2872
+ markWarnOnce(warned, mark, "\u53C2\u8003\u7EBF\u7C7B\u76EE\u4E0D\u5B58\u5728");
2873
+ continue;
2874
+ }
2875
+ const line = document.createElement("div");
2876
+ line.className = "icen-chart-mark-line icen-chart-mark-line--v";
2877
+ line.style.left = `${centerPct(idx).toFixed(2)}%`;
2878
+ line.style.setProperty("--chart-mark-tone", markToneVar(mark.tone));
2879
+ const lab = document.createElement("span");
2880
+ lab.className = "icen-chart-mark-label";
2881
+ lab.textContent = mark.label ?? labels[idx] ?? "";
2882
+ line.appendChild(lab);
2883
+ wrap.appendChild(line);
2884
+ }
2885
+ } else {
2886
+ const idx = labels.indexOf(mark.label);
2887
+ if (idx < 0 || idx >= n) {
2888
+ markWarnOnce(warned, mark, "\u6807\u8BB0\u70B9\u7C7B\u76EE\u4E0D\u5B58\u5728");
2889
+ continue;
2890
+ }
2891
+ const si = Math.max(0, Math.floor(mark.seriesIndex ?? 0));
2892
+ const s = seriesList[si];
2893
+ if (!s) {
2894
+ markWarnOnce(warned, mark, "\u6807\u8BB0\u70B9\u7CFB\u5217\u4E0D\u5B58\u5728");
2895
+ continue;
2896
+ }
2897
+ const v = mark.value ?? s.values[idx] ?? NaN;
2898
+ if (!Number.isFinite(v)) {
2899
+ markWarnOnce(warned, mark, "\u6807\u8BB0\u70B9\u6570\u503C NaN");
2900
+ continue;
2901
+ }
2902
+ const dot = document.createElement("div");
2903
+ dot.className = "icen-chart-mark-point";
2904
+ dot.style.left = `${centerPct(idx).toFixed(2)}%`;
2905
+ dot.style.bottom = `${(clampNum(Math.max(0, v) / max, 0, 1) * 100).toFixed(2)}%`;
2906
+ const lab = document.createElement("span");
2907
+ lab.className = "icen-chart-mark-label";
2908
+ lab.textContent = mark.text ?? mark.label;
2909
+ dot.appendChild(lab);
2910
+ wrap.appendChild(dot);
2911
+ }
2912
+ }
2913
+ }
2914
+ function chartAriaLabel(title, typeName) {
2915
+ return title ? `${typeName}\uFF1A${title}` : typeName;
2916
+ }
2917
+ function svgDimsOf(svg) {
2918
+ const vb = (svg.getAttribute("viewBox") ?? "").split(/\s+/).map(Number);
2919
+ const w = Number.isFinite(vb[2]) && (vb[2] ?? 0) > 0 ? vb[2] : CHART_LINE_W;
2920
+ const h2 = Number.isFinite(vb[3]) && (vb[3] ?? 0) > 0 ? vb[3] : CHART_LINE_H;
2921
+ return { w, h: h2 };
2922
+ }
2923
+ var fluidObservers = /* @__PURE__ */ new WeakMap();
2924
+ function fluidWidth(host) {
2925
+ const w = Math.round(host.getBoundingClientRect().width);
2926
+ return w > 0 ? Math.max(29, w) : 360;
2927
+ }
2928
+ function observeFluidWidth(el, rerender) {
2929
+ if (typeof ResizeObserver === "undefined") return;
2930
+ fluidObservers.get(el)?.disconnect();
2931
+ let last = Math.round(el.getBoundingClientRect().width);
2932
+ const ro = new ResizeObserver(() => {
2933
+ if (!el.isConnected) {
2934
+ ro.disconnect();
2935
+ fluidObservers.delete(el);
2936
+ return;
2937
+ }
2938
+ const w = Math.round(el.getBoundingClientRect().width);
2939
+ if (Math.abs(w - last) < 2) return;
2940
+ last = w;
2941
+ rerender();
2942
+ });
2943
+ ro.observe(el);
2944
+ fluidObservers.set(el, ro);
2945
+ }
2946
+ function releaseFluidWidth(el) {
2947
+ fluidObservers.get(el)?.disconnect();
2948
+ fluidObservers.delete(el);
2949
+ }
2950
+ function createChartToDataURL(root) {
2951
+ const cache = /* @__PURE__ */ new Map();
2952
+ return (opts) => {
2953
+ if (typeof document === "undefined") return void 0;
2954
+ const scale = clampNum(toNum(opts?.scale) ?? 2, 0.5, 4);
2955
+ const svgs = Array.from(root.querySelectorAll("svg"));
2956
+ if (svgs.length === 0) return void 0;
2957
+ const parts = [];
2958
+ for (const svg of svgs) {
2959
+ const { w, h: h2 } = svgDimsOf(svg);
2960
+ const clone = svg.cloneNode(true);
2961
+ clone.setAttribute("xmlns", SVG_NS);
2962
+ clone.setAttribute("width", String(w));
2963
+ clone.setAttribute("height", String(h2));
2964
+ let str;
2965
+ try {
2966
+ str = new XMLSerializer().serializeToString(clone);
2967
+ } catch {
2968
+ return void 0;
2969
+ }
2970
+ parts.push({ src: `data:image/svg+xml;charset=utf-8,${encodeURIComponent(str)}`, w, h: h2 });
2971
+ }
2972
+ const key = `${scale}|${parts.map((p) => p.src).join("")}`;
2973
+ const hit = cache.get(key);
2974
+ if (hit) return hit;
2975
+ const canvas = document.createElement("canvas");
2976
+ let ctx = null;
2977
+ try {
2978
+ ctx = canvas.getContext("2d");
2979
+ } catch {
2980
+ return void 0;
2981
+ }
2982
+ if (!ctx) return void 0;
2983
+ const context = ctx;
2984
+ const totalW = Math.max(...parts.map((p) => p.w));
2985
+ const totalH = parts.reduce((sum2, p) => sum2 + p.h, 0);
2986
+ canvas.width = Math.max(1, Math.round(totalW * scale));
2987
+ canvas.height = Math.max(1, Math.round(totalH * scale));
2988
+ let loaded = 0;
2989
+ let failed = false;
2990
+ let offsetY = 0;
2991
+ for (const part of parts) {
2992
+ const dy = offsetY;
2993
+ offsetY += part.h;
2994
+ const img = new Image();
2995
+ img.onload = () => {
2996
+ if (failed) return;
2997
+ context.drawImage(img, 0, dy * scale, part.w * scale, part.h * scale);
2998
+ loaded += 1;
2999
+ if (loaded === parts.length) {
3000
+ try {
3001
+ cache.set(key, canvas.toDataURL("image/png"));
3002
+ } catch {
3003
+ }
3004
+ }
3005
+ };
3006
+ img.onerror = () => {
3007
+ failed = true;
3008
+ };
3009
+ img.src = part.src;
3010
+ }
3011
+ return cache.get(key);
3012
+ };
3013
+ }
1560
3014
  function dispatchChartEvent(root, type, mark, chart, phase, pointer) {
1561
3015
  const read = (name) => mark.getAttribute(name) ?? void 0;
1562
3016
  const numOr = (v) => v == null ? void 0 : Number(v);
@@ -1564,11 +3018,11 @@ function dispatchChartEvent(root, type, mark, chart, phase, pointer) {
1564
3018
  type,
1565
3019
  phase,
1566
3020
  chart,
1567
- index: numOr(read("data-chart-index")),
1568
- seriesIndex: numOr(read("data-chart-series")),
1569
- seriesName: read("data-chart-series-name"),
1570
- label: read("data-chart-label"),
1571
- value: numOr(read("data-chart-value")),
3021
+ index: numOr(read("data-icen-chart-index")),
3022
+ seriesIndex: numOr(read("data-icen-chart-series")),
3023
+ seriesName: read("data-icen-chart-series-name"),
3024
+ label: read("data-icen-chart-label"),
3025
+ value: numOr(read("data-icen-chart-value")),
1572
3026
  target: mark,
1573
3027
  pointerX: pointer?.x,
1574
3028
  pointerY: pointer?.y
@@ -1579,7 +3033,7 @@ var tooltipEl = null;
1579
3033
  function chartTooltip() {
1580
3034
  if (!tooltipEl) {
1581
3035
  tooltipEl = document.createElement("div");
1582
- tooltipEl.className = "chart-tooltip";
3036
+ tooltipEl.className = "icen-chart-tooltip";
1583
3037
  tooltipEl.setAttribute("role", "tooltip");
1584
3038
  tooltipEl.hidden = true;
1585
3039
  document.body.appendChild(tooltipEl);
@@ -1588,14 +3042,14 @@ function chartTooltip() {
1588
3042
  }
1589
3043
  function applyTooltipSizing(host) {
1590
3044
  const tip = chartTooltip();
1591
- const raw = host?.closest(".chart, [data-chart-root]")?.getAttribute("data-panel-max") ?? null;
3045
+ const raw = host?.closest(".icen-chart, [data-icen-chart-root]")?.getAttribute("data-icen-panel-max") ?? null;
1592
3046
  const n = raw != null ? Number(raw) : NaN;
1593
3047
  tip.style.maxWidth = Number.isFinite(n) && n > 0 ? `${n}px` : "";
1594
3048
  }
1595
3049
  function tooltipText(mark) {
1596
- const label = mark.getAttribute("data-chart-label") ?? "";
1597
- const series = mark.getAttribute("data-chart-series-name");
1598
- const value = mark.getAttribute("data-chart-value");
3050
+ const label = mark.getAttribute("data-icen-chart-label") ?? "";
3051
+ const series = mark.getAttribute("data-icen-chart-series-name");
3052
+ const value = mark.getAttribute("data-icen-chart-value");
1599
3053
  const head = series ? label ? `${series} \xB7 ${label}` : series : label;
1600
3054
  return value != null ? `${head}\uFF1A${value}` : head;
1601
3055
  }
@@ -1627,8 +3081,8 @@ function bindChartEvents(root) {
1627
3081
  const typeNow = () => chartDelegateMeta.get(root)?.type() ?? "vbar";
1628
3082
  const tipEnabled = () => chartDelegateMeta.get(root)?.tooltip() ?? true;
1629
3083
  const markOf = (e) => {
1630
- const t = e.target;
1631
- return t instanceof Element ? t.closest("[data-chart-mark]") : null;
3084
+ const t2 = e.target;
3085
+ return t2 instanceof Element ? t2.closest("[data-icen-chart-mark]") : null;
1632
3086
  };
1633
3087
  let hoverMark = null;
1634
3088
  const enterMark = (mark, x, y) => {
@@ -1725,70 +3179,283 @@ function hasLegendOf(spec) {
1725
3179
  function renderChart(el, raw) {
1726
3180
  const noop = () => void 0;
1727
3181
  if (typeof document === "undefined") {
1728
- return { el, spec: {}, update: noop, on: () => noop, destroy: noop };
3182
+ return {
3183
+ el,
3184
+ spec: {},
3185
+ update: noop,
3186
+ append: noop,
3187
+ toDataURL: () => void 0,
3188
+ on: () => noop,
3189
+ destroy: noop
3190
+ };
1729
3191
  }
1730
3192
  const root = el;
1731
- let current = normalizeChartSpec(raw);
1732
- const typeOf = () => current.type ?? "vbar";
3193
+ let current2 = normalizeChartSpec(raw);
3194
+ const typeOf = () => current2.type ?? "vbar";
1733
3195
  const legendState = { hidden: null };
3196
+ let zoomWindow = null;
3197
+ const warnedMarks = /* @__PURE__ */ new Set();
3198
+ let warnedAppend = false;
3199
+ let zoomDragCleanup = null;
3200
+ const fullLength = () => {
3201
+ if (current2.type === "scatter") return current2.points?.length ?? 0;
3202
+ if (current2.series && current2.series.length > 0) {
3203
+ return Math.max(current2.labels?.length ?? 0, ...current2.series.map((s) => s.values.length));
3204
+ }
3205
+ return Math.max(current2.labels?.length ?? 0, current2.values?.length ?? 0);
3206
+ };
3207
+ const viewOf = () => {
3208
+ if (!zoomWindow) return current2;
3209
+ const { from, to } = zoomWindow;
3210
+ return {
3211
+ ...current2,
3212
+ labels: current2.labels?.slice(from, to + 1),
3213
+ values: current2.values?.slice(from, to + 1),
3214
+ series: current2.series?.map((s) => ({ ...s, values: s.values.slice(from, to + 1) })),
3215
+ points: current2.points?.slice(from, to + 1)
3216
+ };
3217
+ };
3218
+ const applyZoomSelection = (x0, x1) => {
3219
+ const len = fullLength();
3220
+ if (len < 2) return;
3221
+ const base = zoomWindow?.from ?? 0;
3222
+ const viewLen = zoomWindow ? zoomWindow.to - zoomWindow.from + 1 : len;
3223
+ const lo = Math.min(x0, x1);
3224
+ const hi = Math.max(x0, x1);
3225
+ let i0;
3226
+ let i1;
3227
+ const vbar = root.querySelector(".icen-chart-vbar");
3228
+ if (vbar) {
3229
+ const rect = vbar.getBoundingClientRect();
3230
+ const rel0 = rect.width > 0 ? Math.floor((lo - rect.left) / rect.width * viewLen) : 0;
3231
+ const rel1 = rect.width > 0 ? Math.max(rel0, Math.floor((hi - rect.left) / rect.width * viewLen)) : viewLen - 1;
3232
+ i0 = clampNum(rel0 + base, 0, len - 1);
3233
+ i1 = clampNum(rel1 + base, 0, len - 1);
3234
+ } else {
3235
+ const svg = root.querySelector(".icen-chart-line svg");
3236
+ if (!svg) return;
3237
+ const dims = svgDimsOf(svg);
3238
+ const p0 = svgClientPoint(svg, lo, 0, dims.w, dims.h);
3239
+ const p1 = svgClientPoint(svg, hi, 0, dims.w, dims.h);
3240
+ const rel0 = Math.round((p0.x - CHART_LINE_PAD) / (dims.w - CHART_LINE_PAD * 2) * (viewLen - 1));
3241
+ const rel1 = Math.round((p1.x - CHART_LINE_PAD) / (dims.w - CHART_LINE_PAD * 2) * (viewLen - 1));
3242
+ i0 = clampNum(rel0 + base, 0, len - 1);
3243
+ i1 = clampNum(rel1 + base, 0, len - 1);
3244
+ }
3245
+ if (i0 > i1) [i0, i1] = [i1, i0];
3246
+ if (i0 <= 0 && i1 >= len - 1) zoomWindow = null;
3247
+ else zoomWindow = { from: i0, to: Math.max(i1, i0) };
3248
+ render();
3249
+ emitIcen(root, "icen:chart-zoom", { chart: String(current2.type ?? ""), from: i0, to: Math.max(i1, i0) });
3250
+ };
3251
+ const bindZoomGesture = () => {
3252
+ if (current2.zoom !== "x" && current2.zoom !== "brush") return;
3253
+ const t2 = typeOf();
3254
+ if (!isZoomableType(t2) || fullLength() < 2) return;
3255
+ const plot = t2 === "vbar" ? root.querySelector(".icen-chart-vbar") : root.querySelector(".icen-chart-line svg");
3256
+ if (!plot) return;
3257
+ const on = (type, fn) => {
3258
+ plot.addEventListener(type, fn);
3259
+ };
3260
+ let drag = null;
3261
+ const onMove = (e) => {
3262
+ if (!drag) return;
3263
+ drag.x1 = e.clientX;
3264
+ drag.y1 = e.clientY;
3265
+ if (!drag.active && Math.hypot(drag.x1 - drag.x0, drag.y1 - drag.y0) >= CHART_ZOOM_DRAG_MIN_PX) {
3266
+ drag.active = true;
3267
+ const rect = document.createElement("div");
3268
+ rect.className = "icen-chart-zoom-rect";
3269
+ document.body.appendChild(rect);
3270
+ drag.rect = rect;
3271
+ }
3272
+ if (drag.active && drag.rect) {
3273
+ drag.rect.style.left = `${Math.round(Math.min(drag.x0, drag.x1))}px`;
3274
+ drag.rect.style.width = `${Math.round(Math.abs(drag.x1 - drag.x0))}px`;
3275
+ if (current2.zoom === "brush") {
3276
+ drag.rect.style.top = `${Math.round(Math.min(drag.y0, drag.y1))}px`;
3277
+ drag.rect.style.height = `${Math.round(Math.abs(drag.y1 - drag.y0))}px`;
3278
+ } else {
3279
+ const pr = plot.getBoundingClientRect();
3280
+ drag.rect.style.top = `${Math.round(pr.top)}px`;
3281
+ drag.rect.style.height = `${Math.round(pr.height)}px`;
3282
+ }
3283
+ }
3284
+ };
3285
+ const onUp = () => {
3286
+ window.removeEventListener("pointermove", onMove);
3287
+ window.removeEventListener("pointerup", onUp);
3288
+ window.removeEventListener("pointercancel", onUp);
3289
+ zoomDragCleanup = null;
3290
+ if (!drag) return;
3291
+ const d = drag;
3292
+ drag = null;
3293
+ d.rect?.remove();
3294
+ if (!d.active) return;
3295
+ applyZoomSelection(d.x0, d.x1);
3296
+ };
3297
+ const onDown = (e) => {
3298
+ if (e.button !== 0) return;
3299
+ drag = { x0: e.clientX, y0: e.clientY, x1: e.clientX, y1: e.clientY, active: false, rect: null };
3300
+ window.addEventListener("pointermove", onMove);
3301
+ window.addEventListener("pointerup", onUp);
3302
+ window.addEventListener("pointercancel", onUp);
3303
+ zoomDragCleanup = onUp;
3304
+ };
3305
+ on("pointerdown", onDown);
3306
+ on("dblclick", () => {
3307
+ if (!zoomWindow) return;
3308
+ zoomWindow = null;
3309
+ render();
3310
+ });
3311
+ };
1734
3312
  const render = () => {
1735
- if (!current.type) current = { ...current, type: inferChartType(current) };
1736
- const spec = current;
3313
+ if (!current2.type) current2 = { ...current2, type: inferChartType(current2) };
3314
+ const spec = current2;
3315
+ const type = spec.type;
1737
3316
  const formatValue = chartFormatValue(spec.format);
1738
3317
  if (spec.legend !== void 0) legendState.hidden = spec.legend === false;
3318
+ const loading = spec.loading === true;
3319
+ root.classList.toggle("is-loading", loading);
3320
+ let view = viewOf();
3321
+ let note = null;
3322
+ if (!loading && isDownsampleableType(type)) {
3323
+ const r = downsampleView(view, type);
3324
+ view = r.view;
3325
+ note = r.note;
3326
+ }
3327
+ const zoomReset = zoomWindow && (spec.zoom === "x" || spec.zoom === "brush") ? () => {
3328
+ zoomWindow = null;
3329
+ render();
3330
+ } : null;
1739
3331
  withChrome(root, spec, hasLegendOf(spec), (body) => {
1740
- switch (spec.type) {
3332
+ if (loading) {
3333
+ renderChartSkeleton(body);
3334
+ return;
3335
+ }
3336
+ switch (type) {
1741
3337
  case "line":
1742
- 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 });
3338
+ 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 });
1743
3339
  break;
1744
3340
  case "area":
1745
- 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 });
3341
+ 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 });
1746
3342
  break;
1747
3343
  case "vbar":
1748
- 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 });
3344
+ 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 });
1749
3345
  break;
1750
3346
  case "hbar":
1751
- renderHBar(body, { labels: spec.labels ?? [], values: spec.values ?? [], tone: spec.tone, formatValue, emptyLabel: spec.emptyLabel, title: spec.title, legend: spec.legend });
3347
+ renderHBar(body, { labels: view.labels ?? [], values: view.values ?? [], tone: view.tone, formatValue, emptyLabel: view.emptyLabel, title: view.title, legend: view.legend });
1752
3348
  break;
1753
3349
  case "stack":
1754
- renderStack(body, { segments: spec.segments ?? [], formatValue, emptyLabel: spec.emptyLabel, title: spec.title, legend: spec.legend });
3350
+ renderStack(body, { segments: view.segments ?? [], formatValue, emptyLabel: view.emptyLabel, title: view.title, legend: view.legend });
1755
3351
  break;
1756
3352
  case "donut":
1757
- renderDonut(body, { segments: spec.segments ?? [], formatValue, emptyLabel: spec.emptyLabel, title: spec.title, legend: spec.legend });
3353
+ renderDonut(body, { segments: view.segments ?? [], formatValue, emptyLabel: view.emptyLabel, title: view.title, legend: view.legend });
1758
3354
  break;
1759
3355
  case "radar": {
1760
- 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 }] : [];
1761
- renderRadar(body, { axes: spec.axes ?? spec.labels ?? [], series, max: spec.max, levels: spec.levels, formatValue, emptyLabel: spec.emptyLabel, title: spec.title, legend: spec.legend });
3356
+ 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 }] : [];
3357
+ renderRadar(body, { axes: view.axes ?? view.labels ?? [], series, max: view.max, levels: view.levels, formatValue, emptyLabel: view.emptyLabel, title: view.title, legend: view.legend });
1762
3358
  break;
1763
3359
  }
1764
3360
  case "heatmap":
1765
- 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 });
3361
+ 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 });
1766
3362
  break;
1767
3363
  case "calendar":
1768
- 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 });
3364
+ 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 });
1769
3365
  break;
1770
3366
  case "sparkline":
1771
- renderSparkline(body, { labels: spec.labels ?? [], values: spec.values ?? [], tone: spec.tone, formatValue, emptyLabel: spec.emptyLabel, title: spec.title, legend: spec.legend });
3367
+ renderSparkline(body, { labels: view.labels ?? [], values: view.values ?? [], tone: view.tone, formatValue, emptyLabel: view.emptyLabel, title: view.title, legend: view.legend });
1772
3368
  break;
1773
3369
  case "gauge":
1774
- renderGauge(body, { value: spec.values?.[0] ?? 0, max: spec.max, tone: spec.tone, label: spec.labels?.[0], formatValue });
3370
+ renderGauge(body, { value: view.values?.[0] ?? 0, max: view.max, tone: view.tone, label: view.labels?.[0], formatValue });
1775
3371
  break;
1776
3372
  case "scatter":
1777
- renderScatter(body, { points: spec.points ?? [], tone: spec.tone, formatValue, emptyLabel: spec.emptyLabel, title: spec.title, legend: spec.legend });
3373
+ renderScatter(body, { points: view.points ?? [], tone: view.tone, formatValue, emptyLabel: view.emptyLabel, title: view.title, legend: view.legend });
1778
3374
  break;
1779
3375
  default:
1780
- renderEmpty(body, spec.emptyLabel);
3376
+ renderEmpty(body, view.emptyLabel);
1781
3377
  }
1782
- });
3378
+ }, legendState, { note, onZoomReset: zoomReset });
3379
+ if (!loading) {
3380
+ const graphic = root.querySelector('[role="img"]');
3381
+ if (graphic && !graphic.getAttribute("aria-label")) {
3382
+ graphic.setAttribute("aria-label", spec.title ? `${spec.title}\uFF08${type}\uFF09` : type);
3383
+ } else if (!graphic) {
3384
+ const dom = root.querySelector(".icen-chart-vbar, .icen-chart-hbar");
3385
+ if (dom) {
3386
+ dom.setAttribute("role", "img");
3387
+ dom.setAttribute("aria-label", spec.title ? `${spec.title}\uFF08${type}\uFF09` : type);
3388
+ }
3389
+ }
3390
+ }
3391
+ if (loading) return;
3392
+ paintChartMarks(root, view, spec, formatValue, warnedMarks);
3393
+ bindZoomGesture();
1783
3394
  };
1784
- chartDelegateMeta.set(root, { type: typeOf, tooltip: () => current.tooltip !== false });
3395
+ chartDelegateMeta.set(root, { type: typeOf, tooltip: () => current2.tooltip !== false });
1785
3396
  const unbindEvents = bindChartEvents(root);
1786
3397
  render();
3398
+ observeFluidWidth(root, render);
1787
3399
  return {
1788
3400
  el: root,
1789
- spec: current,
3401
+ /** 归一 + 推断后的当前规格(getter:update/append 换引用后永远读到最新) */
3402
+ get spec() {
3403
+ return current2;
3404
+ },
1790
3405
  update(next) {
1791
- current = normalizeChartSpec(next);
3406
+ const prev = current2;
3407
+ current2 = normalizeChartSpec(next);
3408
+ if (zoomWindow) {
3409
+ const sameLabels = JSON.stringify(prev.labels ?? null) === JSON.stringify(current2.labels ?? null);
3410
+ const t2 = current2.type ?? inferChartType(current2);
3411
+ const zoomable = isZoomableType(t2) && (current2.zoom === "x" || current2.zoom === "brush");
3412
+ if (!sameLabels || !zoomable) zoomWindow = null;
3413
+ else {
3414
+ const len = fullLength();
3415
+ if (len < 2) zoomWindow = null;
3416
+ else {
3417
+ const from = clampNum(zoomWindow.from, 0, len - 1);
3418
+ const to = clampNum(zoomWindow.to, 0, len - 1);
3419
+ zoomWindow = from <= to ? { from, to } : null;
3420
+ }
3421
+ }
3422
+ }
3423
+ render();
3424
+ },
3425
+ append(label, values, opts) {
3426
+ const t2 = current2.type ?? inferChartType(current2);
3427
+ if (!isStreamableType(t2)) {
3428
+ if (!warnedAppend) {
3429
+ warnedAppend = true;
3430
+ console.warn(`[icen:chart] append \u4EC5\u652F\u6301 line/area/vbar\uFF08\u5F53\u524D ${String(current2.type ?? t2)}\uFF09\uFF0C\u5DF2\u5FFD\u7565`);
3431
+ }
3432
+ return;
3433
+ }
3434
+ const labels = current2.labels ?? (current2.labels = []);
3435
+ labels.push(String(label ?? ""));
3436
+ const vals = Array.isArray(values) ? values : [];
3437
+ if (current2.series && current2.series.length > 0) {
3438
+ for (const [i, s] of current2.series.entries()) s.values.push(toNum(vals[i]) ?? 0);
3439
+ } else {
3440
+ const v = current2.values ?? (current2.values = []);
3441
+ v.push(toNum(vals[0]) ?? 0);
3442
+ }
3443
+ const maxPoints = opts?.maxPoints != null ? Math.max(1, Math.floor(toNum(opts.maxPoints) ?? 0)) : 0;
3444
+ let dropped = 0;
3445
+ if (maxPoints > 0) {
3446
+ while (labels.length > maxPoints) {
3447
+ labels.shift();
3448
+ if (current2.series) for (const s of current2.series) s.values.shift();
3449
+ else current2.values?.shift();
3450
+ dropped += 1;
3451
+ }
3452
+ }
3453
+ if (zoomWindow) {
3454
+ const len = Math.max(1, labels.length);
3455
+ const size = zoomWindow.to - zoomWindow.from + 1;
3456
+ const to = clampNum(zoomWindow.to - dropped + 1, 0, len - 1);
3457
+ zoomWindow = { from: Math.max(0, to - size + 1), to };
3458
+ }
1792
3459
  render();
1793
3460
  },
1794
3461
  on(name, listener) {
@@ -1798,13 +3465,29 @@ function renderChart(el, raw) {
1798
3465
  root.addEventListener(`icen:chart-${name}`, handler);
1799
3466
  return () => root.removeEventListener(`icen:chart-${name}`, handler);
1800
3467
  },
3468
+ toDataURL: createChartToDataURL(root),
1801
3469
  destroy() {
3470
+ releaseFluidWidth(root);
3471
+ hiddenLegendKeys.delete(root);
3472
+ zoomDragCleanup?.();
1802
3473
  root.textContent = "";
3474
+ root.classList.remove("is-loading");
1803
3475
  unbindEvents();
1804
3476
  chartTooltip().hidden = true;
1805
3477
  }
1806
3478
  };
1807
3479
  }
3480
+ function svgClientPoint(svg, clientX, clientY, viewBoxWidth, viewBoxHeight) {
3481
+ const rect = svg.getBoundingClientRect();
3482
+ const scale = Math.min(rect.width / viewBoxWidth, rect.height / viewBoxHeight);
3483
+ if (!Number.isFinite(scale) || scale <= 0) {
3484
+ return { x: viewBoxWidth / 2, y: viewBoxHeight / 2 };
3485
+ }
3486
+ return {
3487
+ x: (clientX - rect.left - (rect.width - viewBoxWidth * scale) / 2) / scale,
3488
+ y: (clientY - rect.top - (rect.height - viewBoxHeight * scale) / 2) / scale
3489
+ };
3490
+ }
1808
3491
  var GRAPH_W = 360;
1809
3492
  var GRAPH_H = 260;
1810
3493
  var GRAPH_PAD = 28;
@@ -1813,24 +3496,24 @@ var GRAPH_LH = GRAPH_H - GRAPH_PAD * 2;
1813
3496
 
1814
3497
  // src/behaviors/kb-answer.ts
1815
3498
  var ASSET_TYPE_LABELS = {
1816
- "parameterized-query": "\u53C2\u6570\u5316\u67E5\u8BE2",
1817
- function: "\u51FD\u6570",
1818
- curated: "\u4EBA\u5DE5\u7B56\u5C55"
3499
+ "parameterized-query": t("kbAnswer.kindParameterized"),
3500
+ function: t("kbAnswer.kindFunction"),
3501
+ curated: t("kbAnswer.kindCurated")
1819
3502
  };
1820
3503
  var ICON_TRUSTED = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M20 13c0 5-3.5 7.5-7.7 9a.6.6 0 0 1-.6 0C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.2-2.7a1.2 1.2 0 0 1 1.6 0C14.5 3.8 17 5 19 5a1 1 0 0 1 1 1z"/><path d="m9 12 2 2 4-4"/></svg>';
1821
3504
  var ICON_SHIELD = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M20 13c0 5-3.5 7.5-7.7 9a.6.6 0 0 1-.6 0C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.2-2.7a1.2 1.2 0 0 1 1.6 0C14.5 3.8 17 5 19 5a1 1 0 0 1 1 1z"/></svg>';
1822
3505
  function renderVerifiedBadge(via, opts) {
1823
- const btn = h("button", "kb-verified");
3506
+ const btn = h("button", "icen-kb-verified");
1824
3507
  btn.type = "button";
1825
- if (via.assetId) btn.dataset.assetId = via.assetId;
1826
- const badge = h("span", "kb-badge kb-badge--trusted");
1827
- const svg2 = svgIcon(ICON_TRUSTED);
1828
- if (svg2) badge.appendChild(svg2);
1829
- badge.appendChild(document.createTextNode("\u8BA4\u8BC1\u7B54\u6848"));
3508
+ if (via.assetId) btn.dataset.icenAssetId = via.assetId;
3509
+ const badge = h("span", "icen-kb-badge icen-kb-badge--trusted");
3510
+ const svg = svgIcon(ICON_TRUSTED);
3511
+ if (svg) badge.appendChild(svg);
3512
+ badge.appendChild(document.createTextNode(t("kbAnswer.verifiedBadge")));
1830
3513
  btn.appendChild(badge);
1831
- btn.appendChild(h("span", "kb-verified-via", `\u547D\u4E2D\u8D44\u4EA7\uFF1A${ASSET_TYPE_LABELS[via.assetType] ?? via.assetType}`));
1832
- if (via.note) btn.appendChild(h("span", "kb-verified-note", via.note));
1833
- btn.appendChild(h("span", "kb-verified-hint", "\u53C2\u6570\u53EF\u6539\u91CD\u8DD1"));
3514
+ btn.appendChild(h("span", "icen-kb-verified-via", t("kbAnswer.hitAssets", { p0: ASSET_TYPE_LABELS[via.assetType] ?? via.assetType })));
3515
+ if (via.note) btn.appendChild(h("span", "icen-kb-verified-note", via.note));
3516
+ btn.appendChild(h("span", "icen-kb-verified-hint", t("kbAnswer.rerunTip")));
1834
3517
  btn.addEventListener("click", () => {
1835
3518
  emitIcen(btn, "icen:kb-verified-open", { assetId: via.assetId });
1836
3519
  opts?.onVerifiedOpen?.(via.assetId);
@@ -1838,32 +3521,34 @@ function renderVerifiedBadge(via, opts) {
1838
3521
  return btn;
1839
3522
  }
1840
3523
  function renderPermissionNotice(p) {
1841
- const box = h("div", "kb-perm");
1842
- const iconBox = h("span", "kb-perm-icon");
1843
- const svg2 = svgIcon(ICON_SHIELD);
1844
- if (svg2) iconBox.appendChild(svg2);
3524
+ const box = h("div", "icen-kb-perm");
3525
+ const iconBox = h("span", "icen-kb-perm-icon");
3526
+ const svg = svgIcon(ICON_SHIELD);
3527
+ if (svg) iconBox.appendChild(svg);
1845
3528
  box.appendChild(iconBox);
1846
- box.appendChild(h("span", "kb-perm-text", p.rowLevelPolicy ? `\u5DF2\u6309\u4F60\u7684\u6570\u636E\u6743\u9650\u8FC7\u6EE4\uFF1A${p.rowLevelPolicy}` : "\u5DF2\u6309\u4F60\u7684\u6570\u636E\u6743\u9650\u8FC7\u6EE4"));
3529
+ box.appendChild(h("span", "kb-perm-text", p.rowLevelPolicy ? t("kbAnswer.filteredDetail", { p0: p.rowLevelPolicy }) : t("kbAnswer.filtered")));
1847
3530
  if (p.maskedColumns?.length) {
1848
- const mask = h("span", "kb-perm-mask");
1849
- mask.appendChild(h("span", "kb-perm-mask-label", "\u5DF2\u8131\u654F\u5217\uFF1A"));
1850
- for (const col of p.maskedColumns) mask.appendChild(h("span", "kb-chip", col));
3531
+ const mask = h("span", "icen-kb-perm-mask");
3532
+ mask.appendChild(h("span", "icen-kb-perm-mask-label", t("kbAnswer.maskedPrefix")));
3533
+ for (const col of p.maskedColumns) mask.appendChild(h("span", "icen-kb-chip", col));
1851
3534
  box.appendChild(mask);
1852
3535
  }
1853
3536
  return box;
1854
3537
  }
1855
3538
  function renderBody(text, citations) {
1856
- const box = h("div", "kb-answer-body");
3539
+ const box = h("div", "icen-kb-answer-body");
1857
3540
  for (const seg of parseInlineCitations(text)) {
1858
- if (typeof seg.n === "number" && citations && seg.n >= 1 && seg.n <= citations.length) {
1859
- const sup = h("sup", "kb-citation", `[${seg.n}]`);
1860
- sup.dataset.cite = String(seg.n);
1861
- const c = citations[seg.n - 1];
1862
- if (c?.title) sup.title = c.title;
1863
- box.appendChild(sup);
1864
- } else {
1865
- box.appendChild(document.createTextNode(seg.text));
3541
+ if (typeof seg.n === "number" && citations) {
3542
+ const c = citations.find((x) => x.index === seg.n) ?? (seg.n >= 1 && seg.n <= citations.length ? citations[seg.n - 1] : void 0);
3543
+ if (c) {
3544
+ const sup = h("sup", "icen-kb-citation", `[${seg.n}]`);
3545
+ sup.dataset.icenCite = String(seg.n);
3546
+ if (c.title) sup.title = c.title;
3547
+ box.appendChild(sup);
3548
+ continue;
3549
+ }
1866
3550
  }
3551
+ box.appendChild(document.createTextNode(seg.text));
1867
3552
  }
1868
3553
  return box;
1869
3554
  }
@@ -1890,18 +3575,18 @@ function isNumericColumn(col, colIndex, rows) {
1890
3575
  }
1891
3576
  function renderResult(result, opts) {
1892
3577
  if (!result.columns.length) return null;
1893
- const wrap = h("div", "kb-answer-results");
1894
- const meta = h("div", "kb-result-meta");
1895
- meta.appendChild(h("span", "kb-num", `${formatCount(result.rowCount)} \u884C`));
3578
+ const wrap = h("div", "icen-kb-answer-results");
3579
+ const meta = h("div", "icen-kb-result-meta");
3580
+ meta.appendChild(h("span", "icen-kb-num", t("common.rows", { p0: formatCount(result.rowCount) })));
1896
3581
  if (result.durationMs != null) {
1897
- meta.appendChild(h("span", "kb-num kb-result-dur", `${Math.round(result.durationMs)} ms`));
3582
+ meta.appendChild(h("span", "icen-kb-num kb-result-dur", `${Math.round(result.durationMs)} ms`));
1898
3583
  }
1899
3584
  if (result.exportFormats?.length) {
1900
- const exports = h("span", "kb-result-export");
3585
+ const exports = h("span", "icen-kb-result-export");
1901
3586
  for (const fmt2 of result.exportFormats) {
1902
- const btn = h("button", "kb-result-export-btn", `\u5BFC\u51FA ${fmt2}`);
3587
+ const btn = h("button", "icen-kb-result-export-btn", t("kbAnswer.exportNoun", { p0: fmt2 }));
1903
3588
  btn.type = "button";
1904
- btn.dataset.format = fmt2;
3589
+ btn.dataset.icenFormat = fmt2;
1905
3590
  if (!opts?.onExport) btn.disabled = true;
1906
3591
  else btn.addEventListener("click", () => opts.onExport?.(fmt2));
1907
3592
  exports.appendChild(btn);
@@ -1909,13 +3594,13 @@ function renderResult(result, opts) {
1909
3594
  meta.appendChild(exports);
1910
3595
  }
1911
3596
  wrap.appendChild(meta);
1912
- const scroll = h("div", "kb-result-scroll");
1913
- const table = h("table", "kb-result-table");
3597
+ const scroll = h("div", "icen-kb-result-scroll");
3598
+ const table = h("table", "icen-kb-result-table");
1914
3599
  const numCols = result.columns.map((c, i) => isNumericColumn(c, i, result.rows));
1915
3600
  const thead = document.createElement("thead");
1916
3601
  const headRow = document.createElement("tr");
1917
3602
  result.columns.forEach((c, i) => {
1918
- headRow.appendChild(h("th", numCols[i] ? "kb-num" : "", c.name));
3603
+ headRow.appendChild(h("th", numCols[i] ? "icen-kb-num" : "", c.name));
1919
3604
  });
1920
3605
  thead.appendChild(headRow);
1921
3606
  table.appendChild(thead);
@@ -1925,10 +3610,10 @@ function renderResult(result, opts) {
1925
3610
  result.columns.forEach((_, i) => {
1926
3611
  const v = row[i];
1927
3612
  if (v == null) {
1928
- const td = h("td", "kb-result-null", "\u2014");
3613
+ const td = h("td", "icen-kb-result-null", "\u2014");
1929
3614
  tr.appendChild(td);
1930
3615
  } else {
1931
- tr.appendChild(h("td", typeof v === "number" ? "kb-num" : "", String(v)));
3616
+ tr.appendChild(h("td", typeof v === "number" ? "icen-kb-num" : "", String(v)));
1932
3617
  }
1933
3618
  });
1934
3619
  tbody.appendChild(tr);
@@ -1939,14 +3624,14 @@ function renderResult(result, opts) {
1939
3624
  if (result.truncated) {
1940
3625
  const total = result.totalRows != null ? formatCount(result.totalRows) : "\u2014";
1941
3626
  const limitPart = result.limit != null ? `\uFF08LIMIT ${formatCount(result.limit)}\uFF09` : "";
1942
- wrap.appendChild(h("div", "kb-notice kb-result-truncated", `\u5DF2\u622A\u65AD\uFF1A\u663E\u793A ${formatCount(result.rowCount)}/${total} \u884C${limitPart}`));
3627
+ wrap.appendChild(h("div", "icen-kb-notice icen-kb-result-truncated", t("kbAnswer.truncated", { p0: formatCount(result.rowCount), p1: total, p2: limitPart })));
1943
3628
  }
1944
3629
  return wrap;
1945
3630
  }
1946
3631
  var CHART_SWITCHES = [
1947
- { type: "line", label: "\u6298\u7EBF" },
1948
- { type: "vbar", label: "\u67F1\u72B6" },
1949
- { type: "donut", label: "\u997C\u56FE" }
3632
+ { type: "line", label: t("kbAnswer.chartLine") },
3633
+ { type: "vbar", label: t("kbAnswer.chartBar") },
3634
+ { type: "donut", label: t("kbAnswer.chartPie") }
1950
3635
  ];
1951
3636
  function switchable(spec) {
1952
3637
  const hasCat = (spec.labels?.length ?? 0) > 0 && ((spec.values?.length ?? 0) > 0 || (spec.series?.length ?? 0) > 0);
@@ -1977,14 +3662,14 @@ function specAsType(base, target) {
1977
3662
  function renderChartArea(raw) {
1978
3663
  if (raw == null) return null;
1979
3664
  const norm = normalizeChartSpec(raw);
1980
- const area = h("div", "kb-answer-chart");
1981
- const mount = h("div", "chart kb-chart-mount");
3665
+ const area = h("div", "icen-kb-answer-chart");
3666
+ const mount = h("div", "icen-chart icen-kb-chart-mount");
1982
3667
  const handle = renderChart(mount, norm);
1983
3668
  if (switchable(handle.spec)) {
1984
- const switchRow = h("div", "kb-chart-switch");
3669
+ const switchRow = h("div", "icen-kb-chart-switch");
1985
3670
  const chips = /* @__PURE__ */ new Map();
1986
3671
  for (const s of CHART_SWITCHES) {
1987
- const chip = h("button", "kb-chart-chip", s.label);
3672
+ const chip = h("button", "icen-kb-chart-chip", s.label);
1988
3673
  chip.type = "button";
1989
3674
  chip.dataset.chartType = s.type;
1990
3675
  if (handle.spec.type === s.type) chip.classList.add("is-active");
@@ -2006,9 +3691,9 @@ function renderKbAnswer(el, model, opts) {
2006
3691
  if (typeof document === "undefined") return el;
2007
3692
  const m = model ?? {};
2008
3693
  el.textContent = "";
2009
- const root = h("article", "kb-answer");
2010
- root.dataset.kind = m.kind === "verified" ? "verified" : "generated";
2011
- const badges = h("div", "kb-answer-badges");
3694
+ const root = h("article", "icen-kb-answer");
3695
+ root.dataset.icenKind = m.kind === "verified" ? "verified" : "generated";
3696
+ const badges = h("div", "icen-kb-answer-badges");
2012
3697
  if (m.kind === "verified" && m.verifiedVia) badges.appendChild(renderVerifiedBadge(m.verifiedVia, opts));
2013
3698
  if (m.permissionNotice && (m.permissionNotice.rowLevelPolicy || m.permissionNotice.maskedColumns?.length)) {
2014
3699
  badges.appendChild(renderPermissionNotice(m.permissionNotice));
@@ -2016,7 +3701,7 @@ function renderKbAnswer(el, model, opts) {
2016
3701
  if (badges.children.length > 0) root.appendChild(badges);
2017
3702
  if (typeof m.body === "string" && m.body) root.appendChild(renderBody(m.body, m.citations));
2018
3703
  if (m.clarify && (m.clarify.question || m.clarify.options?.length)) {
2019
- const slot = h("div", "kb-answer-clarify");
3704
+ const slot = h("div", "icen-kb-answer-clarify");
2020
3705
  renderKbClarify(slot, m.clarify);
2021
3706
  root.appendChild(slot);
2022
3707
  }
@@ -2024,7 +3709,7 @@ function renderKbAnswer(el, model, opts) {
2024
3709
  const f = m.explain;
2025
3710
  const hasAny = f.tables?.length || f.columns?.length || f.filters?.length || f.aggregates?.length || f.metrics?.length;
2026
3711
  if (hasAny) {
2027
- const slot = h("div", "kb-answer-explain");
3712
+ const slot = h("div", "icen-kb-answer-explain");
2028
3713
  renderKbExplain(slot, f);
2029
3714
  root.appendChild(slot);
2030
3715
  }
@@ -2037,10 +3722,10 @@ function renderKbAnswer(el, model, opts) {
2037
3722
  if (chartArea) root.appendChild(chartArea);
2038
3723
  const followUps = (m.followUps ?? []).map((s) => String(s ?? "").trim()).filter(Boolean);
2039
3724
  if (followUps.length > 0) {
2040
- const row = h("div", "kb-answer-followups");
2041
- row.appendChild(h("span", "kb-followups-label", "\u8FFD\u95EE\u5EFA\u8BAE"));
3725
+ const row = h("div", "icen-kb-answer-followups");
3726
+ row.appendChild(h("span", "icen-kb-followups-label", t("kbAnswer.followups")));
2042
3727
  for (const text of followUps) {
2043
- const chip = h("button", "kb-chip kb-followup", text);
3728
+ const chip = h("button", "icen-kb-chip icen-kb-followup", text);
2044
3729
  chip.type = "button";
2045
3730
  chip.addEventListener("click", () => opts?.onFollowUp?.(text));
2046
3731
  row.appendChild(chip);