@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
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* bf lint command - validates spec files against v2 schema
|
|
3
|
+
* @see bf-eq4
|
|
4
|
+
*/
|
|
5
|
+
import { Command } from 'commander';
|
|
6
|
+
import { readFile, readdir, access } from 'node:fs/promises';
|
|
7
|
+
import { join, relative, resolve } from 'node:path';
|
|
8
|
+
import { parse as parseYaml, LineCounter, parseDocument } from 'yaml';
|
|
9
|
+
import { specSchema } from '@browserflow-ai/core';
|
|
10
|
+
import { colors, symbols } from '../ui/colors.js';
|
|
11
|
+
import { logHeader, logNewline } from '../ui/prompts.js';
|
|
12
|
+
/**
|
|
13
|
+
* Get line number for a path in YAML content
|
|
14
|
+
*/
|
|
15
|
+
export function getLineNumber(content, path) {
|
|
16
|
+
try {
|
|
17
|
+
const lineCounter = new LineCounter();
|
|
18
|
+
const doc = parseDocument(content, { lineCounter });
|
|
19
|
+
if (!doc.contents) {
|
|
20
|
+
return 1;
|
|
21
|
+
}
|
|
22
|
+
// Cast to any to use getIn method - the yaml library types are complex
|
|
23
|
+
const contents = doc.contents;
|
|
24
|
+
if (!('getIn' in contents)) {
|
|
25
|
+
return 1;
|
|
26
|
+
}
|
|
27
|
+
// Use getIn with keepScalar=true to get the actual node
|
|
28
|
+
const node = contents.getIn(path, true);
|
|
29
|
+
if (node && typeof node === 'object' && 'range' in node) {
|
|
30
|
+
const range = node.range;
|
|
31
|
+
if (range && range[0] !== undefined) {
|
|
32
|
+
const pos = lineCounter.linePos(range[0]);
|
|
33
|
+
return pos.line;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
// If we can't find the exact node, try to find the parent
|
|
37
|
+
// This helps when the property doesn't exist (e.g., missing 'id')
|
|
38
|
+
if (path.length > 0) {
|
|
39
|
+
const parentPath = path.slice(0, -1);
|
|
40
|
+
const parentNode = contents.getIn(parentPath, true);
|
|
41
|
+
if (parentNode && typeof parentNode === 'object' && 'range' in parentNode) {
|
|
42
|
+
const range = parentNode.range;
|
|
43
|
+
if (range && range[0] !== undefined) {
|
|
44
|
+
const pos = lineCounter.linePos(range[0]);
|
|
45
|
+
return pos.line;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return 1;
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
return 1;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Format lint error with actionable message
|
|
57
|
+
*/
|
|
58
|
+
export function formatLintError(error) {
|
|
59
|
+
const { path, message, value } = error;
|
|
60
|
+
let actionableMessage = message;
|
|
61
|
+
// Make messages actionable based on error type
|
|
62
|
+
if (path.includes('id') && (message.toLowerCase().includes('required') || message.toLowerCase().includes('invalid'))) {
|
|
63
|
+
actionableMessage = "Step id is required - add 'id: unique_step_id' to this step";
|
|
64
|
+
}
|
|
65
|
+
else if (path.includes('timeout') || path.includes('duration')) {
|
|
66
|
+
if (value !== undefined) {
|
|
67
|
+
actionableMessage = `Invalid duration "${value}" - use format like "3s", "2m", or "500ms"`;
|
|
68
|
+
}
|
|
69
|
+
else if (message.toLowerCase().includes('duration')) {
|
|
70
|
+
actionableMessage = message;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
else if (message.toLowerCase().includes('unique')) {
|
|
74
|
+
actionableMessage = 'Step IDs must be unique within spec - rename duplicate step IDs';
|
|
75
|
+
}
|
|
76
|
+
else if (message.toLowerCase().includes('kebab-case')) {
|
|
77
|
+
if (value !== undefined) {
|
|
78
|
+
actionableMessage = `Name "${value}" must be kebab-case (lowercase letters, numbers, and hyphens only)`;
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
actionableMessage = 'Name must be kebab-case (lowercase letters, numbers, and hyphens only)';
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return {
|
|
85
|
+
...error,
|
|
86
|
+
message: actionableMessage,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Lint a single spec file content
|
|
91
|
+
*/
|
|
92
|
+
export function lintSpec(content, filename) {
|
|
93
|
+
const errors = [];
|
|
94
|
+
// Try to parse YAML
|
|
95
|
+
let parsed;
|
|
96
|
+
try {
|
|
97
|
+
parsed = parseYaml(content);
|
|
98
|
+
}
|
|
99
|
+
catch (e) {
|
|
100
|
+
const error = e;
|
|
101
|
+
errors.push({
|
|
102
|
+
path: '',
|
|
103
|
+
message: `YAML syntax error: ${error.message}`,
|
|
104
|
+
line: 1,
|
|
105
|
+
});
|
|
106
|
+
return { file: filename, errors };
|
|
107
|
+
}
|
|
108
|
+
// Validate against schema
|
|
109
|
+
const validation = specSchema.safeParse(parsed);
|
|
110
|
+
if (!validation.success) {
|
|
111
|
+
for (const issue of validation.error.issues) {
|
|
112
|
+
const path = issue.path.join('.');
|
|
113
|
+
const line = getLineNumber(content, issue.path);
|
|
114
|
+
// Get the value at this path for context
|
|
115
|
+
let value;
|
|
116
|
+
try {
|
|
117
|
+
let current = parsed;
|
|
118
|
+
for (const segment of issue.path) {
|
|
119
|
+
if (current && typeof current === 'object') {
|
|
120
|
+
current = current[segment];
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
value = current;
|
|
124
|
+
}
|
|
125
|
+
catch {
|
|
126
|
+
// Ignore errors getting value
|
|
127
|
+
}
|
|
128
|
+
const error = {
|
|
129
|
+
path,
|
|
130
|
+
message: issue.message,
|
|
131
|
+
line,
|
|
132
|
+
value: typeof value === 'string' || typeof value === 'number' ? value : undefined,
|
|
133
|
+
};
|
|
134
|
+
errors.push(formatLintError(error));
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return { file: filename, errors };
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Lint multiple spec files
|
|
141
|
+
*/
|
|
142
|
+
export async function lintFiles(files, options = {}) {
|
|
143
|
+
const cwd = options.cwd || process.cwd();
|
|
144
|
+
const results = [];
|
|
145
|
+
// If no files specified, find all yaml files in specs/
|
|
146
|
+
let targetFiles = files;
|
|
147
|
+
if (targetFiles.length === 0) {
|
|
148
|
+
try {
|
|
149
|
+
const specsDir = join(cwd, 'specs');
|
|
150
|
+
await access(specsDir);
|
|
151
|
+
const entries = await readdir(specsDir);
|
|
152
|
+
targetFiles = entries
|
|
153
|
+
.filter((f) => f.endsWith('.yaml') || f.endsWith('.yml'))
|
|
154
|
+
.map((f) => join(specsDir, f));
|
|
155
|
+
}
|
|
156
|
+
catch {
|
|
157
|
+
// specs/ doesn't exist
|
|
158
|
+
return [];
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
// Lint each file
|
|
162
|
+
for (const file of targetFiles) {
|
|
163
|
+
const filePath = resolve(cwd, file);
|
|
164
|
+
const displayPath = relative(cwd, filePath);
|
|
165
|
+
try {
|
|
166
|
+
const content = await readFile(filePath, 'utf-8');
|
|
167
|
+
const result = lintSpec(content, displayPath);
|
|
168
|
+
results.push(result);
|
|
169
|
+
}
|
|
170
|
+
catch (e) {
|
|
171
|
+
const error = e;
|
|
172
|
+
results.push({
|
|
173
|
+
file: displayPath,
|
|
174
|
+
errors: [
|
|
175
|
+
{
|
|
176
|
+
path: '',
|
|
177
|
+
message: error.code === 'ENOENT' ? 'File not found' : error.message,
|
|
178
|
+
line: 1,
|
|
179
|
+
},
|
|
180
|
+
],
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return results;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Print lint results to console
|
|
188
|
+
*/
|
|
189
|
+
function printResults(results) {
|
|
190
|
+
let totalPassed = 0;
|
|
191
|
+
let totalFailed = 0;
|
|
192
|
+
let totalErrors = 0;
|
|
193
|
+
for (const result of results) {
|
|
194
|
+
if (result.errors.length === 0) {
|
|
195
|
+
console.log(`${symbols.pass} ${result.file}`);
|
|
196
|
+
totalPassed++;
|
|
197
|
+
}
|
|
198
|
+
else {
|
|
199
|
+
console.log(`${symbols.fail} ${result.file}`);
|
|
200
|
+
totalFailed++;
|
|
201
|
+
totalErrors += result.errors.length;
|
|
202
|
+
for (const error of result.errors) {
|
|
203
|
+
console.log(` ${colors.dim(`Line ${error.line}:`)} ${error.message}`);
|
|
204
|
+
if (error.path) {
|
|
205
|
+
console.log(` ${colors.dim('at')} ${colors.code(error.path)}`);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
logNewline();
|
|
211
|
+
const parts = [];
|
|
212
|
+
if (totalPassed > 0)
|
|
213
|
+
parts.push(colors.pass(`${totalPassed} passed`));
|
|
214
|
+
if (totalFailed > 0)
|
|
215
|
+
parts.push(colors.fail(`${totalFailed} failed`));
|
|
216
|
+
if (totalErrors > 0)
|
|
217
|
+
parts.push(`(${totalErrors} error${totalErrors > 1 ? 's' : ''})`);
|
|
218
|
+
console.log(parts.join(', '));
|
|
219
|
+
}
|
|
220
|
+
export function lintCommand() {
|
|
221
|
+
const cmd = new Command('lint');
|
|
222
|
+
cmd
|
|
223
|
+
.description('Validate BrowserFlow spec files')
|
|
224
|
+
.argument('[specs...]', 'Spec files or directories to lint')
|
|
225
|
+
.option('--fix', 'Attempt to fix issues automatically')
|
|
226
|
+
.action(async (specs, options) => {
|
|
227
|
+
logHeader('Linting specs');
|
|
228
|
+
logNewline();
|
|
229
|
+
const targetDir = specs.length > 0 ? undefined : 'specs/*.yaml';
|
|
230
|
+
if (specs.length === 0) {
|
|
231
|
+
console.log(colors.dim(`Linting ${targetDir}`));
|
|
232
|
+
logNewline();
|
|
233
|
+
}
|
|
234
|
+
const results = await lintFiles(specs, options);
|
|
235
|
+
if (results.length === 0) {
|
|
236
|
+
console.log(colors.dim('No spec files found.'));
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
printResults(results);
|
|
240
|
+
// Exit code 3 for validation failure (per spec)
|
|
241
|
+
const hasErrors = results.some((r) => r.errors.length > 0);
|
|
242
|
+
if (hasErrors) {
|
|
243
|
+
process.exitCode = 3;
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
return cmd;
|
|
247
|
+
}
|
|
248
|
+
//# sourceMappingURL=lint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lint.js","sourceRoot":"","sources":["../../src/commands/lint.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* bf repair command - fix broken tests using failure bundles
|
|
3
|
+
* @see bf-mtk
|
|
4
|
+
*/
|
|
5
|
+
import { Command } from 'commander';
|
|
6
|
+
export type ErrorType = 'locator_not_found' | 'timeout' | 'assertion_failed' | 'screenshot_diff' | 'unknown';
|
|
7
|
+
export interface FailureBundle {
|
|
8
|
+
run_id: string;
|
|
9
|
+
spec_name: string;
|
|
10
|
+
failed_at: string;
|
|
11
|
+
failure: {
|
|
12
|
+
step_id: string;
|
|
13
|
+
action: string;
|
|
14
|
+
error_message: string;
|
|
15
|
+
error_type: ErrorType;
|
|
16
|
+
};
|
|
17
|
+
context: {
|
|
18
|
+
url: string;
|
|
19
|
+
viewport: {
|
|
20
|
+
width: number;
|
|
21
|
+
height: number;
|
|
22
|
+
};
|
|
23
|
+
browser: string;
|
|
24
|
+
};
|
|
25
|
+
artifacts: {
|
|
26
|
+
trace?: string;
|
|
27
|
+
video?: string;
|
|
28
|
+
screenshot?: string;
|
|
29
|
+
diff?: {
|
|
30
|
+
baseline: string;
|
|
31
|
+
actual: string;
|
|
32
|
+
diff: string;
|
|
33
|
+
};
|
|
34
|
+
console_log?: string;
|
|
35
|
+
network_log?: string;
|
|
36
|
+
};
|
|
37
|
+
suggestions?: RepairSuggestion[];
|
|
38
|
+
}
|
|
39
|
+
export interface RepairSuggestion {
|
|
40
|
+
type: 'use_fallback' | 'increase_timeout' | 'update_baseline' | 'add_mask' | 'fix_assertion' | 'investigate';
|
|
41
|
+
description: string;
|
|
42
|
+
confidence: number;
|
|
43
|
+
patch?: Record<string, unknown>;
|
|
44
|
+
}
|
|
45
|
+
export interface RepairPlan {
|
|
46
|
+
suggestions: RepairSuggestion[];
|
|
47
|
+
primarySuggestion: RepairSuggestion;
|
|
48
|
+
autoApplicable: boolean;
|
|
49
|
+
requiresConfirmation: boolean;
|
|
50
|
+
}
|
|
51
|
+
export interface RepairOptions {
|
|
52
|
+
spec?: string;
|
|
53
|
+
fromRun?: string;
|
|
54
|
+
ai?: boolean;
|
|
55
|
+
apply?: boolean;
|
|
56
|
+
headed?: boolean;
|
|
57
|
+
cwd?: string;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Load failure bundle from a run directory or failure.json path
|
|
61
|
+
*/
|
|
62
|
+
export declare function loadFailureBundle(pathOrRunDir: string): Promise<FailureBundle>;
|
|
63
|
+
/**
|
|
64
|
+
* Analyze a failure and generate deterministic repair suggestions
|
|
65
|
+
*/
|
|
66
|
+
export declare function analyzeFailure(bundle: FailureBundle): RepairSuggestion[];
|
|
67
|
+
/**
|
|
68
|
+
* Generate a repair plan from suggestions
|
|
69
|
+
*/
|
|
70
|
+
export declare function generateRepairPlan(suggestions: RepairSuggestion[]): RepairPlan;
|
|
71
|
+
export declare function repairCommand(): Command;
|
|
72
|
+
//# sourceMappingURL=repair.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repair.d.ts","sourceRoot":"","sources":["../../src/commands/repair.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AASpC,MAAM,MAAM,SAAS,GAAG,mBAAmB,GAAG,SAAS,GAAG,kBAAkB,GAAG,iBAAiB,GAAG,SAAS,CAAC;AAE7G,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAElB,OAAO,EAAE;QACP,OAAO,EAAE,MAAM,CAAC;QAChB,MAAM,EAAE,MAAM,CAAC;QACf,aAAa,EAAE,MAAM,CAAC;QACtB,UAAU,EAAE,SAAS,CAAC;KACvB,CAAC;IAEF,OAAO,EAAE;QACP,GAAG,EAAE,MAAM,CAAC;QACZ,QAAQ,EAAE;YAAE,KAAK,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,MAAM,CAAA;SAAE,CAAC;QAC5C,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;IAEF,SAAS,EAAE;QACT,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,IAAI,CAAC,EAAE;YACL,QAAQ,EAAE,MAAM,CAAC;YACjB,MAAM,EAAE,MAAM,CAAC;YACf,IAAI,EAAE,MAAM,CAAC;SACd,CAAC;QACF,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC;IAEF,WAAW,CAAC,EAAE,gBAAgB,EAAE,CAAC;CAClC;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,cAAc,GAAG,kBAAkB,GAAG,iBAAiB,GAAG,UAAU,GAAG,eAAe,GAAG,aAAa,CAAC;IAC7G,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AAED,MAAM,WAAW,UAAU;IACzB,WAAW,EAAE,gBAAgB,EAAE,CAAC;IAChC,iBAAiB,EAAE,gBAAgB,CAAC;IACpC,cAAc,EAAE,OAAO,CAAC;IACxB,oBAAoB,EAAE,OAAO,CAAC;CAC/B;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,EAAE,CAAC,EAAE,OAAO,CAAC;IACb,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAqBpF;AAsCD;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,aAAa,GAAG,gBAAgB,EAAE,CAyExE;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,gBAAgB,EAAE,GAAG,UAAU,CAc9E;AA6CD,wBAAgB,aAAa,IAAI,OAAO,CA4FvC"}
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* bf repair command - fix broken tests using failure bundles
|
|
3
|
+
* @see bf-mtk
|
|
4
|
+
*/
|
|
5
|
+
import { Command } from 'commander';
|
|
6
|
+
import { readFile, access, readdir } from 'node:fs/promises';
|
|
7
|
+
import { join, basename } from 'node:path';
|
|
8
|
+
import { colors, symbols } from '../ui/colors.js';
|
|
9
|
+
import { logHeader, logNewline, logSuccess, logWarning, logError } from '../ui/prompts.js';
|
|
10
|
+
const BROWSERFLOW_DIR = '.browserflow';
|
|
11
|
+
const RUNS_DIR = 'runs';
|
|
12
|
+
/**
|
|
13
|
+
* Load failure bundle from a run directory or failure.json path
|
|
14
|
+
*/
|
|
15
|
+
export async function loadFailureBundle(pathOrRunDir) {
|
|
16
|
+
let failurePath;
|
|
17
|
+
// Check if path is a failure.json file or a directory
|
|
18
|
+
if (pathOrRunDir.endsWith('failure.json')) {
|
|
19
|
+
failurePath = pathOrRunDir;
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
failurePath = join(pathOrRunDir, 'failure.json');
|
|
23
|
+
}
|
|
24
|
+
try {
|
|
25
|
+
await access(failurePath);
|
|
26
|
+
const content = await readFile(failurePath, 'utf-8');
|
|
27
|
+
return JSON.parse(content);
|
|
28
|
+
}
|
|
29
|
+
catch (e) {
|
|
30
|
+
const err = e;
|
|
31
|
+
if (err.code === 'ENOENT') {
|
|
32
|
+
throw new Error(`Failure bundle not found: ${failurePath}`);
|
|
33
|
+
}
|
|
34
|
+
throw e;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Find the latest failure for a spec
|
|
39
|
+
*/
|
|
40
|
+
async function findLatestFailure(specName, cwd = process.cwd()) {
|
|
41
|
+
const runsDir = join(cwd, BROWSERFLOW_DIR, RUNS_DIR, '_execution');
|
|
42
|
+
try {
|
|
43
|
+
await access(runsDir);
|
|
44
|
+
const entries = await readdir(runsDir);
|
|
45
|
+
const runDirs = entries
|
|
46
|
+
.filter((e) => e.startsWith('run-'))
|
|
47
|
+
.sort()
|
|
48
|
+
.reverse();
|
|
49
|
+
// Check each run for a failure.json
|
|
50
|
+
for (const runDir of runDirs) {
|
|
51
|
+
const failurePath = join(runsDir, runDir, 'failure.json');
|
|
52
|
+
try {
|
|
53
|
+
await access(failurePath);
|
|
54
|
+
const content = await readFile(failurePath, 'utf-8');
|
|
55
|
+
const bundle = JSON.parse(content);
|
|
56
|
+
if (!specName || bundle.spec_name === specName) {
|
|
57
|
+
return join(runsDir, runDir);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
// No failure.json in this run
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
// Runs directory doesn't exist
|
|
68
|
+
}
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Analyze a failure and generate deterministic repair suggestions
|
|
73
|
+
*/
|
|
74
|
+
export function analyzeFailure(bundle) {
|
|
75
|
+
const suggestions = [];
|
|
76
|
+
const { failure } = bundle;
|
|
77
|
+
switch (failure.error_type) {
|
|
78
|
+
case 'locator_not_found':
|
|
79
|
+
suggestions.push({
|
|
80
|
+
type: 'use_fallback',
|
|
81
|
+
description: 'Try fallback locator strategy',
|
|
82
|
+
confidence: 0.7,
|
|
83
|
+
patch: { use_fallback: true },
|
|
84
|
+
});
|
|
85
|
+
suggestions.push({
|
|
86
|
+
type: 'investigate',
|
|
87
|
+
description: 'Check if page structure has changed',
|
|
88
|
+
confidence: 0.5,
|
|
89
|
+
});
|
|
90
|
+
break;
|
|
91
|
+
case 'timeout':
|
|
92
|
+
suggestions.push({
|
|
93
|
+
type: 'increase_timeout',
|
|
94
|
+
description: 'Double the timeout duration',
|
|
95
|
+
confidence: 0.8,
|
|
96
|
+
patch: { timeout_multiplier: 2 },
|
|
97
|
+
});
|
|
98
|
+
suggestions.push({
|
|
99
|
+
type: 'investigate',
|
|
100
|
+
description: 'Check for slow network or page load issues',
|
|
101
|
+
confidence: 0.4,
|
|
102
|
+
});
|
|
103
|
+
break;
|
|
104
|
+
case 'assertion_failed':
|
|
105
|
+
suggestions.push({
|
|
106
|
+
type: 'fix_assertion',
|
|
107
|
+
description: 'Review and update the expected value',
|
|
108
|
+
confidence: 0.5,
|
|
109
|
+
});
|
|
110
|
+
suggestions.push({
|
|
111
|
+
type: 'investigate',
|
|
112
|
+
description: 'Verify the application behavior is correct',
|
|
113
|
+
confidence: 0.6,
|
|
114
|
+
});
|
|
115
|
+
break;
|
|
116
|
+
case 'screenshot_diff':
|
|
117
|
+
suggestions.push({
|
|
118
|
+
type: 'update_baseline',
|
|
119
|
+
description: 'Accept the new screenshot as baseline',
|
|
120
|
+
confidence: 0.6,
|
|
121
|
+
});
|
|
122
|
+
suggestions.push({
|
|
123
|
+
type: 'add_mask',
|
|
124
|
+
description: 'Add mask for dynamic content area',
|
|
125
|
+
confidence: 0.7,
|
|
126
|
+
});
|
|
127
|
+
suggestions.push({
|
|
128
|
+
type: 'investigate',
|
|
129
|
+
description: 'Verify visual change is intentional',
|
|
130
|
+
confidence: 0.5,
|
|
131
|
+
});
|
|
132
|
+
break;
|
|
133
|
+
default:
|
|
134
|
+
suggestions.push({
|
|
135
|
+
type: 'investigate',
|
|
136
|
+
description: 'Review error details and stack trace',
|
|
137
|
+
confidence: 0.3,
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
return suggestions;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Generate a repair plan from suggestions
|
|
144
|
+
*/
|
|
145
|
+
export function generateRepairPlan(suggestions) {
|
|
146
|
+
// Sort by confidence descending
|
|
147
|
+
const sorted = [...suggestions].sort((a, b) => b.confidence - a.confidence);
|
|
148
|
+
const primarySuggestion = sorted[0];
|
|
149
|
+
const autoApplicable = primarySuggestion.confidence >= 0.9;
|
|
150
|
+
const requiresConfirmation = !autoApplicable;
|
|
151
|
+
return {
|
|
152
|
+
suggestions: sorted,
|
|
153
|
+
primarySuggestion,
|
|
154
|
+
autoApplicable,
|
|
155
|
+
requiresConfirmation,
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Print failure information
|
|
160
|
+
*/
|
|
161
|
+
function printFailureInfo(bundle) {
|
|
162
|
+
console.log(`${colors.bold('Spec:')} ${bundle.spec_name}`);
|
|
163
|
+
console.log(`${colors.bold('Failed step:')} ${bundle.failure.step_id} (${bundle.failure.action})`);
|
|
164
|
+
console.log(`${colors.bold('Error type:')} ${bundle.failure.error_type}`);
|
|
165
|
+
console.log(`${colors.bold('Message:')} ${bundle.failure.error_message}`);
|
|
166
|
+
logNewline();
|
|
167
|
+
console.log(`${colors.bold('Context:')}`);
|
|
168
|
+
console.log(` URL: ${bundle.context.url}`);
|
|
169
|
+
console.log(` Viewport: ${bundle.context.viewport.width}x${bundle.context.viewport.height}`);
|
|
170
|
+
console.log(` Browser: ${bundle.context.browser}`);
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Print repair suggestions
|
|
174
|
+
*/
|
|
175
|
+
function printSuggestions(plan) {
|
|
176
|
+
console.log(colors.bold('Repair suggestions:'));
|
|
177
|
+
logNewline();
|
|
178
|
+
for (let i = 0; i < plan.suggestions.length; i++) {
|
|
179
|
+
const suggestion = plan.suggestions[i];
|
|
180
|
+
const confidencePercent = Math.round(suggestion.confidence * 100);
|
|
181
|
+
const confidenceColor = suggestion.confidence >= 0.7 ? colors.pass : suggestion.confidence >= 0.5 ? colors.warning : colors.dim;
|
|
182
|
+
const isPrimary = i === 0;
|
|
183
|
+
const prefix = isPrimary ? symbols.arrow : symbols.bullet;
|
|
184
|
+
console.log(`${prefix} ${suggestion.description} ${confidenceColor(`(${confidencePercent}% confidence)`)}`);
|
|
185
|
+
console.log(` ${colors.dim(`Type: ${suggestion.type}`)}`);
|
|
186
|
+
}
|
|
187
|
+
if (plan.autoApplicable) {
|
|
188
|
+
logNewline();
|
|
189
|
+
console.log(colors.pass('Primary suggestion can be auto-applied with --apply flag.'));
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
export function repairCommand() {
|
|
193
|
+
const cmd = new Command('repair');
|
|
194
|
+
cmd
|
|
195
|
+
.description('Fix broken tests using failure bundles')
|
|
196
|
+
.option('-s, --spec <name>', 'Repair specific spec')
|
|
197
|
+
.option('--from-run <path>', 'Path to failure.json or run directory')
|
|
198
|
+
.option('--ai', 'Enable AI-assisted repair suggestions')
|
|
199
|
+
.option('--apply', 'Auto-apply the highest confidence suggestion')
|
|
200
|
+
.option('--headed', 'Show browser during repair verification')
|
|
201
|
+
.action(async (options) => {
|
|
202
|
+
logHeader('Repair Test');
|
|
203
|
+
logNewline();
|
|
204
|
+
const cwd = options.cwd || process.cwd();
|
|
205
|
+
// 1. Find or load failure bundle
|
|
206
|
+
let failurePath = null;
|
|
207
|
+
if (options.fromRun) {
|
|
208
|
+
failurePath = options.fromRun;
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
failurePath = await findLatestFailure(options.spec || '', cwd);
|
|
212
|
+
}
|
|
213
|
+
if (!failurePath) {
|
|
214
|
+
logError('No failure bundle found.');
|
|
215
|
+
console.log(colors.dim('Run "bf run" first to generate test results.'));
|
|
216
|
+
process.exitCode = 1;
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
// 2. Load failure bundle
|
|
220
|
+
let bundle;
|
|
221
|
+
try {
|
|
222
|
+
bundle = await loadFailureBundle(failurePath);
|
|
223
|
+
}
|
|
224
|
+
catch (e) {
|
|
225
|
+
logError(e.message);
|
|
226
|
+
process.exitCode = 1;
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
// 3. Display failure info
|
|
230
|
+
printFailureInfo(bundle);
|
|
231
|
+
logNewline();
|
|
232
|
+
// 4. Analyze and generate suggestions
|
|
233
|
+
const suggestions = analyzeFailure(bundle);
|
|
234
|
+
// 5. (Optional) AI suggestions
|
|
235
|
+
if (options.ai) {
|
|
236
|
+
logWarning('AI-assisted repair not yet implemented. Using deterministic suggestions only.');
|
|
237
|
+
// In a real implementation, we would call an AI service here
|
|
238
|
+
}
|
|
239
|
+
// 6. Generate repair plan
|
|
240
|
+
if (suggestions.length === 0) {
|
|
241
|
+
console.log(colors.dim('No automatic repair suggestions available.'));
|
|
242
|
+
console.log('Manual intervention may be required.');
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
const plan = generateRepairPlan(suggestions);
|
|
246
|
+
// 7. Print suggestions
|
|
247
|
+
printSuggestions(plan);
|
|
248
|
+
// 8. Apply if requested
|
|
249
|
+
if (options.apply) {
|
|
250
|
+
logNewline();
|
|
251
|
+
if (plan.autoApplicable) {
|
|
252
|
+
logSuccess(`Applying: ${plan.primarySuggestion.description}`);
|
|
253
|
+
console.log(colors.dim('(Repair application not yet implemented)'));
|
|
254
|
+
// In a real implementation:
|
|
255
|
+
// - Apply the patch to the lockfile/spec
|
|
256
|
+
// - Regenerate the test
|
|
257
|
+
// - Run verification
|
|
258
|
+
}
|
|
259
|
+
else {
|
|
260
|
+
logWarning('Primary suggestion has low confidence. Please review and apply manually.');
|
|
261
|
+
console.log(colors.dim(`Confidence: ${Math.round(plan.primarySuggestion.confidence * 100)}% (requires 90%+ for auto-apply)`));
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
else {
|
|
265
|
+
logNewline();
|
|
266
|
+
console.log(colors.dim('Run with --apply to auto-apply the primary suggestion.'));
|
|
267
|
+
}
|
|
268
|
+
});
|
|
269
|
+
return cmd;
|
|
270
|
+
}
|
|
271
|
+
//# sourceMappingURL=repair.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repair.js","sourceRoot":"","sources":["../../src/commands/repair.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* bf review command - start review server for exploration approval
|
|
3
|
+
* @see bf-kqu
|
|
4
|
+
*/
|
|
5
|
+
import { Command } from 'commander';
|
|
6
|
+
/**
|
|
7
|
+
* Load exploration data from disk
|
|
8
|
+
*/
|
|
9
|
+
export declare function loadExploration(id: string, cwd?: string): Promise<unknown>;
|
|
10
|
+
/**
|
|
11
|
+
* Save review data to disk
|
|
12
|
+
*/
|
|
13
|
+
export declare function saveReview(id: string, reviewData: unknown, cwd?: string): Promise<string>;
|
|
14
|
+
/**
|
|
15
|
+
* List all available explorations
|
|
16
|
+
*/
|
|
17
|
+
export declare function listExplorations(cwd?: string): Promise<string[]>;
|
|
18
|
+
/**
|
|
19
|
+
* Serve static files from review-ui dist
|
|
20
|
+
* @param pathname The URL pathname to serve
|
|
21
|
+
* @param cwd Optional working directory for testing
|
|
22
|
+
* @internal Exported for testing
|
|
23
|
+
*/
|
|
24
|
+
export declare function serveStaticUI(pathname: string, cwd?: string): Promise<Response>;
|
|
25
|
+
export declare function reviewCommand(): Command;
|
|
26
|
+
//# sourceMappingURL=review.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review.d.ts","sourceRoot":"","sources":["../../src/commands/review.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMpC;;GAEG;AACH,wBAAsB,eAAe,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,GAAE,MAAsB,GAAG,OAAO,CAAC,OAAO,CAAC,CAgB/F;AAED;;GAEG;AACH,wBAAsB,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,GAAG,GAAE,MAAsB,GAAG,OAAO,CAAC,MAAM,CAAC,CAI9G;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,GAAG,GAAE,MAAsB,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAarF;AAoFD;;;;;GAKG;AACH,wBAAsB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAwDrF;AAmCD,wBAAgB,aAAa,IAAI,OAAO,CAmMvC"}
|