zen-gitsync 2.17.5 → 2.17.7

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 (71) hide show
  1. package/README.md +35 -2
  2. package/package.json +1 -1
  3. package/scripts/release.js +139 -48
  4. package/src/aiCommit.js +6 -3
  5. package/src/cli/ai/agent.js +106 -311
  6. package/src/cli/ai/cli.integration.test.js +99 -0
  7. package/src/cli/ai/context.js +90 -0
  8. package/src/cli/ai/modelSetup.js +44 -8
  9. package/src/cli/ai/runtime.test.js +152 -0
  10. package/src/cli/ai/safety.js +27 -4
  11. package/src/cli/ai/safety.test.js +13 -0
  12. package/src/cli/ai/telemetry.js +43 -0
  13. package/src/cli/ai/termui.js +154 -41
  14. package/src/cli/ai/termui.test.js +63 -14
  15. package/src/cli/ai/tools.js +27 -5
  16. package/src/cli/ai/tools.test.js +23 -0
  17. package/src/cli/ai/transport.js +89 -0
  18. package/src/cli/ai/turn.js +126 -0
  19. package/src/config.js +88 -5
  20. package/src/ui/public/assets/{AgentView-DJOdvJEV.js → AgentView-CZc191Xm.js} +3 -3
  21. package/src/ui/public/assets/AgentView-CzUeyQfR.css +1 -0
  22. package/src/ui/public/assets/{AppVersionBadge-D2Li5_R-.js → AppVersionBadge-Gs5lUl7P.js} +2 -2
  23. package/src/ui/public/assets/{BranchSelector-CSd5uaVm.js → BranchSelector-IjaFk0S-.js} +1 -1
  24. package/src/ui/public/assets/{CommitForm-Ckg9-zay.js → CommitForm-C-sowOXH.js} +3 -3
  25. package/src/ui/public/assets/{CommonDialog-B8XOXtz_.js → CommonDialog-QyptFD1R.js} +1 -1
  26. package/src/ui/public/assets/{EditorView-Crj8S2TI.js → EditorView-CvvluFCY.js} +1 -1
  27. package/src/ui/public/assets/{FileDiffViewer-DL07IMz5.js → FileDiffViewer-BXVsdCxE.js} +1 -1
  28. package/src/ui/public/assets/{FlowExecutionViewer-DvVT19Qv.js → FlowExecutionViewer-CRxipXru.js} +1 -1
  29. package/src/ui/public/assets/{FlowOrchestrationWorkspace-kRhK9IyL.js → FlowOrchestrationWorkspace-AE1ZHTKF.js} +1 -1
  30. package/src/ui/public/assets/{IconButton-pqSYKRT8.js → IconButton-BmSueF_H.js} +1 -1
  31. package/src/ui/public/assets/{LogList-BrN6qtFb.js → LogList-iaVA-_aC.js} +1 -1
  32. package/src/ui/public/assets/{MindmapView-CSsT0NDZ.js → MindmapView-DcG4jpCh.js} +1 -1
  33. package/src/ui/public/assets/{MonitorView-edRyBybQ.js → MonitorView-DO59syvl.js} +1 -1
  34. package/src/ui/public/assets/{ProjectStartupButton-DZ8VgU79.js → ProjectStartupButton-DYppceyw.js} +1 -1
  35. package/src/ui/public/assets/{RemoteManagerDialog-pu9szuYB.js → RemoteManagerDialog-CDbxG6pZ.js} +1 -1
  36. package/src/ui/public/assets/{RemoteRepoCard-BSFehgY5.js → RemoteRepoCard-Cko2KB8w.js} +1 -1
  37. package/src/ui/public/assets/{SourceMapView-DbEydLSU.js → SourceMapView-CwWPVdz-.js} +1 -1
  38. package/src/ui/public/assets/{SvgIcon-BVCbrPws.js → SvgIcon-Cf7nOKc8.js} +1 -1
  39. package/src/ui/public/assets/{TemplateManager-DPyYaGCE.js → TemplateManager-DWPDjWxM.js} +1 -1
  40. package/src/ui/public/assets/{UserInputNode-DXHeCjzG.js → UserInputNode-YOziN-5A.js} +1 -1
  41. package/src/ui/public/assets/WorkbenchView-DNnEpIYy.js +13 -0
  42. package/src/ui/public/assets/WorkbenchView-v3QFn6Ln.css +1 -0
  43. package/src/ui/public/assets/_plugin-vue_export-helper-CQjg8MXm.js +19 -0
  44. package/src/ui/public/assets/configStore-C7HOx5S1.js +1 -0
  45. package/src/ui/public/assets/{gitStore-BJbNtjxA.js → gitStore-DIsBd6n4.js} +1 -1
  46. package/src/ui/public/assets/index-FOe1cHkh.css +1 -0
  47. package/src/ui/public/assets/index-MmcnT2Dn.js +24 -0
  48. package/src/ui/public/assets/{previewSandbox-BZV6Eqhv.js → previewSandbox-TKucqLxt.js} +0 -0
  49. package/src/ui/public/assets/{toolsStore-Bu8Ujw_A.js → toolsStore-BiC2mmC3.js} +1 -1
  50. package/src/ui/public/assets/{vendor-CwZs6S_i.js → vendor-92fKgtnz.js} +7 -7
  51. package/src/ui/public/assets/{vendor-_6pgW9Z2.css → vendor-B1UrVTTI.css} +1 -1
  52. package/src/ui/public/index.html +14 -14
  53. package/src/ui/server/routes/codeAnalysis.js +6 -3
  54. package/src/ui/server/routes/config.js +40 -9
  55. package/src/ui/server/routes/fileOpen.js +48 -2
  56. package/src/ui/server/routes/gAiLauncher.test.js +70 -0
  57. package/src/ui/server/routes/workbench/agentChat.js +34 -8
  58. package/src/ui/server/routes/workbench/index.js +37 -6
  59. package/src/ui/server/routes/workbench/jobStore.js +4 -0
  60. package/src/ui/server/routes/workbench/llmClient.js +15 -8
  61. package/src/ui/server/routes/workbench/taskRunner.js +276 -96
  62. package/src/ui/server/routes/workbench/taskRunner.opencode.test.js +126 -0
  63. package/src/utils/aiEndpoint.js +231 -0
  64. package/src/utils/aiEndpoint.test.js +175 -0
  65. package/src/ui/public/assets/AgentView-BsN9y4Kg.css +0 -1
  66. package/src/ui/public/assets/WorkbenchView-CKXtZAJn.css +0 -1
  67. package/src/ui/public/assets/WorkbenchView-DGcirla3.js +0 -13
  68. package/src/ui/public/assets/_plugin-vue_export-helper-C-YBnnP5.js +0 -19
  69. package/src/ui/public/assets/configStore-DoobmT7N.js +0 -1
  70. package/src/ui/public/assets/index-ClqvC4kJ.css +0 -1
  71. package/src/ui/public/assets/index-ndDaGoRO.js +0 -24
