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.
- package/README.md +211 -185
- package/package.json +2 -2
- package/scripts/release.js +33 -16
- package/src/cli/ai/agent.js +24 -2
- package/src/cli/ai/runtime.test.js +1 -1
- package/src/cli/ai/tools.js +69 -14
- package/src/cli/ai/tools.test.js +46 -1
- package/src/config.js +8 -4
- package/src/gitCommit.js +18 -1
- package/src/ui/public/assets/AgentView-DOyN97Ve.js +5 -0
- package/src/ui/public/assets/{AgentView-vvVhbIQ5.css → AgentView-DkM2KXuc.css} +1 -1
- package/src/ui/public/assets/AppVersionBadge-oON3sAj4.js +2 -0
- package/src/ui/public/assets/{BranchSelector-XIN87Mkw.js → BranchSelector-Cpj7eGqY.js} +1 -1
- package/src/ui/public/assets/CommitForm-D_ovYhVw.js +6 -0
- package/src/ui/public/assets/{CommonDialog-BiNTGpA-.js → CommonDialog-ChZbqfRF.js} +1 -1
- package/src/ui/public/assets/EditorView-BPzpI0GV.js +1 -0
- package/src/ui/public/assets/FileDiffViewer-B_qEKA9L.js +15 -0
- package/src/ui/public/assets/{FlowExecutionViewer-D9Vzgh91.js → FlowExecutionViewer-Drw4hlJG.js} +1 -1
- package/src/ui/public/assets/FlowOrchestrationWorkspace-C7yTD1gj.js +21 -0
- package/src/ui/public/assets/{IconButton-DysyaC1j.js → IconButton-DEARmMkZ.js} +1 -1
- package/src/ui/public/assets/{LogList-QDgok-UJ.js → LogList-BA_gowxE.js} +5 -5
- package/src/ui/public/assets/MindmapView-8X6z245q.css +1 -0
- package/src/ui/public/assets/MindmapView-K-XcLLXr.js +2 -0
- package/src/ui/public/assets/MonitorView-C0RL5K9W.js +1 -0
- package/src/ui/public/assets/ProjectStartupButton-DC36_vvU.js +1 -0
- package/src/ui/public/assets/RemoteManagerDialog-Bkqja660.js +4 -0
- package/src/ui/public/assets/{RemoteRepoCard-Bn9cKt1D.js → RemoteRepoCard-Bsm7cj_H.js} +2 -2
- package/src/ui/public/assets/SourceMapView-Y5NKdIk6.js +3 -0
- package/src/ui/public/assets/{SvgIcon-CvtoU5yo.js → SvgIcon-D_mFHXP4.js} +1 -1
- package/src/ui/public/assets/{TemplateManager-saqC9kdQ.js → TemplateManager-BzKVXZhy.js} +1 -1
- package/src/ui/public/assets/UserInputNode-BPLK4aYx.js +1 -0
- package/src/ui/public/assets/WorkbenchView-xbGdiVMQ.js +56 -0
- package/src/ui/public/assets/_plugin-vue_export-helper-dg2VUnSQ.js +19 -0
- package/src/ui/public/assets/configStore-DtjAc3w9.js +1 -0
- package/src/ui/public/assets/{css.worker-DFdt6_zu.js → css.worker-BDCmgL4U.js} +9 -9
- package/src/ui/public/assets/editor.worker-GCPm6rMv.js +26 -0
- package/src/ui/public/assets/{element-plus-Dc1iTOWq.css → element-plus-Cwwq-Gje.css} +1 -1
- package/src/ui/public/assets/element-plus-DxBPQwL7.js +48 -0
- package/src/ui/public/assets/{flow-mindmap-CHxAWdLw.js → flow-mindmap-BqFb1WO5.js} +1 -1
- package/src/ui/public/assets/{gitStore-BgC8OY0k.js → gitStore-BZo9_zyy.js} +5 -5
- package/src/ui/public/assets/{html.worker-JUzsMP-j.js → html.worker-DG8hnSJR.js} +8 -8
- package/src/ui/public/assets/index-CHuCYLWm.js +111 -0
- package/src/ui/public/assets/index-CmbatbSR.css +1 -0
- package/src/ui/public/assets/json.worker-CxwlJRnL.js +58 -0
- package/src/ui/public/assets/{monaco-DkJuNcCr.js → monaco-BScz9v63.js} +6 -6
- package/src/ui/public/assets/{office-docx-CmBY5bpF.js → office-docx-CZXLkCf5.js} +1 -1
- package/src/ui/public/assets/{office-excel-BEhsBUNX.js → office-excel-CBKszjVA.js} +1 -1
- package/src/ui/public/assets/{office-pptx-DWfi413x.js → office-pptx-NeUSnN3k.js} +3 -3
- package/src/ui/public/assets/previewSandbox-BTTTXooN.js +0 -0
- package/src/ui/public/assets/{ts.worker-CmEKzkmF.js → ts.worker-DgFMIcEs.js} +49 -49
- package/src/ui/public/assets/{useThemeObserver-DhCU3SIo.js → useThemeObserver-E7Hk50l3.js} +1 -1
- package/src/ui/public/assets/vendor-DnB9EJa3.css +1 -0
- package/src/ui/public/assets/{vendor-CZnXb2r9.js → vendor-bdHhLiED.js} +28 -28
- package/src/ui/public/assets/{vue-flow-7_n4vJqi.js → vue-flow-fLUQ0_kE.js} +1 -1
- package/src/ui/public/index.html +19 -19
- package/src/ui/server/index.js +4 -0
- package/src/ui/server/routes/explorerContextMenu.js +208 -0
- package/src/ui/server/routes/explorerContextMenu.test.js +180 -0
- package/src/ui/server/routes/workbench/agentChat.js +14 -3
- package/src/ui/server/routes/workbench/agentMarketplace.js +23 -9
- package/src/ui/server/routes/workbench/agentMarketplace.test.js +32 -0
- package/src/ui/server/routes/workbench/agentRoutes.js +14 -7
- package/src/ui/server/routes/workbench/agentRoutes.test.js +47 -1
- package/src/ui/server/routes/workbench/taskRunner.codex.test.js +173 -0
- package/src/ui/server/routes/workbench/taskRunner.js +259 -10
- package/src/ui/server/routes/workbench/taskRunner.opencode.test.js +4 -2
- package/src/ui/public/assets/AgentView-DLHlVWRg.js +0 -5
- package/src/ui/public/assets/AppVersionBadge-JxpMuGwP.js +0 -2
- package/src/ui/public/assets/CommitForm-CW53Er5m.js +0 -6
- package/src/ui/public/assets/EditorView-D0JoJhgt.js +0 -1
- package/src/ui/public/assets/FileDiffViewer-Yas2nO2U.js +0 -15
- package/src/ui/public/assets/FlowOrchestrationWorkspace-DQ3fg5b9.js +0 -21
- package/src/ui/public/assets/MindmapView-BQTqx842.css +0 -1
- package/src/ui/public/assets/MindmapView-CeZsQNBK.js +0 -2
- package/src/ui/public/assets/MonitorView-D1tgmjjS.js +0 -1
- package/src/ui/public/assets/ProjectStartupButton-COntA4q1.js +0 -1
- package/src/ui/public/assets/RemoteManagerDialog-3dihAOab.js +0 -4
- package/src/ui/public/assets/SourceMapView-C8UdzQXF.js +0 -3
- package/src/ui/public/assets/UserInputNode-CvEfvX3i.js +0 -1
- package/src/ui/public/assets/WorkbenchView-B7WAu1Ay.js +0 -56
- package/src/ui/public/assets/_plugin-vue_export-helper-BdTxl34g.js +0 -19
- package/src/ui/public/assets/configStore-AQMSazCM.js +0 -1
- package/src/ui/public/assets/editor.worker-O-CH8JUO.js +0 -26
- package/src/ui/public/assets/element-plus-CMSkP_w2.js +0 -48
- package/src/ui/public/assets/index-Dpx9Bcqn.css +0 -1
- package/src/ui/public/assets/index-qAmzFO10.js +0 -104
- package/src/ui/public/assets/json.worker-B4dEhy0e.js +0 -58
- package/src/ui/public/assets/previewSandbox-CyuMMYaq.js +0 -0
- 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.
|
|
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.
|
|
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",
|
package/scripts/release.js
CHANGED
|
@@ -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
|
-
//
|
|
96
|
-
//
|
|
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
|
-
//
|
|
631
|
-
//
|
|
632
|
-
//
|
|
633
|
-
//
|
|
634
|
-
//
|
|
635
|
-
|
|
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
|
-
|
|
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 {
|
|
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()
|
package/src/cli/ai/agent.js
CHANGED
|
@@ -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
|
-
? (
|
|
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
|
|
package/src/cli/ai/tools.js
CHANGED
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
// - 工具内部异常一律 catch 成字符串返回,不抛给 agent 循环 ——
|
|
25
25
|
// 让模型看到错误信息自己修正,而不是中断整轮对话
|
|
26
26
|
|
|
27
|
-
import {
|
|
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
|
-
//
|
|
241
|
-
//
|
|
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, ...
|
|
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
|
|
307
|
+
const finish = (code) => {
|
|
257
308
|
clearTimeout(timer)
|
|
258
309
|
signal?.removeEventListener('abort', abort)
|
|
259
310
|
resolve({
|
|
260
|
-
code:
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
620
|
+
// 多选只在真的给了选项时才有意义
|
|
621
|
+
const multiple = args.multiple === true && options.length > 0
|
|
622
|
+
return ctx.askUser({ question, options, allowFreeText, multiple })
|
|
568
623
|
}
|
|
569
624
|
|
|
570
625
|
// ──────────────────────────────────────────────
|
package/src/cli/ai/tools.test.js
CHANGED
|
@@ -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
|
|
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)}
|