dsh-eval-guard 0.4.1 → 0.6.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 +13 -3
- package/assets/neural-cifar/workspace.zip +0 -0
- package/assets/neural-fp32/workspace.zip +0 -0
- package/eval/__pycache__/neural-cifar.cpython-310.pyc +0 -0
- package/eval/__pycache__/neural-fp32.cpython-310.pyc +0 -0
- package/eval/neural-cifar.py +15 -0
- package/eval/neural-fp32.py +502 -0
- package/lib/client/index.js +18 -3
- package/lib/client/index.js.map +1 -1
- package/lib/index.js +97 -8
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -25,19 +25,27 @@
|
|
|
25
25
|
| SWE-Bench Pro 单任务 | 1440 分钟,默认关闭 |
|
|
26
26
|
| FeatureBench 单 feature | 1440 分钟,默认关闭 |
|
|
27
27
|
| Neural-CPP 纯 C++ 张量后端 | 1440 分钟,默认关闭 |
|
|
28
|
+
| Neural-FP32 纯 C++ 运算与性能 | 1440 分钟,默认关闭 |
|
|
29
|
+
| Neural-CIFAR 从零训练图像分类 | 1440 分钟,默认关闭 |
|
|
28
30
|
|
|
29
31
|
## 任务与安装
|
|
30
32
|
|
|
31
|
-
|
|
33
|
+
设置页可安装十一个任务包:
|
|
32
34
|
|
|
33
35
|
- 原 5 个比赛任务:坦克大战、仓储调度、圈地、炸弹人、夺旗。
|
|
34
36
|
- 3 个长时单任务:Commit0 单库实现、SWE-Bench Pro 单任务、FeatureBench 单 feature。
|
|
35
|
-
-
|
|
37
|
+
- 3 个纯 C++ 项目:Neural-CPP 张量后端、Neural-FP32 运算与性能、Neural-CIFAR 图像分类训练。
|
|
36
38
|
|
|
37
39
|
Neural-CPP 安装时自动把 workspace.zip 解压到工作区根目录,并在完成后移除 setup.sh;agent 从根目录的 CMakeLists.txt 开始。工作区只包含 TASK.md、CMakeLists.txt 和 include/nn/nn.hpp;实现在 src/ 中从零完成,纯 C++17,无 Python/OpenCL/第三方库。
|
|
38
40
|
|
|
39
41
|
评测器同时兼容旧安装留下的嵌套布局:若根目录没有 CMakeLists.txt,会自动改用 workspace/CMakeLists.txt,避免已经产出的工作区无法评测。
|
|
40
42
|
|
|
43
|
+
Neural-FP32 是独立的新任务:固定 fp32,不做完整训练;agent 从零实现 `build/nn_task` CLI,覆盖逐元素、matmul、linear、relu、softmax、layernorm、mse、conv2d、对应反向传播、AdamW 和 SGD momentum。评测侧用 PyTorch 在相同数据和参数上计算参考值,逐操作输出可执行性、是否通过误差阈值、加权平均相对误差、速度,并在最前面给出是否所有操作可执行、最大加权平均相对误差和速度几何平均;不提供统一 score,速度不受误差门控影响。
|
|
44
|
+
|
|
45
|
+
Neural-CIFAR 在 Neural-FP32 的基础上要求 agent 用同一套 C++ 训练框架构造并训练 CIFAR-10 图像分类网络。任务不限时,agent 定位为神经网络全栈设计与优化大师,提交前应尽可能优化;速度和未知验证集准确率都是重要指标,会参与世界顶尖水平比拼。安装时下载并准备 50k train split;隐藏 10k test split 由独立评测目录 `dsh-eval-guard/neural-cifar-eval/fetch_cifar.py` 获取并放在该目录的 `hidden/`,不作为工作区文件。评测保留全部原算子指标,并额外用 4 线程和全部逻辑 CPU 分别跑推理,输出验证准确率、FPS、平均单图耗时;4 线程 0.02s/image 只报告,不门控。
|
|
46
|
+
|
|
47
|
+
CIFAR-10 下载缓存固定在用户 home 下:`~/.dsh/eval-guard/cache/cifar10/`,保存 train/val 的 images/labels。下载使用 `~/.dsh/eval-guard/cache/cifar10/.download.lock` 独占锁,并实时打印进度;锁存在时认为其他 DSH 实例正在下载,任务安装/评测会提示等待或手动删除锁文件。缓存完整且无锁时直接复用。设置页新增「CIFAR download proxy」输入框,只用于 CIFAR 下载;按任务安装和评测时分别传给 setup/fetch 脚本。
|
|
48
|
+
|
|
41
49
|
评测时在临时目录独立构建,然后从 assets/neural-cpp/hidden/ 注入 C++ 测试源码;测试数据由固定种子在进程内生成,不依赖或复制外部数据文件。
|
|
42
50
|
|
|
43
51
|
结果返回 coreAccuracy(核心 C++ 测试通过率)、matrixAccuracy、逐类型 metrics(f32/int128/MXFP4 的矩阵与反向准确率、平均绝对误差、fwd/bwd 毫秒、fwd/bwd GFLOP/s)、speedGflops,以及按矩阵吞吐计算的 speedGeomeanGflops 和 matrixSizes(f32/i128/MXFP4 均为 256×256×256)。确定性项目使用 4 组独立输入取平均;MXFP4 RNE 和随机舍入分开统计,随机舍入使用 2 组输入×每组 1024 次采样,逐元素比较参考均值/标准差和候选均值/标准差,按 3σ 和 0.1–10× 标准差规则统计正确率。参考值由测试侧独立标量实现先算完,再调用候选实现,参考计算不计入候选耗时。隐藏测试不在工作区,agent 无法读取。开发要求线程数最多 4,评测阶段使用全部逻辑 CPU。
|
|
@@ -76,11 +84,13 @@ Gitee/GitCode 都使用 git fetch --depth 1 origin <任务 commit> 验证。GitL
|
|
|
76
84
|
|
|
77
85
|
设置页安装/评测共用一组任务和工作区选择;「评测当前工作区」只评测一个结果,不生成排行。
|
|
78
86
|
|
|
79
|
-
插件 eval/ 目录内置全部
|
|
87
|
+
插件 eval/ 目录内置全部 11 个任务的单结果评测脚本:
|
|
80
88
|
|
|
81
89
|
- Commit0:单元测试通过率。
|
|
82
90
|
- SWE-Bench Pro / FeatureBench:隐藏 F2P/P2P 测试;全部通过才 resolved,同时返回 passRate。
|
|
83
91
|
- Neural-CPP:独立编译隐藏 C++ 测试,返回 accuracy 与 matmul speedGflops;数据在测试进程内按固定种子生成。
|
|
92
|
+
- Neural-FP32:调用候选 build/nn_task,用 PyTorch 参考值统计每个操作的 MRE 和速度;汇总项在最前面,不输出统一 score。
|
|
93
|
+
- Neural-CIFAR:保留 Neural-FP32 的算子评测,加载训练好的模型,在隐藏验证集上分别用 4 线程和全部线程测准确率/FPS;独立脚本在 `dsh-eval-guard/neural-cifar-eval/`。
|
|
84
94
|
- Tank / Warehouse / Land / Bomberman / CTF:运行官方引擎/裁判,只返回当前工作区候选者结果,不生成排名。
|
|
85
95
|
|
|
86
96
|
评测也是后台任务,日志和结果实时显示,持久化在 jobs 目录。
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Plugin wrapper for the standalone Neural-CIFAR evaluator."""
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
import os
|
|
5
|
+
import sys
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
HERE = Path(__file__).resolve().parent
|
|
9
|
+
STANDALONE = HERE.parent / 'neural-cifar-eval' / 'run_eval.py'
|
|
10
|
+
|
|
11
|
+
if not STANDALONE.is_file():
|
|
12
|
+
print('neural-cifar-eval/run_eval.py missing; copy the standalone evaluator folder first', file=sys.stderr)
|
|
13
|
+
raise SystemExit(1)
|
|
14
|
+
|
|
15
|
+
os.execv(sys.executable, [sys.executable, '-X', 'utf8', str(STANDALONE), *sys.argv[1:]])
|
|
@@ -0,0 +1,502 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Evaluate Neural-FP32: numeric error + speed per operation.
|
|
3
|
+
|
|
4
|
+
Reference numbers are computed with PyTorch on the same data/parameters.
|
|
5
|
+
No expected tensors are stored in the workspace. Candidate timing only wraps
|
|
6
|
+
the CLI call; PyTorch reference computation is outside the timed region.
|
|
7
|
+
"""
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import math
|
|
11
|
+
import os
|
|
12
|
+
import shutil
|
|
13
|
+
import subprocess
|
|
14
|
+
import sys
|
|
15
|
+
import tempfile
|
|
16
|
+
import time
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
|
|
19
|
+
import numpy as np
|
|
20
|
+
import torch
|
|
21
|
+
import torch.nn.functional as F
|
|
22
|
+
|
|
23
|
+
from common import EVAL_ROOT, clean_copy, emit, fail, parse_workspace
|
|
24
|
+
|
|
25
|
+
torch.set_num_threads(1)
|
|
26
|
+
torch.set_float32_matmul_precision('highest')
|
|
27
|
+
torch.use_deterministic_algorithms(True)
|
|
28
|
+
torch.backends.mkldnn.deterministic = True
|
|
29
|
+
torch.manual_seed(1234)
|
|
30
|
+
|
|
31
|
+
SEEDS = (11, 22, 33)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def write_tensor(path: Path, t: torch.Tensor) -> None:
|
|
35
|
+
arr = t.detach().cpu().contiguous().numpy().astype('<f4', copy=False)
|
|
36
|
+
path.write_bytes(arr.tobytes())
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def read_tensor(path: Path, shape: tuple[int, ...]) -> torch.Tensor:
|
|
40
|
+
arr = np.frombuffer(path.read_bytes(), dtype='<f4').copy()
|
|
41
|
+
return torch.from_numpy(arr).reshape(shape)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def mre(cand: torch.Tensor, ref: torch.Tensor) -> float:
|
|
45
|
+
if cand.shape != ref.shape:
|
|
46
|
+
return float('inf')
|
|
47
|
+
c = cand.detach().cpu().numpy().astype(np.float64)
|
|
48
|
+
r = ref.detach().cpu().numpy().astype(np.float64)
|
|
49
|
+
if not np.isfinite(c).all():
|
|
50
|
+
return float('inf')
|
|
51
|
+
den = max(float(np.abs(r).sum()), 1e-30)
|
|
52
|
+
return float(np.abs(c - r).sum() / den)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def build_candidate(workspace: Path, root: Path) -> Path:
|
|
56
|
+
candidate = root / 'candidate'
|
|
57
|
+
clean_copy(workspace, candidate)
|
|
58
|
+
source = candidate
|
|
59
|
+
if not (source / 'CMakeLists.txt').is_file() and (candidate / 'workspace' / 'CMakeLists.txt').is_file():
|
|
60
|
+
source = candidate / 'workspace'
|
|
61
|
+
if not (source / 'CMakeLists.txt').is_file():
|
|
62
|
+
raise RuntimeError('CMakeLists.txt missing at workspace root or workspace/')
|
|
63
|
+
build = source / 'build'
|
|
64
|
+
if build.exists():
|
|
65
|
+
shutil.rmtree(build, ignore_errors=True)
|
|
66
|
+
build.mkdir(parents=True)
|
|
67
|
+
cfg = subprocess.run(['cmake', '-S', '.', '-B', 'build', '-DCMAKE_BUILD_TYPE=Release'],
|
|
68
|
+
cwd=str(source), capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=180)
|
|
69
|
+
if cfg.returncode != 0:
|
|
70
|
+
raise RuntimeError('cmake configure failed\n' + (cfg.stdout + cfg.stderr)[-4000:])
|
|
71
|
+
made = subprocess.run(['cmake', '--build', 'build', '-j4'], cwd=str(source), capture_output=True,
|
|
72
|
+
text=True, encoding='utf-8', errors='replace', timeout=1800)
|
|
73
|
+
if made.returncode != 0:
|
|
74
|
+
raise RuntimeError('build failed\n' + (made.stdout + made.stderr)[-4000:])
|
|
75
|
+
binary = build / 'nn_task'
|
|
76
|
+
if not binary.is_file():
|
|
77
|
+
raise RuntimeError('build/nn_task missing')
|
|
78
|
+
return binary
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class Case:
|
|
82
|
+
def __init__(self, inputs: dict[str, torch.Tensor], outputs: dict[str, torch.Tensor],
|
|
83
|
+
args, flops: float):
|
|
84
|
+
self.inputs = inputs
|
|
85
|
+
self.outputs = outputs
|
|
86
|
+
self.args = args
|
|
87
|
+
self.flops = flops
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def run_operation(name: str, threshold: float, cases: list[Case], binary: Path, root: Path) -> dict:
|
|
91
|
+
op_dir = root / 'ops' / name
|
|
92
|
+
op_dir.mkdir(parents=True, exist_ok=True)
|
|
93
|
+
executable = True
|
|
94
|
+
total_diff = 0.0
|
|
95
|
+
total_ref = 0.0
|
|
96
|
+
total_sec = 0.0
|
|
97
|
+
total_flops = 0.0
|
|
98
|
+
first_error = ''
|
|
99
|
+
compared = False
|
|
100
|
+
for idx, case in enumerate(cases):
|
|
101
|
+
case_dir = op_dir / str(idx)
|
|
102
|
+
case_dir.mkdir(parents=True, exist_ok=True)
|
|
103
|
+
paths: dict[str, str] = {}
|
|
104
|
+
for key, tensor in case.inputs.items():
|
|
105
|
+
p = case_dir / (key + '.bin')
|
|
106
|
+
write_tensor(p, tensor)
|
|
107
|
+
paths[key] = str(p)
|
|
108
|
+
for key in case.outputs:
|
|
109
|
+
paths[key] = str(case_dir / (key + '.bin'))
|
|
110
|
+
cmd = [str(binary)] + [str(x) for x in case.args(paths)]
|
|
111
|
+
started = time.perf_counter()
|
|
112
|
+
try:
|
|
113
|
+
proc = subprocess.run(cmd, cwd=str(case_dir), capture_output=True, text=True,
|
|
114
|
+
encoding='utf-8', errors='replace', timeout=300)
|
|
115
|
+
except subprocess.TimeoutExpired:
|
|
116
|
+
executable = False
|
|
117
|
+
first_error = first_error or 'timeout'
|
|
118
|
+
continue
|
|
119
|
+
elapsed = time.perf_counter() - started
|
|
120
|
+
if proc.returncode != 0:
|
|
121
|
+
executable = False
|
|
122
|
+
first_error = first_error or (proc.stderr or proc.stdout or ('exit ' + str(proc.returncode)))[-500:]
|
|
123
|
+
continue
|
|
124
|
+
total_sec += elapsed
|
|
125
|
+
total_flops += case.flops
|
|
126
|
+
for key, ref in case.outputs.items():
|
|
127
|
+
p = case_dir / (key + '.bin')
|
|
128
|
+
if not p.is_file():
|
|
129
|
+
executable = False
|
|
130
|
+
first_error = first_error or ('missing output ' + key)
|
|
131
|
+
continue
|
|
132
|
+
try:
|
|
133
|
+
cand = read_tensor(p, tuple(ref.shape))
|
|
134
|
+
except Exception as exc:
|
|
135
|
+
executable = False
|
|
136
|
+
first_error = first_error or ('failed to read ' + key + ': ' + str(exc))
|
|
137
|
+
continue
|
|
138
|
+
# Numeric comparison is done even if the candidate is otherwise
|
|
139
|
+
# valid; a failed numeric comparison does not suppress speed.
|
|
140
|
+
total_ref += max(float(ref.detach().cpu().numpy().astype(np.float64).__abs__().sum()), 1e-30)
|
|
141
|
+
total_diff += float(np.abs(cand.detach().cpu().numpy().astype(np.float64) -
|
|
142
|
+
ref.detach().cpu().numpy().astype(np.float64)).sum())
|
|
143
|
+
compared = True
|
|
144
|
+
value = (total_diff / total_ref) if compared and total_ref > 0 else None
|
|
145
|
+
passed = executable and value is not None and value <= threshold
|
|
146
|
+
speed = (total_flops / total_sec / 1e9) if total_sec > 0 else None
|
|
147
|
+
return {
|
|
148
|
+
'name': name,
|
|
149
|
+
'executable': executable,
|
|
150
|
+
'passed': passed,
|
|
151
|
+
'weighted_mean_relative_error': value,
|
|
152
|
+
'threshold': threshold,
|
|
153
|
+
'speed_gflops': speed,
|
|
154
|
+
'error': first_error if not executable else '',
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def t(shape, seed, scale=1.0):
|
|
159
|
+
g = torch.Generator().manual_seed(seed)
|
|
160
|
+
return torch.randn(shape, generator=g, dtype=torch.float32) * scale
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
# ---------------------------------------------------------------------------
|
|
164
|
+
# Case builders. Every operation uses three independent data/parameter sets.
|
|
165
|
+
# ---------------------------------------------------------------------------
|
|
166
|
+
|
|
167
|
+
def cases_elementwise(op: str) -> list[Case]:
|
|
168
|
+
out = []
|
|
169
|
+
for s in SEEDS:
|
|
170
|
+
a = t((64, 256), s)
|
|
171
|
+
b = t((64, 256), s + 100)
|
|
172
|
+
if op == 'div':
|
|
173
|
+
b = torch.where(b.abs() < 0.2, b + 0.5, b)
|
|
174
|
+
ref = {'add': a + b, 'sub': a - b, 'mul': a * b, 'div': a / b}[op]
|
|
175
|
+
out.append(Case({'a': a, 'b': b}, {'out': ref},
|
|
176
|
+
lambda p: ['elementwise', '--op', op, '--shape', '64,256',
|
|
177
|
+
'--a', p['a'], '--b', p['b'], '--out', p['out']],
|
|
178
|
+
a.numel()))
|
|
179
|
+
return out
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def cases_matmul() -> list[Case]:
|
|
183
|
+
out = []
|
|
184
|
+
for s in SEEDS:
|
|
185
|
+
a = t((256, 256), s)
|
|
186
|
+
b = t((256, 256), s + 1)
|
|
187
|
+
out.append(Case({'a': a, 'b': b}, {'out': a @ b},
|
|
188
|
+
lambda p: ['matmul', '--a-shape', '256,256', '--b-shape', '256,256',
|
|
189
|
+
'--a', p['a'], '--b', p['b'], '--out', p['out']],
|
|
190
|
+
2 * 256 * 256 * 256))
|
|
191
|
+
return out
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
def cases_linear() -> list[Case]:
|
|
195
|
+
out = []
|
|
196
|
+
for s in SEEDS:
|
|
197
|
+
x = t((256, 256), s)
|
|
198
|
+
w = t((128, 256), s + 1)
|
|
199
|
+
b = t((128,), s + 2)
|
|
200
|
+
ref = x @ w.T + b
|
|
201
|
+
out.append(Case({'x': x, 'w': w, 'bias': b}, {'out': ref},
|
|
202
|
+
lambda p: ['linear', '--x-shape', '256,256', '--w-shape', '128,256',
|
|
203
|
+
'--b-shape', '128', '--x', p['x'], '--w', p['w'],
|
|
204
|
+
'--bias', p['bias'], '--out', p['out']],
|
|
205
|
+
2 * 256 * 256 * 128))
|
|
206
|
+
return out
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def cases_relu() -> list[Case]:
|
|
210
|
+
out = []
|
|
211
|
+
for s in SEEDS:
|
|
212
|
+
x = t((512, 512), s)
|
|
213
|
+
out.append(Case({'x': x}, {'out': torch.relu(x)},
|
|
214
|
+
lambda p: ['relu', '--shape', '512,512', '--x', p['x'], '--out', p['out']],
|
|
215
|
+
x.numel()))
|
|
216
|
+
return out
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
def cases_softmax() -> list[Case]:
|
|
220
|
+
out = []
|
|
221
|
+
for s in SEEDS:
|
|
222
|
+
x = t((256, 256), s)
|
|
223
|
+
out.append(Case({'x': x}, {'out': torch.softmax(x, dim=-1)},
|
|
224
|
+
lambda p: ['softmax', '--shape', '256,256', '--x', p['x'], '--out', p['out']],
|
|
225
|
+
5 * x.numel()))
|
|
226
|
+
return out
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def cases_layernorm() -> list[Case]:
|
|
230
|
+
out = []
|
|
231
|
+
for s in SEEDS:
|
|
232
|
+
x = t((256, 256), s)
|
|
233
|
+
gamma = torch.randn(256, generator=torch.Generator().manual_seed(s + 1)) * 0.2 + 1.0
|
|
234
|
+
beta = t((256,), s + 2) * 0.1
|
|
235
|
+
ref = F.layer_norm(x, (256,), gamma, beta, 1e-5)
|
|
236
|
+
out.append(Case({'x': x, 'gamma': gamma, 'beta': beta}, {'out': ref},
|
|
237
|
+
lambda p: ['layernorm', '--shape', '256,256', '--x', p['x'],
|
|
238
|
+
'--gamma', p['gamma'], '--beta', p['beta'],
|
|
239
|
+
'--eps', '1e-5', '--out', p['out']],
|
|
240
|
+
8 * x.numel()))
|
|
241
|
+
return out
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
def cases_mse() -> list[Case]:
|
|
245
|
+
out = []
|
|
246
|
+
for s in SEEDS:
|
|
247
|
+
pred = t((512, 512), s)
|
|
248
|
+
target = t((512, 512), s + 1)
|
|
249
|
+
ref = ((pred - target) ** 2).mean().reshape(1)
|
|
250
|
+
out.append(Case({'pred': pred, 'target': target}, {'out': ref},
|
|
251
|
+
lambda p: ['mse', '--pred-shape', '512,512', '--target-shape', '512,512',
|
|
252
|
+
'--pred', p['pred'], '--target', p['target'], '--out', p['out']],
|
|
253
|
+
2 * pred.numel()))
|
|
254
|
+
return out
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
def conv_output(h: int, w: int, k: int, stride: int, pad: int, dil: int) -> tuple[int, int]:
|
|
258
|
+
return ((h + 2 * pad - dil * (k - 1) - 1) // stride + 1,
|
|
259
|
+
(w + 2 * pad - dil * (k - 1) - 1) // stride + 1)
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
def cases_conv2d() -> list[Case]:
|
|
263
|
+
out = []
|
|
264
|
+
for s in SEEDS:
|
|
265
|
+
x = t((8, 3, 32, 32), s)
|
|
266
|
+
w = t((8, 3, 3, 3), s + 1)
|
|
267
|
+
b = t((8,), s + 2)
|
|
268
|
+
ref = F.conv2d(x, w, b, stride=1, padding=1, dilation=1, groups=1)
|
|
269
|
+
ho, wo = conv_output(32, 32, 3, 1, 1, 1)
|
|
270
|
+
out.append(Case({'x': x, 'w': w, 'bias': b}, {'out': ref},
|
|
271
|
+
lambda p: ['conv2d', '--x-shape', '8,3,32,32', '--w-shape', '8,3,3,3',
|
|
272
|
+
'--b-shape', '8', '--x', p['x'], '--w', p['w'], '--bias', p['bias'],
|
|
273
|
+
'--stride', '1,1', '--padding', '1,1', '--dilation', '1,1',
|
|
274
|
+
'--groups', '1', '--out', p['out']],
|
|
275
|
+
2 * 8 * 8 * ho * wo * 3 * 3 * 3))
|
|
276
|
+
return out
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
def cases_matmul_backward() -> list[Case]:
|
|
280
|
+
out = []
|
|
281
|
+
for s in SEEDS:
|
|
282
|
+
a = t((256, 256), s).requires_grad_()
|
|
283
|
+
b = t((256, 256), s + 1).requires_grad_()
|
|
284
|
+
g = t((256, 256), s + 2)
|
|
285
|
+
c = a @ b
|
|
286
|
+
da, db = torch.autograd.grad(c, (a, b), g)
|
|
287
|
+
out.append(Case({'a': a.detach(), 'b': b.detach(), 'grad': g},
|
|
288
|
+
{'da': da, 'db': db},
|
|
289
|
+
lambda p: ['matmul-backward', '--a-shape', '256,256', '--b-shape', '256,256',
|
|
290
|
+
'--a', p['a'], '--b', p['b'], '--grad', p['grad'],
|
|
291
|
+
'--da', p['da'], '--db', p['db']],
|
|
292
|
+
4 * 256 * 256 * 256))
|
|
293
|
+
return out
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
def cases_linear_backward() -> list[Case]:
|
|
297
|
+
out = []
|
|
298
|
+
for s in SEEDS:
|
|
299
|
+
x = t((256, 256), s).requires_grad_()
|
|
300
|
+
w = t((128, 256), s + 1).requires_grad_()
|
|
301
|
+
bias = t((128,), s + 2).requires_grad_()
|
|
302
|
+
y = x @ w.T + bias
|
|
303
|
+
g = t((256, 128), s + 3)
|
|
304
|
+
dx, dw, db = torch.autograd.grad(y, (x, w, bias), g)
|
|
305
|
+
out.append(Case({'x': x.detach(), 'w': w.detach(), 'bias': bias.detach(), 'grad': g},
|
|
306
|
+
{'dx': dx, 'dw': dw, 'db': db},
|
|
307
|
+
lambda p: ['linear-backward', '--x-shape', '256,256', '--w-shape', '128,256',
|
|
308
|
+
'--b-shape', '128', '--x', p['x'], '--w', p['w'], '--bias', p['bias'],
|
|
309
|
+
'--grad', p['grad'], '--dx', p['dx'], '--dw', p['dw'], '--db', p['db']],
|
|
310
|
+
4 * 256 * 256 * 128))
|
|
311
|
+
return out
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
def cases_relu_backward() -> list[Case]:
|
|
315
|
+
out = []
|
|
316
|
+
for s in SEEDS:
|
|
317
|
+
x = t((512, 512), s).requires_grad_()
|
|
318
|
+
g = t((512, 512), s + 1)
|
|
319
|
+
y = torch.relu(x)
|
|
320
|
+
dx = torch.autograd.grad(y, x, g)[0]
|
|
321
|
+
out.append(Case({'x': x.detach(), 'grad': g}, {'dx': dx},
|
|
322
|
+
lambda p: ['relu-backward', '--shape', '512,512', '--x', p['x'],
|
|
323
|
+
'--grad', p['grad'], '--dx', p['dx']],
|
|
324
|
+
x.numel()))
|
|
325
|
+
return out
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
def cases_layernorm_backward() -> list[Case]:
|
|
329
|
+
out = []
|
|
330
|
+
for s in SEEDS:
|
|
331
|
+
x = t((256, 256), s).requires_grad_()
|
|
332
|
+
gamma = (torch.randn(256, generator=torch.Generator().manual_seed(s + 1)) * 0.2 + 1.0).requires_grad_()
|
|
333
|
+
g = t((256, 256), s + 2)
|
|
334
|
+
y = F.layer_norm(x, (256,), gamma, None, 1e-5)
|
|
335
|
+
dx, dgamma = torch.autograd.grad(y, (x, gamma), g)
|
|
336
|
+
out.append(Case({'x': x.detach(), 'gamma': gamma.detach(), 'grad': g},
|
|
337
|
+
{'dx': dx, 'dgamma': dgamma},
|
|
338
|
+
lambda p: ['layernorm-backward', '--shape', '256,256', '--x', p['x'],
|
|
339
|
+
'--gamma', p['gamma'], '--grad', p['grad'], '--eps', '1e-5',
|
|
340
|
+
'--dx', p['dx'], '--dgamma', p['dgamma']],
|
|
341
|
+
10 * x.numel()))
|
|
342
|
+
return out
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
def cases_mse_backward() -> list[Case]:
|
|
346
|
+
out = []
|
|
347
|
+
for s in SEEDS:
|
|
348
|
+
pred = t((512, 512), s).requires_grad_()
|
|
349
|
+
target = t((512, 512), s + 1).requires_grad_()
|
|
350
|
+
loss = ((pred - target) ** 2).mean()
|
|
351
|
+
g = torch.tensor(1.0)
|
|
352
|
+
dp, dt = torch.autograd.grad(loss, (pred, target), g)
|
|
353
|
+
out.append(Case({'pred': pred.detach(), 'target': target.detach(), 'grad': g.reshape(1)},
|
|
354
|
+
{'dp': dp, 'dtarget': dt},
|
|
355
|
+
lambda p: ['mse-backward', '--pred-shape', '512,512', '--target-shape', '512,512',
|
|
356
|
+
'--pred', p['pred'], '--target', p['target'], '--grad', p['grad'],
|
|
357
|
+
'--dp', p['dp'], '--dtarget', p['dtarget']],
|
|
358
|
+
4 * pred.numel()))
|
|
359
|
+
return out
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
def cases_conv2d_backward() -> list[Case]:
|
|
363
|
+
out = []
|
|
364
|
+
for s in SEEDS:
|
|
365
|
+
x = t((4, 3, 16, 16), s).requires_grad_()
|
|
366
|
+
w = t((8, 3, 3, 3), s + 1).requires_grad_()
|
|
367
|
+
b = t((8,), s + 2).requires_grad_()
|
|
368
|
+
y = F.conv2d(x, w, b, stride=1, padding=1)
|
|
369
|
+
g = t((4, 8, 16, 16), s + 3)
|
|
370
|
+
dx, dw, db = torch.autograd.grad(y, (x, w, b), g)
|
|
371
|
+
out.append(Case({'x': x.detach(), 'w': w.detach(), 'bias': b.detach(), 'grad': g},
|
|
372
|
+
{'dx': dx, 'dw': dw, 'db': db},
|
|
373
|
+
lambda p: ['conv2d-backward', '--x-shape', '4,3,16,16', '--w-shape', '8,3,3,3',
|
|
374
|
+
'--b-shape', '8', '--x', p['x'], '--w', p['w'], '--bias', p['bias'],
|
|
375
|
+
'--grad', p['grad'], '--stride', '1,1', '--padding', '1,1',
|
|
376
|
+
'--dilation', '1,1', '--groups', '1',
|
|
377
|
+
'--dx', p['dx'], '--dw', p['dw'], '--db', p['db']],
|
|
378
|
+
4 * 4 * 8 * 16 * 16 * 3 * 3 * 3))
|
|
379
|
+
return out
|
|
380
|
+
|
|
381
|
+
|
|
382
|
+
def adamw_ref(p, g, m, v, lr, b1, b2, eps, wd, step):
|
|
383
|
+
m2 = b1 * m + (1 - b1) * g
|
|
384
|
+
v2 = b2 * v + (1 - b2) * g * g
|
|
385
|
+
mh = m2 / (1 - b1 ** step)
|
|
386
|
+
vh = v2 / (1 - b2 ** step)
|
|
387
|
+
p2 = p * (1 - lr * wd) - lr * mh / (torch.sqrt(vh) + eps)
|
|
388
|
+
return p2, m2, v2
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
def cases_adamw() -> list[Case]:
|
|
392
|
+
out = []
|
|
393
|
+
for s, step in zip(SEEDS, (1, 3, 7)):
|
|
394
|
+
p = t((256, 256), s)
|
|
395
|
+
g = t((256, 256), s + 1)
|
|
396
|
+
m = torch.zeros_like(p)
|
|
397
|
+
v = torch.zeros_like(p)
|
|
398
|
+
ref = adamw_ref(p, g, m, v, 1e-3, 0.9, 0.999, 1e-8, 0.01, step)
|
|
399
|
+
out.append(Case({'param': p, 'grad': g, 'm': m, 'v': v},
|
|
400
|
+
{'param_out': ref[0], 'm_out': ref[1], 'v_out': ref[2]},
|
|
401
|
+
lambda pth, step=step: ['adamw', '--param', pth['param'], '--grad', pth['grad'],
|
|
402
|
+
'--m', pth['m'], '--v', pth['v'], '--lr', '0.001',
|
|
403
|
+
'--beta1', '0.9', '--beta2', '0.999', '--eps', '1e-8',
|
|
404
|
+
'--weight-decay', '0.01', '--step', str(step),
|
|
405
|
+
'--out-param', pth['param_out'], '--out-m', pth['m_out'], '--out-v', pth['v_out']],
|
|
406
|
+
10 * p.numel()))
|
|
407
|
+
return out
|
|
408
|
+
|
|
409
|
+
|
|
410
|
+
def cases_sgd_momentum() -> list[Case]:
|
|
411
|
+
out = []
|
|
412
|
+
for s in SEEDS:
|
|
413
|
+
p = t((256, 256), s)
|
|
414
|
+
g = t((256, 256), s + 1)
|
|
415
|
+
buf = t((256, 256), s + 2) * 0.01
|
|
416
|
+
lr, mu = 0.05, 0.9
|
|
417
|
+
b2 = mu * buf + g
|
|
418
|
+
p2 = p - lr * b2
|
|
419
|
+
out.append(Case({'param': p, 'grad': g, 'buffer': buf}, {'param_out': p2, 'buffer_out': b2},
|
|
420
|
+
lambda pth: ['sgd-momentum', '--param', pth['param'], '--grad', pth['grad'],
|
|
421
|
+
'--momentum-buffer', pth['buffer'], '--lr', '0.05',
|
|
422
|
+
'--momentum', '0.9', '--out-param', pth['param_out'],
|
|
423
|
+
'--out-buffer', pth['buffer_out']],
|
|
424
|
+
6 * p.numel()))
|
|
425
|
+
return out
|
|
426
|
+
|
|
427
|
+
|
|
428
|
+
OPERATIONS = [
|
|
429
|
+
('elementwise.add', 1e-6, lambda: cases_elementwise('add')),
|
|
430
|
+
('elementwise.sub', 1e-6, lambda: cases_elementwise('sub')),
|
|
431
|
+
('elementwise.mul', 1e-6, lambda: cases_elementwise('mul')),
|
|
432
|
+
('elementwise.div', 1e-6, lambda: cases_elementwise('div')),
|
|
433
|
+
('matmul', 1e-5, cases_matmul),
|
|
434
|
+
('linear', 1e-5, cases_linear),
|
|
435
|
+
('relu', 1e-6, cases_relu),
|
|
436
|
+
('softmax', 1e-5, cases_softmax),
|
|
437
|
+
('layernorm', 1e-5, cases_layernorm),
|
|
438
|
+
('mse', 1e-6, cases_mse),
|
|
439
|
+
('conv2d', 1e-4, cases_conv2d),
|
|
440
|
+
('matmul-backward', 1e-4, cases_matmul_backward),
|
|
441
|
+
('linear-backward', 1e-4, cases_linear_backward),
|
|
442
|
+
('relu-backward', 1e-4, cases_relu_backward),
|
|
443
|
+
('layernorm-backward', 1e-4, cases_layernorm_backward),
|
|
444
|
+
('mse-backward', 1e-4, cases_mse_backward),
|
|
445
|
+
('conv2d-backward', 1e-4, cases_conv2d_backward),
|
|
446
|
+
('adamw', 1e-5, cases_adamw),
|
|
447
|
+
('sgd-momentum', 1e-6, cases_sgd_momentum),
|
|
448
|
+
]
|
|
449
|
+
|
|
450
|
+
|
|
451
|
+
def main() -> int:
|
|
452
|
+
workspace = parse_workspace()
|
|
453
|
+
if not torch.__version__:
|
|
454
|
+
return fail({'task': 'neural-fp32', 'ok': False, 'error': 'PyTorch unavailable'})
|
|
455
|
+
with tempfile.TemporaryDirectory(prefix='neural-fp32-eval-') as td:
|
|
456
|
+
root = Path(td)
|
|
457
|
+
try:
|
|
458
|
+
binary = build_candidate(workspace, root)
|
|
459
|
+
except Exception as exc:
|
|
460
|
+
return fail({'task': 'neural-fp32', 'ok': False, 'error': str(exc)})
|
|
461
|
+
rows = []
|
|
462
|
+
for name, threshold, builder in OPERATIONS:
|
|
463
|
+
try:
|
|
464
|
+
cases = builder()
|
|
465
|
+
row = run_operation(name, threshold, cases, binary, root)
|
|
466
|
+
except Exception as exc:
|
|
467
|
+
row = {'name': name, 'executable': False, 'passed': False,
|
|
468
|
+
'weighted_mean_relative_error': None, 'threshold': threshold,
|
|
469
|
+
'speed_gflops': None, 'error': str(exc)}
|
|
470
|
+
rows.append(row)
|
|
471
|
+
|
|
472
|
+
all_exec = all(row['executable'] for row in rows)
|
|
473
|
+
errs = [row['weighted_mean_relative_error'] for row in rows
|
|
474
|
+
if row['weighted_mean_relative_error'] is not None]
|
|
475
|
+
speeds = [row['speed_gflops'] for row in rows if row['speed_gflops'] and row['speed_gflops'] > 0]
|
|
476
|
+
max_err = max(errs) if errs else None
|
|
477
|
+
geomean = math.exp(sum(math.log(v) for v in speeds) / len(speeds)) if speeds else None
|
|
478
|
+
|
|
479
|
+
print(f"all_operations_executable = {str(all_exec).lower()}")
|
|
480
|
+
print(f"max_weighted_mean_relative_error = {max_err}")
|
|
481
|
+
print(f"speed_geomean = {geomean}")
|
|
482
|
+
for row in rows:
|
|
483
|
+
print(f"{row['name']}: executable={row['executable']} pass={row['passed']} "
|
|
484
|
+
f"mre={row['weighted_mean_relative_error']} speed_gflops={row['speed_gflops']}")
|
|
485
|
+
if row['error']:
|
|
486
|
+
print(f" error={row['error'][:300]}")
|
|
487
|
+
|
|
488
|
+
result = {
|
|
489
|
+
'task': 'neural-fp32',
|
|
490
|
+
'ok': True,
|
|
491
|
+
'all_operations_executable': all_exec,
|
|
492
|
+
'max_weighted_mean_relative_error': max_err,
|
|
493
|
+
'speed_geomean': geomean,
|
|
494
|
+
'operations': rows,
|
|
495
|
+
'pytorch': torch.__version__,
|
|
496
|
+
}
|
|
497
|
+
emit(result)
|
|
498
|
+
return 0
|
|
499
|
+
|
|
500
|
+
|
|
501
|
+
if __name__ == '__main__':
|
|
502
|
+
raise SystemExit(main())
|
package/lib/client/index.js
CHANGED
|
@@ -82,7 +82,8 @@ window.__ModuleLoader__.load({
|
|
|
82
82
|
pipIndex: "pypi",
|
|
83
83
|
customPipUrl: "",
|
|
84
84
|
gitProxyUrl: "",
|
|
85
|
-
pipProxyUrl: ""
|
|
85
|
+
pipProxyUrl: "",
|
|
86
|
+
cifarProxyUrl: ""
|
|
86
87
|
};
|
|
87
88
|
const box = {
|
|
88
89
|
border: "1px solid var(--vscode-panel-border, #3c3c3c)",
|
|
@@ -144,7 +145,8 @@ window.__ModuleLoader__.load({
|
|
|
144
145
|
pipIndex: typeof value?.pipIndex === "string" && value.pipIndex !== "" ? value.pipIndex : "pypi",
|
|
145
146
|
customPipUrl: typeof value?.customPipUrl === "string" ? value.customPipUrl : "",
|
|
146
147
|
gitProxyUrl: typeof value?.gitProxyUrl === "string" ? value.gitProxyUrl : "",
|
|
147
|
-
pipProxyUrl: typeof value?.pipProxyUrl === "string" ? value.pipProxyUrl : ""
|
|
148
|
+
pipProxyUrl: typeof value?.pipProxyUrl === "string" ? value.pipProxyUrl : "",
|
|
149
|
+
cifarProxyUrl: typeof value?.cifarProxyUrl === "string" ? value.cifarProxyUrl : ""
|
|
148
150
|
};
|
|
149
151
|
}
|
|
150
152
|
/** The settings card. */
|
|
@@ -337,7 +339,8 @@ window.__ModuleLoader__.load({
|
|
|
337
339
|
pipIndex: draft.pipIndex,
|
|
338
340
|
customPipUrl: draft.customPipUrl,
|
|
339
341
|
gitProxyUrl: draft.gitProxyUrl,
|
|
340
|
-
pipProxyUrl: draft.pipProxyUrl
|
|
342
|
+
pipProxyUrl: draft.pipProxyUrl,
|
|
343
|
+
cifarProxyUrl: draft.cifarProxyUrl
|
|
341
344
|
})
|
|
342
345
|
}).then(readJson);
|
|
343
346
|
if (!result.ok || result.jobId === void 0) {
|
|
@@ -613,6 +616,17 @@ window.__ModuleLoader__.load({
|
|
|
613
616
|
onBlur: () => void save({ pipProxyUrl: draft.pipProxyUrl }),
|
|
614
617
|
placeholder: "127.0.0.1:7897"
|
|
615
618
|
})]
|
|
619
|
+
}),
|
|
620
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
621
|
+
style: row,
|
|
622
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [t("settings.cifarProxy"), ":"] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
623
|
+
style: { width: 260 },
|
|
624
|
+
disabled: !ready,
|
|
625
|
+
value: draft.cifarProxyUrl,
|
|
626
|
+
onChange: (event) => edit({ cifarProxyUrl: event.target.value }),
|
|
627
|
+
onBlur: () => void save({ cifarProxyUrl: draft.cifarProxyUrl }),
|
|
628
|
+
placeholder: "127.0.0.1:7897"
|
|
629
|
+
})]
|
|
616
630
|
})
|
|
617
631
|
] });
|
|
618
632
|
})(),
|
|
@@ -1037,6 +1051,7 @@ window.__ModuleLoader__.load({
|
|
|
1037
1051
|
"settings.startSession": "Open in new conversation",
|
|
1038
1052
|
"settings.gitProxy": "Git proxy",
|
|
1039
1053
|
"settings.pipProxy": "pip proxy",
|
|
1054
|
+
"settings.cifarProxy": "CIFAR download proxy",
|
|
1040
1055
|
"settings.loading": "Loading…",
|
|
1041
1056
|
"settings.recent": "Recent events",
|
|
1042
1057
|
"settings.none": "None.",
|
package/lib/client/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["useSyncExternalStore","useState","useRef","useState"],"sources":["../../src/shared.ts","../../src/client/bridge.ts","../../src/client/Settings.tsx","../../src/client/Toast.tsx","../../src/client/locales.ts","../../src/client/index.ts"],"sourcesContent":["/**\n * Wire types shared by the host and browser halves. Keep this module import-free:\n * the client bundle includes it without pulling host code.\n * @module dsh-eval-guard/shared\n */\n\n/** Settings namespace; also the Loader row id in cordis.patch.yml. */\nexport const SETTINGS_NS = 'eval-guard'\n\n/** Route paths owned by this plugin. */\nexport const STATE_ROUTE = '/api/eval-guard/state'\nexport const CHECK_ROUTE = '/api/eval-guard/check'\nexport const INSTALL_ROUTE = '/api/eval-guard/install'\nexport const PROMPT_ROUTE = '/api/eval-guard/prompt'\nexport const EVENTS_ROUTE = '/api/eval-guard/events'\nexport const REVEAL_ROUTE = '/api/eval-guard/reveal'\nexport const MANUAL_ROUTE = '/api/eval-guard/manual'\nexport const JOBS_ROUTE = '/api/eval-guard/jobs'\nexport const JOB_ROUTE = '/api/eval-guard/job'\nexport const JOB_CANCEL_ROUTE = '/api/eval-guard/job/cancel'\nexport const EVAL_ROUTE = '/api/eval-guard/evaluate'\n\n/** Supported task ids. */\nexport const TANK_TASK = 'tank'\nexport const TANK_TASK_LABEL = '第 6 集 · 坦克大战'\nexport const WAREHOUSE_TASK = 'warehouse'\nexport const WAREHOUSE_TASK_LABEL = '第 5 集 · 仓储调度'\nexport const LAND_TASK = 'land'\nexport const LAND_TASK_LABEL = '第 1 集 · 圈地'\nexport const BOMBERMAN_TASK = 'bomberman'\nexport const BOMBERMAN_TASK_LABEL = '第 2 集 · 炸弹人'\nexport const CTF_TASK = 'ctf'\nexport const CTF_TASK_LABEL = '第 3 集 · 夺旗'\nexport const COMMIT0_TASK = 'commit0'\nexport const COMMIT0_TASK_LABEL = 'Commit0 · 单库实现'\nexport const SWE_BENCH_PRO_TASK = 'swe-bench-pro'\nexport const SWE_BENCH_PRO_TASK_LABEL = 'SWE-Bench Pro · 单任务'\nexport const FEATUREBENCH_TASK = 'featurebench'\nexport const FEATUREBENCH_TASK_LABEL = 'FeatureBench · 单 feature'\nexport const NEURAL_CPP_TASK = 'neural-cpp'\nexport const NEURAL_CPP_TASK_LABEL = 'Neural-CPP · 纯 C++ 张量后端'\n\n/** One validated clone remote for a task. */\nexport interface TaskRemote {\n id: string\n label: string\n url: string\n}\n\n/** Common pip indexes offered by the settings page. */\nexport const PIP_MIRRORS: readonly { id: string; label: string; url: string }[] = [\n { id: 'pypi', label: 'PyPI', url: 'https://pypi.org/simple' },\n { id: 'tsinghua', label: '清华 TUNA', url: 'https://pypi.tuna.tsinghua.edu.cn/simple' },\n { id: 'aliyun', label: '阿里云', url: 'https://mirrors.aliyun.com/pypi/simple' },\n { id: 'tencent', label: '腾讯云', url: 'https://mirrors.cloud.tencent.com/pypi/simple' },\n { id: 'bfsu', label: '北外', url: 'https://mirrors.bfsu.edu.cn/pypi/web/simple' },\n { id: 'sjtu', label: '上海交大', url: 'https://mirror.sjtu.edu.cn/pypi/web/simple' },\n]\n\n/** One task offered by the installer. */\nexport interface TaskInfo {\n id: string\n label: string\n description: string\n /** Default wall-clock limit applied when the user selects this task. */\n timeLimitMinutes: number\n /** Default time-limit switch applied when the user selects this task. */\n timeLimitEnabled: boolean\n /** Whether installation needs a host-side clone / venv setup. */\n needsSetup: boolean\n /** Canonical upstream repository; used to build mirror URLs. */\n repoUrl?: string\n /** Clone remotes verified to contain the exact pinned commit. */\n remotes?: TaskRemote[]\n}\n\nexport type JobKind = 'install' | 'eval'\nexport type JobStatus = 'queued' | 'running' | 'succeeded' | 'failed' | 'cancelled' | 'interrupted'\n\n/** Summary of one background setup or evaluation job. */\nexport interface JobInfo {\n id: string\n kind: JobKind\n task: string\n workspaceId: string\n status: JobStatus\n createdAt: number\n startedAt: number | null\n endedAt: number | null\n updatedAt: number\n error?: string\n}\n\n/** Full job state, including a bounded log and optional result. */\nexport interface JobDetail extends JobInfo {\n log: string\n prompt?: string\n runId?: string\n result?: unknown\n}\n\n/** A live conversation the enable-time warning has to mention. */\nexport interface RunningSession {\n sessionId: string\n title: string\n cwd: string\n running: boolean\n jobs: number\n}\n\n/** One warning surfaced to the browser. */\nexport interface GuardEvent {\n seq: number\n at: number\n sessionId?: string\n runId?: string\n kind: 'tool-blocked' | 'path-denied' | 'process-denied' | 'wait-blocked' | 'timeout' | 'notice'\n tool?: string\n detail: string\n}\n\n/** Host answer for the enable pre-check. */\nexport interface GuardState {\n enabled: boolean\n running: RunningSession[]\n tasks: TaskInfo[]\n defaultBlacklist: string\n generatedDefault: boolean\n workspaceRoot: string\n runsRoot: string\n pipMirrors?: { id: string; label: string; url: string }[]\n}\n\n/** Result of checking one workspace before install. */\nexport interface CheckResult {\n ok: boolean\n workspaceId: string\n path: string\n empty: boolean\n entries: string[]\n error?: string\n}\n\n/** Result of installing the task pack. */\nexport interface InstallResult {\n ok: boolean\n error?: string\n runId?: string\n workspaceId?: string\n workspacePath?: string\n prompt?: string\n}\n\n/** Manual-channel material locations. */\nexport interface ManualPaths {\n source: string\n prompt: string\n}\n\n/** Usage record written next to one run. */\nexport interface RunUsage {\n inputTokens: number\n outputTokens: number\n cacheReadTokens: number\n cacheWriteTokens: number\n reasoningTokens: number\n toolCalls: number\n turns: number\n steps: number\n wallTimeMs: number\n startedAt: number | null\n updatedAt: number\n}\n\n/** Metadata for one guarded task run. */\nexport interface RunRecord {\n runId: string\n task: string\n workspaceId: string\n workspacePath: string\n sessionId: string | null\n createdAt: number\n startedAt: number | null\n endedAt: number | null\n status: 'prepared' | 'active' | 'timeout' | 'ended'\n prompt: string\n timeLimitMinutes: number\n provider?: string\n model?: string\n title?: string\n}\n","/** Shell capabilities published to the Settings panel. */\nexport interface EvalWorkspace { id: string; label: string }\nexport interface EvalBridge {\n startSession(workspaceId: string, prompt: string): void\n workspaces(): readonly EvalWorkspace[]\n}\nlet current: EvalBridge | undefined\nexport function configureEvalBridge(next: EvalBridge | undefined): void { current = next }\nexport function evalBridge(): EvalBridge | undefined { return current }\n","/**\n * Settings panel for the evaluation guard.\n * @module dsh-eval-guard/client/Settings\n */\nimport { useEffect, useRef, useState, useSyncExternalStore, type CSSProperties, type ReactElement } from 'react'\nimport {\n CHECK_ROUTE, EVENTS_ROUTE, INSTALL_ROUTE, MANUAL_ROUTE, REVEAL_ROUTE, STATE_ROUTE,\n JOBS_ROUTE, JOB_ROUTE, JOB_CANCEL_ROUTE, EVAL_ROUTE,\n type CheckResult, type GuardEvent, type GuardState, type InstallResult, type ManualPaths, type JobDetail, type JobInfo,\n PIP_MIRRORS,\n} from '../shared.ts'\nimport { evalBridge } from './bridge.ts'\n\ntype Snapshot = {\n status: 'loading' | 'ready' | 'unavailable'\n value?: Record<string, unknown>\n revision?: number\n writable: boolean\n}\ntype Form = {\n getSnapshot: () => Snapshot\n subscribe: (listener: () => void) => () => void\n mutate: (ops: readonly { op: 'set'; path: string[]; value: unknown }[], revision?: number) => Promise<boolean>\n}\ntype Props = { form: Form; t: (key: string) => string }\n\ninterface Draft {\n enabled: boolean\n timeLimitEnabled: boolean\n timeLimitMinutes: number\n forbiddenPaths: string\n toolBlacklistUseDefault: boolean\n toolBlacklist: string\n cloneSource: string\n customCloneUrl: string\n pipIndex: string\n customPipUrl: string\n gitProxyUrl: string\n pipProxyUrl: string\n}\n\nconst EMPTY: Draft = {\n enabled: false,\n timeLimitEnabled: true,\n timeLimitMinutes: 90,\n forbiddenPaths: '',\n toolBlacklistUseDefault: true,\n toolBlacklist: '',\n cloneSource: 'github',\n customCloneUrl: '',\n pipIndex: 'pypi',\n customPipUrl: '',\n gitProxyUrl: '',\n pipProxyUrl: '',\n}\n\nconst box: CSSProperties = { border: '1px solid var(--vscode-panel-border, #3c3c3c)', borderRadius: 8, padding: 14, marginBottom: 14 }\nconst row: CSSProperties = { display: 'flex', gap: 10, alignItems: 'center', flexWrap: 'wrap', marginBottom: 8 }\nconst note: CSSProperties = { opacity: 0.72, fontSize: 12, lineHeight: 1.5, margin: '6px 0' }\nconst textarea: CSSProperties = { width: '100%', minHeight: 110, fontFamily: 'monospace', fontSize: 12, padding: 8, boxSizing: 'border-box' }\nconst button: CSSProperties = { padding: '5px 12px', borderRadius: 6, cursor: 'pointer' }\nconst primary: CSSProperties = { ...button, background: '#2f6fd0', color: '#fff', border: 'none' }\nconst danger: CSSProperties = { ...button, background: '#a33', color: '#fff', border: 'none' }\n\nasync function readJson<T>(response: Response): Promise<T> { return await response.json() as T }\n\nfunction normalize(value: Record<string, unknown> | undefined): Draft {\n return {\n enabled: value?.enabled === true,\n timeLimitEnabled: value?.timeLimitEnabled !== false,\n timeLimitMinutes: typeof value?.timeLimitMinutes === 'number' ? value.timeLimitMinutes : 90,\n forbiddenPaths: typeof value?.forbiddenPaths === 'string' ? value.forbiddenPaths : '',\n toolBlacklistUseDefault: value?.toolBlacklistUseDefault !== false,\n toolBlacklist: typeof value?.toolBlacklist === 'string' ? value.toolBlacklist : '',\n cloneSource: typeof value?.cloneSource === 'string' && value.cloneSource !== '' ? value.cloneSource : 'github',\n customCloneUrl: typeof value?.customCloneUrl === 'string' ? value.customCloneUrl : '',\n pipIndex: typeof value?.pipIndex === 'string' && value.pipIndex !== '' ? value.pipIndex : 'pypi',\n customPipUrl: typeof value?.customPipUrl === 'string' ? value.customPipUrl : '',\n gitProxyUrl: typeof value?.gitProxyUrl === 'string' ? value.gitProxyUrl : '',\n pipProxyUrl: typeof value?.pipProxyUrl === 'string' ? value.pipProxyUrl : '',\n }\n}\n\n/** The settings card. */\nexport function EvalGuardSettings({ form, t }: Props): ReactElement {\n const snapshot = useSyncExternalStore(form.subscribe, form.getSnapshot, form.getSnapshot)\n const [draft, setDraft] = useState<Draft>(EMPTY)\n const [dirty, setDirty] = useState(false)\n const [state, setState] = useState<GuardState | null>(null)\n const [events, setEvents] = useState<GuardEvent[]>([])\n const [pendingEnable, setPendingEnable] = useState(false)\n const [notice, setNotice] = useState('')\n const [error, setError] = useState('')\n const [workspaceId, setWorkspaceId] = useState(() => typeof localStorage === 'undefined' ? '' : localStorage.getItem('evalGuard.workspaceId') ?? '')\n const [taskId, setTaskId] = useState(() => typeof localStorage === 'undefined' ? '' : localStorage.getItem('evalGuard.taskId') ?? '')\n const [check, setCheck] = useState<CheckResult | null>(null)\n const [manual, setManual] = useState<ManualPaths | null>(null)\n const [prompt, setPrompt] = useState('')\n const [copied, setCopied] = useState('')\n const workspaces = evalBridge()?.workspaces() ?? []\n const [job, setJob] = useState<JobDetail | null>(null)\n const [jobNotice, setJobNotice] = useState('')\n const autoOpenJob = useRef('')\n\n const pollJob = (id: string): void => {\n fetch(JOB_ROUTE + '?id=' + encodeURIComponent(id)).then(readJson<JobDetail>).then(setJob).catch(() => undefined)\n }\n const loadLatestJob = (workspace: string, task: string): void => {\n if (workspace === '' || task === '') { setJob(null); return }\n fetch(JOBS_ROUTE + '?workspaceId=' + encodeURIComponent(workspace) + '&task=' + encodeURIComponent(task))\n .then(readJson<JobInfo[]>).then(items => {\n const latest = items[0]\n if (latest !== undefined) pollJob(latest.id)\n else setJob(null)\n }).catch(() => undefined)\n }\n useEffect(() => {\n if (job === null || (job.status !== 'running' && job.status !== 'queued')) return\n const timer = setInterval(() => { pollJob(job.id) }, 800)\n return () => clearInterval(timer)\n }, [job])\n useEffect(() => { if (job?.status === 'succeeded' && job.kind === 'install' && job.prompt !== undefined) {\n setPrompt(job.prompt); setJobNotice(t('settings.installOk')); loadState()\n if (autoOpenJob.current === job.id) {\n autoOpenJob.current = ''\n evalBridge()?.startSession(job.workspaceId, job.prompt)\n }\n } }, [job])\n useEffect(() => { loadLatestJob(workspaceId, taskId) }, [workspaceId, taskId])\n\n useEffect(() => {\n if (snapshot.status !== 'ready' || snapshot.value === undefined || dirty) return\n setDraft(normalize(snapshot.value))\n }, [snapshot, dirty])\n\n const loadState = (): void => {\n fetch(STATE_ROUTE).then(readJson<GuardState>).then(setState).catch(() => setState(null))\n }\n useEffect(() => {\n loadState()\n let since = 0\n const timer = setInterval(() => {\n fetch(EVENTS_ROUTE + '?since=' + String(since)).then(readJson<{ events: GuardEvent[] }>).then(data => {\n if (data.events.length === 0) return\n since = data.events[data.events.length - 1]!.seq\n setEvents(current => [...data.events, ...current].slice(0, 12))\n }).catch(() => undefined)\n }, 2000)\n return () => clearInterval(timer)\n }, [])\n\n useEffect(() => {\n if (state !== null && state.tasks.length > 0 && (taskId === '' || !state.tasks.some(task => task.id === taskId))) setTaskId(state.tasks[0]!.id)\n }, [state, taskId])\n\n const ready = snapshot.status === 'ready' && snapshot.writable\n const save = async (patch: Partial<Draft>): Promise<void> => {\n if (!ready || snapshot.revision === undefined) return\n const next = { ...draft, ...patch }\n const ops: { op: 'set'; path: string[]; value: unknown }[] = []\n for (const key of Object.keys(patch) as (keyof Draft)[]) ops.push({ op: 'set', path: [key], value: next[key] })\n try {\n const accepted = await form.mutate(ops, snapshot.revision)\n if (!accepted) { setError('保存冲突,请刷新后重试。'); return }\n setDraft(next)\n setDirty(false)\n setError('')\n loadState()\n } catch (reason: unknown) {\n setError(reason instanceof Error ? reason.message : String(reason))\n }\n }\n const edit = (patch: Partial<Draft>): void => {\n setDraft(current => ({ ...current, ...patch }))\n setDirty(true)\n }\n\n const selectTask = (next: string): void => {\n setTaskId(next)\n try { localStorage.setItem('evalGuard.taskId', next) } catch { /* storage is optional */ }\n setCheck(null); setManual(null); setPrompt(''); setJob(null); setJobNotice('')\n if (workspaceId !== '') loadManual(workspaceId, next)\n const task = state?.tasks.find(item => item.id === next)\n if (task === undefined) return\n const remotes = task.remotes ?? []\n const cloneSource = draft.cloneSource === 'custom' || remotes.some(remote => remote.id === draft.cloneSource)\n ? draft.cloneSource : (remotes[0]?.id ?? 'github')\n setDraft(current => ({ ...current, timeLimitMinutes: task.timeLimitMinutes, timeLimitEnabled: task.timeLimitEnabled, cloneSource }))\n setNotice(t('settings.taskDefaults').replace('{minutes}', String(task.timeLimitMinutes)).replace('{state}', task.timeLimitEnabled ? t('settings.on') : t('settings.off')))\n void save({ timeLimitMinutes: task.timeLimitMinutes, timeLimitEnabled: task.timeLimitEnabled, cloneSource })\n }\n\n const toggleEnabled = (next: boolean): void => {\n if (!next) { void save({ enabled: false }); return }\n fetch(STATE_ROUTE).then(readJson<GuardState>).then(latest => {\n setState(latest)\n if (latest.running.length > 0) setPendingEnable(true)\n else void save({ enabled: true })\n }).catch(() => void save({ enabled: true }))\n }\n\n const forceEnable = (): void => {\n setPendingEnable(false)\n void save({ enabled: true })\n }\n\n const loadManual = (id: string, task: string): void => {\n if (id === '') { setCheck(null); setManual(null); setPrompt(''); return }\n fetch(CHECK_ROUTE + '?workspaceId=' + encodeURIComponent(id)).then(readJson<CheckResult>).then(result => {\n setCheck(result)\n if (result.ok) {\n fetch(MANUAL_ROUTE + '?workspaceId=' + encodeURIComponent(id) + '&task=' + encodeURIComponent(task)).then(readJson<ManualPaths>).then(paths => {\n setManual(paths)\n setPrompt(paths.prompt)\n }).catch(() => undefined)\n }\n }).catch((reason: unknown) => setError(reason instanceof Error ? reason.message : String(reason)))\n }\n\n const install = async (): Promise<void> => {\n if (workspaceId === '' || taskId === '') return\n setError(''); setNotice(''); setJobNotice('')\n const checked = await fetch(CHECK_ROUTE + '?workspaceId=' + encodeURIComponent(workspaceId)).then(readJson<CheckResult>)\n setCheck(checked)\n if (!checked.ok || !checked.empty) { setError(checked.error ?? t('settings.nonEmpty')); return }\n const result = await fetch(INSTALL_ROUTE, {\n method: 'POST', headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ workspaceId, task: taskId, cloneSource: draft.cloneSource, customCloneUrl: draft.customCloneUrl,\n pipIndex: draft.pipIndex, customPipUrl: draft.customPipUrl, gitProxyUrl: draft.gitProxyUrl, pipProxyUrl: draft.pipProxyUrl }),\n }).then(readJson<{ ok: boolean; jobId?: string; error?: string }>)\n if (!result.ok || result.jobId === undefined) { autoOpenJob.current = ''; setError(result.error ?? '安装失败'); return }\n autoOpenJob.current = result.jobId\n pollJob(result.jobId)\n }\n\n const evaluate = async (): Promise<void> => {\n if (workspaceId === '' || taskId === '') return\n setError(''); setNotice(''); setJobNotice('')\n const result = await fetch(EVAL_ROUTE, {\n method: 'POST', headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ workspaceId, task: taskId }),\n }).then(readJson<{ ok: boolean; jobId?: string; error?: string }>)\n if (!result.ok || result.jobId === undefined) { setError(result.error ?? '评测启动失败'); return }\n pollJob(result.jobId)\n }\n\n const cancelJob = async (): Promise<void> => {\n if (job === null) return\n await fetch(JOB_CANCEL_ROUTE, { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ id: job.id }) })\n pollJob(job.id)\n }\n\n const copy = async (label: string, text: string): Promise<void> => {\n try {\n await navigator.clipboard.writeText(text)\n setCopied(label)\n setTimeout(() => setCopied(''), 1500)\n } catch { setError('复制失败') }\n }\n const reveal = (target: string): void => {\n void fetch(REVEAL_ROUTE, {\n method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ path: target }),\n })\n }\n const blacklistText = draft.toolBlacklistUseDefault ? state?.defaultBlacklist ?? '' : draft.toolBlacklist\n\n if (snapshot.status === 'loading') return <div style={box}>{t('settings.loading')}</div>\n return <div>\n {pendingEnable && <div style={{ ...box, borderColor: '#caa23a' }}>\n <strong>{t('settings.warningTitle')}</strong>\n <p style={note}>{t('settings.runningWarning')}</p>\n <ul style={{ ...note, paddingLeft: 18 }}>{(state?.running ?? []).map(item =>\n <li key={item.sessionId}>{item.title} · {item.cwd}{item.jobs > 0 ? ' · jobs: ' + String(item.jobs) : ''}</li>)}</ul>\n <div style={row}>\n <button style={button} onClick={() => { setPendingEnable(false); loadState() }}>{t('settings.runningCancel')}</button>\n <button style={danger} onClick={forceEnable}>{t('settings.runningForce')}</button>\n </div>\n </div>}\n\n <section style={box}>\n <div style={row}>\n <label><input type=\"checkbox\" checked={draft.enabled} disabled={!ready} onChange={event => toggleEnabled(event.target.checked)} /> {t('settings.enabled')}</label>\n </div>\n <p style={note}>{t('settings.enabledHint')}</p>\n </section>\n\n <section style={box}>\n <strong>{t('settings.forbidden')}</strong>\n <p style={note}>{t('settings.forbiddenHint')}</p>\n <textarea style={textarea} value={draft.forbiddenPaths} disabled={!ready}\n onChange={event => edit({ forbiddenPaths: event.target.value })}\n onBlur={() => void save({ forbiddenPaths: draft.forbiddenPaths })} />\n </section>\n\n <section style={box}>\n <div style={row}>\n <strong>{t('settings.blacklist')}</strong>\n <button style={button} disabled={!ready} onClick={() => void save({ toolBlacklistUseDefault: true, toolBlacklist: '' })}>{t('settings.reset')}</button>\n </div>\n <p style={note}>{t('settings.blacklistHint')}</p>\n <textarea style={textarea} value={blacklistText} disabled={!ready}\n onChange={event => edit({ toolBlacklistUseDefault: false, toolBlacklist: event.target.value })}\n onBlur={() => void save({ toolBlacklistUseDefault: draft.toolBlacklistUseDefault, toolBlacklist: draft.toolBlacklist })} />\n {draft.toolBlacklistUseDefault && <p style={note}>{t('settings.editingDefault')}</p>}\n </section>\n\n <section style={box}>\n <strong>{t('settings.task')}</strong>\n <p style={note}>{t('settings.taskHint')}</p>\n <div style={row}>\n <span>{t('settings.taskLabel')}:</span>\n <select value={taskId} disabled={state === null || state.tasks.length === 0}\n onChange={event => selectTask(event.target.value)}>\n {(state?.tasks ?? []).map(task => <option key={task.id} value={task.id}>{task.label}</option>)}\n </select>\n </div>\n {state !== null && <p style={note}>{state.tasks.find(task => task.id === taskId)?.description ?? ''}</p>}\n {(() => {\n const selected = state?.tasks.find(item => item.id === taskId)\n if (selected?.needsSetup !== true) return null\n return <div>\n <div style={row}>\n <span>{t('settings.cloneSource')}:</span>\n <select value={draft.cloneSource} disabled={!ready} onChange={event => void save({ cloneSource: event.target.value })}>\n {(selected.remotes ?? []).map(remote => <option key={remote.id} value={remote.id}>{remote.label}</option>)}\n <option value=\"custom\">{t('settings.custom')}</option>\n </select>\n {draft.cloneSource === 'custom' && <input style={{ width: 260 }} disabled={!ready} value={draft.customCloneUrl}\n onChange={event => edit({ customCloneUrl: event.target.value })} onBlur={() => void save({ customCloneUrl: draft.customCloneUrl })} placeholder=\"https://git.example.com\" />}\n </div>\n <div style={row}>\n <span>{t('settings.pipIndex')}:</span>\n <select value={draft.pipIndex} disabled={!ready} onChange={event => void save({ pipIndex: event.target.value })}>\n {PIP_MIRRORS.map(mirror => <option key={mirror.id} value={mirror.id}>{mirror.label}</option>)}\n <option value=\"custom\">{t('settings.custom')}</option>\n </select>\n {draft.pipIndex === 'custom' && <input style={{ width: 260 }} disabled={!ready} value={draft.customPipUrl}\n onChange={event => edit({ customPipUrl: event.target.value })} onBlur={() => void save({ customPipUrl: draft.customPipUrl })} placeholder=\"https://pypi.example.com/simple\" />}\n </div>\n <div style={row}>\n <span>{t('settings.gitProxy')}:</span>\n <input style={{ width: 260 }} disabled={!ready} value={draft.gitProxyUrl}\n onChange={event => edit({ gitProxyUrl: event.target.value })} onBlur={() => void save({ gitProxyUrl: draft.gitProxyUrl })} placeholder=\"127.0.0.1:7897\" />\n </div>\n <div style={row}>\n <span>{t('settings.pipProxy')}:</span>\n <input style={{ width: 260 }} disabled={!ready} value={draft.pipProxyUrl}\n onChange={event => edit({ pipProxyUrl: event.target.value })} onBlur={() => void save({ pipProxyUrl: draft.pipProxyUrl })} placeholder=\"127.0.0.1:7897\" />\n </div>\n </div>\n })()}\n <div style={row}>\n <span>{t('settings.workspace')}:</span>\n <select value={workspaceId} onChange={event => { const next = event.target.value; setWorkspaceId(next); try { localStorage.setItem('evalGuard.workspaceId', next) } catch { /* storage is optional */ } loadManual(next, taskId); loadLatestJob(next, taskId) }}>\n <option value=\"\">{t('settings.pickWorkspace')}</option>\n {workspaces.map(workspace => <option key={workspace.id} value={workspace.id}>{workspace.label}</option>)}\n </select>\n <button style={primary} disabled={workspaceId === '' || taskId === '' || job?.status === 'running'} onClick={() => void install()}>{t('settings.check')}</button>\n <button style={button} disabled={workspaceId === '' || taskId === '' || job?.status === 'running'} onClick={() => void evaluate()}>{t('settings.evaluate')}</button>\n </div>\n <p style={note}>{t('settings.evalHint')}</p>\n {workspaces.length === 0 && <p style={note}>{t('settings.noWorkspaces')}</p>}\n {check !== null && !check.empty && <p style={{ ...note, color: '#d99' }}>{t('settings.nonEmpty')} ({check.entries.slice(0, 6).join(', ')})</p>}\n {notice !== '' && <p style={{ ...note, color: '#7c7' }}>{notice}</p>}\n {error !== '' && <p style={{ ...note, color: '#d77' }}>{error}</p>}\n {jobNotice !== '' && <p style={{ ...note, color: '#7c7' }}>{jobNotice}</p>}\n {job !== null && <div style={{ ...box, borderColor: job.status === 'failed' ? '#a55' : job.status === 'succeeded' ? '#4a7' : '#3a6' }}>\n <div style={row}><strong>{job.kind === 'install' ? t('settings.installJob') : t('settings.evalJob')}</strong><span>{job.status}</span>\n {job.status === 'running' && <button style={danger} onClick={() => void cancelJob()}>{t('settings.cancel')}</button>}\n {job.kind === 'install' && job.status === 'succeeded' && job.prompt !== undefined && workspaceId !== '' && <button style={primary} onClick={() => evalBridge()?.startSession(workspaceId, job.prompt!)}>{t('settings.startSession')}</button>}</div>\n {job.error !== undefined && <p style={{ ...note, color: '#d77' }}>{job.error}</p>}\n <pre style={{ ...textarea, maxHeight: 260, overflow: 'auto' }}>{job.log || t('settings.waiting')}</pre>\n {job.result !== undefined && <pre style={{ ...textarea, maxHeight: 260, overflow: 'auto' }}>{JSON.stringify(job.result, undefined, 2)}</pre>}\n </div>}\n </section>\n\n <section style={box}>\n <div style={row}>\n <label><input type=\"checkbox\" checked={draft.timeLimitEnabled} disabled={!ready} onChange={event => void save({ timeLimitEnabled: event.target.checked })} /> {t('settings.timeLimit')}</label>\n <input type=\"number\" min={1} max={1440} value={draft.timeLimitMinutes} disabled={!ready}\n style={{ width: 90 }} onChange={event => edit({ timeLimitMinutes: Number(event.target.value) })}\n onBlur={() => void save({ timeLimitMinutes: draft.timeLimitMinutes })} />\n <span style={note}>{t('settings.minutes')}</span>\n </div>\n <p style={note}>{t('settings.timeLimitHint')}</p>\n </section>\n\n <section style={box}>\n <strong>{t('settings.manual')}</strong>\n <p style={note}>{t('settings.manualHint')}</p>\n <div style={row}><span>{t('settings.source')}:</span><code style={{ wordBreak: 'break-all' }}>{manual?.source ?? '—'}</code>\n {manual !== null && <button style={button} onClick={() => reveal(manual.source)}>{t('settings.reveal')}</button>}</div>\n <div style={row}><span>{t('settings.target')}:</span><code style={{ wordBreak: 'break-all' }}>{check?.path ?? '—'}</code>\n {check?.path !== undefined && check.path !== '' && <button style={button} onClick={() => reveal(check.path)}>{t('settings.reveal')}</button>}</div>\n <div style={row}><button style={button} disabled={prompt === ''} onClick={() => void copy('prompt', prompt)}>{copied === 'prompt' ? t('settings.copied') : t('settings.copy')}</button></div>\n <textarea style={{ ...textarea, minHeight: 160 }} readOnly value={prompt} placeholder={t('settings.prompt')} />\n </section>\n\n <section style={box}>\n <strong>{t('settings.recent')}</strong>\n {events.length === 0 && <p style={note}>{t('settings.none')}</p>}\n {events.map(event => <div key={event.seq} style={{ ...note, borderTop: '1px solid #333', paddingTop: 4 }}>\n <strong>[{event.kind}]</strong> {event.tool !== undefined ? event.tool + ' · ' : ''}{event.detail}\n </div>)}\n </section>\n </div>\n}\n","/**\n * Frame-wide warning toasts fed by the host event route.\n * @module dsh-eval-guard/client/Toast\n */\nimport { useEffect, useState, type ReactElement } from 'react'\nimport { EVENTS_ROUTE, type GuardEvent } from '../shared.ts'\n\n/** One toast with a dismiss deadline. */\ninterface Shown { event: GuardEvent; until: number }\n\n/** Poll the host event feed and show new warnings. */\nexport function GuardToast({ t }: { t: (key: string) => string }): ReactElement | null {\n const [shown, setShown] = useState<Shown[]>([])\n useEffect(() => {\n let since = 0\n let alive = true\n const poll = (): void => {\n fetch(EVENTS_ROUTE + '?since=' + String(since)).then(async response => await response.json() as { events: GuardEvent[] }).then(data => {\n if (!alive || data.events.length === 0) return\n since = data.events[data.events.length - 1]!.seq\n const warnings = data.events.filter(event => event.kind !== 'notice')\n if (warnings.length === 0) return\n const now = Date.now()\n setShown(current => [...warnings.map(event => ({ event, until: now + 8000 })), ...current].slice(0, 5))\n }).catch(() => undefined)\n }\n const timer = setInterval(() => {\n poll()\n const now = Date.now()\n setShown(current => current.filter(item => item.until > now))\n }, 1500)\n poll()\n return () => { alive = false; clearInterval(timer) }\n }, [])\n if (shown.length === 0) return null\n return <div style={{ position: 'fixed', right: 18, bottom: 18, zIndex: 9999, display: 'flex', flexDirection: 'column', gap: 8, maxWidth: 420 }}>\n {shown.map(item => <div key={item.event.seq} style={{\n background: '#3a2a12', color: '#ffdca8', border: '1px solid #8a6a2a', borderRadius: 8,\n padding: '10px 12px', fontSize: 12, lineHeight: 1.5, boxShadow: '0 6px 24px rgba(0,0,0,.45)',\n }}>\n <strong>{t('settings.warningTitle')}</strong>\n <div>{item.event.detail}</div>\n </div>)}\n </div>\n}\n","/** Locale namespace and dictionaries for the browser half. */\nexport const NS = 'evalGuard'\n\nexport const zh = {\n 'settings.nav': '评测守护',\n 'settings.title': '评测守护',\n 'settings.enabled': '启用评测守护',\n 'settings.enabledHint': '启用后,所有用户主对话只能读写自己的工作区,禁止联网、子代理与跨 agent 通信,并按任务时限强制终止。默认关闭。',\n 'settings.runningWarning': '当前有正在运行的对话。启用评测守护会立即约束它们,是否强行开启?',\n 'settings.runningCancel': '放弃',\n 'settings.runningForce': '强行开启',\n 'settings.timeLimit': '开启最长时长',\n 'settings.timeLimitHint': '从每条用户消息发送时开始计时;到点只终止当前轮次,并递归清理子代理与后台任务。',\n 'settings.minutes': '分钟',\n 'settings.forbidden': '额外禁止路径',\n 'settings.forbiddenHint': '每行一个绝对路径;# 开头为注释;! 开头表示在禁止范围内放开该子路径;按行顺序生效。默认空。',\n 'settings.blacklist': '工具黑名单',\n 'settings.blacklistHint': '每行一个工具名;默认内容按当前已安装工具生成,不存在的工具会被忽略。',\n 'settings.reset': '恢复默认黑名单',\n 'settings.editingDefault': '编辑后将以自定义黑名单保存。',\n 'settings.task': '安装 / 评测任务',\n 'settings.taskHint': '选择任务和工作区;安装与评测共用这组选择。安装会写入素材并准备环境,评测只对当前工作区运行一次。',\n 'settings.taskLabel': '任务',\n 'settings.workspace': '工作区',\n 'settings.pickWorkspace': '请选择工作区',\n 'settings.check': '安装任务',\n 'settings.nonEmpty': '工作区不是空的;未执行任何操作。',\n 'settings.manual': '手动通道',\n 'settings.manualHint': '手动复制素材:自己把素材目录内容复制到工作区根目录;手动填充提示词:复制下面的提示词。',\n 'settings.source': '素材路径',\n 'settings.target': '工作区路径',\n 'settings.copy': '复制',\n 'settings.copied': '已复制',\n 'settings.prompt': '初始提示词',\n 'settings.reveal': '在文件管理器中打开',\n 'settings.noWorkspaces': '没有可选的工作区。',\n 'settings.installOk': '任务素材已安装,提示词已填入新会话,请自行发送。',\n 'settings.taskDefaults': '已按任务默认值设置限时:{minutes} 分钟,限时开关 {state}。你可以随后手动修改。',\n 'settings.on': '打开',\n 'settings.off': '关闭',\n 'settings.evaluate': '评测当前工作区',\n 'settings.evalJob': '评测任务',\n 'settings.installJob': '安装任务',\n 'settings.cloneSource': '仓库来源',\n 'settings.pipIndex': 'pip 镜像',\n 'settings.custom': '自定义',\n 'settings.cancel': '取消',\n 'settings.waiting': '正在准备…',\n 'settings.evalHint': '只评测单个工作区,不做排名。评测任务与安装共用上面的工作区和任务选择。',\n 'settings.startSession': '填入新会话',\n 'settings.gitProxy': 'Git 代理',\n 'settings.pipProxy': 'pip 代理',\n 'settings.loading': '加载中…',\n 'settings.recent': '最近事件',\n 'settings.none': '暂无。',\n 'settings.warningTitle': '评测守护警告',\n 'settings.close': '关闭',\n} as const\n\nexport type Key = keyof typeof zh\n\nexport const en: Record<Key, string> = {\n 'settings.nav': 'Eval Guard',\n 'settings.title': 'Eval Guard',\n 'settings.enabled': 'Enable evaluation guard',\n 'settings.enabledHint': 'When on, every user main conversation may only read/write its own workspace, with network, subagents and cross-agent channels blocked, and a wall-clock limit. Off by default.',\n 'settings.runningWarning': 'Conversations are running right now. Enabling the guard will constrain them immediately. Force enable?',\n 'settings.runningCancel': 'Cancel',\n 'settings.runningForce': 'Force enable',\n 'settings.timeLimit': 'Enable time limit',\n 'settings.timeLimitHint': 'The clock starts at each user message; at the deadline only the current turn is cancelled, and subagents/jobs are cleaned up recursively.',\n 'settings.minutes': 'minutes',\n 'settings.forbidden': 'Extra forbidden paths',\n 'settings.forbiddenHint': 'One absolute path per line; # comments; ! re-allows a subpath; later lines win. Empty by default.',\n 'settings.blacklist': 'Tool blacklist',\n 'settings.blacklistHint': 'One tool name per line; the default is generated from the tools installed now and missing tools are ignored.',\n 'settings.reset': 'Reset default blacklist',\n 'settings.editingDefault': 'Editing switches this to a custom blacklist.',\n 'settings.task': 'Install / evaluate task',\n 'settings.taskHint': 'Pick a task and workspace; install and evaluation share this selection. Install writes the task and prepares the environment; evaluation runs once on the current workspace.',\n 'settings.taskLabel': 'Task',\n 'settings.workspace': 'Workspace',\n 'settings.pickWorkspace': 'Pick a workspace',\n 'settings.check': 'Install task',\n 'settings.nonEmpty': 'The workspace is not empty; nothing was changed.',\n 'settings.manual': 'Manual channel',\n 'settings.manualHint': 'Manual material copy: copy the source folder contents into the workspace root yourself. Manual prompt: copy the text below.',\n 'settings.source': 'Material path',\n 'settings.target': 'Workspace path',\n 'settings.copy': 'Copy',\n 'settings.copied': 'Copied',\n 'settings.prompt': 'Initial prompt',\n 'settings.reveal': 'Open in file manager',\n 'settings.noWorkspaces': 'No workspace is available.',\n 'settings.installOk': 'Task installed and the prompt was seeded into a new conversation; send it yourself.',\n 'settings.taskDefaults': 'Applied task defaults: {minutes} minutes, time limit {state}. You can change them afterwards.',\n 'settings.on': 'on',\n 'settings.off': 'off',\n 'settings.evaluate': 'Evaluate current workspace',\n 'settings.evalJob': 'Evaluation job',\n 'settings.installJob': 'Install job',\n 'settings.cloneSource': 'Clone source',\n 'settings.pipIndex': 'pip index',\n 'settings.custom': 'Custom',\n 'settings.cancel': 'Cancel',\n 'settings.waiting': 'Preparing…',\n 'settings.evalHint': 'Evaluates one workspace only; no ranking. Uses the same workspace/task selection as install.',\n 'settings.startSession': 'Open in new conversation',\n 'settings.gitProxy': 'Git proxy',\n 'settings.pipProxy': 'pip proxy',\n 'settings.loading': 'Loading…',\n 'settings.recent': 'Recent events',\n 'settings.none': 'None.',\n 'settings.warningTitle': 'Eval Guard warning',\n 'settings.close': 'Close',\n}\n","/**\n * Evaluation guard, browser half: the Settings section, the warning toast, and\n * the shell bridge used to seed a new conversation with the task prompt.\n * @module dsh-eval-guard/client\n */\nimport type { Context } from '@deepseek-ai/cordis'\nimport { SETTINGS_NS } from '../shared.ts'\nimport { EvalGuardSettings } from './Settings.tsx'\nimport { GuardToast } from './Toast.tsx'\nimport { configureEvalBridge } from './bridge.ts'\nimport { en, NS, zh, type Key } from './locales.ts'\n\ndeclare module '@deepseek-ai/dsh-client-ui-slots' {\n interface LocaleNamespaceMap {\n evalGuard: Key\n }\n}\n\nexport const inject = ['slots', 'locale', 'configForms', 'uiWorkspace']\n\nexport function apply(ctx: Context): void {\n ctx.effect(() => ctx.locale.register(NS, { zh, en }))\n configureEvalBridge({\n startSession: (workspaceId, prompt) => {\n ctx.uiWorkspace.startSession(workspaceId as Parameters<typeof ctx.uiWorkspace.startSession>[0], { prompt })\n },\n workspaces: () => {\n const service = (ctx as unknown as { get(key: string): unknown }).get('workspaces') as\n { list?: { getSnapshot(): { items?: readonly Record<string, unknown>[] } } } | undefined\n const items = service?.list?.getSnapshot().items ?? []\n return items.map((item, index) => ({\n id: typeof item['workspaceId'] === 'string' ? item['workspaceId'] : String(item['id'] ?? index),\n label: typeof item['title'] === 'string' && item['title'] !== ''\n ? item['title']\n : String(item['path'] ?? item['workspaceId'] ?? ('workspace ' + String(index + 1))),\n }))\n },\n })\n ctx.effect(() => () => { configureEvalBridge(undefined) })\n const t = ctx.locale.bind(NS)\n const form = ctx.configForms.get(SETTINGS_NS) as {\n getSnapshot(): unknown\n subscribe(listener: () => void): () => void\n mutate(ops: never, revision?: number): unknown\n }\n const formFace = {\n getSnapshot: () => form.getSnapshot(),\n subscribe: (listener: () => void) => form.subscribe(listener),\n mutate: (ops: never, revision?: number) => form.mutate(ops, revision),\n }\n ctx.slots.inject('settings.section', () => ctx.slots.register({\n name: 'settings.section', id: SETTINGS_NS, order: 41,\n label: () => t('settings.nav'), locale: NS,\n inject: () => ({ form: formFace }),\n }, EvalGuardSettings))\n ctx.slots.inject('shell.overlay', () => ctx.slots.register({\n name: 'shell.overlay', id: SETTINGS_NS + '.toast', locale: NS,\n inject: () => ({ t }),\n }, GuardToast))\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["useSyncExternalStore","useState","useRef","useState"],"sources":["../../src/shared.ts","../../src/client/bridge.ts","../../src/client/Settings.tsx","../../src/client/Toast.tsx","../../src/client/locales.ts","../../src/client/index.ts"],"sourcesContent":["/**\n * Wire types shared by the host and browser halves. Keep this module import-free:\n * the client bundle includes it without pulling host code.\n * @module dsh-eval-guard/shared\n */\n\n/** Settings namespace; also the Loader row id in cordis.patch.yml. */\nexport const SETTINGS_NS = 'eval-guard'\n\n/** Route paths owned by this plugin. */\nexport const STATE_ROUTE = '/api/eval-guard/state'\nexport const CHECK_ROUTE = '/api/eval-guard/check'\nexport const INSTALL_ROUTE = '/api/eval-guard/install'\nexport const PROMPT_ROUTE = '/api/eval-guard/prompt'\nexport const EVENTS_ROUTE = '/api/eval-guard/events'\nexport const REVEAL_ROUTE = '/api/eval-guard/reveal'\nexport const MANUAL_ROUTE = '/api/eval-guard/manual'\nexport const JOBS_ROUTE = '/api/eval-guard/jobs'\nexport const JOB_ROUTE = '/api/eval-guard/job'\nexport const JOB_CANCEL_ROUTE = '/api/eval-guard/job/cancel'\nexport const EVAL_ROUTE = '/api/eval-guard/evaluate'\n\n/** Supported task ids. */\nexport const TANK_TASK = 'tank'\nexport const TANK_TASK_LABEL = '第 6 集 · 坦克大战'\nexport const WAREHOUSE_TASK = 'warehouse'\nexport const WAREHOUSE_TASK_LABEL = '第 5 集 · 仓储调度'\nexport const LAND_TASK = 'land'\nexport const LAND_TASK_LABEL = '第 1 集 · 圈地'\nexport const BOMBERMAN_TASK = 'bomberman'\nexport const BOMBERMAN_TASK_LABEL = '第 2 集 · 炸弹人'\nexport const CTF_TASK = 'ctf'\nexport const CTF_TASK_LABEL = '第 3 集 · 夺旗'\nexport const COMMIT0_TASK = 'commit0'\nexport const COMMIT0_TASK_LABEL = 'Commit0 · 单库实现'\nexport const SWE_BENCH_PRO_TASK = 'swe-bench-pro'\nexport const SWE_BENCH_PRO_TASK_LABEL = 'SWE-Bench Pro · 单任务'\nexport const FEATUREBENCH_TASK = 'featurebench'\nexport const FEATUREBENCH_TASK_LABEL = 'FeatureBench · 单 feature'\nexport const NEURAL_CPP_TASK = 'neural-cpp'\nexport const NEURAL_CPP_TASK_LABEL = 'Neural-CPP · 纯 C++ 张量后端'\nexport const NEURAL_FP32_TASK = 'neural-fp32'\nexport const NEURAL_FP32_TASK_LABEL = 'Neural-FP32 · 运算与性能'\nexport const NEURAL_CIFAR_TASK = 'neural-cifar'\nexport const NEURAL_CIFAR_TASK_LABEL = 'Neural-CIFAR · 从零训练图像分类'\n\n/** One validated clone remote for a task. */\nexport interface TaskRemote {\n id: string\n label: string\n url: string\n}\n\n/** Common pip indexes offered by the settings page. */\nexport const PIP_MIRRORS: readonly { id: string; label: string; url: string }[] = [\n { id: 'pypi', label: 'PyPI', url: 'https://pypi.org/simple' },\n { id: 'tsinghua', label: '清华 TUNA', url: 'https://pypi.tuna.tsinghua.edu.cn/simple' },\n { id: 'aliyun', label: '阿里云', url: 'https://mirrors.aliyun.com/pypi/simple' },\n { id: 'tencent', label: '腾讯云', url: 'https://mirrors.cloud.tencent.com/pypi/simple' },\n { id: 'bfsu', label: '北外', url: 'https://mirrors.bfsu.edu.cn/pypi/web/simple' },\n { id: 'sjtu', label: '上海交大', url: 'https://mirror.sjtu.edu.cn/pypi/web/simple' },\n]\n\n/** One task offered by the installer. */\nexport interface TaskInfo {\n id: string\n label: string\n description: string\n /** Default wall-clock limit applied when the user selects this task. */\n timeLimitMinutes: number\n /** Default time-limit switch applied when the user selects this task. */\n timeLimitEnabled: boolean\n /** Whether installation needs a host-side clone / venv setup. */\n needsSetup: boolean\n /** Canonical upstream repository; used to build mirror URLs. */\n repoUrl?: string\n /** Clone remotes verified to contain the exact pinned commit. */\n remotes?: TaskRemote[]\n}\n\nexport type JobKind = 'install' | 'eval'\nexport type JobStatus = 'queued' | 'running' | 'succeeded' | 'failed' | 'cancelled' | 'interrupted'\n\n/** Summary of one background setup or evaluation job. */\nexport interface JobInfo {\n id: string\n kind: JobKind\n task: string\n workspaceId: string\n status: JobStatus\n createdAt: number\n startedAt: number | null\n endedAt: number | null\n updatedAt: number\n error?: string\n}\n\n/** Full job state, including a bounded log and optional result. */\nexport interface JobDetail extends JobInfo {\n log: string\n prompt?: string\n runId?: string\n result?: unknown\n}\n\n/** A live conversation the enable-time warning has to mention. */\nexport interface RunningSession {\n sessionId: string\n title: string\n cwd: string\n running: boolean\n jobs: number\n}\n\n/** One warning surfaced to the browser. */\nexport interface GuardEvent {\n seq: number\n at: number\n sessionId?: string\n runId?: string\n kind: 'tool-blocked' | 'path-denied' | 'process-denied' | 'wait-blocked' | 'timeout' | 'notice'\n tool?: string\n detail: string\n}\n\n/** Host answer for the enable pre-check. */\nexport interface GuardState {\n enabled: boolean\n running: RunningSession[]\n tasks: TaskInfo[]\n defaultBlacklist: string\n generatedDefault: boolean\n workspaceRoot: string\n runsRoot: string\n pipMirrors?: { id: string; label: string; url: string }[]\n}\n\n/** Result of checking one workspace before install. */\nexport interface CheckResult {\n ok: boolean\n workspaceId: string\n path: string\n empty: boolean\n entries: string[]\n error?: string\n}\n\n/** Result of installing the task pack. */\nexport interface InstallResult {\n ok: boolean\n error?: string\n runId?: string\n workspaceId?: string\n workspacePath?: string\n prompt?: string\n}\n\n/** Manual-channel material locations. */\nexport interface ManualPaths {\n source: string\n prompt: string\n}\n\n/** Usage record written next to one run. */\nexport interface RunUsage {\n inputTokens: number\n outputTokens: number\n cacheReadTokens: number\n cacheWriteTokens: number\n reasoningTokens: number\n toolCalls: number\n turns: number\n steps: number\n wallTimeMs: number\n startedAt: number | null\n updatedAt: number\n}\n\n/** Metadata for one guarded task run. */\nexport interface RunRecord {\n runId: string\n task: string\n workspaceId: string\n workspacePath: string\n sessionId: string | null\n createdAt: number\n startedAt: number | null\n endedAt: number | null\n status: 'prepared' | 'active' | 'timeout' | 'ended'\n prompt: string\n timeLimitMinutes: number\n provider?: string\n model?: string\n title?: string\n}\n","/** Shell capabilities published to the Settings panel. */\nexport interface EvalWorkspace { id: string; label: string }\nexport interface EvalBridge {\n startSession(workspaceId: string, prompt: string): void\n workspaces(): readonly EvalWorkspace[]\n}\nlet current: EvalBridge | undefined\nexport function configureEvalBridge(next: EvalBridge | undefined): void { current = next }\nexport function evalBridge(): EvalBridge | undefined { return current }\n","/**\n * Settings panel for the evaluation guard.\n * @module dsh-eval-guard/client/Settings\n */\nimport { useEffect, useRef, useState, useSyncExternalStore, type CSSProperties, type ReactElement } from 'react'\nimport {\n CHECK_ROUTE, EVENTS_ROUTE, INSTALL_ROUTE, MANUAL_ROUTE, REVEAL_ROUTE, STATE_ROUTE,\n JOBS_ROUTE, JOB_ROUTE, JOB_CANCEL_ROUTE, EVAL_ROUTE,\n type CheckResult, type GuardEvent, type GuardState, type InstallResult, type ManualPaths, type JobDetail, type JobInfo,\n PIP_MIRRORS,\n} from '../shared.ts'\nimport { evalBridge } from './bridge.ts'\n\ntype Snapshot = {\n status: 'loading' | 'ready' | 'unavailable'\n value?: Record<string, unknown>\n revision?: number\n writable: boolean\n}\ntype Form = {\n getSnapshot: () => Snapshot\n subscribe: (listener: () => void) => () => void\n mutate: (ops: readonly { op: 'set'; path: string[]; value: unknown }[], revision?: number) => Promise<boolean>\n}\ntype Props = { form: Form; t: (key: string) => string }\n\ninterface Draft {\n enabled: boolean\n timeLimitEnabled: boolean\n timeLimitMinutes: number\n forbiddenPaths: string\n toolBlacklistUseDefault: boolean\n toolBlacklist: string\n cloneSource: string\n customCloneUrl: string\n pipIndex: string\n customPipUrl: string\n gitProxyUrl: string\n pipProxyUrl: string\n cifarProxyUrl: string\n}\n\nconst EMPTY: Draft = {\n enabled: false,\n timeLimitEnabled: true,\n timeLimitMinutes: 90,\n forbiddenPaths: '',\n toolBlacklistUseDefault: true,\n toolBlacklist: '',\n cloneSource: 'github',\n customCloneUrl: '',\n pipIndex: 'pypi',\n customPipUrl: '',\n gitProxyUrl: '',\n pipProxyUrl: '',\n cifarProxyUrl: '',\n}\n\nconst box: CSSProperties = { border: '1px solid var(--vscode-panel-border, #3c3c3c)', borderRadius: 8, padding: 14, marginBottom: 14 }\nconst row: CSSProperties = { display: 'flex', gap: 10, alignItems: 'center', flexWrap: 'wrap', marginBottom: 8 }\nconst note: CSSProperties = { opacity: 0.72, fontSize: 12, lineHeight: 1.5, margin: '6px 0' }\nconst textarea: CSSProperties = { width: '100%', minHeight: 110, fontFamily: 'monospace', fontSize: 12, padding: 8, boxSizing: 'border-box' }\nconst button: CSSProperties = { padding: '5px 12px', borderRadius: 6, cursor: 'pointer' }\nconst primary: CSSProperties = { ...button, background: '#2f6fd0', color: '#fff', border: 'none' }\nconst danger: CSSProperties = { ...button, background: '#a33', color: '#fff', border: 'none' }\n\nasync function readJson<T>(response: Response): Promise<T> { return await response.json() as T }\n\nfunction normalize(value: Record<string, unknown> | undefined): Draft {\n return {\n enabled: value?.enabled === true,\n timeLimitEnabled: value?.timeLimitEnabled !== false,\n timeLimitMinutes: typeof value?.timeLimitMinutes === 'number' ? value.timeLimitMinutes : 90,\n forbiddenPaths: typeof value?.forbiddenPaths === 'string' ? value.forbiddenPaths : '',\n toolBlacklistUseDefault: value?.toolBlacklistUseDefault !== false,\n toolBlacklist: typeof value?.toolBlacklist === 'string' ? value.toolBlacklist : '',\n cloneSource: typeof value?.cloneSource === 'string' && value.cloneSource !== '' ? value.cloneSource : 'github',\n customCloneUrl: typeof value?.customCloneUrl === 'string' ? value.customCloneUrl : '',\n pipIndex: typeof value?.pipIndex === 'string' && value.pipIndex !== '' ? value.pipIndex : 'pypi',\n customPipUrl: typeof value?.customPipUrl === 'string' ? value.customPipUrl : '',\n gitProxyUrl: typeof value?.gitProxyUrl === 'string' ? value.gitProxyUrl : '',\n pipProxyUrl: typeof value?.pipProxyUrl === 'string' ? value.pipProxyUrl : '',\n cifarProxyUrl: typeof value?.cifarProxyUrl === 'string' ? value.cifarProxyUrl : '',\n }\n}\n\n/** The settings card. */\nexport function EvalGuardSettings({ form, t }: Props): ReactElement {\n const snapshot = useSyncExternalStore(form.subscribe, form.getSnapshot, form.getSnapshot)\n const [draft, setDraft] = useState<Draft>(EMPTY)\n const [dirty, setDirty] = useState(false)\n const [state, setState] = useState<GuardState | null>(null)\n const [events, setEvents] = useState<GuardEvent[]>([])\n const [pendingEnable, setPendingEnable] = useState(false)\n const [notice, setNotice] = useState('')\n const [error, setError] = useState('')\n const [workspaceId, setWorkspaceId] = useState(() => typeof localStorage === 'undefined' ? '' : localStorage.getItem('evalGuard.workspaceId') ?? '')\n const [taskId, setTaskId] = useState(() => typeof localStorage === 'undefined' ? '' : localStorage.getItem('evalGuard.taskId') ?? '')\n const [check, setCheck] = useState<CheckResult | null>(null)\n const [manual, setManual] = useState<ManualPaths | null>(null)\n const [prompt, setPrompt] = useState('')\n const [copied, setCopied] = useState('')\n const workspaces = evalBridge()?.workspaces() ?? []\n const [job, setJob] = useState<JobDetail | null>(null)\n const [jobNotice, setJobNotice] = useState('')\n const autoOpenJob = useRef('')\n\n const pollJob = (id: string): void => {\n fetch(JOB_ROUTE + '?id=' + encodeURIComponent(id)).then(readJson<JobDetail>).then(setJob).catch(() => undefined)\n }\n const loadLatestJob = (workspace: string, task: string): void => {\n if (workspace === '' || task === '') { setJob(null); return }\n fetch(JOBS_ROUTE + '?workspaceId=' + encodeURIComponent(workspace) + '&task=' + encodeURIComponent(task))\n .then(readJson<JobInfo[]>).then(items => {\n const latest = items[0]\n if (latest !== undefined) pollJob(latest.id)\n else setJob(null)\n }).catch(() => undefined)\n }\n useEffect(() => {\n if (job === null || (job.status !== 'running' && job.status !== 'queued')) return\n const timer = setInterval(() => { pollJob(job.id) }, 800)\n return () => clearInterval(timer)\n }, [job])\n useEffect(() => { if (job?.status === 'succeeded' && job.kind === 'install' && job.prompt !== undefined) {\n setPrompt(job.prompt); setJobNotice(t('settings.installOk')); loadState()\n if (autoOpenJob.current === job.id) {\n autoOpenJob.current = ''\n evalBridge()?.startSession(job.workspaceId, job.prompt)\n }\n } }, [job])\n useEffect(() => { loadLatestJob(workspaceId, taskId) }, [workspaceId, taskId])\n\n useEffect(() => {\n if (snapshot.status !== 'ready' || snapshot.value === undefined || dirty) return\n setDraft(normalize(snapshot.value))\n }, [snapshot, dirty])\n\n const loadState = (): void => {\n fetch(STATE_ROUTE).then(readJson<GuardState>).then(setState).catch(() => setState(null))\n }\n useEffect(() => {\n loadState()\n let since = 0\n const timer = setInterval(() => {\n fetch(EVENTS_ROUTE + '?since=' + String(since)).then(readJson<{ events: GuardEvent[] }>).then(data => {\n if (data.events.length === 0) return\n since = data.events[data.events.length - 1]!.seq\n setEvents(current => [...data.events, ...current].slice(0, 12))\n }).catch(() => undefined)\n }, 2000)\n return () => clearInterval(timer)\n }, [])\n\n useEffect(() => {\n if (state !== null && state.tasks.length > 0 && (taskId === '' || !state.tasks.some(task => task.id === taskId))) setTaskId(state.tasks[0]!.id)\n }, [state, taskId])\n\n const ready = snapshot.status === 'ready' && snapshot.writable\n const save = async (patch: Partial<Draft>): Promise<void> => {\n if (!ready || snapshot.revision === undefined) return\n const next = { ...draft, ...patch }\n const ops: { op: 'set'; path: string[]; value: unknown }[] = []\n for (const key of Object.keys(patch) as (keyof Draft)[]) ops.push({ op: 'set', path: [key], value: next[key] })\n try {\n const accepted = await form.mutate(ops, snapshot.revision)\n if (!accepted) { setError('保存冲突,请刷新后重试。'); return }\n setDraft(next)\n setDirty(false)\n setError('')\n loadState()\n } catch (reason: unknown) {\n setError(reason instanceof Error ? reason.message : String(reason))\n }\n }\n const edit = (patch: Partial<Draft>): void => {\n setDraft(current => ({ ...current, ...patch }))\n setDirty(true)\n }\n\n const selectTask = (next: string): void => {\n setTaskId(next)\n try { localStorage.setItem('evalGuard.taskId', next) } catch { /* storage is optional */ }\n setCheck(null); setManual(null); setPrompt(''); setJob(null); setJobNotice('')\n if (workspaceId !== '') loadManual(workspaceId, next)\n const task = state?.tasks.find(item => item.id === next)\n if (task === undefined) return\n const remotes = task.remotes ?? []\n const cloneSource = draft.cloneSource === 'custom' || remotes.some(remote => remote.id === draft.cloneSource)\n ? draft.cloneSource : (remotes[0]?.id ?? 'github')\n setDraft(current => ({ ...current, timeLimitMinutes: task.timeLimitMinutes, timeLimitEnabled: task.timeLimitEnabled, cloneSource }))\n setNotice(t('settings.taskDefaults').replace('{minutes}', String(task.timeLimitMinutes)).replace('{state}', task.timeLimitEnabled ? t('settings.on') : t('settings.off')))\n void save({ timeLimitMinutes: task.timeLimitMinutes, timeLimitEnabled: task.timeLimitEnabled, cloneSource })\n }\n\n const toggleEnabled = (next: boolean): void => {\n if (!next) { void save({ enabled: false }); return }\n fetch(STATE_ROUTE).then(readJson<GuardState>).then(latest => {\n setState(latest)\n if (latest.running.length > 0) setPendingEnable(true)\n else void save({ enabled: true })\n }).catch(() => void save({ enabled: true }))\n }\n\n const forceEnable = (): void => {\n setPendingEnable(false)\n void save({ enabled: true })\n }\n\n const loadManual = (id: string, task: string): void => {\n if (id === '') { setCheck(null); setManual(null); setPrompt(''); return }\n fetch(CHECK_ROUTE + '?workspaceId=' + encodeURIComponent(id)).then(readJson<CheckResult>).then(result => {\n setCheck(result)\n if (result.ok) {\n fetch(MANUAL_ROUTE + '?workspaceId=' + encodeURIComponent(id) + '&task=' + encodeURIComponent(task)).then(readJson<ManualPaths>).then(paths => {\n setManual(paths)\n setPrompt(paths.prompt)\n }).catch(() => undefined)\n }\n }).catch((reason: unknown) => setError(reason instanceof Error ? reason.message : String(reason)))\n }\n\n const install = async (): Promise<void> => {\n if (workspaceId === '' || taskId === '') return\n setError(''); setNotice(''); setJobNotice('')\n const checked = await fetch(CHECK_ROUTE + '?workspaceId=' + encodeURIComponent(workspaceId)).then(readJson<CheckResult>)\n setCheck(checked)\n if (!checked.ok || !checked.empty) { setError(checked.error ?? t('settings.nonEmpty')); return }\n const result = await fetch(INSTALL_ROUTE, {\n method: 'POST', headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ workspaceId, task: taskId, cloneSource: draft.cloneSource, customCloneUrl: draft.customCloneUrl,\n pipIndex: draft.pipIndex, customPipUrl: draft.customPipUrl, gitProxyUrl: draft.gitProxyUrl, pipProxyUrl: draft.pipProxyUrl, cifarProxyUrl: draft.cifarProxyUrl }),\n }).then(readJson<{ ok: boolean; jobId?: string; error?: string }>)\n if (!result.ok || result.jobId === undefined) { autoOpenJob.current = ''; setError(result.error ?? '安装失败'); return }\n autoOpenJob.current = result.jobId\n pollJob(result.jobId)\n }\n\n const evaluate = async (): Promise<void> => {\n if (workspaceId === '' || taskId === '') return\n setError(''); setNotice(''); setJobNotice('')\n const result = await fetch(EVAL_ROUTE, {\n method: 'POST', headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ workspaceId, task: taskId }),\n }).then(readJson<{ ok: boolean; jobId?: string; error?: string }>)\n if (!result.ok || result.jobId === undefined) { setError(result.error ?? '评测启动失败'); return }\n pollJob(result.jobId)\n }\n\n const cancelJob = async (): Promise<void> => {\n if (job === null) return\n await fetch(JOB_CANCEL_ROUTE, { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ id: job.id }) })\n pollJob(job.id)\n }\n\n const copy = async (label: string, text: string): Promise<void> => {\n try {\n await navigator.clipboard.writeText(text)\n setCopied(label)\n setTimeout(() => setCopied(''), 1500)\n } catch { setError('复制失败') }\n }\n const reveal = (target: string): void => {\n void fetch(REVEAL_ROUTE, {\n method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ path: target }),\n })\n }\n const blacklistText = draft.toolBlacklistUseDefault ? state?.defaultBlacklist ?? '' : draft.toolBlacklist\n\n if (snapshot.status === 'loading') return <div style={box}>{t('settings.loading')}</div>\n return <div>\n {pendingEnable && <div style={{ ...box, borderColor: '#caa23a' }}>\n <strong>{t('settings.warningTitle')}</strong>\n <p style={note}>{t('settings.runningWarning')}</p>\n <ul style={{ ...note, paddingLeft: 18 }}>{(state?.running ?? []).map(item =>\n <li key={item.sessionId}>{item.title} · {item.cwd}{item.jobs > 0 ? ' · jobs: ' + String(item.jobs) : ''}</li>)}</ul>\n <div style={row}>\n <button style={button} onClick={() => { setPendingEnable(false); loadState() }}>{t('settings.runningCancel')}</button>\n <button style={danger} onClick={forceEnable}>{t('settings.runningForce')}</button>\n </div>\n </div>}\n\n <section style={box}>\n <div style={row}>\n <label><input type=\"checkbox\" checked={draft.enabled} disabled={!ready} onChange={event => toggleEnabled(event.target.checked)} /> {t('settings.enabled')}</label>\n </div>\n <p style={note}>{t('settings.enabledHint')}</p>\n </section>\n\n <section style={box}>\n <strong>{t('settings.forbidden')}</strong>\n <p style={note}>{t('settings.forbiddenHint')}</p>\n <textarea style={textarea} value={draft.forbiddenPaths} disabled={!ready}\n onChange={event => edit({ forbiddenPaths: event.target.value })}\n onBlur={() => void save({ forbiddenPaths: draft.forbiddenPaths })} />\n </section>\n\n <section style={box}>\n <div style={row}>\n <strong>{t('settings.blacklist')}</strong>\n <button style={button} disabled={!ready} onClick={() => void save({ toolBlacklistUseDefault: true, toolBlacklist: '' })}>{t('settings.reset')}</button>\n </div>\n <p style={note}>{t('settings.blacklistHint')}</p>\n <textarea style={textarea} value={blacklistText} disabled={!ready}\n onChange={event => edit({ toolBlacklistUseDefault: false, toolBlacklist: event.target.value })}\n onBlur={() => void save({ toolBlacklistUseDefault: draft.toolBlacklistUseDefault, toolBlacklist: draft.toolBlacklist })} />\n {draft.toolBlacklistUseDefault && <p style={note}>{t('settings.editingDefault')}</p>}\n </section>\n\n <section style={box}>\n <strong>{t('settings.task')}</strong>\n <p style={note}>{t('settings.taskHint')}</p>\n <div style={row}>\n <span>{t('settings.taskLabel')}:</span>\n <select value={taskId} disabled={state === null || state.tasks.length === 0}\n onChange={event => selectTask(event.target.value)}>\n {(state?.tasks ?? []).map(task => <option key={task.id} value={task.id}>{task.label}</option>)}\n </select>\n </div>\n {state !== null && <p style={note}>{state.tasks.find(task => task.id === taskId)?.description ?? ''}</p>}\n {(() => {\n const selected = state?.tasks.find(item => item.id === taskId)\n if (selected?.needsSetup !== true) return null\n return <div>\n <div style={row}>\n <span>{t('settings.cloneSource')}:</span>\n <select value={draft.cloneSource} disabled={!ready} onChange={event => void save({ cloneSource: event.target.value })}>\n {(selected.remotes ?? []).map(remote => <option key={remote.id} value={remote.id}>{remote.label}</option>)}\n <option value=\"custom\">{t('settings.custom')}</option>\n </select>\n {draft.cloneSource === 'custom' && <input style={{ width: 260 }} disabled={!ready} value={draft.customCloneUrl}\n onChange={event => edit({ customCloneUrl: event.target.value })} onBlur={() => void save({ customCloneUrl: draft.customCloneUrl })} placeholder=\"https://git.example.com\" />}\n </div>\n <div style={row}>\n <span>{t('settings.pipIndex')}:</span>\n <select value={draft.pipIndex} disabled={!ready} onChange={event => void save({ pipIndex: event.target.value })}>\n {PIP_MIRRORS.map(mirror => <option key={mirror.id} value={mirror.id}>{mirror.label}</option>)}\n <option value=\"custom\">{t('settings.custom')}</option>\n </select>\n {draft.pipIndex === 'custom' && <input style={{ width: 260 }} disabled={!ready} value={draft.customPipUrl}\n onChange={event => edit({ customPipUrl: event.target.value })} onBlur={() => void save({ customPipUrl: draft.customPipUrl })} placeholder=\"https://pypi.example.com/simple\" />}\n </div>\n <div style={row}>\n <span>{t('settings.gitProxy')}:</span>\n <input style={{ width: 260 }} disabled={!ready} value={draft.gitProxyUrl}\n onChange={event => edit({ gitProxyUrl: event.target.value })} onBlur={() => void save({ gitProxyUrl: draft.gitProxyUrl })} placeholder=\"127.0.0.1:7897\" />\n </div>\n <div style={row}>\n <span>{t('settings.pipProxy')}:</span>\n <input style={{ width: 260 }} disabled={!ready} value={draft.pipProxyUrl}\n onChange={event => edit({ pipProxyUrl: event.target.value })} onBlur={() => void save({ pipProxyUrl: draft.pipProxyUrl })} placeholder=\"127.0.0.1:7897\" />\n </div>\n <div style={row}>\n <span>{t('settings.cifarProxy')}:</span>\n <input style={{ width: 260 }} disabled={!ready} value={draft.cifarProxyUrl}\n onChange={event => edit({ cifarProxyUrl: event.target.value })} onBlur={() => void save({ cifarProxyUrl: draft.cifarProxyUrl })} placeholder=\"127.0.0.1:7897\" />\n </div>\n </div>\n })()}\n <div style={row}>\n <span>{t('settings.workspace')}:</span>\n <select value={workspaceId} onChange={event => { const next = event.target.value; setWorkspaceId(next); try { localStorage.setItem('evalGuard.workspaceId', next) } catch { /* storage is optional */ } loadManual(next, taskId); loadLatestJob(next, taskId) }}>\n <option value=\"\">{t('settings.pickWorkspace')}</option>\n {workspaces.map(workspace => <option key={workspace.id} value={workspace.id}>{workspace.label}</option>)}\n </select>\n <button style={primary} disabled={workspaceId === '' || taskId === '' || job?.status === 'running'} onClick={() => void install()}>{t('settings.check')}</button>\n <button style={button} disabled={workspaceId === '' || taskId === '' || job?.status === 'running'} onClick={() => void evaluate()}>{t('settings.evaluate')}</button>\n </div>\n <p style={note}>{t('settings.evalHint')}</p>\n {workspaces.length === 0 && <p style={note}>{t('settings.noWorkspaces')}</p>}\n {check !== null && !check.empty && <p style={{ ...note, color: '#d99' }}>{t('settings.nonEmpty')} ({check.entries.slice(0, 6).join(', ')})</p>}\n {notice !== '' && <p style={{ ...note, color: '#7c7' }}>{notice}</p>}\n {error !== '' && <p style={{ ...note, color: '#d77' }}>{error}</p>}\n {jobNotice !== '' && <p style={{ ...note, color: '#7c7' }}>{jobNotice}</p>}\n {job !== null && <div style={{ ...box, borderColor: job.status === 'failed' ? '#a55' : job.status === 'succeeded' ? '#4a7' : '#3a6' }}>\n <div style={row}><strong>{job.kind === 'install' ? t('settings.installJob') : t('settings.evalJob')}</strong><span>{job.status}</span>\n {job.status === 'running' && <button style={danger} onClick={() => void cancelJob()}>{t('settings.cancel')}</button>}\n {job.kind === 'install' && job.status === 'succeeded' && job.prompt !== undefined && workspaceId !== '' && <button style={primary} onClick={() => evalBridge()?.startSession(workspaceId, job.prompt!)}>{t('settings.startSession')}</button>}</div>\n {job.error !== undefined && <p style={{ ...note, color: '#d77' }}>{job.error}</p>}\n <pre style={{ ...textarea, maxHeight: 260, overflow: 'auto' }}>{job.log || t('settings.waiting')}</pre>\n {job.result !== undefined && <pre style={{ ...textarea, maxHeight: 260, overflow: 'auto' }}>{JSON.stringify(job.result, undefined, 2)}</pre>}\n </div>}\n </section>\n\n <section style={box}>\n <div style={row}>\n <label><input type=\"checkbox\" checked={draft.timeLimitEnabled} disabled={!ready} onChange={event => void save({ timeLimitEnabled: event.target.checked })} /> {t('settings.timeLimit')}</label>\n <input type=\"number\" min={1} max={1440} value={draft.timeLimitMinutes} disabled={!ready}\n style={{ width: 90 }} onChange={event => edit({ timeLimitMinutes: Number(event.target.value) })}\n onBlur={() => void save({ timeLimitMinutes: draft.timeLimitMinutes })} />\n <span style={note}>{t('settings.minutes')}</span>\n </div>\n <p style={note}>{t('settings.timeLimitHint')}</p>\n </section>\n\n <section style={box}>\n <strong>{t('settings.manual')}</strong>\n <p style={note}>{t('settings.manualHint')}</p>\n <div style={row}><span>{t('settings.source')}:</span><code style={{ wordBreak: 'break-all' }}>{manual?.source ?? '—'}</code>\n {manual !== null && <button style={button} onClick={() => reveal(manual.source)}>{t('settings.reveal')}</button>}</div>\n <div style={row}><span>{t('settings.target')}:</span><code style={{ wordBreak: 'break-all' }}>{check?.path ?? '—'}</code>\n {check?.path !== undefined && check.path !== '' && <button style={button} onClick={() => reveal(check.path)}>{t('settings.reveal')}</button>}</div>\n <div style={row}><button style={button} disabled={prompt === ''} onClick={() => void copy('prompt', prompt)}>{copied === 'prompt' ? t('settings.copied') : t('settings.copy')}</button></div>\n <textarea style={{ ...textarea, minHeight: 160 }} readOnly value={prompt} placeholder={t('settings.prompt')} />\n </section>\n\n <section style={box}>\n <strong>{t('settings.recent')}</strong>\n {events.length === 0 && <p style={note}>{t('settings.none')}</p>}\n {events.map(event => <div key={event.seq} style={{ ...note, borderTop: '1px solid #333', paddingTop: 4 }}>\n <strong>[{event.kind}]</strong> {event.tool !== undefined ? event.tool + ' · ' : ''}{event.detail}\n </div>)}\n </section>\n </div>\n}\n","/**\n * Frame-wide warning toasts fed by the host event route.\n * @module dsh-eval-guard/client/Toast\n */\nimport { useEffect, useState, type ReactElement } from 'react'\nimport { EVENTS_ROUTE, type GuardEvent } from '../shared.ts'\n\n/** One toast with a dismiss deadline. */\ninterface Shown { event: GuardEvent; until: number }\n\n/** Poll the host event feed and show new warnings. */\nexport function GuardToast({ t }: { t: (key: string) => string }): ReactElement | null {\n const [shown, setShown] = useState<Shown[]>([])\n useEffect(() => {\n let since = 0\n let alive = true\n const poll = (): void => {\n fetch(EVENTS_ROUTE + '?since=' + String(since)).then(async response => await response.json() as { events: GuardEvent[] }).then(data => {\n if (!alive || data.events.length === 0) return\n since = data.events[data.events.length - 1]!.seq\n const warnings = data.events.filter(event => event.kind !== 'notice')\n if (warnings.length === 0) return\n const now = Date.now()\n setShown(current => [...warnings.map(event => ({ event, until: now + 8000 })), ...current].slice(0, 5))\n }).catch(() => undefined)\n }\n const timer = setInterval(() => {\n poll()\n const now = Date.now()\n setShown(current => current.filter(item => item.until > now))\n }, 1500)\n poll()\n return () => { alive = false; clearInterval(timer) }\n }, [])\n if (shown.length === 0) return null\n return <div style={{ position: 'fixed', right: 18, bottom: 18, zIndex: 9999, display: 'flex', flexDirection: 'column', gap: 8, maxWidth: 420 }}>\n {shown.map(item => <div key={item.event.seq} style={{\n background: '#3a2a12', color: '#ffdca8', border: '1px solid #8a6a2a', borderRadius: 8,\n padding: '10px 12px', fontSize: 12, lineHeight: 1.5, boxShadow: '0 6px 24px rgba(0,0,0,.45)',\n }}>\n <strong>{t('settings.warningTitle')}</strong>\n <div>{item.event.detail}</div>\n </div>)}\n </div>\n}\n","/** Locale namespace and dictionaries for the browser half. */\nexport const NS = 'evalGuard'\n\nexport const zh = {\n 'settings.nav': '评测守护',\n 'settings.title': '评测守护',\n 'settings.enabled': '启用评测守护',\n 'settings.enabledHint': '启用后,所有用户主对话只能读写自己的工作区,禁止联网、子代理与跨 agent 通信,并按任务时限强制终止。默认关闭。',\n 'settings.runningWarning': '当前有正在运行的对话。启用评测守护会立即约束它们,是否强行开启?',\n 'settings.runningCancel': '放弃',\n 'settings.runningForce': '强行开启',\n 'settings.timeLimit': '开启最长时长',\n 'settings.timeLimitHint': '从每条用户消息发送时开始计时;到点只终止当前轮次,并递归清理子代理与后台任务。',\n 'settings.minutes': '分钟',\n 'settings.forbidden': '额外禁止路径',\n 'settings.forbiddenHint': '每行一个绝对路径;# 开头为注释;! 开头表示在禁止范围内放开该子路径;按行顺序生效。默认空。',\n 'settings.blacklist': '工具黑名单',\n 'settings.blacklistHint': '每行一个工具名;默认内容按当前已安装工具生成,不存在的工具会被忽略。',\n 'settings.reset': '恢复默认黑名单',\n 'settings.editingDefault': '编辑后将以自定义黑名单保存。',\n 'settings.task': '安装 / 评测任务',\n 'settings.taskHint': '选择任务和工作区;安装与评测共用这组选择。安装会写入素材并准备环境,评测只对当前工作区运行一次。',\n 'settings.taskLabel': '任务',\n 'settings.workspace': '工作区',\n 'settings.pickWorkspace': '请选择工作区',\n 'settings.check': '安装任务',\n 'settings.nonEmpty': '工作区不是空的;未执行任何操作。',\n 'settings.manual': '手动通道',\n 'settings.manualHint': '手动复制素材:自己把素材目录内容复制到工作区根目录;手动填充提示词:复制下面的提示词。',\n 'settings.source': '素材路径',\n 'settings.target': '工作区路径',\n 'settings.copy': '复制',\n 'settings.copied': '已复制',\n 'settings.prompt': '初始提示词',\n 'settings.reveal': '在文件管理器中打开',\n 'settings.noWorkspaces': '没有可选的工作区。',\n 'settings.installOk': '任务素材已安装,提示词已填入新会话,请自行发送。',\n 'settings.taskDefaults': '已按任务默认值设置限时:{minutes} 分钟,限时开关 {state}。你可以随后手动修改。',\n 'settings.on': '打开',\n 'settings.off': '关闭',\n 'settings.evaluate': '评测当前工作区',\n 'settings.evalJob': '评测任务',\n 'settings.installJob': '安装任务',\n 'settings.cloneSource': '仓库来源',\n 'settings.pipIndex': 'pip 镜像',\n 'settings.custom': '自定义',\n 'settings.cancel': '取消',\n 'settings.waiting': '正在准备…',\n 'settings.evalHint': '只评测单个工作区,不做排名。评测任务与安装共用上面的工作区和任务选择。',\n 'settings.startSession': '填入新会话',\n 'settings.gitProxy': 'Git 代理',\n 'settings.pipProxy': 'pip 代理',\n 'settings.loading': '加载中…',\n 'settings.recent': '最近事件',\n 'settings.none': '暂无。',\n 'settings.warningTitle': '评测守护警告',\n 'settings.close': '关闭',\n} as const\n\nexport type Key = keyof typeof zh\n\nexport const en: Record<Key, string> = {\n 'settings.nav': 'Eval Guard',\n 'settings.title': 'Eval Guard',\n 'settings.enabled': 'Enable evaluation guard',\n 'settings.enabledHint': 'When on, every user main conversation may only read/write its own workspace, with network, subagents and cross-agent channels blocked, and a wall-clock limit. Off by default.',\n 'settings.runningWarning': 'Conversations are running right now. Enabling the guard will constrain them immediately. Force enable?',\n 'settings.runningCancel': 'Cancel',\n 'settings.runningForce': 'Force enable',\n 'settings.timeLimit': 'Enable time limit',\n 'settings.timeLimitHint': 'The clock starts at each user message; at the deadline only the current turn is cancelled, and subagents/jobs are cleaned up recursively.',\n 'settings.minutes': 'minutes',\n 'settings.forbidden': 'Extra forbidden paths',\n 'settings.forbiddenHint': 'One absolute path per line; # comments; ! re-allows a subpath; later lines win. Empty by default.',\n 'settings.blacklist': 'Tool blacklist',\n 'settings.blacklistHint': 'One tool name per line; the default is generated from the tools installed now and missing tools are ignored.',\n 'settings.reset': 'Reset default blacklist',\n 'settings.editingDefault': 'Editing switches this to a custom blacklist.',\n 'settings.task': 'Install / evaluate task',\n 'settings.taskHint': 'Pick a task and workspace; install and evaluation share this selection. Install writes the task and prepares the environment; evaluation runs once on the current workspace.',\n 'settings.taskLabel': 'Task',\n 'settings.workspace': 'Workspace',\n 'settings.pickWorkspace': 'Pick a workspace',\n 'settings.check': 'Install task',\n 'settings.nonEmpty': 'The workspace is not empty; nothing was changed.',\n 'settings.manual': 'Manual channel',\n 'settings.manualHint': 'Manual material copy: copy the source folder contents into the workspace root yourself. Manual prompt: copy the text below.',\n 'settings.source': 'Material path',\n 'settings.target': 'Workspace path',\n 'settings.copy': 'Copy',\n 'settings.copied': 'Copied',\n 'settings.prompt': 'Initial prompt',\n 'settings.reveal': 'Open in file manager',\n 'settings.noWorkspaces': 'No workspace is available.',\n 'settings.installOk': 'Task installed and the prompt was seeded into a new conversation; send it yourself.',\n 'settings.taskDefaults': 'Applied task defaults: {minutes} minutes, time limit {state}. You can change them afterwards.',\n 'settings.on': 'on',\n 'settings.off': 'off',\n 'settings.evaluate': 'Evaluate current workspace',\n 'settings.evalJob': 'Evaluation job',\n 'settings.installJob': 'Install job',\n 'settings.cloneSource': 'Clone source',\n 'settings.pipIndex': 'pip index',\n 'settings.custom': 'Custom',\n 'settings.cancel': 'Cancel',\n 'settings.waiting': 'Preparing…',\n 'settings.evalHint': 'Evaluates one workspace only; no ranking. Uses the same workspace/task selection as install.',\n 'settings.startSession': 'Open in new conversation',\n 'settings.gitProxy': 'Git proxy',\n 'settings.pipProxy': 'pip proxy',\n 'settings.cifarProxy': 'CIFAR download proxy',\n 'settings.loading': 'Loading…',\n 'settings.recent': 'Recent events',\n 'settings.none': 'None.',\n 'settings.warningTitle': 'Eval Guard warning',\n 'settings.close': 'Close',\n}\n","/**\n * Evaluation guard, browser half: the Settings section, the warning toast, and\n * the shell bridge used to seed a new conversation with the task prompt.\n * @module dsh-eval-guard/client\n */\nimport type { Context } from '@deepseek-ai/cordis'\nimport { SETTINGS_NS } from '../shared.ts'\nimport { EvalGuardSettings } from './Settings.tsx'\nimport { GuardToast } from './Toast.tsx'\nimport { configureEvalBridge } from './bridge.ts'\nimport { en, NS, zh, type Key } from './locales.ts'\n\ndeclare module '@deepseek-ai/dsh-client-ui-slots' {\n interface LocaleNamespaceMap {\n evalGuard: Key\n }\n}\n\nexport const inject = ['slots', 'locale', 'configForms', 'uiWorkspace']\n\nexport function apply(ctx: Context): void {\n ctx.effect(() => ctx.locale.register(NS, { zh, en }))\n configureEvalBridge({\n startSession: (workspaceId, prompt) => {\n ctx.uiWorkspace.startSession(workspaceId as Parameters<typeof ctx.uiWorkspace.startSession>[0], { prompt })\n },\n workspaces: () => {\n const service = (ctx as unknown as { get(key: string): unknown }).get('workspaces') as\n { list?: { getSnapshot(): { items?: readonly Record<string, unknown>[] } } } | undefined\n const items = service?.list?.getSnapshot().items ?? []\n return items.map((item, index) => ({\n id: typeof item['workspaceId'] === 'string' ? item['workspaceId'] : String(item['id'] ?? index),\n label: typeof item['title'] === 'string' && item['title'] !== ''\n ? item['title']\n : String(item['path'] ?? item['workspaceId'] ?? ('workspace ' + String(index + 1))),\n }))\n },\n })\n ctx.effect(() => () => { configureEvalBridge(undefined) })\n const t = ctx.locale.bind(NS)\n const form = ctx.configForms.get(SETTINGS_NS) as {\n getSnapshot(): unknown\n subscribe(listener: () => void): () => void\n mutate(ops: never, revision?: number): unknown\n }\n const formFace = {\n getSnapshot: () => form.getSnapshot(),\n subscribe: (listener: () => void) => form.subscribe(listener),\n mutate: (ops: never, revision?: number) => form.mutate(ops, revision),\n }\n ctx.slots.inject('settings.section', () => ctx.slots.register({\n name: 'settings.section', id: SETTINGS_NS, order: 41,\n label: () => t('settings.nav'), locale: NS,\n inject: () => ({ form: formFace }),\n }, EvalGuardSettings))\n ctx.slots.inject('shell.overlay', () => ctx.slots.register({\n name: 'shell.overlay', id: SETTINGS_NS + '.toast', locale: NS,\n inject: () => ({ t }),\n }, GuardToast))\n}\n"],"mappings":"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"}
|
package/lib/index.js
CHANGED
|
@@ -24,7 +24,8 @@ const Config = z.object({
|
|
|
24
24
|
pipIndex: z.string().default("pypi").volatile(),
|
|
25
25
|
customPipUrl: z.string().default("").volatile(),
|
|
26
26
|
gitProxyUrl: z.string().default("").volatile(),
|
|
27
|
-
pipProxyUrl: z.string().default("").volatile()
|
|
27
|
+
pipProxyUrl: z.string().default("").volatile(),
|
|
28
|
+
cifarProxyUrl: z.string().default("").volatile()
|
|
28
29
|
});
|
|
29
30
|
/** Clamp and normalize a live configuration object. */
|
|
30
31
|
function resolveConfig(value) {
|
|
@@ -41,7 +42,8 @@ function resolveConfig(value) {
|
|
|
41
42
|
pipIndex: typeof value?.pipIndex === "string" && value.pipIndex !== "" ? value.pipIndex : "pypi",
|
|
42
43
|
customPipUrl: typeof value?.customPipUrl === "string" ? value.customPipUrl : "",
|
|
43
44
|
gitProxyUrl: typeof value?.gitProxyUrl === "string" ? value.gitProxyUrl : "",
|
|
44
|
-
pipProxyUrl: typeof value?.pipProxyUrl === "string" ? value.pipProxyUrl : ""
|
|
45
|
+
pipProxyUrl: typeof value?.pipProxyUrl === "string" ? value.pipProxyUrl : "",
|
|
46
|
+
cifarProxyUrl: typeof value?.cifarProxyUrl === "string" ? value.cifarProxyUrl : ""
|
|
45
47
|
};
|
|
46
48
|
}
|
|
47
49
|
//#endregion
|
|
@@ -76,6 +78,10 @@ const FEATUREBENCH_TASK = "featurebench";
|
|
|
76
78
|
const FEATUREBENCH_TASK_LABEL = "FeatureBench · 单 feature";
|
|
77
79
|
const NEURAL_CPP_TASK = "neural-cpp";
|
|
78
80
|
const NEURAL_CPP_TASK_LABEL = "Neural-CPP · 纯 C++ 张量后端";
|
|
81
|
+
const NEURAL_FP32_TASK = "neural-fp32";
|
|
82
|
+
const NEURAL_FP32_TASK_LABEL = "Neural-FP32 · 运算与性能";
|
|
83
|
+
const NEURAL_CIFAR_TASK = "neural-cifar";
|
|
84
|
+
const NEURAL_CIFAR_TASK_LABEL = "Neural-CIFAR · 从零训练图像分类";
|
|
79
85
|
/** Common pip indexes offered by the settings page. */
|
|
80
86
|
const PIP_MIRRORS = [
|
|
81
87
|
{
|
|
@@ -818,7 +824,8 @@ var Guard = class {
|
|
|
818
824
|
pipIndex: read("pipIndex"),
|
|
819
825
|
customPipUrl: read("customPipUrl"),
|
|
820
826
|
gitProxyUrl: read("gitProxyUrl"),
|
|
821
|
-
pipProxyUrl: read("pipProxyUrl")
|
|
827
|
+
pipProxyUrl: read("pipProxyUrl"),
|
|
828
|
+
cifarProxyUrl: read("cifarProxyUrl")
|
|
822
829
|
});
|
|
823
830
|
}
|
|
824
831
|
/** Apply a new configuration document. */
|
|
@@ -1681,6 +1688,22 @@ const TASKS = [
|
|
|
1681
1688
|
timeLimitMinutes: 1440,
|
|
1682
1689
|
timeLimitEnabled: false,
|
|
1683
1690
|
needsSetup: true
|
|
1691
|
+
},
|
|
1692
|
+
{
|
|
1693
|
+
id: NEURAL_FP32_TASK,
|
|
1694
|
+
label: NEURAL_FP32_TASK_LABEL,
|
|
1695
|
+
description: "从零实现纯 C++ FP32 神经网络算子、反向传播与优化器 CLI;逐操作统计误差和速度。",
|
|
1696
|
+
timeLimitMinutes: 1440,
|
|
1697
|
+
timeLimitEnabled: false,
|
|
1698
|
+
needsSetup: true
|
|
1699
|
+
},
|
|
1700
|
+
{
|
|
1701
|
+
id: NEURAL_CIFAR_TASK,
|
|
1702
|
+
label: NEURAL_CIFAR_TASK_LABEL,
|
|
1703
|
+
description: "从零实现纯 C++ 训练框架,构造并训练 CIFAR-10 图像分类网络;保留算子指标并统计验证集准确率与多线程推理性能。",
|
|
1704
|
+
timeLimitMinutes: 1440,
|
|
1705
|
+
timeLimitEnabled: false,
|
|
1706
|
+
needsSetup: true
|
|
1684
1707
|
}
|
|
1685
1708
|
];
|
|
1686
1709
|
/** The tank task definition (original prompt; only halftime mechanics removed). */
|
|
@@ -1925,6 +1948,66 @@ const NEURAL_CPP_DEFINITION = {
|
|
|
1925
1948
|
].join("\n");
|
|
1926
1949
|
}
|
|
1927
1950
|
};
|
|
1951
|
+
/** FP32 operator/performance task. */
|
|
1952
|
+
const NEURAL_FP32_DEFINITION = {
|
|
1953
|
+
id: NEURAL_FP32_TASK,
|
|
1954
|
+
label: NEURAL_FP32_TASK_LABEL,
|
|
1955
|
+
description: TASKS[9].description,
|
|
1956
|
+
asset: path.join(packageRoot(), "assets", "neural-fp32", "workspace.zip"),
|
|
1957
|
+
timeLimitMinutes: 1440,
|
|
1958
|
+
timeLimitEnabled: false,
|
|
1959
|
+
needsSetup: true,
|
|
1960
|
+
prompt() {
|
|
1961
|
+
return [
|
|
1962
|
+
"这是一个从零实现的纯 C++ FP32 神经网络算子与性能任务:实现 forward、反向传播、损失和优化器更新,并提供一个固定 CLI 供评测调用;不提供 Python 或 OpenCL 支持。",
|
|
1963
|
+
"",
|
|
1964
|
+
"当前 workspace 已经由安装器准备好:包含 TASK.md 和 CMakeLists.txt。请阅读 TASK.md 的 CLI 协议,实现 src/ 下的程序,构建出 build/nn_task。",
|
|
1965
|
+
"",
|
|
1966
|
+
"要求:",
|
|
1967
|
+
"- 仅使用 Linux + GCC + C++17 标准库;不允许引入第三方依赖;",
|
|
1968
|
+
"- 所有输入输出均为 little-endian float32;",
|
|
1969
|
+
"- 开发/自测阶段线程数最多 4;评测阶段会使用全部逻辑 CPU;",
|
|
1970
|
+
"- 数值参考由评测侧 PyTorch 在相同数据上计算,不要伪造结果;",
|
|
1971
|
+
"- 评测会独立统计每个操作的可执行性、加权平均相对误差和速度;",
|
|
1972
|
+
"- 完成后用几句话总结实现了哪些操作和性能优化。"
|
|
1973
|
+
].join("\n");
|
|
1974
|
+
}
|
|
1975
|
+
};
|
|
1976
|
+
/** CIFAR-10 training task. */
|
|
1977
|
+
const NEURAL_CIFAR_DEFINITION = {
|
|
1978
|
+
id: NEURAL_CIFAR_TASK,
|
|
1979
|
+
label: NEURAL_CIFAR_TASK_LABEL,
|
|
1980
|
+
description: TASKS[10].description,
|
|
1981
|
+
asset: path.join(packageRoot(), "assets", "neural-cifar", "workspace.zip"),
|
|
1982
|
+
timeLimitMinutes: 1440,
|
|
1983
|
+
timeLimitEnabled: false,
|
|
1984
|
+
needsSetup: true,
|
|
1985
|
+
prompt() {
|
|
1986
|
+
return [
|
|
1987
|
+
"你是一名世界顶尖的神经网络全栈设计与优化工程师,也是一名以“榨干每一分合法算力”为信条的竞赛选手。任务:从零实现纯 C++17、仅 CPU 的 FP32 训练框架(算子、反向、优化器、固定 CLI),并用同一框架训练 CIFAR-10 图像分类网络。评测会分别报告隐藏验证集准确率、推理性能、以及保留的算子正确性/误差/速度;不提供统一总分,各项权重未知——因此不要把任何一项做成短板。",
|
|
1988
|
+
"",
|
|
1989
|
+
"请先完整阅读 TASK.md 与 CLI 协议,它是权威规则;在规则模糊处按本提示的保守口径执行,并把理解写入 NOTES.md。硬约束:仅 Linux + GCC + C++17 标准库,固定 fp32,无 Python/OpenCL/CUDA/BLAS/Eigen/第三方库;必须产出 build/nn_task、build/train、build/infer 并留下可加载的 model/;工作区提供 50k train split,评测使用独立隐藏验证集。线程:由你发起的所有运行(开发、自测、算子基准、训练)一律最多 4 个 worker;`infer --threads N` 必须能正确处理不同线程数,但本地自测固定 4;把分块/归约逻辑与线程数解耦,用纯函数单元测试覆盖不同分块的正确性。算子速度不是准确率的竞争者而是共同乘数:更快的 matmul/conv 意味着同样时间能跑更多 epoch,也直接抬高推理 FPS;但任何速度优化都不能牺牲正确性。",
|
|
1990
|
+
"",
|
|
1991
|
+
"你只需要把全部精力放在把结果做到最好:穷尽优化、持续实验、自我批判。评测由独立数据和外部约束执行,不要让对边界的担心分散注意力;把能复现的结果、命令和文件留在工作区即可。",
|
|
1992
|
+
"",
|
|
1993
|
+
"工作方式:",
|
|
1994
|
+
"0) 先必要算子 + 便宜完整基线:尽快实现让 CIFAR 训练跑通所需的最小算子/反向/优化器/线程池与三个 CLI,短训出 model/,端到端跑通 train→infer,拿到第一个本地 holdout 准确率与单图耗时。先保证可交付,再谈优化。",
|
|
1995
|
+
"1) 补全算子正确性(昂贵搜索前必须过门):用独立 double 标量参考、有限差分梯度检查,以及边界形状/广播/分组/步长/空洞/非方形核/softmax 数值稳定/AdamW step 偏置/N=1/H/W<kernel/fp32 写出等用例,逐算子记录误差到 NOTES.md;每次改 conv/matmul/线程池后重测受影响算子与端到端推理。",
|
|
1996
|
+
"2) 持续探索:不断提出实质性不同的架构/训练假设并做可比较的 pilot,一次只改一个主变量;固定可复现的分层 holdout(种子写死),holdout 仅用于评估,不参与训练、增强或归一化统计;把假设、唯一改动、命令、种子、划分、准确率、耗时、算子指标、结论记入 RESULTS.md 排名表。候选扩大训练前先看 pilot 信号;胜出方向继续做单变量消融,最终选择尽量在另一个独立划分/种子上复核。时间无限,持续寻找更高价值的方向;不要跑一个配置就收。",
|
|
1997
|
+
"3) 深挖:学习率/调度/weight decay/增强/标签平滑/EMA/网络结构/推理优化(BN 融合、卷积实现、多线程分块、内存复用);TTA 与集成只在实测准确率收益值得其 FPS 代价时采用;使用 BatchNorm 必须把 running mean/var 固化进 model/ 并在 infer 使用。任何提升若接近噪声,都要结合 5k holdout 抽样误差、随机种子波动和独立复核划分综合判断,不能当成硬阈值;给出准确率-速度 Pareto 权衡再选配置。",
|
|
1998
|
+
"4) 锁定与重训:冻结配置后用全部 50k 重训最终权重(自测 holdout 回归训练集);反复在同一 holdout 上挑选会产生选择性偏差,报告保守期望而非最好一次;CIFAR-10 测试集约 3.3% 与训练集近重复,自测可能偏乐观,按保守口径。长训练必须 checkpoint + resume。",
|
|
1999
|
+
"5) 交付审计:清空/新建 build 目录后 cmake -S . -B build -DCMAKE_BUILD_TYPE=Release && cmake --build build -j4,确认三个二进制从零构建;跑自己的全操作自测(覆盖协议与边界);用真实图像字节跑 infer(4 线程),核对输出为 N 个 uint8;确认无 NaN/崩溃、无绝对路径、不依赖开发进程或临时构建产物。保留已验证的最佳模型,退步立即回退。",
|
|
2000
|
+
"",
|
|
2001
|
+
"时间无限,持续优化,不要因为基线跑通就结束;始终保证工作区处于可评测状态:三个 CLI 可构建、model/ 可加载、退步可回滚。能跑通或超过朴素基线不代表够强,正式对手远强于此。",
|
|
2002
|
+
"",
|
|
2003
|
+
"自我批判:假设自测数字被高估了 0.5%,找出高估来源(holdout 被反复选择、增强/统计泄漏、数据顺序、随机性、口径不一致、单次运气),用不同种子/划分/更严口径复核;主动红队实现(极端与边界形状、大/小数值、eps/溢出、groups/dilation/stride 组合、线程数与确定性、长训练内存与数值稳定性)。",
|
|
2004
|
+
"",
|
|
2005
|
+
"诚实汇报:完成后给出网络结构与训练方法、自测划分与实测结果、推理 FPS 与单图耗时、算子自测结果与已知风险、留下的命令与文件清单。所有数字必须能由留下的命令复现。",
|
|
2006
|
+
"",
|
|
2007
|
+
"不要向我提问,也不要等待确认,独立完成。"
|
|
2008
|
+
].join("\n");
|
|
2009
|
+
}
|
|
2010
|
+
};
|
|
1928
2011
|
/** All task definitions keyed by id. */
|
|
1929
2012
|
const TASK_DEFINITIONS = {
|
|
1930
2013
|
[TANK_TASK]: TANK_DEFINITION,
|
|
@@ -1935,7 +2018,9 @@ const TASK_DEFINITIONS = {
|
|
|
1935
2018
|
[COMMIT0_TASK]: COMMIT0_DEFINITION,
|
|
1936
2019
|
[SWE_BENCH_PRO_TASK]: SWE_BENCH_PRO_DEFINITION,
|
|
1937
2020
|
[FEATUREBENCH_TASK]: FEATUREBENCH_DEFINITION,
|
|
1938
|
-
[NEURAL_CPP_TASK]: NEURAL_CPP_DEFINITION
|
|
2021
|
+
[NEURAL_CPP_TASK]: NEURAL_CPP_DEFINITION,
|
|
2022
|
+
[NEURAL_FP32_TASK]: NEURAL_FP32_DEFINITION,
|
|
2023
|
+
[NEURAL_CIFAR_TASK]: NEURAL_CIFAR_DEFINITION
|
|
1939
2024
|
};
|
|
1940
2025
|
var TaskService = class {
|
|
1941
2026
|
guard;
|
|
@@ -2040,7 +2125,8 @@ var TaskService = class {
|
|
|
2040
2125
|
".repo",
|
|
2041
2126
|
"setup.sh",
|
|
2042
2127
|
"remove.patch",
|
|
2043
|
-
"spec.pdf.bz2"
|
|
2128
|
+
"spec.pdf.bz2",
|
|
2129
|
+
"cifar_cache.py"
|
|
2044
2130
|
]) try {
|
|
2045
2131
|
fs.rmSync(path.join(workspacePath, name), {
|
|
2046
2132
|
recursive: true,
|
|
@@ -2082,7 +2168,8 @@ var TaskService = class {
|
|
|
2082
2168
|
EVAL_PIP_INDEX_URL: this.pipIndexUrl(options),
|
|
2083
2169
|
GIT_TERMINAL_PROMPT: "0",
|
|
2084
2170
|
EVAL_GIT_PROXY: this.proxyValue(options.gitProxyUrl),
|
|
2085
|
-
EVAL_PIP_PROXY: this.proxyValue(options.pipProxyUrl)
|
|
2171
|
+
EVAL_PIP_PROXY: this.proxyValue(options.pipProxyUrl),
|
|
2172
|
+
EVAL_CIFAR_PROXY: this.proxyValue(options.cifarProxyUrl)
|
|
2086
2173
|
};
|
|
2087
2174
|
const command = definition.needsSetup ? ["bash", "setup.sh"] : [
|
|
2088
2175
|
"bash",
|
|
@@ -2157,7 +2244,8 @@ var TaskService = class {
|
|
|
2157
2244
|
cwd: packageRoot(),
|
|
2158
2245
|
env: {
|
|
2159
2246
|
PYTHONPATH: "",
|
|
2160
|
-
PYTHONHOME: ""
|
|
2247
|
+
PYTHONHOME: "",
|
|
2248
|
+
EVAL_CIFAR_PROXY: this.proxyValue(this.guard.configuration.cifarProxyUrl)
|
|
2161
2249
|
}
|
|
2162
2250
|
}).id
|
|
2163
2251
|
};
|
|
@@ -2359,7 +2447,8 @@ function registerRoutes(ctx, guard, tasks) {
|
|
|
2359
2447
|
pipIndex: typeof body.pipIndex === "string" ? body.pipIndex : config.pipIndex,
|
|
2360
2448
|
customPipUrl: typeof body.customPipUrl === "string" ? body.customPipUrl : config.customPipUrl,
|
|
2361
2449
|
gitProxyUrl: typeof body.gitProxyUrl === "string" ? body.gitProxyUrl : config.gitProxyUrl,
|
|
2362
|
-
pipProxyUrl: typeof body.pipProxyUrl === "string" ? body.pipProxyUrl : config.pipProxyUrl
|
|
2450
|
+
pipProxyUrl: typeof body.pipProxyUrl === "string" ? body.pipProxyUrl : config.pipProxyUrl,
|
|
2451
|
+
cifarProxyUrl: typeof body.cifarProxyUrl === "string" ? body.cifarProxyUrl : config.cifarProxyUrl
|
|
2363
2452
|
}));
|
|
2364
2453
|
}
|
|
2365
2454
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-eval-guard",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Evaluation guard for DSH: workspace-only filesystem, no network/subagents, wall-clock limits, and task installation for the meow-ai-arena tank task.",
|
|
6
6
|
"license": "MIT",
|