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,64 @@
1
+ // Browser performance metrics capture via Performance API
2
+ /**
3
+ * Capture browser performance metrics from a Playwright page
4
+ *
5
+ * @param page - Playwright page to measure
6
+ * @returns Performance metrics including LCP, DOM load time, and total load time
7
+ */
8
+ export async function capturePerformanceMetrics(page) {
9
+ try {
10
+ const url = page.url();
11
+ // Wait for load state with timeout
12
+ await page.waitForLoadState('load', { timeout: 10000 });
13
+ // Capture performance metrics via browser Performance API
14
+ const metrics = await page.evaluate(() => {
15
+ return new Promise((resolve) => {
16
+ let lcpValue = 0;
17
+ // Capture LCP via PerformanceObserver with buffered entries
18
+ const lcpObserver = new PerformanceObserver((list) => {
19
+ const entries = list.getEntries();
20
+ const lastEntry = entries[entries.length - 1];
21
+ if (lastEntry && lastEntry.renderTime) {
22
+ lcpValue = lastEntry.renderTime;
23
+ }
24
+ else if (lastEntry && lastEntry.loadTime) {
25
+ lcpValue = lastEntry.loadTime;
26
+ }
27
+ });
28
+ try {
29
+ lcpObserver.observe({ type: 'largest-contentful-paint', buffered: true });
30
+ }
31
+ catch (e) {
32
+ // LCP not supported, will use 0
33
+ }
34
+ // Wait 3 seconds for LCP to settle, then capture navigation timing
35
+ setTimeout(() => {
36
+ lcpObserver.disconnect();
37
+ const navigation = performance.getEntriesByType('navigation')[0];
38
+ resolve({
39
+ lcp: lcpValue,
40
+ domContentLoaded: navigation?.domContentLoadedEventEnd || 0,
41
+ totalLoadTime: navigation?.loadEventEnd || 0,
42
+ });
43
+ }, 500);
44
+ });
45
+ });
46
+ return {
47
+ url,
48
+ lcp: metrics.lcp,
49
+ domContentLoaded: metrics.domContentLoaded,
50
+ totalLoadTime: metrics.totalLoadTime,
51
+ };
52
+ }
53
+ catch (error) {
54
+ console.error('Performance metrics capture failed:', error);
55
+ // Return safe defaults on error
56
+ return {
57
+ url: page.url(),
58
+ lcp: 0,
59
+ domContentLoaded: 0,
60
+ totalLoadTime: 0,
61
+ };
62
+ }
63
+ }
64
+ //# sourceMappingURL=performance-monitor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"performance-monitor.js","sourceRoot":"","sources":["../../src/testing/performance-monitor.ts"],"names":[],"mappings":"AAAA,0DAA0D;AAY1D;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAAC,IAAU;IACxD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAEvB,mCAAmC;QACnC,MAAM,IAAI,CAAC,gBAAgB,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;QAExD,0DAA0D;QAC1D,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE;YACvC,OAAO,IAAI,OAAO,CAIf,CAAC,OAAO,EAAE,EAAE;gBACb,IAAI,QAAQ,GAAG,CAAC,CAAC;gBAEjB,4DAA4D;gBAC5D,MAAM,WAAW,GAAG,IAAI,mBAAmB,CAAC,CAAC,IAAI,EAAE,EAAE;oBACnD,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;oBAClC,MAAM,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAQ,CAAC;oBACrD,IAAI,SAAS,IAAI,SAAS,CAAC,UAAU,EAAE,CAAC;wBACtC,QAAQ,GAAG,SAAS,CAAC,UAAU,CAAC;oBAClC,CAAC;yBAAM,IAAI,SAAS,IAAI,SAAS,CAAC,QAAQ,EAAE,CAAC;wBAC3C,QAAQ,GAAG,SAAS,CAAC,QAAQ,CAAC;oBAChC,CAAC;gBACH,CAAC,CAAC,CAAC;gBAEH,IAAI,CAAC;oBACH,WAAW,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,0BAA0B,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;gBAC5E,CAAC;gBAAC,OAAO,CAAC,EAAE,CAAC;oBACX,gCAAgC;gBAClC,CAAC;gBAED,mEAAmE;gBACnE,UAAU,CAAC,GAAG,EAAE;oBACd,WAAW,CAAC,UAAU,EAAE,CAAC;oBAEzB,MAAM,UAAU,GAAG,WAAW,CAAC,gBAAgB,CAAC,YAAY,CAAC,CAAC,CAAC,CAAgC,CAAC;oBAEhG,OAAO,CAAC;wBACN,GAAG,EAAE,QAAQ;wBACb,gBAAgB,EAAE,UAAU,EAAE,wBAAwB,IAAI,CAAC;wBAC3D,aAAa,EAAE,UAAU,EAAE,YAAY,IAAI,CAAC;qBAC7C,CAAC,CAAC;gBACL,CAAC,EAAE,GAAG,CAAC,CAAC;YACV,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,OAAO;YACL,GAAG;YACH,GAAG,EAAE,OAAO,CAAC,GAAG;YAChB,gBAAgB,EAAE,OAAO,CAAC,gBAAgB;YAC1C,aAAa,EAAE,OAAO,CAAC,aAAa;SACrC,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,qCAAqC,EAAE,KAAK,CAAC,CAAC;QAE5D,gCAAgC;QAChC,OAAO;YACL,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE;YACf,GAAG,EAAE,CAAC;YACN,gBAAgB,EAAE,CAAC;YACnB,aAAa,EAAE,CAAC;SACjB,CAAC;IACJ,CAAC;AACH,CAAC"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Base interface for all artifacts produced by pipeline stages
3
+ */
4
+ export interface ArtifactMetadata {
5
+ version: string;
6
+ stage: string;
7
+ timestamp: string;
8
+ sessionId: string;
9
+ }
10
+ /**
11
+ * Reference to a captured screenshot with dual-format storage
12
+ */
13
+ export interface ScreenshotRef {
14
+ id: string;
15
+ name: string;
16
+ pngPath: string;
17
+ webpPath: string;
18
+ width: number;
19
+ height: number;
20
+ sizes: {
21
+ png: number;
22
+ webp: number;
23
+ reduction: string;
24
+ };
25
+ capturedAt: string;
26
+ }
27
+ /**
28
+ * Cookie consent platform definition
29
+ */
30
+ export interface CookieBannerSelector {
31
+ name: string;
32
+ acceptButton: string;
33
+ rejectButton?: string;
34
+ modal?: string;
35
+ }
36
+ /**
37
+ * Configuration for a single Afterburn run
38
+ */
39
+ export interface SessionConfig {
40
+ sessionId: string;
41
+ targetUrl: string;
42
+ startedAt: string;
43
+ artifactDir: string;
44
+ screenshotDir: string;
45
+ }
46
+ /**
47
+ * Browser launch configuration
48
+ */
49
+ export interface BrowserConfig {
50
+ headless: boolean;
51
+ userAgent: string;
52
+ viewport: {
53
+ width: number;
54
+ height: number;
55
+ };
56
+ locale: string;
57
+ timezoneId: string;
58
+ }
@@ -0,0 +1,3 @@
1
+ // Shared type definitions for all pipeline stages and artifacts
2
+ export {};
3
+ //# sourceMappingURL=artifacts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"artifacts.js","sourceRoot":"","sources":["../../src/types/artifacts.ts"],"names":[],"mappings":"AAAA,gEAAgE"}
@@ -0,0 +1,124 @@
1
+ import type { ArtifactMetadata, ScreenshotRef } from './artifacts.js';
2
+ /**
3
+ * Individual form input/textarea/select field
4
+ */
5
+ export interface FormField {
6
+ type: string;
7
+ name: string;
8
+ label: string;
9
+ required: boolean;
10
+ placeholder: string;
11
+ }
12
+ /**
13
+ * Complete form with all its fields
14
+ */
15
+ export interface FormInfo {
16
+ action: string;
17
+ method: string;
18
+ selector: string;
19
+ fields: FormField[];
20
+ }
21
+ /**
22
+ * Any clickable/interactive element on a page
23
+ */
24
+ export interface InteractiveElement {
25
+ type: 'button' | 'link' | 'input' | 'select' | 'menu' | 'tab' | 'modal-trigger';
26
+ selector: string;
27
+ text: string;
28
+ visible: boolean;
29
+ attributes: Record<string, string>;
30
+ }
31
+ /**
32
+ * A link found on a page
33
+ */
34
+ export interface LinkInfo {
35
+ href: string;
36
+ text: string;
37
+ isInternal: boolean;
38
+ statusCode?: number;
39
+ }
40
+ /**
41
+ * Everything discovered about a single page
42
+ */
43
+ export interface PageData {
44
+ url: string;
45
+ title: string;
46
+ forms: FormInfo[];
47
+ buttons: InteractiveElement[];
48
+ links: LinkInfo[];
49
+ menus: InteractiveElement[];
50
+ otherInteractive: InteractiveElement[];
51
+ screenshotRef?: ScreenshotRef;
52
+ spaFramework?: SPAFramework;
53
+ crawledAt: string;
54
+ }
55
+ /**
56
+ * Detected SPA framework info
57
+ */
58
+ export interface SPAFramework {
59
+ framework: 'react' | 'vue' | 'angular' | 'next' | 'svelte' | 'nuxt' | 'none';
60
+ version?: string;
61
+ router?: string;
62
+ }
63
+ /**
64
+ * Hierarchical tree node for sitemap
65
+ */
66
+ export interface SitemapNode {
67
+ url: string;
68
+ title: string;
69
+ path: string;
70
+ children: SitemapNode[];
71
+ pageData: PageData;
72
+ depth: number;
73
+ }
74
+ /**
75
+ * A link that returned non-2xx status
76
+ */
77
+ export interface BrokenLink {
78
+ url: string;
79
+ sourceUrl: string;
80
+ statusCode: number;
81
+ statusText: string;
82
+ }
83
+ /**
84
+ * Single step in a workflow plan
85
+ */
86
+ export interface WorkflowStep {
87
+ action: 'navigate' | 'click' | 'fill' | 'select' | 'wait' | 'expect';
88
+ selector: string;
89
+ value?: string;
90
+ expectedResult: string;
91
+ confidence: number;
92
+ }
93
+ /**
94
+ * AI-generated test plan
95
+ */
96
+ export interface WorkflowPlan {
97
+ workflowName: string;
98
+ description: string;
99
+ steps: WorkflowStep[];
100
+ priority: 'critical' | 'important' | 'nice-to-have';
101
+ estimatedDuration: number;
102
+ source: 'auto-discovered' | 'user-hint';
103
+ }
104
+ /**
105
+ * Output of the crawler
106
+ */
107
+ export interface CrawlResult {
108
+ pages: PageData[];
109
+ brokenLinks: BrokenLink[];
110
+ totalPagesDiscovered: number;
111
+ totalLinksChecked: number;
112
+ crawlDuration: number;
113
+ spaDetected: SPAFramework;
114
+ }
115
+ /**
116
+ * Complete Phase 2 output artifact (extends ArtifactMetadata)
117
+ */
118
+ export interface DiscoveryArtifact extends ArtifactMetadata {
119
+ targetUrl: string;
120
+ sitemap: SitemapNode;
121
+ crawlResult: CrawlResult;
122
+ workflowPlans: WorkflowPlan[];
123
+ userHints: string[];
124
+ }
@@ -0,0 +1,3 @@
1
+ // Type definitions for Phase 2 discovery and planning modules
2
+ export {};
3
+ //# sourceMappingURL=discovery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discovery.js","sourceRoot":"","sources":["../../src/types/discovery.ts"],"names":[],"mappings":"AAAA,8DAA8D"}
@@ -0,0 +1,154 @@
1
+ import { ScreenshotRef } from './artifacts.js';
2
+ /**
3
+ * Collector for errors detected during workflow execution
4
+ */
5
+ export interface ErrorCollector {
6
+ consoleErrors: Array<{
7
+ message: string;
8
+ url: string;
9
+ timestamp: string;
10
+ }>;
11
+ networkFailures: Array<{
12
+ url: string;
13
+ status: number;
14
+ method: string;
15
+ resourceType: string;
16
+ }>;
17
+ brokenImages: Array<{
18
+ url: string;
19
+ selector: string;
20
+ status: number;
21
+ }>;
22
+ }
23
+ /**
24
+ * Evidence captured when a workflow step fails
25
+ */
26
+ export interface ErrorEvidence {
27
+ screenshotRef?: ScreenshotRef;
28
+ consoleErrors: string[];
29
+ networkFailures: Array<{
30
+ url: string;
31
+ status: number;
32
+ }>;
33
+ pageUrl: string;
34
+ timestamp: string;
35
+ }
36
+ /**
37
+ * Result of a single workflow step execution
38
+ */
39
+ export interface StepResult {
40
+ stepIndex: number;
41
+ action: string;
42
+ selector: string;
43
+ status: 'passed' | 'failed' | 'skipped';
44
+ duration: number;
45
+ error?: string;
46
+ evidence?: ErrorEvidence;
47
+ skippedFields?: Array<{
48
+ selector: string;
49
+ reason: string;
50
+ }>;
51
+ }
52
+ /**
53
+ * Result of dead button detection test
54
+ */
55
+ export interface DeadButtonResult {
56
+ isDead: boolean;
57
+ selector: string;
58
+ reason?: string;
59
+ }
60
+ /**
61
+ * Result of broken form detection test
62
+ */
63
+ export interface BrokenFormResult {
64
+ isBroken: boolean;
65
+ formSelector: string;
66
+ reason?: string;
67
+ filledFields: number;
68
+ skippedFields: number;
69
+ }
70
+ /**
71
+ * Performance metrics captured from browser APIs
72
+ */
73
+ export interface PerformanceMetrics {
74
+ lcp: number;
75
+ domContentLoaded: number;
76
+ totalLoadTime: number;
77
+ url: string;
78
+ }
79
+ /**
80
+ * Individual accessibility violation found by axe-core
81
+ */
82
+ export interface AccessibilityViolation {
83
+ id: string;
84
+ impact: 'critical' | 'serious' | 'moderate' | 'minor';
85
+ description: string;
86
+ nodes: number;
87
+ helpUrl: string;
88
+ }
89
+ /**
90
+ * Accessibility audit report for a single page
91
+ */
92
+ export interface AccessibilityReport {
93
+ url: string;
94
+ violationCount: number;
95
+ violations: AccessibilityViolation[];
96
+ passes: number;
97
+ incomplete: number;
98
+ }
99
+ /**
100
+ * Result of executing a complete workflow
101
+ */
102
+ export interface WorkflowExecutionResult {
103
+ workflowName: string;
104
+ description: string;
105
+ totalSteps: number;
106
+ passedSteps: number;
107
+ failedSteps: number;
108
+ skippedSteps: number;
109
+ stepResults: StepResult[];
110
+ errors: ErrorCollector;
111
+ overallStatus: 'passed' | 'failed';
112
+ duration: number;
113
+ pageScreenshotRef?: string;
114
+ }
115
+ /**
116
+ * A link discovered during crawl that returned non-2xx status
117
+ */
118
+ export interface BrokenLinkIssue {
119
+ url: string;
120
+ sourceUrl: string;
121
+ statusCode: number;
122
+ statusText: string;
123
+ }
124
+ /**
125
+ * Complete execution artifact containing all test results
126
+ */
127
+ /**
128
+ * Individual meta/SEO issue found by heuristic auditor
129
+ */
130
+ export interface MetaIssueResult {
131
+ id: string;
132
+ severity: 'high' | 'medium' | 'low';
133
+ description: string;
134
+ suggestion: string;
135
+ }
136
+ export interface ExecutionArtifact {
137
+ version: string;
138
+ stage: string;
139
+ timestamp: string;
140
+ sessionId: string;
141
+ targetUrl: string;
142
+ workflowResults: WorkflowExecutionResult[];
143
+ pageAudits: Array<{
144
+ url: string;
145
+ accessibility?: AccessibilityReport;
146
+ performance?: PerformanceMetrics;
147
+ metaIssues?: MetaIssueResult[];
148
+ }>;
149
+ deadButtons: DeadButtonResult[];
150
+ brokenForms: BrokenFormResult[];
151
+ brokenLinks: BrokenLinkIssue[];
152
+ totalIssues: number;
153
+ exitCode: number;
154
+ }
@@ -0,0 +1,3 @@
1
+ // Type definitions for workflow execution, error detection, and testing results
2
+ export {};
3
+ //# sourceMappingURL=execution.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"execution.js","sourceRoot":"","sources":["../../src/types/execution.ts"],"names":[],"mappings":"AAAA,gFAAgF"}
@@ -0,0 +1,2 @@
1
+ export * from './artifacts.js';
2
+ export * from './execution.js';
@@ -0,0 +1,4 @@
1
+ // Barrel export for all shared types
2
+ export * from './artifacts.js';
3
+ export * from './execution.js';
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,qCAAqC;AACrC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Redact clearly sensitive patterns from text while preserving useful error context.
3
+ * Conservative approach: only redact things that are obviously secrets.
4
+ */
5
+ export declare function redactSensitiveData(text: string): string;
6
+ /**
7
+ * Redact sensitive query parameters from URLs before they reach reports or LLM prompts.
8
+ * Falls back to general text redaction if the URL cannot be parsed.
9
+ */
10
+ export declare function redactSensitiveUrl(url: string): string;
11
+ /**
12
+ * Sanitize a string for safe inclusion in YAML values.
13
+ * Wraps in double quotes and escapes if value contains YAML special characters.
14
+ */
15
+ export declare function sanitizeForYaml(value: string): string;
16
+ /**
17
+ * Sanitize a string for safe inclusion in Markdown tables.
18
+ * Escapes pipe characters and removes newlines.
19
+ */
20
+ export declare function sanitizeForMarkdown(text: string): string;
21
+ /**
22
+ * Sanitize a string for safe inclusion in markdown inline content.
23
+ * Escapes pipes/backticks and replaces newlines.
24
+ */
25
+ export declare function sanitizeForMarkdownInline(text: string): string;
@@ -0,0 +1,98 @@
1
+ // Redacts sensitive data (API keys, tokens, passwords) from text before it reaches LLM prompts or PR comments
2
+ /**
3
+ * Redact clearly sensitive patterns from text while preserving useful error context.
4
+ * Conservative approach: only redact things that are obviously secrets.
5
+ */
6
+ export function redactSensitiveData(text) {
7
+ if (!text)
8
+ return text;
9
+ let redacted = text;
10
+ // API key prefixes (OpenAI, GitHub, AWS, Anthropic, Stripe, etc.)
11
+ redacted = redacted.replace(/\b(sk-[a-zA-Z0-9]{20,})/g, '[REDACTED_API_KEY]');
12
+ redacted = redacted.replace(/\b(ghp_[a-zA-Z0-9]{36,})/g, '[REDACTED_GITHUB_TOKEN]');
13
+ redacted = redacted.replace(/\b(ghu_[a-zA-Z0-9]{36,})/g, '[REDACTED_GITHUB_TOKEN]');
14
+ redacted = redacted.replace(/\b(gho_[a-zA-Z0-9]{36,})/g, '[REDACTED_GITHUB_TOKEN]');
15
+ redacted = redacted.replace(/\b(ghs_[a-zA-Z0-9]{36,})/g, '[REDACTED_GITHUB_TOKEN]');
16
+ redacted = redacted.replace(/\b(github_pat_[a-zA-Z0-9_]{22,})/g, '[REDACTED_GITHUB_TOKEN]');
17
+ redacted = redacted.replace(/\b(AKIA[0-9A-Z]{16})/g, '[REDACTED_AWS_KEY]');
18
+ redacted = redacted.replace(/\b(sk-ant-[a-zA-Z0-9-]{20,})/g, '[REDACTED_API_KEY]');
19
+ redacted = redacted.replace(/\b(sk_live_[a-zA-Z0-9]{20,})/g, '[REDACTED_STRIPE_KEY]');
20
+ redacted = redacted.replace(/\b(sk_test_[a-zA-Z0-9]{20,})/g, '[REDACTED_STRIPE_KEY]');
21
+ redacted = redacted.replace(/\b(rk_live_[a-zA-Z0-9]{20,})/g, '[REDACTED_STRIPE_KEY]');
22
+ redacted = redacted.replace(/\b(rk_test_[a-zA-Z0-9]{20,})/g, '[REDACTED_STRIPE_KEY]');
23
+ // Bearer tokens in headers
24
+ redacted = redacted.replace(/(Bearer\s+)[a-zA-Z0-9._\-]{20,}/gi, '$1[REDACTED_TOKEN]');
25
+ // Authorization headers with token values
26
+ redacted = redacted.replace(/(Authorization:\s*)[^\s\n]{20,}/gi, '$1[REDACTED_TOKEN]');
27
+ // password=... or passwd=... or secret=... in query strings or config
28
+ redacted = redacted.replace(/((?:password|passwd|secret|token|apikey|api_key|access_token|auth_token)\s*[=:]\s*)("[^"]*"|'[^']*'|\S{8,})/gi, '$1[REDACTED]');
29
+ // Long hex strings (40+ chars, like SHA tokens or secret keys)
30
+ redacted = redacted.replace(/\b[0-9a-f]{40,}\b/gi, '[REDACTED_HEX_TOKEN]');
31
+ // Long base64-looking strings (32+ chars of alphanumeric with +/=)
32
+ // Only match standalone tokens, not error message prose
33
+ redacted = redacted.replace(/\b[A-Za-z0-9+/]{32,}={0,2}\b/g, (match) => {
34
+ // Only redact if it looks like a real token (has mixed case + digits, not just a word)
35
+ const hasUpper = /[A-Z]/.test(match);
36
+ const hasLower = /[a-z]/.test(match);
37
+ const hasDigit = /[0-9]/.test(match);
38
+ if (hasUpper && hasLower && hasDigit) {
39
+ return '[REDACTED_BASE64_TOKEN]';
40
+ }
41
+ return match;
42
+ });
43
+ return redacted;
44
+ }
45
+ /**
46
+ * Redact sensitive query parameters from URLs before they reach reports or LLM prompts.
47
+ * Falls back to general text redaction if the URL cannot be parsed.
48
+ */
49
+ export function redactSensitiveUrl(url) {
50
+ if (!url)
51
+ return url;
52
+ try {
53
+ const parsed = new URL(url);
54
+ const sensitiveParams = ['token', 'key', 'apikey', 'api_key', 'secret', 'password', 'passwd', 'access_token', 'auth_token', 'session', 'jwt'];
55
+ for (const param of sensitiveParams) {
56
+ if (parsed.searchParams.has(param)) {
57
+ parsed.searchParams.set(param, '[REDACTED]');
58
+ }
59
+ }
60
+ return parsed.toString();
61
+ }
62
+ catch {
63
+ return redactSensitiveData(url);
64
+ }
65
+ }
66
+ /**
67
+ * Sanitize a string for safe inclusion in YAML values.
68
+ * Wraps in double quotes and escapes if value contains YAML special characters.
69
+ */
70
+ export function sanitizeForYaml(value) {
71
+ if (!value)
72
+ return '""';
73
+ // If value contains YAML special chars, wrap in double quotes and escape internal quotes
74
+ if (/[:{}\[\]#&*!|>'"% @`\n]/.test(value)) {
75
+ return '"' + value.replace(/\\/g, '\\\\').replace(/"/g, '\\"') + '"';
76
+ }
77
+ return value;
78
+ }
79
+ /**
80
+ * Sanitize a string for safe inclusion in Markdown tables.
81
+ * Escapes pipe characters and removes newlines.
82
+ */
83
+ export function sanitizeForMarkdown(text) {
84
+ return sanitizeForMarkdownInline(text);
85
+ }
86
+ /**
87
+ * Sanitize a string for safe inclusion in markdown inline content.
88
+ * Escapes pipes/backticks and replaces newlines.
89
+ */
90
+ export function sanitizeForMarkdownInline(text) {
91
+ if (!text)
92
+ return '';
93
+ return text
94
+ .replace(/\|/g, '\\|')
95
+ .replace(/`/g, '\\`')
96
+ .replace(/\r?\n/g, ' ');
97
+ }
98
+ //# sourceMappingURL=sanitizer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sanitizer.js","sourceRoot":"","sources":["../../src/utils/sanitizer.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,86 @@
1
+ {
2
+ "name": "afterburn-cli",
3
+ "version": "1.0.0",
4
+ "description": "Automated testing for vibe-coded websites. One command finds broken forms, dead buttons, JS crashes, and more.",
5
+ "main": "dist/index.js",
6
+ "type": "module",
7
+ "engines": {
8
+ "node": ">=18"
9
+ },
10
+ "homepage": "https://github.com/gods-strongest-vibecoder/afterburn#readme",
11
+ "scripts": {
12
+ "build": "tsc",
13
+ "build:action": "tsc -p action/tsconfig.json",
14
+ "bundle:action": "ncc build action/index.js -o action/dist --license licenses.txt",
15
+ "build:release": "npm run build && npm run build:action && npm run bundle:action",
16
+ "dev": "tsx src/index.ts",
17
+ "start": "node dist/index.js",
18
+ "test": "npm run test:unit",
19
+ "test:unit": "vitest run --config vitest.config.unit.ts",
20
+ "pretest:e2e": "npm run build",
21
+ "test:e2e": "vitest run --config vitest.config.e2e.ts",
22
+ "test:smoke:external": "vitest run --config vitest.config.e2e.ts tests/e2e/external-smoke.test.ts",
23
+ "test:coverage": "vitest run --config vitest.config.unit.ts --coverage",
24
+ "test:watch": "vitest --config vitest.config.unit.ts"
25
+ },
26
+ "bin": {
27
+ "afterburn": "dist/index.js",
28
+ "afterburn-cli": "dist/index.js",
29
+ "afterburn-mcp": "dist/mcp/entry.js"
30
+ },
31
+ "files": [
32
+ "dist",
33
+ "templates"
34
+ ],
35
+ "keywords": [
36
+ "testing",
37
+ "automation",
38
+ "playwright",
39
+ "website-testing",
40
+ "accessibility",
41
+ "vibe-coding",
42
+ "cli-tool",
43
+ "developer-tools",
44
+ "bug-detection",
45
+ "qa-automation",
46
+ "mcp",
47
+ "ai-tools",
48
+ "web-development"
49
+ ],
50
+ "author": "Afterburn",
51
+ "repository": {
52
+ "type": "git",
53
+ "url": "https://github.com/gods-strongest-vibecoder/afterburn"
54
+ },
55
+ "license": "MIT",
56
+ "dependencies": {
57
+ "@axe-core/playwright": "^4.11.1",
58
+ "@google/generative-ai": "^0.24.1",
59
+ "@modelcontextprotocol/sdk": "^1.26.0",
60
+ "chalk": "^5.6.2",
61
+ "commander": "^14.0.3",
62
+ "fs-extra": "^11.3.3",
63
+ "handlebars": "^4.7.8",
64
+ "marked": "^17.0.1",
65
+ "ora": "^9.3.0",
66
+ "playwright": "^1.58.2",
67
+ "playwright-extra": "4.3.6",
68
+ "puppeteer-extra-plugin-stealth": "2.11.2",
69
+ "sharp": "^0.34.5",
70
+ "ts-morph": "^27.0.2",
71
+ "zod": "^4.3.6",
72
+ "zod-to-json-schema": "^3.25.1"
73
+ },
74
+ "devDependencies": {
75
+ "@actions/artifact": "^6.1.0",
76
+ "@actions/core": "^3.0.0",
77
+ "@actions/github": "^9.0.0",
78
+ "@types/fs-extra": "^11.0.4",
79
+ "@types/node": "^25.2.1",
80
+ "@vercel/ncc": "^0.38.4",
81
+ "@vitest/coverage-v8": "^4.0.18",
82
+ "tsx": "^4.21.0",
83
+ "typescript": "^5.9.3",
84
+ "vitest": "^4.0.18"
85
+ }
86
+ }