zen-gitsync 2.17.17 → 2.17.18

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 (62) hide show
  1. package/README.md +2 -0
  2. package/package.json +1 -1
  3. package/src/paths.js +10 -0
  4. package/src/ui/public/assets/{AgentView-CXZUWLPL.css → AgentView-AMFKSDeH.css} +1 -1
  5. package/src/ui/public/assets/AgentView-DQAB0ypS.js +13 -0
  6. package/src/ui/public/assets/{AppVersionBadge-D70AjIBo.js → AppVersionBadge-B5VG1_Lu.js} +2 -2
  7. package/src/ui/public/assets/{BranchSelector-t3fnGS_5.js → BranchSelector-Cj6athRO.js} +1 -1
  8. package/src/ui/public/assets/{CommitForm-DmlTnTwc.js → CommitForm-a2tMsfF9.js} +1 -1
  9. package/src/ui/public/assets/{CommonDialog-CecgvEzd.js → CommonDialog-I-GCqRMC.js} +1 -1
  10. package/src/ui/public/assets/EditorView-wTi53Nxc.js +16 -0
  11. package/src/ui/public/assets/{FileDiffViewer-DH8Y2lUO.js → FileDiffViewer-B7i4BmbH.js} +1 -1
  12. package/src/ui/public/assets/{FlowExecutionViewer-Cie2_TG4.js → FlowExecutionViewer-xZjrf8e1.js} +1 -1
  13. package/src/ui/public/assets/{FlowOrchestrationWorkspace-Bbf8X1KP.js → FlowOrchestrationWorkspace-R0QKmUpG.js} +1 -1
  14. package/src/ui/public/assets/{IconButton-BEiZI4F6.js → IconButton-B6eqvssJ.js} +1 -1
  15. package/src/ui/public/assets/{LogList-DvuC03Tx.js → LogList-BPqurE9g.js} +1 -1
  16. package/src/ui/public/assets/{MindmapView-B6rITyNs.js → MindmapView-NdFNlkTF.js} +1 -1
  17. package/src/ui/public/assets/{MonitorView-q92EZvay.js → MonitorView-DuSZa8a3.js} +1 -1
  18. package/src/ui/public/assets/{ProjectStartupButton-RiIi8TwW.js → ProjectStartupButton-BrfKVP-w.js} +1 -1
  19. package/src/ui/public/assets/{RemoteManagerDialog-qtBotYAQ.js → RemoteManagerDialog-BI7fRsOQ.js} +1 -1
  20. package/src/ui/public/assets/{RemoteRepoCard-DvtzfwHV.js → RemoteRepoCard-B4E8Ud3F.js} +1 -1
  21. package/src/ui/public/assets/{SourceMapView-EEWAmy4U.js → SourceMapView-B0OzHjxP.js} +1 -1
  22. package/src/ui/public/assets/{SvgIcon-Bkc_oGUI.js → SvgIcon-B2h7B2yF.js} +1 -1
  23. package/src/ui/public/assets/{TemplateManager-9e4amMlI.js → TemplateManager-mIWE3Qf8.js} +1 -1
  24. package/src/ui/public/assets/{UserInputNode-4FoJblJi.js → UserInputNode-BafC-B2U.js} +1 -1
  25. package/src/ui/public/assets/{WorkbenchView-BFaTinH8.js → WorkbenchView-BseGz8hJ.js} +5 -5
  26. package/src/ui/public/assets/{_plugin-vue_export-helper-BLGowG5t.js → _plugin-vue_export-helper-Dvuzpv2Y.js} +4 -4
  27. package/src/ui/public/assets/agentConversations-BEKqkGcm.js +5 -0
  28. package/src/ui/public/assets/{configStore-BUXv5i5j.js → configStore-CX0FkQ94.js} +1 -1
  29. package/src/ui/public/assets/{gitStore-BGbEYd0U.js → gitStore-CMuWWr2d.js} +1 -1
  30. package/src/ui/public/assets/{index-Di5cimoI.js → index-CB2cIiHl.js} +12 -12
  31. package/src/ui/public/assets/{previewSandbox-DEQpyVNu.js → previewSandbox-DxR4iN9P.js} +0 -0
  32. package/src/ui/public/index.html +10 -10
  33. package/src/ui/server/index.js +28 -2
  34. package/src/ui/server/routes/aiContext/collectors.js +360 -0
  35. package/src/ui/server/routes/aiContext/collectors.test.js +297 -0
  36. package/src/ui/server/routes/aiContext/index.js +444 -0
  37. package/src/ui/server/routes/aiContext/index.test.js +433 -0
  38. package/src/ui/server/routes/aiContext/jobRefresh.js +110 -0
  39. package/src/ui/server/routes/aiContext/jobRefresh.test.js +191 -0
  40. package/src/ui/server/routes/aiContext/render.js +366 -0
  41. package/src/ui/server/routes/aiContext/render.test.js +255 -0
  42. package/src/ui/server/routes/aiContext/wiring.js +80 -0
  43. package/src/ui/server/routes/fs.js +43 -0
  44. package/src/ui/server/routes/mindmap.js +36 -24
  45. package/src/ui/server/routes/monitor.js +44 -35
  46. package/src/ui/server/routes/remoteRepos.js +57 -48
  47. package/src/ui/server/routes/workbench/agentChat.js +35 -7
  48. package/src/ui/server/routes/workbench/agentChatContext.test.js +66 -1
  49. package/src/ui/server/routes/workbench/agentEngines.js +77 -0
  50. package/src/ui/server/routes/workbench/agentEngines.test.js +65 -0
  51. package/src/ui/server/routes/workbench/agentRoutes.js +169 -44
  52. package/src/ui/server/routes/workbench/agentRoutes.test.js +66 -4
  53. package/src/ui/server/routes/workbench/agentSessionStore.js +3 -0
  54. package/src/ui/server/routes/workbench/envContext.js +61 -64
  55. package/src/ui/server/routes/workbench/envContext.test.js +133 -63
  56. package/src/ui/server/routes/workbench/index.js +78 -32
  57. package/src/ui/server/routes/workbench/runExternalTurn.js +279 -0
  58. package/src/ui/server/routes/workbench/runExternalTurn.test.js +275 -0
  59. package/src/ui/server/routes/workbench/shared.js +17 -0
  60. package/src/ui/public/assets/AgentView-Dhs3eKFY.js +0 -7
  61. package/src/ui/public/assets/EditorView-DVRemzZU.js +0 -16
  62. package/src/ui/public/assets/agentConversations-BQCIv4u1.js +0 -5
@@ -0,0 +1,275 @@
1
+ // 外部引擎一轮对话的适配器单测。
2
+ //
3
+ // 这里**故意不 mock 事件处理器** —— 用的是 taskRunner 里真的那三个
4
+ // (createClaudeEventHandler / createOpencodeEventHandler / createCodexEventHandler),
5
+ // 只把 spawn 换成假的子进程喂固定的 NDJSON。这样测的是"三家协议 → SSE 事件"这条真链路:
6
+ // mock 掉处理器就只能测到我自己写的胶水,而那恰恰是最不容易错的部分。
7
+ //
8
+ // 每个引擎的样例 NDJSON 都取自实测(见 taskRunner 各 handler 的头部注释与
9
+ // taskRunner.opencode.test.js / taskRunner.codex.test.js 的 fixture 口径)。
10
+ import { test } from 'node:test';
11
+ import assert from 'node:assert/strict';
12
+ import { EventEmitter } from 'node:events';
13
+ import { Readable } from 'node:stream';
14
+
15
+ import { runExternalTurn } from './runExternalTurn.js';
16
+
17
+ /** 假子进程:按顺序把 lines 推给 stdout,然后 close。 */
18
+ function fakeChild(lines, { exitCode = 0 } = {}) {
19
+ const child = new EventEmitter();
20
+ child.pid = 4242;
21
+ child.exitCode = null;
22
+ child.stdout = new Readable({ read() {} });
23
+ child.stderr = new Readable({ read() {} });
24
+ child.kill = () => { child.exitCode = 0; child.emit('close', 0); };
25
+ setImmediate(() => {
26
+ for (const l of lines) child.stdout.push(`${l}\n`);
27
+ child.stdout.push(null);
28
+ child.exitCode = exitCode;
29
+ child.emit('close', exitCode);
30
+ });
31
+ return child;
32
+ }
33
+
34
+ /** 收事件的小工具 */
35
+ function collector() {
36
+ const events = [];
37
+ return {
38
+ events,
39
+ send: (evt) => events.push(evt),
40
+ of: (type) => events.filter(e => e.type === type),
41
+ types: () => events.map(e => e.type),
42
+ };
43
+ }
44
+
45
+ const baseSession = () => ({ messages: [], engineSessionId: '' });
46
+
47
+ test('claude:stream-json → content / thinking / tool_call_start / tool_result / done', async () => {
48
+ const lines = [
49
+ JSON.stringify({ type: 'system', subtype: 'init', session_id: 'claude-sess-1' }),
50
+ JSON.stringify({ type: 'assistant', message: { content: [{ type: 'text', text: '你好' }] } }),
51
+ JSON.stringify({ type: 'assistant', message: { content: [{ type: 'thinking', thinking: '先看看' }] } }),
52
+ JSON.stringify({ type: 'assistant', message: { content: [{ type: 'tool_use', id: 't1', name: 'Bash', input: { command: 'ls' } }] } }),
53
+ JSON.stringify({ type: 'user', message: { content: [{ type: 'tool_result', tool_use_id: 't1', content: 'a.txt\nb.txt' }] } }),
54
+ JSON.stringify({ type: 'assistant', message: { content: [{ type: 'text', text: '结束' }] } }),
55
+ ];
56
+ const session = baseSession();
57
+ const c = collector();
58
+ await runExternalTurn({
59
+ session, engine: 'claude', userMessage: '列个目录', cwd: 'D:/ws',
60
+ send: c.send,
61
+ launchers: { claude: async () => ({ pid: 4242, child: fakeChild(lines) }) },
62
+ });
63
+
64
+ assert.equal(c.of('content').map(e => e.delta).join(''), '你好结束');
65
+ assert.equal(c.of('thinking').map(e => e.delta).join(''), '先看看');
66
+ const starts = c.of('tool_call_start');
67
+ assert.equal(starts.length, 1);
68
+ assert.equal(starts[0].toolCallId, 't1');
69
+ assert.equal(starts[0].name, 'Bash');
70
+ assert.match(starts[0].argsPreview, /ls/);
71
+ const results = c.of('tool_result');
72
+ assert.equal(results.length, 1);
73
+ assert.match(String(results[0].result), /a\.txt/);
74
+ assert.equal(c.of('done').length, 1);
75
+ assert.equal(c.of('error').length, 0);
76
+ assert.equal(c.of('done')[0].content, '你好结束');
77
+
78
+ // 续聊标识搬运:claude 的 session_id → session.engineSessionId
79
+ assert.equal(session.engineSessionId, 'claude-sess-1');
80
+ });
81
+
82
+ test('opencode:--format json → 同一组事件(含 completed 态工具)', async () => {
83
+ const lines = [
84
+ JSON.stringify({ type: 'step_start', sessionID: 'oc-1', part: { type: 'step-start' } }),
85
+ JSON.stringify({ type: 'text', sessionID: 'oc-1', part: { id: 'p1', type: 'text', text: '看看' } }),
86
+ JSON.stringify({ type: 'reasoning', sessionID: 'oc-1', part: { id: 'p2', type: 'reasoning', text: '思考中' } }),
87
+ JSON.stringify({ type: 'tool_use', sessionID: 'oc-1', part: { id: 'p3', callID: 'c1', type: 'tool', tool: 'bash', state: { status: 'completed', input: { cmd: 'ls' }, output: 'ok' } } }),
88
+ JSON.stringify({ type: 'step_finish', sessionID: 'oc-1', part: { type: 'step-finish' } }),
89
+ ];
90
+ const session = baseSession();
91
+ const c = collector();
92
+ await runExternalTurn({
93
+ session, engine: 'opencode', userMessage: 'hi', cwd: 'D:/ws',
94
+ send: c.send,
95
+ launchers: { opencode: async () => ({ pid: 4242, child: fakeChild(lines) }) },
96
+ });
97
+
98
+ assert.equal(c.of('content').map(e => e.delta).join(''), '看看');
99
+ assert.equal(c.of('thinking').map(e => e.delta).join(''), '思考中');
100
+ assert.equal(c.of('tool_call_start')[0].name, 'bash');
101
+ assert.match(String(c.of('tool_result')[0].result), /ok/);
102
+ assert.equal(c.of('done').length, 1);
103
+ assert.equal(session.engineSessionId, 'oc-1');
104
+ });
105
+
106
+ test('codex:exec --json → 同一组事件(item.* 分派)', async () => {
107
+ const lines = [
108
+ JSON.stringify({ type: 'thread.started', thread_id: 'th-1' }),
109
+ JSON.stringify({ type: 'item.completed', item: { id: 'i1', type: 'agent_message', text: '好了' } }),
110
+ JSON.stringify({ type: 'item.completed', item: { id: 'i2', type: 'reasoning', text: '想想' } }),
111
+ JSON.stringify({ type: 'item.completed', item: { id: 'i3', type: 'command_execution', command: 'ls', status: 'completed', aggregated_output: 'files', exit_code: 0 } }),
112
+ JSON.stringify({ type: 'turn.completed', usage: { input_tokens: 1, output_tokens: 1 } }),
113
+ ];
114
+ const session = baseSession();
115
+ const c = collector();
116
+ await runExternalTurn({
117
+ session, engine: 'codex', userMessage: 'hi', cwd: 'D:/ws',
118
+ send: c.send,
119
+ launchers: { codex: async () => ({ pid: 4242, child: fakeChild(lines) }) },
120
+ });
121
+
122
+ assert.equal(c.of('content').map(e => e.delta).join(''), '好了');
123
+ assert.equal(c.of('thinking').map(e => e.delta).join(''), '想想');
124
+ assert.equal(c.of('tool_call_start')[0].name, 'command_execution');
125
+ assert.match(String(c.of('tool_result')[0].result), /files/);
126
+ assert.equal(c.of('done').length, 1);
127
+ assert.equal(session.engineSessionId, 'th-1');
128
+ });
129
+
130
+ test('非 JSON 行(CLI 的告警)原样贴出来,不当成事件丢掉', async () => {
131
+ const session = baseSession();
132
+ const c = collector();
133
+ await runExternalTurn({
134
+ session, engine: 'claude', userMessage: 'hi', cwd: 'D:/ws',
135
+ send: c.send,
136
+ launchers: { claude: async () => ({ pid: 4242, child: fakeChild(['Warning: something odd', '{"type":"result","subtype":"success"}']) }) },
137
+ });
138
+ assert.match(c.of('content').map(e => e.delta).join(''), /Warning: something odd/);
139
+ assert.equal(c.of('error').length, 0, '告警不该被判成失败');
140
+ });
141
+
142
+ test('跨数据块被切断的 NDJSON 行要能拼回来', async () => {
143
+ const session = baseSession();
144
+ const c = collector();
145
+ const child = new EventEmitter();
146
+ child.pid = 1; child.exitCode = null;
147
+ child.stdout = new Readable({ read() {} });
148
+ child.stderr = new Readable({ read() {} });
149
+ child.kill = () => {};
150
+ setImmediate(() => {
151
+ // 一条 JSON 被从中间切开推送
152
+ child.stdout.push('{"type":"assistant","message":{"content":[{"type":"te');
153
+ child.stdout.push('xt","text":"拼回来了"}]}}\n');
154
+ child.stdout.push(null);
155
+ child.emit('close', 0);
156
+ });
157
+ await runExternalTurn({
158
+ session, engine: 'claude', userMessage: 'hi', cwd: 'D:/ws',
159
+ send: c.send,
160
+ launchers: { claude: async () => ({ pid: 1, child }) },
161
+ });
162
+ assert.equal(c.of('content').map(e => e.delta).join(''), '拼回来了');
163
+ });
164
+
165
+ test('工作区状态块拼在用户消息前面(不写进用户的仓库文件)', async () => {
166
+ const session = baseSession();
167
+ const c = collector();
168
+ let seenPrompt = '';
169
+ await runExternalTurn({
170
+ session, engine: 'claude', userMessage: '我的仓库有哪些', cwd: 'D:/ws',
171
+ promptPrefix: '【工作区状态】快照目录: C:/u/.zen-gitsync/ai-context',
172
+ send: c.send,
173
+ launchers: { claude: async (_cwd, prompt) => { seenPrompt = prompt; return { pid: 1, child: fakeChild([]) }; } },
174
+ });
175
+ assert.match(seenPrompt, /【工作区状态】/);
176
+ assert.match(seenPrompt, /我的仓库有哪些/);
177
+ assert.ok(seenPrompt.indexOf('【工作区状态】') < seenPrompt.indexOf('我的仓库有哪些'), '状态块必须在用户消息之前');
178
+ });
179
+
180
+ test('附件只传绝对路径,内容不进 prompt', async () => {
181
+ const session = baseSession();
182
+ const c = collector();
183
+ let seenPrompt = '';
184
+ await runExternalTurn({
185
+ session, engine: 'claude', userMessage: '看看附件', cwd: 'D:/ws',
186
+ filePaths: ['C:/u/.zen-gitsync/agent-attachments/2026-09-28/a.pdf'],
187
+ send: c.send,
188
+ launchers: { claude: async (_cwd, prompt) => { seenPrompt = prompt; return { pid: 1, child: fakeChild([]) }; } },
189
+ });
190
+ assert.match(seenPrompt, /a\.pdf/);
191
+ assert.match(seenPrompt, /绝对路径/);
192
+ });
193
+
194
+ test('续聊:把上次的 engineSessionId 交给 launcher(--resume / --session)', async () => {
195
+ const session = { messages: [], engineSessionId: 'prev-id' };
196
+ const c = collector();
197
+ let resumeArg = null;
198
+ await runExternalTurn({
199
+ session, engine: 'claude', userMessage: '继续', cwd: 'D:/ws',
200
+ send: c.send,
201
+ launchers: { claude: async (_cwd, _prompt, resumeId) => { resumeArg = resumeId; return { pid: 1, child: fakeChild([]) }; } },
202
+ });
203
+ assert.equal(resumeArg, 'prev-id');
204
+ });
205
+
206
+ test('launcher 抛错(CLI 没装)→ 发 error,不让整轮静默失败', async () => {
207
+ const session = baseSession();
208
+ const c = collector();
209
+ await runExternalTurn({
210
+ session, engine: 'codex', userMessage: 'hi', cwd: 'D:/ws',
211
+ send: c.send,
212
+ launchers: { codex: async () => { throw new Error('spawn codex ENOENT'); } },
213
+ });
214
+ assert.equal(c.of('error').length, 1);
215
+ assert.match(c.of('error')[0].error, /Codex 启动失败/);
216
+ assert.match(c.of('error')[0].error, /ENOENT/);
217
+ assert.equal(c.of('done').length, 0, '启动失败不该再发 done');
218
+ });
219
+
220
+ test('未知引擎 → 明确报错(不静默当内置处理)', async () => {
221
+ const c = collector();
222
+ await runExternalTurn({ session: baseSession(), engine: 'gemini', userMessage: 'hi', cwd: 'D:/ws', send: c.send });
223
+ assert.equal(c.of('error').length, 1);
224
+ assert.match(c.of('error')[0].error, /未知的外部引擎/);
225
+ });
226
+
227
+ test('落盘:user + assistant(带 tool_calls) + tool 结果,形状与 g ai 一致', async () => {
228
+ const lines = [
229
+ JSON.stringify({ type: 'assistant', message: { content: [{ type: 'text', text: '看完了' }] } }),
230
+ JSON.stringify({ type: 'assistant', message: { content: [{ type: 'tool_use', id: 't9', name: 'Read', input: { path: 'a.md' } }] } }),
231
+ JSON.stringify({ type: 'user', message: { content: [{ type: 'tool_result', tool_use_id: 't9', content: '内容' }] } }),
232
+ ];
233
+ const session = baseSession();
234
+ const c = collector();
235
+ await runExternalTurn({
236
+ session, engine: 'claude', userMessage: '看看', cwd: 'D:/ws',
237
+ send: c.send,
238
+ launchers: { claude: async () => ({ pid: 1, child: fakeChild(lines) }) },
239
+ });
240
+
241
+ assert.equal(session.messages[0].role, 'user');
242
+ const assistant = session.messages.find(m => m.role === 'assistant');
243
+ assert.equal(assistant.content, '看完了');
244
+ assert.equal(assistant.tool_calls[0].id, 't9');
245
+ assert.equal(assistant.tool_calls[0].type, 'function');
246
+ assert.equal(assistant.tool_calls[0].function.name, 'Read');
247
+ const tool = session.messages.find(m => m.role === 'tool');
248
+ assert.equal(tool.tool_call_id, 't9');
249
+ assert.equal(tool.content, '内容');
250
+ });
251
+
252
+ test('中止:用户点停止 → 杀掉子进程树并标 [已停止]', async () => {
253
+ const session = baseSession();
254
+ const c = collector();
255
+ const ac = new AbortController();
256
+ let killed = false;
257
+ const child = new EventEmitter();
258
+ child.pid = 999; child.exitCode = null;
259
+ child.stdout = new Readable({ read() {} });
260
+ child.stderr = new Readable({ read() {} });
261
+ child.kill = () => { child.exitCode = 143; child.emit('close', 143); };
262
+ setImmediate(() => { child.stdout.push(JSON.stringify({ type: 'assistant', message: { content: [{ type: 'text', text: '写了一半' }] } }) + '\n'); ac.abort(); });
263
+
264
+ await runExternalTurn({
265
+ session, engine: 'claude', userMessage: 'hi', cwd: 'D:/ws',
266
+ signal: ac.signal,
267
+ send: c.send,
268
+ launchers: { claude: async () => ({ pid: 999, child }) },
269
+ // 注入杀掉实现:真实现走 taskkill,假子进程上观察不到,只能注入
270
+ killTree: () => { killed = true; child.kill(); },
271
+ });
272
+
273
+ assert.equal(killed, true, '中止必须杀掉子进程(否则界面停了、机器上还在跑)');
274
+ assert.match(c.of('done')[0].content, /已停止/);
275
+ });
@@ -49,6 +49,23 @@ export const DEFAULT_JOBS_CONFIG = { maxCount: 500, maxSizeMB: 256 };
49
49
  export const ORCHESTRATOR_FILE = path.join(DATA_DIR, 'orchestrator.json');
