dsh-plugin-teamflow 0.1.8 → 0.1.9
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/CHANGELOG.md +27 -1
- package/README.en.md +14 -3
- package/README.md +6 -3
- package/lib/client.js +922 -259
- package/lib/descriptors.mjs +9 -0
- package/lib/host.mjs +2724 -563
- package/lib/store.mjs +55 -6
- package/package.json +3 -3
package/lib/client.js
CHANGED
|
@@ -51,6 +51,15 @@ window.__ModuleLoader__.load({
|
|
|
51
51
|
parameters: [],
|
|
52
52
|
result: strict
|
|
53
53
|
},
|
|
54
|
+
{
|
|
55
|
+
id: "dsh-plugin-teamflow#teamflow/setLocale",
|
|
56
|
+
service: "teamflow",
|
|
57
|
+
namespace: "teamflow",
|
|
58
|
+
method: "setLocale",
|
|
59
|
+
invocation: { kind: "direct" },
|
|
60
|
+
parameters: [p("locale")],
|
|
61
|
+
result: strict
|
|
62
|
+
},
|
|
54
63
|
{
|
|
55
64
|
id: "dsh-plugin-teamflow#teamflow/list",
|
|
56
65
|
service: "teamflow",
|
|
@@ -287,7 +296,52 @@ window.__ModuleLoader__.load({
|
|
|
287
296
|
* 会话内工作台(index.tsx)与全局面板(panel.tsx)共用:**只放无状态纯展示件**,
|
|
288
297
|
* 不放任何 Remote 调用或会话上下文逻辑——两边数据来源不同(sessionId / productKey),
|
|
289
298
|
* 展示语言必须一致。
|
|
299
|
+
*
|
|
300
|
+
* 双语(v0.1.9):文案统一走宿主 locale 服务(机制说明见 client/locales.ts)。
|
|
301
|
+
* 组件里能拿到注入的 `t`,但**词表/格式化/折叠件是纯函数**,拿不到 prop,
|
|
302
|
+
* 故由 `apply()` 调 `setTranslator()` 注入模块级翻译函数:`bind()` 每次调用都读当前语言,
|
|
303
|
+
* 且宿主在切语言时会重渲染每个 slot outlet(ui-renderer `useLocaleRevision`),
|
|
304
|
+
* 因此模块级函数不会持有过期语言。
|
|
290
305
|
*/
|
|
306
|
+
/** 翻译函数(默认恒等:未注入时显示 key 本身,便于发现漏注册)。 */
|
|
307
|
+
let translate = (key) => key;
|
|
308
|
+
/** 当前语言 id 的读取器(默认 en)。 */
|
|
309
|
+
let localeIdOf = () => "en";
|
|
310
|
+
/**
|
|
311
|
+
* 注入翻译函数与语言读取器(apply 时调用一次)。
|
|
312
|
+
* @param fn - `ctx.locale.bind(NS)` 的返回值(调用时读当前语言)。
|
|
313
|
+
* @param idOf - 返回当前语言 id 的函数(如 `() => ctx.locale.getSnapshot().active`)。
|
|
314
|
+
*/
|
|
315
|
+
function setTranslator(fn, idOf) {
|
|
316
|
+
if (typeof fn === "function") translate = fn;
|
|
317
|
+
if (typeof idOf === "function") localeIdOf = idOf;
|
|
318
|
+
}
|
|
319
|
+
/** 翻译(`{name}` 占位符由宿主替换)。 */
|
|
320
|
+
const t = (key, params) => translate(key, params);
|
|
321
|
+
/** 当前语言的 BCP 47 标签(时间格式化用;未知语言回退 en)。 */
|
|
322
|
+
function localeTag() {
|
|
323
|
+
let id = "en";
|
|
324
|
+
try {
|
|
325
|
+
id = String(localeIdOf() || "en");
|
|
326
|
+
} catch (e) {}
|
|
327
|
+
return id === "zh" ? "zh-CN" : id;
|
|
328
|
+
}
|
|
329
|
+
/** 词表查表:命中返回译文,未命中回退原始值(未知状态/角色等)。 */
|
|
330
|
+
function vocab(prefix, raw) {
|
|
331
|
+
const key = `${prefix}.${raw}`;
|
|
332
|
+
const hit = t(key);
|
|
333
|
+
return hit === key ? String(raw === null || raw === void 0 ? "" : raw) : hit;
|
|
334
|
+
}
|
|
335
|
+
const stText = (s) => vocab("status", s);
|
|
336
|
+
const runStatusText = (s) => vocab("runStatus", s);
|
|
337
|
+
const kindTitle = (k) => vocab("kind", k);
|
|
338
|
+
const roleName = (r) => vocab("role", r);
|
|
339
|
+
/** 角色 chip(带图标;未知角色回退「⚙️ <raw>」)。 */
|
|
340
|
+
function roleChip(r) {
|
|
341
|
+
const key = `roleChip.${r}`;
|
|
342
|
+
const hit = t(key);
|
|
343
|
+
return hit === key ? `⚙️ ${String(r)}` : hit;
|
|
344
|
+
}
|
|
291
345
|
const T = {
|
|
292
346
|
bg: "var(--dsw-alias-bg-base)",
|
|
293
347
|
layer1: "var(--dsw-alias-bg-layer-1)",
|
|
@@ -301,30 +355,7 @@ window.__ModuleLoader__.load({
|
|
|
301
355
|
success: "var(--dsw-alias-state-success-primary)",
|
|
302
356
|
warn: "var(--dsw-alias-state-warn-primary)"
|
|
303
357
|
};
|
|
304
|
-
|
|
305
|
-
created: "立项",
|
|
306
|
-
"in-progress": "进行中",
|
|
307
|
-
"pending-acceptance": "待验收",
|
|
308
|
-
accepted: "已验收",
|
|
309
|
-
closed: "已关闭",
|
|
310
|
-
pending: "待办",
|
|
311
|
-
running: "开发中",
|
|
312
|
-
testable: "待测试",
|
|
313
|
-
testing: "测试中",
|
|
314
|
-
rework: "打回",
|
|
315
|
-
"needs-human": "需人工",
|
|
316
|
-
cancelled: "已关闭",
|
|
317
|
-
open: "待认领",
|
|
318
|
-
claimed: "处理中",
|
|
319
|
-
fixed: "已修复待验",
|
|
320
|
-
verified: "已关闭",
|
|
321
|
-
reopened: "重开",
|
|
322
|
-
done: "已完成",
|
|
323
|
-
completed: "已完成",
|
|
324
|
-
failed: "失败",
|
|
325
|
-
interrupted: "已中断",
|
|
326
|
-
superseded: "已取代"
|
|
327
|
-
};
|
|
358
|
+
/** 状态色表(与语言无关的纯视觉映射)。 */
|
|
328
359
|
const STATUS_COLOR = {
|
|
329
360
|
created: T.text2,
|
|
330
361
|
pending: T.text2,
|
|
@@ -349,7 +380,7 @@ window.__ModuleLoader__.load({
|
|
|
349
380
|
interrupted: T.warn,
|
|
350
381
|
superseded: T.text2
|
|
351
382
|
};
|
|
352
|
-
/** 阶段英文键 →
|
|
383
|
+
/** 阶段英文键 → 图标(2026-09-06 英文化:journal.phase 为英文键,展示名统一走词表——换语言即换表)。 */
|
|
353
384
|
const PHASE_ICON = {
|
|
354
385
|
prd: "📋",
|
|
355
386
|
design: "🎨",
|
|
@@ -359,17 +390,6 @@ window.__ModuleLoader__.load({
|
|
|
359
390
|
qa: "🧪",
|
|
360
391
|
acceptance: "✅"
|
|
361
392
|
};
|
|
362
|
-
const PHASE_NAME = {
|
|
363
|
-
prd: "PRD 产品需求",
|
|
364
|
-
design: "UI/UX 设计",
|
|
365
|
-
scaffold: "架构规划",
|
|
366
|
-
tech: "技术方案",
|
|
367
|
-
dev: "开发",
|
|
368
|
-
qa: "QA 测试",
|
|
369
|
-
acceptance: "产品验收"
|
|
370
|
-
};
|
|
371
|
-
const phaseNameOf = (p) => PHASE_NAME[p] || p || "—";
|
|
372
|
-
const phaseIconOf = (p) => PHASE_ICON[p] || "⚙️";
|
|
373
393
|
/** phase 归一:英文键直通;存量中文映射(防御性——新数据全英文)。 */
|
|
374
394
|
const phaseKeyOf = (p) => ({
|
|
375
395
|
"PRD 产品需求": "prd",
|
|
@@ -380,15 +400,21 @@ window.__ModuleLoader__.load({
|
|
|
380
400
|
"QA 测试": "qa",
|
|
381
401
|
"产品验收": "acceptance"
|
|
382
402
|
})[p] || String(p || "");
|
|
383
|
-
const
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
403
|
+
const phaseNameOf = (p) => vocab("phase", phaseKeyOf(p));
|
|
404
|
+
const phaseIconOf = (p) => PHASE_ICON[phaseKeyOf(p)] || "⚙️";
|
|
405
|
+
/**
|
|
406
|
+
* 阶段的展示名(双语安全的取法)。
|
|
407
|
+
*
|
|
408
|
+
* journal 里 `stage.label` 是**持久化中文**(teams.json 配置 + 历史数据),而每个阶段都带
|
|
409
|
+
* 英文 `phase` 键——所以展示时:任务级阶段(dev 子卡,`taskKey` 有值)保留任务名(LLM 数据,
|
|
410
|
+
* 不该翻译),其余阶段用 `phase` 键查当前语言词表。**只影响展示,不动数据**:
|
|
411
|
+
* `__taskKey`/`taskKeyOf` 的任务聚合身份仍走 label 清理(聚合语义不能随语言变)。
|
|
412
|
+
*/
|
|
413
|
+
function stageLabelOf(s) {
|
|
414
|
+
const raw = String(s && s.label || "");
|
|
415
|
+
if (s && s.taskKey) return raw || String(s.taskKey);
|
|
416
|
+
return (s && s.phase ? phaseNameOf(s.phase) : "") || raw;
|
|
417
|
+
}
|
|
392
418
|
const COLUMNS = {
|
|
393
419
|
req: [
|
|
394
420
|
"created",
|
|
@@ -418,11 +444,6 @@ window.__ModuleLoader__.load({
|
|
|
418
444
|
"needs-human"
|
|
419
445
|
]
|
|
420
446
|
};
|
|
421
|
-
const KIND_TITLE = {
|
|
422
|
-
req: "需求",
|
|
423
|
-
task: "任务",
|
|
424
|
-
bug: "缺陷"
|
|
425
|
-
};
|
|
426
447
|
const h = react.default.createElement;
|
|
427
448
|
const MONO = "ui-monospace, SFMono-Regular, Consolas, \"Cascadia Mono\", monospace";
|
|
428
449
|
const SANS = "-apple-system, BlinkMacSystemFont, \"Segoe UI\", \"PingFang SC\", \"Microsoft YaHei\", sans-serif";
|
|
@@ -461,9 +482,9 @@ window.__ModuleLoader__.load({
|
|
|
461
482
|
function FoldableText({ text, charLimit = 280, lineLimit = 5, style }) {
|
|
462
483
|
const [open, setOpen] = react.default.useState(false);
|
|
463
484
|
if (!text) return null;
|
|
464
|
-
const
|
|
465
|
-
const lines =
|
|
466
|
-
const compact = lines.length <= lineLimit &&
|
|
485
|
+
const s = String(text);
|
|
486
|
+
const lines = s.split("\n");
|
|
487
|
+
const compact = lines.length <= lineLimit && s.length <= charLimit;
|
|
467
488
|
const body = (txt) => h("div", { style: {
|
|
468
489
|
fontSize: 11.5,
|
|
469
490
|
color: T.text,
|
|
@@ -472,10 +493,10 @@ window.__ModuleLoader__.load({
|
|
|
472
493
|
wordBreak: "break-word",
|
|
473
494
|
...style || {}
|
|
474
495
|
} }, txt);
|
|
475
|
-
if (compact) return body(
|
|
476
|
-
if (open) return h("div", null, body(
|
|
496
|
+
if (compact) return body(s);
|
|
497
|
+
if (open) return h("div", null, body(s), h("button", {
|
|
477
498
|
onClick: () => setOpen(false),
|
|
478
|
-
title: "
|
|
499
|
+
title: t("common.collapseFull"),
|
|
479
500
|
style: {
|
|
480
501
|
marginTop: 3,
|
|
481
502
|
font: "inherit",
|
|
@@ -487,12 +508,12 @@ window.__ModuleLoader__.load({
|
|
|
487
508
|
padding: 0,
|
|
488
509
|
cursor: "pointer"
|
|
489
510
|
}
|
|
490
|
-
}, "
|
|
491
|
-
const pre = lines.length > lineLimit ? lines.slice(0, lineLimit).join("\n") :
|
|
492
|
-
const more = lines.length > lineLimit ?
|
|
511
|
+
}, t("common.collapse")));
|
|
512
|
+
const pre = lines.length > lineLimit ? lines.slice(0, lineLimit).join("\n") : s.slice(0, charLimit);
|
|
513
|
+
const more = lines.length > lineLimit ? t("common.moreLines", { n: lines.length - lineLimit }) : "…";
|
|
493
514
|
return h("div", null, body(pre), h("button", {
|
|
494
515
|
onClick: () => setOpen(true),
|
|
495
|
-
title: "
|
|
516
|
+
title: t("common.clickToExpand"),
|
|
496
517
|
style: {
|
|
497
518
|
marginTop: 3,
|
|
498
519
|
font: "inherit",
|
|
@@ -504,11 +525,11 @@ window.__ModuleLoader__.load({
|
|
|
504
525
|
padding: 0,
|
|
505
526
|
cursor: "pointer"
|
|
506
527
|
}
|
|
507
|
-
},
|
|
528
|
+
}, `${t("common.expandFull")}${more}`));
|
|
508
529
|
}
|
|
509
|
-
function fmtTime(
|
|
510
|
-
if (!
|
|
511
|
-
const d = new Date(
|
|
530
|
+
function fmtTime(tm) {
|
|
531
|
+
if (!tm) return "—";
|
|
532
|
+
const d = new Date(tm);
|
|
512
533
|
return `${String(d.getHours()).padStart(2, "0")}:${String(d.getMinutes()).padStart(2, "0")}:${String(d.getSeconds()).padStart(2, "0")}`;
|
|
513
534
|
}
|
|
514
535
|
function fmtDur(a, b) {
|
|
@@ -545,9 +566,15 @@ window.__ModuleLoader__.load({
|
|
|
545
566
|
if (s.usage) {
|
|
546
567
|
const u = s.usage;
|
|
547
568
|
const hit = hitRate(u);
|
|
548
|
-
return
|
|
569
|
+
return t("token.usageLine", {
|
|
570
|
+
input: k(u.input),
|
|
571
|
+
cacheRead: k(u.cacheRead),
|
|
572
|
+
cacheWrite: k(u.cacheWrite),
|
|
573
|
+
output: k(u.output),
|
|
574
|
+
calls: u.calls
|
|
575
|
+
}) + (hit !== null ? t("token.usageHit", { hit }) : "");
|
|
549
576
|
}
|
|
550
|
-
return "
|
|
577
|
+
return t("token.usageMissing");
|
|
551
578
|
}
|
|
552
579
|
/** 节点卡主 token 行:官方口径 —— 输入(未命中)/输入(命中)/输出 + 缓存命中率。 */
|
|
553
580
|
function stageUsageLine(s) {
|
|
@@ -558,16 +585,6 @@ window.__ModuleLoader__.load({
|
|
|
558
585
|
}
|
|
559
586
|
return null;
|
|
560
587
|
}
|
|
561
|
-
const ROLE_NAME = {
|
|
562
|
-
pm: "产品",
|
|
563
|
-
design: "设计",
|
|
564
|
-
arch: "架构",
|
|
565
|
-
tech: "方案",
|
|
566
|
-
dev: "开发",
|
|
567
|
-
qa: "测试",
|
|
568
|
-
acceptance: "验收",
|
|
569
|
-
other: "其他"
|
|
570
|
-
};
|
|
571
588
|
const roleUsage = (u) => {
|
|
572
589
|
if (!u) return "";
|
|
573
590
|
const hit = hitRate(u);
|
|
@@ -576,11 +593,11 @@ window.__ModuleLoader__.load({
|
|
|
576
593
|
/** 任务卡按角色累计的真实 token 摘要(官方口径:未命中/命中输入 + 输出 + 命中率)。 */
|
|
577
594
|
function byRoleLine(task) {
|
|
578
595
|
const roles = task && task.byRole || {};
|
|
579
|
-
return Object.keys(roles).filter((k) => roles[k] && roles[k].input + roles[k].output + roles[k].cacheRead + roles[k].cacheWrite > 0).map((k) => `${
|
|
596
|
+
return Object.keys(roles).filter((k) => roles[k] && roles[k].input + roles[k].output + roles[k].cacheRead + roles[k].cacheWrite > 0).map((k) => `${roleName(k)} ${roleUsage(roles[k])}`).join(" · ");
|
|
580
597
|
}
|
|
581
598
|
/** 多阶段 usage 汇总(官方口径)。 */
|
|
582
599
|
function totalUsage(stages) {
|
|
583
|
-
const
|
|
600
|
+
const sum = {
|
|
584
601
|
input: 0,
|
|
585
602
|
cacheRead: 0,
|
|
586
603
|
cacheWrite: 0,
|
|
@@ -590,17 +607,559 @@ window.__ModuleLoader__.load({
|
|
|
590
607
|
for (const s of stages || []) {
|
|
591
608
|
const u = s && s.usage;
|
|
592
609
|
if (!u) continue;
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
610
|
+
sum.input += u.input || 0;
|
|
611
|
+
sum.cacheRead += u.cacheRead || 0;
|
|
612
|
+
sum.cacheWrite += u.cacheWrite || 0;
|
|
613
|
+
sum.output += u.output || 0;
|
|
614
|
+
sum.calls += u.calls || 0;
|
|
598
615
|
}
|
|
599
|
-
return
|
|
616
|
+
return sum;
|
|
600
617
|
}
|
|
601
|
-
const stText = (s) => STATUS_TEXT[s] || s;
|
|
602
618
|
const stColor = (s) => STATUS_COLOR[s] || T.text2;
|
|
603
619
|
//#endregion
|
|
620
|
+
//#region client/locales.ts
|
|
621
|
+
/**
|
|
622
|
+
* dsh-plugin-teamflow — 客户端文案词典(zh / en)。
|
|
623
|
+
*
|
|
624
|
+
* 机制:走宿主 `ctx.locale`(@deepseek-ai/dsh-client-locale),不自建 i18n:
|
|
625
|
+
* - `apply()` 里 `ctx.locale.register(NS, { zh, en })` 注册两个词典;
|
|
626
|
+
* - `ctx.locale.bind(NS)` 取翻译函数(调用时读当前语言,故可常驻模块变量);
|
|
627
|
+
* - slot 注册项声明 `locale: NS`,切语言时宿主重渲染每个 outlet
|
|
628
|
+
* (ui-renderer `useLocaleRevision`),面板/tab 名称用 thunk `() => t(...)`。
|
|
629
|
+
*
|
|
630
|
+
* 约定:
|
|
631
|
+
* - key 扁平点号命名,按区域前缀分组(common/status/phase/kind/role/stage/…);
|
|
632
|
+
* - 占位符用 `{name}`(宿主 `translate` 的替换语法);
|
|
633
|
+
* - **zh 与 en 的 key 集合必须完全一致**(en 是兜底语言,缺 key 会直接显示 key 本身;
|
|
634
|
+
* 由 test/smoke.js 断言守门);
|
|
635
|
+
* - 数据面文案(LLM 产出的标题/摘要、teams.json 的团队名、journal 里既有中文 label)不在此表,
|
|
636
|
+
* 属 host/产物语言层,见 AGENTS §5「客户端面」锚点。
|
|
637
|
+
*/
|
|
638
|
+
/** 词典命名空间(宿主 LocaleRuntime 的单占位命名空间)。 */
|
|
639
|
+
const NS = "teamflow";
|
|
640
|
+
/** 中文词典(key 为单一事实来源,en 必须与之同形)。 */
|
|
641
|
+
const zh = {
|
|
642
|
+
"common.close": "关闭",
|
|
643
|
+
"common.loading": "加载中…",
|
|
644
|
+
"common.retry": "重试",
|
|
645
|
+
"common.collapse": "收起",
|
|
646
|
+
"common.collapseFull": "收起全文",
|
|
647
|
+
"common.clickToExpand": "点击查看全文",
|
|
648
|
+
"common.expandFull": "展开全文",
|
|
649
|
+
"common.moreLines": "… +{n} 行",
|
|
650
|
+
"common.none": "无",
|
|
651
|
+
"common.noneDash": "(暂无)",
|
|
652
|
+
"common.noSummary": "(无摘要)",
|
|
653
|
+
"common.failed": "失败",
|
|
654
|
+
"common.running": "进行中",
|
|
655
|
+
"common.needsHuman": "需人工介入",
|
|
656
|
+
"common.unknownError": "未知错误",
|
|
657
|
+
"common.gotIt": "知道了",
|
|
658
|
+
"common.remoteNotReady": "remote 未就绪",
|
|
659
|
+
"common.remoteCallFailed": "{what} 调用失败:{detail}",
|
|
660
|
+
"common.remoteEmptyResult": "{what} 返回空结果(ok=true 但无 value;原始信封={raw})",
|
|
661
|
+
"common.calls": "{n} 次",
|
|
662
|
+
"common.callsCount": "{n} 次调用",
|
|
663
|
+
"common.noUsage": "无 token 数据",
|
|
664
|
+
"status.created": "立项",
|
|
665
|
+
"status.in-progress": "进行中",
|
|
666
|
+
"status.pending-acceptance": "待验收",
|
|
667
|
+
"status.accepted": "已验收",
|
|
668
|
+
"status.closed": "已关闭",
|
|
669
|
+
"status.pending": "待办",
|
|
670
|
+
"status.running": "开发中",
|
|
671
|
+
"status.testable": "待测试",
|
|
672
|
+
"status.testing": "测试中",
|
|
673
|
+
"status.rework": "打回",
|
|
674
|
+
"status.needs-human": "需人工",
|
|
675
|
+
"status.cancelled": "已关闭",
|
|
676
|
+
"status.open": "待认领",
|
|
677
|
+
"status.claimed": "处理中",
|
|
678
|
+
"status.fixed": "已修复待验",
|
|
679
|
+
"status.verified": "已关闭",
|
|
680
|
+
"status.reopened": "重开",
|
|
681
|
+
"status.done": "已完成",
|
|
682
|
+
"status.completed": "已完成",
|
|
683
|
+
"status.failed": "失败",
|
|
684
|
+
"status.interrupted": "已中断",
|
|
685
|
+
"status.superseded": "已取代",
|
|
686
|
+
"runStatus.pending": "等待中",
|
|
687
|
+
"runStatus.running": "进行中",
|
|
688
|
+
"runStatus.completed": "已完成",
|
|
689
|
+
"runStatus.failed": "失败",
|
|
690
|
+
"runStatus.cancelled": "已取消",
|
|
691
|
+
"runStatus.interrupted": "已中断",
|
|
692
|
+
"runStatus.superseded": "已取代",
|
|
693
|
+
"phase.prd": "PRD 产品需求",
|
|
694
|
+
"phase.design": "UI/UX 设计",
|
|
695
|
+
"phase.scaffold": "架构规划",
|
|
696
|
+
"phase.tech": "技术方案",
|
|
697
|
+
"phase.dev": "开发",
|
|
698
|
+
"phase.qa": "QA 测试",
|
|
699
|
+
"phase.acceptance": "产品验收",
|
|
700
|
+
"kind.req": "需求",
|
|
701
|
+
"kind.task": "任务",
|
|
702
|
+
"kind.bug": "缺陷",
|
|
703
|
+
"role.pm": "产品",
|
|
704
|
+
"role.design": "设计",
|
|
705
|
+
"role.arch": "架构",
|
|
706
|
+
"role.tech": "方案",
|
|
707
|
+
"role.dev": "开发",
|
|
708
|
+
"role.qa": "测试",
|
|
709
|
+
"role.acceptance": "验收",
|
|
710
|
+
"role.other": "其他",
|
|
711
|
+
"roleChip.pm": "📌 产品",
|
|
712
|
+
"roleChip.design": "🎨 设计",
|
|
713
|
+
"roleChip.arch": "🏗 架构",
|
|
714
|
+
"roleChip.tech": "📐 方案",
|
|
715
|
+
"roleChip.dev": "👨💻 开发",
|
|
716
|
+
"roleChip.qa": "🧪 QA",
|
|
717
|
+
"roleChip.acceptance": "✅ 验收",
|
|
718
|
+
"token.officialTitle": "TOKEN · 官方口径",
|
|
719
|
+
"token.usageLine": "输入(未命中) {input} / 输入(命中) {cacheRead} / 写缓存 {cacheWrite} / 输出 {output} · {calls} 次调用",
|
|
720
|
+
"token.usageHit": " · 缓存命中 {hit}%",
|
|
721
|
+
"token.usageMissing": "无 usage 明细",
|
|
722
|
+
"token.inputMiss": "输入(未命中) {v}",
|
|
723
|
+
"token.inputHit": "输入(命中) {v}",
|
|
724
|
+
"token.cacheWrite": "写缓存 {v}",
|
|
725
|
+
"token.output": "输出 {v}",
|
|
726
|
+
"token.total": "合计 {v}",
|
|
727
|
+
"token.allStagesTip": "输入(未命中)/输入(命中)/输出 全部阶段合计",
|
|
728
|
+
"token.stageLine": "阶段 token:{v}",
|
|
729
|
+
"stage.cardTip": "{label} —— 点击查看阶段详情",
|
|
730
|
+
"stage.retryTip": "重试 {n} 次(共 {m} 次尝试)",
|
|
731
|
+
"stage.detailTitle": "阶段详情",
|
|
732
|
+
"stage.summaryFallback": "(该 run 未保存完整正文,展示摘要)\n\n{summary}",
|
|
733
|
+
"stage.loadFailed": "⚠ 加载失败:{err}",
|
|
734
|
+
"stage.noOutput": "(无产物正文)",
|
|
735
|
+
"stage.attemptHistory": "↻ 尝试历史({n} 次 · 点击查看该次详情)",
|
|
736
|
+
"stage.attemptDone": "✅ 成功",
|
|
737
|
+
"stage.attemptFailed": "❌ {outcome}",
|
|
738
|
+
"stage.attemptRunning": "⏳ 进行中",
|
|
739
|
+
"stage.childJumpBtn": "🎬 跳转子代理会话",
|
|
740
|
+
"stage.childJumpTip": "跳转到该阶段子代理会话(完整推理与工具调用轨迹);跳转后请切换「对话」tab 查看",
|
|
741
|
+
"stage.childNoneTip": "该阶段无可用子代理会话",
|
|
742
|
+
"stage.childCrossSessionTip": "该子代理由会话 {sid} 发起,跨会话跳转暂不支持——请打开其发起会话的团队工作台查看",
|
|
743
|
+
"stage.childCrossSessionNote": "跨会话暂不支持:该子代理由会话 {sid} 发起。如需查看轨迹,请打开其发起会话的团队工作台。",
|
|
744
|
+
"stage.childJumpNote": "跳转成功后,请切「对话」tab 查看该子代理的完整会话轨迹",
|
|
745
|
+
"stage.evidenceTitle": "🔬 验证证据",
|
|
746
|
+
"stage.evidenceMissing": "(缺失——契约未兑现,host 已记警告;可与该 run 的命令日志对照:run 期间在 logs/teamflow/<runId>/,结束后由 host 归档到 $DSH_HOME/teamflow/<workspace>/logs/<runId>/)",
|
|
747
|
+
"stage.evidenceMissingShort": "(缺失——契约未兑现,host 已记警告)",
|
|
748
|
+
"stage.artifactsTitle": "📄 阶段性产物",
|
|
749
|
+
"pipeline.empty": "暂无运行中的流水线——让模型调用 teamflow_start,或在上方输入需求",
|
|
750
|
+
"pipeline.noNodes": "流水线还没有开始执行节点",
|
|
751
|
+
"pipeline.zoomOut": "缩小",
|
|
752
|
+
"pipeline.zoomIn": "放大",
|
|
753
|
+
"pipeline.fitCanvas": "适应画布",
|
|
754
|
+
"pipeline.canvasHint": "✥ 拖动画布 · 滚轮缩放",
|
|
755
|
+
"workbench.title": "团队工作台",
|
|
756
|
+
"workbench.running": "流水线运行中",
|
|
757
|
+
"workbench.idle": "空闲",
|
|
758
|
+
"workbench.refresh": "🔄 刷新",
|
|
759
|
+
"workbench.resumeTip": "断点续跑 {id}\n当前状态:{status};跳过已完成阶段,从第一个未完成阶段重跑",
|
|
760
|
+
"workbench.resuming": "续跑中…",
|
|
761
|
+
"workbench.resumeBtn": "↻ 从断点重跑 #{id}",
|
|
762
|
+
"workbench.loadFailed": "⚠ {err}(确认已安装 dsh-plugin-teamflow 且 web 已重启)",
|
|
763
|
+
"workbench.needsHumanBanner": "⚠ {n} 项需人工介入",
|
|
764
|
+
"workbench.handle": "处理 {id}",
|
|
765
|
+
"workbench.manualReason": "人工处理",
|
|
766
|
+
"workbench.tabPipeline": "🔄 流水线",
|
|
767
|
+
"workbench.tabBoard": "📋 Backlog 看板",
|
|
768
|
+
"workbench.workspaceTip": "当前工作区(workspace 级隔离):{path}",
|
|
769
|
+
"workbench.noWorkspace": "未连接工作区",
|
|
770
|
+
"workbench.history": "历史",
|
|
771
|
+
"workbench.openRightBarTip": "在右侧栏打开该 run 详情(与任务夹产物并排看)",
|
|
772
|
+
"workbench.openRightBarBtn": "⇥ 右栏打开",
|
|
773
|
+
"board.empty": "backlog 为空(还没有流水线运行过)",
|
|
774
|
+
"board.dragReason": "看板拖拽流转",
|
|
775
|
+
"board.cardTip": "{id} · {status}{summary}(点击查看详情)",
|
|
776
|
+
"board.assignDevTip": "dev 分配\n{who}",
|
|
777
|
+
"board.assignQaTip": "qa 分配\n{who}",
|
|
778
|
+
"board.acceptTip": "验收/汇报人\n{who}",
|
|
779
|
+
"board.subtaskCount": "📦 {n} 子卡",
|
|
780
|
+
"board.retries": "重试 {n}",
|
|
781
|
+
"item.overview": "概览",
|
|
782
|
+
"item.acceptRow": "✅ 验收",
|
|
783
|
+
"item.retryRow": "↻ 重试",
|
|
784
|
+
"item.humanRow": "⚠ 人工介入",
|
|
785
|
+
"item.updatedAt": "更新于",
|
|
786
|
+
"item.runSection": "运行",
|
|
787
|
+
"item.runBtn": "▶ 流水线",
|
|
788
|
+
"item.jumpRunTip": "跳转到该需求的流水线视图 #{id}",
|
|
789
|
+
"item.requirement": "需求原文",
|
|
790
|
+
"item.noRequirement": "(无原文)",
|
|
791
|
+
"item.runDocs": "任务夹",
|
|
792
|
+
"item.previewTip": "在右侧栏预览 {path}",
|
|
793
|
+
"item.subtasks": "关联子卡({n})",
|
|
794
|
+
"item.bugs": "关联缺陷({n})",
|
|
795
|
+
"item.timeline": "流转时间线({n})",
|
|
796
|
+
"team.currentTip": "当前团队:{name}(点击切换)",
|
|
797
|
+
"team.pick": "选择团队",
|
|
798
|
+
"team.label": "团队",
|
|
799
|
+
"team.none": "无团队(直接对话)",
|
|
800
|
+
"team.noneNote": "不走 teamflow,模型直接工作",
|
|
801
|
+
"panel.title": "🏭 团队工作台",
|
|
802
|
+
"panel.subtitle": "全局面板 · 按产品线",
|
|
803
|
+
"panel.currentSession": "当前会话 {sid}",
|
|
804
|
+
"panel.noSession": "无当前会话",
|
|
805
|
+
"panel.reload": "刷新数据",
|
|
806
|
+
"panel.backToChat": "回到对话",
|
|
807
|
+
"panel.backToChatTip": "回到对话(再点侧边栏图标即可切回本面板)",
|
|
808
|
+
"panel.railTitle": "产品线 · {n}",
|
|
809
|
+
"panel.rescanTip": "重新扫描 $DSH_HOME/teamflow",
|
|
810
|
+
"panel.refreshing": "刷新中",
|
|
811
|
+
"panel.refresh": "刷新",
|
|
812
|
+
"panel.noProducts": "还没有产品线。在某个工作区跑过一次流水线后,这里会出现对应产品线($DSH_HOME/teamflow/<key>)。",
|
|
813
|
+
"panel.activeRuns": "运行 {n}",
|
|
814
|
+
"panel.updated": "更新 {time}",
|
|
815
|
+
"panel.reading": "读取中…",
|
|
816
|
+
"panel.verdict": "验收 {v}",
|
|
817
|
+
"panel.pickProduct": "选择左侧产品线查看 backlog 与 run(首次进入默认选最近更新的产品线)。",
|
|
818
|
+
"panel.loadingView": "读取产品线数据中…",
|
|
819
|
+
"panel.runChip": "run {n}",
|
|
820
|
+
"panel.activeChip": "活跃 {n}",
|
|
821
|
+
"panel.verdictChip": "验收 {v}",
|
|
822
|
+
"panel.tabRuns": "🚀 流水线 run · {n}",
|
|
823
|
+
"panel.tabBacklog": "📋 Backlog · {n}",
|
|
824
|
+
"panel.pinnedActive": "已置顶进行中 {n}",
|
|
825
|
+
"panel.showRecent": "只看最近 {n} 条",
|
|
826
|
+
"panel.showAll": "展开全部 {n} 条",
|
|
827
|
+
"panel.clearRunFilterTip": "清除 run 状态筛选",
|
|
828
|
+
"panel.filtered": "筛选中 {sel} 项 · 显示 {shown}/{total} × 清除",
|
|
829
|
+
"panel.emptyRunFilter": "该筛选下没有 run。",
|
|
830
|
+
"panel.runHint": "点一行看详情浮层;「去会话右栏」= 跳到该 run 的发起会话并在其右侧栏打开(与任务夹产物并排)",
|
|
831
|
+
"panel.boardHint": "点状态徽章可筛选(多选);终态卡片默认收起,筛选时自动显示",
|
|
832
|
+
"panel.runDetail": "run 详情",
|
|
833
|
+
"panel.goOwnerSession": "去发起会话",
|
|
834
|
+
"panel.goOwnerSessionTip": "跳到该 run 的发起会话,并在那个会话的右侧栏打开(与任务夹产物并排看)",
|
|
835
|
+
"panel.remoteProductsUnavailable": "remote.products 不可用(插件未挂载或版本过旧)",
|
|
836
|
+
"panel.hintNoAddress": "{label}:host 未生成可打开的地址(可能缺少会话上下文)",
|
|
837
|
+
"panel.hintRightbarFailed": "右侧栏打开失败(宿主只在对话视图挂载它):{label}——已在本面板内联显示",
|
|
838
|
+
"panel.hintSessionGone": "发起会话 {sid}… 不在会话列表里(可能已被清理)——已在本面板展示详情",
|
|
839
|
+
"panel.hintSwitchedNoRightbar": "已切到发起会话,但右栏没打开({label})——可在该会话里用「⇥ 右栏打开」重试",
|
|
840
|
+
"panel.hintInlineSuffix": "——已在本面板内联显示",
|
|
841
|
+
"runList.empty": "该产品线还没有 run 记录。",
|
|
842
|
+
"runList.running": "进行中",
|
|
843
|
+
"runList.noRequirement": "(无需求描述)",
|
|
844
|
+
"runList.stageProgress": "阶段 {done}/{total}",
|
|
845
|
+
"runList.openRightBar": "去会话右栏",
|
|
846
|
+
"runList.openRightBarTip": "跳到该 run 的发起会话,并在那个会话的右侧栏打开详情(右侧栏是会话级的:挂到无关会话上没有意义)",
|
|
847
|
+
"runList.callsSuffix": " · {n} 次",
|
|
848
|
+
"panelBoard.empty": "backlog 为空(该产品线还没有立项卡片)。",
|
|
849
|
+
"panelBoard.groupCount": "{kind} · {n}",
|
|
850
|
+
"panelBoard.activeCount": "活动 {n}",
|
|
851
|
+
"panelBoard.clearFilterTip": "清除本组筛选",
|
|
852
|
+
"panelBoard.collapseDone": "收起已完成 {n}",
|
|
853
|
+
"panelBoard.expandDone": "已完成 {n} ▸",
|
|
854
|
+
"panelBoard.collapseDoneTip": "收起已完成/已关闭卡片",
|
|
855
|
+
"panelBoard.expandDoneTip": "展开已完成/已关闭卡片",
|
|
856
|
+
"panelBoard.emptyFiltered": "该筛选下没有卡片。",
|
|
857
|
+
"panelBoard.filterChipOn": "点击取消该状态筛选",
|
|
858
|
+
"panelBoard.filterChipOff": "点击只看该状态(可多选)",
|
|
859
|
+
"panelItem.row.req": "需求",
|
|
860
|
+
"panelItem.row.owner": "负责人",
|
|
861
|
+
"panelItem.row.dev": "开发",
|
|
862
|
+
"panelItem.row.qa": "测试",
|
|
863
|
+
"panelItem.row.accept": "验收",
|
|
864
|
+
"panelItem.row.retries": "重试",
|
|
865
|
+
"panelItem.row.runDocs": "任务夹",
|
|
866
|
+
"panelItem.defectSection": "缺陷详情(QA 报告导入)",
|
|
867
|
+
"panelItem.row.defectId": "缺陷编号",
|
|
868
|
+
"panelItem.row.severity": "严重级",
|
|
869
|
+
"panelItem.row.module": "功能模块",
|
|
870
|
+
"panelItem.row.reproduce": "复现步骤",
|
|
871
|
+
"panelItem.row.expected": "期望行为",
|
|
872
|
+
"panelItem.row.actual": "实际行为",
|
|
873
|
+
"panelItem.row.defectAc": "关联验收项",
|
|
874
|
+
"panelItem.row.defectCheck": "检测命令",
|
|
875
|
+
"panelItem.row.defectCriterion": "通过判据",
|
|
876
|
+
"panelItem.noDefectDetail": "(该卡无缺陷描述:登记时 QA 报告只给了三要素,或为旧版本登记的卡;细节见关联 run 的 QA-REPORT.md)",
|
|
877
|
+
"panelItem.spec": "规格",
|
|
878
|
+
"panelItem.summary": "结论摘要",
|
|
879
|
+
"panelItem.artifacts": "任务夹产物 · {n}",
|
|
880
|
+
"panelItem.artifactTip": "{address}\n(跳到产物所属会话后在该会话右侧栏打开)",
|
|
881
|
+
"panelItem.noArtifacts": "该条目没有可预览的任务夹产物(或缺少会话上下文,无法生成文件地址)。",
|
|
882
|
+
"panelItem.subtasks": "子卡 · {n}",
|
|
883
|
+
"panelItem.bugs": "关联缺陷 · {n}",
|
|
884
|
+
"panelItem.events": "流转时间线 · 最近 {n} 条",
|
|
885
|
+
"detail.runMissing": "未找到该 run(可能已被清理,或地址已过期)。",
|
|
886
|
+
"detail.subagents": "子代理 {n}",
|
|
887
|
+
"detail.stages": "阶段 · {n}",
|
|
888
|
+
"detail.stageFailed": "阶段详情读取失败:{err}",
|
|
889
|
+
"detail.stageTitle": "阶段 #{seq} 详情",
|
|
890
|
+
"detail.output": "阶段产出",
|
|
891
|
+
"detail.attempts": "同任务尝试 · {n}",
|
|
892
|
+
"detail.logs": "日志 · 最近 {n} 条",
|
|
893
|
+
"detail.endedRunning": "进行中",
|
|
894
|
+
"detail.subagentChip": "子代理 {id}",
|
|
895
|
+
"tab.resolveFailed": "无法解析 run 地址:{address}",
|
|
896
|
+
"tab.readingAddress": "读取 tab 地址中…",
|
|
897
|
+
"tab.noHook": "宿主 tab 信息钩子不可用(useTabInfo 缺失)",
|
|
898
|
+
"tab.remoteUnavailable": "remote 不可用(插件未挂载或版本过旧)",
|
|
899
|
+
"tab.readingRun": "读取 run 详情中…"
|
|
900
|
+
};
|
|
901
|
+
/** 英文词典(key 集合必须与 zh 完全一致)。 */
|
|
902
|
+
const en = {
|
|
903
|
+
"common.close": "Close",
|
|
904
|
+
"common.loading": "Loading…",
|
|
905
|
+
"common.retry": "Retry",
|
|
906
|
+
"common.collapse": "Collapse",
|
|
907
|
+
"common.collapseFull": "Collapse",
|
|
908
|
+
"common.clickToExpand": "Click to expand",
|
|
909
|
+
"common.expandFull": "Show more",
|
|
910
|
+
"common.moreLines": "… +{n} lines",
|
|
911
|
+
"common.none": "none",
|
|
912
|
+
"common.noneDash": "(none)",
|
|
913
|
+
"common.noSummary": "(no summary)",
|
|
914
|
+
"common.failed": "Failed",
|
|
915
|
+
"common.running": "Running",
|
|
916
|
+
"common.needsHuman": "needs human intervention",
|
|
917
|
+
"common.unknownError": "unknown error",
|
|
918
|
+
"common.gotIt": "Got it",
|
|
919
|
+
"common.remoteNotReady": "remote not ready",
|
|
920
|
+
"common.remoteCallFailed": "{what} call failed: {detail}",
|
|
921
|
+
"common.remoteEmptyResult": "{what} returned an empty result (ok=true but no value; raw envelope={raw})",
|
|
922
|
+
"common.calls": "{n} calls",
|
|
923
|
+
"common.callsCount": "{n} calls",
|
|
924
|
+
"common.noUsage": "no token data",
|
|
925
|
+
"status.created": "Created",
|
|
926
|
+
"status.in-progress": "In progress",
|
|
927
|
+
"status.pending-acceptance": "Pending acceptance",
|
|
928
|
+
"status.accepted": "Accepted",
|
|
929
|
+
"status.closed": "Closed",
|
|
930
|
+
"status.pending": "Todo",
|
|
931
|
+
"status.running": "Developing",
|
|
932
|
+
"status.testable": "Ready for test",
|
|
933
|
+
"status.testing": "Testing",
|
|
934
|
+
"status.rework": "Rework",
|
|
935
|
+
"status.needs-human": "Needs human",
|
|
936
|
+
"status.cancelled": "Closed",
|
|
937
|
+
"status.open": "Unclaimed",
|
|
938
|
+
"status.claimed": "In progress",
|
|
939
|
+
"status.fixed": "Fixed (pending verify)",
|
|
940
|
+
"status.verified": "Closed",
|
|
941
|
+
"status.reopened": "Reopened",
|
|
942
|
+
"status.done": "Done",
|
|
943
|
+
"status.completed": "Completed",
|
|
944
|
+
"status.failed": "Failed",
|
|
945
|
+
"status.interrupted": "Interrupted",
|
|
946
|
+
"status.superseded": "Superseded",
|
|
947
|
+
"runStatus.pending": "Queued",
|
|
948
|
+
"runStatus.running": "Running",
|
|
949
|
+
"runStatus.completed": "Completed",
|
|
950
|
+
"runStatus.failed": "Failed",
|
|
951
|
+
"runStatus.cancelled": "Cancelled",
|
|
952
|
+
"runStatus.interrupted": "Interrupted",
|
|
953
|
+
"runStatus.superseded": "Superseded",
|
|
954
|
+
"phase.prd": "PRD",
|
|
955
|
+
"phase.design": "UI/UX design",
|
|
956
|
+
"phase.scaffold": "Architecture",
|
|
957
|
+
"phase.tech": "Technical design",
|
|
958
|
+
"phase.dev": "Development",
|
|
959
|
+
"phase.qa": "QA testing",
|
|
960
|
+
"phase.acceptance": "Acceptance",
|
|
961
|
+
"kind.req": "Requirements",
|
|
962
|
+
"kind.task": "Tasks",
|
|
963
|
+
"kind.bug": "Defects",
|
|
964
|
+
"role.pm": "Product",
|
|
965
|
+
"role.design": "Design",
|
|
966
|
+
"role.arch": "Architecture",
|
|
967
|
+
"role.tech": "Tech design",
|
|
968
|
+
"role.dev": "Dev",
|
|
969
|
+
"role.qa": "QA",
|
|
970
|
+
"role.acceptance": "Acceptance",
|
|
971
|
+
"role.other": "Other",
|
|
972
|
+
"roleChip.pm": "📌 Product",
|
|
973
|
+
"roleChip.design": "🎨 Design",
|
|
974
|
+
"roleChip.arch": "🏗 Architecture",
|
|
975
|
+
"roleChip.tech": "📐 Tech design",
|
|
976
|
+
"roleChip.dev": "👨💻 Dev",
|
|
977
|
+
"roleChip.qa": "🧪 QA",
|
|
978
|
+
"roleChip.acceptance": "✅ Acceptance",
|
|
979
|
+
"token.officialTitle": "TOKEN · official metering",
|
|
980
|
+
"token.usageLine": "Input (miss) {input} / Input (hit) {cacheRead} / Cache write {cacheWrite} / Output {output} · {calls} calls",
|
|
981
|
+
"token.usageHit": " · cache hit {hit}%",
|
|
982
|
+
"token.usageMissing": "no usage detail",
|
|
983
|
+
"token.inputMiss": "Input (miss) {v}",
|
|
984
|
+
"token.inputHit": "Input (hit) {v}",
|
|
985
|
+
"token.cacheWrite": "Cache write {v}",
|
|
986
|
+
"token.output": "Output {v}",
|
|
987
|
+
"token.total": "Total {v}",
|
|
988
|
+
"token.allStagesTip": "Input (miss) / Input (hit) / Output totals across all stages",
|
|
989
|
+
"token.stageLine": "Stage tokens: {v}",
|
|
990
|
+
"stage.cardTip": "{label} — click for stage detail",
|
|
991
|
+
"stage.retryTip": "Retried {n}× ({m} attempts in total)",
|
|
992
|
+
"stage.detailTitle": "Stage detail",
|
|
993
|
+
"stage.summaryFallback": "(Full text was not saved for this run — showing the summary)\n\n{summary}",
|
|
994
|
+
"stage.loadFailed": "⚠ Load failed: {err}",
|
|
995
|
+
"stage.noOutput": "(no output text)",
|
|
996
|
+
"stage.attemptHistory": "↻ Attempt history ({n} · click to inspect one)",
|
|
997
|
+
"stage.attemptDone": "✅ OK",
|
|
998
|
+
"stage.attemptFailed": "❌ {outcome}",
|
|
999
|
+
"stage.attemptRunning": "⏳ Running",
|
|
1000
|
+
"stage.childJumpBtn": "🎬 Open subagent session",
|
|
1001
|
+
"stage.childJumpTip": "Open this stage's subagent session (full reasoning and tool-call trail); then switch to the \"Chat\" tab",
|
|
1002
|
+
"stage.childNoneTip": "No subagent session is available for this stage",
|
|
1003
|
+
"stage.childCrossSessionTip": "This subagent was started by session {sid}; cross-session navigation is not supported yet — open the Team Workbench in its originating session",
|
|
1004
|
+
"stage.childCrossSessionNote": "Cross-session navigation is not supported yet: this subagent was started by session {sid}. Open the Team Workbench in its originating session to see the trail.",
|
|
1005
|
+
"stage.childJumpNote": "After jumping, switch to the \"Chat\" tab to see this subagent's full session trail",
|
|
1006
|
+
"stage.evidenceTitle": "🔬 Verification evidence",
|
|
1007
|
+
"stage.evidenceMissing": "(missing — the contract was not honored and the host logged a warning; cross-check with this run's command logs: logs/teamflow/<runId>/ while the run is live, archived by the host to $DSH_HOME/teamflow/<workspace>/logs/<runId>/ afterwards)",
|
|
1008
|
+
"stage.evidenceMissingShort": "(missing — the contract was not honored and the host logged a warning)",
|
|
1009
|
+
"stage.artifactsTitle": "📄 Stage artifacts",
|
|
1010
|
+
"pipeline.empty": "No active pipeline — ask the model to call teamflow_start, or type a requirement above",
|
|
1011
|
+
"pipeline.noNodes": "The pipeline has not started any stage node yet",
|
|
1012
|
+
"pipeline.zoomOut": "Zoom out",
|
|
1013
|
+
"pipeline.zoomIn": "Zoom in",
|
|
1014
|
+
"pipeline.fitCanvas": "Fit canvas",
|
|
1015
|
+
"pipeline.canvasHint": "✥ Drag to pan · scroll to zoom",
|
|
1016
|
+
"workbench.title": "Team Workbench",
|
|
1017
|
+
"workbench.running": "Pipeline running",
|
|
1018
|
+
"workbench.idle": "Idle",
|
|
1019
|
+
"workbench.refresh": "🔄 Refresh",
|
|
1020
|
+
"workbench.resumeTip": "Resume {id}\nCurrent status: {status}; completed stages are skipped and the run restarts from the first unfinished stage",
|
|
1021
|
+
"workbench.resuming": "Resuming…",
|
|
1022
|
+
"workbench.resumeBtn": "↻ Resume from #{id}",
|
|
1023
|
+
"workbench.loadFailed": "⚠ {err} (make sure dsh-plugin-teamflow is installed and the web host was restarted)",
|
|
1024
|
+
"workbench.needsHumanBanner": "⚠ {n} item(s) need human intervention",
|
|
1025
|
+
"workbench.handle": "Handle {id}",
|
|
1026
|
+
"workbench.manualReason": "manual handling",
|
|
1027
|
+
"workbench.tabPipeline": "🔄 Pipeline",
|
|
1028
|
+
"workbench.tabBoard": "📋 Backlog board",
|
|
1029
|
+
"workbench.workspaceTip": "Current workspace (workspace-level isolation): {path}",
|
|
1030
|
+
"workbench.noWorkspace": "no workspace connected",
|
|
1031
|
+
"workbench.history": "History",
|
|
1032
|
+
"workbench.openRightBarTip": "Open this run's detail in the right sidebar (side by side with task-folder artifacts)",
|
|
1033
|
+
"workbench.openRightBarBtn": "⇥ Open in right bar",
|
|
1034
|
+
"board.empty": "Backlog is empty (no pipeline has run yet)",
|
|
1035
|
+
"board.dragReason": "kanban drag transition",
|
|
1036
|
+
"board.cardTip": "{id} · {status}{summary} (click for details)",
|
|
1037
|
+
"board.assignDevTip": "dev assignee\n{who}",
|
|
1038
|
+
"board.assignQaTip": "qa assignee\n{who}",
|
|
1039
|
+
"board.acceptTip": "acceptance/report owner\n{who}",
|
|
1040
|
+
"board.subtaskCount": "📦 {n} subtasks",
|
|
1041
|
+
"board.retries": "retries {n}",
|
|
1042
|
+
"item.overview": "Overview",
|
|
1043
|
+
"item.acceptRow": "✅ Acceptance",
|
|
1044
|
+
"item.retryRow": "↻ Retries",
|
|
1045
|
+
"item.humanRow": "⚠ Human intervention",
|
|
1046
|
+
"item.updatedAt": "Updated",
|
|
1047
|
+
"item.runSection": "Run",
|
|
1048
|
+
"item.runBtn": "▶ Pipeline",
|
|
1049
|
+
"item.jumpRunTip": "Open this requirement's pipeline view #{id}",
|
|
1050
|
+
"item.requirement": "Raw requirement",
|
|
1051
|
+
"item.noRequirement": "(no raw text)",
|
|
1052
|
+
"item.runDocs": "Task folder",
|
|
1053
|
+
"item.previewTip": "Preview {path} in the right sidebar",
|
|
1054
|
+
"item.subtasks": "Linked subtasks ({n})",
|
|
1055
|
+
"item.bugs": "Linked defects ({n})",
|
|
1056
|
+
"item.timeline": "Transition timeline ({n})",
|
|
1057
|
+
"team.currentTip": "Current team: {name} (click to switch)",
|
|
1058
|
+
"team.pick": "Select team",
|
|
1059
|
+
"team.label": "Team",
|
|
1060
|
+
"team.none": "No team (chat directly)",
|
|
1061
|
+
"team.noneNote": "teamflow is not used; the model works directly",
|
|
1062
|
+
"panel.title": "🏭 Team Workbench",
|
|
1063
|
+
"panel.subtitle": "Global panel · by product line",
|
|
1064
|
+
"panel.currentSession": "Session {sid}",
|
|
1065
|
+
"panel.noSession": "No active session",
|
|
1066
|
+
"panel.reload": "Reload data",
|
|
1067
|
+
"panel.backToChat": "Back to chat",
|
|
1068
|
+
"panel.backToChatTip": "Back to chat (click the sidebar icon again to return to this panel)",
|
|
1069
|
+
"panel.railTitle": "Product lines · {n}",
|
|
1070
|
+
"panel.rescanTip": "Rescan $DSH_HOME/teamflow",
|
|
1071
|
+
"panel.refreshing": "Refreshing",
|
|
1072
|
+
"panel.refresh": "Refresh",
|
|
1073
|
+
"panel.noProducts": "No product lines yet. Once a pipeline has run in a workspace, its product line shows up here ($DSH_HOME/teamflow/<key>).",
|
|
1074
|
+
"panel.activeRuns": "{n} running",
|
|
1075
|
+
"panel.updated": "updated {time}",
|
|
1076
|
+
"panel.reading": "Loading…",
|
|
1077
|
+
"panel.verdict": "acceptance {v}",
|
|
1078
|
+
"panel.pickProduct": "Pick a product line on the left to see its backlog and runs (the most recently updated one is selected on first entry).",
|
|
1079
|
+
"panel.loadingView": "Loading product-line data…",
|
|
1080
|
+
"panel.runChip": "runs {n}",
|
|
1081
|
+
"panel.activeChip": "active {n}",
|
|
1082
|
+
"panel.verdictChip": "acceptance {v}",
|
|
1083
|
+
"panel.tabRuns": "🚀 Pipeline runs · {n}",
|
|
1084
|
+
"panel.tabBacklog": "📋 Backlog · {n}",
|
|
1085
|
+
"panel.pinnedActive": "{n} running pinned",
|
|
1086
|
+
"panel.showRecent": "Show latest {n}",
|
|
1087
|
+
"panel.showAll": "Show all {n}",
|
|
1088
|
+
"panel.clearRunFilterTip": "Clear the run status filter",
|
|
1089
|
+
"panel.filtered": "Filtered {sel} · showing {shown}/{total} × clear",
|
|
1090
|
+
"panel.emptyRunFilter": "No runs match this filter.",
|
|
1091
|
+
"panel.runHint": "Click a row for the detail overlay; \"Open in session right bar\" jumps to the run's originating session and opens the right bar there (side by side with task-folder artifacts)",
|
|
1092
|
+
"panel.boardHint": "Click a status badge to filter (multi-select); terminal cards are collapsed by default and appear automatically while filtering",
|
|
1093
|
+
"panel.runDetail": "Run detail",
|
|
1094
|
+
"panel.goOwnerSession": "Go to originating session",
|
|
1095
|
+
"panel.goOwnerSessionTip": "Jump to the run's originating session and open its right bar there (side by side with task-folder artifacts)",
|
|
1096
|
+
"panel.remoteProductsUnavailable": "remote.products unavailable (plugin not mounted or outdated)",
|
|
1097
|
+
"panel.hintNoAddress": "{label}: the host produced no openable address (session context may be missing)",
|
|
1098
|
+
"panel.hintRightbarFailed": "Failed to open the right sidebar (the host mounts it only in the chat view): {label} — shown inline in this panel instead",
|
|
1099
|
+
"panel.hintSessionGone": "Originating session {sid}… is not in the session list (it may have been cleaned up) — showing the detail in this panel",
|
|
1100
|
+
"panel.hintSwitchedNoRightbar": "Switched to the originating session but the right bar did not open ({label}) — retry with \"⇥ Open in right bar\" in that session",
|
|
1101
|
+
"panel.hintInlineSuffix": " — shown inline in this panel instead",
|
|
1102
|
+
"runList.empty": "No runs recorded for this product line yet.",
|
|
1103
|
+
"runList.running": "Running",
|
|
1104
|
+
"runList.noRequirement": "(no requirement text)",
|
|
1105
|
+
"runList.stageProgress": "Stages {done}/{total}",
|
|
1106
|
+
"runList.openRightBar": "Open in session right bar",
|
|
1107
|
+
"runList.openRightBarTip": "Jump to the run's originating session and open the detail in that session's right bar (the right bar is session-scoped: attaching it to an unrelated session is meaningless)",
|
|
1108
|
+
"runList.callsSuffix": " · {n} calls",
|
|
1109
|
+
"panelBoard.empty": "Backlog is empty (this product line has no cards yet).",
|
|
1110
|
+
"panelBoard.groupCount": "{kind} · {n}",
|
|
1111
|
+
"panelBoard.activeCount": "Active {n}",
|
|
1112
|
+
"panelBoard.clearFilterTip": "Clear this group's filter",
|
|
1113
|
+
"panelBoard.collapseDone": "Hide {n} done",
|
|
1114
|
+
"panelBoard.expandDone": "{n} done ▸",
|
|
1115
|
+
"panelBoard.collapseDoneTip": "Hide done/closed cards",
|
|
1116
|
+
"panelBoard.expandDoneTip": "Show done/closed cards",
|
|
1117
|
+
"panelBoard.emptyFiltered": "No cards match this filter.",
|
|
1118
|
+
"panelBoard.filterChipOn": "Click to clear this status filter",
|
|
1119
|
+
"panelBoard.filterChipOff": "Click to filter by this status only (multi-select)",
|
|
1120
|
+
"panelItem.row.req": "Requirement",
|
|
1121
|
+
"panelItem.row.owner": "Owner",
|
|
1122
|
+
"panelItem.row.dev": "Dev",
|
|
1123
|
+
"panelItem.row.qa": "QA",
|
|
1124
|
+
"panelItem.row.accept": "Acceptance",
|
|
1125
|
+
"panelItem.row.retries": "Retries",
|
|
1126
|
+
"panelItem.row.runDocs": "Task folder",
|
|
1127
|
+
"panelItem.defectSection": "Defect detail (imported from the QA report)",
|
|
1128
|
+
"panelItem.row.defectId": "Defect id",
|
|
1129
|
+
"panelItem.row.severity": "Severity",
|
|
1130
|
+
"panelItem.row.module": "Module",
|
|
1131
|
+
"panelItem.row.reproduce": "Steps to reproduce",
|
|
1132
|
+
"panelItem.row.expected": "Expected",
|
|
1133
|
+
"panelItem.row.actual": "Actual",
|
|
1134
|
+
"panelItem.row.defectAc": "Related AC",
|
|
1135
|
+
"panelItem.row.defectCheck": "Check command",
|
|
1136
|
+
"panelItem.row.defectCriterion": "Pass criterion",
|
|
1137
|
+
"panelItem.noDefectDetail": "(No defect description on this card: the QA report only carried the three key fields when it was registered, or the card predates this version; see QA-REPORT.md in the linked run)",
|
|
1138
|
+
"panelItem.spec": "Spec",
|
|
1139
|
+
"panelItem.summary": "Summary",
|
|
1140
|
+
"panelItem.artifacts": "Task-folder artifacts · {n}",
|
|
1141
|
+
"panelItem.artifactTip": "{address}\n(opens in the right sidebar of the session that owns this artifact)",
|
|
1142
|
+
"panelItem.noArtifacts": "This item has no previewable task-folder artifacts (or no session context to build a file address).",
|
|
1143
|
+
"panelItem.subtasks": "Subtasks · {n}",
|
|
1144
|
+
"panelItem.bugs": "Linked defects · {n}",
|
|
1145
|
+
"panelItem.events": "Transition timeline · last {n}",
|
|
1146
|
+
"detail.runMissing": "Run not found (it may have been cleaned up, or the address is stale).",
|
|
1147
|
+
"detail.subagents": "Subagents {n}",
|
|
1148
|
+
"detail.stages": "Stages · {n}",
|
|
1149
|
+
"detail.stageFailed": "Failed to load stage detail: {err}",
|
|
1150
|
+
"detail.stageTitle": "Stage #{seq} detail",
|
|
1151
|
+
"detail.output": "Stage output",
|
|
1152
|
+
"detail.attempts": "Attempts for this task · {n}",
|
|
1153
|
+
"detail.logs": "Logs · last {n}",
|
|
1154
|
+
"detail.endedRunning": "running",
|
|
1155
|
+
"detail.subagentChip": "Subagent {id}",
|
|
1156
|
+
"tab.resolveFailed": "Cannot parse the run address: {address}",
|
|
1157
|
+
"tab.readingAddress": "Reading the tab address…",
|
|
1158
|
+
"tab.noHook": "Host tab-info hook unavailable (useTabInfo missing)",
|
|
1159
|
+
"tab.remoteUnavailable": "remote unavailable (plugin not mounted or outdated)",
|
|
1160
|
+
"tab.readingRun": "Loading run detail…"
|
|
1161
|
+
};
|
|
1162
|
+
//#endregion
|
|
604
1163
|
//#region client/panel.tsx
|
|
605
1164
|
/**
|
|
606
1165
|
* dsh-plugin-teamflow — 全局面板 + 右栏 run 详情 tab(v0.1.8 ①)。
|
|
@@ -649,14 +1208,17 @@ window.__ModuleLoader__.load({
|
|
|
649
1208
|
* 此时不能静默返回 undefined(调用方会把它再包成「未知错误」,丢掉定位信息),故显式报出原始信封。 */
|
|
650
1209
|
function unwrap$1(res, what) {
|
|
651
1210
|
if (!res || !res.ok) {
|
|
652
|
-
let detail = "
|
|
1211
|
+
let detail = t("common.unknownError");
|
|
653
1212
|
try {
|
|
654
|
-
detail = res && res.error && (res.error.message || res.error.code) || JSON.stringify(res) || "
|
|
1213
|
+
detail = res && res.error && (res.error.message || res.error.code) || JSON.stringify(res) || t("common.unknownError");
|
|
655
1214
|
} catch (e) {}
|
|
656
1215
|
try {
|
|
657
1216
|
console.warn("[teamflow] remote 调用失败", what, res);
|
|
658
1217
|
} catch (e) {}
|
|
659
|
-
throw new Error(
|
|
1218
|
+
throw new Error(t("common.remoteCallFailed", {
|
|
1219
|
+
what: what || "remote",
|
|
1220
|
+
detail
|
|
1221
|
+
}));
|
|
660
1222
|
}
|
|
661
1223
|
if (res.value === void 0) {
|
|
662
1224
|
try {
|
|
@@ -668,7 +1230,10 @@ window.__ModuleLoader__.load({
|
|
|
668
1230
|
} catch (e) {
|
|
669
1231
|
raw = String(res);
|
|
670
1232
|
}
|
|
671
|
-
throw new Error(
|
|
1233
|
+
throw new Error(t("common.remoteEmptyResult", {
|
|
1234
|
+
what: what || "remote",
|
|
1235
|
+
raw
|
|
1236
|
+
}));
|
|
672
1237
|
}
|
|
673
1238
|
return res.value;
|
|
674
1239
|
}
|
|
@@ -744,9 +1309,9 @@ window.__ModuleLoader__.load({
|
|
|
744
1309
|
...style
|
|
745
1310
|
} }, text);
|
|
746
1311
|
const runUsageText = (u) => {
|
|
747
|
-
if (!u || !(u.input || u.cacheRead || u.cacheWrite || u.output)) return "
|
|
1312
|
+
if (!u || !(u.input || u.cacheRead || u.cacheWrite || u.output)) return t("common.noUsage");
|
|
748
1313
|
const hit = hitRate(u);
|
|
749
|
-
return `⇅${fmtTokens(u.input)} ⇅${fmtTokens(u.cacheRead)} ⬆${fmtTokens(u.output)}${hit !== null ? ` ·${hit}%` : ""} · ${u.calls}
|
|
1314
|
+
return `⇅${fmtTokens(u.input)} ⇅${fmtTokens(u.cacheRead)} ⬆${fmtTokens(u.output)}${hit !== null ? ` ·${hit}%` : ""} · ${t("common.calls", { n: u.calls })}`;
|
|
750
1315
|
};
|
|
751
1316
|
const RUN_PREVIEW = 8;
|
|
752
1317
|
const TERMINAL_STATUSES = [
|
|
@@ -772,17 +1337,17 @@ window.__ModuleLoader__.load({
|
|
|
772
1337
|
fontSize: 11.5,
|
|
773
1338
|
fontWeight: 700,
|
|
774
1339
|
color: T.text2
|
|
775
|
-
} },
|
|
1340
|
+
} }, t("panel.railTitle", { n: products.length })), h("button", {
|
|
776
1341
|
style: panelBtn,
|
|
777
1342
|
onClick: onRefresh,
|
|
778
1343
|
disabled: busy,
|
|
779
|
-
title: "
|
|
780
|
-
}, busy ? "
|
|
1344
|
+
title: t("panel.rescanTip")
|
|
1345
|
+
}, busy ? t("panel.refreshing") : t("panel.refresh"))), h("div", { style: {
|
|
781
1346
|
flex: 1,
|
|
782
1347
|
minHeight: 0,
|
|
783
1348
|
overflowY: "auto",
|
|
784
1349
|
padding: "0 8px 12px"
|
|
785
|
-
} }, products.length === 0 ? muted("
|
|
1350
|
+
} }, products.length === 0 ? muted(t("panel.noProducts"), { padding: "10px 4px" }) : products.map((p) => {
|
|
786
1351
|
const on = p.key === current;
|
|
787
1352
|
return h("div", {
|
|
788
1353
|
key: p.key,
|
|
@@ -806,7 +1371,7 @@ window.__ModuleLoader__.load({
|
|
|
806
1371
|
overflow: "hidden",
|
|
807
1372
|
textOverflow: "ellipsis",
|
|
808
1373
|
whiteSpace: "nowrap"
|
|
809
|
-
} }, p.title || p.key), p.activeRuns > 0 ? chip(
|
|
1374
|
+
} }, p.title || p.key), p.activeRuns > 0 ? chip(t("panel.activeRuns", { n: p.activeRuns }), T.brand, { dot: true }) : null), h("div", { style: {
|
|
810
1375
|
fontSize: 10,
|
|
811
1376
|
color: T.text2,
|
|
812
1377
|
fontFamily: MONO,
|
|
@@ -820,10 +1385,10 @@ window.__ModuleLoader__.load({
|
|
|
820
1385
|
marginTop: 3,
|
|
821
1386
|
fontSize: 10,
|
|
822
1387
|
color: T.text2
|
|
823
|
-
} }, h("span", null, `run ${p.totalRuns}`), p.updatedAt ? h("span", null,
|
|
1388
|
+
} }, h("span", null, `run ${p.totalRuns}`), p.updatedAt ? h("span", null, t("panel.updated", { time: fmtTime(p.updatedAt) })) : null, p.key === loadingKey ? h("span", { style: {
|
|
824
1389
|
color: T.brand,
|
|
825
1390
|
fontWeight: 600
|
|
826
|
-
} }, "
|
|
1391
|
+
} }, t("panel.reading")) : null), p.lastRequirement ? h("div", { style: {
|
|
827
1392
|
fontSize: 10.5,
|
|
828
1393
|
color: T.text2,
|
|
829
1394
|
marginTop: 3,
|
|
@@ -832,11 +1397,11 @@ window.__ModuleLoader__.load({
|
|
|
832
1397
|
WebkitLineClamp: 2,
|
|
833
1398
|
WebkitBoxOrient: "vertical",
|
|
834
1399
|
overflow: "hidden"
|
|
835
|
-
} }, p.lastRequirement) : null, p.lastVerdict ? h("div", { style: { marginTop: 4 } }, chip(
|
|
1400
|
+
} }, p.lastRequirement) : null, p.lastVerdict ? h("div", { style: { marginTop: 4 } }, chip(t("panel.verdict", { v: p.lastVerdict }), stColor(p.lastVerdict === "accepted" ? "accepted" : p.lastVerdict))) : null);
|
|
836
1401
|
})));
|
|
837
1402
|
}
|
|
838
1403
|
function RunList({ runs, activeRunId, onOpenRun, onInlineRun }) {
|
|
839
|
-
if (!runs.length) return muted("
|
|
1404
|
+
if (!runs.length) return muted(t("runList.empty"), { padding: "2px 2px 8px" });
|
|
840
1405
|
return h("div", { style: {
|
|
841
1406
|
display: "flex",
|
|
842
1407
|
flexDirection: "column",
|
|
@@ -864,35 +1429,38 @@ window.__ModuleLoader__.load({
|
|
|
864
1429
|
} }, h("div", { style: {
|
|
865
1430
|
...flexRow,
|
|
866
1431
|
gap: 6
|
|
867
|
-
} }, chip(
|
|
1432
|
+
} }, chip(runStatusText(r.status), stColor(r.status), { dot: true }), r.mode ? chip(String(r.mode), T.text2) : null, h("span", { style: {
|
|
868
1433
|
fontFamily: MONO,
|
|
869
1434
|
fontSize: 10,
|
|
870
1435
|
color: T.text2
|
|
871
1436
|
} }, r.id), active ? h("span", { style: {
|
|
872
1437
|
fontSize: 10,
|
|
873
1438
|
color: T.brand
|
|
874
|
-
} }, "
|
|
1439
|
+
} }, t("runList.running")) : null), h("div", { style: {
|
|
875
1440
|
fontSize: 11.5,
|
|
876
1441
|
color: T.text,
|
|
877
1442
|
marginTop: 3,
|
|
878
1443
|
overflow: "hidden",
|
|
879
1444
|
textOverflow: "ellipsis",
|
|
880
1445
|
whiteSpace: "nowrap"
|
|
881
|
-
} }, r.requirement ||
|
|
1446
|
+
} }, r.requirement || t("runList.noRequirement")), h("div", { style: {
|
|
882
1447
|
...flexRow,
|
|
883
1448
|
gap: 10,
|
|
884
1449
|
marginTop: 3,
|
|
885
1450
|
fontSize: 10,
|
|
886
1451
|
color: T.text2,
|
|
887
1452
|
fontFamily: MONO
|
|
888
|
-
} }, h("span", null,
|
|
1453
|
+
} }, h("span", null, t("runList.stageProgress", {
|
|
1454
|
+
done: r.doneStages,
|
|
1455
|
+
total: r.stageCount
|
|
1456
|
+
})), h("span", null, runUsageText(r.usage)), h("span", null, `${fmtTime(r.startedAt)}${r.endedAt ? ` → ${fmtTime(r.endedAt)}` : ""} ${fmtDur(r.startedAt, r.endedAt)}`))), h("button", {
|
|
889
1457
|
style: brandBtn,
|
|
890
|
-
title: "
|
|
1458
|
+
title: t("runList.openRightBarTip"),
|
|
891
1459
|
onClick: (e) => {
|
|
892
1460
|
e.stopPropagation();
|
|
893
1461
|
onOpenRun(r);
|
|
894
1462
|
}
|
|
895
|
-
}, "
|
|
1463
|
+
}, t("runList.openRightBar")));
|
|
896
1464
|
}));
|
|
897
1465
|
}
|
|
898
1466
|
function BacklogCard({ kind, item, onOpen }) {
|
|
@@ -950,12 +1518,12 @@ window.__ModuleLoader__.load({
|
|
|
950
1518
|
marginTop: 3,
|
|
951
1519
|
fontSize: 10,
|
|
952
1520
|
color: T.text2
|
|
953
|
-
} }, item.devAssign ? h("span", null, `dev ${item.devAssign}`) : null, item.qaAssign ? h("span", null, `qa ${item.qaAssign}`) : null, item.acceptBy ? h("span", null,
|
|
1521
|
+
} }, item.devAssign ? h("span", null, `dev ${item.devAssign}`) : null, item.qaAssign ? h("span", null, `qa ${item.qaAssign}`) : null, item.acceptBy ? h("span", null, t("panel.verdict", { v: item.acceptBy })) : null, item.retries ? h("span", { style: { color: T.warn } }, t("board.retries", { n: item.retries })) : null, item.humanIntervention ? h("span", { style: { color: T.error } }, t("status.needs-human")) : null));
|
|
954
1522
|
}
|
|
955
1523
|
/** 可点筛选徽章(多选):单击切换该状态,选中态用状态色实心;再点取消。 */
|
|
956
1524
|
const filterChip = (text, color, on, onToggle) => h("button", {
|
|
957
1525
|
onClick: onToggle,
|
|
958
|
-
title: on ? "
|
|
1526
|
+
title: on ? t("panelBoard.filterChipOn") : t("panelBoard.filterChipOff"),
|
|
959
1527
|
style: {
|
|
960
1528
|
font: "inherit",
|
|
961
1529
|
fontSize: 11,
|
|
@@ -993,7 +1561,7 @@ window.__ModuleLoader__.load({
|
|
|
993
1561
|
["task", (backlog.tasks || []).filter((t) => t.type !== "subtask")],
|
|
994
1562
|
["bug", backlog.bugs || []]
|
|
995
1563
|
];
|
|
996
|
-
if (!groups.reduce((a, [, arr]) => a + arr.length, 0)) return muted("
|
|
1564
|
+
if (!groups.reduce((a, [, arr]) => a + arr.length, 0)) return muted(t("panelBoard.empty"), { padding: "2px 2px 8px" });
|
|
997
1565
|
return h("div", null, groups.map(([kind, list]) => {
|
|
998
1566
|
if (!list.length) return null;
|
|
999
1567
|
const done = list.filter((it) => TERMINAL_STATUSES.indexOf(it.status) !== -1 && !it.humanIntervention);
|
|
@@ -1028,33 +1596,40 @@ window.__ModuleLoader__.load({
|
|
|
1028
1596
|
fontWeight: 700,
|
|
1029
1597
|
color: T.text,
|
|
1030
1598
|
flex: "0 0 auto"
|
|
1031
|
-
} },
|
|
1599
|
+
} }, t("panelBoard.groupCount", {
|
|
1600
|
+
kind: kindTitle(kind),
|
|
1601
|
+
n: list.length
|
|
1602
|
+
})), h("span", { style: {
|
|
1032
1603
|
fontSize: 10,
|
|
1033
1604
|
color: T.text2,
|
|
1034
1605
|
flex: "0 0 auto"
|
|
1035
|
-
} },
|
|
1606
|
+
} }, t("panelBoard.activeCount", { n: active.length })), ...Object.keys(byStatus).map((s) => filterChip(`${stText(s)} ${byStatus[s]}`, stColor(s), selSet.has(s), () => toggle(s))), filtering ? h("button", {
|
|
1036
1607
|
style: {
|
|
1037
1608
|
...panelBtn,
|
|
1038
1609
|
marginLeft: "auto",
|
|
1039
1610
|
flex: "0 0 auto"
|
|
1040
1611
|
},
|
|
1041
|
-
title: "
|
|
1612
|
+
title: t("panelBoard.clearFilterTip"),
|
|
1042
1613
|
onClick: () => setFilters((m) => ({
|
|
1043
1614
|
...m,
|
|
1044
1615
|
[kind]: []
|
|
1045
1616
|
}))
|
|
1046
|
-
},
|
|
1617
|
+
}, t("panel.filtered", {
|
|
1618
|
+
sel: sel.length,
|
|
1619
|
+
shown: matched.length,
|
|
1620
|
+
total: list.length
|
|
1621
|
+
})) : done.length ? h("button", {
|
|
1047
1622
|
style: {
|
|
1048
1623
|
...panelBtn,
|
|
1049
1624
|
marginLeft: "auto",
|
|
1050
1625
|
flex: "0 0 auto"
|
|
1051
1626
|
},
|
|
1052
|
-
title: open ? "
|
|
1627
|
+
title: open ? t("panelBoard.collapseDoneTip") : t("panelBoard.expandDoneTip"),
|
|
1053
1628
|
onClick: () => setShowDone((m) => ({
|
|
1054
1629
|
...m,
|
|
1055
1630
|
[kind]: !open
|
|
1056
1631
|
}))
|
|
1057
|
-
}, open ?
|
|
1632
|
+
}, open ? t("panelBoard.collapseDone", { n: done.length }) : t("panelBoard.expandDone", { n: done.length })) : null), visible.length ? h("div", { style: {
|
|
1058
1633
|
display: "grid",
|
|
1059
1634
|
gridTemplateColumns: "repeat(auto-fill, minmax(228px, 1fr))",
|
|
1060
1635
|
gap: 6
|
|
@@ -1063,7 +1638,7 @@ window.__ModuleLoader__.load({
|
|
|
1063
1638
|
kind,
|
|
1064
1639
|
item: it,
|
|
1065
1640
|
onOpen
|
|
1066
|
-
}))) : muted("
|
|
1641
|
+
}))) : muted(t("panelBoard.emptyFiltered"), { fontSize: 10.5 }));
|
|
1067
1642
|
}));
|
|
1068
1643
|
}
|
|
1069
1644
|
function ItemDetailPane({ det, openArtifact, onClose }) {
|
|
@@ -1099,43 +1674,62 @@ window.__ModuleLoader__.load({
|
|
|
1099
1674
|
} }, det.id), chip(stText(det.status), stColor(det.status), { dot: true }), h("span", { style: {
|
|
1100
1675
|
fontSize: 10.5,
|
|
1101
1676
|
color: T.text2
|
|
1102
|
-
} },
|
|
1677
|
+
} }, kindTitle(det.kind))), h("button", {
|
|
1103
1678
|
style: panelBtn,
|
|
1104
1679
|
onClick: onClose
|
|
1105
|
-
}, "
|
|
1680
|
+
}, t("common.close"))), h("div", { style: {
|
|
1106
1681
|
fontSize: 13,
|
|
1107
1682
|
fontWeight: 600,
|
|
1108
1683
|
color: T.text,
|
|
1109
1684
|
lineHeight: 1.45
|
|
1110
|
-
} }, det.title), h("div", { style: {
|
|
1685
|
+
} }, det.title), det.kind === "bug" ? h("div", { style: {
|
|
1686
|
+
display: "flex",
|
|
1687
|
+
flexDirection: "column",
|
|
1688
|
+
gap: 4,
|
|
1689
|
+
padding: "8px 10px",
|
|
1690
|
+
borderRadius: 8,
|
|
1691
|
+
background: T.layer2,
|
|
1692
|
+
border: `1px solid ${T.border}`
|
|
1693
|
+
} }, h("div", { style: {
|
|
1694
|
+
...flexRow,
|
|
1695
|
+
gap: 6
|
|
1696
|
+
} }, h("span", { style: {
|
|
1697
|
+
fontSize: 11,
|
|
1698
|
+
fontWeight: 700,
|
|
1699
|
+
color: T.text
|
|
1700
|
+
} }, t("panelItem.defectSection")), det.severity ? chip(String(det.severity), String(det.severity) === "P0" ? T.error : String(det.severity) === "P1" ? T.warn : T.text2) : null), row(t("panelItem.row.defectId"), det.defectId), row(t("panelItem.row.module"), det.module), row(t("panelItem.row.reproduce"), det.reproduce), row(t("panelItem.row.expected"), det.expected), row(t("panelItem.row.actual"), det.actual), row(t("panelItem.row.defectCheck"), det.defectCheck), row(t("panelItem.row.defectCriterion"), det.defectCriterion), row(t("panelItem.row.defectAc"), det.defectAc), det.reproduce || det.expected || det.actual ? null : h("div", { style: {
|
|
1701
|
+
fontSize: 10.5,
|
|
1702
|
+
color: T.warn,
|
|
1703
|
+
lineHeight: 1.5
|
|
1704
|
+
} }, t("panelItem.noDefectDetail"))) : null, h("div", { style: {
|
|
1111
1705
|
display: "flex",
|
|
1112
1706
|
flexDirection: "column",
|
|
1113
1707
|
gap: 3
|
|
1114
|
-
} }, row("
|
|
1708
|
+
} }, row(t("panelItem.row.req"), det.reqId), row(t("panelItem.row.owner"), det.owner), row(t("panelItem.row.dev"), det.devAssign), row(t("panelItem.row.qa"), det.qaAssign), row(t("panelItem.row.accept"), det.assignBy), row(t("panelItem.row.retries"), det.retries), row(t("panelItem.row.runDocs"), det.runDocs)), det.spec ? h("div", null, h("div", { style: {
|
|
1115
1709
|
fontSize: 11,
|
|
1116
1710
|
color: T.text2,
|
|
1117
1711
|
marginBottom: 3
|
|
1118
|
-
} }, "
|
|
1712
|
+
} }, t("panelItem.spec")), h(FoldableText, { text: det.spec })) : null, det.summary ? h("div", null, h("div", { style: {
|
|
1119
1713
|
fontSize: 11,
|
|
1120
1714
|
color: T.text2,
|
|
1121
1715
|
marginBottom: 3
|
|
1122
|
-
} }, "
|
|
1716
|
+
} }, t("panelItem.summary")), h(FoldableText, { text: det.summary })) : null, det.artifacts && det.artifacts.length ? h("div", null, h("div", { style: {
|
|
1123
1717
|
fontSize: 11,
|
|
1124
1718
|
color: T.text2,
|
|
1125
1719
|
marginBottom: 4
|
|
1126
|
-
} },
|
|
1720
|
+
} }, t("panelItem.artifacts", { n: det.artifacts.length })), h("div", { style: {
|
|
1127
1721
|
...flexRow,
|
|
1128
1722
|
gap: 5
|
|
1129
1723
|
} }, det.artifacts.map((a) => h("button", {
|
|
1130
1724
|
key: a.name,
|
|
1131
1725
|
style: brandBtn,
|
|
1132
|
-
title:
|
|
1726
|
+
title: t("panelItem.artifactTip", { address: a.address }),
|
|
1133
1727
|
onClick: () => openArtifact && openArtifact(a.address, a.name, det.runInfo && det.runInfo.ownerSession || null)
|
|
1134
|
-
}, a.name)))) : muted("
|
|
1728
|
+
}, a.name)))) : muted(t("panelItem.noArtifacts")), det.subtasks && det.subtasks.length ? h("div", null, h("div", { style: {
|
|
1135
1729
|
fontSize: 11,
|
|
1136
1730
|
color: T.text2,
|
|
1137
1731
|
marginBottom: 4
|
|
1138
|
-
} },
|
|
1732
|
+
} }, t("panelItem.subtasks", { n: det.subtasks.length })), h("div", { style: {
|
|
1139
1733
|
display: "flex",
|
|
1140
1734
|
flexDirection: "column",
|
|
1141
1735
|
gap: 4
|
|
@@ -1160,11 +1754,11 @@ window.__ModuleLoader__.load({
|
|
|
1160
1754
|
overflow: "hidden",
|
|
1161
1755
|
textOverflow: "ellipsis",
|
|
1162
1756
|
whiteSpace: "nowrap"
|
|
1163
|
-
} }, s.title), s.failed ? chip("
|
|
1757
|
+
} }, s.title), s.failed ? chip(t("common.failed"), T.error) : null)))) : null, det.bugs && det.bugs.length ? h("div", null, h("div", { style: {
|
|
1164
1758
|
fontSize: 11,
|
|
1165
1759
|
color: T.text2,
|
|
1166
1760
|
marginBottom: 4
|
|
1167
|
-
} },
|
|
1761
|
+
} }, t("panelItem.bugs", { n: det.bugs.length })), h("div", { style: {
|
|
1168
1762
|
display: "flex",
|
|
1169
1763
|
flexDirection: "column",
|
|
1170
1764
|
gap: 4
|
|
@@ -1193,7 +1787,7 @@ window.__ModuleLoader__.load({
|
|
|
1193
1787
|
fontSize: 11,
|
|
1194
1788
|
color: T.text2,
|
|
1195
1789
|
marginBottom: 4
|
|
1196
|
-
} },
|
|
1790
|
+
} }, t("panelItem.events", { n: Math.min(det.events.length, 30) })), h("div", { style: {
|
|
1197
1791
|
display: "flex",
|
|
1198
1792
|
flexDirection: "column",
|
|
1199
1793
|
gap: 3,
|
|
@@ -1209,7 +1803,7 @@ window.__ModuleLoader__.load({
|
|
|
1209
1803
|
setSel(null);
|
|
1210
1804
|
setErr(null);
|
|
1211
1805
|
}, [snap && snap.id]);
|
|
1212
|
-
if (!snap) return muted("
|
|
1806
|
+
if (!snap) return muted(t("detail.runMissing"), { padding: 12 });
|
|
1213
1807
|
const stages = snap.stages || [];
|
|
1214
1808
|
const totals = stages.reduce((a, s) => {
|
|
1215
1809
|
const u = s.usage;
|
|
@@ -1248,7 +1842,7 @@ window.__ModuleLoader__.load({
|
|
|
1248
1842
|
} }, h("div", { style: {
|
|
1249
1843
|
...flexRow,
|
|
1250
1844
|
gap: 6
|
|
1251
|
-
} }, chip(
|
|
1845
|
+
} }, chip(runStatusText(snap.status), stColor(snap.status), { dot: true }), snap.options && snap.options.mode ? chip(String(snap.options.mode), T.text2) : null, h("span", { style: {
|
|
1252
1846
|
fontFamily: MONO,
|
|
1253
1847
|
fontSize: 10.5,
|
|
1254
1848
|
color: T.text2
|
|
@@ -1260,13 +1854,16 @@ window.__ModuleLoader__.load({
|
|
|
1260
1854
|
fontSize: 12,
|
|
1261
1855
|
color: T.text,
|
|
1262
1856
|
lineHeight: 1.5
|
|
1263
|
-
} }, snap.requirement ||
|
|
1857
|
+
} }, snap.requirement || t("runList.noRequirement")), h("div", { style: {
|
|
1264
1858
|
...flexRow,
|
|
1265
1859
|
gap: 12,
|
|
1266
1860
|
fontSize: 10.5,
|
|
1267
1861
|
color: T.text2,
|
|
1268
1862
|
fontFamily: MONO
|
|
1269
|
-
} }, h("span", null, `${fmtTime(snap.startedAt)}${snap.endedAt ? ` → ${fmtTime(snap.endedAt)}` : " →
|
|
1863
|
+
} }, h("span", null, `${fmtTime(snap.startedAt)}${snap.endedAt ? ` → ${fmtTime(snap.endedAt)}` : " → " + t("detail.endedRunning")} · ${fmtDur(snap.startedAt, snap.endedAt)}`), h("span", null, t("runList.stageProgress", {
|
|
1864
|
+
done: stages.filter((s) => s.status === "done").length,
|
|
1865
|
+
total: stages.length
|
|
1866
|
+
})), h("span", null, t("detail.subagents", { n: snap.agentsStarted || 0 }))), h("div", { style: {
|
|
1270
1867
|
...flexRow,
|
|
1271
1868
|
gap: 10,
|
|
1272
1869
|
fontSize: 10.5,
|
|
@@ -1276,7 +1873,7 @@ window.__ModuleLoader__.load({
|
|
|
1276
1873
|
borderRadius: 8,
|
|
1277
1874
|
background: `color-mix(in srgb, ${T.layer2} 60%, transparent)`,
|
|
1278
1875
|
border: `1px solid ${T.border}`
|
|
1279
|
-
} }, h("span", null,
|
|
1876
|
+
} }, h("span", null, t("token.inputMiss", { v: fmtTokens(totals.input) || "0" })), h("span", null, t("token.inputHit", { v: fmtTokens(totals.cacheRead) || "0" })), h("span", null, t("token.cacheWrite", { v: fmtTokens(totals.cacheWrite) || "0" })), h("span", null, t("token.output", { v: fmtTokens(totals.output) || "0" })), h("span", null, t("common.callsCount", { n: totals.calls })), h("span", null, t("token.total", { v: fmtTokens(totalTokens(totals)) || "0" }))), sectionTitle(t("detail.stages", { n: stages.length })), h("div", { style: {
|
|
1280
1877
|
display: "flex",
|
|
1281
1878
|
flexDirection: "column",
|
|
1282
1879
|
gap: 4
|
|
@@ -1305,7 +1902,7 @@ window.__ModuleLoader__.load({
|
|
|
1305
1902
|
fontSize: 11.5,
|
|
1306
1903
|
color: T.text,
|
|
1307
1904
|
fontWeight: 500
|
|
1308
|
-
} },
|
|
1905
|
+
} }, stageLabelOf(s)), chip(stText(s.status), color, { dot: true }), s.outcome && s.outcome !== "completed" ? chip(String(s.outcome), stColor(s.outcome)) : null, h("span", { style: {
|
|
1309
1906
|
marginLeft: "auto",
|
|
1310
1907
|
fontFamily: MONO,
|
|
1311
1908
|
fontSize: 10,
|
|
@@ -1317,13 +1914,13 @@ window.__ModuleLoader__.load({
|
|
|
1317
1914
|
fontFamily: MONO,
|
|
1318
1915
|
fontSize: 10,
|
|
1319
1916
|
color: T.text2
|
|
1320
|
-
} }, h("span", null, stageUsageLine(s) || "
|
|
1917
|
+
} }, h("span", null, stageUsageLine(s) || t("common.noUsage")), s.childId ? h("span", { title: s.childId }, t("detail.subagentChip", { id: String(s.childId).slice(0, 14) })) : null), s.summary ? h("div", { style: {
|
|
1321
1918
|
fontSize: 10.5,
|
|
1322
1919
|
color: T.text2,
|
|
1323
1920
|
marginTop: 3,
|
|
1324
1921
|
lineHeight: 1.45
|
|
1325
1922
|
} }, String(s.summary).slice(0, 200)) : null);
|
|
1326
|
-
})), err ? muted(
|
|
1923
|
+
})), err ? muted(t("detail.stageFailed", { err }), { color: T.error }) : null, sel ? h("div", { style: {
|
|
1327
1924
|
padding: "9px 10px",
|
|
1328
1925
|
borderRadius: 9,
|
|
1329
1926
|
border: `1px solid ${T.border}`,
|
|
@@ -1341,18 +1938,18 @@ window.__ModuleLoader__.load({
|
|
|
1341
1938
|
fontSize: 11.5,
|
|
1342
1939
|
fontWeight: 700,
|
|
1343
1940
|
color: T.text
|
|
1344
|
-
} },
|
|
1941
|
+
} }, t("detail.stageTitle", { seq: sel.seq })), chip(stText(sel.status), stColor(sel.status))), h("button", {
|
|
1345
1942
|
style: panelBtn,
|
|
1346
1943
|
onClick: () => setSel(null)
|
|
1347
|
-
}, "
|
|
1944
|
+
}, t("common.collapse"))), h("div", { style: {
|
|
1348
1945
|
fontSize: 10.5,
|
|
1349
1946
|
color: T.text2,
|
|
1350
1947
|
fontFamily: MONO
|
|
1351
|
-
} },
|
|
1948
|
+
} }, t("token.stageLine", { v: stageUsageLine(sel) || t("common.none") })), sel.verifyEvidence ? h("div", null, h("div", { style: {
|
|
1352
1949
|
fontSize: 11,
|
|
1353
1950
|
color: T.success,
|
|
1354
1951
|
marginBottom: 3
|
|
1355
|
-
} }, "
|
|
1952
|
+
} }, t("stage.evidenceTitle")), h("div", { style: {
|
|
1356
1953
|
whiteSpace: "pre-wrap",
|
|
1357
1954
|
wordBreak: "break-word",
|
|
1358
1955
|
fontSize: 11,
|
|
@@ -1365,11 +1962,11 @@ window.__ModuleLoader__.load({
|
|
|
1365
1962
|
maxHeight: 200,
|
|
1366
1963
|
overflowY: "auto",
|
|
1367
1964
|
fontFamily: MONO
|
|
1368
|
-
} }, sel.verifyEvidence)) : muted("
|
|
1965
|
+
} }, sel.verifyEvidence)) : muted(t("stage.evidenceMissingShort"), { color: T.warn }), sel.output ? h("div", null, h("div", { style: {
|
|
1369
1966
|
fontSize: 11,
|
|
1370
1967
|
color: T.text2,
|
|
1371
1968
|
marginBottom: 3
|
|
1372
|
-
} }, "
|
|
1969
|
+
} }, t("detail.output")), h(FoldableText, {
|
|
1373
1970
|
text: sel.output,
|
|
1374
1971
|
charLimit: 400,
|
|
1375
1972
|
lineLimit: 8,
|
|
@@ -1381,7 +1978,7 @@ window.__ModuleLoader__.load({
|
|
|
1381
1978
|
fontSize: 11,
|
|
1382
1979
|
color: T.text2,
|
|
1383
1980
|
marginBottom: 3
|
|
1384
|
-
} },
|
|
1981
|
+
} }, t("detail.attempts", { n: sel.attempts.length })), h("div", { style: {
|
|
1385
1982
|
display: "flex",
|
|
1386
1983
|
flexDirection: "column",
|
|
1387
1984
|
gap: 3
|
|
@@ -1394,7 +1991,7 @@ window.__ModuleLoader__.load({
|
|
|
1394
1991
|
fontFamily: MONO,
|
|
1395
1992
|
color: T.text2
|
|
1396
1993
|
}
|
|
1397
|
-
}, h("span", null, `#${a.seq}`), chip(stText(a.status), stColor(a.status)), a.outcome ? h("span", null, a.outcome) : null, h("span", { style: { marginLeft: "auto" } }, `${fmtTime(a.startedAt)} · ${fmtDur(a.startedAt, a.endedAt)}`))))) : null) : null, logs.length ? h("div", null, sectionTitle(
|
|
1994
|
+
}, h("span", null, `#${a.seq}`), chip(stText(a.status), stColor(a.status)), a.outcome ? h("span", null, a.outcome) : null, h("span", { style: { marginLeft: "auto" } }, `${fmtTime(a.startedAt)} · ${fmtDur(a.startedAt, a.endedAt)}`))))) : null) : null, logs.length ? h("div", null, sectionTitle(t("detail.logs", { n: logs.length })), h("div", { style: {
|
|
1398
1995
|
display: "flex",
|
|
1399
1996
|
flexDirection: "column",
|
|
1400
1997
|
gap: 2,
|
|
@@ -1447,12 +2044,12 @@ window.__ModuleLoader__.load({
|
|
|
1447
2044
|
let alive = true;
|
|
1448
2045
|
if (!runId) {
|
|
1449
2046
|
setSnap(null);
|
|
1450
|
-
setErr(address ?
|
|
2047
|
+
setErr(address ? t("tab.resolveFailed", { address }) : readTab ? t("tab.readingAddress") : t("tab.noHook"));
|
|
1451
2048
|
return;
|
|
1452
2049
|
}
|
|
1453
2050
|
if (!api) {
|
|
1454
2051
|
setSnap(null);
|
|
1455
|
-
setErr("
|
|
2052
|
+
setErr(t("tab.remoteUnavailable"));
|
|
1456
2053
|
return;
|
|
1457
2054
|
}
|
|
1458
2055
|
api.runDetail(runId).then((v) => {
|
|
@@ -1488,15 +2085,15 @@ window.__ModuleLoader__.load({
|
|
|
1488
2085
|
display: "flex",
|
|
1489
2086
|
flexDirection: "column",
|
|
1490
2087
|
gap: 8
|
|
1491
|
-
} }, muted(pending ? "
|
|
2088
|
+
} }, muted(pending ? t("tab.readingAddress") : err, { color: pending ? T.text2 : T.error }), pending ? null : h("button", {
|
|
1492
2089
|
style: panelBtn,
|
|
1493
2090
|
onClick: () => {
|
|
1494
2091
|
setErr(null);
|
|
1495
2092
|
setNonce((n) => n + 1);
|
|
1496
2093
|
}
|
|
1497
|
-
}, "
|
|
2094
|
+
}, t("common.retry")));
|
|
1498
2095
|
}
|
|
1499
|
-
if (!snap) return muted("
|
|
2096
|
+
if (!snap) return muted(t("tab.readingRun"), { padding: 12 });
|
|
1500
2097
|
return h(RunDetailPane, {
|
|
1501
2098
|
snap,
|
|
1502
2099
|
product,
|
|
@@ -1545,7 +2142,7 @@ window.__ModuleLoader__.load({
|
|
|
1545
2142
|
const attempt = (quiet) => !!(props.openResource && address && props.openResource(address, label, quiet));
|
|
1546
2143
|
if (attempt(false)) return;
|
|
1547
2144
|
if (!address) {
|
|
1548
|
-
setHint(
|
|
2145
|
+
setHint(t("panel.hintNoAddress", { label }));
|
|
1549
2146
|
if (fallback) fallback();
|
|
1550
2147
|
return;
|
|
1551
2148
|
}
|
|
@@ -1560,7 +2157,7 @@ window.__ModuleLoader__.load({
|
|
|
1560
2157
|
setTimeout(tick, 120);
|
|
1561
2158
|
return;
|
|
1562
2159
|
}
|
|
1563
|
-
setHint(
|
|
2160
|
+
setHint(t("panel.hintRightbarFailed", { label }) + (fallback ? t("panel.hintInlineSuffix") : ""));
|
|
1564
2161
|
if (fallback) fallback();
|
|
1565
2162
|
};
|
|
1566
2163
|
setTimeout(tick, 140);
|
|
@@ -1585,7 +2182,7 @@ window.__ModuleLoader__.load({
|
|
|
1585
2182
|
try {
|
|
1586
2183
|
sessions.open(ownerSession);
|
|
1587
2184
|
} catch (e) {
|
|
1588
|
-
setHint(
|
|
2185
|
+
setHint(t("panel.hintSessionGone", { sid: String(ownerSession).slice(0, 8) }));
|
|
1589
2186
|
if (fallback) fallback();
|
|
1590
2187
|
return;
|
|
1591
2188
|
}
|
|
@@ -1606,7 +2203,7 @@ window.__ModuleLoader__.load({
|
|
|
1606
2203
|
setTimeout(tick, 130);
|
|
1607
2204
|
return;
|
|
1608
2205
|
}
|
|
1609
|
-
setHint(
|
|
2206
|
+
setHint(t("panel.hintSwitchedNoRightbar", { label }));
|
|
1610
2207
|
};
|
|
1611
2208
|
setTimeout(tick, 140);
|
|
1612
2209
|
};
|
|
@@ -1614,7 +2211,7 @@ window.__ModuleLoader__.load({
|
|
|
1614
2211
|
if (!remote || typeof remote.products !== "function") {
|
|
1615
2212
|
setState((s) => ({
|
|
1616
2213
|
...s,
|
|
1617
|
-
err: "
|
|
2214
|
+
err: t("panel.remoteProductsUnavailable")
|
|
1618
2215
|
}));
|
|
1619
2216
|
return;
|
|
1620
2217
|
}
|
|
@@ -1802,32 +2399,32 @@ window.__ModuleLoader__.load({
|
|
|
1802
2399
|
} }, h("span", { style: {
|
|
1803
2400
|
fontSize: 13,
|
|
1804
2401
|
fontWeight: 700
|
|
1805
|
-
} }, "
|
|
2402
|
+
} }, t("panel.title")), h("span", { style: {
|
|
1806
2403
|
fontSize: 11,
|
|
1807
2404
|
color: T.text2
|
|
1808
|
-
} }, "
|
|
2405
|
+
} }, t("panel.subtitle")), currentSessionId ? h("span", { style: {
|
|
1809
2406
|
fontSize: 10,
|
|
1810
2407
|
color: T.text2,
|
|
1811
2408
|
fontFamily: MONO
|
|
1812
|
-
} },
|
|
2409
|
+
} }, t("panel.currentSession", { sid: String(currentSessionId).slice(0, 8) })) : h("span", { style: {
|
|
1813
2410
|
fontSize: 10,
|
|
1814
2411
|
color: T.text2
|
|
1815
|
-
} }, "
|
|
2412
|
+
} }, t("panel.noSession"))), h("div", { style: {
|
|
1816
2413
|
...flexRow,
|
|
1817
2414
|
gap: 6
|
|
1818
2415
|
} }, product ? h("button", {
|
|
1819
2416
|
style: panelBtn,
|
|
1820
2417
|
onClick: () => loadView(state.current)
|
|
1821
|
-
}, "
|
|
2418
|
+
}, t("panel.reload")) : null, h("button", {
|
|
1822
2419
|
style: panelBtn,
|
|
1823
|
-
title: "
|
|
2420
|
+
title: t("panel.backToChatTip"),
|
|
1824
2421
|
onClick: () => {
|
|
1825
2422
|
try {
|
|
1826
2423
|
const layout = props.layout;
|
|
1827
2424
|
if (layout && layout.selectPanel) layout.selectPanel(null);
|
|
1828
2425
|
} catch (e) {}
|
|
1829
2426
|
}
|
|
1830
|
-
}, "
|
|
2427
|
+
}, t("panel.backToChat")))), state.err ? h("div", { style: {
|
|
1831
2428
|
padding: "6px 14px",
|
|
1832
2429
|
fontSize: 11,
|
|
1833
2430
|
color: T.error,
|
|
@@ -1844,7 +2441,7 @@ window.__ModuleLoader__.load({
|
|
|
1844
2441
|
} }, h("span", null, hint), h("button", {
|
|
1845
2442
|
style: panelBtn,
|
|
1846
2443
|
onClick: () => setHint(null)
|
|
1847
|
-
}, "
|
|
2444
|
+
}, t("common.gotIt"))) : null, h("div", { style: {
|
|
1848
2445
|
flex: 1,
|
|
1849
2446
|
minHeight: 0,
|
|
1850
2447
|
display: "flex",
|
|
@@ -1862,7 +2459,7 @@ window.__ModuleLoader__.load({
|
|
|
1862
2459
|
minHeight: 0,
|
|
1863
2460
|
display: "flex",
|
|
1864
2461
|
flexDirection: "column"
|
|
1865
|
-
} }, !state.current ? h("div", { style: { padding: "12px 14px" } }, muted("
|
|
2462
|
+
} }, !state.current ? h("div", { style: { padding: "12px 14px" } }, muted(t("panel.pickProduct"))) : !view ? h("div", { style: { padding: "12px 14px" } }, muted(t("panel.loadingView"))) : h(react.default.Fragment, null, h("div", { style: {
|
|
1866
2463
|
...flexRow,
|
|
1867
2464
|
justifyContent: "space-between",
|
|
1868
2465
|
gap: 10,
|
|
@@ -1883,21 +2480,21 @@ window.__ModuleLoader__.load({
|
|
|
1883
2480
|
...flexRow,
|
|
1884
2481
|
gap: 6,
|
|
1885
2482
|
flex: "0 0 auto"
|
|
1886
|
-
} }, chip(
|
|
2483
|
+
} }, chip(t("panel.runChip", { n: product.totalRuns }), T.text2), product.activeRuns > 0 ? chip(t("panel.activeChip", { n: product.activeRuns }), T.brand, { dot: true }) : null, product.lastVerdict ? chip(t("panel.verdictChip", { v: product.lastVerdict }), stColor("accepted")) : null)), h("div", { style: {
|
|
1887
2484
|
display: "flex",
|
|
1888
2485
|
alignItems: "flex-end",
|
|
1889
2486
|
gap: 2,
|
|
1890
2487
|
padding: "0 14px",
|
|
1891
2488
|
borderBottom: `1px solid ${T.border}`
|
|
1892
|
-
} }, panelTabBtn("run",
|
|
2489
|
+
} }, panelTabBtn("run", t("panel.tabRuns", { n: runs.length })), panelTabBtn("backlog", t("panel.tabBacklog", { n: backlogCount })), h("div", { style: {
|
|
1893
2490
|
marginLeft: "auto",
|
|
1894
2491
|
...flexRow,
|
|
1895
2492
|
gap: 6,
|
|
1896
2493
|
paddingBottom: 7
|
|
1897
|
-
} }, panelTab === "run" && !runsExpanded && pinnedActive.length > 0 ? chip(
|
|
2494
|
+
} }, panelTab === "run" && !runsExpanded && pinnedActive.length > 0 ? chip(t("panel.pinnedActive", { n: pinnedActive.length }), T.brand, { dot: true }) : null, panelTab === "run" && runsMatched.length > RUN_PREVIEW ? h("button", {
|
|
1898
2495
|
style: panelBtn,
|
|
1899
2496
|
onClick: () => setRunsExpanded((v) => !v)
|
|
1900
|
-
}, runsExpanded ?
|
|
2497
|
+
}, runsExpanded ? t("panel.showRecent", { n: RUN_PREVIEW }) : t("panel.showAll", { n: runsMatched.length })) : null)), h("div", { style: {
|
|
1901
2498
|
flex: 1,
|
|
1902
2499
|
minHeight: 0,
|
|
1903
2500
|
overflowY: "auto",
|
|
@@ -1907,19 +2504,23 @@ window.__ModuleLoader__.load({
|
|
|
1907
2504
|
...flexRow,
|
|
1908
2505
|
gap: 6,
|
|
1909
2506
|
marginBottom: 8
|
|
1910
|
-
} }, ...RUN_STATUS_ORDER.filter((st) => runStatusCounts[st]).map((st) => filterChip(`${
|
|
2507
|
+
} }, ...RUN_STATUS_ORDER.filter((st) => runStatusCounts[st]).map((st) => filterChip(`${runStatusText(st)} ${runStatusCounts[st]}`, stColor(st), runSelSet.has(st), () => toggleRunStatus(st))), runFiltering ? h("button", {
|
|
1911
2508
|
style: panelBtn,
|
|
1912
|
-
title: "
|
|
2509
|
+
title: t("panel.clearRunFilterTip"),
|
|
1913
2510
|
onClick: () => setRunFilter([])
|
|
1914
|
-
},
|
|
2511
|
+
}, t("panel.filtered", {
|
|
2512
|
+
sel: runSel.length,
|
|
2513
|
+
shown: runsMatched.length,
|
|
2514
|
+
total: runs.length
|
|
2515
|
+
})) : null), visibleRuns.length ? h(RunList, {
|
|
1915
2516
|
runs: visibleRuns,
|
|
1916
2517
|
activeRunId: detail && detail.kind === "run" && detail.run ? detail.run.id : null,
|
|
1917
2518
|
onOpenRun: openRun,
|
|
1918
2519
|
onInlineRun: showInline
|
|
1919
|
-
}) : muted("
|
|
2520
|
+
}) : muted(t("panel.emptyRunFilter"), { fontSize: 10.5 }), muted(t("panel.runHint"), {
|
|
1920
2521
|
fontSize: 10,
|
|
1921
2522
|
marginTop: 8
|
|
1922
|
-
})) : h(react.default.Fragment, null, muted("
|
|
2523
|
+
})) : h(react.default.Fragment, null, muted(t("panel.boardHint"), {
|
|
1923
2524
|
fontSize: 10,
|
|
1924
2525
|
marginBottom: 8
|
|
1925
2526
|
}), h(BacklogGroups, {
|
|
@@ -1952,21 +2553,21 @@ window.__ModuleLoader__.load({
|
|
|
1952
2553
|
fontSize: 11.5,
|
|
1953
2554
|
fontWeight: 700,
|
|
1954
2555
|
color: T.text
|
|
1955
|
-
} }, "
|
|
2556
|
+
} }, t("panel.runDetail")), h("div", { style: {
|
|
1956
2557
|
...flexRow,
|
|
1957
2558
|
gap: 6
|
|
1958
2559
|
} }, detail && detail.data && detail.data.address ? h("button", {
|
|
1959
2560
|
style: brandBtn,
|
|
1960
|
-
title: "
|
|
2561
|
+
title: t("panel.goOwnerSessionTip"),
|
|
1961
2562
|
onClick: () => goOwnerSessionAndOpen({
|
|
1962
2563
|
ownerSession: detail.data.ownerSession,
|
|
1963
2564
|
address: detail.data.address,
|
|
1964
2565
|
label: detail.data.id
|
|
1965
2566
|
})
|
|
1966
|
-
}, "
|
|
2567
|
+
}, t("panel.goOwnerSession")) : null, h("button", {
|
|
1967
2568
|
style: panelBtn,
|
|
1968
2569
|
onClick: closeDetail
|
|
1969
|
-
}, "
|
|
2570
|
+
}, t("common.close")))), h(RunDetailPane, {
|
|
1970
2571
|
snap: detail && detail.data,
|
|
1971
2572
|
product: state.current,
|
|
1972
2573
|
api
|
|
@@ -2059,7 +2660,7 @@ window.__ModuleLoader__.load({
|
|
|
2059
2660
|
const usage = stageUsageLine(s);
|
|
2060
2661
|
return h("div", {
|
|
2061
2662
|
key,
|
|
2062
|
-
title:
|
|
2663
|
+
title: t("stage.cardTip", { label: stageLabelOf(s) }),
|
|
2063
2664
|
onMouseDown: (e) => e.stopPropagation(),
|
|
2064
2665
|
onClick: () => onOpen && onOpen(s),
|
|
2065
2666
|
style: {
|
|
@@ -2108,8 +2709,11 @@ window.__ModuleLoader__.load({
|
|
|
2108
2709
|
textOverflow: "ellipsis",
|
|
2109
2710
|
whiteSpace: "nowrap"
|
|
2110
2711
|
}
|
|
2111
|
-
}, s
|
|
2112
|
-
title:
|
|
2712
|
+
}, stageLabelOf(s)), s.attempts && s.attempts.length > 1 ? h("span", {
|
|
2713
|
+
title: t("stage.retryTip", {
|
|
2714
|
+
n: s.attempts.length - 1,
|
|
2715
|
+
m: s.attempts.length
|
|
2716
|
+
}),
|
|
2113
2717
|
style: {
|
|
2114
2718
|
fontFamily: MONO,
|
|
2115
2719
|
fontSize: 10,
|
|
@@ -2256,7 +2860,7 @@ window.__ModuleLoader__.load({
|
|
|
2256
2860
|
});
|
|
2257
2861
|
} catch (e) {}
|
|
2258
2862
|
};
|
|
2259
|
-
const outText = cur && cur.output ? cur.output : cur && cur.summary ?
|
|
2863
|
+
const outText = cur && cur.output ? cur.output : cur && cur.summary ? t("stage.summaryFallback", { summary: cur.summary }) : det.err ? t("stage.loadFailed", { err: det.err }) : det.loading ? t("common.loading") : t("stage.noOutput");
|
|
2260
2864
|
const closeBtn = {
|
|
2261
2865
|
font: "inherit",
|
|
2262
2866
|
width: 26,
|
|
@@ -2318,7 +2922,7 @@ window.__ModuleLoader__.load({
|
|
|
2318
2922
|
textOverflow: "ellipsis",
|
|
2319
2923
|
whiteSpace: "nowrap"
|
|
2320
2924
|
}
|
|
2321
|
-
}, st ? st
|
|
2925
|
+
}, st ? stageLabelOf(st) : t("stage.detailTitle")), h("div", { style: {
|
|
2322
2926
|
fontSize: 10.5,
|
|
2323
2927
|
color: T.text2,
|
|
2324
2928
|
marginTop: 1,
|
|
@@ -2327,7 +2931,7 @@ window.__ModuleLoader__.load({
|
|
|
2327
2931
|
} }, `${st ? `#${st.seq} · ${st.phase}` : ""}${st && (st.startedAt || st.endedAt) ? ` · ${fmtDur(st.startedAt, st.endedAt)}` : ""}`)), st ? chip(stText(st.status), color, { dot: true }) : null, h("button", {
|
|
2328
2932
|
onClick: onClose,
|
|
2329
2933
|
style: closeBtn,
|
|
2330
|
-
title: "
|
|
2934
|
+
title: t("common.close")
|
|
2331
2935
|
}, "✕")), h("div", { style: {
|
|
2332
2936
|
flex: 1,
|
|
2333
2937
|
overflowY: "auto",
|
|
@@ -2344,7 +2948,7 @@ window.__ModuleLoader__.load({
|
|
|
2344
2948
|
fontWeight: 700,
|
|
2345
2949
|
color: T.text2,
|
|
2346
2950
|
letterSpacing: .3
|
|
2347
|
-
} }, "
|
|
2951
|
+
} }, t("token.officialTitle")), h("span", { style: {
|
|
2348
2952
|
fontSize: 11.5,
|
|
2349
2953
|
fontFamily: MONO,
|
|
2350
2954
|
color: T.text,
|
|
@@ -2358,7 +2962,7 @@ window.__ModuleLoader__.load({
|
|
|
2358
2962
|
fontWeight: 700,
|
|
2359
2963
|
color: T.text2,
|
|
2360
2964
|
letterSpacing: .3
|
|
2361
|
-
} },
|
|
2965
|
+
} }, t("stage.attemptHistory", { n: attempts.length })), h("div", { style: {
|
|
2362
2966
|
display: "flex",
|
|
2363
2967
|
flexDirection: "column",
|
|
2364
2968
|
gap: 4
|
|
@@ -2389,7 +2993,7 @@ window.__ModuleLoader__.load({
|
|
|
2389
2993
|
color: aColor,
|
|
2390
2994
|
flex: "0 0 64px",
|
|
2391
2995
|
fontWeight: 700
|
|
2392
|
-
} }, a.status === "done" ? "
|
|
2996
|
+
} }, a.status === "done" ? t("stage.attemptDone") : a.status === "failed" ? t("stage.attemptFailed", { outcome: a.outcome || t("common.failed") }) : t("stage.attemptRunning")), h("span", { style: {
|
|
2393
2997
|
flex: 1,
|
|
2394
2998
|
minWidth: 0,
|
|
2395
2999
|
fontSize: 10.5,
|
|
@@ -2397,7 +3001,7 @@ window.__ModuleLoader__.load({
|
|
|
2397
3001
|
overflow: "hidden",
|
|
2398
3002
|
textOverflow: "ellipsis",
|
|
2399
3003
|
whiteSpace: "nowrap"
|
|
2400
|
-
} }, (a.summary || a.outcome || "
|
|
3004
|
+
} }, (a.summary || a.outcome || t("common.noSummary")).slice(0, 80)), h("span", { style: {
|
|
2401
3005
|
fontFamily: MONO,
|
|
2402
3006
|
fontSize: 10,
|
|
2403
3007
|
color: T.text2,
|
|
@@ -2415,7 +3019,7 @@ window.__ModuleLoader__.load({
|
|
|
2415
3019
|
} }, h("button", {
|
|
2416
3020
|
onClick: openChild,
|
|
2417
3021
|
disabled: !hasChild,
|
|
2418
|
-
title: crossSession ?
|
|
3022
|
+
title: crossSession ? t("stage.childCrossSessionTip", { sid: ownerSession.slice(-6) }) : hasChild ? t("stage.childJumpTip") : t("stage.childNoneTip"),
|
|
2419
3023
|
style: {
|
|
2420
3024
|
font: "inherit",
|
|
2421
3025
|
fontSize: 12,
|
|
@@ -2432,17 +3036,17 @@ window.__ModuleLoader__.load({
|
|
|
2432
3036
|
color: T.brand,
|
|
2433
3037
|
opacity: hasChild ? 1 : .45
|
|
2434
3038
|
}
|
|
2435
|
-
}, "
|
|
3039
|
+
}, t("stage.childJumpBtn")), crossSession ? h("div", { style: {
|
|
2436
3040
|
fontSize: 10.5,
|
|
2437
3041
|
color: T.text2,
|
|
2438
3042
|
textAlign: "center",
|
|
2439
3043
|
lineHeight: 1.55
|
|
2440
|
-
} },
|
|
3044
|
+
} }, t("stage.childCrossSessionNote", { sid: ownerSession ? ownerSession.slice(-6) : "" })) : hasChild ? h("div", { style: {
|
|
2441
3045
|
fontSize: 10.5,
|
|
2442
3046
|
color: T.text2,
|
|
2443
3047
|
textAlign: "center",
|
|
2444
3048
|
lineHeight: 1.55
|
|
2445
|
-
} }, "
|
|
3049
|
+
} }, t("stage.childJumpNote")) : null), st && phaseKeyOf(st.phase) === "dev" ? h("div", { style: {
|
|
2446
3050
|
display: "flex",
|
|
2447
3051
|
flexDirection: "column",
|
|
2448
3052
|
gap: 5
|
|
@@ -2451,7 +3055,7 @@ window.__ModuleLoader__.load({
|
|
|
2451
3055
|
fontWeight: 700,
|
|
2452
3056
|
color: T.text2,
|
|
2453
3057
|
letterSpacing: .3
|
|
2454
|
-
} }, "
|
|
3058
|
+
} }, t("stage.evidenceTitle")), cur && cur.verifyEvidence ? h("div", { style: {
|
|
2455
3059
|
whiteSpace: "pre-wrap",
|
|
2456
3060
|
wordBreak: "break-word",
|
|
2457
3061
|
fontSize: 11.5,
|
|
@@ -2472,7 +3076,7 @@ window.__ModuleLoader__.load({
|
|
|
2472
3076
|
borderRadius: 10,
|
|
2473
3077
|
padding: "8px 12px",
|
|
2474
3078
|
lineHeight: 1.55
|
|
2475
|
-
} }, "
|
|
3079
|
+
} }, t("stage.evidenceMissing"))) : null, h("div", { style: {
|
|
2476
3080
|
display: "flex",
|
|
2477
3081
|
flexDirection: "column",
|
|
2478
3082
|
gap: 5
|
|
@@ -2481,7 +3085,7 @@ window.__ModuleLoader__.load({
|
|
|
2481
3085
|
fontWeight: 700,
|
|
2482
3086
|
color: T.text2,
|
|
2483
3087
|
letterSpacing: .3
|
|
2484
|
-
} }, "
|
|
3088
|
+
} }, t("stage.artifactsTitle")), h("div", { style: {
|
|
2485
3089
|
whiteSpace: "pre-wrap",
|
|
2486
3090
|
wordBreak: "break-word",
|
|
2487
3091
|
fontSize: 12,
|
|
@@ -2504,7 +3108,7 @@ window.__ModuleLoader__.load({
|
|
|
2504
3108
|
} }, h("div", { style: {
|
|
2505
3109
|
fontSize: 28,
|
|
2506
3110
|
marginBottom: 8
|
|
2507
|
-
} }, "🏭"), "
|
|
3111
|
+
} }, "🏭"), t("pipeline.empty"));
|
|
2508
3112
|
const groups = [];
|
|
2509
3113
|
const taskKeyOf = (s) => String(s.taskKey || String(s.label || "").replace(/^开发 · /, "").replace(/((?:第 \d+ 次重试|补跑))$/, "").trim());
|
|
2510
3114
|
for (const st of active.stages || []) {
|
|
@@ -2779,7 +3383,7 @@ window.__ModuleLoader__.load({
|
|
|
2779
3383
|
justifyContent: "center",
|
|
2780
3384
|
color: T.text2,
|
|
2781
3385
|
fontSize: 13
|
|
2782
|
-
} }, "
|
|
3386
|
+
} }, t("pipeline.noNodes")) : null, h("div", {
|
|
2783
3387
|
onMouseDown: (e) => e.stopPropagation(),
|
|
2784
3388
|
style: {
|
|
2785
3389
|
position: "absolute",
|
|
@@ -2797,7 +3401,7 @@ window.__ModuleLoader__.load({
|
|
|
2797
3401
|
boxShadow: "0 6px 20px rgba(0,0,0,.16)"
|
|
2798
3402
|
}
|
|
2799
3403
|
}, h("button", {
|
|
2800
|
-
title: "
|
|
3404
|
+
title: t("pipeline.zoomOut"),
|
|
2801
3405
|
onClick: () => zoomBy(.86),
|
|
2802
3406
|
style: zoomStyle
|
|
2803
3407
|
}, "−"), h("span", { style: {
|
|
@@ -2807,7 +3411,7 @@ window.__ModuleLoader__.load({
|
|
|
2807
3411
|
minWidth: 34,
|
|
2808
3412
|
textAlign: "center"
|
|
2809
3413
|
} }, `${Math.round(view.s * 100)}%`), h("button", {
|
|
2810
|
-
title: "
|
|
3414
|
+
title: t("pipeline.zoomIn"),
|
|
2811
3415
|
onClick: () => zoomBy(1.16),
|
|
2812
3416
|
style: zoomStyle
|
|
2813
3417
|
}, "+"), h("span", { style: {
|
|
@@ -2815,7 +3419,7 @@ window.__ModuleLoader__.load({
|
|
|
2815
3419
|
height: 14,
|
|
2816
3420
|
background: T.border
|
|
2817
3421
|
} }), h("button", {
|
|
2818
|
-
title: "
|
|
3422
|
+
title: t("pipeline.fitCanvas"),
|
|
2819
3423
|
onClick: fitNow,
|
|
2820
3424
|
style: {
|
|
2821
3425
|
...zoomStyle,
|
|
@@ -2830,7 +3434,7 @@ window.__ModuleLoader__.load({
|
|
|
2830
3434
|
color: T.text2,
|
|
2831
3435
|
paddingRight: 4,
|
|
2832
3436
|
opacity: .85
|
|
2833
|
-
} }, "
|
|
3437
|
+
} }, t("pipeline.canvasHint"))), det ? h(StageDetailDrawer, {
|
|
2834
3438
|
det,
|
|
2835
3439
|
onClose: closeDet,
|
|
2836
3440
|
sessionId,
|
|
@@ -2876,12 +3480,12 @@ window.__ModuleLoader__.load({
|
|
|
2876
3480
|
} }, h("div", { style: {
|
|
2877
3481
|
fontSize: 28,
|
|
2878
3482
|
marginBottom: 8
|
|
2879
|
-
} }, "📋"), "
|
|
3483
|
+
} }, "📋"), t("board.empty"));
|
|
2880
3484
|
const subtaskMap = {};
|
|
2881
3485
|
for (const t of backlog.tasks || []) if (t.type === "subtask" && t.id) subtaskMap[t.id] = t;
|
|
2882
3486
|
const move = async (kind, id, to) => {
|
|
2883
3487
|
try {
|
|
2884
|
-
await api.backlogUpdate(kind, id, to, sessionId, "
|
|
3488
|
+
await api.backlogUpdate(kind, id, to, sessionId, t("board.dragReason"));
|
|
2885
3489
|
} catch (e) {}
|
|
2886
3490
|
onRefresh();
|
|
2887
3491
|
};
|
|
@@ -2911,7 +3515,11 @@ window.__ModuleLoader__.load({
|
|
|
2911
3515
|
transition: "opacity .1s ease, transform .12s ease",
|
|
2912
3516
|
boxShadow: "0 1px 2px rgba(0,0,0,.05)"
|
|
2913
3517
|
},
|
|
2914
|
-
title:
|
|
3518
|
+
title: t("board.cardTip", {
|
|
3519
|
+
id: item.id,
|
|
3520
|
+
status: item.status,
|
|
3521
|
+
summary: item.summary ? "\n" + item.summary : ""
|
|
3522
|
+
})
|
|
2915
3523
|
}, h("div", { style: {
|
|
2916
3524
|
display: "flex",
|
|
2917
3525
|
alignItems: "center",
|
|
@@ -2961,7 +3569,7 @@ window.__ModuleLoader__.load({
|
|
|
2961
3569
|
fontFamily: MONO,
|
|
2962
3570
|
minWidth: 0
|
|
2963
3571
|
} }, item.devAssign ? h("span", {
|
|
2964
|
-
title:
|
|
3572
|
+
title: t("board.assignDevTip", { who: item.devAssign }),
|
|
2965
3573
|
style: {
|
|
2966
3574
|
display: "inline-flex",
|
|
2967
3575
|
alignItems: "center",
|
|
@@ -2973,7 +3581,7 @@ window.__ModuleLoader__.load({
|
|
|
2973
3581
|
whiteSpace: "nowrap"
|
|
2974
3582
|
}
|
|
2975
3583
|
}, `👨💻${item.devAssign}`) : null, item.qaAssign ? h("span", {
|
|
2976
|
-
title:
|
|
3584
|
+
title: t("board.assignQaTip", { who: item.qaAssign }),
|
|
2977
3585
|
style: {
|
|
2978
3586
|
display: "inline-flex",
|
|
2979
3587
|
alignItems: "center",
|
|
@@ -2985,7 +3593,7 @@ window.__ModuleLoader__.load({
|
|
|
2985
3593
|
whiteSpace: "nowrap"
|
|
2986
3594
|
}
|
|
2987
3595
|
}, `🧪${item.qaAssign}`) : null, item.acceptBy ? h("span", {
|
|
2988
|
-
title:
|
|
3596
|
+
title: t("board.acceptTip", { who: item.acceptBy }),
|
|
2989
3597
|
style: {
|
|
2990
3598
|
display: "inline-flex",
|
|
2991
3599
|
alignItems: "center",
|
|
@@ -3027,7 +3635,7 @@ window.__ModuleLoader__.load({
|
|
|
3027
3635
|
color: T.text2,
|
|
3028
3636
|
fontFamily: MONO,
|
|
3029
3637
|
marginBottom: 3
|
|
3030
|
-
} }, h("span", null,
|
|
3638
|
+
} }, h("span", null, t("board.subtaskCount", { n: subs.length })), done > 0 ? h("span", { style: { color: T.success } }, `${done}✓`) : null, running > 0 ? h("span", { style: { color: T.brand } }, `${running}⟳`) : null, failed > 0 ? h("span", { style: { color: T.error } }, `${failed}✗`) : null), subs.map((sub) => h("div", {
|
|
3031
3639
|
key: sub.id,
|
|
3032
3640
|
style: {
|
|
3033
3641
|
display: "flex",
|
|
@@ -3057,7 +3665,7 @@ window.__ModuleLoader__.load({
|
|
|
3057
3665
|
whiteSpace: "nowrap"
|
|
3058
3666
|
}
|
|
3059
3667
|
}, (sub.title || "").replace(/^开发 · /, "")), sub.devAssign ? h("span", {
|
|
3060
|
-
title:
|
|
3668
|
+
title: t("board.assignDevTip", { who: sub.devAssign }),
|
|
3061
3669
|
style: {
|
|
3062
3670
|
flex: "0 1 auto",
|
|
3063
3671
|
color: T.text2,
|
|
@@ -3112,7 +3720,7 @@ window.__ModuleLoader__.load({
|
|
|
3112
3720
|
fontWeight: 700,
|
|
3113
3721
|
fontSize: 13,
|
|
3114
3722
|
padding: "6px 0 8px"
|
|
3115
|
-
} }, h("span", { style: { fontSize: 14 } }, kind === "req" ? "📌" : kind === "task" ? "🔧" : "🐞"),
|
|
3723
|
+
} }, h("span", { style: { fontSize: 14 } }, kind === "req" ? "📌" : kind === "task" ? "🔧" : "🐞"), kindTitle(kind), h("span", { style: {
|
|
3116
3724
|
fontSize: 11,
|
|
3117
3725
|
fontWeight: 600,
|
|
3118
3726
|
color: T.text2,
|
|
@@ -3188,7 +3796,7 @@ window.__ModuleLoader__.load({
|
|
|
3188
3796
|
}) : null);
|
|
3189
3797
|
}
|
|
3190
3798
|
function fmtAt(ts) {
|
|
3191
|
-
return ts ? new Date(ts).toLocaleTimeString(
|
|
3799
|
+
return ts ? new Date(ts).toLocaleTimeString(localeTag(), {
|
|
3192
3800
|
hour: "2-digit",
|
|
3193
3801
|
minute: "2-digit"
|
|
3194
3802
|
}) : "—";
|
|
@@ -3266,7 +3874,7 @@ window.__ModuleLoader__.load({
|
|
|
3266
3874
|
color: T.warn,
|
|
3267
3875
|
flex: "0 0 auto"
|
|
3268
3876
|
} }, `⛽${fmtTokens((extra.usage.input || 0) + (extra.usage.cacheRead || 0) + (extra.usage.cacheWrite || 0) + (extra.usage.output || 0))}`) : null, extra && extra.assignee ? h("span", {
|
|
3269
|
-
title:
|
|
3877
|
+
title: t("board.assignDevTip", { who: extra.assignee }),
|
|
3270
3878
|
style: {
|
|
3271
3879
|
display: "inline-flex",
|
|
3272
3880
|
alignItems: "center",
|
|
@@ -3345,7 +3953,7 @@ window.__ModuleLoader__.load({
|
|
|
3345
3953
|
} }, `${d.id} · ${d.kind}${d.severity ? " · " + d.severity : ""}`) : null), d ? chip(stText(d.status), color, { dot: true }) : null, h("button", {
|
|
3346
3954
|
onClick: onClose,
|
|
3347
3955
|
style: closeBtn,
|
|
3348
|
-
title: "
|
|
3956
|
+
title: t("common.close")
|
|
3349
3957
|
}, "✕")), h("div", { style: {
|
|
3350
3958
|
flex: 1,
|
|
3351
3959
|
overflowY: "auto",
|
|
@@ -3357,7 +3965,7 @@ window.__ModuleLoader__.load({
|
|
|
3357
3965
|
color: T.text2,
|
|
3358
3966
|
fontSize: 12,
|
|
3359
3967
|
padding: 12
|
|
3360
|
-
} }, "
|
|
3968
|
+
} }, t("common.loading")) : err ? h("div", { style: {
|
|
3361
3969
|
color: T.error,
|
|
3362
3970
|
fontSize: 12,
|
|
3363
3971
|
padding: 12
|
|
@@ -3366,7 +3974,7 @@ window.__ModuleLoader__.load({
|
|
|
3366
3974
|
display: "flex",
|
|
3367
3975
|
flexDirection: "column",
|
|
3368
3976
|
gap: 4
|
|
3369
|
-
} }, secTitle("
|
|
3977
|
+
} }, secTitle(t("item.overview")), d.spec ? h(FoldableText, {
|
|
3370
3978
|
text: d.spec,
|
|
3371
3979
|
charLimit: 300,
|
|
3372
3980
|
lineLimit: 4,
|
|
@@ -3384,7 +3992,28 @@ window.__ModuleLoader__.load({
|
|
|
3384
3992
|
flexDirection: "column",
|
|
3385
3993
|
gap: 2,
|
|
3386
3994
|
marginTop: 2
|
|
3387
|
-
} }, d.devAssign ? kv("👨💻 dev", d.devAssign.slice(0, 26), true) : null, d.qaAssign ? kv("🧪 qa", d.qaAssign.slice(0, 26), true) : null, d.assignBy ? kv("
|
|
3995
|
+
} }, d.devAssign ? kv("👨💻 dev", d.devAssign.slice(0, 26), true) : null, d.qaAssign ? kv("🧪 qa", d.qaAssign.slice(0, 26), true) : null, d.assignBy ? kv(t("item.acceptRow"), d.assignBy.slice(0, 26), true) : null, d.owner ? kv("👤 owner", d.owner.slice(0, 26), true) : null, typeof d.retries === "number" && d.retries > 0 ? kv(t("item.retryRow"), String(d.retries)) : null, d.humanIntervention ? kv(t("item.humanRow"), t("common.needsHuman")) : null, kv(t("item.updatedAt"), fmtAt(d.updatedAt) || "—"))),
|
|
3996
|
+
kind === "bug" ? h("div", { style: {
|
|
3997
|
+
display: "flex",
|
|
3998
|
+
flexDirection: "column",
|
|
3999
|
+
gap: 4,
|
|
4000
|
+
padding: "8px 10px",
|
|
4001
|
+
borderRadius: 8,
|
|
4002
|
+
background: T.layer2,
|
|
4003
|
+
border: `1px solid ${T.border}`
|
|
4004
|
+
} }, secTitle(t("panelItem.defectSection")), d.spec ? h(FoldableText, {
|
|
4005
|
+
text: d.spec,
|
|
4006
|
+
charLimit: 300,
|
|
4007
|
+
lineLimit: 4
|
|
4008
|
+
}) : null, h("div", { style: {
|
|
4009
|
+
display: "flex",
|
|
4010
|
+
flexDirection: "column",
|
|
4011
|
+
gap: 2
|
|
4012
|
+
} }, d.defectId ? kv(t("panelItem.row.defectId"), String(d.defectId)) : null, d.severity ? kv(t("panelItem.row.severity"), String(d.severity)) : null, d.module ? kv(t("panelItem.row.module"), String(d.module)) : null, d.reproduce ? kv(t("panelItem.row.reproduce"), String(d.reproduce)) : null, d.expected ? kv(t("panelItem.row.expected"), String(d.expected)) : null, d.actual ? kv(t("panelItem.row.actual"), String(d.actual)) : null, d.defectCheck ? kv(t("panelItem.row.defectCheck"), String(d.defectCheck)) : null, d.defectCriterion ? kv(t("panelItem.row.defectCriterion"), String(d.defectCriterion)) : null, d.defectAc ? kv(t("panelItem.row.defectAc"), String(d.defectAc)) : null), d.reproduce || d.expected || d.actual ? null : h("div", { style: {
|
|
4013
|
+
fontSize: 10.5,
|
|
4014
|
+
color: T.warn,
|
|
4015
|
+
lineHeight: 1.5
|
|
4016
|
+
} }, t("panelItem.noDefectDetail"))) : null,
|
|
3388
4017
|
d.runInfo ? (() => {
|
|
3389
4018
|
const ri = d.runInfo;
|
|
3390
4019
|
return h("div", { style: {
|
|
@@ -3399,14 +4028,14 @@ window.__ModuleLoader__.load({
|
|
|
3399
4028
|
display: "flex",
|
|
3400
4029
|
alignItems: "center",
|
|
3401
4030
|
gap: 8
|
|
3402
|
-
} }, secTitle("
|
|
4031
|
+
} }, secTitle(t("item.runSection")), h("span", { style: {
|
|
3403
4032
|
fontFamily: MONO,
|
|
3404
4033
|
fontSize: 10.5,
|
|
3405
4034
|
color: T.text2,
|
|
3406
4035
|
whiteSpace: "nowrap"
|
|
3407
4036
|
} }, ri.runId), chip(stText(ri.status), stColor(ri.status)), onShowRun ? h("button", {
|
|
3408
4037
|
onClick: () => onShowRun(ri.runId),
|
|
3409
|
-
title:
|
|
4038
|
+
title: t("item.jumpRunTip", { id: String(ri.runId).slice(-6) }),
|
|
3410
4039
|
style: {
|
|
3411
4040
|
marginLeft: "auto",
|
|
3412
4041
|
flex: "0 0 auto",
|
|
@@ -3421,7 +4050,7 @@ window.__ModuleLoader__.load({
|
|
|
3421
4050
|
color: T.brand,
|
|
3422
4051
|
lineHeight: "16px"
|
|
3423
4052
|
}
|
|
3424
|
-
}, "
|
|
4053
|
+
}, t("item.runBtn")) : null), ri.startedAt || ri.endedAt ? h("span", { style: {
|
|
3425
4054
|
fontSize: 10.5,
|
|
3426
4055
|
color: T.text2,
|
|
3427
4056
|
fontFamily: MONO
|
|
@@ -3429,8 +4058,8 @@ window.__ModuleLoader__.load({
|
|
|
3429
4058
|
display: "flex",
|
|
3430
4059
|
flexDirection: "column",
|
|
3431
4060
|
gap: 4
|
|
3432
|
-
} }, secTitle("
|
|
3433
|
-
text: ri.requirement || "
|
|
4061
|
+
} }, secTitle(t("item.requirement")), h(FoldableText, {
|
|
4062
|
+
text: ri.requirement || t("item.noRequirement"),
|
|
3434
4063
|
charLimit: 300,
|
|
3435
4064
|
lineLimit: 4,
|
|
3436
4065
|
style: {
|
|
@@ -3444,7 +4073,7 @@ window.__ModuleLoader__.load({
|
|
|
3444
4073
|
display: "flex",
|
|
3445
4074
|
flexDirection: "column",
|
|
3446
4075
|
gap: 4
|
|
3447
|
-
} }, secTitle("
|
|
4076
|
+
} }, secTitle(t("item.runDocs")), h("div", { style: {
|
|
3448
4077
|
fontSize: 11.5,
|
|
3449
4078
|
fontFamily: MONO,
|
|
3450
4079
|
color: T.brand,
|
|
@@ -3462,7 +4091,7 @@ window.__ModuleLoader__.load({
|
|
|
3462
4091
|
onClick: () => {
|
|
3463
4092
|
if (openArtifact) openArtifact(a.address, a.name);
|
|
3464
4093
|
},
|
|
3465
|
-
title:
|
|
4094
|
+
title: t("item.previewTip", { path: `${d.runDocs}/${a.name}` }),
|
|
3466
4095
|
style: {
|
|
3467
4096
|
fontSize: 10.5,
|
|
3468
4097
|
fontWeight: 600,
|
|
@@ -3480,7 +4109,7 @@ window.__ModuleLoader__.load({
|
|
|
3480
4109
|
display: "flex",
|
|
3481
4110
|
flexDirection: "column",
|
|
3482
4111
|
gap: 4
|
|
3483
|
-
} }, secTitle("
|
|
4112
|
+
} }, secTitle(t("token.officialTitle")), h("span", { style: {
|
|
3484
4113
|
fontSize: 11.5,
|
|
3485
4114
|
fontFamily: MONO,
|
|
3486
4115
|
color: T.text,
|
|
@@ -3492,7 +4121,7 @@ window.__ModuleLoader__.load({
|
|
|
3492
4121
|
marginTop: 2
|
|
3493
4122
|
} }, Object.entries(d.byRole).sort((a, b) => totalTokens(b[1]) - totalTokens(a[1])).map(([role, uRaw]) => {
|
|
3494
4123
|
const u = uRaw;
|
|
3495
|
-
const label = role
|
|
4124
|
+
const label = roleChip(role);
|
|
3496
4125
|
return h("div", {
|
|
3497
4126
|
key: role,
|
|
3498
4127
|
style: {
|
|
@@ -3503,13 +4132,13 @@ window.__ModuleLoader__.load({
|
|
|
3503
4132
|
fontFamily: MONO,
|
|
3504
4133
|
color: T.text2
|
|
3505
4134
|
}
|
|
3506
|
-
}, h("span", { style: { flex: "0 0 64px" } }, label), h("span", { style: { color: T.text } }, `⛽${fmtTokens(totalTokens(u))}`), h("span", null, `${fmtTokens(u.input || 0)}i / ${fmtTokens(u.cacheRead || 0)}c / ${fmtTokens(u.output || 0)}o · ${u.calls || 0}
|
|
4135
|
+
}, h("span", { style: { flex: "0 0 64px" } }, label), h("span", { style: { color: T.text } }, `⛽${fmtTokens(totalTokens(u))}`), h("span", null, `${fmtTokens(u.input || 0)}i / ${fmtTokens(u.cacheRead || 0)}c / ${fmtTokens(u.output || 0)}o · ${t("common.calls", { n: u.calls || 0 })}`));
|
|
3507
4136
|
})) : null) : null,
|
|
3508
4137
|
d.subtasks && d.subtasks.length > 0 ? h("div", { style: {
|
|
3509
4138
|
display: "flex",
|
|
3510
4139
|
flexDirection: "column",
|
|
3511
4140
|
gap: 4
|
|
3512
|
-
} }, secTitle(
|
|
4141
|
+
} }, secTitle(t("item.subtasks", { n: d.subtasks.length })), h("div", { style: {
|
|
3513
4142
|
display: "flex",
|
|
3514
4143
|
flexDirection: "column",
|
|
3515
4144
|
gap: 5
|
|
@@ -3521,7 +4150,7 @@ window.__ModuleLoader__.load({
|
|
|
3521
4150
|
display: "flex",
|
|
3522
4151
|
flexDirection: "column",
|
|
3523
4152
|
gap: 4
|
|
3524
|
-
} }, secTitle(
|
|
4153
|
+
} }, secTitle(t("item.bugs", { n: d.bugs.length })), h("div", { style: {
|
|
3525
4154
|
display: "flex",
|
|
3526
4155
|
flexDirection: "column",
|
|
3527
4156
|
gap: 5
|
|
@@ -3530,7 +4159,7 @@ window.__ModuleLoader__.load({
|
|
|
3530
4159
|
display: "flex",
|
|
3531
4160
|
flexDirection: "column",
|
|
3532
4161
|
gap: 4
|
|
3533
|
-
} }, secTitle(
|
|
4162
|
+
} }, secTitle(t("item.timeline", { n: d.events.length })), h("div", { style: {
|
|
3534
4163
|
display: "flex",
|
|
3535
4164
|
flexDirection: "column",
|
|
3536
4165
|
gap: 0
|
|
@@ -3566,7 +4195,7 @@ window.__ModuleLoader__.load({
|
|
|
3566
4195
|
}, ev.reason || ""))))) : null
|
|
3567
4196
|
]));
|
|
3568
4197
|
}
|
|
3569
|
-
function TeamSelector({ sessionId, remote }) {
|
|
4198
|
+
function TeamSelector({ sessionId, remote, locale }) {
|
|
3570
4199
|
const [teams, setTeams] = react.default.useState([]);
|
|
3571
4200
|
const [active, setActive] = react.default.useState(null);
|
|
3572
4201
|
const [open, setOpen] = react.default.useState(false);
|
|
@@ -3579,7 +4208,11 @@ window.__ModuleLoader__.load({
|
|
|
3579
4208
|
const at = unwrap(await remote.getActiveTeam(sessionId), "getActiveTeam");
|
|
3580
4209
|
setActive(at && at.team ? at.team : null);
|
|
3581
4210
|
} catch (e) {}
|
|
3582
|
-
}, [
|
|
4211
|
+
}, [
|
|
4212
|
+
remote,
|
|
4213
|
+
sessionId,
|
|
4214
|
+
locale
|
|
4215
|
+
]);
|
|
3583
4216
|
react.default.useEffect(() => {
|
|
3584
4217
|
load();
|
|
3585
4218
|
}, [load]);
|
|
@@ -3610,7 +4243,7 @@ window.__ModuleLoader__.load({
|
|
|
3610
4243
|
style: { position: "relative" }
|
|
3611
4244
|
}, h("button", {
|
|
3612
4245
|
onClick: () => setOpen(!open),
|
|
3613
|
-
title: active ?
|
|
4246
|
+
title: active ? t("team.currentTip", { name: active.name }) : t("team.pick"),
|
|
3614
4247
|
style: {
|
|
3615
4248
|
display: "inline-flex",
|
|
3616
4249
|
alignItems: "center",
|
|
@@ -3627,14 +4260,14 @@ window.__ModuleLoader__.load({
|
|
|
3627
4260
|
transition: "all .12s ease"
|
|
3628
4261
|
}
|
|
3629
4262
|
}, h("span", { style: { fontSize: 12 } }, active ? active.icon : "🏭"), h("span", {
|
|
3630
|
-
title: active && active.name ? String(active.name) : "
|
|
4263
|
+
title: active && active.name ? String(active.name) : t("team.label"),
|
|
3631
4264
|
style: {
|
|
3632
4265
|
maxWidth: 80,
|
|
3633
4266
|
overflow: "hidden",
|
|
3634
4267
|
textOverflow: "ellipsis",
|
|
3635
4268
|
whiteSpace: "nowrap"
|
|
3636
4269
|
}
|
|
3637
|
-
}, active ? active.name : "
|
|
4270
|
+
}, active ? active.name : t("team.label")), h("span", { style: {
|
|
3638
4271
|
fontSize: 8,
|
|
3639
4272
|
opacity: .6
|
|
3640
4273
|
} }, open ? "▲" : "▼")), open ? h("div", { style: {
|
|
@@ -3654,7 +4287,7 @@ window.__ModuleLoader__.load({
|
|
|
3654
4287
|
fontSize: 10,
|
|
3655
4288
|
color: T.text2,
|
|
3656
4289
|
borderBottom: `1px solid ${T.border}`
|
|
3657
|
-
} }, "
|
|
4290
|
+
} }, t("team.pick")), h("button", {
|
|
3658
4291
|
onClick: () => select(null),
|
|
3659
4292
|
style: {
|
|
3660
4293
|
display: "flex",
|
|
@@ -3683,14 +4316,14 @@ window.__ModuleLoader__.load({
|
|
|
3683
4316
|
} }, h("div", { style: {
|
|
3684
4317
|
fontWeight: 600,
|
|
3685
4318
|
lineHeight: 1.35
|
|
3686
|
-
} }, "
|
|
4319
|
+
} }, t("team.none")), h("div", { style: {
|
|
3687
4320
|
fontSize: 10.5,
|
|
3688
4321
|
color: T.text2,
|
|
3689
4322
|
marginTop: 3,
|
|
3690
4323
|
lineHeight: 1.45,
|
|
3691
4324
|
whiteSpace: "normal",
|
|
3692
4325
|
wordBreak: "break-word"
|
|
3693
|
-
} }, "
|
|
4326
|
+
} }, t("team.noneNote"))), !active ? h("span", { style: {
|
|
3694
4327
|
marginLeft: "auto",
|
|
3695
4328
|
color: T.text2,
|
|
3696
4329
|
fontSize: 12,
|
|
@@ -3739,7 +4372,10 @@ window.__ModuleLoader__.load({
|
|
|
3739
4372
|
}
|
|
3740
4373
|
/** 解包 remote 信封:失败抛错;成功返回 value。 */
|
|
3741
4374
|
function unwrap(res, what) {
|
|
3742
|
-
if (!res || !res.ok) throw new Error(
|
|
4375
|
+
if (!res || !res.ok) throw new Error(t("common.remoteCallFailed", {
|
|
4376
|
+
what: what || "remote",
|
|
4377
|
+
detail: res && res.error && (res.error.message || res.error.code) || t("common.unknownError")
|
|
4378
|
+
}));
|
|
3743
4379
|
return res.value;
|
|
3744
4380
|
}
|
|
3745
4381
|
function TeamFlowView(props) {
|
|
@@ -3758,7 +4394,7 @@ window.__ModuleLoader__.load({
|
|
|
3758
4394
|
if (!api) {
|
|
3759
4395
|
setState((s) => ({
|
|
3760
4396
|
...s,
|
|
3761
|
-
err: "
|
|
4397
|
+
err: t("common.remoteNotReady")
|
|
3762
4398
|
}));
|
|
3763
4399
|
return;
|
|
3764
4400
|
}
|
|
@@ -3887,7 +4523,7 @@ window.__ModuleLoader__.load({
|
|
|
3887
4523
|
fontWeight: 700,
|
|
3888
4524
|
fontSize: 14,
|
|
3889
4525
|
lineHeight: "18px"
|
|
3890
|
-
} }, "
|
|
4526
|
+
} }, t("workbench.title")), h("span", { style: {
|
|
3891
4527
|
fontSize: 11,
|
|
3892
4528
|
color: T.text2,
|
|
3893
4529
|
display: "flex",
|
|
@@ -3900,7 +4536,7 @@ window.__ModuleLoader__.load({
|
|
|
3900
4536
|
display: "inline-block",
|
|
3901
4537
|
background: anyRunning ? T.success : T.text2,
|
|
3902
4538
|
animation: anyRunning ? "tf-pulse 1.6s ease-in-out infinite" : "none"
|
|
3903
|
-
} }), anyRunning ? "
|
|
4539
|
+
} }), anyRunning ? t("workbench.running") : t("workbench.idle"))), h("button", {
|
|
3904
4540
|
onClick: refresh,
|
|
3905
4541
|
style: {
|
|
3906
4542
|
...btn,
|
|
@@ -3909,10 +4545,13 @@ window.__ModuleLoader__.load({
|
|
|
3909
4545
|
alignItems: "center",
|
|
3910
4546
|
gap: 5
|
|
3911
4547
|
}
|
|
3912
|
-
}, "
|
|
4548
|
+
}, t("workbench.refresh")), canResume ? h("button", {
|
|
3913
4549
|
onClick: onResume,
|
|
3914
4550
|
disabled: busy,
|
|
3915
|
-
title:
|
|
4551
|
+
title: t("workbench.resumeTip", {
|
|
4552
|
+
id: activeRun.id,
|
|
4553
|
+
status: runStatusText(activeRun.status)
|
|
4554
|
+
}),
|
|
3916
4555
|
style: {
|
|
3917
4556
|
...btn,
|
|
3918
4557
|
background: T.error,
|
|
@@ -3920,14 +4559,14 @@ window.__ModuleLoader__.load({
|
|
|
3920
4559
|
border: "none",
|
|
3921
4560
|
fontWeight: 600
|
|
3922
4561
|
}
|
|
3923
|
-
}, busy ? "
|
|
4562
|
+
}, busy ? t("workbench.resuming") : t("workbench.resumeBtn", { id: String(activeRun.id).slice(-6) })) : null), err ? h("div", { style: {
|
|
3924
4563
|
color: T.error,
|
|
3925
4564
|
fontSize: 12,
|
|
3926
4565
|
background: `color-mix(in srgb, ${T.error} 8%, transparent)`,
|
|
3927
4566
|
border: `1px solid color-mix(in srgb, ${T.error} 30%, transparent)`,
|
|
3928
4567
|
borderRadius: 8,
|
|
3929
4568
|
padding: "7px 11px"
|
|
3930
|
-
} },
|
|
4569
|
+
} }, t("workbench.loadFailed", { err })) : null, needHuman.length > 0 ? h("div", { style: {
|
|
3931
4570
|
display: "flex",
|
|
3932
4571
|
alignItems: "center",
|
|
3933
4572
|
gap: 10,
|
|
@@ -3940,13 +4579,13 @@ window.__ModuleLoader__.load({
|
|
|
3940
4579
|
fontWeight: 700,
|
|
3941
4580
|
color: T.warn,
|
|
3942
4581
|
fontSize: 12.5
|
|
3943
|
-
} },
|
|
4582
|
+
} }, t("workbench.needsHumanBanner", { n: needHuman.length })), needHuman.slice(0, 5).map((item) => {
|
|
3944
4583
|
const kind = (backlog.requirements || []).some((r) => r.id === item.id) ? "req" : (backlog.tasks || []).some((t) => t.id === item.id) ? "task" : "bug";
|
|
3945
4584
|
const fin = kind === "bug" ? "verified" : "accepted";
|
|
3946
4585
|
return h("button", {
|
|
3947
4586
|
key: item.id,
|
|
3948
4587
|
onClick: async () => {
|
|
3949
|
-
await api.backlogUpdate(kind, item.id, fin, props.sessionId, "
|
|
4588
|
+
await api.backlogUpdate(kind, item.id, fin, props.sessionId, t("workbench.manualReason"));
|
|
3950
4589
|
refresh();
|
|
3951
4590
|
},
|
|
3952
4591
|
style: {
|
|
@@ -3956,7 +4595,7 @@ window.__ModuleLoader__.load({
|
|
|
3956
4595
|
border: "none",
|
|
3957
4596
|
fontWeight: 600
|
|
3958
4597
|
}
|
|
3959
|
-
},
|
|
4598
|
+
}, t("workbench.handle", { id: item.id }));
|
|
3960
4599
|
})) : null, h("div", { style: {
|
|
3961
4600
|
display: "flex",
|
|
3962
4601
|
alignItems: "center",
|
|
@@ -3965,10 +4604,10 @@ window.__ModuleLoader__.load({
|
|
|
3965
4604
|
} }, h("button", {
|
|
3966
4605
|
onClick: () => setTab("pipeline"),
|
|
3967
4606
|
style: tabBtn(tab === "pipeline")
|
|
3968
|
-
}, "
|
|
4607
|
+
}, t("workbench.tabPipeline")), h("button", {
|
|
3969
4608
|
onClick: () => setTab("board"),
|
|
3970
4609
|
style: tabBtn(tab === "board")
|
|
3971
|
-
}, "
|
|
4610
|
+
}, t("workbench.tabBoard")), h("div", { style: {
|
|
3972
4611
|
marginLeft: "auto",
|
|
3973
4612
|
display: "flex",
|
|
3974
4613
|
alignItems: "center",
|
|
@@ -3984,14 +4623,14 @@ window.__ModuleLoader__.load({
|
|
|
3984
4623
|
color: activeRun.status === "interrupted" ? T.warn : T.text2,
|
|
3985
4624
|
border: `1px solid ${T.border}`
|
|
3986
4625
|
}
|
|
3987
|
-
}, `#${String(activeRun.id).slice(-8)} · ${
|
|
4626
|
+
}, `#${String(activeRun.id).slice(-8)} · ${runStatusText(activeRun.status)}`) : null, total && total.input + total.cacheRead + total.cacheWrite + total.output > 0 ? h("span", {
|
|
3988
4627
|
style: {
|
|
3989
4628
|
fontSize: 11.5,
|
|
3990
4629
|
fontFamily: MONO,
|
|
3991
4630
|
color: T.text2,
|
|
3992
4631
|
cursor: "help"
|
|
3993
4632
|
},
|
|
3994
|
-
title: "
|
|
4633
|
+
title: t("token.allStagesTip")
|
|
3995
4634
|
}, `∑ ⇅${fmtTokens(total.input)}/⇅${fmtTokens(total.cacheRead)}·⬆${fmtTokens(total.output)}`) : null)), h("div", { style: {
|
|
3996
4635
|
display: "flex",
|
|
3997
4636
|
alignItems: "center",
|
|
@@ -3999,7 +4638,7 @@ window.__ModuleLoader__.load({
|
|
|
3999
4638
|
fontSize: 12,
|
|
4000
4639
|
flexWrap: "wrap"
|
|
4001
4640
|
} }, h("span", {
|
|
4002
|
-
title:
|
|
4641
|
+
title: t("workbench.workspaceTip", { path: workspace && workspace.path || t("workbench.noWorkspace") }),
|
|
4003
4642
|
style: {
|
|
4004
4643
|
display: "inline-flex",
|
|
4005
4644
|
alignItems: "center",
|
|
@@ -4024,7 +4663,7 @@ window.__ModuleLoader__.load({
|
|
|
4024
4663
|
display: "flex",
|
|
4025
4664
|
alignItems: "center",
|
|
4026
4665
|
gap: 5
|
|
4027
|
-
} }, h("span", { style: { color: T.text2 } }, "
|
|
4666
|
+
} }, h("span", { style: { color: T.text2 } }, t("workbench.history")), runs.length ? runs.map((r) => {
|
|
4028
4667
|
const sel = r.id === (runId || runs[0] && runs[0].id);
|
|
4029
4668
|
return h("button", {
|
|
4030
4669
|
key: r.id,
|
|
@@ -4035,13 +4674,13 @@ window.__ModuleLoader__.load({
|
|
|
4035
4674
|
}) : h("span", { style: {
|
|
4036
4675
|
color: T.text2,
|
|
4037
4676
|
fontSize: 11.5
|
|
4038
|
-
} }, "
|
|
4677
|
+
} }, t("common.noneDash"))) : null, tab === "pipeline" && activeRun && activeRun.address ? h("button", {
|
|
4039
4678
|
style: chipBtn(false),
|
|
4040
|
-
title: "
|
|
4679
|
+
title: t("workbench.openRightBarTip"),
|
|
4041
4680
|
onClick: () => {
|
|
4042
4681
|
if (!(props.openResource && props.openResource(activeRun.address, activeRun.id))) console.warn("[teamflow] 右侧栏不可用,run 详情请在画布节点里查看");
|
|
4043
4682
|
}
|
|
4044
|
-
}, "
|
|
4683
|
+
}, t("workbench.openRightBarBtn")) : null), h("div", { style: {
|
|
4045
4684
|
flex: 1,
|
|
4046
4685
|
minHeight: 0,
|
|
4047
4686
|
display: "flex",
|
|
@@ -4082,6 +4721,24 @@ window.__ModuleLoader__.load({
|
|
|
4082
4721
|
async function apply(ctx) {
|
|
4083
4722
|
await ctx.remote.$mount(TEAMFLOW_REMOTE_CONTRIBUTION);
|
|
4084
4723
|
const teamflow = ctx.get("remote.teamflow");
|
|
4724
|
+
const t = ctx.locale.bind(NS);
|
|
4725
|
+
ctx.effect(() => ctx.locale.register(NS, {
|
|
4726
|
+
zh,
|
|
4727
|
+
en
|
|
4728
|
+
}), "teamflow: dictionaries");
|
|
4729
|
+
ctx.effect(() => ctx.locale.subscribe(() => setTranslator(t, () => ctx.locale.getSnapshot().active)), "teamflow: translator sync");
|
|
4730
|
+
setTranslator(t, () => ctx.locale.getSnapshot().active);
|
|
4731
|
+
const pushLocaleToHost = (active) => {
|
|
4732
|
+
try {
|
|
4733
|
+
if (typeof active !== "string" || !active) return;
|
|
4734
|
+
const p = teamflow.setLocale(active);
|
|
4735
|
+
if (p && typeof p.catch === "function") p.catch(() => {});
|
|
4736
|
+
} catch (e) {}
|
|
4737
|
+
};
|
|
4738
|
+
ctx.effect(() => {
|
|
4739
|
+
pushLocaleToHost(ctx.locale.getSnapshot().active);
|
|
4740
|
+
return ctx.locale.subscribe(() => pushLocaleToHost(ctx.locale.getSnapshot().active));
|
|
4741
|
+
}, "teamflow: host locale push");
|
|
4085
4742
|
const openResourceSafe = (address, label, quiet) => {
|
|
4086
4743
|
try {
|
|
4087
4744
|
const sidebarRight = ctx.get("sidebarRight");
|
|
@@ -4103,11 +4760,13 @@ window.__ModuleLoader__.load({
|
|
|
4103
4760
|
name: "sidebar.panellist",
|
|
4104
4761
|
id: "teamflow",
|
|
4105
4762
|
order: 60,
|
|
4106
|
-
|
|
4763
|
+
locale: NS,
|
|
4764
|
+
label: () => t("workbench.title")
|
|
4107
4765
|
}, TeamflowPanelIcon));
|
|
4108
4766
|
ctx.slots.inject("main", () => ctx.slots.register({
|
|
4109
4767
|
name: "main",
|
|
4110
4768
|
key: "teamflow",
|
|
4769
|
+
locale: NS,
|
|
4111
4770
|
inject: () => ({
|
|
4112
4771
|
remote: teamflow,
|
|
4113
4772
|
sessions: ctx.get("sessions"),
|
|
@@ -4126,6 +4785,7 @@ window.__ModuleLoader__.load({
|
|
|
4126
4785
|
ctx.slots.inject("sidebar.right.pane.tab", () => ctx.slots.register({
|
|
4127
4786
|
name: "sidebar.right.pane.tab",
|
|
4128
4787
|
key: RUN_TAB_ID,
|
|
4788
|
+
locale: NS,
|
|
4129
4789
|
inject: () => ({
|
|
4130
4790
|
remote: teamflow,
|
|
4131
4791
|
openArtifact
|
|
@@ -4135,7 +4795,8 @@ window.__ModuleLoader__.load({
|
|
|
4135
4795
|
name: "conversation.view",
|
|
4136
4796
|
id: "teamflow",
|
|
4137
4797
|
order: 20,
|
|
4138
|
-
|
|
4798
|
+
locale: NS,
|
|
4799
|
+
label: () => `🏭 ${t("workbench.title")}`,
|
|
4139
4800
|
inject: (sessionId) => ({
|
|
4140
4801
|
sessionId,
|
|
4141
4802
|
remote: teamflow,
|
|
@@ -4148,9 +4809,11 @@ window.__ModuleLoader__.load({
|
|
|
4148
4809
|
name: "conversation.input.right",
|
|
4149
4810
|
id: "teamflow-team-select",
|
|
4150
4811
|
order: 5,
|
|
4812
|
+
locale: NS,
|
|
4151
4813
|
inject: (sessionId) => ({
|
|
4152
4814
|
sessionId,
|
|
4153
|
-
remote: teamflow
|
|
4815
|
+
remote: teamflow,
|
|
4816
|
+
locale: ctx.locale.getSnapshot().active
|
|
4154
4817
|
})
|
|
4155
4818
|
}, TeamSelector));
|
|
4156
4819
|
}
|