@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
@@ -0,0 +1,371 @@
1
+ /**
2
+ * bf review command - start review server for exploration approval
3
+ * @see bf-kqu
4
+ */
5
+ import { Command } from 'commander';
6
+ import { readFile, writeFile, readdir, access } from 'node:fs/promises';
7
+ import { join, dirname } from 'node:path';
8
+ import { fileURLToPath } from 'node:url';
9
+ import { colors } from '../ui/colors.js';
10
+ /**
11
+ * Load exploration data from disk
12
+ */
13
+ export async function loadExploration(id, cwd = process.cwd()) {
14
+ const explorationPath = join(cwd, '.browserflow', 'explorations', id, 'exploration.json');
15
+ try {
16
+ const content = await readFile(explorationPath, 'utf-8');
17
+ return JSON.parse(content);
18
+ }
19
+ catch (error) {
20
+ const err = error;
21
+ if (err.code === 'ENOENT') {
22
+ throw new Error(`Exploration not found: ${id}`);
23
+ }
24
+ if (err instanceof SyntaxError) {
25
+ throw new Error(`Invalid JSON in exploration file: ${err.message}`);
26
+ }
27
+ throw error;
28
+ }
29
+ }
30
+ /**
31
+ * Save review data to disk
32
+ */
33
+ export async function saveReview(id, reviewData, cwd = process.cwd()) {
34
+ const reviewPath = join(cwd, '.browserflow', 'explorations', id, 'review.json');
35
+ await writeFile(reviewPath, JSON.stringify(reviewData, null, 2));
36
+ return reviewPath;
37
+ }
38
+ /**
39
+ * List all available explorations
40
+ */
41
+ export async function listExplorations(cwd = process.cwd()) {
42
+ const explorationsDir = join(cwd, '.browserflow', 'explorations');
43
+ try {
44
+ const entries = await readdir(explorationsDir);
45
+ return entries.filter(e => e.startsWith('exp-'));
46
+ }
47
+ catch (error) {
48
+ const err = error;
49
+ if (err.code === 'ENOENT') {
50
+ return [];
51
+ }
52
+ throw error;
53
+ }
54
+ }
55
+ /**
56
+ * Get MIME type based on file extension
57
+ */
58
+ function getMimeType(pathname) {
59
+ const ext = pathname.split('.').pop()?.toLowerCase();
60
+ const mimeTypes = {
61
+ 'html': 'text/html',
62
+ 'css': 'text/css',
63
+ 'js': 'application/javascript',
64
+ 'json': 'application/json',
65
+ 'png': 'image/png',
66
+ 'jpg': 'image/jpeg',
67
+ 'jpeg': 'image/jpeg',
68
+ 'gif': 'image/gif',
69
+ 'svg': 'image/svg+xml',
70
+ 'ico': 'image/x-icon',
71
+ 'woff': 'font/woff',
72
+ 'woff2': 'font/woff2',
73
+ 'ttf': 'font/ttf',
74
+ };
75
+ return mimeTypes[ext || ''] || 'application/octet-stream';
76
+ }
77
+ /**
78
+ * Find the review-ui dist directory
79
+ * Checks multiple locations to support both development and installed package scenarios
80
+ * @param cwd Optional working directory for testing (used to find monorepo structure)
81
+ */
82
+ async function findReviewUIDistDir(cwd) {
83
+ const __dirname = dirname(fileURLToPath(import.meta.url));
84
+ const workingDir = cwd || process.cwd();
85
+ // When cwd is explicitly provided (testing), check that first
86
+ if (cwd) {
87
+ const testPath = join(cwd, 'packages', 'review-ui', 'dist');
88
+ try {
89
+ await access(testPath);
90
+ return testPath;
91
+ }
92
+ catch {
93
+ // Fall through to other methods
94
+ }
95
+ }
96
+ // Try to find @browserflow-ai/review-ui package (for installed scenarios)
97
+ try {
98
+ const reviewUiPkgPath = await import.meta.resolve?.('@browserflow-ai/review-ui/package.json');
99
+ if (reviewUiPkgPath) {
100
+ const pkgDir = dirname(fileURLToPath(reviewUiPkgPath));
101
+ const distDir = join(pkgDir, 'dist');
102
+ await access(distDir);
103
+ return distDir;
104
+ }
105
+ }
106
+ catch {
107
+ // Package resolution failed, try filesystem paths
108
+ }
109
+ // Fallback: check filesystem locations
110
+ const candidates = [
111
+ // 1. Development: from repo root / cwd
112
+ join(workingDir, 'packages', 'review-ui', 'dist'),
113
+ // 2. Development: monorepo structure (running from source)
114
+ join(__dirname, '..', '..', '..', '..', 'review-ui', 'dist'),
115
+ // 3. Installed package: review-ui as sibling in node_modules
116
+ join(__dirname, '..', '..', '..', 'review-ui', 'dist'),
117
+ ];
118
+ for (const candidate of candidates) {
119
+ try {
120
+ await access(candidate);
121
+ return candidate;
122
+ }
123
+ catch {
124
+ // Try next candidate
125
+ }
126
+ }
127
+ throw new Error('Review UI not found. If running from source, build it with: cd packages/review-ui && bun run build');
128
+ }
129
+ /**
130
+ * Serve static files from review-ui dist
131
+ * @param pathname The URL pathname to serve
132
+ * @param cwd Optional working directory for testing
133
+ * @internal Exported for testing
134
+ */
135
+ export async function serveStaticUI(pathname, cwd) {
136
+ let distDir;
137
+ try {
138
+ distDir = await findReviewUIDistDir(cwd);
139
+ }
140
+ catch (error) {
141
+ return new Response(error.message, { status: 500 });
142
+ }
143
+ try {
144
+ // Serve index.html for root path
145
+ if (pathname === '/' || pathname === '/index.html') {
146
+ const indexPath = join(distDir, 'index.html');
147
+ const content = await readFile(indexPath, 'utf-8');
148
+ return new Response(content, {
149
+ headers: { 'Content-Type': 'text/html' },
150
+ });
151
+ }
152
+ // Try to serve static file from dist
153
+ // Remove leading slash from pathname
154
+ const filePath = join(distDir, pathname.slice(1));
155
+ // Check if file exists and is within distDir (prevent directory traversal)
156
+ if (!filePath.startsWith(distDir)) {
157
+ return new Response('Not Found', { status: 404 });
158
+ }
159
+ try {
160
+ const content = await readFile(filePath);
161
+ const mimeType = getMimeType(pathname);
162
+ return new Response(content, {
163
+ headers: { 'Content-Type': mimeType },
164
+ });
165
+ }
166
+ catch (error) {
167
+ const err = error;
168
+ // If file not found and it's not an /assets/ request, fallback to index.html for SPA routing
169
+ if (err.code === 'ENOENT' && !pathname.startsWith('/assets/')) {
170
+ const indexPath = join(distDir, 'index.html');
171
+ const content = await readFile(indexPath, 'utf-8');
172
+ return new Response(content, {
173
+ headers: { 'Content-Type': 'text/html' },
174
+ });
175
+ }
176
+ // Return 404 for non-existent files in /assets/
177
+ return new Response('Not Found', { status: 404 });
178
+ }
179
+ }
180
+ catch (error) {
181
+ // If dist directory doesn't exist, return error
182
+ return new Response('Review UI not built. Run: cd packages/review-ui && bun run build', {
183
+ status: 500
184
+ });
185
+ }
186
+ }
187
+ /**
188
+ * Open browser to the review UI
189
+ */
190
+ async function openBrowser(url) {
191
+ const { spawn } = await import('node:child_process');
192
+ // Use platform-appropriate command to open browser
193
+ const cmd = process.platform === 'darwin'
194
+ ? 'open'
195
+ : process.platform === 'win32'
196
+ ? 'cmd'
197
+ : 'xdg-open';
198
+ const args = process.platform === 'win32'
199
+ ? ['/c', 'start', url]
200
+ : [url];
201
+ try {
202
+ const child = spawn(cmd, args, {
203
+ detached: true,
204
+ stdio: 'ignore'
205
+ });
206
+ child.on('error', () => {
207
+ console.log(colors.dim(`Could not auto-open browser. Visit: ${url}`));
208
+ });
209
+ child.unref();
210
+ }
211
+ catch {
212
+ console.log(colors.dim(`Could not auto-open browser. Visit: ${url}`));
213
+ }
214
+ }
215
+ export function reviewCommand() {
216
+ return new Command('review')
217
+ .description('Start review server for exploration approval')
218
+ .option('--exploration <id>', 'Specific exploration ID to review')
219
+ .option('--port <port>', 'Server port', '8190')
220
+ .option('--no-open', "Don't auto-open browser")
221
+ .action(async (options) => {
222
+ const port = parseInt(options.port, 10);
223
+ const cwd = process.cwd();
224
+ try {
225
+ const server = Bun.serve({
226
+ port,
227
+ async fetch(req) {
228
+ const url = new URL(req.url);
229
+ // Serve exploration data
230
+ if (url.pathname === '/api/exploration') {
231
+ const id = url.searchParams.get('id') || options.exploration;
232
+ if (!id) {
233
+ // List available explorations
234
+ const explorations = await listExplorations(cwd);
235
+ return Response.json({ explorations });
236
+ }
237
+ try {
238
+ const data = await loadExploration(id, cwd);
239
+ return Response.json(data);
240
+ }
241
+ catch (error) {
242
+ const err = error;
243
+ return Response.json({ error: err.message }, { status: 404 });
244
+ }
245
+ }
246
+ // Handle review submission (POST /api/reviews/:id)
247
+ if (url.pathname.startsWith('/api/reviews/') && req.method === 'POST') {
248
+ const id = url.pathname.split('/').pop() || '';
249
+ if (!id) {
250
+ return Response.json({ error: 'Exploration ID is required' }, { status: 400 });
251
+ }
252
+ try {
253
+ const contentType = req.headers.get('content-type') || '';
254
+ let reviewData;
255
+ const screenshotBlobs = new Map();
256
+ if (contentType.includes('multipart/form-data')) {
257
+ // Parse multipart form data
258
+ const formData = await req.formData();
259
+ // Extract review JSON - can be string or File/Blob
260
+ const reviewDataField = formData.get('review_data');
261
+ let reviewDataStr;
262
+ if (typeof reviewDataField === 'string') {
263
+ reviewDataStr = reviewDataField;
264
+ }
265
+ else if (reviewDataField instanceof Blob) {
266
+ // Handle case where it's sent as a file
267
+ reviewDataStr = await reviewDataField.text();
268
+ }
269
+ else {
270
+ throw new Error('Missing review_data in form submission');
271
+ }
272
+ try {
273
+ reviewData = JSON.parse(reviewDataStr);
274
+ }
275
+ catch (parseErr) {
276
+ throw new Error(`Failed to parse review_data JSON: ${parseErr.message}`);
277
+ }
278
+ // Extract screenshot blobs (step-N-review files)
279
+ for (const [key, value] of formData.entries()) {
280
+ if (key.startsWith('step-') && key.endsWith('-review') && value instanceof Blob) {
281
+ screenshotBlobs.set(key, value);
282
+ }
283
+ }
284
+ }
285
+ else {
286
+ // Backwards compatibility: plain JSON
287
+ reviewData = await req.json();
288
+ }
289
+ // Save review.json
290
+ const reviewPath = await saveReview(id, reviewData, cwd);
291
+ // Save annotated screenshots if any
292
+ if (screenshotBlobs.size > 0) {
293
+ const screenshotsDir = join(cwd, '.browserflow', 'explorations', id, 'screenshots');
294
+ for (const [key, blob] of screenshotBlobs) {
295
+ // Extract step index from key (e.g., "step-2-review" -> "02")
296
+ const match = key.match(/^step-(\d+)-review$/);
297
+ if (match) {
298
+ const stepIndex = match[1];
299
+ const paddedIndex = stepIndex.padStart(2, '0');
300
+ const filename = `step-${paddedIndex}-review.png`;
301
+ const buffer = Buffer.from(await blob.arrayBuffer());
302
+ await writeFile(join(screenshotsDir, filename), buffer);
303
+ }
304
+ }
305
+ }
306
+ return Response.json({ success: true }, {
307
+ headers: {
308
+ 'X-Review-Path': reviewPath
309
+ }
310
+ });
311
+ }
312
+ catch (error) {
313
+ const err = error;
314
+ return Response.json({ error: err.message }, { status: 500 });
315
+ }
316
+ }
317
+ // Serve screenshots from explorations
318
+ if (url.pathname.startsWith('/api/screenshots/')) {
319
+ // Path format: /api/screenshots/{exp-id}/{filename}
320
+ const pathParts = url.pathname.split('/').filter(Boolean);
321
+ if (pathParts.length >= 4) {
322
+ const expId = pathParts[2];
323
+ const filename = pathParts.slice(3).join('/');
324
+ // Prevent directory traversal
325
+ if (filename.includes('..') || expId.includes('..')) {
326
+ return new Response('Forbidden', { status: 403 });
327
+ }
328
+ const screenshotPath = join(cwd, '.browserflow', 'explorations', expId, 'screenshots', filename);
329
+ // Ensure path is within the expected directory
330
+ const expectedBase = join(cwd, '.browserflow', 'explorations', expId, 'screenshots');
331
+ if (!screenshotPath.startsWith(expectedBase)) {
332
+ return new Response('Forbidden', { status: 403 });
333
+ }
334
+ try {
335
+ const content = await readFile(screenshotPath);
336
+ const mimeType = getMimeType(filename);
337
+ return new Response(content, {
338
+ headers: { 'Content-Type': mimeType },
339
+ });
340
+ }
341
+ catch (error) {
342
+ const err = error;
343
+ if (err.code === 'ENOENT') {
344
+ return new Response('Screenshot not found', { status: 404 });
345
+ }
346
+ throw error;
347
+ }
348
+ }
349
+ return new Response('Invalid screenshot path', { status: 400 });
350
+ }
351
+ // Serve static review UI
352
+ return serveStaticUI(url.pathname);
353
+ },
354
+ });
355
+ console.log(colors.info(`Review server: http://localhost:${port}`));
356
+ if (options.open !== false) {
357
+ const explorationParam = options.exploration ? `?id=${options.exploration}` : '';
358
+ await openBrowser(`http://localhost:${port}${explorationParam}`);
359
+ }
360
+ console.log(colors.dim('Press Ctrl+C to stop'));
361
+ // Keep process alive
362
+ await new Promise(() => { });
363
+ }
364
+ catch (error) {
365
+ const err = error;
366
+ console.error(colors.fail(err.message));
367
+ process.exitCode = 1;
368
+ }
369
+ });
370
+ }
371
+ //# sourceMappingURL=review.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review.js","sourceRoot":"","sources":["../../src/commands/review.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import { Command } from 'commander';
2
+ import type { RunOptions } from '../run/types.js';
3
+ export declare function runCommand(): Command;
4
+ export declare function run(options: RunOptions): Promise<void>;
5
+ //# sourceMappingURL=run.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/commands/run.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMpC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAElD,wBAAgB,UAAU,IAAI,OAAO,CA6BpC;AAED,wBAAsB,GAAG,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAsC5D"}
@@ -0,0 +1,66 @@
1
+ import { Command } from 'commander';
2
+ import { basename } from 'node:path';
3
+ import { createRunStore } from '@browserflow-ai/core';
4
+ import { resolveSpecs, executePlaywright } from '../run/executor.js';
5
+ import { collectResults, generateFailureBundles } from '../run/results.js';
6
+ import { printRunHeader, printRunSummary, printError } from '../run/output.js';
7
+ export function runCommand() {
8
+ const cmd = new Command('run');
9
+ cmd
10
+ .description('Run BrowserFlow tests via Playwright')
11
+ .argument('[specs...]', 'Spec files to run')
12
+ .option('-s, --spec <name>', 'Run specific spec by name')
13
+ .option('-t, --tag <tag>', 'Filter tests by tag')
14
+ .option('-p, --parallel <workers>', 'Number of parallel workers', parseInt)
15
+ .option('--headed', 'Run tests in headed browser mode')
16
+ .option('--trace <mode>', 'Trace mode: on, off, on-first-retry', 'off')
17
+ .action(async (specs, cmdOptions) => {
18
+ const options = {
19
+ spec: cmdOptions.spec ?? specs[0],
20
+ tag: cmdOptions.tag,
21
+ parallel: cmdOptions.parallel,
22
+ headed: cmdOptions.headed,
23
+ trace: cmdOptions.trace,
24
+ };
25
+ try {
26
+ await run(options);
27
+ }
28
+ catch (error) {
29
+ printError(error instanceof Error ? error.message : String(error));
30
+ process.exit(1);
31
+ }
32
+ });
33
+ return cmd;
34
+ }
35
+ export async function run(options) {
36
+ const runStore = createRunStore(process.cwd());
37
+ // 1. Determine which specs to run
38
+ const specs = await resolveSpecs(options);
39
+ // 2. Print header
40
+ printRunHeader(specs);
41
+ // 3. Create run directory for this execution
42
+ // Extract spec name from first spec file path
43
+ // e.g., 'specs/login.spec.yaml' -> 'login.spec' or 'login'
44
+ let specName = '_execution'; // fallback
45
+ if (specs.length > 0) {
46
+ const specFile = basename(specs[0]);
47
+ // Remove .yaml/.yml extension if present
48
+ specName = specFile.replace(/\.(yaml|yml)$/, '');
49
+ }
50
+ const runDir = await runStore.createRun(specName);
51
+ // 4. Execute Playwright tests
52
+ const executorResult = await executePlaywright(specs, options, runDir);
53
+ // 5. Collect results and generate summary
54
+ const summary = await collectResults(runDir, executorResult);
55
+ // 6. Print human-friendly output
56
+ printRunSummary(summary);
57
+ // 7. If failures, generate failure bundles
58
+ if (summary.failed > 0) {
59
+ await generateFailureBundles(runDir, summary.failures);
60
+ }
61
+ // 8. Exit with appropriate code
62
+ if (summary.failed > 0) {
63
+ process.exit(5); // Exit code 5 for test failures as per spec
64
+ }
65
+ }
66
+ //# sourceMappingURL=run.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.js","sourceRoot":"","sources":["../../src/commands/run.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { Command } from 'commander';
2
+ export declare function createProgram(): Command;
3
+ export declare function run(argv?: string[]): void;
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAYpC,wBAAgB,aAAa,IAAI,OAAO,CAkBvC;AAED,wBAAgB,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,CAGzC"}
package/dist/index.js ADDED
@@ -0,0 +1,35 @@
1
+ import { Command } from 'commander';
2
+ import { initCommand } from './commands/init.js';
3
+ import { doctorCommand } from './commands/doctor.js';
4
+ import { lintCommand } from './commands/lint.js';
5
+ import { runCommand } from './commands/run.js';
6
+ import { baselineCommand } from './commands/baseline.js';
7
+ import { repairCommand } from './commands/repair.js';
8
+ import { exploreCommand } from './commands/explore.js';
9
+ import { reviewCommand } from './commands/review.js';
10
+ const VERSION = '0.0.1';
11
+ export function createProgram() {
12
+ const program = new Command();
13
+ program
14
+ .name('bf')
15
+ .description('BrowserFlow - Human-in-the-Loop E2E Test Generation')
16
+ .version(VERSION);
17
+ program.addCommand(initCommand());
18
+ program.addCommand(doctorCommand());
19
+ program.addCommand(lintCommand());
20
+ program.addCommand(runCommand());
21
+ program.addCommand(baselineCommand());
22
+ program.addCommand(repairCommand());
23
+ program.addCommand(exploreCommand());
24
+ program.addCommand(reviewCommand());
25
+ return program;
26
+ }
27
+ export function run(argv) {
28
+ const program = createProgram();
29
+ program.parse(argv);
30
+ }
31
+ // Run if this is the entry point
32
+ if (import.meta.main) {
33
+ run();
34
+ }
35
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAErD,MAAM,OAAO,GAAG,OAAO,CAAC;AAExB,MAAM,UAAU,aAAa;IAC3B,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;IAE9B,OAAO;SACJ,IAAI,CAAC,IAAI,CAAC;SACV,WAAW,CAAC,qDAAqD,CAAC;SAClE,OAAO,CAAC,OAAO,CAAC,CAAC;IAEpB,OAAO,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC,CAAC;IAClC,OAAO,CAAC,UAAU,CAAC,aAAa,EAAE,CAAC,CAAC;IACpC,OAAO,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC,CAAC;IAClC,OAAO,CAAC,UAAU,CAAC,UAAU,EAAE,CAAC,CAAC;IACjC,OAAO,CAAC,UAAU,CAAC,eAAe,EAAE,CAAC,CAAC;IACtC,OAAO,CAAC,UAAU,CAAC,aAAa,EAAE,CAAC,CAAC;IACpC,OAAO,CAAC,UAAU,CAAC,cAAc,EAAE,CAAC,CAAC;IACrC,OAAO,CAAC,UAAU,CAAC,aAAa,EAAE,CAAC,CAAC;IAEpC,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,GAAG,CAAC,IAAe;IACjC,MAAM,OAAO,GAAG,aAAa,EAAE,CAAC;IAChC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;AACtB,CAAC;AAED,iCAAiC;AACjC,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;IACrB,GAAG,EAAE,CAAC;AACR,CAAC"}
@@ -0,0 +1,10 @@
1
+ import type { RunOptions } from './types.js';
2
+ export interface ExecutorResult {
3
+ exitCode: number;
4
+ stdout: string;
5
+ stderr: string;
6
+ jsonOutput?: unknown;
7
+ }
8
+ export declare function executePlaywright(specs: string[], options: RunOptions, runDir: string): Promise<ExecutorResult>;
9
+ export declare function resolveSpecs(options: RunOptions): Promise<string[]>;
10
+ //# sourceMappingURL=executor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../../src/run/executor.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,MAAM,EAAE,EACf,OAAO,EAAE,UAAU,EACnB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,cAAc,CAAC,CAyDzB;AA8CD,wBAAsB,YAAY,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CASzE"}
@@ -0,0 +1,95 @@
1
+ import { spawn } from 'node:child_process';
2
+ import * as path from 'node:path';
3
+ export async function executePlaywright(specs, options, runDir) {
4
+ const args = buildPlaywrightArgs(specs, options, runDir);
5
+ return new Promise((resolve) => {
6
+ let stdout = '';
7
+ let stderr = '';
8
+ const child = spawn('bunx', ['playwright', 'test', ...args], {
9
+ stdio: ['ignore', 'pipe', 'pipe'],
10
+ cwd: process.cwd(),
11
+ });
12
+ child.stdout.on('data', (data) => {
13
+ stdout += data.toString();
14
+ });
15
+ child.stderr.on('data', (data) => {
16
+ stderr += data.toString();
17
+ });
18
+ child.on('close', (code) => {
19
+ let jsonOutput;
20
+ try {
21
+ // Parse JSON output from JSON reporter
22
+ // The entire stdout should be valid JSON when using --reporter json
23
+ if (stdout.trim()) {
24
+ jsonOutput = JSON.parse(stdout.trim());
25
+ }
26
+ }
27
+ catch (error) {
28
+ // If JSON parsing fails, try to extract JSON object from mixed output
29
+ try {
30
+ const jsonMatch = stdout.match(/\{[\s\S]*\}/);
31
+ if (jsonMatch) {
32
+ jsonOutput = JSON.parse(jsonMatch[0]);
33
+ }
34
+ }
35
+ catch {
36
+ // Ignore parse errors - jsonOutput will remain undefined
37
+ }
38
+ }
39
+ resolve({
40
+ exitCode: code ?? 1,
41
+ stdout,
42
+ stderr,
43
+ jsonOutput,
44
+ });
45
+ });
46
+ child.on('error', (err) => {
47
+ resolve({
48
+ exitCode: 1,
49
+ stdout,
50
+ stderr: stderr + '\n' + err.message,
51
+ jsonOutput: undefined,
52
+ });
53
+ });
54
+ });
55
+ }
56
+ function buildPlaywrightArgs(specs, options, runDir) {
57
+ const args = [];
58
+ // Config file (if exists)
59
+ args.push('--config', 'e2e/playwright.config.ts');
60
+ // Reporter - use JSON for structured output
61
+ args.push('--reporter', 'json');
62
+ // Output directory for artifacts
63
+ args.push('--output', path.join(runDir, 'artifacts'));
64
+ // Parallel workers
65
+ if (options.parallel !== undefined) {
66
+ args.push('--workers', String(options.parallel));
67
+ }
68
+ // Headed mode
69
+ if (options.headed) {
70
+ args.push('--headed');
71
+ }
72
+ // Trace mode
73
+ if (options.trace) {
74
+ args.push('--trace', options.trace);
75
+ }
76
+ // Tag filter (using Playwright's grep)
77
+ if (options.tag) {
78
+ args.push('--grep', `@${options.tag}`);
79
+ }
80
+ // Spec files
81
+ for (const spec of specs) {
82
+ args.push(`e2e/tests/${spec}.spec.ts`);
83
+ }
84
+ return args;
85
+ }
86
+ export async function resolveSpecs(options) {
87
+ // If specific spec provided, use it
88
+ if (options.spec) {
89
+ return [options.spec];
90
+ }
91
+ // Otherwise, run all specs by not filtering
92
+ // Playwright will run all files matching the config pattern
93
+ return [];
94
+ }
95
+ //# sourceMappingURL=executor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../src/run/executor.ts"],"names":[],"mappings":"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"}