@icen.ai/ui 0.8.0 → 0.9.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.
- package/AGENTS.md +63 -14
- package/README.md +17 -9
- package/dist/base.css +4 -3
- package/dist/behaviors/accordion.d.mts +5 -2
- package/dist/behaviors/accordion.mjs +36 -11
- package/dist/behaviors/ai-branch.d.mts +19 -0
- package/dist/behaviors/ai-branch.mjs +217 -0
- package/dist/behaviors/ai-chat.d.mts +11 -7
- package/dist/behaviors/ai-chat.mjs +134 -51
- package/dist/behaviors/ai-composer.d.mts +28 -3
- package/dist/behaviors/ai-composer.mjs +399 -229
- package/dist/behaviors/ai-core.d.mts +9 -4
- package/dist/behaviors/ai-core.mjs +21 -8
- package/dist/behaviors/ai-diff.d.mts +2 -2
- package/dist/behaviors/ai-diff.mjs +172 -41
- package/dist/behaviors/ai-feedback.d.mts +26 -0
- package/dist/behaviors/ai-feedback.mjs +303 -0
- package/dist/behaviors/ai-panel.d.mts +26 -9
- package/dist/behaviors/ai-panel.mjs +211 -110
- package/dist/behaviors/ai-provider.mjs +54 -48
- package/dist/behaviors/ai-threads.d.mts +38 -0
- package/dist/behaviors/ai-threads.mjs +319 -0
- package/dist/behaviors/ai-tool.d.mts +12 -4
- package/dist/behaviors/ai-tool.mjs +316 -263
- package/dist/behaviors/ai-tools.d.mts +9 -6
- package/dist/behaviors/ai-tools.mjs +264 -155
- package/dist/behaviors/back-top.mjs +16 -1
- package/dist/behaviors/carousel.d.mts +5 -2
- package/dist/behaviors/carousel.mjs +53 -26
- package/dist/behaviors/charts.d.mts +170 -22
- package/dist/behaviors/charts.mjs +1016 -150
- package/dist/behaviors/command-palette.d.mts +40 -6
- package/dist/behaviors/command-palette.mjs +143 -15
- package/dist/behaviors/context-menu.d.mts +21 -4
- package/dist/behaviors/context-menu.mjs +122 -38
- package/dist/behaviors/controls.d.mts +59 -0
- package/dist/behaviors/controls.mjs +601 -0
- package/dist/behaviors/copy.d.mts +5 -2
- package/dist/behaviors/copy.mjs +37 -12
- package/dist/behaviors/datatable.d.mts +12 -0
- package/dist/behaviors/datatable.mjs +226 -43
- package/dist/behaviors/date-picker.d.mts +2 -2
- package/dist/behaviors/date-picker.mjs +171 -32
- package/dist/behaviors/dropdown.d.mts +6 -2
- package/dist/behaviors/dropdown.mjs +164 -25
- package/dist/behaviors/events.d.mts +523 -0
- package/dist/behaviors/events.mjs +208 -0
- package/dist/behaviors/input.mjs +25 -12
- package/dist/behaviors/kb-access.d.mts +34 -0
- package/dist/behaviors/kb-access.mjs +569 -0
- package/dist/behaviors/kb-acl.d.mts +50 -0
- package/dist/behaviors/kb-acl.mjs +405 -0
- package/dist/behaviors/kb-answer.d.mts +38 -0
- package/dist/behaviors/kb-answer.mjs +2055 -0
- package/dist/behaviors/kb-audit.d.mts +23 -0
- package/dist/behaviors/kb-audit.mjs +375 -0
- package/dist/behaviors/kb-canvas.d.mts +44 -0
- package/dist/behaviors/kb-canvas.mjs +589 -0
- package/dist/behaviors/kb-chain.d.mts +15 -0
- package/dist/behaviors/kb-chain.mjs +270 -0
- package/dist/behaviors/kb-checkpoint.d.mts +16 -0
- package/dist/behaviors/kb-checkpoint.mjs +342 -0
- package/dist/behaviors/kb-chunks.d.mts +31 -0
- package/dist/behaviors/kb-chunks.mjs +475 -0
- package/dist/behaviors/kb-citation.d.mts +38 -0
- package/dist/behaviors/kb-citation.mjs +677 -0
- package/dist/behaviors/kb-clarify.d.mts +20 -0
- package/dist/behaviors/kb-clarify.mjs +248 -0
- package/dist/behaviors/kb-conflict.d.mts +22 -0
- package/dist/behaviors/kb-conflict.mjs +284 -0
- package/dist/behaviors/kb-connector.d.mts +17 -0
- package/dist/behaviors/kb-connector.mjs +375 -0
- package/dist/behaviors/kb-core.d.mts +529 -0
- package/dist/behaviors/kb-core.mjs +890 -0
- package/dist/behaviors/kb-eval.d.mts +22 -0
- package/dist/behaviors/kb-eval.mjs +408 -0
- package/dist/behaviors/kb-explain.d.mts +11 -0
- package/dist/behaviors/kb-explain.mjs +243 -0
- package/dist/behaviors/kb-filter.d.mts +31 -0
- package/dist/behaviors/kb-filter.mjs +587 -0
- package/dist/behaviors/kb-gap.d.mts +27 -0
- package/dist/behaviors/kb-gap.mjs +273 -0
- package/dist/behaviors/kb-hittest.d.mts +34 -0
- package/dist/behaviors/kb-hittest.mjs +409 -0
- package/dist/behaviors/kb-metadata.d.mts +29 -0
- package/dist/behaviors/kb-metadata.mjs +326 -0
- package/dist/behaviors/kb-passage.d.mts +41 -0
- package/dist/behaviors/kb-passage.mjs +529 -0
- package/dist/behaviors/kb-pipeline.d.mts +18 -0
- package/dist/behaviors/kb-pipeline.mjs +381 -0
- package/dist/behaviors/kb-qa.d.mts +26 -0
- package/dist/behaviors/kb-qa.mjs +332 -0
- package/dist/behaviors/kb-rerank.d.mts +20 -0
- package/dist/behaviors/kb-rerank.mjs +315 -0
- package/dist/behaviors/kb-retrieval.d.mts +49 -0
- package/dist/behaviors/kb-retrieval.mjs +746 -0
- package/dist/behaviors/kb-review.d.mts +44 -0
- package/dist/behaviors/kb-review.mjs +451 -0
- package/dist/behaviors/kb-sandbox.d.mts +33 -0
- package/dist/behaviors/kb-sandbox.mjs +325 -0
- package/dist/behaviors/kb-segment.d.mts +32 -0
- package/dist/behaviors/kb-segment.mjs +499 -0
- package/dist/behaviors/kb-sources.d.mts +27 -0
- package/dist/behaviors/kb-sources.mjs +373 -0
- package/dist/behaviors/kb-sql.d.mts +43 -0
- package/dist/behaviors/kb-sql.mjs +948 -0
- package/dist/behaviors/kb-trace.d.mts +16 -0
- package/dist/behaviors/kb-trace.mjs +414 -0
- package/dist/behaviors/kb-visibility.d.mts +44 -0
- package/dist/behaviors/kb-visibility.mjs +403 -0
- package/dist/behaviors/kb-who-can.d.mts +32 -0
- package/dist/behaviors/kb-who-can.mjs +379 -0
- package/dist/behaviors/modal.d.mts +24 -5
- package/dist/behaviors/modal.mjs +76 -10
- package/dist/behaviors/nav.d.mts +1 -1
- package/dist/behaviors/nav.mjs +33 -7
- package/dist/behaviors/notification.d.mts +20 -4
- package/dist/behaviors/notification.mjs +53 -73
- package/dist/behaviors/popover.d.mts +39 -3
- package/dist/behaviors/popover.mjs +90 -4
- package/dist/behaviors/select.d.mts +4 -2
- package/dist/behaviors/select.mjs +161 -24
- package/dist/behaviors/sidebar.d.mts +5 -2
- package/dist/behaviors/sidebar.mjs +43 -13
- package/dist/behaviors/slider.d.mts +5 -2
- package/dist/behaviors/slider.mjs +54 -43
- package/dist/behaviors/split-pane.d.mts +6 -2
- package/dist/behaviors/split-pane.mjs +62 -21
- package/dist/behaviors/tabs.d.mts +3 -2
- package/dist/behaviors/tabs.mjs +65 -14
- package/dist/behaviors/tag-input.d.mts +5 -2
- package/dist/behaviors/tag-input.mjs +61 -21
- package/dist/behaviors/theme.d.mts +13 -2
- package/dist/behaviors/theme.mjs +48 -4
- package/dist/behaviors/toast.d.mts +30 -8
- package/dist/behaviors/toast.mjs +74 -7
- package/dist/behaviors/tree.d.mts +5 -2
- package/dist/behaviors/tree.mjs +38 -15
- package/dist/behaviors/upload.mjs +21 -23
- package/dist/cli.mjs +1 -1
- package/dist/components/ai-branch.mjs +3 -0
- package/dist/components/ai-chat.css +295 -0
- package/dist/components/ai-feedback.mjs +3 -0
- package/dist/components/ai-panel.css +218 -1
- package/dist/components/ai-threads.mjs +3 -0
- package/dist/components/ai-tool-call.mjs +1 -1
- package/dist/components/badge.css +1 -1
- package/dist/components/breadcrumb.css +0 -32
- package/dist/components/chart-calendar.mjs +1 -2
- package/dist/components/chart-graph.css +57 -0
- package/dist/components/chart-graph.mjs +4 -0
- package/dist/components/chart-map.mjs +3 -0
- package/dist/components/chart-pie.css +0 -6
- package/dist/components/chart-scatter.mjs +1 -1
- package/dist/components/charts.css +33 -1
- package/dist/components/charts.mjs +1 -0
- package/dist/components/content.css +3 -16
- package/dist/components/datatable.css +1 -1
- package/dist/components/date-picker.css +1 -1
- package/dist/components/kb-access.mjs +4 -0
- package/dist/components/kb-acl.mjs +4 -0
- package/dist/components/kb-agent.css +481 -0
- package/dist/components/kb-answer.mjs +4 -0
- package/dist/components/kb-audit.mjs +4 -0
- package/dist/components/kb-canvas.mjs +4 -0
- package/dist/components/kb-chain.mjs +4 -0
- package/dist/components/kb-checkpoint.mjs +4 -0
- package/dist/components/kb-chunks.mjs +4 -0
- package/dist/components/kb-citation.mjs +4 -0
- package/dist/components/kb-clarify.mjs +4 -0
- package/dist/components/kb-conflict.mjs +4 -0
- package/dist/components/kb-connector.mjs +4 -0
- package/dist/components/kb-data.css +649 -0
- package/dist/components/kb-eval.mjs +4 -0
- package/dist/components/kb-explain.mjs +4 -0
- package/dist/components/kb-filter.mjs +4 -0
- package/dist/components/kb-gap.mjs +4 -0
- package/dist/components/kb-ground.css +566 -0
- package/dist/components/kb-hittest.mjs +4 -0
- package/dist/components/kb-ingest.css +898 -0
- package/dist/components/kb-metadata.mjs +4 -0
- package/dist/components/kb-ops.css +548 -0
- package/dist/components/kb-passage.mjs +4 -0
- package/dist/components/kb-perm.css +444 -0
- package/dist/components/kb-pipeline.mjs +4 -0
- package/dist/components/kb-qa.mjs +4 -0
- package/dist/components/kb-rerank.mjs +4 -0
- package/dist/components/kb-retrieval.mjs +4 -0
- package/dist/components/kb-review.mjs +4 -0
- package/dist/components/kb-sandbox.mjs +4 -0
- package/dist/components/kb-search.css +940 -0
- package/dist/components/kb-segment.mjs +4 -0
- package/dist/components/kb-sources.mjs +4 -0
- package/dist/components/kb-sql.mjs +4 -0
- package/dist/components/kb-trace.mjs +4 -0
- package/dist/components/kb-visibility.mjs +4 -0
- package/dist/components/kb-who-can.mjs +4 -0
- package/dist/components/kb.css +252 -0
- package/dist/components/kb.mjs +9 -0
- package/dist/components/notification.css +2 -3
- package/dist/components/pagination.css +3 -1
- package/dist/components/pagination.mjs +1 -0
- package/dist/components/rating.mjs +1 -0
- package/dist/components/segmented.css +9 -1
- package/dist/components/segmented.mjs +1 -1
- package/dist/components/select.css +67 -4
- package/dist/components/steps.css +13 -3
- package/dist/components/steps.mjs +1 -0
- package/dist/components/switch.css +3 -1
- package/dist/components/switch.mjs +1 -0
- package/dist/components/table.mjs +1 -0
- package/dist/components/tabs.css +23 -0
- package/dist/components/tag-input.css +1 -6
- package/dist/components/upload.css +0 -15
- package/dist/index.d.mts +48 -11
- package/dist/index.mjs +13205 -3615
- package/dist/registry.json +366 -15
- package/dist/retro-effects.css +3 -16
- package/dist/tokens/retro-effects.css +3 -16
- package/dist/tokens/style-profiles.css +3 -2
- package/dist/tokens/typography.css +2 -0
- package/dist/tokens.css +5 -2
- package/dist/ui.css +5713 -267
- package/docs/research/2026-10-03-ai-kb-components.md +392 -0
- package/docs/research/2026-10-03-kb-permissions.md +992 -0
- package/docs/spec/ai-native.md +7 -4
- package/docs/spec/kb-family.md +443 -0
- package/package.json +2 -2
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
// 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
|
+
);
|
|
50
|
+
function isObj(v) {
|
|
51
|
+
return typeof v === "object" && v !== null;
|
|
52
|
+
}
|
|
53
|
+
function pickStr(input, keys) {
|
|
54
|
+
if (!isObj(input)) return void 0;
|
|
55
|
+
for (const k of keys) {
|
|
56
|
+
const v = input[k];
|
|
57
|
+
if (typeof v === "string" && v) return v;
|
|
58
|
+
}
|
|
59
|
+
return void 0;
|
|
60
|
+
}
|
|
61
|
+
function pickNum(src, keys) {
|
|
62
|
+
if (!isObj(src)) return void 0;
|
|
63
|
+
for (const k of keys) {
|
|
64
|
+
const v = src[k];
|
|
65
|
+
if (typeof v === "number" && Number.isFinite(v)) return v;
|
|
66
|
+
}
|
|
67
|
+
return void 0;
|
|
68
|
+
}
|
|
69
|
+
function firstLine(s, max = 80) {
|
|
70
|
+
const line = s.split("\n", 1)[0]?.trim() ?? "";
|
|
71
|
+
return line.length > max ? `${line.slice(0, max)}\u2026` : line;
|
|
72
|
+
}
|
|
73
|
+
function filePathOf(input) {
|
|
74
|
+
return pickStr(input, ["file_path", "path", "file", "filename"]);
|
|
75
|
+
}
|
|
76
|
+
var summarizePath = (input) => filePathOf(input);
|
|
77
|
+
function summarizeRead(input) {
|
|
78
|
+
const p = filePathOf(input);
|
|
79
|
+
if (!p) return void 0;
|
|
80
|
+
const offset = pickNum(input, ["offset", "start_line"]);
|
|
81
|
+
if (offset == null) return p;
|
|
82
|
+
const limit = pickNum(input, ["limit", "end_line"]);
|
|
83
|
+
return limit != null ? `${p}:${offset}-${offset + limit}` : `${p}:${offset}`;
|
|
84
|
+
}
|
|
85
|
+
function summarizeShell(input) {
|
|
86
|
+
const cmd = typeof input === "string" ? input : pickStr(input, ["command", "cmd", "script"]);
|
|
87
|
+
return cmd ? firstLine(cmd) : void 0;
|
|
88
|
+
}
|
|
89
|
+
function summarizeGrep(input) {
|
|
90
|
+
const pattern = pickStr(input, ["pattern", "regex", "query"]);
|
|
91
|
+
const p = filePathOf(input);
|
|
92
|
+
if (pattern) return p ? `${firstLine(pattern, 40)} \xB7 ${p}` : firstLine(pattern);
|
|
93
|
+
return p;
|
|
94
|
+
}
|
|
95
|
+
var sum = (fn) => {
|
|
96
|
+
return (input) => fn(input) ?? "";
|
|
97
|
+
};
|
|
98
|
+
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"])) },
|
|
109
|
+
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"])) },
|
|
111
|
+
todo: {
|
|
112
|
+
label: "\u5F85\u529E",
|
|
113
|
+
icon: ICON_LIST,
|
|
114
|
+
tint: "info",
|
|
115
|
+
summarize: sum((input) => {
|
|
116
|
+
const items = input && typeof input === "object" && Array.isArray(input.items) ? input.items : Array.isArray(input) ? input : [];
|
|
117
|
+
const done = items.filter((it) => it?.status === "done").length;
|
|
118
|
+
return items.length > 0 ? `${done}/${items.length} \u5B8C\u6210` : "";
|
|
119
|
+
})
|
|
120
|
+
},
|
|
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"])) }
|
|
125
|
+
};
|
|
126
|
+
var kindRegistry = new Map(Object.entries(BUILTIN_KINDS));
|
|
127
|
+
function h(tag, className, text) {
|
|
128
|
+
const node = document.createElement(tag);
|
|
129
|
+
if (className) node.className = className;
|
|
130
|
+
if (text != null) node.textContent = text;
|
|
131
|
+
return node;
|
|
132
|
+
}
|
|
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);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// src/behaviors/events.ts
|
|
167
|
+
function emitIcen(source, type, detail) {
|
|
168
|
+
return source.dispatchEvent(
|
|
169
|
+
new CustomEvent(type, { detail, bubbles: true, composed: true, cancelable: true })
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// src/behaviors/ai-feedback.ts
|
|
174
|
+
var DEFAULT_REASONS = ["\u7B54\u6848\u6709\u8BEF", "\u5F15\u7528\u4E0D\u7B26", "\u5185\u5BB9\u8FC7\u65F6", "\u65E0\u5F15\u7528\u4F9D\u636E", "\u8D8A\u6743\u4FE1\u606F"];
|
|
175
|
+
var ICON_THUMB_UP = '<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="M7 10v12"/><path d="M15 5.88 14 10h5.83a2 2 0 0 1 1.92 2.56l-2.33 8A2 2 0 0 1 17.5 22H4a2 2 0 0 1-2-2v-8a2 2 0 0 1 2-2h2.76a2 2 0 0 0 1.79-1.11L12 2a3.13 3.13 0 0 1 3 3.88Z"/></svg>';
|
|
176
|
+
var ICON_THUMB_DOWN = '<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="M17 14V2"/><path d="M9 18.12 10 14H4.17a2 2 0 0 1-1.92-2.56l2.33-8A2 2 0 0 1 6.5 2H20a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2h-2.76a2 2 0 0 0-1.79 1.11L12 22a3.13 3.13 0 0 1-3-3.88Z"/></svg>';
|
|
177
|
+
var feedbackCallbacks = /* @__PURE__ */ new WeakMap();
|
|
178
|
+
function renderAiFeedback(el, opts = {}) {
|
|
179
|
+
if (typeof document === "undefined") return el;
|
|
180
|
+
el.textContent = "";
|
|
181
|
+
const root = h("div", "ai-feedback");
|
|
182
|
+
const votes = h("div", "ai-feedback-votes");
|
|
183
|
+
for (const dir of ["is-up", "is-down"]) {
|
|
184
|
+
const btn = h("button", `ai-feedback-vote ${dir}`);
|
|
185
|
+
btn.type = "button";
|
|
186
|
+
btn.setAttribute("aria-pressed", "false");
|
|
187
|
+
btn.setAttribute("aria-label", dir === "is-up" ? "\u6709\u5E2E\u52A9" : "\u65E0\u5E2E\u52A9");
|
|
188
|
+
const icon = svgIcon(dir === "is-up" ? ICON_THUMB_UP : ICON_THUMB_DOWN);
|
|
189
|
+
if (icon) btn.appendChild(icon);
|
|
190
|
+
votes.appendChild(btn);
|
|
191
|
+
}
|
|
192
|
+
root.appendChild(votes);
|
|
193
|
+
const reasons = h("div", "ai-feedback-reasons");
|
|
194
|
+
reasons.hidden = true;
|
|
195
|
+
const chips = (opts.reasons && opts.reasons.length > 0 ? opts.reasons : Array.from(DEFAULT_REASONS)).filter((r) => typeof r === "string" && r.trim() !== "");
|
|
196
|
+
for (const r of chips) {
|
|
197
|
+
const chip = h("button", "ai-feedback-chip", r);
|
|
198
|
+
chip.type = "button";
|
|
199
|
+
chip.setAttribute("aria-pressed", "false");
|
|
200
|
+
reasons.appendChild(chip);
|
|
201
|
+
}
|
|
202
|
+
const submit = h("button", "ai-feedback-submit", "\u63D0\u4EA4");
|
|
203
|
+
submit.type = "button";
|
|
204
|
+
reasons.appendChild(submit);
|
|
205
|
+
root.appendChild(reasons);
|
|
206
|
+
const done = h("div", "ai-feedback-done", "\u611F\u8C22\u53CD\u9988\uFF0C\u5DF2\u5173\u8054\u5230\u8BE5\u6761\u56DE\u7B54\u7684\u8FFD\u8E2A\u8BB0\u5F55");
|
|
207
|
+
done.hidden = true;
|
|
208
|
+
root.appendChild(done);
|
|
209
|
+
if (opts.onFeedback) feedbackCallbacks.set(root, opts.onFeedback);
|
|
210
|
+
el.appendChild(root);
|
|
211
|
+
return el;
|
|
212
|
+
}
|
|
213
|
+
function notify(root, detail) {
|
|
214
|
+
emitIcen(root, "icen:ai-feedback", { value: detail.value, reason: detail.reason, el: root });
|
|
215
|
+
const cb = feedbackCallbacks.get(root);
|
|
216
|
+
if (cb) cb({ value: detail.value, reason: detail.reason, el: root });
|
|
217
|
+
}
|
|
218
|
+
function voteOf(btn) {
|
|
219
|
+
if (btn.classList.contains("is-up")) return 1;
|
|
220
|
+
if (btn.classList.contains("is-down")) return -1;
|
|
221
|
+
return void 0;
|
|
222
|
+
}
|
|
223
|
+
function resetVotes(root) {
|
|
224
|
+
for (const btn of Array.from(root.querySelectorAll(".ai-feedback-vote"))) {
|
|
225
|
+
btn.classList.remove("is-picked");
|
|
226
|
+
btn.disabled = false;
|
|
227
|
+
btn.setAttribute("aria-pressed", "false");
|
|
228
|
+
}
|
|
229
|
+
const reasons = root.querySelector(".ai-feedback-reasons");
|
|
230
|
+
if (reasons) reasons.hidden = true;
|
|
231
|
+
}
|
|
232
|
+
function pickVote(root, btn, value) {
|
|
233
|
+
for (const other of Array.from(root.querySelectorAll(".ai-feedback-vote"))) {
|
|
234
|
+
if (other === btn) {
|
|
235
|
+
other.classList.add("is-picked");
|
|
236
|
+
other.disabled = false;
|
|
237
|
+
other.setAttribute("aria-pressed", "true");
|
|
238
|
+
} else {
|
|
239
|
+
other.classList.remove("is-picked");
|
|
240
|
+
other.disabled = true;
|
|
241
|
+
other.setAttribute("aria-pressed", "false");
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
const reasons = root.querySelector(".ai-feedback-reasons");
|
|
245
|
+
if (reasons) reasons.hidden = value !== -1;
|
|
246
|
+
}
|
|
247
|
+
function initAiFeedback(root) {
|
|
248
|
+
if (typeof document === "undefined") return () => void 0;
|
|
249
|
+
const scope = root ?? document;
|
|
250
|
+
const marked = scope;
|
|
251
|
+
if (marked.__icenAiFeedbackInit) return () => void 0;
|
|
252
|
+
marked.__icenAiFeedbackInit = true;
|
|
253
|
+
const target = scope;
|
|
254
|
+
const onClick = (e) => {
|
|
255
|
+
const t = e.target instanceof Element ? e.target : null;
|
|
256
|
+
if (!t) return;
|
|
257
|
+
const rootEl = t.closest(".ai-feedback");
|
|
258
|
+
if (!rootEl || rootEl.classList.contains("is-done")) return;
|
|
259
|
+
const chip = t.closest(".ai-feedback-chip");
|
|
260
|
+
if (chip) {
|
|
261
|
+
const picked = chip.classList.contains("is-picked");
|
|
262
|
+
for (const c of Array.from(rootEl.querySelectorAll(".ai-feedback-chip"))) {
|
|
263
|
+
c.classList.remove("is-picked");
|
|
264
|
+
c.setAttribute("aria-pressed", "false");
|
|
265
|
+
}
|
|
266
|
+
if (!picked) {
|
|
267
|
+
chip.classList.add("is-picked");
|
|
268
|
+
chip.setAttribute("aria-pressed", "true");
|
|
269
|
+
}
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
if (t.closest(".ai-feedback-submit")) {
|
|
273
|
+
const reason = rootEl.querySelector(".ai-feedback-chip.is-picked")?.textContent ?? void 0;
|
|
274
|
+
rootEl.classList.add("is-done");
|
|
275
|
+
const done = rootEl.querySelector(".ai-feedback-done");
|
|
276
|
+
if (done) done.hidden = false;
|
|
277
|
+
const reasons = rootEl.querySelector(".ai-feedback-reasons");
|
|
278
|
+
if (reasons) reasons.hidden = true;
|
|
279
|
+
notify(rootEl, { value: -1, reason: reason || void 0 });
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
const voteBtn = t.closest(".ai-feedback-vote");
|
|
283
|
+
if (!voteBtn || voteBtn.disabled) return;
|
|
284
|
+
const value = voteOf(voteBtn);
|
|
285
|
+
if (value === void 0) return;
|
|
286
|
+
if (voteBtn.classList.contains("is-picked")) {
|
|
287
|
+
resetVotes(rootEl);
|
|
288
|
+
notify(rootEl, { value: 0 });
|
|
289
|
+
} else {
|
|
290
|
+
pickVote(rootEl, voteBtn, value);
|
|
291
|
+
notify(rootEl, { value });
|
|
292
|
+
}
|
|
293
|
+
};
|
|
294
|
+
target.addEventListener("click", onClick);
|
|
295
|
+
return () => {
|
|
296
|
+
target.removeEventListener("click", onClick);
|
|
297
|
+
marked.__icenAiFeedbackInit = false;
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
export {
|
|
301
|
+
initAiFeedback,
|
|
302
|
+
renderAiFeedback
|
|
303
|
+
};
|
|
@@ -9,24 +9,39 @@ interface AiTodoItem {
|
|
|
9
9
|
}
|
|
10
10
|
/**
|
|
11
11
|
* 渲染 todo 列表(DOM API,全 textContent)。全部完成时容器加 .is-complete。
|
|
12
|
+
* 每项附 .ai-todo-check 描边勾(§5.27:done 时 CSS 显隐 + 480ms 描边动画,一次不循环)。
|
|
13
|
+
* 返回挂载容器 el(render* 返回挂载元素约定,SSR 下原样返回)。
|
|
12
14
|
*/
|
|
13
|
-
declare function renderAiTodo(
|
|
15
|
+
declare function renderAiTodo(el: HTMLElement, items: AiTodoItem[]): HTMLElement;
|
|
14
16
|
/**
|
|
15
17
|
* todo 委托初始化:仅 data-ai-todo-interactive 容器可点击循环状态(pending→running→done),
|
|
16
18
|
* 只读列表不挂交互。重复调用安全;返回销毁函数。
|
|
17
19
|
*/
|
|
18
20
|
declare function initAiTodo(root?: ParentNode): () => void;
|
|
21
|
+
/** 用量派生指标(§5.27):opts.metrics 给出,或直接挂在 usage 对象同级字段上 */
|
|
22
|
+
interface AiUsageMetrics {
|
|
23
|
+
/** 首 token 延迟(毫秒) */
|
|
24
|
+
ttftMs?: number;
|
|
25
|
+
/** 生成吞吐(tokens/秒) */
|
|
26
|
+
tokensPerSec?: number;
|
|
27
|
+
/** finish reason(stop / length / tool_calls…) */
|
|
28
|
+
finishReason?: string;
|
|
29
|
+
}
|
|
19
30
|
interface AiUsageRenderOpts {
|
|
20
31
|
/** 上下文上限(如 200k):给出时 total 行显示 82k / 200k · 41% */
|
|
21
32
|
total?: number;
|
|
22
33
|
/** 成本(USD):给出时追加到 total 行 */
|
|
23
34
|
cost?: number;
|
|
35
|
+
/** 派生指标(§5.27):任一字段给出时图例下补一行 mono 明细(TTFT 0.8s · 42 tok/s · finish: stop) */
|
|
36
|
+
metrics?: AiUsageMetrics;
|
|
24
37
|
}
|
|
25
38
|
/**
|
|
26
|
-
* 渲染用量分段条 + 图例 +
|
|
39
|
+
* 渲染用量分段条 + 图例 + 占比。返回挂载容器 el(render* 返回挂载元素约定)。
|
|
27
40
|
* 配色契约:input=accent / output=success / cacheRead=info / cacheWrite=warning / reasoning=faint。
|
|
41
|
+
* opts.metrics(或 usage 同级 ttftMs/tokensPerSec/finishReason)存在时图例下补一行
|
|
42
|
+
* .ai-usage-metrics mono 明细(§5.27)。
|
|
28
43
|
*/
|
|
29
|
-
declare function renderAiUsage(
|
|
44
|
+
declare function renderAiUsage(el: HTMLElement, usage: AiUsage, opts?: AiUsageRenderOpts): HTMLElement;
|
|
30
45
|
interface AiUsageRingOpts extends AiUsageRenderOpts {
|
|
31
46
|
/** 弹层标题(默认「上下文窗口」) */
|
|
32
47
|
title?: string;
|
|
@@ -37,9 +52,9 @@ interface AiUsageRingOpts extends AiUsageRenderOpts {
|
|
|
37
52
|
* opts.total 给上下文窗口上限(如 200000)——环填充比 = 已用 / total;
|
|
38
53
|
* 缺省 total 时环不填充、中心显示已用量。
|
|
39
54
|
* 状态档:<60% is-ok(accent)/ 60–85% is-warn / >85% is-hot(error)。
|
|
40
|
-
*
|
|
55
|
+
* 重复调用重渲染;打开中的弹层会被关闭重建。返回挂载容器 el。
|
|
41
56
|
*/
|
|
42
|
-
declare function renderAiUsageRing(
|
|
57
|
+
declare function renderAiUsageRing(el: HTMLElement, usage: AiUsage, opts?: AiUsageRingOpts): HTMLElement;
|
|
43
58
|
interface AiContextFile {
|
|
44
59
|
path: string;
|
|
45
60
|
status?: 'added' | 'modified' | 'deleted';
|
|
@@ -68,14 +83,16 @@ interface AiContextModel {
|
|
|
68
83
|
/**
|
|
69
84
|
* 组合渲染上下文抽屉:usage → renderAiUsage;files → ai-file-chip;
|
|
70
85
|
* mcpServers / skills → .ai-item 行。aside 默认 hidden,由 initAiContext 开合。
|
|
86
|
+
* 返回挂载容器 el(render* 返回挂载元素约定)。
|
|
71
87
|
*/
|
|
72
|
-
declare function renderAiContext(
|
|
88
|
+
declare function renderAiContext(el: HTMLElement, model: AiContextModel): HTMLElement;
|
|
73
89
|
/**
|
|
74
90
|
* 触发器 [data-ai-context-open] 委托开合:
|
|
75
91
|
* - 属性值为 #id / 选择器时定位对应抽屉,空值取 scope 内第一个非 inline 抽屉
|
|
76
92
|
* - 打开:去 hidden → reflow → .is-open 滑入(CSS transition),焦点移入 close 钮
|
|
77
93
|
* - 关闭:[data-ai-context-close] / Esc / 外点;.is-open 移除 → transition 结束(或兜底计时)
|
|
78
94
|
* 后恢复 hidden,焦点还原触发器;Tab/Shift+Tab 焦点圈禁
|
|
95
|
+
* - 开/合从抽屉根元素派 icen:ai-context-open {} / icen:ai-context-close {}(bubbles)
|
|
79
96
|
* - .ai-context--inline 为页面流内嵌变体:不参与开合、不做 fixed
|
|
80
97
|
*/
|
|
81
98
|
declare function initAiContext(root?: ParentNode): () => void;
|
|
@@ -91,8 +108,8 @@ interface AiAuditRenderOpts {
|
|
|
91
108
|
* 渲染审计面板:totals(请求数/失败/累计 tokens/累计成本/平均 TTFT)+ byModel 分组 +
|
|
92
109
|
* 最近请求条目(默认 10 条,最新在前)。source 为 auditor 实例或条目数组(快照渲染,
|
|
93
110
|
* 数据更新后重调)。清除钮派 icen:ai-audit-clear { }(消费方调 auditor.clear() 后重渲染),
|
|
94
|
-
* opts.onClear
|
|
111
|
+
* opts.onClear 给了则走回调。返回挂载容器 el(render* 返回挂载元素约定)。
|
|
95
112
|
*/
|
|
96
|
-
declare function renderAiAudit(
|
|
113
|
+
declare function renderAiAudit(el: HTMLElement, source: AiAuditor | AiAuditEntry[], opts?: AiAuditRenderOpts): HTMLElement;
|
|
97
114
|
|
|
98
|
-
export { type AiAuditRenderOpts, type AiContextFile, type AiContextMcpServer, type AiContextModel, type AiContextSkill, type AiTodoItem, type AiUsageRenderOpts, type AiUsageRingOpts, initAiContext, initAiTodo, renderAiAudit, renderAiContext, renderAiTodo, renderAiUsage, renderAiUsageRing };
|
|
115
|
+
export { type AiAuditRenderOpts, type AiContextFile, type AiContextMcpServer, type AiContextModel, type AiContextSkill, type AiTodoItem, type AiUsageMetrics, type AiUsageRenderOpts, type AiUsageRingOpts, initAiContext, initAiTodo, renderAiAudit, renderAiContext, renderAiTodo, renderAiUsage, renderAiUsageRing };
|