@@ -0,0 +1,89 @@
1
+ import { TOOL_DEFINITIONS } from './tools.js'
2
+ import { buildAiChatRequest, describeAiHttpError } from '../../utils/aiEndpoint.js'
3
+ import { normalizeUsage } from './telemetry.js'
4
+
5
+ // Some compatible gateways reject stream_options. Remember that for this process.
6
+ const withoutStreamUsage = new Set()
7
+
8
+ export async function streamChatOnce({ model, messages, signal, onToken = () => {}, sessionId,
9
+ fetchFn = fetch, timeoutMs = 300000 }) {
10
+ const { url, headers } = buildAiChatRequest({ ...model, sessionId })
11
+ const providerKey = `${url}\n${model.model}`
12
+ const body = { model: model.model, messages, tools: TOOL_DEFINITIONS, temperature: 0.3, stream: true }
13
+ if (!withoutStreamUsage.has(providerKey)) body.stream_options = { include_usage: true }
14
+ const controller = new AbortController()
15
+ let timedOut = false
16
+ const timer = setTimeout(() => { timedOut = true; controller.abort() }, timeoutMs)
17
+ const onAbort = () => controller.abort()
18
+ if (signal?.aborted) controller.abort()
19
+ else signal?.addEventListener('abort', onAbort)
20
+ let content = '', reasoning = '', usage = null, finished = false
21
+ const toolCalls = []
22
+
23
+ const consumeLine = line => {
24
+ const trimmed = line.trim()
25
+ if (!trimmed.startsWith('data:')) return
26
+ const payload = trimmed.slice(5).trim()
27
+ if (payload === '[DONE]') { finished = true; return }
28
+ if (!payload) return
29
+ let evt
30
+ try { evt = JSON.parse(payload) } catch { throw new Error('Invalid JSON in model stream') }
31
+ if (evt.error) throw new Error(evt.error.message || 'Model stream failed')
32
+ // Usage may arrive after finish_reason, in a final event with choices: [].
33
+ // Events report snapshots, so replace fields instead of summing snapshots.
34
+ const nextUsage = normalizeUsage(evt.usage)
35
+ if (nextUsage) usage = Object.fromEntries(Object.entries(nextUsage).map(([key, value]) => [key, value ?? usage?.[key] ?? null]))
36
+ if (evt.choices?.[0]?.finish_reason) finished = true
37
+ const delta = evt.choices?.[0]?.delta || {}
38
+ const thinking = delta.reasoning_content || delta.reasoning || delta.reasoning_text || ''
39
+ if (thinking) { reasoning += thinking; onToken({ thinking }) }
40
+ if (delta.content) { content += delta.content; onToken({ content: delta.content }) }
41
+ for (const tc of delta.tool_calls || []) {
42
+ const i = tc.index ?? 0
43
+ if (!Number.isInteger(i) || i < 0 || i > 1024) throw new Error('Invalid tool call index')
44
+ if (!toolCalls[i]) toolCalls[i] = { id: '', type: 'function', function: { name: '', arguments: '' } }
45
+ if (tc.id) toolCalls[i].id += tc.id
46
+ if (tc.function?.name) toolCalls[i].function.name += tc.function.name
47
+ if (tc.function?.arguments) toolCalls[i].function.arguments += tc.function.arguments
48
+ }
49
+ if (delta.tool_calls?.length) onToken({ toolCalls: true })
50
+ }
51
+ try {
52
+ const request = () => fetchFn(url, { method: 'POST', headers, body: JSON.stringify(body), signal: controller.signal })
53
+ let resp = await request()
54
+ if (!resp.ok) {
55
+ const detail = describeAiHttpError(await resp.text().catch(() => ''), resp.status)
56
+ if ([400, 422].includes(resp.status) && body.stream_options && /stream_options|include_usage/i.test(detail)) {
57
+ delete body.stream_options
58
+ withoutStreamUsage.add(providerKey)
59
+ resp = await request()
60
+ } else throw new Error(`HTTP ${resp.status}: ${detail || resp.statusText}`)
61
+ }
62
+ if (!resp.ok || !resp.body) {
63
+ throw new Error(`HTTP ${resp.status}: ${describeAiHttpError(await resp.text().catch(() => ''), resp.status) || resp.statusText}`)
64
+ }
65
+ const decoder = new TextDecoder()
66
+ let buf = ''
67
+ for await (const chunk of resp.body) {
68
+ buf += decoder.decode(chunk, { stream: true })
69
+ const lines = buf.split('\n')
70
+ buf = lines.pop() ?? ''
71
+ for (const line of lines) consumeLine(line)
72
+ }
73
+ buf += decoder.decode()
74
+ if (buf.trim()) consumeLine(buf)
75
+ if (controller.signal.aborted) throw new DOMException('Aborted', 'AbortError')
76
+ if (!finished) throw new Error('模型响应意外中断,请重试;未执行不完整的工具调用。')
77
+ return { content, reasoning, toolCalls: toolCalls.filter(Boolean), usage, aborted: false }
78
+ } catch (err) {
79
+ if (controller.signal.aborted && !timedOut) {
80
+ return { content, reasoning, toolCalls: [], usage, aborted: true }
81
+ }
82
+ const error = timedOut ? new Error('模型响应超时,请重试或切换模型。') : err
83
+ error.usage = usage
84
+ throw error
85
+ } finally {
86
+ clearTimeout(timer)
87
+ signal?.removeEventListener('abort', onAbort)
88
+ }
89
+ }
@@ -0,0 +1,126 @@
1
+ import { executeTool } from './tools.js'
2
+ import { streamChatOnce } from './transport.js'
3
+ import { createThinkFilter } from './streamFilter.js'
4
+ import { imageToDataUrl } from './images.js'
5
+ import { buildRequestMessages } from './context.js'
6
+ import { createTurnStats, addUsage, accumulateSessionStats } from './telemetry.js'
7
+ import * as terminal from './termui.js'
8
+
9
+ export async function runAgentTurn(state, userText, t, images = [], dependencies = {}) {
10
+ const chat = dependencies.chat || streamChatOnce
11
+ const execute = dependencies.execute || executeTool
12
+ const ui = { ...terminal, ...dependencies.ui }
13
+ const stats = createTurnStats()
14
+ const started = performance.now()
15
+ const cancelled = () => state.cancelRequested || state.abortController?.signal.aborted
16
+ const checkpoint = () => state.persistSession?.()
17
+ const recordUsage = usage => {
18
+ if (!usage) return
19
+ stats.usageRequests++
20
+ stats.usage = addUsage(stats.usage, usage)
21
+ }
22
+ try {
23
+ let userContent = userText
24
+ if (images.length) {
25
+ userContent = [{ type: 'text', text: userText }]
26
+ for (const img of images) {
27
+ try { userContent.push({ type: 'image_url', image_url: { url: await imageToDataUrl(img.path) } }) }
28
+ catch { ui.printWarn(t.imageBadPath(img.path)) }
29
+ }
30
+ }
31
+ state.messages.push({ role: 'user', content: userContent })
32
+ await checkpoint()
33
+ const maxIterations = state.maxToolIterations > 0 ? state.maxToolIterations : 200
34
+ for (let iter = 0; iter < maxIterations; iter++) {
35
+ if (cancelled()) { stats.status = 'cancelled'; return stats }
36
+ const spinner = ui.startSpinner(t.waiting)
37
+ const writer = ui.createAssistantWriter({
38
+ showThinking: state.showThinking !== false,
39
+ thinkingHeader: t.thinkingLabel,
40
+ answerHeader: t.answerLabel,
41
+ thinkingLimit: state.thinkingMode === 'full' ? Infinity : 4,
42
+ thinkingHint: t.thinkingHint,
43
+ })
44
+ const filter = createThinkFilter()
45
+ const render = seg => {
46
+ if (seg.content) {
47
+ if (seg.content.trim() && stats.firstAnswerMs === null) stats.firstAnswerMs = performance.now() - started
48
+ writer.writeContent(seg.content)
49
+ } else if (seg.thinking) writer.writeThinking(seg.thinking)
50
+ }
51
+ let result
52
+ const llmStart = performance.now()
53
+ stats.requests++
54
+ try {
55
+ const messages = buildRequestMessages(state.messages)
56
+ state.prepareMessages?.(messages)
57
+ result = await chat({ model: state.model, messages, signal: state.abortController?.signal,
58
+ sessionId: state.sessionId, onToken: token => {
59
+ if (stats.firstTokenMs === null) stats.firstTokenMs = performance.now() - started
60
+ if (token.content || (token.thinking && state.showThinking !== false)) spinner.stop()
61
+ if (token.thinking) render({ thinking: token.thinking })
62
+ if (token.content) filter.feed(token.content).forEach(render)
63
+ } })
64
+ recordUsage(result.usage)
65
+ } catch (err) {
66
+ recordUsage(err.usage)
67
+ throw err
68
+ } finally {
69
+ stats.llmMs += performance.now() - llmStart
70
+ spinner.stop()
71
+ filter.flush().forEach(render)
72
+ writer.finish()
73
+ }
74
+ if (result.aborted || cancelled()) {
75
+ if (result.content) state.messages.push({ role: 'assistant', content: result.content })
76
+ stats.status = 'cancelled'; return stats
77
+ }
78
+ const { content, toolCalls } = result
79
+ const assistant = { role: 'assistant', content: content || null }
80
+ if (result.reasoning) assistant.reasoning_content = result.reasoning
81
+ if (!toolCalls.length) {
82
+ if (!content?.trim()) throw new Error(t.emptyResponse)
83
+ state.messages.push(assistant)
84
+ stats.status = 'completed'; return stats
85
+ }
86
+ // Assign fallback IDs once, so every result references its assistant call.
87
+ toolCalls.forEach((call, i) => { if (!call.id) call.id = `call_${iter}_${i}` })
88
+ state.messages.push({ ...assistant, tool_calls: toolCalls })
89
+ await checkpoint()
90
+ for (const tc of toolCalls) {
91
+ const name = tc.function?.name || ''
92
+ let output
93
+ if (cancelled()) output = 'Cancelled by user; this tool was not executed.'
94
+ else {
95
+ let args
96
+ try { args = JSON.parse(tc.function?.arguments || '{}') }
97
+ catch { output = '错误: 工具参数不是合法 JSON,请修正后重试。' }
98
+ if (output === undefined) {
99
+ ui.printToolHeader(name, ui.summarizeToolArgs(name, args, { chars: t.chars }), undefined, { locale: state.locale })
100
+ const toolSpinner = ui.startSpinner(t.toolRunning(name))
101
+ const toolStart = performance.now()
102
+ stats.toolCalls++
103
+ try { output = await execute(name, args, { ...state.ctx, signal: state.abortController?.signal }) }
104
+ finally { toolSpinner.stop(); stats.toolsMs += performance.now() - toolStart }
105
+ ui.printToolResult(output, undefined, performance.now() - toolStart, { full: state.fullTools, locale: state.locale })
106
+ } else ui.printToolResult(output)
107
+ }
108
+ state.messages.push({ role: 'tool', tool_call_id: tc.id, name, content: output })
109
+ await checkpoint()
110
+ }
111
+ }
112
+ stats.status = cancelled() ? 'cancelled' : 'limit'
113
+ if (!cancelled()) ui.printWarn(t.toolIterLimit(maxIterations))
114
+ } catch (err) {
115
+ stats.status = cancelled() ? 'cancelled' : 'failed'
116
+ if (!cancelled()) ui.printError(t.llmError(err.message))
117
+ } finally {
118
+ stats.totalMs = performance.now() - started
119
+ stats.completedAt = new Date().toISOString()
120
+ state.lastTurnStats = stats
121
+ state.sessionStats = accumulateSessionStats(state.sessionStats, stats)
122
+ await checkpoint()
123
+ ui.printTurnSummary(stats, { locale: state.locale })
124
+ }
125
+ return stats
126
+ }
package/src/config.js CHANGED
@@ -50,6 +50,43 @@ function resolveConfigPath() {
50
50
  return _configPathReady;
51
51
  }
52
52
 
53
+ // AI 智能体单轮工具调用上限的可调范围。
54
+ // 下限 1 是为了保留"防失控"语义 —— 0 会让智能体一动手就停,没人是这个意图;
55
+ // 上限 2000 是防手改配置写成天文数字后,一轮对话把 API 额度烧光。
56
+ const AI_MAX_TOOL_ITERATIONS_MIN = 1;
57
+ const AI_MAX_TOOL_ITERATIONS_MAX = 2000;
58
+
59
+ /**
60
+ * 规范化单轮最大工具调用次数。
61
+ *
62
+ * 非法值(非数字 / NaN / 越界)一律**夹取**到合法区间而不是回退默认值 ——
63
+ * 用户手改成 5000 的意图明显是"想更大",夹到 2000 比悄悄退回 200 更贴近意图。
64
+ * 完全无法解析(undefined / 'abc')才返回 null,交给调用方取默认值。
65
+ */
66
+ function normalizeAiMaxToolIterations(value) {
67
+ if (value === undefined || value === null || value === '') return null;
68
+ const n = Number(value);
69
+ if (!Number.isFinite(n)) return null;
70
+ const int = Math.floor(n);
71
+ if (int < AI_MAX_TOOL_ITERATIONS_MIN) return AI_MAX_TOOL_ITERATIONS_MIN;
72
+ if (int > AI_MAX_TOOL_ITERATIONS_MAX) return AI_MAX_TOOL_ITERATIONS_MAX;
73
+ return int;
74
+ }
75
+
76
+ // 工作台任务执行器白名单。'claude' 是历史默认;'opencode' 为可选执行器
77
+ // (opencode run --format json,模型跟随 opencode 自身配置)。
78
+ export const TASK_EXECUTORS = ['claude', 'opencode'];
79
+
80
+ /**
81
+ * 规范化任务执行器。非法值返回 null(交给调用方取默认),不抛错 ——
82
+ * 与 normalizeAiMaxToolIterations 同一套"夹取/兜底"语义。
83
+ */
84
+ export function normalizeTaskExecutor(value) {
85
+ if (typeof value !== 'string') return null;
86
+ const v = value.trim().toLowerCase();
87
+ return TASK_EXECUTORS.includes(v) ? v : null;
88
+ }
89
+
53
90
  // 默认配置
