agentic-qe 3.3.0 → 3.3.1

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 (367) hide show
  1. package/README.md +6 -2
  2. package/package.json +6 -1
  3. package/v3/CHANGELOG.md +88 -0
  4. package/v3/dist/cli/bundle.js +18794 -15534
  5. package/v3/dist/cli/command-registry.d.ts +55 -0
  6. package/v3/dist/cli/command-registry.d.ts.map +1 -0
  7. package/v3/dist/cli/command-registry.js +103 -0
  8. package/v3/dist/cli/command-registry.js.map +1 -0
  9. package/v3/dist/cli/commands/code.d.ts +9 -0
  10. package/v3/dist/cli/commands/code.d.ts.map +1 -0
  11. package/v3/dist/cli/commands/code.js +254 -0
  12. package/v3/dist/cli/commands/code.js.map +1 -0
  13. package/v3/dist/cli/commands/completions.d.ts +8 -0
  14. package/v3/dist/cli/commands/completions.d.ts.map +1 -0
  15. package/v3/dist/cli/commands/completions.js +99 -0
  16. package/v3/dist/cli/commands/completions.js.map +1 -0
  17. package/v3/dist/cli/commands/coverage.d.ts +9 -0
  18. package/v3/dist/cli/commands/coverage.d.ts.map +1 -0
  19. package/v3/dist/cli/commands/coverage.js +208 -0
  20. package/v3/dist/cli/commands/coverage.js.map +1 -0
  21. package/v3/dist/cli/commands/fleet.d.ts +11 -0
  22. package/v3/dist/cli/commands/fleet.d.ts.map +1 -0
  23. package/v3/dist/cli/commands/fleet.js +338 -0
  24. package/v3/dist/cli/commands/fleet.js.map +1 -0
  25. package/v3/dist/cli/commands/migrate.d.ts +9 -0
  26. package/v3/dist/cli/commands/migrate.d.ts.map +1 -0
  27. package/v3/dist/cli/commands/migrate.js +566 -0
  28. package/v3/dist/cli/commands/migrate.js.map +1 -0
  29. package/v3/dist/cli/commands/quality.d.ts +9 -0
  30. package/v3/dist/cli/commands/quality.d.ts.map +1 -0
  31. package/v3/dist/cli/commands/quality.js +40 -0
  32. package/v3/dist/cli/commands/quality.js.map +1 -0
  33. package/v3/dist/cli/commands/security.d.ts +9 -0
  34. package/v3/dist/cli/commands/security.d.ts.map +1 -0
  35. package/v3/dist/cli/commands/security.js +124 -0
  36. package/v3/dist/cli/commands/security.js.map +1 -0
  37. package/v3/dist/cli/commands/sync.d.ts +19 -0
  38. package/v3/dist/cli/commands/sync.d.ts.map +1 -0
  39. package/v3/dist/cli/commands/sync.js +283 -0
  40. package/v3/dist/cli/commands/sync.js.map +1 -0
  41. package/v3/dist/cli/commands/test.d.ts +9 -0
  42. package/v3/dist/cli/commands/test.d.ts.map +1 -0
  43. package/v3/dist/cli/commands/test.js +166 -0
  44. package/v3/dist/cli/commands/test.js.map +1 -0
  45. package/v3/dist/cli/handlers/agent-handler.d.ts +20 -0
  46. package/v3/dist/cli/handlers/agent-handler.d.ts.map +1 -0
  47. package/v3/dist/cli/handlers/agent-handler.js +158 -0
  48. package/v3/dist/cli/handlers/agent-handler.js.map +1 -0
  49. package/v3/dist/cli/handlers/domain-handler.d.ts +20 -0
  50. package/v3/dist/cli/handlers/domain-handler.d.ts.map +1 -0
  51. package/v3/dist/cli/handlers/domain-handler.js +115 -0
  52. package/v3/dist/cli/handlers/domain-handler.js.map +1 -0
  53. package/v3/dist/cli/handlers/index.d.ts +13 -0
  54. package/v3/dist/cli/handlers/index.d.ts.map +1 -0
  55. package/v3/dist/cli/handlers/index.js +15 -0
  56. package/v3/dist/cli/handlers/index.js.map +1 -0
  57. package/v3/dist/cli/handlers/init-handler.d.ts +38 -0
  58. package/v3/dist/cli/handlers/init-handler.d.ts.map +1 -0
  59. package/v3/dist/cli/handlers/init-handler.js +288 -0
  60. package/v3/dist/cli/handlers/init-handler.js.map +1 -0
  61. package/v3/dist/cli/handlers/interfaces.d.ts +104 -0
  62. package/v3/dist/cli/handlers/interfaces.d.ts.map +1 -0
  63. package/v3/dist/cli/handlers/interfaces.js +109 -0
  64. package/v3/dist/cli/handlers/interfaces.js.map +1 -0
  65. package/v3/dist/cli/handlers/protocol-handler.d.ts +19 -0
  66. package/v3/dist/cli/handlers/protocol-handler.d.ts.map +1 -0
  67. package/v3/dist/cli/handlers/protocol-handler.js +79 -0
  68. package/v3/dist/cli/handlers/protocol-handler.js.map +1 -0
  69. package/v3/dist/cli/handlers/status-handler.d.ts +30 -0
  70. package/v3/dist/cli/handlers/status-handler.d.ts.map +1 -0
  71. package/v3/dist/cli/handlers/status-handler.js +218 -0
  72. package/v3/dist/cli/handlers/status-handler.js.map +1 -0
  73. package/v3/dist/cli/handlers/task-handler.d.ts +22 -0
  74. package/v3/dist/cli/handlers/task-handler.d.ts.map +1 -0
  75. package/v3/dist/cli/handlers/task-handler.js +271 -0
  76. package/v3/dist/cli/handlers/task-handler.js.map +1 -0
  77. package/v3/dist/cli/index.d.ts +4 -0
  78. package/v3/dist/cli/index.d.ts.map +1 -1
  79. package/v3/dist/cli/index.js +48 -2677
  80. package/v3/dist/cli/index.js.map +1 -1
  81. package/v3/dist/cli/wizards/core/index.d.ts +11 -0
  82. package/v3/dist/cli/wizards/core/index.d.ts.map +1 -0
  83. package/v3/dist/cli/wizards/core/index.js +15 -0
  84. package/v3/dist/cli/wizards/core/index.js.map +1 -0
  85. package/v3/dist/cli/wizards/core/wizard-base.d.ts +87 -0
  86. package/v3/dist/cli/wizards/core/wizard-base.d.ts.map +1 -0
  87. package/v3/dist/cli/wizards/core/wizard-base.js +120 -0
  88. package/v3/dist/cli/wizards/core/wizard-base.js.map +1 -0
  89. package/v3/dist/cli/wizards/core/wizard-command.d.ts +182 -0
  90. package/v3/dist/cli/wizards/core/wizard-command.d.ts.map +1 -0
  91. package/v3/dist/cli/wizards/core/wizard-command.js +45 -0
  92. package/v3/dist/cli/wizards/core/wizard-command.js.map +1 -0
  93. package/v3/dist/cli/wizards/core/wizard-step.d.ts +109 -0
  94. package/v3/dist/cli/wizards/core/wizard-step.d.ts.map +1 -0
  95. package/v3/dist/cli/wizards/core/wizard-step.js +384 -0
  96. package/v3/dist/cli/wizards/core/wizard-step.js.map +1 -0
  97. package/v3/dist/cli/wizards/core/wizard-utils.d.ts +117 -0
  98. package/v3/dist/cli/wizards/core/wizard-utils.d.ts.map +1 -0
  99. package/v3/dist/cli/wizards/core/wizard-utils.js +291 -0
  100. package/v3/dist/cli/wizards/core/wizard-utils.js.map +1 -0
  101. package/v3/dist/cli/wizards/coverage-wizard.d.ts +13 -68
  102. package/v3/dist/cli/wizards/coverage-wizard.d.ts.map +1 -1
  103. package/v3/dist/cli/wizards/coverage-wizard.js +127 -391
  104. package/v3/dist/cli/wizards/coverage-wizard.js.map +1 -1
  105. package/v3/dist/cli/wizards/fleet-wizard.d.ts +13 -64
  106. package/v3/dist/cli/wizards/fleet-wizard.d.ts.map +1 -1
  107. package/v3/dist/cli/wizards/fleet-wizard.js +150 -363
  108. package/v3/dist/cli/wizards/fleet-wizard.js.map +1 -1
  109. package/v3/dist/cli/wizards/index.d.ts +2 -0
  110. package/v3/dist/cli/wizards/index.d.ts.map +1 -1
  111. package/v3/dist/cli/wizards/index.js +3 -0
  112. package/v3/dist/cli/wizards/index.js.map +1 -1
  113. package/v3/dist/cli/wizards/security-wizard.d.ts +13 -64
  114. package/v3/dist/cli/wizards/security-wizard.d.ts.map +1 -1
  115. package/v3/dist/cli/wizards/security-wizard.js +152 -395
  116. package/v3/dist/cli/wizards/security-wizard.js.map +1 -1
  117. package/v3/dist/cli/wizards/test-wizard.d.ts +13 -77
  118. package/v3/dist/cli/wizards/test-wizard.d.ts.map +1 -1
  119. package/v3/dist/cli/wizards/test-wizard.js +196 -328
  120. package/v3/dist/cli/wizards/test-wizard.js.map +1 -1
  121. package/v3/dist/coordination/mincut/mincut-health-monitor.d.ts +3 -0
  122. package/v3/dist/coordination/mincut/mincut-health-monitor.d.ts.map +1 -1
  123. package/v3/dist/coordination/mincut/mincut-health-monitor.js +6 -2
  124. package/v3/dist/coordination/mincut/mincut-health-monitor.js.map +1 -1
  125. package/v3/dist/coordination/mincut/queen-integration.d.ts +3 -0
  126. package/v3/dist/coordination/mincut/queen-integration.d.ts.map +1 -1
  127. package/v3/dist/coordination/mincut/queen-integration.js +6 -1
  128. package/v3/dist/coordination/mincut/queen-integration.js.map +1 -1
  129. package/v3/dist/coordination/task-executor.js +2 -2
  130. package/v3/dist/coordination/task-executor.js.map +1 -1
  131. package/v3/dist/domains/chaos-resilience/plugin.js +2 -2
  132. package/v3/dist/domains/chaos-resilience/plugin.js.map +1 -1
  133. package/v3/dist/domains/code-intelligence/plugin.js +2 -2
  134. package/v3/dist/domains/code-intelligence/plugin.js.map +1 -1
  135. package/v3/dist/domains/contract-testing/plugin.js +2 -2
  136. package/v3/dist/domains/contract-testing/plugin.js.map +1 -1
  137. package/v3/dist/domains/coverage-analysis/plugin.d.ts.map +1 -1
  138. package/v3/dist/domains/coverage-analysis/plugin.js +2 -1
  139. package/v3/dist/domains/coverage-analysis/plugin.js.map +1 -1
  140. package/v3/dist/domains/defect-intelligence/plugin.js +2 -2
  141. package/v3/dist/domains/defect-intelligence/plugin.js.map +1 -1
  142. package/v3/dist/domains/domain-interface.d.ts.map +1 -1
  143. package/v3/dist/domains/domain-interface.js +3 -1
  144. package/v3/dist/domains/domain-interface.js.map +1 -1
  145. package/v3/dist/domains/learning-optimization/plugin.js +2 -2
  146. package/v3/dist/domains/learning-optimization/plugin.js.map +1 -1
  147. package/v3/dist/domains/quality-assessment/plugin.js +2 -2
  148. package/v3/dist/domains/quality-assessment/plugin.js.map +1 -1
  149. package/v3/dist/domains/requirements-validation/plugin.js +2 -2
  150. package/v3/dist/domains/requirements-validation/plugin.js.map +1 -1
  151. package/v3/dist/domains/security-compliance/plugin.js +2 -2
  152. package/v3/dist/domains/security-compliance/plugin.js.map +1 -1
  153. package/v3/dist/domains/test-execution/index.d.ts +2 -1
  154. package/v3/dist/domains/test-execution/index.d.ts.map +1 -1
  155. package/v3/dist/domains/test-execution/index.js +0 -2
  156. package/v3/dist/domains/test-execution/index.js.map +1 -1
  157. package/v3/dist/domains/test-execution/interfaces.d.ts +222 -25
  158. package/v3/dist/domains/test-execution/interfaces.d.ts.map +1 -1
  159. package/v3/dist/domains/test-execution/interfaces.js +130 -3
  160. package/v3/dist/domains/test-execution/interfaces.js.map +1 -1
  161. package/v3/dist/domains/test-execution/plugin.d.ts.map +1 -1
  162. package/v3/dist/domains/test-execution/plugin.js +2 -1
  163. package/v3/dist/domains/test-execution/plugin.js.map +1 -1
  164. package/v3/dist/domains/test-execution/test-prioritization-types.d.ts +5 -172
  165. package/v3/dist/domains/test-execution/test-prioritization-types.d.ts.map +1 -1
  166. package/v3/dist/domains/test-execution/test-prioritization-types.js +6 -129
  167. package/v3/dist/domains/test-execution/test-prioritization-types.js.map +1 -1
  168. package/v3/dist/domains/test-execution/types/index.d.ts +7 -3
  169. package/v3/dist/domains/test-execution/types/index.d.ts.map +1 -1
  170. package/v3/dist/domains/test-execution/types/index.js +7 -17
  171. package/v3/dist/domains/test-execution/types/index.js.map +1 -1
  172. package/v3/dist/domains/test-generation/coordinator.d.ts +1 -1
  173. package/v3/dist/domains/test-generation/coordinator.d.ts.map +1 -1
  174. package/v3/dist/domains/test-generation/coordinator.js +3 -3
  175. package/v3/dist/domains/test-generation/coordinator.js.map +1 -1
  176. package/v3/dist/domains/test-generation/factories/index.d.ts +8 -0
  177. package/v3/dist/domains/test-generation/factories/index.d.ts.map +1 -0
  178. package/v3/dist/domains/test-generation/factories/index.js +8 -0
  179. package/v3/dist/domains/test-generation/factories/index.js.map +1 -0
  180. package/v3/dist/domains/test-generation/factories/test-generator-factory.d.ts +108 -0
  181. package/v3/dist/domains/test-generation/factories/test-generator-factory.d.ts.map +1 -0
  182. package/v3/dist/domains/test-generation/factories/test-generator-factory.js +158 -0
  183. package/v3/dist/domains/test-generation/factories/test-generator-factory.js.map +1 -0
  184. package/v3/dist/domains/test-generation/generators/base-test-generator.d.ts +79 -0
  185. package/v3/dist/domains/test-generation/generators/base-test-generator.d.ts.map +1 -0
  186. package/v3/dist/domains/test-generation/generators/base-test-generator.js +252 -0
  187. package/v3/dist/domains/test-generation/generators/base-test-generator.js.map +1 -0
  188. package/v3/dist/domains/test-generation/generators/index.d.ts +11 -0
  189. package/v3/dist/domains/test-generation/generators/index.d.ts.map +1 -0
  190. package/v3/dist/domains/test-generation/generators/index.js +13 -0
  191. package/v3/dist/domains/test-generation/generators/index.js.map +1 -0
  192. package/v3/dist/domains/test-generation/generators/jest-vitest-generator.d.ts +77 -0
  193. package/v3/dist/domains/test-generation/generators/jest-vitest-generator.d.ts.map +1 -0
  194. package/v3/dist/domains/test-generation/generators/jest-vitest-generator.js +365 -0
  195. package/v3/dist/domains/test-generation/generators/jest-vitest-generator.js.map +1 -0
  196. package/v3/dist/domains/test-generation/generators/mocha-generator.d.ts +56 -0
  197. package/v3/dist/domains/test-generation/generators/mocha-generator.d.ts.map +1 -0
  198. package/v3/dist/domains/test-generation/generators/mocha-generator.js +197 -0
  199. package/v3/dist/domains/test-generation/generators/mocha-generator.js.map +1 -0
  200. package/v3/dist/domains/test-generation/generators/pytest-generator.d.ts +66 -0
  201. package/v3/dist/domains/test-generation/generators/pytest-generator.d.ts.map +1 -0
  202. package/v3/dist/domains/test-generation/generators/pytest-generator.js +240 -0
  203. package/v3/dist/domains/test-generation/generators/pytest-generator.js.map +1 -0
  204. package/v3/dist/domains/test-generation/index.d.ts +2 -2
  205. package/v3/dist/domains/test-generation/index.d.ts.map +1 -1
  206. package/v3/dist/domains/test-generation/index.js +3 -3
  207. package/v3/dist/domains/test-generation/index.js.map +1 -1
  208. package/v3/dist/domains/test-generation/interfaces/index.d.ts +9 -0
  209. package/v3/dist/domains/test-generation/interfaces/index.d.ts.map +1 -0
  210. package/v3/dist/domains/test-generation/interfaces/index.js +9 -0
  211. package/v3/dist/domains/test-generation/interfaces/index.js.map +1 -0
  212. package/v3/dist/domains/test-generation/interfaces/test-generator.interface.d.ts +166 -0
  213. package/v3/dist/domains/test-generation/interfaces/test-generator.interface.d.ts.map +1 -0
  214. package/v3/dist/domains/test-generation/interfaces/test-generator.interface.js +8 -0
  215. package/v3/dist/domains/test-generation/interfaces/test-generator.interface.js.map +1 -0
  216. package/v3/dist/domains/test-generation/interfaces.d.ts +163 -24
  217. package/v3/dist/domains/test-generation/interfaces.d.ts.map +1 -1
  218. package/v3/dist/domains/test-generation/interfaces.js +2 -2
  219. package/v3/dist/domains/test-generation/plugin.d.ts.map +1 -1
  220. package/v3/dist/domains/test-generation/plugin.js +6 -5
  221. package/v3/dist/domains/test-generation/plugin.js.map +1 -1
  222. package/v3/dist/domains/test-generation/{coherence-gate.d.ts → services/coherence-gate-service.d.ts} +4 -4
  223. package/v3/dist/domains/test-generation/services/coherence-gate-service.d.ts.map +1 -0
  224. package/v3/dist/domains/test-generation/{coherence-gate.js → services/coherence-gate-service.js} +2 -2
  225. package/v3/dist/domains/test-generation/services/coherence-gate-service.js.map +1 -0
  226. package/v3/dist/domains/test-generation/services/index.d.ts +8 -2
  227. package/v3/dist/domains/test-generation/services/index.d.ts.map +1 -1
  228. package/v3/dist/domains/test-generation/services/index.js +10 -3
  229. package/v3/dist/domains/test-generation/services/index.js.map +1 -1
  230. package/v3/dist/domains/test-generation/services/property-test-generator.d.ts +34 -0
  231. package/v3/dist/domains/test-generation/services/property-test-generator.d.ts.map +1 -0
  232. package/v3/dist/domains/test-generation/services/property-test-generator.js +306 -0
  233. package/v3/dist/domains/test-generation/services/property-test-generator.js.map +1 -0
  234. package/v3/dist/domains/test-generation/services/tdd-generator.d.ts +33 -0
  235. package/v3/dist/domains/test-generation/services/tdd-generator.d.ts.map +1 -0
  236. package/v3/dist/domains/test-generation/services/tdd-generator.js +342 -0
  237. package/v3/dist/domains/test-generation/services/tdd-generator.js.map +1 -0
  238. package/v3/dist/domains/test-generation/services/test-data-generator.d.ts +34 -0
  239. package/v3/dist/domains/test-generation/services/test-data-generator.d.ts.map +1 -0
  240. package/v3/dist/domains/test-generation/services/test-data-generator.js +245 -0
  241. package/v3/dist/domains/test-generation/services/test-data-generator.js.map +1 -0
  242. package/v3/dist/domains/test-generation/services/test-generator.d.ts +51 -160
  243. package/v3/dist/domains/test-generation/services/test-generator.d.ts.map +1 -1
  244. package/v3/dist/domains/test-generation/services/test-generator.js +101 -1858
  245. package/v3/dist/domains/test-generation/services/test-generator.js.map +1 -1
  246. package/v3/dist/domains/visual-accessibility/plugin.js +2 -2
  247. package/v3/dist/domains/visual-accessibility/plugin.js.map +1 -1
  248. package/v3/dist/init/phases/12-verification.d.ts +23 -0
  249. package/v3/dist/init/phases/12-verification.d.ts.map +1 -1
  250. package/v3/dist/init/phases/12-verification.js +185 -2
  251. package/v3/dist/init/phases/12-verification.js.map +1 -1
  252. package/v3/dist/integrations/agentic-flow/model-router/complexity-analyzer.d.ts +24 -62
  253. package/v3/dist/integrations/agentic-flow/model-router/complexity-analyzer.d.ts.map +1 -1
  254. package/v3/dist/integrations/agentic-flow/model-router/complexity-analyzer.js +45 -497
  255. package/v3/dist/integrations/agentic-flow/model-router/complexity-analyzer.js.map +1 -1
  256. package/v3/dist/integrations/agentic-flow/model-router/router.js +2 -2
  257. package/v3/dist/integrations/agentic-flow/model-router/router.js.map +1 -1
  258. package/v3/dist/integrations/agentic-flow/model-router/score-calculator.d.ts +98 -0
  259. package/v3/dist/integrations/agentic-flow/model-router/score-calculator.d.ts.map +1 -0
  260. package/v3/dist/integrations/agentic-flow/model-router/score-calculator.js +197 -0
  261. package/v3/dist/integrations/agentic-flow/model-router/score-calculator.js.map +1 -0
  262. package/v3/dist/integrations/agentic-flow/model-router/signal-collector.d.ts +102 -0
  263. package/v3/dist/integrations/agentic-flow/model-router/signal-collector.d.ts.map +1 -0
  264. package/v3/dist/integrations/agentic-flow/model-router/signal-collector.js +372 -0
  265. package/v3/dist/integrations/agentic-flow/model-router/signal-collector.js.map +1 -0
  266. package/v3/dist/integrations/agentic-flow/model-router/tier-recommender.d.ts +64 -0
  267. package/v3/dist/integrations/agentic-flow/model-router/tier-recommender.d.ts.map +1 -0
  268. package/v3/dist/integrations/agentic-flow/model-router/tier-recommender.js +120 -0
  269. package/v3/dist/integrations/agentic-flow/model-router/tier-recommender.js.map +1 -0
  270. package/v3/dist/integrations/coherence/coherence-service.d.ts.map +1 -1
  271. package/v3/dist/integrations/coherence/coherence-service.js +87 -30
  272. package/v3/dist/integrations/coherence/coherence-service.js.map +1 -1
  273. package/v3/dist/integrations/coherence/engines/spectral-adapter.d.ts.map +1 -1
  274. package/v3/dist/integrations/coherence/engines/spectral-adapter.js +124 -35
  275. package/v3/dist/integrations/coherence/engines/spectral-adapter.js.map +1 -1
  276. package/v3/dist/learning/memory-auditor.d.ts.map +1 -1
  277. package/v3/dist/learning/memory-auditor.js +3 -1
  278. package/v3/dist/learning/memory-auditor.js.map +1 -1
  279. package/v3/dist/mcp/bundle.js +2475 -1463
  280. package/v3/dist/mcp/security/cve-prevention.d.ts +31 -134
  281. package/v3/dist/mcp/security/cve-prevention.d.ts.map +1 -1
  282. package/v3/dist/mcp/security/cve-prevention.js +37 -562
  283. package/v3/dist/mcp/security/cve-prevention.js.map +1 -1
  284. package/v3/dist/mcp/security/index.d.ts +5 -1
  285. package/v3/dist/mcp/security/index.d.ts.map +1 -1
  286. package/v3/dist/mcp/security/validators/command-validator.d.ts +41 -0
  287. package/v3/dist/mcp/security/validators/command-validator.d.ts.map +1 -0
  288. package/v3/dist/mcp/security/validators/command-validator.js +123 -0
  289. package/v3/dist/mcp/security/validators/command-validator.js.map +1 -0
  290. package/v3/dist/mcp/security/validators/crypto-validator.d.ts +40 -0
  291. package/v3/dist/mcp/security/validators/crypto-validator.d.ts.map +1 -0
  292. package/v3/dist/mcp/security/validators/crypto-validator.js +72 -0
  293. package/v3/dist/mcp/security/validators/crypto-validator.js.map +1 -0
  294. package/v3/dist/mcp/security/validators/index.d.ts +12 -0
  295. package/v3/dist/mcp/security/validators/index.d.ts.map +1 -0
  296. package/v3/dist/mcp/security/validators/index.js +22 -0
  297. package/v3/dist/mcp/security/validators/index.js.map +1 -0
  298. package/v3/dist/mcp/security/validators/input-sanitizer.d.ts +56 -0
  299. package/v3/dist/mcp/security/validators/input-sanitizer.d.ts.map +1 -0
  300. package/v3/dist/mcp/security/validators/input-sanitizer.js +157 -0
  301. package/v3/dist/mcp/security/validators/input-sanitizer.js.map +1 -0
  302. package/v3/dist/mcp/security/validators/interfaces.d.ts +164 -0
  303. package/v3/dist/mcp/security/validators/interfaces.d.ts.map +1 -0
  304. package/v3/dist/mcp/security/validators/interfaces.js +6 -0
  305. package/v3/dist/mcp/security/validators/interfaces.js.map +1 -0
  306. package/v3/dist/mcp/security/validators/path-traversal-validator.d.ts +50 -0
  307. package/v3/dist/mcp/security/validators/path-traversal-validator.d.ts.map +1 -0
  308. package/v3/dist/mcp/security/validators/path-traversal-validator.js +242 -0
  309. package/v3/dist/mcp/security/validators/path-traversal-validator.js.map +1 -0
  310. package/v3/dist/mcp/security/validators/regex-safety-validator.d.ts +50 -0
  311. package/v3/dist/mcp/security/validators/regex-safety-validator.d.ts.map +1 -0
  312. package/v3/dist/mcp/security/validators/regex-safety-validator.js +183 -0
  313. package/v3/dist/mcp/security/validators/regex-safety-validator.js.map +1 -0
  314. package/v3/dist/mcp/security/validators/validation-orchestrator.d.ts +66 -0
  315. package/v3/dist/mcp/security/validators/validation-orchestrator.d.ts.map +1 -0
  316. package/v3/dist/mcp/security/validators/validation-orchestrator.js +146 -0
  317. package/v3/dist/mcp/security/validators/validation-orchestrator.js.map +1 -0
  318. package/v3/dist/mcp/server.d.ts.map +1 -1
  319. package/v3/dist/mcp/server.js +1 -0
  320. package/v3/dist/mcp/server.js.map +1 -1
  321. package/v3/dist/mcp/tool-registry.d.ts +3 -1
  322. package/v3/dist/mcp/tool-registry.d.ts.map +1 -1
  323. package/v3/dist/mcp/tool-registry.js +155 -2
  324. package/v3/dist/mcp/tool-registry.js.map +1 -1
  325. package/v3/dist/mcp/tools/test-generation/generate.d.ts +1 -0
  326. package/v3/dist/mcp/tools/test-generation/generate.d.ts.map +1 -1
  327. package/v3/dist/mcp/tools/test-generation/generate.js +3 -2
  328. package/v3/dist/mcp/tools/test-generation/generate.js.map +1 -1
  329. package/v3/dist/sync/cloud/index.d.ts +8 -0
  330. package/v3/dist/sync/cloud/index.d.ts.map +1 -0
  331. package/v3/dist/sync/cloud/index.js +8 -0
  332. package/v3/dist/sync/cloud/index.js.map +1 -0
  333. package/v3/dist/sync/cloud/postgres-writer.d.ts +88 -0
  334. package/v3/dist/sync/cloud/postgres-writer.d.ts.map +1 -0
  335. package/v3/dist/sync/cloud/postgres-writer.js +319 -0
  336. package/v3/dist/sync/cloud/postgres-writer.js.map +1 -0
  337. package/v3/dist/sync/cloud/tunnel-manager.d.ts +75 -0
  338. package/v3/dist/sync/cloud/tunnel-manager.d.ts.map +1 -0
  339. package/v3/dist/sync/cloud/tunnel-manager.js +221 -0
  340. package/v3/dist/sync/cloud/tunnel-manager.js.map +1 -0
  341. package/v3/dist/sync/index.d.ts +35 -0
  342. package/v3/dist/sync/index.d.ts.map +1 -0
  343. package/v3/dist/sync/index.js +35 -0
  344. package/v3/dist/sync/index.js.map +1 -0
  345. package/v3/dist/sync/interfaces.d.ts +245 -0
  346. package/v3/dist/sync/interfaces.d.ts.map +1 -0
  347. package/v3/dist/sync/interfaces.js +160 -0
  348. package/v3/dist/sync/interfaces.js.map +1 -0
  349. package/v3/dist/sync/readers/index.d.ts +8 -0
  350. package/v3/dist/sync/readers/index.d.ts.map +1 -0
  351. package/v3/dist/sync/readers/index.js +8 -0
  352. package/v3/dist/sync/readers/index.js.map +1 -0
  353. package/v3/dist/sync/readers/json-reader.d.ts +95 -0
  354. package/v3/dist/sync/readers/json-reader.d.ts.map +1 -0
  355. package/v3/dist/sync/readers/json-reader.js +306 -0
  356. package/v3/dist/sync/readers/json-reader.js.map +1 -0
  357. package/v3/dist/sync/readers/sqlite-reader.d.ts +88 -0
  358. package/v3/dist/sync/readers/sqlite-reader.d.ts.map +1 -0
  359. package/v3/dist/sync/readers/sqlite-reader.js +255 -0
  360. package/v3/dist/sync/readers/sqlite-reader.js.map +1 -0
  361. package/v3/dist/sync/sync-agent.d.ts +116 -0
  362. package/v3/dist/sync/sync-agent.d.ts.map +1 -0
  363. package/v3/dist/sync/sync-agent.js +416 -0
  364. package/v3/dist/sync/sync-agent.js.map +1 -0
  365. package/v3/package.json +13 -2
  366. package/v3/dist/domains/test-generation/coherence-gate.d.ts.map +0 -1
  367. package/v3/dist/domains/test-generation/coherence-gate.js.map +0 -1
