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.
Files changed (188) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +281 -0
  3. package/dist/ai/gemini-client.d.ts +21 -0
  4. package/dist/ai/gemini-client.js +105 -0
  5. package/dist/ai/gemini-client.js.map +1 -0
  6. package/dist/ai/index.d.ts +1 -0
  7. package/dist/ai/index.js +3 -0
  8. package/dist/ai/index.js.map +1 -0
  9. package/dist/analysis/diagnosis-schema.d.ts +106 -0
  10. package/dist/analysis/diagnosis-schema.js +54 -0
  11. package/dist/analysis/diagnosis-schema.js.map +1 -0
  12. package/dist/analysis/error-analyzer.d.ts +9 -0
  13. package/dist/analysis/error-analyzer.js +573 -0
  14. package/dist/analysis/error-analyzer.js.map +1 -0
  15. package/dist/analysis/index.d.ts +4 -0
  16. package/dist/analysis/index.js +6 -0
  17. package/dist/analysis/index.js.map +1 -0
  18. package/dist/analysis/source-mapper.d.ts +19 -0
  19. package/dist/analysis/source-mapper.js +329 -0
  20. package/dist/analysis/source-mapper.js.map +1 -0
  21. package/dist/analysis/ui-auditor.d.ts +9 -0
  22. package/dist/analysis/ui-auditor.js +104 -0
  23. package/dist/analysis/ui-auditor.js.map +1 -0
  24. package/dist/artifacts/artifact-storage.d.ts +44 -0
  25. package/dist/artifacts/artifact-storage.js +99 -0
  26. package/dist/artifacts/artifact-storage.js.map +1 -0
  27. package/dist/artifacts/index.d.ts +1 -0
  28. package/dist/artifacts/index.js +3 -0
  29. package/dist/artifacts/index.js.map +1 -0
  30. package/dist/browser/browser-manager.d.ts +45 -0
  31. package/dist/browser/browser-manager.js +88 -0
  32. package/dist/browser/browser-manager.js.map +1 -0
  33. package/dist/browser/challenge-detector.d.ts +10 -0
  34. package/dist/browser/challenge-detector.js +58 -0
  35. package/dist/browser/challenge-detector.js.map +1 -0
  36. package/dist/browser/cookie-dismisser.d.ts +18 -0
  37. package/dist/browser/cookie-dismisser.js +76 -0
  38. package/dist/browser/cookie-dismisser.js.map +1 -0
  39. package/dist/browser/index.d.ts +4 -0
  40. package/dist/browser/index.js +6 -0
  41. package/dist/browser/index.js.map +1 -0
  42. package/dist/browser/stealth-browser.d.ts +13 -0
  43. package/dist/browser/stealth-browser.js +59 -0
  44. package/dist/browser/stealth-browser.js.map +1 -0
  45. package/dist/cli/commander-cli.d.ts +2 -0
  46. package/dist/cli/commander-cli.js +150 -0
  47. package/dist/cli/commander-cli.js.map +1 -0
  48. package/dist/cli/doctor.d.ts +34 -0
  49. package/dist/cli/doctor.js +124 -0
  50. package/dist/cli/doctor.js.map +1 -0
  51. package/dist/cli/first-run.d.ts +6 -0
  52. package/dist/cli/first-run.js +58 -0
  53. package/dist/cli/first-run.js.map +1 -0
  54. package/dist/cli/index.d.ts +3 -0
  55. package/dist/cli/index.js +5 -0
  56. package/dist/cli/index.js.map +1 -0
  57. package/dist/cli/progress.d.ts +11 -0
  58. package/dist/cli/progress.js +30 -0
  59. package/dist/cli/progress.js.map +1 -0
  60. package/dist/core/engine.d.ts +33 -0
  61. package/dist/core/engine.js +269 -0
  62. package/dist/core/engine.js.map +1 -0
  63. package/dist/core/index.d.ts +3 -0
  64. package/dist/core/index.js +4 -0
  65. package/dist/core/index.js.map +1 -0
  66. package/dist/core/validation.d.ts +52 -0
  67. package/dist/core/validation.js +228 -0
  68. package/dist/core/validation.js.map +1 -0
  69. package/dist/discovery/crawler.d.ts +58 -0
  70. package/dist/discovery/crawler.js +240 -0
  71. package/dist/discovery/crawler.js.map +1 -0
  72. package/dist/discovery/discovery-pipeline.d.ts +22 -0
  73. package/dist/discovery/discovery-pipeline.js +256 -0
  74. package/dist/discovery/discovery-pipeline.js.map +1 -0
  75. package/dist/discovery/element-mapper.d.ts +21 -0
  76. package/dist/discovery/element-mapper.js +422 -0
  77. package/dist/discovery/element-mapper.js.map +1 -0
  78. package/dist/discovery/index.d.ts +8 -0
  79. package/dist/discovery/index.js +8 -0
  80. package/dist/discovery/index.js.map +1 -0
  81. package/dist/discovery/link-validator.d.ts +15 -0
  82. package/dist/discovery/link-validator.js +137 -0
  83. package/dist/discovery/link-validator.js.map +1 -0
  84. package/dist/discovery/sitemap-builder.d.ts +19 -0
  85. package/dist/discovery/sitemap-builder.js +166 -0
  86. package/dist/discovery/sitemap-builder.js.map +1 -0
  87. package/dist/discovery/spa-detector.d.ts +12 -0
  88. package/dist/discovery/spa-detector.js +271 -0
  89. package/dist/discovery/spa-detector.js.map +1 -0
  90. package/dist/execution/error-detector.d.ts +10 -0
  91. package/dist/execution/error-detector.js +87 -0
  92. package/dist/execution/error-detector.js.map +1 -0
  93. package/dist/execution/evidence-capture.d.ts +8 -0
  94. package/dist/execution/evidence-capture.js +37 -0
  95. package/dist/execution/evidence-capture.js.map +1 -0
  96. package/dist/execution/index.d.ts +5 -0
  97. package/dist/execution/index.js +7 -0
  98. package/dist/execution/index.js.map +1 -0
  99. package/dist/execution/step-handlers.d.ts +48 -0
  100. package/dist/execution/step-handlers.js +349 -0
  101. package/dist/execution/step-handlers.js.map +1 -0
  102. package/dist/execution/test-data.d.ts +50 -0
  103. package/dist/execution/test-data.js +160 -0
  104. package/dist/execution/test-data.js.map +1 -0
  105. package/dist/execution/workflow-executor.d.ts +56 -0
  106. package/dist/execution/workflow-executor.js +331 -0
  107. package/dist/execution/workflow-executor.js.map +1 -0
  108. package/dist/index.d.ts +2 -0
  109. package/dist/index.js +5 -0
  110. package/dist/index.js.map +1 -0
  111. package/dist/mcp/entry.d.ts +2 -0
  112. package/dist/mcp/entry.js +5 -0
  113. package/dist/mcp/entry.js.map +1 -0
  114. package/dist/mcp/index.d.ts +2 -0
  115. package/dist/mcp/index.js +4 -0
  116. package/dist/mcp/index.js.map +1 -0
  117. package/dist/mcp/server.d.ts +3 -0
  118. package/dist/mcp/server.js +19 -0
  119. package/dist/mcp/server.js.map +1 -0
  120. package/dist/mcp/tools.d.ts +2 -0
  121. package/dist/mcp/tools.js +162 -0
  122. package/dist/mcp/tools.js.map +1 -0
  123. package/dist/planning/heuristic-planner.d.ts +7 -0
  124. package/dist/planning/heuristic-planner.js +238 -0
  125. package/dist/planning/heuristic-planner.js.map +1 -0
  126. package/dist/planning/index.d.ts +3 -0
  127. package/dist/planning/index.js +5 -0
  128. package/dist/planning/index.js.map +1 -0
  129. package/dist/planning/plan-schema.d.ts +74 -0
  130. package/dist/planning/plan-schema.js +39 -0
  131. package/dist/planning/plan-schema.js.map +1 -0
  132. package/dist/planning/workflow-planner.d.ts +39 -0
  133. package/dist/planning/workflow-planner.js +211 -0
  134. package/dist/planning/workflow-planner.js.map +1 -0
  135. package/dist/reports/health-scorer.d.ts +14 -0
  136. package/dist/reports/health-scorer.js +88 -0
  137. package/dist/reports/health-scorer.js.map +1 -0
  138. package/dist/reports/html-generator.d.ts +10 -0
  139. package/dist/reports/html-generator.js +155 -0
  140. package/dist/reports/html-generator.js.map +1 -0
  141. package/dist/reports/index.d.ts +4 -0
  142. package/dist/reports/index.js +6 -0
  143. package/dist/reports/index.js.map +1 -0
  144. package/dist/reports/markdown-generator.d.ts +10 -0
  145. package/dist/reports/markdown-generator.js +334 -0
  146. package/dist/reports/markdown-generator.js.map +1 -0
  147. package/dist/reports/priority-ranker.d.ts +22 -0
  148. package/dist/reports/priority-ranker.js +608 -0
  149. package/dist/reports/priority-ranker.js.map +1 -0
  150. package/dist/screenshots/dual-format.d.ts +14 -0
  151. package/dist/screenshots/dual-format.js +59 -0
  152. package/dist/screenshots/dual-format.js.map +1 -0
  153. package/dist/screenshots/index.d.ts +2 -0
  154. package/dist/screenshots/index.js +4 -0
  155. package/dist/screenshots/index.js.map +1 -0
  156. package/dist/screenshots/screenshot-manager.d.ts +33 -0
  157. package/dist/screenshots/screenshot-manager.js +86 -0
  158. package/dist/screenshots/screenshot-manager.js.map +1 -0
  159. package/dist/testing/accessibility-auditor.d.ts +23 -0
  160. package/dist/testing/accessibility-auditor.js +44 -0
  161. package/dist/testing/accessibility-auditor.js.map +1 -0
  162. package/dist/testing/index.d.ts +4 -0
  163. package/dist/testing/index.js +5 -0
  164. package/dist/testing/index.js.map +1 -0
  165. package/dist/testing/meta-auditor.d.ts +16 -0
  166. package/dist/testing/meta-auditor.js +268 -0
  167. package/dist/testing/meta-auditor.js.map +1 -0
  168. package/dist/testing/performance-monitor.d.ts +15 -0
  169. package/dist/testing/performance-monitor.js +64 -0
  170. package/dist/testing/performance-monitor.js.map +1 -0
  171. package/dist/types/artifacts.d.ts +58 -0
  172. package/dist/types/artifacts.js +3 -0
  173. package/dist/types/artifacts.js.map +1 -0
  174. package/dist/types/discovery.d.ts +124 -0
  175. package/dist/types/discovery.js +3 -0
  176. package/dist/types/discovery.js.map +1 -0
  177. package/dist/types/execution.d.ts +154 -0
  178. package/dist/types/execution.js +3 -0
  179. package/dist/types/execution.js.map +1 -0
  180. package/dist/types/index.d.ts +2 -0
  181. package/dist/types/index.js +4 -0
  182. package/dist/types/index.js.map +1 -0
  183. package/dist/utils/sanitizer.d.ts +25 -0
  184. package/dist/utils/sanitizer.js +98 -0
  185. package/dist/utils/sanitizer.js.map +1 -0
  186. package/package.json +86 -0
  187. package/templates/report.hbs +202 -0
  188. package/templates/styles/report.css +607 -0
