zen-gitsync 2.17.13 → 2.17.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/README.md +211 -185
  2. package/package.json +2 -2
  3. package/scripts/release.js +33 -16
  4. package/src/cli/ai/tools.js +62 -13
  5. package/src/cli/ai/tools.test.js +35 -1
  6. package/src/config.js +4 -0
  7. package/src/gitCommit.js +18 -1
  8. package/src/ui/public/assets/AgentView-Bz9LFamz.js +5 -0
  9. package/src/ui/public/assets/{AppVersionBadge-QszUpjxK.js → AppVersionBadge-D5iXcAEV.js} +2 -2
  10. package/src/ui/public/assets/{BranchSelector-C_j7ayIX.js → BranchSelector-DP4u1f_B.js} +1 -1
  11. package/src/ui/public/assets/{CommitForm-CH_YTHmd.js → CommitForm-boOw8uGS.js} +1 -1
  12. package/src/ui/public/assets/{CommonDialog-78tuotW4.js → CommonDialog-B_qUsIGr.js} +1 -1
  13. package/src/ui/public/assets/{EditorView-CGKjSpRs.js → EditorView-ZULtfIzl.js} +1 -1
  14. package/src/ui/public/assets/{FileDiffViewer-kQ3WnrlJ.js → FileDiffViewer-C4xxq5S0.js} +1 -1
  15. package/src/ui/public/assets/{FlowExecutionViewer-PtAICyWn.js → FlowExecutionViewer-BmfstdaT.js} +1 -1
  16. package/src/ui/public/assets/{FlowOrchestrationWorkspace-tyQdIh0A.js → FlowOrchestrationWorkspace-28kErqrn.js} +1 -1
  17. package/src/ui/public/assets/{IconButton-CNMPSvnE.js → IconButton-DcOAqpq0.js} +1 -1
  18. package/src/ui/public/assets/{LogList-X739IWXT.js → LogList-FEP7EeJt.js} +2 -2
  19. package/src/ui/public/assets/MindmapView-8X6z245q.css +1 -0
  20. package/src/ui/public/assets/MindmapView-NDJvfSCn.js +2 -0
  21. package/src/ui/public/assets/{MonitorView-C_Jj5hEy.js → MonitorView-DU4aBCK0.js} +1 -1
  22. package/src/ui/public/assets/{ProjectStartupButton-wjBZWElK.js → ProjectStartupButton-JQk4Etsu.js} +1 -1
  23. package/src/ui/public/assets/{RemoteManagerDialog-DuS66D7T.js → RemoteManagerDialog-Di2WizMS.js} +1 -1
  24. package/src/ui/public/assets/{RemoteRepoCard-DgOTYE8p.js → RemoteRepoCard-DxB8Q8yE.js} +1 -1
  25. package/src/ui/public/assets/{SourceMapView-wrchi7Si.js → SourceMapView-CfmrPMBm.js} +1 -1
  26. package/src/ui/public/assets/{SvgIcon-BwCRUb-C.js → SvgIcon-yefEMV0-.js} +1 -1
  27. package/src/ui/public/assets/{TemplateManager-B6pI5C4y.js → TemplateManager-CCy_WcSK.js} +1 -1
  28. package/src/ui/public/assets/{UserInputNode-Di1kFO5g.js → UserInputNode-3Gv_9YZx.js} +1 -1
  29. package/src/ui/public/assets/{WorkbenchView-CI_sSeYY.js → WorkbenchView-Dgp6A83v.js} +5 -5
  30. package/src/ui/public/assets/_plugin-vue_export-helper-B1mHBne9.js +19 -0
  31. package/src/ui/public/assets/configStore-BDxel6Co.js +1 -0
  32. package/src/ui/public/assets/element-plus-Cwwq-Gje.css +1 -0
  33. package/src/ui/public/assets/{flow-mindmap-Dybg7aXu.js → flow-mindmap-BqFb1WO5.js} +1 -1
  34. package/src/ui/public/assets/gitStore-D5CWxPLv.js +6 -0
  35. package/src/ui/public/assets/index-CmbatbSR.css +1 -0
  36. package/src/ui/public/assets/index-gpuX9fhG.js +111 -0
  37. package/src/ui/public/assets/{office-docx-BZoGgigI.js → office-docx-CZXLkCf5.js} +1 -1
  38. package/src/ui/public/assets/{office-excel-CWXhvPQt.js → office-excel-CBKszjVA.js} +1 -1
  39. package/src/ui/public/assets/{office-pptx-Di9Tw3Lc.js → office-pptx-NeUSnN3k.js} +1 -1
  40. package/src/ui/public/assets/{previewSandbox-DMg4ngSx.js → previewSandbox-qLKxghfr.js} +0 -0
  41. package/src/ui/public/assets/{useThemeObserver-COR_mDL-.js → useThemeObserver-E7Hk50l3.js} +1 -1
  42. package/src/ui/public/assets/vendor-C5qX_I8r.css +1 -0
  43. package/src/ui/public/assets/{vendor-DP-rcIZp.js → vendor-IQQMq-1c.js} +20 -20
  44. package/src/ui/public/assets/{vue-flow-CLj74gJJ.js → vue-flow-fLUQ0_kE.js} +1 -1
  45. package/src/ui/public/index.html +18 -19
  46. package/src/ui/server/index.js +4 -0
  47. package/src/ui/server/routes/explorerContextMenu.js +208 -0
  48. package/src/ui/server/routes/explorerContextMenu.test.js +180 -0
  49. package/src/ui/server/routes/workbench/agentChat.js +11 -1
  50. package/src/ui/public/assets/AgentView-DHXZJLpl.js +0 -5
  51. package/src/ui/public/assets/MindmapView-BQTqx842.css +0 -1
  52. package/src/ui/public/assets/MindmapView-Ci2gttUI.js +0 -2
  53. package/src/ui/public/assets/_plugin-vue_export-helper-BsV3BiZm.js +0 -19
  54. package/src/ui/public/assets/configStore-Cubt3KDP.js +0 -1
  55. package/src/ui/public/assets/element-plus-VKM0Y6Ty.css +0 -1
  56. package/src/ui/public/assets/gitStore-J2f7bmAs.js +0 -4
  57. package/src/ui/public/assets/index-BZUAVMg6.css +0 -1
  58. package/src/ui/public/assets/index-ClPoUp9g.js +0 -102
  59. package/src/ui/public/assets/toolsStore-B2XGcQx-.js +0 -1
  60. package/src/ui/public/assets/vendor-4ojsjDYc.css +0 -1
  61. /package/src/ui/public/assets/{element-plus-CqvO58xa.js → element-plus-DxBPQwL7.js} +0 -0
