claude-flow-novice 2.15.2 → 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 (533) 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-BACKUP_USAGE.md +243 -243
  36. package/.claude/hooks/cfn-invoke-security-validation.sh +69 -69
  37. package/.claude/hooks/cfn-lint-sql-injection.sh +61 -0
  38. package/.claude/hooks/cfn-post-edit-cfn-retrospective.sh +109 -78
  39. package/.claude/hooks/cfn-post-edit.config.json +44 -44
  40. package/.claude/hooks/cfn-pre-edit-security-warning.sh +40 -0
  41. package/.claude/skills/cfn-agent-spawning/spawn-agent.sh +22 -24
  42. package/.claude/skills/cfn-docker-agent-spawning/SKILL.md +28 -4
  43. package/.claude/skills/cfn-docker-agent-spawning/spawn-agent.sh +3 -1
  44. package/.claude/skills/cfn-docker-loop-orchestration/orchestrate.sh +224 -20
  45. package/.claude/skills/cfn-hybrid-routing/check-dependencies.sh +51 -51
  46. package/.claude/skills/cfn-loop-orchestration/helpers/gate-check.sh +550 -46
  47. package/.claude/skills/cfn-loop-orchestration/helpers/parse-test-results.sh +277 -0
  48. package/.claude/skills/cfn-loop-orchestration/orchestrate.sh +184 -23
  49. package/.claude/skills/cfn-loop-orchestration/security_utils.sh +24 -0
  50. package/.claude/skills/cfn-loop-orchestration/test-iteration-context-injection.sh +366 -0
  51. package/.claude/skills/cfn-loop-validation/orchestrate-cfn-loop.sh +252 -252
  52. package/.claude/skills/cfn-redis-coordination/CENTRALIZED_REDIS_WRAPPER.md +319 -0
  53. package/.claude/skills/cfn-redis-coordination/agent-log.sh +4 -0
  54. package/.claude/skills/cfn-redis-coordination/agent-log.sh.bak +124 -0
  55. package/.claude/skills/cfn-redis-coordination/agent-recovery.sh +74 -74
  56. package/.claude/skills/cfn-redis-coordination/collect-confidence-scores.sh +30 -0
  57. package/.claude/skills/cfn-redis-coordination/get-context.sh +145 -112
  58. package/.claude/skills/cfn-redis-coordination/get-success-criteria.sh +54 -0
  59. package/.claude/skills/cfn-redis-coordination/invoke-waiting-mode.sh +3 -0
  60. package/.claude/skills/cfn-redis-coordination/redis-cli-wrapper.sh +24 -3
  61. package/.claude/skills/cfn-redis-coordination/redis-functions.sh +33 -0
  62. package/.claude/skills/cfn-redis-coordination/report-completion.sh +24 -31
  63. package/.claude/skills/cfn-redis-coordination/store-context.sh +4 -0
  64. package/.claude/skills/cfn-redis-coordination/store-success-criteria.sh +85 -0
  65. package/.claude/skills/cfn-redis-coordination/update-all-scripts.sh +67 -0
  66. package/.claude/skills/cfn-sqlite-memory/ttl-cleanup.sh +17 -25
  67. package/.claude/skills/cfn-transparency-middleware/middleware-config.sh +28 -28
  68. package/.claude/skills/cfn-transparency-middleware/performance-benchmark.sh +78 -78
  69. package/.claude/skills/cfn-transparency-middleware/test-e2e.sh +15 -0
  70. package/.claude/skills/cfn-transparency-middleware/test-integration.sh +161 -161
  71. package/.claude/skills/cfn-transparency-middleware/test-transparency-skill.sh +367 -367
  72. package/.claude/skills/cfn-transparency-middleware/tests/input-validation.sh +107 -92
  73. package/.claude/skills/cfn-transparency-middleware/wrap-agent.sh +131 -131
  74. package/README.md +116 -475
  75. package/claude-assets/agents/cfn-dev-team/README.md +103 -0
  76. package/claude-assets/agents/cfn-dev-team/architecture/goal-planner.md +1 -1
  77. package/claude-assets/agents/cfn-dev-team/coordinators/cfn-frontend-coordinator.md +77 -15
  78. package/claude-assets/agents/cfn-dev-team/coordinators/cfn-v3-coordinator.md +355 -6
  79. package/claude-assets/agents/cfn-dev-team/coordinators/consensus-builder.md +82 -1
  80. package/claude-assets/agents/cfn-dev-team/coordinators/handoff-coordinator.md +82 -1
  81. package/claude-assets/agents/cfn-dev-team/coordinators/multi-sprint-coordinator.md +77 -15
  82. package/claude-assets/agents/cfn-dev-team/dev-ops/docker-specialist.md +99 -12
  83. package/claude-assets/agents/cfn-dev-team/dev-ops/github-commit-agent.md +1 -1
  84. package/claude-assets/agents/cfn-dev-team/dev-ops/kubernetes-specialist.md +97 -0
  85. package/claude-assets/agents/cfn-dev-team/dev-ops/monitoring-specialist.md +20 -1
  86. package/claude-assets/agents/cfn-dev-team/developers/api-gateway-specialist.md +97 -0
  87. package/claude-assets/agents/cfn-dev-team/developers/backend-developer.md +110 -13
  88. package/claude-assets/agents/cfn-dev-team/developers/data/data-engineer.md +106 -15
  89. package/claude-assets/agents/cfn-dev-team/developers/database/database-architect.md +115 -11
  90. package/claude-assets/agents/cfn-dev-team/developers/frontend/mobile-dev.md +94 -7
  91. package/claude-assets/agents/cfn-dev-team/developers/frontend/react-frontend-engineer.md +87 -9
  92. package/claude-assets/agents/cfn-dev-team/developers/frontend/typescript-specialist.md +85 -7
  93. package/claude-assets/agents/cfn-dev-team/developers/frontend/ui-designer.md +160 -28
  94. package/claude-assets/agents/cfn-dev-team/developers/graphql-specialist.md +101 -19
  95. package/claude-assets/agents/cfn-dev-team/developers/rust-developer.md +108 -14
  96. package/claude-assets/agents/cfn-dev-team/reviewers/{reviewer.md → code-reviewer.md} +95 -8
  97. package/claude-assets/agents/cfn-dev-team/reviewers/quality/code-quality-validator.md +107 -7
  98. package/claude-assets/agents/cfn-dev-team/reviewers/quality/perf-analyzer.md +98 -7
  99. package/claude-assets/agents/cfn-dev-team/reviewers/quality/performance-benchmarker.md +95 -7
  100. package/claude-assets/agents/cfn-dev-team/reviewers/quality/security-specialist.md +136 -9
  101. package/claude-assets/agents/cfn-dev-team/testers/api-testing-specialist.md +108 -1
  102. package/claude-assets/agents/cfn-dev-team/testers/chaos-engineering-specialist.md +107 -13
  103. package/claude-assets/agents/cfn-dev-team/testers/contract-tester.md +737 -0
  104. package/claude-assets/agents/cfn-dev-team/testers/e2e/playwright-tester.md +1 -1
  105. package/claude-assets/agents/cfn-dev-team/testers/integration-tester.md +828 -0
  106. package/claude-assets/agents/cfn-dev-team/testers/interaction-tester.md +106 -7
  107. package/claude-assets/agents/cfn-dev-team/testers/load-testing-specialist.md +77 -0
  108. package/claude-assets/agents/cfn-dev-team/testers/mutation-testing-specialist.md +684 -0
  109. package/claude-assets/agents/cfn-dev-team/testers/playwright-tester.md +110 -1
  110. package/claude-assets/agents/cfn-dev-team/testers/tester.md +94 -7
  111. package/claude-assets/agents/cfn-dev-team/utility/code-booster.md +1 -3
  112. package/claude-assets/agents/cfn-dev-team/utility/epic-creator.md +87 -13
  113. package/claude-assets/agents/cfn-dev-team/utility/memory-leak-specialist.md +103 -7
  114. package/claude-assets/agents/cfn-dev-team/utility/researcher.md +1 -3
  115. package/claude-assets/agents/cfn-dev-team/utility/z-ai-specialist.md +94 -7
  116. package/claude-assets/agents/docker-coordinators/cfn-docker-v3-coordinator.md +46 -0
  117. package/claude-assets/agents/project-only-agents/npm-package-specialist.md +1 -1
  118. package/claude-assets/cfn-extras/skills/advanced-features/cfn-agent-swap/recommend-swap.sh +59 -59
  119. package/claude-assets/cfn-extras/skills/analytics/cfn-improvement-recommender/recommend-improvements.sh +91 -91
  120. package/claude-assets/cfn-extras/skills/analytics/cfn-pattern-extraction/extract-patterns.sh +79 -79
  121. package/claude-assets/cfn-extras/skills/analytics/cfn-retrospective-report/generate-report.sh +100 -100
  122. package/claude-assets/cfn-extras/skills/analytics/cfn-telemetry/start-telemetry.sh +110 -110
  123. package/claude-assets/cfn-extras/skills/deprecated/cfn-ace-system/add-bullet.sh +145 -145
  124. package/claude-assets/cfn-extras/skills/deprecated/cfn-ace-system/log-merge.sh +67 -67
  125. package/claude-assets/cfn-extras/skills/deprecated/cfn-ace-system/monitor-injection-performance.sh +137 -137
  126. package/claude-assets/cfn-extras/skills/deprecated/cfn-ace-system/optimize-injection-pipeline.sh +168 -168
  127. package/claude-assets/cfn-extras/skills/deprecated/cfn-ace-system/query-reflections.sh +35 -35
  128. package/claude-assets/cfn-extras/skills/deprecated/cfn-ace-system/store-reflection.sh +45 -45
  129. package/claude-assets/cfn-extras/skills/deprecated/cfn-ace-system/track-ab-test.sh +41 -41
  130. package/claude-assets/cfn-extras/skills/deprecated/cfn-ace-system/update-reflection.sh +41 -41
  131. package/claude-assets/cfn-extras/skills/deprecated/cfn-cli-setup/validate-cli-environment.sh +191 -191
  132. package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-ad-campaigns/operations/create-campaign.sh +231 -231
  133. package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-ad-campaigns/operations/get-campaign-performance.sh +190 -190
  134. package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-ad-campaigns/operations/pause-campaign.sh +142 -142
  135. package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-ad-campaigns/operations/set-budget.sh +181 -181
  136. package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-ad-campaigns/operations/update-bid-strategy.sh +133 -133
  137. package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-chatbot-conversations/operations/get-conversation-history.sh +121 -121
  138. package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-chatbot-conversations/operations/qualify-lead.sh +156 -156
  139. package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-chatbot-conversations/operations/schedule-demo.sh +181 -181
  140. package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-chatbot-conversations/operations/send-message.sh +137 -137
  141. package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-chatbot-conversations/operations/transfer-to-human.sh +179 -179
  142. package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-sms-campaigns/operations/create-campaign.sh +183 -183
  143. package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-sms-campaigns/operations/get-delivery-status.sh +139 -139
  144. package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-sms-campaigns/operations/opt-out.sh +150 -150
  145. package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-sms-campaigns/operations/schedule-campaign.sh +187 -187
  146. package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-sms-campaigns/operations/send-sms.sh +181 -181
  147. package/claude-assets/cfn-extras/skills/ui-portal/cfn-web-portal/test-web-portal-skill.sh +50 -50
  148. package/claude-assets/cfn-extras/skills/ui-portal/cfn-web-portal/validate-deployment.sh +84 -84
  149. package/claude-assets/cfn-extras/skills/utility/cfn-environment-sanitization/sanitize-environment.sh +243 -243
  150. package/claude-assets/commands/cfn-loop-cli.md +16 -2
  151. package/claude-assets/commands/switch-api.md +31 -10
  152. package/claude-assets/hooks/cfn-BACKUP_USAGE.md +243 -243
  153. package/claude-assets/hooks/cfn-invoke-security-validation.sh +69 -69
  154. package/claude-assets/hooks/cfn-lint-sql-injection.sh +61 -0
  155. package/claude-assets/hooks/cfn-post-edit-cfn-retrospective.sh +109 -78
  156. package/claude-assets/hooks/cfn-post-edit.config.json +44 -44
  157. package/claude-assets/hooks/cfn-post-execution/memory-cleanup.sh +19 -19
  158. package/claude-assets/hooks/cfn-pre-edit-security-warning.sh +40 -0
  159. package/claude-assets/hooks/cfn-pre-execution/memory-check.sh +19 -19
  160. package/claude-assets/hooks/detect-hardcoded-credentials.sh +212 -0
  161. package/claude-assets/skills/SKILL_TEMPLATE.md +774 -0
  162. package/claude-assets/skills/agent-lifecycle/execute-lifecycle-hook.sh +543 -572
  163. package/claude-assets/skills/agent-lifecycle/simple-audit.sh +57 -30
  164. package/claude-assets/skills/agent-template-generator/SKILL.md +440 -0
  165. package/claude-assets/skills/agent-template-generator/generate-agent.sh +405 -0
  166. package/claude-assets/skills/agent-validation-linter/SKILL.md +589 -0
  167. package/claude-assets/skills/agent-validation-linter/lint-agents.sh +271 -0
  168. package/claude-assets/skills/bootstrap/bash-fundamentals.md +786 -0
  169. package/claude-assets/skills/bootstrap/database-connection.md +464 -0
  170. package/claude-assets/skills/bootstrap/error-handling.md +580 -0
  171. package/claude-assets/skills/bootstrap/file-operations.md +699 -0
  172. package/claude-assets/skills/bootstrap/skill-loader.md +616 -0
  173. package/claude-assets/skills/bootstrap/sqlite-params.sh +287 -0
  174. package/claude-assets/skills/cfn-agent-spawning/spawn-agent.sh +22 -24
  175. package/claude-assets/skills/cfn-automatic-memory-persistence/persist-agent-output.sh +48 -48
  176. package/claude-assets/skills/cfn-automatic-memory-persistence/query-agent-history.sh +34 -34
  177. package/claude-assets/skills/cfn-automatic-memory-persistence/test-memory-persistence.sh +17 -16
  178. package/claude-assets/skills/cfn-deliverable-validation/confidence-calculator.sh +261 -261
  179. package/claude-assets/skills/cfn-deployment/SKILL.md +293 -0
  180. package/claude-assets/skills/cfn-deployment/execute.sh +21 -0
  181. package/claude-assets/skills/cfn-docker-agent-spawning/SKILL.md +28 -4
  182. package/claude-assets/skills/cfn-docker-agent-spawning/spawn-agent.sh +3 -1
  183. package/claude-assets/skills/cfn-docker-loop-orchestration/orchestrate.sh +224 -20
  184. package/claude-assets/skills/cfn-environment-sanitization/sanitize-environment.sh +38 -0
  185. package/claude-assets/skills/cfn-error-batching-strategy/lib/core-functions.sh +47 -47
  186. package/claude-assets/skills/cfn-expert-update/update-expert.sh +345 -345
  187. package/claude-assets/skills/cfn-file-operations/SKILL.md +290 -0
  188. package/claude-assets/skills/cfn-file-operations/execute.sh +129 -0
  189. package/claude-assets/skills/cfn-file-operations/lib/atomic-write.sh +294 -0
  190. package/claude-assets/skills/cfn-file-operations/lib/lock.sh +361 -0
  191. package/claude-assets/skills/cfn-file-operations/test.sh +369 -0
  192. package/claude-assets/skills/cfn-hybrid-routing/check-dependencies.sh +51 -51
  193. package/claude-assets/skills/cfn-intervention-detector/detect-intervention.sh +110 -110
  194. package/claude-assets/skills/cfn-intervention-orchestrator/execute-intervention.sh +58 -58
  195. package/claude-assets/skills/cfn-log-operations/SKILL.md +308 -0
  196. package/claude-assets/skills/cfn-log-operations/execute.sh +420 -0
  197. package/claude-assets/skills/cfn-log-operations/lib/rotate.sh +406 -0
  198. package/claude-assets/skills/cfn-log-operations/lib/search.sh +448 -0
  199. package/claude-assets/skills/cfn-log-operations/test.sh +394 -0
  200. package/claude-assets/skills/cfn-loop-orchestration/helpers/gate-check.sh +550 -46
  201. package/claude-assets/skills/cfn-loop-orchestration/helpers/parse-test-results.sh +277 -0
  202. package/claude-assets/skills/cfn-loop-orchestration/orchestrate.sh +184 -23
  203. package/claude-assets/skills/cfn-loop-orchestration/security_utils.sh +24 -0
  204. package/claude-assets/skills/cfn-loop-orchestration/test-iteration-context-injection.sh +366 -0
  205. package/claude-assets/skills/cfn-loop-validation/orchestrate-cfn-loop.sh +252 -252
  206. package/claude-assets/skills/cfn-loop2-output-processing/process-validator-output.sh +275 -275
  207. package/claude-assets/skills/cfn-memory-management/check-memory.sh +159 -159
  208. package/claude-assets/skills/cfn-memory-management/cleanup-memory.sh +196 -196
  209. package/claude-assets/skills/cfn-node-heap-sizer/task-mode-heap-limiter.sh +325 -325
  210. package/claude-assets/skills/cfn-parameterized-queries/SKILL.md +339 -0
  211. package/claude-assets/skills/cfn-playbook/query-playbook.sh +19 -15
  212. package/claude-assets/skills/cfn-playbook/update-playbook.sh +25 -14
  213. package/claude-assets/skills/cfn-playbook-auto-update/auto-update-playbook.sh +85 -85
  214. package/claude-assets/skills/cfn-process-instrumentation/instrument-process.sh +44 -0
  215. package/claude-assets/skills/cfn-promotion/SKILL.md +305 -0
  216. package/claude-assets/skills/cfn-redis-coordination/CENTRALIZED_REDIS_WRAPPER.md +319 -0
  217. package/claude-assets/skills/cfn-redis-coordination/agent-log.sh +4 -0
  218. package/claude-assets/skills/cfn-redis-coordination/agent-log.sh.bak +124 -0
  219. package/claude-assets/skills/cfn-redis-coordination/agent-recovery.sh +74 -74
  220. package/claude-assets/skills/cfn-redis-coordination/collect-confidence-scores.sh +30 -0
  221. package/claude-assets/skills/cfn-redis-coordination/get-context.sh +145 -112
  222. package/claude-assets/skills/cfn-redis-coordination/get-success-criteria.sh +54 -0
  223. package/claude-assets/skills/cfn-redis-coordination/invoke-waiting-mode.sh +3 -0
  224. package/claude-assets/skills/cfn-redis-coordination/redis-cli-wrapper.sh +24 -3
  225. package/claude-assets/skills/cfn-redis-coordination/redis-functions.sh +33 -0
  226. package/claude-assets/skills/cfn-redis-coordination/report-completion.sh +24 -31
  227. package/claude-assets/skills/cfn-redis-coordination/store-context.sh +4 -0
  228. package/claude-assets/skills/cfn-redis-coordination/store-success-criteria.sh +85 -0
  229. package/claude-assets/skills/cfn-redis-coordination/update-all-scripts.sh +67 -0
  230. package/claude-assets/skills/cfn-scope-simplifier/simplify-scope.sh +67 -67
  231. package/claude-assets/skills/cfn-skill-loader/SKILL.md +466 -0
  232. package/claude-assets/skills/cfn-skill-loader/execute.sh +344 -0
  233. package/claude-assets/skills/cfn-specialist-injection/recommend-specialist.sh +56 -56
  234. package/claude-assets/skills/cfn-sqlite-memory/ttl-cleanup.sh +17 -25
  235. package/claude-assets/skills/cfn-standardized-error-handling/capture-agent-error.sh +86 -86
  236. package/claude-assets/skills/cfn-standardized-error-handling/test-error-handling.sh +165 -165
  237. package/claude-assets/skills/cfn-task-audit/get-audit-data.sh +42 -21
  238. package/claude-assets/skills/cfn-task-audit/store-task-audit.sh +17 -10
  239. package/claude-assets/skills/cfn-task-config-init/initialize-config.sh +264 -264
  240. package/claude-assets/skills/cfn-task-decomposition/task-decomposer.sh +278 -278
  241. package/claude-assets/skills/cfn-test-runner/detect-regressions.sh +17 -14
  242. package/claude-assets/skills/cfn-test-runner/detect-regressions.sh.backup-1763392821 +55 -0
  243. package/claude-assets/skills/cfn-test-runner/store-benchmarks.sh +17 -19
  244. package/claude-assets/skills/cfn-transparency-middleware/middleware-config.sh +28 -28
  245. package/claude-assets/skills/cfn-transparency-middleware/performance-benchmark.sh +78 -78
  246. package/claude-assets/skills/cfn-transparency-middleware/test-e2e.sh +15 -0
  247. package/claude-assets/skills/cfn-transparency-middleware/test-integration.sh +161 -161
  248. package/claude-assets/skills/cfn-transparency-middleware/test-transparency-skill.sh +367 -367
  249. package/claude-assets/skills/cfn-transparency-middleware/tests/input-validation.sh +107 -92
  250. package/claude-assets/skills/cfn-transparency-middleware/wrap-agent.sh +131 -131
  251. package/claude-assets/skills/cfn-utilities/SKILL.md +237 -0
  252. package/claude-assets/skills/cfn-utilities/execute.sh +32 -0
  253. package/claude-assets/skills/cfn-utilities/lib/errors.sh +56 -0
  254. package/claude-assets/skills/cfn-utilities/lib/file-ops.sh +164 -0
  255. package/claude-assets/skills/cfn-utilities/lib/logging.sh +77 -0
  256. package/claude-assets/skills/cfn-utilities/lib/retry.sh +127 -0
  257. package/claude-assets/skills/cfn-utilities/test.sh +317 -0
  258. package/claude-assets/skills/docker-build/SKILL.md +96 -203
  259. package/claude-assets/skills/docker-build/build.sh +73 -73
  260. package/claude-assets/skills/integration/agent-handoff.sh +492 -0
  261. package/claude-assets/skills/integration/file-operations.sh +414 -0
  262. package/claude-assets/skills/json-validation/SKILL.md +431 -0
  263. package/claude-assets/skills/json-validation/test-validate-success-criteria.sh +421 -0
  264. package/claude-assets/skills/json-validation/validate-success-criteria.sh +197 -0
  265. package/claude-assets/skills/redis-coordination/validate-parameters.sh +34 -0
  266. package/claude-assets/skills/workflow-codification/APPROVAL_WORKFLOW.md +806 -0
  267. package/claude-assets/skills/workflow-codification/COST_TRACKING.md +637 -0
  268. package/claude-assets/skills/workflow-codification/DEPLOY_QUICK_REFERENCE.md +106 -0
  269. package/claude-assets/skills/workflow-codification/EDGE_CASE_TRACKING.md +404 -0
  270. package/claude-assets/skills/workflow-codification/PROPAGATE_UPDATE_QUICK_REFERENCE.md +366 -0
  271. package/claude-assets/skills/workflow-codification/README_PHASE4.md +457 -0
  272. package/claude-assets/skills/workflow-codification/SKILL.md +110 -0
  273. package/claude-assets/skills/workflow-codification/analyze-patterns.sh +899 -0
  274. package/claude-assets/skills/workflow-codification/approval-workflow.sh +514 -0
  275. package/claude-assets/skills/workflow-codification/deploy-approved-skill.sh +481 -0
  276. package/claude-assets/skills/workflow-codification/deploy-approved-skill.sh.backup-1763392820 +512 -0
  277. package/claude-assets/skills/workflow-codification/generate-skill-update.sh +525 -0
  278. package/claude-assets/skills/workflow-codification/lib/security-utils.sh +204 -0
  279. package/claude-assets/skills/workflow-codification/propagate-skill-update.sh +648 -0
  280. package/claude-assets/skills/workflow-codification/propagate-skill-update.sh.backup-1763392820 +664 -0
  281. package/claude-assets/skills/workflow-codification/review-skill.sh +643 -0
  282. package/claude-assets/skills/workflow-codification/templates/email-notification.txt +114 -0
  283. package/claude-assets/skills/workflow-codification/templates/slack-notification.md +85 -0
  284. package/claude-assets/skills/workflow-codification/test-integration.sh +296 -0
  285. package/claude-assets/skills/workflow-codification/test-metadata-update.sh +350 -0
  286. package/claude-assets/skills/workflow-codification/track-cost-savings.sh +486 -0
  287. package/claude-assets/skills/workflow-codification/track-cost-savings.sh.backup-1763392821 +445 -0
  288. package/claude-assets/skills/workflow-codification/track-edge-case.sh +290 -0
  289. package/claude-assets/skills/workflow-codification/workflow-codification.db +0 -0
  290. package/dist/ace/ace-curator.js +10 -2
  291. package/dist/ace/ace-curator.js.map +1 -1
  292. package/dist/ace/ace-generator.js +4 -0
  293. package/dist/ace/ace-generator.js.map +1 -1
  294. package/dist/ace/ace-reflector.js +1 -1
  295. package/dist/ace/ace-reflector.js.map +1 -1
  296. package/dist/ace/context-injection.js +24 -2
  297. package/dist/ace/context-injection.js.map +1 -1
  298. package/dist/agents/agent-loader.js +146 -165
  299. package/dist/agents/agent-loader.js.map +1 -1
  300. package/dist/agents/task-agent-integration.js +1 -1
  301. package/dist/agents/task-agent-integration.js.map +1 -1
  302. package/dist/api/health-endpoints.js +390 -0
  303. package/dist/api/health-endpoints.js.map +1 -0
  304. package/dist/cli/agent-executor.js +4 -1
  305. package/dist/cli/agent-executor.js.map +1 -1
  306. package/dist/cli/agent-prompt-builder.js +89 -1
  307. package/dist/cli/agent-prompt-builder.js.map +1 -1
  308. package/dist/cli/agent-spawn.js +130 -37
  309. package/dist/cli/agent-spawn.js.map +1 -1
  310. package/dist/cli/config-manager.js +91 -109
  311. package/dist/cli/config-manager.js.map +1 -1
  312. package/dist/cli/skill-cache-validator.js +412 -0
  313. package/dist/cli/skill-cache-validator.js.map +1 -0
  314. package/dist/cli/skill-cli.js +991 -0
  315. package/dist/cli/skill-cli.js.map +1 -0
  316. package/dist/cli/skill-execution-logger.js +284 -0
  317. package/dist/cli/skill-execution-logger.js.map +1 -0
  318. package/dist/cli/skill-loader.js +457 -0
  319. package/dist/cli/skill-loader.js.map +1 -0
  320. package/dist/coordination/event-bus.js +2 -2
  321. package/dist/coordination/event-bus.js.map +1 -1
  322. package/dist/coordination/fleet-manager.js +1 -1
  323. package/dist/coordination/fleet-manager.js.map +1 -1
  324. package/dist/coordination/index.js +23 -9
  325. package/dist/coordination/index.js.map +1 -1
  326. package/dist/coordination/types/fleet-manager.types.js.map +1 -1
  327. package/dist/db/migration-manager.js +483 -0
  328. package/dist/db/migration-manager.js.map +1 -0
  329. package/dist/db/skills-query.js +535 -0
  330. package/dist/db/skills-query.js.map +1 -0
  331. package/dist/integration/DatabaseHandoff.js +507 -0
  332. package/dist/integration/DatabaseHandoff.js.map +1 -0
  333. package/dist/integration/StandardAdapter.js +291 -0
  334. package/dist/integration/StandardAdapter.js.map +1 -0
  335. package/dist/jobs/edge-case-analyzer.js +367 -0
  336. package/dist/jobs/edge-case-analyzer.js.map +1 -0
  337. package/dist/jobs/promotion-sla-enforcer.js +288 -0
  338. package/dist/jobs/promotion-sla-enforcer.js.map +1 -0
  339. package/dist/lib/agent-output-parser.js +518 -0
  340. package/dist/lib/agent-output-parser.js.map +1 -0
  341. package/dist/lib/agent-output-validator.js +950 -0
  342. package/dist/lib/agent-output-validator.js.map +1 -0
  343. package/dist/lib/agent-workspace.js +281 -0
  344. package/dist/lib/agent-workspace.js.map +1 -0
  345. package/dist/lib/artifact-registry.js +443 -0
  346. package/dist/lib/artifact-registry.js.map +1 -0
  347. package/dist/lib/atomic-file-writer.js +377 -0
  348. package/dist/lib/atomic-file-writer.js.map +1 -0
  349. package/dist/lib/backup-manager.js +779 -0
  350. package/dist/lib/backup-manager.js.map +1 -0
  351. package/dist/lib/checkpoint-manager.js +837 -0
  352. package/dist/lib/checkpoint-manager.js.map +1 -0
  353. package/dist/lib/circuit-breaker.js +340 -0
  354. package/dist/lib/circuit-breaker.js.map +1 -0
  355. package/dist/lib/completion-signal-handler.js +243 -0
  356. package/dist/lib/completion-signal-handler.js.map +1 -0
  357. package/dist/lib/config-manager.js +312 -0
  358. package/dist/lib/config-manager.js.map +1 -0
  359. package/dist/lib/config-migrator.js +386 -0
  360. package/dist/lib/config-migrator.js.map +1 -0
  361. package/dist/lib/config-validator.js +687 -0
  362. package/dist/lib/config-validator.js.map +1 -0
  363. package/dist/lib/correlation-cache.js +311 -0
  364. package/dist/lib/correlation-cache.js.map +1 -0
  365. package/dist/lib/correlation.js +263 -0
  366. package/dist/lib/correlation.js.map +1 -0
  367. package/dist/lib/database-service/connection-pool-manager.js +520 -0
  368. package/dist/lib/database-service/connection-pool-manager.js.map +1 -0
  369. package/dist/lib/database-service/correlation.js +329 -0
  370. package/dist/lib/database-service/correlation.js.map +1 -0
  371. package/dist/lib/database-service/errors.js +120 -0
  372. package/dist/lib/database-service/errors.js.map +1 -0
  373. package/dist/lib/database-service/index.js +168 -0
  374. package/dist/lib/database-service/index.js.map +1 -0
  375. package/dist/lib/database-service/postgres-adapter.js +526 -0
  376. package/dist/lib/database-service/postgres-adapter.js.map +1 -0
  377. package/dist/lib/database-service/redis-adapter.js +360 -0
  378. package/dist/lib/database-service/redis-adapter.js.map +1 -0
  379. package/dist/lib/database-service/sqlite-adapter.js +544 -0
  380. package/dist/lib/database-service/sqlite-adapter.js.map +1 -0
  381. package/dist/lib/database-service/transaction-manager.js +773 -0
  382. package/dist/lib/database-service/transaction-manager.js.map +1 -0
  383. package/dist/lib/database-service/types.js +23 -0
  384. package/dist/lib/database-service/types.js.map +1 -0
  385. package/dist/lib/deadlock-resolver.js +292 -0
  386. package/dist/lib/deadlock-resolver.js.map +1 -0
  387. package/dist/lib/distributed-lock.js +451 -0
  388. package/dist/lib/distributed-lock.js.map +1 -0
  389. package/dist/lib/edge-case-deduplicator.js +227 -0
  390. package/dist/lib/edge-case-deduplicator.js.map +1 -0
  391. package/dist/lib/encryption-manager.js +322 -0
  392. package/dist/lib/encryption-manager.js.map +1 -0
  393. package/dist/lib/error-aggregator.js +234 -0
  394. package/dist/lib/error-aggregator.js.map +1 -0
  395. package/dist/lib/errors.js +287 -0
  396. package/dist/lib/errors.js.map +1 -0
  397. package/dist/lib/file-lock-manager.js +578 -0
  398. package/dist/lib/file-lock-manager.js.map +1 -0
  399. package/dist/lib/file-operations.js +367 -0
  400. package/dist/lib/file-operations.js.map +1 -0
  401. package/dist/lib/idempotent-write.js +237 -0
  402. package/dist/lib/idempotent-write.js.map +1 -0
  403. package/dist/lib/integration-schema-validator.js +522 -0
  404. package/dist/lib/integration-schema-validator.js.map +1 -0
  405. package/dist/lib/lock-health-monitor.js +298 -0
  406. package/dist/lib/lock-health-monitor.js.map +1 -0
  407. package/dist/lib/log-shipper.js +422 -0
  408. package/dist/lib/log-shipper.js.map +1 -0
  409. package/dist/lib/logging.js +146 -0
  410. package/dist/lib/logging.js.map +1 -0
  411. package/dist/lib/message-deduplicator.js +439 -0
  412. package/dist/lib/message-deduplicator.js.map +1 -0
  413. package/dist/lib/multi-system-query.js +604 -0
  414. package/dist/lib/multi-system-query.js.map +1 -0
  415. package/dist/lib/orphan-detector.js +332 -0
  416. package/dist/lib/orphan-detector.js.map +1 -0
  417. package/dist/lib/password-generator.js +166 -0
  418. package/dist/lib/password-generator.js.map +1 -0
  419. package/dist/lib/path-validator.js +429 -0
  420. package/dist/lib/path-validator.js.map +1 -0
  421. package/dist/lib/query-translator.js +905 -0
  422. package/dist/lib/query-translator.js.map +1 -0
  423. package/dist/lib/queue-recovery.js +469 -0
  424. package/dist/lib/queue-recovery.js.map +1 -0
  425. package/dist/lib/redis-queue-manager.js +512 -0
  426. package/dist/lib/redis-queue-manager.js.map +1 -0
  427. package/dist/lib/reflection-archiver.js +272 -0
  428. package/dist/lib/reflection-archiver.js.map +1 -0
  429. package/dist/lib/retry-manager.js +453 -0
  430. package/dist/lib/retry-manager.js.map +1 -0
  431. package/dist/lib/retry.js +262 -0
  432. package/dist/lib/retry.js.map +1 -0
  433. package/dist/lib/schema-transform.js +695 -0
  434. package/dist/lib/schema-transform.js.map +1 -0
  435. package/dist/lib/schema-validator.js +491 -0
  436. package/dist/lib/schema-validator.js.map +1 -0
  437. package/dist/lib/skill-cache.js +297 -0
  438. package/dist/lib/skill-cache.js.map +1 -0
  439. package/dist/lib/skill-content-manager.js +337 -0
  440. package/dist/lib/skill-content-manager.js.map +1 -0
  441. package/dist/lib/skill-frontmatter-parser.js +237 -0
  442. package/dist/lib/skill-frontmatter-parser.js.map +1 -0
  443. package/dist/lib/skill-git-integration.js +275 -0
  444. package/dist/lib/skill-git-integration.js.map +1 -0
  445. package/dist/lib/skill-markdown-validator.js +396 -0
  446. package/dist/lib/skill-markdown-validator.js.map +1 -0
  447. package/dist/lib/skill-output-parser.js +312 -0
  448. package/dist/lib/skill-output-parser.js.map +1 -0
  449. package/dist/lib/unified-query-api.js +467 -0
  450. package/dist/lib/unified-query-api.js.map +1 -0
  451. package/dist/middleware/auth-middleware.js +350 -0
  452. package/dist/middleware/auth-middleware.js.map +1 -0
  453. package/dist/middleware/schema-validation.js +347 -0
  454. package/dist/middleware/schema-validation.js.map +1 -0
  455. package/dist/providers/anthropic-provider.js +1 -1
  456. package/dist/providers/anthropic-provider.js.map +1 -1
  457. package/dist/providers/provider-factory.js +2 -2
  458. package/dist/providers/provider-factory.js.map +1 -1
  459. package/dist/services/edge-case-analyzer.js +321 -0
  460. package/dist/services/edge-case-analyzer.js.map +1 -0
  461. package/dist/services/edge-case-deduplicator.js +266 -0
  462. package/dist/services/edge-case-deduplicator.js.map +1 -0
  463. package/dist/services/edge-case-detector.js +337 -0
  464. package/dist/services/edge-case-detector.js.map +1 -0
  465. package/dist/services/edge-case-tracker.js +547 -0
  466. package/dist/services/edge-case-tracker.js.map +1 -0
  467. package/dist/services/health-check-system.js +586 -0
  468. package/dist/services/health-check-system.js.map +1 -0
  469. package/dist/services/metrics-logger.js +412 -0
  470. package/dist/services/metrics-logger.js.map +1 -0
  471. package/dist/services/patch-generator.js +378 -0
  472. package/dist/services/patch-generator.js.map +1 -0
  473. package/dist/services/patch-validator.js +337 -0
  474. package/dist/services/patch-validator.js.map +1 -0
  475. package/dist/services/performance-monitor.js +811 -0
  476. package/dist/services/performance-monitor.js.map +1 -0
  477. package/dist/services/promotion-pipeline.js +918 -0
  478. package/dist/services/promotion-pipeline.js.map +1 -0
  479. package/dist/services/promotion-validator.js +394 -0
  480. package/dist/services/promotion-validator.js.map +1 -0
  481. package/dist/services/reflection-logger.js +388 -0
  482. package/dist/services/reflection-logger.js.map +1 -0
  483. package/dist/services/skill-deployment.js +472 -0
  484. package/dist/services/skill-deployment.js.map +1 -0
  485. package/dist/services/skill-loader.js +427 -0
  486. package/dist/services/skill-loader.js.map +1 -0
  487. package/dist/services/skill-promotion.js +372 -0
  488. package/dist/services/skill-promotion.js.map +1 -0
  489. package/dist/services/skill-validator.js +454 -0
  490. package/dist/services/skill-validator.js.map +1 -0
  491. package/dist/services/skill-versioning.js +244 -0
  492. package/dist/services/skill-versioning.js.map +1 -0
  493. package/dist/services/workspace-supervisor.js +597 -0
  494. package/dist/services/workspace-supervisor.js.map +1 -0
  495. package/dist/types/agent-output.js +44 -0
  496. package/dist/types/agent-output.js.map +1 -0
  497. package/dist/types/config.js +28 -0
  498. package/dist/types/config.js.map +1 -0
  499. package/dist/types/edge-case.js +45 -0
  500. package/dist/types/edge-case.js.map +1 -0
  501. package/package.json +201 -176
  502. package/readme/README.md +19 -4
  503. package/scripts/artifact-cleanup.sh +392 -0
  504. package/scripts/backup-cleanup.sh +627 -0
  505. package/scripts/cleanup-workspaces.sh +412 -0
  506. package/scripts/cleanup-yaml-configs.sh +141 -0
  507. package/scripts/deploy-approved-skills.sh +263 -0
  508. package/scripts/deploy-production.sh +355 -355
  509. package/scripts/docker-playwright-fix.sh +311 -311
  510. package/scripts/docker-rebuild-all-agents.sh +127 -127
  511. package/scripts/health-check.sh +447 -0
  512. package/scripts/log-aggregator.sh +554 -0
  513. package/scripts/log-monitor.sh +629 -0
  514. package/scripts/manage-agent-workspaces.sh +434 -0
  515. package/scripts/memory-leak-prevention.sh +305 -305
  516. package/scripts/migrate-artifacts.sh +563 -0
  517. package/scripts/migrate-schema.sh +533 -0
  518. package/scripts/migrate-yaml-to-json.sh +465 -0
  519. package/scripts/promote-staged-skills.sh +423 -0
  520. package/scripts/run-marketing-tests.sh +42 -42
  521. package/scripts/update_paths.sh +46 -46
  522. package/scripts/verify-no-secrets.sh +88 -35
  523. package/.claude/cfn-extras/agents/deprecated-coordinators/adaptive-coordinator.md.backup +0 -161
  524. package/.claude/cfn-extras/agents/deprecated-coordinators/blocking-coordinator-example.md.backup +0 -728
  525. package/.claude/cfn-extras/agents/deprecated-coordinators/mesh-coordinator.md.backup +0 -131
  526. package/.claude/skills/cfn-agent-spawning/spawn-agent.sh.backup +0 -273
  527. package/.claude/skills/cfn-loop-orchestration/orchestrate.sh.backup +0 -949
  528. package/README.md.backup_before_replace +0 -781
  529. package/claude-assets/cfn-extras/agents/deprecated-coordinators/adaptive-coordinator.md.backup +0 -161
  530. package/claude-assets/cfn-extras/agents/deprecated-coordinators/blocking-coordinator-example.md.backup +0 -728
  531. package/claude-assets/cfn-extras/agents/deprecated-coordinators/mesh-coordinator.md.backup +0 -131
  532. package/claude-assets/skills/cfn-agent-spawning/spawn-agent.sh.backup +0 -273
  533. package/claude-assets/skills/cfn-loop-orchestration/orchestrate.sh.backup +0 -949
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/lib/redis-queue-manager.ts"],"sourcesContent":["/**\r\n * Redis Queue Manager\r\n *\r\n * Provides reliable queue operations with idempotency, acknowledgment protocol,\r\n * and message visibility timeout for Docker agent ↔ Redis communication.\r\n * Part of Task 3.4: Redis Queue Consistency & Recovery (Integration Standardization Sprint 3)\r\n *\r\n * Features:\r\n * - Enqueue with idempotency (prevents duplicate messages)\r\n * - Dequeue with acknowledgment protocol\r\n * - Message visibility timeout\r\n * - Queue monitoring (depth, age, throughput)\r\n * - Multiple queue support (task, result, coordination)\r\n * - Performance: <100ms per operation\r\n *\r\n * Usage:\r\n * const queueManager = new RedisQueueManager(redisClient);\r\n *\r\n * // Producer\r\n * await queueManager.enqueue('task-queue', {\r\n * taskId: 'task-001',\r\n * agentType: 'backend-developer',\r\n * payload: { ... }\r\n * });\r\n *\r\n * // Consumer\r\n * const message = await queueManager.dequeue('task-queue', { timeout: 30000 });\r\n * try {\r\n * await processTask(message.payload);\r\n * await queueManager.acknowledge(message.id);\r\n * } catch (error) {\r\n * await queueManager.reject(message.id, { retry: true });\r\n * }\r\n */\r\n\r\nimport { RedisClientType } from 'redis';\r\nimport { v4 as uuidv4 } from 'uuid';\r\nimport { createLogger } from './logging.js';\r\nimport { createError, ErrorCode, isRetryableError } from './errors.js';\r\nimport { withRetry } from './retry.js';\r\nimport { MessageDeduplicator } from './message-deduplicator.js';\r\n\r\nconst logger = createLogger('redis-queue-manager');\r\n\r\n/**\r\n * Queue message\r\n */\r\nexport interface QueueMessage<T = any> {\r\n /** Unique message ID */\r\n id: string;\r\n /** Queue name */\r\n queue: string;\r\n /** Message payload */\r\n payload: T;\r\n /** Message creation timestamp */\r\n createdAt: Date;\r\n /** Message enqueue timestamp */\r\n enqueuedAt: Date;\r\n /** Message dequeue timestamp (if dequeued) */\r\n dequeuedAt?: Date;\r\n /** Number of delivery attempts */\r\n deliveryAttempts: number;\r\n /** Message visibility timeout (milliseconds) */\r\n visibilityTimeout?: number;\r\n /** Message metadata */\r\n metadata?: Record<string, any>;\r\n}\r\n\r\n/**\r\n * Enqueue options\r\n */\r\nexport interface EnqueueOptions {\r\n /** Enable deduplication (default: true) */\r\n deduplicate?: boolean;\r\n /** Message metadata */\r\n metadata?: Record<string, any>;\r\n /** Message visibility timeout in milliseconds (default: 30000) */\r\n visibilityTimeout?: number;\r\n}\r\n\r\n/**\r\n * Dequeue options\r\n */\r\nexport interface DequeueOptions {\r\n /** Maximum wait time in milliseconds (default: 0 - no wait) */\r\n timeout?: number;\r\n /** Message visibility timeout in milliseconds (default: 30000) */\r\n visibilityTimeout?: number;\r\n /** Number of messages to dequeue (default: 1) */\r\n count?: number;\r\n}\r\n\r\n/**\r\n * Reject options\r\n */\r\nexport interface RejectOptions {\r\n /** Retry message (re-enqueue) (default: false) */\r\n retry?: boolean;\r\n /** Error message */\r\n error?: string;\r\n /** Metadata to attach */\r\n metadata?: Record<string, any>;\r\n}\r\n\r\n/**\r\n * Queue statistics\r\n */\r\nexport interface QueueStats {\r\n /** Queue name */\r\n queue: string;\r\n /** Number of messages in queue */\r\n depth: number;\r\n /** Number of messages in processing (invisible) */\r\n inFlight: number;\r\n /** Age of oldest message in seconds */\r\n oldestMessageAge: number;\r\n /** Total messages enqueued */\r\n totalEnqueued: number;\r\n /** Total messages dequeued */\r\n totalDequeued: number;\r\n /** Total messages acknowledged */\r\n totalAcknowledged: number;\r\n /** Total messages rejected */\r\n totalRejected: number;\r\n /** Throughput (messages per second) */\r\n throughput: number;\r\n}\r\n\r\n/**\r\n * Default queue options\r\n */\r\nconst DEFAULT_ENQUEUE_OPTIONS: Required<EnqueueOptions> = {\r\n deduplicate: true,\r\n metadata: {},\r\n visibilityTimeout: 30000, // 30 seconds\r\n};\r\n\r\nconst DEFAULT_DEQUEUE_OPTIONS: Required<DequeueOptions> = {\r\n timeout: 0,\r\n visibilityTimeout: 30000, // 30 seconds\r\n count: 1,\r\n};\r\n\r\n/**\r\n * Redis Queue Manager\r\n *\r\n * Provides reliable queue operations with at-least-once delivery guarantees.\r\n */\r\nexport class RedisQueueManager {\r\n private redis: RedisClientType;\r\n private deduplicator: MessageDeduplicator;\r\n private stats: Map<string, {\r\n enqueued: number;\r\n dequeued: number;\r\n acknowledged: number;\r\n rejected: number;\r\n startTime: Date;\r\n }> = new Map();\r\n\r\n /**\r\n * Create a new RedisQueueManager instance\r\n *\r\n * @param redis - Redis client instance\r\n * @param deduplicator - Optional custom deduplicator instance\r\n */\r\n constructor(redis: RedisClientType, deduplicator?: MessageDeduplicator) {\r\n this.redis = redis;\r\n this.deduplicator = deduplicator || new MessageDeduplicator(redis);\r\n\r\n logger.info('RedisQueueManager initialized');\r\n }\r\n\r\n /**\r\n * Enqueue a message to a queue\r\n *\r\n * @param queue - Queue name\r\n * @param payload - Message payload\r\n * @param options - Enqueue options\r\n * @returns Message ID\r\n */\r\n public async enqueue<T = any>(\r\n queue: string,\r\n payload: T,\r\n options: EnqueueOptions = {}\r\n ): Promise<string> {\r\n const opts = { ...DEFAULT_ENQUEUE_OPTIONS, ...options };\r\n const startTime = Date.now();\r\n\r\n try {\r\n // Check for duplicates if enabled\r\n if (opts.deduplicate) {\r\n const isDuplicate = await this.deduplicator.isDuplicate(payload);\r\n\r\n if (isDuplicate) {\r\n logger.warn('Duplicate message detected, skipping enqueue', {\r\n queue,\r\n payloadHash: this.deduplicator.createFingerprint(payload).substring(0, 16) + '...',\r\n });\r\n\r\n throw createError(\r\n ErrorCode.DB_DUPLICATE_KEY,\r\n 'Duplicate message detected',\r\n { queue }\r\n );\r\n }\r\n }\r\n\r\n // Create message\r\n const message: QueueMessage<T> = {\r\n id: uuidv4(),\r\n queue,\r\n payload,\r\n createdAt: new Date(),\r\n enqueuedAt: new Date(),\r\n deliveryAttempts: 0,\r\n visibilityTimeout: opts.visibilityTimeout,\r\n metadata: opts.metadata,\r\n };\r\n\r\n // Push to queue (RPUSH for FIFO)\r\n await withRetry(\r\n async () => {\r\n const queueKey = this.getQueueKey(queue);\r\n await this.redis.rPush(queueKey, JSON.stringify(message));\r\n },\r\n { maxAttempts: 3, shouldRetry: isRetryableError }\r\n );\r\n\r\n // Mark as processed in deduplicator if enabled\r\n if (opts.deduplicate) {\r\n await this.deduplicator.markProcessed(payload, {\r\n messageId: message.id,\r\n queue,\r\n });\r\n }\r\n\r\n // Update stats\r\n this.updateStats(queue, 'enqueued');\r\n\r\n const duration = Date.now() - startTime;\r\n\r\n logger.debug('Message enqueued', {\r\n queue,\r\n messageId: message.id,\r\n durationMs: duration,\r\n });\r\n\r\n // Validate performance requirement (<100ms)\r\n if (duration > 100) {\r\n logger.warn('Enqueue operation exceeded 100ms target', {\r\n queue,\r\n durationMs: duration,\r\n });\r\n }\r\n\r\n return message.id;\r\n } catch (error) {\r\n logger.error('Failed to enqueue message', error instanceof Error ? error : new Error(String(error)), {\r\n queue,\r\n });\r\n\r\n throw createError(\r\n ErrorCode.DB_QUERY_FAILED,\r\n 'Failed to enqueue message',\r\n { queue },\r\n error instanceof Error ? error : undefined\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Dequeue a message from a queue\r\n *\r\n * @param queue - Queue name\r\n * @param options - Dequeue options\r\n * @returns Message or null if queue is empty\r\n */\r\n public async dequeue<T = any>(\r\n queue: string,\r\n options: DequeueOptions = {}\r\n ): Promise<QueueMessage<T> | null> {\r\n const opts = { ...DEFAULT_DEQUEUE_OPTIONS, ...options };\r\n const startTime = Date.now();\r\n\r\n try {\r\n const queueKey = this.getQueueKey(queue);\r\n const processingKey = this.getProcessingKey(queue);\r\n\r\n let messageData: string | null = null;\r\n\r\n // Use blocking pop if timeout specified\r\n if (opts.timeout > 0) {\r\n const result = await withRetry(\r\n async () => {\r\n // BLMOVE atomically moves from queue to processing set with timeout\r\n return await this.redis.blMove(\r\n queueKey,\r\n processingKey,\r\n 'LEFT',\r\n 'RIGHT',\r\n opts.timeout / 1000 // Convert to seconds\r\n );\r\n },\r\n { maxAttempts: 1 } // Don't retry blocking operations\r\n );\r\n\r\n messageData = result;\r\n } else {\r\n // Non-blocking pop\r\n messageData = await withRetry(\r\n async () => {\r\n return await this.redis.lMove(\r\n queueKey,\r\n processingKey,\r\n 'LEFT',\r\n 'RIGHT'\r\n );\r\n },\r\n { maxAttempts: 3, shouldRetry: isRetryableError }\r\n );\r\n }\r\n\r\n if (!messageData) {\r\n return null;\r\n }\r\n\r\n // Parse message\r\n const message = JSON.parse(messageData) as QueueMessage<T>;\r\n\r\n // Convert date strings back to Date objects\r\n message.createdAt = new Date(message.createdAt);\r\n message.enqueuedAt = new Date(message.enqueuedAt);\r\n message.dequeuedAt = new Date();\r\n message.deliveryAttempts++;\r\n\r\n // Store message with visibility timeout\r\n await this.storeInFlight(message, opts.visibilityTimeout);\r\n\r\n // Update stats\r\n this.updateStats(queue, 'dequeued');\r\n\r\n const duration = Date.now() - startTime;\r\n\r\n logger.debug('Message dequeued', {\r\n queue,\r\n messageId: message.id,\r\n deliveryAttempts: message.deliveryAttempts,\r\n durationMs: duration,\r\n });\r\n\r\n // Validate performance requirement (<100ms)\r\n if (duration > 100) {\r\n logger.warn('Dequeue operation exceeded 100ms target', {\r\n queue,\r\n durationMs: duration,\r\n });\r\n }\r\n\r\n return message;\r\n } catch (error) {\r\n logger.error('Failed to dequeue message', error instanceof Error ? error : new Error(String(error)), {\r\n queue,\r\n });\r\n\r\n throw createError(\r\n ErrorCode.DB_QUERY_FAILED,\r\n 'Failed to dequeue message',\r\n { queue },\r\n error instanceof Error ? error : undefined\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Acknowledge successful message processing\r\n *\r\n * @param messageId - Message ID to acknowledge\r\n */\r\n public async acknowledge(messageId: string): Promise<void> {\r\n const startTime = Date.now();\r\n\r\n try {\r\n // Remove from in-flight storage\r\n const message = await this.getInFlight(messageId);\r\n\r\n if (!message) {\r\n logger.warn('Message not found for acknowledgment', { messageId });\r\n return;\r\n }\r\n\r\n // Remove from processing set\r\n const processingKey = this.getProcessingKey(message.queue);\r\n await withRetry(\r\n async () => {\r\n await this.redis.lRem(processingKey, 1, JSON.stringify(message));\r\n },\r\n { maxAttempts: 3, shouldRetry: isRetryableError }\r\n );\r\n\r\n // Remove from in-flight storage\r\n await this.removeInFlight(messageId);\r\n\r\n // Update stats\r\n this.updateStats(message.queue, 'acknowledged');\r\n\r\n const duration = Date.now() - startTime;\r\n\r\n logger.debug('Message acknowledged', {\r\n queue: message.queue,\r\n messageId,\r\n durationMs: duration,\r\n });\r\n } catch (error) {\r\n logger.error('Failed to acknowledge message', error instanceof Error ? error : new Error(String(error)), {\r\n messageId,\r\n });\r\n\r\n throw createError(\r\n ErrorCode.DB_QUERY_FAILED,\r\n 'Failed to acknowledge message',\r\n { messageId },\r\n error instanceof Error ? error : undefined\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Reject message processing (with optional retry)\r\n *\r\n * @param messageId - Message ID to reject\r\n * @param options - Reject options\r\n */\r\n public async reject(messageId: string, options: RejectOptions = {}): Promise<void> {\r\n const startTime = Date.now();\r\n\r\n try {\r\n // Get message from in-flight storage\r\n const message = await this.getInFlight(messageId);\r\n\r\n if (!message) {\r\n logger.warn('Message not found for rejection', { messageId });\r\n return;\r\n }\r\n\r\n // Remove from processing set\r\n const processingKey = this.getProcessingKey(message.queue);\r\n await withRetry(\r\n async () => {\r\n await this.redis.lRem(processingKey, 1, JSON.stringify(message));\r\n },\r\n { maxAttempts: 3, shouldRetry: isRetryableError }\r\n );\r\n\r\n // Remove from in-flight storage\r\n await this.removeInFlight(messageId);\r\n\r\n if (options.retry) {\r\n // Re-enqueue message\r\n message.metadata = {\r\n ...message.metadata,\r\n ...options.metadata,\r\n rejectedAt: new Date().toISOString(),\r\n rejectionReason: options.error,\r\n };\r\n\r\n const queueKey = this.getQueueKey(message.queue);\r\n await withRetry(\r\n async () => {\r\n await this.redis.rPush(queueKey, JSON.stringify(message));\r\n },\r\n { maxAttempts: 3, shouldRetry: isRetryableError }\r\n );\r\n\r\n logger.debug('Message rejected and re-enqueued', {\r\n queue: message.queue,\r\n messageId,\r\n deliveryAttempts: message.deliveryAttempts,\r\n });\r\n } else {\r\n logger.debug('Message rejected without retry', {\r\n queue: message.queue,\r\n messageId,\r\n });\r\n }\r\n\r\n // Update stats\r\n this.updateStats(message.queue, 'rejected');\r\n\r\n const duration = Date.now() - startTime;\r\n\r\n logger.debug('Message rejected', {\r\n queue: message.queue,\r\n messageId,\r\n retry: options.retry,\r\n durationMs: duration,\r\n });\r\n } catch (error) {\r\n logger.error('Failed to reject message', error instanceof Error ? error : new Error(String(error)), {\r\n messageId,\r\n });\r\n\r\n throw createError(\r\n ErrorCode.DB_QUERY_FAILED,\r\n 'Failed to reject message',\r\n { messageId },\r\n error instanceof Error ? error : undefined\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Get queue statistics\r\n *\r\n * @param queue - Queue name\r\n * @returns Queue statistics\r\n */\r\n public async getStats(queue: string): Promise<QueueStats> {\r\n try {\r\n const queueKey = this.getQueueKey(queue);\r\n const processingKey = this.getProcessingKey(queue);\r\n\r\n // Get queue depth\r\n const depth = await this.redis.lLen(queueKey);\r\n\r\n // Get in-flight count\r\n const inFlight = await this.redis.lLen(processingKey);\r\n\r\n // Get oldest message age\r\n let oldestMessageAge = 0;\r\n const oldestMessage = await this.redis.lIndex(queueKey, 0);\r\n\r\n if (oldestMessage) {\r\n const message = JSON.parse(oldestMessage) as QueueMessage;\r\n const age = Date.now() - new Date(message.enqueuedAt).getTime();\r\n oldestMessageAge = Math.floor(age / 1000); // Convert to seconds\r\n }\r\n\r\n // Get stats from tracking\r\n const stats = this.stats.get(queue) || {\r\n enqueued: 0,\r\n dequeued: 0,\r\n acknowledged: 0,\r\n rejected: 0,\r\n startTime: new Date(),\r\n };\r\n\r\n // Calculate throughput (messages per second)\r\n const elapsed = (Date.now() - stats.startTime.getTime()) / 1000;\r\n const throughput = elapsed > 0 ? stats.dequeued / elapsed : 0;\r\n\r\n return {\r\n queue,\r\n depth,\r\n inFlight,\r\n oldestMessageAge,\r\n totalEnqueued: stats.enqueued,\r\n totalDequeued: stats.dequeued,\r\n totalAcknowledged: stats.acknowledged,\r\n totalRejected: stats.rejected,\r\n throughput,\r\n };\r\n } catch (error) {\r\n logger.error('Failed to get queue stats', error instanceof Error ? error : new Error(String(error)), {\r\n queue,\r\n });\r\n\r\n throw createError(\r\n ErrorCode.DB_QUERY_FAILED,\r\n 'Failed to get queue stats',\r\n { queue },\r\n error instanceof Error ? error : undefined\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Purge all messages from a queue\r\n *\r\n * @param queue - Queue name\r\n * @returns Number of messages purged\r\n */\r\n public async purge(queue: string): Promise<number> {\r\n try {\r\n const queueKey = this.getQueueKey(queue);\r\n\r\n const count = await withRetry(\r\n async () => {\r\n const len = await this.redis.lLen(queueKey);\r\n await this.redis.del(queueKey);\r\n return len;\r\n },\r\n { maxAttempts: 3, shouldRetry: isRetryableError }\r\n );\r\n\r\n logger.info('Queue purged', {\r\n queue,\r\n messagesPurged: count,\r\n });\r\n\r\n return count;\r\n } catch (error) {\r\n logger.error('Failed to purge queue', error instanceof Error ? error : new Error(String(error)), {\r\n queue,\r\n });\r\n\r\n throw createError(\r\n ErrorCode.DB_QUERY_FAILED,\r\n 'Failed to purge queue',\r\n { queue },\r\n error instanceof Error ? error : undefined\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Get all queue names\r\n *\r\n * @returns Array of queue names\r\n */\r\n public async getQueues(): Promise<string[]> {\r\n try {\r\n const pattern = 'queue:*';\r\n const keys = await this.redis.keys(pattern);\r\n\r\n const queues = keys\r\n .filter(key => !key.includes(':processing'))\r\n .map(key => key.replace('queue:', ''));\r\n\r\n return queues;\r\n } catch (error) {\r\n logger.error('Failed to get queues', error instanceof Error ? error : new Error(String(error)));\r\n\r\n throw createError(\r\n ErrorCode.DB_QUERY_FAILED,\r\n 'Failed to get queues',\r\n {},\r\n error instanceof Error ? error : undefined\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Shutdown queue manager (cleanup resources)\r\n */\r\n public shutdown(): void {\r\n this.deduplicator.shutdown();\r\n logger.info('RedisQueueManager shutdown');\r\n }\r\n\r\n /**\r\n * Get Redis key for queue\r\n */\r\n private getQueueKey(queue: string): string {\r\n return `queue:${queue}`;\r\n }\r\n\r\n /**\r\n * Get Redis key for processing set\r\n */\r\n private getProcessingKey(queue: string): string {\r\n return `queue:${queue}:processing`;\r\n }\r\n\r\n /**\r\n * Get Redis key for in-flight message storage\r\n */\r\n private getInFlightKey(messageId: string): string {\r\n return `inflight:${messageId}`;\r\n }\r\n\r\n /**\r\n * Store message in in-flight storage with TTL\r\n */\r\n private async storeInFlight<T = any>(\r\n message: QueueMessage<T>,\r\n visibilityTimeout: number\r\n ): Promise<void> {\r\n const key = this.getInFlightKey(message.id);\r\n\r\n await withRetry(\r\n async () => {\r\n await this.redis.set(\r\n key,\r\n JSON.stringify(message),\r\n { PX: visibilityTimeout }\r\n );\r\n },\r\n { maxAttempts: 3, shouldRetry: isRetryableError }\r\n );\r\n }\r\n\r\n /**\r\n * Get message from in-flight storage\r\n */\r\n private async getInFlight<T = any>(messageId: string): Promise<QueueMessage<T> | null> {\r\n const key = this.getInFlightKey(messageId);\r\n\r\n const data = await withRetry(\r\n async () => await this.redis.get(key),\r\n { maxAttempts: 3, shouldRetry: isRetryableError }\r\n );\r\n\r\n if (!data) {\r\n return null;\r\n }\r\n\r\n const message = JSON.parse(data) as QueueMessage<T>;\r\n\r\n // Convert date strings back to Date objects\r\n message.createdAt = new Date(message.createdAt);\r\n message.enqueuedAt = new Date(message.enqueuedAt);\r\n if (message.dequeuedAt) {\r\n message.dequeuedAt = new Date(message.dequeuedAt);\r\n }\r\n\r\n return message;\r\n }\r\n\r\n /**\r\n * Remove message from in-flight storage\r\n */\r\n private async removeInFlight(messageId: string): Promise<void> {\r\n const key = this.getInFlightKey(messageId);\r\n\r\n await withRetry(\r\n async () => await this.redis.del(key),\r\n { maxAttempts: 3, shouldRetry: isRetryableError }\r\n );\r\n }\r\n\r\n /**\r\n * Update queue statistics\r\n */\r\n private updateStats(queue: string, operation: 'enqueued' | 'dequeued' | 'acknowledged' | 'rejected'): void {\r\n let stats = this.stats.get(queue);\r\n\r\n if (!stats) {\r\n stats = {\r\n enqueued: 0,\r\n dequeued: 0,\r\n acknowledged: 0,\r\n rejected: 0,\r\n startTime: new Date(),\r\n };\r\n this.stats.set(queue, stats);\r\n }\r\n\r\n stats[operation]++;\r\n }\r\n}\r\n"],"names":["v4","uuidv4","createLogger","createError","ErrorCode","isRetryableError","withRetry","MessageDeduplicator","logger","DEFAULT_ENQUEUE_OPTIONS","deduplicate","metadata","visibilityTimeout","DEFAULT_DEQUEUE_OPTIONS","timeout","count","RedisQueueManager","redis","deduplicator","stats","Map","info","enqueue","queue","payload","options","opts","startTime","Date","now","isDuplicate","warn","payloadHash","createFingerprint","substring","DB_DUPLICATE_KEY","message","id","createdAt","enqueuedAt","deliveryAttempts","queueKey","getQueueKey","rPush","JSON","stringify","maxAttempts","shouldRetry","markProcessed","messageId","updateStats","duration","debug","durationMs","error","Error","String","DB_QUERY_FAILED","undefined","dequeue","processingKey","getProcessingKey","messageData","result","blMove","lMove","parse","dequeuedAt","storeInFlight","acknowledge","getInFlight","lRem","removeInFlight","reject","retry","rejectedAt","toISOString","rejectionReason","getStats","depth","lLen","inFlight","oldestMessageAge","oldestMessage","lIndex","age","getTime","Math","floor","get","enqueued","dequeued","acknowledged","rejected","elapsed","throughput","totalEnqueued","totalDequeued","totalAcknowledged","totalRejected","purge","len","del","messagesPurged","getQueues","pattern","keys","queues","filter","key","includes","map","replace","shutdown","getInFlightKey","set","PX","data","operation"],"mappings":"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"}
@@ -0,0 +1,272 @@
1
+ /**
2
+ * Reflection Archiver
3
+ * Task 5.3: ACE Reflection Persistence Standardization
4
+ *
5
+ * Manages automatic archival of Redis reflections to PostgreSQL
6
+ * based on TTL thresholds. Runs as background task.
7
+ *
8
+ * Performance target: <500ms per reflection archive
9
+ */ import { StandardError, ErrorCode } from './errors.js';
10
+ import { logger } from './logging.js';
11
+ const DEFAULT_CONFIG = {
12
+ ttl_threshold_seconds: 3600,
13
+ scan_interval_ms: 300000,
14
+ max_per_scan: 100,
15
+ auto_archive: true
16
+ };
17
+ export class ReflectionArchiver {
18
+ dbService;
19
+ config;
20
+ scanInterval = null;
21
+ metrics = {
22
+ total_archived: 0,
23
+ last_scan_time: null,
24
+ last_scan_count: 0,
25
+ failed_archives: 0,
26
+ average_archive_time_ms: 0,
27
+ redis_unavailable_count: 0
28
+ };
29
+ archiveTimes = [];
30
+ isScanning = false;
31
+ constructor(dbService, config){
32
+ this.dbService = dbService;
33
+ this.config = {
34
+ ...DEFAULT_CONFIG,
35
+ ...config
36
+ };
37
+ }
38
+ /**
39
+ * Start automatic archival process
40
+ */ start() {
41
+ if (this.scanInterval) {
42
+ logger.warn('Archiver already running');
43
+ return;
44
+ }
45
+ if (!this.config.auto_archive) {
46
+ logger.info('Auto-archive disabled in config');
47
+ return;
48
+ }
49
+ logger.info('Starting reflection archiver', {
50
+ scan_interval_ms: this.config.scan_interval_ms,
51
+ ttl_threshold_seconds: this.config.ttl_threshold_seconds,
52
+ max_per_scan: this.config.max_per_scan
53
+ });
54
+ this.scanInterval = setInterval(()=>this.runArchiveScan(), this.config.scan_interval_ms);
55
+ // Run initial scan immediately
56
+ this.runArchiveScan();
57
+ }
58
+ /**
59
+ * Stop automatic archival process
60
+ */ stop() {
61
+ if (this.scanInterval) {
62
+ clearInterval(this.scanInterval);
63
+ this.scanInterval = null;
64
+ logger.info('Reflection archiver stopped');
65
+ }
66
+ }
67
+ /**
68
+ * Manually trigger an archive scan
69
+ */ async manualScan() {
70
+ return await this.runArchiveScan();
71
+ }
72
+ /**
73
+ * Get current archiver metrics
74
+ */ getMetrics() {
75
+ return {
76
+ ...this.metrics
77
+ };
78
+ }
79
+ /**
80
+ * Reset metrics (useful for testing)
81
+ */ resetMetrics() {
82
+ this.metrics = {
83
+ total_archived: 0,
84
+ last_scan_time: null,
85
+ last_scan_count: 0,
86
+ failed_archives: 0,
87
+ average_archive_time_ms: 0,
88
+ redis_unavailable_count: 0
89
+ };
90
+ this.archiveTimes = [];
91
+ }
92
+ // ========== Private Methods ==========
93
+ async runArchiveScan() {
94
+ if (this.isScanning) {
95
+ logger.debug('Archive scan already in progress, skipping');
96
+ return 0;
97
+ }
98
+ this.isScanning = true;
99
+ const scanStartTime = Date.now();
100
+ try {
101
+ const archivedCount = await this.scanAndArchive();
102
+ this.metrics.last_scan_time = new Date();
103
+ this.metrics.last_scan_count = archivedCount;
104
+ this.metrics.total_archived += archivedCount;
105
+ const scanDuration = Date.now() - scanStartTime;
106
+ logger.info('Archive scan complete', {
107
+ archived_count: archivedCount,
108
+ scan_duration_ms: scanDuration,
109
+ total_archived: this.metrics.total_archived
110
+ });
111
+ return archivedCount;
112
+ } catch (error) {
113
+ logger.error('Archive scan failed', {
114
+ error: error instanceof Error ? error.message : String(error)
115
+ });
116
+ return 0;
117
+ } finally{
118
+ this.isScanning = false;
119
+ }
120
+ }
121
+ async scanAndArchive() {
122
+ let redisAdapter;
123
+ try {
124
+ redisAdapter = this.dbService.getAdapter('redis');
125
+ } catch (error) {
126
+ this.metrics.redis_unavailable_count++;
127
+ logger.warn('Redis adapter unavailable, skipping archive scan', {
128
+ redis_unavailable_count: this.metrics.redis_unavailable_count
129
+ });
130
+ return 0;
131
+ }
132
+ let archivedCount = 0;
133
+ try {
134
+ // Get all reflection keys
135
+ const keys = await redisAdapter.keys('reflection:*');
136
+ logger.debug('Scanning reflection keys', {
137
+ key_count: keys.length
138
+ });
139
+ // Process up to max_per_scan keys
140
+ const keysToProcess = keys.slice(0, this.config.max_per_scan);
141
+ for (const key of keysToProcess){
142
+ try {
143
+ const archived = await this.archiveIfExpiring(key);
144
+ if (archived) {
145
+ archivedCount++;
146
+ }
147
+ } catch (error) {
148
+ this.metrics.failed_archives++;
149
+ logger.error('Failed to archive reflection', {
150
+ key,
151
+ error: error instanceof Error ? error.message : String(error),
152
+ failed_archives: this.metrics.failed_archives
153
+ });
154
+ }
155
+ }
156
+ // Update average archive time
157
+ if (this.archiveTimes.length > 0) {
158
+ const sum = this.archiveTimes.reduce((a, b)=>a + b, 0);
159
+ this.metrics.average_archive_time_ms = sum / this.archiveTimes.length;
160
+ }
161
+ // Keep only last 100 archive times for moving average
162
+ if (this.archiveTimes.length > 100) {
163
+ this.archiveTimes = this.archiveTimes.slice(-100);
164
+ }
165
+ return archivedCount;
166
+ } catch (error) {
167
+ logger.error('Scan failed', {
168
+ error: error instanceof Error ? error.message : String(error)
169
+ });
170
+ return archivedCount;
171
+ }
172
+ }
173
+ async archiveIfExpiring(key) {
174
+ const startTime = Date.now();
175
+ try {
176
+ const redisAdapter = this.dbService.getAdapter('redis');
177
+ // Check TTL
178
+ const ttl = await redisAdapter.ttl(key);
179
+ // Skip if key doesn't exist or has no expiration
180
+ if (ttl < 0) {
181
+ return false;
182
+ }
183
+ // Archive if TTL is below threshold
184
+ if (ttl < this.config.ttl_threshold_seconds) {
185
+ const data = await redisAdapter.get(key);
186
+ if (!data) {
187
+ logger.warn('Key exists but has no data', {
188
+ key,
189
+ ttl
190
+ });
191
+ return false;
192
+ }
193
+ let reflection;
194
+ try {
195
+ reflection = JSON.parse(data);
196
+ } catch (error) {
197
+ logger.error('Failed to parse reflection data', {
198
+ key,
199
+ error: error instanceof Error ? error.message : String(error)
200
+ });
201
+ return false;
202
+ }
203
+ // Write to PostgreSQL (idempotent)
204
+ await this.writeToPostgreSQL(reflection);
205
+ const archiveTime = Date.now() - startTime;
206
+ this.archiveTimes.push(archiveTime);
207
+ logger.debug('Reflection archived', {
208
+ key,
209
+ ttl,
210
+ archive_time_ms: archiveTime,
211
+ agent_id: reflection.agent_id,
212
+ task_id: reflection.task_id
213
+ });
214
+ // Warn if archive took too long
215
+ if (archiveTime >= 500) {
216
+ logger.warn('Archive exceeded performance target', {
217
+ key,
218
+ archive_time_ms: archiveTime,
219
+ target_ms: 500
220
+ });
221
+ }
222
+ return true;
223
+ }
224
+ return false;
225
+ } catch (error) {
226
+ throw new StandardError(ErrorCode.DATABASE_ERROR, 'Failed to archive reflection', {
227
+ key,
228
+ error: error instanceof Error ? error.message : String(error)
229
+ });
230
+ }
231
+ }
232
+ async writeToPostgreSQL(reflection) {
233
+ const pgAdapter = this.dbService.getAdapter('postgres');
234
+ const query = `
235
+ INSERT INTO reflections (
236
+ agent_id,
237
+ task_id,
238
+ reflection_type,
239
+ confidence,
240
+ payload,
241
+ timestamp,
242
+ archived_at
243
+ ) VALUES ($1, $2, $3, $4, $5, $6, NOW())
244
+ ON CONFLICT (agent_id, task_id, timestamp)
245
+ DO UPDATE SET
246
+ reflection_type = EXCLUDED.reflection_type,
247
+ confidence = EXCLUDED.confidence,
248
+ payload = EXCLUDED.payload,
249
+ archived_at = NOW()
250
+ `;
251
+ const params = [
252
+ reflection.agent_id,
253
+ reflection.task_id,
254
+ reflection.reflection_type,
255
+ reflection.confidence,
256
+ typeof reflection.payload === 'string' ? reflection.payload : JSON.stringify(reflection.payload),
257
+ reflection.timestamp || new Date()
258
+ ];
259
+ await pgAdapter.execute(query, params);
260
+ }
261
+ }
262
+ /**
263
+ * Factory function to create and start an archiver
264
+ */ export function createArchiver(dbService, config) {
265
+ const archiver = new ReflectionArchiver(dbService, config);
266
+ if (config?.auto_archive !== false) {
267
+ archiver.start();
268
+ }
269
+ return archiver;
270
+ }
271
+
272
+ //# sourceMappingURL=reflection-archiver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/lib/reflection-archiver.ts"],"sourcesContent":["/**\r\n * Reflection Archiver\r\n * Task 5.3: ACE Reflection Persistence Standardization\r\n *\r\n * Manages automatic archival of Redis reflections to PostgreSQL\r\n * based on TTL thresholds. Runs as background task.\r\n *\r\n * Performance target: <500ms per reflection archive\r\n */\r\n\r\nimport { DatabaseService } from './database-service.js';\r\nimport { StandardError, ErrorCode } from './errors.js';\r\nimport { logger } from './logging.js';\r\n\r\nexport interface ArchiverConfig {\r\n /**\r\n * TTL threshold in seconds - archive when Redis key TTL falls below this\r\n * Default: 3600 (1 hour)\r\n */\r\n ttl_threshold_seconds?: number;\r\n\r\n /**\r\n * Interval between archive scans in milliseconds\r\n * Default: 300000 (5 minutes)\r\n */\r\n scan_interval_ms?: number;\r\n\r\n /**\r\n * Maximum reflections to archive per scan\r\n * Default: 100\r\n */\r\n max_per_scan?: number;\r\n\r\n /**\r\n * Enable automatic archival on interval\r\n * Default: true\r\n */\r\n auto_archive?: boolean;\r\n}\r\n\r\nexport interface ArchiveMetrics {\r\n total_archived: number;\r\n last_scan_time: Date | null;\r\n last_scan_count: number;\r\n failed_archives: number;\r\n average_archive_time_ms: number;\r\n redis_unavailable_count: number;\r\n}\r\n\r\nconst DEFAULT_CONFIG: Required<ArchiverConfig> = {\r\n ttl_threshold_seconds: 3600, // 1 hour\r\n scan_interval_ms: 300000, // 5 minutes\r\n max_per_scan: 100,\r\n auto_archive: true,\r\n};\r\n\r\nexport class ReflectionArchiver {\r\n private dbService: DatabaseService;\r\n private config: Required<ArchiverConfig>;\r\n private scanInterval: NodeJS.Timeout | null = null;\r\n private metrics: ArchiveMetrics = {\r\n total_archived: 0,\r\n last_scan_time: null,\r\n last_scan_count: 0,\r\n failed_archives: 0,\r\n average_archive_time_ms: 0,\r\n redis_unavailable_count: 0,\r\n };\r\n\r\n private archiveTimes: number[] = [];\r\n private isScanning: boolean = false;\r\n\r\n constructor(dbService: DatabaseService, config?: ArchiverConfig) {\r\n this.dbService = dbService;\r\n this.config = { ...DEFAULT_CONFIG, ...config };\r\n }\r\n\r\n /**\r\n * Start automatic archival process\r\n */\r\n start(): void {\r\n if (this.scanInterval) {\r\n logger.warn('Archiver already running');\r\n return;\r\n }\r\n\r\n if (!this.config.auto_archive) {\r\n logger.info('Auto-archive disabled in config');\r\n return;\r\n }\r\n\r\n logger.info('Starting reflection archiver', {\r\n scan_interval_ms: this.config.scan_interval_ms,\r\n ttl_threshold_seconds: this.config.ttl_threshold_seconds,\r\n max_per_scan: this.config.max_per_scan,\r\n });\r\n\r\n this.scanInterval = setInterval(\r\n () => this.runArchiveScan(),\r\n this.config.scan_interval_ms\r\n );\r\n\r\n // Run initial scan immediately\r\n this.runArchiveScan();\r\n }\r\n\r\n /**\r\n * Stop automatic archival process\r\n */\r\n stop(): void {\r\n if (this.scanInterval) {\r\n clearInterval(this.scanInterval);\r\n this.scanInterval = null;\r\n logger.info('Reflection archiver stopped');\r\n }\r\n }\r\n\r\n /**\r\n * Manually trigger an archive scan\r\n */\r\n async manualScan(): Promise<number> {\r\n return await this.runArchiveScan();\r\n }\r\n\r\n /**\r\n * Get current archiver metrics\r\n */\r\n getMetrics(): ArchiveMetrics {\r\n return { ...this.metrics };\r\n }\r\n\r\n /**\r\n * Reset metrics (useful for testing)\r\n */\r\n resetMetrics(): void {\r\n this.metrics = {\r\n total_archived: 0,\r\n last_scan_time: null,\r\n last_scan_count: 0,\r\n failed_archives: 0,\r\n average_archive_time_ms: 0,\r\n redis_unavailable_count: 0,\r\n };\r\n this.archiveTimes = [];\r\n }\r\n\r\n // ========== Private Methods ==========\r\n\r\n private async runArchiveScan(): Promise<number> {\r\n if (this.isScanning) {\r\n logger.debug('Archive scan already in progress, skipping');\r\n return 0;\r\n }\r\n\r\n this.isScanning = true;\r\n const scanStartTime = Date.now();\r\n\r\n try {\r\n const archivedCount = await this.scanAndArchive();\r\n\r\n this.metrics.last_scan_time = new Date();\r\n this.metrics.last_scan_count = archivedCount;\r\n this.metrics.total_archived += archivedCount;\r\n\r\n const scanDuration = Date.now() - scanStartTime;\r\n\r\n logger.info('Archive scan complete', {\r\n archived_count: archivedCount,\r\n scan_duration_ms: scanDuration,\r\n total_archived: this.metrics.total_archived,\r\n });\r\n\r\n return archivedCount;\r\n } catch (error) {\r\n logger.error('Archive scan failed', {\r\n error: error instanceof Error ? error.message : String(error),\r\n });\r\n return 0;\r\n } finally {\r\n this.isScanning = false;\r\n }\r\n }\r\n\r\n private async scanAndArchive(): Promise<number> {\r\n let redisAdapter;\r\n\r\n try {\r\n redisAdapter = this.dbService.getAdapter('redis');\r\n } catch (error) {\r\n this.metrics.redis_unavailable_count++;\r\n logger.warn('Redis adapter unavailable, skipping archive scan', {\r\n redis_unavailable_count: this.metrics.redis_unavailable_count,\r\n });\r\n return 0;\r\n }\r\n\r\n let archivedCount = 0;\r\n\r\n try {\r\n // Get all reflection keys\r\n const keys = await redisAdapter.keys('reflection:*');\r\n\r\n logger.debug('Scanning reflection keys', { key_count: keys.length });\r\n\r\n // Process up to max_per_scan keys\r\n const keysToProcess = keys.slice(0, this.config.max_per_scan);\r\n\r\n for (const key of keysToProcess) {\r\n try {\r\n const archived = await this.archiveIfExpiring(key);\r\n\r\n if (archived) {\r\n archivedCount++;\r\n }\r\n } catch (error) {\r\n this.metrics.failed_archives++;\r\n\r\n logger.error('Failed to archive reflection', {\r\n key,\r\n error: error instanceof Error ? error.message : String(error),\r\n failed_archives: this.metrics.failed_archives,\r\n });\r\n }\r\n }\r\n\r\n // Update average archive time\r\n if (this.archiveTimes.length > 0) {\r\n const sum = this.archiveTimes.reduce((a, b) => a + b, 0);\r\n this.metrics.average_archive_time_ms = sum / this.archiveTimes.length;\r\n }\r\n\r\n // Keep only last 100 archive times for moving average\r\n if (this.archiveTimes.length > 100) {\r\n this.archiveTimes = this.archiveTimes.slice(-100);\r\n }\r\n\r\n return archivedCount;\r\n } catch (error) {\r\n logger.error('Scan failed', {\r\n error: error instanceof Error ? error.message : String(error),\r\n });\r\n return archivedCount;\r\n }\r\n }\r\n\r\n private async archiveIfExpiring(key: string): Promise<boolean> {\r\n const startTime = Date.now();\r\n\r\n try {\r\n const redisAdapter = this.dbService.getAdapter('redis');\r\n\r\n // Check TTL\r\n const ttl = await redisAdapter.ttl(key);\r\n\r\n // Skip if key doesn't exist or has no expiration\r\n if (ttl < 0) {\r\n return false;\r\n }\r\n\r\n // Archive if TTL is below threshold\r\n if (ttl < this.config.ttl_threshold_seconds) {\r\n const data = await redisAdapter.get(key);\r\n\r\n if (!data) {\r\n logger.warn('Key exists but has no data', { key, ttl });\r\n return false;\r\n }\r\n\r\n let reflection;\r\n try {\r\n reflection = JSON.parse(data);\r\n } catch (error) {\r\n logger.error('Failed to parse reflection data', {\r\n key,\r\n error: error instanceof Error ? error.message : String(error),\r\n });\r\n return false;\r\n }\r\n\r\n // Write to PostgreSQL (idempotent)\r\n await this.writeToPostgreSQL(reflection);\r\n\r\n const archiveTime = Date.now() - startTime;\r\n this.archiveTimes.push(archiveTime);\r\n\r\n logger.debug('Reflection archived', {\r\n key,\r\n ttl,\r\n archive_time_ms: archiveTime,\r\n agent_id: reflection.agent_id,\r\n task_id: reflection.task_id,\r\n });\r\n\r\n // Warn if archive took too long\r\n if (archiveTime >= 500) {\r\n logger.warn('Archive exceeded performance target', {\r\n key,\r\n archive_time_ms: archiveTime,\r\n target_ms: 500,\r\n });\r\n }\r\n\r\n return true;\r\n }\r\n\r\n return false;\r\n } catch (error) {\r\n throw new StandardError(\r\n ErrorCode.DATABASE_ERROR,\r\n 'Failed to archive reflection',\r\n {\r\n key,\r\n error: error instanceof Error ? error.message : String(error),\r\n }\r\n );\r\n }\r\n }\r\n\r\n private async writeToPostgreSQL(reflection: any): Promise<void> {\r\n const pgAdapter = this.dbService.getAdapter('postgres');\r\n\r\n const query = `\r\n INSERT INTO reflections (\r\n agent_id,\r\n task_id,\r\n reflection_type,\r\n confidence,\r\n payload,\r\n timestamp,\r\n archived_at\r\n ) VALUES ($1, $2, $3, $4, $5, $6, NOW())\r\n ON CONFLICT (agent_id, task_id, timestamp)\r\n DO UPDATE SET\r\n reflection_type = EXCLUDED.reflection_type,\r\n confidence = EXCLUDED.confidence,\r\n payload = EXCLUDED.payload,\r\n archived_at = NOW()\r\n `;\r\n\r\n const params = [\r\n reflection.agent_id,\r\n reflection.task_id,\r\n reflection.reflection_type,\r\n reflection.confidence,\r\n typeof reflection.payload === 'string'\r\n ? reflection.payload\r\n : JSON.stringify(reflection.payload),\r\n reflection.timestamp || new Date(),\r\n ];\r\n\r\n await pgAdapter.execute(query, params);\r\n }\r\n}\r\n\r\n/**\r\n * Factory function to create and start an archiver\r\n */\r\nexport function createArchiver(\r\n dbService: DatabaseService,\r\n config?: ArchiverConfig\r\n): ReflectionArchiver {\r\n const archiver = new ReflectionArchiver(dbService, config);\r\n\r\n if (config?.auto_archive !== false) {\r\n archiver.start();\r\n }\r\n\r\n return archiver;\r\n}\r\n"],"names":["StandardError","ErrorCode","logger","DEFAULT_CONFIG","ttl_threshold_seconds","scan_interval_ms","max_per_scan","auto_archive","ReflectionArchiver","dbService","config","scanInterval","metrics","total_archived","last_scan_time","last_scan_count","failed_archives","average_archive_time_ms","redis_unavailable_count","archiveTimes","isScanning","start","warn","info","setInterval","runArchiveScan","stop","clearInterval","manualScan","getMetrics","resetMetrics","debug","scanStartTime","Date","now","archivedCount","scanAndArchive","scanDuration","archived_count","scan_duration_ms","error","Error","message","String","redisAdapter","getAdapter","keys","key_count","length","keysToProcess","slice","key","archived","archiveIfExpiring","sum","reduce","a","b","startTime","ttl","data","get","reflection","JSON","parse","writeToPostgreSQL","archiveTime","push","archive_time_ms","agent_id","task_id","target_ms","DATABASE_ERROR","pgAdapter","query","params","reflection_type","confidence","payload","stringify","timestamp","execute","createArchiver","archiver"],"mappings":"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"}