@pi-harness/client-web 0.1.2 → 0.1.4

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 (61) hide show
  1. package/LICENSE +9 -0
  2. package/dist/annotation-ui.d.ts +11 -0
  3. package/dist/annotation-ui.d.ts.map +1 -0
  4. package/dist/annotation-ui.js +24 -0
  5. package/dist/annotation-ui.js.map +1 -0
  6. package/dist/browser-session-view.d.ts +7 -0
  7. package/dist/browser-session-view.d.ts.map +1 -0
  8. package/dist/browser-session-view.js +8 -0
  9. package/dist/browser-session-view.js.map +1 -0
  10. package/dist/control-room.d.ts +151 -6
  11. package/dist/control-room.d.ts.map +1 -1
  12. package/dist/control-room.js +156 -11
  13. package/dist/control-room.js.map +1 -1
  14. package/dist/design-contract.d.ts.map +1 -1
  15. package/dist/design-contract.js +178 -19
  16. package/dist/design-contract.js.map +1 -1
  17. package/dist/index.d.ts +4 -1
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +11 -3
  20. package/dist/index.js.map +1 -1
  21. package/dist/markdown.d.ts +5 -0
  22. package/dist/markdown.d.ts.map +1 -0
  23. package/dist/markdown.js +20 -0
  24. package/dist/markdown.js.map +1 -0
  25. package/dist/marketplace-catalog.d.ts +3 -0
  26. package/dist/marketplace-catalog.d.ts.map +1 -0
  27. package/dist/marketplace-catalog.js +10 -0
  28. package/dist/marketplace-catalog.js.map +1 -0
  29. package/dist/marketplace-navigation.d.ts +19 -0
  30. package/dist/marketplace-navigation.d.ts.map +1 -0
  31. package/dist/marketplace-navigation.js +31 -0
  32. package/dist/marketplace-navigation.js.map +1 -0
  33. package/dist/message-content.d.ts +9 -0
  34. package/dist/message-content.d.ts.map +1 -0
  35. package/dist/message-content.js +54 -0
  36. package/dist/message-content.js.map +1 -0
  37. package/dist/plugin-navigation.d.ts +3 -0
  38. package/dist/plugin-navigation.d.ts.map +1 -0
  39. package/dist/plugin-navigation.js +10 -0
  40. package/dist/plugin-navigation.js.map +1 -0
  41. package/dist/plugin-search.d.ts +2 -0
  42. package/dist/plugin-search.d.ts.map +1 -0
  43. package/dist/plugin-search.js +7 -0
  44. package/dist/plugin-search.js.map +1 -0
  45. package/dist/plugin-stars-view.d.ts +12 -0
  46. package/dist/plugin-stars-view.d.ts.map +1 -0
  47. package/dist/plugin-stars-view.js +8 -0
  48. package/dist/plugin-stars-view.js.map +1 -0
  49. package/dist/prompt-completion.d.ts +13 -0
  50. package/dist/prompt-completion.d.ts.map +1 -0
  51. package/dist/prompt-completion.js +17 -0
  52. package/dist/prompt-completion.js.map +1 -0
  53. package/dist/react-room.d.ts +2 -1
  54. package/dist/react-room.d.ts.map +1 -1
  55. package/dist/react-room.js +2347 -93
  56. package/dist/react-room.js.map +1 -1
  57. package/dist/runtime-events.d.ts +4 -0
  58. package/dist/runtime-events.d.ts.map +1 -0
  59. package/dist/runtime-events.js +29 -0
  60. package/dist/runtime-events.js.map +1 -0
  61. package/package.json +19 -7
@@ -1,114 +1,2368 @@
1
- import { jsxs as _jsxs, jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { useCallback, useEffect, useMemo, useState } from "react";
3
- import { createClientApi } from "./control-room.js";
4
- const value = (input, fallback = "—") => { if (input === undefined || input === null || input === "")
5
- return fallback; if (typeof input === "string" || typeof input === "number" || typeof input === "boolean" || typeof input === "bigint")
6
- return String(input); try {
7
- return JSON.stringify(input);
8
- }
9
- catch {
10
- return fallback;
11
- } };
12
- const messageText = (message) => { const content = message.content; if (typeof content === "string")
13
- return content; if (Array.isArray(content))
14
- return content.map((part) => typeof part === "string" ? part : typeof part === "object" && part !== null && typeof part.text === "string" ? part.text : "").join(""); return ""; };
15
- const eventLabel = (event) => value(event.summary ?? event.message ?? event.toolName ?? event.type ?? event.event, "未命名事件");
16
- const capability = (name) => name.includes("model") ? "模型" : name.includes("tool") ? "工具" : name.includes("session") ? "会话" : name.includes("resource") ? "资源" : name.includes("web") || name.includes("gateway") ? "界面" : "运行时";
17
- function sessionGroups(sessions) { const now = new Date(); const start = new Date(now.getFullYear(), now.getMonth(), now.getDate()).getTime(); const yesterday = start - 86_400_000; const groups = new Map(); for (const session of sessions) {
18
- const raw = session.modified ?? session.created;
19
- const timestamp = typeof raw === "number" ? raw : typeof raw === "string" ? Date.parse(raw) : Number.NaN;
20
- const label = Number.isFinite(timestamp) && timestamp >= start ? "今天" : Number.isFinite(timestamp) && timestamp >= yesterday ? "昨天" : "更早";
21
- groups.set(label, [...(groups.get(label) ?? []), session]);
22
- } return ["今天", "昨天", "更早"].flatMap((label) => { const items = groups.get(label); return items?.length ? [[label, items]] : []; }); }
23
- function RuntimeCard({ event }) {
24
- const type = value(event.type, "event");
25
- const output = event.output ?? event.result ?? event.message;
26
- if (type === "tool_execution_start" || type === "tool_execution_end")
27
- return _jsx("article", { className: "turn runtime-event", children: _jsxs("details", { className: "tool-card", open: type === "tool_execution_end", children: [_jsxs("summary", { className: "tool-head", children: [_jsxs("b", { children: [type === "tool_execution_end" ? "✓" : "▤", " ", value(event.toolName ?? event.name, "tool")] }), _jsx("span", { className: "tool-target", children: value(event.args ?? event.toolCallId ?? event.duration, "运行时工具") })] }), output !== undefined && _jsx("pre", { className: "tool-output", children: typeof output === "string" ? output : JSON.stringify(output, null, 2) })] }) });
28
- if (type === "message_update" && typeof event.assistantMessageEvent === "object" && event.assistantMessageEvent !== null && event.assistantMessageEvent.type === "thinking_delta")
29
- return _jsx("article", { className: "turn runtime-event", children: _jsxs("details", { className: "reasoning", children: [_jsx("summary", { className: "reasoning-head", children: "\u601D\u8003" }), _jsx("p", { className: "reasoning-body", children: value(event.assistantMessageEvent.delta, "") })] }) });
30
- if (["agent_start", "turn_start"].includes(type))
31
- return _jsx("article", { className: "turn runtime-event", children: _jsxs("div", { className: "plugin-event", children: ["\u25B7 ", type === "agent_start" ? "agent 开始" : "新一轮开始"] }) });
32
- if (["agent_end", "agent_settled", "turn_end"].includes(type))
33
- return _jsx("article", { className: "turn runtime-event", children: _jsxs("div", { className: "stats-row", children: ["\u2713 ", type === "agent_settled" ? "agent 已停止" : type === "agent_end" ? "agent 完成" : "本轮完成"] }) });
34
- if (type === "queue_update")
35
- return _jsxs("article", { className: "turn runtime-event", children: [_jsx("div", { className: "plugin-event", children: "\u961F\u5217\u66F4\u65B0" }), _jsxs("p", { className: "turn-meta", children: ["steering ", Array.isArray(event.steering) ? event.steering.length : value(event.steering, "0"), " \u00B7 follow-up ", Array.isArray(event.followUp) ? event.followUp.length : value(event.followUp, "0")] })] });
36
- if (type.startsWith("compaction") || type.startsWith("auto_retry") || type.startsWith("summarization") || type === "bash_execution_update")
37
- return _jsxs("article", { className: "turn runtime-event", children: [_jsxs("div", { className: "plugin-event", children: ["\u25C8 ", type] }), _jsx("p", { className: "turn-meta", children: typeof output === "string" ? output : JSON.stringify(event) })] });
38
- return null;
39
- }
40
- function Workspace({ status, onCreate, onStarter, onToml }) {
41
- const starters = [["定位问题", "分析当前仓库并给出根因"], ["修复并测试", "实现修复并运行相关测试"], ["审查改动", "只读检查未提交变更"], ["解释代码", "解释当前文件的关键逻辑"]];
42
- return _jsxs("div", { className: "new-session-screen", children: [_jsx("span", { className: "pi-mark large", children: "\u03C0" }), _jsx("h2", { children: "\u65B0\u4F1A\u8BDD" }), _jsx("p", { children: "\u9009\u62E9\u5F53\u524D\u8FD0\u884C\u65F6\u5DE5\u4F5C\u533A\u540E\u5F00\u59CB\u771F\u5B9E\u4F1A\u8BDD\u3002" }), _jsxs("div", { className: "workspace-picker", children: [_jsxs("button", { className: "workspace-row", onClick: onCreate, type: "button", children: [_jsx("span", { className: "live", children: "\u25CF" }), _jsxs("span", { children: [_jsx("code", { children: status?.cwd ?? "加载工作区…" }), _jsx("small", { children: status ? `${status.sessionId} · ${status.model}` : "由 /api/status 返回" })] }), _jsx("span", { children: "\u203A" })] }), _jsxs("button", { className: "workspace-row", disabled: true, type: "button", children: [_jsx("span", { className: "offline", children: "\uFF0B" }), _jsxs("span", { children: [_jsx("code", { children: "\u6DFB\u52A0\u76EE\u5F55\u2026" }), _jsx("small", { children: "\u5F53\u524D API \u672A\u63D0\u4F9B\u5DE5\u4F5C\u533A\u7BA1\u7406\u63A5\u53E3" })] })] })] }), _jsxs("div", { className: "effective-config", children: [_jsx("code", { children: "pi.toml \u751F\u6548\u503C" }), _jsx("span", { children: status?.model ?? "由运行时提供" }), _jsx("span", { children: status ? `${status.messages} 条消息` : "—" }), _jsx("a", { href: "#", onClick: (event) => { event.preventDefault(); onToml(); }, children: "\u6539\u914D\u7F6E \u2318," })] }), _jsx("div", { className: "starter-grid", children: starters.map(([title, prompt]) => _jsxs("button", { className: "starter-card", onClick: () => onStarter(prompt), type: "button", children: [_jsx("strong", { children: title }), _jsx("small", { children: prompt })] }, title)) })] });
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
3
+ import { createClientApi, failedRefreshLabels, } from "./control-room.js";
4
+ import { getPromptCompletion, replacePromptCompletion } from "./prompt-completion.js";
5
+ import { compactThinkingEvents } from "./runtime-events.js";
6
+ import { MarkdownMessage } from "./markdown.js";
7
+ import { messageText, projectChatTurns } from "./message-content.js";
8
+ import { formatAnnotationPrompt, parseAnnotationPrompt } from "./annotation-ui.js";
9
+ import { marketplaceCategoryTabs, marketplaceDetailPath, marketplaceStatisticItems, readMarketplaceDetailId } from "./marketplace-navigation.js";
10
+ import { loadMarketplaceCatalog } from "./marketplace-catalog.js";
11
+ import { pluginStarsRows } from "./plugin-stars-view.js";
12
+ import { browserSessionTabs } from "./browser-session-view.js";
13
+ import { matchesPluginQuery } from "./plugin-search.js";
14
+ import { installedPluginDetailPath, readInstalledPluginDetailId } from "./plugin-navigation.js";
15
+ const value = (input, fallback = "") => {
16
+ if (input === undefined || input === null || input === "")
17
+ return fallback;
18
+ if (typeof input === "string" || typeof input === "number" || typeof input === "boolean" || typeof input === "bigint")
19
+ return String(input);
20
+ try {
21
+ return JSON.stringify(input);
22
+ }
23
+ catch {
24
+ return fallback;
25
+ }
26
+ };
27
+ const dialogFocusSelector = [
28
+ "button:not([disabled])",
29
+ "a[href]",
30
+ "input:not([disabled])",
31
+ "select:not([disabled])",
32
+ "textarea:not([disabled])",
33
+ "summary",
34
+ '[tabindex]:not([tabindex="-1"])',
35
+ ].join(",");
36
+ function useModalFocus(open, onClose, busy = false, returnFocusSelector) {
37
+ const dialogRef = useRef(null);
38
+ const closeRef = useRef(onClose);
39
+ const busyRef = useRef(busy);
40
+ closeRef.current = onClose;
41
+ busyRef.current = busy;
42
+ useEffect(() => {
43
+ if (!open)
44
+ return;
45
+ const activeElement = document.activeElement;
46
+ const previous = activeElement instanceof HTMLElement && activeElement !== document.body && activeElement !== document.documentElement ? activeElement : undefined;
47
+ const focusable = () => Array.from(dialogRef.current?.querySelectorAll(dialogFocusSelector) ?? []).filter((element) => !element.hidden && element.getAttribute("aria-hidden") !== "true" && element.getClientRects().length > 0);
48
+ const frame = window.requestAnimationFrame(() => {
49
+ const dialog = dialogRef.current;
50
+ if (!dialog || dialog.contains(document.activeElement))
51
+ return;
52
+ (dialog.querySelector("[data-dialog-initial-focus]") ?? focusable()[0])?.focus();
53
+ });
54
+ const onKeyDown = (event) => {
55
+ if (event.key === "Escape") {
56
+ event.preventDefault();
57
+ event.stopImmediatePropagation();
58
+ if (!busyRef.current)
59
+ closeRef.current();
60
+ return;
61
+ }
62
+ if (event.key !== "Tab")
63
+ return;
64
+ const items = focusable();
65
+ if (!items.length) {
66
+ event.preventDefault();
67
+ dialogRef.current?.focus();
68
+ return;
69
+ }
70
+ const first = items[0];
71
+ const last = items.at(-1);
72
+ if (event.shiftKey && document.activeElement === first) {
73
+ event.preventDefault();
74
+ last?.focus();
75
+ }
76
+ else if (!event.shiftKey && document.activeElement === last) {
77
+ event.preventDefault();
78
+ first?.focus();
79
+ }
80
+ };
81
+ window.addEventListener("keydown", onKeyDown, true);
82
+ return () => {
83
+ window.cancelAnimationFrame(frame);
84
+ window.removeEventListener("keydown", onKeyDown, true);
85
+ const returnFocus = previous?.isConnected ? previous : returnFocusSelector ? document.querySelector(returnFocusSelector) : undefined;
86
+ if (returnFocus)
87
+ window.requestAnimationFrame(() => returnFocus.focus());
88
+ };
89
+ }, [open, returnFocusSelector]);
90
+ return dialogRef;
91
+ }
92
+ const sessionSource = (status, session) => status?.cwd ?? (typeof session?.sessionFile === "string" ? session.sessionFile : "未选择工作区");
93
+ const eventLabel = (event) => {
94
+ const type = value(event.type, "");
95
+ if (type === "file_diff")
96
+ return "文件差异";
97
+ if (type === "file")
98
+ return "文件详情";
99
+ return value(event.summary ?? event.message ?? event.toolName ?? event.type ?? event.event, "未命名事件");
100
+ };
101
+ const capability = (name) => {
102
+ const entries = [
103
+ ["context", "上下文"],
104
+ ["agent-teams", "协作"],
105
+ ["modlens", "视觉"],
106
+ ["token-guard", "预算"],
107
+ ["git-time-capsule", "版本控制"],
108
+ ["dependency-checker", "工程诊断"],
109
+ ["at-file", "文件上下文"],
110
+ ["test-harness", "测试"],
111
+ ["session-insights", "会话统计"],
112
+ ["session-compare", "会话对比"],
113
+ ["secure-audit", "安全审计"],
114
+ ["readme-gen", "文档生成"],
115
+ ["i18n-pair", "国际化"],
116
+ ["cleaner", "清理"],
117
+ ["sql-lens", "数据库"],
118
+ ["docker-sandbox", "沙箱"],
119
+ ["mcp-client", "工具协议"],
120
+ ["mcp-panel", "MCP 控制台"],
121
+ ["browser-fetch", "网页抓取"],
122
+ ["web-research", "联网研究"],
123
+ ["browser-session", "浏览器会话"],
124
+ ["yaml-validator", "配置校验"],
125
+ ["mock-server", "接口模拟"],
126
+ ["cli-notifier", "桌面通知"],
127
+ ["obsidian-sync", "知识库"],
128
+ ["context-doctor", "上下文诊断"],
129
+ ["history-compressor", "历史压缩"],
130
+ ["reviewer-bot", "代码审查"],
131
+ ["auto-mode", "安全执行"],
132
+ ["plan-execute", "计划执行"],
133
+ ["plugin-finder", "插件发现"],
134
+ ["taskboard", "任务看板"],
135
+ ["synapse", "会话地图"],
136
+ ["hol-guard", "安全防护"],
137
+ ["plugin-radar", "生态雷达"],
138
+ ["plugin-stars", "排行榜"],
139
+ ["plugin-check", "插件体检"],
140
+ ["annotation", "批注上下文"],
141
+ ["cost-meter", "成本账本"],
142
+ ["undo-savepoint", "恢复保存点"],
143
+ ["skill-catalog", "技能目录"],
144
+ ["graph-memory", "知识图谱"],
145
+ ["memory", "跨会话记忆"],
146
+ ["canvas-draw", "流程图"],
147
+ ["image-compressor", "图片压缩"],
148
+ ["workspace-search", "工作区检索"],
149
+ ["prompt-guard", "提示词防护"],
150
+ ["code2skill", "技能打包"],
151
+ ["tab-manager", "会话标签"],
152
+ ["genui", "结构化界面"],
153
+ ["anchored-standard", "轨迹锚定"],
154
+ ["telemetry-blocker", "遥测拦截"],
155
+ ["change-verifier", "变更门禁"],
156
+ ["plugin-dev", "插件开发"],
157
+ ["openpets", "桌面伙伴"],
158
+ ["vision-toolkit", "视觉素材"],
159
+ ["session-bridge", "会话交接"],
160
+ ["skill-guard", "Skill 安全"],
161
+ ["recall-unread", "会话召回"],
162
+ ["turn-rewind", "会话回退"],
163
+ ["session-export", "会话导出"],
164
+ ["session-search", "会话搜索"],
165
+ ["session-bookmarks", "会话书签"],
166
+ ["llm-verifier", "模型校验"],
167
+ ["module-search", "模块检索"],
168
+ ["workspace-navigator", "工作区导航"],
169
+ ["better-sidebar", "侧栏概览"],
170
+ ["archify", "架构地图"],
171
+ ["mirage-bridge", "Mirage 虚拟终端"],
172
+ ["theme-studio", "主题"],
173
+ ["reverse-skill", "技能隔离"],
174
+ ["colleague-skill", "角色交接"],
175
+ ["prompt-library", "提示词库"],
176
+ ["model", "模型"],
177
+ ["tool", "工具"],
178
+ ["session", "会话"],
179
+ ["resource", "资源"],
180
+ ["web", "界面"],
181
+ ["gateway", "界面"],
182
+ ];
183
+ return entries.find(([needle]) => name.includes(needle))?.[1] ?? "运行时";
184
+ };
185
+ const displayPluginName = (name) => {
186
+ const officialName = new Map([
187
+ ["@pi-harness/core/plugins/context", "Context insights"],
188
+ ["@pi-harness/core/plugins/agent-teams", "Agent Teams"],
189
+ ["@pi-harness/core/plugins/modlens", "ModLens vision bridge"],
190
+ ["@pi-harness/core/plugins/token-guard", "Token Guard"],
191
+ ["@pi-harness/core/plugins/git-time-capsule", "Git Time Capsule"],
192
+ ["@pi-harness/core/plugins/dependency-checker", "Dependency Checker"],
193
+ ["@pi-harness/core/plugins/at-file", "@file context"],
194
+ ["@pi-harness/core/plugins/fail-logger", "Failure Logger"],
195
+ ["@pi-harness/core/plugins/test-harness", "Test Harness"],
196
+ ["@pi-harness/core/plugins/session-insights", "Session Insights"],
197
+ ["@pi-harness/core/plugins/session-compare", "Session Compare"],
198
+ ["@pi-harness/core/plugins/secure-audit", "Secure Audit"],
199
+ ["@pi-harness/core/plugins/readme-gen", "README Generator"],
200
+ ["@pi-harness/core/plugins/i18n-pair", "I18n Pair"],
201
+ ["@pi-harness/core/plugins/cleaner", "Harness Cleaner"],
202
+ ["@pi-harness/core/plugins/sql-lens", "SQL Lens"],
203
+ ["@pi-harness/core/plugins/docker-sandbox", "Docker Sandbox"],
204
+ ["@pi-harness/core/plugins/mcp-client", "MCP Client"],
205
+ ["@pi-harness/core/plugins/mcp-panel", "MCP Console"],
206
+ ["@pi-harness/core/plugins/browser-fetch", "Browser Fetch"],
207
+ ["@pi-harness/core/plugins/web-research", "Web Research"],
208
+ ["@pi-harness/core/plugins/browser-session", "Browser Session"],
209
+ ["@pi-harness/core/plugins/yaml-validator", "YAML Validator"],
210
+ ["@pi-harness/core/plugins/mock-server", "Mock Server"],
211
+ ["@pi-harness/core/plugins/cli-notifier", "CLI Notifier"],
212
+ ["@pi-harness/core/plugins/obsidian-sync", "Obsidian Sync"],
213
+ ["@pi-harness/core/plugins/context-doctor", "Context Doctor"],
214
+ ["@pi-harness/core/plugins/history-compressor", "History Compressor"],
215
+ ["@pi-harness/core/plugins/reviewer-bot", "Reviewer Bot"],
216
+ ["@pi-harness/core/plugins/auto-mode", "Auto Mode"],
217
+ ["@pi-harness/core/plugins/plan-execute", "Plan Execute"],
218
+ ["@pi-harness/core/plugins/plugin-finder", "Plugin Finder"],
219
+ ["@pi-harness/core/plugins/taskboard", "Taskboard"],
220
+ ["@pi-harness/core/plugins/synapse", "Synapse"],
221
+ ["@pi-harness/core/plugins/hol-guard", "HOL Guard"],
222
+ ["@pi-harness/core/plugins/plugin-radar", "Plugin Radar"],
223
+ ["@pi-harness/core/plugins/plugin-check", "Plugin Check"],
224
+ ["@pi-harness/core/plugins/annotation", "Annotations"],
225
+ ["@pi-harness/core/plugins/cost-meter", "Cost Meter"],
226
+ ["@pi-harness/core/plugins/undo-savepoint", "Undo Savepoints"],
227
+ ["@pi-harness/core/plugins/skill-catalog", "Skills Catalog"],
228
+ ["@pi-harness/core/plugins/memory", "Memory"],
229
+ ["@pi-harness/core/plugins/graph-memory", "Graph Memory"],
230
+ ["@pi-harness/core/plugins/canvas-draw", "Canvas Draw"],
231
+ ["@pi-harness/core/plugins/image-compressor", "Image Compressor"],
232
+ ["@pi-harness/core/plugins/workspace-search", "Workspace Search"],
233
+ ["@pi-harness/core/plugins/prompt-guard", "Prompt Guard"],
234
+ ["@pi-harness/core/plugins/code2skill", "Code2Skill"],
235
+ ["@pi-harness/core/plugins/tab-manager", "Session Tabs"],
236
+ ["@pi-harness/core/plugins/genui", "GenUI"],
237
+ ["@pi-harness/core/plugins/anchored-standard", "Anchored Standard"],
238
+ ["@pi-harness/core/plugins/telemetry-blocker", "Telemetry Blocker"],
239
+ ["@pi-harness/core/plugins/change-verifier", "Change Verifier"],
240
+ ["@pi-harness/core/plugins/plugin-dev", "Plugin Dev"],
241
+ ["@pi-harness/core/plugins/openpets", "OpenPets"],
242
+ ["@pi-harness/core/plugins/vision-toolkit", "Vision Toolkit"],
243
+ ["@pi-harness/core/plugins/plugin-stars", "Plugin Stars"],
244
+ ["@pi-harness/core/plugins/session-bridge", "Session Bridge"],
245
+ ["@pi-harness/core/plugins/skill-guard", "Skill Guard"],
246
+ ["@pi-harness/core/plugins/recall-unread", "Recall Unread"],
247
+ ["@pi-harness/core/plugins/turn-rewind", "Turn Rewind"],
248
+ ["@pi-harness/core/plugins/session-export", "Session Export"],
249
+ ["@pi-harness/core/plugins/session-search", "Session Search"],
250
+ ["@pi-harness/core/plugins/session-bookmarks", "Session Bookmarks"],
251
+ ["@pi-harness/core/plugins/llm-verifier", "LLM Verifier"],
252
+ ["@pi-harness/core/plugins/module-search", "Module Search"],
253
+ ["@pi-harness/core/plugins/workspace-navigator", "Workspace Navigator"],
254
+ ["@pi-harness/core/plugins/better-sidebar", "Better Sidebar"],
255
+ ["@pi-harness/core/plugins/archify", "Architecture Map"],
256
+ ["@pi-harness/core/plugins/mirage-bridge", "Mirage Bridge"],
257
+ ["@pi-harness/core/plugins/theme-studio", "Theme Studio"],
258
+ ["@pi-harness/core/plugins/reverse-skill", "Reverse Skill Firewall"],
259
+ ["@pi-harness/core/plugins/colleague-skill", "Colleague Skill"],
260
+ ["@pi-harness/core/plugins/prompt-library", "Prompt Library"],
261
+ ["@pi-harness/core/plugins/runtime-doctor", "Runtime Doctor"],
262
+ ]).get(name);
263
+ if (officialName !== undefined)
264
+ return officialName;
265
+ const packageMatch = name.match(/^@[^/]+\/cordis-plugin-(.+)$/i);
266
+ if (packageMatch)
267
+ return `官方 · ${packageMatch[1]}`;
268
+ if (name.toLowerCase().includes("cordis"))
269
+ return name.replace(/cordis/gi, "runtime");
270
+ return name;
271
+ };
272
+ const readQueryState = () => {
273
+ if (typeof window === "undefined")
274
+ return {
275
+ page: "session",
276
+ view: "chat",
277
+ marketplaceQuery: "",
278
+ marketplaceCapability: "",
279
+ marketplaceCategory: "",
280
+ marketplacePlugin: undefined,
281
+ installedPlugin: undefined,
282
+ marketplacePage: 0,
283
+ };
284
+ const params = new URLSearchParams(window.location.search);
285
+ const page = params.get("page");
286
+ const view = params.get("view");
287
+ const settings = params.get("settings");
288
+ const parsedPage = page === "plugins" || page === "marketplace" ? page : "session";
289
+ const parsedView = view === "trajectory" || view === "files" ? view : "chat";
290
+ const parsedSettings = settings === "providers" || settings === "toml" ? settings : settings === "general" ? settings : undefined;
291
+ const pageNumber = Number.parseInt(params.get("marketplacePage") ?? "0", 10);
292
+ return {
293
+ page: parsedPage,
294
+ view: parsedView,
295
+ settings: parsedSettings,
296
+ sessionPath: params.get("session") ?? undefined,
297
+ marketplaceQuery: params.get("marketplaceQuery") ?? "",
298
+ marketplaceCapability: params.get("capability") ?? "",
299
+ marketplaceCategory: params.get("category") ?? "",
300
+ marketplacePlugin: readMarketplaceDetailId(params),
301
+ installedPlugin: readInstalledPluginDetailId(params),
302
+ marketplacePage: Number.isFinite(pageNumber) && pageNumber >= 0 ? pageNumber : 0,
303
+ };
304
+ };
305
+ function sessionGroups(sessions) {
306
+ const now = new Date();
307
+ const start = new Date(now.getFullYear(), now.getMonth(), now.getDate()).getTime();
308
+ const yesterday = start - 86_400_000;
309
+ const groups = new Map();
310
+ for (const session of sessions) {
311
+ const raw = session.modified ?? session.created;
312
+ const timestamp = typeof raw === "number" ? raw : typeof raw === "string" ? Date.parse(raw) : Number.NaN;
313
+ const label = Number.isFinite(timestamp) && timestamp >= start ? "今天" : Number.isFinite(timestamp) && timestamp >= yesterday ? "昨天" : "更早";
314
+ groups.set(label, [...(groups.get(label) ?? []), session]);
315
+ }
316
+ return ["今天", "昨天", "更早"].flatMap((label) => {
317
+ const items = groups.get(label);
318
+ return items?.length ? [[label, items]] : [];
319
+ });
320
+ }
321
+ function Workspace({ status, workspaces, onCreate, onStarter, onToml, }) {
322
+ const starters = [
323
+ ["定位问题", "分析当前仓库并给出根因"],
324
+ ["修复并测试", "实现修复并运行相关测试"],
325
+ ["审查改动", "只读检查未提交变更"],
326
+ ["解释代码", "解释当前文件的关键逻辑"],
327
+ ];
328
+ return (_jsxs("div", { className: "new-session-screen", children: [_jsx("div", { className: "welcome-kicker", children: "PI AGENT HARNESS \u00B7 REAL RUNTIME" }), _jsxs("div", { className: "welcome-heading", children: [_jsx("span", { className: "pi-mark large", "aria-hidden": "true", children: _jsx("img", { src: "/icons/svg/mark-white.svg", alt: "" }) }), _jsxs("div", { children: [_jsx("h2", { children: "\u5F00\u59CB\u4E00\u4E2A\u5DE5\u4F5C\u4F1A\u8BDD" }), _jsx("p", { children: "\u8FDE\u63A5\u5F53\u524D\u5DE5\u4F5C\u533A\uFF0C\u76F4\u63A5\u8BA9 Pi agent \u8BFB\u53D6\u3001\u4FEE\u6539\u5E76\u9A8C\u8BC1\u4EE3\u7801\u3002" })] })] }), _jsx("div", { className: "workspace-picker", children: workspaces.length ? (workspaces.map((workspace) => (_jsxs("button", { className: "workspace-row", onClick: () => onCreate(workspace), type: "button", children: [_jsx("span", { className: `workspace-status ${workspace.current ? "live" : "offline"}`, children: workspace.current ? "已连接" : "工作区" }), _jsxs("span", { children: [_jsx("code", { children: workspace.path }), _jsx("small", { children: workspace.current && status ? `${workspace.branch} · ${status.model}` : workspace.branch })] }), _jsx("span", { className: "workspace-arrow", children: "\u2197" })] }, workspace.path)))) : (_jsxs("div", { className: "workspace-row is-empty", children: [_jsx("span", { className: "workspace-status offline", children: "\u52A0\u8F7D\u4E2D" }), _jsxs("span", { children: [_jsx("code", { children: status?.cwd ?? "加载工作区…" }), _jsx("small", { children: "\u6B63\u5728\u8BFB\u53D6 git worktree" })] })] })) }), _jsxs("div", { className: "effective-config", children: [_jsx("span", { className: "config-label", children: "\u5F53\u524D\u8FD0\u884C\u65F6" }), _jsx("span", { children: status?.model ?? "由运行时提供" }), _jsx("span", { children: status ? `${status.messages} 条消息` : "—" }), _jsx("a", { href: "#", onClick: (event) => {
329
+ event.preventDefault();
330
+ onToml();
331
+ }, children: "\u6539\u914D\u7F6E \u2318," })] }), _jsx("div", { className: "starter-grid", children: starters.map(([title, prompt]) => (_jsxs("button", { className: "starter-card", onClick: () => onStarter(prompt), type: "button", children: [_jsx("strong", { children: title }), _jsx("small", { children: prompt })] }, title))) })] }));
332
+ }
333
+ function WorkspaceChooser({ workspaces, onSelect, onPickDirectory, onClose, error, }) {
334
+ const dialogRef = useModalFocus(true, onClose);
335
+ return (_jsx("div", { className: "workspace-chooser", onClick: onClose, children: _jsxs("div", { "aria-label": "\u9009\u62E9\u5DE5\u4F5C\u533A", "aria-modal": "true", className: "workspace-chooser-dialog", onClick: (event) => event.stopPropagation(), ref: dialogRef, role: "dialog", tabIndex: -1, children: [_jsxs("div", { className: "workspace-chooser-heading", children: [_jsx("strong", { children: "\u65B0\u5EFA\u4F1A\u8BDD" }), _jsx("button", { "aria-label": "\u5173\u95ED\u5DE5\u4F5C\u533A\u9009\u62E9", onClick: onClose, type: "button", children: "\u00D7" })] }), _jsx("small", { children: "\u9009\u62E9\u8FD9\u4E2A\u4F1A\u8BDD\u8981\u4F7F\u7528\u7684\u5DE5\u4F5C\u533A" }), error ? (_jsx("div", { className: "workspace-chooser-error", role: "alert", children: error })) : null, _jsxs("button", { className: "workspace-pick-directory", "data-dialog-initial-focus": true, onClick: () => void onPickDirectory(), type: "button", children: [_jsx("span", { children: "\u6253\u5F00\u76EE\u5F55" }), _jsx("small", { children: "\u4ECE Finder \u9009\u62E9\u4E00\u4E2A\u65B0\u7684\u5DE5\u4F5C\u76EE\u5F55" })] }), _jsx("div", { className: "workspace-chooser-divider", children: _jsx("span", { children: "\u6216\u9009\u62E9\u5DF2\u6709 worktree" }) }), workspaces.length ? (workspaces.map((workspace) => (_jsxs("button", { className: "workspace-chooser-row", onClick: () => onSelect(workspace), type: "button", children: [_jsx("span", { className: `workspace-status ${workspace.current ? "live" : "offline"}`, children: workspace.current ? "当前" : "worktree" }), _jsxs("span", { children: [_jsx("strong", { children: workspace.name }), _jsx("code", { children: workspace.path })] }), _jsx("small", { children: workspace.branch })] }, workspace.path)))) : (_jsx("span", { className: "workspace-chooser-empty", children: "\u6B63\u5728\u8BFB\u53D6 git worktree\u2026" }))] }) }));
336
+ }
337
+ function SessionDialog({ kind, name, count, value: draft, busy, onChange, onClose, onConfirm, }) {
338
+ const destructive = kind === "delete" || kind === "batch-delete";
339
+ const title = kind === "rename" ? "重命名会话" : kind === "archive" ? "归档会话" : destructive ? "删除会话" : "会话操作";
340
+ const description = kind === "rename"
341
+ ? "给这个会话一个容易识别的名称。"
342
+ : kind === "archive"
343
+ ? "归档后会从默认列表隐藏,之后仍可在会话工具中恢复。"
344
+ : `将永久删除${count && count > 1 ? ` ${count} 个会话` : "这个会话"}及其本地记录,此操作不可撤销。`;
345
+ const dialogRef = useModalFocus(true, onClose, busy, ".session-menu");
346
+ return (_jsx("div", { className: "session-dialog-backdrop", onClick: () => {
347
+ if (!busy)
348
+ onClose();
349
+ }, children: _jsxs("div", { "aria-label": title, "aria-modal": "true", className: "session-dialog", onClick: (event) => event.stopPropagation(), ref: dialogRef, role: "dialog", tabIndex: -1, children: [_jsxs("header", { className: "session-dialog-header", children: [_jsxs("div", { children: [_jsx("strong", { children: title }), _jsx("small", { children: description })] }), _jsx("button", { "aria-label": "\u5173\u95ED", disabled: busy, onClick: onClose, type: "button", children: "\u00D7" })] }), kind === "rename" && (_jsxs("label", { className: "session-dialog-field", children: [_jsx("span", { children: "\u540D\u79F0" }), _jsx("input", { "data-dialog-initial-focus": true, disabled: busy, onChange: (event) => onChange(event.target.value), onKeyDown: (event) => event.key === "Enter" && !busy && onConfirm(), value: draft })] })), name && kind !== "rename" && _jsx("div", { className: "session-dialog-target", children: name }), _jsxs("footer", { className: "session-dialog-actions", children: [_jsx("button", { "data-dialog-initial-focus": kind !== "rename" ? "" : undefined, disabled: busy, onClick: onClose, type: "button", children: "\u53D6\u6D88" }), _jsx("button", { className: destructive ? "danger" : "primary", disabled: busy || (kind === "rename" && !draft.trim()), onClick: onConfirm, type: "button", children: busy ? "处理中…" : kind === "rename" ? "保存名称" : kind === "archive" ? "归档" : "永久删除" })] })] }) }));
350
+ }
351
+ function ConfirmDialog({ title, description, target, confirmLabel, busy, onClose, onConfirm, }) {
352
+ const dialogRef = useModalFocus(true, onClose, busy);
353
+ return (_jsx("div", { className: "session-dialog-backdrop", onClick: () => {
354
+ if (!busy)
355
+ onClose();
356
+ }, children: _jsxs("div", { "aria-label": title, "aria-modal": "true", className: "session-dialog", onClick: (event) => event.stopPropagation(), ref: dialogRef, role: "dialog", tabIndex: -1, children: [_jsxs("header", { className: "session-dialog-header", children: [_jsxs("div", { children: [_jsx("strong", { children: title }), _jsx("small", { children: description })] }), _jsx("button", { "aria-label": "\u5173\u95ED", disabled: busy, onClick: onClose, type: "button", children: "\u00D7" })] }), target && _jsx("div", { className: "session-dialog-target", children: target }), _jsxs("footer", { className: "session-dialog-actions", children: [_jsx("button", { "data-dialog-initial-focus": true, disabled: busy, onClick: onClose, type: "button", children: "\u53D6\u6D88" }), _jsx("button", { className: "danger", disabled: busy, onClick: onConfirm, type: "button", children: busy ? "处理中…" : confirmLabel })] })] }) }));
357
+ }
358
+ function SessionActionMenu({ busy, onRename, onFork, onArchive, onDelete, }) {
359
+ return (_jsxs("div", { className: "session-row-menu-popover", onClick: (event) => event.stopPropagation(), children: [_jsx("button", { disabled: busy, onClick: onRename, type: "button", children: "\u91CD\u547D\u540D" }), _jsx("button", { disabled: busy, onClick: onFork, type: "button", children: "\u590D\u5236\u4F1A\u8BDD" }), _jsx("button", { disabled: busy, onClick: onArchive, type: "button", children: "\u5F52\u6863\u4F1A\u8BDD" }), _jsx("button", { className: "danger", disabled: busy, onClick: onDelete, type: "button", children: "\u5220\u9664\u4F1A\u8BDD" })] }));
360
+ }
361
+ function PromptError({ message }) {
362
+ const everyApiAuth = /No API key found for everyapi/i.test(message);
363
+ const requiresAuth = everyApiAuth || /No API key found|authentication|未配置认证/i.test(message);
364
+ return (_jsxs("div", { className: "action-error", role: "alert", children: [_jsxs("div", { className: "action-error-summary", children: [_jsx("strong", { children: everyApiAuth ? "EveryAPI 认证未注入当前进程" : requiresAuth ? "模型尚未配置认证" : "发送失败" }), _jsx("span", { children: everyApiAuth
365
+ ? "请用 everyapi use pi-harness 启动,或设置 EVERYAPI_RELAY_KEY 后重启。"
366
+ : requiresAuth
367
+ ? "请在设置 → 提供商中配置 API key,然后重试。"
368
+ : "运行时没有接受这次请求,请重试或查看错误详情。" })] }), _jsxs("details", { children: [_jsx("summary", { children: "\u67E5\u770B\u539F\u59CB\u9519\u8BEF" }), _jsx("code", { children: message })] })] }));
369
+ }
370
+ function UserMessageBubble({ text }) {
371
+ const parsed = parseAnnotationPrompt(text);
372
+ return (_jsxs("div", { className: "user-bubble", children: [_jsx("span", { children: parsed.question }), parsed.count > 0 ? (_jsxs("span", { className: "ml-2 inline-flex rounded-md bg-[#edf3fe] px-1.5 py-0.5 text-[10px] text-[#315fb8]", children: ["\u6279\u6CE8 \u00D7", parsed.count] })) : null] }));
43
373
  }
44
374
  function Details({ event, onClose, onCopy }) {
45
375
  if (!event)
46
- return _jsxs("aside", { className: "details-panel", children: [_jsxs("header", { children: [_jsx("strong", { children: "\u4E8B\u4EF6\u8BE6\u60C5" }), _jsx("button", { onClick: onClose, type: "button", children: "\u00D7" })] }), _jsx("div", { className: "details-body", children: _jsx("div", { className: "empty-state", children: "\u9009\u62E9\u8F68\u8FF9\u4E2D\u7684\u4E8B\u4EF6\u67E5\u770B\u539F\u59CB\u6570\u636E\u3002" }) })] });
376
+ return (_jsxs("aside", { className: "details-panel", children: [_jsxs("header", { children: [_jsx("strong", { children: "\u4E8B\u4EF6\u8BE6\u60C5" }), _jsx("button", { "aria-label": "\u5173\u95ED\u4E8B\u4EF6\u8BE6\u60C5", onClick: onClose, type: "button", children: "\u00D7" })] }), _jsx("div", { className: "details-body", children: _jsx("div", { className: "empty-state", children: "\u9009\u62E9\u8F68\u8FF9\u4E2D\u7684\u4E8B\u4EF6\u67E5\u770B\u539F\u59CB\u6570\u636E\u3002" }) })] }));
47
377
  const output = event.output ?? event.result ?? event.message;
48
- const stats = [["来源", value(event.type ?? event.source, "event")], ["产生者", value(event.by ?? event.source)], ["耗时", value(event.duration ?? event.dur)], ["时间", value(event.timestamp ?? event.ts ?? event.time)]];
49
- return _jsxs("aside", { className: "details-panel", children: [_jsxs("header", { children: [_jsx("strong", { children: eventLabel(event) }), _jsx("button", { onClick: onClose, type: "button", children: "\u00D7" })] }), _jsxs("div", { className: "details-body", children: [_jsx("div", { className: "detail-stats", children: stats.map(([key, item]) => _jsxs("div", { children: [_jsx("small", { children: key }), _jsx("b", { children: item })] }, key)) }), output !== undefined && _jsxs("div", { className: "detail-section", children: [_jsx("small", { children: "\u8F93\u51FA" }), _jsx("pre", { className: "tool-output", children: typeof output === "string" ? output : JSON.stringify(output, null, 2) })] }), _jsxs("div", { className: "detail-section", children: [_jsx("small", { children: "\u7ECF\u8FC7\u7684\u63D2\u4EF6" }), _jsx("div", { className: "detail-plugin", children: "Cordis loader \u00B7 runtime event" })] }), _jsxs("div", { className: "detail-actions", children: [_jsx("button", { onClick: onCopy, type: "button", children: "\u590D\u5236 JSON" }), _jsx("button", { disabled: true, title: "\u5F53\u524D API \u672A\u63D0\u4F9B\u91CD\u653E\u63A5\u53E3", type: "button", children: "\u91CD\u653E" })] }), _jsxs("details", { className: "raw-json", children: [_jsx("summary", { children: "\u539F\u59CB JSON" }), _jsx("pre", { className: "raw-json-body", children: JSON.stringify(event, null, 2) })] })] })] });
378
+ const fileDetail = event.type === "file" || event.type === "file_diff";
379
+ const stats = fileDetail
380
+ ? [
381
+ ["来源", "/api/files"],
382
+ ["文件", value(event.path)],
383
+ ]
384
+ : [
385
+ ["来源", value(event.type ?? event.source, "event")],
386
+ ["产生者", value(event.by ?? event.source)],
387
+ ["耗时", value(event.duration ?? event.dur)],
388
+ ["时间", value(event.timestamp ?? event.ts ?? event.time)],
389
+ ];
390
+ return (_jsxs("aside", { className: "details-panel", children: [_jsxs("header", { children: [_jsx("strong", { children: eventLabel(event) }), _jsx("button", { "aria-label": "\u5173\u95ED\u4E8B\u4EF6\u8BE6\u60C5", onClick: onClose, type: "button", children: "\u00D7" })] }), _jsxs("div", { className: "details-body", children: [_jsx("div", { className: "detail-stats", children: stats.map(([key, item]) => (_jsxs("div", { children: [_jsx("small", { children: key }), _jsx("b", { children: item })] }, key))) }), output !== undefined && (_jsxs("div", { className: "detail-section", children: [_jsx("small", { children: "\u8F93\u51FA" }), _jsx("pre", { className: "tool-output", children: typeof output === "string" ? output : JSON.stringify(output, null, 2) })] })), _jsxs("div", { className: "detail-section", children: [_jsx("small", { children: fileDetail ? "数据来源" : "经过的插件" }), _jsx("div", { className: "detail-plugin", children: fileDetail ? "Git workspace · /api/files" : "Runtime loader · event" })] }), _jsxs("div", { className: "detail-actions", children: [_jsx("button", { onClick: onCopy, type: "button", children: "\u590D\u5236 JSON" }), _jsx("button", { disabled: true, title: "\u5F53\u524D API \u672A\u63D0\u4F9B\u91CD\u653E\u63A5\u53E3", type: "button", children: "\u91CD\u653E" })] }), _jsxs("details", { className: "raw-json", children: [_jsx("summary", { children: "\u539F\u59CB JSON" }), _jsx("pre", { className: "raw-json-body", children: JSON.stringify(event, null, 2) })] })] })] }));
50
391
  }
51
392
  function Trajectory({ events, onSelect }) {
52
393
  const [filter, setFilter] = useState("all");
53
- const counts = useMemo(() => { const map = new Map(); events.forEach((event) => { const type = value(event.type, "event"); map.set(type, (map.get(type) ?? 0) + 1); }); return map; }, [events]);
394
+ const counts = useMemo(() => {
395
+ const map = new Map();
396
+ events.forEach((event) => {
397
+ const type = value(event.type, "event");
398
+ map.set(type, (map.get(type) ?? 0) + 1);
399
+ });
400
+ return map;
401
+ }, [events]);
54
402
  const visible = events.filter((event) => filter === "all" || value(event.type, "event") === filter);
55
- return _jsxs("section", { className: "view-panel trajectory-view", children: [_jsxs("div", { className: "trajectory-summary", children: [_jsx("span", { children: "\u6309\u8F6E\u6B21" }), _jsxs("b", { children: [events.length, " \u4E2A\u4E8B\u4EF6"] }), _jsx("div", { className: "timeline", children: events.length ? events.map((event, index) => _jsx("span", { className: "timeline-turn", children: _jsx("i", { className: "timeline-strip", title: eventLabel(event) }) }, index)) : _jsx("span", { className: "timeline-empty", children: "\u7B49\u5F85\u771F\u5B9E\u4E8B\u4EF6\u2026" }) })] }), _jsxs("div", { className: "source-filters", children: [_jsxs("button", { className: `filter ${filter === "all" ? "active" : ""}`, onClick: () => setFilter("all"), type: "button", children: ["\u5168\u90E8 ", events.length] }), [...counts].map(([type, count]) => _jsxs("button", { className: `filter ${filter === type ? "active" : ""}`, onClick: () => setFilter(type), type: "button", children: [type, " ", count] }, type))] }), _jsxs("div", { className: "event-table", children: [_jsxs("div", { className: "event-head", children: [_jsx("span", { children: "\u65F6\u95F4" }), _jsx("span", { children: "\u6765\u6E90" }), _jsx("span", { children: "\u4E8B\u4EF6" }), _jsx("span", { children: "\u4EA7\u751F\u8005" }), _jsx("span", { children: "\u8017\u65F6" })] }), visible.map((event, index) => _jsxs("button", { className: "event-row", onClick: () => onSelect(event), type: "button", children: [_jsx("span", { children: value(event.timestamp ?? event.ts ?? event.time) }), _jsxs("span", { children: [_jsx("i", { className: "event-dot" }), value(event.type, "event")] }), _jsx("strong", { children: eventLabel(event) }), _jsx("span", { children: value(event.by ?? event.source) }), _jsx("span", { children: value(event.duration ?? event.dur) })] }, index)), !visible.length && _jsx("div", { className: "empty-state", children: "\u6682\u65E0\u8F68\u8FF9\u4E8B\u4EF6\u3002" })] })] });
403
+ return (_jsxs("section", { className: "view-panel trajectory-view", children: [_jsxs("div", { className: "trajectory-summary", children: [_jsx("span", { children: "\u6309\u8F6E\u6B21" }), _jsxs("b", { children: [events.length, " \u4E2A\u4E8B\u4EF6"] }), _jsx("div", { className: "timeline", children: events.length ? (events.map((event, index) => (_jsx("span", { className: "timeline-turn", children: _jsx("i", { className: "timeline-strip", title: eventLabel(event) }) }, index)))) : (_jsx("span", { className: "timeline-empty", children: "\u7B49\u5F85\u771F\u5B9E\u4E8B\u4EF6\u2026" })) })] }), _jsxs("div", { className: "source-filters", children: [_jsxs("button", { className: `filter ${filter === "all" ? "active" : ""}`, onClick: () => setFilter("all"), type: "button", children: ["\u5168\u90E8 ", events.length] }), [...counts].map(([type, count]) => (_jsxs("button", { className: `filter ${filter === type ? "active" : ""}`, onClick: () => setFilter(type), type: "button", children: [type, " ", count] }, type)))] }), _jsxs("div", { className: "event-table", children: [_jsxs("div", { className: "event-head", children: [_jsx("span", { children: "\u65F6\u95F4" }), _jsx("span", { children: "\u6765\u6E90" }), _jsx("span", { children: "\u4E8B\u4EF6" }), _jsx("span", { children: "\u4EA7\u751F\u8005" }), _jsx("span", { children: "\u8017\u65F6" })] }), visible.map((event, index) => (_jsxs("button", { className: "event-row", onClick: () => onSelect(event), type: "button", children: [_jsx("span", { children: value(event.timestamp ?? event.ts ?? event.time) }), _jsxs("span", { children: [_jsx("i", { className: "event-dot" }), value(event.type, "event")] }), _jsx("strong", { children: eventLabel(event) }), _jsx("span", { children: value(event.by ?? event.source) }), _jsx("span", { children: value(event.duration ?? event.dur) })] }, index))), !visible.length && _jsx("div", { className: "empty-state", children: "\u6682\u65E0\u8F68\u8FF9\u4E8B\u4EF6\u3002" })] })] }));
404
+ }
405
+ function Files({ files, api, onDiff, onRefresh }) {
406
+ const additions = files.filter((file) => file.status.includes("A") || file.status === "??").length;
407
+ const deletions = files.filter((file) => file.status.includes("D")).length;
408
+ const [message, setMessage] = useState("");
409
+ const [busy, setBusy] = useState(false);
410
+ const [error, setError] = useState("");
411
+ const [revertConfirmOpen, setRevertConfirmOpen] = useState(false);
412
+ const commit = () => {
413
+ const text = message.trim();
414
+ if (!text || busy)
415
+ return;
416
+ setBusy(true);
417
+ setError("");
418
+ void api
419
+ .commitFiles(files.map((file) => file.path), text)
420
+ .then(() => {
421
+ setMessage("");
422
+ onRefresh();
423
+ })
424
+ .catch((cause) => setError(cause instanceof Error ? cause.message : String(cause)))
425
+ .finally(() => setBusy(false));
426
+ };
427
+ const revert = () => {
428
+ if (!files.length || busy)
429
+ return;
430
+ setRevertConfirmOpen(false);
431
+ setBusy(true);
432
+ setError("");
433
+ void api
434
+ .revertFiles(files.map((file) => file.path))
435
+ .then(onRefresh)
436
+ .catch((cause) => setError(cause instanceof Error ? cause.message : String(cause)))
437
+ .finally(() => setBusy(false));
438
+ };
439
+ return (_jsxs("section", { className: "view-panel files-view", children: [_jsxs("div", { className: "files-content", children: [_jsxs("div", { className: "files-title", children: [_jsx("strong", { children: "\u672C\u6B21\u4F1A\u8BDD\u6539\u52A8" }), _jsx("span", { children: "\u7531 /api/files \u63D0\u4F9B" })] }), _jsx("div", { className: "file-summary", children: `${files.length} 个文件 · ${additions} 个新增 · ${deletions} 个删除` }), _jsx("div", { className: "file-list", children: files.length ? (files.map((file) => (_jsxs("div", { className: "file-row", children: [_jsx("b", { className: `file-kind ${file.label === "untracked" ? "new" : ""}`, children: file.label }), _jsx("code", { children: file.path }), _jsx("span", { className: file.status.includes("D") ? "del" : "add", children: file.status }), _jsx("button", { className: "diff-button", onClick: () => onDiff(file.path), type: "button", children: "\u67E5\u770B\u5DEE\u5F02" })] }, file.path)))) : (_jsx("div", { className: "empty-state", children: "\u5DE5\u4F5C\u533A\u6CA1\u6709\u672A\u63D0\u4EA4\u6539\u52A8\u3002" })) }), files.length > 0 && (_jsxs("div", { className: "file-actions", children: [_jsx("input", { "aria-label": "\u63D0\u4EA4\u8BF4\u660E", onChange: (event) => setMessage(event.target.value), placeholder: "\u63D0\u4EA4\u8BF4\u660E", value: message }), _jsx("button", { className: "primary", disabled: busy || !message.trim(), onClick: commit, type: "button", children: busy ? "处理中…" : "提交这些改动" }), _jsx("button", { disabled: busy, onClick: () => setRevertConfirmOpen(true), type: "button", children: "\u5168\u90E8\u64A4\u9500" })] })), error && _jsx("p", { className: "files-error", children: error })] }), revertConfirmOpen && (_jsx(ConfirmDialog, { busy: busy, confirmLabel: "\u786E\u8BA4\u64A4\u9500", description: "\u8FD9\u4F1A\u4E22\u5F03\u5F53\u524D\u5DE5\u4F5C\u533A\u7684\u5168\u90E8\u672A\u63D0\u4EA4\u6539\u52A8\uFF0C\u6B64\u64CD\u4F5C\u4E0D\u53EF\u6062\u590D\u3002", onClose: () => setRevertConfirmOpen(false), onConfirm: revert, target: `${files.length} 个文件`, title: "\u64A4\u9500\u5168\u90E8\u6539\u52A8" }))] }));
440
+ }
441
+ function pluginPanelValue(input) {
442
+ if (typeof input === "string")
443
+ return input;
444
+ try {
445
+ return JSON.stringify(input, null, 2) ?? value(input);
446
+ }
447
+ catch {
448
+ return value(input);
449
+ }
450
+ }
451
+ function PluginPanelCard({ panel, inline = false }) {
452
+ const data = panel.data !== null && typeof panel.data === "object" && !Array.isArray(panel.data) ? panel.data : undefined;
453
+ const entries = data ? Object.entries(data) : [["内容", panel.data]];
454
+ const items = data && Array.isArray(data.items) ? data.items : [];
455
+ const pluginEntries = data && Array.isArray(data.entries) ? data.entries : [];
456
+ const capabilities = data && Array.isArray(data.capabilities) ? data.capabilities : [];
457
+ return (_jsxs("div", { className: `plugin-panel-card ${inline ? "pt-1" : "rounded-[10px] border border-[#e3e7ee] bg-white p-4 shadow-[0_8px_24px_rgba(27,39,64,0.04)]"}`, children: [_jsxs("header", { className: "flex items-start gap-3", children: [_jsx("span", { className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-[#edf3fe] font-mono text-[15px] text-[#3565c5]", children: panel.icon ?? "◈" }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("strong", { className: "block text-[13px] font-semibold text-[#20252b]", children: panel.title }), _jsx("p", { className: "mt-1 text-[11px] leading-4 text-[#687381]", children: panel.description ?? panel.pluginId.replace(/cordis/gi, "runtime") })] })] }), panel.error ? (_jsx("div", { className: "mt-3 rounded-lg border border-[#f4caca] bg-[#fff5f5] px-3 py-2 text-[12px] text-[#b42318]", children: panel.error })) : panel.id === "console-logger-panel" ? (_jsxs("div", { className: "mt-3 grid gap-2", children: [_jsxs("div", { className: "rounded-lg bg-[#f6f8fa] px-3 py-2", children: [_jsx("span", { className: "block font-mono text-[10px] uppercase tracking-[0.08em] text-[#687381]", children: "\u6700\u8FD1\u65E5\u5FD7" }), _jsx("strong", { className: "mt-1 block text-[20px] font-semibold text-[#20252b]", children: value(data?.total ?? 0) })] }), _jsx("div", { className: "max-h-48 overflow-auto rounded-lg border border-[#edf0f3]", children: items.length ? (items.map((item, index) => {
458
+ const message = item !== null && typeof item === "object" ? item : {};
459
+ return (_jsxs("div", { className: "grid grid-cols-[auto_1fr] gap-2 border-b border-[#edf0f3] px-3 py-2 last:border-b-0", children: [_jsx("span", { className: "font-mono text-[10px] text-[#687381]", children: value(message.level ?? "log") }), _jsxs("div", { className: "min-w-0", children: [_jsx("strong", { className: "block truncate text-[11px] text-[#30343b]", children: value(message.source ?? "runtime") }), _jsx("span", { className: "block whitespace-pre-wrap break-words text-[11px] leading-4 text-[#65707b]", children: pluginPanelValue(message.args ?? "") })] })] }, `${value(message.time ?? "log")}-${index}`));
460
+ })) : (_jsx("div", { className: "px-3 py-4 text-[12px] text-[#687381]", children: "\u6682\u65E0\u65E5\u5FD7\u8F93\u51FA\u3002" })) })] })) : panel.id === "plugin-group-panel" ? (_jsx("div", { className: "mt-3 max-h-64 overflow-auto rounded-lg border border-[#edf0f3]", children: pluginEntries.length ? (pluginEntries.map((item, index) => {
461
+ const entry = item !== null && typeof item === "object" ? item : {};
462
+ return (_jsxs("div", { className: "flex items-center gap-3 border-b border-[#edf0f3] px-3 py-2 last:border-b-0", children: [_jsx("span", { className: `h-2 w-2 shrink-0 rounded-full ${entry.enabled === false ? "bg-[#a0a8b2]" : "bg-[#22c55e]"}` }), _jsx("span", { className: "min-w-0 flex-1 truncate font-mono text-[11px] text-[#30343b]", children: value(entry.name ?? "plugin") }), _jsx("span", { className: "text-[10px] text-[#687381]", children: value(entry.state ?? "unknown") })] }, `${value(entry.id ?? "plugin")}-${index}`));
463
+ })) : (_jsx("div", { className: "px-3 py-4 text-[12px] text-[#687381]", children: "\u6682\u65E0\u63D2\u4EF6\u6761\u76EE\u3002" })) })) : panel.id === "timer-service-panel" ? (_jsxs("div", { className: "mt-3 grid gap-3 rounded-lg bg-[#f6f8fa] px-3 py-3", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("span", { className: "font-mono text-[10px] uppercase tracking-[0.08em] text-[#687381]", children: "\u670D\u52A1\u72B6\u6001" }), _jsx("span", { className: `rounded-full px-2 py-1 text-[10px] font-semibold ${data?.registered === true ? "bg-[#e8f8ee] text-[#14733f]" : "bg-[#fff4e5] text-[#8a5a00]"}`, children: data?.registered === true ? "已注册" : "未注册" })] }), _jsx("div", { className: "flex flex-wrap gap-2", children: capabilities.map((capability, index) => (_jsx("span", { className: "rounded-md border border-[#dce5f5] bg-white px-2 py-1 font-mono text-[10px] text-[#3565c5]", children: value(capability) }, `${value(capability)}-${index}`))) })] })) : panel.id === "agent-teams-panel" ? (_jsxs("div", { className: "mt-3 grid gap-3", children: [_jsxs("div", { className: "grid gap-2 sm:grid-cols-3", children: [capabilities.length > 0
464
+ ? capabilities.map((capability, index) => (_jsx("span", { className: "rounded-md border border-[#dce5f5] bg-white px-2 py-1 text-center text-[10px] text-[#3565c5]", children: value(capability) }, `${value(capability)}-${index}`)))
465
+ : null, _jsxs("div", { className: "rounded-lg bg-[#f6f8fa] px-3 py-2", children: [_jsx("span", { className: "block text-[10px] text-[#687381]", children: "\u6210\u5458" }), _jsx("strong", { className: "mt-1 block text-[17px] font-semibold text-[#30343b]", children: value(Array.isArray(data?.members) ? data.members.length : 0) })] }), _jsxs("div", { className: "rounded-lg bg-[#f6f8fa] px-3 py-2", children: [_jsx("span", { className: "block text-[10px] text-[#687381]", children: "\u4EFB\u52A1" }), _jsx("strong", { className: "mt-1 block text-[17px] font-semibold text-[#30343b]", children: value(Array.isArray(data?.tasks) ? data.tasks.length : 0) })] }), _jsxs("div", { className: "rounded-lg bg-[#f6f8fa] px-3 py-2", children: [_jsx("span", { className: "block text-[10px] text-[#687381]", children: "\u672A\u8BFB\u6D88\u606F" }), _jsx("strong", { className: "mt-1 block text-[17px] font-semibold text-[#30343b]", children: value(Array.isArray(data?.messages)
466
+ ? data.messages.filter((message) => message !== null && typeof message === "object" && message.read !== true)
467
+ .length
468
+ : 0) })] }), _jsxs("div", { className: "rounded-lg bg-[#f6f8fa] px-3 py-2", children: [_jsx("span", { className: "block text-[10px] text-[#687381]", children: "\u53EF\u6267\u884C\u4EFB\u52A1" }), _jsx("strong", { className: "mt-1 block text-[17px] font-semibold text-[#30343b]", children: value(Array.isArray(data?.readyTasks) ? data.readyTasks.length : 0) })] })] }), Array.isArray(data?.dependencyCycle) && data.dependencyCycle.length > 1 ? (_jsxs("div", { className: "rounded-lg border border-[#f4caca] bg-[#fff5f5] px-3 py-2 text-[11px] text-[#b42318]", children: ["\u4F9D\u8D56\u5FAA\u73AF\uFF1A", data.dependencyCycle.map((item) => value(item)).join(" → ")] })) : null, _jsx("div", { className: "grid gap-2", children: Array.isArray(data?.members) && data.members.length > 0 ? (data.members.map((item, index) => {
469
+ const member = item !== null && typeof item === "object" ? item : {};
470
+ return (_jsxs("div", { className: "flex items-center gap-3 rounded-lg border border-[#edf0f3] px-3 py-2", children: [_jsx("span", { className: "h-2 w-2 rounded-full bg-[#22c55e]" }), _jsx("span", { className: "min-w-0 flex-1 truncate text-[11px] font-semibold text-[#30343b]", children: value(member.name ?? "成员") }), _jsx("span", { className: "text-[10px] text-[#687381]", children: value(member.role ?? "协作成员") }), _jsx("span", { className: "font-mono text-[10px] text-[#3565c5]", children: value(member.status ?? "idle") })] }, `${value(member.id ?? "member")}-${index}`));
471
+ })) : (_jsx("div", { className: "rounded-lg bg-[#f6f8fa] px-3 py-3 text-[12px] text-[#687381]", children: "\u6682\u65E0\u534F\u4F5C\u6210\u5458\u3002" })) }), _jsx("div", { className: "grid gap-2", children: Array.isArray(data?.tasks) && data.tasks.length > 0 ? (data.tasks.map((item, index) => {
472
+ const task = item !== null && typeof item === "object" ? item : {};
473
+ return (_jsxs("div", { className: "flex items-center gap-3 rounded-lg border border-[#edf0f3] px-3 py-2", children: [_jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("span", { className: "block truncate text-[11px] text-[#30343b]", children: value(task.title ?? "未命名任务") }), Array.isArray(task.dependsOn) && task.dependsOn.length > 0 ? (_jsxs("span", { className: "mt-0.5 block truncate font-mono text-[9px] text-[#687381]", children: ["\u4F9D\u8D56\uFF1A", task.dependsOn.join(", ")] })) : null] }), _jsx("span", { className: "text-[10px] text-[#687381]", children: value(task.assignee ?? "unassigned") }), _jsx("span", { className: `rounded-full px-2 py-1 text-[10px] ${task.status === "blocked" ? "bg-[#fff4e5] text-[#8a5a00]" : task.status === "done" ? "bg-[#e8f8ee] text-[#14733f]" : "bg-[#edf3fe] text-[#3565c5]"}`, children: value(task.status ?? "todo") })] }, `${value(task.id ?? "task")}-${index}`));
474
+ })) : (_jsx("div", { className: "rounded-lg bg-[#f6f8fa] px-3 py-3 text-[12px] text-[#687381]", children: "\u8FD8\u6CA1\u6709\u4EFB\u52A1\u3002\u53EF\u8BA9 Agent \u4F7F\u7528 team_task \u521B\u5EFA\u3002" })) }), _jsxs("div", { className: "grid gap-2", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("span", { className: "text-[11px] font-semibold text-[#30343b]", children: "\u56E2\u961F\u6D88\u606F" }), _jsx("span", { className: "font-mono text-[10px] text-[#687381]", children: "durable mailbox" })] }), Array.isArray(data?.messages) && data.messages.length > 0 ? (Array.from(data.messages)
475
+ .reverse()
476
+ .slice(0, 5)
477
+ .map((item, index) => {
478
+ const message = item !== null && typeof item === "object" ? item : {};
479
+ return (_jsxs("div", { className: `rounded-lg border px-3 py-2 ${message.read === true ? "border-[#edf0f3] bg-white" : "border-[#cfe0ff] bg-[#f4f8ff]"}`, children: [_jsxs("div", { className: "flex items-center gap-2 text-[10px] text-[#687381]", children: [_jsxs("span", { className: "font-mono text-[#3565c5]", children: [value(message.from ?? "unknown"), " \u2192 ", value(message.to ?? "unknown")] }), _jsx("span", { className: "ml-auto", children: message.read === true ? "已读" : "未读" })] }), _jsx("p", { className: "mt-1 whitespace-pre-wrap break-words text-[11px] text-[#30343b]", children: value(message.body ?? "") })] }, `${value(message.id ?? "message")}-${index}`));
480
+ })) : (_jsx("div", { className: "rounded-lg bg-[#f6f8fa] px-3 py-3 text-[12px] text-[#687381]", children: "\u6682\u65E0\u56E2\u961F\u6D88\u606F\u3002" }))] })] })) : panel.id === "modlens-panel" ? (_jsxs("div", { className: "mt-3 grid gap-3", children: [_jsxs("div", { className: `rounded-lg border px-3 py-3 ${data?.attached === true ? "border-[#b9e6c9] bg-[#f0fbf4]" : "border-[#e3e7ee] bg-[#f6f8fa]"}`, children: [_jsxs("div", { className: "flex items-center justify-between gap-3", children: [_jsx("span", { className: "text-[11px] font-semibold text-[#30343b]", children: data?.attached === true ? "图片已附加" : "等待图片" }), _jsx("span", { className: "font-mono text-[10px] text-[#687381]", children: "vision_inspect" })] }), data?.image !== null && data?.image !== undefined && typeof data.image === "object" ? (_jsxs("p", { className: "mt-2 truncate text-[11px] text-[#65707b]", children: [value(data.image.path ?? "图片"), " \u00B7 ", value(data.image.bytes ?? 0), " bytes"] })) : (_jsx("p", { className: "mt-2 text-[11px] text-[#687381]", children: "\u8C03\u7528 vision_inspect \u5E76\u63D0\u4F9B\u5DE5\u4F5C\u533A\u5185\u56FE\u7247\u8DEF\u5F84\u3002" }))] }), _jsx("div", { className: "flex flex-wrap gap-2", children: capabilities.map((capability, index) => (_jsx("span", { className: "rounded-md border border-[#dce5f5] bg-white px-2 py-1 font-mono text-[10px] text-[#3565c5]", children: value(capability) }, `${value(capability)}-${index}`))) })] })) : panel.id === "at-file-panel" ? (_jsxs("div", { className: "mt-3 grid gap-3", children: [_jsxs("div", { className: "rounded-lg border border-[#e3eaf8] bg-[#f6f8ff] px-3 py-3", children: [_jsxs("div", { className: "flex items-center justify-between gap-3", children: [_jsx("span", { className: "text-[11px] font-semibold text-[#30343b]", children: "\u6700\u8FD1\u9644\u52A0" }), _jsx("span", { className: "font-mono text-[10px] text-[#687381]", children: "file_context" })] }), data?.lastFile !== null && data?.lastFile !== undefined && typeof data.lastFile === "object" ? (_jsxs("p", { className: "mt-2 truncate text-[11px] text-[#65707b]", children: [value(data.lastFile.path ?? "文件"), " \u00B7 ", value(data.lastFile.bytes ?? 0), " bytes"] })) : (_jsx("p", { className: "mt-2 text-[11px] text-[#687381]", children: "\u8FD8\u6CA1\u6709\u9644\u52A0\u6587\u4EF6\u3002\u53EF\u4F7F\u7528 @file \u6216\u8BA9 Agent \u8C03\u7528 file_context\u3002" }))] }), _jsxs("div", { className: "flex items-center justify-between text-[11px] text-[#687381]", children: [_jsx("span", { children: "\u5355\u6587\u4EF6\u4E0A\u9650" }), _jsxs("strong", { className: "font-mono text-[#3565c5]", children: [value(data?.maxBytes ?? 0), " bytes"] })] })] })) : panel.id === "git-time-capsule-panel" ? (_jsxs("div", { className: "mt-3 grid gap-3", children: [_jsxs("div", { className: "rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3", children: [_jsxs("div", { className: "flex items-center justify-between gap-3", children: [_jsx("span", { className: "text-[11px] font-semibold text-[#30343b]", children: "\u6700\u8FD1\u5FEB\u7167" }), _jsx("span", { className: "font-mono text-[10px] text-[#687381]", children: "git_snapshot" })] }), data?.latest !== null && data?.latest !== undefined && typeof data.latest === "object" ? (_jsxs("p", { className: "mt-2 truncate text-[11px] text-[#65707b]", children: [value(data.latest.name ?? "snapshot"), " \u00B7 ", value(data.latest.files ?? 0), " \u4E2A\u6587\u4EF6", data.latest.restored === true ? " · 已恢复" : ""] })) : (_jsx("p", { className: "mt-2 text-[11px] text-[#687381]", children: "\u8FD8\u6CA1\u6709\u5FEB\u7167\u3002\u4FEE\u6539\u4EE3\u7801\u524D\u8BA9 Agent \u8C03\u7528 git_snapshot\u3002" }))] }), _jsxs("div", { className: "flex items-center justify-between text-[11px] text-[#687381]", children: [_jsx("span", { children: "\u4FDD\u7559\u5FEB\u7167" }), _jsxs("strong", { className: "font-mono text-[#3565c5]", children: [value(Array.isArray(data?.capsules) ? data.capsules.length : 0), " / 20"] })] }), _jsx("p", { className: "text-[10px] leading-4 text-[#687381]", children: "\u6062\u590D\u4F1A\u53CD\u5411\u5E94\u7528\u9009\u4E2D\u7684 patch\uFF0C\u5FC5\u987B\u663E\u5F0F\u4F20\u5165 confirm=true\u3002" })] })) : panel.id === "dependency-checker-panel" ? (_jsx("div", { className: "mt-3 grid gap-3", children: (() => {
481
+ const report = data?.report !== null && typeof data?.report === "object" ? data.report : {};
482
+ const missing = Array.isArray(report.missing) ? report.missing : [];
483
+ const invalid = Array.isArray(report.invalid) ? report.invalid : [];
484
+ const conflicts = Array.isArray(report.conflicts) ? report.conflicts : [];
485
+ return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex items-center justify-between rounded-lg border border-[#dce5f5] bg-[#f6f8ff] px-3 py-2 text-[10px]", children: [_jsx("span", { className: "text-[#65707b]", children: "\u6E05\u5355\u7C7B\u578B" }), _jsx("strong", { className: "font-mono uppercase text-[#315fb8]", children: value(report.ecosystem ?? "npm") })] }), _jsx("div", { className: "grid grid-cols-3 gap-2", children: [
486
+ ["声明", report.declared ?? 0],
487
+ ["已安装", report.installed ?? 0],
488
+ ["缺失", missing.length + invalid.length],
489
+ ].map(([label, item]) => (_jsxs("div", { className: "rounded-lg bg-[#f6f8fa] px-3 py-2", children: [_jsx("span", { className: "block text-[10px] text-[#687381]", children: value(label) }), _jsx("strong", { className: "mt-1 block text-[17px] font-semibold text-[#30343b]", children: value(item) })] }, value(label)))) }), _jsx("div", { className: `rounded-lg border px-3 py-3 text-[11px] ${missing.length || invalid.length || conflicts.length ? "border-[#f4caca] bg-[#fff5f5] text-[#b42318]" : "border-[#b9e6c9] bg-[#f0fbf4] text-[#14733f]"}`, children: missing.length || invalid.length
490
+ ? `缺失或无效:${[...missing, ...invalid].map((item) => value(item)).join(", ")}`
491
+ : "依赖声明与本地安装一致。" }), conflicts.length > 0 ? (_jsxs("div", { className: "rounded-lg border border-[#f3dfab] bg-[#fffaf0] px-3 py-3 text-[11px] text-[#8a6200]", children: [_jsx("strong", { children: "\u7248\u672C\u51B2\u7A81" }), _jsx("ul", { className: "mt-1 grid gap-1 pl-4", children: conflicts.slice(0, 6).map((item, index) => {
492
+ const conflict = item !== null && typeof item === "object" ? item : {};
493
+ const constraints = Array.isArray(conflict.constraints) ? conflict.constraints.map((constraint) => value(constraint)).join(" · ") : "—";
494
+ return (_jsxs("li", { children: [_jsx("code", { children: value(conflict.name ?? "dependency") }), "\uFF1A", constraints] }, `${value(conflict.name ?? "dependency")}-${index}`));
495
+ }) })] })) : null] }));
496
+ })() })) : panel.id === "token-guard-panel" ? (_jsx("div", { className: "mt-3 grid gap-3", children: _jsxs("div", { className: "grid gap-2 sm:grid-cols-2", children: [_jsxs("div", { className: `rounded-lg border px-3 py-3 ${data?.exceeded === true ? "border-[#f4caca] bg-[#fff5f5]" : "border-[#e3eaf8] bg-[#f6f8ff]"}`, children: [_jsxs("div", { className: "flex items-center justify-between gap-3", children: [_jsx("span", { className: "text-[11px] font-semibold text-[#30343b]", children: "\u4E0A\u4E0B\u6587\u9884\u7B97" }), _jsxs("strong", { className: "font-mono text-[12px] text-[#315fb8]", children: [value(data?.percent ?? "—"), "% / ", value(data?.maxPercent ?? "—"), "%"] })] }), _jsx("div", { className: "mt-2 h-2 overflow-hidden rounded-full bg-[#dfe8fb]", children: _jsx("div", { className: `h-full rounded-full ${data?.exceeded === true ? "bg-[#d64545]" : "bg-[#5d8bea]"}`, style: { width: `${Math.max(0, Math.min(100, typeof data?.percent === "number" ? data.percent : 0))}%` } }) }), _jsx("p", { className: "mt-2 text-[11px] text-[#5d6d82]", children: data?.exceeded === true ? "已达到阈值,运行会被自动停止。" : `自动停止次数:${value(data?.aborts ?? 0)}` })] }), _jsxs("div", { className: `rounded-lg border px-3 py-3 ${data?.runExceeded === true ? "border-[#f4caca] bg-[#fff5f5]" : "border-[#e3eaf8] bg-[#f6f8ff]"}`, children: [_jsxs("div", { className: "flex items-center justify-between gap-3", children: [_jsx("span", { className: "text-[11px] font-semibold text-[#30343b]", children: "\u5355\u6B21\u4EFB\u52A1" }), _jsxs("strong", { className: "font-mono text-[12px] text-[#315fb8]", children: [value(data?.runTokens ?? "—"), " / ", value(data?.maxRunTokens || "—")] })] }), _jsx("p", { className: "mt-2 text-[11px] text-[#5d6d82]", children: data?.maxRunTokens ? "按 agent_start 后累计 token 熔断。" : "未启用绝对 Token 上限。" })] })] }) })) : panel.id === "test-harness-panel" ? (_jsxs("div", { className: "mt-3 grid gap-3", children: [data?.latest !== null && data?.latest !== undefined && typeof data.latest === "object" ? ((() => {
497
+ const run = data.latest;
498
+ return (_jsxs("div", { className: `rounded-lg border px-3 py-3 ${run.exitCode === 0 ? "border-[#b9e6c9] bg-[#f0fbf4]" : "border-[#f4caca] bg-[#fff5f5]"}`, children: [_jsxs("div", { className: "flex items-center justify-between gap-3", children: [_jsx("span", { className: "font-mono text-[11px] font-semibold text-[#30343b]", children: value(run.command ?? "npm run test") }), _jsxs("strong", { className: `text-[12px] ${run.exitCode === 0 ? "text-[#14733f]" : "text-[#b42318]"}`, children: ["exit ", value(run.exitCode ?? "—")] })] }), _jsxs("p", { className: "mt-2 text-[11px] text-[#65707b]", children: ["\u8017\u65F6 ", value(run.durationMs ?? 0), " ms"] })] }));
499
+ })()) : (_jsx("div", { className: "rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3 text-[11px] text-[#687381]", children: "\u8FD8\u6CA1\u6709\u6267\u884C\u9A8C\u8BC1\u811A\u672C\u3002\u53EF\u8BA9 Agent \u8C03\u7528 run_project_tests\u3002" })), _jsx("div", { className: "flex flex-wrap gap-2", children: Array.isArray(data?.allowedScripts)
500
+ ? data.allowedScripts.map((script, index) => (_jsx("span", { className: "rounded-md border border-[#dce5f5] bg-white px-2 py-1 font-mono text-[10px] text-[#3565c5]", children: value(script) }, `${value(script)}-${index}`)))
501
+ : null })] })) : panel.id === "session-insights-panel" ? (_jsx("div", { className: "mt-3 grid gap-3", children: (() => {
502
+ const tokens = data?.tokens !== null && typeof data?.tokens === "object" ? data.tokens : {};
503
+ const usage = data?.contextUsage !== null && typeof data?.contextUsage === "object" ? data.contextUsage : {};
504
+ return (_jsxs(_Fragment, { children: [_jsx("div", { className: "grid grid-cols-3 gap-2", children: [
505
+ ["消息", data?.totalMessages ?? 0],
506
+ ["工具调用", data?.toolCalls ?? 0],
507
+ ["成本", `$${Number(data?.cost ?? 0).toFixed(4)}`],
508
+ ].map(([label, item]) => (_jsxs("div", { className: "rounded-lg bg-[#f6f8fa] px-3 py-2", children: [_jsx("span", { className: "block text-[10px] text-[#687381]", children: value(label) }), _jsx("strong", { className: "mt-1 block text-[17px] font-semibold text-[#30343b]", children: value(item) })] }, value(label)))) }), _jsxs("div", { className: "rounded-lg border border-[#e3eaf8] bg-[#f6f8ff] px-3 py-3", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("span", { className: "text-[11px] font-semibold text-[#30343b]", children: "\u4E0A\u4E0B\u6587" }), _jsxs("strong", { className: "font-mono text-[12px] text-[#315fb8]", children: [value(usage.percent ?? "—"), "%"] })] }), _jsxs("p", { className: "mt-2 text-[11px] text-[#5d6d82]", children: [value(tokens.total ?? 0), " tracked tokens \u00B7 \u8F93\u5165 ", value(tokens.input ?? 0), " \u00B7 \u8F93\u51FA ", value(tokens.output ?? 0)] })] })] }));
509
+ })() })) : panel.id === "session-bridge-panel" ? (_jsx("div", { className: "mt-3 grid gap-3", children: (() => {
510
+ const latestPreview = data?.latestPreview !== null && typeof data?.latestPreview === "object"
511
+ ? data.latestPreview.preview
512
+ : undefined;
513
+ const preview = latestPreview ??
514
+ (data?.currentPreview !== null && typeof data?.currentPreview === "object" ? data.currentPreview : {});
515
+ const sections = [
516
+ ["目标", preview.goal],
517
+ ["当前状态", preview.currentState],
518
+ ["下一步", preview.nextStep],
519
+ ];
520
+ return (_jsxs(_Fragment, { children: [_jsx("div", { className: "rounded-lg border border-[#dce5f5] bg-[#f6f8ff] px-3 py-3 text-[11px] leading-5 text-[#315fb8]", children: "\u9884\u89C8\u4E0D\u4F1A\u521B\u5EFA\u76EE\u6807\u4F1A\u8BDD\uFF0C\u4E5F\u4E0D\u4F1A\u4FEE\u6539\u6E90\u4F1A\u8BDD\u3002" }), sections.map(([label, item]) => (_jsxs("div", { className: "rounded-lg border border-[#e3e7ee] bg-white px-3 py-3", children: [_jsx("span", { className: "block text-[10px] font-semibold uppercase tracking-[0.08em] text-[#687381]", children: label }), _jsx("p", { className: "mt-2 whitespace-pre-wrap text-[11px] leading-5 text-[#30343b]", children: value(item) })] }, label))), _jsx("div", { className: "grid gap-2 sm:grid-cols-2", children: [
521
+ ["关键决策", preview.decisions],
522
+ ["关键文件", preview.keyFiles],
523
+ ].map(([label, items]) => (_jsxs("div", { className: "rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3", children: [_jsx("span", { className: "block text-[10px] font-semibold uppercase tracking-[0.08em] text-[#687381]", children: value(label) }), Array.isArray(items) && items.length > 0 ? (_jsx("ul", { className: "mt-2 grid gap-1 text-[10px] leading-4 text-[#65707b]", children: items.slice(0, 8).map((item, index) => (_jsx("li", { children: value(item) }, `${value(item)}-${index}`))) })) : (_jsx("p", { className: "mt-2 text-[10px] text-[#687381]", children: "\u6682\u65E0" }))] }, value(label)))) })] }));
524
+ })() })) : panel.id === "session-compare-panel" ? (_jsx("div", { className: "mt-3 grid gap-3", children: data?.left && typeof data.left === "object" && data?.right && typeof data.right === "object" ? ((() => {
525
+ const left = data.left;
526
+ const right = data.right;
527
+ return (_jsxs(_Fragment, { children: [_jsx("div", { className: "grid gap-2 sm:grid-cols-2", children: [
528
+ ["左侧会话", left],
529
+ ["右侧会话", right],
530
+ ].map(([label, session]) => {
531
+ const item = session;
532
+ return (_jsxs("div", { className: "rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3", children: [_jsx("span", { className: "block text-[10px] font-semibold uppercase tracking-[0.08em] text-[#687381]", children: value(label) }), _jsx("strong", { className: "mt-2 block truncate text-[12px] text-[#30343b]", children: value(item.name ?? item.id) }), _jsx("code", { className: "mt-1 block truncate text-[10px] text-[#315fb8]", children: value(item.id) }), _jsxs("span", { className: "mt-1 block text-[10px] text-[#65707b]", children: [value(item.messageCount, "0"), " \u6761\u6D88\u606F"] })] }, value(label)));
533
+ }) }), _jsx("div", { className: "grid grid-cols-3 gap-2", children: [
534
+ ["共享", data.shared ?? 0],
535
+ ["右侧新增", Array.isArray(data.added) ? data.added.length : 0],
536
+ ["左侧删除", Array.isArray(data.removed) ? data.removed.length : 0],
537
+ ].map(([label, item]) => (_jsxs("div", { className: "rounded-lg bg-[#f6f8fa] px-3 py-2", children: [_jsx("span", { className: "block text-[10px] text-[#687381]", children: value(label) }), _jsx("strong", { className: "mt-1 block text-[17px] font-semibold text-[#30343b]", children: value(item) })] }, value(label)))) }), _jsx("div", { className: `rounded-lg border px-3 py-3 text-[11px] ${data.changed === true ? "border-[#f4d8a8] bg-[#fff9ed] text-[#9a6700]" : "border-[#b9e6c9] bg-[#f0fbf4] text-[#14733f]"}`, children: data.changed === true ? "两个会话存在消息差异。" : "两个会话内容一致。" }), Array.isArray(data.added) && data.added.length > 0 ? (_jsxs("div", { className: "rounded-lg border border-[#dce5f5] bg-[#f6f8ff] px-3 py-3", children: [_jsx("span", { className: "block text-[10px] font-semibold uppercase tracking-[0.08em] text-[#687381]", children: "\u53F3\u4FA7\u65B0\u589E\u6D88\u606F" }), _jsx("ul", { className: "mt-2 grid gap-1 text-[10px] leading-4 text-[#65707b]", children: data.added.slice(0, 4).map((item, index) => {
538
+ const message = item !== null && typeof item === "object" ? item : {};
539
+ return (_jsxs("li", { children: ["[", value(message.role), "] ", value(message.text)] }, `${value(message.role)}-${index}`));
540
+ }) })] })) : null] }));
541
+ })()) : (_jsx("div", { className: "rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3 text-[11px] text-[#687381]", children: "\u6267\u884C session_compare \u540E\u663E\u793A\u4E24\u4E2A\u4F1A\u8BDD\u7684\u5DEE\u5F02\u3002" })) })) : panel.id === "secure-audit-panel" ? (_jsxs("div", { className: "mt-3 grid gap-3", children: [_jsx("div", { className: "grid grid-cols-4 gap-2", children: [
542
+ ["扫描文件", data?.scanned ?? 0],
543
+ ["严重", data?.critical ?? 0],
544
+ ["高风险", data?.high ?? 0],
545
+ ["总发现", data?.total ?? 0],
546
+ ].map(([label, item]) => (_jsxs("div", { className: "rounded-lg bg-[#f6f8fa] px-2 py-2 text-center", children: [_jsx("span", { className: "block text-[10px] text-[#687381]", children: value(label) }), _jsx("strong", { className: "mt-1 block text-[16px] font-semibold text-[#30343b]", children: value(item) })] }, value(label)))) }), _jsx("div", { className: `rounded-lg border px-3 py-3 text-[11px] ${Number(data?.total ?? 0) > 0 ? "border-[#f4d8a8] bg-[#fff9ed] text-[#9a6700]" : "border-[#b9e6c9] bg-[#f0fbf4] text-[#14733f]"}`, children: Number(data?.total ?? 0) > 0 ? "发现需要人工确认的安全风险。" : "未发现凭据泄露或危险命令。" }), Array.isArray(data?.findings) && data.findings.length > 0 ? (_jsx("div", { className: "grid gap-2", children: data.findings.slice(0, 6).map((item, index) => {
547
+ const finding = item !== null && typeof item === "object" ? item : {};
548
+ const severity = value(finding.severity, "medium");
549
+ return (_jsxs("div", { className: "rounded-lg border border-[#edf0f3] bg-white px-3 py-2", children: [_jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsx("code", { className: "min-w-0 truncate text-[10px] text-[#315fb8]", children: value(finding.path) }), _jsx("span", { className: `shrink-0 text-[10px] font-semibold ${severity === "critical" ? "text-[#b42318]" : "text-[#9a6700]"}`, children: severity })] }), _jsxs("p", { className: "mt-1 text-[10px] leading-4 text-[#65707b]", children: ["\u7B2C ", value(finding.line), " \u884C \u00B7 ", value(finding.message)] })] }, `${value(finding.path)}-${value(finding.line)}-${index}`));
550
+ }) })) : (_jsx("div", { className: "rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3 text-[11px] text-[#687381]", children: "\u8FD0\u884C security_audit \u540E\u663E\u793A\u8131\u654F\u7ED3\u679C\u3002" }))] })) : panel.id === "context-doctor-panel" ? (_jsxs("div", { className: "mt-3 grid gap-3", children: [_jsx("div", { className: `rounded-lg border px-3 py-3 text-[11px] ${data?.status === "warning" ? "border-[#f4caca] bg-[#fff5f5] text-[#b42318]" : "border-[#b9e6c9] bg-[#f0fbf4] text-[#14733f]"}`, children: data?.status === "warning" ? "需要关注上下文风险。" : "上下文状态正常。" }), _jsx("div", { className: "grid grid-cols-3 gap-2", children: [
551
+ ["占用", `${value(data?.usagePercent ?? "—")}%`],
552
+ ["超大消息", data?.oversizedMessages ?? 0],
553
+ ["工具错误", data?.toolErrors ?? 0],
554
+ ].map(([label, item]) => (_jsxs("div", { className: "rounded-lg bg-[#f6f8fa] px-3 py-2", children: [_jsx("span", { className: "block text-[10px] text-[#687381]", children: value(label) }), _jsx("strong", { className: "mt-1 block text-[17px] text-[#30343b]", children: value(item) })] }, value(label)))) }), Array.isArray(data?.recommendations) && data.recommendations.length > 0 ? (_jsx("ul", { className: "grid gap-1 rounded-lg border border-[#e3e7ee] bg-white px-4 py-3 text-[10px] text-[#65707b]", children: data.recommendations.slice(0, 4).map((item, index) => (_jsx("li", { children: value(item) }, `${value(item)}-${index}`))) })) : null] })) : panel.id === "history-compressor-panel" ? (_jsxs("div", { className: "mt-3 grid gap-3", children: [_jsxs("div", { className: "flex items-center justify-between rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3", children: [_jsx("span", { className: "font-mono text-[11px] text-[#30343b]", children: data?.enabled === true ? "自动压缩已启用" : "自动压缩已停用" }), _jsxs("strong", { className: "font-mono text-[11px] text-[#3565c5]", children: ["\u9608\u503C ", value(data?.thresholdPercent ?? "—"), "%"] })] }), _jsxs("div", { className: "grid grid-cols-2 gap-2", children: [_jsxs("div", { className: "rounded-lg bg-[#f6f8fa] px-3 py-2", children: [_jsx("span", { className: "block text-[10px] text-[#687381]", children: "\u5DF2\u538B\u7F29" }), _jsx("strong", { className: "mt-1 block text-[17px] text-[#30343b]", children: value(data?.compactions ?? 0) })] }), _jsxs("div", { className: "rounded-lg bg-[#f6f8fa] px-3 py-2", children: [_jsx("span", { className: "block text-[10px] text-[#687381]", children: "\u5F53\u524D\u5360\u7528" }), _jsxs("strong", { className: "mt-1 block text-[17px] text-[#30343b]", children: [value(data?.lastUsagePercent ?? "—"), "%"] })] })] }), data?.lastError ? _jsxs("p", { className: "text-[11px] text-[#b42318]", children: ["\u6700\u8FD1\u9519\u8BEF\uFF1A", value(data.lastError)] }) : null] })) : panel.id === "session-export-panel" ? (_jsxs("div", { className: "mt-3 grid gap-3", children: [data?.latest && typeof data.latest === "object" ? ((() => {
555
+ const latest = data.latest;
556
+ return (_jsxs("div", { className: "rounded-lg border border-[#dce5f5] bg-[#f6f8ff] px-3 py-3", children: [_jsx("span", { className: "block text-[10px] font-semibold uppercase tracking-[0.08em] text-[#687381]", children: "\u6700\u8FD1\u5BFC\u51FA" }), _jsx("code", { className: "mt-2 block truncate text-[11px] text-[#315fb8]", children: value(latest.path ?? "pi-session.md") }), _jsxs("p", { className: "mt-1 text-[10px] text-[#65707b]", children: [value(latest.messages ?? 0), " \u6761\u6D88\u606F \u00B7 ", value(latest.bytes ?? 0), " bytes"] })] }));
557
+ })()) : (_jsx("div", { className: "rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3 text-[11px] text-[#687381]", children: "\u8FD8\u6CA1\u6709\u5BFC\u51FA\u5F53\u524D\u4F1A\u8BDD\u3002" })), _jsx("p", { className: "text-[10px] leading-4 text-[#687381]", children: "\u5BFC\u51FA\u6587\u4EF6\u53EA\u5141\u8BB8\u5199\u5165\u5F53\u524D\u5DE5\u4F5C\u533A\u5185\u7684 .md \u8DEF\u5F84\uFF0C\u8986\u76D6\u5DF2\u6709\u6587\u4EF6\u9700\u8981\u663E\u5F0F\u786E\u8BA4\u3002" })] })) : panel.id === "session-search-panel" ? (_jsxs("div", { className: "mt-3 grid gap-3", children: [data?.query ? (_jsxs("div", { className: "flex items-center justify-between rounded-lg border border-[#dce5f5] bg-[#f6f8ff] px-3 py-3", children: [_jsx("code", { className: "min-w-0 truncate text-[11px] text-[#315fb8]", children: value(data.query) }), _jsxs("strong", { className: "ml-3 shrink-0 text-[11px] text-[#3565c5]", children: [value(data.total ?? 0), " \u4E2A\u4F1A\u8BDD"] })] })) : (_jsx("div", { className: "rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3 text-[11px] text-[#687381]", children: "\u8F93\u5165\u67E5\u8BE2\u540E\u663E\u793A\u5339\u914D\u7684\u5386\u53F2\u4F1A\u8BDD\u3002" })), Array.isArray(data?.items) && data.items.length > 0 ? (_jsx("div", { className: "grid gap-2", children: data.items.slice(0, 8).map((item, index) => {
558
+ const session = item !== null && typeof item === "object" ? item : {};
559
+ const hits = Array.isArray(session.hits) ? session.hits : [];
560
+ return (_jsxs("div", { className: "rounded-lg border border-[#edf0f3] bg-white px-3 py-2", children: [_jsx("strong", { className: "block truncate text-[11px] text-[#30343b]", children: value(session.name ?? session.id ?? "未命名会话") }), _jsx("p", { className: "mt-1 line-clamp-2 text-[10px] leading-4 text-[#65707b]", children: hits
561
+ .map((hit) => (hit !== null && typeof hit === "object" ? value(hit.text ?? "") : value(hit)))
562
+ .join(" | ") })] }, `${value(session.id ?? "session")}-${index}`));
563
+ }) })) : data?.query ? (_jsx("div", { className: "rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3 text-[11px] text-[#687381]", children: "\u6CA1\u6709\u627E\u5230\u5339\u914D\u7684\u5386\u53F2\u4F1A\u8BDD\u3002" })) : null] })) : panel.id === "session-bookmarks-panel" ? (_jsxs("div", { className: "mt-3 grid gap-3", children: [_jsxs("div", { className: "flex items-center justify-between rounded-lg border border-[#dce5f5] bg-[#f6f8ff] px-3 py-3", children: [_jsx("span", { className: "text-[11px] text-[#65707b]", children: "\u5F53\u524D\u4F1A\u8BDD\u7684\u6301\u4E45\u5316\u4E66\u7B7E" }), _jsxs("strong", { className: "font-mono text-[11px] text-[#3565c5]", children: [value(data?.total ?? 0), " \u4E2A\u4E66\u7B7E"] })] }), Array.isArray(data?.bookmarks) && data.bookmarks.length > 0 ? (_jsx("div", { className: "grid gap-2", children: data.bookmarks.slice(0, 12).map((item, index) => {
564
+ const bookmark = item !== null && typeof item === "object" ? item : {};
565
+ return (_jsxs("div", { className: "rounded-lg border border-[#edf0f3] bg-white px-3 py-2", children: [_jsx("strong", { className: "block truncate text-[11px] text-[#30343b]", children: value(bookmark.label ?? "未命名书签") }), _jsxs("code", { className: "mt-1 block truncate text-[10px] text-[#687381]", children: ["entry: ", value(bookmark.entryId ?? "—")] })] }, `${value(bookmark.id ?? "bookmark")}-${index}`));
566
+ }) })) : (_jsx("div", { className: "rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3 text-[11px] text-[#687381]", children: "\u8FD8\u6CA1\u6709\u6807\u8BB0\u91CD\u8981\u8282\u70B9\u3002" })), _jsx("p", { className: "text-[10px] leading-4 text-[#687381]", children: "\u4E66\u7B7E\u72EC\u7ACB\u4FDD\u5B58\u5728 agent \u76EE\u5F55\uFF0C\u4E0D\u4F1A\u6539\u5199 Pi \u539F\u751F\u4F1A\u8BDD\u8BB0\u5F55\u3002" })] })) : panel.id === "llm-verifier-panel" ? (_jsxs("div", { className: "mt-3 grid gap-3", children: [_jsxs("div", { className: "flex items-center justify-between rounded-lg border border-[#dce5f5] bg-[#f6f8ff] px-3 py-3", children: [_jsx("span", { className: "text-[11px] text-[#65707b]", children: "\u6821\u9A8C\u6A21\u578B" }), _jsxs("code", { className: "max-w-[65%] truncate text-[11px] text-[#315fb8]", children: [value(data?.provider ?? "—"), "/", value(data?.model ?? "—")] })] }), data?.history && typeof data.history === "object"
567
+ ? (() => {
568
+ const history = data.history;
569
+ const counts = history.counts && typeof history.counts === "object" ? history.counts : {};
570
+ return (_jsxs("div", { className: "grid grid-cols-4 gap-2", children: [_jsxs("div", { className: "rounded-lg bg-[#f6f8fa] px-2 py-2 text-center", children: [_jsx("span", { className: "block text-[10px] text-[#687381]", children: "\u7D2F\u8BA1" }), _jsx("strong", { className: "mt-1 block text-[15px] text-[#30343b]", children: value(history.total ?? 0) })] }), _jsxs("div", { className: "rounded-lg bg-[#f0fbf4] px-2 py-2 text-center", children: [_jsx("span", { className: "block text-[10px] text-[#14733f]", children: "\u901A\u8FC7" }), _jsx("strong", { className: "mt-1 block text-[15px] text-[#14733f]", children: value(counts.pass ?? 0) })] }), _jsxs("div", { className: "rounded-lg bg-[#fff5f5] px-2 py-2 text-center", children: [_jsx("span", { className: "block text-[10px] text-[#b42318]", children: "\u5931\u8D25" }), _jsx("strong", { className: "mt-1 block text-[15px] text-[#b42318]", children: value(counts.fail ?? 0) })] }), _jsxs("div", { className: "rounded-lg bg-[#fffaf0] px-2 py-2 text-center", children: [_jsx("span", { className: "block text-[10px] text-[#9a6700]", children: "\u672A\u77E5" }), _jsx("strong", { className: "mt-1 block text-[15px] text-[#9a6700]", children: value(counts.unknown ?? 0) })] })] }));
571
+ })()
572
+ : null, data?.latest && typeof data.latest === "object" ? ((() => {
573
+ const latest = data.latest;
574
+ const verdict = value(latest.verdict ?? "unknown");
575
+ return (_jsxs("div", { className: `rounded-lg border px-3 py-3 text-[11px] ${verdict === "pass" ? "border-[#b9e6c9] bg-[#f0fbf4] text-[#14733f]" : verdict === "fail" ? "border-[#f4caca] bg-[#fff5f5] text-[#b42318]" : "border-[#f3dfab] bg-[#fffaf0] text-[#9a6700]"}`, children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("strong", { className: "uppercase", children: verdict }), _jsxs("span", { className: "font-mono text-[10px]", children: [value(latest.evidenceChars ?? 0), " chars"] })] }), _jsx("p", { className: "mt-2 leading-4", children: value(latest.rationale ?? "没有返回校验理由。") }), _jsxs("p", { className: "mt-2 truncate text-[10px] opacity-70", children: ["\u58F0\u660E\uFF1A", value(latest.claim ?? "—")] })] }));
576
+ })()) : (_jsx("div", { className: "rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3 text-[11px] text-[#687381]", children: "\u8FD8\u6CA1\u6709\u6267\u884C\u6A21\u578B\u6821\u9A8C\u3002" })), _jsx("p", { className: "text-[10px] leading-4 text-[#687381]", children: "\u8BC1\u636E\u6309\u4E0D\u53EF\u4FE1\u6570\u636E\u5904\u7406\uFF0C\u8F93\u5165\u6709\u957F\u5EA6\u4E0A\u9650\uFF1B\u6A21\u578B\u8FD4\u56DE\u975E\u7ED3\u6784\u5316\u7ED3\u679C\u65F6\u663E\u793A unknown\u3002" })] })) : panel.id === "module-search-panel" ? (_jsx("div", { className: "mt-3 grid gap-3", children: data?.latest && typeof data.latest === "object" ? ((() => {
577
+ const latest = data.latest;
578
+ const matches = Array.isArray(latest.matches) ? latest.matches : [];
579
+ return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex items-center justify-between rounded-lg border border-[#dce5f5] bg-[#f6f8ff] px-3 py-3", children: [_jsx("code", { className: "min-w-0 truncate text-[11px] text-[#315fb8]", children: value(latest.query ?? "") }), _jsxs("strong", { className: "ml-3 shrink-0 text-[11px] text-[#3565c5]", children: [value(matches.length), " \u4E2A\u7ED3\u679C"] })] }), matches.length > 0 ? (_jsx("div", { className: "grid gap-2", children: matches.slice(0, 10).map((item, index) => {
580
+ const match = item !== null && typeof item === "object" ? item : {};
581
+ return (_jsxs("div", { className: "rounded-lg border border-[#edf0f3] bg-white px-3 py-2", children: [_jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsxs("code", { className: "min-w-0 truncate text-[10px] text-[#315fb8]", children: [value(match.path ?? "—"), ":", value(match.line ?? "—")] }), _jsx("span", { className: "shrink-0 text-[10px] uppercase text-[#687381]", children: value(match.kind ?? "symbol") })] }), _jsx("p", { className: "mt-1 truncate text-[10px] text-[#65707b]", children: value(match.name ?? "未命名符号") })] }, `${value(match.path ?? "module")}:${value(match.line ?? index)}`));
582
+ }) })) : (_jsx("div", { className: "rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3 text-[11px] text-[#687381]", children: "\u6CA1\u6709\u627E\u5230\u5339\u914D\u7684\u6A21\u5757\u7B26\u53F7\u3002" })), _jsxs("p", { className: "text-[10px] leading-4 text-[#687381]", children: ["\u626B\u63CF ", value(latest.scannedFiles ?? 0), " \u4E2A\u6E90\u7801\u6587\u4EF6\uFF0C\u8DF3\u8FC7\u4F9D\u8D56\u548C\u6784\u5EFA\u76EE\u5F55\u3002"] })] }));
583
+ })()) : (_jsx("div", { className: "rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3 text-[11px] text-[#687381]", children: "\u8F93\u5165\u7B26\u53F7\u540D\u540E\u663E\u793A\u6A21\u5757\u68C0\u7D22\u7ED3\u679C\u3002" })) })) : panel.id === "better-sidebar-panel" ? ((() => {
584
+ const changedFiles = Array.isArray(data?.changedFiles) ? data.changedFiles : [];
585
+ const clean = data?.clean === true;
586
+ return (_jsxs("div", { className: "mt-3 grid gap-3", children: [_jsxs("div", { className: "rounded-lg border border-[#dce5f5] bg-[#f6f8ff] px-3 py-3", children: [_jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsx("code", { className: "min-w-0 truncate text-[11px] text-[#315fb8]", children: value(data?.cwd ?? "当前工作区") }), _jsx("span", { className: `shrink-0 rounded px-1.5 py-0.5 font-mono text-[10px] ${clean ? "bg-[#eaf8f0] text-[#14733f]" : "bg-[#fff0f0] text-[#b42318]"}`, children: clean ? "clean" : `${value(data?.changedCount ?? changedFiles.length)} 个变更` })] }), _jsx("p", { className: "mt-2 font-mono text-[10px] text-[#65707b]", children: value(data?.summary ?? "等待工作区扫描") }), _jsxs("p", { className: "mt-1 text-[10px] text-[#687381]", children: ["\u4F1A\u8BDD ", value(data?.sessionId ?? "—"), " \u00B7 \u76EE\u5F55 ", value(data?.directoryCount ?? 0), " \u00B7 \u6587\u4EF6 ", value(data?.fileCount ?? 0)] })] }), changedFiles.length > 0 ? (_jsx("div", { className: "grid gap-1 rounded-lg border border-[#edf0f3] bg-white px-3 py-2", children: changedFiles.slice(0, 8).map((item, index) => {
587
+ const entry = item !== null && typeof item === "object" ? item : {};
588
+ return (_jsxs("code", { className: "truncate py-0.5 text-[10px] text-[#65707b]", children: [value(entry.status ?? "??"), " ", value(entry.path ?? "未命名")] }, `${value(entry.path ?? "file")}-${index}`));
589
+ }) })) : null, data?.truncated === true ? _jsx("p", { className: "text-[10px] text-[#687381]", children: "\u76EE\u5F55\u6458\u8981\u5DF2\u622A\u65AD\uFF0C\u6267\u884C sidebar_overview \u83B7\u53D6\u6700\u65B0\u6982\u89C8\u3002" }) : null] }));
590
+ })()) : panel.id === "workspace-navigator-panel" ? (_jsx("div", { className: "mt-3 grid gap-3", children: data?.latest && typeof data.latest === "object" ? ((() => {
591
+ const latest = data.latest;
592
+ const nodes = Array.isArray(latest.nodes) ? latest.nodes : [];
593
+ return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex items-center justify-between rounded-lg border border-[#dce5f5] bg-[#f6f8ff] px-3 py-3", children: [_jsx("code", { className: "min-w-0 truncate text-[11px] text-[#315fb8]", children: value(latest.path ?? ".") }), _jsxs("strong", { className: "ml-3 shrink-0 text-[11px] text-[#3565c5]", children: [value(nodes.length), " \u4E2A\u8282\u70B9"] })] }), nodes.length > 0 ? (_jsx("div", { className: "grid gap-1 rounded-lg border border-[#edf0f3] bg-white px-3 py-2", children: nodes.slice(0, 36).map((item, index) => {
594
+ const node = item !== null && typeof item === "object" ? item : {};
595
+ const depth = typeof node.depth === "number" ? Math.min(6, Math.max(1, node.depth)) : 1;
596
+ return (_jsxs("div", { className: "flex items-center gap-2 truncate py-1 text-[10px] text-[#65707b]", children: [_jsxs("span", { className: "shrink-0 text-[#687381]", children: ["· ".repeat(depth - 1), node.kind === "directory" ? "▾" : "·"] }), _jsx("code", { className: "truncate", children: value(node.name ?? node.path ?? "未命名") })] }, `${value(node.path ?? "node")}-${index}`));
597
+ }) })) : (_jsx("div", { className: "rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3 text-[11px] text-[#687381]", children: "\u5F53\u524D\u76EE\u5F55\u4E3A\u7A7A\u3002" })), _jsxs("p", { className: "text-[10px] leading-4 text-[#687381]", children: ["\u76EE\u5F55 ", value(latest.directoryCount ?? 0), " \u4E2A\uFF0C\u6587\u4EF6 ", value(latest.fileCount ?? 0), " \u4E2A\uFF1B\u8DF3\u8FC7\u4F9D\u8D56\u548C\u6784\u5EFA\u76EE\u5F55\u3002"] }), data?.git && typeof data.git === "object"
598
+ ? (() => {
599
+ const git = data.git;
600
+ const entries = Array.isArray(git.entries) ? git.entries : [];
601
+ const available = git.available === true;
602
+ return (_jsxs("div", { className: "rounded-lg border border-[#e3e7ee] bg-white px-3 py-3", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("span", { className: "text-[11px] font-medium text-[#253044]", children: "Git \u72B6\u6001" }), _jsx("span", { className: `text-[10px] ${!available ? "text-[#687381]" : git.clean === true ? "text-[#14733f]" : "text-[#b42318]"}`, children: !available ? "不可用" : git.clean === true ? "clean" : `${entries.length} 个变更` })] }), available ? _jsx("p", { className: "mt-1 font-mono text-[10px] text-[#65707b]", children: value(git.branch ?? "detached HEAD") }) : null, entries.length > 0 ? (_jsx("div", { className: "mt-2 grid gap-1", children: entries.slice(0, 12).map((item, index) => {
603
+ const entry = item !== null && typeof item === "object" ? item : {};
604
+ return (_jsxs("code", { className: "truncate text-[10px] text-[#65707b]", children: [value(entry.status ?? "??"), " ", value(entry.path ?? "未命名")] }, `${value(entry.path ?? "file")}-${index}`));
605
+ }) })) : null] }));
606
+ })()
607
+ : null] }));
608
+ })()) : (_jsx("div", { className: "rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3 text-[11px] text-[#687381]", children: "\u6267\u884C workspace_tree \u540E\u663E\u793A\u5DE5\u4F5C\u533A\u7ED3\u6784\u3002" })) })) : panel.id === "prompt-library-panel" ? (_jsxs("div", { className: "mt-3 grid gap-3", children: [Array.isArray(data?.templates) && data.templates.length > 0 ? (_jsx("div", { className: "grid gap-2", children: data.templates.slice(0, 12).map((item, index) => {
609
+ const template = item !== null && typeof item === "object" ? item : {};
610
+ const tags = Array.isArray(template.tags) ? template.tags.filter((tag) => typeof tag === "string") : [];
611
+ return (_jsxs("div", { className: "rounded-lg border border-[#e3e7ee] bg-white px-3 py-3", children: [_jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsx("strong", { className: "truncate text-[11px] text-[#253044]", children: value(template.title ?? "未命名提示词") }), _jsx("code", { className: "shrink-0 text-[10px] text-[#687381]", children: value(template.id ?? "—") })] }), _jsx("p", { className: "mt-2 line-clamp-2 text-[10px] leading-4 text-[#65707b]", children: value(template.prompt ?? "") }), tags.length > 0 ? (_jsx("div", { className: "mt-2 flex flex-wrap gap-1", children: tags.slice(0, 6).map((tag) => (_jsx("span", { className: "rounded bg-[#f6f8ff] px-1.5 py-0.5 text-[9px] text-[#315fb8]", children: tag }, tag))) })) : null] }, `${value(template.id ?? "prompt")}-${index}`));
612
+ }) })) : (_jsx("div", { className: "rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3 text-[11px] text-[#687381]", children: "\u8FD8\u6CA1\u6709\u4FDD\u5B58\u7684\u63D0\u793A\u8BCD\u3002\u53EF\u8BA9 Agent \u8C03\u7528 prompt_library \u4FDD\u5B58\u6A21\u677F\u3002" })), _jsxs("p", { className: "text-[10px] leading-4 text-[#687381]", children: ["\u5171 ", value(data?.total ?? 0), " \u4E2A\u6A21\u677F\uFF0C\u6570\u636E\u8DDF\u968F\u5F53\u524D\u4F1A\u8BDD\u3002"] })] })) : panel.id === "colleague-skill-panel" ? (_jsx("div", { className: "mt-3 grid gap-3", children: data?.latest && typeof data.latest === "object" ? ((() => {
613
+ const handoff = data.latest;
614
+ const list = (key) => Array.isArray(handoff[key]) ? handoff[key].filter((item) => typeof item === "string") : [];
615
+ const constraints = list("constraints");
616
+ const files = list("files");
617
+ const acceptance = list("acceptance");
618
+ return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex items-center justify-between rounded-lg border border-[#dce5f5] bg-[#f6f8ff] px-3 py-3", children: [_jsx("span", { className: "text-[11px] text-[#65707b]", children: "\u4EA4\u63A5\u7ED9" }), _jsx("strong", { className: "text-[11px] text-[#315fb8]", children: value(handoff.toRole) })] }), _jsx("div", { className: "rounded-lg border border-[#e3e7ee] bg-white px-3 py-3 text-[11px] text-[#253044]", children: value(handoff.objective) }), handoff.context ? _jsx("p", { className: "rounded-lg bg-[#f6f8fa] px-3 py-2 text-[10px] leading-4 text-[#65707b]", children: value(handoff.context) }) : null, files.length > 0 ? (_jsx("div", { className: "grid gap-1 rounded-lg border border-[#edf0f3] bg-white px-3 py-2", children: files.slice(0, 8).map((file) => (_jsx("code", { className: "truncate text-[10px] text-[#65707b]", children: file }, file))) })) : null, _jsxs("div", { className: "grid grid-cols-2 gap-2 text-[10px] text-[#65707b]", children: [_jsxs("span", { children: ["\u7EA6\u675F ", constraints.length, " \u6761"] }), _jsxs("span", { children: ["\u9A8C\u6536 ", acceptance.length, " \u6761"] })] })] }));
619
+ })()) : (_jsx("div", { className: "rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3 text-[11px] text-[#687381]", children: "\u6267\u884C colleague_handoff \u540E\u663E\u793A\u89D2\u8272\u4EA4\u63A5\u5305\u3002" })) })) : panel.id === "reverse-skill-panel" ? (_jsxs("div", { className: "mt-3 grid gap-3", children: [_jsxs("div", { className: "flex items-center justify-between rounded-lg border border-[#dce5f5] bg-[#f6f8ff] px-3 py-3", children: [_jsx("span", { className: "text-[11px] text-[#65707b]", children: "\u590D\u6838\u98CE\u9669\u5185\u5BB9" }), _jsx("strong", { className: "font-mono text-[11px] text-[#3565c5]", children: data?.allowReviewByDefault === true ? "已允许" : "默认阻断" })] }), data?.latest && typeof data.latest === "object" ? ((() => {
620
+ const latest = data.latest;
621
+ const risk = value(latest.risk ?? "safe");
622
+ const findings = Array.isArray(latest.findings) ? latest.findings : [];
623
+ return (_jsxs("div", { className: `rounded-lg border px-3 py-3 text-[11px] ${risk === "blocked" ? "border-[#f4caca] bg-[#fff5f5] text-[#b42318]" : risk === "review" ? "border-[#f3dfab] bg-[#fffaf0] text-[#9a6700]" : "border-[#b9e6c9] bg-[#f0fbf4] text-[#14733f]"}`, children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("strong", { className: "uppercase", children: risk }), _jsx("span", { className: "font-mono text-[10px]", children: latest.contentIncluded === true ? "可注入" : "已隔离" })] }), _jsxs("p", { className: "mt-2", children: [value(latest.name ?? "未命名 Skill"), " \u00B7 ", value(findings.length), " \u4E2A\u98CE\u9669\u9879"] }), findings.length > 0 ? (_jsx("p", { className: "mt-1 text-[10px] opacity-80", children: findings
624
+ .slice(0, 2)
625
+ .map((item) => value(item))
626
+ .join(";") })) : null] }));
627
+ })()) : (_jsx("div", { className: "rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3 text-[11px] text-[#687381]", children: "\u6267\u884C skill_inject \u540E\u663E\u793A\u9694\u79BB\u7ED3\u679C\u3002" })), _jsx("p", { className: "text-[10px] leading-4 text-[#687381]", children: "\u5B89\u5168\u5185\u5BB9\u4F1A\u88AB\u5305\u88F9\u4E3A\u4E0D\u53EF\u4FE1\u6570\u636E\uFF1Breview \u98CE\u9669\u9ED8\u8BA4\u4E0D\u6CE8\u5165\uFF0Cblocked \u5185\u5BB9\u6C38\u4E0D\u8FD4\u56DE\u539F\u6587\u3002" })] })) : panel.id === "reviewer-bot-panel" ? (_jsx("div", { className: "mt-3 grid gap-3", children: data?.latest !== null && data?.latest !== undefined && typeof data.latest === "object" ? ((() => {
628
+ const report = data.latest;
629
+ const status = value(report.status ?? "pass");
630
+ const findings = Array.isArray(report.findings) ? report.findings : [];
631
+ return (_jsxs(_Fragment, { children: [_jsxs("div", { className: `flex items-center justify-between rounded-lg border px-3 py-3 text-[11px] ${status === "error" ? "border-[#f4caca] bg-[#fff5f5] text-[#b42318]" : status === "warning" ? "border-[#f3dfab] bg-[#fffaf0] text-[#9a6700]" : "border-[#b9e6c9] bg-[#f0fbf4] text-[#14733f]"}`, children: [_jsx("span", { children: status === "error" ? "发现阻断风险" : status === "warning" ? "需要关注" : "审查通过" }), _jsxs("strong", { className: "font-mono", children: [value(findings.length), " findings"] })] }), _jsx("div", { className: "grid grid-cols-3 gap-2", children: [
632
+ ["文件", report.changedFiles ?? 0],
633
+ ["新增", report.addedLines ?? 0],
634
+ ["删除", report.removedLines ?? 0],
635
+ ].map(([label, item]) => (_jsxs("div", { className: "rounded-lg bg-[#f6f8fa] px-3 py-2", children: [_jsx("span", { className: "block text-[10px] text-[#687381]", children: value(label) }), _jsx("strong", { className: "mt-1 block text-[17px] text-[#30343b]", children: value(item) })] }, value(label)))) }), findings.length > 0 ? (_jsx("ul", { className: "grid gap-1 rounded-lg border border-[#e3e7ee] bg-white px-4 py-3 text-[10px] text-[#65707b]", children: findings.slice(0, 4).map((finding, index) => (_jsx("li", { children: value(typeof finding === "object" && finding !== null ? (finding.message ?? "finding") : finding) }, index))) })) : null] }));
636
+ })()) : (_jsx("div", { className: "rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3 text-[11px] text-[#687381]", children: "\u8FD8\u6CA1\u6709\u5BA1\u67E5\u5F53\u524D\u6539\u52A8\u3002\u53EF\u8BA9 Agent \u8C03\u7528 review_changes\u3002" })) })) : panel.id === "auto-mode-panel" ? (_jsxs("div", { className: "mt-3 grid gap-3", children: [_jsxs("div", { className: "flex items-center justify-between rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3 text-[11px]", children: [_jsx("span", { className: "font-medium text-[#30343b]", children: data?.mode === "confirm" ? "确认模式" : "安全模式" }), _jsxs("span", { className: "font-mono text-[#65707b]", children: ["\u8D85\u65F6 ", value(data?.timeoutMs ?? "—"), " ms"] })] }), _jsxs("div", { className: "grid grid-cols-2 gap-2", children: [_jsxs("div", { className: "rounded-lg bg-[#f6f8fa] px-3 py-2", children: [_jsx("span", { className: "block text-[10px] text-[#687381]", children: "\u963B\u65AD\u6B21\u6570" }), _jsxs("strong", { className: "mt-1 block text-[17px] text-[#30343b]", children: [value(data?.blocked ?? 0), " \u6B21"] })] }), _jsxs("div", { className: "rounded-lg bg-[#f6f8fa] px-3 py-2", children: [_jsx("span", { className: "block text-[10px] text-[#687381]", children: "\u6700\u8FD1\u547D\u4EE4" }), _jsx("strong", { className: "mt-1 block truncate font-mono text-[11px] text-[#30343b]", children: data?.last && typeof data.last === "object" ? value(data.last.command ?? "—") : "—" })] })] }), data?.last && typeof data.last === "object" ? (_jsx("pre", { className: "max-h-32 overflow-auto rounded-lg border border-[#edf0f3] bg-[#fbfcfd] p-3 text-[10px] leading-4 text-[#65707b]", children: value(data.last.stdout, "") || value(data.last.stderr ?? "无输出") })) : (_jsx("div", { className: "rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3 text-[11px] text-[#687381]", children: "\u5C1A\u672A\u6267\u884C\u547D\u4EE4\u3002Agent \u53EF\u8C03\u7528 auto_mode_exec\u3002" }))] })) : panel.id === "plan-execute-panel" ? (_jsxs("div", { className: "mt-3 grid gap-3", children: [_jsxs("div", { className: "flex items-center justify-between rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3", children: [_jsx("span", { className: "truncate text-[11px] font-medium text-[#30343b]", children: data?.title ? value(data.title) : "尚未创建计划" }), _jsxs("span", { className: "font-mono text-[11px] text-[#3565c5]", children: [value(data?.completed ?? 0), " / ", value(data?.total ?? 0)] })] }), Array.isArray(data?.steps) && data.steps.length > 0 ? (_jsx("ol", { className: "grid gap-1.5", children: data.steps.map((step, index) => {
637
+ const item = step && typeof step === "object" ? step : {};
638
+ const status = value(item.status ?? "pending");
639
+ return (_jsxs("li", { className: "flex items-center gap-2 rounded-lg border border-[#edf0f3] bg-white px-3 py-2 text-[11px]", children: [_jsx("span", { className: `h-2 w-2 rounded-full ${status === "done" ? "bg-[#32a35a]" : status === "in_progress" ? "bg-[#3565c5]" : status === "skipped" ? "bg-[#a0a7b0]" : "bg-[#d7dce2]"}` }), _jsx("span", { className: `min-w-0 flex-1 truncate ${status === "done" ? "text-[#14733f]" : "text-[#30343b]"}`, children: value(item.title ?? "步骤") }), _jsx("span", { className: "font-mono text-[10px] text-[#687381]", children: status })] }, value(item.id ?? index)));
640
+ }) })) : (_jsx("div", { className: "rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3 text-[11px] text-[#687381]", children: "Agent \u53EF\u8C03\u7528 plan_create \u521B\u5EFA\u6267\u884C\u8BA1\u5212\u3002" }))] })) : panel.id === "plugin-stars-panel" ? (_jsxs("div", { className: "mt-3 grid gap-3", children: [_jsxs("div", { className: "flex items-center justify-between rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3 text-[11px]", children: [_jsx("span", { className: "font-medium text-[#30343b]", children: "\u793E\u533A\u6392\u884C\u699C" }), _jsxs("span", { className: "font-mono text-[#65707b]", children: ["\u4E0A\u9650 ", value(data?.limit ?? "—")] })] }), data?.latest && typeof data.latest === "object" ? ((() => {
641
+ const latest = data.latest;
642
+ const entries = Array.isArray(latest.results)
643
+ ? latest.results.flatMap((entry) => {
644
+ if (entry === null || typeof entry !== "object")
645
+ return [];
646
+ const item = entry;
647
+ if (typeof item.fullName !== "string" ||
648
+ typeof item.name !== "string" ||
649
+ typeof item.stars !== "number" ||
650
+ typeof item.htmlUrl !== "string" ||
651
+ typeof item.updatedAt !== "string")
652
+ return [];
653
+ return [{ fullName: item.fullName, name: item.name, stars: item.stars, htmlUrl: item.htmlUrl, updatedAt: item.updatedAt }];
654
+ })
655
+ : [];
656
+ const rows = pluginStarsRows(entries, 8);
657
+ return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex items-center justify-between text-[11px] text-[#65707b]", children: [_jsxs("span", { children: ["\u67E5\u8BE2\uFF1A", value(latest.query, "全部")] }), _jsxs("strong", { className: "font-mono text-[#3565c5]", children: [value(latest.total ?? rows.length), " \u4E2A\u7ED3\u679C"] })] }), rows.length > 0 ? (_jsx("ol", { className: "grid gap-1.5", children: rows.map((row) => (_jsxs("li", { className: "flex items-center gap-2 rounded-lg border border-[#edf0f3] bg-white px-3 py-2", children: [_jsxs("span", { className: "w-5 shrink-0 text-center font-mono text-[10px] text-[#9a6700]", children: ["#", row.rank] }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("a", { className: "block truncate font-mono text-[11px] text-[#315fb8] hover:underline", href: row.htmlUrl, rel: "noreferrer", target: "_blank", children: row.fullName }), _jsxs("span", { className: "block truncate text-[10px] text-[#687381]", children: ["\u66F4\u65B0\u4E8E ", row.updatedAt || "未知"] })] }), _jsxs("span", { className: "shrink-0 font-mono text-[10px] text-[#8a5a00]", children: ["\u2605 ", row.stars.toLocaleString()] })] }, row.fullName))) })) : (_jsx("div", { className: "rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3 text-[11px] text-[#687381]", children: "\u6CA1\u6709\u627E\u5230\u5339\u914D\u7684\u793E\u533A\u63D2\u4EF6\u3002" })), _jsxs("p", { className: "text-[10px] leading-4 text-[#687381]", children: ["\u6765\u6E90\uFF1A", value(latest.source, "dsh-plugin-stars"), " \u00B7 \u4EC5\u5C55\u793A\u516C\u5F00\u4ED3\u5E93\u4FE1\u606F\uFF0C\u4E0D\u4F1A\u81EA\u52A8\u5B89\u88C5\u3002"] })] }));
658
+ })()) : (_jsx("div", { className: "rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3 text-[11px] text-[#687381]", children: "Agent \u53EF\u8C03\u7528 plugin_stars_search \u62C9\u53D6\u5E76\u7B5B\u9009\u793E\u533A\u6392\u884C\u699C\u3002" }))] })) : panel.id === "plugin-finder-panel" ? (_jsxs("div", { className: "mt-3 grid gap-3", children: [_jsxs("div", { className: "flex items-center justify-between rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3 text-[11px]", children: [_jsx("span", { className: "font-medium text-[#30343b]", children: "\u53EA\u8BFB Registry \u641C\u7D22" }), _jsxs("span", { className: "font-mono text-[#65707b]", children: ["\u5173\u952E\u8BCD ", value(data?.keyword ?? "pi-harness"), " \u00B7 \u4E0A\u9650 ", value(data?.limit ?? "—")] })] }), data?.query ? (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex items-center justify-between text-[11px] text-[#65707b]", children: [_jsxs("span", { children: ["\u67E5\u8BE2\uFF1A", value(data.query)] }), _jsxs("strong", { className: "font-mono text-[#3565c5]", children: [value(data.total ?? 0), " \u4E2A\u7ED3\u679C"] })] }), Array.isArray(data?.results) && data.results.length > 0 ? (_jsx("ul", { className: "grid gap-1.5", children: data.results.slice(0, 5).map((result, index) => {
659
+ const item = result && typeof result === "object" ? result : {};
660
+ return (_jsxs("li", { className: "rounded-lg border border-[#edf0f3] bg-white px-3 py-2", children: [_jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsx("strong", { className: "truncate font-mono text-[11px] text-[#30343b]", children: value(item.name ?? "未知插件") }), _jsxs("span", { className: "font-mono text-[10px] text-[#687381]", children: ["v", value(item.version ?? "—")] })] }), _jsx("p", { className: "mt-1 truncate text-[10px] text-[#687381]", children: value(item.description, "") })] }, `${value(item.name ?? "plugin")}-${index}`));
661
+ }) })) : (_jsx("div", { className: "rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3 text-[11px] text-[#687381]", children: "\u6CA1\u6709\u627E\u5230\u5339\u914D\u63D2\u4EF6\u3002" }))] })) : (_jsx("div", { className: "rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3 text-[11px] text-[#687381]", children: "Agent \u53EF\u8C03\u7528 plugin_search \u641C\u7D22 npm Registry\u3002" }))] })) : panel.id === "memory-panel" ? (_jsxs("div", { className: "mt-3 grid gap-3", children: [_jsxs("div", { className: "flex items-center justify-between rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3 text-[11px]", children: [_jsx("span", { className: "font-medium text-[#30343b]", children: "\u8DE8\u4F1A\u8BDD\u8BB0\u5FC6" }), _jsxs("span", { className: "font-mono text-[#3565c5]", children: [value(data?.count ?? 0), " \u6761"] })] }), Array.isArray(data?.memories) && data.memories.length > 0 ? (_jsx("ul", { className: "grid gap-1.5", children: data.memories.slice(0, 5).map((memory, index) => {
662
+ const item = memory && typeof memory === "object" ? memory : {};
663
+ return (_jsxs("li", { className: "rounded-lg border border-[#edf0f3] bg-white px-3 py-2", children: [_jsx("strong", { className: "block truncate font-mono text-[11px] text-[#30343b]", children: value(item.key ?? "未知键") }), _jsx("p", { className: "mt-1 truncate text-[10px] text-[#687381]", children: value(item.value, "") })] }, `${value(item.key ?? "memory")}-${index}`));
664
+ }) })) : (_jsx("div", { className: "rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3 text-[11px] text-[#687381]", children: "\u5C1A\u672A\u4FDD\u5B58\u8BB0\u5FC6\u3002Agent \u53EF\u8C03\u7528 memory_set \u660E\u786E\u5199\u5165\u3002" }))] })) : panel.id === "graph-memory-panel" ? ((() => {
665
+ const kinds = data?.kinds !== null && typeof data?.kinds === "object" ? data.kinds : {};
666
+ const recent = Array.isArray(data?.recent) ? data.recent : [];
667
+ const recentRelations = Array.isArray(data?.recentRelations) ? data.recentRelations : [];
668
+ return (_jsxs("div", { className: "mt-3 grid gap-3", children: [_jsx("div", { className: "grid grid-cols-3 gap-2", children: [
669
+ ["任务", kinds.task ?? 0, "bg-[#3565c5]"],
670
+ ["技能", kinds.skill ?? 0, "bg-[#22a06b]"],
671
+ ["事件", kinds.event ?? 0, "bg-[#d97706]"],
672
+ ].map(([label, count, color]) => (_jsxs("div", { className: "rounded-lg border border-[#edf0f3] bg-[#f8fafc] px-3 py-2", children: [_jsxs("div", { className: "flex items-center gap-1.5 text-[10px] text-[#687381]", children: [_jsx("span", { className: `h-1.5 w-1.5 rounded-full ${value(color)}` }), value(label)] }), _jsx("strong", { className: "mt-1 block font-mono text-[17px] text-[#30343b]", children: value(count) })] }, value(label)))) }), _jsxs("div", { className: "flex items-center justify-between rounded-lg border border-[#e3eaf8] bg-[#f6f8ff] px-3 py-2 text-[10px]", children: [_jsx("span", { className: "text-[#65707b]", children: "\u672C\u5730\u5173\u7CFB\u56FE" }), _jsxs("span", { className: "font-mono text-[#3565c5]", children: [value(data?.nodes ?? 0), " \u8282\u70B9 \u00B7 ", value(data?.relations ?? 0), " \u5173\u7CFB"] })] }), recent.length > 0 ? (_jsxs("ul", { className: "grid gap-1.5", children: [_jsxs("li", { className: "text-[9px] uppercase tracking-[0.08em] text-[#687381]", children: ["\u6700\u8FD1\u8282\u70B9 ", Math.min(recent.length, 5), " / ", value(data?.nodes ?? recent.length)] }), recent.slice(0, 5).map((entry, index) => {
673
+ const item = entry !== null && typeof entry === "object" ? entry : {};
674
+ const kind = item.kind === "task" || item.kind === "skill" || item.kind === "event" ? item.kind : "unknown";
675
+ const kindLabel = kind === "task" ? "任务" : kind === "skill" ? "技能" : kind === "event" ? "事件" : "未知";
676
+ const kindClass = kind === "task"
677
+ ? "bg-[#edf3fe] text-[#315fb8]"
678
+ : kind === "skill"
679
+ ? "bg-[#eaf8f0] text-[#14733f]"
680
+ : kind === "event"
681
+ ? "bg-[#fff4e5] text-[#a15c00]"
682
+ : "bg-[#f2f3f5] text-[#65707b]";
683
+ return (_jsxs("li", { className: "rounded-lg border border-[#edf0f3] bg-white px-3 py-2", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: `rounded px-1.5 py-0.5 text-[9px] font-semibold ${kindClass}`, children: kindLabel }), _jsx("strong", { className: "min-w-0 flex-1 truncate text-[11px] text-[#30343b]", children: value(item.label ?? "未命名节点") })] }), _jsx("p", { className: "mt-1 line-clamp-2 text-[10px] leading-4 text-[#65707b]", children: value(item.summary, "") }), item.source ? _jsxs("p", { className: "mt-1 truncate font-mono text-[9px] text-[#687381]", children: ["\u6765\u6E90\uFF1A", value(item.source)] }) : null] }, `${value(item.id ?? "node")}-${index}`));
684
+ })] })) : (_jsx("div", { className: "rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3 text-[11px] text-[#687381]", children: "\u5C1A\u672A\u8BB0\u5F55\u56FE\u8BB0\u5FC6\u3002Agent \u53EF\u8C03\u7528 graph_memory_record \u521B\u5EFA\u4EFB\u52A1\u3001\u6280\u80FD\u6216\u4E8B\u4EF6\u8282\u70B9\u3002" })), recentRelations.length > 0 ? (_jsxs("div", { className: "grid gap-1 rounded-lg border border-[#edf0f3] bg-[#fbfcfd] px-3 py-2", children: [_jsxs("span", { className: "text-[9px] uppercase tracking-[0.08em] text-[#687381]", children: ["\u6700\u8FD1\u5173\u7CFB ", Math.min(recentRelations.length, 3), " / ", value(data?.relations ?? recentRelations.length)] }), recentRelations.slice(0, 3).map((entry, index) => {
685
+ const relation = entry !== null && typeof entry === "object" ? entry : {};
686
+ return (_jsxs("div", { className: "flex min-w-0 items-center gap-1.5 font-mono text-[9px] text-[#65707b]", children: [_jsx("span", { className: "truncate", children: value(relation.fromLabel ?? relation.from ?? "节点") }), _jsxs("span", { className: "shrink-0 text-[#3565c5]", children: ["\u2014", value(relation.relation ?? "RELATED_TO"), "\u2192"] }), _jsx("span", { className: "truncate", children: value(relation.toLabel ?? relation.to ?? "节点") })] }, `${value(relation.id ?? "relation")}-${index}`));
687
+ })] })) : null] }));
688
+ })()) : panel.id === "taskboard-panel" ? ((() => {
689
+ const counts = data?.counts !== null && typeof data?.counts === "object" ? data.counts : {};
690
+ const recent = Array.isArray(data?.recent) ? data.recent : [];
691
+ const lanes = [
692
+ ["待办", "todo", "bg-[#edf3fe] text-[#315fb8]"],
693
+ ["进行中", "in_progress", "bg-[#fff4e5] text-[#a15c00]"],
694
+ ["待验收", "in_review", "bg-[#f0edff] text-[#6b4fc3]"],
695
+ ["已完成", "done", "bg-[#eaf8f0] text-[#14733f]"],
696
+ ];
697
+ return (_jsxs("div", { className: "mt-3 grid gap-3", children: [_jsxs("div", { className: "flex items-center justify-between rounded-lg border border-[#e3eaf8] bg-[#f6f8ff] px-3 py-2 text-[10px]", children: [_jsx("span", { className: "text-[#65707b]", children: "\u5F53\u524D\u5DE5\u4F5C\u533A\u4EFB\u52A1" }), _jsxs("strong", { className: "font-mono text-[#3565c5]", children: [value(data?.total ?? 0), " \u4E2A"] })] }), _jsx("div", { className: "grid grid-cols-2 gap-2", children: lanes.map(([label, key, color]) => (_jsx("div", { className: "rounded-lg border border-[#edf0f3] bg-[#f8fafc] px-3 py-2", children: _jsxs("div", { className: "flex items-center justify-between text-[10px] text-[#687381]", children: [_jsx("span", { children: label }), _jsx("span", { className: `rounded px-1.5 py-0.5 ${color}`, children: value(counts[key] ?? 0) })] }) }, key))) }), recent.length > 0 ? (_jsxs("ul", { className: "grid gap-1.5", children: [_jsxs("li", { className: "text-[9px] uppercase tracking-[0.08em] text-[#687381]", children: ["\u6700\u8FD1\u4EFB\u52A1 ", Math.min(recent.length, 5), " / ", value(data?.total ?? recent.length)] }), recent.slice(0, 5).map((entry, index) => {
698
+ const task = entry !== null && typeof entry === "object" ? entry : {};
699
+ const status = typeof task.status === "string" ? task.status : "unknown";
700
+ const priority = typeof task.priority === "string" ? task.priority : "medium";
701
+ const statusLabel = status === "backlog"
702
+ ? "待规划"
703
+ : status === "todo"
704
+ ? "待办"
705
+ : status === "in_progress"
706
+ ? "进行中"
707
+ : status === "in_review"
708
+ ? "待验收"
709
+ : status === "blocked"
710
+ ? "阻塞"
711
+ : status === "canceled"
712
+ ? "已取消"
713
+ : status === "done"
714
+ ? "已完成"
715
+ : "未知";
716
+ const statusClass = status === "done"
717
+ ? "bg-[#eaf8f0] text-[#14733f]"
718
+ : status === "blocked" || status === "canceled"
719
+ ? "bg-[#fff5f5] text-[#b42318]"
720
+ : status === "unknown"
721
+ ? "bg-[#f2f3f5] text-[#65707b]"
722
+ : "bg-[#edf3fe] text-[#315fb8]";
723
+ return (_jsxs("li", { className: "rounded-lg border border-[#edf0f3] bg-white px-3 py-2", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("code", { className: "font-mono text-[10px] text-[#3565c5]", children: value(task.key ?? "PIH-?") }), _jsx("strong", { className: "min-w-0 flex-1 truncate text-[11px] text-[#30343b]", children: value(task.title ?? "未命名任务") }), _jsx("span", { className: `rounded px-1.5 py-0.5 text-[9px] ${statusClass}`, children: statusLabel })] }), _jsxs("div", { className: "mt-1 flex items-center gap-2 text-[9px] text-[#687381]", children: [_jsxs("span", { children: ["\u4F18\u5148\u7EA7 ", priority] }), task.dueDate ? _jsxs("span", { children: ["\u622A\u6B62 ", value(task.dueDate)] }) : null] })] }, `${value(task.id ?? "task")}-${index}`));
724
+ })] })) : (_jsx("div", { className: "rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3 text-[11px] text-[#687381]", children: "\u5C1A\u672A\u521B\u5EFA\u4EFB\u52A1\u3002Agent \u53EF\u8C03\u7528 taskboard_create \u521B\u5EFA\u5E26\u7A33\u5B9A\u7F16\u53F7\u7684\u4EFB\u52A1\u3002" }))] }));
725
+ })()) : panel.id === "skill-catalog-panel" ? ((() => {
726
+ const skills = Array.isArray(data?.skills) ? data.skills : [];
727
+ const servers = Array.isArray(data?.mcpServers) ? data.mcpServers : [];
728
+ const diagnostics = Array.isArray(data?.diagnostics) ? data.diagnostics : [];
729
+ return (_jsxs("div", { className: "mt-3 grid gap-3", children: [_jsxs("div", { className: "grid grid-cols-2 gap-2", children: [_jsxs("div", { className: "rounded-lg border border-[#e3eaf8] bg-[#f6f8ff] px-3 py-2", children: [_jsx("span", { className: "block text-[10px] text-[#687381]", children: "Skills" }), _jsx("strong", { className: "mt-1 block font-mono text-[17px] text-[#315fb8]", children: value(data?.skillCount ?? 0) })] }), _jsxs("div", { className: "rounded-lg border border-[#e3eaf8] bg-[#f6f8ff] px-3 py-2", children: [_jsx("span", { className: "block text-[10px] text-[#687381]", children: "MCP \u670D\u52A1\u5668" }), _jsx("strong", { className: "mt-1 block font-mono text-[17px] text-[#315fb8]", children: value(data?.mcpCount ?? 0) })] })] }), skills.length > 0 ? (_jsx("ul", { className: "grid gap-1.5", children: skills.slice(0, 8).map((entry, index) => {
730
+ const item = entry !== null && typeof entry === "object" ? entry : {};
731
+ return (_jsxs("li", { className: "rounded-lg border border-[#edf0f3] bg-white px-3 py-2", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("strong", { className: "min-w-0 flex-1 truncate text-[11px] text-[#30343b]", children: value(item.name, "未命名技能") }), _jsx("span", { className: "rounded bg-[#f2f3f5] px-1.5 py-0.5 text-[9px] text-[#65707b]", children: value(item.scope, "unknown") })] }), _jsx("p", { className: "mt-1 line-clamp-2 text-[10px] text-[#687381]", children: value(item.description, "无描述") })] }, `${value(item.name ?? "skill")}-${index}`));
732
+ }) })) : (_jsx("div", { className: "rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3 text-[11px] text-[#687381]", children: "\u5F53\u524D\u8FD0\u884C\u65F6\u6CA1\u6709\u52A0\u8F7D Skill\u3002" })), servers.length > 0 ? (_jsxs("div", { children: [_jsx("div", { className: "mb-1 text-[10px] font-semibold text-[#65707b]", children: "MCP \u72B6\u6001" }), _jsx("ul", { className: "grid gap-1.5", children: servers.slice(0, 6).map((entry, index) => {
733
+ const item = entry !== null && typeof entry === "object" ? entry : {};
734
+ const running = item.status === "running";
735
+ return (_jsxs("li", { className: "flex items-center justify-between rounded-lg border border-[#edf0f3] bg-white px-3 py-2 text-[10px]", children: [_jsx("span", { className: "truncate font-mono text-[#65707b]", children: value(item.id, "未命名服务器") }), _jsx("span", { className: `rounded px-1.5 py-0.5 ${running ? "bg-[#eaf8f0] text-[#14733f]" : "bg-[#f2f3f5] text-[#65707b]"}`, children: value(item.status, "unknown") })] }, `${value(item.id ?? "server")}-${index}`));
736
+ }) })] })) : null, diagnostics.length > 0 ? (_jsxs("div", { className: "rounded-lg border border-[#fff0c2] bg-[#fffaf0] px-3 py-2 text-[10px] text-[#8a5a00]", children: ["\u8D44\u6E90\u8BCA\u65AD\uFF1A", diagnostics.length, " \u6761\u8B66\u544A"] })) : null, _jsx("div", { className: "text-[10px] text-[#687381]", children: "\u53EA\u8BFB\u67E5\u770B runtime \u5DF2\u52A0\u8F7D\u7684 Skill \u4E0E MCP \u72B6\u6001\uFF1B\u914D\u7F6E\u5199\u5165\u4ECD\u7531\u5404\u81EA\u63D2\u4EF6\u8D1F\u8D23\u3002" })] }));
737
+ })()) : panel.id === "cost-meter-panel" ? ((() => {
738
+ const budget = typeof data?.budget === "number" ? data.budget : null;
739
+ const budgetPercent = typeof data?.budgetPercent === "number" ? data.budgetPercent : null;
740
+ const entries = Array.isArray(data?.entries) ? data.entries : [];
741
+ const budgetClass = budgetPercent !== null && budgetPercent >= 100
742
+ ? "text-[#b42318]"
743
+ : budgetPercent !== null && budgetPercent >= 80
744
+ ? "text-[#a15c00]"
745
+ : "text-[#14733f]";
746
+ return (_jsxs("div", { className: "mt-3 grid gap-3", children: [_jsx("div", { className: "grid grid-cols-3 gap-2", children: [
747
+ ["今日", `$${Number(data?.todayCost ?? 0).toFixed(4)}`],
748
+ ["当前会话", `$${Number(data?.sessionCost ?? 0).toFixed(4)}`],
749
+ ["累计", `$${Number(data?.lifetimeCost ?? 0).toFixed(4)}`],
750
+ ].map(([label, item]) => (_jsxs("div", { className: "rounded-lg bg-[#f6f8fa] px-3 py-2", children: [_jsx("span", { className: "block text-[10px] text-[#687381]", children: value(label) }), _jsx("strong", { className: "mt-1 block font-mono text-[15px] font-semibold text-[#30343b]", children: value(item) })] }, value(label)))) }), _jsxs("div", { className: "rounded-lg border border-[#e3eaf8] bg-[#f6f8ff] px-3 py-3", children: [_jsxs("div", { className: "flex items-center justify-between text-[11px]", children: [_jsx("span", { className: "text-[#65707b]", children: "\u6BCF\u65E5\u9884\u7B97" }), _jsx("strong", { className: budgetClass, children: budget === null ? "未设置" : `$${budget.toFixed(4)} · ${budgetPercent?.toFixed(2) ?? "0.00"}%` })] }), budget !== null ? (_jsx("div", { className: "mt-2 h-1.5 overflow-hidden rounded-full bg-[#dfe8f7]", children: _jsx("div", { className: `h-full ${budgetPercent !== null && budgetPercent >= 100 ? "bg-[#d64545]" : "bg-[#4c83e8]"}`, style: { width: `${Math.min(100, budgetPercent ?? 0)}%` } }) })) : null] }), entries.length > 0 ? (_jsx("ul", { className: "grid gap-1.5", children: entries.slice(0, 5).map((entry, index) => {
751
+ const item = entry !== null && typeof entry === "object" ? entry : {};
752
+ return (_jsxs("li", { className: "flex items-center justify-between rounded-lg border border-[#edf0f3] bg-white px-3 py-2 text-[10px]", children: [_jsx("span", { className: "truncate font-mono text-[#65707b]", children: value(item.sessionId ?? "未知会话") }), _jsxs("strong", { className: "font-mono text-[#30343b]", children: ["$", Number(item.cost ?? 0).toFixed(4)] })] }, `${value(item.sessionId ?? "session")}-${index}`));
753
+ }) })) : (_jsx("div", { className: "rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3 text-[11px] text-[#687381]", children: "\u5C1A\u672A\u8BB0\u5F55\u5DF2\u5B8C\u6210\u4F1A\u8BDD\u3002Agent \u53EF\u8C03\u7528 cost_report \u7684 refresh \u64CD\u4F5C\u5199\u5165\u8D26\u672C\u3002" })), _jsx("div", { className: "text-[10px] text-[#687381]", children: "\u4EC5\u8BB0\u5F55\u8FD0\u884C\u65F6\u62A5\u544A\u7684\u5B9E\u9645\u6210\u672C\uFF0C\u4E0D\u5185\u7F6E\u6216\u731C\u6D4B\u6A21\u578B\u4EF7\u683C\u3002" })] }));
754
+ })()) : panel.id === "undo-savepoint-panel" ? ((() => {
755
+ const savepoints = Array.isArray(data?.savepoints) ? data.savepoints : [];
756
+ return (_jsxs("div", { className: "mt-3 grid gap-3", children: [_jsxs("div", { className: "grid grid-cols-2 gap-2", children: [_jsxs("div", { className: "rounded-lg border border-[#e3eaf8] bg-[#f6f8ff] px-3 py-2", children: [_jsx("span", { className: "block text-[10px] text-[#687381]", children: "\u4FDD\u5B58\u70B9" }), _jsx("strong", { className: "mt-1 block font-mono text-[17px] text-[#315fb8]", children: value(data?.count ?? savepoints.length) })] }), _jsxs("div", { className: "rounded-lg border border-[#e3eaf8] bg-[#f6f8ff] px-3 py-2", children: [_jsx("span", { className: "block text-[10px] text-[#687381]", children: "\u8DDF\u8E2A\u8DEF\u5F84" }), _jsx("strong", { className: "mt-1 block font-mono text-[17px] text-[#315fb8]", children: value(Array.isArray(data?.trackedPaths) ? data.trackedPaths.length : 0) })] })] }), savepoints.length > 0 ? (_jsx("ul", { className: "grid gap-1.5", children: savepoints.slice(0, 6).map((entry, index) => {
757
+ const item = entry !== null && typeof entry === "object" ? entry : {};
758
+ return (_jsx("li", { className: "rounded-lg border border-[#edf0f3] bg-white px-3 py-2", children: _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("code", { className: "font-mono text-[10px] text-[#3565c5]", children: value(item.id, "unknown") }), _jsx("strong", { className: "min-w-0 flex-1 truncate text-[11px] text-[#30343b]", children: value(item.reason, "manual savepoint") }), _jsxs("span", { className: "text-[9px] text-[#687381]", children: [value(item.fileCount, "0"), " \u6587\u4EF6"] })] }) }, `${value(item.id ?? "savepoint")}-${index}`));
759
+ }) })) : (_jsx("div", { className: "rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3 text-[11px] text-[#687381]", children: "\u5C1A\u672A\u521B\u5EFA\u4FDD\u5B58\u70B9\u3002\u4FEE\u6539\u914D\u7F6E\u6216\u63D2\u4EF6\u4EE3\u7801\u524D\uFF0C\u8BA9 Agent \u8C03\u7528 undo_savepoint \u7684 save \u64CD\u4F5C\u3002" })), _jsx("div", { className: "text-[10px] text-[#687381]", children: "\u6062\u590D\u64CD\u4F5C\u8981\u6C42 confirm=true\uFF1B\u654F\u611F\u6587\u4EF6\u3001\u4E8C\u8FDB\u5236\u6587\u4EF6\u548C\u4F9D\u8D56\u76EE\u5F55\u4E0D\u4F1A\u8FDB\u5165\u4FDD\u5B58\u70B9\u3002" })] }));
760
+ })()) : panel.id === "annotation-panel" ? ((() => {
761
+ const annotations = Array.isArray(data?.annotations) ? data.annotations : [];
762
+ const lastPrompt = typeof data?.lastPrompt === "string" ? data.lastPrompt : "";
763
+ return (_jsxs("div", { className: "mt-3 grid gap-3", children: [_jsxs("div", { className: "flex items-center justify-between rounded-lg border border-[#e3eaf8] bg-[#f6f8ff] px-3 py-2 text-[10px]", children: [_jsx("span", { className: "text-[#65707b]", children: "\u5F85\u53D1\u9001\u6279\u6CE8" }), _jsxs("strong", { className: "font-mono text-[#3565c5]", children: [value(data?.count ?? 0), " \u6761"] })] }), annotations.length > 0 ? (_jsx("ol", { className: "grid gap-1.5", children: annotations.slice(0, 8).map((entry, index) => {
764
+ const item = entry !== null && typeof entry === "object" ? entry : {};
765
+ return (_jsxs("li", { className: "rounded-lg border border-[#edf0f3] bg-white px-3 py-2", children: [_jsxs("div", { className: "flex items-start gap-2 text-[10px]", children: [_jsxs("span", { className: "rounded bg-[#edf3fe] px-1.5 py-0.5 font-mono text-[#315fb8]", children: ["#", value(item.id ?? index + 1)] }), _jsx("p", { className: "min-w-0 flex-1 whitespace-pre-wrap text-[#30343b]", children: value(item.quote, "") })] }), item.note ? _jsx("p", { className: "mt-1 pl-8 text-[10px] text-[#687381]", children: value(item.note) }) : null] }, `${value(item.id ?? index)}-${index}`));
766
+ }) })) : (_jsx("div", { className: "rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3 text-[11px] text-[#687381]", children: "\u5C1A\u672A\u6536\u96C6\u6279\u6CE8\u3002Agent \u53EF\u8C03\u7528 annotation_manage \u7684 add \u64CD\u4F5C\u8BB0\u5F55\u56DE\u590D\u7247\u6BB5\u3002" })), lastPrompt ? (_jsxs("details", { className: "rounded-lg border border-[#e3e7ee] bg-white px-3 py-2 text-[10px]", children: [_jsx("summary", { className: "cursor-pointer text-[#65707b]", children: "\u6700\u8FD1\u751F\u6210\u7684\u63D0\u95EE\u4E0A\u4E0B\u6587" }), _jsx("pre", { className: "mt-2 max-h-40 overflow-auto whitespace-pre-wrap text-[10px] text-[#30343b]", children: lastPrompt })] })) : null, _jsx("div", { className: "text-[10px] text-[#687381]", children: "\u6279\u6CE8\u6309\u7F16\u53F7\u7D2F\u79EF\uFF1B\u751F\u6210\u4E0A\u4E0B\u6587\u4E0D\u4F1A\u6539\u5199\u539F\u4F1A\u8BDD\u6D88\u606F\u3002" })] }));
767
+ })()) : panel.id === "runtime-doctor-panel" ? ((() => {
768
+ const status = value(data?.status ?? "unknown");
769
+ const checks = Array.isArray(data?.checks) ? data.checks : [];
770
+ const recommendations = Array.isArray(data?.recommendations) ? data.recommendations : [];
771
+ const statusClass = status === "ok" ? "bg-[#eaf8f0] text-[#14733f]" : status === "warning" ? "bg-[#fff7e8] text-[#a15c00]" : "bg-[#fff0f0] text-[#b42318]";
772
+ return (_jsxs("div", { className: "mt-3 grid gap-3", children: [_jsxs("div", { className: "flex items-center justify-between rounded-lg border border-[#e3eaf8] bg-[#f6f8ff] px-3 py-2", children: [_jsx("span", { className: "text-[11px] text-[#65707b]", children: "\u8FD0\u884C\u65F6\u8FB9\u754C\u68C0\u67E5" }), _jsx("span", { className: `rounded px-2 py-0.5 font-mono text-[10px] uppercase ${statusClass}`, children: status })] }), _jsx("div", { className: "grid gap-1.5", children: checks.map((entry, index) => {
773
+ const check = entry !== null && typeof entry === "object" ? entry : {};
774
+ const checkStatus = value(check.status ?? "unknown");
775
+ const checkClass = checkStatus === "ok"
776
+ ? "bg-[#eaf8f0] text-[#14733f]"
777
+ : checkStatus === "warning"
778
+ ? "bg-[#fff7e8] text-[#a15c00]"
779
+ : "bg-[#fff0f0] text-[#b42318]";
780
+ return (_jsxs("div", { className: "flex items-center gap-2 rounded-lg border border-[#edf0f3] bg-white px-3 py-2 text-[10px]", children: [_jsx("span", { className: `h-1.5 w-1.5 shrink-0 rounded-full ${checkStatus === "ok" ? "bg-[#22c55e]" : checkStatus === "warning" ? "bg-[#e6a21a]" : "bg-[#d64545]"}` }), _jsx("code", { className: "w-20 shrink-0 text-[#65707b]", children: value(check.id ?? "check") }), _jsx("span", { className: "min-w-0 flex-1 truncate text-[#30343b]", children: value(check.detail ?? "—") }), _jsx("span", { className: `rounded px-1.5 py-0.5 font-mono ${checkClass}`, children: checkStatus })] }, `${value(check.id ?? "check")}-${index}`));
781
+ }) }), recommendations.length > 0 ? (_jsxs("div", { className: "rounded-lg border border-[#f3dfab] bg-[#fffaf0] px-3 py-2 text-[10px] text-[#8a6200]", children: [_jsx("strong", { children: "\u5EFA\u8BAE" }), _jsx("ul", { className: "mt-1 grid gap-1 pl-4", children: recommendations.slice(0, 5).map((item, index) => (_jsx("li", { children: value(item) }, `${value(item)}-${index}`))) })] })) : null] }));
782
+ })()) : panel.id === "plugin-check-panel" ? ((() => {
783
+ const latest = data?.latest !== null && typeof data?.latest === "object" ? data.latest : undefined;
784
+ const checks = latest?.checks !== null && typeof latest?.checks === "object" ? latest.checks : undefined;
785
+ const errors = Array.isArray(latest?.errors) ? latest.errors : [];
786
+ const warnings = Array.isArray(latest?.warnings) ? latest.warnings : [];
787
+ const reports = Array.isArray(latest?.reports) ? latest.reports : [];
788
+ const schema = Array.isArray(latest?.checks) ? latest.checks : [];
789
+ const verdict = value(latest?.verdict ?? "—");
790
+ const verdictClass = verdict === "pass" ? "bg-[#eaf8f0] text-[#14733f]" : verdict === "warn" ? "bg-[#fff7e8] text-[#a15c00]" : "bg-[#fff0f0] text-[#b42318]";
791
+ return (_jsxs("div", { className: "mt-3 grid gap-3", children: [latest?.scanned !== undefined ? (_jsxs("div", { className: "flex items-center justify-between rounded-lg border border-[#e3eaf8] bg-[#f6f8ff] px-3 py-2 text-[10px]", children: [_jsx("span", { className: "text-[#65707b]", children: "\u76EE\u5F55\u626B\u63CF" }), _jsxs("strong", { className: "font-mono text-[#3565c5]", children: [value(latest.scanned), " \u4E2A\u4ED3\u5E93"] })] })) : latest?.verdict !== undefined ? (_jsxs("div", { className: "flex items-center justify-between rounded-lg border border-[#e3e7ee] bg-[#f8fafc] px-3 py-2 text-[10px]", children: [_jsx("span", { className: "truncate text-[#65707b]", children: value(latest.repo ?? "当前插件") }), _jsx("span", { className: `rounded px-1.5 py-0.5 font-mono ${verdictClass}`, children: verdict })] })) : schema.length > 0 ? (_jsxs("div", { className: "rounded-lg border border-[#e3eaf8] bg-[#f6f8ff] px-3 py-2 text-[10px] text-[#65707b]", children: ["\u68C0\u67E5\u6E05\u5355\uFF1A", schema.length, " \u9879"] })) : null, checks ? (_jsx("div", { className: "grid grid-cols-3 gap-2", children: [
792
+ ["通过", checks.passed ?? 0],
793
+ ["失败", checks.failed ?? 0],
794
+ ["警告", checks.warned ?? 0],
795
+ ].map(([label, count]) => (_jsxs("div", { className: "rounded-lg border border-[#edf0f3] bg-[#f8fafc] px-3 py-2", children: [_jsx("span", { className: "block text-[10px] text-[#687381]", children: value(label) }), _jsx("strong", { className: "mt-1 block font-mono text-[17px] text-[#30343b]", children: value(count) })] }, value(label)))) })) : null, reports.length > 0 ? (_jsx("ul", { className: "grid gap-1.5", children: reports.slice(0, 6).map((entry, index) => {
796
+ const report = entry !== null && typeof entry === "object" ? entry : {};
797
+ const state = value(report.verdict ?? "—");
798
+ return (_jsxs("li", { className: "flex items-center justify-between rounded-lg border border-[#edf0f3] bg-white px-3 py-2 text-[10px]", children: [_jsx("span", { className: "truncate font-mono text-[#65707b]", children: value(report.repo ?? "未知仓库") }), _jsx("span", { className: `rounded px-1.5 py-0.5 ${state === "pass" ? "bg-[#eaf8f0] text-[#14733f]" : state === "warn" ? "bg-[#fff7e8] text-[#a15c00]" : "bg-[#fff0f0] text-[#b42318]"}`, children: state })] }, `${value(report.repo ?? "repo")}-${index}`));
799
+ }) })) : errors.length > 0 || warnings.length > 0 ? (_jsx("ul", { className: "grid gap-1.5", children: [...errors, ...warnings].slice(0, 5).map((entry, index) => {
800
+ const item = entry !== null && typeof entry === "object" ? entry : {};
801
+ return (_jsxs("li", { className: "rounded-lg border border-[#edf0f3] bg-white px-3 py-2 text-[10px]", children: [_jsx("strong", { className: "font-mono text-[#b42318]", children: value(item.code ?? "issue") }), _jsx("p", { className: "mt-1 text-[#65707b]", children: value(item.message, "") })] }, `${value(item.code ?? "issue")}-${index}`));
802
+ }) })) : (_jsx("div", { className: "rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3 text-[11px] text-[#687381]", children: "\u5C1A\u672A\u68C0\u67E5\u63D2\u4EF6\u3002Agent \u53EF\u8C03\u7528 plugin_check \u6267\u884C check\u3001scan \u6216 schema\u3002" })), _jsx("div", { className: "text-[10px] text-[#687381]", children: "\u53EA\u8BFB\u68C0\u67E5\uFF0C\u4E0D\u4FEE\u6539\u3001\u4E0D\u6784\u5EFA\u88AB\u68C0\u4ED3\u5E93\u3002" })] }));
803
+ })()) : panel.id === "plugin-radar-panel" ? ((() => {
804
+ const results = Array.isArray(data?.results) ? data.results : [];
805
+ return (_jsxs("div", { className: "mt-3 grid gap-3", children: [_jsxs("div", { className: "flex items-center justify-between rounded-lg border border-[#e3eaf8] bg-[#f6f8ff] px-3 py-2 text-[10px]", children: [_jsx("span", { className: "text-[#65707b]", children: "GitHub DSH \u751F\u6001" }), _jsxs("span", { className: "font-mono text-[#3565c5]", children: [value(data?.total ?? 0), " \u4E2A\u4ED3\u5E93 \u00B7 ", Array.isArray(data?.sources) ? data.sources.length : 0, " \u4E2A\u6765\u6E90"] })] }), data?.query ? _jsxs("div", { className: "text-[11px] text-[#65707b]", children: ["\u67E5\u8BE2\uFF1A", value(data.query)] }) : null, results.length > 0 ? (_jsx("ol", { className: "grid gap-1.5", children: results.slice(0, 8).map((entry, index) => {
806
+ const item = entry !== null && typeof entry === "object" ? entry : {};
807
+ const topics = Array.isArray(item.topics) ? item.topics.filter((topic) => typeof topic === "string").slice(0, 3) : [];
808
+ const url = typeof item.url === "string" ? item.url : undefined;
809
+ return (_jsxs("li", { className: "rounded-lg border border-[#edf0f3] bg-white px-3 py-2", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: "w-4 shrink-0 text-right font-mono text-[10px] text-[#687381]", children: index + 1 }), url ? (_jsx("a", { className: "min-w-0 flex-1 truncate font-mono text-[11px] text-[#315fb8] hover:underline", href: url, rel: "noreferrer", target: "_blank", children: value(item.fullName ?? item.name ?? "未知仓库") })) : (_jsx("strong", { className: "min-w-0 flex-1 truncate font-mono text-[11px] text-[#30343b]", children: value(item.fullName ?? item.name ?? "未知仓库") })), _jsxs("span", { className: "shrink-0 font-mono text-[10px] text-[#a15c00]", children: ["\u2605 ", value(item.stars ?? 0)] })] }), _jsx("p", { className: "mt-1 truncate pl-6 text-[10px] text-[#65707b]", children: value(item.description, "暂无描述") }), _jsxs("div", { className: "mt-1 flex min-w-0 items-center gap-2 pl-6 text-[9px] text-[#687381]", children: [item.language ? _jsx("span", { children: value(item.language) }) : null, item.updatedAt ? _jsxs("span", { className: "font-mono", children: ["\u66F4\u65B0 ", value(item.updatedAt)] }) : null, topics.length > 0 ? _jsx("span", { className: "truncate", children: topics.map((topic) => `#${topic}`).join(" ") }) : null] })] }, `${value(item.fullName ?? "repo")}-${index}`));
810
+ }) })) : (_jsx("div", { className: "rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3 text-[11px] text-[#687381]", children: "\u5C1A\u672A\u641C\u7D22\u63D2\u4EF6\u3002Agent \u53EF\u8C03\u7528 plugin_radar_search \u4ECE GitHub \u53D1\u73B0 DSH \u63D2\u4EF6\u3002" })), _jsx("div", { className: "text-[10px] text-[#687381]", children: "\u53EA\u8BFB GitHub \u641C\u7D22\uFF0C\u6309 Star \u964D\u5E8F\uFF1B\u4E0D\u4F1A\u5B89\u88C5\u3001\u6267\u884C\u6216\u4FEE\u6539\u7B2C\u4E09\u65B9\u4ED3\u5E93\u3002" })] }));
811
+ })()) : panel.id === "hol-guard-panel" ? ((() => {
812
+ const receipts = Array.isArray(data?.receipts) ? data.receipts : [];
813
+ const latest = data?.latest !== null && typeof data?.latest === "object" ? data.latest : undefined;
814
+ const riskLabel = (risk) => (risk === "blocked" ? "已阻断" : risk === "review" ? "需复核" : "安全");
815
+ const riskClass = (risk) => risk === "blocked" ? "bg-[#fff0f0] text-[#b42318]" : risk === "review" ? "bg-[#fff7e8] text-[#a15c00]" : "bg-[#eaf8f0] text-[#14733f]";
816
+ return (_jsxs("div", { className: "mt-3 grid gap-3", children: [_jsx("div", { className: "grid grid-cols-3 gap-2", children: [
817
+ ["已阻断", data?.blocked ?? 0],
818
+ ["需复核", data?.review ?? 0],
819
+ ["安全", data?.safe ?? 0],
820
+ ].map(([label, count]) => (_jsxs("div", { className: "rounded-lg border border-[#edf0f3] bg-[#f8fafc] px-3 py-2", children: [_jsx("span", { className: "block text-[10px] text-[#687381]", children: value(label) }), _jsx("strong", { className: "mt-1 block font-mono text-[17px] text-[#30343b]", children: value(count) })] }, value(label)))) }), latest ? (_jsxs("div", { className: `flex items-center justify-between rounded-lg border border-[#e3e7ee] px-3 py-2 text-[10px] ${riskClass(latest.risk)}`, children: [_jsxs("span", { children: ["\u6700\u8FD1\u4E00\u6B21\uFF1A", value(latest.source, "unknown")] }), _jsxs("strong", { children: [riskLabel(latest.risk), " \u00B7 ", value(latest.findings && Array.isArray(latest.findings) ? latest.findings.length : 0), " \u9879"] })] })) : null, receipts.length > 0 ? (_jsxs("ul", { className: "grid gap-1.5", children: [_jsx("li", { className: "text-[9px] uppercase tracking-[0.08em] text-[#687381]", children: "\u6700\u8FD1\u98CE\u9669\u6458\u8981" }), receipts.slice(0, 8).map((entry, index) => {
821
+ const receipt = entry !== null && typeof entry === "object" ? entry : {};
822
+ const findings = Array.isArray(receipt.findings) ? receipt.findings : [];
823
+ return (_jsxs("li", { className: "flex items-center gap-2 rounded-lg border border-[#edf0f3] bg-white px-3 py-2 text-[10px]", children: [_jsx("span", { className: `rounded px-1.5 py-0.5 ${riskClass(receipt.risk)}`, children: riskLabel(receipt.risk) }), _jsx("span", { className: "min-w-0 flex-1 truncate font-mono text-[#65707b]", children: value(receipt.source, "unknown") }), _jsxs("span", { className: "text-[#687381]", children: [findings.length, " \u9879"] })] }, `${value(receipt.source)}-${index}`));
824
+ })] })) : (_jsx("div", { className: "rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3 text-[11px] text-[#687381]", children: "\u5C1A\u672A\u6536\u5230\u5DE5\u5177\u8C03\u7528\u3002Agent \u53EF\u8C03\u7528 hol_guard_scan \u9884\u68C0\u547D\u4EE4\u6216\u6587\u672C\u3002" })), _jsx("div", { className: "text-[10px] text-[#687381]", children: "\u4EC5\u4FDD\u5B58\u98CE\u9669\u6458\u8981\u548C\u8BA1\u6570\uFF0C\u4E0D\u4FDD\u5B58\u547D\u4EE4\u3001\u8DEF\u5F84\u6216\u51ED\u636E\u539F\u6587\uFF1B\u5F53\u524D\u6A21\u5F0F\u4E3A\u5BA1\u8BA1\u3002" })] }));
825
+ })()) : panel.id === "synapse-panel" ? ((() => {
826
+ const nodes = Array.isArray(data?.nodes) ? data.nodes : [];
827
+ const edges = Array.isArray(data?.edges) ? data.edges : [];
828
+ const nodeById = new Map(nodes.filter((entry) => entry !== null && typeof entry === "object").map((entry) => [value(entry.id), entry]));
829
+ return (_jsxs("div", { className: "mt-3 grid gap-3", children: [_jsx("div", { className: "grid grid-cols-3 gap-2", children: [
830
+ ["会话", data?.nodes ?? 0],
831
+ ["分支", data?.edges ?? 0],
832
+ ["孤儿", data?.orphanCount ?? 0],
833
+ ].map(([label, count]) => (_jsxs("div", { className: "rounded-lg border border-[#edf0f3] bg-[#f8fafc] px-3 py-2", children: [_jsx("span", { className: "block text-[10px] text-[#687381]", children: value(label) }), _jsx("strong", { className: "mt-1 block font-mono text-[17px] text-[#30343b]", children: value(count) })] }, value(label)))) }), data?.activeSessionId ? (_jsxs("div", { className: "rounded-lg border border-[#b9d0ff] bg-[#f1f6ff] px-3 py-2 text-[10px] text-[#315fb8]", children: ["\u5F53\u524D\u4F1A\u8BDD\uFF1A", _jsx("code", { className: "font-mono", children: value(data.activeSessionId) })] })) : null, nodes.length > 0 ? (_jsxs("ul", { className: "grid gap-1.5", children: [_jsxs("li", { className: "text-[9px] uppercase tracking-[0.08em] text-[#687381]", children: ["\u6700\u8FD1\u4F1A\u8BDD ", Math.min(nodes.length, 8), " / ", nodes.length] }), nodes.slice(0, 8).map((entry, index) => {
834
+ const node = entry !== null && typeof entry === "object" ? entry : {};
835
+ return (_jsxs("li", { className: `rounded-lg border px-3 py-2 ${node.active === true ? "border-[#b9d0ff] bg-[#f7faff]" : "border-[#edf0f3] bg-white"}`, children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: `h-2 w-2 shrink-0 rounded-full ${node.active === true ? "bg-[#3565c5]" : "bg-[#c4ccd6]"}` }), _jsx("strong", { className: "min-w-0 flex-1 truncate text-[11px] text-[#30343b]", children: value(node.label ?? node.sessionId ?? "未命名会话") }), _jsxs("span", { className: "font-mono text-[9px] text-[#687381]", children: [value(node.messageCount ?? 0), " \u6761\u6D88\u606F"] })] }), _jsxs("div", { className: "mt-1 flex items-center gap-2 text-[9px] text-[#687381]", children: [_jsx("span", { className: "min-w-0 flex-1 truncate font-mono", children: value(node.cwd ?? "未知工作区") }), _jsxs("span", { children: [value(node.branchCount ?? 0), " \u4E2A\u5206\u652F"] })] })] }, `${value(node.id ?? "session")}-${index}`));
836
+ })] })) : (_jsx("div", { className: "rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3 text-[11px] text-[#687381]", children: "\u5F53\u524D\u5DE5\u4F5C\u533A\u8FD8\u6CA1\u6709\u53EF\u6295\u5F71\u7684\u6301\u4E45\u5316\u4F1A\u8BDD\u3002" })), edges.length > 0 ? (_jsxs("div", { className: "grid gap-1 rounded-lg border border-[#edf0f3] bg-[#fbfcfd] px-3 py-2", children: [_jsx("span", { className: "text-[9px] uppercase tracking-[0.08em] text-[#687381]", children: "Fork \u5173\u7CFB" }), edges.slice(0, 5).map((entry, index) => {
837
+ const edge = entry !== null && typeof entry === "object" ? entry : {};
838
+ const from = nodeById.get(value(edge.from));
839
+ const to = nodeById.get(value(edge.to));
840
+ return (_jsxs("div", { className: "flex min-w-0 items-center gap-1.5 font-mono text-[9px] text-[#65707b]", children: [_jsx("span", { className: "truncate", children: value(from?.label ?? edge.from) }), _jsx("span", { className: "shrink-0 text-[#3565c5]", children: "\u2192 fork \u2192" }), _jsx("span", { className: "truncate", children: value(to?.label ?? edge.to) })] }, `${value(edge.from)}-${value(edge.to)}-${index}`));
841
+ })] })) : null, _jsx("div", { className: "text-[10px] text-[#687381]", children: "\u6570\u636E\u6765\u6E90\uFF1APi \u539F\u751F JSONL \u4F1A\u8BDD\uFF1BAgent \u53EF\u8C03\u7528 synapse_session_map \u5237\u65B0\u3002" })] }));
842
+ })()) : panel.id === "archify-panel" ? (_jsx("div", { className: "mt-3 grid gap-3", children: data?.latest && typeof data.latest === "object" ? ((() => {
843
+ const report = data.latest;
844
+ const components = Array.isArray(report.components) ? report.components : [];
845
+ const dependencies = Array.isArray(report.dependencies) ? report.dependencies : [];
846
+ return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "grid grid-cols-2 gap-2", children: [_jsxs("div", { className: "rounded-lg bg-[#f6f8fa] px-3 py-2", children: [_jsx("span", { className: "block text-[10px] text-[#687381]", children: "\u7EC4\u4EF6" }), _jsx("strong", { className: "mt-1 block text-[17px] text-[#30343b]", children: value(components.length) })] }), _jsxs("div", { className: "rounded-lg bg-[#f6f8fa] px-3 py-2", children: [_jsx("span", { className: "block text-[10px] text-[#687381]", children: "\u5916\u90E8\u4F9D\u8D56" }), _jsx("strong", { className: "mt-1 block text-[17px] text-[#30343b]", children: value(dependencies.length) })] })] }), _jsx("div", { className: "grid gap-1.5", children: components.slice(0, 8).map((entry, index) => {
847
+ const component = entry !== null && typeof entry === "object" ? entry : {};
848
+ return (_jsxs("div", { className: "flex items-center gap-2 rounded-lg border border-[#edf0f3] bg-white px-3 py-2 text-[11px]", children: [_jsx("span", { className: "h-2 w-2 rounded-full bg-[#3565c5]" }), _jsx("span", { className: "min-w-0 flex-1 truncate font-mono text-[#30343b]", children: value(component.path ?? "组件") }), _jsxs("span", { className: "font-mono text-[10px] text-[#687381]", children: [value(component.files ?? 0), " files"] })] }, `${value(component.path ?? "component")}-${index}`));
849
+ }) }), dependencies.length > 0 ? (_jsx("div", { className: "flex flex-wrap gap-1.5", children: dependencies.slice(0, 12).map((dependency, index) => (_jsx("span", { className: "rounded-md border border-[#dce5f5] bg-[#f6f8ff] px-2 py-1 font-mono text-[10px] text-[#315fb8]", children: value(dependency) }, `${value(dependency)}-${index}`))) })) : null, _jsx("pre", { className: "max-h-48 overflow-auto rounded-lg border border-[#edf0f3] bg-[#fbfcfd] p-3 text-[10px] leading-4 text-[#65707b]", children: value(report.mermaid, "") }), report.truncated === true ? _jsx("p", { className: "text-[10px] text-[#8a5a00]", children: "\u626B\u63CF\u8FBE\u5230\u8282\u70B9\u4E0A\u9650\uFF0C\u67B6\u6784\u56FE\u53EF\u80FD\u4E0D\u5B8C\u6574\u3002" }) : null] }));
850
+ })()) : (_jsx("div", { className: "rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3 text-[11px] text-[#687381]", children: "Agent \u53EF\u8C03\u7528 architecture_map \u751F\u6210\u5F53\u524D\u5DE5\u4F5C\u533A\u67B6\u6784\u56FE\u3002" })) })) : panel.id === "canvas-draw-panel" ? (_jsxs("div", { className: "mt-3 grid gap-3", children: [_jsxs("div", { className: "flex items-center justify-between rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3 text-[11px]", children: [_jsx("span", { className: "font-medium text-[#30343b]", children: "Mermaid \u6D41\u7A0B\u56FE" }), _jsxs("span", { className: "font-mono text-[#3565c5]", children: [value(data?.nodeCount ?? 0), " \u8282\u70B9 \u00B7 ", value(data?.edgeCount ?? 0), " \u8FDE\u7EBF"] })] }), data?.latest && typeof data.latest === "object" ? (_jsx("pre", { className: "max-h-48 overflow-auto rounded-lg border border-[#edf0f3] bg-[#fbfcfd] p-3 text-[10px] leading-4 text-[#65707b]", children: value(data.latest.mermaid, "") })) : (_jsx("div", { className: "rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3 text-[11px] text-[#687381]", children: "Agent \u53EF\u8C03\u7528 canvas_draw \u751F\u6210\u6D41\u7A0B\u56FE\u6E90\u7801\u3002" }))] })) : panel.id === "image-compressor-panel" ? (_jsxs("div", { className: "mt-3 grid gap-3", children: [_jsxs("div", { className: "flex items-center justify-between rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3 text-[11px]", children: [_jsx("span", { className: "font-medium text-[#30343b]", children: "PNG \u65E0\u635F\u538B\u7F29" }), _jsx("span", { className: "font-mono text-[#65707b]", children: "\u4E0A\u9650 32 MiB" })] }), data?.last && typeof data.last === "object" ? ((() => {
851
+ const report = data.last;
852
+ return (_jsxs("div", { className: "rounded-lg border border-[#b9e6c9] bg-[#f0fbf4] px-3 py-3 text-[11px] text-[#14733f]", children: [value(report.inputPath ?? "图片"), " \u2192 ", value(report.outputPath ?? "输出"), "\uFF0C\u8282\u7701 ", value(report.savedBytes ?? 0), " bytes"] }));
853
+ })()) : (_jsx("div", { className: "rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3 text-[11px] text-[#687381]", children: "Agent \u53EF\u8C03\u7528 image_compress\uFF0C\u5199\u5165\u524D\u5FC5\u987B confirm=true\u3002" }))] })) : panel.id === "workspace-search-panel" ? (_jsxs("div", { className: "mt-3 grid gap-3", children: [_jsxs("div", { className: "flex items-center justify-between rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3 text-[11px]", children: [_jsx("span", { className: "font-medium text-[#30343b]", children: "\u5DE5\u4F5C\u533A\u6587\u672C\u68C0\u7D22" }), _jsxs("span", { className: "font-mono text-[#3565c5]", children: [value(data?.matchCount ?? 0), " \u4E2A\u5339\u914D"] })] }), data?.latest && typeof data.latest === "object" ? ((() => {
854
+ const report = data.latest;
855
+ const matches = Array.isArray(report.matches) ? report.matches : [];
856
+ return matches.length > 0 ? (_jsx("ul", { className: "grid gap-1.5", children: matches.slice(0, 5).map((match, index) => {
857
+ const item = match && typeof match === "object" ? match : {};
858
+ return (_jsxs("li", { className: "rounded-lg border border-[#edf0f3] bg-white px-3 py-2", children: [_jsxs("strong", { className: "block truncate font-mono text-[10px] text-[#3565c5]", children: [value(item.path ?? "未知文件"), ":", value(item.line ?? "?")] }), _jsx("p", { className: "mt-1 truncate font-mono text-[10px] text-[#65707b]", children: value(item.text, "") })] }, `${value(item.path ?? "match")}-${index}`));
859
+ }) })) : (_jsx("div", { className: "rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3 text-[11px] text-[#687381]", children: "\u6CA1\u6709\u627E\u5230\u5339\u914D\u5185\u5BB9\u3002" }));
860
+ })()) : (_jsx("div", { className: "rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3 text-[11px] text-[#687381]", children: "Agent \u53EF\u8C03\u7528 workspace_search \u68C0\u7D22\u5F53\u524D\u5DE5\u4F5C\u533A\u3002" }))] })) : panel.id === "recall-unread-panel" ? (_jsxs("div", { className: "mt-3 grid gap-3", children: [_jsxs("div", { className: "flex items-center justify-between rounded-lg border border-[#dce5f5] bg-[#f6f8ff] px-3 py-3 text-[11px]", children: [_jsx("span", { className: "font-medium text-[#30343b]", children: "\u672A\u56DE\u7B54\u4F1A\u8BDD" }), _jsxs("strong", { className: "font-mono text-[#3565c5]", children: [value(data?.total ?? 0), " \u4E2A"] })] }), Array.isArray(data?.items) && data.items.length > 0 ? (_jsx("div", { className: "grid gap-2", children: data.items.slice(0, 8).map((item, index) => {
861
+ const session = item !== null && typeof item === "object" ? item : {};
862
+ return (_jsxs("div", { className: "rounded-lg border border-[#edf0f3] bg-white px-3 py-2", children: [_jsx("strong", { className: "block truncate text-[11px] text-[#30343b]", children: value(session.name ?? session.id ?? "未命名会话") }), _jsx("p", { className: "mt-1 line-clamp-2 text-[10px] leading-4 text-[#65707b]", children: value(session.message ?? "") })] }, `${value(session.id ?? "session")}-${index}`));
863
+ }) })) : (_jsx("div", { className: "rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3 text-[11px] text-[#687381]", children: "\u6CA1\u6709\u4EE5\u672A\u56DE\u7B54\u7528\u6237\u6D88\u606F\u7ED3\u675F\u7684\u4F1A\u8BDD\u3002" }))] })) : panel.id === "turn-rewind-panel" ? (_jsxs("div", { className: "mt-3 grid gap-3", children: [data?.latest && typeof data.latest === "object" ? ((() => {
864
+ const latest = data.latest;
865
+ const target = latest.target !== null && typeof latest.target === "object" ? latest.target : {};
866
+ const cancelled = latest.cancelled === true;
867
+ return (_jsxs("div", { className: `rounded-lg border px-3 py-3 ${cancelled ? "border-[#f4dfb0] bg-[#fffaf0]" : "border-[#dce5f5] bg-[#f6f8ff]"}`, children: [_jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsx("span", { className: "text-[10px] font-semibold uppercase tracking-[0.08em] text-[#687381]", children: "\u6700\u8FD1\u64CD\u4F5C" }), _jsx("span", { className: `rounded-full px-2 py-1 text-[10px] font-semibold ${cancelled ? "bg-[#fff0c7] text-[#9a6700]" : "bg-[#e8f8ee] text-[#14733f]"}`, children: cancelled ? "已取消" : "已回退" })] }), _jsx("p", { className: "mt-2 line-clamp-2 text-[11px] leading-4 text-[#30343b]", children: value(target.text ?? "未命名轮次") })] }));
868
+ })()) : (_jsx("div", { className: "rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3 text-[11px] text-[#687381]", children: "\u8FD8\u6CA1\u6709\u6267\u884C\u56DE\u9000\u64CD\u4F5C\u3002" })), _jsxs("div", { className: "grid gap-2", children: [_jsx("span", { className: "text-[10px] font-semibold uppercase tracking-[0.08em] text-[#687381]", children: "\u53EF\u56DE\u9000\u8F6E\u6B21" }), (() => {
869
+ const candidates = Array.isArray(data?.candidates) ? data.candidates : [];
870
+ return candidates.length > 0 ? (candidates.slice(-8).map((item, index) => {
871
+ const candidate = item !== null && typeof item === "object" ? item : {};
872
+ return (_jsxs("div", { className: "flex items-start gap-2 rounded-lg border border-[#edf0f3] bg-white px-3 py-2", children: [_jsx("span", { className: "mt-0.5 font-mono text-[10px] text-[#3565c5]", children: candidates.length - index }), _jsx("span", { className: "line-clamp-2 min-w-0 flex-1 text-[11px] leading-4 text-[#65707b]", children: value(candidate.text ?? "未命名轮次") })] }, `${value(candidate.entryId ?? "turn")}-${index}`));
873
+ })) : (_jsx("div", { className: "rounded-lg border border-[#edf0f3] bg-white px-3 py-3 text-[11px] text-[#687381]", children: "\u5F53\u524D\u4F1A\u8BDD\u8FD8\u6CA1\u6709\u53EF\u56DE\u9000\u7684\u7528\u6237\u8F6E\u6B21\u3002" }));
874
+ })()] })] })) : panel.id === "skill-guard-panel" ? (_jsxs("div", { className: "mt-3 grid gap-3", children: [_jsx("div", { className: "grid grid-cols-3 gap-2", children: [
875
+ ["已扫描", data?.total ?? 0],
876
+ ["高风险", data?.blocked ?? 0],
877
+ ["待复核", data?.review ?? 0],
878
+ ].map(([label, item]) => (_jsxs("div", { className: "rounded-lg bg-[#f6f8fa] px-3 py-2", children: [_jsx("span", { className: "block text-[10px] text-[#687381]", children: value(label) }), _jsx("strong", { className: "mt-1 block text-[17px] font-semibold text-[#30343b]", children: value(item) })] }, value(label)))) }), _jsx("div", { className: "grid gap-2", children: Array.isArray(data?.reports) && data.reports.length > 0 ? (data.reports.slice(0, 8).map((item, index) => {
879
+ const report = item !== null && typeof item === "object" ? item : {};
880
+ const risk = report.risk;
881
+ const findings = Array.isArray(report.findings) ? report.findings : [];
882
+ return (_jsxs("div", { className: "rounded-lg border border-[#edf0f3] bg-white px-3 py-2", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: `h-2 w-2 rounded-full ${risk === "blocked" ? "bg-[#d64545]" : risk === "review" ? "bg-[#e0a11a]" : "bg-[#22a06b]"}` }), _jsx("strong", { className: "min-w-0 flex-1 truncate text-[11px] text-[#30343b]", children: value(report.name ?? "unknown") }), _jsx("span", { className: "text-[10px] text-[#687381]", children: risk === "blocked" ? "阻断" : risk === "review" ? "复核" : "安全" })] }), findings.length > 0 ? (_jsx("p", { className: "mt-1 truncate text-[10px] text-[#65707b]", children: findings
883
+ .map((finding) => finding !== null && typeof finding === "object" ? value(finding.code ?? "finding") : value(finding))
884
+ .join(" · ") })) : null] }, `${value(report.name ?? "skill")}-${index}`));
885
+ })) : (_jsx("div", { className: "rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3 text-[11px] text-[#687381]", children: "\u6682\u65E0 Skill \u626B\u63CF\u7ED3\u679C\uFF0C\u53EF\u8BA9 Agent \u8C03\u7528 skill_guard_scan\u3002" })) })] })) : panel.id === "prompt-guard-panel" ? (_jsxs("div", { className: "mt-3 grid gap-3", children: [_jsxs("div", { className: `flex items-center justify-between rounded-lg border px-3 py-3 text-[11px] ${data?.risk === "blocked" ? "border-[#f4caca] bg-[#fff5f5] text-[#b42318]" : data?.risk === "review" ? "border-[#f3dfab] bg-[#fffaf0] text-[#9a6700]" : "border-[#b9e6c9] bg-[#f0fbf4] text-[#14733f]"}`, children: [_jsx("span", { children: data?.risk === "blocked" ? "高风险,需阻断" : data?.risk === "review" ? "需要人工复核" : "未发现风险" }), _jsxs("strong", { className: "font-mono", children: [value(data?.scans ?? 0), " \u6B21\u626B\u63CF"] })] }), data?.latest && typeof data.latest === "object" ? ((() => {
886
+ const report = data.latest;
887
+ const findings = Array.isArray(report.findings) ? report.findings : [];
888
+ return findings.length > 0 ? (_jsx("ul", { className: "grid gap-1 rounded-lg border border-[#e3e7ee] bg-white px-4 py-3 text-[10px] text-[#65707b]", children: findings.slice(0, 4).map((finding, index) => {
889
+ const item = finding && typeof finding === "object" ? finding : {};
890
+ return (_jsxs("li", { children: [_jsx("strong", { className: "font-mono text-[#30343b]", children: value(item.code ?? "finding") }), "\uFF1A", value(item.message, "")] }, `${value(item.code ?? "finding")}-${index}`));
891
+ }) })) : (_jsx("div", { className: "rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3 text-[11px] text-[#687381]", children: "\u6700\u8FD1\u4E00\u6B21\u626B\u63CF\u672A\u53D1\u73B0\u98CE\u9669\u3002" }));
892
+ })()) : (_jsx("div", { className: "rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3 text-[11px] text-[#687381]", children: "Agent \u53EF\u8C03\u7528 prompt_guard_scan \u68C0\u67E5\u4E0D\u53EF\u4FE1\u6587\u672C\u3002" }))] })) : panel.id === "code2skill-panel" ? (_jsxs("div", { className: "mt-3 grid gap-3", children: [_jsxs("div", { className: "rounded-lg border border-[#e3eaf8] bg-[#f6f8ff] px-3 py-3", children: [_jsxs("div", { className: "flex items-center justify-between gap-3", children: [_jsx("span", { className: "text-[11px] font-semibold text-[#30343b]", children: "\u5DF2\u751F\u6210\u6280\u80FD" }), _jsx("strong", { className: "font-mono text-[12px] text-[#315fb8]", children: value(data?.generated ?? 0) })] }), data?.latest !== null && data?.latest !== undefined && typeof data.latest === "object" ? (_jsxs("p", { className: "mt-2 truncate text-[11px] text-[#65707b]", children: [value(data.latest.slug ?? "skill"), " \u00B7", " ", value(Array.isArray(data.latest.files) ? data.latest.files.length : 0), " ", "\u4E2A\u53C2\u8003\u6587\u4EF6"] })) : (_jsx("p", { className: "mt-2 text-[11px] text-[#687381]", children: "\u8FD8\u6CA1\u6709\u751F\u6210\u6280\u80FD\u3002\u53EF\u8BA9 Agent \u8C03\u7528 skill_pack_create\u3002" }))] }), _jsx("p", { className: "text-[10px] text-[#687381]", children: "\u8F93\u51FA\u76EE\u5F55\uFF1A\u9879\u76EE .pi/skills/<name>\uFF0C\u5305\u542B SKILL.md \u548C\u539F\u59CB\u53C2\u8003\u6587\u4EF6\u3002" })] })) : panel.id === "genui-panel" ? (_jsxs("div", { className: "mt-3 grid gap-3", children: [data?.latest !== null && data?.latest !== undefined && typeof data.latest === "object" ? ((() => {
893
+ const report = data.latest;
894
+ const blocks = Array.isArray(report.blocks) ? report.blocks : [];
895
+ const toneClass = {
896
+ neutral: "border-[#e3e7ee] bg-[#f6f8fa] text-[#65707b]",
897
+ info: "border-[#d9e4f7] bg-[#f6f8ff] text-[#315fb8]",
898
+ success: "border-[#b9e6c9] bg-[#f0fbf4] text-[#14733f]",
899
+ warning: "border-[#f3dfab] bg-[#fffaf0] text-[#9a6700]",
900
+ danger: "border-[#f4caca] bg-[#fff5f5] text-[#b42318]",
901
+ };
902
+ return (_jsxs("div", { className: "grid gap-2", children: [_jsxs("div", { className: "flex items-center justify-between text-[11px]", children: [_jsx("strong", { className: "text-[#30343b]", children: value(report.title ?? "结构化卡片") }), _jsxs("span", { className: "font-mono text-[#687381]", children: [value(data.rendered ?? 0), " \u6B21"] })] }), blocks.map((block, index) => {
903
+ const item = block && typeof block === "object" ? block : {};
904
+ const tone = value(item.tone ?? "neutral");
905
+ const blockValue = item.value;
906
+ return item.type === "progress" ? (_jsxs("div", { className: `rounded-lg border px-3 py-2 ${toneClass[tone] ?? toneClass.neutral}`, children: [_jsxs("div", { className: "flex items-center justify-between text-[10px]", children: [_jsx("span", { children: value(item.label ?? "进度") }), _jsxs("strong", { children: [value(blockValue ?? 0), "%"] })] }), _jsx("div", { className: "mt-1 h-1.5 overflow-hidden rounded-full bg-white/70", children: _jsx("div", { className: "h-full rounded-full bg-current", style: { width: `${Math.max(0, Math.min(100, Number(blockValue) || 0))}%` } }) })] }, `${value(item.label)}-${index}`)) : (_jsxs("div", { className: `flex items-center justify-between rounded-lg border px-3 py-2 text-[11px] ${toneClass[tone] ?? toneClass.neutral}`, children: [_jsx("span", { className: "text-[#65707b]", children: value(item.label, "") }), _jsx("strong", { children: value(blockValue, "") })] }, `${value(item.label)}-${index}`));
907
+ })] }));
908
+ })()) : (_jsx("div", { className: "rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3 text-[11px] text-[#687381]", children: "\u8FD8\u6CA1\u6709\u7ED3\u6784\u5316\u5361\u7247\u3002\u53EF\u8BA9 Agent \u8C03\u7528 genui_render\u3002" })), _jsx("p", { className: "text-[10px] text-[#687381]", children: "\u4EC5\u6E32\u67D3\u7ED3\u6784\u5316\u6587\u672C\u3001\u5FBD\u6807\u548C\u8FDB\u5EA6\u5757\uFF1BHTML \u4E0E\u811A\u672C\u6309\u666E\u901A\u6587\u672C\u5904\u7406\u3002" })] })) : panel.id === "anchored-standard-panel" ? (_jsxs("div", { className: "mt-3 grid gap-3", children: [(() => {
909
+ const violations = Array.isArray(data?.violations) ? data.violations : [];
910
+ const violated = data?.status === "violated";
911
+ return (_jsxs(_Fragment, { children: [_jsxs("div", { className: `flex items-center justify-between rounded-lg border px-3 py-3 text-[11px] ${violated ? "border-[#f4caca] bg-[#fff5f5] text-[#b42318]" : "border-[#b9e6c9] bg-[#f0fbf4] text-[#14733f]"}`, children: [_jsx("span", { children: violated ? "轨迹存在违规" : data?.status === "anchored" ? "运行已锚定" : "等待 Agent 运行" }), _jsxs("strong", { className: "font-mono", children: [value(data?.events ?? 0), " \u4E8B\u4EF6"] })] }), _jsxs("div", { className: "grid grid-cols-2 gap-2 text-[10px] text-[#65707b]", children: [_jsxs("div", { className: "rounded-lg bg-[#f6f8fa] px-3 py-2", children: ["\u5DE5\u5177\u8C03\u7528 ", _jsx("strong", { className: "ml-1 text-[#30343b]", children: value(data?.toolCalls ?? 0) })] }), _jsxs("div", { className: "rounded-lg bg-[#f6f8fa] px-3 py-2", children: ["\u8FDD\u89C4\u9879 ", _jsx("strong", { className: "ml-1 text-[#30343b]", children: value(violations.length) })] })] }), violations.length > 0 ? (_jsx("ul", { className: "grid gap-1 rounded-lg border border-[#f4caca] bg-[#fffafa] px-3 py-2 text-[10px] text-[#b42318]", children: violations.slice(0, 4).map((item, index) => (_jsx("li", { children: value(item && typeof item === "object" ? (item.message ?? "违规") : item) }, `${value(item)}-${index}`))) })) : null] }));
912
+ })(), _jsx("p", { className: "text-[10px] text-[#687381]", children: "\u53EF\u8BA9 Agent \u8C03\u7528 trajectory_anchor_check \u5BA1\u8BA1\u5F53\u524D\u6267\u884C\u8F68\u8FF9\u3002" })] })) : panel.id === "telemetry-blocker-panel" ? (_jsxs("div", { className: "mt-3 grid gap-3", children: [_jsxs("div", { className: "flex items-center justify-between rounded-lg border border-[#b9e6c9] bg-[#f0fbf4] px-3 py-3 text-[11px] text-[#14733f]", children: [_jsx("span", { children: "\u9065\u6D4B\u5DF2\u5173\u95ED" }), _jsxs("strong", { className: "font-mono", children: ["\u62E6\u622A ", value(data?.blocked ?? 0), " \u6B21"] })] }), _jsx("div", { className: "rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3 text-[10px] text-[#65707b]", children: Array.isArray(data?.names) && data.names.length > 0 ? `事件名:${data.names.slice(0, 8).map(String).join("、")}` : "尚未收到遥测事件。" }), _jsx("p", { className: "text-[10px] text-[#687381]", children: "\u53EA\u8BB0\u5F55\u4E8B\u4EF6\u540D\u548C\u8BA1\u6570\uFF0C\u4E0D\u4FDD\u7559\u4E8B\u4EF6\u5C5E\u6027\uFF0C\u4E5F\u4E0D\u4F1A\u53D1\u8D77\u7F51\u7EDC\u8BF7\u6C42\u3002" })] })) : panel.id === "plugin-dev-panel" ? (_jsxs("div", { className: "mt-3 grid gap-3", children: [_jsxs("div", { className: `flex items-center justify-between rounded-lg border px-3 py-3 text-[11px] ${data?.status === "reloaded" ? "border-[#b9e6c9] bg-[#f0fbf4] text-[#14733f]" : data?.status === "failed" ? "border-[#f4caca] bg-[#fff5f5] text-[#b42318]" : "border-[#e3e7ee] bg-[#f6f8fa] text-[#65707b]"}`, children: [_jsx("span", { children: data?.status === "reloaded" ? "插件已重载" : data?.status === "failed" ? "插件重载失败" : "等待重载" }), _jsx("strong", { className: "font-mono", children: value(data?.status ?? "idle") })] }), _jsx("p", { className: "text-[10px] text-[#687381]", children: value(data?.reason ?? "修改本地扩展后调用 plugin_dev_reload") }), data?.error ? _jsx("p", { className: "rounded-lg bg-[#fff5f5] px-3 py-2 text-[10px] text-[#b42318]", children: value(data.error) }) : null] })) : panel.id === "openpets-panel" ? (_jsxs("div", { className: "mt-3 grid gap-3", children: [_jsxs("div", { className: "flex items-center gap-3 rounded-lg border border-[#e3e7ee] bg-[#f8fafc] px-3 py-3", children: [_jsx("span", { className: "flex h-10 w-10 items-center justify-center rounded-full bg-[#dceaff] text-[20px] text-[#3565c5]", children: "\u25C9" }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("strong", { className: "block truncate text-[13px] text-[#30343b]", children: value(data?.name ?? "Pi") }), _jsx("span", { className: "text-[10px] text-[#687381]", children: value(data?.lastEvent ?? "session_start") })] }), _jsx("span", { className: "rounded-full bg-[#edf3fe] px-2 py-1 text-[10px] text-[#3565c5]", children: value(data?.mood ?? "idle") })] }), _jsxs("div", { className: "grid grid-cols-2 gap-2 text-[10px] text-[#65707b]", children: [_jsxs("div", { className: "rounded-lg bg-[#f6f8fa] px-3 py-2", children: ["\u80FD\u91CF ", _jsxs("strong", { className: "ml-1 text-[#30343b]", children: [value(data?.energy ?? 0), "%"] })] }), _jsxs("div", { className: "rounded-lg bg-[#f6f8fa] px-3 py-2", children: ["\u4E92\u52A8 ", _jsx("strong", { className: "ml-1 text-[#30343b]", children: value(data?.interactions ?? 0) })] })] }), _jsx("p", { className: "text-[10px] text-[#687381]", children: "\u6839\u636E\u771F\u5B9E Pi \u4F1A\u8BDD\u4E8B\u4EF6\u81EA\u52A8\u53CD\u5E94\uFF0C\u4E5F\u53EF\u8BA9 Agent \u8C03\u7528 pet_react \u8FDB\u884C\u4E92\u52A8\u3002" })] })) : panel.id === "change-verifier-panel" ? (_jsxs("div", { className: "mt-3 grid gap-3", children: [data?.latest !== null && data?.latest !== undefined && typeof data.latest === "object" ? ((() => {
913
+ const report = data.latest;
914
+ const tests = report.tests && typeof report.tests === "object" ? report.tests : {};
915
+ const review = report.review && typeof report.review === "object" ? report.review : {};
916
+ const status = value(report.status ?? "fail");
917
+ return (_jsxs(_Fragment, { children: [_jsxs("div", { className: `flex items-center justify-between rounded-lg border px-3 py-3 text-[11px] ${status === "pass" ? "border-[#b9e6c9] bg-[#f0fbf4] text-[#14733f]" : status === "warning" ? "border-[#f3dfab] bg-[#fffaf0] text-[#9a6700]" : "border-[#f4caca] bg-[#fff5f5] text-[#b42318]"}`, children: [_jsx("span", { children: status === "pass" ? "门禁通过" : status === "warning" ? "门禁有警告" : "门禁失败" }), _jsxs("strong", { className: "font-mono", children: [value(data.runs ?? 0), " \u6B21"] })] }), _jsxs("div", { className: "grid grid-cols-2 gap-2 text-[10px] text-[#65707b]", children: [_jsxs("div", { className: "rounded-lg bg-[#f6f8fa] px-3 py-2", children: ["\u6D4B\u8BD5 exit ", _jsx("strong", { className: "ml-1 text-[#30343b]", children: value(tests.exitCode ?? "—") })] }), _jsxs("div", { className: "rounded-lg bg-[#f6f8fa] px-3 py-2", children: ["\u5BA1\u67E5 ", _jsx("strong", { className: "ml-1 text-[#30343b]", children: value(review.status ?? "—") })] })] })] }));
918
+ })()) : (_jsx("div", { className: "rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3 text-[11px] text-[#687381]", children: "\u8FD8\u6CA1\u6709\u6267\u884C\u53D1\u5E03\u95E8\u7981\u3002\u53EF\u8BA9 Agent \u8C03\u7528 verify_change_gate\u3002" })), _jsx("p", { className: "text-[10px] text-[#687381]", children: "\u590D\u7528 run_project_tests \u548C review_changes\uFF0C\u4E0D\u91CD\u590D\u5B9E\u73B0\u6D4B\u8BD5\u6216\u5BA1\u67E5\u903B\u8F91\u3002" })] })) : panel.id === "readme-gen-panel" ? (_jsx("div", { className: "mt-3 grid gap-3", children: data?.generated === true ? (_jsxs(_Fragment, { children: [_jsxs("div", { className: "rounded-lg border border-[#b9e6c9] bg-[#f0fbf4] px-3 py-3 text-[11px] text-[#14733f]", children: ["\u5DF2\u751F\u6210 ", value(data.name ?? "项目"), " \u7684 README \u6982\u89C8\uFF1A", value(data.scripts ?? 0), " \u4E2A\u811A\u672C\uFF0C", value(data.plugins ?? 0), " \u4E2A\u8FD0\u884C\u65F6\u63D2\u4EF6\u3002"] }), data.lastWrite && typeof data.lastWrite === "object" ? (_jsxs("div", { className: "rounded-lg border border-[#dce5f5] bg-[#f6f8ff] px-3 py-2 text-[11px] text-[#315fb8]", children: ["\u5DF2\u5199\u5165 ", value(data.lastWrite.path ?? "README.generated.md"), " \u00B7", " ", value(data.lastWrite.bytes ?? 0), " bytes", data.lastWrite.overwritten === true ? " · 已覆盖" : " · 新文件"] })) : null, _jsx("p", { className: "text-[10px] leading-4 text-[#687381]", children: "\u9700\u8981\u843D\u76D8\u65F6\u8C03\u7528 readme_write\uFF0C\u5E76\u663E\u5F0F\u4F20\u5165 confirm=true\uFF1B\u9ED8\u8BA4\u5199\u5165 README.generated.md\u3002" })] })) : (_jsx("div", { className: "rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3 text-[11px] text-[#687381]", children: "\u8FD8\u6CA1\u6709\u751F\u6210\u6587\u6863\u3002\u8BA9 Agent \u8C03\u7528 readme_report \u83B7\u53D6 Markdown \u8349\u7A3F\uFF0C\u6216\u8C03\u7528 readme_write \u5199\u5165\u786E\u8BA4\u540E\u7684\u6587\u4EF6\u3002" })) })) : panel.id === "sql-lens-panel" ? (_jsx("div", { className: "mt-3 grid gap-3", children: data?.latest !== null && data?.latest !== undefined && typeof data.latest === "object" ? ((() => {
919
+ const report = data.latest;
920
+ const rows = Array.isArray(report.rows) ? report.rows : [];
921
+ return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex items-center justify-between rounded-lg bg-[#f6f8fa] px-3 py-3", children: [_jsx("span", { className: "truncate font-mono text-[11px] text-[#30343b]", children: value(report.database ?? "database") }), _jsxs("strong", { className: "font-mono text-[12px] text-[#3565c5]", children: [value(rows.length), " rows"] })] }), _jsx("pre", { className: "max-h-48 overflow-auto rounded-lg border border-[#edf0f3] bg-[#fbfcfd] p-3 text-[10px] leading-4 text-[#65707b]", children: JSON.stringify(rows, null, 2) })] }));
922
+ })()) : (_jsx("div", { className: "rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3 text-[11px] text-[#687381]", children: "\u8FD8\u6CA1\u6709\u67E5\u8BE2\u6570\u636E\u5E93\u3002\u53EF\u8BA9 Agent \u8C03\u7528 sql_readonly\u3002" })) })) : panel.id === "theme-studio-panel" ? (_jsxs("div", { className: "mt-3 grid gap-3", children: [_jsxs("div", { className: "flex items-center justify-between rounded-lg border border-[#dce5f5] bg-[#f6f8ff] px-3 py-3", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("strong", { className: "block text-[12px] text-[#30343b]", children: value(data?.label ?? "Light") }), _jsx("p", { className: "mt-1 truncate text-[10px] text-[#65707b]", children: value(data?.description ?? "") })] }), _jsx("span", { className: "shrink-0 rounded-full bg-[#edf3fe] px-2 py-1 font-mono text-[10px] text-[#3565c5]", children: value(data?.theme ?? "light") })] }), Array.isArray(data?.presets) ? (_jsx("div", { className: "grid grid-cols-2 gap-2", children: data.presets.map((preset, index) => {
923
+ const item = preset !== null && typeof preset === "object" ? preset : {};
924
+ const selected = item.id === data.theme;
925
+ return (_jsxs("div", { className: `rounded-lg border px-3 py-2 ${selected ? "border-[#9bbcff] bg-[#f6f8ff]" : "border-[#edf0f3] bg-white"}`, children: [_jsx("strong", { className: "block text-[11px] text-[#30343b]", children: value(item.label ?? item.id ?? "主题") }), _jsx("span", { className: "mt-1 block truncate text-[10px] text-[#687381]", children: value(item.description ?? "") })] }, `${value(item.id ?? "theme")}-${index}`));
926
+ }) })) : null, _jsx("p", { className: "text-[10px] leading-4 text-[#687381]", children: "\u53EF\u8BA9 Agent \u8C03\u7528 theme_set \u5207\u6362\u9884\u8BBE\uFF1B\u9009\u62E9\u4F1A\u4FDD\u5B58\u5230\u5F53\u524D session\uFF0C\u5E76\u7531 React \u6839\u8282\u70B9\u5E94\u7528 token\u3002" })] })) : panel.id === "mirage-bridge-panel" ? (_jsxs("div", { className: "mt-3 grid gap-3", children: [_jsxs("div", { className: `rounded-lg border px-3 py-3 ${data?.available === true ? "border-[#b9e6c9] bg-[#f0fbf4]" : data?.available === false ? "border-[#f3dfab] bg-[#fffaf0]" : "border-[#e3e7ee] bg-[#f6f8fa]"}`, children: [_jsxs("div", { className: "flex items-center justify-between gap-3", children: [_jsx("span", { className: "text-[11px] font-semibold text-[#30343b]", children: "\u5B98\u65B9 Mirage CLI" }), _jsx("strong", { className: `text-[11px] ${data?.available === true ? "text-[#14733f]" : data?.available === false ? "text-[#9a6700]" : "text-[#687381]"}`, children: data?.available === true ? "已连接" : data?.available === false ? "未检测到" : "未检查" })] }), _jsx("p", { className: "mt-2 truncate font-mono text-[10px] text-[#65707b]", children: value(data?.version ?? data?.executable ?? "mirage") }), _jsxs("p", { className: "mt-1 text-[11px] text-[#65707b]", children: ["\u865A\u62DF\u5DE5\u4F5C\u533A\uFF1A", value(data?.workspaceId ?? "未配置")] })] }), data?.lastRun && typeof data.lastRun === "object" ? ((() => {
927
+ const run = data.lastRun;
928
+ return (_jsxs("div", { className: `rounded-lg border px-3 py-3 ${run.exitCode === 0 ? "border-[#b9e6c9] bg-[#f0fbf4]" : "border-[#f4caca] bg-[#fff5f5]"}`, children: [_jsxs("div", { className: "flex items-center justify-between gap-3", children: [_jsx("span", { className: "truncate font-mono text-[10px] text-[#30343b]", children: value(run.command ?? "") }), _jsxs("strong", { className: `shrink-0 text-[11px] ${run.exitCode === 0 ? "text-[#14733f]" : "text-[#b42318]"}`, children: ["exit ", value(run.exitCode ?? "—")] })] }), _jsxs("p", { className: "mt-1 text-[10px] text-[#65707b]", children: ["\u8017\u65F6 ", value(run.durationMs ?? 0), " ms"] })] }));
929
+ })()) : (_jsx("div", { className: "rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3 text-[11px] text-[#687381]", children: "\u5148\u8C03\u7528 mirage_doctor \u68C0\u67E5 CLI\uFF0C\u518D\u8C03\u7528 mirage_execute\u3002" })), data?.lastError ? _jsx("p", { className: "text-[10px] leading-4 text-[#9a6700]", children: value(data.lastError) }) : null] })) : panel.id === "docker-sandbox-panel" ? (_jsxs("div", { className: "mt-3 grid gap-3", children: [data?.latest !== null && data?.latest !== undefined && typeof data.latest === "object" ? ((() => {
930
+ const run = data.latest;
931
+ return (_jsxs("div", { className: "rounded-lg border border-[#b9e6c9] bg-[#f0fbf4] px-3 py-3", children: [_jsxs("div", { className: "flex items-center justify-between gap-3", children: [_jsx("span", { className: "truncate font-mono text-[11px] text-[#30343b]", children: value(run.image ?? "image") }), _jsxs("strong", { className: "font-mono text-[12px] text-[#14733f]", children: ["exit ", value(run.exitCode ?? "—")] })] }), _jsx("p", { className: "mt-2 text-[11px] text-[#65707b]", children: Array.isArray(run.command) ? run.command.map((argument) => value(argument)).join(" ") : "argv" })] }));
932
+ })()) : (_jsx("div", { className: "rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3 text-[11px] text-[#687381]", children: "\u8FD8\u6CA1\u6709\u6C99\u7BB1\u8FD0\u884C\u3002\u9ED8\u8BA4\u65E0\u7F51\u7EDC\u3001\u5DE5\u4F5C\u533A\u53EA\u8BFB\u3002" })), _jsx("div", { className: "flex flex-wrap gap-2", children: data?.defaults !== null && typeof data?.defaults === "object"
933
+ ? Object.entries(data.defaults).map(([key, entryValue]) => (_jsxs("span", { className: "rounded-md border border-[#dce5f5] bg-white px-2 py-1 font-mono text-[10px] text-[#3565c5]", children: [key, ":", value(entryValue)] }, key)))
934
+ : null })] })) : panel.id === "yaml-validator-panel" ? (_jsxs("div", { className: "mt-3 grid gap-3", children: [data?.latest !== null && data?.latest !== undefined && typeof data.latest === "object" ? ((() => {
935
+ const report = data.latest;
936
+ const errors = Array.isArray(report.errors) ? report.errors : [];
937
+ const warnings = Array.isArray(report.warnings) ? report.warnings : [];
938
+ const valid = report.valid === true;
939
+ return (_jsxs(_Fragment, { children: [_jsx("div", { className: `rounded-lg border px-3 py-3 text-[11px] ${valid ? "border-[#b9e6c9] bg-[#f0fbf4] text-[#14733f]" : "border-[#f4caca] bg-[#fff5f5] text-[#b42318]"}`, children: valid ? "YAML 语法有效。" : `发现 ${errors.length} 个语法错误。` }), _jsx("div", { className: "grid grid-cols-3 gap-2", children: [
940
+ ["文档", report.documents ?? 0],
941
+ ["错误", errors.length],
942
+ ["警告", warnings.length],
943
+ ].map(([label, entryValue]) => (_jsxs("div", { className: "rounded-lg bg-[#f6f8fa] px-3 py-2", children: [_jsx("span", { className: "block text-[10px] text-[#687381]", children: value(label) }), _jsx("strong", { className: "mt-1 block text-[17px] text-[#30343b]", children: value(entryValue) })] }, value(label)))) }), !valid && errors.length > 0 ? (_jsx("pre", { className: "max-h-32 overflow-auto rounded-lg border border-[#f4caca] bg-[#fffafa] p-3 text-[10px] leading-4 text-[#b42318]", children: errors
944
+ .map((error) => typeof error === "object" && error !== null
945
+ ? `${value(error.line ?? "?")}:${value(error.column ?? "?")} ${value(error.message, "")}`
946
+ : value(error))
947
+ .join("\n") })) : null] }));
948
+ })()) : (_jsx("div", { className: "rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3 text-[11px] text-[#687381]", children: "\u8FD8\u6CA1\u6709\u6821\u9A8C YAML\u3002\u53EF\u8BA9 Agent \u8C03\u7528 yaml_validate\u3002" })), _jsx("span", { className: "rounded-md border border-[#dce5f5] bg-white px-2 py-1 font-mono text-[10px] text-[#3565c5]", children: "max:512KiB \u00B7 read-only" })] })) : panel.id === "browser-session-panel" ? ((() => {
949
+ const tabs = Array.isArray(data?.tabs)
950
+ ? browserSessionTabs(data.tabs.flatMap((tab) => {
951
+ if (tab === null || typeof tab !== "object")
952
+ return [];
953
+ const item = tab;
954
+ return typeof item.targetId === "string" && typeof item.url === "string"
955
+ ? [{ targetId: item.targetId, title: typeof item.title === "string" ? item.title : "", url: item.url }]
956
+ : [];
957
+ }), 8)
958
+ : [];
959
+ const latest = data?.latest !== null && data?.latest !== undefined && typeof data.latest === "object" ? data.latest : undefined;
960
+ const latestAction = latest?.screenshot
961
+ ? "已截图"
962
+ : latest?.clicked === true
963
+ ? "已点击"
964
+ : latest?.text
965
+ ? "已读取"
966
+ : latest?.status === "navigated"
967
+ ? "已导航"
968
+ : undefined;
969
+ return (_jsxs("div", { className: "mt-3 grid gap-3", children: [_jsxs("div", { className: "rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3", children: [_jsxs("div", { className: "flex items-center justify-between gap-3", children: [_jsx("span", { className: "truncate font-mono text-[11px] text-[#30343b]", children: value(data?.endpoint ?? "本地浏览器未连接") }), _jsx("span", { className: `rounded-full px-2 py-1 text-[10px] font-semibold ${data?.connected === true ? "bg-[#e8f8ee] text-[#14733f]" : "bg-[#fff4e5] text-[#8a5a00]"}`, children: data?.connected === true ? "已连接" : "未连接" })] }), _jsxs("p", { className: "mt-2 text-[11px] text-[#687381]", children: ["Chrome DevTools Protocol \u00B7 ", tabs.length, " \u4E2A\u53EF\u8C03\u8BD5\u9875\u9762"] }), data?.connected === false ? (_jsxs("p", { className: "mt-2 text-[11px] text-[#b42318]", children: ["\u8BF7\u4F7F\u7528 remote-debugging-port \u542F\u52A8 Chrome\u3002", value(data.error, "")] })) : null] }), latestAction ? (_jsxs("div", { className: "flex items-center justify-between rounded-lg border border-[#dce5f5] bg-[#f6f8ff] px-3 py-2 text-[11px]", children: [_jsx("span", { className: "text-[#65707b]", children: "\u6700\u8FD1\u52A8\u4F5C" }), _jsx("strong", { className: "font-mono text-[#315fb8]", children: latestAction })] })) : null, tabs.length > 0 ? (_jsx("div", { className: "grid gap-2", children: tabs.map((tab) => (_jsxs("div", { className: "rounded-lg border border-[#e3e7ee] bg-white px-3 py-2", children: [_jsx("strong", { className: "block truncate text-[11px] text-[#30343b]", children: tab.title }), _jsx("span", { className: "mt-1 block truncate font-mono text-[10px] text-[#687381]", children: tab.url })] }, tab.targetId))) })) : (_jsx("div", { className: "rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3 text-[11px] text-[#687381]", children: "\u6CA1\u6709\u53EF\u8C03\u8BD5\u7684\u6D4F\u89C8\u5668\u9875\u9762\u3002" })), _jsxs("div", { className: "flex flex-wrap gap-2 text-[10px] text-[#687381]", children: [_jsx("span", { className: "rounded-md border border-[#dce5f5] bg-white px-2 py-1 font-mono text-[#3565c5]", children: "tabs" }), _jsx("span", { className: "rounded-md border border-[#dce5f5] bg-white px-2 py-1 font-mono text-[#3565c5]", children: "read" }), _jsx("span", { className: "rounded-md border border-[#dce5f5] bg-white px-2 py-1 font-mono text-[#3565c5]", children: "click" }), _jsx("span", { className: "rounded-md border border-[#dce5f5] bg-white px-2 py-1 font-mono text-[#3565c5]", children: "screenshot" })] })] }));
970
+ })()) : panel.id === "mcp-client-panel" ? (_jsxs("div", { className: "mt-3 grid gap-3", children: [_jsxs("div", { className: "rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3", children: [_jsxs("div", { className: "flex items-center justify-between gap-3", children: [_jsx("span", { className: "truncate font-mono text-[11px] text-[#30343b]", children: value(data?.server ?? "尚未连接 MCP 服务器") }), _jsxs("div", { className: "flex shrink-0 items-center gap-2 font-mono text-[10px] text-[#3565c5]", children: [_jsxs("span", { children: [value(Array.isArray(data?.tools) ? data.tools.length : 0), " \u5DE5\u5177"] }), _jsx("span", { className: "text-[#687381]", children: "\u00B7" }), _jsxs("span", { children: [value(Array.isArray(data?.resources) ? data.resources.length : 0), " \u8D44\u6E90"] }), _jsx("span", { className: "text-[#687381]", children: "\u00B7" }), _jsxs("span", { children: [value(Array.isArray(data?.prompts) ? data.prompts.length : 0), " \u63D0\u793A"] })] })] }), _jsx("p", { className: "mt-2 text-[11px] text-[#687381]", children: data?.lastCall === null || data?.lastCall === undefined ? "使用 mcp_list_tools 发现 stdio 工具。" : `最近调用:${value(data.lastCall)}` })] }), Array.isArray(data?.tools) && data.tools.length > 0 ? (_jsx("div", { className: "flex flex-wrap gap-2", children: data.tools.slice(0, 12).map((tool, index) => {
971
+ const item = typeof tool === "object" && tool !== null ? tool : {};
972
+ return (_jsx("span", { className: "rounded-md border border-[#dce5f5] bg-white px-2 py-1 font-mono text-[10px] text-[#3565c5]", children: value(item.name ?? "tool") }, `${value(item.name ?? "tool")}-${index}`));
973
+ }) })) : null, Array.isArray(data?.resources) && data.resources.length > 0 ? (_jsxs("div", { className: "grid gap-2", children: [_jsx("span", { className: "text-[10px] font-semibold uppercase tracking-[0.12em] text-[#687381]", children: "\u8D44\u6E90" }), _jsx("div", { className: "flex flex-wrap gap-2", children: data.resources.slice(0, 8).map((resource, index) => {
974
+ const item = typeof resource === "object" && resource !== null ? resource : {};
975
+ return (_jsx("span", { className: "rounded-md border border-[#dce5f5] bg-white px-2 py-1 font-mono text-[10px] text-[#65707b]", children: value(item.name ?? item.uri ?? "resource") }, `${value(item.uri ?? "resource")}-${index}`));
976
+ }) })] })) : null, Array.isArray(data?.prompts) && data.prompts.length > 0 ? (_jsxs("div", { className: "grid gap-2", children: [_jsx("span", { className: "text-[10px] font-semibold uppercase tracking-[0.12em] text-[#687381]", children: "\u63D0\u793A\u6A21\u677F" }), _jsx("div", { className: "flex flex-wrap gap-2", children: data.prompts.slice(0, 8).map((prompt, index) => {
977
+ const item = typeof prompt === "object" && prompt !== null ? prompt : {};
978
+ return (_jsx("span", { className: "rounded-md border border-[#dce5f5] bg-white px-2 py-1 font-mono text-[10px] text-[#65707b]", children: value(item.name ?? "prompt") }, `${value(item.name ?? "prompt")}-${index}`));
979
+ }) })] })) : null, Array.isArray(data?.servers) && data.servers.length > 0 ? (_jsx("div", { className: "grid gap-2", children: data.servers.map((server, index) => {
980
+ const item = typeof server === "object" && server !== null ? server : {};
981
+ return (_jsxs("div", { className: "flex items-center justify-between rounded-lg border border-[#e3e7ee] bg-white px-3 py-2 text-[10px]", children: [_jsx("span", { className: "font-mono text-[#30343b]", children: value(item.id ?? "server") }), _jsx("span", { className: "text-[#14733f]", children: value(item.status ?? "unknown") })] }, `${value(item.id ?? "server")}-${index}`));
982
+ }) })) : null] })) : panel.id === "mcp-panel" ? ((() => {
983
+ const servers = Array.isArray(data?.servers) ? data.servers : [];
984
+ return (_jsxs("div", { className: "mt-3 grid gap-3", children: [servers.length > 0 ? (_jsx("ul", { className: "grid gap-2", children: servers.map((entry, index) => {
985
+ const server = entry !== null && typeof entry === "object" ? entry : {};
986
+ const healthy = server.status === "running";
987
+ return (_jsxs("li", { className: "rounded-lg border border-[#e3e7ee] bg-white px-3 py-2", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("strong", { className: "min-w-0 flex-1 truncate font-mono text-[11px] text-[#30343b]", children: value(server.id, "未命名服务器") }), _jsx("span", { className: `rounded px-1.5 py-0.5 text-[9px] ${healthy ? "bg-[#eaf8f0] text-[#14733f]" : "bg-[#fff5f5] text-[#b42318]"}`, children: value(server.status, "unknown") })] }), _jsxs("div", { className: "mt-1 flex items-center gap-2 text-[10px] text-[#687381]", children: [_jsxs("span", { children: [value(server.toolCount, "0"), " \u4E2A\u6865\u63A5\u5DE5\u5177"] }), _jsx("span", { children: "\u00B7" }), _jsx("span", { children: value(server.statusSource, "runtime") })] })] }, `${value(server.id ?? "server")}-${index}`));
988
+ }) })) : (_jsx("div", { className: "rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3 text-[11px] text-[#687381]", children: "\u5F53\u524D\u6CA1\u6709 MCP \u670D\u52A1\u5668\u5FEB\u7167\u3002" })), _jsxs("div", { className: "text-[10px] text-[#687381]", children: ["\u53EA\u8BFB\u8BFB\u53D6\u5B98\u65B9 MCP bridge \u72B6\u6001\uFF1B\u5065\u5EB7\u5EFA\u8BAE\u901A\u8FC7 mcp_panel \u7684 health \u64CD\u4F5C\u67E5\u770B\u3002", data?.writesEnabled === true ? ` 已启用 profile patch 写入:${value(data.patchPath)}` : " profile patch 写入未配置,apply 会被拒绝。"] })] }));
989
+ })()) : panel.id === "mock-server-panel" ? (_jsxs("div", { className: "mt-3 grid gap-3", children: [_jsxs("div", { className: "flex items-center justify-between rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3", children: [_jsx("span", { className: "font-mono text-[11px] text-[#30343b]", children: data?.running === true ? "运行中" : "未启动" }), _jsxs("strong", { className: "font-mono text-[11px] text-[#3565c5]", children: [value(data?.routes ?? 0), " \u8DEF\u7531"] })] }), data?.url ? _jsx("code", { className: "rounded-md bg-white px-3 py-2 text-[10px] text-[#65707b]", children: value(data.url) }) : null, data?.lastRequest ? _jsxs("p", { className: "text-[11px] text-[#687381]", children: ["\u6700\u8FD1\u8BF7\u6C42\uFF1A", value(data.lastRequest)] }) : null] })) : panel.id === "cli-notifier-panel" ? (_jsxs("div", { className: "mt-3 grid gap-3", children: [_jsxs("div", { className: "flex items-center justify-between rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3", children: [_jsx("span", { className: "font-mono text-[11px] text-[#30343b]", children: data?.enabled === true ? "已启用" : "已停用" }), _jsx("span", { className: "font-mono text-[10px] text-[#687381]", children: value(data?.platform ?? "unknown") })] }), Array.isArray(data?.notifications) && data.notifications.length > 0 ? (_jsx("div", { className: "grid gap-2", children: data.notifications.slice(0, 5).map((notification, index) => {
990
+ const item = typeof notification === "object" && notification !== null ? notification : {};
991
+ return (_jsxs("div", { className: "rounded-lg border border-[#e3e7ee] bg-white px-3 py-2 text-[10px]", children: [_jsx("strong", { className: "block text-[#30343b]", children: value(item.title ?? "Pi Harness") }), _jsx("span", { className: "mt-1 block text-[#65707b]", children: value(item.message, "") })] }, `${value(item.time ?? "notification")}-${index}`));
992
+ }) })) : (_jsx("div", { className: "rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3 text-[11px] text-[#687381]", children: "\u8FD8\u6CA1\u6709\u53D1\u9001\u901A\u77E5\u3002" }))] })) : panel.id === "obsidian-sync-panel" ? (_jsxs("div", { className: "mt-3 grid gap-3", children: [_jsxs("div", { className: "flex items-center justify-between rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3", children: [_jsx("span", { className: "font-mono text-[11px] text-[#30343b]", children: data?.configured === true ? "已配置" : "未配置 vault" }), _jsx("span", { className: "font-mono text-[10px] text-[#687381]", children: "Markdown" })] }), data?.vaultPath ? _jsx("code", { className: "truncate rounded-md bg-white px-3 py-2 text-[10px] text-[#65707b]", children: value(data.vaultPath) }) : null, data?.last !== null && data?.last !== undefined && typeof data.last === "object" ? (_jsxs("p", { className: "text-[11px] text-[#687381]", children: ["\u6700\u8FD1\u5199\u5165\uFF1A", value(data.last.relativePath ?? "note.md")] })) : (_jsx("div", { className: "rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3 text-[11px] text-[#687381]", children: "\u8FD8\u6CA1\u6709\u540C\u6B65\u7B14\u8BB0\u3002" }))] })) : panel.id === "web-research-panel" ? (_jsxs("div", { className: "mt-3 grid gap-3", children: [_jsxs("div", { className: "flex items-center justify-between rounded-lg border border-[#e3eaf8] bg-[#f6f8ff] px-3 py-3 text-[11px]", children: [_jsx("span", { className: "text-[#315fb8]", children: data?.keyless === true ? "Firecrawl 匿名模式" : "Firecrawl 已认证" }), _jsxs("strong", { className: "font-mono text-[#315fb8]", children: ["\u6700\u591A ", value(data?.maxResults ?? 8), " \u6761"] })] }), data?.latest !== null && data?.latest !== undefined && typeof data.latest === "object" ? ((() => {
993
+ const report = data.latest;
994
+ const items = Array.isArray(report.items) ? report.items : [];
995
+ return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex items-center justify-between gap-3 text-[11px]", children: [_jsx("strong", { className: "truncate text-[#30343b]", children: value(report.query ?? "网页搜索") }), _jsxs("span", { className: "shrink-0 font-mono text-[#687381]", children: ["\u524D ", Math.min(8, items.length), " / \u5171 ", items.length] })] }), _jsx("div", { className: "grid gap-2", children: items.slice(0, 8).map((entry, index) => {
996
+ const item = entry !== null && typeof entry === "object" ? entry : {};
997
+ return (_jsxs("a", { className: "rounded-lg border border-[#e3e7ee] bg-white px-3 py-2 transition-colors hover:border-[#bdd0f5] hover:bg-[#fbfdff]", href: value(item.url, ""), rel: "noreferrer", target: "_blank", children: [_jsx("strong", { className: "block truncate text-[11px] text-[#30343b]", children: value(item.title ?? item.url ?? "来源") }), _jsx("span", { className: "mt-1 block truncate font-mono text-[10px] text-[#3565c5]", children: value(item.source ?? item.url, "") }), item.snippet ? _jsx("span", { className: "mt-1 line-clamp-2 block text-[10px] leading-4 text-[#65707b]", children: value(item.snippet) }) : null] }, `${value(item.url ?? "source")}-${index}`));
998
+ }) })] }));
999
+ })()) : (_jsx("div", { className: "rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3 text-[11px] text-[#687381]", children: "\u8FD8\u6CA1\u6709\u8054\u7F51\u641C\u7D22\u3002\u53EF\u8BA9 Agent \u8C03\u7528 web_search\uFF1B\u5355\u9875\u8BFB\u53D6\u4F7F\u7528 read_page\u3002" })), _jsxs("p", { className: "text-[10px] text-[#687381]", children: ["\u641C\u7D22\u8BCD\u4F1A\u53D1\u9001\u5230 Firecrawl\uFF1B\u9875\u9762\u8BFB\u53D6", data?.readPageAvailable === true ? "已复用本地 Browser Fetch" : "需要启用 Browser Fetch", "\u3002"] })] })) : panel.id === "browser-fetch-panel" ? (_jsxs("div", { className: "mt-3 grid gap-3", children: [data?.latest !== null && data?.latest !== undefined && typeof data.latest === "object" ? ((() => {
1000
+ const result = data.latest;
1001
+ return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex items-center justify-between gap-3 rounded-lg bg-[#f6f8fa] px-3 py-3", children: [_jsx("span", { className: "truncate font-mono text-[11px] text-[#30343b]", children: value(result.finalUrl ?? result.url ?? "page") }), _jsxs("strong", { className: "font-mono text-[12px] text-[#14733f]", children: ["HTTP ", value(result.status ?? "—")] })] }), _jsx("pre", { className: "max-h-48 overflow-auto rounded-lg border border-[#edf0f3] bg-[#fbfcfd] p-3 text-[10px] leading-4 text-[#65707b]", children: value(result.text, "") })] }));
1002
+ })()) : (_jsx("div", { className: "rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3 text-[11px] text-[#687381]", children: "\u8FD8\u6CA1\u6709\u6293\u53D6\u7F51\u9875\u3002\u9ED8\u8BA4\u963B\u6B62\u672C\u5730\u548C\u79C1\u6709\u7F51\u7EDC\u76EE\u6807\u3002" })), _jsxs("div", { className: "flex flex-wrap gap-2", children: [_jsx("span", { className: "rounded-md border border-[#dce5f5] bg-white px-2 py-1 font-mono text-[10px] text-[#3565c5]", children: "max:512KiB" }), _jsx("span", { className: "rounded-md border border-[#dce5f5] bg-white px-2 py-1 font-mono text-[10px] text-[#3565c5]", children: "scripts:disabled" }), _jsxs("span", { className: "rounded-md border border-[#dce5f5] bg-white px-2 py-1 font-mono text-[10px] text-[#3565c5]", children: ["private:", value(data?.allowPrivate === true ? "allowed" : "blocked")] })] })] })) : panel.id === "i18n-pair-panel" ? (_jsx("div", { className: "mt-3 grid gap-3", children: data?.report !== null && data?.report !== undefined && typeof data.report === "object" ? ((() => {
1003
+ const report = data.report;
1004
+ const missing = Array.isArray(report.missing) ? report.missing : [];
1005
+ const extra = Array.isArray(report.extra) ? report.extra : [];
1006
+ const healthy = missing.length === 0 && extra.length === 0;
1007
+ return (_jsxs(_Fragment, { children: [_jsx("div", { className: `rounded-lg border px-3 py-3 text-[11px] ${healthy ? "border-[#b9e6c9] bg-[#f0fbf4] text-[#14733f]" : "border-[#f4caca] bg-[#fff5f5] text-[#b42318]"}`, children: healthy ? "语言包键完全一致。" : `缺失 ${missing.length} 个,额外 ${extra.length} 个。` }), _jsxs("div", { className: "grid grid-cols-2 gap-2", children: [_jsxs("div", { className: "rounded-lg bg-[#f6f8fa] px-3 py-2", children: [_jsx("span", { className: "block text-[10px] text-[#687381]", children: "\u57FA\u51C6\u952E" }), _jsx("strong", { className: "mt-1 block text-[17px] text-[#30343b]", children: value(report.baseKeys ?? 0) })] }), _jsxs("div", { className: "rounded-lg bg-[#f6f8fa] px-3 py-2", children: [_jsx("span", { className: "block text-[10px] text-[#687381]", children: "\u76EE\u6807\u952E" }), _jsx("strong", { className: "mt-1 block text-[17px] text-[#30343b]", children: value(report.targetKeys ?? 0) })] })] })] }));
1008
+ })()) : (_jsx("div", { className: "rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3 text-[11px] text-[#687381]", children: "\u8FD8\u6CA1\u6709\u68C0\u67E5\u8BED\u8A00\u5305\u3002\u53EF\u8BA9 Agent \u8C03\u7528 i18n_check\u3002" })) })) : panel.id === "cleaner-panel" ? (_jsxs("div", { className: "mt-3 grid gap-3", children: [_jsxs("div", { className: "rounded-lg border border-[#e3e7ee] bg-[#f6f8fa] px-3 py-3", children: [_jsxs("div", { className: "flex items-center justify-between gap-3", children: [_jsx("span", { className: "text-[11px] font-semibold text-[#30343b]", children: "\u5FEB\u7167\u6E05\u7406" }), _jsxs("strong", { className: "font-mono text-[12px] text-[#3565c5]", children: [value(Array.isArray(data?.capsules) ? data.capsules.length : 0), " \u4E2A"] })] }), _jsx("p", { className: "mt-2 text-[11px] text-[#687381]", children: "\u4EC5\u6E05\u7406 agent \u6570\u636E\u76EE\u5F55\u4E2D\u7684 .patch \u5FEB\u7167\uFF0C\u5FC5\u987B\u663E\u5F0F confirm=true\u3002" })] }), _jsxs("div", { className: "flex items-center justify-between text-[11px] text-[#687381]", children: [_jsx("span", { children: "\u4E0A\u6B21\u6E05\u7406" }), _jsxs("strong", { className: "font-mono text-[#3565c5]", children: [value(data?.lastRemoved ?? 0), " \u4E2A"] })] })] })) : panel.id === "fail-logger-panel" ? (_jsxs("div", { className: "mt-3 grid gap-3", children: [_jsxs("div", { className: "flex items-center justify-between rounded-lg bg-[#fff5f5] px-3 py-3", children: [_jsx("span", { className: "text-[11px] font-semibold text-[#7f1d1d]", children: "\u53BB\u91CD\u540E\u7684\u5931\u8D25\u8BB0\u5F55" }), _jsx("strong", { className: "font-mono text-[17px] text-[#b42318]", children: value(data?.total ?? 0) })] }), _jsx("div", { className: "max-h-48 overflow-auto rounded-lg border border-[#edf0f3]", children: Array.isArray(data?.failures) && data.failures.length > 0 ? (data.failures.map((item, index) => {
1009
+ const failure = item !== null && typeof item === "object" ? item : {};
1010
+ return (_jsxs("div", { className: "grid grid-cols-[auto_1fr] gap-2 border-b border-[#edf0f3] px-3 py-2 last:border-b-0", children: [_jsx("span", { className: "font-mono text-[10px] text-[#b42318]", children: value(failure.source ?? "runtime") }), _jsx("span", { className: "break-words text-[11px] leading-4 text-[#65707b]", children: value(failure.message ?? "未知错误") })] }, `${value(failure.time ?? "failure")}-${index}`));
1011
+ })) : (_jsx("div", { className: "px-3 py-4 text-[12px] text-[#687381]", children: "\u6682\u65E0\u5931\u8D25\u8BB0\u5F55\u3002" })) })] })) : panel.id === "context-insight-panel" ? (_jsxs("div", { className: "mt-3 grid gap-3", children: [_jsxs("div", { className: "rounded-lg border border-[#e3eaf8] bg-[#f6f8ff] px-3 py-3", children: [_jsxs("div", { className: "flex items-center justify-between gap-3", children: [_jsx("span", { className: "font-mono text-[10px] uppercase tracking-[0.08em] text-[#5d6d82]", children: "\u4E0A\u4E0B\u6587\u5360\u7528" }), _jsx("strong", { className: "text-[13px] font-semibold text-[#315fb8]", children: data?.percent === null || data?.percent === undefined ? "—" : `${value(data.percent)}%` })] }), _jsx("div", { className: "mt-2 h-2 overflow-hidden rounded-full bg-[#dfe8fb]", children: _jsx("div", { className: "h-full rounded-full bg-[#5d8bea] transition-[width] duration-300", style: { width: `${Math.max(0, Math.min(100, typeof data?.percent === "number" ? data.percent : 0))}%` } }) }), _jsxs("p", { className: "mt-2 text-[11px] text-[#5d6d82]", children: [data?.tokens === null || data?.tokens === undefined ? "令牌数未知" : `${value(data.tokens)} tokens`, data?.contextWindow === null || data?.contextWindow === undefined ? "" : ` / ${value(data.contextWindow)} 上限`] })] }), _jsx("div", { className: "grid grid-cols-3 gap-2", children: [
1012
+ ["消息", data?.messages ?? 0],
1013
+ ["事件", data?.events ?? 0],
1014
+ ["压缩", data?.compactions ?? 0],
1015
+ ].map(([label, item]) => (_jsxs("div", { className: "rounded-lg bg-[#f6f8fa] px-3 py-2", children: [_jsx("span", { className: "block text-[10px] text-[#687381]", children: value(label) }), _jsx("strong", { className: "mt-1 block text-[17px] font-semibold text-[#30343b]", children: value(item) })] }, value(label)))) }), _jsxs("div", { className: "rounded-lg border border-[#edf0f3] bg-white px-3 py-3", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("span", { className: "text-[11px] font-semibold text-[#30343b]", children: "\u6D88\u606F\u7EC4\u6210" }), _jsx("span", { className: "text-[10px] text-[#687381]", children: "\u6309\u89D2\u8272\u7EDF\u8BA1" })] }), _jsx("div", { className: "mt-2 grid grid-cols-5 gap-1.5", children: [
1016
+ ["用户", data?.composition?.user ?? 0],
1017
+ ["助手", data?.composition?.assistant ?? 0],
1018
+ ["工具", data?.composition?.toolResult ?? 0],
1019
+ ["系统", data?.composition?.system ?? 0],
1020
+ ["其他", data?.composition?.other ?? 0],
1021
+ ].map(([label, item]) => (_jsxs("div", { className: "rounded bg-[#f6f8fa] px-2 py-1.5 text-center", children: [_jsx("span", { className: "block text-[10px] text-[#687381]", children: value(label) }), _jsx("strong", { className: "mt-0.5 block font-mono text-[13px] text-[#30343b]", children: value(item) })] }, value(label)))) })] }), _jsxs("div", { className: "rounded-lg border border-[#edf0f3] bg-white px-3 py-3", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("span", { className: "text-[11px] font-semibold text-[#30343b]", children: "\u6700\u8FD1\u4E0A\u4E0B\u6587\u4E8B\u4EF6" }), _jsx("span", { className: "text-[10px] text-[#687381]", children: "\u6700\u591A\u4FDD\u7559 50 \u6761" })] }), _jsx("div", { className: "mt-2 max-h-28 overflow-auto", children: Array.isArray(data?.recentEvents) && data.recentEvents.length > 0 ? (data.recentEvents
1022
+ .slice(-6)
1023
+ .reverse()
1024
+ .map((item, index) => {
1025
+ const event = item !== null && typeof item === "object" ? item : {};
1026
+ return (_jsxs("div", { className: "flex items-center justify-between border-b border-[#f0f2f5] py-1.5 last:border-b-0", children: [_jsx("span", { className: "font-mono text-[10px] text-[#5d6d82]", children: value(event.type, "unknown") }), _jsx("span", { className: "text-[10px] text-[#687381]", children: typeof event.at === "number" ? new Date(event.at).toLocaleTimeString() : "—" })] }, `${value(event.type)}-${value(event.at)}-${index}`));
1027
+ })) : (_jsx("div", { className: "py-2 text-[11px] text-[#687381]", children: "\u6682\u65E0\u4E0A\u4E0B\u6587\u4E8B\u4EF6\u3002" })) })] })] })) : (_jsx("div", { className: "mt-3 grid gap-2", children: entries.map(([key, item]) => (_jsxs("div", { className: "rounded-lg bg-[#f6f8fa] px-3 py-2", children: [_jsx("span", { className: "block font-mono text-[10px] uppercase tracking-[0.08em] text-[#687381]", children: key }), _jsx("pre", { className: "mt-1 max-h-48 overflow-auto whitespace-pre-wrap break-words text-[12px] leading-5 text-[#30343b]", children: pluginPanelValue(item) })] }, key))) }))] }));
56
1028
  }
57
- function Files({ files, api, onDiff, onRefresh }) { const additions = files.filter((file) => file.status.includes("A") || file.status === "??").length; const deletions = files.filter((file) => file.status.includes("D")).length; const [message, setMessage] = useState(""); const [busy, setBusy] = useState(false); const [error, setError] = useState(""); const commit = () => { const text = message.trim(); if (!text || busy)
58
- return; setBusy(true); setError(""); void api.commitFiles(files.map((file) => file.path), text).then(() => { setMessage(""); onRefresh(); }).catch((cause) => setError(cause instanceof Error ? cause.message : String(cause))).finally(() => setBusy(false)); }; const revert = () => { if (!files.length || busy || !window.confirm("撤销这些未提交改动?此操作不可恢复。"))
59
- return; setBusy(true); setError(""); void api.revertFiles(files.map((file) => file.path)).then(onRefresh).catch((cause) => setError(cause instanceof Error ? cause.message : String(cause))).finally(() => setBusy(false)); }; return _jsx("section", { className: "view-panel files-view", children: _jsxs("div", { className: "files-content", children: [_jsxs("div", { className: "files-title", children: [_jsx("strong", { children: "\u672C\u6B21\u4F1A\u8BDD\u6539\u52A8" }), _jsx("span", { children: "\u7531 /api/files \u63D0\u4F9B" })] }), _jsxs("div", { className: "file-summary", children: [files.length, " \u4E2A\u6587\u4EF6 \u00B7 ", additions, " \u4E2A\u65B0\u589E \u00B7 ", deletions, " \u4E2A\u5220\u9664"] }), _jsx("div", { className: "file-list", children: files.length ? files.map((file) => _jsxs("div", { className: "file-row", children: [_jsx("b", { className: `file-kind ${file.label === "untracked" ? "new" : ""}`, children: file.label }), _jsx("code", { children: file.path }), _jsx("span", { className: file.status.includes("D") ? "del" : "add", children: file.status }), _jsx("button", { className: "diff-button", onClick: () => onDiff(file.path), type: "button", children: "\u67E5\u770B\u5DEE\u5F02" })] }, file.path)) : _jsx("div", { className: "empty-state", children: "\u5DE5\u4F5C\u533A\u6CA1\u6709\u672A\u63D0\u4EA4\u6539\u52A8\u3002" }) }), files.length > 0 && _jsxs("div", { className: "file-actions", children: [_jsx("input", { "aria-label": "\u63D0\u4EA4\u8BF4\u660E", onChange: (event) => setMessage(event.target.value), placeholder: "\u63D0\u4EA4\u8BF4\u660E", value: message }), _jsx("button", { className: "primary", disabled: busy || !message.trim(), onClick: commit, type: "button", children: busy ? "处理中…" : "提交这些改动" }), _jsx("button", { disabled: busy, onClick: revert, type: "button", children: "\u5168\u90E8\u64A4\u9500" })] }), error && _jsx("p", { className: "action-error", children: error })] }) }); }
60
- function Plugins({ plugins, tab, onTab, onToml }) { const groups = useMemo(() => { const map = new Map(); plugins.forEach((plugin) => map.set(capability(plugin.name), [...(map.get(capability(plugin.name)) ?? []), plugin.name])); return map; }, [plugins]); return _jsx("section", { className: "view-panel plugins-view", children: _jsxs("div", { className: "plugins-page", children: [_jsxs("div", { className: "subnav", children: [_jsxs("div", { className: "segmented", children: [_jsx("button", { className: tab === "installed" ? "active" : "", onClick: () => onTab("installed"), type: "button", children: "\u5DF2\u5B89\u88C5" }), _jsx("button", { className: tab === "extensions" ? "active" : "", onClick: () => onTab("extensions"), type: "button", children: "\u6269\u5C55\u70B9" })] }), _jsx("span", { children: "\u8FD0\u884C\u65F6\u63D2\u4EF6\u6E05\u5355" }), _jsx("a", { href: "#", onClick: (event) => { event.preventDefault(); onToml(); }, children: "\u5728 pi.toml \u91CC\u770B\u8FD9\u4EFD\u6E05\u5355" })] }), _jsx("div", { className: "plugins-scroll", children: tab === "installed" ? _jsxs(_Fragment, { children: [_jsx("div", { className: "plugins-list", children: plugins.map((plugin) => _jsx("article", { className: "plugin-card", children: _jsxs("div", { className: "plugin-card-head", children: [_jsx("span", { className: "plugin-icon", children: "\u25C8" }), _jsxs("div", { className: "plugin-copy", children: [_jsxs("div", { className: "plugin-title", children: [_jsx("code", { children: plugin.name }), _jsx("small", { children: plugin.state }), _jsx("span", { className: "capability", children: capability(plugin.name) })] }), _jsx("p", { className: "plugin-description", children: plugin.enabled ? "由当前 Cordis loader 加载并启用,能力与 hook 由运行时注册。" : "由当前 Cordis loader 加载但已停用。" }), _jsxs("div", { className: "hook-list", children: [_jsx("span", { children: "loader" }), _jsx("span", { children: plugin.state === "active" ? "active" : `state:${plugin.state}` })] })] }), _jsx("span", { className: `switch ${plugin.enabled ? "on" : ""}`, children: _jsx("i", {}) })] }) }, plugin.id)) }), _jsxs("div", { className: "plugin-add", children: [_jsx("code", { children: "dsh plugin add" }), _jsx("input", { disabled: true, placeholder: "github:owner/repo" }), _jsx("button", { className: "primary", disabled: true, type: "button", children: "\u5B89\u88C5" })] })] }) : _jsxs(_Fragment, { children: [_jsx("p", { className: "extension-note", children: "\u6BCF\u4E2A\u6269\u5C55\u70B9\u7531\u54EA\u4E9B\u5305\u5360\u7528\uFF0C\u6309 Cordis loader \u7684\u6267\u884C\u987A\u5E8F\u6392\u5217\u3002" }), _jsxs("div", { className: "extension-table", children: [_jsxs("div", { className: "extension-row extension-head", children: [_jsx("span", { children: "\u6269\u5C55\u70B9" }), _jsx("span", { children: "\u5360\u7528\u8005\uFF08\u6309\u5E8F\uFF09" }), _jsx("span", { children: "\u6570\u91CF" })] }), [...groups].map(([point, owners]) => _jsxs("div", { className: "extension-row", children: [_jsx("code", { children: point }), _jsx("div", { className: "extension-owners", children: owners.map((owner) => _jsx("span", { children: owner }, owner)) }), _jsx("code", { children: owners.length })] }, point))] })] }) })] }) }); }
61
- function Marketplace({ plugins, capabilities }) {
1029
+ function PluginUninstallDialog({ pluginName, busy, error, onCancel, onConfirm, }) {
1030
+ const dialogRef = useModalFocus(true, onCancel, busy);
1031
+ return (_jsx("div", { className: "plugin-confirm-backdrop", onClick: () => {
1032
+ if (!busy)
1033
+ onCancel();
1034
+ }, children: _jsxs("div", { "aria-label": "\u786E\u8BA4\u5378\u8F7D\u63D2\u4EF6", "aria-modal": "true", className: "plugin-confirm-dialog", onClick: (event) => event.stopPropagation(), ref: dialogRef, role: "dialog", tabIndex: -1, children: [_jsx("header", { children: _jsxs("div", { children: [_jsx("strong", { children: "\u5378\u8F7D\u63D2\u4EF6\uFF1F" }), _jsx("small", { children: "\u5C06\u4ECE\u8FD0\u884C\u914D\u7F6E\u4E2D\u79FB\u9664\uFF0C\u4E4B\u540E\u53EF\u4EE5\u4ECE\u63D2\u4EF6\u5E02\u573A\u91CD\u65B0\u5B89\u88C5\u3002" })] }) }), _jsx("code", { children: pluginName }), error && (_jsx("p", { className: "plugin-confirm-error", role: "alert", children: error })), _jsxs("footer", { children: [_jsx("button", { "data-dialog-initial-focus": true, disabled: busy, onClick: onCancel, type: "button", children: "\u53D6\u6D88" }), _jsx("button", { className: "danger", disabled: busy, onClick: onConfirm, type: "button", children: busy ? "卸载中…" : "确认卸载" })] })] }) }));
1035
+ }
1036
+ function Plugins({ plugins, panels, catalog, onMarketplace, onOpenDetail, onToml, onToggle, onUninstall, }) {
1037
+ const catalogByPackage = useMemo(() => new Map(catalog.map((plugin) => [plugin.packageName, plugin])), [catalog]);
1038
+ const panelPluginIds = useMemo(() => new Set(panels.map((panel) => panel.pluginId)), [panels]);
1039
+ const installedPlugins = useMemo(() => plugins.filter((plugin) => plugin.removable || panelPluginIds.has(plugin.name)), [panelPluginIds, plugins]);
62
1040
  const [query, setQuery] = useState("");
63
- const [capabilityFilter, setCapabilityFilter] = useState("");
64
- const [copied, setCopied] = useState();
65
- const copyInstall = (plugin) => {
66
- const profile = JSON.stringify({ id: plugin.id, name: plugin.profile.name, config: plugin.profile.config }, null, 2);
67
- const command = `npm install --save-exact ${plugin.packageName}@${plugin.version}\n\nAdd this entry to your Cordis profile:\n${profile}`;
68
- void navigator.clipboard?.writeText(command).then(() => { setCopied(plugin.id); window.setTimeout(() => setCopied((current) => current === plugin.id ? undefined : current), 1800); });
69
- };
70
- return _jsx("section", { className: "view-panel marketplace-view", children: _jsxs("div", { className: "plugins-page", children: [_jsxs("div", { className: "marketplace-hero", children: [_jsxs("div", { children: [_jsx("small", { children: "COMMUNITY MARKETPLACE" }), _jsx("h2", { children: "\u53D1\u73B0 Cordis \u63D2\u4EF6" }), _jsx("p", { children: "\u53EF\u5BA1\u67E5\u7684\u793E\u533A\u76EE\u5F55\u3002\u6BCF\u4E2A\u6761\u76EE\u90FD\u5305\u542B npm \u5305\u3001\u7248\u672C\u3001\u8BB8\u53EF\u8BC1\u548C Cordis \u914D\u7F6E\u5165\u53E3\u3002" })] }), _jsx("a", { href: "https://github.com/pi-harness/pi-harness/blob/main/docs/plugin-marketplace.md", target: "_blank", rel: "noreferrer", children: "\u8D21\u732E\u63D2\u4EF6 \u2197" })] }), _jsxs("div", { className: "marketplace-toolbar", children: [_jsx("input", { "aria-label": "\u641C\u7D22\u63D2\u4EF6", onChange: (event) => setQuery(event.target.value), placeholder: "\u641C\u7D22\u540D\u79F0\u3001\u5305\u540D\u3001\u80FD\u529B\u2026", value: query }), _jsxs("select", { "aria-label": "\u6309\u80FD\u529B\u7B5B\u9009", onChange: (event) => setCapabilityFilter(event.target.value), value: capabilityFilter, children: [_jsx("option", { value: "", children: "\u5168\u90E8\u80FD\u529B" }), capabilities.map((item) => _jsx("option", { value: item, children: item }, item))] }), _jsxs("span", { children: [plugins.length, " \u4E2A\u5DF2\u5BA1\u6838\u6761\u76EE"] })] }), _jsxs("div", { className: "plugins-scroll", children: [_jsxs("div", { className: "marketplace-list", children: [plugins.filter((plugin) => { const text = `${plugin.name} ${plugin.packageName} ${plugin.description} ${plugin.author} ${plugin.capabilities.join(" ")}`.toLowerCase(); return (!query || text.includes(query.toLowerCase())) && (!capabilityFilter || plugin.capabilities.includes(capabilityFilter)); }).map((plugin) => _jsxs("article", { className: "marketplace-card", children: [_jsxs("div", { className: "marketplace-card-head", children: [_jsx("div", { className: "marketplace-icon", children: "\u25C8" }), _jsxs("div", { className: "plugin-copy", children: [_jsxs("div", { className: "plugin-title", children: [_jsx("strong", { children: plugin.name }), _jsx("span", { className: "marketplace-badge", children: plugin.status === "verified" ? "已验证" : "实验性" }), _jsx("span", { className: `marketplace-source ${plugin.source}`, children: plugin.source === "official" ? "官方" : "社区" })] }), _jsxs("code", { className: "marketplace-package", children: [plugin.packageName, "@", plugin.version] }), _jsx("p", { children: plugin.description }), _jsxs("div", { className: "hook-list", children: [plugin.capabilities.map((item) => _jsx("span", { children: item }, item)), plugin.hooks.map((item) => _jsxs("span", { children: ["hook:", item] }, item))] })] }), _jsx("button", { className: "marketplace-install", onClick: () => copyInstall(plugin), type: "button", children: copied === plugin.id ? "已复制" : "复制安装指引" })] }), _jsxs("footer", { className: "marketplace-meta", children: [_jsxs("span", { children: [plugin.author, " \u00B7 ", plugin.license] }), _jsx("a", { href: plugin.repository, target: "_blank", rel: "noreferrer", children: "\u67E5\u770B\u6E90\u7801 \u2197" })] })] }, plugin.id)), !plugins.length && _jsx("div", { className: "empty-state", children: "\u6CA1\u6709\u5339\u914D\u7684\u63D2\u4EF6\u3002" })] }), _jsxs("div", { className: "marketplace-contribute", children: [_jsx("strong", { children: "\u4F60\u6709\u4E00\u4E2A Cordis \u63D2\u4EF6\uFF1F" }), _jsx("span", { children: "\u5728 registry JSON \u6DFB\u52A0\u5143\u6570\u636E\uFF0C\u9644\u6D4B\u8BD5\u548C README \u540E\u63D0\u4EA4 PR\uFF1B\u5BA1\u6838\u901A\u8FC7\u540E\u4F1A\u51FA\u73B0\u5728\u8FD9\u91CC\u3002" }), _jsx("a", { href: "https://github.com/pi-harness/pi-harness/blob/main/docs/plugin-marketplace.md", target: "_blank", rel: "noreferrer", children: "\u67E5\u770B\u8D21\u732E\u89C4\u8303 \u2197" })] })] })] }) });
71
- }
72
- function Settings({ data, api, tab, onTab, onClose }) { const status = data.status; const [providerState, setProviderState] = useState({}); const runProviderAction = (provider, action) => { setProviderState((current) => ({ ...current, [provider]: action === "test" ? "测试中…" : "刷新中…" })); if (action === "test")
73
- void api.testProvider(provider).then((result) => setProviderState((current) => ({ ...current, [provider]: result.reachable ? "连接正常" : "未检测到认证" }))).catch((cause) => setProviderState((current) => ({ ...current, [provider]: cause instanceof Error ? cause.message : String(cause) })));
74
- else
75
- void api.refreshProvider(provider).then((result) => setProviderState((current) => ({ ...current, [provider]: `${result.models.length} 个模型已刷新` }))).catch((cause) => setProviderState((current) => ({ ...current, [provider]: cause instanceof Error ? cause.message : String(cause) }))); }; return _jsx("div", { className: "settings-overlay", children: _jsxs("div", { className: "settings-dialog", children: [_jsxs("aside", { children: [_jsx("strong", { children: "\u8BBE\u7F6E" }), ["general", "plugins", "providers", "toml"].map((item) => _jsx("button", { className: `settings-tab ${tab === item ? "active" : ""}`, onClick: () => onTab(item), type: "button", children: item === "general" ? "通用" : item === "plugins" ? `插件 ${data.plugins.length}` : item === "providers" ? `提供商 ${data.providers.length}` : "pi.toml" }, item))] }), _jsxs("section", { children: [_jsxs("header", { children: [_jsx("strong", { children: tab === "general" ? "通用" : tab === "plugins" ? "插件" : tab === "providers" ? "提供商" : "pi.toml" }), _jsx("small", { children: tab === "toml" ? "配置即代码,改完重载" : "运行时状态与快捷键" }), _jsx("button", { onClick: onClose, type: "button", children: "\u00D7" })] }), _jsxs("div", { className: "settings-body", children: [tab === "general" && _jsxs(_Fragment, { children: [[["工作目录", status?.cwd], ["agent 目录", status?.agentDir], ["会话", status ? `${status.sessionId} · ${status.messages} 条消息` : "—"], ["快捷键", "⌘K 命令 · ⌘, 设置 · ⌃C 中断"], ["权限策略", "当前 API 未提供修改接口"]].map(([key, item]) => _jsx("div", { className: "general-row", children: _jsxs("div", { children: [_jsx("strong", { children: key }), _jsx("small", { children: value(item) })] }) }, key)), _jsxs("div", { className: "general-row", children: [_jsxs("div", { children: [_jsx("strong", { children: "\u4EFB\u52A1\u7ED3\u675F\u63D0\u9192" }), _jsx("small", { children: "\u7531 runtime \u63D2\u4EF6\u63D0\u4F9B" })] }), _jsx("span", { className: "switch", children: _jsx("i", {}) })] }), _jsxs("div", { className: "general-row", children: [_jsxs("div", { children: [_jsx("strong", { children: "\u81EA\u52A8\u538B\u7F29\u4E0A\u4E0B\u6587" }), _jsx("small", { children: "\u4E8B\u4EF6\u901A\u8FC7 SSE \u5B9E\u65F6\u5237\u65B0" })] }), _jsx("span", { className: "switch on", children: _jsx("i", {}) })] })] }), tab === "plugins" && data.plugins.map((plugin) => _jsxs("div", { className: "settings-plugin-row", children: ["\u25C8 ", _jsxs("code", { children: [plugin.name, " \u00B7 ", plugin.id, " \u00B7 ", plugin.state] })] }, plugin.id)), tab === "providers" && _jsxs(_Fragment, { children: [_jsx("small", { children: "\u8FD0\u884C\u65F6\u6CE8\u518C\u63D0\u4F9B\u5546 \u00B7 /api/providers" }), data.providers.length ? data.providers.map((provider) => _jsxs("article", { className: "provider-card", children: [_jsxs("div", { className: "provider-head", children: [_jsx("span", { className: "provider-dot", children: "\u25CF" }), _jsx("strong", { children: provider.name }), _jsx("span", { className: "provider-state", children: provider.active ? "当前会话" : value(provider.auth?.configured, "未配置") })] }), _jsxs("div", { className: "provider-field", children: [_jsx("code", { children: "provider" }), _jsx("input", { disabled: true, value: provider.provider, readOnly: true })] }), _jsxs("div", { className: "provider-field", children: [_jsx("code", { children: "model" }), _jsx("input", { disabled: true, value: provider.activeModel ? `${provider.activeModel.provider}/${provider.activeModel.id}` : provider.models.map((model) => model.id).join(", "), readOnly: true })] }), _jsxs("div", { className: "provider-field", children: [_jsx("code", { children: "api_key" }), _jsx("input", { disabled: true, value: "\u4E0D\u4F1A\u5728\u6D4F\u89C8\u5668\u663E\u793A", readOnly: true })] }), _jsxs("div", { className: "provider-footer", children: [_jsxs("code", { children: [provider.models.length, " \u4E2A\u6A21\u578B"] }), _jsx("button", { onClick: () => runProviderAction(provider.provider, "test"), type: "button", children: "\u6D4B\u8BD5\u8FDE\u63A5" }), _jsx("button", { className: "link-button", onClick: () => runProviderAction(provider.provider, "refresh"), type: "button", children: "\u62C9\u53D6\u6A21\u578B" })] }), providerState[provider.provider] && _jsx("small", { className: "provider-result", children: providerState[provider.provider] })] }, provider.provider)) : _jsx("div", { className: "empty-state", children: "\u8FD0\u884C\u65F6\u6CA1\u6709\u6CE8\u518C\u63D0\u4F9B\u5546\u3002" })] }), tab === "toml" && _jsxs(_Fragment, { children: [_jsxs("div", { className: "toml-toolbar", children: [_jsx("span", { children: "~/.config/pi/pi.toml" }), _jsx("button", { className: "active", type: "button", children: "\u8868\u5355" }), _jsx("button", { disabled: true, type: "button", children: "\u6E90\u7801" }), _jsx("button", { className: "primary", disabled: true, type: "button", children: "\u91CD\u8F7D" })] }), _jsx("div", { className: "toml", children: _jsx("div", { className: "empty-state", children: "pi.toml \u8BFB\u53D6\u4E0E\u5199\u5165 API \u5C1A\u672A\u63D0\u4F9B\u3002" }) })] })] })] })] }) }); }
76
- function CommandPalette({ commands, onClose, onUse }) { const [query, setQuery] = useState(""); const visible = commands.filter((command) => `${command.invocationName} ${command.description ?? ""}`.toLowerCase().includes(query.toLowerCase())); return _jsx("div", { className: "command-palette", onClick: (event) => { if (event.target === event.currentTarget)
77
- onClose(); }, children: _jsxs("div", { className: "palette-dialog", children: [_jsx("input", { autoFocus: true, onChange: (event) => setQuery(event.target.value), placeholder: "\u547D\u4EE4\u3001\u5305\u3001\u4F1A\u8BDD\u3001\u6587\u4EF6", value: query }), _jsxs("div", { className: "palette-group", children: [_jsx("small", { children: "COMMANDS \u00B7 RUNTIME REGISTRY" }), visible.length ? visible.map((command) => { const invocation = `/${command.invocationName}`; return _jsxs("button", { onClick: () => { onUse(invocation); onClose(); }, type: "button", children: [_jsx("code", { children: invocation }), _jsx("span", { children: command.description ?? command.source ?? "由当前运行时注册" })] }, `${command.invocationName}:${command.source ?? "runtime"}`); }) : _jsx("div", { className: "empty-state", children: commands.length ? "没有匹配的命令。" : "当前运行时没有可用的命令注册清单。" })] })] }) }); }
78
- export function ControlRoomView({ api = createClientApi() }) {
79
- const [data, setData] = useState({ sessions: [], files: [], models: [], providers: [], plugins: [], marketplace: [], marketplaceCapabilities: [], commands: [] });
80
- const [view, setView] = useState("chat");
81
- const [page, setPage] = useState("session");
82
- const [pluginTab, setPluginTab] = useState("installed");
83
- const [settings, setSettings] = useState();
84
- const [details, setDetails] = useState({});
1041
+ const [categoryFilter, setCategoryFilter] = useState("");
1042
+ const [busyPlugin, setBusyPlugin] = useState();
1043
+ const [pluginError, setPluginError] = useState("");
1044
+ const [pendingUninstall, setPendingUninstall] = useState();
1045
+ const scrollRef = useRef(null);
1046
+ const installedCategories = useMemo(() => {
1047
+ const counts = new Map();
1048
+ for (const plugin of installedPlugins) {
1049
+ const category = catalogByPackage.get(plugin.name)?.category ?? plugin.category ?? { id: "other", label: "其他" };
1050
+ const current = counts.get(category.id);
1051
+ counts.set(category.id, { ...category, count: (current?.count ?? 0) + 1 });
1052
+ }
1053
+ return marketplaceCategoryTabs([...counts.values()].sort((left, right) => right.count - left.count || left.label.localeCompare(right.label, "zh-CN")));
1054
+ }, [catalogByPackage, installedPlugins]);
1055
+ const visiblePlugins = useMemo(() => {
1056
+ return installedPlugins.filter((plugin) => {
1057
+ const metadata = catalogByPackage.get(plugin.name);
1058
+ const category = metadata?.category ?? plugin.category ?? { id: "other", label: "其他" };
1059
+ if (categoryFilter && category.id !== categoryFilter)
1060
+ return false;
1061
+ const fields = [
1062
+ plugin.name,
1063
+ metadata?.name,
1064
+ displayPluginName(plugin.name),
1065
+ metadata?.category.label,
1066
+ ...(metadata?.capabilities ?? []),
1067
+ plugin.category?.label,
1068
+ capability(plugin.name),
1069
+ ];
1070
+ return matchesPluginQuery(query, fields);
1071
+ });
1072
+ }, [catalogByPackage, categoryFilter, installedPlugins, query]);
1073
+ useEffect(() => {
1074
+ scrollRef.current?.scrollTo({ top: 0 });
1075
+ }, [categoryFilter, query]);
1076
+ useEffect(() => {
1077
+ if (categoryFilter && !installedCategories.some((category) => category.id === categoryFilter))
1078
+ setCategoryFilter("");
1079
+ }, [categoryFilter, installedCategories]);
1080
+ const runPluginAction = async (plugin, action) => {
1081
+ setPluginError("");
1082
+ setBusyPlugin(plugin.id);
1083
+ try {
1084
+ await action(plugin);
1085
+ return true;
1086
+ }
1087
+ catch (error) {
1088
+ setPluginError(error instanceof Error ? error.message : String(error));
1089
+ return false;
1090
+ }
1091
+ finally {
1092
+ setBusyPlugin(undefined);
1093
+ }
1094
+ };
1095
+ return (_jsx("section", { className: "view-panel plugins-view", children: _jsxs("div", { className: "plugins-page", children: [_jsxs("div", { className: "subnav", children: [_jsxs("div", { "aria-label": "\u63D2\u4EF6\u76EE\u5F55", className: "segmented", children: [_jsx("button", { "aria-pressed": "true", className: "active", type: "button", children: "\u5DF2\u5B89\u88C5" }), _jsx("button", { "aria-pressed": "false", onClick: onMarketplace, type: "button", children: "\u63D2\u4EF6\u5E02\u573A" })] }), _jsx("span", { children: "\u5DF2\u5B89\u88C5\u63D2\u4EF6" }), _jsx("a", { href: "#", onClick: (event) => {
1096
+ event.preventDefault();
1097
+ onToml();
1098
+ }, children: "\u67E5\u770B\u8FD0\u884C\u914D\u7F6E" })] }), _jsxs("div", { className: "plugins-toolbar", children: [_jsx("input", { "aria-label": "\u641C\u7D22\u5DF2\u5B89\u88C5\u63D2\u4EF6", onChange: (event) => setQuery(event.target.value), placeholder: "\u641C\u7D22\u540D\u79F0\u3001\u5305\u540D\u6216\u80FD\u529B\u2026", type: "search", value: query }), _jsxs("span", { "aria-live": "polite", children: [query.trim() || categoryFilter ? `${visiblePlugins.length} / ${installedPlugins.length}` : `${installedPlugins.length}`, " \u4E2A\u63D2\u4EF6"] })] }), _jsx("nav", { "aria-label": "\u5DF2\u5B89\u88C5\u63D2\u4EF6\u5206\u7C7B", className: "marketplace-categories", children: installedCategories.map((category) => {
1099
+ const active = categoryFilter === category.id;
1100
+ return (_jsxs("button", { "aria-pressed": active, className: `marketplace-category ${active ? "active" : ""}`, onClick: () => setCategoryFilter(category.id), type: "button", children: [_jsx("span", { children: category.label }), _jsx("span", { className: active ? "font-mono text-[10px] text-[#3565c5]" : "font-mono text-[10px] text-[#687381]", children: category.count })] }, category.id || "all"));
1101
+ }) }), _jsxs("div", { className: "plugins-scroll", ref: scrollRef, children: [_jsxs("div", { className: "plugins-list", children: [visiblePlugins.map((plugin) => {
1102
+ const metadata = catalogByPackage.get(plugin.name);
1103
+ const categoryLabel = metadata?.category.label ?? plugin.category?.label;
1104
+ const capabilityLabel = capability(plugin.name);
1105
+ const pluginTitle = metadata?.name ?? displayPluginName(plugin.name);
1106
+ return (_jsxs("article", { className: "catalog-card plugin-card", children: [_jsxs("div", { className: "plugin-card-head", children: [_jsx("span", { className: "plugin-icon", children: "\u25C8" }), _jsx("div", { className: "plugin-copy", children: _jsxs("div", { className: "plugin-heading", children: [_jsxs("div", { className: "plugin-title", children: [_jsx("strong", { children: pluginTitle }), _jsx("span", { className: `plugin-state ${plugin.enabled ? "active" : ""}`, children: plugin.enabled ? "运行中" : "已停用" }), categoryLabel && _jsx("span", { className: "capability", children: categoryLabel }), categoryLabel !== capabilityLabel && _jsx("span", { className: "capability", children: capabilityLabel })] }), _jsx("div", { className: "plugin-actions", children: plugin.removable ? (_jsxs(_Fragment, { children: [_jsx("button", { "aria-label": `${plugin.enabled ? "停用" : "启用"} ${pluginTitle}`, "aria-pressed": plugin.enabled, className: "plugin-switch-button", disabled: busyPlugin !== undefined, onClick: () => void runPluginAction(plugin, (item) => onToggle(item)), type: "button", children: _jsx("span", { "aria-hidden": "true", className: `switch ${plugin.enabled ? "on" : ""}`, children: _jsx("i", {}) }) }), _jsx("button", { className: "plugin-uninstall", disabled: busyPlugin !== undefined, onClick: () => {
1107
+ setPluginError("");
1108
+ setPendingUninstall(plugin);
1109
+ }, type: "button", children: "\u5378\u8F7D" })] })) : (_jsx("span", { className: `switch ${plugin.enabled ? "on" : ""}`, children: _jsx("i", {}) })) })] }) })] }), _jsxs("div", { className: "plugin-card-body", children: [_jsx("code", { className: "plugin-package", children: plugin.name }), _jsx("p", { className: "plugin-description", children: plugin.enabled ? "由当前运行时加载并启用,能力与 hook 已注册。" : "由当前运行时加载但已停用。" }), _jsxs("div", { className: "hook-list", children: [_jsx("span", { children: "loader" }), _jsx("span", { children: plugin.state === "active" ? "active" : `state:${plugin.state}` })] })] }), _jsxs("footer", { className: "plugin-card-footer", children: [_jsx("a", { className: "plugin-detail-link", href: installedPluginDetailPath(plugin.name), onClick: (event) => {
1110
+ event.preventDefault();
1111
+ onOpenDetail(plugin);
1112
+ }, children: "\u67E5\u770B\u8BE6\u60C5 \u2192" }), panelPluginIds.has(plugin.name) ? _jsx("span", { children: "\u5B9E\u65F6\u9762\u677F" }) : null] })] }, plugin.id));
1113
+ }), !installedPlugins.length ? (_jsx("div", { className: "empty-state", children: "\u8FD8\u6CA1\u6709\u5B89\u88C5\u53EF\u7BA1\u7406\u7684\u63D2\u4EF6\u3002\u53BB\u63D2\u4EF6\u5E02\u573A\u5B89\u88C5\u4E00\u4E2A\u5427\u3002" })) : !visiblePlugins.length ? (_jsx("div", { className: "empty-state", children: "\u6CA1\u6709\u5339\u914D\u5F53\u524D\u641C\u7D22\u4E0E\u5206\u7C7B\u6761\u4EF6\u7684\u5DF2\u5B89\u88C5\u63D2\u4EF6\u3002" })) : null] }), pluginError && _jsx("p", { className: "plugin-action-error", children: pluginError }), panels.length > installedPlugins.length && (_jsxs("section", { className: "mt-4 border-t border-[#e3e7ee] pt-4", children: [_jsxs("div", { className: "mb-3 flex items-baseline justify-between gap-3", children: [_jsxs("div", { children: [_jsx("strong", { className: "text-[13px] font-semibold text-[#20252b]", children: "\u5176\u4ED6\u63D2\u4EF6\u9762\u677F" }), _jsx("p", { className: "mt-1 text-[12px] text-[#687381]", children: "\u7531\u5DF2\u542F\u7528\u63D2\u4EF6\u63D0\u4F9B\u7684\u5B9E\u65F6\u72B6\u6001\u3002" })] }), _jsx("span", { className: "font-mono text-[10px] uppercase tracking-[0.08em] text-[#687381]", children: "LIVE" })] }), _jsx("div", { className: "grid gap-3 xl:grid-cols-2", children: panels
1114
+ .filter((panel) => !installedPlugins.some((plugin) => plugin.name === panel.pluginId))
1115
+ .map((panel) => (_jsx(PluginPanelCard, { panel: panel }, panel.id))) })] }))] }), pendingUninstall && (_jsx(PluginUninstallDialog, { busy: busyPlugin !== undefined, error: pluginError, onCancel: () => setPendingUninstall(undefined), onConfirm: () => void runPluginAction(pendingUninstall, onUninstall).then((completed) => {
1116
+ if (completed)
1117
+ setPendingUninstall(undefined);
1118
+ }), pluginName: catalogByPackage.get(pendingUninstall.name)?.name ?? displayPluginName(pendingUninstall.name) }))] }) }));
1119
+ }
1120
+ function InstalledPluginDetail({ plugin, panel, metadata, onBack, onToggle, onUninstall, }) {
1121
+ const [busyAction, setBusyAction] = useState();
1122
+ const [error, setError] = useState("");
1123
+ const [confirmUninstall, setConfirmUninstall] = useState(false);
1124
+ const title = metadata?.name ?? displayPluginName(plugin.name);
1125
+ const run = async (action, callback) => {
1126
+ setError("");
1127
+ setBusyAction(action);
1128
+ try {
1129
+ await callback();
1130
+ return true;
1131
+ }
1132
+ catch (cause) {
1133
+ setError(cause instanceof Error ? cause.message : String(cause));
1134
+ return false;
1135
+ }
1136
+ finally {
1137
+ setBusyAction(undefined);
1138
+ }
1139
+ };
1140
+ return (_jsxs("section", { className: "marketplace-page flex min-w-0 flex-1 flex-col", children: [_jsxs("div", { className: "min-h-0 flex-1 overflow-auto", children: [_jsxs("div", { className: "subnav plugin-detail-subnav", children: [_jsx("a", { href: "?page=plugins", onClick: (event) => {
1141
+ event.preventDefault();
1142
+ onBack();
1143
+ }, children: "\u2190 \u5DF2\u5B89\u88C5\u63D2\u4EF6" }), _jsx("span", { children: "\u63D2\u4EF6\u8BE6\u60C5" })] }), _jsxs("div", { className: "plugin-detail-content", children: [_jsxs("header", { className: "border-b border-[#e3e7ee] pb-7", children: [_jsxs("div", { className: "mb-4 flex flex-wrap items-center gap-2", children: [_jsx("span", { className: `rounded px-2 py-1 font-mono text-[10px] ${plugin.enabled ? "bg-[#e6faed] text-[#14733f]" : "bg-[#eef0f3] text-[#687381]"}`, children: plugin.enabled ? "运行中" : "已停用" }), _jsx("span", { className: "rounded bg-[#f2edff] px-2 py-1 text-[10px] text-[#6d4bc3]", children: metadata?.category.label ?? plugin.category?.label ?? "运行时插件" }), _jsx("span", { className: "rounded bg-[#e4edfd] px-2 py-1 font-mono text-[10px] text-[#3565c5]", children: capability(plugin.name) })] }), _jsxs("div", { className: "flex flex-wrap items-end justify-between gap-5", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("p", { className: "mb-2 font-mono text-[11px] uppercase tracking-[0.14em] text-[#687381]", children: "PLUGIN DETAIL" }), _jsx("h1", { className: "text-3xl font-semibold tracking-[-0.03em] text-[#20252b]", children: title }), _jsxs("code", { className: "mt-3 block break-all text-[12px] text-[#687381]", children: [plugin.name, metadata ? ` · v${metadata.version}` : ""] })] }), plugin.removable ? (_jsxs("div", { className: "plugin-detail-actions", children: [_jsx("button", { className: "plugin-detail-action", disabled: busyAction !== undefined, onClick: () => void run("toggle", () => onToggle(plugin)), type: "button", children: busyAction === "toggle" ? "处理中…" : plugin.enabled ? "停用插件" : "启用插件" }), _jsx("button", { className: "plugin-detail-action danger", disabled: busyAction !== undefined, onClick: () => {
1144
+ setError("");
1145
+ setConfirmUninstall(true);
1146
+ }, type: "button", children: "\u5378\u8F7D\u63D2\u4EF6" })] })) : (_jsx("span", { className: "rounded-full bg-[#eef0f3] px-3 py-1.5 text-[11px] text-[#687381]", children: "\u5185\u7F6E\u7EC4\u4EF6" }))] }), _jsx("p", { className: "mt-5 max-w-3xl text-[14px] leading-7 text-[#59636e]", children: metadata?.description ?? (plugin.enabled ? "由当前运行时加载并启用,能力与 hook 已注册。" : "插件保留在运行配置中,但当前处于停用状态。") }), error && (_jsxs("p", { className: "mt-3 text-[12px] text-[#b42318]", role: "alert", children: ["\u64CD\u4F5C\u5931\u8D25\uFF1A", error] }))] }), _jsxs("div", { className: "grid gap-4 py-6 lg:grid-cols-[minmax(0,1fr)_280px]", children: [_jsxs("div", { className: "space-y-4", children: [_jsxs("section", { className: "rounded-[10px] border border-[#e3e7ee] bg-white p-5", children: [_jsx("h2", { className: "text-[13px] font-semibold text-[#20252b]", children: "\u63D2\u4EF6\u80FD\u529B" }), _jsx("div", { className: "mt-4 flex flex-wrap gap-2", children: (metadata?.capabilities.length ? metadata.capabilities : [capability(plugin.name)]).map((item) => (_jsx("span", { className: "rounded-md bg-[#f1f4f9] px-2 py-1 font-mono text-[11px] text-[#61666b]", children: item }, item))) })] }), metadata?.hooks.length ? (_jsxs("section", { className: "rounded-[10px] border border-[#e3e7ee] bg-white p-5", children: [_jsx("h2", { className: "text-[13px] font-semibold text-[#20252b]", children: "\u6269\u5C55\u70B9" }), _jsx("div", { className: "mt-4 space-y-2", children: metadata.hooks.map((item) => (_jsx("div", { className: "rounded-md bg-[#f8f9fb] px-3 py-2 font-mono text-[11px] text-[#61666b]", children: item }, item))) })] })) : null, _jsxs("section", { className: "rounded-[10px] border border-[#e3e7ee] bg-white p-5", children: [_jsxs("div", { className: "mb-4 flex items-center justify-between gap-3", children: [_jsxs("div", { children: [_jsx("h2", { className: "text-[13px] font-semibold text-[#20252b]", children: "\u5B9E\u65F6\u8BE6\u60C5" }), _jsx("p", { className: "mt-1 text-[12px] text-[#687381]", children: "\u5F53\u524D\u672C\u673A\u4F1A\u8BDD\u4E2D\u7684\u63D2\u4EF6\u8FD0\u884C\u72B6\u6001\u3002" })] }), _jsx("span", { className: "font-mono text-[10px] uppercase tracking-[0.1em] text-[#687381]", children: "LIVE" })] }), panel ? _jsx(PluginPanelCard, { inline: true, panel: panel }) : _jsx("div", { className: "empty-state", children: "\u8FD9\u4E2A\u63D2\u4EF6\u6682\u672A\u63D0\u4F9B\u5B9E\u65F6\u9762\u677F\u3002" })] })] }), _jsxs("aside", { className: "h-fit rounded-[10px] border border-[#e3e7ee] bg-white p-5", children: [_jsx("h2", { className: "text-[13px] font-semibold text-[#20252b]", children: "\u63D2\u4EF6\u4FE1\u606F" }), _jsxs("dl", { className: "mt-4 divide-y divide-[#eef0f3] text-[12px]", children: [_jsxs("div", { className: "flex justify-between gap-4 py-3", children: [_jsx("dt", { className: "text-[#687381]", children: "\u8FD0\u884C\u72B6\u6001" }), _jsx("dd", { className: "font-mono text-[#3b424b]", children: plugin.state })] }), _jsxs("div", { className: "flex justify-between gap-4 py-3", children: [_jsx("dt", { className: "text-[#687381]", children: "\u914D\u7F6E\u6807\u8BC6" }), _jsx("dd", { className: "max-w-[150px] break-all text-right font-mono text-[#3b424b]", children: plugin.id })] }), _jsxs("div", { className: "flex justify-between gap-4 py-3", children: [_jsx("dt", { className: "text-[#687381]", children: "\u5206\u7C7B" }), _jsx("dd", { className: "text-right text-[#3b424b]", children: plugin.category?.label ?? "运行时插件" })] }), _jsxs("div", { className: "flex justify-between gap-4 py-3", children: [_jsx("dt", { className: "text-[#687381]", children: "\u7BA1\u7406\u65B9\u5F0F" }), _jsx("dd", { className: "text-right text-[#3b424b]", children: plugin.removable ? "可配置" : "随运行时加载" })] }), metadata ? (_jsxs("div", { className: "flex justify-between gap-4 py-3", children: [_jsx("dt", { className: "text-[#687381]", children: "\u7248\u672C" }), _jsx("dd", { className: "font-mono text-[#3b424b]", children: metadata.version })] })) : null] }), metadata ? (_jsx("a", { className: "mt-4 block border-t border-[#eef0f3] pt-4 text-[12px] text-[#3565c5]", href: metadata.repository, rel: "noreferrer", target: "_blank", children: "\u67E5\u770B\u6E90\u7801 \u2197" })) : null] })] })] })] }), confirmUninstall ? (_jsx(PluginUninstallDialog, { busy: busyAction === "uninstall", error: error, onCancel: () => setConfirmUninstall(false), onConfirm: () => void run("uninstall", () => onUninstall(plugin)).then((completed) => {
1147
+ if (completed)
1148
+ setConfirmUninstall(false);
1149
+ }), pluginName: title })) : null] }));
1150
+ }
1151
+ function Marketplace({ plugins, capabilities, categories, total, page, hasNext, query, capabilityFilter, categoryFilter, onQueryChange, onCapabilityChange, onCategoryChange, onPageChange, onOpenDetail, onBack, onToml, installedPackages, onInstall, }) {
1152
+ const [installing, setInstalling] = useState();
1153
+ const [installError, setInstallError] = useState("");
1154
+ const [installNotice, setInstallNotice] = useState("");
1155
+ const categoryTabs = marketplaceCategoryTabs(categories);
1156
+ const install = async (plugin) => {
1157
+ setInstallError("");
1158
+ setInstallNotice("");
1159
+ setInstalling(plugin.id);
1160
+ try {
1161
+ const result = await onInstall(plugin);
1162
+ if (result.restartRequired === true)
1163
+ setInstallNotice("已写入 profile,重启 Pi Harness 后生效。");
1164
+ }
1165
+ catch (error) {
1166
+ setInstallError(error instanceof Error ? error.message : String(error));
1167
+ }
1168
+ finally {
1169
+ setInstalling(undefined);
1170
+ }
1171
+ };
1172
+ return (_jsx("section", { className: "marketplace-page flex min-w-0 flex-1 flex-col", children: _jsxs("div", { className: "flex min-h-0 flex-1 flex-col", children: [_jsxs("div", { className: "subnav", children: [_jsxs("div", { "aria-label": "\u63D2\u4EF6\u76EE\u5F55", className: "segmented", children: [_jsx("button", { "aria-pressed": "false", onClick: onBack, type: "button", children: "\u5DF2\u5B89\u88C5" }), _jsx("button", { "aria-pressed": "true", className: "active", type: "button", children: "\u63D2\u4EF6\u5E02\u573A" })] }), _jsx("span", { children: "\u5DF2\u5BA1\u6838\u63D2\u4EF6\u76EE\u5F55" }), _jsx("a", { href: "#", onClick: (event) => {
1173
+ event.preventDefault();
1174
+ onToml();
1175
+ }, children: "\u67E5\u770B\u8FD0\u884C\u914D\u7F6E" })] }), _jsxs("div", { className: "marketplace-toolbar", children: [_jsx("input", { className: "marketplace-search", "aria-label": "\u641C\u7D22\u63D2\u4EF6", onChange: (event) => onQueryChange(event.target.value), placeholder: "\u641C\u7D22\u540D\u79F0\u3001\u5305\u540D\u3001\u80FD\u529B\u2026", value: query }), _jsxs("select", { className: "marketplace-filter", "aria-label": "\u6309\u80FD\u529B\u7B5B\u9009", onChange: (event) => onCapabilityChange(event.target.value), value: capabilityFilter, children: [_jsx("option", { value: "", children: "\u5168\u90E8\u80FD\u529B" }), capabilities.map((item) => (_jsx("option", { value: item, children: item }, item)))] }), _jsxs("span", { className: "marketplace-count", children: [total, " \u4E2A\u5DF2\u5BA1\u6838\u6761\u76EE \u00B7 \u63A8\u8350\u6392\u5E8F"] })] }), _jsx("nav", { "aria-label": "\u63D2\u4EF6\u5206\u7C7B", className: "marketplace-categories", children: categoryTabs.map((category) => {
1176
+ const active = categoryFilter === category.id;
1177
+ return (_jsxs("button", { "aria-pressed": active, className: `marketplace-category ${active ? "active" : ""}`, onClick: () => onCategoryChange(category.id), type: "button", children: [_jsx("span", { children: category.label }), _jsx("span", { className: active ? "font-mono text-[10px] text-[#3565c5]" : "font-mono text-[10px] text-[#687381]", children: category.count })] }, category.id || "all"));
1178
+ }) }), _jsxs("div", { className: "marketplace-scroll", children: [_jsxs("div", { className: "marketplace-grid", children: [plugins.map((plugin) => (_jsxs("article", { className: "catalog-card marketplace-card", children: [_jsxs("div", { className: "flex items-start gap-2.5", children: [_jsx("div", { className: "marketplace-card-mark", children: "\u25C8" }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-1.5", children: [_jsx("strong", { className: "marketplace-title", children: plugin.name }), _jsx("span", { className: plugin.status === "verified"
1179
+ ? "rounded bg-[#e6faed] px-1.5 py-px font-mono text-[10px] text-[#14733f]"
1180
+ : "rounded bg-[#fff5e7] px-1.5 py-px font-mono text-[10px] text-[#9a6700]", children: plugin.status === "verified" ? "已验证" : "实验性" }), _jsx("span", { className: plugin.source === "official"
1181
+ ? "rounded bg-[#e4edfd] px-1.5 py-px font-mono text-[10px] text-[#3565c5]"
1182
+ : "rounded bg-[#fef5e7] px-1.5 py-px font-mono text-[10px] text-[#9a6700]", children: plugin.source === "official" ? "官方" : "社区" }), _jsx("span", { className: "rounded bg-[#f2edff] px-1.5 py-px text-[10px] text-[#6d4bc3]", children: plugin.category.label })] }), _jsxs("code", { className: "marketplace-package", children: [displayPluginName(plugin.packageName), " \u00B7 v", plugin.version] }), _jsx("p", { className: "marketplace-description", children: plugin.description }), _jsxs("div", { className: "marketplace-tags", children: [plugin.capabilities.map((item) => (_jsx("span", { className: "rounded bg-[#f1f4f9] px-1.5 py-px font-mono text-[10px] text-[#61666b]", children: item }, item))), plugin.hooks.map((item) => (_jsxs("span", { className: "rounded bg-[#f1f4f9] px-1.5 py-px font-mono text-[10px] text-[#61666b]", children: ["hook:", item] }, item)))] }), plugin.statistics && (_jsx("div", { className: "mt-3 grid grid-cols-3 divide-x divide-[#e3e7ee] rounded-md border border-[#e3e7ee] bg-[#f8f9fb]", children: marketplaceStatisticItems(plugin.statistics).map((item) => (_jsxs("span", { className: "min-w-0 px-2 py-1.5", title: `${item.label} ${item.value}`, children: [_jsx("small", { className: "block truncate text-[9px] text-[#687381]", children: item.label }), _jsx("strong", { className: "mt-0.5 block truncate font-mono text-[10px] font-medium text-[#3b424b]", children: item.value })] }, item.label))) }))] })] }), _jsxs("footer", { className: "marketplace-card-footer", children: [_jsxs("span", { children: [plugin.author, " \u00B7 ", plugin.license] }), _jsx("a", { href: marketplaceDetailPath(plugin.id), onClick: (event) => {
1183
+ event.preventDefault();
1184
+ onOpenDetail(plugin);
1185
+ }, children: "\u67E5\u770B\u8BE6\u60C5 \u2192" }), _jsx("a", { href: plugin.repository, target: "_blank", rel: "noreferrer", children: "\u67E5\u770B\u6E90\u7801 \u2197" }), _jsx("button", { disabled: installedPackages.has(plugin.packageName) || installing !== undefined, onClick: () => void install(plugin), type: "button", children: installedPackages.has(plugin.packageName) ? "已安装" : installing === plugin.id ? "安装中…" : "安装" })] })] }, plugin.id))), !plugins.length && _jsx("div", { className: "p-7 text-center text-[12px] text-[#687381]", children: "\u6CA1\u6709\u5339\u914D\u7684\u63D2\u4EF6\u3002" })] }), installNotice && _jsx("p", { className: "mt-2 text-[11px] text-[#3565c5]", children: installNotice }), installError && _jsxs("p", { className: "mt-2 text-[11px] text-[#b42318]", children: ["\u5B89\u88C5\u5931\u8D25\uFF1A", installError] }), _jsxs("div", { className: "marketplace-pagination", children: [_jsx("button", { className: "marketplace-pagination-button", disabled: page === 0, onClick: () => onPageChange(page - 1), type: "button", children: "\u4E0A\u4E00\u9875" }), _jsxs("span", { children: ["\u7B2C ", page + 1, " \u9875"] }), _jsx("button", { className: "marketplace-pagination-button", disabled: !hasNext, onClick: () => onPageChange(page + 1), type: "button", children: "\u4E0B\u4E00\u9875" })] }), _jsxs("div", { className: "marketplace-contribute mt-3 flex items-center gap-2.5 rounded-[10px] border border-dashed border-[#b8ccf5] bg-[#f8f9ff] p-2.5 text-[11.5px] text-[#687381]", children: [_jsx("strong", { className: "text-[12px] text-[#0f1115]", children: "\u4F60\u6709\u4E00\u4E2A Pi Harness \u63D2\u4EF6\uFF1F" }), _jsx("span", { children: "\u5728 entries \u76EE\u5F55\u65B0\u589E\u4E00\u4E2A\u5143\u6570\u636E\u6587\u4EF6\uFF0C\u9644\u6D4B\u8BD5\u548C README \u540E\u63D0\u4EA4 PR\uFF1B\u5BA1\u6838\u901A\u8FC7\u540E\u4F1A\u51FA\u73B0\u5728\u8FD9\u91CC\u3002" }), _jsx("a", { className: "ml-auto flex-none text-[#3565c5]", href: "https://github.com/pi-harness/pi-harness/blob/main/docs/plugin-marketplace.md", target: "_blank", rel: "noreferrer", children: "\u67E5\u770B\u8D21\u732E\u89C4\u8303 \u2197" })] })] })] }) }));
1186
+ }
1187
+ function MarketplaceDetail({ plugin, installed, onInstall, onBack, }) {
1188
+ const [busy, setBusy] = useState(false);
1189
+ const [error, setError] = useState("");
1190
+ const [notice, setNotice] = useState("");
1191
+ const install = async () => {
1192
+ setError("");
1193
+ setNotice("");
1194
+ setBusy(true);
1195
+ try {
1196
+ const result = await onInstall(plugin);
1197
+ if (result.restartRequired === true)
1198
+ setNotice("已写入 profile,重启 Pi Harness 后生效。");
1199
+ }
1200
+ catch (cause) {
1201
+ setError(cause instanceof Error ? cause.message : String(cause));
1202
+ }
1203
+ finally {
1204
+ setBusy(false);
1205
+ }
1206
+ };
1207
+ return (_jsx("section", { className: "marketplace-page flex min-w-0 flex-1 flex-col", children: _jsxs("div", { className: "min-h-0 flex-1 overflow-auto", children: [_jsxs("div", { className: "subnav plugin-detail-subnav", children: [_jsx("a", { href: "?page=marketplace", onClick: (event) => {
1208
+ event.preventDefault();
1209
+ onBack();
1210
+ }, children: "\u2190 \u63D2\u4EF6\u5E02\u573A" }), _jsx("span", { children: "\u63D2\u4EF6\u8BE6\u60C5" })] }), _jsxs("div", { className: "plugin-detail-content", children: [_jsxs("header", { className: "border-b border-[#e3e7ee] pb-7", children: [_jsxs("div", { className: "mb-4 flex flex-wrap items-center gap-2", children: [_jsx("span", { className: "rounded bg-[#e4edfd] px-2 py-1 font-mono text-[10px] text-[#3565c5]", children: plugin.source === "official" ? "官方插件" : "社区插件" }), _jsx("span", { className: "rounded bg-[#f2edff] px-2 py-1 text-[10px] text-[#6d4bc3]", children: plugin.category.label }), _jsx("span", { className: plugin.status === "verified"
1211
+ ? "rounded bg-[#e6faed] px-2 py-1 font-mono text-[10px] text-[#14733f]"
1212
+ : "rounded bg-[#fff5e7] px-2 py-1 font-mono text-[10px] text-[#9a6700]", children: plugin.status === "verified" ? "已验证" : "实验性" })] }), _jsxs("div", { className: "flex flex-wrap items-end justify-between gap-5", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("p", { className: "mb-2 font-mono text-[11px] uppercase tracking-[0.14em] text-[#687381]", children: "PLUGIN DETAIL" }), _jsx("h1", { className: "text-3xl font-semibold tracking-[-0.03em] text-[#20252b]", children: plugin.name }), _jsxs("code", { className: "mt-3 block break-all text-[12px] text-[#687381]", children: [plugin.packageName, " \u00B7 v", plugin.version] })] }), _jsx("div", { className: "plugin-detail-actions", children: _jsx("button", { className: "plugin-detail-action primary", disabled: installed || busy, onClick: () => void install(), type: "button", children: installed ? "已安装" : busy ? "安装中…" : "安装插件" }) })] }), _jsx("p", { className: "mt-5 max-w-3xl text-[14px] leading-7 text-[#59636e]", children: plugin.description }), notice && _jsx("p", { className: "mt-3 text-[12px] text-[#3565c5]", children: notice }), error && _jsxs("p", { className: "mt-3 text-[12px] text-[#b42318]", children: ["\u5B89\u88C5\u5931\u8D25\uFF1A", error] })] }), _jsxs("div", { className: "grid gap-4 py-6 lg:grid-cols-[minmax(0,1fr)_280px]", children: [_jsxs("div", { className: "space-y-4", children: [_jsxs("section", { className: "rounded-[10px] border border-[#e3e7ee] bg-white p-5", children: [_jsx("h2", { className: "text-[13px] font-semibold text-[#20252b]", children: "\u63D2\u4EF6\u80FD\u529B" }), _jsx("div", { className: "mt-4 flex flex-wrap gap-2", children: plugin.capabilities.map((item) => (_jsx("span", { className: "rounded-md bg-[#f1f4f9] px-2 py-1 font-mono text-[11px] text-[#61666b]", children: item }, item))) })] }), _jsxs("section", { className: "rounded-[10px] border border-[#e3e7ee] bg-white p-5", children: [_jsx("h2", { className: "text-[13px] font-semibold text-[#20252b]", children: "\u6269\u5C55\u70B9" }), _jsx("div", { className: "mt-4 space-y-2", children: plugin.hooks.map((item) => (_jsx("div", { className: "rounded-md bg-[#f8f9fb] px-3 py-2 font-mono text-[11px] text-[#61666b]", children: item }, item))) })] }), _jsxs("section", { className: "rounded-[10px] border border-[#e3e7ee] bg-white p-5", children: [_jsx("h2", { className: "text-[13px] font-semibold text-[#20252b]", children: "\u8FD0\u884C\u914D\u7F6E" }), _jsx("p", { className: "mt-1 text-[12px] text-[#687381]", children: "\u5B89\u88C5\u540E\u4F1A\u5199\u5165\u5F53\u524D\u8FD0\u884C profile\u3002" }), _jsx("pre", { className: "mt-4 overflow-auto rounded-lg bg-[#f7f8fa] p-4 text-[11px] leading-6 text-[#3b424b]", children: _jsx("code", { children: JSON.stringify(plugin.profile, null, 2) }) })] })] }), _jsxs("aside", { className: "h-fit rounded-[10px] border border-[#e3e7ee] bg-white p-5", children: [_jsx("h2", { className: "text-[13px] font-semibold text-[#20252b]", children: "\u63D2\u4EF6\u4FE1\u606F" }), _jsxs("dl", { className: "mt-4 divide-y divide-[#eef0f3] text-[12px]", children: [_jsxs("div", { className: "flex justify-between gap-4 py-3", children: [_jsx("dt", { className: "text-[#687381]", children: "\u4F5C\u8005" }), _jsx("dd", { className: "text-right text-[#3b424b]", children: plugin.author })] }), _jsxs("div", { className: "flex justify-between gap-4 py-3", children: [_jsx("dt", { className: "text-[#687381]", children: "\u8BB8\u53EF\u8BC1" }), _jsx("dd", { className: "font-mono text-[#3b424b]", children: plugin.license })] }), _jsxs("div", { className: "flex justify-between gap-4 py-3", children: [_jsx("dt", { className: "text-[#687381]", children: "\u5206\u7C7B" }), _jsx("dd", { className: "text-right text-[#3b424b]", children: plugin.category.label })] }), _jsxs("div", { className: "flex justify-between gap-4 py-3", children: [_jsx("dt", { className: "text-[#687381]", children: "\u7248\u672C" }), _jsx("dd", { className: "font-mono text-[#3b424b]", children: plugin.version })] }), marketplaceStatisticItems(plugin.statistics).map((item) => (_jsxs("div", { className: "flex justify-between gap-4 py-3", children: [_jsx("dt", { className: "text-[#687381]", children: item.label }), _jsx("dd", { className: "font-mono text-[#3b424b]", children: item.value })] }, item.label)))] }), _jsx("a", { className: "mt-4 block border-t border-[#eef0f3] pt-4 text-[12px] text-[#3565c5]", href: plugin.repository, target: "_blank", rel: "noreferrer", children: "\u67E5\u770B\u6E90\u7801 \u2197" })] })] })] })] }) }));
1213
+ }
1214
+ function Settings({ data, api, tab, onTab, onClose, onRefresh, }) {
1215
+ const status = data.status;
1216
+ const [providerState, setProviderState] = useState({});
1217
+ const [providerBusy, setProviderBusy] = useState({});
1218
+ const [providerAddOpen, setProviderAddOpen] = useState(false);
1219
+ const [providerForm, setProviderForm] = useState({ provider: "", name: "", baseUrl: "", api: "openai-completions", apiKey: "", model: "" });
1220
+ const [config, setConfig] = useState();
1221
+ const [configMode, setConfigMode] = useState("form");
1222
+ const [configSourceDraft, setConfigSourceDraft] = useState("");
1223
+ const [configBusy, setConfigBusy] = useState(false);
1224
+ const [configState, setConfigState] = useState("");
1225
+ const notifierActive = data.plugins.some((plugin) => plugin.name.endsWith("/cli-notifier") && plugin.enabled);
1226
+ const providerDialogRef = useModalFocus(providerAddOpen, () => setProviderAddOpen(false), providerBusy.__add);
1227
+ useEffect(() => {
1228
+ if (tab !== "general" && tab !== "toml")
1229
+ return;
1230
+ setConfigState("读取中…");
1231
+ void api
1232
+ .getConfig()
1233
+ .then((value) => {
1234
+ setConfig(value);
1235
+ setConfigSourceDraft(value.source);
1236
+ setConfigState("");
1237
+ })
1238
+ .catch((cause) => setConfigState(cause instanceof Error ? cause.message : String(cause)));
1239
+ }, [api, tab]);
1240
+ const updateConfig = (input, message) => {
1241
+ setConfigBusy(true);
1242
+ setConfigState(message);
1243
+ void api
1244
+ .updateConfig(input)
1245
+ .then((value) => {
1246
+ setConfig(value);
1247
+ setConfigSourceDraft(value.source);
1248
+ })
1249
+ .then(() => setConfigState("已保存"))
1250
+ .catch((cause) => setConfigState(cause instanceof Error ? cause.message : String(cause)))
1251
+ .finally(() => setConfigBusy(false));
1252
+ };
1253
+ const runProviderAction = (provider, action) => {
1254
+ if (providerBusy[provider])
1255
+ return;
1256
+ setProviderBusy((current) => ({ ...current, [provider]: true }));
1257
+ setProviderState((current) => ({ ...current, [provider]: action === "test" ? "测试中…" : "刷新中…" }));
1258
+ if (action === "test")
1259
+ void api
1260
+ .testProvider(provider)
1261
+ .then((result) => {
1262
+ const auth = result.auth;
1263
+ const label = auth && typeof auth === "object" && "label" in auth && typeof auth.label === "string" ? auth.label : undefined;
1264
+ setProviderState((current) => ({ ...current, [provider]: result.reachable ? "连接正常" : (label ?? "未检测到认证") }));
1265
+ })
1266
+ .catch((cause) => setProviderState((current) => ({ ...current, [provider]: cause instanceof Error ? cause.message : String(cause) })))
1267
+ .finally(() => setProviderBusy((current) => ({ ...current, [provider]: false })));
1268
+ else
1269
+ void api
1270
+ .refreshProvider(provider)
1271
+ .then((result) => setProviderState((current) => ({ ...current, [provider]: `${result.models.length} 个模型已刷新` })))
1272
+ .catch((cause) => setProviderState((current) => ({ ...current, [provider]: cause instanceof Error ? cause.message : String(cause) })))
1273
+ .finally(() => setProviderBusy((current) => ({ ...current, [provider]: false })));
1274
+ };
1275
+ return (_jsx("section", { className: "view-panel settings-page", children: _jsxs("div", { className: "settings-dialog", children: [_jsx("nav", { "aria-label": "\u8BBE\u7F6E\u5206\u7C7B", className: "settings-top-tabs", children: ["general", "providers", "toml"].map((item) => (_jsx("button", { "aria-pressed": tab === item, className: `settings-tab ${tab === item ? "active" : ""}`, onClick: () => onTab(item), type: "button", children: item === "general" ? "通用" : item === "providers" ? `提供商 ${data.providers.length}` : "运行配置" }, item))) }), _jsxs("section", { children: [_jsxs("header", { children: [_jsx("button", { className: "settings-back", onClick: onClose, type: "button", children: "\u2190 \u8FD4\u56DE\u4F1A\u8BDD" }), _jsxs("div", { className: "settings-header-copy", children: [_jsx("strong", { children: tab === "general" ? "通用" : tab === "providers" ? "提供商" : "运行配置" }), _jsx("small", { children: tab === "toml" ? "配置即代码,改完重载" : "运行时状态与快捷键" })] })] }), _jsxs("div", { className: "settings-body", children: [tab === "general" && (_jsxs(_Fragment, { children: [[
1276
+ ["工作目录", status?.cwd],
1277
+ ["agent 目录", status?.agentDir],
1278
+ ["会话", status ? `${status.sessionId} · ${status.messages} 条消息` : "—"],
1279
+ ["快捷键", "⌘K 命令 · ⌘, 设置 · ⌃C 中断"],
1280
+ ["权限策略", "当前 API 未提供修改接口"],
1281
+ ].map(([key, item]) => (_jsx("div", { className: "general-row", children: _jsxs("div", { children: [_jsx("strong", { children: key }), _jsx("small", { children: value(item) })] }) }, key))), _jsxs("div", { className: "general-row", children: [_jsxs("div", { children: [_jsx("strong", { children: "\u4EFB\u52A1\u7ED3\u675F\u63D0\u9192\u63D2\u4EF6" }), _jsx("small", { children: "\u7531 CLI Notifier \u63D0\u4F9B\uFF0C\u5177\u4F53\u76EE\u6807\u5728\u63D2\u4EF6\u914D\u7F6E\u4E2D\u7BA1\u7406" })] }), _jsx("span", { className: `setting-status ${notifierActive ? "on" : ""}`, children: notifierActive ? "已加载" : "未加载" })] }), _jsxs("div", { className: "general-row", children: [_jsxs("div", { children: [_jsx("strong", { children: "\u81EA\u52A8\u538B\u7F29\u4E0A\u4E0B\u6587" }), _jsx("small", { children: "\u63A5\u8FD1\u4E0A\u4E0B\u6587\u4E0A\u9650\u65F6\u81EA\u52A8\u6574\u7406\u5386\u53F2\u6D88\u606F\uFF0C\u53EF\u5728\u8FD0\u884C\u914D\u7F6E\u4E2D\u4FEE\u6539" }), !config && configState && configState !== "读取中…" ? (_jsxs("small", { className: "setting-error", role: "alert", children: ["\u914D\u7F6E\u8BFB\u53D6\u5931\u8D25\uFF1A", configState] })) : null] }), _jsx("span", { className: `setting-status ${config?.settings.compaction.enabled ? "on" : ""}`, children: config ? (config.settings.compaction.enabled ? "已开启" : "已关闭") : configState === "读取中…" ? "读取中" : "不可用" })] })] })), tab === "providers" && (_jsxs(_Fragment, { children: [_jsxs("div", { className: "provider-add-head", children: [_jsxs("div", { children: [_jsx("strong", { children: "\u5DF2\u542F\u7528\u63D0\u4F9B\u5546" }), _jsx("small", { children: "\u6A21\u578B\u5217\u8868\u53EA\u663E\u793A\u5F53\u524D\u4F1A\u8BDD\u548C\u5DF2\u914D\u7F6E\u63D0\u4F9B\u5546\u3002" })] }), _jsx("button", { className: "primary", onClick: () => setProviderAddOpen(true), type: "button", children: "\u6DFB\u52A0\u63D0\u4F9B\u5546" })] }), providerAddOpen && (_jsx("div", { className: "provider-add-overlay", onClick: () => {
1282
+ if (!providerBusy.__add)
1283
+ setProviderAddOpen(false);
1284
+ }, onKeyDown: (event) => {
1285
+ if (event.key === "Escape") {
1286
+ event.stopPropagation();
1287
+ if (!providerBusy.__add)
1288
+ setProviderAddOpen(false);
1289
+ }
1290
+ }, children: _jsxs("div", { "aria-busy": providerBusy.__add, "aria-label": "\u6DFB\u52A0\u63D0\u4F9B\u5546", "aria-modal": "true", className: "provider-add-modal", onClick: (event) => event.stopPropagation(), ref: providerDialogRef, role: "dialog", tabIndex: -1, children: [_jsxs("header", { children: [_jsxs("div", { children: [_jsx("strong", { children: "\u6DFB\u52A0\u81EA\u5B9A\u4E49\u63D0\u4F9B\u5546" }), _jsx("small", { children: "\u6CE8\u518C OpenAI \u517C\u5BB9\u63A5\u53E3\uFF0C\u51ED\u636E\u53EA\u63D0\u4EA4\u5230\u672C\u673A Pi runtime\u3002" })] }), _jsx("button", { "aria-label": "\u5173\u95ED\u6DFB\u52A0\u63D0\u4F9B\u5546", disabled: providerBusy.__add, onClick: () => setProviderAddOpen(false), type: "button", children: "\u00D7" })] }), _jsxs("form", { className: "provider-add-form", onSubmit: (event) => {
1291
+ event.preventDefault();
1292
+ if (!providerForm.provider || !providerForm.baseUrl || !providerForm.apiKey || !providerForm.model)
1293
+ return;
1294
+ setProviderBusy((current) => ({ ...current, __add: true }));
1295
+ setProviderState((current) => ({ ...current, __add: "添加中…" }));
1296
+ void api
1297
+ .addProvider(providerForm)
1298
+ .then(async () => {
1299
+ setProviderForm({ provider: "", name: "", baseUrl: "", api: "openai-completions", apiKey: "", model: "" });
1300
+ setProviderState((current) => ({ ...current, __add: "已添加" }));
1301
+ await onRefresh();
1302
+ setProviderAddOpen(false);
1303
+ })
1304
+ .catch((cause) => setProviderState((current) => ({ ...current, __add: cause instanceof Error ? cause.message : String(cause) })))
1305
+ .finally(() => setProviderBusy((current) => ({ ...current, __add: false })));
1306
+ }, children: [_jsxs("label", { children: [_jsx("span", { children: "\u63D0\u4F9B\u5546 ID" }), _jsx("input", { "aria-label": "\u63D0\u4F9B\u5546 ID", "data-dialog-initial-focus": true, maxLength: 64, minLength: 2, pattern: "[a-z0-9][a-z0-9._-]{1,63}", placeholder: "\u4F8B\u5982 openrouter", required: true, value: providerForm.provider, onChange: (event) => setProviderForm((current) => ({ ...current, provider: event.target.value })) })] }), _jsxs("label", { children: [_jsx("span", { children: "\u663E\u793A\u540D\u79F0" }), _jsx("input", { "aria-label": "\u63D0\u4F9B\u5546\u540D\u79F0", placeholder: "\u53EF\u9009", value: providerForm.name, onChange: (event) => setProviderForm((current) => ({ ...current, name: event.target.value })) })] }), _jsxs("label", { className: "provider-add-wide", children: [_jsx("span", { children: "\u63A5\u53E3\u5730\u5740" }), _jsx("input", { "aria-label": "\u63A5\u53E3\u5730\u5740", placeholder: "https://api.example.com/v1", required: true, type: "url", value: providerForm.baseUrl, onChange: (event) => setProviderForm((current) => ({ ...current, baseUrl: event.target.value })) })] }), _jsxs("label", { children: [_jsx("span", { children: "\u6A21\u578B ID" }), _jsx("input", { "aria-label": "\u6A21\u578B ID", placeholder: "\u4F8B\u5982 gpt-4o", required: true, value: providerForm.model, onChange: (event) => setProviderForm((current) => ({ ...current, model: event.target.value })) })] }), _jsxs("label", { children: [_jsx("span", { children: "\u534F\u8BAE" }), _jsxs("select", { "aria-label": "\u534F\u8BAE", value: providerForm.api, onChange: (event) => setProviderForm((current) => ({ ...current, api: event.target.value })), children: [_jsx("option", { value: "openai-completions", children: "OpenAI Completions" }), _jsx("option", { value: "openai-responses", children: "OpenAI Responses" })] })] }), _jsxs("label", { className: "provider-add-wide", children: [_jsx("span", { children: "API key" }), _jsx("input", { "aria-label": "API key", placeholder: "\u53EA\u5728\u672C\u673A\u63D0\u4EA4\uFF0C\u4E0D\u4F1A\u56DE\u663E", required: true, type: "password", value: providerForm.apiKey, onChange: (event) => setProviderForm((current) => ({ ...current, apiKey: event.target.value })) })] }), _jsxs("div", { className: "provider-add-actions", children: [_jsx("button", { className: "primary", disabled: providerBusy.__add, type: "submit", children: providerBusy.__add ? "添加中…" : "添加提供商" }), providerState.__add && _jsx("small", { "aria-live": "polite", children: providerState.__add })] })] })] }) })), _jsx("small", { children: "\u5DF2\u542F\u7528\u63D0\u4F9B\u5546 \u00B7 /api/providers" }), data.providers.length ? (data.providers.map((provider) => (_jsxs("article", { className: "provider-card", children: [_jsxs("div", { className: "provider-head", children: [_jsx("span", { className: "provider-dot", children: "\u25CF" }), _jsx("strong", { children: provider.name }), _jsx("span", { className: "provider-state", children: provider.active ? "当前会话" : provider.auth?.configured === true ? "已配置" : "未配置" })] }), _jsxs("div", { className: "provider-field", children: [_jsx("code", { children: "provider" }), _jsx("input", { "aria-label": `${provider.name} 提供商 ID`, disabled: true, value: provider.provider, readOnly: true })] }), _jsxs("div", { className: "provider-field", children: [_jsx("code", { children: "model" }), _jsxs("div", { className: "provider-model-value", title: provider.models.map((model) => model.id).join(", ") || "暂无模型", children: [_jsx("span", { children: provider.activeModel ? `${provider.activeModel.provider}/${provider.activeModel.id}` : "未选择模型" }), provider.models.length > 0 && (_jsxs("details", { className: "provider-models-details", children: [_jsxs("summary", { children: ["\u67E5\u770B ", provider.models.length, " \u4E2A\u6A21\u578B"] }), _jsx("div", { className: "model-chips", children: provider.models.map((model) => (_jsx("span", { children: model.id }, model.id))) })] }))] })] }), _jsxs("div", { className: "provider-field", children: [_jsx("code", { children: "api_key" }), _jsx("input", { "aria-label": `${provider.name} API key 状态`, disabled: true, value: "\u4E0D\u4F1A\u5728\u6D4F\u89C8\u5668\u663E\u793A", readOnly: true })] }), _jsxs("div", { className: "provider-footer", children: [_jsxs("code", { children: [provider.models.length, " \u4E2A\u6A21\u578B"] }), _jsx("button", { disabled: providerBusy[provider.provider], onClick: () => runProviderAction(provider.provider, "test"), type: "button", children: providerBusy[provider.provider] && providerState[provider.provider] === "测试中…" ? "测试中…" : "测试连接" }), _jsx("button", { className: "link-button", disabled: providerBusy[provider.provider], onClick: () => runProviderAction(provider.provider, "refresh"), type: "button", children: providerBusy[provider.provider] && providerState[provider.provider] === "刷新中…" ? "刷新中…" : "拉取模型" })] }), providerState[provider.provider] && (_jsx("small", { "aria-live": "polite", className: "provider-result", children: providerState[provider.provider] }))] }, provider.provider)))) : (_jsx("div", { className: "empty-state", children: "\u8FD0\u884C\u65F6\u6CA1\u6709\u6CE8\u518C\u63D0\u4F9B\u5546\u3002" }))] })), tab === "toml" && (_jsxs("div", { className: "config-editor", children: [_jsxs("div", { className: "toml-toolbar", children: [_jsxs("div", { children: [_jsx("strong", { children: "\u8FD0\u884C\u65F6\u914D\u7F6E" }), _jsx("span", { children: config?.path ?? "~/.pi/agent/settings.json" })] }), _jsx("button", { className: configMode === "form" ? "active" : "", onClick: () => setConfigMode("form"), type: "button", children: "\u8868\u5355" }), _jsx("button", { className: configMode === "source" ? "active" : "", onClick: () => setConfigMode("source"), type: "button", children: "\u6E90\u7801" }), _jsx("button", { className: "primary", disabled: configBusy, onClick: () => {
1307
+ setConfigBusy(true);
1308
+ setConfigState("重载中…");
1309
+ void api
1310
+ .reloadConfig()
1311
+ .then(setConfig)
1312
+ .then(() => setConfigState("已从磁盘重载"))
1313
+ .catch((cause) => setConfigState(cause instanceof Error ? cause.message : String(cause)))
1314
+ .finally(() => setConfigBusy(false));
1315
+ }, type: "button", children: "\u91CD\u8F7D" })] }), configState && (_jsx("div", { "aria-live": "polite", className: `config-state ${configState.includes("失败") || configState.includes("Error") ? "error" : ""}`, children: configState })), config ? (configMode === "source" ? (_jsxs("div", { className: "config-source-editor", children: [_jsx("textarea", { "aria-label": "settings.json \u6E90\u7801", className: "config-source", onChange: (event) => setConfigSourceDraft(event.target.value), spellCheck: false, value: configSourceDraft }), _jsxs("div", { className: "config-source-actions", children: [_jsx("small", { children: "\u5B8C\u6574 JSON \u914D\u7F6E\uFF0C\u53EF\u7F16\u8F91\u672A\u77E5\u5B57\u6BB5\uFF1B\u4FDD\u5B58\u524D\u4F1A\u6821\u9A8C\u8BED\u6CD5\u3002" }), _jsx("button", { className: "primary", disabled: configBusy || !configSourceDraft.trim(), onClick: () => {
1316
+ setConfigBusy(true);
1317
+ setConfigState("保存源码…");
1318
+ void api
1319
+ .updateConfigSource(configSourceDraft)
1320
+ .then((value) => {
1321
+ setConfig(value);
1322
+ setConfigSourceDraft(value.source);
1323
+ setConfigState("已保存源码");
1324
+ })
1325
+ .catch((cause) => setConfigState(cause instanceof Error ? cause.message : String(cause)))
1326
+ .finally(() => setConfigBusy(false));
1327
+ }, type: "button", children: "\u4FDD\u5B58\u6E90\u7801" })] })] })) : (_jsxs("div", { className: "config-sections", children: [_jsxs("section", { className: "config-section", children: [_jsxs("header", { children: [_jsx("strong", { children: "\u6A21\u578B\u9ED8\u8BA4\u503C" }), _jsx("small", { children: "\u65B0\u4F1A\u8BDD\u542F\u52A8\u65F6\u4F7F\u7528\u7684\u6A21\u578B\u548C\u601D\u8003\u7EA7\u522B" })] }), _jsxs("label", { className: "config-field", children: [_jsx("span", { children: "\u63D0\u4F9B\u5546" }), _jsxs("select", { disabled: configBusy, onChange: (event) => updateConfig({ defaultProvider: event.target.value }, "保存提供商…"), value: config.settings.defaultProvider ?? "", children: [_jsx("option", { value: "", children: "\u8DDF\u968F\u8FD0\u884C\u65F6" }), data.providers.map((provider) => (_jsx("option", { value: provider.provider, children: provider.name }, provider.provider)))] })] }), _jsxs("label", { className: "config-field", children: [_jsx("span", { children: "\u6A21\u578B" }), _jsxs("select", { disabled: configBusy, onChange: (event) => updateConfig({ defaultModel: event.target.value }, "保存模型…"), value: config.settings.defaultModel ?? "", children: [_jsx("option", { value: "", children: "\u8DDF\u968F\u63D0\u4F9B\u5546" }), data.models.map((model) => (_jsxs("option", { value: model.id, children: [model.provider, "/", model.name] }, `${model.provider}/${model.id}`)))] })] }), _jsxs("label", { className: "config-field", children: [_jsx("span", { children: "\u601D\u8003\u7EA7\u522B" }), _jsx("select", { disabled: configBusy, onChange: (event) => updateConfig({ defaultThinkingLevel: event.target.value }, "保存思考级别…"), value: config.settings.defaultThinkingLevel ?? "medium", children: ["off", "minimal", "low", "medium", "high", "xhigh", "max"].map((level) => (_jsx("option", { value: level, children: level }, level))) })] })] }), _jsxs("section", { className: "config-section", children: [_jsxs("header", { children: [_jsx("strong", { children: "\u8FD0\u884C\u7B56\u7565" }), _jsx("small", { children: "\u6D88\u606F\u961F\u5217\u548C\u7F51\u7EDC\u4F20\u8F93\u884C\u4E3A" })] }), _jsxs("label", { className: "config-field", children: [_jsx("span", { children: "\u4F20\u8F93\u65B9\u5F0F" }), _jsxs("select", { disabled: configBusy, onChange: (event) => updateConfig({ transport: event.target.value }, "保存传输方式…"), value: config.settings.transport, children: [_jsx("option", { value: "auto", children: "\u81EA\u52A8" }), _jsx("option", { value: "sse", children: "SSE" }), _jsx("option", { value: "websocket", children: "WebSocket" })] })] }), _jsxs("label", { className: "config-field", children: [_jsx("span", { children: "Steering \u6D88\u606F" }), _jsxs("select", { disabled: configBusy, onChange: (event) => updateConfig({ steeringMode: event.target.value }, "保存队列策略…"), value: config.settings.steeringMode, children: [_jsx("option", { value: "one-at-a-time", children: "\u9010\u6761\u53D1\u9001" }), _jsx("option", { value: "all", children: "\u4E00\u6B21\u53D1\u9001\u5168\u90E8" })] })] }), _jsxs("label", { className: "config-field", children: [_jsx("span", { children: "Follow-up \u6D88\u606F" }), _jsxs("select", { disabled: configBusy, onChange: (event) => updateConfig({ followUpMode: event.target.value }, "保存跟进策略…"), value: config.settings.followUpMode, children: [_jsx("option", { value: "one-at-a-time", children: "\u9010\u6761\u53D1\u9001" }), _jsx("option", { value: "all", children: "\u4E00\u6B21\u53D1\u9001\u5168\u90E8" })] })] })] }), _jsxs("section", { className: "config-section", children: [_jsxs("header", { children: [_jsx("strong", { children: "\u4E0A\u4E0B\u6587\u4E0E\u663E\u793A" }), _jsx("small", { children: "\u63A7\u5236\u601D\u8003\u5185\u5BB9\u548C\u81EA\u52A8\u538B\u7F29" })] }), _jsxs("label", { className: "config-toggle", children: [_jsxs("span", { children: [_jsx("strong", { children: "\u9690\u85CF\u601D\u8003\u6B63\u6587" }), _jsx("small", { children: "\u53EA\u663E\u793A\u53EF\u5C55\u5F00\u7684\u601D\u8003\u6458\u8981" })] }), _jsx("input", { checked: config.settings.hideThinkingBlock, disabled: configBusy, onChange: (event) => updateConfig({ hideThinkingBlock: event.target.checked }, "保存显示设置…"), type: "checkbox" })] }), _jsxs("label", { className: "config-toggle", children: [_jsxs("span", { children: [_jsx("strong", { children: "\u81EA\u52A8\u538B\u7F29\u4E0A\u4E0B\u6587" }), _jsx("small", { children: "\u63A5\u8FD1\u4E0A\u4E0B\u6587\u4E0A\u9650\u65F6\u81EA\u52A8\u6574\u7406\u5386\u53F2\u6D88\u606F" })] }), _jsx("input", { checked: config.settings.compaction.enabled, disabled: configBusy, onChange: (event) => updateConfig({ compaction: { ...config.settings.compaction, enabled: event.target.checked } }, "保存压缩设置…"), type: "checkbox" })] }), _jsxs("label", { className: "config-toggle", children: [_jsxs("span", { children: [_jsx("strong", { children: "\u81EA\u52A8\u91CD\u8BD5" }), _jsx("small", { children: "\u4E34\u65F6\u7F51\u7EDC\u9519\u8BEF\u65F6\u81EA\u52A8\u91CD\u8BD5\u8BF7\u6C42" })] }), _jsx("input", { checked: config.settings.retry.enabled, disabled: configBusy, onChange: (event) => updateConfig({ retry: { ...config.settings.retry, enabled: event.target.checked } }, "保存重试设置…"), type: "checkbox" })] }), _jsxs("label", { className: "config-toggle", children: [_jsxs("span", { children: [_jsx("strong", { children: "\u663E\u793A\u56FE\u7247" }), _jsx("small", { children: "\u5141\u8BB8\u6A21\u578B\u54CD\u5E94\u4E2D\u7684\u56FE\u7247\u6E32\u67D3" })] }), _jsx("input", { checked: config.settings.terminal.showImages, disabled: configBusy, onChange: (event) => updateConfig({ terminal: { ...config.settings.terminal, showImages: event.target.checked } }, "保存图片设置…"), type: "checkbox" })] })] }), _jsxs("section", { className: "config-section", children: [_jsxs("header", { children: [_jsx("strong", { children: "\u7EC8\u7AEF\u4E0E\u5BFC\u822A" }), _jsx("small", { children: "\u63A7\u5236\u547D\u4EE4\u884C\u754C\u9762\u548C\u6D88\u606F\u6E32\u67D3\u884C\u4E3A" })] }), _jsxs("label", { className: "config-toggle", children: [_jsxs("span", { children: [_jsx("strong", { children: "\u5B89\u9759\u542F\u52A8" }), _jsx("small", { children: "\u542F\u52A8\u65F6\u9690\u85CF\u7248\u672C\u548C\u66F4\u65B0\u63D0\u793A" })] }), _jsx("input", { checked: config.settings.advanced.quietStartup, disabled: configBusy, onChange: (event) => updateConfig({ advanced: { ...config.settings.advanced, quietStartup: event.target.checked } }, "保存启动设置…"), type: "checkbox" })] }), _jsxs("label", { className: "config-field", children: [_jsx("span", { children: "\u9879\u76EE\u53EF\u4FE1\u7B56\u7565" }), _jsxs("select", { disabled: configBusy, onChange: (event) => updateConfig({ advanced: { ...config.settings.advanced, projectTrust: event.target.value } }, "保存信任策略…"), value: config.settings.advanced.projectTrust, children: [_jsx("option", { value: "ask", children: "\u6BCF\u6B21\u8BE2\u95EE" }), _jsx("option", { value: "always", children: "\u59CB\u7EC8\u4FE1\u4EFB" }), _jsx("option", { value: "never", children: "\u4ECE\u4E0D\u4FE1\u4EFB" })] })] }), _jsxs("label", { className: "config-field", children: [_jsx("span", { children: "Mermaid \u6E32\u67D3" }), _jsxs("select", { disabled: configBusy, onChange: (event) => updateConfig({ advanced: { ...config.settings.advanced, mermaid: event.target.value } }, "保存 Mermaid 设置…"), value: config.settings.advanced.mermaid, children: [_jsx("option", { value: "off", children: "\u5173\u95ED" }), _jsx("option", { value: "final", children: "\u5B8C\u6210\u540E\u6E32\u67D3" }), _jsx("option", { value: "streaming", children: "\u6D41\u5F0F\u6E32\u67D3" })] })] }), _jsxs("label", { className: "config-field", children: [_jsx("span", { children: "\u53CC\u51FB Escape" }), _jsxs("select", { disabled: configBusy, onChange: (event) => updateConfig({ advanced: { ...config.settings.advanced, doubleEscapeAction: event.target.value } }, "保存快捷键设置…"), value: config.settings.advanced.doubleEscapeAction, children: [_jsx("option", { value: "tree", children: "\u6253\u5F00\u4F1A\u8BDD\u6811" }), _jsx("option", { value: "fork", children: "\u521B\u5EFA\u5206\u652F" }), _jsx("option", { value: "none", children: "\u4E0D\u6267\u884C" })] })] })] }), _jsxs("section", { className: "config-section", children: [_jsxs("header", { children: [_jsx("strong", { children: "\u8BCA\u65AD\u4E0E\u9690\u79C1" }), _jsx("small", { children: "\u63A7\u5236\u7F13\u5B58\u63D0\u793A\u548C\u533F\u540D\u6570\u636E\u4E0A\u62A5" })] }), _jsxs("label", { className: "config-toggle", children: [_jsxs("span", { children: [_jsx("strong", { children: "\u663E\u793A\u7F13\u5B58\u672A\u547D\u4E2D" }), _jsx("small", { children: "\u5728\u6D88\u606F\u4E2D\u663E\u793A\u6A21\u578B\u7F13\u5B58\u8BCA\u65AD" })] }), _jsx("input", { checked: config.settings.advanced.showCacheMissNotices, disabled: configBusy, onChange: (event) => updateConfig({ advanced: { ...config.settings.advanced, showCacheMissNotices: event.target.checked } }, "保存诊断设置…"), type: "checkbox" })] }), _jsxs("label", { className: "config-toggle", children: [_jsxs("span", { children: [_jsx("strong", { children: "\u5B89\u88C5\u9065\u6D4B" }), _jsx("small", { children: "\u53D1\u9001\u533F\u540D\u5B89\u88C5\u548C\u7248\u672C\u7EDF\u8BA1" })] }), _jsx("input", { checked: config.settings.advanced.enableInstallTelemetry, disabled: configBusy, onChange: (event) => updateConfig({ advanced: { ...config.settings.advanced, enableInstallTelemetry: event.target.checked } }, "保存隐私设置…"), type: "checkbox" })] })] })] }))) : (_jsx("div", { className: "empty-state", children: "\u6B63\u5728\u8BFB\u53D6\u8FD0\u884C\u65F6\u914D\u7F6E\u2026" }))] }))] })] })] }) }));
1328
+ }
1329
+ const filterCommands = (commands, query) => {
1330
+ const normalized = query.trim().toLowerCase();
1331
+ return commands.filter((command) => `${command.invocationName} ${command.description ?? ""}`.toLowerCase().includes(normalized));
1332
+ };
1333
+ function CommandPalette({ commands, query, activeIndex, onActiveIndexChange, onUse, }) {
1334
+ const visible = filterCommands(commands, query);
1335
+ const execute = (index) => {
1336
+ const command = visible[index];
1337
+ if (!command)
1338
+ return;
1339
+ onUse(`/${command.invocationName}`);
1340
+ };
1341
+ return (_jsx("div", { "aria-label": "\u547D\u4EE4\u9762\u677F", className: "command-palette", id: "command-menu", role: "listbox", children: _jsxs("div", { className: "palette-group", children: [_jsxs("small", { children: ["COMMANDS ", _jsx("span", { children: "\u00B7 RUNTIME REGISTRY" })] }), visible.length ? (visible.map((command, index) => {
1342
+ const invocation = `/${command.invocationName}`;
1343
+ return (_jsxs("button", { "aria-selected": index === activeIndex, onClick: () => execute(index), onMouseEnter: () => onActiveIndexChange(index), role: "option", type: "button", children: [_jsx("code", { children: invocation }), _jsx("span", { children: command.description ?? command.source ?? "由当前运行时注册" })] }, `${command.invocationName}:${command.source ?? "runtime"}`));
1344
+ })) : (_jsx("div", { className: "empty-state", children: commands.length ? "没有匹配的命令。" : "当前运行时没有可用的命令注册清单。" }))] }) }));
1345
+ }
1346
+ function PromptCompletionPopover({ kind, commands, files, query, activeIndex, onActiveIndexChange, onUse, }) {
1347
+ const items = kind === "command"
1348
+ ? filterCommands(commands, query).slice(0, 12)
1349
+ : files.filter((file) => `${file.path} ${file.label} ${file.status}`.toLowerCase().includes(query.trim().toLowerCase())).slice(0, 12);
1350
+ return (_jsxs("div", { "aria-label": kind === "command" ? "命令补全" : "文件补全", className: "prompt-completion", role: "listbox", children: [_jsx("small", { children: kind === "command" ? "命令" : "文件" }), items.length ? (items.slice(0, 12).map((item, index) => {
1351
+ const label = kind === "command" ? `/${item.invocationName}` : `@${item.path}`;
1352
+ const detail = kind === "command" ? (item.description ?? item.source ?? "由当前运行时注册") : item.status;
1353
+ return (_jsxs("button", { "aria-selected": index === activeIndex, onClick: () => onUse(label), onMouseEnter: () => onActiveIndexChange(index), role: "option", type: "button", children: [_jsx("strong", { children: label }), _jsx("span", { children: detail })] }, `${kind}:${label}`));
1354
+ })) : (_jsx("span", { className: "prompt-completion-empty", children: "\u6CA1\u6709\u5339\u914D\u9879" }))] }));
1355
+ }
1356
+ function GlobalSearch({ commands, sessions, files, onClose, onUse, onOpenSession, onOpenFile, }) {
1357
+ const [query, setQuery] = useState("");
1358
+ const [activeIndex, setActiveIndex] = useState(0);
1359
+ const dialogRef = useModalFocus(true, onClose);
1360
+ const normalized = query.trim().toLowerCase();
1361
+ const matches = (text) => !normalized || text.toLowerCase().includes(normalized);
1362
+ const items = [
1363
+ ...commands
1364
+ .filter((command) => matches(`${command.invocationName} ${command.description ?? ""}`))
1365
+ .map((command) => ({ kind: "command", command })),
1366
+ ...sessions
1367
+ .filter((session) => matches(`${value(session.name, "")} ${value(session.firstMessage, "")} ${value(session.sessionId, "")}`))
1368
+ .map((session) => ({ kind: "session", session })),
1369
+ ...files.filter((file) => matches(`${file.path} ${file.label} ${file.status}`)).map((file) => ({ kind: "file", file })),
1370
+ ];
1371
+ useEffect(() => setActiveIndex(0), [query]);
1372
+ const execute = (item) => {
1373
+ if (!item)
1374
+ return;
1375
+ if (item.kind === "command")
1376
+ onUse(`/${item.command.invocationName}`);
1377
+ else if (item.kind === "session")
1378
+ onOpenSession(item.session);
1379
+ else
1380
+ onOpenFile(item.file);
1381
+ onClose();
1382
+ };
1383
+ return (_jsx("div", { className: "global-search", onClick: (event) => {
1384
+ if (event.target === event.currentTarget)
1385
+ onClose();
1386
+ }, children: _jsxs("div", { "aria-label": "\u5168\u5C40\u641C\u7D22", "aria-modal": "true", className: "global-search-dialog", ref: dialogRef, role: "dialog", tabIndex: -1, children: [_jsxs("div", { className: "global-search-heading", children: [_jsx("strong", { children: "\u5168\u5C40\u641C\u7D22" }), _jsx("small", { children: "\u547D\u4EE4 \u00B7 \u4F1A\u8BDD \u00B7 \u6587\u4EF6" })] }), _jsx("input", { "aria-label": "\u5168\u5C40\u641C\u7D22", "data-dialog-initial-focus": true, onChange: (event) => setQuery(event.target.value), onKeyDown: (event) => {
1387
+ if (event.key === "Escape") {
1388
+ event.preventDefault();
1389
+ onClose();
1390
+ }
1391
+ else if (event.key === "ArrowDown" && items.length) {
1392
+ event.preventDefault();
1393
+ setActiveIndex((index) => (index + 1) % items.length);
1394
+ }
1395
+ else if (event.key === "ArrowUp" && items.length) {
1396
+ event.preventDefault();
1397
+ setActiveIndex((index) => (index - 1 + items.length) % items.length);
1398
+ }
1399
+ else if (event.key === "Enter") {
1400
+ event.preventDefault();
1401
+ execute(items[activeIndex]);
1402
+ }
1403
+ }, placeholder: "\u641C\u7D22\u547D\u4EE4\u3001\u4F1A\u8BDD\u6216\u6587\u4EF6", value: query }), _jsx("div", { className: "global-search-results", role: "listbox", children: items.length ? (["command", "session", "file"].map((kind) => {
1404
+ const group = items.filter((item) => item.kind === kind);
1405
+ if (!group.length)
1406
+ return null;
1407
+ const label = kind === "command" ? "命令" : kind === "session" ? "会话" : "文件";
1408
+ return (_jsxs("section", { className: "global-search-group", children: [_jsx("small", { children: label }), group.map((item) => {
1409
+ const index = items.indexOf(item);
1410
+ const title = item.kind === "command"
1411
+ ? `/${item.command.invocationName}`
1412
+ : item.kind === "session"
1413
+ ? value(item.session.name ?? item.session.firstMessage ?? item.session.sessionId, "未命名会话")
1414
+ : item.file.label;
1415
+ const detail = item.kind === "command"
1416
+ ? (item.command.description ?? item.command.source ?? "由当前运行时注册")
1417
+ : item.kind === "session"
1418
+ ? `${value(item.session.messageCount, "0")} 条消息`
1419
+ : `${item.file.path} · ${item.file.status}`;
1420
+ return (_jsxs("button", { "aria-selected": index === activeIndex, onClick: () => execute(item), onMouseEnter: () => setActiveIndex(index), role: "option", type: "button", children: [_jsx("strong", { children: title }), _jsx("span", { children: detail })] }, `${item.kind}:${title}:${index}`));
1421
+ })] }, kind));
1422
+ })) : (_jsx("div", { className: "empty-state", children: "\u6CA1\u6709\u5339\u914D\u7684\u547D\u4EE4\u3001\u4F1A\u8BDD\u6216\u6587\u4EF6\u3002" })) })] }) }));
1423
+ }
1424
+ export function ControlRoomView({ api = createClientApi(), appVersion }) {
1425
+ const initialQueryState = useMemo(readQueryState, []);
1426
+ const [data, setData] = useState({
1427
+ sessions: [],
1428
+ files: [],
1429
+ models: [],
1430
+ providers: [],
1431
+ plugins: [],
1432
+ pluginPanels: [],
1433
+ marketplace: [],
1434
+ marketplaceCapabilities: [],
1435
+ marketplaceCategories: [],
1436
+ marketplaceTotal: 0,
1437
+ marketplacePage: 0,
1438
+ marketplaceHasNext: false,
1439
+ commands: [],
1440
+ workspaces: [],
1441
+ });
1442
+ const [view, setView] = useState(initialQueryState.view);
1443
+ const [page, setPage] = useState(initialQueryState.page);
1444
+ const [settings, setSettings] = useState(initialQueryState.settings);
1445
+ const [details, setDetails] = useState();
85
1446
  const [commandOpen, setCommandOpen] = useState(false);
1447
+ const [globalSearchOpen, setGlobalSearchOpen] = useState(false);
1448
+ const [commandQuery, setCommandQuery] = useState("");
1449
+ const [commandIndex, setCommandIndex] = useState(0);
86
1450
  const [sessionMenuOpen, setSessionMenuOpen] = useState(false);
1451
+ const [sessionMenuPath, setSessionMenuPath] = useState();
1452
+ const [sessionToolsOpen, setSessionToolsOpen] = useState(false);
1453
+ const [sessionSelectionMode, setSessionSelectionMode] = useState(false);
1454
+ const [sessionDialog, setSessionDialog] = useState();
1455
+ const [sessionNameDraft, setSessionNameDraft] = useState("");
1456
+ const [workspaceChooserOpen, setWorkspaceChooserOpen] = useState(false);
1457
+ const [workspaceError, setWorkspaceError] = useState("");
1458
+ const [selectedWorkspacePath, setSelectedWorkspacePath] = useState();
1459
+ const [selectedSessionPath, setSelectedSessionPath] = useState(initialQueryState.sessionPath);
1460
+ const initialSessionPathRef = useRef(initialQueryState.sessionPath);
1461
+ const sessionRestoreAttemptedRef = useRef(false);
87
1462
  const [draft, setDraft] = useState("");
1463
+ const [annotations, setAnnotations] = useState([]);
1464
+ const [annotationSelection, setAnnotationSelection] = useState("");
1465
+ const [annotationNote, setAnnotationNote] = useState("");
88
1466
  const [search, setSearch] = useState("");
1467
+ const searchInputRef = useRef(null);
1468
+ const [marketplaceQuery, setMarketplaceQuery] = useState(initialQueryState.marketplaceQuery);
1469
+ const [marketplaceCapability, setMarketplaceCapability] = useState(initialQueryState.marketplaceCapability);
1470
+ const [marketplaceCategory, setMarketplaceCategory] = useState(initialQueryState.marketplaceCategory);
1471
+ const [marketplacePluginId, setMarketplacePluginId] = useState(initialQueryState.marketplacePlugin);
1472
+ const [marketplaceDetail, setMarketplaceDetail] = useState();
1473
+ const [marketplaceDetailPending, setMarketplaceDetailPending] = useState(initialQueryState.marketplacePlugin !== undefined);
1474
+ const [marketplaceDetailError, setMarketplaceDetailError] = useState("");
1475
+ const [marketplaceCatalog, setMarketplaceCatalog] = useState([]);
1476
+ const [installedPluginId, setInstalledPluginId] = useState(initialQueryState.installedPlugin);
1477
+ const [installedPluginMetadata, setInstalledPluginMetadata] = useState();
1478
+ const [marketplacePage, setMarketplacePage] = useState(initialQueryState.marketplacePage);
89
1479
  const [permission, setPermission] = useState(true);
90
- const refresh = useCallback(async () => { const [status, session, sessions, files, models, providers, plugins, marketplace, commands] = await Promise.allSettled([api.getStatus(), api.getSession(), api.listSessions(), api.getFiles(), api.listModels(), api.listProviders(), api.listPlugins(), api.listMarketplace(), api.listCommands()]); setData((current) => ({ status: status.status === "fulfilled" ? status.value : current.status, session: session.status === "fulfilled" ? session.value : current.session, sessions: sessions.status === "fulfilled" ? sessions.value : current.sessions, files: files.status === "fulfilled" ? files.value : current.files, models: models.status === "fulfilled" ? models.value : current.models, providers: providers.status === "fulfilled" ? providers.value : current.providers, plugins: plugins.status === "fulfilled" ? plugins.value : current.plugins, marketplace: marketplace.status === "fulfilled" ? marketplace.value.items : current.marketplace, marketplaceCapabilities: marketplace.status === "fulfilled" ? marketplace.value.capabilities : current.marketplaceCapabilities, commands: commands.status === "fulfilled" ? commands.value : current.commands })); }, [api]);
91
- useEffect(() => { void refresh(); const unsubscribe = api.subscribeEvents(() => void refresh()); const timer = window.setInterval(() => void refresh(), 5000); return () => { unsubscribe(); window.clearInterval(timer); }; }, [api, refresh]);
92
- useEffect(() => { const onKeyDown = (event) => { if (event.key === "Escape") {
1480
+ const [contextExpanded, setContextExpanded] = useState(false);
1481
+ const [promptError, setPromptError] = useState("");
1482
+ const [promptBusy, setPromptBusy] = useState(false);
1483
+ const [pendingPrompt, setPendingPrompt] = useState("");
1484
+ const [sessionActionBusy, setSessionActionBusy] = useState(false);
1485
+ const [includeArchivedSessions, setIncludeArchivedSessions] = useState(false);
1486
+ const [sessionPage, setSessionPage] = useState(0);
1487
+ const [sessionTotal, setSessionTotal] = useState(0);
1488
+ const [sessionHasNext, setSessionHasNext] = useState(false);
1489
+ const [selectedSessionPaths, setSelectedSessionPaths] = useState(new Set());
1490
+ const importInputRef = useRef(null);
1491
+ const [streamingAssistant, setStreamingAssistant] = useState();
1492
+ const promptInputRef = useRef(null);
1493
+ const chatScrollRef = useRef(null);
1494
+ const stickToBottomRef = useRef(true);
1495
+ const refreshTimerRef = useRef(undefined);
1496
+ const refreshQueuedRef = useRef(false);
1497
+ const [promptCaret, setPromptCaret] = useState(0);
1498
+ const [promptCompletionSuppressed, setPromptCompletionSuppressed] = useState(false);
1499
+ const [promptCompletionIndex, setPromptCompletionIndex] = useState(0);
1500
+ const [initialRefreshPending, setInitialRefreshPending] = useState(true);
1501
+ const [refreshIssues, setRefreshIssues] = useState([]);
1502
+ useEffect(() => {
1503
+ let cancelled = false;
1504
+ void loadMarketplaceCatalog(api)
1505
+ .then((items) => {
1506
+ if (!cancelled)
1507
+ setMarketplaceCatalog(items);
1508
+ })
1509
+ .catch(() => {
1510
+ if (!cancelled)
1511
+ setMarketplaceCatalog([]);
1512
+ });
1513
+ return () => {
1514
+ cancelled = true;
1515
+ };
1516
+ }, [api]);
1517
+ useEffect(() => {
1518
+ if (!selectedSessionPath && data.session?.sessionFile)
1519
+ setSelectedSessionPath(data.session.sessionFile);
1520
+ }, [data.session?.sessionFile, selectedSessionPath]);
1521
+ const promptCompletion = useMemo(() => getPromptCompletion(draft, promptCaret), [draft, promptCaret]);
1522
+ const promptCompletionItems = useMemo(() => {
1523
+ if (!promptCompletion)
1524
+ return [];
1525
+ return promptCompletion.kind === "command"
1526
+ ? filterCommands(data.commands, promptCompletion.query).slice(0, 12)
1527
+ : data.files
1528
+ .filter((file) => `${file.path} ${file.label} ${file.status}`.toLowerCase().includes(promptCompletion.query.trim().toLowerCase()))
1529
+ .slice(0, 12);
1530
+ }, [data.commands, data.files, promptCompletion]);
1531
+ const promptCompletionOpen = Boolean(promptCompletion && !promptCompletionSuppressed && promptCompletionItems.length);
1532
+ const installedPackages = useMemo(() => new Set(data.plugins.filter((plugin) => plugin.removable).map((plugin) => plugin.name)), [data.plugins]);
1533
+ const workspaceReady = !workspaceChooserOpen && Boolean(selectedWorkspacePath || data.status?.cwd || data.workspaces.find((workspace) => workspace.current)?.path || data.session);
1534
+ const installedPluginCount = useMemo(() => {
1535
+ const panelPluginIds = new Set(data.pluginPanels.map((panel) => panel.pluginId));
1536
+ return data.plugins.filter((plugin) => plugin.removable || panelPluginIds.has(plugin.name)).length;
1537
+ }, [data.pluginPanels, data.plugins]);
1538
+ useEffect(() => {
1539
+ setPromptCompletionIndex(0);
1540
+ }, [promptCompletion?.kind, promptCompletion?.query]);
1541
+ useEffect(() => {
1542
+ if (typeof window === "undefined")
1543
+ return;
1544
+ const params = new URLSearchParams(window.location.search);
1545
+ params.set("page", page);
1546
+ if (view === "chat")
1547
+ params.delete("view");
1548
+ else
1549
+ params.set("view", view);
1550
+ if (settings)
1551
+ params.set("settings", settings);
1552
+ else
1553
+ params.delete("settings");
1554
+ if (selectedSessionPath)
1555
+ params.set("session", selectedSessionPath);
1556
+ else
1557
+ params.delete("session");
1558
+ if (marketplaceQuery)
1559
+ params.set("marketplaceQuery", marketplaceQuery);
1560
+ else
1561
+ params.delete("marketplaceQuery");
1562
+ if (marketplaceCapability)
1563
+ params.set("capability", marketplaceCapability);
1564
+ else
1565
+ params.delete("capability");
1566
+ if (marketplaceCategory)
1567
+ params.set("category", marketplaceCategory);
1568
+ else
1569
+ params.delete("category");
1570
+ if (page === "plugins" && installedPluginId)
1571
+ params.set("plugin", installedPluginId);
1572
+ else if (page === "marketplace" && marketplacePluginId)
1573
+ params.set("plugin", marketplacePluginId);
1574
+ else
1575
+ params.delete("plugin");
1576
+ if (marketplacePage > 0)
1577
+ params.set("marketplacePage", String(marketplacePage));
1578
+ else
1579
+ params.delete("marketplacePage");
1580
+ const query = params.toString();
1581
+ window.history.replaceState(null, "", `${window.location.pathname}${query ? `?${query}` : ""}${window.location.hash}`);
1582
+ }, [
1583
+ installedPluginId,
1584
+ marketplaceCapability,
1585
+ marketplaceCategory,
1586
+ marketplacePage,
1587
+ marketplacePluginId,
1588
+ marketplaceQuery,
1589
+ page,
1590
+ selectedSessionPath,
1591
+ settings,
1592
+ view,
1593
+ ]);
1594
+ useEffect(() => {
1595
+ const onPopState = () => {
1596
+ const next = readQueryState();
1597
+ setCommandOpen(false);
1598
+ setGlobalSearchOpen(false);
1599
+ setSessionMenuOpen(false);
1600
+ setDetails(undefined);
1601
+ setPage(next.page);
1602
+ setView(next.view);
1603
+ setSettings(next.settings);
1604
+ setSelectedSessionPath(next.sessionPath);
1605
+ setMarketplaceQuery(next.marketplaceQuery);
1606
+ setMarketplaceCapability(next.marketplaceCapability);
1607
+ setMarketplaceCategory(next.marketplaceCategory);
1608
+ setMarketplacePage(next.marketplacePage);
1609
+ setInstalledPluginId(next.installedPlugin);
1610
+ setMarketplacePluginId(next.marketplacePlugin);
1611
+ };
1612
+ window.addEventListener("popstate", onPopState);
1613
+ return () => window.removeEventListener("popstate", onPopState);
1614
+ }, []);
1615
+ useEffect(() => {
1616
+ if (marketplacePluginId === undefined) {
1617
+ setMarketplaceDetail(undefined);
1618
+ setMarketplaceDetailPending(false);
1619
+ setMarketplaceDetailError("");
1620
+ return;
1621
+ }
1622
+ const visible = data.marketplace.find((plugin) => plugin.id === marketplacePluginId);
1623
+ if (visible !== undefined) {
1624
+ setMarketplaceDetail(visible);
1625
+ setMarketplaceDetailPending(false);
1626
+ setMarketplaceDetailError("");
1627
+ return;
1628
+ }
1629
+ let cancelled = false;
1630
+ setMarketplaceDetail(undefined);
1631
+ setMarketplaceDetailPending(true);
1632
+ setMarketplaceDetailError("");
1633
+ void api
1634
+ .listMarketplace("", "", 0, 100)
1635
+ .then((result) => {
1636
+ if (cancelled)
1637
+ return;
1638
+ const plugin = result.items.find((item) => item.id === marketplacePluginId);
1639
+ if (plugin === undefined)
1640
+ setMarketplaceDetailError("没有找到这个市场插件,它可能已下架。");
1641
+ else
1642
+ setMarketplaceDetail(plugin);
1643
+ })
1644
+ .catch((cause) => {
1645
+ if (!cancelled)
1646
+ setMarketplaceDetailError(cause instanceof Error ? cause.message : String(cause));
1647
+ })
1648
+ .finally(() => {
1649
+ if (!cancelled)
1650
+ setMarketplaceDetailPending(false);
1651
+ });
1652
+ return () => {
1653
+ cancelled = true;
1654
+ };
1655
+ }, [api, data.marketplace, marketplacePluginId]);
1656
+ useEffect(() => {
1657
+ if (installedPluginId === undefined) {
1658
+ setInstalledPluginMetadata(undefined);
1659
+ return;
1660
+ }
1661
+ let cancelled = false;
1662
+ setInstalledPluginMetadata(undefined);
1663
+ void api
1664
+ .listMarketplace("", "", 0, 100)
1665
+ .then((result) => {
1666
+ if (!cancelled)
1667
+ setInstalledPluginMetadata(result.items.find((item) => item.packageName === installedPluginId));
1668
+ })
1669
+ .catch(() => {
1670
+ if (!cancelled)
1671
+ setInstalledPluginMetadata(undefined);
1672
+ });
1673
+ return () => {
1674
+ cancelled = true;
1675
+ };
1676
+ }, [api, installedPluginId]);
1677
+ const refresh = useCallback(async () => {
1678
+ const results = await Promise.allSettled([
1679
+ api.getStatus(),
1680
+ api.getSession(),
1681
+ api.listSessions(sessionPage, 30, includeArchivedSessions),
1682
+ api.getFiles(),
1683
+ api.listModels(),
1684
+ api.listProviders(),
1685
+ api.listPlugins(),
1686
+ api.listPluginPanels(),
1687
+ api.listMarketplace(marketplaceQuery, marketplaceCapability, marketplacePage, 24, marketplaceCategory),
1688
+ api.listCommands(),
1689
+ api.listWorkspaces(),
1690
+ ]);
1691
+ const [status, session, sessions, files, models, providers, plugins, pluginPanels, marketplace, commands, workspaces] = results;
1692
+ setRefreshIssues(failedRefreshLabels(["运行状态", "当前会话", "会话列表", "文件", "模型", "提供商", "插件", "插件面板", "插件市场", "命令", "工作区"], results));
1693
+ setInitialRefreshPending(false);
1694
+ setData((current) => ({
1695
+ status: status.status === "fulfilled" ? status.value : current.status,
1696
+ session: session.status === "fulfilled" ? session.value : current.session,
1697
+ sessions: sessions.status === "fulfilled" ? sessions.value.items : current.sessions,
1698
+ files: files.status === "fulfilled" ? files.value : current.files,
1699
+ models: models.status === "fulfilled" ? models.value : current.models,
1700
+ providers: providers.status === "fulfilled" ? providers.value : current.providers,
1701
+ plugins: plugins.status === "fulfilled" ? plugins.value : current.plugins,
1702
+ pluginPanels: pluginPanels.status === "fulfilled" ? pluginPanels.value : current.pluginPanels,
1703
+ marketplace: marketplace.status === "fulfilled" ? marketplace.value.items : current.marketplace,
1704
+ marketplaceCapabilities: marketplace.status === "fulfilled" ? marketplace.value.capabilities : current.marketplaceCapabilities,
1705
+ marketplaceCategories: marketplace.status === "fulfilled" ? marketplace.value.categories : current.marketplaceCategories,
1706
+ marketplaceTotal: marketplace.status === "fulfilled" ? marketplace.value.total : current.marketplaceTotal,
1707
+ marketplacePage: marketplace.status === "fulfilled" ? marketplace.value.page : current.marketplacePage,
1708
+ marketplaceHasNext: marketplace.status === "fulfilled" ? marketplace.value.hasNext : current.marketplaceHasNext,
1709
+ commands: commands.status === "fulfilled" ? commands.value : current.commands,
1710
+ workspaces: workspaces.status === "fulfilled" ? workspaces.value : current.workspaces,
1711
+ }));
1712
+ if (sessions.status === "fulfilled") {
1713
+ setSessionTotal(sessions.value.total);
1714
+ setSessionHasNext(sessions.value.hasNext);
1715
+ }
1716
+ }, [api, includeArchivedSessions, marketplaceCapability, marketplaceCategory, marketplacePage, marketplaceQuery, sessionPage]);
1717
+ const scheduleRefresh = useCallback(() => {
1718
+ refreshQueuedRef.current = true;
1719
+ if (refreshTimerRef.current !== undefined)
1720
+ return;
1721
+ refreshTimerRef.current = window.setTimeout(() => {
1722
+ refreshTimerRef.current = undefined;
1723
+ if (!refreshQueuedRef.current)
1724
+ return;
1725
+ refreshQueuedRef.current = false;
1726
+ void refresh();
1727
+ }, 100);
1728
+ }, [refresh]);
1729
+ const handleRuntimeEvent = useCallback((payload) => {
1730
+ scheduleRefresh();
1731
+ const event = payload.event;
1732
+ if (typeof event !== "object" || event === null)
1733
+ return;
1734
+ const runtimeEvent = event;
1735
+ if (runtimeEvent.type === "turn_start") {
1736
+ setStreamingAssistant({ thinking: "", text: "" });
1737
+ return;
1738
+ }
1739
+ if (runtimeEvent.type !== "message_update" || typeof runtimeEvent.assistantMessageEvent !== "object" || runtimeEvent.assistantMessageEvent === null)
1740
+ return;
1741
+ const assistantMessageEvent = runtimeEvent.assistantMessageEvent;
1742
+ const type = assistantMessageEvent.type;
1743
+ if (type !== "thinking_delta" && type !== "text_delta")
1744
+ return;
1745
+ const delta = typeof assistantMessageEvent.delta === "string" ? assistantMessageEvent.delta : "";
1746
+ if (!delta)
1747
+ return;
1748
+ setStreamingAssistant((current) => ({
1749
+ thinking: (current?.thinking ?? "") + (type === "thinking_delta" ? delta : ""),
1750
+ text: (current?.text ?? "") + (type === "text_delta" ? delta : ""),
1751
+ }));
1752
+ }, [scheduleRefresh]);
1753
+ const createNewSession = useCallback(async (workspace) => {
1754
+ setPromptError("");
1755
+ setWorkspaceError("");
1756
+ try {
1757
+ const created = await api.createSession(workspace?.path);
1758
+ if (created.sessionFile)
1759
+ setSelectedSessionPath(created.sessionFile);
1760
+ setSettings(undefined);
1761
+ setCommandOpen(false);
1762
+ setGlobalSearchOpen(false);
1763
+ setDetails(undefined);
1764
+ setWorkspaceChooserOpen(false);
1765
+ setSelectedWorkspacePath(workspace?.path);
1766
+ setCommandQuery("");
1767
+ setPage("session");
1768
+ setView("chat");
1769
+ setSessionMenuOpen(false);
1770
+ await refresh();
1771
+ }
1772
+ catch (cause) {
1773
+ const message = cause instanceof Error ? cause.message : String(cause);
1774
+ if (workspace)
1775
+ setWorkspaceError(message);
1776
+ else
1777
+ setPromptError(message);
1778
+ }
1779
+ }, [api, refresh]);
1780
+ const beginNewSession = () => {
1781
+ setPromptError("");
1782
+ setWorkspaceError("");
1783
+ setSelectedWorkspacePath(undefined);
1784
+ setWorkspaceChooserOpen(true);
1785
+ };
1786
+ const pickDirectory = useCallback(async () => {
1787
+ try {
1788
+ const path = await api.pickDirectory();
1789
+ const name = path.split(/[\\/]/).filter(Boolean).pop() ?? path;
1790
+ await createNewSession({ path, branch: "directory", current: false, name });
1791
+ }
1792
+ catch (cause) {
1793
+ setWorkspaceError(cause instanceof Error ? cause.message : String(cause));
1794
+ }
1795
+ }, [api, createNewSession]);
1796
+ const openDirectory = useCallback(async () => {
1797
+ await pickDirectory();
1798
+ }, [pickDirectory]);
1799
+ useEffect(() => {
1800
+ void refresh();
1801
+ const unsubscribe = api.subscribeEvents(handleRuntimeEvent);
1802
+ const timer = window.setInterval(() => void refresh(), 5000);
1803
+ return () => {
1804
+ unsubscribe();
1805
+ window.clearInterval(timer);
1806
+ if (refreshTimerRef.current !== undefined) {
1807
+ window.clearTimeout(refreshTimerRef.current);
1808
+ refreshTimerRef.current = undefined;
1809
+ }
1810
+ };
1811
+ }, [api, handleRuntimeEvent, refresh]);
1812
+ useEffect(() => {
1813
+ if (data.status?.status !== "running")
1814
+ setStreamingAssistant(undefined);
1815
+ }, [data.status?.status]);
1816
+ useEffect(() => {
1817
+ const path = initialSessionPathRef.current;
1818
+ if (!path || sessionRestoreAttemptedRef.current || data.sessions.length === 0)
1819
+ return;
1820
+ sessionRestoreAttemptedRef.current = true;
1821
+ const target = data.sessions.find((session) => session.path === path);
1822
+ if (!target || typeof target.path !== "string") {
1823
+ setSelectedSessionPath(undefined);
1824
+ return;
1825
+ }
1826
+ if (data.session?.sessionFile === target.path)
1827
+ return;
1828
+ void api
1829
+ .openSession(target.path)
1830
+ .then(refresh)
1831
+ .catch((cause) => setPromptError(cause instanceof Error ? cause.message : String(cause)));
1832
+ }, [api, data.session?.sessionFile, data.sessions, refresh]);
1833
+ useEffect(() => {
1834
+ setCommandIndex(0);
1835
+ if (!commandOpen)
1836
+ return;
1837
+ const frame = window.requestAnimationFrame(() => searchInputRef.current?.focus());
1838
+ return () => window.cancelAnimationFrame(frame);
1839
+ }, [commandOpen, commandQuery]);
1840
+ useEffect(() => {
1841
+ const onKeyDown = (event) => {
1842
+ if (event.key === "Escape") {
1843
+ if (sessionDialog) {
1844
+ setSessionDialog(undefined);
1845
+ return;
1846
+ }
1847
+ if (globalSearchOpen) {
1848
+ setGlobalSearchOpen(false);
1849
+ return;
1850
+ }
1851
+ if (commandOpen) {
1852
+ setCommandOpen(false);
1853
+ setCommandQuery("");
1854
+ return;
1855
+ }
1856
+ if (details !== undefined) {
1857
+ setDetails(undefined);
1858
+ return;
1859
+ }
1860
+ setCommandOpen(false);
1861
+ setSessionMenuOpen(false);
1862
+ setSessionToolsOpen(false);
1863
+ setWorkspaceChooserOpen(false);
1864
+ setSettings(undefined);
1865
+ }
1866
+ if ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === "k") {
1867
+ event.preventDefault();
1868
+ setCommandOpen(false);
1869
+ setGlobalSearchOpen(true);
1870
+ }
1871
+ if ((event.metaKey || event.ctrlKey) && event.key === ",") {
1872
+ event.preventDefault();
1873
+ setCommandOpen(false);
1874
+ setGlobalSearchOpen(false);
1875
+ setDetails(undefined);
1876
+ setSettings("general");
1877
+ }
1878
+ };
1879
+ window.addEventListener("keydown", onKeyDown);
1880
+ return () => window.removeEventListener("keydown", onKeyDown);
1881
+ }, [commandOpen, details, globalSearchOpen, sessionDialog]);
1882
+ const events = data.session?.events ?? [];
1883
+ const displayEvents = useMemo(() => compactThinkingEvents(events), [events]);
1884
+ useEffect(() => {
1885
+ if (!stickToBottomRef.current)
1886
+ return;
1887
+ const frame = window.requestAnimationFrame(() => {
1888
+ const element = chatScrollRef.current;
1889
+ if (element)
1890
+ element.scrollTop = element.scrollHeight;
1891
+ });
1892
+ return () => window.cancelAnimationFrame(frame);
1893
+ }, [data.session?.messages.length, data.status?.events, pendingPrompt, promptBusy]);
1894
+ const filteredSessions = data.sessions.filter((session) => !search ||
1895
+ value(session.name ?? session.firstMessage, "未命名会话")
1896
+ .toLowerCase()
1897
+ .includes(search.toLowerCase()));
1898
+ const submit = (event) => {
1899
+ event.preventDefault();
1900
+ const question = draft.trim();
1901
+ const prompt = annotations.length > 0 ? formatAnnotationPrompt(annotations, question) : question;
1902
+ if (!prompt || promptBusy)
1903
+ return;
1904
+ setDraft("");
1905
+ setPromptError("");
1906
+ setPendingPrompt(prompt);
1907
+ setStreamingAssistant(undefined);
1908
+ stickToBottomRef.current = true;
1909
+ setPromptBusy(true);
1910
+ void api
1911
+ .prompt(prompt)
1912
+ .then(async () => {
1913
+ setAnnotations([]);
1914
+ await refresh();
1915
+ })
1916
+ .catch((cause) => setPromptError(cause instanceof Error ? cause.message : String(cause)))
1917
+ .finally(() => setPendingPrompt(""))
1918
+ .finally(() => setPromptBusy(false));
1919
+ };
1920
+ const captureAnnotationSelection = () => {
1921
+ window.requestAnimationFrame(() => {
1922
+ const selected = window.getSelection()?.toString().trim() ?? "";
1923
+ if (selected.length > 0)
1924
+ setAnnotationSelection(selected.slice(0, 4_000));
1925
+ });
1926
+ };
1927
+ const addAnnotation = () => {
1928
+ const quote = annotationSelection.trim();
1929
+ if (!quote)
1930
+ return;
1931
+ setAnnotations((current) => [
1932
+ ...current,
1933
+ { id: current.length === 0 ? 1 : Math.max(...current.map((item) => item.id)) + 1, quote, note: annotationNote.trim() },
1934
+ ]);
1935
+ setAnnotationSelection("");
1936
+ setAnnotationNote("");
1937
+ };
1938
+ const openSession = (session) => {
1939
+ const path = typeof session.path === "string" ? session.path : "";
1940
+ if (!path)
1941
+ return;
1942
+ setSettings(undefined);
1943
+ setCommandOpen(false);
1944
+ setGlobalSearchOpen(false);
1945
+ setPage("session");
1946
+ setView("chat");
1947
+ setDetails(undefined);
1948
+ setSelectedSessionPath(path);
1949
+ void api
1950
+ .openSession(path)
1951
+ .then(refresh)
1952
+ .catch((cause) => setPromptError(cause instanceof Error ? cause.message : String(cause)));
1953
+ };
1954
+ const sessionAction = async (action) => {
1955
+ if (sessionActionBusy)
1956
+ return;
1957
+ setSessionActionBusy(true);
1958
+ setPromptError("");
1959
+ try {
1960
+ await action();
1961
+ await refresh();
1962
+ setSelectedSessionPaths(new Set());
1963
+ setSessionMenuOpen(false);
1964
+ setSessionMenuPath(undefined);
1965
+ setSessionToolsOpen(false);
1966
+ setSessionSelectionMode(false);
1967
+ setSessionDialog(undefined);
1968
+ }
1969
+ catch (cause) {
1970
+ setPromptError(cause instanceof Error ? cause.message : String(cause));
1971
+ }
1972
+ finally {
1973
+ setSessionActionBusy(false);
1974
+ }
1975
+ };
1976
+ const activeSessionPath = data.session?.sessionFile;
1977
+ const toggleSessionSelection = (path) => {
1978
+ setSelectedSessionPaths((current) => {
1979
+ const next = new Set(current);
1980
+ if (next.has(path))
1981
+ next.delete(path);
1982
+ else
1983
+ next.add(path);
1984
+ return next;
1985
+ });
1986
+ };
1987
+ const openSessionMenu = (path, name) => {
1988
+ setSelectedSessionPath(path);
1989
+ setSessionNameDraft(name ?? "");
1990
+ setSessionMenuPath(path);
1991
+ setSessionMenuOpen(true);
1992
+ };
1993
+ const closeSessionMenu = () => {
1994
+ setSessionMenuOpen(false);
1995
+ setSessionMenuPath(undefined);
1996
+ };
1997
+ const pushInstalledPluginRoute = (pluginId) => {
1998
+ const params = new URLSearchParams(window.location.search);
1999
+ params.set("page", "plugins");
2000
+ params.delete("settings");
2001
+ if (pluginId)
2002
+ params.set("plugin", pluginId);
2003
+ else
2004
+ params.delete("plugin");
2005
+ const query = params.toString();
2006
+ window.history.pushState(null, "", `${window.location.pathname}${query ? `?${query}` : ""}${window.location.hash}`);
2007
+ setSettings(undefined);
2008
+ setDetails(undefined);
93
2009
  setCommandOpen(false);
2010
+ setGlobalSearchOpen(false);
94
2011
  setSessionMenuOpen(false);
2012
+ setSessionMenuPath(undefined);
2013
+ setPage("plugins");
2014
+ setInstalledPluginId(pluginId);
2015
+ setMarketplacePluginId(undefined);
2016
+ };
2017
+ const pushMarketplacePluginRoute = (pluginId) => {
2018
+ const params = new URLSearchParams(window.location.search);
2019
+ params.set("page", "marketplace");
2020
+ params.delete("settings");
2021
+ if (pluginId)
2022
+ params.set("plugin", pluginId);
2023
+ else
2024
+ params.delete("plugin");
2025
+ const query = params.toString();
2026
+ window.history.pushState(null, "", `${window.location.pathname}${query ? `?${query}` : ""}${window.location.hash}`);
95
2027
  setSettings(undefined);
96
- } if ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === "k") {
97
- event.preventDefault();
98
- setCommandOpen(true);
99
- } if ((event.metaKey || event.ctrlKey) && event.key === ",") {
100
- event.preventDefault();
101
- setSettings("general");
102
- } }; window.addEventListener("keydown", onKeyDown); return () => window.removeEventListener("keydown", onKeyDown); }, []);
103
- const events = data.session?.events ?? [];
104
- const filteredSessions = data.sessions.filter((session) => !search || value(session.name ?? session.firstMessage, "未命名会话").toLowerCase().includes(search.toLowerCase()));
105
- const submit = (event) => { event.preventDefault(); const prompt = draft.trim(); if (!prompt)
106
- return; setDraft(""); void api.prompt(prompt).then(() => refresh()); };
107
- const openSession = (session) => { const path = typeof session.path === "string" ? session.path : ""; if (path)
108
- void api.openSession(path).then(refresh); };
109
- const content = page === "plugins" ? _jsx(Plugins, { plugins: data.plugins, tab: pluginTab, onTab: setPluginTab, onToml: () => setSettings("toml") }) : page === "marketplace" ? _jsx(Marketplace, { plugins: data.marketplace, capabilities: data.marketplaceCapabilities }) : view === "chat" ? _jsxs("section", { className: "view-panel chat-view", children: [_jsxs("div", { className: "chat-scroll", children: [data.session?.messages.length ? data.session.messages.map((message, index) => _jsx("article", { className: `turn ${message.role === "user" ? "user" : "text"}`, children: message.role === "user" ? _jsx("div", { className: "user-bubble", children: messageText(message) }) : _jsx("p", { className: "turn-text", children: messageText(message) }) }, index)) : _jsx(Workspace, { status: data.status, onCreate: () => void api.createSession().then(refresh), onStarter: setDraft, onToml: () => setSettings("toml") }), events.map((event, index) => _jsx(RuntimeCard, { event: event }, `${value(event.type, "event")}-${index}`))] }), _jsxs("div", { className: "composer-wrap", children: [_jsxs("div", { className: "context-line", children: [_jsxs("span", { children: ["\u4E0A\u4E0B\u6587 ", _jsx("b", { children: data.status ? `${data.status.messages} / ${data.status.model}` : "0 / —" })] }), _jsxs("div", { className: `context-bar ${permission ? "" : "expanded"}`, children: [_jsx("i", {}), _jsx("i", {}), _jsx("i", {})] }), _jsx("button", { onClick: () => setPermission((current) => !current), type: "button", children: permission ? "构成" : "收起" })] }), _jsxs("form", { className: "composer", onSubmit: submit, children: [_jsx("textarea", { "aria-label": "Prompt", onChange: (event) => setDraft(event.target.value), placeholder: "\u63CF\u8FF0\u8981\u505A\u7684\u6539\u52A8\uFF0C\u2318\u21B5 \u53D1\u9001\uFF1B@ \u5F15\u7528\u6587\u4EF6\uFF0C/ \u8C03\u7528\u547D\u4EE4", rows: 2, value: draft }), _jsxs("div", { className: "composer-tools", children: [_jsx("select", { "aria-label": "\u6A21\u578B", value: data.status?.model ?? "", onChange: (event) => { const [provider, model] = event.target.value.split("/"); if (provider && model)
110
- void api.selectModel(provider, model); }, children: data.models.map((model) => _jsx("option", { value: `${model.provider}/${model.id}`, children: model.name === model.id ? `${model.provider}/${model.id}` : `${model.name} (${model.provider})` }, `${model.provider}/${model.id}`)) }), _jsxs("button", { className: "tool-chip", onClick: () => setPermission((current) => !current), type: "button", children: ["\u25CF ", permission ? "改动前询问" : "自动允许"] }), _jsx("button", { className: "tool-chip", onClick: () => setCommandOpen(true), type: "button", children: "\uFF0F \u547D\u4EE4" }), _jsx("span", { className: "composer-hint", children: "\u2318\u21B5 \u53D1\u9001 \u00B7 \u2318K \u547D\u4EE4 \u00B7 \u2303C \u4E2D\u65AD" }), _jsx("button", { className: "send-button", type: "submit", children: "\u2191" })] })] })] })] }) : view === "trajectory" ? _jsx(Trajectory, { events: events, onSelect: setDetails }) : _jsx(Files, { api: api, files: data.files, onDiff: (file) => void api.getFileDiff(file).then((diff) => setDetails({ type: "file_diff", path: diff.path, output: diff.diff })), onRefresh: () => void refresh() });
2028
+ setDetails(undefined);
2029
+ setCommandOpen(false);
2030
+ setGlobalSearchOpen(false);
2031
+ setSessionMenuOpen(false);
2032
+ setSessionMenuPath(undefined);
2033
+ setPage("marketplace");
2034
+ setInstalledPluginId(undefined);
2035
+ setMarketplacePluginId(pluginId);
2036
+ };
2037
+ const installedPlugin = installedPluginId === undefined ? undefined : data.plugins.find((plugin) => plugin.name === installedPluginId);
2038
+ const installedPluginPanel = installedPluginId === undefined ? undefined : data.pluginPanels.find((panel) => panel.pluginId === installedPluginId);
2039
+ const content = settings ? (_jsx(Settings, { api: api, data: data, tab: settings, onTab: setSettings, onRefresh: refresh, onClose: () => {
2040
+ setSettings(undefined);
2041
+ setPage("session");
2042
+ setView("chat");
2043
+ setDetails(undefined);
2044
+ } })) : page === "plugins" && installedPluginId && installedPlugin ? (_jsx(InstalledPluginDetail, { metadata: installedPluginMetadata, onBack: () => pushInstalledPluginRoute(undefined), onToggle: async (plugin) => {
2045
+ await api.togglePlugin(plugin.id, !plugin.enabled);
2046
+ await refresh();
2047
+ }, onUninstall: async (plugin) => {
2048
+ await api.uninstallPlugin(plugin.id);
2049
+ const plugins = await api.listPlugins();
2050
+ setData((current) => ({ ...current, plugins: plugins.filter((item) => item.id !== plugin.id) }));
2051
+ pushInstalledPluginRoute(undefined);
2052
+ }, panel: installedPluginPanel, plugin: installedPlugin })) : page === "plugins" && installedPluginId ? (_jsxs("section", { className: "view-panel min-w-0 overflow-auto bg-[#f8f9fb]", children: [_jsxs("div", { className: "subnav plugin-detail-subnav bg-white", children: [_jsx("a", { href: "?page=plugins", onClick: (event) => {
2053
+ event.preventDefault();
2054
+ pushInstalledPluginRoute(undefined);
2055
+ }, children: "\u2190 \u5DF2\u5B89\u88C5\u63D2\u4EF6" }), _jsx("span", { children: "\u63D2\u4EF6\u8BE6\u60C5" })] }), _jsx("div", { className: "empty-state", children: data.status ? "没有找到这个已安装插件,它可能已被移除。" : "正在读取插件详情…" })] })) : page === "plugins" ? (_jsx(Plugins, { plugins: data.plugins, panels: data.pluginPanels, catalog: marketplaceCatalog.length ? marketplaceCatalog : data.marketplace, onMarketplace: () => pushMarketplacePluginRoute(undefined), onOpenDetail: (plugin) => pushInstalledPluginRoute(plugin.name), onToml: () => {
2056
+ setDetails(undefined);
2057
+ setSettings("toml");
2058
+ }, onToggle: async (plugin) => {
2059
+ await api.togglePlugin(plugin.id, !plugin.enabled);
2060
+ await refresh();
2061
+ }, onUninstall: async (plugin) => {
2062
+ await api.uninstallPlugin(plugin.id);
2063
+ const plugins = await api.listPlugins();
2064
+ setData((current) => ({ ...current, plugins: plugins.filter((item) => item.id !== plugin.id) }));
2065
+ } })) : page === "marketplace" ? (marketplacePluginId && marketplaceDetail?.id === marketplacePluginId ? (_jsx(MarketplaceDetail, { plugin: marketplaceDetail, installed: installedPackages.has(marketplaceDetail.packageName), onBack: () => pushMarketplacePluginRoute(undefined), onInstall: async (plugin) => {
2066
+ const result = await api.installMarketplace(plugin.id);
2067
+ await refresh();
2068
+ return result;
2069
+ } })) : marketplacePluginId ? (_jsx("section", { className: "marketplace-page flex min-w-0 flex-1 flex-col", children: _jsxs("div", { className: "min-h-0 flex-1 overflow-auto", children: [_jsxs("div", { className: "subnav plugin-detail-subnav", children: [_jsx("a", { href: "?page=marketplace", onClick: (event) => {
2070
+ event.preventDefault();
2071
+ pushMarketplacePluginRoute(undefined);
2072
+ }, children: "\u2190 \u63D2\u4EF6\u5E02\u573A" }), _jsx("span", { children: "\u63D2\u4EF6\u8BE6\u60C5" })] }), _jsx("div", { className: "empty-state", children: marketplaceDetailPending ? "正在读取插件详情…" : marketplaceDetailError || "没有找到这个市场插件,它可能已下架。" })] }) })) : (_jsx(Marketplace, { plugins: data.marketplace, capabilities: data.marketplaceCapabilities, categories: data.marketplaceCategories, total: data.marketplaceTotal, page: data.marketplacePage, hasNext: data.marketplaceHasNext, query: marketplaceQuery, capabilityFilter: marketplaceCapability, categoryFilter: marketplaceCategory, onQueryChange: (value) => {
2073
+ setMarketplaceQuery(value);
2074
+ setMarketplacePage(0);
2075
+ }, onCapabilityChange: (value) => {
2076
+ setMarketplaceCapability(value);
2077
+ setMarketplacePage(0);
2078
+ }, onCategoryChange: (value) => {
2079
+ setMarketplaceCategory(value);
2080
+ setMarketplacePage(0);
2081
+ }, onOpenDetail: (plugin) => pushMarketplacePluginRoute(plugin.id), onPageChange: setMarketplacePage, onBack: () => pushInstalledPluginRoute(undefined), onToml: () => {
2082
+ setDetails(undefined);
2083
+ setSettings("toml");
2084
+ }, installedPackages: installedPackages, onInstall: async (plugin) => {
2085
+ const result = await api.installMarketplace(plugin.id);
2086
+ await refresh();
2087
+ return result;
2088
+ } }))) : view === "chat" ? (_jsxs("section", { className: "view-panel chat-view", children: [_jsxs("div", { className: `chat-scroll ${data.session?.messages.length ? "" : "is-empty"}`, onScroll: (event) => {
2089
+ const element = event.currentTarget;
2090
+ stickToBottomRef.current = element.scrollHeight - element.scrollTop - element.clientHeight < 120;
2091
+ }, ref: chatScrollRef, children: [data.session?.messages.length ? (projectChatTurns(data.session.messages).map((turn, index) => {
2092
+ return (_jsx("article", { className: `turn ${turn.role === "user" ? "user" : "text"}`, children: turn.role === "user" ? (_jsx(UserMessageBubble, { text: turn.text })) : (_jsxs(_Fragment, { children: [turn.thinking && (_jsxs("details", { className: "reasoning message-reasoning", children: [_jsx("summary", { className: "reasoning-head", children: "\u601D\u8003" }), _jsx("div", { className: "reasoning-body", children: _jsx(MarkdownMessage, { text: turn.thinking }) })] })), turn.text && _jsx(MarkdownMessage, { onMouseUp: captureAnnotationSelection, text: turn.text })] })) }, index));
2093
+ })) : (_jsx(Workspace, { status: data.status, workspaces: data.workspaces, onCreate: (workspace) => void createNewSession(workspace), onStarter: setDraft, onToml: () => {
2094
+ setDetails(undefined);
2095
+ setSettings("toml");
2096
+ } })), streamingAssistant && data.status?.status === "running" && (_jsxs("article", { className: "turn text streaming-turn", "aria-live": "polite", children: [streamingAssistant.thinking && (_jsxs("details", { className: "reasoning message-reasoning", children: [_jsx("summary", { className: "reasoning-head", children: "\u601D\u8003\u4E2D\u2026" }), _jsx("div", { className: "reasoning-body", children: _jsx(MarkdownMessage, { text: streamingAssistant.thinking }) })] })), !streamingAssistant.thinking && !streamingAssistant.text && _jsx("div", { className: "streaming-placeholder", children: "\u6B63\u5728\u751F\u6210\u2026" }), streamingAssistant.text && _jsx(MarkdownMessage, { onMouseUp: captureAnnotationSelection, text: streamingAssistant.text })] })), pendingPrompt && !data.session?.messages.some((message) => message.role === "user" && messageText(message) === pendingPrompt) && (_jsx("article", { className: "turn user pending-turn", children: _jsx(UserMessageBubble, { text: pendingPrompt }) }))] }), _jsxs("div", { className: "composer-wrap", children: [_jsxs("div", { className: "context-line", children: [_jsx("span", { className: "context-label", children: "\u5B9E\u65F6\u4E0A\u4E0B\u6587" }), _jsxs("div", { className: "context-metrics", children: [_jsxs("span", { children: [_jsx("b", { children: data.status?.messages ?? 0 }), " \u6761\u6D88\u606F"] }), _jsxs("span", { children: [_jsx("b", { children: data.status?.events ?? events.length }), " \u4E2A\u4E8B\u4EF6"] }), _jsx("span", { children: _jsx("b", { children: value(data.status?.model) }) })] }), _jsx("button", { "aria-expanded": contextExpanded, onClick: () => setContextExpanded((current) => !current), type: "button", children: contextExpanded ? "收起" : "展开" })] }), contextExpanded && (_jsxs("div", { className: "context-breakdown", role: "status", children: [_jsxs("span", { children: ["\u6D88\u606F ", _jsx("b", { children: data.status?.messages ?? 0 })] }), _jsxs("span", { children: ["\u8FD0\u884C\u65F6\u4E8B\u4EF6 ", _jsx("b", { children: data.status?.events ?? events.length })] }), _jsxs("span", { children: ["\u6A21\u578B ", _jsx("b", { children: value(data.status?.model) })] })] })), _jsxs("div", { className: "composer-stack", children: [promptError && _jsx(PromptError, { message: promptError }), annotationSelection ? (_jsxs("div", { "aria-label": "\u6DFB\u52A0\u6279\u6CE8", className: "rounded-lg border border-[#cdddf8] bg-[#f6f8ff] px-3 py-2", children: [_jsxs("div", { className: "flex items-start gap-2", children: [_jsx("span", { className: "mt-0.5 shrink-0 rounded bg-[#dce9ff] px-1.5 py-0.5 text-[10px] text-[#315fb8]", children: "\u9009\u4E2D\u7247\u6BB5" }), _jsx("p", { className: "max-h-16 flex-1 overflow-auto whitespace-pre-wrap text-[11px] text-[#30343b]", children: annotationSelection }), _jsx("button", { "aria-label": "\u53D6\u6D88\u6279\u6CE8", className: "text-[12px] text-[#687381]", onClick: () => setAnnotationSelection(""), type: "button", children: "\u00D7" })] }), _jsxs("div", { className: "mt-2 flex items-center gap-2", children: [_jsx("input", { "aria-label": "\u6279\u6CE8\u5907\u6CE8", className: "min-w-0 flex-1 rounded-md border border-[#dce5f5] bg-white px-2 py-1.5 text-[11px] outline-none", onChange: (event) => setAnnotationNote(event.target.value), placeholder: "\u5907\u6CE8\uFF08\u53EF\u9009\uFF09", value: annotationNote }), _jsx("button", { className: "rounded-md bg-[#3565c5] px-3 py-1.5 text-[11px] font-medium text-white", onClick: addAnnotation, type: "button", children: "\u52A0\u5165\u6279\u6CE8" })] })] })) : null, annotations.length > 0 ? (_jsxs("div", { className: "flex items-center gap-2 overflow-x-auto text-[10px]", children: [_jsxs("span", { className: "shrink-0 rounded-md bg-[#edf3fe] px-2 py-1 font-medium text-[#315fb8]", children: ["\u6279\u6CE8 \u00D7", annotations.length] }), annotations.map((annotation) => (_jsxs("button", { className: "max-w-48 shrink-0 truncate rounded-md border border-[#dce5f5] bg-white px-2 py-1 text-left text-[#65707b]", onClick: () => setAnnotations((current) => current.filter((item) => item.id !== annotation.id)), title: "\u70B9\u51FB\u79FB\u9664\u6279\u6CE8", type: "button", children: ["#", annotation.id, " ", annotation.quote] }, annotation.id))), _jsx("button", { className: "shrink-0 text-[#687381]", onClick: () => setAnnotations([]), type: "button", children: "\u6E05\u7A7A" })] })) : null, _jsxs("form", { className: "composer", onSubmit: submit, children: [_jsx("textarea", { "aria-label": "Prompt", onChange: (event) => {
2097
+ setDraft(event.target.value);
2098
+ setPromptCaret(event.currentTarget.selectionStart ?? event.target.value.length);
2099
+ setPromptCompletionSuppressed(false);
2100
+ event.currentTarget.style.height = "auto";
2101
+ event.currentTarget.style.height = `${Math.min(event.currentTarget.scrollHeight, 180)}px`;
2102
+ }, onKeyDown: (event) => {
2103
+ const caret = event.currentTarget.selectionStart ?? draft.length;
2104
+ const completion = getPromptCompletion(event.currentTarget.value, caret);
2105
+ const items = completion
2106
+ ? completion.kind === "command"
2107
+ ? filterCommands(data.commands, completion.query).slice(0, 12)
2108
+ : data.files
2109
+ .filter((file) => `${file.path} ${file.label} ${file.status}`.toLowerCase().includes(completion.query.trim().toLowerCase()))
2110
+ .slice(0, 12)
2111
+ : [];
2112
+ const popupOpen = Boolean(completion && !promptCompletionSuppressed && items.length);
2113
+ if (popupOpen && (event.key === "ArrowDown" || event.key === "ArrowUp")) {
2114
+ event.preventDefault();
2115
+ setPromptCompletionIndex((index) => (index + (event.key === "ArrowDown" ? 1 : -1) + items.length) % items.length);
2116
+ return;
2117
+ }
2118
+ if (popupOpen && (event.key === "Enter" || event.key === "Tab")) {
2119
+ event.preventDefault();
2120
+ const item = items[promptCompletionIndex];
2121
+ if (item && completion) {
2122
+ const value = completion.kind === "command" ? `/${item.invocationName}` : `@${item.path}`;
2123
+ const replacement = replacePromptCompletion(event.currentTarget.value, completion, `${value} `);
2124
+ setDraft(replacement.text);
2125
+ setPromptCaret(replacement.caret);
2126
+ setPromptCompletionSuppressed(false);
2127
+ requestAnimationFrame(() => {
2128
+ const input = promptInputRef.current;
2129
+ input?.focus();
2130
+ input?.setSelectionRange(replacement.caret, replacement.caret);
2131
+ });
2132
+ }
2133
+ return;
2134
+ }
2135
+ if (event.key === "Escape" && completion && !promptCompletionSuppressed) {
2136
+ event.preventDefault();
2137
+ setPromptCompletionSuppressed(true);
2138
+ return;
2139
+ }
2140
+ if ((event.metaKey || event.ctrlKey) && event.key === "Enter") {
2141
+ event.preventDefault();
2142
+ event.currentTarget.form?.requestSubmit();
2143
+ }
2144
+ }, onClick: () => {
2145
+ if (!workspaceReady)
2146
+ setWorkspaceChooserOpen(true);
2147
+ }, onFocus: (event) => {
2148
+ if (!workspaceReady) {
2149
+ event.currentTarget.blur();
2150
+ setWorkspaceChooserOpen(true);
2151
+ }
2152
+ }, placeholder: workspaceReady ? "描述要做的改动,⌘↵ 发送;@ 引用文件,/ 调用命令" : "先选择工作区,再描述要做的改动", readOnly: !workspaceReady, ref: promptInputRef, rows: 2, value: draft }), promptCompletionOpen && promptCompletion && (_jsx(PromptCompletionPopover, { activeIndex: promptCompletionIndex, commands: data.commands, files: data.files, kind: promptCompletion.kind, onActiveIndexChange: setPromptCompletionIndex, onUse: (value) => {
2153
+ const replacement = replacePromptCompletion(draft, promptCompletion, `${value} `);
2154
+ setDraft(replacement.text);
2155
+ setPromptCaret(replacement.caret);
2156
+ setPromptCompletionSuppressed(false);
2157
+ requestAnimationFrame(() => {
2158
+ const input = promptInputRef.current;
2159
+ input?.focus();
2160
+ input?.setSelectionRange(replacement.caret, replacement.caret);
2161
+ });
2162
+ }, query: promptCompletion.query })), _jsxs("div", { className: "composer-tools", children: [_jsx("select", { "aria-label": "\u6A21\u578B", disabled: !data.models.length || promptBusy, value: data.status?.model ?? "", onChange: (event) => {
2163
+ const [provider, model] = event.target.value.split("/");
2164
+ if (provider && model)
2165
+ void api.selectModel(provider, model);
2166
+ }, children: data.models.length ? (data.models.map((model) => (_jsx("option", { value: `${model.provider}/${model.id}`, children: model.name === model.id ? `${model.provider}/${model.id}` : `${model.name} (${model.provider})` }, `${model.provider}/${model.id}`)))) : (_jsx("option", { value: "", children: "\u6682\u65E0\u53EF\u7528\u6A21\u578B" })) }), _jsxs("button", { className: "tool-chip", onClick: () => setPermission((current) => !current), type: "button", children: ["\u25CF ", permission ? "改动前询问" : "自动允许"] }), _jsx("button", { className: "tool-chip", onClick: () => setCommandOpen(true), type: "button", children: "\uFF0F \u547D\u4EE4" }), _jsx("span", { className: "composer-hint", children: "\u2318\u21B5 \u53D1\u9001 \u00B7 \u2318K \u547D\u4EE4 \u00B7 \u2303C \u4E2D\u65AD" }), _jsx("button", { "aria-label": promptBusy ? "发送中" : "发送消息", className: "send-button", disabled: promptBusy || !draft.trim(), title: promptBusy ? "正在发送" : "发送消息(⌘↵)", type: "submit", children: promptBusy ? "…" : "↑" })] })] })] })] })] })) : view === "trajectory" ? (_jsx(Trajectory, { events: displayEvents, onSelect: setDetails })) : (_jsx(Files, { api: api, files: data.files, onDiff: (file) => void api.getFileDiff(file).then((diff) => setDetails({ type: "file_diff", path: diff.path, output: diff.diff })), onRefresh: () => void refresh() }));
111
2167
  const groups = sessionGroups(filteredSessions);
112
- return _jsxs("div", { className: "app-frame", children: [_jsxs("aside", { className: "sidebar", children: [_jsxs("header", { className: "brand-row", children: [_jsx("span", { className: "pi-mark", children: "\u03C0" }), _jsx("strong", { children: "pi harness" }), _jsx("span", { className: "version", children: "0.9.4" })] }), _jsxs("div", { className: "sidebar-actions", children: [_jsx("button", { className: "new-session", onClick: () => void api.createSession().then(refresh), type: "button", children: "\uFF0B \u65B0\u5EFA\u4F1A\u8BDD" }), _jsx("input", { onChange: (event) => setSearch(event.target.value), placeholder: "\u641C\u7D22\u4F1A\u8BDD\u4E0E\u4E8B\u4EF6", type: "search", value: search })] }), _jsx("div", { className: "sidebar-scroll", children: groups.length ? groups.map(([label, sessions]) => _jsxs("div", { className: "session-group", children: [_jsx("div", { className: "group-label", children: label }), sessions.map((session, index) => _jsxs("button", { className: `session-row ${session.sessionId === data.session?.sessionId ? "active" : ""}`, onClick: () => openSession(session), type: "button", children: [_jsx("span", { className: "session-dot ok" }), _jsxs("span", { className: "session-copy", children: [_jsx("strong", { children: value(session.name ?? session.firstMessage, "未命名会话") }), _jsxs("small", { children: [value(session.messageCount, "0"), " \u6761\u6D88\u606F"] })] })] }, index))] }, label)) : _jsx("div", { className: "empty-state", children: "\u6682\u65E0\u5DF2\u4FDD\u5B58\u4F1A\u8BDD" }) }), _jsxs("footer", { className: "sidebar-footer", children: [_jsxs("div", { className: "runtime-cells", children: [_jsxs("span", { children: ["model ", _jsx("b", { children: value(data.status?.model) })] }), _jsxs("span", { children: ["msgs ", _jsx("b", { children: data.status?.messages ?? 0 })] }), _jsxs("span", { children: ["status ", _jsx("b", { children: value(data.status?.status, "connecting") })] })] }), _jsxs("button", { className: `sidebar-link ${page === "plugins" ? "active" : ""}`, onClick: () => { setPage("plugins"); setSettings(undefined); }, type: "button", children: ["\u25C8 ", _jsx("span", { children: "\u63D2\u4EF6" }), _jsx("b", { children: data.plugins.length })] }), _jsxs("button", { className: `sidebar-link ${page === "marketplace" ? "active" : ""}`, onClick: () => { setPage("marketplace"); setSettings(undefined); }, type: "button", children: ["\u2726 ", _jsx("span", { children: "\u5E02\u573A" }), _jsx("b", { children: data.marketplace.length })] }), _jsxs("button", { className: "sidebar-link", onClick: () => setSettings("general"), type: "button", children: ["\u2699 ", _jsx("span", { children: "\u8BBE\u7F6E" })] }), _jsxs("button", { className: "sidebar-link", onClick: () => setCommandOpen(true), type: "button", children: [_jsx("span", { className: "link-glyph", children: "\u2318" }), _jsx("span", { children: "\u547D\u4EE4\u9762\u677F" }), _jsx("small", { children: "\u2318K" })] })] })] }), _jsxs("section", { className: "main-pane", children: [_jsxs("header", { className: "main-header", children: [_jsxs("div", { className: "active-heading", children: [_jsx("strong", { children: page === "plugins" ? "插件" : page === "marketplace" ? "插件市场" : data.session?.messages.length ? data.session.sessionId.slice(0, 12) : "新会话" }), _jsx("small", { children: page === "plugins" ? "Cordis loader 运行时清单" : page === "marketplace" ? "社区目录 · 可审查安装指引" : data.session?.sessionFile ?? "未选择工作区" })] }), _jsx("div", { className: "header-spacer" }), _jsxs("div", { className: "run-indicator", children: ["\u25CF ", data.status?.status === "running" ? "running · Pi agent" : "idle"] }), _jsx("button", { className: "stop-button", disabled: data.status?.status !== "running", onClick: () => void api.abort().then(refresh), type: "button", children: "\u505C\u6B62" }), page === "session" && _jsx("div", { className: "view-tabs", children: ["chat", "trajectory", "files"].map((item) => _jsx("button", { className: `view-tab ${view === item ? "active" : ""}`, onClick: () => setView(item), type: "button", children: item === "chat" ? "对话" : item === "trajectory" ? "轨迹" : "产出" }, item)) }), _jsx("button", { className: "session-menu", onClick: () => setSessionMenuOpen((current) => !current), type: "button", "aria-label": "\u4F1A\u8BDD\u64CD\u4F5C", children: "\u22EF" }), _jsx("button", { className: "details-toggle", onClick: () => setDetails(details ? undefined : {}), type: "button", children: "\u25E8 \u8BE6\u60C5" }), _jsx("span", { className: `status-pill ${data.status?.status === "running" ? "running" : "online"}`, children: value(data.status?.status, "connecting") }), sessionMenuOpen && _jsxs("div", { className: "session-menu-popover", children: [_jsxs("button", { className: "session-action", onClick: () => void api.createSession().then(refresh), type: "button", children: [_jsx("strong", { children: "\u65B0\u5EFA\u4F1A\u8BDD" }), _jsx("small", { children: "\u6E05\u7A7A\u5E76\u5F00\u59CB\u65B0\u7684\u8FD0\u884C\u65F6\u4F1A\u8BDD" })] }), _jsxs("button", { className: "session-action", onClick: () => window.location.reload(), type: "button", children: [_jsx("strong", { children: "\u5237\u65B0\u4F1A\u8BDD" }), _jsx("small", { children: "\u91CD\u65B0\u8BFB\u53D6\u8FD0\u884C\u65F6\u72B6\u6001" })] }), _jsxs("button", { className: "session-action", disabled: true, type: "button", children: [_jsx("strong", { children: "\u5BFC\u51FA\u4E8B\u4EF6" }), _jsx("small", { children: "API \u6682\u672A\u63D0\u4F9B\u5BFC\u51FA\u63A5\u53E3" })] }), _jsxs("button", { className: "session-action", disabled: true, type: "button", children: [_jsx("strong", { children: "\u5220\u9664\u4F1A\u8BDD" }), _jsx("small", { children: "API \u6682\u672A\u63D0\u4F9B\u5220\u9664\u63A5\u53E3" })] })] })] }), _jsx("div", { className: "view-host", children: content })] }), details !== undefined && _jsx(Details, { event: Object.keys(details).length ? details : undefined, onClose: () => setDetails(undefined), onCopy: () => void navigator.clipboard?.writeText(JSON.stringify(details, null, 2)) }), settings && _jsx(Settings, { api: api, data: data, tab: settings, onTab: setSettings, onClose: () => setSettings(undefined) }), commandOpen && _jsx(CommandPalette, { commands: data.commands, onClose: () => setCommandOpen(false), onUse: setDraft })] });
2168
+ const showCurrentSession = Boolean(data.session && !search && !filteredSessions.some((session) => session.sessionId === data.session?.sessionId));
2169
+ const visibleCommands = filterCommands(data.commands, commandQuery);
2170
+ const betterSidebarPanel = data.pluginPanels.find((panel) => panel.id === "better-sidebar-panel");
2171
+ const betterSidebarData = betterSidebarPanel?.data !== null && typeof betterSidebarPanel?.data === "object" && !Array.isArray(betterSidebarPanel?.data)
2172
+ ? betterSidebarPanel.data
2173
+ : undefined;
2174
+ const themeStudioPanel = data.pluginPanels.find((panel) => panel.id === "theme-studio-panel");
2175
+ const themeStudioData = themeStudioPanel?.data !== null && typeof themeStudioPanel?.data === "object" && !Array.isArray(themeStudioPanel?.data)
2176
+ ? themeStudioPanel.data
2177
+ : undefined;
2178
+ const themeStyle = useMemo(() => {
2179
+ if (!themeStudioData?.tokens || typeof themeStudioData.tokens !== "object" || Array.isArray(themeStudioData.tokens))
2180
+ return undefined;
2181
+ const tokens = Object.entries(themeStudioData.tokens).filter(([key, token]) => key.startsWith("--") && typeof token === "string");
2182
+ return tokens.length ? Object.fromEntries(tokens) : undefined;
2183
+ }, [themeStudioData]);
2184
+ const activeTheme = typeof themeStudioData?.theme === "string" ? themeStudioData.theme : undefined;
2185
+ const useCommand = (value) => {
2186
+ setDraft(value);
2187
+ setCommandOpen(false);
2188
+ setCommandQuery("");
2189
+ };
2190
+ return (_jsxs("div", { className: "app-frame", "data-theme": activeTheme, style: themeStyle, children: [_jsxs("aside", { className: "sidebar", children: [_jsxs("header", { className: "brand-row", children: [_jsx("span", { className: "pi-mark", "aria-hidden": "true", children: _jsx("img", { src: "/icons/svg/mark-white.svg", alt: "" }) }), _jsx("strong", { children: "pi harness" }), appVersion ? _jsx("span", { className: "version", children: appVersion }) : null] }), _jsxs("div", { className: "sidebar-actions", children: [_jsx("button", { className: "new-session", onClick: beginNewSession, type: "button", "aria-expanded": workspaceChooserOpen, children: "\uFF0B \u65B0\u5EFA\u4F1A\u8BDD" }), _jsxs("div", { className: "session-search", children: [_jsx("input", { "aria-controls": commandOpen ? "command-menu" : undefined, "aria-expanded": commandOpen, "aria-label": commandOpen ? "搜索命令" : "搜索会话", onChange: (event) => {
2191
+ const next = event.target.value;
2192
+ if (!commandOpen && next.startsWith("/")) {
2193
+ setCommandOpen(true);
2194
+ setCommandQuery(next.slice(1));
2195
+ return;
2196
+ }
2197
+ if (commandOpen)
2198
+ setCommandQuery(next.replace(/^\/\s?/, ""));
2199
+ else
2200
+ setSearch(next);
2201
+ }, onKeyDown: (event) => {
2202
+ if (!commandOpen)
2203
+ return;
2204
+ if (event.key === "ArrowDown" && visibleCommands.length) {
2205
+ event.preventDefault();
2206
+ setCommandIndex((index) => (index + 1) % visibleCommands.length);
2207
+ }
2208
+ else if (event.key === "ArrowUp" && visibleCommands.length) {
2209
+ event.preventDefault();
2210
+ setCommandIndex((index) => (index - 1 + visibleCommands.length) % visibleCommands.length);
2211
+ }
2212
+ else if (event.key === "Enter" && visibleCommands.length) {
2213
+ event.preventDefault();
2214
+ useCommand(`/${visibleCommands[commandIndex]?.invocationName ?? ""}`);
2215
+ }
2216
+ }, placeholder: commandOpen ? "输入命令名称或描述" : "搜索会话 · ⌘K 命令", ref: searchInputRef, type: "search", value: commandOpen ? `/${commandQuery}` : search }), commandOpen && (_jsx(CommandPalette, { activeIndex: commandIndex, commands: data.commands, onActiveIndexChange: setCommandIndex, onUse: useCommand, query: commandQuery }))] }), _jsx("input", { accept: ".jsonl,application/json,application/x-ndjson", "aria-label": "\u5BFC\u5165\u4F1A\u8BDD\u6587\u4EF6", hidden: true, onChange: (event) => {
2217
+ const file = event.currentTarget.files?.[0];
2218
+ event.currentTarget.value = "";
2219
+ if (!file)
2220
+ return;
2221
+ void sessionAction(async () => {
2222
+ const imported = await api.importSession(await file.text(), file.name);
2223
+ if (imported.sessionFile)
2224
+ setSelectedSessionPath(imported.sessionFile);
2225
+ });
2226
+ }, ref: importInputRef, type: "file" })] }), _jsxs("div", { className: "session-list-toolbar", children: [_jsxs("div", { className: "session-list-title", children: [_jsx("strong", { children: "\u4F1A\u8BDD" }), _jsx("span", { children: sessionTotal || data.sessions.length })] }), _jsxs("div", { className: "session-list-tools", children: [_jsx("button", { "aria-pressed": sessionSelectionMode, className: `session-tool-button ${sessionSelectionMode ? "active" : ""}`, onClick: () => {
2227
+ setSessionSelectionMode((current) => !current);
2228
+ setSelectedSessionPaths(new Set());
2229
+ }, type: "button", children: sessionSelectionMode ? "完成" : "选择" }), _jsxs("div", { className: "session-tools-wrap", children: [_jsx("button", { "aria-expanded": sessionToolsOpen, "aria-label": "\u4F1A\u8BDD\u5DE5\u5177", className: "session-tool-button icon", onClick: () => setSessionToolsOpen((current) => !current), type: "button", children: "\u22EF" }), sessionToolsOpen && (_jsxs("div", { className: "session-tools-popover", children: [_jsx("button", { onClick: () => window.location.reload(), type: "button", children: "\u5237\u65B0\u5217\u8868" }), _jsx("button", { onClick: () => importInputRef.current?.click(), type: "button", children: "\u5BFC\u5165\u4F1A\u8BDD" }), _jsx("button", { disabled: !activeSessionPath || sessionActionBusy, onClick: () => {
2230
+ if (!activeSessionPath)
2231
+ return;
2232
+ void sessionAction(async () => {
2233
+ const blob = await api.exportSession(activeSessionPath);
2234
+ const link = document.createElement("a");
2235
+ link.href = URL.createObjectURL(blob);
2236
+ link.download = `${data.session?.sessionId ?? "session"}.jsonl`;
2237
+ link.click();
2238
+ URL.revokeObjectURL(link.href);
2239
+ });
2240
+ }, type: "button", children: "\u5BFC\u51FA\u5F53\u524D\u4F1A\u8BDD" }), _jsx("button", { onClick: () => {
2241
+ setIncludeArchivedSessions((current) => !current);
2242
+ setSessionToolsOpen(false);
2243
+ void refresh();
2244
+ }, type: "button", children: includeArchivedSessions ? "隐藏归档会话" : "显示归档会话" })] }))] })] })] }), sessionSelectionMode && selectedSessionPaths.size > 0 && (_jsxs("div", { className: "session-batch-bar", children: [_jsxs("span", { children: [selectedSessionPaths.size, " \u4E2A\u5DF2\u9009\u62E9"] }), _jsx("button", { onClick: () => void sessionAction(() => api.batchSessions("archive", [...selectedSessionPaths]).then(() => undefined)), type: "button", children: "\u5F52\u6863" }), _jsx("button", { onClick: () => void sessionAction(() => api.batchSessions("pin", [...selectedSessionPaths]).then(() => undefined)), type: "button", children: "\u7F6E\u9876" }), _jsx("button", { className: "danger", onClick: () => {
2245
+ setSessionDialog("batch-delete");
2246
+ }, type: "button", children: "\u5220\u9664" })] })), _jsxs("div", { className: "sidebar-scroll", children: [showCurrentSession && data.session && (_jsxs("div", { className: "session-group", children: [_jsx("div", { className: "group-label", children: "\u5F53\u524D" }), _jsxs("div", { className: "session-row-wrap current-session-row", children: [sessionSelectionMode && (_jsx("input", { "aria-label": "\u9009\u62E9\u5F53\u524D\u4F1A\u8BDD", checked: activeSessionPath ? selectedSessionPaths.has(activeSessionPath) : false, onChange: () => activeSessionPath && toggleSessionSelection(activeSessionPath), type: "checkbox" })), _jsxs("button", { className: "session-row active", onClick: () => {
2247
+ setSettings(undefined);
2248
+ setCommandOpen(false);
2249
+ setGlobalSearchOpen(false);
2250
+ setPage("session");
2251
+ setView("chat");
2252
+ setDetails(undefined);
2253
+ setSessionMenuOpen(false);
2254
+ void refresh();
2255
+ }, type: "button", children: [_jsx("span", { className: "session-dot ok" }), _jsxs("span", { className: "session-copy", children: [_jsx("strong", { children: data.session.messages.length ? data.session.sessionId.slice(0, 12) : "新会话" }), _jsxs("small", { children: [data.session.messages.length, " \u6761\u6D88\u606F"] })] })] }), !sessionSelectionMode && activeSessionPath && (_jsx("button", { "aria-label": "\u5F53\u524D\u4F1A\u8BDD\u64CD\u4F5C", className: "session-row-more", onClick: () => openSessionMenu(activeSessionPath, data.session?.messages.length ? data.session?.sessionId.slice(0, 12) : "新会话"), type: "button", children: "\u22EF" })), !sessionSelectionMode && activeSessionPath && sessionMenuPath === activeSessionPath && sessionMenuOpen && (_jsx(SessionActionMenu, { busy: sessionActionBusy, onArchive: () => {
2256
+ closeSessionMenu();
2257
+ setSessionDialog("archive");
2258
+ }, onDelete: () => {
2259
+ closeSessionMenu();
2260
+ setSessionDialog("delete");
2261
+ }, onFork: () => void sessionAction(async () => {
2262
+ const result = await api.forkSession(activeSessionPath);
2263
+ if (result.sessionFile) {
2264
+ setSelectedSessionPath(result.sessionFile);
2265
+ await api.openSession(result.sessionFile);
2266
+ }
2267
+ }), onRename: () => {
2268
+ closeSessionMenu();
2269
+ setSessionDialog("rename");
2270
+ } }))] })] })), groups.length ? (groups.map(([label, sessions]) => (_jsxs("div", { className: "session-group", children: [_jsx("div", { className: "group-label", children: label }), sessions.map((session, index) => (_jsxs("div", { className: "session-row-wrap", children: [sessionSelectionMode && (_jsx("input", { "aria-label": `选择会话 ${value(session.name ?? session.firstMessage, "未命名会话")}`, checked: typeof session.path === "string" && selectedSessionPaths.has(session.path), onChange: () => {
2271
+ if (typeof session.path === "string")
2272
+ toggleSessionSelection(session.path);
2273
+ }, type: "checkbox" })), _jsxs("button", { className: `session-row ${session.sessionId === data.session?.sessionId ? "active" : ""}`, onClick: () => openSession(session), type: "button", children: [_jsx("span", { className: "session-dot ok" }), _jsxs("span", { className: "session-copy", children: [_jsx("strong", { children: value(session.name ?? session.firstMessage, "未命名会话") }), _jsxs("small", { children: [value(session.messageCount, "0"), " \u6761\u6D88\u606F", session.pinned === true ? " · 已置顶" : "", session.archived === true ? " · 已归档" : ""] })] })] }), !sessionSelectionMode && typeof session.path === "string" && (_jsx("button", { "aria-label": `会话操作 ${value(session.name ?? session.firstMessage, "未命名会话")}`, className: "session-row-more", onClick: (event) => {
2274
+ event.stopPropagation();
2275
+ openSessionMenu(session.path, value(session.name ?? session.firstMessage, ""));
2276
+ }, type: "button", children: "\u22EF" })), !sessionSelectionMode && typeof session.path === "string" && sessionMenuPath === session.path && sessionMenuOpen && (_jsx(SessionActionMenu, { busy: sessionActionBusy, onArchive: () => {
2277
+ closeSessionMenu();
2278
+ setSessionDialog("archive");
2279
+ }, onDelete: () => {
2280
+ closeSessionMenu();
2281
+ setSessionDialog("delete");
2282
+ }, onFork: () => void sessionAction(async () => {
2283
+ const result = await api.forkSession(session.path);
2284
+ if (result.sessionFile) {
2285
+ setSelectedSessionPath(result.sessionFile);
2286
+ await api.openSession(result.sessionFile);
2287
+ }
2288
+ }), onRename: () => {
2289
+ closeSessionMenu();
2290
+ setSessionDialog("rename");
2291
+ } }))] }, index)))] }, label)))) : !showCurrentSession ? (_jsx("div", { className: "empty-state", children: "\u6682\u65E0\u5DF2\u4FDD\u5B58\u4F1A\u8BDD" })) : null, sessionTotal > 30 && (_jsxs("div", { className: "session-pagination", children: [_jsx("button", { disabled: sessionPage === 0, onClick: () => setSessionPage((page) => Math.max(0, page - 1)), type: "button", children: "\u4E0A\u4E00\u9875" }), _jsxs("span", { children: [sessionPage + 1, " / ", Math.max(1, Math.ceil(sessionTotal / 30))] }), _jsx("button", { disabled: !sessionHasNext, onClick: () => setSessionPage((page) => page + 1), type: "button", children: "\u4E0B\u4E00\u9875" })] })), betterSidebarData && (_jsxs("section", { "aria-label": "\u5DE5\u4F5C\u533A\u6982\u89C8", className: "mx-3 mt-3 rounded-lg border border-[#dce5f5] bg-[#f6f8ff] px-3 py-3", children: [_jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsx("strong", { className: "text-[11px] font-semibold text-[#253044]", children: "\u5DE5\u4F5C\u533A\u6982\u89C8" }), _jsx("span", { className: `rounded px-1.5 py-0.5 font-mono text-[9px] ${betterSidebarData.clean === true ? "bg-[#eaf8f0] text-[#14733f]" : "bg-[#fff0f0] text-[#b42318]"}`, children: betterSidebarData.clean === true ? "clean" : `${value(betterSidebarData.changedCount ?? 0)} 变更` })] }), _jsx("code", { className: "mt-2 block truncate text-[10px] text-[#315fb8]", children: value(betterSidebarData.cwd ?? "当前工作区") }), _jsx("p", { className: "mt-1 truncate font-mono text-[10px] text-[#65707b]", children: value(betterSidebarData.branch ?? "非 Git 工作区") }), Array.isArray(betterSidebarData.changedFiles) && betterSidebarData.changedFiles.length > 0 ? (_jsx("div", { className: "mt-2 grid gap-1 border-t border-[#dce5f5] pt-2", children: betterSidebarData.changedFiles.slice(0, 3).map((item, index) => {
2292
+ const file = item !== null && typeof item === "object" ? item : {};
2293
+ return (_jsxs("code", { className: "truncate text-[9px] text-[#65707b]", children: [value(file.status ?? "??"), " ", value(file.path ?? "未命名")] }, `${value(file.path ?? "file")}-${index}`));
2294
+ }) })) : null] }))] }), _jsxs("footer", { className: "sidebar-footer", children: [_jsxs("div", { className: "runtime-cells", children: [_jsxs("span", { children: ["model ", _jsx("b", { children: value(data.status?.model) })] }), _jsxs("span", { children: ["msgs ", _jsx("b", { children: data.status?.messages ?? 0 })] }), _jsxs("span", { children: ["status ", _jsx("b", { children: value(data.status?.status, "connecting") })] })] }), _jsx("button", { "aria-label": "\u65B0\u5EFA\u4F1A\u8BDD", className: "sidebar-link compact-new-session", onClick: beginNewSession, title: "\u65B0\u5EFA\u4F1A\u8BDD", type: "button", children: "\uFF0B" }), _jsxs("button", { "aria-label": `插件,已安装 ${installedPluginCount} 个`, className: `sidebar-link ${page === "plugins" || page === "marketplace" ? "active" : ""}`, onClick: () => pushInstalledPluginRoute(undefined), title: `插件 · ${installedPluginCount} 个`, type: "button", children: ["\u25C8 ", _jsx("span", { children: "\u63D2\u4EF6" }), _jsx("b", { children: installedPluginCount })] }), _jsxs("button", { "aria-label": "\u8BBE\u7F6E", className: `sidebar-link ${settings ? "active" : ""}`, onClick: () => {
2295
+ setCommandOpen(false);
2296
+ setGlobalSearchOpen(false);
2297
+ setSessionMenuOpen(false);
2298
+ setSessionMenuPath(undefined);
2299
+ setDetails(undefined);
2300
+ setSettings("general");
2301
+ }, title: "\u8BBE\u7F6E", type: "button", children: ["\u2699 ", _jsx("span", { children: "\u8BBE\u7F6E" })] })] })] }), _jsxs("section", { className: "main-pane", children: [_jsxs("header", { className: "main-header", children: [_jsxs("div", { className: "active-heading", children: [_jsx("strong", { children: settings
2302
+ ? "设置"
2303
+ : page === "plugins"
2304
+ ? installedPluginId
2305
+ ? "插件详情"
2306
+ : "运行时插件"
2307
+ : page === "marketplace"
2308
+ ? marketplacePluginId
2309
+ ? "插件详情"
2310
+ : "插件市场"
2311
+ : data.session?.messages.length
2312
+ ? data.session.sessionId.slice(0, 12)
2313
+ : "新会话" }), _jsx("small", { children: settings
2314
+ ? "运行时状态与配置"
2315
+ : page === "plugins"
2316
+ ? installedPluginId
2317
+ ? (installedPluginMetadata?.name ?? displayPluginName(installedPluginId))
2318
+ : "已安装插件"
2319
+ : page === "marketplace"
2320
+ ? marketplacePluginId
2321
+ ? (marketplaceDetail?.name ?? marketplacePluginId)
2322
+ : "官方与社区 · 已审核目录"
2323
+ : sessionSource(data.status, data.session) })] }), _jsx("div", { className: "header-spacer" }), data.status?.status === "running" && (_jsxs("div", { className: "run-indicator running", children: [_jsx("span", { className: "run-dot" }), _jsx("span", { children: "\u8FD0\u884C\u4E2D \u00B7 Pi agent" }), _jsx("button", { className: "stop-button", onClick: () => void api.abort().then(refresh), type: "button", children: "\u505C\u6B62" })] })), !settings && page === "session" && (_jsx("div", { "aria-label": "\u4F1A\u8BDD\u89C6\u56FE", className: "view-tabs", children: ["chat", "trajectory", "files"].map((item) => (_jsx("button", { "aria-pressed": view === item, className: `view-tab ${view === item ? "active" : ""}`, onClick: () => {
2324
+ setView(item);
2325
+ setDetails(undefined);
2326
+ }, type: "button", children: item === "chat" ? "对话" : item === "trajectory" ? "轨迹" : "产出" }, item))) })), !settings && page === "session" && _jsx("span", { "aria-hidden": "true", className: "header-divider" }), !settings && page === "session" && (_jsxs(_Fragment, { children: [_jsx("button", { className: "session-menu", onClick: () => {
2327
+ setSessionMenuPath(undefined);
2328
+ setSessionMenuOpen((current) => !current);
2329
+ }, type: "button", "aria-label": "\u4F1A\u8BDD\u64CD\u4F5C", children: "\u22EF" }), _jsx("button", { "aria-pressed": details !== undefined, className: "details-toggle", onClick: () => setDetails(details ? undefined : {}), type: "button", children: "\u25E8 \u8BE6\u60C5" })] })), !settings && page === "session" && sessionMenuOpen && !sessionMenuPath && (_jsxs("div", { className: "session-menu-popover compact-session-menu", children: [_jsxs("button", { className: "session-action", disabled: !activeSessionPath || sessionActionBusy, onClick: () => {
2330
+ setSessionNameDraft(data.session?.sessionId?.slice(0, 12) ?? "");
2331
+ setSessionDialog("rename");
2332
+ setSessionMenuOpen(false);
2333
+ }, type: "button", children: [_jsx("strong", { children: "\u91CD\u547D\u540D" }), _jsx("small", { children: "\u8BBE\u7F6E\u4E00\u4E2A\u5BB9\u6613\u8BC6\u522B\u7684\u540D\u79F0" })] }), _jsxs("button", { className: "session-action", disabled: !activeSessionPath || sessionActionBusy, onClick: () => void sessionAction(async () => {
2334
+ const result = await api.forkSession(activeSessionPath);
2335
+ if (result.sessionFile) {
2336
+ setSelectedSessionPath(result.sessionFile);
2337
+ await api.openSession(result.sessionFile);
2338
+ }
2339
+ }), type: "button", children: [_jsx("strong", { children: "\u590D\u5236\u4F1A\u8BDD" }), _jsx("small", { children: "\u590D\u5236\u4E0A\u4E0B\u6587\u5E76\u6253\u5F00\u526F\u672C" })] }), _jsxs("button", { className: "session-action", disabled: !activeSessionPath || sessionActionBusy, onClick: () => {
2340
+ setSessionMenuOpen(false);
2341
+ setSessionDialog("archive");
2342
+ }, type: "button", children: [_jsx("strong", { children: "\u5F52\u6863\u4F1A\u8BDD" }), _jsx("small", { children: "\u4ECE\u9ED8\u8BA4\u5217\u8868\u9690\u85CF" })] }), _jsxs("button", { className: "session-action danger", disabled: !activeSessionPath || sessionActionBusy, onClick: () => {
2343
+ setSessionMenuOpen(false);
2344
+ setSessionDialog("delete");
2345
+ }, type: "button", children: [_jsx("strong", { children: "\u5220\u9664\u4F1A\u8BDD" }), _jsx("small", { children: "\u6C38\u4E45\u5220\u9664\u672C\u5730\u8BB0\u5F55" })] })] }))] }), refreshIssues.length > 0 && (_jsxs("div", { "aria-live": "polite", className: "refresh-warning", role: "status", children: [_jsxs("span", { children: [_jsx("strong", { children: "\u90E8\u5206\u6570\u636E\u5237\u65B0\u5931\u8D25" }), refreshIssues.join("、"), "\u53EF\u80FD\u4E3A\u7A7A\u6216\u663E\u793A\u4E0A\u6B21\u7ED3\u679C\u3002"] }), _jsx("button", { onClick: () => void refresh(), type: "button", children: "\u91CD\u8BD5" })] })), _jsx("div", { className: "view-host", children: initialRefreshPending ? (_jsxs("div", { "aria-live": "polite", className: "initial-loading", role: "status", children: [_jsx("span", { "aria-hidden": "true" }), "\u6B63\u5728\u8FDE\u63A5 Pi runtime\u2026"] })) : (content) })] }), !settings && page === "session" && details !== undefined && (_jsx(Details, { event: Object.keys(details).length ? details : undefined, onClose: () => setDetails(undefined), onCopy: () => void navigator.clipboard?.writeText(JSON.stringify(details, null, 2)) })), globalSearchOpen && (_jsx(GlobalSearch, { commands: data.commands, files: data.files, onClose: () => setGlobalSearchOpen(false), onOpenFile: (file) => {
2346
+ setPage("session");
2347
+ setView("files");
2348
+ setDetails({ type: "file", path: file.path, status: file.status });
2349
+ }, onOpenSession: openSession, onUse: setDraft, sessions: data.sessions })), workspaceChooserOpen && (_jsx(WorkspaceChooser, { error: workspaceError, onClose: () => setWorkspaceChooserOpen(false), onPickDirectory: openDirectory, onSelect: (workspace) => void createNewSession(workspace), workspaces: data.workspaces })), sessionDialog && (_jsx(SessionDialog, { busy: sessionActionBusy, count: sessionDialog === "batch-delete" ? selectedSessionPaths.size : undefined, kind: sessionDialog, name: sessionDialog === "rename" ? undefined : value(data.session?.sessionId, "当前会话"), onChange: setSessionNameDraft, onClose: () => setSessionDialog(undefined), onConfirm: () => {
2350
+ if (sessionDialog === "rename" && activeSessionPath) {
2351
+ void sessionAction(() => api.renameSession(activeSessionPath, sessionNameDraft.trim()).then(() => undefined));
2352
+ }
2353
+ else if (sessionDialog === "archive" && activeSessionPath) {
2354
+ void sessionAction(async () => {
2355
+ await api.setSessionMetadata(activeSessionPath, { archived: true });
2356
+ });
2357
+ }
2358
+ else if (sessionDialog === "delete" && activeSessionPath) {
2359
+ void sessionAction(async () => {
2360
+ await api.deleteSession(activeSessionPath);
2361
+ });
2362
+ }
2363
+ else if (sessionDialog === "batch-delete") {
2364
+ void sessionAction(() => api.batchSessions("delete", [...selectedSessionPaths]).then(() => undefined));
2365
+ }
2366
+ }, value: sessionNameDraft }))] }));
113
2367
  }
114
2368
  //# sourceMappingURL=react-room.js.map