@@ -0,0 +1,180 @@
1
+ // Copyright 2026 xz333221
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // http://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+ //
15
+ // 资源管理器右键菜单(设置 → 通用设置 → 系统集成)的回归测试。
16
+ // 全程用假的 execFileFn —— 真的往 HKCU 写注册表会污染跑测试的这台机器。
17
+ import { test } from 'node:test'
18
+ import assert from 'node:assert/strict'
19
+ import {
20
+ buildMenuCommand,
21
+ getExplorerContextMenuStatus,
22
+ installExplorerContextMenu,
23
+ MENU_REGISTRY_ROOTS,
24
+ registerExplorerContextMenuRoutes,
25
+ sanitizeMenuLabel,
26
+ uninstallExplorerContextMenu,
27
+ } from './explorerContextMenu.js'
28
+
29
+ /** 记录所有 reg.exe 调用并返回空输出的假实现 */
30
+ function createFakeReg({ fail = () => false } = {}) {
31
+ const calls = []
32
+ const execFileFn = async (file, args) => {
33
+ calls.push({ file, args })
34
+ const error = fail(args)
35
+ if (error) throw error
36
+ return { stdout: '', stderr: '' }
37
+ }
38
+ return { calls, execFileFn }
39
+ }
40
+
41
+ /** 从假调用记录里取出某个 reg 子命令的目标键 */
42
+ function targetsOf(calls, subcommand) {
43
+ return calls.filter((c) => c.args[0] === subcommand).map((c) => c.args[1])
44
+ }
45
+
46
+ test('sanitizeMenuLabel: 空值/非字符串退回默认标题', () => {
47
+ const fallback = '用 g UI 打开'
48
+ for (const input of [undefined, null, '', ' ', 42, {}, '\n\t']) {
49
+ assert.equal(sanitizeMenuLabel(input), fallback)
50
+ }
51
+ })
52
+
53
+ test('sanitizeMenuLabel: 控制字符换空格、首尾裁剪、超长截断', () => {
54
+ assert.equal(sanitizeMenuLabel(' 用 g UI 打开 '), '用 g UI 打开')
55
+ assert.equal(sanitizeMenuLabel('用 g UI\n打开'), '用 g UI 打开')
56
+ assert.equal(sanitizeMenuLabel('x'.repeat(200)).length, 64)
57
+ })
58
+
59
+ test('buildMenuCommand: 指向本包 CLI 的 ui 子命令,目录交给 %V', () => {
60
+ const command = buildMenuCommand({ nodePath: 'C:\\Program Files\\nodejs\\node.exe', entryPath: 'D:\\a b\\gitCommit.js' })
61
+ assert.equal(command, '"C:\\Program Files\\nodejs\\node.exe" "D:\\a b\\gitCommit.js" ui --path="%V"')
62
+ // 不带 cmd.exe / start:%V 由 Explorer 展开后才交给 node,中间没有第二层词法
63
+ assert.doesNotMatch(command, /cmd\.exe/i)
64
+ })
65
+
66
+ test('install: 两个落点都写入标题 + 图标 + command 子键', async () => {
67
+ const { calls, execFileFn } = createFakeReg()
68
+ const { label } = await installExplorerContextMenu({ label: '用 g UI 打开', execFileFn, nodePath: 'C:\\node\\node.exe', entryPath: 'D:\\zen\\gitCommit.js' })
69
+
70
+ assert.equal(label, '用 g UI 打开')
71
+ const menuKeys = targetsOf(calls, 'add').filter((k) => !k.endsWith('\\command'))
72
+ assert.deepEqual([...new Set(menuKeys)], [...MENU_REGISTRY_ROOTS])
73
+ assert.deepEqual(targetsOf(calls, 'add').filter((k) => k.endsWith('\\command')), MENU_REGISTRY_ROOTS.map((k) => `${k}\\command`))
74
+ for (const call of calls) {
75
+ assert.equal(call.file, 'reg.exe')
76
+ assert.ok(call.args.includes('/f'), 'reg add 必须带 /f,否则第二次点击会弹覆盖确认')
77
+ }
78
+ const titleCall = calls.find((c) => c.args[1] === MENU_REGISTRY_ROOTS[0] && c.args[2] === '/ve')
79
+ assert.deepEqual(titleCall.args.slice(-2), ['用 g UI 打开', '/f'])
80
+ const commandCall = calls.find((c) => c.args[1] === `${MENU_REGISTRY_ROOTS[0]}\\command`)
81
+ assert.equal(commandCall.args.at(-2), '"C:\\node\\node.exe" "D:\\zen\\gitCommit.js" ui --path="%V"')
82
+ })
83
+
84
+ test('install: 客户端传来的脏标题被清洗后写入', async () => {
85
+ const { calls, execFileFn } = createFakeReg()
86
+ await installExplorerContextMenu({ label: 'Open with g UI\r\nrm -rf /', execFileFn })
87
+ const titleCall = calls.find((c) => c.args[1] === MENU_REGISTRY_ROOTS[0] && c.args[2] === '/ve')
88
+ assert.equal(titleCall.args.at(-2), 'Open with g UI rm -rf /')
89
+ })
90
+
91
+ test('uninstall: 两个落点都删,键不存在(退出码 1)不算失败', async () => {
92
+ const missing = Object.assign(new Error('reg.exe exited with code 1'), { code: 1 })
93
+ const { calls, execFileFn } = createFakeReg({ fail: (args) => (args[0] === 'delete' && args[1].includes('Background') ? missing : false) })
94
+ await uninstallExplorerContextMenu({ execFileFn })
95
+ assert.deepEqual(targetsOf(calls, 'delete'), [...MENU_REGISTRY_ROOTS])
96
+ })
97
+
98
+ test('uninstall: 真正的删除失败(非"键不存在")必须抛出来', async () => {
99
+ const { execFileFn } = createFakeReg({ fail: () => Object.assign(new Error('拒绝访问'), { code: 5 }) })
100
+ await assert.rejects(() => uninstallExplorerContextMenu({ execFileFn }), /拒绝访问/)
101
+ })
102
+
103
+ test('status: 两个键都在才算已安装', async () => {
104
+ const both = createFakeReg()
105
+ assert.equal((await getExplorerContextMenuStatus({ execFileFn: both.execFileFn })).installed, true)
106
+ assert.deepEqual(targetsOf(both.calls, 'query'), [...MENU_REGISTRY_ROOTS])
107
+
108
+ const half = createFakeReg({ fail: (args) => (args[1].includes('Background') ? Object.assign(new Error('missing'), { code: 1 }) : false) })
109
+ const status = await getExplorerContextMenuStatus({ execFileFn: half.execFileFn })
110
+ assert.equal(status.installed, false)
111
+ assert.equal(status.keys[MENU_REGISTRY_ROOTS[1]], false)
112
+ })
113
+
114
+ // ── 路由层 ────────────────────────────────────────────────────────────────
115
+
116
+ function createRouteHarness(options) {
117
+ const routes = new Map()
118
+ const app = {
119
+ get(path, handler) { routes.set(`GET ${path}`, handler) },
120
+ post(path, handler) { routes.set(`POST ${path}`, handler) },
121
+ }
122
+ registerExplorerContextMenuRoutes({ app, ...options })
123
+ async function request(key, body) {
124
+ const response = { code: 200, body: null, status(code) { this.code = code; return this }, json(value) { this.body = value; return this } }
125
+ await routes.get(key)({ method: key.split(' ')[0], path: key.split(' ')[1], body }, response, () => {})
126
+ return response
127
+ }
128
+ return { request }
129
+ }
130
+
131
+ test('route: 非 Windows 返回 supported=false,写操作直接 400', async () => {
132
+ const { calls, execFileFn } = createFakeReg()
133
+ const { request } = createRouteHarness({ platform: 'darwin', execFileFn })
134
+
135
+ const status = await request('GET /api/explorer-context-menu')
136
+ assert.equal(status.body.supported, false)
137
+ assert.equal(status.body.installed, false)
138
+
139
+ for (const key of ['POST /api/explorer-context-menu/install', 'POST /api/explorer-context-menu/uninstall']) {
140
+ const response = await request(key)
141
+ assert.equal(response.code, 400)
142
+ assert.equal(response.body.success, false)
143
+ }
144
+ assert.equal(calls.length, 0, '非 Windows 不该调用 reg.exe')
145
+ })
146
+
147
+ test('route: 安装→查询→卸载 的状态流转', async () => {
148
+ const installedKeys = new Set()
149
+ const execFileFn = async (file, args) => {
150
+ assert.equal(file, 'reg.exe')
151
+ if (args[0] === 'add') return { stdout: '', stderr: '' }
152
+ if (args[0] === 'delete') { installedKeys.delete(args[1]); return { stdout: '', stderr: '' } }
153
+ if (installedKeys.has(args[1])) return { stdout: '', stderr: '' }
154
+ throw Object.assign(new Error('missing'), { code: 1 })
155
+ }
156
+ // add 之后把键记成已存在,模拟真实注册表
157
+ const wrapping = async (file, args) => { const r = await execFileFn(file, args); if (args[0] === 'add' && !args[1].endsWith('\\command')) installedKeys.add(args[1]); return r }
158
+
159
+ const { request } = createRouteHarness({ platform: 'win32', execFileFn: wrapping, nodePath: 'C:\\node\\node.exe', entryPath: 'D:\\zen\\gitCommit.js' })
160
+
161
+ assert.equal((await request('GET /api/explorer-context-menu')).body.installed, false)
162
+
163
+ const install = await request('POST /api/explorer-context-menu/install', { label: '用 g UI 打开' })
164
+ assert.equal(install.body.success, true)
165
+ assert.match(install.body.message, /用 g UI 打开/)
166
+
167
+ assert.equal((await request('GET /api/explorer-context-menu')).body.installed, true)
168
+
169
+ const uninstall = await request('POST /api/explorer-context-menu/uninstall')
170
+ assert.equal(uninstall.body.success, true)
171
+ assert.equal((await request('GET /api/explorer-context-menu')).body.installed, false)
172
+ })
173
+
174
+ test('route: reg.exe 写失败时返回 400 和原因', async () => {
175
+ const { execFileFn } = createFakeReg({ fail: () => Object.assign(new Error('拒绝访问注册表'), { code: 5 }) })
176
+ const { request } = createRouteHarness({ platform: 'win32', execFileFn })
177
+ const response = await request('POST /api/explorer-context-menu/install', { label: '用 g UI 打开' })
178
+ assert.equal(response.code, 400)
179
+ assert.match(response.body.error, /拒绝访问注册表/)
180
+ })
@@ -22,6 +22,7 @@
22
22
  // - { type: 'thinking', delta } — 推理过程增量
23
23
  // - { type: 'content', delta } — 正文增量
24
24
  // - { type: 'tool_call_start', toolCallId, name, argsPreview }
25
+ // - { type: 'tool_output', toolCallId, chunk } — 命令执行中的增量输出(仅展示)
25
26
  // - { type: 'tool_result', toolCallId, name, result }
26
27
  // - { type: 'ask_user', interactionId, question, options, allowFreeText }
27
28
  // - { type: 'done', content } — 本轮最终完成
