@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,112 @@
1
+ /**
2
+ * FinOps Analyzer — Cloud resource cost analysis and rightsizing recommendations
3
+ * Analyzes resource usage and provides cost optimization recommendations
4
+ */
5
+
6
+ const fs = require('fs');
7
+ const path = require('path');
8
+
9
+ class FinopsAnalyzer {
10
+ constructor(cwd) {
11
+ this.cwd = cwd || process.cwd();
12
+ this.costsPath = path.join(this.cwd, '.planning', 'finops', 'costs.json');
13
+ this.ensureFile();
14
+ }
15
+
16
+ /**
17
+ * Analyze cloud resource costs
18
+ * @param {Object} resources - Resource usage data
19
+ * @returns {Object} Cost analysis with recommendations
20
+ */
21
+ analyzeCosts(resources = {}) {
22
+ const analysis = {
23
+ timestamp: new Date().toISOString(),
24
+ totalCost: 0,
25
+ byResource: {},
26
+ byCategory: {},
27
+ recommendations: []
28
+ };
29
+
30
+ // Analyze each resource
31
+ for (const [name, resource] of Object.entries(resources)) {
32
+ const cost = resource.cost || 0;
33
+ const category = resource.category || 'other';
34
+
35
+ analysis.totalCost += cost;
36
+ analysis.byResource[name] = cost;
37
+
38
+ if (!analysis.byCategory[category]) {
39
+ analysis.byCategory[category] = 0;
40
+ }
41
+ analysis.byCategory[category] += cost;
42
+
43
+ // Generate rightsizing recommendations
44
+ if (resource.utilization < 30) {
45
+ analysis.recommendations.push({
46
+ resource: name,
47
+ type: 'rightsize',
48
+ reason: `Low utilization (${resource.utilization}%)`,
49
+ suggestion: 'Downsize instance or consolidate workloads',
50
+ potentialSavings: Math.round(cost * 0.4)
51
+ });
52
+ }
53
+ }
54
+
55
+ return analysis;
56
+ }
57
+
58
+ /**
59
+ * Get cost trend over time
60
+ * @returns {Array} Cost trend data
61
+ */
62
+ getTrend() {
63
+ if (!fs.existsSync(this.costsPath)) return [];
64
+ const costs = JSON.parse(fs.readFileSync(this.costsPath, 'utf8'));
65
+ return costs.trend || [];
66
+ }
67
+
68
+ /**
69
+ * Save cost data
70
+ * @param {Object} costData - Cost data to save
71
+ */
72
+ saveCostData(costData) {
73
+ const data = {
74
+ timestamp: new Date().toISOString(),
75
+ ...costData
76
+ };
77
+
78
+ let existing = { trend: [] };
79
+ if (fs.existsSync(this.costsPath)) {
80
+ existing = JSON.parse(fs.readFileSync(this.costsPath, 'utf8'));
81
+ }
82
+
83
+ existing.trend.push(data);
84
+ fs.writeFileSync(this.costsPath, JSON.stringify(existing, null, 2), 'utf8');
85
+ }
86
+
87
+ /**
88
+ * Ensure costs file exists
89
+ */
90
+ ensureFile() {
91
+ const dir = path.dirname(this.costsPath);
92
+ if (!fs.existsSync(dir)) {
93
+ fs.mkdirSync(dir, { recursive: true });
94
+ }
95
+ if (!fs.existsSync(this.costsPath)) {
96
+ fs.writeFileSync(this.costsPath, '{"trend":[]}', 'utf8');
97
+ }
98
+ }
99
+ }
100
+
101
+ /**
102
+ * Analyze cloud resource costs
103
+ * @param {Object} resources - Resource usage data
104
+ * @param {string} cwd - Working directory
105
+ * @returns {Object} Cost analysis
106
+ */
107
+ function analyzeCosts(resources = {}, cwd) {
108
+ const analyzer = new FinopsAnalyzer(cwd);
109
+ return analyzer.analyzeCosts(resources);
110
+ }
111
+
112
+ module.exports = { FinopsAnalyzer, analyzeCosts };
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Spot Manager — Spot/preemptible instance management recommendations
3
+ * Analyzes workload patterns and recommends spot vs on-demand instances
4
+ */
5
+
6
+ const fs = require('fs');
7
+ const path = require('path');
8
+
9
+ class SpotManager {
10
+ constructor(cwd) {
11
+ this.cwd = cwd || process.cwd();
12
+ this.recommendationsPath = path.join(this.cwd, '.planning', 'finops', 'spot-recommendations.json');
13
+ }
14
+
15
+ /**
16
+ * Analyze workload for spot instance suitability
17
+ * @param {Object} workload - Workload characteristics
18
+ * @returns {Object} Spot recommendations
19
+ */
20
+ analyzeWorkload(workload = {}) {
21
+ const recommendations = {
22
+ timestamp: new Date().toISOString(),
23
+ workloads: [],
24
+ totalPotentialSavings: 0
25
+ };
26
+
27
+ for (const [name, characteristics] of Object.entries(workload)) {
28
+ const suitability = this.calculateSpotSuitability(characteristics);
29
+ const savings = this.calculateSavings(characteristics.cost, suitability);
30
+
31
+ recommendations.workloads.push({
32
+ name,
33
+ spotSuitable: suitability.score >= 70,
34
+ suitabilityScore: suitability.score,
35
+ reasons: suitability.reasons,
36
+ currentCost: characteristics.cost,
37
+ potentialSavings: savings,
38
+ recommendation: suitability.score >= 70 ? 'Use spot instances' : 'Use on-demand'
39
+ });
40
+
41
+ recommendations.totalPotentialSavings += savings;
42
+ }
43
+
44
+ return recommendations;
45
+ }
46
+
47
+ /**
48
+ * Calculate spot suitability score
49
+ * @param {Object} characteristics - Workload characteristics
50
+ * @returns {Object} Suitability analysis
51
+ */
52
+ calculateSpotSuitability(characteristics) {
53
+ let score = 50; // Base score
54
+ const reasons = [];
55
+
56
+ // Fault tolerant workloads are good for spot
57
+ if (characteristics.faultTolerant) {
58
+ score += 30;
59
+ reasons.push('Fault tolerant workload');
60
+ }
61
+
62
+ // Batch processing is good for spot
63
+ if (characteristics.batchProcessing) {
64
+ score += 20;
65
+ reasons.push('Batch processing workload');
66
+ }
67
+
68
+ // Stateful workloads are bad for spot
69
+ if (characteristics.stateful) {
70
+ score -= 20;
71
+ reasons.push('Stateful workload (checkpointing recommended)');
72
+ }
73
+
74
+ // Time-sensitive workloads are bad for spot
75
+ if (characteristics.timeSensitive) {
76
+ score -= 30;
77
+ reasons.push('Time-sensitive workload');
78
+ }
79
+
80
+ return {
81
+ score: Math.min(100, Math.max(0, score)),
82
+ reasons
83
+ };
84
+ }
85
+
86
+ /**
87
+ * Calculate potential savings from spot
88
+ * @param {number} currentCost - Current on-demand cost
89
+ * @param {number} suitability - Suitability score
90
+ * @returns {number} Potential savings
91
+ */
92
+ calculateSavings(currentCost, suitability) {
93
+ // Spot instances typically 60-90% cheaper
94
+ const savingsRate = 0.7;
95
+ return Math.round(currentCost * savingsRate * (suitability / 100));
96
+ }
97
+
98
+ /**
99
+ * Save recommendations
100
+ * @param {Object} recommendations - Recommendations to save
101
+ */
102
+ saveRecommendations(recommendations) {
103
+ fs.writeFileSync(this.recommendationsPath, JSON.stringify(recommendations, null, 2), 'utf8');
104
+ }
105
+ }
106
+
107
+ /**
108
+ * Analyze workload for spot suitability
109
+ * @param {Object} workload - Workload characteristics
110
+ * @param {string} cwd - Working directory
111
+ * @returns {Object} Spot recommendations
112
+ */
113
+ function analyzeWorkload(workload = {}, cwd) {
114
+ const manager = new SpotManager(cwd);
115
+ return manager.analyzeWorkload(workload);
116
+ }
117
+
118
+ module.exports = { SpotManager, analyzeWorkload };
@@ -0,0 +1,396 @@
1
+ /**
2
+ * Framework Detector — Detailed framework detection from config files and imports
3
+ *
4
+ * Provides:
5
+ * - detectFromConfig(rootPath): Analyzes config files for framework confirmation
6
+ * - detectFromImports(sourceFiles): Analyzes import statements for framework usage
7
+ */
8
+
9
+ const fs = require('fs');
10
+ const path = require('path');
11
+
12
+ class FrameworkDetector {
13
+ constructor(rootPath) {
14
+ this.rootPath = rootPath;
15
+ }
16
+
17
+ /**
18
+ * Detect frameworks from config files
19
+ * @param {string} rootPath - Root directory to analyze
20
+ * @returns {object} Object with detected frameworks from configs
21
+ */
22
+ detectFromConfig(rootPath = this.rootPath) {
23
+ const configPatterns = {
24
+ typescript: ['tsconfig.json'],
25
+ vite: ['vite.config.js', 'vite.config.ts', 'vite.config.mjs'],
26
+ webpack: ['webpack.config.js', 'webpack.config.ts'],
27
+ rollup: ['rollup.config.js', 'rollup.config.ts'],
28
+ eslint: ['.eslintrc.js', '.eslintrc.json', '.eslintrc', '.eslintrc.cjs', 'eslint.config.js'],
29
+ prettier: ['.prettierrc', '.prettierrc.js', '.prettierrc.json', 'prettier.config.js'],
30
+ next: ['next.config.js', 'next.config.mjs', 'next.config.ts'],
31
+ nuxt: ['nuxt.config.js', 'nuxt.config.ts'],
32
+ remix: ['remix.config.js'],
33
+ prisma: ['prisma/schema.prisma'],
34
+ jest: ['jest.config.js', 'jest.config.ts', 'jest.config.cjs'],
35
+ vitest: ['vitest.config.js', 'vitest.config.ts'],
36
+ cypress: ['cypress.config.js', 'cypress.config.ts'],
37
+ playwright: ['playwright.config.js', 'playwright.config.ts'],
38
+ tailwind: ['tailwind.config.js', 'tailwind.config.ts'],
39
+ postcss: ['postcss.config.js', 'postcss.config.cjs'],
40
+ babel: ['babel.config.js', '.babelrc', '.babelrc.js'],
41
+ docker: ['Dockerfile'],
42
+ dockerCompose: ['docker-compose.yml', 'docker-compose.yaml'],
43
+ serverless: ['serverless.yml', 'serverless.yaml'],
44
+ vercel: ['vercel.json'],
45
+ netlify: ['netlify.toml'],
46
+ heroku: ['Procfile'],
47
+ terraform: ['main.tf', 'terraform.tfvars'],
48
+ kubernetes: ['k8s/', 'kubernetes/', 'helm/']
49
+ };
50
+
51
+ const detected = {};
52
+
53
+ for (const [framework, patterns] of Object.entries(configPatterns)) {
54
+ for (const pattern of patterns) {
55
+ const fullPath = path.join(rootPath, pattern);
56
+ if (fs.existsSync(fullPath)) {
57
+ detected[framework] = {
58
+ config: pattern,
59
+ path: fullPath,
60
+ confidence: 'high'
61
+ };
62
+ break;
63
+ }
64
+ // Check for directory patterns
65
+ if (pattern.endsWith('/')) {
66
+ const dirPath = path.join(rootPath, pattern);
67
+ if (fs.existsSync(dirPath) && fs.statSync(dirPath).isDirectory()) {
68
+ detected[framework] = {
69
+ config: pattern,
70
+ path: dirPath,
71
+ confidence: 'medium'
72
+ };
73
+ break;
74
+ }
75
+ }
76
+ }
77
+ }
78
+
79
+ return detected;
80
+ }
81
+
82
+ /**
83
+ * Detect frameworks from import statements in source files
84
+ * @param {Array} sourceFiles - Array of source file paths
85
+ * @returns {object} Object with detected frameworks from imports
86
+ */
87
+ detectFromImports(sourceFiles = []) {
88
+ const frameworkImports = {
89
+ 'React': {
90
+ patterns: ['import React', 'import {', 'from \'react\'', 'from "react"'],
91
+ name: 'React'
92
+ },
93
+ 'Next.js': {
94
+ patterns: ['from \'next\'', 'from "next"', 'import {', 'next/server', 'next/router'],
95
+ name: 'Next.js'
96
+ },
97
+ 'Vue.js': {
98
+ patterns: ['import Vue', 'from \'vue\'', 'from "vue"', 'createApp'],
99
+ name: 'Vue.js'
100
+ },
101
+ 'Nuxt.js': {
102
+ patterns: ['from \'#app\'', 'from "#app"', 'useNuxtApp', 'defineNuxtComponent'],
103
+ name: 'Nuxt.js'
104
+ },
105
+ 'Angular': {
106
+ patterns: ['from \'@angular/core\'', 'from "@angular/core"', '@Component', '@Injectable'],
107
+ name: 'Angular'
108
+ },
109
+ 'Svelte': {
110
+ patterns: ['from \'svelte\'', 'from "svelte"', 'import { onMount', 'import { writable'],
111
+ name: 'Svelte'
112
+ },
113
+ 'SolidJS': {
114
+ patterns: ['from \'solid-js\'', 'from "solid-js"', 'createSignal', 'createEffect'],
115
+ name: 'SolidJS'
116
+ },
117
+ 'Express': {
118
+ patterns: ['import express', 'from \'express\'', 'from "express"', 'require(\'express\')'],
119
+ name: 'Express'
120
+ },
121
+ 'Fastify': {
122
+ patterns: ['import fastify', 'from \'fastify\'', 'from "fastify"'],
123
+ name: 'Fastify'
124
+ },
125
+ 'NestJS': {
126
+ patterns: ['from \'@nestjs/core\'', 'from "@nestjs/core"', '@Module', '@Controller'],
127
+ name: 'NestJS'
128
+ },
129
+ 'Koa': {
130
+ patterns: ['import Koa', 'from \'koa\'', 'from "koa"'],
131
+ name: 'Koa'
132
+ },
133
+ 'Remix': {
134
+ patterns: ['from \'@remix-run\'', 'from "@remix-run"', 'useLoaderData', 'ActionFunction'],
135
+ name: 'Remix'
136
+ },
137
+ 'Django': {
138
+ patterns: ['from django.', 'import django', 'django.conf'],
139
+ name: 'Django'
140
+ },
141
+ 'Flask': {
142
+ patterns: ['from flask', 'import Flask', 'flask.'],
143
+ name: 'Flask'
144
+ },
145
+ 'FastAPI': {
146
+ patterns: ['from fastapi', 'import FastAPI', 'FastAPI()'],
147
+ name: 'FastAPI'
148
+ }
149
+ };
150
+
151
+ const detected = {};
152
+
153
+ for (const file of sourceFiles) {
154
+ try {
155
+ const content = fs.readFileSync(file, 'utf8');
156
+
157
+ for (const [key, config] of Object.entries(frameworkImports)) {
158
+ for (const pattern of config.patterns) {
159
+ if (content.includes(pattern)) {
160
+ if (!detected[key]) {
161
+ detected[key] = {
162
+ name: config.name,
163
+ files: [],
164
+ evidence: []
165
+ };
166
+ }
167
+ if (!detected[key].files.includes(file)) {
168
+ detected[key].files.push(file);
169
+ }
170
+ detected[key].evidence.push({
171
+ file,
172
+ pattern
173
+ });
174
+ break;
175
+ }
176
+ }
177
+ }
178
+ } catch (err) {
179
+ // Ignore read errors
180
+ }
181
+ }
182
+
183
+ return detected;
184
+ }
185
+
186
+ /**
187
+ * Detect framework-specific patterns in source files
188
+ * @param {Array} sourceFiles - Array of source file paths
189
+ * @returns {object} Object with detected framework patterns
190
+ */
191
+ detectFrameworkPatterns(sourceFiles = []) {
192
+ const patterns = {
193
+ 'React': {
194
+ components: /function\s+\w+Component\s*\(/,
195
+ hooks: /use\w+\(/,
196
+ jsx: /<\w+\s*[^>]*>/,
197
+ context: /createContext|useContext/
198
+ },
199
+ 'Next.js': {
200
+ pages: /pages\//,
201
+ api: /pages\/api\//,
202
+ getServerSideProps: /getServerSideProps|getStaticProps|getStaticPaths/,
203
+ image: /<Image\s/,
204
+ link: /<Link\s/
205
+ },
206
+ 'Vue.js': {
207
+ component: /export\s+default\s*{/,
208
+ template: /<template>/,
209
+ setup: /setup\s*\(\)/,
210
+ directives: /v-if|v-for|v-model/
211
+ },
212
+ 'Angular': {
213
+ decorator: /@\w+\(/,
214
+ module: /@NgModule/,
215
+ component: /@Component/,
216
+ service: /@Injectable/,
217
+ dependency: /constructor\s*\([^)]*private\s+\w+:\s+\w+/
218
+ },
219
+ 'Express': {
220
+ router: /express\.Router/,
221
+ middleware: /app\.use\(|router\.use\(/,
222
+ route: /app\.(get|post|put|delete|patch)\(/,
223
+ request: /req\.|request\./
224
+ },
225
+ 'NestJS': {
226
+ module: /@Module\(/,
227
+ controller: /@Controller\(/,
228
+ service: /@Injectable\(/,
229
+ guard: /@UseGuards\(/,
230
+ interceptor: /@UseInterceptors\(/
231
+ }
232
+ };
233
+
234
+ const results = {};
235
+
236
+ for (const [framework, patternSet] of Object.entries(patterns)) {
237
+ const matches = {
238
+ total: 0,
239
+ files: {},
240
+ patterns: {}
241
+ };
242
+
243
+ for (const file of sourceFiles) {
244
+ try {
245
+ const content = fs.readFileSync(file, 'utf8');
246
+ const fileMatches = {};
247
+
248
+ for (const [patternName, regex] of Object.entries(patternSet)) {
249
+ const matchCount = (content.match(regex) || []).length;
250
+ if (matchCount > 0) {
251
+ fileMatches[patternName] = matchCount;
252
+ matches.patterns[patternName] = (matches.patterns[patternName] || 0) + matchCount;
253
+ matches.total += matchCount;
254
+ }
255
+ }
256
+
257
+ if (Object.keys(fileMatches).length > 0) {
258
+ matches.files[file] = fileMatches;
259
+ }
260
+ } catch (err) {
261
+ // Ignore read errors
262
+ }
263
+ }
264
+
265
+ if (matches.total > 0) {
266
+ results[framework] = matches;
267
+ }
268
+ }
269
+
270
+ return results;
271
+ }
272
+
273
+ /**
274
+ * Get comprehensive framework analysis
275
+ * @param {string} rootPath - Root directory to analyze
276
+ * @returns {object} Comprehensive framework analysis
277
+ */
278
+ analyze(rootPath = this.rootPath) {
279
+ const configDetection = this.detectFromConfig(rootPath);
280
+
281
+ // Get source files
282
+ const sourceFiles = this._getSourceFiles(rootPath);
283
+ const importDetection = this.detectFromImports(sourceFiles);
284
+ const patternDetection = this.detectFrameworkPatterns(sourceFiles);
285
+
286
+ // Merge results
287
+ const frameworks = {};
288
+
289
+ // Add config-based detections
290
+ for (const [framework, config] of Object.entries(configDetection)) {
291
+ frameworks[framework] = {
292
+ detected: true,
293
+ confidence: config.confidence,
294
+ source: 'config',
295
+ config: config.config,
296
+ importEvidence: null,
297
+ patternEvidence: null
298
+ };
299
+ }
300
+
301
+ // Add import-based detections
302
+ for (const [framework, evidence] of Object.entries(importDetection)) {
303
+ if (frameworks[framework]) {
304
+ frameworks[framework].importEvidence = evidence;
305
+ frameworks[framework].confidence = 'high';
306
+ } else {
307
+ frameworks[framework] = {
308
+ detected: true,
309
+ confidence: 'medium',
310
+ source: 'imports',
311
+ config: null,
312
+ importEvidence: evidence,
313
+ patternEvidence: null
314
+ };
315
+ }
316
+ }
317
+
318
+ // Add pattern-based detections
319
+ for (const [framework, patterns] of Object.entries(patternDetection)) {
320
+ if (frameworks[framework]) {
321
+ frameworks[framework].patternEvidence = patterns;
322
+ } else {
323
+ frameworks[framework] = {
324
+ detected: true,
325
+ confidence: 'low',
326
+ source: 'patterns',
327
+ config: null,
328
+ importEvidence: null,
329
+ patternEvidence: patterns
330
+ };
331
+ }
332
+ }
333
+
334
+ return {
335
+ frameworks,
336
+ summary: {
337
+ total: Object.keys(frameworks).length,
338
+ byConfidence: {
339
+ high: Object.values(frameworks).filter(f => f.confidence === 'high').length,
340
+ medium: Object.values(frameworks).filter(f => f.confidence === 'medium').length,
341
+ low: Object.values(frameworks).filter(f => f.confidence === 'low').length
342
+ }
343
+ }
344
+ };
345
+ }
346
+
347
+ /**
348
+ * Get source files from root path
349
+ * @private
350
+ */
351
+ _getSourceFiles(rootPath) {
352
+ const files = [];
353
+ const srcDir = path.join(rootPath, 'src');
354
+ const appDir = path.join(rootPath, 'app');
355
+ const libDir = path.join(rootPath, 'lib');
356
+ const pagesDir = path.join(rootPath, 'pages');
357
+ const componentsDir = path.join(rootPath, 'components');
358
+
359
+ const dirsToSearch = [rootPath];
360
+ if (fs.existsSync(srcDir)) dirsToSearch.push(srcDir);
361
+ if (fs.existsSync(appDir)) dirsToSearch.push(appDir);
362
+ if (fs.existsSync(libDir)) dirsToSearch.push(libDir);
363
+ if (fs.existsSync(pagesDir)) dirsToSearch.push(pagesDir);
364
+ if (fs.existsSync(componentsDir)) dirsToSearch.push(componentsDir);
365
+
366
+ for (const dir of dirsToSearch) {
367
+ this._collectSourceFiles(dir, files);
368
+ }
369
+
370
+ return files.slice(0, 100); // Limit to 100 files
371
+ }
372
+
373
+ /**
374
+ * Collect source files from directory
375
+ * @private
376
+ */
377
+ _collectSourceFiles(dir, files, depth = 0) {
378
+ if (depth > 5 || dir.includes('node_modules')) return;
379
+
380
+ try {
381
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
382
+ for (const entry of entries) {
383
+ const fullPath = path.join(dir, entry.name);
384
+ if (entry.isDirectory()) {
385
+ this._collectSourceFiles(fullPath, files, depth + 1);
386
+ } else if (entry.isFile() && /\.(ts|tsx|js|jsx)$/.test(entry.name)) {
387
+ files.push(fullPath);
388
+ }
389
+ }
390
+ } catch (err) {
391
+ // Ignore errors
392
+ }
393
+ }
394
+ }
395
+
396
+ module.exports = { FrameworkDetector };
@@ -10,7 +10,9 @@ const { safeReadFile, output, error } = require('./core.cjs');
10
10
 
11
11
  function extractFrontmatter(content) {
12
12
  const frontmatter = {};
13
- const match = content.match(/^---\n([\s\S]+?)\n---/);
13
+ // Normalize CRLF to LF so regex works on Windows-converted files
14
+ const normalized = content.replace(/\r\n/g, '\n');
15
+ const match = normalized.match(/^---\n([\s\S]+?)\n---/);
14
16
  if (!match) return frontmatter;
15
17
 
16
18
  const yaml = match[1];