dsh-super-code 0.0.9 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +62 -120
  2. package/client/index.js +129 -100
  3. package/package.json +2 -3
package/README.md CHANGED
@@ -1,162 +1,104 @@
1
1
  # dsh-super-code
2
2
 
3
- DeepSeek Harness 编码插件。用户只选择 `super-code`;Agent 按交付目标选择内部专业团队,简单任务直接完成,需要时再加载方法、建立任务档案或并行委派。没有独立路由模型调用、强制五阶段流程或统一反思循环。
3
+ 一个更快、更节省、更准确的 DeepSeek Harness 编码插件。
4
4
 
5
- 0.0.9 收敛为一套宿主原生执行路径:移除旧 workflow、任务图和模型池设置;任务写入与读取分离,页面只接收档案摘要;成员费用缺失不再阻止产物评审,但始终明确未核实。离线评测支持同 preset 的版本对照及完整请求计费。没有增加循环、调度器或必经模型调用,也不宣称未经真实对照验证的质量或费用收益。
5
+ 在选定的 SWE-bench Pro hard-100 评测中,平均耗时减少约 36%,每题输入 token 减少约 17%,正确率提高 5 个百分点。
6
6
 
7
- ## 效果基准(0.0.6 历史结果)
7
+ A faster, more accurate, and more cost-effective DeepSeek Harness plug-in component.
8
8
 
9
- SWE-bench Lite 前 100 题,`deepseek/deepseek-flash`、reasoning `high`,两组都通过完整 DeepSeek Harness Agent 流程:
9
+ On the selected SWE-bench Pro hard-100 evaluation, average elapsed time decreased by about 36%, input tokens per task by about 17%, and accuracy increased by 5 percentage points.
10
10
 
11
- | | DSH minimal | super-code |
12
- |---|---:|---:|
13
- | 正确率 | 99% | 99% |
14
- | 平均总 token | 737,421 | 419,145(-43%) |
15
- | 平均耗时 | 314 秒 | 89 秒(-72%) |
11
+ ## 介绍 · Introduction
16
12
 
17
- 在这批题上,super-code 保持了相同正确率,同时减少了 token 和耗时。结果使用本地 focused tests,不是官方 Docker SWE-bench 分数。
13
+ `dsh-super-code` 是 DeepSeek Harness 的编码插件,提供一个可直接使用的 `super-code` Agent 预设。
18
14
 
19
- ## 安装与选择
15
+ `dsh-super-code` is a coding plugin for DeepSeek Harness with one ready-to-use `super-code` Agent preset.
20
16
 
21
- 要求 Node.js 22+、Harness **0.1.5-rc.2+**,使用当前 persona-prefix API 和右侧栏服务,不兼容 0.1.2-rc.1。使用宿主的模型、工具、权限、子 Agent 和 Session 持久化。
17
+ 它会根据任务选择调研、设计、开发、验证和优化方法,简单任务直接完成,复杂任务按需组织工作。
22
18
 
