@webywz/eval-smoke 0.3.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +228 -127
- package/dist/baseline.d.ts +25 -0
- package/dist/baseline.d.ts.map +1 -0
- package/dist/baseline.js +86 -0
- package/dist/baseline.js.map +1 -0
- package/dist/github-summary.d.ts +4 -0
- package/dist/github-summary.d.ts.map +1 -0
- package/dist/github-summary.js +39 -0
- package/dist/github-summary.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/run-cli.d.ts +7 -1
- package/dist/run-cli.d.ts.map +1 -1
- package/dist/run-cli.js +78 -3
- package/dist/run-cli.js.map +1 -1
- package/dist/summary-md.d.ts +4 -0
- package/dist/summary-md.d.ts.map +1 -0
- package/dist/summary-md.js +22 -0
- package/dist/summary-md.js.map +1 -0
- package/examples/github-action.yml +41 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,8 +1,22 @@
|
|
|
1
1
|
# eval-smoke
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/@webywz/eval-smoke)
|
|
4
|
+
[](https://www.npmjs.com/package/@webywz/eval-smoke)
|
|
5
|
+
[](./LICENSE)
|
|
4
6
|
|
|
5
|
-
|
|
7
|
+
> **One-minute smoke evals for prompts and models.**
|
|
8
|
+
>
|
|
9
|
+
> **一分钟烟雾测试:在发版前拦住 prompt / 模型回归。**
|
|
10
|
+
|
|
11
|
+
YAML or JSON in. Pass/fail out. Exit `1` on regression. Optional JUnit for CI.
|
|
12
|
+
|
|
13
|
+
YAML 或 JSON 进,通过/失败出。回归时退出码 `1`。可选 JUnit 对接 CI。
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## English
|
|
18
|
+
|
|
19
|
+
### Demo
|
|
6
20
|
|
|
7
21
|
```bash
|
|
8
22
|
npm i -g @webywz/eval-smoke
|
|
@@ -10,8 +24,8 @@ eval-smoke init
|
|
|
10
24
|
eval-smoke suite.yaml --mock
|
|
11
25
|
```
|
|
12
26
|
|
|
13
|
-
```
|
|
14
|
-
eval-smoke 0.
|
|
27
|
+
```text
|
|
28
|
+
eval-smoke 0.4.0 · mock · gpt-4o-mini · smoke · 4 cases
|
|
15
29
|
|
|
16
30
|
pass greeting 0ms
|
|
17
31
|
pass capital-france 0ms
|
|
@@ -21,23 +35,31 @@ eval-smoke 0.3.0 · mock · gpt-4o-mini · smoke · 4 cases
|
|
|
21
35
|
4 passed 0 failed 1ms
|
|
22
36
|
```
|
|
23
37
|
|
|
24
|
-
`--mock` is offline and deterministic.
|
|
38
|
+
`--mock` is offline and deterministic. CI and contributors do not need API keys.
|
|
39
|
+
|
|
40
|
+
### Features
|
|
25
41
|
|
|
26
|
-
|
|
42
|
+
| | |
|
|
43
|
+
| --- | --- |
|
|
44
|
+
| **Tiny suite** | A handful of cases — not a full harness |
|
|
45
|
+
| **Matchers** | `equals`, `contains`, `not_contains`, `regex`, `json`, `min_tokens` / `max_tokens` |
|
|
46
|
+
| **init** | `eval-smoke init` scaffolds a mock-friendly `suite.yaml` |
|
|
47
|
+
| **Filter** | `--only` by id substring or `/regex/` |
|
|
48
|
+
| **CI** | `--junit`, `--github-summary`, exit codes, `--fail-fast`, `--concurrency` |
|
|
49
|
+
| **Baseline** | `--baseline` / `--update-baseline` catch pass→fail regressions |
|
|
50
|
+
| **Providers** | Mock offline; live OpenAI / Anthropic when keyed |
|
|
51
|
+
|
|
52
|
+
### Install
|
|
27
53
|
|
|
28
54
|
```bash
|
|
29
55
|
npm i -g @webywz/eval-smoke
|
|
30
|
-
# or
|
|
56
|
+
# or one-off:
|
|
31
57
|
npx @webywz/eval-smoke suite.yaml --mock
|
|
32
58
|
```
|
|
33
59
|
|
|
34
|
-
|
|
60
|
+
Node 18+.
|
|
35
61
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
1. Scaffold a suite with `eval-smoke init`, or copy the example.
|
|
39
|
-
2. Run mock mode until the runner and matchers look right.
|
|
40
|
-
3. Point the same file at a live model when you are ready.
|
|
62
|
+
### Quick start
|
|
41
63
|
|
|
42
64
|
```bash
|
|
43
65
|
eval-smoke init
|
|
@@ -46,23 +68,26 @@ eval-smoke suite.yaml --mock --only greeting
|
|
|
46
68
|
eval-smoke suite.yaml --mock --junit junit.xml
|
|
47
69
|
eval-smoke examples/suite.yaml --mock --json
|
|
48
70
|
eval-smoke examples/suite.yaml --mock --concurrency 4
|
|
71
|
+
eval-smoke examples/suite.yaml --mock --update-baseline baseline.json
|
|
72
|
+
eval-smoke examples/suite.yaml --mock --baseline baseline.json
|
|
73
|
+
eval-smoke examples/suite.yaml --mock --github-summary
|
|
49
74
|
OPENAI_API_KEY=sk-... eval-smoke examples/suite.yaml
|
|
50
75
|
ANTHROPIC_API_KEY=sk-ant-... eval-smoke examples/suite.yaml --model claude-3-5-haiku-20241022
|
|
51
76
|
```
|
|
52
77
|
|
|
53
|
-
|
|
78
|
+
### `eval-smoke init`
|
|
54
79
|
|
|
55
80
|
```bash
|
|
56
81
|
eval-smoke init # writes ./suite.yaml
|
|
57
82
|
eval-smoke init ./prompts # writes ./prompts/suite.yaml
|
|
58
|
-
eval-smoke init --force # overwrite
|
|
83
|
+
eval-smoke init --force # overwrite
|
|
59
84
|
```
|
|
60
85
|
|
|
61
|
-
Creates a small mock-friendly suite (greeting, capital, arithmetic, refusal). Refuses to overwrite unless
|
|
86
|
+
Creates a small mock-friendly suite (greeting, capital, arithmetic, refusal). Refuses to overwrite unless `--force`.
|
|
62
87
|
|
|
63
|
-
|
|
88
|
+
### Suite format
|
|
64
89
|
|
|
65
|
-
|
|
90
|
+
YAML or JSON — a list of cases, or an object with `cases`:
|
|
66
91
|
|
|
67
92
|
```yaml
|
|
68
93
|
name: demo
|
|
@@ -87,132 +112,219 @@ cases:
|
|
|
87
112
|
city: Paris
|
|
88
113
|
```
|
|
89
114
|
|
|
90
|
-
|
|
115
|
+
| Field | Notes |
|
|
116
|
+
| --- | --- |
|
|
117
|
+
| `id` / `prompt` | Required |
|
|
118
|
+
| `expect.contains` | Substring, case-insensitive; string or list |
|
|
119
|
+
| `expect.not_contains` | Must be absent |
|
|
120
|
+
| `expect.regex` | `/pattern/i`, `(?i)pattern`, or raw |
|
|
121
|
+
| `expect.equals` | Exact after NFC + LF normalize |
|
|
122
|
+
| `expect.json` | `true` = parseable; object/array = deep-equal |
|
|
123
|
+
| `expect.min_tokens` / `max_tokens` | Approx via `ceil(chars / 4)` |
|
|
124
|
+
| `system` / `model` | Suite or case |
|
|
125
|
+
| `provider` | `openai`, `anthropic`, or `mock` |
|
|
126
|
+
|
|
127
|
+
At least one matcher per case. Failures print expected/actual (and a first-diff for `equals`).
|
|
128
|
+
|
|
129
|
+
### CLI
|
|
91
130
|
|
|
92
|
-
```yaml
|
|
93
|
-
- id: capital-france
|
|
94
|
-
prompt: What is the capital of France? Answer with the city name only.
|
|
95
|
-
expect:
|
|
96
|
-
contains: Paris
|
|
97
131
|
```
|
|
132
|
+
eval-smoke <suite.yaml|suite.json> [options]
|
|
133
|
+
eval-smoke init [dir] [--force]
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
| Flag | Meaning |
|
|
137
|
+
| --- | --- |
|
|
138
|
+
| `--mock` | Offline deterministic runner |
|
|
139
|
+
| `--json` | Machine-readable JSON report |
|
|
140
|
+
| `--junit <path>` | Write JUnit XML (still prints human report unless `--json`) |
|
|
141
|
+
| `--baseline <path>` | Exit `1` if a baseline-passing case now fails or is missing |
|
|
142
|
+
| `--update-baseline <path>` | Write current report JSON (pretty) to path |
|
|
143
|
+
| `--github-summary [path]` | Append pass/fail Markdown to `$GITHUB_STEP_SUMMARY` or path |
|
|
144
|
+
| `--only <pattern>` | Cases whose id contains pattern, or matches `/regex/` |
|
|
145
|
+
| `--fail-fast` | Stop after first failure |
|
|
146
|
+
| `--concurrency <n>` | Parallel cases (default 1; ignored with `--fail-fast`) |
|
|
147
|
+
| `--timeout <ms>` | Per-case timeout (default 30000) |
|
|
148
|
+
| `--model <name>` | Override suite model |
|
|
149
|
+
| `--provider <name>` | `openai` \| `anthropic` \| `mock` |
|
|
150
|
+
| `--force` | Overwrite for `init` |
|
|
151
|
+
| `--no-color` | Disable ANSI (`NO_COLOR` respected) |
|
|
152
|
+
|
|
153
|
+
| Exit | Meaning |
|
|
154
|
+
| --- | --- |
|
|
155
|
+
| `0` | All passed |
|
|
156
|
+
| `1` | One or more failed |
|
|
157
|
+
| `2` | Usage / config error (missing file, bad YAML, no key, `--only` matched nothing) |
|
|
158
|
+
|
|
159
|
+
### Runners
|
|
98
160
|
|
|
99
|
-
|
|
100
|
-
| --- | --- | --- |
|
|
101
|
-
| `id` | case | Required, unique. |
|
|
102
|
-
| `prompt` | case | Required. |
|
|
103
|
-
| `expect.contains` | case | Substring, case-insensitive. String or list; all must match. |
|
|
104
|
-
| `expect.not_contains` | case | Substring must be absent. String or list. |
|
|
105
|
-
| `expect.regex` | case | JavaScript regex. `/pattern/i`, `(?i)pattern`, or a raw pattern. |
|
|
106
|
-
| `expect.equals` | case | Exact match after NFC + LF normalize; one trailing newline ignored. |
|
|
107
|
-
| `expect.json` | case | `true` = must parse as JSON; object/array = deep-equal after parse. |
|
|
108
|
-
| `expect.min_tokens` | case | Approximate floor using `ceil(chars / 4)`. |
|
|
109
|
-
| `expect.max_tokens` | case | Approximate cap using `ceil(chars / 4)`. |
|
|
110
|
-
| `system` | suite or case | Optional system prompt for live providers. |
|
|
111
|
-
| `model` | suite or case | Live default: `gpt-4o-mini` or `claude-3-5-haiku-20241022`. |
|
|
112
|
-
| `provider` | suite | `openai`, `anthropic`, or `mock`. |
|
|
161
|
+
**Mock** never calls the network. Canned replies keep the example suite green in CI:
|
|
113
162
|
|
|
114
|
-
|
|
163
|
+
| Prompt contains | Mock reply |
|
|
164
|
+
| --- | --- |
|
|
165
|
+
| `hello` | `Hello` |
|
|
166
|
+
| `capital of France` | `Paris` |
|
|
167
|
+
| `2 + 2` | `4` |
|
|
168
|
+
| `ignore previous` / `PWNED` | a refusal without `PWNED` |
|
|
115
169
|
|
|
116
|
-
|
|
170
|
+
**Live OpenAI** with `OPENAI_API_KEY` (optional `OPENAI_BASE_URL`). **Live Anthropic** with `ANTHROPIC_API_KEY`, or when the model name starts with `claude`.
|
|
117
171
|
|
|
172
|
+
### Library
|
|
173
|
+
|
|
174
|
+
```ts
|
|
175
|
+
import { loadSuite, runSuite, formatJUnit, initSuite } from "@webywz/eval-smoke";
|
|
176
|
+
|
|
177
|
+
initSuite(".", { force: false });
|
|
178
|
+
const suite = loadSuite("suite.yaml");
|
|
179
|
+
const report = await runSuite(suite, { mock: true, concurrency: 4 });
|
|
180
|
+
console.log(formatJUnit(report));
|
|
181
|
+
if (!report.ok) process.exit(1);
|
|
118
182
|
```
|
|
119
|
-
eval-smoke <suite.yaml|suite.json> [options]
|
|
120
|
-
eval-smoke init [dir] [--force]
|
|
121
183
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
--force Overwrite existing suite.yaml for init
|
|
132
|
-
--no-color Disable ANSI colors (also respects NO_COLOR)
|
|
133
|
-
-h, --help
|
|
134
|
-
-v, --version
|
|
184
|
+
### CI snippet
|
|
185
|
+
|
|
186
|
+
```yaml
|
|
187
|
+
- run: npx @webywz/eval-smoke@0.4.0 prompts/smoke.yaml --mock --junit junit.xml
|
|
188
|
+
- uses: actions/upload-artifact@v4
|
|
189
|
+
if: always()
|
|
190
|
+
with:
|
|
191
|
+
name: junit
|
|
192
|
+
path: junit.xml
|
|
135
193
|
```
|
|
136
194
|
|
|
137
|
-
|
|
195
|
+
### Links
|
|
196
|
+
|
|
197
|
+
| | |
|
|
138
198
|
| --- | --- |
|
|
139
|
-
|
|
|
140
|
-
|
|
|
141
|
-
|
|
|
199
|
+
| npm | [npmjs.com/package/@webywz/eval-smoke](https://www.npmjs.com/package/@webywz/eval-smoke) |
|
|
200
|
+
| Issues | [github.com/webywz/eval-smoke/issues](https://github.com/webywz/eval-smoke/issues) |
|
|
201
|
+
| License | [MIT](./LICENSE) © webywz |
|
|
202
|
+
|
|
203
|
+
---
|
|
142
204
|
|
|
143
|
-
|
|
205
|
+
## 中文
|
|
144
206
|
|
|
145
|
-
|
|
207
|
+
### 演示
|
|
146
208
|
|
|
147
209
|
```bash
|
|
148
|
-
eval-smoke
|
|
149
|
-
eval-smoke
|
|
150
|
-
eval-smoke suite.yaml --mock
|
|
210
|
+
npm i -g @webywz/eval-smoke
|
|
211
|
+
eval-smoke init
|
|
212
|
+
eval-smoke suite.yaml --mock
|
|
151
213
|
```
|
|
152
214
|
|
|
153
|
-
|
|
215
|
+
`--mock` 离线、确定。CI 与贡献者不需要 API key。
|
|
154
216
|
|
|
155
|
-
###
|
|
217
|
+
### 功能
|
|
156
218
|
|
|
157
|
-
|
|
219
|
+
| | |
|
|
220
|
+
| --- | --- |
|
|
221
|
+
| **轻量套件** | 少量用例,不是完整评测框架 |
|
|
222
|
+
| **匹配器** | `equals`、`contains`、`not_contains`、`regex`、`json`、token 上下限 |
|
|
223
|
+
| **init** | `eval-smoke init` 生成可 mock 的 `suite.yaml` |
|
|
224
|
+
| **过滤** | `--only`:id 子串或 `/regex/` |
|
|
225
|
+
| **CI** | `--junit`、`--github-summary`、退出码、`--fail-fast`、`--concurrency` |
|
|
226
|
+
| **基线** | `--baseline` / `--update-baseline` 拦住 pass→fail 回归 |
|
|
227
|
+
| **提供商** | Mock 离线;有 key 时走 OpenAI / Anthropic |
|
|
228
|
+
|
|
229
|
+
### 安装
|
|
158
230
|
|
|
159
231
|
```bash
|
|
160
|
-
|
|
232
|
+
npm i -g @webywz/eval-smoke
|
|
233
|
+
# 或一次性:
|
|
234
|
+
npx @webywz/eval-smoke suite.yaml --mock
|
|
161
235
|
```
|
|
162
236
|
|
|
163
|
-
|
|
237
|
+
需要 Node 18+。
|
|
238
|
+
|
|
239
|
+
### 快速开始
|
|
164
240
|
|
|
165
|
-
|
|
241
|
+
```bash
|
|
242
|
+
eval-smoke init
|
|
243
|
+
eval-smoke suite.yaml --mock
|
|
244
|
+
eval-smoke suite.yaml --mock --only greeting
|
|
245
|
+
eval-smoke suite.yaml --mock --junit junit.xml
|
|
246
|
+
eval-smoke examples/suite.yaml --mock --json
|
|
247
|
+
eval-smoke examples/suite.yaml --mock --concurrency 4
|
|
248
|
+
eval-smoke examples/suite.yaml --mock --update-baseline baseline.json
|
|
249
|
+
eval-smoke examples/suite.yaml --mock --baseline baseline.json
|
|
250
|
+
eval-smoke examples/suite.yaml --mock --github-summary
|
|
251
|
+
OPENAI_API_KEY=sk-... eval-smoke examples/suite.yaml
|
|
252
|
+
ANTHROPIC_API_KEY=sk-ant-... eval-smoke examples/suite.yaml --model claude-3-5-haiku-20241022
|
|
253
|
+
```
|
|
166
254
|
|
|
167
|
-
|
|
255
|
+
### `eval-smoke init`
|
|
168
256
|
|
|
169
|
-
|
|
257
|
+
```bash
|
|
258
|
+
eval-smoke init # 写入 ./suite.yaml
|
|
259
|
+
eval-smoke init ./prompts # 写入 ./prompts/suite.yaml
|
|
260
|
+
eval-smoke init --force # 覆盖已有文件
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
生成小型 mock 友好套件(问候、首都、算术、拒答)。不加 `--force` 不会覆盖已有文件。
|
|
264
|
+
|
|
265
|
+
### 套件格式
|
|
266
|
+
|
|
267
|
+
YAML 或 JSON —— 用例列表,或带 `cases` 的对象:
|
|
268
|
+
|
|
269
|
+
```yaml
|
|
270
|
+
name: demo
|
|
271
|
+
model: gpt-4o-mini
|
|
272
|
+
cases:
|
|
273
|
+
- id: greeting
|
|
274
|
+
prompt: Reply with exactly the word Hello.
|
|
275
|
+
expect:
|
|
276
|
+
equals: Hello
|
|
277
|
+
contains: Hello
|
|
278
|
+
not_contains: Goodbye
|
|
279
|
+
regex: "(?i)^hello\\b"
|
|
280
|
+
min_tokens: 1
|
|
281
|
+
max_tokens: 32
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
| 字段 | 说明 |
|
|
170
285
|
| --- | --- |
|
|
171
|
-
| `
|
|
172
|
-
| `
|
|
173
|
-
| `
|
|
174
|
-
| `
|
|
286
|
+
| `id` / `prompt` | 必填 |
|
|
287
|
+
| `expect.contains` | 子串,忽略大小写;字符串或列表 |
|
|
288
|
+
| `expect.not_contains` | 不得出现 |
|
|
289
|
+
| `expect.regex` | `/pattern/i`、`(?i)pattern` 或裸模式 |
|
|
290
|
+
| `expect.equals` | NFC + LF 规范化后精确匹配 |
|
|
291
|
+
| `expect.json` | `true` = 可解析;对象/数组 = 深相等 |
|
|
292
|
+
| `expect.min_tokens` / `max_tokens` | 约 `ceil(chars / 4)` |
|
|
293
|
+
| `system` / `model` | 套件级或用例级 |
|
|
294
|
+
| `provider` | `openai` / `anthropic` / `mock` |
|
|
175
295
|
|
|
176
|
-
|
|
296
|
+
每个用例至少要有一个匹配器。失败时打印期望/实际(`equals` 还有首差位置)。
|
|
177
297
|
|
|
178
|
-
|
|
298
|
+
### 命令行要点
|
|
179
299
|
|
|
180
|
-
|
|
300
|
+
| 参数 | 含义 |
|
|
301
|
+
| --- | --- |
|
|
302
|
+
| `--mock` | 离线确定性运行 |
|
|
303
|
+
| `--json` | JSON 报告 |
|
|
304
|
+
| `--junit <path>` | 写出 JUnit XML(仍打印人类可读报告,除非同时 `--json`) |
|
|
305
|
+
| `--baseline <path>` | 基线里曾通过的用例若失败或缺失则退出 `1` |
|
|
306
|
+
| `--update-baseline <path>` | 把当前报告 JSON(pretty)写入路径 |
|
|
307
|
+
| `--github-summary [path]` | 追加通过/失败 Markdown 到 `$GITHUB_STEP_SUMMARY` 或指定路径 |
|
|
308
|
+
| `--only <pattern>` | 按 id 子串或 `/regex/` 过滤 |
|
|
309
|
+
| `--fail-fast` | 首个失败即停 |
|
|
310
|
+
| `--concurrency <n>` | 并行用例数(默认 1) |
|
|
311
|
+
| `--timeout <ms>` | 单用例超时(默认 30000) |
|
|
312
|
+
| `--model` / `--provider` | 覆盖模型 / 提供商 |
|
|
313
|
+
| `--force` | `init` 时覆盖 |
|
|
314
|
+
|
|
315
|
+
| 退出码 | 含义 |
|
|
316
|
+
| --- | --- |
|
|
317
|
+
| `0` | 全部通过 |
|
|
318
|
+
| `1` | 有失败 |
|
|
319
|
+
| `2` | 用法/配置错误(缺文件、坏 YAML、无 key、`--only` 无匹配) |
|
|
181
320
|
|
|
182
|
-
|
|
321
|
+
### 运行器
|
|
183
322
|
|
|
184
|
-
|
|
323
|
+
**Mock** 永不联网。内置 canned 回复保证示例套件在 CI 里绿。
|
|
185
324
|
|
|
186
|
-
|
|
187
|
-
eval-smoke examples/suite.yaml --mock --json
|
|
188
|
-
```
|
|
325
|
+
**Live OpenAI**:`OPENAI_API_KEY`(可选 `OPENAI_BASE_URL`)。**Live Anthropic**:`ANTHROPIC_API_KEY`,或模型名以 `claude` 开头。
|
|
189
326
|
|
|
190
|
-
|
|
191
|
-
{
|
|
192
|
-
"ok": true,
|
|
193
|
-
"version": "0.3.0",
|
|
194
|
-
"runner": "mock",
|
|
195
|
-
"model": "gpt-4o-mini",
|
|
196
|
-
"suite": "demo",
|
|
197
|
-
"passed": 5,
|
|
198
|
-
"failed": 0,
|
|
199
|
-
"skipped": 0,
|
|
200
|
-
"duration_ms": 1,
|
|
201
|
-
"cases": [
|
|
202
|
-
{
|
|
203
|
-
"id": "greeting",
|
|
204
|
-
"ok": true,
|
|
205
|
-
"duration_ms": 1,
|
|
206
|
-
"output": "Hello",
|
|
207
|
-
"checks": [{ "name": "contains", "ok": true, "expected": "Hello" }]
|
|
208
|
-
}
|
|
209
|
-
]
|
|
210
|
-
}
|
|
211
|
-
```
|
|
212
|
-
|
|
213
|
-
Failed checks may include `actual` plus a multi-line `detail` (first-diff for `equals`).
|
|
214
|
-
|
|
215
|
-
## Programmatic API
|
|
327
|
+
### 库用法
|
|
216
328
|
|
|
217
329
|
```ts
|
|
218
330
|
import { loadSuite, runSuite, formatJUnit, initSuite } from "@webywz/eval-smoke";
|
|
@@ -224,21 +336,10 @@ console.log(formatJUnit(report));
|
|
|
224
336
|
if (!report.ok) process.exit(1);
|
|
225
337
|
```
|
|
226
338
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
## CI
|
|
339
|
+
### 链接
|
|
230
340
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
if: always()
|
|
237
|
-
with:
|
|
238
|
-
name: junit
|
|
239
|
-
path: junit.xml
|
|
240
|
-
```
|
|
241
|
-
|
|
242
|
-
## License
|
|
243
|
-
|
|
244
|
-
MIT
|
|
341
|
+
| | |
|
|
342
|
+
| --- | --- |
|
|
343
|
+
| npm | [npmjs.com/package/@webywz/eval-smoke](https://www.npmjs.com/package/@webywz/eval-smoke) |
|
|
344
|
+
| Issues | [github.com/webywz/eval-smoke/issues](https://github.com/webywz/eval-smoke/issues) |
|
|
345
|
+
| License | [MIT](./LICENSE) © webywz |
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { Report } from "./types.js";
|
|
2
|
+
export interface BaselineCase {
|
|
3
|
+
id: string;
|
|
4
|
+
ok: boolean;
|
|
5
|
+
}
|
|
6
|
+
export interface BaselineFile {
|
|
7
|
+
cases: BaselineCase[];
|
|
8
|
+
}
|
|
9
|
+
/** Minimal shape: case id → ok. Accepts a full Report or a slim baseline. */
|
|
10
|
+
export declare function loadBaseline(path: string): Map<string, boolean>;
|
|
11
|
+
export interface BaselineCheck {
|
|
12
|
+
ok: boolean;
|
|
13
|
+
regressions: string[];
|
|
14
|
+
/** Human-readable lines */
|
|
15
|
+
report: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Fail if any case that passed in baseline now fails, or a baseline case is missing
|
|
19
|
+
* from the current run. New cases are OK. Skipped current cases that passed in
|
|
20
|
+
* baseline count as missing/regression.
|
|
21
|
+
*/
|
|
22
|
+
export declare function checkBaseline(report: Report, baseline: Map<string, boolean>): BaselineCheck;
|
|
23
|
+
/** Pretty-print current report JSON for --update-baseline. */
|
|
24
|
+
export declare function writeBaseline(path: string, report: Report): void;
|
|
25
|
+
//# sourceMappingURL=baseline.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"baseline.d.ts","sourceRoot":"","sources":["../src/baseline.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAGzC,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,OAAO,CAAC;CACb;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,YAAY,EAAE,CAAC;CACvB;AAED,6EAA6E;AAC7E,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAmC/D;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,OAAO,CAAC;IACZ,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,2BAA2B;IAC3B,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,aAAa,CAgC3F;AAED,8DAA8D;AAC9D,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAEhE"}
|
package/dist/baseline.js
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { UsageError } from "./types.js";
|
|
3
|
+
/** Minimal shape: case id → ok. Accepts a full Report or a slim baseline. */
|
|
4
|
+
export function loadBaseline(path) {
|
|
5
|
+
let raw;
|
|
6
|
+
try {
|
|
7
|
+
raw = readFileSync(path, "utf8");
|
|
8
|
+
}
|
|
9
|
+
catch (error) {
|
|
10
|
+
const code = error && typeof error === "object" && "code" in error
|
|
11
|
+
? String(error.code)
|
|
12
|
+
: "";
|
|
13
|
+
if (code === "ENOENT")
|
|
14
|
+
throw new UsageError(`baseline not found: ${path}`);
|
|
15
|
+
throw error;
|
|
16
|
+
}
|
|
17
|
+
let parsed;
|
|
18
|
+
try {
|
|
19
|
+
parsed = JSON.parse(raw);
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
throw new UsageError(`baseline is not valid JSON: ${path}`);
|
|
23
|
+
}
|
|
24
|
+
if (!parsed || typeof parsed !== "object") {
|
|
25
|
+
throw new UsageError(`baseline must be a JSON object: ${path}`);
|
|
26
|
+
}
|
|
27
|
+
const cases = parsed.cases;
|
|
28
|
+
if (!Array.isArray(cases)) {
|
|
29
|
+
throw new UsageError(`baseline missing cases[]: ${path}`);
|
|
30
|
+
}
|
|
31
|
+
const map = new Map();
|
|
32
|
+
for (const entry of cases) {
|
|
33
|
+
if (!entry || typeof entry !== "object")
|
|
34
|
+
continue;
|
|
35
|
+
const id = entry.id;
|
|
36
|
+
const ok = entry.ok;
|
|
37
|
+
if (typeof id !== "string" || !id)
|
|
38
|
+
continue;
|
|
39
|
+
if (typeof ok !== "boolean")
|
|
40
|
+
continue;
|
|
41
|
+
map.set(id, ok);
|
|
42
|
+
}
|
|
43
|
+
return map;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Fail if any case that passed in baseline now fails, or a baseline case is missing
|
|
47
|
+
* from the current run. New cases are OK. Skipped current cases that passed in
|
|
48
|
+
* baseline count as missing/regression.
|
|
49
|
+
*/
|
|
50
|
+
export function checkBaseline(report, baseline) {
|
|
51
|
+
const byId = new Map(report.cases.map((c) => [c.id, c]));
|
|
52
|
+
const regressions = [];
|
|
53
|
+
for (const [id, wasOk] of baseline) {
|
|
54
|
+
if (!wasOk)
|
|
55
|
+
continue; // only guard formerly-passing cases
|
|
56
|
+
const current = byId.get(id);
|
|
57
|
+
if (!current) {
|
|
58
|
+
regressions.push(`${id}: missing from current run (passed in baseline)`);
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
if (current.skipped) {
|
|
62
|
+
regressions.push(`${id}: skipped now (passed in baseline)`);
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
if (!current.ok) {
|
|
66
|
+
regressions.push(`${id}: was pass, now fail`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
const lines = ["baseline check:"];
|
|
70
|
+
if (regressions.length === 0) {
|
|
71
|
+
lines.push(" ok — no regressions vs baseline");
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
lines.push(` ${regressions.length} regression(s):`);
|
|
75
|
+
for (const line of regressions) {
|
|
76
|
+
lines.push(` - ${line}`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
lines.push("");
|
|
80
|
+
return { ok: regressions.length === 0, regressions, report: lines.join("\n") };
|
|
81
|
+
}
|
|
82
|
+
/** Pretty-print current report JSON for --update-baseline. */
|
|
83
|
+
export function writeBaseline(path, report) {
|
|
84
|
+
writeFileSync(path, `${JSON.stringify(report, null, 2)}\n`, "utf8");
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=baseline.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"baseline.js","sourceRoot":"","sources":["../src/baseline.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAEtD,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAWxC,6EAA6E;AAC7E,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACH,GAAG,GAAG,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACnC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,GACR,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,IAAI,KAAK;YACnD,CAAC,CAAC,MAAM,CAAE,KAA2B,CAAC,IAAI,CAAC;YAC3C,CAAC,CAAC,EAAE,CAAC;QACT,IAAI,IAAI,KAAK,QAAQ;YAAE,MAAM,IAAI,UAAU,CAAC,uBAAuB,IAAI,EAAE,CAAC,CAAC;QAC3E,MAAM,KAAK,CAAC;IACd,CAAC;IACD,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC3B,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,UAAU,CAAC,+BAA+B,IAAI,EAAE,CAAC,CAAC;IAC9D,CAAC;IACD,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC1C,MAAM,IAAI,UAAU,CAAC,mCAAmC,IAAI,EAAE,CAAC,CAAC;IAClE,CAAC;IACD,MAAM,KAAK,GAAI,MAA8B,CAAC,KAAK,CAAC;IACpD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,UAAU,CAAC,6BAA6B,IAAI,EAAE,CAAC,CAAC;IAC5D,CAAC;IACD,MAAM,GAAG,GAAG,IAAI,GAAG,EAAmB,CAAC;IACvC,KAAK,MAAM,KAAK,IAAI,KAAK,EAAE,CAAC;QAC1B,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ;YAAE,SAAS;QAClD,MAAM,EAAE,GAAI,KAA0B,CAAC,EAAE,CAAC;QAC1C,MAAM,EAAE,GAAI,KAA0B,CAAC,EAAE,CAAC;QAC1C,IAAI,OAAO,EAAE,KAAK,QAAQ,IAAI,CAAC,EAAE;YAAE,SAAS;QAC5C,IAAI,OAAO,EAAE,KAAK,SAAS;YAAE,SAAS;QACtC,GAAG,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;IAClB,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AASD;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,MAAc,EAAE,QAA8B;IAC1E,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACzD,MAAM,WAAW,GAAa,EAAE,CAAC;IAEjC,KAAK,MAAM,CAAC,EAAE,EAAE,KAAK,CAAC,IAAI,QAAQ,EAAE,CAAC;QACnC,IAAI,CAAC,KAAK;YAAE,SAAS,CAAC,oCAAoC;QAC1D,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC7B,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,WAAW,CAAC,IAAI,CAAC,GAAG,EAAE,iDAAiD,CAAC,CAAC;YACzE,SAAS;QACX,CAAC;QACD,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;YACpB,WAAW,CAAC,IAAI,CAAC,GAAG,EAAE,oCAAoC,CAAC,CAAC;YAC5D,SAAS;QACX,CAAC;QACD,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC;YAChB,WAAW,CAAC,IAAI,CAAC,GAAG,EAAE,sBAAsB,CAAC,CAAC;QAChD,CAAC;IACH,CAAC;IAED,MAAM,KAAK,GAAG,CAAC,iBAAiB,CAAC,CAAC;IAClC,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC7B,KAAK,CAAC,IAAI,CAAC,mCAAmC,CAAC,CAAC;IAClD,CAAC;SAAM,CAAC;QACN,KAAK,CAAC,IAAI,CAAC,KAAK,WAAW,CAAC,MAAM,iBAAiB,CAAC,CAAC;QACrD,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;YAC/B,KAAK,CAAC,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAEf,OAAO,EAAE,EAAE,EAAE,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,WAAW,EAAE,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;AACjF,CAAC;AAED,8DAA8D;AAC9D,MAAM,UAAU,aAAa,CAAC,IAAY,EAAE,MAAc;IACxD,aAAa,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AACtE,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare const DEFAULT_GITHUB_SUMMARY = "github-step-summary.md";
|
|
2
|
+
export declare function resolveGithubSummaryPath(flagPath: string | true | undefined, env?: NodeJS.ProcessEnv, cwd?: string): string | undefined;
|
|
3
|
+
export declare function appendGithubSummary(path: string, markdown: string): void;
|
|
4
|
+
//# sourceMappingURL=github-summary.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github-summary.d.ts","sourceRoot":"","sources":["../src/github-summary.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,sBAAsB,2BAA2B,CAAC;AAE/D,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACnC,GAAG,GAAE,MAAM,CAAC,UAAwB,EACpC,GAAG,GAAE,MAAsB,GAC1B,MAAM,GAAG,SAAS,CAWpB;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAoBxE"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { appendFileSync, mkdirSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { dirname, resolve } from "node:path";
|
|
3
|
+
export const DEFAULT_GITHUB_SUMMARY = "github-step-summary.md";
|
|
4
|
+
export function resolveGithubSummaryPath(flagPath, env = process.env, cwd = process.cwd()) {
|
|
5
|
+
if (flagPath === undefined) {
|
|
6
|
+
const fromEnv = env.GITHUB_STEP_SUMMARY;
|
|
7
|
+
return fromEnv && fromEnv.trim() ? fromEnv : undefined;
|
|
8
|
+
}
|
|
9
|
+
if (flagPath === true || flagPath === "") {
|
|
10
|
+
const fromEnv = env.GITHUB_STEP_SUMMARY;
|
|
11
|
+
if (fromEnv && fromEnv.trim())
|
|
12
|
+
return fromEnv;
|
|
13
|
+
return resolve(cwd, DEFAULT_GITHUB_SUMMARY);
|
|
14
|
+
}
|
|
15
|
+
return resolve(cwd, flagPath);
|
|
16
|
+
}
|
|
17
|
+
export function appendGithubSummary(path, markdown) {
|
|
18
|
+
const body = markdown.endsWith("\n") ? markdown : `${markdown}\n`;
|
|
19
|
+
try {
|
|
20
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
// ignore
|
|
24
|
+
}
|
|
25
|
+
try {
|
|
26
|
+
appendFileSync(path, body, "utf8");
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
const code = error && typeof error === "object" && "code" in error
|
|
30
|
+
? String(error.code)
|
|
31
|
+
: "";
|
|
32
|
+
if (code === "ENOENT") {
|
|
33
|
+
writeFileSync(path, body, "utf8");
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
throw error;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=github-summary.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github-summary.js","sourceRoot":"","sources":["../src/github-summary.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACnE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAE7C,MAAM,CAAC,MAAM,sBAAsB,GAAG,wBAAwB,CAAC;AAE/D,MAAM,UAAU,wBAAwB,CACtC,QAAmC,EACnC,MAAyB,OAAO,CAAC,GAAG,EACpC,MAAc,OAAO,CAAC,GAAG,EAAE;IAE3B,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,MAAM,OAAO,GAAG,GAAG,CAAC,mBAAmB,CAAC;QACxC,OAAO,OAAO,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;IACzD,CAAC;IACD,IAAI,QAAQ,KAAK,IAAI,IAAI,QAAQ,KAAK,EAAE,EAAE,CAAC;QACzC,MAAM,OAAO,GAAG,GAAG,CAAC,mBAAmB,CAAC;QACxC,IAAI,OAAO,IAAI,OAAO,CAAC,IAAI,EAAE;YAAE,OAAO,OAAO,CAAC;QAC9C,OAAO,OAAO,CAAC,GAAG,EAAE,sBAAsB,CAAC,CAAC;IAC9C,CAAC;IACD,OAAO,OAAO,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,IAAY,EAAE,QAAgB;IAChE,MAAM,IAAI,GAAG,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,QAAQ,IAAI,CAAC;IAClE,IAAI,CAAC;QACH,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAChD,CAAC;IAAC,MAAM,CAAC;QACP,SAAS;IACX,CAAC;IACD,IAAI,CAAC;QACH,cAAc,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IACrC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,GACR,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,IAAI,KAAK;YACnD,CAAC,CAAC,MAAM,CAAE,KAA2B,CAAC,IAAI,CAAC;YAC3C,CAAC,CAAC,EAAE,CAAC;QACT,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;YACtB,aAAa,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;YAClC,OAAO;QACT,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -9,4 +9,8 @@ export { estimateTokens } from "./tokens.js";
|
|
|
9
9
|
export { VERSION } from "./version.js";
|
|
10
10
|
export type { Case, CaseResult, CheckName, CheckResult, CompleteFn, CompleteRequest, Expect, JsonExpect, ProviderName, Report, RunOptions, Suite, } from "./types.js";
|
|
11
11
|
export { UsageError } from "./types.js";
|
|
12
|
+
export { checkBaseline, loadBaseline, writeBaseline } from "./baseline.js";
|
|
13
|
+
export type { BaselineCheck, BaselineCase, BaselineFile } from "./baseline.js";
|
|
14
|
+
export { appendGithubSummary, resolveGithubSummaryPath, DEFAULT_GITHUB_SUMMARY } from "./github-summary.js";
|
|
15
|
+
export { formatGithubSummary } from "./summary-md.js";
|
|
12
16
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC5E,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAC1F,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAC/E,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACpC,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,YAAY,EACV,IAAI,EACJ,UAAU,EACV,SAAS,EACT,WAAW,EACX,UAAU,EACV,eAAe,EACf,MAAM,EACN,UAAU,EACV,YAAY,EACZ,MAAM,EACN,UAAU,EACV,KAAK,GACN,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC5E,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAC1F,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAC/E,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACpC,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,YAAY,EACV,IAAI,EACJ,UAAU,EACV,SAAS,EACT,WAAW,EACX,UAAU,EACV,eAAe,EACf,MAAM,EACN,UAAU,EACV,YAAY,EACZ,MAAM,EACN,UAAU,EACV,KAAK,GACN,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAExC,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC3E,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC/E,OAAO,EAAE,mBAAmB,EAAE,wBAAwB,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAC5G,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -8,4 +8,7 @@ export { runSuite } from "./run.js";
|
|
|
8
8
|
export { estimateTokens } from "./tokens.js";
|
|
9
9
|
export { VERSION } from "./version.js";
|
|
10
10
|
export { UsageError } from "./types.js";
|
|
11
|
+
export { checkBaseline, loadBaseline, writeBaseline } from "./baseline.js";
|
|
12
|
+
export { appendGithubSummary, resolveGithubSummaryPath, DEFAULT_GITHUB_SUMMARY } from "./github-summary.js";
|
|
13
|
+
export { formatGithubSummary } from "./summary-md.js";
|
|
11
14
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC5E,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAC1F,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAC/E,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACpC,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAevC,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC5E,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAC1F,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAC/E,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACpC,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAevC,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAExC,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAE3E,OAAO,EAAE,mBAAmB,EAAE,wBAAwB,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAC5G,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC"}
|
package/dist/run-cli.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type Suite } from "./types.js";
|
|
2
|
-
export declare const HELP = "eval-smoke \u2014 one-minute smoke evals for prompts and models\n\nUsage:\n eval-smoke <suite.yaml|suite.json> [options]\n eval-smoke init [dir] [--force]\n\nOptions:\n --mock Offline runner with deterministic fake answers\n --json Machine-readable JSON report\n --junit <path> Write JUnit XML report to path (still prints human report unless --json)\n --only <pattern> Run cases whose id contains pattern, or matches /regex/\n --fail-fast Stop after the first failing case\n --concurrency <n> Run up to N cases in parallel (default: 1; ignored with --fail-fast)\n --timeout <ms> Per-case timeout (default: 30000)\n --model <name> Override suite model\n --provider <name> openai | anthropic | mock\n --force Overwrite existing suite.yaml when using init\n --no-color Disable ANSI colors (also respects NO_COLOR)\n -h, --help Show this help\n -v, --version Show version\n\nExit codes:\n 0 all cases passed\n 1 one or more cases failed\n 2 usage or configuration error\n\nExamples:\n eval-smoke init\n eval-smoke init ./prompts --force\n eval-smoke examples/suite.yaml --mock\n eval-smoke examples/suite.yaml --mock --only greeting\n eval-smoke examples/suite.yaml --mock --only '/^capital/'\n eval-smoke examples/suite.yaml --mock --junit junit.xml\n eval-smoke examples/suite.yaml --json --fail-fast\n eval-smoke examples/suite.yaml --mock --concurrency 4\n OPENAI_API_KEY=sk-... eval-smoke examples/suite.yaml\n";
|
|
2
|
+
export declare const HELP = "eval-smoke \u2014 one-minute smoke evals for prompts and models\n\nUsage:\n eval-smoke <suite.yaml|suite.json> [options]\n eval-smoke init [dir] [--force]\n\nOptions:\n --mock Offline runner with deterministic fake answers\n --json Machine-readable JSON report\n --junit <path> Write JUnit XML report to path (still prints human report unless --json)\n --only <pattern> Run cases whose id contains pattern, or matches /regex/\n --fail-fast Stop after the first failing case\n --concurrency <n> Run up to N cases in parallel (default: 1; ignored with --fail-fast)\n --timeout <ms> Per-case timeout (default: 30000)\n --model <name> Override suite model\n --provider <name> openai | anthropic | mock\n --baseline <path> Fail if any baseline-passing case now fails or is missing\n --update-baseline <path> Write current report JSON to path (pretty)\n --github-summary [path] Append Markdown to GITHUB_STEP_SUMMARY or path\n --force Overwrite existing suite.yaml when using init\n --no-color Disable ANSI colors (also respects NO_COLOR)\n -h, --help Show this help\n -v, --version Show version\n\nExit codes:\n 0 all cases passed (and baseline clean when --baseline is set)\n 1 one or more cases failed, or baseline regression\n 2 usage or configuration error\n\nExamples:\n eval-smoke init\n eval-smoke init ./prompts --force\n eval-smoke examples/suite.yaml --mock\n eval-smoke examples/suite.yaml --mock --only greeting\n eval-smoke examples/suite.yaml --mock --only '/^capital/'\n eval-smoke examples/suite.yaml --mock --junit junit.xml\n eval-smoke examples/suite.yaml --json --fail-fast\n eval-smoke examples/suite.yaml --mock --concurrency 4\n eval-smoke examples/suite.yaml --mock --update-baseline baseline.json\n eval-smoke examples/suite.yaml --mock --baseline baseline.json\n eval-smoke examples/suite.yaml --mock --github-summary\n OPENAI_API_KEY=sk-... eval-smoke examples/suite.yaml\n";
|
|
3
3
|
export interface CliIo {
|
|
4
4
|
stdout: {
|
|
5
5
|
write(text: string): void;
|
|
@@ -14,5 +14,11 @@ export interface CliIo {
|
|
|
14
14
|
/** Match case ids by substring, or by /regex/ flags (same style as matchers). */
|
|
15
15
|
export declare function matchOnly(id: string, pattern: string): boolean;
|
|
16
16
|
export declare function filterSuiteByOnly(suite: Suite, pattern: string): Suite;
|
|
17
|
+
/**
|
|
18
|
+
* Rewrite bare `--github-summary` into `--github-summary=__auto__` so node:util
|
|
19
|
+
* parseArgs (string option) accepts it. `--github-summary=path` and
|
|
20
|
+
* `--github-summary path` stay as-is.
|
|
21
|
+
*/
|
|
22
|
+
export declare function normalizeGithubSummaryArgv(argv: string[]): string[];
|
|
17
23
|
export declare function runCli(argv: string[], io?: CliIo): Promise<number>;
|
|
18
24
|
//# sourceMappingURL=run-cli.d.ts.map
|
package/dist/run-cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-cli.d.ts","sourceRoot":"","sources":["../src/run-cli.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"run-cli.d.ts","sourceRoot":"","sources":["../src/run-cli.ts"],"names":[],"mappings":"AAYA,OAAO,EAAiC,KAAK,KAAK,EAAE,MAAM,YAAY,CAAC;AAMvE,eAAO,MAAM,IAAI,i/DA0ChB,CAAC;AAEF,MAAM,WAAW,KAAK;IACpB,MAAM,EAAE;QAAE,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;IACtC,MAAM,EAAE;QAAE,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;IACtC,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,OAAO,CAAC;CAChB;AAkCD,iFAAiF;AACjF,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAQ9D;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,GAAG,KAAK,CAMtE;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAiBnE;AAQD,wBAAsB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,GAAE,KAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,CAgIrF"}
|
package/dist/run-cli.js
CHANGED
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
import { writeFileSync } from "node:fs";
|
|
2
2
|
import { resolve } from "node:path";
|
|
3
3
|
import { parseArgs } from "node:util";
|
|
4
|
+
import { checkBaseline, loadBaseline, writeBaseline } from "./baseline.js";
|
|
5
|
+
import { appendGithubSummary, resolveGithubSummaryPath } from "./github-summary.js";
|
|
4
6
|
import { initSuite } from "./init.js";
|
|
5
7
|
import { formatJUnit } from "./junit.js";
|
|
6
8
|
import { loadSuite } from "./load-suite.js";
|
|
7
9
|
import { compileRegex } from "./matchers.js";
|
|
8
10
|
import { formatReport } from "./report.js";
|
|
9
11
|
import { DEFAULT_TIMEOUT_MS, runSuite } from "./run.js";
|
|
12
|
+
import { formatGithubSummary } from "./summary-md.js";
|
|
10
13
|
import { UsageError } from "./types.js";
|
|
11
14
|
import { VERSION } from "./version.js";
|
|
15
|
+
/** Sentinel so node:util accepts a bare --github-summary flag. */
|
|
16
|
+
const GITHUB_SUMMARY_AUTO = "__auto__";
|
|
12
17
|
export const HELP = `eval-smoke — one-minute smoke evals for prompts and models
|
|
13
18
|
|
|
14
19
|
Usage:
|
|
@@ -25,14 +30,17 @@ Options:
|
|
|
25
30
|
--timeout <ms> Per-case timeout (default: ${DEFAULT_TIMEOUT_MS})
|
|
26
31
|
--model <name> Override suite model
|
|
27
32
|
--provider <name> openai | anthropic | mock
|
|
33
|
+
--baseline <path> Fail if any baseline-passing case now fails or is missing
|
|
34
|
+
--update-baseline <path> Write current report JSON to path (pretty)
|
|
35
|
+
--github-summary [path] Append Markdown to GITHUB_STEP_SUMMARY or path
|
|
28
36
|
--force Overwrite existing suite.yaml when using init
|
|
29
37
|
--no-color Disable ANSI colors (also respects NO_COLOR)
|
|
30
38
|
-h, --help Show this help
|
|
31
39
|
-v, --version Show version
|
|
32
40
|
|
|
33
41
|
Exit codes:
|
|
34
|
-
0 all cases passed
|
|
35
|
-
1 one or more cases failed
|
|
42
|
+
0 all cases passed (and baseline clean when --baseline is set)
|
|
43
|
+
1 one or more cases failed, or baseline regression
|
|
36
44
|
2 usage or configuration error
|
|
37
45
|
|
|
38
46
|
Examples:
|
|
@@ -44,6 +52,9 @@ Examples:
|
|
|
44
52
|
eval-smoke examples/suite.yaml --mock --junit junit.xml
|
|
45
53
|
eval-smoke examples/suite.yaml --json --fail-fast
|
|
46
54
|
eval-smoke examples/suite.yaml --mock --concurrency 4
|
|
55
|
+
eval-smoke examples/suite.yaml --mock --update-baseline baseline.json
|
|
56
|
+
eval-smoke examples/suite.yaml --mock --baseline baseline.json
|
|
57
|
+
eval-smoke examples/suite.yaml --mock --github-summary
|
|
47
58
|
OPENAI_API_KEY=sk-... eval-smoke examples/suite.yaml
|
|
48
59
|
`;
|
|
49
60
|
const defaultIo = () => ({
|
|
@@ -95,11 +106,42 @@ export function filterSuiteByOnly(suite, pattern) {
|
|
|
95
106
|
}
|
|
96
107
|
return { ...suite, cases };
|
|
97
108
|
}
|
|
109
|
+
/**
|
|
110
|
+
* Rewrite bare `--github-summary` into `--github-summary=__auto__` so node:util
|
|
111
|
+
* parseArgs (string option) accepts it. `--github-summary=path` and
|
|
112
|
+
* `--github-summary path` stay as-is.
|
|
113
|
+
*/
|
|
114
|
+
export function normalizeGithubSummaryArgv(argv) {
|
|
115
|
+
const out = [];
|
|
116
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
117
|
+
const token = argv[i];
|
|
118
|
+
if (token === "--github-summary") {
|
|
119
|
+
const next = argv[i + 1];
|
|
120
|
+
if (!next || next.startsWith("-")) {
|
|
121
|
+
out.push(`--github-summary=${GITHUB_SUMMARY_AUTO}`);
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
out.push("--github-summary", next);
|
|
125
|
+
i += 1;
|
|
126
|
+
}
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
out.push(token);
|
|
130
|
+
}
|
|
131
|
+
return out;
|
|
132
|
+
}
|
|
133
|
+
function githubSummaryFlag(raw) {
|
|
134
|
+
if (raw == null)
|
|
135
|
+
return undefined;
|
|
136
|
+
if (raw === GITHUB_SUMMARY_AUTO)
|
|
137
|
+
return true;
|
|
138
|
+
return raw;
|
|
139
|
+
}
|
|
98
140
|
export async function runCli(argv, io = defaultIo()) {
|
|
99
141
|
let parsed;
|
|
100
142
|
try {
|
|
101
143
|
parsed = parseArgs({
|
|
102
|
-
args: argv,
|
|
144
|
+
args: normalizeGithubSummaryArgv(argv),
|
|
103
145
|
allowPositionals: true,
|
|
104
146
|
strict: true,
|
|
105
147
|
options: {
|
|
@@ -112,6 +154,9 @@ export async function runCli(argv, io = defaultIo()) {
|
|
|
112
154
|
timeout: { type: "string" },
|
|
113
155
|
model: { type: "string" },
|
|
114
156
|
provider: { type: "string" },
|
|
157
|
+
baseline: { type: "string" },
|
|
158
|
+
"update-baseline": { type: "string" },
|
|
159
|
+
"github-summary": { type: "string" },
|
|
115
160
|
force: { type: "boolean", default: false },
|
|
116
161
|
"no-color": { type: "boolean", default: false },
|
|
117
162
|
help: { type: "boolean", short: "h", default: false },
|
|
@@ -158,6 +203,9 @@ export async function runCli(argv, io = defaultIo()) {
|
|
|
158
203
|
const json = asBool(values.json);
|
|
159
204
|
const only = asString(values.only);
|
|
160
205
|
const junitPath = asString(values.junit);
|
|
206
|
+
const baselinePath = asString(values.baseline);
|
|
207
|
+
const updateBaselinePath = asString(values["update-baseline"]);
|
|
208
|
+
const githubSummary = githubSummaryFlag(asString(values["github-summary"]));
|
|
161
209
|
let suite = loadSuite(suitePath, io.cwd);
|
|
162
210
|
if (only != null) {
|
|
163
211
|
suite = filterSuiteByOnly(suite, only);
|
|
@@ -175,9 +223,36 @@ export async function runCli(argv, io = defaultIo()) {
|
|
|
175
223
|
const out = resolve(io.cwd, junitPath);
|
|
176
224
|
writeFileSync(out, formatJUnit(report), "utf8");
|
|
177
225
|
}
|
|
226
|
+
if (updateBaselinePath != null) {
|
|
227
|
+
const out = resolve(io.cwd, updateBaselinePath);
|
|
228
|
+
writeBaseline(out, report);
|
|
229
|
+
io.stderr.write(`Wrote baseline ${out}\n`);
|
|
230
|
+
}
|
|
231
|
+
let baselineFailed = false;
|
|
232
|
+
if (baselinePath != null) {
|
|
233
|
+
const baseline = loadBaseline(resolve(io.cwd, baselinePath));
|
|
234
|
+
const check = checkBaseline(report, baseline);
|
|
235
|
+
io.stderr.write(check.report);
|
|
236
|
+
if (!check.ok)
|
|
237
|
+
baselineFailed = true;
|
|
238
|
+
}
|
|
239
|
+
const outSummary = githubSummary === undefined
|
|
240
|
+
? resolveGithubSummaryPath(undefined, io.env, io.cwd)
|
|
241
|
+
: resolveGithubSummaryPath(githubSummary, io.env, io.cwd);
|
|
242
|
+
if (outSummary) {
|
|
243
|
+
try {
|
|
244
|
+
appendGithubSummary(outSummary, formatGithubSummary(report));
|
|
245
|
+
}
|
|
246
|
+
catch (error) {
|
|
247
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
248
|
+
io.stderr.write(`could not write github summary: ${message}\n`);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
178
251
|
const noColor = asBool(values["no-color"]) || Boolean(io.env.NO_COLOR);
|
|
179
252
|
const color = io.isTTY && !json && !noColor;
|
|
180
253
|
io.stdout.write(formatReport(report, { json, color }));
|
|
254
|
+
if (baselineFailed)
|
|
255
|
+
return 1;
|
|
181
256
|
return report.ok ? 0 : 1;
|
|
182
257
|
}
|
|
183
258
|
catch (error) {
|
package/dist/run-cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-cli.js","sourceRoot":"","sources":["../src/run-cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACxC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,kBAAkB,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACxD,OAAO,EAAE,UAAU,EAAiC,MAAM,YAAY,CAAC;AACvE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,MAAM,CAAC,MAAM,IAAI,GAAG;;;;;;;;;;;;;mDAa+B,kBAAkB
|
|
1
|
+
{"version":3,"file":"run-cli.js","sourceRoot":"","sources":["../src/run-cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"summary-md.d.ts","sourceRoot":"","sources":["../src/summary-md.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEzC,wEAAwE;AACxE,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAoB1D"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/** Concise pass/fail Markdown table for GitHub Actions step summary. */
|
|
2
|
+
export function formatGithubSummary(report) {
|
|
3
|
+
const lines = [];
|
|
4
|
+
lines.push(`### eval-smoke · ${escape(report.suite ?? "suite")}`);
|
|
5
|
+
lines.push("");
|
|
6
|
+
lines.push(`**${report.passed} passed · ${report.failed} failed${report.skipped ? ` · ${report.skipped} skipped` : ""} · ${report.duration_ms}ms** · \`${report.runner}\` / \`${escape(report.model)}\``);
|
|
7
|
+
lines.push("");
|
|
8
|
+
lines.push("| Case | Result | ms |");
|
|
9
|
+
lines.push("| --- | --- | ---: |");
|
|
10
|
+
for (const c of report.cases) {
|
|
11
|
+
const status = c.skipped ? "skip" : c.ok ? "✅ pass" : "❌ fail";
|
|
12
|
+
lines.push(`| \`${escape(c.id)}\` | ${status} | ${c.duration_ms} |`);
|
|
13
|
+
}
|
|
14
|
+
lines.push("");
|
|
15
|
+
lines.push(report.ok ? "**Suite: PASS**" : "**Suite: FAIL**");
|
|
16
|
+
lines.push("");
|
|
17
|
+
return lines.join("\n");
|
|
18
|
+
}
|
|
19
|
+
function escape(text) {
|
|
20
|
+
return text.replace(/\|/g, "\\|").replace(/\r?\n/g, " ");
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=summary-md.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"summary-md.js","sourceRoot":"","sources":["../src/summary-md.ts"],"names":[],"mappings":"AAEA,wEAAwE;AACxE,MAAM,UAAU,mBAAmB,CAAC,MAAc;IAChD,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,CAAC,IAAI,CAAC,oBAAoB,MAAM,CAAC,MAAM,CAAC,KAAK,IAAI,OAAO,CAAC,EAAE,CAAC,CAAC;IAClE,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CACR,KAAK,MAAM,CAAC,MAAM,aAAa,MAAM,CAAC,MAAM,UAC1C,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,MAAM,CAAC,OAAO,UAAU,CAAC,CAAC,CAAC,EACpD,MAAM,MAAM,CAAC,WAAW,YAAY,MAAM,CAAC,MAAM,UAAU,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CACpF,CAAC;IACF,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC;IACrC,KAAK,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;IACnC,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QAC7B,MAAM,MAAM,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC;QAC/D,KAAK,CAAC,IAAI,CAAC,OAAO,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,QAAQ,MAAM,MAAM,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC;IACvE,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC;IAC9D,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,SAAS,MAAM,CAAC,IAAY;IAC1B,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;AAC3D,CAAC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Copy-paste: run eval-smoke in GitHub Actions (mock offline + JUnit + step summary).
|
|
2
|
+
# No clone of this repo required — npx pulls @webywz/eval-smoke from npm.
|
|
3
|
+
#
|
|
4
|
+
# Human report → stdout (job log). JUnit → file. Markdown → $GITHUB_STEP_SUMMARY.
|
|
5
|
+
|
|
6
|
+
name: Smoke eval with eval-smoke
|
|
7
|
+
|
|
8
|
+
on:
|
|
9
|
+
workflow_dispatch:
|
|
10
|
+
# Or: push / pull_request when you have a suite.yaml in the repo.
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
eval:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
|
+
|
|
18
|
+
- uses: actions/setup-node@v4
|
|
19
|
+
with:
|
|
20
|
+
node-version: 22
|
|
21
|
+
|
|
22
|
+
# Offline smoke against the published example suite (no API key):
|
|
23
|
+
- name: Mock smoke + JUnit + step summary
|
|
24
|
+
run: |
|
|
25
|
+
npx --yes @webywz/eval-smoke --help >/dev/null
|
|
26
|
+
# Prefer a suite checked into YOUR repo; this uses the package example via init:
|
|
27
|
+
npx --yes @webywz/eval-smoke init ./eval-smoke-ci --force
|
|
28
|
+
npx --yes @webywz/eval-smoke ./eval-smoke-ci/suite.yaml \
|
|
29
|
+
--mock \
|
|
30
|
+
--junit junit-eval-smoke.xml \
|
|
31
|
+
--github-summary \
|
|
32
|
+
--update-baseline eval-smoke-baseline.json
|
|
33
|
+
|
|
34
|
+
- name: Upload JUnit
|
|
35
|
+
if: always()
|
|
36
|
+
uses: actions/upload-artifact@v4
|
|
37
|
+
with:
|
|
38
|
+
name: eval-smoke-junit
|
|
39
|
+
path: |
|
|
40
|
+
junit-eval-smoke.xml
|
|
41
|
+
eval-smoke-baseline.json
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webywz/eval-smoke",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "One-minute smoke evals for prompts and models
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"description": "One-minute smoke evals for prompts and models \u2014 equals/json matchers, diffs, concurrency, JUnit, init.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"eval-smoke": "dist/cli.js"
|