dsh-eval-pack 0.1.0-alpha.10 → 0.1.0-alpha.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Changelog
2
2
 
3
- ## [0.1.0-alpha.10] — 2026-11-01
3
+ ## [0.1.0-alpha.12] — 2026-11-01
4
4
 
5
5
  ### Security / Fixes
6
6
 
package/README-zh.md CHANGED
@@ -37,6 +37,81 @@ dsh plugin --profile <profile> add dsh-eval-pack
37
37
 
38
38
  *本地真实测试运行;不调用模型或网络。*
39
39
 
40
+ ## 一句话
41
+
42
+ 把一小包评测样本逐条按 JSON 精确比对,给出通过率、失败项和 pass@k。
43
+
44
+ ## 适合 / 不适合
45
+
46
+ - **适合**:想复核一个小评测包(3–50 个样本)的通过率,需要确定性的 JSON 相等评分、不接受模糊匹配的场景。
47
+ - **不适合**:需要调用模型、主观打分或跑真实 benchmark 的场景;本包只做评分与汇总,不运行被测对象。
48
+
49
+ ## 输入
50
+
51
+ - `pack.json`:`name`、`version` 与 `tasks`(任务 id 列表)。
52
+ - 每个样本一个 JSON:`id`、`prompt`、`expected`;评分只看 `expected` 与运行结果里的 `actual`。
53
+ - `run.json`:一次运行的结果 `results[].actual`,以及 pass@k 用的 `sampling[]`(`samples` / `correct`)。
54
+ - 自带样例在 `samples/quickstart/input/`:3 个样本 JSON + 1 个 run 结果,合计远小于 500 KB。
55
+ - 工具不设硬性大小上限;单个 JSON 建议 ≤1 MB,样例只是最小可复现集。
56
+
57
+ ## 输出
58
+
59
+ - 终端摘要:lint 是否通过、逐条 pass/fail、通过率与失败 id、pass@1 与 pass@3。
60
+ - 不写任何文件;需要留档时把 `--json` 的输出重定向到自己的文件即可。
61
+ - 评分规则:对象键顺序不影响结果,数组顺序会影响结果,数字必须完全相等。
62
+
63
+ ## 示例
64
+
65
+ 直接复制这句话:
66
+
67
+ > 我用自带样例跑一次评测:3 个样本里过了几个、哪个没过、pass@3 是多少?
68
+
69
+ 也可以自己跑(真实运行,截图即来自这条命令):
70
+
71
+ ```sh
72
+ node samples/quickstart/run.mjs
73
+ ```
74
+
75
+ ![dsh-eval-pack quickstart 真实运行输出](docs/assets/quickstart.png)
76
+
77
+ *合成评测包 → 金标 `samples/quickstart/expected/result.json`;命令与哈希见 `screenshots.json`。*
78
+
79
+ ## 权限
80
+
81
+ - 读:你指定的评测包 JSON、样本 JSON 与运行结果 JSON(由会话读取后作为参数传入);不读其他目录
82
+ - 写:无(四个工具全部只读,不写任何文件)
83
+ - 联网:否(源码中没有 HTTP / DNS / WebSocket 调用)
84
+ - 外部系统:无(不调用模型、不连接评测平台、不上传数据)
85
+
86
+ 四个工具全部标 **R0(只读)**;逐项见下方工具表。
87
+
88
+ ## FAQ
89
+
90
+ ### 装不上怎么办?
91
+
92
+ 确认 DSH `>=0.2.1-rc.3 <0.4.0`、Node `>=24.9 <25`,并用全新的 `DSH_HOME` 重试;完整步骤见 `TROUBLESHOOTING.md`。
93
+
94
+ ### 为什么两份 JSON 看起来一样却没通过?
95
+
96
+ 评分先做稳定序列化:对象的键顺序无所谓,但数组顺序、数字精度和字符串大小写都按原样比较;`12.34` 与 `12.35` 就是不相等。
97
+
98
+ ### pass@k 是怎么算的?
99
+
100
+ 用无偏估计 `1 - C(n-c, k) / C(n, k)`,其中 `n` 是每个任务的采样数、`c` 是其中正确的次数;`k` 不能超过 `n`。
101
+
102
+ ### 能处理我的真实评测集吗?
103
+
104
+ 可以本地运行,但本包是 alpha、只用公开/合成评测包验证,不构成 benchmark 结论;真实评测集请先脱敏。
105
+
106
+ ### 会联网或调用模型吗?
107
+
108
+ 不会。lint、评分与汇总全部在本机完成。
109
+
110
+ ## 版本
111
+
112
+ - 当前版本:`0.1.0-alpha.12`(与 `package.json` 一致)
113
+ - 测试:`node --test test/*.test.mjs` 全绿(14 个用例,0 失败)
114
+
40
115
  ## 安装
