@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,458 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Discussion Synthesizer — Reads DISCUSSION.md, extracts consensus and blockers
5
+ *
6
+ * Parses the multi-agent DISCUSSION.md format to extract:
7
+ * - Hard blockers from any agent
8
+ * - Warnings and advisory notes
9
+ * - Consensus status (open | consensus-reached | needs-human)
10
+ * - Go/No-Go recommendation
11
+ */
12
+
13
+ 'use strict';
14
+
15
+ const fs = require('fs');
16
+ const path = require('path');
17
+ const { withLock } = require('./file-lock.cjs');
18
+
19
+ // ─────────────────────────────────────────────
20
+ // Parser
21
+ // ─────────────────────────────────────────────
22
+
23
+ /**
24
+ * Parse DISCUSSION.md file
25
+ * @param {string} filePath
26
+ * @returns {{ frontmatter: object, sections: object[], consensus: object, blockers: string[], warnings: string[] }}
27
+ */
28
+ function parseDiscussion(filePath) {
29
+ if (!fs.existsSync(filePath)) {
30
+ return {
31
+ found: false,
32
+ filePath,
33
+ frontmatter: {},
34
+ sections: [],
35
+ consensus: { status: 'open', goNoGo: 'GO', rationale: 'No discussion file — proceeding' },
36
+ blockers: [],
37
+ warnings: []
38
+ };
39
+ }
40
+
41
+ const content = fs.readFileSync(filePath, 'utf8');
42
+ const lines = content.split('\n');
43
+
44
+ // Parse YAML frontmatter
45
+ const frontmatter = parseFrontmatter(content);
46
+
47
+ // Parse agent sections
48
+ const sections = parseAgentSections(lines);
49
+
50
+ // Extract blockers and warnings from all sections
51
+ const blockers = [];
52
+ const warnings = [];
53
+
54
+ for (const section of sections) {
55
+ const sectionBlockers = extractBlockers(section.content);
56
+ const sectionWarnings = extractWarnings(section.content);
57
+ blockers.push(...sectionBlockers.map(b => ({ agent: section.agent, text: b })));
58
+ warnings.push(...sectionWarnings.map(w => ({ agent: section.agent, text: w })));
59
+ }
60
+
61
+ // Parse consensus section
62
+ const consensus = parseConsensus(sections);
63
+
64
+ return {
65
+ found: true,
66
+ filePath,
67
+ frontmatter,
68
+ sections,
69
+ consensus,
70
+ blockers,
71
+ warnings,
72
+ hasBlockers: blockers.length > 0,
73
+ hasWarnings: warnings.length > 0
74
+ };
75
+ }
76
+
77
+ /**
78
+ * Parse YAML frontmatter from discussion file
79
+ */
80
+ function parseFrontmatter(content) {
81
+ const match = content.match(/^---\n([\s\S]*?)\n---/);
82
+ if (!match) return {};
83
+
84
+ const fm = {};
85
+ const lines = match[1].split('\n');
86
+ for (const line of lines) {
87
+ const colonIdx = line.indexOf(':');
88
+ if (colonIdx === -1) continue;
89
+ const key = line.slice(0, colonIdx).trim();
90
+ const value = line.slice(colonIdx + 1).trim();
91
+ // Remove quotes
92
+ fm[key] = value.replace(/^['"]|['"]$/g, '');
93
+ }
94
+ return fm;
95
+ }
96
+
97
+ /**
98
+ * Parse agent sections from DISCUSSION.md
99
+ * Returns array of { agent, heading, content }
100
+ */
101
+ function parseAgentSections(lines) {
102
+ const sections = [];
103
+ let currentSection = null;
104
+ let currentContent = [];
105
+
106
+ const agentHeadings = [
107
+ { pattern: /## Requirements Perspective/, agent: 'requirements' },
108
+ { pattern: /## Tech Lead Perspective/, agent: 'tech-lead' },
109
+ { pattern: /## Observer Perspective/, agent: 'observer' },
110
+ { pattern: /## Scrum Master Perspective/, agent: 'scrum-master' },
111
+ { pattern: /## Consensus/, agent: 'consensus' }
112
+ ];
113
+
114
+ for (let i = 0; i < lines.length; i++) {
115
+ const line = lines[i];
116
+
117
+ // Check if line starts a known section
118
+ const matchedHeading = agentHeadings.find(h => h.pattern.test(line));
119
+
120
+ if (matchedHeading) {
121
+ // Save previous section
122
+ if (currentSection) {
123
+ sections.push({
124
+ agent: currentSection.agent,
125
+ heading: currentSection.heading,
126
+ content: currentContent.join('\n').trim()
127
+ });
128
+ }
129
+ currentSection = { agent: matchedHeading.agent, heading: line };
130
+ currentContent = [];
131
+ } else if (currentSection) {
132
+ currentContent.push(line);
133
+ }
134
+ }
135
+
136
+ // Push last section
137
+ if (currentSection) {
138
+ sections.push({
139
+ agent: currentSection.agent,
140
+ heading: currentSection.heading,
141
+ content: currentContent.join('\n').trim()
142
+ });
143
+ }
144
+
145
+ return sections;
146
+ }
147
+
148
+ /**
149
+ * Extract blocker statements from section content
150
+ * Looks for BLOCKER markers used by agents
151
+ */
152
+ function extractBlockers(content) {
153
+ const blockers = [];
154
+ const lines = content.split('\n');
155
+
156
+ for (const line of lines) {
157
+ if (line.includes('🛑') || line.includes('BLOCKER') || line.match(/\*\*BLOCKER/i)) {
158
+ // Extract the description after the marker
159
+ const cleaned = line
160
+ .replace(/[🛑*]/g, '')
161
+ .replace(/BLOCKER\s*—?\s*/i, '')
162
+ .trim();
163
+ if (cleaned && cleaned.length > 3) {
164
+ blockers.push(cleaned);
165
+ }
166
+ }
167
+ }
168
+
169
+ return blockers;
170
+ }
171
+
172
+ /**
173
+ * Extract warning statements from section content
174
+ */
175
+ function extractWarnings(content) {
176
+ const warnings = [];
177
+ const lines = content.split('\n');
178
+
179
+ for (const line of lines) {
180
+ if (line.includes('⚠️') || line.match(/\*\*WARNING/i)) {
181
+ const cleaned = line
182
+ .replace(/[⚠️*]/g, '')
183
+ .replace(/WARNING\s*—?\s*/i, '')
184
+ .trim();
185
+ if (cleaned && cleaned.length > 3) {
186
+ warnings.push(cleaned);
187
+ }
188
+ }
189
+ }
190
+
191
+ return warnings;
192
+ }
193
+
194
+ /**
195
+ * Parse consensus section for Go/No-Go status
196
+ */
197
+ function parseConsensus(sections) {
198
+ const consensusSection = sections.find(s => s.agent === 'consensus');
199
+
200
+ if (!consensusSection) {
201
+ return { status: 'open', goNoGo: 'GO', rationale: 'No consensus section yet' };
202
+ }
203
+
204
+ const content = consensusSection.content;
205
+
206
+ // Extract Go/No-Go
207
+ let goNoGo = 'GO';
208
+ if (content.match(/NO-GO/i)) goNoGo = 'NO-GO';
209
+ else if (content.match(/HUMAN-NEEDED/i)) goNoGo = 'HUMAN-NEEDED';
210
+ else if (content.match(/^.*GO.*$/m)) goNoGo = 'GO';
211
+
212
+ // Extract status
213
+ let status = 'open';
214
+ if (content.match(/consensus-reached/i) || goNoGo !== 'open') status = 'consensus-reached';
215
+ if (goNoGo === 'HUMAN-NEEDED') status = 'needs-human';
216
+
217
+ // Extract rationale
218
+ const rationaleMatch = content.match(/### Rationale\n([^\n]+)/);
219
+ const rationale = rationaleMatch ? rationaleMatch[1].trim() : '';
220
+
221
+ return { status, goNoGo, rationale };
222
+ }
223
+
224
+ // ─────────────────────────────────────────────
225
+ // Synthesis
226
+ // ─────────────────────────────────────────────
227
+
228
+ /**
229
+ * Synthesize discussion into orchestrator-ready decision
230
+ * @param {string} discussionPath - Path to DISCUSSION.md
231
+ * @returns {{ proceed: boolean, reason: string, blockers: object[], warnings: object[], score: object }}
232
+ */
233
+ function synthesize(discussionPath) {
234
+ const discussion = parseDiscussion(discussionPath);
235
+
236
+ if (!discussion.found) {
237
+ return {
238
+ proceed: true,
239
+ reason: 'No discussion file — no pre-flight concerns',
240
+ blockers: [],
241
+ warnings: [],
242
+ agentsParticipated: []
243
+ };
244
+ }
245
+
246
+ const hasBlockers = discussion.blockers.length > 0;
247
+ const consensusGoNoGo = discussion.consensus.goNoGo;
248
+
249
+ // Determine whether to proceed
250
+ let proceed = true;
251
+ let reason = '';
252
+
253
+ if (hasBlockers || consensusGoNoGo === 'NO-GO') {
254
+ proceed = false;
255
+ reason = hasBlockers
256
+ ? `${discussion.blockers.length} blocker(s) must be resolved before execution`
257
+ : 'Consensus is NO-GO';
258
+ } else if (consensusGoNoGo === 'HUMAN-NEEDED') {
259
+ proceed = false;
260
+ reason = 'Human input required before proceeding';
261
+ } else {
262
+ proceed = true;
263
+ reason = discussion.warnings.length > 0
264
+ ? `${discussion.warnings.length} warning(s) — proceeding with awareness`
265
+ : 'No blockers found — proceeding';
266
+ }
267
+
268
+ const agentsParticipated = discussion.sections
269
+ .filter(s => s.agent !== 'consensus')
270
+ .filter(s => !s.content.includes('{Populated') && s.content.trim().length > 20)
271
+ .map(s => s.agent);
272
+
273
+ return {
274
+ proceed,
275
+ reason,
276
+ blockers: discussion.blockers,
277
+ warnings: discussion.warnings,
278
+ consensus: discussion.consensus,
279
+ agentsParticipated,
280
+ frontmatter: discussion.frontmatter
281
+ };
282
+ }
283
+
284
+ /**
285
+ * Check if a discussion file needs updating (agents haven't written yet)
286
+ * @param {string} discussionPath
287
+ * @returns {{ needsObserver: boolean, needsTechLead: boolean, needsScrumMaster: boolean }}
288
+ */
289
+ function checkParticipation(discussionPath) {
290
+ const discussion = parseDiscussion(discussionPath);
291
+
292
+ if (!discussion.found) {
293
+ return { needsObserver: true, needsTechLead: true, needsScrumMaster: true };
294
+ }
295
+
296
+ const populated = (agent) => {
297
+ const section = discussion.sections.find(s => s.agent === agent);
298
+ return section && !section.content.includes('{Populated') && section.content.trim().length > 20;
299
+ };
300
+
301
+ return {
302
+ needsObserver: !populated('observer'),
303
+ needsTechLead: !populated('tech-lead'),
304
+ needsScrumMaster: !populated('scrum-master'),
305
+ needsRequirements: !populated('requirements')
306
+ };
307
+ }
308
+
309
+ /**
310
+ * Update consensus section in DISCUSSION.md
311
+ * @param {string} discussionPath
312
+ * @param {object} consensusData - { goNoGo, blockers, warnings, rationale }
313
+ */
314
+ async function updateConsensus(discussionPath, consensusData) {
315
+ if (!fs.existsSync(discussionPath)) return false;
316
+ return withLock(discussionPath, async () => {
317
+ const content = fs.readFileSync(discussionPath, 'utf8');
318
+
319
+ const blockerList = consensusData.blockers.length > 0
320
+ ? consensusData.blockers.map(b => `- 🛑 ${b.agent}: ${b.text}`).join('\n')
321
+ : 'None';
322
+
323
+ const warningList = consensusData.warnings.length > 0
324
+ ? consensusData.warnings.slice(0, 5).map(w => `- ⚠️ ${w.agent}: ${w.text}`).join('\n')
325
+ : 'None';
326
+
327
+ const now = new Date().toISOString();
328
+ const status = consensusData.goNoGo === 'GO'
329
+ ? 'consensus-reached'
330
+ : consensusData.goNoGo === 'HUMAN-NEEDED' ? 'needs-human' : 'consensus-reached';
331
+
332
+ const consensusSection = `## Consensus
333
+
334
+ > *Synthesized by orchestrator from above perspectives*
335
+
336
+ **Status:** ${status}
337
+
338
+ ### Blockers
339
+ ${blockerList}
340
+
341
+ ### Key Warnings
342
+ ${warningList}
343
+
344
+ ### Go / No-Go
345
+ ${consensusData.goNoGo} — ${consensusData.rationale}
346
+
347
+ ### Rationale
348
+ ${consensusData.rationale}
349
+
350
+ ---
351
+
352
+ *Discussion opened: {timestamp}*
353
+ *Last updated: ${now}*`;
354
+
355
+ // Replace existing consensus section or append
356
+ let updated;
357
+ if (content.includes('## Consensus')) {
358
+ updated = content.replace(/## Consensus[\s\S]*$/, consensusSection);
359
+ } else {
360
+ updated = content + '\n\n' + consensusSection;
361
+ }
362
+
363
+ // Also update frontmatter status
364
+ updated = updated.replace(/^status: .*$/m, `status: ${status}`);
365
+
366
+ fs.writeFileSync(discussionPath, updated, 'utf8');
367
+ return true;
368
+ });
369
+ }
370
+
371
+ /**
372
+ * Format synthesis result as human-readable text
373
+ * @param {object} result - From synthesize()
374
+ * @returns {string}
375
+ */
376
+ function formatSynthesis(result) {
377
+ const lines = [];
378
+
379
+ lines.push(`## Pre-Flight Discussion Summary`);
380
+ lines.push(`**Decision:** ${result.proceed ? '✓ GO — proceed to execution' : '✗ ' + (result.consensus && result.consensus.goNoGo === 'HUMAN-NEEDED' ? 'HUMAN-NEEDED' : 'NO-GO')}`);
381
+ lines.push(`**Reason:** ${result.reason}`);
382
+ lines.push(`**Agents participated:** ${result.agentsParticipated.join(', ') || 'none'}`);
383
+
384
+ if (result.blockers.length > 0) {
385
+ lines.push('');
386
+ lines.push('### Blockers (must resolve)');
387
+ for (const b of result.blockers) {
388
+ lines.push(`- 🛑 **${b.agent}:** ${b.text}`);
389
+ }
390
+ }
391
+
392
+ if (result.warnings.length > 0) {
393
+ lines.push('');
394
+ lines.push('### Warnings (advisory)');
395
+ for (const w of result.warnings.slice(0, 5)) {
396
+ lines.push(`- ⚠️ **${w.agent}:** ${w.text}`);
397
+ }
398
+ }
399
+
400
+ return lines.join('\n');
401
+ }
402
+
403
+ // ─────────────────────────────────────────────
404
+ // CLI Interface
405
+ // ─────────────────────────────────────────────
406
+
407
+ if (require.main === module) {
408
+ const args = process.argv.slice(2);
409
+ const cmd = args[0];
410
+ const discussionPath = args[1];
411
+
412
+ if (!cmd) {
413
+ console.error('Usage: discussion-synthesizer.cjs <synthesize|check-participation|update-consensus> <path> [options]');
414
+ process.exit(1);
415
+ }
416
+
417
+ (async () => {
418
+ try {
419
+ if (cmd === 'synthesize') {
420
+ if (!discussionPath) { console.error('Path required'); process.exit(1); }
421
+ const result = synthesize(discussionPath);
422
+ if (args.includes('--json')) {
423
+ console.log(JSON.stringify(result, null, 2));
424
+ } else {
425
+ console.log(formatSynthesis(result));
426
+ process.exit(result.proceed ? 0 : 1);
427
+ }
428
+ } else if (cmd === 'check-participation') {
429
+ if (!discussionPath) { console.error('Path required'); process.exit(1); }
430
+ const result = checkParticipation(discussionPath);
431
+ console.log(JSON.stringify(result, null, 2));
432
+ } else if (cmd === 'update-consensus') {
433
+ if (!discussionPath) { console.error('Path required'); process.exit(1); }
434
+ const dataArg = args[2];
435
+ if (!dataArg) { console.error('Consensus data JSON required'); process.exit(1); }
436
+ const data = JSON.parse(dataArg);
437
+ const ok = await updateConsensus(discussionPath, data);
438
+ console.log(JSON.stringify({ updated: ok }));
439
+ } else {
440
+ console.error(`Unknown command: ${cmd}`);
441
+ process.exit(1);
442
+ }
443
+ } catch (err) {
444
+ console.error(`Error: ${err.message}`);
445
+ process.exit(1);
446
+ }
447
+ })();
448
+ }
449
+
450
+ module.exports = {
451
+ parseDiscussion,
452
+ synthesize,
453
+ checkParticipation,
454
+ updateConsensus,
455
+ formatSynthesis,
456
+ extractBlockers,
457
+ extractWarnings
458
+ };
@@ -0,0 +1,207 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * File Access Service
5
+ *
6
+ * Provides file reading capabilities with glob pattern support.
7
+ * Uses micromatch for glob matching with support for negation and brace expansion.
8
+ */
9
+
10
+ const fs = require('fs');
11
+ const path = require('path');
12
+ const micromatch = require('micromatch');
13
+ const { FileAccessError } = require('./context-errors.cjs');
14
+
15
+ const MAX_FILE_COUNT = 1000;
16
+
17
+ class FileAccessService {
18
+ /**
19
+ * Create a new FileAccessService instance
20
+ * @param {string} cwd - Current working directory (defaults to process.cwd())
21
+ */
22
+ constructor(cwd) {
23
+ this.cwd = cwd || process.cwd();
24
+ }
25
+
26
+ /**
27
+ * Read files matching patterns
28
+ * @param {string|string[]} patterns - File patterns (glob or single path)
29
+ * @returns {Array<{path: string, content: string}>} - Array of file objects
30
+ * @throws {FileAccessError} - On file access errors
31
+ */
32
+ readFiles(patterns) {
33
+ const patternArray = Array.isArray(patterns) ? patterns : [patterns];
34
+
35
+ // Get all files recursively
36
+ const allFiles = this._getAllFiles(this.cwd);
37
+
38
+ // Convert paths to relative paths from cwd
39
+ const relativeFiles = allFiles.map(f => {
40
+ const relPath = path.relative(this.cwd, f);
41
+ // Convert to POSIX style paths for glob matching
42
+ return relPath.replace(/\\/g, '/');
43
+ });
44
+
45
+ // Filter with micromatch
46
+ const matchedFiles = micromatch.match(relativeFiles, patternArray, {
47
+ dot: false, // Don't match hidden files/directories by default
48
+ nocase: false
49
+ });
50
+
51
+ // Check max file count
52
+ if (matchedFiles.length > MAX_FILE_COUNT) {
53
+ throw new FileAccessError(
54
+ matchedFiles[0],
55
+ `Max file count exceeded: ${matchedFiles.length} > ${MAX_FILE_COUNT}`
56
+ );
57
+ }
58
+
59
+ // Read file contents
60
+ const results = matchedFiles.map(filePath => {
61
+ const fullPath = path.join(this.cwd, filePath);
62
+
63
+ if (!fs.existsSync(fullPath)) {
64
+ throw new FileAccessError(filePath, 'File not found');
65
+ }
66
+
67
+ try {
68
+ const content = fs.readFileSync(fullPath, 'utf-8');
69
+ return {
70
+ path: filePath,
71
+ content
72
+ };
73
+ } catch (err) {
74
+ if (err.code === 'EACCES') {
75
+ throw new FileAccessError(filePath, 'Permission denied');
76
+ }
77
+ throw new FileAccessError(filePath, err.message);
78
+ }
79
+ });
80
+
81
+ return results;
82
+ }
83
+
84
+ /**
85
+ * Get all files recursively from a directory
86
+ * @param {string} dir - Directory to scan
87
+ * @returns {string[]} - Array of file paths
88
+ * @private
89
+ */
90
+ _getAllFiles(dir) {
91
+ const files = [];
92
+
93
+ try {
94
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
95
+
96
+ for (const entry of entries) {
97
+ const fullPath = path.join(dir, entry.name);
98
+
99
+ // Skip hidden directories (starting with .)
100
+ if (entry.isDirectory() && !entry.name.startsWith('.')) {
101
+ const subFiles = this._getAllFiles(fullPath);
102
+ files.push(...subFiles);
103
+ } else if (entry.isFile()) {
104
+ files.push(fullPath);
105
+ }
106
+ }
107
+ } catch (err) {
108
+ // Ignore permission errors during directory traversal
109
+ if (err.code !== 'EACCES') {
110
+ throw err;
111
+ }
112
+ }
113
+
114
+ return files;
115
+ }
116
+
117
+ /**
118
+ * Normalize a file path (convert Windows paths to Unix style)
119
+ * @param {string} filePath - The path to normalize
120
+ * @returns {string} - Normalized path
121
+ * @throws {FileAccessError} - On path traversal attempts
122
+ */
123
+ normalizePath(filePath) {
124
+ // Convert Windows backslashes to forward slashes
125
+ const normalized = filePath.replace(/\\/g, '/');
126
+
127
+ // Check for path traversal attempts
128
+ if (normalized.includes('..')) {
129
+ throw new FileAccessError(filePath, 'Path traversal not allowed');
130
+ }
131
+
132
+ return normalized;
133
+ }
134
+
135
+ /**
136
+ * Validate a file path
137
+ * @param {string} filePath - The path to validate
138
+ * @returns {boolean} - True if valid
139
+ */
140
+ validatePath(filePath) {
141
+ // Reject paths with null bytes
142
+ if (filePath.includes('\x00')) {
143
+ return false;
144
+ }
145
+
146
+ // Resolve the path
147
+ const resolvedPath = path.resolve(this.cwd, filePath);
148
+
149
+ // Check if path is within cwd (prevent access outside project)
150
+ const normalizedCwd = path.resolve(this.cwd).replace(/\\/g, '/');
151
+ const normalizedResolved = resolvedPath.replace(/\\/g, '/');
152
+
153
+ // Path must be within or equal to cwd
154
+ if (!normalizedResolved.startsWith(normalizedCwd)) {
155
+ return false;
156
+ }
157
+
158
+ return true;
159
+ }
160
+
161
+ /**
162
+ * Check if a file exists
163
+ * @param {string} filePath - Path to check
164
+ * @returns {boolean} - True if file exists
165
+ */
166
+ fileExists(filePath) {
167
+ const fullPath = path.join(this.cwd, filePath);
168
+ return fs.existsSync(fullPath);
169
+ }
170
+
171
+ /**
172
+ * Read a single file
173
+ * @param {string} filePath - Path to the file
174
+ * @returns {{path: string, content: string}} - File object
175
+ * @throws {FileAccessError} - On file access errors
176
+ */
177
+ readFile(filePath) {
178
+ const results = this.readFiles([filePath]);
179
+ return results[0] || null;
180
+ }
181
+
182
+ /**
183
+ * Get file info (size, modified time, etc.)
184
+ * @param {string} filePath - Path to the file
185
+ * @returns {{path: string, size: number, mtime: Date}} - File info
186
+ * @throws {FileAccessError} - On file access errors
187
+ */
188
+ getFileInfo(filePath) {
189
+ const fullPath = path.join(this.cwd, filePath);
190
+
191
+ if (!fs.existsSync(fullPath)) {
192
+ throw new FileAccessError(filePath, 'File not found');
193
+ }
194
+
195
+ const stats = fs.statSync(fullPath);
196
+
197
+ return {
198
+ path: filePath,
199
+ size: stats.size,
200
+ mtime: stats.mtime,
201
+ isDirectory: stats.isDirectory(),
202
+ isFile: stats.isFile()
203
+ };
204
+ }
205
+ }
206
+
207
+ module.exports = FileAccessService;