@avi770/testteam 1.2.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 (325) hide show
  1. package/CHANGELOG.md +54 -0
  2. package/LICENSE +21 -0
  3. package/README.md +167 -0
  4. package/agents/01-analyst.ts +100 -0
  5. package/agents/02-seed-architect.ts +59 -0
  6. package/agents/03-test-generator.ts +191 -0
  7. package/agents/04-unit-runner.ts +160 -0
  8. package/agents/05-browser-crawler.ts +790 -0
  9. package/agents/06-api-exerciser.ts +311 -0
  10. package/agents/07-security-scout.ts +188 -0
  11. package/agents/08-a11y-guardian.ts +212 -0
  12. package/agents/09-healer.ts +228 -0
  13. package/agents/10-reporter.ts +266 -0
  14. package/agents/11-fixer.ts +253 -0
  15. package/agents/12-ux-inspector.ts +444 -0
  16. package/agents/13-performance-profiler.ts +271 -0
  17. package/agents/14-data-integrity-auditor.ts +417 -0
  18. package/agents/15-regression-sentinel.ts +307 -0
  19. package/agents/16-chaos-agent.ts +228 -0
  20. package/agents/17-documentation-validator.ts +266 -0
  21. package/agents/18-integration-watchdog.ts +178 -0
  22. package/agents/19-tenant-isolation-auditor.ts +199 -0
  23. package/agents/20-workflow-completion-tester.ts +203 -0
  24. package/agents/21-state-session-tester.ts +262 -0
  25. package/agents/22-email-notification-verifier.ts +244 -0
  26. package/agents/23-migration-tester.ts +80 -0
  27. package/agents/__tests__/01-analyst.test.ts +188 -0
  28. package/agents/__tests__/02-seed-architect.test.ts +152 -0
  29. package/agents/__tests__/03-test-generator-full.test.ts +321 -0
  30. package/agents/__tests__/03-test-generator.test.ts +318 -0
  31. package/agents/__tests__/04-unit-runner.test.ts +320 -0
  32. package/agents/__tests__/05-browser-crawler-beta.test.ts +492 -0
  33. package/agents/__tests__/05-browser-crawler-release.test.ts +412 -0
  34. package/agents/__tests__/05-browser-crawler-uat.test.ts +578 -0
  35. package/agents/__tests__/05-browser-crawler.test.ts +518 -0
  36. package/agents/__tests__/06-api-exerciser.test.ts +619 -0
  37. package/agents/__tests__/07-security-scout.test.ts +382 -0
  38. package/agents/__tests__/08-a11y-guardian.test.ts +530 -0
  39. package/agents/__tests__/09-healer.test.ts +384 -0
  40. package/agents/__tests__/10-reporter.test.ts +366 -0
  41. package/agents/__tests__/11-fixer.test.ts +406 -0
  42. package/agents/__tests__/12-ux-inspector-extended.test.ts +465 -0
  43. package/agents/__tests__/12-ux-inspector.test.ts +443 -0
  44. package/agents/__tests__/13-performance-profiler.test.ts +411 -0
  45. package/agents/__tests__/14-data-integrity-auditor-extended.test.ts +573 -0
  46. package/agents/__tests__/14-data-integrity-auditor.test.ts +407 -0
  47. package/agents/__tests__/15-regression-sentinel.test.ts +657 -0
  48. package/agents/__tests__/16-chaos-agent.test.ts +427 -0
  49. package/agents/__tests__/17-documentation-validator.test.ts +402 -0
  50. package/agents/__tests__/18-integration-watchdog.test.ts +263 -0
  51. package/agents/__tests__/19-tenant-isolation-auditor.test.ts +400 -0
  52. package/agents/__tests__/20-workflow-completion-tester.test.ts +586 -0
  53. package/agents/__tests__/21-state-session-tester.test.ts +374 -0
  54. package/agents/__tests__/22-email-notification-verifier.test.ts +441 -0
  55. package/agents/__tests__/23-migration-tester.test.ts +145 -0
  56. package/agents/__tests__/base-agent.test.ts +188 -0
  57. package/agents/__tests__/registry.test.ts +218 -0
  58. package/agents/base-agent.ts +77 -0
  59. package/agents/registry.ts +136 -0
  60. package/baselines/api-schemas/.gitkeep +0 -0
  61. package/baselines/performance/.gitkeep +0 -0
  62. package/baselines/screenshots/.gitkeep +0 -0
  63. package/bin/testteam.js +10 -0
  64. package/core/__tests__/ci-output.test.ts +430 -0
  65. package/core/__tests__/cli.test.ts +387 -0
  66. package/core/__tests__/config.test.ts +78 -0
  67. package/core/__tests__/cost-tracker.test.ts +158 -0
  68. package/core/__tests__/evidence.test.ts +265 -0
  69. package/core/__tests__/fix-loop.test.ts +210 -0
  70. package/core/__tests__/health-check.test.ts +44 -0
  71. package/core/__tests__/init.test.ts +609 -0
  72. package/core/__tests__/integration.test.ts +204 -0
  73. package/core/__tests__/license-gen.test.ts +227 -0
  74. package/core/__tests__/license.test.ts +326 -0
  75. package/core/__tests__/multi-browser.test.ts +278 -0
  76. package/core/__tests__/orchestrator.test.ts +519 -0
  77. package/core/__tests__/phase-gate.test.ts +43 -0
  78. package/core/__tests__/report-html.test.ts +398 -0
  79. package/core/__tests__/report-upload.test.ts +325 -0
  80. package/core/__tests__/run-counter.test.ts +234 -0
  81. package/core/ci-output.ts +240 -0
  82. package/core/cli.ts +232 -0
  83. package/core/config.ts +178 -0
  84. package/core/cost-tracker.ts +59 -0
  85. package/core/evidence.ts +132 -0
  86. package/core/fix-loop.ts +85 -0
  87. package/core/health-check.ts +54 -0
  88. package/core/init.ts +546 -0
  89. package/core/license-gen.ts +212 -0
  90. package/core/license.ts +211 -0
  91. package/core/messages.ts +67 -0
  92. package/core/multi-browser.ts +136 -0
  93. package/core/orchestrator.ts +354 -0
  94. package/core/phase-gate.ts +55 -0
  95. package/core/report-html.ts +657 -0
  96. package/core/report-upload.ts +188 -0
  97. package/core/run-counter.ts +175 -0
  98. package/core/types.ts +57 -0
  99. package/dist/agents/01-analyst.d.ts +11 -0
  100. package/dist/agents/01-analyst.d.ts.map +1 -0
  101. package/dist/agents/01-analyst.js +75 -0
  102. package/dist/agents/01-analyst.js.map +1 -0
  103. package/dist/agents/02-seed-architect.d.ts +11 -0
  104. package/dist/agents/02-seed-architect.d.ts.map +1 -0
  105. package/dist/agents/02-seed-architect.js +51 -0
  106. package/dist/agents/02-seed-architect.js.map +1 -0
  107. package/dist/agents/03-test-generator.d.ts +9 -0
  108. package/dist/agents/03-test-generator.d.ts.map +1 -0
  109. package/dist/agents/03-test-generator.js +167 -0
  110. package/dist/agents/03-test-generator.js.map +1 -0
  111. package/dist/agents/04-unit-runner.d.ts +9 -0
  112. package/dist/agents/04-unit-runner.d.ts.map +1 -0
  113. package/dist/agents/04-unit-runner.js +113 -0
  114. package/dist/agents/04-unit-runner.js.map +1 -0
  115. package/dist/agents/05-browser-crawler.d.ts +30 -0
  116. package/dist/agents/05-browser-crawler.d.ts.map +1 -0
  117. package/dist/agents/05-browser-crawler.js +685 -0
  118. package/dist/agents/05-browser-crawler.js.map +1 -0
  119. package/dist/agents/06-api-exerciser.d.ts +23 -0
  120. package/dist/agents/06-api-exerciser.d.ts.map +1 -0
  121. package/dist/agents/06-api-exerciser.js +253 -0
  122. package/dist/agents/06-api-exerciser.js.map +1 -0
  123. package/dist/agents/07-security-scout.d.ts +11 -0
  124. package/dist/agents/07-security-scout.d.ts.map +1 -0
  125. package/dist/agents/07-security-scout.js +142 -0
  126. package/dist/agents/07-security-scout.js.map +1 -0
  127. package/dist/agents/08-a11y-guardian.d.ts +13 -0
  128. package/dist/agents/08-a11y-guardian.d.ts.map +1 -0
  129. package/dist/agents/08-a11y-guardian.js +176 -0
  130. package/dist/agents/08-a11y-guardian.js.map +1 -0
  131. package/dist/agents/09-healer.d.ts +33 -0
  132. package/dist/agents/09-healer.d.ts.map +1 -0
  133. package/dist/agents/09-healer.js +167 -0
  134. package/dist/agents/09-healer.js.map +1 -0
  135. package/dist/agents/10-reporter.d.ts +26 -0
  136. package/dist/agents/10-reporter.d.ts.map +1 -0
  137. package/dist/agents/10-reporter.js +215 -0
  138. package/dist/agents/10-reporter.js.map +1 -0
  139. package/dist/agents/11-fixer.d.ts +26 -0
  140. package/dist/agents/11-fixer.d.ts.map +1 -0
  141. package/dist/agents/11-fixer.js +195 -0
  142. package/dist/agents/11-fixer.js.map +1 -0
  143. package/dist/agents/12-ux-inspector.d.ts +15 -0
  144. package/dist/agents/12-ux-inspector.d.ts.map +1 -0
  145. package/dist/agents/12-ux-inspector.js +364 -0
  146. package/dist/agents/12-ux-inspector.js.map +1 -0
  147. package/dist/agents/13-performance-profiler.d.ts +13 -0
  148. package/dist/agents/13-performance-profiler.d.ts.map +1 -0
  149. package/dist/agents/13-performance-profiler.js +216 -0
  150. package/dist/agents/13-performance-profiler.js.map +1 -0
  151. package/dist/agents/14-data-integrity-auditor.d.ts +12 -0
  152. package/dist/agents/14-data-integrity-auditor.d.ts.map +1 -0
  153. package/dist/agents/14-data-integrity-auditor.js +356 -0
  154. package/dist/agents/14-data-integrity-auditor.js.map +1 -0
  155. package/dist/agents/15-regression-sentinel.d.ts +25 -0
  156. package/dist/agents/15-regression-sentinel.d.ts.map +1 -0
  157. package/dist/agents/15-regression-sentinel.js +251 -0
  158. package/dist/agents/15-regression-sentinel.js.map +1 -0
  159. package/dist/agents/16-chaos-agent.d.ts +9 -0
  160. package/dist/agents/16-chaos-agent.d.ts.map +1 -0
  161. package/dist/agents/16-chaos-agent.js +207 -0
  162. package/dist/agents/16-chaos-agent.js.map +1 -0
  163. package/dist/agents/17-documentation-validator.d.ts +31 -0
  164. package/dist/agents/17-documentation-validator.d.ts.map +1 -0
  165. package/dist/agents/17-documentation-validator.js +246 -0
  166. package/dist/agents/17-documentation-validator.js.map +1 -0
  167. package/dist/agents/18-integration-watchdog.d.ts +10 -0
  168. package/dist/agents/18-integration-watchdog.d.ts.map +1 -0
  169. package/dist/agents/18-integration-watchdog.js +138 -0
  170. package/dist/agents/18-integration-watchdog.js.map +1 -0
  171. package/dist/agents/19-tenant-isolation-auditor.d.ts +9 -0
  172. package/dist/agents/19-tenant-isolation-auditor.d.ts.map +1 -0
  173. package/dist/agents/19-tenant-isolation-auditor.js +166 -0
  174. package/dist/agents/19-tenant-isolation-auditor.js.map +1 -0
  175. package/dist/agents/20-workflow-completion-tester.d.ts +12 -0
  176. package/dist/agents/20-workflow-completion-tester.d.ts.map +1 -0
  177. package/dist/agents/20-workflow-completion-tester.js +159 -0
  178. package/dist/agents/20-workflow-completion-tester.js.map +1 -0
  179. package/dist/agents/21-state-session-tester.d.ts +10 -0
  180. package/dist/agents/21-state-session-tester.d.ts.map +1 -0
  181. package/dist/agents/21-state-session-tester.js +233 -0
  182. package/dist/agents/21-state-session-tester.js.map +1 -0
  183. package/dist/agents/22-email-notification-verifier.d.ts +11 -0
  184. package/dist/agents/22-email-notification-verifier.d.ts.map +1 -0
  185. package/dist/agents/22-email-notification-verifier.js +199 -0
  186. package/dist/agents/22-email-notification-verifier.js.map +1 -0
  187. package/dist/agents/23-migration-tester.d.ts +10 -0
  188. package/dist/agents/23-migration-tester.d.ts.map +1 -0
  189. package/dist/agents/23-migration-tester.js +74 -0
  190. package/dist/agents/23-migration-tester.js.map +1 -0
  191. package/dist/agents/base-agent.d.ts +19 -0
  192. package/dist/agents/base-agent.d.ts.map +1 -0
  193. package/dist/agents/base-agent.js +67 -0
  194. package/dist/agents/base-agent.js.map +1 -0
  195. package/dist/agents/registry.d.ts +29 -0
  196. package/dist/agents/registry.d.ts.map +1 -0
  197. package/dist/agents/registry.js +117 -0
  198. package/dist/agents/registry.js.map +1 -0
  199. package/dist/core/ci-output.d.ts +35 -0
  200. package/dist/core/ci-output.d.ts.map +1 -0
  201. package/dist/core/ci-output.js +193 -0
  202. package/dist/core/ci-output.js.map +1 -0
  203. package/dist/core/cli.d.ts +11 -0
  204. package/dist/core/cli.d.ts.map +1 -0
  205. package/dist/core/cli.js +197 -0
  206. package/dist/core/cli.js.map +1 -0
  207. package/dist/core/config.d.ts +111 -0
  208. package/dist/core/config.d.ts.map +1 -0
  209. package/dist/core/config.js +42 -0
  210. package/dist/core/config.js.map +1 -0
  211. package/dist/core/cost-tracker.d.ts +22 -0
  212. package/dist/core/cost-tracker.d.ts.map +1 -0
  213. package/dist/core/cost-tracker.js +41 -0
  214. package/dist/core/cost-tracker.js.map +1 -0
  215. package/dist/core/evidence.d.ts +28 -0
  216. package/dist/core/evidence.d.ts.map +1 -0
  217. package/dist/core/evidence.js +95 -0
  218. package/dist/core/evidence.js.map +1 -0
  219. package/dist/core/fix-loop.d.ts +29 -0
  220. package/dist/core/fix-loop.d.ts.map +1 -0
  221. package/dist/core/fix-loop.js +70 -0
  222. package/dist/core/fix-loop.js.map +1 -0
  223. package/dist/core/health-check.d.ts +21 -0
  224. package/dist/core/health-check.d.ts.map +1 -0
  225. package/dist/core/health-check.js +26 -0
  226. package/dist/core/health-check.js.map +1 -0
  227. package/dist/core/init.d.ts +2 -0
  228. package/dist/core/init.d.ts.map +1 -0
  229. package/dist/core/init.js +435 -0
  230. package/dist/core/init.js.map +1 -0
  231. package/dist/core/license-gen.d.ts +12 -0
  232. package/dist/core/license-gen.d.ts.map +1 -0
  233. package/dist/core/license-gen.js +169 -0
  234. package/dist/core/license-gen.js.map +1 -0
  235. package/dist/core/license.d.ts +33 -0
  236. package/dist/core/license.d.ts.map +1 -0
  237. package/dist/core/license.js +170 -0
  238. package/dist/core/license.js.map +1 -0
  239. package/dist/core/messages.d.ts +10 -0
  240. package/dist/core/messages.d.ts.map +1 -0
  241. package/dist/core/messages.js +47 -0
  242. package/dist/core/messages.js.map +1 -0
  243. package/dist/core/multi-browser.d.ts +36 -0
  244. package/dist/core/multi-browser.d.ts.map +1 -0
  245. package/dist/core/multi-browser.js +88 -0
  246. package/dist/core/multi-browser.js.map +1 -0
  247. package/dist/core/orchestrator.d.ts +48 -0
  248. package/dist/core/orchestrator.d.ts.map +1 -0
  249. package/dist/core/orchestrator.js +291 -0
  250. package/dist/core/orchestrator.js.map +1 -0
  251. package/dist/core/phase-gate.d.ts +4 -0
  252. package/dist/core/phase-gate.d.ts.map +1 -0
  253. package/dist/core/phase-gate.js +39 -0
  254. package/dist/core/phase-gate.js.map +1 -0
  255. package/dist/core/report-html.d.ts +9 -0
  256. package/dist/core/report-html.d.ts.map +1 -0
  257. package/dist/core/report-html.js +617 -0
  258. package/dist/core/report-html.js.map +1 -0
  259. package/dist/core/report-upload.d.ts +16 -0
  260. package/dist/core/report-upload.d.ts.map +1 -0
  261. package/dist/core/report-upload.js +124 -0
  262. package/dist/core/report-upload.js.map +1 -0
  263. package/dist/core/run-counter.d.ts +40 -0
  264. package/dist/core/run-counter.d.ts.map +1 -0
  265. package/dist/core/run-counter.js +120 -0
  266. package/dist/core/run-counter.js.map +1 -0
  267. package/dist/core/types.d.ts +53 -0
  268. package/dist/core/types.d.ts.map +1 -0
  269. package/dist/core/types.js +2 -0
  270. package/dist/core/types.js.map +1 -0
  271. package/dist/helpers/api-client.d.ts +30 -0
  272. package/dist/helpers/api-client.d.ts.map +1 -0
  273. package/dist/helpers/api-client.js +77 -0
  274. package/dist/helpers/api-client.js.map +1 -0
  275. package/dist/helpers/element-discovery.d.ts +18 -0
  276. package/dist/helpers/element-discovery.d.ts.map +1 -0
  277. package/dist/helpers/element-discovery.js +82 -0
  278. package/dist/helpers/element-discovery.js.map +1 -0
  279. package/dist/helpers/env-resolver.d.ts +29 -0
  280. package/dist/helpers/env-resolver.d.ts.map +1 -0
  281. package/dist/helpers/env-resolver.js +51 -0
  282. package/dist/helpers/env-resolver.js.map +1 -0
  283. package/dist/helpers/form-filler.d.ts +13 -0
  284. package/dist/helpers/form-filler.d.ts.map +1 -0
  285. package/dist/helpers/form-filler.js +98 -0
  286. package/dist/helpers/form-filler.js.map +1 -0
  287. package/dist/helpers/modal-handler.d.ts +16 -0
  288. package/dist/helpers/modal-handler.d.ts.map +1 -0
  289. package/dist/helpers/modal-handler.js +95 -0
  290. package/dist/helpers/modal-handler.js.map +1 -0
  291. package/dist/helpers/navigation.d.ts +37 -0
  292. package/dist/helpers/navigation.d.ts.map +1 -0
  293. package/dist/helpers/navigation.js +83 -0
  294. package/dist/helpers/navigation.js.map +1 -0
  295. package/dist/helpers/quality-gate.d.ts +17 -0
  296. package/dist/helpers/quality-gate.d.ts.map +1 -0
  297. package/dist/helpers/quality-gate.js +144 -0
  298. package/dist/helpers/quality-gate.js.map +1 -0
  299. package/dist/helpers/screenshot.d.ts +24 -0
  300. package/dist/helpers/screenshot.d.ts.map +1 -0
  301. package/dist/helpers/screenshot.js +76 -0
  302. package/dist/helpers/screenshot.js.map +1 -0
  303. package/dist/helpers/seed-validator.d.ts +15 -0
  304. package/dist/helpers/seed-validator.d.ts.map +1 -0
  305. package/dist/helpers/seed-validator.js +53 -0
  306. package/dist/helpers/seed-validator.js.map +1 -0
  307. package/helpers/__tests__/api-client.test.ts +199 -0
  308. package/helpers/__tests__/element-discovery.test.ts +202 -0
  309. package/helpers/__tests__/form-filler-extended.test.ts +212 -0
  310. package/helpers/__tests__/form-filler.test.ts +99 -0
  311. package/helpers/__tests__/modal-handler.test.ts +152 -0
  312. package/helpers/__tests__/navigation.test.ts +214 -0
  313. package/helpers/__tests__/quality-gate.test.ts +117 -0
  314. package/helpers/__tests__/screenshot.test.ts +139 -0
  315. package/helpers/__tests__/seed-validator.test.ts +114 -0
  316. package/helpers/api-client.ts +111 -0
  317. package/helpers/element-discovery.ts +105 -0
  318. package/helpers/env-resolver.ts +69 -0
  319. package/helpers/form-filler.ts +126 -0
  320. package/helpers/modal-handler.ts +108 -0
  321. package/helpers/navigation.ts +100 -0
  322. package/helpers/quality-gate.ts +180 -0
  323. package/helpers/screenshot.ts +111 -0
  324. package/helpers/seed-validator.ts +70 -0
  325. package/package.json +88 -0