41
116
 
42
117
  安装并验证:
@@ -76,6 +151,8 @@ dsh plugin --profile <profile> remove dsh-eval-pack
76
151
  |---|---|---|
77
152
  | `eval.pack_lint` | 校验 eval-pack 名称/版本及任务 id 唯一性 | R0 |
78
153
  | `eval.grade` | 确定性的 JSON 相等评分 | R0 |
154
+ | `eval.summary` | 汇总一次运行:通过数、通过率、失败任务 id | R0 |
155
+ | `eval.pass_at_k` | 按采样数计算无偏 pass@k 与均值 | R0 |
79
156
 
80
157
  ## 快速开始
81
158
 
@@ -84,9 +161,9 @@ dsh plugin --profile <profile> add dsh-eval-pack
84
161
  dsh --profile <profile> --dump-config | grep dsh-eval-pack
85
162
  ```
86
163
 
87
- ## 示例
164
+ ## 验收
88
165
 
89
- ### fixture 支撑的示例
166
+ ### fixture 支撑的验收行
90
167
 
91
168
  输入: [`ACCEPTANCE.csv`](https://github.com/PerryLink/dsh-eval-pack/blob/main/ACCEPTANCE.csv)
92
169
 
@@ -109,7 +186,8 @@ dsh --profile <profile> --dump-config | grep dsh-eval-pack
109
186
 
110
187
  ## 公开样例
111
188
 
112
- 公开/合成 fixture 在 `fixtures/`;`ACCEPTANCE.csv` 记录公开检查,全部 `counted=false`。
189
+ - `samples/quickstart/`:随 npm 包一起发布的合成评测包(3 个样本 + run 结果 + 金标),`node samples/quickstart/run.mjs --check` 可直接复现金标。
190
+ - `ACCEPTANCE.csv` 记录公开检查,除 `PS1-QS01` 外全部 `counted=false`。
113
191
 
114
192
  ## 开发
115
193
 
@@ -1,8 +1,29 @@
1
1
  # Troubleshooting — dsh-eval-pack
2
2
 
3
+ 每条按「症状 / 原因 / 动作」写。报错原文都是 `<一句人话>(E_XXX)|下一步:<动作>`,
4
+ 把 `E_XXX` 和这句话一起发到 issue 即可定位;不要把客户评测数据贴进 issue。
5
+
6
+ ## 1. 评测包本身不合格(E_PACK_TASKS_EMPTY / E_TASK_DUPLICATE / E_PACK_NAME)
7
+
8
+ - **症状**:`评测包里一个任务都没有(E_PACK_TASKS_EMPTY)|下一步:往 tasks 里至少放一个带 id 的任务`
9
+ - **原因**:`pack.json` 缺少 `name` / `version`,或 `tasks` 为空、任务 id 重复。
10
+ - **动作**:先跑 `eval.pack_lint`;按返回的错误码补齐字段、把重复 id 改成唯一值,再评分。
11
+
12
+ ## 2. 正确样本数超过采样数(E_EVAL_CORRECT)
13
+
14
+ - **症状**:`正确的样本数超过了采样数(E_EVAL_CORRECT)|下一步:确认 correct ≤ samples 再算 pass@k`
15
+ - **原因**:`sampling[]` 里 `correct` 填得比 `samples` 大,通常是两次运行的计数拼错了。
16
+ - **动作**:确认每个任务的 `samples` 和 `correct` 来自同一次运行;`correct` 最多等于 `samples`。
17
+
18
+ ## 3. k 超过采样数(E_EVAL_K)
19
+
20
+ - **症状**:`k 超过了采样数(E_EVAL_K)|下一步:把 k 改成 1 到 samples 之间的整数`
21
+ - **原因**:拿 10 次采样的数据去算 pass@20,估计量没有定义。
22
+ - **动作**:把 `k` 改成不超过该任务 `samples` 的整数;不同任务采样数不同时,先取最小值再统一 `k`。
23
+
3
24
  ## Install or activation fails
4
25
 
5
- - DSH must satisfy `>=0.2.1-rc.3 <0.3.0`; Node must be `>=24.9 <25`.
26
+ - DSH must satisfy `>=0.2.1-rc.3 <0.4.0`; Node must be `>=24.9 <25`.
6
27
  - Run `dsh --version` and `node --version`, then retry with a fresh `DSH_HOME`:
7
28
 
8
29
  ```sh
