zen-gitsync 2.17.15 → 2.17.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/README.md +6 -6
  2. package/package.json +1 -1
  3. package/src/cli/ai/agent.js +24 -2
  4. package/src/cli/ai/runtime.test.js +1 -1
  5. package/src/cli/ai/tools.js +7 -1
  6. package/src/cli/ai/tools.test.js +11 -0
  7. package/src/config.js +4 -4
  8. package/src/ui/public/assets/AgentView-DOyN97Ve.js +5 -0
  9. package/src/ui/public/assets/{AgentView-vvVhbIQ5.css → AgentView-DkM2KXuc.css} +1 -1
  10. package/src/ui/public/assets/{AppVersionBadge-D5iXcAEV.js → AppVersionBadge-oON3sAj4.js} +2 -2
  11. package/src/ui/public/assets/{BranchSelector-DP4u1f_B.js → BranchSelector-Cpj7eGqY.js} +1 -1
  12. package/src/ui/public/assets/{CommitForm-boOw8uGS.js → CommitForm-D_ovYhVw.js} +1 -1
  13. package/src/ui/public/assets/{CommonDialog-B_qUsIGr.js → CommonDialog-ChZbqfRF.js} +1 -1
  14. package/src/ui/public/assets/{EditorView-ZULtfIzl.js → EditorView-BPzpI0GV.js} +1 -1
  15. package/src/ui/public/assets/{FileDiffViewer-C4xxq5S0.js → FileDiffViewer-B_qEKA9L.js} +1 -1
  16. package/src/ui/public/assets/{FlowExecutionViewer-BmfstdaT.js → FlowExecutionViewer-Drw4hlJG.js} +1 -1
  17. package/src/ui/public/assets/{FlowOrchestrationWorkspace-28kErqrn.js → FlowOrchestrationWorkspace-C7yTD1gj.js} +1 -1
  18. package/src/ui/public/assets/{IconButton-DcOAqpq0.js → IconButton-DEARmMkZ.js} +1 -1
  19. package/src/ui/public/assets/{LogList-FEP7EeJt.js → LogList-BA_gowxE.js} +1 -1
  20. package/src/ui/public/assets/{MindmapView-NDJvfSCn.js → MindmapView-K-XcLLXr.js} +1 -1
  21. package/src/ui/public/assets/{MonitorView-DU4aBCK0.js → MonitorView-C0RL5K9W.js} +1 -1
  22. package/src/ui/public/assets/{ProjectStartupButton-JQk4Etsu.js → ProjectStartupButton-DC36_vvU.js} +1 -1
  23. package/src/ui/public/assets/{RemoteManagerDialog-Di2WizMS.js → RemoteManagerDialog-Bkqja660.js} +1 -1
  24. package/src/ui/public/assets/{RemoteRepoCard-DxB8Q8yE.js → RemoteRepoCard-Bsm7cj_H.js} +1 -1
  25. package/src/ui/public/assets/{SourceMapView-CfmrPMBm.js → SourceMapView-Y5NKdIk6.js} +1 -1
  26. package/src/ui/public/assets/{SvgIcon-yefEMV0-.js → SvgIcon-D_mFHXP4.js} +1 -1
  27. package/src/ui/public/assets/{TemplateManager-CCy_WcSK.js → TemplateManager-BzKVXZhy.js} +1 -1
  28. package/src/ui/public/assets/{UserInputNode-3Gv_9YZx.js → UserInputNode-BPLK4aYx.js} +1 -1
  29. package/src/ui/public/assets/{WorkbenchView-Dgp6A83v.js → WorkbenchView-xbGdiVMQ.js} +25 -25
  30. package/src/ui/public/assets/{_plugin-vue_export-helper-B1mHBne9.js → _plugin-vue_export-helper-dg2VUnSQ.js} +3 -3
  31. package/src/ui/public/assets/configStore-DtjAc3w9.js +1 -0
  32. package/src/ui/public/assets/{gitStore-D5CWxPLv.js → gitStore-BZo9_zyy.js} +1 -1
  33. package/src/ui/public/assets/{index-gpuX9fhG.js → index-CHuCYLWm.js} +45 -45
  34. package/src/ui/public/assets/{previewSandbox-qLKxghfr.js → previewSandbox-BTTTXooN.js} +0 -0
  35. package/src/ui/public/assets/{vendor-C5qX_I8r.css → vendor-DnB9EJa3.css} +1 -1
  36. package/src/ui/public/assets/{vendor-IQQMq-1c.js → vendor-bdHhLiED.js} +43 -43
  37. package/src/ui/public/index.html +12 -12
  38. package/src/ui/server/routes/workbench/agentChat.js +3 -2
  39. package/src/ui/server/routes/workbench/agentMarketplace.js +23 -9
  40. package/src/ui/server/routes/workbench/agentMarketplace.test.js +32 -0
  41. package/src/ui/server/routes/workbench/agentRoutes.js +14 -7
  42. package/src/ui/server/routes/workbench/agentRoutes.test.js +47 -1
  43. package/src/ui/server/routes/workbench/taskRunner.codex.test.js +173 -0
  44. package/src/ui/server/routes/workbench/taskRunner.js +259 -10
  45. package/src/ui/server/routes/workbench/taskRunner.opencode.test.js +4 -2
  46. package/src/ui/public/assets/AgentView-Bz9LFamz.js +0 -5
  47. package/src/ui/public/assets/configStore-BDxel6Co.js +0 -1
@@ -15,13 +15,15 @@
15
15
  // 任务执行引擎:spawn 本地 agent CLI 跑子任务,流式收集输出,更新 job 状态。
16
16
  // 拆分自原 routes/workbench.js 1108-1564 行。
17
17
  //
18
- // 支持两种执行器(executor):
18
+ // 支持三种执行器(executor):
19
19
  // - claude —— claude -p --output-format stream-json(默认,历史行为)
20
20
  // - opencode —— opencode run --format json --auto(sst/opencode CLI,跟随其自身默认模型)
21
+ // - codex —— codex exec --json(OpenAI Codex CLI,跟随其自身配置;2026-09-27 加入)
21
22
  //
22
23
  // 核心 API:
23
24
  // - launchClaudeInNewWindow(cwd, prompt, resumeSessionId) spawn claude,返回 {pid, child}
24
25
  // - launchOpencodeRun(cwd, prompt, resumeSessionId) spawn opencode,返回 {pid, child}
26
+ // - launchCodexExec(cwd, prompt, resumeSessionId) spawn codex,返回 {pid, child}
25
27
  // - normalizeTaskExecutor(value) 非法值回落 'claude'
26
28
  // - runSingleSubtask(task, sub, repoPath, branch, opts) 跑一次任务(sub 是运行载体,见下)
27
29
  // - waitProcessExit(pid) polling 等进程退出
@@ -185,10 +187,11 @@ function attachPromptStdin(child, promptText, resolve, reject) {
185
187
  }
186
188
 
187
189
  // ── 执行器(executor) ──────────────────────────────────────────────────
188
- // 工作台任务默认由 claude CLI 执行;opencode 作为可选执行器(2026-09-20)。
189
- // 两者都用「stdin 喂 prompt + stdout 结构化 JSON 事件流」的同构形态,
190
- // 差异只在协议:claude 是 stream-json,opencode 是 --format json 的事件 NDJSON。
191
- export const TASK_EXECUTORS = ['claude', 'opencode'];
190
+ // 工作台任务默认由 claude CLI 执行;opencode(2026-09-20)、codex(2026-09-27)
191
+ // 作为可选执行器。三者都用「stdin 喂 prompt + stdout 结构化 JSON 事件流」的同构形态,
192
+ // 差异只在协议:claude 是 stream-json,opencode 是 --format json 的事件 NDJSON,
193
+ // codex 是 exec --json 的 thread/item 事件 NDJSON。
194
+ export const TASK_EXECUTORS = ['claude', 'opencode', 'codex'];
192
195
 
193
196
  /** 非法/缺省的 executor 一律回落 'claude'(历史行为的兼容兜底)。
194
197
  * body.executor 来自网络,做一次 trim + 小写归一,与 config.js 同名函数同语义。 */
@@ -269,6 +272,95 @@ export function launchOpencodeRun(cwd, promptText, resumeSessionId) {
269
272
  });
270
273
  }
271
274
 
275
+ // ── codex 执行器(2026-09-27 加入) ──────────────────────────────────────
276
+ // codex exec 是非交互模式,形态与另两个执行器同构(stdin 喂 prompt + stdout NDJSON):
277
+ //
278
+ // codex exec [resume <thread_id>] --json --skip-git-repo-check
279
+ // --dangerously-bypass-approvals-and-sandbox - (`-` = prompt 从 stdin 读)
280
+ //
281
+ // - --json 输出 JSONL 事件流(thread.started / item.* / turn.*)
282
+ // - --dangerously-bypass-approvals-and-sandbox
283
+ // 免批准 + 免沙箱,对应 claude 的 bypassPermissions、opencode 的 --auto。
284
+ // 工作台任务全程无人应答批准提示,不跳过的话一遇审批就卡死
285
+ // - --skip-git-repo-check
286
+ // 工作台允许在非 git 目录建任务,不跳过的话 codex 直接拒绝启动
287
+ // - 不传 -m / -s:模型与沙箱跟随 codex 自身配置(同 opencode 的口径)
288
+ // - 续聊:codex exec resume <thread_id>,thread_id 来自 thread.started 事件
289
+
290
+ /**
291
+ * Windows 下把 codex 解析成可直接 spawn 的 exe。
292
+ *
293
+ * npm 全局安装的 codex 是 .cmd shim(Node 23+ 拒绝 spawn .cmd,EINVAL),shim 指向
294
+ * `node bin/codex.js`;而 bin/codex.js 自己也只是一层壳,真正干活的原生二进制在平台
295
+ * 子包里:node_modules/@openai/codex/node_modules/@openai/codex-win32-<arch>/vendor/
296
+ * <triple>/bin/codex.exe(与 bin/codex.js 的查找口径一致,另留一份无平台子包的兜底路径)。
297
+ *
298
+ * 为什么不直接 spawn(process.execPath, [bin/codex.js, ...]):那层壳会再 spawn 一次原生
299
+ * 二进制,取消任务时 kill 到的只是壳进程,原生 codex 会变孤儿继续改文件。
300
+ */
301
+ function resolveCodexExe() {
302
+ try {
303
+ const lines = execFileSync('where', ['codex'], { encoding: 'utf8', windowsHide: true })
304
+ .split(/\r?\n/).map(s => s.trim()).filter(Boolean);
305
+ // 独立安装(scoop / 手动下载 / 包管理器直装)优先:PATH 上直接就是原生 exe
306
+ const directExe = lines.find(s => /\.exe$/i.test(s));
307
+ if (directExe && fs.existsSync(directExe)) return directExe;
308
+ const cmdShim = lines.find(s => /\.cmd$/i.test(s));
309
+ if (cmdShim) {
310
+ const prefix = path.dirname(cmdShim);
311
+ const triple = process.arch === 'arm64' ? 'aarch64-pc-windows-msvc' : 'x86_64-pc-windows-msvc';
312
+ const archTag = process.arch === 'arm64' ? 'arm64' : 'x64';
313
+ const candidates = [
314
+ path.join(prefix, 'node_modules', '@openai', 'codex', 'node_modules', '@openai',
315
+ `codex-win32-${archTag}`, 'vendor', triple, 'bin', 'codex.exe'),
316
+ path.join(prefix, 'node_modules', '@openai', 'codex', 'vendor', triple, 'bin', 'codex.exe'),
317
+ ];
318
+ for (const exe of candidates) {
319
+ if (fs.existsSync(exe)) return exe;
320
+ }
321
+ }
322
+ } catch { /* fallback */ }
323
+ // 兜底交给 PATH:装在非 npm 全局目录时通常有 codex.exe
324
+ return 'codex.exe';
325
+ }
326
+
327
+ /**
328
+ * codex 子进程环境。
329
+ * RUST_LOG=error:codex 默认把 tracing 的 INFO 日志写 stderr,而 stderr 里非 JSON 行
330
+ * 会被当正文贴进输出面板(实测一次执行能刷出上百行);压到 error 档即可清干净,
331
+ * 真正的报错走 stdout 的 JSON 事件流(error / turn.failed),信息不丢。
332
+ */
333
+ function buildCodexEnv() {
334
+ return { ...process.env, LANG: 'zh_CN.UTF-8', RUST_LOG: 'error' };
335
+ }
336
+
337
+ /** spawn codex exec 跑一个 prompt,返回 { pid, child }(参数口径见上方注释)。 */
338
+ export function launchCodexExec(cwd, promptText, resumeSessionId) {
339
+ return new Promise((resolve, reject) => {
340
+ const flags = ['--json', '--skip-git-repo-check', '--dangerously-bypass-approvals-and-sandbox'];
341
+ const args = resumeSessionId
342
+ ? ['exec', 'resume', ...flags, String(resumeSessionId), '-']
343
+ : ['exec', ...flags, '-'];
344
+ let child;
345
+ if (process.platform === 'win32') {
346
+ child = spawn(resolveCodexExe(), args, {
347
+ cwd,
348
+ stdio: ['pipe', 'pipe', 'pipe'],
349
+ windowsHide: false,
350
+ env: buildCodexEnv()
351
+ });
352
+ } else {
353
+ child = spawn('codex', args, {
354
+ cwd,
355
+ detached: true,
356
+ stdio: ['pipe', 'pipe', 'pipe'],
357
+ env: buildCodexEnv()
358
+ });
359
+ }
360
+ attachPromptStdin(child, promptText, resolve, reject);
361
+ });
362
+ }
363
+
272
364
  // ── 工具调用(tool_use)收集 ──────────────────────────────────────────────