@@ -0,0 +1,176 @@
1
+ import { execFile } from 'child_process';
2
+ import { BaseAgent } from './base-agent';
3
+ import { login, navigateToSection, waitForSectionLoad } from '../helpers/navigation';
4
+ import { captureScreenshot } from '../helpers/screenshot';
5
+ import { resolveEnvironment } from '../helpers/env-resolver';
6
+ function execFilePromise(file, args) {
7
+ return new Promise((resolve, reject) => {
8
+ execFile(file, args, { shell: true }, (error, stdout, stderr) => {
9
+ if (error) {
10
+ reject(error);
11
+ return;
12
+ }
13
+ resolve({ stdout: stdout ?? '', stderr: stderr ?? '' });
14
+ });
15
+ });
16
+ }
17
+ /** Map axe-core impact values to FindingSeverity. */
18
+ export function mapAxeImpact(impact) {
19
+ switch ((impact ?? '').toLowerCase()) {
20
+ case 'critical': return 'critical';
21
+ case 'serious': return 'high';
22
+ case 'moderate': return 'medium';
23
+ case 'minor': return 'low';
24
+ default: return 'low';
25
+ }
26
+ }
27
+ export class A11yGuardianAgent extends BaseAgent {
28
+ agentId = 8;
29
+ agentName = 'A11y Guardian';
30
+ async preFlight() {
31
+ await execFilePromise('npx', ['playwright', '--version']);
32
+ }
33
+ async execute() {
34
+ const findings = [];
35
+ const { env } = await resolveEnvironment(this.config, this.phase);
36
+ if (!env) {
37
+ findings.push({
38
+ id: `${this.agentId}-no-env`,
39
+ type: 'infra-issue',
40
+ severity: 'critical',
41
+ agentId: this.agentId,
42
+ module: 'a11y-guardian',
43
+ description: 'No environment configured — cannot perform accessibility scan',
44
+ });
45
+ return findings;
46
+ }
47
+ const rawLoginUrl = this.config.auth.loginUrl ?? '/login';
48
+ const loginUrl = rawLoginUrl.startsWith('http') ? rawLoginUrl : `${env.baseUrl}${rawLoginUrl}`;
49
+ const credentials = this.config.auth.credentials?.['admin'] ??
50
+ Object.values(this.config.auth.credentials ?? {})[0];
51
+ if (!credentials) {
52
+ findings.push({
53
+ id: `${this.agentId}-no-credentials`,
54
+ type: 'infra-issue',
55
+ severity: 'critical',
56
+ agentId: this.agentId,
57
+ module: 'a11y-guardian',
58
+ description: 'No credentials configured — cannot log in for accessibility scan',
59
+ });
60
+ return findings;
61
+ }
62
+ const { chromium } = await import('playwright');
63
+ const { AxeBuilder } = await import('@axe-core/playwright');
64
+ let browser = null;
65
+ let page = null;
66
+ try {
67
+ browser = await chromium.launch({ headless: true });
68
+ page = await browser.newPage();
69
+ try {
70
+ await login(page, credentials, loginUrl);
71
+ }
72
+ catch (loginError) {
73
+ findings.push({
74
+ id: `${this.agentId}-login-failed`,
75
+ type: 'infra-issue',
76
+ severity: 'medium',
77
+ agentId: this.agentId,
78
+ module: 'auth',
79
+ description: `Login failed (will scan anonymously): ${loginError instanceof Error ? loginError.message.split('\n')[0] : String(loginError)}`,
80
+ });
81
+ // Navigate to baseUrl so anonymous scanning can proceed
82
+ await page.goto(env.baseUrl, { waitUntil: 'networkidle', timeout: 10000 }).catch(() => { });
83
+ }
84
+ for (const module of this.config.modules) {
85
+ try {
86
+ await navigateToSection(page, module.id, this.config);
87
+ await waitForSectionLoad(page);
88
+ }
89
+ catch (navErr) {
90
+ findings.push({
91
+ id: `${this.agentId}-nav-${module.id}`,
92
+ type: 'infra-issue',
93
+ severity: 'high',
94
+ agentId: this.agentId,
95
+ module: module.id,
96
+ description: `[A11y] Navigation to module "${module.id}" failed: ${navErr instanceof Error ? navErr.message : String(navErr)}`,
97
+ });
98
+ continue;
99
+ }
100
+ const screenshotPath = await captureScreenshot(page, `a11y-${module.id}`, this.runDir);
101
+ this.addEvidence({
102
+ type: 'screenshot',
103
+ path: screenshotPath,
104
+ description: `A11y scan screenshot for module "${module.id}"`,
105
+ });
106
+ let axeResults;
107
+ try {
108
+ axeResults = await new AxeBuilder({ page }).analyze();
109
+ }
110
+ catch (axeErr) {
111
+ findings.push({
112
+ id: `${this.agentId}-axe-error-${module.id}`,
113
+ type: 'infra-issue',
114
+ severity: 'medium',
115
+ agentId: this.agentId,
116
+ module: module.id,
117
+ description: `[A11y] axe-core scan failed for module "${module.id}": ${axeErr instanceof Error ? axeErr.message : String(axeErr)}`,
118
+ });
119
+ continue;
120
+ }
121
+ for (const violation of axeResults.violations) {
122
+ const severity = mapAxeImpact(violation.impact ?? null);
123
+ const nodeCount = violation.nodes.length;
124
+ findings.push({
125
+ id: `${this.agentId}-axe-${module.id}-${violation.id}`,
126
+ type: 'code-bug-logic',
127
+ severity,
128
+ agentId: this.agentId,
129
+ module: module.id,
130
+ description: `[A11y] ${violation.description} (rule: ${violation.id}, ${nodeCount} node${nodeCount !== 1 ? 's' : ''})`,
131
+ screenshot: screenshotPath,
132
+ suggestedFix: violation.help,
133
+ });
134
+ }
135
+ }
136
+ // Optional: Lighthouse CI
137
+ await this.runLighthouseIfAvailable();
138
+ // Optional: Pa11y CI
139
+ await this.runPa11yIfAvailable();
140
+ }
141
+ finally {
142
+ if (page)
143
+ await page.close().catch(() => undefined);
144
+ if (browser)
145
+ await browser.close().catch(() => undefined);
146
+ }
147
+ return findings;
148
+ }
149
+ async runLighthouseIfAvailable() {
150
+ try {
151
+ await execFilePromise('npx', ['lhci', 'autorun']);
152
+ this.addEvidence({
153
+ type: 'report',
154
+ path: 'lhci-report',
155
+ description: 'Lighthouse CI accessibility report',
156
+ });
157
+ }
158
+ catch {
159
+ // Lighthouse not available or failed — non-fatal, skip silently
160
+ }
161
+ }
162
+ async runPa11yIfAvailable() {
163
+ try {
164
+ await execFilePromise('npx', ['pa11y-ci']);
165
+ this.addEvidence({
166
+ type: 'report',
167
+ path: 'pa11y-report',
168
+ description: 'Pa11y CI accessibility report',
169
+ });
170
+ }
171
+ catch {
172
+ // Pa11y not available or failed — non-fatal, skip silently
173
+ }
174
+ }
175
+ }
176
+ //# sourceMappingURL=08-a11y-guardian.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"08-a11y-guardian.js","sourceRoot":"","sources":["../../agents/08-a11y-guardian.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ import { BaseAgent } from './base-agent';
2
+ import type { Finding } from '../core/types';
3
+ /** Describes the root-cause category of a test-bug finding. */
4
+ type FixStrategy = 'selector' | 'timing' | 'data' | 'unknown';
5
+ /**
6
+ * Classifies a test-bug finding into one of three fix strategies based on
7
+ * keywords in the description.
8
+ *
9
+ * - selector: element-locator problems (element not found, stale selector, …)
10
+ * - timing: race-condition / timeout problems
11
+ * - data: seed / fixture / data mismatch problems
12
+ * - unknown: fallback when no keyword matches
13
+ */
14
+ export declare function classifyFixStrategy(finding: Finding): FixStrategy;
15
+ /**
16
+ * Generates a suggested fix string given a FixStrategy and the original
17
+ * finding. The generated suggestion intentionally uses plain English so it
18
+ * can be reviewed by a developer or fed to a downstream AI patch agent.
19
+ */
20
+ export declare function generateFixSuggestion(finding: Finding, strategy: FixStrategy): string;
21
+ export declare class HealerAgent extends BaseAgent {
22
+ readonly agentId = 9;
23
+ readonly agentName = "Healer";
24
+ /** Attempt tracking for the current run (finding id → attempt count). */
25
+ private readonly attemptMap;
26
+ /** Set to true when there are no findings to process — makes execute() a no-op. */
27
+ private noFindings;
28
+ protected preFlight(): Promise<void>;
29
+ protected execute(): Promise<Finding[]>;
30
+ private getOrCreateAttemptRecord;
31
+ }
32
+ export {};
33
+ //# sourceMappingURL=09-healer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"09-healer.d.ts","sourceRoot":"","sources":["../../agents/09-healer.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAK7C,+DAA+D;AAC/D,KAAK,WAAW,GAAG,UAAU,GAAG,QAAQ,GAAG,MAAM,GAAG,SAAS,CAAC;AAQ9D;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,WAAW,CAkCjE;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,WAAW,GAAG,MAAM,CAiCrF;AAED,qBAAa,WAAY,SAAQ,SAAS;IACxC,QAAQ,CAAC,OAAO,KAAK;IACrB,QAAQ,CAAC,SAAS,YAAY;IAE9B,yEAAyE;IACzE,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAoC;IAE/D,mFAAmF;IACnF,OAAO,CAAC,UAAU,CAAS;cAEX,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;cAmB1B,OAAO,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;IA4E7C,OAAO,CAAC,wBAAwB;CAOjC"}
@@ -0,0 +1,167 @@
1
+ import * as fs from 'fs/promises';
2
+ import * as path from 'path';
3
+ import { BaseAgent } from './base-agent';
4
+ import { validateCodeQuality } from '../helpers/quality-gate';
5
+ /** Maximum number of fix attempts per finding before escalation. */
6
+ const MAX_ATTEMPTS = 3;
7
+ /**
8
+ * Classifies a test-bug finding into one of three fix strategies based on
9
+ * keywords in the description.
10
+ *
11
+ * - selector: element-locator problems (element not found, stale selector, …)
12
+ * - timing: race-condition / timeout problems
13
+ * - data: seed / fixture / data mismatch problems
14
+ * - unknown: fallback when no keyword matches
15
+ */
16
+ export function classifyFixStrategy(finding) {
17
+ const lower = finding.description.toLowerCase();
18
+ if (lower.includes('selector') ||
19
+ lower.includes('element not found') ||
20
+ lower.includes('locator') ||
21
+ lower.includes('stale') ||
22
+ lower.includes('no such element')) {
23
+ return 'selector';
24
+ }
25
+ if (lower.includes('timeout') ||
26
+ lower.includes('timing') ||
27
+ lower.includes('race') ||
28
+ lower.includes('wait') ||
29
+ lower.includes('timed out')) {
30
+ return 'timing';
31
+ }
32
+ if (lower.includes('seed') ||
33
+ lower.includes('fixture') ||
34
+ lower.includes('data') ||
35
+ lower.includes('expected value') ||
36
+ lower.includes('mismatch')) {
37
+ return 'data';
38
+ }
39
+ return 'unknown';
40
+ }
41
+ /**
42
+ * Generates a suggested fix string given a FixStrategy and the original
43
+ * finding. The generated suggestion intentionally uses plain English so it
44
+ * can be reviewed by a developer or fed to a downstream AI patch agent.
45
+ */
46
+ export function generateFixSuggestion(finding, strategy) {
47
+ switch (strategy) {
48
+ case 'selector':
49
+ return (`[Healer] Selector fix for "${finding.module}": ` +
50
+ `Update the element selector/locator — the target element may have changed its ` +
51
+ `data-testid, class, or role attribute. ` +
52
+ `Suggested action: inspect the current DOM and replace the stale selector with ` +
53
+ `a stable data-testid attribute (e.g. data-testid="<component>-<action>").`);
54
+ case 'timing':
55
+ return (`[Healer] Timing fix for "${finding.module}": ` +
56
+ `Add an explicit wait before the failing assertion. ` +
57
+ `Suggested action: replace hard sleeps with \`waitFor\` / \`waitForSelector\` ` +
58
+ `or increase the relevant timeout in the test configuration.`);
59
+ case 'data':
60
+ return (`[Healer] Data fix for "${finding.module}": ` +
61
+ `Update the test seed or fixture so the expected values match the current schema. ` +
62
+ `Suggested action: re-run \`pnpm seed:test\` to refresh test data, or update ` +
63
+ `the fixture file to reflect the current data model.`);
64
+ default:
65
+ return (`[Healer] Unknown strategy for "${finding.module}": ` +
66
+ `Manual investigation required — no known fix pattern matched the description.`);
67
+ }
68
+ }
69
+ export class HealerAgent extends BaseAgent {
70
+ agentId = 9;
71
+ agentName = 'Healer';
72
+ /** Attempt tracking for the current run (finding id → attempt count). */
73
+ attemptMap = new Map();
74
+ /** Set to true when there are no findings to process — makes execute() a no-op. */
75
+ noFindings = false;
76
+ async preFlight() {
77
+ const testBugsDir = path.join(this.runDir, 'findings', 'test-bugs');
78
+ let entries;
79
+ try {
80
+ entries = await fs.readdir(testBugsDir);
81
+ }
82
+ catch (err) {
83
+ if (isNodeError(err) && err.code === 'ENOENT') {
84
+ this.noFindings = true;
85
+ return;
86
+ }
87
+ throw err;
88
+ }
89
+ const jsonFiles = entries.filter((e) => e.endsWith('.json'));
90
+ if (jsonFiles.length === 0) {
91
+ this.noFindings = true;
92
+ }
93
+ }
94
+ async execute() {
95
+ if (this.noFindings) {
96
+ return [];
97
+ }
98
+ const testBugsDir = path.join(this.runDir, 'findings', 'test-bugs');
99
+ let entries;
100
+ try {
101
+ entries = await fs.readdir(testBugsDir);
102
+ }
103
+ catch {
104
+ return [];
105
+ }
106
+ const jsonFiles = entries.filter((e) => e.endsWith('.json'));
107
+ const unresolvedFindings = [];
108
+ for (const filename of jsonFiles) {
109
+ const filePath = path.join(testBugsDir, filename);
110
+ let finding;
111
+ try {
112
+ const raw = await fs.readFile(filePath, 'utf-8');
113
+ finding = JSON.parse(raw);
114
+ }
115
+ catch {
116
+ continue;
117
+ }
118
+ const record = this.getOrCreateAttemptRecord(finding.id);
119
+ if (record.attempts >= MAX_ATTEMPTS) {
120
+ unresolvedFindings.push({
121
+ ...finding,
122
+ suggestedFix: `[Healer] Escalated after ${MAX_ATTEMPTS} attempts — requires manual investigation.`,
123
+ });
124
+ continue;
125
+ }
126
+ record.attempts += 1;
127
+ const strategy = classifyFixStrategy(finding);
128
+ const suggestion = generateFixSuggestion(finding, strategy);
129
+ // Run quality gate on any embedded test code in suggestedFix (if present)
130
+ const qualityViolations = validateCodeQuality(suggestion, `healer-fix-${finding.id}.ts`);
131
+ const hasErrors = qualityViolations.some((v) => v.severity === 'error');
132
+ if (hasErrors) {
133
+ // The fix suggestion itself has quality errors — escalate
134
+ unresolvedFindings.push({
135
+ ...finding,
136
+ suggestedFix: `[Healer] Generated fix failed quality gate (attempt ${record.attempts}/${MAX_ATTEMPTS}): ` +
137
+ qualityViolations.map((v) => v.message).join('; '),
138
+ });
139
+ continue;
140
+ }
141
+ const resolvedFinding = {
142
+ ...finding,
143
+ suggestedFix: suggestion,
144
+ };
145
+ this.addEvidence({
146
+ type: 'log',
147
+ path: filePath,
148
+ description: `Healer processed test-bug "${finding.id}" with strategy "${strategy}" (attempt ${record.attempts})`,
149
+ });
150
+ // Write updated finding back to disk
151
+ await fs.writeFile(filePath, JSON.stringify(resolvedFinding, null, 2), 'utf-8');
152
+ }
153
+ return unresolvedFindings;
154
+ }
155
+ getOrCreateAttemptRecord(findingId) {
156
+ const existing = this.attemptMap.get(findingId);
157
+ if (existing)
158
+ return existing;
159
+ const record = { findingId, attempts: 0 };
160
+ this.attemptMap.set(findingId, record);
161
+ return record;
162
+ }
163
+ }
164
+ function isNodeError(err) {
165
+ return err instanceof Error && 'code' in err;
166
+ }
167
+ //# sourceMappingURL=09-healer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"09-healer.js","sourceRoot":"","sources":["../../agents/09-healer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import { BaseAgent } from './base-agent';
2
+ import type { AgentResult, Finding } from '../core/types';
3
+ /** Release-gate recommendation. */
4
+ export type ReleaseRecommendation = 'GO' | 'CONDITIONAL GO' | 'NO-GO';
5
+ /**
6
+ * Determines the release recommendation based on the severity of all findings
7
+ * across every agent result.
8
+ *
9
+ * - NO-GO: any critical finding
10
+ * - CONDITIONAL GO: 0 critical findings, at least one high finding
11
+ * - GO: 0 critical and 0 high findings
12
+ */
13
+ export declare function determineRecommendation(results: AgentResult[]): ReleaseRecommendation;
14
+ /**
15
+ * Builds the full markdown report string from the collected agent results.
16
+ */
17
+ export declare function buildMarkdownReport(results: AgentResult[], runId: string, recommendation: ReleaseRecommendation): string;
18
+ export declare class ReporterAgent extends BaseAgent {
19
+ readonly agentId = 10;
20
+ readonly agentName = "Reporter";
21
+ /** When true, execute() returns a single informational finding instead of a full report. */
22
+ private noPriorResults;
23
+ protected preFlight(): Promise<void>;
24
+ protected execute(): Promise<Finding[]>;
25
+ }
26
+ //# sourceMappingURL=10-reporter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"10-reporter.d.ts","sourceRoot":"","sources":["../../agents/10-reporter.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,OAAO,KAAK,EAAE,WAAW,EAAE,OAAO,EAA0B,MAAM,eAAe,CAAC;AAKlF,mCAAmC;AACnC,MAAM,MAAM,qBAAqB,GAAG,IAAI,GAAG,gBAAgB,GAAG,OAAO,CAAC;AAUtE;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,WAAW,EAAE,GAAG,qBAAqB,CAQrF;AAsDD;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,WAAW,EAAE,EACtB,KAAK,EAAE,MAAM,EACb,cAAc,EAAE,qBAAqB,GACpC,MAAM,CA8DR;AAED,qBAAa,aAAc,SAAQ,SAAS;IAC1C,QAAQ,CAAC,OAAO,MAAM;IACtB,QAAQ,CAAC,SAAS,cAAc;IAEhC,4FAA4F;IAC5F,OAAO,CAAC,cAAc,CAAS;cAEf,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;cAqB1B,OAAO,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;CAgE9C"}
@@ -0,0 +1,215 @@
1
+ import * as fs from 'fs/promises';
2
+ import * as path from 'path';
3
+ import { BaseAgent } from './base-agent';
4
+ import { readAgentResult } from '../core/evidence';
5
+ /** Agent IDs whose results are pulled into the consolidated report. */
6
+ const KNOWN_AGENT_IDS = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23];
7
+ /**
8
+ * Determines the release recommendation based on the severity of all findings
9
+ * across every agent result.
10
+ *
11
+ * - NO-GO: any critical finding
12
+ * - CONDITIONAL GO: 0 critical findings, at least one high finding
13
+ * - GO: 0 critical and 0 high findings
14
+ */
15
+ export function determineRecommendation(results) {
16
+ const allFindings = results.flatMap((r) => r.findings);
17
+ const hasCritical = allFindings.some((f) => f.severity === 'critical');
18
+ const hasHigh = allFindings.some((f) => f.severity === 'high');
19
+ if (hasCritical)
20
+ return 'NO-GO';
21
+ if (hasHigh)
22
+ return 'CONDITIONAL GO';
23
+ return 'GO';
24
+ }
25
+ /**
26
+ * Aggregates agent results by phase.
27
+ */
28
+ function aggregateByPhase(results) {
29
+ const map = new Map();
30
+ for (const result of results) {
31
+ const phase = result.phase;
32
+ const existing = map.get(phase) ?? {
33
+ phase,
34
+ passCount: 0,
35
+ failCount: 0,
36
+ findings: [],
37
+ };
38
+ if (result.status === 'passed') {
39
+ existing.passCount += 1;
40
+ }
41
+ else {
42
+ existing.failCount += 1;
43
+ }
44
+ existing.findings.push(...result.findings);
45
+ map.set(phase, existing);
46
+ }
47
+ return map;
48
+ }
49
+ function severityEmoji(severity) {
50
+ switch (severity) {
51
+ case 'critical': return 'CRITICAL';
52
+ case 'high': return 'HIGH';
53
+ case 'medium': return 'MEDIUM';
54
+ case 'low': return 'LOW';
55
+ case 'info': return 'INFO';
56
+ }
57
+ }
58
+ function formatFindingLine(f) {
59
+ const loc = f.file ? ` (${f.file}${f.line ? `:${f.line}` : ''})` : '';
60
+ return `- [${severityEmoji(f.severity)}] Agent ${f.agentId} | ${f.module}${loc}: ${f.description}`;
61
+ }
62
+ /**
63
+ * Extracts a summary string from the agent result with the given ID, or returns
64
+ * a placeholder when that result is not present in the collection.
65
+ */
66
+ function agentSummaryLine(results, agentId, label) {
67
+ const result = results.find((r) => r.agentId === agentId);
68
+ if (!result)
69
+ return `${label}: not run`;
70
+ return `${label}: ${result.summary}`;
71
+ }
72
+ /**
73
+ * Builds the full markdown report string from the collected agent results.
74
+ */
75
+ export function buildMarkdownReport(results, runId, recommendation) {
76
+ const phaseMap = aggregateByPhase(results);
77
+ const phases = ['alpha', 'beta', 'uat', 'release'];
78
+ const lines = [];
79
+ lines.push(`# TestTeam — Release Report`);
80
+ lines.push(`**Run ID:** ${runId}`);
81
+ lines.push(`**Generated:** ${new Date().toISOString()}`);
82
+ lines.push(`**Recommendation:** ${recommendation}`);
83
+ lines.push('');
84
+ // Phase summaries
85
+ lines.push('## Phase Summaries');
86
+ for (const phase of phases) {
87
+ const summary = phaseMap.get(phase);
88
+ if (!summary) {
89
+ lines.push(`### ${phase.toUpperCase()}`);
90
+ lines.push('No agents ran in this phase.');
91
+ lines.push('');
92
+ continue;
93
+ }
94
+ lines.push(`### ${phase.toUpperCase()}`);
95
+ lines.push(`- Pass: ${summary.passCount}`);
96
+ lines.push(`- Fail: ${summary.failCount}`);
97
+ lines.push(`- Total findings: ${summary.findings.length}`);
98
+ lines.push('');
99
+ }
100
+ // Specialist summaries
101
+ lines.push('## Specialist Summaries');
102
+ lines.push(agentSummaryLine(results, 4, 'Coverage (Agent 4)'));
103
+ lines.push(agentSummaryLine(results, 7, 'Security (Agent 7)'));
104
+ lines.push(agentSummaryLine(results, 8, 'Accessibility (Agent 8)'));
105
+ lines.push(agentSummaryLine(results, 13, 'Performance (Agent 13)'));
106
+ lines.push(agentSummaryLine(results, 14, 'Data Integrity (Agent 14)'));
107
+ lines.push('');
108
+ // All findings by severity
109
+ const allFindings = results.flatMap((r) => r.findings);
110
+ const severities = ['critical', 'high', 'medium', 'low'];
111
+ lines.push('## Findings by Severity');
112
+ for (const sev of severities) {
113
+ const group = allFindings.filter((f) => f.severity === sev);
114
+ if (group.length === 0)
115
+ continue;
116
+ lines.push(`### ${sev.toUpperCase()} (${group.length})`);
117
+ for (const f of group) {
118
+ lines.push(formatFindingLine(f));
119
+ }
120
+ lines.push('');
121
+ }
122
+ if (allFindings.length === 0) {
123
+ lines.push('No findings — all agents passed.');
124
+ lines.push('');
125
+ }
126
+ lines.push(`---`);
127
+ lines.push(`_Generated by TestTeam Reporter (Agent 10)_`);
128
+ return lines.join('\n');
129
+ }
130
+ export class ReporterAgent extends BaseAgent {
131
+ agentId = 10;
132
+ agentName = 'Reporter';
133
+ /** When true, execute() returns a single informational finding instead of a full report. */
134
+ noPriorResults = false;
135
+ async preFlight() {
136
+ const agentResultsDir = path.join(this.runDir, 'agent-results');
137
+ let entries;
138
+ try {
139
+ entries = await fs.readdir(agentResultsDir);
140
+ }
141
+ catch (err) {
142
+ if (isNodeError(err) && err.code === 'ENOENT') {
143
+ // Directory missing — gracefully degrade instead of throwing
144
+ this.noPriorResults = true;
145
+ return;
146
+ }
147
+ throw err;
148
+ }
149
+ const jsonFiles = entries.filter((e) => e.endsWith('.json'));
150
+ if (jsonFiles.length === 0) {
151
+ // Empty directory — gracefully degrade instead of throwing
152
+ this.noPriorResults = true;
153
+ }
154
+ }
155
+ async execute() {
156
+ if (this.noPriorResults) {
157
+ return [{
158
+ id: `${this.agentId}-no-results`,
159
+ type: 'infra-issue',
160
+ severity: 'low',
161
+ agentId: this.agentId,
162
+ module: 'reporter',
163
+ description: 'No agent results to report — agent-results directory is empty or missing',
164
+ }];
165
+ }
166
+ // Read all available agent results
167
+ const results = [];
168
+ for (const agentId of KNOWN_AGENT_IDS) {
169
+ const result = await readAgentResult(this.runDir, agentId);
170
+ if (result) {
171
+ results.push(result);
172
+ }
173
+ }
174
+ // Also read any extra result files not in the known-IDs list
175
+ const agentResultsDir = path.join(this.runDir, 'agent-results');
176
+ try {
177
+ const entries = await fs.readdir(agentResultsDir);
178
+ for (const entry of entries) {
179
+ if (!entry.endsWith('.json'))
180
+ continue;
181
+ const idStr = entry.replace('.json', '');
182
+ const id = parseInt(idStr, 10);
183
+ if (isNaN(id) || KNOWN_AGENT_IDS.includes(id))
184
+ continue;
185
+ const raw = await fs.readFile(path.join(agentResultsDir, entry), 'utf-8');
186
+ results.push(JSON.parse(raw));
187
+ }
188
+ }
189
+ catch {
190
+ // Ignore read errors for extra files
191
+ }
192
+ const recommendation = determineRecommendation(results);
193
+ // Use run directory name as run ID
194
+ const runId = path.basename(this.runDir);
195
+ const date = new Date().toISOString().slice(0, 10);
196
+ const reportFilename = `${date}-${runId}.md`;
197
+ const reportsDir = path.join(path.dirname(path.dirname(this.runDir)), // go up from .run/<runId> to project root
198
+ 'testteam', 'reports');
199
+ await fs.mkdir(reportsDir, { recursive: true });
200
+ const reportPath = path.join(reportsDir, reportFilename);
201
+ const markdownContent = buildMarkdownReport(results, runId, recommendation);
202
+ await fs.writeFile(reportPath, markdownContent, 'utf-8');
203
+ this.addEvidence({
204
+ type: 'report',
205
+ path: reportPath,
206
+ description: `Consolidated release report — recommendation: ${recommendation}`,
207
+ });
208
+ // Reporter does not generate new findings — it only aggregates
209
+ return [];
210
+ }
211
+ }
212
+ function isNodeError(err) {
213
+ return err instanceof Error && 'code' in err;
214
+ }
215
+ //# sourceMappingURL=10-reporter.js.map