zen-gitsync 2.18.12 → 2.18.13

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 (79) hide show
  1. package/package.json +1 -1
  2. package/src/cli/ai/agent.js +1385 -1385
  3. package/src/cli/ai/context.js +431 -431
  4. package/src/cli/ai/context.test.js +376 -376
  5. package/src/cli/ai/turn.js +190 -190
  6. package/src/ui/public/assets/AgentView-CuEM6xzC.js +11 -0
  7. package/src/ui/public/assets/AppVersionBadge-BK1Fiv3b.js +2 -0
  8. package/src/ui/public/assets/BranchSelector-avxY_m05.js +1 -0
  9. package/src/ui/public/assets/CommitForm-hThTnoNt.js +14 -0
  10. package/src/ui/public/assets/CommonDialog-zaBdFGFH.js +1 -0
  11. package/src/ui/public/assets/CopySessionButton-CAxaqLQL.js +21 -0
  12. package/src/ui/public/assets/EditorView-iSA2SXJR.js +37 -0
  13. package/src/ui/public/assets/{FlowExecutionViewer-Ce4Q5ia6.js → FlowExecutionViewer-C5ylYV2C.js} +1 -1
  14. package/src/ui/public/assets/FlowOrchestrationWorkspace-CiQ07ZQv.js +21 -0
  15. package/src/ui/public/assets/LogList-Sjb8vmvq.js +7 -0
  16. package/src/ui/public/assets/MindmapView-B5rChFMP.js +2 -0
  17. package/src/ui/public/assets/MonitorView-Dcc-i2Fo.js +3 -0
  18. package/src/ui/public/assets/ProjectStartupButton-fz6eLCZU.js +1 -0
  19. package/src/ui/public/assets/RecentDirectoriesChat-BDnNp9jh.js +3 -0
  20. package/src/ui/public/assets/RemoteManagerDialog-NA1jRC7O.js +4 -0
  21. package/src/ui/public/assets/RemoteRepoCard-CKm4KqHs.js +7 -0
  22. package/src/ui/public/assets/SourceMapView-Drfato_u.js +3 -0
  23. package/src/ui/public/assets/SvgIcon-DR_79iBR.js +1 -0
  24. package/src/ui/public/assets/UserInputNode-DroKvDOa.js +1 -0
  25. package/src/ui/public/assets/WorkbenchView-CW7OACCU.js +326 -0
  26. package/src/ui/public/assets/{WorkbenchView-DzBtCzay.css → WorkbenchView-C_u6BptZ.css} +1 -1
  27. package/src/ui/public/assets/{_plugin-vue_export-helper-BY0jlMBE.js → _plugin-vue_export-helper-bQQyMRS6.js} +5 -5
  28. package/src/ui/public/assets/{agentConversations-CC01a7SP.js → agentConversations-wYAksLq1.js} +8 -8
  29. package/src/ui/public/assets/{configStore-EvRYufor.js → configStore-BeHB-gV4.js} +1 -1
  30. package/src/ui/public/assets/{css.worker-BDCmgL4U.js → css.worker-DFdt6_zu.js} +9 -9
  31. package/src/ui/public/assets/{dagre-Ct-SQ-7k.js → dagre-CXi8gaG9.js} +4 -4
  32. package/src/ui/public/assets/editor.worker-O-CH8JUO.js +26 -0
  33. package/src/ui/public/assets/{element-plus-D-6gla1z.css → element-plus-DJ3ZQa98.css} +1 -1
  34. package/src/ui/public/assets/element-plus-DgSY_Wt4.js +48 -0
  35. package/src/ui/public/assets/{flow-mindmap-C8x6ucsA.js → flow-mindmap-BsTRkgat.js} +56 -56
  36. package/src/ui/public/assets/{html.worker-DG8hnSJR.js → html.worker-JUzsMP-j.js} +8 -8
  37. package/src/ui/public/assets/index-BRQstBzy.js +211 -0
  38. package/src/ui/public/assets/json.worker-B4dEhy0e.js +58 -0
  39. package/src/ui/public/assets/{monaco-BV4P06MT.js → monaco-CnWeufxc.js} +6 -6
  40. package/src/ui/public/assets/{office-docx-B8BoOvth.js → office-docx-EUfAIM4w.js} +6 -6
  41. package/src/ui/public/assets/{office-excel-CFRkxKv8.js → office-excel-BZW0bXQo.js} +1 -1
  42. package/src/ui/public/assets/{office-pptx-DXdbDvLM.js → office-pptx-CBvDNZ4m.js} +3 -3
  43. package/src/ui/public/assets/{ts.worker-DgFMIcEs.js → ts.worker-CmEKzkmF.js} +49 -49
  44. package/src/ui/public/assets/{useOrchestrator-C8BD2JSO.js → useOrchestrator-Bhl7DGKW.js} +1 -1
  45. package/src/ui/public/assets/{vendor-DYtaPSUU.js → vendor-CZlKgriV.js} +43 -43
  46. package/src/ui/public/assets/vue-flow-DawpR_uk.js +39 -0
  47. package/src/ui/public/index.html +12 -12
  48. package/src/ui/server/routes/config.js +1348 -1348
  49. package/src/ui/server/routes/workbench/agentChat.js +752 -752
  50. package/src/ui/server/routes/workbench/agentChatShared.test.js +496 -496
  51. package/src/ui/server/routes/workbench/agentRoutes.js +13 -1
  52. package/src/ui/server/routes/workbench/agentRoutes.test.js +75 -0
  53. package/src/ui/server/routes/workbench/index.js +2 -1
  54. package/src/ui/server/routes/workbench/scheduleRoutes.js +2 -2
  55. package/src/ui/server/routes/workbench/shared.js +17 -0
  56. package/src/ui/public/assets/AgentView-CVbcrngz.js +0 -11
  57. package/src/ui/public/assets/AppVersionBadge-7gFB6t_t.js +0 -2
  58. package/src/ui/public/assets/BranchSelector-BIRNxA6U.js +0 -1
  59. package/src/ui/public/assets/CommitForm-CWpaazi7.js +0 -14
  60. package/src/ui/public/assets/CommonDialog-DrxsmpDL.js +0 -1
  61. package/src/ui/public/assets/CopySessionButton-C_01fcd3.js +0 -21
  62. package/src/ui/public/assets/EditorView-D80wG480.js +0 -37
  63. package/src/ui/public/assets/FlowOrchestrationWorkspace-Cq1zEt5K.js +0 -21
  64. package/src/ui/public/assets/LogList-DtmJG27U.js +0 -7
  65. package/src/ui/public/assets/MindmapView-BR2_C4Du.js +0 -2
  66. package/src/ui/public/assets/MonitorView-Cs_kwPBu.js +0 -3
  67. package/src/ui/public/assets/ProjectStartupButton-BfQJ0i5X.js +0 -1
  68. package/src/ui/public/assets/RecentDirectoriesChat-_gNQGqkM.js +0 -3
  69. package/src/ui/public/assets/RemoteManagerDialog-KY5I3Ftv.js +0 -4
  70. package/src/ui/public/assets/RemoteRepoCard-BUgdGtwC.js +0 -7
  71. package/src/ui/public/assets/SourceMapView-RkGgdvnN.js +0 -3
  72. package/src/ui/public/assets/SvgIcon-CP7WAT4C.js +0 -1
  73. package/src/ui/public/assets/UserInputNode-CwSqPh4O.js +0 -1
  74. package/src/ui/public/assets/WorkbenchView-CBfccRIP.js +0 -320
  75. package/src/ui/public/assets/editor.worker-GCPm6rMv.js +0 -26
  76. package/src/ui/public/assets/element-plus-CDrtgG55.js +0 -48
  77. package/src/ui/public/assets/index-CyEcaEC9.js +0 -211
  78. package/src/ui/public/assets/json.worker-CxwlJRnL.js +0 -58
  79. package/src/ui/public/assets/vue-flow-B7Hdmt-y.js +0 -39
