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.
- package/README.md +62 -120
- package/client/index.js +129 -100
- package/package.json +2 -3
package/README.md
CHANGED
|
@@ -1,162 +1,104 @@
|
|
|
1
1
|
# dsh-super-code
|
|
2
2
|
|
|
3
|
-
DeepSeek Harness
|
|
3
|
+
一个更快、更节省、更准确的 DeepSeek Harness 编码插件。
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
在选定的 SWE-bench Pro hard-100 评测中,平均耗时减少约 36%,每题输入 token 减少约 17%,正确率提高 5 个百分点。
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
A faster, more accurate, and more cost-effective DeepSeek Harness plug-in component.
|
|
8
8
|
|
|
9
|
-
SWE-bench
|
|
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
|
-
|
|
12
|
-
|---|---:|---:|
|
|
13
|
-
| 正确率 | 99% | 99% |
|
|
14
|
-
| 平均总 token | 737,421 | 419,145(-43%) |
|
|
15
|
-
| 平均耗时 | 314 秒 | 89 秒(-72%) |
|
|
11
|
+
## 介绍 · Introduction
|
|
16
12
|
|
|
17
|
-
|
|
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
|
-
|
|
17
|
+
它会根据任务选择调研、设计、开发、验证和优化方法,简单任务直接完成,复杂任务按需组织工作。
|
|
22
18
|
|
|
23
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
35
|
+
[](docs/images/preset-settings.png)
|
|
68
36
|
|
|
69
|
-
|
|
37
|
+
当前版本不使用三模型池,也不需要单独配置插件模型。在 Harness“设置”→“模型”中配置提供方,再从对话输入框下方选择模型和推理等级;已有可用配置时直接沿用。插件跟随当前会话的模型,子 Agent 在未单独覆盖时继承父 Agent 的选择。
|
|
70
38
|
|
|
71
|
-
-
|
|
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
|
-
|
|
41
|
+
## 效果 · Results
|
|
78
42
|
|
|
79
|
-
|
|
43
|
+
SWE-bench Pro hard-100,使用 `deepseek-v4.1-flash`、reasoning `high`、原生 DSH Web RPC 和官方评分器。
|
|
80
44
|
|
|
81
|
-
|
|
45
|
+
SWE-bench Pro hard-100 with `deepseek-v4.1-flash`, reasoning `high`, native DSH Web RPC, and the official grader.
|
|
82
46
|
|
|
83
|
-
|
|
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
|
-
|
|
56
|
+
这批结果来自 `0.0.9` 候选;`0.1.0` 沿用该历史基准,未重新执行完整 100 题评测。
|
|
86
57
|
|
|
87
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
80
|
+
测试题号和每题明细见 [`eval/results/swebench-pro-final-100/`](eval/results/swebench-pro-final-100/),详细文档见 [`docs/`](docs/)。
|
|
96
81
|
|
|
97
|
-
|
|
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
|
-
|
|
84
|
+
## 使用 · Usage
|
|
100
85
|
|
|
101
|
-
|
|
86
|
+
安装后,在 DeepSeek Harness 的“设置”→“Agent 预设”中选择 `super-code`。创建任务后,插件会按任务复杂度组织调研、实现和验证;复杂任务可在右侧 Agent 执行树中查看进度,点击节点查看对应的执行内容和用量。
|
|
102
87
|
|
|
103
|
-
|
|
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
|
-
|
|
90
|
+
[](docs/images/agent-tree.png)
|
|
106
91
|
|
|
107
|
-
|
|
92
|
+
截图来自全新隔离会话中的 DSH 网页版,展示 hard-100 难度排名第一题 `task-099`(`future-architect/vuls` 的 OS 生命周期预警)的初步调研:一个主 Agent 与三个子 Agent 分别核查 EOL/版本解析、告警链路和测试边界。图中保留了整个右侧栏,包括状态、用量、缓存率和缩放操作;这是协作展示,不代表该题已修复或通过评分。
|
|
108
93
|
|
|
109
|
-
|
|
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
|
-
|
|
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
|
-
|
|
100
|
+
## 感谢 · Thanks
|
|
116
101
|
|
|
117
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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: '
|
|
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, '
|
|
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 ||
|
|
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':
|
|
253
|
-
React.createElement('input', { type: 'search', value: filters.query, 'aria-label':
|
|
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', '
|
|
256
|
-
select('sort', '
|
|
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 ? '
|
|
260
|
-
React.createElement('p', { className: 'dsh-super-code-history-summary', role: 'status' }, range.valid ?
|
|
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 ? '
|
|
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(
|
|
270
|
-
'aria-label':
|
|
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(
|
|
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: '
|
|
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' },
|
|
443
|
-
React.createElement('button', { type: 'button', className: 'dsh-super-code-icon-button', disabled: busy || !view.root, onClick: reload, title: '
|
|
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
|
-
['
|
|
447
|
-
React.createElement('i', { className: 'dsh-super-code-circle ' + ['active', 'idle', 'stopped', 'unavailable'][index], 'aria-hidden': true }),
|
|
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': '
|
|
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': '
|
|
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) },
|
|
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':
|
|
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 ||
|
|
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(
|
|
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 ? '
|
|
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:
|
|
508
|
-
React.createElement('span', null, usage.known ? `${number(usage.tokens)} token` :
|
|
509
|
-
React.createElement('span', null, usage.known ?
|
|
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 ? '
|
|
512
|
-
title: '
|
|
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: '
|
|
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 ?
|
|
566
|
-
if (event.type === 'turn/error') return { ...base, kind: 'error', label: '
|
|
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 ?
|
|
641
|
-
!full &&
|
|
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 ? '
|
|
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 ||
|
|
719
|
+
const title = node?.title || node?.displayTitle || text(t, 'detail.title')
|
|
694
720
|
const metrics = [
|
|
695
|
-
['
|
|
696
|
-
['
|
|
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':
|
|
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: '
|
|
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,
|
|
710
|
-
React.createElement('div', null, React.createElement('dt', null, '
|
|
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':
|
|
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
|
-
|
|
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(
|
|
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: () => '
|
|
886
|
-
guide: [{ order: 40, title: () => '
|
|
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 || '
|
|
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
|
|
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"
|