@howlil/ez-agents 3.4.2 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (365) hide show
  1. package/README.md +735 -462
  2. package/agents/ez-architect-agent.md +267 -0
  3. package/agents/ez-backend-agent.md +303 -0
  4. package/agents/ez-chief-strategist.md +271 -0
  5. package/agents/ez-codebase-mapper.md +770 -770
  6. package/agents/ez-context-manager.md +319 -0
  7. package/agents/ez-debugger.md +1255 -1255
  8. package/agents/ez-design-expert.md +347 -0
  9. package/agents/ez-devops-agent.md +331 -0
  10. package/agents/ez-executor.md +487 -487
  11. package/agents/ez-frontend-agent.md +322 -0
  12. package/agents/ez-phase-researcher.md +553 -553
  13. package/agents/ez-planner.md +1307 -1307
  14. package/agents/ez-product-engineer.md +435 -0
  15. package/agents/ez-project-researcher.md +629 -629
  16. package/agents/ez-qa-agent.md +320 -0
  17. package/agents/ez-release-agent.md +333 -0
  18. package/agents/ez-requirements-agent.md +377 -0
  19. package/agents/ez-roadmapper.md +650 -650
  20. package/agents/ez-technical-writer.md +551 -0
  21. package/agents/ez-ux-expert.md +393 -0
  22. package/agents/ez-verifier.md +579 -579
  23. package/bin/guards/autonomy-guard.cjs +346 -0
  24. package/bin/guards/context-budget-guard.cjs +278 -0
  25. package/bin/guards/hallucination-guard.cjs +380 -0
  26. package/bin/guards/hidden-state-guard.cjs +182 -0
  27. package/bin/guards/team-overhead-guard.cjs +266 -0
  28. package/bin/guards/tool-sprawl-guard.cjs +271 -0
  29. package/bin/install.js +3221 -3272
  30. package/bin/lib/analytics/analytics-collector.cjs +86 -0
  31. package/bin/lib/analytics/analytics-reporter.cjs +130 -0
  32. package/bin/lib/analytics/cohort-analyzer.cjs +138 -0
  33. package/bin/lib/analytics/funnel-analyzer.cjs +147 -0
  34. package/bin/lib/analytics/nps-tracker.cjs +147 -0
  35. package/bin/lib/archetype-detector.cjs +289 -0
  36. package/bin/lib/assistant-adapter.cjs +361 -0
  37. package/bin/lib/audit-exec.cjs +175 -0
  38. package/bin/lib/auth.cjs +176 -0
  39. package/bin/lib/backup-service.cjs +422 -0
  40. package/bin/lib/bdd-validator.cjs +622 -0
  41. package/bin/lib/business-flow-mapper.cjs +429 -0
  42. package/bin/lib/circuit-breaker.cjs +276 -0
  43. package/bin/lib/code-complexity-analyzer.cjs +360 -0
  44. package/bin/lib/codebase-analyzer.cjs +241 -0
  45. package/bin/lib/commands.cjs +691 -0
  46. package/bin/lib/config.cjs +236 -0
  47. package/bin/lib/constraint-extractor.cjs +526 -0
  48. package/bin/lib/content-scanner.cjs +238 -0
  49. package/bin/lib/context-cache.cjs +154 -0
  50. package/bin/lib/context-compressor.cjs +102 -0
  51. package/bin/lib/context-deduplicator.cjs +105 -0
  52. package/bin/lib/context-errors.cjs +78 -0
  53. package/bin/lib/context-manager.cjs +338 -0
  54. package/bin/lib/context-metadata-tracker.cjs +140 -0
  55. package/bin/lib/context-relevance-scorer.cjs +99 -0
  56. package/bin/lib/core.cjs +507 -0
  57. package/bin/lib/cost-alerts.cjs +174 -0
  58. package/bin/lib/cost-tracker.cjs +275 -0
  59. package/bin/lib/crash-recovery.cjs +220 -0
  60. package/bin/lib/dependency-graph.cjs +319 -0
  61. package/bin/lib/deploy/deploy-audit-log.cjs +76 -0
  62. package/bin/lib/deploy/deploy-detector.cjs +69 -0
  63. package/bin/lib/deploy/deploy-env-manager.cjs +109 -0
  64. package/bin/lib/deploy/deploy-health-check.cjs +88 -0
  65. package/bin/lib/deploy/deploy-pre-flight.cjs +57 -0
  66. package/bin/lib/deploy/deploy-rollback.cjs +72 -0
  67. package/bin/lib/deploy/deploy-runner.cjs +97 -0
  68. package/bin/lib/deploy/deploy-status.cjs +74 -0
  69. package/bin/lib/discussion-synthesizer.cjs +439 -0
  70. package/bin/lib/error-cache.cjs +114 -0
  71. package/bin/lib/error-registry.cjs +177 -0
  72. package/bin/lib/file-access.cjs +207 -0
  73. package/bin/lib/file-lock.cjs +236 -0
  74. package/bin/lib/finops/budget-enforcer.cjs +126 -0
  75. package/bin/lib/finops/cost-reporter.cjs +132 -0
  76. package/bin/lib/finops/finops-analyzer.cjs +112 -0
  77. package/bin/lib/finops/spot-manager.cjs +118 -0
  78. package/bin/lib/framework-detector.cjs +396 -0
  79. package/bin/lib/frontmatter.cjs +313 -0
  80. package/bin/lib/fs-utils.cjs +153 -0
  81. package/bin/lib/gate-executor.cjs +272 -0
  82. package/bin/lib/gates/README.md +374 -0
  83. package/bin/lib/gates/gate-01-requirement.cjs +303 -0
  84. package/bin/lib/gates/gate-02-architecture.cjs +555 -0
  85. package/bin/lib/gates/gate-03-code.cjs +635 -0
  86. package/bin/lib/gates/gate-04-security.cjs +829 -0
  87. package/bin/lib/git-errors.cjs +83 -0
  88. package/bin/lib/git-utils.cjs +321 -0
  89. package/bin/lib/git-workflow-engine.cjs +1157 -0
  90. package/bin/lib/health-check.cjs +227 -0
  91. package/bin/lib/index.cjs +279 -0
  92. package/bin/lib/init.cjs +725 -0
  93. package/bin/lib/lock-logger.cjs +194 -0
  94. package/bin/lib/lock-state.cjs +263 -0
  95. package/bin/lib/lockfile-validator.cjs +227 -0
  96. package/bin/lib/log-rotation.cjs +71 -0
  97. package/bin/lib/logger.cjs +125 -0
  98. package/bin/lib/memory-compression.cjs +256 -0
  99. package/bin/lib/milestone.cjs +247 -0
  100. package/bin/lib/model-provider.cjs +241 -0
  101. package/bin/lib/package-manager-detector.cjs +203 -0
  102. package/bin/lib/package-manager-executor.cjs +385 -0
  103. package/bin/lib/package-manager-service.cjs +216 -0
  104. package/bin/lib/perf/api-monitor.cjs +88 -0
  105. package/bin/lib/perf/db-optimizer.cjs +78 -0
  106. package/bin/lib/perf/frontend-performance.cjs +56 -0
  107. package/bin/lib/perf/perf-analyzer.cjs +77 -0
  108. package/bin/lib/perf/perf-baseline.cjs +102 -0
  109. package/bin/lib/perf/perf-reporter.cjs +117 -0
  110. package/bin/lib/perf/regression-detector.cjs +92 -0
  111. package/bin/lib/phase.cjs +963 -0
  112. package/bin/lib/planning-write.cjs +123 -0
  113. package/bin/lib/project-reporter.cjs +565 -0
  114. package/bin/lib/quality-gate.cjs +332 -0
  115. package/bin/lib/quality-metrics.cjs +324 -0
  116. package/bin/lib/recovery-manager.cjs +98 -0
  117. package/bin/lib/release-validator.cjs +617 -0
  118. package/bin/lib/retry.cjs +119 -0
  119. package/bin/lib/roadmap.cjs +309 -0
  120. package/bin/lib/safe-exec.cjs +173 -0
  121. package/bin/lib/safe-path.cjs +130 -0
  122. package/bin/lib/security-errors.cjs +62 -0
  123. package/bin/lib/session-chain.cjs +304 -0
  124. package/bin/lib/session-errors.cjs +81 -0
  125. package/bin/lib/session-export.cjs +251 -0
  126. package/bin/lib/session-import.cjs +262 -0
  127. package/bin/lib/session-manager.cjs +280 -0
  128. package/bin/lib/skill-context.cjs +148 -0
  129. package/bin/lib/skill-matcher.cjs +236 -0
  130. package/bin/lib/skill-registry.cjs +360 -0
  131. package/bin/lib/skill-resolver.cjs +449 -0
  132. package/bin/lib/skill-triggers.cjs +90 -0
  133. package/bin/lib/skill-validator.cjs +270 -0
  134. package/bin/lib/skill-versioning.cjs +355 -0
  135. package/bin/lib/stack-detector.cjs +399 -0
  136. package/bin/lib/state.cjs +736 -0
  137. package/bin/lib/tech-debt-analyzer.cjs +309 -0
  138. package/bin/lib/temp-file.cjs +239 -0
  139. package/bin/lib/template.cjs +223 -0
  140. package/bin/lib/test-file-lock.cjs +112 -0
  141. package/bin/lib/test-graceful.cjs +93 -0
  142. package/bin/lib/test-logger.cjs +60 -0
  143. package/bin/lib/test-safe-exec.cjs +38 -0
  144. package/bin/lib/test-safe-path.cjs +33 -0
  145. package/bin/lib/test-temp-file.cjs +125 -0
  146. package/bin/lib/tier-manager.cjs +428 -0
  147. package/bin/lib/timeout-exec.cjs +63 -0
  148. package/bin/lib/tradeoff-analyzer.cjs +284 -0
  149. package/bin/lib/url-fetch.cjs +170 -0
  150. package/bin/lib/verify.cjs +863 -0
  151. package/bin/update.js +217 -214
  152. package/commands/deploy.cjs +53 -0
  153. package/commands/ez/add-tests.md +41 -41
  154. package/commands/ez/audit-milestone.md +36 -36
  155. package/commands/ez/complete-milestone.md +136 -136
  156. package/commands/ez/discuss-phase.md +90 -90
  157. package/commands/ez/execute-phase.md +52 -41
  158. package/commands/ez/help.md +22 -22
  159. package/commands/ez/map-codebase.md +71 -71
  160. package/commands/ez/new-milestone.md +44 -44
  161. package/commands/ez/new-project.md +51 -42
  162. package/commands/ez/plan-phase.md +53 -45
  163. package/commands/ez/progress.md +36 -24
  164. package/commands/ez/quick.md +45 -45
  165. package/commands/ez/resume-work.md +40 -40
  166. package/commands/ez/run-phase.md +580 -0
  167. package/commands/ez/settings.md +36 -36
  168. package/commands/ez/update.md +37 -37
  169. package/commands/ez/verify-work.md +402 -38
  170. package/commands/health-check.cjs +44 -0
  171. package/commands/rollback.cjs +47 -0
  172. package/ez-agents/bin/ez-tools.cjs +1692 -716
  173. package/ez-agents/bin/guards/autonomy-guard.cjs +346 -0
  174. package/ez-agents/bin/guards/context-budget-guard.cjs +247 -0
  175. package/ez-agents/bin/guards/hallucination-guard.cjs +271 -0
  176. package/ez-agents/bin/guards/hidden-state-guard.cjs +182 -0
  177. package/ez-agents/bin/guards/team-overhead-guard.cjs +266 -0
  178. package/ez-agents/bin/guards/tool-sprawl-guard.cjs +271 -0
  179. package/ez-agents/bin/lib/analytics/analytics-collector.cjs +86 -0
  180. package/ez-agents/bin/lib/analytics/analytics-reporter.cjs +130 -0
  181. package/ez-agents/bin/lib/analytics/cohort-analyzer.cjs +138 -0
  182. package/ez-agents/bin/lib/analytics/funnel-analyzer.cjs +147 -0
  183. package/ez-agents/bin/lib/analytics/nps-tracker.cjs +147 -0
  184. package/ez-agents/bin/lib/archetype-detector.cjs +289 -0
  185. package/ez-agents/bin/lib/audit-exec.cjs +166 -167
  186. package/ez-agents/bin/lib/auth.cjs +176 -176
  187. package/ez-agents/bin/lib/backup-service.cjs +422 -0
  188. package/ez-agents/bin/lib/bdd-validator.cjs +622 -0
  189. package/ez-agents/bin/lib/business-flow-mapper.cjs +429 -0
  190. package/ez-agents/bin/lib/code-complexity-analyzer.cjs +360 -0
  191. package/ez-agents/bin/lib/codebase-analyzer.cjs +241 -0
  192. package/ez-agents/bin/lib/commands.cjs +685 -685
  193. package/ez-agents/bin/lib/config.cjs +41 -1
  194. package/ez-agents/bin/lib/constraint-extractor.cjs +526 -0
  195. package/ez-agents/bin/lib/content-scanner.cjs +238 -0
  196. package/ez-agents/bin/lib/context-cache.cjs +154 -0
  197. package/ez-agents/bin/lib/context-errors.cjs +71 -0
  198. package/ez-agents/bin/lib/context-manager.cjs +220 -0
  199. package/ez-agents/bin/lib/core.cjs +507 -512
  200. package/ez-agents/bin/lib/cost-tracker.cjs +243 -0
  201. package/ez-agents/bin/lib/crash-recovery.cjs +172 -0
  202. package/ez-agents/bin/lib/dependency-graph.cjs +319 -0
  203. package/ez-agents/bin/lib/deploy/deploy-audit-log.cjs +76 -0
  204. package/ez-agents/bin/lib/deploy/deploy-detector.cjs +69 -0
  205. package/ez-agents/bin/lib/deploy/deploy-env-manager.cjs +109 -0
  206. package/ez-agents/bin/lib/deploy/deploy-health-check.cjs +88 -0
  207. package/ez-agents/bin/lib/deploy/deploy-pre-flight.cjs +57 -0
  208. package/ez-agents/bin/lib/deploy/deploy-rollback.cjs +72 -0
  209. package/ez-agents/bin/lib/deploy/deploy-runner.cjs +97 -0
  210. package/ez-agents/bin/lib/deploy/deploy-status.cjs +74 -0
  211. package/ez-agents/bin/lib/discussion-synthesizer.cjs +458 -0
  212. package/ez-agents/bin/lib/file-access.cjs +207 -0
  213. package/ez-agents/bin/lib/finops/budget-enforcer.cjs +126 -0
  214. package/ez-agents/bin/lib/finops/cost-reporter.cjs +132 -0
  215. package/ez-agents/bin/lib/finops/finops-analyzer.cjs +112 -0
  216. package/ez-agents/bin/lib/finops/spot-manager.cjs +118 -0
  217. package/ez-agents/bin/lib/framework-detector.cjs +396 -0
  218. package/ez-agents/bin/lib/frontmatter.cjs +3 -1
  219. package/ez-agents/bin/lib/gates/README.md +374 -0
  220. package/ez-agents/bin/lib/gates/gate-01-requirement.cjs +303 -0
  221. package/ez-agents/bin/lib/gates/gate-02-architecture.cjs +555 -0
  222. package/ez-agents/bin/lib/gates/gate-03-code.cjs +635 -0
  223. package/ez-agents/bin/lib/gates/gate-04-security.cjs +829 -0
  224. package/ez-agents/bin/lib/git-errors.cjs +83 -0
  225. package/ez-agents/bin/lib/git-utils.cjs +118 -0
  226. package/ez-agents/bin/lib/git-workflow-engine.cjs +1157 -0
  227. package/ez-agents/bin/lib/health-check.cjs +162 -162
  228. package/ez-agents/bin/lib/index.cjs +40 -2
  229. package/ez-agents/bin/lib/init.cjs +0 -2
  230. package/ez-agents/bin/lib/lockfile-validator.cjs +227 -0
  231. package/ez-agents/bin/lib/log-rotation.cjs +71 -0
  232. package/ez-agents/bin/lib/logger.cjs +99 -154
  233. package/ez-agents/bin/lib/memory-compression.cjs +256 -0
  234. package/ez-agents/bin/lib/package-manager-detector.cjs +203 -0
  235. package/ez-agents/bin/lib/package-manager-executor.cjs +385 -0
  236. package/ez-agents/bin/lib/package-manager-service.cjs +216 -0
  237. package/ez-agents/bin/lib/perf/api-monitor.cjs +88 -0
  238. package/ez-agents/bin/lib/perf/db-optimizer.cjs +78 -0
  239. package/ez-agents/bin/lib/perf/frontend-performance.cjs +56 -0
  240. package/ez-agents/bin/lib/perf/perf-analyzer.cjs +77 -0
  241. package/ez-agents/bin/lib/perf/perf-baseline.cjs +102 -0
  242. package/ez-agents/bin/lib/perf/perf-reporter.cjs +117 -0
  243. package/ez-agents/bin/lib/perf/regression-detector.cjs +92 -0
  244. package/ez-agents/bin/lib/project-reporter.cjs +502 -0
  245. package/ez-agents/bin/lib/quality-gate.cjs +332 -0
  246. package/ez-agents/bin/lib/recovery-manager.cjs +98 -0
  247. package/ez-agents/bin/lib/release-validator.cjs +617 -0
  248. package/ez-agents/bin/lib/safe-exec.cjs +128 -214
  249. package/ez-agents/bin/lib/security-errors.cjs +62 -0
  250. package/ez-agents/bin/lib/session-chain.cjs +304 -0
  251. package/ez-agents/bin/lib/session-errors.cjs +81 -0
  252. package/ez-agents/bin/lib/session-export.cjs +251 -0
  253. package/ez-agents/bin/lib/session-import.cjs +262 -0
  254. package/ez-agents/bin/lib/session-manager.cjs +280 -0
  255. package/ez-agents/bin/lib/skill-context.cjs +148 -0
  256. package/ez-agents/bin/lib/skill-matcher.cjs +236 -0
  257. package/ez-agents/bin/lib/skill-registry.cjs +341 -0
  258. package/ez-agents/bin/lib/skill-resolver.cjs +449 -0
  259. package/ez-agents/bin/lib/skill-triggers.cjs +90 -0
  260. package/ez-agents/bin/lib/skill-validator.cjs +270 -0
  261. package/ez-agents/bin/lib/skill-versioning.cjs +355 -0
  262. package/ez-agents/bin/lib/stack-detector.cjs +399 -0
  263. package/ez-agents/bin/lib/tech-debt-analyzer.cjs +309 -0
  264. package/ez-agents/bin/lib/tier-manager.cjs +428 -0
  265. package/ez-agents/bin/lib/tradeoff-analyzer.cjs +284 -0
  266. package/ez-agents/bin/lib/url-fetch.cjs +170 -0
  267. package/ez-agents/bin/lib/verify.cjs +863 -863
  268. package/ez-agents/references/decimal-phase-calculation.md +65 -65
  269. package/ez-agents/references/git-integration.md +248 -248
  270. package/ez-agents/references/git-planning-commit.md +38 -38
  271. package/ez-agents/references/metrics-schema.md +118 -0
  272. package/ez-agents/references/model-profile-resolution.md +34 -34
  273. package/ez-agents/references/model-profiles.md +93 -93
  274. package/ez-agents/references/phase-argument-parsing.md +61 -61
  275. package/ez-agents/references/planning-config.md +340 -200
  276. package/ez-agents/references/tier-strategy.md +103 -0
  277. package/ez-agents/references/ui-brand.md +160 -160
  278. package/ez-agents/references/verification-patterns.md +612 -612
  279. package/ez-agents/templates/DEBUG.md +164 -164
  280. package/ez-agents/templates/UAT.md +247 -247
  281. package/ez-agents/templates/agent-output-format.md +404 -0
  282. package/ez-agents/templates/bdd-feature.md +173 -0
  283. package/ez-agents/templates/codebase/architecture.md +255 -255
  284. package/ez-agents/templates/codebase/structure.md +285 -285
  285. package/ez-agents/templates/copilot-instructions.md +7 -7
  286. package/ez-agents/templates/debug-subagent-prompt.md +91 -91
  287. package/ez-agents/templates/discovery.md +146 -146
  288. package/ez-agents/templates/discussion.md +68 -0
  289. package/ez-agents/templates/handoff-protocol.md +294 -0
  290. package/ez-agents/templates/incident-runbook.md +205 -0
  291. package/ez-agents/templates/mode-workflow-templates.md +301 -0
  292. package/ez-agents/templates/phase-prompt.md +610 -610
  293. package/ez-agents/templates/planner-subagent-prompt.md +117 -117
  294. package/ez-agents/templates/project.md +184 -184
  295. package/ez-agents/templates/release-checklist.md +136 -0
  296. package/ez-agents/templates/research.md +552 -552
  297. package/ez-agents/templates/rollback-plan.md +201 -0
  298. package/ez-agents/templates/security-user-setup.md +244 -0
  299. package/ez-agents/templates/skill-validation-rules.md +476 -0
  300. package/ez-agents/templates/state.md +180 -176
  301. package/ez-agents/templates/summary-complex.md +59 -59
  302. package/ez-agents/tests/gates/gate-01-02.test.cjs +812 -0
  303. package/ez-agents/tests/gates/gate-03-04.test.cjs +762 -0
  304. package/ez-agents/tests/gates/gate-05-validator.test.cjs +145 -0
  305. package/ez-agents/tests/gates/gate-06-docs-validator.test.cjs +244 -0
  306. package/ez-agents/tests/gates/gate-07-release-validator.test.cjs +219 -0
  307. package/ez-agents/tests/guards/context-budget-guard.test.cjs +145 -0
  308. package/ez-agents/tests/guards/edge-case-guards.test.cjs +238 -0
  309. package/ez-agents/tests/guards/hallucination-guard.test.cjs +124 -0
  310. package/ez-agents/workflows/audit-milestone.md +1 -1
  311. package/ez-agents/workflows/autonomous.md +131 -30
  312. package/ez-agents/workflows/complete-milestone.md +1 -1
  313. package/ez-agents/workflows/discuss-phase.md +1 -1
  314. package/ez-agents/workflows/execute-phase.md +169 -3
  315. package/ez-agents/workflows/help.md +86 -133
  316. package/ez-agents/workflows/hotfix.md +291 -0
  317. package/ez-agents/workflows/new-milestone.md +340 -11
  318. package/ez-agents/workflows/new-project.md +294 -318
  319. package/ez-agents/workflows/plan-phase.md +22 -40
  320. package/ez-agents/workflows/progress.md +15 -25
  321. package/ez-agents/workflows/release.md +253 -0
  322. package/ez-agents/workflows/resume-session.md +215 -0
  323. package/ez-agents/workflows/run-phase.md +531 -0
  324. package/ez-agents/workflows/settings.md +2 -35
  325. package/hooks/dist/ez-check-update.js +81 -81
  326. package/hooks/dist/ez-context-monitor.js +148 -141
  327. package/hooks/dist/ez-statusline.js +115 -115
  328. package/package.json +78 -64
  329. package/scripts/fix-qwen-installation.js +144 -144
  330. package/agents/ez-integration-checker.md +0 -443
  331. package/agents/ez-nyquist-auditor.md +0 -176
  332. package/agents/ez-plan-checker.md +0 -706
  333. package/agents/ez-research-synthesizer.md +0 -247
  334. package/agents/ez-ui-auditor.md +0 -439
  335. package/agents/ez-ui-checker.md +0 -300
  336. package/agents/ez-ui-researcher.md +0 -353
  337. package/commands/ez/add-phase.md +0 -43
  338. package/commands/ez/add-todo.md +0 -47
  339. package/commands/ez/auth.md +0 -87
  340. package/commands/ez/autonomous.md +0 -41
  341. package/commands/ez/check-todos.md +0 -45
  342. package/commands/ez/cleanup.md +0 -18
  343. package/commands/ez/debug.md +0 -168
  344. package/commands/ez/health.md +0 -22
  345. package/commands/ez/insert-phase.md +0 -32
  346. package/commands/ez/join-discord.md +0 -18
  347. package/commands/ez/list-phase-assumptions.md +0 -46
  348. package/commands/ez/pause-work.md +0 -38
  349. package/commands/ez/plan-milestone-gaps.md +0 -34
  350. package/commands/ez/reapply-patches.md +0 -124
  351. package/commands/ez/remove-phase.md +0 -31
  352. package/commands/ez/research-phase.md +0 -190
  353. package/commands/ez/set-profile.md +0 -34
  354. package/commands/ez/stats.md +0 -18
  355. package/commands/ez/ui-phase.md +0 -34
  356. package/commands/ez/ui-review.md +0 -32
  357. package/commands/ez/validate-phase.md +0 -35
  358. package/ez-agents/templates/UI-SPEC.md +0 -100
  359. package/ez-agents/templates/VALIDATION.md +0 -76
  360. package/ez-agents/templates/context.md +0 -352
  361. package/ez-agents/templates/verification-report.md +0 -322
  362. package/ez-agents/workflows/research-phase.md +0 -74
  363. package/ez-agents/workflows/ui-phase.md +0 -290
  364. package/ez-agents/workflows/ui-review.md +0 -157
  365. package/ez-agents/workflows/validate-phase.md +0 -167