@@ -7279,12 +7279,11 @@ var init_types3 = __esm({
7279
7279
  }
7280
7280
  });
7281
7281
 
7282
- // src/integrations/agentic-flow/model-router/complexity-analyzer.ts
7283
- var COMPLEXITY_KEYWORDS, SCOPE_PATTERNS, ComplexityAnalyzer;
7284
- var init_complexity_analyzer = __esm({
7285
- "src/integrations/agentic-flow/model-router/complexity-analyzer.ts"() {
7282
+ // src/integrations/agentic-flow/model-router/signal-collector.ts
7283
+ var COMPLEXITY_KEYWORDS, SCOPE_PATTERNS, SignalCollector;
7284
+ var init_signal_collector = __esm({
7285
+ "src/integrations/agentic-flow/model-router/signal-collector.ts"() {
7286
7286
  "use strict";
7287
- init_types3();
7288
7287
  init_types2();
7289
7288
  COMPLEXITY_KEYWORDS = {
7290
7289
  // Tier 0 - Mechanical transforms
@@ -7348,7 +7347,7 @@ var init_complexity_analyzer = __esm({
7348
7347
  multiStep: /\b(orchestrate|coordinate|workflow|pipeline|multi[- ]step)\b/i,
7349
7348
  crossDomain: /\b(cross[- ]domain|across (domains|modules)|integrate|coordination)\b/i
7350
7349
  };
7351
- ComplexityAnalyzer = class {
7350
+ SignalCollector = class {
7352
7351
  config;
7353
7352
  agentBoosterAdapter;
7354
7353
  constructor(config, agentBoosterAdapter) {
@@ -7356,46 +7355,44 @@ var init_complexity_analyzer = __esm({
7356
7355
  this.agentBoosterAdapter = agentBoosterAdapter;
7357
7356
  }
7358
7357
  /**
7359
- * Analyze task complexity
7358
+ * Collect all complexity signals from input
7360
7359
  */
7361
- async analyze(input) {
7362
- const startTime = Date.now();
7363
- try {
7364
- const signals = await this.collectSignals(input);
7365
- const codeComplexity = this.calculateCodeComplexity(signals);
7366
- const reasoningComplexity = this.calculateReasoningComplexity(signals);
7367
- const scopeComplexity = this.calculateScopeComplexity(signals);
7368
- const overall = this.calculateOverallComplexity(
7369
- codeComplexity,
7370
- reasoningComplexity,
7371
- scopeComplexity,
7372
- signals
7373
- );
7374
- const recommendedTier = this.getRecommendedTier(overall);
7375
- const alternateTiers = this.findAlternateTiers(overall, recommendedTier);
7376
- const confidence = this.calculateConfidence(signals, input);
7377
- const explanation = this.generateExplanation(
7378
- overall,
7379
- recommendedTier,
7380
- signals
7381
- );
7382
- return {
7383
- overall,
7384
- codeComplexity,
7385
- reasoningComplexity,
7386
- scopeComplexity,
7387
- confidence,
7388
- signals,
7389
- recommendedTier,
7390
- alternateTiers,
7391
- explanation
7392
- };
7393
- } catch (error) {
7394
- throw new ComplexityAnalysisError(
7395
- `Failed to analyze task complexity: ${error instanceof Error ? error.message : "Unknown error"}`,
7396
- error instanceof Error ? error : void 0
7397
- );
7398
- }
7360
+ async collectSignals(input) {
7361
+ const taskLower = input.task.toLowerCase();
7362
+ const agentBoosterCheck = await this.checkAgentBoosterEligibility(input);
7363
+ const keywordMatches = {
7364
+ simple: this.findKeywordMatches(taskLower, COMPLEXITY_KEYWORDS.simple),
7365
+ moderate: this.findKeywordMatches(taskLower, COMPLEXITY_KEYWORDS.moderate),
7366
+ complex: this.findKeywordMatches(taskLower, COMPLEXITY_KEYWORDS.complex),
7367
+ critical: this.findKeywordMatches(taskLower, COMPLEXITY_KEYWORDS.critical)
7368
+ };
7369
+ const linesOfCode = input.codeContext ? input.codeContext.split("\n").length : void 0;
7370
+ const fileCount = input.filePaths ? input.filePaths.length : void 0;
7371
+ const hasArchitectureScope = SCOPE_PATTERNS.architecture.test(taskLower);
7372
+ const hasSecurityScope = SCOPE_PATTERNS.security.test(taskLower);
7373
+ const requiresMultiStepReasoning = SCOPE_PATTERNS.multiStep.test(taskLower);
7374
+ const requiresCrossDomainCoordination = SCOPE_PATTERNS.crossDomain.test(taskLower);
7375
+ const requiresCreativity = this.detectCreativityRequirement(taskLower);
7376
+ const languageComplexity = this.estimateLanguageComplexity(
7377
+ input.codeContext,
7378
+ input.filePaths
7379
+ );
7380
+ const cyclomaticComplexity = input.codeContext ? this.estimateCyclomaticComplexity(input.codeContext) : void 0;
7381
+ return {
7382
+ linesOfCode,
7383
+ fileCount,
7384
+ hasArchitectureScope,
7385
+ hasSecurityScope,
7386
+ requiresMultiStepReasoning,
7387
+ requiresCrossDomainCoordination,
7388
+ isMechanicalTransform: agentBoosterCheck.eligible,
7389
+ languageComplexity,
7390
+ cyclomaticComplexity,
7391
+ dependencyCount: this.countDependencies(input.codeContext),
7392
+ requiresCreativity,
7393
+ detectedTransformType: agentBoosterCheck.transformType,
7394
+ keywordMatches
7395
+ };
7399
7396
  }
7400
7397
  /**
7401
7398
  * Check if task is eligible for Agent Booster (Tier 0)
@@ -7416,7 +7413,12 @@ var init_complexity_analyzer = __esm({
7416
7413
  let confidence = 0;
7417
7414
  for (const keyword of keywords) {
7418
7415
  if (taskLower.includes(keyword.toLowerCase())) {
7419
- confidence += 0.2;
7416
+ confidence = confidence === 0 ? 0.5 : confidence + 0.25;
7417
+ }
7418
+ }
7419
+ for (const mechanicalKeyword of COMPLEXITY_KEYWORDS.mechanical) {
7420
+ if (taskLower.includes(mechanicalKeyword.toLowerCase())) {
7421
+ confidence = Math.max(confidence, 0.6);
7420
7422
  }
7421
7423
  }
7422
7424
  if (confidence > maxConfidence) {
@@ -7451,143 +7453,8 @@ var init_complexity_analyzer = __esm({
7451
7453
  reason: eligible ? `Detected ${detectedTransformType} transform pattern` : "No mechanical transform pattern detected"
7452
7454
  };
7453
7455
  }
7454
- /**
7455
- * Get recommended tier based on complexity score
7456
- */
7457
- getRecommendedTier(complexity) {
7458
- for (const tier of [0, 1, 2, 3, 4]) {
7459
- const [min, max] = TIER_METADATA[tier].complexityRange;
7460
- if (complexity >= min && complexity <= max) {
7461
- return tier;
7462
- }
7463
- }
7464
- return 2;
7465
- }
7466
- // ============================================================================
7467
- // Private: Signal Collection
7468
- // ============================================================================
7469
- /**
7470
- * Collect all complexity signals from input
7471
- */
7472
- async collectSignals(input) {
7473
- const taskLower = input.task.toLowerCase();
7474
- const codeLower = input.codeContext?.toLowerCase() || "";
7475
- const agentBoosterCheck = await this.checkAgentBoosterEligibility(input);
7476
- const keywordMatches = {
7477
- simple: this.findKeywordMatches(taskLower, COMPLEXITY_KEYWORDS.simple),
7478
- moderate: this.findKeywordMatches(taskLower, COMPLEXITY_KEYWORDS.moderate),
7479
- complex: this.findKeywordMatches(taskLower, COMPLEXITY_KEYWORDS.complex),
7480
- critical: this.findKeywordMatches(taskLower, COMPLEXITY_KEYWORDS.critical)
7481
- };
7482
- const linesOfCode = input.codeContext ? input.codeContext.split("\n").length : void 0;
7483
- const fileCount = input.filePaths ? input.filePaths.length : void 0;
7484
- const hasArchitectureScope = SCOPE_PATTERNS.architecture.test(taskLower);
7485
- const hasSecurityScope = SCOPE_PATTERNS.security.test(taskLower);
7486
- const requiresMultiStepReasoning = SCOPE_PATTERNS.multiStep.test(taskLower);
7487
- const requiresCrossDomainCoordination = SCOPE_PATTERNS.crossDomain.test(taskLower);
7488
- const requiresCreativity = taskLower.includes("design") || taskLower.includes("creative") || taskLower.includes("innovative") || taskLower.includes("novel");
7489
- const languageComplexity = this.estimateLanguageComplexity(
7490
- input.codeContext,
7491
- input.filePaths
7492
- );
7493
- const cyclomaticComplexity = input.codeContext ? this.estimateCyclomaticComplexity(input.codeContext) : void 0;
7494
- return {
7495
- linesOfCode,
7496
- fileCount,
7497
- hasArchitectureScope,
7498
- hasSecurityScope,
7499
- requiresMultiStepReasoning,
7500
- requiresCrossDomainCoordination,
7501
- isMechanicalTransform: agentBoosterCheck.eligible,
7502
- languageComplexity,
7503
- cyclomaticComplexity,
7504
- dependencyCount: this.countDependencies(input.codeContext),
7505
- requiresCreativity,
7506
- detectedTransformType: agentBoosterCheck.transformType,
7507
- keywordMatches
7508
- };
7509
- }
7510
- // ============================================================================
7511
- // Private: Complexity Calculation
7512
- // ============================================================================
7513
- /**
7514
- * Calculate code complexity component (0-100)
7515
- */
7516
- calculateCodeComplexity(signals) {
7517
- let score = 0;
7518
- if (signals.linesOfCode !== void 0) {
7519
- if (signals.linesOfCode < 10) score += 0;
7520
- else if (signals.linesOfCode < 50) score += 10;
7521
- else if (signals.linesOfCode < 200) score += 20;
7522
- else score += 30;
7523
- }
7524
- if (signals.fileCount !== void 0) {
7525
- if (signals.fileCount === 1) score += 0;
7526
- else if (signals.fileCount < 5) score += 10;
7527
- else score += 20;
7528
- }
7529
- if (signals.cyclomaticComplexity !== void 0) {
7530
- if (signals.cyclomaticComplexity < 5) score += 0;
7531
- else if (signals.cyclomaticComplexity < 10) score += 10;
7532
- else if (signals.cyclomaticComplexity < 20) score += 20;
7533
- else score += 30;
7534
- }
7535
- if (signals.languageComplexity === "low") score += 0;
7536
- else if (signals.languageComplexity === "medium") score += 10;
7537
- else if (signals.languageComplexity === "high") score += 20;
7538
- return Math.min(score, 100);
7539
- }
7540
- /**
7541
- * Calculate reasoning complexity component (0-100)
7542
- */
7543
- calculateReasoningComplexity(signals) {
7544
- let score = 0;
7545
- const keywordScore = signals.keywordMatches.simple.length * 5 + signals.keywordMatches.moderate.length * 15 + signals.keywordMatches.complex.length * 25 + signals.keywordMatches.critical.length * 35;
7546
- score += Math.min(keywordScore, 60);
7547
- if (signals.requiresMultiStepReasoning) score += 20;
7548
- if (signals.requiresCreativity) score += 20;
7549
- return Math.min(score, 100);
7550
- }
7551
- /**
7552
- * Calculate scope complexity component (0-100)
7553
- */
7554
- calculateScopeComplexity(signals) {
7555
- let score = 0;
7556
- if (signals.hasArchitectureScope) score += 40;
7557
- if (signals.hasSecurityScope) score += 30;
7558
- if (signals.requiresCrossDomainCoordination) score += 20;
7559
- if (signals.dependencyCount !== void 0) {
7560
- if (signals.dependencyCount < 3) score += 0;
7561
- else if (signals.dependencyCount < 10) score += 5;
7562
- else score += 10;
7563
- }
7564
- return Math.min(score, 100);
7565
- }
7566
- /**
7567
- * Calculate overall complexity score (0-100)
7568
- */
7569
- calculateOverallComplexity(codeComplexity, reasoningComplexity, scopeComplexity, signals) {
7570
- if (signals.isMechanicalTransform) {
7571
- return 5;
7572
- }
7573
- const weighted = codeComplexity * 0.3 + reasoningComplexity * 0.4 + scopeComplexity * 0.3;
7574
- return Math.min(Math.round(weighted), 100);
7575
- }
7576
- /**
7577
- * Calculate confidence in complexity assessment (0-1)
7578
- */
7579
- calculateConfidence(signals, input) {
7580
- let confidence = 0.5;
7581
- if (input.codeContext) confidence += 0.2;
7582
- if (input.filePaths && input.filePaths.length > 0) confidence += 0.1;
7583
- const totalKeywords = signals.keywordMatches.simple.length + signals.keywordMatches.moderate.length + signals.keywordMatches.complex.length + signals.keywordMatches.critical.length;
7584
- if (totalKeywords >= 3) confidence += 0.1;
7585
- else if (totalKeywords >= 1) confidence += 0.05;
7586
- if (signals.isMechanicalTransform) confidence += 0.15;
7587
- return Math.min(confidence, 1);
7588
- }
7589
7456
  // ============================================================================
7590
- // Private: Helper Methods
7457
+ // Private Helper Methods
7591
7458
  // ============================================================================
7592
7459
  /**
7593
7460
  * Find matching keywords in text
@@ -7601,6 +7468,12 @@ var init_complexity_analyzer = __esm({
7601
7468
  }
7602
7469
  return matches;
7603
7470
  }
7471
+ /**
7472
+ * Detect creativity requirements from task text
7473
+ */
7474
+ detectCreativityRequirement(taskLower) {
7475
+ return taskLower.includes("design") || taskLower.includes("creative") || taskLower.includes("innovative") || taskLower.includes("novel");
7476
+ }
7604
7477
  /**
7605
7478
  * Estimate language complexity from code context
7606
7479
  */
@@ -7668,23 +7541,205 @@ var init_complexity_analyzer = __esm({
7668
7541
  */
7669
7542
  getTransformKeywords(transformType) {
7670
7543
  const keywordMap = {
7671
- "var-to-const": ["var to const", "convert var", "var declaration"],
7672
- "add-types": ["add types", "typescript types", "type annotations"],
7673
- "remove-console": ["remove console", "delete console", "console.log"],
7544
+ "var-to-const": [
7545
+ "var to const",
7546
+ "convert var",
7547
+ "var declaration",
7548
+ "var to let",
7549
+ "convert var to const",
7550
+ // Added explicit full phrase
7551
+ "change var to const"
7552
+ ],
7553
+ "add-types": [
7554
+ "add types",
7555
+ "add type",
7556
+ "typescript types",
7557
+ "type annotations",
7558
+ "type annotation",
7559
+ "add type annotations"
7560
+ ],
7561
+ "remove-console": [
7562
+ "remove console",
7563
+ "delete console",
7564
+ "console.log",
7565
+ "remove console.log",
7566
+ "strip console"
7567
+ ],
7674
7568
  "promise-to-async": [
7675
7569
  "promise to async",
7676
7570
  "async await",
7677
- ".then to async"
7571
+ ".then to async",
7572
+ "convert to async",
7573
+ "convert function to async"
7678
7574
  ],
7679
7575
  "cjs-to-esm": [
7680
7576
  "commonjs to esm",
7681
7577
  "require to import",
7682
- "convert to esm"
7578
+ "convert to esm",
7579
+ "cjs to esm",
7580
+ "module conversion"
7683
7581
  ],
7684
- "func-to-arrow": ["arrow function", "function to arrow", "convert to arrow"]
7582
+ "func-to-arrow": [
7583
+ "arrow function",
7584
+ "function to arrow",
7585
+ "convert to arrow",
7586
+ "convert function to arrow"
7587
+ ]
7685
7588
  };
7686
7589
  return keywordMap[transformType] || [];
7687
7590
  }
7591
+ };
7592
+ }
7593
+ });
7594
+
7595
+ // src/integrations/agentic-flow/model-router/score-calculator.ts
7596
+ var ScoreCalculator;
7597
+ var init_score_calculator = __esm({
7598
+ "src/integrations/agentic-flow/model-router/score-calculator.ts"() {
7599
+ "use strict";
7600
+ ScoreCalculator = class {
7601
+ /**
7602
+ * Calculate code complexity component (0-100)
7603
+ */
7604
+ calculateCodeComplexity(signals) {
7605
+ let score = 0;
7606
+ score += this.calculateLinesOfCodeContribution(signals.linesOfCode);
7607
+ score += this.calculateFileCountContribution(signals.fileCount);
7608
+ score += this.calculateCyclomaticContribution(signals.cyclomaticComplexity);
7609
+ score += this.calculateLanguageContribution(signals.languageComplexity);
7610
+ return Math.min(score, 100);
7611
+ }
7612
+ /**
7613
+ * Calculate reasoning complexity component (0-100)
7614
+ */
7615
+ calculateReasoningComplexity(signals) {
7616
+ let score = 0;
7617
+ score += this.calculateKeywordScore(signals.keywordMatches);
7618
+ if (signals.requiresMultiStepReasoning) score += 20;
7619
+ if (signals.requiresCreativity) score += 20;
7620
+ return Math.min(score, 100);
7621
+ }
7622
+ /**
7623
+ * Calculate scope complexity component (0-100)
7624
+ */
7625
+ calculateScopeComplexity(signals) {
7626
+ let score = 0;
7627
+ if (signals.hasArchitectureScope) score += 40;
7628
+ if (signals.hasSecurityScope) score += 30;
7629
+ if (signals.requiresCrossDomainCoordination) score += 20;
7630
+ score += this.calculateDependencyContribution(signals.dependencyCount);
7631
+ return Math.min(score, 100);
7632
+ }
7633
+ /**
7634
+ * Calculate overall complexity score (0-100)
7635
+ */
7636
+ calculateOverallComplexity(codeComplexity, reasoningComplexity, scopeComplexity, signals) {
7637
+ if (signals.isMechanicalTransform) {
7638
+ return 5;
7639
+ }
7640
+ const weighted = codeComplexity * 0.3 + reasoningComplexity * 0.4 + scopeComplexity * 0.3;
7641
+ return Math.min(Math.round(weighted), 100);
7642
+ }
7643
+ /**
7644
+ * Calculate confidence in complexity assessment (0-1)
7645
+ */
7646
+ calculateConfidence(signals, input) {
7647
+ let confidence = 0.5;
7648
+ if (input.codeContext) confidence += 0.2;
7649
+ if (input.filePaths && input.filePaths.length > 0) confidence += 0.1;
7650
+ confidence += this.calculateKeywordConfidenceBoost(signals.keywordMatches);
7651
+ if (signals.isMechanicalTransform) confidence += 0.15;
7652
+ return Math.min(confidence, 1);
7653
+ }
7654
+ // ============================================================================
7655
+ // Private Helper Methods
7656
+ // ============================================================================
7657
+ /**
7658
+ * Calculate lines of code contribution (0-30 points)
7659
+ */
7660
+ calculateLinesOfCodeContribution(linesOfCode) {
7661
+ if (linesOfCode === void 0) return 0;
7662
+ if (linesOfCode < 10) return 0;
7663
+ if (linesOfCode < 50) return 10;
7664
+ if (linesOfCode < 200) return 20;
7665
+ return 30;
7666
+ }
7667
+ /**
7668
+ * Calculate file count contribution (0-20 points)
7669
+ */
7670
+ calculateFileCountContribution(fileCount) {
7671
+ if (fileCount === void 0) return 0;
7672
+ if (fileCount === 1) return 0;
7673
+ if (fileCount < 5) return 10;
7674
+ return 20;
7675
+ }
7676
+ /**
7677
+ * Calculate cyclomatic complexity contribution (0-30 points)
7678
+ */
7679
+ calculateCyclomaticContribution(cyclomaticComplexity) {
7680
+ if (cyclomaticComplexity === void 0) return 0;
7681
+ if (cyclomaticComplexity < 5) return 0;
7682
+ if (cyclomaticComplexity < 10) return 10;
7683
+ if (cyclomaticComplexity < 20) return 20;
7684
+ return 30;
7685
+ }
7686
+ /**
7687
+ * Calculate language complexity contribution (0-20 points)
7688
+ */
7689
+ calculateLanguageContribution(languageComplexity) {
7690
+ if (languageComplexity === "low") return 0;
7691
+ if (languageComplexity === "medium") return 10;
7692
+ if (languageComplexity === "high") return 20;
7693
+ return 0;
7694
+ }
7695
+ /**
7696
+ * Calculate keyword score (0-60 points)
7697
+ */
7698
+ calculateKeywordScore(keywordMatches) {
7699
+ const keywordScore = keywordMatches.simple.length * 5 + keywordMatches.moderate.length * 15 + keywordMatches.complex.length * 25 + keywordMatches.critical.length * 35;
7700
+ return Math.min(keywordScore, 60);
7701
+ }
7702
+ /**
7703
+ * Calculate dependency count contribution (0-10 points)
7704
+ */
7705
+ calculateDependencyContribution(dependencyCount) {
7706
+ if (dependencyCount === void 0) return 0;
7707
+ if (dependencyCount < 3) return 0;
7708
+ if (dependencyCount < 10) return 5;
7709
+ return 10;
7710
+ }
7711
+ /**
7712
+ * Calculate confidence boost from keyword matches (0-0.1)
7713
+ */
7714
+ calculateKeywordConfidenceBoost(keywordMatches) {
7715
+ const totalKeywords = keywordMatches.simple.length + keywordMatches.moderate.length + keywordMatches.complex.length + keywordMatches.critical.length;
7716
+ if (totalKeywords >= 3) return 0.1;
7717
+ if (totalKeywords >= 1) return 0.05;
7718
+ return 0;
7719
+ }
7720
+ };
7721
+ }
7722
+ });
7723
+
7724
+ // src/integrations/agentic-flow/model-router/tier-recommender.ts
7725
+ var TierRecommender;
7726
+ var init_tier_recommender = __esm({
7727
+ "src/integrations/agentic-flow/model-router/tier-recommender.ts"() {
7728
+ "use strict";
7729
+ init_types3();
7730
+ TierRecommender = class {
7731
+ /**
7732
+ * Get recommended tier based on complexity score
7733
+ */
7734
+ getRecommendedTier(complexity) {
7735
+ for (const tier of [0, 1, 2, 3, 4]) {
7736
+ const [min, max] = TIER_METADATA[tier].complexityRange;
7737
+ if (complexity >= min && complexity <= max) {
7738
+ return tier;
7739
+ }
7740
+ }
7741
+ return 2;
7742
+ }
7688
7743
  /**
7689
7744
  * Find alternative tiers that could handle this task
7690
7745
  */
@@ -7708,29 +7763,143 @@ var init_complexity_analyzer = __esm({
7708
7763
  const parts = [];
7709
7764
  parts.push(`Complexity score: ${overall}/100 (Tier ${tier})`);
7710
7765
  if (signals.isMechanicalTransform) {
7711
- parts.push(
7712
- `Detected mechanical transform: ${signals.detectedTransformType}`
7713
- );
7766
+ parts.push(this.formatMechanicalTransformInfo(signals.detectedTransformType));
7714
7767
  }
7768
+ parts.push(...this.formatScopeExplanations(signals));
7769
+ parts.push(...this.formatCodeMetricsExplanations(signals));
7770
+ return parts.join(". ");
7771
+ }
7772
+ // ============================================================================
7773
+ // Private Helper Methods
7774
+ // ============================================================================
7775
+ /**
7776
+ * Format mechanical transform information
7777
+ */
7778
+ formatMechanicalTransformInfo(transformType) {
7779
+ return `Detected mechanical transform: ${transformType}`;
7780
+ }
7781
+ /**
7782
+ * Format scope-related explanations
7783
+ */
7784
+ formatScopeExplanations(signals) {
7785
+ const explanations = [];
7715
7786
  if (signals.hasArchitectureScope) {
7716
- parts.push("Architecture scope detected");
7787
+ explanations.push("Architecture scope detected");
7717
7788
  }
7718
7789
  if (signals.hasSecurityScope) {
7719
- parts.push("Security scope detected");
7790
+ explanations.push("Security scope detected");
7720
7791
  }
7721
7792
  if (signals.requiresMultiStepReasoning) {
7722
- parts.push("Multi-step reasoning required");
7793
+ explanations.push("Multi-step reasoning required");
7723
7794
  }
7724
7795
  if (signals.requiresCrossDomainCoordination) {
7725
- parts.push("Cross-domain coordination required");
7796
+ explanations.push("Cross-domain coordination required");
7726
7797
  }
7798
+ return explanations;
7799
+ }
7800
+ /**
7801
+ * Format code metrics explanations
7802
+ */
7803
+ formatCodeMetricsExplanations(signals) {
7804
+ const explanations = [];
7727
7805
  if (signals.linesOfCode !== void 0 && signals.linesOfCode > 100) {
7728
- parts.push(`Large code change: ${signals.linesOfCode} lines`);
7806
+ explanations.push(`Large code change: ${signals.linesOfCode} lines`);
7729
7807
  }
7730
7808
  if (signals.fileCount !== void 0 && signals.fileCount > 3) {
7731
- parts.push(`Multi-file change: ${signals.fileCount} files`);
7809
+ explanations.push(`Multi-file change: ${signals.fileCount} files`);
7732
7810
  }
7733
- return parts.join(". ");
7811
+ return explanations;
7812
+ }
7813
+ };
7814
+ }
7815
+ });
7816
+
7817
+ // src/integrations/agentic-flow/model-router/complexity-analyzer.ts
7818
+ function createComplexityAnalyzer(config, agentBoosterAdapter) {
7819
+ const signalCollector = new SignalCollector(config, agentBoosterAdapter);
7820
+ const scoreCalculator = new ScoreCalculator();
7821
+ const tierRecommender = new TierRecommender();
7822
+ return new ComplexityAnalyzer(
7823
+ config,
7824
+ signalCollector,
7825
+ scoreCalculator,
7826
+ tierRecommender
7827
+ );
7828
+ }
7829
+ var ComplexityAnalyzer;
7830
+ var init_complexity_analyzer = __esm({
7831
+ "src/integrations/agentic-flow/model-router/complexity-analyzer.ts"() {
7832
+ "use strict";
7833
+ init_types3();
7834
+ init_signal_collector();
7835
+ init_score_calculator();
7836
+ init_tier_recommender();
7837
+ init_signal_collector();
7838
+ init_score_calculator();
7839
+ init_tier_recommender();
7840
+ ComplexityAnalyzer = class {
7841
+ config;
7842
+ signalCollector;
7843
+ scoreCalculator;
7844
+ tierRecommender;
7845
+ constructor(config, signalCollector, scoreCalculator, tierRecommender) {
7846
+ this.config = config;
7847
+ this.signalCollector = signalCollector;
7848
+ this.scoreCalculator = scoreCalculator;
7849
+ this.tierRecommender = tierRecommender;
7850
+ }
7851
+ /**
7852
+ * Analyze task complexity
7853
+ */
7854
+ async analyze(input) {
7855
+ try {
7856
+ const signals = await this.signalCollector.collectSignals(input);
7857
+ const codeComplexity = this.scoreCalculator.calculateCodeComplexity(signals);
7858
+ const reasoningComplexity = this.scoreCalculator.calculateReasoningComplexity(signals);
7859
+ const scopeComplexity = this.scoreCalculator.calculateScopeComplexity(signals);
7860
+ const overall = this.scoreCalculator.calculateOverallComplexity(
7861
+ codeComplexity,
7862
+ reasoningComplexity,
7863
+ scopeComplexity,
7864
+ signals
7865
+ );
7866
+ const recommendedTier = this.tierRecommender.getRecommendedTier(overall);
7867
+ const alternateTiers = this.tierRecommender.findAlternateTiers(overall, recommendedTier);
7868
+ const confidence = this.scoreCalculator.calculateConfidence(signals, input);
7869
+ const explanation = this.tierRecommender.generateExplanation(
7870
+ overall,
7871
+ recommendedTier,
7872
+ signals
7873
+ );
7874
+ return {
7875
+ overall,
7876
+ codeComplexity,
7877
+ reasoningComplexity,
7878
+ scopeComplexity,
7879
+ confidence,
7880
+ signals,
7881
+ recommendedTier,
7882
+ alternateTiers,
7883
+ explanation
7884
+ };
7885
+ } catch (error) {
7886
+ throw new ComplexityAnalysisError(
7887
+ `Failed to analyze task complexity: ${error instanceof Error ? error.message : "Unknown error"}`,
7888
+ error instanceof Error ? error : void 0
7889
+ );
7890
+ }
7891
+ }
7892
+ /**
7893
+ * Check if task is eligible for Agent Booster (Tier 0)
7894
+ */
7895
+ async checkAgentBoosterEligibility(input) {
7896
+ return this.signalCollector.checkAgentBoosterEligibility(input);
7897
+ }
7898
+ /**
7899
+ * Get recommended tier based on complexity score
7900
+ */
7901
+ getRecommendedTier(complexity) {
7902
+ return this.tierRecommender.getRecommendedTier(complexity);
7734
7903
  }
7735
7904
  };
7736
7905
  }
@@ -8303,7 +8472,7 @@ var init_router = __esm({
8303
8472
  this.config = { ...DEFAULT_ROUTER_CONFIG, ...config };
8304
8473
  this.agentBoosterAdapter = agentBoosterAdapter;
8305
8474
  this.persistentMetricsTracker = persistentMetricsTracker;
8306
- this.complexityAnalyzer = new ComplexityAnalyzer(
8475
+ this.complexityAnalyzer = createComplexityAnalyzer(
8307
8476
  this.config,
8308
8477
  agentBoosterAdapter
8309
8478
  );
@@ -10869,7 +11038,740 @@ function err(error) {
10869
11038
  return { success: false, error };
10870
11039
  }
10871
11040
 
11041
+ // src/mcp/security/validators/path-traversal-validator.ts
11042
+ var PATH_TRAVERSAL_PATTERNS = [
11043
+ /\.\./,
11044
+ // Basic traversal
11045
+ /%2e%2e/i,
11046
+ // URL encoded ..
11047
+ /%252e%252e/i,
11048
+ // Double URL encoded
11049
+ /\.\.%2f/i,
11050
+ // Mixed encoding
11051
+ /%2f\.\./i,
11052
+ // Forward slash + ..
11053
+ /\.\.%5c/i,
11054
+ // Backslash + ..
11055
+ /\.\.\\/,
11056
+ // Windows backslash traversal
11057
+ /%c0%ae/i,
11058
+ // UTF-8 overlong encoding
11059
+ /%c0%2f/i,
11060
+ // UTF-8 overlong /
11061
+ /%c1%9c/i,
11062
+ // UTF-8 overlong \
11063
+ /\0/,
11064
+ // Null byte injection
11065
+ /%00/i
11066
+ // URL encoded null
11067
+ ];
11068
+ var DANGEROUS_PATH_COMPONENTS = [
11069
+ /^\/etc\//i,
11070
+ /^\/proc\//i,
11071
+ /^\/sys\//i,
11072
+ /^\/dev\//i,
11073
+ /^\/root\//i,
11074
+ /^\/home\/.+\/\./i,
11075
+ /^[A-Z]:\\Windows/i,
11076
+ /^[A-Z]:\\System/i,
11077
+ /^[A-Z]:\\Users\\.+\\AppData/i
11078
+ ];
11079
+ var PathTraversalValidator = class {
11080
+ name = "path-traversal";
11081
+ /**
11082
+ * Get the primary risk level this validator addresses
11083
+ */
11084
+ getRiskLevel() {
11085
+ return "critical";
11086
+ }
11087
+ /**
11088
+ * Validate a file path against traversal attacks
11089
+ */
11090
+ validate(path16, options = {}) {
11091
+ const {
11092
+ basePath = "",
11093
+ allowAbsolute = false,
11094
+ allowedExtensions = [],
11095
+ deniedExtensions = [".exe", ".bat", ".cmd", ".sh", ".ps1", ".dll", ".so"],
11096
+ maxDepth = 10,
11097
+ maxLength = 4096
11098
+ } = options;
11099
+ if (path16.length > maxLength) {
11100
+ return {
11101
+ valid: false,
11102
+ error: `Path exceeds maximum length of ${maxLength}`,
11103
+ riskLevel: "medium"
11104
+ };
11105
+ }
11106
+ for (const pattern of PATH_TRAVERSAL_PATTERNS) {
11107
+ if (pattern.test(path16)) {
11108
+ return {
11109
+ valid: false,
11110
+ error: "Path traversal attempt detected",
11111
+ riskLevel: "critical"
11112
+ };
11113
+ }
11114
+ }
11115
+ if (!allowAbsolute && (path16.startsWith("/") || /^[A-Z]:/i.test(path16))) {
11116
+ return {
11117
+ valid: false,
11118
+ error: "Absolute paths are not allowed",
11119
+ riskLevel: "high"
11120
+ };
11121
+ }
11122
+ for (const pattern of DANGEROUS_PATH_COMPONENTS) {
11123
+ if (pattern.test(path16)) {
11124
+ return {
11125
+ valid: false,
11126
+ error: "Access to system paths is not allowed",
11127
+ riskLevel: "critical"
11128
+ };
11129
+ }
11130
+ }
11131
+ const normalizedPath = this.normalizePath(path16);
11132
+ if (normalizedPath.includes("..")) {
11133
+ return {
11134
+ valid: false,
11135
+ error: "Path traversal detected after normalization",
11136
+ riskLevel: "critical"
11137
+ };
11138
+ }
11139
+ const depth = normalizedPath.split("/").filter(Boolean).length;
11140
+ if (depth > maxDepth) {
11141
+ return {
11142
+ valid: false,
11143
+ error: `Path depth exceeds maximum of ${maxDepth}`,
11144
+ riskLevel: "low"
11145
+ };
11146
+ }
11147
+ const ext = this.getExtension(normalizedPath);
11148
+ if (ext) {
11149
+ const extWithDot = `.${ext.toLowerCase()}`;
11150
+ const extWithoutDot = ext.toLowerCase();
11151
+ if (deniedExtensions.length > 0) {
11152
+ const isDenied = deniedExtensions.some(
11153
+ (denied) => denied.toLowerCase() === extWithDot || denied.toLowerCase() === extWithoutDot
11154
+ );
11155
+ if (isDenied) {
11156
+ return {
11157
+ valid: false,
11158
+ error: `File extension '${ext}' is not allowed`,
11159
+ riskLevel: "high"
11160
+ };
11161
+ }
11162
+ }
11163
+ if (allowedExtensions.length > 0) {
11164
+ const isAllowed = allowedExtensions.some(
11165
+ (allowed) => allowed.toLowerCase() === extWithDot || allowed.toLowerCase() === extWithoutDot
11166
+ );
11167
+ if (!isAllowed) {
11168
+ return {
11169
+ valid: false,
11170
+ error: `File extension '${ext}' is not in allowed list`,
11171
+ riskLevel: "medium"
11172
+ };
11173
+ }
11174
+ }
11175
+ }
11176
+ const finalPath = basePath ? this.joinPathsAbsolute(basePath, normalizedPath) : normalizedPath;
11177
+ const normalizedBase = basePath.startsWith("/") ? `/${this.normalizePath(basePath)}` : this.normalizePath(basePath);
11178
+ if (basePath && !finalPath.startsWith(normalizedBase)) {
11179
+ return {
11180
+ valid: false,
11181
+ error: "Path escapes base directory",
11182
+ riskLevel: "critical"
11183
+ };
11184
+ }
11185
+ return {
11186
+ valid: true,
11187
+ normalizedPath: finalPath,
11188
+ riskLevel: "none"
11189
+ };
11190
+ }
11191
+ /**
11192
+ * Normalize a path by resolving . and .. components
11193
+ */
11194
+ normalizePath(path16) {
11195
+ let normalized = path16.replace(/\\/g, "/");
11196
+ normalized = normalized.replace(/\/+/g, "/");
11197
+ const parts = normalized.split("/");
11198
+ const result = [];
11199
+ for (const part of parts) {
11200
+ if (part === "." || part === "") {
11201
+ continue;
11202
+ }
11203
+ if (part === "..") {
11204
+ if (result.length > 0 && result[result.length - 1] !== "..") {
11205
+ result.pop();
11206
+ }
11207
+ } else {
11208
+ result.push(part);
11209
+ }
11210
+ }
11211
+ return result.join("/");
11212
+ }
11213
+ /**
11214
+ * Safely join path components (strips leading/trailing slashes from all parts)
11215
+ */
11216
+ joinPaths(...paths) {
11217
+ if (paths.length === 0) return "";
11218
+ return paths.map((p) => p.replace(/^\/+|\/+$/g, "")).filter(Boolean).join("/");
11219
+ }
11220
+ /**
11221
+ * Join paths preserving absolute path from first component
11222
+ */
11223
+ joinPathsAbsolute(...paths) {
11224
+ if (paths.length === 0) return "";
11225
+ const isAbsolute4 = paths[0].startsWith("/");
11226
+ const result = paths.map((p) => {
11227
+ while (p.startsWith("/")) p = p.slice(1);
11228
+ while (p.endsWith("/")) p = p.slice(0, -1);
11229
+ return p;
11230
+ }).filter(Boolean).join("/");
11231
+ return isAbsolute4 ? `/${result}` : result;
11232
+ }
11233
+ /**
11234
+ * Get file extension from path
11235
+ */
11236
+ getExtension(path16) {
11237
+ const match = path16.match(/\.([^./\\]+)$/);
11238
+ return match ? match[1] : null;
11239
+ }
11240
+ };
11241
+ var defaultValidator = new PathTraversalValidator();
11242
+ var validatePath = (path16, options) => defaultValidator.validate(path16, options);
11243
+
11244
+ // src/mcp/security/validators/regex-safety-validator.ts
11245
+ var REDOS_PATTERNS = [
11246
+ /\(\.\*\)\+/,
11247
+ // (.*)+
11248
+ /\(\.\+\)\+/,
11249
+ // (.+)+
11250
+ /\([^)]*\?\)\+/,
11251
+ // (...?)+
11252
+ /\([^)]*\*\)\+/,
11253
+ // (...*)+
11254
+ /\([^)]*\+\)\+/,
11255
+ // (...+)+
11256
+ /\(\[.*?\]\+\)\+/,
11257
+ // ([...]+)+
11258
+ /\(\[.*?\]\*\)\+/,
11259
+ // ([...]*)+
11260
+ /\(\[.*?\]\?\)\+/,
11261
+ // ([...]?)+
11262
+ /\(\[.*?\]\*\)\*/,
11263
+ // ([...]*)*
11264
+ /\.\*\.\*/,
11265
+ // .*.*
11266
+ /\.\+\.\+/,
11267
+ // .+.+
11268
+ /\(\.\|\.\)/
11269
+ // (.|.)
11270
+ ];
11271
+ var MAX_REGEX_COMPLEXITY = 3;
11272
+ function countQuantifierNesting(pattern) {
11273
+ let maxDepth = 0;
11274
+ let currentDepth = 0;
11275
+ let inGroup = false;
11276
+ let escaped = false;
11277
+ for (let i = 0; i < pattern.length; i++) {
11278
+ const char = pattern[i];
11279
+ if (escaped) {
11280
+ escaped = false;
11281
+ continue;
11282
+ }
11283
+ if (char === "\\") {
11284
+ escaped = true;
11285
+ continue;
11286
+ }
11287
+ if (char === "(") {
11288
+ inGroup = true;
11289
+ continue;
11290
+ }
11291
+ if (char === ")") {
11292
+ inGroup = false;
11293
+ const next = pattern[i + 1];
11294
+ if (next === "*" || next === "+" || next === "?" || next === "{") {
11295
+ currentDepth++;
11296
+ maxDepth = Math.max(maxDepth, currentDepth);
11297
+ }
11298
+ continue;
11299
+ }
11300
+ if ((char === "*" || char === "+" || char === "?") && !inGroup) {
11301
+ currentDepth = 1;
11302
+ maxDepth = Math.max(maxDepth, currentDepth);
11303
+ }
11304
+ }
11305
+ return maxDepth;
11306
+ }
11307
+ function hasExponentialBacktracking(pattern) {
11308
+ const dangerous = [
11309
+ /\(\[^\\]*\]\+\)\+/,
11310
+ // ([...]+)+
11311
+ /\(\[^\\]*\]\*\)\*/,
11312
+ // ([...]*)*
11313
+ /\([^)]+\|[^)]+\)\+/,
11314
+ // (a|b)+
11315
+ /\(\.\*\)[*+]/,
11316
+ // (.*)+, (.*)*
11317
+ /\(\.\+\)[*+]/
11318
+ // (.+)+, (.+)*
11319
+ ];
11320
+ return dangerous.some((d) => d.test(pattern));
11321
+ }
11322
+ var RegexSafetyValidator = class {
11323
+ name = "regex-safety";
11324
+ maxComplexity;
11325
+ constructor(maxComplexity = MAX_REGEX_COMPLEXITY) {
11326
+ this.maxComplexity = maxComplexity;
11327
+ }
11328
+ /**
11329
+ * Get the primary risk level this validator addresses
11330
+ */
11331
+ getRiskLevel() {
11332
+ return "high";
11333
+ }
11334
+ /**
11335
+ * Validate a regex pattern (IValidationStrategy interface)
11336
+ */
11337
+ validate(pattern, options = {}) {
11338
+ const { maxLength = 1e4, maxComplexity = this.maxComplexity } = options;
11339
+ if (pattern.length > maxLength) {
11340
+ return {
11341
+ valid: false,
11342
+ error: `Pattern exceeds maximum length of ${maxLength}`,
11343
+ riskLevel: "medium"
11344
+ };
11345
+ }
11346
+ const result = this.isRegexSafe(pattern, maxComplexity);
11347
+ return {
11348
+ valid: result.safe,
11349
+ error: result.error,
11350
+ riskLevel: result.safe ? "none" : "high"
11351
+ };
11352
+ }
11353
+ /**
11354
+ * Check if a regex pattern is safe from ReDoS
11355
+ */
11356
+ isRegexSafe(pattern, maxComplexity = this.maxComplexity) {
11357
+ const riskyPatterns = [];
11358
+ for (const redosPattern of REDOS_PATTERNS) {
11359
+ if (redosPattern.test(pattern)) {
11360
+ riskyPatterns.push(redosPattern.source);
11361
+ }
11362
+ }
11363
+ const quantifierDepth = countQuantifierNesting(pattern);
11364
+ if (quantifierDepth > maxComplexity) {
11365
+ riskyPatterns.push(`Quantifier nesting depth: ${quantifierDepth} (max: ${maxComplexity})`);
11366
+ }
11367
+ if (hasExponentialBacktracking(pattern)) {
11368
+ riskyPatterns.push("Exponential backtracking potential detected");
11369
+ }
11370
+ return {
11371
+ safe: riskyPatterns.length === 0,
11372
+ pattern,
11373
+ escapedPattern: this.escapeRegex(pattern),
11374
+ riskyPatterns,
11375
+ error: riskyPatterns.length > 0 ? "Pattern may cause ReDoS" : void 0
11376
+ };
11377
+ }
11378
+ /**
11379
+ * Escape special regex characters in a string
11380
+ */
11381
+ escapeRegex(str) {
11382
+ return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
11383
+ }
11384
+ /**
11385
+ * Create a safe regex with validation
11386
+ */
11387
+ createSafeRegex(pattern, flags, maxLength = 1e4) {
11388
+ const safety = this.isRegexSafe(pattern);
11389
+ if (!safety.safe) {
11390
+ return null;
11391
+ }
11392
+ if (pattern.length > maxLength) {
11393
+ return null;
11394
+ }
11395
+ try {
11396
+ return new RegExp(pattern, flags);
11397
+ } catch {
11398
+ return null;
11399
+ }
11400
+ }
11401
+ };
11402
+ var defaultValidator2 = new RegexSafetyValidator();
11403
+
11404
+ // src/mcp/security/validators/crypto-validator.ts
11405
+ import { createHash, timingSafeEqual, randomBytes } from "crypto";
11406
+ var CryptoValidator = class {
11407
+ name = "crypto-security";
11408
+ /**
11409
+ * Get the primary risk level this validator addresses
11410
+ */
11411
+ getRiskLevel() {
11412
+ return "critical";
11413
+ }
11414
+ /**
11415
+ * Perform a timing-safe string comparison
11416
+ * Prevents timing attacks by ensuring constant-time comparison
11417
+ */
11418
+ timingSafeCompare(a, b) {
11419
+ const maxLen = Math.max(a.length, b.length);
11420
+ const paddedA = a.padEnd(maxLen, "\0");
11421
+ const paddedB = b.padEnd(maxLen, "\0");
11422
+ try {
11423
+ return timingSafeEqual(Buffer.from(paddedA), Buffer.from(paddedB));
11424
+ } catch {
11425
+ return false;
11426
+ }
11427
+ }
11428
+ /**
11429
+ * Timing-safe comparison for hashed values
11430
+ * Hashes the input value and compares against expected hash
11431
+ */
11432
+ timingSafeHashCompare(value, expectedHash) {
11433
+ const hash = createHash("sha256").update(value).digest("hex");
11434
+ return this.timingSafeCompare(hash, expectedHash);
11435
+ }
11436
+ /**
11437
+ * Generate a secure random token
11438
+ * Uses cryptographically secure random bytes
11439
+ */
11440
+ generateSecureToken(length = 32) {
11441
+ return randomBytes(length).toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
11442
+ }
11443
+ /**
11444
+ * Hash a value securely using SHA-256
11445
+ */
11446
+ secureHash(value, salt) {
11447
+ const data = salt ? `${salt}:${value}` : value;
11448
+ return createHash("sha256").update(data).digest("hex");
11449
+ }
11450
+ };
11451
+ var defaultValidator3 = new CryptoValidator();
11452
+
11453
+ // src/mcp/security/validators/input-sanitizer.ts
11454
+ var HTML_ESCAPE_MAP = {
11455
+ "&": "&amp;",
11456
+ "<": "&lt;",
11457
+ ">": "&gt;",
11458
+ '"': "&quot;",
11459
+ "'": "&#x27;",
11460
+ "/": "&#x2F;",
11461
+ "`": "&#x60;",
11462
+ "=": "&#x3D;"
11463
+ };
11464
+ var SQL_INJECTION_PATTERNS = [
11465
+ /('|")\s*;\s*--/i,
11466
+ /'\s*OR\s+'1'\s*=\s*'1/i,
11467
+ /"\s*OR\s+"1"\s*=\s*"1/i,
11468
+ /UNION\s+SELECT/i,
11469
+ /INSERT\s+INTO/i,
11470
+ /DROP\s+TABLE/i,
11471
+ /DELETE\s+FROM/i,
11472
+ /UPDATE\s+.*\s+SET/i,
11473
+ /EXEC(\s+|\()sp_/i,
11474
+ /xp_cmdshell/i
11475
+ ];
11476
+ var SHELL_METACHARACTERS = /[|;&$`<>{}[\]!#*?~]/g;
11477
+ var DANGEROUS_CONTROL_CHARS = /[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g;
11478
+ var InputSanitizer = class {
11479
+ name = "input-sanitization";
11480
+ /**
11481
+ * Get the primary risk level this sanitizer addresses
11482
+ */
11483
+ getRiskLevel() {
11484
+ return "high";
11485
+ }
11486
+ /**
11487
+ * Sanitize input string with configurable options
11488
+ */
11489
+ sanitize(input, options = {}) {
11490
+ const {
11491
+ maxLength = 1e4,
11492
+ allowedChars,
11493
+ stripHtml = true,
11494
+ stripSql = true,
11495
+ escapeShell = true,
11496
+ trim = true,
11497
+ stripControlChars = true
11498
+ } = options;
11499
+ let result = input;
11500
+ if (stripControlChars) {
11501
+ result = result.replace(DANGEROUS_CONTROL_CHARS, "");
11502
+ }
11503
+ if (trim) {
11504
+ result = result.trim();
11505
+ }
11506
+ if (result.length > maxLength) {
11507
+ result = result.substring(0, maxLength);
11508
+ }
11509
+ if (stripHtml) {
11510
+ result = this.stripHtmlTags(result);
11511
+ }
11512
+ if (stripSql) {
11513
+ for (const pattern of SQL_INJECTION_PATTERNS) {
11514
+ result = result.replace(pattern, "");
11515
+ }
11516
+ }
11517
+ if (escapeShell) {
11518
+ result = result.replace(SHELL_METACHARACTERS, "");
11519
+ }
11520
+ if (allowedChars) {
11521
+ result = result.split("").filter((char) => allowedChars.test(char)).join("");
11522
+ }
11523
+ return result;
11524
+ }
11525
+ /**
11526
+ * Escape HTML special characters
11527
+ */
11528
+ escapeHtml(str) {
11529
+ return str.replace(/[&<>"'`=/]/g, (char) => HTML_ESCAPE_MAP[char] || char);
11530
+ }
11531
+ /**
11532
+ * Strip HTML tags from a string
11533
+ * Handles both complete tags and incomplete/malformed tags to prevent XSS
11534
+ */
11535
+ stripHtmlTags(str) {
11536
+ const MAX_LENGTH = 1e5;
11537
+ if (str.length > MAX_LENGTH) {
11538
+ str = str.slice(0, MAX_LENGTH);
11539
+ }
11540
+ let result = str;
11541
+ let prevLength;
11542
+ do {
11543
+ prevLength = result.length;
11544
+ let cleaned = "";
11545
+ let inTag = false;
11546
+ for (let i = 0; i < result.length; i++) {
11547
+ const char = result[i];
11548
+ if (char === "<") {
11549
+ inTag = true;
11550
+ } else if (char === ">" && inTag) {
11551
+ inTag = false;
11552
+ } else if (!inTag) {
11553
+ cleaned += char;
11554
+ }
11555
+ }
11556
+ result = cleaned;
11557
+ } while (result.length < prevLength && result.length > 0);
11558
+ result = result.replace(/</g, "&lt;").replace(/>/g, "&gt;");
11559
+ return result;
11560
+ }
11561
+ };
11562
+ var defaultSanitizer = new InputSanitizer();
11563
+ var sanitizeInput = (input, options) => defaultSanitizer.sanitize(input, options);
11564
+
11565
+ // src/mcp/security/validators/command-validator.ts
11566
+ var DEFAULT_ALLOWED_COMMANDS = [
11567
+ "ls",
11568
+ "cat",
11569
+ "echo",
11570
+ "grep",
11571
+ "find",
11572
+ "head",
11573
+ "tail",
11574
+ "wc",
11575
+ "npm",
11576
+ "node",
11577
+ "yarn",
11578
+ "pnpm",
11579
+ "git",
11580
+ "jest",
11581
+ "vitest",
11582
+ "playwright"
11583
+ ];
11584
+ var BLOCKED_COMMAND_PATTERNS = [
11585
+ /;/,
11586
+ // Command chaining with semicolon
11587
+ /&&/,
11588
+ // Command chaining with AND
11589
+ /\|\|/,
11590
+ // Command chaining with OR
11591
+ /\|/,
11592
+ // Piping
11593
+ /`.*`/,
11594
+ // Backtick command substitution
11595
+ /\$\(.*\)/,
11596
+ // $() command substitution
11597
+ />\s*\/dev\/sd/i,
11598
+ // Writing to block devices
11599
+ />\s*\/etc\//i
11600
+ // Writing to /etc
11601
+ ];
11602
+ var SHELL_METACHARACTERS2 = /[|;&$`<>{}[\]!#*?~]/g;
11603
+ var CommandValidator = class {
11604
+ name = "command-injection";
11605
+ defaultAllowedCommands;
11606
+ constructor(defaultAllowedCommands = DEFAULT_ALLOWED_COMMANDS) {
11607
+ this.defaultAllowedCommands = defaultAllowedCommands;
11608
+ }
11609
+ /**
11610
+ * Get the primary risk level this validator addresses
11611
+ */
11612
+ getRiskLevel() {
11613
+ return "critical";
11614
+ }
11615
+ /**
11616
+ * Validate a command (IValidationStrategy interface)
11617
+ */
11618
+ validate(command, options = {}) {
11619
+ const allowedCommands = options.allowedCommands ?? this.defaultAllowedCommands;
11620
+ return this.validateCommand(command, allowedCommands);
11621
+ }
11622
+ /**
11623
+ * Validate and sanitize a command
11624
+ */
11625
+ validateCommand(command, allowedCommands = this.defaultAllowedCommands) {
11626
+ const blockedPatterns = [];
11627
+ for (const pattern of BLOCKED_COMMAND_PATTERNS) {
11628
+ if (pattern.test(command)) {
11629
+ blockedPatterns.push(pattern.source);
11630
+ }
11631
+ }
11632
+ if (blockedPatterns.length > 0) {
11633
+ return {
11634
+ valid: false,
11635
+ error: "Command contains blocked patterns",
11636
+ blockedPatterns,
11637
+ riskLevel: "critical"
11638
+ };
11639
+ }
11640
+ const parts = command.trim().split(/\s+/);
11641
+ const baseCommand = parts[0].split("/").pop() || "";
11642
+ if (!allowedCommands.includes(baseCommand)) {
11643
+ return {
11644
+ valid: false,
11645
+ error: `Command '${baseCommand}' is not in the allowed list`,
11646
+ blockedPatterns: [],
11647
+ riskLevel: "high"
11648
+ };
11649
+ }
11650
+ const sanitizedParts = parts.map((part, i) => {
11651
+ if (i === 0) return part;
11652
+ return part.replace(SHELL_METACHARACTERS2, "");
11653
+ });
11654
+ return {
11655
+ valid: true,
11656
+ sanitizedCommand: sanitizedParts.join(" "),
11657
+ blockedPatterns: [],
11658
+ riskLevel: "none"
11659
+ };
11660
+ }
11661
+ /**
11662
+ * Escape a string for safe shell usage
11663
+ */
11664
+ escapeShellArg(arg) {
11665
+ return `'${arg.replace(/'/g, "'\\''")}'`;
11666
+ }
11667
+ };
11668
+ var defaultValidator4 = new CommandValidator();
11669
+ var validateCommand = (command, allowedCommands) => {
11670
+ if (allowedCommands) {
11671
+ return defaultValidator4.validateCommand(command, allowedCommands);
11672
+ }
11673
+ return defaultValidator4.validate(command);
11674
+ };
11675
+
10872
11676
  // src/mcp/tool-registry.ts
11677
+ var VALID_TOOL_NAME_PATTERN = /^[a-zA-Z][a-zA-Z0-9_:-]{0,127}$/;
11678
+ var MAX_PARAM_STRING_LENGTH = 1e6;
11679
+ function validateToolName(name) {
11680
+ if (typeof name !== "string") {
11681
+ return { valid: false, error: "Tool name must be a string" };
11682
+ }
11683
+ if (name.length === 0) {
11684
+ return { valid: false, error: "Tool name cannot be empty" };
11685
+ }
11686
+ if (name.length > 128) {
11687
+ return { valid: false, error: "Tool name exceeds maximum length (128)" };
11688
+ }
11689
+ if (!VALID_TOOL_NAME_PATTERN.test(name)) {
11690
+ return {
11691
+ valid: false,
11692
+ error: "Tool name contains invalid characters. Use only alphanumeric, underscore, hyphen, or colon"
11693
+ };
11694
+ }
11695
+ return { valid: true };
11696
+ }
11697
+ function validateParamValue(value, param) {
11698
+ if (value === void 0 || value === null) {
11699
+ if (param.required) {
11700
+ return { valid: false, error: `Required parameter '${param.name}' is missing` };
11701
+ }
11702
+ return { valid: true };
11703
+ }
11704
+ switch (param.type) {
11705
+ case "string":
11706
+ if (typeof value !== "string") {
11707
+ return { valid: false, error: `Parameter '${param.name}' must be a string` };
11708
+ }
11709
+ if (value.length > MAX_PARAM_STRING_LENGTH) {
11710
+ return { valid: false, error: `Parameter '${param.name}' exceeds maximum length` };
11711
+ }
11712
+ break;
11713
+ case "number":
11714
+ if (typeof value !== "number" || isNaN(value)) {
11715
+ return { valid: false, error: `Parameter '${param.name}' must be a number` };
11716
+ }
11717
+ break;
11718
+ case "boolean":
11719
+ if (typeof value !== "boolean") {
11720
+ return { valid: false, error: `Parameter '${param.name}' must be a boolean` };
11721
+ }
11722
+ break;
11723
+ case "object":
11724
+ if (typeof value !== "object" || Array.isArray(value)) {
11725
+ return { valid: false, error: `Parameter '${param.name}' must be an object` };
11726
+ }
11727
+ break;
11728
+ case "array":
11729
+ if (!Array.isArray(value)) {
11730
+ return { valid: false, error: `Parameter '${param.name}' must be an array` };
11731
+ }
11732
+ break;
11733
+ }
11734
+ if (param.enum && param.enum.length > 0) {
11735
+ if (!param.enum.includes(value)) {
11736
+ return {
11737
+ valid: false,
11738
+ error: `Parameter '${param.name}' must be one of: ${param.enum.join(", ")}`
11739
+ };
11740
+ }
11741
+ }
11742
+ return { valid: true };
11743
+ }
11744
+ function validateParams(params, definition) {
11745
+ const errors = [];
11746
+ const knownParams = new Set(definition.parameters.map((p) => p.name));
11747
+ for (const key of Object.keys(params)) {
11748
+ if (!knownParams.has(key)) {
11749
+ errors.push(`Unknown parameter: '${key}'`);
11750
+ }
11751
+ }
11752
+ for (const param of definition.parameters) {
11753
+ const result = validateParamValue(params[param.name], param);
11754
+ if (!result.valid && result.error) {
11755
+ errors.push(result.error);
11756
+ }
11757
+ }
11758
+ return { valid: errors.length === 0, errors };
11759
+ }
11760
+ function sanitizeParams(params) {
11761
+ const sanitized = { ...params };
11762
+ for (const [key, value] of Object.entries(sanitized)) {
11763
+ if (typeof value === "string") {
11764
+ sanitized[key] = sanitizeInput(value);
11765
+ } else if (Array.isArray(value)) {
11766
+ sanitized[key] = value.map(
11767
+ (item) => typeof item === "string" ? sanitizeInput(item) : item
11768
+ );
11769
+ } else if (typeof value === "object" && value !== null) {
11770
+ sanitized[key] = sanitizeParams(value);
11771
+ }
11772
+ }
11773
+ return sanitized;
11774
+ }
10873
11775
  var DOMAIN_KEYWORDS = {
10874
11776
  "test-generation": [
10875
11777
  "test",
@@ -11137,11 +12039,20 @@ var ToolRegistry = class {
11137
12039
  return Array.from(names).map((name) => this.tools.get(name)?.definition).filter((d) => d !== void 0);
11138
12040
  }
11139
12041
  /**
11140
- * Invoke a tool
12042
+ * Invoke a tool with input validation and sanitization (SEC-001 fix)
11141
12043
  */
11142
12044
  async invoke(name, params) {
11143
12045
  const startTime = Date.now();
11144
12046
  const requestId = uuidv4();
12047
+ const nameValidation = validateToolName(name);
12048
+ if (!nameValidation.valid) {
12049
+ this.stats.errors++;
12050
+ return {
12051
+ success: false,
12052
+ error: `Invalid tool name: ${nameValidation.error}`,
12053
+ metadata: this.createMetadata(startTime, requestId)
12054
+ };
12055
+ }
11145
12056
  const tool = this.tools.get(name);
11146
12057
  if (!tool) {
11147
12058
  this.stats.errors++;
@@ -11151,6 +12062,16 @@ var ToolRegistry = class {
11151
12062
  metadata: this.createMetadata(startTime, requestId)
11152
12063
  };
11153
12064
  }
12065
+ const paramValidation = validateParams(params, tool.definition);
12066
+ if (!paramValidation.valid) {
12067
+ this.stats.errors++;
12068
+ return {
12069
+ success: false,
12070
+ error: `Parameter validation failed: ${paramValidation.errors.join("; ")}`,
12071
+ metadata: this.createMetadata(startTime, requestId, tool.definition.domain)
12072
+ };
12073
+ }
12074
+ const sanitizedParams = sanitizeParams(params);
11154
12075
  if (!tool.loaded) {
11155
12076
  tool.loaded = true;
11156
12077
  this.stats.loadedTools++;
@@ -11159,7 +12080,7 @@ var ToolRegistry = class {
11159
12080
  tool.lastUsed = /* @__PURE__ */ new Date();
11160
12081
  this.stats.invocations++;
11161
12082
  try {
11162
- const result = await tool.handler(params);
12083
+ const result = await tool.handler(sanitizedParams);
11163
12084
  return {
11164
12085
  ...result,
11165
12086
  metadata: {
@@ -11971,8 +12892,10 @@ var BaseDomainPlugin = class {
11971
12892
  this.memory = memory;
11972
12893
  }
11973
12894
  _initialized = false;
12895
+ // Issue #205 fix: Default to 'idle' status for fresh installs (0 agents)
12896
+ // Domains transition to 'healthy' when they have active agents
11974
12897
  _health = {
11975
- status: "healthy",
12898
+ status: "idle",
11976
12899
  agents: { total: 0, active: 0, idle: 0, failed: 0 },
11977
12900
  errors: []
11978
12901
  };
@@ -12094,403 +13017,207 @@ import { v4 as uuidv44 } from "uuid";
12094
13017
  import * as fs2 from "fs";
12095
13018
  import * as path2 from "path";
12096
13019
  import * as ts from "typescript";
13020
+
13021
+ // src/domains/test-generation/generators/base-test-generator.ts
12097
13022
  import { faker } from "@faker-js/faker";
12098
- var DEFAULT_CONFIG = {
12099
- defaultFramework: "jest",
12100
- maxTestsPerFile: 50,
12101
- coverageTargetDefault: 80,
12102
- enableAIGeneration: true
12103
- };
12104
- var TestGeneratorService = class {
12105
- constructor(memory, config = {}) {
12106
- this.memory = memory;
12107
- this.config = { ...DEFAULT_CONFIG, ...config };
12108
- }
12109
- config;
12110
- /**
12111
- * Generate tests for given source files
12112
- */
12113
- async generateTests(request) {
12114
- try {
12115
- const {
12116
- sourceFiles,
12117
- testType,
12118
- framework,
12119
- coverageTarget = this.config.coverageTargetDefault,
12120
- patterns = []
12121
- } = request;
12122
- if (sourceFiles.length === 0) {
12123
- return err(new Error("No source files provided"));
12124
- }
12125
- const tests = [];
12126
- const patternsUsed = [];
12127
- for (const sourceFile of sourceFiles) {
12128
- const fileTests = await this.generateTestsForFile(
12129
- sourceFile,
12130
- testType,
12131
- framework,
12132
- patterns
12133
- );
12134
- if (fileTests.success) {
12135
- tests.push(...fileTests.value.tests);
12136
- patternsUsed.push(...fileTests.value.patternsUsed);
12137
- }
12138
- }
12139
- const coverageEstimate = this.estimateCoverage(tests, coverageTarget);
12140
- await this.storeGenerationMetadata(tests, patternsUsed);
12141
- return ok({
12142
- tests,
12143
- coverageEstimate,
12144
- patternsUsed: [...new Set(patternsUsed)]
12145
- });
12146
- } catch (error) {
12147
- return err(error instanceof Error ? error : new Error(String(error)));
12148
- }
12149
- }
13023
+ var BaseTestGenerator = class {
13024
+ // ============================================================================
13025
+ // Shared Utilities - Available to all subclasses
13026
+ // ============================================================================
12150
13027
  /**
12151
- * Generate tests specifically targeting coverage gaps
13028
+ * Generate a test value for a parameter based on its type and name
13029
+ * Uses @faker-js/faker for realistic test data
13030
+ *
13031
+ * @param param - Parameter information
13032
+ * @returns Generated test value as a string
12152
13033
  */
12153
- async generateForCoverageGap(file, uncoveredLines, framework) {
12154
- try {
12155
- if (uncoveredLines.length === 0) {
12156
- return ok([]);
12157
- }
12158
- const tests = [];
12159
- const lineGroups = this.groupConsecutiveLines(uncoveredLines);
12160
- for (const group of lineGroups) {
12161
- const test = await this.generateTestForLines(file, group, framework);
12162
- if (test) {
12163
- tests.push(test);
12164
- }
12165
- }
12166
- return ok(tests);
12167
- } catch (error) {
12168
- return err(error instanceof Error ? error : new Error(String(error)));
13034
+ generateTestValue(param) {
13035
+ if (param.defaultValue) {
13036
+ return param.defaultValue;
12169
13037
  }
13038
+ const type = param.type?.toLowerCase() || "unknown";
13039
+ const name = param.name.toLowerCase();
13040
+ if (name.includes("id")) return `'${faker.string.uuid()}'`;
13041
+ if (name.includes("email")) return `'${faker.internet.email()}'`;
13042
+ if (name.includes("name")) return `'${faker.person.fullName()}'`;
13043
+ if (name.includes("url")) return `'${faker.internet.url()}'`;
13044
+ if (name.includes("date")) return `new Date('${faker.date.recent().toISOString()}')`;
13045
+ if (name.includes("phone")) return `'${faker.phone.number()}'`;
13046
+ if (name.includes("address")) return `'${faker.location.streetAddress()}'`;
13047
+ if (type.includes("string")) return `'${faker.lorem.word()}'`;
13048
+ if (type.includes("number")) return String(faker.number.int({ min: 1, max: 100 }));
13049
+ if (type.includes("boolean")) return "true";
13050
+ if (type.includes("[]") || type.includes("array")) return "[]";
13051
+ if (type.includes("object") || type.includes("{")) return "{}";
13052
+ if (type.includes("function")) return "() => {}";
13053
+ if (type.includes("promise")) return "Promise.resolve()";
13054
+ if (type.includes("date")) return "new Date()";
13055
+ return `mock${param.name.charAt(0).toUpperCase() + param.name.slice(1)}`;
12170
13056
  }
12171
13057
  /**
12172
- * Generate tests following TDD workflow
13058
+ * Generate test cases for a function based on its signature
13059
+ * Creates happy-path, edge-case, error-handling, and boundary tests
13060
+ *
13061
+ * @param fn - Function information from AST
13062
+ * @returns Array of test cases
12173
13063
  */
12174
- async generateTDDTests(request) {
12175
- try {
12176
- const { feature, behavior, framework, phase } = request;
12177
- switch (phase) {
12178
- case "red":
12179
- return ok(await this.generateRedPhaseTest(feature, behavior, framework));
12180
- case "green":
12181
- return ok(await this.generateGreenPhaseCode(feature, behavior, framework));
12182
- case "refactor":
12183
- return ok(await this.generateRefactoringSuggestions(feature, behavior));
12184
- default:
12185
- return err(new Error(`Unknown TDD phase: ${phase}`));
13064
+ generateTestCasesForFunction(fn) {
13065
+ const testCases = [];
13066
+ const validParams = fn.parameters.map((p) => this.generateTestValue(p)).join(", ");
13067
+ const fnCall = fn.isAsync ? `await ${fn.name}(${validParams})` : `${fn.name}(${validParams})`;
13068
+ testCases.push({
13069
+ description: "should handle valid input correctly",
13070
+ type: "happy-path",
13071
+ action: `const result = ${fnCall};`,
13072
+ assertion: "expect(result).toBeDefined();"
13073
+ });
13074
+ for (const param of fn.parameters) {
13075
+ if (!param.optional) {
13076
+ const paramsWithUndefined = fn.parameters.map((p) => p.name === param.name ? "undefined" : this.generateTestValue(p)).join(", ");
13077
+ testCases.push({
13078
+ description: `should handle undefined ${param.name}`,
13079
+ type: "error-handling",
13080
+ action: fn.isAsync ? `const action = async () => await ${fn.name}(${paramsWithUndefined});` : `const action = () => ${fn.name}(${paramsWithUndefined});`,
13081
+ assertion: "expect(action).toThrow();"
13082
+ });
12186
13083
  }
12187
- } catch (error) {
12188
- return err(error instanceof Error ? error : new Error(String(error)));
13084
+ testCases.push(...this.generateBoundaryTestCases(fn, param));
12189
13085
  }
12190
- }
12191
- /**
12192
- * Generate property-based tests
12193
- */
12194
- async generatePropertyTests(request) {
12195
- try {
12196
- const { function: funcName, properties, constraints = {} } = request;
12197
- const tests = properties.map((property) => ({
12198
- property,
12199
- testCode: this.generatePropertyTestCode(funcName, property, constraints),
12200
- generators: this.inferGenerators(property, constraints)
12201
- }));
12202
- return ok({
12203
- tests,
12204
- arbitraries: this.collectArbitraries(tests)
13086
+ if (fn.isAsync) {
13087
+ testCases.push({
13088
+ description: "should handle async rejection gracefully",
13089
+ type: "error-handling",
13090
+ action: `// Mock or setup to cause rejection`,
13091
+ assertion: `// await expect(${fn.name}(invalidParams)).rejects.toThrow();`
12205
13092
  });
12206
- } catch (error) {
12207
- return err(error instanceof Error ? error : new Error(String(error)));
12208
13093
  }
13094
+ return testCases;
12209
13095
  }
12210
13096
  /**
12211
- * Generate test data based on schema
13097
+ * Generate boundary test cases for a parameter based on its type
12212
13098
  */
12213
- async generateTestData(request) {
12214
- try {
12215
- const { schema, count, locale = "en", preserveRelationships = false } = request;
12216
- const seed = Date.now();
12217
- const records = [];
12218
- for (let i = 0; i < count; i++) {
12219
- const record = this.generateRecordFromSchema(schema, seed + i, locale);
12220
- records.push(record);
12221
- }
12222
- if (preserveRelationships) {
12223
- this.linkRelatedRecords(records, schema);
12224
- }
12225
- return ok({
12226
- records,
12227
- schema,
12228
- seed
13099
+ generateBoundaryTestCases(fn, param) {
13100
+ const testCases = [];
13101
+ const type = param.type?.toLowerCase() || "";
13102
+ if (type.includes("string")) {
13103
+ const paramsWithEmpty = fn.parameters.map((p) => p.name === param.name ? "''" : this.generateTestValue(p)).join(", ");
13104
+ const emptyCall = fn.isAsync ? `await ${fn.name}(${paramsWithEmpty})` : `${fn.name}(${paramsWithEmpty})`;
13105
+ testCases.push({
13106
+ description: `should handle empty string for ${param.name}`,
13107
+ type: "boundary",
13108
+ action: `const result = ${emptyCall};`,
13109
+ assertion: "expect(result).toBeDefined();"
12229
13110
  });
12230
- } catch (error) {
12231
- return err(error instanceof Error ? error : new Error(String(error)));
12232
13111
  }
12233
- }
12234
- // ============================================================================
12235
- // Private Helper Methods
12236
- // ============================================================================
12237
- async generateTestsForFile(sourceFile, testType, framework, patterns) {
12238
- const testFile = this.getTestFilePath(sourceFile, framework);
12239
- const patternsUsed = [];
12240
- const applicablePatterns = await this.findApplicablePatterns(sourceFile, patterns);
12241
- patternsUsed.push(...applicablePatterns.map((p) => p.name));
12242
- let codeAnalysis = null;
12243
- try {
12244
- const content = fs2.readFileSync(sourceFile, "utf-8");
12245
- codeAnalysis = this.analyzeSourceCode(content, sourceFile);
12246
- } catch {
13112
+ if (type.includes("number")) {
13113
+ const paramsWithZero = fn.parameters.map((p) => p.name === param.name ? "0" : this.generateTestValue(p)).join(", ");
13114
+ const zeroCall = fn.isAsync ? `await ${fn.name}(${paramsWithZero})` : `${fn.name}(${paramsWithZero})`;
13115
+ testCases.push({
13116
+ description: `should handle zero for ${param.name}`,
13117
+ type: "boundary",
13118
+ action: `const result = ${zeroCall};`,
13119
+ assertion: "expect(result).toBeDefined();"
13120
+ });
13121
+ const paramsWithNegative = fn.parameters.map((p) => p.name === param.name ? "-1" : this.generateTestValue(p)).join(", ");
13122
+ const negativeCall = fn.isAsync ? `await ${fn.name}(${paramsWithNegative})` : `${fn.name}(${paramsWithNegative})`;
13123
+ testCases.push({
13124
+ description: `should handle negative value for ${param.name}`,
13125
+ type: "edge-case",
13126
+ action: `const result = ${negativeCall};`,
13127
+ assertion: "expect(result).toBeDefined();"
13128
+ });
12247
13129
  }
12248
- let testCode;
12249
- if (codeAnalysis && (codeAnalysis.functions.length > 0 || codeAnalysis.classes.length > 0)) {
12250
- testCode = this.generateRealTestCode(
12251
- sourceFile,
12252
- testType,
12253
- framework,
12254
- codeAnalysis,
12255
- applicablePatterns
12256
- );
12257
- } else {
12258
- testCode = this.generateStubTestCode(sourceFile, testType, framework, applicablePatterns);
13130
+ if (type.includes("[]") || type.includes("array")) {
13131
+ const paramsWithEmpty = fn.parameters.map((p) => p.name === param.name ? "[]" : this.generateTestValue(p)).join(", ");
13132
+ const emptyCall = fn.isAsync ? `await ${fn.name}(${paramsWithEmpty})` : `${fn.name}(${paramsWithEmpty})`;
13133
+ testCases.push({
13134
+ description: `should handle empty array for ${param.name}`,
13135
+ type: "boundary",
13136
+ action: `const result = ${emptyCall};`,
13137
+ assertion: "expect(result).toBeDefined();"
13138
+ });
12259
13139
  }
12260
- const test = {
12261
- id: uuidv44(),
12262
- name: `${this.extractModuleName(sourceFile)} tests`,
12263
- sourceFile,
12264
- testFile,
12265
- testCode,
12266
- type: testType,
12267
- assertions: this.countAssertions(testCode)
12268
- };
12269
- return ok({ tests: [test], patternsUsed });
13140
+ return testCases;
12270
13141
  }
12271
13142
  /**
12272
- * Analyze source code using TypeScript AST
13143
+ * Extract exports from code analysis for import statements
12273
13144
  */
12274
- analyzeSourceCode(content, fileName) {
12275
- const sourceFile = ts.createSourceFile(
12276
- path2.basename(fileName),
12277
- content,
12278
- ts.ScriptTarget.Latest,
12279
- true,
12280
- ts.ScriptKind.TS
12281
- );
12282
- const functions = [];
12283
- const classes = [];
12284
- const visit = (node) => {
12285
- if (ts.isFunctionDeclaration(node) && node.name) {
12286
- functions.push(this.extractFunctionInfo(node, sourceFile));
12287
- } else if (ts.isVariableStatement(node)) {
12288
- for (const declaration of node.declarationList.declarations) {
12289
- if (ts.isVariableDeclaration(declaration) && declaration.initializer && (ts.isArrowFunction(declaration.initializer) || ts.isFunctionExpression(declaration.initializer))) {
12290
- const name = declaration.name.getText(sourceFile);
12291
- functions.push(
12292
- this.extractArrowFunctionInfo(name, declaration.initializer, sourceFile, node)
12293
- );
12294
- }
12295
- }
12296
- } else if (ts.isClassDeclaration(node) && node.name) {
12297
- classes.push(this.extractClassInfo(node, sourceFile));
12298
- }
12299
- ts.forEachChild(node, visit);
12300
- };
12301
- ts.forEachChild(sourceFile, visit);
12302
- return { functions, classes };
13145
+ extractExports(functions, classes) {
13146
+ const exports = [];
13147
+ for (const fn of functions) {
13148
+ if (fn.isExported) exports.push(fn.name);
13149
+ }
13150
+ for (const cls of classes) {
13151
+ if (cls.isExported) exports.push(cls.name);
13152
+ }
13153
+ return exports;
12303
13154
  }
12304
13155
  /**
12305
- * Extract function information from AST
13156
+ * Generate import statement based on exports
12306
13157
  */
12307
- extractFunctionInfo(node, sourceFile) {
12308
- const name = node.name?.getText(sourceFile) || "anonymous";
12309
- const parameters = this.extractParameters(node.parameters, sourceFile);
12310
- const returnType = node.type?.getText(sourceFile);
12311
- const isAsync = node.modifiers?.some((m) => m.kind === ts.SyntaxKind.AsyncKeyword) ?? false;
12312
- const isExported = node.modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword) ?? false;
12313
- const { line: startLine } = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile));
12314
- const { line: endLine } = sourceFile.getLineAndCharacterOfPosition(node.getEnd());
12315
- return {
12316
- name,
12317
- parameters,
12318
- returnType,
12319
- isAsync,
12320
- isExported,
12321
- complexity: this.calculateComplexity(node),
12322
- startLine: startLine + 1,
12323
- endLine: endLine + 1,
12324
- body: node.body?.getText(sourceFile)
12325
- };
13158
+ generateImportStatement(exports, importPath, moduleName) {
13159
+ if (exports.length > 0) {
13160
+ return `import { ${exports.join(", ")} } from '${importPath}';`;
13161
+ }
13162
+ return `import * as ${moduleName} from '${importPath}';`;
12326
13163
  }
12327
13164
  /**
12328
- * Extract arrow function information from AST
13165
+ * Generate pattern comment header
12329
13166
  */
12330
- extractArrowFunctionInfo(name, node, sourceFile, parentNode) {
12331
- const parameters = this.extractParameters(node.parameters, sourceFile);
12332
- const returnType = node.type?.getText(sourceFile);
12333
- const isAsync = node.modifiers?.some((m) => m.kind === ts.SyntaxKind.AsyncKeyword) ?? false;
12334
- const isExported = ts.isVariableStatement(parentNode) && (parentNode.modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword) ?? false);
12335
- const { line: startLine } = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile));
12336
- const { line: endLine } = sourceFile.getLineAndCharacterOfPosition(node.getEnd());
12337
- return {
12338
- name,
12339
- parameters,
12340
- returnType,
12341
- isAsync,
12342
- isExported,
12343
- complexity: this.calculateComplexity(node),
12344
- startLine: startLine + 1,
12345
- endLine: endLine + 1,
12346
- body: node.body?.getText(sourceFile)
12347
- };
13167
+ generatePatternComment(patterns) {
13168
+ if (patterns.length === 0) return "";
13169
+ return `// Applied patterns: ${patterns.map((p) => p.name).join(", ")}
13170
+ `;
12348
13171
  }
12349
13172
  /**
12350
- * Extract class information from AST
13173
+ * Convert string to camelCase
12351
13174
  */
12352
- extractClassInfo(node, sourceFile) {
12353
- const name = node.name?.getText(sourceFile) || "AnonymousClass";
12354
- const methods = [];
12355
- const properties = [];
12356
- let hasConstructor = false;
12357
- let constructorParams;
12358
- const isExported = node.modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword) ?? false;
12359
- for (const member of node.members) {
12360
- if (ts.isMethodDeclaration(member)) {
12361
- const methodName = member.name.getText(sourceFile);
12362
- const parameters = this.extractParameters(member.parameters, sourceFile);
12363
- const returnType = member.type?.getText(sourceFile);
12364
- const isAsync = member.modifiers?.some((m) => m.kind === ts.SyntaxKind.AsyncKeyword) ?? false;
12365
- const { line: startLine } = sourceFile.getLineAndCharacterOfPosition(
12366
- member.getStart(sourceFile)
12367
- );
12368
- const { line: endLine } = sourceFile.getLineAndCharacterOfPosition(member.getEnd());
12369
- methods.push({
12370
- name: methodName,
12371
- parameters,
12372
- returnType,
12373
- isAsync,
12374
- isExported: false,
12375
- complexity: this.calculateComplexity(member),
12376
- startLine: startLine + 1,
12377
- endLine: endLine + 1,
12378
- body: member.body?.getText(sourceFile)
12379
- });
12380
- } else if (ts.isConstructorDeclaration(member)) {
12381
- hasConstructor = true;
12382
- constructorParams = this.extractParameters(member.parameters, sourceFile);
12383
- } else if (ts.isPropertyDeclaration(member)) {
12384
- const propName = member.name.getText(sourceFile);
12385
- const propType = member.type?.getText(sourceFile);
12386
- const isPrivate = member.modifiers?.some((m) => m.kind === ts.SyntaxKind.PrivateKeyword) ?? false;
12387
- const isReadonly = member.modifiers?.some((m) => m.kind === ts.SyntaxKind.ReadonlyKeyword) ?? false;
12388
- properties.push({
12389
- name: propName,
12390
- type: propType,
12391
- isPrivate,
12392
- isReadonly
12393
- });
12394
- }
12395
- }
12396
- return {
12397
- name,
12398
- methods,
12399
- properties,
12400
- isExported,
12401
- hasConstructor,
12402
- constructorParams
12403
- };
13175
+ camelCase(str) {
13176
+ return str.replace(/[^a-zA-Z0-9]+(.)/g, (_, chr) => chr.toUpperCase()).replace(/^./, (chr) => chr.toLowerCase());
12404
13177
  }
12405
13178
  /**
12406
- * Extract parameters from a function
13179
+ * Convert string to PascalCase
12407
13180
  */
12408
- extractParameters(params, sourceFile) {
12409
- return params.map((param) => ({
12410
- name: param.name.getText(sourceFile),
12411
- type: param.type?.getText(sourceFile),
12412
- optional: param.questionToken !== void 0,
12413
- defaultValue: param.initializer?.getText(sourceFile)
12414
- }));
13181
+ pascalCase(str) {
13182
+ return str.replace(/[^a-zA-Z0-9]+(.)/g, (_, chr) => chr.toUpperCase()).replace(/^./, (chr) => chr.toUpperCase());
12415
13183
  }
12416
13184
  /**
12417
- * Calculate cyclomatic complexity of a node
13185
+ * Format line range for display
12418
13186
  */
12419
- calculateComplexity(node) {
12420
- let complexity = 1;
12421
- const visit = (n) => {
12422
- switch (n.kind) {
12423
- case ts.SyntaxKind.IfStatement:
12424
- case ts.SyntaxKind.ForStatement:
12425
- case ts.SyntaxKind.ForInStatement:
12426
- case ts.SyntaxKind.ForOfStatement:
12427
- case ts.SyntaxKind.WhileStatement:
12428
- case ts.SyntaxKind.DoStatement:
12429
- case ts.SyntaxKind.CaseClause:
12430
- case ts.SyntaxKind.CatchClause:
12431
- case ts.SyntaxKind.ConditionalExpression:
12432
- complexity++;
12433
- break;
12434
- case ts.SyntaxKind.BinaryExpression: {
12435
- const binary = n;
12436
- if (binary.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken || binary.operatorToken.kind === ts.SyntaxKind.BarBarToken) {
12437
- complexity++;
12438
- }
12439
- break;
12440
- }
12441
- }
12442
- ts.forEachChild(n, visit);
12443
- };
12444
- ts.forEachChild(node, visit);
12445
- return complexity;
13187
+ formatLineRange(lines) {
13188
+ if (lines.length === 1) {
13189
+ return `line ${lines[0]}`;
13190
+ }
13191
+ return `lines ${lines[0]}-${lines[lines.length - 1]}`;
13192
+ }
13193
+ };
13194
+
13195
+ // src/domains/test-generation/generators/jest-vitest-generator.ts
13196
+ var JestVitestGenerator = class extends BaseTestGenerator {
13197
+ framework;
13198
+ constructor(framework = "vitest") {
13199
+ super();
13200
+ this.framework = framework;
12446
13201
  }
12447
13202
  /**
12448
- * Generate real test code based on AST analysis
13203
+ * Get the mock utility name (vi for vitest, jest for jest)
12449
13204
  */
12450
- generateRealTestCode(sourceFile, testType, framework, analysis, patterns) {
12451
- const moduleName = this.extractModuleName(sourceFile);
12452
- const importPath = this.getImportPath(sourceFile);
12453
- switch (framework) {
12454
- case "jest":
12455
- case "vitest":
12456
- return this.generateRealJestVitestTest(
12457
- moduleName,
12458
- importPath,
12459
- testType,
12460
- analysis,
12461
- patterns,
12462
- framework
12463
- );
12464
- case "mocha":
12465
- return this.generateRealMochaTest(moduleName, importPath, testType, analysis, patterns);
12466
- case "pytest":
12467
- return this.generateRealPytestTest(moduleName, importPath, testType, analysis, patterns);
12468
- default:
12469
- return this.generateRealJestVitestTest(
12470
- moduleName,
12471
- importPath,
12472
- testType,
12473
- analysis,
12474
- patterns,
12475
- "vitest"
12476
- );
12477
- }
13205
+ get mockUtil() {
13206
+ return this.framework === "vitest" ? "vi" : "jest";
12478
13207
  }
12479
13208
  /**
12480
- * Generate real Jest/Vitest test code
13209
+ * Generate complete test file from analysis
12481
13210
  */
12482
- generateRealJestVitestTest(moduleName, importPath, testType, analysis, patterns, framework) {
12483
- const patternComment = patterns.length > 0 ? `// Applied patterns: ${patterns.map((p) => p.name).join(", ")}
12484
- ` : "";
12485
- const exports = [];
12486
- for (const fn of analysis.functions) {
12487
- if (fn.isExported) exports.push(fn.name);
12488
- }
12489
- for (const cls of analysis.classes) {
12490
- if (cls.isExported) exports.push(cls.name);
13211
+ generateTests(context) {
13212
+ const { moduleName, importPath, testType, patterns, analysis } = context;
13213
+ if (!analysis || analysis.functions.length === 0 && analysis.classes.length === 0) {
13214
+ return this.generateStubTests(context);
12491
13215
  }
12492
- const importStatement = exports.length > 0 ? `import { ${exports.join(", ")} } from '${importPath}';` : `import * as ${moduleName} from '${importPath}';`;
12493
- let testCode = `${patternComment}import { describe, it, expect, beforeEach${framework === "vitest" ? ", vi" : ""} } from '${framework}';
13216
+ const patternComment = this.generatePatternComment(patterns);
13217
+ const exports = this.extractExports(analysis.functions, analysis.classes);
13218
+ const importStatement = this.generateImportStatement(exports, importPath, moduleName);
13219
+ const mockImport = this.framework === "vitest" ? ", vi" : "";
13220
+ let testCode = `${patternComment}import { describe, it, expect, beforeEach${mockImport} } from '${this.framework}';
12494
13221
  ${importStatement}
12495
13222
 
12496
13223
  `;
@@ -12503,7 +13230,7 @@ ${importStatement}
12503
13230
  return testCode;
12504
13231
  }
12505
13232
  /**
12506
- * Generate tests for a function
13233
+ * Generate tests for a standalone function
12507
13234
  */
12508
13235
  generateFunctionTests(fn, _testType) {
12509
13236
  const testCases = this.generateTestCasesForFunction(fn);
@@ -12531,78 +13258,6 @@ ${importStatement}
12531
13258
  `;
12532
13259
  return code;
12533
13260
  }
12534
- /**
12535
- * Generate test cases for a function
12536
- */
12537
- generateTestCasesForFunction(fn) {
12538
- const testCases = [];
12539
- const validParams = fn.parameters.map((p) => this.generateTestValue(p)).join(", ");
12540
- const fnCall = fn.isAsync ? `await ${fn.name}(${validParams})` : `${fn.name}(${validParams})`;
12541
- testCases.push({
12542
- description: "should handle valid input correctly",
12543
- type: "happy-path",
12544
- action: `const result = ${fnCall};`,
12545
- assertion: "expect(result).toBeDefined();"
12546
- });
12547
- for (const param of fn.parameters) {
12548
- if (!param.optional) {
12549
- const paramsWithUndefined = fn.parameters.map((p) => p.name === param.name ? "undefined" : this.generateTestValue(p)).join(", ");
12550
- testCases.push({
12551
- description: `should handle undefined ${param.name}`,
12552
- type: "error-handling",
12553
- action: fn.isAsync ? `const action = async () => await ${fn.name}(${paramsWithUndefined});` : `const action = () => ${fn.name}(${paramsWithUndefined});`,
12554
- assertion: "expect(action).toThrow();"
12555
- });
12556
- }
12557
- if (param.type?.includes("string")) {
12558
- const paramsWithEmpty = fn.parameters.map((p) => p.name === param.name ? "''" : this.generateTestValue(p)).join(", ");
12559
- const emptyCall = fn.isAsync ? `await ${fn.name}(${paramsWithEmpty})` : `${fn.name}(${paramsWithEmpty})`;
12560
- testCases.push({
12561
- description: `should handle empty string for ${param.name}`,
12562
- type: "boundary",
12563
- action: `const result = ${emptyCall};`,
12564
- assertion: "expect(result).toBeDefined();"
12565
- });
12566
- }
12567
- if (param.type?.includes("number")) {
12568
- const paramsWithZero = fn.parameters.map((p) => p.name === param.name ? "0" : this.generateTestValue(p)).join(", ");
12569
- const zeroCall = fn.isAsync ? `await ${fn.name}(${paramsWithZero})` : `${fn.name}(${paramsWithZero})`;
12570
- testCases.push({
12571
- description: `should handle zero for ${param.name}`,
12572
- type: "boundary",
12573
- action: `const result = ${zeroCall};`,
12574
- assertion: "expect(result).toBeDefined();"
12575
- });
12576
- const paramsWithNegative = fn.parameters.map((p) => p.name === param.name ? "-1" : this.generateTestValue(p)).join(", ");
12577
- const negativeCall = fn.isAsync ? `await ${fn.name}(${paramsWithNegative})` : `${fn.name}(${paramsWithNegative})`;
12578
- testCases.push({
12579
- description: `should handle negative value for ${param.name}`,
12580
- type: "edge-case",
12581
- action: `const result = ${negativeCall};`,
12582
- assertion: "expect(result).toBeDefined();"
12583
- });
12584
- }
12585
- if (param.type?.includes("[]") || param.type?.includes("Array")) {
12586
- const paramsWithEmpty = fn.parameters.map((p) => p.name === param.name ? "[]" : this.generateTestValue(p)).join(", ");
12587
- const emptyCall = fn.isAsync ? `await ${fn.name}(${paramsWithEmpty})` : `${fn.name}(${paramsWithEmpty})`;
12588
- testCases.push({
12589
- description: `should handle empty array for ${param.name}`,
12590
- type: "boundary",
12591
- action: `const result = ${emptyCall};`,
12592
- assertion: "expect(result).toBeDefined();"
12593
- });
12594
- }
12595
- }
12596
- if (fn.isAsync) {
12597
- testCases.push({
12598
- description: "should handle async rejection gracefully",
12599
- type: "error-handling",
12600
- action: `// Mock or setup to cause rejection`,
12601
- assertion: `// await expect(${fn.name}(invalidParams)).rejects.toThrow();`
12602
- });
12603
- }
12604
- return testCases;
12605
- }
12606
13261
  /**
12607
13262
  * Generate tests for a class
12608
13263
  */
@@ -12682,259 +13337,11 @@ ${importStatement}
12682
13337
  return code;
12683
13338
  }
12684
13339
  /**
12685
- * Generate a test value for a parameter
12686
- */
12687
- generateTestValue(param) {
12688
- if (param.defaultValue) {
12689
- return param.defaultValue;
12690
- }
12691
- const type = param.type?.toLowerCase() || "unknown";
12692
- const name = param.name.toLowerCase();
12693
- if (name.includes("id")) return `'${faker.string.uuid()}'`;
12694
- if (name.includes("email")) return `'${faker.internet.email()}'`;
12695
- if (name.includes("name")) return `'${faker.person.fullName()}'`;
12696
- if (name.includes("url")) return `'${faker.internet.url()}'`;
12697
- if (name.includes("date")) return `new Date('${faker.date.recent().toISOString()}')`;
12698
- if (type.includes("string")) return `'${faker.lorem.word()}'`;
12699
- if (type.includes("number")) return String(faker.number.int({ min: 1, max: 100 }));
12700
- if (type.includes("boolean")) return "true";
12701
- if (type.includes("[]") || type.includes("array")) return "[]";
12702
- if (type.includes("object") || type.includes("{")) return "{}";
12703
- if (type.includes("function")) return "() => {}";
12704
- if (type.includes("promise")) return "Promise.resolve()";
12705
- if (type.includes("date")) return "new Date()";
12706
- return `mock${param.name.charAt(0).toUpperCase() + param.name.slice(1)}`;
12707
- }
12708
- /**
12709
- * Generate real Mocha test code
12710
- */
12711
- generateRealMochaTest(moduleName, importPath, testType, analysis, patterns) {
12712
- const patternComment = patterns.length > 0 ? `// Applied patterns: ${patterns.map((p) => p.name).join(", ")}
12713
- ` : "";
12714
- const exports = [];
12715
- for (const fn of analysis.functions) {
12716
- if (fn.isExported) exports.push(fn.name);
12717
- }
12718
- for (const cls of analysis.classes) {
12719
- if (cls.isExported) exports.push(cls.name);
12720
- }
12721
- const importStatement = exports.length > 0 ? `import { ${exports.join(", ")} } from '${importPath}';` : `import * as ${moduleName} from '${importPath}';`;
12722
- let code = `${patternComment}import { expect } from 'chai';
12723
- ${importStatement}
12724
-
12725
- describe('${moduleName} - ${testType} tests', function() {
12726
- `;
12727
- for (const fn of analysis.functions) {
12728
- code += this.generateMochaFunctionTests(fn);
12729
- }
12730
- for (const cls of analysis.classes) {
12731
- code += this.generateMochaClassTests(cls);
12732
- }
12733
- code += `});
12734
- `;
12735
- return code;
12736
- }
12737
- /**
12738
- * Generate Mocha tests for a function
12739
- */
12740
- generateMochaFunctionTests(fn) {
12741
- const validParams = fn.parameters.map((p) => this.generateTestValue(p)).join(", ");
12742
- const fnCall = fn.isAsync ? `await ${fn.name}(${validParams})` : `${fn.name}(${validParams})`;
12743
- let code = ` describe('${fn.name}', function() {
12744
- `;
12745
- code += ` it('should handle valid input', ${fn.isAsync ? "async " : ""}function() {
12746
- `;
12747
- code += ` const result = ${fnCall};
12748
- `;
12749
- code += ` expect(result).to.not.be.undefined;
12750
- `;
12751
- code += ` });
12752
- `;
12753
- code += ` });
12754
-
12755
- `;
12756
- return code;
12757
- }
12758
- /**
12759
- * Generate Mocha tests for a class
12760
- */
12761
- generateMochaClassTests(cls) {
12762
- const constructorArgs = cls.constructorParams?.map((p) => this.generateTestValue(p)).join(", ") || "";
12763
- let code = ` describe('${cls.name}', function() {
12764
- `;
12765
- code += ` let instance;
12766
-
12767
- `;
12768
- code += ` beforeEach(function() {
12769
- `;
12770
- code += ` instance = new ${cls.name}(${constructorArgs});
12771
- `;
12772
- code += ` });
12773
-
12774
- `;
12775
- code += ` it('should instantiate correctly', function() {
12776
- `;
12777
- code += ` expect(instance).to.be.instanceOf(${cls.name});
12778
- `;
12779
- code += ` });
12780
- `;
12781
- for (const method of cls.methods) {
12782
- if (!method.name.startsWith("_")) {
12783
- const methodParams = method.parameters.map((p) => this.generateTestValue(p)).join(", ");
12784
- code += `
12785
- it('${method.name} should work', ${method.isAsync ? "async " : ""}function() {
12786
- `;
12787
- code += ` const result = ${method.isAsync ? "await " : ""}instance.${method.name}(${methodParams});
12788
- `;
12789
- code += ` expect(result).to.not.be.undefined;
12790
- `;
12791
- code += ` });
12792
- `;
12793
- }
12794
- }
12795
- code += ` });
12796
-
12797
- `;
12798
- return code;
12799
- }
12800
- /**
12801
- * Generate real Pytest test code
12802
- */
12803
- generateRealPytestTest(moduleName, importPath, testType, analysis, patterns) {
12804
- const patternComment = patterns.length > 0 ? `# Applied patterns: ${patterns.map((p) => p.name).join(", ")}
12805
- ` : "";
12806
- const exports = [];
12807
- for (const fn of analysis.functions) {
12808
- if (fn.isExported) exports.push(fn.name);
12809
- }
12810
- for (const cls of analysis.classes) {
12811
- if (cls.isExported) exports.push(cls.name);
12812
- }
12813
- const pythonImport = importPath.replace(/\//g, ".").replace(/\.(ts|js)$/, "");
12814
- const importStatement = exports.length > 0 ? `from ${pythonImport} import ${exports.join(", ")}` : `import ${pythonImport} as ${moduleName}`;
12815
- let code = `${patternComment}import pytest
12816
- ${importStatement}
12817
-
12818
-
12819
- class Test${moduleName.charAt(0).toUpperCase() + moduleName.slice(1)}:
12820
- """${testType} tests for ${moduleName}"""
12821
-
12822
- `;
12823
- for (const fn of analysis.functions) {
12824
- code += this.generatePytestFunctionTests(fn);
12825
- }
12826
- for (const cls of analysis.classes) {
12827
- code += this.generatePytestClassTests(cls);
12828
- }
12829
- return code;
12830
- }
12831
- /**
12832
- * Generate Pytest tests for a function
12833
- */
12834
- generatePytestFunctionTests(fn) {
12835
- const validParams = fn.parameters.map((p) => this.generatePythonTestValue(p)).join(", ");
12836
- let code = ` def test_${fn.name}_valid_input(self):
12837
- `;
12838
- code += ` """Test ${fn.name} with valid input"""
12839
- `;
12840
- code += ` result = ${fn.name}(${validParams})
12841
- `;
12842
- code += ` assert result is not None
12843
-
12844
- `;
12845
- return code;
12846
- }
12847
- /**
12848
- * Generate Pytest tests for a class
12849
- */
12850
- generatePytestClassTests(cls) {
12851
- const constructorArgs = cls.constructorParams?.map((p) => this.generatePythonTestValue(p)).join(", ") || "";
12852
- let code = `
12853
- class Test${cls.name}:
12854
- `;
12855
- code += ` """Tests for ${cls.name}"""
12856
-
12857
- `;
12858
- code += ` @pytest.fixture
12859
- `;
12860
- code += ` def instance(self):
12861
- `;
12862
- code += ` return ${cls.name}(${constructorArgs})
12863
-
12864
- `;
12865
- code += ` def test_instantiation(self, instance):
12866
- `;
12867
- code += ` assert isinstance(instance, ${cls.name})
12868
-
12869
- `;
12870
- for (const method of cls.methods) {
12871
- if (!method.name.startsWith("_")) {
12872
- const methodParams = method.parameters.map((p) => this.generatePythonTestValue(p)).join(", ");
12873
- code += ` def test_${method.name}(self, instance):
12874
- `;
12875
- code += ` result = instance.${method.name}(${methodParams})
12876
- `;
12877
- code += ` assert result is not None
12878
-
12879
- `;
12880
- }
12881
- }
12882
- return code;
12883
- }
12884
- /**
12885
- * Generate a Python test value for a parameter
13340
+ * Generate stub tests when no AST analysis is available
12886
13341
  */
12887
- generatePythonTestValue(param) {
12888
- const type = param.type?.toLowerCase() || "unknown";
12889
- const name = param.name.toLowerCase();
12890
- if (name.includes("id")) return `"${faker.string.uuid()}"`;
12891
- if (name.includes("name")) return `"${faker.person.fullName()}"`;
12892
- if (name.includes("email")) return `"${faker.internet.email()}"`;
12893
- if (type.includes("str")) return `"${faker.lorem.word()}"`;
12894
- if (type.includes("int") || type.includes("number")) {
12895
- return String(faker.number.int({ min: 1, max: 100 }));
12896
- }
12897
- if (type.includes("bool")) return "True";
12898
- if (type.includes("list") || type.includes("[]")) return "[]";
12899
- if (type.includes("dict") || type.includes("{}")) return "{}";
12900
- return "None";
12901
- }
12902
- async findApplicablePatterns(sourceFile, requestedPatterns) {
12903
- const patterns = [];
12904
- for (const patternName of requestedPatterns) {
12905
- const stored = await this.memory.get(`pattern:${patternName}`);
12906
- if (stored) {
12907
- patterns.push(stored);
12908
- }
12909
- }
12910
- const extension = sourceFile.split(".").pop() || "";
12911
- const searchResults = await this.memory.search(`pattern:*:${extension}`, 5);
12912
- for (const key of searchResults) {
12913
- const pattern = await this.memory.get(key);
12914
- if (pattern && !patterns.some((p) => p.id === pattern.id)) {
12915
- patterns.push(pattern);
12916
- }
12917
- }
12918
- return patterns;
12919
- }
12920
- generateStubTestCode(sourceFile, testType, framework, patterns) {
12921
- const moduleName = this.extractModuleName(sourceFile);
12922
- const importPath = this.getImportPath(sourceFile);
12923
- switch (framework) {
12924
- case "jest":
12925
- case "vitest":
12926
- return this.generateJestVitestTest(moduleName, importPath, testType, patterns);
12927
- case "mocha":
12928
- return this.generateMochaTest(moduleName, importPath, testType, patterns);
12929
- case "pytest":
12930
- return this.generatePytestTest(moduleName, importPath, testType, patterns);
12931
- default:
12932
- return this.generateJestVitestTest(moduleName, importPath, testType, patterns);
12933
- }
12934
- }
12935
- generateJestVitestTest(moduleName, importPath, testType, patterns) {
12936
- const patternComment = patterns.length > 0 ? `// Applied patterns: ${patterns.map((p) => p.name).join(", ")}
12937
- ` : "";
13342
+ generateStubTests(context) {
13343
+ const { moduleName, importPath, testType, patterns } = context;
13344
+ const patternComment = this.generatePatternComment(patterns);
12938
13345
  const basicOpsTest = this.generateBasicOpsTest(moduleName, patterns);
12939
13346
  const edgeCaseTest = this.generateEdgeCaseTest(moduleName, patterns);
12940
13347
  const errorHandlingTest = this.generateErrorHandlingTest(moduleName, patterns);
@@ -12954,7 +13361,43 @@ ${errorHandlingTest}
12954
13361
  `;
12955
13362
  }
12956
13363
  /**
12957
- * Generate basic operations test based on patterns
13364
+ * Generate coverage-focused tests for specific lines
13365
+ */
13366
+ generateCoverageTests(moduleName, importPath, lines) {
13367
+ const funcName = this.camelCase(moduleName);
13368
+ const lineRange = this.formatLineRange(lines);
13369
+ return `// Coverage test for ${lineRange} in ${moduleName}
13370
+ import { ${funcName} } from '${importPath}';
13371
+
13372
+ describe('${moduleName} coverage', () => {
13373
+ describe('${lineRange}', () => {
13374
+ it('should execute code path covering ${lineRange}', () => {
13375
+ // Arrange: Set up test inputs to reach uncovered lines
13376
+ const testInput = undefined; // Replace with appropriate input
13377
+
13378
+ // Act: Execute the code path
13379
+ const result = ${funcName}(testInput);
13380
+
13381
+ // Assert: Verify the code was reached and behaves correctly
13382
+ expect(result).toBeDefined();
13383
+ });
13384
+
13385
+ it('should handle edge case for ${lineRange}', () => {
13386
+ // Arrange: Set up edge case input
13387
+ const edgeCaseInput = null;
13388
+
13389
+ // Act & Assert: Verify edge case handling
13390
+ expect(() => ${funcName}(edgeCaseInput)).not.toThrow();
13391
+ });
13392
+ });
13393
+ });
13394
+ `;
13395
+ }
13396
+ // ============================================================================
13397
+ // Pattern-Aware Stub Test Generators
13398
+ // ============================================================================
13399
+ /**
13400
+ * Generate basic operations test based on detected patterns
12958
13401
  */
12959
13402
  generateBasicOpsTest(moduleName, patterns) {
12960
13403
  const isService = patterns.some(
@@ -13013,7 +13456,7 @@ ${errorHandlingTest}
13013
13456
  });`;
13014
13457
  }
13015
13458
  /**
13016
- * Generate edge case test based on patterns
13459
+ * Generate edge case test based on detected patterns
13017
13460
  */
13018
13461
  generateEdgeCaseTest(moduleName, patterns) {
13019
13462
  const hasValidation = patterns.some(
@@ -13060,7 +13503,7 @@ ${errorHandlingTest}
13060
13503
  });`;
13061
13504
  }
13062
13505
  /**
13063
- * Generate error handling test based on patterns
13506
+ * Generate error handling test based on detected patterns
13064
13507
  */
13065
13508
  generateErrorHandlingTest(moduleName, patterns) {
13066
13509
  const hasErrorPattern = patterns.some(
@@ -13111,9 +13554,118 @@ ${errorHandlingTest}
13111
13554
  expect(() => Object.keys(${moduleName})).not.toThrow();
13112
13555
  });`;
13113
13556
  }
13114
- generateMochaTest(moduleName, importPath, testType, patterns) {
13115
- const patternComment = patterns.length > 0 ? `// Applied patterns: ${patterns.map((p) => p.name).join(", ")}
13116
- ` : "";
13557
+ };
13558
+
13559
+ // src/domains/test-generation/generators/mocha-generator.ts
13560
+ var MochaGenerator = class extends BaseTestGenerator {
13561
+ framework = "mocha";
13562
+ /**
13563
+ * Generate complete test file from analysis
13564
+ */
13565
+ generateTests(context) {
13566
+ const { moduleName, importPath, testType, patterns, analysis } = context;
13567
+ if (!analysis || analysis.functions.length === 0 && analysis.classes.length === 0) {
13568
+ return this.generateStubTests(context);
13569
+ }
13570
+ const patternComment = this.generatePatternComment(patterns);
13571
+ const exports = this.extractExports(analysis.functions, analysis.classes);
13572
+ const importStatement = this.generateImportStatement(exports, importPath, moduleName);
13573
+ let code = `${patternComment}import { expect } from 'chai';
13574
+ ${importStatement}
13575
+
13576
+ describe('${moduleName} - ${testType} tests', function() {
13577
+ `;
13578
+ for (const fn of analysis.functions) {
13579
+ code += this.generateFunctionTests(fn, testType);
13580
+ }
13581
+ for (const cls of analysis.classes) {
13582
+ code += this.generateClassTests(cls, testType);
13583
+ }
13584
+ code += `});
13585
+ `;
13586
+ return code;
13587
+ }
13588
+ /**
13589
+ * Generate tests for a standalone function
13590
+ */
13591
+ generateFunctionTests(fn, _testType) {
13592
+ const validParams = fn.parameters.map((p) => this.generateTestValue(p)).join(", ");
13593
+ const fnCall = fn.isAsync ? `await ${fn.name}(${validParams})` : `${fn.name}(${validParams})`;
13594
+ let code = ` describe('${fn.name}', function() {
13595
+ `;
13596
+ code += ` it('should handle valid input', ${fn.isAsync ? "async " : ""}function() {
13597
+ `;
13598
+ code += ` const result = ${fnCall};
13599
+ `;
13600
+ code += ` expect(result).to.not.be.undefined;
13601
+ `;
13602
+ code += ` });
13603
+ `;
13604
+ for (const param of fn.parameters) {
13605
+ if (!param.optional) {
13606
+ const paramsWithUndefined = fn.parameters.map((p) => p.name === param.name ? "undefined" : this.generateTestValue(p)).join(", ");
13607
+ code += `
13608
+ it('should handle undefined ${param.name}', function() {
13609
+ `;
13610
+ code += ` expect(function() { ${fn.name}(${paramsWithUndefined}); }).to.throw();
13611
+ `;
13612
+ code += ` });
13613
+ `;
13614
+ }
13615
+ }
13616
+ code += ` });
13617
+
13618
+ `;
13619
+ return code;
13620
+ }
13621
+ /**
13622
+ * Generate tests for a class
13623
+ */
13624
+ generateClassTests(cls, _testType) {
13625
+ const constructorArgs = cls.constructorParams?.map((p) => this.generateTestValue(p)).join(", ") || "";
13626
+ let code = ` describe('${cls.name}', function() {
13627
+ `;
13628
+ code += ` let instance;
13629
+
13630
+ `;
13631
+ code += ` beforeEach(function() {
13632
+ `;
13633
+ code += ` instance = new ${cls.name}(${constructorArgs});
13634
+ `;
13635
+ code += ` });
13636
+
13637
+ `;
13638
+ code += ` it('should instantiate correctly', function() {
13639
+ `;
13640
+ code += ` expect(instance).to.be.instanceOf(${cls.name});
13641
+ `;
13642
+ code += ` });
13643
+ `;
13644
+ for (const method of cls.methods) {
13645
+ if (!method.name.startsWith("_")) {
13646
+ const methodParams = method.parameters.map((p) => this.generateTestValue(p)).join(", ");
13647
+ code += `
13648
+ it('${method.name} should work', ${method.isAsync ? "async " : ""}function() {
13649
+ `;
13650
+ code += ` const result = ${method.isAsync ? "await " : ""}instance.${method.name}(${methodParams});
13651
+ `;
13652
+ code += ` expect(result).to.not.be.undefined;
13653
+ `;
13654
+ code += ` });
13655
+ `;
13656
+ }
13657
+ }
13658
+ code += ` });
13659
+
13660
+ `;
13661
+ return code;
13662
+ }
13663
+ /**
13664
+ * Generate stub tests when no AST analysis is available
13665
+ */
13666
+ generateStubTests(context) {
13667
+ const { moduleName, importPath, testType, patterns } = context;
13668
+ const patternComment = this.generatePatternComment(patterns);
13117
13669
  const isAsync = patterns.some(
13118
13670
  (p) => p.name.toLowerCase().includes("async") || p.name.toLowerCase().includes("promise")
13119
13671
  );
@@ -13146,12 +13698,12 @@ describe('${moduleName}', function() {
13146
13698
  ? new ${moduleName}()
13147
13699
  : ${moduleName};
13148
13700
  expect(instance).to.exist;
13149
- expect(() => JSON.stringify(instance)).to.not.throw();
13701
+ expect(function() { JSON.stringify(instance); }).to.not.throw();
13150
13702
  });
13151
13703
 
13152
13704
  it('should handle error conditions', function() {
13153
13705
  // Verify error resilience
13154
- expect(() => {
13706
+ expect(function() {
13155
13707
  const instance = typeof ${moduleName} === 'function'
13156
13708
  ? new ${moduleName}()
13157
13709
  : ${moduleName};
@@ -13162,9 +13714,147 @@ describe('${moduleName}', function() {
13162
13714
  });
13163
13715
  `;
13164
13716
  }
13165
- generatePytestTest(moduleName, importPath, testType, patterns) {
13166
- const patternComment = patterns.length > 0 ? `# Applied patterns: ${patterns.map((p) => p.name).join(", ")}
13167
- ` : "";
13717
+ /**
13718
+ * Generate coverage-focused tests for specific lines
13719
+ */
13720
+ generateCoverageTests(moduleName, importPath, lines) {
13721
+ const funcName = this.camelCase(moduleName);
13722
+ const lineRange = this.formatLineRange(lines);
13723
+ return `// Coverage test for ${lineRange} in ${moduleName}
13724
+ import { expect } from 'chai';
13725
+ import { ${funcName} } from '${importPath}';
13726
+
13727
+ describe('${moduleName} coverage', function() {
13728
+ describe('${lineRange}', function() {
13729
+ it('should execute code path covering ${lineRange}', function() {
13730
+ // Arrange: Set up test inputs to reach uncovered lines
13731
+ const testInput = undefined; // Replace with appropriate input
13732
+
13733
+ // Act: Execute the code path
13734
+ const result = ${funcName}(testInput);
13735
+
13736
+ // Assert: Verify the code was reached and behaves correctly
13737
+ expect(result).to.not.be.undefined;
13738
+ });
13739
+
13740
+ it('should handle edge case for ${lineRange}', function() {
13741
+ // Arrange: Set up edge case input
13742
+ const edgeCaseInput = null;
13743
+
13744
+ // Act & Assert: Verify edge case handling
13745
+ expect(function() { ${funcName}(edgeCaseInput); }).to.not.throw();
13746
+ });
13747
+ });
13748
+ });
13749
+ `;
13750
+ }
13751
+ };
13752
+
13753
+ // src/domains/test-generation/generators/pytest-generator.ts
13754
+ import { faker as faker2 } from "@faker-js/faker";
13755
+ var PytestGenerator = class extends BaseTestGenerator {
13756
+ framework = "pytest";
13757
+ /**
13758
+ * Generate complete test file from analysis
13759
+ */
13760
+ generateTests(context) {
13761
+ const { moduleName, importPath, testType, patterns, analysis } = context;
13762
+ if (!analysis || analysis.functions.length === 0 && analysis.classes.length === 0) {
13763
+ return this.generateStubTests(context);
13764
+ }
13765
+ const patternComment = this.generatePythonPatternComment(patterns);
13766
+ const exports = this.extractExports(analysis.functions, analysis.classes);
13767
+ const pythonImport = importPath.replace(/\//g, ".").replace(/\.(ts|js)$/, "");
13768
+ const importStatement = exports.length > 0 ? `from ${pythonImport} import ${exports.join(", ")}` : `import ${pythonImport} as ${moduleName}`;
13769
+ let code = `${patternComment}import pytest
13770
+ ${importStatement}
13771
+
13772
+
13773
+ class Test${this.pascalCase(moduleName)}:
13774
+ """${testType} tests for ${moduleName}"""
13775
+
13776
+ `;
13777
+ for (const fn of analysis.functions) {
13778
+ code += this.generateFunctionTests(fn, testType);
13779
+ }
13780
+ for (const cls of analysis.classes) {
13781
+ code += this.generateClassTests(cls, testType);
13782
+ }
13783
+ return code;
13784
+ }
13785
+ /**
13786
+ * Generate tests for a standalone function
13787
+ */
13788
+ generateFunctionTests(fn, _testType) {
13789
+ const validParams = fn.parameters.map((p) => this.generatePythonTestValue(p)).join(", ");
13790
+ let code = ` def test_${fn.name}_valid_input(self):
13791
+ `;
13792
+ code += ` """Test ${fn.name} with valid input"""
13793
+ `;
13794
+ code += ` result = ${fn.name}(${validParams})
13795
+ `;
13796
+ code += ` assert result is not None
13797
+
13798
+ `;
13799
+ for (const param of fn.parameters) {
13800
+ if (!param.optional && param.type?.includes("str")) {
13801
+ code += ` def test_${fn.name}_empty_${param.name}(self):
13802
+ `;
13803
+ code += ` """Test ${fn.name} with empty ${param.name}"""
13804
+ `;
13805
+ const paramsWithEmpty = fn.parameters.map((p) => p.name === param.name ? '""' : this.generatePythonTestValue(p)).join(", ");
13806
+ code += ` result = ${fn.name}(${paramsWithEmpty})
13807
+ `;
13808
+ code += ` assert result is not None
13809
+
13810
+ `;
13811
+ }
13812
+ }
13813
+ return code;
13814
+ }
13815
+ /**
13816
+ * Generate tests for a class
13817
+ */
13818
+ generateClassTests(cls, _testType) {
13819
+ const constructorArgs = cls.constructorParams?.map((p) => this.generatePythonTestValue(p)).join(", ") || "";
13820
+ let code = `
13821
+ class Test${cls.name}:
13822
+ `;
13823
+ code += ` """Tests for ${cls.name}"""
13824
+
13825
+ `;
13826
+ code += ` @pytest.fixture
13827
+ `;
13828
+ code += ` def instance(self):
13829
+ `;
13830
+ code += ` return ${cls.name}(${constructorArgs})
13831
+
13832
+ `;
13833
+ code += ` def test_instantiation(self, instance):
13834
+ `;
13835
+ code += ` assert isinstance(instance, ${cls.name})
13836
+
13837
+ `;
13838
+ for (const method of cls.methods) {
13839
+ if (!method.name.startsWith("_")) {
13840
+ const methodParams = method.parameters.map((p) => this.generatePythonTestValue(p)).join(", ");
13841
+ code += ` def test_${method.name}(self, instance):
13842
+ `;
13843
+ code += ` result = instance.${method.name}(${methodParams})
13844
+ `;
13845
+ code += ` assert result is not None
13846
+
13847
+ `;
13848
+ }
13849
+ }
13850
+ return code;
13851
+ }
13852
+ /**
13853
+ * Generate stub tests when no AST analysis is available
13854
+ */
13855
+ generateStubTests(context) {
13856
+ const { moduleName, importPath, testType, patterns } = context;
13857
+ const patternComment = this.generatePythonPatternComment(patterns);
13168
13858
  const isAsync = patterns.some(
13169
13859
  (p) => p.name.toLowerCase().includes("async") || p.name.toLowerCase().includes("promise")
13170
13860
  );
@@ -13174,7 +13864,7 @@ describe('${moduleName}', function() {
13174
13864
  from ${importPath} import ${moduleName}
13175
13865
 
13176
13866
 
13177
- class Test${moduleName}:
13867
+ class Test${this.pascalCase(moduleName)}:
13178
13868
  """${testType} tests for ${moduleName}"""
13179
13869
 
13180
13870
  def test_is_defined(self):
@@ -13213,7 +13903,169 @@ class Test${moduleName}:
13213
13903
  pass
13214
13904
  `;
13215
13905
  }
13216
- async generateRedPhaseTest(feature, behavior, _framework) {
13906
+ /**
13907
+ * Generate coverage-focused tests for specific lines
13908
+ */
13909
+ generateCoverageTests(moduleName, importPath, lines) {
13910
+ const funcName = this.camelCase(moduleName);
13911
+ const lineRange = this.formatLineRange(lines);
13912
+ const pythonImport = importPath.replace(/\//g, ".");
13913
+ return `# Coverage test for ${lineRange} in ${moduleName}
13914
+ import pytest
13915
+ from ${pythonImport} import ${funcName}
13916
+
13917
+ class Test${this.pascalCase(moduleName)}Coverage:
13918
+ """Tests to cover ${lineRange}"""
13919
+
13920
+ def test_cover_${lines[0]}_${lines[lines.length - 1]}(self):
13921
+ """Exercise code path covering ${lineRange}"""
13922
+ # Arrange: Set up test inputs to reach uncovered lines
13923
+ test_input = None # Replace with appropriate input
13924
+
13925
+ # Act: Execute the code path
13926
+ try:
13927
+ result = ${funcName}(test_input)
13928
+
13929
+ # Assert: Verify expected behavior
13930
+ assert result is not None
13931
+ except Exception as e:
13932
+ # If exception is expected for this path, verify it
13933
+ pytest.fail(f"Unexpected exception: {e}")
13934
+ `;
13935
+ }
13936
+ // ============================================================================
13937
+ // Python-Specific Helpers
13938
+ // ============================================================================
13939
+ /**
13940
+ * Generate Python pattern comment
13941
+ */
13942
+ generatePythonPatternComment(patterns) {
13943
+ if (patterns.length === 0) return "";
13944
+ return `# Applied patterns: ${patterns.map((p) => p.name).join(", ")}
13945
+ `;
13946
+ }
13947
+ /**
13948
+ * Generate a Python test value for a parameter
13949
+ */
13950
+ generatePythonTestValue(param) {
13951
+ const type = param.type?.toLowerCase() || "unknown";
13952
+ const name = param.name.toLowerCase();
13953
+ if (name.includes("id")) return `"${faker2.string.uuid()}"`;
13954
+ if (name.includes("name")) return `"${faker2.person.fullName()}"`;
13955
+ if (name.includes("email")) return `"${faker2.internet.email()}"`;
13956
+ if (name.includes("url")) return `"${faker2.internet.url()}"`;
13957
+ if (type.includes("str")) return `"${faker2.lorem.word()}"`;
13958
+ if (type.includes("int") || type.includes("number")) {
13959
+ return String(faker2.number.int({ min: 1, max: 100 }));
13960
+ }
13961
+ if (type.includes("bool")) return "True";
13962
+ if (type.includes("list") || type.includes("[]")) return "[]";
13963
+ if (type.includes("dict") || type.includes("{}")) return "{}";
13964
+ if (type.includes("float")) return String(faker2.number.float({ min: 0, max: 100 }));
13965
+ return "None";
13966
+ }
13967
+ };
13968
+
13969
+ // src/domains/test-generation/factories/test-generator-factory.ts
13970
+ var SUPPORTED_FRAMEWORKS = [
13971
+ "jest",
13972
+ "vitest",
13973
+ "mocha",
13974
+ "pytest"
13975
+ ];
13976
+ var DEFAULT_FRAMEWORK = "vitest";
13977
+ var TestGeneratorFactory = class {
13978
+ /**
13979
+ * Cache of created generators for reuse
13980
+ */
13981
+ cache = /* @__PURE__ */ new Map();
13982
+ /**
13983
+ * Create a test generator for the specified framework
13984
+ *
13985
+ * @param framework - Target test framework
13986
+ * @returns Test generator instance
13987
+ * @throws Error if framework is not supported
13988
+ */
13989
+ create(framework) {
13990
+ const cached = this.cache.get(framework);
13991
+ if (cached) {
13992
+ return cached;
13993
+ }
13994
+ const generator = this.createGenerator(framework);
13995
+ this.cache.set(framework, generator);
13996
+ return generator;
13997
+ }
13998
+ /**
13999
+ * Check if a framework is supported
14000
+ *
14001
+ * @param framework - Framework to check
14002
+ * @returns True if supported, with type narrowing
14003
+ */
14004
+ supports(framework) {
14005
+ return SUPPORTED_FRAMEWORKS.includes(framework);
14006
+ }
14007
+ /**
14008
+ * Get the default framework
14009
+ *
14010
+ * @returns Default test framework (vitest)
14011
+ */
14012
+ getDefault() {
14013
+ return DEFAULT_FRAMEWORK;
14014
+ }
14015
+ /**
14016
+ * Get all supported frameworks
14017
+ *
14018
+ * @returns Array of supported framework names
14019
+ */
14020
+ getSupportedFrameworks() {
14021
+ return [...SUPPORTED_FRAMEWORKS];
14022
+ }
14023
+ /**
14024
+ * Create a generator instance for the framework
14025
+ */
14026
+ createGenerator(framework) {
14027
+ switch (framework) {
14028
+ case "jest":
14029
+ return new JestVitestGenerator("jest");
14030
+ case "vitest":
14031
+ return new JestVitestGenerator("vitest");
14032
+ case "mocha":
14033
+ return new MochaGenerator();
14034
+ case "pytest":
14035
+ return new PytestGenerator();
14036
+ default:
14037
+ throw new Error(`Unsupported test framework: ${framework}`);
14038
+ }
14039
+ }
14040
+ /**
14041
+ * Clear the generator cache
14042
+ * Useful for testing or when memory needs to be freed
14043
+ */
14044
+ clearCache() {
14045
+ this.cache.clear();
14046
+ }
14047
+ };
14048
+ var testGeneratorFactory = new TestGeneratorFactory();
14049
+
14050
+ // src/domains/test-generation/services/tdd-generator.ts
14051
+ var TDDGeneratorService = class {
14052
+ /**
14053
+ * Generate TDD artifacts based on the requested phase
14054
+ */
14055
+ async generateTDDTests(request) {
14056
+ const { feature, behavior, framework, phase } = request;
14057
+ switch (phase) {
14058
+ case "red":
14059
+ return this.generateRedPhaseTest(feature, behavior, framework);
14060
+ case "green":
14061
+ return this.generateGreenPhaseCode(feature, behavior, framework);
14062
+ case "refactor":
14063
+ return this.generateRefactoringSuggestions(feature, behavior);
14064
+ default:
14065
+ throw new Error(`Unknown TDD phase: ${phase}`);
14066
+ }
14067
+ }
14068
+ generateRedPhaseTest(feature, behavior, _framework) {
13217
14069
  const funcName = this.camelCase(feature);
13218
14070
  const assertions = this.generateAssertionsFromBehavior(behavior, funcName);
13219
14071
  const testCode = `describe('${feature}', () => {
@@ -13228,10 +14080,6 @@ ${assertions}
13228
14080
  nextStep: "Write the minimal implementation to make this test pass"
13229
14081
  };
13230
14082
  }
13231
- /**
13232
- * Generate specific assertions from behavior description
13233
- * Uses NLP-style extraction to infer test values and assertions
13234
- */
13235
14083
  generateAssertionsFromBehavior(behavior, funcName) {
13236
14084
  const behaviorLower = behavior.toLowerCase();
13237
14085
  const assertions = [];
@@ -13272,7 +14120,7 @@ ${assertions}
13272
14120
  } else if (context.extractedNumber !== void 0) {
13273
14121
  assertions.push(` expect(result).toContain(${expectedValue});`);
13274
14122
  } else {
13275
- assertions.push(` expect(result).toContain(testInput); // Contains the input`);
14123
+ assertions.push(` expect(result).toContain(testInput);`);
13276
14124
  }
13277
14125
  } else if (behaviorLower.includes("length") || behaviorLower.includes("count")) {
13278
14126
  assertions.push(` const result = ${funcCall};`);
@@ -13329,9 +14177,6 @@ ${assertions}
13329
14177
  }
13330
14178
  return assertions.join("\n");
13331
14179
  }
13332
- /**
13333
- * Extract contextual information from behavior description
13334
- */
13335
14180
  extractBehaviorContext(behavior) {
13336
14181
  const context = {};
13337
14182
  const stringMatch = behavior.match(/["']([^"']+)["']/);
@@ -13363,9 +14208,6 @@ ${assertions}
13363
14208
  }
13364
14209
  return context;
13365
14210
  }
13366
- /**
13367
- * Build function call with appropriate arguments based on context
13368
- */
13369
14211
  buildFunctionCall(funcName, context, behaviorLower) {
13370
14212
  if (context.inputType) {
13371
14213
  return `${funcName}(testInput)`;
@@ -13398,7 +14240,7 @@ ${assertions}
13398
14240
  }
13399
14241
  return `${funcName}(input)`;
13400
14242
  }
13401
- async generateGreenPhaseCode(feature, behavior, _framework) {
14243
+ generateGreenPhaseCode(feature, behavior, _framework) {
13402
14244
  const behaviorLower = behavior.toLowerCase();
13403
14245
  const funcName = this.camelCase(feature);
13404
14246
  const { returnType, implementation, params } = this.inferImplementationFromBehavior(behaviorLower);
@@ -13415,10 +14257,6 @@ ${implementation}
13415
14257
  nextStep: "Refactor the code while keeping tests green"
13416
14258
  };
13417
14259
  }
13418
- /**
13419
- * Infer implementation details from behavior description using heuristics
13420
- * Analyzes the behavior text to determine return type, parameters, and minimal implementation
13421
- */
13422
14260
  inferImplementationFromBehavior(behavior) {
13423
14261
  let returnType = "unknown";
13424
14262
  let implementation = " return undefined;";
@@ -13481,7 +14319,7 @@ ${implementation}`;
13481
14319
  }
13482
14320
  return { returnType, implementation, params };
13483
14321
  }
13484
- async generateRefactoringSuggestions(_feature, _behavior) {
14322
+ generateRefactoringSuggestions(_feature, _behavior) {
13485
14323
  return {
13486
14324
  phase: "refactor",
13487
14325
  refactoringChanges: [
@@ -13494,6 +14332,28 @@ ${implementation}`;
13494
14332
  nextStep: "Apply refactoring changes and ensure all tests still pass"
13495
14333
  };
13496
14334
  }
14335
+ camelCase(str) {
14336
+ return str.replace(/[^a-zA-Z0-9]+(.)/g, (_, chr) => chr.toUpperCase()).replace(/^./, (chr) => chr.toLowerCase());
14337
+ }
14338
+ };
14339
+
14340
+ // src/domains/test-generation/services/property-test-generator.ts
14341
+ var PropertyTestGeneratorService = class {
14342
+ /**
14343
+ * Generate property-based tests
14344
+ */
14345
+ async generatePropertyTests(request) {
14346
+ const { function: funcName, properties, constraints = {} } = request;
14347
+ const tests = properties.map((property) => ({
14348
+ property,
14349
+ testCode: this.generatePropertyTestCode(funcName, property, constraints),
14350
+ generators: this.inferGenerators(property, constraints)
14351
+ }));
14352
+ return {
14353
+ tests,
14354
+ arbitraries: this.collectArbitraries(tests)
14355
+ };
14356
+ }
13497
14357
  generatePropertyTestCode(funcName, property, constraints) {
13498
14358
  const propertyLower = property.toLowerCase();
13499
14359
  const { generators, assertion, setupCode } = this.analyzePropertyForTestGeneration(
@@ -13515,9 +14375,6 @@ ${setupCode}
13515
14375
  });
13516
14376
  });`;
13517
14377
  }
13518
- /**
13519
- * Analyze property description to determine generators and assertions
13520
- */
13521
14378
  analyzePropertyForTestGeneration(propertyLower, funcName, constraints) {
13522
14379
  const generators = [];
13523
14380
  let assertion = "return result !== undefined;";
@@ -13611,9 +14468,6 @@ ${setupCode}
13611
14468
  }
13612
14469
  return { generators, assertion, setupCode };
13613
14470
  }
13614
- /**
13615
- * Infer the appropriate fast-check generator from constraints
13616
- */
13617
14471
  inferGeneratorFromConstraints(constraints, hint) {
13618
14472
  const type = constraints.type?.toLowerCase() || hint.toLowerCase();
13619
14473
  if (type.includes("string") || type.includes("text")) {
@@ -13632,34 +14486,19 @@ ${setupCode}
13632
14486
  }
13633
14487
  return "fc.integer()";
13634
14488
  }
13635
- if (type.includes("float") || type.includes("decimal")) {
13636
- return "fc.float()";
13637
- }
13638
- if (type.includes("boolean") || type.includes("bool")) {
13639
- return "fc.boolean()";
13640
- }
14489
+ if (type.includes("float") || type.includes("decimal")) return "fc.float()";
14490
+ if (type.includes("boolean") || type.includes("bool")) return "fc.boolean()";
13641
14491
  if (type.includes("array") || type.includes("list")) {
13642
14492
  const itemType = constraints.itemType || "anything";
13643
14493
  const itemGen = this.getSimpleGenerator(itemType);
13644
14494
  return `fc.array(${itemGen})`;
13645
14495
  }
13646
- if (type.includes("object") || type.includes("record")) {
13647
- return "fc.object()";
13648
- }
13649
- if (type.includes("date")) {
13650
- return "fc.date()";
13651
- }
13652
- if (type.includes("uuid") || type.includes("id")) {
13653
- return "fc.uuid()";
13654
- }
13655
- if (type.includes("email")) {
13656
- return "fc.emailAddress()";
13657
- }
14496
+ if (type.includes("object") || type.includes("record")) return "fc.object()";
14497
+ if (type.includes("date")) return "fc.date()";
14498
+ if (type.includes("uuid") || type.includes("id")) return "fc.uuid()";
14499
+ if (type.includes("email")) return "fc.emailAddress()";
13658
14500
  return "fc.anything()";
13659
14501
  }
13660
- /**
13661
- * Get a simple generator for a type name
13662
- */
13663
14502
  getSimpleGenerator(typeName) {
13664
14503
  const typeMap = {
13665
14504
  string: "fc.string()",
@@ -13673,22 +14512,12 @@ ${setupCode}
13673
14512
  };
13674
14513
  return typeMap[typeName.toLowerCase()] || "fc.anything()";
13675
14514
  }
13676
- /**
13677
- * Generate parameter names from generator list
13678
- */
13679
14515
  generatePropertyParams(generators) {
13680
- if (generators.length === 1) {
13681
- return "input";
13682
- }
14516
+ if (generators.length === 1) return "input";
13683
14517
  return generators.map((_, i) => String.fromCharCode(97 + i)).join(", ");
13684
14518
  }
13685
- /**
13686
- * Generate argument list for function call
13687
- */
13688
14519
  generatePropertyArgs(generators) {
13689
- if (generators.length === 1) {
13690
- return "input";
13691
- }
14520
+ if (generators.length === 1) return "input";
13692
14521
  return generators.map((_, i) => String.fromCharCode(97 + i)).join(", ");
13693
14522
  }
13694
14523
  inferGenerators(property, constraints) {
@@ -13771,8 +14600,33 @@ ${setupCode}
13771
14600
  }
13772
14601
  return Array.from(arbitraries);
13773
14602
  }
14603
+ };
14604
+
14605
+ // src/domains/test-generation/services/test-data-generator.ts
14606
+ import { faker as faker3 } from "@faker-js/faker";
14607
+ var TestDataGeneratorService = class {
14608
+ /**
14609
+ * Generate test data based on schema
14610
+ */
14611
+ async generateTestData(request) {
14612
+ const { schema, count, locale = "en", preserveRelationships = false } = request;
14613
+ const seed = Date.now();
14614
+ const records = [];
14615
+ for (let i = 0; i < count; i++) {
14616
+ const record = this.generateRecordFromSchema(schema, seed + i, locale);
14617
+ records.push(record);
14618
+ }
14619
+ if (preserveRelationships) {
14620
+ this.linkRelatedRecords(records, schema);
14621
+ }
14622
+ return {
14623
+ records,
14624
+ schema,
14625
+ seed
14626
+ };
14627
+ }
13774
14628
  generateRecordFromSchema(schema, seed, locale) {
13775
- faker.seed(seed);
14629
+ faker3.seed(seed);
13776
14630
  if (locale && locale !== "en") {
13777
14631
  }
13778
14632
  const record = {};
@@ -13805,146 +14659,146 @@ ${setupCode}
13805
14659
  return this.generateNumberValue(options);
13806
14660
  case "float":
13807
14661
  case "decimal":
13808
- return faker.number.float({ min: options?.min ?? 0, max: options?.max ?? 1e3, fractionDigits: 2 });
14662
+ return faker3.number.float({ min: options?.min ?? 0, max: options?.max ?? 1e3, fractionDigits: 2 });
13809
14663
  case "boolean":
13810
14664
  case "bool":
13811
- return faker.datatype.boolean();
14665
+ return faker3.datatype.boolean();
13812
14666
  case "date":
13813
14667
  case "datetime":
13814
- return faker.date.recent().toISOString();
14668
+ return faker3.date.recent().toISOString();
13815
14669
  case "email":
13816
- return faker.internet.email();
14670
+ return faker3.internet.email();
13817
14671
  case "uuid":
13818
14672
  case "id":
13819
- return faker.string.uuid();
14673
+ return faker3.string.uuid();
13820
14674
  case "url":
13821
- return faker.internet.url();
14675
+ return faker3.internet.url();
13822
14676
  case "phone":
13823
- return faker.phone.number();
14677
+ return faker3.phone.number();
13824
14678
  case "address":
13825
14679
  return this.generateAddress();
13826
14680
  case "name":
13827
14681
  case "fullname":
13828
- return faker.person.fullName();
14682
+ return faker3.person.fullName();
13829
14683
  case "firstname":
13830
- return faker.person.firstName();
14684
+ return faker3.person.firstName();
13831
14685
  case "lastname":
13832
- return faker.person.lastName();
14686
+ return faker3.person.lastName();
13833
14687
  case "username":
13834
- return faker.internet.username();
14688
+ return faker3.internet.username();
13835
14689
  case "password":
13836
- return faker.internet.password();
14690
+ return faker3.internet.password();
13837
14691
  case "company":
13838
- return faker.company.name();
14692
+ return faker3.company.name();
13839
14693
  case "jobtitle":
13840
- return faker.person.jobTitle();
14694
+ return faker3.person.jobTitle();
13841
14695
  case "text":
13842
14696
  case "paragraph":
13843
- return faker.lorem.paragraph();
14697
+ return faker3.lorem.paragraph();
13844
14698
  case "sentence":
13845
- return faker.lorem.sentence();
14699
+ return faker3.lorem.sentence();
13846
14700
  case "word":
13847
14701
  case "words":
13848
- return faker.lorem.word();
14702
+ return faker3.lorem.word();
13849
14703
  case "avatar":
13850
14704
  case "image":
13851
- return faker.image.avatar();
14705
+ return faker3.image.avatar();
13852
14706
  case "color":
13853
- return faker.color.rgb();
14707
+ return faker3.color.rgb();
13854
14708
  case "ipaddress":
13855
14709
  case "ip":
13856
- return faker.internet.ipv4();
14710
+ return faker3.internet.ipv4();
13857
14711
  case "mac":
13858
- return faker.internet.mac();
14712
+ return faker3.internet.mac();
13859
14713
  case "latitude":
13860
- return faker.location.latitude();
14714
+ return faker3.location.latitude();
13861
14715
  case "longitude":
13862
- return faker.location.longitude();
14716
+ return faker3.location.longitude();
13863
14717
  case "country":
13864
- return faker.location.country();
14718
+ return faker3.location.country();
13865
14719
  case "city":
13866
- return faker.location.city();
14720
+ return faker3.location.city();
13867
14721
  case "zipcode":
13868
14722
  case "postalcode":
13869
- return faker.location.zipCode();
14723
+ return faker3.location.zipCode();
13870
14724
  case "creditcard":
13871
- return faker.finance.creditCardNumber();
14725
+ return faker3.finance.creditCardNumber();
13872
14726
  case "currency":
13873
- return faker.finance.currencyCode();
14727
+ return faker3.finance.currencyCode();
13874
14728
  case "amount":
13875
14729
  case "price":
13876
- return faker.finance.amount();
14730
+ return faker3.finance.amount();
13877
14731
  case "json":
13878
14732
  case "object":
13879
- return { key: faker.lorem.word(), value: faker.lorem.sentence() };
14733
+ return { key: faker3.lorem.word(), value: faker3.lorem.sentence() };
13880
14734
  case "array":
13881
- return [faker.lorem.word(), faker.lorem.word(), faker.lorem.word()];
14735
+ return [faker3.lorem.word(), faker3.lorem.word(), faker3.lorem.word()];
13882
14736
  case "enum":
13883
14737
  if (options?.enum && options.enum.length > 0) {
13884
- return faker.helpers.arrayElement(options.enum);
14738
+ return faker3.helpers.arrayElement(options.enum);
13885
14739
  }
13886
- return faker.lorem.word();
14740
+ return faker3.lorem.word();
13887
14741
  default:
13888
14742
  return this.inferValueFromFieldName(fieldName);
13889
14743
  }
13890
14744
  }
13891
14745
  generateStringValue(fieldName, options) {
13892
14746
  const lowerName = fieldName.toLowerCase();
13893
- if (lowerName.includes("email")) return faker.internet.email();
13894
- if (lowerName.includes("name") && lowerName.includes("first")) return faker.person.firstName();
13895
- if (lowerName.includes("name") && lowerName.includes("last")) return faker.person.lastName();
13896
- if (lowerName.includes("name")) return faker.person.fullName();
13897
- if (lowerName.includes("phone")) return faker.phone.number();
13898
- if (lowerName.includes("address")) return faker.location.streetAddress();
13899
- if (lowerName.includes("city")) return faker.location.city();
13900
- if (lowerName.includes("country")) return faker.location.country();
13901
- if (lowerName.includes("zip") || lowerName.includes("postal")) return faker.location.zipCode();
13902
- if (lowerName.includes("url") || lowerName.includes("website")) return faker.internet.url();
13903
- if (lowerName.includes("username") || lowerName.includes("user")) return faker.internet.username();
13904
- if (lowerName.includes("password")) return faker.internet.password();
13905
- if (lowerName.includes("description") || lowerName.includes("bio")) return faker.lorem.paragraph();
13906
- if (lowerName.includes("title")) return faker.lorem.sentence();
13907
- if (lowerName.includes("company")) return faker.company.name();
13908
- if (lowerName.includes("job")) return faker.person.jobTitle();
13909
- if (lowerName.includes("avatar") || lowerName.includes("image")) return faker.image.avatar();
14747
+ if (lowerName.includes("email")) return faker3.internet.email();
14748
+ if (lowerName.includes("name") && lowerName.includes("first")) return faker3.person.firstName();
14749
+ if (lowerName.includes("name") && lowerName.includes("last")) return faker3.person.lastName();
14750
+ if (lowerName.includes("name")) return faker3.person.fullName();
14751
+ if (lowerName.includes("phone")) return faker3.phone.number();
14752
+ if (lowerName.includes("address")) return faker3.location.streetAddress();
14753
+ if (lowerName.includes("city")) return faker3.location.city();
14754
+ if (lowerName.includes("country")) return faker3.location.country();
14755
+ if (lowerName.includes("zip") || lowerName.includes("postal")) return faker3.location.zipCode();
14756
+ if (lowerName.includes("url") || lowerName.includes("website")) return faker3.internet.url();
14757
+ if (lowerName.includes("username") || lowerName.includes("user")) return faker3.internet.username();
14758
+ if (lowerName.includes("password")) return faker3.internet.password();
14759
+ if (lowerName.includes("description") || lowerName.includes("bio")) return faker3.lorem.paragraph();
14760
+ if (lowerName.includes("title")) return faker3.lorem.sentence();
14761
+ if (lowerName.includes("company")) return faker3.company.name();
14762
+ if (lowerName.includes("job")) return faker3.person.jobTitle();
14763
+ if (lowerName.includes("avatar") || lowerName.includes("image")) return faker3.image.avatar();
13910
14764
  if (options?.pattern) {
13911
- return faker.helpers.fromRegExp(options.pattern);
14765
+ return faker3.helpers.fromRegExp(options.pattern);
13912
14766
  }
13913
- return faker.lorem.words(3);
14767
+ return faker3.lorem.words(3);
13914
14768
  }
13915
14769
  generateNumberValue(options) {
13916
14770
  const min = options?.min ?? 0;
13917
14771
  const max = options?.max ?? 1e4;
13918
- return faker.number.int({ min, max });
14772
+ return faker3.number.int({ min, max });
13919
14773
  }
13920
14774
  generateAddress() {
13921
14775
  return {
13922
- street: faker.location.streetAddress(),
13923
- city: faker.location.city(),
13924
- state: faker.location.state(),
13925
- zipCode: faker.location.zipCode(),
13926
- country: faker.location.country()
14776
+ street: faker3.location.streetAddress(),
14777
+ city: faker3.location.city(),
14778
+ state: faker3.location.state(),
14779
+ zipCode: faker3.location.zipCode(),
14780
+ country: faker3.location.country()
13927
14781
  };
13928
14782
  }
13929
14783
  inferValueFromFieldName(fieldName) {
13930
14784
  const lowerName = fieldName.toLowerCase();
13931
- if (lowerName.includes("id")) return faker.string.uuid();
13932
- if (lowerName.includes("email")) return faker.internet.email();
13933
- if (lowerName.includes("name")) return faker.person.fullName();
13934
- if (lowerName.includes("phone")) return faker.phone.number();
13935
- if (lowerName.includes("date") || lowerName.includes("time")) return faker.date.recent().toISOString();
13936
- if (lowerName.includes("url")) return faker.internet.url();
13937
- if (lowerName.includes("count") || lowerName.includes("amount")) return faker.number.int({ min: 0, max: 100 });
13938
- if (lowerName.includes("price")) return faker.finance.amount();
14785
+ if (lowerName.includes("id")) return faker3.string.uuid();
14786
+ if (lowerName.includes("email")) return faker3.internet.email();
14787
+ if (lowerName.includes("name")) return faker3.person.fullName();
14788
+ if (lowerName.includes("phone")) return faker3.phone.number();
14789
+ if (lowerName.includes("date") || lowerName.includes("time")) return faker3.date.recent().toISOString();
14790
+ if (lowerName.includes("url")) return faker3.internet.url();
14791
+ if (lowerName.includes("count") || lowerName.includes("amount")) return faker3.number.int({ min: 0, max: 100 });
14792
+ if (lowerName.includes("price")) return faker3.finance.amount();
13939
14793
  if (lowerName.includes("active") || lowerName.includes("enabled") || lowerName.includes("is")) {
13940
- return faker.datatype.boolean();
14794
+ return faker3.datatype.boolean();
13941
14795
  }
13942
- return faker.lorem.word();
14796
+ return faker3.lorem.word();
13943
14797
  }
13944
14798
  callFakerMethod(methodPath) {
13945
14799
  try {
13946
14800
  const parts = methodPath.split(".");
13947
- let result = faker;
14801
+ let result = faker3;
13948
14802
  for (const part of parts) {
13949
14803
  if (result && typeof result === "object" && part in result) {
13950
14804
  const next = result[part];
@@ -13954,12 +14808,12 @@ ${setupCode}
13954
14808
  result = next;
13955
14809
  }
13956
14810
  } else {
13957
- return faker.lorem.word();
14811
+ return faker3.lorem.word();
13958
14812
  }
13959
14813
  }
13960
14814
  return result;
13961
14815
  } catch {
13962
- return faker.lorem.word();
14816
+ return faker3.lorem.word();
13963
14817
  }
13964
14818
  }
13965
14819
  linkRelatedRecords(records, schema) {
@@ -13978,21 +14832,177 @@ ${setupCode}
13978
14832
  for (const { field, reference } of referenceFields) {
13979
14833
  if (i > 0 && reference === "id") {
13980
14834
  const prevRecord = records[Math.floor(Math.random() * i)];
13981
- record[field] = prevRecord["id"] ?? faker.string.uuid();
14835
+ record[field] = prevRecord["id"] ?? faker3.string.uuid();
13982
14836
  } else {
13983
- record[field] = faker.string.uuid();
14837
+ record[field] = faker3.string.uuid();
13984
14838
  }
13985
14839
  }
13986
14840
  }
13987
14841
  }
13988
14842
  }
14843
+ };
14844
+
14845
+ // src/domains/test-generation/services/test-generator.ts
14846
+ var DEFAULT_CONFIG = {
14847
+ defaultFramework: "vitest",
14848
+ maxTestsPerFile: 50,
14849
+ coverageTargetDefault: 80,
14850
+ enableAIGeneration: true
14851
+ };
14852
+ var TestGeneratorService = class {
14853
+ config;
14854
+ memory;
14855
+ generatorFactory;
14856
+ tddGenerator;
14857
+ propertyTestGenerator;
14858
+ testDataGenerator;
14859
+ constructor(dependencies, config = {}) {
14860
+ this.config = { ...DEFAULT_CONFIG, ...config };
14861
+ this.memory = dependencies.memory;
14862
+ this.generatorFactory = dependencies.generatorFactory || new TestGeneratorFactory();
14863
+ this.tddGenerator = dependencies.tddGenerator || new TDDGeneratorService();
14864
+ this.propertyTestGenerator = dependencies.propertyTestGenerator || new PropertyTestGeneratorService();
14865
+ this.testDataGenerator = dependencies.testDataGenerator || new TestDataGeneratorService();
14866
+ }
14867
+ /**
14868
+ * Generate tests for given source files
14869
+ */
14870
+ async generateTests(request) {
14871
+ try {
14872
+ const {
14873
+ sourceFiles,
14874
+ testType,
14875
+ framework,
14876
+ coverageTarget = this.config.coverageTargetDefault,
14877
+ patterns = []
14878
+ } = request;
14879
+ if (sourceFiles.length === 0) {
14880
+ return err(new Error("No source files provided"));
14881
+ }
14882
+ const tests = [];
14883
+ const patternsUsed = [];
14884
+ for (const sourceFile of sourceFiles) {
14885
+ const fileTests = await this.generateTestsForFile(
14886
+ sourceFile,
14887
+ testType,
14888
+ framework,
14889
+ patterns
14890
+ );
14891
+ if (fileTests.success) {
14892
+ tests.push(...fileTests.value.tests);
14893
+ patternsUsed.push(...fileTests.value.patternsUsed);
14894
+ }
14895
+ }
14896
+ const coverageEstimate = this.estimateCoverage(tests, coverageTarget);
14897
+ await this.storeGenerationMetadata(tests, patternsUsed);
14898
+ return ok({
14899
+ tests,
14900
+ coverageEstimate,
14901
+ patternsUsed: Array.from(new Set(patternsUsed))
14902
+ });
14903
+ } catch (error) {
14904
+ return err(error instanceof Error ? error : new Error(String(error)));
14905
+ }
14906
+ }
14907
+ /**
14908
+ * Generate tests specifically targeting coverage gaps
14909
+ */
14910
+ async generateForCoverageGap(file, uncoveredLines, framework) {
14911
+ try {
14912
+ if (uncoveredLines.length === 0) {
14913
+ return ok([]);
14914
+ }
14915
+ const tests = [];
14916
+ const lineGroups = this.groupConsecutiveLines(uncoveredLines);
14917
+ const frameworkType = this.generatorFactory.supports(framework) ? framework : this.config.defaultFramework;
14918
+ for (const group of lineGroups) {
14919
+ const test = await this.generateTestForLines(file, group, frameworkType);
14920
+ if (test) {
14921
+ tests.push(test);
14922
+ }
14923
+ }
14924
+ return ok(tests);
14925
+ } catch (error) {
14926
+ return err(error instanceof Error ? error : new Error(String(error)));
14927
+ }
14928
+ }
14929
+ /**
14930
+ * Generate tests following TDD workflow - delegates to TDDGeneratorService
14931
+ */
14932
+ async generateTDDTests(request) {
14933
+ try {
14934
+ const result = await this.tddGenerator.generateTDDTests(request);
14935
+ return ok(result);
14936
+ } catch (error) {
14937
+ return err(error instanceof Error ? error : new Error(String(error)));
14938
+ }
14939
+ }
14940
+ /**
14941
+ * Generate property-based tests - delegates to PropertyTestGeneratorService
14942
+ */
14943
+ async generatePropertyTests(request) {
14944
+ try {
14945
+ const result = await this.propertyTestGenerator.generatePropertyTests(request);
14946
+ return ok(result);
14947
+ } catch (error) {
14948
+ return err(error instanceof Error ? error : new Error(String(error)));
14949
+ }
14950
+ }
14951
+ /**
14952
+ * Generate test data based on schema - delegates to TestDataGeneratorService
14953
+ */
14954
+ async generateTestData(request) {
14955
+ try {
14956
+ const result = await this.testDataGenerator.generateTestData(request);
14957
+ return ok(result);
14958
+ } catch (error) {
14959
+ return err(error instanceof Error ? error : new Error(String(error)));
14960
+ }
14961
+ }
14962
+ // ============================================================================
14963
+ // Private Helper Methods - Core Test Generation
14964
+ // ============================================================================
14965
+ async generateTestsForFile(sourceFile, testType, framework, patterns) {
14966
+ const testFile = this.getTestFilePath(sourceFile, framework);
14967
+ const patternsUsed = [];
14968
+ const applicablePatterns = await this.findApplicablePatterns(sourceFile, patterns);
14969
+ patternsUsed.push(...applicablePatterns.map((p) => p.name));
14970
+ let codeAnalysis = null;
14971
+ try {
14972
+ const content = fs2.readFileSync(sourceFile, "utf-8");
14973
+ codeAnalysis = this.analyzeSourceCode(content, sourceFile);
14974
+ } catch {
14975
+ }
14976
+ const generator = this.generatorFactory.create(framework);
14977
+ const moduleName = this.extractModuleName(sourceFile);
14978
+ const importPath = this.getImportPath(sourceFile);
14979
+ const context = {
14980
+ moduleName,
14981
+ importPath,
14982
+ testType,
14983
+ patterns: applicablePatterns,
14984
+ analysis: codeAnalysis ?? void 0
14985
+ };
14986
+ const testCode = generator.generateTests(context);
14987
+ const test = {
14988
+ id: uuidv44(),
14989
+ name: `${moduleName} tests`,
14990
+ sourceFile,
14991
+ testFile,
14992
+ testCode,
14993
+ type: testType,
14994
+ assertions: this.countAssertions(testCode)
14995
+ };
14996
+ return ok({ tests: [test], patternsUsed });
14997
+ }
13989
14998
  async generateTestForLines(file, lines, framework) {
13990
14999
  if (lines.length === 0) return null;
13991
15000
  const testId = uuidv44();
13992
15001
  const testFile = this.getTestFilePath(file, framework);
13993
15002
  const moduleName = this.extractModuleName(file);
13994
15003
  const importPath = this.getImportPath(file);
13995
- const testCode = this.generateCoverageTestCode(moduleName, importPath, lines, framework);
15004
+ const generator = this.generatorFactory.create(framework);
15005
+ const testCode = generator.generateCoverageTests(moduleName, importPath, lines);
13996
15006
  return {
13997
15007
  id: testId,
13998
15008
  name: `Coverage test for lines ${lines[0]}-${lines[lines.length - 1]}`,
@@ -14003,62 +15013,187 @@ ${setupCode}
14003
15013
  assertions: this.countAssertions(testCode)
14004
15014
  };
14005
15015
  }
14006
- /**
14007
- * Generate actual coverage test code for specific lines
14008
- */
14009
- generateCoverageTestCode(moduleName, importPath, lines, framework) {
14010
- const funcName = this.camelCase(moduleName);
14011
- const lineRange = lines.length === 1 ? `line ${lines[0]}` : `lines ${lines[0]}-${lines[lines.length - 1]}`;
14012
- if (framework === "pytest") {
14013
- return `# Coverage test for ${lineRange} in ${moduleName}
14014
- import pytest
14015
- from ${importPath.replace(/\//g, ".")} import ${funcName}
14016
-
14017
- class Test${this.pascalCase(moduleName)}Coverage:
14018
- """Tests to cover ${lineRange}"""
14019
-
14020
- def test_cover_${lines[0]}_${lines[lines.length - 1]}(self):
14021
- """Exercise code path covering ${lineRange}"""
14022
- # Arrange: Set up test inputs to reach uncovered lines
14023
- test_input = None # Replace with appropriate input
14024
-
14025
- # Act: Execute the code path
14026
- try:
14027
- result = ${funcName}(test_input)
14028
-
14029
- # Assert: Verify expected behavior
14030
- assert result is not None
14031
- except Exception as e:
14032
- # If exception is expected for this path, verify it
14033
- pytest.fail(f"Unexpected exception: {e}")
14034
- `;
15016
+ // ============================================================================
15017
+ // Private Helper Methods - AST Analysis
15018
+ // ============================================================================
15019
+ analyzeSourceCode(content, fileName) {
15020
+ const sourceFile = ts.createSourceFile(
15021
+ path2.basename(fileName),
15022
+ content,
15023
+ ts.ScriptTarget.Latest,
15024
+ true,
15025
+ ts.ScriptKind.TS
15026
+ );
15027
+ const functions = [];
15028
+ const classes = [];
15029
+ const visit = (node) => {
15030
+ if (ts.isFunctionDeclaration(node) && node.name) {
15031
+ functions.push(this.extractFunctionInfo(node, sourceFile));
15032
+ } else if (ts.isVariableStatement(node)) {
15033
+ for (const declaration of node.declarationList.declarations) {
15034
+ if (ts.isVariableDeclaration(declaration) && declaration.initializer && (ts.isArrowFunction(declaration.initializer) || ts.isFunctionExpression(declaration.initializer))) {
15035
+ const name = declaration.name.getText(sourceFile);
15036
+ functions.push(
15037
+ this.extractArrowFunctionInfo(name, declaration.initializer, sourceFile, node)
15038
+ );
15039
+ }
15040
+ }
15041
+ } else if (ts.isClassDeclaration(node) && node.name) {
15042
+ classes.push(this.extractClassInfo(node, sourceFile));
15043
+ }
15044
+ ts.forEachChild(node, visit);
15045
+ };
15046
+ ts.forEachChild(sourceFile, visit);
15047
+ return { functions, classes };
15048
+ }
15049
+ extractFunctionInfo(node, sourceFile) {
15050
+ const name = node.name?.getText(sourceFile) || "anonymous";
15051
+ const parameters = this.extractParameters(node.parameters, sourceFile);
15052
+ const returnType = node.type?.getText(sourceFile);
15053
+ const isAsync = node.modifiers?.some((m) => m.kind === ts.SyntaxKind.AsyncKeyword) ?? false;
15054
+ const isExported = node.modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword) ?? false;
15055
+ const { line: startLine } = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile));
15056
+ const { line: endLine } = sourceFile.getLineAndCharacterOfPosition(node.getEnd());
15057
+ return {
15058
+ name,
15059
+ parameters,
15060
+ returnType,
15061
+ isAsync,
15062
+ isExported,
15063
+ complexity: this.calculateComplexity(node),
15064
+ startLine: startLine + 1,
15065
+ endLine: endLine + 1,
15066
+ body: node.body?.getText(sourceFile)
15067
+ };
15068
+ }
15069
+ extractArrowFunctionInfo(name, node, sourceFile, parentNode) {
15070
+ const parameters = this.extractParameters(node.parameters, sourceFile);
15071
+ const returnType = node.type?.getText(sourceFile);
15072
+ const isAsync = node.modifiers?.some((m) => m.kind === ts.SyntaxKind.AsyncKeyword) ?? false;
15073
+ const isExported = ts.isVariableStatement(parentNode) && (parentNode.modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword) ?? false);
15074
+ const { line: startLine } = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile));
15075
+ const { line: endLine } = sourceFile.getLineAndCharacterOfPosition(node.getEnd());
15076
+ return {
15077
+ name,
15078
+ parameters,
15079
+ returnType,
15080
+ isAsync,
15081
+ isExported,
15082
+ complexity: this.calculateComplexity(node),
15083
+ startLine: startLine + 1,
15084
+ endLine: endLine + 1,
15085
+ body: node.body?.getText(sourceFile)
15086
+ };
15087
+ }
15088
+ extractClassInfo(node, sourceFile) {
15089
+ const name = node.name?.getText(sourceFile) || "AnonymousClass";
15090
+ const methods = [];
15091
+ const properties = [];
15092
+ let hasConstructor = false;
15093
+ let constructorParams;
15094
+ const isExported = node.modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword) ?? false;
15095
+ for (const member of node.members) {
15096
+ if (ts.isMethodDeclaration(member)) {
15097
+ const methodName = member.name.getText(sourceFile);
15098
+ const parameters = this.extractParameters(member.parameters, sourceFile);
15099
+ const returnType = member.type?.getText(sourceFile);
15100
+ const isAsync = member.modifiers?.some((m) => m.kind === ts.SyntaxKind.AsyncKeyword) ?? false;
15101
+ const { line: startLine } = sourceFile.getLineAndCharacterOfPosition(
15102
+ member.getStart(sourceFile)
15103
+ );
15104
+ const { line: endLine } = sourceFile.getLineAndCharacterOfPosition(member.getEnd());
15105
+ methods.push({
15106
+ name: methodName,
15107
+ parameters,
15108
+ returnType,
15109
+ isAsync,
15110
+ isExported: false,
15111
+ complexity: this.calculateComplexity(member),
15112
+ startLine: startLine + 1,
15113
+ endLine: endLine + 1,
15114
+ body: member.body?.getText(sourceFile)
15115
+ });
15116
+ } else if (ts.isConstructorDeclaration(member)) {
15117
+ hasConstructor = true;
15118
+ constructorParams = this.extractParameters(member.parameters, sourceFile);
15119
+ } else if (ts.isPropertyDeclaration(member)) {
15120
+ const propName = member.name.getText(sourceFile);
15121
+ const propType = member.type?.getText(sourceFile);
15122
+ const isPrivate = member.modifiers?.some((m) => m.kind === ts.SyntaxKind.PrivateKeyword) ?? false;
15123
+ const isReadonly = member.modifiers?.some((m) => m.kind === ts.SyntaxKind.ReadonlyKeyword) ?? false;
15124
+ properties.push({
15125
+ name: propName,
15126
+ type: propType,
15127
+ isPrivate,
15128
+ isReadonly
15129
+ });
15130
+ }
14035
15131
  }
14036
- return `// Coverage test for ${lineRange} in ${moduleName}
14037
- import { ${funcName} } from '${importPath}';
14038
-
14039
- describe('${moduleName} coverage', () => {
14040
- describe('${lineRange}', () => {
14041
- it('should execute code path covering ${lineRange}', () => {
14042
- // Arrange: Set up test inputs to reach uncovered lines
14043
- const testInput = undefined; // Replace with appropriate input
14044
-
14045
- // Act: Execute the code path
14046
- const result = ${funcName}(testInput);
14047
-
14048
- // Assert: Verify the code was reached and behaves correctly
14049
- expect(result).toBeDefined();
14050
- });
14051
-
14052
- it('should handle edge case for ${lineRange}', () => {
14053
- // Arrange: Set up edge case input
14054
- const edgeCaseInput = null;
14055
-
14056
- // Act & Assert: Verify edge case handling
14057
- expect(() => ${funcName}(edgeCaseInput)).not.toThrow();
14058
- });
14059
- });
14060
- });
14061
- `;
15132
+ return {
15133
+ name,
15134
+ methods,
15135
+ properties,
15136
+ isExported,
15137
+ hasConstructor,
15138
+ constructorParams
15139
+ };
15140
+ }
15141
+ extractParameters(params, sourceFile) {
15142
+ return params.map((param) => ({
15143
+ name: param.name.getText(sourceFile),
15144
+ type: param.type?.getText(sourceFile),
15145
+ optional: param.questionToken !== void 0,
15146
+ defaultValue: param.initializer?.getText(sourceFile)
15147
+ }));
15148
+ }
15149
+ calculateComplexity(node) {
15150
+ let complexity = 1;
15151
+ const visit = (n) => {
15152
+ switch (n.kind) {
15153
+ case ts.SyntaxKind.IfStatement:
15154
+ case ts.SyntaxKind.ForStatement:
15155
+ case ts.SyntaxKind.ForInStatement:
15156
+ case ts.SyntaxKind.ForOfStatement:
15157
+ case ts.SyntaxKind.WhileStatement:
15158
+ case ts.SyntaxKind.DoStatement:
15159
+ case ts.SyntaxKind.CaseClause:
15160
+ case ts.SyntaxKind.CatchClause:
15161
+ case ts.SyntaxKind.ConditionalExpression:
15162
+ complexity++;
15163
+ break;
15164
+ case ts.SyntaxKind.BinaryExpression: {
15165
+ const binary = n;
15166
+ if (binary.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken || binary.operatorToken.kind === ts.SyntaxKind.BarBarToken) {
15167
+ complexity++;
15168
+ }
15169
+ break;
15170
+ }
15171
+ }
15172
+ ts.forEachChild(n, visit);
15173
+ };
15174
+ ts.forEachChild(node, visit);
15175
+ return complexity;
15176
+ }
15177
+ // ============================================================================
15178
+ // Private Helper Methods - Utility Functions
15179
+ // ============================================================================
15180
+ async findApplicablePatterns(sourceFile, requestedPatterns) {
15181
+ const patterns = [];
15182
+ for (const patternName of requestedPatterns) {
15183
+ const stored = await this.memory.get(`pattern:${patternName}`);
15184
+ if (stored) {
15185
+ patterns.push(stored);
15186
+ }
15187
+ }
15188
+ const extension = sourceFile.split(".").pop() || "";
15189
+ const searchResults = await this.memory.search(`pattern:*:${extension}`, 5);
15190
+ for (const key of searchResults) {
15191
+ const pattern = await this.memory.get(key);
15192
+ if (pattern && !patterns.some((p) => p.id === pattern.id)) {
15193
+ patterns.push(pattern);
15194
+ }
15195
+ }
15196
+ return patterns;
14062
15197
  }
14063
15198
  groupConsecutiveLines(lines) {
14064
15199
  if (lines.length === 0) return [];
@@ -14119,12 +15254,6 @@ describe('${moduleName} coverage', () => {
14119
15254
  const estimatedCoverage = Math.min(target, Math.max(0, diminishedEstimate));
14120
15255
  return Math.round(estimatedCoverage * 10) / 10;
14121
15256
  }
14122
- camelCase(str) {
14123
- return str.replace(/[^a-zA-Z0-9]+(.)/g, (_, chr) => chr.toUpperCase()).replace(/^./, (chr) => chr.toLowerCase());
14124
- }
14125
- pascalCase(str) {
14126
- return str.replace(/[^a-zA-Z0-9]+(.)/g, (_, chr) => chr.toUpperCase()).replace(/^./, (chr) => chr.toUpperCase());
14127
- }
14128
15257
  async storeGenerationMetadata(tests, patterns) {
14129
15258
  const metadata = {
14130
15259
  generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -14136,10 +15265,12 @@ describe('${moduleName} coverage', () => {
14136
15265
  `test-generation:metadata:${Date.now()}`,
14137
15266
  metadata,
14138
15267
  { namespace: "test-generation", ttl: 86400 * 7 }
14139
- // 7 days
14140
15268
  );
14141
15269
  }
14142
15270
  };
15271
+ function createTestGeneratorService(memory, config = {}) {
15272
+ return new TestGeneratorService({ memory }, config);
15273
+ }
14143
15274
 
14144
15275
  // src/domains/test-generation/services/pattern-matcher.ts
14145
15276
  import { v4 as uuidv45 } from "uuid";
@@ -14310,7 +15441,7 @@ var OllamaClient = class {
14310
15441
  };
14311
15442
 
14312
15443
  // src/shared/embeddings/embedding-cache.ts
14313
- import { createHash } from "crypto";
15444
+ import { createHash as createHash2 } from "crypto";
14314
15445
  var EmbeddingCache = class {
14315
15446
  cache;
14316
15447
  maxSize;
@@ -14326,7 +15457,7 @@ var EmbeddingCache = class {
14326
15457
  * Generate SHA-256 hash of content for cache key
14327
15458
  */
14328
15459
  hashContent(content, model) {
14329
- return createHash("sha256").update(`${model}:${content}`).digest("hex");
15460
+ return createHash2("sha256").update(`${model}:${content}`).digest("hex");
14330
15461
  }
14331
15462
  /**
14332
15463
  * Get cached embedding if available
@@ -17889,7 +19020,7 @@ var DecisionTransformerAlgorithm = class extends BaseRLAlgorithm {
17889
19020
  }
17890
19021
  };
17891
19022
 
17892
- // src/domains/test-generation/coherence-gate.ts
19023
+ // src/domains/test-generation/services/coherence-gate-service.ts
17893
19024
  var DEFAULT_COHERENCE_GATE_CONFIG = {
17894
19025
  enabled: true,
17895
19026
  coherenceThreshold: 0.1,
@@ -18297,7 +19428,7 @@ var TestGenerationCoordinator = class {
18297
19428
  this.agentCoordinator = agentCoordinator;
18298
19429
  this.coherenceService = coherenceService;
18299
19430
  this.config = { ...DEFAULT_CONFIG3, ...config };
18300
- this.testGenerator = new TestGeneratorService(memory);
19431
+ this.testGenerator = createTestGeneratorService(memory);
18301
19432
  this.patternMatcher = new PatternMatcherService(memory);
18302
19433
  if (this.config.enableCoherenceGate && coherenceService) {
18303
19434
  this.coherenceGate = createTestGenerationCoherenceGate(
@@ -19159,7 +20290,7 @@ var TestGenerationPlugin = class extends BaseDomainPlugin {
19159
20290
  // Lifecycle Methods
19160
20291
  // ============================================================================
19161
20292
  async onInitialize() {
19162
- this.testGenerator = new TestGeneratorService(
20293
+ this.testGenerator = createTestGeneratorService(
19163
20294
  this.memory,
19164
20295
  this.pluginConfig.testGenerator
19165
20296
  );
@@ -19175,7 +20306,7 @@ var TestGenerationPlugin = class extends BaseDomainPlugin {
19175
20306
  );
19176
20307
  await this.coordinator.initialize();
19177
20308
  this.updateHealth({
19178
- status: "healthy",
20309
+ status: "idle",
19179
20310
  agents: { total: 0, active: 0, idle: 0, failed: 0 },
19180
20311
  lastActivity: /* @__PURE__ */ new Date(),
19181
20312
  errors: []
@@ -21332,7 +22463,46 @@ var RetryHandlerService = class {
21332
22463
  }
21333
22464
  };
21334
22465
 
21335
- // src/domains/test-execution/test-prioritization-types.ts
22466
+ // src/domains/test-execution/types/e2e-step.types.ts
22467
+ var E2EStepType = {
22468
+ /** Navigate to a URL */
22469
+ NAVIGATE: "navigate",
22470
+ /** Click an element */
22471
+ CLICK: "click",
22472
+ /** Type text into an element */
22473
+ TYPE: "type",
22474
+ /** Wait for a condition */
22475
+ WAIT: "wait",
22476
+ /** Make an assertion */
22477
+ ASSERT: "assert",
22478
+ /** Take a screenshot */
22479
+ SCREENSHOT: "screenshot",
22480
+ /** Perform accessibility check */
22481
+ A11Y_CHECK: "a11y-check"
22482
+ };
22483
+ function isNavigateStep(step) {
22484
+ return step.type === E2EStepType.NAVIGATE;
22485
+ }
22486
+ function isClickStep(step) {
22487
+ return step.type === E2EStepType.CLICK;
22488
+ }
22489
+ function isTypeStep(step) {
22490
+ return step.type === E2EStepType.TYPE;
22491
+ }
22492
+ function isWaitStep(step) {
22493
+ return step.type === E2EStepType.WAIT;
22494
+ }
22495
+ function isAssertStep(step) {
22496
+ return step.type === E2EStepType.ASSERT;
22497
+ }
22498
+ function isScreenshotStep(step) {
22499
+ return step.type === E2EStepType.SCREENSHOT;
22500
+ }
22501
+ function isA11yCheckStep(step) {
22502
+ return step.type === E2EStepType.A11Y_CHECK;
22503
+ }
22504
+
22505
+ // src/domains/test-execution/interfaces.ts
21336
22506
  function mapToFeatures(test) {
21337
22507
  const failureProbability = Math.min(1, test.failureRate ?? 0);
21338
22508
  const flakiness = Math.min(1, test.flakinessScore ?? 0);
@@ -23975,45 +25145,6 @@ async function getBrowserClientForUseCase(useCase) {
23975
25145
  return createBrowserClient({ useCase });
23976
25146
  }
23977
25147
 
23978
- // src/domains/test-execution/types/e2e-step.types.ts
23979
- var E2EStepType = {
23980
- /** Navigate to a URL */
23981
- NAVIGATE: "navigate",
23982
- /** Click an element */
23983
- CLICK: "click",
23984
- /** Type text into an element */
23985
- TYPE: "type",
23986
- /** Wait for a condition */
23987
- WAIT: "wait",
23988
- /** Make an assertion */
23989
- ASSERT: "assert",
23990
- /** Take a screenshot */
23991
- SCREENSHOT: "screenshot",
23992
- /** Perform accessibility check */
23993
- A11Y_CHECK: "a11y-check"
23994
- };
23995
- function isNavigateStep(step) {
23996
- return step.type === E2EStepType.NAVIGATE;
23997
- }
23998
- function isClickStep(step) {
23999
- return step.type === E2EStepType.CLICK;
24000
- }
24001
- function isTypeStep(step) {
24002
- return step.type === E2EStepType.TYPE;
24003
- }
24004
- function isWaitStep(step) {
24005
- return step.type === E2EStepType.WAIT;
24006
- }
24007
- function isAssertStep(step) {
24008
- return step.type === E2EStepType.ASSERT;
24009
- }
24010
- function isScreenshotStep(step) {
24011
- return step.type === E2EStepType.SCREENSHOT;
24012
- }
24013
- function isA11yCheckStep(step) {
24014
- return step.type === E2EStepType.A11Y_CHECK;
24015
- }
24016
-
24017
25148
  // src/domains/test-execution/services/e2e-runner.ts
24018
25149
  var DEFAULT_E2E_RUNNER_CONFIG = {
24019
25150
  defaultStepTimeout: 3e4,
@@ -26197,7 +27328,7 @@ var TestExecutionPlugin = class extends BaseDomainPlugin {
26197
27328
  );
26198
27329
  await this.coordinator.initialize();
26199
27330
  this.updateHealth({
26200
- status: "healthy",
27331
+ status: "idle",
26201
27332
  lastActivity: /* @__PURE__ */ new Date()
26202
27333
  });
26203
27334
  }
@@ -28743,7 +29874,7 @@ var CoverageAnalysisPlugin = class _CoverageAnalysisPlugin extends BaseDomainPlu
28743
29874
  async onInitialize() {
28744
29875
  await this.coordinator.initialize();
28745
29876
  this.updateHealth({
28746
- status: "healthy",
29877
+ status: "idle",
28747
29878
  lastActivity: /* @__PURE__ */ new Date()
28748
29879
  });
28749
29880
  }
@@ -29590,251 +30721,6 @@ var typescriptParser = new TypeScriptParser();
29590
30721
  // src/shared/io/file-reader.ts
29591
30722
  import * as fs5 from "node:fs/promises";
29592
30723
  import * as path5 from "node:path";
29593
-
29594
- // src/mcp/security/cve-prevention.ts
29595
- var PATH_TRAVERSAL_PATTERNS = [
29596
- /\.\./,
29597
- // Basic traversal
29598
- /%2e%2e/i,
29599
- // URL encoded ..
29600
- /%252e%252e/i,
29601
- // Double URL encoded
29602
- /\.\.%2f/i,
29603
- // Mixed encoding
29604
- /%2f\.\./i,
29605
- // Forward slash + ..
29606
- /\.\.%5c/i,
29607
- // Backslash + ..
29608
- /\.\.\\/,
29609
- // Windows backslash traversal
29610
- /%c0%ae/i,
29611
- // UTF-8 overlong encoding
29612
- /%c0%2f/i,
29613
- // UTF-8 overlong /
29614
- /%c1%9c/i,
29615
- // UTF-8 overlong \
29616
- /\0/,
29617
- // Null byte injection
29618
- /%00/i
29619
- // URL encoded null
29620
- ];
29621
- var DANGEROUS_PATH_COMPONENTS = [
29622
- /^\/etc\//i,
29623
- /^\/proc\//i,
29624
- /^\/sys\//i,
29625
- /^\/dev\//i,
29626
- /^\/root\//i,
29627
- /^\/home\/.+\/\./i,
29628
- /^[A-Z]:\\Windows/i,
29629
- /^[A-Z]:\\System/i,
29630
- /^[A-Z]:\\Users\\.+\\AppData/i
29631
- ];
29632
- function validatePath(path16, options = {}) {
29633
- const {
29634
- basePath = "",
29635
- allowAbsolute = false,
29636
- allowedExtensions = [],
29637
- deniedExtensions = [".exe", ".bat", ".cmd", ".sh", ".ps1", ".dll", ".so"],
29638
- maxDepth = 10,
29639
- maxLength = 4096
29640
- } = options;
29641
- if (path16.length > maxLength) {
29642
- return {
29643
- valid: false,
29644
- error: `Path exceeds maximum length of ${maxLength}`,
29645
- riskLevel: "medium"
29646
- };
29647
- }
29648
- for (const pattern of PATH_TRAVERSAL_PATTERNS) {
29649
- if (pattern.test(path16)) {
29650
- return {
29651
- valid: false,
29652
- error: "Path traversal attempt detected",
29653
- riskLevel: "critical"
29654
- };
29655
- }
29656
- }
29657
- if (!allowAbsolute && (path16.startsWith("/") || /^[A-Z]:/i.test(path16))) {
29658
- return {
29659
- valid: false,
29660
- error: "Absolute paths are not allowed",
29661
- riskLevel: "high"
29662
- };
29663
- }
29664
- for (const pattern of DANGEROUS_PATH_COMPONENTS) {
29665
- if (pattern.test(path16)) {
29666
- return {
29667
- valid: false,
29668
- error: "Access to system paths is not allowed",
29669
- riskLevel: "critical"
29670
- };
29671
- }
29672
- }
29673
- const normalizedPath = normalizePath(path16);
29674
- if (normalizedPath.includes("..")) {
29675
- return {
29676
- valid: false,
29677
- error: "Path traversal detected after normalization",
29678
- riskLevel: "critical"
29679
- };
29680
- }
29681
- const depth = normalizedPath.split("/").filter(Boolean).length;
29682
- if (depth > maxDepth) {
29683
- return {
29684
- valid: false,
29685
- error: `Path depth exceeds maximum of ${maxDepth}`,
29686
- riskLevel: "low"
29687
- };
29688
- }
29689
- const ext = getExtension(normalizedPath);
29690
- if (ext) {
29691
- const extWithDot = `.${ext.toLowerCase()}`;
29692
- const extWithoutDot = ext.toLowerCase();
29693
- if (deniedExtensions.length > 0) {
29694
- const isDenied = deniedExtensions.some(
29695
- (denied) => denied.toLowerCase() === extWithDot || denied.toLowerCase() === extWithoutDot
29696
- );
29697
- if (isDenied) {
29698
- return {
29699
- valid: false,
29700
- error: `File extension '${ext}' is not allowed`,
29701
- riskLevel: "high"
29702
- };
29703
- }
29704
- }
29705
- if (allowedExtensions.length > 0) {
29706
- const isAllowed = allowedExtensions.some(
29707
- (allowed) => allowed.toLowerCase() === extWithDot || allowed.toLowerCase() === extWithoutDot
29708
- );
29709
- if (!isAllowed) {
29710
- return {
29711
- valid: false,
29712
- error: `File extension '${ext}' is not in allowed list`,
29713
- riskLevel: "medium"
29714
- };
29715
- }
29716
- }
29717
- }
29718
- const finalPath = basePath ? joinPathsAbsolute(basePath, normalizedPath) : normalizedPath;
29719
- const normalizedBase = basePath.startsWith("/") ? `/${normalizePath(basePath)}` : normalizePath(basePath);
29720
- if (basePath && !finalPath.startsWith(normalizedBase)) {
29721
- return {
29722
- valid: false,
29723
- error: "Path escapes base directory",
29724
- riskLevel: "critical"
29725
- };
29726
- }
29727
- return {
29728
- valid: true,
29729
- normalizedPath: finalPath,
29730
- riskLevel: "none"
29731
- };
29732
- }
29733
- function normalizePath(path16) {
29734
- let normalized = path16.replace(/\\/g, "/");
29735
- normalized = normalized.replace(/\/+/g, "/");
29736
- const parts = normalized.split("/");
29737
- const result = [];
29738
- for (const part of parts) {
29739
- if (part === "." || part === "") {
29740
- continue;
29741
- }
29742
- if (part === "..") {
29743
- if (result.length > 0 && result[result.length - 1] !== "..") {
29744
- result.pop();
29745
- }
29746
- } else {
29747
- result.push(part);
29748
- }
29749
- }
29750
- return result.join("/");
29751
- }
29752
- function joinPathsAbsolute(...paths) {
29753
- if (paths.length === 0) return "";
29754
- const isAbsolute4 = paths[0].startsWith("/");
29755
- const result = paths.map((p) => {
29756
- while (p.startsWith("/")) p = p.slice(1);
29757
- while (p.endsWith("/")) p = p.slice(0, -1);
29758
- return p;
29759
- }).filter(Boolean).join("/");
29760
- return isAbsolute4 ? `/${result}` : result;
29761
- }
29762
- function getExtension(path16) {
29763
- const match = path16.match(/\.([^./\\]+)$/);
29764
- return match ? match[1] : null;
29765
- }
29766
- var SHELL_METACHARACTERS = /[|;&$`<>{}[\]!#*?~]/g;
29767
- var DEFAULT_ALLOWED_COMMANDS = [
29768
- "ls",
29769
- "cat",
29770
- "echo",
29771
- "grep",
29772
- "find",
29773
- "head",
29774
- "tail",
29775
- "wc",
29776
- "npm",
29777
- "node",
29778
- "yarn",
29779
- "pnpm",
29780
- "git",
29781
- "jest",
29782
- "vitest",
29783
- "playwright"
29784
- ];
29785
- var BLOCKED_COMMAND_PATTERNS = [
29786
- /;/,
29787
- // Command chaining with semicolon
29788
- /&&/,
29789
- // Command chaining with AND
29790
- /\|\|/,
29791
- // Command chaining with OR
29792
- /\|/,
29793
- // Piping
29794
- /`.*`/,
29795
- // Backtick command substitution
29796
- /\$\(.*\)/,
29797
- // $() command substitution
29798
- />\s*\/dev\/sd/i,
29799
- // Writing to block devices
29800
- />\s*\/etc\//i
29801
- // Writing to /etc
29802
- ];
29803
- function validateCommand(command, allowedCommands = DEFAULT_ALLOWED_COMMANDS) {
29804
- const blockedPatterns = [];
29805
- for (const pattern of BLOCKED_COMMAND_PATTERNS) {
29806
- if (pattern.test(command)) {
29807
- blockedPatterns.push(pattern.source);
29808
- }
29809
- }
29810
- if (blockedPatterns.length > 0) {
29811
- return {
29812
- valid: false,
29813
- error: "Command contains blocked patterns",
29814
- blockedPatterns
29815
- };
29816
- }
29817
- const parts = command.trim().split(/\s+/);
29818
- const baseCommand = parts[0].split("/").pop() || "";
29819
- if (!allowedCommands.includes(baseCommand)) {
29820
- return {
29821
- valid: false,
29822
- error: `Command '${baseCommand}' is not in the allowed list`,
29823
- blockedPatterns: []
29824
- };
29825
- }
29826
- const sanitizedParts = parts.map((part, i) => {
29827
- if (i === 0) return part;
29828
- return part.replace(SHELL_METACHARACTERS, "");
29829
- });
29830
- return {
29831
- valid: true,
29832
- sanitizedCommand: sanitizedParts.join(" "),
29833
- blockedPatterns: []
29834
- };
29835
- }
29836
-
29837
- // src/shared/io/file-reader.ts
29838
30724
  var FileReadError = class extends Error {
29839
30725
  constructor(message, filePath, code, cause) {
29840
30726
  super(message);
@@ -34313,7 +35199,7 @@ var QualityAssessmentPlugin = class extends BaseDomainPlugin {
34313
35199
  );
34314
35200
  await this.coordinator.initialize();
34315
35201
  this.updateHealth({
34316
- status: "healthy",
35202
+ status: "idle",
34317
35203
  agents: { total: 0, active: 0, idle: 0, failed: 0 },
34318
35204
  lastActivity: /* @__PURE__ */ new Date(),
34319
35205
  errors: []
@@ -37213,7 +38099,7 @@ var DefectIntelligencePlugin = class extends BaseDomainPlugin {
37213
38099
  );
37214
38100
  await this.coordinator.initialize();
37215
38101
  this.updateHealth({
37216
- status: "healthy",
38102
+ status: "idle",
37217
38103
  agents: { total: 0, active: 0, idle: 0, failed: 0 },
37218
38104
  lastActivity: /* @__PURE__ */ new Date(),
37219
38105
  errors: []
@@ -39927,7 +40813,7 @@ var RequirementsValidationPlugin = class extends BaseDomainPlugin {
39927
40813
  );
39928
40814
  await this.coordinator.initialize();
39929
40815
  this.updateHealth({
39930
- status: "healthy",
40816
+ status: "idle",
39931
40817
  agents: { total: 0, active: 0, idle: 0, failed: 0 },
39932
40818
  lastActivity: /* @__PURE__ */ new Date(),
39933
40819
  errors: []
@@ -45803,7 +46689,7 @@ var CodeIntelligencePlugin = class extends BaseDomainPlugin {
45803
46689
  );
45804
46690
  await this.coordinator.initialize();
45805
46691
  this.updateHealth({
45806
- status: "healthy",
46692
+ status: "idle",
45807
46693
  agents: { total: 0, active: 0, idle: 0, failed: 0 },
45808
46694
  lastActivity: /* @__PURE__ */ new Date(),
45809
46695
  errors: []
@@ -47182,7 +48068,7 @@ var DEFAULT_CONFIG25 = {
47182
48068
  dastMaxDepth: 5,
47183
48069
  dastActiveScanning: false
47184
48070
  };
47185
- var SQL_INJECTION_PATTERNS = [
48071
+ var SQL_INJECTION_PATTERNS2 = [
47186
48072
  {
47187
48073
  id: "sqli-string-concat",
47188
48074
  pattern: /query\s*\(\s*['"`].*\+.*['"`]\s*\)/g,
@@ -47590,7 +48476,7 @@ var AUTH_PATTERNS = [
47590
48476
  }
47591
48477
  ];
47592
48478
  var ALL_SECURITY_PATTERNS = [
47593
- ...SQL_INJECTION_PATTERNS,
48479
+ ...SQL_INJECTION_PATTERNS2,
47594
48480
  ...XSS_PATTERNS,
47595
48481
  ...SECRET_PATTERNS,
47596
48482
  ...PATH_TRAVERSAL_PATTERNS2,
@@ -53300,7 +54186,7 @@ var SecurityCompliancePlugin = class extends BaseDomainPlugin {
53300
54186
  );
53301
54187
  await this.coordinator.initialize();
53302
54188
  this.updateHealth({
53303
- status: "healthy",
54189
+ status: "idle",
53304
54190
  agents: { total: 0, active: 0, idle: 0, failed: 0 },
53305
54191
  lastActivity: /* @__PURE__ */ new Date(),
53306
54192
  errors: []
@@ -57429,7 +58315,7 @@ var ContractTestingPlugin = class extends BaseDomainPlugin {
57429
58315
  );
57430
58316
  await this.coordinator.initialize();
57431
58317
  this.updateHealth({
57432
- status: "healthy",
58318
+ status: "idle",
57433
58319
  agents: { total: 0, active: 0, idle: 0, failed: 0 },
57434
58320
  lastActivity: /* @__PURE__ */ new Date(),
57435
58321
  errors: []
@@ -62503,7 +63389,7 @@ var VisualAccessibilityPlugin = class extends BaseDomainPlugin {
62503
63389
  );
62504
63390
  await this.coordinator.initialize();
62505
63391
  this.updateHealth({
62506
- status: "healthy",
63392
+ status: "idle",
62507
63393
  agents: { total: 0, active: 0, idle: 0, failed: 0 },
62508
63394
  lastActivity: /* @__PURE__ */ new Date(),
62509
63395
  errors: []
@@ -66313,7 +67199,7 @@ var ChaosResiliencePlugin = class extends BaseDomainPlugin {
66313
67199
  );
66314
67200
  await this.coordinator.initialize();
66315
67201
  this.updateHealth({
66316
- status: "healthy",
67202
+ status: "idle",
66317
67203
  agents: { total: 0, active: 0, idle: 0, failed: 0 },
66318
67204
  lastActivity: /* @__PURE__ */ new Date(),
66319
67205
  errors: []
@@ -70530,7 +71416,7 @@ var LearningOptimizationPlugin = class extends BaseDomainPlugin {
70530
71416
  );
70531
71417
  await this.coordinator.initialize();
70532
71418
  this.updateHealth({
70533
- status: "healthy",
71419
+ status: "idle",
70534
71420
  agents: { total: 0, active: 0, idle: 0, failed: 0 },
70535
71421
  lastActivity: /* @__PURE__ */ new Date(),
70536
71422
  errors: []
@@ -73527,9 +74413,13 @@ var MinCutHealthMonitor = class {
73527
74413
  /**
73528
74414
  * Issue #205 fix: Check if topology is empty/fresh (no agents spawned yet)
73529
74415
  * An empty topology is normal for a fresh install - not a critical issue
74416
+ *
74417
+ * Note: Domain coordinator vertices and workflow edges are always created,
74418
+ * so we check for actual agent vertices instead of raw counts.
73530
74419
  */
73531
74420
  isEmptyTopology() {
73532
- return this.graph.vertexCount === 0 || this.graph.edgeCount === 0;
74421
+ const agentVertices = this.graph.getVerticesByType("agent");
74422
+ return agentVertices.length === 0;
73533
74423
  }
73534
74424
  /**
73535
74425
  * Perform health check
@@ -74655,9 +75545,13 @@ var QueenMinCutBridge = class {
74655
75545
  }
74656
75546
  /**
74657
75547
  * Issue #205 fix: Check if topology is empty/fresh (no agents spawned yet)
75548
+ *
75549
+ * Note: Domain coordinator vertices and workflow edges are always created,
75550
+ * so we check for actual agent vertices instead of raw counts.
74658
75551
  */
74659
75552
  isEmptyTopology() {
74660
- return this.graph.vertexCount === 0 || this.graph.edgeCount === 0;
75553
+ const agentVertices = this.graph.getVerticesByType("agent");
75554
+ return agentVertices.length === 0;
74661
75555
  }
74662
75556
  /**
74663
75557
  * Convert MinCut alerts to Queen health issues
@@ -76979,7 +77873,7 @@ import * as path11 from "path";
76979
77873
  // src/coordination/result-saver.ts
76980
77874
  import * as fs9 from "fs/promises";
76981
77875
  import * as path10 from "path";
76982
- import { createHash as createHash2 } from "crypto";
77876
+ import { createHash as createHash3 } from "crypto";
76983
77877
  var TEST_FILE_PATTERNS = {
76984
77878
  typescript: {
76985
77879
  jest: ".test.ts",
@@ -77406,7 +78300,7 @@ ${data.recommendations.length === 0 ? "No recommendations - all quality gates pa
77406
78300
  async createFileEntry(filePath, format) {
77407
78301
  const content = await fs9.readFile(filePath);
77408
78302
  const stats = await fs9.stat(filePath);
77409
- const checksum = createHash2("sha256").update(content).digest("hex").slice(0, 16);
78303
+ const checksum = createHash3("sha256").update(content).digest("hex").slice(0, 16);
77410
78304
  return {
77411
78305
  path: filePath,
77412
78306
  format,
@@ -77501,7 +78395,7 @@ function getSecurityScanner(memory) {
77501
78395
  }
77502
78396
  function getTestGenerator(memory) {
77503
78397
  if (!testGenerator) {
77504
- testGenerator = new TestGeneratorService(memory);
78398
+ testGenerator = createTestGeneratorService(memory);
77505
78399
  }
77506
78400
  return testGenerator;
77507
78401
  }
@@ -83911,11 +84805,12 @@ var TestGenerateTool = class extends MCPToolBase {
83911
84805
  testGeneratorService = null;
83912
84806
  /**
83913
84807
  * Initialize or get the test generator service with persistent storage
84808
+ * Uses factory function for proper dependency injection
83914
84809
  */
83915
84810
  async getService() {
83916
84811
  if (!this.testGeneratorService) {
83917
84812
  const memory = await getSharedMemoryBackend();
83918
- this.testGeneratorService = new TestGeneratorService(
84813
+ this.testGeneratorService = createTestGeneratorService(
83919
84814
  memory,
83920
84815
  {
83921
84816
  defaultFramework: "vitest",
@@ -94449,19 +95344,16 @@ function createSpectralEngineWrapper(rawEngine) {
94449
95344
  return indexToString.get(idx) ?? `unknown-${idx}`;
94450
95345
  };
94451
95346
  const buildGraph = () => ({
94452
- nodes: Array.from(nodes).map((id) => ({
94453
- id: getOrCreateIndex(id),
94454
- // Numeric index
94455
- label: id
94456
- // Original string ID as label
94457
- })),
94458
- edges: edges.map((e) => ({
94459
- source: getOrCreateIndex(e.source),
94460
- // Convert to numeric
94461
- target: getOrCreateIndex(e.target),
94462
- // Convert to numeric
94463
- weight: e.weight
94464
- }))
95347
+ n: nodes.size,
95348
+ // Number of nodes
95349
+ edges: edges.map((e) => [
95350
+ getOrCreateIndex(e.source),
95351
+ // source as numeric index
95352
+ getOrCreateIndex(e.target),
95353
+ // target as numeric index
95354
+ e.weight
95355
+ // weight
95356
+ ])
94465
95357
  });
94466
95358
  return {
94467
95359
  add_node(id) {
@@ -94482,19 +95374,54 @@ function createSpectralEngineWrapper(rawEngine) {
94482
95374
  }
94483
95375
  },
94484
95376
  compute_fiedler_value() {
94485
- const graph = buildGraph();
94486
- return rawEngine.algebraicConnectivity(graph);
95377
+ if (nodes.size < 2) {
95378
+ return 0;
95379
+ }
95380
+ if (edges.length === 0) {
95381
+ return 0;
95382
+ }
95383
+ try {
95384
+ const graph = buildGraph();
95385
+ const fiedler = rawEngine.algebraicConnectivity(graph);
95386
+ return Number.isFinite(fiedler) && fiedler >= 0 ? fiedler : 0;
95387
+ } catch (error) {
95388
+ console.warn("[SpectralAdapter] algebraicConnectivity failed:", error);
95389
+ return 0;
95390
+ }
94487
95391
  },
94488
95392
  predict_collapse_risk() {
94489
- const graph = buildGraph();
94490
- const fiedler = rawEngine.algebraicConnectivity(graph);
94491
- return Math.max(0, Math.min(1, 1 - fiedler));
95393
+ if (nodes.size < 2) {
95394
+ return 0;
95395
+ }
95396
+ if (edges.length === 0) {
95397
+ return 1;
95398
+ }
95399
+ try {
95400
+ const graph = buildGraph();
95401
+ const fiedler = rawEngine.algebraicConnectivity(graph);
95402
+ const validFiedler = Number.isFinite(fiedler) && fiedler >= 0 ? fiedler : 0;
95403
+ return Math.max(0, Math.min(1, 1 - validFiedler));
95404
+ } catch (error) {
95405
+ console.warn("[SpectralAdapter] predict_collapse_risk failed:", error);
95406
+ return 0.8;
95407
+ }
94492
95408
  },
94493
95409
  get_weak_vertices(count) {
94494
- const graph = buildGraph();
94495
- const minCut = rawEngine.predictMinCut(graph);
94496
- if (!minCut?.vertices) return Array.from(nodes).slice(0, count);
94497
- return minCut.vertices.slice(0, count).map((idx) => getStringId(idx));
95410
+ if (nodes.size === 0) {
95411
+ return [];
95412
+ }
95413
+ if (edges.length === 0) {
95414
+ return Array.from(nodes).slice(0, count);
95415
+ }
95416
+ try {
95417
+ const graph = buildGraph();
95418
+ const minCut = rawEngine.predictMinCut(graph);
95419
+ if (!minCut?.vertices) return Array.from(nodes).slice(0, count);
95420
+ return minCut.vertices.slice(0, count).map((idx) => getStringId(idx));
95421
+ } catch (error) {
95422
+ console.warn("[SpectralAdapter] predictMinCut failed:", error);
95423
+ return Array.from(nodes).slice(0, count);
95424
+ }
94498
95425
  },
94499
95426
  clear() {
94500
95427
  nodes.clear();
@@ -94620,9 +95547,21 @@ var SpectralAdapter = class {
94620
95547
  if (this.nodes.size < 2) {
94621
95548
  return 0;
94622
95549
  }
94623
- const fiedlerValue = this.engine.compute_fiedler_value();
94624
- this.logger.debug("Computed Fiedler value", { fiedlerValue });
94625
- return fiedlerValue;
95550
+ if (this.edges.length === 0) {
95551
+ return 0;
95552
+ }
95553
+ try {
95554
+ const fiedlerValue = this.engine.compute_fiedler_value();
95555
+ this.logger.debug("Computed Fiedler value", { fiedlerValue });
95556
+ return fiedlerValue;
95557
+ } catch (error) {
95558
+ this.logger.warn("Failed to compute Fiedler value", {
95559
+ error: error instanceof Error ? error.message : String(error),
95560
+ nodeCount: this.nodes.size,
95561
+ edgeCount: this.edges.length
95562
+ });
95563
+ return 0;
95564
+ }
94626
95565
  }
94627
95566
  /**
94628
95567
  * Predict the risk of swarm collapse
@@ -94636,9 +95575,21 @@ var SpectralAdapter = class {
94636
95575
  if (this.nodes.size < 2) {
94637
95576
  return 0;
94638
95577
  }
94639
- const risk = this.engine.predict_collapse_risk();
94640
- this.logger.debug("Predicted collapse risk", { risk });
94641
- return risk;
95578
+ if (this.edges.length === 0) {
95579
+ return 1;
95580
+ }
95581
+ try {
95582
+ const risk = this.engine.predict_collapse_risk();
95583
+ this.logger.debug("Predicted collapse risk", { risk });
95584
+ return risk;
95585
+ } catch (error) {
95586
+ this.logger.warn("Failed to predict collapse risk", {
95587
+ error: error instanceof Error ? error.message : String(error),
95588
+ nodeCount: this.nodes.size,
95589
+ edgeCount: this.edges.length
95590
+ });
95591
+ return 0.8;
95592
+ }
94642
95593
  }
94643
95594
  /**
94644
95595
  * Get the nodes most at risk of causing collapse
@@ -94654,13 +95605,25 @@ var SpectralAdapter = class {
94654
95605
  if (this.nodes.size === 0) {
94655
95606
  return [];
94656
95607
  }
95608
+ if (this.edges.length === 0) {
95609
+ return Array.from(this.nodes).slice(0, count);
95610
+ }
94657
95611
  const safeCount = Math.min(count, this.nodes.size);
94658
- const weakVertices = this.engine.get_weak_vertices(safeCount);
94659
- this.logger.debug("Retrieved weak vertices", {
94660
- requested: count,
94661
- returned: weakVertices.length
94662
- });
94663
- return weakVertices;
95612
+ try {
95613
+ const weakVertices = this.engine.get_weak_vertices(safeCount);
95614
+ this.logger.debug("Retrieved weak vertices", {
95615
+ requested: count,
95616
+ returned: weakVertices.length
95617
+ });
95618
+ return weakVertices;
95619
+ } catch (error) {
95620
+ this.logger.warn("Failed to get weak vertices", {
95621
+ error: error instanceof Error ? error.message : String(error),
95622
+ nodeCount: this.nodes.size,
95623
+ edgeCount: this.edges.length
95624
+ });
95625
+ return Array.from(this.nodes).slice(0, count);
95626
+ }
94664
95627
  }
94665
95628
  /**
94666
95629
  * Analyze a swarm state for collapse risk
@@ -94719,8 +95682,10 @@ var SpectralAdapter = class {
94719
95682
  const successSim = 1 - Math.abs(agent1.successRate - agent2.successRate);
94720
95683
  const typeBonus = agent1.agentType === agent2.agentType ? 0.2 : 0;
94721
95684
  let beliefSim = 0;
94722
- if (agent1.beliefs.length > 0 && agent2.beliefs.length > 0) {
94723
- beliefSim = this.computeBeliefOverlap(agent1.beliefs, agent2.beliefs);
95685
+ const beliefs1 = agent1.beliefs ?? [];
95686
+ const beliefs2 = agent2.beliefs ?? [];
95687
+ if (beliefs1.length > 0 && beliefs2.length > 0) {
95688
+ beliefSim = this.computeBeliefOverlap(beliefs1, beliefs2);
94724
95689
  }
94725
95690
  return healthSim * 0.3 + successSim * 0.3 + typeBonus + beliefSim * 0.2;
94726
95691
  }
@@ -96224,8 +97189,27 @@ var CoherenceService = class {
96224
97189
  */
96225
97190
  async predictCollapse(state2) {
96226
97191
  this.ensureInitialized();
97192
+ if (!state2.agents || state2.agents.length === 0) {
97193
+ return {
97194
+ risk: 0,
97195
+ fiedlerValue: 0,
97196
+ collapseImminent: false,
97197
+ weakVertices: [],
97198
+ recommendations: ["No agents to analyze"],
97199
+ durationMs: 0,
97200
+ usedFallback: true
97201
+ };
97202
+ }
96227
97203
  if (this.spectralAdapter?.isInitialized()) {
96228
- return this.spectralAdapter.analyzeSwarmState(state2);
97204
+ try {
97205
+ return this.spectralAdapter.analyzeSwarmState(state2);
97206
+ } catch (error) {
97207
+ this.logger.warn("Spectral collapse prediction failed, using fallback", {
97208
+ error: error instanceof Error ? error.message : String(error),
97209
+ agentCount: state2.agents.length
97210
+ });
97211
+ return this.predictCollapseWithFallback(state2);
97212
+ }
96229
97213
  }
96230
97214
  return this.predictCollapseWithFallback(state2);
96231
97215
  }
@@ -96392,34 +97376,60 @@ var CoherenceService = class {
96392
97376
  async verifyConsensus(votes) {
96393
97377
  this.ensureInitialized();
96394
97378
  const startTime = Date.now();
97379
+ if (votes.length < 2) {
97380
+ return {
97381
+ isValid: votes.length === 1,
97382
+ confidence: votes.length === 1 ? votes[0].confidence : 0,
97383
+ isFalseConsensus: false,
97384
+ fiedlerValue: votes.length === 1 ? 1 : 0,
97385
+ collapseRisk: 0,
97386
+ recommendation: votes.length === 0 ? "No votes to analyze" : "Single vote - consensus trivially achieved",
97387
+ durationMs: Date.now() - startTime,
97388
+ usedFallback: true
97389
+ };
97390
+ }
96395
97391
  if (this.spectralAdapter?.isInitialized()) {
96396
- this.spectralAdapter.clear();
96397
- for (const vote of votes) {
96398
- this.spectralAdapter.addNode(vote.agentId);
96399
- }
96400
- for (let i = 0; i < votes.length; i++) {
96401
- for (let j = i + 1; j < votes.length; j++) {
96402
- if (votes[i].verdict === votes[j].verdict) {
96403
- this.spectralAdapter.addEdge(
96404
- votes[i].agentId,
96405
- votes[j].agentId,
96406
- Math.min(votes[i].confidence, votes[j].confidence)
96407
- );
97392
+ try {
97393
+ this.spectralAdapter.clear();
97394
+ for (const vote of votes) {
97395
+ this.spectralAdapter.addNode(vote.agentId);
97396
+ }
97397
+ let edgeCount = 0;
97398
+ for (let i = 0; i < votes.length; i++) {
97399
+ for (let j = i + 1; j < votes.length; j++) {
97400
+ if (votes[i].verdict === votes[j].verdict) {
97401
+ this.spectralAdapter.addEdge(
97402
+ votes[i].agentId,
97403
+ votes[j].agentId,
97404
+ Math.min(votes[i].confidence, votes[j].confidence)
97405
+ );
97406
+ edgeCount++;
97407
+ }
96408
97408
  }
96409
97409
  }
97410
+ if (edgeCount === 0) {
97411
+ this.logger.debug("No agreement edges, using fallback consensus");
97412
+ return this.verifyConsensusWithFallback(votes, startTime);
97413
+ }
97414
+ const collapseRisk = this.spectralAdapter.predictCollapseRisk();
97415
+ const fiedlerValue = this.spectralAdapter.computeFiedlerValue();
97416
+ return {
97417
+ isValid: collapseRisk < 0.3 && fiedlerValue > 0.1,
97418
+ confidence: 1 - collapseRisk,
97419
+ isFalseConsensus: fiedlerValue < 0.05,
97420
+ fiedlerValue,
97421
+ collapseRisk,
97422
+ recommendation: collapseRisk > 0.3 ? "Spawn independent reviewer" : "Consensus verified",
97423
+ durationMs: Date.now() - startTime,
97424
+ usedFallback: false
97425
+ };
97426
+ } catch (error) {
97427
+ this.logger.warn("Spectral consensus verification failed, using fallback", {
97428
+ error: error instanceof Error ? error.message : String(error),
97429
+ voteCount: votes.length
97430
+ });
97431
+ return this.verifyConsensusWithFallback(votes, startTime);
96410
97432
  }
96411
- const collapseRisk = this.spectralAdapter.predictCollapseRisk();
96412
- const fiedlerValue = this.spectralAdapter.computeFiedlerValue();
96413
- return {
96414
- isValid: collapseRisk < 0.3 && fiedlerValue > 0.1,
96415
- confidence: 1 - collapseRisk,
96416
- isFalseConsensus: fiedlerValue < 0.05,
96417
- fiedlerValue,
96418
- collapseRisk,
96419
- recommendation: collapseRisk > 0.3 ? "Spawn independent reviewer" : "Consensus verified",
96420
- durationMs: Date.now() - startTime,
96421
- usedFallback: false
96422
- };
96423
97433
  }
96424
97434
  return this.verifyConsensusWithFallback(votes, startTime);
96425
97435
  }
@@ -96561,16 +97571,17 @@ var CoherenceService = class {
96561
97571
  * Convert agent health to a numerical embedding
96562
97572
  */
96563
97573
  agentHealthToEmbedding(health) {
97574
+ const beliefs = health.beliefs ?? [];
96564
97575
  return [
96565
97576
  health.health,
96566
97577
  health.successRate,
96567
97578
  Math.min(1, health.errorCount / 10),
96568
97579
  this.agentTypeToNumber(health.agentType),
96569
- health.beliefs.length / 10,
97580
+ beliefs.length / 10,
96570
97581
  // Add belief embeddings (first 3 beliefs, padded)
96571
- ...health.beliefs[0]?.embedding.slice(0, 5) || [0, 0, 0, 0, 0],
96572
- ...health.beliefs[1]?.embedding.slice(0, 5) || [0, 0, 0, 0, 0],
96573
- ...health.beliefs[2]?.embedding.slice(0, 5) || [0, 0, 0, 0, 0]
97582
+ ...beliefs[0]?.embedding.slice(0, 5) || [0, 0, 0, 0, 0],
97583
+ ...beliefs[1]?.embedding.slice(0, 5) || [0, 0, 0, 0, 0],
97584
+ ...beliefs[2]?.embedding.slice(0, 5) || [0, 0, 0, 0, 0]
96574
97585
  ];
96575
97586
  }
96576
97587
  /**
@@ -97777,7 +98788,8 @@ var MemoryCoherenceAuditor = class {
97777
98788
  findBroadPatterns(patterns) {
97778
98789
  return patterns.filter((p) => {
97779
98790
  const hasGenericName = /generic|general|common|basic/i.test(p.name);
97780
- const hasLowSpecificity = p.context.tags.length < 2;
98791
+ const tags = p.context?.tags;
98792
+ const hasLowSpecificity = !tags || tags.length < 2;
97781
98793
  return hasGenericName || hasLowSpecificity;
97782
98794
  }).map((p) => p.id);
97783
98795
  }