@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,246 @@
1
+ import { readdir, readFile, stat } from 'node:fs/promises';
2
+ import { join } from 'path';
3
+ import { BaseAgent } from './base-agent';
4
+ /** Regex to extract URLs from markdown link syntax [text](url) */
5
+ const MARKDOWN_LINK_REGEX = /\[.*?\]\((https?:\/\/[^)]+)\)/g;
6
+ /** Regex to extract bare URLs (not inside markdown link parens) */
7
+ const BARE_URL_REGEX = /(?<!\()(https?:\/\/[^\s"'<>)\]]+)/g;
8
+ /** Regex to find catch blocks that swallow errors with just a log */
9
+ const BARE_CATCH_LOG_REGEX = /catch\s*\([^)]*\)\s*\{[^}]*(?:console\.log|console\.error|logger\.\w+)\s*\(\s*(?:\w+\.message|error\.message)\s*\)[^}]*\}/g;
10
+ async function fileExists(p) {
11
+ try {
12
+ await stat(p);
13
+ return true;
14
+ }
15
+ catch {
16
+ return false;
17
+ }
18
+ }
19
+ async function isDirectory(p) {
20
+ try {
21
+ return (await stat(p)).isDirectory();
22
+ }
23
+ catch {
24
+ return false;
25
+ }
26
+ }
27
+ export class DocumentationValidatorAgent extends BaseAgent {
28
+ agentId = 17;
29
+ agentName = 'Documentation Validator';
30
+ async preFlight() {
31
+ const projectRoot = this.resolveProjectRoot();
32
+ const readmeExists = await fileExists(join(projectRoot, 'README.md'));
33
+ const docsExists = await fileExists(join(projectRoot, 'docs'));
34
+ if (!readmeExists && !docsExists) {
35
+ throw new Error('No README.md or docs/ directory found — nothing to validate');
36
+ }
37
+ }
38
+ async execute() {
39
+ const findings = [];
40
+ const projectRoot = this.resolveProjectRoot();
41
+ // 1. Collect all markdown files from project root and docs/
42
+ const markdownFiles = await this.collectMarkdownFiles(projectRoot);
43
+ // 2. Extract all URLs from markdown files
44
+ const urlSources = await this.extractUrlsFromFiles(markdownFiles);
45
+ // 3. HTTP HEAD each URL — create finding for 404/5xx
46
+ const brokenLinkFindings = await this.checkUrls(urlSources);
47
+ findings.push(...brokenLinkFindings);
48
+ // 4. Scan source code for catch blocks that only log error.message
49
+ const catchFindings = await this.scanForBareCatchLogs(projectRoot);
50
+ findings.push(...catchFindings);
51
+ return findings;
52
+ }
53
+ // ---------------------------------------------------------------------------
54
+ // Helpers
55
+ // ---------------------------------------------------------------------------
56
+ /**
57
+ * Resolve the project root. The runDir is typically a subdirectory created
58
+ * for the current test run; the actual project root is the repo root.
59
+ * We walk upward from runDir until we find a package.json or use CWD.
60
+ */
61
+ resolveProjectRoot() {
62
+ // Prefer process.cwd() — the test runner / CLI always sets CWD to repo root
63
+ return process.cwd();
64
+ }
65
+ /** Recursively collect .md files from projectRoot and any docs/ sub-directory. */
66
+ async collectMarkdownFiles(projectRoot) {
67
+ const files = [];
68
+ // Root-level .md files
69
+ try {
70
+ const rootEntries = await readdir(projectRoot);
71
+ for (const entry of rootEntries) {
72
+ if (entry.endsWith('.md')) {
73
+ files.push(join(projectRoot, entry));
74
+ }
75
+ }
76
+ }
77
+ catch {
78
+ // Cannot read project root — return empty
79
+ return files;
80
+ }
81
+ // docs/ sub-directory (recursive)
82
+ const docsDir = join(projectRoot, 'docs');
83
+ const docsIsDir = await isDirectory(docsDir);
84
+ if (docsIsDir) {
85
+ await this.walkMarkdownFiles(docsDir, files);
86
+ }
87
+ return files;
88
+ }
89
+ async walkMarkdownFiles(dir, results) {
90
+ let entries;
91
+ try {
92
+ entries = await readdir(dir);
93
+ }
94
+ catch {
95
+ return;
96
+ }
97
+ for (const entry of entries) {
98
+ const fullPath = join(dir, entry);
99
+ try {
100
+ const s = await stat(fullPath);
101
+ if (s.isDirectory()) {
102
+ await this.walkMarkdownFiles(fullPath, results);
103
+ }
104
+ else if (entry.endsWith('.md')) {
105
+ results.push(fullPath);
106
+ }
107
+ }
108
+ catch {
109
+ // Skip unreadable entries
110
+ }
111
+ }
112
+ }
113
+ /**
114
+ * Extract all HTTP/HTTPS URLs from the given markdown files.
115
+ * Returns a map: url → source file path.
116
+ */
117
+ async extractUrlsFromFiles(files) {
118
+ const urlMap = new Map();
119
+ for (const filePath of files) {
120
+ let content;
121
+ try {
122
+ content = await readFile(filePath, 'utf-8');
123
+ }
124
+ catch {
125
+ continue;
126
+ }
127
+ // Markdown link syntax
128
+ for (const match of content.matchAll(MARKDOWN_LINK_REGEX)) {
129
+ const url = match[1];
130
+ if (url && !urlMap.has(url)) {
131
+ urlMap.set(url, filePath);
132
+ }
133
+ }
134
+ // Bare URLs not already captured via markdown links
135
+ for (const match of content.matchAll(BARE_URL_REGEX)) {
136
+ const url = match[0];
137
+ if (url && !urlMap.has(url)) {
138
+ urlMap.set(url, filePath);
139
+ }
140
+ }
141
+ }
142
+ return urlMap;
143
+ }
144
+ /** HEAD each URL; create a 'low' finding for 404 or 5xx responses. */
145
+ async checkUrls(urlSources) {
146
+ const findings = [];
147
+ let findingIndex = 0;
148
+ for (const [url, sourceFile] of urlSources) {
149
+ let status = null;
150
+ try {
151
+ const response = await fetch(url, {
152
+ method: 'HEAD',
153
+ signal: AbortSignal.timeout(10_000),
154
+ redirect: 'follow',
155
+ });
156
+ status = response.status;
157
+ }
158
+ catch {
159
+ // Network error — treat as unreachable
160
+ status = null;
161
+ }
162
+ const isBroken = status === null ||
163
+ status === 404 ||
164
+ status >= 500;
165
+ if (isBroken) {
166
+ const statusLabel = status !== null ? String(status) : 'unreachable';
167
+ findings.push({
168
+ id: `${this.agentId}-broken-link-${findingIndex++}`,
169
+ type: 'test-bug',
170
+ severity: 'low',
171
+ agentId: this.agentId,
172
+ module: 'documentation',
173
+ description: `Broken link [${statusLabel}]: ${url}`,
174
+ file: sourceFile,
175
+ });
176
+ }
177
+ }
178
+ return findings;
179
+ }
180
+ /**
181
+ * Scan TypeScript / JavaScript source files for catch blocks that only log
182
+ * error.message without providing a user-friendly message.
183
+ */
184
+ async scanForBareCatchLogs(projectRoot) {
185
+ const findings = [];
186
+ const srcDirs = ['src', 'apps', 'libs', 'packages'];
187
+ for (const dir of srcDirs) {
188
+ const fullDir = join(projectRoot, dir);
189
+ const dirExists = await fileExists(fullDir);
190
+ if (!dirExists)
191
+ continue;
192
+ const sourceFiles = [];
193
+ await this.walkSourceFiles(fullDir, sourceFiles);
194
+ for (const filePath of sourceFiles) {
195
+ let content;
196
+ try {
197
+ content = await readFile(filePath, 'utf-8');
198
+ }
199
+ catch {
200
+ continue;
201
+ }
202
+ const matches = content.match(BARE_CATCH_LOG_REGEX);
203
+ if (matches && matches.length > 0) {
204
+ findings.push({
205
+ id: `${this.agentId}-bare-catch-${filePath.replace(/[^a-z0-9]/gi, '-').slice(-60)}`,
206
+ type: 'code-bug-logic',
207
+ severity: 'low',
208
+ agentId: this.agentId,
209
+ module: 'error-handling',
210
+ description: `${matches.length} catch block(s) in "${filePath}" only log error.message without a user-friendly message`,
211
+ file: filePath,
212
+ suggestedFix: 'Replace bare error.message logs with structured error responses that include user-friendly messages',
213
+ });
214
+ }
215
+ }
216
+ }
217
+ return findings;
218
+ }
219
+ async walkSourceFiles(dir, results) {
220
+ let entries;
221
+ try {
222
+ entries = await readdir(dir);
223
+ }
224
+ catch {
225
+ return;
226
+ }
227
+ for (const entry of entries) {
228
+ if (entry === 'node_modules' || entry === 'dist' || entry === '.git')
229
+ continue;
230
+ const fullPath = join(dir, entry);
231
+ try {
232
+ const s = await stat(fullPath);
233
+ if (s.isDirectory()) {
234
+ await this.walkSourceFiles(fullPath, results);
235
+ }
236
+ else if (entry.endsWith('.ts') || entry.endsWith('.js')) {
237
+ results.push(fullPath);
238
+ }
239
+ }
240
+ catch {
241
+ // Skip unreadable entries
242
+ }
243
+ }
244
+ }
245
+ }
246
+ //# sourceMappingURL=17-documentation-validator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"17-documentation-validator.js","sourceRoot":"","sources":["../../agents/17-documentation-validator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import { BaseAgent } from './base-agent';
2
+ import type { Finding } from '../core/types';
3
+ export declare class IntegrationWatchdogAgent extends BaseAgent {
4
+ readonly agentId = 18;
5
+ readonly agentName = "Integration Watchdog";
6
+ private repoRoot;
7
+ protected preFlight(): Promise<void>;
8
+ protected execute(): Promise<Finding[]>;
9
+ }
10
+ //# sourceMappingURL=18-integration-watchdog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"18-integration-watchdog.d.ts","sourceRoot":"","sources":["../../agents/18-integration-watchdog.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AA4B7C,qBAAa,wBAAyB,SAAQ,SAAS;IACrD,QAAQ,CAAC,OAAO,MAAM;IACtB,QAAQ,CAAC,SAAS,0BAA0B;IAC5C,OAAO,CAAC,QAAQ,CAAM;cAEN,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;cAgB1B,OAAO,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;CA4H9C"}
@@ -0,0 +1,138 @@
1
+ import { execFile } from 'node:child_process';
2
+ import { existsSync } from 'node:fs';
3
+ import { resolve } from 'node:path';
4
+ import { BaseAgent } from './base-agent';
5
+ function runVitest(vitestConfigPath, cwd) {
6
+ return new Promise((resolveP, rejectP) => {
7
+ execFile('npx', ['vitest', 'run', '--config', vitestConfigPath], { cwd, shell: true }, (err, stdout, stderr) => {
8
+ if (err) {
9
+ const enriched = Object.assign(new Error(err.message), {
10
+ stdout: stdout ?? '',
11
+ stderr: stderr ?? '',
12
+ });
13
+ rejectP(enriched);
14
+ return;
15
+ }
16
+ resolveP({ stdout: stdout ?? '', stderr: stderr ?? '' });
17
+ });
18
+ });
19
+ }
20
+ export class IntegrationWatchdogAgent extends BaseAgent {
21
+ agentId = 18;
22
+ agentName = 'Integration Watchdog';
23
+ repoRoot = '';
24
+ async preFlight() {
25
+ this.repoRoot = this.config.projectRoot ?? process.cwd();
26
+ if (this.config.integrations.length === 0) {
27
+ throw new Error('IntegrationWatchdogAgent requires at least one integration in config.integrations');
28
+ }
29
+ // Verify worker directories exist
30
+ const workersDir = resolve(this.repoRoot, 'apps', 'workers');
31
+ if (!existsSync(workersDir)) {
32
+ throw new Error(`Worker directory not found: ${workersDir}`);
33
+ }
34
+ }
35
+ async execute() {
36
+ const findings = [];
37
+ // -----------------------------------------------------------------------
38
+ // Worker coverage checks
39
+ // -----------------------------------------------------------------------
40
+ for (const worker of this.config.workers) {
41
+ const workerName = worker.name;
42
+ // Check source file exists
43
+ const workerSrcCandidates = [
44
+ resolve(this.repoRoot, 'apps', 'workers', 'src', `${workerName}.ts`),
45
+ resolve(this.repoRoot, 'apps', 'workers', 'src', workerName, 'index.ts'),
46
+ resolve(this.repoRoot, 'apps', 'workers', `${workerName}.ts`),
47
+ ];
48
+ const workerSrcExists = workerSrcCandidates.some((p) => existsSync(p));
49
+ if (!workerSrcExists) {
50
+ findings.push({
51
+ id: `${this.agentId}-worker-missing-${workerName}`,
52
+ type: 'infra-issue',
53
+ severity: 'medium',
54
+ agentId: this.agentId,
55
+ module: `worker:${workerName}`,
56
+ description: `Worker source file not found for "${workerName}". ` +
57
+ `Searched: ${workerSrcCandidates.join(', ')}`,
58
+ suggestedFix: `Create the worker source file at apps/workers/src/${workerName}.ts`,
59
+ });
60
+ continue;
61
+ }
62
+ // Check test files exist
63
+ const workerTestCandidates = [
64
+ resolve(this.repoRoot, 'apps', 'workers', 'src', `${workerName}.test.ts`),
65
+ resolve(this.repoRoot, 'apps', 'workers', 'src', `${workerName}.spec.ts`),
66
+ resolve(this.repoRoot, 'apps', 'workers', '__tests__', `${workerName}.test.ts`),
67
+ resolve(this.repoRoot, 'apps', 'workers', 'src', workerName, `${workerName}.test.ts`),
68
+ ];
69
+ const workerTestExists = workerTestCandidates.some((p) => existsSync(p));
70
+ if (!workerTestExists) {
71
+ findings.push({
72
+ id: `${this.agentId}-worker-no-tests-${workerName}`,
73
+ type: 'test-bug',
74
+ severity: 'medium',
75
+ agentId: this.agentId,
76
+ module: `worker:${workerName}`,
77
+ description: `No test file found for worker "${workerName}".`,
78
+ suggestedFix: `Add tests at apps/workers/src/${workerName}.test.ts`,
79
+ });
80
+ }
81
+ }
82
+ // -----------------------------------------------------------------------
83
+ // Run worker tests if workers config and vitest config exist
84
+ // -----------------------------------------------------------------------
85
+ if (this.config.workers.length > 0) {
86
+ const vitestConfig = resolve(this.repoRoot, 'apps', 'workers', 'vitest.config.ts');
87
+ if (existsSync(vitestConfig)) {
88
+ try {
89
+ await runVitest(vitestConfig, this.repoRoot);
90
+ }
91
+ catch (error) {
92
+ const stderr = error instanceof Error && 'stderr' in error
93
+ ? String(error.stderr)
94
+ : String(error);
95
+ const stdout = error instanceof Error && 'stdout' in error
96
+ ? String(error.stdout)
97
+ : '';
98
+ findings.push({
99
+ id: `${this.agentId}-worker-tests-failed`,
100
+ type: 'test-bug',
101
+ severity: 'high',
102
+ agentId: this.agentId,
103
+ module: 'workers',
104
+ description: `Worker test suite failed.\n${stderr || stdout}`,
105
+ suggestedFix: 'Fix the failing worker tests before promoting to UAT.',
106
+ });
107
+ }
108
+ }
109
+ }
110
+ // -----------------------------------------------------------------------
111
+ // Integration sandbox checks
112
+ // -----------------------------------------------------------------------
113
+ for (const integration of this.config.integrations) {
114
+ const integrationName = integration.name;
115
+ // Detect sandbox availability — look for connection config
116
+ const connectionConfigCandidates = [
117
+ resolve(this.repoRoot, 'apps', 'workers', 'src', 'integrations', `${integrationName}.ts`),
118
+ resolve(this.repoRoot, 'apps', 'api', 'src', 'integrations', `${integrationName}.ts`),
119
+ resolve(this.repoRoot, 'apps', 'workers', 'src', 'integrations', `${integrationName}-sandbox.ts`),
120
+ ];
121
+ const sandboxAvailable = connectionConfigCandidates.some((p) => existsSync(p));
122
+ if (!sandboxAvailable) {
123
+ findings.push({
124
+ id: `${this.agentId}-integration-no-sandbox-${integrationName}`,
125
+ type: 'infra-issue',
126
+ severity: 'low',
127
+ agentId: this.agentId,
128
+ module: `integration:${integrationName}`,
129
+ description: `Advisory: No sandbox connection config found for integration "${integrationName}". ` +
130
+ `End-to-end integration testing cannot be performed automatically.`,
131
+ suggestedFix: `Add a sandbox configuration at apps/workers/src/integrations/${integrationName}.ts`,
132
+ });
133
+ }
134
+ }
135
+ return findings;
136
+ }
137
+ }
138
+ //# sourceMappingURL=18-integration-watchdog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"18-integration-watchdog.js","sourceRoot":"","sources":["../../agents/18-integration-watchdog.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { Finding } from '../core/types';
2
+ import { BaseAgent } from './base-agent';
3
+ export declare class TenantIsolationAuditorAgent extends BaseAgent {
4
+ readonly agentId = 19;
5
+ readonly agentName = "Tenant Isolation Auditor";
6
+ protected preFlight(): Promise<void>;
7
+ protected execute(): Promise<Finding[]>;
8
+ }
9
+ //# sourceMappingURL=19-tenant-isolation-auditor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"19-tenant-isolation-auditor.d.ts","sourceRoot":"","sources":["../../agents/19-tenant-isolation-auditor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAIzC,qBAAa,2BAA4B,SAAQ,SAAS;IACxD,QAAQ,CAAC,OAAO,MAAM;IACtB,QAAQ,CAAC,SAAS,8BAA8B;cAEhC,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;cAc1B,OAAO,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;CA+K9C"}
@@ -0,0 +1,166 @@
1
+ import { BaseAgent } from './base-agent';
2
+ import { ApiClient } from '../helpers/api-client';
3
+ import { resolveEnvironment } from '../helpers/env-resolver';
4
+ export class TenantIsolationAuditorAgent extends BaseAgent {
5
+ agentId = 19;
6
+ agentName = 'Tenant Isolation Auditor';
7
+ async preFlight() {
8
+ if (!this.config.tenancy.enabled) {
9
+ throw new Error('TenantIsolationAuditorAgent requires config.tenancy.enabled to be true');
10
+ }
11
+ if (this.config.tenancy.testFirms.length < 1) {
12
+ throw new Error('TenantIsolationAuditorAgent requires at least one firm in config.tenancy.testFirms');
13
+ }
14
+ }
15
+ async execute() {
16
+ const findings = [];
17
+ const { env, fallback } = await resolveEnvironment(this.config, this.phase);
18
+ if (!env) {
19
+ findings.push({
20
+ id: `${this.agentId}-no-env`,
21
+ type: 'infra-issue',
22
+ severity: 'critical',
23
+ agentId: this.agentId,
24
+ module: 'tenancy',
25
+ description: 'No environment configured — cannot run tenant isolation audit',
26
+ });
27
+ return findings;
28
+ }
29
+ const credentials = this.config.auth.credentials?.['admin'] ??
30
+ Object.values(this.config.auth.credentials ?? {})[0];
31
+ if (!credentials) {
32
+ findings.push({
33
+ id: `${this.agentId}-no-credentials`,
34
+ type: 'infra-issue',
35
+ severity: 'critical',
36
+ agentId: this.agentId,
37
+ module: 'tenancy',
38
+ description: 'No credentials configured — cannot authenticate for tenant isolation audit',
39
+ });
40
+ return findings;
41
+ }
42
+ const firmA = this.config.tenancy.testFirms[0];
43
+ const firmB = this.config.tenancy.testFirms.length > 1 ? this.config.tenancy.testFirms[1] : null;
44
+ const isolationField = this.config.tenancy.isolationField;
45
+ let client;
46
+ try {
47
+ client = await ApiClient.createAuthenticated(env.baseUrl, credentials);
48
+ }
49
+ catch (error) {
50
+ // Auth failure is always medium — indicates missing API or wrong credentials, not a tenant isolation bug
51
+ const authSeverity = 'medium';
52
+ findings.push({
53
+ id: `${this.agentId}-auth-failed`,
54
+ type: 'infra-issue',
55
+ severity: authSeverity,
56
+ agentId: this.agentId,
57
+ module: 'tenancy',
58
+ description: `Authentication failed for tenant isolation audit: ${error instanceof Error ? error.message : String(error)}`,
59
+ });
60
+ return findings;
61
+ }
62
+ // -----------------------------------------------------------------------
63
+ // Test 1: URL tampering — access resources with wrong firmId in URL
64
+ // -----------------------------------------------------------------------
65
+ const urlTamperPaths = [
66
+ `/api/clients?${isolationField}=${firmA}`,
67
+ `/api/invoices?${isolationField}=${firmA}`,
68
+ `/api/transactions?${isolationField}=${firmA}`,
69
+ ];
70
+ // Use firmB if available, otherwise try a synthetic non-existent firm
71
+ const wrongFirm = firmB ?? 'wrong-firm-99999';
72
+ for (const basePath of urlTamperPaths) {
73
+ const tamperedPath = basePath.replace(`${isolationField}=${firmA}`, `${isolationField}=${wrongFirm}`);
74
+ let response;
75
+ try {
76
+ response = await client.get(tamperedPath);
77
+ }
78
+ catch {
79
+ // Network or parse error — skip this path
80
+ continue;
81
+ }
82
+ if (response.status === 200) {
83
+ const hasData = Array.isArray(response.body)
84
+ ? response.body.length > 0
85
+ : response.body !== null && typeof response.body === 'object';
86
+ if (hasData) {
87
+ findings.push({
88
+ id: `${this.agentId}-url-tamper-${tamperedPath.replace(/[^a-zA-Z0-9]/g, '-')}`,
89
+ type: 'code-bug-security',
90
+ severity: 'critical',
91
+ agentId: this.agentId,
92
+ module: 'tenancy',
93
+ description: `URL tampering data leak: GET ${tamperedPath} returned 200 with data while authenticated as firm "${firmA}". ` +
94
+ `Firm "${wrongFirm}" data should not be accessible.`,
95
+ suggestedFix: `Enforce tenant scoping in all query handlers — always filter by the authenticated user's ${isolationField}, ignoring URL parameters.`,
96
+ });
97
+ }
98
+ }
99
+ }
100
+ // -----------------------------------------------------------------------
101
+ // Test 2: API parameter tampering — POST with different firmId
102
+ // -----------------------------------------------------------------------
103
+ const postPaths = ['/api/clients/search', '/api/invoices/search', '/api/reports/generate'];
104
+ for (const path of postPaths) {
105
+ let response;
106
+ try {
107
+ response = await client.post(path, { [isolationField]: wrongFirm, limit: 5 });
108
+ }
109
+ catch {
110
+ continue;
111
+ }
112
+ if (response.status === 200) {
113
+ const hasData = Array.isArray(response.body)
114
+ ? response.body.length > 0
115
+ : response.body !== null && typeof response.body === 'object';
116
+ if (hasData) {
117
+ findings.push({
118
+ id: `${this.agentId}-param-tamper-${path.replace(/\//g, '-')}`,
119
+ type: 'code-bug-security',
120
+ severity: 'critical',
121
+ agentId: this.agentId,
122
+ module: 'tenancy',
123
+ description: `API parameter tampering data leak: POST ${path} with ${isolationField}=${wrongFirm} returned 200 with data ` +
124
+ `while authenticated as firm "${firmA}".`,
125
+ suggestedFix: `Never trust ${isolationField} from the request body — always derive it from the authenticated user's JWT claims.`,
126
+ });
127
+ }
128
+ }
129
+ }
130
+ // -----------------------------------------------------------------------
131
+ // Test 3: Search isolation — search for firm B data while logged in as firm A
132
+ // -----------------------------------------------------------------------
133
+ if (firmB !== null) {
134
+ const searchPaths = [
135
+ { path: `/api/clients/search`, body: { query: firmB, limit: 5 } },
136
+ { path: `/api/invoices/search`, body: { query: firmB, limit: 5 } },
137
+ ];
138
+ for (const { path, body } of searchPaths) {
139
+ let response;
140
+ try {
141
+ response = await client.post(path, body);
142
+ }
143
+ catch {
144
+ continue;
145
+ }
146
+ if (response.status === 200) {
147
+ const results = Array.isArray(response.body) ? response.body : [];
148
+ if (results.length > 0) {
149
+ findings.push({
150
+ id: `${this.agentId}-search-isolation-${path.replace(/\//g, '-')}`,
151
+ type: 'code-bug-security',
152
+ severity: 'critical',
153
+ agentId: this.agentId,
154
+ module: 'tenancy',
155
+ description: `Search isolation failure: POST ${path} with query for firm "${firmB}" ` +
156
+ `returned ${results.length} result(s) while authenticated as firm "${firmA}".`,
157
+ suggestedFix: 'All search handlers must apply tenant scoping before executing the query.',
158
+ });
159
+ }
160
+ }
161
+ }
162
+ }
163
+ return findings;
164
+ }
165
+ }
166
+ //# sourceMappingURL=19-tenant-isolation-auditor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"19-tenant-isolation-auditor.js","sourceRoot":"","sources":["../../agents/19-tenant-isolation-auditor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { Finding } from '../core/types';
2
+ import { BaseAgent } from './base-agent';
3
+ export declare class WorkflowCompletionTesterAgent extends BaseAgent {
4
+ readonly agentId = 20;
5
+ readonly agentName = "Workflow Completion Tester";
6
+ private baseUrl;
7
+ protected preFlight(): Promise<void>;
8
+ protected execute(): Promise<Finding[]>;
9
+ private runWorkflow;
10
+ private executeStep;
11
+ }
12
+ //# sourceMappingURL=20-workflow-completion-tester.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"20-workflow-completion-tester.d.ts","sourceRoot":"","sources":["../../agents/20-workflow-completion-tester.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAE7C,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAMzC,qBAAa,6BAA8B,SAAQ,SAAS;IAC1D,QAAQ,CAAC,OAAO,MAAM;IACtB,QAAQ,CAAC,SAAS,gCAAgC;IAClD,OAAO,CAAC,OAAO,CAAM;cAEL,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;cAW1B,OAAO,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;YAiE/B,WAAW;YA8DX,WAAW;CAkD1B"}