273
365
  // 为什么要有这一层:job.output 只承载「模型说的话」。工具调用(读了哪个文件、跑了什么命令、
274
366
  // 拿到了什么结果)原本在两个事件处理器里被整段丢掉,于是前端只剩「思考 + 正文」两块,
@@ -585,6 +677,156 @@ export function createOpencodeEventHandler(job, appendOutput, appendThinking, to
585
677
  };
586
678
  }
587
679
 
680
+ /**
681
+ * codex `exec --json` 事件处理器。
682
+ *
683
+ * 事件形态(codex-cli 0.157.x;schema 源:openai/codex codex-rs/exec/src/exec_events.rs):
684
+ * { type:'thread.started', thread_id } 会话续接标识(exec resume <id>)
685
+ * { type:'turn.started' } / { type:'turn.completed', usage }
686
+ * { type:'turn.failed', error:{ message } } 本轮终态失败(进程退出码可能仍是 0)
687
+ * { type:'item.started'|'item.updated'|'item.completed', item:{ id, type, ... } }
688
+ * { type:'error', message } 重试等非终止信息(真失败走 turn.failed)
689
+ *
690
+ * item.type(snake_case)分派:
691
+ * agent_message 正文 → output(按 item.id 做累积/增量去重,两种推送语义都兼容)
692
+ * reasoning 思考 → thinking
693
+ * command_execution 命令 → 工具调用(command 作参数摘要,aggregated_output 作结果)
694
+ * file_change 改动文件清单 → 工具调用
695
+ * mcp_tool_call MCP 工具 → 工具调用(server.tool 作名字)
696
+ * web_search 搜索 → 工具调用
697
+ * error 非致命告警(配置项被忽略 / 模型元信息缺失等)→ 贴进 output,不判失败
698
+ * 其余(todo_list / collab_tool_call / 未来新增)忽略 —— 事件枚举是 non_exhaustive,
699
+ * 未知类型不能影响正文收集与终态判定。
700
+ * (导出仅为回归测试可见:taskRunner.codex.test.js)
701
+ */
702
+ export function createCodexEventHandler(job, appendOutput, appendThinking, toolCalls) {
703
+ const tracker = toolCalls || createToolCallTracker(job);
704
+ const seenTextItems = new Map(); // item.id -> 已落地的累计文本
705
+
706
+ const appendItemText = (item, isThinking) => {
707
+ const text = typeof item?.text === 'string' ? item.text : '';
708
+ if (!text) return;
709
+ const id = typeof item?.id === 'string' ? item.id : '';
710
+ const prev = id ? seenTextItems.get(id) : undefined;
711
+ let delta = text;
712
+ if (prev !== undefined) {
713
+ delta = text.startsWith(prev) ? text.slice(prev.length) : text;
714
+ }
715
+ if (!delta) return;
716
+ if (id) seenTextItems.set(id, prev !== undefined ? prev + delta : text);
717
+ if (isThinking) appendThinking(delta);
718
+ else appendOutput(delta);
719
+ };
720
+
721
+ // codex 的 status: in_progress | completed | failed | declined(snake_case)
722
+ const mapItemStatus = (raw) => {
723
+ const s = typeof raw === 'string' ? raw.toLowerCase() : '';
724
+ if (s === 'completed') return 'done';
725
+ if (s === 'failed' || s === 'declined') return 'error';
726
+ return 'running';
727
+ };
728
+
729
+ const changesText = (changes) => (Array.isArray(changes) ? changes : [])
730
+ .map(c => (c && c.path ? `${c.kind || 'update'} ${c.path}` : ''))
731
+ .filter(Boolean)
732
+ .join('\n');
733
+
734
+ const handleItem = (item) => {
735
+ if (!item || typeof item !== 'object') return;
736
+ switch (item.type) {
737
+ case 'agent_message':
738
+ appendItemText(item, false);
739
+ return;
740
+ case 'reasoning':
741
+ appendItemText(item, true);
742
+ return;
743
+ case 'error':
744
+ // 非致命告警:原样贴出来让用户看得见,但不置 agentError —— 那会把告警变成任务失败
745
+ if (item.message) appendOutput(`\n> [codex] ${item.message}\n`);
746
+ return;
747
+ case 'command_execution': {
748
+ const status = mapItemStatus(item.status);
749
+ tracker.record({
750
+ id: item.id,
751
+ name: 'command_execution',
752
+ input: { command: item.command },
753
+ status,
754
+ output: status === 'running' ? undefined : item.aggregated_output,
755
+ error: status === 'error' ? `命令未成功完成(exit_code=${item.exit_code ?? 'null'})` : ''
756
+ });
757
+ return;
758
+ }
759
+ case 'file_change': {
760
+ const status = mapItemStatus(item.status);
761
+ tracker.record({
762
+ id: item.id,
763
+ name: 'file_change',
764
+ input: { changes: item.changes },
765
+ status,
766
+ output: status === 'running' ? undefined : changesText(item.changes),
767
+ error: status === 'error' ? '文件改动未应用' : ''
768
+ });
769
+ return;
770
+ }
771
+ case 'mcp_tool_call': {
772
+ const status = mapItemStatus(item.status);
773
+ tracker.record({
774
+ id: item.id,
775
+ name: item.server && item.tool ? `${item.server}.${item.tool}` : (item.tool || 'mcp_tool_call'),
776
+ input: item.arguments,
777
+ // result.content 是 MCP 的内容块数组(与 claude 的 tool_result 同形态),
778
+ // 直接喂给 extractToolText 能压成文本;没有 content 时整包 JSON 兜底
779
+ status,
780
+ output: status === 'running' ? undefined : (item.result?.content ?? item.result),
781
+ error: item.error?.message || (status === 'error' ? 'MCP 工具调用失败' : '')
782
+ });
783
+ return;
784
+ }
785
+ case 'web_search': {
786
+ const status = mapItemStatus(item.status);
787
+ tracker.record({
788
+ id: item.id,
789
+ name: 'web_search',
790
+ input: { query: item.query },
791
+ status,
792
+ output: status === 'running' ? undefined : item.results
793
+ });
794
+ return;
795
+ }
796
+ default:
797
+ return;
798
+ }
799
+ };
800
+
801
+ return (evt) => {
802
+ if (!evt || typeof evt !== 'object') return;
803
+ // thread_id 是 codex 的会话续接标识(exec resume <id>)。复用 claudeSessionId 字段:
804
+ // 前端与续接路由都认它,换执行器只是取值来源不同。
805
+ if (evt.type === 'thread.started') {
806
+ if (typeof evt.thread_id === 'string' && evt.thread_id && job.claudeSessionId !== evt.thread_id) {
807
+ job.claudeSessionId = evt.thread_id;
808
+ publish('job:update', job);
809
+ }
810
+ return;
811
+ }
812
+ if (evt.type === 'item.started' || evt.type === 'item.updated' || evt.type === 'item.completed') {
813
+ handleItem(evt.item);
814
+ return;
815
+ }
816
+ if (evt.type === 'turn.failed') {
817
+ const msg = evt.error?.message
818
+ || (evt.error?.additional_details ? String(evt.error.additional_details) : '')
819
+ || 'codex 执行出错';
820
+ if (!job.agentError) job.agentError = msg;
821
+ return;
822
+ }
823
+ if (evt.type === 'error') {
824
+ // 非终止信息(如 "Reconnecting... 1/5" 重试提示):贴进 output,终态仍由 turn.* 决定
825
+ if (evt.message) appendOutput(`\n> [codex] ${evt.message}\n`);
826
+ }
827
+ };
828
+ }
829
+
588
830
  /**
589
831
  * 执行一次任务。任务一次只跑一个进程,本函数是唯一的执行入口
590
832
  * (首次执行、手动重跑、续聊都走它)。
@@ -595,10 +837,11 @@ export function createOpencodeEventHandler(job, appendOutput, appendThinking, to
595
837
  * @param {string} branch 分支名(可空)
596
838
  * @param {object} [options]
597
839
  * @param {string|null} [options.resumeSessionId]
598
- * 续接历史会话:claude 走 --resume <id>,opencode 走 --session <id>。
599
- * id 来自上一轮 stream 事件捕获的会话标识(两者都记在 job.claudeSessionId)。
840
+ * 续接历史会话:claude 走 --resume <id>,opencode 走 --session <id>,
841
+ * codex 走 exec resume <thread_id>。
842
+ * id 来自上一轮 stream 事件捕获的会话标识(三者都记在 job.claudeSessionId)。
600
843
  * @param {string} [options.executor]
601
- * 执行器 'claude' | 'opencode'。缺省回落 'claude';路由层负责把
844
+ * 执行器 'claude' | 'opencode' | 'codex'。缺省回落 'claude';路由层负责把
602
845
  * "body 指定 > 配置默认"先解析好再传进来。
603
846
  * @returns {Promise<'done'|'cancelled'|'error'>} 本次运行的终态
604
847
  */
