snapeval 1.0.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/LICENSE +21 -0
- package/README.md +194 -0
- package/bin/snapeval.ts +226 -0
- package/dist/bin/snapeval.d.ts +2 -0
- package/dist/bin/snapeval.js +191 -0
- package/dist/bin/snapeval.js.map +1 -0
- package/dist/src/adapters/inference/copilot.d.ts +9 -0
- package/dist/src/adapters/inference/copilot.js +25 -0
- package/dist/src/adapters/inference/copilot.js.map +1 -0
- package/dist/src/adapters/inference/github-models.d.ts +9 -0
- package/dist/src/adapters/inference/github-models.js +62 -0
- package/dist/src/adapters/inference/github-models.js.map +1 -0
- package/dist/src/adapters/inference/resolve.d.ts +2 -0
- package/dist/src/adapters/inference/resolve.js +49 -0
- package/dist/src/adapters/inference/resolve.js.map +1 -0
- package/dist/src/adapters/report/json.d.ts +7 -0
- package/dist/src/adapters/report/json.js +39 -0
- package/dist/src/adapters/report/json.js.map +1 -0
- package/dist/src/adapters/report/terminal.d.ts +5 -0
- package/dist/src/adapters/report/terminal.js +42 -0
- package/dist/src/adapters/report/terminal.js.map +1 -0
- package/dist/src/adapters/skill/copilot-cli.d.ts +6 -0
- package/dist/src/adapters/skill/copilot-cli.js +51 -0
- package/dist/src/adapters/skill/copilot-cli.js.map +1 -0
- package/dist/src/commands/approve.d.ts +5 -0
- package/dist/src/commands/approve.js +40 -0
- package/dist/src/commands/approve.js.map +1 -0
- package/dist/src/commands/capture.d.ts +4 -0
- package/dist/src/commands/capture.js +18 -0
- package/dist/src/commands/capture.js.map +1 -0
- package/dist/src/commands/check.d.ts +6 -0
- package/dist/src/commands/check.js +68 -0
- package/dist/src/commands/check.js.map +1 -0
- package/dist/src/commands/init.d.ts +2 -0
- package/dist/src/commands/init.js +27 -0
- package/dist/src/commands/init.js.map +1 -0
- package/dist/src/commands/report.d.ts +4 -0
- package/dist/src/commands/report.js +26 -0
- package/dist/src/commands/report.js.map +1 -0
- package/dist/src/config.d.ts +3 -0
- package/dist/src/config.js +30 -0
- package/dist/src/config.js.map +1 -0
- package/dist/src/engine/budget.d.ts +10 -0
- package/dist/src/engine/budget.js +25 -0
- package/dist/src/engine/budget.js.map +1 -0
- package/dist/src/engine/comparison/embedding.d.ts +6 -0
- package/dist/src/engine/comparison/embedding.js +19 -0
- package/dist/src/engine/comparison/embedding.js.map +1 -0
- package/dist/src/engine/comparison/judge.d.ts +8 -0
- package/dist/src/engine/comparison/judge.js +64 -0
- package/dist/src/engine/comparison/judge.js.map +1 -0
- package/dist/src/engine/comparison/pipeline.d.ts +6 -0
- package/dist/src/engine/comparison/pipeline.js +31 -0
- package/dist/src/engine/comparison/pipeline.js.map +1 -0
- package/dist/src/engine/comparison/schema.d.ts +2 -0
- package/dist/src/engine/comparison/schema.js +28 -0
- package/dist/src/engine/comparison/schema.js.map +1 -0
- package/dist/src/engine/comparison/variance.d.ts +3 -0
- package/dist/src/engine/comparison/variance.js +26 -0
- package/dist/src/engine/comparison/variance.js.map +1 -0
- package/dist/src/engine/generator.d.ts +3 -0
- package/dist/src/engine/generator.js +52 -0
- package/dist/src/engine/generator.js.map +1 -0
- package/dist/src/engine/snapshot.d.ts +11 -0
- package/dist/src/engine/snapshot.js +46 -0
- package/dist/src/engine/snapshot.js.map +1 -0
- package/dist/src/errors.d.ts +16 -0
- package/dist/src/errors.js +33 -0
- package/dist/src/errors.js.map +1 -0
- package/dist/src/types.d.ts +125 -0
- package/dist/src/types.js +2 -0
- package/dist/src/types.js.map +1 -0
- package/package.json +53 -0
- package/plugin.json +9 -0
- package/scripts/snapeval-cli.sh +7 -0
- package/skills/snapeval/SKILL.md +51 -0
- package/src/adapters/inference/copilot.ts +30 -0
- package/src/adapters/inference/github-models.ts +74 -0
- package/src/adapters/inference/resolve.ts +70 -0
- package/src/adapters/report/json.ts +64 -0
- package/src/adapters/report/terminal.ts +59 -0
- package/src/adapters/skill/copilot-cli.ts +60 -0
- package/src/commands/approve.ts +58 -0
- package/src/commands/capture.ts +25 -0
- package/src/commands/check.ts +86 -0
- package/src/commands/init.ts +38 -0
- package/src/commands/report.ts +36 -0
- package/src/config.ts +37 -0
- package/src/engine/budget.ts +27 -0
- package/src/engine/comparison/embedding.ts +26 -0
- package/src/engine/comparison/judge.ts +78 -0
- package/src/engine/comparison/pipeline.ts +43 -0
- package/src/engine/comparison/schema.ts +22 -0
- package/src/engine/comparison/variance.ts +31 -0
- package/src/engine/generator.ts +61 -0
- package/src/engine/snapshot.ts +48 -0
- package/src/errors.ts +34 -0
- package/src/types.ts +153 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Matan Tsach
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
# snapeval
|
|
2
|
+
|
|
3
|
+
Semantic snapshot testing for AI skills. Zero assertions. AI-driven. Free inference.
|
|
4
|
+
|
|
5
|
+
[](https://github.com/matantsach/snapeval/actions/workflows/ci.yml)
|
|
6
|
+
[](https://www.npmjs.com/package/snapeval)
|
|
7
|
+
[](https://opensource.org/licenses/MIT)
|
|
8
|
+
|
|
9
|
+
snapeval evaluates [agentskills.io](https://agentskills.io) skills through semantic snapshot testing. It generates test cases from your skill's `SKILL.md`, captures baseline outputs, and detects regressions through a tiered comparison pipeline — all with zero manual test authoring.
|
|
10
|
+
|
|
11
|
+
## Why snapeval?
|
|
12
|
+
|
|
13
|
+
- **Zero assertions** — AI generates test cases from your SKILL.md. You never write test logic.
|
|
14
|
+
- **Semantic comparison** — Three-tier pipeline: schema check (free) → embedding similarity (cheap) → LLM judge with order-swap debiasing (expensive). Most checks cost $0.
|
|
15
|
+
- **Free inference** — Uses gpt-5-mini via Copilot CLI (0x multiplier on paid plans) and GitHub Models API (free with GITHUB_TOKEN).
|
|
16
|
+
- **Non-determinism handling** — Variance envelope from N baseline runs prevents false regressions.
|
|
17
|
+
- **Platform-agnostic** — Adapter-based architecture. Copilot CLI first, Claude Code and others coming.
|
|
18
|
+
|
|
19
|
+
## Quick Start
|
|
20
|
+
|
|
21
|
+
### As a Copilot CLI Plugin
|
|
22
|
+
|
|
23
|
+
Install directly from the GitHub repo:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
gh copilot -- plugin install matantsach/snapeval
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Or register the marketplace first, then install by name:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
gh copilot -- plugin marketplace add matantsach/snapeval
|
|
33
|
+
gh copilot -- plugin install snapeval@snapeval-marketplace
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Then in Copilot CLI interactive mode, just ask naturally:
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
> evaluate my code-reviewer skill
|
|
40
|
+
> check skills/code-reviewer for regressions
|
|
41
|
+
> approve scenario 3
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
The agent will use the snapeval skill automatically based on your prompt.
|
|
45
|
+
|
|
46
|
+
### As a CLI
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
npx snapeval init <skill-path> # AI generates test cases from SKILL.md
|
|
50
|
+
npx snapeval capture <skill-path> # Run tests, save baseline snapshots
|
|
51
|
+
npx snapeval check <skill-path> # Compare current output to baselines
|
|
52
|
+
npx snapeval approve [--scenario N] # Accept new behavior as baseline
|
|
53
|
+
npx snapeval report <skill-path> # Generate benchmark.json
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Local Development
|
|
57
|
+
|
|
58
|
+
For development without `npx`, clone and use `tsx` directly:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
git clone https://github.com/matantsach/snapeval.git
|
|
62
|
+
cd snapeval && npm install
|
|
63
|
+
npx tsx bin/snapeval.ts init <skill-path>
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Or load as a local plugin during development:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
gh copilot -- --plugin-dir /path/to/snapeval
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### In CI
|
|
73
|
+
|
|
74
|
+
Commit your `evals.json` and `snapshots/` directory, then add a workflow:
|
|
75
|
+
|
|
76
|
+
```yaml
|
|
77
|
+
# .github/workflows/skill-eval.yml
|
|
78
|
+
name: Skill Evaluation
|
|
79
|
+
on: [pull_request]
|
|
80
|
+
|
|
81
|
+
jobs:
|
|
82
|
+
eval:
|
|
83
|
+
runs-on: ubuntu-latest
|
|
84
|
+
steps:
|
|
85
|
+
- uses: actions/checkout@v4
|
|
86
|
+
- uses: actions/setup-node@v4
|
|
87
|
+
with:
|
|
88
|
+
node-version: 22
|
|
89
|
+
- run: npm ci
|
|
90
|
+
- run: npx tsx bin/snapeval.ts check skills/my-skill --ci --skip-embedding
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
> **Note:** The `--skip-embedding` flag runs Tier 1 (schema) and Tier 3 (LLM judge) only, skipping Tier 2 which requires the GitHub Models embedding API. For Tier 1-only checks (fastest, free, no API needed), committed baselines with stable output structures will pass without any inference calls.
|
|
94
|
+
|
|
95
|
+
## How It Works
|
|
96
|
+
|
|
97
|
+
```
|
|
98
|
+
SKILL.md → AI generates test scenarios → Capture baseline snapshots
|
|
99
|
+
↓
|
|
100
|
+
Modify skill → Re-run scenarios → Compare via tiered pipeline
|
|
101
|
+
↓
|
|
102
|
+
Schema match? → PASS (free, instant)
|
|
103
|
+
Embedding > 0.85? → PASS (cheap)
|
|
104
|
+
LLM Judge agrees? → PASS/REGRESSED (expensive)
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Comparison Pipeline
|
|
108
|
+
|
|
109
|
+
| Tier | Method | Cost | When Used |
|
|
110
|
+
|------|--------|------|-----------|
|
|
111
|
+
| 1 | Schema check | Free | Structural skeleton matches |
|
|
112
|
+
| 2 | Embedding similarity | Cheap | Schema differs but meaning similar |
|
|
113
|
+
| 3 | LLM judge (order-swap) | Expensive | Ambiguous cases only |
|
|
114
|
+
|
|
115
|
+
Most stable skills are checked entirely at Tier 1 — $0.00 per run.
|
|
116
|
+
|
|
117
|
+
## Eval Format
|
|
118
|
+
|
|
119
|
+
snapeval follows the [agentskills.io evaluation standard](https://agentskills.io/skill-creation/evaluating-skills):
|
|
120
|
+
|
|
121
|
+
```
|
|
122
|
+
my-skill/
|
|
123
|
+
├── SKILL.md
|
|
124
|
+
└── evals/
|
|
125
|
+
├── evals.json ← AI-generated test cases
|
|
126
|
+
├── snapshots/ ← Captured baseline outputs
|
|
127
|
+
└── results/
|
|
128
|
+
└── iteration-N/
|
|
129
|
+
├── grading.json
|
|
130
|
+
├── timing.json
|
|
131
|
+
└── benchmark.json
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Configuration
|
|
135
|
+
|
|
136
|
+
Create `snapeval.config.json` in your skill or project root:
|
|
137
|
+
|
|
138
|
+
```json
|
|
139
|
+
{
|
|
140
|
+
"adapter": "copilot-cli",
|
|
141
|
+
"inference": "auto",
|
|
142
|
+
"threshold": 0.85,
|
|
143
|
+
"runs": 3,
|
|
144
|
+
"budget": "unlimited"
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
CLI flags override config file values.
|
|
149
|
+
|
|
150
|
+
## CLI Reference
|
|
151
|
+
|
|
152
|
+
```
|
|
153
|
+
snapeval init [skill-dir] Generate test cases from SKILL.md using AI
|
|
154
|
+
snapeval capture [skill-dir] Run skill against all scenarios, save baselines
|
|
155
|
+
snapeval check [skill-dir] Compare current output against baselines
|
|
156
|
+
snapeval approve [skill-dir] Approve regressed scenarios as new baselines
|
|
157
|
+
snapeval report [skill-dir] Write results to evals/results/iteration-N/
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
**Common flags:**
|
|
161
|
+
|
|
162
|
+
| Flag | Description | Default |
|
|
163
|
+
|------|-------------|---------|
|
|
164
|
+
| `--adapter <name>` | Skill adapter | `copilot-cli` |
|
|
165
|
+
| `--inference <name>` | Inference adapter | `auto` |
|
|
166
|
+
| `--threshold <n>` | Embedding similarity threshold | `0.85` |
|
|
167
|
+
| `--budget <amount>` | Spend cap in USD | `unlimited` |
|
|
168
|
+
| `--runs <n>` | Baseline runs per scenario | `1` |
|
|
169
|
+
| `--ci` | CI mode: exit 1 on regressions | off |
|
|
170
|
+
| `--skip-embedding` | Skip Tier 2 (embedding) | off |
|
|
171
|
+
| `--scenario <ids>` | Comma-separated scenario IDs | all |
|
|
172
|
+
| `--verbose` | Verbose output | off |
|
|
173
|
+
|
|
174
|
+
## Architecture
|
|
175
|
+
|
|
176
|
+
Three surfaces over a shared core engine:
|
|
177
|
+
|
|
178
|
+
- **Plugin** (SKILL.md) — Interactive product. AI handles everything.
|
|
179
|
+
- **CLI** (`npx snapeval`) — Headless backend for CI and power users.
|
|
180
|
+
- **GitHub Action** — CI wrapper (coming in v2).
|
|
181
|
+
|
|
182
|
+
Three adapter layers for platform independence:
|
|
183
|
+
|
|
184
|
+
- **SkillAdapter** — How to invoke a skill (Copilot CLI, Claude Code, generic)
|
|
185
|
+
- **InferenceAdapter** — Where to get LLM capabilities (Copilot gpt-5-mini, GitHub Models API)
|
|
186
|
+
- **ReportAdapter** — How to present results (terminal, JSON, PR comment)
|
|
187
|
+
|
|
188
|
+
## Contributing
|
|
189
|
+
|
|
190
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
|
|
191
|
+
|
|
192
|
+
## License
|
|
193
|
+
|
|
194
|
+
[MIT](LICENSE)
|
package/bin/snapeval.ts
ADDED
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import { resolveConfig } from '../src/config.js';
|
|
4
|
+
import { resolveInference } from '../src/adapters/inference/resolve.js';
|
|
5
|
+
import { CopilotCLIAdapter } from '../src/adapters/skill/copilot-cli.js';
|
|
6
|
+
import { TerminalReporter } from '../src/adapters/report/terminal.js';
|
|
7
|
+
import { initCommand } from '../src/commands/init.js';
|
|
8
|
+
import { captureCommand } from '../src/commands/capture.js';
|
|
9
|
+
import { checkCommand } from '../src/commands/check.js';
|
|
10
|
+
import { approveCommand, approveFromResults } from '../src/commands/approve.js';
|
|
11
|
+
import { reportCommand } from '../src/commands/report.js';
|
|
12
|
+
import { SnapevalError } from '../src/errors.js';
|
|
13
|
+
import * as path from 'node:path';
|
|
14
|
+
|
|
15
|
+
const program = new Command();
|
|
16
|
+
|
|
17
|
+
program
|
|
18
|
+
.name('snapeval')
|
|
19
|
+
.description('Semantic snapshot testing for AI skills')
|
|
20
|
+
.version('1.0.0');
|
|
21
|
+
|
|
22
|
+
// --- init ---
|
|
23
|
+
program
|
|
24
|
+
.command('init')
|
|
25
|
+
.description('Generate test cases from SKILL.md using AI')
|
|
26
|
+
.option('--adapter <adapter>', 'Skill adapter to use', 'copilot-cli')
|
|
27
|
+
.option('--inference <inference>', 'Inference adapter to use', 'auto')
|
|
28
|
+
.option('--verbose', 'Verbose output')
|
|
29
|
+
.argument('[skill-dir]', 'Path to skill directory', process.cwd())
|
|
30
|
+
.action(async (skillDir: string, opts: Record<string, string | boolean>) => {
|
|
31
|
+
try {
|
|
32
|
+
const skillPath = path.resolve(skillDir);
|
|
33
|
+
const config = resolveConfig(
|
|
34
|
+
{ adapter: opts.adapter as string, inference: opts.inference as string },
|
|
35
|
+
process.cwd(),
|
|
36
|
+
skillPath
|
|
37
|
+
);
|
|
38
|
+
const inference = resolveInference(config.inference);
|
|
39
|
+
await initCommand(skillPath, inference);
|
|
40
|
+
console.log(`Generated evals at ${path.join(skillPath, 'evals', 'evals.json')}`);
|
|
41
|
+
process.exit(0);
|
|
42
|
+
} catch (err) {
|
|
43
|
+
handleError(err);
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// --- capture ---
|
|
48
|
+
program
|
|
49
|
+
.command('capture')
|
|
50
|
+
.description('Run skill against all scenarios and save baseline snapshots')
|
|
51
|
+
.option('--adapter <adapter>', 'Skill adapter to use', 'copilot-cli')
|
|
52
|
+
.option('--inference <inference>', 'Inference adapter to use', 'auto')
|
|
53
|
+
.option('--runs <n>', 'Number of runs per scenario', '1')
|
|
54
|
+
.option('--verbose', 'Verbose output')
|
|
55
|
+
.argument('[skill-dir]', 'Path to skill directory', process.cwd())
|
|
56
|
+
.action(async (skillDir: string, opts: Record<string, string | boolean>) => {
|
|
57
|
+
try {
|
|
58
|
+
const skillPath = path.resolve(skillDir);
|
|
59
|
+
const config = resolveConfig(
|
|
60
|
+
{
|
|
61
|
+
adapter: opts.adapter as string,
|
|
62
|
+
inference: opts.inference as string,
|
|
63
|
+
runs: opts.runs ? parseInt(opts.runs as string, 10) : undefined,
|
|
64
|
+
},
|
|
65
|
+
process.cwd(),
|
|
66
|
+
skillPath
|
|
67
|
+
);
|
|
68
|
+
const skillAdapter = resolveSkillAdapter(config.adapter);
|
|
69
|
+
await captureCommand(skillPath, skillAdapter, { runs: config.runs });
|
|
70
|
+
console.log(`Captured baselines at ${path.join(skillPath, 'evals', 'snapshots')}`);
|
|
71
|
+
process.exit(0);
|
|
72
|
+
} catch (err) {
|
|
73
|
+
handleError(err);
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// --- check ---
|
|
78
|
+
program
|
|
79
|
+
.command('check')
|
|
80
|
+
.description('Compare current skill output against baselines')
|
|
81
|
+
.option('--adapter <adapter>', 'Skill adapter to use', 'copilot-cli')
|
|
82
|
+
.option('--inference <inference>', 'Inference adapter to use', 'auto')
|
|
83
|
+
.option('--threshold <n>', 'Similarity threshold (0–1)', '0.85')
|
|
84
|
+
.option('--budget <amount>', 'Spend cap in USD (or "unlimited")', 'unlimited')
|
|
85
|
+
.option('--ci', 'CI mode: exit 1 on regressions, no interactive prompts')
|
|
86
|
+
.option('--skip-embedding', 'Skip embedding tier (tier 2)')
|
|
87
|
+
.option('--verbose', 'Verbose output')
|
|
88
|
+
.option('--scenario <ids>', 'Comma-separated scenario IDs to check')
|
|
89
|
+
.argument('[skill-dir]', 'Path to skill directory', process.cwd())
|
|
90
|
+
.action(async (skillDir: string, opts: Record<string, string | boolean>) => {
|
|
91
|
+
try {
|
|
92
|
+
const skillPath = path.resolve(skillDir);
|
|
93
|
+
const config = resolveConfig(
|
|
94
|
+
{
|
|
95
|
+
adapter: opts.adapter as string,
|
|
96
|
+
inference: opts.inference as string,
|
|
97
|
+
threshold: opts.threshold ? parseFloat(opts.threshold as string) : undefined,
|
|
98
|
+
budget: opts.budget as string,
|
|
99
|
+
},
|
|
100
|
+
process.cwd(),
|
|
101
|
+
skillPath
|
|
102
|
+
);
|
|
103
|
+
const skillAdapter = resolveSkillAdapter(config.adapter);
|
|
104
|
+
const inference = resolveInference(config.inference);
|
|
105
|
+
|
|
106
|
+
const results = await checkCommand(skillPath, skillAdapter, inference, {
|
|
107
|
+
threshold: config.threshold,
|
|
108
|
+
budget: config.budget,
|
|
109
|
+
skipEmbedding: Boolean(opts.skipEmbedding),
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
// Always print terminal report
|
|
113
|
+
const reporter = new TerminalReporter();
|
|
114
|
+
await reporter.report(results);
|
|
115
|
+
|
|
116
|
+
const hasRegressions = results.summary.regressed > 0;
|
|
117
|
+
if (hasRegressions) {
|
|
118
|
+
process.exit(1);
|
|
119
|
+
}
|
|
120
|
+
process.exit(0);
|
|
121
|
+
} catch (err) {
|
|
122
|
+
handleError(err);
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
// --- approve ---
|
|
127
|
+
program
|
|
128
|
+
.command('approve')
|
|
129
|
+
.description('Approve regressed scenarios as new baselines')
|
|
130
|
+
.option('--adapter <adapter>', 'Skill adapter to use', 'copilot-cli')
|
|
131
|
+
.option('--inference <inference>', 'Inference adapter to use', 'auto')
|
|
132
|
+
.option('--scenario <ids>', 'Comma-separated scenario IDs to approve (default: all)')
|
|
133
|
+
.option('--verbose', 'Verbose output')
|
|
134
|
+
.argument('[skill-dir]', 'Path to skill directory', process.cwd())
|
|
135
|
+
.action(async (skillDir: string, opts: Record<string, string | boolean>) => {
|
|
136
|
+
try {
|
|
137
|
+
const skillPath = path.resolve(skillDir);
|
|
138
|
+
const config = resolveConfig(
|
|
139
|
+
{ adapter: opts.adapter as string, inference: opts.inference as string },
|
|
140
|
+
process.cwd(),
|
|
141
|
+
skillPath
|
|
142
|
+
);
|
|
143
|
+
const skillAdapter = resolveSkillAdapter(config.adapter);
|
|
144
|
+
|
|
145
|
+
const scenarioIds = opts.scenario
|
|
146
|
+
? (opts.scenario as string).split(',').map((s) => parseInt(s.trim(), 10))
|
|
147
|
+
: undefined;
|
|
148
|
+
|
|
149
|
+
await approveCommand(skillPath, skillAdapter, { scenarioIds });
|
|
150
|
+
console.log('Approved snapshots updated.');
|
|
151
|
+
process.exit(0);
|
|
152
|
+
} catch (err) {
|
|
153
|
+
handleError(err);
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
// --- report ---
|
|
158
|
+
program
|
|
159
|
+
.command('report')
|
|
160
|
+
.description('Write latest check results to evals/results/iteration-N/')
|
|
161
|
+
.option('--adapter <adapter>', 'Skill adapter to use', 'copilot-cli')
|
|
162
|
+
.option('--inference <inference>', 'Inference adapter to use', 'auto')
|
|
163
|
+
.option('--threshold <n>', 'Similarity threshold (0–1)', '0.85')
|
|
164
|
+
.option('--budget <amount>', 'Spend cap in USD (or "unlimited")', 'unlimited')
|
|
165
|
+
.option('--skip-embedding', 'Skip embedding tier (tier 2)')
|
|
166
|
+
.option('--verbose', 'Verbose output')
|
|
167
|
+
.argument('[skill-dir]', 'Path to skill directory', process.cwd())
|
|
168
|
+
.action(async (skillDir: string, opts: Record<string, string | boolean>) => {
|
|
169
|
+
try {
|
|
170
|
+
const skillPath = path.resolve(skillDir);
|
|
171
|
+
const config = resolveConfig(
|
|
172
|
+
{
|
|
173
|
+
adapter: opts.adapter as string,
|
|
174
|
+
inference: opts.inference as string,
|
|
175
|
+
threshold: opts.threshold ? parseFloat(opts.threshold as string) : undefined,
|
|
176
|
+
budget: opts.budget as string,
|
|
177
|
+
},
|
|
178
|
+
process.cwd(),
|
|
179
|
+
skillPath
|
|
180
|
+
);
|
|
181
|
+
const skillAdapter = resolveSkillAdapter(config.adapter);
|
|
182
|
+
const inference = resolveInference(config.inference);
|
|
183
|
+
|
|
184
|
+
const results = await checkCommand(skillPath, skillAdapter, inference, {
|
|
185
|
+
threshold: config.threshold,
|
|
186
|
+
budget: config.budget,
|
|
187
|
+
skipEmbedding: Boolean(opts.skipEmbedding),
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
await reportCommand(skillPath, results, { verbose: Boolean(opts.verbose) });
|
|
191
|
+
|
|
192
|
+
const hasRegressions = results.summary.regressed > 0;
|
|
193
|
+
if (hasRegressions) {
|
|
194
|
+
process.exit(1);
|
|
195
|
+
}
|
|
196
|
+
process.exit(0);
|
|
197
|
+
} catch (err) {
|
|
198
|
+
handleError(err);
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
// --- helpers ---
|
|
203
|
+
|
|
204
|
+
function resolveSkillAdapter(adapterName: string) {
|
|
205
|
+
if (adapterName === 'copilot-cli') {
|
|
206
|
+
return new CopilotCLIAdapter();
|
|
207
|
+
}
|
|
208
|
+
throw new SnapevalError(
|
|
209
|
+
`Unknown skill adapter "${adapterName}". Valid options: copilot-cli.`
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function handleError(err: unknown): never {
|
|
214
|
+
if (err instanceof SnapevalError) {
|
|
215
|
+
console.error(`Error: ${err.message}`);
|
|
216
|
+
process.exit(err.exitCode ?? 2);
|
|
217
|
+
}
|
|
218
|
+
if (err instanceof Error) {
|
|
219
|
+
console.error(`Error: ${err.message}`);
|
|
220
|
+
process.exit(2);
|
|
221
|
+
}
|
|
222
|
+
console.error('An unknown error occurred.');
|
|
223
|
+
process.exit(2);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
program.parse(process.argv);
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import { resolveConfig } from '../src/config.js';
|
|
4
|
+
import { resolveInference } from '../src/adapters/inference/resolve.js';
|
|
5
|
+
import { CopilotCLIAdapter } from '../src/adapters/skill/copilot-cli.js';
|
|
6
|
+
import { TerminalReporter } from '../src/adapters/report/terminal.js';
|
|
7
|
+
import { initCommand } from '../src/commands/init.js';
|
|
8
|
+
import { captureCommand } from '../src/commands/capture.js';
|
|
9
|
+
import { checkCommand } from '../src/commands/check.js';
|
|
10
|
+
import { approveCommand } from '../src/commands/approve.js';
|
|
11
|
+
import { reportCommand } from '../src/commands/report.js';
|
|
12
|
+
import { SnapevalError } from '../src/errors.js';
|
|
13
|
+
import * as path from 'node:path';
|
|
14
|
+
const program = new Command();
|
|
15
|
+
program
|
|
16
|
+
.name('snapeval')
|
|
17
|
+
.description('Semantic snapshot testing for AI skills')
|
|
18
|
+
.version('1.0.0');
|
|
19
|
+
// --- init ---
|
|
20
|
+
program
|
|
21
|
+
.command('init')
|
|
22
|
+
.description('Generate test cases from SKILL.md using AI')
|
|
23
|
+
.option('--adapter <adapter>', 'Skill adapter to use', 'copilot-cli')
|
|
24
|
+
.option('--inference <inference>', 'Inference adapter to use', 'auto')
|
|
25
|
+
.option('--verbose', 'Verbose output')
|
|
26
|
+
.argument('[skill-dir]', 'Path to skill directory', process.cwd())
|
|
27
|
+
.action(async (skillDir, opts) => {
|
|
28
|
+
try {
|
|
29
|
+
const skillPath = path.resolve(skillDir);
|
|
30
|
+
const config = resolveConfig({ adapter: opts.adapter, inference: opts.inference }, process.cwd(), skillPath);
|
|
31
|
+
const inference = resolveInference(config.inference);
|
|
32
|
+
await initCommand(skillPath, inference);
|
|
33
|
+
console.log(`Generated evals at ${path.join(skillPath, 'evals', 'evals.json')}`);
|
|
34
|
+
process.exit(0);
|
|
35
|
+
}
|
|
36
|
+
catch (err) {
|
|
37
|
+
handleError(err);
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
// --- capture ---
|
|
41
|
+
program
|
|
42
|
+
.command('capture')
|
|
43
|
+
.description('Run skill against all scenarios and save baseline snapshots')
|
|
44
|
+
.option('--adapter <adapter>', 'Skill adapter to use', 'copilot-cli')
|
|
45
|
+
.option('--inference <inference>', 'Inference adapter to use', 'auto')
|
|
46
|
+
.option('--runs <n>', 'Number of runs per scenario', '1')
|
|
47
|
+
.option('--verbose', 'Verbose output')
|
|
48
|
+
.argument('[skill-dir]', 'Path to skill directory', process.cwd())
|
|
49
|
+
.action(async (skillDir, opts) => {
|
|
50
|
+
try {
|
|
51
|
+
const skillPath = path.resolve(skillDir);
|
|
52
|
+
const config = resolveConfig({
|
|
53
|
+
adapter: opts.adapter,
|
|
54
|
+
inference: opts.inference,
|
|
55
|
+
runs: opts.runs ? parseInt(opts.runs, 10) : undefined,
|
|
56
|
+
}, process.cwd(), skillPath);
|
|
57
|
+
const skillAdapter = resolveSkillAdapter(config.adapter);
|
|
58
|
+
await captureCommand(skillPath, skillAdapter, { runs: config.runs });
|
|
59
|
+
console.log(`Captured baselines at ${path.join(skillPath, 'evals', 'snapshots')}`);
|
|
60
|
+
process.exit(0);
|
|
61
|
+
}
|
|
62
|
+
catch (err) {
|
|
63
|
+
handleError(err);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
// --- check ---
|
|
67
|
+
program
|
|
68
|
+
.command('check')
|
|
69
|
+
.description('Compare current skill output against baselines')
|
|
70
|
+
.option('--adapter <adapter>', 'Skill adapter to use', 'copilot-cli')
|
|
71
|
+
.option('--inference <inference>', 'Inference adapter to use', 'auto')
|
|
72
|
+
.option('--threshold <n>', 'Similarity threshold (0–1)', '0.85')
|
|
73
|
+
.option('--budget <amount>', 'Spend cap in USD (or "unlimited")', 'unlimited')
|
|
74
|
+
.option('--ci', 'CI mode: exit 1 on regressions, no interactive prompts')
|
|
75
|
+
.option('--skip-embedding', 'Skip embedding tier (tier 2)')
|
|
76
|
+
.option('--verbose', 'Verbose output')
|
|
77
|
+
.option('--scenario <ids>', 'Comma-separated scenario IDs to check')
|
|
78
|
+
.argument('[skill-dir]', 'Path to skill directory', process.cwd())
|
|
79
|
+
.action(async (skillDir, opts) => {
|
|
80
|
+
try {
|
|
81
|
+
const skillPath = path.resolve(skillDir);
|
|
82
|
+
const config = resolveConfig({
|
|
83
|
+
adapter: opts.adapter,
|
|
84
|
+
inference: opts.inference,
|
|
85
|
+
threshold: opts.threshold ? parseFloat(opts.threshold) : undefined,
|
|
86
|
+
budget: opts.budget,
|
|
87
|
+
}, process.cwd(), skillPath);
|
|
88
|
+
const skillAdapter = resolveSkillAdapter(config.adapter);
|
|
89
|
+
const inference = resolveInference(config.inference);
|
|
90
|
+
const results = await checkCommand(skillPath, skillAdapter, inference, {
|
|
91
|
+
threshold: config.threshold,
|
|
92
|
+
budget: config.budget,
|
|
93
|
+
skipEmbedding: Boolean(opts.skipEmbedding),
|
|
94
|
+
});
|
|
95
|
+
// Always print terminal report
|
|
96
|
+
const reporter = new TerminalReporter();
|
|
97
|
+
await reporter.report(results);
|
|
98
|
+
const hasRegressions = results.summary.regressed > 0;
|
|
99
|
+
if (hasRegressions) {
|
|
100
|
+
process.exit(1);
|
|
101
|
+
}
|
|
102
|
+
process.exit(0);
|
|
103
|
+
}
|
|
104
|
+
catch (err) {
|
|
105
|
+
handleError(err);
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
// --- approve ---
|
|
109
|
+
program
|
|
110
|
+
.command('approve')
|
|
111
|
+
.description('Approve regressed scenarios as new baselines')
|
|
112
|
+
.option('--adapter <adapter>', 'Skill adapter to use', 'copilot-cli')
|
|
113
|
+
.option('--inference <inference>', 'Inference adapter to use', 'auto')
|
|
114
|
+
.option('--scenario <ids>', 'Comma-separated scenario IDs to approve (default: all)')
|
|
115
|
+
.option('--verbose', 'Verbose output')
|
|
116
|
+
.argument('[skill-dir]', 'Path to skill directory', process.cwd())
|
|
117
|
+
.action(async (skillDir, opts) => {
|
|
118
|
+
try {
|
|
119
|
+
const skillPath = path.resolve(skillDir);
|
|
120
|
+
const config = resolveConfig({ adapter: opts.adapter, inference: opts.inference }, process.cwd(), skillPath);
|
|
121
|
+
const skillAdapter = resolveSkillAdapter(config.adapter);
|
|
122
|
+
const scenarioIds = opts.scenario
|
|
123
|
+
? opts.scenario.split(',').map((s) => parseInt(s.trim(), 10))
|
|
124
|
+
: undefined;
|
|
125
|
+
await approveCommand(skillPath, skillAdapter, { scenarioIds });
|
|
126
|
+
console.log('Approved snapshots updated.');
|
|
127
|
+
process.exit(0);
|
|
128
|
+
}
|
|
129
|
+
catch (err) {
|
|
130
|
+
handleError(err);
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
// --- report ---
|
|
134
|
+
program
|
|
135
|
+
.command('report')
|
|
136
|
+
.description('Write latest check results to evals/results/iteration-N/')
|
|
137
|
+
.option('--adapter <adapter>', 'Skill adapter to use', 'copilot-cli')
|
|
138
|
+
.option('--inference <inference>', 'Inference adapter to use', 'auto')
|
|
139
|
+
.option('--threshold <n>', 'Similarity threshold (0–1)', '0.85')
|
|
140
|
+
.option('--budget <amount>', 'Spend cap in USD (or "unlimited")', 'unlimited')
|
|
141
|
+
.option('--skip-embedding', 'Skip embedding tier (tier 2)')
|
|
142
|
+
.option('--verbose', 'Verbose output')
|
|
143
|
+
.argument('[skill-dir]', 'Path to skill directory', process.cwd())
|
|
144
|
+
.action(async (skillDir, opts) => {
|
|
145
|
+
try {
|
|
146
|
+
const skillPath = path.resolve(skillDir);
|
|
147
|
+
const config = resolveConfig({
|
|
148
|
+
adapter: opts.adapter,
|
|
149
|
+
inference: opts.inference,
|
|
150
|
+
threshold: opts.threshold ? parseFloat(opts.threshold) : undefined,
|
|
151
|
+
budget: opts.budget,
|
|
152
|
+
}, process.cwd(), skillPath);
|
|
153
|
+
const skillAdapter = resolveSkillAdapter(config.adapter);
|
|
154
|
+
const inference = resolveInference(config.inference);
|
|
155
|
+
const results = await checkCommand(skillPath, skillAdapter, inference, {
|
|
156
|
+
threshold: config.threshold,
|
|
157
|
+
budget: config.budget,
|
|
158
|
+
skipEmbedding: Boolean(opts.skipEmbedding),
|
|
159
|
+
});
|
|
160
|
+
await reportCommand(skillPath, results, { verbose: Boolean(opts.verbose) });
|
|
161
|
+
const hasRegressions = results.summary.regressed > 0;
|
|
162
|
+
if (hasRegressions) {
|
|
163
|
+
process.exit(1);
|
|
164
|
+
}
|
|
165
|
+
process.exit(0);
|
|
166
|
+
}
|
|
167
|
+
catch (err) {
|
|
168
|
+
handleError(err);
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
// --- helpers ---
|
|
172
|
+
function resolveSkillAdapter(adapterName) {
|
|
173
|
+
if (adapterName === 'copilot-cli') {
|
|
174
|
+
return new CopilotCLIAdapter();
|
|
175
|
+
}
|
|
176
|
+
throw new SnapevalError(`Unknown skill adapter "${adapterName}". Valid options: copilot-cli.`);
|
|
177
|
+
}
|
|
178
|
+
function handleError(err) {
|
|
179
|
+
if (err instanceof SnapevalError) {
|
|
180
|
+
console.error(`Error: ${err.message}`);
|
|
181
|
+
process.exit(err.exitCode ?? 2);
|
|
182
|
+
}
|
|
183
|
+
if (err instanceof Error) {
|
|
184
|
+
console.error(`Error: ${err.message}`);
|
|
185
|
+
process.exit(2);
|
|
186
|
+
}
|
|
187
|
+
console.error('An unknown error occurred.');
|
|
188
|
+
process.exit(2);
|
|
189
|
+
}
|
|
190
|
+
program.parse(process.argv);
|
|
191
|
+
//# sourceMappingURL=snapeval.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"snapeval.js","sourceRoot":"","sources":["../../bin/snapeval.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { InferenceAdapter, Message, ChatOptions } from '../../types.js';
|
|
2
|
+
export declare class CopilotInference implements InferenceAdapter {
|
|
3
|
+
private readonly fallback?;
|
|
4
|
+
readonly name = "copilot";
|
|
5
|
+
constructor(fallback?: InferenceAdapter | undefined);
|
|
6
|
+
chat(messages: Message[], _options?: ChatOptions): Promise<string>;
|
|
7
|
+
embed(text: string): Promise<number[]>;
|
|
8
|
+
estimateCost(_tokens: number): number;
|
|
9
|
+
}
|