zen-gitsync 2.18.8 → 2.18.10
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 +2 -2
- package/package.json +2 -1
- package/src/cli/ai/agent.js +7 -0
- package/src/cli/ai/runtime.test.js +22 -1
- package/src/cli/ai/tools.js +153 -2
- package/src/cli/ai/tools.test.js +71 -2
- package/src/cli/ai/transport.js +8 -3
- package/src/config.js +7 -5
- package/src/mcp/tools/workbench.js +1 -1
- package/src/ui/public/assets/{AgentView-DZx3n-So.css → AgentView-BnEgu3NT.css} +1 -1
- package/src/ui/public/assets/AgentView-DQQe_ivW.js +1 -0
- package/src/ui/public/assets/{AppVersionBadge-Bg5lrtKb.js → AppVersionBadge-D7PiBP0p.js} +2 -2
- package/src/ui/public/assets/{BranchSelector-CxjTqAkl.js → BranchSelector-BzHoMBOc.js} +1 -1
- package/src/ui/public/assets/{CommitForm-BWWrOvj5.js → CommitForm-CNTjLYTR.js} +2 -2
- package/src/ui/public/assets/{CommonDialog-x5jfL4Lq.js → CommonDialog-j_53ORvj.js} +1 -1
- package/src/ui/public/assets/CopySessionButton-Dy5t8Mjy.js +20 -0
- package/src/ui/public/assets/EditorView-CwcdA0Ei.js +1 -0
- package/src/ui/public/assets/{EditorView-BUiVsBv7.css → EditorView-Ims2BUK_.css} +1 -1
- package/src/ui/public/assets/{FlowExecutionViewer-BkZ20jxN.js → FlowExecutionViewer-CQ-TPhwF.js} +1 -1
- package/src/ui/public/assets/{FlowOrchestrationWorkspace-aZBYu29g.js → FlowOrchestrationWorkspace-CJHpEBCw.js} +1 -1
- package/src/ui/public/assets/{LogList-CSIbmUMK.js → LogList-KUePBjAt.js} +4 -4
- package/src/ui/public/assets/{MindmapView-JYLp185X.js → MindmapView-CwdvsuEK.js} +1 -1
- package/src/ui/public/assets/{MonitorView-BS2Mh-I7.js → MonitorView-CjEnnrTL.js} +1 -1
- package/src/ui/public/assets/{ProjectStartupButton-DAEP6ZU5.js → ProjectStartupButton-B36lRb6-.js} +1 -1
- package/src/ui/public/assets/RecentDirectoriesChat-7fzSkSmc.css +1 -0
- package/src/ui/public/assets/RecentDirectoriesChat-DNiji9Pr.js +1 -0
- package/src/ui/public/assets/{RemoteManagerDialog-aaNmsKpy.js → RemoteManagerDialog-Dj_GpA-c.js} +1 -1
- package/src/ui/public/assets/{RemoteRepoCard-DndI8rNZ.js → RemoteRepoCard-C8u9M6dn.js} +1 -1
- package/src/ui/public/assets/{SourceMapView-BTD9-R8t.js → SourceMapView-eng0B9U2.js} +1 -1
- package/src/ui/public/assets/{SvgIcon-0n6uuKFm.js → SvgIcon-5AlG3IfR.js} +1 -1
- package/src/ui/public/assets/{UserInputNode-B-mDg9Wy.js → UserInputNode-BKP869D6.js} +1 -1
- package/src/ui/public/assets/WorkbenchView-CZO18THH.js +6 -0
- package/src/ui/public/assets/WorkbenchView-DogERhHQ.css +1 -0
- package/src/ui/public/assets/{_plugin-vue_export-helper-C3o7kvRL.js → _plugin-vue_export-helper-Csn085FF.js} +4 -4
- package/src/ui/public/assets/agentConversations-De3wKTsN.js +10 -0
- package/src/ui/public/assets/configStore-DOaPZ6Mq.js +1 -0
- package/src/ui/public/assets/index-DQ82h1aq.js +57 -0
- package/src/ui/public/assets/index-NYzaTfbS.css +1 -0
- package/src/ui/public/assets/{useOrchestrator-CS9sn7nV.js → useOrchestrator-BjC7oHpt.js} +1 -1
- package/src/ui/public/index.html +6 -6
- package/src/ui/server/index.js +8 -0
- package/src/ui/server/routes/fileOpen.js +57 -1
- package/src/ui/server/routes/fileOpen.test.js +1 -1
- package/src/ui/server/routes/git/clone.js +5 -13
- package/src/ui/server/routes/workbench/agentChat.js +75 -10
- package/src/ui/server/routes/workbench/agentChatExtensions.test.js +290 -0
- package/src/ui/server/routes/workbench/agentEngines.js +8 -4
- package/src/ui/server/routes/workbench/agentExtensions.js +157 -0
- package/src/ui/server/routes/workbench/agentMarketplace.js +12 -0
- package/src/ui/server/routes/workbench/agentParity.test.js +16 -0
- package/src/ui/server/routes/workbench/agentRoutes.js +99 -7
- package/src/ui/server/routes/workbench/agentRoutes.test.js +141 -1
- package/src/ui/server/routes/workbench/executorModels.js +30 -5
- package/src/ui/server/routes/workbench/executorModels.test.js +16 -4
- package/src/ui/server/routes/workbench/index.js +17 -5
- package/src/ui/server/routes/workbench/jobActivity.js +3 -3
- package/src/ui/server/routes/workbench/jobActivity.test.js +1 -0
- package/src/ui/server/routes/workbench/runExternalTurn.js +22 -25
- package/src/ui/server/routes/workbench/runExternalTurn.test.js +34 -0
- package/src/ui/server/routes/workbench/scheduler.js +3 -0
- package/src/ui/server/routes/workbench/taskRunner.codebuddy.test.js +275 -0
- package/src/ui/server/routes/workbench/taskRunner.js +311 -24
- package/src/ui/server/routes/workbench/taskRunner.opencode.test.js +2 -1
- package/src/utils/gitRepoName.js +33 -0
- package/src/ui/public/assets/AgentView-BRAUZCtA.js +0 -1
- package/src/ui/public/assets/CopySessionButton-D0wFpk8a.js +0 -20
- package/src/ui/public/assets/EditorView-DmaGiI-z.js +0 -1
- package/src/ui/public/assets/RecentDirectoriesChat-B19uAf8k.css +0 -1
- package/src/ui/public/assets/RecentDirectoriesChat-CVFTShrU.js +0 -1
- package/src/ui/public/assets/WorkbenchView-CfSrCIbp.js +0 -8
- package/src/ui/public/assets/WorkbenchView-D6NRqZ5W.css +0 -1
- package/src/ui/public/assets/agentConversations-DpiGplZB.js +0 -8
- package/src/ui/public/assets/configStore-BdL3uW2E.js +0 -1
- package/src/ui/public/assets/index-BS7BDFG4.js +0 -57
- package/src/ui/public/assets/index-DwJWiCiN.css +0 -1
|
@@ -15,10 +15,13 @@
|
|
|
15
15
|
// 任务执行引擎:spawn 本地 agent CLI 跑子任务,流式收集输出,更新 job 状态。
|
|
16
16
|
// 拆分自原 routes/workbench.js 1108-1564 行。
|
|
17
17
|
//
|
|
18
|
-
//
|
|
19
|
-
// - claude
|
|
20
|
-
// - opencode
|
|
21
|
-
// - codex
|
|
18
|
+
// 支持四种执行器(executor):
|
|
19
|
+
// - claude —— claude -p --output-format stream-json(默认,历史行为)
|
|
20
|
+
// - opencode —— opencode run --format json --auto(sst/opencode CLI,跟随其自身默认模型)
|
|
21
|
+
// - codex —— codex exec --json(OpenAI Codex CLI,跟随其自身配置;2026-09-27 加入)
|
|
22
|
+
// - codebuddy —— codebuddy -p --output-format stream-json -y --port 0
|
|
23
|
+
// (腾讯 CodeBuddy Code CLI,即 WorkBuddy 桌面版的智能体引擎;
|
|
24
|
+
// 2026-10-12 加入,协议与 claude 的 stream-json 逐字段对齐)
|
|
22
25
|
//
|
|
23
26
|
// 核心 API:
|
|
24
27
|
// - launchClaudeInNewWindow(cwd, prompt, resumeSessionId) spawn claude,返回 {pid, child}
|
|
@@ -216,11 +219,32 @@ function attachPromptStdin(child, promptText, resolve, reject) {
|
|
|
216
219
|
}
|
|
217
220
|
|
|
218
221
|
// ── 执行器(executor) ──────────────────────────────────────────────────
|
|
219
|
-
// 工作台任务默认由 claude CLI 执行;opencode(2026-09-20)、codex(2026-09-27
|
|
220
|
-
//
|
|
221
|
-
//
|
|
222
|
-
// codex 是 exec --json 的 thread/item 事件 NDJSON。
|
|
223
|
-
|
|
222
|
+
// 工作台任务默认由 claude CLI 执行;opencode(2026-09-20)、codex(2026-09-27)、
|
|
223
|
+
// codebuddy(2026-10-12)作为可选执行器。四者都用「stdin 喂 prompt + stdout 结构化
|
|
224
|
+
// JSON 事件流」的同构形态,差异只在协议:claude / codebuddy 是 stream-json,
|
|
225
|
+
// opencode 是 --format json 的事件 NDJSON,codex 是 exec --json 的 thread/item 事件 NDJSON。
|
|
226
|
+
//
|
|
227
|
+
// ⚠️ 这份清单与 src/config.js 的 TASK_EXECUTORS 是**同一份口径的两处书写**——
|
|
228
|
+
// 历史上为此吵过(见 agentEngines.js 文件头):config.js 那份是"配置/归一化"的
|
|
229
|
+
// 真相源,本文件这份服务"运行时分发"。两边不一致的失效方式是 normalize 放行、
|
|
230
|
+
// 这里查无此人 → 静默回落 claude。加第五家时两处都要改,taskRunner.*.test.js 有钉子。
|
|
231
|
+
export const TASK_EXECUTORS = ['claude', 'opencode', 'codex', 'codebuddy'];
|
|
232
|
+
|
|
233
|
+
/** 执行器 → launcher。runSingleSubtask 与 runExternalTurn 共用这一张表。 */
|
|
234
|
+
export const EXECUTOR_LAUNCHERS = {
|
|
235
|
+
claude: launchClaudeInNewWindow,
|
|
236
|
+
opencode: launchOpencodeRun,
|
|
237
|
+
codex: launchCodexExec,
|
|
238
|
+
codebuddy: launchCodebuddyPrint,
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
/** 执行器 → NDJSON 事件处理器工厂。 */
|
|
242
|
+
export const EXECUTOR_HANDLERS = {
|
|
243
|
+
claude: createClaudeEventHandler,
|
|
244
|
+
opencode: createOpencodeEventHandler,
|
|
245
|
+
codex: createCodexEventHandler,
|
|
246
|
+
codebuddy: createCodebuddyEventHandler,
|
|
247
|
+
};
|
|
224
248
|
|
|
225
249
|
/** 非法/缺省的 executor 一律回落 'claude'(历史行为的兼容兜底)。
|
|
226
250
|
* body.executor 来自网络,做一次 trim + 小写归一,与 config.js 同名函数同语义。 */
|
|
@@ -390,6 +414,274 @@ export function launchCodexExec(cwd, promptText, resumeSessionId) {
|
|
|
390
414
|
});
|
|
391
415
|
}
|
|
392
416
|
|
|
417
|
+
// ── codebuddy 执行器(2026-10-12 加入) ────────────────────────────────────
|
|
418
|
+
// CodeBuddy Code CLI(`codebuddy` / `cbc`,npm 包 @tencent-ai/codebuddy-code)就是
|
|
419
|
+
// WorkBuddy 桌面版内置的智能体引擎。把它接进来 = 工作台/对话面板可以直接调度
|
|
420
|
+
// "WorkBuddy 同款引擎"(同一套工具集、Skills、权限模型),账号体系也是同一个
|
|
421
|
+
// (都走腾讯账号;CLI 侧首次要在终端扫码登录一次,写 ~/.codebuddy)。
|
|
422
|
+
//
|
|
423
|
+
// ⚠️ 与桌面版**不共享任何运行时身份**:桌面版给它自己的子进程注入一整套变量
|
|
424
|
+
// (CODEBUDDY_HOST=workbuddy-desktop / CONFIG_DIR / MCP_CONFIG / 会话追踪 id…),
|
|
425
|
+
// 这套变量继承过来会让 CLI 以"桌面版子进程"身份运行 —— 实测直接认证失败。
|
|
426
|
+
// 全部在 buildCodebuddyEnv 里剥掉,CLI 固定以独立模式读自己的 ~/.codebuddy,
|
|
427
|
+
// 行为可复现,不随 g gui 被谁拉起而变。
|
|
428
|
+
//
|
|
429
|
+
// 实测口径(2026-10-12,CLI 2.164.0,本机与官方文档双向核对):
|
|
430
|
+
//
|
|
431
|
+
// codebuddy -p --output-format stream-json -y --port 0 [--resume <sessionId>]
|
|
432
|
+
// - prompt 从 stdin 喂(-p 无位置参数时读 stdin,与 claude 的 `-p -` 同效,
|
|
433
|
+
// 顺带避开 Windows 命令行 32K 上限)
|
|
434
|
+
// - --output-format stream-json NDJSON 事件流,**协议与 claude 逐字段对齐**
|
|
435
|
+
// (官方文档原话"对齐 Anthropic Claude Code v2.1.88"):
|
|
436
|
+
// system/init(带 session_id / tools / model / permissionMode)
|
|
437
|
+
// assistant(message.content 里的 text / thinking / tool_use 块)
|
|
438
|
+
// user(message.content 里的 tool_result 块,回指 tool_use_id)
|
|
439
|
+
// result(终态,带 is_error / errors / usage / total_cost_usd)
|
|
440
|
+
// 另有 system/status、ai-title 等 cbc 特有事件,handler 一律忽略。
|
|
441
|
+
// - -y 非交互免批准。init 事件回传 permissionMode: 'bypassPermissions'
|
|
442
|
+
// (不给 -y 时写操作会被拦,和另三家一个性质)
|
|
443
|
+
// - --port 0 **每次 spawn 必须显式传**。CLI 每次运行会自带一个引擎服务器,
|
|
444
|
+
// 默认端口写死 62443 —— 而 WorkBuddy 桌面版常驻就占着 62443,
|
|
445
|
+
// 不传端口(或传固定值)会 EADDRINUSE 直接退出。0 = 让 OS 选空闲
|
|
446
|
+
// 端口,实测并发两个任务各起各的互不冲突。
|
|
447
|
+
// - --resume 续接会话,id 取自上一轮 init 事件的 session_id(落 job.claudeSessionId)
|
|
448
|
+
// - 不传 --model:模型跟随 CLI 自己的配置(与另三家同一口径,探测见 executorModels.js)
|
|
449
|
+
// - 不需要 --verbose:claude 的 stream-json 必须配 --verbose,cbc 不用
|
|
450
|
+
// (实测不带 --verbose 事件流完整)。
|
|
451
|
+
//
|
|
452
|
+
// 登录态:CLI 读 ~/.codebuddy 下的凭据。**首次使用前要先在终端跑一次
|
|
453
|
+
// `codebuddy` 扫码登录**(微信),之后 headless 才能过认证;也可以用
|
|
454
|
+
// CODEBUDDY_API_KEY(+可选 CODEBUDDY_BASE_URL)环境变量认证。读不到凭据时
|
|
455
|
+
// 会话照常起,但模型调用返回 "Authentication required",表现是一轮秒退的
|
|
456
|
+
// error_during_execution —— 这种失败由 result 事件如实带出,不静默。
|
|
457
|
+
// (另见 buildCodebuddyEnv:桌面版注入的 CODEBUDDY_CONFIG_DIR 会被删掉。)
|
|
458
|
+
|
|
459
|
+
/**
|
|
460
|
+
* Windows 下把 codebuddy 解析成可直接 spawn 的目标。
|
|
461
|
+
*
|
|
462
|
+
* 三种安装形态都见过(2026-10-12):
|
|
463
|
+
* 1. npm 全局(`npm i -g @tencent-ai/codebuddy-code`)—— PATH 上是 .cmd shim,
|
|
464
|
+
* shim 实质是 `node <prefix>\node_modules\@tencent-ai\codebuddy-code\bin\codebuddy`。
|
|
465
|
+
* Node 23+ 拒绝直接 spawn .cmd(EINVAL),所以像 claude 一样解析到 node + bin 脚本。
|
|
466
|
+
* 2. 原生二进制安装(install.ps1 → %USERPROFILE%\AppData\Local\codebuddy\bin)——
|
|
467
|
+
* PATH 上直接是 codebuddy.exe,优先用(少一层 node 包装,杀进程树也更干净)。
|
|
468
|
+
* 3. 手动放 PATH 的其它形态 —— 兜底交给 PATH。
|
|
469
|
+
*/
|
|
470
|
+
function resolveCodebuddyExe() {
|
|
471
|
+
try {
|
|
472
|
+
const lines = execFileSync('where', ['codebuddy'], { encoding: 'utf8', windowsHide: true })
|
|
473
|
+
.split(/\r?\n/).map(s => s.trim()).filter(Boolean);
|
|
474
|
+
// 独立安装优先:PATH 上直接就是原生 exe
|
|
475
|
+
const directExe = lines.find(s => /\.exe$/i.test(s));
|
|
476
|
+
if (directExe && fs.existsSync(directExe)) return { exe: directExe, prefixArgs: [] };
|
|
477
|
+
const cmdShim = lines.find(s => /\.cmd$/i.test(s));
|
|
478
|
+
if (cmdShim) {
|
|
479
|
+
const prefix = path.dirname(cmdShim);
|
|
480
|
+
const binJs = path.join(prefix, 'node_modules', '@tencent-ai', 'codebuddy-code', 'bin', 'codebuddy');
|
|
481
|
+
if (fs.existsSync(binJs)) return { exe: process.execPath, prefixArgs: [binJs] };
|
|
482
|
+
}
|
|
483
|
+
} catch { /* fallback */ }
|
|
484
|
+
return { exe: 'codebuddy', prefixArgs: [] };
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
/**
|
|
488
|
+
* WorkBuddy 桌面版注入给**它自己子进程**的环境变量,一个都不能让 codebuddy 子进程继承。
|
|
489
|
+
*
|
|
490
|
+
* ★ 两个实测确认的认证杀手(2026-10-12 逐变量二分 + CLI 日志取证):
|
|
491
|
+
* 1. `CODEBUDDY_HOST=workbuddy-desktop` —— 带上它,CLI 认为自己是"桌面版引擎
|
|
492
|
+
* 的子进程",转而去找桌面版凭据(`auth/workbuddy-desktop.info`,其解密密钥
|
|
493
|
+
* 只存在于桌面版运行时),拿不到就报 "Authentication required"(日志:
|
|
494
|
+
* AtRestEncryption missing-key → AuthRefresh failed)。而用户明明在
|
|
495
|
+
* ~/.codebuddy 登录过。
|
|
496
|
+
* 2. `CODEBUDDY_FORCE_LITE_WB_BUNDLE=1`(+配套 FORCE_HEADLESS_BUNDLE)——
|
|
497
|
+
* bin/codebuddy 里**专为桌面版宿主准备的 bundle 分流通道**(CLI 源码注释
|
|
498
|
+
* 原话:"宿主(workbuddy-server 起 sidecar / prewarm)在 spawn cbc 前设
|
|
499
|
+
* CODEBUDDY_FORCE_LITE_WB_BUNDLE=1,直接命中 codebuddy-lite-wb.js")。
|
|
500
|
+
* 命中后跑的是 lite-wb 裁剪包,强绑定桌面版身份,同样认证失败
|
|
501
|
+
* (日志 ProcessExit 调用栈落在 codebuddy-lite-wb.mjs)。
|
|
502
|
+
*
|
|
503
|
+
* 剥离策略:**前缀级 + 认证白名单**。桌面版实测注入 54 个 CODEBUDDY_* 变量
|
|
504
|
+
* (外加 WORKBUDDY_* / CLIENT_INFO_* / ACC_* / TENCENT_DOCS_LOCAL_* 各家族),
|
|
505
|
+
* 逐个人肉枚举是在打地鼠 —— FORCE_* 这对杀手就是枚举清单时代漏掉的。
|
|
506
|
+
*
|
|
507
|
+
* 判据(为什么这些前缀可以整族剥、为什么"全环境白名单"方向又是错的):
|
|
508
|
+
* 看"用户在自己的终端里跑 codebuddy 时环境里有没有它"。桌面版在拉起 g gui
|
|
509
|
+
* 或它的 sidecar 时注入的这几族变量,用户正常场景**全部不存在**;剥掉它们
|
|
510
|
+
* 只是把子进程环境对齐到"用户终端里的 codebuddy",不引入任何新偏差。
|
|
511
|
+
* 而 DB_* / pw / IMG_LIB 这类用户自己永久设置的变量不在这里剥。
|
|
512
|
+
* (反向的"只保留必需变量"白名单同样错:HTTP(S)_PROXY / NODE_EXTRA_CA_CERTS
|
|
513
|
+
* 这类网络变量是合法继承项,一刀切会把用户的代理环境也切没。)
|
|
514
|
+
*/
|
|
515
|
+
const CODEBUDDY_DESKTOP_ENV_PREFIXES = Object.freeze([
|
|
516
|
+
'CODEBUDDY_', // 运行时开关全家(认证白名单见 CODEBUDDY_ENV_KEEP)
|
|
517
|
+
'WORKBUDDY_', // 桌面版自家命名空间(含 PAC_RPC_TOKEN 等内部令牌)
|
|
518
|
+
'CLIENT_INFO_', // 桌面版客户端身份(PRODUCT_NAME=WorkBuddy / MACHINE_ID / UA 后缀)
|
|
519
|
+
'ACC_', // 产品配置注入(ACC_PRODUCT_CONFIG_PATH → workbuddy 产品 json)
|
|
520
|
+
'TENCENT_DOCS_LOCAL_', // 腾讯文档本地 MCP 地址注入
|
|
521
|
+
]);
|
|
522
|
+
|
|
523
|
+
/**
|
|
524
|
+
* 前缀剥离里**必须放行**的例外:官方文档的 headless 认证通道。
|
|
525
|
+
* 用户在终端里显式设置它们属于正当配置,g gui 继承用户环境 = 继承用户意图。
|
|
526
|
+
* 只放行有文档背书的这两个(其余几百个 CODEBUDDY_* 开关一律剥,理由见上)。
|
|
527
|
+
*/
|
|
528
|
+
const CODEBUDDY_ENV_KEEP = Object.freeze([
|
|
529
|
+
'CODEBUDDY_API_KEY',
|
|
530
|
+
'CODEBUDDY_BASE_URL',
|
|
531
|
+
]);
|
|
532
|
+
|
|
533
|
+
/**
|
|
534
|
+
* 不属于任何前缀、但同样只在桌面版会话里出现的单键(逐个人工核对过)。
|
|
535
|
+
* 归入同一份剥离清单,测试里逐键钉住。
|
|
536
|
+
*/
|
|
537
|
+
const CODEBUDDY_DESKTOP_ENV_KEYS = Object.freeze([
|
|
538
|
+
// 遥测 / 链路追踪:会把子会话的 trace 挂到桌面版那次会话下
|
|
539
|
+
'BAGGAGE', 'TRACEPARENT',
|
|
540
|
+
// 桌面版遥测 SDK 标记
|
|
541
|
+
'GALILEO_ENABLE', 'GALILEO_SDK_READY',
|
|
542
|
+
// 桌面版沙箱中心管道 / 网关服务地址(SERVER__PORT 与 SERVICE_PROXY_URL 同端口同源)
|
|
543
|
+
'SANDBOX_CENTER_IPC_ADDRESS', 'SERVER__HOST', 'SERVER__PORT',
|
|
544
|
+
// 桌面版运行时路径与 Electron 标记(EXEPATH=桌面版 PortableGit;GENIE_TRASH_DIR=桌面版垃圾箱)
|
|
545
|
+
'EXEPATH', 'GENIE_TRASH_DIR', 'ELECTRON_RUN_AS_NODE', 'ORIGINAL_XDG_CURRENT_DESKTOP',
|
|
546
|
+
]);
|
|
547
|
+
|
|
548
|
+
/**
|
|
549
|
+
* codebuddy 子进程环境。四个刻意为之的取舍:
|
|
550
|
+
* - LANG=zh_CN.UTF-8:与另三家一致(CLI 的提示词/输出跟随 locale)。
|
|
551
|
+
* - DISABLE_AUTOUPDATER=1:执行器场景**不允许 CLI 自我更新** —— 任务跑到一半
|
|
552
|
+
* 二进制被换掉,轻则行为漂移重则进程被杀。用户想更新自己跑 `codebuddy update`。
|
|
553
|
+
* - CODEBUDDY_CODE_DISABLE_BACKGROUND_TASKS=1:-p 单发模式进程随首个 result
|
|
554
|
+
* 结束,收不了后台任务的跨轮回推事件(官方文档对 SDK query() 单发用法也是
|
|
555
|
+
* 这么处理的)。禁掉之后模型的 run_in_background 参数从工具 schema 里隐藏,
|
|
556
|
+
* 不会出现"派了后台任务然后永远等不到通知"。
|
|
557
|
+
* - **剥掉桌面版注入的前缀族**(见上方注释的两个杀手 —— 不剥 CODEBUDDY_HOST
|
|
558
|
+
* 或 CODEBUDDY_FORCE_LITE_WB_BUNDLE 都会直接认证失败,2026-10-12 实测)。
|
|
559
|
+
* (导出仅为回归测试可见:taskRunner.codebuddy.test.js 钉住剥/留两侧的边界)
|
|
560
|
+
*/
|
|
561
|
+
export function buildCodebuddyEnv() {
|
|
562
|
+
const env = { ...process.env };
|
|
563
|
+
const keep = new Set(CODEBUDDY_ENV_KEEP);
|
|
564
|
+
for (const key of Object.keys(env)) {
|
|
565
|
+
if (keep.has(key)) continue;
|
|
566
|
+
if (CODEBUDDY_DESKTOP_ENV_KEYS.includes(key)) { delete env[key]; continue; }
|
|
567
|
+
if (CODEBUDDY_DESKTOP_ENV_PREFIXES.some((p) => key.startsWith(p))) delete env[key];
|
|
568
|
+
}
|
|
569
|
+
// 自己的三项在**剥离之后**设置:CODEBUDDY_CODE_DISABLE_BACKGROUND_TASKS 本身
|
|
570
|
+
// 命中 CODEBUDDY_ 前缀,若像从前那样先合并进来会被剥离循环顺手删掉。
|
|
571
|
+
env.LANG = 'zh_CN.UTF-8';
|
|
572
|
+
env.DISABLE_AUTOUPDATER = '1';
|
|
573
|
+
env.CODEBUDDY_CODE_DISABLE_BACKGROUND_TASKS = '1';
|
|
574
|
+
return env;
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
/**
|
|
578
|
+
* codebuddy 的 spawn argv(纯函数,抽出来为了能**真的跑断言**而不用 spawn 进程 ——
|
|
579
|
+
* 与 fileOpen.js 的 buildOpencodeArgs / buildCodexArgs 同一个理由。
|
|
580
|
+
*
|
|
581
|
+
* 口径见上方大注释。`--port 0` 是实测出来的必须项:CLI 自带引擎服务器占固定端口
|
|
582
|
+
* 62443,与 WorkBuddy 桌面版冲突,0 让 OS 选空闲端口(并发任务互不打架)。
|
|
583
|
+
*/
|
|
584
|
+
export function buildCodebuddyArgs(resumeSessionId) {
|
|
585
|
+
const args = [];
|
|
586
|
+
if (resumeSessionId) {
|
|
587
|
+
args.push('--resume', String(resumeSessionId));
|
|
588
|
+
}
|
|
589
|
+
args.push(
|
|
590
|
+
'-p',
|
|
591
|
+
'--output-format', 'stream-json',
|
|
592
|
+
'-y',
|
|
593
|
+
'--port', '0'
|
|
594
|
+
);
|
|
595
|
+
return args;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
/** spawn codebuddy 跑一个 prompt(非交互),返回 { pid, child }(参数口径见上方注释)。 */
|
|
599
|
+
export async function launchCodebuddyPrint(cwd, promptText, resumeSessionId) {
|
|
600
|
+
const args = buildCodebuddyArgs(resumeSessionId);
|
|
601
|
+
const { exe, prefixArgs } = resolveCodebuddyExe();
|
|
602
|
+
const spawnArgs = [...prefixArgs, ...args];
|
|
603
|
+
return new Promise((resolve, reject) => {
|
|
604
|
+
let child;
|
|
605
|
+
if (process.platform === 'win32') {
|
|
606
|
+
child = spawn(exe, spawnArgs, {
|
|
607
|
+
cwd,
|
|
608
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
609
|
+
windowsHide: false,
|
|
610
|
+
env: buildCodebuddyEnv()
|
|
611
|
+
});
|
|
612
|
+
} else {
|
|
613
|
+
child = spawn(exe, spawnArgs, {
|
|
614
|
+
cwd,
|
|
615
|
+
detached: true,
|
|
616
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
617
|
+
env: buildCodebuddyEnv()
|
|
618
|
+
});
|
|
619
|
+
}
|
|
620
|
+
attachPromptStdin(child, promptText, resolve, reject);
|
|
621
|
+
});
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
/**
|
|
625
|
+
* codebuddy stream-json 事件处理器。
|
|
626
|
+
*
|
|
627
|
+
* **协议与 claude 逐字段对齐**(2026-10-12 实测:init/assistant/user/result 四种
|
|
628
|
+
* 事件、content 块的 text/thinking/tool_use、user 事件里的 tool_result 回指,
|
|
629
|
+
* 全部同构;工具调用同样是"先 tool_use(running)、后 user(tool_result)"两条)。
|
|
630
|
+
* 所以这里刻意**另写一份**而不是直接复用 createClaudeEventHandler:
|
|
631
|
+
* 对齐是实测结论、不是合同 —— cbc 还多出 system/status、ai-title 等自有事件,
|
|
632
|
+
* 将来协议分叉时在这里修,不会顺带改坏 claude 那条链路(本仓库对"同一份口径
|
|
633
|
+
* 多处实现"的失效方式有惨痛记忆:不报错,只是悄悄少一半数据)。
|
|
634
|
+
*
|
|
635
|
+
* 已知被忽略的事件:system/status、system/task_*(后台任务,已被
|
|
636
|
+
* CODEBUDDY_CODE_DISABLE_BACKGROUND_TASKS 禁用)、ai-title、result。
|
|
637
|
+
* (导出仅为回归测试可见:taskRunner.codebuddy.test.js)
|
|
638
|
+
*/
|
|
639
|
+
export function createCodebuddyEventHandler(job, appendOutput, appendThinking, toolCalls) {
|
|
640
|
+
const tracker = toolCalls || createToolCallTracker(job);
|
|
641
|
+
return (evt) => {
|
|
642
|
+
if (!evt || typeof evt !== 'object') return;
|
|
643
|
+
// init:session_id 落 job.claudeSessionId(--resume 续接用)
|
|
644
|
+
if (evt.type === 'system' && evt.subtype === 'init' && typeof evt.session_id === 'string') {
|
|
645
|
+
if (!job.claudeSessionId || job.claudeSessionId !== evt.session_id) {
|
|
646
|
+
job.claudeSessionId = evt.session_id;
|
|
647
|
+
publish('job:update', job);
|
|
648
|
+
}
|
|
649
|
+
return;
|
|
650
|
+
}
|
|
651
|
+
// 工具结果:与 claude 完全同构 —— user 事件的 content 是块数组,
|
|
652
|
+
// 里面才是 tool_result(用户自己那条 prompt 的 content 是字符串,不会走到这)
|
|
653
|
+
if (evt.type === 'user') {
|
|
654
|
+
const ublocks = evt.message?.content;
|
|
655
|
+
if (Array.isArray(ublocks)) {
|
|
656
|
+
for (const b of ublocks) {
|
|
657
|
+
if (b && b.type === 'tool_result' && b.tool_use_id) {
|
|
658
|
+
const text = extractToolText(b.content);
|
|
659
|
+
tracker.record({
|
|
660
|
+
id: b.tool_use_id,
|
|
661
|
+
status: b.is_error ? 'error' : 'done',
|
|
662
|
+
output: text,
|
|
663
|
+
error: b.is_error ? (text || '工具执行失败') : ''
|
|
664
|
+
});
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
return;
|
|
669
|
+
}
|
|
670
|
+
if (evt.type !== 'assistant') return;
|
|
671
|
+
const blocks = evt.message?.content;
|
|
672
|
+
if (!Array.isArray(blocks)) return;
|
|
673
|
+
for (const b of blocks) {
|
|
674
|
+
if (b.type === 'text' && typeof b.text === 'string') {
|
|
675
|
+
appendOutput(b.text);
|
|
676
|
+
} else if (b.type === 'thinking' && typeof b.thinking === 'string') {
|
|
677
|
+
appendThinking(b.thinking);
|
|
678
|
+
} else if (b.type === 'tool_use') {
|
|
679
|
+
tracker.record({ id: b.id, name: b.name, input: b.input, status: 'running' });
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
};
|
|
683
|
+
}
|
|
684
|
+
|
|
393
685
|
// ── 工具调用(tool_use)收集 ──────────────────────────────────────────────
|
|
394
686
|
// 为什么要有这一层:job.output 只承载「模型说的话」。工具调用(读了哪个文件、跑了什么命令、
|
|
395
687
|
// 拿到了什么结果)原本在两个事件处理器里被整段丢掉,于是前端只剩「思考 + 正文」两块,
|
|
@@ -901,10 +1193,10 @@ export function createCodexEventHandler(job, appendOutput, appendThinking, toolC
|
|
|
901
1193
|
* @param {object} [options]
|
|
902
1194
|
* @param {string|null} [options.resumeSessionId]
|
|
903
1195
|
* 续接历史会话:claude 走 --resume <id>,opencode 走 --session <id>,
|
|
904
|
-
* codex 走 exec resume <thread_id>。
|
|
905
|
-
* id 来自上一轮 stream 事件捕获的会话标识(
|
|
1196
|
+
* codex 走 exec resume <thread_id>,codebuddy 走 --resume <session_id>。
|
|
1197
|
+
* id 来自上一轮 stream 事件捕获的会话标识(四家都记在 job.claudeSessionId)。
|
|
906
1198
|
* @param {string} [options.executor]
|
|
907
|
-
* 执行器 'claude' | 'opencode' | 'codex'。缺省回落 'claude';路由层负责把
|
|
1199
|
+
* 执行器 'claude' | 'opencode' | 'codex' | 'codebuddy'。缺省回落 'claude';路由层负责把
|
|
908
1200
|
* "body 指定 > 配置默认"先解析好再传进来。
|
|
909
1201
|
* @returns {Promise<'done'|'cancelled'|'error'>} 本次运行的终态
|
|
910
1202
|
*/
|
|
@@ -990,8 +1282,8 @@ export async function runSingleSubtask(task, sub, repoPath, branch, options) {
|
|
|
990
1282
|
// 路由层用它保证"用同一个 CLI 续同一个会话"。
|
|
991
1283
|
agent: executor,
|
|
992
1284
|
// 续接历史会话时先填上,首条协议事件回来后再用真值覆盖(通常等同)。
|
|
993
|
-
// 字段名保留 claudeSessionId:claude 的 session_id
|
|
994
|
-
// 都存这里,语义是"该执行器的会话续接标识"。
|
|
1285
|
+
// 字段名保留 claudeSessionId:claude 的 session_id / opencode 的 sessionID /
|
|
1286
|
+
// codebuddy 的 session_id 都存这里,语义是"该执行器的会话续接标识"。
|
|
995
1287
|
claudeSessionId: resumeSessionId,
|
|
996
1288
|
// 工具调用流水({id,name,argsPreview,arguments,result,status,error}[])。
|
|
997
1289
|
// 先给个空数组,前端拿到的 job:update 就有了稳定形态,不用到处判 undefined。
|
|
@@ -1013,11 +1305,9 @@ export async function runSingleSubtask(task, sub, repoPath, branch, options) {
|
|
|
1013
1305
|
let toolTracker = null;
|
|
1014
1306
|
|
|
1015
1307
|
try {
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
? launchCodexExec
|
|
1020
|
-
: launchClaudeInNewWindow;
|
|
1308
|
+
// 查表而不是 if 链:加执行器只改 EXECUTOR_LAUNCHERS 一张表(四家以后 if 链
|
|
1309
|
+
// 已经长得该收了)。查无此人理论上不可能 —— normalizeTaskExecutor 刚夹过一遍。
|
|
1310
|
+
const launcher = EXECUTOR_LAUNCHERS[executor] || launchClaudeInNewWindow;
|
|
1021
1311
|
const { pid, child } = await launcher(repoPath || process.cwd(), prompt, resumeSessionId);
|
|
1022
1312
|
job.pid = pid;
|
|
1023
1313
|
// 保存 child 引用,供 cancel 接口调用 kill
|
|
@@ -1074,11 +1364,8 @@ export async function runSingleSubtask(task, sub, repoPath, branch, options) {
|
|
|
1074
1364
|
publish('job:toolcalls', { id: job.id, updates });
|
|
1075
1365
|
});
|
|
1076
1366
|
|
|
1077
|
-
const
|
|
1078
|
-
|
|
1079
|
-
: executor === 'codex'
|
|
1080
|
-
? createCodexEventHandler(job, appendOutput, appendThinking, toolTracker)
|
|
1081
|
-
: createClaudeEventHandler(job, appendOutput, appendThinking, toolTracker);
|
|
1367
|
+
const makeHandler = EXECUTOR_HANDLERS[executor] || createClaudeEventHandler;
|
|
1368
|
+
const handleEvent = makeHandler(job, appendOutput, appendThinking, toolTracker);
|
|
1082
1369
|
|
|
1083
1370
|
const handleLine = (line, channel) => {
|
|
1084
1371
|
const trimmed = line.trim();
|
|
@@ -54,9 +54,10 @@ function makeSink() {
|
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
test('normalizeTaskExecutor:白名单 + 大小写 + 非法回落', () => {
|
|
57
|
-
assert.deepEqual(TASK_EXECUTORS, ['claude', 'opencode', 'codex']);
|
|
57
|
+
assert.deepEqual(TASK_EXECUTORS, ['claude', 'opencode', 'codex', 'codebuddy']);
|
|
58
58
|
assert.equal(normalizeTaskExecutor('opencode'), 'opencode');
|
|
59
59
|
assert.equal(normalizeTaskExecutor('codex'), 'codex');
|
|
60
|
+
assert.equal(normalizeTaskExecutor('codebuddy'), 'codebuddy');
|
|
60
61
|
// 大小写不敏感(存储前统一小写)
|
|
61
62
|
assert.equal(normalizeTaskExecutor('OpenCode'), 'opencode');
|
|
62
63
|
assert.equal(normalizeTaskExecutor('opencode '), 'opencode');
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// Copyright 2026 xz333221
|
|
2
|
+
//
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
// You may obtain a copy of the License at
|
|
6
|
+
//
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
//
|
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
// See the License for the specific language governing permissions and
|
|
13
|
+
// limitations under the License.
|
|
14
|
+
//
|
|
15
|
+
// 「从远程地址推导仓库目录名」的唯一实现。
|
|
16
|
+
//
|
|
17
|
+
// 两处调用方:GUI 的克隆路由(/api/clone 决定 clone 出来的子目录名)与 g ai 的
|
|
18
|
+
// run_command 后处理(把 git clone 的落点登记进常用目录时,地址里没写目标目录,
|
|
19
|
+
// 只能按仓库名猜)。两边口径必须一致 —— 否则"认为克隆到了 A、实际在 B"。
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* 从远程地址里取出仓库目录名(clone 出来的子目录就用它)。
|
|
23
|
+
* git@github.com:owner/repo.git → repo
|
|
24
|
+
* https://gitee.com/owner/repo.git → repo
|
|
25
|
+
* https://github.com/owner/repo/ → repo
|
|
26
|
+
* 取不出来返回空串,调用方兜底成 repository。
|
|
27
|
+
*/
|
|
28
|
+
export function repoNameFromUrl(url) {
|
|
29
|
+
const s = String(url || '').trim().replace(/\/+$/, '')
|
|
30
|
+
if (!s) return ''
|
|
31
|
+
const tail = s.split(/[/:]/).filter(Boolean).pop() || ''
|
|
32
|
+
return tail.replace(/\.git$/i, '')
|
|
33
|
+
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import"./rolldown-runtime-C0FnF6B9.js";import{$r as e,$t as t,An as n,At as r,Ct as i,Dn as a,Dr as o,En as s,Fn as c,Fr as l,Gn as u,Gt as d,Ht as f,J as p,Jn as m,Jr as h,Jt as g,Ln as _,M as v,On as y,Pn as b,Qn as x,Sn as S,Tt as C,Vn as w,W as T,Xn as E,Xr as D,Yt as O,_n as k,a as ee,an as te,dn as A,er as j,et as M,gn as N,i as P,j as ne,kn as F,kt as I,lr as L,lt as re,mn as R,mr as z,mt as ie,r as B,rr as V,sr as H,st as U,tt as W,ur as G,vn as K,xr as q,yr as ae}from"./element-plus-J45pKUrE.js";import{a as J,r as oe}from"./vendor-B3NyhlYR.js";import{n as Y,t as X}from"./_plugin-vue_export-helper-C3o7kvRL.js";import{t as se}from"./configStore-BdL3uW2E.js";import{t as ce}from"./CommonDialog-x5jfL4Lq.js";import{G as Z,W as le,v as ue}from"./index-BS7BDFG4.js";import{a as de,c as fe,i as pe,l as me,n as he,o as ge,p as _e,r as ve,s as ye,t as be,u as xe}from"./agentConversations-DpiGplZB.js";import{c as Se,s as Ce,t as we}from"./CopySessionButton-D0wFpk8a.js";import{t as Te}from"./useOrchestrator-CS9sn7nV.js";w(),z(),A(),l();var Ee={class:`marketplace-panel`},De={class:`mp-toolbar`},Oe={class:`mp-search`},ke=[`placeholder`],Ae={class:`mp-toolbar-sub`},je={class:`mp-target-hint`},Me={class:`mp-source-filter`},Ne=[`onClick`],Pe={class:`mp-body`},Fe={class:`mp-group-header`},Ie={class:`mp-group-title`},Le={key:0,class:`mp-group-count`},Re={key:1,class:`mp-group-error`},ze=[`href`,`title`],Be={key:0,class:`mp-grid`},Ve={class:`mp-card-head`},He=[`title`],Ue={key:0,class:`mp-card-metric`},We=[`title`],Ge={class:`mp-card-meta`},Ke=[`title`],qe=[`title`],Je={key:2,class:`mp-tag remote`},Ye={class:`mp-card-foot`},Xe=[`href`],Ze={key:1,class:`mp-installed-chip`},Qe=[`disabled`,`onClick`],$e={key:3,class:`mp-not-installable`},et={key:1,class:`mp-empty`},tt={key:0,class:`mp-group installed`},nt={class:`mp-group-header`},rt={class:`mp-group-title`},it={class:`mp-group-count`},at={key:0,class:`mp-installed-block`},ot={class:`mp-installed-target`},st={class:`mp-installed-list`},ct=[`title`],lt=[`title`],ut={key:1,class:`mp-meta-pkg`},dt={key:2,class:`mp-tag warn`},ft=[`disabled`,`title`,`onClick`],pt=[`disabled`,`onClick`],mt={key:1,class:`mp-empty all`},ht={key:0,class:`mkt-form`},gt={class:`mkt-form-name`},_t=[`onUpdate:modelValue`,`placeholder`],vt={key:0,class:`mkt-field`},yt={class:`mkt-hint`},bt=X(_({__name:`MarketplacePanel`,props:{type:{}},setup(t){let r=t,l=se(),u=q([]),m=q([]),g=q(!1),_=q(``),C=q(``),w=q([]),E=q(`project`),D=q(new Set),k=q(new Set),A=q(new Set),M=s(()=>l.currentDirectory||``),N=null;async function R(){if(!g.value){g.value=!0;try{let e=new URLSearchParams({type:r.type,cwd:M.value});C.value&&e.set(`q`,C.value),w.value.length&&e.set(`sources`,w.value.join(`,`));let t=await(await fetch(`/api/agent/marketplace/catalog?${e}`)).json();t?.success?(u.value=t.groups||[],m.value=t.installed||[]):P.error(t?.error||Y(`@MKT:加载失败`))}catch{P.error(Y(`@MKT:加载失败`))}finally{g.value=!1}}}H(_,e=>{N&&clearTimeout(N),N=setTimeout(()=>{C.value=e.trim(),R()},400)}),H(w,()=>R()),H(()=>r.type,()=>{w.value=[],C.value=``,_.value=``,R()}),H(M,()=>R()),R();let z=s(()=>{let e=M.value?M.value.split(/[\\/]/).filter(Boolean).pop():``;return E.value===`project`?e||Y(`@MKT:当前项目`):Y(`@MKT:g ai 智能体`)});function V(e){return e.stars?`${U(e.stars)} ★`:e.downloads?`${U(e.downloads)} ${Y(`@MKT:周下载`)}`:e.uses?`${U(e.uses)} ${Y(`@MKT:次使用`)}`:``}function U(e){return e>=1e3?`${(e/1e3).toFixed(e>=1e4?0:1)}k`:String(e)}function J(e){return`${e.id}`}function oe(e){return D.value.has(J(e))}let X=s(()=>{let e={project:[],global:[]};for(let t of m.value)(e[t.target]||=[]).push(t);return e}),Z=ae({visible:!1,item:null,env:{},args:``});function le(e){return r.type===`mcp`&&(!!e.envKeys?.length||!!e.args?.length)}function ue(e){Z.item=e,Z.env=Object.fromEntries((e.envKeys||[]).map(e=>[e,``])),Z.args=(e.args||[]).join(` `),Z.visible=!0}function de(){let e=Z.item;if(Z.visible=!1,!e)return;let t=Object.fromEntries(Object.entries(Z.env).filter(([,e])=>e.trim()!==``)),n=Z.args.trim()?Z.args.trim().match(/(?:[^\s"]+|"[^"]*")+/g)?.map(e=>e.replace(/^"|"$/g,``))??void 0:void 0;pe(e,{env:t,...n?{args:n}:{}})}async function fe(e){if(!e.installed||await me(e)){if(le(e)){ue(e);return}await pe(e,{})}}async function pe(e,t){let n=J(e);D.value.add(n);try{let n=await fetch(`/api/agent/marketplace/install`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({type:r.type,target:E.value,cwd:M.value,item:{...e,...t}})}),i=await n.json().catch(()=>null);if(!n.ok||!i?.success){P.error(i?.error||Y(`@MKT:安装失败`));return}i.item?.warning&&P.warning(i.item.warning),i.item?.envKeys?.length?P.warning(`${Y(`@MKT:还缺环境变量`)}: ${i.item.envKeys.join(`, `)}`):P.success(Y(`@MKT:安装成功`)),await R()}catch{P.error(Y(`@MKT:安装失败`))}finally{D.value.delete(n)}}async function me(e){try{return await B.confirm(`${e.name} ${Y(`@MKT:已安装,要重新安装吗?`)}`,Y(`@MKT:重新安装`),{confirmButtonText:Y(`@MKT:重装`),cancelButtonText:Y(`@MKT:取消`),type:`warning`}),!0}catch{return!1}}async function he(e){let t=`${e.target}:${e.id}`;A.value.add(t);try{let t=await fetch(`/api/agent/marketplace/reveal`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({type:r.type,target:e.target,cwd:M.value,id:e.id})}),n=await t.json().catch(()=>null);(!t.ok||!n?.success)&&P.error(n?.error||Y(`@MKT:打开失败`))}catch{P.error(Y(`@MKT:打开失败`))}finally{A.value.delete(t)}}async function ge(e){try{await B.confirm(`${Y(`@MKT:确定卸载`)} ${e.name}?`,Y(`@MKT:卸载`),{confirmButtonText:Y(`@MKT:卸载`),cancelButtonText:Y(`@MKT:取消`),type:`warning`})}catch{return}let t=`${e.target}:${e.id}`;k.value.add(t);try{let t=new URLSearchParams({target:e.target,cwd:M.value}),n=await fetch(`/api/agent/marketplace/item/${r.type}/${encodeURIComponent(e.id)}?${t}`,{method:`DELETE`}),i=await n.json().catch(()=>null);if(!n.ok||!i?.success){P.error(i?.error||Y(`@MKT:卸载失败`));return}P.success(Y(`@MKT:已卸载`)),await R()}catch{P.error(Y(`@MKT:卸载失败`))}finally{k.value.delete(t)}}return(r,s)=>{let l=p,C=ne,D=v,M=T,N=ee;return x(),n(`div`,Ee,[a(`div`,De,[a(`div`,Oe,[c(l,{class:`mp-search-icon`},{default:L(()=>[c(o(d))]),_:1}),G(a(`input`,{"onUpdate:modelValue":s[0]||=e=>_.value=e,class:`mp-search-input`,type:`text`,placeholder:t.type===`skill`?o(Y)(`@MKT:搜索 Skill...`):o(Y)(`@MKT:搜索 MCP 服务...`)},null,8,ke),[[K,_.value]])]),c(D,{modelValue:E.value,"onUpdate:modelValue":s[1]||=e=>E.value=e,size:`small`,class:`mp-target`},{default:L(()=>[c(C,{value:`project`},{default:L(()=>[b(e(o(Y)(`@MKT:当前项目`)),1)]),_:1}),c(C,{value:`global`},{default:L(()=>[b(e(o(Y)(`@MKT:g ai 智能体`)),1)]),_:1})]),_:1},8,[`modelValue`]),c(M,{content:o(Y)(`@MKT:刷新`),placement:`top`,"show-after":300},{default:L(()=>[a(`button`,{class:h([`mp-refresh`,{spinning:g.value}]),onClick:R},[c(l,null,{default:L(()=>[c(o(f))]),_:1})],2)]),_:1},8,[`content`])]),a(`div`,Ae,[a(`span`,je,[b(e(o(Y)(`@MKT:安装到`))+` `,1),a(`b`,null,e(z.value),1)]),a(`div`,Me,[(x(!0),n(S,null,j(u.value,t=>(x(),n(`button`,{key:t.id,class:h([`mp-chip`,{active:w.value.includes(t.id)}]),onClick:()=>{let e=w.value.indexOf(t.id);e>=0?w.value.splice(e,1):w.value.push(t.id)}},e(t.label),11,Ne))),128)),w.value.length?(x(),n(`button`,{key:0,class:`mp-chip clear`,onClick:s[2]||=e=>w.value=[]},e(o(Y)(`@MKT:全部来源`)),1)):F(``,!0)])]),G((x(),n(`div`,Pe,[(x(!0),n(S,null,j(u.value,t=>(x(),n(`section`,{key:t.id,class:`mp-group`},[a(`header`,Fe,[a(`h3`,Ie,e(t.label),1),t.status===`ok`?(x(),n(`span`,Le,e(t.items.length),1)):(x(),n(`span`,Re,[c(l,null,{default:L(()=>[c(o(te))]),_:1}),b(` `+e(t.error||o(Y)(`@MKT:来源不可用`)),1)])),t.homepage?(x(),n(`a`,{key:2,class:`mp-group-link`,href:t.homepage,target:`_blank`,rel:`noopener noreferrer`,title:t.homepage},[c(l,null,{default:L(()=>[c(o(I))]),_:1})],8,ze)):F(``,!0)]),t.status===`ok`&&t.items.length?(x(),n(`div`,Be,[(x(!0),n(S,null,j(t.items,t=>(x(),n(`article`,{key:J(t),class:`mp-card`},[a(`div`,Ve,[a(`span`,{class:`mp-card-name`,title:t.name},e(t.name),9,He),V(t)?(x(),n(`span`,Ue,[c(l,null,{default:L(()=>[t.stars?(x(),y(o(O),{key:0})):(x(),y(o(ie),{key:1}))]),_:2},1024),b(` `+e(V(t)),1)])):F(``,!0)]),a(`p`,{class:`mp-card-desc`,title:t.description},e(t.description||o(Y)(`@MKT:暂无描述`)),9,We),a(`div`,Ge,[t.package?(x(),n(`code`,{key:0,class:`mp-meta-pkg`,title:t.package},e(t.package),9,Ke)):t.repository?(x(),n(`span`,{key:1,class:`mp-meta-repo`,title:t.repository+(t.subpath?` · `+t.subpath:``)},[b(e(t.repository),1),t.subpath?(x(),n(S,{key:0},[b(` · `+e(t.subpath),1)],64)):F(``,!0)],8,qe)):F(``,!0),t.transport===`remote`?(x(),n(`span`,Je,e(o(Y)(`@MKT:远程服务`)),1)):F(``,!0),(x(!0),n(S,null,j((t.tags||[]).slice(0,2),t=>(x(),n(`span`,{key:t,class:`mp-tag`},e(t),1))),128))]),a(`div`,Ye,[t.upstream?(x(),n(`a`,{key:0,class:`mp-card-link`,href:t.upstream,target:`_blank`,rel:`noopener noreferrer`},e(o(Y)(`@MKT:查看来源`)),9,Xe)):F(``,!0),s[6]||=a(`span`,{class:`mp-foot-spacer`},null,-1),t.installed?(x(),n(`span`,Ze,[c(l,null,{default:L(()=>[c(o(W))]),_:1}),b(e(o(Y)(`@MKT:已安装`)),1)])):t.installable===!1?(x(),n(`span`,$e,e(o(Y)(`@MKT:暂不支持一键安装`)),1)):(x(),n(`button`,{key:2,class:`mp-install-btn`,disabled:oe(t),onClick:e=>fe(t)},e(oe(t)?o(Y)(`@MKT:安装中...`):o(Y)(`@MKT:安装`)),9,Qe))])]))),128))])):t.status===`ok`?(x(),n(`div`,et,e(o(Y)(`@MKT:该来源暂无结果`)),1)):F(``,!0)]))),128)),m.value.length?(x(),n(`section`,tt,[a(`header`,nt,[a(`h3`,rt,e(o(Y)(`@MKT:已安装`)),1),a(`span`,it,e(m.value.length),1)]),(x(),n(S,null,j([`project`,`global`],t=>a(`div`,{key:t},[X.value[t]?.length?(x(),n(`div`,at,[a(`div`,ot,e(t===`project`?o(Y)(`@MKT:当前项目`):o(Y)(`@MKT:g ai 智能体`)),1),a(`div`,st,[(x(!0),n(S,null,j(X.value[t],r=>(x(),n(`div`,{key:t+r.id,class:`mp-installed-row`},[a(`span`,{class:`mp-installed-name`,title:r.name},e(r.name),9,ct),r.id&&r.id!==r.name?(x(),n(`code`,{key:0,class:`mp-installed-id`,title:r.dir||r.file||r.id},e(r.id),9,lt)):F(``,!0),r.package?(x(),n(`code`,ut,e(r.package),1)):F(``,!0),r.requiredEnv?.length?(x(),n(`span`,dt,e(o(Y)(`@MKT:待配置`))+`: `+e(r.requiredEnv.join(`, `)),1)):F(``,!0),s[7]||=a(`span`,{class:`mp-foot-spacer`},null,-1),a(`button`,{class:`mp-reveal-btn`,disabled:A.value.has(t+r.id),title:r.dir||r.file||``,onClick:e=>he(r)},[c(l,null,{default:L(()=>[c(o(i))]),_:1}),b(` `+e(o(Y)(`@MKT:打开文件夹`)),1)],8,ft),a(`button`,{class:`mp-remove-btn`,disabled:k.value.has(t+r.id),onClick:e=>ge(r)},[c(l,null,{default:L(()=>[c(o(re))]),_:1}),b(` `+e(k.value.has(t+r.id)?o(Y)(`@MKT:卸载中...`):o(Y)(`@MKT:卸载`)),1)],8,pt)]))),128))])])):F(``,!0)])),64))])):F(``,!0),!g.value&&!u.value.length?(x(),n(`div`,mt,e(o(Y)(`@MKT:加载失败`)),1)):F(``,!0)])),[[N,g.value]]),c(ce,{modelValue:Z.visible,"onUpdate:modelValue":s[5]||=e=>Z.visible=e,title:o(Y)(`@MKT:配置 MCP`),width:`460px`,type:`flex`,"close-on-click-modal":!1,"append-to-body":``},{footer:L(()=>[a(`button`,{class:`mkt-cancel`,onClick:s[4]||=e=>Z.visible=!1},e(o(Y)(`@MKT:取消`)),1),a(`button`,{class:`mkt-confirm`,onClick:de},e(o(Y)(`@MKT:安装`)),1)]),default:L(()=>[Z.item?(x(),n(`div`,ht,[a(`p`,gt,e(Z.item.name),1),(x(!0),n(S,null,j(Object.keys(Z.env),t=>(x(),n(`div`,{key:t,class:`mkt-field`},[a(`label`,null,e(t),1),G(a(`input`,{"onUpdate:modelValue":e=>Z.env[t]=e,type:`text`,autocomplete:`off`,placeholder:o(Y)(`@MKT:环境变量值`),spellcheck:`false`},null,8,_t),[[K,Z.env[t]]])]))),128)),Z.item.args?.length?(x(),n(`div`,vt,[a(`label`,null,e(o(Y)(`@MKT:启动参数`)),1),G(a(`input`,{"onUpdate:modelValue":s[3]||=e=>Z.args=e,type:`text`,autocomplete:`off`,spellcheck:`false`},null,512),[[K,Z.args]]),a(`p`,yt,e(o(Y)(`@MKT:参数提示`)),1)])):F(``,!0)])):F(``,!0)]),_:1},8,[`modelValue`,`title`])])}}}),[[`__scopeId`,`data-v-536d7952`]]);async function Q(e,t){let n=await fetch(e,{headers:{"Content-Type":`application/json`},...t}),r={};try{r=await n.json()}catch{}if(!n.ok||r.success===!1)throw Error(r.error||`请求失败 (${n.status})`);return r}async function xt(){let e=await Q(`/api/schedules`);return Array.isArray(e.tasks)?e.tasks:[]}async function St(e){return(await Q(`/api/schedules`,{method:`POST`,body:JSON.stringify(e)})).task}async function Ct(e,t){return(await Q(`/api/schedules/${encodeURIComponent(e)}`,{method:`PUT`,body:JSON.stringify(t)})).task}async function wt(e){await Q(`/api/schedules/${encodeURIComponent(e)}`,{method:`DELETE`})}async function Tt(e){await Q(`/api/schedules/${encodeURIComponent(e)}/run`,{method:`POST`})}async function Et(e){await Q(`/api/schedules/${encodeURIComponent(e)}/stop`,{method:`POST`})}function Dt(e){if(typeof EventSource>`u`)return()=>{};let t=new EventSource(`/api/schedules/events`);return t.onmessage=t=>{try{e(JSON.parse(t.data))}catch{}},()=>t.close()}var Ot=e=>/^\d+$/.test(e)?Number(e):null;function kt(e){let t=String(e||``).trim(),n=t.split(/\s+/);if(n.length!==5)return{kind:`custom`,raw:t};let[r,i,a,o,s]=n,c=Ot(r),l=Ot(i);if(t===`* * * * *`)return{kind:`every-minute`,raw:t};let u=r.match(/^\*\/(\d+)$/);if(u&&i===`*`&&a===`*`&&o===`*`&&s===`*`)return{kind:`every-n-minutes`,n:Number(u[1]),raw:t};if(c!==null&&i===`*`&&a===`*`&&o===`*`&&s===`*`)return{kind:`hourly`,minute:c,raw:t};if(c!==null&&l!==null&&a===`*`&&o===`*`&&s===`*`)return{kind:`daily`,hour:l,minute:c,raw:t};let d=Ot(s);if(c!==null&&l!==null&&a===`*`&&o===`*`&&d!==null)return{kind:`weekly`,weekday:d%7,hour:l,minute:c,raw:t};let f=Ot(a);return c!==null&&l!==null&&f!==null&&o===`*`&&s===`*`?{kind:`monthly`,day:f,hour:l,minute:c,raw:t}:{kind:`custom`,raw:t}}var $=e=>String(e).padStart(2,`0`),At=e=>new Date(e.getFullYear(),e.getMonth(),e.getDate()).getTime();function jt(e,t=new Date){if(!e)return{kind:`none`};let n=new Date(e);if(Number.isNaN(n.getTime()))return{kind:`none`};let r=`${$(n.getHours())}:${$(n.getMinutes())}`,i=Math.round((At(n)-At(t))/864e5);return i<0?{kind:`date`,date:`${n.getMonth()+1}-${$(n.getDate())}`,time:r}:i===0?{kind:`today`,time:r}:i===1?{kind:`tomorrow`,time:r}:i<7?{kind:`weekday`,weekday:n.getDay(),time:r}:{kind:`date`,date:`${n.getMonth()+1}-${$(n.getDate())}`,time:r}}function Mt(e){switch(e){case`ok`:return`ok`;case`error`:case`timed-out`:return`error`;case`skipped-busy`:case`missed`:case`cancelled`:return`skipped`;default:return`pending`}}function Nt(e){let t=Number(e);if(!Number.isFinite(t)||t<0)return``;if(t<1e3)return`<1s`;let n=Math.round(t/1e3);if(n<60)return`${n}s`;let r=Math.floor(n/60);return r<60?`${r}m${$(n%60)}s`:`${Math.floor(r/60)}h${$(r%60)}m`}function Pt(e){let t=Math.min(59,Math.max(0,Math.floor(e.minute))),n=Math.min(23,Math.max(0,Math.floor(e.hour))),r=(Math.floor(e.weekday)%7+7)%7;switch(e.freq){case`minutes`:return`*/${Math.min(59,Math.max(1,Math.floor(e.everyMinutes??30)))} * * * *`;case`hourly`:return`${t} * * * *`;case`daily`:return`${t} ${n} * * *`;case`weekly`:return`${t} ${n} * * ${r}`;case`custom`:return String(e.custom||``).trim()}}w(),l(),z(),A();var Ft={class:`schedule-panel`},It={class:`schedule-toolbar`},Lt={class:`schedule-summary`},Rt={key:0,class:`schedule-error`},zt={key:1,class:`schedule-loading`},Bt={key:2,class:`schedule-empty`},Vt={class:`schedule-empty-title`},Ht={class:`schedule-empty-desc`},Ut={key:3,class:`schedule-list`},Wt={class:`schedule-card-body`},Gt={class:`schedule-card-head`},Kt={class:`schedule-name`},qt={key:0,class:`schedule-running`},Jt=[`aria-checked`,`aria-label`,`onClick`],Yt={class:`schedule-card-sub`},Xt={class:`schedule-desc`},Zt=[`onClick`],Qt={class:`schedule-card-side`},$t={class:`schedule-actions`},en=[`disabled`,`onClick`],tn=[`disabled`,`onClick`],nn=[`onClick`],rn=[`onClick`],an={class:`sch-form`},on={class:`sch-field`},sn={class:`sch-field-label`},cn=[`placeholder`],ln={class:`sch-field`},un={class:`sch-field-label`},dn={class:`sch-freq-row`},fn=[`value`],pn={class:`sch-inline-label`},mn=[`value`],hn={class:`sch-inline-label`},gn=[`value`],_n=[`value`],vn=[`value`],yn={class:`sch-inline-label`},bn=[`value`],xn={class:`sch-inline-label`},Sn=[`placeholder`],Cn={class:`sch-hint`},wn={class:`sch-field`},Tn={class:`sch-field-label`},En=[`placeholder`],Dn={class:`sch-field`},On={class:`sch-field-label`},kn=[`placeholder`],An={class:`sch-field`},jn={class:`sch-field-label`},Mn={class:`sch-radio-row`},Nn={class:`sch-radio`},Pn={class:`sch-radio`},Fn={class:`sch-radio`},In={key:0,class:`sch-form-error`},Ln={class:`sch-form-footer`},Rn=[`disabled`],zn={class:`sch-confirm-text`},Bn={class:`sch-form-footer`},Vn=X(_({__name:`SchedulePanel`,emits:[`open-session`],setup(t,{emit:r}){let i=r,l=se(),u=q([]),d=q(!0),f=q(``),p=q({}),g=null,_=null;async function v(){try{u.value=await xt(),f.value=``}catch(e){f.value=e?.message||String(e)}finally{d.value=!1}}function y(){_===null&&(_=window.setTimeout(()=>{_=null,v()},150))}E(async()=>{await v(),g=Dt(e=>{[`tasks_changed`,`task_started`,`task_finished`,`hello`].includes(e.type)&&y()})}),m(()=>{g?.(),_!==null&&window.clearTimeout(_)});let b=s(()=>{let e=u.value.filter(e=>e.enabled).length,t=u.value.length-e;return u.value.length?Y(`@SCHED:{on} 个启用 · {off} 个停用`,{on:e,off:t}):``}),C=[`@SCHED:周日`,`@SCHED:周一`,`@SCHED:周二`,`@SCHED:周三`,`@SCHED:周四`,`@SCHED:周五`,`@SCHED:周六`];function w(e){let t=kt(e.schedule);switch(t.kind){case`every-minute`:return Y(`@SCHED:每分钟`);case`every-n-minutes`:return Y(`@SCHED:每 {n} 分钟`,{n:t.n});case`hourly`:return Y(`@SCHED:每小时第 {minute} 分钟`,{minute:t.minute});case`daily`:return Y(`@SCHED:每天 {time}`,{time:`${String(t.hour).padStart(2,`0`)}:${String(t.minute).padStart(2,`0`)}`});case`weekly`:return Y(`@SCHED:每周 {weekday} {time}`,{weekday:Y(C[t.weekday]),time:`${String(t.hour).padStart(2,`0`)}:${String(t.minute).padStart(2,`0`)}`});case`monthly`:return Y(`@SCHED:每月 {day} 日 {time}`,{day:t.day,time:`${String(t.hour).padStart(2,`0`)}:${String(t.minute).padStart(2,`0`)}`});default:return t.raw}}function T(e){if(!e.enabled)return Y(`@SCHED:已停用`);if(e.running)return Y(`@SCHED:运行中...`);let t=jt(e.nextRunAt);switch(t.kind){case`none`:return``;case`today`:return Y(`@SCHED:下次 今天 {time}`,{time:t.time});case`tomorrow`:return Y(`@SCHED:下次 明天 {time}`,{time:t.time});case`weekday`:return Y(`@SCHED:下次 {weekday} {time}`,{weekday:Y(C[t.weekday]),time:t.time});case`date`:return Y(`@SCHED:下次 {date} {time}`,{date:t.date,time:t.time})}}function D(e){let t=e.lastRun;if(!t)return Y(`@SCHED:还没执行过`);switch(t.status){case`ok`:return Y(`@SCHED:成功`);case`error`:return Y(`@SCHED:失败`);case`timed-out`:return Y(`@SCHED:超时中止`);case`skipped-busy`:return Y(`@SCHED:已跳过(会话忙)`);case`missed`:return Y(`@SCHED:已错过(未运行)`);case`cancelled`:return Y(`@SCHED:已停止`);default:return t.status}}function O(e){let t=e.lastRun;if(!t)return Y(`@SCHED:还没执行过`);let n=Nt(t.durationMs),r=Y(`@SCHED:上次 {status}`,{status:D(e)});return n?`${r} · ${n}`:r}function ee(e){return e.lastRun?`is-${Mt(e.lastRun.status)}`:`is-muted`}async function te(e,t){if(!p.value[e.id]){p.value={...p.value,[e.id]:!0};try{await t(),await v()}catch(e){P.error(e?.message||String(e))}finally{let t={...p.value};delete t[e.id],p.value=t}}}function A(e){return te(e,()=>Ct(e.id,{enabled:!e.enabled}))}function M(e){return te(e,()=>Tt(e.id))}function ne(e){return te(e,()=>Et(e.id))}let I=q(!1),re=q(null);function z(e){re.value=e,I.value=!0}async function ie(){let e=re.value;if(e)try{await wt(e.id),I.value=!1,await v()}catch(e){P.error(e?.message||String(e))}}let B=q(!1),V=q(``),H=q(``),U=q(!1),W=q({name:``,freq:`daily`,everyMinutes:30,minute:0,hour:9,weekday:1,custom:``,cwd:``,prompt:``,onMissed:`run`,enabled:!0}),ae=s(()=>[{value:`minutes`,label:Y(`@SCHED:每 N 分钟`)},{value:`hourly`,label:Y(`@SCHED:每小时`)},{value:`daily`,label:Y(`@SCHED:每天`)},{value:`weekly`,label:Y(`@SCHED:每周`)},{value:`custom`,label:Y(`@SCHED:自定义 cron`)}]),J=s(()=>Pt({freq:W.value.freq,everyMinutes:W.value.everyMinutes,minute:W.value.minute,hour:W.value.hour,weekday:W.value.weekday,custom:W.value.custom}));function oe(){W.value={name:``,freq:`daily`,everyMinutes:30,minute:0,hour:9,weekday:1,custom:``,cwd:l.currentDirectory||``,prompt:``,onMissed:`run`,enabled:!0},H.value=``}function X(){V.value=``,oe(),B.value=!0}function Z(e){V.value=e.id;let t=kt(e.schedule),n={name:e.name,freq:`custom`,everyMinutes:30,minute:0,hour:9,weekday:1,custom:e.schedule,cwd:e.cwd,prompt:e.prompt,onMissed:e.onMissed===`skip`?`skip`:`run`,enabled:e.enabled};switch(t.kind){case`every-n-minutes`:n.freq=`minutes`,n.everyMinutes=t.n;break;case`hourly`:n.freq=`hourly`,n.minute=t.minute;break;case`daily`:n.freq=`daily`,n.minute=t.minute,n.hour=t.hour;break;case`weekly`:n.freq=`weekly`,n.minute=t.minute,n.hour=t.hour,n.weekday=t.weekday;break;default:n.freq=`custom`}W.value=n,H.value=``,B.value=!0}async function le(){let e=W.value;if(!e.name.trim()){H.value=Y(`@SCHED:任务名不能为空`);return}if(!e.prompt.trim()){H.value=Y(`@SCHED:提示词不能为空`);return}let t=J.value;if(!t){H.value=Y(`@SCHED:cron 表达式不能为空`);return}let n={name:e.name.trim(),schedule:t,cwd:e.cwd.trim(),prompt:e.prompt.trim(),enabled:e.enabled,onMissed:e.onMissed};U.value=!0;try{V.value?await Ct(V.value,n):await St(n),B.value=!1,await v()}catch(e){H.value=e?.message||String(e)}finally{U.value=!1}}return(t,r)=>(x(),n(`div`,Ft,[a(`div`,It,[a(`span`,Lt,e(b.value),1),a(`button`,{type:`button`,class:`sch-btn sch-btn-primary`,onClick:X},e(o(Y)(`@SCHED:新建任务`)),1)]),f.value?(x(),n(`div`,Rt,e(o(Y)(`@SCHED:操作失败:{error}`,{error:f.value})),1)):F(``,!0),d.value?(x(),n(`div`,zt,e(o(Y)(`@SCHED:加载中...`)),1)):u.value.length?(x(),n(`div`,Ut,[(x(!0),n(S,null,j(u.value,t=>(x(),n(`article`,{key:t.id,class:h([`schedule-card`,{"is-disabled":!t.enabled,"is-running":!!t.running}])},[a(`div`,Wt,[a(`div`,Gt,[a(`span`,Kt,e(t.name),1),t.running?(x(),n(`span`,qt,e(o(Y)(`@SCHED:运行中`)),1)):F(``,!0),a(`button`,{type:`button`,class:h([`sch-switch`,{on:t.enabled}]),role:`switch`,"aria-checked":t.enabled,"aria-label":t.enabled?o(Y)(`@SCHED:停用`):o(Y)(`@SCHED:启用`),onClick:e=>A(t)},[...r[17]||=[a(`span`,{class:`sch-switch-knob`},null,-1)]],10,Jt)]),a(`div`,Yt,[a(`span`,Xt,e(w(t)),1),r[18]||=a(`span`,{class:`schedule-sep`},`·`,-1),a(`span`,{class:h([`schedule-last`,ee(t)])},e(O(t)),3),t.sessionId?(x(),n(`button`,{key:0,type:`button`,class:`sch-link`,onClick:e=>i(`open-session`,t.sessionId)},e(o(Y)(`@SCHED:查看会话`)),9,Zt)):F(``,!0)])]),a(`div`,Qt,[a(`div`,{class:h([`schedule-next`,{"is-muted":!t.enabled}])},e(T(t)),3),a(`div`,$t,[t.running?(x(),n(`button`,{key:0,type:`button`,class:`sch-btn`,disabled:!!p.value[t.id],onClick:e=>ne(t)},e(o(Y)(`@SCHED:停止`)),9,en)):(x(),n(`button`,{key:1,type:`button`,class:`sch-btn`,disabled:!!p.value[t.id],onClick:e=>M(t)},e(o(Y)(`@SCHED:运行`)),9,tn)),a(`button`,{type:`button`,class:`sch-btn`,onClick:e=>Z(t)},e(o(Y)(`@SCHED:编辑`)),9,nn),a(`button`,{type:`button`,class:`sch-btn sch-btn-danger`,onClick:e=>z(t)},e(o(Y)(`@SCHED:删除`)),9,rn)])])],2))),128))])):(x(),n(`div`,Bt,[a(`p`,Vt,e(o(Y)(`@SCHED:还没有定时任务`)),1),a(`p`,Ht,e(o(Y)(`@SCHED:让 g ai 在指定时间自动做事:定时拉代码、定时巡检、定时汇总。也可以在对话里直接说「每天 9 点帮我…」,让 g ai 来创建。`)),1)])),c(ce,{modelValue:B.value,"onUpdate:modelValue":r[14]||=e=>B.value=e,title:V.value?o(Y)(`@SCHED:编辑任务`):o(Y)(`@SCHED:新建任务`),"close-on-click-modal":!1,"append-to-body":!0,size:`medium`,width:`560px`,"z-index":3e6,"custom-class":`schedule-dialog`},{default:L(()=>[a(`div`,an,[a(`label`,on,[a(`span`,sn,e(o(Y)(`@SCHED:任务名`)),1),G(a(`input`,{"onUpdate:modelValue":r[0]||=e=>W.value.name=e,class:`sch-input`,type:`text`,placeholder:o(Y)(`@SCHED:如:每日拉代码`)},null,8,cn),[[K,W.value.name]])]),a(`div`,ln,[a(`span`,un,e(o(Y)(`@SCHED:执行计划`)),1),a(`div`,dn,[G(a(`select`,{"onUpdate:modelValue":r[1]||=e=>W.value.freq=e,class:`sch-input sch-select`},[(x(!0),n(S,null,j(ae.value,t=>(x(),n(`option`,{key:t.value,value:t.value},e(t.label),9,fn))),128))],512),[[k,W.value.freq]]),W.value.freq===`minutes`?(x(),n(S,{key:0},[a(`span`,pn,e(o(Y)(`@SCHED:每`)),1),G(a(`select`,{"onUpdate:modelValue":r[2]||=e=>W.value.everyMinutes=e,class:`sch-input sch-select sch-select-sm`},[(x(),n(S,null,j([5,10,15,20,30,60],t=>a(`option`,{key:t,value:t},e(t),9,mn)),64))],512),[[k,W.value.everyMinutes,void 0,{number:!0}]]),a(`span`,hn,e(o(Y)(`@SCHED:分钟`)),1)],64)):W.value.freq===`daily`||W.value.freq===`weekly`?(x(),n(S,{key:1},[W.value.freq===`weekly`?G((x(),n(`select`,{key:0,"onUpdate:modelValue":r[3]||=e=>W.value.weekday=e,class:`sch-input sch-select sch-select-sm`},[(x(),n(S,null,j(C,(t,n)=>a(`option`,{key:n,value:n},e(o(Y)(t)),9,gn)),64))],512)),[[k,W.value.weekday,void 0,{number:!0}]]):F(``,!0),G(a(`select`,{"onUpdate:modelValue":r[4]||=e=>W.value.hour=e,class:`sch-input sch-select sch-select-sm`},[(x(),n(S,null,j(24,t=>a(`option`,{key:t-1,value:t-1},e(String(t-1).padStart(2,`0`)),9,_n)),64))],512),[[k,W.value.hour,void 0,{number:!0}]]),r[19]||=a(`span`,{class:`sch-inline-label`},`:`,-1),G(a(`select`,{"onUpdate:modelValue":r[5]||=e=>W.value.minute=e,class:`sch-input sch-select sch-select-sm`},[(x(),n(S,null,j(60,t=>a(`option`,{key:t-1,value:t-1},e(String(t-1).padStart(2,`0`)),9,vn)),64))],512),[[k,W.value.minute,void 0,{number:!0}]])],64)):W.value.freq===`hourly`?(x(),n(S,{key:2},[a(`span`,yn,e(o(Y)(`@SCHED:第`)),1),G(a(`select`,{"onUpdate:modelValue":r[6]||=e=>W.value.minute=e,class:`sch-input sch-select sch-select-sm`},[(x(),n(S,null,j(60,t=>a(`option`,{key:t-1,value:t-1},e(String(t-1).padStart(2,`0`)),9,bn)),64))],512),[[k,W.value.minute,void 0,{number:!0}]]),a(`span`,xn,e(o(Y)(`@SCHED:分钟`)),1)],64)):G((x(),n(`input`,{key:3,"onUpdate:modelValue":r[7]||=e=>W.value.custom=e,class:`sch-input sch-input-cron`,type:`text`,spellcheck:`false`,placeholder:o(Y)(`@SCHED:如:0 9 * * 1-5`)},null,8,Sn)),[[K,W.value.custom]])]),a(`span`,Cn,e(o(Y)(`@SCHED:cron:{cron}(分 时 日 月 周,本地时间)`,{cron:J.value||`—`})),1)]),a(`label`,wn,[a(`span`,Tn,e(o(Y)(`@SCHED:项目目录`)),1),G(a(`input`,{"onUpdate:modelValue":r[8]||=e=>W.value.cwd=e,class:`sch-input`,type:`text`,spellcheck:`false`,placeholder:o(Y)(`@SCHED:任务在该目录下执行(默认当前项目)`)},null,8,En),[[K,W.value.cwd]])]),a(`label`,Dn,[a(`span`,On,e(o(Y)(`@SCHED:提示词`)),1),G(a(`textarea`,{"onUpdate:modelValue":r[9]||=e=>W.value.prompt=e,class:`sch-input sch-textarea`,rows:`4`,placeholder:o(Y)(`@SCHED:到点后发给 g ai 的完整指令,例如:检查所有仓库远端更新,有变更就 pull;写成一次自足的请求(未来那一轮没有现在的上下文)`)},null,8,kn),[[K,W.value.prompt]])]),a(`div`,An,[a(`span`,jn,e(o(Y)(`@SCHED:错过补偿`)),1),a(`div`,Mn,[a(`label`,Nn,[G(a(`input`,{"onUpdate:modelValue":r[10]||=e=>W.value.onMissed=e,type:`radio`,value:`run`},null,512),[[N,W.value.onMissed]]),a(`span`,null,e(o(Y)(`@SCHED:补跑一次(g ui 重新运行后)`)),1)]),a(`label`,Pn,[G(a(`input`,{"onUpdate:modelValue":r[11]||=e=>W.value.onMissed=e,type:`radio`,value:`skip`},null,512),[[N,W.value.onMissed]]),a(`span`,null,e(o(Y)(`@SCHED:跳过`)),1)]),a(`label`,Fn,[G(a(`input`,{"onUpdate:modelValue":r[12]||=e=>W.value.enabled=e,type:`checkbox`},null,512),[[R,W.value.enabled]]),a(`span`,null,e(o(Y)(`@SCHED:创建后启用`)),1)])])]),H.value?(x(),n(`p`,In,e(H.value),1)):F(``,!0)]),a(`div`,Ln,[a(`button`,{type:`button`,class:`sch-btn`,onClick:r[13]||=e=>B.value=!1},e(o(Y)(`@SCHED:取消`)),1),a(`button`,{type:`button`,class:`sch-btn sch-btn-primary`,disabled:U.value,onClick:le},e(U.value?o(Y)(`@SCHED:保存中...`):o(Y)(`@SCHED:保存`)),9,Rn)])]),_:1},8,[`modelValue`,`title`]),c(ce,{modelValue:I.value,"onUpdate:modelValue":r[16]||=e=>I.value=e,title:o(Y)(`@SCHED:删除任务`),"close-on-click-modal":!1,"append-to-body":!0,size:`small`,width:`400px`,"z-index":3e6,"custom-class":`schedule-dialog-confirm`},{default:L(()=>[a(`p`,zn,e(o(Y)(`@SCHED:确定删除「{name}」吗?已产生的会话会保留,但任务不再执行。`,{name:re.value?.name||``})),1),a(`div`,Bn,[a(`button`,{type:`button`,class:`sch-btn`,onClick:r[15]||=e=>I.value=!1},e(o(Y)(`@SCHED:取消`)),1),a(`button`,{type:`button`,class:`sch-btn sch-btn-danger`,onClick:ie},e(o(Y)(`@SCHED:删除`)),1)])]),_:1},8,[`modelValue`,`title`])]))}}),[[`__scopeId`,`data-v-75be84e5`]]);w(),z(),l(),A();var Hn={class:`aps`},Un={class:`aps__scroll`},Wn={class:`aps__head`},Gn={class:`aps__title`},Kn={class:`aps__intro`},qn={class:`aps__card aps__card--gai`},Jn={class:`aps__card-head`},Yn={class:`aps__card-title`},Xn={class:`aps__count`},Zn={class:`aps__hint`},Qn=[`placeholder`],$n={class:`aps__foot`},er={key:0,class:`aps__saved`},tr=[`disabled`],nr={class:`aps__card aps__card--dispatch`},rr={class:`aps__card-head`},ir={class:`aps__card-title`},ar={class:`aps__hint`},or={class:`aps__field`},sr={class:`aps__card-head`},cr={class:`aps__label`,for:`aps-global`},lr={class:`aps__count`},ur=[`placeholder`],dr={class:`aps__field`},fr={class:`aps__card-head`},pr={class:`aps__label`,for:`aps-project`},mr={key:0,class:`aps__count`},hr=[`disabled`,`placeholder`],gr={class:`aps__hint`},_r={class:`aps__foot`},vr={key:0,class:`aps__saved`},yr={key:1,class:`aps__saved`},br=[`disabled`],xr=4e3,Sr=X(_({__name:`AgentPromptSettings`,setup(t){let r=se(),{defaultPrompt:i,projectPrompts:c,loadOrchestrator:l,saveDefaultPrompt:u,saveProjectPrompt:d}=Te(),f=q(``),p=q(!1),m=q(!1),h=s(()=>r.agentDefaultPrompt||``),g=s(()=>f.value.trim()!==h.value.trim());async function _(){if(!p.value&&g.value){p.value=!0;try{await r.saveAiSettings({agentDefaultPrompt:f.value})&&(f.value=h.value,m.value=!0,P.success(Y(`@AGENT:已保存 g ai 默认提示词`)))}finally{p.value=!1}}}let v=s(()=>r.currentDirectory||``),y=s(()=>Z(v.value)||v.value),b=s(()=>{let e=le(v.value);return e&&c.value?.[e]?.prompt||``}),S=q(``),C=q(``),w=q(!1),T=q(!1),D=q(!1),O=s(()=>S.value.trim()!==(i.value||``).trim()||!!v.value&&C.value.trim()!==b.value.trim());function k(){S.value=i.value||``,C.value=b.value}E(async()=>{f.value=h.value,k();let e=await l(!0);D.value=!e,e&&k()});async function ee(){if(!w.value&&O.value){w.value=!0;try{let e=!0,t=S.value.trim();t!==(i.value||``).trim()&&(e=await u(t));let n=C.value.trim();e&&v.value&&n!==b.value.trim()&&(e=await d(v.value,n)),e&&(k(),T.value=!0)}finally{w.value=!1}}}return(t,r)=>(x(),n(`div`,Hn,[a(`div`,Un,[a(`header`,Wn,[a(`h3`,Gn,e(o(Y)(`@AGENT:提示词设置`)),1),a(`p`,Kn,e(o(Y)(`@AGENT:这里配的两块提示词,和 g ai 对话时每一轮都会自动带上。改完下一次发消息就生效,不用新开会话。`)),1)]),a(`section`,qn,[a(`div`,Jn,[a(`h4`,Yn,e(o(Y)(`@AGENT:g ai 智能体的默认提示词`)),1),a(`span`,Xn,e(f.value.length)+` / `+e(xr),1)]),a(`p`,Zn,e(o(Y)(`@AGENT:只作用于 g ai 自己:每次对话都会带上(定时任务也一样)。派发出去的任务读不到这一段。`)),1),G(a(`textarea`,{id:`aps-gai`,"onUpdate:modelValue":r[0]||=e=>f.value=e,class:`aps__area`,rows:`6`,maxlength:xr,placeholder:o(Y)(`@AGENT:例如:回答用中文;改完代码先跑一遍验证再汇报;不要动 dist 目录`)},null,8,Qn),[[K,f.value]]),a(`div`,$n,[m.value&&!g.value?(x(),n(`span`,er,e(o(Y)(`@AGENT:已保存`)),1)):F(``,!0),r[3]||=a(`span`,{class:`aps__spacer`},null,-1),a(`button`,{type:`button`,class:`aps__btn aps__btn--primary`,disabled:p.value||!g.value,onClick:_},e(p.value?o(Y)(`@AGENT:保存中…`):o(Y)(`@AGENT:保存`)),9,tr)])]),a(`section`,nr,[a(`div`,rr,[a(`h4`,ir,e(o(Y)(`@AGENT:派发任务的提示词`)),1)]),a(`p`,ar,e(o(Y)(`@AGENT:与工作台「预设提示词」是同一份设置,在哪边改都一样。派发任务时附加在指令之前,和 g ai 对话时也会带上。`)),1),a(`div`,or,[a(`div`,sr,[a(`label`,cr,e(o(Y)(`@AGENT:全局提示词`)),1),a(`span`,lr,e(S.value.length)+` / `+e(xr),1)]),G(a(`textarea`,{id:`aps-global`,"onUpdate:modelValue":r[1]||=e=>S.value=e,class:`aps__area`,rows:`5`,maxlength:xr,placeholder:o(Y)(`@AGENT:对所有项目生效。例如:回答用中文;改完代码必须跑一遍测试;不要动 dist 目录`)},null,8,ur),[[K,S.value]])]),a(`div`,dr,[a(`div`,fr,[a(`label`,pr,e(v.value?o(Y)(`@AGENT:「{name}」的项目提示词`,{name:y.value}):o(Y)(`@AGENT:项目提示词`)),1),v.value?(x(),n(`span`,mr,e(C.value.length)+` / `+e(xr),1)):F(``,!0)]),G(a(`textarea`,{id:`aps-project`,"onUpdate:modelValue":r[2]||=e=>C.value=e,class:`aps__area`,rows:`5`,maxlength:xr,disabled:!v.value,placeholder:v.value?o(Y)(`@AGENT:只在这个项目派发/对话时附加。例如:包管理器用 pnpm;改动集中在 src/ui 下`):o(Y)(`@AGENT:当前没有打开项目,项目级提示词暂时不能设置`)},null,8,hr),[[K,C.value]]),a(`p`,gr,e(v.value?o(Y)(`@AGENT:项目提示词追加在全局提示词之后(不覆盖全局),在「{name}」里派发或对话时一起带上`,{name:y.value}):o(Y)(`@AGENT:先在左上角切到一个项目,才能设置它的提示词`)),1)]),a(`div`,_r,[T.value&&!O.value?(x(),n(`span`,vr,e(o(Y)(`@AGENT:已保存`)),1)):D.value?(x(),n(`span`,yr,e(o(Y)(`@AGENT:读取设置失败,请稍后重试`)),1)):F(``,!0),r[4]||=a(`span`,{class:`aps__spacer`},null,-1),a(`button`,{type:`button`,class:`aps__btn aps__btn--primary`,disabled:w.value||!O.value,onClick:ee},e(w.value?o(Y)(`@AGENT:保存中…`):o(Y)(`@AGENT:保存`)),9,br)])])])]))}}),[[`__scopeId`,`data-v-ae77c09c`]]);w(),z(),l();var Cr={class:`agent-chat-area`},wr={class:`agent-tabs`,role:`tablist`},Tr=[`aria-selected`,`onClick`],Er={class:`agent-tab-body`},Dr={key:0,class:`agent-chat-pane`},Or={key:0,class:`agent-list-page`},kr={key:0,class:`agent-page-bar`},Ar=[`title`,`aria-label`],jr={class:`agent-page-title`},Mr={key:0,class:`chat-loading`},Nr=X(_({__name:`AgentView`,setup(i){let l=se(),d=q(null),{narrow:f}=Se(d),m=q(`chat`),_=q(`chat`),v=s(()=>_.value===`mcp`?`mcp`:`skill`),b=s(()=>[{id:`chat`,label:Y(`@AGENT:对话`),icon:M},{id:`schedule`,label:Y(`@AGENT:定时任务`),icon:t},{id:`skill`,label:Y(`@AGENT:Skill 广场`),icon:C},{id:`mcp`,label:Y(`@AGENT:MCP 广场`),icon:U},{id:`settings`,label:Y(`@AGENT:设置`),icon:g}]),{sessions:w,sessionsLoading:T,currentSessionId:E,messages:O,isStreaming:k,sessionLoading:ee,loadSessions:te,loadSession:A,deleteSession:N,renameSession:P,newSession:ne,sendMessage:I,retryTurn:re,questionPanel:R,answeringQuestion:z,answerQuestion:ie,isSessionGenerating:B,currentEngine:W,pendingEngine:G,isEngineLocked:K,pickEngine:ae,stop:X,inputContextUsage:ce,queuedMessages:Z,queuePaused:le,removeQueuedMessage:Te,flushQueued:Ee}=xe(),De=s(()=>K.value?W.value:G.value);function Oe(e){K.value||ae(e)}let ke=s(()=>{let e=l.theme;return e===`dark`||e===`auto`&&window.matchMedia(`(prefers-color-scheme: dark)`).matches?`dark`:`light`}),Ae=s(()=>fe(w.value,B)),je=de(),Me=s(()=>Ae.value.find(e=>e.id===E.value)?.title||Y(`@AGENT:对话`)),Ne={"--welcome-avatar":`url("${be}")`},Pe=s(()=>ue(l.agentPresetPrompts));async function Fe(e){await I(e.text,e.files),await u(),Be()}async function Ie(e){await I(e.prompt),await u(),Be()}let Le=ge(),Re=q(null),ze=ye();function Be(e=!0){Re.value?.scrollToBottom(e)}H(()=>O.value.length,()=>{u(()=>Be(!1))});function Ve(e){A(e),m.value=`chat`}function He(e){e&&(_.value=`chat`,Ve(e))}function Ue(){ne(),m.value=`chat`}let We=q(280),Ge=q(!1);function Ke(e){Ge.value=!0;let t=e.clientX,n=We.value,r=e=>{let r=e.clientX-t,i=Math.max(200,Math.min(500,n+r));We.value=i},i=()=>{Ge.value=!1,document.removeEventListener(`mousemove`,r),document.removeEventListener(`mouseup`,i)};document.addEventListener(`mousemove`,r),document.addEventListener(`mouseup`,i)}return H(f,e=>{e||(m.value=`chat`)}),H(()=>[l.currentDirectory,k.value],async([e,t],n)=>{let r=!n||e!==n[0],i=!!n&&n[1]===!0&&!t;(r||i)&&await te(),E.value&&!k.value&&!w.value.some(e=>e.sessionId===E.value)&&ne()},{immediate:!0}),(t,i)=>(x(),n(`div`,{ref_key:`rootRef`,ref:d,class:`agent-view`},[_.value===`chat`&&!o(f)?(x(),n(S,{key:0},[a(`aside`,{class:`agent-sidebar`,style:D({width:We.value+`px`})},[c(o(oe),{class:`agent-conversations`,items:Ae.value,"active-id":o(E),loading:o(T),labels:o(je),onSelect:Ve,onNew:Ue,onRename:o(P),onDelete:o(N)},null,8,[`items`,`active-id`,`loading`,`labels`,`onRename`,`onDelete`])],4),a(`div`,{class:h([`sidebar-resizer`,{active:Ge.value}]),onMousedown:Ke},null,34)],64)):F(``,!0),a(`main`,Cr,[a(`nav`,wr,[(x(!0),n(S,null,j(b.value,t=>(x(),n(`button`,{key:t.id,type:`button`,class:h([`agent-tab`,{active:_.value===t.id}]),role:`tab`,"aria-selected":_.value===t.id,onClick:e=>_.value=t.id},[c(o(p),null,{default:L(()=>[(x(),y(V(t.icon)))]),_:2},1024),a(`span`,null,e(t.label),1)],10,Tr))),128)),_.value===`chat`?(x(),y(Ce,{key:0,class:`agent-engine`,engine:De.value,locked:o(K),onSelect:Oe},null,8,[`engine`,`locked`])):F(``,!0),_.value===`chat`?(x(),y(we,{key:1,class:`agent-copy`,messages:o(O),title:Me.value,engine:o(_e)(De.value)},null,8,[`messages`,`title`,`engine`])):F(``,!0)]),a(`div`,Er,[_.value===`chat`?(x(),n(`div`,Dr,[o(f)&&m.value===`list`?(x(),n(`div`,Or,[c(o(oe),{class:`agent-conversations`,items:Ae.value,"active-id":o(E),loading:o(T),labels:o(je),onSelect:Ve,onNew:Ue,onRename:o(P),onDelete:o(N)},null,8,[`items`,`active-id`,`loading`,`labels`,`onRename`,`onDelete`])])):(x(),n(S,{key:1},[o(f)?(x(),n(`div`,kr,[a(`button`,{type:`button`,class:`agent-page-back`,title:o(Y)(`@AGENT:返回会话列表`),"aria-label":o(Y)(`@AGENT:返回会话列表`),onClick:i[0]||=e=>m.value=`list`},[...i[1]||=[a(`svg`,{viewBox:`0 0 24 24`,width:`14`,height:`14`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`},[a(`line`,{x1:`19`,y1:`12`,x2:`5`,y2:`12`}),a(`polyline`,{points:`12 19 5 12 12 5`})],-1)]],8,Ar),a(`span`,jr,e(Me.value),1)])):F(``,!0),a(`div`,{class:`agent-chat-host`,style:Ne},[o(ee)?(x(),n(`div`,Mr,[c(o(p),{class:`is-loading`,size:32},{default:L(()=>[c(o(r))]),_:1}),a(`span`,null,e(o(Y)(`@AGENT:加载会话中...`)),1)])):(x(),y(o(J),{key:1,ref_key:`chatContainerRef`,ref:Re,messages:o(O),"preset-questions":Pe.value,"welcome-title":o(Y)(`@AGENT:智能体助手`),"welcome-description":o(Y)(`@AGENT:我可以帮你阅读代码、执行命令、修改文件。选择下方话题或直接输入你的问题。`),"assistant-name":o(he),"assistant-avatar":o(be),theme:ke.value,generating:o(k),"allow-queue":!0,queued:o(Z),"queue-paused":o(le),"queue-labels":o(ze),"upload-config":{accept:o(me)},"context-usage":o(ce),placeholder:o(k)?o(Y)(`@AGENT:生成中,发送后会排队,等本轮跑完自动接上…`):o(Y)(`@AGENT:输入消息,Enter 发送`),question:o(R),"question-submitting":o(z),"question-labels":o(Le),"plan-config":{labels:{title:o(Y)(`@AGENT:计划`),raw:o(Y)(`@AGENT:原始参数`)}},"message-rail-config":o(pe),"message-meta-config":o(ve),onSend:Fe,onSelect:Ie,onStop:o(X),onUnqueue:o(Te),onFlushQueued:o(Ee),onAnswer:o(ie),onRetry:o(re)},null,8,[`messages`,`preset-questions`,`welcome-title`,`welcome-description`,`assistant-name`,`assistant-avatar`,`theme`,`generating`,`queued`,`queue-paused`,`queue-labels`,`upload-config`,`context-usage`,`placeholder`,`question`,`question-submitting`,`question-labels`,`plan-config`,`message-rail-config`,`message-meta-config`,`onStop`,`onUnqueue`,`onFlushQueued`,`onAnswer`,`onRetry`]))])],64))])):_.value===`schedule`?(x(),y(Vn,{key:1,onOpenSession:He})):_.value===`skill`||_.value===`mcp`?(x(),y(bt,{key:2,type:v.value},null,8,[`type`])):(x(),y(Sr,{key:3}))])])],512))}}),[[`__scopeId`,`data-v-287616d8`]]);export{Nr as default};
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import"./rolldown-runtime-C0FnF6B9.js";import{$r as e,An as t,C as n,Dn as r,Dr as i,En as a,Fn as o,Fr as s,Gn as c,J as l,Jn as u,Jr as d,Ln as f,On as p,Pn as m,Qn as h,S as g,Sn as _,Vn as v,Xn as y,Y as ee,er as te,i as b,kn as x,lr as S,mr as C,tt as ne,w,xr as T}from"./element-plus-J45pKUrE.js";import{n as E,t as D}from"./_plugin-vue_export-helper-C3o7kvRL.js";import{t as O}from"./SvgIcon-0n6uuKFm.js";import{l as re}from"./configStore-BdL3uW2E.js";import{D as ie,V as ae,h as k}from"./index-BS7BDFG4.js";import{d as oe,f as A,m as j,n as se,p as M}from"./agentConversations-DpiGplZB.js";v(),C();function N(e,t=680){let n=T(0),r=null;function i(){let t=e.value;return t?(n.value=t.clientWidth,typeof ResizeObserver>`u`||(r=new ResizeObserver(e=>{let t=e[0]?.contentRect?.width;typeof t==`number`&&(n.value=t)}),r.observe(t),!0)):!1}return y(()=>{i()||c(()=>i())}),u(()=>{r?.disconnect(),r=null}),{width:n,narrow:a(()=>n.value>0&&n.value<t)}}v(),C(),s();var P={class:`agent-engine`},F=[`disabled`,`title`,`aria-label`],I={class:`agent-engine__name`},L={class:`agent-engine__item`},R={class:`agent-engine__item-name`},z={key:3,class:`agent-engine__item-missing`},B=D(f({__name:`AgentEngineSelector`,props:{engine:{},locked:{type:Boolean}},emits:[`select`],setup(s,{emit:c}){let u=s,f=c,m=ae(),v=a(()=>M(u.engine)),y=a(()=>({gai:!0,claude:m.claudeAvailable,opencode:m.opencodeAvailable,codex:m.codexAvailable})),b=T(!1),C=T(null);function D(e){if(!u.locked){if(!y.value[e]){if(!j(e))return;C.value=e,b.value=!0;return}f(`select`,e)}}return(a,c)=>(h(),t(`div`,P,[o(i(g),{trigger:`click`,onCommand:D},{dropdown:S(()=>[o(i(w),null,{default:S(()=>[(h(!0),t(_,null,te(i(oe),a=>(h(),p(i(n),{key:a.id,command:a.id},{default:S(()=>[r(`span`,L,[i(j)(a.id)?(h(),p(k,{key:0,executor:a.id,class:`agent-engine__item-icon`},null,8,[`executor`])):(h(),p(O,{key:1,"icon-class":i(A),class:`agent-engine__item-icon`},null,8,[`icon-class`])),r(`span`,R,e(a.name),1),s.engine===a.id?(h(),p(i(l),{key:2,class:`agent-engine__item-check`},{default:S(()=>[o(i(ne))]),_:1})):y.value[a.id]?x(``,!0):(h(),t(`span`,z,e(i(E)(`@42BB9:未安装`)),1))])]),_:2},1032,[`command`]))),128))]),_:1})]),default:S(()=>[r(`button`,{type:`button`,class:d([`agent-engine__btn`,{"is-locked":s.locked}]),disabled:s.locked,title:s.locked?i(E)(`@AGENT:本会话的引擎已锁定;要换引擎请新建会话`):i(E)(`@AGENT:新建会话使用的引擎`),"aria-label":i(E)(`@AGENT:智能体引擎`)},[i(j)(s.engine)?(h(),p(k,{key:0,executor:s.engine,class:`agent-engine__icon`},null,8,[`executor`])):(h(),p(O,{key:1,"icon-class":i(A),class:`agent-engine__icon`},null,8,[`icon-class`])),r(`span`,I,e(v.value),1),o(i(l),{class:`agent-engine__caret`},{default:S(()=>[o(i(ee))]),_:1})],10,F)]),_:1}),o(ie,{modelValue:b.value,"onUpdate:modelValue":c[0]||=e=>b.value=e,tool:C.value},null,8,[`modelValue`,`tool`])]))}}),[[`__scopeId`,`data-v-cc0a8973`]]),V=8192;function H(e,t){return e.length>t?`…(前文已截断)\n${e.slice(-t)}`:e}function U(e,t){let n=e||`done`;return n!==`pending`&&n!==`running`||t===`running`||t===`pending`?n:t===`cancelled`||t===`error`?`error`:`done`}function W(e){let t=e?.toolCalls;if(!Array.isArray(t)||t.length===0)return[];let n=e?.status||`done`,r=[];for(let e=0;e<t.length;e++){let i=t[e];if(!i||typeof i!=`object`)continue;let a=U(i.status,n),o=typeof i.result==`string`?i.result:``;r.push({id:typeof i.id==`string`&&i.id?i.id:`tool-${e}`,name:typeof i.name==`string`?i.name:``,argsPreview:typeof i.argsPreview==`string`?i.argsPreview:``,arguments:typeof i.arguments==`string`?i.arguments:``,result:o?H(o,V):``,status:a,error:typeof i.error==`string`&&i.error?i.error:void 0})}return r}var G=`
|
|
2
|
-
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
`,K=`[运行环境 ·`,ce=`## 跨会话记忆库`,le=/\n\n---\n本任务包含 \d+ 个附件(请按文件路径读取[\s\S]*$/,ue=/\n\n续接 #\d+\s*$/;function q(e){let t=e.indexOf(G);return t===-1?0:t+7}function J(e){let t=typeof e==`string`?e:``;return t?(t.startsWith(K)&&(t=t.slice(q(t))),t.startsWith(ce)&&(t=t.slice(q(t))),t=t.replace(le,``).replace(ue,``),t.trim()):``}function Y(e){switch(e){case`todo`:return E(`@WORKBENCH:待执行`);case`running`:return E(`@WORKBENCH:执行中`);case`done`:return E(`@WORKBENCH:已完成`);case`error`:return E(`@WORKBENCH:出错`);case`cancelled`:return E(`@WORKBENCH:已取消`);case`pending`:return E(`@WORKBENCH:排队中`);default:return e}}function de(e){switch(e){case`running`:return`var(--color-primary)`;case`done`:return`#22c55e`;case`error`:return`#ef4444`;case`cancelled`:return`#9ca3af`;case`pending`:return`#f59e0b`;default:return`var(--text-tertiary)`}}function X(e){let t=e?new Date(e):new Date;if(Number.isNaN(t.getTime()))return``;let n=e=>String(e).padStart(2,`0`);return`${t.getFullYear()}-${n(t.getMonth()+1)}-${n(t.getDate())} ${n(t.getHours())}:${n(t.getMinutes())}`}function fe(e,t=120){let n=e.replace(/\s+/g,` `).trim();return n.length>t?`${n.slice(0,t-1)}…`:n}function pe(e){let t=(e.match(/`+/g)||[]).reduce((e,t)=>Math.max(e,t.length),0),n="`".repeat(Math.max(3,t+1));return`${n}\n${e}\n${n}`}function Z(e,t){return`### ${e}\n\n${t.trim()}`}function me(e){let t=[];return e.forEach((e,n)=>{let r=e.name||E(`@WORKBENCH:工具`),i=fe(e.argsPreview||``);t.push(`${n+1}. **${r}**${i?` — \`${i}\``:``}`);let a=(e.status===`error`?e.error:e.result)||e.result||e.error||``;a.trim()&&t.push(``,pe(a.trim()))}),t.join(`
|
|
6
|
-
`)}function he(e,t={},n={}){let r=Array.isArray(e)?e.filter(Boolean):[],i=n.scope===`brief`,a=[];if(r.forEach((e,t)=>{let n=[],r=J(e.prompt);if(r&&n.push(Z(E(`@WORKBENCH:用户提示词`),r)),!i){let t=(e.thinking||``).trim();t&&n.push(Z(E(`@WORKBENCH:Claude 思考`),t));let r=me(W(e));r&&n.push(Z(E(`@WORKBENCH:工具调用`),r))}let o=(e.output||``).trim();o&&n.push(Z(E(`@WORKBENCH:模型返回`),o));let s=(e.error||e.agentError||``).trim();if(s&&n.push(Z(E(`@WORKBENCH:出错`),s)),n.length===0)return;let c=[re(e.agent),Y(e.status),X(e.startedAt)].filter(Boolean);a.push(`## ${E(`@WORKBENCH:第 {n} 轮`,{n:t+1})}\n\n*${c.join(` · `)}*\n\n${n.join(`
|
|
7
|
-
|
|
8
|
-
`)}`)}),a.length===0)return``;let o=[`# ${(t.title||``).trim()||E(`@WORKBENCH:未命名任务`)}`],s=(t.projectName||``).trim();return s&&o.push(``,`- ${E(`@WORKBENCH:项目:{name}`,{name:s})}`),o.push(`- ${E(`@WORKBENCH:导出时间:{time}`,{time:X((t.now||new Date).toISOString())})}`),`${o.join(`
|
|
9
|
-
`)}\n\n---\n\n${a.join(`
|
|
10
|
-
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
`)}\n`}function ge(e,t=120){let n=e.replace(/\s+/g,` `).trim();return n.length>t?`${n.slice(0,t-1)}…`:n}function _e(e){let t=(e.match(/`+/g)||[]).reduce((e,t)=>Math.max(e,t.length),0),n="`".repeat(Math.max(3,t+1));return`${n}\n${e}\n${n}`}function Q(e,t){return`### ${e}\n\n${t.trim()}`}function ve(e,t){return e===`user`?E(`@AGENT:我`):t}function ye(e){if(!Array.isArray(e)||!e.length)return``;let t=[];return e.forEach((e,n)=>{let r=e.name||E(`@AGENT:工具`),i=ge(e.argsPreview||``);t.push(`${n+1}. **${r}**${i?` — \`${i}\``:``}`);let a=(e.status===`error`?e.error:e.result)||e.result||e.error||``;a.trim()&&t.push(``,_e(a.trim()))}),t.join(`
|
|
14
|
-
`)}function be(e,t,n){if(e.role===`system`)return``;let r=[];if(t){let t=(e.reasoning||``).trim();t&&r.push(Q(E(`@AGENT:思考`),t));let n=ye(e.toolCalls);n&&r.push(Q(E(`@AGENT:工具调用`),n))}let i=(e.content||``).trim();i&&r.push(i);let a=(e.attachments||[]).map(e=>e.name).filter(Boolean);a.length&&r.push(`${E(`@AGENT:附件`)}:${a.join(`、`)}`);let o=(e.error||``).trim();if(o&&r.push(`> ⚠️ ${o}`),r.length===0){if(e.role!==`assistant`)return``;r.push(`*${E(`@AGENT:本轮未输出正文`)}*`)}return`## ${ve(e.role,n)}\n\n${r.join(`
|
|
15
|
-
|
|
16
|
-
`)}`}function xe(e,t={},n={}){let r=Array.isArray(e)?e.filter(Boolean):[],i=n.scope===`full`,a=(t.assistantName||``).trim()||`g ai`,o=[];for(let e of r){let t=be(e,i,a);t&&o.push(t)}if(o.length===0)return``;let s=[`${E(`@AGENT:导出时间`)}:${X((t.now||new Date).toISOString())}`],c=(t.engine||``).trim();return c&&s.push(`${E(`@AGENT:引擎`)}:${c}`),s.push(E(`@AGENT:共 {n} 条消息`,{n:o.length})),`${`# ${(t.title||``).trim()||E(`@AGENT:无标题`)}\n\n- ${s.join(` · `)}`}\n\n---\n\n${o.join(`
|
|
17
|
-
|
|
18
|
-
---
|
|
19
|
-
|
|
20
|
-
`)}\n`}v(),C(),s();var Se={class:`csb`},Ce=[`title`,`aria-label`],$={key:0,viewBox:`0 0 24 24`,width:`13`,height:`13`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`},we={key:1,viewBox:`0 0 24 24`,width:`13`,height:`13`,fill:`none`,stroke:`currentColor`,"stroke-width":`1.8`,"stroke-linecap":`round`,"stroke-linejoin":`round`},Te=[`title`,`aria-label`],Ee=D(f({__name:`CopySessionButton`,props:{messages:{},title:{},engine:{}},setup(a){let s=a,c=T(!1),l=null;u(()=>{l&&clearTimeout(l)});async function f(e){try{if(navigator?.clipboard?.writeText)return await navigator.clipboard.writeText(e),!0}catch{}try{let t=document.createElement(`textarea`);t.value=e,t.style.position=`fixed`,t.style.opacity=`0`,t.style.left=`-9999px`,document.body.appendChild(t),t.select();let n=document.execCommand(`copy`);return document.body.removeChild(t),n}catch{return!1}}async function p(e){let t=xe(s.messages||[],{title:s.title,engine:s.engine,assistantName:se},{scope:e});if(!t){b.warning(E(`@AGENT:暂无会话内容可复制`));return}if(!await f(t)){b.error(E(`@AGENT:复制失败`));return}c.value=!0,b.success(E(`@AGENT:已复制会话`)),l&&clearTimeout(l),l=setTimeout(()=>{c.value=!1,l=null},1500)}function _(e){p(e===`full`?`full`:`brief`)}return(a,s)=>{let l=n,u=w,f=g;return h(),t(`div`,Se,[r(`button`,{type:`button`,class:d([`csb__btn`,{"is-flash":c.value}]),title:i(E)(`@AGENT:复制本会话的对话内容(默认精简:仅对话正文)`),"aria-label":i(E)(`@AGENT:复制会话`),onClick:s[0]||=e=>p(`brief`)},[c.value?(h(),t(`svg`,$,[...s[1]||=[r(`polyline`,{points:`20 6 9 17 4 12`},null,-1)]])):(h(),t(`svg`,we,[...s[2]||=[r(`rect`,{x:`9`,y:`9`,width:`13`,height:`13`,rx:`2`},null,-1),r(`path`,{d:`M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1`},null,-1)]]))],10,Ce),o(f,{trigger:`click`,placement:`bottom-end`,onCommand:_},{dropdown:S(()=>[o(u,null,{default:S(()=>[o(l,{command:`brief`},{default:S(()=>[m(e(i(E)(`@AGENT:精简:对话正文`)),1)]),_:1}),o(l,{command:`full`},{default:S(()=>[m(e(i(E)(`@AGENT:全量:对话正文 + 思考 + 工具调用`)),1)]),_:1})]),_:1})]),default:S(()=>[r(`button`,{type:`button`,class:`csb__btn csb__caret`,title:i(E)(`@AGENT:选择复制范围`),"aria-label":i(E)(`@AGENT:选择复制范围`)},[...s[3]||=[r(`svg`,{viewBox:`0 0 24 24`,width:`11`,height:`11`,fill:`none`,stroke:`currentColor`,"stroke-width":`2.2`,"stroke-linecap":`round`,"stroke-linejoin":`round`},[r(`polyline`,{points:`6 9 12 15 18 9`})],-1)]],8,Te)]),_:1})])}}}),[[`__scopeId`,`data-v-065fed5e`]]);export{J as a,N as c,Y as i,he as n,W as o,de as r,B as s,Ee as t};
|