@howlil/ez-agents 3.5.0 → 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 (382) hide show
  1. package/README.md +735 -537
  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 -333
  18. package/agents/ez-requirements-agent.md +377 -377
  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/lib/analytics/analytics-collector.cjs +86 -0
  30. package/bin/lib/analytics/analytics-reporter.cjs +130 -0
  31. package/bin/lib/analytics/cohort-analyzer.cjs +138 -0
  32. package/bin/lib/analytics/funnel-analyzer.cjs +147 -0
  33. package/bin/lib/analytics/nps-tracker.cjs +147 -0
  34. package/bin/lib/archetype-detector.cjs +289 -0
  35. package/bin/lib/assistant-adapter.cjs +361 -0
  36. package/bin/lib/audit-exec.cjs +175 -0
  37. package/bin/lib/auth.cjs +176 -0
  38. package/bin/lib/backup-service.cjs +422 -0
  39. package/bin/lib/bdd-validator.cjs +622 -0
  40. package/bin/lib/business-flow-mapper.cjs +429 -0
  41. package/bin/lib/circuit-breaker.cjs +276 -0
  42. package/bin/lib/code-complexity-analyzer.cjs +360 -0
  43. package/bin/lib/codebase-analyzer.cjs +241 -0
  44. package/bin/lib/commands.cjs +691 -0
  45. package/bin/lib/config.cjs +236 -0
  46. package/bin/lib/constraint-extractor.cjs +526 -0
  47. package/bin/lib/content-scanner.cjs +238 -0
  48. package/bin/lib/context-cache.cjs +154 -0
  49. package/bin/lib/context-compressor.cjs +102 -0
  50. package/bin/lib/context-deduplicator.cjs +105 -0
  51. package/bin/lib/context-errors.cjs +78 -0
  52. package/bin/lib/context-manager.cjs +338 -0
  53. package/bin/lib/context-metadata-tracker.cjs +140 -0
  54. package/bin/lib/context-relevance-scorer.cjs +99 -0
  55. package/bin/lib/core.cjs +507 -0
  56. package/bin/lib/cost-alerts.cjs +174 -0
  57. package/bin/lib/cost-tracker.cjs +275 -0
  58. package/bin/lib/crash-recovery.cjs +220 -0
  59. package/bin/lib/dependency-graph.cjs +319 -0
  60. package/bin/lib/deploy/deploy-audit-log.cjs +76 -0
  61. package/bin/lib/deploy/deploy-detector.cjs +69 -0
  62. package/bin/lib/deploy/deploy-env-manager.cjs +109 -0
  63. package/bin/lib/deploy/deploy-health-check.cjs +88 -0
  64. package/bin/lib/deploy/deploy-pre-flight.cjs +57 -0
  65. package/bin/lib/deploy/deploy-rollback.cjs +72 -0
  66. package/bin/lib/deploy/deploy-runner.cjs +97 -0
  67. package/bin/lib/deploy/deploy-status.cjs +74 -0
  68. package/bin/lib/discussion-synthesizer.cjs +439 -0
  69. package/bin/lib/error-cache.cjs +114 -0
  70. package/bin/lib/error-registry.cjs +177 -0
  71. package/bin/lib/file-access.cjs +207 -0
  72. package/bin/lib/file-lock.cjs +236 -0
  73. package/bin/lib/finops/budget-enforcer.cjs +126 -0
  74. package/bin/lib/finops/cost-reporter.cjs +132 -0
  75. package/bin/lib/finops/finops-analyzer.cjs +112 -0
  76. package/bin/lib/finops/spot-manager.cjs +118 -0
  77. package/bin/lib/framework-detector.cjs +396 -0
  78. package/bin/lib/frontmatter.cjs +313 -0
  79. package/bin/lib/fs-utils.cjs +153 -0
  80. package/bin/lib/gate-executor.cjs +272 -0
  81. package/bin/lib/gates/README.md +374 -0
  82. package/bin/lib/gates/gate-01-requirement.cjs +303 -0
  83. package/bin/lib/gates/gate-02-architecture.cjs +555 -0
  84. package/bin/lib/gates/gate-03-code.cjs +635 -0
  85. package/bin/lib/gates/gate-04-security.cjs +829 -0
  86. package/bin/lib/git-errors.cjs +83 -0
  87. package/bin/lib/git-utils.cjs +321 -0
  88. package/bin/lib/git-workflow-engine.cjs +1157 -0
  89. package/bin/lib/health-check.cjs +227 -0
  90. package/bin/lib/index.cjs +279 -0
  91. package/bin/lib/init.cjs +725 -0
  92. package/bin/lib/lock-logger.cjs +194 -0
  93. package/bin/lib/lock-state.cjs +263 -0
  94. package/bin/lib/lockfile-validator.cjs +227 -0
  95. package/bin/lib/log-rotation.cjs +71 -0
  96. package/bin/lib/logger.cjs +125 -0
  97. package/bin/lib/memory-compression.cjs +256 -0
  98. package/bin/lib/milestone.cjs +247 -0
  99. package/bin/lib/model-provider.cjs +241 -0
  100. package/bin/lib/package-manager-detector.cjs +203 -0
  101. package/bin/lib/package-manager-executor.cjs +385 -0
  102. package/bin/lib/package-manager-service.cjs +216 -0
  103. package/bin/lib/perf/api-monitor.cjs +88 -0
  104. package/bin/lib/perf/db-optimizer.cjs +78 -0
  105. package/bin/lib/perf/frontend-performance.cjs +56 -0
  106. package/bin/lib/perf/perf-analyzer.cjs +77 -0
  107. package/bin/lib/perf/perf-baseline.cjs +102 -0
  108. package/bin/lib/perf/perf-reporter.cjs +117 -0
  109. package/bin/lib/perf/regression-detector.cjs +92 -0
  110. package/bin/lib/phase.cjs +963 -0
  111. package/bin/lib/planning-write.cjs +123 -0
  112. package/bin/lib/project-reporter.cjs +565 -0
  113. package/bin/lib/quality-gate.cjs +332 -0
  114. package/bin/lib/quality-metrics.cjs +324 -0
  115. package/bin/lib/recovery-manager.cjs +98 -0
  116. package/bin/lib/release-validator.cjs +617 -0
  117. package/bin/lib/retry.cjs +119 -0
  118. package/bin/lib/roadmap.cjs +309 -0
  119. package/bin/lib/safe-exec.cjs +173 -0
  120. package/bin/lib/safe-path.cjs +130 -0
  121. package/bin/lib/security-errors.cjs +62 -0
  122. package/bin/lib/session-chain.cjs +304 -0
  123. package/bin/lib/session-errors.cjs +81 -0
  124. package/bin/lib/session-export.cjs +251 -0
  125. package/bin/lib/session-import.cjs +262 -0
  126. package/bin/lib/session-manager.cjs +280 -0
  127. package/bin/lib/skill-context.cjs +148 -0
  128. package/bin/lib/skill-matcher.cjs +236 -0
  129. package/bin/lib/skill-registry.cjs +360 -0
  130. package/bin/lib/skill-resolver.cjs +449 -0
  131. package/bin/lib/skill-triggers.cjs +90 -0
  132. package/bin/lib/skill-validator.cjs +270 -0
  133. package/bin/lib/skill-versioning.cjs +355 -0
  134. package/bin/lib/stack-detector.cjs +399 -0
  135. package/bin/lib/state.cjs +736 -0
  136. package/bin/lib/tech-debt-analyzer.cjs +309 -0
  137. package/bin/lib/temp-file.cjs +239 -0
  138. package/bin/lib/template.cjs +223 -0
  139. package/bin/lib/test-file-lock.cjs +112 -0
  140. package/bin/lib/test-graceful.cjs +93 -0
  141. package/bin/lib/test-logger.cjs +60 -0
  142. package/bin/lib/test-safe-exec.cjs +38 -0
  143. package/bin/lib/test-safe-path.cjs +33 -0
  144. package/bin/lib/test-temp-file.cjs +125 -0
  145. package/bin/lib/tier-manager.cjs +428 -0
  146. package/bin/lib/timeout-exec.cjs +63 -0
  147. package/bin/lib/tradeoff-analyzer.cjs +284 -0
  148. package/bin/lib/url-fetch.cjs +170 -0
  149. package/bin/lib/verify.cjs +863 -0
  150. package/bin/update.js +217 -214
  151. package/commands/deploy.cjs +53 -0
  152. package/commands/ez/add-tests.md +41 -41
  153. package/commands/ez/audit-milestone.md +36 -36
  154. package/commands/ez/complete-milestone.md +136 -136
  155. package/commands/ez/discuss-phase.md +90 -90
  156. package/commands/ez/execute-phase.md +52 -52
  157. package/commands/ez/help.md +22 -22
  158. package/commands/ez/map-codebase.md +71 -71
  159. package/commands/ez/new-milestone.md +44 -44
  160. package/commands/ez/new-project.md +51 -42
  161. package/commands/ez/plan-phase.md +53 -53
  162. package/commands/ez/progress.md +36 -36
  163. package/commands/ez/quick.md +45 -45
  164. package/commands/ez/resume-work.md +40 -40
  165. package/commands/ez/run-phase.md +580 -0
  166. package/commands/ez/settings.md +36 -36
  167. package/commands/ez/update.md +37 -37
  168. package/commands/ez/verify-work.md +402 -38
  169. package/commands/health-check.cjs +44 -0
  170. package/commands/rollback.cjs +47 -0
  171. package/ez-agents/bin/ez-tools.cjs +599 -2
  172. package/ez-agents/bin/guards/autonomy-guard.cjs +346 -0
  173. package/ez-agents/bin/guards/context-budget-guard.cjs +247 -0
  174. package/ez-agents/bin/guards/hallucination-guard.cjs +271 -0
  175. package/ez-agents/bin/guards/hidden-state-guard.cjs +182 -0
  176. package/ez-agents/bin/guards/team-overhead-guard.cjs +266 -0
  177. package/ez-agents/bin/guards/tool-sprawl-guard.cjs +271 -0
  178. package/ez-agents/bin/lib/analytics/analytics-collector.cjs +86 -0
  179. package/ez-agents/bin/lib/analytics/analytics-reporter.cjs +130 -0
  180. package/ez-agents/bin/lib/analytics/cohort-analyzer.cjs +138 -0
  181. package/ez-agents/bin/lib/analytics/funnel-analyzer.cjs +147 -0
  182. package/ez-agents/bin/lib/analytics/nps-tracker.cjs +147 -0
  183. package/ez-agents/bin/lib/archetype-detector.cjs +289 -0
  184. package/ez-agents/bin/lib/audit-exec.cjs +166 -167
  185. package/ez-agents/bin/lib/auth.cjs +176 -176
  186. package/ez-agents/bin/lib/backup-service.cjs +422 -0
  187. package/ez-agents/bin/lib/bdd-validator.cjs +622 -622
  188. package/ez-agents/bin/lib/business-flow-mapper.cjs +429 -0
  189. package/ez-agents/bin/lib/code-complexity-analyzer.cjs +360 -0
  190. package/ez-agents/bin/lib/codebase-analyzer.cjs +241 -0
  191. package/ez-agents/bin/lib/commands.cjs +685 -685
  192. package/ez-agents/bin/lib/config.cjs +41 -1
  193. package/ez-agents/bin/lib/constraint-extractor.cjs +526 -0
  194. package/ez-agents/bin/lib/content-scanner.cjs +238 -238
  195. package/ez-agents/bin/lib/context-cache.cjs +154 -154
  196. package/ez-agents/bin/lib/context-errors.cjs +71 -71
  197. package/ez-agents/bin/lib/context-manager.cjs +220 -220
  198. package/ez-agents/bin/lib/core.cjs +507 -512
  199. package/ez-agents/bin/lib/cost-tracker.cjs +243 -0
  200. package/ez-agents/bin/lib/crash-recovery.cjs +172 -0
  201. package/ez-agents/bin/lib/dependency-graph.cjs +319 -0
  202. package/ez-agents/bin/lib/deploy/deploy-audit-log.cjs +76 -0
  203. package/ez-agents/bin/lib/deploy/deploy-detector.cjs +69 -0
  204. package/ez-agents/bin/lib/deploy/deploy-env-manager.cjs +109 -0
  205. package/ez-agents/bin/lib/deploy/deploy-health-check.cjs +88 -0
  206. package/ez-agents/bin/lib/deploy/deploy-pre-flight.cjs +57 -0
  207. package/ez-agents/bin/lib/deploy/deploy-rollback.cjs +72 -0
  208. package/ez-agents/bin/lib/deploy/deploy-runner.cjs +97 -0
  209. package/ez-agents/bin/lib/deploy/deploy-status.cjs +74 -0
  210. package/ez-agents/bin/lib/file-access.cjs +207 -207
  211. package/ez-agents/bin/lib/finops/budget-enforcer.cjs +126 -0
  212. package/ez-agents/bin/lib/finops/cost-reporter.cjs +132 -0
  213. package/ez-agents/bin/lib/finops/finops-analyzer.cjs +112 -0
  214. package/ez-agents/bin/lib/finops/spot-manager.cjs +118 -0
  215. package/ez-agents/bin/lib/framework-detector.cjs +396 -0
  216. package/ez-agents/bin/lib/frontmatter.cjs +3 -1
  217. package/ez-agents/bin/lib/gates/README.md +374 -0
  218. package/ez-agents/bin/lib/gates/gate-01-requirement.cjs +303 -0
  219. package/ez-agents/bin/lib/gates/gate-02-architecture.cjs +555 -0
  220. package/ez-agents/bin/lib/gates/gate-03-code.cjs +635 -0
  221. package/ez-agents/bin/lib/gates/gate-04-security.cjs +829 -0
  222. package/ez-agents/bin/lib/git-errors.cjs +83 -83
  223. package/ez-agents/bin/lib/git-utils.cjs +321 -321
  224. package/ez-agents/bin/lib/git-workflow-engine.cjs +1157 -1157
  225. package/ez-agents/bin/lib/health-check.cjs +162 -162
  226. package/ez-agents/bin/lib/index.cjs +2 -8
  227. package/ez-agents/bin/lib/init.cjs +0 -2
  228. package/ez-agents/bin/lib/lockfile-validator.cjs +227 -227
  229. package/ez-agents/bin/lib/log-rotation.cjs +71 -0
  230. package/ez-agents/bin/lib/logger.cjs +22 -47
  231. package/ez-agents/bin/lib/memory-compression.cjs +256 -256
  232. package/ez-agents/bin/lib/package-manager-detector.cjs +203 -203
  233. package/ez-agents/bin/lib/package-manager-executor.cjs +385 -385
  234. package/ez-agents/bin/lib/package-manager-service.cjs +216 -216
  235. package/ez-agents/bin/lib/perf/api-monitor.cjs +88 -0
  236. package/ez-agents/bin/lib/perf/db-optimizer.cjs +78 -0
  237. package/ez-agents/bin/lib/perf/frontend-performance.cjs +56 -0
  238. package/ez-agents/bin/lib/perf/perf-analyzer.cjs +77 -0
  239. package/ez-agents/bin/lib/perf/perf-baseline.cjs +102 -0
  240. package/ez-agents/bin/lib/perf/perf-reporter.cjs +117 -0
  241. package/ez-agents/bin/lib/perf/regression-detector.cjs +92 -0
  242. package/ez-agents/bin/lib/project-reporter.cjs +502 -0
  243. package/ez-agents/bin/lib/quality-gate.cjs +332 -0
  244. package/ez-agents/bin/lib/recovery-manager.cjs +98 -0
  245. package/ez-agents/bin/lib/release-validator.cjs +617 -614
  246. package/ez-agents/bin/lib/security-errors.cjs +62 -0
  247. package/ez-agents/bin/lib/session-chain.cjs +304 -304
  248. package/ez-agents/bin/lib/session-errors.cjs +81 -81
  249. package/ez-agents/bin/lib/session-export.cjs +251 -251
  250. package/ez-agents/bin/lib/session-import.cjs +262 -262
  251. package/ez-agents/bin/lib/session-manager.cjs +280 -280
  252. package/ez-agents/bin/lib/skill-context.cjs +148 -0
  253. package/ez-agents/bin/lib/skill-matcher.cjs +236 -0
  254. package/ez-agents/bin/lib/skill-registry.cjs +341 -0
  255. package/ez-agents/bin/lib/skill-resolver.cjs +449 -0
  256. package/ez-agents/bin/lib/skill-triggers.cjs +90 -0
  257. package/ez-agents/bin/lib/skill-validator.cjs +270 -0
  258. package/ez-agents/bin/lib/skill-versioning.cjs +355 -0
  259. package/ez-agents/bin/lib/stack-detector.cjs +399 -0
  260. package/ez-agents/bin/lib/tech-debt-analyzer.cjs +309 -0
  261. package/ez-agents/bin/lib/tier-manager.cjs +428 -428
  262. package/ez-agents/bin/lib/tradeoff-analyzer.cjs +284 -0
  263. package/ez-agents/bin/lib/url-fetch.cjs +170 -170
  264. package/ez-agents/bin/lib/verify.cjs +863 -863
  265. package/ez-agents/references/decimal-phase-calculation.md +65 -65
  266. package/ez-agents/references/git-integration.md +248 -248
  267. package/ez-agents/references/git-planning-commit.md +38 -38
  268. package/ez-agents/references/metrics-schema.md +118 -118
  269. package/ez-agents/references/model-profile-resolution.md +34 -34
  270. package/ez-agents/references/model-profiles.md +93 -93
  271. package/ez-agents/references/phase-argument-parsing.md +61 -61
  272. package/ez-agents/references/planning-config.md +340 -340
  273. package/ez-agents/references/tier-strategy.md +103 -103
  274. package/ez-agents/references/ui-brand.md +160 -160
  275. package/ez-agents/references/verification-patterns.md +612 -612
  276. package/ez-agents/templates/DEBUG.md +164 -164
  277. package/ez-agents/templates/UAT.md +247 -247
  278. package/ez-agents/templates/agent-output-format.md +404 -0
  279. package/ez-agents/templates/bdd-feature.md +173 -173
  280. package/ez-agents/templates/codebase/architecture.md +255 -255
  281. package/ez-agents/templates/codebase/structure.md +285 -285
  282. package/ez-agents/templates/copilot-instructions.md +7 -7
  283. package/ez-agents/templates/debug-subagent-prompt.md +91 -91
  284. package/ez-agents/templates/discovery.md +146 -146
  285. package/ez-agents/templates/discussion.md +68 -68
  286. package/ez-agents/templates/handoff-protocol.md +294 -0
  287. package/ez-agents/templates/incident-runbook.md +205 -205
  288. package/ez-agents/templates/mode-workflow-templates.md +301 -0
  289. package/ez-agents/templates/phase-prompt.md +610 -610
  290. package/ez-agents/templates/planner-subagent-prompt.md +117 -117
  291. package/ez-agents/templates/project.md +184 -184
  292. package/ez-agents/templates/release-checklist.md +136 -133
  293. package/ez-agents/templates/research.md +552 -552
  294. package/ez-agents/templates/rollback-plan.md +201 -201
  295. package/ez-agents/templates/security-user-setup.md +244 -0
  296. package/ez-agents/templates/skill-validation-rules.md +476 -0
  297. package/ez-agents/templates/state.md +180 -176
  298. package/ez-agents/templates/summary-complex.md +59 -59
  299. package/ez-agents/tests/gates/gate-01-02.test.cjs +812 -0
  300. package/ez-agents/tests/gates/gate-03-04.test.cjs +762 -0
  301. package/ez-agents/tests/gates/gate-05-validator.test.cjs +145 -0
  302. package/ez-agents/tests/gates/gate-06-docs-validator.test.cjs +244 -0
  303. package/ez-agents/tests/gates/gate-07-release-validator.test.cjs +219 -0
  304. package/ez-agents/tests/guards/context-budget-guard.test.cjs +145 -0
  305. package/ez-agents/tests/guards/edge-case-guards.test.cjs +238 -0
  306. package/ez-agents/tests/guards/hallucination-guard.test.cjs +124 -0
  307. package/ez-agents/workflows/audit-milestone.md +1 -1
  308. package/ez-agents/workflows/autonomous.md +844 -844
  309. package/ez-agents/workflows/complete-milestone.md +1 -1
  310. package/ez-agents/workflows/discuss-phase.md +1 -1
  311. package/ez-agents/workflows/execute-phase.md +124 -3
  312. package/ez-agents/workflows/help.md +42 -181
  313. package/ez-agents/workflows/hotfix.md +291 -291
  314. package/ez-agents/workflows/new-milestone.md +713 -713
  315. package/ez-agents/workflows/new-project.md +1089 -1107
  316. package/ez-agents/workflows/plan-phase.md +0 -40
  317. package/ez-agents/workflows/release.md +253 -253
  318. package/ez-agents/workflows/resume-session.md +215 -215
  319. package/ez-agents/workflows/run-phase.md +531 -0
  320. package/ez-agents/workflows/settings.md +2 -35
  321. package/hooks/dist/ez-check-update.js +81 -81
  322. package/hooks/dist/ez-context-monitor.js +148 -141
  323. package/hooks/dist/ez-statusline.js +115 -115
  324. package/package.json +78 -71
  325. package/scripts/fix-qwen-installation.js +144 -144
  326. package/agents/ez-integration-checker.md +0 -443
  327. package/agents/ez-nyquist-auditor.md +0 -176
  328. package/agents/ez-observer-agent.md +0 -260
  329. package/agents/ez-plan-checker.md +0 -706
  330. package/agents/ez-research-synthesizer.md +0 -247
  331. package/agents/ez-scrum-master-agent.md +0 -242
  332. package/agents/ez-tech-lead-agent.md +0 -267
  333. package/agents/ez-ui-auditor.md +0 -439
  334. package/agents/ez-ui-checker.md +0 -300
  335. package/agents/ez-ui-researcher.md +0 -353
  336. package/commands/ez/add-phase.md +0 -43
  337. package/commands/ez/add-todo.md +0 -47
  338. package/commands/ez/arch-review.md +0 -102
  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/export-session.md +0 -79
  345. package/commands/ez/gather-requirements.md +0 -117
  346. package/commands/ez/git-workflow.md +0 -72
  347. package/commands/ez/health.md +0 -22
  348. package/commands/ez/hotfix.md +0 -120
  349. package/commands/ez/import-session.md +0 -82
  350. package/commands/ez/insert-phase.md +0 -32
  351. package/commands/ez/join-discord.md +0 -18
  352. package/commands/ez/list-phase-assumptions.md +0 -46
  353. package/commands/ez/list-sessions.md +0 -96
  354. package/commands/ez/package-manager.md +0 -316
  355. package/commands/ez/pause-work.md +0 -38
  356. package/commands/ez/plan-milestone-gaps.md +0 -34
  357. package/commands/ez/preflight.md +0 -79
  358. package/commands/ez/reapply-patches.md +0 -124
  359. package/commands/ez/release.md +0 -153
  360. package/commands/ez/remove-phase.md +0 -31
  361. package/commands/ez/research-phase.md +0 -190
  362. package/commands/ez/resume.md +0 -107
  363. package/commands/ez/set-profile.md +0 -34
  364. package/commands/ez/standup.md +0 -85
  365. package/commands/ez/stats.md +0 -18
  366. package/commands/ez/ui-phase.md +0 -34
  367. package/commands/ez/ui-review.md +0 -32
  368. package/commands/ez/validate-phase.md +0 -35
  369. package/ez-agents/bin/lib/metrics-tracker.cjs +0 -406
  370. package/ez-agents/templates/UI-SPEC.md +0 -100
  371. package/ez-agents/templates/VALIDATION.md +0 -76
  372. package/ez-agents/templates/context.md +0 -352
  373. package/ez-agents/templates/verification-report.md +0 -322
  374. package/ez-agents/workflows/arch-review.md +0 -54
  375. package/ez-agents/workflows/export-session.md +0 -255
  376. package/ez-agents/workflows/gather-requirements.md +0 -206
  377. package/ez-agents/workflows/import-session.md +0 -303
  378. package/ez-agents/workflows/research-phase.md +0 -74
  379. package/ez-agents/workflows/standup.md +0 -64
  380. package/ez-agents/workflows/ui-phase.md +0 -290
  381. package/ez-agents/workflows/ui-review.md +0 -157
  382. package/ez-agents/workflows/validate-phase.md +0 -167
