@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,275 @@
1
+ 'use strict';
2
+ /**
3
+ * EZ Cost Tracker — Token usage and USD cost recording with budget enforcement
4
+ * Persists entries to .planning/metrics.json using file-lock for concurrent safety.
5
+ * Usage:
6
+ * const CostTracker = require('./cost-tracker.cjs');
7
+ * const ct = new CostTracker(cwd);
8
+ * await ct.record({ phase: 30, provider: 'claude', model: 'claude-sonnet-4-6', input_tokens: 1000, output_tokens: 500 });
9
+ * const report = ct.aggregate();
10
+ * const budget = ct.checkBudget();
11
+ */
12
+
13
+ const fs = require('fs');
14
+ const path = require('path');
15
+ const { withLock } = require('./file-lock.cjs');
16
+ const Logger = require('./logger.cjs');
17
+ const logger = new Logger();
18
+ const CostAlerts = require('./cost-alerts.cjs');
19
+
20
+ /**
21
+ * Returns default cost configuration with model rates.
22
+ */
23
+ function defaultCostConfig() {
24
+ return {
25
+ enabled: true,
26
+ budget: null,
27
+ warning_threshold: 80,
28
+ auto_pause: false,
29
+ rates: {
30
+ 'claude-3': { input: 0.003, output: 0.015 },
31
+ 'claude-sonnet-4-6': { input: 0.003, output: 0.015 },
32
+ 'gpt-4': { input: 0.03, output: 0.06 },
33
+ 'qwen': { input: 0.002, output: 0.006 },
34
+ 'kimi': { input: 0.002, output: 0.006 },
35
+ },
36
+ };
37
+ }
38
+
39
+ /**
40
+ * Read cost_tracking section from .planning/config.json.
41
+ * Falls back to defaultCostConfig() when absent or unreadable.
42
+ * @param {string} cwd
43
+ * @returns {object}
44
+ */
45
+ function readCostConfig(cwd) {
46
+ const configPath = path.join(cwd, '.planning', 'config.json');
47
+ if (!fs.existsSync(configPath)) return defaultCostConfig();
48
+ try {
49
+ const raw = JSON.parse(fs.readFileSync(configPath, 'utf8'));
50
+ return Object.assign(defaultCostConfig(), raw.cost_tracking || {});
51
+ } catch (e) {
52
+ return defaultCostConfig();
53
+ }
54
+ }
55
+
56
+ class CostTracker {
57
+ /**
58
+ * @param {string} [cwd] - Working directory (defaults to process.cwd())
59
+ */
60
+ constructor(cwd) {
61
+ this.cwd = cwd || process.cwd();
62
+ this.metricsPath = path.join(this.cwd, '.planning', 'metrics.json');
63
+ }
64
+
65
+ /**
66
+ * Returns the cost_tracking config merged with defaults.
67
+ * @returns {object}
68
+ */
69
+ getConfig() {
70
+ return readCostConfig(this.cwd);
71
+ }
72
+
73
+ /**
74
+ * Record a cost entry to metrics.json atomically (via file-lock).
75
+ * If cost_usd is not supplied, it is computed from token counts and model rates.
76
+ * @param {object} entry
77
+ * @param {string} [entry.agent] - Agent name for per-agent tracking (e.g., 'ez-planner', 'ez-executor')
78
+ * @returns {Promise<void>}
79
+ */
80
+ async record(entry) {
81
+ // Ensure .planning directory exists before locking
82
+ const planningDir = path.join(this.cwd, '.planning');
83
+ if (!fs.existsSync(planningDir)) {
84
+ fs.mkdirSync(planningDir, { recursive: true });
85
+ }
86
+
87
+ await withLock(this.metricsPath, async () => {
88
+ // Read existing data or initialise empty structure
89
+ let data = { version: '1.0', entries: [] };
90
+ if (fs.existsSync(this.metricsPath)) {
91
+ try {
92
+ data = JSON.parse(fs.readFileSync(this.metricsPath, 'utf8'));
93
+ if (!Array.isArray(data.entries)) data.entries = [];
94
+ } catch (e) {
95
+ logger.warn('cost-tracker: failed to parse metrics.json, reinitialising', { error: e.message });
96
+ data = { version: '1.0', entries: [] };
97
+ }
98
+ }
99
+
100
+ // Compute cost_usd if not provided
101
+ let cost_usd = entry.cost_usd;
102
+ if (cost_usd === undefined || cost_usd === null) {
103
+ const cfg = readCostConfig(this.cwd);
104
+ const rates = cfg.rates || {};
105
+ const modelKey = entry.model;
106
+ const providerKey = entry.provider;
107
+ const rate = rates[modelKey] || rates[providerKey] || null;
108
+ if (rate) {
109
+ const inputTokens = entry.input_tokens || 0;
110
+ const outputTokens = entry.output_tokens || 0;
111
+ cost_usd = (inputTokens * rate.input + outputTokens * rate.output) / 1000;
112
+ } else {
113
+ cost_usd = 0;
114
+ }
115
+ }
116
+
117
+ const fullEntry = Object.assign({}, entry, {
118
+ timestamp: new Date().toISOString(),
119
+ cost_usd,
120
+ });
121
+
122
+ data.entries.push(fullEntry);
123
+ fs.writeFileSync(this.metricsPath, JSON.stringify(data, null, 2), 'utf8');
124
+ });
125
+ }
126
+
127
+ /**
128
+ * Aggregate cost entries, optionally filtered.
129
+ * @param {object} [filter] - Optional { phase?, milestone?, provider?, by_agent? }
130
+ * @param {boolean} [filter.by_agent] - If true, group by agent field and return nested breakdown
131
+ * @returns {{ total: { cost: number, tokens: number }, by_phase: object, by_provider: object, by_agent?: object }}
132
+ */
133
+ aggregate(filter = {}) {
134
+ const emptyResult = () => ({ total: { cost: 0, tokens: 0 }, by_phase: {}, by_provider: {} });
135
+
136
+ if (!fs.existsSync(this.metricsPath)) return emptyResult();
137
+
138
+ let data;
139
+ try {
140
+ data = JSON.parse(fs.readFileSync(this.metricsPath, 'utf8'));
141
+ } catch (e) {
142
+ return emptyResult();
143
+ }
144
+
145
+ let entries = data.entries || [];
146
+
147
+ if (filter.phase !== undefined) entries = entries.filter(e => e.phase == filter.phase);
148
+ if (filter.milestone) entries = entries.filter(e => e.milestone === filter.milestone);
149
+ if (filter.provider) entries = entries.filter(e => e.provider === filter.provider);
150
+
151
+ const result = { total: { cost: 0, tokens: 0 }, by_phase: {}, by_provider: {} };
152
+
153
+ for (const e of entries) {
154
+ const phaseKey = String(e.phase || 'unknown');
155
+ if (!result.by_phase[phaseKey]) result.by_phase[phaseKey] = { cost: 0, tokens: 0 };
156
+ result.by_phase[phaseKey].cost += e.cost_usd || 0;
157
+ result.by_phase[phaseKey].tokens += (e.input_tokens || 0) + (e.output_tokens || 0);
158
+
159
+ const provKey = e.provider || 'unknown';
160
+ if (!result.by_provider[provKey]) result.by_provider[provKey] = { cost: 0 };
161
+ result.by_provider[provKey].cost += e.cost_usd || 0;
162
+
163
+ result.total.cost += e.cost_usd || 0;
164
+ result.total.tokens += (e.input_tokens || 0) + (e.output_tokens || 0);
165
+ }
166
+
167
+ // Add by_agent breakdown if requested
168
+ if (filter.by_agent) {
169
+ result.by_agent = {};
170
+ for (const e of entries) {
171
+ const agentKey = e.agent || 'unknown';
172
+ if (!result.by_agent[agentKey]) result.by_agent[agentKey] = { cost: 0, tokens: 0 };
173
+ result.by_agent[agentKey].cost += e.cost_usd || 0;
174
+ result.by_agent[agentKey].tokens += (e.input_tokens || 0) + (e.output_tokens || 0);
175
+ }
176
+ }
177
+
178
+ return result;
179
+ }
180
+
181
+ /**
182
+ * Check total spending against a budget ceiling.
183
+ * Does NOT call process.exit() — caller decides how to react.
184
+ * Triggers multi-threshold alerts when thresholds are crossed.
185
+ * @param {object} [opts] - { ceiling?, warning_threshold? }
186
+ * @returns {{ status: 'ok'|'warning'|'exceeded', message: string, total?: number, ceiling?: number, percentUsed?: number, alerts?: Array }}
187
+ */
188
+ async checkBudget(opts = {}) {
189
+ const cfg = this.getConfig();
190
+ const ceiling = (opts.ceiling !== undefined) ? opts.ceiling : cfg.budget;
191
+ const warning_threshold = (opts.warning_threshold !== undefined) ? opts.warning_threshold : cfg.warning_threshold;
192
+
193
+ const agg = this.aggregate();
194
+ const total = agg.total.cost;
195
+
196
+ if (ceiling === null || ceiling === undefined || typeof ceiling !== 'number') {
197
+ return { status: 'ok', message: 'No budget set' };
198
+ }
199
+
200
+ const percentUsed = (total / ceiling) * 100;
201
+ const alerts = new CostAlerts(this.cwd).checkThresholds({ percentUsed, totalSpent: total, budget: ceiling });
202
+
203
+ // Log triggered alerts
204
+ if (alerts.length > 0) {
205
+ const costAlerts = new CostAlerts(this.cwd);
206
+ for (const alert of alerts) {
207
+ await costAlerts.logAlert(alert);
208
+ }
209
+ }
210
+
211
+ if (total >= ceiling) {
212
+ return {
213
+ status: 'exceeded',
214
+ message: `Budget ceiling $${ceiling} exceeded ($${total.toFixed(4)} spent)`,
215
+ total,
216
+ ceiling,
217
+ percentUsed,
218
+ alerts
219
+ };
220
+ }
221
+
222
+ if (percentUsed >= warning_threshold) {
223
+ return {
224
+ status: 'warning',
225
+ message: `${percentUsed.toFixed(1)}% of budget used`,
226
+ total,
227
+ ceiling,
228
+ percentUsed,
229
+ alerts
230
+ };
231
+ }
232
+
233
+ return {
234
+ status: 'ok',
235
+ message: 'Within budget',
236
+ total,
237
+ ceiling,
238
+ percentUsed,
239
+ alerts
240
+ };
241
+ }
242
+
243
+ /**
244
+ * Persist a budget ceiling (and optional warning threshold) to .planning/config.json.
245
+ * @param {number} ceiling
246
+ * @param {number} [warningThreshold]
247
+ */
248
+ setBudget(ceiling, warningThreshold) {
249
+ const configPath = path.join(this.cwd, '.planning', 'config.json');
250
+ const planningDir = path.join(this.cwd, '.planning');
251
+
252
+ if (!fs.existsSync(planningDir)) {
253
+ fs.mkdirSync(planningDir, { recursive: true });
254
+ }
255
+
256
+ let config = {};
257
+ if (fs.existsSync(configPath)) {
258
+ try {
259
+ config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
260
+ } catch (e) {
261
+ config = {};
262
+ }
263
+ }
264
+
265
+ if (!config.cost_tracking) config.cost_tracking = {};
266
+ config.cost_tracking.budget = ceiling;
267
+ if (warningThreshold !== undefined) {
268
+ config.cost_tracking.warning_threshold = warningThreshold;
269
+ }
270
+
271
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf8');
272
+ }
273
+ }
274
+
275
+ module.exports = CostTracker;
@@ -0,0 +1,220 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * EZ Crash Recovery — PID-stamped lock file management
5
+ * Detects orphaned operations and enables safe concurrent execution gates.
6
+ * Usage:
7
+ * const CrashRecovery = require('./crash-recovery.cjs');
8
+ * const cr = new CrashRecovery(cwd);
9
+ * cr.acquire('phase-30-plan');
10
+ * // ... later ...
11
+ * cr.release('phase-30-plan');
12
+ */
13
+
14
+ const fs = require('fs');
15
+ const path = require('path');
16
+ const Logger = require('./logger.cjs');
17
+ const logger = new Logger();
18
+
19
+ const HEARTBEAT_INTERVAL_MS = 10000;
20
+ const STALE_HEARTBEAT_MS = 60000;
21
+
22
+ /**
23
+ * Check if a process is alive by sending signal 0.
24
+ * @param {number} pid
25
+ * @returns {boolean}
26
+ */
27
+ function isProcessAlive(pid) {
28
+ try {
29
+ process.kill(Number(pid), 0);
30
+ return true;
31
+ } catch (e) {
32
+ if (e.code === 'ESRCH') return false; // No such process
33
+ if (e.code === 'EPERM') return true; // Process exists, no permission
34
+ return false;
35
+ }
36
+ }
37
+
38
+ class CrashRecovery {
39
+ /**
40
+ * @param {string} cwd - Root directory containing .planning/
41
+ */
42
+ constructor(cwd) {
43
+ this.cwd = cwd || process.cwd();
44
+ this.locksDir = path.join(this.cwd, '.planning', 'locks');
45
+ this._intervals = {};
46
+ this._exitHandlers = {};
47
+ }
48
+
49
+ /**
50
+ * Sanitize an operation name to be a safe file name component.
51
+ * @param {string} operation
52
+ * @returns {string}
53
+ */
54
+ slugifyOperation(operation) {
55
+ return String(operation).replace(/[^a-zA-Z0-9-_]/g, '_');
56
+ }
57
+
58
+ /**
59
+ * Return the full path to the lock file for an operation.
60
+ * @param {string} operation
61
+ * @returns {string}
62
+ */
63
+ getLockPath(operation) {
64
+ return path.join(this.locksDir, this.slugifyOperation(operation) + '.lock.json');
65
+ }
66
+
67
+ /**
68
+ * Acquire a lock for the given operation.
69
+ * Creates a PID-stamped JSON lock file and starts a heartbeat interval.
70
+ * @param {string} operation
71
+ */
72
+ acquire(operation) {
73
+ if (!fs.existsSync(this.locksDir)) {
74
+ fs.mkdirSync(this.locksDir, { recursive: true });
75
+ }
76
+
77
+ const lockPath = this.getLockPath(operation);
78
+ const now = new Date().toISOString();
79
+ const data = { pid: process.pid, started: now, heartbeat: now, operation };
80
+ fs.writeFileSync(lockPath, JSON.stringify(data, null, 2), 'utf8');
81
+ logger.debug('Lock acquired: ' + operation);
82
+
83
+ // Heartbeat interval — keeps heartbeat timestamp fresh every 10s
84
+ const intervalId = setInterval(() => {
85
+ try {
86
+ if (fs.existsSync(lockPath)) {
87
+ const current = JSON.parse(fs.readFileSync(lockPath, 'utf8'));
88
+ current.heartbeat = new Date().toISOString();
89
+ fs.writeFileSync(lockPath, JSON.stringify(current, null, 2), 'utf8');
90
+ }
91
+ } catch (e) {
92
+ // Ignore heartbeat write errors (process may be exiting)
93
+ }
94
+ }, HEARTBEAT_INTERVAL_MS);
95
+
96
+ // Allow process to exit naturally even with active interval
97
+ if (intervalId.unref) intervalId.unref();
98
+ this._intervals[operation] = intervalId;
99
+
100
+ // Release on process exit to avoid orphaned lock files
101
+ const exitHandler = () => this.release(operation);
102
+ this._exitHandlers[operation] = exitHandler;
103
+ process.on('exit', exitHandler);
104
+ }
105
+
106
+ /**
107
+ * Check whether a lock is orphaned (process is dead or heartbeat is stale).
108
+ * @param {string} operation
109
+ * @returns {boolean}
110
+ */
111
+ isOrphan(operation) {
112
+ const lockPath = this.getLockPath(operation);
113
+ if (!fs.existsSync(lockPath)) return false;
114
+
115
+ let data;
116
+ try {
117
+ data = JSON.parse(fs.readFileSync(lockPath, 'utf8'));
118
+ } catch (e) {
119
+ return true; // Corrupt lock file treated as orphan
120
+ }
121
+
122
+ if (!isProcessAlive(data.pid)) return true;
123
+
124
+ // Stale heartbeat check — lock is orphaned if heartbeat is too old
125
+ const heartbeatAge = Date.now() - new Date(data.heartbeat).getTime();
126
+ if (heartbeatAge > STALE_HEARTBEAT_MS) return true;
127
+
128
+ return false;
129
+ }
130
+
131
+ /**
132
+ * Release a lock for the given operation.
133
+ * Clears the heartbeat interval and removes the lock file.
134
+ * @param {string} operation
135
+ */
136
+ release(operation) {
137
+ if (this._intervals[operation]) {
138
+ clearInterval(this._intervals[operation]);
139
+ delete this._intervals[operation];
140
+ }
141
+
142
+ if (this._exitHandlers[operation]) {
143
+ process.off('exit', this._exitHandlers[operation]);
144
+ delete this._exitHandlers[operation];
145
+ }
146
+
147
+ const lockPath = this.getLockPath(operation);
148
+ if (fs.existsSync(lockPath)) {
149
+ try {
150
+ fs.unlinkSync(lockPath);
151
+ } catch (e) {
152
+ // Ignore unlink errors (file may already be removed)
153
+ }
154
+ }
155
+
156
+ logger.debug('Lock released: ' + operation);
157
+ }
158
+
159
+ /**
160
+ * Return a list of operation slugs whose lock files are orphaned.
161
+ * @returns {string[]}
162
+ */
163
+ listOrphans() {
164
+ if (!fs.existsSync(this.locksDir)) return [];
165
+ return fs.readdirSync(this.locksDir)
166
+ .filter(f => f.endsWith('.lock.json'))
167
+ .map(f => f.replace(/\.lock\.json$/, ''))
168
+ .filter(op => this.isOrphan(op));
169
+ }
170
+
171
+ /**
172
+ * Return a list of all active locks with their metadata.
173
+ * @returns {Array<{operation: string, pid: number, started: string, heartbeat: string}>}
174
+ */
175
+ listLocks() {
176
+ if (!fs.existsSync(this.locksDir)) return [];
177
+ return fs.readdirSync(this.locksDir)
178
+ .filter(f => f.endsWith('.lock.json'))
179
+ .map(f => {
180
+ const lockPath = path.join(this.locksDir, f);
181
+ try {
182
+ const data = JSON.parse(fs.readFileSync(lockPath, 'utf8'));
183
+ return {
184
+ operation: data.operation,
185
+ pid: data.pid,
186
+ started: data.started,
187
+ heartbeat: data.heartbeat
188
+ };
189
+ } catch (e) {
190
+ return null;
191
+ }
192
+ })
193
+ .filter(lock => lock !== null);
194
+ }
195
+
196
+ /**
197
+ * Get the status of a specific lock.
198
+ * @param {string} operation
199
+ * @returns {{locked: boolean, pid?: number, started?: string, heartbeat?: string}}
200
+ */
201
+ getLockStatus(operation) {
202
+ const lockPath = this.getLockPath(operation);
203
+ if (!fs.existsSync(lockPath)) {
204
+ return { locked: false };
205
+ }
206
+ try {
207
+ const data = JSON.parse(fs.readFileSync(lockPath, 'utf8'));
208
+ return {
209
+ locked: true,
210
+ pid: data.pid,
211
+ started: data.started,
212
+ heartbeat: data.heartbeat
213
+ };
214
+ } catch (e) {
215
+ return { locked: false };
216
+ }
217
+ }
218
+ }
219
+
220
+ module.exports = CrashRecovery;