claude-flow-novice 2.15.3 → 2.15.4

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 (461) hide show
  1. package/.claude/cfn-extras/skills/advanced-features/cfn-agent-swap/recommend-swap.sh +59 -59
  2. package/.claude/cfn-extras/skills/analytics/cfn-improvement-recommender/recommend-improvements.sh +91 -91
  3. package/.claude/cfn-extras/skills/analytics/cfn-pattern-extraction/extract-patterns.sh +79 -79
  4. package/.claude/cfn-extras/skills/analytics/cfn-retrospective-report/generate-report.sh +100 -100
  5. package/.claude/cfn-extras/skills/analytics/cfn-telemetry/start-telemetry.sh +110 -110
  6. package/.claude/cfn-extras/skills/deprecated/cfn-ace-system/add-bullet.sh +145 -145
  7. package/.claude/cfn-extras/skills/deprecated/cfn-ace-system/log-merge.sh +67 -67
  8. package/.claude/cfn-extras/skills/deprecated/cfn-ace-system/monitor-injection-performance.sh +137 -137
  9. package/.claude/cfn-extras/skills/deprecated/cfn-ace-system/optimize-injection-pipeline.sh +168 -168
  10. package/.claude/cfn-extras/skills/deprecated/cfn-ace-system/query-reflections.sh +35 -35
  11. package/.claude/cfn-extras/skills/deprecated/cfn-ace-system/store-reflection.sh +45 -45
  12. package/.claude/cfn-extras/skills/deprecated/cfn-ace-system/track-ab-test.sh +41 -41
  13. package/.claude/cfn-extras/skills/deprecated/cfn-ace-system/update-reflection.sh +41 -41
  14. package/.claude/cfn-extras/skills/deprecated/cfn-cli-setup/validate-cli-environment.sh +191 -191
  15. package/.claude/cfn-extras/skills/marketing/cfn-marketing-ad-campaigns/operations/create-campaign.sh +231 -231
  16. package/.claude/cfn-extras/skills/marketing/cfn-marketing-ad-campaigns/operations/get-campaign-performance.sh +190 -190
  17. package/.claude/cfn-extras/skills/marketing/cfn-marketing-ad-campaigns/operations/pause-campaign.sh +142 -142
  18. package/.claude/cfn-extras/skills/marketing/cfn-marketing-ad-campaigns/operations/set-budget.sh +181 -181
  19. package/.claude/cfn-extras/skills/marketing/cfn-marketing-ad-campaigns/operations/update-bid-strategy.sh +133 -133
  20. package/.claude/cfn-extras/skills/marketing/cfn-marketing-chatbot-conversations/operations/get-conversation-history.sh +121 -121
  21. package/.claude/cfn-extras/skills/marketing/cfn-marketing-chatbot-conversations/operations/qualify-lead.sh +156 -156
  22. package/.claude/cfn-extras/skills/marketing/cfn-marketing-chatbot-conversations/operations/schedule-demo.sh +181 -181
  23. package/.claude/cfn-extras/skills/marketing/cfn-marketing-chatbot-conversations/operations/send-message.sh +137 -137
  24. package/.claude/cfn-extras/skills/marketing/cfn-marketing-chatbot-conversations/operations/transfer-to-human.sh +179 -179
  25. package/.claude/cfn-extras/skills/marketing/cfn-marketing-sms-campaigns/operations/create-campaign.sh +183 -183
  26. package/.claude/cfn-extras/skills/marketing/cfn-marketing-sms-campaigns/operations/get-delivery-status.sh +139 -139
  27. package/.claude/cfn-extras/skills/marketing/cfn-marketing-sms-campaigns/operations/opt-out.sh +150 -150
  28. package/.claude/cfn-extras/skills/marketing/cfn-marketing-sms-campaigns/operations/schedule-campaign.sh +187 -187
  29. package/.claude/cfn-extras/skills/marketing/cfn-marketing-sms-campaigns/operations/send-sms.sh +181 -181
  30. package/.claude/cfn-extras/skills/ui-portal/cfn-web-portal/test-web-portal-skill.sh +50 -50
  31. package/.claude/cfn-extras/skills/ui-portal/cfn-web-portal/validate-deployment.sh +84 -84
  32. package/.claude/cfn-extras/skills/utility/cfn-environment-sanitization/sanitize-environment.sh +243 -243
  33. package/.claude/commands/cfn-loop-cli.md +16 -2
  34. package/.claude/commands/switch-api.md +31 -10
  35. package/.claude/hooks/cfn-lint-sql-injection.sh +61 -0
  36. package/.claude/hooks/cfn-post-edit-cfn-retrospective.sh +33 -2
  37. package/.claude/hooks/cfn-pre-edit-security-warning.sh +40 -0
  38. package/.claude/skills/cfn-agent-spawning/spawn-agent.sh +22 -24
  39. package/.claude/skills/cfn-docker-agent-spawning/SKILL.md +28 -4
  40. package/.claude/skills/cfn-docker-agent-spawning/spawn-agent.sh +3 -1
  41. package/.claude/skills/cfn-docker-loop-orchestration/orchestrate.sh +224 -20
  42. package/.claude/skills/cfn-loop-orchestration/helpers/gate-check.sh +550 -46
  43. package/.claude/skills/cfn-loop-orchestration/helpers/parse-test-results.sh +277 -0
  44. package/.claude/skills/cfn-loop-orchestration/orchestrate.sh +184 -23
  45. package/.claude/skills/cfn-loop-orchestration/security_utils.sh +24 -0
  46. package/.claude/skills/cfn-loop-orchestration/test-iteration-context-injection.sh +366 -0
  47. package/.claude/skills/cfn-redis-coordination/CENTRALIZED_REDIS_WRAPPER.md +319 -0
  48. package/.claude/skills/cfn-redis-coordination/agent-log.sh +4 -0
  49. package/.claude/skills/cfn-redis-coordination/agent-log.sh.bak +124 -0
  50. package/.claude/skills/cfn-redis-coordination/agent-recovery.sh +2 -2
  51. package/.claude/skills/cfn-redis-coordination/collect-confidence-scores.sh +30 -0
  52. package/.claude/skills/cfn-redis-coordination/get-context.sh +33 -0
  53. package/.claude/skills/cfn-redis-coordination/get-success-criteria.sh +54 -0
  54. package/.claude/skills/cfn-redis-coordination/invoke-waiting-mode.sh +3 -0
  55. package/.claude/skills/cfn-redis-coordination/redis-cli-wrapper.sh +24 -3
  56. package/.claude/skills/cfn-redis-coordination/redis-functions.sh +33 -0
  57. package/.claude/skills/cfn-redis-coordination/report-completion.sh +24 -31
  58. package/.claude/skills/cfn-redis-coordination/store-context.sh +4 -0
  59. package/.claude/skills/cfn-redis-coordination/store-success-criteria.sh +85 -0
  60. package/.claude/skills/cfn-redis-coordination/update-all-scripts.sh +67 -0
  61. package/.claude/skills/cfn-sqlite-memory/ttl-cleanup.sh +17 -25
  62. package/.claude/skills/cfn-transparency-middleware/test-e2e.sh +15 -0
  63. package/.claude/skills/cfn-transparency-middleware/tests/input-validation.sh +15 -0
  64. package/README.md +116 -475
  65. package/claude-assets/agents/cfn-dev-team/README.md +103 -0
  66. package/claude-assets/agents/cfn-dev-team/architecture/goal-planner.md +1 -1
  67. package/claude-assets/agents/cfn-dev-team/coordinators/cfn-frontend-coordinator.md +77 -15
  68. package/claude-assets/agents/cfn-dev-team/coordinators/cfn-v3-coordinator.md +355 -6
  69. package/claude-assets/agents/cfn-dev-team/coordinators/consensus-builder.md +82 -1
  70. package/claude-assets/agents/cfn-dev-team/coordinators/handoff-coordinator.md +82 -1
  71. package/claude-assets/agents/cfn-dev-team/coordinators/multi-sprint-coordinator.md +77 -15
  72. package/claude-assets/agents/cfn-dev-team/dev-ops/docker-specialist.md +99 -12
  73. package/claude-assets/agents/cfn-dev-team/dev-ops/github-commit-agent.md +1 -1
  74. package/claude-assets/agents/cfn-dev-team/dev-ops/kubernetes-specialist.md +97 -0
  75. package/claude-assets/agents/cfn-dev-team/dev-ops/monitoring-specialist.md +20 -1
  76. package/claude-assets/agents/cfn-dev-team/developers/api-gateway-specialist.md +97 -0
  77. package/claude-assets/agents/cfn-dev-team/developers/backend-developer.md +110 -13
  78. package/claude-assets/agents/cfn-dev-team/developers/data/data-engineer.md +106 -15
  79. package/claude-assets/agents/cfn-dev-team/developers/database/database-architect.md +115 -11
  80. package/claude-assets/agents/cfn-dev-team/developers/frontend/mobile-dev.md +94 -7
  81. package/claude-assets/agents/cfn-dev-team/developers/frontend/react-frontend-engineer.md +87 -9
  82. package/claude-assets/agents/cfn-dev-team/developers/frontend/typescript-specialist.md +85 -7
  83. package/claude-assets/agents/cfn-dev-team/developers/frontend/ui-designer.md +160 -28
  84. package/claude-assets/agents/cfn-dev-team/developers/graphql-specialist.md +101 -19
  85. package/claude-assets/agents/cfn-dev-team/developers/rust-developer.md +108 -14
  86. package/claude-assets/agents/cfn-dev-team/reviewers/{reviewer.md → code-reviewer.md} +95 -8
  87. package/claude-assets/agents/cfn-dev-team/reviewers/quality/code-quality-validator.md +107 -7
  88. package/claude-assets/agents/cfn-dev-team/reviewers/quality/perf-analyzer.md +98 -7
  89. package/claude-assets/agents/cfn-dev-team/reviewers/quality/performance-benchmarker.md +95 -7
  90. package/claude-assets/agents/cfn-dev-team/reviewers/quality/security-specialist.md +136 -9
  91. package/claude-assets/agents/cfn-dev-team/testers/api-testing-specialist.md +108 -1
  92. package/claude-assets/agents/cfn-dev-team/testers/chaos-engineering-specialist.md +107 -13
  93. package/claude-assets/agents/cfn-dev-team/testers/contract-tester.md +737 -0
  94. package/claude-assets/agents/cfn-dev-team/testers/e2e/playwright-tester.md +1 -1
  95. package/claude-assets/agents/cfn-dev-team/testers/integration-tester.md +828 -0
  96. package/claude-assets/agents/cfn-dev-team/testers/interaction-tester.md +106 -7
  97. package/claude-assets/agents/cfn-dev-team/testers/load-testing-specialist.md +77 -0
  98. package/claude-assets/agents/cfn-dev-team/testers/mutation-testing-specialist.md +684 -0
  99. package/claude-assets/agents/cfn-dev-team/testers/playwright-tester.md +110 -1
  100. package/claude-assets/agents/cfn-dev-team/testers/tester.md +94 -7
  101. package/claude-assets/agents/cfn-dev-team/utility/code-booster.md +1 -3
  102. package/claude-assets/agents/cfn-dev-team/utility/epic-creator.md +87 -13
  103. package/claude-assets/agents/cfn-dev-team/utility/memory-leak-specialist.md +103 -7
  104. package/claude-assets/agents/cfn-dev-team/utility/researcher.md +1 -3
  105. package/claude-assets/agents/cfn-dev-team/utility/z-ai-specialist.md +94 -7
  106. package/claude-assets/agents/docker-coordinators/cfn-docker-v3-coordinator.md +46 -0
  107. package/claude-assets/agents/project-only-agents/npm-package-specialist.md +1 -1
  108. package/claude-assets/cfn-extras/skills/advanced-features/cfn-agent-swap/recommend-swap.sh +59 -59
  109. package/claude-assets/cfn-extras/skills/analytics/cfn-improvement-recommender/recommend-improvements.sh +91 -91
  110. package/claude-assets/cfn-extras/skills/analytics/cfn-pattern-extraction/extract-patterns.sh +79 -79
  111. package/claude-assets/cfn-extras/skills/analytics/cfn-retrospective-report/generate-report.sh +100 -100
  112. package/claude-assets/cfn-extras/skills/analytics/cfn-telemetry/start-telemetry.sh +110 -110
  113. package/claude-assets/cfn-extras/skills/deprecated/cfn-ace-system/add-bullet.sh +145 -145
  114. package/claude-assets/cfn-extras/skills/deprecated/cfn-ace-system/log-merge.sh +67 -67
  115. package/claude-assets/cfn-extras/skills/deprecated/cfn-ace-system/monitor-injection-performance.sh +137 -137
  116. package/claude-assets/cfn-extras/skills/deprecated/cfn-ace-system/optimize-injection-pipeline.sh +168 -168
  117. package/claude-assets/cfn-extras/skills/deprecated/cfn-ace-system/query-reflections.sh +35 -35
  118. package/claude-assets/cfn-extras/skills/deprecated/cfn-ace-system/store-reflection.sh +45 -45
  119. package/claude-assets/cfn-extras/skills/deprecated/cfn-ace-system/track-ab-test.sh +41 -41
  120. package/claude-assets/cfn-extras/skills/deprecated/cfn-ace-system/update-reflection.sh +41 -41
  121. package/claude-assets/cfn-extras/skills/deprecated/cfn-cli-setup/validate-cli-environment.sh +191 -191
  122. package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-ad-campaigns/operations/create-campaign.sh +231 -231
  123. package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-ad-campaigns/operations/get-campaign-performance.sh +190 -190
  124. package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-ad-campaigns/operations/pause-campaign.sh +142 -142
  125. package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-ad-campaigns/operations/set-budget.sh +181 -181
  126. package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-ad-campaigns/operations/update-bid-strategy.sh +133 -133
  127. package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-chatbot-conversations/operations/get-conversation-history.sh +121 -121
  128. package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-chatbot-conversations/operations/qualify-lead.sh +156 -156
  129. package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-chatbot-conversations/operations/schedule-demo.sh +181 -181
  130. package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-chatbot-conversations/operations/send-message.sh +137 -137
  131. package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-chatbot-conversations/operations/transfer-to-human.sh +179 -179
  132. package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-sms-campaigns/operations/create-campaign.sh +183 -183
  133. package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-sms-campaigns/operations/get-delivery-status.sh +139 -139
  134. package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-sms-campaigns/operations/opt-out.sh +150 -150
  135. package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-sms-campaigns/operations/schedule-campaign.sh +187 -187
  136. package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-sms-campaigns/operations/send-sms.sh +181 -181
  137. package/claude-assets/cfn-extras/skills/ui-portal/cfn-web-portal/test-web-portal-skill.sh +50 -50
  138. package/claude-assets/cfn-extras/skills/ui-portal/cfn-web-portal/validate-deployment.sh +84 -84
  139. package/claude-assets/cfn-extras/skills/utility/cfn-environment-sanitization/sanitize-environment.sh +243 -243
  140. package/claude-assets/commands/cfn-loop-cli.md +16 -2
  141. package/claude-assets/commands/switch-api.md +31 -10
  142. package/claude-assets/hooks/cfn-lint-sql-injection.sh +61 -0
  143. package/claude-assets/hooks/cfn-post-edit-cfn-retrospective.sh +33 -2
  144. package/claude-assets/hooks/cfn-pre-edit-security-warning.sh +40 -0
  145. package/claude-assets/hooks/detect-hardcoded-credentials.sh +212 -0
  146. package/claude-assets/skills/SKILL_TEMPLATE.md +774 -0
  147. package/claude-assets/skills/agent-lifecycle/execute-lifecycle-hook.sh +84 -113
  148. package/claude-assets/skills/agent-lifecycle/simple-audit.sh +33 -6
  149. package/claude-assets/skills/agent-template-generator/SKILL.md +440 -0
  150. package/claude-assets/skills/agent-template-generator/generate-agent.sh +405 -0
  151. package/claude-assets/skills/agent-validation-linter/SKILL.md +589 -0
  152. package/claude-assets/skills/agent-validation-linter/lint-agents.sh +271 -0
  153. package/claude-assets/skills/bootstrap/bash-fundamentals.md +786 -0
  154. package/claude-assets/skills/bootstrap/database-connection.md +464 -0
  155. package/claude-assets/skills/bootstrap/error-handling.md +580 -0
  156. package/claude-assets/skills/bootstrap/file-operations.md +699 -0
  157. package/claude-assets/skills/bootstrap/skill-loader.md +616 -0
  158. package/claude-assets/skills/bootstrap/sqlite-params.sh +287 -0
  159. package/claude-assets/skills/cfn-agent-spawning/spawn-agent.sh +22 -24
  160. package/claude-assets/skills/cfn-automatic-memory-persistence/test-memory-persistence.sh +17 -16
  161. package/claude-assets/skills/cfn-deployment/SKILL.md +293 -0
  162. package/claude-assets/skills/cfn-deployment/execute.sh +21 -0
  163. package/claude-assets/skills/cfn-docker-agent-spawning/SKILL.md +28 -4
  164. package/claude-assets/skills/cfn-docker-agent-spawning/spawn-agent.sh +3 -1
  165. package/claude-assets/skills/cfn-docker-loop-orchestration/orchestrate.sh +224 -20
  166. package/claude-assets/skills/cfn-environment-sanitization/sanitize-environment.sh +38 -0
  167. package/claude-assets/skills/cfn-error-batching-strategy/lib/core-functions.sh +47 -47
  168. package/claude-assets/skills/cfn-file-operations/SKILL.md +290 -0
  169. package/claude-assets/skills/cfn-file-operations/execute.sh +129 -0
  170. package/claude-assets/skills/cfn-file-operations/lib/atomic-write.sh +294 -0
  171. package/claude-assets/skills/cfn-file-operations/lib/lock.sh +361 -0
  172. package/claude-assets/skills/cfn-file-operations/test.sh +369 -0
  173. package/claude-assets/skills/cfn-log-operations/SKILL.md +308 -0
  174. package/claude-assets/skills/cfn-log-operations/execute.sh +420 -0
  175. package/claude-assets/skills/cfn-log-operations/lib/rotate.sh +406 -0
  176. package/claude-assets/skills/cfn-log-operations/lib/search.sh +448 -0
  177. package/claude-assets/skills/cfn-log-operations/test.sh +394 -0
  178. package/claude-assets/skills/cfn-loop-orchestration/helpers/gate-check.sh +550 -46
  179. package/claude-assets/skills/cfn-loop-orchestration/helpers/parse-test-results.sh +277 -0
  180. package/claude-assets/skills/cfn-loop-orchestration/orchestrate.sh +184 -23
  181. package/claude-assets/skills/cfn-loop-orchestration/security_utils.sh +24 -0
  182. package/claude-assets/skills/cfn-loop-orchestration/test-iteration-context-injection.sh +366 -0
  183. package/claude-assets/skills/cfn-parameterized-queries/SKILL.md +339 -0
  184. package/claude-assets/skills/cfn-playbook/query-playbook.sh +19 -15
  185. package/claude-assets/skills/cfn-playbook/update-playbook.sh +25 -14
  186. package/claude-assets/skills/cfn-process-instrumentation/instrument-process.sh +44 -0
  187. package/claude-assets/skills/cfn-promotion/SKILL.md +305 -0
  188. package/claude-assets/skills/cfn-redis-coordination/CENTRALIZED_REDIS_WRAPPER.md +319 -0
  189. package/claude-assets/skills/cfn-redis-coordination/agent-log.sh +4 -0
  190. package/claude-assets/skills/cfn-redis-coordination/agent-log.sh.bak +124 -0
  191. package/claude-assets/skills/cfn-redis-coordination/agent-recovery.sh +2 -2
  192. package/claude-assets/skills/cfn-redis-coordination/collect-confidence-scores.sh +30 -0
  193. package/claude-assets/skills/cfn-redis-coordination/get-context.sh +33 -0
  194. package/claude-assets/skills/cfn-redis-coordination/get-success-criteria.sh +54 -0
  195. package/claude-assets/skills/cfn-redis-coordination/invoke-waiting-mode.sh +3 -0
  196. package/claude-assets/skills/cfn-redis-coordination/redis-cli-wrapper.sh +24 -3
  197. package/claude-assets/skills/cfn-redis-coordination/redis-functions.sh +33 -0
  198. package/claude-assets/skills/cfn-redis-coordination/report-completion.sh +24 -31
  199. package/claude-assets/skills/cfn-redis-coordination/store-context.sh +4 -0
  200. package/claude-assets/skills/cfn-redis-coordination/store-success-criteria.sh +85 -0
  201. package/claude-assets/skills/cfn-redis-coordination/update-all-scripts.sh +67 -0
  202. package/claude-assets/skills/cfn-skill-loader/SKILL.md +466 -0
  203. package/claude-assets/skills/cfn-skill-loader/execute.sh +344 -0
  204. package/claude-assets/skills/cfn-sqlite-memory/ttl-cleanup.sh +17 -25
  205. package/claude-assets/skills/cfn-task-audit/get-audit-data.sh +42 -21
  206. package/claude-assets/skills/cfn-task-audit/store-task-audit.sh +17 -10
  207. package/claude-assets/skills/cfn-test-runner/detect-regressions.sh +17 -14
  208. package/claude-assets/skills/cfn-test-runner/detect-regressions.sh.backup-1763392821 +55 -0
  209. package/claude-assets/skills/cfn-test-runner/store-benchmarks.sh +17 -19
  210. package/claude-assets/skills/cfn-transparency-middleware/test-e2e.sh +15 -0
  211. package/claude-assets/skills/cfn-transparency-middleware/tests/input-validation.sh +15 -0
  212. package/claude-assets/skills/cfn-utilities/SKILL.md +237 -0
  213. package/claude-assets/skills/cfn-utilities/execute.sh +32 -0
  214. package/claude-assets/skills/cfn-utilities/lib/errors.sh +56 -0
  215. package/claude-assets/skills/cfn-utilities/lib/file-ops.sh +164 -0
  216. package/claude-assets/skills/cfn-utilities/lib/logging.sh +77 -0
  217. package/claude-assets/skills/cfn-utilities/lib/retry.sh +127 -0
  218. package/claude-assets/skills/cfn-utilities/test.sh +317 -0
  219. package/claude-assets/skills/integration/agent-handoff.sh +62 -64
  220. package/claude-assets/skills/json-validation/SKILL.md +431 -0
  221. package/claude-assets/skills/json-validation/test-validate-success-criteria.sh +421 -0
  222. package/claude-assets/skills/json-validation/validate-success-criteria.sh +197 -0
  223. package/claude-assets/skills/redis-coordination/validate-parameters.sh +34 -0
  224. package/claude-assets/skills/workflow-codification/DEPLOY_QUICK_REFERENCE.md +106 -0
  225. package/claude-assets/skills/workflow-codification/PROPAGATE_UPDATE_QUICK_REFERENCE.md +366 -0
  226. package/claude-assets/skills/workflow-codification/deploy-approved-skill.sh +481 -0
  227. package/claude-assets/skills/workflow-codification/deploy-approved-skill.sh.backup-1763392820 +512 -0
  228. package/claude-assets/skills/workflow-codification/lib/security-utils.sh +204 -0
  229. package/claude-assets/skills/workflow-codification/propagate-skill-update.sh +648 -0
  230. package/claude-assets/skills/workflow-codification/propagate-skill-update.sh.backup-1763392820 +664 -0
  231. package/claude-assets/skills/workflow-codification/test-integration.sh +15 -0
  232. package/claude-assets/skills/workflow-codification/test-metadata-update.sh +350 -0
  233. package/claude-assets/skills/workflow-codification/track-cost-savings.sh +55 -14
  234. package/claude-assets/skills/workflow-codification/track-cost-savings.sh.backup-1763392821 +445 -0
  235. package/claude-assets/skills/workflow-codification/track-edge-case.sh +27 -60
  236. package/claude-assets/skills/workflow-codification/workflow-codification.db +0 -0
  237. package/dist/ace/ace-curator.js +10 -2
  238. package/dist/ace/ace-curator.js.map +1 -1
  239. package/dist/ace/ace-generator.js +4 -0
  240. package/dist/ace/ace-generator.js.map +1 -1
  241. package/dist/ace/ace-reflector.js +1 -1
  242. package/dist/ace/ace-reflector.js.map +1 -1
  243. package/dist/ace/context-injection.js +24 -2
  244. package/dist/ace/context-injection.js.map +1 -1
  245. package/dist/agents/agent-loader.js +146 -165
  246. package/dist/agents/agent-loader.js.map +1 -1
  247. package/dist/agents/task-agent-integration.js +1 -1
  248. package/dist/agents/task-agent-integration.js.map +1 -1
  249. package/dist/api/health-endpoints.js +390 -0
  250. package/dist/api/health-endpoints.js.map +1 -0
  251. package/dist/cli/agent-executor.js +4 -1
  252. package/dist/cli/agent-executor.js.map +1 -1
  253. package/dist/cli/agent-prompt-builder.js +89 -1
  254. package/dist/cli/agent-prompt-builder.js.map +1 -1
  255. package/dist/cli/agent-spawn.js +130 -37
  256. package/dist/cli/agent-spawn.js.map +1 -1
  257. package/dist/cli/skill-cache-validator.js +412 -0
  258. package/dist/cli/skill-cache-validator.js.map +1 -0
  259. package/dist/cli/skill-cli.js +991 -0
  260. package/dist/cli/skill-cli.js.map +1 -0
  261. package/dist/cli/skill-execution-logger.js +284 -0
  262. package/dist/cli/skill-execution-logger.js.map +1 -0
  263. package/dist/cli/skill-loader.js +457 -0
  264. package/dist/cli/skill-loader.js.map +1 -0
  265. package/dist/coordination/event-bus.js +2 -2
  266. package/dist/coordination/event-bus.js.map +1 -1
  267. package/dist/coordination/fleet-manager.js +1 -1
  268. package/dist/coordination/fleet-manager.js.map +1 -1
  269. package/dist/coordination/index.js +23 -9
  270. package/dist/coordination/index.js.map +1 -1
  271. package/dist/coordination/types/fleet-manager.types.js.map +1 -1
  272. package/dist/db/migration-manager.js +483 -0
  273. package/dist/db/migration-manager.js.map +1 -0
  274. package/dist/db/skills-query.js +535 -0
  275. package/dist/db/skills-query.js.map +1 -0
  276. package/dist/integration/DatabaseHandoff.js +1 -1
  277. package/dist/integration/DatabaseHandoff.js.map +1 -1
  278. package/dist/jobs/edge-case-analyzer.js +367 -0
  279. package/dist/jobs/edge-case-analyzer.js.map +1 -0
  280. package/dist/jobs/promotion-sla-enforcer.js +288 -0
  281. package/dist/jobs/promotion-sla-enforcer.js.map +1 -0
  282. package/dist/lib/agent-output-parser.js.map +1 -1
  283. package/dist/lib/agent-output-validator.js.map +1 -1
  284. package/dist/lib/agent-workspace.js +281 -0
  285. package/dist/lib/agent-workspace.js.map +1 -0
  286. package/dist/lib/atomic-file-writer.js +377 -0
  287. package/dist/lib/atomic-file-writer.js.map +1 -0
  288. package/dist/lib/backup-manager.js +779 -0
  289. package/dist/lib/backup-manager.js.map +1 -0
  290. package/dist/lib/checkpoint-manager.js +837 -0
  291. package/dist/lib/checkpoint-manager.js.map +1 -0
  292. package/dist/lib/circuit-breaker.js +340 -0
  293. package/dist/lib/circuit-breaker.js.map +1 -0
  294. package/dist/lib/completion-signal-handler.js +243 -0
  295. package/dist/lib/completion-signal-handler.js.map +1 -0
  296. package/dist/lib/config-manager.js +312 -0
  297. package/dist/lib/config-manager.js.map +1 -0
  298. package/dist/lib/config-migrator.js +386 -0
  299. package/dist/lib/config-migrator.js.map +1 -0
  300. package/dist/lib/config-validator.js.map +1 -1
  301. package/dist/lib/correlation-cache.js +311 -0
  302. package/dist/lib/correlation-cache.js.map +1 -0
  303. package/dist/lib/correlation.js +263 -0
  304. package/dist/lib/correlation.js.map +1 -0
  305. package/dist/lib/database-service/connection-pool-manager.js +520 -0
  306. package/dist/lib/database-service/connection-pool-manager.js.map +1 -0
  307. package/dist/lib/database-service/correlation.js +329 -0
  308. package/dist/lib/database-service/correlation.js.map +1 -0
  309. package/dist/lib/database-service/errors.js +120 -0
  310. package/dist/lib/database-service/errors.js.map +1 -0
  311. package/dist/lib/database-service/index.js +168 -0
  312. package/dist/lib/database-service/index.js.map +1 -0
  313. package/dist/lib/database-service/postgres-adapter.js +526 -0
  314. package/dist/lib/database-service/postgres-adapter.js.map +1 -0
  315. package/dist/lib/database-service/redis-adapter.js +360 -0
  316. package/dist/lib/database-service/redis-adapter.js.map +1 -0
  317. package/dist/lib/database-service/sqlite-adapter.js +544 -0
  318. package/dist/lib/database-service/sqlite-adapter.js.map +1 -0
  319. package/dist/lib/database-service/transaction-manager.js +773 -0
  320. package/dist/lib/database-service/transaction-manager.js.map +1 -0
  321. package/dist/lib/database-service/types.js +23 -0
  322. package/dist/lib/database-service/types.js.map +1 -0
  323. package/dist/lib/deadlock-resolver.js +292 -0
  324. package/dist/lib/deadlock-resolver.js.map +1 -0
  325. package/dist/lib/distributed-lock.js +451 -0
  326. package/dist/lib/distributed-lock.js.map +1 -0
  327. package/dist/lib/edge-case-deduplicator.js +227 -0
  328. package/dist/lib/edge-case-deduplicator.js.map +1 -0
  329. package/dist/lib/encryption-manager.js +322 -0
  330. package/dist/lib/encryption-manager.js.map +1 -0
  331. package/dist/lib/error-aggregator.js +234 -0
  332. package/dist/lib/error-aggregator.js.map +1 -0
  333. package/dist/lib/errors.js +287 -0
  334. package/dist/lib/errors.js.map +1 -0
  335. package/dist/lib/file-lock-manager.js +578 -0
  336. package/dist/lib/file-lock-manager.js.map +1 -0
  337. package/dist/lib/file-operations.js +367 -0
  338. package/dist/lib/file-operations.js.map +1 -0
  339. package/dist/lib/idempotent-write.js +237 -0
  340. package/dist/lib/idempotent-write.js.map +1 -0
  341. package/dist/lib/integration-schema-validator.js +522 -0
  342. package/dist/lib/integration-schema-validator.js.map +1 -0
  343. package/dist/lib/lock-health-monitor.js +298 -0
  344. package/dist/lib/lock-health-monitor.js.map +1 -0
  345. package/dist/lib/log-shipper.js +422 -0
  346. package/dist/lib/log-shipper.js.map +1 -0
  347. package/dist/lib/logging.js +146 -0
  348. package/dist/lib/logging.js.map +1 -0
  349. package/dist/lib/message-deduplicator.js +439 -0
  350. package/dist/lib/message-deduplicator.js.map +1 -0
  351. package/dist/lib/multi-system-query.js +604 -0
  352. package/dist/lib/multi-system-query.js.map +1 -0
  353. package/dist/lib/orphan-detector.js +332 -0
  354. package/dist/lib/orphan-detector.js.map +1 -0
  355. package/dist/lib/password-generator.js +166 -0
  356. package/dist/lib/password-generator.js.map +1 -0
  357. package/dist/lib/path-validator.js +429 -0
  358. package/dist/lib/path-validator.js.map +1 -0
  359. package/dist/lib/query-translator.js +905 -0
  360. package/dist/lib/query-translator.js.map +1 -0
  361. package/dist/lib/queue-recovery.js +469 -0
  362. package/dist/lib/queue-recovery.js.map +1 -0
  363. package/dist/lib/redis-queue-manager.js +512 -0
  364. package/dist/lib/redis-queue-manager.js.map +1 -0
  365. package/dist/lib/reflection-archiver.js +272 -0
  366. package/dist/lib/reflection-archiver.js.map +1 -0
  367. package/dist/lib/retry-manager.js +453 -0
  368. package/dist/lib/retry-manager.js.map +1 -0
  369. package/dist/lib/retry.js +262 -0
  370. package/dist/lib/retry.js.map +1 -0
  371. package/dist/lib/schema-transform.js +695 -0
  372. package/dist/lib/schema-transform.js.map +1 -0
  373. package/dist/lib/schema-validator.js +491 -0
  374. package/dist/lib/schema-validator.js.map +1 -0
  375. package/dist/lib/skill-cache.js +297 -0
  376. package/dist/lib/skill-cache.js.map +1 -0
  377. package/dist/lib/skill-content-manager.js +337 -0
  378. package/dist/lib/skill-content-manager.js.map +1 -0
  379. package/dist/lib/skill-frontmatter-parser.js +237 -0
  380. package/dist/lib/skill-frontmatter-parser.js.map +1 -0
  381. package/dist/lib/skill-git-integration.js +275 -0
  382. package/dist/lib/skill-git-integration.js.map +1 -0
  383. package/dist/lib/skill-markdown-validator.js +396 -0
  384. package/dist/lib/skill-markdown-validator.js.map +1 -0
  385. package/dist/lib/skill-output-parser.js +312 -0
  386. package/dist/lib/skill-output-parser.js.map +1 -0
  387. package/dist/lib/unified-query-api.js +467 -0
  388. package/dist/lib/unified-query-api.js.map +1 -0
  389. package/dist/middleware/auth-middleware.js +350 -0
  390. package/dist/middleware/auth-middleware.js.map +1 -0
  391. package/dist/middleware/schema-validation.js +347 -0
  392. package/dist/middleware/schema-validation.js.map +1 -0
  393. package/dist/providers/anthropic-provider.js +1 -1
  394. package/dist/providers/anthropic-provider.js.map +1 -1
  395. package/dist/providers/provider-factory.js +2 -2
  396. package/dist/providers/provider-factory.js.map +1 -1
  397. package/dist/services/edge-case-analyzer.js +321 -0
  398. package/dist/services/edge-case-analyzer.js.map +1 -0
  399. package/dist/services/edge-case-deduplicator.js +266 -0
  400. package/dist/services/edge-case-deduplicator.js.map +1 -0
  401. package/dist/services/edge-case-detector.js +337 -0
  402. package/dist/services/edge-case-detector.js.map +1 -0
  403. package/dist/services/edge-case-tracker.js +547 -0
  404. package/dist/services/edge-case-tracker.js.map +1 -0
  405. package/dist/services/health-check-system.js +586 -0
  406. package/dist/services/health-check-system.js.map +1 -0
  407. package/dist/services/metrics-logger.js +412 -0
  408. package/dist/services/metrics-logger.js.map +1 -0
  409. package/dist/services/patch-generator.js +378 -0
  410. package/dist/services/patch-generator.js.map +1 -0
  411. package/dist/services/patch-validator.js +337 -0
  412. package/dist/services/patch-validator.js.map +1 -0
  413. package/dist/services/performance-monitor.js +811 -0
  414. package/dist/services/performance-monitor.js.map +1 -0
  415. package/dist/services/promotion-pipeline.js +918 -0
  416. package/dist/services/promotion-pipeline.js.map +1 -0
  417. package/dist/services/promotion-validator.js +394 -0
  418. package/dist/services/promotion-validator.js.map +1 -0
  419. package/dist/services/reflection-logger.js +388 -0
  420. package/dist/services/reflection-logger.js.map +1 -0
  421. package/dist/services/skill-deployment.js +472 -0
  422. package/dist/services/skill-deployment.js.map +1 -0
  423. package/dist/services/skill-loader.js +427 -0
  424. package/dist/services/skill-loader.js.map +1 -0
  425. package/dist/services/skill-promotion.js +372 -0
  426. package/dist/services/skill-promotion.js.map +1 -0
  427. package/dist/services/skill-validator.js +454 -0
  428. package/dist/services/skill-validator.js.map +1 -0
  429. package/dist/services/skill-versioning.js +244 -0
  430. package/dist/services/skill-versioning.js.map +1 -0
  431. package/dist/services/workspace-supervisor.js +597 -0
  432. package/dist/services/workspace-supervisor.js.map +1 -0
  433. package/dist/types/edge-case.js +45 -0
  434. package/dist/types/edge-case.js.map +1 -0
  435. package/package.json +201 -177
  436. package/readme/README.md +19 -4
  437. package/scripts/backup-cleanup.sh +627 -0
  438. package/scripts/cleanup-workspaces.sh +412 -0
  439. package/scripts/cleanup-yaml-configs.sh +141 -0
  440. package/scripts/deploy-approved-skills.sh +263 -0
  441. package/scripts/health-check.sh +447 -0
  442. package/scripts/log-aggregator.sh +554 -0
  443. package/scripts/log-monitor.sh +629 -0
  444. package/scripts/manage-agent-workspaces.sh +434 -0
  445. package/scripts/migrate-schema.sh +533 -0
  446. package/scripts/promote-staged-skills.sh +423 -0
  447. package/scripts/verify-no-secrets.sh +88 -35
  448. package/.claude/cfn-extras/agents/deprecated-coordinators/adaptive-coordinator.md.backup +0 -161
  449. package/.claude/cfn-extras/agents/deprecated-coordinators/blocking-coordinator-example.md.backup +0 -728
  450. package/.claude/cfn-extras/agents/deprecated-coordinators/mesh-coordinator.md.backup +0 -131
  451. package/.claude/skills/agent-lifecycle/SKILL.md +0 -60
  452. package/.claude/skills/agent-lifecycle/execute-lifecycle-hook.sh +0 -573
  453. package/.claude/skills/agent-lifecycle/simple-audit.sh +0 -31
  454. package/.claude/skills/cfn-agent-spawning/spawn-agent.sh.backup +0 -273
  455. package/.claude/skills/cfn-loop-orchestration/orchestrate.sh.backup +0 -949
  456. package/README.md.backup_before_replace +0 -781
  457. package/claude-assets/cfn-extras/agents/deprecated-coordinators/adaptive-coordinator.md.backup +0 -161
  458. package/claude-assets/cfn-extras/agents/deprecated-coordinators/blocking-coordinator-example.md.backup +0 -728
  459. package/claude-assets/cfn-extras/agents/deprecated-coordinators/mesh-coordinator.md.backup +0 -131
  460. package/claude-assets/skills/cfn-agent-spawning/spawn-agent.sh.backup +0 -273
  461. package/claude-assets/skills/cfn-loop-orchestration/orchestrate.sh.backup +0 -949
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/services/health-check-system.ts"],"sourcesContent":["/**\r\n * Health Check System\r\n *\r\n * Comprehensive health monitoring for all critical services:\r\n * - Database connectivity and latency\r\n * - Redis connectivity and performance\r\n * - File system availability and disk space\r\n * - Active agent count and queue depth\r\n *\r\n * Provides sub-second health detection (<1s overall response time)\r\n * and detailed health reports for monitoring integration.\r\n *\r\n * Part of Task P2-4.1: Comprehensive Health Checks\r\n */\r\n\r\nimport { getDatabaseService } from '../lib/database-service.js';\r\nimport { RedisQueueManager } from '../lib/redis-queue-manager.js';\r\nimport { StandardError, ErrorCode } from '../lib/errors.js';\r\nimport fs from 'fs';\r\nimport os from 'os';\r\nimport util from 'util';\r\n\r\n/**\r\n * Health status enumeration\r\n */\r\nexport enum HealthStatus {\r\n HEALTHY = 'healthy',\r\n DEGRADED = 'degraded',\r\n UNHEALTHY = 'unhealthy',\r\n}\r\n\r\n/**\r\n * Individual health check result\r\n */\r\nexport interface HealthCheck {\r\n /**\r\n * Service name\r\n */\r\n name: string;\r\n\r\n /**\r\n * Current health status\r\n */\r\n status: 'healthy' | 'degraded' | 'unhealthy';\r\n\r\n /**\r\n * Response latency in milliseconds\r\n */\r\n latency: number;\r\n\r\n /**\r\n * Human-readable health status message\r\n */\r\n message?: string;\r\n\r\n /**\r\n * Timestamp of the health check\r\n */\r\n timestamp: Date;\r\n\r\n /**\r\n * Dependent service health checks (if aggregated)\r\n */\r\n dependencies?: HealthCheck[];\r\n\r\n /**\r\n * Additional metadata about the service\r\n */\r\n metadata?: Record<string, any>;\r\n}\r\n\r\n/**\r\n * Detailed health report including all services and metrics\r\n */\r\nexport interface DetailedHealthReport {\r\n /**\r\n * Report generation timestamp\r\n */\r\n timestamp: Date;\r\n\r\n /**\r\n * Overall system health status\r\n */\r\n overallStatus: 'healthy' | 'degraded' | 'unhealthy';\r\n\r\n /**\r\n * Total health check latency in milliseconds\r\n */\r\n latency: number;\r\n\r\n /**\r\n * Individual service health checks\r\n */\r\n services: {\r\n database: HealthCheck;\r\n redis: HealthCheck;\r\n filesystem: HealthCheck;\r\n agents: HealthCheck;\r\n };\r\n\r\n /**\r\n * Alerts or warnings\r\n */\r\n alerts?: string[];\r\n}\r\n\r\n/**\r\n * Aggregated health statistics from all services\r\n */\r\nexport interface AggregatedHealthStats {\r\n /**\r\n * Timestamp when stats were collected\r\n */\r\n timestamp: Date;\r\n\r\n /**\r\n * Overall system health status\r\n */\r\n overallStatus: 'healthy' | 'degraded' | 'unhealthy';\r\n\r\n /**\r\n * Total aggregation latency in milliseconds\r\n */\r\n latency: number;\r\n\r\n /**\r\n * Average latency across all services in milliseconds\r\n */\r\n averageServiceLatency: number;\r\n\r\n /**\r\n * Service count summary\r\n */\r\n serviceCount: {\r\n total: number;\r\n healthy: number;\r\n degraded: number;\r\n unhealthy: number;\r\n };\r\n\r\n /**\r\n * Individual service summaries\r\n */\r\n services: {\r\n database: {\r\n status: 'healthy' | 'degraded' | 'unhealthy';\r\n latency: number;\r\n message?: string;\r\n };\r\n redis: {\r\n status: 'healthy' | 'degraded' | 'unhealthy';\r\n latency: number;\r\n message?: string;\r\n };\r\n filesystem: {\r\n status: 'healthy' | 'degraded' | 'unhealthy';\r\n latency: number;\r\n message?: string;\r\n };\r\n agents: {\r\n status: 'healthy' | 'degraded' | 'unhealthy';\r\n latency: number;\r\n message?: string;\r\n };\r\n };\r\n\r\n /**\r\n * Detailed metadata from all services\r\n */\r\n metadata: Record<string, any>;\r\n\r\n /**\r\n * Warning messages from degraded services\r\n */\r\n warnings: string[];\r\n\r\n /**\r\n * Error messages from unhealthy services\r\n */\r\n errors: string[];\r\n}\r\n\r\n/**\r\n * Health check system configuration\r\n */\r\nexport interface HealthCheckConfig {\r\n /**\r\n * Database check timeout in milliseconds (default: 500)\r\n */\r\n databaseTimeout?: number;\r\n\r\n /**\r\n * Redis check timeout in milliseconds (default: 500)\r\n */\r\n redisTimeout?: number;\r\n\r\n /**\r\n * File system check timeout in milliseconds (default: 500)\r\n */\r\n filesystemTimeout?: number;\r\n\r\n /**\r\n * Agents check timeout in milliseconds (default: 500)\r\n */\r\n agentsTimeout?: number;\r\n\r\n /**\r\n * Disk usage warning threshold percentage (default: 80)\r\n */\r\n diskUsageWarnThreshold?: number;\r\n\r\n /**\r\n * Disk usage critical threshold percentage (default: 95)\r\n */\r\n diskUsageCriticalThreshold?: number;\r\n\r\n /**\r\n * Queue depth warning threshold (default: 100)\r\n */\r\n queueDepthWarnThreshold?: number;\r\n\r\n /**\r\n * Queue depth critical threshold (default: 500)\r\n */\r\n queueDepthCriticalThreshold?: number;\r\n}\r\n\r\n/**\r\n * Comprehensive health check system\r\n */\r\nexport class HealthCheckSystem {\r\n private config: Required<HealthCheckConfig>;\r\n private redisManager: RedisQueueManager | null = null;\r\n\r\n constructor(config?: HealthCheckConfig) {\r\n this.config = {\r\n databaseTimeout: config?.databaseTimeout ?? 500,\r\n redisTimeout: config?.redisTimeout ?? 500,\r\n filesystemTimeout: config?.filesystemTimeout ?? 500,\r\n agentsTimeout: config?.agentsTimeout ?? 500,\r\n diskUsageWarnThreshold: config?.diskUsageWarnThreshold ?? 80,\r\n diskUsageCriticalThreshold: config?.diskUsageCriticalThreshold ?? 95,\r\n queueDepthWarnThreshold: config?.queueDepthWarnThreshold ?? 100,\r\n queueDepthCriticalThreshold: config?.queueDepthCriticalThreshold ?? 500,\r\n };\r\n\r\n try {\r\n this.redisManager = new RedisQueueManager();\r\n } catch (error) {\r\n // Redis initialization may fail in test environments\r\n // Will be handled gracefully in checkRedis()\r\n }\r\n }\r\n\r\n /**\r\n * Check database health\r\n * Verifies connectivity and measures response latency\r\n */\r\n async checkDatabase(): Promise<HealthCheck> {\r\n const startTime = Date.now();\r\n\r\n try {\r\n const db = getDatabaseService();\r\n\r\n // Create a timeout promise\r\n const timeoutPromise = new Promise((_, reject) =>\r\n setTimeout(() => reject(new Error('Database check timeout')), this.config.databaseTimeout)\r\n );\r\n\r\n // Race between actual check and timeout\r\n await Promise.race([\r\n (async () => {\r\n // Simple connectivity check using a lightweight query\r\n await db.query('SELECT 1');\r\n })(),\r\n timeoutPromise,\r\n ]);\r\n\r\n const latency = Date.now() - startTime;\r\n\r\n return {\r\n name: 'database',\r\n status: HealthStatus.HEALTHY,\r\n latency,\r\n message: 'Database connected and responding',\r\n timestamp: new Date(),\r\n metadata: {\r\n responseTime: latency,\r\n type: 'postgresql',\r\n },\r\n };\r\n } catch (error) {\r\n const latency = Date.now() - startTime;\r\n const message =\r\n error instanceof Error\r\n ? error.message\r\n : 'Unknown database error';\r\n\r\n return {\r\n name: 'database',\r\n status: latency > this.config.databaseTimeout\r\n ? HealthStatus.UNHEALTHY\r\n : HealthStatus.UNHEALTHY,\r\n latency,\r\n message: `Database check failed: ${message}`,\r\n timestamp: new Date(),\r\n metadata: {\r\n error: message,\r\n timeout: latency > this.config.databaseTimeout,\r\n },\r\n };\r\n }\r\n }\r\n\r\n /**\r\n * Check Redis health\r\n * Verifies connectivity and measures ping response time\r\n */\r\n async checkRedis(): Promise<HealthCheck> {\r\n const startTime = Date.now();\r\n\r\n try {\r\n if (!this.redisManager) {\r\n throw new Error('Redis manager not initialized');\r\n }\r\n\r\n // Create a timeout promise\r\n const timeoutPromise = new Promise((_, reject) =>\r\n setTimeout(() => reject(new Error('Redis check timeout')), this.config.redisTimeout)\r\n );\r\n\r\n // Race between actual check and timeout\r\n await Promise.race([\r\n this.redisManager.ping(),\r\n timeoutPromise,\r\n ]);\r\n\r\n const latency = Date.now() - startTime;\r\n\r\n // Get additional metrics\r\n let metadata: Record<string, any> = { responseTime: latency };\r\n\r\n try {\r\n const stats = await this.redisManager.getStats();\r\n metadata = { ...metadata, ...stats };\r\n } catch {\r\n // If stats fail, just continue with basic response time\r\n }\r\n\r\n return {\r\n name: 'redis',\r\n status: HealthStatus.HEALTHY,\r\n latency,\r\n message: 'Redis responding to PING',\r\n timestamp: new Date(),\r\n metadata,\r\n };\r\n } catch (error) {\r\n const latency = Date.now() - startTime;\r\n const message =\r\n error instanceof Error\r\n ? error.message\r\n : 'Unknown Redis error';\r\n\r\n const status =\r\n message.includes('timeout') || latency > this.config.redisTimeout\r\n ? HealthStatus.UNHEALTHY\r\n : HealthStatus.UNHEALTHY;\r\n\r\n return {\r\n name: 'redis',\r\n status,\r\n latency,\r\n message: `Redis check failed: ${message}`,\r\n timestamp: new Date(),\r\n metadata: {\r\n error: message,\r\n timeout: latency > this.config.redisTimeout,\r\n },\r\n };\r\n }\r\n }\r\n\r\n /**\r\n * Check file system health\r\n * Verifies disk space and write permissions\r\n */\r\n async checkFileSystem(): Promise<HealthCheck> {\r\n const startTime = Date.now();\r\n\r\n try {\r\n // Create a timeout promise\r\n const timeoutPromise = new Promise((_, reject) =>\r\n setTimeout(() => reject(new Error('Filesystem check timeout')), this.config.filesystemTimeout)\r\n );\r\n\r\n // Race between actual check and timeout\r\n const result = await Promise.race([\r\n this.getFileSystemMetrics(),\r\n timeoutPromise,\r\n ]) as FileSystemMetrics;\r\n\r\n const latency = Date.now() - startTime;\r\n\r\n // Determine health status based on disk usage\r\n let status: 'healthy' | 'degraded' | 'unhealthy' = HealthStatus.HEALTHY;\r\n let message = 'File system healthy';\r\n\r\n if (result.diskUsagePercent > this.config.diskUsageCriticalThreshold) {\r\n status = HealthStatus.UNHEALTHY;\r\n message = `Critical disk usage: ${result.diskUsagePercent.toFixed(1)}%`;\r\n } else if (result.diskUsagePercent > this.config.diskUsageWarnThreshold) {\r\n status = HealthStatus.DEGRADED;\r\n message = `Degraded disk usage: ${result.diskUsagePercent.toFixed(1)}%`;\r\n }\r\n\r\n if (!result.writePermission) {\r\n status = HealthStatus.UNHEALTHY;\r\n message = 'Write permission denied on temp directory';\r\n }\r\n\r\n return {\r\n name: 'filesystem',\r\n status,\r\n latency,\r\n message,\r\n timestamp: new Date(),\r\n metadata: {\r\n diskUsagePercent: result.diskUsagePercent,\r\n writePermission: result.writePermission,\r\n freeSpaceMB: result.freeSpaceMB,\r\n totalSpaceMB: result.totalSpaceMB,\r\n },\r\n };\r\n } catch (error) {\r\n const latency = Date.now() - startTime;\r\n const message =\r\n error instanceof Error\r\n ? error.message\r\n : 'Unknown filesystem error';\r\n\r\n return {\r\n name: 'filesystem',\r\n status: HealthStatus.UNHEALTHY,\r\n latency,\r\n message: `File system check failed: ${message}`,\r\n timestamp: new Date(),\r\n metadata: {\r\n error: message,\r\n },\r\n };\r\n }\r\n }\r\n\r\n /**\r\n * Check agent health\r\n * Verifies active agent count and queue depth\r\n */\r\n async checkAgents(): Promise<HealthCheck> {\r\n const startTime = Date.now();\r\n\r\n try {\r\n // Create a timeout promise\r\n const timeoutPromise = new Promise((_, reject) =>\r\n setTimeout(() => reject(new Error('Agents check timeout')), this.config.agentsTimeout)\r\n );\r\n\r\n // Race between actual check and timeout\r\n const metrics = await Promise.race([\r\n this.getAgentMetrics(),\r\n timeoutPromise,\r\n ]) as AgentMetrics;\r\n\r\n const latency = Date.now() - startTime;\r\n\r\n // Determine health status based on queue depth\r\n let status: 'healthy' | 'degraded' | 'unhealthy' = HealthStatus.HEALTHY;\r\n let message = `${metrics.activeAgentCount} agents active`;\r\n\r\n if (metrics.queueDepth > this.config.queueDepthCriticalThreshold) {\r\n status = HealthStatus.UNHEALTHY;\r\n message = `Critical queue depth: ${metrics.queueDepth} tasks`;\r\n } else if (metrics.queueDepth > this.config.queueDepthWarnThreshold) {\r\n status = HealthStatus.DEGRADED;\r\n message = `High queue depth: ${metrics.queueDepth} tasks`;\r\n }\r\n\r\n return {\r\n name: 'agents',\r\n status,\r\n latency,\r\n message,\r\n timestamp: new Date(),\r\n metadata: {\r\n activeAgentCount: metrics.activeAgentCount,\r\n queueDepth: metrics.queueDepth,\r\n },\r\n };\r\n } catch (error) {\r\n const latency = Date.now() - startTime;\r\n const message =\r\n error instanceof Error\r\n ? error.message\r\n : 'Unknown agent error';\r\n\r\n return {\r\n name: 'agents',\r\n status: HealthStatus.UNHEALTHY,\r\n latency,\r\n message: `Agent check failed: ${message}`,\r\n timestamp: new Date(),\r\n metadata: {\r\n error: message,\r\n },\r\n };\r\n }\r\n }\r\n\r\n /**\r\n * Get overall system health\r\n * Aggregates all service health checks\r\n */\r\n async getOverallHealth(): Promise<HealthCheck> {\r\n const overallStartTime = Date.now();\r\n\r\n const [database, redis, filesystem, agents] = await Promise.all([\r\n this.checkDatabase(),\r\n this.checkRedis(),\r\n this.checkFileSystem(),\r\n this.checkAgents(),\r\n ]);\r\n\r\n const dependencies = [database, redis, filesystem, agents];\r\n\r\n // Determine overall status\r\n // UNHEALTHY if any service is unhealthy\r\n // DEGRADED if any service is degraded\r\n // HEALTHY if all services are healthy\r\n let overallStatus: 'healthy' | 'degraded' | 'unhealthy' = HealthStatus.HEALTHY;\r\n const unhealthyServices = dependencies.filter((d) => d.status === HealthStatus.UNHEALTHY);\r\n const degradedServices = dependencies.filter((d) => d.status === HealthStatus.DEGRADED);\r\n\r\n if (unhealthyServices.length > 0) {\r\n overallStatus = HealthStatus.UNHEALTHY;\r\n } else if (degradedServices.length > 0) {\r\n overallStatus = HealthStatus.DEGRADED;\r\n }\r\n\r\n const latency = Date.now() - overallStartTime;\r\n const statusMessage =\r\n unhealthyServices.length > 0\r\n ? `${unhealthyServices.length} service(s) unhealthy`\r\n : degradedServices.length > 0\r\n ? `${degradedServices.length} service(s) degraded`\r\n : 'All services healthy';\r\n\r\n return {\r\n name: 'overall',\r\n status: overallStatus,\r\n latency,\r\n message: statusMessage,\r\n timestamp: new Date(),\r\n dependencies,\r\n };\r\n }\r\n\r\n /**\r\n * Get detailed health report\r\n * Includes all services and aggregated metrics\r\n */\r\n async getDetailedHealthReport(): Promise<DetailedHealthReport> {\r\n const reportStartTime = Date.now();\r\n\r\n const overall = await this.getOverallHealth();\r\n\r\n const report: DetailedHealthReport = {\r\n timestamp: new Date(),\r\n overallStatus: overall.status as 'healthy' | 'degraded' | 'unhealthy',\r\n latency: Date.now() - reportStartTime,\r\n services: {\r\n database: overall.dependencies![0],\r\n redis: overall.dependencies![1],\r\n filesystem: overall.dependencies![2],\r\n agents: overall.dependencies![3],\r\n },\r\n alerts: [],\r\n };\r\n\r\n // Build alerts\r\n if (report.overallStatus === HealthStatus.UNHEALTHY) {\r\n const unhealthy = overall.dependencies!.filter((d) => d.status === HealthStatus.UNHEALTHY);\r\n report.alerts = unhealthy.map((s) => `${s.name}: ${s.message}`);\r\n }\r\n\r\n if (report.overallStatus === HealthStatus.DEGRADED) {\r\n const degraded = overall.dependencies!.filter((d) => d.status === HealthStatus.DEGRADED);\r\n report.alerts = degraded.map((s) => `${s.name}: ${s.message}`);\r\n }\r\n\r\n return report;\r\n }\r\n\r\n /**\r\n * Fast ping check for basic connectivity\r\n * Returns in <100ms for Kubernetes probes and dashboards\r\n *\r\n * This is a lightweight check that verifies the system is responsive\r\n * without performing expensive operations like database queries.\r\n *\r\n * @param timeout - Optional timeout in milliseconds (default: 100ms)\r\n * @returns HealthCheck with basic connectivity status\r\n * @throws StandardError if ping fails or timeout exceeded\r\n */\r\n async ping(timeout: number = 100): Promise<HealthCheck> {\r\n const startTime = Date.now();\r\n\r\n try {\r\n // Create a timeout promise\r\n const timeoutPromise = new Promise<never>((_, reject) =>\r\n setTimeout(() => reject(\r\n new StandardError(\r\n ErrorCode.OPERATION_TIMEOUT,\r\n `Ping timeout after ${timeout}ms`,\r\n { timeout }\r\n )\r\n ), timeout)\r\n );\r\n\r\n // Race between basic checks and timeout\r\n await Promise.race([\r\n // Minimal checks - just verify system is responsive\r\n (async () => {\r\n // Check if we can access Date (basic runtime check)\r\n const now = Date.now();\r\n\r\n // Verify process is alive\r\n if (typeof process === 'undefined') {\r\n throw new StandardError(\r\n ErrorCode.UNKNOWN_ERROR,\r\n 'Process runtime not available',\r\n { check: 'ping' }\r\n );\r\n }\r\n\r\n // Verify we have memory available\r\n const memUsage = process.memoryUsage();\r\n if (memUsage.heapUsed > memUsage.heapTotal * 0.95) {\r\n throw new StandardError(\r\n ErrorCode.UNKNOWN_ERROR,\r\n 'Memory critically low',\r\n {\r\n heapUsed: memUsage.heapUsed,\r\n heapTotal: memUsage.heapTotal,\r\n percentUsed: (memUsage.heapUsed / memUsage.heapTotal) * 100\r\n }\r\n );\r\n }\r\n })(),\r\n timeoutPromise,\r\n ]);\r\n\r\n const latency = Date.now() - startTime;\r\n\r\n // Ensure we're under the target response time\r\n if (latency >= timeout) {\r\n throw new StandardError(\r\n ErrorCode.OPERATION_TIMEOUT,\r\n `Ping exceeded target response time: ${latency}ms >= ${timeout}ms`,\r\n { latency, timeout }\r\n );\r\n }\r\n\r\n return {\r\n name: 'ping',\r\n status: HealthStatus.HEALTHY,\r\n latency,\r\n message: 'System responsive',\r\n timestamp: new Date(),\r\n metadata: {\r\n responseTime: latency,\r\n memoryUsage: process.memoryUsage(),\r\n uptime: process.uptime(),\r\n },\r\n };\r\n } catch (error) {\r\n const latency = Date.now() - startTime;\r\n\r\n if (error instanceof StandardError) {\r\n throw error;\r\n }\r\n\r\n const message = error instanceof Error ? error.message : 'Unknown ping error';\r\n\r\n throw new StandardError(\r\n ErrorCode.UNKNOWN_ERROR,\r\n `Ping failed: ${message}`,\r\n { latency, timeout },\r\n error instanceof Error ? error : undefined\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Get aggregated health statistics from all endpoints\r\n * Provides a comprehensive view of system health metrics\r\n *\r\n * @param timeout - Optional timeout in milliseconds (default: 5000ms)\r\n * @returns AggregatedHealthStats with metrics from all services\r\n */\r\n async getAggregateStats(timeout: number = 5000): Promise<AggregatedHealthStats> {\r\n const startTime = Date.now();\r\n\r\n try {\r\n // Create a timeout promise\r\n const timeoutPromise = new Promise<never>((_, reject) =>\r\n setTimeout(() => reject(\r\n new StandardError(\r\n ErrorCode.OPERATION_TIMEOUT,\r\n `Aggregate stats timeout after ${timeout}ms`,\r\n { timeout }\r\n )\r\n ), timeout)\r\n );\r\n\r\n // Race between collecting all stats and timeout\r\n const result = await Promise.race([\r\n (async () => {\r\n // Collect all health checks in parallel\r\n const [database, redis, filesystem, agents] = await Promise.all([\r\n this.checkDatabase(),\r\n this.checkRedis(),\r\n this.checkFileSystem(),\r\n this.checkAgents(),\r\n ]);\r\n\r\n return { database, redis, filesystem, agents };\r\n })(),\r\n timeoutPromise,\r\n ]);\r\n\r\n const latency = Date.now() - startTime;\r\n\r\n // Calculate aggregate metrics\r\n const services = [result.database, result.redis, result.filesystem, result.agents];\r\n const healthyCount = services.filter((s) => s.status === HealthStatus.HEALTHY).length;\r\n const degradedCount = services.filter((s) => s.status === HealthStatus.DEGRADED).length;\r\n const unhealthyCount = services.filter((s) => s.status === HealthStatus.UNHEALTHY).length;\r\n\r\n // Determine overall status\r\n let overallStatus: 'healthy' | 'degraded' | 'unhealthy' = HealthStatus.HEALTHY;\r\n if (unhealthyCount > 0) {\r\n overallStatus = HealthStatus.UNHEALTHY;\r\n } else if (degradedCount > 0) {\r\n overallStatus = HealthStatus.DEGRADED;\r\n }\r\n\r\n // Calculate average latency\r\n const totalLatency = services.reduce((sum, s) => sum + s.latency, 0);\r\n const averageLatency = totalLatency / services.length;\r\n\r\n // Collect metadata from all services\r\n const metadata: Record<string, any> = {\r\n database: result.database.metadata,\r\n redis: result.redis.metadata,\r\n filesystem: result.filesystem.metadata,\r\n agents: result.agents.metadata,\r\n };\r\n\r\n // Build warnings list\r\n const warnings: string[] = [];\r\n if (degradedCount > 0) {\r\n const degradedServices = services.filter((s) => s.status === HealthStatus.DEGRADED);\r\n warnings.push(...degradedServices.map((s) => `${s.name}: ${s.message}`));\r\n }\r\n\r\n // Build errors list\r\n const errors: string[] = [];\r\n if (unhealthyCount > 0) {\r\n const unhealthyServices = services.filter((s) => s.status === HealthStatus.UNHEALTHY);\r\n errors.push(...unhealthyServices.map((s) => `${s.name}: ${s.message}`));\r\n }\r\n\r\n return {\r\n timestamp: new Date(),\r\n overallStatus,\r\n latency,\r\n averageServiceLatency: averageLatency,\r\n serviceCount: {\r\n total: services.length,\r\n healthy: healthyCount,\r\n degraded: degradedCount,\r\n unhealthy: unhealthyCount,\r\n },\r\n services: {\r\n database: {\r\n status: result.database.status,\r\n latency: result.database.latency,\r\n message: result.database.message,\r\n },\r\n redis: {\r\n status: result.redis.status,\r\n latency: result.redis.latency,\r\n message: result.redis.message,\r\n },\r\n filesystem: {\r\n status: result.filesystem.status,\r\n latency: result.filesystem.latency,\r\n message: result.filesystem.message,\r\n },\r\n agents: {\r\n status: result.agents.status,\r\n latency: result.agents.latency,\r\n message: result.agents.message,\r\n },\r\n },\r\n metadata,\r\n warnings,\r\n errors,\r\n };\r\n } catch (error) {\r\n const latency = Date.now() - startTime;\r\n\r\n if (error instanceof StandardError) {\r\n throw error;\r\n }\r\n\r\n const message = error instanceof Error ? error.message : 'Unknown aggregation error';\r\n\r\n throw new StandardError(\r\n ErrorCode.UNKNOWN_ERROR,\r\n `Failed to aggregate health stats: ${message}`,\r\n { latency, timeout },\r\n error instanceof Error ? error : undefined\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Get file system metrics\r\n * Private helper for filesystem check\r\n */\r\n private async getFileSystemMetrics(): Promise<FileSystemMetrics> {\r\n return new Promise((resolve, reject) => {\r\n // Get disk usage statistics\r\n const tempDir = os.tmpdir();\r\n const stat = fs.statSync(tempDir);\r\n\r\n // Use statvfs to get disk space information\r\n fs.statfs(tempDir, (err, stats) => {\r\n if (err) {\r\n reject(err);\r\n return;\r\n }\r\n\r\n const totalBlocks = stats.blocks;\r\n const availableBlocks = stats.bavail;\r\n const blockSize = stats.bsize;\r\n\r\n const totalSpaceMB = (totalBlocks * blockSize) / (1024 * 1024);\r\n const availableSpaceMB = (availableBlocks * blockSize) / (1024 * 1024);\r\n const usedSpaceMB = totalSpaceMB - availableSpaceMB;\r\n const diskUsagePercent = (usedSpaceMB / totalSpaceMB) * 100;\r\n\r\n // Check write permission by attempting to create a temp file\r\n const testFile = `${tempDir}/.health-check-test-${Date.now()}`;\r\n let writePermission = false;\r\n\r\n try {\r\n fs.writeFileSync(testFile, 'health-check-test');\r\n fs.unlinkSync(testFile);\r\n writePermission = true;\r\n } catch {\r\n writePermission = false;\r\n }\r\n\r\n resolve({\r\n totalSpaceMB,\r\n availableSpaceMB,\r\n usedSpaceMB,\r\n diskUsagePercent,\r\n writePermission,\r\n freeSpaceMB: availableSpaceMB,\r\n });\r\n });\r\n });\r\n }\r\n\r\n /**\r\n * Get agent metrics\r\n * Private helper for agent check\r\n */\r\n private async getAgentMetrics(): Promise<AgentMetrics> {\r\n // Get active agent count from Redis queue\r\n let activeAgentCount = 0;\r\n let queueDepth = 0;\r\n\r\n try {\r\n if (this.redisManager) {\r\n const stats = await this.redisManager.getStats();\r\n activeAgentCount = stats.activeCount || 0;\r\n queueDepth = stats.pendingCount || 0;\r\n }\r\n } catch {\r\n // If Redis is unavailable, return default metrics\r\n activeAgentCount = 0;\r\n queueDepth = 0;\r\n }\r\n\r\n return {\r\n activeAgentCount,\r\n queueDepth,\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * File system metrics helper interface\r\n */\r\ninterface FileSystemMetrics {\r\n totalSpaceMB: number;\r\n availableSpaceMB: number;\r\n usedSpaceMB: number;\r\n diskUsagePercent: number;\r\n writePermission: boolean;\r\n freeSpaceMB: number;\r\n}\r\n\r\n/**\r\n * Agent metrics helper interface\r\n */\r\ninterface AgentMetrics {\r\n activeAgentCount: number;\r\n queueDepth: number;\r\n}\r\n\r\n// Export types for use in API endpoints\r\nexport { FileSystemMetrics, AgentMetrics };\r\n"],"names":["getDatabaseService","RedisQueueManager","StandardError","ErrorCode","fs","os","HealthStatus","HealthCheckSystem","config","redisManager","databaseTimeout","redisTimeout","filesystemTimeout","agentsTimeout","diskUsageWarnThreshold","diskUsageCriticalThreshold","queueDepthWarnThreshold","queueDepthCriticalThreshold","error","checkDatabase","startTime","Date","now","db","timeoutPromise","Promise","_","reject","setTimeout","Error","race","query","latency","name","status","message","timestamp","metadata","responseTime","type","timeout","checkRedis","ping","stats","getStats","includes","checkFileSystem","result","getFileSystemMetrics","diskUsagePercent","toFixed","writePermission","freeSpaceMB","totalSpaceMB","checkAgents","metrics","getAgentMetrics","activeAgentCount","queueDepth","getOverallHealth","overallStartTime","database","redis","filesystem","agents","all","dependencies","overallStatus","unhealthyServices","filter","d","degradedServices","length","statusMessage","getDetailedHealthReport","reportStartTime","overall","report","services","alerts","unhealthy","map","s","degraded","OPERATION_TIMEOUT","process","UNKNOWN_ERROR","check","memUsage","memoryUsage","heapUsed","heapTotal","percentUsed","uptime","undefined","getAggregateStats","healthyCount","degradedCount","unhealthyCount","totalLatency","reduce","sum","averageLatency","warnings","push","errors","averageServiceLatency","serviceCount","total","healthy","resolve","tempDir","tmpdir","stat","statSync","statfs","err","totalBlocks","blocks","availableBlocks","bavail","blockSize","bsize","availableSpaceMB","usedSpaceMB","testFile","writeFileSync","unlinkSync","activeCount","pendingCount"],"mappings":"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"}
@@ -0,0 +1,412 @@
1
+ /**
2
+ * Metrics Logger Service
3
+ *
4
+ * Unified metrics and execution logging with dual database writes (PostgreSQL + SQLite).
5
+ * Part of Task 2.3: Unified Metrics and Execution Logging
6
+ *
7
+ * Features:
8
+ * - Atomic dual writes to PostgreSQL and SQLite
9
+ * - Idempotent writes (retries don't create duplicates)
10
+ * - Batch logging support
11
+ * - Cost tracking ($0.001 precision)
12
+ * - Token counting
13
+ * - Query interface for metrics analysis
14
+ */ import { v4 as uuidv4 } from 'uuid';
15
+ import { createIdempotentKey, hasBeenWritten, markWritten, batchCheckWritten, batchMarkWritten, validateCostAccuracy, roundCost } from '../lib/idempotent-write.js';
16
+ import { createLogger } from '../lib/logging.js';
17
+ import { StandardError, ErrorCode } from '../lib/errors.js';
18
+ const logger = createLogger('metrics-logger');
19
+ /**
20
+ * Metrics Logger Service
21
+ */ export class MetricsLogger {
22
+ dbService;
23
+ sqliteAdapter;
24
+ postgresAdapter;
25
+ batchSize;
26
+ flushIntervalMs;
27
+ batchQueue = [];
28
+ flushTimer = null;
29
+ constructor(config){
30
+ this.dbService = config.dbService;
31
+ this.batchSize = config.batchSize || 100;
32
+ this.flushIntervalMs = config.flushIntervalMs || 5000; // 5 seconds
33
+ // Get database adapters
34
+ this.sqliteAdapter = this.dbService.getAdapter('sqlite');
35
+ this.postgresAdapter = this.dbService.getAdapter('postgres');
36
+ logger.info('MetricsLogger initialized', {
37
+ batch_size: this.batchSize,
38
+ flush_interval_ms: this.flushIntervalMs
39
+ });
40
+ }
41
+ /**
42
+ * Log single execution metrics
43
+ *
44
+ * @param metrics - Execution metrics to log
45
+ */ async logExecution(metrics) {
46
+ try {
47
+ // Validate and normalize metrics
48
+ const normalizedMetrics = this.normalizeMetrics(metrics);
49
+ // Generate idempotency key
50
+ const idempotencyKey = createIdempotentKey(normalizedMetrics);
51
+ // Check if already written to both databases
52
+ const [sqliteWritten, postgresWritten] = await Promise.all([
53
+ hasBeenWritten(idempotencyKey, this.sqliteAdapter),
54
+ hasBeenWritten(idempotencyKey, this.postgresAdapter)
55
+ ]);
56
+ if (sqliteWritten && postgresWritten) {
57
+ logger.debug('Metrics already logged (idempotent)', {
58
+ idempotency_key: idempotencyKey.substring(0, 16) + '...',
59
+ metrics_id: normalizedMetrics.id
60
+ });
61
+ return; // Already written, skip
62
+ }
63
+ // Atomic write to both databases
64
+ await this.dbService.executeTransaction([
65
+ {
66
+ database: 'sqlite',
67
+ operation: async (adapter)=>{
68
+ if (!sqliteWritten) {
69
+ await adapter.insert('execution_metrics', normalizedMetrics);
70
+ await markWritten(idempotencyKey, adapter, normalizedMetrics.id);
71
+ }
72
+ }
73
+ },
74
+ {
75
+ database: 'postgres',
76
+ operation: async (adapter)=>{
77
+ if (!postgresWritten) {
78
+ await adapter.insert('execution_metrics', normalizedMetrics);
79
+ await markWritten(idempotencyKey, adapter, normalizedMetrics.id);
80
+ }
81
+ }
82
+ }
83
+ ]);
84
+ logger.info('Metrics logged successfully', {
85
+ metrics_id: normalizedMetrics.id,
86
+ agent_id: normalizedMetrics.agent_id,
87
+ task_id: normalizedMetrics.task_id,
88
+ duration_ms: normalizedMetrics.duration_ms,
89
+ cost_usd: normalizedMetrics.cost_usd,
90
+ status: normalizedMetrics.status
91
+ });
92
+ } catch (error) {
93
+ logger.error('Failed to log metrics', {
94
+ agent_id: metrics.agent_id,
95
+ task_id: metrics.task_id,
96
+ error: error instanceof Error ? error.message : String(error)
97
+ });
98
+ throw new StandardError(ErrorCode.DATABASE_ERROR, 'Failed to log execution metrics', {
99
+ metrics,
100
+ error
101
+ });
102
+ }
103
+ }
104
+ /**
105
+ * Log batch of execution metrics (atomic)
106
+ *
107
+ * @param metricsList - Array of execution metrics
108
+ */ async logBatch(metricsList) {
109
+ try {
110
+ if (metricsList.length === 0) {
111
+ logger.debug('Empty batch, skipping');
112
+ return;
113
+ }
114
+ // Normalize all metrics
115
+ const normalizedMetrics = metricsList.map((m)=>this.normalizeMetrics(m));
116
+ // Deduplicate based on idempotency keys
117
+ const uniqueMetrics = await this.deduplicateBatch(normalizedMetrics);
118
+ if (uniqueMetrics.length === 0) {
119
+ logger.debug('All metrics already logged (idempotent)', {
120
+ original_count: metricsList.length
121
+ });
122
+ return;
123
+ }
124
+ // Prepare idempotency key entries
125
+ const idempotencyEntries = uniqueMetrics.map((m)=>({
126
+ key: createIdempotentKey(m),
127
+ metricsId: m.id
128
+ }));
129
+ // Batch write to both databases (atomic)
130
+ await this.dbService.executeTransaction([
131
+ {
132
+ database: 'sqlite',
133
+ operation: async (adapter)=>{
134
+ await adapter.insertMany('execution_metrics', uniqueMetrics);
135
+ await batchMarkWritten(idempotencyEntries, adapter);
136
+ }
137
+ },
138
+ {
139
+ database: 'postgres',
140
+ operation: async (adapter)=>{
141
+ await adapter.insertMany('execution_metrics', uniqueMetrics);
142
+ await batchMarkWritten(idempotencyEntries, adapter);
143
+ }
144
+ }
145
+ ]);
146
+ logger.info('Batch metrics logged successfully', {
147
+ total_metrics: metricsList.length,
148
+ unique_metrics: uniqueMetrics.length,
149
+ duplicates_skipped: metricsList.length - uniqueMetrics.length
150
+ });
151
+ } catch (error) {
152
+ logger.error('Failed to log batch metrics', {
153
+ batch_size: metricsList.length,
154
+ error: error instanceof Error ? error.message : String(error)
155
+ });
156
+ throw new StandardError(ErrorCode.DATABASE_ERROR, 'Failed to log batch metrics', {
157
+ metricsList,
158
+ error
159
+ });
160
+ }
161
+ }
162
+ /**
163
+ * Query metrics with filters
164
+ *
165
+ * @param filters - Query filters
166
+ * @returns Array of execution metrics
167
+ */ async queryMetrics(filters) {
168
+ try {
169
+ const queryOptions = {
170
+ filters: [],
171
+ limit: filters.limit || 100,
172
+ offset: filters.offset || 0,
173
+ orderBy: 'timestamp',
174
+ order: 'desc'
175
+ };
176
+ // Add filters
177
+ if (filters.agent_id) {
178
+ queryOptions.filters?.push({
179
+ field: 'agent_id',
180
+ operator: 'eq',
181
+ value: filters.agent_id
182
+ });
183
+ }
184
+ if (filters.skill_id) {
185
+ queryOptions.filters?.push({
186
+ field: 'skill_id',
187
+ operator: 'eq',
188
+ value: filters.skill_id
189
+ });
190
+ }
191
+ if (filters.task_id) {
192
+ queryOptions.filters?.push({
193
+ field: 'task_id',
194
+ operator: 'eq',
195
+ value: filters.task_id
196
+ });
197
+ }
198
+ if (filters.status) {
199
+ queryOptions.filters?.push({
200
+ field: 'status',
201
+ operator: 'eq',
202
+ value: filters.status
203
+ });
204
+ }
205
+ if (filters.start_date && filters.end_date) {
206
+ queryOptions.filters?.push({
207
+ field: 'timestamp',
208
+ operator: 'between',
209
+ value: [
210
+ filters.start_date,
211
+ filters.end_date
212
+ ]
213
+ });
214
+ }
215
+ // Query from SQLite (primary source for metrics)
216
+ const results = await this.sqliteAdapter.list('execution_metrics', queryOptions);
217
+ logger.debug('Metrics query executed', {
218
+ filters,
219
+ result_count: results.length
220
+ });
221
+ return results;
222
+ } catch (error) {
223
+ logger.error('Failed to query metrics', {
224
+ filters,
225
+ error: error instanceof Error ? error.message : String(error)
226
+ });
227
+ throw new StandardError(ErrorCode.DATABASE_ERROR, 'Failed to query metrics', {
228
+ filters,
229
+ error
230
+ });
231
+ }
232
+ }
233
+ /**
234
+ * Get aggregated metrics by agent
235
+ *
236
+ * @param startDate - Start date for aggregation
237
+ * @param endDate - End date for aggregation
238
+ * @returns Array of aggregated metrics
239
+ */ async getAggregatedMetrics(startDate, endDate) {
240
+ try {
241
+ // Query all metrics in date range
242
+ const filters = {
243
+ start_date: startDate,
244
+ end_date: endDate,
245
+ limit: 10000
246
+ };
247
+ const metrics = await this.queryMetrics(filters);
248
+ // Aggregate by agent_id
249
+ const aggregationMap = new Map();
250
+ metrics.forEach((m)=>{
251
+ if (!aggregationMap.has(m.agent_id)) {
252
+ aggregationMap.set(m.agent_id, {
253
+ agent_id: m.agent_id,
254
+ total_executions: 0,
255
+ total_cost_usd: 0,
256
+ total_tokens: 0,
257
+ avg_duration_ms: 0,
258
+ success_count: 0,
259
+ failure_count: 0,
260
+ success_rate: 0
261
+ });
262
+ }
263
+ const agg = aggregationMap.get(m.agent_id);
264
+ agg.total_executions++;
265
+ agg.total_cost_usd += m.cost_usd;
266
+ agg.total_tokens += m.tokens_used;
267
+ agg.avg_duration_ms += m.duration_ms;
268
+ if (m.status === 'success') {
269
+ agg.success_count++;
270
+ } else {
271
+ agg.failure_count++;
272
+ }
273
+ });
274
+ // Calculate averages and success rates
275
+ const results = [];
276
+ aggregationMap.forEach((agg)=>{
277
+ agg.avg_duration_ms = Math.round(agg.avg_duration_ms / agg.total_executions);
278
+ agg.success_rate = agg.success_count / agg.total_executions * 100;
279
+ agg.total_cost_usd = roundCost(agg.total_cost_usd);
280
+ results.push(agg);
281
+ });
282
+ // Sort by total cost (descending)
283
+ results.sort((a, b)=>b.total_cost_usd - a.total_cost_usd);
284
+ logger.info('Aggregated metrics calculated', {
285
+ agent_count: results.length,
286
+ total_executions: results.reduce((sum, agg)=>sum + agg.total_executions, 0)
287
+ });
288
+ return results;
289
+ } catch (error) {
290
+ logger.error('Failed to get aggregated metrics', {
291
+ error: error instanceof Error ? error.message : String(error)
292
+ });
293
+ throw new StandardError(ErrorCode.DATABASE_ERROR, 'Failed to get aggregated metrics', {
294
+ error
295
+ });
296
+ }
297
+ }
298
+ /**
299
+ * Add metrics to batch queue
300
+ *
301
+ * @param metrics - Execution metrics to queue
302
+ */ async queueMetrics(metrics) {
303
+ this.batchQueue.push(metrics);
304
+ // Flush if batch size reached
305
+ if (this.batchQueue.length >= this.batchSize) {
306
+ await this.flush();
307
+ } else {
308
+ // Start flush timer if not already running
309
+ if (!this.flushTimer) {
310
+ this.flushTimer = setTimeout(()=>this.flush(), this.flushIntervalMs);
311
+ }
312
+ }
313
+ }
314
+ /**
315
+ * Flush batch queue
316
+ */ async flush() {
317
+ if (this.batchQueue.length === 0) {
318
+ return;
319
+ }
320
+ // Clear timer
321
+ if (this.flushTimer) {
322
+ clearTimeout(this.flushTimer);
323
+ this.flushTimer = null;
324
+ }
325
+ // Copy and clear queue
326
+ const batch = [
327
+ ...this.batchQueue
328
+ ];
329
+ this.batchQueue = [];
330
+ // Log batch
331
+ await this.logBatch(batch);
332
+ }
333
+ /**
334
+ * Normalize metrics (add ID, validate, round cost)
335
+ *
336
+ * @param metrics - Raw metrics
337
+ * @returns Normalized metrics
338
+ */ normalizeMetrics(metrics) {
339
+ // Generate ID if not provided
340
+ const id = metrics.id || uuidv4();
341
+ // Validate cost accuracy
342
+ const cost = roundCost(metrics.cost_usd);
343
+ if (!validateCostAccuracy(cost)) {
344
+ logger.warn('Cost accuracy validation failed', {
345
+ original_cost: metrics.cost_usd,
346
+ rounded_cost: cost
347
+ });
348
+ }
349
+ // Ensure timestamp is Date object
350
+ const timestamp = metrics.timestamp instanceof Date ? metrics.timestamp : new Date(metrics.timestamp);
351
+ return {
352
+ ...metrics,
353
+ id,
354
+ timestamp,
355
+ cost_usd: cost,
356
+ metadata: metrics.metadata ? JSON.stringify(metrics.metadata) : undefined
357
+ };
358
+ }
359
+ /**
360
+ * Deduplicate batch based on idempotency keys
361
+ *
362
+ * @param metricsList - Batch of metrics
363
+ * @returns Unique metrics (not already written)
364
+ */ async deduplicateBatch(metricsList) {
365
+ // Generate idempotency keys
366
+ const keys = metricsList.map((m)=>createIdempotentKey(m));
367
+ // Check which keys already exist in SQLite
368
+ const sqliteStatus = await batchCheckWritten(keys, this.sqliteAdapter);
369
+ // Check which keys already exist in PostgreSQL
370
+ const postgresStatus = await batchCheckWritten(keys, this.postgresAdapter);
371
+ // Filter out metrics that are already written to BOTH databases
372
+ const uniqueMetrics = [];
373
+ metricsList.forEach((metrics, index)=>{
374
+ const key = keys[index];
375
+ const inSQLite = sqliteStatus.get(key) || false;
376
+ const inPostgres = postgresStatus.get(key) || false;
377
+ if (!inSQLite || !inPostgres) {
378
+ // At least one database doesn't have this metric, include it
379
+ uniqueMetrics.push(metrics);
380
+ }
381
+ });
382
+ return uniqueMetrics;
383
+ }
384
+ /**
385
+ * Close and cleanup resources
386
+ */ async close() {
387
+ // Flush remaining metrics
388
+ await this.flush();
389
+ // Clear timer
390
+ if (this.flushTimer) {
391
+ clearTimeout(this.flushTimer);
392
+ this.flushTimer = null;
393
+ }
394
+ logger.info('MetricsLogger closed');
395
+ }
396
+ }
397
+ /**
398
+ * Create MetricsLogger instance
399
+ *
400
+ * @param dbService - Database service
401
+ * @param batchSize - Optional batch size
402
+ * @param flushIntervalMs - Optional flush interval
403
+ * @returns MetricsLogger instance
404
+ */ export function createMetricsLogger(dbService, batchSize, flushIntervalMs) {
405
+ return new MetricsLogger({
406
+ dbService,
407
+ batchSize,
408
+ flushIntervalMs
409
+ });
410
+ }
411
+
412
+ //# sourceMappingURL=metrics-logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/services/metrics-logger.ts"],"sourcesContent":["/**\r\n * Metrics Logger Service\r\n *\r\n * Unified metrics and execution logging with dual database writes (PostgreSQL + SQLite).\r\n * Part of Task 2.3: Unified Metrics and Execution Logging\r\n *\r\n * Features:\r\n * - Atomic dual writes to PostgreSQL and SQLite\r\n * - Idempotent writes (retries don't create duplicates)\r\n * - Batch logging support\r\n * - Cost tracking ($0.001 precision)\r\n * - Token counting\r\n * - Query interface for metrics analysis\r\n */\r\n\r\nimport { v4 as uuidv4 } from 'uuid';\r\nimport { DatabaseService } from '../lib/database-service.js';\r\nimport { IDatabaseAdapter, QueryOptions, OperationResult } from '../lib/database-service/types.js';\r\nimport {\r\n createIdempotentKey,\r\n hasBeenWritten,\r\n markWritten,\r\n batchCheckWritten,\r\n batchMarkWritten,\r\n validateCostAccuracy,\r\n roundCost,\r\n} from '../lib/idempotent-write.js';\r\nimport { createLogger } from '../lib/logging.js';\r\nimport { StandardError, ErrorCode } from '../lib/errors.js';\r\n\r\nconst logger = createLogger('metrics-logger');\r\n\r\n/**\r\n * Execution metrics interface\r\n */\r\nexport interface ExecutionMetrics {\r\n id?: string;\r\n timestamp: Date;\r\n agent_id: string;\r\n skill_id?: string;\r\n task_id: string;\r\n duration_ms: number;\r\n tokens_used: number;\r\n cost_usd: number;\r\n status: 'success' | 'failure' | 'timeout' | 'cancelled';\r\n error_message?: string;\r\n metadata?: Record<string, any>;\r\n}\r\n\r\n/**\r\n * Metrics filter for querying\r\n */\r\nexport interface MetricsFilter {\r\n agent_id?: string;\r\n skill_id?: string;\r\n task_id?: string;\r\n status?: 'success' | 'failure' | 'timeout' | 'cancelled';\r\n start_date?: Date;\r\n end_date?: Date;\r\n limit?: number;\r\n offset?: number;\r\n}\r\n\r\n/**\r\n * Metrics aggregation result\r\n */\r\nexport interface MetricsAggregation {\r\n agent_id: string;\r\n total_executions: number;\r\n total_cost_usd: number;\r\n total_tokens: number;\r\n avg_duration_ms: number;\r\n success_count: number;\r\n failure_count: number;\r\n success_rate: number;\r\n}\r\n\r\n/**\r\n * Metrics Logger Service Configuration\r\n */\r\nexport interface MetricsLoggerConfig {\r\n dbService: DatabaseService;\r\n batchSize?: number;\r\n flushIntervalMs?: number;\r\n}\r\n\r\n/**\r\n * Metrics Logger Service\r\n */\r\nexport class MetricsLogger {\r\n private dbService: DatabaseService;\r\n private sqliteAdapter: IDatabaseAdapter;\r\n private postgresAdapter: IDatabaseAdapter;\r\n private batchSize: number;\r\n private flushIntervalMs: number;\r\n private batchQueue: ExecutionMetrics[] = [];\r\n private flushTimer: NodeJS.Timeout | null = null;\r\n\r\n constructor(config: MetricsLoggerConfig) {\r\n this.dbService = config.dbService;\r\n this.batchSize = config.batchSize || 100;\r\n this.flushIntervalMs = config.flushIntervalMs || 5000; // 5 seconds\r\n\r\n // Get database adapters\r\n this.sqliteAdapter = this.dbService.getAdapter('sqlite');\r\n this.postgresAdapter = this.dbService.getAdapter('postgres');\r\n\r\n logger.info('MetricsLogger initialized', {\r\n batch_size: this.batchSize,\r\n flush_interval_ms: this.flushIntervalMs,\r\n });\r\n }\r\n\r\n /**\r\n * Log single execution metrics\r\n *\r\n * @param metrics - Execution metrics to log\r\n */\r\n async logExecution(metrics: ExecutionMetrics): Promise<void> {\r\n try {\r\n // Validate and normalize metrics\r\n const normalizedMetrics = this.normalizeMetrics(metrics);\r\n\r\n // Generate idempotency key\r\n const idempotencyKey = createIdempotentKey(normalizedMetrics);\r\n\r\n // Check if already written to both databases\r\n const [sqliteWritten, postgresWritten] = await Promise.all([\r\n hasBeenWritten(idempotencyKey, this.sqliteAdapter),\r\n hasBeenWritten(idempotencyKey, this.postgresAdapter),\r\n ]);\r\n\r\n if (sqliteWritten && postgresWritten) {\r\n logger.debug('Metrics already logged (idempotent)', {\r\n idempotency_key: idempotencyKey.substring(0, 16) + '...',\r\n metrics_id: normalizedMetrics.id,\r\n });\r\n return; // Already written, skip\r\n }\r\n\r\n // Atomic write to both databases\r\n await this.dbService.executeTransaction([\r\n {\r\n database: 'sqlite',\r\n operation: async (adapter) => {\r\n if (!sqliteWritten) {\r\n await adapter.insert('execution_metrics', normalizedMetrics);\r\n await markWritten(idempotencyKey, adapter, normalizedMetrics.id);\r\n }\r\n },\r\n },\r\n {\r\n database: 'postgres',\r\n operation: async (adapter) => {\r\n if (!postgresWritten) {\r\n await adapter.insert('execution_metrics', normalizedMetrics);\r\n await markWritten(idempotencyKey, adapter, normalizedMetrics.id);\r\n }\r\n },\r\n },\r\n ]);\r\n\r\n logger.info('Metrics logged successfully', {\r\n metrics_id: normalizedMetrics.id,\r\n agent_id: normalizedMetrics.agent_id,\r\n task_id: normalizedMetrics.task_id,\r\n duration_ms: normalizedMetrics.duration_ms,\r\n cost_usd: normalizedMetrics.cost_usd,\r\n status: normalizedMetrics.status,\r\n });\r\n } catch (error) {\r\n logger.error('Failed to log metrics', {\r\n agent_id: metrics.agent_id,\r\n task_id: metrics.task_id,\r\n error: error instanceof Error ? error.message : String(error),\r\n });\r\n\r\n throw new StandardError(\r\n ErrorCode.DATABASE_ERROR,\r\n 'Failed to log execution metrics',\r\n { metrics, error }\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Log batch of execution metrics (atomic)\r\n *\r\n * @param metricsList - Array of execution metrics\r\n */\r\n async logBatch(metricsList: ExecutionMetrics[]): Promise<void> {\r\n try {\r\n if (metricsList.length === 0) {\r\n logger.debug('Empty batch, skipping');\r\n return;\r\n }\r\n\r\n // Normalize all metrics\r\n const normalizedMetrics = metricsList.map(m => this.normalizeMetrics(m));\r\n\r\n // Deduplicate based on idempotency keys\r\n const uniqueMetrics = await this.deduplicateBatch(normalizedMetrics);\r\n\r\n if (uniqueMetrics.length === 0) {\r\n logger.debug('All metrics already logged (idempotent)', {\r\n original_count: metricsList.length,\r\n });\r\n return;\r\n }\r\n\r\n // Prepare idempotency key entries\r\n const idempotencyEntries = uniqueMetrics.map(m => ({\r\n key: createIdempotentKey(m),\r\n metricsId: m.id,\r\n }));\r\n\r\n // Batch write to both databases (atomic)\r\n await this.dbService.executeTransaction([\r\n {\r\n database: 'sqlite',\r\n operation: async (adapter) => {\r\n await adapter.insertMany('execution_metrics', uniqueMetrics);\r\n await batchMarkWritten(idempotencyEntries, adapter);\r\n },\r\n },\r\n {\r\n database: 'postgres',\r\n operation: async (adapter) => {\r\n await adapter.insertMany('execution_metrics', uniqueMetrics);\r\n await batchMarkWritten(idempotencyEntries, adapter);\r\n },\r\n },\r\n ]);\r\n\r\n logger.info('Batch metrics logged successfully', {\r\n total_metrics: metricsList.length,\r\n unique_metrics: uniqueMetrics.length,\r\n duplicates_skipped: metricsList.length - uniqueMetrics.length,\r\n });\r\n } catch (error) {\r\n logger.error('Failed to log batch metrics', {\r\n batch_size: metricsList.length,\r\n error: error instanceof Error ? error.message : String(error),\r\n });\r\n\r\n throw new StandardError(\r\n ErrorCode.DATABASE_ERROR,\r\n 'Failed to log batch metrics',\r\n { metricsList, error }\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Query metrics with filters\r\n *\r\n * @param filters - Query filters\r\n * @returns Array of execution metrics\r\n */\r\n async queryMetrics(filters: MetricsFilter): Promise<ExecutionMetrics[]> {\r\n try {\r\n const queryOptions: QueryOptions<ExecutionMetrics> = {\r\n filters: [],\r\n limit: filters.limit || 100,\r\n offset: filters.offset || 0,\r\n orderBy: 'timestamp' as keyof ExecutionMetrics,\r\n order: 'desc',\r\n };\r\n\r\n // Add filters\r\n if (filters.agent_id) {\r\n queryOptions.filters?.push({\r\n field: 'agent_id' as keyof ExecutionMetrics,\r\n operator: 'eq',\r\n value: filters.agent_id,\r\n });\r\n }\r\n\r\n if (filters.skill_id) {\r\n queryOptions.filters?.push({\r\n field: 'skill_id' as keyof ExecutionMetrics,\r\n operator: 'eq',\r\n value: filters.skill_id,\r\n });\r\n }\r\n\r\n if (filters.task_id) {\r\n queryOptions.filters?.push({\r\n field: 'task_id' as keyof ExecutionMetrics,\r\n operator: 'eq',\r\n value: filters.task_id,\r\n });\r\n }\r\n\r\n if (filters.status) {\r\n queryOptions.filters?.push({\r\n field: 'status' as keyof ExecutionMetrics,\r\n operator: 'eq',\r\n value: filters.status,\r\n });\r\n }\r\n\r\n if (filters.start_date && filters.end_date) {\r\n queryOptions.filters?.push({\r\n field: 'timestamp' as keyof ExecutionMetrics,\r\n operator: 'between',\r\n value: [filters.start_date, filters.end_date],\r\n });\r\n }\r\n\r\n // Query from SQLite (primary source for metrics)\r\n const results = await this.sqliteAdapter.list<ExecutionMetrics>(\r\n 'execution_metrics',\r\n queryOptions\r\n );\r\n\r\n logger.debug('Metrics query executed', {\r\n filters,\r\n result_count: results.length,\r\n });\r\n\r\n return results;\r\n } catch (error) {\r\n logger.error('Failed to query metrics', {\r\n filters,\r\n error: error instanceof Error ? error.message : String(error),\r\n });\r\n\r\n throw new StandardError(\r\n ErrorCode.DATABASE_ERROR,\r\n 'Failed to query metrics',\r\n { filters, error }\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Get aggregated metrics by agent\r\n *\r\n * @param startDate - Start date for aggregation\r\n * @param endDate - End date for aggregation\r\n * @returns Array of aggregated metrics\r\n */\r\n async getAggregatedMetrics(\r\n startDate?: Date,\r\n endDate?: Date\r\n ): Promise<MetricsAggregation[]> {\r\n try {\r\n // Query all metrics in date range\r\n const filters: MetricsFilter = {\r\n start_date: startDate,\r\n end_date: endDate,\r\n limit: 10000, // Large limit for aggregation\r\n };\r\n\r\n const metrics = await this.queryMetrics(filters);\r\n\r\n // Aggregate by agent_id\r\n const aggregationMap = new Map<string, MetricsAggregation>();\r\n\r\n metrics.forEach(m => {\r\n if (!aggregationMap.has(m.agent_id)) {\r\n aggregationMap.set(m.agent_id, {\r\n agent_id: m.agent_id,\r\n total_executions: 0,\r\n total_cost_usd: 0,\r\n total_tokens: 0,\r\n avg_duration_ms: 0,\r\n success_count: 0,\r\n failure_count: 0,\r\n success_rate: 0,\r\n });\r\n }\r\n\r\n const agg = aggregationMap.get(m.agent_id)!;\r\n agg.total_executions++;\r\n agg.total_cost_usd += m.cost_usd;\r\n agg.total_tokens += m.tokens_used;\r\n agg.avg_duration_ms += m.duration_ms;\r\n\r\n if (m.status === 'success') {\r\n agg.success_count++;\r\n } else {\r\n agg.failure_count++;\r\n }\r\n });\r\n\r\n // Calculate averages and success rates\r\n const results: MetricsAggregation[] = [];\r\n aggregationMap.forEach(agg => {\r\n agg.avg_duration_ms = Math.round(agg.avg_duration_ms / agg.total_executions);\r\n agg.success_rate = (agg.success_count / agg.total_executions) * 100;\r\n agg.total_cost_usd = roundCost(agg.total_cost_usd);\r\n results.push(agg);\r\n });\r\n\r\n // Sort by total cost (descending)\r\n results.sort((a, b) => b.total_cost_usd - a.total_cost_usd);\r\n\r\n logger.info('Aggregated metrics calculated', {\r\n agent_count: results.length,\r\n total_executions: results.reduce((sum, agg) => sum + agg.total_executions, 0),\r\n });\r\n\r\n return results;\r\n } catch (error) {\r\n logger.error('Failed to get aggregated metrics', {\r\n error: error instanceof Error ? error.message : String(error),\r\n });\r\n\r\n throw new StandardError(\r\n ErrorCode.DATABASE_ERROR,\r\n 'Failed to get aggregated metrics',\r\n { error }\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Add metrics to batch queue\r\n *\r\n * @param metrics - Execution metrics to queue\r\n */\r\n async queueMetrics(metrics: ExecutionMetrics): Promise<void> {\r\n this.batchQueue.push(metrics);\r\n\r\n // Flush if batch size reached\r\n if (this.batchQueue.length >= this.batchSize) {\r\n await this.flush();\r\n } else {\r\n // Start flush timer if not already running\r\n if (!this.flushTimer) {\r\n this.flushTimer = setTimeout(() => this.flush(), this.flushIntervalMs);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Flush batch queue\r\n */\r\n async flush(): Promise<void> {\r\n if (this.batchQueue.length === 0) {\r\n return;\r\n }\r\n\r\n // Clear timer\r\n if (this.flushTimer) {\r\n clearTimeout(this.flushTimer);\r\n this.flushTimer = null;\r\n }\r\n\r\n // Copy and clear queue\r\n const batch = [...this.batchQueue];\r\n this.batchQueue = [];\r\n\r\n // Log batch\r\n await this.logBatch(batch);\r\n }\r\n\r\n /**\r\n * Normalize metrics (add ID, validate, round cost)\r\n *\r\n * @param metrics - Raw metrics\r\n * @returns Normalized metrics\r\n */\r\n private normalizeMetrics(metrics: ExecutionMetrics): ExecutionMetrics {\r\n // Generate ID if not provided\r\n const id = metrics.id || uuidv4();\r\n\r\n // Validate cost accuracy\r\n const cost = roundCost(metrics.cost_usd);\r\n if (!validateCostAccuracy(cost)) {\r\n logger.warn('Cost accuracy validation failed', {\r\n original_cost: metrics.cost_usd,\r\n rounded_cost: cost,\r\n });\r\n }\r\n\r\n // Ensure timestamp is Date object\r\n const timestamp = metrics.timestamp instanceof Date\r\n ? metrics.timestamp\r\n : new Date(metrics.timestamp);\r\n\r\n return {\r\n ...metrics,\r\n id,\r\n timestamp,\r\n cost_usd: cost,\r\n metadata: metrics.metadata ? JSON.stringify(metrics.metadata) : undefined,\r\n } as ExecutionMetrics;\r\n }\r\n\r\n /**\r\n * Deduplicate batch based on idempotency keys\r\n *\r\n * @param metricsList - Batch of metrics\r\n * @returns Unique metrics (not already written)\r\n */\r\n private async deduplicateBatch(\r\n metricsList: ExecutionMetrics[]\r\n ): Promise<ExecutionMetrics[]> {\r\n // Generate idempotency keys\r\n const keys = metricsList.map(m => createIdempotentKey(m));\r\n\r\n // Check which keys already exist in SQLite\r\n const sqliteStatus = await batchCheckWritten(keys, this.sqliteAdapter);\r\n\r\n // Check which keys already exist in PostgreSQL\r\n const postgresStatus = await batchCheckWritten(keys, this.postgresAdapter);\r\n\r\n // Filter out metrics that are already written to BOTH databases\r\n const uniqueMetrics: ExecutionMetrics[] = [];\r\n metricsList.forEach((metrics, index) => {\r\n const key = keys[index];\r\n const inSQLite = sqliteStatus.get(key) || false;\r\n const inPostgres = postgresStatus.get(key) || false;\r\n\r\n if (!inSQLite || !inPostgres) {\r\n // At least one database doesn't have this metric, include it\r\n uniqueMetrics.push(metrics);\r\n }\r\n });\r\n\r\n return uniqueMetrics;\r\n }\r\n\r\n /**\r\n * Close and cleanup resources\r\n */\r\n async close(): Promise<void> {\r\n // Flush remaining metrics\r\n await this.flush();\r\n\r\n // Clear timer\r\n if (this.flushTimer) {\r\n clearTimeout(this.flushTimer);\r\n this.flushTimer = null;\r\n }\r\n\r\n logger.info('MetricsLogger closed');\r\n }\r\n}\r\n\r\n/**\r\n * Create MetricsLogger instance\r\n *\r\n * @param dbService - Database service\r\n * @param batchSize - Optional batch size\r\n * @param flushIntervalMs - Optional flush interval\r\n * @returns MetricsLogger instance\r\n */\r\nexport function createMetricsLogger(\r\n dbService: DatabaseService,\r\n batchSize?: number,\r\n flushIntervalMs?: number\r\n): MetricsLogger {\r\n return new MetricsLogger({\r\n dbService,\r\n batchSize,\r\n flushIntervalMs,\r\n });\r\n}\r\n"],"names":["v4","uuidv4","createIdempotentKey","hasBeenWritten","markWritten","batchCheckWritten","batchMarkWritten","validateCostAccuracy","roundCost","createLogger","StandardError","ErrorCode","logger","MetricsLogger","dbService","sqliteAdapter","postgresAdapter","batchSize","flushIntervalMs","batchQueue","flushTimer","config","getAdapter","info","batch_size","flush_interval_ms","logExecution","metrics","normalizedMetrics","normalizeMetrics","idempotencyKey","sqliteWritten","postgresWritten","Promise","all","debug","idempotency_key","substring","metrics_id","id","executeTransaction","database","operation","adapter","insert","agent_id","task_id","duration_ms","cost_usd","status","error","Error","message","String","DATABASE_ERROR","logBatch","metricsList","length","map","m","uniqueMetrics","deduplicateBatch","original_count","idempotencyEntries","key","metricsId","insertMany","total_metrics","unique_metrics","duplicates_skipped","queryMetrics","filters","queryOptions","limit","offset","orderBy","order","push","field","operator","value","skill_id","start_date","end_date","results","list","result_count","getAggregatedMetrics","startDate","endDate","aggregationMap","Map","forEach","has","set","total_executions","total_cost_usd","total_tokens","avg_duration_ms","success_count","failure_count","success_rate","agg","get","tokens_used","Math","round","sort","a","b","agent_count","reduce","sum","queueMetrics","flush","setTimeout","clearTimeout","batch","cost","warn","original_cost","rounded_cost","timestamp","Date","metadata","JSON","stringify","undefined","keys","sqliteStatus","postgresStatus","index","inSQLite","inPostgres","close","createMetricsLogger"],"mappings":"AAAA;;;;;;;;;;;;;CAaC,GAED,SAASA,MAAMC,MAAM,QAAQ,OAAO;AAGpC,SACEC,mBAAmB,EACnBC,cAAc,EACdC,WAAW,EACXC,iBAAiB,EACjBC,gBAAgB,EAChBC,oBAAoB,EACpBC,SAAS,QACJ,6BAA6B;AACpC,SAASC,YAAY,QAAQ,oBAAoB;AACjD,SAASC,aAAa,EAAEC,SAAS,QAAQ,mBAAmB;AAE5D,MAAMC,SAASH,aAAa;AAwD5B;;CAEC,GACD,OAAO,MAAMI;IACHC,UAA2B;IAC3BC,cAAgC;IAChCC,gBAAkC;IAClCC,UAAkB;IAClBC,gBAAwB;IACxBC,aAAiC,EAAE,CAAC;IACpCC,aAAoC,KAAK;IAEjD,YAAYC,MAA2B,CAAE;QACvC,IAAI,CAACP,SAAS,GAAGO,OAAOP,SAAS;QACjC,IAAI,CAACG,SAAS,GAAGI,OAAOJ,SAAS,IAAI;QACrC,IAAI,CAACC,eAAe,GAAGG,OAAOH,eAAe,IAAI,MAAM,YAAY;QAEnE,wBAAwB;QACxB,IAAI,CAACH,aAAa,GAAG,IAAI,CAACD,SAAS,CAACQ,UAAU,CAAC;QAC/C,IAAI,CAACN,eAAe,GAAG,IAAI,CAACF,SAAS,CAACQ,UAAU,CAAC;QAEjDV,OAAOW,IAAI,CAAC,6BAA6B;YACvCC,YAAY,IAAI,CAACP,SAAS;YAC1BQ,mBAAmB,IAAI,CAACP,eAAe;QACzC;IACF;IAEA;;;;GAIC,GACD,MAAMQ,aAAaC,OAAyB,EAAiB;QAC3D,IAAI;YACF,iCAAiC;YACjC,MAAMC,oBAAoB,IAAI,CAACC,gBAAgB,CAACF;YAEhD,2BAA2B;YAC3B,MAAMG,iBAAiB5B,oBAAoB0B;YAE3C,6CAA6C;YAC7C,MAAM,CAACG,eAAeC,gBAAgB,GAAG,MAAMC,QAAQC,GAAG,CAAC;gBACzD/B,eAAe2B,gBAAgB,IAAI,CAACf,aAAa;gBACjDZ,eAAe2B,gBAAgB,IAAI,CAACd,eAAe;aACpD;YAED,IAAIe,iBAAiBC,iBAAiB;gBACpCpB,OAAOuB,KAAK,CAAC,uCAAuC;oBAClDC,iBAAiBN,eAAeO,SAAS,CAAC,GAAG,MAAM;oBACnDC,YAAYV,kBAAkBW,EAAE;gBAClC;gBACA,QAAQ,wBAAwB;YAClC;YAEA,iCAAiC;YACjC,MAAM,IAAI,CAACzB,SAAS,CAAC0B,kBAAkB,CAAC;gBACtC;oBACEC,UAAU;oBACVC,WAAW,OAAOC;wBAChB,IAAI,CAACZ,eAAe;4BAClB,MAAMY,QAAQC,MAAM,CAAC,qBAAqBhB;4BAC1C,MAAMxB,YAAY0B,gBAAgBa,SAASf,kBAAkBW,EAAE;wBACjE;oBACF;gBACF;gBACA;oBACEE,UAAU;oBACVC,WAAW,OAAOC;wBAChB,IAAI,CAACX,iBAAiB;4BACpB,MAAMW,QAAQC,MAAM,CAAC,qBAAqBhB;4BAC1C,MAAMxB,YAAY0B,gBAAgBa,SAASf,kBAAkBW,EAAE;wBACjE;oBACF;gBACF;aACD;YAED3B,OAAOW,IAAI,CAAC,+BAA+B;gBACzCe,YAAYV,kBAAkBW,EAAE;gBAChCM,UAAUjB,kBAAkBiB,QAAQ;gBACpCC,SAASlB,kBAAkBkB,OAAO;gBAClCC,aAAanB,kBAAkBmB,WAAW;gBAC1CC,UAAUpB,kBAAkBoB,QAAQ;gBACpCC,QAAQrB,kBAAkBqB,MAAM;YAClC;QACF,EAAE,OAAOC,OAAO;YACdtC,OAAOsC,KAAK,CAAC,yBAAyB;gBACpCL,UAAUlB,QAAQkB,QAAQ;gBAC1BC,SAASnB,QAAQmB,OAAO;gBACxBI,OAAOA,iBAAiBC,QAAQD,MAAME,OAAO,GAAGC,OAAOH;YACzD;YAEA,MAAM,IAAIxC,cACRC,UAAU2C,cAAc,EACxB,mCACA;gBAAE3B;gBAASuB;YAAM;QAErB;IACF;IAEA;;;;GAIC,GACD,MAAMK,SAASC,WAA+B,EAAiB;QAC7D,IAAI;YACF,IAAIA,YAAYC,MAAM,KAAK,GAAG;gBAC5B7C,OAAOuB,KAAK,CAAC;gBACb;YACF;YAEA,wBAAwB;YACxB,MAAMP,oBAAoB4B,YAAYE,GAAG,CAACC,CAAAA,IAAK,IAAI,CAAC9B,gBAAgB,CAAC8B;YAErE,wCAAwC;YACxC,MAAMC,gBAAgB,MAAM,IAAI,CAACC,gBAAgB,CAACjC;YAElD,IAAIgC,cAAcH,MAAM,KAAK,GAAG;gBAC9B7C,OAAOuB,KAAK,CAAC,2CAA2C;oBACtD2B,gBAAgBN,YAAYC,MAAM;gBACpC;gBACA;YACF;YAEA,kCAAkC;YAClC,MAAMM,qBAAqBH,cAAcF,GAAG,CAACC,CAAAA,IAAM,CAAA;oBACjDK,KAAK9D,oBAAoByD;oBACzBM,WAAWN,EAAEpB,EAAE;gBACjB,CAAA;YAEA,yCAAyC;YACzC,MAAM,IAAI,CAACzB,SAAS,CAAC0B,kBAAkB,CAAC;gBACtC;oBACEC,UAAU;oBACVC,WAAW,OAAOC;wBAChB,MAAMA,QAAQuB,UAAU,CAAC,qBAAqBN;wBAC9C,MAAMtD,iBAAiByD,oBAAoBpB;oBAC7C;gBACF;gBACA;oBACEF,UAAU;oBACVC,WAAW,OAAOC;wBAChB,MAAMA,QAAQuB,UAAU,CAAC,qBAAqBN;wBAC9C,MAAMtD,iBAAiByD,oBAAoBpB;oBAC7C;gBACF;aACD;YAED/B,OAAOW,IAAI,CAAC,qCAAqC;gBAC/C4C,eAAeX,YAAYC,MAAM;gBACjCW,gBAAgBR,cAAcH,MAAM;gBACpCY,oBAAoBb,YAAYC,MAAM,GAAGG,cAAcH,MAAM;YAC/D;QACF,EAAE,OAAOP,OAAO;YACdtC,OAAOsC,KAAK,CAAC,+BAA+B;gBAC1C1B,YAAYgC,YAAYC,MAAM;gBAC9BP,OAAOA,iBAAiBC,QAAQD,MAAME,OAAO,GAAGC,OAAOH;YACzD;YAEA,MAAM,IAAIxC,cACRC,UAAU2C,cAAc,EACxB,+BACA;gBAAEE;gBAAaN;YAAM;QAEzB;IACF;IAEA;;;;;GAKC,GACD,MAAMoB,aAAaC,OAAsB,EAA+B;QACtE,IAAI;YACF,MAAMC,eAA+C;gBACnDD,SAAS,EAAE;gBACXE,OAAOF,QAAQE,KAAK,IAAI;gBACxBC,QAAQH,QAAQG,MAAM,IAAI;gBAC1BC,SAAS;gBACTC,OAAO;YACT;YAEA,cAAc;YACd,IAAIL,QAAQ1B,QAAQ,EAAE;gBACpB2B,aAAaD,OAAO,EAAEM,KAAK;oBACzBC,OAAO;oBACPC,UAAU;oBACVC,OAAOT,QAAQ1B,QAAQ;gBACzB;YACF;YAEA,IAAI0B,QAAQU,QAAQ,EAAE;gBACpBT,aAAaD,OAAO,EAAEM,KAAK;oBACzBC,OAAO;oBACPC,UAAU;oBACVC,OAAOT,QAAQU,QAAQ;gBACzB;YACF;YAEA,IAAIV,QAAQzB,OAAO,EAAE;gBACnB0B,aAAaD,OAAO,EAAEM,KAAK;oBACzBC,OAAO;oBACPC,UAAU;oBACVC,OAAOT,QAAQzB,OAAO;gBACxB;YACF;YAEA,IAAIyB,QAAQtB,MAAM,EAAE;gBAClBuB,aAAaD,OAAO,EAAEM,KAAK;oBACzBC,OAAO;oBACPC,UAAU;oBACVC,OAAOT,QAAQtB,MAAM;gBACvB;YACF;YAEA,IAAIsB,QAAQW,UAAU,IAAIX,QAAQY,QAAQ,EAAE;gBAC1CX,aAAaD,OAAO,EAAEM,KAAK;oBACzBC,OAAO;oBACPC,UAAU;oBACVC,OAAO;wBAACT,QAAQW,UAAU;wBAAEX,QAAQY,QAAQ;qBAAC;gBAC/C;YACF;YAEA,iDAAiD;YACjD,MAAMC,UAAU,MAAM,IAAI,CAACrE,aAAa,CAACsE,IAAI,CAC3C,qBACAb;YAGF5D,OAAOuB,KAAK,CAAC,0BAA0B;gBACrCoC;gBACAe,cAAcF,QAAQ3B,MAAM;YAC9B;YAEA,OAAO2B;QACT,EAAE,OAAOlC,OAAO;YACdtC,OAAOsC,KAAK,CAAC,2BAA2B;gBACtCqB;gBACArB,OAAOA,iBAAiBC,QAAQD,MAAME,OAAO,GAAGC,OAAOH;YACzD;YAEA,MAAM,IAAIxC,cACRC,UAAU2C,cAAc,EACxB,2BACA;gBAAEiB;gBAASrB;YAAM;QAErB;IACF;IAEA;;;;;;GAMC,GACD,MAAMqC,qBACJC,SAAgB,EAChBC,OAAc,EACiB;QAC/B,IAAI;YACF,kCAAkC;YAClC,MAAMlB,UAAyB;gBAC7BW,YAAYM;gBACZL,UAAUM;gBACVhB,OAAO;YACT;YAEA,MAAM9C,UAAU,MAAM,IAAI,CAAC2C,YAAY,CAACC;YAExC,wBAAwB;YACxB,MAAMmB,iBAAiB,IAAIC;YAE3BhE,QAAQiE,OAAO,CAACjC,CAAAA;gBACd,IAAI,CAAC+B,eAAeG,GAAG,CAAClC,EAAEd,QAAQ,GAAG;oBACnC6C,eAAeI,GAAG,CAACnC,EAAEd,QAAQ,EAAE;wBAC7BA,UAAUc,EAAEd,QAAQ;wBACpBkD,kBAAkB;wBAClBC,gBAAgB;wBAChBC,cAAc;wBACdC,iBAAiB;wBACjBC,eAAe;wBACfC,eAAe;wBACfC,cAAc;oBAChB;gBACF;gBAEA,MAAMC,MAAMZ,eAAea,GAAG,CAAC5C,EAAEd,QAAQ;gBACzCyD,IAAIP,gBAAgB;gBACpBO,IAAIN,cAAc,IAAIrC,EAAEX,QAAQ;gBAChCsD,IAAIL,YAAY,IAAItC,EAAE6C,WAAW;gBACjCF,IAAIJ,eAAe,IAAIvC,EAAEZ,WAAW;gBAEpC,IAAIY,EAAEV,MAAM,KAAK,WAAW;oBAC1BqD,IAAIH,aAAa;gBACnB,OAAO;oBACLG,IAAIF,aAAa;gBACnB;YACF;YAEA,uCAAuC;YACvC,MAAMhB,UAAgC,EAAE;YACxCM,eAAeE,OAAO,CAACU,CAAAA;gBACrBA,IAAIJ,eAAe,GAAGO,KAAKC,KAAK,CAACJ,IAAIJ,eAAe,GAAGI,IAAIP,gBAAgB;gBAC3EO,IAAID,YAAY,GAAG,AAACC,IAAIH,aAAa,GAAGG,IAAIP,gBAAgB,GAAI;gBAChEO,IAAIN,cAAc,GAAGxF,UAAU8F,IAAIN,cAAc;gBACjDZ,QAAQP,IAAI,CAACyB;YACf;YAEA,kCAAkC;YAClClB,QAAQuB,IAAI,CAAC,CAACC,GAAGC,IAAMA,EAAEb,cAAc,GAAGY,EAAEZ,cAAc;YAE1DpF,OAAOW,IAAI,CAAC,iCAAiC;gBAC3CuF,aAAa1B,QAAQ3B,MAAM;gBAC3BsC,kBAAkBX,QAAQ2B,MAAM,CAAC,CAACC,KAAKV,MAAQU,MAAMV,IAAIP,gBAAgB,EAAE;YAC7E;YAEA,OAAOX;QACT,EAAE,OAAOlC,OAAO;YACdtC,OAAOsC,KAAK,CAAC,oCAAoC;gBAC/CA,OAAOA,iBAAiBC,QAAQD,MAAME,OAAO,GAAGC,OAAOH;YACzD;YAEA,MAAM,IAAIxC,cACRC,UAAU2C,cAAc,EACxB,oCACA;gBAAEJ;YAAM;QAEZ;IACF;IAEA;;;;GAIC,GACD,MAAM+D,aAAatF,OAAyB,EAAiB;QAC3D,IAAI,CAACR,UAAU,CAAC0D,IAAI,CAAClD;QAErB,8BAA8B;QAC9B,IAAI,IAAI,CAACR,UAAU,CAACsC,MAAM,IAAI,IAAI,CAACxC,SAAS,EAAE;YAC5C,MAAM,IAAI,CAACiG,KAAK;QAClB,OAAO;YACL,2CAA2C;YAC3C,IAAI,CAAC,IAAI,CAAC9F,UAAU,EAAE;gBACpB,IAAI,CAACA,UAAU,GAAG+F,WAAW,IAAM,IAAI,CAACD,KAAK,IAAI,IAAI,CAAChG,eAAe;YACvE;QACF;IACF;IAEA;;GAEC,GACD,MAAMgG,QAAuB;QAC3B,IAAI,IAAI,CAAC/F,UAAU,CAACsC,MAAM,KAAK,GAAG;YAChC;QACF;QAEA,cAAc;QACd,IAAI,IAAI,CAACrC,UAAU,EAAE;YACnBgG,aAAa,IAAI,CAAChG,UAAU;YAC5B,IAAI,CAACA,UAAU,GAAG;QACpB;QAEA,uBAAuB;QACvB,MAAMiG,QAAQ;eAAI,IAAI,CAAClG,UAAU;SAAC;QAClC,IAAI,CAACA,UAAU,GAAG,EAAE;QAEpB,YAAY;QACZ,MAAM,IAAI,CAACoC,QAAQ,CAAC8D;IACtB;IAEA;;;;;GAKC,GACD,AAAQxF,iBAAiBF,OAAyB,EAAoB;QACpE,8BAA8B;QAC9B,MAAMY,KAAKZ,QAAQY,EAAE,IAAItC;QAEzB,yBAAyB;QACzB,MAAMqH,OAAO9G,UAAUmB,QAAQqB,QAAQ;QACvC,IAAI,CAACzC,qBAAqB+G,OAAO;YAC/B1G,OAAO2G,IAAI,CAAC,mCAAmC;gBAC7CC,eAAe7F,QAAQqB,QAAQ;gBAC/ByE,cAAcH;YAChB;QACF;QAEA,kCAAkC;QAClC,MAAMI,YAAY/F,QAAQ+F,SAAS,YAAYC,OAC3ChG,QAAQ+F,SAAS,GACjB,IAAIC,KAAKhG,QAAQ+F,SAAS;QAE9B,OAAO;YACL,GAAG/F,OAAO;YACVY;YACAmF;YACA1E,UAAUsE;YACVM,UAAUjG,QAAQiG,QAAQ,GAAGC,KAAKC,SAAS,CAACnG,QAAQiG,QAAQ,IAAIG;QAClE;IACF;IAEA;;;;;GAKC,GACD,MAAclE,iBACZL,WAA+B,EACF;QAC7B,4BAA4B;QAC5B,MAAMwE,OAAOxE,YAAYE,GAAG,CAACC,CAAAA,IAAKzD,oBAAoByD;QAEtD,2CAA2C;QAC3C,MAAMsE,eAAe,MAAM5H,kBAAkB2H,MAAM,IAAI,CAACjH,aAAa;QAErE,+CAA+C;QAC/C,MAAMmH,iBAAiB,MAAM7H,kBAAkB2H,MAAM,IAAI,CAAChH,eAAe;QAEzE,gEAAgE;QAChE,MAAM4C,gBAAoC,EAAE;QAC5CJ,YAAYoC,OAAO,CAAC,CAACjE,SAASwG;YAC5B,MAAMnE,MAAMgE,IAAI,CAACG,MAAM;YACvB,MAAMC,WAAWH,aAAa1B,GAAG,CAACvC,QAAQ;YAC1C,MAAMqE,aAAaH,eAAe3B,GAAG,CAACvC,QAAQ;YAE9C,IAAI,CAACoE,YAAY,CAACC,YAAY;gBAC5B,6DAA6D;gBAC7DzE,cAAciB,IAAI,CAAClD;YACrB;QACF;QAEA,OAAOiC;IACT;IAEA;;GAEC,GACD,MAAM0E,QAAuB;QAC3B,0BAA0B;QAC1B,MAAM,IAAI,CAACpB,KAAK;QAEhB,cAAc;QACd,IAAI,IAAI,CAAC9F,UAAU,EAAE;YACnBgG,aAAa,IAAI,CAAChG,UAAU;YAC5B,IAAI,CAACA,UAAU,GAAG;QACpB;QAEAR,OAAOW,IAAI,CAAC;IACd;AACF;AAEA;;;;;;;CAOC,GACD,OAAO,SAASgH,oBACdzH,SAA0B,EAC1BG,SAAkB,EAClBC,eAAwB;IAExB,OAAO,IAAIL,cAAc;QACvBC;QACAG;QACAC;IACF;AACF"}