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.
Files changed (98) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +194 -0
  3. package/bin/snapeval.ts +226 -0
  4. package/dist/bin/snapeval.d.ts +2 -0
  5. package/dist/bin/snapeval.js +191 -0
  6. package/dist/bin/snapeval.js.map +1 -0
  7. package/dist/src/adapters/inference/copilot.d.ts +9 -0
  8. package/dist/src/adapters/inference/copilot.js +25 -0
  9. package/dist/src/adapters/inference/copilot.js.map +1 -0
  10. package/dist/src/adapters/inference/github-models.d.ts +9 -0
  11. package/dist/src/adapters/inference/github-models.js +62 -0
  12. package/dist/src/adapters/inference/github-models.js.map +1 -0
  13. package/dist/src/adapters/inference/resolve.d.ts +2 -0
  14. package/dist/src/adapters/inference/resolve.js +49 -0
  15. package/dist/src/adapters/inference/resolve.js.map +1 -0
  16. package/dist/src/adapters/report/json.d.ts +7 -0
  17. package/dist/src/adapters/report/json.js +39 -0
  18. package/dist/src/adapters/report/json.js.map +1 -0
  19. package/dist/src/adapters/report/terminal.d.ts +5 -0
  20. package/dist/src/adapters/report/terminal.js +42 -0
  21. package/dist/src/adapters/report/terminal.js.map +1 -0
  22. package/dist/src/adapters/skill/copilot-cli.d.ts +6 -0
  23. package/dist/src/adapters/skill/copilot-cli.js +51 -0
  24. package/dist/src/adapters/skill/copilot-cli.js.map +1 -0
  25. package/dist/src/commands/approve.d.ts +5 -0
  26. package/dist/src/commands/approve.js +40 -0
  27. package/dist/src/commands/approve.js.map +1 -0
  28. package/dist/src/commands/capture.d.ts +4 -0
  29. package/dist/src/commands/capture.js +18 -0
  30. package/dist/src/commands/capture.js.map +1 -0
  31. package/dist/src/commands/check.d.ts +6 -0
  32. package/dist/src/commands/check.js +68 -0
  33. package/dist/src/commands/check.js.map +1 -0
  34. package/dist/src/commands/init.d.ts +2 -0
  35. package/dist/src/commands/init.js +27 -0
  36. package/dist/src/commands/init.js.map +1 -0
  37. package/dist/src/commands/report.d.ts +4 -0
  38. package/dist/src/commands/report.js +26 -0
  39. package/dist/src/commands/report.js.map +1 -0
  40. package/dist/src/config.d.ts +3 -0
  41. package/dist/src/config.js +30 -0
  42. package/dist/src/config.js.map +1 -0
  43. package/dist/src/engine/budget.d.ts +10 -0
  44. package/dist/src/engine/budget.js +25 -0
  45. package/dist/src/engine/budget.js.map +1 -0
  46. package/dist/src/engine/comparison/embedding.d.ts +6 -0
  47. package/dist/src/engine/comparison/embedding.js +19 -0
  48. package/dist/src/engine/comparison/embedding.js.map +1 -0
  49. package/dist/src/engine/comparison/judge.d.ts +8 -0
  50. package/dist/src/engine/comparison/judge.js +64 -0
  51. package/dist/src/engine/comparison/judge.js.map +1 -0
  52. package/dist/src/engine/comparison/pipeline.d.ts +6 -0
  53. package/dist/src/engine/comparison/pipeline.js +31 -0
  54. package/dist/src/engine/comparison/pipeline.js.map +1 -0
  55. package/dist/src/engine/comparison/schema.d.ts +2 -0
  56. package/dist/src/engine/comparison/schema.js +28 -0
  57. package/dist/src/engine/comparison/schema.js.map +1 -0
  58. package/dist/src/engine/comparison/variance.d.ts +3 -0
  59. package/dist/src/engine/comparison/variance.js +26 -0
  60. package/dist/src/engine/comparison/variance.js.map +1 -0
  61. package/dist/src/engine/generator.d.ts +3 -0
  62. package/dist/src/engine/generator.js +52 -0
  63. package/dist/src/engine/generator.js.map +1 -0
  64. package/dist/src/engine/snapshot.d.ts +11 -0
  65. package/dist/src/engine/snapshot.js +46 -0
  66. package/dist/src/engine/snapshot.js.map +1 -0
  67. package/dist/src/errors.d.ts +16 -0
  68. package/dist/src/errors.js +33 -0
  69. package/dist/src/errors.js.map +1 -0
  70. package/dist/src/types.d.ts +125 -0
  71. package/dist/src/types.js +2 -0
  72. package/dist/src/types.js.map +1 -0
  73. package/package.json +53 -0
  74. package/plugin.json +9 -0
  75. package/scripts/snapeval-cli.sh +7 -0
  76. package/skills/snapeval/SKILL.md +51 -0
  77. package/src/adapters/inference/copilot.ts +30 -0
  78. package/src/adapters/inference/github-models.ts +74 -0
  79. package/src/adapters/inference/resolve.ts +70 -0
  80. package/src/adapters/report/json.ts +64 -0
  81. package/src/adapters/report/terminal.ts +59 -0
  82. package/src/adapters/skill/copilot-cli.ts +60 -0
  83. package/src/commands/approve.ts +58 -0
  84. package/src/commands/capture.ts +25 -0
  85. package/src/commands/check.ts +86 -0
  86. package/src/commands/init.ts +38 -0
  87. package/src/commands/report.ts +36 -0
  88. package/src/config.ts +37 -0
  89. package/src/engine/budget.ts +27 -0
  90. package/src/engine/comparison/embedding.ts +26 -0
  91. package/src/engine/comparison/judge.ts +78 -0
  92. package/src/engine/comparison/pipeline.ts +43 -0
  93. package/src/engine/comparison/schema.ts +22 -0
  94. package/src/engine/comparison/variance.ts +31 -0
  95. package/src/engine/generator.ts +61 -0
  96. package/src/engine/snapshot.ts +48 -0
  97. package/src/errors.ts +34 -0
  98. 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
+ [![CI](https://github.com/matantsach/snapeval/actions/workflows/ci.yml/badge.svg)](https://github.com/matantsach/snapeval/actions/workflows/ci.yml)
6
+ [![npm version](https://img.shields.io/npm/v/snapeval.svg)](https://www.npmjs.com/package/snapeval)
7
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](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)
@@ -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,2 @@
1
+ #!/usr/bin/env tsx
2
+ export {};
@@ -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
+ }