@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,124 @@
1
+ import { readFile, copyFile, mkdir, stat } from 'node:fs/promises';
2
+ import { basename, join, resolve } from 'node:path';
3
+ import { createRequire } from 'node:module';
4
+ /**
5
+ * Dynamically load an optional npm package at runtime.
6
+ * Uses createRequire to avoid TypeScript static module resolution errors.
7
+ */
8
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
9
+ async function optionalRequire(packageName) {
10
+ const require = createRequire(import.meta.url);
11
+ return require(packageName);
12
+ }
13
+ function generateReportFilename(originalPath) {
14
+ const base = basename(originalPath, '.html');
15
+ const ts = new Date().toISOString().replace(/[:.]/g, '-');
16
+ return `${base}-${ts}.html`;
17
+ }
18
+ async function uploadLocal(htmlPath, config) {
19
+ const prefix = config.prefix ?? 'testteam-reports/';
20
+ const reportsDir = resolve(prefix);
21
+ await mkdir(reportsDir, { recursive: true });
22
+ const filename = generateReportFilename(htmlPath);
23
+ const destPath = join(reportsDir, filename);
24
+ await copyFile(htmlPath, destPath);
25
+ const fileStat = await stat(destPath);
26
+ const absoluteDest = resolve(destPath);
27
+ return {
28
+ url: `file://${absoluteDest.replace(/\\/g, '/')}`,
29
+ provider: 'local',
30
+ size: fileStat.size,
31
+ timestamp: Date.now(),
32
+ };
33
+ }
34
+ async function uploadS3(htmlPath, config) {
35
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
36
+ let sdk;
37
+ try {
38
+ sdk = await optionalRequire('@aws-sdk/client-s3');
39
+ }
40
+ catch {
41
+ throw new Error('Install @aws-sdk/client-s3 to use S3 uploads: npm install @aws-sdk/client-s3');
42
+ }
43
+ if (!config.bucket) {
44
+ throw new Error('S3 upload requires a bucket name in config.bucket');
45
+ }
46
+ const prefix = config.prefix ?? 'testteam-reports/';
47
+ const filename = generateReportFilename(htmlPath);
48
+ const key = `${prefix}${filename}`;
49
+ const body = await readFile(htmlPath);
50
+ const client = new sdk.S3Client({
51
+ region: config.region ?? 'us-east-1',
52
+ });
53
+ await client.send(new sdk.PutObjectCommand({
54
+ Bucket: config.bucket,
55
+ Key: key,
56
+ Body: body,
57
+ ContentType: 'text/html',
58
+ }));
59
+ const region = config.region ?? 'us-east-1';
60
+ const url = `https://${config.bucket}.s3.${region}.amazonaws.com/${key}`;
61
+ return {
62
+ url,
63
+ provider: 's3',
64
+ size: body.byteLength,
65
+ timestamp: Date.now(),
66
+ };
67
+ }
68
+ async function uploadAzureBlob(htmlPath, config) {
69
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
70
+ let sdk;
71
+ try {
72
+ sdk = await optionalRequire('@azure/storage-blob');
73
+ }
74
+ catch {
75
+ throw new Error('Install @azure/storage-blob to use Azure Blob uploads: npm install @azure/storage-blob');
76
+ }
77
+ if (!config.connectionString) {
78
+ throw new Error('Azure Blob upload requires a connectionString in config.connectionString');
79
+ }
80
+ if (!config.bucket) {
81
+ throw new Error('Azure Blob upload requires a container name in config.bucket');
82
+ }
83
+ const prefix = config.prefix ?? 'testteam-reports/';
84
+ const filename = generateReportFilename(htmlPath);
85
+ const blobName = `${prefix}${filename}`;
86
+ const body = await readFile(htmlPath);
87
+ const blobServiceClient = sdk.BlobServiceClient.fromConnectionString(config.connectionString);
88
+ const containerClient = blobServiceClient.getContainerClient(config.bucket);
89
+ await containerClient.createIfNotExists({ access: 'blob' });
90
+ const blockBlobClient = containerClient.getBlockBlobClient(blobName);
91
+ await blockBlobClient.upload(body, body.byteLength, {
92
+ blobHTTPHeaders: { blobContentType: 'text/html' },
93
+ });
94
+ return {
95
+ url: blockBlobClient.url,
96
+ provider: 'azure-blob',
97
+ size: body.byteLength,
98
+ timestamp: Date.now(),
99
+ };
100
+ }
101
+ export async function uploadReport(htmlPath, config) {
102
+ const absolutePath = resolve(htmlPath);
103
+ // Verify file exists before attempting upload
104
+ await stat(absolutePath);
105
+ switch (config.provider) {
106
+ case 'local':
107
+ return uploadLocal(absolutePath, config);
108
+ case 's3':
109
+ return uploadS3(absolutePath, config);
110
+ case 'azure-blob':
111
+ return uploadAzureBlob(absolutePath, config);
112
+ default: {
113
+ const exhaustive = config.provider;
114
+ throw new Error(`Unknown upload provider: ${String(exhaustive)}`);
115
+ }
116
+ }
117
+ }
118
+ export function getDefaultUploadConfig() {
119
+ return {
120
+ provider: 'local',
121
+ prefix: 'testteam-reports/',
122
+ };
123
+ }
124
+ //# sourceMappingURL=report-upload.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report-upload.js","sourceRoot":"","sources":["../../core/report-upload.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ export interface RunRecord {
2
+ timestamp: number;
3
+ phase: string;
4
+ configName: string;
5
+ }
6
+ export interface RunCounterState {
7
+ periodStart: number;
8
+ periodEnd: number;
9
+ runs: RunRecord[];
10
+ totalRuns: number;
11
+ }
12
+ export interface RunLimitCheck {
13
+ allowed: boolean;
14
+ used: number;
15
+ remaining: number;
16
+ warning: boolean;
17
+ }
18
+ /** Return Unix timestamp (ms) for midnight UTC on the 1st of the given date's month. */
19
+ declare function periodStartFor(date: Date): number;
20
+ /** Return Unix timestamp (ms) for 23:59:59.999 UTC on the last day of the given date's month. */
21
+ declare function periodEndFor(date: Date): number;
22
+ /** Returns the absolute path to the run-counter file inside `configDir`. */
23
+ export declare function getRunCounterPath(configDir: string): string;
24
+ /**
25
+ * Load the run counter state from disk.
26
+ * If the file does not exist or the current billing period has expired,
27
+ * a fresh state for the current month is returned (and persisted).
28
+ */
29
+ export declare function loadRunCounter(configDir: string): RunCounterState;
30
+ /** Record a pipeline run in the current billing period. */
31
+ export declare function recordRun(configDir: string, phase: string, configName: string): void;
32
+ /**
33
+ * Check whether a new run is allowed under the given monthly limit.
34
+ * `warning` is `true` when usage has reached 80 % or more of the limit.
35
+ */
36
+ export declare function checkRunLimit(configDir: string, maxRuns: number): RunLimitCheck;
37
+ /** Manually reset the run counter (admin / support use). */
38
+ export declare function resetRunCounter(configDir: string): void;
39
+ export { periodStartFor as _periodStartFor, periodEndFor as _periodEndFor };
40
+ //# sourceMappingURL=run-counter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-counter.d.ts","sourceRoot":"","sources":["../../core/run-counter.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,SAAS;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,SAAS,EAAE,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;CAClB;AAMD,wFAAwF;AACxF,iBAAS,cAAc,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAE1C;AAED,iGAAiG;AACjG,iBAAS,YAAY,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CASxC;AAmCD,4EAA4E;AAC5E,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAE3D;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,eAAe,CAgCjE;AAED,2DAA2D;AAC3D,wBAAgB,SAAS,CACvB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,MAAM,GACjB,IAAI,CAaN;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,GACd,aAAa,CAQf;AAED,4DAA4D;AAC5D,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAGvD;AAUD,OAAO,EAAE,cAAc,IAAI,eAAe,EAAE,YAAY,IAAI,aAAa,EAAE,CAAC"}
@@ -0,0 +1,120 @@
1
+ import * as fs from 'node:fs';
2
+ import * as path from 'node:path';
3
+ const RUN_COUNTER_FILENAME = '.testteam-runs.json';
4
+ // ── Period helpers ───────────────────────────────────────────────────
5
+ /** Return Unix timestamp (ms) for midnight UTC on the 1st of the given date's month. */
6
+ function periodStartFor(date) {
7
+ return Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), 1);
8
+ }
9
+ /** Return Unix timestamp (ms) for 23:59:59.999 UTC on the last day of the given date's month. */
10
+ function periodEndFor(date) {
11
+ // Month + 1, day 0 gives last day of current month
12
+ const lastDay = new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth() + 1, 0));
13
+ return Date.UTC(lastDay.getUTCFullYear(), lastDay.getUTCMonth(), lastDay.getUTCDate(), 23, 59, 59, 999);
14
+ }
15
+ function createFreshState(now) {
16
+ return {
17
+ periodStart: periodStartFor(now),
18
+ periodEnd: periodEndFor(now),
19
+ runs: [],
20
+ totalRuns: 0,
21
+ };
22
+ }
23
+ // ── Type guard ──────────────────────────────────────────────────────
24
+ function isRunCounterState(value) {
25
+ if (typeof value !== 'object' || value === null)
26
+ return false;
27
+ const obj = value;
28
+ if (typeof obj['periodStart'] !== 'number')
29
+ return false;
30
+ if (typeof obj['periodEnd'] !== 'number')
31
+ return false;
32
+ if (typeof obj['totalRuns'] !== 'number')
33
+ return false;
34
+ if (!Array.isArray(obj['runs']))
35
+ return false;
36
+ return obj['runs'].every((r) => {
37
+ if (typeof r !== 'object' || r === null)
38
+ return false;
39
+ const rec = r;
40
+ return (typeof rec['timestamp'] === 'number' &&
41
+ typeof rec['phase'] === 'string' &&
42
+ typeof rec['configName'] === 'string');
43
+ });
44
+ }
45
+ // ── Public API ──────────────────────────────────────────────────────
46
+ /** Returns the absolute path to the run-counter file inside `configDir`. */
47
+ export function getRunCounterPath(configDir) {
48
+ return path.join(configDir, RUN_COUNTER_FILENAME);
49
+ }
50
+ /**
51
+ * Load the run counter state from disk.
52
+ * If the file does not exist or the current billing period has expired,
53
+ * a fresh state for the current month is returned (and persisted).
54
+ */
55
+ export function loadRunCounter(configDir) {
56
+ const filePath = getRunCounterPath(configDir);
57
+ const now = new Date();
58
+ try {
59
+ if (!fs.existsSync(filePath)) {
60
+ const fresh = createFreshState(now);
61
+ saveRunCounter(configDir, fresh);
62
+ return fresh;
63
+ }
64
+ const raw = JSON.parse(fs.readFileSync(filePath, 'utf8'));
65
+ if (!isRunCounterState(raw)) {
66
+ const fresh = createFreshState(now);
67
+ saveRunCounter(configDir, fresh);
68
+ return fresh;
69
+ }
70
+ // Auto-reset if past the billing period
71
+ if (now.getTime() > raw.periodEnd) {
72
+ const fresh = createFreshState(now);
73
+ saveRunCounter(configDir, fresh);
74
+ return fresh;
75
+ }
76
+ return raw;
77
+ }
78
+ catch {
79
+ const fresh = createFreshState(now);
80
+ saveRunCounter(configDir, fresh);
81
+ return fresh;
82
+ }
83
+ }
84
+ /** Record a pipeline run in the current billing period. */
85
+ export function recordRun(configDir, phase, configName) {
86
+ const state = loadRunCounter(configDir);
87
+ const record = {
88
+ timestamp: Date.now(),
89
+ phase,
90
+ configName,
91
+ };
92
+ state.runs.push(record);
93
+ state.totalRuns = state.runs.length;
94
+ saveRunCounter(configDir, state);
95
+ }
96
+ /**
97
+ * Check whether a new run is allowed under the given monthly limit.
98
+ * `warning` is `true` when usage has reached 80 % or more of the limit.
99
+ */
100
+ export function checkRunLimit(configDir, maxRuns) {
101
+ const state = loadRunCounter(configDir);
102
+ const used = state.totalRuns;
103
+ const remaining = Math.max(0, maxRuns - used);
104
+ const allowed = used < maxRuns;
105
+ const warning = used >= maxRuns * 0.8;
106
+ return { allowed, used, remaining, warning };
107
+ }
108
+ /** Manually reset the run counter (admin / support use). */
109
+ export function resetRunCounter(configDir) {
110
+ const fresh = createFreshState(new Date());
111
+ saveRunCounter(configDir, fresh);
112
+ }
113
+ // ── Internal helpers ────────────────────────────────────────────────
114
+ function saveRunCounter(configDir, state) {
115
+ const filePath = getRunCounterPath(configDir);
116
+ fs.writeFileSync(filePath, JSON.stringify(state, null, 2), 'utf8');
117
+ }
118
+ // Exported for testing only
119
+ export { periodStartFor as _periodStartFor, periodEndFor as _periodEndFor };
120
+ //# sourceMappingURL=run-counter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-counter.js","sourceRoot":"","sources":["../../core/run-counter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ export type Phase = 'alpha' | 'beta' | 'uat' | 'release';
2
+ export type AgentStatus = 'pending' | 'running' | 'passed' | 'failed' | 'skipped';
3
+ export type FindingType = 'test-bug' | 'code-bug-cosmetic' | 'code-bug-logic' | 'code-bug-security' | 'infra-issue';
4
+ export type FindingSeverity = 'critical' | 'high' | 'medium' | 'low' | 'info';
5
+ export interface AgentResult {
6
+ agentId: number;
7
+ agentName: string;
8
+ phase: Phase;
9
+ status: AgentStatus;
10
+ startedAt: string;
11
+ completedAt: string;
12
+ durationMs: number;
13
+ findings: Finding[];
14
+ evidence: EvidenceItem[];
15
+ summary: string;
16
+ }
17
+ export interface Finding {
18
+ id: string;
19
+ type: FindingType;
20
+ severity: FindingSeverity;
21
+ agentId: number;
22
+ module: string;
23
+ description: string;
24
+ file?: string;
25
+ line?: number;
26
+ screenshot?: string;
27
+ consoleError?: string;
28
+ stackTrace?: string;
29
+ suggestedFix?: string;
30
+ }
31
+ export interface EvidenceItem {
32
+ type: 'screenshot' | 'log' | 'report' | 'video' | 'snapshot';
33
+ path: string;
34
+ description: string;
35
+ }
36
+ export interface PhaseGateResult {
37
+ phase: Phase;
38
+ passed: boolean;
39
+ blockingResults: AgentResult[];
40
+ advisoryResults: AgentResult[];
41
+ failedBlockingAgents: number[];
42
+ timestamp: string;
43
+ }
44
+ export interface RunState {
45
+ runId: string;
46
+ startedAt: string;
47
+ currentPhase: Phase;
48
+ phaseAttempt: number;
49
+ agentResults: Map<number, AgentResult>;
50
+ gateResults: PhaseGateResult[];
51
+ totalCost: number;
52
+ }
53
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../core/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,KAAK,GAAG,OAAO,GAAG,MAAM,GAAG,KAAK,GAAG,SAAS,CAAC;AACzD,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;AAClF,MAAM,MAAM,WAAW,GAAG,UAAU,GAAG,mBAAmB,GAAG,gBAAgB,GAAG,mBAAmB,GAAG,aAAa,CAAC;AACpH,MAAM,MAAM,eAAe,GAAG,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;AAE9E,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,KAAK,CAAC;IACb,MAAM,EAAE,WAAW,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,WAAW,CAAC;IAClB,QAAQ,EAAE,eAAe,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,YAAY,GAAG,KAAK,GAAG,QAAQ,GAAG,OAAO,GAAG,UAAU,CAAC;IAC7D,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,KAAK,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;IAChB,eAAe,EAAE,WAAW,EAAE,CAAC;IAC/B,eAAe,EAAE,WAAW,EAAE,CAAC;IAC/B,oBAAoB,EAAE,MAAM,EAAE,CAAC;IAC/B,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,KAAK,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACvC,WAAW,EAAE,eAAe,EAAE,CAAC;IAC/B,SAAS,EAAE,MAAM,CAAC;CACnB"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../core/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,30 @@
1
+ export interface ApiResponse {
2
+ status: number;
3
+ body: unknown;
4
+ headers: Record<string, string>;
5
+ durationMs: number;
6
+ }
7
+ /**
8
+ * Lightweight HTTP client for integration and API tests.
9
+ * Automatically attaches Authorization headers when a token is present
10
+ * and records response duration for every request.
11
+ */
12
+ export declare class ApiClient {
13
+ private readonly baseUrl;
14
+ private token?;
15
+ constructor(baseUrl: string, token?: string | undefined);
16
+ /**
17
+ * Creates an authenticated ApiClient by POSTing credentials to /api/auth/login
18
+ * and storing the returned JWT for subsequent requests.
19
+ */
20
+ static createAuthenticated(baseUrl: string, credentials: {
21
+ email: string;
22
+ password: string;
23
+ }): Promise<ApiClient>;
24
+ get(path: string): Promise<ApiResponse>;
25
+ post(path: string, body?: unknown): Promise<ApiResponse>;
26
+ put(path: string, body?: unknown): Promise<ApiResponse>;
27
+ delete(path: string): Promise<ApiResponse>;
28
+ private request;
29
+ }
30
+ //# sourceMappingURL=api-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-client.d.ts","sourceRoot":"","sources":["../../helpers/api-client.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,UAAU,EAAE,MAAM,CAAC;CACpB;AAQD;;;;GAIG;AACH,qBAAa,SAAS;IAElB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,KAAK,CAAC;gBADG,OAAO,EAAE,MAAM,EACxB,KAAK,CAAC,EAAE,MAAM,YAAA;IAGxB;;;OAGG;WACU,mBAAmB,CAC9B,OAAO,EAAE,MAAM,EACf,WAAW,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,GAC/C,OAAO,CAAC,SAAS,CAAC;IAgBf,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAIvC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,WAAW,CAAC;IAIxD,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,WAAW,CAAC;IAIvD,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;YAIlC,OAAO;CA+CtB"}
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Lightweight HTTP client for integration and API tests.
3
+ * Automatically attaches Authorization headers when a token is present
4
+ * and records response duration for every request.
5
+ */
6
+ export class ApiClient {
7
+ baseUrl;
8
+ token;
9
+ constructor(baseUrl, token) {
10
+ this.baseUrl = baseUrl;
11
+ this.token = token;
12
+ }
13
+ /**
14
+ * Creates an authenticated ApiClient by POSTing credentials to /api/auth/login
15
+ * and storing the returned JWT for subsequent requests.
16
+ */
17
+ static async createAuthenticated(baseUrl, credentials) {
18
+ const client = new ApiClient(baseUrl);
19
+ const response = await client.post('/api/auth/login', credentials);
20
+ const body = response.body;
21
+ const jwt = body?.access_token ?? body?.accessToken ?? body?.token;
22
+ if (!jwt) {
23
+ throw new Error(`Authentication failed: no token in response (status ${response.status})`);
24
+ }
25
+ return new ApiClient(baseUrl, String(jwt));
26
+ }
27
+ async get(path) {
28
+ return this.request('GET', path);
29
+ }
30
+ async post(path, body) {
31
+ return this.request('POST', path, body);
32
+ }
33
+ async put(path, body) {
34
+ return this.request('PUT', path, body);
35
+ }
36
+ async delete(path) {
37
+ return this.request('DELETE', path);
38
+ }
39
+ async request(method, path, body) {
40
+ const url = `${this.baseUrl}${path}`;
41
+ const headers = {
42
+ 'Content-Type': 'application/json',
43
+ };
44
+ if (this.token) {
45
+ headers['Authorization'] = `Bearer ${this.token}`;
46
+ }
47
+ const init = {
48
+ method,
49
+ headers,
50
+ };
51
+ if (body !== undefined) {
52
+ init.body = JSON.stringify(body);
53
+ }
54
+ const start = Date.now();
55
+ const response = await fetch(url, init);
56
+ const durationMs = Date.now() - start;
57
+ const responseHeaders = {};
58
+ response.headers.forEach((value, key) => {
59
+ responseHeaders[key] = value;
60
+ });
61
+ let responseBody;
62
+ const contentType = response.headers.get('content-type') ?? '';
63
+ if (contentType.includes('application/json')) {
64
+ responseBody = await response.json();
65
+ }
66
+ else {
67
+ responseBody = await response.text();
68
+ }
69
+ return {
70
+ status: response.status,
71
+ body: responseBody,
72
+ headers: responseHeaders,
73
+ durationMs,
74
+ };
75
+ }
76
+ }
77
+ //# sourceMappingURL=api-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-client.js","sourceRoot":"","sources":["../../helpers/api-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import type { Page } from 'playwright';
2
+ export interface DiscoveredElement {
3
+ selector: string;
4
+ type: 'button' | 'link' | 'input' | 'select' | 'textarea' | 'tab' | 'menuitem' | 'other';
5
+ text: string;
6
+ isDestructive: boolean;
7
+ ariaLabel?: string;
8
+ }
9
+ /**
10
+ * Returns true when the given text (lowercased) contains any destructive keyword.
11
+ */
12
+ export declare function classifyAsDestructive(text: string): boolean;
13
+ /**
14
+ * Discovers all interactive elements on the given Playwright page and returns
15
+ * a deduplicated, classified list with unique selectors.
16
+ */
17
+ export declare function discoverInteractiveElements(page: Page): Promise<DiscoveredElement[]>;
18
+ //# sourceMappingURL=element-discovery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"element-discovery.d.ts","sourceRoot":"","sources":["../../helpers/element-discovery.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAEvC,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,UAAU,GAAG,KAAK,GAAG,UAAU,GAAG,OAAO,CAAC;IACzF,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,OAAO,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAKD;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAG3D;AAyCD;;;GAGG;AACH,wBAAsB,2BAA2B,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAwC1F"}
@@ -0,0 +1,82 @@
1
+ // Keywords that indicate a destructive action
2
+ const DESTRUCTIVE_KEYWORDS = ['delete', 'remove', 'archive', 'destroy', 'clear', 'reset'];
3
+ /**
4
+ * Returns true when the given text (lowercased) contains any destructive keyword.
5
+ */
6
+ export function classifyAsDestructive(text) {
7
+ const lower = text.toLowerCase();
8
+ return DESTRUCTIVE_KEYWORDS.some((keyword) => lower.includes(keyword));
9
+ }
10
+ // CSS selectors targeting all interactive element categories
11
+ const INTERACTIVE_SELECTORS = [
12
+ 'button',
13
+ 'a[href]',
14
+ 'input',
15
+ 'select',
16
+ 'textarea',
17
+ '[role="button"]',
18
+ '[role="tab"]',
19
+ '[role="menuitem"]',
20
+ '[data-testid]',
21
+ '[aria-haspopup]',
22
+ ].join(', ');
23
+ function resolveType(tag, role) {
24
+ if (role === 'tab')
25
+ return 'tab';
26
+ if (role === 'menuitem')
27
+ return 'menuitem';
28
+ if (role === 'button' || tag === 'button')
29
+ return 'button';
30
+ if (tag === 'a')
31
+ return 'link';
32
+ if (tag === 'input')
33
+ return 'input';
34
+ if (tag === 'select')
35
+ return 'select';
36
+ if (tag === 'textarea')
37
+ return 'textarea';
38
+ return 'other';
39
+ }
40
+ function buildSelector(testId, ariaLabel, tag, text) {
41
+ if (testId)
42
+ return `[data-testid="${testId}"]`;
43
+ if (ariaLabel)
44
+ return `[aria-label="${ariaLabel}"]`;
45
+ const safeSuffix = text.trim().slice(0, 40).replace(/"/g, '\\"');
46
+ return safeSuffix ? `${tag}:text("${safeSuffix}")` : tag;
47
+ }
48
+ /**
49
+ * Discovers all interactive elements on the given Playwright page and returns
50
+ * a deduplicated, classified list with unique selectors.
51
+ */
52
+ export async function discoverInteractiveElements(page) {
53
+ const rawElements = await page.evaluate((selector) => {
54
+ const nodes = Array.from(document.querySelectorAll(selector));
55
+ return nodes.map((el) => ({
56
+ tag: el.tagName.toLowerCase(),
57
+ role: el.getAttribute('role') ?? '',
58
+ text: (el.textContent ?? '').trim(),
59
+ ariaLabel: el.getAttribute('aria-label'),
60
+ testId: el.getAttribute('data-testid'),
61
+ }));
62
+ }, INTERACTIVE_SELECTORS);
63
+ const seenSelectors = new Set();
64
+ const discovered = [];
65
+ for (const raw of rawElements) {
66
+ const selector = buildSelector(raw.testId, raw.ariaLabel, raw.tag, raw.text);
67
+ if (seenSelectors.has(selector))
68
+ continue;
69
+ seenSelectors.add(selector);
70
+ const labelText = raw.ariaLabel ?? raw.text;
71
+ const discovered_element = {
72
+ selector,
73
+ type: resolveType(raw.tag, raw.role),
74
+ text: raw.text,
75
+ isDestructive: classifyAsDestructive(labelText),
76
+ ...(raw.ariaLabel !== null ? { ariaLabel: raw.ariaLabel } : {}),
77
+ };
78
+ discovered.push(discovered_element);
79
+ }
80
+ return discovered;
81
+ }
82
+ //# sourceMappingURL=element-discovery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"element-discovery.js","sourceRoot":"","sources":["../../helpers/element-discovery.ts"],"names":[],"mappings":"AAUA,8CAA8C;AAC9C,MAAM,oBAAoB,GAAG,CAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;AAE1F;;GAEG;AACH,MAAM,UAAU,qBAAqB,CAAC,IAAY;IAChD,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;IACjC,OAAO,oBAAoB,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;AACzE,CAAC;AAED,6DAA6D;AAC7D,MAAM,qBAAqB,GAAG;IAC5B,QAAQ;IACR,SAAS;IACT,OAAO;IACP,QAAQ;IACR,UAAU;IACV,iBAAiB;IACjB,cAAc;IACd,mBAAmB;IACnB,eAAe;IACf,iBAAiB;CAClB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAIb,SAAS,WAAW,CAAC,GAAW,EAAE,IAAY;IAC5C,IAAI,IAAI,KAAK,KAAK;QAAE,OAAO,KAAK,CAAC;IACjC,IAAI,IAAI,KAAK,UAAU;QAAE,OAAO,UAAU,CAAC;IAC3C,IAAI,IAAI,KAAK,QAAQ,IAAI,GAAG,KAAK,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAC3D,IAAI,GAAG,KAAK,GAAG;QAAE,OAAO,MAAM,CAAC;IAC/B,IAAI,GAAG,KAAK,OAAO;QAAE,OAAO,OAAO,CAAC;IACpC,IAAI,GAAG,KAAK,QAAQ;QAAE,OAAO,QAAQ,CAAC;IACtC,IAAI,GAAG,KAAK,UAAU;QAAE,OAAO,UAAU,CAAC;IAC1C,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,aAAa,CACpB,MAAqB,EACrB,SAAwB,EACxB,GAAW,EACX,IAAY;IAEZ,IAAI,MAAM;QAAE,OAAO,iBAAiB,MAAM,IAAI,CAAC;IAC/C,IAAI,SAAS;QAAE,OAAO,gBAAgB,SAAS,IAAI,CAAC;IACpD,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IACjE,OAAO,UAAU,CAAC,CAAC,CAAC,GAAG,GAAG,UAAU,UAAU,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC;AAC3D,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,2BAA2B,CAAC,IAAU;IAS1D,MAAM,WAAW,GAAiB,MAAM,IAAI,CAAC,QAAQ,CAAC,CAAC,QAAgB,EAAE,EAAE;QACzE,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC,CAAC;QAC9D,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;YACxB,GAAG,EAAE,EAAE,CAAC,OAAO,CAAC,WAAW,EAAE;YAC7B,IAAI,EAAE,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,EAAE;YACnC,IAAI,EAAE,CAAC,EAAE,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE;YACnC,SAAS,EAAE,EAAE,CAAC,YAAY,CAAC,YAAY,CAAC;YACxC,MAAM,EAAE,EAAE,CAAC,YAAY,CAAC,aAAa,CAAC;SACvC,CAAC,CAAC,CAAC;IACN,CAAC,EAAE,qBAAqB,CAAC,CAAC;IAE1B,MAAM,aAAa,GAAG,IAAI,GAAG,EAAU,CAAC;IACxC,MAAM,UAAU,GAAwB,EAAE,CAAC;IAE3C,KAAK,MAAM,GAAG,IAAI,WAAW,EAAE,CAAC;QAC9B,MAAM,QAAQ,GAAG,aAAa,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,SAAS,EAAE,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;QAC7E,IAAI,aAAa,CAAC,GAAG,CAAC,QAAQ,CAAC;YAAE,SAAS;QAC1C,aAAa,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAE5B,MAAM,SAAS,GAAG,GAAG,CAAC,SAAS,IAAI,GAAG,CAAC,IAAI,CAAC;QAC5C,MAAM,kBAAkB,GAAsB;YAC5C,QAAQ;YACR,IAAI,EAAE,WAAW,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC;YACpC,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,aAAa,EAAE,qBAAqB,CAAC,SAAS,CAAC;YAC/C,GAAG,CAAC,GAAG,CAAC,SAAS,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,GAAG,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAChE,CAAC;QACF,UAAU,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;IACtC,CAAC;IAED,OAAO,UAAU,CAAC;AACpB,CAAC"}
@@ -0,0 +1,29 @@
1
+ import type { ValidatedConfig } from '../core/config';
2
+ import type { Phase } from '../core/types';
3
+ interface EnvironmentConfig {
4
+ baseUrl: string;
5
+ seed?: boolean;
6
+ }
7
+ interface ResolvedEnvironment {
8
+ env: EnvironmentConfig;
9
+ /** True when the phase's configured URL was unreachable and we fell back to alpha. */
10
+ fallback: boolean;
11
+ }
12
+ /**
13
+ * Check whether a URL responds with a non-5xx status within a timeout.
14
+ * Exported so agents can use it directly without duplicating the function.
15
+ */
16
+ export declare function isUrlReachable(url: string, timeoutMs?: number): Promise<boolean>;
17
+ /**
18
+ * Resolve the environment for a given phase with automatic fallback.
19
+ *
20
+ * 1. Try the phase's configured environment (`config.environments[phase]`).
21
+ * 2. If the URL is reachable → return `{ env, fallback: false }`.
22
+ * 3. If unreachable → try `config.environments['alpha']` (localhost).
23
+ * 4. If alpha is reachable → return `{ env: alphaEnv, fallback: true }`.
24
+ * 5. If neither is reachable → return the phase's env with `fallback: false`
25
+ * so the agent can decide how to handle the failure.
26
+ */
27
+ export declare function resolveEnvironment(config: ValidatedConfig, phase: Phase): Promise<ResolvedEnvironment>;
28
+ export {};
29
+ //# sourceMappingURL=env-resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env-resolver.d.ts","sourceRoot":"","sources":["../../helpers/env-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAE3C,UAAU,iBAAiB;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,UAAU,mBAAmB;IAC3B,GAAG,EAAE,iBAAiB,CAAC;IACvB,sFAAsF;IACtF,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,SAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAUpF;AAED;;;;;;;;;GASG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,eAAe,EACvB,KAAK,EAAE,KAAK,GACX,OAAO,CAAC,mBAAmB,CAAC,CAyB9B"}