afterburn-cli 1.0.0
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/LICENSE +21 -0
- package/README.md +281 -0
- package/dist/ai/gemini-client.d.ts +21 -0
- package/dist/ai/gemini-client.js +105 -0
- package/dist/ai/gemini-client.js.map +1 -0
- package/dist/ai/index.d.ts +1 -0
- package/dist/ai/index.js +3 -0
- package/dist/ai/index.js.map +1 -0
- package/dist/analysis/diagnosis-schema.d.ts +106 -0
- package/dist/analysis/diagnosis-schema.js +54 -0
- package/dist/analysis/diagnosis-schema.js.map +1 -0
- package/dist/analysis/error-analyzer.d.ts +9 -0
- package/dist/analysis/error-analyzer.js +573 -0
- package/dist/analysis/error-analyzer.js.map +1 -0
- package/dist/analysis/index.d.ts +4 -0
- package/dist/analysis/index.js +6 -0
- package/dist/analysis/index.js.map +1 -0
- package/dist/analysis/source-mapper.d.ts +19 -0
- package/dist/analysis/source-mapper.js +329 -0
- package/dist/analysis/source-mapper.js.map +1 -0
- package/dist/analysis/ui-auditor.d.ts +9 -0
- package/dist/analysis/ui-auditor.js +104 -0
- package/dist/analysis/ui-auditor.js.map +1 -0
- package/dist/artifacts/artifact-storage.d.ts +44 -0
- package/dist/artifacts/artifact-storage.js +99 -0
- package/dist/artifacts/artifact-storage.js.map +1 -0
- package/dist/artifacts/index.d.ts +1 -0
- package/dist/artifacts/index.js +3 -0
- package/dist/artifacts/index.js.map +1 -0
- package/dist/browser/browser-manager.d.ts +45 -0
- package/dist/browser/browser-manager.js +88 -0
- package/dist/browser/browser-manager.js.map +1 -0
- package/dist/browser/challenge-detector.d.ts +10 -0
- package/dist/browser/challenge-detector.js +58 -0
- package/dist/browser/challenge-detector.js.map +1 -0
- package/dist/browser/cookie-dismisser.d.ts +18 -0
- package/dist/browser/cookie-dismisser.js +76 -0
- package/dist/browser/cookie-dismisser.js.map +1 -0
- package/dist/browser/index.d.ts +4 -0
- package/dist/browser/index.js +6 -0
- package/dist/browser/index.js.map +1 -0
- package/dist/browser/stealth-browser.d.ts +13 -0
- package/dist/browser/stealth-browser.js +59 -0
- package/dist/browser/stealth-browser.js.map +1 -0
- package/dist/cli/commander-cli.d.ts +2 -0
- package/dist/cli/commander-cli.js +150 -0
- package/dist/cli/commander-cli.js.map +1 -0
- package/dist/cli/doctor.d.ts +34 -0
- package/dist/cli/doctor.js +124 -0
- package/dist/cli/doctor.js.map +1 -0
- package/dist/cli/first-run.d.ts +6 -0
- package/dist/cli/first-run.js +58 -0
- package/dist/cli/first-run.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.js +5 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/progress.d.ts +11 -0
- package/dist/cli/progress.js +30 -0
- package/dist/cli/progress.js.map +1 -0
- package/dist/core/engine.d.ts +33 -0
- package/dist/core/engine.js +269 -0
- package/dist/core/engine.js.map +1 -0
- package/dist/core/index.d.ts +3 -0
- package/dist/core/index.js +4 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/validation.d.ts +52 -0
- package/dist/core/validation.js +228 -0
- package/dist/core/validation.js.map +1 -0
- package/dist/discovery/crawler.d.ts +58 -0
- package/dist/discovery/crawler.js +240 -0
- package/dist/discovery/crawler.js.map +1 -0
- package/dist/discovery/discovery-pipeline.d.ts +22 -0
- package/dist/discovery/discovery-pipeline.js +256 -0
- package/dist/discovery/discovery-pipeline.js.map +1 -0
- package/dist/discovery/element-mapper.d.ts +21 -0
- package/dist/discovery/element-mapper.js +422 -0
- package/dist/discovery/element-mapper.js.map +1 -0
- package/dist/discovery/index.d.ts +8 -0
- package/dist/discovery/index.js +8 -0
- package/dist/discovery/index.js.map +1 -0
- package/dist/discovery/link-validator.d.ts +15 -0
- package/dist/discovery/link-validator.js +137 -0
- package/dist/discovery/link-validator.js.map +1 -0
- package/dist/discovery/sitemap-builder.d.ts +19 -0
- package/dist/discovery/sitemap-builder.js +166 -0
- package/dist/discovery/sitemap-builder.js.map +1 -0
- package/dist/discovery/spa-detector.d.ts +12 -0
- package/dist/discovery/spa-detector.js +271 -0
- package/dist/discovery/spa-detector.js.map +1 -0
- package/dist/execution/error-detector.d.ts +10 -0
- package/dist/execution/error-detector.js +87 -0
- package/dist/execution/error-detector.js.map +1 -0
- package/dist/execution/evidence-capture.d.ts +8 -0
- package/dist/execution/evidence-capture.js +37 -0
- package/dist/execution/evidence-capture.js.map +1 -0
- package/dist/execution/index.d.ts +5 -0
- package/dist/execution/index.js +7 -0
- package/dist/execution/index.js.map +1 -0
- package/dist/execution/step-handlers.d.ts +48 -0
- package/dist/execution/step-handlers.js +349 -0
- package/dist/execution/step-handlers.js.map +1 -0
- package/dist/execution/test-data.d.ts +50 -0
- package/dist/execution/test-data.js +160 -0
- package/dist/execution/test-data.js.map +1 -0
- package/dist/execution/workflow-executor.d.ts +56 -0
- package/dist/execution/workflow-executor.js +331 -0
- package/dist/execution/workflow-executor.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/entry.d.ts +2 -0
- package/dist/mcp/entry.js +5 -0
- package/dist/mcp/entry.js.map +1 -0
- package/dist/mcp/index.d.ts +2 -0
- package/dist/mcp/index.js +4 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/server.d.ts +3 -0
- package/dist/mcp/server.js +19 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/tools.d.ts +2 -0
- package/dist/mcp/tools.js +162 -0
- package/dist/mcp/tools.js.map +1 -0
- package/dist/planning/heuristic-planner.d.ts +7 -0
- package/dist/planning/heuristic-planner.js +238 -0
- package/dist/planning/heuristic-planner.js.map +1 -0
- package/dist/planning/index.d.ts +3 -0
- package/dist/planning/index.js +5 -0
- package/dist/planning/index.js.map +1 -0
- package/dist/planning/plan-schema.d.ts +74 -0
- package/dist/planning/plan-schema.js +39 -0
- package/dist/planning/plan-schema.js.map +1 -0
- package/dist/planning/workflow-planner.d.ts +39 -0
- package/dist/planning/workflow-planner.js +211 -0
- package/dist/planning/workflow-planner.js.map +1 -0
- package/dist/reports/health-scorer.d.ts +14 -0
- package/dist/reports/health-scorer.js +88 -0
- package/dist/reports/health-scorer.js.map +1 -0
- package/dist/reports/html-generator.d.ts +10 -0
- package/dist/reports/html-generator.js +155 -0
- package/dist/reports/html-generator.js.map +1 -0
- package/dist/reports/index.d.ts +4 -0
- package/dist/reports/index.js +6 -0
- package/dist/reports/index.js.map +1 -0
- package/dist/reports/markdown-generator.d.ts +10 -0
- package/dist/reports/markdown-generator.js +334 -0
- package/dist/reports/markdown-generator.js.map +1 -0
- package/dist/reports/priority-ranker.d.ts +22 -0
- package/dist/reports/priority-ranker.js +608 -0
- package/dist/reports/priority-ranker.js.map +1 -0
- package/dist/screenshots/dual-format.d.ts +14 -0
- package/dist/screenshots/dual-format.js +59 -0
- package/dist/screenshots/dual-format.js.map +1 -0
- package/dist/screenshots/index.d.ts +2 -0
- package/dist/screenshots/index.js +4 -0
- package/dist/screenshots/index.js.map +1 -0
- package/dist/screenshots/screenshot-manager.d.ts +33 -0
- package/dist/screenshots/screenshot-manager.js +86 -0
- package/dist/screenshots/screenshot-manager.js.map +1 -0
- package/dist/testing/accessibility-auditor.d.ts +23 -0
- package/dist/testing/accessibility-auditor.js +44 -0
- package/dist/testing/accessibility-auditor.js.map +1 -0
- package/dist/testing/index.d.ts +4 -0
- package/dist/testing/index.js +5 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing/meta-auditor.d.ts +16 -0
- package/dist/testing/meta-auditor.js +268 -0
- package/dist/testing/meta-auditor.js.map +1 -0
- package/dist/testing/performance-monitor.d.ts +15 -0
- package/dist/testing/performance-monitor.js +64 -0
- package/dist/testing/performance-monitor.js.map +1 -0
- package/dist/types/artifacts.d.ts +58 -0
- package/dist/types/artifacts.js +3 -0
- package/dist/types/artifacts.js.map +1 -0
- package/dist/types/discovery.d.ts +124 -0
- package/dist/types/discovery.js +3 -0
- package/dist/types/discovery.js.map +1 -0
- package/dist/types/execution.d.ts +154 -0
- package/dist/types/execution.js +3 -0
- package/dist/types/execution.js.map +1 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.js +4 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/sanitizer.d.ts +25 -0
- package/dist/utils/sanitizer.js +98 -0
- package/dist/utils/sanitizer.js.map +1 -0
- package/package.json +86 -0
- package/templates/report.hbs +202 -0
- package/templates/styles/report.css +607 -0
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
// Cross-references browser errors with TypeScript/JavaScript source code using AST analysis
|
|
2
|
+
import { Project, SyntaxKind } from 'ts-morph';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import fs from 'fs-extra';
|
|
5
|
+
/**
|
|
6
|
+
* Extract search terms from error messages to find relevant code locations
|
|
7
|
+
*/
|
|
8
|
+
function extractSearchTerms(errorMessage) {
|
|
9
|
+
// Strip common error prefixes
|
|
10
|
+
let cleaned = errorMessage
|
|
11
|
+
.replace(/^(Error|TypeError|ReferenceError|SyntaxError|RangeError):\s*/i, '')
|
|
12
|
+
.trim();
|
|
13
|
+
const terms = new Set();
|
|
14
|
+
// Extract quoted strings (between ', ", or `)
|
|
15
|
+
const quotedRegex = /['"`]([^'"`]+)['"`]/g;
|
|
16
|
+
let match;
|
|
17
|
+
while ((match = quotedRegex.exec(cleaned)) !== null) {
|
|
18
|
+
terms.add(match[1]);
|
|
19
|
+
}
|
|
20
|
+
// Extract identifiers after "Cannot read property" / "Cannot read properties of"
|
|
21
|
+
const propertyMatch = cleaned.match(/Cannot read propert(?:y|ies)(?: of)? ['"`]?(\w+)['"`]?/i);
|
|
22
|
+
if (propertyMatch) {
|
|
23
|
+
terms.add(propertyMatch[1]);
|
|
24
|
+
}
|
|
25
|
+
// Extract identifiers before "is not a function" / "is not defined"
|
|
26
|
+
const functionMatch = cleaned.match(/(\w+)\s+is not (?:a function|defined)/i);
|
|
27
|
+
if (functionMatch) {
|
|
28
|
+
terms.add(functionMatch[1]);
|
|
29
|
+
}
|
|
30
|
+
// Extract URL path segments that look like route handlers
|
|
31
|
+
const pathMatch = cleaned.match(/\/([a-z][a-z0-9-]*(?:\/[a-z][a-z0-9-]*)*)/gi);
|
|
32
|
+
if (pathMatch) {
|
|
33
|
+
pathMatch.forEach(p => {
|
|
34
|
+
const segments = p.split('/').filter(s => s && s.length > 2);
|
|
35
|
+
segments.forEach(seg => terms.add(seg));
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
// Extract camelCase and PascalCase identifiers
|
|
39
|
+
const identifierRegex = /\b([a-z][a-zA-Z0-9]*[A-Z][a-zA-Z0-9]*|[A-Z][a-z0-9]+(?:[A-Z][a-z0-9]+)*)\b/g;
|
|
40
|
+
while ((match = identifierRegex.exec(cleaned)) !== null) {
|
|
41
|
+
terms.add(match[1]);
|
|
42
|
+
}
|
|
43
|
+
// Filter out common words and noise
|
|
44
|
+
const stopWords = new Set(['undefined', 'null', 'object', 'string', 'number', 'the', 'of', 'is', 'at', 'in', 'on', 'to', 'a', 'an']);
|
|
45
|
+
const filtered = Array.from(terms).filter(term => term.length > 2 && !stopWords.has(term.toLowerCase()));
|
|
46
|
+
// Sort by length (longer = more specific = search first)
|
|
47
|
+
return filtered.sort((a, b) => b.length - a.length);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Map a single error message to source code location
|
|
51
|
+
* Returns null if source path invalid, timeout occurs, or no match found
|
|
52
|
+
*
|
|
53
|
+
* Uses a cancelled flag so that when the timeout fires, the ts-morph scanning
|
|
54
|
+
* loop exits early and the Project reference is released for GC. Without this,
|
|
55
|
+
* Promise.race would leave the AST work running and consuming CPU/memory
|
|
56
|
+
* indefinitely on large codebases.
|
|
57
|
+
*/
|
|
58
|
+
export async function mapErrorToSource(errorMessage, sourcePath) {
|
|
59
|
+
let cancelled = false;
|
|
60
|
+
let projectRef = null;
|
|
61
|
+
// 10-second timeout protection — sets cancellation flag and releases ts-morph Project
|
|
62
|
+
const timeoutPromise = new Promise((resolve) => {
|
|
63
|
+
setTimeout(() => {
|
|
64
|
+
cancelled = true;
|
|
65
|
+
projectRef = null; // Release for GC
|
|
66
|
+
resolve(null);
|
|
67
|
+
}, 10000);
|
|
68
|
+
});
|
|
69
|
+
const searchPromise = async () => {
|
|
70
|
+
try {
|
|
71
|
+
// Validate source path exists
|
|
72
|
+
if (!await fs.pathExists(sourcePath)) {
|
|
73
|
+
console.warn(`[source-mapper] Source path does not exist: ${sourcePath}`);
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
// Initialize ts-morph project
|
|
77
|
+
projectRef = new Project({
|
|
78
|
+
skipAddingFilesFromTsConfig: true,
|
|
79
|
+
});
|
|
80
|
+
// Try to load from tsconfig.json
|
|
81
|
+
const tsconfigPath = path.join(sourcePath, 'tsconfig.json');
|
|
82
|
+
if (await fs.pathExists(tsconfigPath)) {
|
|
83
|
+
projectRef.addSourceFilesFromTsConfig(tsconfigPath);
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
// Fallback: manually add .ts/.tsx/.js/.jsx files
|
|
87
|
+
const patterns = [
|
|
88
|
+
path.join(sourcePath, '**/*.ts'),
|
|
89
|
+
path.join(sourcePath, '**/*.tsx'),
|
|
90
|
+
path.join(sourcePath, '**/*.js'),
|
|
91
|
+
path.join(sourcePath, '**/*.jsx'),
|
|
92
|
+
];
|
|
93
|
+
projectRef.addSourceFilesAtPaths(patterns);
|
|
94
|
+
}
|
|
95
|
+
if (cancelled)
|
|
96
|
+
return null;
|
|
97
|
+
const sourceFiles = projectRef.getSourceFiles();
|
|
98
|
+
if (sourceFiles.length === 0) {
|
|
99
|
+
console.warn(`[source-mapper] No source files found in: ${sourcePath}`);
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
// Extract search terms from error message
|
|
103
|
+
const searchTerms = extractSearchTerms(errorMessage);
|
|
104
|
+
if (searchTerms.length === 0) {
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
const matches = [];
|
|
108
|
+
for (const sourceFile of sourceFiles) {
|
|
109
|
+
// Check cancellation between files to avoid wasted CPU on timeout
|
|
110
|
+
if (cancelled)
|
|
111
|
+
return null;
|
|
112
|
+
const filePath = sourceFile.getFilePath();
|
|
113
|
+
// Search function declarations and arrow functions
|
|
114
|
+
sourceFile.getFunctions().forEach(fn => {
|
|
115
|
+
const name = fn.getName();
|
|
116
|
+
if (name && searchTerms.some(term => name.includes(term))) {
|
|
117
|
+
const score = searchTerms.some(term => name === term) ? 10 : 5;
|
|
118
|
+
matches.push({
|
|
119
|
+
file: filePath,
|
|
120
|
+
line: fn.getStartLineNumber(),
|
|
121
|
+
context: fn.getText().slice(0, 200),
|
|
122
|
+
score,
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
// Search arrow functions in variable declarations
|
|
127
|
+
sourceFile.getVariableDeclarations().forEach(varDecl => {
|
|
128
|
+
const name = varDecl.getName();
|
|
129
|
+
const initializer = varDecl.getInitializer();
|
|
130
|
+
if (initializer?.getKind() === SyntaxKind.ArrowFunction) {
|
|
131
|
+
if (searchTerms.some(term => name.includes(term))) {
|
|
132
|
+
const score = searchTerms.some(term => name === term) ? 10 : 5;
|
|
133
|
+
matches.push({
|
|
134
|
+
file: filePath,
|
|
135
|
+
line: varDecl.getStartLineNumber(),
|
|
136
|
+
context: varDecl.getText().slice(0, 200),
|
|
137
|
+
score,
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
// Search class declarations
|
|
143
|
+
sourceFile.getClasses().forEach(cls => {
|
|
144
|
+
const name = cls.getName();
|
|
145
|
+
if (name && searchTerms.some(term => name.includes(term))) {
|
|
146
|
+
const score = searchTerms.some(term => name === term) ? 10 : 5;
|
|
147
|
+
matches.push({
|
|
148
|
+
file: filePath,
|
|
149
|
+
line: cls.getStartLineNumber(),
|
|
150
|
+
context: cls.getText().slice(0, 200),
|
|
151
|
+
score,
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
// Search string literals
|
|
156
|
+
sourceFile.getDescendantsOfKind(SyntaxKind.StringLiteral).forEach(str => {
|
|
157
|
+
const text = str.getLiteralText();
|
|
158
|
+
if (searchTerms.some(term => text.includes(term))) {
|
|
159
|
+
matches.push({
|
|
160
|
+
file: filePath,
|
|
161
|
+
line: str.getStartLineNumber(),
|
|
162
|
+
context: str.getParent()?.getText().slice(0, 200) || text,
|
|
163
|
+
score: 3,
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
// Return highest-scoring match
|
|
169
|
+
if (matches.length === 0) {
|
|
170
|
+
return null;
|
|
171
|
+
}
|
|
172
|
+
matches.sort((a, b) => b.score - a.score);
|
|
173
|
+
const best = matches[0];
|
|
174
|
+
return {
|
|
175
|
+
file: path.relative(sourcePath, best.file),
|
|
176
|
+
line: best.line,
|
|
177
|
+
context: best.context,
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
catch (error) {
|
|
181
|
+
// Graceful degradation on any ts-morph errors
|
|
182
|
+
console.warn(`[source-mapper] Failed to analyze source:`, error);
|
|
183
|
+
return null;
|
|
184
|
+
}
|
|
185
|
+
finally {
|
|
186
|
+
projectRef = null; // Ensure GC can collect ts-morph resources
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
// Race between search and timeout
|
|
190
|
+
return Promise.race([searchPromise(), timeoutPromise]);
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Map multiple errors to source locations in a single batch.
|
|
194
|
+
* Shares 10-second timeout across all searches for efficiency.
|
|
195
|
+
* Uses cancellation flag to stop work when timeout fires (same pattern as mapErrorToSource).
|
|
196
|
+
*/
|
|
197
|
+
export async function mapMultipleErrors(errors, sourcePath) {
|
|
198
|
+
const results = new Map();
|
|
199
|
+
let cancelled = false;
|
|
200
|
+
let projectRef = null;
|
|
201
|
+
// 10-second timeout for entire batch — cancels ongoing work and frees ts-morph memory
|
|
202
|
+
const timeoutPromise = new Promise((resolve) => {
|
|
203
|
+
setTimeout(() => {
|
|
204
|
+
cancelled = true;
|
|
205
|
+
projectRef = null;
|
|
206
|
+
resolve();
|
|
207
|
+
}, 10000);
|
|
208
|
+
});
|
|
209
|
+
const batchSearchPromise = async () => {
|
|
210
|
+
try {
|
|
211
|
+
// Validate source path exists
|
|
212
|
+
if (!await fs.pathExists(sourcePath)) {
|
|
213
|
+
console.warn(`[source-mapper] Source path does not exist: ${sourcePath}`);
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
// Initialize ts-morph project ONCE
|
|
217
|
+
projectRef = new Project({
|
|
218
|
+
skipAddingFilesFromTsConfig: true,
|
|
219
|
+
});
|
|
220
|
+
const tsconfigPath = path.join(sourcePath, 'tsconfig.json');
|
|
221
|
+
if (await fs.pathExists(tsconfigPath)) {
|
|
222
|
+
projectRef.addSourceFilesFromTsConfig(tsconfigPath);
|
|
223
|
+
}
|
|
224
|
+
else {
|
|
225
|
+
const patterns = [
|
|
226
|
+
path.join(sourcePath, '**/*.ts'),
|
|
227
|
+
path.join(sourcePath, '**/*.tsx'),
|
|
228
|
+
path.join(sourcePath, '**/*.js'),
|
|
229
|
+
path.join(sourcePath, '**/*.jsx'),
|
|
230
|
+
];
|
|
231
|
+
projectRef.addSourceFilesAtPaths(patterns);
|
|
232
|
+
}
|
|
233
|
+
if (cancelled)
|
|
234
|
+
return;
|
|
235
|
+
const sourceFiles = projectRef.getSourceFiles();
|
|
236
|
+
if (sourceFiles.length === 0) {
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
// Search for each error
|
|
240
|
+
for (const error of errors) {
|
|
241
|
+
if (cancelled)
|
|
242
|
+
return;
|
|
243
|
+
const searchTerms = extractSearchTerms(error.message);
|
|
244
|
+
if (searchTerms.length === 0)
|
|
245
|
+
continue;
|
|
246
|
+
const matches = [];
|
|
247
|
+
for (const sourceFile of sourceFiles) {
|
|
248
|
+
if (cancelled)
|
|
249
|
+
return;
|
|
250
|
+
const filePath = sourceFile.getFilePath();
|
|
251
|
+
// Search functions
|
|
252
|
+
sourceFile.getFunctions().forEach(fn => {
|
|
253
|
+
const name = fn.getName();
|
|
254
|
+
if (name && searchTerms.some(term => name.includes(term))) {
|
|
255
|
+
const score = searchTerms.some(term => name === term) ? 10 : 5;
|
|
256
|
+
matches.push({
|
|
257
|
+
file: filePath,
|
|
258
|
+
line: fn.getStartLineNumber(),
|
|
259
|
+
context: fn.getText().slice(0, 200),
|
|
260
|
+
score,
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
});
|
|
264
|
+
// Search arrow functions
|
|
265
|
+
sourceFile.getVariableDeclarations().forEach(varDecl => {
|
|
266
|
+
const name = varDecl.getName();
|
|
267
|
+
const initializer = varDecl.getInitializer();
|
|
268
|
+
if (initializer?.getKind() === SyntaxKind.ArrowFunction) {
|
|
269
|
+
if (searchTerms.some(term => name.includes(term))) {
|
|
270
|
+
const score = searchTerms.some(term => name === term) ? 10 : 5;
|
|
271
|
+
matches.push({
|
|
272
|
+
file: filePath,
|
|
273
|
+
line: varDecl.getStartLineNumber(),
|
|
274
|
+
context: varDecl.getText().slice(0, 200),
|
|
275
|
+
score,
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
});
|
|
280
|
+
// Search classes
|
|
281
|
+
sourceFile.getClasses().forEach(cls => {
|
|
282
|
+
const name = cls.getName();
|
|
283
|
+
if (name && searchTerms.some(term => name.includes(term))) {
|
|
284
|
+
const score = searchTerms.some(term => name === term) ? 10 : 5;
|
|
285
|
+
matches.push({
|
|
286
|
+
file: filePath,
|
|
287
|
+
line: cls.getStartLineNumber(),
|
|
288
|
+
context: cls.getText().slice(0, 200),
|
|
289
|
+
score,
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
});
|
|
293
|
+
// Search string literals
|
|
294
|
+
sourceFile.getDescendantsOfKind(SyntaxKind.StringLiteral).forEach(str => {
|
|
295
|
+
const text = str.getLiteralText();
|
|
296
|
+
if (searchTerms.some(term => text.includes(term))) {
|
|
297
|
+
matches.push({
|
|
298
|
+
file: filePath,
|
|
299
|
+
line: str.getStartLineNumber(),
|
|
300
|
+
context: str.getParent()?.getText().slice(0, 200) || text,
|
|
301
|
+
score: 3,
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
// Store best match
|
|
307
|
+
if (matches.length > 0) {
|
|
308
|
+
matches.sort((a, b) => b.score - a.score);
|
|
309
|
+
const best = matches[0];
|
|
310
|
+
results.set(error.message, {
|
|
311
|
+
file: path.relative(sourcePath, best.file),
|
|
312
|
+
line: best.line,
|
|
313
|
+
context: best.context,
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
catch (error) {
|
|
319
|
+
console.warn(`[source-mapper] Batch analysis failed:`, error);
|
|
320
|
+
}
|
|
321
|
+
finally {
|
|
322
|
+
projectRef = null; // Ensure GC can collect ts-morph resources
|
|
323
|
+
}
|
|
324
|
+
};
|
|
325
|
+
// Race between batch search and timeout
|
|
326
|
+
await Promise.race([batchSearchPromise(), timeoutPromise]);
|
|
327
|
+
return results;
|
|
328
|
+
}
|
|
329
|
+
//# sourceMappingURL=source-mapper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"source-mapper.js","sourceRoot":"","sources":["../../src/analysis/source-mapper.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ExecutionArtifact } from '../types/execution.js';
|
|
2
|
+
import { UIAuditResult } from './diagnosis-schema.js';
|
|
3
|
+
/**
|
|
4
|
+
* Main export: Audit UI/UX issues from screenshots in execution artifact
|
|
5
|
+
*/
|
|
6
|
+
export declare function auditUI(artifact: ExecutionArtifact, options?: {
|
|
7
|
+
apiKey?: string;
|
|
8
|
+
aiEnabled?: boolean;
|
|
9
|
+
}): Promise<UIAuditResult[]>;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
// Vision LLM-powered UI/UX auditor for screenshot analysis
|
|
2
|
+
import { GeminiClient } from '../ai/gemini-client.js';
|
|
3
|
+
import { UIAuditSchema } from './diagnosis-schema.js';
|
|
4
|
+
import { redactSensitiveUrl } from '../utils/sanitizer.js';
|
|
5
|
+
import fs from 'node:fs';
|
|
6
|
+
/**
|
|
7
|
+
* Main export: Audit UI/UX issues from screenshots in execution artifact
|
|
8
|
+
*/
|
|
9
|
+
export async function auditUI(artifact, options) {
|
|
10
|
+
const apiKey = options?.apiKey || process.env.GEMINI_API_KEY;
|
|
11
|
+
const aiEnabled = options?.aiEnabled ?? (apiKey ? true : false);
|
|
12
|
+
if (!apiKey || !aiEnabled) {
|
|
13
|
+
console.warn('UI auditing requires GEMINI_API_KEY and AI to be enabled. Skipping visual analysis.');
|
|
14
|
+
return [];
|
|
15
|
+
}
|
|
16
|
+
// Extract screenshots from execution artifact
|
|
17
|
+
const screenshots = extractScreenshots(artifact);
|
|
18
|
+
if (screenshots.length === 0) {
|
|
19
|
+
return [];
|
|
20
|
+
}
|
|
21
|
+
// Initialize Gemini client
|
|
22
|
+
const gemini = new GeminiClient(apiKey);
|
|
23
|
+
// Audit each screenshot
|
|
24
|
+
const auditResults = [];
|
|
25
|
+
for (const screenshot of screenshots) {
|
|
26
|
+
try {
|
|
27
|
+
const audit = await auditScreenshot(screenshot.pngPath, screenshot.url, gemini);
|
|
28
|
+
auditResults.push(audit);
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
console.warn(`Failed to audit screenshot ${screenshot.pngPath}:`, error);
|
|
32
|
+
// Continue with other screenshots
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return auditResults;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Extract screenshots from execution artifact
|
|
39
|
+
* Collects from workflowResults[].stepResults[].evidence?.screenshotRef
|
|
40
|
+
*/
|
|
41
|
+
function extractScreenshots(artifact) {
|
|
42
|
+
const screenshotMap = new Map(); // pngPath -> url (deduplicate by path)
|
|
43
|
+
for (const workflow of artifact.workflowResults) {
|
|
44
|
+
for (const step of workflow.stepResults) {
|
|
45
|
+
if (step.evidence?.screenshotRef) {
|
|
46
|
+
const { pngPath } = step.evidence.screenshotRef;
|
|
47
|
+
const { pageUrl } = step.evidence;
|
|
48
|
+
// Deduplicate by path, verify file exists
|
|
49
|
+
if (!screenshotMap.has(pngPath) && fs.existsSync(pngPath)) {
|
|
50
|
+
screenshotMap.set(pngPath, pageUrl);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
// Convert map to array
|
|
56
|
+
return Array.from(screenshotMap.entries()).map(([pngPath, url]) => ({
|
|
57
|
+
url,
|
|
58
|
+
pngPath,
|
|
59
|
+
}));
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Audit a single screenshot using Gemini Vision LLM
|
|
63
|
+
*/
|
|
64
|
+
async function auditScreenshot(pngPath, pageUrl, gemini) {
|
|
65
|
+
// Redact sensitive URL before sending to Gemini
|
|
66
|
+
const safeUrl = redactSensitiveUrl(pageUrl);
|
|
67
|
+
const prompt = buildVisionPrompt(safeUrl);
|
|
68
|
+
// Call Gemini Vision API with structured output
|
|
69
|
+
const audit = await gemini.generateStructuredWithImage(prompt, UIAuditSchema, pngPath);
|
|
70
|
+
return {
|
|
71
|
+
...audit,
|
|
72
|
+
pageUrl: safeUrl,
|
|
73
|
+
screenshotRef: pngPath,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Build vision LLM prompt for UI auditing
|
|
78
|
+
*/
|
|
79
|
+
function buildVisionPrompt(pageUrl) {
|
|
80
|
+
const safeUrl = redactSensitiveUrl(pageUrl);
|
|
81
|
+
return `You are a UI/UX expert reviewing a web page screenshot. Analyze it for visual issues.
|
|
82
|
+
|
|
83
|
+
Page URL: ${safeUrl}
|
|
84
|
+
|
|
85
|
+
Look for these specific issues:
|
|
86
|
+
|
|
87
|
+
1. LAYOUT ISSUES: Elements overlapping, cramped spacing, content cut off at edges,
|
|
88
|
+
misaligned sections, inconsistent margins/padding, elements pushed off-screen
|
|
89
|
+
|
|
90
|
+
2. CONTRAST & READABILITY: Text hard to read against background, insufficient color
|
|
91
|
+
contrast (WCAG AA requires 4.5:1 for normal text), tiny font sizes, light gray
|
|
92
|
+
text on white background
|
|
93
|
+
|
|
94
|
+
3. FORMATTING ISSUES: Text truncated with "...", buttons too small to tap on mobile,
|
|
95
|
+
inconsistent font sizes, broken grid layouts, images stretched or squished
|
|
96
|
+
|
|
97
|
+
4. IMPROVEMENT SUGGESTIONS: What would make this page better for users?
|
|
98
|
+
Write suggestions in plain English as if explaining to someone who built this
|
|
99
|
+
with AI tools and doesn't know CSS deeply.
|
|
100
|
+
|
|
101
|
+
Be specific about WHERE on the page each issue appears (top, bottom, left sidebar, etc).
|
|
102
|
+
Only report issues you are confident about. If the page looks fine, say so.`;
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=ui-auditor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui-auditor.js","sourceRoot":"","sources":["../../src/analysis/ui-auditor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { ArtifactMetadata } from '../types/artifacts.js';
|
|
2
|
+
/**
|
|
3
|
+
* Manages JSON artifact storage with save/load/cleanup operations
|
|
4
|
+
*/
|
|
5
|
+
export declare class ArtifactStorage {
|
|
6
|
+
private readonly baseDir;
|
|
7
|
+
private currentSessionId?;
|
|
8
|
+
constructor(baseDir?: string);
|
|
9
|
+
private buildFilename;
|
|
10
|
+
/**
|
|
11
|
+
* Saves an artifact as a versioned JSON file
|
|
12
|
+
* @param artifact - Artifact with metadata
|
|
13
|
+
* @returns Filepath where artifact was saved
|
|
14
|
+
*/
|
|
15
|
+
save<T extends ArtifactMetadata>(artifact: T): Promise<string>;
|
|
16
|
+
/**
|
|
17
|
+
* Loads an artifact from storage
|
|
18
|
+
* @param stage - Pipeline stage name
|
|
19
|
+
* @param sessionId - Session UUID
|
|
20
|
+
* @returns Parsed artifact
|
|
21
|
+
* @throws Error if artifact not found
|
|
22
|
+
*/
|
|
23
|
+
load<T extends ArtifactMetadata>(stage: string, sessionId: string): Promise<T>;
|
|
24
|
+
/**
|
|
25
|
+
* Checks if an artifact exists
|
|
26
|
+
* @param stage - Pipeline stage name
|
|
27
|
+
* @param sessionId - Session UUID
|
|
28
|
+
* @returns True if artifact file exists
|
|
29
|
+
*/
|
|
30
|
+
exists(stage: string, sessionId: string): Promise<boolean>;
|
|
31
|
+
/**
|
|
32
|
+
* Lists all artifact files, optionally filtered by stage
|
|
33
|
+
* @param stage - Optional stage prefix to filter by
|
|
34
|
+
* @returns Array of artifact filenames
|
|
35
|
+
*/
|
|
36
|
+
list(stage?: string): Promise<string[]>;
|
|
37
|
+
/**
|
|
38
|
+
* Removes artifacts older than specified days based on file modification time.
|
|
39
|
+
* Excludes artifacts from the current session.
|
|
40
|
+
* @param olderThanDays - Age threshold in days (default: 7). Set to 0 to clean all old artifacts.
|
|
41
|
+
* @returns Count of deleted files
|
|
42
|
+
*/
|
|
43
|
+
cleanup(olderThanDays?: number): Promise<number>;
|
|
44
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
// JSON file persistence for pipeline artifacts with versioning and cleanup
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import fs from 'fs-extra';
|
|
4
|
+
import { sanitizeSessionId } from '../core/validation.js';
|
|
5
|
+
/**
|
|
6
|
+
* Manages JSON artifact storage with save/load/cleanup operations
|
|
7
|
+
*/
|
|
8
|
+
export class ArtifactStorage {
|
|
9
|
+
baseDir;
|
|
10
|
+
currentSessionId;
|
|
11
|
+
constructor(baseDir = '.afterburn/artifacts') {
|
|
12
|
+
this.baseDir = baseDir;
|
|
13
|
+
fs.ensureDirSync(this.baseDir);
|
|
14
|
+
}
|
|
15
|
+
buildFilename(stage, sessionId) {
|
|
16
|
+
const safeStage = stage.replace(/[^a-zA-Z0-9_-]/g, '_');
|
|
17
|
+
const safeSessionId = sanitizeSessionId(sessionId);
|
|
18
|
+
return `${safeStage}-${safeSessionId}.json`;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Saves an artifact as a versioned JSON file
|
|
22
|
+
* @param artifact - Artifact with metadata
|
|
23
|
+
* @returns Filepath where artifact was saved
|
|
24
|
+
*/
|
|
25
|
+
async save(artifact) {
|
|
26
|
+
const filename = this.buildFilename(artifact.stage, artifact.sessionId);
|
|
27
|
+
const filepath = join(this.baseDir, filename);
|
|
28
|
+
await fs.writeJson(filepath, artifact, { spaces: 2 });
|
|
29
|
+
// Track current session for cleanup
|
|
30
|
+
this.currentSessionId = sanitizeSessionId(artifact.sessionId);
|
|
31
|
+
return filepath;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Loads an artifact from storage
|
|
35
|
+
* @param stage - Pipeline stage name
|
|
36
|
+
* @param sessionId - Session UUID
|
|
37
|
+
* @returns Parsed artifact
|
|
38
|
+
* @throws Error if artifact not found
|
|
39
|
+
*/
|
|
40
|
+
async load(stage, sessionId) {
|
|
41
|
+
const filename = this.buildFilename(stage, sessionId);
|
|
42
|
+
const filepath = join(this.baseDir, filename);
|
|
43
|
+
if (!(await fs.pathExists(filepath))) {
|
|
44
|
+
throw new Error(`Artifact not found: ${stage}-${sessionId}`);
|
|
45
|
+
}
|
|
46
|
+
return fs.readJson(filepath);
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Checks if an artifact exists
|
|
50
|
+
* @param stage - Pipeline stage name
|
|
51
|
+
* @param sessionId - Session UUID
|
|
52
|
+
* @returns True if artifact file exists
|
|
53
|
+
*/
|
|
54
|
+
async exists(stage, sessionId) {
|
|
55
|
+
const filename = this.buildFilename(stage, sessionId);
|
|
56
|
+
const filepath = join(this.baseDir, filename);
|
|
57
|
+
return fs.pathExists(filepath);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Lists all artifact files, optionally filtered by stage
|
|
61
|
+
* @param stage - Optional stage prefix to filter by
|
|
62
|
+
* @returns Array of artifact filenames
|
|
63
|
+
*/
|
|
64
|
+
async list(stage) {
|
|
65
|
+
const files = await fs.readdir(this.baseDir);
|
|
66
|
+
const jsonFiles = files.filter((f) => f.endsWith('.json'));
|
|
67
|
+
if (!stage) {
|
|
68
|
+
return jsonFiles;
|
|
69
|
+
}
|
|
70
|
+
return jsonFiles.filter((f) => f.startsWith(`${stage}-`));
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Removes artifacts older than specified days based on file modification time.
|
|
74
|
+
* Excludes artifacts from the current session.
|
|
75
|
+
* @param olderThanDays - Age threshold in days (default: 7). Set to 0 to clean all old artifacts.
|
|
76
|
+
* @returns Count of deleted files
|
|
77
|
+
*/
|
|
78
|
+
async cleanup(olderThanDays = 7) {
|
|
79
|
+
const files = await this.list();
|
|
80
|
+
const now = Date.now();
|
|
81
|
+
const threshold = olderThanDays * 24 * 60 * 60 * 1000; // Convert days to milliseconds
|
|
82
|
+
let deletedCount = 0;
|
|
83
|
+
for (const file of files) {
|
|
84
|
+
// Skip artifacts from current session
|
|
85
|
+
if (this.currentSessionId && file.includes(this.currentSessionId)) {
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
const filepath = join(this.baseDir, file);
|
|
89
|
+
const stats = await fs.stat(filepath);
|
|
90
|
+
const age = now - stats.mtimeMs;
|
|
91
|
+
if (age > threshold) {
|
|
92
|
+
await fs.unlink(filepath);
|
|
93
|
+
deletedCount++;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return deletedCount;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=artifact-storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"artifact-storage.js","sourceRoot":"","sources":["../../src/artifacts/artifact-storage.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { ArtifactStorage } from './artifact-storage.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/artifacts/index.ts"],"names":[],"mappings":"AAAA,qCAAqC;AACrC,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC"}
|