23
- ```bash
24
- dsh plugin --profile web add dsh-super-code
25
- ```
26
-
27
- 插件注册唯一的 `super-code` preset 并设为默认;宿主自带和用户自定义 preset 仍可用。插件不再增加预设切换控件;宿主原生预设入口及已开始会话的组合不可变规则保持不变。
28
-
29
- 项目与 npm 包统一命名为 `dsh-super-code`,源码仓库为 [ArtlexYoung/dsh-super-code](https://github.com/ArtlexYoung/dsh-super-code)。本地改名不代表新包已发布到 npm。已有安装需更新包引用和 preset 根目录路径;新任务档案使用新包名标识,仍可读取更名前的档案。0.0.9 移除旧 `SuperAgent*` / `ctx.superAgent` API、旧模型池设置及 `core/*` 通配出口,不提供兼容包装;历史 runner 使用冻结旧包。已保存档案的读取、`superAgentUsage` 用量字段与侧栏资源协议仍保持原值,避免丢失已有记录。
30
-
31
- ```json
32
- { "request": { "agentPreset": "super-code" } }
33
- ```
34
-
35
- 原 `solo`、`team`、`research`、`optimization` preset 已删除,不提供别名、迁移或旧会话恢复兼容。升级后请新建 `super-code` 会话。联网调研使用宿主 web backend 和权限;没有可用 backend 时必须报告限制。
19
+ It selects research, design, development, verification, and optimization methods as needed for each task.
36
20
 
37
- ## 内部团队与方法
21
+ ## 在 DeepSeek Harness 中安装 · Installation
38
22
 
39
- | 主责 | 交付目标 | 常用专项方法 |
40
- | --- | --- | --- |
41
- | research 调研 | 有证据的事实、诊断、技术判断 | 调查、集成 |
42
- | design 设计 | 可实施的产品、接口、算法或架构方案 | 产品、架构、算法 |
43
- | develop 开发 | 功能、修复、重构、迁移、集成 | 产品、bug 修复、架构、集成 |
44
- | verify 测试 | 测试、审查发现、验收证据 | 测试、集成 |
45
- | optimize 优化 | 有测量依据的改进 | 性能、算法、架构、质量 |
23
+ 要求 DeepSeek Harness 0.1.5-rc.2 或更高版本。
46
24
 
47
- 团队是专业方法集合,不是五个常驻 Agent。主 Agent 根据任务含义选择主责,通过 `super_code_method` 按需读取;专项方法跨团队共享。没有独立分类的工作按简单/复杂深度处理。架构优化与性能优化分别确定目标,不能把代码更短当作性能提升。
25
+ Requires DeepSeek Harness 0.1.5-rc.2 or later.
48
26
 
49
- 按需加载优化的是全任务成本,不是单次文本长度:已知方法可直接读取,无需先查询团队目录;专项返回仅保留交付目标和完整方法。上下文已包含有效指导、任务状态或执行结果时不重复取回,独立读取尽量同批;缺失、过期或存疑的信息仍需检查。工具调用不等于模型请求,但额外往返通常会再次计入输入上下文和输出,缓存部分也依供应商计费。实际收益应比较全部请求的累计费用、次数及延迟,不能用少几百字符代替效果评测。
50
-
51
- 只解释或设计不授权改代码。独立、有收益的工作可用宿主 subagent 并行执行;共享文件需要单一写入者或隔离工作区。成员只在范围相关、上下文仍有效时复用;短简报明确目标、所有权、约束、验收和预算,负责人继续本地工作并整合结果。交付简要说明产物、实际执行的检查和剩余缺口,不强制回答模板。这些是指导要求,不是新增调度或自动验收机制。
52
-
53
- ### 可选的具体指导
54
-
55
- 默认使用标准指导。不按模型名字猜测强弱,不自动切换模型。部署方可在 preset 的 `super-code` 插件配置中显式指定需要更具体提醒的精确路由:
56
-
57
- ```yaml
58
- guidedRoutes:
59
- - provider: your-provider
60
- model: your-exact-model
27
+ ```bash
28
+ dsh plugin --profile web add dsh-super-code
61
29
  ```
62
30
 
63
- 指导依据宿主本次装配后的 `provider/model` 变量选择,配合宿主 `installModelSelection` 的单步快照;未知路由或缺失身份回退标准指导,不从旧 header 猜测。自定义宿主路由若在装配后另行改写请求,不在该一致性保证内。两种指导遵循相同授权和证据要求,配置收益需实际评测,不默认给任何品牌分档。
31
+ 安装后在 Harness 的 “设置”-“Agent 预设” 中选择 `super-code`,模型、权限和工具继续使用 Harness 的配置。
64
32
 
65
- ## 长对话与任务档案
33
+ After installation, select `super-code` in "Settings" - "Agent Presets" in Harness; models, permissions, and tools use the Harness configuration.
66
34
 
67
- `super_code_task` 为复杂或跨轮任务保存有来源的要求、验收标准、决策、证据、下一步、工作区和代码版本。简单任务不强制建档。
35
+ [![Super Code 配置入口 · Super Code settings](docs/images/preset-settings-preview.png)](docs/images/preset-settings.png)
68
36
 
69
- 预设使用 Harness 原生、按 Agent 隔离的压缩服务:自动压缩沿用宿主默认策略,也可使用 `/compact` 手动压缩。压缩可调用当前模型生成摘要,其费用计入任务;不保证摘要的语义完整性,关键约束仍通过任务档案恢复。不新增插件摘要器或循环。
37
+ 当前版本不使用三模型池,也不需要单独配置插件模型。在 Harness“设置”→“模型”中配置提供方,再从对话输入框下方选择模型和推理等级;已有可用配置时直接沿用。插件跟随当前会话的模型,子 Agent 在未单独覆盖时继承父 Agent 的选择。
70
38
 
71
- - `create/read/list/update/focus`:要求以 id 合并,未修改的约束保留;修改必须引用本会话真实用户消息。并发写使用 `expectedRevision`,拒绝旧版本覆盖。`read` 默认或 `view: resume` 返回 `{current}` 紧凑恢复视图,保留目标、全部硬约束、验收、决定、下一步和有界有效证据;`omittedEvidence` 标明省略的有效证据数量,`staleEvidence` 标明不再适用的数量。需要原始来源、其他证据或记录字段时可直接传 `view: full`,返回原始完整档案,无需先读恢复视图。完整档案中的证据须核对要求/代码版本,不能直接视为当前证明;读取不切换焦点或新增任务快照。
72
- - `source`:通过用户事件序号取回原文。动态上下文包含任务目录、最近用户事件序号和焦点任务的紧凑视图:保留全部要求、验收、决策和来源序号,不重复原文;最多展示最近 3 条有效证据,预算不足时优先省略证据并标明数量,可通过 `read(view: full)` 读取完整档案。硬约束不静默截断,必需字段超预算的更新会明确失败。
73
- - `archive/archives/history/restore`:完成或取消的任务可归档;每页最多扫描 4,096 个事件、返回 10 个归档摘要,每 256 条让出执行并检查取消。稀疏历史在工具内部继续查找,达到上限返回 `nextBeforeSeq` 和 `done`;`done: false` 不能解释成没有记录。历史全文留在宿主日志。用户要求继续时,恢复工具要求新的用户来源和检查后的代码版本;保留约束、清空旧决策并让旧证据失效,不自动启动工作。
74
- - `delegate/validate_member`:简报绑定会话、任务身份、要求版本、代码版本和成员责任。过期、失败、取消或未确认停止的返回不可评审。`reviewable` 只表示可以交给负责人核对,不等于已验收。成员无须猜测费用:缺失费用返回 `accounting.kind: unavailable`;可选自报费用标为 `model-reported`,预算结论仍为 `unknown`,不会被当作宿主认证或硬预算执行。
75
- - `evidence`:已有引用时传 `record:{callSeq,resultSeq}` 或 `{ref}`,两次索引读取回查本会话配对记录。长输出默认保留首尾并明确省略中间,最多 8,000 个 UTF-16 单元;短输出完整返回,参数预览最多 2,000 单元。需要原始输出时使用返回的 `readMore`,或 `record:{ref,offset:0}` 连续分页;偏移由工具返回,不需要猜测,原始日志不变。此处“完整”只指已记录文本,不保证原工具未截断或执行了全部测试。不知道序号时省略 `record`,按需列出最多 12 条调用/返回身份;参数预览最多 240 单元并标明截断,按 `callId/turn/step` 配对并检查参数。目录每页最多扫描 4,096 条、每 256 条让出执行;通过 `eventSeq: nextBeforeSeq` 继续。跨会话、缺失或不匹配引用不可用;不执行命令、不维护新账本,工具返回不等于测试通过或当前代码已验证。
39
+ The current version has no three-pool model configuration. Configure a provider under Harness “Settings” → “Models”, then select the model and reasoning effort below the message input. Existing working settings can be reused. The plugin follows the current session model, and child Agents inherit their parent's selection unless explicitly overridden.
76
40
 
77
- 恢复视图中,证据只按记录的需求/源码版本匹配,不自动核验当前工作区;`evidenceBasis` 明确这一边界。源码版本应区分相关未提交改动,不能只依赖未变化的 HEAD。更新版本会使旧证据失效,但完整记录保留供回查。没有新增文件监听、自动版本猜测或恢复时的强制测试。
41
+ ## 效果 · Results
78
42
 
79
- 同值 `update` 和重复 `focus` 返回 `unchanged: true`,不追加任务快照、不增加修订;来源和旧版本校验仍先执行,用户来源变化、暂停恢复不会被去重。未确认的 checkpoint 也会先重试,持久化失败不能被“无变化”掩盖。参数错误返回有限字段位置、错误种类及必要的类型或数量要求,缺少 `expectedRevision` 明确提示;不回显提交值,不自动修正版本、来源或输入。
43
+ SWE-bench Pro hard-100,使用 `deepseek-v4.1-flash`、reasoning `high`、原生 DSH Web RPC 和官方评分器。
80
44
 
81
- 真实进度更新夹带相同目标、工作区、验收或要求时,只增加普通修订,不清空决定或使成员绑定失效;真实要求、纠正来源、代码版本和状态变化仍按相应规则失效。首次装配的动态上下文可能早于最新用户消息入库;最新来源序号缺席时使用 `list` 的 `recentUserEventSeqs`,不要猜序号。
45
+ SWE-bench Pro hard-100 with `deepseek-v4.1-flash`, reasoning `high`, native DSH Web RPC, and the official grader.
82
46
 
83
- 任务焦点与执行状态分离,切换话题不自动取消工作。暂停再激活会改变委派版本,旧成员返回仍然过期;普通进度更新不影响有效简报。完成或取消的任务只能归档后凭归档之后的新用户消息恢复,不能直接改回 active。归档是显式操作,工作集默认最多 32 个任务,上限 128;上下文默认最多 32 KiB,可在 preset 的 `super-code` 插件配置中调整 `maxTasks`、`maxContextBytes`(1–256 KiB)。要求和证据还有各自条数/长度限制。
47
+ > 提示:
48
+ > SWE-bench Pro 是面向真实软件工程任务的高难度评测集。每道题都来自真实开源仓库,通常需要理解现有代码、修改多个文件、运行测试并根据失败结果继续修复,评测结果以官方测试是否通过为准。这里选取其中难度最高的 100 道题,重点观察长任务中的正确率、调用次数、token 和耗时。
49
+ >
50
+ > SWE-bench Pro is a challenging benchmark for real-world software engineering tasks. Each task comes from a real open-source repository and typically requires understanding existing code, editing multiple files, running tests, and iterating on failures. The official test result is the pass criterion. This evaluation uses the 100 hardest selected tasks to measure accuracy, model calls, token usage, and elapsed time on long-running tasks.
51
+ >
52
+ > 经过预评测,`DSH minimal` 预设和 `deepseek-v4.1-flash` 的 `high` 思考强度取得了最高正确率,因此将它们作为统一比较基准。
53
+ >
54
+ > In preliminary runs, the `DSH minimal` preset with `deepseek-v4.1-flash` at `high` reasoning achieved the highest accuracy, so it is used as the common baseline.
84
55
 
85
- 档案通过宿主支持的 plugin-source `user/message` 事件和 `superCodeTasks` projection 保存,写工具在宿主 `flush` 成功后才返回成功;失败后的下一次工具调用重试 checkpoint,不重复追加事件。宿主先发布内存 projection 再 flush,因此磁盘失败时 UI 可能短暂显示尚未确认持久化的记录。插件此时阻止模型动态上下文把该 checkpoint 当作已确认事实,但不提供跨 UI/磁盘事务保证。
56
+ 这批结果来自 `0.0.9` 候选;`0.1.0` 沿用该历史基准,未重新执行完整 100 题评测。
86
57
 
87
- 紧凑视图只减少动态上下文的重复内容。当前完整快照仍通过上述消息事件持久化,并可能重复出现在模型历史中;尚未解决历史快照累积,不能据视图字节数推算整段对话的 token 节省。这些工具验证来源引用和版本,不证明模型对原文的解释正确,也不强制模型调用工具。真实长程理解和 token 收益需要模型评测。
58
+ These results are from the `0.0.9` candidate. Version `0.1.0` retains this historical benchmark; the full 100-task evaluation has not been rerun for this release.
88
59
 
89
- ## Web 界面与插件入口
60
+ | 指标 / Metric | DSH minimal | super-code 0.0.9 | 优化幅度 / Change |
61
+ |---|---:|---:|---:|
62
+ | 有效评分 / Valid scores | 100/100 | 100/100 | **持平 / 0%** |
63
+ | 通过题数 / Passed | 41 | 46 | **+12.2%** |
64
+ | 正确率 / Accuracy | 41% | 46% | **+5 个百分点 / +5 pp** |
65
+ | 平均模型调用/题 / Model calls per task | 124.85 | 92.78 | **-25.7%** |
66
+ | 平均工具调用/题 / Tool calls per task | 126.54 | 115.41 | **-8.9%** |
67
+ | 每题平均总输入 token / Average total input tokens per task | 11,477,170 | 9,525,316 | **-17.0%** |
68
+ | 每题平均总输出 token / Average total output tokens per task | 100,877 | 97,901 | **-3.0%** |
69
+ | 缓存命中率 / Cache hit rate | 99.360% | 99.329% | **-0.031%** |
70
+ | 平均测试时长 / Average test time | 25.49 分钟 / min | 16.27 分钟 / min | **-36.2%** |
90
71
 
91
- Web client 使用公开 slots、Remote 和 Session projection:任务档案与插件用量统一收口到侧栏,输入区不再重复展示档案、用量汇总或预设选择。根 Agent 详情展示当前任务的目标、状态和下一步,其他任务按需展开。右侧节点树只展示当前会话及其成员;点击节点或按 Enter/空格在右侧打开该 Agent 的只读标签,重复打开会复用标签,不切换主对话。详情顶部展示层级路径、token 总量和缓存命中率,输入/输出及缓存读取/写入在“用量详情”展开;下面按时间展示用户任务、Agent 回复和执行错误,隐藏内部上下文、推理及工具调用和结果(包括 super_code_task)。宿主原生用量展示不受影响。
72
+ > 因为输入和输出 token 均有减少,因此缓存命中率略微下降是可以接受的,属于正常波动范围。
73
+ >
74
+ > Since both input and output token usage decrease, the slight drop in cache hit rate is acceptable and within normal variation.
92
75
 
93
- 执行树采用从上到下的紧凑圆形节点图,自动读取可见节点的下级目录,无需逐层展开。点击节点直接打开侧栏详情,主对话不变;实色背景表示运行、待命、停止和不可用,摘要只显示子树 token 和按累计输入计算的缓存命中率。支持鼠标/触屏拖动平移、滚轮及按钮缩放(40%–200%)、适应窗口;双击空白处适应窗口,切换标签保留视图位置。首批最多渲染 200 个节点,大树分批显示。详情使用宿主 SessionEventStream 读取持久记录,按页加载历史、最多保留 200 条展示记录,隐藏/关闭详情时释放订阅。状态采用宿主活动事实,停止不等于验收成功;不可读记录和缺失用量单独标识,不伪造结果。token 服务使用固定大小计数器,不积累无限 usage 数组。
76
+ > Token 指标按每道题的历史明细计算:先分别合计该题已记录模型调用的输入(含缓存)和输出 token,再对 100 道题取平均,包含多轮调用和上下文增长;未返回用量的请求不作估算,不代表完整账单费用。
77
+ >
78
+ > Token metrics are calculated from task histories: input (including cached tokens) and output tokens are summed separately across recorded model calls for each task, then averaged over 100 tasks. This includes multi-turn calls and context growth. Requests without reported usage are not estimated; these figures do not represent complete billing costs.
94
79
 
95
- 长程执行树自动整理:每个分支默认保留最近创建的 4 个直接节点,窄侧栏保留 2 个,较深的空闲分支收起下级;运行、诊断/未知、当前会话和焦点路径额外保留。圆圈旁的小箭头手动折叠/展开下级,“自动整理”恢复默认。较早节点进入“已收起”,在同一列表连续虚拟滚动,仅渲染可视区域及少量缓冲行;支持搜索、创建时间范围(今天、近 7/30 天、自定义日期)及时间、累计 Token、标题双向排序。日期按本地时区且包含结束日;未知时间不参与日期筛选,未知时间或用量排序置后,部分用量以 ≈ 提示。上下方向键、Home/End 可遍历全部匹配项,点击打开原始详情;筛选仅覆盖已加载的收起节点,不额外预读冷目录。这只是视图归档,不删除会话、不停止成员,待命也不会被标成已完成。已加载目录继续订阅,成员恢复运行会重新显示。用量始终基于完整已加载树;画布自动适应尺寸,手动拖动/缩放后保持用户位置。折叠偏好只保存在当前页面标签内,重载后重新自动整理。
80
+ 测试题号和每题明细见 [`eval/results/swebench-pro-final-100/`](eval/results/swebench-pro-final-100/),详细文档见 [`docs/`](docs/)。
96
81
 
97
- 页面档案 projection 只传任务目录和当前目标、状态、下一步,不传原文、证据或完整要求。完整状态仍由宿主保存,模型恢复视图保留全部硬约束。减少页面传输不等于减少模型历史 token。读取取得已确认快照后,历史扫描不占写队列;写入仍串行,并在 flush 成功后确认。
82
+ Task IDs and per-task details are available in [`eval/results/swebench-pro-final-100/`](eval/results/swebench-pro-final-100); detailed documentation is in [`docs/`](docs/).
98
83
 
99
- 包根默认导出注册宿主投影并提供浏览器发现入口;`dsh-super-code/dsh` 仅注册投影;`dsh-super-code/super-code` 仅用于 Agent scope。根入口导出当前团队、指导、任务和证据的领域函数,离线评测独立从 `dsh-super-code/evaluation` 导入。主 Agent 与成员模型始终由 Harness 选择,不再提供无效的模型池控件。
84
+ ## 使用 · Usage
100
85
 
101
- ## 困难问题的有界实验
86
+ 安装后,在 DeepSeek Harness 的“设置”→“Agent 预设”中选择 `super-code`。创建任务后,插件会按任务复杂度组织调研、实现和验证;复杂任务可在右侧 Agent 执行树中查看进度,点击节点查看对应的执行内容和用量。
102
87
 
103
- 现有 `super_code_method` 可附带 `recipe: reduce | differential | interleavings | metamorphic`,直接返回所选示例和已安装模块地址;不需要先读目录。不选 recipe 时返回内容不变,主提示词不注入示例。
88
+ After installation, select `super-code` under “Settings” → “Agent Presets” in DeepSeek Harness. The plugin organizes research, implementation, and verification according to task complexity; for complex tasks, use the Agent execution tree on the right to inspect progress, execution details, and usage.
104
89
 
105
- 独立模块 `dsh-super-code/experiments` 提供失败输入缩减、差分、两条有序序列的交错枚举及契约关系验证。模型调整示例后,通过宿主前台 `bash` 的一次调用运行多个检查,组合搜索和缩减时共享 `ExperimentBudget`。不新增 Agent、模型循环、依赖或宿主执行器。模块不在插件常驻入口加载。
90
+ [![Agent 执行树 · Agent execution tree](docs/images/agent-tree-preview.png)](docs/images/agent-tree.png)
106
91
 
107
- 调用者必须提供可靠判据、结构化可克隆的数据,并隔离每次实验状态。差分参考实现应独立可信,关系来自真实契约;输入缩减仅接受相同故障签名的两次复现,宽泛签名可能混淆不同故障。`one-removal` 只表示在可重复判据下不能再删单个元素,不保证全局最小。`checked` 仅覆盖给定样本;交错枚举保持两条序列各自顺序,最多 256 步,`limited` 明确表示没有穷尽,也不代表覆盖真实系统全部调度。
92
+ 截图来自全新隔离会话中的 DSH 网页版,展示 hard-100 难度排名第一题 `task-099`(`future-architect/vuls` 的 OS 生命周期预警)的初步调研:一个主 Agent 与三个子 Agent 分别核查 EOL/版本解析、告警链路和测试边界。图中保留了整个右侧栏,包括状态、用量、缓存率和缩放操作;这是协作展示,不代表该题已修复或通过评分。
108
93
 
109
- 差分示例只报告原始差异反例,不把通用 `behavior-difference` 自动用于同故障缩减。需要组合时,用任务契约限定目标判据和签名;同签名仍不证明同一根因。各示例只附带相关说明,输出保留状态、原因、实际检查预算及适用的覆盖/最小性信息,数组预览最多 8 项,明确原始长度;完整结果仍在脚本变量中,大报告按需保存到任务文件。
94
+ Captured from a fresh, isolated DSH web session, the full sidebar shows initial investigation of the highest-ranked hard-100 task, `task-099` (`future-architect/vuls`, OS lifecycle warnings). A lead Agent and three child Agents investigate EOL/version parsing, the warning pipeline, and test boundaries. Status, usage, cache hit rate, and zoom controls are all visible. This is a collaboration example, not a claim that the task was fixed or passed grading.
110
95
 
111
- `maxChecks` 按 probe 次数计数,含复现确认;一个差分或关系 probe 含两次观察。`timeoutMs` 和可选 `AbortSignal` 为协作式限制,不能打断死循环或不合作的 Promise,必须同时设置宿主前台 `bash.timeoutMs`。预算耗尽只返回已确认结果;`unknown`、异常、未稳定复现都不能当通过。回调异常向外抛出;副作用只可针对已授权且可安全重复的操作。大报告可保存在任务文件中,终端只输出必要摘要。能力测试不等于已证明真实模型正确率或费用改善。
96
+ 拖动空白处平移,滚轮或按钮缩放,点击节点在侧边栏新标签中查看详情。插件界面跟随 Harness 的中英文语言设置。
112
97
 
113
- ## 版本对照评测
98
+ Drag empty space to pan, use the wheel or buttons to zoom, and click a node to open its details in a sidebar tab. The plugin follows the Harness Chinese/English language setting.
114
99
 
115
- `evaluateSuperCodeBatch` 使用 `super-code/v3`:运行前固定 manifest,`baseline` 和 `candidate` 分别声明 preset、版本与实际包摘要;允许同为 super-code 的两个版本直接比较。每个任务每侧一条汇总,包含全部尝试的请求记录;不挑最好一次、不覆盖历史。
100
+ ## 感谢 · Thanks
116
101
 
117
- ```bash
118
- npm run build
119
- npm run eval:super-code -- manifest.json measurements.jsonl
120
- # 安装后:super-code-eval manifest.json measurements.jsonl
121
- ```
122
-
123
- 命令只读离线证据,不运行模型。退出码 0 为通过,1 为未通过/不完整,2 为输入无效。旧协议输入明确拒绝;历史四场景和 v2 使用冻结旧版本工具。
124
-
125
- manifest 与逐行输入类型见 `src/core/evaluation.ts` 或包内声明。必须固定任务、模型、推理、评分器、工具、资源、环境及 Harness 条件,并在运行前明确 `gates`,例如:
126
-
127
- ```json
128
- { "minAccuracyUplift": 0, "maxLostSuccesses": 0, "minCostReduction": 0.1 }
129
- ```
130
-
131
- 这是“质量不退化、费用至少下降 10%”的实验目标示例,不是本版已达到的收益。可省略费用/延迟改善门槛,但报告仍需完整计费证据。每个类别禁止净质量退化,报告同题新增成功、丢失成功及不可评分项;小样本无退化不是统计证明。
132
-
133
- 每侧提供 `expectedRequests`、`requestManifestComplete` 与实际 `requests`。每个请求记录 session/attempt 身份、root/member/retry/compaction 类型、provider/model、价格引用、互斥的 uncachedInput/cacheRead/cacheWrite/output 桶及工具费用。价格表提供币种、来源、有效时间、各桶每百万 token 单价和实际 perRequest 费用(没有时明确 0)。请求清单必须来自完整宿主日志,CLI 本身不能证明清单未遗漏。
134
-
135
- 重复或异常请求拒绝;缺题 `incomplete`,版本/条件变化 `unmatched`,mock/replay、环境/评分故障、未知结果、缺请求/用量/价格或混合币种 `unmeasured`。Agent 未交付和审计拒绝计为失败,环境故障单列,所有已观察尝试的请求与用量仍保留。失败分类由评测适配器负责,不能用环境标签掩盖能力失败。
136
-
137
- ## 开发
138
-
139
- ```bash
140
- npm install
141
- npm run typecheck
142
- npm test
143
- npm run build
144
- node --check client/index.js
145
- npm pack --dry-run
146
- ```
147
-
148
- 设计和隔离宿主验证资料放在 `.development/`,历史数据与模型 runner 在本地 `eval/`;两者不进入 Git/npm。`provider:health` 依赖本地 `eval/runners/provider-health.mjs`。本地旧 runner 属于历史协议,不直接用于新 v3 发布判定;不要修改历史结果适配新协议。离线验收命令不启动模型。
149
-
150
- ```text
151
- presets/super-code/ # 唯一产品预设
152
- src/core/teams.ts # 五团队与共享方法
153
- src/core/task-memory.ts # 有界工作集和要求修订
154
- src/core/delegation.ts # 委派简报与结果版本核对
155
- src/core/evaluation.ts # v3 版本配对与请求计费
156
- src/dsh/super-code.ts # scoped 工具与动态上下文
157
- src/task-memory-store.ts # 会话写屏障与持久化确认
158
- src/evaluate.ts # 离线评测 CLI
159
- client/index.js # 宿主 Web slots
160
- ```
102
+ 感谢 DeepSeek Harness、SWE-bench Pro 及所有开源项目维护者。
161
103
 
162
- Apache License 2.0,见 [LICENSE](LICENSE)。
104
+ Thanks to the DeepSeek Harness team, SWE-bench Pro contributors, and all open-source maintainers.
package/client/index.js CHANGED
@@ -12,20 +12,46 @@ const { useEffect, useLayoutEffect, useRef, useMemo, useState, useSyncExternalSt
12
12
  const { IconRefreshOutline16 } = require('@deepseek-ai/dsh-client-ui-primitives')
13
13
  const { SessionEventStream } = require('@deepseek-ai/dsh-api-session-controller')
14
14
 
15
- function TaskMemoryPanel({ state }) {
15
+ const LOCALE_NS = 'dshSuperCode'
16
+ const zh = {
17
+ 'task.memory': '任务档案', 'task.other': '其他任务', 'task.history': '任务记录',
18
+ 'status.active': '进行中', 'status.paused': '已暂停', 'status.completed': '已完成', 'status.cancelled': '已取消',
19
+ 'next': '下一步:', 'tree.title': '协作执行', 'tree.count': '显示 {shown} / {total} · 运行中 {running}',
20
+ 'tree.refresh': '刷新执行记录', 'tree.legend.active': '运行中', 'tree.legend.idle': '待命', 'tree.legend.stopped': '已停止', 'tree.legend.unavailable': '记录不可用',
21
+ 'tree.empty': '暂无会话', 'tree.zoom.out': '缩小节点图', 'tree.zoom.in': '放大节点图', 'tree.fit': '适应窗口',
22
+ 'tree.organize': '自动整理', 'tree.collapsed': '已收起 {count}', 'tree.more': '显示更多', 'tree.canvas': '拖动平移,滚轮缩放,双击空白适应窗口',
23
+ 'tree.aria': 'Agent 执行树', 'tree.status': '状态颜色', 'tree.usage': '本节点及所有已知下级合计,包含本节点。{partial}Token {tokens};缓存读取 {cache};{agents} 个 Agent',
24
+ 'usage.unknown': '用量 —', 'usage.cache': '缓存 {value}%', 'usage.partial': '部分', 'usage.incomplete': '部分记录或用量尚不可用;仅显示已知值。',
25
+ 'history.aria': '已收起的 Agent', 'history.search': '搜索 Agent 或上级任务', 'history.find': '查找收起的 Agent', 'history.created': '创建时间', 'history.sort': '排序',
26
+ 'history.all': '全部时间', 'history.today': '今天', 'history.week': '近 7 天', 'history.month': '近 30 天', 'history.custom': '自定义', 'history.latest': '最新创建', 'history.earliest': '最早创建', 'history.tokensHigh': 'Token 从多到少', 'history.tokensLow': 'Token 从少到多', 'history.titleAsc': '标题正序', 'history.titleDesc': '标题倒序',
27
+ 'history.start': '开始日期', 'history.end': '结束日期', 'history.summary': '{shown} / {total} 个已收起节点 · Token 含下级', 'history.invalid': '请选择有效的起止日期', 'history.empty': '没有匹配的节点', 'history.view': '查看 {title} 的详情', 'history.unknownTime': '时间未知', 'history.unknownUsage': '用量未知',
28
+ 'detail.path': 'Agent 路径', 'detail.title': 'Agent 详情', 'detail.refresh': '刷新对话详情', 'detail.task': '任务', 'detail.agent': 'Agent', 'detail.interrupted': 'Agent · 已中断', 'detail.error': '执行错误', 'detail.incomplete': '执行未完成,请稍后重试。', 'detail.input': '输入', 'detail.output': '输出', 'detail.cacheRead': '缓存读取', 'detail.cacheWrite': '缓存写入', 'detail.total': 'Token 总量', 'detail.hitRate': '缓存命中率', 'detail.moreUsage': '用量详情', 'detail.unavailable': '未提供', 'detail.reading': '正在读取对话…', 'detail.read': '读取中…', 'detail.older': '加载更早记录', 'detail.latest': '回到最新', 'detail.empty': '暂无执行内容', 'detail.new': '有新内容 · 查看最新', 'detail.loadError': '对话详情读取失败', 'detail.connection': '连接中断,正在重连', 'detail.historyError': '历史记录读取失败', 'detail.open': '展开全文', 'detail.noAccess': '无法打开详情,请重试', 'tree.loadError': '部分执行记录读取失败,请刷新重试', 'detail.unknown': '用量未知', 'main.agent': '主 Agent', 'tree.open': '点击查看详情', 'tree.expand': '展开', 'tree.collapse': '收起', 'image': '[图片]'
29
+ }
30
+ const en = {
31
+ 'task.memory': 'Task memory', 'task.other': 'Other tasks', 'task.history': 'Task history',
32
+ 'status.active': 'Active', 'status.paused': 'Paused', 'status.completed': 'Completed', 'status.cancelled': 'Cancelled', 'next': 'Next: ',
33
+ 'tree.title': 'Collaborative execution', 'tree.count': 'Showing {shown} / {total} · Running {running}', 'tree.refresh': 'Refresh execution records', 'tree.legend.active': 'Running', 'tree.legend.idle': 'Idle', 'tree.legend.stopped': 'Stopped', 'tree.legend.unavailable': 'Unavailable', 'tree.empty': 'No sessions', 'tree.zoom.out': 'Zoom out', 'tree.zoom.in': 'Zoom in', 'tree.fit': 'Fit to window', 'tree.organize': 'Organize automatically', 'tree.collapsed': '{count} collapsed', 'tree.more': 'Show more', 'tree.canvas': 'Drag to pan, scroll to zoom, double-click empty space to fit', 'tree.aria': 'Agent execution tree', 'tree.status': 'Status colors', 'tree.usage': 'This node and all known descendants. {partial}Tokens {tokens}; cache reads {cache}; {agents} agents', 'usage.unknown': 'Usage —', 'usage.cache': 'Cache {value}%', 'usage.partial': 'partial', 'usage.incomplete': 'Some records or usage are unavailable; showing known values only.',
34
+ 'history.aria': 'Collapsed agents', 'history.search': 'Search agents or parent tasks', 'history.find': 'Find collapsed agents', 'history.created': 'Created', 'history.sort': 'Sort', 'history.all': 'All time', 'history.today': 'Today', 'history.week': 'Last 7 days', 'history.month': 'Last 30 days', 'history.custom': 'Custom', 'history.latest': 'Newest first', 'history.earliest': 'Oldest first', 'history.tokensHigh': 'Most tokens first', 'history.tokensLow': 'Fewest tokens first', 'history.titleAsc': 'Title A–Z', 'history.titleDesc': 'Title Z–A', 'history.start': 'Start date', 'history.end': 'End date', 'history.summary': '{shown} / {total} collapsed nodes · Includes descendants', 'history.invalid': 'Choose a valid date range', 'history.empty': 'No matching nodes', 'history.view': 'View details for {title}', 'history.unknownTime': 'Unknown time', 'history.unknownUsage': 'Usage unknown',
35
+ 'detail.path': 'Agent path', 'detail.title': 'Agent details', 'detail.refresh': 'Refresh conversation details', 'detail.task': 'Task', 'detail.agent': 'Agent', 'detail.interrupted': 'Agent · Interrupted', 'detail.error': 'Execution error', 'detail.incomplete': 'Execution did not finish. Try again later.', 'detail.input': 'Input', 'detail.output': 'Output', 'detail.cacheRead': 'Cache reads', 'detail.cacheWrite': 'Cache writes', 'detail.total': 'Total tokens', 'detail.hitRate': 'Cache hit rate', 'detail.moreUsage': 'Usage details', 'detail.unavailable': 'Unavailable', 'detail.reading': 'Reading conversation…', 'detail.read': 'Reading…', 'detail.older': 'Load earlier records', 'detail.latest': 'Back to latest', 'detail.empty': 'No execution content', 'detail.new': 'New content · View latest', 'detail.loadError': 'Could not read conversation details', 'detail.connection': 'Connection interrupted, reconnecting', 'detail.historyError': 'Could not read history', 'detail.open': 'Expand', 'detail.noAccess': 'Could not open details. Try again.', 'tree.loadError': 'Some execution records failed to load. Refresh to retry.', 'detail.unknown': 'Usage unknown', 'main.agent': 'Main agent', 'tree.open': 'Click to view details', 'tree.expand': 'Expand', 'tree.collapse': 'Collapse', 'image': '[Image]'
36
+ }
37
+ function formatText(template, values = {}) { return template.replace(/\{(\w+)\}/g, (_, key) => values[key] ?? '') }
38
+ function text(t, key, values) { return formatText(t(key), values) }
39
+ function localeCode(t) { return text(t, 'status.active') === en['status.active'] ? 'en-US' : 'zh-CN' }
40
+
41
+ function TaskMemoryPanel({ state, t = key => zh[key] || key }) {
16
42
  const tasks = state?.tasks || []
17
43
  if (!tasks.length) return null
18
44
  const current = state.current?.kind === 'task' ? state.current : undefined
19
- const labels = { active: '进行中', paused: '已暂停', completed: '已完成', cancelled: '已取消' }
20
- return React.createElement('section', { className: 'dsh-super-code-task-memory', 'aria-label': '任务档案' },
45
+ const labels = { active: text(t, 'status.active'), paused: text(t, 'status.paused'), completed: text(t, 'status.completed'), cancelled: text(t, 'status.cancelled') }
46
+ return React.createElement('section', { className: 'dsh-super-code-task-memory', 'aria-label': text(t, 'task.memory') },
21
47
  current && React.createElement(React.Fragment, null,
22
48
  React.createElement('div', { className: 'dsh-super-code-task-heading' },
23
49
  React.createElement('strong', null, current.title),
24
50
  React.createElement('span', null, labels[current.status] || current.status)),
25
51
  current.goal && React.createElement('p', null, current.goal),
26
- current.next && React.createElement('p', null, '下一步:', current.next)),
52
+ current.next && React.createElement('p', null, text(t, 'next'), current.next)),
27
53
  tasks.some(task => task.id !== current?.id) && React.createElement('details', null,
28
- React.createElement('summary', null, current ? '其他任务' : '任务记录'),
54
+ React.createElement('summary', null, current ? text(t, 'task.other') : text(t, 'task.history')),
29
55
  React.createElement('ul', null, tasks.filter(task => task.id !== current?.id).map(task => React.createElement('li', { key: task.id }, `${task.title} · ${labels[task.status] || task.status}`)))),
30
56
  )
31
57
  }
@@ -151,7 +177,6 @@ function agentTreeTotals(view, catalogs = {}) {
151
177
 
152
178
  const historyRowHeight = 56
153
179
  const historyCollator = new Intl.Collator('zh-CN', { numeric: true, sensitivity: 'base' })
154
- const historyDateFormat = new Intl.DateTimeFormat('zh-CN', { month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit' })
155
180
 
156
181
  function agentHistoryRange(range, from = '', to = '', now = Date.now()) {
157
182
  const today = new Date(now)
@@ -181,7 +206,7 @@ function agentHistoryRows(view, hidden, totals, options = {}) {
181
206
  const rows = []
182
207
  for (const id of hidden) {
183
208
  const node = view.nodes.get(id), title = node.title || node.displayTitle || id
184
- const parent = view.nodes.get(node.parentId)?.title || '主 Agent', usage = totals.get(id)
209
+ const parent = view.nodes.get(node.parentId)?.title || text(options.t || (key => zh[key] || key), 'main.agent'), usage = totals.get(id)
185
210
  const time = Number.isFinite(node.createdAt) && node.createdAt >= 0 && node.createdAt <= 8640000000000000 ? node.createdAt : -1
186
211
  if (query && !`${title} ${parent}`.toLocaleLowerCase().includes(query)) continue
187
212
  if (options.range && options.range !== 'all' && (time < 0 || time < range.start || time >= range.end)) continue
@@ -208,11 +233,12 @@ function agentHistoryWindow(count, scrollTop, height) {
208
233
  }
209
234
 
210
235
  /** Local scroll state keeps the graph out of the scrolling render path. */
211
- function AgentHistory({ view, hidden, totals, open }) {
236
+ function AgentHistory({ view, hidden, totals, open, t = key => zh[key] || key }) {
212
237
  const [filters, setFilters] = useState({ query: '', range: 'all', from: '', to: '', sort: 'time-desc' })
213
238
  const [scroll, setScroll] = useState({ top: 0, height: 168 })
214
239
  const viewport = useRef(null), focusTarget = useRef('')
215
- const records = useMemo(() => agentHistoryRows(view, hidden, totals, filters), [view, hidden, totals, filters])
240
+ const records = useMemo(() => agentHistoryRows(view, hidden, totals, { ...filters, t }), [view, hidden, totals, filters, t])
241
+ const dateFormat = useMemo(() => new Intl.DateTimeFormat(localeCode(t), { month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit' }), [t])
216
242
  const window = agentHistoryWindow(records.length, scroll.top, scroll.height)
217
243
  const range = agentHistoryRange(filters.range, filters.from, filters.to)
218
244
  const change = (key, value) => setFilters(previous => ({ ...previous, [key]: value }))
@@ -249,33 +275,33 @@ function AgentHistory({ view, hidden, totals, open }) {
249
275
  const select = (key, label, choices) => React.createElement('label', null, label,
250
276
  React.createElement('select', { value: filters[key], 'aria-label': label, onChange: event => change(key, event.target.value) },
251
277
  choices.map(([value, text]) => React.createElement('option', { key: value, value }, text))))
252
- return React.createElement('section', { className: 'dsh-super-code-history', 'aria-label': '已收起的 Agent' },
253
- React.createElement('input', { type: 'search', value: filters.query, 'aria-label': '查找收起的 Agent', placeholder: '搜索 Agent 或上级任务', onChange: event => change('query', event.target.value) }),
278
+ return React.createElement('section', { className: 'dsh-super-code-history', 'aria-label': text(t, 'history.aria') },
279
+ React.createElement('input', { type: 'search', value: filters.query, 'aria-label': text(t, 'history.find'), placeholder: text(t, 'history.search'), onChange: event => change('query', event.target.value) }),
254
280
  React.createElement('div', { className: 'dsh-super-code-history-filters' },
255
- select('range', '创建时间', [['all', '全部时间'], ['today', '今天'], ['week', '近 7 天'], ['month', '近 30 天'], ['custom', '自定义']]),
256
- select('sort', '排序', [['time-desc', '最新创建'], ['time-asc', '最早创建'], ['tokens-desc', 'Token 从多到少'], ['tokens-asc', 'Token 从少到多'], ['title-asc', '标题正序'], ['title-desc', '标题倒序']])),
281
+ select('range', text(t, 'history.created'), [['all', text(t, 'history.all')], ['today', text(t, 'history.today')], ['week', text(t, 'history.week')], ['month', text(t, 'history.month')], ['custom', text(t, 'history.custom')]]),
282
+ select('sort', text(t, 'history.sort'), [['time-desc', text(t, 'history.latest')], ['time-asc', text(t, 'history.earliest')], ['tokens-desc', text(t, 'history.tokensHigh')], ['tokens-asc', text(t, 'history.tokensLow')], ['title-asc', text(t, 'history.titleAsc')], ['title-desc', text(t, 'history.titleDesc')]])),
257
283
  filters.range === 'custom' && React.createElement('div', { className: 'dsh-super-code-history-filters' },
258
- ['from', 'to'].map((key, index) => React.createElement('label', { key }, index ? '结束日期' : '开始日期',
259
- React.createElement('input', { type: 'date', value: filters[key], 'aria-label': index ? '结束日期' : '开始日期', onChange: event => change(key, event.target.value) })))),
260
- React.createElement('p', { className: 'dsh-super-code-history-summary', role: 'status' }, range.valid ? `${records.length} / ${hidden.length} 个已收起节点 · Token 含下级` : '请选择有效的起止日期'),
261
- React.createElement('div', { ref: viewport, className: 'dsh-super-code-history-list', role: 'list', 'aria-label': '收起节点列表',
284
+ ['from', 'to'].map((key, index) => React.createElement('label', { key }, index ? text(t, 'history.end') : text(t, 'history.start'),
285
+ React.createElement('input', { type: 'date', value: filters[key], 'aria-label': index ? text(t, 'history.end') : text(t, 'history.start'), onChange: event => change(key, event.target.value) })))),
286
+ React.createElement('p', { className: 'dsh-super-code-history-summary', role: 'status' }, range.valid ? text(t, 'history.summary', { shown: records.length, total: hidden.length }) : text(t, 'history.invalid')),
287
+ React.createElement('div', { ref: viewport, className: 'dsh-super-code-history-list', role: 'list', 'aria-label': text(t, 'history.aria'),
262
288
  onScroll: event => { const top = event.currentTarget.scrollTop; setScroll(previous => previous.top === top ? previous : { ...previous, top }) } },
263
289
  React.createElement('div', { style: { height: window.height, position: 'relative' } }, records.slice(window.start, window.end).map((record, offset) => {
264
- const index = window.start + offset, status = agentExecutionStatus(record.node, false)
265
- const date = record.time < 0 ? '时间未知' : historyDateFormat.format(record.time)
290
+ const index = window.start + offset, status = agentExecutionStatus(record.node, false, t)
291
+ const date = record.time < 0 ? text(t, 'history.unknownTime') : dateFormat.format(record.time)
266
292
  return React.createElement('div', { key: record.id, role: 'listitem', 'aria-posinset': index + 1, 'aria-setsize': records.length,
267
293
  style: { position: 'absolute', top: index * historyRowHeight, height: historyRowHeight, width: '100%' } },
268
294
  React.createElement('button', { type: 'button', 'data-history-id': record.id, onClick: () => open(record.node), onKeyDown: event => keyDown(event, index),
269
- title: `${record.title} · ${record.parent} · ${record.time < 0 ? date : new Date(record.time).toLocaleString('zh-CN')} · ${record.tokens < 0 ? '用量未知' : record.tokens + ' Token' + (record.partial ? '(部分)' : '')}`,
270
- 'aria-label': `查看 ${record.title} 的详情` },
295
+ title: `${record.title} · ${record.parent} · ${record.time < 0 ? date : new Date(record.time).toLocaleString()} · ${record.tokens < 0 ? text(t, 'history.unknownUsage') : record.tokens + ' Token' + (record.partial ? ' (' + text(t, 'usage.partial') + ')' : '')}`,
296
+ 'aria-label': text(t, 'history.view', { title: record.title }) },
271
297
  React.createElement('i', { className: 'dsh-super-code-circle ' + status.tone, 'aria-hidden': true }),
272
298
  React.createElement('span', null, React.createElement('strong', null, record.title), React.createElement('small', null, `${status.label} · ${date} · ${record.parent}`)),
273
- React.createElement('small', null, record.tokens < 0 ? '—' : `${record.partial ? '≈' : ''}${record.tokens.toLocaleString('zh-CN', { notation: 'compact', maximumFractionDigits: 1 })} tok`)))
299
+ React.createElement('small', null, record.tokens < 0 ? '—' : `${record.partial ? '≈' : ''}${record.tokens.toLocaleString(localeCode(t), { notation: 'compact', maximumFractionDigits: 1 })} tok`)))
274
300
  })),
275
- !records.length && React.createElement('p', { className: 'dsh-super-code-history-empty' }, '没有匹配的节点')))
301
+ !records.length && React.createElement('p', { className: 'dsh-super-code-history-empty' }, text(t, 'history.empty'))))
276
302
  }
277
303
 
278
- function AgentTree({ useSessions, useTabInfo, treeStates, openDetail, refresh, watchCatalog }) {
304
+ function AgentTree({ useSessions, useTabInfo, treeStates, openDetail, refresh, watchCatalog, t = key => zh[key] || key }) {
279
305
  const state = useSessions(s => s)
280
306
  const { tab } = useTabInfo()
281
307
  const view = useMemo(() => buildAgentView(state), [state.byId, state.subagentsByParent, state.current, state.currentAddress])
@@ -287,7 +313,7 @@ function AgentTree({ useSessions, useTabInfo, treeStates, openDetail, refresh, w
287
313
  }
288
314
  return value
289
315
  }, [treeStates, tab.signal, view.root])
290
- return React.createElement(AgentTreeBody, { key: view.root, state, view, saved, openDetail, refresh, watchCatalog })
316
+ return React.createElement(AgentTreeBody, { key: view.root, state, view, saved, openDetail, refresh, watchCatalog, t })
291
317
  }
292
318
 
293
319
  function AgentCatalogWatch({ id, watchCatalog }) {
@@ -316,13 +342,13 @@ function agentTreeLayout(view, limit) {
316
342
  height: Math.max(140, ...rows.map(row => row.level * 128)) }
317
343
  }
318
344
 
319
- function agentExecutionStatus(node, isRoot) {
320
- if (!node || node.unavailable || typeof node.running !== 'boolean') return { tone: 'unavailable', label: '记录不可用' }
321
- if (node.running) return { tone: 'active', label: '运行中' }
322
- return isRoot || node.mode === 'continuable' ? { tone: 'idle', label: '待命' } : { tone: 'stopped', label: '已停止' }
345
+ function agentExecutionStatus(node, isRoot, t = key => zh[key] || key) {
346
+ if (!node || node.unavailable || typeof node.running !== 'boolean') return { tone: 'unavailable', label: text(t, 'tree.legend.unavailable') }
347
+ if (node.running) return { tone: 'active', label: text(t, 'tree.legend.active') }
348
+ return isRoot || node.mode === 'continuable' ? { tone: 'idle', label: text(t, 'tree.legend.idle') } : { tone: 'stopped', label: text(t, 'tree.legend.stopped') }
323
349
  }
324
350
 
325
- function AgentTreeBody({ state, view, saved, openDetail, refresh, watchCatalog }) {
351
+ function AgentTreeBody({ state, view, saved, openDetail, refresh, watchCatalog, t = key => zh[key] || key }) {
326
352
  const [pan, setPan] = useState(saved.pan || { x: 0, y: 0 })
327
353
  const [zoom, setZoom] = useState(saved.zoom || 1)
328
354
  const viewport = useRef(null), graph = useRef(null)
@@ -402,12 +428,12 @@ function AgentTreeBody({ state, view, saved, openDetail, refresh, watchCatalog }
402
428
  ...Object.keys(catalogs).filter(id => view.nodes.has(id))])]
403
429
  const open = node => {
404
430
  setError('')
405
- Promise.resolve().then(() => openDetail(node)).catch(() => setError('无法打开详情,请重试'))
431
+ Promise.resolve().then(() => openDetail(node)).catch(() => setError(text(t, 'detail.noAccess')))
406
432
  }
407
433
  const reload = async () => {
408
434
  setBusy(true); setError('')
409
435
  try { await Promise.all([...new Set([view.root, ...watched])].filter(Boolean).map(id => refresh(id))) }
410
- catch { setError('执行记录刷新失败') }
436
+ catch { setError(text(t, 'tree.loadError')) }
411
437
  finally { setBusy(false) }
412
438
  }
413
439
  const keyDown = (event, row) => {
@@ -438,23 +464,23 @@ function AgentTreeBody({ state, view, saved, openDetail, refresh, watchCatalog }
438
464
  watched.map(id => React.createElement(AgentCatalogWatch, { key: id, id, watchCatalog })),
439
465
  React.createElement('header', { className: 'dsh-super-code-tree-header' },
440
466
  React.createElement('div', null,
441
- React.createElement('strong', null, '协作执行'),
442
- React.createElement('span', { className: 'dsh-super-code-tree-count' }, `显示 ${rows.length} / ${view.nodes.size} · 运行中 ${running}`)),
443
- React.createElement('button', { type: 'button', className: 'dsh-super-code-icon-button', disabled: busy || !view.root, onClick: reload, title: '刷新执行记录', 'aria-label': '刷新执行记录' }, React.createElement(IconRefreshOutline16))),
444
- (error || catalogError) && React.createElement('p', { role: 'alert', className: 'dsh-super-code-tree-error' }, error || '部分执行记录读取失败,请刷新重试'),
445
- React.createElement('div', { className: 'dsh-super-code-graph-legend', 'aria-label': '状态颜色' },
446
- ['运行中', '待命', '已停止', '记录不可用'].map((label, index) => React.createElement('span', { key: label },
447
- React.createElement('i', { className: 'dsh-super-code-circle ' + ['active', 'idle', 'stopped', 'unavailable'][index], 'aria-hidden': true }), label))),
448
- !view.root && React.createElement('p', { className: 'dsh-super-code-tree-empty' }, '暂无会话'),
449
- React.createElement('div', { className: 'dsh-super-code-graph-controls', 'aria-label': '画布操作' },
450
- React.createElement('button', { type: 'button', 'aria-label': '缩小节点图', disabled: zoom <= .4, onClick: () => zoomButton(1 / 1.2) }, '−'),
467
+ React.createElement('strong', null, text(t, 'tree.title')),
468
+ React.createElement('span', { className: 'dsh-super-code-tree-count' }, text(t, 'tree.count', { shown: rows.length, total: view.nodes.size, running }))),
469
+ React.createElement('button', { type: 'button', className: 'dsh-super-code-icon-button', disabled: busy || !view.root, onClick: reload, title: text(t, 'tree.refresh'), 'aria-label': text(t, 'tree.refresh') }, React.createElement(IconRefreshOutline16))),
470
+ (error || catalogError) && React.createElement('p', { role: 'alert', className: 'dsh-super-code-tree-error' }, error || text(t, 'tree.loadError')),
471
+ React.createElement('div', { className: 'dsh-super-code-graph-legend', 'aria-label': text(t, 'tree.status') },
472
+ ['tree.legend.active', 'tree.legend.idle', 'tree.legend.stopped', 'tree.legend.unavailable'].map((key, index) => React.createElement('span', { key },
473
+ React.createElement('i', { className: 'dsh-super-code-circle ' + ['active', 'idle', 'stopped', 'unavailable'][index], 'aria-hidden': true }), text(t, key)))),
474
+ !view.root && React.createElement('p', { className: 'dsh-super-code-tree-empty' }, text(t, 'tree.empty')),
475
+ React.createElement('div', { className: 'dsh-super-code-graph-controls', 'aria-label': text(t, 'tree.canvas') },
476
+ React.createElement('button', { type: 'button', 'aria-label': text(t, 'tree.zoom.out'), disabled: zoom <= .4, onClick: () => zoomButton(1 / 1.2) }, '−'),
451
477
  React.createElement('span', { 'aria-live': 'polite' }, `${Math.round(zoom * 100)}%`),
452
- React.createElement('button', { type: 'button', 'aria-label': '放大节点图', disabled: zoom >= 2, onClick: () => zoomButton(1.2) }, '+'),
453
- React.createElement('button', { type: 'button', onClick: fit }, '适应窗口')),
478
+ React.createElement('button', { type: 'button', 'aria-label': text(t, 'tree.zoom.in'), disabled: zoom >= 2, onClick: () => zoomButton(1.2) }, '+'),
479
+ React.createElement('button', { type: 'button', onClick: fit }, text(t, 'tree.fit'))),
454
480
  (display.hidden.length > 0 || expanded.size > 0 || collapsed.size > 0) && React.createElement('div', { className: 'dsh-super-code-history-controls' },
455
- React.createElement('button', { type: 'button', 'aria-expanded': historyOpen, onClick: () => setHistoryOpen(!historyOpen) }, `已收起 ${display.hidden.length}`),
456
- (expanded.size > 0 || collapsed.size > 0) && React.createElement('button', { type: 'button', onClick: () => { autoFit.current = true; setExpanded(new Set()); setCollapsed(new Set()); setFocused(state.current) } }, '自动整理')),
457
- historyOpen && React.createElement(AgentHistory, { view, hidden: display.hidden, totals, open }),
481
+ React.createElement('button', { type: 'button', 'aria-expanded': historyOpen, onClick: () => setHistoryOpen(!historyOpen) }, text(t, 'tree.collapsed', { count: display.hidden.length })),
482
+ (expanded.size > 0 || collapsed.size > 0) && React.createElement('button', { type: 'button', onClick: () => { autoFit.current = true; setExpanded(new Set()); setCollapsed(new Set()); setFocused(state.current) } }, text(t, 'tree.organize'))),
483
+ historyOpen && React.createElement(AgentHistory, { view, hidden: display.hidden, totals, open, t }),
458
484
  React.createElement('div', { ref: viewport, className: 'dsh-super-code-graph-scroll',
459
485
  onPointerDown: event => {
460
486
  if (!event.isPrimary || event.button !== 0) return
@@ -474,20 +500,20 @@ function AgentTreeBody({ state, view, saved, openDetail, refresh, watchCatalog }
474
500
  onPointerUp: finishDrag, onPointerCancel: finishDrag, onLostPointerCapture: finishDrag,
475
501
  onClickCapture: event => { if (gesture.current.moved && event.detail !== 0) { event.preventDefault(); event.stopPropagation() } },
476
502
  onDoubleClick: event => { if (!event.target.closest('[role="treeitem"]')) fit() },
477
- title: '拖动平移,滚轮缩放,双击空白适应窗口',
503
+ title: text(t, 'tree.canvas'),
478
504
  },
479
- React.createElement('div', { ref: graph, role: 'tree', 'aria-label': 'Agent 执行树', className: 'dsh-super-code-graph', style: { width, height, transform: `translate(${pan.x}px, ${pan.y}px) scale(${zoom})` } },
505
+ React.createElement('div', { ref: graph, role: 'tree', 'aria-label': text(t, 'tree.aria'), className: 'dsh-super-code-graph', style: { width, height, transform: `translate(${pan.x}px, ${pan.y}px) scale(${zoom})` } },
480
506
  React.createElement('svg', { width, height, className: 'dsh-super-code-graph-edges', 'aria-hidden': true }, edges.map(edge => {
481
507
  const parent = positions.get(edge.parent), child = positions.get(edge.child)
482
508
  return React.createElement('path', { key: edge.child, d: `M ${parent.x} ${parent.y + 105} V ${child.y - 12} H ${child.x} V ${child.y}`, fill: 'none' })
483
509
  })),
484
510
  rows.map(row => {
485
511
  const node = view.nodes.get(row.id)
486
- const title = node.title || node.displayTitle || '主 Agent'
487
- const { label: status, tone } = agentExecutionStatus(node, row.id === view.root)
512
+ const title = node.title || node.displayTitle || text(t, 'main.agent')
513
+ const { label: status, tone } = agentExecutionStatus(node, row.id === view.root, t)
488
514
  const usage = totals.get(row.id)
489
515
  const partial = usage.partial || usage.known < usage.agents
490
- const number = value => value.toLocaleString('zh-CN', { notation: 'compact', maximumFractionDigits: 1 })
516
+ const number = value => value.toLocaleString(localeCode(t), { notation: 'compact', maximumFractionDigits: 1 })
491
517
  const hasChildren = (view.children.get(row.id) || []).length > 0
492
518
  const isExpanded = (display.view.children.get(row.id) || []).length > 0
493
519
  return React.createElement(React.Fragment, { key: row.id }, React.createElement('button', {
@@ -497,23 +523,23 @@ function AgentTreeBody({ state, view, saved, openDetail, refresh, watchCatalog }
497
523
  'aria-expanded': hasChildren ? isExpanded : undefined,
498
524
  'aria-disabled': node.unavailable || undefined, 'aria-label': `${title},${status}`,
499
525
  className: `dsh-super-code-graph-node${row.id === state.current ? ' selected' : ''}${node.running ? ' running' : ''}`,
500
- style: { left: row.x - 64, top: row.y }, title: `${title} · ${status} · 点击查看详情`,
526
+ style: { left: row.x - 64, top: row.y }, title: `${title} · ${status} · ${text(t, 'tree.open')}`,
501
527
  onFocus: () => setFocused(row.id), onClick: () => { if (!node.unavailable) open(node) },
502
528
  onKeyDown: event => { if (event.target === event.currentTarget) keyDown(event, row) },
503
529
  },
504
- React.createElement('span', { className: 'dsh-super-code-circle ' + tone, 'aria-hidden': true }, row.id === view.root ? '主' : String(rows.findIndex(item => item.id === row.id))),
530
+ React.createElement('span', { className: 'dsh-super-code-circle ' + tone, 'aria-hidden': true }, row.id === view.root ? text(t, 'main.agent').slice(0, 1) : String(rows.findIndex(item => item.id === row.id))),
505
531
  React.createElement('span', { className: 'dsh-super-code-tree-content' },
506
532
  React.createElement('span', { className: 'dsh-super-code-tree-title' }, title),
507
- React.createElement('span', { className: 'dsh-super-code-tree-usage', title: `本节点及所有已知下级合计,包含本节点。${partial ? '部分记录或用量尚不可用;仅显示已知值。' : ''}Token ${usage.tokens.toLocaleString('zh-CN')};缓存读取 ${usage.cache.toLocaleString('zh-CN')};${usage.agents} 个 Agent` },
508
- React.createElement('span', null, usage.known ? `${number(usage.tokens)} token` : '用量 —'),
509
- React.createElement('span', null, usage.known ? `缓存 ${usage.input ? Math.round(usage.cache / usage.input * 100) : 0}%${partial ? ' · 部分' : ''}` : '缓存 —')))),
533
+ React.createElement('span', { className: 'dsh-super-code-tree-usage', title: text(t, 'tree.usage', { partial: partial ? text(t, 'usage.incomplete') : '', tokens: usage.tokens.toLocaleString(), cache: usage.cache.toLocaleString(), agents: usage.agents }) },
534
+ React.createElement('span', null, usage.known ? `${number(usage.tokens)} token` : text(t, 'usage.unknown')),
535
+ React.createElement('span', null, usage.known ? text(t, 'usage.cache', { value: usage.input ? Math.round(usage.cache / usage.input * 100) : 0 }) + (partial ? ` · ${text(t, 'usage.partial')}` : '') : 'Cache —')))),
510
536
  hasChildren && React.createElement('button', { type: 'button', className: 'dsh-super-code-branch-toggle',
511
- style: { left: row.x + 21, top: row.y + 25 }, 'aria-label': `${collapsed.has(row.id) || !isExpanded ? '展开' : '收起'} ${title} 的下级`,
512
- title: '整理下级节点;运行中的分支始终保留', onClick: () => toggleBranch(row.id) },
537
+ style: { left: row.x + 21, top: row.y + 25 }, 'aria-label': `${collapsed.has(row.id) || !isExpanded ? text(t, 'tree.expand') : text(t, 'tree.collapse')} ${title}`,
538
+ title: text(t, 'tree.organize'), onClick: () => toggleBranch(row.id) },
513
539
  React.createElement('svg', { width: 12, height: 12, viewBox: '0 0 12 12', 'aria-hidden': true, style: { transform: collapsed.has(row.id) || !isExpanded ? 'rotate(-90deg)' : undefined } },
514
540
  React.createElement('path', { d: 'M3 4.5 6 7.5 9 4.5', fill: 'none', stroke: 'currentColor', strokeWidth: 1.5 }))))
515
541
  }))),
516
- more && React.createElement('button', { type: 'button', className: 'dsh-super-code-tree-more', onClick: () => setLimit(limit + 200) }, '显示更多'))
542
+ more && React.createElement('button', { type: 'button', className: 'dsh-super-code-tree-more', onClick: () => setLimit(limit + 200) }, text(t, 'tree.more')))
517
543
  }
518
544
 
519
545
  function agentDetailAddress(node) {
@@ -554,22 +580,22 @@ function contentText(blocks) {
554
580
  }).filter(Boolean).join('\n\n')
555
581
  }
556
582
 
557
- function detailRecord(entry) {
583
+ function detailRecord(entry, t = key => zh[key] || key) {
558
584
  const event = entry.event, data = event?.data
559
585
  if (!data) return { kind: 'skip' }
560
586
  const base = { seq: event.seq, time: event.time }
561
587
  if (event.type === 'user/message') {
562
588
  if (data.source?.kind !== 'user') return { kind: 'skip' }
563
- return { ...base, kind: 'message', label: '任务', text: contentText(data.content) }
589
+ return { ...base, kind: 'message', label: text(t, 'detail.task'), text: contentText(data.content) }
564
590
  }
565
- if (event.type === 'assistant/message') return { ...base, kind: 'message', label: data.interrupted ? 'Agent · 已中断' : 'Agent', text: contentText(data.message?.content) }
566
- if (event.type === 'turn/error') return { ...base, kind: 'error', label: '执行错误', text: data.message || '执行未完成,请稍后重试。' }
591
+ if (event.type === 'assistant/message') return { ...base, kind: 'message', label: data.interrupted ? text(t, 'detail.interrupted') : text(t, 'detail.agent'), text: contentText(data.message?.content) }
592
+ if (event.type === 'turn/error') return { ...base, kind: 'error', label: text(t, 'detail.error'), text: data.message || text(t, 'detail.incomplete') }
567
593
  return { kind: 'skip' }
568
594
  }
569
595
 
570
596
  // The host journal owns decoding, cursor validation and reconnects. This view
571
597
  // keeps a bounded display window and never stages or sends to another session.
572
- function createAgentInspector(createStream, address, readPage, initial) {
598
+ function createAgentInspector(createStream, address, readPage, initial, t = key => zh[key] || key) {
573
599
  let snapshot = initial || { status: 'loading', items: [], hasMore: false, earlier: false, truncated: false, projections: {}, error: '', firstSeq: 0, cursor: -1 }
574
600
  let cursor = snapshot.cursor
575
601
  let disposed = false, stream
@@ -580,7 +606,7 @@ function createAgentInspector(createStream, address, readPage, initial) {
580
606
  snapshot = { ...snapshot, cursor, ...patch }
581
607
  listeners.forEach(listener => listener())
582
608
  }
583
- const itemsOf = entries => entries.map(detailRecord).filter(item => item.kind !== 'skip' && item.text)
609
+ const itemsOf = entries => entries.map(entry => detailRecord(entry, t)).filter(item => item.kind !== 'skip' && item.text)
584
610
  stream = createStream(agentDetailTarget(address), {
585
611
  publish: change => {
586
612
  if (disposed) return
@@ -609,13 +635,13 @@ function createAgentInspector(createStream, address, readPage, initial) {
609
635
  }
610
636
  }
611
637
  },
612
- carrierFailed: () => publish({ error: '连接中断,正在重连' }),
613
- failed: () => publish({ status: 'error', error: '对话详情读取失败' }),
638
+ carrierFailed: () => publish({ error: text(t, 'detail.connection') }),
639
+ failed: () => publish({ status: 'error', error: text(t, 'detail.loadError') }),
614
640
  })
615
641
  return {
616
642
  getSnapshot: () => snapshot,
617
643
  subscribe: listener => { listeners.add(listener); return () => listeners.delete(listener) },
618
- start: () => { stream.open({ maxMessages: 40 }).catch(() => publish({ status: 'error', error: '对话详情读取失败' })) },
644
+ start: () => { stream.open({ maxMessages: 40 }).catch(() => publish({ status: 'error', error: text(t, 'detail.loadError') })) },
619
645
  older: async () => {
620
646
  if (snapshot.status === 'paging' || !snapshot.hasMore) return
621
647
  publish({ status: 'paging', error: '' })
@@ -628,20 +654,20 @@ function createAgentInspector(createStream, address, readPage, initial) {
628
654
  firstSeq: items.length > 200 ? visible[0].seq : result.value.records[0]?.event.seq ?? 0,
629
655
  hasMore: result.value.hasMore || items.length > 200 })
630
656
  }
631
- catch { publish({ status: 'error', error: '历史记录读取失败' }) }
657
+ catch { publish({ status: 'error', error: text(t, 'detail.historyError') }) }
632
658
  },
633
659
  dispose: () => { disposed = true; listeners.clear(); void stream.dispose() },
634
660
  }
635
661
  }
636
662
 
637
- function DetailText({ text }) {
663
+ function DetailText({ text: value, t = key => zh[key] || key }) {
638
664
  const [full, setFull] = useState(false)
639
665
  return React.createElement(React.Fragment, null,
640
- React.createElement('pre', null, full ? text : text.slice(0, 12000)),
641
- !full && text.length > 12000 && React.createElement('button', { type: 'button', onClick: () => setFull(true) }, '展开全文'))
666
+ React.createElement('pre', null, full ? value : value.slice(0, 12000)),
667
+ !full && value.length > 12000 && React.createElement('button', { type: 'button', onClick: () => setFull(true) }, text(t, 'detail.open')))
642
668
  }
643
669
 
644
- function AgentDetail({ useTabInfo, useSessions, createInspector, detailStates }) {
670
+ function AgentDetail({ useTabInfo, useSessions, createInspector, detailStates, t = key => zh[key] || key }) {
645
671
  const { tab } = useTabInfo()
646
672
  const state = useSessions(s => s)
647
673
  const saved = useMemo(() => {
@@ -687,52 +713,52 @@ function AgentDetail({ useTabInfo, useSessions, createInspector, detailStates })
687
713
  const projections = state.byId[id]?.projectionValues || snapshot.projections
688
714
  const totals = projections.superAgentUsage?.totals || projections.tokenUsage
689
715
  const input = totals ? (totals.uncachedInputTokens || 0) + (totals.cacheReadTokens || 0) + (totals.cacheWriteTokens || 0) : 0
690
- const format = value => value === undefined ? '未提供' : value.toLocaleString('zh-CN')
716
+ const format = value => value === undefined ? text(t, 'detail.unavailable') : value.toLocaleString(localeCode(t))
691
717
  const tasks = projections.superCodeTasks
692
718
  const task = tasks?.current?.kind === 'task' ? tasks.current : undefined
693
- const title = node?.title || node?.displayTitle || 'Agent 详情'
719
+ const title = node?.title || node?.displayTitle || text(t, 'detail.title')
694
720
  const metrics = [
695
- ['输入', totals ? input : undefined], ['输出', totals?.outputTokens],
696
- ['缓存读取', totals?.cacheReadTokens], ['缓存写入', totals?.cacheWriteTokens],
721
+ [text(t, 'detail.input'), totals ? input : undefined], [text(t, 'detail.output'), totals?.outputTokens],
722
+ [text(t, 'detail.cacheRead'), totals?.cacheReadTokens], [text(t, 'detail.cacheWrite'), totals?.cacheWriteTokens],
697
723
  ]
698
724
  return React.createElement('section', { className: 'dsh-super-code-detail', 'data-agent-detail': id },
699
725
  React.createElement('header', { className: 'dsh-super-code-detail-header' },
700
- React.createElement('nav', { 'aria-label': 'Agent 路径' }, path.map((part, index) => React.createElement('span', { key: part.id }, index > 0 ? ' / ' : '', part.title))),
726
+ React.createElement('nav', { 'aria-label': text(t, 'detail.path') }, path.map((part, index) => React.createElement('span', { key: part.id }, index > 0 ? ' / ' : '', part.title))),
701
727
  React.createElement('div', { className: 'dsh-super-code-detail-heading' },
702
728
  React.createElement('div', null,
703
729
  React.createElement('h2', null, title),
704
- React.createElement('span', { className: 'dsh-super-code-detail-status' }, agentExecutionStatus(node, id === view.root).label)),
705
- React.createElement('button', { type: 'button', className: 'dsh-super-code-icon-button', title: '刷新对话详情', 'aria-label': '刷新对话详情', onClick: latest }, React.createElement(IconRefreshOutline16))),
730
+ React.createElement('span', { className: 'dsh-super-code-detail-status' }, agentExecutionStatus(node, id === view.root, t).label)),
731
+ React.createElement('button', { type: 'button', className: 'dsh-super-code-icon-button', title: text(t, 'detail.refresh'), 'aria-label': text(t, 'detail.refresh'), onClick: latest }, React.createElement(IconRefreshOutline16))),
706
732
  id !== view.root && task?.goal && task.goal !== title && React.createElement('p', { className: 'dsh-super-code-detail-task' }, task.goal),
707
- id === view.root && React.createElement(TaskMemoryPanel, { state: tasks }),
733
+ id === view.root && React.createElement(TaskMemoryPanel, { state: tasks, t }),
708
734
  React.createElement('dl', { className: 'dsh-super-code-detail-metrics' },
709
- React.createElement('div', null, React.createElement('dt', null, 'Token 总量'), React.createElement('dd', null, format(totals ? input + (totals.outputTokens || 0) : undefined))),
710
- React.createElement('div', null, React.createElement('dt', null, '缓存命中率'), React.createElement('dd', null, totals ? (input ? Math.round((totals.cacheReadTokens || 0) / input * 100) : 0) + '%' : '未提供'))),
735
+ React.createElement('div', null, React.createElement('dt', null, text(t, 'detail.total')), React.createElement('dd', null, format(totals ? input + (totals.outputTokens || 0) : undefined))),
736
+ React.createElement('div', null, React.createElement('dt', null, text(t, 'detail.hitRate')), React.createElement('dd', null, totals ? (input ? Math.round((totals.cacheReadTokens || 0) / input * 100) : 0) + '%' : text(t, 'detail.unavailable')))),
711
737
  React.createElement('details', { className: 'dsh-super-code-usage-details', open: saved.open.has('usage'), onToggle: event => { if (event.currentTarget.open) saved.open.add('usage'); else saved.open.delete('usage') } },
712
- React.createElement('summary', null, '用量详情'),
738
+ React.createElement('summary', null, text(t, 'detail.moreUsage')),
713
739
  React.createElement('dl', { className: 'dsh-super-code-detail-metrics' }, metrics.map(([label, value]) => React.createElement('div', { key: label }, React.createElement('dt', null, label), React.createElement('dd', null, format(value))))))),
714
- React.createElement('div', { ref: log, className: 'dsh-super-code-detail-log', 'aria-label': 'Agent 执行内容', onScroll: event => {
740
+ React.createElement('div', { ref: log, className: 'dsh-super-code-detail-log', 'aria-label': text(t, 'tree.title'), onScroll: event => {
715
741
  const element = event.currentTarget
716
742
  saved.top = element.scrollTop
717
743
  saved.following = !snapshot.earlier && element.scrollHeight - element.clientHeight - element.scrollTop < 32
718
744
  if (saved.following) markUnread(false)
719
745
  } },
720
746
  snapshot.error && React.createElement('p', { role: 'alert' }, snapshot.error),
721
- snapshot.status === 'loading' && React.createElement('p', { role: 'status' }, '正在读取对话…'),
722
- snapshot.hasMore && React.createElement('button', { type: 'button', disabled: snapshot.status === 'paging', onClick: inspector.older }, snapshot.status === 'paging' ? '读取中…' : '加载更早记录'),
723
- (snapshot.earlier || snapshot.truncated) && React.createElement('button', { type: 'button', onClick: latest }, '回到最新'),
724
- snapshot.status === 'ready' && !snapshot.items.length && React.createElement('p', null, '暂无执行内容'),
747
+ snapshot.status === 'loading' && React.createElement('p', { role: 'status' }, text(t, 'detail.reading')),
748
+ snapshot.hasMore && React.createElement('button', { type: 'button', disabled: snapshot.status === 'paging', onClick: inspector.older }, snapshot.status === 'paging' ? text(t, 'detail.read') : text(t, 'detail.older')),
749
+ (snapshot.earlier || snapshot.truncated) && React.createElement('button', { type: 'button', onClick: latest }, text(t, 'detail.latest')),
750
+ snapshot.status === 'ready' && !snapshot.items.length && React.createElement('p', null, text(t, 'detail.empty')),
725
751
  snapshot.items.map(item => React.createElement('article', { key: item.seq, className: 'dsh-super-code-detail-entry ' + item.kind },
726
752
  item.collapsed ? React.createElement('details', { open: saved.open.has(item.seq), onToggle: event => { if (event.currentTarget.open) saved.open.add(item.seq); else saved.open.delete(item.seq) } },
727
753
  React.createElement('summary', null, item.label),
728
- React.createElement(DetailText, { text: item.text }))
754
+ React.createElement(DetailText, { text: item.text, t }))
729
755
  : React.createElement(React.Fragment, null,
730
756
  React.createElement('div', { className: 'dsh-super-code-detail-entry-label' }, item.label,
731
- React.createElement('time', null, new Date(item.time).toLocaleTimeString('zh-CN', { hour12: false }))),
732
- React.createElement(DetailText, { text: item.text })))) ),
757
+ React.createElement('time', null, new Date(item.time).toLocaleTimeString(localeCode(t), { hour12: false }))),
758
+ React.createElement(DetailText, { text: item.text, t })))) ),
733
759
  unread && React.createElement('button', { type: 'button', className: 'dsh-super-code-new-content', onClick: () => {
734
760
  saved.following = true; log.current.scrollTop = log.current.scrollHeight; markUnread(false)
735
- } }, '有新内容 · 查看最新'))
761
+ } }, text(t, 'detail.new')))
736
762
  }
737
763
 
738
764
  const inject = [
@@ -741,6 +767,9 @@ const inject = [
741
767
  ]
742
768
 
743
769
  function apply(ctx) {
770
+ const locale = ctx.locale || { register: () => () => {}, bind: () => key => zh[key] || key }
771
+ ctx.effect(() => locale.register(LOCALE_NS, { zh, en }), 'dsh-super-code: dictionaries')
772
+ const t = locale.bind(LOCALE_NS)
744
773
  ctx.effect(() => {
745
774
  const style = document.createElement('style')
746
775
  style.dataset.dshSuperCode = 'true'
@@ -882,8 +911,8 @@ function apply(ctx) {
882
911
  const treeKind = 'super-agent-agents'
883
912
  const disposeTreeType = ctx.sidebarRightTabs.register({
884
913
  id: treeId, kind: treeKind,
885
- title: () => 'Agent 执行树',
886
- guide: [{ order: 40, title: () => 'Agent 执行树', description: () => '查看 Agent 层级和执行对话' }],
914
+ title: () => t('tree.aria'),
915
+ guide: [{ order: 40, title: () => t('tree.aria'), description: () => t('tree.canvas') }],
887
916
  })
888
917
  const treeActions = {
889
918
  // The host unmounts hidden bodies; tab signals live until close/unload.
@@ -897,20 +926,20 @@ function apply(ctx) {
897
926
  title: address => {
898
927
  const target = agentDetailTarget(address), state = ctx.sessions.list.getSnapshot()
899
928
  const node = buildAgentView(state).nodes.get(target.childSessionId || target.sessionId)
900
- return node?.title || node?.displayTitle || 'Agent 详情'
929
+ return node?.title || node?.displayTitle || t('detail.title')
901
930
  },
902
931
  })
903
932
  const detailActions = { detailStates: new WeakMap(), createInspector: (address, initial) => createAgentInspector(
904
933
  (target, options) => new SessionEventStream(ctx.remote, target, options), address,
905
- (request, signal) => ctx.remote.session.page(request, signal), initial) }
934
+ (request, signal) => ctx.remote.session.page(request, signal), initial, t) }
906
935
  ctx.slots.inject('sidebar.right.pane.tab', () => ctx.slots.register({
907
- name: 'sidebar.right.pane.tab', key: 'dsh-super-code-detail', inject: () => detailActions,
936
+ name: 'sidebar.right.pane.tab', key: 'dsh-super-code-detail', inject: () => ({ ...detailActions, t }),
908
937
  }, AgentDetail))
909
938
  ctx.slots.inject('sidebar.right.pane.tab', () => ctx.slots.register({
910
939
  // Keyed tab bodies dispatch by the definition id, while `kind` is the
911
940
  // page/content discriminator used by the Sidebar controller.
912
941
  name: 'sidebar.right.pane.tab', key: treeId,
913
- inject: () => treeActions,
942
+ inject: () => ({ ...treeActions, t }),
914
943
  }, AgentTree))
915
944
  ctx.effect(() => disposeTreeType, 'super-code: Agent tree tab')
916
945
  ctx.effect(() => disposeDetailType, 'super-code: Agent detail tab')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-super-code",
3
- "version": "0.0.9",
3
+ "version": "0.1.0",
4
4
  "description": "One super-code preset with specialist teams and durable task memory for DeepSeek Harness.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -78,8 +78,7 @@
78
78
  "typecheck": "tsc -p tsconfig.json --noEmit",
79
79
  "test": "tsx --test test/**/*.test.ts",
80
80
  "pack:check": "npm pack --dry-run",
81
- "eval:super-code": "node lib/evaluate.js",
82
- "provider:health": "node eval/runners/provider-health.mjs"
81
+ "eval:super-code": "node lib/evaluate.js"
83
82
  },
84
83
  "engines": {
85
84
  "node": ">=22"