@@ -13,25 +34,23 @@ dsh --profile <profile> --dump-config | grep dsh-eval-pack
13
34
 
14
35
  ## The tool cannot find an input
15
36
 
16
- - All paths are local. Use an absolute path, or a path relative to the process working directory.
17
- - The public samples under `fixtures/` are repository-only; they are not shipped in the npm tarball. Download them from the GitHub repository if needed.
18
- - Supported material: eval-pack JSON.
37
+ - All paths are local. Pass the pack, case and run JSON as arguments; the shipped quickstart lives in `samples/quickstart/`.
38
+ - Supported material: eval-pack JSON, per-case sample JSON and one run-result JSON.
19
39
 
20
40
  ## Parse or encoding failures
21
41
 
22
- - Text inputs must be UTF-8; CSV headers must match the README's documented column names.
23
- - Remove a UTF-8 BOM if the first header is reported as unknown.
42
+ - All inputs must be UTF-8 JSON; remove a UTF-8 BOM if the parser rejects the first key.
24
43
  - Check the pack name/version and unique task ids; grading is deterministic JSON equality, not a benchmark.
25
44
 
26
45
  ## Permission or write failures
27
46
 
28
- - Tools marked `R1 local write` write under the configured DSH data directory.
29
- - For tests, point `DSH_HOME` at a temporary directory; do not write into a real profile.
47
+ - All four tools are read-only (`R0`); they do not write files.
48
+ - For tests, run against the shipped synthetic sample; no `DSH_HOME` writes are involved.
30
49
 
31
50
  ## The result looks wrong
32
51
 
33
- - Check the tool boundary in the README first. These are public/synthetic alpha tools, not a production or customer-validated determination.
34
- - Compare the reported row ids and input rows; the output is deliberately explicit about what it could not run.
52
+ - Check the tool boundary in the README first. These are public/synthetic alpha tools, not a production or customer-validated benchmark.
53
+ - Compare the reported task ids with the input tasks; the output is deliberately explicit about which case failed.
35
54
 
36
55
  ## Run the tests
37
56
 
@@ -0,0 +1,6 @@
1
+ $ node samples/quickstart/run.mjs
2
+ dsh-eval-pack quickstart - synthetic eval pack (not a benchmark)
3
+ pack synthetic-invoice-basics@1.0.0: lint ok, 3 tasks
4
+ grades: case-01 pass, case-02 fail, case-03 pass
5
+ summary: 2/3 passed (0.666667), failures: case-02
6
+ pass@1 mean 0.633333; pass@3 mean 0.9
Binary file
@@ -7,6 +7,8 @@ export interface EvalPack {
7
7
  version: string;
8
8
  tasks: EvalTask[];
9
9
  }
10
+ export type EvalErrorCode = 'E_PACK_NOT_OBJECT' | 'E_PACK_NAME' | 'E_PACK_VERSION' | 'E_PACK_TASKS_EMPTY' | 'E_TASK_ID' | 'E_TASK_DUPLICATE' | 'E_EVAL_SAMPLES' | 'E_EVAL_CORRECT' | 'E_EVAL_K';
11
+ export declare function evalErrorMessage(code: EvalErrorCode): string;
10
12
  export declare function lintPack(input: unknown): string[];
11
13
  /** Stable serialisation: object keys sorted at every level, arrays kept in order. */
12
14
  export declare function canonical(value: unknown): string;
