zen-gitsync 2.17.5 → 2.17.6
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 +13 -0
- package/package.json +1 -1
- package/src/aiCommit.js +6 -3
- package/src/cli/ai/agent.js +23 -8
- package/src/cli/ai/modelSetup.js +6 -8
- package/src/config.js +57 -4
- package/src/ui/public/assets/{AgentView-DJOdvJEV.js → AgentView-BC3F0F6m.js} +3 -3
- package/src/ui/public/assets/AgentView-CzUeyQfR.css +1 -0
- package/src/ui/public/assets/{AppVersionBadge-D2Li5_R-.js → AppVersionBadge-DV6KuLqb.js} +2 -2
- package/src/ui/public/assets/{BranchSelector-CSd5uaVm.js → BranchSelector-DGXDAOkR.js} +1 -1
- package/src/ui/public/assets/{CommitForm-Ckg9-zay.js → CommitForm-BYBj7UUa.js} +1 -1
- package/src/ui/public/assets/{CommonDialog-B8XOXtz_.js → CommonDialog-DWMCeujE.js} +1 -1
- package/src/ui/public/assets/{EditorView-Crj8S2TI.js → EditorView-D-TEQZso.js} +1 -1
- package/src/ui/public/assets/{FileDiffViewer-DL07IMz5.js → FileDiffViewer-C4ZANajI.js} +1 -1
- package/src/ui/public/assets/{FlowExecutionViewer-DvVT19Qv.js → FlowExecutionViewer-DUv7mBuG.js} +1 -1
- package/src/ui/public/assets/{FlowOrchestrationWorkspace-kRhK9IyL.js → FlowOrchestrationWorkspace-BiSuvzL7.js} +1 -1
- package/src/ui/public/assets/{IconButton-pqSYKRT8.js → IconButton-BltPKVbV.js} +1 -1
- package/src/ui/public/assets/{LogList-BrN6qtFb.js → LogList-BY1Haq9r.js} +1 -1
- package/src/ui/public/assets/{MindmapView-CSsT0NDZ.js → MindmapView-BKsvCnYv.js} +1 -1
- package/src/ui/public/assets/{MonitorView-edRyBybQ.js → MonitorView-B3_NaJRy.js} +1 -1
- package/src/ui/public/assets/{ProjectStartupButton-DZ8VgU79.js → ProjectStartupButton-DP3eDVRp.js} +1 -1
- package/src/ui/public/assets/{RemoteManagerDialog-pu9szuYB.js → RemoteManagerDialog-Bl9b_iRv.js} +1 -1
- package/src/ui/public/assets/{RemoteRepoCard-BSFehgY5.js → RemoteRepoCard-TQ3DxDnq.js} +1 -1
- package/src/ui/public/assets/{SourceMapView-DbEydLSU.js → SourceMapView-BF-Mzv3V.js} +1 -1
- package/src/ui/public/assets/{SvgIcon-BVCbrPws.js → SvgIcon-DxazW7dI.js} +1 -1
- package/src/ui/public/assets/{TemplateManager-DPyYaGCE.js → TemplateManager-BN6gWFWX.js} +1 -1
- package/src/ui/public/assets/{UserInputNode-DXHeCjzG.js → UserInputNode-CPwvIfP6.js} +1 -1
- package/src/ui/public/assets/WorkbenchView-CDu61WWs.js +13 -0
- package/src/ui/public/assets/{WorkbenchView-CKXtZAJn.css → WorkbenchView-DEejub9Z.css} +1 -1
- package/src/ui/public/assets/{_plugin-vue_export-helper-C-YBnnP5.js → _plugin-vue_export-helper-B7A-NgBp.js} +5 -5
- package/src/ui/public/assets/configStore-Dx84lvTX.js +1 -0
- package/src/ui/public/assets/{gitStore-BJbNtjxA.js → gitStore-CYrdjXPU.js} +1 -1
- package/src/ui/public/assets/index-DNHOYMCg.js +24 -0
- package/src/ui/public/assets/index-Dsfmp6w8.css +1 -0
- package/src/ui/public/assets/{previewSandbox-BZV6Eqhv.js → previewSandbox-D_j5PWX1.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 +32 -6
- package/src/ui/server/routes/workbench/agentChat.js +34 -8
- package/src/ui/server/routes/workbench/llmClient.js +15 -8
- 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-DGcirla3.js +0 -13
- 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
package/README.md
CHANGED
|
@@ -384,6 +384,7 @@ A dedicated view (robot icon in the activity bar) for chatting with the built-in
|
|
|
384
384
|
| Streaming chat | SSE-based real-time streaming with thinking process, content, tool calls, and tool results rendered inline |
|
|
385
385
|
| Tool call display | Each tool invocation (run_command, read_file, edit_file, list_files, search_text, write_file) is shown as a collapsible card with arguments preview and execution result |
|
|
386
386
|
| Session persistence | All conversations are saved to `~/.zen-gitsync/agent-sessions/` as JSON files; the CLI agent (`g ai`) writes to the same directory so Web and CLI sessions are unified |
|
|
387
|
+
| Per-turn tool limit | A single message may trigger up to N tool calls in a row (default **200**, range 1–2000). Configurable in **Settings → AI models → Agent Runtime**; hitting the limit ends the turn and asks you to send another message. The same setting drives the CLI agent |
|
|
387
388
|
| Preset questions | Quick-start buttons on the welcome screen for common tasks (view project structure, analyze code quality, write tests, check git status) |
|
|
388
389
|
| Stop generation | A floating stop button appears during streaming; aborts the LLM request and any running child processes |
|
|
389
390
|
| Theme sync | The chat area follows the GUI's current theme (light / dark / auto) |
|
|
@@ -454,6 +455,12 @@ to numeric input. `Esc` or `Ctrl+C` cancels the wizard cleanly.
|
|
|
454
455
|
|
|
455
456
|
In-session commands: `/help`, `/model`, `/addmodel`, `/cd <path>`, `/image [path]`, `/think`, `/clear`, `/exit`.
|
|
456
457
|
|
|
458
|
+
Tool-call budget: one message may trigger up to N tool calls in a row before the turn is
|
|
459
|
+
force-ended with a "max tool iterations reached" notice (send another message to continue).
|
|
460
|
+
N defaults to **200** and is configurable in **Settings → AI models → Agent Runtime**
|
|
461
|
+
(`aiMaxToolIterations` in `~/.zen-gitsync/config.json`, range 1–2000) — the Web agent shares
|
|
462
|
+
the same value.
|
|
463
|
+
|
|
457
464
|
Images: press `Alt+V` in the REPL to paste a clipboard image (screenshot), or attach a
|
|
458
465
|
local file with `/image <path>`; images are sent as multimodal `image_url` parts with your
|
|
459
466
|
next message (requires a vision-capable model). `/image` alone lists pending images,
|
|
@@ -973,6 +980,7 @@ Activity Bar 中的机器人图标视图,可直接在浏览器中与内置 AI
|
|
|
973
980
|
| 流式对话 | 基于 SSE 的实时流式输出,包含思考过程、正文内容、工具调用和工具结果的内联渲染 |
|
|
974
981
|
| 工具调用展示 | 每次工具调用(run_command、read_file、edit_file、list_files、search_text、write_file)以可折叠卡片形式展示,含参数预览和执行结果 |
|
|
975
982
|
| 会话持久化 | 所有对话保存为 JSON 文件到 `~/.zen-gitsync/agent-sessions/`;CLI 智能体(`g ai`)写入同一目录,Web 端与 CLI 端会话统一管理 |
|
|
983
|
+
| 单轮工具调用上限 | 一条消息内智能体最多连续调用多少次工具(默认 **200**,可调范围 1–2000)。在 **设置 → AI 模型配置 → 智能体运行时** 中修改;达到上限本轮会被强制结束并提示再发一条消息继续。CLI 智能体共用同一项设置 |
|
|
976
984
|
| 预设问题 | 开场界面提供快捷按钮(查看项目结构、分析代码质量、写测试、Git 状态检查)|
|
|
977
985
|
| 停止生成 | 流式输出期间出现浮动停止按钮;中止 LLM 请求及正在运行的子进程 |
|
|
978
986
|
| 主题同步 | 对话区域跟随 GUI 当前主题(浅色 / 深色 / 自动)|
|
|
@@ -1038,6 +1046,11 @@ $ g ai --model=2 # 使用第 2 个已配置的模型(序号或
|
|
|
1038
1046
|
|
|
1039
1047
|
会话内命令:`/help`、`/model`、`/addmodel`、`/cd <路径>`、`/image [路径]`、`/think`、`/clear`、`/exit`。
|
|
1040
1048
|
|
|
1049
|
+
工具调用预算:一条消息内智能体最多连续调用 N 次工具,触顶后本轮被强制结束并提示
|
|
1050
|
+
"已达单轮最大工具调用次数",再发一条消息即可继续。N 默认 **200**,可在
|
|
1051
|
+
**设置 → AI 模型配置 → 智能体运行时** 修改(即 `~/.zen-gitsync/config.json` 的
|
|
1052
|
+
`aiMaxToolIterations`,范围 1–2000),Web 端智能体共用同一项设置。
|
|
1053
|
+
|
|
1041
1054
|
图片:在 REPL 中按 `Alt+V` 粘贴剪贴板图片(截图),或用 `/image <路径>` 附加本地图片;
|
|
1042
1055
|
图片以多模态 `image_url` 部件随下一条消息发送(需视觉模型)。单独 `/image` 查看待发送图片,
|
|
1043
1056
|
`/image clear` 清除。
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zen-gitsync",
|
|
3
|
-
"version": "2.17.
|
|
3
|
+
"version": "2.17.6",
|
|
4
4
|
"description": "Auto commit, scheduled sync, and visual GUI for Git. Run `g` in any repo for one-key commit & push, AI commit messages, scheduled background sync, and a drag-and-drop workflow builder.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
package/src/aiCommit.js
CHANGED
|
@@ -19,6 +19,7 @@ import chalk from 'chalk';
|
|
|
19
19
|
import ora from 'ora';
|
|
20
20
|
import config from './config.js';
|
|
21
21
|
import { execGitCommand } from './utils/index.js';
|
|
22
|
+
import { buildAiChatRequest } from './utils/aiEndpoint.js';
|
|
22
23
|
|
|
23
24
|
// ──────────────────────────────────────────────
|
|
24
25
|
// 跳过的产物/资源/lock 文件(与 GUI config.js SKIP_FILE_PATTERNS 一致)
|
|
@@ -276,9 +277,11 @@ ${diffText || '(no staged content, please infer from the file list)'}`;
|
|
|
276
277
|
// 4. 调用 LLM
|
|
277
278
|
spinner.start('AI 正在生成提交信息...');
|
|
278
279
|
const { default: fetch } = await import('node-fetch').catch(() => ({ default: globalThis.fetch }));
|
|
279
|
-
const url =
|
|
280
|
-
|
|
281
|
-
|
|
280
|
+
const { url, headers } = buildAiChatRequest({
|
|
281
|
+
baseURL: defaultModel.baseURL,
|
|
282
|
+
model: defaultModel.model,
|
|
283
|
+
apiKey: defaultModel.apiKey
|
|
284
|
+
});
|
|
282
285
|
const body = JSON.stringify({
|
|
283
286
|
model: defaultModel.model,
|
|
284
287
|
messages: [{ role: 'user', content: prompt }],
|
package/src/cli/ai/agent.js
CHANGED
|
@@ -58,6 +58,7 @@ import {
|
|
|
58
58
|
import { readClipboardImage, checkImageFile, imageToDataUrl, formatBytes } from './images.js'
|
|
59
59
|
import { runModelSetup, collectModelInput, buildModelConfig, selectFromList } from './modelSetup.js'
|
|
60
60
|
import { genSessionId, autoTitle, writeSession, enforceRetention, listSessions } from './sessionStore.js'
|
|
61
|
+
import { buildAiChatRequest, describeAiHttpError } from '../../utils/aiEndpoint.js'
|
|
61
62
|
|
|
62
63
|
// truncateDisplay 已迁移到 termui.js;这里 re-export 保持既有测试/外部引用不断
|
|
63
64
|
export { truncateDisplay } from './termui.js'
|
|
@@ -65,7 +66,7 @@ export { truncateDisplay } from './termui.js'
|
|
|
65
66
|
// ──────────────────────────────────────────────
|
|
66
67
|
// 常量
|
|
67
68
|
// ──────────────────────────────────────────────
|
|
68
|
-
const
|
|
69
|
+
const DEFAULT_MAX_TOOL_ITERATIONS = 200 // 单轮工具调用循环数兜底值(防失控);实际值取配置里的 aiMaxToolIterations
|
|
69
70
|
const MAX_HISTORY_MESSAGES = 40 // 历史消息上限(超出后从最旧的整段对话裁剪)
|
|
70
71
|
const LLM_TIMEOUT_MS = 300000 // 单次 LLM 请求超时(5 分钟,长推理模型够用)
|
|
71
72
|
|
|
@@ -285,10 +286,14 @@ ${isWin ? `- This is Windows cmd.exe. The following Unix commands do NOT exist h
|
|
|
285
286
|
// LLM 流式调用(OpenAI 兼容 + function calling)
|
|
286
287
|
// 返回 { content, toolCalls, aborted }
|
|
287
288
|
// ──────────────────────────────────────────────
|
|
288
|
-
async function streamChatOnce({ model, messages, signal, onToken }) {
|
|
289
|
-
|
|
290
|
-
const headers = {
|
|
291
|
-
|
|
289
|
+
async function streamChatOnce({ model, messages, signal, onToken, sessionId }) {
|
|
290
|
+
// sessionId = 会话 ID:OpenCode 网关靠它做路由与提示缓存,同一条会话的所有请求要复用
|
|
291
|
+
const { url, headers } = buildAiChatRequest({
|
|
292
|
+
baseURL: model.baseURL,
|
|
293
|
+
model: model.model,
|
|
294
|
+
apiKey: model.apiKey,
|
|
295
|
+
sessionId,
|
|
296
|
+
})
|
|
292
297
|
|
|
293
298
|
const body = JSON.stringify({
|
|
294
299
|
model: model.model,
|
|
@@ -314,7 +319,8 @@ async function streamChatOnce({ model, messages, signal, onToken }) {
|
|
|
314
319
|
const resp = await fetch(url, { method: 'POST', headers, body, signal: controller.signal })
|
|
315
320
|
if (!resp.ok || !resp.body) {
|
|
316
321
|
const errText = await resp.text().catch(() => '')
|
|
317
|
-
|
|
322
|
+
// 抽 error.message:provider 的说明都在里面,整坨 JSON 打到终端没法看
|
|
323
|
+
const snippet = describeAiHttpError(errText, resp.status)
|
|
318
324
|
// 400 且提到 tools/functions:大概率是模型不支持 function calling
|
|
319
325
|
if (resp.status === 400 && /tool|function/i.test(snippet)) {
|
|
320
326
|
throw new Error(`HTTP 400: 当前模型可能不支持 function calling(${snippet})。请在 g ui 中换用支持工具调用的模型(如 deepseek / qwen / gpt 系列)。`)
|
|
@@ -472,7 +478,11 @@ async function runAgentTurn(state, userText, t, images = []) {
|
|
|
472
478
|
// 旧消息里的图片降级为占位文字,防止 base64 随对话轮次累积撑爆上下文
|
|
473
479
|
stripStaleImages(state.messages, state.locale)
|
|
474
480
|
|
|
475
|
-
|
|
481
|
+
const maxIterations = Number.isFinite(state.maxToolIterations) && state.maxToolIterations > 0
|
|
482
|
+
? state.maxToolIterations
|
|
483
|
+
: DEFAULT_MAX_TOOL_ITERATIONS
|
|
484
|
+
|
|
485
|
+
for (let iter = 0; iter < maxIterations; iter++) {
|
|
476
486
|
trimHistory(state.messages)
|
|
477
487
|
|
|
478
488
|
// 首个 token 到达前转 spinner,到达后停掉并让位给流式渲染
|
|
@@ -508,6 +518,8 @@ async function runAgentTurn(state, userText, t, images = []) {
|
|
|
508
518
|
model: state.model,
|
|
509
519
|
messages: state.messages,
|
|
510
520
|
signal: state.abortController?.signal,
|
|
521
|
+
// 同一会话(含工具调用产生的每一轮请求)复用同一个会话 ID
|
|
522
|
+
sessionId: state.sessionId,
|
|
511
523
|
onToken: ({ thinking, content }) => {
|
|
512
524
|
if (thinking) renderSeg({ thinking })
|
|
513
525
|
if (content) for (const seg of thinkFilter.feed(content)) renderSeg(seg)
|
|
@@ -580,7 +592,7 @@ async function runAgentTurn(state, userText, t, images = []) {
|
|
|
580
592
|
// 工具结果全部入历史后继续循环,让模型基于结果决定下一步
|
|
581
593
|
}
|
|
582
594
|
|
|
583
|
-
printWarn(t.toolIterLimit(
|
|
595
|
+
printWarn(t.toolIterLimit(maxIterations))
|
|
584
596
|
}
|
|
585
597
|
|
|
586
598
|
// JSON 解析失败时的参数回显:单行截断,不进 summarizeToolArgs(它没有结构化参数可用)
|
|
@@ -897,6 +909,9 @@ export async function runAiAgent(argv = []) {
|
|
|
897
909
|
model,
|
|
898
910
|
locale,
|
|
899
911
|
shellDesc,
|
|
912
|
+
// 单轮工具调用上限:来自全局配置 aiMaxToolIterations(loadConfig 已规范化),
|
|
913
|
+
// 读不到时由 runAgentTurn 兜底成 DEFAULT_MAX_TOOL_ITERATIONS
|
|
914
|
+
maxToolIterations: cfg.aiMaxToolIterations,
|
|
900
915
|
currentChild: null,
|
|
901
916
|
abortController: null,
|
|
902
917
|
cancelRequested: false,
|
package/src/cli/ai/modelSetup.js
CHANGED
|
@@ -35,6 +35,7 @@ import readline from 'node:readline'
|
|
|
35
35
|
import chalk from 'chalk'
|
|
36
36
|
import config from '../../config.js'
|
|
37
37
|
import { startSpinner, renderSelectableListBody, parseKeyForSelectableList } from './termui.js'
|
|
38
|
+
import { buildAiChatRequest, buildAiApiRequest } from '../../utils/aiEndpoint.js'
|
|
38
39
|
|
|
39
40
|
// ──────────────────────────────────────────────
|
|
40
41
|
// 预设服务商列表
|
|
@@ -279,14 +280,13 @@ export async function fetchModelsFromApi({ baseURL, apiKey, timeoutMs = 5000, fe
|
|
|
279
280
|
const fetch = fetchFn || globalThis.fetch
|
|
280
281
|
if (!fetch) return []
|
|
281
282
|
|
|
282
|
-
const url = `${String(baseURL || '').replace(/\/$/, '')}/models`
|
|
283
|
-
const headers = {}
|
|
284
|
-
if (apiKey) headers['Authorization'] = `Bearer ${apiKey}`
|
|
285
|
-
|
|
286
283
|
const controller = new AbortController()
|
|
287
284
|
const timer = setTimeout(() => controller.abort(), timeoutMs)
|
|
288
285
|
|
|
289
286
|
try {
|
|
287
|
+
// 拉模型列表也要带客户端身份/会话头:OpenCode 网关对没有身份的请求照样拦。
|
|
288
|
+
// 放在 try 里保证"本函数不抛错"的契约不被 baseURL 为空破坏。
|
|
289
|
+
const { url, headers } = buildAiApiRequest({ baseURL, path: '/models', apiKey })
|
|
290
290
|
const res = await fetch(url, {
|
|
291
291
|
method: 'GET',
|
|
292
292
|
headers,
|
|
@@ -327,10 +327,6 @@ export async function testModelConnection({ baseURL, model, apiKey, timeoutMs =
|
|
|
327
327
|
const fetch = fetchFn || globalThis.fetch
|
|
328
328
|
if (!fetch) throw new Error('fetch is not available')
|
|
329
329
|
|
|
330
|
-
const url = `${String(baseURL || '').replace(/\/$/, '')}/chat/completions`
|
|
331
|
-
const headers = { 'Content-Type': 'application/json' }
|
|
332
|
-
if (apiKey) headers['Authorization'] = `Bearer ${apiKey}`
|
|
333
|
-
|
|
334
330
|
const body = JSON.stringify({
|
|
335
331
|
model,
|
|
336
332
|
messages: [{ role: 'user', content: 'hi' }],
|
|
@@ -341,6 +337,8 @@ export async function testModelConnection({ baseURL, model, apiKey, timeoutMs =
|
|
|
341
337
|
const controller = new AbortController()
|
|
342
338
|
const timer = setTimeout(() => controller.abort(), timeoutMs)
|
|
343
339
|
try {
|
|
340
|
+
// 统一构造:身份/会话头 + OpenCode 网关的协议族校验(非 chat 模型直接给可读报错)
|
|
341
|
+
const { url, headers } = buildAiChatRequest({ baseURL, model, apiKey })
|
|
344
342
|
const res = await fetch(url, {
|
|
345
343
|
method: 'POST',
|
|
346
344
|
headers,
|
package/src/config.js
CHANGED
|
@@ -50,6 +50,29 @@ 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
|
+
|
|
53
76
|
// 默认配置
|
|
54
77
|
const defaultConfig = {
|
|
55
78
|
defaultCommitMessage: "submit",
|
|
@@ -90,6 +113,11 @@ const defaultConfig = {
|
|
|
90
113
|
locale: 'zh-CN', // 语言: zh-CN | en-US
|
|
91
114
|
// AI 模型配置
|
|
92
115
|
models: [],
|
|
116
|
+
// AI 智能体单轮最大工具调用次数(防失控)。CLI `g ai` 与 Web 智能体共用,全局生效。
|
|
117
|
+
// 2026-09-20: 40 → 200。40 轮在"读多个文件 → 逐个验证 → 再改"这类任务里很容易触顶,
|
|
118
|
+
// 触顶后本轮被强制结束,用户必须再发一条消息才能接着跑,体感像被截断。
|
|
119
|
+
// 想调小/调大改这个值即可(GUI: 设置 → AI 模型配置)。
|
|
120
|
+
aiMaxToolIterations: 200,
|
|
93
121
|
// UI 状态(跨项目共享,存到顶层 ui 对象)
|
|
94
122
|
// 之前散落在 localStorage,因随机端口启动而失效,迁到文件持久化
|
|
95
123
|
ui: {
|
|
@@ -396,7 +424,12 @@ async function loadConfig() {
|
|
|
396
424
|
}
|
|
397
425
|
// 兼容旧版(全局扁平结构)
|
|
398
426
|
if (raw && !raw.projects) {
|
|
399
|
-
return {
|
|
427
|
+
return {
|
|
428
|
+
...defaultConfig,
|
|
429
|
+
...raw,
|
|
430
|
+
aiMaxToolIterations: normalizeAiMaxToolIterations(raw.aiMaxToolIterations)
|
|
431
|
+
?? defaultConfig.aiMaxToolIterations
|
|
432
|
+
};
|
|
400
433
|
}
|
|
401
434
|
|
|
402
435
|
// 新版结构:{ projects: { [key]: projectConfig }, theme?, locale?, ui?, recentDirectories? }
|
|
@@ -409,7 +442,10 @@ async function loadConfig() {
|
|
|
409
442
|
theme: raw?.theme ?? defaultConfig.theme,
|
|
410
443
|
locale: raw?.locale ?? defaultConfig.locale,
|
|
411
444
|
models: raw?.models ?? defaultConfig.models,
|
|
412
|
-
ui: raw?.ui ?? defaultConfig.ui
|
|
445
|
+
ui: raw?.ui ?? defaultConfig.ui,
|
|
446
|
+
// 同 models:全局配置,始终取顶层,防止被项目配置里的旧值覆盖
|
|
447
|
+
aiMaxToolIterations: normalizeAiMaxToolIterations(raw?.aiMaxToolIterations)
|
|
448
|
+
?? defaultConfig.aiMaxToolIterations
|
|
413
449
|
};
|
|
414
450
|
}
|
|
415
451
|
|
|
@@ -457,7 +493,7 @@ async function saveConfig(config) {
|
|
|
457
493
|
|
|
458
494
|
// 分离全局设置和项目设置
|
|
459
495
|
// models / ui 也是全局配置(跨项目共享),和 theme/locale 一样存到顶层
|
|
460
|
-
const { theme, locale, models, ui, ...projectConfig } = config;
|
|
496
|
+
const { theme, locale, models, ui, aiMaxToolIterations, ...projectConfig } = config;
|
|
461
497
|
|
|
462
498
|
// 保存全局设置到根级别
|
|
463
499
|
if (theme !== undefined) {
|
|
@@ -472,6 +508,11 @@ async function saveConfig(config) {
|
|
|
472
508
|
if (ui !== undefined) {
|
|
473
509
|
raw.ui = ui;
|
|
474
510
|
}
|
|
511
|
+
// 工具调用上限同属全局设置:非法值不落盘(保留磁盘上的旧值),避免把手改坏的值固化
|
|
512
|
+
const normalizedIterations = normalizeAiMaxToolIterations(aiMaxToolIterations);
|
|
513
|
+
if (normalizedIterations !== null) {
|
|
514
|
+
raw.aiMaxToolIterations = normalizedIterations;
|
|
515
|
+
}
|
|
475
516
|
|
|
476
517
|
// 写入当前项目配置(在 defaultConfig 基础上合并,但不清空顶层其它键)
|
|
477
518
|
const existingProjectConfig = (raw.projects[key] && typeof raw.projects[key] === 'object') ? raw.projects[key] : {};
|
|
@@ -662,7 +703,19 @@ export default {
|
|
|
662
703
|
// 显式删除某个项目的全部分文件。写路径刻意不做删除(防"只加载了一个项目就写回"
|
|
663
704
|
// 连带清空其它项目),清理失效项目只能走这里。
|
|
664
705
|
deleteProjectConfig: deleteProjectConfigAndInvalidate,
|
|
706
|
+
// AI 智能体单轮工具调用上限的规范化/区间(GUI 保存前也要用,见 /api/config/save-ai-settings)
|
|
707
|
+
normalizeAiMaxToolIterations,
|
|
708
|
+
AI_MAX_TOOL_ITERATIONS_MIN,
|
|
709
|
+
AI_MAX_TOOL_ITERATIONS_MAX,
|
|
665
710
|
};
|
|
666
711
|
|
|
667
712
|
// 命名导出 — 用于测试与外部复用
|
|
668
|
-
export {
|
|
713
|
+
export {
|
|
714
|
+
ConfigWriteError,
|
|
715
|
+
normalizeProjectPath,
|
|
716
|
+
invalidateCurrentProjectKey,
|
|
717
|
+
invalidateRawConfigCache,
|
|
718
|
+
normalizeAiMaxToolIterations,
|
|
719
|
+
AI_MAX_TOOL_ITERATIONS_MIN,
|
|
720
|
+
AI_MAX_TOOL_ITERATIONS_MAX,
|
|
721
|
+
};
|
|
@@ -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-B7A-NgBp.js";import{t as P}from"./configStore-Dx84lvTX.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-B7A-NgBp.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.6`,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-B7A-NgBp.js";import{t as D}from"./SvgIcon-DxazW7dI.js";import{t as O}from"./IconButton-BltPKVbV.js";import{t as k}from"./gitStore-CYrdjXPU.js";import{t as A}from"./CommonDialog-DWMCeujE.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};
|