dsh-eval-guard 0.6.0 → 0.6.1

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 CHANGED
@@ -44,7 +44,9 @@ Neural-FP32 是独立的新任务:固定 fp32,不做完整训练;agent 从
44
44
 
45
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
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 脚本。
47
+ CIFAR-10 下载缓存固定在用户 home 下:`~/.dsh/eval-guard/cache/cifar10/`,保存 train/val 的 images/labels。下载使用 `~/.dsh/eval-guard/cache/cifar10/.download.lock` 独占锁,并实时打印进度;锁存在时认为其他 DSH 实例正在下载,任务安装/评测会提示等待或手动删除锁文件。缓存完整且无锁时直接复用。设置页新增「CIFAR download mirror」和「CIFAR download proxy」输入框:mirror 可选 Toronto 官方、Toronto Cave 或自定义 tar.gz URL,proxy 只用于 CIFAR 下载。按任务安装和评测时分别传给 setup/fetch 脚本。
48
+
49
+ 所有任务的后台安装被取消或失败时,会删除本次安装已搬入工作区的文件,并清空工作区。清理只会在安装开始前工作区确实为空时执行,原工作区有内容时绝不触发。Neural-CIFAR 还会删除本次安装拥有的 CIFAR 下载锁,但不会删除其他 DSH 实例的锁。
48
50
 
49
51
  评测时在临时目录独立构建,然后从 assets/neural-cpp/hidden/ 注入 C++ 测试源码;测试数据由固定种子在进程内生成,不依赖或复制外部数据文件。
50
52
 
Binary file
@@ -23,6 +23,15 @@ window.__ModuleLoader__.load({
23
23
  const JOB_CANCEL_ROUTE = "/api/eval-guard/job/cancel";
24
24
  const EVAL_ROUTE = "/api/eval-guard/evaluate";
25
25
  /** Common pip indexes offered by the settings page. */
26
+ const CIFAR_MIRRORS = [{
27
+ id: "toronto",
28
+ label: "Toronto 官方",
29
+ url: "https://www.cs.toronto.edu/~kriz/cifar-10-binary.tar.gz"
30
+ }, {
31
+ id: "cave",
32
+ label: "Toronto Cave",
33
+ url: "https://cave.cs.toronto.edu/kriz/cifar-10-binary.tar.gz"
34
+ }];
26
35
  const PIP_MIRRORS = [
27
36
  {
28
37
  id: "pypi",
@@ -83,7 +92,9 @@ window.__ModuleLoader__.load({
83
92
  customPipUrl: "",
84
93
  gitProxyUrl: "",
85
94
  pipProxyUrl: "",
86
- cifarProxyUrl: ""
95
+ cifarProxyUrl: "",
96
+ cifarMirror: "toronto",
97
+ customCifarUrl: ""
87
98
  };
88
99
  const box = {
89
100
  border: "1px solid var(--vscode-panel-border, #3c3c3c)",
@@ -146,7 +157,9 @@ window.__ModuleLoader__.load({
146
157
  customPipUrl: typeof value?.customPipUrl === "string" ? value.customPipUrl : "",
147
158
  gitProxyUrl: typeof value?.gitProxyUrl === "string" ? value.gitProxyUrl : "",
148
159
  pipProxyUrl: typeof value?.pipProxyUrl === "string" ? value.pipProxyUrl : "",
149
- cifarProxyUrl: typeof value?.cifarProxyUrl === "string" ? value.cifarProxyUrl : ""
160
+ cifarProxyUrl: typeof value?.cifarProxyUrl === "string" ? value.cifarProxyUrl : "",
161
+ cifarMirror: typeof value?.cifarMirror === "string" && value.cifarMirror !== "" ? value.cifarMirror : "toronto",
162
+ customCifarUrl: typeof value?.customCifarUrl === "string" ? value.customCifarUrl : ""
150
163
  };
151
164
  }
152
165
  /** The settings card. */
@@ -340,7 +353,9 @@ window.__ModuleLoader__.load({
340
353
  customPipUrl: draft.customPipUrl,
341
354
  gitProxyUrl: draft.gitProxyUrl,
342
355
  pipProxyUrl: draft.pipProxyUrl,
343
- cifarProxyUrl: draft.cifarProxyUrl
356
+ cifarProxyUrl: draft.cifarProxyUrl,
357
+ cifarMirror: draft.cifarMirror,
358
+ customCifarUrl: draft.customCifarUrl
344
359
  })
345
360
  }).then(readJson);
346
361
  if (!result.ok || result.jobId === void 0) {
@@ -617,6 +632,32 @@ window.__ModuleLoader__.load({
617
632
  placeholder: "127.0.0.1:7897"
618
633
  })]
619
634
  }),
635
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
636
+ style: row,
637
+ children: [
638
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [t("settings.cifarMirror"), ":"] }),
639
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
640
+ value: draft.cifarMirror,
641
+ disabled: !ready,
642
+ onChange: (event) => void save({ cifarMirror: event.target.value }),
643
+ children: [CIFAR_MIRRORS.map((mirror) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
644
+ value: mirror.id,
645
+ children: mirror.label
646
+ }, mirror.id)), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
647
+ value: "custom",
648
+ children: t("settings.custom")
649
+ })]
650
+ }),
651
+ draft.cifarMirror === "custom" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
652
+ style: { width: 320 },
653
+ disabled: !ready,
654
+ value: draft.customCifarUrl,
655
+ onChange: (event) => edit({ customCifarUrl: event.target.value }),
656
+ onBlur: () => void save({ customCifarUrl: draft.customCifarUrl }),
657
+ placeholder: "https://.../cifar-10-binary.tar.gz"
658
+ })
659
+ ]
660
+ }),
620
661
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
621
662
  style: row,