@@ -677,7 +920,11 @@ export async function runSingleSubtask(task, sub, repoPath, branch, options) {
677
920
  let toolTracker = null;
678
921
 
679
922
  try {
680
- const launcher = executor === 'opencode' ? launchOpencodeRun : launchClaudeInNewWindow;
923
+ const launcher = executor === 'opencode'
924
+ ? launchOpencodeRun
925
+ : executor === 'codex'
926
+ ? launchCodexExec
927
+ : launchClaudeInNewWindow;
681
928
  const { pid, child } = await launcher(repoPath || process.cwd(), prompt, resumeSessionId);
682
929
  job.pid = pid;
683
930
  // 保存 child 引用,供 cancel 接口调用 kill
@@ -729,7 +976,9 @@ export async function runSingleSubtask(task, sub, repoPath, branch, options) {
729
976
 
730
977
  const handleEvent = executor === 'opencode'
731
978
  ? createOpencodeEventHandler(job, appendOutput, appendThinking, toolTracker)
732
- : createClaudeEventHandler(job, appendOutput, appendThinking, toolTracker);
979
+ : executor === 'codex'
980
+ ? createCodexEventHandler(job, appendOutput, appendThinking, toolTracker)
981
+ : createClaudeEventHandler(job, appendOutput, appendThinking, toolTracker);
733
982
 
734
983
  const handleLine = (line, channel) => {
735
984
  const trimmed = line.trim();
@@ -54,12 +54,14 @@ function makeSink() {
54
54
  }
55
55
 
56
56
  test('normalizeTaskExecutor:白名单 + 大小写 + 非法回落', () => {
57
- assert.deepEqual(TASK_EXECUTORS, ['claude', 'opencode']);
57
+ assert.deepEqual(TASK_EXECUTORS, ['claude', 'opencode', 'codex']);
58
58
  assert.equal(normalizeTaskExecutor('opencode'), 'opencode');
59
+ assert.equal(normalizeTaskExecutor('codex'), 'codex');
59
60
  // 大小写不敏感(存储前统一小写)
60
61
  assert.equal(normalizeTaskExecutor('OpenCode'), 'opencode');
61
62
  assert.equal(normalizeTaskExecutor('opencode '), 'opencode');
62
- assert.equal(normalizeTaskExecutor('codex'), 'claude');
63
+ assert.equal(normalizeTaskExecutor('Codex '), 'codex');
64
+ assert.equal(normalizeTaskExecutor('gpt'), 'claude');
63
65
  assert.equal(normalizeTaskExecutor(undefined), 'claude');
64
66
  assert.equal(normalizeTaskExecutor(null), 'claude');
65
67
  });
@@ -1,5 +0,0 @@
1
- import"./rolldown-runtime-C0FnF6B9.js";import{$ as e,$r as t,A as n,Dn as r,E as i,En as a,Fn as o,H as s,Jt as c,K as l,Mn as u,Nn as d,On as f,Ot as p,Pr as m,Q as h,Qn as g,Rt as _,Tn as v,Un as y,Vt as b,Wt as x,Xn as S,Yr as C,_r as w,a as T,ar as E,bn as D,cn as O,cr as k,ct as ee,et as te,fr as A,gn as j,i as M,in as ne,j as N,kt as P,mt as F,ot as re,pt as I,qr as L,r as R,sr as z,tr as ie,un as B,wn as V,wt as ae,yn as H,yr as U,zn as W}from"./element-plus-DxBPQwL7.js";import{i as oe,n as G,t as K}from"./vendor-IQQMq-1c.js";import{n as q,t as J}from"./_plugin-vue_export-helper-B1mHBne9.js";import{t as Y}from"./configStore-BDxel6Co.js";W(),A();var X=65536,Z=`local-`;function Q(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:ce(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 i=`msg-${r}`,a=``,o=[],s=r;for(;s<n;){let t=e.messages[s];if(t.role!==`assistant`&&t.role!==`tool`)break;if(t.role===`assistant`){if(typeof t.content==`string`&&(a+=t.content),t.tool_calls&&t.tool_calls.length>0)for(let e of t.tool_calls)o.push({id:e.id||e.function?.name||K(),name:e.function?.name||``,arguments:e.function?.arguments||``,argsPreview:se(e.function?.name||``,e.function?.arguments||``),status:`done`,result:``})}else{let e=t.tool_call_id||t.name||``,n=o.find(t=>t.id===e);if(n){let e=t.content;typeof e!=`string`&&(e=`(non-text result)`),e.length>X&&(e=`…(前文已截断)\n${e.slice(-65536)}`),n.result=e}}s++}r=s-1,a.length>X&&(a=`…(前文已截断)\n${a.slice(-65536)}`);let c=!!a,l=o.length>0;(c||l)&&t.push({id:i,role:`assistant`,content:a,toolCalls:l?o:void 0,status:`done`,createdAt:Date.now()})}}}return t}function se(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 $(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 ce(e){let t=/^data:([^;,]+)/.exec(e);return t?t[1]:``}function le(){let e=Y(),t=U([]),n=U(!1),r=w(new Map),i=U(null),a=U(!1),o=0,s=0;function c(e){return{key:e,sessionId:e.startsWith(Z)?null:e,title:``,messages:[],isStreaming:!1,abortController:null,nonce:0,pendingQuestion:null,answeringQuestion:!1}}function l(e){let t=r.get(e);return t||=(r.set(e,c(e)),r.get(e)),t}let u=V(()=>i.value?r.get(i.value)??null:null),d=V(()=>u.value?.messages??[]),f=V(()=>u.value?.isStreaming??!1),p=V(()=>u.value?.pendingQuestion??null),m=V(()=>u.value?.answeringQuestion??!1);function h(e){return!!r.get(e)?.isStreaming}function g(t){let n=[...t];for(let t of r.values()){if(!t.isStreaming||!t.sessionId)continue;let r=n.findIndex(e=>e.sessionId===t.sessionId);if(r===-1){let r=new Date().toISOString();n.unshift({sessionId:t.sessionId,title:t.title||q(`@AGENT:无标题`),source:`web`,cwd:e.currentDirectory||``,model:``,createdAt:r,updatedAt:r,messageCount:t.messages.filter(e=>e.role===`user`).length||1,size:0,isGenerating:!0})}else n[r]={...n[r],isGenerating:!0}}return n}async function _(){let r=++o,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!==o)return;if(!n.success){M.error(n.error||q(`@AGENT:加载会话列表失败`));return}let a=Array.isArray(n.sessions)?n.sessions:[];t.value=g(a)}catch(e){if(r!==o)return;M.error(q(`@AGENT:加载会话列表失败`)+`: `+(e?.message||e))}finally{r===o&&(n.value=!1)}}function v(n,r){let i=new Date().toISOString(),a=t.value.find(e=>e.sessionId===n);if(a){a.isGenerating=!0,a.updatedAt=i;return}t.value=[{sessionId:n,title:r||q(`@AGENT:无标题`),source:`web`,cwd:e.currentDirectory||``,model:``,createdAt:i,updatedAt:i,messageCount:1,size:0,isGenerating:!0},...t.value]}function y(e){let n=t.value.find(t=>t.sessionId===e);n&&(n.isGenerating=!1)}async function b(e){if(r.get(e)?.isStreaming){i.value=e;return}a.value=!0,i.value=e;try{let t=await fetch(`/api/agent/sessions/${encodeURIComponent(e)}`).then(e=>e.json());if(!t.success){M.error(t.error||q(`@AGENT:加载会话失败`));return}let n=l(e);n.sessionId=e,n.messages=Q(t.session),t.session?.title&&(n.title=t.session.title)}catch(e){M.error(q(`@AGENT:加载会话失败`)+`: `+(e?.message||e))}finally{a.value=!1}}async function x(e){try{await R.confirm(q(`@AGENT:确认删除该会话`),q(`@AGENT:删除后无法恢复`),{type:`warning`})}catch{return}let n=r.get(e);if(n?.abortController)try{n.abortController.abort()}catch{}r.delete(e);try{let n=await fetch(`/api/agent/sessions/${encodeURIComponent(e)}`,{method:`DELETE`}).then(e=>e.json());if(!n.success){M.error(n.error||q(`@AGENT:删除失败`));return}t.value=t.value.filter(t=>t.sessionId!==e),i.value===e&&(i.value=null),M.success(q(`@AGENT:已删除`))}catch(e){M.error(q(`@AGENT:删除失败`)+`: `+(e?.message||e))}}async function S(e,n){try{let i=await fetch(`/api/agent/sessions/${encodeURIComponent(e)}`,{method:`PUT`,headers:{"Content-Type":`application/json`},body:JSON.stringify({title:n})}).then(e=>e.json());if(!i.success){M.error(i.error||q(`@AGENT:重命名失败`));return}let a=t.value.find(t=>t.sessionId===e);a&&(a.title=n);let o=r.get(e);o&&(o.title=n),M.success(q(`@AGENT:已重命名`))}catch(e){M.error(q(`@AGENT:重命名失败`)+`: `+(e?.message||e))}}function C(){i.value=null}async function T(t,n=[]){let a=n.filter(e=>e?.file?.type?.startsWith(`image/`));a.length<n.length&&M.warning(q(`@AGENT:仅支持发送图片,非图片文件已忽略`));let o=l(i.value||`${Z}${Date.now()}-${++s}`);if(!t.trim()&&a.length===0||o.isStreaming)return;let c=(await Promise.allSettled(a.map(e=>$(e.file)))).map(e=>e.status===`fulfilled`?e.value:``).filter(e=>e.startsWith(`data:image/`));i.value=o.key,o.nonce+=1;let u=o.nonce;o.abortController=new AbortController;let d=o.abortController;o.pendingQuestion=null,o.answeringQuestion=!1;let f={id:K(),role:`user`,content:t,status:`done`,createdAt:Date.now()};a.length>0&&(f.attachments=a.map(e=>({id:e.id,name:e.file.name||`image`,size:e.file.size||0,type:e.file.type||``,preview:e.preview}))),o.messages.push(f);let p=w({id:K(),role:`assistant`,content:``,status:`pending`,createdAt:Date.now()});o.messages.push(p),o.isStreaming=!0;let m=[],h=o.sessionId;try{let n=await fetch(`/api/agent/chat`,{method:`POST`,headers:{"Content-Type":`application/json`,Accept:`text/event-stream`},body:JSON.stringify({sessionId:o.sessionId||``,userMessage:t,cwd:e.currentDirectory||``,...c.length>0?{images:c}:{}}),signal:d.signal});if(u!==o.nonce)return;if(!n.ok||!n.body){let e=await n.text().catch(()=>``);throw Error(e||`HTTP ${n.status}`)}let a=n.body.getReader(),s=new TextDecoder(`utf-8`),l=``;for(;;){let{value:e,done:n}=await a.read();if(u!==o.nonce)return;if(n)break;l+=s.decode(e,{stream:!0});let c=l.split(`
2
- `);l=c.pop()??``;for(let e of c){let n=e.trim();if(!n.startsWith(`data:`))continue;let a=n.slice(5).trim();if(!a)continue;let s;try{s=JSON.parse(a)}catch{continue}switch(s.type){case`meta`:if(s.sessionId){let e=String(s.sessionId);if(h=e,o.sessionId!==e){let t=o.key;o.sessionId=e,o.key=e,t!==e&&(r.delete(t),r.set(e,o),i.value===t&&(i.value=e))}let n=String(s.title||``).trim()||t.trim().split(`
3
- `)[0].trim().slice(0,40)||q(`@AGENT:无标题`);o.title||=n,v(e,n)}break;case`thinking`:p.reasoning||(p.reasoning=``,p.reasoningStatus=`streaming`),p.reasoning+=String(s.delta||``),p.status=`streaming`;break;case`content`:p.status===`pending`&&(p.status=`streaming`);{let e=String(s.delta||``);p.content+=e;let t=G(p.content);t.reasoning&&(p.reasoning||(p.reasoning=``,p.reasoningStatus=`streaming`),p.reasoning=t.reasoning,p.content=t.content)}break;case`tool_call_start`:{let e=w({id:s.toolCallId||K(),name:s.name||``,argsPreview:s.argsPreview||``,arguments:s.argsPreview||``,status:`running`,result:``});m.push(e),p.toolCalls||=[],p.toolCalls.push(e),p.status===`pending`&&(p.status=`streaming`);break}case`tool_output`:{let e=m.find(e=>e.id===s.toolCallId);if(e){let t=`${e.result||``}${String(s.chunk||``)}`;e.result=t.length>X?`…(前文已截断)\n${t.slice(-65536)}`:t}break}case`tool_result`:{let e=m.find(e=>e.id===s.toolCallId);e&&(e.result=String(s.result||``),e.status=`done`,e.name===`ask_user`&&(o.pendingQuestion=null));break}case`ask_user`:o.pendingQuestion={interactionId:String(s.interactionId||``),question:String(s.question||``),options:Array.isArray(s.options)?s.options.map(e=>String(e)):[],allowFreeText:s.allowFreeText!==!1};break;case`done`:{let e=s.content||p.content,t=G(e);t.reasoning&&!p.reasoning&&(p.reasoning=t.reasoning),p.content=t.content,p.status=`done`,p.reasoningStatus===`streaming`&&(p.reasoningStatus=`done`);break}case`error`:p.status=`error`,p.error=String(s.error||q(`@AGENT:未知错误`)),p.reasoningStatus===`streaming`&&(p.reasoningStatus=`done`)}}}if(u!==o.nonce)return;p.status===`pending`&&(p.status=`done`)}catch(e){if(u!==o.nonce)return;e?.name===`AbortError`||d.signal.aborted?(p.content=(p.content||``)+`
4
-
5
- [`+q(`@AGENT:已停止`)+`]`,p.status=`done`,p.reasoningStatus===`streaming`&&(p.reasoningStatus=`done`)):(p.status=`error`,p.error=e?.message||String(e),M.error(p.error||q(`@AGENT:对话失败`)))}finally{u===o.nonce&&(o.isStreaming=!1,o.pendingQuestion=null,o.answeringQuestion=!1,o.abortController=null),h&&y(h),_().catch(()=>{})}}async function E(e){let t=u.value,n=t?.pendingQuestion,r=t?.sessionId,i=String(e||``).trim();if(!t||!n||!r||!i||t.answeringQuestion)return!1;t.answeringQuestion=!0;try{let e=await fetch(`/api/agent/respond`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({sessionId:r,interactionId:n.interactionId,answer:i})}).then(e=>e.json());if(!e.success)throw Error(e.error||q(`@AGENT:回答提交失败`));return t.pendingQuestion=null,!0}catch(e){return M.error(e?.message||q(`@AGENT:回答提交失败`)),!1}finally{t.answeringQuestion=!1}}function D(){let e=u.value;e?.abortController&&(e.abortController.abort(),e.abortController=null)}return{sessions:t,sessionsLoading:n,currentSessionId:i,messages:d,isStreaming:f,sessionLoading:a,pendingQuestion:p,answeringQuestion:m,isSessionGenerating:h,loadSessions:_,loadSession:b,deleteSession:x,renameSession:S,newSession:C,sendMessage:T,answerQuestion:E,stop:D}}W(),A();var ue=o({__name:`MarketplacePanel`,props:{type:{type:String,required:!0}},setup(e,{expose:t}){t();let n=e,r=Y(),i=U([]),a=U([]),o=U(!1),s=U(``),l=U(``),u=U([]),d=U(`project`),f=U(new Set),m=U(new Set),h=V(()=>r.currentDirectory||``),g=null;async function _(){if(!o.value){o.value=!0;try{let e=new URLSearchParams({type:n.type,cwd:h.value});l.value&&e.set(`q`,l.value),u.value.length&&e.set(`sources`,u.value.join(`,`));let t=await(await fetch(`/api/agent/marketplace/catalog?${e}`)).json();t?.success?(i.value=t.groups||[],a.value=t.installed||[]):M.error(t?.error||q(`@MKT:加载失败`))}catch{M.error(q(`@MKT:加载失败`))}finally{o.value=!1}}}E(s,e=>{g&&clearTimeout(g),g=setTimeout(()=>{l.value=e.trim(),_()},400)}),E(u,()=>_()),E(()=>n.type,()=>{u.value=[],l.value=``,s.value=``,_()}),E(h,()=>_()),_();let v=V(()=>{let e=h.value?h.value.split(/[\\/]/).filter(Boolean).pop():``;return d.value===`project`?e||q(`@MKT:当前项目`):q(`@MKT:g ai 智能体`)});function y(e){return e.stars?`${S(e.stars)} ★`:e.downloads?`${S(e.downloads)} ${q(`@MKT:周下载`)}`:e.uses?`${S(e.uses)} ${q(`@MKT:次使用`)}`:``}function S(e){return e>=1e3?`${(e/1e3).toFixed(e>=1e4?0:1)}k`:String(e)}function C(e){return`${e.id}`}function T(e){return f.value.has(C(e))}let D=V(()=>{let e={project:[],global:[]};for(let t of a.value)(e[t.target]||=[]).push(t);return e}),O=w({visible:!1,item:null,env:{},args:``});function k(e){return n.type===`mcp`&&(!!e.envKeys?.length||!!e.args?.length)}function A(e){O.item=e,O.env=Object.fromEntries((e.envKeys||[]).map(e=>[e,``])),O.args=(e.args||[]).join(` `),O.visible=!0}function j(){let e=O.item;if(O.visible=!1,!e)return;let t=Object.fromEntries(Object.entries(O.env).filter(([,e])=>e.trim()!==``)),n=O.args.trim()?O.args.trim().match(/(?:[^\s"]+|"[^"]*")+/g)?.map(e=>e.replace(/^"|"$/g,``))??void 0:void 0;P(e,{env:t,...n?{args:n}:{}})}async function N(e){if(!e.installed||await F(e)){if(k(e)){A(e);return}await P(e,{})}}async function P(e,t){let r=C(e);f.value.add(r);try{let r=await fetch(`/api/agent/marketplace/install`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({type:n.type,target:d.value,cwd:h.value,item:{...e,...t}})}),i=await r.json().catch(()=>null);if(!r.ok||!i?.success){M.error(i?.error||q(`@MKT:安装失败`));return}i.item?.warning&&M.warning(i.item.warning),i.item?.envKeys?.length?M.warning(`${q(`@MKT:还缺环境变量`)}: ${i.item.envKeys.join(`, `)}`):M.success(q(`@MKT:安装成功`)),await _()}catch{M.error(q(`@MKT:安装失败`))}finally{f.value.delete(r)}}async function F(e){try{return await R.confirm(`${e.name} ${q(`@MKT:已安装,要重新安装吗?`)}`,q(`@MKT:重新安装`),{confirmButtonText:q(`@MKT:重装`),cancelButtonText:q(`@MKT:取消`),type:`warning`}),!0}catch{return!1}}async function re(e){try{await R.confirm(`${q(`@MKT:确定卸载`)} ${e.name}?`,q(`@MKT:卸载`),{confirmButtonText:q(`@MKT:卸载`),cancelButtonText:q(`@MKT:取消`),type:`warning`})}catch{return}let t=`${e.target}:${e.id}`;m.value.add(t);try{let t=new URLSearchParams({target:e.target,cwd:h.value}),r=await fetch(`/api/agent/marketplace/item/${n.type}/${encodeURIComponent(e.id)}?${t}`,{method:`DELETE`}),i=await r.json().catch(()=>null);if(!r.ok||!i?.success){M.error(i?.error||q(`@MKT:卸载失败`));return}M.success(q(`@MKT:已卸载`)),await _()}catch{M.error(q(`@MKT:卸载失败`))}finally{m.value.delete(t)}}let L={props:n,configStore:r,groups:i,installed:a,loading:o,searchInput:s,query:l,selectedSources:u,installTarget:d,installing:f,removing:m,cwd:h,get searchTimer(){return g},set searchTimer(e){g=e},loadCatalog:_,targetLabel:v,metricText:y,formatCount:S,cardKey:C,isBusy:T,installedByTarget:D,configDialog:O,needsConfig:k,openConfigDialog:A,confirmConfig:j,onInstall:N,doInstall:P,confirmReinstall:F,onRemove:re,get $t(){return q},get Search(){return x},get Refresh(){return b},get Delete(){return ee},get Link(){return p},get Check(){return te},get Star(){return c},get Download(){return I},get Warning(){return ne}};return Object.defineProperty(L,"__isScriptSetup",{enumerable:!1,value:!0}),L}});W(),B(),m();var de={class:`marketplace-panel`},fe={class:`mp-toolbar`},pe={class:`mp-search`},me=[`placeholder`],he={class:`mp-toolbar-sub`},ge={class:`mp-target-hint`},_e={class:`mp-source-filter`},ve=[`onClick`],ye={class:`mp-body`},be={class:`mp-group-header`},xe={class:`mp-group-title`},Se={key:0,class:`mp-group-count`},Ce={key:1,class:`mp-group-error`},we=[`href`,`title`],Te={key:0,class:`mp-grid`},Ee={class:`mp-card-head`},De=[`title`],Oe={key:0,class:`mp-card-metric`},ke=[`title`],Ae={class:`mp-card-meta`},je=[`title`],Me=[`title`],Ne={key:2,class:`mp-tag remote`},Pe={class:`mp-card-foot`},Fe=[`href`],Ie={key:1,class:`mp-installed-chip`},Le=[`disabled`,`onClick`],Re={key:3,class:`mp-not-installable`},ze={key:1,class:`mp-empty`},Be={key:0,class:`mp-group installed`},Ve={class:`mp-group-header`},He={class:`mp-group-title`},Ue={class:`mp-group-count`},We={key:0,class:`mp-installed-block`},Ge={class:`mp-installed-target`},Ke={class:`mp-installed-list`},qe={class:`mp-installed-name`},Je={key:0,class:`mp-meta-pkg`},Ye={key:1,class:`mp-tag warn`},Xe=[`disabled`,`onClick`],Ze={key:1,class:`mp-empty all`},Qe={key:0,class:`mkt-form`},$e={class:`mkt-form-name`},et=[`onUpdate:modelValue`,`placeholder`],tt={key:0,class:`mkt-field`},nt={class:`mkt-hint`};function rt(e,o,c,p,m,h){let _=l,y=n,b=N,x=s,C=i,w=T;return S(),f(`div`,de,[r(` ── 工具栏 ───────────────────────────────── `),v(`div`,fe,[v(`div`,pe,[d(_,{class:`mp-search-icon`},{default:z(()=>[d(p.Search)]),_:1}),k(v(`input`,{"onUpdate:modelValue":o[0]||=e=>p.searchInput=e,class:`mp-search-input`,type:`text`,placeholder:c.type===`skill`?p.$t(`@MKT:搜索 Skill...`):p.$t(`@MKT:搜索 MCP 服务...`)},null,8,me),[[j,p.searchInput]])]),d(b,{modelValue:p.installTarget,"onUpdate:modelValue":o[1]||=e=>p.installTarget=e,size:`small`,class:`mp-target`},{default:z(()=>[d(y,{value:`project`},{default:z(()=>[u(t(p.$t(`@MKT:当前项目`)),1)]),_:1}),d(y,{value:`global`},{default:z(()=>[u(t(p.$t(`@MKT:g ai 智能体`)),1)]),_:1})]),_:1},8,[`modelValue`]),d(x,{content:p.$t(`@MKT:刷新`),placement:`top`,"show-after":300},{default:z(()=>[v(`button`,{class:L([`mp-refresh`,{spinning:p.loading}]),onClick:p.loadCatalog},[d(_,null,{default:z(()=>[d(p.Refresh)]),_:1})],2)]),_:1},8,[`content`])]),v(`div`,he,[v(`span`,ge,[u(t(p.$t(`@MKT:安装到`))+` `,1),v(`b`,null,t(p.targetLabel),1)]),v(`div`,_e,[(S(!0),f(D,null,g(p.groups,e=>(S(),f(`button`,{key:e.id,class:L([`mp-chip`,{active:p.selectedSources.includes(e.id)}]),onClick:()=>{let t=p.selectedSources.indexOf(e.id);t>=0?p.selectedSources.splice(t,1):p.selectedSources.push(e.id)}},t(e.label),11,ve))),128)),p.selectedSources.length?(S(),f(`button`,{key:0,class:`mp-chip clear`,onClick:o[2]||=e=>p.selectedSources=[]},t(p.$t(`@MKT:全部来源`)),1)):r(`v-if`,!0)])]),r(` ── 内容 ─────────────────────────────────── `),k((S(),f(`div`,ye,[(S(!0),f(D,null,g(p.groups,e=>(S(),f(`section`,{key:e.id,class:`mp-group`},[v(`header`,be,[v(`h3`,xe,t(e.label),1),e.status===`ok`?(S(),f(`span`,Se,t(e.items.length),1)):(S(),f(`span`,Ce,[d(_,null,{default:z(()=>[d(p.Warning)]),_:1}),u(` `+t(e.error||p.$t(`@MKT:来源不可用`)),1)])),e.homepage?(S(),f(`a`,{key:2,class:`mp-group-link`,href:e.homepage,target:`_blank`,rel:`noopener noreferrer`,title:e.homepage},[d(_,null,{default:z(()=>[d(p.Link)]),_:1})],8,we)):r(`v-if`,!0)]),e.status===`ok`&&e.items.length?(S(),f(`div`,Te,[(S(!0),f(D,null,g(e.items,e=>(S(),f(`article`,{key:p.cardKey(e),class:`mp-card`},[v(`div`,Ee,[v(`span`,{class:`mp-card-name`,title:e.name},t(e.name),9,De),p.metricText(e)?(S(),f(`span`,Oe,[d(_,null,{default:z(()=>[e.stars?(S(),a(p.Star,{key:0})):(S(),a(p.Download,{key:1}))]),_:2},1024),u(` `+t(p.metricText(e)),1)])):r(`v-if`,!0)]),v(`p`,{class:`mp-card-desc`,title:e.description},t(e.description||p.$t(`@MKT:暂无描述`)),9,ke),v(`div`,Ae,[e.package?(S(),f(`code`,{key:0,class:`mp-meta-pkg`,title:e.package},t(e.package),9,je)):e.repository?(S(),f(`span`,{key:1,class:`mp-meta-repo`,title:e.repository+(e.subpath?` · `+e.subpath:``)},[u(t(e.repository),1),e.subpath?(S(),f(D,{key:0},[u(` · `+t(e.subpath),1)],64)):r(`v-if`,!0)],8,Me)):r(`v-if`,!0),e.transport===`remote`?(S(),f(`span`,Ne,t(p.$t(`@MKT:远程服务`)),1)):r(`v-if`,!0),(S(!0),f(D,null,g((e.tags||[]).slice(0,2),e=>(S(),f(`span`,{key:e,class:`mp-tag`},t(e),1))),128))]),v(`div`,Pe,[e.upstream?(S(),f(`a`,{key:0,class:`mp-card-link`,href:e.upstream,target:`_blank`,rel:`noopener noreferrer`},t(p.$t(`@MKT:查看来源`)),9,Fe)):r(`v-if`,!0),o[6]||=v(`span`,{class:`mp-foot-spacer`},null,-1),e.installed?(S(),f(`span`,Ie,[d(_,null,{default:z(()=>[d(p.Check)]),_:1}),u(t(p.$t(`@MKT:已安装`)),1)])):e.installable===!1?(S(),f(`span`,Re,t(p.$t(`@MKT:暂不支持一键安装`)),1)):(S(),f(`button`,{key:2,class:`mp-install-btn`,disabled:p.isBusy(e),onClick:t=>p.onInstall(e)},t(p.isBusy(e)?p.$t(`@MKT:安装中...`):p.$t(`@MKT:安装`)),9,Le))])]))),128))])):e.status===`ok`?(S(),f(`div`,ze,t(p.$t(`@MKT:该来源暂无结果`)),1)):r(`v-if`,!0)]))),128)),r(` ── 已安装 ─────────────────────────────── `),p.installed.length?(S(),f(`section`,Be,[v(`header`,Ve,[v(`h3`,He,t(p.$t(`@MKT:已安装`)),1),v(`span`,Ue,t(p.installed.length),1)]),(S(),f(D,null,g([`project`,`global`],e=>v(`div`,{key:e},[p.installedByTarget[e]?.length?(S(),f(`div`,We,[v(`div`,Ge,t(e===`project`?p.$t(`@MKT:当前项目`):p.$t(`@MKT:g ai 智能体`)),1),v(`div`,Ke,[(S(!0),f(D,null,g(p.installedByTarget[e],n=>(S(),f(`div`,{key:e+n.id,class:`mp-installed-row`},[v(`span`,qe,t(n.name),1),n.package?(S(),f(`code`,Je,t(n.package),1)):r(`v-if`,!0),n.requiredEnv?.length?(S(),f(`span`,Ye,t(p.$t(`@MKT:待配置`))+`: `+t(n.requiredEnv.join(`, `)),1)):r(`v-if`,!0),o[7]||=v(`span`,{class:`mp-foot-spacer`},null,-1),v(`button`,{class:`mp-remove-btn`,disabled:p.removing.has(e+n.id),onClick:e=>p.onRemove(n)},[d(_,null,{default:z(()=>[d(p.Delete)]),_:1}),u(` `+t(p.removing.has(e+n.id)?p.$t(`@MKT:卸载中...`):p.$t(`@MKT:卸载`)),1)],8,Xe)]))),128))])])):r(`v-if`,!0)])),64))])):r(`v-if`,!0),!p.loading&&!p.groups.length?(S(),f(`div`,Ze,t(p.$t(`@MKT:加载失败`)),1)):r(`v-if`,!0)])),[[w,p.loading]]),r(` ── MCP 安装前配置 ───────────────────────── `),d(C,{modelValue:p.configDialog.visible,"onUpdate:modelValue":o[5]||=e=>p.configDialog.visible=e,title:p.$t(`@MKT:配置 MCP`),width:`460px`,"close-on-click-modal":!1,"append-to-body":``},{footer:z(()=>[v(`button`,{class:`mkt-cancel`,onClick:o[4]||=e=>p.configDialog.visible=!1},t(p.$t(`@MKT:取消`)),1),v(`button`,{class:`mkt-confirm`,onClick:p.confirmConfig},t(p.$t(`@MKT:安装`)),1)]),default:z(()=>[p.configDialog.item?(S(),f(`div`,Qe,[v(`p`,$e,t(p.configDialog.item.name),1),(S(!0),f(D,null,g(Object.keys(p.configDialog.env),e=>(S(),f(`div`,{key:e,class:`mkt-field`},[v(`label`,null,t(e),1),k(v(`input`,{"onUpdate:modelValue":t=>p.configDialog.env[e]=t,type:`text`,autocomplete:`off`,placeholder:p.$t(`@MKT:环境变量值`),spellcheck:`false`},null,8,et),[[j,p.configDialog.env[e]]])]))),128)),p.configDialog.item.args?.length?(S(),f(`div`,tt,[v(`label`,null,t(p.$t(`@MKT:启动参数`)),1),k(v(`input`,{"onUpdate:modelValue":o[3]||=e=>p.configDialog.args=e,type:`text`,autocomplete:`off`,spellcheck:`false`},null,512),[[j,p.configDialog.args]]),v(`p`,nt,t(p.$t(`@MKT:参数提示`)),1)])):r(`v-if`,!0)])):r(`v-if`,!0)]),_:1},8,[`modelValue`,`title`])])}var it=J(ue,[[`render`,rt],[`__scopeId`,`data-v-e9f9e851`],[`__file`,`D:/workspace/github_workspace/zen-gitsync/src/ui/client/src/components/MarketplacePanel.vue`]]);W(),A();var at=o({__name:`AgentView`,setup(t,{expose:n}){n();let r=Y(),i=U(`chat`),a=V(()=>i.value===`mcp`?`mcp`:`skill`),o=V(()=>[{id:`chat`,label:q(`@AGENT:对话`),icon:h},{id:`skill`,label:q(`@AGENT:Skill 广场`),icon:ae},{id:`mcp`,label:q(`@AGENT:MCP 广场`),icon:re}]),{sessions:c,sessionsLoading:u,currentSessionId:d,messages:f,isStreaming:p,sessionLoading:m,loadSessions:g,loadSession:v,deleteSession:b,renameSession:S,newSession:C,sendMessage:w,pendingQuestion:T,answeringQuestion:D,answerQuestion:O,isSessionGenerating:k,stop:A}=le(),j=V(()=>{let e=r.theme;return e===`dark`||e===`auto`&&window.matchMedia(`(prefers-color-scheme: dark)`).matches?`dark`:`light`}),M=U(``),ne=V(()=>{if(!M.value.trim())return c.value;let e=M.value.toLowerCase();return c.value.filter(t=>(t.title||``).toLowerCase().includes(e)||(t.model||``).toLowerCase().includes(e))}),N=V(()=>[{id:`p1`,label:q(`@AGENT:查看项目结构`),prompt:q(`@AGENT:prompt_p1`)},{id:`p2`,label:q(`@AGENT:分析代码质量`),prompt:q(`@AGENT:prompt_p2`)},{id:`p3`,label:q(`@AGENT:帮我写测试`),prompt:q(`@AGENT:prompt_p3`)},{id:`p4`,label:q(`@AGENT:Git 状态检查`),prompt:q(`@AGENT:prompt_p4`)},{id:`p5`,label:q(`@AGENT:帮我启动项目`),prompt:q(`@AGENT:prompt_p5`)}]);async function I(e){await w(e.text,e.files),await y(),H()}async function L(e){await w(e.prompt),await y(),H()}let z=U(``);async function ie(e=z.value){await O(e)&&(z.value=``)}let B=U(null);function H(e=!0){B.value?.scrollToBottom(e)}E(()=>f.value.length,()=>{y(()=>H(!1))});function W(e){v(e)}function G(){C()}function K(e,t){t.stopPropagation(),b(e)}async function J(e,t,n){n.stopPropagation();try{let{value:n}=await R.prompt(q(`@AGENT:请输入新的会话标题`),q(`@AGENT:重命名会话`),{inputValue:t,inputPattern:/.+/,inputErrorMessage:q(`@AGENT:标题不能为空`)});n&&n!==t&&await S(e,n)}catch{}}function X(e){if(!e)return``;try{let t=new Date(e);if(Number.isNaN(t.getTime()))return e;let n=new Date,r=n.getTime()-t.getTime(),i=e=>String(e).padStart(2,`0`);if(t.toDateString()===n.toDateString())return`${i(t.getHours())}:${i(t.getMinutes())}`;if(r<6048e5){let e=Math.floor(r/864e5);return e===0?q(`@AGENT:今天`):`${e}${q(`@AGENT:天前`)}`}return`${t.getFullYear()}-${i(t.getMonth()+1)}-${i(t.getDate())}`}catch{return e}}let Z=U(280),Q=U(!1);function se(e){Q.value=!0;let t=e.clientX,n=Z.value,r=e=>{let r=e.clientX-t,i=Math.max(200,Math.min(500,n+r));Z.value=i},i=()=>{Q.value=!1,document.removeEventListener(`mousemove`,r),document.removeEventListener(`mouseup`,i)};document.addEventListener(`mousemove`,r),document.addEventListener(`mouseup`,i)}E(()=>[r.currentDirectory,p.value],async([e,t],n)=>{let r=!n||e!==n[0],i=!!n&&n[1]===!0&&!t;(r||i)&&await g(),d.value&&!p.value&&!c.value.some(e=>e.sessionId===d.value)&&C()},{immediate:!0});let $={configStore:r,activeTab:i,marketplaceType:a,tabs:o,sessions:c,sessionsLoading:u,currentSessionId:d,messages:f,isStreaming:p,sessionLoading:m,loadSessions:g,loadSession:v,deleteSession:b,renameSession:S,newSession:C,sendMessage:w,pendingQuestion:T,answeringQuestion:D,answerQuestion:O,isSessionGenerating:k,stop:A,chatTheme:j,searchQuery:M,filteredSessions:ne,presetQuestions:N,onSend:I,onSelectPreset:L,pendingAnswer:z,submitPendingAnswer:ie,chatContainerRef:B,scrollToBottom:H,selectSession:W,handleNewSession:G,handleDelete:K,handleRename:J,formatDate:X,sidebarWidth:Z,isResizing:Q,startResize:se,get $t(){return q},get ElTooltip(){return s},get ElIcon(){return l},get Plus(){return _},get Search(){return x},get Delete(){return ee},get Edit(){return F},get ChatLineRound(){return e},get Loading(){return P},get Check(){return te},get ChatContainer(){return oe},MarketplacePanel:it};return Object.defineProperty($,"__isScriptSetup",{enumerable:!1,value:!0}),$}});W(),m(),B();var ot={class:`agent-view`},st={class:`sidebar-header`},ct={class:`sidebar-search`},lt=[`placeholder`],ut={class:`session-list`},dt={key:0,class:`empty-state`},ft={class:`empty-text`},pt={key:0,class:`empty-hint`},mt=[`onClick`],ht={class:`session-item-main`},gt={class:`session-item-title`},_t={class:`session-item-meta`},vt={key:0,class:`meta-generating`},yt={class:`meta-time`},bt={class:`meta-count`},xt={key:2,class:`meta-source cli`},St=[`onClick`],Ct=[`onClick`],wt={class:`agent-chat-area`},Tt={class:`agent-tabs`,role:`tablist`},Et=[`aria-selected`,`onClick`],Dt={class:`agent-tab-body`},Ot={key:0,class:`agent-chat-pane`},kt={key:0,class:`chat-loading`},At={key:0,class:`ask-user-panel`,"aria-live":`polite`},jt={class:`ask-user-title`},Mt={class:`ask-user-question`},Nt={key:0,class:`ask-user-options`},Pt=[`disabled`,`onClick`],Ft=[`disabled`,`placeholder`,`aria-label`],It=[`disabled`],Lt={key:0,class:`stop-button-bar`};function Rt(e,n,i,o,s,c){let l=T;return S(),f(`div`,ot,[r(` ═══ 左侧:会话列表(只在「对话」Tab 显示)═══ `),o.activeTab===`chat`?(S(),f(D,{key:0},[v(`aside`,{class:`agent-sidebar`,style:C({width:o.sidebarWidth+`px`})},[r(` 顶部操作栏 `),v(`div`,st,[v(`button`,{class:`new-session-btn`,onClick:o.handleNewSession},[d(o.ElIcon,null,{default:z(()=>[d(o.Plus)]),_:1}),v(`span`,null,t(o.$t(`@AGENT:新建会话`)),1)])]),r(` 搜索框 `),v(`div`,ct,[d(o.ElIcon,{class:`search-icon`},{default:z(()=>[d(o.Search)]),_:1}),k(v(`input`,{"onUpdate:modelValue":n[0]||=e=>o.searchQuery=e,placeholder:o.$t(`@AGENT:搜索会话...`),class:`search-input`,type:`text`},null,8,lt),[[j,o.searchQuery]])]),r(` 会话列表 `),k((S(),f(`div`,ut,[o.filteredSessions.length===0&&!o.sessionsLoading?(S(),f(`div`,dt,[d(o.ElIcon,{size:28,color:`var(--text-tertiary)`},{default:z(()=>[d(o.ChatLineRound)]),_:1}),v(`div`,ft,t(o.searchQuery?o.$t(`@AGENT:未找到匹配的会话`):o.$t(`@AGENT:暂无会话`)),1),o.searchQuery?r(`v-if`,!0):(S(),f(`div`,pt,t(o.$t(`@AGENT:点击上方按钮开始对话`)),1))])):r(`v-if`,!0),(S(!0),f(D,null,g(o.filteredSessions,e=>(S(),f(`div`,{key:e.sessionId,class:L([`session-item`,{active:o.currentSessionId===e.sessionId}]),onClick:t=>o.selectSession(e.sessionId)},[v(`div`,ht,[v(`div`,gt,t(e.title||o.$t(`@AGENT:无标题`)),1),v(`div`,_t,[e.isGenerating||o.isSessionGenerating(e.sessionId)?(S(),f(`span`,vt,[d(o.ElIcon,{class:`is-loading`},{default:z(()=>[d(o.Loading)]),_:1}),u(` `+t(o.$t(`@AGENT:正在生成中...`)),1)])):(S(),f(D,{key:1},[v(`span`,yt,t(o.formatDate(e.updatedAt)),1),n[5]||=v(`span`,{class:`meta-dot`},`·`,-1),v(`span`,bt,t(e.messageCount)+` `+t(o.$t(`@AGENT:条`)),1)],64)),e.source===`cli`?(S(),f(`span`,xt,`CLI`)):r(`v-if`,!0)])]),v(`div`,{class:`session-item-actions`,onClick:n[1]||=H(()=>{},[`stop`])},[d(o.ElTooltip,{content:o.$t(`@AGENT:重命名`),placement:`top`,"show-after":500},{default:z(()=>[v(`button`,{class:`item-action-btn`,onClick:t=>o.handleRename(e.sessionId,e.title,t)},[d(o.ElIcon,null,{default:z(()=>[d(o.Edit)]),_:1})],8,St)]),_:2},1032,[`content`]),d(o.ElTooltip,{content:o.$t(`@AGENT:删除`),placement:`top`,"show-after":500},{default:z(()=>[v(`button`,{class:`item-action-btn danger`,onClick:t=>o.handleDelete(e.sessionId,t)},[d(o.ElIcon,null,{default:z(()=>[d(o.Delete)]),_:1})],8,Ct)]),_:2},1032,[`content`])])],10,mt))),128))])),[[l,o.sessionsLoading]])],4),r(` 拖拽分隔条 `),v(`div`,{class:L([`sidebar-resizer`,{active:o.isResizing}]),onMousedown:o.startResize},null,34)],64)):r(`v-if`,!0),r(` ═══ 右侧:Tab 栏 + 内容区 ═══ `),v(`main`,wt,[v(`nav`,Tt,[(S(!0),f(D,null,g(o.tabs,e=>(S(),f(`button`,{key:e.id,type:`button`,class:L([`agent-tab`,{active:o.activeTab===e.id}]),role:`tab`,"aria-selected":o.activeTab===e.id,onClick:t=>o.activeTab=e.id},[d(o.ElIcon,null,{default:z(()=>[(S(),a(ie(e.icon)))]),_:2},1024),v(`span`,null,t(e.label),1)],10,Et))),128))]),v(`div`,Dt,[r(` ── 对话 ── `),o.activeTab===`chat`?(S(),f(`div`,Ot,[r(` 加载中 `),o.sessionLoading?(S(),f(`div`,kt,[d(o.ElIcon,{class:`is-loading`,size:32},{default:z(()=>[d(o.Loading)]),_:1}),v(`span`,null,t(o.$t(`@AGENT:加载会话中...`)),1)])):(S(),f(D,{key:1},[r(` ChatContainer `),d(o.ChatContainer,{ref:`chatContainerRef`,messages:o.messages,"preset-questions":o.presetQuestions,"welcome-title":o.$t(`@AGENT:智能体助手`),"welcome-description":o.$t(`@AGENT:我可以帮你阅读代码、执行命令、修改文件。选择下方话题或直接输入你的问题。`),"assistant-name":`g ai`,theme:o.chatTheme,disabled:o.isStreaming,"upload-config":{accept:`image/*`},placeholder:o.isStreaming?o.$t(`@AGENT:正在生成中...`):o.$t(`@AGENT:输入消息,Enter 发送`),onSend:o.onSend,onSelect:o.onSelectPreset},null,8,[`messages`,`preset-questions`,`welcome-title`,`welcome-description`,`theme`,`disabled`,`placeholder`])],2112)),d(O,{name:`fade`},{default:z(()=>[o.pendingQuestion?(S(),f(`section`,At,[v(`div`,jt,[d(o.ElIcon,null,{default:z(()=>[d(o.ChatLineRound)]),_:1}),v(`span`,null,t(o.$t(`@AGENT:等待你的回答`)),1)]),v(`div`,Mt,t(o.pendingQuestion.question),1),o.pendingQuestion.options.length?(S(),f(`div`,Nt,[(S(!0),f(D,null,g(o.pendingQuestion.options,e=>(S(),f(`button`,{key:e,type:`button`,class:`ask-user-option`,disabled:o.answeringQuestion,onClick:t=>o.submitPendingAnswer(e)},[d(o.ElIcon,null,{default:z(()=>[d(o.Check)]),_:1}),v(`span`,null,t(e),1)],8,Pt))),128))])):r(`v-if`,!0),o.pendingQuestion.allowFreeText||o.pendingQuestion.options.length===0?(S(),f(`form`,{key:1,class:`ask-user-form`,onSubmit:n[3]||=H(e=>o.submitPendingAnswer(),[`prevent`])},[k(v(`input`,{"onUpdate:modelValue":n[2]||=e=>o.pendingAnswer=e,type:`text`,disabled:o.answeringQuestion,placeholder:o.$t(`@AGENT:输入回答`),"aria-label":o.$t(`@AGENT:输入回答`)},null,8,Ft),[[j,o.pendingAnswer]]),v(`button`,{type:`submit`,disabled:o.answeringQuestion||!o.pendingAnswer.trim()},[d(o.ElIcon,null,{default:z(()=>[d(o.Check)]),_:1}),v(`span`,null,t(o.$t(`@AGENT:提交回答`)),1)],8,It)],32)):r(`v-if`,!0)])):r(`v-if`,!0)]),_:1}),r(` 停止按钮浮层 `),d(O,{name:`fade`},{default:z(()=>[o.isStreaming?(S(),f(`div`,Lt,[v(`button`,{class:`stop-button`,onClick:n[4]||=(...e)=>o.stop&&o.stop(...e)},[d(o.ElIcon,null,{default:z(()=>[d(o.Loading,{class:`is-loading`})]),_:1}),v(`span`,null,t(o.$t(`@AGENT:停止生成`)),1)])])):r(`v-if`,!0)]),_:1})])):(S(),f(D,{key:1},[r(` ── Skill 广场 / MCP 广场 ── `),d(o.MarketplacePanel,{type:o.marketplaceType},null,8,[`type`])],2112))])])])}var zt=J(at,[[`render`,Rt],[`__scopeId`,`data-v-bd681ddd`],[`__file`,`D:/workspace/github_workspace/zen-gitsync/src/ui/client/src/views/AgentView.vue`]]);export{zt as default};
@@ -1 +0,0 @@
1
- import"./rolldown-runtime-C0FnF6B9.js";import{ar as e,fr as t,i as n,n as r,t as i,wn as a,yr as o,zn as s}from"./element-plus-DxBPQwL7.js";import{m as c}from"./vendor-IQQMq-1c.js";import{a as l,n as u,r as d}from"./_plugin-vue_export-helper-B1mHBne9.js";var f={"zh-CN":r,"en-US":i};function p(e){return f[e]||r}t(),s();var m=c(`locale`,()=>{let e=o(d()),t=a(()=>p(e.value));async function n(t){l(t),e.value=t;let n=h();n.locale!==t&&await n.saveGeneralSettings({locale:t})}return{currentLocale:e,elementPlusLocale:t,changeLocale:n}});t(),s();var h=c(`config`,()=>{let t=o(``),r=o([]),i=o([]),s=o([]),c=o([]),d=o([]),f=o([]),p=o([]),h=o([]),g=o(!1),_=o({enabled:!1,type:`command`,refId:``}),v=o(!1),y=o(!1),b=o(``),x=o(``),S=o(``),C=o(!0),w=o(!1),T=o(!0),E=o(!1),D=o(!1),O=o(!0),k=o(`light`),A=o(`zh-CN`),j=o([]),M=o(200),N=o(`claude`),P=o(!1),F={layout:{leftRatio:.25,midRatio:.375,rightRatio:.375,topRatio:.5},layoutsByProject:{},aiDiffSummaryByProject:{},fileListViewMode:`list`,fileDiffSplitPercent:35,diffPreviewSplitPercent:55,commandConsole:{expanded:!0,useTerminal:!0,showTerminalSessions:!0,splitPercent:25},editorAutoSave:!1,mindmapDirs:[],mindmapDir:``,headerToolsHidden:[],pickerGlobalSearch:!1},I=o(JSON.parse(JSON.stringify(F))),L=o(!1);function R(e){S.value=e||``}let z=a(()=>{let e=S.value;return e?I.value.aiDiffSummaryByProject[e]!==!1:!1});function ee(){let e=S.value;if(e&&I.value.layoutsByProject?.[e]){I.value.layout={...I.value.layoutsByProject[e]};return}}function B(e){let t=document.documentElement;e===`dark`?t.setAttribute(`data-theme`,`dark`):e===`light`?t.removeAttribute(`data-theme`):window.matchMedia(`(prefers-color-scheme: dark)`).matches?t.setAttribute(`data-theme`,`dark`):t.removeAttribute(`data-theme`)}function te(){let e=document.documentElement.getAttribute(`data-theme`)===`dark`?`light`:`dark`;return k.value=e,B(e),$({theme:e}).catch(e=>{console.error(`保存主题切换结果失败:`,e)}),e}B(k.value);let V=a(()=>({defaultCommitMessage:t.value,descriptionTemplates:r.value,scopeTemplates:i.value,messageTemplates:s.value,commandTemplates:c.value,lockedFiles:d.value,customCommands:f.value,orchestrations:p.value,startupItems:h.value,startupAutoRun:g.value,afterQuickPushAction:_.value,currentDirectory:S.value})),ne=a(()=>!!(b.value&&b.value.trim()));async function H(){try{let e=await fetch(`/api/config/open-file`,{method:`POST`,headers:{"Content-Type":`application/json`}}),t=await e.json().catch(()=>({}));return e.ok&&t?.success?(n.success(u(`@D50BB:已打开系统配置文件`)),!0):(n.error(`${u(`@D50BB:打开系统配置文件失败: `)}${t?.error||``}`),!1)}catch(e){return n.error(`${u(`@D50BB:打开系统配置文件失败: `)}${e.message}`),!1}}async function U(e=!1){if(!e&&y.value&&!v.value)return console.log(u(`@D50BB:使用缓存的配置信息`)),V.value;v.value=!0;try{v.value=!0,console.log(u(`@D50BB:加载配置信息...`));let e=await fetch(`/api/config/getConfig`),a=await e.json().catch(()=>({}));if(!e.ok||a&&a.success===!1){let e=String(a?.error||u(`@D50BB:加载配置失败`)),t=String(a?.configPath||``),r=t?`\n${u(`@D50BB:配置文件`)}: ${t}`:``;return n.error(`${u(`@D50BB:加载配置失败: `)}${e}${r}`),b.value=e,x.value=t,null}if(b.value=``,x.value=``,t.value=a.defaultCommitMessage||``,r.value=a.descriptionTemplates||[],i.value=a.scopeTemplates||[],s.value=a.messageTemplates||[],c.value=a.commandTemplates||[],d.value=a.lockedFiles||[],f.value=a.customCommands||[],p.value=a.orchestrations||[],h.value=(a.startupItems||[]).map(e=>({id:String(e?.id??``),type:e?.type===`workflow`?`workflow`:`command`,refId:String(e?.refId??e?.commandId??``),createdAt:Number(e?.createdAt??Date.now()),enabled:typeof e?.enabled!=`boolean`||e.enabled})).filter(e=>e.id&&e.refId),g.value=a.startupAutoRun||!1,_.value={enabled:!!a?.afterQuickPushAction?.enabled,type:a?.afterQuickPushAction?.type===`workflow`?`workflow`:`command`,refId:String(a?.afterQuickPushAction?.refId||``).trim()},a.isStandardCommit!==void 0&&(T.value=!!a.isStandardCommit),a.skipHooks!==void 0&&(E.value=!!a.skipHooks),a.autoQuickPushOnEnter!==void 0&&(D.value=!!a.autoQuickPushOnEnter),a.autoSetDefaultMessage!==void 0&&(w.value=!!a.autoSetDefaultMessage),a.autoClosePushModal!==void 0&&(C.value=!!a.autoClosePushModal),a.pullBeforePush!==void 0&&(O.value=!!a.pullBeforePush),Array.isArray(a.models)&&(j.value=a.models),Number.isFinite(Number(a.aiMaxToolIterations))&&Number(a.aiMaxToolIterations)>0&&(M.value=Math.floor(Number(a.aiMaxToolIterations))),(a.taskExecutor===`claude`||a.taskExecutor===`opencode`)&&(N.value=a.taskExecutor),typeof a.notifyOnTaskDone==`boolean`&&(P.value=a.notifyOnTaskDone),a.theme&&[`light`,`dark`,`auto`].includes(a.theme)&&(k.value=a.theme,B(a.theme)),a.locale&&[`zh-CN`,`en-US`].includes(a.locale)){A.value=a.locale,l(a.locale);let e=m();e.currentLocale=a.locale}if(a.currentDirectory&&(S.value=a.currentDirectory),a.ui==null){let e=e=>{try{return localStorage.getItem(e)}catch{return null}},t={},n=e(`zen-gitsync-layout-left-ratio`),r=e(`zen-gitsync-layout-mid-ratio`),i=e(`zen-gitsync-layout-right-ratio`),a=e(`zen-gitsync-layout-top-ratio`);if(n||r||i||a){let e=(e,t)=>{let n=e==null?NaN:parseFloat(e);return Number.isFinite(n)?n:t};t.layout={leftRatio:e(n,F.layout.leftRatio),midRatio:e(r,F.layout.midRatio),rightRatio:e(i,F.layout.rightRatio),topRatio:e(a,F.layout.topRatio)}}let o=e(`zen-gitsync-file-list-view-mode`);(o===`list`||o===`tree`)&&(t.fileListViewMode=o);let s=e(`zen-gitsync-filediff-ratio`)??e(`fileDiff.splitPercent`);if(s!=null){let e=parseFloat(s);Number.isFinite(e)&&(t.fileDiffSplitPercent=Math.min(85,Math.max(15,e)))}let c=e(`useTerminal`),l=e(`isConsoleExpanded`),u=e(`showTerminalSessions`),d=e(`zen-gitsync-commandconsole-ratio`);if(c!==null||l!==null||u!==null||d!=null){let e=d==null?NaN:parseFloat(d);t.commandConsole={useTerminal:c!==`false`,expanded:l!==`false`,showTerminalSessions:u==null||u===`true`,splitPercent:Number.isFinite(e)?Math.min(85,Math.max(15,e)):F.commandConsole.splitPercent}}let f=e(`zen-gitsync-editor-auto-save`);f!=null&&(t.editorAutoSave=f===`true`),Object.keys(t).length>0&&(I.value={...I.value,...t}),Object.keys(t).length>0&&J(t,{immediate:!0}).catch(e=>{console.error(`迁移 UI 设置到文件失败:`,e)});try{[`zen-gitsync-theme`,`zen-gitsync-locale`,`zen-gitsync-editor-auto-save`,`zen-gitsync-file-list-view-mode`,`zen-gitsync-filediff-ratio`,`fileDiff.splitPercent`,`isConsoleExpanded`,`useTerminal`,`showTerminalSessions`,`zen-gitsync-commandconsole-ratio`,`zen-gitsync-layout-left-ratio`,`zen-gitsync-layout-mid-ratio`,`zen-gitsync-layout-right-ratio`,`zen-gitsync-layout-top-ratio`,`locale`].forEach(e=>localStorage.removeItem(e))}catch{}}else{let e=a.ui.layoutsByProject&&typeof a.ui.layoutsByProject==`object`&&!Array.isArray(a.ui.layoutsByProject)?a.ui.layoutsByProject:{},t={};for(let[n,r]of Object.entries(e))if(r&&typeof r==`object`&&!Array.isArray(r)){let e=r;t[n]={leftRatio:Number.isFinite(Number(e.leftRatio))?Number(e.leftRatio):F.layout.leftRatio,midRatio:Number.isFinite(Number(e.midRatio))?Number(e.midRatio):F.layout.midRatio,rightRatio:Number.isFinite(Number(e.rightRatio))?Number(e.rightRatio):F.layout.rightRatio,topRatio:Number.isFinite(Number(e.topRatio))?Number(e.topRatio):F.layout.topRatio}}let n=a.ui.aiDiffSummaryByProject&&typeof a.ui.aiDiffSummaryByProject==`object`&&!Array.isArray(a.ui.aiDiffSummaryByProject)?a.ui.aiDiffSummaryByProject:{},r={};for(let[e,t]of Object.entries(n))typeof t==`boolean`&&(r[e]=t);let i=typeof a.ui.mindmapDir==`string`?a.ui.mindmapDir.trim():``,o=[],s=new Set,c=Array.isArray(a.ui.mindmapDirs)?a.ui.mindmapDirs:[];for(let e of c){if(typeof e!=`string`)continue;let t=e.trim();if(!t)continue;let n=t.toLowerCase();s.has(n)||(s.add(n),o.push(t))}o.length===0&&i&&o.push(i);let l={...F.layout,...a.ui.layout||{}};I.value={layout:l,layoutsByProject:t,aiDiffSummaryByProject:r,fileListViewMode:a.ui.fileListViewMode===`tree`?`tree`:`list`,fileDiffSplitPercent:Number.isFinite(Number(a.ui.fileDiffSplitPercent))?Math.min(85,Math.max(15,Number(a.ui.fileDiffSplitPercent))):F.fileDiffSplitPercent,diffPreviewSplitPercent:Number.isFinite(Number(a.ui.diffPreviewSplitPercent))?Math.min(85,Math.max(25,Number(a.ui.diffPreviewSplitPercent))):F.diffPreviewSplitPercent,commandConsole:{expanded:typeof a.ui.commandConsole?.expanded==`boolean`?a.ui.commandConsole.expanded:F.commandConsole.expanded,useTerminal:typeof a.ui.commandConsole?.useTerminal==`boolean`?a.ui.commandConsole.useTerminal:F.commandConsole.useTerminal,showTerminalSessions:typeof a.ui.commandConsole?.showTerminalSessions==`boolean`?a.ui.commandConsole.showTerminalSessions:F.commandConsole.showTerminalSessions,splitPercent:Number.isFinite(Number(a.ui.commandConsole?.splitPercent))?Math.min(85,Math.max(15,Number(a.ui.commandConsole.splitPercent))):F.commandConsole.splitPercent},editorAutoSave:typeof a.ui.editorAutoSave==`boolean`?a.ui.editorAutoSave:F.editorAutoSave,mindmapDirs:o,mindmapDir:i,headerToolsHidden:Array.isArray(a.ui.headerToolsHidden)?a.ui.headerToolsHidden.filter(e=>typeof e==`string`):[],pickerGlobalSearch:typeof a.ui.pickerGlobalSearch==`boolean`?a.ui.pickerGlobalSearch:F.pickerGlobalSearch}}return ee(),L.value=!0,y.value=!0,console.log(u(`@D50BB:配置信息加载完成`)),V.value}catch(e){return console.error(`加载配置失败:`,e),n.error(`${u(`@D50BB:加载配置失败: `)}${e.message}`),b.value=e.message,null}finally{v.value=!1}}async function W(){try{await fetch(`/api/config/save-commit-settings`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({isStandardCommit:T.value,skipHooks:E.value,autoQuickPushOnEnter:D.value,autoSetDefaultMessage:w.value,autoClosePushModal:C.value,pullBeforePush:O.value})})}catch(e){console.error(`保存提交设置失败:`,e)}}e([T,E,D,w,C,O],()=>{y.value&&W()});let G=null,K={};async function q(){if(G&&=(clearTimeout(G),null),Object.keys(K).length===0)return;let e=K;K={};try{await fetch(`/api/config/save-ui-settings`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify(e)})}catch(e){console.error(`保存 UI 设置失败:`,e)}}async function J(e,t={}){if(L.value){if(t.immediate){Object.assign(K,e),await q();return}Object.assign(K,e),G&&clearTimeout(G),G=setTimeout(()=>{q()},300)}}async function Y(){I.value.layout={...F.layout};let e=S.value;return e&&(I.value.layoutsByProject={...I.value.layoutsByProject,[e]:{...I.value.layout}}),await J({layoutsByProject:I.value.layoutsByProject},{immediate:!0}),I.value.layout}async function X(e){let t=S.value;t&&(I.value.aiDiffSummaryByProject={...I.value.aiDiffSummaryByProject,[t]:e},await J({aiDiffSummaryByProject:{[t]:e}},{immediate:!0}))}e(()=>I.value.fileListViewMode,e=>{L.value&&J({fileListViewMode:e})}),e(()=>I.value.fileDiffSplitPercent,e=>{L.value&&J({fileDiffSplitPercent:e})}),e(()=>I.value.diffPreviewSplitPercent,e=>{L.value&&e!=null&&J({diffPreviewSplitPercent:e})}),e(()=>I.value.editorAutoSave,e=>{L.value&&J({editorAutoSave:e})}),e(()=>I.value.headerToolsHidden,e=>{L.value&&Array.isArray(e)&&J({headerToolsHidden:e})}),e(()=>I.value.mindmapDirs,e=>{L.value&&Array.isArray(e)&&J({mindmapDirs:e})}),e(()=>I.value.pickerGlobalSearch,e=>{L.value&&J({pickerGlobalSearch:e})}),e(()=>I.value.layout,e=>{if(!L.value)return;let t=S.value;t&&(I.value.layoutsByProject={...I.value.layoutsByProject,[t]:e},J({layoutsByProject:I.value.layoutsByProject}))},{deep:!0}),e(()=>I.value.commandConsole,e=>{L.value&&J({commandConsole:e})},{deep:!0}),typeof window<`u`&&window.addEventListener(`beforeunload`,()=>{q()});async function re(e){try{let r=await(await fetch(`/api/config/saveDefaultMessage`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({defaultCommitMessage:e})})).json();return r.success?(t.value=e,n.success(u(`@D50BB:默认提交信息已保存`)),!0):(n.error(`${u(`@D50BB:保存失败: `)}${r.error}`),!1)}catch(e){return n.error(`${u(`@D50BB:保存失败: `)}${e.message}`),!1}}async function ie(e){try{let t=await(await fetch(`/api/config/save-after-quick-push-action`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({afterQuickPushAction:{enabled:!!e?.enabled,type:e?.type===`workflow`?`workflow`:`command`,refId:String(e?.refId||``).trim()}})})).json();return t.success?(_.value={enabled:!!e?.enabled,type:e?.type===`workflow`?`workflow`:`command`,refId:String(e?.refId||``).trim()},!0):(n.error(`保存提交后启动项失败: ${t.error}`),!1)}catch(e){return n.error(`保存提交后启动项失败: ${e.message}`),!1}}async function ae(e,t){try{let a=await(await fetch(`/api/config/save-template`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({template:e,type:t})})).json();return a.success?(t===`description`?r.value.includes(e)||r.value.push(e):t===`scope`?i.value.includes(e)||i.value.push(e):t===`message`?s.value.includes(e)||s.value.push(e):t===`command`&&(c.value.includes(e)||c.value.push(e)),n.success(u(`@D50BB:模板已保存`)),!0):(n.error(`${u(`@D50BB:保存模板失败: `)}${a.error}`),!1)}catch(e){return n.error(`${u(`@D50BB:保存模板失败: `)}${e.message}`),!1}}async function oe(e,t){try{let a=await(await fetch(`/api/config/delete-template`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({template:e,type:t})})).json();return a.success?(t===`description`?r.value=r.value.filter(t=>t!==e):t===`scope`?i.value=i.value.filter(t=>t!==e):t===`message`?s.value=s.value.filter(t=>t!==e):t===`command`&&(c.value=c.value.filter(t=>t!==e)),n.success(u(`@D50BB:模板已删除`)),!0):(n.error(`${u(`@D50BB:删除模板失败: `)}${a.error}`),!1)}catch(e){return n.error(`${u(`@D50BB:删除模板失败: `)}${e.message}`),!1}}async function se(e,t,a){try{let o=await(await fetch(`/api/config/update-template`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({oldTemplate:e,newTemplate:t,type:a})})).json();if(o.success){if(a===`description`){let n=r.value.indexOf(e);n!==-1&&(r.value[n]=t)}else if(a===`scope`){let n=i.value.indexOf(e);n!==-1&&(i.value[n]=t)}else if(a===`message`){let n=s.value.indexOf(e);n!==-1&&(s.value[n]=t)}else if(a===`command`){let n=c.value.indexOf(e);n!==-1&&(c.value[n]=t)}return n.success(u(`@D50BB:模板已更新`)),!0}return n.error(`${u(`@D50BB:更新模板失败: `)}${o.error}`),!1}catch(e){return n.error(`${u(`@D50BB:更新模板失败: `)}${e.message}`),!1}}async function ce(e,t){try{let a=await(await fetch(`/api/config/pin-template`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({template:e,type:t})})).json();return a.success?(t===`description`?(r.value=r.value.filter(t=>t!==e),r.value.unshift(e)):t===`scope`?(i.value=i.value.filter(t=>t!==e),i.value.unshift(e)):t===`message`?(s.value=s.value.filter(t=>t!==e),s.value.unshift(e)):t===`command`&&(c.value=c.value.filter(t=>t!==e),c.value.unshift(e)),n.success(u(`@D50BB:模板已置顶`)),!0):(n.error(`${u(`@D50BB:置顶模板失败: `)}${a.error}`),!1)}catch(e){return n.error(`${u(`@D50BB:置顶模板失败: `)}${e.message}`),!1}}async function Z(){try{let e=await(await fetch(`/api/locked-files`)).json();return e.success?(d.value=e.lockedFiles||[],e.lockedFiles):(n.error(`${u(`@D50BB:加载锁定文件列表失败: `)}${e.error}`),[])}catch(e){return console.error(`加载锁定文件列表失败:`,e),n.error(`${u(`@D50BB:加载锁定文件列表失败: `)}${e.message}`),[]}}async function le(e){try{let t=await(await fetch(`/api/lock-file`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({filePath:e})})).json();return t.success?(await Z(),n.success(`${u(`@D50BB:文件已锁定: `)}${e}`),!0):(n.error(`${u(`@D50BB:锁定文件失败: `)}${t.error}`),!1)}catch(e){return console.error(`锁定文件失败:`,e),n.error(`${u(`@D50BB:锁定文件失败: `)}${e.message}`),!1}}async function ue(e){try{let t=await(await fetch(`/api/unlock-file`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({filePath:e})})).json();return t.success?(await Z(),n.success(`${u(`@D50BB:文件已解锁: `)}${e}`),!0):(n.error(`${u(`@D50BB:解锁文件失败: `)}${t.error}`),!1)}catch(e){return console.error(`解锁文件失败:`,e),n.error(`${u(`@D50BB:解锁文件失败: `)}${e.message}`),!1}}async function de(e){try{let t=await(await fetch(`/api/check-file-lock`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({filePath:e})})).json();return t.success?t.isLocked:(console.error(`检查文件锁定状态失败:`,t.error),!1)}catch(e){return console.error(`检查文件锁定状态失败:`,e),!1}}async function fe(e){try{let t=await(await fetch(`/api/config/save-custom-command`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({command:e})})).json();return t.success?(await U(!0),n.success(u(`@CMD01:命令已保存`)),!0):(n.error(`${u(`@CMD01:保存命令失败: `)}${t.error}`),!1)}catch(e){return n.error(`${u(`@CMD01:保存命令失败: `)}${e.message}`),!1}}async function Q(e){try{let t=await(await fetch(`/api/config/delete-custom-command`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({id:e})})).json();return t.success?(await U(!0),n.success(u(`@CMD01:命令已删除`)),!0):(n.error(`${u(`@CMD01:删除命令失败: `)}${t.error}`),!1)}catch(e){return n.error(`${u(`@CMD01:删除命令失败: `)}${e.message}`),!1}}async function pe(e,t){try{let r=await(await fetch(`/api/config/update-custom-command`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({id:e,command:t})})).json();return r.success?(await U(!0),n.success(u(`@CMD01:命令已更新`)),!0):(n.error(`${u(`@CMD01:更新命令失败: `)}${r.error}`),!1)}catch(e){return n.error(`${u(`@CMD01:更新命令失败: `)}${e.message}`),!1}}async function me(e){try{let t=await(await fetch(`/api/config/pin-custom-command`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({id:e})})).json();return t.success?(await U(!0),!0):(n.error(t.error),!1)}catch(e){return n.error(e.message),!1}}async function he(e){try{let t=await(await fetch(`/api/config/save-orchestration`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({orchestration:e})})).json();return t.success?(await U(!0),n.success(u(`@ORCH:编排已保存`)),t.orchestration||null):(n.error(`${u(`@ORCH:保存编排失败: `)}${t.error}`),null)}catch(e){return n.error(`${u(`@ORCH:保存编排失败: `)}${e.message}`),null}}async function ge(e){try{let t=await(await fetch(`/api/config/delete-orchestration`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({id:e})})).json();return t.success?(await U(!0),n.success(u(`@ORCH:编排已删除`)),!0):(n.error(`${u(`@ORCH:删除编排失败: `)}${t.error}`),!1)}catch(e){return n.error(`${u(`@ORCH:删除编排失败: `)}${e.message}`),!1}}async function _e(e,t){try{let r=await(await fetch(`/api/config/update-orchestration`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({id:e,orchestration:t})})).json();return r.success?(await U(!0),n.success(u(`@ORCH:编排已更新`)),!0):(n.error(`${u(`@ORCH:更新编排失败: `)}${r.error}`),!1)}catch(e){return n.error(`${u(`@ORCH:更新编排失败: `)}${e.message}`),!1}}async function ve(e,t){try{let r=await(await fetch(`/api/config/save-startup-items`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({startupItems:e,startupAutoRun:t===void 0?g.value:t})})).json();return r.success?(h.value=e,t!==void 0&&(g.value=t),!0):(n.error(`保存启动项失败: ${r.error}`),!1)}catch(e){return n.error(`保存启动项失败: ${e.message}`),!1}}async function ye(e){try{let t=await(await fetch(`/api/config/save-ai-settings`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({aiMaxToolIterations:e.aiMaxToolIterations})})).json();return t.success?(M.value=Number(t.aiMaxToolIterations)||e.aiMaxToolIterations,!0):(n.error(`${u(`@D50BB:保存 AI 设置失败: `)}${t.error}`),!1)}catch(e){return n.error(`${u(`@D50BB:保存 AI 设置失败: `)}${e.message}`),!1}}async function be(e){try{let t=await(await fetch(`/api/config/save-models`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({models:e})})).json();return t.success?(j.value=e,!0):(n.error(`${u(`@D50BB:保存模型失败: `)}${t.error}`),!1)}catch(e){return n.error(`${u(`@D50BB:保存模型失败: `)}${e.message}`),!1}}async function $(e){try{let t=await(await fetch(`/api/config/save-general-settings`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify(e)})).json();if(t.success){if(e.theme&&(k.value=e.theme,B(e.theme)),e.locale){A.value=e.locale,l(e.locale);let t=m();t.currentLocale=e.locale}return(e.taskExecutor===`claude`||e.taskExecutor===`opencode`)&&(N.value=e.taskExecutor),typeof e.notifyOnTaskDone==`boolean`&&(P.value=e.notifyOnTaskDone),!0}return n.error(`保存通用设置失败: ${t.error}`),!1}catch(e){return n.error(`保存通用设置失败: ${e.message}`),!1}}return{models:j,aiMaxToolIterations:M,taskExecutor:N,notifyOnTaskDone:P,defaultCommitMessage:t,descriptionTemplates:r,scopeTemplates:i,messageTemplates:s,commandTemplates:c,lockedFiles:d,customCommands:f,orchestrations:p,startupItems:h,startupAutoRun:g,afterQuickPushAction:_,isLoading:v,isLoaded:y,configLoadError:b,configFilePath:x,hasConfigLoadError:ne,currentDirectory:S,config:V,autoClosePushModal:C,autoSetDefaultMessage:w,isStandardCommit:T,skipHooks:E,autoQuickPushOnEnter:D,pullBeforePush:O,theme:k,locale:A,ui:I,isUiLoaded:L,aiDiffSummaryEnabled:z,loadConfig:U,setCurrentDirectory:R,openSystemConfigFile:H,saveTemplate:ae,saveModels:be,saveAiSettings:ye,saveGeneralSettings:$,saveUiSettings:J,setAiDiffSummaryEnabled:X,resetUiLayout:Y,applyTheme:B,toggleTheme:te,saveDefaultMessage:re,deleteTemplate:oe,updateTemplate:se,pinTemplate:ce,loadLockedFiles:Z,lockFile:le,unlockFile:ue,isFileLocked:de,saveCustomCommand:fe,deleteCustomCommand:Q,updateCustomCommand:pe,pinCustomCommand:me,saveOrchestration:he,deleteOrchestration:ge,updateOrchestration:_e,saveStartupItems:ve,saveAfterQuickPushAction:ie,saveCommitSettings:W}});export{m as n,h as t};