zen-gitsync 2.17.14 → 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 (89) hide show
  1. package/README.md +211 -185
  2. package/package.json +2 -2
  3. package/scripts/release.js +33 -16
  4. package/src/cli/ai/agent.js +24 -2
  5. package/src/cli/ai/runtime.test.js +1 -1
  6. package/src/cli/ai/tools.js +69 -14
  7. package/src/cli/ai/tools.test.js +46 -1
  8. package/src/config.js +8 -4
  9. package/src/gitCommit.js +18 -1
  10. package/src/ui/public/assets/AgentView-DOyN97Ve.js +5 -0
  11. package/src/ui/public/assets/{AgentView-vvVhbIQ5.css → AgentView-DkM2KXuc.css} +1 -1
  12. package/src/ui/public/assets/AppVersionBadge-oON3sAj4.js +2 -0
  13. package/src/ui/public/assets/{BranchSelector-XIN87Mkw.js → BranchSelector-Cpj7eGqY.js} +1 -1
  14. package/src/ui/public/assets/CommitForm-D_ovYhVw.js +6 -0
  15. package/src/ui/public/assets/{CommonDialog-BiNTGpA-.js → CommonDialog-ChZbqfRF.js} +1 -1
  16. package/src/ui/public/assets/EditorView-BPzpI0GV.js +1 -0
  17. package/src/ui/public/assets/FileDiffViewer-B_qEKA9L.js +15 -0
  18. package/src/ui/public/assets/{FlowExecutionViewer-D9Vzgh91.js → FlowExecutionViewer-Drw4hlJG.js} +1 -1
  19. package/src/ui/public/assets/FlowOrchestrationWorkspace-C7yTD1gj.js +21 -0
  20. package/src/ui/public/assets/{IconButton-DysyaC1j.js → IconButton-DEARmMkZ.js} +1 -1
  21. package/src/ui/public/assets/{LogList-QDgok-UJ.js → LogList-BA_gowxE.js} +5 -5
  22. package/src/ui/public/assets/MindmapView-8X6z245q.css +1 -0
  23. package/src/ui/public/assets/MindmapView-K-XcLLXr.js +2 -0
  24. package/src/ui/public/assets/MonitorView-C0RL5K9W.js +1 -0
  25. package/src/ui/public/assets/ProjectStartupButton-DC36_vvU.js +1 -0
  26. package/src/ui/public/assets/RemoteManagerDialog-Bkqja660.js +4 -0
  27. package/src/ui/public/assets/{RemoteRepoCard-Bn9cKt1D.js → RemoteRepoCard-Bsm7cj_H.js} +2 -2
  28. package/src/ui/public/assets/SourceMapView-Y5NKdIk6.js +3 -0
  29. package/src/ui/public/assets/{SvgIcon-CvtoU5yo.js → SvgIcon-D_mFHXP4.js} +1 -1
  30. package/src/ui/public/assets/{TemplateManager-saqC9kdQ.js → TemplateManager-BzKVXZhy.js} +1 -1
  31. package/src/ui/public/assets/UserInputNode-BPLK4aYx.js +1 -0
  32. package/src/ui/public/assets/WorkbenchView-xbGdiVMQ.js +56 -0
  33. package/src/ui/public/assets/_plugin-vue_export-helper-dg2VUnSQ.js +19 -0
  34. package/src/ui/public/assets/configStore-DtjAc3w9.js +1 -0
  35. package/src/ui/public/assets/{css.worker-DFdt6_zu.js → css.worker-BDCmgL4U.js} +9 -9
  36. package/src/ui/public/assets/editor.worker-GCPm6rMv.js +26 -0
  37. package/src/ui/public/assets/{element-plus-Dc1iTOWq.css → element-plus-Cwwq-Gje.css} +1 -1
  38. package/src/ui/public/assets/element-plus-DxBPQwL7.js +48 -0
  39. package/src/ui/public/assets/{flow-mindmap-CHxAWdLw.js → flow-mindmap-BqFb1WO5.js} +1 -1
  40. package/src/ui/public/assets/{gitStore-BgC8OY0k.js → gitStore-BZo9_zyy.js} +5 -5
  41. package/src/ui/public/assets/{html.worker-JUzsMP-j.js → html.worker-DG8hnSJR.js} +8 -8
  42. package/src/ui/public/assets/index-CHuCYLWm.js +111 -0
  43. package/src/ui/public/assets/index-CmbatbSR.css +1 -0
  44. package/src/ui/public/assets/json.worker-CxwlJRnL.js +58 -0
  45. package/src/ui/public/assets/{monaco-DkJuNcCr.js → monaco-BScz9v63.js} +6 -6
  46. package/src/ui/public/assets/{office-docx-CmBY5bpF.js → office-docx-CZXLkCf5.js} +1 -1
  47. package/src/ui/public/assets/{office-excel-BEhsBUNX.js → office-excel-CBKszjVA.js} +1 -1
  48. package/src/ui/public/assets/{office-pptx-DWfi413x.js → office-pptx-NeUSnN3k.js} +3 -3
  49. package/src/ui/public/assets/previewSandbox-BTTTXooN.js +0 -0
  50. package/src/ui/public/assets/{ts.worker-CmEKzkmF.js → ts.worker-DgFMIcEs.js} +49 -49
  51. package/src/ui/public/assets/{useThemeObserver-DhCU3SIo.js → useThemeObserver-E7Hk50l3.js} +1 -1
  52. package/src/ui/public/assets/vendor-DnB9EJa3.css +1 -0
  53. package/src/ui/public/assets/{vendor-CZnXb2r9.js → vendor-bdHhLiED.js} +28 -28
  54. package/src/ui/public/assets/{vue-flow-7_n4vJqi.js → vue-flow-fLUQ0_kE.js} +1 -1
  55. package/src/ui/public/index.html +19 -19
  56. package/src/ui/server/index.js +4 -0
  57. package/src/ui/server/routes/explorerContextMenu.js +208 -0
  58. package/src/ui/server/routes/explorerContextMenu.test.js +180 -0
  59. package/src/ui/server/routes/workbench/agentChat.js +14 -3
  60. package/src/ui/server/routes/workbench/agentMarketplace.js +23 -9
  61. package/src/ui/server/routes/workbench/agentMarketplace.test.js +32 -0
  62. package/src/ui/server/routes/workbench/agentRoutes.js +14 -7
  63. package/src/ui/server/routes/workbench/agentRoutes.test.js +47 -1
  64. package/src/ui/server/routes/workbench/taskRunner.codex.test.js +173 -0
  65. package/src/ui/server/routes/workbench/taskRunner.js +259 -10
  66. package/src/ui/server/routes/workbench/taskRunner.opencode.test.js +4 -2
  67. package/src/ui/public/assets/AgentView-DLHlVWRg.js +0 -5
  68. package/src/ui/public/assets/AppVersionBadge-JxpMuGwP.js +0 -2
  69. package/src/ui/public/assets/CommitForm-CW53Er5m.js +0 -6
  70. package/src/ui/public/assets/EditorView-D0JoJhgt.js +0 -1
  71. package/src/ui/public/assets/FileDiffViewer-Yas2nO2U.js +0 -15
  72. package/src/ui/public/assets/FlowOrchestrationWorkspace-DQ3fg5b9.js +0 -21
  73. package/src/ui/public/assets/MindmapView-BQTqx842.css +0 -1
  74. package/src/ui/public/assets/MindmapView-CeZsQNBK.js +0 -2
  75. package/src/ui/public/assets/MonitorView-D1tgmjjS.js +0 -1
  76. package/src/ui/public/assets/ProjectStartupButton-COntA4q1.js +0 -1
  77. package/src/ui/public/assets/RemoteManagerDialog-3dihAOab.js +0 -4
  78. package/src/ui/public/assets/SourceMapView-C8UdzQXF.js +0 -3
  79. package/src/ui/public/assets/UserInputNode-CvEfvX3i.js +0 -1
  80. package/src/ui/public/assets/WorkbenchView-B7WAu1Ay.js +0 -56
  81. package/src/ui/public/assets/_plugin-vue_export-helper-BdTxl34g.js +0 -19
  82. package/src/ui/public/assets/configStore-AQMSazCM.js +0 -1
  83. package/src/ui/public/assets/editor.worker-O-CH8JUO.js +0 -26
  84. package/src/ui/public/assets/element-plus-CMSkP_w2.js +0 -48
  85. package/src/ui/public/assets/index-Dpx9Bcqn.css +0 -1
  86. package/src/ui/public/assets/index-qAmzFO10.js +0 -104
  87. package/src/ui/public/assets/json.worker-B4dEhy0e.js +0 -58
  88. package/src/ui/public/assets/previewSandbox-CyuMMYaq.js +0 -0
  89. package/src/ui/public/assets/vendor-4ojsjDYc.css +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zen-gitsync",
3
- "version": "2.17.14",
3
+ "version": "2.17.16",
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",
@@ -130,7 +130,7 @@
130
130
  "date-fns": "^4.1.0",
131
131
  "express": "^5.1.0",
132
132
  "iconv-lite": "^0.7.0",
133
- "local-file-picker": "^0.2.3",
133
+ "local-file-picker": "^0.2.4",
134
134
  "log-update": "^6.1.0",
135
135
  "open": "^10.1.2",
136
136
  "ora": "^8.1.1",
@@ -28,6 +28,7 @@
28
28
  * npm run release -- --skip-push # 只发布到 npm,不 push git
29
29
  * npm run release -- --dry-run # 只打印计划,不真正改 package.json / commit / publish
30
30
  * npm run release -- --poll-interval=20 --poll-timeout=600 # 调自更新重试节奏(秒)
31
+ * npm run release -- --install-timeout=900 # 单次 npm install 上限(秒),0 = 不限时(默认)
31
32
  *
32
33
  * 发布后自更新:每轮先探 tarball 能不能取,能取到才调 npm;两条路(`pkg@<版本>` /
33
34
  * tarball URL 直连)都试,装上后校验全局版本,失败把原因打出来。