@@ -0,0 +1,1157 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Git Workflow Engine
5
+ *
6
+ * Enterprise-grade Git workflow management with branch hierarchy,
7
+ * validation gates, and automated merging.
8
+ *
9
+ * Branch Hierarchy:
10
+ * main (production) ← develop (staging) ← phase/* ← {feature,fix,docs,refactor}/*
11
+ */
12
+
13
+ const GitUtils = require('./git-utils.cjs');
14
+ const Logger = require('./logger.cjs');
15
+ const {
16
+ GitWorkflowError,
17
+ BranchExistsError,
18
+ BranchNotFoundError,
19
+ MergeConflictError,
20
+ ValidationFailedError
21
+ } = require('./git-errors.cjs');
22
+
23
+ class GitWorkflowEngine {
24
+ constructor(config = {}) {
25
+ this.git = new GitUtils(process.cwd());
26
+ this.logger = new Logger();
27
+ this.config = config;
28
+ this.validationLevels = {
29
+ minimal: ['format', 'lint'],
30
+ standard: ['format', 'lint', 'test'],
31
+ full: ['format', 'lint', 'test', 'security', 'performance']
32
+ };
33
+ }
34
+
35
+ /**
36
+ * Detect branch type from name
37
+ */
38
+ detectBranchType(branchName) {
39
+ const patterns = {
40
+ feature: /^feature\//,
41
+ fix: /^fix\//,
42
+ docs: /^docs\//,
43
+ refactor: /^refactor\//,
44
+ phase: /^phase\//,
45
+ release: /^release\//,
46
+ hotfix: /^hotfix\//
47
+ };
48
+
49
+ for (const [type, pattern] of Object.entries(patterns)) {
50
+ if (pattern.test(branchName)) {
51
+ return type;
52
+ }
53
+ }
54
+ return null;
55
+ }
56
+
57
+ /**
58
+ * Validate branch naming convention
59
+ */
60
+ validateBranchNaming(branchName, type) {
61
+ const patterns = {
62
+ feature: /^feature\/[a-zA-Z0-9\-_]+$/,
63
+ fix: /^fix\/[a-zA-Z0-9\-_]+$/,
64
+ docs: /^docs\/[a-zA-Z0-9\-_]+$/,
65
+ refactor: /^refactor\/[a-zA-Z0-9\-_]+$/,
66
+ phase: /^phase\/\d+-[a-zA-Z0-9\-_]+$/,
67
+ release: /^release\/v\d+\.\d+\.\d+$/,
68
+ hotfix: /^hotfix\/[a-zA-Z0-9\-_]+$/
69
+ };
70
+
71
+ const pattern = patterns[type];
72
+ if (!pattern) {
73
+ throw new ValidationFailedError('branch_type', [`Unknown branch type: ${type}`]);
74
+ }
75
+
76
+ if (!pattern.test(branchName)) {
77
+ throw new ValidationFailedError('branch_naming', [
78
+ `Branch '${branchName}' does not match ${type} pattern: ${pattern}`
79
+ ]);
80
+ }
81
+
82
+ return true;
83
+ }
84
+
85
+ /**
86
+ * Validate merge strategy
87
+ */
88
+ _validateStrategy(strategy) {
89
+ const validStrategies = ['merge', 'squash', 'rebase'];
90
+ if (!validStrategies.includes(strategy)) {
91
+ throw new ValidationFailedError('merge_strategy', [
92
+ `Invalid merge strategy: ${strategy}. Must be one of: ${validStrategies.join(', ')}`
93
+ ]);
94
+ }
95
+ return true;
96
+ }
97
+
98
+ /**
99
+ * Create phase branch from develop
100
+ * PHASE-GIT-01: Auto-create phase branch from develop
101
+ */
102
+ async createPhaseBranch(phaseNumber, phaseSlug) {
103
+ const branchName = `phase/${phaseNumber}-${phaseSlug}`;
104
+
105
+ // Validate naming convention
106
+ this.validateBranchNaming(branchName, 'phase');
107
+
108
+ // Check if branch exists
109
+ if (await this.git.branchExists(branchName)) {
110
+ throw new BranchExistsError(branchName);
111
+ }
112
+
113
+ // Determine source branch (develop or main)
114
+ let sourceBranch = 'develop';
115
+ if (!(await this.git.branchExists('develop'))) {
116
+ this.logger.warn('develop branch not found, using main', { sourceBranch: 'main' });
117
+ sourceBranch = 'main';
118
+ }
119
+
120
+ // Create branch
121
+ await this.git.createBranch(branchName, sourceBranch);
122
+
123
+ this.logger.info('Phase branch created', {
124
+ branch: branchName,
125
+ phaseNumber,
126
+ phaseSlug,
127
+ source: sourceBranch
128
+ });
129
+
130
+ return branchName;
131
+ }
132
+
133
+ /**
134
+ * Create feature/fix/docs/refactor branch
135
+ * PHASE-GIT-02: Auto-create feature/fix/docs/refactor branches within phase
136
+ */
137
+ async createWorkBranch(type, ticketId = null, slug) {
138
+ const validTypes = ['feature', 'fix', 'docs', 'refactor'];
139
+
140
+ if (!validTypes.includes(type)) {
141
+ throw new ValidationFailedError('branch_type', [
142
+ `Invalid branch type: ${type}. Must be one of: ${validTypes.join(', ')}`
143
+ ]);
144
+ }
145
+
146
+ // Build branch name
147
+ let branchName;
148
+ if (ticketId && ['feature', 'fix'].includes(type)) {
149
+ branchName = `${type}/${ticketId}-${slug}`;
150
+ } else {
151
+ branchName = `${type}/${slug}`;
152
+ }
153
+
154
+ // Validate naming convention
155
+ this.validateBranchNaming(branchName, type);
156
+
157
+ // Check if branch exists
158
+ if (await this.git.branchExists(branchName)) {
159
+ throw new BranchExistsError(branchName);
160
+ }
161
+
162
+ // Source from current branch (should be phase branch or develop)
163
+ const sourceBranch = await this.git.getCurrentBranch();
164
+
165
+ // Create branch
166
+ await this.git.createBranch(branchName, sourceBranch);
167
+
168
+ this.logger.info('Work branch created', {
169
+ branch: branchName,
170
+ type,
171
+ ticketId,
172
+ slug,
173
+ source: sourceBranch
174
+ });
175
+
176
+ return branchName;
177
+ }
178
+
179
+ /**
180
+ * Create atomic commit for task completion
181
+ * PHASE-GIT-03: Auto-commit after each task completion
182
+ * PHASE-GIT-04: Commit message format: <type>(scope): <description> [TASK-XX]
183
+ */
184
+ async commitTask(taskDescription, taskId, files = []) {
185
+ // Parse task ID to number for formatting
186
+ const taskNum = parseInt(taskId.replace('TASK-', ''), 10);
187
+ const formattedTaskId = `TASK-${String(taskNum).padStart(2, '0')}`;
188
+
189
+ // Extract commit type from task description
190
+ const typePatterns = {
191
+ feat: /add|implement|create|new|enable/i,
192
+ fix: /fix|resolve|patch|correct/i,
193
+ docs: /document|update docs|readme/i,
194
+ refactor: /refactor|restructure|reorganize/i,
195
+ test: /test|add tests/i,
196
+ chore: /update|configure|setup|clean/i
197
+ };
198
+
199
+ let commitType = 'chore';
200
+ for (const [type, pattern] of Object.entries(typePatterns)) {
201
+ if (pattern.test(taskDescription)) {
202
+ commitType = type;
203
+ break;
204
+ }
205
+ }
206
+
207
+ // Extract scope (optional)
208
+ const scopePattern = /\[([^\]]+)\]/;
209
+ const scopeMatch = taskDescription.match(scopePattern);
210
+ const scope = scopeMatch ? `(${scopeMatch[1]})` : '';
211
+
212
+ // Clean description
213
+ let cleanDescription = taskDescription
214
+ .replace(scopePattern, '')
215
+ .replace(/^(add|implement|create|fix|update|resolve)\s+/i, '')
216
+ .trim();
217
+
218
+ // Build commit message
219
+ const commitMessage = `${commitType}${scope}: ${cleanDescription} [${formattedTaskId}]`;
220
+
221
+ // Create commit
222
+ const commitHash = await this.git.commitAtomic(commitMessage, files);
223
+
224
+ this.logger.info('Task commit created', {
225
+ hash: commitHash,
226
+ message: commitMessage,
227
+ taskId: formattedTaskId
228
+ });
229
+
230
+ return commitHash;
231
+ }
232
+
233
+ /**
234
+ * Validate planning file consistency
235
+ */
236
+ async _validatePlanningFiles() {
237
+ const fs = require('fs');
238
+ const path = require('path');
239
+ const errors = [];
240
+
241
+ // Check STATE.md exists
242
+ const statePath = path.join(process.cwd(), '.planning', 'STATE.md');
243
+ if (!fs.existsSync(statePath)) {
244
+ errors.push('STATE.md not found');
245
+ }
246
+
247
+ // Check STATE.md has required frontmatter
248
+ if (fs.existsSync(statePath)) {
249
+ const stateContent = fs.readFileSync(statePath, 'utf-8');
250
+ if (!stateContent.includes('current_phase:') || !stateContent.includes('status:')) {
251
+ errors.push('STATE.md missing required frontmatter fields');
252
+ }
253
+ }
254
+
255
+ return {
256
+ name: 'planning_consistency',
257
+ passed: errors.length === 0,
258
+ message: errors.length === 0 ? 'Planning files consistent' : errors.join('; ')
259
+ };
260
+ }
261
+
262
+ /**
263
+ * Run format check (Prettier)
264
+ */
265
+ async _runFormatCheck() {
266
+ const { execFile } = require('child_process');
267
+ const { promisify } = require('util');
268
+ const execFileAsync = promisify(execFile);
269
+
270
+ try {
271
+ await execFileAsync('npx', ['prettier', '--check', '.'], { cwd: process.cwd() });
272
+ return { name: 'format', passed: true, message: 'Format check passed' };
273
+ } catch (err) {
274
+ return { name: 'format', passed: false, message: 'Format check failed' };
275
+ }
276
+ }
277
+
278
+ /**
279
+ * Run lint check (ESLint)
280
+ */
281
+ async _runLintCheck() {
282
+ const { execFile } = require('child_process');
283
+ const { promisify } = require('util');
284
+ const execFileAsync = promisify(execFile);
285
+
286
+ try {
287
+ await execFileAsync('npx', ['eslint', '.'], { cwd: process.cwd() });
288
+ return { name: 'lint', passed: true, message: 'Lint check passed' };
289
+ } catch (err) {
290
+ return { name: 'lint', passed: false, message: 'Lint check failed' };
291
+ }
292
+ }
293
+
294
+ /**
295
+ * Run test check
296
+ */
297
+ async _runTestCheck() {
298
+ const { execFile } = require('child_process');
299
+ const { promisify } = require('util');
300
+ const execFileAsync = promisify(execFile);
301
+
302
+ try {
303
+ await execFileAsync('npm', ['test'], { cwd: process.cwd() });
304
+ return { name: 'test', passed: true, message: 'Test check passed' };
305
+ } catch (err) {
306
+ return { name: 'test', passed: false, message: 'Test check failed' };
307
+ }
308
+ }
309
+
310
+ /**
311
+ * Run security check (npm audit)
312
+ */
313
+ async _runSecurityCheck() {
314
+ const { execFile } = require('child_process');
315
+ const { promisify } = require('util');
316
+ const execFileAsync = promisify(execFile);
317
+
318
+ try {
319
+ await execFileAsync('npm', ['audit', '--audit-level=critical'], { cwd: process.cwd() });
320
+ return { name: 'security', passed: true, message: 'Security check passed' };
321
+ } catch (err) {
322
+ return { name: 'security', passed: false, message: 'Security check failed: critical vulnerabilities found' };
323
+ }
324
+ }
325
+
326
+ /**
327
+ * Validate branch before merge
328
+ * PHASE-GIT-05: Validate feature/fix branches before merge to phase
329
+ */
330
+ async validateBeforeMerge(branch, validationLevel = 'standard') {
331
+ const currentBranch = await this.git.getCurrentBranch();
332
+ const checks = [];
333
+ let passed = true;
334
+
335
+ try {
336
+ // Switch to branch for validation
337
+ await this.git.checkout(branch);
338
+
339
+ // Get validation checks based on level
340
+ const requiredChecks = this.validationLevels[validationLevel] || this.validationLevels.standard;
341
+
342
+ // Planning file consistency check (always run)
343
+ const planningCheck = await this._validatePlanningFiles();
344
+ checks.push(planningCheck);
345
+ if (!planningCheck.passed) passed = false;
346
+
347
+ // Format check
348
+ if (requiredChecks.includes('format')) {
349
+ const formatCheck = await this._runFormatCheck();
350
+ checks.push(formatCheck);
351
+ if (!formatCheck.passed) passed = false;
352
+ }
353
+
354
+ // Lint check
355
+ if (requiredChecks.includes('lint')) {
356
+ const lintCheck = await this._runLintCheck();
357
+ checks.push(lintCheck);
358
+ if (!lintCheck.passed) passed = false;
359
+ }
360
+
361
+ // Test check
362
+ if (requiredChecks.includes('test')) {
363
+ const testCheck = await this._runTestCheck();
364
+ checks.push(testCheck);
365
+ if (!testCheck.passed) passed = false;
366
+ }
367
+
368
+ // Security check (full level only)
369
+ if (requiredChecks.includes('security')) {
370
+ const securityCheck = await this._runSecurityCheck();
371
+ checks.push(securityCheck);
372
+ if (!securityCheck.passed) passed = false;
373
+ }
374
+
375
+ const result = {
376
+ branch,
377
+ validationLevel,
378
+ passed,
379
+ checks,
380
+ timestamp: new Date().toISOString()
381
+ };
382
+
383
+ this.logger.info('Validation completed', result);
384
+
385
+ if (!passed) {
386
+ throw new ValidationFailedError('pre_merge', checks.filter(c => !c.passed).map(c => c.message));
387
+ }
388
+
389
+ return result;
390
+ } finally {
391
+ // Restore original branch
392
+ if (currentBranch !== branch) {
393
+ await this.git.checkout(currentBranch);
394
+ }
395
+ }
396
+ }
397
+
398
+ /**
399
+ * Merge feature/fix branch to phase branch
400
+ * PHASE-GIT-06: Auto-merge feature/fix branches to phase branch after validation
401
+ */
402
+ async mergeToPhase(featureBranch, phaseBranch) {
403
+ const branchType = this.detectBranchType(featureBranch);
404
+ const strategy = this.config.git?.merge_strategies?.[branchType] || 'squash';
405
+
406
+ this.logger.info('Merging to phase', {
407
+ source: featureBranch,
408
+ target: phaseBranch,
409
+ strategy
410
+ });
411
+
412
+ // Validate before merge
413
+ await this.validateBeforeMerge(featureBranch, 'standard');
414
+
415
+ // Check for conflicts
416
+ const hasConflicts = await this.git.hasConflicts(featureBranch, phaseBranch);
417
+ if (hasConflicts) {
418
+ throw new MergeConflictError(featureBranch, phaseBranch);
419
+ }
420
+
421
+ // Perform merge
422
+ await this.git.mergeWithStrategy(featureBranch, phaseBranch, strategy);
423
+
424
+ this.logger.info('Merge to phase completed', {
425
+ source: featureBranch,
426
+ target: phaseBranch
427
+ });
428
+
429
+ return { success: true, source: featureBranch, target: phaseBranch };
430
+ }
431
+
432
+ /**
433
+ * Merge phase branch to develop
434
+ * PHASE-GIT-08: Auto-merge phase branch to develop after validation
435
+ */
436
+ async mergePhaseToDevelop(phaseBranch) {
437
+ const strategy = this.config.git?.merge_strategies?.phase || 'merge';
438
+ const targetBranch = 'develop';
439
+
440
+ this.logger.info('Merging phase to develop', {
441
+ source: phaseBranch,
442
+ target: targetBranch,
443
+ strategy
444
+ });
445
+
446
+ // Validate before merge
447
+ await this.validateBeforeMerge(phaseBranch, 'full');
448
+
449
+ // Check for conflicts
450
+ const hasConflicts = await this.git.hasConflicts(phaseBranch, targetBranch);
451
+ if (hasConflicts) {
452
+ throw new MergeConflictError(phaseBranch, targetBranch);
453
+ }
454
+
455
+ // Perform merge
456
+ await this.git.mergeWithStrategy(phaseBranch, targetBranch, strategy);
457
+
458
+ this.logger.info('Phase merge to develop completed', {
459
+ source: phaseBranch,
460
+ target: targetBranch
461
+ });
462
+
463
+ return { success: true, source: phaseBranch, target: targetBranch };
464
+ }
465
+
466
+ /**
467
+ * Create release branch from develop
468
+ * PHASE-GIT-09: Create release branch from develop for stabilization
469
+ */
470
+ async createReleaseBranch(version) {
471
+ const semver = require('semver');
472
+
473
+ // Validate version format
474
+ const validVersion = semver.valid(version);
475
+ if (!validVersion) {
476
+ throw new ValidationFailedError('version_format', [
477
+ `Invalid version format: ${version}. Must be valid semver (e.g., 2.0.0)`
478
+ ]);
479
+ }
480
+
481
+ const branchName = `release/v${validVersion}`;
482
+
483
+ // Check if branch exists
484
+ if (await this.git.branchExists(branchName)) {
485
+ throw new BranchExistsError(branchName);
486
+ }
487
+
488
+ // Source from develop
489
+ if (!(await this.git.branchExists('develop'))) {
490
+ throw new BranchNotFoundError('develop');
491
+ }
492
+
493
+ // Create branch
494
+ await this.git.createBranch(branchName, 'develop');
495
+
496
+ this.logger.info('Release branch created', {
497
+ branch: branchName,
498
+ version: validVersion
499
+ });
500
+
501
+ return branchName;
502
+ }
503
+
504
+ /**
505
+ * Run integration tests
506
+ */
507
+ async _runIntegrationTestCheck() {
508
+ const { execFile } = require('child_process');
509
+ const { promisify } = require('util');
510
+ const execFileAsync = promisify(execFile);
511
+
512
+ try {
513
+ // Try to run integration tests if they exist
514
+ await execFileAsync('npm', ['run', 'test:integration'], { cwd: process.cwd() });
515
+ return { name: 'integration_tests', passed: true, message: 'Integration tests passed' };
516
+ } catch (err) {
517
+ // If integration test script doesn't exist, skip
518
+ if (err.code === 1 || err.stderr?.includes('Missing script')) {
519
+ return { name: 'integration_tests', passed: true, message: 'Integration tests not configured, skipped' };
520
+ }
521
+ return { name: 'integration_tests', passed: false, message: 'Integration tests failed' };
522
+ }
523
+ }
524
+
525
+ /**
526
+ * Run dependency audit
527
+ */
528
+ async _runDependencyAudit() {
529
+ const { execFile } = require('child_process');
530
+ const { promisify } = require('util');
531
+ const execFileAsync = promisify(execFile);
532
+
533
+ try {
534
+ await execFileAsync('npm', ['audit', '--production', '--audit-level=high'], { cwd: process.cwd() });
535
+ return { name: 'dependency_audit', passed: true, message: 'Dependency audit passed' };
536
+ } catch (err) {
537
+ return { name: 'dependency_audit', passed: false, message: 'Dependency audit failed: high/critical vulnerabilities' };
538
+ }
539
+ }
540
+
541
+ /**
542
+ * Run critical bug detection
543
+ */
544
+ async _runCriticalBugDetection() {
545
+ // Check for common critical bug patterns in code
546
+ const fs = require('fs');
547
+ const path = require('path');
548
+ const errors = [];
549
+
550
+ // Example: Check for console.log in production code (excluding tests)
551
+ const srcDir = path.join(process.cwd(), 'ez-agents', 'bin', 'lib');
552
+ if (fs.existsSync(srcDir)) {
553
+ const files = fs.readdirSync(srcDir).filter(f => f.endsWith('.cjs'));
554
+ for (const file of files) {
555
+ const content = fs.readFileSync(path.join(srcDir, file), 'utf-8');
556
+ if (content.includes('console.log(') && !content.includes('// console.log')) {
557
+ errors.push(`Potential debug logging in ${file}`);
558
+ }
559
+ }
560
+ }
561
+
562
+ return {
563
+ name: 'critical_bug_detection',
564
+ passed: errors.length === 0,
565
+ message: errors.length === 0 ? 'No critical bugs detected' : errors.join('; ')
566
+ };
567
+ }
568
+
569
+ /**
570
+ * Validate release branch stability
571
+ * PHASE-GIT-10: Run full test suite, integration tests, security scans on release branch
572
+ * PHASE-GIT-11: Validate release branch stability (zero critical bugs, all tests green)
573
+ */
574
+ async validateReleaseBranch(releaseBranch) {
575
+ const currentBranch = await this.git.getCurrentBranch();
576
+ const checks = [];
577
+ let passed = true;
578
+ let criticalFailures = 0;
579
+
580
+ try {
581
+ // Switch to release branch
582
+ await this.git.checkout(releaseBranch);
583
+
584
+ // Full test suite
585
+ this.logger.info('Running full test suite', { branch: releaseBranch });
586
+ const testCheck = await this._runTestCheck();
587
+ testCheck.name = 'full_test_suite';
588
+ testCheck.critical = true;
589
+ checks.push(testCheck);
590
+ if (!testCheck.passed) {
591
+ passed = false;
592
+ criticalFailures++;
593
+ }
594
+
595
+ // Integration tests
596
+ this.logger.info('Running integration tests', { branch: releaseBranch });
597
+ const integrationCheck = await this._runIntegrationTestCheck();
598
+ integrationCheck.critical = true;
599
+ checks.push(integrationCheck);
600
+ if (!integrationCheck.passed) {
601
+ passed = false;
602
+ criticalFailures++;
603
+ }
604
+
605
+ // Security scan - npm audit
606
+ this.logger.info('Running security audit', { branch: releaseBranch });
607
+ const securityCheck = await this._runSecurityCheck();
608
+ securityCheck.critical = true;
609
+ checks.push(securityCheck);
610
+ if (!securityCheck.passed) {
611
+ passed = false;
612
+ criticalFailures++;
613
+ }
614
+
615
+ // Dependency vulnerability scan
616
+ this.logger.info('Scanning dependencies', { branch: releaseBranch });
617
+ const dependencyCheck = await this._runDependencyAudit();
618
+ dependencyCheck.critical = true;
619
+ checks.push(dependencyCheck);
620
+ if (!dependencyCheck.passed) {
621
+ passed = false;
622
+ criticalFailures++;
623
+ }
624
+
625
+ // Critical bug detection (check for known critical patterns)
626
+ this.logger.info('Checking for critical bugs', { branch: releaseBranch });
627
+ const criticalBugCheck = await this._runCriticalBugDetection();
628
+ criticalBugCheck.critical = true;
629
+ checks.push(criticalBugCheck);
630
+ if (!criticalBugCheck.passed) {
631
+ passed = false;
632
+ criticalFailures++;
633
+ }
634
+
635
+ const result = {
636
+ branch: releaseBranch,
637
+ passed,
638
+ criticalFailures,
639
+ checks,
640
+ timestamp: new Date().toISOString()
641
+ };
642
+
643
+ this.logger.info('Release validation completed', result);
644
+
645
+ if (criticalFailures > 0) {
646
+ throw new ValidationFailedError('release_stability', [
647
+ `${criticalFailures} critical check(s) failed`,
648
+ ...checks.filter(c => c.critical && !c.passed).map(c => c.message)
649
+ ]);
650
+ }
651
+
652
+ return result;
653
+ } finally {
654
+ // Restore original branch
655
+ if (currentBranch !== releaseBranch) {
656
+ await this.git.checkout(currentBranch);
657
+ }
658
+ }
659
+ }
660
+
661
+ /**
662
+ * Bump version in package.json
663
+ */
664
+ async _bumpVersion(newVersion) {
665
+ const fs = require('fs');
666
+ const path = require('path');
667
+
668
+ const packagePath = path.join(process.cwd(), 'package.json');
669
+ if (fs.existsSync(packagePath)) {
670
+ const packageJson = JSON.parse(fs.readFileSync(packagePath, 'utf-8'));
671
+ packageJson.version = newVersion;
672
+ fs.writeFileSync(packagePath, JSON.stringify(packageJson, null, 2) + '\n');
673
+
674
+ // Commit version bump
675
+ await this.git.add('package.json');
676
+ await this.git.commitAtomic(`chore: bump version to ${newVersion} [RELEASE]`, ['package.json']);
677
+
678
+ this.logger.info('Version bumped', { version: newVersion });
679
+ }
680
+ }
681
+
682
+ /**
683
+ * Merge release to main with version tag
684
+ * PHASE-GIT-12: Merge release to main with version tag
685
+ * PHASE-GIT-13: Merge release back to develop with version bump
686
+ */
687
+ async mergeReleaseToMain(releaseBranch) {
688
+ const semver = require('semver');
689
+
690
+ // Extract version from branch name
691
+ const versionMatch = releaseBranch.match(/^release\/v(\d+\.\d+\.\d+)$/);
692
+ if (!versionMatch) {
693
+ throw new ValidationFailedError('release_branch_format', [
694
+ `Invalid release branch format: ${releaseBranch}. Expected: release/vX.Y.Z`
695
+ ]);
696
+ }
697
+
698
+ const version = versionMatch[1];
699
+ const tagName = `v${version}`;
700
+
701
+ this.logger.info('Merging release to main', {
702
+ releaseBranch,
703
+ version,
704
+ tagName
705
+ });
706
+
707
+ // Validate release branch
708
+ await this.validateReleaseBranch(releaseBranch);
709
+
710
+ // Merge to main
711
+ await this.git.checkout('main');
712
+ await this.git.mergeWithStrategy(releaseBranch, 'main', 'merge');
713
+
714
+ // Create tag
715
+ await this.git.tagRelease(tagName, `Release ${tagName}`);
716
+
717
+ this.logger.info('Release merged to main', {
718
+ branch: 'main',
719
+ tag: tagName
720
+ });
721
+
722
+ // Merge back to develop with version bump
723
+ await this.git.checkout('develop');
724
+ await this.git.mergeWithStrategy(releaseBranch, 'develop', 'merge');
725
+
726
+ // Bump version in package.json
727
+ await this._bumpVersion(version);
728
+
729
+ this.logger.info('Release merged to develop', {
730
+ branch: 'develop',
731
+ version
732
+ });
733
+
734
+ return {
735
+ success: true,
736
+ releaseBranch,
737
+ mainTag: tagName,
738
+ version
739
+ };
740
+ }
741
+
742
+ /**
743
+ * Create pull request for enterprise mode
744
+ */
745
+ async _createPullRequest(source, target, options = {}) {
746
+ const { Octokit } = require('@octokit/rest');
747
+
748
+ // Check if GitHub token is configured
749
+ const githubToken = process.env.GITHUB_TOKEN;
750
+ if (!githubToken) {
751
+ throw new ValidationFailedError('github_auth', [
752
+ 'GITHUB_TOKEN environment variable not set. Required for enterprise PR workflow.'
753
+ ]);
754
+ }
755
+
756
+ const octokit = new Octokit({ auth: githubToken });
757
+
758
+ // Get repository info
759
+ const repoPath = process.cwd();
760
+ const { execFile } = require('child_process');
761
+ const { promisify } = require('util');
762
+ const execFileAsync = promisify(execFile);
763
+
764
+ try {
765
+ const { stdout: remoteUrl } = await execFileAsync('git', ['remote', 'get-url', 'origin'], { cwd: repoPath });
766
+ const repoMatch = remoteUrl.match(/github\.com[:/]([^/]+)\/([^.]+)\.git/);
767
+
768
+ if (!repoMatch) {
769
+ throw new Error('Could not parse repository URL');
770
+ }
771
+
772
+ const [, owner, repo] = repoMatch;
773
+
774
+ // Create PR
775
+ const prTitle = options.title || `Merge '${source}' into '${target}'`;
776
+ const prBody = options.body || `Automated PR for merging ${source} into ${target}`;
777
+
778
+ const { data: pr } = await octokit.pulls.create({
779
+ owner,
780
+ repo,
781
+ title: prTitle,
782
+ body: prBody,
783
+ head: source,
784
+ base: target
785
+ });
786
+
787
+ this.logger.info('Pull request created', {
788
+ number: pr.number,
789
+ url: pr.html_url,
790
+ source,
791
+ target
792
+ });
793
+
794
+ return {
795
+ success: true,
796
+ mode: 'enterprise',
797
+ pullRequest: pr.number,
798
+ url: pr.html_url,
799
+ requiredReviewers: options.requiredReviewers,
800
+ createdAt: new Date().toISOString()
801
+ };
802
+ } catch (err) {
803
+ this.logger.error('Failed to create pull request', { error: err.message });
804
+ throw new GitWorkflowError(`Failed to create PR: ${err.message}`, {
805
+ code: 'PR_CREATION_FAILED',
806
+ details: { source, target }
807
+ });
808
+ }
809
+ }
810
+
811
+ /**
812
+ * Merge branch with enterprise/open source mode support
813
+ * PHASE-GIT-14: Support enterprise workflow (protected branches, PR required, code review)
814
+ * PHASE-GIT-15: Support open source workflow (direct merge after automated validation)
815
+ */
816
+ async mergeBranch(source, target, options = {}) {
817
+ const enterpriseMode = this.config.git?.enterprise_mode?.require_pull_request || false;
818
+ const requiredReviewers = this.config.git?.enterprise_mode?.required_reviewers || 1;
819
+
820
+ // Validate strategy
821
+ const strategy = options.strategy || this.config.git?.merge_strategies?.[this.detectBranchType(source)] || 'merge';
822
+ this._validateStrategy(strategy);
823
+
824
+ this.logger.info('Merge branch requested', {
825
+ source,
826
+ target,
827
+ enterpriseMode,
828
+ requiredReviewers,
829
+ strategy
830
+ });
831
+
832
+ if (enterpriseMode) {
833
+ // Enterprise mode: Create PR and require approval
834
+ return await this._createPullRequest(source, target, {
835
+ ...options,
836
+ requiredReviewers
837
+ });
838
+ } else {
839
+ // Open source mode: Direct merge after validation
840
+ await this.validateBeforeMerge(source, options.validationLevel || 'standard');
841
+
842
+ await this.git.mergeWithStrategy(source, target, strategy);
843
+
844
+ this.logger.info('Direct merge completed (open source mode)', {
845
+ source,
846
+ target
847
+ });
848
+
849
+ return {
850
+ success: true,
851
+ mode: 'open_source',
852
+ source,
853
+ target,
854
+ mergedAt: new Date().toISOString()
855
+ };
856
+ }
857
+ }
858
+
859
+ /**
860
+ * Create and merge Hotfix
861
+ * PHASE-GIT-17: Hotfix workflow (create from main, merge to main + develop)
862
+ */
863
+ async createHotfix(description) {
864
+ // Create slug from description
865
+ const slug = description
866
+ .toLowerCase()
867
+ .replace(/[^a-z0-9]+/g, '-')
868
+ .replace(/^-|-$/g, '');
869
+
870
+ const branchName = `hotfix/${slug}`;
871
+
872
+ // Check if branch exists
873
+ if (await this.git.branchExists(branchName)) {
874
+ throw new BranchExistsError(branchName);
875
+ }
876
+
877
+ // Create hotfix branch from main
878
+ await this.git.createBranch(branchName, 'main');
879
+
880
+ this.logger.info('Hotfix branch created', {
881
+ branch: branchName,
882
+ description
883
+ });
884
+
885
+ return branchName;
886
+ }
887
+
888
+ /**
889
+ * Merge hotfix to main and develop
890
+ */
891
+ async mergeHotfix(hotfixBranch, version = null) {
892
+ const branchType = this.detectBranchType(hotfixBranch);
893
+ if (branchType !== 'hotfix') {
894
+ throw new ValidationFailedError('branch_type', [
895
+ `Expected hotfix branch, got: ${hotfixBranch}`
896
+ ]);
897
+ }
898
+
899
+ this.logger.info('Merging hotfix', { branch: hotfixBranch });
900
+
901
+ // Validate hotfix
902
+ await this.validateBeforeMerge(hotfixBranch, 'standard');
903
+
904
+ // Merge to main
905
+ await this.git.checkout('main');
906
+ await this.git.mergeWithStrategy(hotfixBranch, 'main', 'squash');
907
+
908
+ // Create tag if version provided
909
+ if (version) {
910
+ const tagName = `v${version}`;
911
+ await this.git.tagRelease(tagName, `Hotfix ${version}`);
912
+ this.logger.info('Hotfix tagged', { tag: tagName });
913
+ }
914
+
915
+ // Merge to develop
916
+ await this.git.checkout('develop');
917
+ await this.git.mergeWithStrategy(hotfixBranch, 'develop', 'squash');
918
+
919
+ this.logger.info('Hotfix merged to main and develop', {
920
+ branch: hotfixBranch
921
+ });
922
+
923
+ return {
924
+ success: true,
925
+ hotfixBranch,
926
+ mergedTo: ['main', 'develop'],
927
+ version
928
+ };
929
+ }
930
+
931
+ /**
932
+ * Rollback phase
933
+ * PHASE-GIT-18: Rollback capability with auto-revert if phase introduces regressions
934
+ */
935
+ async rollbackPhase(phaseNumber) {
936
+ const phasePattern = `phase/${phaseNumber}-`;
937
+ const branches = await this.git.listBranches(phasePattern + '*');
938
+
939
+ if (branches.length === 0) {
940
+ throw new BranchNotFoundError(`phase/${phaseNumber}-*`);
941
+ }
942
+
943
+ const phaseBranch = branches[0];
944
+ this.logger.info('Rolling back phase', { phaseNumber, phaseBranch });
945
+
946
+ // Create rollback branch for safety
947
+ const rollbackBranch = `rollback/phase-${phaseNumber}-${Date.now()}`;
948
+ await this.git.createBranch(rollbackBranch, 'develop');
949
+
950
+ // Check if phase was merged to develop
951
+ const currentBranch = await this.git.getCurrentBranch();
952
+ await this.git.checkout('develop');
953
+
954
+ // Find merge commit
955
+ const { execFile } = require('child_process');
956
+ const { promisify } = require('util');
957
+ const execFileAsync = promisify(execFile);
958
+
959
+ try {
960
+ const { stdout } = await execFileAsync('git', [
961
+ 'log', '--oneline', '--grep', phaseBranch, '-n', '1'
962
+ ], { cwd: process.cwd() });
963
+
964
+ if (stdout) {
965
+ const mergeCommit = stdout.split(' ')[0];
966
+
967
+ // Revert the merge commit
968
+ await this.git.revertCommit(mergeCommit);
969
+
970
+ this.logger.info('Phase rollback completed', {
971
+ phaseNumber,
972
+ revertedCommit: mergeCommit,
973
+ rollbackBranch
974
+ });
975
+
976
+ return {
977
+ success: true,
978
+ phaseNumber,
979
+ revertedCommit: mergeCommit,
980
+ rollbackBranch
981
+ };
982
+ } else {
983
+ // Phase not merged yet, just delete the branch
984
+ await this.git.deleteBranch(phaseBranch, true);
985
+
986
+ this.logger.info('Phase branch deleted (not merged)', {
987
+ phaseNumber,
988
+ phaseBranch
989
+ });
990
+
991
+ return {
992
+ success: true,
993
+ phaseNumber,
994
+ deleted: true,
995
+ rollbackBranch
996
+ };
997
+ }
998
+ } finally {
999
+ await this.git.checkout(currentBranch);
1000
+ }
1001
+ }
1002
+
1003
+ /**
1004
+ * Check branch protection rules
1005
+ * PHASE-GIT-19: Branch protection rules enforcement (require PR, reviews, status checks)
1006
+ */
1007
+ async checkBranchProtection(branch) {
1008
+ const { Octokit } = require('@octokit/rest');
1009
+
1010
+ const githubToken = process.env.GITHUB_TOKEN;
1011
+ if (!githubToken) {
1012
+ this.logger.warn('GITHUB_TOKEN not set, skipping branch protection check');
1013
+ return { protected: false, reason: 'no_token' };
1014
+ }
1015
+
1016
+ const octokit = new Octokit({ auth: githubToken });
1017
+
1018
+ // Get repository info
1019
+ const { execFile } = require('child_process');
1020
+ const { promisify } = require('util');
1021
+ const execFileAsync = promisify(execFile);
1022
+
1023
+ try {
1024
+ const { stdout: remoteUrl } = await execFileAsync('git', ['remote', 'get-url', 'origin'], { cwd: process.cwd() });
1025
+ const repoMatch = remoteUrl.match(/github\.com[:/]([^/]+)\/([^.]+)\.git/);
1026
+
1027
+ if (!repoMatch) {
1028
+ throw new Error('Could not parse repository URL');
1029
+ }
1030
+
1031
+ const [, owner, repo] = repoMatch;
1032
+
1033
+ // Get branch protection rules
1034
+ try {
1035
+ const { data: protection } = await octokit.repos.getBranchProtection({
1036
+ owner,
1037
+ repo,
1038
+ branch
1039
+ });
1040
+
1041
+ const result = {
1042
+ protected: true,
1043
+ requiredStatusChecks: protection.required_status_checks?.strict || false,
1044
+ requiredPullRequestReviews: protection.required_pull_request_reviews || null,
1045
+ requiredLinearHistory: protection.required_linear_history?.enabled || false,
1046
+ allowForcePushes: protection.allow_force_pushes?.enabled || false,
1047
+ allowDeletions: protection.allow_deletions?.enabled || false
1048
+ };
1049
+
1050
+ this.logger.info('Branch protection status', { branch, ...result });
1051
+
1052
+ // Validate enterprise mode requirements
1053
+ if (this.config.git?.enterprise_mode?.require_pull_request) {
1054
+ if (!result.requiredPullRequestReviews) {
1055
+ throw new ValidationFailedError('branch_protection', [
1056
+ `Branch '${branch}' does not require pull request reviews (enterprise mode requires it)`
1057
+ ]);
1058
+ }
1059
+ }
1060
+
1061
+ return result;
1062
+ } catch (err) {
1063
+ if (err.status === 404) {
1064
+ // Branch not protected
1065
+ return { protected: false, reason: 'not_protected' };
1066
+ }
1067
+ throw err;
1068
+ }
1069
+ } catch (err) {
1070
+ this.logger.error('Failed to check branch protection', { error: err.message });
1071
+ throw new GitWorkflowError(`Failed to check branch protection: ${err.message}`, {
1072
+ code: 'PROTECTION_CHECK_FAILED',
1073
+ details: { branch }
1074
+ });
1075
+ }
1076
+ }
1077
+
1078
+ /**
1079
+ * Enhance changelog with task IDs
1080
+ */
1081
+ _enhanceChangelogWithTaskIds(changelog) {
1082
+ // Add header
1083
+ const header = `# Changelog\n\nAll notable changes to this project will be documented in this file.\n\n`;
1084
+
1085
+ // Parse task IDs from commits and add to changelog
1086
+ const taskPattern = /\[TASK-(\d+)\]/g;
1087
+ const enhanced = changelog.replace(taskPattern, (match, taskId) => {
1088
+ return `[Task #${taskId}](https://github.com/howlil/ez-agents/issues/${taskId})`;
1089
+ });
1090
+
1091
+ return header + enhanced;
1092
+ }
1093
+
1094
+ /**
1095
+ * Generate changelog from commits
1096
+ * PHASE-GIT-20: Automated changelog generation from commits on merge to main
1097
+ */
1098
+ async generateChangelog(fromTag, toTag = 'HEAD') {
1099
+ const conventionalChangelog = require('conventional-changelog');
1100
+ const fs = require('fs');
1101
+ const path = require('path');
1102
+
1103
+ this.logger.info('Generating changelog', { fromTag, toTag });
1104
+
1105
+ return new Promise((resolve, reject) => {
1106
+ const changelogStream = conventionalChangelog({
1107
+ preset: 'angular',
1108
+ releaseCount: 1
1109
+ }, {
1110
+ from: fromTag,
1111
+ to: toTag
1112
+ }, {
1113
+ commits: true,
1114
+ commitsPath: process.cwd()
1115
+ });
1116
+
1117
+ let changelog = '';
1118
+
1119
+ changelogStream.on('data', (chunk) => {
1120
+ changelog += chunk.toString();
1121
+ });
1122
+
1123
+ changelogStream.on('end', () => {
1124
+ // Parse and enhance with task IDs
1125
+ const enhancedChangelog = this._enhanceChangelogWithTaskIds(changelog);
1126
+
1127
+ // Append to CHANGELOG.md
1128
+ const changelogPath = path.join(process.cwd(), 'CHANGELOG.md');
1129
+
1130
+ if (fs.existsSync(changelogPath)) {
1131
+ const existingContent = fs.readFileSync(changelogPath, 'utf-8');
1132
+ fs.writeFileSync(changelogPath, enhancedChangelog + '\n' + existingContent);
1133
+ } else {
1134
+ fs.writeFileSync(changelogPath, enhancedChangelog);
1135
+ }
1136
+
1137
+ this.logger.info('Changelog generated', { path: changelogPath });
1138
+
1139
+ resolve({
1140
+ success: true,
1141
+ fromTag,
1142
+ toTag,
1143
+ path: changelogPath
1144
+ });
1145
+ });
1146
+
1147
+ changelogStream.on('error', (err) => {
1148
+ this.logger.error('Changelog generation failed', { error: err.message });
1149
+ reject(new GitWorkflowError(`Changelog generation failed: ${err.message}`, {
1150
+ code: 'CHANGELOG_GENERATION_FAILED'
1151
+ }));
1152
+ });
1153
+ });
1154
+ }
1155
+ }
1156
+
1157
+ module.exports = GitWorkflowEngine;