@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.
Files changed (90) hide show
  1. package/bin/bf.js +3 -0
  2. package/dist/commands/baseline.d.ts +77 -0
  3. package/dist/commands/baseline.d.ts.map +1 -0
  4. package/dist/commands/baseline.js +429 -0
  5. package/dist/commands/baseline.js.map +1 -0
  6. package/dist/commands/doctor.d.ts +39 -0
  7. package/dist/commands/doctor.d.ts.map +1 -0
  8. package/dist/commands/doctor.js +230 -0
  9. package/dist/commands/doctor.js.map +1 -0
  10. package/dist/commands/explore.d.ts +12 -0
  11. package/dist/commands/explore.d.ts.map +1 -0
  12. package/dist/commands/explore.js +114 -0
  13. package/dist/commands/explore.js.map +1 -0
  14. package/dist/commands/init.d.ts +15 -0
  15. package/dist/commands/init.d.ts.map +1 -0
  16. package/dist/commands/init.js +160 -0
  17. package/dist/commands/init.js.map +1 -0
  18. package/dist/commands/lint.d.ts +37 -0
  19. package/dist/commands/lint.d.ts.map +1 -0
  20. package/dist/commands/lint.js +248 -0
  21. package/dist/commands/lint.js.map +1 -0
  22. package/dist/commands/repair.d.ts +72 -0
  23. package/dist/commands/repair.d.ts.map +1 -0
  24. package/dist/commands/repair.js +271 -0
  25. package/dist/commands/repair.js.map +1 -0
  26. package/dist/commands/review.d.ts +26 -0
  27. package/dist/commands/review.d.ts.map +1 -0
  28. package/dist/commands/review.js +371 -0
  29. package/dist/commands/review.js.map +1 -0
  30. package/dist/commands/run.d.ts +5 -0
  31. package/dist/commands/run.d.ts.map +1 -0
  32. package/dist/commands/run.js +66 -0
  33. package/dist/commands/run.js.map +1 -0
  34. package/dist/index.d.ts +4 -0
  35. package/dist/index.d.ts.map +1 -0
  36. package/dist/index.js +35 -0
  37. package/dist/index.js.map +1 -0
  38. package/dist/run/executor.d.ts +10 -0
  39. package/dist/run/executor.d.ts.map +1 -0
  40. package/dist/run/executor.js +95 -0
  41. package/dist/run/executor.js.map +1 -0
  42. package/dist/run/failure-bundle.d.ts +65 -0
  43. package/dist/run/failure-bundle.d.ts.map +1 -0
  44. package/dist/run/failure-bundle.js +253 -0
  45. package/dist/run/failure-bundle.js.map +1 -0
  46. package/dist/run/index.d.ts +6 -0
  47. package/dist/run/index.d.ts.map +1 -0
  48. package/dist/run/index.js +6 -0
  49. package/dist/run/index.js.map +1 -0
  50. package/dist/run/output.d.ts +5 -0
  51. package/dist/run/output.d.ts.map +1 -0
  52. package/dist/run/output.js +62 -0
  53. package/dist/run/output.js.map +1 -0
  54. package/dist/run/results.d.ts +5 -0
  55. package/dist/run/results.d.ts.map +1 -0
  56. package/dist/run/results.js +124 -0
  57. package/dist/run/results.js.map +1 -0
  58. package/dist/run/types.d.ts +44 -0
  59. package/dist/run/types.d.ts.map +1 -0
  60. package/dist/run/types.js +2 -0
  61. package/dist/run/types.js.map +1 -0
  62. package/dist/ui/box.d.ts +13 -0
  63. package/dist/ui/box.d.ts.map +1 -0
  64. package/dist/ui/box.js +32 -0
  65. package/dist/ui/box.js.map +1 -0
  66. package/dist/ui/colors.d.ts +28 -0
  67. package/dist/ui/colors.d.ts.map +1 -0
  68. package/dist/ui/colors.js +34 -0
  69. package/dist/ui/colors.js.map +1 -0
  70. package/dist/ui/env.d.ts +31 -0
  71. package/dist/ui/env.d.ts.map +1 -0
  72. package/dist/ui/env.js +77 -0
  73. package/dist/ui/env.js.map +1 -0
  74. package/dist/ui/index.d.ts +7 -0
  75. package/dist/ui/index.d.ts.map +1 -0
  76. package/dist/ui/index.js +7 -0
  77. package/dist/ui/index.js.map +1 -0
  78. package/dist/ui/output.d.ts +18 -0
  79. package/dist/ui/output.d.ts.map +1 -0
  80. package/dist/ui/output.js +33 -0
  81. package/dist/ui/output.js.map +1 -0
  82. package/dist/ui/prompts.d.ts +12 -0
  83. package/dist/ui/prompts.d.ts.map +1 -0
  84. package/dist/ui/prompts.js +37 -0
  85. package/dist/ui/prompts.js.map +1 -0
  86. package/dist/ui/spinner.d.ts +9 -0
  87. package/dist/ui/spinner.d.ts.map +1 -0
  88. package/dist/ui/spinner.js +27 -0
  89. package/dist/ui/spinner.js.map +1 -0
  90. package/package.json +78 -0
package/bin/bf.js ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env bun
2
+ import { run } from '../dist/index.js';
3
+ run();
@@ -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"}