@@ -0,0 +1,56 @@
1
+ import type { WorkflowPlan } from '../types/discovery.js';
2
+ import type { ExecutionArtifact } from '../types/execution.js';
3
+ export interface ExecutionOptions {
4
+ targetUrl: string;
5
+ sessionId: string;
6
+ workflowPlans: WorkflowPlan[];
7
+ email?: string;
8
+ password?: string;
9
+ headless?: boolean;
10
+ onProgress?: (message: string) => void;
11
+ }
12
+ /**
13
+ * Executes all workflow plans with comprehensive error detection and auditing
14
+ */
15
+ export declare class WorkflowExecutor {
16
+ private browserManager;
17
+ private screenshotManager;
18
+ private options;
19
+ constructor(options: ExecutionOptions);
20
+ /**
21
+ * Main execution flow: runs all workflows and produces execution artifact
22
+ */
23
+ execute(): Promise<ExecutionArtifact>;
24
+ /**
25
+ * Execute a single workflow plan
26
+ */
27
+ private executeWorkflow;
28
+ /**
29
+ * Audit a page with accessibility and performance checks
30
+ */
31
+ private auditPage;
32
+ /**
33
+ * Find the parent form selector for a field
34
+ */
35
+ private findFormSelector;
36
+ /**
37
+ * Inject --email and --password into login form fields
38
+ */
39
+ private injectCredentialsIfNeeded;
40
+ /**
41
+ * Check if selector looks like an email field
42
+ */
43
+ private isEmailField;
44
+ /**
45
+ * Check if selector looks like a password field
46
+ */
47
+ private isPasswordField;
48
+ /**
49
+ * Calculate total issues across all results
50
+ */
51
+ private calculateTotalIssues;
52
+ /**
53
+ * Log message with optional progress callback
54
+ */
55
+ private log;
56
+ }
@@ -0,0 +1,331 @@
1
+ // Workflow execution orchestrator: runs workflow plans with error capture, evidence collection, and page auditing
2
+ import { BrowserManager } from '../browser/index.js';
3
+ import { ScreenshotManager } from '../screenshots/index.js';
4
+ import { setupErrorListeners } from './error-detector.js';
5
+ import { executeStep, captureClickState, checkDeadButton, detectBrokenForm, DEAD_BUTTON_WAIT } from './step-handlers.js';
6
+ import { captureErrorEvidence } from './evidence-capture.js';
7
+ import { auditAccessibility } from '../testing/accessibility-auditor.js';
8
+ import { capturePerformanceMetrics } from '../testing/performance-monitor.js';
9
+ import { auditMeta } from '../testing/meta-auditor.js';
10
+ /**
11
+ * Executes all workflow plans with comprehensive error detection and auditing
12
+ */
13
+ export class WorkflowExecutor {
14
+ browserManager;
15
+ screenshotManager;
16
+ options;
17
+ constructor(options) {
18
+ this.options = options;
19
+ this.browserManager = new BrowserManager({ headless: options.headless ?? true });
20
+ this.screenshotManager = new ScreenshotManager();
21
+ }
22
+ /**
23
+ * Main execution flow: runs all workflows and produces execution artifact
24
+ */
25
+ async execute() {
26
+ this.log('Launching browser...');
27
+ await this.browserManager.launch();
28
+ const workflowResults = [];
29
+ const pageAudits = [];
30
+ const allDeadButtons = [];
31
+ const allBrokenForms = [];
32
+ try {
33
+ // Execute each workflow sequentially
34
+ for (const plan of this.options.workflowPlans) {
35
+ this.log(`\nExecuting workflow: ${plan.workflowName}`);
36
+ const result = await this.executeWorkflow(plan, pageAudits, allDeadButtons, allBrokenForms);
37
+ workflowResults.push(result);
38
+ this.log(` Status: ${result.overallStatus} (${result.passedSteps}/${result.totalSteps} passed)`);
39
+ }
40
+ }
41
+ finally {
42
+ await this.browserManager.close();
43
+ }
44
+ // Calculate total issues and exit code
45
+ const totalIssues = this.calculateTotalIssues(workflowResults, pageAudits, allDeadButtons, allBrokenForms);
46
+ const exitCode = (workflowResults.some(r => r.overallStatus === 'failed') || totalIssues > 0) ? 1 : 0;
47
+ // Build execution artifact
48
+ const artifact = {
49
+ version: '1.0.0',
50
+ stage: 'execution',
51
+ timestamp: new Date().toISOString(),
52
+ sessionId: this.options.sessionId,
53
+ targetUrl: this.options.targetUrl,
54
+ workflowResults,
55
+ pageAudits,
56
+ deadButtons: allDeadButtons,
57
+ brokenForms: allBrokenForms,
58
+ brokenLinks: [], // Populated by engine from discovery phase
59
+ totalIssues,
60
+ exitCode,
61
+ };
62
+ return artifact;
63
+ }
64
+ /**
65
+ * Execute a single workflow plan
66
+ */
67
+ async executeWorkflow(plan, pageAudits, allDeadButtons, allBrokenForms) {
68
+ const workflowStart = Date.now();
69
+ // Create a fresh page for this workflow
70
+ const page = await this.browserManager.newPage();
71
+ // Set up error listeners
72
+ const { collector, cleanup } = setupErrorListeners(page);
73
+ // Set up a single persistent dialog handler to auto-dismiss alert/confirm/prompt.
74
+ // This MUST be a single handler per page — stacking page.once('dialog') per step
75
+ // caused crashes when multiple handlers tried to dismiss the same dialog.
76
+ const dialogHandler = async (dialog) => {
77
+ try {
78
+ await dialog.dismiss();
79
+ }
80
+ catch {
81
+ // Dialog may already be handled — safe to ignore
82
+ }
83
+ };
84
+ page.on('dialog', dialogHandler);
85
+ const stepResults = [];
86
+ let firstNavUrl = null;
87
+ let lastUrl = '';
88
+ let pageScreenshotPath;
89
+ try {
90
+ // Execute each step sequentially
91
+ for (let i = 0; i < plan.steps.length; i++) {
92
+ const step = plan.steps[i];
93
+ this.log(` Step ${i + 1}/${plan.steps.length}: ${step.action} ${step.selector}`);
94
+ // Inject credentials if this is a login workflow
95
+ const stepWithCreds = this.injectCredentialsIfNeeded(step, plan);
96
+ // Capture pre-click state for dead-button detection (before executeStep clicks)
97
+ let preClickState;
98
+ let networkActivity = false;
99
+ let networkListener;
100
+ if (step.action === 'click') {
101
+ preClickState = await captureClickState(page);
102
+ networkListener = () => { networkActivity = true; };
103
+ page.on('request', networkListener);
104
+ }
105
+ // Execute the step
106
+ const result = await executeStep(page, stepWithCreds, i, this.options.targetUrl);
107
+ // After step, check for dead button using pre/post state comparison (no re-click)
108
+ if (step.action === 'click' && result.status === 'passed' && preClickState) {
109
+ await page.waitForTimeout(DEAD_BUTTON_WAIT);
110
+ const postState = await captureClickState(page);
111
+ postState.hadNetworkActivity = networkActivity;
112
+ if (networkListener)
113
+ page.off('request', networkListener);
114
+ const deadResult = checkDeadButton(step.selector, preClickState, postState);
115
+ if (deadResult.isDead) {
116
+ allDeadButtons.push(deadResult);
117
+ this.log(` Warning: Dead button detected`);
118
+ }
119
+ }
120
+ else if (networkListener) {
121
+ page.off('request', networkListener);
122
+ }
123
+ // Capture evidence on failure
124
+ if (result.status === 'failed') {
125
+ this.log(` Failed: ${result.error}`);
126
+ result.evidence = await captureErrorEvidence(page, collector, this.screenshotManager, i);
127
+ }
128
+ stepResults.push(result);
129
+ // Track first navigation URL for auditing
130
+ if (step.action === 'navigate' && !firstNavUrl) {
131
+ firstNavUrl = page.url();
132
+ }
133
+ // Track last URL
134
+ lastUrl = page.url();
135
+ // Form detection: check if this step interacts with a form
136
+ const isFormFillThenSubmit = step.action === 'fill' &&
137
+ i + 1 < plan.steps.length &&
138
+ plan.steps[i + 1].action === 'click' &&
139
+ plan.steps[i + 1].selector.includes('submit');
140
+ const isClickInsideForm = step.action === 'click' && result.status === 'passed';
141
+ if (isFormFillThenSubmit || isClickInsideForm) {
142
+ const formSelector = await this.findFormSelector(page, step.selector);
143
+ if (formSelector) {
144
+ const brokenResult = await detectBrokenForm(page, formSelector);
145
+ if (brokenResult.isBroken) {
146
+ allBrokenForms.push(brokenResult);
147
+ this.log(` Warning: Broken form detected`);
148
+ }
149
+ }
150
+ }
151
+ }
152
+ // Audit key pages (first navigation + final URL)
153
+ if (firstNavUrl) {
154
+ await this.auditPage(page, firstNavUrl, pageAudits);
155
+ }
156
+ if (lastUrl && lastUrl !== firstNavUrl) {
157
+ await this.auditPage(page, lastUrl, pageAudits);
158
+ }
159
+ // Capture page-level screenshot for report embedding (before page closes)
160
+ try {
161
+ const pageScreenshot = await this.screenshotManager.capture(page, `workflow-${plan.workflowName.replace(/\s+/g, '-').toLowerCase()}`);
162
+ pageScreenshotPath = pageScreenshot.pngPath;
163
+ }
164
+ catch {
165
+ // Graceful degradation — screenshot failure doesn't break workflow
166
+ }
167
+ }
168
+ finally {
169
+ // Clean up error listeners and dialog handler
170
+ cleanup();
171
+ page.off('dialog', dialogHandler);
172
+ await page.close();
173
+ }
174
+ // Calculate workflow result
175
+ const passedSteps = stepResults.filter(r => r.status === 'passed').length;
176
+ const failedSteps = stepResults.filter(r => r.status === 'failed').length;
177
+ const skippedSteps = stepResults.filter(r => r.status === 'skipped').length;
178
+ const overallStatus = failedSteps > 0 ? 'failed' : 'passed';
179
+ return {
180
+ workflowName: plan.workflowName,
181
+ description: plan.description,
182
+ totalSteps: plan.steps.length,
183
+ passedSteps,
184
+ failedSteps,
185
+ skippedSteps,
186
+ stepResults,
187
+ errors: collector,
188
+ overallStatus,
189
+ duration: Date.now() - workflowStart,
190
+ pageScreenshotRef: pageScreenshotPath,
191
+ };
192
+ }
193
+ /**
194
+ * Audit a page with accessibility and performance checks
195
+ */
196
+ async auditPage(page, url, pageAudits) {
197
+ // Check if we already audited this URL
198
+ if (pageAudits.some(a => a.url === url)) {
199
+ return;
200
+ }
201
+ this.log(` Auditing page: ${url}`);
202
+ // Ensure audit data is captured from the URL being recorded.
203
+ if (page.url() !== url) {
204
+ try {
205
+ await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 15_000 });
206
+ }
207
+ catch (error) {
208
+ this.log(` Skipping audit: unable to load ${url} (${error instanceof Error ? error.message : String(error)})`);
209
+ return;
210
+ }
211
+ }
212
+ const [accessibility, performance, metaAudit] = await Promise.all([
213
+ auditAccessibility(page),
214
+ capturePerformanceMetrics(page),
215
+ auditMeta(page),
216
+ ]);
217
+ pageAudits.push({
218
+ url,
219
+ accessibility,
220
+ performance,
221
+ metaIssues: metaAudit.issues.length > 0 ? metaAudit.issues : undefined,
222
+ });
223
+ if (accessibility.violationCount > 0) {
224
+ this.log(` Accessibility: ${accessibility.violationCount} violations found`);
225
+ }
226
+ if (metaAudit.issues.length > 0) {
227
+ this.log(` Meta/SEO: ${metaAudit.issues.length} issues found`);
228
+ }
229
+ if (performance.lcp > 0) {
230
+ this.log(` Performance: LCP ${Math.round(performance.lcp)}ms`);
231
+ }
232
+ }
233
+ /**
234
+ * Find the parent form selector for a field
235
+ */
236
+ async findFormSelector(page, fieldSelector) {
237
+ try {
238
+ return await page.evaluate((selector) => {
239
+ const field = document.querySelector(selector);
240
+ if (!field)
241
+ return null;
242
+ const form = field.closest('form');
243
+ if (!form)
244
+ return null;
245
+ // Try to build a unique selector
246
+ if (form.id)
247
+ return `form#${form.id}`;
248
+ if (form.className)
249
+ return `form.${form.className.split(' ')[0]}`;
250
+ return 'form';
251
+ }, fieldSelector);
252
+ }
253
+ catch {
254
+ return null;
255
+ }
256
+ }
257
+ /**
258
+ * Inject --email and --password into login form fields
259
+ */
260
+ injectCredentialsIfNeeded(step, plan) {
261
+ // Only inject if this is a fill action and we have credentials
262
+ if (step.action !== 'fill') {
263
+ return step;
264
+ }
265
+ // Check if this looks like a login workflow
266
+ const isLoginWorkflow = plan.workflowName.toLowerCase().includes('login') ||
267
+ plan.workflowName.toLowerCase().includes('sign in') ||
268
+ plan.description.toLowerCase().includes('authentication');
269
+ if (!isLoginWorkflow) {
270
+ return step;
271
+ }
272
+ // Inject email
273
+ if (this.options.email && this.isEmailField(step.selector)) {
274
+ return { ...step, value: this.options.email };
275
+ }
276
+ // Inject password
277
+ if (this.options.password && this.isPasswordField(step.selector)) {
278
+ return { ...step, value: this.options.password };
279
+ }
280
+ return step;
281
+ }
282
+ /**
283
+ * Check if selector looks like an email field
284
+ */
285
+ isEmailField(selector) {
286
+ const lower = selector.toLowerCase();
287
+ return lower.includes('email') || lower.includes('username') || lower.includes('user');
288
+ }
289
+ /**
290
+ * Check if selector looks like a password field
291
+ */
292
+ isPasswordField(selector) {
293
+ const lower = selector.toLowerCase();
294
+ return lower.includes('password') || lower.includes('pass');
295
+ }
296
+ /**
297
+ * Calculate total issues across all results
298
+ */
299
+ calculateTotalIssues(workflowResults, pageAudits, deadButtons, brokenForms) {
300
+ let total = 0;
301
+ // Failed workflow steps
302
+ total += workflowResults.reduce((sum, r) => sum + r.failedSteps, 0);
303
+ // Console errors
304
+ total += workflowResults.reduce((sum, r) => sum + r.errors.consoleErrors.length, 0);
305
+ // Network failures
306
+ total += workflowResults.reduce((sum, r) => sum + r.errors.networkFailures.length, 0);
307
+ // Broken images
308
+ total += workflowResults.reduce((sum, r) => sum + r.errors.brokenImages.length, 0);
309
+ // Dead buttons
310
+ total += deadButtons.filter(b => b.isDead).length;
311
+ // Broken forms
312
+ total += brokenForms.filter(f => f.isBroken).length;
313
+ // Note: broken links are added post-execution by engine.ts from discovery data
314
+ // Accessibility violations (only critical and serious)
315
+ total += pageAudits.reduce((sum, audit) => {
316
+ if (!audit.accessibility)
317
+ return sum;
318
+ return sum + audit.accessibility.violations.filter(v => v.impact === 'critical' || v.impact === 'serious').length;
319
+ }, 0);
320
+ return total;
321
+ }
322
+ /**
323
+ * Log message with optional progress callback
324
+ */
325
+ log(message) {
326
+ if (this.options.onProgress) {
327
+ this.options.onProgress(message);
328
+ }
329
+ }
330
+ }
331
+ //# sourceMappingURL=workflow-executor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflow-executor.js","sourceRoot":"","sources":["../../src/execution/workflow-executor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+ // Afterburn CLI entry point
3
+ import { program } from './cli/index.js';
4
+ program.parse();
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,4BAA4B;AAC5B,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAEzC,OAAO,CAAC,KAAK,EAAE,CAAC"}
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+ // Afterburn MCP server entry point
3
+ import { startServer } from './server.js';
4
+ startServer().catch(console.error);
5
+ //# sourceMappingURL=entry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entry.js","sourceRoot":"","sources":["../../src/mcp/entry.ts"],"names":[],"mappings":";AACA,mCAAmC;AACnC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,WAAW,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { createServer, startServer } from './server.js';
2
+ export { registerTools } from './tools.js';
@@ -0,0 +1,4 @@
1
+ // MCP module barrel export
2
+ export { createServer, startServer } from './server.js';
3
+ export { registerTools } from './tools.js';
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":"AAAA,2BAA2B;AAC3B,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function createServer(): McpServer;
3
+ export declare function startServer(): Promise<void>;
@@ -0,0 +1,19 @@
1
+ // MCP server initialization and transport setup
2
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
4
+ import { registerTools } from './tools.js';
5
+ export function createServer() {
6
+ const server = new McpServer({ name: 'afterburn-mcp', version: '1.0.0' }, {
7
+ capabilities: {
8
+ tools: {}
9
+ }
10
+ });
11
+ registerTools(server);
12
+ return server;
13
+ }
14
+ export async function startServer() {
15
+ const server = createServer();
16
+ const transport = new StdioServerTransport();
17
+ await server.connect(transport);
18
+ }
19
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"AAAA,gDAAgD;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE3C,MAAM,UAAU,YAAY;IAC1B,MAAM,MAAM,GAAG,IAAI,SAAS,CAC1B,EAAE,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,OAAO,EAAE,EAC3C;QACE,YAAY,EAAE;YACZ,KAAK,EAAE,EAAE;SACV;KACF,CACF,CAAC;IAEF,aAAa,CAAC,MAAM,CAAC,CAAC;IAEtB,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC;IAC9B,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;AAClC,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function registerTools(server: McpServer): void;
@@ -0,0 +1,162 @@
1
+ import { z } from 'zod';
2
+ import { runAfterburn } from '../core/engine.js';
3
+ import { validatePublicUrl, validatePath, validateMaxPages } from '../core/validation.js';
4
+ import { sanitizeForMarkdownInline, redactSensitiveData, redactSensitiveUrl } from '../utils/sanitizer.js';
5
+ export function registerTools(server) {
6
+ // Register scan_website tool
7
+ server.registerTool('scan_website', {
8
+ description: 'Scan a website for broken workflows, errors, accessibility issues, and UI/UX problems. Returns both structured JSON data and a markdown summary.',
9
+ inputSchema: z.object({
10
+ url: z.string().describe('The target website URL to scan (required)'),
11
+ source: z.string().optional().describe('Optional path to source code directory for source mapping'),
12
+ email: z.string().optional().describe('Optional email for login workflow testing'),
13
+ password: z.string().optional().describe('Optional password for login workflow testing'),
14
+ outputDir: z.string().optional().describe('Optional custom output directory for reports'),
15
+ maxPages: z.union([z.number(), z.string()]).optional().transform(val => {
16
+ if (val === undefined || val === null)
17
+ return undefined;
18
+ if (typeof val === 'string') {
19
+ const trimmed = val.trim();
20
+ if (!/^\d+$/.test(trimmed)) {
21
+ throw new Error(`Invalid maxPages value: "${val}". Must be a non-negative integer.`);
22
+ }
23
+ const parsed = Number(trimmed);
24
+ return parsed;
25
+ }
26
+ if (typeof val === 'number') {
27
+ if (isNaN(val) || val < 0 || !Number.isInteger(val)) {
28
+ throw new Error(`Invalid maxPages value: ${val}. Must be a non-negative integer.`);
29
+ }
30
+ return val;
31
+ }
32
+ return undefined;
33
+ }).describe('Optional maximum number of pages to crawl (default: 50)')
34
+ })
35
+ }, async (args, extra) => {
36
+ try {
37
+ // Security: validate all string inputs at the MCP boundary
38
+ const validatedUrl = await validatePublicUrl(args.url);
39
+ const validatedSource = args.source ? validatePath(args.source, 'source', process.cwd()) : undefined;
40
+ const validatedOutputDir = args.outputDir ? validatePath(args.outputDir, 'outputDir', process.cwd()) : undefined;
41
+ const validatedMaxPages = validateMaxPages(args.maxPages);
42
+ // Track progress if client supports it
43
+ const progressToken = extra._meta?.progressToken;
44
+ const sendProgress = async (stage, message) => {
45
+ if (progressToken && server.server) {
46
+ try {
47
+ await server.server.notification({
48
+ method: 'notifications/progress',
49
+ params: {
50
+ progressToken,
51
+ progress: 0, // MCP progress is 0-1, but we don't have precise percentages
52
+ total: 1,
53
+ message: `[${stage}] ${message}`
54
+ }
55
+ });
56
+ }
57
+ catch (err) {
58
+ // Progress notifications are best-effort, don't fail on errors
59
+ console.error('Failed to send progress notification:', err);
60
+ }
61
+ }
62
+ };
63
+ // Run Afterburn scan with validated inputs
64
+ const result = await runAfterburn({
65
+ targetUrl: validatedUrl,
66
+ sourcePath: validatedSource,
67
+ email: args.email,
68
+ password: args.password,
69
+ outputDir: validatedOutputDir,
70
+ maxPages: validatedMaxPages,
71
+ onProgress: async (stage, message) => {
72
+ await sendProgress(stage, message);
73
+ }
74
+ });
75
+ // Build structured JSON response
76
+ const structuredResult = {
77
+ healthScore: result.healthScore.overall,
78
+ healthLabel: result.healthScore.label,
79
+ totalIssues: result.totalIssues,
80
+ workflowsPassed: result.workflowsPassed,
81
+ workflowsTotal: result.workflowsTotal,
82
+ highPriorityIssues: result.highPriorityCount,
83
+ mediumPriorityIssues: result.mediumPriorityCount,
84
+ lowPriorityIssues: result.lowPriorityCount,
85
+ issues: result.prioritizedIssues.slice(0, 20).map(issue => ({
86
+ priority: issue.priority,
87
+ category: issue.category,
88
+ summary: redactSensitiveData(issue.summary),
89
+ fix: redactSensitiveData(issue.fixSuggestion),
90
+ location: redactSensitiveUrl(issue.location)
91
+ })),
92
+ reportPaths: {
93
+ html: result.htmlReportPath,
94
+ markdown: result.markdownReportPath
95
+ },
96
+ sessionId: result.sessionId
97
+ };
98
+ // Build markdown summary
99
+ const markdownSummary = buildMarkdownSummary(result);
100
+ // Return both JSON and markdown content blocks
101
+ return {
102
+ content: [
103
+ {
104
+ type: 'text',
105
+ text: JSON.stringify(structuredResult, null, 2)
106
+ },
107
+ {
108
+ type: 'text',
109
+ text: markdownSummary
110
+ }
111
+ ]
112
+ };
113
+ }
114
+ catch (error) {
115
+ // Return error as structured response - server stays responsive
116
+ const errorMessage = error instanceof Error ? error.message : String(error);
117
+ return {
118
+ content: [
119
+ {
120
+ type: 'text',
121
+ text: JSON.stringify({
122
+ isError: true,
123
+ error: errorMessage,
124
+ message: 'Scan failed. Check the error message for details.'
125
+ }, null, 2)
126
+ }
127
+ ],
128
+ isError: true
129
+ };
130
+ }
131
+ });
132
+ }
133
+ function buildMarkdownSummary(result) {
134
+ const lines = [];
135
+ lines.push('# Afterburn Scan Summary\n');
136
+ lines.push(`**Health Score:** ${result.healthScore.overall}/100 (${result.healthScore.label})\n`);
137
+ lines.push(`**Total Issues:** ${result.totalIssues}`);
138
+ lines.push(`**Workflows:** ${result.workflowsPassed}/${result.workflowsTotal} passed\n`);
139
+ if (result.totalIssues > 0) {
140
+ lines.push('## Top Issues\n');
141
+ const topIssues = result.prioritizedIssues.slice(0, 5);
142
+ topIssues.forEach((issue, idx) => {
143
+ lines.push(`### ${idx + 1}. [${issue.priority.toUpperCase()}] ${issue.category}`);
144
+ lines.push(`**Problem:** ${redactSensitiveData(sanitizeForMarkdownInline(issue.summary))}`);
145
+ lines.push(`**Fix:** ${redactSensitiveData(sanitizeForMarkdownInline(issue.fixSuggestion))}`);
146
+ lines.push(`**Location:** ${sanitizeForMarkdownInline(redactSensitiveUrl(issue.location))}\n`);
147
+ });
148
+ }
149
+ else {
150
+ lines.push('## No Issues Found\n');
151
+ lines.push('All workflows passed and no errors detected. Great job!\n');
152
+ }
153
+ if (result.htmlReportPath) {
154
+ lines.push(`## Reports\n`);
155
+ lines.push(`- **HTML Report:** ${result.htmlReportPath}`);
156
+ if (result.markdownReportPath) {
157
+ lines.push(`- **Markdown Report:** ${result.markdownReportPath}`);
158
+ }
159
+ }
160
+ return lines.join('\n');
161
+ }
162
+ //# sourceMappingURL=tools.js.map