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.
- package/README.md +35 -2
- package/package.json +1 -1
- package/scripts/release.js +139 -48
- package/src/aiCommit.js +6 -3
- package/src/cli/ai/agent.js +106 -311
- package/src/cli/ai/cli.integration.test.js +99 -0
- package/src/cli/ai/context.js +90 -0
- package/src/cli/ai/modelSetup.js +44 -8
- package/src/cli/ai/runtime.test.js +152 -0
- package/src/cli/ai/safety.js +27 -4
- package/src/cli/ai/safety.test.js +13 -0
- package/src/cli/ai/telemetry.js +43 -0
- package/src/cli/ai/termui.js +154 -41
- package/src/cli/ai/termui.test.js +63 -14
- package/src/cli/ai/tools.js +27 -5
- package/src/cli/ai/tools.test.js +23 -0
- package/src/cli/ai/transport.js +89 -0
- package/src/cli/ai/turn.js +126 -0
- package/src/config.js +88 -5
- package/src/ui/public/assets/{AgentView-DJOdvJEV.js → AgentView-CZc191Xm.js} +3 -3
- package/src/ui/public/assets/AgentView-CzUeyQfR.css +1 -0
- package/src/ui/public/assets/{AppVersionBadge-D2Li5_R-.js → AppVersionBadge-Gs5lUl7P.js} +2 -2
- package/src/ui/public/assets/{BranchSelector-CSd5uaVm.js → BranchSelector-IjaFk0S-.js} +1 -1
- package/src/ui/public/assets/{CommitForm-Ckg9-zay.js → CommitForm-C-sowOXH.js} +3 -3
- package/src/ui/public/assets/{CommonDialog-B8XOXtz_.js → CommonDialog-QyptFD1R.js} +1 -1
- package/src/ui/public/assets/{EditorView-Crj8S2TI.js → EditorView-CvvluFCY.js} +1 -1
- package/src/ui/public/assets/{FileDiffViewer-DL07IMz5.js → FileDiffViewer-BXVsdCxE.js} +1 -1
- package/src/ui/public/assets/{FlowExecutionViewer-DvVT19Qv.js → FlowExecutionViewer-CRxipXru.js} +1 -1
- package/src/ui/public/assets/{FlowOrchestrationWorkspace-kRhK9IyL.js → FlowOrchestrationWorkspace-AE1ZHTKF.js} +1 -1
- package/src/ui/public/assets/{IconButton-pqSYKRT8.js → IconButton-BmSueF_H.js} +1 -1
- package/src/ui/public/assets/{LogList-BrN6qtFb.js → LogList-iaVA-_aC.js} +1 -1
- package/src/ui/public/assets/{MindmapView-CSsT0NDZ.js → MindmapView-DcG4jpCh.js} +1 -1
- package/src/ui/public/assets/{MonitorView-edRyBybQ.js → MonitorView-DO59syvl.js} +1 -1
- package/src/ui/public/assets/{ProjectStartupButton-DZ8VgU79.js → ProjectStartupButton-DYppceyw.js} +1 -1
- package/src/ui/public/assets/{RemoteManagerDialog-pu9szuYB.js → RemoteManagerDialog-CDbxG6pZ.js} +1 -1
- package/src/ui/public/assets/{RemoteRepoCard-BSFehgY5.js → RemoteRepoCard-Cko2KB8w.js} +1 -1
- package/src/ui/public/assets/{SourceMapView-DbEydLSU.js → SourceMapView-CwWPVdz-.js} +1 -1
- package/src/ui/public/assets/{SvgIcon-BVCbrPws.js → SvgIcon-Cf7nOKc8.js} +1 -1
- package/src/ui/public/assets/{TemplateManager-DPyYaGCE.js → TemplateManager-DWPDjWxM.js} +1 -1
- package/src/ui/public/assets/{UserInputNode-DXHeCjzG.js → UserInputNode-YOziN-5A.js} +1 -1
- package/src/ui/public/assets/WorkbenchView-DNnEpIYy.js +13 -0
- package/src/ui/public/assets/WorkbenchView-v3QFn6Ln.css +1 -0
- package/src/ui/public/assets/_plugin-vue_export-helper-CQjg8MXm.js +19 -0
- package/src/ui/public/assets/configStore-C7HOx5S1.js +1 -0
- package/src/ui/public/assets/{gitStore-BJbNtjxA.js → gitStore-DIsBd6n4.js} +1 -1
- package/src/ui/public/assets/index-FOe1cHkh.css +1 -0
- package/src/ui/public/assets/index-MmcnT2Dn.js +24 -0
- package/src/ui/public/assets/{previewSandbox-BZV6Eqhv.js → previewSandbox-TKucqLxt.js} +0 -0
- package/src/ui/public/assets/{toolsStore-Bu8Ujw_A.js → toolsStore-BiC2mmC3.js} +1 -1
- package/src/ui/public/assets/{vendor-CwZs6S_i.js → vendor-92fKgtnz.js} +7 -7
- package/src/ui/public/assets/{vendor-_6pgW9Z2.css → vendor-B1UrVTTI.css} +1 -1
- package/src/ui/public/index.html +14 -14
- package/src/ui/server/routes/codeAnalysis.js +6 -3
- package/src/ui/server/routes/config.js +40 -9
- package/src/ui/server/routes/fileOpen.js +48 -2
- package/src/ui/server/routes/gAiLauncher.test.js +70 -0
- package/src/ui/server/routes/workbench/agentChat.js +34 -8
- package/src/ui/server/routes/workbench/index.js +37 -6
- package/src/ui/server/routes/workbench/jobStore.js +4 -0
- package/src/ui/server/routes/workbench/llmClient.js +15 -8
- package/src/ui/server/routes/workbench/taskRunner.js +276 -96
- package/src/ui/server/routes/workbench/taskRunner.opencode.test.js +126 -0
- package/src/utils/aiEndpoint.js +231 -0
- package/src/utils/aiEndpoint.test.js +175 -0
- package/src/ui/public/assets/AgentView-BsN9y4Kg.css +0 -1
- package/src/ui/public/assets/WorkbenchView-CKXtZAJn.css +0 -1
- package/src/ui/public/assets/WorkbenchView-DGcirla3.js +0 -13
- package/src/ui/public/assets/_plugin-vue_export-helper-C-YBnnP5.js +0 -19
- package/src/ui/public/assets/configStore-DoobmT7N.js +0 -1
- package/src/ui/public/assets/index-ClqvC4kJ.css +0 -1
- 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', {
|
|
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 {
|
|
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 {
|
|
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
|
|
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=
|
|
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(),
|
|
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-
|
|
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.
|
|
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-
|
|
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};
|