622
663
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [t("settings.cifarProxy"), ":"] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
@@ -744,7 +785,7 @@ window.__ModuleLoader__.load({
744
785
  maxHeight: 260,
745
786
  overflow: "auto"
746
787
  },
747
- children: job.log || t("settings.waiting")
788
+ children: job.log || (job.status === "running" || job.status === "queued" ? t("settings.waiting") : "")
748
789
  }),
749
790
  job.result !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", {
750
791
  style: {
@@ -1052,6 +1093,7 @@ window.__ModuleLoader__.load({
1052
1093
  "settings.gitProxy": "Git proxy",
1053
1094
  "settings.pipProxy": "pip proxy",
1054
1095
  "settings.cifarProxy": "CIFAR download proxy",
1096
+ "settings.cifarMirror": "CIFAR download mirror",
1055
1097
  "settings.loading": "Loading…",
1056
1098
  "settings.recent": "Recent events",
1057
1099
  "settings.none": "None.",
@@ -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++ 张量后端'\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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"}
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 CIFAR_MIRRORS: readonly { id: string; label: string; url: string }[] = [\n { id: 'toronto', label: 'Toronto 官方', url: 'https://www.cs.toronto.edu/~kriz/cifar-10-binary.tar.gz' },\n { id: 'cave', label: 'Toronto Cave', url: 'https://cave.cs.toronto.edu/kriz/cifar-10-binary.tar.gz' },\n]\n\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, CIFAR_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 cifarMirror: string\n customCifarUrl: 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 cifarMirror: 'toronto',\n customCifarUrl: '',\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 cifarMirror: typeof value?.cifarMirror === 'string' && value.cifarMirror !== '' ? value.cifarMirror : 'toronto',\n customCifarUrl: typeof value?.customCifarUrl === 'string' ? value.customCifarUrl : '',\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, cifarMirror: draft.cifarMirror, customCifarUrl: draft.customCifarUrl }),\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.cifarMirror')}:</span>\n <select value={draft.cifarMirror} disabled={!ready} onChange={event => void save({ cifarMirror: event.target.value })}>\n {CIFAR_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.cifarMirror === 'custom' && <input style={{ width: 320 }} disabled={!ready} value={draft.customCifarUrl}\n onChange={event => edit({ customCifarUrl: event.target.value })} onBlur={() => void save({ customCifarUrl: draft.customCifarUrl })} placeholder=\"https://.../cifar-10-binary.tar.gz\" />}\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 || (job.status === 'running' || job.status === 'queued' ? 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.cifarMirror': 'CIFAR download mirror',\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
@@ -25,7 +25,9 @@ const Config = z.object({
25
25
  customPipUrl: z.string().default("").volatile(),
26
26
  gitProxyUrl: z.string().default("").volatile(),
27
27
  pipProxyUrl: z.string().default("").volatile(),
28
- cifarProxyUrl: z.string().default("").volatile()
28
+ cifarProxyUrl: z.string().default("").volatile(),
29
+ cifarMirror: z.string().default("toronto").volatile(),
30
+ customCifarUrl: z.string().default("").volatile()
29
31
  });
30
32
  /** Clamp and normalize a live configuration object. */
31
33
  function resolveConfig(value) {
@@ -43,7 +45,9 @@ function resolveConfig(value) {
43
45
  customPipUrl: typeof value?.customPipUrl === "string" ? value.customPipUrl : "",
44
46
  gitProxyUrl: typeof value?.gitProxyUrl === "string" ? value.gitProxyUrl : "",
45
47
  pipProxyUrl: typeof value?.pipProxyUrl === "string" ? value.pipProxyUrl : "",
46
- cifarProxyUrl: typeof value?.cifarProxyUrl === "string" ? value.cifarProxyUrl : ""
48
+ cifarProxyUrl: typeof value?.cifarProxyUrl === "string" ? value.cifarProxyUrl : "",
49
+ cifarMirror: typeof value?.cifarMirror === "string" && value.cifarMirror !== "" ? value.cifarMirror : "toronto",
50
+ customCifarUrl: typeof value?.customCifarUrl === "string" ? value.customCifarUrl : ""
47
51
  };
48
52
  }
49
53
  //#endregion
@@ -83,6 +87,15 @@ const NEURAL_FP32_TASK_LABEL = "Neural-FP32 · 运算与性能";
83
87
  const NEURAL_CIFAR_TASK = "neural-cifar";
84
88
  const NEURAL_CIFAR_TASK_LABEL = "Neural-CIFAR · 从零训练图像分类";
85
89
  /** Common pip indexes offered by the settings page. */
90
+ const CIFAR_MIRRORS = [{
91
+ id: "toronto",
92
+ label: "Toronto 官方",
93
+ url: "https://www.cs.toronto.edu/~kriz/cifar-10-binary.tar.gz"
94
+ }, {
95
+ id: "cave",
96
+ label: "Toronto Cave",
97
+ url: "https://cave.cs.toronto.edu/kriz/cifar-10-binary.tar.gz"
98
+ }];
86
99
  const PIP_MIRRORS = [
87
100
  {
88
101
  id: "pypi",
@@ -825,7 +838,9 @@ var Guard = class {
825
838
  customPipUrl: read("customPipUrl"),
826
839
  gitProxyUrl: read("gitProxyUrl"),
827
840
  pipProxyUrl: read("pipProxyUrl"),
828
- cifarProxyUrl: read("cifarProxyUrl")
841
+ cifarProxyUrl: read("cifarProxyUrl"),
842
+ cifarMirror: read("cifarMirror"),
843
+ customCifarUrl: read("customCifarUrl")
829
844
  });
830
845
  }
831
846
  /** Apply a new configuration document. */
@@ -1390,6 +1405,7 @@ var JobManager = class {
1390
1405
  root;
1391
1406
  jobs = /* @__PURE__ */ new Map();
1392
1407
  children = /* @__PURE__ */ new Map();
1408
+ cancelHandlers = /* @__PURE__ */ new Map();
1393
1409
  constructor() {
1394
1410
  this.root = path.join(guardRoot(), "jobs");
1395
1411
  fs.mkdirSync(this.root, { recursive: true });
@@ -1466,6 +1482,7 @@ var JobManager = class {
1466
1482
  return this.info(job);
1467
1483
  }
1468
1484
  this.children.set(jobId, child);
1485
+ if (options.onCancel !== void 0) this.cancelHandlers.set(jobId, options.onCancel);
1469
1486
  const append = (chunk) => {
1470
1487
  try {
1471
1488
  fs.appendFileSync(logFile, chunk);
@@ -1482,6 +1499,7 @@ var JobManager = class {
1482
1499
  });
1483
1500
  child.on("exit", (code, signal) => {
1484
1501
  this.children.delete(jobId);
1502
+ this.cancelHandlers.delete(jobId);
1485
1503
  if (job.status === "cancelled") return;
1486
1504
  if (code === 0) try {
1487
1505
  const extra = options.onSuccess?.(this.detail(jobId));
@@ -1500,10 +1518,16 @@ var JobManager = class {
1500
1518
  } catch (error) {
1501
1519
  job.status = "failed";
1502
1520
  job.error = error instanceof Error ? error.message : String(error);
1521
+ try {
1522
+ options.onFailure?.(this.detail(jobId));
1523
+ } catch {}
1503
1524
  }
1504
1525
  else {
1505
1526
  job.status = "failed";
1506
1527
  job.error = signal !== null ? "进程被信号 " + signal + " 终止" : "退出码 " + String(code);
1528
+ try {
1529
+ options.onFailure?.(this.detail(jobId));
1530
+ } catch {}
1507
1531
  }
1508
1532
  job.endedAt = now();
1509
1533
  job.updatedAt = now();
@@ -1522,13 +1546,37 @@ var JobManager = class {
1522
1546
  job.error = "用户取消";
1523
1547
  this.write(job);
1524
1548
  const child = this.children.get(jobId);
1525
- if (child?.pid !== void 0) try {
1526
- process.kill(-child.pid, "SIGTERM");
1527
- } catch {
1528
- try {
1529
- child.kill("SIGTERM");
1549
+ const handler = this.cancelHandlers.get(jobId);
1550
+ this.cancelHandlers.delete(jobId);
1551
+ let cleaned = false;
1552
+ const cleanup = () => {
1553
+ if (cleaned) return;
1554
+ cleaned = true;
1555
+ if (handler !== void 0) try {
1556
+ handler(this.detail(jobId));
1530
1557
  } catch {}
1531
- }
1558
+ };
1559
+ if (child?.pid !== void 0) {
1560
+ child.once("exit", cleanup);
1561
+ try {
1562
+ process.kill(-child.pid, "SIGTERM");
1563
+ } catch {
1564
+ try {
1565
+ child.kill("SIGTERM");
1566
+ } catch {}
1567
+ }
1568
+ setTimeout(() => {
1569
+ if (cleaned) return;
1570
+ try {
1571
+ process.kill(-child.pid, "SIGKILL");
1572
+ } catch {
1573
+ try {
1574
+ child.kill("SIGKILL");
1575
+ } catch {}
1576
+ }
1577
+ cleanup();
1578
+ }, 2e3).unref?.();
1579
+ } else cleanup();
1532
1580
  return this.info(job);
1533
1581
  }
1534
1582
  /** Current state, including a bounded log tail and optional result. */
@@ -2046,6 +2094,12 @@ var TaskService = class {
2046
2094
  if (value === "") return "";
2047
2095
  return /^[a-z][a-z0-9+.-]*:\/\//i.test(value) ? value : "http://" + value;
2048
2096
  }
2097
+ /** The CIFAR-10 binary archive URL for the selected mirror. */
2098
+ cifarUrl(options) {
2099
+ const mirror = options.cifarMirror ?? "toronto";
2100
+ if (mirror === "custom") return (options.customCifarUrl ?? "").trim() || CIFAR_MIRRORS[0].url;
2101
+ return CIFAR_MIRRORS.find((item) => item.id === mirror)?.url ?? CIFAR_MIRRORS[0].url;
2102
+ }
2049
2103
  /** The pip index URL for a task, honouring the selected mirror. */
2050
2104
  pipIndexUrl(options) {
2051
2105
  const index = options.pipIndex ?? "pypi";
@@ -2134,6 +2188,23 @@ var TaskService = class {
2134
2188
  });
2135
2189
  } catch {}
2136
2190
  }
2191
+ /** Remove every entry created by an install that never reached success. */
2192
+ wipeInstallWorkspace(workspacePath) {
2193
+ try {
2194
+ for (const entry of fs.readdirSync(workspacePath)) fs.rmSync(path.join(workspacePath, entry), {
2195
+ recursive: true,
2196
+ force: true
2197
+ });
2198
+ } catch {}
2199
+ }
2200
+ /** Remove the shared CIFAR lock only when it belongs to this install. */
2201
+ cleanupCifarLock(token) {
2202
+ const lock = path.join(os.homedir(), ".dsh", "eval-guard", "cache", "cifar10", ".download.lock");
2203
+ try {
2204
+ if (!fs.existsSync(lock)) return;
2205
+ if (fs.readFileSync(lock, "utf8").includes("token=" + token)) fs.rmSync(lock, { force: true });
2206
+ } catch {}
2207
+ }
2137
2208
  /** Start a non-blocking install. The settings page polls the returned job. */
2138
2209
  startInstall(workspaceId, taskId, options = {}) {
2139
2210
  const definition = TASK_DEFINITIONS[taskId];
@@ -2154,61 +2225,75 @@ var TaskService = class {
2154
2225
  ok: false,
2155
2226
  error: "请先启用评测守护,再安装评测任务。"
2156
2227
  };
2228
+ const initiallyEmpty = checked.empty;
2229
+ const installToken = "install-" + Date.now().toString(36) + "-" + Math.random().toString(36).slice(2, 10);
2230
+ const cleanupInstall = () => {
2231
+ if (!initiallyEmpty) return;
2232
+ this.wipeInstallWorkspace(checked.path);
2233
+ this.cleanupCifarLock(installToken);
2234
+ };
2157
2235
  try {
2158
2236
  fs.copyFileSync(this.materialZip(taskId), path.join(checked.path, "workspace.zip"));
2159
2237
  if (definition.needsSetup) this.extractMaterial(checked.path);
2160
2238
  } catch (error) {
2239
+ cleanupInstall();
2161
2240
  return {
2162
2241
  ok: false,
2163
2242
  error: "复制素材失败:" + (error instanceof Error ? error.message : String(error))
2164
2243
  };
2165
2244
  }
2166
2245
  const env = {
2246
+ EVAL_INSTALL_TOKEN: installToken,
2167
2247
  EVAL_CLONE_URL: this.cloneUrl(definition, options),
2168
2248
  EVAL_PIP_INDEX_URL: this.pipIndexUrl(options),
2169
2249
  GIT_TERMINAL_PROMPT: "0",
2170
2250
  EVAL_GIT_PROXY: this.proxyValue(options.gitProxyUrl),
2171
2251
  EVAL_PIP_PROXY: this.proxyValue(options.pipProxyUrl),
2172
- EVAL_CIFAR_PROXY: this.proxyValue(options.cifarProxyUrl)
2252
+ EVAL_CIFAR_PROXY: this.proxyValue(options.cifarProxyUrl),
2253
+ EVAL_CIFAR_URL: this.cifarUrl(options)
2173
2254
  };
2174
2255
  const command = definition.needsSetup ? ["bash", "setup.sh"] : [
2175
2256
  "bash",
2176
2257
  "-c",
2177
2258
  "true"
2178
2259
  ];
2260
+ const job = this.jobs.start({
2261
+ kind: "install",
2262
+ task: taskId,
2263
+ workspaceId,
2264
+ command,
2265
+ cwd: checked.path,
2266
+ env,
2267
+ onCancel: cleanupInstall,
2268
+ onFailure: cleanupInstall,
2269
+ onSuccess: () => {
2270
+ if (definition.needsSetup) this.cleanupWorkspace(checked.path);
2271
+ const runId = this.newRunId();
2272
+ const prompt = this.guard.promptFor(checked.path, this.materialZip(taskId), definition);
2273
+ const run = {
2274
+ runId,
2275
+ task: definition.id,
2276
+ workspaceId,
2277
+ workspacePath: checked.path,
2278
+ sessionId: null,
2279
+ createdAt: Date.now(),
2280
+ startedAt: null,
2281
+ endedAt: null,
2282
+ status: "prepared",
2283
+ prompt,
2284
+ timeLimitMinutes: this.guard.configuration.timeLimitMinutes
2285
+ };
2286
+ this.guard.registerRun(run);
2287
+ return {
2288
+ runId,
2289
+ prompt
2290
+ };
2291
+ }
2292
+ });
2293
+ if (job.status === "failed") cleanupInstall();
2179
2294
  return {
2180
2295
  ok: true,
2181
- jobId: this.jobs.start({
2182
- kind: "install",
2183
- task: taskId,
2184
- workspaceId,
2185
- command,
2186
- cwd: checked.path,
2187
- env,
2188
- onSuccess: () => {
2189
- if (definition.needsSetup) this.cleanupWorkspace(checked.path);
2190
- const runId = this.newRunId();
2191
- const prompt = this.guard.promptFor(checked.path, this.materialZip(taskId), definition);
2192
- const run = {
2193
- runId,
2194
- task: definition.id,
2195
- workspaceId,
2196
- workspacePath: checked.path,
2197
- sessionId: null,
2198
- createdAt: Date.now(),
2199
- startedAt: null,
2200
- endedAt: null,
2201
- status: "prepared",
2202
- prompt,
2203
- timeLimitMinutes: this.guard.configuration.timeLimitMinutes
2204
- };
2205
- this.guard.registerRun(run);
2206
- return {
2207
- runId,
2208
- prompt
2209
- };
2210
- }
2211
- }).id
2296
+ jobId: job.id
2212
2297
  };
2213
2298
  }
2214
2299
  /** Start a single-workspace evaluation job. */
@@ -2245,7 +2330,8 @@ var TaskService = class {
2245
2330
  env: {
2246
2331
  PYTHONPATH: "",
2247
2332
  PYTHONHOME: "",
2248
- EVAL_CIFAR_PROXY: this.proxyValue(this.guard.configuration.cifarProxyUrl)
2333
+ EVAL_CIFAR_PROXY: this.proxyValue(this.guard.configuration.cifarProxyUrl),
2334
+ EVAL_CIFAR_URL: this.cifarUrl(this.guard.configuration)
2249
2335
  }
2250
2336
  }).id
2251
2337
  };
@@ -2300,6 +2386,7 @@ var TaskService = class {
2300
2386
  if (definition.prepare !== void 0) definition.prepare(checked.path);
2301
2387
  if (definition.needsSetup) this.cleanupWorkspace(checked.path);
2302
2388
  } catch (error) {
2389
+ if (checked.empty) this.wipeInstallWorkspace(checked.path);
2303
2390
  return {
2304
2391
  ok: false,
2305
2392
  workspaceId,
@@ -2448,7 +2535,9 @@ function registerRoutes(ctx, guard, tasks) {
2448
2535
  customPipUrl: typeof body.customPipUrl === "string" ? body.customPipUrl : config.customPipUrl,
2449
2536
  gitProxyUrl: typeof body.gitProxyUrl === "string" ? body.gitProxyUrl : config.gitProxyUrl,
2450
2537
  pipProxyUrl: typeof body.pipProxyUrl === "string" ? body.pipProxyUrl : config.pipProxyUrl,
2451
- cifarProxyUrl: typeof body.cifarProxyUrl === "string" ? body.cifarProxyUrl : config.cifarProxyUrl
2538
+ cifarProxyUrl: typeof body.cifarProxyUrl === "string" ? body.cifarProxyUrl : config.cifarProxyUrl,
2539
+ cifarMirror: typeof body.cifarMirror === "string" ? body.cifarMirror : config.cifarMirror,
2540
+ customCifarUrl: typeof body.customCifarUrl === "string" ? body.customCifarUrl : config.customCifarUrl
2452
2541
  }));
2453
2542
  }
2454
2543
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-eval-guard",
3
- "version": "0.6.0",
3
+ "version": "0.6.1",
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",