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/lib/query-translator.ts"],"sourcesContent":["/**\r\n * Query Translator - SECURITY HARDENED\r\n *\r\n * Translates between SQL queries and Redis commands for cross-backend compatibility.\r\n * Includes query optimization and backend recommendation logic.\r\n *\r\n * SECURITY ENHANCEMENTS (CVE-2024-SQL-INJECTION):\r\n * - Input validation with whitelisting for identifiers (table/column names)\r\n * - Parameterized queries for ALL database values\r\n * - Comprehensive SQL injection prevention\r\n * - Strict identifier validation against allowed patterns\r\n * - Error handling using StandardError\r\n *\r\n * Part of Phase 2, Task P2-3.1: Unified Query API\r\n *\r\n * Features:\r\n * - SQL to Redis translation with security validation\r\n * - Redis to SQL translation with parameterization\r\n * - Query optimization\r\n * - Backend recommendation based on query patterns\r\n * - Performance monitoring (<50ms translation time)\r\n *\r\n * @example\r\n * ```typescript\r\n * const translator = new QueryTranslator({\r\n * allowedTables: ['tasks', 'users', 'projects'],\r\n * allowedFields: { tasks: ['id', 'name', 'status', 'description'] }\r\n * });\r\n *\r\n * // Translate SQL to Redis (fully parameterized)\r\n * const redisCmd = translator.translateSQLToRedis(\r\n * 'SELECT * FROM tasks WHERE id = ?',\r\n * ['task-123']\r\n * );\r\n *\r\n * // Translate Redis to SQL (fully parameterized)\r\n * const sqlQuery = translator.translateRedisToSQL({\r\n * command: 'HGETALL',\r\n * key: 'task:123'\r\n * });\r\n * ```\r\n */\r\n\r\nimport { BackendType, QueryRequest } from './unified-query-api.js';\r\nimport { StandardError, ErrorCode } from './errors.js';\r\n\r\n/**\r\n * Redis command structure\r\n */\r\nexport interface RedisCommand {\r\n command: string;\r\n key?: string;\r\n fields?: Record<string, any>;\r\n args?: any[];\r\n}\r\n\r\n/**\r\n * Translation result\r\n */\r\nexport interface TranslationResult {\r\n success: boolean;\r\n redisCommand?: RedisCommand;\r\n sqlQuery?: string;\r\n sqlParams?: any[];\r\n executionTime: number;\r\n recommendedBackend?: BackendType;\r\n warnings?: string[];\r\n}\r\n\r\n/**\r\n * Query optimization result\r\n */\r\nexport interface OptimizationResult {\r\n indexed?: string[];\r\n executionPlan?: string;\r\n estimatedCost?: number;\r\n recommendations?: string[];\r\n}\r\n\r\n/**\r\n * Configuration for QueryTranslator\r\n */\r\nexport interface QueryTranslatorConfig {\r\n // Whitelist of allowed table names\r\n allowedTables?: string[];\r\n\r\n // Whitelist of allowed fields per table\r\n allowedFields?: Record<string, string[]>;\r\n\r\n // Maximum allowed query length\r\n maxQueryLength?: number;\r\n\r\n // Maximum allowed parameters\r\n maxParams?: number;\r\n\r\n // Enable strict mode (block all unvalidated identifiers)\r\n strictMode?: boolean;\r\n}\r\n\r\n/**\r\n * Identifier validation result\r\n */\r\ninterface IdentifierValidationResult {\r\n valid: boolean;\r\n sanitized?: string;\r\n error?: string;\r\n}\r\n\r\n/**\r\n * SQL query parser - SECURITY HARDENED\r\n */\r\nclass SQLParser {\r\n private allowedTables: Set<string>;\r\n private allowedFields: Map<string, Set<string>>;\r\n private strictMode: boolean;\r\n\r\n constructor(\r\n allowedTables?: string[],\r\n allowedFields?: Record<string, string[]>,\r\n strictMode: boolean = true\r\n ) {\r\n this.allowedTables = new Set(allowedTables || []);\r\n this.allowedFields = new Map();\r\n\r\n if (allowedFields) {\r\n for (const [table, fields] of Object.entries(allowedFields)) {\r\n this.allowedFields.set(table.toLowerCase(), new Set(fields.map(f => f.toLowerCase())));\r\n }\r\n }\r\n\r\n this.strictMode = strictMode;\r\n }\r\n\r\n /**\r\n * Validate SQL identifier (table/column name)\r\n * Pattern: alphanumeric, underscore, starts with letter or underscore\r\n */\r\n private validateIdentifier(identifier: string, type: 'table' | 'field'): IdentifierValidationResult {\r\n if (!identifier || typeof identifier !== 'string') {\r\n return {\r\n valid: false,\r\n error: `Invalid ${type} name: must be a non-empty string`\r\n };\r\n }\r\n\r\n // Remove surrounding whitespace\r\n const trimmed = identifier.trim();\r\n\r\n // Check pattern: must start with letter or underscore, contain only alphanumeric and underscore\r\n const identifierPattern = /^[a-zA-Z_][a-zA-Z0-9_]*$/;\r\n if (!identifierPattern.test(trimmed)) {\r\n return {\r\n valid: false,\r\n error: `Invalid ${type} name: must match pattern /^[a-zA-Z_][a-zA-Z0-9_]*$/. Got: \"${identifier}\"`\r\n };\r\n }\r\n\r\n // Check length (reasonable limit to prevent DoS)\r\n if (trimmed.length > 128) {\r\n return {\r\n valid: false,\r\n error: `Invalid ${type} name: exceeds maximum length of 128 characters`\r\n };\r\n }\r\n\r\n return { valid: true, sanitized: trimmed };\r\n }\r\n\r\n /**\r\n * Validate table name against whitelist\r\n */\r\n private validateTableName(table: string): IdentifierValidationResult {\r\n const validation = this.validateIdentifier(table, 'table');\r\n if (!validation.valid) {\r\n return validation;\r\n }\r\n\r\n const sanitized = validation.sanitized!.toLowerCase();\r\n\r\n // In strict mode, check against whitelist\r\n if (this.strictMode && this.allowedTables.size > 0) {\r\n if (!this.allowedTables.has(sanitized)) {\r\n return {\r\n valid: false,\r\n error: `Table \"${table}\" is not in the whitelist of allowed tables`\r\n };\r\n }\r\n }\r\n\r\n return { valid: true, sanitized: validation.sanitized };\r\n }\r\n\r\n /**\r\n * Validate field name against whitelist for specific table\r\n */\r\n private validateFieldName(field: string, table?: string): IdentifierValidationResult {\r\n const validation = this.validateIdentifier(field, 'field');\r\n if (!validation.valid) {\r\n return validation;\r\n }\r\n\r\n const sanitized = validation.sanitized!.toLowerCase();\r\n\r\n // In strict mode, check against whitelist if available\r\n if (this.strictMode && table) {\r\n const tableLower = table.toLowerCase();\r\n const allowedFieldsForTable = this.allowedFields.get(tableLower);\r\n\r\n if (allowedFieldsForTable && !allowedFieldsForTable.has(sanitized)) {\r\n return {\r\n valid: false,\r\n error: `Field \"${field}\" is not in the whitelist for table \"${table}\"`\r\n };\r\n }\r\n }\r\n\r\n return { valid: true, sanitized: validation.sanitized };\r\n }\r\n\r\n /**\r\n * Parse SQL SELECT statement\r\n */\r\n parseSelect(sql: string): {\r\n table?: string;\r\n fields?: string[];\r\n where?: { field: string; operator: string; value?: any }[];\r\n joins?: Array<{ table: string; on: string }>;\r\n error?: string;\r\n } {\r\n const result: any = {};\r\n\r\n try {\r\n // Extract table name\r\n const tableMatch = sql.match(/FROM\\s+(\\w+)/i);\r\n if (tableMatch) {\r\n const tableValidation = this.validateTableName(tableMatch[1]);\r\n if (!tableValidation.valid) {\r\n return { error: tableValidation.error };\r\n }\r\n result.table = tableValidation.sanitized;\r\n }\r\n\r\n // Extract fields\r\n const fieldsMatch = sql.match(/SELECT\\s+(.*?)\\s+FROM/i);\r\n if (fieldsMatch) {\r\n const fields = fieldsMatch[1].trim();\r\n if (fields === '*') {\r\n result.fields = ['*'];\r\n } else {\r\n const fieldList = fields.split(',').map(f => f.trim());\r\n const validatedFields = [];\r\n\r\n for (const field of fieldList) {\r\n const fieldValidation = this.validateFieldName(field, result.table);\r\n if (!fieldValidation.valid) {\r\n return { error: fieldValidation.error };\r\n }\r\n validatedFields.push(fieldValidation.sanitized);\r\n }\r\n result.fields = validatedFields;\r\n }\r\n }\r\n\r\n // Extract WHERE clause\r\n const whereMatch = sql.match(/WHERE\\s+(.*?)(?:ORDER BY|GROUP BY|LIMIT|$)/i);\r\n if (whereMatch) {\r\n const whereClause = whereMatch[1].trim();\r\n const whereResult = this.parseWhereClause(whereClause, result.table);\r\n if (whereResult.error) {\r\n return { error: whereResult.error };\r\n }\r\n result.where = whereResult.conditions;\r\n }\r\n\r\n // Extract JOINs\r\n const joinMatches = sql.matchAll(/(?:INNER |LEFT |RIGHT |)?JOIN\\s+(\\w+)\\s+ON\\s+(.*?)(?:WHERE|ORDER BY|GROUP BY|LIMIT|JOIN|$)/gi);\r\n result.joins = [];\r\n for (const match of joinMatches) {\r\n const joinTableValidation = this.validateTableName(match[1]);\r\n if (!joinTableValidation.valid) {\r\n return { error: joinTableValidation.error };\r\n }\r\n result.joins.push({\r\n table: joinTableValidation.sanitized,\r\n on: match[2].trim(),\r\n });\r\n }\r\n\r\n return result;\r\n } catch (error) {\r\n return {\r\n error: `Failed to parse SELECT statement: ${error instanceof Error ? error.message : 'Unknown error'}`\r\n };\r\n }\r\n }\r\n\r\n /**\r\n * Parse WHERE clause with validation\r\n */\r\n private parseWhereClause(whereClause: string, table?: string): {\r\n conditions?: Array<{ field: string; operator: string; value?: any }>;\r\n error?: string;\r\n } {\r\n const conditions: Array<{ field: string; operator: string; value?: any }> = [];\r\n\r\n try {\r\n // Simple parser for basic conditions\r\n // Format: field = ? OR field LIKE ? etc.\r\n const parts = whereClause.split(/\\s+AND\\s+/i);\r\n\r\n for (const part of parts) {\r\n const match = part.match(/(\\w+)\\s*(=|!=|>|>=|<|<=|LIKE|IN|NOT IN)\\s*(.+)/i);\r\n if (match) {\r\n const fieldValidation = this.validateFieldName(match[1], table);\r\n if (!fieldValidation.valid) {\r\n return { error: fieldValidation.error };\r\n }\r\n\r\n conditions.push({\r\n field: fieldValidation.sanitized!,\r\n operator: match[2].toLowerCase(),\r\n value: match[3] === '?' ? undefined : match[3],\r\n });\r\n }\r\n }\r\n\r\n return { conditions };\r\n } catch (error) {\r\n return {\r\n error: `Failed to parse WHERE clause: ${error instanceof Error ? error.message : 'Unknown error'}`\r\n };\r\n }\r\n }\r\n\r\n /**\r\n * Parse SQL INSERT statement with validation\r\n */\r\n parseInsert(sql: string): {\r\n table?: string;\r\n fields?: string[];\r\n error?: string;\r\n } {\r\n const result: any = {};\r\n\r\n try {\r\n // Extract table name\r\n const tableMatch = sql.match(/INSERT INTO\\s+(\\w+)/i);\r\n if (tableMatch) {\r\n const tableValidation = this.validateTableName(tableMatch[1]);\r\n if (!tableValidation.valid) {\r\n return { error: tableValidation.error };\r\n }\r\n result.table = tableValidation.sanitized;\r\n }\r\n\r\n // Extract fields\r\n const fieldsMatch = sql.match(/\\(([^)]+)\\)\\s+VALUES/i);\r\n if (fieldsMatch) {\r\n const fieldList = fieldsMatch[1].split(',').map(f => f.trim());\r\n const validatedFields = [];\r\n\r\n for (const field of fieldList) {\r\n const fieldValidation = this.validateFieldName(field, result.table);\r\n if (!fieldValidation.valid) {\r\n return { error: fieldValidation.error };\r\n }\r\n validatedFields.push(fieldValidation.sanitized);\r\n }\r\n result.fields = validatedFields;\r\n }\r\n\r\n return result;\r\n } catch (error) {\r\n return {\r\n error: `Failed to parse INSERT statement: ${error instanceof Error ? error.message : 'Unknown error'}`\r\n };\r\n }\r\n }\r\n\r\n /**\r\n * Parse SQL UPDATE statement with validation\r\n */\r\n parseUpdate(sql: string): {\r\n table?: string;\r\n fields?: string[];\r\n where?: { field: string; operator: string; value?: any }[];\r\n error?: string;\r\n } {\r\n const result: any = {};\r\n\r\n try {\r\n // Extract table name\r\n const tableMatch = sql.match(/UPDATE\\s+(\\w+)/i);\r\n if (tableMatch) {\r\n const tableValidation = this.validateTableName(tableMatch[1]);\r\n if (!tableValidation.valid) {\r\n return { error: tableValidation.error };\r\n }\r\n result.table = tableValidation.sanitized;\r\n }\r\n\r\n // Extract SET clause\r\n const setMatch = sql.match(/SET\\s+(.*?)\\s+WHERE/i);\r\n if (setMatch) {\r\n const setParts = setMatch[1].split(',');\r\n const validatedFields = [];\r\n\r\n for (const part of setParts) {\r\n const field = part.split('=')[0].trim();\r\n const fieldValidation = this.validateFieldName(field, result.table);\r\n if (!fieldValidation.valid) {\r\n return { error: fieldValidation.error };\r\n }\r\n validatedFields.push(fieldValidation.sanitized);\r\n }\r\n result.fields = validatedFields;\r\n }\r\n\r\n // Extract WHERE clause\r\n const whereMatch = sql.match(/WHERE\\s+(.*?)$/i);\r\n if (whereMatch) {\r\n const whereResult = this.parseWhereClause(whereMatch[1].trim(), result.table);\r\n if (whereResult.error) {\r\n return { error: whereResult.error };\r\n }\r\n result.where = whereResult.conditions;\r\n }\r\n\r\n return result;\r\n } catch (error) {\r\n return {\r\n error: `Failed to parse UPDATE statement: ${error instanceof Error ? error.message : 'Unknown error'}`\r\n };\r\n }\r\n }\r\n\r\n /**\r\n * Parse SQL DELETE statement with validation\r\n */\r\n parseDelete(sql: string): {\r\n table?: string;\r\n where?: { field: string; operator: string; value?: any }[];\r\n error?: string;\r\n } {\r\n const result: any = {};\r\n\r\n try {\r\n // Extract table name\r\n const tableMatch = sql.match(/DELETE FROM\\s+(\\w+)/i);\r\n if (tableMatch) {\r\n const tableValidation = this.validateTableName(tableMatch[1]);\r\n if (!tableValidation.valid) {\r\n return { error: tableValidation.error };\r\n }\r\n result.table = tableValidation.sanitized;\r\n }\r\n\r\n // Extract WHERE clause\r\n const whereMatch = sql.match(/WHERE\\s+(.*?)$/i);\r\n if (whereMatch) {\r\n const whereResult = this.parseWhereClause(whereMatch[1].trim(), result.table);\r\n if (whereResult.error) {\r\n return { error: whereResult.error };\r\n }\r\n result.where = whereResult.conditions;\r\n }\r\n\r\n return result;\r\n } catch (error) {\r\n return {\r\n error: `Failed to parse DELETE statement: ${error instanceof Error ? error.message : 'Unknown error'}`\r\n };\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Query Translator - SECURITY HARDENED\r\n *\r\n * Provides bidirectional translation between SQL and Redis commands\r\n * with comprehensive input validation and SQL injection prevention\r\n */\r\nexport class QueryTranslator {\r\n private parser: SQLParser;\r\n private config: Required<QueryTranslatorConfig>;\r\n\r\n constructor(config?: QueryTranslatorConfig) {\r\n this.config = {\r\n allowedTables: config?.allowedTables || [],\r\n allowedFields: config?.allowedFields || {},\r\n maxQueryLength: config?.maxQueryLength || 10000,\r\n maxParams: config?.maxParams || 100,\r\n strictMode: config?.strictMode !== false,\r\n };\r\n\r\n this.parser = new SQLParser(\r\n this.config.allowedTables,\r\n this.config.allowedFields,\r\n this.config.strictMode\r\n );\r\n }\r\n\r\n /**\r\n * Validate input parameters\r\n */\r\n private validateInput(sql: string, params: any[] = []): { valid: boolean; error?: string } {\r\n if (!sql || typeof sql !== 'string') {\r\n return { valid: false, error: 'SQL query must be a non-empty string' };\r\n }\r\n\r\n if (sql.length > this.config.maxQueryLength) {\r\n return {\r\n valid: false,\r\n error: `SQL query exceeds maximum length of ${this.config.maxQueryLength} characters`\r\n };\r\n }\r\n\r\n if (!Array.isArray(params)) {\r\n return { valid: false, error: 'Parameters must be an array' };\r\n }\r\n\r\n if (params.length > this.config.maxParams) {\r\n return {\r\n valid: false,\r\n error: `Too many parameters. Maximum: ${this.config.maxParams}`\r\n };\r\n }\r\n\r\n // Detect SQL injection patterns in the query\r\n // These patterns should ONLY appear in specific contexts (after ?)\r\n const injectionPatterns = [\r\n /\\bOR\\b[\\s]*(\\d+\\s*=\\s*\\d+|'[^']*'\\s*=\\s*'[^']*'|true|1)/i, // OR 1=1, OR 'a'='a'\r\n /\\bUNION\\b[\\s]+(SELECT|ALL)/i, // UNION SELECT\r\n /--\\s*$/i, // SQL comments at end\r\n /\\/\\*[\\s\\S]*?\\*\\//i, // Multi-line comments\r\n /;\\s*(SELECT|INSERT|UPDATE|DELETE|DROP|TRUNCATE|ALTER)/i, // Stacked queries\r\n /\\bDROP\\b|\\bTRUNCATE\\b|\\bALTER\\b|\\bCREATE\\b/i, // DDL commands\r\n /\\bEVAL\\b|\\bEXEC\\b|\\bSCRIPT\\b/i, // Dangerous functions\r\n /\\x00/, // Null bytes\r\n ];\r\n\r\n // Split query into parts based on ? placeholders\r\n const parts = sql.split('?');\r\n\r\n // Check structure: should be [prefix, suffix] or [prefix1, middle1, middle2, suffix]\r\n // Injection attempts will have SQL keywords AFTER the ?\r\n for (let i = 0; i < parts.length; i++) {\r\n const part = parts[i];\r\n\r\n // First part should contain SELECT/INSERT/UPDATE/DELETE/FROM\r\n if (i === 0) {\r\n // Validate it's a valid SQL statement start\r\n if (!/(SELECT|INSERT|UPDATE|DELETE|FROM)\\b/i.test(part)) {\r\n // Only valid if it's completely empty (error caught elsewhere)\r\n if (part.trim()) {\r\n return {\r\n valid: false,\r\n error: 'Invalid SQL query structure. Must start with SELECT, INSERT, UPDATE, or DELETE'\r\n };\r\n }\r\n }\r\n } else if (i === parts.length - 1) {\r\n // Last part (after last ?) should not have SQL keywords that indicate injection\r\n if (/\\b(OR|UNION|SELECT|INSERT|UPDATE|DELETE|DROP|TRUNCATE)\\b/i.test(part)) {\r\n return {\r\n valid: false,\r\n error: 'SQL query contains suspicious injection patterns'\r\n };\r\n }\r\n } else {\r\n // Middle parts (between ? and ?) should be minimal\r\n // Should only contain WHERE, AND, OR (as operators), commas, etc.\r\n // But NOT SELECT, UNION, etc.\r\n if (/\\b(UNION|SELECT|INSERT|UPDATE|DELETE|DROP)\\b/i.test(part)) {\r\n return {\r\n valid: false,\r\n error: 'SQL query contains suspicious injection patterns'\r\n };\r\n }\r\n }\r\n }\r\n\r\n // Check for injection patterns in the entire query\r\n for (const pattern of injectionPatterns) {\r\n // Skip OR if it's part of valid syntax (after WHERE)\r\n if (pattern.source.includes('OR') && /WHERE[\\s\\S]*\\?[\\s\\S]*OR/i.test(sql)) {\r\n // This could be valid OR in WHERE clause\r\n const afterQuestion = sql.substring(sql.indexOf('?') + 1);\r\n if (/\\bOR\\b[\\s]*[\\'\\\"]?\\d+['\\\"]*\\s*=\\s*[\\'\\\"]?\\d+['\\\"]*|OR\\s*'[^']*'\\s*=\\s*'[^']*'|OR\\s*TRUE/i.test(afterQuestion)) {\r\n return {\r\n valid: false,\r\n error: 'SQL query contains SQL injection pattern: OR-based bypass'\r\n };\r\n }\r\n } else if (pattern.test(sql) && !sql.includes('?')) {\r\n // Pattern found but no parameterization\r\n return {\r\n valid: false,\r\n error: 'SQL query contains suspicious patterns. Use parameterized queries.'\r\n };\r\n }\r\n }\r\n\r\n return { valid: true };\r\n }\r\n\r\n /**\r\n * Validate Redis command structure\r\n */\r\n private validateRedisCommand(command: RedisCommand): { valid: boolean; error?: string } {\r\n if (!command || typeof command !== 'object') {\r\n return { valid: false, error: 'Redis command must be an object' };\r\n }\r\n\r\n if (!command.command || typeof command.command !== 'string') {\r\n return { valid: false, error: 'Redis command name must be a non-empty string' };\r\n }\r\n\r\n const allowedCommands = ['GET', 'SET', 'HGET', 'HGETALL', 'HMSET', 'HSET', 'DEL', 'MGET', 'MSET'];\r\n if (!allowedCommands.includes(command.command.toUpperCase())) {\r\n return {\r\n valid: false,\r\n error: `Redis command \"${command.command}\" is not allowed. Allowed: ${allowedCommands.join(', ')}`\r\n };\r\n }\r\n\r\n if (command.key && typeof command.key !== 'string') {\r\n return { valid: false, error: 'Redis key must be a string' };\r\n }\r\n\r\n if (command.fields && typeof command.fields !== 'object') {\r\n return { valid: false, error: 'Redis fields must be an object' };\r\n }\r\n\r\n if (command.args && !Array.isArray(command.args)) {\r\n return { valid: false, error: 'Redis args must be an array' };\r\n }\r\n\r\n return { valid: true };\r\n }\r\n\r\n /**\r\n * Translate SQL query to Redis commands\r\n */\r\n translateSQLToRedis(sql: string, params: any[] = []): TranslationResult {\r\n const startTime = Date.now();\r\n const warnings: string[] = [];\r\n\r\n try {\r\n // Validate inputs\r\n const inputValidation = this.validateInput(sql, params);\r\n if (!inputValidation.valid) {\r\n throw new StandardError(\r\n ErrorCode.VALIDATION_FAILED,\r\n inputValidation.error || 'Invalid input',\r\n { sql, paramCount: params.length }\r\n );\r\n }\r\n\r\n // Determine query type\r\n const queryType = this.getQueryType(sql);\r\n\r\n let redisCommand: RedisCommand | undefined;\r\n let recommendedBackend = BackendType.REDIS;\r\n\r\n switch (queryType) {\r\n case 'SELECT': {\r\n const selectParsed = this.parser.parseSelect(sql);\r\n\r\n if (selectParsed.error) {\r\n throw new StandardError(\r\n ErrorCode.PARSE_ERROR,\r\n `Failed to parse SELECT statement: ${selectParsed.error}`,\r\n { sql }\r\n );\r\n }\r\n\r\n // Check if query is complex (has joins)\r\n if (selectParsed.joins && selectParsed.joins.length > 0) {\r\n warnings.push('Complex queries with JOINs are better suited for PostgreSQL');\r\n recommendedBackend = BackendType.POSTGRES;\r\n }\r\n\r\n // Translate to Redis HGETALL or GET\r\n if (selectParsed.where && selectParsed.where.length > 0) {\r\n const idCondition = selectParsed.where.find(w => w.field === 'id');\r\n if (idCondition) {\r\n const keyValue = params[0];\r\n\r\n // Validate key value\r\n if (typeof keyValue !== 'string' && typeof keyValue !== 'number') {\r\n throw new StandardError(\r\n ErrorCode.VALIDATION_FAILED,\r\n 'Redis key value must be a string or number',\r\n { paramValue: typeof keyValue }\r\n );\r\n }\r\n\r\n const redisKey = `${selectParsed.table}:${keyValue}`;\r\n\r\n redisCommand = {\r\n command: selectParsed.fields?.[0] === '*' ? 'HGETALL' : 'HGET',\r\n key: redisKey,\r\n };\r\n }\r\n }\r\n break;\r\n }\r\n\r\n case 'INSERT': {\r\n const insertParsed = this.parser.parseInsert(sql);\r\n\r\n if (insertParsed.error) {\r\n throw new StandardError(\r\n ErrorCode.PARSE_ERROR,\r\n `Failed to parse INSERT statement: ${insertParsed.error}`,\r\n { sql }\r\n );\r\n }\r\n\r\n if (insertParsed.table && insertParsed.fields) {\r\n const idValue = params[0];\r\n\r\n // Validate key value\r\n if (typeof idValue !== 'string' && typeof idValue !== 'number') {\r\n throw new StandardError(\r\n ErrorCode.VALIDATION_FAILED,\r\n 'Redis key value must be a string or number',\r\n { paramValue: typeof idValue }\r\n );\r\n }\r\n\r\n const redisKey = `${insertParsed.table}:${idValue}`;\r\n\r\n // Build field-value pairs with validation\r\n const fields: Record<string, any> = {};\r\n for (let i = 0; i < insertParsed.fields.length && i < params.length; i++) {\r\n // Ensure params are not objects/arrays (prevent injection)\r\n const paramValue = params[i];\r\n if (typeof paramValue === 'object' && paramValue !== null) {\r\n throw new StandardError(\r\n ErrorCode.VALIDATION_FAILED,\r\n 'Parameter values must be primitives (string, number, boolean, null)',\r\n { paramIndex: i, paramType: typeof paramValue }\r\n );\r\n }\r\n fields[insertParsed.fields[i]] = paramValue;\r\n }\r\n\r\n redisCommand = {\r\n command: 'HMSET',\r\n key: redisKey,\r\n fields,\r\n };\r\n }\r\n break;\r\n }\r\n\r\n case 'UPDATE': {\r\n const updateParsed = this.parser.parseUpdate(sql);\r\n\r\n if (updateParsed.error) {\r\n throw new StandardError(\r\n ErrorCode.PARSE_ERROR,\r\n `Failed to parse UPDATE statement: ${updateParsed.error}`,\r\n { sql }\r\n );\r\n }\r\n\r\n if (updateParsed.table && updateParsed.where) {\r\n const idCondition = updateParsed.where.find(w => w.field === 'id');\r\n if (idCondition) {\r\n const keyValue = params[params.length - 1];\r\n\r\n // Validate key value\r\n if (typeof keyValue !== 'string' && typeof keyValue !== 'number') {\r\n throw new StandardError(\r\n ErrorCode.VALIDATION_FAILED,\r\n 'Redis key value must be a string or number',\r\n { paramValue: typeof keyValue }\r\n );\r\n }\r\n\r\n const redisKey = `${updateParsed.table}:${keyValue}`;\r\n\r\n redisCommand = {\r\n command: 'HSET',\r\n key: redisKey,\r\n args: params.slice(0, -1),\r\n };\r\n }\r\n }\r\n break;\r\n }\r\n\r\n case 'DELETE': {\r\n const deleteParsed = this.parser.parseDelete(sql);\r\n\r\n if (deleteParsed.error) {\r\n throw new StandardError(\r\n ErrorCode.PARSE_ERROR,\r\n `Failed to parse DELETE statement: ${deleteParsed.error}`,\r\n { sql }\r\n );\r\n }\r\n\r\n if (deleteParsed.table && deleteParsed.where) {\r\n const idCondition = deleteParsed.where.find(w => w.field === 'id');\r\n if (idCondition) {\r\n const keyValue = params[0];\r\n\r\n // Validate key value\r\n if (typeof keyValue !== 'string' && typeof keyValue !== 'number') {\r\n throw new StandardError(\r\n ErrorCode.VALIDATION_FAILED,\r\n 'Redis key value must be a string or number',\r\n { paramValue: typeof keyValue }\r\n );\r\n }\r\n\r\n const redisKey = `${deleteParsed.table}:${keyValue}`;\r\n\r\n redisCommand = {\r\n command: 'DEL',\r\n key: redisKey,\r\n };\r\n }\r\n }\r\n break;\r\n }\r\n\r\n default:\r\n warnings.push(`Unsupported SQL query type: ${queryType}`);\r\n recommendedBackend = BackendType.POSTGRES;\r\n }\r\n\r\n const executionTime = Date.now() - startTime;\r\n\r\n if (executionTime > 50) {\r\n warnings.push(`Translation took ${executionTime}ms (target: <50ms)`);\r\n }\r\n\r\n return {\r\n success: !!redisCommand,\r\n redisCommand,\r\n executionTime,\r\n recommendedBackend,\r\n warnings: warnings.length > 0 ? warnings : undefined,\r\n };\r\n } catch (error) {\r\n const executionTime = Date.now() - startTime;\r\n\r\n const message = error instanceof StandardError\r\n ? error.message\r\n : error instanceof Error\r\n ? error.message\r\n : 'Unknown error';\r\n\r\n return {\r\n success: false,\r\n executionTime,\r\n warnings: [`Translation failed: ${message}`],\r\n };\r\n }\r\n }\r\n\r\n /**\r\n * Translate Redis command to SQL query (with parameterization)\r\n */\r\n translateRedisToSQL(command: RedisCommand): TranslationResult {\r\n const startTime = Date.now();\r\n const warnings: string[] = [];\r\n\r\n try {\r\n // Validate Redis command\r\n const commandValidation = this.validateRedisCommand(command);\r\n if (!commandValidation.valid) {\r\n throw new StandardError(\r\n ErrorCode.VALIDATION_FAILED,\r\n commandValidation.error || 'Invalid Redis command',\r\n { command: command.command }\r\n );\r\n }\r\n\r\n let sqlQuery: string | undefined;\r\n let sqlParams: any[] = [];\r\n\r\n // Parse Redis key to extract table and ID\r\n const keyParts = command.key?.split(':') || [];\r\n const table = keyParts[0] || 'unknown';\r\n const id = keyParts[1];\r\n\r\n // Validate table name\r\n const tableValidation = this.parser['validateTableName'] ||\r\n ((t: string) => ({ valid: true, sanitized: t }));\r\n\r\n // Since validateTableName is private, we do basic validation\r\n const tablePattern = /^[a-zA-Z_][a-zA-Z0-9_]*$/;\r\n if (!tablePattern.test(table)) {\r\n throw new StandardError(\r\n ErrorCode.VALIDATION_FAILED,\r\n 'Invalid table name in Redis key',\r\n { key: command.key }\r\n );\r\n }\r\n\r\n switch (command.command.toUpperCase()) {\r\n case 'GET':\r\n case 'HGET':\r\n case 'HGETALL': {\r\n // SELECT * FROM table WHERE id = ?\r\n sqlQuery = `SELECT * FROM ${table} WHERE id = ?`;\r\n sqlParams = [id];\r\n break;\r\n }\r\n\r\n case 'SET':\r\n case 'HMSET': {\r\n // INSERT INTO table (field1, field2, ...) VALUES (?, ?, ...)\r\n if (command.fields) {\r\n const fields = Object.keys(command.fields);\r\n const placeholders = fields.map(() => '?').join(', ');\r\n sqlQuery = `INSERT INTO ${table} (${fields.join(', ')}) VALUES (${placeholders})`;\r\n sqlParams = Object.values(command.fields);\r\n\r\n // Validate all params are primitives\r\n for (let i = 0; i < sqlParams.length; i++) {\r\n if (typeof sqlParams[i] === 'object' && sqlParams[i] !== null) {\r\n throw new StandardError(\r\n ErrorCode.VALIDATION_FAILED,\r\n 'Parameter values must be primitives',\r\n { paramIndex: i }\r\n );\r\n }\r\n }\r\n }\r\n break;\r\n }\r\n\r\n case 'HSET': {\r\n // UPDATE table SET field = ? WHERE id = ?\r\n if (command.args && command.args.length > 0) {\r\n const field = command.args[0];\r\n\r\n // Validate field name\r\n if (typeof field !== 'string' || !/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(field)) {\r\n throw new StandardError(\r\n ErrorCode.VALIDATION_FAILED,\r\n 'Invalid field name in HSET command',\r\n { field }\r\n );\r\n }\r\n\r\n sqlQuery = `UPDATE ${table} SET ${field} = ? WHERE id = ?`;\r\n sqlParams = [command.args[1], id];\r\n\r\n // Validate params\r\n for (let i = 0; i < sqlParams.length; i++) {\r\n if (typeof sqlParams[i] === 'object' && sqlParams[i] !== null) {\r\n throw new StandardError(\r\n ErrorCode.VALIDATION_FAILED,\r\n 'Parameter values must be primitives',\r\n { paramIndex: i }\r\n );\r\n }\r\n }\r\n }\r\n break;\r\n }\r\n\r\n case 'DEL': {\r\n // DELETE FROM table WHERE id = ?\r\n sqlQuery = `DELETE FROM ${table} WHERE id = ?`;\r\n sqlParams = [id];\r\n break;\r\n }\r\n\r\n default:\r\n warnings.push(`Unsupported Redis command: ${command.command}`);\r\n }\r\n\r\n const executionTime = Date.now() - startTime;\r\n\r\n if (executionTime > 50) {\r\n warnings.push(`Translation took ${executionTime}ms (target: <50ms)`);\r\n }\r\n\r\n return {\r\n success: !!sqlQuery,\r\n sqlQuery,\r\n sqlParams,\r\n executionTime,\r\n warnings: warnings.length > 0 ? warnings : undefined,\r\n };\r\n } catch (error) {\r\n const executionTime = Date.now() - startTime;\r\n\r\n const message = error instanceof StandardError\r\n ? error.message\r\n : error instanceof Error\r\n ? error.message\r\n : 'Unknown error';\r\n\r\n return {\r\n success: false,\r\n executionTime,\r\n warnings: [`Translation failed: ${message}`],\r\n };\r\n }\r\n }\r\n\r\n /**\r\n * Optimize query and provide recommendations\r\n */\r\n optimizeQuery(request: QueryRequest): OptimizationResult & { indexes?: string[] } {\r\n const result: OptimizationResult & { indexes?: string[] } = {\r\n indexed: [],\r\n recommendations: [],\r\n };\r\n\r\n // Recommend indexes for filtered fields\r\n if (request.filters) {\r\n const indexFields = request.filters.map(f => String(f.field));\r\n result.indexed = indexFields;\r\n result.indexes = indexFields;\r\n result.recommendations?.push(`Consider adding indexes on: ${indexFields.join(', ')}`);\r\n }\r\n\r\n // Estimate query cost\r\n let cost = 1;\r\n if (request.joins) {\r\n cost += request.joins.length * 10; // JOINs are expensive\r\n }\r\n if (request.filters) {\r\n cost += request.filters.length * 2;\r\n }\r\n result.estimatedCost = cost;\r\n\r\n // Provide optimization recommendations\r\n if (request.joins && request.joins.length > 2) {\r\n result.recommendations?.push('Consider denormalizing data or using materialized views for complex joins');\r\n }\r\n\r\n if (request.filters && request.filters.length > 5) {\r\n result.recommendations?.push('Consider composite indexes for multiple filter conditions');\r\n }\r\n\r\n return result;\r\n }\r\n\r\n /**\r\n * Recommend backend based on query characteristics\r\n */\r\n recommendBackend(request: QueryRequest): BackendType {\r\n // Simple key-value access → Redis\r\n if (request.key && !request.joins) {\r\n return BackendType.REDIS;\r\n }\r\n\r\n // Complex queries with JOINs → PostgreSQL\r\n if (request.joins && request.joins.length > 0) {\r\n return BackendType.POSTGRES;\r\n }\r\n\r\n // Session/cache data → Redis\r\n if (request.dataType === 'cache' || request.dataType === 'session') {\r\n return BackendType.REDIS;\r\n }\r\n\r\n // Embedded/local data → SQLite\r\n if (request.dataType === 'embedded') {\r\n return BackendType.SQLITE;\r\n }\r\n\r\n // Default to PostgreSQL for structured data\r\n return BackendType.POSTGRES;\r\n }\r\n\r\n /**\r\n * Get query type from SQL string\r\n */\r\n private getQueryType(sql: string): string {\r\n const trimmed = sql.trim().toUpperCase();\r\n\r\n if (trimmed.startsWith('SELECT')) return 'SELECT';\r\n if (trimmed.startsWith('INSERT')) return 'INSERT';\r\n if (trimmed.startsWith('UPDATE')) return 'UPDATE';\r\n if (trimmed.startsWith('DELETE')) return 'DELETE';\r\n\r\n return 'UNKNOWN';\r\n }\r\n}\r\n"],"names":["BackendType","StandardError","ErrorCode","SQLParser","allowedTables","allowedFields","strictMode","Set","Map","table","fields","Object","entries","set","toLowerCase","map","f","validateIdentifier","identifier","type","valid","error","trimmed","trim","identifierPattern","test","length","sanitized","validateTableName","validation","size","has","validateFieldName","field","tableLower","allowedFieldsForTable","get","parseSelect","sql","result","tableMatch","match","tableValidation","fieldsMatch","fieldList","split","validatedFields","fieldValidation","push","whereMatch","whereClause","whereResult","parseWhereClause","where","conditions","joinMatches","matchAll","joins","joinTableValidation","on","Error","message","parts","part","operator","value","undefined","parseInsert","parseUpdate","setMatch","setParts","parseDelete","QueryTranslator","parser","config","maxQueryLength","maxParams","validateInput","params","Array","isArray","injectionPatterns","i","pattern","source","includes","afterQuestion","substring","indexOf","validateRedisCommand","command","allowedCommands","toUpperCase","join","key","args","translateSQLToRedis","startTime","Date","now","warnings","inputValidation","VALIDATION_FAILED","paramCount","queryType","getQueryType","redisCommand","recommendedBackend","REDIS","selectParsed","PARSE_ERROR","POSTGRES","idCondition","find","w","keyValue","paramValue","redisKey","insertParsed","idValue","paramIndex","paramType","updateParsed","slice","deleteParsed","executionTime","success","translateRedisToSQL","commandValidation","sqlQuery","sqlParams","keyParts","id","t","tablePattern","keys","placeholders","values","optimizeQuery","request","indexed","recommendations","filters","indexFields","String","indexes","cost","estimatedCost","recommendBackend","dataType","SQLITE","startsWith"],"mappings":"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"}
@@ -0,0 +1,469 @@
1
+ /**
2
+ * Queue Recovery System
3
+ *
4
+ * Provides failure detection, dead letter queue management, and automatic recovery
5
+ * for Redis queue operations. Handles coordinator crashes and message reprocessing.
6
+ * Part of Task 3.4: Redis Queue Consistency & Recovery (Integration Standardization Sprint 3)
7
+ *
8
+ * Features:
9
+ * - Dead letter queue for failed messages
10
+ * - Automatic retry with exponential backoff
11
+ * - Failure detection (tasks not processed within timeout)
12
+ * - Coordinator crash recovery procedure
13
+ * - Message reprocessing safeguards
14
+ *
15
+ * Usage:
16
+ * const recovery = new QueueRecovery(queueManager);
17
+ *
18
+ * // Start monitoring for stuck messages
19
+ * recovery.startMonitoring();
20
+ *
21
+ * // Recover from coordinator crash
22
+ * await recovery.recoverFromCrash();
23
+ *
24
+ * // Process dead letter queue
25
+ * const reprocessed = await recovery.reprocessDeadLetters();
26
+ */ import { createLogger } from './logging.js';
27
+ import { createError, ErrorCode, isRetryableError } from './errors.js';
28
+ import { sleep } from './retry.js';
29
+ const logger = createLogger('queue-recovery');
30
+ /**
31
+ * Default recovery options
32
+ */ const DEFAULT_RECOVERY_OPTIONS = {
33
+ maxRetries: 3,
34
+ baseRetryDelayMs: 1000,
35
+ maxRetryDelayMs: 60000,
36
+ processingTimeoutMs: 300000,
37
+ monitoringIntervalMs: 60000,
38
+ deadLetterQueue: 'dlq',
39
+ autoReprocess: false
40
+ };
41
+ /**
42
+ * Queue Recovery System
43
+ *
44
+ * Handles failure detection, retry, and recovery for queue operations.
45
+ */ export class QueueRecovery {
46
+ queueManager;
47
+ redis;
48
+ options;
49
+ monitoringTimer = null;
50
+ stats = {
51
+ totalRecovered: 0,
52
+ totalDeadLettered: 0,
53
+ totalReprocessed: 0,
54
+ totalStuckDetected: 0
55
+ };
56
+ /**
57
+ * Create a new QueueRecovery instance
58
+ *
59
+ * @param queueManager - Queue manager instance
60
+ * @param redis - Redis client instance
61
+ * @param options - Recovery options
62
+ */ constructor(queueManager, redis, options = {}){
63
+ this.queueManager = queueManager;
64
+ this.redis = redis;
65
+ this.options = {
66
+ ...DEFAULT_RECOVERY_OPTIONS,
67
+ ...options
68
+ };
69
+ logger.info('QueueRecovery initialized', {
70
+ maxRetries: this.options.maxRetries,
71
+ processingTimeoutMs: this.options.processingTimeoutMs,
72
+ deadLetterQueue: this.options.deadLetterQueue
73
+ });
74
+ }
75
+ /**
76
+ * Retry message processing with exponential backoff
77
+ *
78
+ * @param message - Message to retry
79
+ * @param processFn - Function to process message
80
+ * @returns Processing result
81
+ */ async retryWithBackoff(message, processFn) {
82
+ const maxAttempts = this.options.maxRetries;
83
+ let attempt = message.deliveryAttempts;
84
+ while(attempt <= maxAttempts){
85
+ try {
86
+ logger.debug('Processing message with retry', {
87
+ messageId: message.id,
88
+ attempt,
89
+ maxAttempts
90
+ });
91
+ const result = await processFn(message.payload);
92
+ if (attempt > 1) {
93
+ this.stats.totalRecovered++;
94
+ logger.info('Message processed successfully after retry', {
95
+ messageId: message.id,
96
+ attempt
97
+ });
98
+ }
99
+ return result;
100
+ } catch (error) {
101
+ const err = error instanceof Error ? error : new Error(String(error));
102
+ logger.warn('Message processing failed', {
103
+ messageId: message.id,
104
+ attempt,
105
+ error: err.message
106
+ });
107
+ // Check if we should retry
108
+ if (!isRetryableError(err) || attempt >= maxAttempts) {
109
+ logger.error('Message processing failed permanently', err, {
110
+ messageId: message.id,
111
+ attempt,
112
+ retryable: isRetryableError(err)
113
+ });
114
+ // Send to dead letter queue
115
+ await this.sendToDeadLetter(message, err.message);
116
+ throw err;
117
+ }
118
+ // Calculate backoff delay
119
+ const delay = this.calculateBackoffDelay(attempt);
120
+ logger.debug('Retrying message after delay', {
121
+ messageId: message.id,
122
+ attempt,
123
+ delayMs: delay
124
+ });
125
+ // Wait before retry
126
+ await sleep(delay);
127
+ attempt++;
128
+ }
129
+ }
130
+ // Should never reach here, but TypeScript needs it
131
+ throw createError(ErrorCode.RETRY_EXHAUSTED, 'Message processing retry exhausted', {
132
+ messageId: message.id,
133
+ attempts: attempt
134
+ });
135
+ }
136
+ /**
137
+ * Send message to dead letter queue
138
+ *
139
+ * @param message - Message to dead letter
140
+ * @param reason - Failure reason
141
+ */ async sendToDeadLetter(message, reason) {
142
+ try {
143
+ const metadata = {
144
+ originalQueue: message.queue,
145
+ failureReason: reason,
146
+ retryAttempts: message.deliveryAttempts,
147
+ deadLetteredAt: new Date(),
148
+ originalMetadata: message.metadata
149
+ };
150
+ // Enqueue to dead letter queue
151
+ await this.queueManager.enqueue(this.options.deadLetterQueue, message.payload, {
152
+ deduplicate: false,
153
+ metadata
154
+ });
155
+ this.stats.totalDeadLettered++;
156
+ logger.info('Message sent to dead letter queue', {
157
+ messageId: message.id,
158
+ originalQueue: message.queue,
159
+ reason,
160
+ retryAttempts: message.deliveryAttempts
161
+ });
162
+ } catch (error) {
163
+ logger.error('Failed to send message to DLQ', error instanceof Error ? error : new Error(String(error)), {
164
+ messageId: message.id
165
+ });
166
+ throw createError(ErrorCode.DB_QUERY_FAILED, 'Failed to send message to dead letter queue', {
167
+ messageId: message.id
168
+ }, error instanceof Error ? error : undefined);
169
+ }
170
+ }
171
+ /**
172
+ * Reprocess messages from dead letter queue
173
+ *
174
+ * @param processFn - Function to process dead letter messages
175
+ * @param maxMessages - Maximum number of messages to reprocess (default: 100)
176
+ * @returns Number of messages reprocessed
177
+ */ async reprocessDeadLetters(processFn, maxMessages = 100) {
178
+ let reprocessedCount = 0;
179
+ try {
180
+ logger.info('Starting dead letter reprocessing', {
181
+ maxMessages
182
+ });
183
+ for(let i = 0; i < maxMessages; i++){
184
+ // Dequeue from dead letter queue
185
+ const message = await this.queueManager.dequeue(this.options.deadLetterQueue, {
186
+ timeout: 0
187
+ });
188
+ if (!message) {
189
+ break;
190
+ }
191
+ try {
192
+ const metadata = message.metadata;
193
+ // Process message
194
+ await processFn(message.payload, metadata);
195
+ // Acknowledge successful processing
196
+ await this.queueManager.acknowledge(message.id);
197
+ reprocessedCount++;
198
+ this.stats.totalReprocessed++;
199
+ logger.debug('Dead letter message reprocessed', {
200
+ messageId: message.id,
201
+ originalQueue: metadata.originalQueue
202
+ });
203
+ } catch (error) {
204
+ // Reject message (will stay in DLQ or be retried based on options)
205
+ await this.queueManager.reject(message.id, {
206
+ retry: false,
207
+ error: error instanceof Error ? error.message : String(error)
208
+ });
209
+ logger.error('Failed to reprocess dead letter', error instanceof Error ? error : new Error(String(error)), {
210
+ messageId: message.id
211
+ });
212
+ }
213
+ }
214
+ logger.info('Dead letter reprocessing complete', {
215
+ reprocessedCount
216
+ });
217
+ return reprocessedCount;
218
+ } catch (error) {
219
+ logger.error('Dead letter reprocessing failed', error instanceof Error ? error : new Error(String(error)));
220
+ throw createError(ErrorCode.DB_QUERY_FAILED, 'Failed to reprocess dead letters', {
221
+ reprocessedCount
222
+ }, error instanceof Error ? error : undefined);
223
+ }
224
+ }
225
+ /**
226
+ * Detect and recover stuck messages (messages in processing longer than timeout)
227
+ *
228
+ * @param queue - Queue name to check
229
+ * @returns Number of stuck messages recovered
230
+ */ async recoverStuckMessages(queue) {
231
+ try {
232
+ const processingKey = `queue:${queue}:processing`;
233
+ const queueKey = `queue:${queue}`;
234
+ // Get all messages in processing
235
+ const processingMessages = await this.redis.lRange(processingKey, 0, -1);
236
+ let recoveredCount = 0;
237
+ const now = Date.now();
238
+ for (const messageData of processingMessages){
239
+ const message = JSON.parse(messageData);
240
+ // Check if message is stuck (processing longer than timeout)
241
+ if (message.dequeuedAt) {
242
+ const processingTime = now - new Date(message.dequeuedAt).getTime();
243
+ if (processingTime > this.options.processingTimeoutMs) {
244
+ logger.warn('Stuck message detected', {
245
+ messageId: message.id,
246
+ queue,
247
+ processingTimeMs: processingTime,
248
+ timeoutMs: this.options.processingTimeoutMs
249
+ });
250
+ this.stats.totalStuckDetected++;
251
+ // Check if message has exceeded max retries
252
+ if (message.deliveryAttempts >= this.options.maxRetries) {
253
+ // Send to dead letter queue
254
+ await this.sendToDeadLetter(message, `Message stuck in processing for ${processingTime}ms (exceeded max retries)`);
255
+ // Remove from processing
256
+ await this.redis.lRem(processingKey, 1, messageData);
257
+ logger.info('Stuck message sent to DLQ', {
258
+ messageId: message.id,
259
+ deliveryAttempts: message.deliveryAttempts
260
+ });
261
+ } else {
262
+ // Re-enqueue for retry
263
+ message.deliveryAttempts++;
264
+ message.metadata = {
265
+ ...message.metadata,
266
+ recoveredAt: new Date().toISOString(),
267
+ recoveryReason: 'Stuck in processing'
268
+ };
269
+ // Remove from processing and add back to queue
270
+ await this.redis.lRem(processingKey, 1, messageData);
271
+ await this.redis.rPush(queueKey, JSON.stringify(message));
272
+ recoveredCount++;
273
+ this.stats.totalRecovered++;
274
+ logger.info('Stuck message re-enqueued', {
275
+ messageId: message.id,
276
+ deliveryAttempts: message.deliveryAttempts
277
+ });
278
+ }
279
+ }
280
+ }
281
+ }
282
+ if (recoveredCount > 0) {
283
+ this.stats.lastRecoveryAt = new Date();
284
+ }
285
+ logger.debug('Stuck message recovery complete', {
286
+ queue,
287
+ recoveredCount,
288
+ totalStuckDetected: this.stats.totalStuckDetected
289
+ });
290
+ return recoveredCount;
291
+ } catch (error) {
292
+ logger.error('Failed to recover stuck messages', error instanceof Error ? error : new Error(String(error)), {
293
+ queue
294
+ });
295
+ throw createError(ErrorCode.DB_QUERY_FAILED, 'Failed to recover stuck messages', {
296
+ queue
297
+ }, error instanceof Error ? error : undefined);
298
+ }
299
+ }
300
+ /**
301
+ * Recover from coordinator crash
302
+ *
303
+ * Scans all queues for stuck messages and recovers them.
304
+ *
305
+ * @returns Object with recovery results per queue
306
+ */ async recoverFromCrash() {
307
+ try {
308
+ logger.info('Starting coordinator crash recovery');
309
+ // Get all queues
310
+ const queues = await this.queueManager.getQueues();
311
+ const results = {};
312
+ // Recover stuck messages from each queue
313
+ for (const queue of queues){
314
+ // Skip dead letter queue
315
+ if (queue === this.options.deadLetterQueue) {
316
+ continue;
317
+ }
318
+ const recovered = await this.recoverStuckMessages(queue);
319
+ results[queue] = recovered;
320
+ }
321
+ const totalRecovered = Object.values(results).reduce((sum, count)=>sum + count, 0);
322
+ logger.info('Coordinator crash recovery complete', {
323
+ queuesProcessed: queues.length,
324
+ totalRecovered,
325
+ results
326
+ });
327
+ return results;
328
+ } catch (error) {
329
+ logger.error('Coordinator crash recovery failed', error instanceof Error ? error : new Error(String(error)));
330
+ throw createError(ErrorCode.DB_QUERY_FAILED, 'Failed to recover from coordinator crash', {}, error instanceof Error ? error : undefined);
331
+ }
332
+ }
333
+ /**
334
+ * Start automatic monitoring for stuck messages
335
+ */ startMonitoring() {
336
+ if (this.monitoringTimer) {
337
+ logger.warn('Monitoring already started');
338
+ return;
339
+ }
340
+ this.monitoringTimer = setInterval(async ()=>{
341
+ try {
342
+ await this.recoverFromCrash();
343
+ // Auto-reprocess dead letters if enabled
344
+ if (this.options.autoReprocess) {
345
+ await this.reprocessDeadLetters(async (payload, metadata)=>{
346
+ logger.debug('Auto-reprocessing dead letter', {
347
+ originalQueue: metadata.originalQueue
348
+ });
349
+ // Re-enqueue to original queue
350
+ await this.queueManager.enqueue(metadata.originalQueue, payload, {
351
+ deduplicate: false,
352
+ metadata: {
353
+ ...metadata,
354
+ reprocessedAt: new Date().toISOString()
355
+ }
356
+ });
357
+ });
358
+ }
359
+ } catch (error) {
360
+ logger.error('Monitoring cycle failed', error instanceof Error ? error : new Error(String(error)));
361
+ }
362
+ }, this.options.monitoringIntervalMs);
363
+ logger.info('Monitoring started', {
364
+ intervalMs: this.options.monitoringIntervalMs,
365
+ autoReprocess: this.options.autoReprocess
366
+ });
367
+ }
368
+ /**
369
+ * Stop automatic monitoring
370
+ */ stopMonitoring() {
371
+ if (this.monitoringTimer) {
372
+ clearInterval(this.monitoringTimer);
373
+ this.monitoringTimer = null;
374
+ logger.info('Monitoring stopped');
375
+ }
376
+ }
377
+ /**
378
+ * Get recovery statistics
379
+ *
380
+ * @returns Current statistics
381
+ */ getStats() {
382
+ return {
383
+ ...this.stats
384
+ };
385
+ }
386
+ /**
387
+ * Reset statistics
388
+ */ resetStats() {
389
+ this.stats = {
390
+ totalRecovered: 0,
391
+ totalDeadLettered: 0,
392
+ totalReprocessed: 0,
393
+ totalStuckDetected: 0
394
+ };
395
+ logger.debug('Statistics reset');
396
+ }
397
+ /**
398
+ * Shutdown recovery system (stop monitoring)
399
+ */ shutdown() {
400
+ this.stopMonitoring();
401
+ logger.info('QueueRecovery shutdown');
402
+ }
403
+ /**
404
+ * Calculate exponential backoff delay
405
+ *
406
+ * @param attempt - Current attempt number (1-based)
407
+ * @returns Delay in milliseconds
408
+ */ calculateBackoffDelay(attempt) {
409
+ // Exponential backoff: baseDelay * 2^(attempt - 1)
410
+ const delay = this.options.baseRetryDelayMs * Math.pow(2, attempt - 1);
411
+ // Cap at max delay
412
+ const cappedDelay = Math.min(delay, this.options.maxRetryDelayMs);
413
+ // Add jitter (+/- 10%) to prevent thundering herd
414
+ const jitterFactor = 0.1;
415
+ const jitterRange = cappedDelay * jitterFactor;
416
+ const jitter = (Math.random() * 2 - 1) * jitterRange;
417
+ return Math.max(0, Math.floor(cappedDelay + jitter));
418
+ }
419
+ }
420
+ /**
421
+ * Message reprocessing safeguards
422
+ */ export class ReprocessingSafeguards {
423
+ processedMessages = new Set();
424
+ maxProcessedTracking;
425
+ /**
426
+ * Create a new ReprocessingSafeguards instance
427
+ *
428
+ * @param maxProcessedTracking - Maximum number of processed message IDs to track (default: 10000)
429
+ */ constructor(maxProcessedTracking = 10000){
430
+ this.maxProcessedTracking = maxProcessedTracking;
431
+ logger.debug('ReprocessingSafeguards initialized', {
432
+ maxProcessedTracking
433
+ });
434
+ }
435
+ /**
436
+ * Check if message has already been processed
437
+ *
438
+ * @param messageId - Message ID to check
439
+ * @returns True if already processed
440
+ */ hasBeenProcessed(messageId) {
441
+ return this.processedMessages.has(messageId);
442
+ }
443
+ /**
444
+ * Mark message as processed
445
+ *
446
+ * @param messageId - Message ID to mark
447
+ */ markProcessed(messageId) {
448
+ // Implement simple LRU-like behavior
449
+ if (this.processedMessages.size >= this.maxProcessedTracking) {
450
+ // Remove oldest entry (first in Set)
451
+ const firstId = this.processedMessages.values().next().value;
452
+ this.processedMessages.delete(firstId);
453
+ }
454
+ this.processedMessages.add(messageId);
455
+ }
456
+ /**
457
+ * Clear all processed message tracking
458
+ */ clear() {
459
+ this.processedMessages.clear();
460
+ logger.debug('Processed messages cleared');
461
+ }
462
+ /**
463
+ * Get number of tracked processed messages
464
+ */ getTrackedCount() {
465
+ return this.processedMessages.size;
466
+ }
467
+ }
468
+
469
+ //# sourceMappingURL=queue-recovery.js.map