50
50
  export const MAX_ORCHESTRATOR_INSTRUCTIONS = 200;
51
51
 
52
+ /**
53
+ * 「真相源文件」清单 —— 注入给模型、让它需要细节时自己去读全文的那几个文件。
54
+ *
55
+ * 为什么集中在这一处:有**两条**链路都要把这份清单报给模型 ——
56
+ * · aiContext(智能体页对话,七个板块的注入块)
57
+ * · envContext(多项目编排台派发任务时的运行环境块)
58
+ * 以前是各写各的(一个写三个文件名、另一个写四个),加一个可读文件就得改两处,
59
+ * 而漏改的那一处**不会报错**:模型只是永远不知道那个文件存在,于是回答"我看不到"。
60
+ * 现在路径只有这一份,标签/取舍仍由各视图自己决定(那是视图的职责,不是口径)。
61
+ */
62
+ export const TRUTH_FILES = {
63
+ tasksFile: TASKS_FILE,
64
+ jobsFile: JOBS_FILE,
65
+ orchestratorFile: ORCHESTRATOR_FILE,
66
+ configFile: CONFIG_FILE,
67
+ };
68
+
52
69
  // 派发默认提示词(全局 / 各项目级)**单条**长度上限。
53
70
  // 它不是"指令",而是一条每次派发都会被拼进 prompt 的约束 —— 4000 字足够写下一整套
54
71
  // 规范,再长只会让每一次执行都白烧一遍 token。
