@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,230 @@
1
+ import { Command } from 'commander';
2
+ import { exec as execCallback } from 'node:child_process';
3
+ import { promisify } from 'node:util';
4
+ import { access, readFile } from 'node:fs/promises';
5
+ import { join } from 'node:path';
6
+ import { createServer } from 'node:net';
7
+ import { parse as parseYaml } from 'yaml';
8
+ import { logSuccess, logError, logWarning, logHeader, logNewline } from '../ui/prompts.js';
9
+ import { colors } from '../ui/colors.js';
10
+ const exec = promisify(execCallback);
11
+ async function fileExists(path) {
12
+ try {
13
+ await access(path);
14
+ return true;
15
+ }
16
+ catch {
17
+ return false;
18
+ }
19
+ }
20
+ async function isPortAvailable(port) {
21
+ return new Promise((resolve) => {
22
+ const server = createServer();
23
+ server.once('error', () => resolve(false));
24
+ server.once('listening', () => {
25
+ server.close();
26
+ resolve(true);
27
+ });
28
+ server.listen(port, '127.0.0.1');
29
+ });
30
+ }
31
+ export async function checkNodeVersion() {
32
+ const version = process.version;
33
+ const major = parseInt(version.slice(1));
34
+ if (major >= 18) {
35
+ return { status: 'pass', message: `Node.js ${version}` };
36
+ }
37
+ return {
38
+ status: 'fail',
39
+ message: `Node.js ${version} (need >=18)`,
40
+ fixHint: 'Install Node.js 18+ from https://nodejs.org',
41
+ };
42
+ }
43
+ export async function checkAgentBrowser() {
44
+ try {
45
+ const { stdout } = await exec('agent-browser --version');
46
+ const version = stdout.trim();
47
+ // Handle version with or without 'v' prefix
48
+ const displayVersion = version.startsWith('v') ? version : `v${version}`;
49
+ return { status: 'pass', message: displayVersion };
50
+ }
51
+ catch {
52
+ return {
53
+ status: 'fail',
54
+ message: 'Not installed',
55
+ fixHint: 'Run: bun add -g agent-browser',
56
+ };
57
+ }
58
+ }
59
+ export async function checkPlaywrightBrowsers() {
60
+ try {
61
+ // Get playwright version
62
+ const { stdout: versionOutput } = await exec('bunx playwright --version');
63
+ const version = versionOutput.trim();
64
+ // Check if chromium is installed using --list
65
+ try {
66
+ const { stdout: listOutput } = await exec('bunx playwright install --list');
67
+ // Check if chromium is listed in the browsers section
68
+ if (listOutput.includes('chromium-')) {
69
+ return { status: 'pass', message: `Installed (Playwright ${version})` };
70
+ }
71
+ return {
72
+ status: 'warn',
73
+ message: `Playwright ${version} (chromium not installed)`,
74
+ fixHint: 'Run: bunx playwright install chromium',
75
+ };
76
+ }
77
+ catch {
78
+ return {
79
+ status: 'warn',
80
+ message: `Playwright ${version} (browsers may need install)`,
81
+ fixHint: 'Run: bunx playwright install chromium',
82
+ };
83
+ }
84
+ }
85
+ catch {
86
+ return {
87
+ status: 'fail',
88
+ message: 'Not installed',
89
+ fixHint: 'Run: bunx playwright install chromium',
90
+ };
91
+ }
92
+ }
93
+ async function loadConfig() {
94
+ const configPath = join(process.cwd(), 'browserflow.yaml');
95
+ if (!(await fileExists(configPath))) {
96
+ return { config: null, error: 'No browserflow.yaml' };
97
+ }
98
+ try {
99
+ const content = await readFile(configPath, 'utf-8');
100
+ const config = parseYaml(content);
101
+ return { config };
102
+ }
103
+ catch (err) {
104
+ return { config: null, error: `Invalid YAML: ${err.message}` };
105
+ }
106
+ }
107
+ export async function checkConfiguration() {
108
+ const { config, error } = await loadConfig();
109
+ if (!config) {
110
+ return {
111
+ status: 'fail',
112
+ message: error ?? 'No browserflow.yaml',
113
+ fixHint: 'Run: bf init',
114
+ };
115
+ }
116
+ return { status: 'pass', message: 'Valid' };
117
+ }
118
+ export async function checkReviewPort() {
119
+ const { config } = await loadConfig();
120
+ const port = config?.review?.port ?? 8190;
121
+ if (await isPortAvailable(port)) {
122
+ return { status: 'pass', message: `Port ${port} available` };
123
+ }
124
+ return {
125
+ status: 'warn',
126
+ message: `Port ${port} in use`,
127
+ fixHint: 'Change review.port in browserflow.yaml',
128
+ };
129
+ }
130
+ function createDefaultChecks() {
131
+ return [
132
+ { name: 'Node.js version', check: checkNodeVersion },
133
+ { name: 'agent-browser', check: checkAgentBrowser },
134
+ { name: 'Playwright browsers', check: checkPlaywrightBrowsers },
135
+ { name: 'Configuration', check: checkConfiguration },
136
+ { name: 'Review port', check: checkReviewPort },
137
+ ];
138
+ }
139
+ export function createMockChecks(options = {}) {
140
+ if (options.allPass) {
141
+ return [
142
+ { name: 'Node.js version', check: async () => ({ status: 'pass', message: 'v20.0.0' }) },
143
+ { name: 'agent-browser', check: async () => ({ status: 'pass', message: 'v0.5.0' }) },
144
+ { name: 'Playwright browsers', check: async () => ({ status: 'pass', message: 'Installed' }) },
145
+ { name: 'Configuration', check: async () => ({ status: 'pass', message: 'Valid' }) },
146
+ { name: 'Review port', check: async () => ({ status: 'pass', message: 'Port 8190 available' }) },
147
+ ];
148
+ }
149
+ return createDefaultChecks();
150
+ }
151
+ export async function runDoctor(options, checks = createDefaultChecks()) {
152
+ const checkOutputs = [];
153
+ for (const check of checks) {
154
+ const result = await check.check();
155
+ checkOutputs.push({ name: check.name, result });
156
+ // Attempt fix if requested and available
157
+ if (options.fix && result.status === 'fail' && check.fix) {
158
+ try {
159
+ await check.fix();
160
+ // Re-run check after fix
161
+ const newResult = await check.check();
162
+ checkOutputs[checkOutputs.length - 1].result = newResult;
163
+ }
164
+ catch {
165
+ // Fix failed, keep original result
166
+ }
167
+ }
168
+ }
169
+ const summary = {
170
+ passed: checkOutputs.filter(c => c.result.status === 'pass').length,
171
+ warnings: checkOutputs.filter(c => c.result.status === 'warn').length,
172
+ failed: checkOutputs.filter(c => c.result.status === 'fail').length,
173
+ };
174
+ // Exit code: 0 for all pass, 0 for warnings only, 1 for any failures
175
+ const exitCode = summary.failed > 0 ? 1 : 0;
176
+ return { checks: checkOutputs, summary, exitCode };
177
+ }
178
+ function formatCheckOutput(check) {
179
+ const { name, result } = check;
180
+ const paddedName = name.padEnd(20);
181
+ switch (result.status) {
182
+ case 'pass':
183
+ logSuccess(`${paddedName} ${result.message}`);
184
+ break;
185
+ case 'warn':
186
+ logWarning(`${paddedName} ${result.message}`);
187
+ if (result.fixHint) {
188
+ console.log(` ${colors.dim('→')} ${result.fixHint}`);
189
+ }
190
+ break;
191
+ case 'fail':
192
+ logError(`${paddedName} ${result.message}`);
193
+ if (result.fixHint) {
194
+ console.log(` ${colors.dim('→')} ${result.fixHint}`);
195
+ }
196
+ break;
197
+ }
198
+ }
199
+ export function doctorCommand() {
200
+ const cmd = new Command('doctor');
201
+ cmd
202
+ .description('Check environment and dependencies')
203
+ .option('-v, --verbose', 'Show detailed output')
204
+ .option('--fix', 'Attempt to fix issues automatically')
205
+ .action(async (options) => {
206
+ logHeader('BrowserFlow Doctor');
207
+ logNewline();
208
+ const result = await runDoctor(options);
209
+ for (const check of result.checks) {
210
+ formatCheckOutput(check);
211
+ }
212
+ logNewline();
213
+ const { passed, warnings, failed } = result.summary;
214
+ const parts = [];
215
+ if (passed > 0)
216
+ parts.push(colors.pass(`${passed} passed`));
217
+ if (warnings > 0)
218
+ parts.push(colors.warning(`${warnings} warning${warnings > 1 ? 's' : ''}`));
219
+ if (failed > 0)
220
+ parts.push(colors.fail(`${failed} failed`));
221
+ console.log(parts.join(', '));
222
+ if (failed > 0 && !options.fix) {
223
+ logNewline();
224
+ console.log(colors.dim('Run bf doctor --fix to attempt automatic fixes.'));
225
+ }
226
+ process.exitCode = result.exitCode;
227
+ });
228
+ return cmd;
229
+ }
230
+ //# sourceMappingURL=doctor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * bf explore command - runs AI exploration for a spec
3
+ * @see bf-x9t
4
+ */
5
+ import { Command } from 'commander';
6
+ import type { BrowserFlowSpec } from '@browserflow-ai/core';
7
+ /**
8
+ * Load and validate a spec file
9
+ */
10
+ export declare function loadAndValidateSpec(specName: string, cwd?: string): Promise<BrowserFlowSpec>;
11
+ export declare function exploreCommand(): Command;
12
+ //# sourceMappingURL=explore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"explore.d.ts","sourceRoot":"","sources":["../../src/commands/explore.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKpC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAK5D;;GAEG;AACH,wBAAsB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,GAAE,MAAsB,GAAG,OAAO,CAAC,eAAe,CAAC,CAmCjH;AA4BD,wBAAgB,cAAc,IAAI,OAAO,CAkDxC"}
@@ -0,0 +1,114 @@
1
+ /**
2
+ * bf explore command - runs AI exploration for a spec
3
+ * @see bf-x9t
4
+ */
5
+ import { Command } from 'commander';
6
+ import { readFile, mkdir, writeFile } from 'node:fs/promises';
7
+ import { join } from 'node:path';
8
+ import { parse as parseYaml } from 'yaml';
9
+ import { specSchema } from '@browserflow-ai/core';
10
+ import { Explorer, ClaudeAdapter, ClaudeCliAdapter, createBrowserSession } from '@browserflow-ai/exploration';
11
+ import { colors } from '../ui/colors.js';
12
+ /**
13
+ * Load and validate a spec file
14
+ */
15
+ export async function loadAndValidateSpec(specName, cwd = process.cwd()) {
16
+ const specPath = join(cwd, 'specs', `${specName}.yaml`);
17
+ // Read file
18
+ let content;
19
+ try {
20
+ content = await readFile(specPath, 'utf-8');
21
+ }
22
+ catch (error) {
23
+ const err = error;
24
+ if (err.code === 'ENOENT') {
25
+ throw new Error(`Spec file not found: ${specPath}`);
26
+ }
27
+ throw error;
28
+ }
29
+ // Parse YAML
30
+ let parsed;
31
+ try {
32
+ parsed = parseYaml(content);
33
+ }
34
+ catch (error) {
35
+ const err = error;
36
+ throw new Error(`YAML syntax error: ${err.message}`);
37
+ }
38
+ // Validate against schema
39
+ const validation = specSchema.safeParse(parsed);
40
+ if (!validation.success) {
41
+ const issues = validation.error.issues.map((issue) => {
42
+ const path = issue.path.join('.');
43
+ return ` - ${path}: ${issue.message}`;
44
+ }).join('\n');
45
+ throw new Error(`Spec validation failed:\n${issues}`);
46
+ }
47
+ return validation.data;
48
+ }
49
+ /**
50
+ * Write exploration output to disk
51
+ */
52
+ async function writeExplorationOutput(result) {
53
+ const outputDir = join('.browserflow', 'explorations', result.explorationId);
54
+ await mkdir(outputDir, { recursive: true });
55
+ await writeFile(join(outputDir, 'exploration.json'), JSON.stringify(result, null, 2));
56
+ }
57
+ /**
58
+ * Create an AI adapter based on the adapter name
59
+ */
60
+ function createAdapter(adapterName) {
61
+ switch (adapterName) {
62
+ case 'claude':
63
+ return new ClaudeAdapter();
64
+ case 'claude-cli':
65
+ return new ClaudeCliAdapter();
66
+ default:
67
+ throw new Error(`Unknown adapter: ${adapterName}. Available: claude, claude-cli`);
68
+ }
69
+ }
70
+ export function exploreCommand() {
71
+ const cmd = new Command('explore');
72
+ cmd
73
+ .description('Run AI exploration for a spec')
74
+ .requiredOption('--spec <name>', 'Spec name to explore')
75
+ .option('--url <url>', 'Base URL (overrides config)')
76
+ .option('--headed', 'Run browser in headed mode')
77
+ .option('--adapter <name>', 'AI adapter: claude (SDK), claude-cli (CLI)', 'claude')
78
+ .action(async (options) => {
79
+ try {
80
+ // 1. Load and validate spec
81
+ const spec = await loadAndValidateSpec(options.spec);
82
+ // 2. Determine base URL
83
+ const baseUrl = options.url || 'http://localhost:3000';
84
+ // 3. Create browser session and AI adapter
85
+ const browser = createBrowserSession();
86
+ const adapter = createAdapter(options.adapter);
87
+ // 4. Create explorer
88
+ const explorer = new Explorer({
89
+ adapter,
90
+ browser,
91
+ headless: !options.headed,
92
+ outputDir: '.browserflow/explorations',
93
+ });
94
+ // 5. Run exploration
95
+ console.log(colors.dim(`Running exploration for ${spec.name}...`));
96
+ const result = await explorer.runExploration(spec, baseUrl, {
97
+ specPath: `specs/${options.spec}.yaml`,
98
+ headless: !options.headed,
99
+ });
100
+ // 6. Write exploration output
101
+ await writeExplorationOutput(result);
102
+ // 7. Print summary
103
+ console.log(colors.success(`Exploration complete: ${result.explorationId}`));
104
+ console.log(`Run \`bf review --exploration ${result.explorationId}\` to review`);
105
+ }
106
+ catch (error) {
107
+ const err = error;
108
+ console.error(colors.fail(err.message));
109
+ process.exitCode = 1;
110
+ }
111
+ });
112
+ return cmd;
113
+ }
114
+ //# sourceMappingURL=explore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"explore.js","sourceRoot":"","sources":["../../src/commands/explore.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import { Command } from 'commander';
2
+ export declare const DEFAULT_CONFIG = "project:\n name: my-project\n base_url: http://localhost:3000\n\nruntime:\n browser: chromium\n headless: true\n viewport:\n width: 1280\n height: 720\n timeout: 30s\n\nlocators:\n prefer_testid: true\n testid_attributes:\n - data-testid\n - data-test\n\nexploration:\n adapter: claude\n max_retries: 3\n\nreview:\n port: 8190\n auto_open: true\n\noutput:\n tests_dir: e2e/tests\n baselines_dir: baselines\n";
3
+ export declare const EXAMPLE_SPEC = "version: 2\nname: example\ndescription: Example spec - customize for your app\n\nsteps:\n - id: visit_home\n action: navigate\n url: /\n\n - id: homepage_screenshot\n action: screenshot\n name: homepage\n\ntags:\n - example\n - smoke\n";
4
+ export interface InitOptions {
5
+ force?: boolean;
6
+ example?: boolean;
7
+ }
8
+ export interface InitResult {
9
+ created: string[];
10
+ updated: string[];
11
+ skipped: string[];
12
+ }
13
+ export declare function runInit(options: InitOptions): Promise<InitResult>;
14
+ export declare function initCommand(): Command;
15
+ //# sourceMappingURL=init.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMpC,eAAO,MAAM,cAAc,sbA6B1B,CAAC;AAEF,eAAO,MAAM,YAAY,gQAgBxB,CAAC;AAIF,MAAM,WAAW,WAAW;IAC1B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AA2CD,wBAAsB,OAAO,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CAyCvE;AAED,wBAAgB,WAAW,IAAI,OAAO,CAuCrC"}
@@ -0,0 +1,160 @@
1
+ import { Command } from 'commander';
2
+ import { mkdir, writeFile, readFile, access } from 'node:fs/promises';
3
+ import { join } from 'node:path';
4
+ import { logSuccess, logWarning, logHeader, logNewline, logInfo } from '../ui/prompts.js';
5
+ import { colors } from '../ui/colors.js';
6
+ export const DEFAULT_CONFIG = `project:
7
+ name: my-project
8
+ base_url: http://localhost:3000
9
+
10
+ runtime:
11
+ browser: chromium
12
+ headless: true
13
+ viewport:
14
+ width: 1280
15
+ height: 720
16
+ timeout: 30s
17
+
18
+ locators:
19
+ prefer_testid: true
20
+ testid_attributes:
21
+ - data-testid
22
+ - data-test
23
+
24
+ exploration:
25
+ adapter: claude
26
+ max_retries: 3
27
+
28
+ review:
29
+ port: 8190
30
+ auto_open: true
31
+
32
+ output:
33
+ tests_dir: e2e/tests
34
+ baselines_dir: baselines
35
+ `;
36
+ export const EXAMPLE_SPEC = `version: 2
37
+ name: example
38
+ description: Example spec - customize for your app
39
+
40
+ steps:
41
+ - id: visit_home
42
+ action: navigate
43
+ url: /
44
+
45
+ - id: homepage_screenshot
46
+ action: screenshot
47
+ name: homepage
48
+
49
+ tags:
50
+ - example
51
+ - smoke
52
+ `;
53
+ const GITIGNORE_ENTRIES = ['.browserflow/', 'node_modules/'];
54
+ async function fileExists(path) {
55
+ try {
56
+ await access(path);
57
+ return true;
58
+ }
59
+ catch {
60
+ return false;
61
+ }
62
+ }
63
+ async function appendToGitignore(entries) {
64
+ const gitignorePath = join(process.cwd(), '.gitignore');
65
+ let existingContent = '';
66
+ const added = [];
67
+ try {
68
+ existingContent = await readFile(gitignorePath, 'utf-8');
69
+ }
70
+ catch {
71
+ // File doesn't exist yet
72
+ }
73
+ const existingLines = new Set(existingContent.split('\n').map(l => l.trim()));
74
+ const toAdd = [];
75
+ for (const entry of entries) {
76
+ if (!existingLines.has(entry)) {
77
+ toAdd.push(entry);
78
+ added.push(entry);
79
+ }
80
+ }
81
+ if (toAdd.length > 0) {
82
+ const newContent = existingContent
83
+ ? existingContent.trimEnd() + '\n' + toAdd.join('\n') + '\n'
84
+ : toAdd.join('\n') + '\n';
85
+ await writeFile(gitignorePath, newContent);
86
+ return { updated: true, added };
87
+ }
88
+ return { updated: false, added: [] };
89
+ }
90
+ export async function runInit(options) {
91
+ const result = {
92
+ created: [],
93
+ updated: [],
94
+ skipped: [],
95
+ };
96
+ // 1. Create browserflow.yaml
97
+ const configPath = join(process.cwd(), 'browserflow.yaml');
98
+ const configExists = await fileExists(configPath);
99
+ if (!configExists || options.force) {
100
+ await writeFile(configPath, DEFAULT_CONFIG);
101
+ result.created.push('browserflow.yaml');
102
+ }
103
+ else {
104
+ result.skipped.push('browserflow.yaml');
105
+ }
106
+ // 2. Create specs/ directory
107
+ const specsDir = join(process.cwd(), 'specs');
108
+ const specsDirExists = await fileExists(specsDir);
109
+ if (!specsDirExists) {
110
+ await mkdir(specsDir, { recursive: true });
111
+ result.created.push('specs/');
112
+ }
113
+ // 3. Update .gitignore
114
+ const gitignoreResult = await appendToGitignore(GITIGNORE_ENTRIES);
115
+ if (gitignoreResult.updated) {
116
+ result.updated.push('.gitignore');
117
+ }
118
+ // 4. Create example spec (if --example)
119
+ if (options.example) {
120
+ const examplePath = join(specsDir, 'example.yaml');
121
+ await writeFile(examplePath, EXAMPLE_SPEC);
122
+ result.created.push('specs/example.yaml');
123
+ }
124
+ return result;
125
+ }
126
+ export function initCommand() {
127
+ const cmd = new Command('init');
128
+ cmd
129
+ .description('Initialize BrowserFlow in the current project')
130
+ .option('-f, --force', 'Overwrite existing configuration')
131
+ .option('--example', 'Create an example spec file')
132
+ .action(async (options) => {
133
+ logHeader('BrowserFlow Initialized!');
134
+ logNewline();
135
+ const result = await runInit(options);
136
+ if (result.created.length > 0 || result.updated.length > 0) {
137
+ console.log(colors.bold('Created:'));
138
+ for (const file of result.created) {
139
+ logSuccess(file);
140
+ }
141
+ for (const file of result.updated) {
142
+ logSuccess(`${file} (updated)`);
143
+ }
144
+ logNewline();
145
+ }
146
+ if (result.skipped.length > 0) {
147
+ console.log(colors.bold('Skipped (already exists):'));
148
+ for (const file of result.skipped) {
149
+ logWarning(`${file} - use --force to overwrite`);
150
+ }
151
+ logNewline();
152
+ }
153
+ console.log(colors.bold('Next steps:'));
154
+ logInfo('Edit browserflow.yaml with your project settings');
155
+ logInfo('Write specs in specs/ directory');
156
+ logInfo(`Run: ${colors.code('bf explore --spec <name>')}`);
157
+ });
158
+ return cmd;
159
+ }
160
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * bf lint command - validates spec files against v2 schema
3
+ * @see bf-eq4
4
+ */
5
+ import { Command } from 'commander';
6
+ export interface LintError {
7
+ path: string;
8
+ message: string;
9
+ line: number;
10
+ value?: unknown;
11
+ }
12
+ export interface LintResult {
13
+ file: string;
14
+ errors: LintError[];
15
+ }
16
+ export interface LintOptions {
17
+ fix?: boolean;
18
+ cwd?: string;
19
+ }
20
+ /**
21
+ * Get line number for a path in YAML content
22
+ */
23
+ export declare function getLineNumber(content: string, path: (string | number)[]): number;
24
+ /**
25
+ * Format lint error with actionable message
26
+ */
27
+ export declare function formatLintError(error: LintError): LintError;
28
+ /**
29
+ * Lint a single spec file content
30
+ */
31
+ export declare function lintSpec(content: string, filename: string): LintResult;
32
+ /**
33
+ * Lint multiple spec files
34
+ */
35
+ export declare function lintFiles(files: string[], options?: LintOptions): Promise<LintResult[]>;
36
+ export declare function lintCommand(): Command;
37
+ //# sourceMappingURL=lint.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lint.d.ts","sourceRoot":"","sources":["../../src/commands/lint.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAQpC,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,SAAS,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,WAAW;IAC1B,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,GAAG,MAAM,CA4ChF;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,SAAS,GAAG,SAAS,CA2B3D;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,UAAU,CAmDtE;AAED;;GAEG;AACH,wBAAsB,SAAS,CAC7B,KAAK,EAAE,MAAM,EAAE,EACf,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC,UAAU,EAAE,CAAC,CA6CvB;AAqCD,wBAAgB,WAAW,IAAI,OAAO,CAkCrC"}