54
91
  const defaultConfig = {
55
92
  defaultCommitMessage: "submit",
@@ -90,6 +127,15 @@ const defaultConfig = {
90
127
  locale: 'zh-CN', // 语言: zh-CN | en-US
91
128
  // AI 模型配置
92
129
  models: [],
130
+ // AI 智能体单轮最大工具调用次数(防失控)。CLI `g ai` 与 Web 智能体共用,全局生效。
131
+ // 2026-09-20: 40 → 200。40 轮在"读多个文件 → 逐个验证 → 再改"这类任务里很容易触顶,
132
+ // 触顶后本轮被强制结束,用户必须再发一条消息才能接着跑,体感像被截断。
133
+ // 想调小/调大改这个值即可(GUI: 设置 → AI 模型配置)。
134
+ aiMaxToolIterations: 200,
135
+ // 工作台任务执行器(claude | opencode)。全局配置,跨项目共享。
136
+ // 决定「执行任务 / 执行子任务 / 从此处开始 / 简单任务续聊」这条链路
137
+ // 默认 spawn 哪个本地 CLI;执行入口可以按次覆盖(见 workbench 执行路由)。
138
+ taskExecutor: 'claude',
93
139
  // UI 状态(跨项目共享,存到顶层 ui 对象)
94
140
  // 之前散落在 localStorage,因随机端口启动而失效,迁到文件持久化
95
141
  ui: {
@@ -128,7 +174,9 @@ function getCurrentProjectKey() {
128
174
  }
129
175
  let key = null;
130
176
  try {
131
- const gitRoot = execSync('git rev-parse --show-toplevel', { encoding: 'utf8' }).trim();
177
+ const gitRoot = execSync('git rev-parse --show-toplevel', {
178
+ encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'], timeout: 5000, windowsHide: true,
179
+ }).trim();
132
180
  if (gitRoot) key = normalizeProjectPath(gitRoot);
133
181
  } catch (_) {
134
182
  // 非 Git 项目或 git 不可用,降级到 CWD
@@ -396,7 +444,13 @@ async function loadConfig() {
396
444
  }
397
445
  // 兼容旧版(全局扁平结构)
398
446
  if (raw && !raw.projects) {
399
- return { ...defaultConfig, ...raw };
447
+ return {
448
+ ...defaultConfig,
449
+ ...raw,
450
+ aiMaxToolIterations: normalizeAiMaxToolIterations(raw.aiMaxToolIterations)
451
+ ?? defaultConfig.aiMaxToolIterations,
452
+ taskExecutor: normalizeTaskExecutor(raw.taskExecutor) ?? defaultConfig.taskExecutor
453
+ };
400
454
  }
401
455
 
402
456
  // 新版结构:{ projects: { [key]: projectConfig }, theme?, locale?, ui?, recentDirectories? }
@@ -409,7 +463,11 @@ async function loadConfig() {
409
463
  theme: raw?.theme ?? defaultConfig.theme,
410
464
  locale: raw?.locale ?? defaultConfig.locale,
411
465
  models: raw?.models ?? defaultConfig.models,
412
- ui: raw?.ui ?? defaultConfig.ui
466
+ ui: raw?.ui ?? defaultConfig.ui,
467
+ // 同 models:全局配置,始终取顶层,防止被项目配置里的旧值覆盖
468
+ aiMaxToolIterations: normalizeAiMaxToolIterations(raw?.aiMaxToolIterations)
469
+ ?? defaultConfig.aiMaxToolIterations,
470
+ taskExecutor: normalizeTaskExecutor(raw?.taskExecutor) ?? defaultConfig.taskExecutor
413
471
  };
414
472
  }
415
473
 
@@ -457,7 +515,7 @@ async function saveConfig(config) {
457
515
 
458
516
  // 分离全局设置和项目设置
459
517
  // models / ui 也是全局配置(跨项目共享),和 theme/locale 一样存到顶层
460
- const { theme, locale, models, ui, ...projectConfig } = config;
518
+ const { theme, locale, models, ui, aiMaxToolIterations, taskExecutor, ...projectConfig } = config;
461
519
 
462
520
  // 保存全局设置到根级别
463
521
  if (theme !== undefined) {
@@ -472,6 +530,16 @@ async function saveConfig(config) {
472
530
  if (ui !== undefined) {
473
531
  raw.ui = ui;
474
532
  }
533
+ // 工具调用上限同属全局设置:非法值不落盘(保留磁盘上的旧值),避免把手改坏的值固化
534
+ const normalizedIterations = normalizeAiMaxToolIterations(aiMaxToolIterations);
535
+ if (normalizedIterations !== null) {
536
+ raw.aiMaxToolIterations = normalizedIterations;
537
+ }
538
+ // 任务执行器同属全局设置:白名单外的值不落盘
539
+ const normalizedExecutor = normalizeTaskExecutor(taskExecutor);
540
+ if (normalizedExecutor !== null) {
541
+ raw.taskExecutor = normalizedExecutor;
542
+ }
475
543
 
476
544
  // 写入当前项目配置(在 defaultConfig 基础上合并,但不清空顶层其它键)
477
545
  const existingProjectConfig = (raw.projects[key] && typeof raw.projects[key] === 'object') ? raw.projects[key] : {};
@@ -662,7 +730,22 @@ export default {
662
730
  // 显式删除某个项目的全部分文件。写路径刻意不做删除(防"只加载了一个项目就写回"
663
731
  // 连带清空其它项目),清理失效项目只能走这里。
664
732
  deleteProjectConfig: deleteProjectConfigAndInvalidate,
733
+ // AI 智能体单轮工具调用上限的规范化/区间(GUI 保存前也要用,见 /api/config/save-ai-settings)
734
+ normalizeAiMaxToolIterations,
735
+ AI_MAX_TOOL_ITERATIONS_MIN,
736
+ AI_MAX_TOOL_ITERATIONS_MAX,
737
+ // 工作台任务执行器规范化(GUI 保存前也要用,见 /api/config/save-general-settings)
738
+ normalizeTaskExecutor,
739
+ TASK_EXECUTORS,
665
740
  };
666
741
 
667
742
  // 命名导出 — 用于测试与外部复用
668
- export { ConfigWriteError, normalizeProjectPath, invalidateCurrentProjectKey, invalidateRawConfigCache };
743
+ export {
744
+ ConfigWriteError,
745
+ normalizeProjectPath,
746
+ invalidateCurrentProjectKey,
747
+ invalidateRawConfigCache,
748
+ normalizeAiMaxToolIterations,
749
+ AI_MAX_TOOL_ITERATIONS_MIN,
750
+ AI_MAX_TOOL_ITERATIONS_MAX,
751
+ };
@@ -1,4 +1,4 @@
1
- import"./rolldown-runtime-C0FnF6B9.js";import{$n as e,At as t,Bn as n,Dn as r,En as i,Er as a,G as o,Gt as s,In as c,On as l,Pn as u,Pr as d,Qr as f,Tn as p,Wn as m,Y as h,Yr as g,Zn as _,_n as ee,a as v,bn as te,br as y,cn as ne,cr as b,gt as x,i as S,kn as C,lr as w,o as re,or as T,pr as E,qr as D,tt as ie,un as O,ut as ae,vr as k,xn as oe,zt as se}from"./element-plus-KTmRV-so.js";import{a as ce,r as A,t as j}from"./vendor-CwZs6S_i.js";import{n as M,t as N}from"./_plugin-vue_export-helper-C-YBnnP5.js";import{t as P}from"./configStore-DoobmT7N.js";E();var F=65536;function I(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:z(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>F&&(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||A(),name:e.function?.name||``,arguments:e.function?.arguments||``,argsPreview:L(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>F&&(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 L(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 R(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 z(e){let t=/^data:([^;,]+)/.exec(e);return t?t[1]:``}function B(){let e=P(),t=y([]),n=y(!1),r=y(null),i=y([]),a=y(!1),o=y(!1),s=null,c=0,l=0;async function u(){let r=++l,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!==l)return;if(!n.success){v.error(n.error||M(`@AGENT:加载会话列表失败`));return}t.value=Array.isArray(n.sessions)?n.sessions:[]}catch(e){if(r!==l)return;v.error(M(`@AGENT:加载会话列表失败`)+`: `+(e?.message||e))}finally{r===l&&(n.value=!1)}}async function d(e){o.value=!0,r.value=e;try{let t=await fetch(`/api/agent/sessions/${encodeURIComponent(e)}`).then(e=>e.json());if(!t.success){v.error(t.error||M(`@AGENT:加载会话失败`));return}i.value=I(t.session)}catch(e){v.error(M(`@AGENT:加载会话失败`)+`: `+(e?.message||e))}finally{o.value=!1}}async function f(e){try{await S.confirm(M(`@AGENT:确认删除该会话`),M(`@AGENT:删除后无法恢复`),{type:`warning`})}catch{return}try{let n=await fetch(`/api/agent/sessions/${encodeURIComponent(e)}`,{method:`DELETE`}).then(e=>e.json());if(!n.success){v.error(n.error||M(`@AGENT:删除失败`));return}t.value=t.value.filter(t=>t.sessionId!==e),r.value===e&&(r.value=null,i.value=[]),v.success(M(`@AGENT:已删除`))}catch(e){v.error(M(`@AGENT:删除失败`)+`: `+(e?.message||e))}}async function p(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){v.error(r.error||M(`@AGENT:重命名失败`));return}let i=t.value.find(t=>t.sessionId===e);i&&(i.title=n),v.success(M(`@AGENT:已重命名`))}catch(e){v.error(M(`@AGENT:重命名失败`)+`: `+(e?.message||e))}}function m(){r.value=null,i.value=[]}async function h(t,n=[]){let o=n.filter(e=>e?.file?.type?.startsWith(`image/`));if(o.length<n.length&&v.warning(M(`@AGENT:仅支持发送图片,非图片文件已忽略`)),!t.trim()&&o.length===0||a.value)return;let l=(await Promise.allSettled(o.map(e=>R(e.file)))).map(e=>e.status===`fulfilled`?e.value:``).filter(e=>e.startsWith(`data:image/`)),d=++c;s=new AbortController;let f=s,p={id:A(),role:`user`,content:t,status:`done`,createdAt:Date.now()};o.length>0&&(p.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(p);let m=k({id:A(),role:`assistant`,content:``,status:`pending`,createdAt:Date.now()});i.value.push(m),a.value=!0;let h=[];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||``,...l.length>0?{images:l}:{}}),signal:f.signal});if(d!==c)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`),s=``,p=r.value;for(;;){let{value:e,done:t}=await a.read();if(d!==c)return;if(t)break;s+=o.decode(e,{stream:!0});let n=s.split(`
2
- `);s=n.pop()??``;for(let e of n){let t=e.trim();if(!t.startsWith(`data:`))continue;let n=t.slice(5).trim();if(!n)continue;let i;try{i=JSON.parse(n)}catch{continue}switch(i.type){case`meta`:i.sessionId&&(p=i.sessionId,r.value=i.sessionId);break;case`thinking`:m.reasoning||(m.reasoning=``,m.reasoningStatus=`streaming`),m.reasoning+=String(i.delta||``),m.status=`streaming`;break;case`content`:m.status===`pending`&&(m.status=`streaming`);{let e=String(i.delta||``);m.content+=e;let t=j(m.content);t.reasoning&&(m.reasoning||(m.reasoning=``,m.reasoningStatus=`streaming`),m.reasoning=t.reasoning,m.content=t.content)}break;case`tool_call_start`:{let e=k({id:i.toolCallId||A(),name:i.name||``,argsPreview:i.argsPreview||``,arguments:i.argsPreview||``,status:`running`,result:``});h.push(e),m.toolCalls||=[],m.toolCalls.push(e),m.status===`pending`&&(m.status=`streaming`);break}case`tool_result`:{let e=h.find(e=>e.id===i.toolCallId);e&&(e.result=String(i.result||``),e.status=`done`);break}case`done`:{let e=i.content||m.content,t=j(e);t.reasoning&&!m.reasoning&&(m.reasoning=t.reasoning),m.content=t.content,m.status=`done`,m.reasoningStatus===`streaming`&&(m.reasoningStatus=`done`);break}case`error`:m.status=`error`,m.error=String(i.error||M(`@AGENT:未知错误`)),m.reasoningStatus===`streaming`&&(m.reasoningStatus=`done`)}}i.value=[...i.value]}if(d!==c)return;m.status===`pending`&&(m.status=`done`),p&&p!==r.value&&(r.value=p),u().catch(()=>{})}catch(e){if(d!==c)return;e?.name===`AbortError`||f.signal.aborted?(m.content=(m.content||``)+`
1
+ import"./rolldown-runtime-C0FnF6B9.js";import{$n as e,At as t,Bn as n,Dn as r,En as i,Er as a,G as o,Gt as s,In as c,On as l,Pn as u,Pr as d,Qr as f,Tn as p,Wn as m,Y as h,Yr as g,Zn as _,_n as ee,a as v,bn as te,br as y,cn as ne,cr as b,gt as re,i as x,kn as S,lr as C,o as ie,or as w,pr as T,qr as E,tt as D,un as O,ut as ae,vr as k,xn as oe,zt as se}from"./element-plus-KTmRV-so.js";import{a as A,n as j,r as ce}from"./vendor-92fKgtnz.js";import{n as M,t as N}from"./_plugin-vue_export-helper-CQjg8MXm.js";import{t as P}from"./configStore-C7HOx5S1.js";T();var F=65536;function I(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:z(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>F&&(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||j(),name:e.function?.name||``,arguments:e.function?.arguments||``,argsPreview:L(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>F&&(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 L(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 R(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 z(e){let t=/^data:([^;,]+)/.exec(e);return t?t[1]:``}function B(){let e=P(),t=y([]),n=y(!1),r=y(null),i=y([]),a=y(!1),o=y(!1),s=null,c=0,l=0;async function u(){let r=++l,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!==l)return;if(!n.success){v.error(n.error||M(`@AGENT:加载会话列表失败`));return}t.value=Array.isArray(n.sessions)?n.sessions:[]}catch(e){if(r!==l)return;v.error(M(`@AGENT:加载会话列表失败`)+`: `+(e?.message||e))}finally{r===l&&(n.value=!1)}}async function d(e){o.value=!0,r.value=e;try{let t=await fetch(`/api/agent/sessions/${encodeURIComponent(e)}`).then(e=>e.json());if(!t.success){v.error(t.error||M(`@AGENT:加载会话失败`));return}i.value=I(t.session)}catch(e){v.error(M(`@AGENT:加载会话失败`)+`: `+(e?.message||e))}finally{o.value=!1}}async function f(e){try{await x.confirm(M(`@AGENT:确认删除该会话`),M(`@AGENT:删除后无法恢复`),{type:`warning`})}catch{return}try{let n=await fetch(`/api/agent/sessions/${encodeURIComponent(e)}`,{method:`DELETE`}).then(e=>e.json());if(!n.success){v.error(n.error||M(`@AGENT:删除失败`));return}t.value=t.value.filter(t=>t.sessionId!==e),r.value===e&&(r.value=null,i.value=[]),v.success(M(`@AGENT:已删除`))}catch(e){v.error(M(`@AGENT:删除失败`)+`: `+(e?.message||e))}}async function p(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){v.error(r.error||M(`@AGENT:重命名失败`));return}let i=t.value.find(t=>t.sessionId===e);i&&(i.title=n),v.success(M(`@AGENT:已重命名`))}catch(e){v.error(M(`@AGENT:重命名失败`)+`: `+(e?.message||e))}}function m(){r.value=null,i.value=[]}async function h(t,n=[]){let o=n.filter(e=>e?.file?.type?.startsWith(`image/`));if(o.length<n.length&&v.warning(M(`@AGENT:仅支持发送图片,非图片文件已忽略`)),!t.trim()&&o.length===0||a.value)return;let l=(await Promise.allSettled(o.map(e=>R(e.file)))).map(e=>e.status===`fulfilled`?e.value:``).filter(e=>e.startsWith(`data:image/`)),d=++c;s=new AbortController;let f=s,p={id:j(),role:`user`,content:t,status:`done`,createdAt:Date.now()};o.length>0&&(p.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(p);let m=k({id:j(),role:`assistant`,content:``,status:`pending`,createdAt:Date.now()});i.value.push(m),a.value=!0;let h=[];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||``,...l.length>0?{images:l}:{}}),signal:f.signal});if(d!==c)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`),s=``,p=r.value;for(;;){let{value:e,done:t}=await a.read();if(d!==c)return;if(t)break;s+=o.decode(e,{stream:!0});let n=s.split(`
2
+ `);s=n.pop()??``;for(let e of n){let t=e.trim();if(!t.startsWith(`data:`))continue;let n=t.slice(5).trim();if(!n)continue;let i;try{i=JSON.parse(n)}catch{continue}switch(i.type){case`meta`:i.sessionId&&(p=i.sessionId,r.value=i.sessionId);break;case`thinking`:m.reasoning||(m.reasoning=``,m.reasoningStatus=`streaming`),m.reasoning+=String(i.delta||``),m.status=`streaming`;break;case`content`:m.status===`pending`&&(m.status=`streaming`);{let e=String(i.delta||``);m.content+=e;let t=A(m.content);t.reasoning&&(m.reasoning||(m.reasoning=``,m.reasoningStatus=`streaming`),m.reasoning=t.reasoning,m.content=t.content)}break;case`tool_call_start`:{let e=k({id:i.toolCallId||j(),name:i.name||``,argsPreview:i.argsPreview||``,arguments:i.argsPreview||``,status:`running`,result:``});h.push(e),m.toolCalls||=[],m.toolCalls.push(e),m.status===`pending`&&(m.status=`streaming`);break}case`tool_result`:{let e=h.find(e=>e.id===i.toolCallId);e&&(e.result=String(i.result||``),e.status=`done`);break}case`done`:{let e=i.content||m.content,t=A(e);t.reasoning&&!m.reasoning&&(m.reasoning=t.reasoning),m.content=t.content,m.status=`done`,m.reasoningStatus===`streaming`&&(m.reasoningStatus=`done`);break}case`error`:m.status=`error`,m.error=String(i.error||M(`@AGENT:未知错误`)),m.reasoningStatus===`streaming`&&(m.reasoningStatus=`done`)}}i.value=[...i.value]}if(d!==c)return;m.status===`pending`&&(m.status=`done`),p&&p!==r.value&&(r.value=p),u().catch(()=>{})}catch(e){if(d!==c)return;e?.name===`AbortError`||f.signal.aborted?(m.content=(m.content||``)+`
3
3
 
4
- [`+M(`@AGENT:已停止`)+`]`,m.status=`done`,m.reasoningStatus===`streaming`&&(m.reasoningStatus=`done`)):(m.status=`error`,m.error=e?.message||String(e),v.error(m.error||M(`@AGENT:对话失败`)))}finally{d===c&&(a.value=!1,s=null)}}function g(){s&&=(s.abort(),null)}return{sessions:t,sessionsLoading:n,currentSessionId:r,messages:i,isStreaming:a,sessionLoading:o,loadSessions:u,loadSession:d,deleteSession:f,renameSession:p,newSession:m,sendMessage:h,stop:g}}n(),E(),d(),O();var V={class:`agent-view`},H={class:`sidebar-header`},U={class:`sidebar-search`},W=[`placeholder`],G={class:`session-list`},le={key:0,class:`empty-state`},K={class:`empty-text`},ue={key:0,class:`empty-hint`},de=[`onClick`],fe={class:`session-item-main`},pe={class:`session-item-title`},me={class:`session-item-meta`},he={class:`meta-time`},ge={class:`meta-count`},_e={key:0,class:`meta-source cli`},ve=[`onClick`],ye=[`onClick`],be={class:`agent-chat-area`},xe={key:0,class:`chat-loading`},Se={key:0,class:`stop-button-bar`},q=N(c({__name:`AgentView`,setup(n){let c=P(),{sessions:d,sessionsLoading:E,currentSessionId:O,messages:k,isStreaming:A,sessionLoading:j,loadSessions:N,loadSession:F,deleteSession:I,renameSession:L,newSession:R,sendMessage:z,stop:q}=B(),Ce=p(()=>{let e=c.theme;return e===`dark`||e===`auto`&&window.matchMedia(`(prefers-color-scheme: dark)`).matches?`dark`:`light`}),J=y(``),Y=p(()=>{if(!J.value.trim())return d.value;let e=J.value.toLowerCase();return d.value.filter(t=>(t.title||``).toLowerCase().includes(e)||(t.model||``).toLowerCase().includes(e))}),we=p(()=>[{id:`p1`,label:M(`@AGENT:查看项目结构`),prompt:M(`@AGENT:prompt_p1`)},{id:`p2`,label:M(`@AGENT:分析代码质量`),prompt:M(`@AGENT:prompt_p2`)},{id:`p3`,label:M(`@AGENT:帮我写测试`),prompt:M(`@AGENT:prompt_p3`)},{id:`p4`,label:M(`@AGENT:Git 状态检查`),prompt:M(`@AGENT:prompt_p4`)}]);async function Te(e){await z(e.text,e.files),await m(),Z()}async function Ee(e){await z(e.prompt),await m(),Z()}let X=y(null);function Z(e=!0){X.value?.scrollToBottom(e)}T(()=>k.value.length,()=>{m(()=>Z(!1))});function De(e){if(A.value){v.warning(M(`@AGENT:请先停止当前生成`));return}F(e)}function Oe(){if(A.value){v.warning(M(`@AGENT:请先停止当前生成`));return}R()}function ke(e,t){if(t.stopPropagation(),A.value&&O.value===e){v.warning(M(`@AGENT:请先停止当前生成`));return}I(e)}async function Ae(e,t,n){n.stopPropagation();try{let{value:n}=await S.prompt(M(`@AGENT:请输入新的会话标题`),M(`@AGENT:重命名会话`),{inputValue:t,inputPattern:/.+/,inputErrorMessage:M(`@AGENT:标题不能为空`)});n&&n!==t&&await L(e,n)}catch{}}function je(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?M(`@AGENT:今天`):`${e}${M(`@AGENT:天前`)}`}return`${t.getFullYear()}-${i(t.getMonth()+1)}-${i(t.getDate())}`}catch{return e}}let Q=y(280),$=y(!1);function Me(e){$.value=!0;let t=e.clientX,n=Q.value,r=e=>{let r=e.clientX-t,i=Math.max(200,Math.min(500,n+r));Q.value=i},i=()=>{$.value=!1,document.removeEventListener(`mousemove`,r),document.removeEventListener(`mouseup`,i)};document.addEventListener(`mousemove`,r),document.addEventListener(`mouseup`,i)}return T(()=>[c.currentDirectory,A.value],async([e,t],n)=>{let r=!n||e!==n[0],i=!!n&&n[1]===!0&&!t;(r||i)&&await N(),O.value&&!A.value&&!d.value.some(e=>e.sessionId===O.value)&&R()},{immediate:!0}),(n,c)=>{let d=re;return _(),C(`div`,V,[i(`aside`,{class:`agent-sidebar`,style:g({width:Q.value+`px`})},[i(`div`,H,[i(`button`,{class:`new-session-btn`,onClick:Oe},[u(a(h),null,{default:b(()=>[u(a(se))]),_:1}),i(`span`,null,f(a(M)(`@AGENT:新建会话`)),1)])]),i(`div`,U,[u(a(h),{class:`search-icon`},{default:b(()=>[u(a(s))]),_:1}),w(i(`input`,{"onUpdate:modelValue":c[0]||=e=>J.value=e,placeholder:a(M)(`@AGENT:搜索会话...`),class:`search-input`,type:`text`},null,8,W),[[ee,J.value]])]),w((_(),C(`div`,G,[Y.value.length===0&&!a(E)?(_(),C(`div`,le,[u(a(h),{size:28,color:`var(--text-tertiary)`},{default:b(()=>[u(a(ie))]),_:1}),i(`div`,K,f(J.value?a(M)(`@AGENT:未找到匹配的会话`):a(M)(`@AGENT:暂无会话`)),1),J.value?l(``,!0):(_(),C(`div`,ue,f(a(M)(`@AGENT:点击上方按钮开始对话`)),1))])):l(``,!0),(_(!0),C(oe,null,e(Y.value,e=>(_(),C(`div`,{key:e.sessionId,class:D([`session-item`,{active:a(O)===e.sessionId}]),onClick:t=>De(e.sessionId)},[i(`div`,fe,[i(`div`,pe,f(e.title||a(M)(`@AGENT:无标题`)),1),i(`div`,me,[i(`span`,he,f(je(e.updatedAt)),1),c[3]||=i(`span`,{class:`meta-dot`},`·`,-1),i(`span`,ge,f(e.messageCount)+` `+f(a(M)(`@AGENT:条`)),1),e.source===`cli`?(_(),C(`span`,_e,`CLI`)):l(``,!0)])]),i(`div`,{class:`session-item-actions`,onClick:c[1]||=te(()=>{},[`stop`])},[u(a(o),{content:a(M)(`@AGENT:重命名`),placement:`top`,"show-after":500},{default:b(()=>[i(`button`,{class:`item-action-btn`,onClick:t=>Ae(e.sessionId,e.title,t)},[u(a(h),null,{default:b(()=>[u(a(x))]),_:1})],8,ve)]),_:2},1032,[`content`]),u(a(o),{content:a(M)(`@AGENT:删除`),placement:`top`,"show-after":500},{default:b(()=>[i(`button`,{class:`item-action-btn danger`,onClick:t=>ke(e.sessionId,t)},[u(a(h),null,{default:b(()=>[u(a(ae))]),_:1})],8,ye)]),_:2},1032,[`content`])])],10,de))),128))])),[[d,a(E)]])],4),i(`div`,{class:D([`sidebar-resizer`,{active:$.value}]),onMousedown:Me},null,34),i(`main`,be,[a(j)?(_(),C(`div`,xe,[u(a(h),{class:`is-loading`,size:32},{default:b(()=>[u(a(t))]),_:1}),i(`span`,null,f(a(M)(`@AGENT:加载会话中...`)),1)])):(_(),r(a(ce),{key:1,ref_key:`chatContainerRef`,ref:X,messages:a(k),"preset-questions":we.value,"welcome-title":a(M)(`@AGENT:智能体助手`),"welcome-description":a(M)(`@AGENT:我可以帮你阅读代码、执行命令、修改文件。选择下方话题或直接输入你的问题。`),"assistant-name":`g ai`,theme:Ce.value,disabled:a(A),"upload-config":{accept:`image/*`},placeholder:a(A)?a(M)(`@AGENT:正在生成中...`):a(M)(`@AGENT:输入消息,Enter 发送`),onSend:Te,onSelect:Ee},null,8,[`messages`,`preset-questions`,`welcome-title`,`welcome-description`,`theme`,`disabled`,`placeholder`])),u(ne,{name:`fade`},{default:b(()=>[a(A)?(_(),C(`div`,Se,[i(`button`,{class:`stop-button`,onClick:c[2]||=(...e)=>a(q)&&a(q)(...e)},[u(a(h),null,{default:b(()=>[u(a(t),{class:`is-loading`})]),_:1}),i(`span`,null,f(a(M)(`@AGENT:停止生成`)),1)])])):l(``,!0)]),_:1})])])}}}),[[`__scopeId`,`data-v-773baa74`]]);export{q as default};
4
+ [`+M(`@AGENT:已停止`)+`]`,m.status=`done`,m.reasoningStatus===`streaming`&&(m.reasoningStatus=`done`)):(m.status=`error`,m.error=e?.message||String(e),v.error(m.error||M(`@AGENT:对话失败`)))}finally{d===c&&(a.value=!1,s=null)}}function g(){s&&=(s.abort(),null)}return{sessions:t,sessionsLoading:n,currentSessionId:r,messages:i,isStreaming:a,sessionLoading:o,loadSessions:u,loadSession:d,deleteSession:f,renameSession:p,newSession:m,sendMessage:h,stop:g}}n(),T(),d(),O();var V={class:`agent-view`},H={class:`sidebar-header`},U={class:`sidebar-search`},W=[`placeholder`],G={class:`session-list`},le={key:0,class:`empty-state`},ue={class:`empty-text`},de={key:0,class:`empty-hint`},fe=[`onClick`],pe={class:`session-item-main`},K={class:`session-item-title`},me={class:`session-item-meta`},he={class:`meta-time`},ge={class:`meta-count`},_e={key:0,class:`meta-source cli`},ve=[`onClick`],ye=[`onClick`],be={class:`agent-chat-area`},xe={key:0,class:`chat-loading`},Se={key:0,class:`stop-button-bar`},q=N(c({__name:`AgentView`,setup(n){let c=P(),{sessions:d,sessionsLoading:T,currentSessionId:O,messages:k,isStreaming:A,sessionLoading:j,loadSessions:N,loadSession:F,deleteSession:I,renameSession:L,newSession:R,sendMessage:z,stop:q}=B(),Ce=p(()=>{let e=c.theme;return e===`dark`||e===`auto`&&window.matchMedia(`(prefers-color-scheme: dark)`).matches?`dark`:`light`}),J=y(``),Y=p(()=>{if(!J.value.trim())return d.value;let e=J.value.toLowerCase();return d.value.filter(t=>(t.title||``).toLowerCase().includes(e)||(t.model||``).toLowerCase().includes(e))}),we=p(()=>[{id:`p1`,label:M(`@AGENT:查看项目结构`),prompt:M(`@AGENT:prompt_p1`)},{id:`p2`,label:M(`@AGENT:分析代码质量`),prompt:M(`@AGENT:prompt_p2`)},{id:`p3`,label:M(`@AGENT:帮我写测试`),prompt:M(`@AGENT:prompt_p3`)},{id:`p4`,label:M(`@AGENT:Git 状态检查`),prompt:M(`@AGENT:prompt_p4`)},{id:`p5`,label:M(`@AGENT:帮我启动项目`),prompt:M(`@AGENT:prompt_p5`)}]);async function Te(e){await z(e.text,e.files),await m(),Z()}async function Ee(e){await z(e.prompt),await m(),Z()}let X=y(null);function Z(e=!0){X.value?.scrollToBottom(e)}w(()=>k.value.length,()=>{m(()=>Z(!1))});function De(e){if(A.value){v.warning(M(`@AGENT:请先停止当前生成`));return}F(e)}function Oe(){if(A.value){v.warning(M(`@AGENT:请先停止当前生成`));return}R()}function ke(e,t){if(t.stopPropagation(),A.value&&O.value===e){v.warning(M(`@AGENT:请先停止当前生成`));return}I(e)}async function Ae(e,t,n){n.stopPropagation();try{let{value:n}=await x.prompt(M(`@AGENT:请输入新的会话标题`),M(`@AGENT:重命名会话`),{inputValue:t,inputPattern:/.+/,inputErrorMessage:M(`@AGENT:标题不能为空`)});n&&n!==t&&await L(e,n)}catch{}}function je(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?M(`@AGENT:今天`):`${e}${M(`@AGENT:天前`)}`}return`${t.getFullYear()}-${i(t.getMonth()+1)}-${i(t.getDate())}`}catch{return e}}let Q=y(280),$=y(!1);function Me(e){$.value=!0;let t=e.clientX,n=Q.value,r=e=>{let r=e.clientX-t,i=Math.max(200,Math.min(500,n+r));Q.value=i},i=()=>{$.value=!1,document.removeEventListener(`mousemove`,r),document.removeEventListener(`mouseup`,i)};document.addEventListener(`mousemove`,r),document.addEventListener(`mouseup`,i)}return w(()=>[c.currentDirectory,A.value],async([e,t],n)=>{let r=!n||e!==n[0],i=!!n&&n[1]===!0&&!t;(r||i)&&await N(),O.value&&!A.value&&!d.value.some(e=>e.sessionId===O.value)&&R()},{immediate:!0}),(n,c)=>{let d=ie;return _(),S(`div`,V,[i(`aside`,{class:`agent-sidebar`,style:g({width:Q.value+`px`})},[i(`div`,H,[i(`button`,{class:`new-session-btn`,onClick:Oe},[u(a(h),null,{default:b(()=>[u(a(se))]),_:1}),i(`span`,null,f(a(M)(`@AGENT:新建会话`)),1)])]),i(`div`,U,[u(a(h),{class:`search-icon`},{default:b(()=>[u(a(s))]),_:1}),C(i(`input`,{"onUpdate:modelValue":c[0]||=e=>J.value=e,placeholder:a(M)(`@AGENT:搜索会话...`),class:`search-input`,type:`text`},null,8,W),[[ee,J.value]])]),C((_(),S(`div`,G,[Y.value.length===0&&!a(T)?(_(),S(`div`,le,[u(a(h),{size:28,color:`var(--text-tertiary)`},{default:b(()=>[u(a(D))]),_:1}),i(`div`,ue,f(J.value?a(M)(`@AGENT:未找到匹配的会话`):a(M)(`@AGENT:暂无会话`)),1),J.value?l(``,!0):(_(),S(`div`,de,f(a(M)(`@AGENT:点击上方按钮开始对话`)),1))])):l(``,!0),(_(!0),S(oe,null,e(Y.value,e=>(_(),S(`div`,{key:e.sessionId,class:E([`session-item`,{active:a(O)===e.sessionId}]),onClick:t=>De(e.sessionId)},[i(`div`,pe,[i(`div`,K,f(e.title||a(M)(`@AGENT:无标题`)),1),i(`div`,me,[i(`span`,he,f(je(e.updatedAt)),1),c[3]||=i(`span`,{class:`meta-dot`},`·`,-1),i(`span`,ge,f(e.messageCount)+` `+f(a(M)(`@AGENT:条`)),1),e.source===`cli`?(_(),S(`span`,_e,`CLI`)):l(``,!0)])]),i(`div`,{class:`session-item-actions`,onClick:c[1]||=te(()=>{},[`stop`])},[u(a(o),{content:a(M)(`@AGENT:重命名`),placement:`top`,"show-after":500},{default:b(()=>[i(`button`,{class:`item-action-btn`,onClick:t=>Ae(e.sessionId,e.title,t)},[u(a(h),null,{default:b(()=>[u(a(re))]),_:1})],8,ve)]),_:2},1032,[`content`]),u(a(o),{content:a(M)(`@AGENT:删除`),placement:`top`,"show-after":500},{default:b(()=>[i(`button`,{class:`item-action-btn danger`,onClick:t=>ke(e.sessionId,t)},[u(a(h),null,{default:b(()=>[u(a(ae))]),_:1})],8,ye)]),_:2},1032,[`content`])])],10,fe))),128))])),[[d,a(T)]])],4),i(`div`,{class:E([`sidebar-resizer`,{active:$.value}]),onMousedown:Me},null,34),i(`main`,be,[a(j)?(_(),S(`div`,xe,[u(a(h),{class:`is-loading`,size:32},{default:b(()=>[u(a(t))]),_:1}),i(`span`,null,f(a(M)(`@AGENT:加载会话中...`)),1)])):(_(),r(a(ce),{key:1,ref_key:`chatContainerRef`,ref:X,messages:a(k),"preset-questions":we.value,"welcome-title":a(M)(`@AGENT:智能体助手`),"welcome-description":a(M)(`@AGENT:我可以帮你阅读代码、执行命令、修改文件。选择下方话题或直接输入你的问题。`),"assistant-name":`g ai`,theme:Ce.value,disabled:a(A),"upload-config":{accept:`image/*`},placeholder:a(A)?a(M)(`@AGENT:正在生成中...`):a(M)(`@AGENT:输入消息,Enter 发送`),onSend:Te,onSelect:Ee},null,8,[`messages`,`preset-questions`,`welcome-title`,`welcome-description`,`theme`,`disabled`,`placeholder`])),u(ne,{name:`fade`},{default:b(()=>[a(A)?(_(),S(`div`,Se,[i(`button`,{class:`stop-button`,onClick:c[2]||=(...e)=>a(q)&&a(q)(...e)},[u(a(h),null,{default:b(()=>[u(a(t),{class:`is-loading`})]),_:1}),i(`span`,null,f(a(M)(`@AGENT:停止生成`)),1)])])):l(``,!0)]),_:1})])])}}}),[[`__scopeId`,`data-v-a1a388e1`]]);export{q as default};
@@ -0,0 +1 @@
1
+ .agent-view[data-v-a1a388e1]{background:var(--bg-container);height:100%;min-height:0;display:flex}.agent-sidebar[data-v-a1a388e1]{background:var(--bg-panel);border-right:1px solid var(--border-color);flex-direction:column;flex-shrink:0;display:flex;overflow:hidden}.sidebar-header[data-v-a1a388e1]{flex-shrink:0;padding:10px 12px}.new-session-btn[data-v-a1a388e1]{border:1px dashed var(--border-color);border-radius:var(--radius-md);width:100%;color:var(--text-secondary);cursor:pointer;background:0 0;justify-content:center;align-items:center;gap:6px;padding:8px 12px;font-family:inherit;font-size:13px;transition:all .15s;display:flex}.new-session-btn[data-v-a1a388e1]:hover{border-color:var(--color-primary);color:var(--color-primary);background:color-mix(in srgb, var(--color-primary) 6%, transparent)}.sidebar-search[data-v-a1a388e1]{flex-shrink:0;align-items:center;gap:6px;padding:0 12px 8px;display:flex}.sidebar-search .search-icon[data-v-a1a388e1]{color:var(--text-tertiary);flex-shrink:0}.sidebar-search .search-input[data-v-a1a388e1]{color:var(--text-primary);background:0 0;border:none;outline:none;flex:1;padding:4px 0;font-family:inherit;font-size:13px}.sidebar-search .search-input[data-v-a1a388e1]::placeholder{color:var(--text-tertiary)}.session-list[data-v-a1a388e1]{flex:1;min-height:0;padding:0 6px 8px;overflow-y:auto}.empty-state[data-v-a1a388e1]{text-align:center;color:var(--text-tertiary);flex-direction:column;justify-content:center;align-items:center;padding:48px 16px;display:flex}.empty-state .empty-text[data-v-a1a388e1]{color:var(--text-secondary);margin-top:10px;font-size:14px}.empty-state .empty-hint[data-v-a1a388e1]{margin-top:4px;font-size:12px}.session-item[data-v-a1a388e1]{border-radius:var(--radius-sm);cursor:pointer;align-items:flex-start;gap:4px;padding:8px 10px;transition:background .12s;display:flex;position:relative}.session-item[data-v-a1a388e1]:hover{background:var(--bg-hover)}.session-item:hover .session-item-actions[data-v-a1a388e1]{opacity:1}.session-item.active[data-v-a1a388e1]{background:color-mix(in srgb, var(--color-primary) 10%, transparent)}.session-item.active .session-item-title[data-v-a1a388e1]{color:var(--color-primary)}.session-item.active[data-v-a1a388e1]:before{content:"";background:var(--color-primary);border-radius:0 2px 2px 0;width:3px;height:20px;position:absolute;top:50%;left:0;transform:translateY(-50%)}.session-item-main[data-v-a1a388e1]{flex:1;min-width:0}.session-item-title[data-v-a1a388e1]{color:var(--text-primary);white-space:nowrap;text-overflow:ellipsis;margin-bottom:2px;font-size:13px;font-weight:500;overflow:hidden}.session-item-meta[data-v-a1a388e1]{color:var(--text-tertiary);align-items:center;gap:4px;font-size:11px;display:flex}.session-item-meta .meta-dot[data-v-a1a388e1]{opacity:.5}.session-item-meta .meta-source[data-v-a1a388e1]{border-radius:3px;padding:0 4px;font-size:10px;font-weight:600}.session-item-meta .meta-source.cli[data-v-a1a388e1]{background:color-mix(in srgb, var(--color-warning) 20%, transparent);color:var(--color-warning)}.session-item-actions[data-v-a1a388e1]{opacity:0;flex-shrink:0;gap:2px;transition:opacity .12s;display:flex}.item-action-btn[data-v-a1a388e1]{width:24px;height:24px;color:var(--text-tertiary);cursor:pointer;border-radius:var(--radius-xs);background:0 0;border:none;justify-content:center;align-items:center;padding:0;transition:all .12s;display:flex}.item-action-btn[data-v-a1a388e1]:hover{background:var(--bg-hover);color:var(--text-secondary)}.item-action-btn.danger[data-v-a1a388e1]:hover{color:var(--color-danger);background:color-mix(in srgb, var(--color-danger) 10%, transparent)}.sidebar-resizer[data-v-a1a388e1]{cursor:col-resize;background:0 0;flex-shrink:0;width:4px;transition:background .15s}.sidebar-resizer[data-v-a1a388e1]:hover,.sidebar-resizer.active[data-v-a1a388e1]{background:var(--color-primary);opacity:.3}.agent-chat-area[data-v-a1a388e1]{flex-direction:column;flex:1;min-width:0;display:flex;position:relative;overflow:hidden}.chat-loading[data-v-a1a388e1]{color:var(--text-tertiary);flex-direction:column;flex:1;justify-content:center;align-items:center;gap:12px;font-size:14px;display:flex}.stop-button-bar[data-v-a1a388e1]{z-index:10;position:absolute;bottom:80px;left:50%;transform:translate(-50%)}.stop-button[data-v-a1a388e1]{border:1px solid var(--color-danger);background:var(--bg-container);color:var(--color-danger);cursor:pointer;border-radius:20px;align-items:center;gap:6px;padding:6px 16px;font-family:inherit;font-size:13px;transition:all .15s;display:flex;box-shadow:0 2px 8px #0000001f}.stop-button[data-v-a1a388e1]:hover{background:var(--color-danger);color:#fff}.fade-enter-active[data-v-a1a388e1],.fade-leave-active[data-v-a1a388e1]{transition:opacity .2s}.fade-enter-from[data-v-a1a388e1],.fade-leave-to[data-v-a1a388e1]{opacity:0}[data-theme=dark]{background:var(--bg-panel)}
@@ -1,2 +1,2 @@
1
- import"./rolldown-runtime-C0FnF6B9.js";import{At as e,B as t,Bn as n,D as r,Dn as i,En as a,Er as o,G as s,In as c,Nn as l,On as u,Pn as d,Pr as f,Qr as p,Tn as m,Wn as h,Y as g,Yn as _,Zn as v,a as y,br as b,cr as x,i as S,it as C,kn as w,or as T,pr as E,qn as D,qr as O,rt as k}from"./element-plus-KTmRV-so.js";import{n as A,t as j}from"./_plugin-vue_export-helper-C-YBnnP5.js";async function M(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 N(){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 P(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 M(t,t=>{try{e(JSON.parse(t))}catch{}})}async function F(){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())};M(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(()=>{})})}n(),E(),f();var I={key:3},L={key:4},R={key:5},z={key:0,class:`upgrade-hint`},B={key:0,class:`upgrade-countdown`},V={key:1,class:`upgrade-manual`},H={class:`upgrade-manual__label`},U=`npm install -g zen-gitsync --registry https://registry.npmjs.org/`,W=j(c({__name:`UpgradeDialog`,props:{modelValue:{type:Boolean},logs:{},status:{},countdown:{default:0}},emits:[`update:modelValue`,`retry`,`restart`,`cancel`],setup(n,{emit:s}){let c=n,f=s,m=b(null);T(()=>c.logs,async()=>{await h(),m.value&&(m.value.scrollTop=m.value.scrollHeight)});function _(){c.status!==`running`&&(c.status===`success`&&c.countdown>0&&f(`cancel`),f(`update:modelValue`,!1))}function S(){f(`retry`)}function E(){f(`restart`)}function D(){f(`cancel`),f(`update:modelValue`,!1)}async function j(){try{await navigator.clipboard.writeText(U),y.success(A(`@F13B4:已复制升级命令`))}catch{y.warning(A(`@F13B4:复制失败,请手动复制`))}}return(s,c)=>{let h=g,y=t,b=r;return v(),i(b,{"model-value":n.modelValue,"onUpdate:modelValue":c[0]||=e=>f(`update:modelValue`,e),title:o(A)(`@F13B4:升级`),width:`680px`,"close-on-click-modal":!1,"close-on-press-escape":!1,"show-close":n.status!==`running`,"append-to-body":``,onClose:_},{footer:x(()=>[n.status===`failed`?(v(),i(y,{key:0,type:`primary`,onClick:S},{default:x(()=>[l(p(o(A)(`@F13B4:重试`)),1)]),_:1})):u(``,!0),n.status===`failed`?(v(),i(y,{key:1,onClick:j},{default:x(()=>[l(p(o(A)(`@F13B4:复制升级命令`)),1)]),_:1})):u(``,!0),n.status===`success`?(v(),i(y,{key:2,type:`primary`,onClick:E},{default:x(()=>[l(p(o(A)(`@F13B4:立即重启并刷新`)),1)]),_:1})):u(``,!0),n.status===`success`?(v(),i(y,{key:3,onClick:D},{default:x(()=>[l(p(o(A)(`@F13B4:稍后手动重启`)),1)]),_:1})):u(``,!0),n.status===`running`?(v(),i(y,{key:4,disabled:``},{default:x(()=>[l(p(o(A)(`@F13B4:升级中`))+`... `,1)]),_:1})):u(``,!0)]),default:x(()=>[a(`div`,{class:O([`upgrade-status`,`is-${n.status}`])},[n.status===`running`?(v(),i(h,{key:0,class:`is-loading`},{default:x(()=>[d(o(e))]),_:1})):n.status===`success`?(v(),i(h,{key:1,color:`#67c23a`},{default:x(()=>[d(o(k))]),_:1})):(v(),i(h,{key:2,color:`#f56c6c`},{default:x(()=>[d(o(C))]),_:1})),n.status===`running`?(v(),w(`span`,I,p(o(A)(`@F13B4:升级中`)),1)):n.status===`success`?(v(),w(`span`,L,p(o(A)(`@F13B4:升级完成`)),1)):(v(),w(`span`,R,p(o(A)(`@F13B4:升级失败`)),1))],2),n.status===`success`?(v(),w(`p`,z,[l(p(o(A)(`@F13B4:新版本已全局安装,需要重启服务才能生效`))+` `,1),n.countdown>0?(v(),w(`span`,B,p(o(A)(`@F13B4:{seconds} 秒后自动刷新`,{seconds:n.countdown})),1)):u(``,!0)])):u(``,!0),n.status===`failed`?(v(),w(`p`,V,[a(`span`,H,p(o(A)(`@F13B4:手动升级命令`)),1),a(`code`,{class:`upgrade-manual__cmd`},p(U))])):u(``,!0),a(`pre`,{ref_key:`logEl`,ref:m,class:`upgrade-log`},p(n.logs||o(A)(`@F13B4:等待日志输出`)),513)]),_:1},8,[`model-value`,`title`,`show-close`])}}}),[[`__scopeId`,`data-v-40c190d7`]]);n(),E(),f();var G={class:`app-version-badge`},K=[`aria-label`],q=[`aria-label`],J=[`title`,`aria-label`],Y={class:`upgrade-btn__label`},X={class:`upgrade-btn__version`},Z=`https://github.com/xz333221/zen-gitsync/releases`,Q=5,$=`app-version-check`,ee=36e5,te=j(c({__name:`AppVersionBadge`,setup(e){let t=`2.17.5`,n=b(t),r=m(()=>n.value||t),i=b(null),c=b(!1),l=b(``),f=b(`running`),h=b(0),g=null,C=b(!1);function T(){try{let e=sessionStorage.getItem($);if(!e)return null;let{at:t,data:n}=JSON.parse(e);return Date.now()-t>ee?null:n}catch{return null}}function E(e){try{sessionStorage.setItem($,JSON.stringify({at:Date.now(),data:e}))}catch{}}async function O(e=!1){let t=T();t&&(i.value=t);try{let t=await N();i.value=t,E(t),t.current&&(n.value=t.current),!e&&t.success&&t.hasUpdate&&y({type:`success`,message:A(`@F13B4:发现新版本 {version}`,{version:t.latest??``}),duration:4e3})}catch(t){e||y({type:`warning`,message:A(`@F13B4:检查更新失败 {error}`,{error:t?.message||``})})}}async function k(){if(i.value?.hasUpdate){try{await S.confirm(A(`@F13B4:确定要从 {current} 升级到 {latest} 吗?`,{current:i.value.current,latest:i.value.latest}),A(`@F13B4:升级`),{confirmButtonText:A(`@F13B4:确定升级`),cancelButtonText:A(`@F13B4:取消`),type:`info`})}catch{return}l.value=``,f.value=`running`,c.value=!0,await P(e=>{if(e.type===`done`){if(f.value=e.code===0?`success`:`failed`,e.code===0){try{sessionStorage.removeItem($)}catch{}i.value?.latest&&(n.value=i.value.latest),j()}}else e.message&&(l.value+=e.message)})}}function j(){M(),h.value=Q,g=setInterval(()=>{--h.value,h.value<=0&&(g&&=(clearInterval(g),null),L())},1e3)}function M(){g&&=(clearInterval(g),null),h.value=0}function I(){M()}async function L(){if(M(),!C.value){C.value=!0;try{let e=await F(),{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];y({type:`warning`,message:n?A(n):A(`@F13B4:重启失败 {error}`,{error:t})}),C.value=!1}}}return D(()=>{M()}),_(()=>{O(!0)}),(e,t)=>{let n=s;return v(),w(`div`,G,[d(n,{content:o(A)(`@F13B4:在 GitHub 上查看源码`),placement:`top`,effect:`dark`,"show-after":300},{default:x(()=>[a(`a`,{href:`https://github.com/xz333221/zen-gitsync`,target:`_blank`,rel:`noopener noreferrer`,class:`badge-icon-link`,"aria-label":o(A)(`@F13B4:在 GitHub 上查看源码`)},[...t[1]||=[a(`svg`,{viewBox:`0 0 24 24`,width:`15`,height:`15`,"aria-hidden":`true`,fill:`currentColor`,xmlns:`http://www.w3.org/2000/svg`},[a(`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,K)]),_:1},8,[`content`]),d(n,{content:o(A)(`@F13B4:在 npm 上查看包`),placement:`top`,effect:`dark`,"show-after":300},{default:x(()=>[a(`a`,{href:`https://www.npmjs.com/package/zen-gitsync`,target:`_blank`,rel:`noopener noreferrer`,class:`badge-icon-link badge-icon-link--npm`,"aria-label":o(A)(`@F13B4:在 npm 上查看包`)},[...t[2]||=[a(`svg`,{viewBox:`0 0 24 24`,width:`15`,height:`15`,"aria-hidden":`true`,fill:`currentColor`,xmlns:`http://www.w3.org/2000/svg`},[a(`path`,{d:`M2 2v20h20V2H2zm17.167 17.167H12.5v-10h-3.333v10H4.833V4.833h14.334v14.334z`})],-1)]],8,q)]),_:1},8,[`content`]),d(n,{content:o(A)(`@F13B4:查看更新`),placement:`top`,effect:`dark`,"show-after":300},{default:x(()=>[a(`a`,{href:Z,target:`_blank`,rel:`noopener noreferrer`,class:`version-link`},`v`+p(r.value),1)]),_:1},8,[`content`]),i.value?.hasUpdate?(v(),w(`button`,{key:0,type:`button`,class:`upgrade-btn`,title:o(A)(`@F13B4:发现新版本 {version},点击升级`,{version:i.value.latest??``}),"aria-label":o(A)(`@F13B4:发现新版本 {version},点击升级`,{version:i.value.latest??``}),onClick:k},[t[3]||=a(`span`,{class:`upgrade-btn__dot`,"aria-hidden":`true`},null,-1),a(`span`,Y,p(o(A)(`@F13B4:升级`)),1),a(`span`,X,`v`+p(i.value.latest),1)],8,J)):u(``,!0),d(W,{modelValue:c.value,"onUpdate:modelValue":t[0]||=e=>c.value=e,logs:l.value,status:f.value,countdown:h.value,onRetry:k,onRestart:L,onCancel:I},null,8,[`modelValue`,`logs`,`status`,`countdown`])])}}}),[[`__scopeId`,`data-v-bc7c0d5c`]]);export{te as default};
1
+ import"./rolldown-runtime-C0FnF6B9.js";import{At as e,B as t,Bn as n,D as r,Dn as i,En as a,Er as o,G as s,In as c,Nn as l,On as u,Pn as d,Pr as f,Qr as p,Tn as m,Wn as h,Y as g,Yn as _,Zn as v,a as y,br as b,cr as x,i as S,it as C,kn as w,or as T,pr as E,qn as D,qr as O,rt as k}from"./element-plus-KTmRV-so.js";import{n as A,t as j}from"./_plugin-vue_export-helper-CQjg8MXm.js";async function M(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 N(){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 P(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 M(t,t=>{try{e(JSON.parse(t))}catch{}})}async function F(){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())};M(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(()=>{})})}n(),E(),f();var I={key:3},L={key:4},R={key:5},z={key:0,class:`upgrade-hint`},B={key:0,class:`upgrade-countdown`},V={key:1,class:`upgrade-manual`},H={class:`upgrade-manual__label`},U=`npm install -g zen-gitsync --registry https://registry.npmjs.org/`,W=j(c({__name:`UpgradeDialog`,props:{modelValue:{type:Boolean},logs:{},status:{},countdown:{default:0}},emits:[`update:modelValue`,`retry`,`restart`,`cancel`],setup(n,{emit:s}){let c=n,f=s,m=b(null);T(()=>c.logs,async()=>{await h(),m.value&&(m.value.scrollTop=m.value.scrollHeight)});function _(){c.status!==`running`&&(c.status===`success`&&c.countdown>0&&f(`cancel`),f(`update:modelValue`,!1))}function S(){f(`retry`)}function E(){f(`restart`)}function D(){f(`cancel`),f(`update:modelValue`,!1)}async function j(){try{await navigator.clipboard.writeText(U),y.success(A(`@F13B4:已复制升级命令`))}catch{y.warning(A(`@F13B4:复制失败,请手动复制`))}}return(s,c)=>{let h=g,y=t,b=r;return v(),i(b,{"model-value":n.modelValue,"onUpdate:modelValue":c[0]||=e=>f(`update:modelValue`,e),title:o(A)(`@F13B4:升级`),width:`680px`,"close-on-click-modal":!1,"close-on-press-escape":!1,"show-close":n.status!==`running`,"append-to-body":``,onClose:_},{footer:x(()=>[n.status===`failed`?(v(),i(y,{key:0,type:`primary`,onClick:S},{default:x(()=>[l(p(o(A)(`@F13B4:重试`)),1)]),_:1})):u(``,!0),n.status===`failed`?(v(),i(y,{key:1,onClick:j},{default:x(()=>[l(p(o(A)(`@F13B4:复制升级命令`)),1)]),_:1})):u(``,!0),n.status===`success`?(v(),i(y,{key:2,type:`primary`,onClick:E},{default:x(()=>[l(p(o(A)(`@F13B4:立即重启并刷新`)),1)]),_:1})):u(``,!0),n.status===`success`?(v(),i(y,{key:3,onClick:D},{default:x(()=>[l(p(o(A)(`@F13B4:稍后手动重启`)),1)]),_:1})):u(``,!0),n.status===`running`?(v(),i(y,{key:4,disabled:``},{default:x(()=>[l(p(o(A)(`@F13B4:升级中`))+`... `,1)]),_:1})):u(``,!0)]),default:x(()=>[a(`div`,{class:O([`upgrade-status`,`is-${n.status}`])},[n.status===`running`?(v(),i(h,{key:0,class:`is-loading`},{default:x(()=>[d(o(e))]),_:1})):n.status===`success`?(v(),i(h,{key:1,color:`#67c23a`},{default:x(()=>[d(o(k))]),_:1})):(v(),i(h,{key:2,color:`#f56c6c`},{default:x(()=>[d(o(C))]),_:1})),n.status===`running`?(v(),w(`span`,I,p(o(A)(`@F13B4:升级中`)),1)):n.status===`success`?(v(),w(`span`,L,p(o(A)(`@F13B4:升级完成`)),1)):(v(),w(`span`,R,p(o(A)(`@F13B4:升级失败`)),1))],2),n.status===`success`?(v(),w(`p`,z,[l(p(o(A)(`@F13B4:新版本已全局安装,需要重启服务才能生效`))+` `,1),n.countdown>0?(v(),w(`span`,B,p(o(A)(`@F13B4:{seconds} 秒后自动刷新`,{seconds:n.countdown})),1)):u(``,!0)])):u(``,!0),n.status===`failed`?(v(),w(`p`,V,[a(`span`,H,p(o(A)(`@F13B4:手动升级命令`)),1),a(`code`,{class:`upgrade-manual__cmd`},p(U))])):u(``,!0),a(`pre`,{ref_key:`logEl`,ref:m,class:`upgrade-log`},p(n.logs||o(A)(`@F13B4:等待日志输出`)),513)]),_:1},8,[`model-value`,`title`,`show-close`])}}}),[[`__scopeId`,`data-v-40c190d7`]]);n(),E(),f();var G={class:`app-version-badge`},K=[`aria-label`],q=[`aria-label`],J=[`title`,`aria-label`],Y={class:`upgrade-btn__label`},X={class:`upgrade-btn__version`},Z=`https://github.com/xz333221/zen-gitsync/releases`,Q=5,$=`app-version-check`,ee=36e5,te=j(c({__name:`AppVersionBadge`,setup(e){let t=`2.17.7`,n=b(t),r=m(()=>n.value||t),i=b(null),c=b(!1),l=b(``),f=b(`running`),h=b(0),g=null,C=b(!1);function T(){try{let e=sessionStorage.getItem($);if(!e)return null;let{at:t,data:n}=JSON.parse(e);return Date.now()-t>ee?null:n}catch{return null}}function E(e){try{sessionStorage.setItem($,JSON.stringify({at:Date.now(),data:e}))}catch{}}async function O(e=!1){let t=T();t&&(i.value=t);try{let t=await N();i.value=t,E(t),t.current&&(n.value=t.current),!e&&t.success&&t.hasUpdate&&y({type:`success`,message:A(`@F13B4:发现新版本 {version}`,{version:t.latest??``}),duration:4e3})}catch(t){e||y({type:`warning`,message:A(`@F13B4:检查更新失败 {error}`,{error:t?.message||``})})}}async function k(){if(i.value?.hasUpdate){try{await S.confirm(A(`@F13B4:确定要从 {current} 升级到 {latest} 吗?`,{current:i.value.current,latest:i.value.latest}),A(`@F13B4:升级`),{confirmButtonText:A(`@F13B4:确定升级`),cancelButtonText:A(`@F13B4:取消`),type:`info`})}catch{return}l.value=``,f.value=`running`,c.value=!0,await P(e=>{if(e.type===`done`){if(f.value=e.code===0?`success`:`failed`,e.code===0){try{sessionStorage.removeItem($)}catch{}i.value?.latest&&(n.value=i.value.latest),j()}}else e.message&&(l.value+=e.message)})}}function j(){M(),h.value=Q,g=setInterval(()=>{--h.value,h.value<=0&&(g&&=(clearInterval(g),null),L())},1e3)}function M(){g&&=(clearInterval(g),null),h.value=0}function I(){M()}async function L(){if(M(),!C.value){C.value=!0;try{let e=await F(),{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];y({type:`warning`,message:n?A(n):A(`@F13B4:重启失败 {error}`,{error:t})}),C.value=!1}}}return D(()=>{M()}),_(()=>{O(!0)}),(e,t)=>{let n=s;return v(),w(`div`,G,[d(n,{content:o(A)(`@F13B4:在 GitHub 上查看源码`),placement:`top`,effect:`dark`,"show-after":300},{default:x(()=>[a(`a`,{href:`https://github.com/xz333221/zen-gitsync`,target:`_blank`,rel:`noopener noreferrer`,class:`badge-icon-link`,"aria-label":o(A)(`@F13B4:在 GitHub 上查看源码`)},[...t[1]||=[a(`svg`,{viewBox:`0 0 24 24`,width:`15`,height:`15`,"aria-hidden":`true`,fill:`currentColor`,xmlns:`http://www.w3.org/2000/svg`},[a(`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,K)]),_:1},8,[`content`]),d(n,{content:o(A)(`@F13B4:在 npm 上查看包`),placement:`top`,effect:`dark`,"show-after":300},{default:x(()=>[a(`a`,{href:`https://www.npmjs.com/package/zen-gitsync`,target:`_blank`,rel:`noopener noreferrer`,class:`badge-icon-link badge-icon-link--npm`,"aria-label":o(A)(`@F13B4:在 npm 上查看包`)},[...t[2]||=[a(`svg`,{viewBox:`0 0 24 24`,width:`15`,height:`15`,"aria-hidden":`true`,fill:`currentColor`,xmlns:`http://www.w3.org/2000/svg`},[a(`path`,{d:`M2 2v20h20V2H2zm17.167 17.167H12.5v-10h-3.333v10H4.833V4.833h14.334v14.334z`})],-1)]],8,q)]),_:1},8,[`content`]),d(n,{content:o(A)(`@F13B4:查看更新`),placement:`top`,effect:`dark`,"show-after":300},{default:x(()=>[a(`a`,{href:Z,target:`_blank`,rel:`noopener noreferrer`,class:`version-link`},`v`+p(r.value),1)]),_:1},8,[`content`]),i.value?.hasUpdate?(v(),w(`button`,{key:0,type:`button`,class:`upgrade-btn`,title:o(A)(`@F13B4:发现新版本 {version},点击升级`,{version:i.value.latest??``}),"aria-label":o(A)(`@F13B4:发现新版本 {version},点击升级`,{version:i.value.latest??``}),onClick:k},[t[3]||=a(`span`,{class:`upgrade-btn__dot`,"aria-hidden":`true`},null,-1),a(`span`,Y,p(o(A)(`@F13B4:升级`)),1),a(`span`,X,`v`+p(i.value.latest),1)],8,J)):u(``,!0),d(W,{modelValue:c.value,"onUpdate:modelValue":t[0]||=e=>c.value=e,logs:l.value,status:f.value,countdown:h.value,onRetry:k,onRestart:L,onCancel:I},null,8,[`modelValue`,`logs`,`status`,`countdown`])])}}}),[[`__scopeId`,`data-v-bc7c0d5c`]]);export{te as default};
@@ -1 +1 @@
1
- import"./rolldown-runtime-C0FnF6B9.js";import{$n as e,Bn as t,Dn as n,En as r,Er as i,Ht as ee,In as a,K as te,L as ne,Nt as re,On as o,Pn as s,Pr as c,Qr as l,R as ie,Tn as u,W as d,Y as ae,Zn as f,br as p,cr as m,kn as h,nt as g,pr as _,q as v,qr as y,r as b,un as x,xn as S,yn as C,zt as w}from"./element-plus-KTmRV-so.js";import{n as T,t as E}from"./_plugin-vue_export-helper-C-YBnnP5.js";import{t as D}from"./SvgIcon-BVCbrPws.js";import{t as O}from"./IconButton-pqSYKRT8.js";import{t as k}from"./gitStore-BJbNtjxA.js";import{t as A}from"./CommonDialog-B8XOXtz_.js";t(),_(),c(),x();var j={key:0,class:`branch-info`},M={class:`branch-wrapper`},N={class:`branch-btn`},P={class:`branch-btn-name`},F={class:`branch-btn-caret`},I={class:`branch-popover-inner`},L={class:`branch-search`},R={class:`branch-list`},z=[`onClick`],B={key:1,class:`branch-item-check-placeholder`},V={class:`branch-item-name`},oe={key:0,class:`branch-empty`},H={class:`branch-popover-footer`},U={class:`create-branch-content`},W={class:`form-label`},G={class:`form-label`},K={class:`dialog-footer`},q={class:`footer-actions`},se=[`disabled`],J=E(a({__name:`BranchSelector`,emits:[`branchChanged`],setup(t,{emit:a}){let c=k(),_=a,x=p(!1),E=p(``),J=u(()=>{let e=E.value.trim().toLowerCase();return e?c.allBranches.filter(t=>t.toLowerCase().includes(e)):c.allBranches});async function ce(e){if(e===c.currentBranch){x.value=!1;return}x.value=!1,await c.changeBranch(e)&&(_(`branchChanged`),c.refreshLog())}let Y=p(!1),X=p(``),Z=p(``);function le(){x.value=!1,Z.value=c.currentBranch,Y.value=!0}async function Q(){await c.createBranch(X.value,Z.value)&&(Y.value=!1,X.value=``,_(`branchChanged`))}let $=p(!1);async function ue(){if(!$.value){$.value=!0;try{await Promise.all([c.getCurrentBranch(!0),c.getBranchStatus(!0),c.getAllBranches()]),_(`branchChanged`),c.refreshLog()}finally{$.value=!1}}}return(t,a)=>{let u=ae,p=d,_=b,k=v,de=ne,fe=ie,pe=te;return i(c).currentBranch?(f(),h(`div`,j,[r(`div`,M,[s(_,{visible:x.value,"onUpdate:visible":a[1]||=e=>x.value=e,placement:`top-start`,width:260,trigger:`click`,"popper-class":`branch-popover`,"show-arrow":!1,onShow:a[2]||=e=>E.value=``},{reference:m(()=>[r(`button`,N,[s(D,{"icon-class":`git-branch`,"class-name":`branch-btn-icon`}),r(`span`,P,l(i(c).currentBranch),1),r(`span`,F,[s(u,null,{default:m(()=>[...a[7]||=[r(`svg`,{viewBox:`0 0 1024 1024`,xmlns:`http://www.w3.org/2000/svg`},[r(`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:m(()=>[r(`div`,I,[r(`div`,L,[s(p,{modelValue:E.value,"onUpdate:modelValue":a[0]||=e=>E.value=e,placeholder:i(T)(`@F13B4:搜索或签出分支`),size:`small`,clearable:``,autofocus:``},null,8,[`modelValue`,`placeholder`])]),r(`div`,R,[(f(!0),h(S,null,e(J.value,e=>(f(),h(`div`,{key:e,class:y([`branch-item`,{"is-active":e===i(c).currentBranch}]),onClick:t=>ce(e)},[e===i(c).currentBranch?(f(),n(u,{key:0,class:`branch-item-check`},{default:m(()=>[s(i(g))]),_:1})):(f(),h(`span`,B)),s(D,{"icon-class":`git-branch`,"class-name":`branch-item-icon`}),r(`span`,V,l(e),1)],10,z))),128)),J.value.length===0?(f(),h(`div`,oe,l(i(T)(`@F13B4:没有匹配的分支`)),1)):o(``,!0)]),r(`div`,H,[r(`button`,{class:`branch-create-btn`,onClick:le},[s(u,null,{default:m(()=>[s(i(w))]),_:1}),r(`span`,null,l(i(T)(`@F13B4:创建新分支`)),1)])])])]),_:1},8,[`visible`]),s(O,{tooltip:i(T)(`@CMDCON:刷新`),onClick:ue},{default:m(()=>[s(u,{class:y({"is-loading":$.value})},{default:m(()=>[s(i(ee))]),_:1},8,[`class`])]),_:1},8,[`tooltip`])]),s(A,{modelValue:Y.value,"onUpdate:modelValue":a[6]||=e=>Y.value=e,title:i(T)(`@F13B4:创建新分支`),size:`small`,"destroy-on-close":!0,"append-to-body":!0,"custom-class":`create-branch-dialog`},{footer:m(()=>[r(`div`,K,[r(`div`,q,[r(`button`,{type:`button`,class:`dialog-cancel-btn`,onClick:a[5]||=e=>Y.value=!1},l(i(T)(`@F13B4:取消`)),1),r(`button`,{type:`button`,class:`dialog-confirm-btn`,onClick:Q,disabled:i(c).isCreatingBranch},[i(c).isCreatingBranch?(f(),n(u,{key:1,class:`is-loading`},{default:m(()=>[...a[8]||=[r(`svg`,{viewBox:`0 0 1024 1024`,xmlns:`http://www.w3.org/2000/svg`},[r(`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})):(f(),n(u,{key:0},{default:m(()=>[s(i(g))]),_:1})),r(`span`,null,l(i(T)(`@F13B4:创建`)),1)],8,se)])])]),default:m(()=>[r(`div`,U,[s(pe,{model:{newBranchName:X.value,selectedBaseBranch:Z.value},"label-position":`top`},{default:m(()=>[s(k,null,{label:m(()=>[r(`div`,W,[s(u,{class:`label-icon`},{default:m(()=>[s(i(w))]),_:1}),r(`span`,null,l(i(T)(`@F13B4:新分支名称`)),1)])]),default:m(()=>[s(p,{modelValue:X.value,"onUpdate:modelValue":a[3]||=e=>X.value=e,placeholder:i(T)(`@F13B4:请输入新分支名称`),class:`modern-input`,size:`large`,onKeyup:C(Q,[`enter`])},null,8,[`modelValue`,`placeholder`])]),_:1}),s(k,null,{label:m(()=>[r(`div`,G,[s(u,{class:`label-icon`},{default:m(()=>[s(i(re))]),_:1}),r(`span`,null,l(i(T)(`@F13B4:基于分支`)),1)])]),default:m(()=>[s(fe,{modelValue:Z.value,"onUpdate:modelValue":a[4]||=e=>Z.value=e,placeholder:i(T)(`@F13B4:选择基础分支`),class:`modern-select`,size:`large`,style:{width:`100%`}},{default:m(()=>[(f(!0),h(S,null,e(i(c).allBranches,e=>(f(),n(de,{key:e,label:e,value:e},null,8,[`label`,`value`]))),128))]),_:1},8,[`modelValue`,`placeholder`])]),_:1})]),_:1},8,[`model`])])]),_:1},8,[`modelValue`,`title`])])):o(``,!0)}}}),[[`__scopeId`,`data-v-665171bc`]]);export{J as default};
1
+ import"./rolldown-runtime-C0FnF6B9.js";import{$n as e,Bn as t,Dn as n,En as r,Er as i,Ht as ee,In as a,K as te,L as ne,Nt as re,On as o,Pn as s,Pr as c,Qr as l,R as ie,Tn as u,W as d,Y as ae,Zn as f,br as p,cr as m,kn as h,nt as g,pr as _,q as v,qr as y,r as b,un as x,xn as S,yn as C,zt as w}from"./element-plus-KTmRV-so.js";import{n as T,t as E}from"./_plugin-vue_export-helper-CQjg8MXm.js";import{t as D}from"./SvgIcon-Cf7nOKc8.js";import{t as O}from"./IconButton-BmSueF_H.js";import{t as k}from"./gitStore-DIsBd6n4.js";import{t as A}from"./CommonDialog-QyptFD1R.js";t(),_(),c(),x();var j={key:0,class:`branch-info`},M={class:`branch-wrapper`},N={class:`branch-btn`},P={class:`branch-btn-name`},F={class:`branch-btn-caret`},I={class:`branch-popover-inner`},L={class:`branch-search`},R={class:`branch-list`},z=[`onClick`],B={key:1,class:`branch-item-check-placeholder`},V={class:`branch-item-name`},oe={key:0,class:`branch-empty`},H={class:`branch-popover-footer`},U={class:`create-branch-content`},W={class:`form-label`},G={class:`form-label`},K={class:`dialog-footer`},q={class:`footer-actions`},se=[`disabled`],J=E(a({__name:`BranchSelector`,emits:[`branchChanged`],setup(t,{emit:a}){let c=k(),_=a,x=p(!1),E=p(``),J=u(()=>{let e=E.value.trim().toLowerCase();return e?c.allBranches.filter(t=>t.toLowerCase().includes(e)):c.allBranches});async function ce(e){if(e===c.currentBranch){x.value=!1;return}x.value=!1,await c.changeBranch(e)&&(_(`branchChanged`),c.refreshLog())}let Y=p(!1),X=p(``),Z=p(``);function le(){x.value=!1,Z.value=c.currentBranch,Y.value=!0}async function Q(){await c.createBranch(X.value,Z.value)&&(Y.value=!1,X.value=``,_(`branchChanged`))}let $=p(!1);async function ue(){if(!$.value){$.value=!0;try{await Promise.all([c.getCurrentBranch(!0),c.getBranchStatus(!0),c.getAllBranches()]),_(`branchChanged`),c.refreshLog()}finally{$.value=!1}}}return(t,a)=>{let u=ae,p=d,_=b,k=v,de=ne,fe=ie,pe=te;return i(c).currentBranch?(f(),h(`div`,j,[r(`div`,M,[s(_,{visible:x.value,"onUpdate:visible":a[1]||=e=>x.value=e,placement:`top-start`,width:260,trigger:`click`,"popper-class":`branch-popover`,"show-arrow":!1,onShow:a[2]||=e=>E.value=``},{reference:m(()=>[r(`button`,N,[s(D,{"icon-class":`git-branch`,"class-name":`branch-btn-icon`}),r(`span`,P,l(i(c).currentBranch),1),r(`span`,F,[s(u,null,{default:m(()=>[...a[7]||=[r(`svg`,{viewBox:`0 0 1024 1024`,xmlns:`http://www.w3.org/2000/svg`},[r(`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:m(()=>[r(`div`,I,[r(`div`,L,[s(p,{modelValue:E.value,"onUpdate:modelValue":a[0]||=e=>E.value=e,placeholder:i(T)(`@F13B4:搜索或签出分支`),size:`small`,clearable:``,autofocus:``},null,8,[`modelValue`,`placeholder`])]),r(`div`,R,[(f(!0),h(S,null,e(J.value,e=>(f(),h(`div`,{key:e,class:y([`branch-item`,{"is-active":e===i(c).currentBranch}]),onClick:t=>ce(e)},[e===i(c).currentBranch?(f(),n(u,{key:0,class:`branch-item-check`},{default:m(()=>[s(i(g))]),_:1})):(f(),h(`span`,B)),s(D,{"icon-class":`git-branch`,"class-name":`branch-item-icon`}),r(`span`,V,l(e),1)],10,z))),128)),J.value.length===0?(f(),h(`div`,oe,l(i(T)(`@F13B4:没有匹配的分支`)),1)):o(``,!0)]),r(`div`,H,[r(`button`,{class:`branch-create-btn`,onClick:le},[s(u,null,{default:m(()=>[s(i(w))]),_:1}),r(`span`,null,l(i(T)(`@F13B4:创建新分支`)),1)])])])]),_:1},8,[`visible`]),s(O,{tooltip:i(T)(`@CMDCON:刷新`),onClick:ue},{default:m(()=>[s(u,{class:y({"is-loading":$.value})},{default:m(()=>[s(i(ee))]),_:1},8,[`class`])]),_:1},8,[`tooltip`])]),s(A,{modelValue:Y.value,"onUpdate:modelValue":a[6]||=e=>Y.value=e,title:i(T)(`@F13B4:创建新分支`),size:`small`,"destroy-on-close":!0,"append-to-body":!0,"custom-class":`create-branch-dialog`},{footer:m(()=>[r(`div`,K,[r(`div`,q,[r(`button`,{type:`button`,class:`dialog-cancel-btn`,onClick:a[5]||=e=>Y.value=!1},l(i(T)(`@F13B4:取消`)),1),r(`button`,{type:`button`,class:`dialog-confirm-btn`,onClick:Q,disabled:i(c).isCreatingBranch},[i(c).isCreatingBranch?(f(),n(u,{key:1,class:`is-loading`},{default:m(()=>[...a[8]||=[r(`svg`,{viewBox:`0 0 1024 1024`,xmlns:`http://www.w3.org/2000/svg`},[r(`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})):(f(),n(u,{key:0},{default:m(()=>[s(i(g))]),_:1})),r(`span`,null,l(i(T)(`@F13B4:创建`)),1)],8,se)])])]),default:m(()=>[r(`div`,U,[s(pe,{model:{newBranchName:X.value,selectedBaseBranch:Z.value},"label-position":`top`},{default:m(()=>[s(k,null,{label:m(()=>[r(`div`,W,[s(u,{class:`label-icon`},{default:m(()=>[s(i(w))]),_:1}),r(`span`,null,l(i(T)(`@F13B4:新分支名称`)),1)])]),default:m(()=>[s(p,{modelValue:X.value,"onUpdate:modelValue":a[3]||=e=>X.value=e,placeholder:i(T)(`@F13B4:请输入新分支名称`),class:`modern-input`,size:`large`,onKeyup:C(Q,[`enter`])},null,8,[`modelValue`,`placeholder`])]),_:1}),s(k,null,{label:m(()=>[r(`div`,G,[s(u,{class:`label-icon`},{default:m(()=>[s(i(re))]),_:1}),r(`span`,null,l(i(T)(`@F13B4:基于分支`)),1)])]),default:m(()=>[s(fe,{modelValue:Z.value,"onUpdate:modelValue":a[4]||=e=>Z.value=e,placeholder:i(T)(`@F13B4:选择基础分支`),class:`modern-select`,size:`large`,style:{width:`100%`}},{default:m(()=>[(f(!0),h(S,null,e(i(c).allBranches,e=>(f(),n(de,{key:e,label:e,value:e},null,8,[`label`,`value`]))),128))]),_:1},8,[`modelValue`,`placeholder`])]),_:1})]),_:1},8,[`model`])])]),_:1},8,[`modelValue`,`title`])])):o(``,!0)}}}),[[`__scopeId`,`data-v-665171bc`]]);export{J as default};