@@ -0,0 +1,762 @@
1
+ /**
2
+ * Gate 3-4 Tests
3
+ *
4
+ * Tests for Code Quality (Gate 3) and Security Baseline (Gate 4)
5
+ *
6
+ * Test cases:
7
+ * Gate 3:
8
+ * 1. Gate 3 passes for clean code with short functions
9
+ * 2. Gate 3 flags functions > 50 lines
10
+ * 3. Gate 3 flags nesting > 4 levels
11
+ * 4. Gate 3 detects magic numbers without named constants
12
+ * 5. Gate 3 detects generic helper sprawl
13
+ *
14
+ * Gate 4:
15
+ * 6. Gate 4 passes when auth uses secure session management
16
+ * 7. Gate 4 flags hardcoded credentials
17
+ * 8. Gate 4 flags eval() usage
18
+ * 9. Gate 4 flags execSync with user input
19
+ * 10. Gate 4 flags SQL query concatenation
20
+ * 11. Gate 4 passes when env vars used for secrets
21
+ * 12. Gate 4 flags missing input validation
22
+ */
23
+
24
+ const { describe, it, beforeEach } = require('node:test');
25
+ const { strict: assert } = require('node:assert');
26
+
27
+ // Import Gate 3
28
+ const {
29
+ executeGate3,
30
+ checkFunctionLength,
31
+ calculateNestingDepth,
32
+ detectMagicNumbers,
33
+ detectGenericHelperSprawl,
34
+ THRESHOLDS,
35
+ } = require('../../bin/lib/gates/gate-03-code.cjs');
36
+
37
+ // Import Gate 4
38
+ const {
39
+ executeGate4,
40
+ detectEvalUsage,
41
+ detectExecUsage,
42
+ detectSqlInjection,
43
+ detectHardcodedSecrets,
44
+ checkSessionSecurity,
45
+ checkEnvVarUsage,
46
+ } = require('../../bin/lib/gates/gate-04-security.cjs');
47
+
48
+ // Import QualityGate for integration test
49
+ const { QualityGate } = require('../../bin/lib/quality-gate.cjs');
50
+ const { registerGate3 } = require('../../bin/lib/gates/gate-03-code.cjs');
51
+ const { registerGate4 } = require('../../bin/lib/gates/gate-04-security.cjs');
52
+
53
+ describe('Gate 3: Code Quality', () => {
54
+ describe('executeGate3', () => {
55
+ it('Gate 3 passes for clean code with short functions', async () => {
56
+ const context = {
57
+ files: [
58
+ {
59
+ path: '/src/utils.js',
60
+ content: `
61
+ function add(a, b) {
62
+ return a + b;
63
+ }
64
+
65
+ function greet(name) {
66
+ return 'Hello, ' + name;
67
+ }
68
+ `,
69
+ functions: [
70
+ {
71
+ name: 'add',
72
+ startLine: 1,
73
+ endLine: 3,
74
+ body: 'function add(a, b) {\n return a + b;\n}',
75
+ parameters: ['a', 'b'],
76
+ },
77
+ {
78
+ name: 'greet',
79
+ startLine: 5,
80
+ endLine: 7,
81
+ body: "function greet(name) {\n return 'Hello, ' + name;\n}",
82
+ parameters: ['name'],
83
+ },
84
+ ],
85
+ },
86
+ ],
87
+ };
88
+
89
+ const result = await executeGate3(context);
90
+
91
+ assert.strictEqual(result.passed, true);
92
+ assert.strictEqual(result.errors.length, 0);
93
+ });
94
+
95
+ it('Gate 3 flags functions > 50 lines', async () => {
96
+ // Generate a function with 55 lines
97
+ const longFunctionBody = 'function longFunction() {\n' +
98
+ Array(55).fill(' console.log("line");').join('\n') +
99
+ '\n}';
100
+
101
+ const context = {
102
+ files: [
103
+ {
104
+ path: '/src/long.js',
105
+ content: longFunctionBody,
106
+ functions: [
107
+ {
108
+ name: 'longFunction',
109
+ startLine: 1,
110
+ endLine: 56,
111
+ body: longFunctionBody,
112
+ parameters: [],
113
+ },
114
+ ],
115
+ },
116
+ ],
117
+ };
118
+
119
+ const result = await executeGate3(context);
120
+
121
+ assert.strictEqual(result.passed, false);
122
+ assert.ok(result.errors.length > 0);
123
+ assert.ok(result.errors.some(e => e.message.includes('longFunction')));
124
+ assert.ok(result.errors.some(e => e.message.includes('lines')));
125
+ });
126
+
127
+ it('Gate 3 flags nesting > 4 levels', async () => {
128
+ const deeplyNestedCode = `
129
+ function process() {
130
+ if (true) {
131
+ for (let i = 0; i < 10; i++) {
132
+ while (true) {
133
+ switch (x) {
134
+ case 1:
135
+ if (y) {
136
+ console.log('too deep');
137
+ }
138
+ }
139
+ }
140
+ }
141
+ }
142
+ }
143
+ `;
144
+
145
+ const context = {
146
+ files: [
147
+ {
148
+ path: '/src/nested.js',
149
+ content: deeplyNestedCode,
150
+ },
151
+ ],
152
+ };
153
+
154
+ const result = await executeGate3(context);
155
+
156
+ assert.strictEqual(result.passed, false);
157
+ assert.ok(result.errors.length > 0);
158
+ assert.ok(result.errors.some(e => e.message.includes('Nesting')));
159
+ });
160
+
161
+ it('Gate 3 detects magic numbers without named constants', async () => {
162
+ const codeWithMagicNumbers = `
163
+ function calculate() {
164
+ const tax = 1250 * 0.0875;
165
+ const discount = price * 0.15;
166
+ const shipping = 49.99;
167
+ return tax + discount + shipping;
168
+ }
169
+ `;
170
+
171
+ const context = {
172
+ files: [
173
+ {
174
+ path: '/src/calc.js',
175
+ content: codeWithMagicNumbers,
176
+ },
177
+ ],
178
+ namedConstants: [],
179
+ };
180
+
181
+ const result = await executeGate3(context);
182
+
183
+ assert.strictEqual(result.passed, true); // Magic numbers are warnings, not errors
184
+ assert.ok(result.warnings.length > 0);
185
+ assert.ok(result.warnings.some(w => w.includes('Magic number')));
186
+ });
187
+
188
+ it('Gate 3 detects generic helper sprawl', async () => {
189
+ const context = {
190
+ genericHelpers: [
191
+ { name: 'utils', usageCount: 5 },
192
+ { name: 'helpers', usageCount: 10 },
193
+ { name: 'common', usageCount: 0 },
194
+ ],
195
+ };
196
+
197
+ const result = await executeGate3(context);
198
+
199
+ assert.strictEqual(result.passed, true); // Helper sprawl is a warning
200
+ assert.ok(result.warnings.length > 0);
201
+ assert.ok(result.warnings.some(w => w.includes('Generic helper') || w.includes('utils') || w.includes('helpers')));
202
+ });
203
+ });
204
+
205
+ describe('checkFunctionLength', () => {
206
+ it('should pass for short functions', () => {
207
+ const shortBody = 'function test() {\n return 1;\n}';
208
+ const result = checkFunctionLength(shortBody);
209
+ assert.strictEqual(result.exceeds, false);
210
+ assert.strictEqual(result.length, 3);
211
+ });
212
+
213
+ it('should fail for long functions', () => {
214
+ const longBody = 'function test() {\n' +
215
+ Array(60).fill(' console.log("line");').join('\n') +
216
+ '\n}';
217
+ const result = checkFunctionLength(longBody);
218
+ assert.strictEqual(result.exceeds, true);
219
+ assert.ok(result.length > THRESHOLDS.maxFunctionLength);
220
+ });
221
+ });
222
+
223
+ describe('calculateNestingDepth', () => {
224
+ it('should calculate nesting depth correctly', () => {
225
+ const code = `
226
+ function test() {
227
+ if (true) {
228
+ for (let i = 0; i < 10; i++) {
229
+ while (true) {
230
+ console.log('deep');
231
+ }
232
+ }
233
+ }
234
+ }
235
+ `;
236
+ const depth = calculateNestingDepth(code);
237
+ // The function counts brace nesting: function->if->for->while = 4 levels
238
+ // But subtracts 1 for the outermost scope, so expected is 3
239
+ assert.strictEqual(depth, 3); // if -> for -> while
240
+ });
241
+
242
+ it('should return 0 for flat code', () => {
243
+ const code = 'const x = 1;\nconst y = 2;';
244
+ const depth = calculateNestingDepth(code);
245
+ assert.strictEqual(depth, 0);
246
+ });
247
+
248
+ it('should handle shallow nesting', () => {
249
+ const code = `
250
+ if (true) {
251
+ console.log('hello');
252
+ }
253
+ `;
254
+ const depth = calculateNestingDepth(code);
255
+ // Single if block = 1 level of braces, but no outer function scope
256
+ // So depth is 0 (we subtract 1 for the outermost scope)
257
+ assert.strictEqual(depth, 0);
258
+ });
259
+ });
260
+
261
+ describe('detectMagicNumbers', () => {
262
+ it('should detect magic numbers', () => {
263
+ const code = 'const x = 42; const y = 100;';
264
+ const magicNumbers = detectMagicNumbers(code);
265
+ assert.ok(magicNumbers.length > 0);
266
+ assert.ok(magicNumbers.some(m => m.value === 42));
267
+ });
268
+
269
+ it('should ignore 0, 1, 2', () => {
270
+ const code = 'for (let i = 0; i < 10; i += 1) { const x = 2; }';
271
+ const magicNumbers = detectMagicNumbers(code);
272
+ // 10 should still be detected
273
+ assert.ok(magicNumbers.some(m => m.value === 10));
274
+ });
275
+
276
+ it('should skip named constants', () => {
277
+ const code = 'const TAX_RATE = 0.0875; const tax = price * TAX_RATE;';
278
+ const namedConstants = [{ name: 'TAX_RATE', value: 0.0875 }];
279
+ const magicNumbers = detectMagicNumbers(code, namedConstants);
280
+ // Should not flag 0.0875 since it's a named constant
281
+ assert.strictEqual(magicNumbers.length, 0);
282
+ });
283
+
284
+ it('should skip numbers in strings', () => {
285
+ const code = 'const msg = "Price is 99.99"; const x = 42;';
286
+ const magicNumbers = detectMagicNumbers(code);
287
+ // Should only flag 42, not 99.99 in string
288
+ assert.ok(magicNumbers.some(m => m.value === 42));
289
+ assert.ok(!magicNumbers.some(m => m.value === 99.99));
290
+ });
291
+ });
292
+
293
+ describe('detectGenericHelperSprawl', () => {
294
+ it('should detect sprawl for generic helper names', () => {
295
+ const helpers = [
296
+ { name: 'utils', usageCount: 5 },
297
+ { name: 'helpers', usageCount: 10 },
298
+ ];
299
+ const issues = detectGenericHelperSprawl(helpers);
300
+ assert.ok(issues.length > 0);
301
+ assert.ok(issues.some(i => i.name === 'utils' || i.name === 'helpers'));
302
+ });
303
+
304
+ it('should not flag specific helper names', () => {
305
+ const helpers = [
306
+ { name: 'stringUtils', usageCount: 5 },
307
+ { name: 'dateHelpers', usageCount: 3 },
308
+ ];
309
+ const issues = detectGenericHelperSprawl(helpers);
310
+ assert.strictEqual(issues.length, 0);
311
+ });
312
+
313
+ it('should flag unused generic helpers', () => {
314
+ const helpers = [
315
+ { name: 'utils', usageCount: 0 },
316
+ ];
317
+ const issues = detectGenericHelperSprawl(helpers);
318
+ assert.ok(issues.length > 0);
319
+ assert.ok(issues.some(i => i.issue.includes('Unused')));
320
+ });
321
+ });
322
+ });
323
+
324
+ describe('Gate 4: Security Baseline', () => {
325
+ describe('executeGate4', () => {
326
+ it('Gate 4 passes when auth uses secure session management', async () => {
327
+ const secureCode = `
328
+ const session = require('express-session');
329
+ const RedisStore = require('connect-redis')(session);
330
+
331
+ app.use(session({
332
+ store: new RedisStore({ client: redisClient }),
333
+ secret: process.env.SESSION_SECRET,
334
+ resave: false,
335
+ saveUninitialized: false,
336
+ cookie: {
337
+ secure: true,
338
+ httpOnly: true,
339
+ sameSite: 'strict',
340
+ maxAge: 3600000
341
+ }
342
+ }));
343
+ `;
344
+
345
+ const context = {
346
+ files: [
347
+ {
348
+ path: '/src/auth.js',
349
+ content: secureCode,
350
+ },
351
+ ],
352
+ authConfig: {
353
+ method: 'session',
354
+ sessionStore: 'redis',
355
+ httpsEnforced: true,
356
+ csrfProtection: true,
357
+ hashingAlgorithm: 'bcrypt',
358
+ },
359
+ };
360
+
361
+ const result = await executeGate4(context);
362
+
363
+ assert.strictEqual(result.passed, true);
364
+ assert.strictEqual(result.errors.length, 0);
365
+ });
366
+
367
+ it('Gate 4 flags hardcoded credentials', async () => {
368
+ const insecureCode = `
369
+ const config = {
370
+ dbPassword: 'super_secret_password123',
371
+ apiKey: 'sk_live_abcdef1234567890abcdef',
372
+ awsKey: 'AKIAIOSFODNN7EXAMPLE'
373
+ };
374
+ `;
375
+
376
+ const context = {
377
+ files: [
378
+ {
379
+ path: '/src/config.js',
380
+ content: insecureCode,
381
+ },
382
+ ],
383
+ };
384
+
385
+ const result = await executeGate4(context);
386
+
387
+ assert.strictEqual(result.passed, false);
388
+ assert.ok(result.errors.length > 0);
389
+ assert.ok(result.errors.some(e => e.message.includes('password') || e.message.includes('secret') || e.message.includes('API')));
390
+ });
391
+
392
+ it('Gate 4 flags eval() usage', async () => {
393
+ const codeWithEval = `
394
+ function processUserInput(input) {
395
+ const result = eval(input);
396
+ return result;
397
+ }
398
+ `;
399
+
400
+ const context = {
401
+ files: [
402
+ {
403
+ path: '/src/dangerous.js',
404
+ content: codeWithEval,
405
+ },
406
+ ],
407
+ };
408
+
409
+ const result = await executeGate4(context);
410
+
411
+ assert.strictEqual(result.passed, false);
412
+ assert.ok(result.errors.length > 0);
413
+ assert.ok(result.errors.some(e => e.message.includes('eval')));
414
+ });
415
+
416
+ it('Gate 4 flags execSync with user input', async () => {
417
+ const codeWithExec = `
418
+ const { execSync } = require('child_process');
419
+
420
+ function runCommand(userInput) {
421
+ const result = execSync('echo ' + userInput, { encoding: 'utf-8' });
422
+ return result;
423
+ }
424
+ `;
425
+
426
+ const context = {
427
+ files: [
428
+ {
429
+ path: '/src/exec.js',
430
+ content: codeWithExec,
431
+ },
432
+ ],
433
+ };
434
+
435
+ const result = await executeGate4(context);
436
+
437
+ assert.strictEqual(result.passed, false);
438
+ assert.ok(result.errors.length > 0);
439
+ assert.ok(result.errors.some(e => e.message.includes('execSync') || e.message.includes('command injection')));
440
+ });
441
+
442
+ it('Gate 4 flags SQL query concatenation', async () => {
443
+ const codeWithSqlInjection = `
444
+ function getUserById(id) {
445
+ const query = 'SELECT * FROM users WHERE id = ' + id;
446
+ return db.query(query);
447
+ }
448
+
449
+ function searchUsers(name) {
450
+ return db.execute(\`SELECT * FROM users WHERE name = '\${name}'\`);
451
+ }
452
+ `;
453
+
454
+ const context = {
455
+ files: [
456
+ {
457
+ path: '/src/db.js',
458
+ content: codeWithSqlInjection,
459
+ },
460
+ ],
461
+ };
462
+
463
+ const result = await executeGate4(context);
464
+
465
+ assert.strictEqual(result.passed, false);
466
+ assert.ok(result.errors.length > 0);
467
+ assert.ok(result.errors.some(e => e.message.includes('SQL') || e.message.includes('parameterized')));
468
+ });
469
+
470
+ it('Gate 4 passes when env vars used for secrets', async () => {
471
+ const secureCode = `
472
+ const config = {
473
+ dbPassword: process.env.DB_PASSWORD,
474
+ apiKey: process.env.API_KEY,
475
+ jwtSecret: process.env.JWT_SECRET,
476
+ sessionSecret: process.env.SESSION_SECRET
477
+ };
478
+ `;
479
+
480
+ const context = {
481
+ files: [
482
+ {
483
+ path: '/src/config.js',
484
+ content: secureCode,
485
+ },
486
+ ],
487
+ };
488
+
489
+ const result = await executeGate4(context);
490
+
491
+ assert.strictEqual(result.passed, true);
492
+ assert.strictEqual(result.errors.length, 0);
493
+ });
494
+
495
+ it('Gate 4 flags missing input validation', async () => {
496
+ const codeWithoutValidation = `
497
+ app.post('/api/users', (req, res) => {
498
+ const { name, email, age } = req.body;
499
+ db.insert({ name, email, age });
500
+ res.json({ success: true });
501
+ });
502
+ `;
503
+
504
+ const context = {
505
+ files: [
506
+ {
507
+ path: '/src/routes.js',
508
+ content: codeWithoutValidation,
509
+ },
510
+ ],
511
+ hasInputValidation: false,
512
+ };
513
+
514
+ const result = await executeGate4(context);
515
+
516
+ assert.strictEqual(result.passed, false);
517
+ assert.ok(result.errors.length > 0);
518
+ assert.ok(result.errors.some(e => e.message.includes('input validation') || e.message.includes('Validation')));
519
+ });
520
+ });
521
+
522
+ describe('detectEvalUsage', () => {
523
+ it('should detect eval() calls', () => {
524
+ const code = 'const result = eval("1 + 1");';
525
+ const issues = detectEvalUsage(code);
526
+ assert.ok(issues.length > 0);
527
+ assert.ok(issues.some(i => i.type === 'eval'));
528
+ });
529
+
530
+ it('should detect Function constructor', () => {
531
+ const code = 'const fn = new Function("a", "b", "return a + b");';
532
+ const issues = detectEvalUsage(code);
533
+ assert.ok(issues.length > 0);
534
+ assert.ok(issues.some(i => i.type === 'function-constructor'));
535
+ });
536
+
537
+ it('should return empty for safe code', () => {
538
+ const code = 'const result = JSON.parse("{\"x\": 1}");';
539
+ const issues = detectEvalUsage(code);
540
+ assert.strictEqual(issues.length, 0);
541
+ });
542
+ });
543
+
544
+ describe('detectExecUsage', () => {
545
+ it('should detect execSync with user input', () => {
546
+ const code = 'execSync("ls " + req.params.path);';
547
+ const issues = detectExecUsage(code);
548
+ assert.ok(issues.length > 0);
549
+ assert.ok(issues.some(i => i.type === 'execSync-user-input'));
550
+ });
551
+
552
+ it('should warn about execSync without obvious user input', () => {
553
+ const code = 'execSync("npm install");';
554
+ const issues = detectExecUsage(code);
555
+ assert.ok(issues.length > 0);
556
+ assert.ok(issues.some(i => i.severity === 'warning'));
557
+ });
558
+ });
559
+
560
+ describe('detectSqlInjection', () => {
561
+ it('should detect string concatenation in SQL', () => {
562
+ const code = "db.query('SELECT * FROM users WHERE id = ' + userId);";
563
+ const issues = detectSqlInjection(code);
564
+ assert.ok(issues.length > 0);
565
+ assert.ok(issues.some(i => i.message.includes('SQL')));
566
+ });
567
+
568
+ it('should detect template literal SQL injection', () => {
569
+ const code = 'db.execute(`SELECT * FROM users WHERE name = "${name}"`);';
570
+ const issues = detectSqlInjection(code);
571
+ assert.ok(issues.length > 0);
572
+ assert.ok(issues.some(i => i.message.includes('parameterized')));
573
+ });
574
+ });
575
+
576
+ describe('detectHardcodedSecrets', () => {
577
+ it('should detect AWS keys', () => {
578
+ const code = "const key = 'AKIAIOSFODNN7EXAMPLE';";
579
+ const issues = detectHardcodedSecrets(code);
580
+ assert.ok(issues.length > 0);
581
+ assert.ok(issues.some(i => i.message.includes('AWS')));
582
+ });
583
+
584
+ it('should detect API keys', () => {
585
+ const code = "const apiKey = 'api_key_1234567890abcdef';";
586
+ const issues = detectHardcodedSecrets(code);
587
+ assert.ok(issues.length > 0);
588
+ assert.ok(issues.some(i => i.message.includes('API key')));
589
+ });
590
+
591
+ it('should detect passwords', () => {
592
+ const code = "const password = 'mySecretPassword123';";
593
+ const issues = detectHardcodedSecrets(code);
594
+ assert.ok(issues.length > 0);
595
+ assert.ok(issues.some(i => i.message.toLowerCase().includes('password')));
596
+ });
597
+
598
+ it('should skip process.env usage', () => {
599
+ const code = "const secret = process.env.SECRET_KEY;";
600
+ const issues = detectHardcodedSecrets(code);
601
+ assert.strictEqual(issues.length, 0);
602
+ });
603
+
604
+ it('should skip example values', () => {
605
+ const code = "const apiKey = 'YOUR_API_KEY_HERE';";
606
+ const issues = detectHardcodedSecrets(code);
607
+ assert.strictEqual(issues.length, 0);
608
+ });
609
+ });
610
+
611
+ describe('checkSessionSecurity', () => {
612
+ it('should detect insecure session config', () => {
613
+ const code = `
614
+ app.use(session({
615
+ cookie: {
616
+ secure: false,
617
+ httpOnly: false
618
+ }
619
+ }));
620
+ `;
621
+ const result = checkSessionSecurity(code);
622
+ assert.strictEqual(result.secure, false);
623
+ assert.ok(result.issues.length > 0);
624
+ });
625
+
626
+ it('should flag memory session store', () => {
627
+ const code = 'app.use(session({}));';
628
+ const result = checkSessionSecurity(code, { sessionStore: 'memory' });
629
+ assert.strictEqual(result.secure, false);
630
+ assert.ok(result.issues.some(i => i.message.includes('memory')));
631
+ });
632
+
633
+ it('should flag weak hashing algorithm', () => {
634
+ const code = 'app.use(session({}));';
635
+ const result = checkSessionSecurity(code, { hashingAlgorithm: 'md5' });
636
+ assert.strictEqual(result.secure, false);
637
+ assert.ok(result.issues.some(i => i.message.includes('md5') || i.message.includes('Weak')));
638
+ });
639
+ });
640
+
641
+ describe('checkEnvVarUsage', () => {
642
+ it('should recognize process.env usage', () => {
643
+ const code = 'const secret = process.env.SECRET_KEY;';
644
+ const result = checkEnvVarUsage(code);
645
+ assert.strictEqual(result.usesEnvVars, true);
646
+ assert.strictEqual(result.issues.length, 0);
647
+ });
648
+
649
+ it('should flag hardcoded sensitive values', () => {
650
+ const code = "const password = 'secret123';";
651
+ const result = checkEnvVarUsage(code);
652
+ assert.ok(result.issues.length > 0);
653
+ assert.ok(result.issues.some(i => i.message.includes('password')));
654
+ });
655
+ });
656
+ });
657
+
658
+ describe('Gate Integration Tests', () => {
659
+ let gates;
660
+
661
+ beforeEach(() => {
662
+ gates = new QualityGate();
663
+ });
664
+
665
+ it('Gate 3 registers with QualityGate coordinator', () => {
666
+ registerGate3(gates);
667
+
668
+ const registeredGates = gates.getRegisteredGates();
669
+ assert.ok(registeredGates.includes('gate-03-code'));
670
+ });
671
+
672
+ it('Gate 4 registers with QualityGate coordinator', () => {
673
+ registerGate4(gates);
674
+
675
+ const registeredGates = gates.getRegisteredGates();
676
+ assert.ok(registeredGates.includes('gate-04-security'));
677
+ });
678
+
679
+ it('Both gates execute successfully through coordinator', async () => {
680
+ registerGate3(gates);
681
+ registerGate4(gates);
682
+
683
+ const gate3Context = {
684
+ files: [
685
+ {
686
+ path: '/src/clean.js',
687
+ content: 'function add(a, b) { return a + b; }',
688
+ functions: [
689
+ { name: 'add', startLine: 1, endLine: 1, body: 'function add(a, b) { return a + b; }', parameters: ['a', 'b'] },
690
+ ],
691
+ },
692
+ ],
693
+ };
694
+
695
+ const gate4Context = {
696
+ files: [
697
+ {
698
+ path: '/src/secure.js',
699
+ content: 'const secret = process.env.SECRET_KEY;',
700
+ },
701
+ ],
702
+ authConfig: {
703
+ hashingAlgorithm: 'bcrypt',
704
+ httpsEnforced: true,
705
+ },
706
+ };
707
+
708
+ const gate3Result = await gates.executeGate('gate-03-code', gate3Context);
709
+ const gate4Result = await gates.executeGate('gate-04-security', gate4Context);
710
+
711
+ assert.strictEqual(gate3Result.passed, true);
712
+ assert.strictEqual(gate4Result.passed, true);
713
+ });
714
+
715
+ it('Gate 3 fails through coordinator for long functions', async () => {
716
+ registerGate3(gates);
717
+
718
+ const longFunctionBody = 'function longFunction() {\n' +
719
+ Array(60).fill(' console.log("line");').join('\n') +
720
+ '\n}';
721
+
722
+ const context = {
723
+ files: [
724
+ {
725
+ path: '/src/long.js',
726
+ content: longFunctionBody,
727
+ functions: [
728
+ { name: 'longFunction', startLine: 1, endLine: 61, body: longFunctionBody, parameters: [] },
729
+ ],
730
+ },
731
+ ],
732
+ };
733
+
734
+ const result = await gates.executeGate('gate-03-code', context);
735
+
736
+ assert.strictEqual(result.passed, false);
737
+ assert.ok(result.errors.length > 0);
738
+ });
739
+
740
+ it('Gate 4 fails through coordinator for security issues', async () => {
741
+ registerGate4(gates);
742
+
743
+ const insecureCode = `
744
+ const password = 'hardcoded123';
745
+ const result = eval(userInput);
746
+ `;
747
+
748
+ const context = {
749
+ files: [
750
+ {
751
+ path: '/src/insecure.js',
752
+ content: insecureCode,
753
+ },
754
+ ],
755
+ };
756
+
757
+ const result = await gates.executeGate('gate-04-security', context);
758
+
759
+ assert.strictEqual(result.passed, false);
760
+ assert.ok(result.errors.length > 0);
761
+ });
762
+ });