@@ -92,8 +93,9 @@ function readNumberArg(name, fallback) {
92
93
  // 于是 600s 眼看要耗尽、终端上 25 轮只有"→ npm install"没有任何原因。
93
94
  // 对策两条:① 每轮先自己探一次 tarball(isTarballFetchable,GET 而非 HEAD),
94
95
  // 取不到就跳过这一轮的 npm 调用并把状态打出来;② 失败原因压一行打出来。
95
- // 另外单次 npm 调用必须有时间上限(见 INSTALL_TIMEOUT_MS),否则一次网络卡死
96
- // 就能吃掉整个预算,外面那个 15s 一轮的循环根本没机会重试。
96
+ // 单次 npm 调用不再硬性截断(见 INSTALL_TIMEOUT_MS):曾经给 180s 是为了"快速失败、
97
+ // 把重试交给外层循环",但实测更常见的是 180s 不够 —— 每轮装到一半被杀、下轮从零重来,
98
+ // 进度永远清零(2026-09-24 v2.17.14 卡了 27 轮)。要收紧可用 `--install-timeout=<秒>`。
97
99
  //
98
100
  // 默认 15s 一轮、上限 600s;可用 `--poll-interval=<秒>` / `--poll-timeout=<秒>` 调。
99
101
  const POLL_INTERVAL_MS = readNumberArg('--poll-interval', 15) * 1000
@@ -627,30 +629,43 @@ function readGlobalInstalledVersion() {
627
629
  // 输出先兜住不打印:重试期间每失败一次就刷一屏 `npm error` 太吵,
628
630
  // 失败时由调用方压成一行打出来(summarizeInstallError),整轮失败才回放全文。
629
631
  //
630
- // 时间必须**有界**:npm 自己的 fetch-timeout 是 5 分钟、还要重试 2 次,
631
- // 网络卡住时单次 `npm install` 能吃掉十几分钟 —— 实测挂在一个坏代理上,
632
- // 一次调用就耗掉了整个 600s 预算,外面那个"每 15s 重试一轮"的循环根本没有机会跑第二轮。
633
- // 所以这里把 fetch 重试收紧、再给 execSync 一个硬上限:让每次尝试**快速失败**,
634
- // 把"重试"这件事交给外层循环(它本来就在做,而且间隔只有 15s)。
635
- const INSTALL_TIMEOUT_MS = 180000
632
+ // 单次安装要不要设上限:**默认不设**(--install-timeout=0)。
633
+ //
634
+ // 早期这里硬写 180s,理由是"npm 自己的 fetch-timeout 是 5 分钟、还要重试 2 次,
635
+ // 网络卡住时单次 install 能吃掉十几分钟";但实测发现更常见的是反过来的坑 ——
636
+ // 首次装一个大包 + 冷缓存 + 国内直连 registry.npmjs.org,180s 根本不够,
637
+ // 于是每一轮都是"装到一半被杀 → 下一轮从零重来",27 轮全卡在同一处,
638
+ // 永远装不上(2026-09-24 v2.17.14)。**杀掉重来 ≠ 快速失败**,它只是把进度清零。
639
+ //
640
+ // 现在把上限交给调用方:INSTALL_TIMEOUT_MS > 0 时才给 execSync 传 timeout;
641
+ // 为 0 时不传该选项 —— 单次 install 跑到自然结束(npm 自身的 fetch-timeout 仍在,
642
+ // 所以不会真的无限挂住)。
643
+ const INSTALL_TIMEOUT_MS = readNumberArg('--install-timeout', 0) * 1000
636
644
  function tryInstallGlobal(spec) {
637
- console.log(chalk.gray(` → npm install -g ${spec}`))
645
+ const limit = INSTALL_TIMEOUT_MS
646
+ console.log(chalk.gray(` → npm install -g ${spec}${limit > 0 ? `(上限 ${limit / 1000}s)` : '(不限时)'}`))
638
647
  try {
648
+ const opts = {
649
+ stdio: ['ignore', 'pipe', 'pipe'],
650
+ maxBuffer: 8 * 1024 * 1024,
651
+ }
652
+ if (limit > 0) opts.timeout = limit
639
653
  execSync(
640
654
  `npm install -g ${spec} --registry=${NPM_REGISTRY} --prefer-online`
641
655
  + ' --fetch-retries=1 --fetch-retry-mintimeout=3000 --fetch-retry-maxtimeout=10000',
642
- {
643
- stdio: ['ignore', 'pipe', 'pipe'],
644
- maxBuffer: 8 * 1024 * 1024,
645
- timeout: INSTALL_TIMEOUT_MS,
646
- }
656
+ opts
647
657
  )
648
658
  return { ok: true }
649
659
  } catch (err) {
650
660
  // 超时会被 execSync 杀掉(带 SIGTERM),stderr 可能是空的 —— 补一句可读的原因
651
661
  const out = `${err.stdout ?? ''}${err.stderr ?? ''}`.trim()
652
662
  if (!out && (err.killed || err.signal)) {
653
- return { ok: false, output: `安装超时(${INSTALL_TIMEOUT_MS / 1000}s 到点被终止)` }
663
+ return {
664
+ ok: false,
665
+ output: limit > 0
666
+ ? `安装超时(${limit / 1000}s 到点被终止,可用 --install-timeout=<秒> 放宽或 =0 不限时)`
667
+ : '安装被中断(信号终止)',
668
+ }
654
669
  }
655
670
  return { ok: false, output: out || String(err.message || err) }
656
671
  }
@@ -818,7 +833,9 @@ async function selfUpdateGlobal(version) {
818
833
  console.log(chalk.gray('不空等 dist-tags:每轮先探 tarball,能取到才调 npm,失败会打印原因。'))
819
834
  console.log(chalk.gray(
820
835
  `间隔 ${POLL_INTERVAL_MS / 1000}s,上限 ${POLL_TIMEOUT_MS / 1000}s`
821
- + '(可用 --poll-interval / --poll-timeout 调)。'
836
+ + '(可用 --poll-interval / --poll-timeout 调);'
837
+ + `单次安装${INSTALL_TIMEOUT_MS > 0 ? `上限 ${INSTALL_TIMEOUT_MS / 1000}s` : '不限时'}`
838
+ + '(可用 --install-timeout=<秒> 调,0 = 不限时)。'
822
839
  ))
823
840
 
824
841
  const startedAt = Date.now()
@@ -849,9 +849,11 @@ export async function runAiAgent(argv = []) {
849
849
 
850
850
  // ask_user pauses the tool loop inside the same readline session. The REPL
851
851
  // line handler is bypassed while this small wizard owns the input line.
852
- state.ctx.askUser = ({ question, options = [], allowFreeText = true }) => {
852
+ state.ctx.askUser = ({ question, options = [], allowFreeText = true, multiple = false }) => {
853
853
  const zh = !String(state.locale || '').startsWith('en')
854
854
  const safeOptions = Array.isArray(options) ? options.filter(Boolean).slice(0, 20) : []
855
+ // 多选只在真的给了选项时才有意义(与 tools.js 的归一化口径一致)
856
+ const multi = multiple === true && safeOptions.length > 0
855
857
  state.inWizard = true
856
858
  if (safeOptions.length > 0) {
857
859
  console.log(chalk.cyan(`\n${question}`))
@@ -906,11 +908,31 @@ export async function runAiAgent(argv = []) {
906
908
 
907
909
  const promptAnswer = () => {
908
910
  const hint = safeOptions.length > 0
909
- ? (allowFreeText ? (zh ? '请输入序号或直接输入回答' : 'Choose a number or type an answer') : (zh ? '请输入序号' : 'Choose a number'))
911
+ ? (multi
912
+ ? (zh ? '请输入序号(逗号分隔可多选)' : 'Choose numbers, comma-separated for multiple')
913
+ : allowFreeText ? (zh ? '请输入序号或直接输入回答' : 'Choose a number or type an answer') : (zh ? '请输入序号' : 'Choose a number'))
910
914
  : (zh ? '请输入回答' : 'Type your answer')
911
915
  rl.question(`${hint}: `, { signal: questionController.signal }, answer => {
912
916
  if (settled) return
913
917
  const trimmed = String(answer || '').trim()
918
+ if (multi) {
919
+ // 逗号分隔的序号 → 选项列表(JSON 数组字符串回给模型,与 Web 端口径一致);
920
+ // 整行不是合法序号串时,允许自由输入的话就把它当作唯一一项
921
+ const parts = trimmed.split(/[,,]/).map(part => part.trim()).filter(Boolean)
922
+ const indexes = parts.map(part => Number.parseInt(part, 10))
923
+ const allIndexes = parts.length > 0 && indexes.every((n, i) => Number.isInteger(n) && String(n) === parts[i] && n >= 1 && n <= safeOptions.length)
924
+ if (allIndexes) {
925
+ finish(JSON.stringify(indexes.map(n => safeOptions[n - 1])))
926
+ return
927
+ }
928
+ if (allowFreeText && trimmed) {
929
+ finish(JSON.stringify([trimmed]))
930
+ return
931
+ }
932
+ console.log(chalk.yellow(zh ? `请输入 1-${safeOptions.length} 之间的序号,多个用逗号分隔` : `Enter numbers from 1 to ${safeOptions.length}, comma-separated`))
933
+ promptAnswer()
934
+ return
935
+ }
914
936
  if (safeOptions.length > 0) {
915
937
  const index = Number.parseInt(trimmed, 10)
916
938
  if (Number.isInteger(index) && index >= 1 && index <= safeOptions.length) {
@@ -154,7 +154,7 @@ test('ask_user pauses a turn until the answer arrives, then continues the model
154
154
  })
155
155
 
156
156
  await new Promise(resolve => setImmediate(resolve))
157
- assert.deepEqual(asked, { question: 'Which option?', options: ['A', 'B'], allowFreeText: false })
157
+ assert.deepEqual(asked, { question: 'Which option?', options: ['A', 'B'], allowFreeText: false, multiple: false })
158
158
  assert.equal(round, 1)
159
159
  resolveAnswer('B')
160
160
 
@@ -24,7 +24,7 @@
24
24
  // - 工具内部异常一律 catch 成字符串返回,不抛给 agent 循环 ——
25
25
  // 让模型看到错误信息自己修正,而不是中断整轮对话
26
26
 
27
- import { exec, execFile } from 'node:child_process'
27
+ import { execFile, spawn } from 'node:child_process'
28
28
  import { promises as fs } from 'node:fs'
29
29
  import path from 'node:path'
30
30
  import iconv from 'iconv-lite'
@@ -45,6 +45,19 @@ const MAX_SEARCH_FILE_SIZE = 1024 * 1024 // search_text 跳过大文件(1MB)
45
45
  const CMD_TIMEOUT_DEFAULT = 120 // run_command 默认超时(秒)
46
46
  const CMD_TIMEOUT_MAX = 600 // run_command 超时上限(秒)
47
47
 
48
+ // 已知的长耗时命令(装依赖 / 构建 / 测试 / clone …)。模型不给 timeout_seconds 时
49
+ // 默认只有 120s,这类命令经常跑不完就被终止,模型再换个写法重试 —— 白等好几轮。
50
+ // 命中即直接给到上限,不再依赖模型自己判断。
51
+ const LONG_CMD_RE = /(?:^|[\s;&|(])(?:npm|pnpm|yarn|bun)\s+(?:i\b|install\b|ci\b|add\b|create\b)|(?:^|[\s;&|(])(?:npm|pnpm|yarn|bun)\s+(?:run\s+)?(?:build|test|lint|e2e|typecheck)\b|(?:^|[\s;&|(])git\s+clone\b|(?:^|[\s;&|(])pip3?\s+install\b/i
52
+
53
+ // run_command 本次执行的超时(秒)。长耗时命令即使模型给了更小的值也抬到上限 ——
54
+ // 它填小值基本都是照抄默认值,而不是"想快速失败"。
55
+ export function resolveCommandTimeout(command, requestedSeconds) {
56
+ const n = Number(requestedSeconds) || CMD_TIMEOUT_DEFAULT
57
+ const clamped = Math.max(1, Math.min(CMD_TIMEOUT_MAX, n))
58
+ return LONG_CMD_RE.test(String(command || '')) ? CMD_TIMEOUT_MAX : clamped
59
+ }
60
+
48
61
  // 目录遍历时跳过的目录名(产物/依赖/VCS)
49
62
  const SKIP_DIRS = new Set([
50
63
  'node_modules', '.git', '.svn', '.hg', 'dist', 'build', 'out',
@@ -198,6 +211,10 @@ export const TOOL_DEFINITIONS = [
198
211
  type: 'boolean',
199
212
  description: 'Whether the user may type an answer that is not one of the listed options. Defaults to true.',
200
213
  },
214
+ multiple: {
215
+ type: 'boolean',
216
+ description: 'Allow selecting several options at once. Only meaningful when options are provided. Defaults to false.',
217
+ },
201
218
  },
202
219
  required: ['question'],
203
220
  },
@@ -237,8 +254,9 @@ function decodeOutput(buf) {
237
254
  }
238
255
  }
239
256
 
240
- // 包装 exec 为 Promise,stdout/stderr 合并返回;出错(非零退出)也正常返回输出
241
- // encoding:'buffer' 拿原始字节,由 decodeOutput 决定真实编码
257
+ // 子进程执行封装:stdout/stderr 原始字节累计到结束再整体解码
258
+ // (由 decodeOutput 决定真实编码,GBK 兜底);执行中若有 onOutput 回调,
259
+ // 每来一块就推一块已解码文本 —— Web 端据此把命令输出实时推给界面。
242
260
  export function terminateCommand(child) {
243
261
  if (!child?.pid || child.exitCode !== null) return Promise.resolve()
244
262
  if (process.platform === 'win32') {
@@ -250,21 +268,56 @@ export function terminateCommand(child) {
250
268
 
251
269
  function execCommand(command, options) {
252
270
  return new Promise((resolve) => {
253
- const { signal, timeout, onChild, ...execOptions } = options
271
+ const { signal, timeout, onChild, onOutput, ...spawnOptions } = options
254
272
  let timedOut = false
273
+ let spawnError = null
274
+ const child = spawn(command, {
275
+ ...spawnOptions,
276
+ shell: true,
277
+ detached: process.platform !== 'win32',
278
+ windowsHide: true,
279
+ // stdin 直接给 EOF:命令等输入时尽快失败,不再挂在永不关闭的 stdin 管道上干等超时
280
+ stdio: ['ignore', 'pipe', 'pipe'],
281
+ })
282
+
283
+ // 原始字节缓冲上限(对应 exec 时代的 maxBuffer);超限丢最老的块,保留尾部
284
+ const MAX_BUFFER_BYTES = 32 * 1024 * 1024
285
+ const chunks = { stdout: [], stderr: [] }
286
+ const bytes = { stdout: 0, stderr: 0 }
287
+ // 实时预览用增量 UTF-8 解码。GBK 输出在预览里可能显示成乱码,
288
+ // 但最终结果仍走 decodeOutput(UTF-8 严格解码失败 → GBK 兜底),不影响回喂模型。
289
+ const decoders = { stdout: new TextDecoder('utf-8'), stderr: new TextDecoder('utf-8') }
290
+
291
+ const onChunk = (stream, buf) => {
292
+ chunks[stream].push(buf)
293
+ bytes[stream] += buf.length
294
+ while (bytes[stream] > MAX_BUFFER_BYTES && chunks[stream].length > 1) {
295
+ bytes[stream] -= chunks[stream].shift().length
296
+ }
297
+ if (typeof onOutput === 'function') {
298
+ const text = decoders[stream].decode(buf, { stream: true })
299
+ if (text) onOutput(text)
300
+ }
301
+ }
302
+ child.stdout?.on('data', (buf) => onChunk('stdout', buf))
303
+ child.stderr?.on('data', (buf) => onChunk('stderr', buf))
304
+ child.on('error', (err) => { spawnError = err })
305
+
255
306
  const abort = () => { void terminateCommand(child) }
256
- const child = exec(command, { ...execOptions, detached: process.platform !== 'win32', encoding: 'buffer' }, (err, stdout, stderr) => {
307
+ const finish = (code) => {
257
308
  clearTimeout(timer)
258
309
  signal?.removeEventListener('abort', abort)
259
310
  resolve({
260
- code: err ? (typeof err.code === 'number' ? err.code : 1) : 0,
311
+ code: typeof code === 'number' ? code : 1,
261
312
  killed: timedOut,
262
313
  cancelled: !!signal?.aborted,
263
- stdout: decodeOutput(stdout),
264
- stderr: decodeOutput(stderr),
265
- errorMessage: err && !('code' in err) ? err.message : null,
314
+ stdout: decodeOutput(Buffer.concat(chunks.stdout)),
315
+ stderr: decodeOutput(Buffer.concat(chunks.stderr)),
316
+ errorMessage: spawnError ? spawnError.message : null,
266
317
  })
267
- })
318
+ }
319
+ child.on('close', finish)
320
+
268
321
  const timer = setTimeout(() => { timedOut = true; void terminateCommand(child) }, timeout)
269
322
  timer.unref()
270
323
  signal?.addEventListener('abort', abort, { once: true })
@@ -297,8 +350,7 @@ async function toolRunCommand(args, ctx) {
297
350
  }
298
351
 
299
352
  const cwd = resolvePath(ctx, args.cwd)
300
- let timeoutSec = Number(args.timeout_seconds) || CMD_TIMEOUT_DEFAULT
301
- timeoutSec = Math.max(1, Math.min(CMD_TIMEOUT_MAX, timeoutSec))
353
+ const timeoutSec = resolveCommandTimeout(command, args.timeout_seconds)
302
354
 
303
355
  // 验证 cwd 存在,避免 exec 抛模糊错误
304
356
  try {
@@ -316,10 +368,11 @@ async function toolRunCommand(args, ctx) {
316
368
  const execOptions = {
317
369
  cwd,
318
370
  timeout: timeoutSec * 1000,
319
- maxBuffer: 32 * 1024 * 1024,
320
371
  windowsHide: true,
321
372
  onChild: ctx.onChild,
322
373
  signal: ctx.signal,
374
+ // 执行中的增量输出(Web 端推 SSE 给界面;CLI 不传,等于没有副作用)
375
+ onOutput: ctx.onOutput,
323
376
  }
324
377
  const firstEnv = await augmentEnvPath(baseEnv)
325
378
  let result = await execCommand(command, { ...execOptions, env: firstEnv })
@@ -564,7 +617,9 @@ async function toolAskUser(args, ctx) {
564
617
  ? args.options.map(option => String(option || '').trim()).filter(Boolean).slice(0, 20)
565
618
  : []
566
619
  const allowFreeText = options.length === 0 || args.allow_free_text !== false
567
- return ctx.askUser({ question, options, allowFreeText })
620
+ // 多选只在真的给了选项时才有意义
621
+ const multiple = args.multiple === true && options.length > 0
622
+ return ctx.askUser({ question, options, allowFreeText, multiple })
568
623
  }
569
624
 
570
625
  // ──────────────────────────────────────────────
@@ -19,7 +19,7 @@ import assert from 'node:assert/strict'
19
19
  import { promises as fs } from 'node:fs'
20
20
  import os from 'node:os'
21
21
  import path from 'node:path'
22
- import { TOOL_DEFINITIONS, executeTool } from './tools.js'
22
+ import { TOOL_DEFINITIONS, executeTool, resolveCommandTimeout } from './tools.js'
23
23
 
24
24
  let tmpDir
25
25
  const ctx = { cwd: null, onChild: null }
@@ -30,6 +30,7 @@ test('ask_user schema and arguments support options plus free text', async () =>
30
30
  assert.deepEqual(definition.function.parameters.required, ['question'])
31
31
  assert.ok(definition.function.parameters.properties.options)
32
32
  assert.ok(definition.function.parameters.properties.allow_free_text)
33
+ assert.ok(definition.function.parameters.properties.multiple)
33
34
 
34
35
  let received
35
36
  const result = await executeTool('ask_user', {
@@ -48,9 +49,19 @@ test('ask_user schema and arguments support options plus free text', async () =>
48
49
  question: 'Which path should I take?',
49
50
  options: ['Fast', '42'],
50
51
  allowFreeText: false,
52
+ multiple: false,
51
53
  })
52
54
  })
53
55
 
56
+ test('ask_user 把 multiple 透传给交互回调,没有选项时强制单选', async () => {
57
+ const seen = []
58
+ const askUser = async value => { seen.push(value); return 'x' }
59
+ await executeTool('ask_user', { question: '选几个?', options: ['A', 'B'], multiple: true }, { ...ctx, askUser })
60
+ await executeTool('ask_user', { question: '随便说', multiple: true }, { ...ctx, askUser })
61
+ assert.equal(seen[0].multiple, true)
62
+ assert.equal(seen[1].multiple, false, '没有选项时多选无意义')
63
+ })
64
+
54
65
  test('ask_user returns a useful error when no interactive callback exists', async () => {
55
66
  const result = await executeTool('ask_user', { question: 'Continue?' }, ctx)
56
67
  assert.match(result, /ask_user is unavailable/)
@@ -260,6 +271,40 @@ test('run_command 本地化错误消息解码正确(Windows GBK 回归)', async
260
271
  }
261
272
  })
262
273
 
274
+ // ========== run_command: 实时输出 + 超时选择 ==========
275
+
276
+ test('run_command 执行期间通过 onOutput 增量回传输出(命令结束前就能拿到)', async () => {
277
+ const chunks = []
278
+ let returned = false
279
+ const pending = executeTool('run_command', {
280
+ command: 'node -e "console.log(\'live-1\'); setTimeout(()=>console.log(\'live-2\'), 600)"',
281
+ }, { ...ctx, onOutput: text => chunks.push(text) }).then(r => { returned = true; return r })
282
+
283
+ const deadline = Date.now() + 5000
284
+ while (!chunks.join('').includes('live-1') && Date.now() < deadline) {
285
+ await new Promise(r => setTimeout(r, 20))
286
+ }
287
+ assert.match(chunks.join(''), /live-1/, '命令还在跑时就该收到第一行输出')
288
+ assert.equal(returned, false, '此时 run_command 不应已返回')
289
+
290
+ const result = await pending
291
+ assert.match(result, /live-1/)
292
+ assert.match(result, /live-2/)
293
+ })
294
+
295
+ test('resolveCommandTimeout: 长耗时命令抬到上限,普通命令保持默认 / 模型给的值', () => {
296
+ // 安装 / 构建 / clone 这类命令:模型不给够超时容易被 120s 杀掉再重试
297
+ assert.equal(resolveCommandTimeout('npm install', undefined), 600)
298
+ assert.equal(resolveCommandTimeout('npm i --save-dev vite', undefined), 600)
299
+ assert.equal(resolveCommandTimeout('pnpm install && npm run build', 60), 600)
300
+ assert.equal(resolveCommandTimeout('git clone git@github.com:a/b.git', undefined), 600)
301
+ // 普通命令不动
302
+ assert.equal(resolveCommandTimeout('echo hi', undefined), 120)
303
+ assert.equal(resolveCommandTimeout('echo hi', 30), 30)
304
+ // 起服务这类命令不抬:它本来就不该等到超时
305
+ assert.equal(resolveCommandTimeout('npm run dev', 60), 60)
306
+ })
307
+
263
308
  // ========== list_projects: 只在 GUI 里有实现,CLI 下要给一句能照着做的话 ==========
264
309
 
265
310
  test('list_projects 把参数透传给注入的实现', async () => {
package/src/config.js CHANGED
@@ -73,9 +73,9 @@ function normalizeAiMaxToolIterations(value) {
73
73
  return int;
74
74
  }
75
75
 
76
- // 工作台任务执行器白名单。'claude' 是历史默认;'opencode' 为可选执行器
77
- // (opencode run --format json,模型跟随 opencode 自身配置)。
78
- export const TASK_EXECUTORS = ['claude', 'opencode'];
76
+ // 工作台任务执行器白名单。'claude' 是历史默认;'opencode' / 'codex' 为可选执行器
77
+ // (opencode run --format json / codex exec --json,模型都跟随各自 CLI 的配置)。
78
+ export const TASK_EXECUTORS = ['claude', 'opencode', 'codex'];
79
79
 
80
80
  /**
81
81
  * 规范化任务执行器。非法值返回 null(交给调用方取默认),不抛错 ——
@@ -143,7 +143,7 @@ const defaultConfig = {
143
143
  // 触顶后本轮被强制结束,用户必须再发一条消息才能接着跑,体感像被截断。
144
144
  // 想调小/调大改这个值即可(GUI: 设置 → AI 模型配置)。
145
145
  aiMaxToolIterations: 200,
146
- // 工作台任务执行器(claude | opencode)。全局配置,跨项目共享。
146
+ // 工作台任务执行器(claude | opencode | codex)。全局配置,跨项目共享。
147
147
  // 决定「执行任务 / 执行子任务 / 从此处开始 / 简单任务续聊」这条链路
148
148
  // 默认 spawn 哪个本地 CLI;执行入口可以按次覆盖(见 workbench 执行路由)。
149
149
  taskExecutor: 'claude',
@@ -163,6 +163,10 @@ const defaultConfig = {
163
163
  splitPercent: 25, // 15-85
164
164
  },
165
165
  editorAutoSave: false,
166
+ // 顶栏工具图标(VSCode / Claude Code / Codex / …)中**隐藏**的那几个。
167
+ // 白名单式的默认空数组:以后新增工具默认就固定显示,不需要回头改默认值。
168
+ // 未勾选(= 落在本数组里)的工具连同未安装的一起收进顶栏右侧「更多」菜单。
169
+ headerToolsHidden: [],
166
170
  }
167
171
  };
168
172
 
package/src/gitCommit.js CHANGED
@@ -17,7 +17,8 @@
17
17
  import {
18
18
  coloredLog, errorLog, execGitCommand, showHelp,
19
19
  getCwd, judgePlatform, judgeLog, judgeHelp, exec_exit, judgeUnmerged, formatDuration,
20
- exec_push, execPull, judgeRemote, execDiff, execAddAndCommit, delay, addScriptToPackageJson, addResetScriptToPackageJson
20
+ exec_push, execPull, judgeRemote, execDiff, execAddAndCommit, delay, addScriptToPackageJson, addResetScriptToPackageJson,
21
+ parseCwdArg, invalidateCwdCache
21
22
  } from './utils/index.js';
22
23
  import readline from 'readline'
23
24
  import ora from 'ora';
@@ -258,6 +259,22 @@ async function main() {
258
259
 
259
260
  // 检查是否是UI命令
260
261
  if (process.argv.includes('ui')) {
262
+ // `g ui --path=<目录>`:资源管理器右键菜单写进注册表的命令就是
263
+ // node <pkg>/src/gitCommit.js ui --path="%V"
264
+ // (%V = 被右键的目录,由 Explorer 展开)。先切到目标目录再起服务端 ——
265
+ // server 用 process.cwd() 当"当前项目",这样浏览器打开的就是右键的那个仓库。
266
+ // 路径带空格时命令行里的引号会被 Windows 的 argv 解析吞掉(node 实测),这里拿到
267
+ // 的已是干净路径。切目录失败只警告、不阻断,否则目录被删就整个 GUI 起不来。
268
+ const uiPath = parseCwdArg(process.argv);
269
+ if (uiPath) {
270
+ try {
271
+ process.chdir(uiPath);
272
+ invalidateCwdCache(); // getCwd() 缓存的是"启动时的目录"语义,换目录后必须失效
273
+ } catch (error) {
274
+ console.warn(chalk.yellow(`⚠️ 无法切换到目录 ${uiPath},仍从 ${process.cwd()} 启动: ${error.message}`));
275
+ }
276
+ }
277
+
261
278
  const startUIServer = await loadStartUIServer();
262
279
  await startUIServer(false, false); // 传入noOpen=false, savePort=false
263
280
  return;
@@ -0,0 +1,5 @@
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,cr as O,ct as k,et as ee,fr as A,gn as j,i as M,in as te,j as N,kt as ne,mt as P,ot as F,pt as I,qr as L,r as R,sr as z,tr as B,un as V,wn as H,wt as re,yn as U,yr as W,zn as G}from"./element-plus-DxBPQwL7.js";import{i as ie,o as K,r as q}from"./vendor-bdHhLiED.js";import{n as J,t as Y}from"./_plugin-vue_export-helper-dg2VUnSQ.js";import{t as X}from"./configStore-DtjAc3w9.js";G(),A();var Z=65536,Q=`local-`;function ae(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:se(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:$(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>Z&&(e=`…(前文已截断)\n${e.slice(-65536)}`),n.result=e}}s++}r=s-1,a.length>Z&&(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 $(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 oe(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 se(e){let t=/^data:([^;,]+)/.exec(e);return t?t[1]:``}function ce(){let e=X(),t=W([]),n=W(!1),r=w(new Map),i=W(null),a=W(!1),o=0,s=0;function c(e){return{key:e,sessionId:e.startsWith(Q)?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=H(()=>i.value?r.get(i.value)??null:null),d=H(()=>u.value?.messages??[]),f=H(()=>u.value?.isStreaming??!1),p=H(()=>u.value?.pendingQuestion??null),m=H(()=>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||J(`@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||J(`@AGENT:加载会话列表失败`));return}let a=Array.isArray(n.sessions)?n.sessions:[];t.value=g(a)}catch(e){if(r!==o)return;M.error(J(`@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||J(`@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||J(`@AGENT:加载会话失败`));return}let n=l(e);n.sessionId=e,n.messages=ae(t.session),t.session?.title&&(n.title=t.session.title)}catch(e){M.error(J(`@AGENT:加载会话失败`)+`: `+(e?.message||e))}finally{a.value=!1}}async function x(e){try{await R.confirm(J(`@AGENT:确认删除该会话`),J(`@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||J(`@AGENT:删除失败`));return}t.value=t.value.filter(t=>t.sessionId!==e),i.value===e&&(i.value=null),M.success(J(`@AGENT:已删除`))}catch(e){M.error(J(`@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||J(`@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(J(`@AGENT:已重命名`))}catch(e){M.error(J(`@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(J(`@AGENT:仅支持发送图片,非图片文件已忽略`));let o=l(i.value||`${Q}${Date.now()}-${++s}`);if(!t.trim()&&a.length===0||o.isStreaming)return;let c=(await Promise.allSettled(a.map(e=>oe(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)||J(`@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=q(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>Z?`…(前文已截断)\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,multiple:s.multiple===!0};break;case`done`:{let e=s.content||p.content,t=q(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||J(`@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
+ [`+J(`@AGENT:已停止`)+`]`,p.status=`done`,p.reasoningStatus===`streaming`&&(p.reasoningStatus=`done`)):(p.status=`error`,p.error=e?.message||String(e),M.error(p.error||J(`@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=(Array.isArray(e)?e:[e]).map(e=>String(e??``).trim()).filter(Boolean);if(!t||!n||!r||!i.length||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:n.multiple?i:i[0]})}).then(e=>e.json());if(!e.success)throw Error(e.error||J(`@AGENT:回答提交失败`));return t.pendingQuestion=null,!0}catch(e){return M.error(e?.message||J(`@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}}G(),A();var le=o({__name:`MarketplacePanel`,props:{type:{type:String,required:!0}},setup(e,{expose:t}){t();let n=e,r=X(),i=W([]),a=W([]),o=W(!1),s=W(``),l=W(``),u=W([]),d=W(`project`),f=W(new Set),m=W(new Set),h=H(()=>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||J(`@MKT:加载失败`))}catch{M.error(J(`@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=H(()=>{let e=h.value?h.value.split(/[\\/]/).filter(Boolean).pop():``;return d.value===`project`?e||J(`@MKT:当前项目`):J(`@MKT:g ai 智能体`)});function y(e){return e.stars?`${S(e.stars)} ★`:e.downloads?`${S(e.downloads)} ${J(`@MKT:周下载`)}`:e.uses?`${S(e.uses)} ${J(`@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=H(()=>{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 A(e){return n.type===`mcp`&&(!!e.envKeys?.length||!!e.args?.length)}function j(e){O.item=e,O.env=Object.fromEntries((e.envKeys||[]).map(e=>[e,``])),O.args=(e.args||[]).join(` `),O.visible=!0}function N(){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 ne(e){if(!e.installed||await F(e)){if(A(e)){j(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||J(`@MKT:安装失败`));return}i.item?.warning&&M.warning(i.item.warning),i.item?.envKeys?.length?M.warning(`${J(`@MKT:还缺环境变量`)}: ${i.item.envKeys.join(`, `)}`):M.success(J(`@MKT:安装成功`)),await _()}catch{M.error(J(`@MKT:安装失败`))}finally{f.value.delete(r)}}async function F(e){try{return await R.confirm(`${e.name} ${J(`@MKT:已安装,要重新安装吗?`)}`,J(`@MKT:重新安装`),{confirmButtonText:J(`@MKT:重装`),cancelButtonText:J(`@MKT:取消`),type:`warning`}),!0}catch{return!1}}async function L(e){try{await R.confirm(`${J(`@MKT:确定卸载`)} ${e.name}?`,J(`@MKT:卸载`),{confirmButtonText:J(`@MKT:卸载`),cancelButtonText:J(`@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||J(`@MKT:卸载失败`));return}M.success(J(`@MKT:已卸载`)),await _()}catch{M.error(J(`@MKT:卸载失败`))}finally{m.value.delete(t)}}let z={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:A,openConfigDialog:j,confirmConfig:N,onInstall:ne,doInstall:P,confirmReinstall:F,onRemove:L,get $t(){return J},get Search(){return x},get Refresh(){return b},get Delete(){return k},get Link(){return p},get Check(){return ee},get Star(){return c},get Download(){return I},get Warning(){return te}};return Object.defineProperty(z,"__isScriptSetup",{enumerable:!1,value:!0}),z}});G(),V(),m();var ue={class:`marketplace-panel`},de={class:`mp-toolbar`},fe={class:`mp-search`},pe=[`placeholder`],me={class:`mp-toolbar-sub`},he={class:`mp-target-hint`},ge={class:`mp-source-filter`},_e=[`onClick`],ve={class:`mp-body`},ye={class:`mp-group-header`},be={class:`mp-group-title`},xe={key:0,class:`mp-group-count`},Se={key:1,class:`mp-group-error`},Ce=[`href`,`title`],we={key:0,class:`mp-grid`},Te={class:`mp-card-head`},Ee=[`title`],De={key:0,class:`mp-card-metric`},Oe=[`title`],ke={class:`mp-card-meta`},Ae=[`title`],je=[`title`],Me={key:2,class:`mp-tag remote`},Ne={class:`mp-card-foot`},Pe=[`href`],Fe={key:1,class:`mp-installed-chip`},Ie=[`disabled`,`onClick`],Le={key:3,class:`mp-not-installable`},Re={key:1,class:`mp-empty`},ze={key:0,class:`mp-group installed`},Be={class:`mp-group-header`},Ve={class:`mp-group-title`},He={class:`mp-group-count`},Ue={key:0,class:`mp-installed-block`},We={class:`mp-installed-target`},Ge={class:`mp-installed-list`},Ke={class:`mp-installed-name`},qe={key:0,class:`mp-meta-pkg`},Je={key:1,class:`mp-tag warn`},Ye=[`disabled`,`onClick`],Xe={key:1,class:`mp-empty all`},Ze={key:0,class:`mkt-form`},Qe={class:`mkt-form-name`},$e=[`onUpdate:modelValue`,`placeholder`],et={key:0,class:`mkt-field`},tt={class:`mkt-hint`};function nt(e,o,c,p,m,h){let _=l,y=n,b=N,x=s,C=i,w=T;return S(),f(`div`,ue,[r(` ── 工具栏 ───────────────────────────────── `),v(`div`,de,[v(`div`,fe,[d(_,{class:`mp-search-icon`},{default:z(()=>[d(p.Search)]),_:1}),O(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,pe),[[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`,me,[v(`span`,he,[u(t(p.$t(`@MKT:安装到`))+` `,1),v(`b`,null,t(p.targetLabel),1)]),v(`div`,ge,[(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,_e))),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(` ── 内容 ─────────────────────────────────── `),O((S(),f(`div`,ve,[(S(!0),f(D,null,g(p.groups,e=>(S(),f(`section`,{key:e.id,class:`mp-group`},[v(`header`,ye,[v(`h3`,be,t(e.label),1),e.status===`ok`?(S(),f(`span`,xe,t(e.items.length),1)):(S(),f(`span`,Se,[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,Ce)):r(`v-if`,!0)]),e.status===`ok`&&e.items.length?(S(),f(`div`,we,[(S(!0),f(D,null,g(e.items,e=>(S(),f(`article`,{key:p.cardKey(e),class:`mp-card`},[v(`div`,Te,[v(`span`,{class:`mp-card-name`,title:e.name},t(e.name),9,Ee),p.metricText(e)?(S(),f(`span`,De,[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,Oe),v(`div`,ke,[e.package?(S(),f(`code`,{key:0,class:`mp-meta-pkg`,title:e.package},t(e.package),9,Ae)):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,je)):r(`v-if`,!0),e.transport===`remote`?(S(),f(`span`,Me,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`,Ne,[e.upstream?(S(),f(`a`,{key:0,class:`mp-card-link`,href:e.upstream,target:`_blank`,rel:`noopener noreferrer`},t(p.$t(`@MKT:查看来源`)),9,Pe)):r(`v-if`,!0),o[6]||=v(`span`,{class:`mp-foot-spacer`},null,-1),e.installed?(S(),f(`span`,Fe,[d(_,null,{default:z(()=>[d(p.Check)]),_:1}),u(t(p.$t(`@MKT:已安装`)),1)])):e.installable===!1?(S(),f(`span`,Le,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,Ie))])]))),128))])):e.status===`ok`?(S(),f(`div`,Re,t(p.$t(`@MKT:该来源暂无结果`)),1)):r(`v-if`,!0)]))),128)),r(` ── 已安装 ─────────────────────────────── `),p.installed.length?(S(),f(`section`,ze,[v(`header`,Be,[v(`h3`,Ve,t(p.$t(`@MKT:已安装`)),1),v(`span`,He,t(p.installed.length),1)]),(S(),f(D,null,g([`project`,`global`],e=>v(`div`,{key:e},[p.installedByTarget[e]?.length?(S(),f(`div`,Ue,[v(`div`,We,t(e===`project`?p.$t(`@MKT:当前项目`):p.$t(`@MKT:g ai 智能体`)),1),v(`div`,Ge,[(S(!0),f(D,null,g(p.installedByTarget[e],n=>(S(),f(`div`,{key:e+n.id,class:`mp-installed-row`},[v(`span`,Ke,t(n.name),1),n.package?(S(),f(`code`,qe,t(n.package),1)):r(`v-if`,!0),n.requiredEnv?.length?(S(),f(`span`,Je,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,Ye)]))),128))])])):r(`v-if`,!0)])),64))])):r(`v-if`,!0),!p.loading&&!p.groups.length?(S(),f(`div`,Xe,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`,Ze,[v(`p`,Qe,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),O(v(`input`,{"onUpdate:modelValue":t=>p.configDialog.env[e]=t,type:`text`,autocomplete:`off`,placeholder:p.$t(`@MKT:环境变量值`),spellcheck:`false`},null,8,$e),[[j,p.configDialog.env[e]]])]))),128)),p.configDialog.item.args?.length?(S(),f(`div`,et,[v(`label`,null,t(p.$t(`@MKT:启动参数`)),1),O(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`,tt,t(p.$t(`@MKT:参数提示`)),1)])):r(`v-if`,!0)])):r(`v-if`,!0)]),_:1},8,[`modelValue`,`title`])])}var rt=Y(le,[[`render`,nt],[`__scopeId`,`data-v-e9f9e851`],[`__file`,`D:/workspace/github_workspace/zen-gitsync/src/ui/client/src/components/MarketplacePanel.vue`]]);G(),A();var it=o({__name:`AgentView`,setup(t,{expose:n}){n();let r=X(),i=W(`chat`),a=H(()=>i.value===`mcp`?`mcp`:`skill`),o=H(()=>[{id:`chat`,label:J(`@AGENT:对话`),icon:h},{id:`skill`,label:J(`@AGENT:Skill 广场`),icon:re},{id:`mcp`,label:J(`@AGENT:MCP 广场`),icon:F}]),{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:ee,stop:A}=ce(),j=H(()=>{let e=r.theme;return e===`dark`||e===`auto`&&window.matchMedia(`(prefers-color-scheme: dark)`).matches?`dark`:`light`}),M=W(``),te=H(()=>{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=H(()=>[{id:`p1`,label:J(`@AGENT:查看项目结构`),prompt:J(`@AGENT:prompt_p1`)},{id:`p2`,label:J(`@AGENT:分析代码质量`),prompt:J(`@AGENT:prompt_p2`)},{id:`p3`,label:J(`@AGENT:帮我写测试`),prompt:J(`@AGENT:prompt_p3`)},{id:`p4`,label:J(`@AGENT:Git 状态检查`),prompt:J(`@AGENT:prompt_p4`)},{id:`p5`,label:J(`@AGENT:帮我启动项目`),prompt:J(`@AGENT:prompt_p5`)}]);async function I(e){await w(e.text,e.files),await y(),V()}async function L(e){await w(e.prompt),await y(),V()}let z=H(()=>({title:J(`@AGENT:等待你的回答`),placeholder:J(`@AGENT:输入回答`),submit:J(`@AGENT:提交回答`)})),B=W(null);function V(e=!0){B.value?.scrollToBottom(e)}E(()=>f.value.length,()=>{y(()=>V(!1))});function U(e){v(e)}function G(){C()}function K(e,t){t.stopPropagation(),b(e)}async function q(e,t,n){n.stopPropagation();try{let{value:n}=await R.prompt(J(`@AGENT:请输入新的会话标题`),J(`@AGENT:重命名会话`),{inputValue:t,inputPattern:/.+/,inputErrorMessage:J(`@AGENT:标题不能为空`)});n&&n!==t&&await S(e,n)}catch{}}function Y(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?J(`@AGENT:今天`):`${e}${J(`@AGENT:天前`)}`}return`${t.getFullYear()}-${i(t.getMonth()+1)}-${i(t.getDate())}`}catch{return e}}let Z=W(280),Q=W(!1);function ae(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:ee,stop:A,chatTheme:j,searchQuery:M,filteredSessions:te,presetQuestions:N,onSend:I,onSelectPreset:L,questionLabels:z,chatContainerRef:B,scrollToBottom:V,selectSession:U,handleNewSession:G,handleDelete:K,handleRename:q,formatDate:Y,sidebarWidth:Z,isResizing:Q,startResize:ae,get $t(){return J},get ElTooltip(){return s},get ElIcon(){return l},get Plus(){return _},get Search(){return x},get Delete(){return k},get Edit(){return P},get ChatLineRound(){return e},get Loading(){return ne},get ChatContainer(){return ie},MarketplacePanel:rt};return Object.defineProperty($,"__isScriptSetup",{enumerable:!1,value:!0}),$}});G(),m(),V();var at={class:`agent-view`},ot={class:`sidebar-header`},st={class:`sidebar-search`},ct=[`placeholder`],lt={class:`session-list`},ut={key:0,class:`empty-state`},dt={class:`empty-text`},ft={key:0,class:`empty-hint`},pt=[`onClick`],mt={class:`session-item-main`},ht={class:`session-item-title`},gt={class:`session-item-meta`},_t={key:0,class:`meta-generating`},vt={class:`meta-time`},yt={class:`meta-count`},bt={key:2,class:`meta-source cli`},xt=[`onClick`],St=[`onClick`],Ct={class:`agent-chat-area`},wt={class:`agent-tabs`,role:`tablist`},Tt=[`aria-selected`,`onClick`],Et={class:`agent-tab-body`},Dt={key:0,class:`agent-chat-pane`},Ot={key:0,class:`chat-loading`};function kt(e,n,i,o,s,c){let l=T;return S(),f(`div`,at,[r(` ═══ 左侧:会话列表(只在「对话」Tab 显示)═══ `),o.activeTab===`chat`?(S(),f(D,{key:0},[v(`aside`,{class:`agent-sidebar`,style:C({width:o.sidebarWidth+`px`})},[r(` 顶部操作栏 `),v(`div`,ot,[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`,st,[d(o.ElIcon,{class:`search-icon`},{default:z(()=>[d(o.Search)]),_:1}),O(v(`input`,{"onUpdate:modelValue":n[0]||=e=>o.searchQuery=e,placeholder:o.$t(`@AGENT:搜索会话...`),class:`search-input`,type:`text`},null,8,ct),[[j,o.searchQuery]])]),r(` 会话列表 `),O((S(),f(`div`,lt,[o.filteredSessions.length===0&&!o.sessionsLoading?(S(),f(`div`,ut,[d(o.ElIcon,{size:28,color:`var(--text-tertiary)`},{default:z(()=>[d(o.ChatLineRound)]),_:1}),v(`div`,dt,t(o.searchQuery?o.$t(`@AGENT:未找到匹配的会话`):o.$t(`@AGENT:暂无会话`)),1),o.searchQuery?r(`v-if`,!0):(S(),f(`div`,ft,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`,mt,[v(`div`,ht,t(e.title||o.$t(`@AGENT:无标题`)),1),v(`div`,gt,[e.isGenerating||o.isSessionGenerating(e.sessionId)?(S(),f(`span`,_t,[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`,vt,t(o.formatDate(e.updatedAt)),1),n[2]||=v(`span`,{class:`meta-dot`},`·`,-1),v(`span`,yt,t(e.messageCount)+` `+t(o.$t(`@AGENT:条`)),1)],64)),e.source===`cli`?(S(),f(`span`,bt,`CLI`)):r(`v-if`,!0)])]),v(`div`,{class:`session-item-actions`,onClick:n[1]||=U(()=>{},[`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,xt)]),_: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,St)]),_:2},1032,[`content`])])],10,pt))),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`,Ct,[v(`nav`,wt,[(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(B(e.icon)))]),_:2},1024),v(`span`,null,t(e.label),1)],10,Tt))),128))]),v(`div`,Et,[r(` ── 对话 ── `),o.activeTab===`chat`?(S(),f(`div`,Dt,[r(` 加载中 `),o.sessionLoading?(S(),f(`div`,Ot,[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,generating:o.isStreaming,"upload-config":{accept:`image/*`},placeholder:o.isStreaming?o.$t(`@AGENT:正在生成中...`):o.$t(`@AGENT:输入消息,Enter 发送`),question:o.pendingQuestion,"question-submitting":o.answeringQuestion,"question-labels":o.questionLabels,onSend:o.onSend,onSelect:o.onSelectPreset,onStop:o.stop,onAnswer:o.answerQuestion},null,8,[`messages`,`preset-questions`,`welcome-title`,`welcome-description`,`theme`,`disabled`,`generating`,`placeholder`,`question`,`question-submitting`,`question-labels`,`onStop`,`onAnswer`])],2112))])):(S(),f(D,{key:1},[r(` ── Skill 广场 / MCP 广场 ── `),d(o.MarketplacePanel,{type:o.marketplaceType},null,8,[`type`])],2112))])])])}var At=Y(it,[[`render`,kt],[`__scopeId`,`data-v-bd681ddd`],[`__file`,`D:/workspace/github_workspace/zen-gitsync/src/ui/client/src/views/AgentView.vue`]]);export{At as default};
@@ -1 +1 @@
1
- .marketplace-panel[data-v-e9f9e851]{background:var(--bg-container);flex-direction:column;height:100%;min-height:0;display:flex}.mp-toolbar[data-v-e9f9e851]{flex-shrink:0;align-items:center;gap:12px;padding:12px 16px 8px;display:flex}.mp-search[data-v-e9f9e851]{border:1px solid var(--border-color);border-radius:var(--radius-md);background:var(--bg-panel);flex:1;align-items:center;gap:6px;max-width:420px;height:32px;padding:0 10px;transition:border-color .15s;display:flex}.mp-search[data-v-e9f9e851]:focus-within{border-color:var(--color-primary)}.mp-search .mp-search-icon[data-v-e9f9e851]{color:var(--text-tertiary);flex-shrink:0}.mp-search .mp-search-input[data-v-e9f9e851]{color:var(--text-primary);background:0 0;border:none;outline:none;flex:1;font-family:inherit;font-size:13px}.mp-search .mp-search-input[data-v-e9f9e851]::placeholder{color:var(--text-tertiary)}.mp-target[data-v-e9f9e851]{flex-shrink:0}.mp-refresh[data-v-e9f9e851]{border:1px solid var(--border-color);border-radius:var(--radius-md);background:var(--bg-panel);width:30px;height:30px;color:var(--text-secondary);cursor:pointer;justify-content:center;align-items:center;transition:all .15s;display:flex}.mp-refresh[data-v-e9f9e851]:hover{color:var(--color-primary);border-color:var(--color-primary)}.mp-refresh.spinning svg[data-v-e9f9e851]{animation:.9s linear infinite mkt-spin-e9f9e851}@keyframes mkt-spin-e9f9e851{to{transform:rotate(360deg)}}.mp-toolbar-sub[data-v-e9f9e851]{flex-wrap:wrap;flex-shrink:0;align-items:center;gap:12px;padding:0 16px 10px;display:flex}.mp-target-hint[data-v-e9f9e851]{color:var(--text-tertiary);font-size:12px}.mp-target-hint b[data-v-e9f9e851]{color:var(--color-primary);font-weight:600}.mp-source-filter[data-v-e9f9e851]{flex-wrap:wrap;align-items:center;gap:6px;display:flex}.mp-chip[data-v-e9f9e851]{border:1px solid var(--border-color);color:var(--text-tertiary);cursor:pointer;background:0 0;border-radius:12px;padding:2px 10px;font-family:inherit;font-size:12px;transition:all .15s}.mp-chip[data-v-e9f9e851]:hover{color:var(--text-secondary);border-color:var(--text-tertiary)}.mp-chip.active[data-v-e9f9e851]{color:var(--color-primary);border-color:var(--color-primary);background:color-mix(in srgb, var(--color-primary) 8%, transparent)}.mp-chip.clear[data-v-e9f9e851]{color:var(--text-tertiary);border-style:dashed}.mp-body[data-v-e9f9e851]{flex:1;min-height:0;padding:0 16px 20px;overflow-y:auto}.mp-group[data-v-e9f9e851]{margin-bottom:20px}.mp-group.installed[data-v-e9f9e851]{border-top:1px dashed var(--border-color);padding-top:14px}.mp-group-header[data-v-e9f9e851]{align-items:center;gap:8px;margin-bottom:10px;display:flex}.mp-group-title[data-v-e9f9e851]{color:var(--text-primary);margin:0;font-size:13px;font-weight:600}.mp-group-count[data-v-e9f9e851]{background:var(--bg-hover);min-width:20px;height:18px;color:var(--text-tertiary);border-radius:9px;justify-content:center;align-items:center;padding:0 6px;font-size:11px;display:inline-flex}.mp-group-error[data-v-e9f9e851]{color:var(--color-warning);align-items:center;gap:4px;font-size:12px;display:inline-flex}.mp-group-link[data-v-e9f9e851]{color:var(--text-tertiary);transition:color .15s;display:inline-flex}.mp-group-link[data-v-e9f9e851]:hover{color:var(--color-primary)}.mp-grid[data-v-e9f9e851]{grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:10px;display:grid}.mp-card[data-v-e9f9e851]{border:1px solid var(--border-color);border-radius:var(--radius-md);background:var(--bg-panel);flex-direction:column;gap:6px;padding:12px;transition:border-color .15s,box-shadow .15s;display:flex}.mp-card[data-v-e9f9e851]:hover{border-color:color-mix(in srgb, var(--color-primary) 40%, var(--border-color));box-shadow:var(--shadow-sm)}.mp-card-head[data-v-e9f9e851]{align-items:center;gap:8px;display:flex}.mp-card-name[data-v-e9f9e851]{min-width:0;color:var(--text-primary);white-space:nowrap;text-overflow:ellipsis;flex:1;font-size:13px;font-weight:600;overflow:hidden}.mp-card-metric[data-v-e9f9e851]{color:var(--text-tertiary);flex-shrink:0;align-items:center;gap:3px;font-size:11px;display:inline-flex}.mp-card-desc[data-v-e9f9e851]{color:var(--text-secondary);-webkit-line-clamp:2;-webkit-box-orient:vertical;min-height:36px;margin:0;font-size:12px;line-height:1.5;display:-webkit-box;overflow:hidden}.mp-card-meta[data-v-e9f9e851]{flex-wrap:wrap;align-items:center;gap:6px;min-height:18px;display:flex}.mp-meta-pkg[data-v-e9f9e851],.mp-meta-repo[data-v-e9f9e851]{color:var(--text-tertiary);white-space:nowrap;text-overflow:ellipsis;max-width:220px;font-size:11px;overflow:hidden}.mp-tag[data-v-e9f9e851]{background:var(--bg-hover);color:var(--text-tertiary);border-radius:8px;flex-shrink:0;padding:1px 6px;font-size:10px}.mp-tag.remote[data-v-e9f9e851]{background:color-mix(in srgb, var(--color-info,#06b6d4) 14%, transparent);color:var(--color-info,#06b6d4)}.mp-tag.warn[data-v-e9f9e851]{background:color-mix(in srgb, var(--color-warning) 14%, transparent);color:var(--color-warning)}.mp-card-foot[data-v-e9f9e851]{align-items:center;gap:8px;margin-top:2px;display:flex}.mp-card-link[data-v-e9f9e851]{color:var(--text-tertiary);font-size:11px;text-decoration:none}.mp-card-link[data-v-e9f9e851]:hover{color:var(--color-primary);text-decoration:underline}.mp-foot-spacer[data-v-e9f9e851]{flex:1}.mp-install-btn[data-v-e9f9e851]{border:1px solid var(--color-primary);border-radius:var(--radius-sm);color:var(--color-primary);cursor:pointer;background:0 0;padding:4px 14px;font-family:inherit;font-size:12px;transition:all .15s}.mp-install-btn[data-v-e9f9e851]:hover:not(:disabled){background:var(--color-primary);color:#fff}.mp-install-btn[data-v-e9f9e851]:disabled{opacity:.5;cursor:not-allowed}.mp-installed-chip[data-v-e9f9e851]{color:var(--color-success,#34d399);align-items:center;gap:3px;font-size:11px;display:inline-flex}.mp-not-installable[data-v-e9f9e851]{color:var(--text-tertiary);font-size:11px}.mp-empty[data-v-e9f9e851]{color:var(--text-tertiary);padding:16px 0;font-size:12px}.mp-empty.all[data-v-e9f9e851]{text-align:center;padding:48px 0}.mp-installed-block[data-v-e9f9e851]{margin-bottom:12px}.mp-installed-target[data-v-e9f9e851]{color:var(--text-tertiary);text-transform:uppercase;letter-spacing:.4px;margin-bottom:6px;font-size:11px;font-weight:600}.mp-installed-list[data-v-e9f9e851]{flex-direction:column;gap:4px;display:flex}.mp-installed-row[data-v-e9f9e851]{border:1px solid var(--border-color);border-radius:var(--radius-sm);background:var(--bg-panel);align-items:center;gap:10px;padding:6px 10px;display:flex}.mp-installed-name[data-v-e9f9e851]{color:var(--text-primary);white-space:nowrap;text-overflow:ellipsis;font-size:12px;font-weight:500;overflow:hidden}.mp-remove-btn[data-v-e9f9e851]{border:1px solid var(--border-color);border-radius:var(--radius-xs);color:var(--text-tertiary);cursor:pointer;background:0 0;align-items:center;gap:4px;padding:3px 10px;font-family:inherit;font-size:11px;transition:all .15s;display:inline-flex}.mp-remove-btn[data-v-e9f9e851]:hover:not(:disabled){color:var(--color-danger);border-color:var(--color-danger)}.mp-remove-btn[data-v-e9f9e851]:disabled{opacity:.5;cursor:not-allowed}@media (prefers-reduced-motion:reduce){.mp-refresh.spinning svg[data-v-e9f9e851]{animation:none}}.mkt-form[data-v-e9f9e851]{flex-direction:column;gap:12px;display:flex}.mkt-form-name[data-v-e9f9e851]{color:var(--text-primary);margin:0;font-size:13px;font-weight:600}.mkt-field[data-v-e9f9e851]{flex-direction:column;gap:4px;display:flex}.mkt-field label[data-v-e9f9e851]{color:var(--text-secondary);font-size:12px;font-weight:600}.mkt-field input[data-v-e9f9e851]{border:1px solid var(--border-color);background:var(--bg-container);height:30px;color:var(--text-primary);border-radius:6px;padding:0 8px;font-family:inherit;font-size:13px;transition:border-color .15s}.mkt-field input[data-v-e9f9e851]:focus{border-color:var(--color-primary);outline:none}.mkt-hint[data-v-e9f9e851]{color:var(--text-tertiary);margin:0;font-size:11px}.mkt-cancel[data-v-e9f9e851],.mkt-confirm[data-v-e9f9e851]{border-radius:var(--radius-sm);cursor:pointer;padding:6px 16px;font-family:inherit;font-size:13px;transition:all .15s}.mkt-cancel[data-v-e9f9e851]{border:1px solid var(--border-color);color:var(--text-secondary);background:0 0;margin-right:8px}.mkt-cancel[data-v-e9f9e851]:hover{color:var(--text-primary);border-color:var(--text-tertiary)}.mkt-confirm[data-v-e9f9e851]{border:1px solid var(--color-primary);background:var(--color-primary);color:#fff}.mkt-confirm[data-v-e9f9e851]:hover{opacity:.9}.agent-view[data-v-bd681ddd]{background:var(--bg-container);height:100%;min-height:0;display:flex}.agent-sidebar[data-v-bd681ddd]{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-bd681ddd]{flex-shrink:0;padding:10px 12px}.new-session-btn[data-v-bd681ddd]{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-bd681ddd]:hover{border-color:var(--color-primary);color:var(--color-primary);background:color-mix(in srgb, var(--color-primary) 6%, transparent)}.sidebar-search[data-v-bd681ddd]{flex-shrink:0;align-items:center;gap:6px;padding:0 12px 8px;display:flex}.sidebar-search .search-icon[data-v-bd681ddd]{color:var(--text-tertiary);flex-shrink:0}.sidebar-search .search-input[data-v-bd681ddd]{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-bd681ddd]::placeholder{color:var(--text-tertiary)}.session-list[data-v-bd681ddd]{flex:1;min-height:0;padding:0 6px 8px;overflow-y:auto}.empty-state[data-v-bd681ddd]{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-bd681ddd]{color:var(--text-secondary);margin-top:10px;font-size:14px}.empty-state .empty-hint[data-v-bd681ddd]{margin-top:4px;font-size:12px}.session-item[data-v-bd681ddd]{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-bd681ddd]:hover{background:var(--bg-hover)}.session-item:hover .session-item-actions[data-v-bd681ddd]{opacity:1}.session-item.active[data-v-bd681ddd]{background:color-mix(in srgb, var(--color-primary) 10%, transparent)}.session-item.active .session-item-title[data-v-bd681ddd]{color:var(--color-primary)}.session-item.active[data-v-bd681ddd]: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-bd681ddd]{flex:1;min-width:0}.session-item-title[data-v-bd681ddd]{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-bd681ddd]{color:var(--text-tertiary);align-items:center;gap:4px;font-size:11px;display:flex}.session-item-meta .meta-dot[data-v-bd681ddd]{opacity:.5}.session-item-meta .meta-generating[data-v-bd681ddd]{color:var(--color-primary);align-items:center;gap:3px;display:inline-flex}.session-item-meta .meta-source[data-v-bd681ddd]{border-radius:3px;padding:0 4px;font-size:10px;font-weight:600}.session-item-meta .meta-source.cli[data-v-bd681ddd]{background:color-mix(in srgb, var(--color-warning) 20%, transparent);color:var(--color-warning)}.session-item-actions[data-v-bd681ddd]{opacity:0;flex-shrink:0;gap:2px;transition:opacity .12s;display:flex}.item-action-btn[data-v-bd681ddd]{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-bd681ddd]:hover{background:var(--bg-hover);color:var(--text-secondary)}.item-action-btn.danger[data-v-bd681ddd]:hover{color:var(--color-danger);background:color-mix(in srgb, var(--color-danger) 10%, transparent)}.sidebar-resizer[data-v-bd681ddd]{cursor:col-resize;background:0 0;flex-shrink:0;width:4px;transition:background .15s}.sidebar-resizer[data-v-bd681ddd]:hover,.sidebar-resizer.active[data-v-bd681ddd]{background:var(--color-primary);opacity:.3}.agent-chat-area[data-v-bd681ddd]{flex-direction:column;flex:1;min-width:0;display:flex;position:relative;overflow:hidden}.agent-tabs[data-v-bd681ddd]{border-bottom:1px solid var(--border-color);background:var(--bg-panel);flex-shrink:0;align-items:center;gap:4px;padding:8px 12px 0;display:flex}.agent-tab[data-v-bd681ddd]{color:var(--text-tertiary);cursor:pointer;border-radius:var(--radius-sm) var(--radius-sm) 0 0;background:0 0;border:none;border-bottom:2px solid #0000;align-items:center;gap:6px;padding:7px 14px 9px;font-family:inherit;font-size:13px;transition:color .15s,border-color .15s,background .15s;display:inline-flex}.agent-tab[data-v-bd681ddd]:hover{color:var(--text-secondary);background:var(--bg-hover)}.agent-tab.active[data-v-bd681ddd]{color:var(--color-primary);border-bottom-color:var(--color-primary);font-weight:600}.agent-tab-body[data-v-bd681ddd]{flex-direction:column;flex:1;min-height:0;display:flex;overflow:hidden}.agent-chat-pane[data-v-bd681ddd]{flex-direction:column;flex:1;min-height:0;display:flex;position:relative;overflow:hidden}.agent-tab-body[data-v-bd681ddd]>.marketplace-panel{flex:1;min-height:0}.chat-loading[data-v-bd681ddd]{color:var(--text-tertiary);flex-direction:column;flex:1;justify-content:center;align-items:center;gap:12px;font-size:14px;display:flex}.ask-user-panel[data-v-bd681ddd]{z-index:9;border:1px solid var(--color-primary);border-radius:var(--radius-md);background:var(--bg-container);flex-direction:column;gap:10px;padding:12px 14px;display:flex;position:absolute;bottom:132px;left:16px;right:16px;box-shadow:0 4px 16px #00000029}.ask-user-title[data-v-bd681ddd]{color:var(--color-primary);align-items:center;gap:6px;font-size:12px;font-weight:600;display:flex}.ask-user-question[data-v-bd681ddd]{color:var(--text-primary);white-space:pre-wrap;overflow-wrap:anywhere;font-size:14px;line-height:1.45}.ask-user-options[data-v-bd681ddd]{flex-wrap:wrap;gap:8px;display:flex}.ask-user-option[data-v-bd681ddd],.ask-user-form button[data-v-bd681ddd]{border:1px solid var(--border-color);border-radius:var(--radius-sm);background:var(--bg-hover);min-height:32px;color:var(--text-primary);font:inherit;cursor:pointer;justify-content:center;align-items:center;gap:5px;padding:5px 10px;font-size:13px;transition:border-color .15s,color .15s,background .15s;display:inline-flex}.ask-user-option[data-v-bd681ddd]:hover:not(:disabled),.ask-user-form button[data-v-bd681ddd]:hover:not(:disabled){border-color:var(--color-primary);color:var(--color-primary);background:color-mix(in srgb, var(--color-primary) 8%, var(--bg-hover))}.ask-user-option[data-v-bd681ddd]:disabled,.ask-user-form button[data-v-bd681ddd]:disabled{cursor:wait;opacity:.6}.ask-user-form[data-v-bd681ddd]{gap:8px;display:flex}.ask-user-form input[data-v-bd681ddd]{border:1px solid var(--border-color);border-radius:var(--radius-sm);background:var(--bg-input);min-width:0;height:32px;color:var(--text-primary);font:inherit;outline:none;flex:1;padding:5px 9px;font-size:13px}.ask-user-form input[data-v-bd681ddd]:focus{border-color:var(--color-primary)}.stop-button-bar[data-v-bd681ddd]{z-index:10;position:absolute;bottom:80px;left:50%;transform:translate(-50%)}.stop-button[data-v-bd681ddd]{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-bd681ddd]:hover{background:var(--color-danger);color:#fff}.fade-enter-active[data-v-bd681ddd],.fade-leave-active[data-v-bd681ddd]{transition:opacity .2s}.fade-enter-from[data-v-bd681ddd],.fade-leave-to[data-v-bd681ddd]{opacity:0}[data-theme=dark]{background:var(--bg-panel)}
1
+ .marketplace-panel[data-v-e9f9e851]{background:var(--bg-container);flex-direction:column;height:100%;min-height:0;display:flex}.mp-toolbar[data-v-e9f9e851]{flex-shrink:0;align-items:center;gap:12px;padding:12px 16px 8px;display:flex}.mp-search[data-v-e9f9e851]{border:1px solid var(--border-color);border-radius:var(--radius-md);background:var(--bg-panel);flex:1;align-items:center;gap:6px;max-width:420px;height:32px;padding:0 10px;transition:border-color .15s;display:flex}.mp-search[data-v-e9f9e851]:focus-within{border-color:var(--color-primary)}.mp-search .mp-search-icon[data-v-e9f9e851]{color:var(--text-tertiary);flex-shrink:0}.mp-search .mp-search-input[data-v-e9f9e851]{color:var(--text-primary);background:0 0;border:none;outline:none;flex:1;font-family:inherit;font-size:13px}.mp-search .mp-search-input[data-v-e9f9e851]::placeholder{color:var(--text-tertiary)}.mp-target[data-v-e9f9e851]{flex-shrink:0}.mp-refresh[data-v-e9f9e851]{border:1px solid var(--border-color);border-radius:var(--radius-md);background:var(--bg-panel);width:30px;height:30px;color:var(--text-secondary);cursor:pointer;justify-content:center;align-items:center;transition:all .15s;display:flex}.mp-refresh[data-v-e9f9e851]:hover{color:var(--color-primary);border-color:var(--color-primary)}.mp-refresh.spinning svg[data-v-e9f9e851]{animation:.9s linear infinite mkt-spin-e9f9e851}@keyframes mkt-spin-e9f9e851{to{transform:rotate(360deg)}}.mp-toolbar-sub[data-v-e9f9e851]{flex-wrap:wrap;flex-shrink:0;align-items:center;gap:12px;padding:0 16px 10px;display:flex}.mp-target-hint[data-v-e9f9e851]{color:var(--text-tertiary);font-size:12px}.mp-target-hint b[data-v-e9f9e851]{color:var(--color-primary);font-weight:600}.mp-source-filter[data-v-e9f9e851]{flex-wrap:wrap;align-items:center;gap:6px;display:flex}.mp-chip[data-v-e9f9e851]{border:1px solid var(--border-color);color:var(--text-tertiary);cursor:pointer;background:0 0;border-radius:12px;padding:2px 10px;font-family:inherit;font-size:12px;transition:all .15s}.mp-chip[data-v-e9f9e851]:hover{color:var(--text-secondary);border-color:var(--text-tertiary)}.mp-chip.active[data-v-e9f9e851]{color:var(--color-primary);border-color:var(--color-primary);background:color-mix(in srgb, var(--color-primary) 8%, transparent)}.mp-chip.clear[data-v-e9f9e851]{color:var(--text-tertiary);border-style:dashed}.mp-body[data-v-e9f9e851]{flex:1;min-height:0;padding:0 16px 20px;overflow-y:auto}.mp-group[data-v-e9f9e851]{margin-bottom:20px}.mp-group.installed[data-v-e9f9e851]{border-top:1px dashed var(--border-color);padding-top:14px}.mp-group-header[data-v-e9f9e851]{align-items:center;gap:8px;margin-bottom:10px;display:flex}.mp-group-title[data-v-e9f9e851]{color:var(--text-primary);margin:0;font-size:13px;font-weight:600}.mp-group-count[data-v-e9f9e851]{background:var(--bg-hover);min-width:20px;height:18px;color:var(--text-tertiary);border-radius:9px;justify-content:center;align-items:center;padding:0 6px;font-size:11px;display:inline-flex}.mp-group-error[data-v-e9f9e851]{color:var(--color-warning);align-items:center;gap:4px;font-size:12px;display:inline-flex}.mp-group-link[data-v-e9f9e851]{color:var(--text-tertiary);transition:color .15s;display:inline-flex}.mp-group-link[data-v-e9f9e851]:hover{color:var(--color-primary)}.mp-grid[data-v-e9f9e851]{grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:10px;display:grid}.mp-card[data-v-e9f9e851]{border:1px solid var(--border-color);border-radius:var(--radius-md);background:var(--bg-panel);flex-direction:column;gap:6px;padding:12px;transition:border-color .15s,box-shadow .15s;display:flex}.mp-card[data-v-e9f9e851]:hover{border-color:color-mix(in srgb, var(--color-primary) 40%, var(--border-color));box-shadow:var(--shadow-sm)}.mp-card-head[data-v-e9f9e851]{align-items:center;gap:8px;display:flex}.mp-card-name[data-v-e9f9e851]{min-width:0;color:var(--text-primary);white-space:nowrap;text-overflow:ellipsis;flex:1;font-size:13px;font-weight:600;overflow:hidden}.mp-card-metric[data-v-e9f9e851]{color:var(--text-tertiary);flex-shrink:0;align-items:center;gap:3px;font-size:11px;display:inline-flex}.mp-card-desc[data-v-e9f9e851]{color:var(--text-secondary);-webkit-line-clamp:2;-webkit-box-orient:vertical;min-height:36px;margin:0;font-size:12px;line-height:1.5;display:-webkit-box;overflow:hidden}.mp-card-meta[data-v-e9f9e851]{flex-wrap:wrap;align-items:center;gap:6px;min-height:18px;display:flex}.mp-meta-pkg[data-v-e9f9e851],.mp-meta-repo[data-v-e9f9e851]{color:var(--text-tertiary);white-space:nowrap;text-overflow:ellipsis;max-width:220px;font-size:11px;overflow:hidden}.mp-tag[data-v-e9f9e851]{background:var(--bg-hover);color:var(--text-tertiary);border-radius:8px;flex-shrink:0;padding:1px 6px;font-size:10px}.mp-tag.remote[data-v-e9f9e851]{background:color-mix(in srgb, var(--color-info,#06b6d4) 14%, transparent);color:var(--color-info,#06b6d4)}.mp-tag.warn[data-v-e9f9e851]{background:color-mix(in srgb, var(--color-warning) 14%, transparent);color:var(--color-warning)}.mp-card-foot[data-v-e9f9e851]{align-items:center;gap:8px;margin-top:2px;display:flex}.mp-card-link[data-v-e9f9e851]{color:var(--text-tertiary);font-size:11px;text-decoration:none}.mp-card-link[data-v-e9f9e851]:hover{color:var(--color-primary);text-decoration:underline}.mp-foot-spacer[data-v-e9f9e851]{flex:1}.mp-install-btn[data-v-e9f9e851]{border:1px solid var(--color-primary);border-radius:var(--radius-sm);color:var(--color-primary);cursor:pointer;background:0 0;padding:4px 14px;font-family:inherit;font-size:12px;transition:all .15s}.mp-install-btn[data-v-e9f9e851]:hover:not(:disabled){background:var(--color-primary);color:#fff}.mp-install-btn[data-v-e9f9e851]:disabled{opacity:.5;cursor:not-allowed}.mp-installed-chip[data-v-e9f9e851]{color:var(--color-success,#34d399);align-items:center;gap:3px;font-size:11px;display:inline-flex}.mp-not-installable[data-v-e9f9e851]{color:var(--text-tertiary);font-size:11px}.mp-empty[data-v-e9f9e851]{color:var(--text-tertiary);padding:16px 0;font-size:12px}.mp-empty.all[data-v-e9f9e851]{text-align:center;padding:48px 0}.mp-installed-block[data-v-e9f9e851]{margin-bottom:12px}.mp-installed-target[data-v-e9f9e851]{color:var(--text-tertiary);text-transform:uppercase;letter-spacing:.4px;margin-bottom:6px;font-size:11px;font-weight:600}.mp-installed-list[data-v-e9f9e851]{flex-direction:column;gap:4px;display:flex}.mp-installed-row[data-v-e9f9e851]{border:1px solid var(--border-color);border-radius:var(--radius-sm);background:var(--bg-panel);align-items:center;gap:10px;padding:6px 10px;display:flex}.mp-installed-name[data-v-e9f9e851]{color:var(--text-primary);white-space:nowrap;text-overflow:ellipsis;font-size:12px;font-weight:500;overflow:hidden}.mp-remove-btn[data-v-e9f9e851]{border:1px solid var(--border-color);border-radius:var(--radius-xs);color:var(--text-tertiary);cursor:pointer;background:0 0;align-items:center;gap:4px;padding:3px 10px;font-family:inherit;font-size:11px;transition:all .15s;display:inline-flex}.mp-remove-btn[data-v-e9f9e851]:hover:not(:disabled){color:var(--color-danger);border-color:var(--color-danger)}.mp-remove-btn[data-v-e9f9e851]:disabled{opacity:.5;cursor:not-allowed}@media (prefers-reduced-motion:reduce){.mp-refresh.spinning svg[data-v-e9f9e851]{animation:none}}.mkt-form[data-v-e9f9e851]{flex-direction:column;gap:12px;display:flex}.mkt-form-name[data-v-e9f9e851]{color:var(--text-primary);margin:0;font-size:13px;font-weight:600}.mkt-field[data-v-e9f9e851]{flex-direction:column;gap:4px;display:flex}.mkt-field label[data-v-e9f9e851]{color:var(--text-secondary);font-size:12px;font-weight:600}.mkt-field input[data-v-e9f9e851]{border:1px solid var(--border-color);background:var(--bg-container);height:30px;color:var(--text-primary);border-radius:6px;padding:0 8px;font-family:inherit;font-size:13px;transition:border-color .15s}.mkt-field input[data-v-e9f9e851]:focus{border-color:var(--color-primary);outline:none}.mkt-hint[data-v-e9f9e851]{color:var(--text-tertiary);margin:0;font-size:11px}.mkt-cancel[data-v-e9f9e851],.mkt-confirm[data-v-e9f9e851]{border-radius:var(--radius-sm);cursor:pointer;padding:6px 16px;font-family:inherit;font-size:13px;transition:all .15s}.mkt-cancel[data-v-e9f9e851]{border:1px solid var(--border-color);color:var(--text-secondary);background:0 0;margin-right:8px}.mkt-cancel[data-v-e9f9e851]:hover{color:var(--text-primary);border-color:var(--text-tertiary)}.mkt-confirm[data-v-e9f9e851]{border:1px solid var(--color-primary);background:var(--color-primary);color:#fff}.mkt-confirm[data-v-e9f9e851]:hover{opacity:.9}.agent-view[data-v-bd681ddd]{background:var(--bg-container);height:100%;min-height:0;display:flex}.agent-sidebar[data-v-bd681ddd]{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-bd681ddd]{flex-shrink:0;padding:10px 12px}.new-session-btn[data-v-bd681ddd]{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-bd681ddd]:hover{border-color:var(--color-primary);color:var(--color-primary);background:color-mix(in srgb, var(--color-primary) 6%, transparent)}.sidebar-search[data-v-bd681ddd]{flex-shrink:0;align-items:center;gap:6px;padding:0 12px 8px;display:flex}.sidebar-search .search-icon[data-v-bd681ddd]{color:var(--text-tertiary);flex-shrink:0}.sidebar-search .search-input[data-v-bd681ddd]{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-bd681ddd]::placeholder{color:var(--text-tertiary)}.session-list[data-v-bd681ddd]{flex:1;min-height:0;padding:0 6px 8px;overflow-y:auto}.empty-state[data-v-bd681ddd]{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-bd681ddd]{color:var(--text-secondary);margin-top:10px;font-size:14px}.empty-state .empty-hint[data-v-bd681ddd]{margin-top:4px;font-size:12px}.session-item[data-v-bd681ddd]{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-bd681ddd]:hover{background:var(--bg-hover)}.session-item:hover .session-item-actions[data-v-bd681ddd]{opacity:1}.session-item.active[data-v-bd681ddd]{background:color-mix(in srgb, var(--color-primary) 10%, transparent)}.session-item.active .session-item-title[data-v-bd681ddd]{color:var(--color-primary)}.session-item.active[data-v-bd681ddd]: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-bd681ddd]{flex:1;min-width:0}.session-item-title[data-v-bd681ddd]{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-bd681ddd]{color:var(--text-tertiary);align-items:center;gap:4px;font-size:11px;display:flex}.session-item-meta .meta-dot[data-v-bd681ddd]{opacity:.5}.session-item-meta .meta-generating[data-v-bd681ddd]{color:var(--color-primary);align-items:center;gap:3px;display:inline-flex}.session-item-meta .meta-source[data-v-bd681ddd]{border-radius:3px;padding:0 4px;font-size:10px;font-weight:600}.session-item-meta .meta-source.cli[data-v-bd681ddd]{background:color-mix(in srgb, var(--color-warning) 20%, transparent);color:var(--color-warning)}.session-item-actions[data-v-bd681ddd]{opacity:0;flex-shrink:0;gap:2px;transition:opacity .12s;display:flex}.item-action-btn[data-v-bd681ddd]{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-bd681ddd]:hover{background:var(--bg-hover);color:var(--text-secondary)}.item-action-btn.danger[data-v-bd681ddd]:hover{color:var(--color-danger);background:color-mix(in srgb, var(--color-danger) 10%, transparent)}.sidebar-resizer[data-v-bd681ddd]{cursor:col-resize;background:0 0;flex-shrink:0;width:4px;transition:background .15s}.sidebar-resizer[data-v-bd681ddd]:hover,.sidebar-resizer.active[data-v-bd681ddd]{background:var(--color-primary);opacity:.3}.agent-chat-area[data-v-bd681ddd]{flex-direction:column;flex:1;min-width:0;display:flex;position:relative;overflow:hidden}.agent-tabs[data-v-bd681ddd]{border-bottom:1px solid var(--border-color);background:var(--bg-panel);flex-shrink:0;align-items:center;gap:4px;padding:8px 12px 0;display:flex}.agent-tab[data-v-bd681ddd]{color:var(--text-tertiary);cursor:pointer;border-radius:var(--radius-sm) var(--radius-sm) 0 0;background:0 0;border:none;border-bottom:2px solid #0000;align-items:center;gap:6px;padding:7px 14px 9px;font-family:inherit;font-size:13px;transition:color .15s,border-color .15s,background .15s;display:inline-flex}.agent-tab[data-v-bd681ddd]:hover{color:var(--text-secondary);background:var(--bg-hover)}.agent-tab.active[data-v-bd681ddd]{color:var(--color-primary);border-bottom-color:var(--color-primary);font-weight:600}.agent-tab-body[data-v-bd681ddd]{flex-direction:column;flex:1;min-height:0;display:flex;overflow:hidden}.agent-chat-pane[data-v-bd681ddd]{flex-direction:column;flex:1;min-height:0;display:flex;position:relative;overflow:hidden}.agent-tab-body[data-v-bd681ddd]>.marketplace-panel{flex:1;min-height:0}.chat-loading[data-v-bd681ddd]{color:var(--text-tertiary);flex-direction:column;flex:1;justify-content:center;align-items:center;gap:12px;font-size:14px;display:flex}[data-theme=dark]{background:var(--bg-panel)}