@@ -1,7 +0,0 @@
1
- import"./rolldown-runtime-C0FnF6B9.js";import{$ as e,A as t,Bt as n,Cn as r,Ct as i,Dn as a,Dt as o,En as s,Gn as c,H as l,Hn as u,Jr as d,K as f,Kr as p,Mn as m,Nr as h,Ot as g,Pn as _,Q as v,Qr as y,Rn as b,Tn as x,Ut as S,Yn as C,Zn as w,a as T,at as E,dr as D,er as O,ft as k,gr as A,hn as j,i as M,ir as N,j as P,jn as F,ln as I,or as L,qn as R,qt as z,r as B,rn as V,sr as H,st as U,vr as W,wn as G,yn as K}from"./element-plus-D7LDHcAn.js";import{n as ee,s as te}from"./vendor-CLmPUj3K.js";import{n as q,t as J}from"./_plugin-vue_export-helper-BLGowG5t.js";import{t as Y}from"./configStore-BUXv5i5j.js";import{t as X}from"./CommonDialog-CecgvEzd.js";import{a as ne,i as re,n as ie,o as ae,r as oe,t as se}from"./agentConversations-BQCIv4u1.js";b(),D();function ce(e,t=680){let n=W(0),i=null;function a(){let t=e.value;return t?(n.value=t.clientWidth,typeof ResizeObserver>`u`||(i=new ResizeObserver(e=>{let t=e[0]?.contentRect?.width;typeof t==`number`&&(n.value=t)}),i.observe(t),!0)):!1}return R(()=>{a()||u(()=>a())}),c(()=>{i?.disconnect(),i=null}),{width:n,narrow:r(()=>n.value>0&&n.value<t)}}b(),D();var Z=_({__name:`MarketplacePanel`,props:{type:{type:String,required:!0}},setup(t,{expose:i}){i();let a=t,s=Y(),c=W([]),l=W([]),u=W(!1),d=W(``),f=W(``),p=W([]),m=W(`project`),h=W(new Set),g=W(new Set),_=r(()=>s.currentDirectory||``),v=null;async function y(){if(!u.value){u.value=!0;try{let e=new URLSearchParams({type:a.type,cwd:_.value});f.value&&e.set(`q`,f.value),p.value.length&&e.set(`sources`,p.value.join(`,`));let t=await(await fetch(`/api/agent/marketplace/catalog?${e}`)).json();t?.success?(c.value=t.groups||[],l.value=t.installed||[]):M.error(t?.error||q(`@MKT:加载失败`))}catch{M.error(q(`@MKT:加载失败`))}finally{u.value=!1}}}N(d,e=>{v&&clearTimeout(v),v=setTimeout(()=>{f.value=e.trim(),y()},400)}),N(p,()=>y()),N(()=>a.type,()=>{p.value=[],f.value=``,d.value=``,y()}),N(_,()=>y()),y();let b=r(()=>{let e=_.value?_.value.split(/[\\/]/).filter(Boolean).pop():``;return m.value===`project`?e||q(`@MKT:当前项目`):q(`@MKT:g ai 智能体`)});function x(e){return e.stars?`${C(e.stars)} ★`:e.downloads?`${C(e.downloads)} ${q(`@MKT:周下载`)}`:e.uses?`${C(e.uses)} ${q(`@MKT:次使用`)}`:``}function C(e){return e>=1e3?`${(e/1e3).toFixed(e>=1e4?0:1)}k`:String(e)}function w(e){return`${e.id}`}function T(e){return h.value.has(w(e))}let E=r(()=>{let e={project:[],global:[]};for(let t of l.value)(e[t.target]||=[]).push(t);return e}),D=A({visible:!1,item:null,env:{},args:``});function O(e){return a.type===`mcp`&&(!!e.envKeys?.length||!!e.args?.length)}function j(e){D.item=e,D.env=Object.fromEntries((e.envKeys||[]).map(e=>[e,``])),D.args=(e.args||[]).join(` `),D.visible=!0}function P(){let e=D.item;if(D.visible=!1,!e)return;let t=Object.fromEntries(Object.entries(D.env).filter(([,e])=>e.trim()!==``)),n=D.args.trim()?D.args.trim().match(/(?:[^\s"]+|"[^"]*")+/g)?.map(e=>e.replace(/^"|"$/g,``))??void 0:void 0;I(e,{env:t,...n?{args:n}:{}})}async function F(e){if(!e.installed||await L(e)){if(O(e)){j(e);return}await I(e,{})}}async function I(e,t){let n=w(e);h.value.add(n);try{let n=await fetch(`/api/agent/marketplace/install`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({type:a.type,target:m.value,cwd:_.value,item:{...e,...t}})}),r=await n.json().catch(()=>null);if(!n.ok||!r?.success){M.error(r?.error||q(`@MKT:安装失败`));return}r.item?.warning&&M.warning(r.item.warning),r.item?.envKeys?.length?M.warning(`${q(`@MKT:还缺环境变量`)}: ${r.item.envKeys.join(`, `)}`):M.success(q(`@MKT:安装成功`)),await y()}catch{M.error(q(`@MKT:安装失败`))}finally{h.value.delete(n)}}async function L(e){try{return await B.confirm(`${e.name} ${q(`@MKT:已安装,要重新安装吗?`)}`,q(`@MKT:重新安装`),{confirmButtonText:q(`@MKT:重装`),cancelButtonText:q(`@MKT:取消`),type:`warning`}),!0}catch{return!1}}async function R(e){try{await B.confirm(`${q(`@MKT:确定卸载`)} ${e.name}?`,q(`@MKT:卸载`),{confirmButtonText:q(`@MKT:卸载`),cancelButtonText:q(`@MKT:取消`),type:`warning`})}catch{return}let t=`${e.target}:${e.id}`;g.value.add(t);try{let t=new URLSearchParams({target:e.target,cwd:_.value}),n=await fetch(`/api/agent/marketplace/item/${a.type}/${encodeURIComponent(e.id)}?${t}`,{method:`DELETE`}),r=await n.json().catch(()=>null);if(!n.ok||!r?.success){M.error(r?.error||q(`@MKT:卸载失败`));return}M.success(q(`@MKT:已卸载`)),await y()}catch{M.error(q(`@MKT:卸载失败`))}finally{g.value.delete(t)}}let H={props:a,configStore:s,groups:c,installed:l,loading:u,searchInput:d,query:f,selectedSources:p,installTarget:m,installing:h,removing:g,cwd:_,get searchTimer(){return v},set searchTimer(e){v=e},loadCatalog:y,targetLabel:b,metricText:x,formatCount:C,cardKey:w,isBusy:T,installedByTarget:E,configDialog:D,needsConfig:O,openConfigDialog:j,confirmConfig:P,onInstall:F,doInstall:I,confirmReinstall:L,onRemove:R,get $t(){return q},get Search(){return S},get Refresh(){return n},get Delete(){return U},get Link(){return o},get Check(){return e},get Star(){return z},get Download(){return k},get Warning(){return V},CommonDialog:X};return Object.defineProperty(H,"__isScriptSetup",{enumerable:!1,value:!0}),H}});b(),I(),h();var Q={class:`marketplace-panel`},le={class:`mp-toolbar`},ue={class:`mp-search`},de=[`placeholder`],fe={class:`mp-toolbar-sub`},pe={class:`mp-target-hint`},me={class:`mp-source-filter`},he=[`onClick`],ge={class:`mp-body`},_e={class:`mp-group-header`},ve={class:`mp-group-title`},ye={key:0,class:`mp-group-count`},be={key:1,class:`mp-group-error`},xe=[`href`,`title`],Se={key:0,class:`mp-grid`},Ce={class:`mp-card-head`},we=[`title`],Te={key:0,class:`mp-card-metric`},Ee=[`title`],De={class:`mp-card-meta`},Oe=[`title`],ke=[`title`],Ae={key:2,class:`mp-tag remote`},je={class:`mp-card-foot`},Me=[`href`],Ne={key:1,class:`mp-installed-chip`},Pe=[`disabled`,`onClick`],Fe={key:3,class:`mp-not-installable`},Ie={key:1,class:`mp-empty`},Le={key:0,class:`mp-group installed`},Re={class:`mp-group-header`},ze={class:`mp-group-title`},Be={class:`mp-group-count`},Ve={key:0,class:`mp-installed-block`},He={class:`mp-installed-target`},Ue={class:`mp-installed-list`},We={class:`mp-installed-name`},Ge={key:0,class:`mp-meta-pkg`},Ke={key:1,class:`mp-tag warn`},qe=[`disabled`,`onClick`],Je={key:1,class:`mp-empty all`},Ye={key:0,class:`mkt-form`},Xe={class:`mkt-form-name`},Ze=[`onUpdate:modelValue`,`placeholder`],Qe={key:0,class:`mkt-field`},$e={class:`mkt-hint`};function et(e,n,r,i,o,c){let u=f,d=t,h=P,g=l,_=T;return C(),a(`div`,Q,[s(` ── 工具栏 ───────────────────────────────── `),G(`div`,le,[G(`div`,ue,[m(u,{class:`mp-search-icon`},{default:L(()=>[m(i.Search)]),_:1}),H(G(`input`,{"onUpdate:modelValue":n[0]||=e=>i.searchInput=e,class:`mp-search-input`,type:`text`,placeholder:r.type===`skill`?i.$t(`@MKT:搜索 Skill...`):i.$t(`@MKT:搜索 MCP 服务...`)},null,8,de),[[j,i.searchInput]])]),m(h,{modelValue:i.installTarget,"onUpdate:modelValue":n[1]||=e=>i.installTarget=e,size:`small`,class:`mp-target`},{default:L(()=>[m(d,{value:`project`},{default:L(()=>[F(y(i.$t(`@MKT:当前项目`)),1)]),_:1}),m(d,{value:`global`},{default:L(()=>[F(y(i.$t(`@MKT:g ai 智能体`)),1)]),_:1})]),_:1},8,[`modelValue`]),m(g,{content:i.$t(`@MKT:刷新`),placement:`top`,"show-after":300},{default:L(()=>[G(`button`,{class:p([`mp-refresh`,{spinning:i.loading}]),onClick:i.loadCatalog},[m(u,null,{default:L(()=>[m(i.Refresh)]),_:1})],2)]),_:1},8,[`content`])]),G(`div`,fe,[G(`span`,pe,[F(y(i.$t(`@MKT:安装到`))+` `,1),G(`b`,null,y(i.targetLabel),1)]),G(`div`,me,[(C(!0),a(K,null,w(i.groups,e=>(C(),a(`button`,{key:e.id,class:p([`mp-chip`,{active:i.selectedSources.includes(e.id)}]),onClick:()=>{let t=i.selectedSources.indexOf(e.id);t>=0?i.selectedSources.splice(t,1):i.selectedSources.push(e.id)}},y(e.label),11,he))),128)),i.selectedSources.length?(C(),a(`button`,{key:0,class:`mp-chip clear`,onClick:n[2]||=e=>i.selectedSources=[]},y(i.$t(`@MKT:全部来源`)),1)):s(`v-if`,!0)])]),s(` ── 内容 ─────────────────────────────────── `),H((C(),a(`div`,ge,[(C(!0),a(K,null,w(i.groups,e=>(C(),a(`section`,{key:e.id,class:`mp-group`},[G(`header`,_e,[G(`h3`,ve,y(e.label),1),e.status===`ok`?(C(),a(`span`,ye,y(e.items.length),1)):(C(),a(`span`,be,[m(u,null,{default:L(()=>[m(i.Warning)]),_:1}),F(` `+y(e.error||i.$t(`@MKT:来源不可用`)),1)])),e.homepage?(C(),a(`a`,{key:2,class:`mp-group-link`,href:e.homepage,target:`_blank`,rel:`noopener noreferrer`,title:e.homepage},[m(u,null,{default:L(()=>[m(i.Link)]),_:1})],8,xe)):s(`v-if`,!0)]),e.status===`ok`&&e.items.length?(C(),a(`div`,Se,[(C(!0),a(K,null,w(e.items,e=>(C(),a(`article`,{key:i.cardKey(e),class:`mp-card`},[G(`div`,Ce,[G(`span`,{class:`mp-card-name`,title:e.name},y(e.name),9,we),i.metricText(e)?(C(),a(`span`,Te,[m(u,null,{default:L(()=>[e.stars?(C(),x(i.Star,{key:0})):(C(),x(i.Download,{key:1}))]),_:2},1024),F(` `+y(i.metricText(e)),1)])):s(`v-if`,!0)]),G(`p`,{class:`mp-card-desc`,title:e.description},y(e.description||i.$t(`@MKT:暂无描述`)),9,Ee),G(`div`,De,[e.package?(C(),a(`code`,{key:0,class:`mp-meta-pkg`,title:e.package},y(e.package),9,Oe)):e.repository?(C(),a(`span`,{key:1,class:`mp-meta-repo`,title:e.repository+(e.subpath?` · `+e.subpath:``)},[F(y(e.repository),1),e.subpath?(C(),a(K,{key:0},[F(` · `+y(e.subpath),1)],64)):s(`v-if`,!0)],8,ke)):s(`v-if`,!0),e.transport===`remote`?(C(),a(`span`,Ae,y(i.$t(`@MKT:远程服务`)),1)):s(`v-if`,!0),(C(!0),a(K,null,w((e.tags||[]).slice(0,2),e=>(C(),a(`span`,{key:e,class:`mp-tag`},y(e),1))),128))]),G(`div`,je,[e.upstream?(C(),a(`a`,{key:0,class:`mp-card-link`,href:e.upstream,target:`_blank`,rel:`noopener noreferrer`},y(i.$t(`@MKT:查看来源`)),9,Me)):s(`v-if`,!0),n[6]||=G(`span`,{class:`mp-foot-spacer`},null,-1),e.installed?(C(),a(`span`,Ne,[m(u,null,{default:L(()=>[m(i.Check)]),_:1}),F(y(i.$t(`@MKT:已安装`)),1)])):e.installable===!1?(C(),a(`span`,Fe,y(i.$t(`@MKT:暂不支持一键安装`)),1)):(C(),a(`button`,{key:2,class:`mp-install-btn`,disabled:i.isBusy(e),onClick:t=>i.onInstall(e)},y(i.isBusy(e)?i.$t(`@MKT:安装中...`):i.$t(`@MKT:安装`)),9,Pe))])]))),128))])):e.status===`ok`?(C(),a(`div`,Ie,y(i.$t(`@MKT:该来源暂无结果`)),1)):s(`v-if`,!0)]))),128)),s(` ── 已安装 ─────────────────────────────── `),i.installed.length?(C(),a(`section`,Le,[G(`header`,Re,[G(`h3`,ze,y(i.$t(`@MKT:已安装`)),1),G(`span`,Be,y(i.installed.length),1)]),(C(),a(K,null,w([`project`,`global`],e=>G(`div`,{key:e},[i.installedByTarget[e]?.length?(C(),a(`div`,Ve,[G(`div`,He,y(e===`project`?i.$t(`@MKT:当前项目`):i.$t(`@MKT:g ai 智能体`)),1),G(`div`,Ue,[(C(!0),a(K,null,w(i.installedByTarget[e],t=>(C(),a(`div`,{key:e+t.id,class:`mp-installed-row`},[G(`span`,We,y(t.name),1),t.package?(C(),a(`code`,Ge,y(t.package),1)):s(`v-if`,!0),t.requiredEnv?.length?(C(),a(`span`,Ke,y(i.$t(`@MKT:待配置`))+`: `+y(t.requiredEnv.join(`, `)),1)):s(`v-if`,!0),n[7]||=G(`span`,{class:`mp-foot-spacer`},null,-1),G(`button`,{class:`mp-remove-btn`,disabled:i.removing.has(e+t.id),onClick:e=>i.onRemove(t)},[m(u,null,{default:L(()=>[m(i.Delete)]),_:1}),F(` `+y(i.removing.has(e+t.id)?i.$t(`@MKT:卸载中...`):i.$t(`@MKT:卸载`)),1)],8,qe)]))),128))])])):s(`v-if`,!0)])),64))])):s(`v-if`,!0),!i.loading&&!i.groups.length?(C(),a(`div`,Je,y(i.$t(`@MKT:加载失败`)),1)):s(`v-if`,!0)])),[[_,i.loading]]),s(` ── MCP 安装前配置 ───────────────────────── `),m(i.CommonDialog,{modelValue:i.configDialog.visible,"onUpdate:modelValue":n[5]||=e=>i.configDialog.visible=e,title:i.$t(`@MKT:配置 MCP`),width:`460px`,type:`flex`,"close-on-click-modal":!1,"append-to-body":``},{footer:L(()=>[G(`button`,{class:`mkt-cancel`,onClick:n[4]||=e=>i.configDialog.visible=!1},y(i.$t(`@MKT:取消`)),1),G(`button`,{class:`mkt-confirm`,onClick:i.confirmConfig},y(i.$t(`@MKT:安装`)),1)]),default:L(()=>[i.configDialog.item?(C(),a(`div`,Ye,[G(`p`,Xe,y(i.configDialog.item.name),1),(C(!0),a(K,null,w(Object.keys(i.configDialog.env),e=>(C(),a(`div`,{key:e,class:`mkt-field`},[G(`label`,null,y(e),1),H(G(`input`,{"onUpdate:modelValue":t=>i.configDialog.env[e]=t,type:`text`,autocomplete:`off`,placeholder:i.$t(`@MKT:环境变量值`),spellcheck:`false`},null,8,Ze),[[j,i.configDialog.env[e]]])]))),128)),i.configDialog.item.args?.length?(C(),a(`div`,Qe,[G(`label`,null,y(i.$t(`@MKT:启动参数`)),1),H(G(`input`,{"onUpdate:modelValue":n[3]||=e=>i.configDialog.args=e,type:`text`,autocomplete:`off`,spellcheck:`false`},null,512),[[j,i.configDialog.args]]),G(`p`,$e,y(i.$t(`@MKT:参数提示`)),1)])):s(`v-if`,!0)])):s(`v-if`,!0)]),_:1},8,[`modelValue`,`title`])])}var tt=J(Z,[[`render`,et],[`__scopeId`,`data-v-e9f9e851`],[`__file`,`D:/workspace/github_workspace/zen-gitsync/src/ui/client/src/components/MarketplacePanel.vue`]]);b(),D();var $=_({__name:`AgentView`,setup(e,{expose:t}){t();let n=Y(),a=W(null),{narrow:o}=ce(a),s=W(`chat`),c=W(`chat`),l=r(()=>c.value===`mcp`?`mcp`:`skill`),d=r(()=>[{id:`chat`,label:q(`@AGENT:对话`),icon:v},{id:`skill`,label:q(`@AGENT:Skill 广场`),icon:i},{id:`mcp`,label:q(`@AGENT:MCP 广场`),icon:E}]),{sessions:p,sessionsLoading:m,currentSessionId:h,messages:_,isStreaming:y,sessionLoading:b,loadSessions:x,loadSession:S,deleteSession:C,renameSession:w,newSession:T,sendMessage:D,pendingQuestion:O,answeringQuestion:k,answerQuestion:A,isSessionGenerating:j,stop:M}=ae(),P=r(()=>{let e=n.theme;return e===`dark`||e===`auto`&&window.matchMedia(`(prefers-color-scheme: dark)`).matches?`dark`:`light`}),F=r(()=>re(p.value,j)),I=ie(),L=r(()=>F.value.find(e=>e.id===h.value)?.title||q(`@AGENT:对话`)),R=r(()=>[{id:`p1`,label:q(`@AGENT:查看项目结构`),prompt:q(`@AGENT:prompt_p1`)},{id:`p2`,label:q(`@AGENT:分析代码质量`),prompt:q(`@AGENT:prompt_p2`)},{id:`p3`,label:q(`@AGENT:帮我写测试`),prompt:q(`@AGENT:prompt_p3`)},{id:`p4`,label:q(`@AGENT:Git 状态检查`),prompt:q(`@AGENT:prompt_p4`)},{id:`p5`,label:q(`@AGENT:帮我启动项目`),prompt:q(`@AGENT:prompt_p5`)}]);async function z(e){await D(e.text,e.files),await u(),U()}async function B(e){await D(e.prompt),await u(),U()}let V=oe(),H=W(null);function U(e=!0){H.value?.scrollToBottom(e)}N(()=>_.value.length,()=>{u(()=>U(!1))});function G(e){S(e),s.value=`chat`}function K(){T(),s.value=`chat`}let J=W(280),X=W(!1);function Z(e){X.value=!0;let t=e.clientX,n=J.value,r=e=>{let r=e.clientX-t,i=Math.max(200,Math.min(500,n+r));J.value=i},i=()=>{X.value=!1,document.removeEventListener(`mousemove`,r),document.removeEventListener(`mouseup`,i)};document.addEventListener(`mousemove`,r),document.addEventListener(`mouseup`,i)}N(o,e=>{e||(s.value=`chat`)}),N(()=>[n.currentDirectory,y.value],async([e,t],n)=>{let r=!n||e!==n[0],i=!!n&&n[1]===!0&&!t;(r||i)&&await x(),h.value&&!y.value&&!p.value.some(e=>e.sessionId===h.value)&&T()},{immediate:!0});let Q={configStore:n,rootRef:a,narrow:o,chatPage:s,activeTab:c,marketplaceType:l,tabs:d,sessions:p,sessionsLoading:m,currentSessionId:h,messages:_,isStreaming:y,sessionLoading:b,loadSessions:x,loadSession:S,deleteSession:C,renameSession:w,newSession:T,sendMessage:D,pendingQuestion:O,answeringQuestion:k,answerQuestion:A,isSessionGenerating:j,stop:M,chatTheme:P,conversationItems:F,conversationLabels:I,currentSessionTitle:L,presetQuestions:R,onSend:z,onSelectPreset:B,questionLabels:V,chatContainerRef:H,scrollToBottom:U,selectSession:G,handleNewSession:K,sidebarWidth:J,isResizing:X,startResize:Z,get $t(){return q},get ElIcon(){return f},get Loading(){return g},get ChatContainer(){return te},get ConversationList(){return ee},get AGENT_UPLOAD_ACCEPT(){return ne},get AGENT_ASSISTANT_NAME(){return se},MarketplacePanel:tt};return Object.defineProperty(Q,"__isScriptSetup",{enumerable:!1,value:!0}),Q}});b(),h();var nt={ref:`rootRef`,class:`agent-view`},rt={class:`agent-chat-area`},it={class:`agent-tabs`,role:`tablist`},at=[`aria-selected`,`onClick`],ot={class:`agent-tab-body`},st={key:0,class:`agent-chat-pane`},ct={key:0,class:`agent-list-page`},lt={key:0,class:`agent-page-bar`},ut=[`title`,`aria-label`],dt={class:`agent-page-title`},ft={class:`agent-chat-host`},pt={key:0,class:`chat-loading`};function mt(e,t,n,r,i,o){return C(),a(`div`,nt,[s(` ═══ 宽屏:左侧会话列表(只在「对话」Tab 显示)═══
2
- 窄屏时这一整块不渲染,会话列表改成 body 里的一个整页(见 .agent-list-page) `),r.activeTab===`chat`&&!r.narrow?(C(),a(K,{key:0},[G(`aside`,{class:`agent-sidebar`,style:d({width:r.sidebarWidth+`px`})},[s(` 会话列表:UI 与交互都在组件库的 ConversationList 里 `),m(r.ConversationList,{class:`agent-conversations`,items:r.conversationItems,"active-id":r.currentSessionId,loading:r.sessionsLoading,labels:r.conversationLabels,onSelect:r.selectSession,onNew:r.handleNewSession,onRename:r.renameSession,onDelete:r.deleteSession},null,8,[`items`,`active-id`,`loading`,`labels`,`onRename`,`onDelete`])],4),s(` 拖拽分隔条 `),G(`div`,{class:p([`sidebar-resizer`,{active:r.isResizing}]),onMousedown:r.startResize},null,34)],64)):s(`v-if`,!0),s(` ═══ 右侧:Tab 栏 + 内容区 ═══ `),G(`main`,rt,[G(`nav`,it,[(C(!0),a(K,null,w(r.tabs,e=>(C(),a(`button`,{key:e.id,type:`button`,class:p([`agent-tab`,{active:r.activeTab===e.id}]),role:`tab`,"aria-selected":r.activeTab===e.id,onClick:t=>r.activeTab=e.id},[m(r.ElIcon,null,{default:L(()=>[(C(),x(O(e.icon)))]),_:2},1024),G(`span`,null,y(e.label),1)],10,at))),128))]),G(`div`,ot,[s(` ── 对话 ── `),r.activeTab===`chat`?(C(),a(`div`,st,[s(` 窄屏 · 会话列表页:列表独占整页 `),r.narrow&&r.chatPage===`list`?(C(),a(`div`,ct,[m(r.ConversationList,{class:`agent-conversations`,items:r.conversationItems,"active-id":r.currentSessionId,loading:r.sessionsLoading,labels:r.conversationLabels,onSelect:r.selectSession,onNew:r.handleNewSession,onRename:r.renameSession,onDelete:r.deleteSession},null,8,[`items`,`active-id`,`loading`,`labels`,`onRename`,`onDelete`])])):(C(),a(K,{key:1},[s(` 对话页(窄屏时顶上多一条返回条;宽屏左侧就摆着列表,不需要) `),r.narrow?(C(),a(`div`,lt,[G(`button`,{type:`button`,class:`agent-page-back`,title:r.$t(`@AGENT:返回会话列表`),"aria-label":r.$t(`@AGENT:返回会话列表`),onClick:t[0]||=e=>r.chatPage=`list`},[...t[1]||=[G(`svg`,{viewBox:`0 0 24 24`,width:`14`,height:`14`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`},[G(`line`,{x1:`19`,y1:`12`,x2:`5`,y2:`12`}),G(`polyline`,{points:`12 19 5 12 12 5`})],-1)]],8,ut),G(`span`,dt,y(r.currentSessionTitle),1)])):s(`v-if`,!0),s(`
3
- 对话宿主:单独开一层裁剪边界。
4
- 欢迎页在矮/窄窗口里会比可用高度还高,而它是垂直居中的 —— 溢出的部分
5
- 会**向上**跑出 .acu-chat,盖到刚加的返回条上(把返回条的点击也一起吃掉,
6
- e2e 实测就是这个症状)。宿主的 overflow:hidden 把它裁在自己这一格里。
7
- `),G(`div`,ft,[s(` 加载中 `),r.sessionLoading?(C(),a(`div`,pt,[m(r.ElIcon,{class:`is-loading`,size:32},{default:L(()=>[m(r.Loading)]),_:1}),G(`span`,null,y(r.$t(`@AGENT:加载会话中...`)),1)])):(C(),a(K,{key:1},[s(` ChatContainer `),m(r.ChatContainer,{ref:`chatContainerRef`,messages:r.messages,"preset-questions":r.presetQuestions,"welcome-title":r.$t(`@AGENT:智能体助手`),"welcome-description":r.$t(`@AGENT:我可以帮你阅读代码、执行命令、修改文件。选择下方话题或直接输入你的问题。`),"assistant-name":r.AGENT_ASSISTANT_NAME,theme:r.chatTheme,disabled:r.isStreaming,generating:r.isStreaming,"upload-config":{accept:r.AGENT_UPLOAD_ACCEPT},placeholder:r.isStreaming?r.$t(`@AGENT:正在生成中...`):r.$t(`@AGENT:输入消息,Enter 发送`),question:r.pendingQuestion,"question-submitting":r.answeringQuestion,"question-labels":r.questionLabels,onSend:r.onSend,onSelect:r.onSelectPreset,onStop:r.stop,onAnswer:r.answerQuestion},null,8,[`messages`,`preset-questions`,`welcome-title`,`welcome-description`,`assistant-name`,`theme`,`disabled`,`generating`,`upload-config`,`placeholder`,`question`,`question-submitting`,`question-labels`,`onStop`,`onAnswer`])],2112))])],64))])):(C(),a(K,{key:1},[s(` ── Skill 广场 / MCP 广场 ── `),m(r.MarketplacePanel,{type:r.marketplaceType},null,8,[`type`])],2112))])])],512)}var ht=J($,[[`render`,mt],[`__scopeId`,`data-v-bd681ddd`],[`__file`,`D:/workspace/github_workspace/zen-gitsync/src/ui/client/src/views/AgentView.vue`]]);export{ht as default};
@@ -1,16 +0,0 @@
1
- import"./rolldown-runtime-C0FnF6B9.js";import{An as e,Cn as t,Dn as n,En as r,Gn as i,H as a,Hn as o,Jr as s,Kr as c,Mn as l,Nr as u,Pn as d,Qr as f,Rn as p,Tn as m,Yn as h,Zn as g,_n as _,dr as v,gn as y,hn as b,i as x,ir as S,jn as C,ln as w,or as T,qn as ee,sr as E,vn as D,vr as O,wn as k,xn as te,yn as A,yr as ne}from"./element-plus-D7LDHcAn.js";import{n as re,s as ie}from"./vendor-CLmPUj3K.js";import{n as j,t as M}from"./_plugin-vue_export-helper-BLGowG5t.js";import{t as N}from"./SvgIcon-Bkc_oGUI.js";import{t as ae}from"./configStore-BUXv5i5j.js";import{n as P,r as oe,t as se}from"./useThemeObserver-QpveGpnn.js";import{a as ce,i as F,n as le,r as ue,s as de,t as fe}from"./previewSandbox-DEQpyVNu.js";import{a as pe,c as me,l as he,n as ge,o as _e,r as ve,s as ye}from"./monaco-BScz9v63.js";import{r as be,t as I}from"./flow-mindmap-zXXF3qDh.js";import{r as xe}from"./index-Di5cimoI.js";import{a as L,i as R,n as Se,o as Ce,r as we,t as Te}from"./agentConversations-BQCIv4u1.js";function Ee(e){return{ts:`typescript`,tsx:`typescript`,js:`javascript`,mjs:`javascript`,cjs:`javascript`,jsx:`javascript`,vue:`html`,html:`html`,htm:`html`,css:`css`,scss:`scss`,less:`less`,json:`json`,jsonc:`json`,md:`markdown`,markdown:`markdown`,yaml:`yaml`,yml:`yaml`,toml:`ini`,xml:`xml`,svg:`xml`,sh:`shell`,bash:`shell`,zsh:`shell`,fish:`shell`,ps1:`powershell`,py:`python`,go:`go`,rs:`rust`,java:`java`,kt:`kotlin`,rb:`ruby`,php:`php`,c:`c`,cpp:`cpp`,h:`cpp`,cs:`csharp`,sql:`sql`,graphql:`graphql`,gql:`graphql`,txt:`plaintext`,log:`plaintext`,ini:`ini`,env:`ini`,gitignore:`ini`,dockerfile:`dockerfile`}[e.toLowerCase()]??`plaintext`}p();var z=d({__name:`MindmapPreview`,props:{content:{type:String,required:!0}},setup(e,{expose:n}){n();let r=e,i={props:r,data:t(()=>I(r.content||``,`未命名文档`)),get MindMap(){return be}};return Object.defineProperty(i,"__isScriptSetup",{enumerable:!1,value:!0}),i}});p();var B={class:`mindmap-preview`},De={class:`mindmap-preview-canvas`};function Oe(e,t,r,i,a,o){return h(),n(`div`,B,[t[0]||=k(`div`,{class:`mindmap-preview-header`},[k(`span`,{class:`mindmap-preview-title`},`整篇导图`),k(`span`,{class:`mindmap-preview-hint`},`基于整篇 Markdown 自动生成 · 阅读模式`)],-1),k(`div`,De,[l(i.MindMap,{data:i.data,"preview-mode":``},null,8,[`data`])])])}var ke=M(z,[[`render`,Oe],[`__scopeId`,`data-v-3969a8bf`],[`__file`,`D:/workspace/github_workspace/zen-gitsync/src/ui/client/src/components/MindmapPreview.vue`]]);p(),v();var V=d({__name:`EditorAgentPanel`,props:{activeFilePath:{type:[String,null],required:!1},activeFileName:{type:String,required:!1},active:{type:Boolean,required:!1}},emits:[`close`],setup(e,{expose:n,emit:r}){n();let a=e,s=r,{theme:c}=se(),l=t(()=>c.value===`dark`?`dark`:`light`),{sessions:u,sessionsLoading:d,currentSessionId:f,messages:p,isStreaming:m,pendingQuestion:h,answeringQuestion:g,isSessionGenerating:_,loadSessions:v,loadSession:y,deleteSession:b,renameSession:x,newSession:C,sendMessage:w,answerQuestion:T,stop:E}=Ce(),D=t(()=>R(u.value,_)),k=Se(),te=we(),A=O(null),ne=O(null),M=O(`chat`),N=O(null),ae=O(!1),P=null,oe=t(()=>!!a.activeFileName&&!ae.value);function ce(e){return Array.from(e.children).find(e=>e.classList?.contains(`acu-input-attachments`))??null}function F(){let e=A.value?.$el?.querySelector?.(`.acu-input-wrap`);if(!e)return;let t=e.querySelector(`.agent-context-slot`);if(!oe.value){if(!t)return;N.value=null,o(()=>t.remove());return}let n=N.value&&e.contains(N.value)?N.value:t;n||(n=document.createElement(`div`),n.className=`agent-context-slot`);let r=ce(e),i=r??e;n.parentElement!==i&&i.insertBefore(n,r?r.firstChild:e.firstChild),N.value=n}function le(e=!0){A.value?.scrollToBottom(e)}async function ue(e){let t=ae.value?void 0:a.activeFilePath||void 0;await w(e.text,e.files,{openFilePath:t}),await o(),le()}function de(e){y(e),M.value=`chat`}function fe(){C(),M.value=`chat`}S(()=>p.value.length,()=>{o(()=>le(!1))});function pe(){let e=ne.value;!e||typeof MutationObserver>`u`||(P?.disconnect(),P=new MutationObserver(()=>F()),P.observe(e,{childList:!0,subtree:!0}))}S(()=>a.active,e=>{e&&(M.value=`chat`,v().catch(()=>{}),o(()=>{F(),le(!1)}))}),S(M,e=>{e===`chat`&&o(F)}),S(()=>a.activeFilePath,()=>{ae.value=!1}),S(oe,e=>{e&&o(F)}),ee(()=>{v().catch(()=>{}),o(()=>{F(),pe()})}),i(()=>{P?.disconnect(),P=null,N.value=null});let me={props:a,emit:s,theme:c,chatTheme:l,sessions:u,sessionsLoading:d,currentSessionId:f,messages:p,isStreaming:m,pendingQuestion:h,answeringQuestion:g,isSessionGenerating:_,loadSessions:v,loadSession:y,deleteSession:b,renameSession:x,newSession:C,sendMessage:w,answerQuestion:T,stop:E,conversationItems:D,conversationLabels:k,questionLabels:te,chatRef:A,chatHostRef:ne,page:M,contextSlot:N,contextDismissed:ae,get slotObserver(){return P},set slotObserver(e){P=e},showContextCard:oe,findAttachmentsHost:ce,syncContextSlot:F,scrollToBottom:le,onSend:ue,onSelectSession:de,onNewSession:fe,watchChatDom:pe,get $t(){return j},get ChatContainer(){return ie},get ConversationList(){return re},get AGENT_UPLOAD_ACCEPT(){return L},get AGENT_ASSISTANT_NAME(){return Te}};return Object.defineProperty(me,"__isScriptSetup",{enumerable:!1,value:!0}),me}});p(),u(),w();var H={class:`editor-agent-panel`},Ae={class:`agent-panel-header`},je=[`title`,`aria-label`],Me={class:`agent-panel-title`},U={key:1,class:`agent-panel-title`},Ne=[`title`,`aria-label`],W=[`title`],Pe={class:`agent-panel-convs`},Fe={ref:`chatHostRef`,class:`agent-panel-chat`},Ie=[`title`],Le={class:`agent-context-att-name`},Re=[`title`,`aria-label`];function ze(t,i,a,o,s,c){return h(),n(A,null,[r(`
2
- 文件空间右侧的 g ai 对话面板。
3
- - 恒为两个整页:「会话列表页 ↔ 对话页」,头部按钮来回翻(与「智能体」视图窄屏同一套心智模型)
4
- - 复用的都是组件库的独立导出:ConversationList(列表)+ ChatContainer(对话),不需要改库
5
- - "当前打开的文档"通过请求级注入告知模型(sendMessage 的 openFilePath 选项);
6
- 它修饰的是**这一条消息的上下文**,所以做成附件卡片、搬进输入框内部(见 contextSlot)
7
- - 自己持有一个 useAgentChat 实例:runs/refs 与「对话」Tab 隔离,互不打断
8
- `),k(`div`,H,[k(`div`,Ae,[r(` 会话列表页:整条 header 让给「返回对话 + 标题」 `),o.page===`list`?(h(),n(A,{key:0},[k(`button`,{class:`agent-panel-icon-btn agent-panel-back-btn`,title:o.$t(`@EDITOR:返回对话`),"aria-label":o.$t(`@EDITOR:返回对话`),onClick:i[0]||=e=>o.page=`chat`},[...i[4]||=[k(`svg`,{viewBox:`0 0 24 24`,width:`13`,height:`13`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`},[k(`line`,{x1:`19`,y1:`12`,x2:`5`,y2:`12`}),k(`polyline`,{points:`12 19 5 12 12 5`})],-1)]],8,je),k(`span`,Me,f(o.$t(`@EDITOR:会话列表`)),1)],64)):(h(),n(`span`,U,f(o.$t(`@EDITOR:g ai 对话`)),1)),i[7]||=k(`div`,{class:`agent-panel-spacer`},null,-1),o.page===`chat`?(h(),n(`button`,{key:2,class:`agent-panel-icon-btn agent-panel-list-btn`,title:o.$t(`@EDITOR:会话列表`),"aria-label":o.$t(`@EDITOR:会话列表`),onClick:i[1]||=e=>o.page=`list`},[...i[5]||=[e(`<svg viewBox="0 0 24 24" width="13" height="13" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" data-v-7cc12c51><line x1="8" y1="6" x2="21" y2="6" data-v-7cc12c51></line><line x1="8" y1="12" x2="21" y2="12" data-v-7cc12c51></line><line x1="8" y1="18" x2="21" y2="18" data-v-7cc12c51></line><line x1="3" y1="6" x2="3.01" y2="6" data-v-7cc12c51></line><line x1="3" y1="12" x2="3.01" y2="12" data-v-7cc12c51></line><line x1="3" y1="18" x2="3.01" y2="18" data-v-7cc12c51></line></svg>`,1)]],8,Ne)):r(`v-if`,!0),k(`button`,{class:`agent-panel-icon-btn`,title:o.$t(`@EDITOR:关闭对话`),onClick:i[2]||=e=>o.emit(`close`)},[...i[6]||=[k(`svg`,{viewBox:`0 0 24 24`,width:`13`,height:`13`,fill:`none`,stroke:`currentColor`,"stroke-width":`2.5`,"stroke-linecap":`round`},[k(`line`,{x1:`18`,y1:`6`,x2:`6`,y2:`18`}),k(`line`,{x1:`6`,y1:`6`,x2:`18`,y2:`18`})],-1)]],8,W)]),r(` 会话列表页:整页独占(行高正常 + 带搜索框,整页的列表没理由再挤) `),E(k(`div`,Pe,[l(o.ConversationList,{"show-search":!0,items:o.conversationItems,"active-id":o.currentSessionId,loading:o.sessionsLoading,labels:o.conversationLabels,onSelect:o.onSelectSession,onNew:o.onNewSession,onRename:o.renameSession,onDelete:o.deleteSession},null,8,[`items`,`active-id`,`loading`,`labels`,`onRename`,`onDelete`])],512),[[y,o.page===`list`]]),r(` 对话页 `),E(k(`div`,Fe,[l(o.ChatContainer,{ref:`chatRef`,messages:o.messages,"assistant-name":o.AGENT_ASSISTANT_NAME,theme:o.chatTheme,disabled:o.isStreaming,generating:o.isStreaming,placeholder:o.isStreaming?o.$t(`@AGENT:正在生成中...`):o.$t(`@AGENT:输入消息,Enter 发送`),"upload-config":{accept:o.AGENT_UPLOAD_ACCEPT},question:o.pendingQuestion,"question-submitting":o.answeringQuestion,"question-labels":o.questionLabels,onSend:o.onSend,onStop:o.stop,onAnswer:o.answerQuestion},null,8,[`messages`,`assistant-name`,`theme`,`disabled`,`generating`,`placeholder`,`upload-config`,`question`,`question-submitting`,`question-labels`,`onStop`,`onAnswer`]),r(`
9
- 当前文档:**和添加的附件同处一行、同一副样子**。
10
- 组件库的 ChatContainer / ChatInput 没有任何插槽(dist 里 \`slots\` 出现 0 次),
11
- 没法声明式地往输入框里放东西,所以:
12
- · 往 \`.acu-input-wrap\` 插一个锚点,再把卡片 Teleport 进去(节点仍是 Vue 渲染的);
13
- · **有附件行(.acu-input-attachments)时锚点住进它内部** —— 卡片因此成为那一行的
14
- flex item,与附件并排、共用同一套 gap/wrap。只插在输入框最前面是不行的:
15
- Vue 更新输入框时会用自己的锚点 \`insertBefore\`,把外来节点挤到后面去。
16
- `),o.contextSlot?(h(),m(te,{key:0,to:o.contextSlot},[o.showContextCard?(h(),n(`div`,{key:0,class:`agent-context-att`,title:a.activeFilePath||``},[i[9]||=k(`svg`,{class:`agent-context-att-icon`,viewBox:`0 0 24 24`,width:`14`,height:`14`,fill:`none`,stroke:`currentColor`,"stroke-width":`1.7`,"stroke-linecap":`round`,"stroke-linejoin":`round`,"aria-hidden":`true`},[k(`path`,{d:`M14 3H7a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V8z`}),k(`polyline`,{points:`14 3 14 8 19 8`})],-1),k(`span`,Le,f(a.activeFileName),1),k(`button`,{type:`button`,class:`agent-context-att-remove`,title:o.$t(`@EDITOR:不引用当前文档`),"aria-label":o.$t(`@EDITOR:不引用当前文档`),onClick:i[3]||=e=>o.contextDismissed=!0},[...i[8]||=[k(`svg`,{viewBox:`0 0 24 24`,width:`10`,height:`10`,fill:`none`,stroke:`currentColor`,"stroke-width":`3`,"stroke-linecap":`round`,"aria-hidden":`true`},[k(`line`,{x1:`18`,y1:`6`,x2:`6`,y2:`18`}),k(`line`,{x1:`6`,y1:`6`,x2:`18`,y2:`18`})],-1)]],8,Re)],8,Ie)):r(`v-if`,!0)],8,[`to`])):r(`v-if`,!0)],512),[[y,o.page===`chat`]])])],2112)}var Be=M(V,[[`render`,ze],[`__scopeId`,`data-v-7cc12c51`],[`__file`,`D:/workspace/github_workspace/zen-gitsync/src/ui/client/src/components/EditorAgentPanel.vue`]]);p(),v();var Ve=15e3,G=d({__name:`EditorView`,props:{pendingFilePath:{type:[String,null],required:!1}},setup(e,{expose:n}){n(),self.MonacoEnvironment={getWorker(e,t){return t===`json`?new me:t===`css`||t===`scss`||t===`less`?new ye:t===`html`||t===`handlebars`||t===`razor`?new _e:t===`typescript`||t===`javascript`?new pe:new he}};let r=e,s=ae(),c=xe(),l=O([]),u=O(!1),d=O(``),f=O(``),p=null;function m(){d.value=``,f.value=``,p&&=(clearTimeout(p),null)}S(d,e=>{p&&clearTimeout(p),p=setTimeout(()=>{f.value=e,p=null},180)}),i(()=>{p&&clearTimeout(p),_()});let h=null;function g(){_(),h=setInterval(()=>{document.hidden||s.currentDirectory&&(d.value.trim()||w())},Ve)}function _(){h&&=(clearInterval(h),null)}S(()=>s.currentDirectory,()=>{g()});async function v(e,t=0){let n=await(await fetch(`/api/browse_directory?path=${encodeURIComponent(e)}`)).json();return n.success?n.items.map(e=>({...e,depth:t,expanded:!1,loading:!1,children:(e.type,void 0)})):[]}async function y(){let e=s.currentDirectory;if(e){u.value=!0;try{l.value=await v(e,0)}finally{u.value=!1}}}function b(e,t=new Set){for(let n of e)n.type===`directory`&&n.expanded&&(t.add(n.path),n.children&&b(n.children,t));return t}async function C(e,t){for(let n of e)n.type===`directory`&&t.has(n.path)&&(n.children||=await v(n.path,n.depth+1),n.expanded=!0,await C(n.children,t))}async function w(){let e=s.currentDirectory;if(!e)return;let t=b(l.value);u.value=!0;try{l.value=await v(e,0),t.size>0&&await C(l.value,t)}finally{u.value=!1}}async function T(e){if(e.type===`directory`){if(e.expanded)e.expanded=!1;else{if(!e.children){e.loading=!0;try{e.children=await v(e.path,e.depth+1)}finally{e.loading=!1}}e.expanded=!0}}}function E(e){let t=[];for(let n of e)t.push(n),n.type===`directory`&&n.expanded&&n.children&&t.push(...E(n.children));return t}let D=t(()=>f.value.trim().toLowerCase());function k(e,t){if(!t)return e;let n=[];for(let r of e){let e=r.children?k(r.children,t):[],i=r.name.toLowerCase().includes(t);r.type===`directory`?(i||e.length>0)&&(r.expanded=!0,r.children!==void 0&&(r.children=e),n.push(r)):i&&n.push(r)}return n}let te=t(()=>k(l.value,D.value)),A=t(()=>D.value.length>0&&te.value.length===0);function re(e){let t=f.value.trim();if(!t)return[{text:e,hit:!1}];let n=e.toLowerCase(),r=t.toLowerCase(),i=[],a=0,o=n.indexOf(r,a);for(;o!==-1;)o>a&&i.push({text:e.slice(a,o),hit:!1}),i.push({text:e.slice(o,o+r.length),hit:!0}),a=o+r.length,o=n.indexOf(r,a);return a<e.length&&i.push({text:e.slice(a),hit:!1}),i}let ie=O(null);function M(){let e=ie.value;e&&(e.focus(),e.select())}function be(){d.value?(m(),ie.value?.focus()):(ie.value?.blur(),z.value?.focus())}let I=O([]),L=O(null),R=O(null);async function Se(e){if(R.value=e,e.type!==`file`){T(e);return}let t=I.value.find(t=>t.path===e.path);if(console.log(`[debug-open-in-editor] EditorView openFile existing tab check:`,{path:e.path,found:!!t,tabsCount:I.value.length}),t){L.value=e.path,o(()=>V());return}let n=e.name.split(`.`).pop()||``;if(dt.has(n.toLowerCase())){let t={path:e.path,name:e.name,content:``,originalContent:``,isDirty:!1,language:`plaintext`};I.value.push(t),L.value=e.path,Y.value=!0;return}if(de(e.name)){let t={path:e.path,name:e.name,content:``,originalContent:``,isDirty:!1,language:`office`};I.value.push(t),L.value=e.path,X.value=!1,Y.value=!0;return}try{let t=await fetch(`/api/editor/file?path=${encodeURIComponent(e.path)}`),r=await t.json();if(console.log(`[debug-open-in-editor] EditorView fetch /api/editor/file response:`,{path:e.path,status:t.status,data:r}),!r.success){x.error(`${j(`@EDITOR:打开文件失败: `)}${r.error}`);return}let i=Ee(n),a={path:e.path,name:e.name,content:r.content,originalContent:r.content,isDirty:!1,language:i};console.log(`[debug-open-in-editor] EditorView pushing tab:`,{path:a.path,name:a.name,contentLen:a.content.length,lang:a.language}),I.value.push(a),L.value=e.path,console.log(`[debug-open-in-editor] EditorView tabs after push:`,I.value.length,`activeTabPath=`,L.value)}catch(e){console.log(`[debug-open-in-editor] EditorView fetch threw:`,e),x.error(`${j(`@EDITOR:打开文件失败: `)}${e.message}`)}}S(()=>r.pendingFilePath,async e=>{if(console.log(`[debug-open-in-editor] EditorView watcher fired, filePath=`,e),!e)return;await o();let t=e.split(/[\\/]/).pop()||e;console.log(`[debug-open-in-editor] EditorView calling openFile, name=`,t,`path=`,e),await Se({name:t,path:e,type:`file`,depth:0}),console.log(`[debug-open-in-editor] EditorView openFile returned`)},{immediate:!0});function Ce(e,t){t.stopPropagation();let n=I.value.findIndex(t=>t.path===e);n!==-1&&(!I.value[n].isDirty||confirm(j(`@EDITOR:文件未保存,确认关闭?`)))&&(I.value.splice(n,1),L.value===e&&(L.value=I.value[Math.min(n,I.value.length-1)]?.path??null))}let we=()=>I.value.find(e=>e.path===L.value)??null,Te=O(null),z=ne(null),B=new Map;function De(e){let t=B.get(e.path);return(!t||t.isDisposed())&&(t=ve.createModel(e.content,e.language,ge.file(e.path)),B.set(e.path,t)),t}function Oe(){if(!Te.value)return;let e=document.documentElement.getAttribute(`data-theme`)===`dark`;z.value=ve.create(Te.value,{theme:e?`vs-dark`:`vs`,fontSize:13,lineHeight:20,fontFamily:`'JetBrains Mono', 'Fira Code', 'Cascadia Code', Consolas, monospace`,minimap:{enabled:!0},scrollBeyondLastLine:!1,renderWhitespace:`selection`,automaticLayout:!0,tabSize:2,wordWrap:`off`,smoothScrolling:!0,cursorBlinking:`smooth`,padding:{top:8,bottom:8},editContext:!1}),z.value.onDidChangeModelContent(()=>{let e=we();if(!e)return;let t=z.value.getValue();e.content=t,e.isDirty=t!==e.originalContent}),z.value.onDidBlurEditorText(()=>{s.ui.editorAutoSave&&we()?.isDirty&&je(!1),requestAnimationFrame(()=>{if(!U.value||U.value.offsetParent===null)return;let e=document.activeElement;e&&(e.tagName===`INPUT`||e.tagName===`TEXTAREA`||e.isContentEditable||e.classList?.contains(`native-edit-context`)||e.classList?.contains(`monaco-editor`))||V()})})}S(L,e=>{if(!z.value||!e)return;let t=I.value.find(t=>t.path===e);if(!t)return;let n=De(t);z.value.setModel(n),o(()=>V())});function V(){if(!z.value)return;z.value.focus();let e=document.querySelector(`.monaco-editor .native-edit-context`);e&&document.activeElement!==e&&requestAnimationFrame(()=>e.focus?.())}S(()=>I.value.filter(e=>e.isDirty).length,e=>{c.setDirtyCount(e)},{immediate:!0}),i(()=>c.setDirtyCount(0)),se(()=>{let e=document.documentElement.getAttribute(`data-theme`)===`dark`;ve.setTheme(e?`vs-dark`:`vs`)});let H=null;function Ae(){if(H||!U.value)return;let e=[U.value],t=U.value.parentElement;for(;t;){if(t.classList.contains(`view-pane`)||t.classList.contains(`editor-pane`)){e.push(t);break}t=t.parentElement}H=new MutationObserver(()=>{U.value&&U.value.offsetParent!==null&&L.value&&z.value&&requestAnimationFrame(()=>{let e=document.activeElement;e&&(e.tagName===`INPUT`||e.tagName===`TEXTAREA`||e.isContentEditable||e.classList?.contains(`native-edit-context`)||e.classList?.contains(`monaco-editor`))||V()})});let n=H;e.forEach(e=>n.observe(e,{attributes:!0,attributeFilter:[`style`,`class`,`hidden`]}))}ee(async()=>{Oe(),await y(),Ae(),g(),L.value&&o(()=>V())}),i(()=>{H?.disconnect(),H=null,z.value?.dispose(),B.forEach(e=>e.dispose()),B.clear()});async function je(e=!1){let t=we();if(t)try{let n=await(await fetch(`/api/editor/file`,{method:`PUT`,headers:{"Content-Type":`application/json`},body:JSON.stringify({path:t.path,content:t.content})})).json();if(!n.success){x.error(`${j(`@EDITOR:保存失败: `)}${n.error}`);return}t.originalContent=t.content,t.isDirty=!1,e||x.success(j(`@EDITOR:已保存`))}catch(e){x.error(`${j(`@EDITOR:保存失败: `)}${e.message}`)}}function Me(e){let t=e.ctrlKey||e.metaKey;if(t&&e.key.toLowerCase()===`f`){e.preventDefault(),M();return}t&&e.key===`s`&&(e.preventDefault(),je())}ee(()=>window.addEventListener(`keydown`,Me)),i(()=>window.removeEventListener(`keydown`,Me));let U=O(null),Ne=O(220),W=!1,Pe=0,Fe=0;function Ie(e){W=!0,Pe=e.clientX,Fe=Ne.value,document.addEventListener(`mousemove`,Le),document.addEventListener(`mouseup`,Re),e.preventDefault()}function Le(e){if(!W)return;let t=e.clientX-Pe;Ne.value=Math.max(140,Math.min(400,Fe+t))}function Re(){W=!1,document.removeEventListener(`mousemove`,Le),document.removeEventListener(`mouseup`,Re)}function ze(e){return e.type===`directory`?oe(e.name):P(e.name)}let G=O(null),K=O(null),He=O(null),Ue=O(null);function We(){let e=R.value;return e?e.type===`directory`?{parentPath:e.path,afterNode:e,depth:e.depth+1}:{parentPath:e.path.includes(`/`)||e.path.includes(`\\`)?e.path.replace(/[\\/][^\\/]+$/,``):s.currentDirectory??``,afterNode:e,depth:e.depth}:{parentPath:s.currentDirectory??``,afterNode:null,depth:0}}async function Ge(){let e=We();R.value?.type===`directory`&&!R.value.expanded&&await T(R.value),G.value={...e,kind:`file`,value:``},await o(),He.value?.focus()}async function Ke(){let e=We();R.value?.type===`directory`&&!R.value.expanded&&await T(R.value),G.value={...e,kind:`directory`,value:``},await o(),He.value?.focus()}function qe(){G.value=null}async function Je(){let e=G.value;if(!e||!e.value.trim()){G.value=null;return}let t=e.value.trim(),n=e.parentPath.replace(/[/\\]$/,``)+`/`+t;if(e.kind===`file`){let e=await(await fetch(`/api/editor/file`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({path:n})})).json();if(!e.success){x.error(e.error);return}x.success(j(`@EDITOR:创建成功`))}else{let e=await(await fetch(`/api/editor/directory`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({path:n})})).json();if(!e.success){x.error(e.error);return}x.success(j(`@EDITOR:创建成功`))}G.value=null,await w()}function Ye(e){e.key===`Enter`&&(e.preventDefault(),Je()),e.key===`Escape`&&(e.preventDefault(),qe())}let q=O(null),Xe=O(null);function Ze(e,t){e.preventDefault(),q.value={x:e.clientX,y:e.clientY,node:t}}function J(){q.value=null}async function Qe(){let e=q.value?.node;J(),e&&(R.value=e),e?.type===`directory`&&!e.expanded&&await T(e);let t=We();G.value={...t,kind:`file`,value:``},await o(),He.value?.focus()}async function $e(){let e=q.value?.node;J(),e&&(R.value=e),e?.type===`directory`&&!e.expanded&&await T(e);let t=We();G.value={...t,kind:`directory`,value:``},await o(),He.value?.focus()}async function et(){let e=q.value?.node;J(),e&&(K.value={node:e,value:e.name},await o(),Ue.value?.focus(),Ue.value?.select())}async function tt(){let e=K.value;if(!e||!e.value.trim()||e.value.trim()===e.node.name){K.value=null;return}let t=e.value.trim(),n=e.node.path.replace(/[\\/][^\\/]+$/,``).replace(/[/\\]$/,``)+`/`+t,r=await(await fetch(`/api/editor/rename`,{method:`PUT`,headers:{"Content-Type":`application/json`},body:JSON.stringify({oldPath:e.node.path,newPath:n})})).json();if(!r.success){x.error(r.error);return}let i=I.value.find(t=>t.path===e.node.path);i&&(i.path=n,i.name=t,L.value===e.node.path&&(L.value=n)),K.value=null,await w()}function nt(e){e.key===`Enter`&&(e.preventDefault(),tt()),e.key===`Escape`&&(e.preventDefault(),K.value=null)}async function rt(){let e=q.value?.node;if(J(),!e)return;let t=e.type===`directory`?j(`@EDITOR:文件夹`):j(`@EDITOR:文件`);if(!confirm(`${j(`@EDITOR:确认删除`)} ${t} "${e.name}"?`))return;let n=await(await fetch(`/api/editor/entry?path=${encodeURIComponent(e.path)}`,{method:`DELETE`})).json();if(!n.success){x.error(n.error);return}let r=I.value.findIndex(t=>t.path===e.path);r!==-1&&(I.value.splice(r,1),L.value===e.path&&(L.value=I.value[Math.max(0,r-1)]?.path??null)),x.success(j(`@EDITOR:已删除`)),await w()}async function it(){let e=q.value?.node;if(J(),e)try{let t=await(await fetch(`/api/editor/reveal`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({path:e.path})})).json();t.success||x.error(t.error)}catch(e){x.error(e?.message||String(e))}}function at(e){let t=s.currentDirectory;if(!t)return e;let n=e=>e.replace(/\\/g,`/`).replace(/\/+$/,``),r=n(t),i=n(e);return i===r?`.`:i.startsWith(r+`/`)?i.slice(r.length+1):i}async function ot(e){try{if(navigator.clipboard&&window.isSecureContext)return await navigator.clipboard.writeText(e),!0}catch{}try{let t=document.createElement(`textarea`);t.value=e,t.style.position=`fixed`,t.style.left=`-9999px`,document.body.appendChild(t),t.select();let n=document.execCommand(`copy`);return document.body.removeChild(t),n}catch{return!1}}async function st(){let e=q.value?.node;J(),e&&(await ot(e.path)?x.success(j(`@EDITOR:已复制到剪贴板`)):x.error(j(`@EDITOR:复制失败`)))}async function ct(){let e=q.value?.node;J(),e&&(await ot(at(e.path))?x.success(j(`@EDITOR:已复制到剪贴板`)):x.error(j(`@EDITOR:复制失败`)))}async function lt(){let e=q.value?.node;if(J(),e)try{let t=await(await fetch(`/api/editor/open-in-vscode`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({path:e.path})})).json();t.success||x.error(t.error||j(`@EDITOR:VSCode 未安装`))}catch(e){x.error(e?.message||String(e))}}ee(()=>document.addEventListener(`click`,J)),i(()=>document.removeEventListener(`click`,J));let ut=new Set([`md`,`html`,`htm`,`svg`]),dt=new Set([`png`,`jpg`,`jpeg`,`gif`,`webp`,`ico`,`bmp`]),Y=O(!1),X=O(!1),Z=O(!1),ft=O(!1),pt=O(0),Q=t(()=>I.value.find(e=>e.path===L.value)??null),mt=t(()=>Q.value?.language===`plaintext`&&Q.value?.content===``),ht=t(()=>Q.value?.language===`office`),$=t(()=>(Q.value?.name??``).split(`.`).pop()?.toLowerCase()??``),gt=t(()=>ut.has($.value)||dt.has($.value)||de($.value)),_t=t(()=>((Q.value?.content??``).match(/^#{1,6}\s+/gm)||[]).length),vt=t(()=>$.value===`md`&&_t.value>0);S(L,()=>{Y.value&&!gt.value&&(Y.value=!1),X.value&&!vt.value&&(X.value=!1)});function yt(){gt.value&&(Y.value||(X.value=!1,Z.value=!1),Y.value=!Y.value)}function bt(){vt.value&&(X.value||(Y.value=!1,Z.value=!1),X.value=!X.value)}function xt(){Z.value||(Y.value=!1,X.value=!1),Z.value=!Z.value,ft.value=!0}let St=t(()=>{let e=Q.value;if(!e)return``;let t=$.value,n=document.documentElement.getAttribute(`data-theme`)===`light`?`#ffffff`:`#0d1117`;return t===`html`||t===`htm`?le(e.content):t===`svg`?`<!DOCTYPE html><html><head><meta charset="utf-8"><style>html,body{margin:0;padding:0;background:${n};display:flex;align-items:center;justify-content:center;min-height:100vh;}svg{max-width:100%;max-height:90vh;}</style></head><body>${e.content}</body></html>`:``}),Ct=!1,wt=0,Tt=0;function Et(e){Ct=!0,wt=e.clientX,Tt=pt.value,document.addEventListener(`mousemove`,Dt),document.addEventListener(`mouseup`,Ot),e.preventDefault()}function Dt(e){if(!Ct)return;let t=e.clientX-wt;pt.value=Math.max(200,Math.min(900,Tt+t))}function Ot(){Ct=!1,document.removeEventListener(`mousemove`,Dt),document.removeEventListener(`mouseup`,Ot)}let kt={props:r,configStore:s,editorTabsStore:c,treeNodes:l,treeLoading:u,searchQuery:d,debouncedSearchQuery:f,get searchDebounceTimer(){return p},set searchDebounceTimer(e){p=e},clearSearch:m,TREE_POLL_MS:Ve,get treePollTimer(){return h},set treePollTimer(e){h=e},startTreePolling:g,stopTreePolling:_,loadDir:v,initTree:y,collectExpandedPaths:b,restoreExpanded:C,refreshTree:w,toggleDir:T,flattenTree:E,searchQueryLower:D,filterTree:k,visibleTree:te,noSearchResults:A,highlightName:re,searchInputRef:ie,focusSearchInput:M,onSearchEscape:be,tabs:I,activeTabPath:L,selectedNode:R,openFile:Se,closeTab:Ce,activeTab:we,editorContainerRef:Te,editorInstance:z,modelCache:B,getOrCreateModel:De,mountEditor:Oe,focusEditor:V,get viewVisibilityObserver(){return H},set viewVisibilityObserver(e){H=e},setupViewVisibilityObserver:Ae,saveCurrentFile:je,handleKeydown:Me,containerRef:U,sidebarWidth:Ne,get isResizing(){return W},set isResizing(e){W=e},get resizeStartX(){return Pe},set resizeStartX(e){Pe=e},get resizeStartW(){return Fe},set resizeStartW(e){Fe=e},startSidebarResize:Ie,onSidebarResize:Le,stopSidebarResize:Re,getNodeSpriteId:ze,inlineInput:G,renameInput:K,inlineInputRef:He,renameInputRef:Ue,getTargetDir:We,startNewFile:Ge,startNewFolder:Ke,cancelInlineInput:qe,confirmInlineInput:Je,handleInlineKeydown:Ye,ctxMenu:q,ctxMenuRef:Xe,openContextMenu:Ze,closeContextMenu:J,ctxNewFile:Qe,ctxNewFolder:$e,ctxRename:et,confirmRename:tt,handleRenameKeydown:nt,ctxDelete:rt,ctxRevealInExplorer:it,toWorkspaceRelative:at,copyToClipboard:ot,ctxCopyAbsolutePath:st,ctxCopyRelativePath:ct,ctxOpenInVscode:lt,PREVIEW_TEXT_EXTS:ut,IMAGE_EXTS:dt,showPreview:Y,showMindmap:X,showAgentChat:Z,agentOpened:ft,previewWidth:pt,activeTabRef:Q,activeTabIsImage:mt,activeTabIsOffice:ht,activeExt:$,isPreviewable:gt,mindmapTitleCount:_t,isMindmapable:vt,togglePreview:yt,toggleMindmap:bt,toggleAgentChat:xt,previewSrcdoc:St,get isPreviewResizing(){return Ct},set isPreviewResizing(e){Ct=e},get previewResizeStartX(){return wt},set previewResizeStartX(e){wt=e},get previewResizeStartW(){return Tt},set previewResizeStartW(e){Tt=e},startPreviewResize:Et,onPreviewResize:Dt,stopPreviewResize:Ot,get $t(){return j},get ElTooltip(){return a},ImagePreview:ce,OfficePreview:ue,MarkdownPreview:F,MindmapPreview:ke,EditorAgentPanel:Be,SvgIcon:N,get PREVIEW_IFRAME_SANDBOX(){return fe}};return Object.defineProperty(kt,"__isScriptSetup",{enumerable:!1,value:!0}),kt}});p(),u(),w();var K={class:`editor-view`,ref:`containerRef`},He={class:`sidebar-header`},Ue={class:`sidebar-title`},We={class:`sidebar-actions`},Ge={class:`sidebar-search`},Ke=[`placeholder`,`title`],qe=[`title`,`aria-label`],Je={key:0,class:`sidebar-tree`},Ye={key:1,class:`tree-arrow-spacer`},q={class:`tree-icon mit-icon`,"aria-hidden":`true`},Xe=[`xlink:href`],Ze=[`onClick`,`onContextmenu`],J={key:1,class:`tree-arrow-spacer`},Qe={key:2,class:`tree-icon mit-icon`,"aria-hidden":`true`},$e=[`xlink:href`],et={key:3,class:`tree-icon mit-icon`,"aria-hidden":`true`},tt=[`xlink:href`],nt=[`title`],rt={key:0,class:`tree-name-hit`},it={key:4,class:`tree-loading`},at={key:0,viewBox:`0 0 24 24`,width:`13`,height:`13`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`,style:{"flex-shrink":`0`,color:`var(--color-warning)`}},ot={key:1,viewBox:`0 0 24 24`,width:`13`,height:`13`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`,style:{"flex-shrink":`0`,color:`var(--text-tertiary)`}},st=[`placeholder`],ct={key:0,class:`tree-node tree-inline-input-row`,style:{paddingLeft:`12px`}},lt={key:0,viewBox:`0 0 24 24`,width:`13`,height:`13`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`,style:{"flex-shrink":`0`,color:`var(--color-warning)`}},ut={key:1,viewBox:`0 0 24 24`,width:`13`,height:`13`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`,style:{"flex-shrink":`0`,color:`var(--text-tertiary)`}},dt=[`placeholder`],Y={key:1,class:`tree-empty`},X={key:1,class:`sidebar-loading`},Z={class:`editor-main`},ft={key:0,class:`editor-tabs`},pt=[`onClick`,`title`],Q={class:`tab-name`},mt={key:0,class:`tab-dirty-dot`},ht=[`onClick`],$=[`title`],gt=[`disabled`,`title`],_t=[`title`],vt={key:1,class:`editor-empty`},yt={viewBox:`0 0 24 24`,width:`48`,height:`48`,fill:`none`,stroke:`currentColor`,"stroke-width":`1.2`,"stroke-linecap":`round`,"stroke-linejoin":`round`,style:{opacity:`.3`}},bt={class:`editor-empty-hint`},xt={class:`editor-body`},St={key:0,class:`image-tab-placeholder`},Ct={viewBox:`0 0 24 24`,width:`56`,height:`56`,fill:`none`,stroke:`currentColor`,"stroke-width":`1.2`,"stroke-linecap":`round`,"stroke-linejoin":`round`,style:{opacity:`.35`}},wt={class:`image-tab-placeholder-title`},Tt={class:`image-tab-placeholder-hint`},Et={class:`preview-header`},Dt={class:`preview-title`},Ot={class:`preview-ext-badge`},kt=[`title`],At={class:`preview-body`},jt=[`sandbox`,`srcdoc`];function Mt(t,i,a,o,u,d){return h(),n(A,null,[k(`div`,K,[r(` 左侧文件树 `),k(`div`,{class:`editor-sidebar`,style:s({width:o.sidebarWidth+`px`})},[k(`div`,He,[k(`span`,Ue,f(o.$t(`@EDITOR:资源管理器`)),1),k(`div`,We,[l(o.ElTooltip,{content:o.$t(`@EDITOR:新建文件`),placement:`bottom`,"show-after":300},{default:T(()=>[k(`button`,{class:`sidebar-action-btn`,onClick:o.startNewFile},[r(` new-file icon `),i[10]||=k(`svg`,{viewBox:`0 0 24 24`,width:`14`,height:`14`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`},[k(`path`,{d:`M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z`}),k(`polyline`,{points:`14 2 14 8 20 8`}),k(`line`,{x1:`12`,y1:`13`,x2:`12`,y2:`19`}),k(`line`,{x1:`9`,y1:`16`,x2:`15`,y2:`16`})],-1)])]),_:1},8,[`content`]),l(o.ElTooltip,{content:o.$t(`@EDITOR:新建文件夹`),placement:`bottom`,"show-after":300},{default:T(()=>[k(`button`,{class:`sidebar-action-btn`,onClick:o.startNewFolder},[r(` new-folder icon `),i[11]||=k(`svg`,{viewBox:`0 0 24 24`,width:`14`,height:`14`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`},[k(`path`,{d:`M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z`}),k(`line`,{x1:`12`,y1:`11`,x2:`12`,y2:`17`}),k(`line`,{x1:`9`,y1:`14`,x2:`15`,y2:`14`})],-1)])]),_:1},8,[`content`]),l(o.ElTooltip,{content:o.$t(`@EDITOR:刷新`),placement:`bottom`,"show-after":300},{default:T(()=>[k(`button`,{class:`sidebar-action-btn`,onClick:o.initTree},[...i[12]||=[k(`svg`,{viewBox:`0 0 24 24`,width:`14`,height:`14`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`},[k(`polyline`,{points:`1 4 1 10 7 10`}),k(`polyline`,{points:`23 20 23 14 17 14`}),k(`path`,{d:`M20.49 9A9 9 0 0 0 5.64 5.64L1 10m22 4l-4.64 4.36A9 9 0 0 1 3.51 15`})],-1)]])]),_:1},8,[`content`])])]),k(`div`,Ge,[i[14]||=k(`svg`,{class:`sidebar-search-icon`,viewBox:`0 0 24 24`,width:`13`,height:`13`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`,"aria-hidden":`true`},[k(`circle`,{cx:`11`,cy:`11`,r:`7`}),k(`line`,{x1:`21`,y1:`21`,x2:`16.65`,y2:`16.65`})],-1),E(k(`input`,{ref:`searchInputRef`,"onUpdate:modelValue":i[0]||=e=>o.searchQuery=e,type:`text`,class:`sidebar-search-input`,placeholder:o.$t(`@EDITOR:搜索文件...`),title:o.$t(`@EDITOR:搜索文件...`),spellcheck:`false`,autocomplete:`off`,onKeydown:_(o.onSearchEscape,[`escape`])},null,40,Ke),[[b,o.searchQuery]]),o.searchQuery?(h(),n(`button`,{key:0,class:`sidebar-search-clear`,title:o.$t(`@EDITOR:清除搜索`),"aria-label":o.$t(`@EDITOR:清除搜索`),onClick:o.clearSearch},[...i[13]||=[k(`svg`,{viewBox:`0 0 24 24`,width:`12`,height:`12`,fill:`none`,stroke:`currentColor`,"stroke-width":`2.5`,"stroke-linecap":`round`,"stroke-linejoin":`round`,"aria-hidden":`true`},[k(`line`,{x1:`18`,y1:`6`,x2:`6`,y2:`18`}),k(`line`,{x1:`6`,y1:`6`,x2:`18`,y2:`18`})],-1)]],8,qe)):r(`v-if`,!0)]),o.treeLoading?(h(),n(`div`,X,[...i[23]||=[k(`span`,{class:`spin-icon`},null,-1)]])):(h(),n(`div`,Je,[(h(!0),n(A,null,g(o.flattenTree(o.visibleTree),e=>(h(),n(A,{key:e.path},[r(` 重命名时用输入框替换节点 `),o.renameInput&&o.renameInput.node.path===e.path?(h(),n(`div`,{key:0,class:`tree-node tree-inline-input-row`,style:s({paddingLeft:12+e.depth*14+`px`})},[e.type===`directory`?(h(),n(`span`,{key:0,class:c([`tree-arrow`,{expanded:e.expanded}])},[...i[15]||=[k(`svg`,{viewBox:`0 0 24 24`,width:`10`,height:`10`,fill:`none`,stroke:`currentColor`,"stroke-width":`2.5`,"stroke-linecap":`round`,"stroke-linejoin":`round`},[k(`polyline`,{points:`9 18 15 12 9 6`})],-1)]],2)):(h(),n(`span`,Ye)),(h(),n(`svg`,q,[k(`use`,{"xlink:href":`#${o.getNodeSpriteId(e)}`},null,8,Xe)])),E(k(`input`,{ref_for:!0,ref:`renameInputRef`,"onUpdate:modelValue":i[1]||=e=>o.renameInput.value=e,onKeydown:o.handleRenameKeydown,onBlur:o.confirmRename,onClick:i[2]||=D(()=>{},[`stop`])},null,544),[[b,o.renameInput.value]])],4)):(h(),n(A,{key:1},[r(` 普通节点 `),k(`div`,{class:c([`tree-node`,{"tree-node--dir":e.type===`directory`,"tree-node--file":e.type===`file`,"tree-node--active":o.activeTabPath===e.path,"tree-node--selected":o.selectedNode?.path===e.path&&o.activeTabPath!==e.path}]),style:s({paddingLeft:12+e.depth*14+`px`}),onClick:t=>o.openFile(e),onContextmenu:t=>o.openContextMenu(t,e)},[r(` 展开箭头 `),e.type===`directory`?(h(),n(`span`,{key:0,class:c([`tree-arrow`,{expanded:e.expanded}])},[...i[16]||=[k(`svg`,{viewBox:`0 0 24 24`,width:`10`,height:`10`,fill:`none`,stroke:`currentColor`,"stroke-width":`2.5`,"stroke-linecap":`round`,"stroke-linejoin":`round`},[k(`polyline`,{points:`9 18 15 12 9 6`})],-1)]],2)):(h(),n(`span`,J)),r(` 图标 `),e.type===`directory`?(h(),n(`svg`,Qe,[k(`use`,{"xlink:href":`#${o.getNodeSpriteId(e)}`},null,8,$e)])):(h(),n(`svg`,et,[k(`use`,{"xlink:href":`#${o.getNodeSpriteId(e)}`},null,8,tt)])),r(` 名称(命中关键字高亮) `),k(`span`,{class:`tree-name`,title:e.path},[(h(!0),n(A,null,g(o.highlightName(e.name),(e,t)=>(h(),n(A,{key:t},[e.hit?(h(),n(`span`,rt,f(e.text),1)):(h(),n(A,{key:1},[C(f(e.text),1)],64))],64))),128))],8,nt),e.loading?(h(),n(`span`,it)):r(`v-if`,!0)],46,Ze)],2112)),r(` 内联新建输入框:紧跟在 afterNode 之后 `),o.inlineInput&&o.inlineInput.afterNode?.path===e.path?(h(),n(`div`,{key:2,class:`tree-node tree-inline-input-row`,style:s({paddingLeft:12+o.inlineInput.depth*14+`px`})},[i[19]||=k(`span`,{class:`tree-arrow-spacer`},null,-1),o.inlineInput.kind===`directory`?(h(),n(`svg`,at,[...i[17]||=[k(`path`,{d:`M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z`},null,-1)]])):(h(),n(`svg`,ot,[...i[18]||=[k(`path`,{d:`M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z`},null,-1),k(`polyline`,{points:`14 2 14 8 20 8`},null,-1)]])),E(k(`input`,{ref_for:!0,ref:`inlineInputRef`,class:`tree-inline-input`,"onUpdate:modelValue":i[3]||=e=>o.inlineInput.value=e,placeholder:o.inlineInput.kind===`file`?o.$t(`@EDITOR:输入文件名`):o.$t(`@EDITOR:输入文件夹名`),onKeydown:o.handleInlineKeydown,onBlur:o.cancelInlineInput,onClick:i[4]||=D(()=>{},[`stop`])},null,40,st),[[b,o.inlineInput.value]])],4)):r(`v-if`,!0)],64))),128)),r(` 根级输入框(无选中节点时出现在列表末尾) `),o.inlineInput&&o.inlineInput.afterNode===null?(h(),n(`div`,ct,[i[22]||=k(`span`,{class:`tree-arrow-spacer`},null,-1),o.inlineInput.kind===`directory`?(h(),n(`svg`,lt,[...i[20]||=[k(`path`,{d:`M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z`},null,-1)]])):(h(),n(`svg`,ut,[...i[21]||=[k(`path`,{d:`M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z`},null,-1),k(`polyline`,{points:`14 2 14 8 20 8`},null,-1)]])),E(k(`input`,{ref:`inlineInputRef`,class:`tree-inline-input`,"onUpdate:modelValue":i[5]||=e=>o.inlineInput.value=e,placeholder:o.inlineInput.kind===`file`?o.$t(`@EDITOR:输入文件名`):o.$t(`@EDITOR:输入文件夹名`),onKeydown:o.handleInlineKeydown,onBlur:o.cancelInlineInput,onClick:i[6]||=D(()=>{},[`stop`])},null,40,dt),[[b,o.inlineInput.value]])])):r(`v-if`,!0),!o.inlineInput&&(o.noSearchResults||o.treeNodes.length===0)?(h(),n(`div`,Y,f(o.noSearchResults?o.$t(`@EDITOR:未找到匹配文件`):o.$t(`@EDITOR:暂无文件`)),1)):r(`v-if`,!0)]))],4),r(` 拖拽分隔条 `),k(`div`,{class:`editor-resizer`,onMousedown:o.startSidebarResize},null,32),r(` 右侧编辑区 `),k(`div`,Z,[r(` 标签栏 `),o.tabs.length>0?(h(),n(`div`,ft,[(h(!0),n(A,null,g(o.tabs,e=>(h(),n(`div`,{key:e.path,class:c([`editor-tab`,{active:o.activeTabPath===e.path,dirty:e.isDirty}]),onClick:t=>o.activeTabPath=e.path,title:e.path},[k(`span`,Q,f(e.name),1),e.isDirty?(h(),n(`span`,mt)):r(`v-if`,!0),k(`button`,{class:`tab-close`,onClick:t=>o.closeTab(e.path,t)},[...i[24]||=[k(`svg`,{viewBox:`0 0 24 24`,width:`12`,height:`12`,fill:`none`,stroke:`currentColor`,"stroke-width":`2.5`,"stroke-linecap":`round`},[k(`line`,{x1:`18`,y1:`6`,x2:`6`,y2:`18`}),k(`line`,{x1:`6`,y1:`6`,x2:`18`,y2:`18`})],-1)]],8,ht)],10,pt))),128)),i[28]||=k(`div`,{class:`editor-tabs-spacer`},null,-1),r(` 预览切换按钮 `),o.isPreviewable?(h(),n(`button`,{key:0,class:c([`preview-toggle-btn`,{active:o.showPreview}]),title:o.showPreview?o.$t(`@EDITOR:关闭预览`):o.$t(`@EDITOR:打开预览`),onClick:o.togglePreview},[i[25]||=k(`svg`,{viewBox:`0 0 24 24`,width:`14`,height:`14`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`},[k(`path`,{d:`M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z`}),k(`circle`,{cx:`12`,cy:`12`,r:`3`})],-1),k(`span`,null,f(o.$t(`@EDITOR:预览`)),1)],10,$)):r(`v-if`,!0),r(` 思维导图:整篇 markdown 渲染为一张大导图 `),o.isMindmapable?(h(),n(`button`,{key:1,class:c([`preview-toggle-btn mindmap-toggle-btn`,{active:o.showMindmap,disabled:!o.isMindmapable}]),disabled:!o.isMindmapable,title:o.isMindmapable?o.showMindmap?o.$t(`@EDITOR:关闭思维导图`):o.$t(`@EDITOR:打开思维导图`):o.$t(`@EDITOR:需要至少一个 # 标题`),onClick:o.toggleMindmap},[i[26]||=e(`<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" data-v-fc2ebf13><circle cx="12" cy="12" r="2" data-v-fc2ebf13></circle><circle cx="5" cy="6" r="1.6" data-v-fc2ebf13></circle><circle cx="19" cy="6" r="1.6" data-v-fc2ebf13></circle><circle cx="5" cy="18" r="1.6" data-v-fc2ebf13></circle><circle cx="19" cy="18" r="1.6" data-v-fc2ebf13></circle><line x1="11" y1="11" x2="6.4" y2="7" data-v-fc2ebf13></line><line x1="13" y1="11" x2="17.6" y2="7" data-v-fc2ebf13></line><line x1="11" y1="13" x2="6.4" y2="17" data-v-fc2ebf13></line><line x1="13" y1="13" x2="17.6" y2="17" data-v-fc2ebf13></line></svg>`,1),k(`span`,null,f(o.$t(`@EDITOR:思维导图`)),1)],10,gt)):r(`v-if`,!0),r(` g ai 对话:文件空间右侧的智能体面板(与预览/思维导图互斥) `),k(`button`,{class:c([`preview-toggle-btn agent-toggle-btn`,{active:o.showAgentChat}]),title:o.showAgentChat?o.$t(`@EDITOR:关闭 g ai 对话`):o.$t(`@EDITOR:打开 g ai 对话`),onClick:o.toggleAgentChat},[i[27]||=k(`svg`,{viewBox:`0 0 24 24`,width:`14`,height:`14`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`},[k(`path`,{d:`M12 3l1.9 4.6L18.5 9.5l-4.6 1.9L12 16l-1.9-4.6L5.5 9.5l4.6-1.9z`}),k(`path`,{d:`M18 16.5l.9 2.1 2.1.9-2.1.9-.9 2.1-.9-2.1-2.1-.9 2.1-.9z`})],-1),k(`span`,null,f(o.$t(`@EDITOR:g ai 对话`)),1)],10,_t)])):r(`v-if`,!0),r(` 无文件打开时的提示 `),o.tabs.length===0?(h(),n(`div`,vt,[(h(),n(`svg`,yt,[...i[29]||=[k(`path`,{d:`M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z`},null,-1),k(`polyline`,{points:`14 2 14 8 20 8`},null,-1)]])),k(`p`,null,f(o.$t(`@EDITOR:从左侧选择文件打开`)),1),k(`p`,bt,f(o.$t(`@EDITOR:Ctrl+S 保存`)),1)])):r(`v-if`,!0),r(` Monaco 容器(始终挂载,tab 为空或 image tab 时隐藏) `),k(`div`,xt,[k(`div`,{class:c([`monaco-container`,{hidden:o.tabs.length===0||o.activeTabIsImage||o.activeTabIsOffice}]),ref:`editorContainerRef`},null,2),r(` 图片 tab 时的占位提示(主预览区在右侧 preview-panel) `),o.activeTabIsImage&&o.tabs.length>0&&!o.showPreview&&!o.showMindmap?(h(),n(`div`,St,[(h(),n(`svg`,Ct,[...i[30]||=[k(`rect`,{x:`3`,y:`3`,width:`18`,height:`18`,rx:`2`},null,-1),k(`circle`,{cx:`9`,cy:`9`,r:`2`},null,-1),k(`path`,{d:`m21 15-5-5L5 21`},null,-1)]])),k(`p`,wt,f(o.activeTabRef?.name),1),k(`p`,Tt,f(o.$t(`@EDITOR:这是图片文件,已在右侧预览面板中打开`)),1)])):r(`v-if`,!0),r(` 预览分隔条(在面板右侧,拉动调整面板宽度) `),(o.showPreview||o.showMindmap||o.showAgentChat)&&o.tabs.length>0?(h(),n(`div`,{key:1,class:`preview-resizer`,onMousedown:o.startPreviewResize},null,32)):r(`v-if`,!0),r(` g ai 对话面板:v-if 懒挂载 + v-show 保状态(切到预览再切回来,进行中的流还在) `),o.agentOpened?E((h(),m(o.EditorAgentPanel,{key:2,active:o.showAgentChat&&o.tabs.length>0,"active-file-path":o.activeTabPath,"active-file-name":o.activeTabRef?.name??``,style:s({flexBasis:o.previewWidth+`px`}),onClose:i[7]||=e=>o.showAgentChat=!1},null,8,[`active`,`active-file-path`,`active-file-name`,`style`])),[[y,o.showAgentChat&&o.tabs.length>0]]):r(`v-if`,!0),r(` 预览面板 `),(o.showPreview||o.showMindmap)&&o.tabs.length>0?(h(),n(`div`,{key:3,class:`preview-panel`,style:s({flexBasis:o.previewWidth+`px`})},[k(`div`,Et,[k(`span`,Dt,f(o.showMindmap?o.$t(`@EDITOR:思维导图`):o.$t(`@EDITOR:预览`)),1),k(`span`,Ot,f(o.activeExt.toUpperCase()),1),i[32]||=k(`div`,{class:`preview-header-spacer`},null,-1),k(`button`,{class:`preview-close-btn`,title:o.showMindmap?o.$t(`@EDITOR:关闭思维导图`):o.$t(`@EDITOR:关闭预览`),onClick:i[8]||=e=>o.showMindmap?o.showMindmap=!1:o.showPreview=!1},[...i[31]||=[k(`svg`,{viewBox:`0 0 24 24`,width:`13`,height:`13`,fill:`none`,stroke:`currentColor`,"stroke-width":`2.5`,"stroke-linecap":`round`},[k(`line`,{x1:`18`,y1:`6`,x2:`6`,y2:`18`}),k(`line`,{x1:`6`,y1:`6`,x2:`18`,y2:`18`})],-1)]],8,kt)]),k(`div`,At,[r(` 思维导图:整篇 markdown → 一张大导图 `),o.showMindmap&&o.activeExt===`md`&&o.activeTabRef?(h(),m(o.MindmapPreview,{key:0,content:o.activeTabRef.content,class:`preview-mindmap`},null,8,[`content`])):o.showPreview&&o.activeExt===`md`&&o.activeTabRef?(h(),n(A,{key:1},[r(` Markdown → in-app 渲染 `),l(o.MarkdownPreview,{content:o.activeTabRef.content,class:`preview-markdown`},null,8,[`content`])],2112)):o.showPreview&&[`html`,`htm`,`svg`].includes(o.activeExt)?(h(),n(A,{key:2},[r(` HTML / SVG → sandboxed iframe (JS 可执行,不透明 origin 隔离宿主) `),k(`iframe`,{class:`preview-iframe`,sandbox:o.PREVIEW_IFRAME_SANDBOX,srcdoc:o.previewSrcdoc},null,8,jt)],2112)):o.showPreview&&o.IMAGE_EXTS.has(o.activeExt)&&o.activeTabRef?(h(),n(A,{key:3},[r(` 图片预览(使用增强版 ImagePreview,支持缩放/拖拽) `),l(o.ImagePreview,{"file-path":o.activeTabRef.path,"file-name":o.activeTabRef.name},null,8,[`file-path`,`file-name`])],2112)):o.showPreview&&o.activeTabIsOffice&&o.activeTabRef?(h(),m(o.OfficePreview,{key:4,"file-path":o.activeTabRef.path},null,8,[`file-path`])):r(`v-if`,!0)])],4)):r(`v-if`,!0)])])],512),r(` 右键菜单 `),(h(),m(te,{to:`body`},[o.ctxMenu?(h(),n(`div`,{key:0,ref:`ctxMenuRef`,class:`ctx-menu`,style:s({left:o.ctxMenu.x+`px`,top:o.ctxMenu.y+`px`}),onClick:i[9]||=D(()=>{},[`stop`])},[k(`button`,{class:`ctx-menu-item`,onClick:o.ctxNewFile},[i[33]||=k(`svg`,{viewBox:`0 0 24 24`,width:`13`,height:`13`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`},[k(`path`,{d:`M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z`}),k(`polyline`,{points:`14 2 14 8 20 8`}),k(`line`,{x1:`12`,y1:`13`,x2:`12`,y2:`19`}),k(`line`,{x1:`9`,y1:`16`,x2:`15`,y2:`16`})],-1),C(` `+f(o.$t(`@EDITOR:新建文件`)),1)]),k(`button`,{class:`ctx-menu-item`,onClick:o.ctxNewFolder},[i[34]||=k(`svg`,{viewBox:`0 0 24 24`,width:`13`,height:`13`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`},[k(`path`,{d:`M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z`}),k(`line`,{x1:`12`,y1:`11`,x2:`12`,y2:`17`}),k(`line`,{x1:`9`,y1:`14`,x2:`15`,y2:`14`})],-1),C(` `+f(o.$t(`@EDITOR:新建文件夹`)),1)]),i[40]||=k(`div`,{class:`ctx-menu-sep`},null,-1),k(`button`,{class:`ctx-menu-item`,onClick:o.ctxCopyAbsolutePath},[i[35]||=k(`svg`,{viewBox:`0 0 24 24`,width:`13`,height:`13`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`},[k(`rect`,{x:`9`,y:`9`,width:`13`,height:`13`,rx:`2`,ry:`2`}),k(`path`,{d:`M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1`})],-1),C(` `+f(o.$t(`@EDITOR:复制绝对路径`)),1)]),k(`button`,{class:`ctx-menu-item`,onClick:o.ctxCopyRelativePath},[i[36]||=k(`svg`,{viewBox:`0 0 24 24`,width:`13`,height:`13`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`},[k(`path`,{d:`M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71`}),k(`path`,{d:`M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71`})],-1),C(` `+f(o.$t(`@EDITOR:复制相对路径`)),1)]),i[41]||=k(`div`,{class:`ctx-menu-sep`},null,-1),k(`button`,{class:`ctx-menu-item`,onClick:o.ctxRevealInExplorer},[i[37]||=k(`svg`,{viewBox:`0 0 24 24`,width:`13`,height:`13`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`},[k(`path`,{d:`M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z`}),k(`path`,{d:`M3 7v10a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2`})],-1),C(` `+f(o.$t(`@EDITOR:在资源管理器中打开`)),1)]),k(`button`,{class:`ctx-menu-item`,onClick:o.ctxOpenInVscode},[l(o.SvgIcon,{"icon-class":`vscode`,"class-name":`ctx-menu-icon`}),C(` `+f(o.$t(`@EDITOR:在 VSCode 中打开`)),1)]),k(`button`,{class:`ctx-menu-item`,onClick:o.ctxRename},[i[38]||=k(`svg`,{viewBox:`0 0 24 24`,width:`13`,height:`13`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`},[k(`path`,{d:`M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7`}),k(`path`,{d:`M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z`})],-1),C(` `+f(o.$t(`@EDITOR:重命名`)),1)]),k(`button`,{class:`ctx-menu-item ctx-menu-item--danger`,onClick:o.ctxDelete},[i[39]||=k(`svg`,{viewBox:`0 0 24 24`,width:`13`,height:`13`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`},[k(`polyline`,{points:`3 6 5 6 21 6`}),k(`path`,{d:`M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6`}),k(`path`,{d:`M10 11v6`}),k(`path`,{d:`M14 11v6`}),k(`path`,{d:`M9 6V4a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2`})],-1),C(` `+f(o.$t(`@EDITOR:删除`)),1)])],4)):r(`v-if`,!0)]))],64)}var Nt=M(G,[[`render`,Mt],[`__scopeId`,`data-v-fc2ebf13`],[`__file`,`D:/workspace/github_workspace/zen-gitsync/src/ui/client/src/views/EditorView.vue`]]);export{Nt as default};
@@ -1,5 +0,0 @@
1
- import"./rolldown-runtime-C0FnF6B9.js";import{Cn as e,Rn as t,dr as n,gr as r,i,r as a,vr as o}from"./element-plus-D7LDHcAn.js";import{i as s,o as c}from"./vendor-CLmPUj3K.js";import{n as l}from"./_plugin-vue_export-helper-BLGowG5t.js";import{t as u}from"./configStore-BUXv5i5j.js";t(),n();var d=[`image/*`,`.pdf`,`.txt`,`.md`,`.json`,`.csv`,`.log`,`.yml`,`.yaml`,`.xml`,`.toml`,`.ini`,`.html`,`.css`,`.js`,`.ts`,`.tsx`,`.vue`,`.py`,`.java`,`.go`,`.rs`,`.sql`,`.sh`].join(`,`),f=65536,p=`local-`;function m(e){if(!e||!Array.isArray(e.messages))return[];let t=[],n=e.messages.length;for(let r=0;r<n;r++){let i=e.messages[r];if(i.role!==`system`){if(i.role===`user`){let e=``,n;if(typeof i.content==`string`)e=i.content;else if(Array.isArray(i.content)){e=i.content.filter(e=>e?.type===`text`).map(e=>e.text||``).join(` `);let t=i.content.filter(e=>e?.type===`image_url`&&typeof e.image_url?.url==`string`).map((e,t)=>({id:`att-${r}-${t}`,name:`image`,size:0,type:_(e.image_url?.url||``)||`image/*`,preview:e.image_url?.url}));t.length>0&&(n=t)}(e||n)&&t.push({id:`msg-${r}`,role:`user`,content:e,attachments:n,status:`done`,createdAt:Date.now()})}else if(i.role===`assistant`){let i=`msg-${r}`,a=``,o=[],s=r;for(;s<n;){let t=e.messages[s];if(t.role!==`assistant`&&t.role!==`tool`)break;if(t.role===`assistant`){if(typeof t.content==`string`&&(a+=t.content),t.tool_calls&&t.tool_calls.length>0)for(let e of t.tool_calls)o.push({id:e.id||e.function?.name||c(),name:e.function?.name||``,arguments:e.function?.arguments||``,argsPreview:h(e.function?.name||``,e.function?.arguments||``),status:`done`,result:``})}else{let e=t.tool_call_id||t.name||``,n=o.find(t=>t.id===e);if(n){let e=t.content;typeof e!=`string`&&(e=`(non-text result)`),e.length>f&&(e=`…(前文已截断)\n${e.slice(-65536)}`),n.result=e}}s++}r=s-1,a.length>f&&(a=`…(前文已截断)\n${a.slice(-65536)}`);let l=!!a,u=o.length>0;(l||u)&&t.push({id:i,role:`assistant`,content:a,toolCalls:u?o:void 0,status:`done`,createdAt:Date.now()})}}}return t}function h(e,t){try{let n=JSON.parse(t);switch(e){case`run_command`:return String(n.command||``).slice(0,200);case`read_file`:case`write_file`:case`edit_file`:return String(n.path||``);case`list_files`:return String(n.path||`.`);case`search_text`:return String(n.pattern||``);default:return JSON.stringify(n).slice(0,200)}}catch{return t.slice(0,200)}}function g(e){return new Promise((t,n)=>{let r=new FileReader;r.onload=()=>t(String(r.result||``)),r.onerror=()=>n(r.error||Error(`FileReader failed`)),r.readAsDataURL(e)})}function _(e){let t=/^data:([^;,]+)/.exec(e);return t?t[1]:``}function v(){let t=u(),n=o([]),d=o(!1),h=r(new Map),_=o(null),v=o(!1),y=0,b=0,x=new Set;function S(e){return{key:e,sessionId:e.startsWith(p)?null:e,title:``,messages:[],isStreaming:!1,abortController:null,nonce:0,pendingQuestion:null,answeringQuestion:!1}}function C(e){let t=h.get(e);return t||=(h.set(e,S(e)),h.get(e)),t}let w=e(()=>_.value?h.get(_.value)??null:null),T=e(()=>w.value?.messages??[]),E=e(()=>w.value?.isStreaming??!1),D=e(()=>w.value?.pendingQuestion??null),O=e(()=>w.value?.answeringQuestion??!1);function k(e){return!!h.get(e)?.isStreaming}function A(e){let n=[...e];for(let e of h.values()){if(!e.sessionId)continue;let r=n.findIndex(t=>t.sessionId===e.sessionId);if(r!==-1){x.delete(e.sessionId),e.isStreaming&&(n[r]={...n[r],isGenerating:!0});continue}if(!e.isStreaming&&!x.has(e.sessionId))continue;let i=new Date().toISOString();n.unshift({sessionId:e.sessionId,title:e.title||l(`@AGENT:无标题`),source:`web`,cwd:t.currentDirectory||``,model:``,createdAt:i,updatedAt:i,messageCount:e.messages.filter(e=>e.role===`user`).length||1,size:0,isGenerating:e.isStreaming})}return n}async function j(){let e=++y,r=t.currentDirectory||``;if(!r){n.value=[],d.value=!1;return}d.value=!0;try{let t=`/api/agent/sessions?cwd=${encodeURIComponent(r)}`,a=await fetch(t).then(e=>e.json());if(e!==y)return;if(!a.success){i.error(a.error||l(`@AGENT:加载会话列表失败`));return}let o=Array.isArray(a.sessions)?a.sessions:[];n.value=A(o)}catch(t){if(e!==y)return;i.error(l(`@AGENT:加载会话列表失败`)+`: `+(t?.message||t))}finally{e===y&&(d.value=!1)}}function M(e,r){let i=new Date().toISOString(),a=n.value.find(t=>t.sessionId===e);if(a){a.isGenerating=!0,a.updatedAt=i;return}n.value=[{sessionId:e,title:r||l(`@AGENT:无标题`),source:`web`,cwd:t.currentDirectory||``,model:``,createdAt:i,updatedAt:i,messageCount:1,size:0,isGenerating:!0},...n.value]}function N(e){let t=n.value.find(t=>t.sessionId===e);t&&(t.isGenerating=!1)}async function P(e){if(h.get(e)?.isStreaming){_.value=e;return}v.value=!0,_.value=e;try{let t=await fetch(`/api/agent/sessions/${encodeURIComponent(e)}`).then(e=>e.json());if(!t.success){i.error(t.error||l(`@AGENT:加载会话失败`));return}let n=C(e);n.sessionId=e,n.messages=m(t.session),t.session?.title&&(n.title=t.session.title)}catch(e){i.error(l(`@AGENT:加载会话失败`)+`: `+(e?.message||e))}finally{v.value=!1}}async function F(e){try{await a.confirm(l(`@AGENT:确认删除该会话`),l(`@AGENT:删除后无法恢复`),{type:`warning`})}catch{return}let t=h.get(e);if(t?.abortController)try{t.abortController.abort()}catch{}h.delete(e);try{let t=await fetch(`/api/agent/sessions/${encodeURIComponent(e)}`,{method:`DELETE`}).then(e=>e.json());if(!t.success){i.error(t.error||l(`@AGENT:删除失败`));return}n.value=n.value.filter(t=>t.sessionId!==e),_.value===e&&(_.value=null),i.success(l(`@AGENT:已删除`))}catch(e){i.error(l(`@AGENT:删除失败`)+`: `+(e?.message||e))}}async function I(e,t){try{let r=await fetch(`/api/agent/sessions/${encodeURIComponent(e)}`,{method:`PUT`,headers:{"Content-Type":`application/json`},body:JSON.stringify({title:t})}).then(e=>e.json());if(!r.success){i.error(r.error||l(`@AGENT:重命名失败`));return}let a=n.value.find(t=>t.sessionId===e);a&&(a.title=t);let o=h.get(e);o&&(o.title=t),i.success(l(`@AGENT:已重命名`))}catch(e){i.error(l(`@AGENT:重命名失败`)+`: `+(e?.message||e))}}function L(){_.value=null}async function R(e,n=[],a={}){let o=n.filter(e=>e?.file?.type?.startsWith(`image/`)),u=n.filter(e=>!e?.file?.type?.startsWith(`image/`)),d=[],m=0;for(let e of u){let t=e.file.size||0;if(!(t>10485760)){if(d.length>=10||m+t>20971520)break;m+=t,d.push(e)}}let v=u.filter(e=>!d.includes(e));v.length>0&&i.warning(`${l(`@AGENT:以下附件超过大小或数量上限,已忽略:`)}${v.map(e=>e.file.name).join(`、`)}`);let y=C(_.value||`${p}${Date.now()}-${++b}`);if(!e.trim()&&o.length===0&&d.length===0||y.isStreaming)return;let S=(await Promise.allSettled(o.map(e=>g(e.file)))).map(e=>e.status===`fulfilled`?e.value:``).filter(e=>e.startsWith(`data:image/`)),w=(await Promise.allSettled(d.map(async e=>({name:e.file.name||`file`,dataUrl:await g(e.file)})))).map(e=>e.status===`fulfilled`?e.value:null).filter(e=>!!e&&typeof e.dataUrl==`string`&&e.dataUrl.startsWith(`data:`));_.value=y.key,y.nonce+=1;let T=y.nonce;y.abortController=new AbortController;let E=y.abortController;y.pendingQuestion=null,y.answeringQuestion=!1;let D={id:c(),role:`user`,content:e,status:`done`,createdAt:Date.now()},O=[...o,...d];O.length>0&&(D.attachments=O.map(e=>({id:e.id,name:e.file.name||`image`,size:e.file.size||0,type:e.file.type||``,preview:e.preview}))),y.messages.push(D);let k=r({id:c(),role:`assistant`,content:``,status:`pending`,createdAt:Date.now()});y.messages.push(k),y.isStreaming=!0;let A=[],P=y.sessionId,F=!1;try{let n=await fetch(`/api/agent/chat`,{method:`POST`,headers:{"Content-Type":`application/json`,Accept:`text/event-stream`},body:JSON.stringify({sessionId:y.sessionId||``,userMessage:e,cwd:t.currentDirectory||``,...S.length>0?{images:S}:{},...w.length>0?{attachments:w}:{},...a.openFilePath?{openFilePath:a.openFilePath}:{}}),signal:E.signal});if(T!==y.nonce)return;if(!n.ok||!n.body){let e=await n.text().catch(()=>``);throw Error(e||`HTTP ${n.status}`)}let i=n.body.getReader(),o=new TextDecoder(`utf-8`),u=``;for(;;){let{value:t,done:n}=await i.read();if(T!==y.nonce)return;if(n)break;u+=o.decode(t,{stream:!0});let a=u.split(`
2
- `);u=a.pop()??``;for(let t of a){let n=t.trim();if(!n.startsWith(`data:`))continue;let i=n.slice(5).trim();if(!i)continue;let a;try{a=JSON.parse(i)}catch{continue}switch(a.type){case`meta`:if(a.sessionId){let t=String(a.sessionId);if(P=t,y.sessionId!==t){let e=y.key;y.sessionId=t,y.key=t,e!==t&&(h.delete(e),h.set(t,y),_.value===e&&(_.value=t))}let n=String(a.title||``).trim()||e.trim().split(`
3
- `)[0].trim().slice(0,40)||l(`@AGENT:无标题`);y.title||=n,M(t,n)}break;case`thinking`:k.reasoning||(k.reasoning=``,k.reasoningStatus=`streaming`),k.reasoning+=String(a.delta||``),k.status=`streaming`;break;case`content`:k.status===`pending`&&(k.status=`streaming`);{let e=String(a.delta||``);k.content+=e;let t=s(k.content);t.reasoning&&(k.reasoning||(k.reasoning=``,k.reasoningStatus=`streaming`),k.reasoning=t.reasoning,k.content=t.content)}break;case`tool_call_start`:{let e=r({id:a.toolCallId||c(),name:a.name||``,argsPreview:a.argsPreview||``,arguments:a.argsPreview||``,status:`running`,result:``});A.push(e),k.toolCalls||=[],k.toolCalls.push(e),k.status===`pending`&&(k.status=`streaming`);break}case`tool_output`:{let e=A.find(e=>e.id===a.toolCallId);if(e){let t=`${e.result||``}${String(a.chunk||``)}`;e.result=t.length>f?`…(前文已截断)\n${t.slice(-65536)}`:t}break}case`tool_result`:{let e=A.find(e=>e.id===a.toolCallId);e&&(e.result=String(a.result||``),e.status=`done`,e.name===`ask_user`&&(y.pendingQuestion=null));break}case`ask_user`:y.pendingQuestion={interactionId:String(a.interactionId||``),question:String(a.question||``),options:Array.isArray(a.options)?a.options.map(e=>String(e)):[],allowFreeText:a.allowFreeText!==!1,multiple:a.multiple===!0};break;case`done`:{let e=a.content||k.content,t=s(e);t.reasoning&&!k.reasoning&&(k.reasoning=t.reasoning),k.content=t.content,k.status=`done`,k.reasoningStatus===`streaming`&&(k.reasoningStatus=`done`);break}case`error`:k.status=`error`,k.error=String(a.error||l(`@AGENT:未知错误`)),k.reasoningStatus===`streaming`&&(k.reasoningStatus=`done`)}}}if(T!==y.nonce)return;k.status===`pending`&&(k.status=`done`)}catch(e){if(T!==y.nonce)return;e?.name===`AbortError`||E.signal.aborted?(F=!0,k.content=(k.content||``)+`
4
-
5
- [`+l(`@AGENT:已停止`)+`]`,k.status=`done`,k.reasoningStatus===`streaming`&&(k.reasoningStatus=`done`)):(k.status=`error`,k.error=e?.message||String(e),i.error(k.error||l(`@AGENT:对话失败`)))}finally{T===y.nonce&&(y.isStreaming=!1,y.pendingQuestion=null,y.answeringQuestion=!1,y.abortController=null),P&&(F&&x.add(P),N(P)),j().catch(()=>{})}}async function z(e){let t=w.value,n=t?.pendingQuestion,r=t?.sessionId,a=(Array.isArray(e)?e:[e]).map(e=>String(e??``).trim()).filter(Boolean);if(!t||!n||!r||!a.length||t.answeringQuestion)return!1;t.answeringQuestion=!0;try{let e=await fetch(`/api/agent/respond`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({sessionId:r,interactionId:n.interactionId,answer:n.multiple?a:a[0]})}).then(e=>e.json());if(!e.success)throw Error(e.error||l(`@AGENT:回答提交失败`));return t.pendingQuestion=null,!0}catch(e){return i.error(e?.message||l(`@AGENT:回答提交失败`)),!1}finally{t.answeringQuestion=!1}}function B(){let e=w.value;e?.abortController&&(e.abortController.abort(),e.abortController=null)}return{sessions:n,sessionsLoading:d,currentSessionId:_,messages:T,isStreaming:E,sessionLoading:v,pendingQuestion:D,answeringQuestion:O,isSessionGenerating:k,loadSessions:j,loadSession:P,deleteSession:F,renameSession:I,newSession:L,sendMessage:R,answerQuestion:z,stop:B}}function y(e){if(!e)return``;try{let t=new Date(e);if(Number.isNaN(t.getTime()))return e;let n=new Date,r=n.getTime()-t.getTime(),i=e=>String(e).padStart(2,`0`);if(t.toDateString()===n.toDateString())return`${i(t.getHours())}:${i(t.getMinutes())}`;if(r<6048e5){let e=Math.floor(r/864e5);return e===0?l(`@AGENT:今天`):`${e}${l(`@AGENT:天前`)}`}return`${t.getFullYear()}-${i(t.getMonth()+1)}-${i(t.getDate())}`}catch{return e}}function b(e,t){return e.map(e=>({id:e.sessionId,title:e.title||l(`@AGENT:无标题`),meta:`${y(e.updatedAt)} · ${e.messageCount??0} ${l(`@AGENT:条`)}`,generatingText:e.isGenerating||t(e.sessionId)?l(`@AGENT:正在生成中...`):``,badge:e.source===`cli`?`CLI`:``,searchText:e.model}))}function x(){return{newConversation:l(`@AGENT:新建会话`),searchPlaceholder:l(`@AGENT:搜索会话...`),empty:l(`@AGENT:暂无会话`),emptyHint:l(`@AGENT:点击上方按钮开始对话`),noResult:l(`@AGENT:未找到匹配的会话`),loading:l(`@AGENT:加载会话中...`),rename:l(`@AGENT:重命名`),delete:l(`@AGENT:删除`),untitled:l(`@AGENT:无标题`)}}var S=`g ai`;function C(){return{title:l(`@AGENT:等待你的回答`),placeholder:l(`@AGENT:输入回答`),submit:l(`@AGENT:提交回答`)}}export{d as a,b as i,x as n,v as o,C as r,S as t};