@@ -355,7 +356,16 @@ export async function runAgentTurn({ session, model, userMessage, images = [], c
355
356
  const argsPreview = summarizeArgs(name, args);
356
357
  send({ type: 'tool_call_start', toolCallId, name, argsPreview });
357
358
 
358
- const toolCtx = { ...ctx, signal };
359
+ const toolCtx = {
360
+ ...ctx,
361
+ signal,
362
+ // run_command 执行期间的增量输出 → 前端实时显示。
363
+ // 只用于展示,不进会话历史 —— 历史里存的仍是带 exit code 的最终结果。
364
+ onOutput: (chunk) => {
365
+ const text = String(chunk || '');
366
+ if (text) send({ type: 'tool_output', toolCallId, name, chunk: text });
367
+ },
368
+ };
359
369
  if (name === 'ask_user' && typeof ctx.askUser === 'function') {
360
370
  toolCtx.askUser = askArgs => ctx.askUser(askArgs, {
361
371
  sessionId: session.sessionId,
@@ -1,5 +0,0 @@
1
- import"./rolldown-runtime-C0FnF6B9.js";import{$ as e,$r as t,A as n,Dn as r,E as i,En as a,Fn as o,H as s,Jt as c,K as l,Mn as u,Nn as d,On as f,Ot as p,Pr as m,Q as h,Qn as g,Rt as _,Tn as v,Un as y,Vt as b,Wt as x,Xn as S,Yr as C,_r as w,a as T,ar as E,bn as D,cn as O,cr as k,ct as ee,et as A,fr as j,gn as M,i as N,in as te,j as P,kt as F,mt as I,ot as ne,pt as re,qr as L,r as R,sr as z,tr as ie,un as B,wn as V,wt as ae,yn as H,yr as U,zn as W}from"./element-plus-CqvO58xa.js";import{i as oe,n as G,t as K}from"./vendor-DP-rcIZp.js";import{n as q,t as J}from"./_plugin-vue_export-helper-BsV3BiZm.js";import{t as Y}from"./configStore-Cubt3KDP.js";j();var X=65536;function Z(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 a=``;typeof i.content==`string`&&(a=i.content),a.length>X&&(a=`…(前文已截断)\n${a.slice(-65536)}`);let o=[];if(i.tool_calls&&i.tool_calls.length>0)for(let e of i.tool_calls)o.push({id:e.id||e.function?.name||K(),name:e.function?.name||``,arguments:e.function?.arguments||``,argsPreview:Q(e.function?.name||``,e.function?.arguments||``),status:`done`,result:``});let s=r+1;for(;s<n&&e.messages[s].role===`tool`;){let t=e.messages[s],n=t.tool_call_id||t.name||``,i=o.find(e=>e.id===n);if(i){let e=t.content;typeof e!=`string`&&(e=`(non-text result)`),e.length>X&&(e=`…(前文已截断)\n${e.slice(-65536)}`),i.result=e}r=s,s++}let c=!!a,l=o.length>0;(c||l)&&t.push({id:`msg-${r}`,role:`assistant`,content:a||``,toolCalls:l?o:void 0,status:`done`,createdAt:Date.now()})}}}return t}function Q(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 se(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 ce(){let e=Y(),t=U([]),n=U(!1),r=U(null),i=U([]),a=U(!1),o=U(!1),s=U(null),c=U(!1),l=null,u=0,d=0;async function f(){let r=++d,i=e.currentDirectory||``;if(!i){t.value=[],n.value=!1;return}n.value=!0;try{let e=`/api/agent/sessions?cwd=${encodeURIComponent(i)}`,n=await fetch(e).then(e=>e.json());if(r!==d)return;if(!n.success){N.error(n.error||q(`@AGENT:加载会话列表失败`));return}t.value=Array.isArray(n.sessions)?n.sessions:[]}catch(e){if(r!==d)return;N.error(q(`@AGENT:加载会话列表失败`)+`: `+(e?.message||e))}finally{r===d&&(n.value=!1)}}function p(n,r){let i=new Date().toISOString(),a=t.value.find(e=>e.sessionId===n);if(a){a.isGenerating=!0,a.updatedAt=i;return}t.value=[{sessionId:n,title:r,source:`web`,cwd:e.currentDirectory||``,model:``,createdAt:i,updatedAt:i,messageCount:1,size:0,isGenerating:!0},...t.value]}function m(e){let n=t.value.find(t=>t.sessionId===e);n&&(n.isGenerating=!1)}async function h(e){o.value=!0,r.value=e;try{let t=await fetch(`/api/agent/sessions/${encodeURIComponent(e)}`).then(e=>e.json());if(!t.success){N.error(t.error||q(`@AGENT:加载会话失败`));return}i.value=Z(t.session)}catch(e){N.error(q(`@AGENT:加载会话失败`)+`: `+(e?.message||e))}finally{o.value=!1}}async function g(e){try{await R.confirm(q(`@AGENT:确认删除该会话`),q(`@AGENT:删除后无法恢复`),{type:`warning`})}catch{return}try{let n=await fetch(`/api/agent/sessions/${encodeURIComponent(e)}`,{method:`DELETE`}).then(e=>e.json());if(!n.success){N.error(n.error||q(`@AGENT:删除失败`));return}t.value=t.value.filter(t=>t.sessionId!==e),r.value===e&&(r.value=null,i.value=[]),N.success(q(`@AGENT:已删除`))}catch(e){N.error(q(`@AGENT:删除失败`)+`: `+(e?.message||e))}}async function _(e,n){try{let r=await fetch(`/api/agent/sessions/${encodeURIComponent(e)}`,{method:`PUT`,headers:{"Content-Type":`application/json`},body:JSON.stringify({title:n})}).then(e=>e.json());if(!r.success){N.error(r.error||q(`@AGENT:重命名失败`));return}let i=t.value.find(t=>t.sessionId===e);i&&(i.title=n),N.success(q(`@AGENT:已重命名`))}catch(e){N.error(q(`@AGENT:重命名失败`)+`: `+(e?.message||e))}}function v(){r.value=null,i.value=[],s.value=null,t.value=t.value.filter(e=>!e.isGenerating)}async function y(t,n=[]){let o=n.filter(e=>e?.file?.type?.startsWith(`image/`));if(o.length<n.length&&N.warning(q(`@AGENT:仅支持发送图片,非图片文件已忽略`)),!t.trim()&&o.length===0||a.value)return;let d=(await Promise.allSettled(o.map(e=>se(e.file)))).map(e=>e.status===`fulfilled`?e.value:``).filter(e=>e.startsWith(`data:image/`)),h=++u;l=new AbortController;let g=l,_={id:K(),role:`user`,content:t,status:`done`,createdAt:Date.now()};o.length>0&&(_.attachments=o.map(e=>({id:e.id,name:e.file.name||`image`,size:e.file.size||0,type:e.file.type||``,preview:e.preview}))),i.value.push(_);let v=w({id:K(),role:`assistant`,content:``,status:`pending`,createdAt:Date.now()});i.value.push(v),a.value=!0;let y=[],b=null;try{let n=await fetch(`/api/agent/chat`,{method:`POST`,headers:{"Content-Type":`application/json`,Accept:`text/event-stream`},body:JSON.stringify({sessionId:r.value||``,userMessage:t,cwd:e.currentDirectory||``,...d.length>0?{images:d}:{}}),signal:g.signal});if(h!==u)return;if(!n.ok||!n.body){let e=await n.text().catch(()=>``);throw Error(e||`HTTP ${n.status}`)}let a=n.body.getReader(),o=new TextDecoder(`utf-8`),c=``,l=r.value;for(;;){let{value:e,done:n}=await a.read();if(h!==u)return;if(n)break;c+=o.decode(e,{stream:!0});let d=c.split(`
2
- `);c=d.pop()??``;for(let e of d){let n=e.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){l=a.sessionId,b=a.sessionId,r.value=a.sessionId;let e=String(a.title||``).trim()||t.trim().split(`
3
- `)[0].trim().slice(0,40)||q(`@AGENT:无标题`);p(a.sessionId,e)}break;case`thinking`:v.reasoning||(v.reasoning=``,v.reasoningStatus=`streaming`),v.reasoning+=String(a.delta||``),v.status=`streaming`;break;case`content`:v.status===`pending`&&(v.status=`streaming`);{let e=String(a.delta||``);v.content+=e;let t=G(v.content);t.reasoning&&(v.reasoning||(v.reasoning=``,v.reasoningStatus=`streaming`),v.reasoning=t.reasoning,v.content=t.content)}break;case`tool_call_start`:{let e=w({id:a.toolCallId||K(),name:a.name||``,argsPreview:a.argsPreview||``,arguments:a.argsPreview||``,status:`running`,result:``});y.push(e),v.toolCalls||=[],v.toolCalls.push(e),v.status===`pending`&&(v.status=`streaming`);break}case`tool_result`:{let e=y.find(e=>e.id===a.toolCallId);e&&(e.result=String(a.result||``),e.status=`done`,e.name===`ask_user`&&(s.value=null));break}case`ask_user`:s.value={interactionId:String(a.interactionId||``),question:String(a.question||``),options:Array.isArray(a.options)?a.options.map(e=>String(e)):[],allowFreeText:a.allowFreeText!==!1};break;case`done`:{let e=a.content||v.content,t=G(e);t.reasoning&&!v.reasoning&&(v.reasoning=t.reasoning),v.content=t.content,v.status=`done`,v.reasoningStatus===`streaming`&&(v.reasoningStatus=`done`);break}case`error`:v.status=`error`,v.error=String(a.error||q(`@AGENT:未知错误`)),v.reasoningStatus===`streaming`&&(v.reasoningStatus=`done`)}}i.value=[...i.value]}if(h!==u)return;v.status===`pending`&&(v.status=`done`),l&&l!==r.value&&(r.value=l),f().catch(()=>{})}catch(e){if(h!==u)return;e?.name===`AbortError`||g.signal.aborted?(v.content=(v.content||``)+`
4
-
5
- [`+q(`@AGENT:已停止`)+`]`,v.status=`done`,v.reasoningStatus===`streaming`&&(v.reasoningStatus=`done`)):(v.status=`error`,v.error=e?.message||String(e),N.error(v.error||q(`@AGENT:对话失败`)))}finally{h===u&&(a.value=!1,s.value=null,c.value=!1,l=null,b&&m(b))}}async function b(e){let t=s.value,n=r.value,i=String(e||``).trim();if(!t||!n||!i||c.value)return!1;c.value=!0;try{let e=await fetch(`/api/agent/respond`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({sessionId:n,interactionId:t.interactionId,answer:i})}).then(e=>e.json());if(!e.success)throw Error(e.error||q(`@AGENT:回答提交失败`));return s.value=null,!0}catch(e){return N.error(e?.message||q(`@AGENT:回答提交失败`)),!1}finally{c.value=!1}}function x(){l&&=(l.abort(),null)}return{sessions:t,sessionsLoading:n,currentSessionId:r,messages:i,isStreaming:a,sessionLoading:o,pendingQuestion:s,answeringQuestion:c,loadSessions:f,loadSession:h,deleteSession:g,renameSession:_,newSession:v,sendMessage:y,answerQuestion:b,stop:x}}W(),j();var le=o({__name:`MarketplacePanel`,props:{type:{type:String,required:!0}},setup(e,{expose:t}){t();let n=e,r=Y(),i=U([]),a=U([]),o=U(!1),s=U(``),l=U(``),u=U([]),d=U(`project`),f=U(new Set),m=U(new Set),h=V(()=>r.currentDirectory||``),g=null;async function _(){if(!o.value){o.value=!0;try{let e=new URLSearchParams({type:n.type,cwd:h.value});l.value&&e.set(`q`,l.value),u.value.length&&e.set(`sources`,u.value.join(`,`));let t=await(await fetch(`/api/agent/marketplace/catalog?${e}`)).json();t?.success?(i.value=t.groups||[],a.value=t.installed||[]):N.error(t?.error||q(`@MKT:加载失败`))}catch{N.error(q(`@MKT:加载失败`))}finally{o.value=!1}}}E(s,e=>{g&&clearTimeout(g),g=setTimeout(()=>{l.value=e.trim(),_()},400)}),E(u,()=>_()),E(()=>n.type,()=>{u.value=[],l.value=``,s.value=``,_()}),E(h,()=>_()),_();let v=V(()=>{let e=h.value?h.value.split(/[\\/]/).filter(Boolean).pop():``;return d.value===`project`?e||q(`@MKT:当前项目`):q(`@MKT:g ai 智能体`)});function y(e){return e.stars?`${S(e.stars)} ★`:e.downloads?`${S(e.downloads)} ${q(`@MKT:周下载`)}`:e.uses?`${S(e.uses)} ${q(`@MKT:次使用`)}`:``}function S(e){return e>=1e3?`${(e/1e3).toFixed(e>=1e4?0:1)}k`:String(e)}function C(e){return`${e.id}`}function T(e){return f.value.has(C(e))}let D=V(()=>{let e={project:[],global:[]};for(let t of a.value)(e[t.target]||=[]).push(t);return e}),O=w({visible:!1,item:null,env:{},args:``});function k(e){return n.type===`mcp`&&(!!e.envKeys?.length||!!e.args?.length)}function j(e){O.item=e,O.env=Object.fromEntries((e.envKeys||[]).map(e=>[e,``])),O.args=(e.args||[]).join(` `),O.visible=!0}function M(){let e=O.item;if(O.visible=!1,!e)return;let t=Object.fromEntries(Object.entries(O.env).filter(([,e])=>e.trim()!==``)),n=O.args.trim()?O.args.trim().match(/(?:[^\s"]+|"[^"]*")+/g)?.map(e=>e.replace(/^"|"$/g,``))??void 0:void 0;F(e,{env:t,...n?{args:n}:{}})}async function P(e){if(!e.installed||await I(e)){if(k(e)){j(e);return}await F(e,{})}}async function F(e,t){let r=C(e);f.value.add(r);try{let r=await fetch(`/api/agent/marketplace/install`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({type:n.type,target:d.value,cwd:h.value,item:{...e,...t}})}),i=await r.json().catch(()=>null);if(!r.ok||!i?.success){N.error(i?.error||q(`@MKT:安装失败`));return}i.item?.warning&&N.warning(i.item.warning),i.item?.envKeys?.length?N.warning(`${q(`@MKT:还缺环境变量`)}: ${i.item.envKeys.join(`, `)}`):N.success(q(`@MKT:安装成功`)),await _()}catch{N.error(q(`@MKT:安装失败`))}finally{f.value.delete(r)}}async function I(e){try{return await R.confirm(`${e.name} ${q(`@MKT:已安装,要重新安装吗?`)}`,q(`@MKT:重新安装`),{confirmButtonText:q(`@MKT:重装`),cancelButtonText:q(`@MKT:取消`),type:`warning`}),!0}catch{return!1}}async function ne(e){try{await R.confirm(`${q(`@MKT:确定卸载`)} ${e.name}?`,q(`@MKT:卸载`),{confirmButtonText:q(`@MKT:卸载`),cancelButtonText:q(`@MKT:取消`),type:`warning`})}catch{return}let t=`${e.target}:${e.id}`;m.value.add(t);try{let t=new URLSearchParams({target:e.target,cwd:h.value}),r=await fetch(`/api/agent/marketplace/item/${n.type}/${encodeURIComponent(e.id)}?${t}`,{method:`DELETE`}),i=await r.json().catch(()=>null);if(!r.ok||!i?.success){N.error(i?.error||q(`@MKT:卸载失败`));return}N.success(q(`@MKT:已卸载`)),await _()}catch{N.error(q(`@MKT:卸载失败`))}finally{m.value.delete(t)}}let L={props:n,configStore:r,groups:i,installed:a,loading:o,searchInput:s,query:l,selectedSources:u,installTarget:d,installing:f,removing:m,cwd:h,get searchTimer(){return g},set searchTimer(e){g=e},loadCatalog:_,targetLabel:v,metricText:y,formatCount:S,cardKey:C,isBusy:T,installedByTarget:D,configDialog:O,needsConfig:k,openConfigDialog:j,confirmConfig:M,onInstall:P,doInstall:F,confirmReinstall:I,onRemove:ne,get $t(){return q},get Search(){return x},get Refresh(){return b},get Delete(){return ee},get Link(){return p},get Check(){return A},get Star(){return c},get Download(){return re},get Warning(){return te}};return Object.defineProperty(L,"__isScriptSetup",{enumerable:!1,value:!0}),L}});W(),B(),m();var ue={class:`marketplace-panel`},de={class:`mp-toolbar`},fe={class:`mp-search`},pe=[`placeholder`],me={class:`mp-toolbar-sub`},he={class:`mp-target-hint`},ge={class:`mp-source-filter`},_e=[`onClick`],ve={class:`mp-body`},ye={class:`mp-group-header`},be={class:`mp-group-title`},xe={key:0,class:`mp-group-count`},Se={key:1,class:`mp-group-error`},Ce=[`href`,`title`],we={key:0,class:`mp-grid`},Te={class:`mp-card-head`},Ee=[`title`],De={key:0,class:`mp-card-metric`},Oe=[`title`],ke={class:`mp-card-meta`},Ae=[`title`],je=[`title`],Me={key:2,class:`mp-tag remote`},Ne={class:`mp-card-foot`},Pe=[`href`],Fe={key:1,class:`mp-installed-chip`},Ie=[`disabled`,`onClick`],Le={key:3,class:`mp-not-installable`},Re={key:1,class:`mp-empty`},ze={key:0,class:`mp-group installed`},Be={class:`mp-group-header`},Ve={class:`mp-group-title`},He={class:`mp-group-count`},Ue={key:0,class:`mp-installed-block`},We={class:`mp-installed-target`},Ge={class:`mp-installed-list`},Ke={class:`mp-installed-name`},qe={key:0,class:`mp-meta-pkg`},Je={key:1,class:`mp-tag warn`},Ye=[`disabled`,`onClick`],Xe={key:1,class:`mp-empty all`},Ze={key:0,class:`mkt-form`},Qe={class:`mkt-form-name`},$e=[`onUpdate:modelValue`,`placeholder`],et={key:0,class:`mkt-field`},tt={class:`mkt-hint`};function nt(e,o,c,p,m,h){let _=l,y=n,b=P,x=s,C=i,w=T;return S(),f(`div`,ue,[r(` ── 工具栏 ───────────────────────────────── `),v(`div`,de,[v(`div`,fe,[d(_,{class:`mp-search-icon`},{default:z(()=>[d(p.Search)]),_:1}),k(v(`input`,{"onUpdate:modelValue":o[0]||=e=>p.searchInput=e,class:`mp-search-input`,type:`text`,placeholder:c.type===`skill`?p.$t(`@MKT:搜索 Skill...`):p.$t(`@MKT:搜索 MCP 服务...`)},null,8,pe),[[M,p.searchInput]])]),d(b,{modelValue:p.installTarget,"onUpdate:modelValue":o[1]||=e=>p.installTarget=e,size:`small`,class:`mp-target`},{default:z(()=>[d(y,{value:`project`},{default:z(()=>[u(t(p.$t(`@MKT:当前项目`)),1)]),_:1}),d(y,{value:`global`},{default:z(()=>[u(t(p.$t(`@MKT:g ai 智能体`)),1)]),_:1})]),_:1},8,[`modelValue`]),d(x,{content:p.$t(`@MKT:刷新`),placement:`top`,"show-after":300},{default:z(()=>[v(`button`,{class:L([`mp-refresh`,{spinning:p.loading}]),onClick:p.loadCatalog},[d(_,null,{default:z(()=>[d(p.Refresh)]),_:1})],2)]),_:1},8,[`content`])]),v(`div`,me,[v(`span`,he,[u(t(p.$t(`@MKT:安装到`))+` `,1),v(`b`,null,t(p.targetLabel),1)]),v(`div`,ge,[(S(!0),f(D,null,g(p.groups,e=>(S(),f(`button`,{key:e.id,class:L([`mp-chip`,{active:p.selectedSources.includes(e.id)}]),onClick:()=>{let t=p.selectedSources.indexOf(e.id);t>=0?p.selectedSources.splice(t,1):p.selectedSources.push(e.id)}},t(e.label),11,_e))),128)),p.selectedSources.length?(S(),f(`button`,{key:0,class:`mp-chip clear`,onClick:o[2]||=e=>p.selectedSources=[]},t(p.$t(`@MKT:全部来源`)),1)):r(`v-if`,!0)])]),r(` ── 内容 ─────────────────────────────────── `),k((S(),f(`div`,ve,[(S(!0),f(D,null,g(p.groups,e=>(S(),f(`section`,{key:e.id,class:`mp-group`},[v(`header`,ye,[v(`h3`,be,t(e.label),1),e.status===`ok`?(S(),f(`span`,xe,t(e.items.length),1)):(S(),f(`span`,Se,[d(_,null,{default:z(()=>[d(p.Warning)]),_:1}),u(` `+t(e.error||p.$t(`@MKT:来源不可用`)),1)])),e.homepage?(S(),f(`a`,{key:2,class:`mp-group-link`,href:e.homepage,target:`_blank`,rel:`noopener noreferrer`,title:e.homepage},[d(_,null,{default:z(()=>[d(p.Link)]),_:1})],8,Ce)):r(`v-if`,!0)]),e.status===`ok`&&e.items.length?(S(),f(`div`,we,[(S(!0),f(D,null,g(e.items,e=>(S(),f(`article`,{key:p.cardKey(e),class:`mp-card`},[v(`div`,Te,[v(`span`,{class:`mp-card-name`,title:e.name},t(e.name),9,Ee),p.metricText(e)?(S(),f(`span`,De,[d(_,null,{default:z(()=>[e.stars?(S(),a(p.Star,{key:0})):(S(),a(p.Download,{key:1}))]),_:2},1024),u(` `+t(p.metricText(e)),1)])):r(`v-if`,!0)]),v(`p`,{class:`mp-card-desc`,title:e.description},t(e.description||p.$t(`@MKT:暂无描述`)),9,Oe),v(`div`,ke,[e.package?(S(),f(`code`,{key:0,class:`mp-meta-pkg`,title:e.package},t(e.package),9,Ae)):e.repository?(S(),f(`span`,{key:1,class:`mp-meta-repo`,title:e.repository+(e.subpath?` · `+e.subpath:``)},[u(t(e.repository),1),e.subpath?(S(),f(D,{key:0},[u(` · `+t(e.subpath),1)],64)):r(`v-if`,!0)],8,je)):r(`v-if`,!0),e.transport===`remote`?(S(),f(`span`,Me,t(p.$t(`@MKT:远程服务`)),1)):r(`v-if`,!0),(S(!0),f(D,null,g((e.tags||[]).slice(0,2),e=>(S(),f(`span`,{key:e,class:`mp-tag`},t(e),1))),128))]),v(`div`,Ne,[e.upstream?(S(),f(`a`,{key:0,class:`mp-card-link`,href:e.upstream,target:`_blank`,rel:`noopener noreferrer`},t(p.$t(`@MKT:查看来源`)),9,Pe)):r(`v-if`,!0),o[6]||=v(`span`,{class:`mp-foot-spacer`},null,-1),e.installed?(S(),f(`span`,Fe,[d(_,null,{default:z(()=>[d(p.Check)]),_:1}),u(t(p.$t(`@MKT:已安装`)),1)])):e.installable===!1?(S(),f(`span`,Le,t(p.$t(`@MKT:暂不支持一键安装`)),1)):(S(),f(`button`,{key:2,class:`mp-install-btn`,disabled:p.isBusy(e),onClick:t=>p.onInstall(e)},t(p.isBusy(e)?p.$t(`@MKT:安装中...`):p.$t(`@MKT:安装`)),9,Ie))])]))),128))])):e.status===`ok`?(S(),f(`div`,Re,t(p.$t(`@MKT:该来源暂无结果`)),1)):r(`v-if`,!0)]))),128)),r(` ── 已安装 ─────────────────────────────── `),p.installed.length?(S(),f(`section`,ze,[v(`header`,Be,[v(`h3`,Ve,t(p.$t(`@MKT:已安装`)),1),v(`span`,He,t(p.installed.length),1)]),(S(),f(D,null,g([`project`,`global`],e=>v(`div`,{key:e},[p.installedByTarget[e]?.length?(S(),f(`div`,Ue,[v(`div`,We,t(e===`project`?p.$t(`@MKT:当前项目`):p.$t(`@MKT:g ai 智能体`)),1),v(`div`,Ge,[(S(!0),f(D,null,g(p.installedByTarget[e],n=>(S(),f(`div`,{key:e+n.id,class:`mp-installed-row`},[v(`span`,Ke,t(n.name),1),n.package?(S(),f(`code`,qe,t(n.package),1)):r(`v-if`,!0),n.requiredEnv?.length?(S(),f(`span`,Je,t(p.$t(`@MKT:待配置`))+`: `+t(n.requiredEnv.join(`, `)),1)):r(`v-if`,!0),o[7]||=v(`span`,{class:`mp-foot-spacer`},null,-1),v(`button`,{class:`mp-remove-btn`,disabled:p.removing.has(e+n.id),onClick:e=>p.onRemove(n)},[d(_,null,{default:z(()=>[d(p.Delete)]),_:1}),u(` `+t(p.removing.has(e+n.id)?p.$t(`@MKT:卸载中...`):p.$t(`@MKT:卸载`)),1)],8,Ye)]))),128))])])):r(`v-if`,!0)])),64))])):r(`v-if`,!0),!p.loading&&!p.groups.length?(S(),f(`div`,Xe,t(p.$t(`@MKT:加载失败`)),1)):r(`v-if`,!0)])),[[w,p.loading]]),r(` ── MCP 安装前配置 ───────────────────────── `),d(C,{modelValue:p.configDialog.visible,"onUpdate:modelValue":o[5]||=e=>p.configDialog.visible=e,title:p.$t(`@MKT:配置 MCP`),width:`460px`,"close-on-click-modal":!1,"append-to-body":``},{footer:z(()=>[v(`button`,{class:`mkt-cancel`,onClick:o[4]||=e=>p.configDialog.visible=!1},t(p.$t(`@MKT:取消`)),1),v(`button`,{class:`mkt-confirm`,onClick:p.confirmConfig},t(p.$t(`@MKT:安装`)),1)]),default:z(()=>[p.configDialog.item?(S(),f(`div`,Ze,[v(`p`,Qe,t(p.configDialog.item.name),1),(S(!0),f(D,null,g(Object.keys(p.configDialog.env),e=>(S(),f(`div`,{key:e,class:`mkt-field`},[v(`label`,null,t(e),1),k(v(`input`,{"onUpdate:modelValue":t=>p.configDialog.env[e]=t,type:`text`,autocomplete:`off`,placeholder:p.$t(`@MKT:环境变量值`),spellcheck:`false`},null,8,$e),[[M,p.configDialog.env[e]]])]))),128)),p.configDialog.item.args?.length?(S(),f(`div`,et,[v(`label`,null,t(p.$t(`@MKT:启动参数`)),1),k(v(`input`,{"onUpdate:modelValue":o[3]||=e=>p.configDialog.args=e,type:`text`,autocomplete:`off`,spellcheck:`false`},null,512),[[M,p.configDialog.args]]),v(`p`,tt,t(p.$t(`@MKT:参数提示`)),1)])):r(`v-if`,!0)])):r(`v-if`,!0)]),_:1},8,[`modelValue`,`title`])])}var rt=J(le,[[`render`,nt],[`__scopeId`,`data-v-e9f9e851`],[`__file`,`D:/workspace/github_workspace/zen-gitsync/src/ui/client/src/components/MarketplacePanel.vue`]]);W(),j();var it=o({__name:`AgentView`,setup(t,{expose:n}){n();let r=Y(),i=U(`chat`),a=V(()=>i.value===`mcp`?`mcp`:`skill`),o=V(()=>[{id:`chat`,label:q(`@AGENT:对话`),icon:h},{id:`skill`,label:q(`@AGENT:Skill 广场`),icon:ae},{id:`mcp`,label:q(`@AGENT:MCP 广场`),icon:ne}]),{sessions:c,sessionsLoading:u,currentSessionId:d,messages:f,isStreaming:p,sessionLoading:m,loadSessions:g,loadSession:v,deleteSession:b,renameSession:S,newSession:C,sendMessage:w,pendingQuestion:T,answeringQuestion:D,answerQuestion:O,stop:k}=ce(),j=V(()=>{let e=r.theme;return e===`dark`||e===`auto`&&window.matchMedia(`(prefers-color-scheme: dark)`).matches?`dark`:`light`}),M=U(``),te=V(()=>{if(!M.value.trim())return c.value;let e=M.value.toLowerCase();return c.value.filter(t=>(t.title||``).toLowerCase().includes(e)||(t.model||``).toLowerCase().includes(e))}),P=V(()=>[{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 re(e){await w(e.text,e.files),await y(),H()}async function L(e){await w(e.prompt),await y(),H()}let z=U(``);async function ie(e=z.value){await O(e)&&(z.value=``)}let B=U(null);function H(e=!0){B.value?.scrollToBottom(e)}E(()=>f.value.length,()=>{y(()=>H(!1))});function W(e){if(p.value){N.warning(q(`@AGENT:请先停止当前生成`));return}v(e)}function G(){if(p.value){N.warning(q(`@AGENT:请先停止当前生成`));return}C()}function K(e,t){if(t.stopPropagation(),p.value&&d.value===e){N.warning(q(`@AGENT:请先停止当前生成`));return}b(e)}async function J(e,t,n){n.stopPropagation();try{let{value:n}=await R.prompt(q(`@AGENT:请输入新的会话标题`),q(`@AGENT:重命名会话`),{inputValue:t,inputPattern:/.+/,inputErrorMessage:q(`@AGENT:标题不能为空`)});n&&n!==t&&await S(e,n)}catch{}}function X(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?q(`@AGENT:今天`):`${e}${q(`@AGENT:天前`)}`}return`${t.getFullYear()}-${i(t.getMonth()+1)}-${i(t.getDate())}`}catch{return e}}let Z=U(280),Q=U(!1);function se(e){Q.value=!0;let t=e.clientX,n=Z.value,r=e=>{let r=e.clientX-t,i=Math.max(200,Math.min(500,n+r));Z.value=i},i=()=>{Q.value=!1,document.removeEventListener(`mousemove`,r),document.removeEventListener(`mouseup`,i)};document.addEventListener(`mousemove`,r),document.addEventListener(`mouseup`,i)}E(()=>[r.currentDirectory,p.value],async([e,t],n)=>{let r=!n||e!==n[0],i=!!n&&n[1]===!0&&!t;(r||i)&&await g(),d.value&&!p.value&&!c.value.some(e=>e.sessionId===d.value)&&C()},{immediate:!0});let $={configStore:r,activeTab:i,marketplaceType:a,tabs:o,sessions:c,sessionsLoading:u,currentSessionId:d,messages:f,isStreaming:p,sessionLoading:m,loadSessions:g,loadSession:v,deleteSession:b,renameSession:S,newSession:C,sendMessage:w,pendingQuestion:T,answeringQuestion:D,answerQuestion:O,stop:k,chatTheme:j,searchQuery:M,filteredSessions:te,presetQuestions:P,onSend:re,onSelectPreset:L,pendingAnswer:z,submitPendingAnswer:ie,chatContainerRef:B,scrollToBottom:H,selectSession:W,handleNewSession:G,handleDelete:K,handleRename:J,formatDate:X,sidebarWidth:Z,isResizing:Q,startResize:se,get $t(){return q},get ElTooltip(){return s},get ElIcon(){return l},get Plus(){return _},get Search(){return x},get Delete(){return ee},get Edit(){return I},get ChatLineRound(){return e},get Loading(){return F},get Check(){return A},get ChatContainer(){return oe},MarketplacePanel:rt};return Object.defineProperty($,"__isScriptSetup",{enumerable:!1,value:!0}),$}});W(),m(),B();var at={class:`agent-view`},ot={class:`sidebar-header`},st={class:`sidebar-search`},ct=[`placeholder`],lt={class:`session-list`},ut={key:0,class:`empty-state`},dt={class:`empty-text`},ft={key:0,class:`empty-hint`},pt=[`onClick`],mt={class:`session-item-main`},ht={class:`session-item-title`},gt={class:`session-item-meta`},_t={key:0,class:`meta-generating`},vt={class:`meta-time`},yt={class:`meta-count`},bt={key:2,class:`meta-source cli`},xt=[`onClick`],St=[`onClick`],Ct={class:`agent-chat-area`},wt={class:`agent-tabs`,role:`tablist`},Tt=[`aria-selected`,`onClick`],Et={class:`agent-tab-body`},Dt={key:0,class:`agent-chat-pane`},Ot={key:0,class:`chat-loading`},kt={key:0,class:`ask-user-panel`,"aria-live":`polite`},At={class:`ask-user-title`},jt={class:`ask-user-question`},Mt={key:0,class:`ask-user-options`},Nt=[`disabled`,`onClick`],Pt=[`disabled`,`placeholder`,`aria-label`],Ft=[`disabled`],It={key:0,class:`stop-button-bar`};function Lt(e,n,i,o,s,c){let l=T;return S(),f(`div`,at,[r(` ═══ 左侧:会话列表(只在「对话」Tab 显示)═══ `),o.activeTab===`chat`?(S(),f(D,{key:0},[v(`aside`,{class:`agent-sidebar`,style:C({width:o.sidebarWidth+`px`})},[r(` 顶部操作栏 `),v(`div`,ot,[v(`button`,{class:`new-session-btn`,onClick:o.handleNewSession},[d(o.ElIcon,null,{default:z(()=>[d(o.Plus)]),_:1}),v(`span`,null,t(o.$t(`@AGENT:新建会话`)),1)])]),r(` 搜索框 `),v(`div`,st,[d(o.ElIcon,{class:`search-icon`},{default:z(()=>[d(o.Search)]),_:1}),k(v(`input`,{"onUpdate:modelValue":n[0]||=e=>o.searchQuery=e,placeholder:o.$t(`@AGENT:搜索会话...`),class:`search-input`,type:`text`},null,8,ct),[[M,o.searchQuery]])]),r(` 会话列表 `),k((S(),f(`div`,lt,[o.filteredSessions.length===0&&!o.sessionsLoading?(S(),f(`div`,ut,[d(o.ElIcon,{size:28,color:`var(--text-tertiary)`},{default:z(()=>[d(o.ChatLineRound)]),_:1}),v(`div`,dt,t(o.searchQuery?o.$t(`@AGENT:未找到匹配的会话`):o.$t(`@AGENT:暂无会话`)),1),o.searchQuery?r(`v-if`,!0):(S(),f(`div`,ft,t(o.$t(`@AGENT:点击上方按钮开始对话`)),1))])):r(`v-if`,!0),(S(!0),f(D,null,g(o.filteredSessions,e=>(S(),f(`div`,{key:e.sessionId,class:L([`session-item`,{active:o.currentSessionId===e.sessionId}]),onClick:t=>o.selectSession(e.sessionId)},[v(`div`,mt,[v(`div`,ht,t(e.title||o.$t(`@AGENT:无标题`)),1),v(`div`,gt,[e.isGenerating?(S(),f(`span`,_t,[d(o.ElIcon,{class:`is-loading`},{default:z(()=>[d(o.Loading)]),_:1}),u(` `+t(o.$t(`@AGENT:正在生成中...`)),1)])):(S(),f(D,{key:1},[v(`span`,vt,t(o.formatDate(e.updatedAt)),1),n[5]||=v(`span`,{class:`meta-dot`},`·`,-1),v(`span`,yt,t(e.messageCount)+` `+t(o.$t(`@AGENT:条`)),1)],64)),e.source===`cli`?(S(),f(`span`,bt,`CLI`)):r(`v-if`,!0)])]),v(`div`,{class:`session-item-actions`,onClick:n[1]||=H(()=>{},[`stop`])},[d(o.ElTooltip,{content:o.$t(`@AGENT:重命名`),placement:`top`,"show-after":500},{default:z(()=>[v(`button`,{class:`item-action-btn`,onClick:t=>o.handleRename(e.sessionId,e.title,t)},[d(o.ElIcon,null,{default:z(()=>[d(o.Edit)]),_:1})],8,xt)]),_:2},1032,[`content`]),d(o.ElTooltip,{content:o.$t(`@AGENT:删除`),placement:`top`,"show-after":500},{default:z(()=>[v(`button`,{class:`item-action-btn danger`,onClick:t=>o.handleDelete(e.sessionId,t)},[d(o.ElIcon,null,{default:z(()=>[d(o.Delete)]),_:1})],8,St)]),_:2},1032,[`content`])])],10,pt))),128))])),[[l,o.sessionsLoading]])],4),r(` 拖拽分隔条 `),v(`div`,{class:L([`sidebar-resizer`,{active:o.isResizing}]),onMousedown:o.startResize},null,34)],64)):r(`v-if`,!0),r(` ═══ 右侧:Tab 栏 + 内容区 ═══ `),v(`main`,Ct,[v(`nav`,wt,[(S(!0),f(D,null,g(o.tabs,e=>(S(),f(`button`,{key:e.id,type:`button`,class:L([`agent-tab`,{active:o.activeTab===e.id}]),role:`tab`,"aria-selected":o.activeTab===e.id,onClick:t=>o.activeTab=e.id},[d(o.ElIcon,null,{default:z(()=>[(S(),a(ie(e.icon)))]),_:2},1024),v(`span`,null,t(e.label),1)],10,Tt))),128))]),v(`div`,Et,[r(` ── 对话 ── `),o.activeTab===`chat`?(S(),f(`div`,Dt,[r(` 加载中 `),o.sessionLoading?(S(),f(`div`,Ot,[d(o.ElIcon,{class:`is-loading`,size:32},{default:z(()=>[d(o.Loading)]),_:1}),v(`span`,null,t(o.$t(`@AGENT:加载会话中...`)),1)])):(S(),f(D,{key:1},[r(` ChatContainer `),d(o.ChatContainer,{ref:`chatContainerRef`,messages:o.messages,"preset-questions":o.presetQuestions,"welcome-title":o.$t(`@AGENT:智能体助手`),"welcome-description":o.$t(`@AGENT:我可以帮你阅读代码、执行命令、修改文件。选择下方话题或直接输入你的问题。`),"assistant-name":`g ai`,theme:o.chatTheme,disabled:o.isStreaming,"upload-config":{accept:`image/*`},placeholder:o.isStreaming?o.$t(`@AGENT:正在生成中...`):o.$t(`@AGENT:输入消息,Enter 发送`),onSend:o.onSend,onSelect:o.onSelectPreset},null,8,[`messages`,`preset-questions`,`welcome-title`,`welcome-description`,`theme`,`disabled`,`placeholder`])],2112)),d(O,{name:`fade`},{default:z(()=>[o.pendingQuestion?(S(),f(`section`,kt,[v(`div`,At,[d(o.ElIcon,null,{default:z(()=>[d(o.ChatLineRound)]),_:1}),v(`span`,null,t(o.$t(`@AGENT:等待你的回答`)),1)]),v(`div`,jt,t(o.pendingQuestion.question),1),o.pendingQuestion.options.length?(S(),f(`div`,Mt,[(S(!0),f(D,null,g(o.pendingQuestion.options,e=>(S(),f(`button`,{key:e,type:`button`,class:`ask-user-option`,disabled:o.answeringQuestion,onClick:t=>o.submitPendingAnswer(e)},[d(o.ElIcon,null,{default:z(()=>[d(o.Check)]),_:1}),v(`span`,null,t(e),1)],8,Nt))),128))])):r(`v-if`,!0),o.pendingQuestion.allowFreeText||o.pendingQuestion.options.length===0?(S(),f(`form`,{key:1,class:`ask-user-form`,onSubmit:n[3]||=H(e=>o.submitPendingAnswer(),[`prevent`])},[k(v(`input`,{"onUpdate:modelValue":n[2]||=e=>o.pendingAnswer=e,type:`text`,disabled:o.answeringQuestion,placeholder:o.$t(`@AGENT:输入回答`),"aria-label":o.$t(`@AGENT:输入回答`)},null,8,Pt),[[M,o.pendingAnswer]]),v(`button`,{type:`submit`,disabled:o.answeringQuestion||!o.pendingAnswer.trim()},[d(o.ElIcon,null,{default:z(()=>[d(o.Check)]),_:1}),v(`span`,null,t(o.$t(`@AGENT:提交回答`)),1)],8,Ft)],32)):r(`v-if`,!0)])):r(`v-if`,!0)]),_:1}),r(` 停止按钮浮层 `),d(O,{name:`fade`},{default:z(()=>[o.isStreaming?(S(),f(`div`,It,[v(`button`,{class:`stop-button`,onClick:n[4]||=(...e)=>o.stop&&o.stop(...e)},[d(o.ElIcon,null,{default:z(()=>[d(o.Loading,{class:`is-loading`})]),_:1}),v(`span`,null,t(o.$t(`@AGENT:停止生成`)),1)])])):r(`v-if`,!0)]),_:1})])):(S(),f(D,{key:1},[r(` ── Skill 广场 / MCP 广场 ── `),d(o.MarketplacePanel,{type:o.marketplaceType},null,8,[`type`])],2112))])])])}var Rt=J(it,[[`render`,Lt],[`__scopeId`,`data-v-bd681ddd`],[`__file`,`D:/workspace/github_workspace/zen-gitsync/src/ui/client/src/views/AgentView.vue`]]);export{Rt as default};
@@ -1 +0,0 @@
1
- .mindmap-view[data-v-b157fbd3]{background:var(--bg-page);flex-direction:column;height:100%;min-height:0;display:flex;overflow:hidden}.mm-toolbar[data-v-b157fbd3]{background:var(--bg-container);border-bottom:1px solid var(--border-color);flex-shrink:0;justify-content:space-between;align-items:center;gap:12px;padding:8px 14px;display:flex}.mm-toolbar-left[data-v-b157fbd3],.mm-toolbar-right[data-v-b157fbd3]{align-items:center;gap:8px;min-width:0;display:flex}.mm-toolbar-left[data-v-b157fbd3]{flex:1}.mm-toolbar-right[data-v-b157fbd3]{flex-shrink:0}.mm-dir-path[data-v-b157fbd3]{color:var(--text-secondary);font-size:12px;font-family:var(--font-mono,monospace);white-space:nowrap;text-overflow:ellipsis;background:var(--bg-subtle);border-radius:var(--radius-sm);flex:1;min-width:0;padding:2px 8px;overflow:hidden}.mm-dir-empty[data-v-b157fbd3]{color:var(--text-tertiary);font-size:12px;font-style:italic}.mm-status[data-v-b157fbd3]{color:var(--text-secondary);align-items:center;gap:4px;margin-left:4px;font-size:12px;display:flex}.mm-status-title[data-v-b157fbd3]{white-space:nowrap;text-overflow:ellipsis;max-width:160px;font-weight:500;overflow:hidden}.mm-status-dirty[data-v-b157fbd3]{color:var(--color-warning);font-size:14px;line-height:1}.mm-body[data-v-b157fbd3]{flex:1;min-height:0;display:flex;overflow:hidden}.mm-sidebar[data-v-b157fbd3]{background:var(--bg-container);border-right:1px solid var(--border-color);flex-direction:column;flex-shrink:0;width:240px;display:flex}.mm-sidebar-header[data-v-b157fbd3]{border-bottom:1px solid var(--border-color);background:var(--bg-panel);justify-content:space-between;align-items:center;padding:8px 12px;display:flex}.mm-sidebar-title[data-v-b157fbd3]{color:var(--text-secondary);letter-spacing:.5px;text-transform:uppercase;font-size:12px;font-weight:600}.mm-sidebar-list[data-v-b157fbd3]{flex:1;min-height:0;padding:4px;overflow-y:auto}.mm-sidebar-empty[data-v-b157fbd3],.mm-sidebar-error[data-v-b157fbd3]{text-align:center;color:var(--text-tertiary);padding:24px 12px;font-size:12px}.mm-sidebar-error[data-v-b157fbd3]{color:var(--color-danger)}.mm-file-item[data-v-b157fbd3]{border-radius:var(--radius-md);cursor:pointer;align-items:center;gap:8px;padding:6px 8px;transition:background .15s;display:flex;position:relative}.mm-file-item[data-v-b157fbd3]:hover{background:var(--bg-hover)}.mm-file-item.active[data-v-b157fbd3]{background:color-mix(in srgb, var(--color-primary) 12%, transparent)}.mm-file-item.active .mm-file-title[data-v-b157fbd3]{color:var(--color-primary);font-weight:600}.mm-file-info[data-v-b157fbd3]{flex-direction:column;flex:1;gap:1px;min-width:0;display:flex}.mm-file-title[data-v-b157fbd3]{color:var(--text-primary);white-space:nowrap;text-overflow:ellipsis;font-size:13px;overflow:hidden}.mm-file-meta[data-v-b157fbd3]{color:var(--text-tertiary);white-space:nowrap;text-overflow:ellipsis;font-size:10.5px;overflow:hidden}.mm-file-actions[data-v-b157fbd3]{opacity:0;align-items:center;gap:2px;transition:opacity .15s;display:flex}.mm-file-item:hover .mm-file-actions[data-v-b157fbd3]{opacity:1}.mm-editor[data-v-b157fbd3]{background:var(--bg-container);flex:1;min-width:0;min-height:0;position:relative}.mm-editor[data-v-b157fbd3] .zm-mindmap,.mm-editor[data-v-b157fbd3]>*{width:100%;height:100%}.mm-editor-empty[data-v-b157fbd3]{color:var(--text-tertiary);flex-direction:column;justify-content:center;align-items:center;gap:8px;display:flex;position:absolute;inset:0}.mm-editor-empty svg[data-v-b157fbd3]{opacity:.4}.mm-editor-empty-title[data-v-b157fbd3]{color:var(--text-secondary);margin:8px 0 0;font-size:16px;font-weight:600}.mm-editor-empty-hint[data-v-b157fbd3]{color:var(--text-tertiary);margin:0;font-size:13px}@media (width<=900px){.mm-sidebar[data-v-b157fbd3]{width:180px}.mm-dir-path[data-v-b157fbd3]{max-width:160px}}
@@ -1,2 +0,0 @@
1
- import"./rolldown-runtime-C0FnF6B9.js";import{$r as e,Dn as t,En as n,Fn as r,Jn as i,Kn as a,L as o,Mn as s,Nn as c,On as l,Pr as u,Qn as d,Rt as f,St as p,Tn as m,Vt as h,Xn as g,a as _,ar as v,bn as y,bt as b,cr as x,ct as S,fr as C,ft as w,i as T,jn as E,mt as D,qr as O,r as k,sr as A,un as j,wn as M,yn as N,yr as P,zn as F}from"./element-plus-CqvO58xa.js";import{h as I,l as L,m as R}from"./vendor-DP-rcIZp.js";import{n as z,t as B}from"./_plugin-vue_export-helper-BsV3BiZm.js";import{n as V,t as H}from"./configStore-Cubt3KDP.js";import{n as U,r as ee}from"./flow-mindmap-Dybg7aXu.js";C(),F();var W=R(`mindmap`,()=>{let e=H(),t=P(e.ui.mindmapDir||``),n=P([]),r=P(null),i=P(!1),a=P(!1),o=P(null),s=P(``),c=M(()=>r.value!==null),l=M(()=>n.value.length);function u(t){e.saveUiSettings({mindmapDir:t})}async function d(e){let r=e??t.value;if(!r){o.value=null,n.value=[];return}a.value=!0,o.value=null;try{let e=await(await fetch(`/api/mindmap/list?dir=${encodeURIComponent(r)}`)).json();e.success?(t.value=e.dir,n.value=e.files||[],u(e.dir)):(o.value=e.error||`读取目录失败`,n.value=[])}catch(e){o.value=e?.message||String(e),n.value=[]}finally{a.value=!1}}async function f(e){await d(e)}async function p(e,t=!1){if(!t&&i.value&&r.value)throw Error(`UNSAVED_CHANGES`);a.value=!0,o.value=null;try{let t=await(await fetch(`/api/mindmap/read?path=${encodeURIComponent(e)}`)).json();t.success?(r.value={path:t.path,title:t.title,content:t.content,mtime:t.mtime},s.value=t.content,i.value=!1):o.value=t.error||`读取文件失败`}catch(e){o.value=e?.message||String(e)}finally{a.value=!1}}async function m(e,n=!1){if(!t.value)throw Error(`未选择目录`);if(!n&&i.value&&r.value)throw Error(`UNSAVED_CHANGES`);a.value=!0,o.value=null;try{let n=await(await fetch(`/api/mindmap/create`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({dir:t.value,name:e})})).json();if(n.success)r.value={path:n.path,title:n.title,content:n.content,mtime:n.mtime},s.value=n.content,i.value=!1,await d();else throw o.value=n.error||`新建失败`,Error(n.error||`新建失败`)}catch(e){throw e.message===`UNSAVED_CHANGES`||(o.value=e?.message||String(e)),e}finally{a.value=!1}}async function h(e){if(!r.value)throw Error(`没有打开的文件`);a.value=!0,o.value=null;try{let t=await(await fetch(`/api/mindmap/save`,{method:`PUT`,headers:{"Content-Type":`application/json`},body:JSON.stringify({path:r.value.path,content:e})})).json();if(t.success)return r.value&&(r.value.content=e,r.value.mtime=t.mtime),s.value=e,i.value=!1,await d(),t;throw o.value=t.error||`保存失败`,Error(t.error||`保存失败`)}catch(e){throw o.value=e?.message||String(e),e}finally{a.value=!1}}async function g(e){let t=await(await fetch(`/api/mindmap/delete`,{method:`DELETE`,headers:{"Content-Type":`application/json`},body:JSON.stringify({path:e})})).json();if(!t.success)throw Error(t.error||`删除失败`);return r.value&&r.value.path===e&&(r.value=null,i.value=!1,s.value=``),await d(),t}async function _(e,t){let n=await(await fetch(`/api/mindmap/rename`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({path:e,newName:t})})).json();if(!n.success)throw Error(n.error||`重命名失败`);return r.value&&e===r.value.path&&(r.value={...r.value,path:n.path,title:t}),await d(),n}function v(){r.value&&(i.value=!0)}function y(){r.value=null,i.value=!1,s.value=``}return{currentDir:t,files:n,current:r,dirty:i,loading:a,error:o,hasCurrent:c,filesCount:l,listFiles:d,setDir:f,openFile:p,createFile:m,saveCurrent:h,deleteFile:g,renameFile:_,markDirty:v,closeCurrent:y}});F(),C();var G=1500,K=r({__name:`MindmapView`,setup(e,{expose:t}){t();let n=W(),r=H(),{currentLocale:o}=I(V()),s=M(()=>{let e=r.theme;return e===`dark`?!0:e===`light`?!1:window.matchMedia?.(`(prefers-color-scheme: dark)`).matches??!1}),c=P(null),l=P(!1);function u(){l.value=!0}function d(e){l.value=!1,e&&e.length>0&&n.setDir(e[0])}async function m(){if(!n.currentDir){T.warning(z(`@MINDMAP:请先选择目录`));return}if(!await C())return;let e=``;try{e=(await k.prompt(z(`@MINDMAP:输入文件名提示`),z(`@MINDMAP:新建思维导图`),{confirmButtonText:z(`@MINDMAP:新建`),cancelButtonText:z(`@MINDMAP:取消`),inputPlaceholder:z(`@MINDMAP:文件名占位`),inputValidator:e=>!e||!e.trim()?z(`@MINDMAP:名称不能为空`):!/[\\/:*?"<>|]/.test(e)||z(`@MINDMAP:名称含非法字符`)})).value.trim()}catch{return}try{await n.createFile(e,!0),T.success(z(`@MINDMAP:已新建并打开`))}catch(e){T.error(e?.message||z(`@MINDMAP:新建失败`))}}async function g(e=!1){if(n.current)try{let t=c.value?.exportData();if(!t){e||T.warning(z(`@MINDMAP:无法获取数据`));return}await n.saveCurrent(t),e||T.success(z(`@MINDMAP:已保存`))}catch(e){T.error(e?.message||z(`@MINDMAP:保存失败`))}}let _=null;function y(){n.current&&n.dirty&&(_&&clearTimeout(_),_=setTimeout(()=>{_=null,n.current&&n.dirty&&g(!0)},G))}function x(){_&&=(clearTimeout(_),null)}async function C(){if(!n.dirty||!n.current)return!0;try{await k.confirm(z(`@MINDMAP:未保存提示`).replace(`{title}`,n.current.title),z(`@MINDMAP:未保存的改动`),{confirmButtonText:z(`@MINDMAP:保存`),cancelButtonText:z(`@MINDMAP:丢弃`),distinguishCancelAndClose:!0,type:`warning`}),x();let e=c.value?.exportData();return e&&(await n.saveCurrent(e),T.success(z(`@MINDMAP:已保存`))),!0}catch(e){return e===`cancel`&&(x(),!0)}}async function E(e){if(!(n.current&&n.current.path===e)&&await C())try{await n.openFile(e,!0)}catch(e){T.error(e?.message||z(`@MINDMAP:打开失败`))}}async function O(e){try{await k.confirm(z(`@MINDMAP:确认删除提示`).replace(`{title}`,e.title),z(`@MINDMAP:删除`),{confirmButtonText:z(`@MINDMAP:删除`),cancelButtonText:z(`@MINDMAP:取消`),type:`warning`})}catch{return}try{await n.deleteFile(e.path),T.success(z(`@MINDMAP:已删除`))}catch(e){T.error(e?.message||z(`@MINDMAP:删除失败`))}}async function A(e){let t=``;try{t=(await k.prompt(z(`@MINDMAP:输入新名称提示`),z(`@MINDMAP:重命名`),{confirmButtonText:z(`@MINDMAP:确定`),cancelButtonText:z(`@MINDMAP:取消`),inputValue:e.title,inputValidator:e=>!e||!e.trim()?z(`@MINDMAP:名称不能为空`):!/[\\/:*?"<>|]/.test(e)||z(`@MINDMAP:名称含非法字符`)})).value.trim()}catch{return}try{await n.renameFile(e.path,t),T.success(z(`@MINDMAP:已重命名`))}catch(e){T.error(e?.message||z(`@MINDMAP:重命名失败`))}}function j(e){n.markDirty(),y()}function N(e){}async function F(){if(!n.currentDir){T.warning(z(`@MINDMAP:请先选择目录`));return}let e=``,t=``;try{e=(await k.prompt(z(`@MINDMAP:粘贴Markdown提示`),z(`@MINDMAP:从Markdown导入`),{confirmButtonText:z(`@MINDMAP:导入`),cancelButtonText:z(`@MINDMAP:取消`),inputType:`textarea`,inputPlaceholder:z(`@MINDMAP:Markdown占位`),inputValidator:e=>!e||!e.trim()?z(`@MINDMAP:内容不能为空`):!0})).value}catch{return}try{t=(await k.prompt(z(`@MINDMAP:输入文件名提示`),z(`@MINDMAP:文件名`),{confirmButtonText:z(`@MINDMAP:新建`),cancelButtonText:z(`@MINDMAP:取消`),inputValidator:e=>!e||!e.trim()?z(`@MINDMAP:名称不能为空`):!/[\\/:*?"<>|]/.test(e)||z(`@MINDMAP:名称含非法字符`)})).value.trim()}catch{return}try{await n.createFile(t,!0);let r=U(e,t),i=JSON.stringify(r,null,2);await n.saveCurrent(i),T.success(z(`@MINDMAP:已导入`))}catch(e){T.error(e?.message||z(`@MINDMAP:导入失败`))}}async function R(){if(c.value)try{let e=c.value.getMarkdown();await navigator.clipboard.writeText(e),T.success(z(`@MINDMAP:已复制Markdown`))}catch(e){T.error(e?.message||z(`@MINDMAP:复制失败`))}}function B(e){(e.ctrlKey||e.metaKey)&&e.key===`s`&&(e.preventDefault(),n.current&&n.dirty&&(x(),g()))}let K=P(0);v(()=>n.current?.path,()=>{K.value++});let q=P(!1);function J(){q.value=!q.value}let Y=M(()=>{let e=n.current?.content;if(!e)return null;try{return JSON.parse(e)}catch{return null}});i(async()=>{window.addEventListener(`keydown`,B),n.currentDir&&await n.listFiles()}),a(()=>{window.removeEventListener(`keydown`,B),x()});function X(e){if(!e)return`-`;let t=new Date(e),n=Date.now()-e;return n<6e4?z(`@MINDMAP:刚刚`):n<36e5?`${Math.floor(n/6e4)}${z(`@MINDMAP:分钟前`)}`:n<864e5?`${Math.floor(n/36e5)}${z(`@MINDMAP:小时前`)}`:`${t.getMonth()+1}/${t.getDate()} ${String(t.getHours()).padStart(2,`0`)}:${String(t.getMinutes()).padStart(2,`0`)}`}function Z(e){return e?e<1024?`${e} B`:e<1048576?`${(e/1024).toFixed(1)} KB`:`${(e/1024/1024).toFixed(1)} MB`:`0 B`}let Q={store:n,configStore:r,currentLocale:o,isDark:s,mmRef:c,filePickerVisible:l,openDirPicker:u,onPickerConfirm:d,handleNewFile:m,handleSave:g,AUTOSAVE_DELAY:G,get autosaveTimer(){return _},set autosaveTimer(e){_=e},scheduleAutosave:y,cancelAutosave:x,confirmDiscardIfDirty:C,handleOpenFile:E,handleDelete:O,handleRename:A,onMindMapChange:j,onMindMapSelect:N,handleImportMarkdown:F,handleExportMarkdown:R,onKeydown:B,mmKey:K,previewMode:q,onCanvasTogglePreview:J,mmData:Y,formatTime:X,formatSize:Z,get $t(){return z},get FolderOpened(){return p},get Plus(){return f},get FolderChecked(){return b},get Delete(){return S},get Edit(){return D},get Refresh(){return h},get Document(){return w},get FilePicker(){return L},get MindMap(){return ee}};return Object.defineProperty(Q,"__isScriptSetup",{enumerable:!1,value:!0}),Q}});F(),u(),j();var q={class:`mindmap-view`},J={class:`mm-toolbar`},Y={class:`mm-toolbar-left`},X=[`title`],Z={key:1,class:`mm-dir-empty`},Q={class:`mm-toolbar-right`},te={key:0,class:`mm-status`},ne=[`title`],re={key:0,class:`mm-status-dirty`},ie={class:`mm-body`},ae={class:`mm-sidebar`},oe={class:`mm-sidebar-header`},se={class:`mm-sidebar-title`},ce={class:`mm-sidebar-list`},le={key:0,class:`mm-sidebar-error`},ue={key:1,class:`mm-sidebar-empty`},de={key:2,class:`mm-sidebar-empty`},fe=[`onClick`],pe={class:`mm-file-info`},$=[`title`],me={class:`mm-file-meta`},he={class:`mm-editor`},ge={key:0,class:`mm-editor-empty`},_e={class:`mm-editor-empty-title`},ve={class:`mm-editor-empty-hint`};function ye(r,i,a,u,f,p){let h=o,v=_;return g(),l(`div`,q,[t(` 顶部工具栏 `),m(`div`,J,[m(`div`,Y,[c(h,{size:`small`,icon:u.FolderOpened,onClick:u.openDirPicker},{default:A(()=>[s(e(u.$t(`@MINDMAP:选择目录`)),1)]),_:1},8,[`icon`]),u.store.currentDir?(g(),l(`span`,{key:0,class:`mm-dir-path`,title:u.store.currentDir},e(u.store.currentDir),9,X)):(g(),l(`span`,Z,e(u.$t(`@MINDMAP:未选择目录`)),1))]),m(`div`,Q,[c(h,{size:`small`,icon:u.Plus,disabled:!u.store.currentDir,onClick:u.handleNewFile},{default:A(()=>[s(e(u.$t(`@MINDMAP:新建`)),1)]),_:1},8,[`icon`,`disabled`]),c(h,{size:`small`,icon:u.Document,disabled:!u.store.currentDir,onClick:u.handleImportMarkdown},{default:A(()=>[s(e(u.$t(`@MINDMAP:从MD导入`)),1)]),_:1},8,[`icon`,`disabled`]),c(h,{size:`small`,icon:u.Edit,disabled:!u.store.current,onClick:u.handleExportMarkdown},{default:A(()=>[s(e(u.$t(`@MINDMAP:复制MD`)),1)]),_:1},8,[`icon`,`disabled`]),c(h,{size:`small`,type:`primary`,icon:u.FolderChecked,disabled:!u.store.current||!u.store.dirty,loading:u.store.loading,onClick:i[0]||=()=>{u.cancelAutosave(),u.handleSave()}},{default:A(()=>[s(e(u.$t(`@MINDMAP:保存`)),1)]),_:1},8,[`icon`,`disabled`,`loading`]),u.store.current?(g(),l(`span`,te,[m(`span`,{class:`mm-status-title`,title:u.store.current.title},e(u.store.current.title),9,ne),u.store.dirty?(g(),l(`span`,re,`●`)):t(`v-if`,!0)])):t(`v-if`,!0)])]),m(`div`,ie,[t(` 左侧文件列表 `),m(`div`,ae,[m(`div`,oe,[m(`span`,se,e(u.$t(`@MINDMAP:文件列表`)),1),c(h,{size:`small`,text:``,icon:u.Refresh,loading:u.store.loading,onClick:i[1]||=e=>u.store.listFiles(),disabled:!u.store.currentDir},null,8,[`icon`,`loading`,`disabled`])]),x((g(),l(`div`,ce,[u.store.error&&!u.store.loading?(g(),l(`div`,le,e(u.store.error),1)):u.store.currentDir?u.store.files.length===0?(g(),l(`div`,de,e(u.$t(`@MINDMAP:暂无思维导图`)),1)):(g(!0),l(y,{key:3},d(u.store.files,t=>(g(),l(`div`,{key:t.path,class:O([`mm-file-item`,{active:u.store.current?.path===t.path}]),onClick:e=>u.handleOpenFile(t.path)},[m(`div`,pe,[m(`div`,{class:`mm-file-title`,title:t.title},e(t.title),9,$),m(`div`,me,e(u.formatTime(t.mtime))+` · `+e(u.formatSize(t.size)),1)]),m(`div`,{class:`mm-file-actions`,onClick:i[2]||=N(()=>{},[`stop`])},[c(h,{size:`small`,text:``,icon:u.Edit,onClick:e=>u.handleRename(t),title:u.$t(`@MINDMAP:重命名`)},null,8,[`icon`,`onClick`,`title`]),c(h,{size:`small`,text:``,type:`danger`,icon:u.Delete,onClick:e=>u.handleDelete(t),title:u.$t(`@MINDMAP:删除`)},null,8,[`icon`,`onClick`,`title`])])],10,fe))),128)):(g(),l(`div`,ue,e(u.$t(`@MINDMAP:请先选择目录`)),1))])),[[v,u.store.loading]])]),t(` 右侧编辑区 `),m(`div`,he,[u.store.current?(g(),n(u.MindMap,{key:u.mmKey,ref:`mmRef`,data:u.mmData,"preview-mode":u.previewMode,onChange:u.onMindMapChange,onSelect:u.onMindMapSelect,onCanvasTogglePreview:u.onCanvasTogglePreview},null,8,[`data`,`preview-mode`])):(g(),l(`div`,ge,[i[4]||=E(`<svg viewBox="0 0 24 24" width="56" height="56" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" data-v-b157fbd3><circle cx="12" cy="12" r="2" data-v-b157fbd3></circle><circle cx="5" cy="5" r="2" data-v-b157fbd3></circle><circle cx="19" cy="5" r="2" data-v-b157fbd3></circle><circle cx="5" cy="19" r="2" data-v-b157fbd3></circle><circle cx="19" cy="19" r="2" data-v-b157fbd3></circle><line x1="10.5" y1="10.5" x2="6.5" y2="6.5" data-v-b157fbd3></line><line x1="13.5" y1="10.5" x2="17.5" y2="6.5" data-v-b157fbd3></line><line x1="10.5" y1="13.5" x2="6.5" y2="17.5" data-v-b157fbd3></line><line x1="13.5" y1="13.5" x2="17.5" y2="17.5" data-v-b157fbd3></line></svg>`,1),m(`p`,_e,e(u.$t(`@MINDMAP:思维导图编辑器`)),1),m(`p`,ve,e(u.store.currentDir?u.$t(`@MINDMAP:从左侧选择或新建`):u.$t(`@MINDMAP:先选择目录提示`)),1)]))])]),t(` 目录选择(local-file-picker) `),t(` 传入当前目录作为 defaultPath:用户改目录时不用每次都从根目录找,
2
- 已选过的话直接定位到上次的位置;无效时 picker 自动回落到用户目录 `),c(u.FilePicker,{visible:u.filePickerVisible,mode:`directory`,theme:u.isDark?`dark`:`light`,locale:u.currentLocale,"default-path":u.store.currentDir||``,onClose:i[3]||=e=>u.filePickerVisible=!1,onConfirm:u.onPickerConfirm},null,8,[`visible`,`theme`,`locale`,`default-path`])])}var be=B(K,[[`render`,ye],[`__scopeId`,`data-v-b157fbd3`],[`__file`,`D:/workspace/github_workspace/zen-gitsync/src/ui/client/src/views/MindmapView.vue`]]);export{be as default};