@@ -1,3 +1,22 @@
1
+ /**
2
+ * Human-facing wording for every code this package can surface.
3
+ * Renderer: `<一句人话>(E_CODE)|下一步:<一个动作>` (Package Standard v1 §4).
4
+ */
5
+ const EVAL_HUMAN = {
6
+ E_PACK_NOT_OBJECT: { text: '这不是一个评测包对象,读不出名称、版本和任务', next: '传一个包含 name / version / tasks 的 JSON 对象' },
7
+ E_PACK_NAME: { text: '评测包缺少名称', next: '给评测包加一个非空的 name 再跑 lint' },
8
+ E_PACK_VERSION: { text: '评测包缺少版本号', next: '给评测包加一个非空的 version(例如 "1.0.0")' },
9
+ E_PACK_TASKS_EMPTY: { text: '评测包里一个任务都没有', next: '往 tasks 里至少放一个带 id 的任务' },
10
+ E_TASK_ID: { text: '有一个任务没有 id', next: '给每个任务补一个非空且唯一的 id' },
11
+ E_TASK_DUPLICATE: { text: '评测包里有重复的任务 id', next: '把重复的 id 改成唯一值再跑 lint' },
12
+ E_EVAL_SAMPLES: { text: '采样数必须是正整数', next: '把 samples 改成 ≥1 的整数' },
13
+ E_EVAL_CORRECT: { text: '正确的样本数超过了采样数', next: '确认 correct ≤ samples 再算 pass@k' },
14
+ E_EVAL_K: { text: 'k 超过了采样数', next: '把 k 改成 1 到 samples 之间的整数' },
15
+ };
16
+ export function evalErrorMessage(code) {
17
+ const human = EVAL_HUMAN[code];
18
+ return `${human.text}(${code})|下一步:${human.next}`;
19
+ }
1
20
  export function lintPack(input) {
2
21
  const errors = [];
3
22
  if (!input || typeof input !== 'object')
@@ -68,11 +87,11 @@ function comb(n, k) {
68
87
  export function passAtK(task, k) {
69
88
  const { samples, correct } = task;
70
89
  if (!Number.isInteger(samples) || samples < 1)
71
- throw new Error('E_EVAL_SAMPLES: samples must be a positive integer');
90
+ throw new Error(evalErrorMessage('E_EVAL_SAMPLES'));
72
91
  if (!Number.isInteger(correct) || correct < 0 || correct > samples)
73
- throw new Error('E_EVAL_CORRECT: correct must be between 0 and samples');
92
+ throw new Error(evalErrorMessage('E_EVAL_CORRECT'));
74
93
  if (!Number.isInteger(k) || k < 1 || k > samples)
75
- throw new Error('E_EVAL_K: k must be between 1 and samples');
94
+ throw new Error(evalErrorMessage('E_EVAL_K'));
76
95
  const denominator = comb(samples, k);
77
96
  const numerator = comb(samples - correct, k);
78
97
  const value = 1 - Number(numerator) / Number(denominator);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-eval-pack",
3
- "version": "0.1.0-alpha.10",
3
+ "version": "0.1.0-alpha.12",
4
4
  "description": "Public/synthetic eval-pack lint and deterministic JSON grader; not a validated benchmark.",
5
5
  "type": "module",
6
6
  "main": "./lib/plugin/index.js",
@@ -29,11 +29,24 @@
29
29
  "CHANGELOG.md",
30
30
  "TROUBLESHOOTING.md",
31
31
  "screenshots.json",
32
- "icon.svg"
32
+ "icon.svg",
33
+ "samples"
33
34
  ],
34
35
  "dsh": {
35
36
  "bundle": {
36
37
  "patch": "./cordis.patch.yml"
38
+ },
39
+ "demo": {
40
+ "sample": "samples/quickstart/input",
41
+ "prompt": "我用自带样例跑一次评测:3 个样本里过了几个、哪个没过、pass@3 是多少?",
42
+ "expect": "samples/quickstart/expected/result.json",
43
+ "screenshot": "docs/assets/quickstart.png",
44
+ "reads": [
45
+ "用户指定的评测包 JSON、样本 JSON 与运行结果 JSON(样例:samples/quickstart/input)"
46
+ ],
47
+ "writes": [],
48
+ "network": false,
49
+ "external": []
37
50
  }
38
51
  },
39
52
  "engines": {
@@ -80,5 +93,10 @@
80
93
  "bugs": {
81
94
  "url": "https://github.com/PerryLink/dsh-eval-pack/issues"
82
95
  },
83
- "icon": "icon.svg"
96
+ "icon": "icon.svg",
97
+ "peerDependenciesMeta": {
98
+ "@deepseek-ai/dsh-tools": {
99
+ "optional": true
100
+ }
101
+ }
84
102
  }
@@ -0,0 +1,70 @@
1
+ {
2
+ "sample": "samples/quickstart/input",
3
+ "synthetic": true,
4
+ "pack": {
5
+ "name": "synthetic-invoice-basics",
6
+ "version": "1.0.0",
7
+ "tasks": 3
8
+ },
9
+ "lint": {
10
+ "ok": true,
11
+ "errors": []
12
+ },
13
+ "grades": [
14
+ {
15
+ "id": "case-01",
16
+ "pass": true
17
+ },
18
+ {
19
+ "id": "case-02",
20
+ "pass": false
21
+ },
22
+ {
23
+ "id": "case-03",
24
+ "pass": true
25
+ }
26
+ ],
27
+ "summary": {
28
+ "total": 3,
29
+ "passed": 2,
30
+ "failed": 1,
31
+ "pass_rate": 0.666667,
32
+ "failures": [
33
+ "case-02"
34
+ ]
35
+ },
36
+ "pass_at_1": {
37
+ "mean": 0.633333,
38
+ "tasks": [
39
+ {
40
+ "task_id": "case-01",
41
+ "pass_at_k": 0.7
42
+ },
43
+ {
44
+ "task_id": "case-02",
45
+ "pass_at_k": 0.3
46
+ },
47
+ {
48
+ "task_id": "case-03",
49
+ "pass_at_k": 0.9
50
+ }
51
+ ]
52
+ },
53
+ "pass_at_3": {
54
+ "mean": 0.9,
55
+ "tasks": [
56
+ {
57
+ "task_id": "case-01",
58
+ "pass_at_k": 0.991667
59
+ },
60
+ {
61
+ "task_id": "case-02",
62
+ "pass_at_k": 0.708333
63
+ },
64
+ {
65
+ "task_id": "case-03",
66
+ "pass_at_k": 1
67
+ }
68
+ ]
69
+ }
70
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "id": "case-01",
3
+ "prompt": "Two invoice lines are 88.50 and 44.00. Return the total as {\"total\": number}.",
4
+ "expected": { "total": 132.5 }
5
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "id": "case-02",
3
+ "prompt": "Round 12.345 EUR half-up to two decimals. Return {\"amount\": string, \"currency\": string}.",
4
+ "expected": { "amount": "12.35", "currency": "EUR" }
5
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "id": "case-03",
3
+ "prompt": "Net is 100 and tax is 8%. Return {net, tax, gross} as numbers.",
4
+ "expected": { "net": 100, "tax": 8, "gross": 108 }
5
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "name": "synthetic-invoice-basics",
3
+ "version": "1.0.0",
4
+ "description": "Three tiny invoice-arithmetic tasks for the quickstart. Synthetic; not a benchmark.",
5
+ "tasks": [
6
+ { "id": "case-01" },
7
+ { "id": "case-02" },
8
+ { "id": "case-03" }
9
+ ]
10
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "run_id": "synthetic-run-2026-11-02",
3
+ "note": "Actual outputs of a synthetic reference run. No model was called; no customer data.",
4
+ "results": [
5
+ { "id": "case-01", "actual": { "total": 132.5 } },
6
+ { "id": "case-02", "actual": { "amount": "12.34", "currency": "EUR" } },
7
+ { "id": "case-03", "actual": { "gross": 108, "tax": 8, "net": 100 } }
8
+ ],
9
+ "sampling": [
10
+ { "task_id": "case-01", "samples": 10, "correct": 7 },
11
+ { "task_id": "case-02", "samples": 10, "correct": 3 },
12
+ { "task_id": "case-03", "samples": 10, "correct": 9 }
13
+ ]
14
+ }
@@ -0,0 +1,82 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * dsh-eval-pack quickstart — lints the bundled synthetic eval pack, grades the shipped
4
+ * reference run, and reports pass@k. `expected/result.json` is the stdout of
5
+ * `node samples/quickstart/run.mjs --json`, so it is a real run over the sample.
6
+ *
7
+ * node samples/quickstart/run.mjs # human-readable summary
8
+ * node samples/quickstart/run.mjs --json # the golden result on stdout
9
+ * node samples/quickstart/run.mjs --check # recompute and diff against the golden file
10
+ *
11
+ * Everything is local and synthetic: no model call, no network, no customer data.
12
+ */
13
+ import assert from 'node:assert/strict'
14
+ import { readFile } from 'node:fs/promises'
15
+ import path from 'node:path'
16
+ import { fileURLToPath } from 'node:url'
17
+ import { createTools } from '../../lib/plugin/tools.js'
18
+
19
+ const here = path.dirname(fileURLToPath(import.meta.url))
20
+ const inputDir = path.join(here, 'input')
21
+ const expectedPath = path.join(here, 'expected', 'result.json')
22
+ const mode = process.argv.includes('--check') ? 'check' : process.argv.includes('--json') ? 'json' : 'summary'
23
+ const readJson = async (name) => JSON.parse(await readFile(path.join(inputDir, name), 'utf8'))
24
+
25
+ async function run() {
26
+ const pack = await readJson('pack.json')
27
+ const reference = await readJson('run.json')
28
+ const cases = []
29
+ for (const task of pack.tasks) cases.push(await readJson(path.join('cases', `${task.id}.json`)))
30
+
31
+ const tools = Object.fromEntries(createTools().map((tool) => [tool.name, tool]))
32
+ const call = (name, args) => tools[name].execute(args, { callId: 'quickstart' })
33
+ const actualById = new Map(reference.results.map((result) => [result.id, result.actual]))
34
+
35
+ const lint = await call('eval.pack_lint', { pack })
36
+ const results = []
37
+ const grades = []
38
+ for (const testCase of cases) {
39
+ const actual = actualById.get(testCase.id)
40
+ assert.notEqual(actual, undefined, `run.json has no result for ${testCase.id}`)
41
+ const graded = await call('eval.grade', { actual, expected: testCase.expected })
42
+ grades.push({ id: testCase.id, pass: graded.pass })
43
+ results.push({ id: testCase.id, actual, expected: testCase.expected })
44
+ }
45
+ const summary = await call('eval.summary', { results })
46
+ const pass1 = await call('eval.pass_at_k', { k: 1, tasks: reference.sampling })
47
+ const pass3 = await call('eval.pass_at_k', { k: 3, tasks: reference.sampling })
48
+ const compact = (result) => ({ mean: result.mean, tasks: result.tasks.map((task) => ({ task_id: task.task_id, pass_at_k: task.pass_at_k })) })
49
+
50
+ return {
51
+ sample: 'samples/quickstart/input',
52
+ synthetic: true,
53
+ pack: { name: pack.name, version: pack.version, tasks: pack.tasks.length },
54
+ lint: { ok: lint.ok, errors: lint.errors },
55
+ grades,
56
+ summary,
57
+ pass_at_1: compact(pass1),
58
+ pass_at_3: compact(pass3),
59
+ }
60
+ }
61
+
62
+ function printSummary(result) {
63
+ console.log('dsh-eval-pack quickstart - synthetic eval pack (not a benchmark)')
64
+ console.log(`pack ${result.pack.name}@${result.pack.version}: lint ${result.lint.ok ? 'ok' : result.lint.errors.join(', ')}, ${result.pack.tasks} tasks`)
65
+ console.log(`grades: ${result.grades.map((grade) => `${grade.id} ${grade.pass ? 'pass' : 'fail'}`).join(', ')}`)
66
+ console.log(`summary: ${result.summary.passed}/${result.summary.total} passed (${result.summary.pass_rate})${result.summary.failures.length ? `, failures: ${result.summary.failures.join(', ')}` : ''}`)
67
+ console.log(`pass@1 mean ${result.pass_at_1.mean}; pass@3 mean ${result.pass_at_3.mean}`)
68
+ }
69
+
70
+ const result = await run()
71
+
72
+ if (mode === 'json') {
73
+ process.stdout.write(`${JSON.stringify(result, null, 2)}\n`)
74
+ } else if (mode === 'check') {
75
+ const expected = JSON.parse(await readFile(expectedPath, 'utf8'))
76
+ assert.deepEqual(result, expected)
77
+ printSummary(result)
78
+ console.log('golden samples/quickstart/expected/result.json matches')
79
+ console.log('quickstart ok')
80
+ } else {
81
+ printSummary(result)
82
+ }
package/screenshots.json CHANGED
@@ -1,4 +1,17 @@
1
1
  [
2
+ {
3
+ "path": "docs/assets/quickstart.png",
4
+ "kind": "quickstart",
5
+ "alt": "dsh-eval-pack quickstart run on the shipped synthetic eval pack",
6
+ "caption": "Real run: node samples/quickstart/run.mjs on samples/quickstart/input (3 sample JSONs + one reference run); output matches samples/quickstart/expected/result.json.",
7
+ "command": "node samples/quickstart/run.mjs",
8
+ "run_at": "2026-11-02T22:15:29+08:00",
9
+ "output_sha256": "2ba7ea5016ceded8fdeb186844ddd89d51125920ad9fa4bee9eef888989ea7d1",
10
+ "output_path": "samples/quickstart/expected/result.json",
11
+ "log": "docs/assets/quickstart.log",
12
+ "log_sha256": "bc94be001ab24a17449d124decbc283676a4ee46a61b1a18bd91613e0370594a",
13
+ "image_sha256": "f2e019f6129925293f80dc5147d77d4a92ff49a629a9becfa46452d08273ae0b"
14
+ },
2
15
  {
3
16
  "path": "docs/assets/dsh-eval-pack-hero.png",
4
17
  "kind": "hero",