openspec-playwright 0.3.14 → 0.3.16
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/.claude/skills/openspec-e2e/SKILL.md +3 -3
- package/README.md +1 -0
- package/bin/openspec-pw +4 -3
- package/dist/commands/visionCheck.d.ts +11 -3
- package/dist/commands/visionCheck.js +198 -78
- package/dist/commands/visionCheck.js.map +1 -1
- package/dist/index.js +11 -1
- package/dist/index.js.map +1 -1
- package/dist/utils/ollama.d.ts +33 -12
- package/dist/utils/ollama.js +324 -72
- package/dist/utils/ollama.js.map +1 -1
- package/package.json +5 -1
- package/templates/app-knowledge.md +0 -16
|
@@ -461,9 +461,9 @@ If Ollama with a vision model is available, analyze screenshots for layout anoma
|
|
|
461
461
|
|
|
462
462
|
If Vision Check shows `⚠ disabled` or `⚠ not reachable` → skip this step entirely. Vision Check is optional and should not block exploration.
|
|
463
463
|
|
|
464
|
-
**Configuration
|
|
465
|
-
|
|
466
|
-
|
|
464
|
+
**Configuration**:
|
|
465
|
+
- `.env` file in `tests/playwright/` (highest priority): `OLLAMA_URL`, `OLLAMA_VISION_MODEL`, `OLLAMA_VISION_ENABLED`
|
|
466
|
+
- Environment variables: `OLLAMA_URL`, `OLLAMA_VISION_MODEL`
|
|
467
467
|
|
|
468
468
|
If no configuration is found, vision check is disabled.
|
|
469
469
|
|
package/README.md
CHANGED
|
@@ -40,6 +40,7 @@ openspec-pw audit # Audit tests for orphaned specs and issues
|
|
|
40
40
|
openspec-pw migrate # Migrate old test files to new structure
|
|
41
41
|
openspec-pw explore # Explore routes in parallel with Playwright
|
|
42
42
|
openspec-pw vision-check # Analyze screenshots for layout anomalies (Ollama VLM)
|
|
43
|
+
# Supports: multi-viewport, baseline diff, HTML report
|
|
43
44
|
openspec-pw uninstall # Remove integration from the project
|
|
44
45
|
```
|
|
45
46
|
|
package/bin/openspec-pw
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
# Resolve symlinks to find real script location, then go up to package root
|
|
3
3
|
REAL="$(readlink -f "$0" 2>/dev/null || echo "$0")"
|
|
4
4
|
DIR="$(cd "$(dirname "$REAL")/.." && pwd)"
|
|
5
|
-
#
|
|
6
|
-
|
|
7
|
-
cd "$DIR" && node dist/index.js "$@"
|
|
5
|
+
# Save caller's CWD before cd so init/git get the correct working directory
|
|
6
|
+
ORIG_CWD="$(pwd)"
|
|
7
|
+
cd "$DIR" && OPENSPE_PW_CWD="$ORIG_CWD" node dist/index.js "$@"
|
|
8
|
+
cd "$ORIG_CWD"
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Vision check command: Analyze screenshots for layout anomalies using Ollama VLM.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* Modes:
|
|
5
|
+
* --screenshots "..." Analyze existing files (single mode)
|
|
6
|
+
* --url ... --viewport ... Capture from URL at multiple viewports
|
|
7
|
+
* --baseline Save as baseline (with --screenshots or --url+viewport)
|
|
8
|
+
* --diff Compare against baseline
|
|
9
|
+
* --report <path> Generate HTML report
|
|
7
10
|
*
|
|
8
11
|
* Exit codes:
|
|
9
12
|
* 0 = Check completed (with or without anomalies)
|
|
@@ -18,6 +21,11 @@ export interface VisionCheckOptions {
|
|
|
18
21
|
dryRun?: boolean;
|
|
19
22
|
severity?: string;
|
|
20
23
|
json?: boolean;
|
|
24
|
+
viewport?: string;
|
|
25
|
+
url?: string;
|
|
26
|
+
baseline?: boolean;
|
|
27
|
+
diff?: boolean;
|
|
28
|
+
report?: string;
|
|
21
29
|
}
|
|
22
30
|
/**
|
|
23
31
|
* Main vision check command.
|
|
@@ -1,20 +1,24 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Vision check command: Analyze screenshots for layout anomalies using Ollama VLM.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* Modes:
|
|
5
|
+
* --screenshots "..." Analyze existing files (single mode)
|
|
6
|
+
* --url ... --viewport ... Capture from URL at multiple viewports
|
|
7
|
+
* --baseline Save as baseline (with --screenshots or --url+viewport)
|
|
8
|
+
* --diff Compare against baseline
|
|
9
|
+
* --report <path> Generate HTML report
|
|
7
10
|
*
|
|
8
11
|
* Exit codes:
|
|
9
12
|
* 0 = Check completed (with or without anomalies)
|
|
10
13
|
* 1 = Ollama not available (skipped)
|
|
11
14
|
* 2 = Configuration missing or invalid (skipped)
|
|
12
15
|
*/
|
|
13
|
-
import { existsSync, readFileSync, writeFileSync } from "fs";
|
|
16
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs";
|
|
14
17
|
import { join, basename } from "path";
|
|
15
18
|
import { glob } from "glob";
|
|
16
19
|
import chalk from "chalk";
|
|
17
|
-
import {
|
|
20
|
+
import { chromium } from "playwright";
|
|
21
|
+
import { loadOllamaConfig, checkOllamaHealth, batchAnalyzeScreenshots, compareScreenshotDiff, generateHtmlReport, } from "../utils/ollama.js";
|
|
18
22
|
/**
|
|
19
23
|
* Extract route name from screenshot path.
|
|
20
24
|
* e.g., "__screenshots__/dashboard.png" → "/dashboard"
|
|
@@ -53,62 +57,91 @@ function filterBySeverity(anomalies, severityFilter) {
|
|
|
53
57
|
const levels = severityFilter.toLowerCase().split(",").map((s) => s.trim());
|
|
54
58
|
return anomalies.filter((a) => levels.includes(a.severity));
|
|
55
59
|
}
|
|
60
|
+
// ── Viewport presets ───────────────────────────────────────────────────────────
|
|
61
|
+
const VIEWPORT_PRESETS = {
|
|
62
|
+
mobile: { width: 375, height: 667 },
|
|
63
|
+
tablet: { width: 768, height: 1024 },
|
|
64
|
+
desktop: { width: 1280, height: 720 },
|
|
65
|
+
wide: { width: 1920, height: 1080 },
|
|
66
|
+
};
|
|
56
67
|
/**
|
|
57
|
-
*
|
|
68
|
+
* Parse viewport string: "mobile,desktop" or "375x667,1280x720"
|
|
58
69
|
*/
|
|
59
|
-
function
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
}
|
|
65
|
-
let content = readFileSync(explorationPath, "utf-8");
|
|
66
|
-
// Find or create Visual Anomalies section
|
|
67
|
-
const sectionHeader = "## Visual Anomalies";
|
|
68
|
-
const tableHeader = `| Route | Element | Type | Position | Severity | Description |
|
|
69
|
-
| --- | --- | --- | --- | --- | --- |`;
|
|
70
|
-
if (!content.includes(sectionHeader)) {
|
|
71
|
-
// Add section before "## Next Steps" or at the end
|
|
72
|
-
const nextStepsIndex = content.indexOf("## Next Steps");
|
|
73
|
-
if (nextStepsIndex !== -1) {
|
|
74
|
-
content =
|
|
75
|
-
content.slice(0, nextStepsIndex) +
|
|
76
|
-
`${sectionHeader}\n\n${tableHeader}\n\n` +
|
|
77
|
-
content.slice(nextStepsIndex);
|
|
70
|
+
function parseViewports(input) {
|
|
71
|
+
return input.split(",").map((v) => {
|
|
72
|
+
const name = v.trim().toLowerCase();
|
|
73
|
+
if (VIEWPORT_PRESETS[name]) {
|
|
74
|
+
return { name, ...VIEWPORT_PRESETS[name] };
|
|
78
75
|
}
|
|
79
|
-
|
|
80
|
-
|
|
76
|
+
const parts = name.split("x");
|
|
77
|
+
if (parts.length === 2) {
|
|
78
|
+
const w = parseInt(parts[0], 10);
|
|
79
|
+
const h = parseInt(parts[1], 10);
|
|
80
|
+
if (w > 0 && h > 0) {
|
|
81
|
+
return { name: `${w}x${h}`, width: w, height: h };
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
throw new Error(`Invalid viewport: "${v}". Use presets (mobile/tablet/desktop/wide) or WxH (e.g. 375x667)`);
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
// ── Baseline paths ───────────────────────────────────────────────────────────
|
|
88
|
+
const BASELINE_DIR = ".openspec-pw/vision-baseline";
|
|
89
|
+
const DIFF_DIR = ".openspec-pw/vision-diff";
|
|
90
|
+
/**
|
|
91
|
+
* Capture screenshots from a URL at multiple viewports using Playwright.
|
|
92
|
+
*/
|
|
93
|
+
async function captureFromUrl(url, viewports, outputDir, concurrency = 2) {
|
|
94
|
+
const results = [];
|
|
95
|
+
mkdirSync(outputDir, { recursive: true });
|
|
96
|
+
let browser = null;
|
|
97
|
+
try {
|
|
98
|
+
browser = await chromium.launch({ headless: true });
|
|
99
|
+
for (let i = 0; i < viewports.length; i += concurrency) {
|
|
100
|
+
const batch = viewports.slice(i, i + concurrency);
|
|
101
|
+
const batchPromises = batch.map(async (vp) => {
|
|
102
|
+
// Each viewport gets its own context so viewport size doesn't affect other captures
|
|
103
|
+
const context = await browser.newContext({
|
|
104
|
+
viewport: { width: vp.width, height: vp.height },
|
|
105
|
+
});
|
|
106
|
+
const page = await context.newPage();
|
|
107
|
+
try {
|
|
108
|
+
await page.goto(url, { waitUntil: "networkidle", timeout: 30000 });
|
|
109
|
+
const filename = `${vp.name}.png`;
|
|
110
|
+
const filepath = join(outputDir, filename);
|
|
111
|
+
await page.screenshot({ path: filepath, fullPage: true });
|
|
112
|
+
return { path: filepath, route: `${vp.name}:${url}`, viewport: vp.name };
|
|
113
|
+
}
|
|
114
|
+
finally {
|
|
115
|
+
await context.close();
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
const batchResults = await Promise.all(batchPromises);
|
|
119
|
+
results.push(...batchResults);
|
|
81
120
|
}
|
|
82
121
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
const cells = row.split("|").map((c) => c.trim()).filter(Boolean);
|
|
87
|
-
return `${cells[0]}:${cells[1]}:${cells[2]}`;
|
|
88
|
-
}));
|
|
89
|
-
const newRows = [];
|
|
90
|
-
for (const a of anomalies) {
|
|
91
|
-
const key = `${a.route}:${a.element}:${a.type}`;
|
|
92
|
-
if (!existingKeys.has(key)) {
|
|
93
|
-
newRows.push(`| ${a.route} | ${a.element} | ${a.type} | ${a.position} | ${a.severity} | ${a.description} |`);
|
|
94
|
-
existingKeys.add(key);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
if (newRows.length > 0) {
|
|
98
|
-
// Insert after table header
|
|
99
|
-
const headerIndex = content.indexOf(tableHeader);
|
|
100
|
-
if (headerIndex !== -1) {
|
|
101
|
-
const insertPoint = headerIndex + tableHeader.length;
|
|
102
|
-
content =
|
|
103
|
-
content.slice(0, insertPoint) +
|
|
104
|
-
"\n" +
|
|
105
|
-
newRows.join("\n") +
|
|
106
|
-
content.slice(insertPoint);
|
|
107
|
-
}
|
|
108
|
-
writeFileSync(explorationPath, content, "utf-8");
|
|
109
|
-
console.log(chalk.green(` ✓ Appended ${newRows.length} anomalies to app-exploration.md`));
|
|
122
|
+
finally {
|
|
123
|
+
if (browser)
|
|
124
|
+
await browser.close();
|
|
110
125
|
}
|
|
126
|
+
return results;
|
|
111
127
|
}
|
|
128
|
+
/**
|
|
129
|
+
* Copy screenshots to baseline directory.
|
|
130
|
+
*/
|
|
131
|
+
function saveBaseline(screenshots, projectRoot) {
|
|
132
|
+
const baselineDir = join(projectRoot, BASELINE_DIR);
|
|
133
|
+
mkdirSync(baselineDir, { recursive: true });
|
|
134
|
+
for (const s of screenshots) {
|
|
135
|
+
const name = s.viewport
|
|
136
|
+
? `${basename(s.path, ".png")}-baseline.png`
|
|
137
|
+
: `${basename(s.path, ".png")}-baseline.png`;
|
|
138
|
+
const dest = join(baselineDir, name);
|
|
139
|
+
writeFileSync(dest, readFileSync(s.path));
|
|
140
|
+
console.log(chalk.green(` ✓ Baseline saved: ${dest}`));
|
|
141
|
+
}
|
|
142
|
+
return baselineDir;
|
|
143
|
+
}
|
|
144
|
+
// ── Main command ─────────────────────────────────────────────────────────────
|
|
112
145
|
/**
|
|
113
146
|
* Main vision check command.
|
|
114
147
|
*/
|
|
@@ -133,18 +166,53 @@ export async function visionCheck(options) {
|
|
|
133
166
|
}
|
|
134
167
|
process.exit(2);
|
|
135
168
|
}
|
|
136
|
-
// 2.
|
|
169
|
+
// 2. Parse viewports
|
|
170
|
+
let viewports = null;
|
|
171
|
+
if (options.viewport) {
|
|
172
|
+
viewports = parseViewports(options.viewport);
|
|
173
|
+
}
|
|
174
|
+
// 3. Gather screenshots
|
|
175
|
+
let screenshots = [];
|
|
176
|
+
if (options.viewport && options.url) {
|
|
177
|
+
// Multi-viewport capture mode
|
|
178
|
+
if (!options.json) {
|
|
179
|
+
console.log(chalk.blue(`\n📷 Capturing at ${viewports.length} viewport(s) from ${options.url}...\n`));
|
|
180
|
+
}
|
|
181
|
+
screenshots = await captureFromUrl(options.url, viewports, join(projectRoot, ".openspec-pw/vision-current"));
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
// File-based mode
|
|
185
|
+
screenshots = await resolveScreenshots(options.screenshots);
|
|
186
|
+
}
|
|
187
|
+
if (screenshots.length === 0) {
|
|
188
|
+
if (options.viewport && !options.url) {
|
|
189
|
+
console.log(chalk.yellow("Error: --viewport requires --url"));
|
|
190
|
+
}
|
|
191
|
+
else {
|
|
192
|
+
console.log(chalk.yellow("No screenshots found. Provide --screenshots <pattern> or --url <url> --viewport <views>"));
|
|
193
|
+
}
|
|
194
|
+
process.exit(1);
|
|
195
|
+
}
|
|
196
|
+
// 4. Baseline mode: save and exit
|
|
197
|
+
if (options.baseline) {
|
|
198
|
+
const baselineDir = saveBaseline(screenshots, projectRoot);
|
|
199
|
+
if (!options.json) {
|
|
200
|
+
console.log(chalk.green(`\n✓ Baseline saved (${screenshots.length} screenshots) in ${baselineDir}`));
|
|
201
|
+
}
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
// 5. Dry run
|
|
137
205
|
if (options.dryRun) {
|
|
138
|
-
|
|
139
|
-
console.log(chalk.blue("\n📷 Screenshots to analyze (dry run):\n"));
|
|
206
|
+
console.log(chalk.blue("\n📷 Screenshots (dry run):\n"));
|
|
140
207
|
for (const s of screenshots) {
|
|
141
|
-
|
|
208
|
+
const vp = s.viewport ? ` [${s.viewport}]` : "";
|
|
209
|
+
console.log(` ${s.route}${vp} → ${s.path}`);
|
|
142
210
|
}
|
|
143
211
|
console.log(chalk.gray(`\nTotal: ${screenshots.length} files`));
|
|
144
212
|
console.log(chalk.gray(`Ollama: ${config.url} (${config.model})`));
|
|
145
213
|
return;
|
|
146
214
|
}
|
|
147
|
-
//
|
|
215
|
+
// 6. Health check
|
|
148
216
|
const health = await checkOllamaHealth(config);
|
|
149
217
|
if (!health.ok) {
|
|
150
218
|
const result = {
|
|
@@ -163,29 +231,77 @@ export async function visionCheck(options) {
|
|
|
163
231
|
}
|
|
164
232
|
process.exit(1);
|
|
165
233
|
}
|
|
166
|
-
// 4. Resolve screenshots
|
|
167
|
-
const screenshots = await resolveScreenshots(options.screenshots);
|
|
168
|
-
if (screenshots.length === 0) {
|
|
169
|
-
console.log(chalk.yellow("No screenshots found matching pattern"));
|
|
170
|
-
process.exit(0);
|
|
171
|
-
}
|
|
172
234
|
if (!options.json) {
|
|
173
|
-
|
|
235
|
+
const mode = options.diff ? "diff" : "analyze";
|
|
236
|
+
console.log(chalk.blue(`\n🔍 ${mode === "diff" ? "Pixel diff" : "Analyzing"} ${screenshots.length} screenshot(s)...\n`));
|
|
174
237
|
}
|
|
175
|
-
//
|
|
176
|
-
const
|
|
177
|
-
|
|
178
|
-
|
|
238
|
+
// 7. Diff mode: compare with baseline
|
|
239
|
+
const result = {
|
|
240
|
+
processed: 0,
|
|
241
|
+
anomalies: [],
|
|
242
|
+
skipped: [],
|
|
243
|
+
ollamaUrl: config.url,
|
|
244
|
+
model: config.model,
|
|
245
|
+
baselineDir: join(projectRoot, BASELINE_DIR),
|
|
246
|
+
};
|
|
247
|
+
if (options.diff) {
|
|
248
|
+
const baselineDir = join(projectRoot, BASELINE_DIR);
|
|
249
|
+
const diffDir = join(projectRoot, DIFF_DIR);
|
|
250
|
+
mkdirSync(diffDir, { recursive: true });
|
|
251
|
+
for (const s of screenshots) {
|
|
252
|
+
const baseName = basename(s.path, ".png");
|
|
253
|
+
const baselinePath = join(baselineDir, `${baseName}-baseline.png`);
|
|
254
|
+
const diffPath = join(diffDir, `${baseName}-diff.png`);
|
|
255
|
+
if (!existsSync(baselinePath)) {
|
|
256
|
+
result.skipped.push(s.path);
|
|
257
|
+
if (!options.json) {
|
|
258
|
+
console.log(chalk.yellow(` ⚠ No baseline for ${s.route}, skipping diff`));
|
|
259
|
+
}
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
262
|
+
try {
|
|
263
|
+
const { changed, anomalies } = await compareScreenshotDiff(config, baselinePath, s.path, diffPath, s.route);
|
|
264
|
+
result.processed++;
|
|
265
|
+
result.anomalies.push(...anomalies.map((a) => ({ ...a, viewport: s.viewport })));
|
|
266
|
+
if (!options.json) {
|
|
267
|
+
if (changed) {
|
|
268
|
+
console.log(chalk.yellow(` ~ ${s.route}${s.viewport ? ` [${s.viewport}]` : ""}: ${anomalies.length} anomaly(ies)`));
|
|
269
|
+
}
|
|
270
|
+
else {
|
|
271
|
+
console.log(chalk.gray(` ✓ ${s.route}${s.viewport ? ` [${s.viewport}]` : ""}: no changes`));
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
catch (err) {
|
|
276
|
+
const error = err;
|
|
277
|
+
result.skipped.push(s.path);
|
|
278
|
+
if (!options.json) {
|
|
279
|
+
console.error(chalk.red(` ✗ ${s.route}: ${error.message}`));
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
else {
|
|
285
|
+
// Analyze mode: batch analyze screenshots
|
|
286
|
+
const concurrency = options.parallel || 4;
|
|
287
|
+
const batchResult = await batchAnalyzeScreenshots(config, screenshots.map((s) => ({ path: s.path, route: s.route })), concurrency);
|
|
288
|
+
result.processed = batchResult.processed;
|
|
289
|
+
result.anomalies = batchResult.anomalies.map((a) => ({
|
|
290
|
+
...a,
|
|
291
|
+
viewport: screenshots.find((s) => s.path === a.screenshot)?.viewport,
|
|
292
|
+
}));
|
|
293
|
+
result.skipped = batchResult.skipped;
|
|
294
|
+
}
|
|
295
|
+
// 8. Filter by severity
|
|
179
296
|
if (options.severity) {
|
|
180
297
|
result.anomalies = filterBySeverity(result.anomalies, options.severity);
|
|
181
298
|
}
|
|
182
|
-
//
|
|
299
|
+
// 9. Output
|
|
183
300
|
if (options.json) {
|
|
184
301
|
console.log(JSON.stringify(result, null, 2));
|
|
185
302
|
}
|
|
186
303
|
else {
|
|
187
|
-
|
|
188
|
-
console.log(chalk.blue("─── Vision Check Results ───\n"));
|
|
304
|
+
console.log(chalk.blue("─── Results ───\n"));
|
|
189
305
|
console.log(` Processed: ${result.processed}/${screenshots.length}`);
|
|
190
306
|
console.log(` Anomalies: ${result.anomalies.length}`);
|
|
191
307
|
if (result.skipped.length > 0) {
|
|
@@ -199,7 +315,8 @@ export async function visionCheck(options) {
|
|
|
199
315
|
: a.severity === "warning"
|
|
200
316
|
? chalk.yellow
|
|
201
317
|
: chalk.gray;
|
|
202
|
-
|
|
318
|
+
const vp = a.viewport ? ` [${a.viewport}]` : "";
|
|
319
|
+
console.log(` ${severityColor(`[${a.severity}]`)} ${a.route}${vp}`);
|
|
203
320
|
console.log(` Element: ${a.element}`);
|
|
204
321
|
console.log(` Type: ${a.type} (${a.position})`);
|
|
205
322
|
console.log(` ${a.description}\n`);
|
|
@@ -209,11 +326,14 @@ export async function visionCheck(options) {
|
|
|
209
326
|
console.log(chalk.green("\n ✓ No layout anomalies detected\n"));
|
|
210
327
|
}
|
|
211
328
|
}
|
|
212
|
-
//
|
|
213
|
-
if (
|
|
214
|
-
|
|
329
|
+
// 10. HTML report
|
|
330
|
+
if (options.report) {
|
|
331
|
+
generateHtmlReport(result, screenshots.map((s) => ({ path: s.path, route: s.route })), options.report, options.diff ? join(projectRoot, DIFF_DIR) : undefined);
|
|
332
|
+
if (!options.json) {
|
|
333
|
+
console.log(chalk.green(` ✓ HTML report: ${options.report}`));
|
|
334
|
+
}
|
|
215
335
|
}
|
|
216
|
-
//
|
|
336
|
+
// 11. JSON output file
|
|
217
337
|
if (options.output) {
|
|
218
338
|
writeFileSync(options.output, JSON.stringify(result, null, 2), "utf-8");
|
|
219
339
|
if (!options.json) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"visionCheck.js","sourceRoot":"","sources":["../../src/commands/visionCheck.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"visionCheck.js","sourceRoot":"","sources":["../../src/commands/visionCheck.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
// Restore caller's working directory (passed from shell wrapper via env var).
|
|
2
|
+
// This ensures init/git/file operations use the user's directory, not the global package dir.
|
|
3
|
+
if (process.env.OPENSPE_PW_CWD) {
|
|
4
|
+
process.chdir(process.env.OPENSPE_PW_CWD);
|
|
5
|
+
}
|
|
1
6
|
import { readFileSync } from "fs";
|
|
2
7
|
import { join, dirname } from "path";
|
|
3
8
|
import { fileURLToPath } from "url";
|
|
@@ -78,13 +83,18 @@ program
|
|
|
78
83
|
program
|
|
79
84
|
.command("vision-check")
|
|
80
85
|
.description("Analyze screenshots for layout anomalies using Ollama VLM")
|
|
81
|
-
.
|
|
86
|
+
.option("-s, --screenshots <pattern>", "Screenshot path(s): glob pattern or comma-separated list")
|
|
82
87
|
.option("-c, --config <path>", "Config file path (default: app-knowledge.md)")
|
|
83
88
|
.option("-p, --parallel <n>", "Number of parallel requests to Ollama", (v) => parseInt(v, 10), 4)
|
|
84
89
|
.option("-o, --output <path>", "Write JSON results to file")
|
|
85
90
|
.option("--severity <levels>", "Filter by severity: blocking,warning,minor")
|
|
86
91
|
.option("-n, --dry-run", "List screenshots without analyzing")
|
|
87
92
|
.option("--json", "Output results as JSON")
|
|
93
|
+
.option("--viewport <views>", "Capture at multiple viewports: comma-separated presets (mobile,tablet,desktop,wide) or WxH (e.g. 375x667). Requires --url.")
|
|
94
|
+
.option("--url <url>", "URL to capture screenshots from (used with --viewport)")
|
|
95
|
+
.option("--baseline", "Save screenshots as baseline (used with --viewport or --screenshots)")
|
|
96
|
+
.option("--diff", "Compare current screenshots against baseline (requires prior --baseline run)")
|
|
97
|
+
.option("--report <path>", "Generate HTML report at the given path")
|
|
88
98
|
.action(async (opts) => {
|
|
89
99
|
await visionCheck(opts);
|
|
90
100
|
});
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/utils/ollama.d.ts
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Ollama API utilities for vision model integration.
|
|
3
3
|
*
|
|
4
|
-
* Configuration
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* 3. app-knowledge.md Vision Check Config section
|
|
8
|
-
*
|
|
9
|
-
* If no configuration is found, vision check is disabled.
|
|
4
|
+
* Configuration: reads from `.env` in `tests/playwright/` (highest priority),
|
|
5
|
+
* then falls back to environment variables. If no URL or model is found,
|
|
6
|
+
* vision check is disabled.
|
|
10
7
|
*/
|
|
11
8
|
export interface OllamaConfig {
|
|
12
9
|
url: string;
|
|
@@ -17,10 +14,12 @@ export interface VisionAnomaly {
|
|
|
17
14
|
route: string;
|
|
18
15
|
screenshot: string;
|
|
19
16
|
element: string;
|
|
20
|
-
type: "obscured" | "crowded" | "overflowed";
|
|
17
|
+
type: "obscured" | "crowded" | "overflowed" | "missing" | "incorrect";
|
|
21
18
|
position: string;
|
|
22
19
|
severity: "blocking" | "warning" | "minor";
|
|
23
20
|
description: string;
|
|
21
|
+
viewport?: string;
|
|
22
|
+
changed?: boolean;
|
|
24
23
|
}
|
|
25
24
|
export interface VisionCheckResult {
|
|
26
25
|
processed: number;
|
|
@@ -29,17 +28,23 @@ export interface VisionCheckResult {
|
|
|
29
28
|
skipReason?: string;
|
|
30
29
|
ollamaUrl: string;
|
|
31
30
|
model: string;
|
|
31
|
+
baselineDir?: string;
|
|
32
|
+
currentDir?: string;
|
|
32
33
|
}
|
|
33
34
|
export interface OllamaGenerateResponse {
|
|
34
35
|
response: string;
|
|
35
36
|
done: boolean;
|
|
36
37
|
}
|
|
38
|
+
export interface PixelDiffRegion {
|
|
39
|
+
x: number;
|
|
40
|
+
y: number;
|
|
41
|
+
width: number;
|
|
42
|
+
height: number;
|
|
43
|
+
changedPixels: number;
|
|
44
|
+
}
|
|
37
45
|
/**
|
|
38
|
-
* Load Ollama config
|
|
39
|
-
*
|
|
40
|
-
* 2. app-knowledge.md Vision Check Config section
|
|
41
|
-
*
|
|
42
|
-
* If no configuration is found, returns enabled=false.
|
|
46
|
+
* Load Ollama config from `.env` in `tests/playwright/` and environment variables.
|
|
47
|
+
* If no URL or model is configured, vision check is disabled.
|
|
43
48
|
*/
|
|
44
49
|
export declare function loadOllamaConfig(projectRoot?: string): OllamaConfig;
|
|
45
50
|
/**
|
|
@@ -61,3 +66,19 @@ export declare function batchAnalyzeScreenshots(config: OllamaConfig, screenshot
|
|
|
61
66
|
path: string;
|
|
62
67
|
route: string;
|
|
63
68
|
}>, concurrency?: number): Promise<VisionCheckResult>;
|
|
69
|
+
/**
|
|
70
|
+
* Compare two screenshots with pixel diff.
|
|
71
|
+
* Returns changed regions and optionally saves a diff image.
|
|
72
|
+
*/
|
|
73
|
+
export declare function compareScreenshotDiff(config: OllamaConfig, baselinePath: string, currentPath: string, diffPath: string, route: string): Promise<{
|
|
74
|
+
changed: boolean;
|
|
75
|
+
anomalies: VisionAnomaly[];
|
|
76
|
+
}>;
|
|
77
|
+
/**
|
|
78
|
+
* Generate a self-contained HTML report with embedded screenshots and results.
|
|
79
|
+
* If diffDir is provided, diff images are shown alongside current screenshots.
|
|
80
|
+
*/
|
|
81
|
+
export declare function generateHtmlReport(result: VisionCheckResult, screenshots: Array<{
|
|
82
|
+
path: string;
|
|
83
|
+
route: string;
|
|
84
|
+
}>, outputPath: string, diffDir?: string): void;
|
package/dist/utils/ollama.js
CHANGED
|
@@ -1,70 +1,35 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Ollama API utilities for vision model integration.
|
|
3
3
|
*
|
|
4
|
-
* Configuration
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* 3. app-knowledge.md Vision Check Config section
|
|
8
|
-
*
|
|
9
|
-
* If no configuration is found, vision check is disabled.
|
|
4
|
+
* Configuration: reads from `.env` in `tests/playwright/` (highest priority),
|
|
5
|
+
* then falls back to environment variables. If no URL or model is found,
|
|
6
|
+
* vision check is disabled.
|
|
10
7
|
*/
|
|
11
|
-
import {
|
|
8
|
+
import { config as loadEnv } from "dotenv";
|
|
9
|
+
import { createRequire } from "module";
|
|
10
|
+
import { existsSync, readFileSync, writeFileSync } from "fs";
|
|
12
11
|
import { join } from "path";
|
|
12
|
+
const _require = createRequire(import.meta.url);
|
|
13
13
|
// ── Config loading ────────────────────────────────────────────────────────────
|
|
14
14
|
/**
|
|
15
|
-
* Load Ollama config from
|
|
16
|
-
*
|
|
17
|
-
*/
|
|
18
|
-
function loadFromAppKnowledge(projectRoot) {
|
|
19
|
-
const appKnowledgePath = join(projectRoot, "tests", "playwright", "app-knowledge.md");
|
|
20
|
-
if (!existsSync(appKnowledgePath))
|
|
21
|
-
return {};
|
|
22
|
-
try {
|
|
23
|
-
const content = readFileSync(appKnowledgePath, "utf-8");
|
|
24
|
-
const match = content.match(/## Vision Check Config\s*\n([\s\S]*?)(?=\n##|\n---|\z)/);
|
|
25
|
-
if (!match)
|
|
26
|
-
return {};
|
|
27
|
-
const section = match[1];
|
|
28
|
-
const config = {};
|
|
29
|
-
const urlMatch = section.match(/ollama_url:\s*(.+)/);
|
|
30
|
-
if (urlMatch)
|
|
31
|
-
config.url = urlMatch[1].trim();
|
|
32
|
-
const modelMatch = section.match(/vision_model:\s*(.+)/);
|
|
33
|
-
if (modelMatch)
|
|
34
|
-
config.model = modelMatch[1].trim();
|
|
35
|
-
const enabledMatch = section.match(/vision_enabled:\s*(.+)/);
|
|
36
|
-
if (enabledMatch)
|
|
37
|
-
config.enabled = enabledMatch[1].trim() === "true";
|
|
38
|
-
return config;
|
|
39
|
-
}
|
|
40
|
-
catch {
|
|
41
|
-
return {};
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* Load Ollama config with priority:
|
|
46
|
-
* 1. Environment variables (OLLAMA_URL, OLLAMA_VISION_MODEL)
|
|
47
|
-
* 2. app-knowledge.md Vision Check Config section
|
|
48
|
-
*
|
|
49
|
-
* If no configuration is found, returns enabled=false.
|
|
15
|
+
* Load Ollama config from `.env` in `tests/playwright/` and environment variables.
|
|
16
|
+
* If no URL or model is configured, vision check is disabled.
|
|
50
17
|
*/
|
|
51
18
|
export function loadOllamaConfig(projectRoot = process.cwd()) {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
19
|
+
// Lazy load .env from tests/playwright/ (falls back gracefully if missing)
|
|
20
|
+
const envPath = join(projectRoot, "tests", "playwright", ".env");
|
|
21
|
+
if (existsSync(envPath)) {
|
|
22
|
+
loadEnv({ path: envPath });
|
|
23
|
+
}
|
|
24
|
+
const url = process.env.OLLAMA_URL;
|
|
25
|
+
const model = process.env.OLLAMA_VISION_MODEL;
|
|
56
26
|
// If no url or model configured, disable vision check
|
|
57
27
|
if (!url || !model) {
|
|
58
28
|
return { url: "", model: "", enabled: false };
|
|
59
29
|
}
|
|
60
30
|
// Enabled: default true unless explicitly disabled
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
enabled = process.env.OLLAMA_VISION_ENABLED === "true";
|
|
64
|
-
}
|
|
65
|
-
else if (appKnowledge.enabled !== undefined) {
|
|
66
|
-
enabled = appKnowledge.enabled;
|
|
67
|
-
}
|
|
31
|
+
const enabled = process.env.OLLAMA_VISION_ENABLED === undefined ||
|
|
32
|
+
process.env.OLLAMA_VISION_ENABLED === "true";
|
|
68
33
|
return { url, model, enabled };
|
|
69
34
|
}
|
|
70
35
|
// ── Health check ──────────────────────────────────────────────────────────────
|
|
@@ -111,25 +76,34 @@ export async function checkOllamaHealth(config) {
|
|
|
111
76
|
}
|
|
112
77
|
}
|
|
113
78
|
// ── Vision analysis ───────────────────────────────────────────────────────────
|
|
114
|
-
const VISION_PROMPT =
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
79
|
+
const VISION_PROMPT = [
|
|
80
|
+
"你是专业的UI测试工程师,以普通用户视角审视这张截图。",
|
|
81
|
+
"",
|
|
82
|
+
"【检测目标】用户可感知的功能性UI问题,不包括:",
|
|
83
|
+
"- 装饰性图标、logo的细微偏差",
|
|
84
|
+
"- CSS hover/transition动画状态",
|
|
85
|
+
"- 浏览器默认样式(滚动条、右键菜单)",
|
|
86
|
+
"- 动态广告/推荐内容(如能正常交互则不报错)",
|
|
87
|
+
"",
|
|
88
|
+
"【问题类型】",
|
|
89
|
+
"1. obscured — 可交互元素被遮挡/覆盖,无法点击",
|
|
90
|
+
"2. crowded — 元素间距过窄、文字重叠、难以区分",
|
|
91
|
+
"3. overflowed — 内容被裁剪,关键信息不可见",
|
|
92
|
+
"4. missing — 明显应该存在的元素完全消失",
|
|
93
|
+
"5. incorrect — 文本内容明显错误、样式完全错误",
|
|
94
|
+
"",
|
|
95
|
+
"【严重程度】",
|
|
96
|
+
"- blocking:核心功能不可用(如提交按钮被遮挡)",
|
|
97
|
+
"- warning:影响使用体验(如重要文字被截断)",
|
|
98
|
+
"- minor:细微视觉问题(图标轻微偏移)",
|
|
99
|
+
"",
|
|
100
|
+
"【定位】用屏幕区域:左上/上/右上/左/中/右/左下/下/右下",
|
|
101
|
+
"",
|
|
102
|
+
'返回JSON格式,不要包含任何其他文字:',
|
|
103
|
+
'{"anomalies":[]}',
|
|
104
|
+
"",
|
|
105
|
+
'如果一切正常,返回:{"anomalies":[]}',
|
|
106
|
+
].join("\n");
|
|
133
107
|
/**
|
|
134
108
|
* Analyze a single screenshot with the vision model.
|
|
135
109
|
*/
|
|
@@ -205,4 +179,282 @@ export async function batchAnalyzeScreenshots(config, screenshots, concurrency =
|
|
|
205
179
|
}
|
|
206
180
|
return result;
|
|
207
181
|
}
|
|
182
|
+
// ── Pixel diff ───────────────────────────────────────────────────────────────
|
|
183
|
+
const DIFF_PROMPT = `你是专业的UI回归测试工程师。这张图是像素差异图,红色高亮区域表示与基准版不同。
|
|
184
|
+
|
|
185
|
+
请分析红色高亮区域,检测:
|
|
186
|
+
1. 哪些变化是真实的UI bug(如元素被遮挡、布局错乱、内容丢失)
|
|
187
|
+
2. 哪些变化是正常的(如动态内容更新、动画状态变化)
|
|
188
|
+
|
|
189
|
+
【忽略】动态广告/推荐内容、时间戳、数值变化、hover/focus状态、第三方嵌入内容的变化。
|
|
190
|
+
|
|
191
|
+
【问题类型】
|
|
192
|
+
- obscured:可交互元素被遮挡,无法点击
|
|
193
|
+
- crowded:元素间距错乱、文字重叠
|
|
194
|
+
- overflowed:内容被裁剪,关键信息不可见
|
|
195
|
+
- missing:原有元素消失
|
|
196
|
+
- incorrect:样式/内容明显错误
|
|
197
|
+
|
|
198
|
+
【严重程度】
|
|
199
|
+
- blocking:核心功能不可用
|
|
200
|
+
- warning:影响使用体验
|
|
201
|
+
- minor:细微视觉回归
|
|
202
|
+
|
|
203
|
+
返回JSON(不要包含任何其他文字):
|
|
204
|
+
{"anomalies":[]}`;
|
|
205
|
+
/**
|
|
206
|
+
* Compare two screenshots with pixel diff.
|
|
207
|
+
* Returns changed regions and optionally saves a diff image.
|
|
208
|
+
*/
|
|
209
|
+
export async function compareScreenshotDiff(config, baselinePath, currentPath, diffPath, route) {
|
|
210
|
+
const pixelmatch = _require("pixelmatch");
|
|
211
|
+
const { PNG } = _require("pngjs");
|
|
212
|
+
if (!existsSync(baselinePath)) {
|
|
213
|
+
throw new Error("Baseline screenshot not found: " + baselinePath);
|
|
214
|
+
}
|
|
215
|
+
if (!existsSync(currentPath)) {
|
|
216
|
+
throw new Error("Current screenshot not found: " + currentPath);
|
|
217
|
+
}
|
|
218
|
+
const img1 = PNG.sync.read(readFileSync(baselinePath));
|
|
219
|
+
const img2 = PNG.sync.read(readFileSync(currentPath));
|
|
220
|
+
if (img1.width !== img2.width || img1.height !== img2.height) {
|
|
221
|
+
throw new Error(`Screenshot dimensions mismatch: ${img1.width}x${img1.height} vs ${img2.width}x${img2.height}`);
|
|
222
|
+
}
|
|
223
|
+
const diff = new PNG(img1.width, img1.height);
|
|
224
|
+
const changedPixels = pixelmatch(img1.data, img2.data, diff.data, img1.width, img1.height, { threshold: 0.1 });
|
|
225
|
+
const changedRatio = changedPixels / (img1.width * img1.height);
|
|
226
|
+
// Save diff image
|
|
227
|
+
writeFileSync(diffPath, PNG.sync.write(diff));
|
|
228
|
+
// If no meaningful changes, skip VLM analysis
|
|
229
|
+
if (changedRatio < 0.001) {
|
|
230
|
+
return { changed: false, anomalies: [] };
|
|
231
|
+
}
|
|
232
|
+
// Analyze diff image with VLM (only diff image to avoid context overflow)
|
|
233
|
+
const diffB64 = readFileSync(diffPath).toString("base64");
|
|
234
|
+
const response = await fetch(`${config.url}/api/generate`, {
|
|
235
|
+
method: "POST",
|
|
236
|
+
headers: { "Content-Type": "application/json" },
|
|
237
|
+
body: JSON.stringify({
|
|
238
|
+
model: config.model,
|
|
239
|
+
prompt: DIFF_PROMPT,
|
|
240
|
+
images: [diffB64],
|
|
241
|
+
stream: false,
|
|
242
|
+
}),
|
|
243
|
+
});
|
|
244
|
+
if (!response.ok) {
|
|
245
|
+
throw new Error(`Ollama API error: ${response.status}`);
|
|
246
|
+
}
|
|
247
|
+
const data = (await response.json());
|
|
248
|
+
const responseText = data.response || "";
|
|
249
|
+
let jsonStr = responseText;
|
|
250
|
+
const jsonMatch = responseText.match(/```(?:json)?\s*([\s\S]*?)```/);
|
|
251
|
+
if (jsonMatch) {
|
|
252
|
+
jsonStr = jsonMatch[1];
|
|
253
|
+
}
|
|
254
|
+
try {
|
|
255
|
+
const parsed = JSON.parse(jsonStr.trim());
|
|
256
|
+
const anomalies = (parsed.anomalies || []).map((a) => ({
|
|
257
|
+
...a,
|
|
258
|
+
route,
|
|
259
|
+
screenshot: currentPath,
|
|
260
|
+
changed: true,
|
|
261
|
+
}));
|
|
262
|
+
return { changed: true, anomalies };
|
|
263
|
+
}
|
|
264
|
+
catch {
|
|
265
|
+
console.error(`Warning: Could not parse diff response for ${route}`);
|
|
266
|
+
return { changed: true, anomalies: [] };
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
// ── HTML Report ─────────────────────────────────────────────────────────────
|
|
270
|
+
/**
|
|
271
|
+
* Generate a self-contained HTML report with embedded screenshots and results.
|
|
272
|
+
* If diffDir is provided, diff images are shown alongside current screenshots.
|
|
273
|
+
*/
|
|
274
|
+
export function generateHtmlReport(result, screenshots, outputPath, diffDir) {
|
|
275
|
+
const timestamp = new Date().toISOString();
|
|
276
|
+
// Group anomalies by severity
|
|
277
|
+
const bySeverity = {
|
|
278
|
+
blocking: [],
|
|
279
|
+
warning: [],
|
|
280
|
+
minor: [],
|
|
281
|
+
};
|
|
282
|
+
for (const a of result.anomalies) {
|
|
283
|
+
const key = a.severity || "minor";
|
|
284
|
+
if (bySeverity[key])
|
|
285
|
+
bySeverity[key].push(a);
|
|
286
|
+
}
|
|
287
|
+
// Build screenshot cards with base64 images
|
|
288
|
+
const screenshotCards = screenshots
|
|
289
|
+
.map((s) => {
|
|
290
|
+
const base64 = readFileSync(s.path).toString("base64");
|
|
291
|
+
// Check for diff image
|
|
292
|
+
let diffBase64 = "";
|
|
293
|
+
let hasDiff = false;
|
|
294
|
+
if (diffDir) {
|
|
295
|
+
const baseName = s.path.split("/").pop().replace(".png", "");
|
|
296
|
+
const diffPath = join(diffDir, `${baseName}-diff.png`);
|
|
297
|
+
if (existsSync(diffPath)) {
|
|
298
|
+
diffBase64 = readFileSync(diffPath).toString("base64");
|
|
299
|
+
hasDiff = true;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
const anomalies = result.anomalies.filter((a) => a.screenshot === s.path);
|
|
303
|
+
const badge = anomalies.length > 0
|
|
304
|
+
? `<span class="badge badge-${anomalies[0].severity}">${anomalies.length} issue${anomalies.length > 1 ? "s" : ""}</span>`
|
|
305
|
+
: `<span class="badge badge-ok">OK</span>`;
|
|
306
|
+
const anomalyList = anomalies.length > 0
|
|
307
|
+
? `<div class="anomaly-list">
|
|
308
|
+
${anomalies
|
|
309
|
+
.map((a) => ` <div class="anomaly-item severity-${a.severity}">
|
|
310
|
+
<div class="anomaly-header">
|
|
311
|
+
<span class="type-badge">${a.type}</span>
|
|
312
|
+
<span class="severity-badge ${a.severity}">${a.severity}</span>
|
|
313
|
+
${a.viewport ? `<span class="viewport-badge">${a.viewport}</span>` : ""}
|
|
314
|
+
${a.changed ? `<span class="diff-badge">changed</span>` : ""}
|
|
315
|
+
</div>
|
|
316
|
+
<div class="anomaly-body">
|
|
317
|
+
<strong>${a.element}</strong>
|
|
318
|
+
<p>${a.description}</p>
|
|
319
|
+
<div class="anomaly-meta">${a.position}</div>
|
|
320
|
+
</div>
|
|
321
|
+
</div>`)
|
|
322
|
+
.join("\n")}
|
|
323
|
+
</div>`
|
|
324
|
+
: "";
|
|
325
|
+
const diffSection = hasDiff
|
|
326
|
+
? `<div class="card-diff"><div class="diff-label">Diff</div><img src="data:image/png;base64,${diffBase64}" alt="diff" /></div>`
|
|
327
|
+
: "";
|
|
328
|
+
const currentSection = `<div class="card-img"><div class="img-label">Current</div><img src="data:image/png;base64,${base64}" alt="${s.route}" /></div>`;
|
|
329
|
+
const comparisonSection = hasDiff
|
|
330
|
+
? `<div class="card-comparison">${currentSection}${diffSection}</div>`
|
|
331
|
+
: currentSection;
|
|
332
|
+
return ` <div class="screenshot-card ${anomalies.length > 0 ? "has-issues" : ""}">
|
|
333
|
+
<div class="card-header">
|
|
334
|
+
<span class="route">${s.route}</span>
|
|
335
|
+
${badge}
|
|
336
|
+
</div>
|
|
337
|
+
<div class="card-body">${comparisonSection}</div>
|
|
338
|
+
${anomalyList}
|
|
339
|
+
</div>`;
|
|
340
|
+
})
|
|
341
|
+
.join("\n");
|
|
342
|
+
const html = `<!DOCTYPE html>
|
|
343
|
+
<html lang="en">
|
|
344
|
+
<head>
|
|
345
|
+
<meta charset="UTF-8">
|
|
346
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
347
|
+
<title>Vision Check Report</title>
|
|
348
|
+
<style>
|
|
349
|
+
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
350
|
+
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; background: #0f172a; color: #e2e8f0; padding: 24px; }
|
|
351
|
+
.header { margin-bottom: 24px; }
|
|
352
|
+
.header h1 { font-size: 24px; font-weight: 600; color: #f8fafc; }
|
|
353
|
+
.meta { font-size: 13px; color: #94a3b8; margin-top: 4px; }
|
|
354
|
+
.summary { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 12px; margin-bottom: 32px; }
|
|
355
|
+
.stat-card { background: #1e293b; border-radius: 12px; padding: 16px; }
|
|
356
|
+
.stat-value { font-size: 32px; font-weight: 700; }
|
|
357
|
+
.stat-label { font-size: 12px; color: #94a3b8; margin-top: 4px; }
|
|
358
|
+
.stat-blocking .stat-value { color: #ef4444; }
|
|
359
|
+
.stat-warning .stat-value { color: #f59e0b; }
|
|
360
|
+
.stat-minor .stat-value { color: #94a3b8; }
|
|
361
|
+
.stat-processed .stat-value { color: #22c55e; }
|
|
362
|
+
.section { margin-bottom: 32px; }
|
|
363
|
+
.section h2 { font-size: 18px; font-weight: 600; margin-bottom: 16px; color: #f8fafc; border-bottom: 1px solid #334155; padding-bottom: 8px; }
|
|
364
|
+
.screenshots-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(400px, 1fr)); gap: 16px; }
|
|
365
|
+
.screenshot-card { background: #1e293b; border-radius: 12px; overflow: hidden; border: 1px solid #334155; }
|
|
366
|
+
.screenshot-card.has-issues { border-color: #475569; }
|
|
367
|
+
.card-header { padding: 12px 16px; display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid #334155; }
|
|
368
|
+
.route { font-family: monospace; font-size: 14px; font-weight: 600; color: #f8fafc; }
|
|
369
|
+
.badge { font-size: 11px; font-weight: 600; padding: 3px 8px; border-radius: 9999px; }
|
|
370
|
+
.badge-ok { background: #14532d; color: #4ade80; }
|
|
371
|
+
.badge-blocking { background: #7f1d1d; color: #fca5a5; }
|
|
372
|
+
.badge-warning { background: #78350f; color: #fcd34d; }
|
|
373
|
+
.badge-minor { background: #1e293b; color: #94a3b8; border: 1px solid #475569; }
|
|
374
|
+
.card-body { padding: 8px; }
|
|
375
|
+
.card-comparison { display: grid; grid-template-columns: 1fr 1fr; gap: 4px; }
|
|
376
|
+
.card-img { position: relative; }
|
|
377
|
+
.img-label { position: absolute; top: 4px; left: 4px; font-size: 10px; background: rgba(0,0,0,0.6); color: #fff; padding: 2px 6px; border-radius: 4px; z-index: 1; }
|
|
378
|
+
.card-diff { position: relative; }
|
|
379
|
+
.diff-label { position: absolute; top: 4px; left: 4px; font-size: 10px; background: rgba(220,38,38,0.8); color: #fff; padding: 2px 6px; border-radius: 4px; z-index: 1; }
|
|
380
|
+
.card-body img { width: 100%; border-radius: 6px; display: block; }
|
|
381
|
+
.anomaly-list { padding: 12px 16px; border-top: 1px solid #334155; }
|
|
382
|
+
.anomaly-item { padding: 10px 12px; border-radius: 8px; margin-bottom: 8px; background: #0f172a; }
|
|
383
|
+
.anomaly-item:last-child { margin-bottom: 0; }
|
|
384
|
+
.anomaly-header { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; }
|
|
385
|
+
.type-badge { font-size: 11px; font-weight: 600; padding: 2px 6px; border-radius: 4px; background: #334155; color: #e2e8f0; font-family: monospace; }
|
|
386
|
+
.severity-badge { font-size: 11px; font-weight: 600; padding: 2px 6px; border-radius: 4px; }
|
|
387
|
+
.severity-badge.blocking { background: #7f1d1d; color: #fca5a5; }
|
|
388
|
+
.severity-badge.warning { background: #78350f; color: #fcd34d; }
|
|
389
|
+
.severity-badge.minor { background: #1e293b; color: #94a3b8; border: 1px solid #475569; }
|
|
390
|
+
.viewport-badge { font-size: 11px; padding: 2px 6px; border-radius: 4px; background: #312e81; color: #a5b4fc; }
|
|
391
|
+
.diff-badge { font-size: 11px; padding: 2px 6px; border-radius: 4px; background: #dc2626; color: #fff; font-family: monospace; }
|
|
392
|
+
.anomaly-body { }
|
|
393
|
+
.anomaly-body strong { font-size: 13px; color: #f8fafc; }
|
|
394
|
+
.anomaly-body p { font-size: 12px; color: #cbd5e1; margin-top: 4px; line-height: 1.5; }
|
|
395
|
+
.anomaly-meta { font-size: 11px; color: #64748b; margin-top: 4px; }
|
|
396
|
+
.empty-state { text-align: center; padding: 48px; color: #64748b; }
|
|
397
|
+
.empty-state h3 { font-size: 18px; color: #94a3b8; margin-bottom: 8px; }
|
|
398
|
+
.diff-indicator { display: inline-block; width: 8px; height: 8px; border-radius: 50%; background: #f59e0b; margin-right: 4px; }
|
|
399
|
+
.diff-mode { font-size: 14px; background: #dc2626; color: #fff; padding: 2px 8px; border-radius: 6px; font-weight: normal; vertical-align: middle; }
|
|
400
|
+
</style>
|
|
401
|
+
</head>
|
|
402
|
+
<body>
|
|
403
|
+
<div class="header">
|
|
404
|
+
<h1>Vision Check Report${diffDir ? " <span class='diff-mode'>DIFF MODE</span>" : ""}</h1>
|
|
405
|
+
<div class="meta">Generated: ${timestamp} | Ollama: ${result.ollamaUrl} | Model: ${result.model}${diffDir ? " | Baseline: " + result.baselineDir : ""}</div>
|
|
406
|
+
</div>
|
|
407
|
+
|
|
408
|
+
<div class="summary">
|
|
409
|
+
<div class="stat-card stat-processed">
|
|
410
|
+
<div class="stat-value">${result.processed}</div>
|
|
411
|
+
<div class="stat-label">Processed</div>
|
|
412
|
+
</div>
|
|
413
|
+
<div class="stat-card stat-blocking">
|
|
414
|
+
<div class="stat-value">${bySeverity.blocking.length}</div>
|
|
415
|
+
<div class="stat-label">Blocking</div>
|
|
416
|
+
</div>
|
|
417
|
+
<div class="stat-card stat-warning">
|
|
418
|
+
<div class="stat-value">${bySeverity.warning.length}</div>
|
|
419
|
+
<div class="stat-label">Warning</div>
|
|
420
|
+
</div>
|
|
421
|
+
<div class="stat-card stat-minor">
|
|
422
|
+
<div class="stat-value">${bySeverity.minor.length}</div>
|
|
423
|
+
<div class="stat-label">Minor</div>
|
|
424
|
+
</div>
|
|
425
|
+
</div>
|
|
426
|
+
|
|
427
|
+
<div class="section">
|
|
428
|
+
<h2>Screenshots (${screenshots.length})</h2>
|
|
429
|
+
${screenshotCards
|
|
430
|
+
? `<div class="screenshots-grid">${screenshotCards}</div>`
|
|
431
|
+
: `<div class="empty-state"><h3>No screenshots analyzed</h3></div>`}
|
|
432
|
+
</div>
|
|
433
|
+
|
|
434
|
+
${result.anomalies.length > 0
|
|
435
|
+
? `<div class="section">
|
|
436
|
+
<h2>All Anomalies</h2>
|
|
437
|
+
<div class="anomaly-list" style="padding:0;border:none;background:transparent">
|
|
438
|
+
${result.anomalies
|
|
439
|
+
.map((a) => ` <div class="anomaly-item severity-${a.severity}">
|
|
440
|
+
<div class="anomaly-header">
|
|
441
|
+
<span class="type-badge">${a.type}</span>
|
|
442
|
+
<span class="severity-badge ${a.severity}">${a.severity}</span>
|
|
443
|
+
${a.viewport ? `<span class="viewport-badge">${a.viewport}</span>` : ""}
|
|
444
|
+
${a.changed ? `<span class="diff-indicator" title="Pixel diff detected"></span>` : ""}
|
|
445
|
+
</div>
|
|
446
|
+
<div class="anomaly-body">
|
|
447
|
+
<strong>${a.element}</strong>
|
|
448
|
+
<p>${a.description}</p>
|
|
449
|
+
<div class="anomaly-meta">${a.route} · ${a.position}</div>
|
|
450
|
+
</div>
|
|
451
|
+
</div>`)
|
|
452
|
+
.join("\n")}
|
|
453
|
+
</div>
|
|
454
|
+
</div>`
|
|
455
|
+
: ""}
|
|
456
|
+
</body>
|
|
457
|
+
</html>`;
|
|
458
|
+
writeFileSync(outputPath, html, "utf-8");
|
|
459
|
+
}
|
|
208
460
|
//# sourceMappingURL=ollama.js.map
|
package/dist/utils/ollama.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ollama.js","sourceRoot":"","sources":["../../src/utils/ollama.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ollama.js","sourceRoot":"","sources":["../../src/utils/ollama.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openspec-playwright",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.16",
|
|
4
4
|
"description": "OpenSpec + Playwright E2E verification setup tool for Claude Code",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -23,12 +23,16 @@
|
|
|
23
23
|
"@types/tar": "^6.1.13",
|
|
24
24
|
"chalk": "^5.3.0",
|
|
25
25
|
"commander": "^12.1.0",
|
|
26
|
+
"dotenv": "^17.4.2",
|
|
26
27
|
"glob": "^13.0.6",
|
|
28
|
+
"pixelmatch": "^7.1.0",
|
|
27
29
|
"playwright": "^1.50.0",
|
|
30
|
+
"pngjs": "^7.0.0",
|
|
28
31
|
"tar": "^7.5.13"
|
|
29
32
|
},
|
|
30
33
|
"devDependencies": {
|
|
31
34
|
"@types/node": "^22.0.0",
|
|
35
|
+
"@types/pixelmatch": "^5.2.6",
|
|
32
36
|
"@typescript-eslint/eslint-plugin": "^8.58.0",
|
|
33
37
|
"@typescript-eslint/parser": "^8.58.0",
|
|
34
38
|
"@vitest/coverage-v8": "^4.1.2",
|
|
@@ -101,22 +101,6 @@ Persists assertion repairs (typos, spec drift) across sessions.
|
|
|
101
101
|
|
|
102
102
|
---
|
|
103
103
|
|
|
104
|
-
## Vision Check Config
|
|
105
|
-
|
|
106
|
-
Ollama VLM configuration for layout anomaly detection. See `openspec-pw doctor` for status.
|
|
107
|
-
|
|
108
|
-
```
|
|
109
|
-
ollama_url:
|
|
110
|
-
vision_model:
|
|
111
|
-
vision_enabled: false
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
> **Note**: Vision check is disabled by default. Configure `ollama_url` and `vision_model` to enable.
|
|
115
|
-
> Environment variables (`OLLAMA_URL`, `OLLAMA_VISION_MODEL`) override these values.
|
|
116
|
-
> Run `openspec-pw vision-check --dry-run` to verify configuration.
|
|
117
|
-
|
|
118
|
-
---
|
|
119
|
-
|
|
120
104
|
## Changelog
|
|
121
105
|
|
|
122
106
|
| Date | Change | By |
|