@browserflow-ai/cli 0.0.6
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/bin/bf.js +3 -0
- package/dist/commands/baseline.d.ts +77 -0
- package/dist/commands/baseline.d.ts.map +1 -0
- package/dist/commands/baseline.js +429 -0
- package/dist/commands/baseline.js.map +1 -0
- package/dist/commands/doctor.d.ts +39 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +230 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/explore.d.ts +12 -0
- package/dist/commands/explore.d.ts.map +1 -0
- package/dist/commands/explore.js +114 -0
- package/dist/commands/explore.js.map +1 -0
- package/dist/commands/init.d.ts +15 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +160 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/lint.d.ts +37 -0
- package/dist/commands/lint.d.ts.map +1 -0
- package/dist/commands/lint.js +248 -0
- package/dist/commands/lint.js.map +1 -0
- package/dist/commands/repair.d.ts +72 -0
- package/dist/commands/repair.d.ts.map +1 -0
- package/dist/commands/repair.js +271 -0
- package/dist/commands/repair.js.map +1 -0
- package/dist/commands/review.d.ts +26 -0
- package/dist/commands/review.d.ts.map +1 -0
- package/dist/commands/review.js +371 -0
- package/dist/commands/review.js.map +1 -0
- package/dist/commands/run.d.ts +5 -0
- package/dist/commands/run.d.ts.map +1 -0
- package/dist/commands/run.js +66 -0
- package/dist/commands/run.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +35 -0
- package/dist/index.js.map +1 -0
- package/dist/run/executor.d.ts +10 -0
- package/dist/run/executor.d.ts.map +1 -0
- package/dist/run/executor.js +95 -0
- package/dist/run/executor.js.map +1 -0
- package/dist/run/failure-bundle.d.ts +65 -0
- package/dist/run/failure-bundle.d.ts.map +1 -0
- package/dist/run/failure-bundle.js +253 -0
- package/dist/run/failure-bundle.js.map +1 -0
- package/dist/run/index.d.ts +6 -0
- package/dist/run/index.d.ts.map +1 -0
- package/dist/run/index.js +6 -0
- package/dist/run/index.js.map +1 -0
- package/dist/run/output.d.ts +5 -0
- package/dist/run/output.d.ts.map +1 -0
- package/dist/run/output.js +62 -0
- package/dist/run/output.js.map +1 -0
- package/dist/run/results.d.ts +5 -0
- package/dist/run/results.d.ts.map +1 -0
- package/dist/run/results.js +124 -0
- package/dist/run/results.js.map +1 -0
- package/dist/run/types.d.ts +44 -0
- package/dist/run/types.d.ts.map +1 -0
- package/dist/run/types.js +2 -0
- package/dist/run/types.js.map +1 -0
- package/dist/ui/box.d.ts +13 -0
- package/dist/ui/box.d.ts.map +1 -0
- package/dist/ui/box.js +32 -0
- package/dist/ui/box.js.map +1 -0
- package/dist/ui/colors.d.ts +28 -0
- package/dist/ui/colors.d.ts.map +1 -0
- package/dist/ui/colors.js +34 -0
- package/dist/ui/colors.js.map +1 -0
- package/dist/ui/env.d.ts +31 -0
- package/dist/ui/env.d.ts.map +1 -0
- package/dist/ui/env.js +77 -0
- package/dist/ui/env.js.map +1 -0
- package/dist/ui/index.d.ts +7 -0
- package/dist/ui/index.d.ts.map +1 -0
- package/dist/ui/index.js +7 -0
- package/dist/ui/index.js.map +1 -0
- package/dist/ui/output.d.ts +18 -0
- package/dist/ui/output.d.ts.map +1 -0
- package/dist/ui/output.js +33 -0
- package/dist/ui/output.js.map +1 -0
- package/dist/ui/prompts.d.ts +12 -0
- package/dist/ui/prompts.d.ts.map +1 -0
- package/dist/ui/prompts.js +37 -0
- package/dist/ui/prompts.js.map +1 -0
- package/dist/ui/spinner.d.ts +9 -0
- package/dist/ui/spinner.d.ts.map +1 -0
- package/dist/ui/spinner.js +27 -0
- package/dist/ui/spinner.js.map +1 -0
- package/package.json +78 -0
package/bin/bf.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* bf baseline commands - manage visual regression baselines
|
|
3
|
+
* @see bf-lp7
|
|
4
|
+
*/
|
|
5
|
+
import { Command } from 'commander';
|
|
6
|
+
export interface BaselineInfo {
|
|
7
|
+
name: string;
|
|
8
|
+
path: string;
|
|
9
|
+
status: 'match' | 'diff' | 'missing' | 'new';
|
|
10
|
+
diffPercent?: number;
|
|
11
|
+
}
|
|
12
|
+
export interface BaselineAcceptanceRecord {
|
|
13
|
+
accepted_at: string;
|
|
14
|
+
accepted_by: string;
|
|
15
|
+
run_id: string;
|
|
16
|
+
previous_hash: string | null;
|
|
17
|
+
current_hash: string;
|
|
18
|
+
}
|
|
19
|
+
export interface BaselineStatus {
|
|
20
|
+
specName: string;
|
|
21
|
+
baselines: BaselineInfo[];
|
|
22
|
+
newScreenshots: string[];
|
|
23
|
+
}
|
|
24
|
+
export interface AcceptResult {
|
|
25
|
+
accepted: string[];
|
|
26
|
+
failed: string[];
|
|
27
|
+
}
|
|
28
|
+
export declare class BaselineStore {
|
|
29
|
+
private baseDir;
|
|
30
|
+
constructor(projectRoot?: string);
|
|
31
|
+
getBaselinesForSpec(specName: string): Promise<BaselineInfo[]>;
|
|
32
|
+
getActualsFromRun(runDir: string): Promise<{
|
|
33
|
+
name: string;
|
|
34
|
+
path: string;
|
|
35
|
+
}[]>;
|
|
36
|
+
getLatestRun(specName: string): Promise<string | null>;
|
|
37
|
+
getRunDir(specName: string, runId: string): Promise<string>;
|
|
38
|
+
copyToBaselines(specName: string, screenshotName: string, sourcePath: string): Promise<string>;
|
|
39
|
+
recordAcceptance(specName: string, screenshotName: string, record: BaselineAcceptanceRecord): Promise<void>;
|
|
40
|
+
hashFile(filePath: string): Promise<string>;
|
|
41
|
+
getExistingBaselineHash(specName: string, screenshotName: string): Promise<string | null>;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Compare two image files to check if they match
|
|
45
|
+
*/
|
|
46
|
+
export declare function compareImages(path1: string, path2: string, options?: {
|
|
47
|
+
threshold?: number;
|
|
48
|
+
generateDiff?: boolean;
|
|
49
|
+
diffPath?: string;
|
|
50
|
+
}): Promise<{
|
|
51
|
+
match: boolean;
|
|
52
|
+
diffPercent: number;
|
|
53
|
+
diffPath?: string;
|
|
54
|
+
}>;
|
|
55
|
+
/**
|
|
56
|
+
* Get baseline status for a spec
|
|
57
|
+
*/
|
|
58
|
+
export declare function getBaselineStatus(specName: string, options?: {
|
|
59
|
+
cwd?: string;
|
|
60
|
+
}): Promise<BaselineStatus>;
|
|
61
|
+
/**
|
|
62
|
+
* Get pending baselines that need acceptance (diffs or new screenshots)
|
|
63
|
+
*/
|
|
64
|
+
export declare function getPendingBaselines(specName: string, options?: {
|
|
65
|
+
cwd?: string;
|
|
66
|
+
}): Promise<BaselineInfo[]>;
|
|
67
|
+
/**
|
|
68
|
+
* Accept baselines from a run
|
|
69
|
+
*/
|
|
70
|
+
export declare function acceptBaselines(specName: string, options?: {
|
|
71
|
+
runId?: string;
|
|
72
|
+
screenshot?: string;
|
|
73
|
+
all?: boolean;
|
|
74
|
+
cwd?: string;
|
|
75
|
+
}): Promise<AcceptResult>;
|
|
76
|
+
export declare function baselineCommand(): Command;
|
|
77
|
+
//# sourceMappingURL=baseline.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"baseline.d.ts","sourceRoot":"","sources":["../../src/commands/baseline.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,429 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* bf baseline commands - manage visual regression baselines
|
|
3
|
+
* @see bf-lp7
|
|
4
|
+
*/
|
|
5
|
+
import { Command } from 'commander';
|
|
6
|
+
import { readFile, readdir, access, copyFile, mkdir, writeFile, stat } from 'node:fs/promises';
|
|
7
|
+
import { join, basename } from 'node:path';
|
|
8
|
+
import { createHash } from 'node:crypto';
|
|
9
|
+
import { createInterface } from 'node:readline';
|
|
10
|
+
import { PNG } from 'pngjs';
|
|
11
|
+
import pixelmatch from 'pixelmatch';
|
|
12
|
+
import { colors, symbols } from '../ui/colors.js';
|
|
13
|
+
import { logHeader, logNewline, logSuccess, logError, logWarning } from '../ui/prompts.js';
|
|
14
|
+
import { isInteractive } from '../ui/env.js';
|
|
15
|
+
const BROWSERFLOW_DIR = '.browserflow';
|
|
16
|
+
const BASELINES_DIR = 'baselines';
|
|
17
|
+
const RUNS_DIR = 'runs';
|
|
18
|
+
/**
|
|
19
|
+
* Simple readline-based confirmation prompt
|
|
20
|
+
*/
|
|
21
|
+
async function confirm(message) {
|
|
22
|
+
if (!isInteractive()) {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
const rl = createInterface({
|
|
26
|
+
input: process.stdin,
|
|
27
|
+
output: process.stdout,
|
|
28
|
+
});
|
|
29
|
+
return new Promise((resolve) => {
|
|
30
|
+
rl.question(`${message} (y/N) `, (answer) => {
|
|
31
|
+
rl.close();
|
|
32
|
+
resolve(answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes');
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
export class BaselineStore {
|
|
37
|
+
baseDir;
|
|
38
|
+
constructor(projectRoot = process.cwd()) {
|
|
39
|
+
this.baseDir = join(projectRoot, BROWSERFLOW_DIR);
|
|
40
|
+
}
|
|
41
|
+
async getBaselinesForSpec(specName) {
|
|
42
|
+
const baselineDir = join(this.baseDir, BASELINES_DIR, specName);
|
|
43
|
+
try {
|
|
44
|
+
await access(baselineDir);
|
|
45
|
+
const entries = await readdir(baselineDir);
|
|
46
|
+
return entries
|
|
47
|
+
.filter((f) => f.endsWith('.png'))
|
|
48
|
+
.map((f) => ({
|
|
49
|
+
name: basename(f, '.png'),
|
|
50
|
+
path: join(baselineDir, f),
|
|
51
|
+
status: 'match',
|
|
52
|
+
}));
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return [];
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
async getActualsFromRun(runDir) {
|
|
59
|
+
const screenshotsDir = join(runDir, 'artifacts', 'screenshots');
|
|
60
|
+
try {
|
|
61
|
+
await access(screenshotsDir);
|
|
62
|
+
const entries = await readdir(screenshotsDir);
|
|
63
|
+
return entries
|
|
64
|
+
.filter((f) => f.endsWith('.png'))
|
|
65
|
+
.map((f) => ({
|
|
66
|
+
name: basename(f, '.png'),
|
|
67
|
+
path: join(screenshotsDir, f),
|
|
68
|
+
}));
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
return [];
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
async getLatestRun(specName) {
|
|
75
|
+
const specDir = join(this.baseDir, RUNS_DIR, specName);
|
|
76
|
+
try {
|
|
77
|
+
await access(specDir);
|
|
78
|
+
const entries = await readdir(specDir);
|
|
79
|
+
const runDirs = await Promise.all(entries
|
|
80
|
+
.filter((e) => e.startsWith('run-'))
|
|
81
|
+
.map(async (name) => {
|
|
82
|
+
const fullPath = join(specDir, name);
|
|
83
|
+
const stats = await stat(fullPath);
|
|
84
|
+
return { name, path: fullPath, mtime: stats.mtime.getTime() };
|
|
85
|
+
}));
|
|
86
|
+
if (runDirs.length === 0)
|
|
87
|
+
return null;
|
|
88
|
+
// Sort by modification time, most recent first
|
|
89
|
+
runDirs.sort((a, b) => b.mtime - a.mtime);
|
|
90
|
+
return runDirs[0].path;
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
async getRunDir(specName, runId) {
|
|
97
|
+
return join(this.baseDir, RUNS_DIR, specName, runId);
|
|
98
|
+
}
|
|
99
|
+
async copyToBaselines(specName, screenshotName, sourcePath) {
|
|
100
|
+
const baselineDir = join(this.baseDir, BASELINES_DIR, specName);
|
|
101
|
+
await mkdir(baselineDir, { recursive: true });
|
|
102
|
+
const destPath = join(baselineDir, `${screenshotName}.png`);
|
|
103
|
+
await copyFile(sourcePath, destPath);
|
|
104
|
+
return destPath;
|
|
105
|
+
}
|
|
106
|
+
async recordAcceptance(specName, screenshotName, record) {
|
|
107
|
+
const baselineDir = join(this.baseDir, BASELINES_DIR, specName);
|
|
108
|
+
await mkdir(baselineDir, { recursive: true });
|
|
109
|
+
const metaPath = join(baselineDir, `${screenshotName}.meta.json`);
|
|
110
|
+
await writeFile(metaPath, JSON.stringify(record, null, 2));
|
|
111
|
+
}
|
|
112
|
+
async hashFile(filePath) {
|
|
113
|
+
const content = await readFile(filePath);
|
|
114
|
+
return createHash('sha256').update(content).digest('hex').slice(0, 16);
|
|
115
|
+
}
|
|
116
|
+
async getExistingBaselineHash(specName, screenshotName) {
|
|
117
|
+
try {
|
|
118
|
+
const baselinePath = join(this.baseDir, BASELINES_DIR, specName, `${screenshotName}.png`);
|
|
119
|
+
return await this.hashFile(baselinePath);
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Compare two image files to check if they match
|
|
128
|
+
*/
|
|
129
|
+
export async function compareImages(path1, path2, options = {}) {
|
|
130
|
+
const { threshold = 0.1, generateDiff = true, diffPath } = options;
|
|
131
|
+
try {
|
|
132
|
+
const [img1Buffer, img2Buffer] = await Promise.all([
|
|
133
|
+
readFile(path1),
|
|
134
|
+
readFile(path2),
|
|
135
|
+
]);
|
|
136
|
+
const img1 = PNG.sync.read(img1Buffer);
|
|
137
|
+
const img2 = PNG.sync.read(img2Buffer);
|
|
138
|
+
// Handle size mismatch
|
|
139
|
+
if (img1.width !== img2.width || img1.height !== img2.height) {
|
|
140
|
+
return { match: false, diffPercent: 100 };
|
|
141
|
+
}
|
|
142
|
+
const { width, height } = img1;
|
|
143
|
+
const diff = generateDiff ? new PNG({ width, height }) : null;
|
|
144
|
+
const mismatchedPixels = pixelmatch(img1.data, img2.data, diff?.data ?? null, width, height, { threshold });
|
|
145
|
+
const totalPixels = width * height;
|
|
146
|
+
const diffPercent = (mismatchedPixels / totalPixels) * 100;
|
|
147
|
+
const match = mismatchedPixels === 0;
|
|
148
|
+
// Write diff image if requested and images differ
|
|
149
|
+
if (!match && diff && diffPath) {
|
|
150
|
+
await writeFile(diffPath, PNG.sync.write(diff));
|
|
151
|
+
return { match, diffPercent, diffPath };
|
|
152
|
+
}
|
|
153
|
+
return { match, diffPercent };
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
return { match: false, diffPercent: 0 };
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Get baseline status for a spec
|
|
161
|
+
*/
|
|
162
|
+
export async function getBaselineStatus(specName, options = {}) {
|
|
163
|
+
const cwd = options.cwd || process.cwd();
|
|
164
|
+
const store = new BaselineStore(cwd);
|
|
165
|
+
const baselines = await store.getBaselinesForSpec(specName);
|
|
166
|
+
const latestRun = await store.getLatestRun(specName);
|
|
167
|
+
if (!latestRun) {
|
|
168
|
+
return {
|
|
169
|
+
specName,
|
|
170
|
+
baselines: baselines.map((b) => ({ ...b, status: 'match' })),
|
|
171
|
+
newScreenshots: [],
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
const actuals = await store.getActualsFromRun(latestRun);
|
|
175
|
+
const actualMap = new Map(actuals.map((a) => [a.name, a]));
|
|
176
|
+
// Check status of each baseline
|
|
177
|
+
const baselineResults = [];
|
|
178
|
+
for (const baseline of baselines) {
|
|
179
|
+
const actual = actualMap.get(baseline.name);
|
|
180
|
+
if (!actual) {
|
|
181
|
+
baselineResults.push({ ...baseline, status: 'missing' });
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
const comparison = await compareImages(baseline.path, actual.path);
|
|
185
|
+
if (comparison.match) {
|
|
186
|
+
baselineResults.push({ ...baseline, status: 'match' });
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
baselineResults.push({
|
|
190
|
+
...baseline,
|
|
191
|
+
status: 'diff',
|
|
192
|
+
diffPercent: comparison.diffPercent,
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
// Find new screenshots (in actuals but not in baselines)
|
|
198
|
+
const baselineNames = new Set(baselines.map((b) => b.name));
|
|
199
|
+
const newScreenshots = actuals.filter((a) => !baselineNames.has(a.name)).map((a) => a.name);
|
|
200
|
+
return {
|
|
201
|
+
specName,
|
|
202
|
+
baselines: baselineResults,
|
|
203
|
+
newScreenshots,
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Get pending baselines that need acceptance (diffs or new screenshots)
|
|
208
|
+
*/
|
|
209
|
+
export async function getPendingBaselines(specName, options = {}) {
|
|
210
|
+
const status = await getBaselineStatus(specName, options);
|
|
211
|
+
// Include baselines with diffs (not missing - those aren't in latest run)
|
|
212
|
+
const diffs = status.baselines.filter(b => b.status === 'diff');
|
|
213
|
+
// Include new screenshots
|
|
214
|
+
const newScreenshots = status.newScreenshots.map(name => ({
|
|
215
|
+
name,
|
|
216
|
+
path: '', // Path not relevant for display
|
|
217
|
+
status: 'new',
|
|
218
|
+
}));
|
|
219
|
+
return [...diffs, ...newScreenshots];
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Accept baselines from a run
|
|
223
|
+
*/
|
|
224
|
+
export async function acceptBaselines(specName, options = {}) {
|
|
225
|
+
const cwd = options.cwd || process.cwd();
|
|
226
|
+
const store = new BaselineStore(cwd);
|
|
227
|
+
// Find run directory
|
|
228
|
+
let runDir;
|
|
229
|
+
if (options.runId) {
|
|
230
|
+
runDir = await store.getRunDir(specName, options.runId);
|
|
231
|
+
}
|
|
232
|
+
else {
|
|
233
|
+
const latest = await store.getLatestRun(specName);
|
|
234
|
+
if (!latest) {
|
|
235
|
+
return { accepted: [], failed: ['No runs found'] };
|
|
236
|
+
}
|
|
237
|
+
runDir = latest;
|
|
238
|
+
}
|
|
239
|
+
// Get actuals from run
|
|
240
|
+
const actuals = await store.getActualsFromRun(runDir);
|
|
241
|
+
// Filter if specific screenshot requested
|
|
242
|
+
const toAccept = options.screenshot
|
|
243
|
+
? actuals.filter((a) => a.name === options.screenshot)
|
|
244
|
+
: actuals;
|
|
245
|
+
if (toAccept.length === 0) {
|
|
246
|
+
return { accepted: [], failed: ['No screenshots found to accept'] };
|
|
247
|
+
}
|
|
248
|
+
const accepted = [];
|
|
249
|
+
const failed = [];
|
|
250
|
+
for (const actual of toAccept) {
|
|
251
|
+
try {
|
|
252
|
+
// Get existing hash for recording
|
|
253
|
+
const previousHash = await store.getExistingBaselineHash(specName, actual.name);
|
|
254
|
+
// Copy to baselines
|
|
255
|
+
await store.copyToBaselines(specName, actual.name, actual.path);
|
|
256
|
+
// Calculate new hash
|
|
257
|
+
const currentHash = await store.hashFile(actual.path);
|
|
258
|
+
// Record acceptance metadata
|
|
259
|
+
const record = {
|
|
260
|
+
accepted_at: new Date().toISOString(),
|
|
261
|
+
accepted_by: process.env.USER || 'unknown',
|
|
262
|
+
run_id: basename(runDir),
|
|
263
|
+
previous_hash: previousHash,
|
|
264
|
+
current_hash: currentHash,
|
|
265
|
+
};
|
|
266
|
+
await store.recordAcceptance(specName, actual.name, record);
|
|
267
|
+
accepted.push(actual.name);
|
|
268
|
+
}
|
|
269
|
+
catch (e) {
|
|
270
|
+
const err = e;
|
|
271
|
+
failed.push(`${actual.name}: ${err.message}`);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
return { accepted, failed };
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Print baseline status
|
|
278
|
+
*/
|
|
279
|
+
function printBaselineStatus(status) {
|
|
280
|
+
console.log(`Baseline status for: ${colors.bold(status.specName)}\n`);
|
|
281
|
+
if (status.baselines.length === 0 && status.newScreenshots.length === 0) {
|
|
282
|
+
console.log(colors.dim(' No baselines or screenshots found.'));
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
for (const baseline of status.baselines) {
|
|
286
|
+
let icon;
|
|
287
|
+
let statusText;
|
|
288
|
+
switch (baseline.status) {
|
|
289
|
+
case 'match':
|
|
290
|
+
icon = symbols.pass;
|
|
291
|
+
statusText = '';
|
|
292
|
+
break;
|
|
293
|
+
case 'diff':
|
|
294
|
+
icon = symbols.fail;
|
|
295
|
+
statusText = baseline.diffPercent
|
|
296
|
+
? colors.warning(` (differs by ${baseline.diffPercent.toFixed(1)}%)`)
|
|
297
|
+
: colors.warning(' (differs)');
|
|
298
|
+
break;
|
|
299
|
+
case 'missing':
|
|
300
|
+
icon = colors.warning('?');
|
|
301
|
+
statusText = colors.dim(' (no actual in latest run)');
|
|
302
|
+
break;
|
|
303
|
+
default:
|
|
304
|
+
icon = symbols.pending;
|
|
305
|
+
statusText = '';
|
|
306
|
+
}
|
|
307
|
+
console.log(` ${icon} ${baseline.name}${statusText}`);
|
|
308
|
+
}
|
|
309
|
+
if (status.newScreenshots.length > 0) {
|
|
310
|
+
logNewline();
|
|
311
|
+
console.log(colors.dim('New screenshots (not in baselines):'));
|
|
312
|
+
for (const name of status.newScreenshots) {
|
|
313
|
+
console.log(` ${colors.info('+')} ${name}`);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
export function baselineCommand() {
|
|
318
|
+
const cmd = new Command('baseline');
|
|
319
|
+
cmd.description('Manage visual regression baselines');
|
|
320
|
+
// bf baseline status --spec <name>
|
|
321
|
+
cmd
|
|
322
|
+
.command('status')
|
|
323
|
+
.description('Show baseline status for a spec')
|
|
324
|
+
.requiredOption('-s, --spec <name>', 'Spec name')
|
|
325
|
+
.action(async (options) => {
|
|
326
|
+
logHeader('Baseline Status');
|
|
327
|
+
logNewline();
|
|
328
|
+
const status = await getBaselineStatus(options.spec);
|
|
329
|
+
printBaselineStatus(status);
|
|
330
|
+
});
|
|
331
|
+
// bf baseline accept --spec <name> [--run-id <id>] [--all]
|
|
332
|
+
cmd
|
|
333
|
+
.command('accept')
|
|
334
|
+
.description('Accept screenshots as new baselines')
|
|
335
|
+
.requiredOption('-s, --spec <name>', 'Spec name')
|
|
336
|
+
.option('-r, --run-id <id>', 'Specific run ID to accept from')
|
|
337
|
+
.option('--screenshot <name>', 'Accept only this screenshot')
|
|
338
|
+
.option('--all', 'Accept all screenshots without confirmation')
|
|
339
|
+
.action(async (options) => {
|
|
340
|
+
logHeader('Accept Baselines');
|
|
341
|
+
logNewline();
|
|
342
|
+
// Without --all or --screenshot, require confirmation
|
|
343
|
+
if (!options.all && !options.screenshot) {
|
|
344
|
+
const pending = await getPendingBaselines(options.spec);
|
|
345
|
+
if (pending.length === 0) {
|
|
346
|
+
console.log(colors.dim('No pending baselines to accept'));
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
console.log(`Found ${colors.info(pending.length.toString())} pending baseline${pending.length > 1 ? 's' : ''}:`);
|
|
350
|
+
for (const baseline of pending) {
|
|
351
|
+
const statusIcon = baseline.status === 'diff' ? symbols.fail : symbols.pending;
|
|
352
|
+
const statusText = baseline.status === 'diff'
|
|
353
|
+
? colors.fail('differs from current')
|
|
354
|
+
: colors.info('new screenshot');
|
|
355
|
+
console.log(` ${statusIcon} ${baseline.name} ${colors.dim(`(${statusText})`)}`);
|
|
356
|
+
}
|
|
357
|
+
logNewline();
|
|
358
|
+
const confirmed = await confirm(`Accept all ${pending.length} baseline${pending.length > 1 ? 's' : ''}?`);
|
|
359
|
+
if (!confirmed) {
|
|
360
|
+
console.log(colors.dim('Cancelled'));
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
363
|
+
logNewline();
|
|
364
|
+
}
|
|
365
|
+
const result = await acceptBaselines(options.spec, {
|
|
366
|
+
runId: options.runId,
|
|
367
|
+
screenshot: options.screenshot,
|
|
368
|
+
all: options.all || true, // If we got here, user confirmed
|
|
369
|
+
});
|
|
370
|
+
if (result.accepted.length > 0) {
|
|
371
|
+
for (const name of result.accepted) {
|
|
372
|
+
logSuccess(`Accepted: ${name}`);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
if (result.failed.length > 0) {
|
|
376
|
+
for (const name of result.failed) {
|
|
377
|
+
logError(`Failed: ${name}`);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
logNewline();
|
|
381
|
+
console.log(`${colors.pass(`${result.accepted.length} accepted`)}, ${colors.fail(`${result.failed.length} failed`)}`);
|
|
382
|
+
});
|
|
383
|
+
// bf baseline update --spec <name> (alias for accept from latest)
|
|
384
|
+
cmd
|
|
385
|
+
.command('update')
|
|
386
|
+
.description('Update baselines from the latest run (alias for accept --all)')
|
|
387
|
+
.requiredOption('-s, --spec <name>', 'Spec name')
|
|
388
|
+
.action(async (options) => {
|
|
389
|
+
logHeader('Update Baselines');
|
|
390
|
+
logNewline();
|
|
391
|
+
const result = await acceptBaselines(options.spec, { all: true });
|
|
392
|
+
if (result.accepted.length > 0) {
|
|
393
|
+
for (const name of result.accepted) {
|
|
394
|
+
logSuccess(`Updated: ${name}`);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
if (result.failed.length > 0) {
|
|
398
|
+
for (const name of result.failed) {
|
|
399
|
+
logError(`Failed: ${name}`);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
logNewline();
|
|
403
|
+
console.log(`${colors.pass(`${result.accepted.length} updated`)}, ${colors.fail(`${result.failed.length} failed`)}`);
|
|
404
|
+
});
|
|
405
|
+
// bf baseline diff --spec <name> - would open Review UI
|
|
406
|
+
cmd
|
|
407
|
+
.command('diff')
|
|
408
|
+
.description('Open Review UI to view diff gallery')
|
|
409
|
+
.requiredOption('-s, --spec <name>', 'Spec name')
|
|
410
|
+
.action(async (options) => {
|
|
411
|
+
logHeader('Baseline Diff');
|
|
412
|
+
logNewline();
|
|
413
|
+
const status = await getBaselineStatus(options.spec);
|
|
414
|
+
const diffs = status.baselines.filter((b) => b.status === 'diff');
|
|
415
|
+
if (diffs.length === 0) {
|
|
416
|
+
console.log(colors.pass('No differences found. All baselines match.'));
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
console.log(`Found ${diffs.length} difference(s):`);
|
|
420
|
+
for (const diff of diffs) {
|
|
421
|
+
console.log(` ${symbols.fail} ${diff.name}`);
|
|
422
|
+
}
|
|
423
|
+
logNewline();
|
|
424
|
+
console.log(colors.dim('To open the Review UI, run: bf review --spec ' + options.spec));
|
|
425
|
+
// In a full implementation, this would launch a server and open the browser
|
|
426
|
+
});
|
|
427
|
+
return cmd;
|
|
428
|
+
}
|
|
429
|
+
//# sourceMappingURL=baseline.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"baseline.js","sourceRoot":"","sources":["../../src/commands/baseline.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
export interface CheckResult {
|
|
3
|
+
status: 'pass' | 'warn' | 'fail';
|
|
4
|
+
message: string;
|
|
5
|
+
fixHint?: string;
|
|
6
|
+
}
|
|
7
|
+
export interface Check {
|
|
8
|
+
name: string;
|
|
9
|
+
check: () => Promise<CheckResult>;
|
|
10
|
+
fix?: () => Promise<void>;
|
|
11
|
+
}
|
|
12
|
+
export interface CheckOutput {
|
|
13
|
+
name: string;
|
|
14
|
+
result: CheckResult;
|
|
15
|
+
}
|
|
16
|
+
export interface DoctorResult {
|
|
17
|
+
checks: CheckOutput[];
|
|
18
|
+
summary: {
|
|
19
|
+
passed: number;
|
|
20
|
+
warnings: number;
|
|
21
|
+
failed: number;
|
|
22
|
+
};
|
|
23
|
+
exitCode: number;
|
|
24
|
+
}
|
|
25
|
+
export interface DoctorOptions {
|
|
26
|
+
fix?: boolean;
|
|
27
|
+
verbose?: boolean;
|
|
28
|
+
}
|
|
29
|
+
export declare function checkNodeVersion(): Promise<CheckResult>;
|
|
30
|
+
export declare function checkAgentBrowser(): Promise<CheckResult>;
|
|
31
|
+
export declare function checkPlaywrightBrowsers(): Promise<CheckResult>;
|
|
32
|
+
export declare function checkConfiguration(): Promise<CheckResult>;
|
|
33
|
+
export declare function checkReviewPort(): Promise<CheckResult>;
|
|
34
|
+
export declare function createMockChecks(options?: {
|
|
35
|
+
allPass?: boolean;
|
|
36
|
+
}): Check[];
|
|
37
|
+
export declare function runDoctor(options: DoctorOptions, checks?: Check[]): Promise<DoctorResult>;
|
|
38
|
+
export declare function doctorCommand(): Command;
|
|
39
|
+
//# sourceMappingURL=doctor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAYpC,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,KAAK;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,OAAO,CAAC,WAAW,CAAC,CAAC;IAClC,GAAG,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3B;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,WAAW,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,OAAO,EAAE;QACP,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAuBD,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,WAAW,CAAC,CAa7D;AAED,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,WAAW,CAAC,CAc9D;AAED,wBAAsB,uBAAuB,IAAI,OAAO,CAAC,WAAW,CAAC,CAgCpE;AAkBD,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,WAAW,CAAC,CAY/D;AAED,wBAAsB,eAAe,IAAI,OAAO,CAAC,WAAW,CAAC,CAc5D;AAYD,wBAAgB,gBAAgB,CAAC,OAAO,GAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,KAAK,EAAE,CAW7E;AAED,wBAAsB,SAAS,CAC7B,OAAO,EAAE,aAAa,EACtB,MAAM,GAAE,KAAK,EAA0B,GACtC,OAAO,CAAC,YAAY,CAAC,CA8BvB;AAyBD,wBAAgB,aAAa,IAAI,OAAO,CAoCvC"}
|