@@ -1,190 +1,190 @@
1
- import { executeTool, splitToolOutput, toolMessageContent } from './tools.js'
2
- import { streamChatOnce } from './transport.js'
3
- import { createThinkFilter } from './streamFilter.js'
4
- import { imageToDataUrl } from './images.js'
5
- import { prepareRequestMessages } from './context.js'
6
- import { createTurnStats, addUsage, accumulateSessionStats } from './telemetry.js'
7
- import { recordTurnTiming } from './sessionStore.js'
8
- import * as terminal from './termui.js'
9
-
10
- // 「等人」型工具:执行期间会接管输入行、停下来等用户作答(目前只有 ask_user)。
11
- // 这类工具不能转工具 spinner —— ora 每 80ms 在同一行 clearLine + 重绘,会把
12
- // readline 刚画出的提示符(「请输入序号或直接输入回答:」)连同用户正在敲的字
13
- // 一起清掉,屏幕上只剩下一个不断跳秒数的「执行 ask_user...」,看起来就像"选不了"。
14
- // 它自己的交互界面(问题 + 编号选项 + 提示符)就是进度提示,不需要再叠一层。
15
- const INTERACTIVE_TOOLS = new Set(['ask_user'])
16
-
17
- export async function runAgentTurn(state, userText, t, images = [], dependencies = {}) {
18
- const chat = dependencies.chat || streamChatOnce
19
- const baseExecute = dependencies.execute || executeTool
20
- // 扩展(目前是 MCP)工具按名字分流:名字属于扩展就走扩展,否则回落内置工具。
21
- // 必须先用 owns() 判断 —— 不能把所有调用都先喂给扩展再靠 null 回落,
22
- // 那样每个内置工具都会多绕一层,而且扩展端也无法假设"进来的都是自己的"。
23
- // 没装扩展时 owns() 恒为 false,等价于直接调内置工具,零开销。
24
- const extensions = dependencies.extensions || state.extensions
25
- const execute = extensions
26
- ? async (name, args, ctx) => {
27
- if (extensions.owns?.(name)) {
28
- const output = await extensions.execute(name, args, ctx)
29
- if (output !== null && output !== undefined) return output
30
- }
31
- return baseExecute(name, args, ctx)
32
- }
33
- : baseExecute
34
- const ui = { ...terminal, ...dependencies.ui }
35
- const stats = createTurnStats()
36
- const started = performance.now()
37
- const cancelled = () => state.cancelRequested || state.abortController?.signal.aborted
38
- const checkpoint = () => state.persistSession?.()
39
- const recordUsage = usage => {
40
- if (!usage) return
41
- stats.usageRequests++
42
- stats.usage = addUsage(stats.usage, usage)
43
- }
44
- // 本轮是第几轮(0 基 user 序号),供 finally 里记用时用。
45
- // 声明在 try 外面:finally 看不到 try 块里的 const,而 -1 正好是"这轮没轮到记"的哨兵值
46
- let turnIndex = -1
47
- try {
48
- let userContent = userText
49
- if (images.length) {
50
- userContent = [{ type: 'text', text: userText }]
51
- for (const img of images) {
52
- try { userContent.push({ type: 'image_url', image_url: { url: await imageToDataUrl(img.path) } }) }
53
- catch { ui.printWarn(t.imageBadPath(img.path)) }
54
- }
55
- }
56
- // 本轮用时记录要对齐到"第几条 user 消息",序号得在这条消息入栈之前取
57
- // (与 Web 侧 agentRoutes.js 同一口径,见 sessionStore.js 的 recordTurnTiming)
58
- turnIndex = state.messages.filter(m => m?.role === 'user').length
59
- state.messages.push({ role: 'user', content: userContent })
60
- await checkpoint()
61
-
62
- // 兜底只在 state.maxToolIterations 缺失/非正数时生效,正常路径由 loadConfig 规范化后传入。
63
- // 默认值与 config.js 的 aiMaxToolIterations 保持一致(1000),别让两处悄悄分叉。
64
- const maxIterations = state.maxToolIterations > 0 ? state.maxToolIterations : 1000
65
- for (let iter = 0; iter < maxIterations; iter++) {
66
- if (cancelled()) { stats.status = 'cancelled'; return stats }
67
- const spinner = ui.startSpinner(t.waiting)
68
- // 一次请求可能被传输层自动重试多次(长静默 / 网关 5xx / 流中断)。
69
- // 每次尝试都换一套 writer + filter:终端没法把已经打出去的字擦掉,
70
- // 与其让两次尝试的输出拼在一起,不如把上一截收尾、重开一块新的(中间一行重试提示)。
71
- const makeWriter = () => ui.createAssistantWriter({
72
- showThinking: state.showThinking !== false,
73
- thinkingHeader: t.thinkingLabel,
74
- answerHeader: t.answerLabel,
75
- thinkingLimit: state.thinkingMode === 'compact' ? terminal.THINKING_PREVIEW_LINES : Infinity,
76
- thinkingHint: t.thinkingHint,
77
- })
78
- let writer = makeWriter()
79
- let filter = createThinkFilter()
80
- const render = seg => {
81
- if (seg.content) {
82
- if (seg.content.trim() && stats.firstAnswerMs === null) stats.firstAnswerMs = performance.now() - started
83
- writer.writeContent(seg.content)
84
- } else if (seg.thinking) writer.writeThinking(seg.thinking)
85
- }
86
- let result
87
- const llmStart = performance.now()
88
- stats.requests++
89
- try {
90
- // 统一入口(与 Web 智能体面板共用):有界化 + 旧图片降级 + 消毒,只作用于请求副本,
91
- // 磁盘上的完整会话记录不受影响。
92
- // 预算来自 state.requestBudget(agent.js 按全局配置 aiMaxRequestTokens 解析);
93
- // 缺失时 prepareRequestMessages 各自兜底默认值,老调用方不用改。
94
- const messages = prepareRequestMessages(state.messages, { locale: state.locale, ...(state.requestBudget || {}) })
95
- result = await chat({ model: state.model, messages, signal: state.abortController?.signal,
96
- sessionId: state.sessionId, extraTools: extensions?.tools,
97
- onRetry: info => {
98
- filter.flush().forEach(render)
99
- writer.finish()
100
- ui.printWarn(t.llmRetrying(info.attempt, info.maxRetries, info.error?.message || ''))
101
- writer = makeWriter()
102
- filter = createThinkFilter()
103
- // 重试是一次**真的**请求,计入本轮请求数(/stats 里那个"请求数"要能对得上网关账单)
104
- stats.requests++
105
- stats.retries++
106
- },
107
- onToken: token => {
108
- if (stats.firstTokenMs === null) stats.firstTokenMs = performance.now() - started
109
- if (token.content || (token.thinking && state.showThinking !== false)) spinner.stop()
110
- if (token.thinking) render({ thinking: token.thinking })
111
- if (token.content) filter.feed(token.content).forEach(render)
112
- } })
113
- recordUsage(result.usage)
114
- } catch (err) {
115
- recordUsage(err.usage)
116
- throw err
117
- } finally {
118
- stats.llmMs += performance.now() - llmStart
119
- spinner.stop()
120
- filter.flush().forEach(render)
121
- writer.finish()
122
- }
123
- if (result.aborted || cancelled()) {
124
- if (result.content) state.messages.push({ role: 'assistant', content: result.content })
125
- stats.status = 'cancelled'; return stats
126
- }
127
- const { content, toolCalls } = result
128
- const assistant = { role: 'assistant', content: content || null }
129
- if (result.reasoning) assistant.reasoning_content = result.reasoning
130
- if (!toolCalls.length) {
131
- if (!content?.trim()) throw new Error(t.emptyResponse)
132
- state.messages.push(assistant)
133
- stats.status = 'completed'; return stats
134
- }
135
- // Assign fallback IDs once, so every result references its assistant call.
136
- toolCalls.forEach((call, i) => { if (!call.id) call.id = `call_${iter}_${i}` })
137
- state.messages.push({ ...assistant, tool_calls: toolCalls })
138
- await checkpoint()
139
- for (const tc of toolCalls) {
140
- const name = tc.function?.name || ''
141
- let output
142
- let args
143
- let toolMs // 只有真执行过的工具才有耗时(见下面的渲染判断)
144
- if (cancelled()) {
145
- // 与改动前一致:取消的这次调用只入历史,不渲染结果块
146
- output = 'Cancelled by user; this tool was not executed.'
147
- } else {
148
- try { args = JSON.parse(tc.function?.arguments || '{}') }
149
- catch { output = '错误: 工具参数不是合法 JSON,请修正后重试。' }
150
- if (output === undefined) {
151
- ui.printToolHeader(name, ui.summarizeToolArgs(name, args, { chars: t.chars }), undefined, { locale: state.locale })
152
- const toolSpinner = INTERACTIVE_TOOLS.has(name) ? null : ui.startSpinner(t.toolRunning(name))
153
- const toolStart = performance.now()
154
- stats.toolCalls++
155
- try { output = await execute(name, args, { ...state.ctx, signal: state.abortController?.signal }) }
156
- finally { toolSpinner?.stop(); toolMs = performance.now() - toolStart; stats.toolsMs += toolMs }
157
- } else {
158
- ui.printToolResult(output)
159
- }
160
- }
161
- // 工具结果可能是多模态的(read_image)。渲染层和回灌的消息都只吃**文本部分**,
162
- // 图片要进 content 数组 —— 拆在最后统一做,免得上面每个分支各写一遍。
163
- const { text: outText, images: outImages } = splitToolOutput(output)
164
- if (toolMs !== undefined) {
165
- ui.printToolResult(outText, undefined, toolMs, { full: state.fullTools, locale: state.locale })
166
- // 工具级的收尾渲染(目前只有 update_plan 画计划清单)。
167
- // 走钩子而不是在这里写 if (name === 'x'):再加工具时这一行不用动。
168
- ui.afterTool?.(name, args, outText, { locale: state.locale })
169
- }
170
- state.messages.push({ role: 'tool', tool_call_id: tc.id, name, content: toolMessageContent(outText, outImages) })
171
- await checkpoint()
172
- }
173
- }
174
- stats.status = cancelled() ? 'cancelled' : 'limit'
175
- if (!cancelled()) ui.printWarn(t.toolIterLimit(maxIterations))
176
- } catch (err) {
177
- stats.status = cancelled() ? 'cancelled' : 'failed'
178
- if (!cancelled()) ui.printError(t.llmError(err.message))
179
- } finally {
180
- stats.totalMs = performance.now() - started
181
- stats.completedAt = new Date().toISOString()
182
- state.lastTurnStats = stats
183
- state.sessionStats = accumulateSessionStats(state.sessionStats, stats)
184
- // 界面读的是这条(Web 端 g ai 对话列表里也能看到 CLI 会话的每轮用时)
185
- recordTurnTiming(state, { turnIndex, durationMs: stats.totalMs, finishedAt: stats.completedAt })
186
- await checkpoint()
187
- ui.printTurnSummary(stats, { locale: state.locale })
188
- }
189
- return stats
190
- }
1
+ import { executeTool, splitToolOutput, toolMessageContent } from './tools.js'
2
+ import { streamChatOnce } from './transport.js'
3
+ import { createThinkFilter } from './streamFilter.js'
4
+ import { imageToDataUrl } from './images.js'
5
+ import { prepareRequestMessages } from './context.js'
6
+ import { createTurnStats, addUsage, accumulateSessionStats } from './telemetry.js'
7
+ import { recordTurnTiming } from './sessionStore.js'
8
+ import * as terminal from './termui.js'
9
+
10
+ // 「等人」型工具:执行期间会接管输入行、停下来等用户作答(目前只有 ask_user)。
11
+ // 这类工具不能转工具 spinner —— ora 每 80ms 在同一行 clearLine + 重绘,会把
12
+ // readline 刚画出的提示符(「请输入序号或直接输入回答:」)连同用户正在敲的字
13
+ // 一起清掉,屏幕上只剩下一个不断跳秒数的「执行 ask_user...」,看起来就像"选不了"。
14
+ // 它自己的交互界面(问题 + 编号选项 + 提示符)就是进度提示,不需要再叠一层。
15
+ const INTERACTIVE_TOOLS = new Set(['ask_user'])
16
+
17
+ export async function runAgentTurn(state, userText, t, images = [], dependencies = {}) {
18
+ const chat = dependencies.chat || streamChatOnce
19
+ const baseExecute = dependencies.execute || executeTool
20
+ // 扩展(目前是 MCP)工具按名字分流:名字属于扩展就走扩展,否则回落内置工具。
21
+ // 必须先用 owns() 判断 —— 不能把所有调用都先喂给扩展再靠 null 回落,
22
+ // 那样每个内置工具都会多绕一层,而且扩展端也无法假设"进来的都是自己的"。
23
+ // 没装扩展时 owns() 恒为 false,等价于直接调内置工具,零开销。
24
+ const extensions = dependencies.extensions || state.extensions
25
+ const execute = extensions
26
+ ? async (name, args, ctx) => {
27
+ if (extensions.owns?.(name)) {
28
+ const output = await extensions.execute(name, args, ctx)
29
+ if (output !== null && output !== undefined) return output
30
+ }
31
+ return baseExecute(name, args, ctx)
32
+ }
33
+ : baseExecute
34
+ const ui = { ...terminal, ...dependencies.ui }
35
+ const stats = createTurnStats()
36
+ const started = performance.now()
37
+ const cancelled = () => state.cancelRequested || state.abortController?.signal.aborted
38
+ const checkpoint = () => state.persistSession?.()
39
+ const recordUsage = usage => {
40
+ if (!usage) return
41
+ stats.usageRequests++
42
+ stats.usage = addUsage(stats.usage, usage)
43
+ }
44
+ // 本轮是第几轮(0 基 user 序号),供 finally 里记用时用。
45
+ // 声明在 try 外面:finally 看不到 try 块里的 const,而 -1 正好是"这轮没轮到记"的哨兵值
46
+ let turnIndex = -1
47
+ try {
48
+ let userContent = userText
49
+ if (images.length) {
50
+ userContent = [{ type: 'text', text: userText }]
51
+ for (const img of images) {
52
+ try { userContent.push({ type: 'image_url', image_url: { url: await imageToDataUrl(img.path) } }) }
53
+ catch { ui.printWarn(t.imageBadPath(img.path)) }
54
+ }
55
+ }
56
+ // 本轮用时记录要对齐到"第几条 user 消息",序号得在这条消息入栈之前取
57
+ // (与 Web 侧 agentRoutes.js 同一口径,见 sessionStore.js 的 recordTurnTiming)
58
+ turnIndex = state.messages.filter(m => m?.role === 'user').length
59
+ state.messages.push({ role: 'user', content: userContent })
60
+ await checkpoint()
61
+
62
+ // 兜底只在 state.maxToolIterations 缺失/非正数时生效,正常路径由 loadConfig 规范化后传入。
63
+ // 默认值与 config.js 的 aiMaxToolIterations 保持一致(1000),别让两处悄悄分叉。
64
+ const maxIterations = state.maxToolIterations > 0 ? state.maxToolIterations : 1000
65
+ for (let iter = 0; iter < maxIterations; iter++) {
66
+ if (cancelled()) { stats.status = 'cancelled'; return stats }
67
+ const spinner = ui.startSpinner(t.waiting)
68
+ // 一次请求可能被传输层自动重试多次(长静默 / 网关 5xx / 流中断)。
69
+ // 每次尝试都换一套 writer + filter:终端没法把已经打出去的字擦掉,
70
+ // 与其让两次尝试的输出拼在一起,不如把上一截收尾、重开一块新的(中间一行重试提示)。
71
+ const makeWriter = () => ui.createAssistantWriter({
72
+ showThinking: state.showThinking !== false,
73
+ thinkingHeader: t.thinkingLabel,
74
+ answerHeader: t.answerLabel,
75
+ thinkingLimit: state.thinkingMode === 'compact' ? terminal.THINKING_PREVIEW_LINES : Infinity,
76
+ thinkingHint: t.thinkingHint,
77
+ })
78
+ let writer = makeWriter()
79
+ let filter = createThinkFilter()
80
+ const render = seg => {
81
+ if (seg.content) {
82
+ if (seg.content.trim() && stats.firstAnswerMs === null) stats.firstAnswerMs = performance.now() - started
83
+ writer.writeContent(seg.content)
84
+ } else if (seg.thinking) writer.writeThinking(seg.thinking)
85
+ }
86
+ let result
87
+ const llmStart = performance.now()
88
+ stats.requests++
89
+ try {
90
+ // 统一入口(与 Web 智能体面板共用):有界化 + 旧图片降级 + 消毒,只作用于请求副本,
91
+ // 磁盘上的完整会话记录不受影响。
92
+ // 预算来自 state.requestBudget(agent.js 按全局配置 aiMaxRequestTokens 解析);
93
+ // 缺失时 prepareRequestMessages 各自兜底默认值,老调用方不用改。
94
+ const messages = prepareRequestMessages(state.messages, { locale: state.locale, ...(state.requestBudget || {}) })
95
+ result = await chat({ model: state.model, messages, signal: state.abortController?.signal,
96
+ sessionId: state.sessionId, extraTools: extensions?.tools,
97
+ onRetry: info => {
98
+ filter.flush().forEach(render)
99
+ writer.finish()
100
+ ui.printWarn(t.llmRetrying(info.attempt, info.maxRetries, info.error?.message || ''))
101
+ writer = makeWriter()
102
+ filter = createThinkFilter()
103
+ // 重试是一次**真的**请求,计入本轮请求数(/stats 里那个"请求数"要能对得上网关账单)
104
+ stats.requests++
105
+ stats.retries++
106
+ },
107
+ onToken: token => {
108
+ if (stats.firstTokenMs === null) stats.firstTokenMs = performance.now() - started
109
+ if (token.content || (token.thinking && state.showThinking !== false)) spinner.stop()
110
+ if (token.thinking) render({ thinking: token.thinking })
111
+ if (token.content) filter.feed(token.content).forEach(render)
112
+ } })
113
+ recordUsage(result.usage)
114
+ } catch (err) {
115
+ recordUsage(err.usage)
116
+ throw err
117
+ } finally {
118
+ stats.llmMs += performance.now() - llmStart
119
+ spinner.stop()
120
+ filter.flush().forEach(render)
121
+ writer.finish()
122
+ }
123
+ if (result.aborted || cancelled()) {
124
+ if (result.content) state.messages.push({ role: 'assistant', content: result.content })
125
+ stats.status = 'cancelled'; return stats
126
+ }
127
+ const { content, toolCalls } = result
128
+ const assistant = { role: 'assistant', content: content || null }
129
+ if (result.reasoning) assistant.reasoning_content = result.reasoning
130
+ if (!toolCalls.length) {
131
+ if (!content?.trim()) throw new Error(t.emptyResponse)
132
+ state.messages.push(assistant)
133
+ stats.status = 'completed'; return stats
134
+ }
135
+ // Assign fallback IDs once, so every result references its assistant call.
136
+ toolCalls.forEach((call, i) => { if (!call.id) call.id = `call_${iter}_${i}` })
137
+ state.messages.push({ ...assistant, tool_calls: toolCalls })
138
+ await checkpoint()
139
+ for (const tc of toolCalls) {
140
+ const name = tc.function?.name || ''
141
+ let output
142
+ let args
143
+ let toolMs // 只有真执行过的工具才有耗时(见下面的渲染判断)
144
+ if (cancelled()) {
145
+ // 与改动前一致:取消的这次调用只入历史,不渲染结果块
146
+ output = 'Cancelled by user; this tool was not executed.'
147
+ } else {
148
+ try { args = JSON.parse(tc.function?.arguments || '{}') }
149
+ catch { output = '错误: 工具参数不是合法 JSON,请修正后重试。' }
150
+ if (output === undefined) {
151
+ ui.printToolHeader(name, ui.summarizeToolArgs(name, args, { chars: t.chars }), undefined, { locale: state.locale })
152
+ const toolSpinner = INTERACTIVE_TOOLS.has(name) ? null : ui.startSpinner(t.toolRunning(name))
153
+ const toolStart = performance.now()
154
+ stats.toolCalls++
155
+ try { output = await execute(name, args, { ...state.ctx, signal: state.abortController?.signal }) }
156
+ finally { toolSpinner?.stop(); toolMs = performance.now() - toolStart; stats.toolsMs += toolMs }
157
+ } else {
158
+ ui.printToolResult(output)
159
+ }
160
+ }
161
+ // 工具结果可能是多模态的(read_image)。渲染层和回灌的消息都只吃**文本部分**,
162
+ // 图片要进 content 数组 —— 拆在最后统一做,免得上面每个分支各写一遍。
163
+ const { text: outText, images: outImages } = splitToolOutput(output)
164
+ if (toolMs !== undefined) {
165
+ ui.printToolResult(outText, undefined, toolMs, { full: state.fullTools, locale: state.locale })
166
+ // 工具级的收尾渲染(目前只有 update_plan 画计划清单)。
167
+ // 走钩子而不是在这里写 if (name === 'x'):再加工具时这一行不用动。
168
+ ui.afterTool?.(name, args, outText, { locale: state.locale })
169
+ }
170
+ state.messages.push({ role: 'tool', tool_call_id: tc.id, name, content: toolMessageContent(outText, outImages) })
171
+ await checkpoint()
172
+ }
173
+ }
174
+ stats.status = cancelled() ? 'cancelled' : 'limit'
175
+ if (!cancelled()) ui.printWarn(t.toolIterLimit(maxIterations))
176
+ } catch (err) {
177
+ stats.status = cancelled() ? 'cancelled' : 'failed'
178
+ if (!cancelled()) ui.printError(t.llmError(err.message))
179
+ } finally {
180
+ stats.totalMs = performance.now() - started
181
+ stats.completedAt = new Date().toISOString()
182
+ state.lastTurnStats = stats
183
+ state.sessionStats = accumulateSessionStats(state.sessionStats, stats)
184
+ // 界面读的是这条(Web 端 g ai 对话列表里也能看到 CLI 会话的每轮用时)
185
+ recordTurnTiming(state, { turnIndex, durationMs: stats.totalMs, finishedAt: stats.completedAt })
186
+ await checkpoint()
187
+ ui.printTurnSummary(stats, { locale: state.locale })
188
+ }
189
+ return stats
190
+ }
@@ -0,0 +1,11 @@
1
+ import"./rolldown-runtime-C0FnF6B9.js";import{$n as e,An as t,At as n,Cn as r,Ct as i,Dn as a,Fn as o,Hn as s,In as c,J as l,Kn as u,Kt as d,Lr as f,M as p,On as m,Qr as h,Rn as g,Sr as _,Tt as v,Ut as y,W as b,Xr as x,Xt as S,Yn as C,Yt as w,Zn as T,_n as E,a as D,br as O,cr as k,dr as A,en as ee,et as j,fn as M,hn as N,hr as P,i as F,ir as I,j as L,jn as R,kn as z,kt as B,lt as te,mt as ne,ni as V,o as re,on as ie,st as ae,tr as H,tt as oe,ur as U,vn as W,yn as G}from"./element-plus-DgSY_Wt4.js";import{c as se,t as ce}from"./vendor-CZlKgriV.js";import{n as K,t as q}from"./_plugin-vue_export-helper-bQQyMRS6.js";import{t as le}from"./configStore-BeHB-gV4.js";import{t as ue}from"./CommonDialog-zaBdFGFH.js";import{J as de,b as fe,q as pe}from"./index-BRQstBzy.js";import{a as me,c as he,i as ge,l as _e,m as ve,n as ye,o as be,r as xe,s as Se,t as Ce,u as we}from"./agentConversations-wYAksLq1.js";import{l as Te,s as Ee,t as De,u as Oe}from"./CopySessionButton-CAxaqLQL.js";import{t as ke}from"./useOrchestrator-Bhl7DGKW.js";async function J(e,t){let n=await fetch(e,{headers:{"Content-Type":`application/json`},...t}),r={};try{r=await n.json()}catch{}if(!n.ok||r.success===!1)throw Error(r.error||`请求失败 (${n.status})`);return r}async function Ae(){let e=await J(`/api/schedules`);return Array.isArray(e.tasks)?e.tasks:[]}async function je(e){return(await J(`/api/schedules`,{method:`POST`,body:JSON.stringify(e)})).task}async function Me(e,t){return(await J(`/api/schedules/${encodeURIComponent(e)}`,{method:`PUT`,body:JSON.stringify(t)})).task}async function Ne(e){await J(`/api/schedules/${encodeURIComponent(e)}`,{method:`DELETE`})}async function Y(e){await J(`/api/schedules/${encodeURIComponent(e)}/run`,{method:`POST`})}async function Pe(e){await J(`/api/schedules/${encodeURIComponent(e)}/stop`,{method:`POST`})}function Fe(e){if(typeof EventSource>`u`)return()=>{};let t=new EventSource(`/api/schedules/events`);return t.onmessage=t=>{try{e(JSON.parse(t.data))}catch{}},()=>t.close()}var X=e=>/^\d+$/.test(e)?Number(e):null;function Ie(e){let t=String(e||``).trim(),n=t.split(/\s+/);if(n.length!==5)return{kind:`custom`,raw:t};let[r,i,a,o,s]=n,c=X(r),l=X(i);if(t===`* * * * *`)return{kind:`every-minute`,raw:t};let u=r.match(/^\*\/(\d+)$/);if(u&&i===`*`&&a===`*`&&o===`*`&&s===`*`)return{kind:`every-n-minutes`,n:Number(u[1]),raw:t};if(c!==null&&i===`*`&&a===`*`&&o===`*`&&s===`*`)return{kind:`hourly`,minute:c,raw:t};if(c!==null&&l!==null&&a===`*`&&o===`*`&&s===`*`)return{kind:`daily`,hour:l,minute:c,raw:t};let d=X(s);if(c!==null&&l!==null&&a===`*`&&o===`*`&&d!==null)return{kind:`weekly`,weekday:d%7,hour:l,minute:c,raw:t};let f=X(a);return c!==null&&l!==null&&f!==null&&o===`*`&&s===`*`?{kind:`monthly`,day:f,hour:l,minute:c,raw:t}:{kind:`custom`,raw:t}}var Z=e=>String(e).padStart(2,`0`),Q=e=>new Date(e.getFullYear(),e.getMonth(),e.getDate()).getTime();function Le(e,t=new Date){if(!e)return{kind:`none`};let n=new Date(e);if(Number.isNaN(n.getTime()))return{kind:`none`};let r=`${Z(n.getHours())}:${Z(n.getMinutes())}`,i=Math.round((Q(n)-Q(t))/864e5);return i<0?{kind:`date`,date:`${n.getMonth()+1}-${Z(n.getDate())}`,time:r}:i===0?{kind:`today`,time:r}:i===1?{kind:`tomorrow`,time:r}:i<7?{kind:`weekday`,weekday:n.getDay(),time:r}:{kind:`date`,date:`${n.getMonth()+1}-${Z(n.getDate())}`,time:r}}function Re(e){switch(e){case`ok`:return`ok`;case`error`:case`timed-out`:return`error`;case`skipped-busy`:case`missed`:case`cancelled`:return`skipped`;default:return`pending`}}function ze(e){let t=Number(e);if(!Number.isFinite(t)||t<0)return``;if(t<1e3)return`<1s`;let n=Math.round(t/1e3);if(n<60)return`${n}s`;let r=Math.floor(n/60);return r<60?`${r}m${Z(n%60)}s`:`${Math.floor(r/60)}h${Z(r%60)}m`}function $(e){let t=Math.min(59,Math.max(0,Math.floor(e.minute))),n=Math.min(23,Math.max(0,Math.floor(e.hour))),r=(Math.floor(e.weekday)%7+7)%7;switch(e.freq){case`minutes`:return`*/${Math.min(59,Math.max(1,Math.floor(e.everyMinutes??30)))} * * * *`;case`hourly`:return`${t} * * * *`;case`daily`:return`${t} ${n} * * *`;case`weekly`:return`${t} ${n} * * ${r}`;case`custom`:return String(e.custom||``).trim()}}s(),P();var Be=g({__name:`MarketplacePanel`,props:{type:{type:String,required:!0}},setup(e,{expose:t}){t();let n=e,r=le(),o=_([]),s=_([]),c=_(!1),l=_(``),u=_(``),f=_([]),p=_(`project`),m=_(new Set),h=_(new Set),g=_(new Set),v=a(()=>r.currentDirectory||``),b=null;async function x(){if(!c.value){c.value=!0;try{let e=new URLSearchParams({type:n.type,cwd:v.value});u.value&&e.set(`q`,u.value),f.value.length&&e.set(`sources`,f.value.join(`,`));let t=await(await fetch(`/api/agent/marketplace/catalog?${e}`)).json();t?.success?(o.value=t.groups||[],s.value=t.installed||[]):D.error(t?.error||K(`@MKT:加载失败`))}catch{D.error(K(`@MKT:加载失败`))}finally{c.value=!1}}}k(l,e=>{b&&clearTimeout(b),b=setTimeout(()=>{u.value=e.trim(),x()},400)}),k(f,()=>x()),k(()=>n.type,()=>{f.value=[],u.value=``,l.value=``,x()}),k(v,()=>x()),x();let C=a(()=>{let e=v.value?v.value.split(/[\\/]/).filter(Boolean).pop():``;return p.value===`project`?e||K(`@MKT:当前项目`):K(`@MKT:g ai 智能体`)});function w(e){return e.stars?`${T(e.stars)} ★`:e.downloads?`${T(e.downloads)} ${K(`@MKT:周下载`)}`:e.uses?`${T(e.uses)} ${K(`@MKT:次使用`)}`:``}function T(e){return e>=1e3?`${(e/1e3).toFixed(e>=1e4?0:1)}k`:String(e)}function E(e){return`${e.id}`}function A(e){return m.value.has(E(e))}let ee=a(()=>{let e={project:[],global:[]};for(let t of s.value)(e[t.target]||=[]).push(t);return e}),j=O({visible:!1,item:null,env:{},args:``});function M(e){return n.type===`mcp`&&(!!e.envKeys?.length||!!e.args?.length)}function N(e){j.item=e,j.env=Object.fromEntries((e.envKeys||[]).map(e=>[e,``])),j.args=(e.args||[]).join(` `),j.visible=!0}function P(){let e=j.item;if(j.visible=!1,!e)return;let t=Object.fromEntries(Object.entries(j.env).filter(([,e])=>e.trim()!==``)),n=j.args.trim()?j.args.trim().match(/(?:[^\s"]+|"[^"]*")+/g)?.map(e=>e.replace(/^"|"$/g,``))??void 0:void 0;L(e,{env:t,...n?{args:n}:{}})}async function I(e){if(!e.installed||await R(e)){if(M(e)){N(e);return}await L(e,{})}}async function L(e,t){let r=E(e);m.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:p.value,cwd:v.value,item:{...e,...t}})}),i=await r.json().catch(()=>null);if(!r.ok||!i?.success){D.error(i?.error||K(`@MKT:安装失败`));return}i.item?.warning&&D.warning(i.item.warning),i.item?.envKeys?.length?D.warning(`${K(`@MKT:还缺环境变量`)}: ${i.item.envKeys.join(`, `)}`):D.success(K(`@MKT:安装成功`)),await x()}catch{D.error(K(`@MKT:安装失败`))}finally{m.value.delete(r)}}async function R(e){try{return await F.confirm(`${e.name} ${K(`@MKT:已安装,要重新安装吗?`)}`,K(`@MKT:重新安装`),{confirmButtonText:K(`@MKT:重装`),cancelButtonText:K(`@MKT:取消`),type:`warning`}),!0}catch{return!1}}async function z(e){let t=`${e.target}:${e.id}`;g.value.add(t);try{let t=await fetch(`/api/agent/marketplace/reveal`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({type:n.type,target:e.target,cwd:v.value,id:e.id})}),r=await t.json().catch(()=>null);(!t.ok||!r?.success)&&D.error(r?.error||K(`@MKT:打开失败`))}catch{D.error(K(`@MKT:打开失败`))}finally{g.value.delete(t)}}async function V(e){try{await F.confirm(`${K(`@MKT:确定卸载`)} ${e.name}?`,K(`@MKT:卸载`),{confirmButtonText:K(`@MKT:卸载`),cancelButtonText:K(`@MKT:取消`),type:`warning`})}catch{return}let t=`${e.target}:${e.id}`;h.value.add(t);try{let t=new URLSearchParams({target:e.target,cwd:v.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){D.error(i?.error||K(`@MKT:卸载失败`));return}D.success(K(`@MKT:已卸载`)),await x()}catch{D.error(K(`@MKT:卸载失败`))}finally{h.value.delete(t)}}let re={props:n,configStore:r,groups:o,installed:s,loading:c,searchInput:l,query:u,selectedSources:f,installTarget:p,installing:m,removing:h,revealing:g,cwd:v,get searchTimer(){return b},set searchTimer(e){b=e},loadCatalog:x,targetLabel:C,metricText:w,formatCount:T,cardKey:E,isBusy:A,installedByTarget:ee,configDialog:j,needsConfig:M,openConfigDialog:N,confirmConfig:P,onInstall:I,doInstall:L,confirmReinstall:R,onReveal:z,onRemove:V,get $t(){return K},get Search(){return d},get Refresh(){return y},get Delete(){return te},get Link(){return B},get Check(){return oe},get Star(){return S},get Download(){return ne},get Warning(){return ie},get FolderOpened(){return i},CommonDialog:ue};return Object.defineProperty(re,"__isScriptSetup",{enumerable:!1,value:!0}),re}});s(),M(),f();var Ve={class:`marketplace-panel`},He={class:`mp-toolbar`},Ue={class:`mp-search`},We=[`placeholder`],Ge={class:`mp-toolbar-sub`},Ke={class:`mp-target-hint`},qe={class:`mp-source-filter`},Je=[`onClick`],Ye={class:`mp-body`},Xe={class:`mp-group-header`},Ze={class:`mp-group-title`},Qe={key:0,class:`mp-group-count`},$e={key:1,class:`mp-group-error`},et=[`href`,`title`],tt={key:0,class:`mp-grid`},nt={class:`mp-card-head`},rt=[`title`],it={key:0,class:`mp-card-metric`},at=[`title`],ot={class:`mp-card-meta`},st=[`title`],ct=[`title`],lt={key:2,class:`mp-tag remote`},ut={class:`mp-card-foot`},dt=[`href`],ft={key:1,class:`mp-installed-chip`},pt=[`disabled`,`onClick`],mt={key:3,class:`mp-not-installable`},ht={key:1,class:`mp-empty`},gt={key:0,class:`mp-group installed`},_t={class:`mp-group-header`},vt={class:`mp-group-title`},yt={class:`mp-group-count`},bt={key:0,class:`mp-installed-block`},xt={class:`mp-installed-target`},St={class:`mp-installed-list`},Ct=[`title`],wt=[`title`],Tt={key:1,class:`mp-meta-pkg`},Et={key:2,class:`mp-tag warn`},Dt=[`disabled`,`title`,`onClick`],Ot=[`disabled`,`onClick`],kt={key:1,class:`mp-empty all`},At={key:0,class:`mkt-form`},jt={class:`mkt-form-name`},Mt=[`onUpdate:modelValue`,`placeholder`],Nt={key:0,class:`mkt-field`},Pt={class:`mkt-hint`};function Ft(n,i,a,s,u,d){let f=l,h=L,g=p,_=b,v=re;return e(),R(`div`,Ve,[t(` ── 工具栏 ───────────────────────────────── `),m(`div`,He,[m(`div`,Ue,[c(f,{class:`mp-search-icon`},{default:U(()=>[c(s.Search)]),_:1}),A(m(`input`,{"onUpdate:modelValue":i[0]||=e=>s.searchInput=e,class:`mp-search-input`,type:`text`,placeholder:a.type===`skill`?s.$t(`@MKT:搜索 Skill...`):s.$t(`@MKT:搜索 MCP 服务...`)},null,8,We),[[G,s.searchInput]])]),c(g,{modelValue:s.installTarget,"onUpdate:modelValue":i[1]||=e=>s.installTarget=e,size:`small`,class:`mp-target`},{default:U(()=>[c(h,{value:`project`},{default:U(()=>[o(V(s.$t(`@MKT:当前项目`)),1)]),_:1}),c(h,{value:`global`},{default:U(()=>[o(V(s.$t(`@MKT:g ai 智能体`)),1)]),_:1})]),_:1},8,[`modelValue`]),c(_,{content:s.$t(`@MKT:刷新`),placement:`top`,"show-after":300},{default:U(()=>[m(`button`,{class:x([`mp-refresh`,{spinning:s.loading}]),onClick:s.loadCatalog},[c(f,null,{default:U(()=>[c(s.Refresh)]),_:1})],2)]),_:1},8,[`content`])]),m(`div`,Ge,[m(`span`,Ke,[o(V(s.$t(`@MKT:安装到`))+` `,1),m(`b`,null,V(s.targetLabel),1)]),m(`div`,qe,[(e(!0),R(r,null,H(s.groups,t=>(e(),R(`button`,{key:t.id,class:x([`mp-chip`,{active:s.selectedSources.includes(t.id)}]),onClick:()=>{let e=s.selectedSources.indexOf(t.id);e>=0?s.selectedSources.splice(e,1):s.selectedSources.push(t.id)}},V(t.label),11,Je))),128)),s.selectedSources.length?(e(),R(`button`,{key:0,class:`mp-chip clear`,onClick:i[2]||=e=>s.selectedSources=[]},V(s.$t(`@MKT:全部来源`)),1)):t(`v-if`,!0)])]),t(` ── 内容 ─────────────────────────────────── `),A((e(),R(`div`,Ye,[(e(!0),R(r,null,H(s.groups,n=>(e(),R(`section`,{key:n.id,class:`mp-group`},[m(`header`,Xe,[m(`h3`,Ze,V(n.label),1),n.status===`ok`?(e(),R(`span`,Qe,V(n.items.length),1)):(e(),R(`span`,$e,[c(f,null,{default:U(()=>[c(s.Warning)]),_:1}),o(` `+V(n.error||s.$t(`@MKT:来源不可用`)),1)])),n.homepage?(e(),R(`a`,{key:2,class:`mp-group-link`,href:n.homepage,target:`_blank`,rel:`noopener noreferrer`,title:n.homepage},[c(f,null,{default:U(()=>[c(s.Link)]),_:1})],8,et)):t(`v-if`,!0)]),n.status===`ok`&&n.items.length?(e(),R(`div`,tt,[(e(!0),R(r,null,H(n.items,n=>(e(),R(`article`,{key:s.cardKey(n),class:`mp-card`},[m(`div`,nt,[m(`span`,{class:`mp-card-name`,title:n.name},V(n.name),9,rt),s.metricText(n)?(e(),R(`span`,it,[c(f,null,{default:U(()=>[n.stars?(e(),z(s.Star,{key:0})):(e(),z(s.Download,{key:1}))]),_:2},1024),o(` `+V(s.metricText(n)),1)])):t(`v-if`,!0)]),m(`p`,{class:`mp-card-desc`,title:n.description},V(n.description||s.$t(`@MKT:暂无描述`)),9,at),m(`div`,ot,[n.package?(e(),R(`code`,{key:0,class:`mp-meta-pkg`,title:n.package},V(n.package),9,st)):n.repository?(e(),R(`span`,{key:1,class:`mp-meta-repo`,title:n.repository+(n.subpath?` · `+n.subpath:``)},[o(V(n.repository),1),n.subpath?(e(),R(r,{key:0},[o(` · `+V(n.subpath),1)],64)):t(`v-if`,!0)],8,ct)):t(`v-if`,!0),n.transport===`remote`?(e(),R(`span`,lt,V(s.$t(`@MKT:远程服务`)),1)):t(`v-if`,!0),(e(!0),R(r,null,H((n.tags||[]).slice(0,2),t=>(e(),R(`span`,{key:t,class:`mp-tag`},V(t),1))),128))]),m(`div`,ut,[n.upstream?(e(),R(`a`,{key:0,class:`mp-card-link`,href:n.upstream,target:`_blank`,rel:`noopener noreferrer`},V(s.$t(`@MKT:查看来源`)),9,dt)):t(`v-if`,!0),i[6]||=m(`span`,{class:`mp-foot-spacer`},null,-1),n.installed?(e(),R(`span`,ft,[c(f,null,{default:U(()=>[c(s.Check)]),_:1}),o(V(s.$t(`@MKT:已安装`)),1)])):n.installable===!1?(e(),R(`span`,mt,V(s.$t(`@MKT:暂不支持一键安装`)),1)):(e(),R(`button`,{key:2,class:`mp-install-btn`,disabled:s.isBusy(n),onClick:e=>s.onInstall(n)},V(s.isBusy(n)?s.$t(`@MKT:安装中...`):s.$t(`@MKT:安装`)),9,pt))])]))),128))])):n.status===`ok`?(e(),R(`div`,ht,V(s.$t(`@MKT:该来源暂无结果`)),1)):t(`v-if`,!0)]))),128)),t(` ── 已安装 ─────────────────────────────── `),s.installed.length?(e(),R(`section`,gt,[m(`header`,_t,[m(`h3`,vt,V(s.$t(`@MKT:已安装`)),1),m(`span`,yt,V(s.installed.length),1)]),(e(),R(r,null,H([`project`,`global`],n=>m(`div`,{key:n},[s.installedByTarget[n]?.length?(e(),R(`div`,bt,[m(`div`,xt,V(n===`project`?s.$t(`@MKT:当前项目`):s.$t(`@MKT:g ai 智能体`)),1),m(`div`,St,[(e(!0),R(r,null,H(s.installedByTarget[n],r=>(e(),R(`div`,{key:n+r.id,class:`mp-installed-row`},[m(`span`,{class:`mp-installed-name`,title:r.name},V(r.name),9,Ct),t(` 实际落盘的标识:SKILL.md 里的 name 常与仓库名不同(如仓库 taste-skill
2
+ 里的 skill 自称 brandkit),不显示这个用户就对不上广场卡片上的名字 `),r.id&&r.id!==r.name?(e(),R(`code`,{key:0,class:`mp-installed-id`,title:r.dir||r.file||r.id},V(r.id),9,wt)):t(`v-if`,!0),r.package?(e(),R(`code`,Tt,V(r.package),1)):t(`v-if`,!0),r.requiredEnv?.length?(e(),R(`span`,Et,V(s.$t(`@MKT:待配置`))+`: `+V(r.requiredEnv.join(`, `)),1)):t(`v-if`,!0),i[7]||=m(`span`,{class:`mp-foot-spacer`},null,-1),m(`button`,{class:`mp-reveal-btn`,disabled:s.revealing.has(n+r.id),title:r.dir||r.file||``,onClick:e=>s.onReveal(r)},[c(f,null,{default:U(()=>[c(s.FolderOpened)]),_:1}),o(` `+V(s.$t(`@MKT:打开文件夹`)),1)],8,Dt),m(`button`,{class:`mp-remove-btn`,disabled:s.removing.has(n+r.id),onClick:e=>s.onRemove(r)},[c(f,null,{default:U(()=>[c(s.Delete)]),_:1}),o(` `+V(s.removing.has(n+r.id)?s.$t(`@MKT:卸载中...`):s.$t(`@MKT:卸载`)),1)],8,Ot)]))),128))])])):t(`v-if`,!0)])),64))])):t(`v-if`,!0),!s.loading&&!s.groups.length?(e(),R(`div`,kt,V(s.$t(`@MKT:加载失败`)),1)):t(`v-if`,!0)])),[[v,s.loading]]),t(` ── MCP 安装前配置 ───────────────────────── `),c(s.CommonDialog,{modelValue:s.configDialog.visible,"onUpdate:modelValue":i[5]||=e=>s.configDialog.visible=e,title:s.$t(`@MKT:配置 MCP`),width:`460px`,type:`flex`,"close-on-click-modal":!1,"append-to-body":``},{footer:U(()=>[m(`button`,{class:`mkt-cancel`,onClick:i[4]||=e=>s.configDialog.visible=!1},V(s.$t(`@MKT:取消`)),1),m(`button`,{class:`mkt-confirm`,onClick:s.confirmConfig},V(s.$t(`@MKT:安装`)),1)]),default:U(()=>[s.configDialog.item?(e(),R(`div`,At,[m(`p`,jt,V(s.configDialog.item.name),1),(e(!0),R(r,null,H(Object.keys(s.configDialog.env),t=>(e(),R(`div`,{key:t,class:`mkt-field`},[m(`label`,null,V(t),1),A(m(`input`,{"onUpdate:modelValue":e=>s.configDialog.env[t]=e,type:`text`,autocomplete:`off`,placeholder:s.$t(`@MKT:环境变量值`),spellcheck:`false`},null,8,Mt),[[G,s.configDialog.env[t]]])]))),128)),s.configDialog.item.args?.length?(e(),R(`div`,Nt,[m(`label`,null,V(s.$t(`@MKT:启动参数`)),1),A(m(`input`,{"onUpdate:modelValue":i[3]||=e=>s.configDialog.args=e,type:`text`,autocomplete:`off`,spellcheck:`false`},null,512),[[G,s.configDialog.args]]),m(`p`,Pt,V(s.$t(`@MKT:参数提示`)),1)])):t(`v-if`,!0)])):t(`v-if`,!0)]),_:1},8,[`modelValue`,`title`])])}var It=q(Be,[[`render`,Ft],[`__scopeId`,`data-v-e9f9e851`],[`__file`,`C:/workspace/github_workspace/xz333221/zen-gitsync/src/ui/client/src/components/MarketplacePanel.vue`]]);s(),P();var Lt=g({__name:`SchedulePanel`,emits:[`open-session`],setup(e,{expose:t,emit:n}){t();let r=n,i=le(),o=_([]),s=_(!0),c=_(``),l=_({}),u=null,d=null;async function f(){try{o.value=await Ae(),c.value=``}catch(e){c.value=e?.message||String(e)}finally{s.value=!1}}function p(){d===null&&(d=window.setTimeout(()=>{d=null,f()},150))}T(async()=>{await f(),u=Fe(e=>{[`tasks_changed`,`task_started`,`task_finished`,`hello`].includes(e.type)&&p()})}),C(()=>{u?.(),d!==null&&window.clearTimeout(d)});let m=a(()=>{let e=o.value.filter(e=>e.enabled).length,t=o.value.length-e;return o.value.length?K(`@SCHED:{on} 个启用 · {off} 个停用`,{on:e,off:t}):``}),h=[`@SCHED:周日`,`@SCHED:周一`,`@SCHED:周二`,`@SCHED:周三`,`@SCHED:周四`,`@SCHED:周五`,`@SCHED:周六`];function g(e){let t=Ie(e.schedule);switch(t.kind){case`every-minute`:return K(`@SCHED:每分钟`);case`every-n-minutes`:return K(`@SCHED:每 {n} 分钟`,{n:t.n});case`hourly`:return K(`@SCHED:每小时第 {minute} 分钟`,{minute:t.minute});case`daily`:return K(`@SCHED:每天 {time}`,{time:`${String(t.hour).padStart(2,`0`)}:${String(t.minute).padStart(2,`0`)}`});case`weekly`:return K(`@SCHED:每周 {weekday} {time}`,{weekday:K(h[t.weekday]),time:`${String(t.hour).padStart(2,`0`)}:${String(t.minute).padStart(2,`0`)}`});case`monthly`:return K(`@SCHED:每月 {day} 日 {time}`,{day:t.day,time:`${String(t.hour).padStart(2,`0`)}:${String(t.minute).padStart(2,`0`)}`});default:return t.raw}}function v(e){if(!e.enabled)return K(`@SCHED:已停用`);if(e.running)return K(`@SCHED:运行中...`);let t=Le(e.nextRunAt);switch(t.kind){case`none`:return``;case`today`:return K(`@SCHED:下次 今天 {time}`,{time:t.time});case`tomorrow`:return K(`@SCHED:下次 明天 {time}`,{time:t.time});case`weekday`:return K(`@SCHED:下次 {weekday} {time}`,{weekday:K(h[t.weekday]),time:t.time});case`date`:return K(`@SCHED:下次 {date} {time}`,{date:t.date,time:t.time})}}function y(e){let t=e.lastRun;if(!t)return K(`@SCHED:还没执行过`);switch(t.status){case`ok`:return K(`@SCHED:成功`);case`error`:return K(`@SCHED:失败`);case`timed-out`:return K(`@SCHED:超时中止`);case`skipped-busy`:return K(`@SCHED:已跳过(会话忙)`);case`missed`:return K(`@SCHED:已错过(未运行)`);case`cancelled`:return K(`@SCHED:已停止`);default:return t.status}}function b(e){let t=e.lastRun;if(!t)return K(`@SCHED:还没执行过`);let n=ze(t.durationMs),r=K(`@SCHED:上次 {status}`,{status:y(e)});return n?`${r} · ${n}`:r}function x(e){return e.lastRun?`is-${Re(e.lastRun.status)}`:`is-muted`}async function S(e,t){if(!l.value[e.id]){l.value={...l.value,[e.id]:!0};try{await t(),await f()}catch(e){D.error(e?.message||String(e))}finally{let t={...l.value};delete t[e.id],l.value=t}}}function w(e){return S(e,()=>Me(e.id,{enabled:!e.enabled}))}function E(e){return S(e,()=>Y(e.id))}function O(e){return S(e,()=>Pe(e.id))}let k=_(!1),A=_(null);function ee(e){A.value=e,k.value=!0}async function j(){let e=A.value;if(e)try{await Ne(e.id),k.value=!1,await f()}catch(e){D.error(e?.message||String(e))}}let M=_(!1),N=_(``),P=_(``),F=_(!1),I=_({name:``,freq:`daily`,everyMinutes:30,minute:0,hour:9,weekday:1,custom:``,cwd:``,prompt:``,onMissed:`run`,enabled:!0}),L=a(()=>[{value:`minutes`,label:K(`@SCHED:每 N 分钟`)},{value:`hourly`,label:K(`@SCHED:每小时`)},{value:`daily`,label:K(`@SCHED:每天`)},{value:`weekly`,label:K(`@SCHED:每周`)},{value:`custom`,label:K(`@SCHED:自定义 cron`)}]),R=a(()=>$({freq:I.value.freq,everyMinutes:I.value.everyMinutes,minute:I.value.minute,hour:I.value.hour,weekday:I.value.weekday,custom:I.value.custom}));function z(){I.value={name:``,freq:`daily`,everyMinutes:30,minute:0,hour:9,weekday:1,custom:``,cwd:i.currentDirectory||``,prompt:``,onMissed:`run`,enabled:!0},P.value=``}function B(){N.value=``,z(),M.value=!0}function te(e){N.value=e.id;let t=Ie(e.schedule),n={name:e.name,freq:`custom`,everyMinutes:30,minute:0,hour:9,weekday:1,custom:e.schedule,cwd:e.cwd,prompt:e.prompt,onMissed:e.onMissed===`skip`?`skip`:`run`,enabled:e.enabled};switch(t.kind){case`every-n-minutes`:n.freq=`minutes`,n.everyMinutes=t.n;break;case`hourly`:n.freq=`hourly`,n.minute=t.minute;break;case`daily`:n.freq=`daily`,n.minute=t.minute,n.hour=t.hour;break;case`weekly`:n.freq=`weekly`,n.minute=t.minute,n.hour=t.hour,n.weekday=t.weekday;break;default:n.freq=`custom`}I.value=n,P.value=``,M.value=!0}async function ne(){let e=I.value;if(!e.name.trim()){P.value=K(`@SCHED:任务名不能为空`);return}if(!e.prompt.trim()){P.value=K(`@SCHED:提示词不能为空`);return}let t=R.value;if(!t){P.value=K(`@SCHED:cron 表达式不能为空`);return}let n={name:e.name.trim(),schedule:t,cwd:e.cwd.trim(),prompt:e.prompt.trim(),enabled:e.enabled,onMissed:e.onMissed};F.value=!0;try{N.value?await Me(N.value,n):await je(n),M.value=!1,await f()}catch(e){P.value=e?.message||String(e)}finally{F.value=!1}}let V={emit:r,configStore:i,tasks:o,loading:s,errorMsg:c,pending:l,get disposeEvents(){return u},set disposeEvents(e){u=e},get refreshTimer(){return d},set refreshTimer(e){d=e},refresh:f,scheduleRefresh:p,summaryText:m,WEEKDAY_KEYS:h,descText:g,nextText:v,lastStatusText:y,lastText:b,lastClass:x,withPending:S,toggle:w,runNow:E,stop:O,confirmVisible:k,confirmTarget:A,askRemove:ee,confirmRemove:j,formVisible:M,editingId:N,formError:P,saving:F,form:I,freqOptions:L,cronPreview:R,resetForm:z,openCreate:B,openEdit:te,submitForm:ne,get $t(){return K},CommonDialog:ue};return Object.defineProperty(V,"__isScriptSetup",{enumerable:!1,value:!0}),V}});f(),s(),M();var Rt={class:`schedule-panel`},zt={class:`schedule-toolbar`},Bt={class:`schedule-summary`},Vt={key:0,class:`schedule-error`},Ht={key:1,class:`schedule-loading`},Ut={key:2,class:`schedule-empty`},Wt={class:`schedule-empty-title`},Gt={class:`schedule-empty-desc`},Kt={key:3,class:`schedule-list`},qt={class:`schedule-card-body`},Jt={class:`schedule-card-head`},Yt={class:`schedule-name`},Xt={key:0,class:`schedule-running`},Zt=[`aria-checked`,`aria-label`,`onClick`],Qt={class:`schedule-card-sub`},$t={class:`schedule-desc`},en=[`onClick`],tn={class:`schedule-card-side`},nn={class:`schedule-actions`},rn=[`disabled`,`onClick`],an=[`disabled`,`onClick`],on=[`onClick`],sn=[`onClick`],cn={class:`sch-form`},ln={class:`sch-field`},un={class:`sch-field-label`},dn=[`placeholder`],fn={class:`sch-field`},pn={class:`sch-field-label`},mn={class:`sch-freq-row`},hn=[`value`],gn={class:`sch-inline-label`},_n=[`value`],vn={class:`sch-inline-label`},yn=[`value`],bn=[`value`],xn=[`value`],Sn={class:`sch-inline-label`},Cn=[`value`],wn={class:`sch-inline-label`},Tn=[`placeholder`],En={class:`sch-hint`},Dn={class:`sch-field`},On={class:`sch-field-label`},kn=[`placeholder`],An={class:`sch-field`},jn={class:`sch-field-label`},Mn=[`placeholder`],Nn={class:`sch-field`},Pn={class:`sch-field-label`},Fn={class:`sch-radio-row`},In={class:`sch-radio`},Ln={class:`sch-radio`},Rn={class:`sch-radio`},zn={key:0,class:`sch-form-error`},Bn={class:`sch-form-footer`},Vn=[`disabled`],Hn={class:`sch-confirm-text`},Un={class:`sch-form-footer`};function Wn(n,i,a,o,s,l){return e(),R(`div`,Rt,[m(`div`,zt,[m(`span`,Bt,V(o.summaryText),1),m(`button`,{type:`button`,class:`sch-btn sch-btn-primary`,onClick:o.openCreate},V(o.$t(`@SCHED:新建任务`)),1)]),o.errorMsg?(e(),R(`div`,Vt,V(o.$t(`@SCHED:操作失败:{error}`,{error:o.errorMsg})),1)):t(`v-if`,!0),o.loading?(e(),R(`div`,Ht,V(o.$t(`@SCHED:加载中...`)),1)):o.tasks.length?(e(),R(`div`,Kt,[(e(!0),R(r,null,H(o.tasks,n=>(e(),R(`article`,{key:n.id,class:x([`schedule-card`,{"is-disabled":!n.enabled,"is-running":!!n.running}])},[m(`div`,qt,[m(`div`,Jt,[m(`span`,Yt,V(n.name),1),n.running?(e(),R(`span`,Xt,V(o.$t(`@SCHED:运行中`)),1)):t(`v-if`,!0),m(`button`,{type:`button`,class:x([`sch-switch`,{on:n.enabled}]),role:`switch`,"aria-checked":n.enabled,"aria-label":n.enabled?o.$t(`@SCHED:停用`):o.$t(`@SCHED:启用`),onClick:e=>o.toggle(n)},[...i[17]||=[m(`span`,{class:`sch-switch-knob`},null,-1)]],10,Zt)]),m(`div`,Qt,[m(`span`,$t,V(o.descText(n)),1),i[18]||=m(`span`,{class:`schedule-sep`},`·`,-1),m(`span`,{class:x([`schedule-last`,o.lastClass(n)])},V(o.lastText(n)),3),n.sessionId?(e(),R(`button`,{key:0,type:`button`,class:`sch-link`,onClick:e=>o.emit(`open-session`,n.sessionId)},V(o.$t(`@SCHED:查看会话`)),9,en)):t(`v-if`,!0)])]),m(`div`,tn,[m(`div`,{class:x([`schedule-next`,{"is-muted":!n.enabled}])},V(o.nextText(n)),3),m(`div`,nn,[n.running?(e(),R(`button`,{key:0,type:`button`,class:`sch-btn`,disabled:!!o.pending[n.id],onClick:e=>o.stop(n)},V(o.$t(`@SCHED:停止`)),9,rn)):(e(),R(`button`,{key:1,type:`button`,class:`sch-btn`,disabled:!!o.pending[n.id],onClick:e=>o.runNow(n)},V(o.$t(`@SCHED:运行`)),9,an)),m(`button`,{type:`button`,class:`sch-btn`,onClick:e=>o.openEdit(n)},V(o.$t(`@SCHED:编辑`)),9,on),m(`button`,{type:`button`,class:`sch-btn sch-btn-danger`,onClick:e=>o.askRemove(n)},V(o.$t(`@SCHED:删除`)),9,sn)])])],2))),128))])):(e(),R(`div`,Ut,[m(`p`,Wt,V(o.$t(`@SCHED:还没有定时任务`)),1),m(`p`,Gt,V(o.$t(`@SCHED:让 g ai 在指定时间自动做事:定时拉代码、定时巡检、定时汇总。也可以在对话里直接说「每天 9 点帮我…」,让 g ai 来创建。`)),1)])),t(` 新建 / 编辑 `),c(o.CommonDialog,{modelValue:o.formVisible,"onUpdate:modelValue":i[14]||=e=>o.formVisible=e,title:o.editingId?o.$t(`@SCHED:编辑任务`):o.$t(`@SCHED:新建任务`),"close-on-click-modal":!1,"append-to-body":!0,size:`medium`,width:`560px`,"z-index":3e6,"custom-class":`schedule-dialog`},{default:U(()=>[m(`div`,cn,[m(`label`,ln,[m(`span`,un,V(o.$t(`@SCHED:任务名`)),1),A(m(`input`,{"onUpdate:modelValue":i[0]||=e=>o.form.name=e,class:`sch-input`,type:`text`,placeholder:o.$t(`@SCHED:如:每日拉代码`)},null,8,dn),[[G,o.form.name]])]),m(`div`,fn,[m(`span`,pn,V(o.$t(`@SCHED:执行计划`)),1),m(`div`,mn,[A(m(`select`,{"onUpdate:modelValue":i[1]||=e=>o.form.freq=e,class:`sch-input sch-select`},[(e(!0),R(r,null,H(o.freqOptions,t=>(e(),R(`option`,{key:t.value,value:t.value},V(t.label),9,hn))),128))],512),[[W,o.form.freq]]),o.form.freq===`minutes`?(e(),R(r,{key:0},[m(`span`,gn,V(o.$t(`@SCHED:每`)),1),A(m(`select`,{"onUpdate:modelValue":i[2]||=e=>o.form.everyMinutes=e,class:`sch-input sch-select sch-select-sm`},[(e(),R(r,null,H([5,10,15,20,30,60],e=>m(`option`,{key:e,value:e},V(e),9,_n)),64))],512),[[W,o.form.everyMinutes,void 0,{number:!0}]]),m(`span`,vn,V(o.$t(`@SCHED:分钟`)),1)],64)):o.form.freq===`daily`||o.form.freq===`weekly`?(e(),R(r,{key:1},[o.form.freq===`weekly`?A((e(),R(`select`,{key:0,"onUpdate:modelValue":i[3]||=e=>o.form.weekday=e,class:`sch-input sch-select sch-select-sm`},[(e(),R(r,null,H(o.WEEKDAY_KEYS,(e,t)=>m(`option`,{key:t,value:t},V(o.$t(e)),9,yn)),64))],512)),[[W,o.form.weekday,void 0,{number:!0}]]):t(`v-if`,!0),A(m(`select`,{"onUpdate:modelValue":i[4]||=e=>o.form.hour=e,class:`sch-input sch-select sch-select-sm`},[(e(),R(r,null,H(24,e=>m(`option`,{key:e-1,value:e-1},V(String(e-1).padStart(2,`0`)),9,bn)),64))],512),[[W,o.form.hour,void 0,{number:!0}]]),i[19]||=m(`span`,{class:`sch-inline-label`},`:`,-1),A(m(`select`,{"onUpdate:modelValue":i[5]||=e=>o.form.minute=e,class:`sch-input sch-select sch-select-sm`},[(e(),R(r,null,H(60,e=>m(`option`,{key:e-1,value:e-1},V(String(e-1).padStart(2,`0`)),9,xn)),64))],512),[[W,o.form.minute,void 0,{number:!0}]])],64)):o.form.freq===`hourly`?(e(),R(r,{key:2},[m(`span`,Sn,V(o.$t(`@SCHED:第`)),1),A(m(`select`,{"onUpdate:modelValue":i[6]||=e=>o.form.minute=e,class:`sch-input sch-select sch-select-sm`},[(e(),R(r,null,H(60,e=>m(`option`,{key:e-1,value:e-1},V(String(e-1).padStart(2,`0`)),9,Cn)),64))],512),[[W,o.form.minute,void 0,{number:!0}]]),m(`span`,wn,V(o.$t(`@SCHED:分钟`)),1)],64)):A((e(),R(`input`,{key:3,"onUpdate:modelValue":i[7]||=e=>o.form.custom=e,class:`sch-input sch-input-cron`,type:`text`,spellcheck:`false`,placeholder:o.$t(`@SCHED:如:0 9 * * 1-5`)},null,8,Tn)),[[G,o.form.custom]])]),m(`span`,En,V(o.$t(`@SCHED:cron:{cron}(分 时 日 月 周,本地时间)`,{cron:o.cronPreview||`—`})),1)]),m(`label`,Dn,[m(`span`,On,V(o.$t(`@SCHED:项目目录`)),1),A(m(`input`,{"onUpdate:modelValue":i[8]||=e=>o.form.cwd=e,class:`sch-input`,type:`text`,spellcheck:`false`,placeholder:o.$t(`@SCHED:任务在该目录下执行(默认当前项目)`)},null,8,kn),[[G,o.form.cwd]])]),m(`label`,An,[m(`span`,jn,V(o.$t(`@SCHED:提示词`)),1),A(m(`textarea`,{"onUpdate:modelValue":i[9]||=e=>o.form.prompt=e,class:`sch-input sch-textarea`,rows:`4`,placeholder:o.$t(`@SCHED:到点后发给 g ai 的完整指令,例如:检查所有仓库远端更新,有变更就 pull;写成一次自足的请求(未来那一轮没有现在的上下文)`)},null,8,Mn),[[G,o.form.prompt]])]),m(`div`,Nn,[m(`span`,Pn,V(o.$t(`@SCHED:错过补偿`)),1),m(`div`,Fn,[m(`label`,In,[A(m(`input`,{"onUpdate:modelValue":i[10]||=e=>o.form.onMissed=e,type:`radio`,value:`run`},null,512),[[E,o.form.onMissed]]),m(`span`,null,V(o.$t(`@SCHED:补跑一次(g ui 重新运行后)`)),1)]),m(`label`,Ln,[A(m(`input`,{"onUpdate:modelValue":i[11]||=e=>o.form.onMissed=e,type:`radio`,value:`skip`},null,512),[[E,o.form.onMissed]]),m(`span`,null,V(o.$t(`@SCHED:跳过`)),1)]),m(`label`,Rn,[A(m(`input`,{"onUpdate:modelValue":i[12]||=e=>o.form.enabled=e,type:`checkbox`},null,512),[[N,o.form.enabled]]),m(`span`,null,V(o.$t(`@SCHED:创建后启用`)),1)])])]),o.formError?(e(),R(`p`,zn,V(o.formError),1)):t(`v-if`,!0)]),m(`div`,Bn,[m(`button`,{type:`button`,class:`sch-btn`,onClick:i[13]||=e=>o.formVisible=!1},V(o.$t(`@SCHED:取消`)),1),m(`button`,{type:`button`,class:`sch-btn sch-btn-primary`,disabled:o.saving,onClick:o.submitForm},V(o.saving?o.$t(`@SCHED:保存中...`):o.$t(`@SCHED:保存`)),9,Vn)])]),_:1},8,[`modelValue`,`title`]),t(` 删除确认 `),c(o.CommonDialog,{modelValue:o.confirmVisible,"onUpdate:modelValue":i[16]||=e=>o.confirmVisible=e,title:o.$t(`@SCHED:删除任务`),"close-on-click-modal":!1,"append-to-body":!0,size:`small`,width:`400px`,"z-index":3e6,"custom-class":`schedule-dialog-confirm`},{default:U(()=>[m(`p`,Hn,V(o.$t(`@SCHED:确定删除「{name}」吗?已产生的会话会保留,但任务不再执行。`,{name:o.confirmTarget?.name||``})),1),m(`div`,Un,[m(`button`,{type:`button`,class:`sch-btn`,onClick:i[15]||=e=>o.confirmVisible=!1},V(o.$t(`@SCHED:取消`)),1),m(`button`,{type:`button`,class:`sch-btn sch-btn-danger`,onClick:o.confirmRemove},V(o.$t(`@SCHED:删除`)),1)])]),_:1},8,[`modelValue`,`title`])])}var Gn=q(Lt,[[`render`,Wn],[`__scopeId`,`data-v-63dc658b`],[`__file`,`C:/workspace/github_workspace/xz333221/zen-gitsync/src/ui/client/src/components/SchedulePanel.vue`]]);s(),P();var Kn=4e3,qn=g({__name:`AgentPromptSettings`,setup(e,{expose:t}){t();let n=le(),{defaultPrompt:r,projectPrompts:i,loadOrchestrator:o,saveDefaultPrompt:s,saveProjectPrompt:c}=ke(),l=_(``),u=_(!1),d=_(!1),f=a(()=>n.agentDefaultPrompt||``),p=a(()=>l.value.trim()!==f.value.trim());async function m(){if(!u.value&&p.value){u.value=!0;try{await n.saveAiSettings({agentDefaultPrompt:l.value})&&(l.value=f.value,d.value=!0,D.success(K(`@AGENT:已保存 g ai 默认提示词`)))}finally{u.value=!1}}}let h=a(()=>n.currentDirectory||``),g=a(()=>de(h.value)||h.value),v=a(()=>{let e=pe(h.value);return e&&i.value?.[e]?.prompt||``}),y=_(``),b=_(``),x=_(!1),S=_(!1),C=_(!1),w=a(()=>y.value.trim()!==(r.value||``).trim()||!!h.value&&b.value.trim()!==v.value.trim());function E(){y.value=r.value||``,b.value=v.value}T(async()=>{l.value=f.value,E();let e=await o(!0);C.value=!e,e&&E()});async function O(){if(!x.value&&w.value){x.value=!0;try{let e=!0,t=y.value.trim();t!==(r.value||``).trim()&&(e=await s(t));let n=b.value.trim();e&&h.value&&n!==v.value.trim()&&(e=await c(h.value,n)),e&&(E(),S.value=!0)}finally{x.value=!1}}}let k={configStore:n,defaultPrompt:r,projectPrompts:i,loadOrchestrator:o,saveDefaultPrompt:s,saveProjectPrompt:c,MAX_CHARS:Kn,gaiDraft:l,savingGai:u,gaiSaved:d,gaiStored:f,gaiDirty:p,saveGai:m,projectPath:h,projectName:g,projectPrompt:v,globalDraft:y,projectDraft:b,savingDispatch:x,dispatchSaved:S,dispatchLoadFailed:C,dispatchDirty:w,syncDispatchDraft:E,saveDispatch:O,get $t(){return K}};return Object.defineProperty(k,"__isScriptSetup",{enumerable:!1,value:!0}),k}});f(),s(),M();var Jn={class:`aps`},Yn={class:`aps__scroll`},Xn={class:`aps__head`},Zn={class:`aps__title`},Qn={class:`aps__intro`},$n={class:`aps__card aps__card--gai`},er={class:`aps__card-head`},tr={class:`aps__card-title`},nr={class:`aps__count`},rr={class:`aps__hint`},ir=[`placeholder`],ar={class:`aps__foot`},or={key:0,class:`aps__saved`},sr=[`disabled`],cr={class:`aps__card aps__card--dispatch`},lr={class:`aps__card-head`},ur={class:`aps__card-title`},dr={class:`aps__hint`},fr={class:`aps__field`},pr={class:`aps__card-head`},mr={class:`aps__label`,for:`aps-global`},hr={class:`aps__count`},gr=[`placeholder`],_r={class:`aps__field`},vr={class:`aps__card-head`},yr={class:`aps__label`,for:`aps-project`},br={key:0,class:`aps__count`},xr=[`disabled`,`placeholder`],Sr={class:`aps__hint`},Cr={class:`aps__foot`},wr={key:0,class:`aps__saved`},Tr={key:1,class:`aps__saved`},Er=[`disabled`];function Dr(n,r,i,a,o,s){return e(),R(`div`,Jn,[m(`div`,Yn,[m(`header`,Xn,[m(`h3`,Zn,V(a.$t(`@AGENT:提示词设置`)),1),m(`p`,Qn,V(a.$t(`@AGENT:这里配的两块提示词,和 g ai 对话时每一轮都会自动带上。改完下一次发消息就生效,不用新开会话。`)),1)]),t(` ── ① g ai 智能体的默认提示词 ── `),m(`section`,$n,[m(`div`,er,[m(`h4`,tr,V(a.$t(`@AGENT:g ai 智能体的默认提示词`)),1),m(`span`,nr,V(a.gaiDraft.length)+` / `+V(a.MAX_CHARS),1)]),m(`p`,rr,V(a.$t(`@AGENT:只作用于 g ai 自己:每次对话都会带上(定时任务也一样)。派发出去的任务读不到这一段。`)),1),A(m(`textarea`,{id:`aps-gai`,"onUpdate:modelValue":r[0]||=e=>a.gaiDraft=e,class:`aps__area`,rows:`6`,maxlength:a.MAX_CHARS,placeholder:a.$t(`@AGENT:例如:回答用中文;改完代码先跑一遍验证再汇报;不要动 dist 目录`)},null,8,ir),[[G,a.gaiDraft]]),m(`div`,ar,[a.gaiSaved&&!a.gaiDirty?(e(),R(`span`,or,V(a.$t(`@AGENT:已保存`)),1)):t(`v-if`,!0),r[3]||=m(`span`,{class:`aps__spacer`},null,-1),m(`button`,{type:`button`,class:`aps__btn aps__btn--primary`,disabled:a.savingGai||!a.gaiDirty,onClick:a.saveGai},V(a.savingGai?a.$t(`@AGENT:保存中…`):a.$t(`@AGENT:保存`)),9,sr)])]),t(` ── ② 派发任务的提示词 ── `),m(`section`,cr,[m(`div`,lr,[m(`h4`,ur,V(a.$t(`@AGENT:派发任务的提示词`)),1)]),m(`p`,dr,V(a.$t(`@AGENT:与工作台「预设提示词」是同一份设置,在哪边改都一样。派发任务时附加在指令之前,和 g ai 对话时也会带上。`)),1),m(`div`,fr,[m(`div`,pr,[m(`label`,mr,V(a.$t(`@AGENT:全局提示词`)),1),m(`span`,hr,V(a.globalDraft.length)+` / `+V(a.MAX_CHARS),1)]),A(m(`textarea`,{id:`aps-global`,"onUpdate:modelValue":r[1]||=e=>a.globalDraft=e,class:`aps__area`,rows:`5`,maxlength:a.MAX_CHARS,placeholder:a.$t(`@AGENT:对所有项目生效。例如:回答用中文;改完代码必须跑一遍测试;不要动 dist 目录`)},null,8,gr),[[G,a.globalDraft]])]),m(`div`,_r,[m(`div`,vr,[m(`label`,yr,V(a.projectPath?a.$t(`@AGENT:「{name}」的项目提示词`,{name:a.projectName}):a.$t(`@AGENT:项目提示词`)),1),a.projectPath?(e(),R(`span`,br,V(a.projectDraft.length)+` / `+V(a.MAX_CHARS),1)):t(`v-if`,!0)]),A(m(`textarea`,{id:`aps-project`,"onUpdate:modelValue":r[2]||=e=>a.projectDraft=e,class:`aps__area`,rows:`5`,maxlength:a.MAX_CHARS,disabled:!a.projectPath,placeholder:a.projectPath?a.$t(`@AGENT:只在这个项目派发/对话时附加。例如:包管理器用 pnpm;改动集中在 src/ui 下`):a.$t(`@AGENT:当前没有打开项目,项目级提示词暂时不能设置`)},null,8,xr),[[G,a.projectDraft]]),m(`p`,Sr,V(a.projectPath?a.$t(`@AGENT:项目提示词追加在全局提示词之后(不覆盖全局),在「{name}」里派发或对话时一起带上`,{name:a.projectName}):a.$t(`@AGENT:先在左上角切到一个项目,才能设置它的提示词`)),1)]),m(`div`,Cr,[a.dispatchSaved&&!a.dispatchDirty?(e(),R(`span`,wr,V(a.$t(`@AGENT:已保存`)),1)):a.dispatchLoadFailed?(e(),R(`span`,Tr,V(a.$t(`@AGENT:读取设置失败,请稍后重试`)),1)):t(`v-if`,!0),r[4]||=m(`span`,{class:`aps__spacer`},null,-1),m(`button`,{type:`button`,class:`aps__btn aps__btn--primary`,disabled:a.savingDispatch||!a.dispatchDirty,onClick:a.saveDispatch},V(a.savingDispatch?a.$t(`@AGENT:保存中…`):a.$t(`@AGENT:保存`)),9,Er)])])])])}var Or=q(qn,[[`render`,Dr],[`__scopeId`,`data-v-f9ada51b`],[`__file`,`C:/workspace/github_workspace/xz333221/zen-gitsync/src/ui/client/src/components/AgentPromptSettings.vue`]]);s(),P();var kr=40,Ar=g({__name:`AgentView`,setup(e,{expose:t}){t();let r=le(),i=_(null),{narrow:o}=Oe(i),s=_(`chat`),c=_(`chat`),d=a(()=>c.value===`mcp`?`mcp`:`skill`),f=a(()=>[{id:`chat`,label:K(`@AGENT:对话`),icon:j},{id:`schedule`,label:K(`@AGENT:定时任务`),icon:ee},{id:`skill`,label:K(`@AGENT:Skill 广场`),icon:v},{id:`mcp`,label:K(`@AGENT:MCP 广场`),icon:ae},{id:`settings`,label:K(`@AGENT:设置`),icon:w}]),{sessions:p,sessionsLoading:m,currentSessionId:h,messages:g,displayMessages:y,isStreaming:b,sessionLoading:x,loadSessions:S,loadSession:E,deleteSession:D,renameSession:O,newSession:A,sendMessage:M,retryTurn:N,questionPanel:P,answeringQuestion:F,answerQuestion:I,isSessionGenerating:L,currentEngine:R,pendingEngine:z,isEngineLocked:B,pickEngine:te,stop:ne,inputContextUsage:V,queuedMessages:re,queuePaused:ie,removeQueuedMessage:H,flushQueued:oe}=we(),U=a(()=>B.value?R.value:z.value);function W(e){B.value||te(e)}let G=a(()=>{let e=r.theme;return e===`dark`||e===`auto`&&window.matchMedia(`(prefers-color-scheme: dark)`).matches?`dark`:`light`}),q=a(()=>he(p.value,L)),ue=me(),de=a(()=>q.value.find(e=>e.id===h.value)?.title||K(`@AGENT:对话`)),pe={"--welcome-avatar":`url("${Ce}")`},ke=a(()=>fe(r.agentPresetPrompts));async function J(e){await M(e.text,e.files),await u(),Y()}async function Ae(e){await M(e.prompt),await u(),Y()}let je=be(),Me=_(null),Ne=Se();function Y(e=!0){Me.value?.scrollToBottom(e)}k(()=>g.value.length,()=>{u(()=>Y(!1))});function Pe(e){E(e),s.value=`chat`}function X(e){e&&(c.value=`chat`,Pe(e))}function Ie(){A(),s.value=`chat`}let Z=_(280),Q=_(!1),{convListCollapsed:Le,setConvListCollapsed:Re}=Te();function ze(e){if(Le.value)return;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)}k(o,e=>{e||(s.value=`chat`)}),k(()=>[r.currentDirectory,b.value],async([e,t],n)=>{let r=!n||e!==n[0],i=!!n&&n[1]===!0&&!t;(r||i)&&await S(),h.value&&!b.value&&!p.value.some(e=>e.sessionId===h.value)&&A()},{immediate:!0});let $=null;T(()=>{$=Fe(e=>{e.type===`task_finished`&&S().catch(()=>{})})}),C(()=>{$?.(),$=null});let Be={configStore:r,rootRef:i,narrow:o,chatPage:s,activeTab:c,marketplaceType:d,tabs:f,sessions:p,sessionsLoading:m,currentSessionId:h,messages:g,displayMessages:y,isStreaming:b,sessionLoading:x,loadSessions:S,loadSession:E,deleteSession:D,renameSession:O,newSession:A,sendMessage:M,retryTurn:N,questionPanel:P,answeringQuestion:F,answerQuestion:I,isSessionGenerating:L,currentEngine:R,pendingEngine:z,isEngineLocked:B,pickEngine:te,stop:ne,inputContextUsage:V,queuedMessages:re,queuePaused:ie,removeQueuedMessage:H,flushQueued:oe,displayEngine:U,handleEngineSelect:W,chatTheme:G,conversationItems:q,conversationLabels:ue,currentSessionTitle:de,welcomeAvatarStyle:pe,presetQuestions:ke,onSend:J,onSelectPreset:Ae,questionLabels:je,chatContainerRef:Me,queueLabels:Ne,scrollToBottom:Y,selectSession:Pe,handleScheduleOpenSession:X,handleNewSession:Ie,sidebarWidth:Z,isResizing:Q,convListCollapsed:Le,setConvListCollapsed:Re,CONV_RAIL_WIDTH:kr,startResize:ze,get disposeScheduleEvents(){return $},set disposeScheduleEvents(e){$=e},get $t(){return K},get ElIcon(){return l},get Loading(){return n},get ChatContainer(){return se},get ConversationList(){return ce},get AGENT_UPLOAD_ACCEPT(){return _e},get AGENT_ASSISTANT_NAME(){return ye},get AGENT_ASSISTANT_AVATAR(){return Ce},get MESSAGE_RAIL_CONFIG(){return ge},get MESSAGE_META_CONFIG(){return xe},get agentEngineName(){return ve},MarketplacePanel:It,SchedulePanel:Gn,AgentPromptSettings:Or,AgentEngineSelector:Ee,CopySessionButton:De};return Object.defineProperty(Be,"__isScriptSetup",{enumerable:!1,value:!0}),Be}});s(),f();var jr={ref:`rootRef`,class:`agent-view`},Mr={class:`agent-chat-area`},Nr={class:`agent-tabs`,role:`tablist`},Pr=[`aria-selected`,`onClick`],Fr={class:`agent-tab-body`},Ir={key:0,class:`agent-chat-pane`},Lr={key:0,class:`agent-list-page`},Rr={key:0,class:`agent-page-bar`},zr=[`title`,`aria-label`],Br={class:`agent-page-title`},Vr={key:0,class:`chat-loading`};function Hr(n,i,a,o,s,l){return e(),R(`div`,jr,[t(` ═══ 宽屏:左侧会话列表(只在「对话」Tab 显示)═══
3
+ 窄屏时这一整块不渲染,会话列表改成 body 里的一个整页(见 .agent-list-page) `),o.activeTab===`chat`&&!o.narrow?(e(),R(r,{key:0},[m(`aside`,{class:x([`agent-sidebar`,{"is-convs-collapsed":o.convListCollapsed}]),style:h({width:(o.convListCollapsed?o.CONV_RAIL_WIDTH:o.sidebarWidth)+`px`})},[t(` 会话列表:UI 与交互都在组件库的 ConversationList 里(含收起 / 展开) `),c(o.ConversationList,{class:`agent-conversations`,items:o.conversationItems,"active-id":o.currentSessionId,loading:o.sessionsLoading,labels:o.conversationLabels,collapsible:``,collapsed:o.convListCollapsed,"onUpdate:collapsed":o.setConvListCollapsed,onSelect:o.selectSession,onNew:o.handleNewSession,onRename:o.renameSession,onDelete:o.deleteSession},null,8,[`items`,`active-id`,`loading`,`labels`,`collapsed`,`onUpdate:collapsed`,`onRename`,`onDelete`])],6),t(` 拖拽分隔条(收起时藏起来:40px 的收纳条没有可拖的余地) `),o.convListCollapsed?t(`v-if`,!0):(e(),R(`div`,{key:0,class:x([`sidebar-resizer`,{active:o.isResizing}]),onMousedown:o.startResize},null,34))],64)):t(`v-if`,!0),t(` ═══ 右侧:Tab 栏 + 内容区 ═══ `),m(`main`,Mr,[m(`nav`,Nr,[(e(!0),R(r,null,H(o.tabs,t=>(e(),R(`button`,{key:t.id,type:`button`,class:x([`agent-tab`,{active:o.activeTab===t.id}]),role:`tab`,"aria-selected":o.activeTab===t.id,onClick:e=>o.activeTab=t.id},[c(o.ElIcon,null,{default:U(()=>[(e(),z(I(t.icon)))]),_:2},1024),m(`span`,null,V(t.label),1)],10,Pr))),128)),t(` ═══ 引擎选择器 ═══
4
+ 与工作台执行器下拉同一套交互(点击展开、未安装标出来、点了直接开安装弹窗)。
5
+ 下拉本体收口在 AgentEngineSelector,文件空间 g ai 面板复用同一份实现。
6
+ 会话一旦落盘就置灰:引擎在会话建立时锁定(三家续聊标识互不通用),要换请新建。 `),o.activeTab===`chat`?(e(),z(o.AgentEngineSelector,{key:0,class:`agent-engine`,engine:o.displayEngine,locked:o.isEngineLocked,onSelect:o.handleEngineSelect},null,8,[`engine`,`locked`])):t(`v-if`,!0),t(` 复制整条会话(默认精简范围,小箭头可选全量)——与工作台的「复制执行内容」同一套口径 `),o.activeTab===`chat`?(e(),z(o.CopySessionButton,{key:1,class:`agent-copy`,messages:o.messages,title:o.currentSessionTitle,engine:o.agentEngineName(o.displayEngine)},null,8,[`messages`,`title`,`engine`])):t(`v-if`,!0)]),m(`div`,Fr,[t(` ── 对话 ── `),o.activeTab===`chat`?(e(),R(`div`,Ir,[t(` 窄屏 · 会话列表页:列表独占整页 `),o.narrow&&o.chatPage===`list`?(e(),R(`div`,Lr,[c(o.ConversationList,{class:`agent-conversations`,items:o.conversationItems,"active-id":o.currentSessionId,loading:o.sessionsLoading,labels:o.conversationLabels,onSelect:o.selectSession,onNew:o.handleNewSession,onRename:o.renameSession,onDelete:o.deleteSession},null,8,[`items`,`active-id`,`loading`,`labels`,`onRename`,`onDelete`])])):(e(),R(r,{key:1},[t(` 对话页(窄屏时顶上多一条返回条;宽屏左侧就摆着列表,不需要) `),o.narrow?(e(),R(`div`,Rr,[m(`button`,{type:`button`,class:`agent-page-back`,title:o.$t(`@AGENT:返回会话列表`),"aria-label":o.$t(`@AGENT:返回会话列表`),onClick:i[0]||=e=>o.chatPage=`list`},[...i[1]||=[m(`svg`,{viewBox:`0 0 24 24`,width:`14`,height:`14`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`},[m(`line`,{x1:`19`,y1:`12`,x2:`5`,y2:`12`}),m(`polyline`,{points:`12 19 5 12 12 5`})],-1)]],8,zr),m(`span`,Br,V(o.currentSessionTitle),1)])):t(`v-if`,!0),t(`
7
+ 对话宿主:单独开一层裁剪边界。
8
+ 欢迎页在矮/窄窗口里会比可用高度还高,而它是垂直居中的 —— 溢出的部分
9
+ 会**向上**跑出 .acu-chat,盖到刚加的返回条上(把返回条的点击也一起吃掉,
10
+ e2e 实测就是这个症状)。宿主的 overflow:hidden 把它裁在自己这一格里。
11
+ `),m(`div`,{class:`agent-chat-host`,style:o.welcomeAvatarStyle},[t(` 加载中 `),o.sessionLoading?(e(),R(`div`,Vr,[c(o.ElIcon,{class:`is-loading`,size:32},{default:U(()=>[c(o.Loading)]),_:1}),m(`span`,null,V(o.$t(`@AGENT:加载会话中...`)),1)])):(e(),R(r,{key:1},[t(` ChatContainer `),c(o.ChatContainer,{ref:`chatContainerRef`,messages:o.displayMessages,"preset-questions":o.presetQuestions,"welcome-title":o.$t(`@AGENT:智能体助手`),"welcome-description":o.$t(`@AGENT:我可以帮你阅读代码、执行命令、修改文件。选择下方话题或直接输入你的问题。`),"assistant-name":o.AGENT_ASSISTANT_NAME,"assistant-avatar":o.AGENT_ASSISTANT_AVATAR,theme:o.chatTheme,generating:o.isStreaming,"allow-queue":!0,queued:o.queuedMessages,"queue-paused":o.queuePaused,"queue-labels":o.queueLabels,"upload-config":{accept:o.AGENT_UPLOAD_ACCEPT},"context-usage":o.inputContextUsage,placeholder:o.isStreaming?o.$t(`@AGENT:生成中,发送后会排队,等本轮跑完自动接上…`):o.$t(`@AGENT:输入消息,Enter 发送`),question:o.questionPanel,"question-submitting":o.answeringQuestion,"question-labels":o.questionLabels,"plan-config":{labels:{title:o.$t(`@AGENT:计划`),raw:o.$t(`@AGENT:原始参数`)}},"message-rail-config":o.MESSAGE_RAIL_CONFIG,"message-meta-config":o.MESSAGE_META_CONFIG,onSend:o.onSend,onSelect:o.onSelectPreset,onStop:o.stop,onUnqueue:o.removeQueuedMessage,onFlushQueued:o.flushQueued,onAnswer:o.answerQuestion,onRetry:o.retryTurn},null,8,[`messages`,`preset-questions`,`welcome-title`,`welcome-description`,`assistant-name`,`assistant-avatar`,`theme`,`generating`,`queued`,`queue-paused`,`queue-labels`,`upload-config`,`context-usage`,`placeholder`,`question`,`question-submitting`,`question-labels`,`plan-config`,`message-rail-config`,`message-meta-config`,`onStop`,`onUnqueue`,`onFlushQueued`,`onAnswer`,`onRetry`])],2112))])],64))])):o.activeTab===`schedule`?(e(),R(r,{key:1},[t(` ── 定时任务 ── `),c(o.SchedulePanel,{onOpenSession:o.handleScheduleOpenSession})],2112)):o.activeTab===`skill`||o.activeTab===`mcp`?(e(),R(r,{key:2},[t(` ── Skill 广场 / MCP 广场 ── `),c(o.MarketplacePanel,{type:o.marketplaceType},null,8,[`type`])],2112)):(e(),R(r,{key:3},[t(` ── 设置(提示词设置)── `),c(o.AgentPromptSettings)],2112))])])],512)}var Ur=q(Ar,[[`render`,Hr],[`__scopeId`,`data-v-bd681ddd`],[`__file`,`C:/workspace/github_workspace/xz333221/zen-gitsync/src/ui/client/src/views/AgentView.vue`]]);export{Ur as default};
@@ -0,0 +1,2 @@
1
+ import"./rolldown-runtime-C0FnF6B9.js";import{$n as e,An as t,At as n,Dn as r,Fn as i,Hn as a,In as o,J as s,Kn as c,Lr as l,On as u,Rn as d,Sr as f,W as p,Xr as m,Yn as h,Zn as g,a as _,cr as v,hr as y,i as b,jn as x,kn as S,ni as C,nt as w,rt as T,ur as E,z as D}from"./element-plus-DgSY_Wt4.js";import{n as O,t as k}from"./_plugin-vue_export-helper-bQQyMRS6.js";import{t as A}from"./CommonDialog-zaBdFGFH.js";async function j(e,t){let n=e.body.getReader(),r=new TextDecoder(`utf-8`),i=``;for(;;){let{done:e,value:a}=await n.read();if(e)break;i+=r.decode(a,{stream:!0});let o=i.split(`
2
+ `);i=o.pop()??``;for(let e of o)e.trim()&&t(e)}i.trim()&&t(i)}async function M(){let e=await fetch(`/api/app-version`);return e.ok?e.json():{success:!1,current:``,latest:null,hasUpdate:!1,error:`HTTP ${e.status}`}}async function N(e){let t=await fetch(`/api/app-upgrade`,{method:`POST`});if(!t.ok){let n=`HTTP ${t.status}`;try{let e=await t.json();e?.error&&(n=e.error)}catch{}e({type:`error`,message:n}),e({type:`done`,code:t.status});return}if(!t.body){e({type:`error`,message:`响应无 body`}),e({type:`done`,code:-1});return}await j(t,t=>{try{e(JSON.parse(t))}catch{}})}async function P(){let e=await fetch(`/api/app-restart`,{method:`POST`});if(!e.ok){let t=`HTTP ${e.status}`;try{let n=await e.json();n?.error&&(t=n.error)}catch{}throw Error(t)}if(!e.body)throw Error(`响应无 body`);return new Promise((t,n)=>{let r=!1,i=e=>{r||(r=!0,e())};j(e,e=>{try{let r=JSON.parse(e);r.type===`ready`&&typeof r.port==`number`&&r.port>0?i(()=>t(r.port)):r.type===`timeout`?i(()=>n(Error(`restart.timeout`))):r.type===`error`&&i(()=>n(Error(r.message||`restart.failed`)))}catch{}}).then(()=>{i(()=>n(Error(`restart.stream-closed`)))}).catch(()=>{})})}a(),y();var F=`npm install -g zen-gitsync --registry https://registry.npmjs.org/`,I=d({__name:`UpgradeDialog`,props:{modelValue:{type:Boolean,required:!0},logs:{type:String,required:!0},status:{type:String,required:!0},countdown:{type:Number,required:!1,default:0}},emits:[`update:modelValue`,`retry`,`restart`,`cancel`],setup(e,{expose:t,emit:r}){t();let i=e,a=r,o=f(null);v(()=>i.logs,async()=>{await c(),o.value&&(o.value.scrollTop=o.value.scrollHeight)});function s(){i.status!==`running`&&(i.status===`success`&&i.countdown>0&&a(`cancel`),a(`update:modelValue`,!1))}function l(){a(`retry`)}function u(){a(`restart`)}function d(){a(`cancel`),a(`update:modelValue`,!1)}async function p(){try{await navigator.clipboard.writeText(F),_.success(O(`@F13B4:已复制升级命令`))}catch{_.warning(O(`@F13B4:复制失败,请手动复制`))}}let m={MANUAL_COMMAND:F,props:i,emit:a,logEl:o,close:s,onRetry:l,onRestart:u,onLater:d,onCopyCommand:p,get Loading(){return n},get CircleCheck(){return w},get CircleClose(){return T},get $t(){return O},CommonDialog:A};return Object.defineProperty(m,"__isScriptSetup",{enumerable:!1,value:!0}),m}});a(),l();var L={key:3},R={key:4},z={key:5},B={key:0,class:`upgrade-hint`},V={key:0,class:`upgrade-countdown`},H={key:1,class:`upgrade-manual`},U={class:`upgrade-manual__label`};function W(n,r,a,c,l,d){let f=s,p=D;return e(),S(c.CommonDialog,{"model-value":a.modelValue,"onUpdate:modelValue":r[0]||=e=>c.emit(`update:modelValue`,e),title:c.$t(`@F13B4:升级`),width:`680px`,type:`flex`,"close-on-click-modal":!1,"close-on-press-escape":!1,"show-close":a.status!==`running`,"append-to-body":``,onClose:c.close},{footer:E(()=>[a.status===`failed`?(e(),S(p,{key:0,type:`primary`,onClick:c.onRetry},{default:E(()=>[i(C(c.$t(`@F13B4:重试`)),1)]),_:1})):t(`v-if`,!0),a.status===`failed`?(e(),S(p,{key:1,onClick:c.onCopyCommand},{default:E(()=>[i(C(c.$t(`@F13B4:复制升级命令`)),1)]),_:1})):t(`v-if`,!0),a.status===`success`?(e(),S(p,{key:2,type:`primary`,onClick:c.onRestart},{default:E(()=>[i(C(c.$t(`@F13B4:立即重启并刷新`)),1)]),_:1})):t(`v-if`,!0),a.status===`success`?(e(),S(p,{key:3,onClick:c.onLater},{default:E(()=>[i(C(c.$t(`@F13B4:稍后手动重启`)),1)]),_:1})):t(`v-if`,!0),a.status===`running`?(e(),S(p,{key:4,disabled:``},{default:E(()=>[i(C(c.$t(`@F13B4:升级中`))+`... `,1)]),_:1})):t(`v-if`,!0)]),default:E(()=>[u(`div`,{class:m([`upgrade-status`,`is-${a.status}`])},[a.status===`running`?(e(),S(f,{key:0,class:`is-loading`},{default:E(()=>[o(c.Loading)]),_:1})):a.status===`success`?(e(),S(f,{key:1,color:`var(--color-success)`},{default:E(()=>[o(c.CircleCheck)]),_:1})):(e(),S(f,{key:2,color:`var(--color-danger)`},{default:E(()=>[o(c.CircleClose)]),_:1})),a.status===`running`?(e(),x(`span`,L,C(c.$t(`@F13B4:升级中`)),1)):a.status===`success`?(e(),x(`span`,R,C(c.$t(`@F13B4:升级完成`)),1)):(e(),x(`span`,z,C(c.$t(`@F13B4:升级失败`)),1))],2),a.status===`success`?(e(),x(`p`,B,[i(C(c.$t(`@F13B4:新版本已全局安装,需要重启服务才能生效`))+` `,1),a.countdown>0?(e(),x(`span`,V,C(c.$t(`@F13B4:{seconds} 秒后自动刷新`,{seconds:a.countdown})),1)):t(`v-if`,!0)])):t(`v-if`,!0),a.status===`failed`?(e(),x(`p`,H,[u(`span`,U,C(c.$t(`@F13B4:手动升级命令`)),1),u(`code`,{class:`upgrade-manual__cmd`},C(c.MANUAL_COMMAND))])):t(`v-if`,!0),u(`pre`,{ref:`logEl`,class:`upgrade-log`},C(a.logs||c.$t(`@F13B4:等待日志输出`)),513)]),_:1},8,[`model-value`,`title`,`show-close`])}var G=k(I,[[`render`,W],[`__scopeId`,`data-v-bc566bba`],[`__file`,`C:/workspace/github_workspace/xz333221/zen-gitsync/src/ui/client/src/components/UpgradeDialog.vue`]]);a(),y();var K=`https://github.com/xz333221/zen-gitsync/tags`,q=5,J=`app-version-check`,Y=36e5,X=d({__name:`AppVersionBadge`,setup(e,{expose:t}){t();let n=`2.18.13`,i=f(n),a=r(()=>i.value||n),o=f(null),s=f(!1),c=f(``),l=f(`running`),u=f(0),d=null,p=f(!1);function m(){try{let e=sessionStorage.getItem(J);if(!e)return null;let{at:t,data:n}=JSON.parse(e);return Date.now()-t>Y?null:n}catch{return null}}function v(e){try{sessionStorage.setItem(J,JSON.stringify({at:Date.now(),data:e}))}catch{}}async function y(e=!1){let t=m();t&&(o.value=t);try{let t=await M();o.value=t,v(t),t.current&&(i.value=t.current),!e&&t.success&&t.hasUpdate&&_({type:`success`,message:O(`@F13B4:发现新版本 {version}`,{version:t.latest??``}),duration:4e3})}catch(t){e||_({type:`warning`,message:O(`@F13B4:检查更新失败 {error}`,{error:t?.message||``})})}}async function x(){if(o.value?.hasUpdate){try{await b.confirm(O(`@F13B4:确定要从 {current} 升级到 {latest} 吗?`,{current:o.value.current,latest:o.value.latest}),O(`@F13B4:升级`),{confirmButtonText:O(`@F13B4:确定升级`),cancelButtonText:O(`@F13B4:取消`),type:`info`})}catch{return}c.value=``,l.value=`running`,s.value=!0,await N(e=>{if(e.type===`done`){if(l.value=e.code===0?`success`:`failed`,e.code===0){try{sessionStorage.removeItem(J)}catch{}o.value?.latest&&(i.value=o.value.latest),S()}}else e.message&&(c.value+=e.message)})}}function S(){C(),u.value=q,d=setInterval(()=>{--u.value,u.value<=0&&(d&&=(clearInterval(d),null),T())},1e3)}function C(){d&&=(clearInterval(d),null),u.value=0}function w(){C()}async function T(){if(C(),!p.value){p.value=!0;try{let e=await P(),{pathname:t,search:n,hash:r}=window.location;window.location.href=`http://localhost:${e}${t}${n}${r}`}catch(e){let t=e?.message||``,n={"restart.timeout":`@F13B4:重启超时`,"restart.stream-closed":`@F13B4:重启失败,请刷新页面重试`,"restart.failed":`@F13B4:重启失败`}[t];_({type:`warning`,message:n?O(n):O(`@F13B4:重启失败 {error}`,{error:t})}),p.value=!1}}}h(()=>{C()}),g(()=>{y(!0)});let E={buildVersion:n,releasesUrl:K,runtimeVersion:i,displayVersion:a,latestInfo:o,upgradeDialogVisible:s,upgradeLogs:c,upgradeStatus:l,AUTO_REFRESH_SECONDS:q,countdown:u,get countdownTimer(){return d},set countdownTimer(e){d=e},restartInFlight:p,CACHE_KEY:J,CACHE_TTL_MS:Y,readCache:m,writeCache:v,checkUpdate:y,handleUpgrade:x,startAutoRefreshCountdown:S,cancelAutoRefreshCountdown:C,handleCancelAutoRefresh:w,handleRestart:T,get $t(){return O},UpgradeDialog:G};return Object.defineProperty(E,"__isScriptSetup",{enumerable:!1,value:!0}),E}});a(),l();var Z={class:`app-version-badge`},Q=[`aria-label`],$=[`aria-label`],ee=[`title`,`aria-label`],te={class:`upgrade-btn__label`},ne={class:`upgrade-btn__version`};function re(n,r,i,a,s,c){let l=p;return e(),x(`div`,Z,[t(` GitHub 链接 `),o(l,{content:a.$t(`@F13B4:在 GitHub 上查看源码`),placement:`top`,effect:`dark`,"show-after":300},{default:E(()=>[u(`a`,{href:`https://github.com/xz333221/zen-gitsync`,target:`_blank`,rel:`noopener noreferrer`,class:`badge-icon-link`,"aria-label":a.$t(`@F13B4:在 GitHub 上查看源码`)},[...r[1]||=[u(`svg`,{viewBox:`0 0 24 24`,width:`15`,height:`15`,"aria-hidden":`true`,fill:`currentColor`,xmlns:`http://www.w3.org/2000/svg`},[u(`path`,{d:`M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0 1 12 6.844a9.59 9.59 0 0 1 2.504.337c1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.02 10.02 0 0 0 22 12.017C22 6.484 17.522 2 12 2z`})],-1)]],8,Q)]),_:1},8,[`content`]),t(` NPM 链接 `),o(l,{content:a.$t(`@F13B4:在 npm 上查看包`),placement:`top`,effect:`dark`,"show-after":300},{default:E(()=>[u(`a`,{href:`https://www.npmjs.com/package/zen-gitsync`,target:`_blank`,rel:`noopener noreferrer`,class:`badge-icon-link badge-icon-link--npm`,"aria-label":a.$t(`@F13B4:在 npm 上查看包`)},[...r[2]||=[u(`svg`,{viewBox:`0 0 24 24`,width:`15`,height:`15`,"aria-hidden":`true`,fill:`currentColor`,xmlns:`http://www.w3.org/2000/svg`},[u(`path`,{d:`M2 2v20h20V2H2zm17.167 17.167H12.5v-10h-3.333v10H4.833V4.833h14.334v14.334z`})],-1)]],8,$)]),_:1},8,[`content`]),t(` 版本号 `),o(l,{content:a.$t(`@F13B4:查看更新`),placement:`top`,effect:`dark`,"show-after":300},{default:E(()=>[u(`a`,{href:a.releasesUrl,target:`_blank`,rel:`noopener noreferrer`,class:`version-link`},`v`+C(a.displayVersion),1)]),_:1},8,[`content`]),a.latestInfo?.hasUpdate?(e(),x(`button`,{key:0,type:`button`,class:`upgrade-btn`,title:a.$t(`@F13B4:发现新版本 {version},点击升级`,{version:a.latestInfo.latest??``}),"aria-label":a.$t(`@F13B4:发现新版本 {version},点击升级`,{version:a.latestInfo.latest??``}),onClick:a.handleUpgrade},[r[3]||=u(`span`,{class:`upgrade-btn__dot`,"aria-hidden":`true`},null,-1),u(`span`,te,C(a.$t(`@F13B4:升级`)),1),u(`span`,ne,`v`+C(a.latestInfo.latest),1)],8,ee)):t(`v-if`,!0),o(a.UpgradeDialog,{modelValue:a.upgradeDialogVisible,"onUpdate:modelValue":r[0]||=e=>a.upgradeDialogVisible=e,logs:a.upgradeLogs,status:a.upgradeStatus,countdown:a.countdown,onRetry:a.handleUpgrade,onRestart:a.handleRestart,onCancel:a.handleCancelAutoRefresh},null,8,[`modelValue`,`logs`,`status`,`countdown`])])}var ie=k(X,[[`render`,re],[`__scopeId`,`data-v-7e0300ec`],[`__file`,`C:/workspace/github_workspace/xz333221/zen-gitsync/src/ui/client/src/components/AppVersionBadge.vue`]]);export{ie as default};
@@ -0,0 +1 @@
1
+ import"./rolldown-runtime-C0FnF6B9.js";import{$n as e,An as t,Bt as n,Cn as r,Dn as i,F as a,G as o,Hn as s,I as c,In as l,J as u,K as d,Lr as f,On as p,Pt as m,Rn as h,Sr as g,U as _,Ut as v,Xr as y,fn as b,hr as x,jn as S,kn as C,ni as w,r as T,tr as E,tt as D,ur as O,xn as k}from"./element-plus-DgSY_Wt4.js";import{n as A,t as j}from"./_plugin-vue_export-helper-bQQyMRS6.js";import{t as M}from"./SvgIcon-DR_79iBR.js";import{t as N}from"./CommonDialog-zaBdFGFH.js";import{G as P,K as F}from"./index-BRQstBzy.js";s(),x();var I=h({__name:`BranchSelector`,emits:[`branchChanged`],setup(e,{expose:t,emit:r}){t();let a=P(),o=r,s=g(!1),c=g(``),l=i(()=>{let e=c.value.trim().toLowerCase();return e?a.allBranches.filter(t=>t.toLowerCase().includes(e)):a.allBranches});async function u(e){if(e===a.currentBranch){s.value=!1;return}s.value=!1,await a.changeBranch(e)&&(o(`branchChanged`),a.refreshLog())}let d=g(!1),f=g(``),p=g(``);function h(){s.value=!1,p.value=a.currentBranch,d.value=!0}async function _(){await a.createBranch(f.value,p.value)&&(d.value=!1,f.value=``,o(`branchChanged`))}let y=g(!1);async function b(){if(!y.value){y.value=!0;try{await Promise.all([a.getCurrentBranch(!0),a.getBranchStatus(!0),a.getAllBranches()]),o(`branchChanged`),a.refreshLog()}finally{y.value=!1}}}let x={gitStore:a,emit:o,branchPopoverVisible:s,branchFilter:c,filteredBranches:l,selectBranch:u,createBranchDialogVisible:d,newBranchName:f,selectedBaseBranch:p,openCreateBranchDialog:h,createNewBranch:_,isRefreshingBranch:y,refreshCurrentBranch:b,get $t(){return A},get Plus(){return n},get Menu(){return m},get Check(){return D},get Refresh(){return v},CommonDialog:N,IconButton:F,SvgIcon:M};return Object.defineProperty(x,"__isScriptSetup",{enumerable:!1,value:!0}),x}});s(),f(),b();var L={key:0,class:`branch-info`},R={class:`branch-wrapper`},z={class:`branch-btn`},B={class:`branch-btn-name`},V={class:`branch-btn-caret`},H={class:`branch-popover-inner`},U={class:`branch-search`},W={class:`branch-list`},G=[`onClick`],K={key:1,class:`branch-item-check-placeholder`},q={class:`branch-item-name`},J={key:0,class:`branch-empty`},Y={class:`branch-popover-footer`},X={class:`create-branch-content`},Z={class:`form-label`},Q={class:`form-label`},$={class:`dialog-footer`},ee={class:`footer-actions`},te=[`disabled`];function ne(n,i,s,f,m,h){let g=u,v=_,b=T,x=d,D=a,A=c,j=o;return f.gitStore.currentBranch?(e(),S(`div`,L,[p(`div`,R,[t(` VSCode 风格分支按钮 + 弹出列表 `),l(b,{visible:f.branchPopoverVisible,"onUpdate:visible":i[1]||=e=>f.branchPopoverVisible=e,placement:`top-start`,width:260,trigger:`click`,"popper-class":`branch-popover`,"show-arrow":!1,onShow:i[2]||=e=>f.branchFilter=``},{reference:O(()=>[p(`button`,z,[l(f.SvgIcon,{"icon-class":`git-branch`,"class-name":`branch-btn-icon`}),p(`span`,B,w(f.gitStore.currentBranch),1),p(`span`,V,[l(g,null,{default:O(()=>[...i[7]||=[p(`svg`,{viewBox:`0 0 1024 1024`,xmlns:`http://www.w3.org/2000/svg`},[p(`path`,{fill:`currentColor`,d:`M831.872 340.864 512 652.672 192.128 340.864a30.592 30.592 0 0 0-42.752 0 29.12 29.12 0 0 0 0 41.6L489.664 714.24a32 32 0 0 0 44.672 0l340.288-331.776a29.12 29.12 0 0 0 0-41.6 30.592 30.592 0 0 0-42.752 0z`})],-1)]]),_:1})])])]),default:O(()=>[p(`div`,H,[t(` 搜索框 `),p(`div`,U,[l(v,{modelValue:f.branchFilter,"onUpdate:modelValue":i[0]||=e=>f.branchFilter=e,placeholder:f.$t(`@F13B4:搜索或签出分支`),size:`small`,clearable:``,autofocus:``},null,8,[`modelValue`,`placeholder`])]),t(` 分支列表 `),p(`div`,W,[(e(!0),S(r,null,E(f.filteredBranches,t=>(e(),S(`div`,{key:t,class:y([`branch-item`,{"is-active":t===f.gitStore.currentBranch}]),onClick:e=>f.selectBranch(t)},[t===f.gitStore.currentBranch?(e(),C(g,{key:0,class:`branch-item-check`},{default:O(()=>[l(f.Check)]),_:1})):(e(),S(`span`,K)),l(f.SvgIcon,{"icon-class":`git-branch`,"class-name":`branch-item-icon`}),p(`span`,q,w(t),1)],10,G))),128)),f.filteredBranches.length===0?(e(),S(`div`,J,w(f.$t(`@F13B4:没有匹配的分支`)),1)):t(`v-if`,!0)]),t(` 底部:创建新分支 `),p(`div`,Y,[p(`button`,{class:`branch-create-btn`,onClick:f.openCreateBranchDialog},[l(g,null,{default:O(()=>[l(f.Plus)]),_:1}),p(`span`,null,w(f.$t(`@F13B4:创建新分支`)),1)])])])]),_:1},8,[`visible`]),t(` 刷新按钮 `),l(f.IconButton,{tooltip:f.$t(`@CMDCON:刷新`),onClick:f.refreshCurrentBranch},{default:O(()=>[l(g,{class:y({"is-loading":f.isRefreshingBranch})},{default:O(()=>[l(f.Refresh)]),_:1},8,[`class`])]),_:1},8,[`tooltip`])]),t(` 创建分支对话框 `),l(f.CommonDialog,{modelValue:f.createBranchDialogVisible,"onUpdate:modelValue":i[6]||=e=>f.createBranchDialogVisible=e,title:f.$t(`@F13B4:创建新分支`),size:`small`,"destroy-on-close":!0,"append-to-body":!0,"custom-class":`create-branch-dialog`},{footer:O(()=>[p(`div`,$,[p(`div`,ee,[p(`button`,{type:`button`,class:`dialog-cancel-btn`,onClick:i[5]||=e=>f.createBranchDialogVisible=!1},w(f.$t(`@F13B4:取消`)),1),p(`button`,{type:`button`,class:`dialog-confirm-btn`,onClick:f.createNewBranch,disabled:f.gitStore.isCreatingBranch},[f.gitStore.isCreatingBranch?(e(),C(g,{key:1,class:`is-loading`},{default:O(()=>[...i[8]||=[p(`svg`,{viewBox:`0 0 1024 1024`,xmlns:`http://www.w3.org/2000/svg`},[p(`path`,{fill:`currentColor`,d:`M512 64a32 32 0 0 1 32 32v192a32 32 0 0 1-64 0V96a32 32 0 0 1 32-32zm0 640a32 32 0 0 1 32 32v192a32 32 0 1 1-64 0V736a32 32 0 0 1 32-32zm448-192a32 32 0 0 1-32 32H736a32 32 0 1 1 0-64h192a32 32 0 0 1 32 32zm-640 0a32 32 0 0 1-32 32H96a32 32 0 0 1 0-64h192a32 32 0 0 1 32 32z`})],-1)]]),_:1})):(e(),C(g,{key:0},{default:O(()=>[l(f.Check)]),_:1})),p(`span`,null,w(f.$t(`@F13B4:创建`)),1)],8,te)])])]),default:O(()=>[p(`div`,X,[l(j,{model:{newBranchName:f.newBranchName,selectedBaseBranch:f.selectedBaseBranch},"label-position":`top`},{default:O(()=>[l(x,null,{label:O(()=>[p(`div`,Z,[l(g,{class:`label-icon`},{default:O(()=>[l(f.Plus)]),_:1}),p(`span`,null,w(f.$t(`@F13B4:新分支名称`)),1)])]),default:O(()=>[l(v,{modelValue:f.newBranchName,"onUpdate:modelValue":i[3]||=e=>f.newBranchName=e,placeholder:f.$t(`@F13B4:请输入新分支名称`),class:`modern-input`,size:`large`,onKeyup:k(f.createNewBranch,[`enter`])},null,8,[`modelValue`,`placeholder`])]),_:1}),l(x,null,{label:O(()=>[p(`div`,Q,[l(g,{class:`label-icon`},{default:O(()=>[l(f.Menu)]),_:1}),p(`span`,null,w(f.$t(`@F13B4:基于分支`)),1)])]),default:O(()=>[l(A,{modelValue:f.selectedBaseBranch,"onUpdate:modelValue":i[4]||=e=>f.selectedBaseBranch=e,placeholder:f.$t(`@F13B4:选择基础分支`),class:`modern-select`,size:`large`,style:{width:`100%`}},{default:O(()=>[(e(!0),S(r,null,E(f.gitStore.allBranches,t=>(e(),C(D,{key:t,label:t,value:t},null,8,[`label`,`value`]))),128))]),_:1},8,[`modelValue`,`placeholder`])]),_:1})]),_:1},8,[`model`])])]),_:1},8,[`modelValue`,`title`])])):t(`v-if`,!0)}var re=j(I,[[`render`,ne],[`__scopeId`,`data-v-9548a76f`],[`__file`,`C:/workspace/github_workspace/xz333221/zen-gitsync/src/ui/client/src/components/BranchSelector.vue`]]);export{re as default};