zen-gitsync 2.13.22 → 2.13.23
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/package.json +1 -1
- package/scripts/README_COLOR_CONVERTER.md +196 -196
- package/scripts/README_FONTSIZE_CONVERTER.md +278 -278
- package/scripts/README_SPACING_CONVERTER.md +126 -126
- package/scripts/README_STYLE_VARS.md +180 -180
- package/src/ui/public/assets/{AppVersionBadge-CS59-kD5.js → AppVersionBadge-BUS8w2f8.js} +2 -2
- package/src/ui/public/assets/{BranchSelector-DulCErgN.js → BranchSelector-Dm7nENer.js} +1 -1
- package/src/ui/public/assets/{CommandConsole-H1j4BsHx.js → CommandConsole-C1W9ZQkE.js} +2 -2
- package/src/ui/public/assets/{CommitForm-DIdLEAZ_.js → CommitForm-C76W1ZZH.js} +1 -1
- package/src/ui/public/assets/{CustomCommandManager-Cm5yU0TM.js → CustomCommandManager-JKx8JYqn.js} +1 -1
- package/src/ui/public/assets/{EditorView-CTvDExIi.js → EditorView-CriUYDvi.js} +0 -0
- package/src/ui/public/assets/{FileDiffViewer-C7Cosx8a.js → FileDiffViewer-DNWsiIGt.js} +1 -1
- package/src/ui/public/assets/{FlowExecutionViewer-BeGTXBVV.js → FlowExecutionViewer-CTDh2bCD.js} +1 -1
- package/src/ui/public/assets/{FlowOrchestrationWorkspace-CuqAZCaM.js → FlowOrchestrationWorkspace-Chah2aGN.js} +1 -1
- package/src/ui/public/assets/{GitStatus-DBDjyLJD.js → GitStatus-DP-DQsiS.js} +1 -1
- package/src/ui/public/assets/{ImagePreview-C8eIs5yL.js → ImagePreview-D8klNa6F.js} +1 -1
- package/src/ui/public/assets/{LogList-YCJ_gVWr.js → LogList-Z76_5USQ.js} +1 -1
- package/src/ui/public/assets/{ProjectStartupButton-gWSO3HCJ.js → ProjectStartupButton-C5oF4unq.js} +1 -1
- package/src/ui/public/assets/{RemoteRepoCard-9iWOAx2g.js → RemoteRepoCard-B-fGjb8Y.js} +1 -1
- package/src/ui/public/assets/{ResetToRemoteButton-BckRJ_lM.js → ResetToRemoteButton-BixSoEVs.js} +1 -1
- package/src/ui/public/assets/{SourceMapView-DWBowIx1.js → SourceMapView-C9HZiJ9N.js} +1 -1
- package/src/ui/public/assets/{TemplateManager-DiKpGMhi.js → TemplateManager-C7SuKq0f.js} +1 -1
- package/src/ui/public/assets/{UserInputNode-CU11vBBn.js → UserInputNode-CYy0UpzR.js} +1 -1
- package/src/ui/public/assets/WorkbenchView-A9Oik707.js +12 -0
- package/src/ui/public/assets/WorkbenchView-DvML7yIv.css +1 -0
- package/src/ui/public/assets/{_plugin-vue_export-helper-vLPduyLG.js → _plugin-vue_export-helper-BfbhkIv4.js} +2 -2
- package/src/ui/public/assets/{index-BxxqloTb.js → index-DPSGvy34.js} +3 -3
- package/src/ui/public/favicon.svg +75 -75
- package/src/ui/public/index.html +19 -19
- package/src/ui/public/logo.svg +74 -74
- package/src/ui/server/routes/workbench.js +160 -23
- package/src/ui/public/assets/WorkbenchView-BsVMwobR.js +0 -12
- package/src/ui/public/assets/WorkbenchView-DslIMLgz.css +0 -1
|
@@ -388,8 +388,70 @@ async function listDirTree(projectPath, maxDepth = 2, maxEntries = 400) {
|
|
|
388
388
|
return lines.join('\n');
|
|
389
389
|
}
|
|
390
390
|
|
|
391
|
+
// 剥离 LLM 输出的 思考块、```json``` 代码块围栏,以及首尾说明文字。
|
|
392
|
+
// 原贪婪正则 /({[\s\S]*})/ 会把 思考块(内含未配对花括号或字符串)一起吞进 JSON.parse,
|
|
393
|
+
// 在 DeepSeek 等会输出 推理链的模型上偶发 "Unterminated string in JSON"。
|
|
394
|
+
function stripThinkingBlocks(content) {
|
|
395
|
+
let s = String(content || '');
|
|
396
|
+
// 1) 显式 思考块(成对标签)
|
|
397
|
+
s = s.replace(/<think(?:ing)?>[\s\S]*?<\/think(?:ing)?>/gi, '');
|
|
398
|
+
// 2) 某些 provider 流式结尾会留下裸 <think>...</think> 之外的残段(无结束标签时被截断)
|
|
399
|
+
s = s.replace(/<think(?:ing)?>[\s\S]*$/gi, '');
|
|
400
|
+
// 3) ```json ... ``` 代码块围栏(保留内部 JSON)
|
|
401
|
+
s = s.replace(/```json\s*/gi, '').replace(/```/g, '');
|
|
402
|
+
return s;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
// 在剥离 思考块 的文本里定位第一个「平衡花括号对象」的起点/终点。
|
|
406
|
+
// 跳过字符串内的 {/}(含转义)以及 Jinja {{ }} 模板占位符;
|
|
407
|
+
// 同时只在「JSON 特征显著」的 { 处起算 —— 即该 { 之后不远处出现 " 字符串。
|
|
408
|
+
// 这能避免把 LLM 思考文本里的裸 { ... }(如 "see { views, stores }")误当 JSON 起点。
|
|
409
|
+
function extractFirstJsonObject(content) {
|
|
410
|
+
const s = String(content || '');
|
|
411
|
+
let depth = 0;
|
|
412
|
+
let inStr = false;
|
|
413
|
+
let escape = false;
|
|
414
|
+
let start = -1;
|
|
415
|
+
for (let i = 0; i < s.length; i++) {
|
|
416
|
+
const ch = s[i];
|
|
417
|
+
if (inStr) {
|
|
418
|
+
if (escape) { escape = false; continue; }
|
|
419
|
+
if (ch === '\\') { escape = true; continue; }
|
|
420
|
+
if (ch === '"') { inStr = false; }
|
|
421
|
+
continue;
|
|
422
|
+
}
|
|
423
|
+
if (ch === '"') { inStr = true; continue; }
|
|
424
|
+
// 跳过 Jinja {{ }} 占位符(提示词模板常用,勿当 JSON)
|
|
425
|
+
if (ch === '{' && s[i + 1] === '{') { i++; continue; }
|
|
426
|
+
if (ch === '}' && s[i - 1] === '}') { continue; }
|
|
427
|
+
if (ch === '{') {
|
|
428
|
+
if (depth === 0) {
|
|
429
|
+
// 启发式判断「这看起来像 JSON 起点」:
|
|
430
|
+
// 1. { 之前紧邻「真正的语义字符」(字母/数字/中文/下划线) → 不是 JSON 起点(散文里的花括号)
|
|
431
|
+
// 但接受 . , ; : 等句末标点(LLM 经常以「总结:{...}」直接开头 JSON)
|
|
432
|
+
// 2. { 之后跳过空白第一个字符必须是 " 或 }(空对象)
|
|
433
|
+
const before = i > 0 ? s[i - 1] : '';
|
|
434
|
+
if (/[A-Za-z0-9_一-龥]/.test(before)) continue;
|
|
435
|
+
let j = i + 1;
|
|
436
|
+
while (j < s.length && /\s/.test(s[j])) j++;
|
|
437
|
+
const firstNonWs = s[j];
|
|
438
|
+
if (firstNonWs !== '"' && firstNonWs !== '}') continue;
|
|
439
|
+
start = i;
|
|
440
|
+
}
|
|
441
|
+
depth++;
|
|
442
|
+
} else if (ch === '}') {
|
|
443
|
+
if (depth > 0) depth--;
|
|
444
|
+
if (depth === 0 && start !== -1) {
|
|
445
|
+
return s.slice(start, i + 1);
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
// 兜底:找不到平衡对象时返回原文(让上层 JSON.parse 报清晰错误)
|
|
450
|
+
return s;
|
|
451
|
+
}
|
|
452
|
+
|
|
391
453
|
async function callLlmJson(model, prompt, opts = {}) {
|
|
392
|
-
const {
|
|
454
|
+
const { timeoutMs = 60000, images = [] } = opts;
|
|
393
455
|
const { default: fetch } = await import('node-fetch').catch(() => ({ default: globalThis.fetch }));
|
|
394
456
|
const url = `${String(model.baseURL || '').replace(/\/$/, '')}/chat/completions`;
|
|
395
457
|
const headers = { 'Content-Type': 'application/json' };
|
|
@@ -410,7 +472,6 @@ async function callLlmJson(model, prompt, opts = {}) {
|
|
|
410
472
|
const body = JSON.stringify({
|
|
411
473
|
model: model.model,
|
|
412
474
|
messages: [{ role: 'user', content: userContent }],
|
|
413
|
-
max_tokens: maxTokens,
|
|
414
475
|
temperature: 0.4,
|
|
415
476
|
response_format: { type: 'json_object' },
|
|
416
477
|
stream: false,
|
|
@@ -422,18 +483,37 @@ async function callLlmJson(model, prompt, opts = {}) {
|
|
|
422
483
|
const resp = await fetch(url, { method: 'POST', headers, body, signal: controller.signal });
|
|
423
484
|
const data = await resp.json().catch(() => ({}));
|
|
424
485
|
if (!resp.ok) throw new Error(data?.error?.message || `HTTP ${resp.status}`);
|
|
425
|
-
const content = data?.choices?.[0]?.message?.content || '
|
|
486
|
+
const content = data?.choices?.[0]?.message?.content || '';
|
|
487
|
+
if (!content.trim()) {
|
|
488
|
+
throw new Error('LLM 返回内容为空');
|
|
489
|
+
}
|
|
426
490
|
try {
|
|
427
|
-
const
|
|
428
|
-
return JSON.parse(
|
|
429
|
-
} catch {
|
|
430
|
-
|
|
491
|
+
const cleaned = stripThinkingBlocks(content);
|
|
492
|
+
return JSON.parse(extractFirstJsonObject(cleaned));
|
|
493
|
+
} catch (err) {
|
|
494
|
+
const snippet = content.length > 500 ? content.slice(0, 500) + '…' : content;
|
|
495
|
+
throw new Error(`LLM 返回非 JSON 或被截断:${err.message};原始内容片段:${snippet}`);
|
|
431
496
|
}
|
|
432
497
|
} finally {
|
|
433
498
|
clearTimeout(timer);
|
|
434
499
|
}
|
|
435
500
|
}
|
|
436
501
|
|
|
502
|
+
async function callLlmJsonWithRetry(model, prompt, opts = {}, retries = 1) {
|
|
503
|
+
let lastErr;
|
|
504
|
+
for (let i = 0; i <= retries; i++) {
|
|
505
|
+
try {
|
|
506
|
+
return await callLlmJson(model, prompt, opts);
|
|
507
|
+
} catch (err) {
|
|
508
|
+
lastErr = err;
|
|
509
|
+
if (i < retries) {
|
|
510
|
+
await new Promise(r => setTimeout(r, 800 * (i + 1)));
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
throw lastErr;
|
|
515
|
+
}
|
|
516
|
+
|
|
437
517
|
/**
|
|
438
518
|
* 流式调用 OpenAI 兼容 LLM。每收到一个 chunk 调 onDelta 回调。
|
|
439
519
|
* onDelta 接收 { thinking?: string, content?: string },二选一。
|
|
@@ -1118,13 +1198,21 @@ async function runTaskQueue(task, repoPath, branch, opts) {
|
|
|
1118
1198
|
const priorOutputs = fromIndex > 0
|
|
1119
1199
|
? await collectPriorOutputsUpTo(task, fromIndex)
|
|
1120
1200
|
: []
|
|
1201
|
+
// 连续模式(默认):任意 sub 终态非 done(cancelled / error)→ 整批停,后续 sub 保持 todo。
|
|
1202
|
+
// AI 拆出来的 sub 一般前后强依赖(前一步产出是后一步输入),出错就停下来让用户决策。
|
|
1203
|
+
// 关闭后回退旧行为:单个 sub 失败不影响后续 sub 继续跑。
|
|
1204
|
+
const sequential = task.sequential !== false
|
|
1121
1205
|
for (let i = fromIndex; i < task.subtasks.length; i++) {
|
|
1122
1206
|
const sub = task.subtasks[i]
|
|
1123
1207
|
if (sub.status === 'done') continue;
|
|
1124
|
-
await runSingleSubtask(task, sub, repoPath, branch, priorOutputs)
|
|
1208
|
+
const outcome = await runSingleSubtask(task, sub, repoPath, branch, priorOutputs)
|
|
1125
1209
|
// 逐 sub 落盘:之前只在队列跑完才 persistTaskAfterRun,中途崩溃会丢已完成
|
|
1126
1210
|
// sub 的状态。runSingleSubtask 已经把 sub.status 改完,这里补一次落盘。
|
|
1127
1211
|
await persistTaskAfterRun(task)
|
|
1212
|
+
if (sequential && outcome !== 'done') {
|
|
1213
|
+
// cancelled / error → 后续 sub 全部保持 todo,不再继续
|
|
1214
|
+
break
|
|
1215
|
+
}
|
|
1128
1216
|
}
|
|
1129
1217
|
}
|
|
1130
1218
|
|
|
@@ -1325,7 +1413,12 @@ ${prompt}`
|
|
|
1325
1413
|
job.exitCode = 130; // 128 + SIGINT(2),约定俗成的"用户取消"退出码
|
|
1326
1414
|
job.status = 'cancelled';
|
|
1327
1415
|
job.error = '用户已停止执行';
|
|
1328
|
-
// sub
|
|
1416
|
+
// 同步把闭包里的 sub 也置 cancelled(cancel 接口的 syncSubToCancelled 改了磁盘 task
|
|
1417
|
+
// 引用,但 runSingleSubtask 形参里的 sub 是另一份内存引用)。否则 finally publish sub:update
|
|
1418
|
+
// 会用 status='running' 覆盖掉前端已渲染的 cancelled 状态,导致 UI 反复跳回 running。
|
|
1419
|
+
// 同时 sequential=true 时 runTaskQueue 会看到 outcome='cancelled',break 不再跑后续 sub。
|
|
1420
|
+
sub.status = 'cancelled';
|
|
1421
|
+
if (!sub.error) sub.error = '用户已停止执行';
|
|
1329
1422
|
} else {
|
|
1330
1423
|
job.exitCode = 0;
|
|
1331
1424
|
job.status = 'done';
|
|
@@ -1359,6 +1452,36 @@ ${prompt}`
|
|
|
1359
1452
|
console.warn('[workbench] flushJobsSaveNow failed (job id=' + job.id + ', status=' + job.status + '):', err && err.message || err)
|
|
1360
1453
|
}
|
|
1361
1454
|
}
|
|
1455
|
+
// 把 sub 的终态返回给 runTaskQueue,用于「连续模式」判断要不要 break 整批队列
|
|
1456
|
+
return job.status // 'done' | 'cancelled' | 'error'
|
|
1457
|
+
}
|
|
1458
|
+
|
|
1459
|
+
/**
|
|
1460
|
+
* 把被取消的 sub 同步置 'cancelled' 并落盘。
|
|
1461
|
+
* cancelJob 路径专用:前端 taskIsRunning/sub.is-running 都看 sub.status,不改就会出现
|
|
1462
|
+
* "主任务黄点 + sub running 动效 + 右侧执行完成"三处不一致。
|
|
1463
|
+
*
|
|
1464
|
+
* 简单任务的虚拟 subId 不在 tasks.json 里(task.subtasks 是 complex 才有),所以这里
|
|
1465
|
+
* 找不到 sub 时静默返回;简单任务的 running 状态由 job 数组单独维护(见 taskIsRunning)。
|
|
1466
|
+
*
|
|
1467
|
+
* @returns {{ taskId: string, sub: object } | null} 找到并更新时返回新 sub,否则 null
|
|
1468
|
+
*/
|
|
1469
|
+
async function syncSubToCancelled(job) {
|
|
1470
|
+
if (!job || !job.taskId || !job.subId) return null
|
|
1471
|
+
const data = await readJson(TASKS_FILE, { tasks: [] })
|
|
1472
|
+
const task = (data.tasks || []).find(x => x.id === job.taskId)
|
|
1473
|
+
if (!task || !Array.isArray(task.subtasks)) return null
|
|
1474
|
+
const sub = task.subtasks.find(s => s && s.id === job.subId)
|
|
1475
|
+
if (!sub) return null
|
|
1476
|
+
if (sub.status === 'cancelled') return { taskId: task.id, sub } // 已置过,幂等返回
|
|
1477
|
+
sub.status = 'cancelled'
|
|
1478
|
+
sub.error = '用户已停止执行'
|
|
1479
|
+
sub.errorAt = nowIso()
|
|
1480
|
+
task.updatedAt = nowIso()
|
|
1481
|
+
await writeJson(TASKS_FILE, data)
|
|
1482
|
+
publish('sub:update', { taskId: task.id, sub })
|
|
1483
|
+
publish('task:update', task)
|
|
1484
|
+
return { taskId: task.id, sub }
|
|
1362
1485
|
}
|
|
1363
1486
|
|
|
1364
1487
|
/** 把 task.subtasks 写回 tasks.json,并广播 task:update。runTaskQueue 和"单 sub 执行"共用。 */
|
|
@@ -1488,7 +1611,7 @@ export function registerWorkbenchRoutes({ app, getCurrentProjectPath, getProject
|
|
|
1488
1611
|
}
|
|
1489
1612
|
|
|
1490
1613
|
const projectName = path.basename(projectPath);
|
|
1491
|
-
const LLM_OPTS = {
|
|
1614
|
+
const LLM_OPTS = { timeoutMs: 1200000 };
|
|
1492
1615
|
|
|
1493
1616
|
// ── 第一阶段:基于可编辑指令 + 根目录概览,生成「可复用的提示词模板」 ──
|
|
1494
1617
|
const overviewBlock = subProjects.map(sp =>
|
|
@@ -1522,7 +1645,7 @@ ${subProjects.map(sp => {
|
|
|
1522
1645
|
"template": "可复用的提示词模板,长度不限,请充分覆盖 {{task.title}} / {{task.desc}} / {{sub.title}} / {{sub.desc}} / {{repo.path}} / {{branch}} 这 6 个变量的用法与上下文"
|
|
1523
1646
|
}`;
|
|
1524
1647
|
|
|
1525
|
-
const first = await
|
|
1648
|
+
const first = await callLlmJsonWithRetry(model, firstPrompt, LLM_OPTS);
|
|
1526
1649
|
const templateName = String(first.name || '').trim() || `${projectName}架构说明`;
|
|
1527
1650
|
const template = String(first.template || '').trim();
|
|
1528
1651
|
|
|
@@ -1553,11 +1676,15 @@ ${sp.readme || '(无)'}
|
|
|
1553
1676
|
{
|
|
1554
1677
|
"summary": "该子项目的架构说明,长度不限,模型自行决定篇幅与详尽程度,能写多详细就多详细"
|
|
1555
1678
|
}`;
|
|
1556
|
-
const r = await
|
|
1679
|
+
const r = await callLlmJsonWithRetry(model, subPrompt, LLM_OPTS);
|
|
1557
1680
|
return { name: sp.name, root: sp.root, summary: String(r.summary || '').trim() };
|
|
1558
1681
|
}
|
|
1559
1682
|
|
|
1560
|
-
|
|
1683
|
+
// 串行执行,避免并发触发 provider 限流(429)导致整批失败
|
|
1684
|
+
const subSummaries = [];
|
|
1685
|
+
for (const sp of subProjects) {
|
|
1686
|
+
subSummaries.push(await summarizeOneSub(sp));
|
|
1687
|
+
}
|
|
1561
1688
|
|
|
1562
1689
|
// ── 第三阶段:仅多子项目时合并(单子项目直接拿它的 summary) ──
|
|
1563
1690
|
let finalSummary = '';
|
|
@@ -1578,7 +1705,7 @@ ${sp.readme || '(无)'}
|
|
|
1578
1705
|
## 子项目说明
|
|
1579
1706
|
${subSummaries.map((s, i) => `\n### [${i + 1}] ${s.name} (${s.root})\n${s.summary || '(空)'}`).join('\n')}`;
|
|
1580
1707
|
|
|
1581
|
-
const merged = await
|
|
1708
|
+
const merged = await callLlmJsonWithRetry(model, mergePrompt, LLM_OPTS);
|
|
1582
1709
|
finalSummary = String(merged.summary || '').trim()
|
|
1583
1710
|
|| subSummaries.map(s => `### ${s.name}\n${s.summary}`).join('\n\n');
|
|
1584
1711
|
finalName = String(merged.name || '').trim() || templateName;
|
|
@@ -1588,13 +1715,9 @@ ${subSummaries.map((s, i) => `\n### [${i + 1}] ${s.name} (${s.root})\n${s.summar
|
|
|
1588
1715
|
finalName = `${projectName}架构说明`;
|
|
1589
1716
|
|
|
1590
1717
|
if (!finalSummary) {
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
name: finalName,
|
|
1595
|
-
template,
|
|
1596
|
-
result: '',
|
|
1597
|
-
content: template
|
|
1718
|
+
return res.status(502).json({
|
|
1719
|
+
success: false,
|
|
1720
|
+
error: '模型返回为空,请稍后重试'
|
|
1598
1721
|
});
|
|
1599
1722
|
}
|
|
1600
1723
|
|
|
@@ -2276,11 +2399,14 @@ ${desc ? `描述:${desc}` : '描述:(无)'}${attachmentBlock}${templateB
|
|
|
2276
2399
|
|
|
2277
2400
|
app.post('/api/workbench/tasks', async (req, res) => {
|
|
2278
2401
|
try {
|
|
2279
|
-
const { id, title, desc, promptId, subtasks, type: rawType, simpleOverride } = req.body || {};
|
|
2402
|
+
const { id, title, desc, promptId, subtasks, type: rawType, simpleOverride, sequential: rawSequential } = req.body || {};
|
|
2280
2403
|
// title 非必填:允许空字符串,UI 层会用"未命名任务"占位
|
|
2281
2404
|
const safeTitle = typeof title === 'string' ? title.trim() : '';
|
|
2282
2405
|
// type 归一化:仅接受 'simple' | 'complex',缺省/未知一律按 complex
|
|
2283
2406
|
const taskType = rawType === 'simple' ? 'simple' : 'complex';
|
|
2407
|
+
// sequential 归一化:仅接受 boolean,缺省/非布尔一律 true(连续模式),
|
|
2408
|
+
// 旧任务没字段时也是 true,保留连续默认行为
|
|
2409
|
+
const sequential = rawSequential === false ? false : true;
|
|
2284
2410
|
const safeOverride = typeof simpleOverride === 'string' ? simpleOverride.slice(0, 8000) : '';
|
|
2285
2411
|
const data = await readJson(TASKS_FILE, { tasks: [] });
|
|
2286
2412
|
const tasks = data.tasks || [];
|
|
@@ -2296,6 +2422,8 @@ ${desc ? `描述:${desc}` : '描述:(无)'}${attachmentBlock}${templateB
|
|
|
2296
2422
|
desc: desc || '',
|
|
2297
2423
|
promptId: promptId || null,
|
|
2298
2424
|
type: taskType,
|
|
2425
|
+
// 复杂任务可显式关闭连续模式;简单任务无意义,固定 true
|
|
2426
|
+
sequential: taskType === 'complex' ? sequential : true,
|
|
2299
2427
|
simpleOverride: taskType === 'simple' ? safeOverride : '',
|
|
2300
2428
|
subtasks: Array.isArray(subtasks) ? subtasks.map(s => ({
|
|
2301
2429
|
id: s.id || genId(),
|
|
@@ -2329,6 +2457,8 @@ ${desc ? `描述:${desc}` : '描述:(无)'}${attachmentBlock}${templateB
|
|
|
2329
2457
|
desc: desc || '',
|
|
2330
2458
|
promptId: promptId || null,
|
|
2331
2459
|
type: taskType,
|
|
2460
|
+
// 新建任务:简单任务固定 true,复杂任务用传入值(默认 true)
|
|
2461
|
+
sequential: taskType === 'complex' ? sequential : true,
|
|
2332
2462
|
simpleOverride: taskType === 'simple' ? safeOverride : '',
|
|
2333
2463
|
projectPath: currentProjectPath || '',
|
|
2334
2464
|
subtasks: Array.isArray(subtasks) ? subtasks.map(s => ({
|
|
@@ -2530,7 +2660,11 @@ ${desc ? `描述:${desc}` : '描述:(无)'}${attachmentBlock}${templateB
|
|
|
2530
2660
|
// - 找到正在运行的 job,调 child.kill() 终止 claude 进程
|
|
2531
2661
|
// - Windows 下用 taskkill /T /F 杀进程树(claude 进程可能 fork 出子进程)
|
|
2532
2662
|
// - 加入 cancelledJobs 集合,runTaskQueue 退出循环后会把 job 标为 'cancelled'
|
|
2533
|
-
// -
|
|
2663
|
+
// - 同步把 sub.status 改为 'cancelled' 并 publish sub:update,
|
|
2664
|
+
// 否则前端 sub 列表/任务头黄点会一直显示 running(sub.status 没动)。
|
|
2665
|
+
// 历史这里只改 job.status 导致 UI 误显示「执行中」。
|
|
2666
|
+
// - 只影响这一个 sub;同 task 后续 sub 在 sequential=false 时继续执行,
|
|
2667
|
+
// sequential=true 时由 runTaskQueue 自然 break(见 runSingleSubtask 的 cancelled 分支)
|
|
2534
2668
|
app.post('/api/workbench/jobs/:id/cancel', (req, res) => {
|
|
2535
2669
|
const job = jobs.get(req.params.id)
|
|
2536
2670
|
if (!job) {
|
|
@@ -2545,6 +2679,9 @@ ${desc ? `描述:${desc}` : '描述:(无)'}${attachmentBlock}${templateB
|
|
|
2545
2679
|
job.error = '用户已停止执行'
|
|
2546
2680
|
job.endedAt = nowIso()
|
|
2547
2681
|
publish('job:update', { ...job }) // 用浅拷贝避免序列化 child 引用
|
|
2682
|
+
// 同步把 sub 也置 cancelled,否则 taskIsRunning(sub.status==='running') 一直 true
|
|
2683
|
+
// → 左侧任务头黄点 + 右侧 sub 列表 running 动效都不消失
|
|
2684
|
+
const subInfo = syncSubToCancelled(job)
|
|
2548
2685
|
// 终态:fire-and-forget 同步落盘,cancel 是显式操作,要保证不丢
|
|
2549
2686
|
flushJobsSaveNow().catch(err => console.warn('[workbench] jobs save failed:', err.message))
|
|
2550
2687
|
const child = job.child
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import"./rolldown-runtime-CMxvf4Kt.js";import{A as e,B as t,Cn as n,D as r,E as i,En as a,Et as o,F as s,Fn as c,In as l,It as u,J as d,K as f,L as p,Ln as m,Lt as h,Nn as g,Nt as _,Ot as v,Pt as y,Qn as b,R as x,Sn as S,Tt as ee,Vn as C,W as te,Wn as w,X as T,Y as ne,Yn as E,Z as re,Zn as D,_n as O,_r as ie,a as k,at as A,b as j,cn as ae,cr as M,ct as N,dn as P,dt as oe,et as F,f as se,gn as I,gt as ce,hn as L,hr as R,i as z,ir as le,it as ue,k as de,l as B,ln as fe,lt as pe,mr as V,o as me,on as he,or as ge,ot as _e,p as ve,pn as ye,pt as be,q as xe,r as Se,rt as Ce,sn as we,un as H,vn as U,vr as W,wn as G,x as K,y as q,yn as J,yt as Te,zn as Y}from"./element-plus-CJjFCgLP.js";import{r as Ee}from"./vendor-0YbzMuxw.js";import{n as X,t as Z}from"./_plugin-vue_export-helper-vLPduyLG.js";import{n as De}from"./index-BxxqloTb.js";var Oe={class:`ai-split-direct-pane`},ke={key:0,class:`ai-split-status`},Ae={key:1,class:`ai-split-status`},je={key:1},Me={key:2},Ne={key:2,class:`ai-split-status is-error`},Pe={key:3,class:`ai-split-idle`},Fe={class:`ai-split-idle__title`},Ie={class:`ai-split-idle__desc`},Le={class:`ai-split-prompt-actions`},Re={key:0,class:`ai-split-prompt-editor`},ze={class:`ai-split-prompt-editor__actions`},Be={key:1,class:`ai-split-pre`},Ve={class:`ai-split-subhead`},He={class:`ai-split-user-actions`},Ue={key:3,class:`ai-split-pre`},We={key:0,class:`ai-split-tab-count`},Ge={class:`ai-split-pre ai-split-pre--think`},Ke={key:0,class:`ai-split-tab-count`},qe={class:`ai-split-parse-error__detail`},Je={class:`ai-split-parse-error__hint`},Q={class:`ai-split-parse-error__actions`},Ye={key:1,class:`ai-split-raw-toolbar`},Xe={class:`ai-split-raw-tip`},Ze={key:0,class:`ai-split-tab-count`},Qe={key:0,class:`ai-split-empty`},$e={key:1,class:`ai-split-list`},et={class:`ai-split-list__no`},tt={class:`ai-split-list__body`},nt={class:`ai-split-list__title`},rt={class:`ai-split-list__desc`},it={key:5,class:`ai-split-footer-hint`},at={class:`ai-split-direct-footer`},ot=Z(a({__name:`AISplitDirectPane`,props:{title:{},desc:{},taskId:{},promptId:{}},emits:[`confirm`],setup(e,{emit:r}){let i=e,a=r,s=M(`idle`),c=M(`prompt`),l=M(``),f=M(``),p=M(``),m=M(``),h=M(``),g=M([]),_=M(``),v=M(``),y=M(``),b=null,x=0,ee=L(()=>p.value.length),w=L(()=>m.value.length),T=L(()=>s.value===`result`&&g.value.length>0),re=L(()=>s.value===`running`),ie=L(()=>s.value===`preview`),A=M(``),j=M(!1);function ae(){b&&=(b.abort(),null)}function N(){ae(),s.value=`idle`,c.value=`prompt`,l.value=``,f.value=``,A.value=``,p.value=``,m.value=``,h.value=``,g.value=[],_.value=``,v.value=``,y.value=``}async function oe(){if(!i.title.trim()){k.warning(X(`@WORKBENCH:请先填写任务标题`));return}N(),s.value=`preview`,c.value=`prompt`,j.value=!0;try{let e=await fetch(`/api/workbench/tasks/ai-split-preview`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({title:i.title,desc:i.desc,taskId:i.taskId||``,promptId:i.promptId||``})}).then(e=>e.json());if(!e.success){s.value=`error`,_.value=e.error||X(`@WORKBENCH:生成预览失败`);return}l.value=e.system||``,f.value=e.user||``,A.value=e.user||``}catch(e){s.value=`error`,_.value=e?.message||String(e)}finally{j.value=!1}}async function F(){if(!A.value.trim()){k.warning(X(`@WORKBENCH:提示词不能为空`));return}let e=++x;ae(),p.value=``,m.value=``,h.value=``,g.value=[],v.value=``,y.value=``,_.value=``,s.value=`running`,c.value=`thinking`,f.value=A.value,b=new AbortController;let t=b;try{let n=await fetch(`/api/workbench/tasks/ai-split-subtasks`,{method:`POST`,headers:{"Content-Type":`application/json`,Accept:`text/event-stream`},body:JSON.stringify({title:i.title,desc:i.desc,taskId:i.taskId||``,promptId:i.promptId||``,customUserBlock:A.value}),signal:t.signal});if(e!==x)return;if(!n.ok||!n.body){let e=await n.text().catch(()=>``);throw Error(e||`HTTP ${n.status}`)}let r=n.body.getReader(),a=new TextDecoder(`utf-8`),o=``,u=null;for(;;){let{value:t,done:n}=await r.read();if(e!==x)return;if(n)break;o+=a.decode(t,{stream:!0});let i=o.split(`
|
|
2
|
-
`);o=i.pop()??``;for(let e of i){let t=e.trim();if(!t.startsWith(`data:`))continue;let n=t.slice(5).trim();if(!n)continue;let r;try{r=JSON.parse(n)}catch{continue}switch(r.type){case`meta`:l.value=r.prompt?.system||l.value;break;case`thinking`:p.value+=String(r.delta||``);break;case`content`:m.value+=String(r.delta||``);break;case`done`:u=r;break;case`error`:throw Error(r.error||`AI 拆分失败`)}}}if(e!==x)return;if(!u)throw Error(X(`@WORKBENCH:AI 未返回结果`));g.value=Array.isArray(u.subtasks)?u.subtasks:[],h.value=u.raw||m.value,v.value=String(u.parseError||``),y.value=String(u.parseStage||``),p.value||=X(`@WORKBENCH:(当前模型未返回独立的思考内容,可切换到「原始结果」查看完整输出)`),s.value=`result`,c.value=g.value.length>0?`confirm`:`raw`}catch(n){if(e!==x)return;if(n?.name===`AbortError`||t.signal.aborted){s.value=`preview`,c.value=`prompt`;return}s.value=`error`,_.value=n?.message||String(n)}finally{e===x&&(b=null)}}function ce(){T.value&&a(`confirm`,g.value.slice())}function R(){A.value.trim()?F():oe()}function z(){b&&(b.abort(),b=null,k.info(X(`@WORKBENCH:已停止拆分`)))}let le=M(!1);async function ue(){if(!m.value.trim()){k.warning(X(`@WORKBENCH:原始结果为空,无法解析`));return}le.value=!0;try{let e=await fetch(`/api/workbench/tasks/parse-subtasks`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({raw:m.value})}).then(e=>e.json());if(!e.success){k.error(e.error||X(`@WORKBENCH:解析失败`));return}g.value=Array.isArray(e.subtasks)?e.subtasks:[],v.value=String(e.parseError||``),y.value=String(e.parseStage||``),h.value=m.value,g.value.length>0?(k.success(X(`@WORKBENCH:解析成功,已识别 {n} 个子任务`,{n:g.value.length})),c.value=`confirm`):k.warning(X(`@WORKBENCH:仍未解析到子任务,请继续修改原始结果`))}catch(e){k.error(X(`@WORKBENCH:解析失败: `)+(e?.message||e))}finally{le.value=!1}}E(()=>i.taskId,()=>{N()});let de=M(!1),B=M(``),fe=M(!1);function pe(){B.value=l.value,de.value=!0}async function me(){if(!B.value.trim()){k.warning(X(`@WORKBENCH:指令内容不能为空`));return}fe.value=!0;try{let e=await fetch(`/api/workbench/tasks/ai-subtask-instruction`,{method:`PUT`,headers:{"Content-Type":`application/json`},body:JSON.stringify({instruction:B.value})}).then(e=>e.json());e.success?(k.success(X(`@WORKBENCH:已保存指令`)),de.value=!1,oe()):k.error(e.error||X(`@WORKBENCH:保存失败`))}catch(e){k.error(X(`@WORKBENCH:保存失败: `)+(e?.message||e))}finally{fe.value=!1}}function he(){de.value=!1}return(e,r)=>{let i=ne,a=t,h=te,y=se,b=d,x=ve;return Y(),J(`div`,Oe,[re.value?(Y(),J(`div`,ke,[G(i,{class:`is-loading`},{default:D(()=>[G(V(o))]),_:1}),I(`span`,null,W(V(X)(`@WORKBENCH:AI 正在拆分…`)),1),G(a,{size:`small`,link:``,type:`danger`,class:`ai-split-status__stop`,onClick:z},{default:D(()=>[n(W(V(X)(`@WORKBENCH:停止拆分`)),1)]),_:1})])):ie.value?(Y(),J(`div`,Ae,[j.value?(Y(),O(i,{key:0,class:`is-loading`},{default:D(()=>[G(V(o))]),_:1})):U(``,!0),j.value?(Y(),J(`span`,je,W(V(X)(`@WORKBENCH:正在生成提示词预览…`)),1)):(Y(),J(`span`,Me,W(V(X)(`@WORKBENCH:提示词已就绪,可在下方编辑后点「发送给 AI」开始拆分`)),1))])):s.value===`error`?(Y(),J(`div`,Ne,[G(i,{color:`#f56c6c`},{default:D(()=>[G(V(Ce))]),_:1}),I(`span`,null,W(_.value),1)])):s.value===`idle`?(Y(),J(`div`,Pe,[r[5]||=S(`<div class="ai-split-idle__icon" aria-hidden="true" data-v-85bcc687><svg viewBox="0 0 24 24" width="36" height="36" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" data-v-85bcc687><path d="M12 3v3" data-v-85bcc687></path><path d="M12 18v3" data-v-85bcc687></path><path d="M3 12h3" data-v-85bcc687></path><path d="M18 12h3" data-v-85bcc687></path><path d="M5.6 5.6l2.1 2.1" data-v-85bcc687></path><path d="M16.3 16.3l2.1 2.1" data-v-85bcc687></path><path d="M5.6 18.4l2.1-2.1" data-v-85bcc687></path><path d="M16.3 7.7l2.1-2.1" data-v-85bcc687></path><circle cx="12" cy="12" r="4" data-v-85bcc687></circle></svg></div>`,1),I(`div`,Fe,W(V(X)(`@WORKBENCH:准备用 AI 拆分任务`)),1),I(`div`,Ie,W(V(X)(`@WORKBENCH:点击下方按钮开始生成。生成期间可切换到「思考 / 原始结果」实时查看模型输出。`)),1),G(a,{type:`primary`,icon:V(u),onClick:oe},{default:D(()=>[n(W(V(X)(`@WORKBENCH:开始拆分`)),1)]),_:1},8,[`icon`])])):U(``,!0),s.value===`idle`?U(``,!0):(Y(),O(x,{key:4,modelValue:c.value,"onUpdate:modelValue":r[4]||=e=>c.value=e,class:`ai-split-tabs`},{default:D(()=>[G(y,{label:V(X)(`@WORKBENCH:提示词`),name:`prompt`},{default:D(()=>[I(`div`,Le,[G(a,{size:`small`,disabled:re.value,onClick:pe},{default:D(()=>[n(W(V(X)(`@WORKBENCH:编辑指令`)),1)]),_:1},8,[`disabled`])]),de.value?(Y(),J(`div`,Re,[G(h,{modelValue:B.value,"onUpdate:modelValue":r[0]||=e=>B.value=e,type:`textarea`,rows:12,placeholder:V(X)(`@WORKBENCH:指令内容`)},null,8,[`modelValue`,`placeholder`]),I(`div`,ze,[G(a,{size:`small`,onClick:he},{default:D(()=>[n(W(V(X)(`@WORKBENCH:取消`)),1)]),_:1}),G(a,{size:`small`,type:`primary`,loading:fe.value,onClick:me},{default:D(()=>[n(W(V(X)(`@WORKBENCH:保存并重跑`)),1)]),_:1},8,[`loading`])])])):(Y(),J(`pre`,Be,W(l.value||`(等待 LLM 启动…)`),1)),I(`h4`,Ve,W(V(X)(`@WORKBENCH:用户提示词(拼装后)`)),1),ie.value?(Y(),J(P,{key:2},[G(h,{modelValue:A.value,"onUpdate:modelValue":r[1]||=e=>A.value=e,type:`textarea`,rows:16,placeholder:V(X)(`@WORKBENCH:正在生成预览…`),readonly:j.value,class:`ai-split-user-editor`,resize:`none`},null,8,[`modelValue`,`placeholder`,`readonly`]),I(`div`,He,[G(a,{size:`small`,disabled:j.value,onClick:N},{default:D(()=>[n(W(V(X)(`@WORKBENCH:取消`)),1)]),_:1},8,[`disabled`]),G(a,{type:`primary`,icon:V(u),disabled:j.value||!A.value.trim(),onClick:F},{default:D(()=>[n(W(V(X)(`@WORKBENCH:发送给 AI`)),1)]),_:1},8,[`icon`,`disabled`])])],64)):(Y(),J(`pre`,Ue,W(f.value||`(等待 LLM 启动…)`),1))]),_:1},8,[`label`]),G(y,{name:`thinking`},{label:D(()=>[I(`span`,null,[n(W(V(X)(`@WORKBENCH:思考`))+` `,1),ee.value>0?(Y(),J(`span`,We,`(`+W(ee.value)+`)`,1)):U(``,!0)])]),default:D(()=>[I(`pre`,Ge,W(p.value||V(X)(`@WORKBENCH:(暂无输出)`)),1)]),_:1}),G(y,{name:`raw`},{label:D(()=>[I(`span`,null,[n(W(V(X)(`@WORKBENCH:原始结果`))+` `,1),w.value>0?(Y(),J(`span`,Ke,`(`+W(w.value)+`)`,1)):U(``,!0)])]),default:D(()=>[v.value&&s.value===`result`?(Y(),O(b,{key:0,type:`warning`,"show-icon":``,closable:!1,class:`ai-split-parse-error`},{title:D(()=>[n(W(V(X)(`@WORKBENCH:模型返回内容解析失败,无法识别为有效的子任务 JSON`)),1)]),default:D(()=>[I(`div`,qe,W(v.value),1),I(`div`,Je,W(V(X)(`@WORKBENCH:常见原因:desc 内夹杂了 ASCII 双引号、出现尾随逗号,或输出被截断。可在下方文本框中手动修改后点「重新解析」,或重新生成。`)),1),I(`div`,Q,[G(a,{size:`small`,type:`primary`,loading:le.value,onClick:ue},{default:D(()=>[n(W(V(X)(`@WORKBENCH:重新解析`)),1)]),_:1},8,[`loading`]),G(a,{size:`small`,onClick:R},{default:D(()=>[n(W(V(X)(`@WORKBENCH:重新生成`)),1)]),_:1}),G(a,{size:`small`,onClick:r[2]||=e=>c.value=`prompt`},{default:D(()=>[n(W(V(X)(`@WORKBENCH:去编辑指令`)),1)]),_:1})])]),_:1})):U(``,!0),s.value===`result`||m.value?(Y(),J(`div`,Ye,[I(`span`,Xe,W(V(X)(`@WORKBENCH:可直接编辑下方文本,修正后点「重新解析」即可入库`)),1),G(a,{size:`small`,type:`primary`,loading:le.value,disabled:!m.value.trim(),onClick:ue},{default:D(()=>[n(W(V(X)(`@WORKBENCH:重新解析`)),1)]),_:1},8,[`loading`,`disabled`])])):U(``,!0),G(h,{modelValue:m.value,"onUpdate:modelValue":r[3]||=e=>m.value=e,type:`textarea`,rows:14,placeholder:V(X)(`@WORKBENCH:(暂无输出)`),readonly:re.value,class:`ai-split-raw-editor`,resize:`none`},null,8,[`modelValue`,`placeholder`,`readonly`])]),_:1}),G(y,{name:`confirm`,disabled:g.value.length===0},{label:D(()=>[I(`span`,null,[n(W(V(X)(`@WORKBENCH:确认入库`))+` `,1),g.value.length>0?(Y(),J(`span`,Ze,`(`+W(g.value.length)+`)`,1)):U(``,!0)])]),default:D(()=>[g.value.length===0?(Y(),J(`div`,Qe,W(V(X)(`@WORKBENCH:(暂无子任务)`)),1)):(Y(),J(`ul`,$e,[(Y(!0),J(P,null,C(g.value,(e,t)=>(Y(),J(`li`,{key:t,class:`ai-split-list__item`},[I(`div`,et,W(t+1),1),I(`div`,tt,[I(`div`,nt,W(e.title),1),I(`div`,rt,W(e.desc),1)])]))),128))]))]),_:1},8,[`disabled`])]),_:1},8,[`modelValue`])),v.value&&s.value===`result`&&g.value.length===0?(Y(),J(`div`,it,[G(i,{color:`#e6a23c`},{default:D(()=>[G(V(Ce))]),_:1}),I(`span`,null,W(V(X)(`@WORKBENCH:解析失败,未能从模型输出中提取出子任务 — 请查看「原始结果」`)),1)])):U(``,!0),I(`div`,at,[s.value===`error`||s.value===`result`&&v.value&&g.value.length===0?(Y(),O(a,{key:0,onClick:R},{default:D(()=>[n(W(V(X)(`@WORKBENCH:重新生成`)),1)]),_:1})):U(``,!0),s.value===`result`&&g.value.length>0?(Y(),O(a,{key:1,onClick:R},{default:D(()=>[n(W(V(X)(`@WORKBENCH:重新拆分`)),1)]),_:1})):U(``,!0),G(a,{type:`primary`,disabled:!T.value,onClick:ce},{default:D(()=>[n(W(V(X)(`@WORKBENCH:确认入库`))+` (`+W(g.value.length)+`) `,1)]),_:1},8,[`disabled`])])])}}}),[[`__scopeId`,`data-v-85bcc687`]]),st={class:`ai-chat-pane`},ct={key:0,class:`ai-chat-streaming-banner`},lt={key:1,class:`ai-chat-empty`},ut={class:`ai-chat-empty__title`},dt={class:`ai-chat-empty__desc`},ft={key:0,class:`ai-chat-bubble user`},pt={class:`ai-chat-content`},mt={key:1,class:`ai-chat-bubble assistant`},ht={class:`ai-chat-pre ai-chat-pre--think`},gt={key:1,class:`ai-chat-content-text`},_t={key:2,class:`ai-chat-subtasks`},vt={class:`ai-chat-subtasks__head`},yt={class:`ai-chat-subtasks__count`},bt={class:`ai-chat-list`},xt={class:`ai-chat-list__no`},St={class:`ai-chat-list__body`},Ct={class:`ai-chat-list__title`},wt={class:`ai-chat-list__desc`},Tt={class:`ai-chat-parse-error__detail`},Et={class:`ai-chat-pre`},Dt={key:5,class:`ai-chat-turn__actions`},Ot={class:`ai-chat-input`},kt={class:`ai-chat-input__actions`},At={key:0,class:`ai-chat-history__loading`},jt={key:1,class:`ai-chat-history__empty`},Mt={key:2,class:`ai-chat-history__list`},Nt={class:`ai-chat-history__title`},Pt={class:`ai-chat-history__meta`},Ft={class:`ai-chat-history__actions`},It=Z(a({__name:`AISplitChatPane`,props:{title:{},desc:{},taskId:{},promptId:{},initialSessionId:{}},emits:[`confirm`],setup(r,{emit:a}){let s=r,c=a,l=M(`idle`),d=M(``),f=M([]),p=M(``),m=M(``),_=null,v=0,y=M(null),b=L(()=>l.value===`streaming`),x=L(()=>{if(!b.value)return``;let e=[...f.value].reverse().find(e=>e.role===`assistant`);return e?e.content?X(`@WORKBENCH:AI 正在输出…`):e.thinking?X(`@WORKBENCH:AI 正在思考… (已思考 {n} 字)`,{n:e.thinking.length}):X(`@WORKBENCH:AI 正在思考…`):X(`@WORKBENCH:AI 正在思考…`)}),S=M(!1),ee=M(!1),w=M([]);function T(){y.value&&(y.value.scrollTop=y.value.scrollHeight)}async function E(){let e=p.value.trim();if(!e||b.value)return;if(!d.value&&!s.title.trim()){k.warning(X(`@WORKBENCH:请先填写任务标题`));return}let t=++v;_=new AbortController;let n=_,r={role:`user`,content:e};f.value.push(r),p.value=``;let i={role:`assistant`,content:``,thinking:``};f.value.push(i),l.value=`streaming`,await g(),T();try{let r=await fetch(`/api/workbench/tasks/ai-chat-split`,{method:`POST`,headers:{"Content-Type":`application/json`,Accept:`text/event-stream`},body:JSON.stringify({sessionId:d.value,title:s.title,desc:s.desc,taskId:s.taskId||``,promptId:s.promptId||``,userMessage:e}),signal:n.signal});if(t!==v)return;if(!r.ok||!r.body){let e=await r.text().catch(()=>``);throw Error(e||`HTTP ${r.status}`)}let a=r.body.getReader(),o=new TextDecoder(`utf-8`),c=``,u=null,p=!1;for(;;){let{value:e,done:n}=await a.read();if(t!==v)return;if(n)break;c+=o.decode(e,{stream:!0});let r=c.split(`
|
|
3
|
-
`);c=r.pop()??``;for(let e of r){let t=e.trim();if(!t.startsWith(`data:`))continue;let n=t.slice(5).trim();if(!n)continue;let r;try{r=JSON.parse(n)}catch{continue}switch(r.type){case`meta`:r.sessionId&&(d.value=r.sessionId);break;case`user_echo`:p=!0;break;case`thinking`:i.thinking=(i.thinking||``)+String(r.delta||``);break;case`content`:i.content+=String(r.delta||``);break;case`done`:u=r;break;case`error`:throw Error(r.error||`对话拆分失败`)}}f.value=[...f.value],await g(),T()}if(t!==v)return;if(!p&&!u)throw Error(X(`@WORKBENCH:AI 未返回结果`));u&&(i.subtasks=Array.isArray(u.subtasks)?u.subtasks:[],i.raw=String(u.raw||i.content),i.parseError=String(u.parseError||``),i.parseStage=String(u.parseStage||``)),f.value=[...f.value],await g(),T(),l.value=`idle`}catch(e){if(t!==v)return;if(e?.name===`AbortError`||n.signal.aborted){i.content=(i.content||``)+`
|
|
4
|
-
|
|
5
|
-
[已停止]`,f.value=[...f.value],l.value=`idle`;return}l.value=`error`,m.value=e?.message||String(e),k.error(m.value)}finally{t===v&&(_=null)}}function re(){_&&=(_.abort(),null)}function ie(){if(b.value){k.warning(X(`@WORKBENCH:请先停止当前生成`));return}f.value=[],d.value=``,m.value=``,l.value=`idle`}function j(e){if(!e.subtasks||e.subtasks.length===0){k.warning(X(`@WORKBENCH:当前没有可应用的子任务`));return}c(`confirm`,e.subtasks.slice())}async function ae(){S.value=!0,ee.value=!0;try{let e=await fetch(`/api/workbench/tasks/ai-chat-sessions`).then(e=>e.json());if(!e.success){k.error(e.error||X(`@WORKBENCH:加载历史会话失败`));return}w.value=Array.isArray(e.sessions)?e.sessions:[]}catch(e){k.error(X(`@WORKBENCH:加载历史会话失败: `)+(e?.message||e))}finally{ee.value=!1}}async function N(e){if(S.value=!1,b.value){k.warning(X(`@WORKBENCH:请先停止当前生成`));return}try{let t=await fetch(`/api/workbench/tasks/ai-chat-sessions/${encodeURIComponent(e)}`).then(e=>e.json());if(!t.success){k.error(t.error||X(`@WORKBENCH:加载历史会话失败`));return}let n=t.session;d.value=n.sessionId;let r=(n.messages||[]).filter(e=>e.role===`user`||e.role===`assistant`).map(e=>({role:e.role,content:e.content||``,thinking:``,subtasks:void 0,raw:void 0,parseError:``,parseStage:``})),i=[...r].reverse().find(e=>e.role===`assistant`);i&&Array.isArray(n.latestSubtasks)&&(i.subtasks=n.latestSubtasks,i.raw=n.latestRaw,i.parseStage=n.latestParseStage),f.value=r,l.value=`idle`,k.success(X(`@WORKBENCH:已恢复历史会话`)),await g(),T()}catch(e){k.error(X(`@WORKBENCH:加载历史会话失败: `)+(e?.message||e))}}async function oe(e){try{await z.confirm(X(`@WORKBENCH:确认删除该会话`),X(`@WORKBENCH:删除后无法恢复`),{type:`warning`})}catch{return}try{let t=await fetch(`/api/workbench/tasks/ai-chat-sessions/${encodeURIComponent(e)}`,{method:`DELETE`}).then(e=>e.json());if(!t.success){k.error(t.error||X(`@WORKBENCH:删除失败`));return}w.value=w.value.filter(t=>t.sessionId!==e),k.success(X(`@WORKBENCH:已删除`))}catch(e){k.error(X(`@WORKBENCH:删除失败: `)+(e?.message||e))}}function se(e){if(!e)return``;try{let t=new Date(e);if(Number.isNaN(t.getTime()))return e;let n=e=>String(e).padStart(2,`0`);return`${t.getFullYear()}-${n(t.getMonth()+1)}-${n(t.getDate())} ${n(t.getHours())}:${n(t.getMinutes())}`}catch{return e}}function ce(e){return e?e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:`${(e/1024/1024).toFixed(2)} MB`:`0 B`}return s.initialSessionId&&N(s.initialSessionId),(r,a)=>{let s=ne,c=e,l=de,d=t,m=te,g=i;return Y(),J(`div`,st,[I(`div`,{ref_key:`streamEl`,ref:y,class:`ai-chat-stream`},[b.value?(Y(),J(`div`,ct,[G(s,{class:`is-loading`},{default:D(()=>[G(V(o))]),_:1}),I(`span`,null,W(x.value),1)])):U(``,!0),f.value.length===0&&!b.value?(Y(),J(`div`,lt,[G(s,{size:32,color:`#909399`},{default:D(()=>[G(V(F))]),_:1}),I(`div`,ut,W(V(X)(`@WORKBENCH:开始与 AI 对话拆分`)),1),I(`div`,dt,W(V(X)(`@WORKBENCH:输入你想让 AI 怎么拆分或调整(Enter 发送,Shift+Enter 换行)`)),1)])):U(``,!0),(Y(!0),J(P,null,C(f.value,(e,t)=>(Y(),J(`div`,{key:t,class:R([`ai-chat-turn`,`ai-chat-turn--${e.role}`])},[e.role===`user`?(Y(),J(`div`,ft,[I(`pre`,pt,W(e.content),1)])):(Y(),J(`div`,mt,[e.thinking?(Y(),O(l,{key:0,class:`ai-chat-collapse`},{default:D(()=>[G(c,{title:V(X)(`@WORKBENCH:思考过程`)+` (${e.thinking.length})`,name:`think`},{default:D(()=>[I(`pre`,ht,W(e.thinking),1)]),_:2},1032,[`title`])]),_:2},1024)):U(``,!0),e.content?(Y(),J(`div`,gt,W(e.content),1)):U(``,!0),e.subtasks&&e.subtasks.length>0?(Y(),J(`div`,_t,[I(`div`,vt,[I(`span`,yt,W(V(X)(`@WORKBENCH:识别到 {n} 个子任务`,{n:e.subtasks.length})),1)]),I(`ul`,bt,[(Y(!0),J(P,null,C(e.subtasks,(e,t)=>(Y(),J(`li`,{key:t,class:`ai-chat-list__item`},[I(`div`,xt,W(t+1),1),I(`div`,St,[I(`div`,Ct,W(e.title),1),I(`div`,wt,W(e.desc),1)])]))),128))])])):U(``,!0),e.parseError&&(!e.subtasks||e.subtasks.length===0)?(Y(),O(l,{key:3,class:`ai-chat-collapse`},{default:D(()=>[G(c,{title:V(X)(`@WORKBENCH:查看解析详情`),name:`diag`},{default:D(()=>[I(`div`,Tt,W(e.parseError),1)]),_:2},1032,[`title`])]),_:2},1024)):U(``,!0),e.raw&&e.raw!==e.content?(Y(),O(l,{key:4,class:`ai-chat-collapse`},{default:D(()=>[G(c,{title:V(X)(`@WORKBENCH:查看原始 LLM 输出`),name:`raw`},{default:D(()=>[I(`pre`,Et,W(e.raw),1)]),_:2},1032,[`title`])]),_:2},1024)):U(``,!0),e.subtasks&&e.subtasks.length>0?(Y(),J(`div`,Dt,[G(d,{type:`primary`,size:`small`,icon:V(u),onClick:t=>j(e)},{default:D(()=>[n(W(V(X)(`@WORKBENCH:应用本轮`))+` (`+W(e.subtasks.length)+`) `,1)]),_:2},1032,[`icon`,`onClick`])])):U(``,!0)]))],2))),128))],512),I(`div`,Ot,[G(m,{modelValue:p.value,"onUpdate:modelValue":a[0]||=e=>p.value=e,type:`textarea`,rows:3,disabled:b.value,placeholder:V(X)(`@WORKBENCH:输入你想让 AI 怎么拆分或调整(Enter 发送,Shift+Enter 换行)`),onKeydown:fe(H(E,[`exact`,`prevent`]),[`enter`])},null,8,[`modelValue`,`disabled`,`placeholder`,`onKeydown`]),I(`div`,kt,[b.value?(Y(),O(d,{key:0,type:`danger`,icon:V(Ce),onClick:re},{default:D(()=>[n(W(V(X)(`@WORKBENCH:停止`)),1)]),_:1},8,[`icon`])):(Y(),O(d,{key:1,type:`primary`,icon:V(u),disabled:!p.value.trim(),onClick:E},{default:D(()=>[n(W(V(X)(`@WORKBENCH:发送`)),1)]),_:1},8,[`icon`,`disabled`])),G(d,{disabled:b.value,icon:V(h),onClick:ie},{default:D(()=>[n(W(V(X)(`@WORKBENCH:清空对话`)),1)]),_:1},8,[`disabled`,`icon`]),G(d,{disabled:b.value,icon:V(A),onClick:ae},{default:D(()=>[n(W(V(X)(`@WORKBENCH:历史会话`)),1)]),_:1},8,[`disabled`,`icon`])])]),G(g,{modelValue:S.value,"onUpdate:modelValue":a[1]||=e=>S.value=e,title:V(X)(`@WORKBENCH:历史会话`),direction:`rtl`,size:`420px`},{default:D(()=>[ee.value?(Y(),J(`div`,At,[G(s,{class:`is-loading`},{default:D(()=>[G(V(o))]),_:1})])):w.value.length===0?(Y(),J(`div`,jt,W(V(X)(`@WORKBENCH:暂无历史会话`)),1)):(Y(),J(`ul`,Mt,[(Y(!0),J(P,null,C(w.value,e=>(Y(),J(`li`,{key:e.sessionId,class:`ai-chat-history__item`},[I(`div`,Nt,W(e.title||`(无标题)`),1),I(`div`,Pt,[I(`span`,null,W(se(e.updatedAt)),1),a[2]||=I(`span`,null,`·`,-1),I(`span`,null,W(e.messageCount)+` 条消息`,1),a[3]||=I(`span`,null,`·`,-1),I(`span`,null,W(e.latestSubtaskCount)+` 个子任务`,1),a[4]||=I(`span`,null,`·`,-1),I(`span`,null,W(ce(e.size)),1)]),I(`div`,Ft,[G(d,{size:`small`,type:`primary`,onClick:t=>N(e.sessionId)},{default:D(()=>[n(W(V(X)(`@WORKBENCH:恢复`)),1)]),_:1},8,[`onClick`]),G(d,{size:`small`,type:`danger`,onClick:t=>oe(e.sessionId)},{default:D(()=>[n(W(V(X)(`@WORKBENCH:删除`)),1)]),_:1},8,[`onClick`])])]))),128))]))]),_:1},8,[`modelValue`,`title`])])}}}),[[`__scopeId`,`data-v-e5b87036`]]),Lt={class:`ai-split-mode-bar`},Rt=Z(a({__name:`AISplitDialog`,props:{modelValue:{type:Boolean},title:{},desc:{},taskId:{},promptId:{}},emits:[`update:modelValue`,`confirm`],setup(e,{emit:t}){let n=e,i=t,a=M(`direct`),o=L(()=>[{label:X(`@WORKBENCH:直接拆分`),value:`direct`},{label:X(`@WORKBENCH:对话拆分`),value:`chat`}]);function s(e){i(`confirm`,e),i(`update:modelValue`,!1)}return E(()=>n.modelValue,e=>{e&&(a.value=`direct`)}),(t,n)=>{let c=B,l=r;return Y(),O(l,{"model-value":e.modelValue,"onUpdate:modelValue":n[1]||=e=>i(`update:modelValue`,e),title:V(X)(`@WORKBENCH:AI 拆分任务`),width:`800px`,"close-on-click-modal":!1,"close-on-press-escape":!0,"show-close":!0},{default:D(()=>[I(`div`,Lt,[G(c,{modelValue:a.value,"onUpdate:modelValue":n[0]||=e=>a.value=e,options:o.value,block:!1},null,8,[`modelValue`,`options`])]),a.value===`direct`?(Y(),O(ot,{key:0,title:e.title,desc:e.desc,"task-id":e.taskId,"prompt-id":e.promptId,onConfirm:s},null,8,[`title`,`desc`,`task-id`,`prompt-id`])):(Y(),O(It,{key:1,title:e.title,desc:e.desc,"task-id":e.taskId,"prompt-id":e.promptId,onConfirm:s},null,8,[`title`,`desc`,`task-id`,`prompt-id`]))]),_:1},8,[`model-value`,`title`])}}}),[[`__scopeId`,`data-v-2732cf4b`]]),zt={class:`wb-attachments__head`},Bt={class:`wb-attachments__label`},Vt={class:`wb-attachments__count`},Ht=[`disabled`],Ut={key:0,class:`wb-attachments__paste-hint`},Wt={key:1,class:`wb-attachments__list`},Gt=[`title`,`onClick`,`onContextmenu`],Kt=[`src`,`alt`],qt={key:1},Jt={class:`wb-attachment__meta`},$=[`title`],Yt=[`onClick`,`title`],Xt=Z(a({__name:`AttachmentZone`,props:{attachments:{},isImage:{type:Function},humanSize:{type:Function},isUploading:{type:Boolean},isPasteHover:{type:Boolean},maxCount:{},onPick:{type:Function},onRemove:{type:Function}},emits:[`paste`,`drop`,`dragover`,`dragenter`,`dragleave`],setup(e,{emit:t}){let r=e,i=t,a=L(()=>r.attachments.filter(e=>r.isImage(e))),o=L(()=>a.value.map(e=>`/api/workbench/attachments/${e.id}/raw`)),s=M(0),l=M(!1);function u(e){if(r.isImage(e)){let t=a.value.findIndex(t=>t.id===e.id);s.value=t>=0?t:0,l.value=!0}else window.open(`/api/workbench/attachments/${e.id}/raw`,`_blank`,`noopener`)}function d(){l.value=!1}let f=M({visible:!1,x:0,y:0,att:null}),p=M(!1);function m(e,t){if(!r.isImage(e))return;t.preventDefault();let n=window.innerWidth-180,i=window.innerHeight-120;f.value={visible:!0,x:Math.min(t.clientX,n),y:Math.min(t.clientY,i),att:e}}function h(){f.value.visible&&(f.value.visible=!1)}async function g(){let e=f.value.att;if(!(!e||p.value)){if(h(),!navigator.clipboard||typeof ClipboardItem>`u`){k({type:`warning`,message:X(`@WORKBENCH:当前浏览器不支持复制图片`)});return}p.value=!0;try{let t=await fetch(`/api/workbench/attachments/${e.id}/raw`,{credentials:`same-origin`});if(!t.ok)throw Error(`HTTP ${t.status}`);let n=await t.blob(),r=[`image/png`,`image/jpeg`,`image/webp`,`image/gif`].includes(n.type)?n.type:`image/png`,i=new ClipboardItem({[r]:n});await navigator.clipboard.write([i]),k({type:`success`,message:X(`@WORKBENCH:图片已复制到剪贴板`),duration:1800})}catch(e){k({type:`error`,message:X(`@WORKBENCH:复制失败 {error}`,{error:e?.message||``})})}finally{p.value=!1}}}return typeof window<`u`&&(window.addEventListener(`click`,h),window.addEventListener(`scroll`,h,!0),window.addEventListener(`blur`,h)),c(()=>{typeof window>`u`||(window.removeEventListener(`click`,h),window.removeEventListener(`scroll`,h,!0),window.removeEventListener(`blur`,h))}),(t,r)=>(Y(),J(P,null,[I(`div`,{class:R([`wb-attachments`,{"is-paste-hover":e.isPasteHover}]),onPaste:r[1]||=e=>i(`paste`,e),onDrop:r[2]||=H(e=>i(`drop`,e),[`prevent`]),onDragover:r[3]||=H(e=>i(`dragover`,e),[`prevent`]),onDragenter:r[4]||=H(e=>i(`dragenter`,e),[`prevent`]),onDragleave:r[5]||=e=>i(`dragleave`,e)},[I(`div`,zt,[I(`span`,Bt,[n(W(V(X)(`@WORKBENCH:附件`))+` `,1),I(`span`,Vt,W(e.attachments.length)+` / `+W(e.maxCount),1)]),I(`button`,{class:`wb-attachments__add wb-soft-btn`,disabled:e.isUploading||e.attachments.length>=e.maxCount,onClick:r[0]||=(...t)=>e.onPick&&e.onPick(...t)},W(e.isUploading?V(X)(`@WORKBENCH:上传中…`):V(X)(`@WORKBENCH:添加附件`)),9,Ht)]),e.isPasteHover?(Y(),J(`div`,Ut,W(V(X)(`@WORKBENCH:粘贴图片以快速添加`)),1)):U(``,!0),e.attachments.length>0?(Y(),J(`ul`,Wt,[(Y(!0),J(P,null,C(e.attachments,t=>(Y(),J(`li`,{key:t.id,class:`wb-attachment`},[I(`button`,{type:`button`,class:`wb-attachment__preview`,title:V(X)(`@WORKBENCH:点击预览`),onClick:e=>u(t),onContextmenu:e=>m(t,e)},[I(`div`,{class:R([`wb-attachment__icon`,{"wb-attachment__icon--img":e.isImage(t)}])},[e.isImage(t)?(Y(),J(`img`,{key:0,src:`/api/workbench/attachments/${t.id}/raw`,alt:t.originalName,loading:`lazy`},null,8,Kt)):(Y(),J(`span`,qt,W(t.ext.toUpperCase()),1))],2),I(`div`,Jt,[I(`div`,{class:`wb-attachment__name`,title:`${t.originalName} (${e.humanSize(t.size)})`},W(t.originalName),9,$)])],40,Gt),I(`button`,{class:`wb-attachment__del`,onClick:H(n=>e.onRemove(t),[`stop`]),title:V(X)(`@WORKBENCH:删除`)},`×`,8,Yt)]))),128))])):U(``,!0)],34),(Y(),O(ye,{to:`body`},[l.value&&o.value.length>0?(Y(),O(V(K),{key:0,"url-list":o.value,"initial-index":s.value,"hide-on-click-modal":!0,onClose:d},null,8,[`url-list`,`initial-index`])):U(``,!0)])),(Y(),O(ye,{to:`body`},[f.value.visible&&f.value.att&&e.isImage(f.value.att)?(Y(),J(`ul`,{key:0,class:`wb-ctx-menu`,style:ie({top:f.value.y+`px`,left:f.value.x+`px`}),onContextmenu:r[6]||=H(()=>{},[`prevent`])},[I(`li`,{class:R([`wb-ctx-menu__item`,{"is-disabled":p.value}]),onClick:g},[r[7]||=I(`span`,{class:`wb-ctx-menu__icon`,"aria-hidden":`true`},[I(`svg`,{viewBox:`0 0 24 24`,width:`14`,height:`14`,fill:`none`,stroke:`currentColor`,"stroke-width":`1.8`,"stroke-linecap":`round`,"stroke-linejoin":`round`},[I(`rect`,{x:`9`,y:`9`,width:`11`,height:`11`,rx:`2`}),I(`path`,{d:`M5 15V5a2 2 0 0 1 2-2h10`})])],-1),I(`span`,null,W(V(X)(`@WORKBENCH:复制图片`)),1)],2)],36)):U(``,!0)]))],64))}}),[[`__scopeId`,`data-v-9e1ed466`]]),Zt=[`aria-expanded`],Qt={class:`wb-log-summary__left`},$t={key:0,class:`wb-log-summary__status wb-log-summary__status--running`},en={class:`wb-log-summary__label`},tn={key:0,class:`wb-log-summary__elapsed`},nn={key:1,class:`wb-log-summary__status wb-log-summary__status--pending`},rn={class:`wb-log-summary__label`},an={key:2,class:`wb-log-summary__status wb-log-summary__status--done`},on={key:0,class:`wb-log-summary__icon`},sn={key:1,class:`wb-log-summary__icon`},cn={class:`wb-log-summary__label`},ln={key:2,class:`wb-log-summary__elapsed`},un={key:3},dn={class:`wb-log-summary__right`},fn={class:`wb-log-summary__meta`},pn=[`title`],mn={class:`wb-log-details__body`},hn=[`open`],gn={class:`wb-log-section__summary`},_n={class:`wb-log-section__tag wb-log-section__tag--user`},vn={class:`wb-log-section__count`},yn=[`title`],bn={class:`wb-log-section__pre wb-log-section__pre--user`},xn=[`open`],Sn={class:`wb-log-section__summary`},Cn={class:`wb-log-section__tag wb-log-section__tag--think`},wn={class:`wb-log-section__count`},Tn=[`title`],En={class:`wb-log-section__pre wb-log-section__pre--think`},Dn=[`aria-expanded`,`title`],On={class:`wb-log-pre__label`},kn={class:`wb-log-pre__meta`},An=[`title`],jn=[`title`,`disabled`],Mn={key:1,class:`wb-log-pre__empty`},Nn={key:1,class:`wb-log-fullscreen__empty`},Pn=64*1024,Fn=60,In=Z(a({__name:`JobLogDetails`,props:{job:{}},setup(e){let t=e,n=M(!0);function i(){n.value=!n.value}function a(){let e=t.job.output||``;return e?e.length<=Pn?e:`${X(`@WORKBENCH:…(前文已截断)`)}\n${e.slice(-65536)}`:``}function o(){let e=t.job.thinking||``;return e?e.length<=Pn?e:`${X(`@WORKBENCH:…(前文已截断)`)}\n${e.slice(-65536)}`:``}async function s(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 c(e){let n=t.job[e]||``;if(!n){k.warning(X(`@WORKBENCH:暂无内容可复制`));return}await s(n)?k.success(X(`@WORKBENCH:已复制到剪贴板`)):k.error(X(`@WORKBENCH:复制失败`))}async function l(){let e=[];if(t.job.prompt&&e.push(`## ${X(`@WORKBENCH:用户提示词`)}\n\n${t.job.prompt}`),t.job.thinking&&e.push(`## ${X(`@WORKBENCH:Claude 思考`)}\n\n${t.job.thinking}`),t.job.output&&e.push(`## ${X(`@WORKBENCH:模型返回`)}\n\n${t.job.output}`),!e.length){k.warning(X(`@WORKBENCH:暂无内容可复制`));return}await s(e.join(`
|
|
6
|
-
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
`))?k.success(X(`@WORKBENCH:已复制到剪贴板`)):k.error(X(`@WORKBENCH:复制失败`))}let u=L(()=>a()),d=L(()=>t.job.status===`running`||t.job.status===`pending`),f=L(()=>{let e=t.job.status;return e===`done`||e===`error`||e===`cancelled`}),p=M(0),h=null;function _(){v(),h=setInterval(()=>{let e=u.value.length;if(e===0){p.value=0,v();return}let t=Math.max(1,Math.ceil(Fn/30));p.value<e&&(p.value=Math.min(e,p.value+t)),p.value>=e&&v()},33)}function v(){h&&=(clearInterval(h),null)}E(()=>[t.job.output?.length||0,t.job.status],([e,t])=>{t===`done`||t===`error`||t===`cancelled`?(v(),p.value=e):p.value<e&&!h&&_()},{immediate:!0}),m(()=>v());let y=L(()=>u.value.slice(0,p.value)),x=L(()=>(t.job.output||``).slice(0,p.value)),S=L(()=>p.value>=(t.job.output||``).length),ee=M(null);E(()=>t.job.status,(e,t)=>{e===`running`&&t!==`running`&&(ee.value=ee.value??Date.now())});let C=L(()=>{if(!ee.value)return``;let e=ee.value,n=t.job.endedAt?new Date(t.job.endedAt).getTime():Date.now(),r=Math.max(0,Math.floor((n-e)/1e3));return r<60?`${r}s`:`${Math.floor(r/60)}分${(r%60).toString().padStart(2,`0`)}秒`}),te=M(null),w=!1,T=M(!1);function ne(){if(w)return;if((t.job.output||``).length>0){T.value=!1;return}let e=t.job.status;e===`running`||e===`pending`?T.value=(t.job.thinking||``).length>0:T.value=!1}function re(e){let t=e.target;w=!0,T.value=t.open}E(()=>t.job.status,(e,t)=>{!(t===`running`||t===`pending`)&&(e===`running`||e===`pending`)&&(w=!1),ne()}),E(()=>(t.job.thinking||``).length,()=>ne(),{immediate:!0}),E(()=>(t.job.output||``).length,()=>ne());let ie=!1,A=M(!0);function j(e){let t=e.target;ie=!0,A.value=t.open}E(()=>t.job.status,(e,t)=>{!(t===`running`||t===`pending`)&&(e===`running`||e===`pending`)?(ie=!1,A.value=!0):ie||(A.value=!0)});let N=M(!0);function P(){N.value=!N.value}E(()=>t.job.status,(e,t)=>{!(t===`running`||t===`pending`)&&(e===`running`||e===`pending`)&&(N.value=!0)}),E(()=>(t.job.output||``).length,async()=>{n.value||N.value&&(await g(),te.value&&(te.value.scrollTop=te.value.scrollHeight))});let oe=M(!1),F=L(()=>!!(t.job.output&&t.job.output.length)),se=M(null);E(oe,async e=>{e&&(await g(),se.value&&(se.value.scrollTop=se.value.scrollHeight))}),E(()=>(t.job.output||``).length,async()=>{oe.value&&(await g(),se.value&&(se.value.scrollTop=se.value.scrollHeight))});function ce(){}return(t,a)=>{let s=r;return Y(),J(`div`,{class:R([`wb-log-details`,{"is-running":d.value,"is-pending":e.job.status===`pending`,"is-finished":f.value}])},[I(`div`,{class:`wb-log-summary`,onClick:i,role:`button`,"aria-expanded":!n.value},[I(`span`,Qt,[e.job.status===`running`?(Y(),J(`span`,$t,[I(`span`,en,W(V(X)(`@WORKBENCH:正在执行…`)),1),a[5]||=I(`span`,{class:`wb-log-dots`,"aria-hidden":`true`},[I(`span`,{class:`wb-log-dots__dot`}),I(`span`,{class:`wb-log-dots__dot`}),I(`span`,{class:`wb-log-dots__dot`})],-1),C.value?(Y(),J(`span`,tn,W(C.value),1)):U(``,!0)])):e.job.status===`pending`?(Y(),J(`span`,nn,[I(`span`,rn,W(V(X)(`@WORKBENCH:排队中…`)),1),a[6]||=I(`span`,{class:`wb-log-dots`,"aria-hidden":`true`},[I(`span`,{class:`wb-log-dots__dot`}),I(`span`,{class:`wb-log-dots__dot`}),I(`span`,{class:`wb-log-dots__dot`})],-1)])):f.value?(Y(),J(`span`,an,[e.job.status===`error`?(Y(),J(`span`,on,`✗`)):(Y(),J(`span`,sn,`✓`)),I(`span`,cn,W(e.job.status===`error`?V(X)(`@WORKBENCH:执行出错`):V(X)(`@WORKBENCH:执行完成`)),1),C.value?(Y(),J(`span`,ln,W(C.value),1)):U(``,!0)])):(Y(),J(`span`,un,W(V(X)(`@WORKBENCH:查看执行日志`)),1))]),I(`span`,dn,[I(`span`,fn,W((e.job.output||``).length)+` `+W(V(X)(`@WORKBENCH:字符`)),1),I(`button`,{type:`button`,class:`wb-log-copy`,title:V(X)(`@WORKBENCH:复制全部(含提示词与输出)`),onClick:H(l,[`stop`])},` ⧉ `+W(V(X)(`@WORKBENCH:复制全部`)),9,pn)])],8,Zt),b(I(`div`,mn,[e.job.prompt?(Y(),J(`details`,{key:0,class:`wb-log-section`,open:A.value,onToggle:j},[I(`summary`,gn,[I(`span`,_n,W(V(X)(`@WORKBENCH:用户提示词`)),1),I(`span`,vn,W((e.job.prompt||``).length)+` `+W(V(X)(`@WORKBENCH:字符`)),1),I(`button`,{type:`button`,class:`wb-log-copy wb-log-copy--sm`,title:V(X)(`@WORKBENCH:复制用户提示词`),onClick:a[0]||=H(e=>c(`prompt`),[`stop`])},` ⧉ `+W(V(X)(`@WORKBENCH:复制`)),9,yn)]),I(`pre`,bn,W(e.job.prompt),1)],40,hn)):U(``,!0),e.job.thinking?(Y(),J(`details`,{key:1,class:`wb-log-section`,open:T.value,onToggle:re},[I(`summary`,Sn,[I(`span`,Cn,W(V(X)(`@WORKBENCH:Claude 思考`)),1),I(`span`,wn,W((e.job.thinking||``).length)+` `+W(V(X)(`@WORKBENCH:字符`)),1),I(`button`,{type:`button`,class:`wb-log-copy wb-copy--sm`,title:V(X)(`@WORKBENCH:复制思考内容`),onClick:a[1]||=H(e=>c(`thinking`),[`stop`])},` ⧉ `+W(V(X)(`@WORKBENCH:复制`)),9,Tn)]),I(`pre`,En,W(o()),1)],40,xn)):U(``,!0),I(`div`,{class:`wb-log-pre__head`,role:`button`,"aria-expanded":N.value,title:N.value?V(X)(`@WORKBENCH:收起`):V(X)(`@WORKBENCH:展开`),onClick:P},[I(`span`,{class:R([`wb-log-pre__toggle-icon`,{"is-expanded":N.value}]),"aria-hidden":`true`},`▸`,2),I(`span`,On,W(V(X)(`@WORKBENCH:模型返回`)),1),I(`span`,kn,W((e.job.output||``).length)+` `+W(V(X)(`@WORKBENCH:字符`)),1),I(`button`,{type:`button`,class:`wb-log-copy wb-log-copy--sm`,title:V(X)(`@WORKBENCH:复制模型返回`),onClick:a[2]||=H(e=>c(`output`),[`stop`])},` ⧉ `+W(V(X)(`@WORKBENCH:复制`)),9,An),I(`button`,{type:`button`,class:`wb-log-copy wb-log-copy--sm`,title:V(X)(`@WORKBENCH:全屏查看模型返回`),disabled:!F.value,onClick:a[3]||=H(e=>oe.value=!0,[`stop`])},` ⛶ `+W(V(X)(`@WORKBENCH:全屏`)),9,jn)],8,Dn),b(I(`div`,{ref_key:`preRef`,ref:te,class:`wb-log-pre`},[F.value?(Y(),O(V(Ee),{key:0,content:y.value,final:S.value,typewriter:!1,class:`wb-log-pre__render`},null,8,[`content`,`final`])):(Y(),J(`div`,Mn,W(V(X)(`@WORKBENCH:(暂无输出)`)),1))],512),[[ae,N.value]]),G(s,{modelValue:oe.value,"onUpdate:modelValue":a[4]||=e=>oe.value=e,title:V(X)(`@WORKBENCH:模型返回 - 全屏查看`),fullscreen:``,"close-on-click-modal":!1,class:`wb-log-fullscreen-dialog`,onClosed:ce},{default:D(()=>[I(`div`,{ref_key:`fullscreenContainerRef`,ref:se,class:`wb-log-fullscreen`},[F.value?(Y(),O(V(Ee),{key:0,content:x.value,final:S.value,typewriter:!1,class:`wb-log-fullscreen__render`},null,8,[`content`,`final`])):(Y(),J(`div`,Nn,W(V(X)(`@WORKBENCH:(暂无输出)`)),1))],512)]),_:1},8,[`modelValue`,`title`])],512),[[ae,!n.value]])],2)}}}),[[`__scopeId`,`data-v-74f27a55`]]);function Ln(e){switch(e){case`todo`:return X(`@WORKBENCH:待执行`);case`running`:return X(`@WORKBENCH:执行中`);case`done`:return X(`@WORKBENCH:已完成`);case`error`:return X(`@WORKBENCH:出错`);case`cancelled`:return X(`@WORKBENCH:已取消`);case`pending`:return X(`@WORKBENCH:排队中`);default:return e}}function Rn(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)`}}var zn={class:`exec-logs`},Bn={class:`exec-logs__head`},Vn={class:`exec-logs__title-block`},Hn={class:`exec-logs__stats`},Un={class:`exec-logs__head-actions`},Wn={class:`exec-logs__config`},Gn={class:`exec-logs__config-label`},Kn={class:`exec-logs__config-field`},qn={class:`exec-logs__config-name`},Jn={class:`exec-logs__config-field`},Yn={class:`exec-logs__config-name`},Xn={class:`exec-logs__filter`},Zn={key:0,class:`exec-logs__batch-meta`},Qn={key:0,class:`exec-logs__batch`},$n={class:`exec-logs__list`},er={key:0,class:`exec-logs__empty`},tr={class:`exec-logs__empty-art`,"aria-hidden":`true`},nr={class:`exec-logs__empty-title`},rr={class:`exec-logs__empty-hint`},ir={class:`exec-card__head`},ar=[`title`],or={class:`exec-card__meta`},sr={key:0,class:`exec-card__task`},cr={key:1,class:`exec-card__time`},lr={key:2,class:`exec-card__exit`},ur=[`title`,`onClick`],dr={key:0,class:`exec-card__error`},fr={key:1,class:`exec-logs__pager`},pr=50,mr=Z(a({__name:`ExecutionLogManager`,setup(e){function r(e){return e instanceof Error?e.message:String(e)}let i=M([]),a=M(0),o=ge({count:0,sizeMB:0,byStatus:{}}),c=M(!1),u=M(new Set),d=ge({q:``,status:``,page:1}),f=M({maxCount:500,maxSizeMB:256}),m=ge({maxCount:500,maxSizeMB:256}),g=M(!1),_=[{value:`pending`,label:X(`@WORKBENCH:排队中`)},{value:`running`,label:X(`@WORKBENCH:执行中`)},{value:`done`,label:X(`@WORKBENCH:已完成`)},{value:`error`,label:X(`@WORKBENCH:出错`)},{value:`cancelled`,label:X(`@WORKBENCH:已取消`)}],v=L(()=>i.value.length>0&&i.value.every(e=>u.value.has(e.id))),y=L(()=>i.value.some(e=>u.value.has(e.id))&&!v.value);async function S(){c.value=!0;try{let e=new URLSearchParams;d.q&&e.set(`q`,d.q),d.status&&e.set(`status`,d.status),e.set(`limit`,String(pr)),e.set(`offset`,String((d.page-1)*pr));let t=await fetch(`/api/workbench/jobs/list?${e.toString()}`).then(e=>e.json());if(!t.success)throw Error(t.error||`list failed`);i.value=t.jobs,a.value=t.total,o.count=t.stats.count,o.sizeMB=t.stats.sizeMB,o.byStatus=t.stats.byStatus;let n=new Set(i.value.map(e=>e.id));for(let e of Array.from(u.value))n.has(e)||u.value.delete(e)}catch(e){k.error(X(`@WORKBENCH:加载失败`)+`: `+r(e))}finally{c.value=!1}}async function ee(){try{let e=await fetch(`/api/workbench/jobs/config`).then(e=>e.json());e.success&&(f.value=e.config,m.maxCount=e.config.maxCount,m.maxSizeMB=e.config.maxSizeMB)}catch{}}async function w(){g.value=!0;try{let e=await fetch(`/api/workbench/jobs/config`,{method:`PUT`,headers:{"Content-Type":`application/json`},body:JSON.stringify({maxCount:m.maxCount,maxSizeMB:m.maxSizeMB})}).then(e=>e.json());if(!e.success)throw Error(e.error||`save failed`);f.value=e.config,k.success(X(`@WORKBENCH:已保存策略`)),await S()}catch(e){k.error(X(`@WORKBENCH:保存失败`)+`: `+r(e))}finally{g.value=!1}}function T(){d.page=1,S()}function E(){d.q=``,d.status=``,d.page=1,S()}function re(e,t){t?u.value.add(e):u.value.delete(e),u.value=new Set(u.value)}function O(e){if(e)for(let e of i.value)u.value.add(e.id);else for(let e of i.value)u.value.delete(e.id);u.value=new Set(u.value)}async function A(e){try{await z.confirm(X(`@WORKBENCH:确定要删除所选的 {count} 条日志吗?`,{count:1}),X(`@WORKBENCH:删除`),{type:`warning`})}catch{return}try{let t=await fetch(`/api/workbench/jobs/${e}`,{method:`DELETE`}).then(e=>e.json());if(!t.success)throw Error(t.error||`delete failed`);u.value.delete(e),u.value=new Set(u.value),await S()}catch(e){k.error(X(`@WORKBENCH:保存失败`)+`: `+r(e))}}async function ae(){let e=Array.from(u.value);if(e.length!==0){try{await z.confirm(X(`@WORKBENCH:确定要删除所选的 {count} 条日志吗?`,{count:e.length}),X(`@WORKBENCH:批量删除`),{type:`warning`})}catch{return}try{let t=await fetch(`/api/workbench/jobs/batch-delete`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({ids:e})}).then(e=>e.json());if(!t.success)throw Error(t.error||`batch delete failed`);k.success(X(`@WORKBENCH:成功删除 {count} 条`,{count:t.removed||e.length})),u.value=new Set,await S()}catch(e){k.error(X(`@WORKBENCH:保存失败`)+`: `+r(e))}}}async function N(){let e=o.count;if(e!==0){try{await z.confirm(X(`@WORKBENCH:确定要清空所有 {count} 条执行日志吗?此操作不可恢复。`,{count:e}),X(`@WORKBENCH:清空全部`),{type:`warning`,confirmButtonText:X(`@WORKBENCH:清空全部`)})}catch{return}try{let t=await fetch(`/api/workbench/jobs/clear`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({confirm:!0})}).then(e=>e.json());if(!t.success)throw Error(t.error||`clear failed`);k.success(X(`@WORKBENCH:成功删除 {count} 条`,{count:t.removed||e})),u.value=new Set,await S()}catch(e){k.error(X(`@WORKBENCH:保存失败`)+`: `+r(e))}}}function oe(e,t){if(!e)return``;let n=new Date(e).getTime(),r=t?new Date(t).getTime():Date.now(),i=Math.max(0,r-n);return i<1e3?`${i}ms`:i<6e4?`${(i/1e3).toFixed(1)}s`:i<36e5?`${Math.floor(i/6e4)}m ${Math.floor(i%6e4/1e3)}s`:`${Math.floor(i/36e5)}h ${Math.floor(i%36e5/6e4)}m`}return l(()=>{S(),ee()}),(e,r)=>{let l=t,f=j,ee=te,k=p,M=x,F=s,se=ne,ce=q,L=me;return Y(),J(`div`,zn,[I(`header`,Bn,[I(`div`,Vn,[I(`span`,Hn,W(V(X)(`@WORKBENCH:共 {count} 条,占 {size} MB`,{count:o.count,size:o.sizeMB})),1)]),I(`div`,Un,[G(l,{icon:V(h),size:`small`,loading:c.value,onClick:S},{default:D(()=>[n(W(V(X)(`@WORKBENCH:刷新`)),1)]),_:1},8,[`icon`,`loading`]),G(l,{type:`danger`,plain:``,size:`small`,disabled:o.count===0,onClick:N},{default:D(()=>[n(W(V(X)(`@WORKBENCH:清空全部`)),1)]),_:1},8,[`disabled`])])]),I(`div`,Wn,[I(`span`,Gn,W(V(X)(`@WORKBENCH:保存策略`)),1),I(`span`,Kn,[I(`span`,qn,W(V(X)(`@WORKBENCH:最大条数`)),1),G(f,{modelValue:m.maxCount,"onUpdate:modelValue":r[0]||=e=>m.maxCount=e,min:0,max:1e4,step:50,size:`small`,"controls-position":`right`,style:{width:`130px`}},null,8,[`modelValue`])]),I(`span`,Jn,[I(`span`,Yn,W(V(X)(`@WORKBENCH:最大体积 (MB)`)),1),G(f,{modelValue:m.maxSizeMB,"onUpdate:modelValue":r[1]||=e=>m.maxSizeMB=e,min:0,max:10240,step:32,size:`small`,"controls-position":`right`,style:{width:`140px`}},null,8,[`modelValue`])]),G(l,{type:`primary`,size:`small`,loading:g.value,onClick:w},{default:D(()=>[n(W(V(X)(`@WORKBENCH:保存策略`)),1)]),_:1},8,[`loading`])]),I(`div`,Xn,[G(ee,{modelValue:d.q,"onUpdate:modelValue":r[2]||=e=>d.q=e,placeholder:V(X)(`@WORKBENCH:搜索标题 / 任务`),clearable:``,size:`small`,style:{width:`240px`},onKeyup:fe(T,[`enter`]),onClear:T},null,8,[`modelValue`,`placeholder`]),G(M,{modelValue:d.status,"onUpdate:modelValue":r[3]||=e=>d.status=e,placeholder:V(X)(`@WORKBENCH:全部状态`),clearable:``,size:`small`,style:{width:`130px`},onChange:T},{default:D(()=>[(Y(),J(P,null,C(_,e=>G(k,{key:e.value,label:e.label,value:e.value},null,8,[`label`,`value`])),64))]),_:1},8,[`modelValue`,`placeholder`]),G(l,{size:`small`,onClick:E},{default:D(()=>[n(W(V(X)(`@WORKBENCH:重置`)),1)]),_:1}),r[5]||=I(`span`,{class:`exec-logs__filter-spacer`},null,-1),u.value.size>0?(Y(),J(`span`,Zn,W(V(X)(`@WORKBENCH:已选择 {count} 项`,{count:u.value.size})),1)):U(``,!0)]),u.value.size>0?(Y(),J(`div`,Qn,[G(F,{"model-value":v.value,indeterminate:y.value,onChange:O},{default:D(()=>[n(W(v.value?V(X)(`@WORKBENCH:取消全选`):V(X)(`@WORKBENCH:全选`)),1)]),_:1},8,[`model-value`,`indeterminate`]),G(l,{type:`danger`,size:`small`,onClick:ae},{default:D(()=>[n(W(V(X)(`@WORKBENCH:批量删除`)),1)]),_:1})])):U(``,!0),b((Y(),J(`div`,$n,[!c.value&&i.value.length===0?(Y(),J(`div`,er,[I(`div`,tr,[G(se,null,{default:D(()=>[G(V(be))]),_:1})]),I(`div`,nr,W(V(X)(`@WORKBENCH:暂无执行日志`)),1),I(`div`,rr,W(V(X)(`@WORKBENCH:点击「执行任务」开始一次执行,日志会出现在这里。`)),1)])):U(``,!0),(Y(!0),J(P,null,C(i.value,e=>(Y(),J(`article`,{key:e.id,class:R([`exec-card`,{"is-selected":u.value.has(e.id)}])},[I(`header`,ir,[G(F,{"model-value":u.value.has(e.id),onChange:t=>re(e.id,t)},null,8,[`model-value`,`onChange`]),I(`span`,{class:`exec-card__status`,style:ie({color:V(Rn)(e.status),borderColor:V(Rn)(e.status)})},W(V(Ln)(e.status)),5),I(`span`,{class:`exec-card__title`,title:e.title||V(X)(`@WORKBENCH:无标题`)},W(e.title||V(X)(`@WORKBENCH:无标题`)),9,ar),r[6]||=I(`span`,{class:`exec-card__spacer`},null,-1),I(`span`,or,[e.taskTitle?(Y(),J(`span`,sr,`📁 `+W(e.taskTitle),1)):U(``,!0),e.startedAt?(Y(),J(`span`,cr,`⏱ `+W(oe(e.startedAt,e.endedAt)),1)):U(``,!0),e.exitCode===null?U(``,!0):(Y(),J(`span`,lr,`exit `+W(e.exitCode),1))]),I(`button`,{type:`button`,class:`exec-card__del`,title:V(X)(`@WORKBENCH:删除`),onClick:t=>A(e.id)},`×`,8,ur)]),e.error?(Y(),J(`p`,dr,`⚠ `+W(e.error),1)):U(``,!0),G(In,{job:e},null,8,[`job`])],2))),128))])),[[L,c.value]]),a.value>pr?(Y(),J(`footer`,fr,[G(ce,{"current-page":d.page,"onUpdate:currentPage":r[4]||=e=>d.page=e,"page-size":pr,total:a.value,layout:`prev, pager, next, total`,background:``,small:``,onCurrentChange:S},null,8,[`current-page`,`total`])])):U(``,!0)])}}}),[[`__scopeId`,`data-v-174a9b87`]]),hr={class:`workbench`},gr={class:`workbench__editor-row`},_r={class:`wb-sidebar`},vr={class:`wb-section`},yr={class:`wb-section__head`},br={class:`wb-section__tag`},xr={class:`wb-section__title`},Sr={class:`wb-pill wb-section__count`},Cr=[`disabled`],wr={class:`wb-task-list`},Tr=[`aria-expanded`,`title`,`onClick`,`onKeydown`],Er=[`title`],Dr={class:`wb-pill wb-task-group__count`},Or=[`data-icon`,`onClick`],kr=[`data-icon`],Ar={class:`wb-task-item__body`},jr=[`title`],Mr={class:`wb-task-item__meta`},Nr=[`title`],Pr={class:`wb-pill wb-task-item__num`},Fr=[`title`],Ir={class:`wb-pill wb-task-item__num`},Lr=[`title`],Rr=[`title`,`aria-label`],zr=[`title`],Br=[`title`],Vr=[`onClick`,`title`,`aria-label`],Hr={key:0,class:`wb-empty wb-empty--rich`},Ur={class:`wb-empty__art`,"aria-hidden":`true`},Wr={class:`wb-empty__title`},Gr={class:`wb-empty__hint`},Kr={class:`wb-empty__cta`},qr={class:`wb-section`},Jr={class:`wb-section__head`},Yr={class:`wb-section__tag wb-section__tag--accent`},Xr={class:`wb-section__title`},Zr={class:`wb-pill wb-section__count`},Qr=[`title`,`aria-label`],$r={class:`wb-prompt-list`},ei={class:`wb-prompt-item__icon`},ti=[`onClick`,`title`],ni=[`title`],ri=[`onClick`,`title`,`aria-label`],ii={key:0,class:`wb-empty wb-empty--compact`},ai={class:`wb-split`},oi={key:0,class:`wb-placeholder`},si={class:`wb-split__header`},ci=[`placeholder`],li=[`title`],ui={key:0,class:`wb-meta-save__dot`},di={key:1,class:`wb-meta-save__check`},fi={key:2,class:`wb-meta-save__bang`},pi={key:3,class:`wb-meta-save__dot`},mi={value:null},hi=[`value`],gi=[`aria-label`],_i=[`aria-selected`],vi=[`aria-selected`],yi=[`disabled`,`title`],bi=[`title`,`aria-label`],xi=[`title`,`aria-label`],Si=[`open`],Ci={class:`wb-task-desc__summary`},wi={class:`wb-task-desc__label`},Ti={key:0,class:`wb-task-desc__tag`},Ei={key:0},Di={key:1,class:`wb-task-desc__tag-attachment`},Oi=[`placeholder`],ki={key:0,class:`wb-exec-list`},Ai={class:`wb-exec-list__header`},ji={class:`wb-exec-list__title`},Mi={class:`wb-split__sub-actions`},Ni={key:0,class:`wb-dirty-badge`},Pi={class:`wb-exec-sub-list`},Fi=[`onClick`],Ii={class:`wb-exec-sub-item__row1`},Li=[`title`],Ri={class:`wb-sub-error`},zi={class:`wb-sub-error__head`},Bi={class:`wb-sub-error__title`},Vi={key:0,class:`wb-sub-error__time`},Hi={class:`wb-sub-error__msg`},Ui={class:`wb-sub-error__actions`},Wi=[`title`],Gi=[`title`],Ki={key:2,class:`wb-exec-sub-item__dirty-dot`,title:`未保存`},qi={class:`wb-exec-sub-item__row2`},Ji={key:0,class:`wb-sub-item__pid`},Yi={class:`wb-exec-sub-item__actions`},Xi=[`title`,`onClick`],Zi=[`title`,`onClick`],Qi=[`title`,`onClick`],$i=[`title`,`disabled`,`onClick`],ea=[`title`,`disabled`,`onClick`],ta={key:0,class:`wb-empty wb-empty--rich`},na={class:`wb-empty__art`,"aria-hidden":`true`},ra={class:`wb-empty__title`},ia={class:`wb-empty__cta`},aa={class:`wb-exec-detail`},oa={key:0,class:`wb-placeholder`},sa={class:`wb-exec-detail__head`},ca=[`placeholder`],la=[`title`],ua=[`placeholder`],da={class:`wb-form-item__label wb-simple__override-summary`},fa=[`title`],pa=[`disabled`],ma=[`placeholder`],ha={key:0,class:`wb-simple__continue`},ga=[`placeholder`],_a={class:`wb-simple__continue-actions`},va={style:{display:`flex`,gap:`8px`,"align-items":`center`}},ya=`__simple`,ba=`__no_project__`,xa=`wb.collapsedGroupPaths.v1`,Sa=`wb.seenGroupPaths.v1`,Ca=`.png,.jpg,.jpeg,.gif,.webp,.bmp,.svg,.pdf,.txt,.md,.csv,.json,.log`,wa=5*1024*1024,Ta=Z(a({__name:`WorkbenchView`,setup(e){let i=M([]),a=M([]),o=M([]),s=M(!1),u=M(null),d=L(()=>a.value.find(e=>e.id===u.value)||null),p=L(()=>d.value?.type===`simple`),m=M(null),h=L(()=>!d.value||p.value||!m.value?null:d.value.subtasks.find(e=>e.id===m.value)||null),x=M(new Map),S=M({title:``,desc:``,promptId:null,simpleOverride:``});function A(){let e=new Map;if(d.value)for(let t of d.value.subtasks)e.set(t.id,{id:t.id,title:t.title,desc:t.desc,promptOverride:t.promptOverride});x.value=e,d.value?S.value={title:d.value.title,desc:d.value.desc,promptId:d.value.promptId,simpleOverride:d.value.simpleOverride||``}:S.value={title:``,desc:``,promptId:null,simpleOverride:``}}let j=L(()=>{let e=new Set;if(!d.value)return e;for(let t of d.value.subtasks){let n=x.value.get(t.id);if(!n){e.add(t.id);continue}(n.title!==t.title||n.desc!==t.desc||n.promptOverride!==t.promptOverride)&&e.add(t.id)}return e}),ae=L(()=>j.value.size>0),F=M(`idle`),se=M(0),de=null,B=L(()=>{if(!d.value)return!1;let e=d.value;return S.value.title!==e.title||S.value.desc!==e.desc||S.value.promptId!==e.promptId||S.value.simpleOverride!==(e.simpleOverride||``)});function me(){de!==null&&(clearTimeout(de),de=null)}async function ve(){if(!d.value)return!1;if(!B.value)return!0;if(F.value=`saving`,await kt(!1))return se.value=Date.now(),F.value=`saved`,setTimeout(()=>{F.value===`saved`&&Date.now()-se.value>=4e3&&(F.value=`idle`)},4e3),!0;F.value=`error`;let e=Date.now();return setTimeout(()=>{F.value===`error`&&Date.now()-e>=4e3&&(F.value=`idle`)},4e3),!1}E(()=>d.value?{id:d.value.id,title:d.value.title,desc:d.value.desc,promptId:d.value.promptId,simpleOverride:d.value.simpleOverride||``}:null,(e,t)=>{!e||!t||e.id!==t.id||(de!==null&&clearTimeout(de),de=window.setTimeout(()=>{ve()},1500))},{deep:!0}),E(u,async(e,t)=>{me(),d.value&&B.value&&await ve()}),E(u,()=>{jt.value=!1});function ye(e){try{let t=new Blob([JSON.stringify(e)],{type:`application/json`});navigator.sendBeacon?.(`/api/workbench/tasks`,t)}catch{}}function Ce(){d.value&&B.value&&ye(d.value)}let K=ge({visible:!1,editing:null,name:``,content:``,aiLoading:!1}),q=ge({visible:!1,text:``,loading:!1,saving:!1}),Ee=M(!1),Z=null,Oe=De();function ke(){Oe.setRunning(o.value.filter(e=>e.status===`running`).length)}function Ae(e){return o.value.find(t=>t.subId===e)||null}function je(e,t){if(e===`hello`){o.value=t.jobs||[],ke();return}if(e===`job:update`){let e=t,n=o.value.findIndex(t=>t.id===e.id);n>=0?o.value[n]=e:o.value.push(e),ke();return}if(e===`job:thinking-delta`||e===`job:output-delta`){let n=e===`job:thinking-delta`?`thinking`:`output`,r=t?.delta||``;if(!r)return;let i=o.value.findIndex(e=>e.id===t.id);if(i<0)return;let a=o.value[i][n]||``;o.value[i][n]=a+r;return}if(e===`sub:update`){let e=a.value.find(e=>e.id===t.taskId);if(e){let n=e.subtasks.findIndex(e=>e.id===t.sub.id);n>=0&&(e.subtasks[n]=t.sub)}}if(e===`task:update`){let e=a.value.findIndex(e=>e.id===t.id);e>=0&&(a.value[e]=t)}e===`task:error`&&k.error(t.error||X(`@WORKBENCH:执行出错`))}let Me=[{key:`image`,patterns:[/图\s*片/,/上\s*传/,/upload/i,/image/i,/screenshot/i,/截图/,/附件/,/attachment/i]},{key:`icon`,patterns:[/图\s*标/,/icon/i,/svg/i]},{key:`test`,patterns:[/测\s*试/,/test/i,/spec/i,/\bqa\b/i]},{key:`ui`,patterns:[/ui\s*优\s*化/,/样\s*式/,/style/i,/css/i,/界面/,/视\s*觉/,/design/i]}];async function Ne(e){try{if(navigator.clipboard&&window.isSecureContext)return await navigator.clipboard.writeText(e),!0}catch{}try{let t=document.createElement(`textarea`);t.value=e,t.style.position=`fixed`,t.style.left=`-9999px`,document.body.appendChild(t),t.select();let n=document.execCommand(`copy`);return document.body.removeChild(t),n}catch{return!1}}function Pe(e){if(!e)return``;let t=new Date(e);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())}:${n(t.getSeconds())}`}async function Fe(e){let t=await Ne(`[${e.title||X(`@WORKBENCH:未命名子任务`)}]\n${e.error||``}`);k[t?`success`:`error`](X(t?`@WORKBENCH:已复制错误信息`:`@WORKBENCH:复制失败`))}function Ie(e){m.value=e.id,s.value=!0}function Le(e){let t=(e||``).trim();if(!t)return`doc`;for(let e of Me)if(e.patterns.some(e=>e.test(t)))return e.key;return`doc`}let Re={icon:le(be),image:le(_),test:le(ce),ui:le(v),doc:le(be),idea:le(v)};function ze(e){return Re[Le(e.title)]}function Be(e){if(!e)return[];let t=`${e.id}${ya}`;return o.value.filter(e=>e.subId===t||e.subId.startsWith(`${t}__r`)).sort((e,t)=>{let n=e.startedAt||``,r=t.startedAt||``;return n&&r?n.localeCompare(r):n?-1:+!!r})}function Ve(e){if(!e)return null;let t=Be(e);return t.length>0?t[t.length-1]:null}function He(e){return e?e.status===`pending`||e.status===`running`?`running`:e.status===`done`?`done`:e.status===`cancelled`?`cancelled`:`error`:`idle`}function Ue(e){return Array.isArray(e.attachments)?e.attachments.length:0}function We(e){return Array.isArray(e.subtasks)?e.subtasks.length:0}function Ge(e){return Array.isArray(e.subtasks)?e.subtasks.filter(e=>e&&e.status===`done`).length:0}function Ke(e){if(Array.isArray(e.subtasks)&&e.subtasks.some(e=>e&&e.status===`running`))return!0;let t=`${e.id}__simple`,n=o.value.find(e=>e.subId===t||e.subId.startsWith(`${t}__r`));return!!(n&&(n.status===`running`||n.status===`pending`))}async function qe(){i.value=(await fetch(`/api/workbench/prompts`).then(e=>e.json()).catch(()=>({prompts:[]}))).prompts||[]}async function Je(){a.value=(await fetch(`/api/workbench/tasks`).then(e=>e.json()).catch(()=>({tasks:[]}))).tasks||[],!u.value&&a.value.length>0&&(u.value=a.value[0].id),A()}let Q=M({path:``,name:``});async function Ye(){let e=await fetch(`/api/workbench/current-project`).then(e=>e.json()).catch(()=>({}));e&&typeof e.projectPath==`string`&&(Q.value={path:e.projectPath,name:e.projectName||``})}function Xe(e){try{let t=localStorage.getItem(e);if(!t)return new Set;let n=JSON.parse(t);return new Set(Array.isArray(n)?n.filter(e=>typeof e==`string`):[])}catch{return new Set}}function Ze(e,t){try{localStorage.setItem(e,JSON.stringify(Array.from(t)))}catch{}}let Qe=M(Xe(xa)),$e=M(Xe(Sa));E(Qe,e=>Ze(xa,e),{deep:!1}),E($e,e=>Ze(Sa,e),{deep:!1});function et(e){return Qe.value.has(e)}function tt(e){Qe.value.has(e)?Qe.value.delete(e):Qe.value.add(e),Qe.value=new Set(Qe.value);let t=new Set($e.value);t.add(e),$e.value=t}let nt=L(()=>{let e=a.value,t=new Map;for(let n of e){let e=(n.projectPath||``).trim()||ba;t.has(e)||t.set(e,[]),t.get(e).push(n)}let n=Q.value.path,r=Array.from(t.keys()).sort((e,t)=>e===n?-1:t===n||e===ba?1:t===ba?-1:e.localeCompare(t));return{groups:r.map(e=>({path:e,label:e===ba?X(`@WORKBENCH:未关联项目`):e,tasks:t.get(e)})),hasMultiple:r.length>1}});function rt(e){if(!e||e===ba)return e;let t=e.split(/[\\/]/).filter(Boolean);return t.length<=1?e:t.slice(-2).join(`/`)}E(()=>nt.value.groups.map(e=>e.path),e=>{let t=Q.value.path,n=new Set(Qe.value),r=new Set($e.value),i=!1;for(let a of e)r.has(a)||(r.add(a),a!==t&&(n.add(a),i=!0));i&&(Qe.value=n),$e.value=r},{immediate:!0});async function it(){o.value=(await fetch(`/api/workbench/jobs`).then(e=>e.json()).catch(()=>({jobs:[]}))).jobs||[],ke()}async function at(e){try{let t=await fetch(`/api/workbench/jobs/by-task/${encodeURIComponent(e)}`,{method:`DELETE`}).then(e=>e.json());return t?.success?(o.value=o.value.filter(t=>t.taskId!==e),ke(),t.removed||0):(console.warn(`[clearJobsByTask] failed:`,t?.error),0)}catch(e){return console.warn(`[clearJobsByTask] error:`,e),0}}async function ot(e){try{let t=await fetch(`/api/workbench/jobs/by-task/${encodeURIComponent(e)}?keepDone=true`,{method:`DELETE`}).then(e=>e.json());if(!t?.success)return console.warn(`[clearNonDoneJobsByTask] failed:`,t?.error),0;let n=new Set(t.ids||[]);return o.value=o.value.filter(t=>!(t.taskId===e&&n.has(t.id))),ke(),t.removed||0}catch(e){return console.warn(`[clearNonDoneJobsByTask] error:`,e),0}}async function st(){if(!d.value)return;let e=d.value,t=Array.isArray(e.subtasks)?e.subtasks:[],n=t.filter(e=>e.status===`done`).length,r=t.filter(e=>e.status===`error`).length,i=t.filter(e=>e.status===`running`).length,a=o.value.filter(t=>t.taskId===e.id),s=n+r===0?X(`@WORKBENCH:当前任务还没有执行内容,确认仍要清空?`):X(`@WORKBENCH:将清空 {n} 个已执行/失败的子任务和 {m} 条执行记录,任务拆分/描述/附件保留。`,{n:n+r,m:a.length});try{await z.confirm(s,X(`@WORKBENCH:清空执行内容`),{confirmButtonText:X(`@WORKBENCH:清空`),cancelButtonText:X(`@WORKBENCH:取消`),type:`warning`})}catch{return}if(i>0){k.warning(X(`@WORKBENCH:有 {n} 个子任务正在执行,请先停止`,{n:i}));return}let c=await fetch(`/api/workbench/tasks/${encodeURIComponent(e.id)}/clear-execution`,{method:`POST`,headers:{"Content-Type":`application/json`}}).then(e=>e.json()).catch(e=>({success:!1,error:e?.message||String(e)}));if(c?.success){if(Array.isArray(e.subtasks))for(let t of e.subtasks)t.status=`todo`,t.error&&delete t.error;o.value=o.value.filter(t=>t.taskId!==e.id),ke(),k.success(c.message||X(`@WORKBENCH:已清空执行内容`))}else k.error(c?.error||X(`@WORKBENCH:清空失败`))}async function ct(){if(!d.value)return;let e=d.value,t=Array.isArray(e.subtasks)?e.subtasks.length:0;if(t===0){k.warning(X(`@WORKBENCH:当前任务没有子任务`));return}if(o.value.find(t=>t.taskId===e.id&&(t.status===`running`||t.status===`pending`))){k.warning(X(`@WORKBENCH:有子任务正在执行,请先停止`));return}try{await z.confirm(X(`@WORKBENCH:将删除 {n} 个子任务,任务描述/附件/标题保留,确认?`,{n:t}),X(`@WORKBENCH:清空子任务`),{confirmButtonText:X(`@WORKBENCH:清空`),cancelButtonText:X(`@WORKBENCH:取消`),type:`warning`})}catch{return}let n=await fetch(`/api/workbench/tasks/${encodeURIComponent(e.id)}/clear-subtasks`,{method:`POST`,headers:{"Content-Type":`application/json`}}).then(e=>e.json()).catch(e=>({success:!1,error:e?.message||String(e)}));n?.success?(e.subtasks=[],m.value=null,j.value.clear(),x.value.clear(),o.value=o.value.filter(t=>t.taskId!==e.id),ke(),k.success(n.message||X(`@WORKBENCH:已清空子任务`))):k.error(n?.error||X(`@WORKBENCH:清空失败`))}function lt(){Z&&=(Z.close(),null),Z=new EventSource(`/api/workbench/events`),Z.onmessage=e=>{try{let t=JSON.parse(e.data);je(t.event,t.payload)}catch{}},Z.onerror=()=>{Z&&=(Z.close(),null),setTimeout(lt,3e3)}}function ut(){K.editing=null,K.name=``,K.content=``,K.aiLoading=!1,K.visible=!0}function dt(e){K.editing=e,K.name=e.name,K.content=e.content,K.aiLoading=!1,K.visible=!0}async function ft(){if(!K.aiLoading){K.aiLoading=!0;try{let e=await fetch(`/api/workbench/prompts/ai-generate`,{method:`POST`}).then(e=>e.json());e.success?(K.name=e.name||K.name,K.content=e.result||``,k.success(X(`@WORKBENCH:已生成,可继续编辑`))):k.error(e.error||X(`@WORKBENCH:生成失败`))}catch(e){k.error(X(`@WORKBENCH:网络错误: `)+(e&&e.message||e))}finally{K.aiLoading=!1}}}async function pt(){q.visible=!0,q.loading=!0;try{let e=await fetch(`/api/workbench/prompts/ai-instruction`).then(e=>e.json());e.success?q.text=e.instruction||``:k.error(e.error||X(`@WORKBENCH:读取指令失败`))}catch(e){k.error(X(`@WORKBENCH:读取指令失败`)+`: `+(e&&e.message||e))}finally{q.loading=!1}}async function mt(){if(!q.text.trim()){k.warning(X(`@WORKBENCH:指令内容不能为空`));return}q.saving=!0;try{let e=await fetch(`/api/workbench/prompts/ai-instruction`,{method:`PUT`,headers:{"Content-Type":`application/json`},body:JSON.stringify({instruction:q.text})}).then(e=>e.json());e.success?(k.success(X(`@WORKBENCH:已保存指令`)),q.visible=!1):k.error(e.error||X(`@WORKBENCH:保存失败`))}catch(e){k.error(X(`@WORKBENCH:网络错误: `)+(e&&e.message||e))}finally{q.saving=!1}}async function ht(){if(!K.name.trim()||!K.content.trim()){k.warning(X(`@WORKBENCH:名称和内容不能为空`));return}let e={id:K.editing?.id,name:K.name.trim(),content:K.content},t=await fetch(`/api/workbench/prompts`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify(e)}).then(e=>e.json());t.success?(k.success(X(`@WORKBENCH:已保存`)),K.visible=!1,qe()):k.error(t.error||X(`@WORKBENCH:保存失败`))}async function gt(e){await z.confirm(X(`@WORKBENCH:删除提示词「{name}」?`,{name:e.name}),X(`@WORKBENCH:确认`),{type:`warning`}),await fetch(`/api/workbench/prompts/${e.id}`,{method:`DELETE`}),qe();for(let t of a.value)t.promptId===e.id&&(t.promptId=null,await fetch(`/api/workbench/tasks`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify(t)}));Je()}let _t=M(!1),vt=M(null);async function yt(){if(_t.value)return;_t.value=!0;let e={title:``,desc:``,promptId:null,type:`simple`,simpleOverride:``,subtasks:[]};Q.value.path&&(e.projectPath=Q.value.path);try{let t=await fetch(`/api/workbench/tasks`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify(e)}).then(e=>e.json());if(!t.success){k.error(t.error||X(`@WORKBENCH:保存失败`));return}me(),d.value&&B.value&&await ve(),await Je(),t.task?.id&&(u.value=t.task.id,A(),k.success(X(`@WORKBENCH:已新建任务`)),await g(),vt.value?.focus())}finally{_t.value=!1}}async function bt(e,t){if(e.type===t)return;let n=e.type===`complex`&&t===`simple`&&(e.subtasks?.length??0)>0;if(n)try{await z.confirm(X(`@WORKBENCH:任务「{title}」当前有 {n} 个子任务,切换为简单任务后会清空这些子任务,确认继续?`,{title:e.title,n:e.subtasks.length}),X(`@WORKBENCH:切换任务类型`),{type:`warning`,confirmButtonText:X(`@WORKBENCH:切换并清空`),cancelButtonText:X(`@WORKBENCH:取消`)})}catch{return}let r={id:e.id,title:e.title,desc:e.desc,promptId:e.promptId,type:t,simpleOverride:e.simpleOverride||``,subtasks:n?[]:e.subtasks||[]},i=await fetch(`/api/workbench/tasks`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify(r)}).then(e=>e.json());if(!i.success){k.error(i.error||X(`@WORKBENCH:保存失败`));return}await Je(),k.success(X(t===`simple`?`@WORKBENCH:已切换为简单任务`:`@WORKBENCH:已切换为复杂任务`))}async function xt(e){d.value&&await bt(d.value,e)}async function St(e){await z.confirm(X(`@WORKBENCH:删除任务「{title}」及其所有子任务?`,{title:e.title}),X(`@WORKBENCH:确认`),{type:`warning`}),await fetch(`/api/workbench/tasks/${e.id}`,{method:`DELETE`}),u.value===e.id&&(u.value=null),Je()}async function Ct(e){u.value!==e.id&&(me(),d.value&&B.value&&await ve(),u.value=e.id,A())}E(()=>d.value,e=>{if(!e||e.type===`simple`){m.value=null;return}m.value=e.subtasks.find(e=>e.status===`running`)?.id||e.subtasks[0]?.id||null},{immediate:!0}),E(()=>d.value?.subtasks?.length,()=>{!d.value||p.value||(!m.value||!d.value.subtasks.find(e=>e.id===m.value))&&(m.value=d.value.subtasks[0]?.id||null)}),E(()=>d.value?.subtasks?.map(e=>({id:e.id,status:e.status}))||[],()=>{if(!d.value||p.value)return;let e=d.value.subtasks,t=e.find(e=>e.id===m.value);if(!t||t.status!==`running`){let t=e.find(e=>e.status===`running`);t&&t.id!==m.value&&(m.value=t.id)}});let wt=M(new Set);function Tt(e){return wt.value.has(e)}function Et(e,t){t?wt.value.add(e):wt.value.delete(e),wt.value=new Set(wt.value)}async function Dt(){if(!d.value)return;let e={id:`${Date.now().toString(36)}-${Math.random().toString(36).slice(2,6)}`,title:X(`@WORKBENCH:新子任务`),desc:``,status:`todo`,promptOverride:``};d.value.subtasks.push(e),Et(e.id,!0);try{await kt(!1)}finally{Et(e.id,!1)}}async function Ot(e){if(d.value){d.value.subtasks=d.value.subtasks.filter(t=>t.id!==e.id),Et(e.id,!0);try{await kt(!1)}finally{Et(e.id,!1)}}}async function kt(e){if(!d.value)return!1;let t=await fetch(`/api/workbench/tasks`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify(d.value)}).then(e=>e.json());return t.success?(e&&k.success(X(`@WORKBENCH:已保存拆分`)),await Je(),!0):(k.error(t.error||X(`@WORKBENCH:保存失败`)),!1)}async function At(){await kt(!0)}let jt=M(!1);function Mt(){if(d.value){if(!(d.value.title||``).trim()){k.warning(X(`@WORKBENCH:请先填写任务标题`));return}jt.value=!0}}function Nt(e){if(d.value){for(let t of e)d.value.subtasks.push({id:`${Date.now().toString(36)}-${Math.random().toString(36).slice(2,6)}`,title:t.title,desc:t.desc||``,status:`todo`,promptOverride:``,attachments:[]});k.success(X(`@WORKBENCH:已生成 {n} 个子任务,请审阅后保存`,{n:e.length}))}}async function Pt(e){if(e.type===`simple`)return Ft(e);if(!e.subtasks||e.subtasks.length===0){k.warning(X(`@WORKBENCH:请先拆分任务`));return}if(d.value&&d.value.id===e.id){let t=a.value.find(t=>t.id===e.id);if((!t||t.title!==d.value.title||t.desc!==d.value.desc||JSON.stringify(t.subtasks)!==JSON.stringify(d.value.subtasks)||t.promptId!==d.value.promptId)&&!await kt(!1))return}let t=e.subtasks.filter(e=>e.status===`done`);if(t.length>0){let n=`close`;try{await z.confirm(X(`@WORKBENCH:该任务有 {n} 个子任务已 done,如何处理?`,{n:t.length})+`
|
|
10
|
-
|
|
11
|
-
`+X(`@WORKBENCH:点"确定"将重置全部 done 为 todo,从头跑一遍(会消耗 token)`)+`
|
|
12
|
-
`+X(`@WORKBENCH:点"取消"将保留 done 状态,只跑未完成的 sub`),X(`@WORKBENCH:检测到已完成子任务`),{confirmButtonText:X(`@WORKBENCH:重置全部并重跑`),cancelButtonText:X(`@WORKBENCH:只跑未完成`),type:`warning`,distinguishCancelAndClose:!0,showClose:!0}),n=`confirm`}catch(e){n=e===`cancel`?`cancel`:`close`}if(n===`close`)return;if(n===`confirm`){let t=await fetch(`/api/workbench/tasks/${encodeURIComponent(e.id)}/clear-execution`,{method:`POST`,headers:{"Content-Type":`application/json`}}).then(e=>e.json()).catch(e=>({success:!1,error:e?.message||String(e)}));if(!t?.success){k.error(t?.error||X(`@WORKBENCH:清空失败`));return}if(Array.isArray(e.subtasks))for(let t of e.subtasks)t.status=`todo`,t.error&&delete t.error;o.value=o.value.filter(t=>t.taskId!==e.id),ke(),k.success(t.message||X(`@WORKBENCH:已重置,准备从头执行`))}}await ot(e.id);let n=await fetch(`/api/workbench/tasks/${e.id}/run`,{method:`POST`}).then(e=>e.json());n.success?k.success(n.message||X(`@WORKBENCH:已加入执行队列`)):k.error(n.error||X(`@WORKBENCH:执行失败`))}async function Ft(e){if(d.value&&d.value.id===e.id){let t=a.value.find(t=>t.id===e.id);if((!t||t.title!==d.value.title||t.desc!==d.value.desc||t.promptId!==d.value.promptId||(t.simpleOverride||``)!==(d.value.simpleOverride||``))&&!await kt(!1))return}await at(e.id);let t=await fetch(`/api/workbench/tasks/${e.id}/run-simple`,{method:`POST`}).then(e=>e.json());t.success?k.success(t.message||X(`@WORKBENCH:已加入执行队列`)):k.error(t.error||X(`@WORKBENCH:执行失败`))}async function It(e,t){let n=Be(e).slice(-1)[0];if(!n){k.error(X(`@WORKBENCH:没有可续接的会话`));return}let r=await fetch(`/api/workbench/jobs/${n.id}/continue`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({userMessage:t})}).then(e=>e.json()).catch(e=>({success:!1,error:e?.message||String(e)}));r.success?k.success(r.message||X(`@WORKBENCH:已加入续接队列`)):k.error(r.error||X(`@WORKBENCH:续接失败`))}let Lt=ge({});async function zt(e){try{await z.confirm(X(`@WORKBENCH:退出后将清空本次对话的全部轮次,确认?`),X(`@WORKBENCH:退出执行`),{confirmButtonText:X(`@WORKBENCH:退出`),cancelButtonText:X(`@WORKBENCH:取消`),type:`warning`})}catch{return}await at(e.id),delete Lt[e.id]}async function Bt(e){let t=(Lt[e.id]||``).trim();t&&(await It(e,t),Lt[e.id]=``)}async function Vt(e){if(!d.value)return;let t=d.value,n=Ae(e.id);if(n&&(n.status===`running`||n.status===`pending`)){k.warning(X(`@WORKBENCH:该子任务正在执行中`));return}let r=a.value.find(e=>e.id===t.id);if((!r||r.title!==t.title||r.desc!==t.desc||JSON.stringify(r.subtasks)!==JSON.stringify(t.subtasks)||r.promptId!==t.promptId)&&!await kt(!1))return;let i=await fetch(`/api/workbench/subtasks/${e.id}/run`,{method:`POST`}).then(e=>e.json()).catch(e=>({success:!1,error:e?.message||String(e)}));i.success?k.success(i.message||X(`@WORKBENCH:已开始执行子任务`)):k.error(i.error||X(`@WORKBENCH:执行失败`))}function Ht(e){if(e.status===`done`)return!1;let t=Ae(e.id);return!(t&&(t.status===`running`||t.status===`pending`))}function Ut(e){if(!Ht(e)||!d.value)return!1;let t=d.value.subtasks||[],n=t.findIndex(t=>t.id===e.id);return!(n<0||n===t.length-1)}async function Wt(e){if(!d.value)return;let t=d.value,n=(t.subtasks||[]).findIndex(t=>t.id===e.id);if(n<0)return;let r=a.value.find(e=>e.id===t.id);if((!r||r.title!==t.title||r.desc!==t.desc||JSON.stringify(r.subtasks)!==JSON.stringify(t.subtasks)||r.promptId!==t.promptId)&&!await kt(!1))return;let i=await fetch(`/api/workbench/tasks/${t.id}/run-from`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({startSubIndex:n})}).then(e=>e.json()).catch(e=>({success:!1,error:e?.message||String(e)}));i.success?k.success(i.message||X(`@WORKBENCH:已从此处开始执行`)):k.error(i.error||X(`@WORKBENCH:执行失败`))}async function Gt(e){if(d.value&&!Tt(e.id)){Et(e.id,!0);try{let t=x.value.get(e.id);t&&x.value.set(e.id,{...t,status:`todo`}),e.status=`todo`,await kt(!1)}finally{Et(e.id,!1)}}}async function Kt(e){try{await z.confirm(X(`@WORKBENCH:确认停止执行?已输出的内容会保留。`),X(`@WORKBENCH:停止执行`),{confirmButtonText:X(`@WORKBENCH:停止`),cancelButtonText:X(`@WORKBENCH:取消`),type:`warning`})}catch{return}let t=await fetch(`/api/workbench/jobs/${e.id}/cancel`,{method:`POST`}).then(e=>e.json()).catch(e=>({success:!1,error:e?.message||String(e)}));t.success?k.success(X(`@WORKBENCH:已发送停止信号`)):k.error(t.error||X(`@WORKBENCH:停止失败`))}l(async()=>{await Promise.all([qe(),Je(),Ye(),it()]),lt(),window.addEventListener(`beforeunload`,Ce)}),c(()=>{Z&&=(Z.close(),null),window.removeEventListener(`beforeunload`,Ce),d.value&&B.value&&ye(d.value)});let qt=new Set([`image/png`,`image/jpeg`,`image/jpg`,`image/gif`,`image/webp`,`image/bmp`,`image/svg+xml`,`application/pdf`,`text/plain`,`text/markdown`,`text/x-markdown`,`text/csv`,`application/json`,`text/json`,`text/x-log`]),Jt=M({}),$=M(null);function Yt(e){return!!Jt.value[e]}function Zt(e,t){if(e instanceof File)return e;let n=e.type||`application/octet-stream`;return new File([e],t,{type:n})}function Qt(e){return e.kind===`task`?`task-${e.task?.id??``}`:`sub-${e.sub.id}`}function $t(e){let t=e.kind===`task`?e.task?.attachments:e.sub.attachments;return Array.isArray(t)?t:[]}function en(e,t){e.kind===`task`?e.task&&(e.task.attachments=t):e.sub.attachments=t}function tn(e){return e.kind===`task`?`/api/workbench/tasks/${e.task?.id??``}/attachments`:`/api/workbench/subtasks/${e.sub.id}/attachments`}function nn(e,t){return e.kind===`task`?`/api/workbench/tasks/${e.task?.id??``}/attachments/${t}`:`/api/workbench/subtasks/${e.sub.id}/attachments/${t}`}function rn(e,t){if(!e.clipboardData)return;let n=Array.from(e.clipboardData.items).filter(e=>e.kind===`file`&&e.type.startsWith(`image/`));if(n.length>0){e.preventDefault();for(let e of n){let n=e.getAsFile();if(!n)continue;let r=(n.type.split(`/`)[1]||`png`).replace(`jpeg`,`jpg`);on(t,Zt(n,`paste-${new Date().toISOString().replace(/[:.]/g,`-`)}.${r}`))}return}let r=Array.from(e.clipboardData.items).filter(e=>e.kind===`file`&&!e.type.startsWith(`image/`));if(r.length>0){e.preventDefault();for(let e of r){let n=e.getAsFile();n&&on(t,Zt(n,n.name||`pasted-file`))}}}function an(e,t){$.value=null,Array.from(e.dataTransfer?.files||[]).forEach(e=>on(t,e))}async function on(e,t){if(t.size>wa){k.error(`「${t.name}」${X(`@WORKBENCH:超过 5MB 限制`)}`);return}if(!qt.has(t.type)&&!t.name.match(/\.(png|jpg|jpeg|gif|webp|bmp|svg|pdf|txt|md|markdown|csv|json|log)$/i)){k.error(`${X(`@WORKBENCH:不支持的文件类型`)}(${t.name})`);return}let n=$t(e);if(n.length>=9){k.error(X(`@WORKBENCH:单个任务最多 9 个附件`));return}if(n.find(e=>e.originalName===t.name&&e.size===t.size)){k.info(`${t.name} ${X(`@WORKBENCH:已存在,已复用`)}`);return}let r=Qt(e);Jt.value[r]=!0;try{let n=await fetch(tn(e),{method:`POST`,headers:{"Content-Type":`application/octet-stream`,"X-Original-Name":t.name,"X-Mime-Type":t.type||`application/octet-stream`},body:t}).then(e=>e.json());if(n.success){let r=$t(e);r.push(n.attachment),en(e,r),k.success(`${X(`@WORKBENCH:已添加:`)}${t.name}`)}else k.error(n.error||X(`@WORKBENCH:上传失败`))}catch(e){k.error(X(`@WORKBENCH:上传失败`)+`:`+(e&&e.message||e))}finally{Jt.value[r]=!1}}async function sn(e,t){try{await z.confirm(X(`@WORKBENCH:删除附件「{name}」?`,{name:t.originalName}),X(`@WORKBENCH:确认`),{type:`warning`})}catch{return}let n=await fetch(nn(e,t.id),{method:`DELETE`}).then(e=>e.json());n.success?(en(e,$t(e).filter(e=>e.id!==t.id)),k.success(X(`@WORKBENCH:已删除`))):k.error(n.error||X(`@WORKBENCH:删除失败`))}function cn(e){let t=document.createElement(`input`);t.type=`file`,t.accept=Ca,t.multiple=!0,t.onchange=()=>{Array.from(t.files||[]).forEach(t=>on(e,t))},t.click()}let ln=new Set([`png`,`jpg`,`jpeg`,`gif`,`webp`,`bmp`,`svg`]);function un(e){return ln.has(String(e.ext||``).toLowerCase())}function dn(e){return e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:`${(e/1024/1024).toFixed(2)} MB`}return(e,o)=>{let c=ne,l=t,g=Se,x=r,S=te,E=xe,k=f;return Y(),J(`div`,hr,[I(`div`,gr,[I(`aside`,_r,[I(`section`,vr,[I(`header`,yr,[I(`span`,br,W(V(X)(`@WORKBENCH:任务`)),1),I(`h3`,xr,W(V(X)(`@WORKBENCH:任务列表`)),1),I(`span`,Sr,W(a.value.length),1)]),I(`button`,{class:`wb-new-btn`,disabled:_t.value,onClick:yt},[G(c,{class:`wb-new-btn__icon`},{default:D(()=>[G(V(y))]),_:1}),I(`span`,null,W(V(X)(`@WORKBENCH:新建任务`)),1),o[39]||=I(`span`,{class:`wb-new-btn__shortcut`},`N`,-1)],8,Cr),I(`ul`,wr,[(Y(!0),J(P,null,C(nt.value.groups,e=>(Y(),J(P,{key:e.path},[nt.value.hasMultiple?(Y(),J(`li`,{key:0,class:R([`wb-task-group__head`,{"is-current":e.path===Q.value.path,"is-collapsed":et(e.path)}]),role:`button`,tabindex:`0`,"aria-expanded":!et(e.path),title:et(e.path)?V(X)(`@WORKBENCH:展开`):V(X)(`@WORKBENCH:收起`),onClick:t=>tt(e.path),onKeydown:[fe(H(t=>tt(e.path),[`prevent`]),[`enter`]),fe(H(t=>tt(e.path),[`prevent`]),[`space`])]},[G(c,{class:`wb-task-group__caret`},{default:D(()=>[(Y(),O(w(et(e.path)?V(re):V(T))))]),_:2},1024),G(c,{class:`wb-task-group__icon`},{default:D(()=>[G(V(Te))]),_:1}),I(`span`,{class:`wb-task-group__name`,title:e.path===Q.value.path?Q.value.path:e.label},W(e.path===Q.value.path?Q.value.name:rt(e.label)),9,Er),I(`span`,Dr,W(e.tasks.length),1)],42,Tr)):U(``,!0),et(e.path)?U(``,!0):(Y(!0),J(P,{key:1},C(e.tasks,e=>(Y(),J(`li`,{key:e.id,class:R([`wb-task-item`,{active:e.id===u.value,"has-attachment":Ue(e)>0,"is-other-project":e.projectPath&&e.projectPath!==Q.value.path,"is-running":Ke(e)}]),"data-icon":Le(e.title),onClick:t=>Ct(e)},[I(`div`,{class:`wb-task-item__avatar`,"data-icon":Le(e.title)},[G(c,null,{default:D(()=>[(Y(),O(w(ze(e))))]),_:2},1024)],8,kr),I(`div`,Ar,[I(`div`,{class:`wb-task-item__title`,title:e.title},W(e.title||V(X)(`@WORKBENCH:未命名任务`)),9,jr),I(`div`,Mr,[We(e)>0?(Y(),J(`span`,{key:0,class:R([`wb-task-item__meta-item`,{"wb-task-item__meta-item--running":Ke(e)}]),title:V(X)(`@WORKBENCH:个子任务`)},[G(c,{class:`wb-task-item__meta-icon`},{default:D(()=>[G(V(ee))]),_:1}),I(`span`,Pr,W(Ge(e))+`/`+W(We(e)),1)],10,Nr)):U(``,!0),Ue(e)>0?(Y(),J(`span`,{key:1,class:`wb-task-item__meta-item`,title:V(X)(`@WORKBENCH:附件`)},[G(c,{class:`wb-task-item__meta-icon`},{default:D(()=>[G(V(_))]),_:1}),I(`span`,Ir,W(Ue(e)),1)],8,Fr)):U(``,!0),e.promptId?(Y(),J(`span`,{key:2,class:`wb-task-item__meta-item wb-task-item__meta-item--accent`,title:V(X)(`@WORKBENCH:已绑定预置提示词`)},[G(c,{class:`wb-task-item__meta-icon`},{default:D(()=>[G(V(v))]),_:1})],8,Lr)):U(``,!0),I(`button`,{type:`button`,class:R([`wb-task-item__meta-item wb-task-item__type-toggle`,e.type===`simple`?`wb-task-item__meta-item--simple`:`wb-task-item__meta-item--complex`]),title:e.type===`simple`?V(X)(`@WORKBENCH:简单任务 - 点击切换为复杂任务`):V(X)(`@WORKBENCH:复杂任务 - 点击切换为简单任务`),"aria-label":e.type===`simple`?V(X)(`@WORKBENCH:切换为复杂任务`):V(X)(`@WORKBENCH:切换为简单任务`)},W(e.type===`simple`?V(X)(`@WORKBENCH:简单`):V(X)(`@WORKBENCH:复杂`)),11,Rr),e.projectPath&&e.projectPath!==Q.value.path?(Y(),J(`span`,{key:3,class:`wb-task-item__meta-item wb-task-item__meta-item--project`,title:e.projectPath},W(rt(e.projectPath)),9,zr)):U(``,!0)])]),Ke(e)?(Y(),J(`span`,{key:0,class:`wb-task-item__running-dot`,title:V(X)(`@WORKBENCH:执行中`),"aria-hidden":`true`},null,8,Br)):U(``,!0),I(`button`,{class:`wb-task-item__del`,onClick:H(t=>St(e),[`stop`]),title:V(X)(`@WORKBENCH:删除`),"aria-label":V(X)(`@WORKBENCH:删除`)},[G(c,null,{default:D(()=>[G(V(_e))]),_:1})],8,Vr)],10,Or))),128))],64))),128)),a.value.length===0?(Y(),J(`li`,Hr,[I(`div`,Ur,[G(c,null,{default:D(()=>[G(V(oe))]),_:1})]),I(`div`,Wr,W(V(X)(`@WORKBENCH:暂无任务`)),1),I(`div`,Gr,W(V(X)(`@WORKBENCH:点击上方按钮新建`)),1),I(`div`,Kr,[G(l,{type:`primary`,size:`small`,icon:V(y),loading:_t.value,onClick:yt},{default:D(()=>[n(W(V(X)(`@WORKBENCH:新建任务`)),1)]),_:1},8,[`icon`,`loading`])])])):U(``,!0)])]),I(`section`,qr,[I(`header`,Jr,[I(`span`,Yr,W(V(X)(`@WORKBENCH:提示`)),1),I(`h3`,Xr,W(V(X)(`@WORKBENCH:预置提示词`)),1),I(`span`,Zr,W(i.value.length),1),I(`button`,{class:`wb-section__action`,onClick:ut,title:V(X)(`@WORKBENCH:新建提示词`),"aria-label":V(X)(`@WORKBENCH:新建提示词`)},[G(c,null,{default:D(()=>[G(V(y))]),_:1})],8,Qr)]),I(`ul`,$r,[(Y(!0),J(P,null,C(i.value,e=>(Y(),J(`li`,{key:e.id,class:`wb-prompt-item`},[I(`div`,ei,[G(c,null,{default:D(()=>[G(V(v))]),_:1})]),I(`span`,{class:`wb-prompt-item__name`,onClick:t=>dt(e),title:e.content},W(e.name),9,ti),Q.value.name?(Y(),J(`span`,{key:0,class:`wb-prompt-item__project`,title:V(X)(`@WORKBENCH:适用于当前项目`)+`:`+Q.value.path},W(Q.value.name),9,ni)):U(``,!0),I(`button`,{class:`wb-prompt-item__del`,onClick:t=>gt(e),title:V(X)(`@WORKBENCH:删除`),"aria-label":V(X)(`@WORKBENCH:删除`)},[G(c,null,{default:D(()=>[G(V(_e))]),_:1})],8,ri)]))),128)),i.value.length===0?(Y(),J(`li`,ii,W(V(X)(`@WORKBENCH:暂无提示词`)),1)):U(``,!0)])])]),I(`section`,ai,[d.value?(Y(),J(P,{key:1},[I(`div`,si,[b(I(`input`,{ref_key:`titleInputRef`,ref:vt,class:`wb-input wb-input--title`,"onUpdate:modelValue":o[0]||=e=>d.value.title=e,placeholder:V(X)(`@WORKBENCH:任务标题`)},null,8,ci),[[we,d.value.title]]),F.value!==`idle`||B.value?(Y(),J(`span`,{key:0,class:R([`wb-meta-save`,{"is-saving":F.value===`saving`,"is-saved":F.value===`saved`,"is-error":F.value===`error`,"is-dirty":B.value&&F.value===`idle`}]),title:F.value===`saving`?V(X)(`@WORKBENCH:保存中…`):F.value===`error`?V(X)(`@WORKBENCH:保存失败`):F.value===`saved`?V(X)(`@WORKBENCH:已保存`):``},[F.value===`saving`?(Y(),J(`span`,ui)):F.value===`saved`?(Y(),J(`span`,di,`✓`)):F.value===`error`?(Y(),J(`span`,fi,`!`)):(Y(),J(`span`,pi)),n(` `+W(F.value===`saving`?V(X)(`@WORKBENCH:保存中…`):F.value===`saved`?V(X)(`@WORKBENCH:已保存`):F.value===`error`?V(X)(`@WORKBENCH:保存失败`):V(X)(`@WORKBENCH:有未保存的更改`)),1)],10,li)):U(``,!0),b(I(`select`,{class:`wb-select`,"onUpdate:modelValue":o[1]||=e=>d.value.promptId=e},[I(`option`,mi,W(V(X)(`@WORKBENCH:不绑定预置提示词`)),1),(Y(!0),J(P,null,C(i.value,e=>(Y(),J(`option`,{key:e.id,value:e.id},W(e.name),9,hi))),128))],512),[[he,d.value.promptId]]),I(`div`,{class:`wb-mode-switch`,role:`tablist`,"aria-label":V(X)(`@WORKBENCH:任务类型`)},[I(`button`,{type:`button`,role:`tab`,class:R([`wb-mode-switch__btn`,{"is-active":!p.value}]),"aria-selected":!p.value,onClick:o[2]||=e=>xt(`complex`)},W(V(X)(`@WORKBENCH:复杂`)),11,_i),I(`button`,{type:`button`,role:`tab`,class:R([`wb-mode-switch__btn`,{"is-active":p.value}]),"aria-selected":p.value,onClick:o[3]||=e=>xt(`simple`)},W(V(X)(`@WORKBENCH:简单`)),11,vi),I(`span`,{class:R([`wb-mode-switch__indicator`,{"is-right":p.value}]),"aria-hidden":`true`},null,2)],8,gi),p.value?U(``,!0):(Y(),J(`button`,{key:1,type:`button`,class:`wb-ai-split-btn`,disabled:!d.value.title||!d.value.title.trim(),title:V(X)(`@WORKBENCH:AI 拆分`),onClick:Mt},[o[40]||=I(`svg`,{class:`wb-ai-split-btn__icon`,viewBox:`0 0 16 16`,width:`14`,height:`14`,"aria-hidden":`true`},[I(`path`,{d:`M8 1.5l1.6 3.4 3.4 1.6-3.4 1.6L8 11.5 6.4 8.1 3 6.5l3.4-1.6L8 1.5zM2.5 9.5l.8 1.6 1.6.8-1.6.8-.8 1.6-.8-1.6L.1 11.9l1.6-.8.8-1.6zm11 0l.8 1.6 1.6.8-1.6.8-.8 1.6-.8-1.6-1.6-.8 1.6-.8.8-1.6z`,fill:`currentColor`})],-1),I(`span`,null,W(V(X)(`@WORKBENCH:AI 拆分`)),1)],8,yi)),G(l,{type:`primary`,loading:!1,onClick:o[4]||=e=>Pt(d.value)},{default:D(()=>[n(W(p.value?V(X)(`@WORKBENCH:执行`):V(X)(`@WORKBENCH:执行任务`)),1)]),_:1}),I(`button`,{type:`button`,class:`wb-logs-inline-btn wb-logs-inline-btn--danger`,title:V(X)(`@WORKBENCH:清空当前任务的所有执行内容`),"aria-label":V(X)(`@WORKBENCH:清空当前任务的所有执行内容`),onClick:st},[G(c,{class:`wb-logs-inline-btn__icon`},{default:D(()=>[G(V(pe))]),_:1}),I(`span`,null,W(V(X)(`@WORKBENCH:清空执行`)),1)],8,bi),I(`button`,{type:`button`,class:`wb-logs-inline-btn`,title:V(X)(`@WORKBENCH:执行日志`),"aria-label":V(X)(`@WORKBENCH:执行日志`),onClick:o[5]||=e=>s.value=!0},[G(c,{class:`wb-logs-inline-btn__icon`},{default:D(()=>[G(V(be))]),_:1}),I(`span`,null,W(V(X)(`@WORKBENCH:执行日志`)),1)],8,xi)]),I(`details`,{class:`wb-task-desc`,open:Ee.value,onToggle:o[13]||=e=>Ee.value=e.target.open},[I(`summary`,Ci,[G(c,{class:`wb-task-desc__caret`},{default:D(()=>[(Y(),O(w(Ee.value?V(T):V(re))))]),_:1}),I(`span`,wi,W(V(X)(`@WORKBENCH:任务描述(可选)`)),1),d.value.desc&&d.value.desc.length>0||d.value.attachments&&d.value.attachments.length>0?(Y(),J(`span`,Ti,[d.value.desc&&d.value.desc.length>0?(Y(),J(`span`,Ei,W(V(X)(`@WORKBENCH:已填写`)),1)):U(``,!0),d.value.attachments&&d.value.attachments.length>0?(Y(),J(`span`,Di,W(d.value.attachments.length),1)):U(``,!0)])):U(``,!0)]),b(I(`textarea`,{class:`wb-textarea`,"onUpdate:modelValue":o[6]||=e=>d.value.desc=e,placeholder:V(X)(`@WORKBENCH:任务描述(可选)`),rows:`2`,onPaste:o[7]||=e=>rn(e,{kind:`task`,task:d.value})},null,40,Oi),[[we,d.value.desc]]),G(Xt,{attachments:d.value.attachments||[],"is-image":un,"human-size":dn,"is-uploading":Yt(`task-`+d.value.id),"is-paste-hover":$.value===`task-`+d.value.id,"max-count":9,"on-pick":()=>cn({kind:`task`,task:d.value}),"on-remove":e=>sn({kind:`task`,task:d.value},e),onPaste:o[8]||=e=>rn(e,{kind:`task`,task:d.value}),onDrop:o[9]||=H(e=>an(e,{kind:`task`,task:d.value}),[`prevent`]),onDragover:o[10]||=H(e=>$.value=`task-`+d.value.id,[`prevent`]),onDragenter:o[11]||=H(e=>$.value=`task-`+d.value.id,[`prevent`]),onDragleave:o[12]||=e=>$.value=$.value===`task-`+d.value.id?null:$.value},null,8,[`attachments`,`is-uploading`,`is-paste-hover`,`on-pick`,`on-remove`])],40,Si),I(`div`,{class:R([`wb-execution-body`,{"wb-execution-body--simple":p.value}])},[p.value?U(``,!0):(Y(),J(`div`,ki,[I(`div`,Ai,[I(`h4`,ji,W(V(X)(`@WORKBENCH:子任务拆分`)),1),I(`div`,Mi,[G(l,{size:`small`,plain:``,icon:V(y),disabled:d.value.subtasks.length===0,onClick:Dt},{default:D(()=>[n(W(V(X)(`@WORKBENCH:添加子任务`)),1)]),_:1},8,[`icon`,`disabled`]),G(l,{size:`small`,type:ae.value?`primary`:`default`,disabled:d.value.subtasks.length===0,onClick:At},{default:D(()=>[n(W(V(X)(`@WORKBENCH:保存拆分`))+` `,1),ae.value?(Y(),J(`span`,Ni,W(j.value.size),1)):U(``,!0)]),_:1},8,[`type`,`disabled`]),G(l,{size:`small`,type:`danger`,plain:``,icon:V(pe),disabled:!d.value.subtasks||d.value.subtasks.length===0,title:V(X)(`@WORKBENCH:只清空子任务,任务描述/附件/标题保留`),onClick:ct},{default:D(()=>[n(W(V(X)(`@WORKBENCH:清空子任务`)),1)]),_:1},8,[`icon`,`disabled`,`title`])])]),I(`ul`,Pi,[(Y(!0),J(P,null,C(d.value.subtasks,e=>(Y(),J(`li`,{key:e.id,class:R([`wb-exec-sub-item`,{"is-selected":m.value===e.id,"is-running":e.status===`running`,"is-done":e.status===`done`,"is-dirty":j.value.has(e.id),"is-persisting":Tt(e.id)}]),onClick:t=>m.value=e.id},[I(`div`,Ii,[e.status===`error`&&e.error?(Y(),O(g,{key:0,placement:`right-start`,width:420,trigger:`hover`,"show-after":120,"popper-class":`wb-sub-error-popover`},{reference:D(()=>[I(`span`,{class:`wb-sub-item__status wb-sub-item__status--dot wb-sub-item__status--clickable`,style:ie({background:V(Rn)(e.status)}),title:V(X)(`@WORKBENCH:点击查看错误详情`)},[...o[41]||=[I(`span`,{class:`wb-simple__status-dot`,"aria-hidden":`true`},null,-1)]],12,Li)]),default:D(()=>[I(`div`,Ri,[I(`div`,zi,[G(c,{class:`wb-sub-error__icon`},{default:D(()=>[G(V(ue))]),_:1}),I(`span`,Bi,W(V(X)(`@WORKBENCH:执行出错`)),1),e.errorAt?(Y(),J(`span`,Vi,W(Pe(e.errorAt)),1)):U(``,!0)]),I(`pre`,Hi,W(e.error),1),I(`div`,Ui,[G(l,{size:`small`,icon:V(N),onClick:t=>Fe(e)},{default:D(()=>[n(W(V(X)(`@WORKBENCH:复制错误信息`)),1)]),_:1},8,[`icon`,`onClick`]),G(l,{size:`small`,type:`primary`,onClick:t=>Ie(e)},{default:D(()=>[n(W(V(X)(`@WORKBENCH:查看执行日志`)),1)]),_:1},8,[`onClick`])])])]),_:2},1024)):(Y(),J(`span`,{key:1,class:`wb-sub-item__status wb-sub-item__status--dot`,style:ie({background:V(Rn)(e.status)}),title:V(X)(`@WORKBENCH:任务完成状态`)},[...o[42]||=[I(`span`,{class:`wb-simple__status-dot`,"aria-hidden":`true`},null,-1)]],12,Wi)),I(`span`,{class:`wb-exec-sub-item__title`,title:e.title},W(e.title||V(X)(`@WORKBENCH:未命名子任务`)),9,Gi),j.value.has(e.id)?(Y(),J(`span`,Ki)):U(``,!0)]),I(`div`,qi,[Ae(e.id)?(Y(),J(`span`,Ji,`PID: `+W(Ae(e.id)?.pid),1)):U(``,!0),I(`span`,Yi,[Ht(e)?(Y(),J(`button`,{key:0,class:`wb-exec-sub-btn wb-exec-sub-btn--run`,title:V(X)(`@WORKBENCH:单独执行此子任务`),onClick:H(t=>Vt(e),[`stop`])},W(V(X)(`@WORKBENCH:执行`)),9,Xi)):U(``,!0),Ut(e)?(Y(),J(`button`,{key:1,class:`wb-exec-sub-btn wb-exec-sub-btn--run-from`,title:V(X)(`@WORKBENCH:从此处执行后续子任务`),onClick:H(t=>Wt(e),[`stop`])},W(V(X)(`@WORKBENCH:从此处开始`)),9,Zi)):U(``,!0),Ae(e.id)&&(Ae(e.id)?.status===`running`||Ae(e.id)?.status===`pending`)?(Y(),J(`button`,{key:2,class:`wb-exec-sub-btn wb-exec-sub-btn--stop`,title:V(X)(`@WORKBENCH:停止执行`),onClick:H(t=>Kt(Ae(e.id)),[`stop`])},W(V(X)(`@WORKBENCH:停止`)),9,Qi)):U(``,!0),e.status===`done`?(Y(),J(`button`,{key:3,class:`wb-exec-sub-btn wb-exec-sub-btn--undo`,title:V(X)(`@WORKBENCH:取消完成`),disabled:Tt(e.id),onClick:H(t=>Gt(e),[`stop`])},W(V(X)(`@WORKBENCH:取消完成`)),9,$i)):U(``,!0),I(`button`,{class:`wb-exec-sub-btn wb-exec-sub-btn--del`,title:V(X)(`@WORKBENCH:删除`),disabled:Tt(e.id),onClick:H(t=>Ot(e),[`stop`])},`×`,8,ea)])])],10,Fi))),128)),d.value.subtasks.length===0?(Y(),J(`li`,ta,[I(`div`,na,[G(c,null,{default:D(()=>[G(V(ee))]),_:1})]),I(`div`,ra,W(V(X)(`@WORKBENCH:拆分任务,逐项执行`)),1),I(`div`,ia,[G(l,{type:`primary`,size:`small`,icon:V(y),onClick:Dt},{default:D(()=>[n(W(V(X)(`@WORKBENCH:添加子任务`)),1)]),_:1},8,[`icon`])])])):U(``,!0)])])),I(`div`,aa,[p.value?(Y(),J(P,{key:1},[I(`details`,{class:R([`wb-simple__override`,{"has-content":!!(d.value.simpleOverride&&d.value.simpleOverride.trim())}])},[I(`summary`,da,[G(c,{class:`wb-simple__override-caret`},{default:D(()=>[G(V(re))]),_:1}),I(`span`,null,W(V(X)(`@WORKBENCH:覆盖预置提示词(可选)`)),1),d.value.simpleOverride&&d.value.simpleOverride.trim()?(Y(),J(`span`,{key:0,class:`wb-simple__override-tag`,title:V(X)(`@WORKBENCH:已填写覆盖内容`)},W(V(X)(`@WORKBENCH:已填写`)),9,fa)):U(``,!0),He(Ve(d.value))===`running`&&Ve(d.value)?(Y(),J(`button`,{key:1,class:`wb-simple__stop`,disabled:Tt(Ve(d.value).id),onClick:o[24]||=H(e=>Kt(Ve(d.value)),[`stop`])},W(V(X)(`@WORKBENCH:停止`)),9,pa)):U(``,!0)]),b(I(`textarea`,{class:`wb-textarea`,"onUpdate:modelValue":o[25]||=e=>d.value.simpleOverride=e,placeholder:V(X)(`@WORKBENCH:留空则使用上方选定的「预置提示词」模板;可用变量同子任务:{{task.title}} {{task.desc}} {{repo.path}} {{branch}}`),rows:`6`},null,8,ma),[[we,d.value.simpleOverride]])],2),(Y(!0),J(P,null,C(Be(d.value),e=>(Y(),O(In,{key:e.id,job:e},null,8,[`job`]))),128)),Ve(d.value)&&[`done`,`error`,`cancelled`].includes(He(Ve(d.value)))?(Y(),J(`div`,ha,[b(I(`textarea`,{class:`wb-textarea wb-simple__continue-input`,"onUpdate:modelValue":o[26]||=e=>Lt[d.value.id]=e,placeholder:V(X)(`@WORKBENCH:输入后续问题继续对话…(Ctrl+Enter 发送)`),rows:`3`,onKeydown:o[27]||=fe(H(e=>Bt(d.value),[`ctrl`,`prevent`]),[`enter`])},null,40,ga),[[we,Lt[d.value.id]]]),I(`div`,_a,[G(l,{onClick:o[28]||=e=>zt(d.value)},{default:D(()=>[n(W(V(X)(`@WORKBENCH:退出`)),1)]),_:1}),G(l,{type:`primary`,disabled:!(Lt[d.value.id]||``).trim(),onClick:o[29]||=e=>Bt(d.value)},{default:D(()=>[n(W(V(X)(`@WORKBENCH:发送`)),1)]),_:1},8,[`disabled`])])])):U(``,!0)],64)):(Y(),J(P,{key:0},[h.value?(Y(),J(P,{key:1},[I(`div`,sa,[b(I(`input`,{class:`wb-input`,"onUpdate:modelValue":o[14]||=e=>h.value.title=e,placeholder:V(X)(`@WORKBENCH:子任务标题`),onClick:o[15]||=H(()=>{},[`stop`]),onPaste:o[16]||=e=>rn(e,{kind:`sub`,task:d.value,sub:h.value})},null,40,ca),[[we,h.value.title]]),j.value.has(h.value.id)?(Y(),J(`span`,{key:0,class:`wb-sub-item__dirty`,title:V(X)(`@WORKBENCH:有未保存的更改`)},W(V(X)(`@WORKBENCH:未保存`)),9,la)):U(``,!0)]),b(I(`textarea`,{class:`wb-textarea wb-textarea--sm`,"onUpdate:modelValue":o[17]||=e=>h.value.desc=e,placeholder:V(X)(`@WORKBENCH:子任务描述 / 独立提示词覆盖`),rows:`3`,onPaste:o[18]||=e=>rn(e,{kind:`sub`,task:d.value,sub:h.value})},null,40,ua),[[we,h.value.desc]]),Ae(h.value.id)?(Y(),O(In,{key:0,job:Ae(h.value.id)},null,8,[`job`])):U(``,!0),G(Xt,{attachments:h.value.attachments||[],"is-image":un,"human-size":dn,"is-uploading":Yt(`sub-`+h.value.id),"is-paste-hover":$.value===h.value.id,"max-count":9,"on-pick":()=>cn({kind:`sub`,task:d.value,sub:h.value}),"on-remove":e=>sn({kind:`sub`,task:d.value,sub:h.value},e),onPaste:o[19]||=e=>rn(e,{kind:`sub`,task:d.value,sub:h.value}),onDrop:o[20]||=H(e=>an(e,{kind:`sub`,task:d.value,sub:h.value}),[`prevent`]),onDragover:o[21]||=H(e=>$.value=h.value.id,[`prevent`]),onDragenter:o[22]||=H(e=>$.value=h.value.id,[`prevent`]),onDragleave:o[23]||=e=>$.value=$.value===h.value.id?null:$.value},null,8,[`attachments`,`is-uploading`,`is-paste-hover`,`on-pick`,`on-remove`])],64)):(Y(),J(`div`,oa,[I(`p`,null,W(d.value.subtasks.length===0?V(X)(`@WORKBENCH:手动添加子任务,或让 AI 帮你自动拆分`):V(X)(`@WORKBENCH:左侧选择子任务查看详情`)),1)]))],64))])],2)],64)):(Y(),J(`div`,oi,[I(`p`,null,W(V(X)(`@WORKBENCH:左侧选择任务,或新建一个任务开始`)),1)]))])]),G(x,{modelValue:s.value,"onUpdate:modelValue":o[30]||=e=>s.value=e,title:V(X)(`@WORKBENCH:执行日志`),width:`1080px`,"close-on-click-modal":!1,top:`6vh`,class:`wb-logs-dialog`},{default:D(()=>[G(mr)]),_:1},8,[`modelValue`,`title`]),G(x,{modelValue:K.visible,"onUpdate:modelValue":o[34]||=e=>K.visible=e,title:K.editing?V(X)(`@WORKBENCH:编辑提示词`):V(X)(`@WORKBENCH:新建提示词`),width:`640px`},{footer:D(()=>[G(l,{onClick:o[33]||=e=>K.visible=!1},{default:D(()=>[n(W(V(X)(`@WORKBENCH:取消`)),1)]),_:1}),G(l,{type:`primary`,onClick:ht},{default:D(()=>[n(W(V(X)(`@WORKBENCH:保存`)),1)]),_:1})]),default:D(()=>[G(k,{"label-position":`top`},{default:D(()=>[G(E,{label:V(X)(`@WORKBENCH:名称`)},{default:D(()=>[G(S,{modelValue:K.name,"onUpdate:modelValue":o[31]||=e=>K.name=e,placeholder:V(X)(`@WORKBENCH:如:代码审查 / 写测试`)},null,8,[`modelValue`,`placeholder`])]),_:1},8,[`label`]),G(E,null,{default:D(()=>[I(`div`,va,[G(l,{type:`primary`,plain:``,loading:K.aiLoading,onClick:ft},{default:D(()=>[n(W(V(X)(`@WORKBENCH:AI 生成项目架构说明`)),1)]),_:1},8,[`loading`]),G(l,{onClick:pt},{default:D(()=>[n(W(V(X)(`@WORKBENCH:编辑指令`)),1)]),_:1})])]),_:1}),G(E,{label:V(X)(`@WORKBENCH:内容`)},{default:D(()=>[G(S,{modelValue:K.content,"onUpdate:modelValue":o[32]||=e=>K.content=e,type:`textarea`,rows:10,placeholder:V(X)(`@WORKBENCH:可用变量:`)+`{{task.title}} {{task.desc}} {{sub.title}} {{sub.desc}} {{repo.path}} {{branch}}`},null,8,[`modelValue`,`placeholder`])]),_:1},8,[`label`])]),_:1})]),_:1},8,[`modelValue`,`title`]),G(x,{modelValue:q.visible,"onUpdate:modelValue":o[37]||=e=>q.visible=e,title:V(X)(`@WORKBENCH:编辑生成指令`),width:`720px`,"append-to-body":``},{footer:D(()=>[G(l,{onClick:o[36]||=e=>q.visible=!1},{default:D(()=>[n(W(V(X)(`@WORKBENCH:取消`)),1)]),_:1}),G(l,{type:`primary`,loading:q.saving,onClick:mt},{default:D(()=>[n(W(V(X)(`@WORKBENCH:保存`)),1)]),_:1},8,[`loading`])]),default:D(()=>[G(k,{"label-position":`top`},{default:D(()=>[G(E,{label:V(X)(`@WORKBENCH:指令内容`)},{default:D(()=>[G(S,{modelValue:q.text,"onUpdate:modelValue":o[35]||=e=>q.text=e,type:`textarea`,rows:18,placeholder:V(X)(`@WORKBENCH:指令内容`)},null,8,[`modelValue`,`placeholder`])]),_:1},8,[`label`])]),_:1})]),_:1},8,[`modelValue`,`title`]),d.value?(Y(),O(Rt,{key:0,modelValue:jt.value,"onUpdate:modelValue":o[38]||=e=>jt.value=e,title:d.value.title,desc:d.value.desc,"task-id":d.value.id,"prompt-id":d.value.promptId,onConfirm:Nt},null,8,[`modelValue`,`title`,`desc`,`task-id`,`prompt-id`])):U(``,!0)])}}}),[[`__scopeId`,`data-v-1ae5d369`]]);export{Ta as default};
|