@icen.ai/ui 0.8.1 → 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 +49 -6
- package/README.md +12 -9
- package/dist/behaviors/ai-branch.d.mts +19 -0
- package/dist/behaviors/ai-branch.mjs +217 -0
- package/dist/behaviors/ai-chat.d.mts +8 -6
- package/dist/behaviors/ai-chat.mjs +68 -8
- package/dist/behaviors/ai-composer.mjs +108 -20
- package/dist/behaviors/ai-feedback.d.mts +26 -0
- package/dist/behaviors/ai-feedback.mjs +303 -0
- package/dist/behaviors/ai-panel.d.mts +15 -1
- package/dist/behaviors/ai-panel.mjs +26 -0
- package/dist/behaviors/ai-threads.d.mts +38 -0
- package/dist/behaviors/ai-threads.mjs +319 -0
- package/dist/behaviors/ai-tool.mjs +5 -0
- package/dist/behaviors/ai-tools.mjs +5 -0
- package/dist/behaviors/charts.d.mts +103 -1
- package/dist/behaviors/charts.mjs +795 -0
- package/dist/behaviors/events.d.mts +193 -0
- 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/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 +217 -0
- package/dist/components/ai-threads.mjs +3 -0
- 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-scatter.mjs +1 -1
- package/dist/components/charts.css +32 -0
- package/dist/components/charts.mjs +1 -0
- 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/index.d.mts +37 -2
- package/dist/index.mjs +8555 -205
- package/dist/registry.json +325 -3
- package/dist/ui.css +5451 -45
- 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/kb-family.md +443 -0
- package/package.json +2 -2
|
@@ -0,0 +1,326 @@
|
|
|
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
|
+
|
|
134
|
+
// src/behaviors/kb-core.ts
|
|
135
|
+
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>` });
|
|
136
|
+
var BUILTIN_SOURCE_TYPES = {
|
|
137
|
+
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"/>'),
|
|
138
|
+
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"/>'),
|
|
139
|
+
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"/>'),
|
|
140
|
+
sheet: ic("\u8868\u683C", '<rect x="3" y="3" width="18" height="18" rx="2"/><path d="M3 9h18M3 15h18M9 3v18M15 3v18"/>'),
|
|
141
|
+
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"/>'),
|
|
142
|
+
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"/>'),
|
|
143
|
+
code: ic("\u4EE3\u7801", '<path d="m16 18 6-6-6-6"/><path d="m8 6-6 6 6 6"/>'),
|
|
144
|
+
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"/>'),
|
|
145
|
+
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"/>'),
|
|
146
|
+
mail: ic("\u90AE\u4EF6", '<rect x="2" y="4" width="20" height="16" rx="2"/><path d="m22 7-10 7L2 7"/>')
|
|
147
|
+
};
|
|
148
|
+
var sourceTypeRegistry = new Map(Object.entries(BUILTIN_SOURCE_TYPES));
|
|
149
|
+
|
|
150
|
+
// src/behaviors/events.ts
|
|
151
|
+
function emitIcen(source, type, detail) {
|
|
152
|
+
return source.dispatchEvent(
|
|
153
|
+
new CustomEvent(type, { detail, bubbles: true, composed: true, cancelable: true })
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// src/behaviors/kb-metadata.ts
|
|
158
|
+
var TYPES = ["string", "number", "time"];
|
|
159
|
+
function buildRow(field, value) {
|
|
160
|
+
const row = h("tr", `kb-metadata-row${field.builtin ? " is-builtin" : ""}`);
|
|
161
|
+
row.dataset.key = field.key;
|
|
162
|
+
const keyTd = h("td", "kb-metadata-key");
|
|
163
|
+
keyTd.textContent = field.key;
|
|
164
|
+
if (field.label && field.label !== field.key) {
|
|
165
|
+
keyTd.appendChild(document.createTextNode(" "));
|
|
166
|
+
keyTd.appendChild(h("span", "kb-metadata-key-label", field.label));
|
|
167
|
+
}
|
|
168
|
+
if (field.builtin) keyTd.appendChild(h("span", "kb-metadata-builtin-flag", "\u5185\u7F6E"));
|
|
169
|
+
row.appendChild(keyTd);
|
|
170
|
+
const typeTd = h("td");
|
|
171
|
+
typeTd.appendChild(h("span", `kb-badge kb-metadata-type is-${field.type}`, field.type));
|
|
172
|
+
row.appendChild(typeTd);
|
|
173
|
+
const valueTd = h("td", "kb-metadata-value");
|
|
174
|
+
if (field.builtin) {
|
|
175
|
+
valueTd.appendChild(h("span", "kb-metadata-readonly", value != null ? String(value) : "\u2014"));
|
|
176
|
+
} else {
|
|
177
|
+
const input = h("input", "kb-input kb-metadata-bind");
|
|
178
|
+
input.type = field.type === "number" ? "number" : "text";
|
|
179
|
+
input.value = value != null ? String(value) : "";
|
|
180
|
+
input.dataset.kbMetadataBind = "";
|
|
181
|
+
input.setAttribute("aria-label", `${field.key} \u7684\u503C`);
|
|
182
|
+
valueTd.appendChild(input);
|
|
183
|
+
}
|
|
184
|
+
row.appendChild(valueTd);
|
|
185
|
+
const opsTd = h("td", "kb-metadata-ops");
|
|
186
|
+
if (!field.builtin) {
|
|
187
|
+
const rm = h("button", "kb-btn");
|
|
188
|
+
rm.type = "button";
|
|
189
|
+
rm.dataset.kbMetadataRemove = "";
|
|
190
|
+
rm.textContent = "\u79FB\u9664";
|
|
191
|
+
rm.setAttribute("aria-label", `\u79FB\u9664\u5B57\u6BB5 ${field.key}`);
|
|
192
|
+
opsTd.appendChild(rm);
|
|
193
|
+
}
|
|
194
|
+
row.appendChild(opsTd);
|
|
195
|
+
return row;
|
|
196
|
+
}
|
|
197
|
+
function buildNewRow() {
|
|
198
|
+
const bar = h("div", "kb-metadata-new");
|
|
199
|
+
const keyInput = h("input", "kb-input kb-input--mono kb-metadata-new-key");
|
|
200
|
+
keyInput.type = "text";
|
|
201
|
+
keyInput.placeholder = "\u5B57\u6BB5\u540D\uFF0C\u5982 department";
|
|
202
|
+
keyInput.dataset.kbMetadataNewKey = "";
|
|
203
|
+
keyInput.setAttribute("aria-label", "\u65B0\u5B57\u6BB5\u540D");
|
|
204
|
+
bar.appendChild(keyInput);
|
|
205
|
+
const pick = h("div", "kb-seg kb-metadata-type-pick");
|
|
206
|
+
pick.setAttribute("role", "radiogroup");
|
|
207
|
+
pick.setAttribute("aria-label", "\u65B0\u5B57\u6BB5\u7C7B\u578B");
|
|
208
|
+
TYPES.forEach((t, i) => {
|
|
209
|
+
const item = h("button", `kb-seg-item kb-metadata-type-item${i === 0 ? " is-active" : ""}`);
|
|
210
|
+
item.type = "button";
|
|
211
|
+
item.setAttribute("role", "radio");
|
|
212
|
+
item.setAttribute("aria-checked", String(i === 0));
|
|
213
|
+
item.dataset.value = t;
|
|
214
|
+
item.textContent = t;
|
|
215
|
+
pick.appendChild(item);
|
|
216
|
+
});
|
|
217
|
+
bar.appendChild(pick);
|
|
218
|
+
const define = h("button", "kb-btn");
|
|
219
|
+
define.type = "button";
|
|
220
|
+
define.dataset.kbMetadataDefine = "";
|
|
221
|
+
define.textContent = "\u65B0\u589E\u5B57\u6BB5";
|
|
222
|
+
bar.appendChild(define);
|
|
223
|
+
return bar;
|
|
224
|
+
}
|
|
225
|
+
function renderKbMetadata(el, model) {
|
|
226
|
+
if (typeof document === "undefined") return el;
|
|
227
|
+
const fields = Array.isArray(model?.fields) ? model.fields : [];
|
|
228
|
+
const values = model?.values ?? {};
|
|
229
|
+
el.textContent = "";
|
|
230
|
+
const root = h("div", "kb-metadata");
|
|
231
|
+
const table = document.createElement("table");
|
|
232
|
+
table.className = "kb-metadata-table";
|
|
233
|
+
const thead = document.createElement("thead");
|
|
234
|
+
const headRow = document.createElement("tr");
|
|
235
|
+
["\u5B57\u6BB5", "\u7C7B\u578B", "\u503C", ""].forEach((label) => headRow.appendChild(h("th", "kb-metadata-th", label)));
|
|
236
|
+
thead.appendChild(headRow);
|
|
237
|
+
table.appendChild(thead);
|
|
238
|
+
const tbody = document.createElement("tbody");
|
|
239
|
+
if (!fields.length) {
|
|
240
|
+
const emptyRow = h("tr", "kb-metadata-empty-row");
|
|
241
|
+
const td = h("td", "kb-metadata-empty", "\u6682\u65E0\u5143\u6570\u636E\u5B57\u6BB5");
|
|
242
|
+
td.colSpan = 4;
|
|
243
|
+
emptyRow.appendChild(td);
|
|
244
|
+
tbody.appendChild(emptyRow);
|
|
245
|
+
} else {
|
|
246
|
+
fields.forEach((f) => tbody.appendChild(buildRow(f, values[f.key])));
|
|
247
|
+
}
|
|
248
|
+
table.appendChild(tbody);
|
|
249
|
+
root.appendChild(table);
|
|
250
|
+
root.appendChild(buildNewRow());
|
|
251
|
+
el.appendChild(root);
|
|
252
|
+
return el;
|
|
253
|
+
}
|
|
254
|
+
function appendDefinedRow(root, key, type) {
|
|
255
|
+
const tbody = root.querySelector("tbody");
|
|
256
|
+
if (!tbody) return;
|
|
257
|
+
const empty = tbody.querySelector(".kb-metadata-empty-row");
|
|
258
|
+
if (empty) empty.remove();
|
|
259
|
+
tbody.appendChild(buildRow({ key, type }, ""));
|
|
260
|
+
}
|
|
261
|
+
function initKbMetadata(root) {
|
|
262
|
+
if (typeof document === "undefined") return () => void 0;
|
|
263
|
+
const scope = root ?? document;
|
|
264
|
+
const marked = scope;
|
|
265
|
+
if (marked.__icenKbMetadataInit) return () => void 0;
|
|
266
|
+
marked.__icenKbMetadataInit = true;
|
|
267
|
+
const target = scope;
|
|
268
|
+
const onClick = (e) => {
|
|
269
|
+
const t = e.target instanceof Element ? e.target : null;
|
|
270
|
+
if (!t) return;
|
|
271
|
+
const rm = t.closest("[data-kb-metadata-remove]");
|
|
272
|
+
if (rm) {
|
|
273
|
+
const row = rm.closest(".kb-metadata-row[data-key]");
|
|
274
|
+
if (!row) return;
|
|
275
|
+
const key = row.dataset.key ?? "";
|
|
276
|
+
emitIcen(row, "icen:kb-metadata-change", { action: "remove", key });
|
|
277
|
+
row.remove();
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
const define = t.closest("[data-kb-metadata-define]");
|
|
281
|
+
if (define) {
|
|
282
|
+
const root2 = define.closest(".kb-metadata");
|
|
283
|
+
const keyInput = root2?.querySelector("[data-kb-metadata-new-key]");
|
|
284
|
+
if (!root2 || !keyInput) return;
|
|
285
|
+
const key = keyInput.value.trim();
|
|
286
|
+
if (!key) {
|
|
287
|
+
keyInput.setAttribute("aria-invalid", "true");
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
keyInput.removeAttribute("aria-invalid");
|
|
291
|
+
const active = root2.querySelector(".kb-metadata-type-item.is-active");
|
|
292
|
+
const type = TYPES.includes(active?.dataset.value ?? "") ? active?.dataset.value : "string";
|
|
293
|
+
appendDefinedRow(root2, key, type);
|
|
294
|
+
keyInput.value = "";
|
|
295
|
+
emitIcen(root2, "icen:kb-metadata-change", { action: "define", key });
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
const typeItem = t.closest(".kb-metadata-type-item");
|
|
299
|
+
if (typeItem) {
|
|
300
|
+
const seg = typeItem.closest(".kb-metadata-type-pick");
|
|
301
|
+
if (!seg || typeItem.classList.contains("is-active")) return;
|
|
302
|
+
seg.querySelectorAll(".kb-metadata-type-item").forEach((it) => {
|
|
303
|
+
const on = it === typeItem;
|
|
304
|
+
it.classList.toggle("is-active", on);
|
|
305
|
+
it.setAttribute("aria-checked", String(on));
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
};
|
|
309
|
+
const onChange = (e) => {
|
|
310
|
+
const t = e.target;
|
|
311
|
+
if (!(t instanceof HTMLInputElement) || !t.hasAttribute("data-kb-metadata-bind")) return;
|
|
312
|
+
const row = t.closest(".kb-metadata-row[data-key]");
|
|
313
|
+
if (row) emitIcen(row, "icen:kb-metadata-change", { action: "bind", key: row.dataset.key ?? "" });
|
|
314
|
+
};
|
|
315
|
+
target.addEventListener("click", onClick);
|
|
316
|
+
target.addEventListener("change", onChange);
|
|
317
|
+
return () => {
|
|
318
|
+
target.removeEventListener("click", onClick);
|
|
319
|
+
target.removeEventListener("change", onChange);
|
|
320
|
+
marked.__icenKbMetadataInit = false;
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
export {
|
|
324
|
+
initKbMetadata,
|
|
325
|
+
renderKbMetadata
|
|
326
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { KbLocation, KbCitation } from './kb-core.js';
|
|
2
|
+
import './ai-core.js';
|
|
3
|
+
|
|
4
|
+
/** getDocument 的返回契约:原文 + 定位 + 上下文(受限来源可只给 content 空串并依赖 citedText 回落) */
|
|
5
|
+
interface KbPassageDoc {
|
|
6
|
+
content: string;
|
|
7
|
+
loc?: KbLocation;
|
|
8
|
+
contextBefore?: string;
|
|
9
|
+
contextAfter?: string;
|
|
10
|
+
}
|
|
11
|
+
/** createKbPassage 的配置项:原文取数 / 跳转锚定容器 / 开合回调 */
|
|
12
|
+
interface KbPassageOptions {
|
|
13
|
+
/** 原文取数(同步返回或 Promise;未提供 / 落空时回落 citation.citedText → snippet) */
|
|
14
|
+
getDocument?: (citation: KbCitation) => KbPassageDoc | null | undefined | Promise<KbPassageDoc | null | undefined>;
|
|
15
|
+
/** 跳转锚定容器(元素或惰性取值函数;提供后 open 时滚动定位 [data-kb-loc]) */
|
|
16
|
+
anchor?: HTMLElement | (() => HTMLElement | null | undefined);
|
|
17
|
+
/** 打开回调(与 icen:kb-passage-jump 事件双通道) */
|
|
18
|
+
onJump?: (citation: KbCitation) => void;
|
|
19
|
+
/** 关闭回调(与 icen:kb-passage-close 事件双通道) */
|
|
20
|
+
onClose?: () => void;
|
|
21
|
+
}
|
|
22
|
+
/** kb-passage 句柄:open/close/highlight/expand/destroy(函数名冻结,规格 §5.3) */
|
|
23
|
+
interface KbPassageHandle {
|
|
24
|
+
/** 打开抽屉并渲染某条引用的原文定位 */
|
|
25
|
+
open(citation: KbCitation): void;
|
|
26
|
+
/** 关闭抽屉(派 icen:kb-passage-close,焦点还原) */
|
|
27
|
+
close(): void;
|
|
28
|
+
/** 高亮正文命中词(多词轮转 data-hit 0/1/2 分色) */
|
|
29
|
+
highlight(terms: string | string[]): void;
|
|
30
|
+
/** 展开上下文(当前仅一层;delta 预留) */
|
|
31
|
+
expand(delta?: number): void;
|
|
32
|
+
/** 销毁:解绑监听、静默关闭、清空挂载容器 */
|
|
33
|
+
destroy(): void;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* 创建原文定位抽屉(挂载容器 el 内搭骨架,返回句柄)。
|
|
37
|
+
* 句柄方法对无效状态(未打开 / 已销毁)安全 no-op。
|
|
38
|
+
*/
|
|
39
|
+
declare function createKbPassage(el: HTMLElement, opts?: KbPassageOptions): KbPassageHandle;
|
|
40
|
+
|
|
41
|
+
export { type KbPassageDoc, type KbPassageHandle, type KbPassageOptions, createKbPassage };
|