@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,325 @@
|
|
|
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-sandbox.ts
|
|
158
|
+
var DEFAULT_TIMEOUT_MS = 8e3;
|
|
159
|
+
function isSandboxMessage(data) {
|
|
160
|
+
if (!data || typeof data !== "object") return false;
|
|
161
|
+
const m = data;
|
|
162
|
+
if (m.jsonrpc !== "2.0") return false;
|
|
163
|
+
if (typeof m.method === "string") return true;
|
|
164
|
+
if (m.id !== void 0 && m.id !== null && ("result" in m || "error" in m)) return true;
|
|
165
|
+
return false;
|
|
166
|
+
}
|
|
167
|
+
function createKbSandbox(el, opts = {}) {
|
|
168
|
+
const stub = { load: () => void 0, call: () => Promise.reject(new Error("kb-sandbox: SSR")), destroy: () => void 0 };
|
|
169
|
+
if (typeof document === "undefined" || !el) return stub;
|
|
170
|
+
const timeoutMs = typeof opts.timeoutMs === "number" && opts.timeoutMs > 0 ? opts.timeoutMs : DEFAULT_TIMEOUT_MS;
|
|
171
|
+
const allowedOrigins = Array.isArray(opts.allowedOrigins) ? opts.allowedOrigins.filter((o) => typeof o === "string") : null;
|
|
172
|
+
el.classList.add("kb-sandbox");
|
|
173
|
+
el.dataset.state = "idle";
|
|
174
|
+
const stage = h("div", "kb-sandbox-stage");
|
|
175
|
+
const frame = document.createElement("iframe");
|
|
176
|
+
frame.className = "kb-sandbox-frame";
|
|
177
|
+
frame.setAttribute("sandbox", "allow-scripts");
|
|
178
|
+
frame.title = "MCP App \u6C99\u7BB1";
|
|
179
|
+
const loading = h("div", "kb-sandbox-loading");
|
|
180
|
+
loading.appendChild(h("i", "kb-sandbox-spin"));
|
|
181
|
+
const err = h("div", "kb-sandbox-err");
|
|
182
|
+
const errMsg = h("span", "kb-sandbox-err-msg");
|
|
183
|
+
err.appendChild(errMsg);
|
|
184
|
+
stage.append(frame, loading, err);
|
|
185
|
+
el.textContent = "";
|
|
186
|
+
el.appendChild(stage);
|
|
187
|
+
const ac = new AbortController();
|
|
188
|
+
const { signal } = ac;
|
|
189
|
+
const pending = /* @__PURE__ */ new Map();
|
|
190
|
+
let seq = 0;
|
|
191
|
+
let loadSeq = 0;
|
|
192
|
+
let destroyed = false;
|
|
193
|
+
let state = "idle";
|
|
194
|
+
const setState = (s) => {
|
|
195
|
+
state = s;
|
|
196
|
+
el.dataset.state = s;
|
|
197
|
+
};
|
|
198
|
+
const notify = (channel, payload) => {
|
|
199
|
+
emitIcen(el, "icen:kb-sandbox-message", { channel, payload });
|
|
200
|
+
opts.onMessage?.({ channel, payload });
|
|
201
|
+
};
|
|
202
|
+
const showError = (message) => {
|
|
203
|
+
errMsg.textContent = message;
|
|
204
|
+
setState("error");
|
|
205
|
+
};
|
|
206
|
+
const failPending = (message) => {
|
|
207
|
+
for (const [, p] of pending) {
|
|
208
|
+
clearTimeout(p.timer);
|
|
209
|
+
p.reject(new Error(`kb-sandbox: ${message}`));
|
|
210
|
+
}
|
|
211
|
+
pending.clear();
|
|
212
|
+
};
|
|
213
|
+
const onWindowMessage = (e) => {
|
|
214
|
+
if (destroyed || e.source !== frame.contentWindow) return;
|
|
215
|
+
if (allowedOrigins && !allowedOrigins.includes(e.origin)) return;
|
|
216
|
+
const payload = e.data;
|
|
217
|
+
if (!isSandboxMessage(payload)) return;
|
|
218
|
+
notify("in", payload);
|
|
219
|
+
if (payload.method === "app.ready") {
|
|
220
|
+
setState("ready");
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
if (payload.id != null && ("result" in payload || "error" in payload)) {
|
|
224
|
+
const p = pending.get(payload.id);
|
|
225
|
+
if (!p) return;
|
|
226
|
+
pending.delete(payload.id);
|
|
227
|
+
clearTimeout(p.timer);
|
|
228
|
+
if (payload.error) p.reject(new Error(`kb-sandbox: ${payload.error.message}`));
|
|
229
|
+
else p.resolve(payload.result);
|
|
230
|
+
}
|
|
231
|
+
};
|
|
232
|
+
window.addEventListener("message", onWindowMessage, { signal });
|
|
233
|
+
frame.addEventListener(
|
|
234
|
+
"load",
|
|
235
|
+
() => {
|
|
236
|
+
if (!destroyed && state === "loading") setState("ready");
|
|
237
|
+
},
|
|
238
|
+
{ signal }
|
|
239
|
+
);
|
|
240
|
+
const mountSrcdoc = (html) => {
|
|
241
|
+
frame.removeAttribute("src");
|
|
242
|
+
frame.srcdoc = html;
|
|
243
|
+
setState("loading");
|
|
244
|
+
};
|
|
245
|
+
const load = (uriOrHtml, loadOpts) => {
|
|
246
|
+
if (destroyed) return;
|
|
247
|
+
const s = String(uriOrHtml ?? "");
|
|
248
|
+
failPending("reloaded");
|
|
249
|
+
errMsg.textContent = "";
|
|
250
|
+
const mySeq = ++loadSeq;
|
|
251
|
+
if (s.startsWith("ui://")) {
|
|
252
|
+
if (typeof opts.resolve !== "function") {
|
|
253
|
+
showError("\u5BBF\u4E3B\u672A\u63D0\u4F9B ui:// \u89E3\u6790\u5668");
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
let resolved;
|
|
257
|
+
try {
|
|
258
|
+
resolved = opts.resolve(s);
|
|
259
|
+
} catch (e) {
|
|
260
|
+
showError(`ui:// \u89E3\u6790\u5931\u8D25\uFF1A${e instanceof Error ? e.message : String(e)}`);
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
if (resolved != null && typeof resolved.then === "function") {
|
|
264
|
+
setState("loading");
|
|
265
|
+
resolved.then(
|
|
266
|
+
(html) => {
|
|
267
|
+
if (destroyed || mySeq !== loadSeq) return;
|
|
268
|
+
if (typeof html === "string" && html) mountSrcdoc(html);
|
|
269
|
+
else showError("\u5BBF\u4E3B\u672A\u63D0\u4F9B ui:// \u89E3\u6790\u5668");
|
|
270
|
+
},
|
|
271
|
+
(e) => {
|
|
272
|
+
if (destroyed || mySeq !== loadSeq) return;
|
|
273
|
+
showError(`ui:// \u89E3\u6790\u5931\u8D25\uFF1A${e instanceof Error ? e.message : String(e)}`);
|
|
274
|
+
}
|
|
275
|
+
);
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
if (typeof resolved === "string" && resolved) {
|
|
279
|
+
mountSrcdoc(resolved);
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
showError("\u5BBF\u4E3B\u672A\u63D0\u4F9B ui:// \u89E3\u6790\u5668");
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
if (loadOpts?.srcDoc || s.includes("<")) mountSrcdoc(s);
|
|
286
|
+
else {
|
|
287
|
+
frame.removeAttribute("srcdoc");
|
|
288
|
+
setState("loading");
|
|
289
|
+
frame.src = s;
|
|
290
|
+
}
|
|
291
|
+
};
|
|
292
|
+
const call = (name, args) => new Promise((resolve, reject) => {
|
|
293
|
+
if (destroyed) {
|
|
294
|
+
reject(new Error("kb-sandbox: destroyed"));
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
if (state === "idle" || state === "error" || !frame.contentWindow) {
|
|
298
|
+
reject(new Error("kb-sandbox: \u5E94\u7528\u672A\u5C31\u7EEA"));
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
const id = ++seq;
|
|
302
|
+
const payload = { jsonrpc: "2.0", id, method: name, params: args };
|
|
303
|
+
const timer = setTimeout(() => {
|
|
304
|
+
pending.delete(id);
|
|
305
|
+
reject(new Error(`kb-sandbox: \u8C03\u7528\u8D85\u65F6\uFF08${timeoutMs}ms\uFF09`));
|
|
306
|
+
}, timeoutMs);
|
|
307
|
+
pending.set(id, { resolve, reject, timer });
|
|
308
|
+
frame.contentWindow.postMessage(payload, "*");
|
|
309
|
+
notify("out", payload);
|
|
310
|
+
});
|
|
311
|
+
const destroy = () => {
|
|
312
|
+
if (destroyed) return;
|
|
313
|
+
destroyed = true;
|
|
314
|
+
ac.abort();
|
|
315
|
+
failPending("destroyed");
|
|
316
|
+
frame.remove();
|
|
317
|
+
el.classList.remove("kb-sandbox");
|
|
318
|
+
delete el.dataset.state;
|
|
319
|
+
el.textContent = "";
|
|
320
|
+
};
|
|
321
|
+
return { load, call, destroy };
|
|
322
|
+
}
|
|
323
|
+
export {
|
|
324
|
+
createKbSandbox
|
|
325
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { KbSegmentConfig } from './kb-core.js';
|
|
2
|
+
import './ai-core.js';
|
|
3
|
+
|
|
4
|
+
/** createKbSegment 选项 */
|
|
5
|
+
interface KbSegmentOpts {
|
|
6
|
+
/** 初始分段配置(宽进:走 normalizeSegmentConfig 归一) */
|
|
7
|
+
config?: Partial<KbSegmentConfig>;
|
|
8
|
+
/** 预览样本文本(真实切分的素材) */
|
|
9
|
+
sample?: string;
|
|
10
|
+
/** 用户变更回调(与 icen:kb-segment-change 事件双通道) */
|
|
11
|
+
onChange?: (config: KbSegmentConfig) => void;
|
|
12
|
+
}
|
|
13
|
+
/** createKbSegment 句柄 */
|
|
14
|
+
interface KbSegmentHandle {
|
|
15
|
+
/** 当前配置(归一化副本,调用方可安全改写) */
|
|
16
|
+
getConfig(): KbSegmentConfig;
|
|
17
|
+
/** 程序化赋值(合并 + 同步表单 + 重算预览;不派事件不触发 onChange) */
|
|
18
|
+
setConfig(config: Partial<KbSegmentConfig>): void;
|
|
19
|
+
/** 重算预览;给 sample 则同时更换样本 */
|
|
20
|
+
refresh(sample?: string): void;
|
|
21
|
+
/** 摘除全部监听(销毁后句柄方法仍可读写,但不再响应交互/派事件) */
|
|
22
|
+
destroy(): void;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* 挂载分段策略编辑器(左表单右预览)并返回句柄。
|
|
26
|
+
* 表单任一用户变更 → 即时用 kb-core segmentText 真实切分重算预览,并
|
|
27
|
+
* 派 icen:kb-segment-change { config } + 调 opts.onChange(双通道)。
|
|
28
|
+
* SSR(无 document)下返回惰性句柄(getConfig 可用,DOM 操作 no-op)。
|
|
29
|
+
*/
|
|
30
|
+
declare function createKbSegment(el: HTMLElement, opts?: KbSegmentOpts): KbSegmentHandle;
|
|
31
|
+
|
|
32
|
+
export { type KbSegmentHandle, type KbSegmentOpts, createKbSegment };
|