claude-flow-novice 2.15.10 → 2.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (652) hide show
  1. package/.claude/cfn-extras/agents/cfn-v3-coordinator.md +517 -0
  2. package/.claude/commands/cfn-loop-cli.md +158 -464
  3. package/.claude/commands/cfn-loop-trigger.md +114 -0
  4. package/.claude/hooks/cfn-invoke-post-edit-ts.sh +100 -0
  5. package/.claude/hooks/cfn-invoke-post-edit-ts.sh.backup +78 -0
  6. package/.claude/hooks/cfn-invoke-post-edit.sh +22 -0
  7. package/.claude/hooks/cfn-invoke-post-edit.sh.backup +87 -0
  8. package/.claude/hooks/cfn-invoke-pre-edit-ts.sh +116 -0
  9. package/.claude/hooks/cfn-invoke-pre-edit-ts.sh.backup +94 -0
  10. package/.claude/hooks/cfn-invoke-pre-edit.sh +22 -0
  11. package/.claude/hooks/cfn-invoke-pre-edit.sh.backup +88 -0
  12. package/.claude/skills/cfn-agent-spawning/SKILL.md +48 -1
  13. package/.claude/skills/cfn-agent-spawning/SKILL.md.backup +135 -0
  14. package/.claude/skills/cfn-agent-spawning/TYPESCRIPT_MIGRATION.md +567 -0
  15. package/.claude/skills/cfn-agent-spawning/check-dependencies.sh +22 -0
  16. package/.claude/skills/{cfn-redis-coordination/check-dependencies.sh → cfn-agent-spawning/check-dependencies.sh.backup} +3 -5
  17. package/.claude/skills/cfn-agent-spawning/get-agent-provider-env.sh +22 -0
  18. package/.claude/skills/cfn-agent-spawning/get-agent-provider-env.sh.backup +127 -0
  19. package/.claude/skills/cfn-agent-spawning/parse-agent-provider.sh +22 -0
  20. package/.claude/skills/cfn-agent-spawning/parse-agent-provider.sh.backup +59 -0
  21. package/.claude/skills/cfn-agent-spawning/spawn-agent-wrapper.sh +63 -0
  22. package/.claude/skills/cfn-agent-spawning/spawn-agent-wrapper.sh.backup +41 -0
  23. package/.claude/skills/cfn-agent-spawning/spawn-agent.sh +26 -1
  24. package/.claude/skills/cfn-agent-spawning/spawn-templates.sh +22 -0
  25. package/.claude/skills/cfn-agent-spawning/spawn-templates.sh.backup +613 -0
  26. package/.claude/skills/cfn-agent-spawning/spawn-worker.sh +22 -0
  27. package/.claude/skills/cfn-agent-spawning/spawn-worker.sh.backup +176 -0
  28. package/.claude/skills/cfn-loop-orchestration/.backups/unknown/1763619700_33aff4a69b99159e4e849107ebc4d09f/metadata.json +8 -0
  29. package/.claude/skills/cfn-loop-orchestration/.backups/unknown/1763619700_33aff4a69b99159e4e849107ebc4d09f/original +271 -0
  30. package/.claude/skills/cfn-loop-orchestration/.backups/unknown/1763619700_33aff4a69b99159e4e849107ebc4d09f/revert.sh +7 -0
  31. package/.claude/skills/cfn-loop-orchestration/.backups/unknown/1763671642_06496e8c399a79db08167cc00ed4b31e/metadata.json +8 -0
  32. package/.claude/skills/cfn-loop-orchestration/.backups/unknown/1763671642_06496e8c399a79db08167cc00ed4b31e/original +325 -0
  33. package/.claude/skills/cfn-loop-orchestration/.backups/unknown/1763671642_06496e8c399a79db08167cc00ed4b31e/revert.sh +7 -0
  34. package/.claude/skills/cfn-loop-orchestration/CLI_IMPLEMENTATION_SUMMARY.md +330 -0
  35. package/.claude/skills/cfn-loop-orchestration/CONFIGURATION_IMPROVEMENTS.md +318 -0
  36. package/.claude/skills/cfn-loop-orchestration/CONTEXT_LOOKUP_MIGRATION.md +308 -0
  37. package/.claude/skills/cfn-loop-orchestration/CONTEXT_LOOKUP_QUICK_START.md +378 -0
  38. package/.claude/skills/cfn-loop-orchestration/E2E_VALIDATION_REPORT.md +262 -0
  39. package/.claude/skills/cfn-loop-orchestration/IMPLEMENTATION_SUMMARY.md +319 -519
  40. package/.claude/skills/cfn-loop-orchestration/NORTH_STAR_E2E_REPORT.md +299 -0
  41. package/.claude/skills/cfn-loop-orchestration/NORTH_STAR_EXECUTION_SUMMARY.md +403 -0
  42. package/.claude/skills/cfn-loop-orchestration/NORTH_STAR_INDEX.md +323 -0
  43. package/.claude/skills/cfn-loop-orchestration/SKILL.md +159 -48
  44. package/.claude/skills/cfn-loop-orchestration/SPAWN_AGENTS_IMPLEMENTATION.md +188 -0
  45. package/.claude/skills/cfn-loop-orchestration/TEST_COVERAGE_REPORT.md +335 -0
  46. package/.claude/skills/cfn-loop-orchestration/TEST_COVERAGE_SUMMARY.md +456 -0
  47. package/.claude/skills/cfn-loop-orchestration/TYPESCRIPT_INTEGRATION_REPORT.md +709 -0
  48. package/.claude/skills/cfn-loop-orchestration/TYPESCRIPT_INTEGRATION_SUMMARY.md +257 -0
  49. package/.claude/skills/cfn-loop-orchestration/VALIDATION_REPORT.md +572 -0
  50. package/.claude/skills/cfn-loop-orchestration/VALIDATION_SUMMARY.txt +196 -0
  51. package/.claude/skills/cfn-loop-orchestration/VALIDATOR_MODULE_GUIDE.md +526 -0
  52. package/.claude/skills/cfn-loop-orchestration/archive/legacy-bash/README.md +167 -0
  53. package/.claude/skills/cfn-loop-orchestration/archive/legacy-bash/orchestrate-enhanced.sh +548 -0
  54. package/{claude-assets/skills/cfn-loop-orchestration → .claude/skills/cfn-loop-orchestration/archive/legacy-bash}/orchestrate-wrapper.sh +11 -1
  55. package/.claude/skills/cfn-loop-orchestration/archive/legacy-bash/orchestrate.sh +182 -0
  56. package/.claude/skills/cfn-loop-orchestration/e2e-validation-fixed.js +240 -0
  57. package/.claude/skills/cfn-loop-orchestration/e2e-validation.js +213 -0
  58. package/.claude/skills/cfn-loop-orchestration/package-lock.json +3 -0
  59. package/.claude/skills/cfn-loop-orchestration/package.json +4 -0
  60. package/.claude/skills/cfn-loop-orchestration/run-north-star-e2e.ts +210 -0
  61. package/.claude/skills/cfn-loop-orchestration/src/cli/orchestrator-cli.ts +396 -0
  62. package/.claude/skills/cfn-loop-orchestration/src/helpers/CONFIDENCE_AGGREGATOR.md +564 -0
  63. package/.claude/skills/cfn-loop-orchestration/src/helpers/CONFIDENCE_AGGREGATOR_QUICK_REF.md +241 -0
  64. package/.claude/skills/cfn-loop-orchestration/src/helpers/CONTEXT_INJECTOR_IMPLEMENTATION.md +375 -0
  65. package/.claude/skills/cfn-loop-orchestration/src/helpers/CONTEXT_INJECTOR_QUICK_REFERENCE.md +362 -0
  66. package/.claude/skills/cfn-loop-orchestration/src/helpers/CONTEXT_INJECTOR_README.md +307 -0
  67. package/.claude/skills/cfn-loop-orchestration/src/helpers/CONTEXT_INJECTOR_USAGE_GUIDE.md +508 -0
  68. package/.claude/skills/cfn-loop-orchestration/src/helpers/confidence-aggregator.ts +473 -0
  69. package/.claude/skills/cfn-loop-orchestration/src/helpers/consensus.ts +1 -1
  70. package/.claude/skills/cfn-loop-orchestration/src/helpers/context-injector.ts +349 -0
  71. package/.claude/skills/cfn-loop-orchestration/src/helpers/context-lookup.ts +486 -0
  72. package/.claude/skills/cfn-loop-orchestration/src/helpers/deliverable-verifier.ts +6 -2
  73. package/.claude/skills/cfn-loop-orchestration/src/helpers/gate-check.ts +1 -1
  74. package/.claude/skills/cfn-loop-orchestration/src/helpers/product-owner-decision.ts +316 -0
  75. package/.claude/skills/cfn-loop-orchestration/src/helpers/spawn-agents.ts +357 -0
  76. package/.claude/skills/cfn-loop-orchestration/src/helpers/validator.ts +276 -0
  77. package/.claude/skills/cfn-loop-orchestration/src/index.ts +2 -0
  78. package/.claude/skills/cfn-loop-orchestration/src/orchestrate.ts +743 -2
  79. package/.claude/skills/cfn-loop-orchestration/src/types.ts +56 -0
  80. package/.claude/skills/cfn-loop-orchestration/test-cli.sh +92 -0
  81. package/.claude/skills/cfn-loop-orchestration/test-typescript-integration.sh +442 -0
  82. package/.claude/skills/cfn-loop-orchestration/tests/agent-spawner.test.ts +124 -0
  83. package/.claude/skills/cfn-loop-orchestration/tests/confidence-aggregator.test.ts +604 -0
  84. package/.claude/skills/cfn-loop-orchestration/tests/context-injector.test.ts +561 -0
  85. package/.claude/skills/cfn-loop-orchestration/tests/context-lookup.test.ts +661 -0
  86. package/.claude/skills/cfn-loop-orchestration/tests/deliverable-verifier.test.ts +2 -2
  87. package/.claude/skills/cfn-loop-orchestration/tests/gate-check-edge-cases.test.ts +422 -0
  88. package/.claude/skills/cfn-loop-orchestration/tests/gate-checker.test.ts +276 -0
  89. package/.claude/skills/cfn-loop-orchestration/tests/logger.test.ts +291 -0
  90. package/.claude/skills/cfn-loop-orchestration/tests/north-star-e2e.test.ts +334 -0
  91. package/.claude/skills/cfn-loop-orchestration/tests/redis-coordinator.test.ts +321 -0
  92. package/.claude/skills/cfn-loop-orchestration/tests/spawn-agents.test.ts +284 -0
  93. package/.claude/skills/cfn-loop-orchestration/tests/validator.test.ts +643 -0
  94. package/.claude/skills/cfn-loop-validation/IMPLEMENTATION_SUMMARY.md +672 -0
  95. package/.claude/skills/cfn-loop-validation/INDEX.md +531 -0
  96. package/.claude/skills/cfn-loop-validation/README_TYPESCRIPT.md +454 -0
  97. package/.claude/skills/cfn-loop-validation/SKILL.md +48 -1
  98. package/.claude/skills/cfn-loop-validation/SKILL.md.backup +353 -0
  99. package/.claude/skills/cfn-loop-validation/SKILL_TYPESCRIPT.md +782 -0
  100. package/.claude/skills/cfn-loop-validation/VAPOR_DETECTION_EXAMPLES.md +598 -0
  101. package/.claude/skills/cfn-loop-validation/check-dependencies.sh +22 -0
  102. package/{claude-assets/skills/cfn-redis-coordination/check-dependencies.sh → .claude/skills/cfn-loop-validation/check-dependencies.sh.backup} +4 -5
  103. package/.claude/skills/cfn-loop-validation/detect-vapor.sh +59 -0
  104. package/.claude/skills/cfn-loop-validation/detect-vapor.sh.backup +37 -0
  105. package/.claude/skills/cfn-loop-validation/dist/.tsbuildinfo +1 -0
  106. package/.claude/skills/cfn-loop-validation/dist/cli/detect-vapor.d.ts +14 -0
  107. package/.claude/skills/cfn-loop-validation/dist/cli/detect-vapor.d.ts.map +1 -0
  108. package/.claude/skills/cfn-loop-validation/dist/cli/detect-vapor.js +185 -0
  109. package/.claude/skills/cfn-loop-validation/dist/cli/detect-vapor.js.map +1 -0
  110. package/.claude/skills/cfn-loop-validation/dist/cli/validate-deliverables.d.ts +14 -0
  111. package/.claude/skills/cfn-loop-validation/dist/cli/validate-deliverables.d.ts.map +1 -0
  112. package/.claude/skills/cfn-loop-validation/dist/cli/validate-deliverables.js +176 -0
  113. package/.claude/skills/cfn-loop-validation/dist/cli/validate-deliverables.js.map +1 -0
  114. package/.claude/skills/cfn-loop-validation/dist/cli/validate-gate.d.ts +19 -0
  115. package/.claude/skills/cfn-loop-validation/dist/cli/validate-gate.d.ts.map +1 -0
  116. package/.claude/skills/cfn-loop-validation/dist/cli/validate-gate.js +123 -0
  117. package/.claude/skills/cfn-loop-validation/dist/cli/validate-gate.js.map +1 -0
  118. package/.claude/skills/cfn-loop-validation/dist/types.d.ts +156 -0
  119. package/.claude/skills/cfn-loop-validation/dist/types.d.ts.map +1 -0
  120. package/.claude/skills/cfn-loop-validation/dist/types.js +66 -0
  121. package/.claude/skills/cfn-loop-validation/dist/types.js.map +1 -0
  122. package/.claude/skills/cfn-loop-validation/dist/validator.d.ts +85 -0
  123. package/.claude/skills/cfn-loop-validation/dist/validator.d.ts.map +1 -0
  124. package/.claude/skills/cfn-loop-validation/dist/validator.js +411 -0
  125. package/.claude/skills/cfn-loop-validation/dist/validator.js.map +1 -0
  126. package/.claude/skills/cfn-loop-validation/orchestrate-cfn-loop.sh +22 -0
  127. package/.claude/skills/cfn-loop-validation/orchestrate-cfn-loop.sh.backup +252 -0
  128. package/.claude/skills/cfn-loop-validation/package.json +93 -0
  129. package/.claude/skills/cfn-loop-validation/src/cli/detect-vapor.ts +177 -0
  130. package/.claude/skills/cfn-loop-validation/src/cli/validate-deliverables.ts +161 -0
  131. package/.claude/skills/cfn-loop-validation/src/cli/validate-gate.ts +139 -0
  132. package/.claude/skills/cfn-loop-validation/src/types.ts +215 -0
  133. package/.claude/skills/cfn-loop-validation/src/validator.ts +503 -0
  134. package/.claude/skills/cfn-loop-validation/tests/validator.test.ts +537 -0
  135. package/.claude/skills/{cfn-redis-coordination → cfn-loop-validation}/tsconfig.json +34 -31
  136. package/.claude/skills/cfn-loop-validation/validate-deliverables.sh +59 -0
  137. package/.claude/skills/cfn-loop-validation/validate-deliverables.sh.backup +37 -0
  138. package/.claude/skills/cfn-loop-validation/validate-gate.sh +63 -0
  139. package/.claude/skills/cfn-loop-validation/validate-gate.sh.backup +41 -0
  140. package/.claude/skills/cfn-loop-validation/validate-iteration.sh +22 -0
  141. package/.claude/skills/cfn-loop-validation/validate-iteration.sh.backup +134 -0
  142. package/.claude/skills/cfn-product-owner-decision/SKILL.md +479 -147
  143. package/.claude/skills/cfn-product-owner-decision/TYPESCRIPT_IMPLEMENTATION.md +653 -0
  144. package/{claude-assets/skills/cfn-product-owner-decision → .claude/skills/cfn-product-owner-decision/archive/legacy-bash}/execute-decision.sh +24 -2
  145. package/.claude/skills/pre-edit-backup/SKILL.md +324 -0
  146. package/.claude/skills/pre-edit-backup/SKILL.md.backup +277 -0
  147. package/.claude/skills/pre-edit-backup/backup.sh +22 -0
  148. package/.claude/skills/pre-edit-backup/backup.sh.backup +107 -0
  149. package/claude-assets/agents/cfn-dev-team/CLAUDE.md +9 -81
  150. package/claude-assets/agents/cfn-dev-team/architecture/base-template-generator.md +4 -4
  151. package/claude-assets/agents/cfn-dev-team/architecture/planner.md +4 -4
  152. package/claude-assets/agents/cfn-dev-team/architecture/system-architect.md +5 -5
  153. package/claude-assets/agents/cfn-dev-team/coordinators/cfn-frontend-coordinator.md +1 -0
  154. package/claude-assets/agents/cfn-dev-team/coordinators/consensus-builder.md +1 -0
  155. package/claude-assets/agents/cfn-dev-team/coordinators/handoff-coordinator.md +1 -0
  156. package/claude-assets/agents/cfn-dev-team/coordinators/multi-sprint-coordinator.md +1 -0
  157. package/claude-assets/agents/cfn-dev-team/dev-ops/devops-engineer.md +14 -4
  158. package/claude-assets/agents/cfn-dev-team/dev-ops/docker-specialist.md +63 -70
  159. package/claude-assets/agents/cfn-dev-team/dev-ops/kubernetes-specialist.md +50 -70
  160. package/claude-assets/agents/cfn-dev-team/dev-ops/monitoring-specialist.md +13 -4
  161. package/claude-assets/agents/cfn-dev-team/developers/api-gateway-specialist.md +27 -58
  162. package/claude-assets/agents/cfn-dev-team/developers/backend-developer.md +40 -58
  163. package/claude-assets/agents/cfn-dev-team/developers/data/data-engineer.md +18 -20
  164. package/claude-assets/agents/cfn-dev-team/developers/database/database-architect.md +19 -28
  165. package/claude-assets/agents/cfn-dev-team/developers/frontend/mobile-dev.md +15 -19
  166. package/claude-assets/agents/cfn-dev-team/developers/frontend/react-frontend-engineer.md +15 -10
  167. package/claude-assets/agents/cfn-dev-team/developers/frontend/typescript-specialist.md +15 -10
  168. package/claude-assets/agents/cfn-dev-team/developers/frontend/ui-designer.md +15 -25
  169. package/claude-assets/agents/cfn-dev-team/developers/graphql-specialist.md +17 -21
  170. package/claude-assets/agents/cfn-dev-team/developers/rust-developer.md +17 -21
  171. package/claude-assets/agents/cfn-dev-team/product-owners/accessibility-advocate-persona.md +4 -4
  172. package/claude-assets/agents/cfn-dev-team/product-owners/cto-agent.md +4 -4
  173. package/claude-assets/agents/cfn-dev-team/product-owners/power-user-persona.md +4 -4
  174. package/claude-assets/agents/cfn-dev-team/product-owners/product-owner.md +19 -27
  175. package/claude-assets/agents/cfn-dev-team/reviewers/code-reviewer.md +20 -51
  176. package/claude-assets/agents/cfn-dev-team/reviewers/quality/code-quality-validator.md +22 -71
  177. package/claude-assets/agents/cfn-dev-team/reviewers/quality/perf-analyzer.md +21 -64
  178. package/claude-assets/agents/cfn-dev-team/reviewers/quality/performance-benchmarker.md +22 -67
  179. package/claude-assets/agents/cfn-dev-team/reviewers/quality/security-specialist.md +23 -67
  180. package/claude-assets/agents/cfn-dev-team/testers/api-testing-specialist.md +14 -70
  181. package/claude-assets/agents/cfn-dev-team/testers/chaos-engineering-specialist.md +25 -73
  182. package/claude-assets/agents/cfn-dev-team/testers/contract-tester.md +26 -65
  183. package/claude-assets/agents/cfn-dev-team/testers/e2e/playwright-tester.md +5 -5
  184. package/claude-assets/agents/cfn-dev-team/testers/integration-tester.md +27 -67
  185. package/claude-assets/agents/cfn-dev-team/testers/interaction-tester.md +16 -73
  186. package/claude-assets/agents/cfn-dev-team/testers/load-testing-specialist.md +27 -67
  187. package/claude-assets/agents/cfn-dev-team/testers/mutation-testing-specialist.md +27 -60
  188. package/claude-assets/agents/cfn-dev-team/testers/playwright-tester.md +15 -74
  189. package/claude-assets/agents/cfn-dev-team/testers/tester.md +14 -60
  190. package/claude-assets/agents/cfn-dev-team/testers/unit/tdd-london-unit-swarm.md +5 -5
  191. package/claude-assets/agents/cfn-dev-team/testers/validation/validation-production-validator.md +4 -4
  192. package/claude-assets/agents/cfn-dev-team/testing/test-validation-agent.md +4 -4
  193. package/claude-assets/agents/cfn-dev-team/utility/agent-builder.md +16 -16
  194. package/claude-assets/agents/cfn-dev-team/utility/analyst.md +16 -32
  195. package/claude-assets/agents/cfn-dev-team/utility/code-booster.md +17 -17
  196. package/claude-assets/agents/cfn-dev-team/utility/context-curator.md +10 -5
  197. package/claude-assets/agents/cfn-dev-team/utility/epic-creator.md +12 -102
  198. package/claude-assets/agents/cfn-dev-team/utility/memory-leak-specialist.md +127 -814
  199. package/claude-assets/agents/cfn-dev-team/utility/researcher.md +16 -25
  200. package/claude-assets/agents/cfn-dev-team/utility/z-ai-specialist.md +157 -667
  201. package/claude-assets/agents/custom/cfn-docker-expert.md +102 -0
  202. package/claude-assets/agents/custom/cfn-loops-cli-expert.md +129 -0
  203. package/claude-assets/cfn-extras/agents/cfn-v3-coordinator.md +517 -0
  204. package/claude-assets/commands/cfn-loop-cli.md +158 -464
  205. package/claude-assets/commands/cfn-loop-trigger.md +114 -0
  206. package/claude-assets/hooks/SKILL.md +518 -0
  207. package/claude-assets/hooks/SKILL.md.backup +471 -0
  208. package/claude-assets/hooks/cfn-invoke-post-edit-ts.sh +100 -0
  209. package/claude-assets/hooks/cfn-invoke-post-edit-ts.sh.backup +78 -0
  210. package/claude-assets/hooks/cfn-invoke-post-edit.sh +22 -0
  211. package/claude-assets/hooks/cfn-invoke-post-edit.sh.backup +87 -0
  212. package/claude-assets/hooks/cfn-invoke-pre-edit-ts.sh +116 -0
  213. package/claude-assets/hooks/cfn-invoke-pre-edit-ts.sh.backup +94 -0
  214. package/claude-assets/hooks/cfn-invoke-pre-edit.sh +22 -0
  215. package/claude-assets/hooks/cfn-invoke-pre-edit.sh.backup +88 -0
  216. package/claude-assets/skills/cfn-agent-selection-with-fallback/DELIVERABLES.md +409 -0
  217. package/claude-assets/skills/cfn-agent-selection-with-fallback/IMPLEMENTATION_SUMMARY.md +396 -0
  218. package/claude-assets/skills/cfn-agent-selection-with-fallback/INTEGRATION_GUIDE.md +308 -0
  219. package/claude-assets/skills/cfn-agent-selection-with-fallback/QUICK_REFERENCE.md +239 -0
  220. package/claude-assets/skills/cfn-agent-selection-with-fallback/SKILL.md +107 -1
  221. package/claude-assets/skills/cfn-agent-selection-with-fallback/SKILL.md.backup +302 -0
  222. package/claude-assets/skills/cfn-agent-selection-with-fallback/TYPESCRIPT_MIGRATION.md +295 -0
  223. package/claude-assets/skills/cfn-agent-selection-with-fallback/dist/agent-selector.cjs +297 -0
  224. package/claude-assets/skills/cfn-agent-selection-with-fallback/dist/agent-selector.js +297 -0
  225. package/claude-assets/skills/cfn-agent-selection-with-fallback/dist/cli.cjs +96 -0
  226. package/claude-assets/skills/cfn-agent-selection-with-fallback/dist/cli.js +96 -0
  227. package/claude-assets/skills/cfn-agent-selection-with-fallback/select-agents-ts.sh +45 -0
  228. package/claude-assets/skills/cfn-agent-selection-with-fallback/select-agents-ts.sh.backup +23 -0
  229. package/claude-assets/skills/cfn-agent-selection-with-fallback/select-agents.sh +22 -0
  230. package/claude-assets/skills/cfn-agent-selection-with-fallback/select-agents.sh.backup +173 -0
  231. package/claude-assets/skills/cfn-agent-selection-with-fallback/src/agent-selector.test.ts +357 -0
  232. package/claude-assets/skills/cfn-agent-selection-with-fallback/src/agent-selector.ts +350 -0
  233. package/claude-assets/skills/cfn-agent-selection-with-fallback/src/cli.ts +74 -0
  234. package/claude-assets/skills/cfn-agent-selection-with-fallback/task-classifier.sh +22 -0
  235. package/claude-assets/skills/cfn-agent-selection-with-fallback/task-classifier.sh.backup +71 -0
  236. package/claude-assets/skills/cfn-agent-selection-with-fallback/tsconfig.json +18 -0
  237. package/claude-assets/skills/cfn-agent-spawning/SKILL.md +48 -1
  238. package/claude-assets/skills/cfn-agent-spawning/SKILL.md.backup +135 -0
  239. package/claude-assets/skills/cfn-agent-spawning/TYPESCRIPT_MIGRATION.md +567 -0
  240. package/claude-assets/skills/cfn-agent-spawning/check-dependencies.sh +22 -0
  241. package/claude-assets/skills/cfn-agent-spawning/check-dependencies.sh.backup +30 -0
  242. package/claude-assets/skills/cfn-agent-spawning/get-agent-provider-env.sh +22 -0
  243. package/claude-assets/skills/cfn-agent-spawning/get-agent-provider-env.sh.backup +127 -0
  244. package/claude-assets/skills/cfn-agent-spawning/parse-agent-provider.sh +22 -0
  245. package/claude-assets/skills/cfn-agent-spawning/parse-agent-provider.sh.backup +59 -0
  246. package/claude-assets/skills/cfn-agent-spawning/spawn-agent-wrapper.sh +63 -0
  247. package/claude-assets/skills/cfn-agent-spawning/spawn-agent-wrapper.sh.backup +41 -0
  248. package/claude-assets/skills/cfn-agent-spawning/spawn-agent.sh +26 -1
  249. package/claude-assets/skills/cfn-agent-spawning/spawn-templates.sh +22 -0
  250. package/claude-assets/skills/cfn-agent-spawning/spawn-templates.sh.backup +613 -0
  251. package/claude-assets/skills/cfn-agent-spawning/spawn-worker.sh +22 -0
  252. package/claude-assets/skills/cfn-agent-spawning/spawn-worker.sh.backup +176 -0
  253. package/claude-assets/skills/cfn-coordination/agent-completion.sh.backup +36 -0
  254. package/claude-assets/skills/cfn-coordination/coordination-signal.sh.backup +36 -0
  255. package/claude-assets/skills/cfn-coordination/coordination-wait.sh.backup +36 -0
  256. package/claude-assets/skills/cfn-dependency-ingestion/README.md +101 -0
  257. package/claude-assets/skills/cfn-dependency-ingestion/SKILL.md +369 -0
  258. package/claude-assets/skills/cfn-dependency-ingestion/build.sh +23 -0
  259. package/claude-assets/skills/cfn-dependency-ingestion/dist/ingest-dependencies.js +478 -0
  260. package/claude-assets/skills/cfn-dependency-ingestion/ingest-dependencies.sh +295 -0
  261. package/claude-assets/skills/cfn-dependency-ingestion/src/ingest-dependencies.ts +563 -0
  262. package/claude-assets/skills/cfn-loop-orchestration/.backups/unknown/1763619700_33aff4a69b99159e4e849107ebc4d09f/metadata.json +8 -0
  263. package/claude-assets/skills/cfn-loop-orchestration/.backups/unknown/1763619700_33aff4a69b99159e4e849107ebc4d09f/original +271 -0
  264. package/claude-assets/skills/cfn-loop-orchestration/.backups/unknown/1763619700_33aff4a69b99159e4e849107ebc4d09f/revert.sh +7 -0
  265. package/claude-assets/skills/cfn-loop-orchestration/.backups/unknown/1763671642_06496e8c399a79db08167cc00ed4b31e/metadata.json +8 -0
  266. package/claude-assets/skills/cfn-loop-orchestration/.backups/unknown/1763671642_06496e8c399a79db08167cc00ed4b31e/original +325 -0
  267. package/claude-assets/skills/cfn-loop-orchestration/.backups/unknown/1763671642_06496e8c399a79db08167cc00ed4b31e/revert.sh +7 -0
  268. package/claude-assets/skills/cfn-loop-orchestration/CLI_IMPLEMENTATION_SUMMARY.md +330 -0
  269. package/claude-assets/skills/cfn-loop-orchestration/CONFIGURATION_IMPROVEMENTS.md +318 -0
  270. package/claude-assets/skills/cfn-loop-orchestration/CONTEXT_LOOKUP_MIGRATION.md +308 -0
  271. package/claude-assets/skills/cfn-loop-orchestration/CONTEXT_LOOKUP_QUICK_START.md +378 -0
  272. package/claude-assets/skills/cfn-loop-orchestration/E2E_VALIDATION_REPORT.md +262 -0
  273. package/claude-assets/skills/cfn-loop-orchestration/IMPLEMENTATION_SUMMARY.md +319 -519
  274. package/claude-assets/skills/cfn-loop-orchestration/NORTH_STAR_E2E_REPORT.md +299 -0
  275. package/claude-assets/skills/cfn-loop-orchestration/NORTH_STAR_EXECUTION_SUMMARY.md +403 -0
  276. package/claude-assets/skills/cfn-loop-orchestration/NORTH_STAR_INDEX.md +323 -0
  277. package/claude-assets/skills/cfn-loop-orchestration/SKILL.md +159 -48
  278. package/claude-assets/skills/cfn-loop-orchestration/SPAWN_AGENTS_IMPLEMENTATION.md +188 -0
  279. package/claude-assets/skills/cfn-loop-orchestration/TEST_COVERAGE_REPORT.md +335 -0
  280. package/claude-assets/skills/cfn-loop-orchestration/TEST_COVERAGE_SUMMARY.md +456 -0
  281. package/claude-assets/skills/cfn-loop-orchestration/TYPESCRIPT_INTEGRATION_REPORT.md +709 -0
  282. package/claude-assets/skills/cfn-loop-orchestration/TYPESCRIPT_INTEGRATION_SUMMARY.md +257 -0
  283. package/claude-assets/skills/cfn-loop-orchestration/VALIDATION_REPORT.md +572 -0
  284. package/claude-assets/skills/cfn-loop-orchestration/VALIDATION_SUMMARY.txt +196 -0
  285. package/claude-assets/skills/cfn-loop-orchestration/VALIDATOR_MODULE_GUIDE.md +526 -0
  286. package/claude-assets/skills/cfn-loop-orchestration/archive/legacy-bash/README.md +167 -0
  287. package/claude-assets/skills/cfn-loop-orchestration/archive/legacy-bash/orchestrate-enhanced.sh +548 -0
  288. package/{.claude/skills/cfn-loop-orchestration → claude-assets/skills/cfn-loop-orchestration/archive/legacy-bash}/orchestrate-wrapper.sh +11 -1
  289. package/claude-assets/skills/cfn-loop-orchestration/archive/legacy-bash/orchestrate.sh +182 -0
  290. package/claude-assets/skills/cfn-loop-orchestration/e2e-validation-fixed.js +240 -0
  291. package/claude-assets/skills/cfn-loop-orchestration/e2e-validation.js +213 -0
  292. package/claude-assets/skills/cfn-loop-orchestration/package-lock.json +3 -0
  293. package/claude-assets/skills/cfn-loop-orchestration/package.json +4 -0
  294. package/claude-assets/skills/cfn-loop-orchestration/run-north-star-e2e.ts +210 -0
  295. package/claude-assets/skills/cfn-loop-orchestration/src/cli/orchestrator-cli.ts +396 -0
  296. package/claude-assets/skills/cfn-loop-orchestration/src/helpers/CONFIDENCE_AGGREGATOR.md +564 -0
  297. package/claude-assets/skills/cfn-loop-orchestration/src/helpers/CONFIDENCE_AGGREGATOR_QUICK_REF.md +241 -0
  298. package/claude-assets/skills/cfn-loop-orchestration/src/helpers/CONTEXT_INJECTOR_IMPLEMENTATION.md +375 -0
  299. package/claude-assets/skills/cfn-loop-orchestration/src/helpers/CONTEXT_INJECTOR_QUICK_REFERENCE.md +362 -0
  300. package/claude-assets/skills/cfn-loop-orchestration/src/helpers/CONTEXT_INJECTOR_README.md +307 -0
  301. package/claude-assets/skills/cfn-loop-orchestration/src/helpers/CONTEXT_INJECTOR_USAGE_GUIDE.md +508 -0
  302. package/claude-assets/skills/cfn-loop-orchestration/src/helpers/confidence-aggregator.ts +473 -0
  303. package/claude-assets/skills/cfn-loop-orchestration/src/helpers/consensus.ts +1 -1
  304. package/claude-assets/skills/cfn-loop-orchestration/src/helpers/context-injector.ts +349 -0
  305. package/claude-assets/skills/cfn-loop-orchestration/src/helpers/context-lookup.ts +486 -0
  306. package/claude-assets/skills/cfn-loop-orchestration/src/helpers/deliverable-verifier.ts +6 -2
  307. package/claude-assets/skills/cfn-loop-orchestration/src/helpers/gate-check.ts +1 -1
  308. package/claude-assets/skills/cfn-loop-orchestration/src/helpers/product-owner-decision.ts +316 -0
  309. package/claude-assets/skills/cfn-loop-orchestration/src/helpers/spawn-agents.ts +357 -0
  310. package/claude-assets/skills/cfn-loop-orchestration/src/helpers/validator.ts +276 -0
  311. package/claude-assets/skills/cfn-loop-orchestration/src/index.ts +2 -0
  312. package/claude-assets/skills/cfn-loop-orchestration/src/orchestrate.ts +743 -2
  313. package/claude-assets/skills/cfn-loop-orchestration/src/types.ts +56 -0
  314. package/claude-assets/skills/cfn-loop-orchestration/test-cli.sh +92 -0
  315. package/claude-assets/skills/cfn-loop-orchestration/test-typescript-integration.sh +442 -0
  316. package/claude-assets/skills/cfn-loop-orchestration/tests/agent-spawner.test.ts +124 -0
  317. package/claude-assets/skills/cfn-loop-orchestration/tests/confidence-aggregator.test.ts +604 -0
  318. package/claude-assets/skills/cfn-loop-orchestration/tests/context-injector.test.ts +561 -0
  319. package/claude-assets/skills/cfn-loop-orchestration/tests/context-lookup.test.ts +661 -0
  320. package/claude-assets/skills/cfn-loop-orchestration/tests/deliverable-verifier.test.ts +2 -2
  321. package/claude-assets/skills/cfn-loop-orchestration/tests/gate-check-edge-cases.test.ts +422 -0
  322. package/claude-assets/skills/cfn-loop-orchestration/tests/gate-checker.test.ts +276 -0
  323. package/claude-assets/skills/cfn-loop-orchestration/tests/logger.test.ts +291 -0
  324. package/claude-assets/skills/cfn-loop-orchestration/tests/north-star-e2e.test.ts +334 -0
  325. package/claude-assets/skills/cfn-loop-orchestration/tests/redis-coordinator.test.ts +321 -0
  326. package/claude-assets/skills/cfn-loop-orchestration/tests/spawn-agents.test.ts +284 -0
  327. package/claude-assets/skills/cfn-loop-orchestration/tests/validator.test.ts +643 -0
  328. package/claude-assets/skills/cfn-loop-output-processing/.eslintrc.json +33 -0
  329. package/claude-assets/skills/cfn-loop-output-processing/DELIVERY_SUMMARY.txt +462 -0
  330. package/claude-assets/skills/cfn-loop-output-processing/DEPRECATION_NOTICE.md +183 -0
  331. package/claude-assets/skills/cfn-loop-output-processing/EXAMPLES.md +609 -0
  332. package/claude-assets/skills/cfn-loop-output-processing/IMPLEMENTATION_SUMMARY.md +418 -0
  333. package/claude-assets/skills/cfn-loop-output-processing/INDEX.md +531 -0
  334. package/claude-assets/skills/cfn-loop-output-processing/MIGRATION.md +362 -0
  335. package/claude-assets/skills/cfn-loop-output-processing/README.md +114 -0
  336. package/claude-assets/skills/cfn-loop-output-processing/SKILL.md +633 -0
  337. package/{.claude/skills/cfn-docker-redis-coordination → claude-assets/skills/cfn-loop-output-processing}/jest.config.js +7 -15
  338. package/claude-assets/skills/cfn-loop-output-processing/package.json +50 -0
  339. package/claude-assets/skills/cfn-loop-output-processing/src/cli/process-loop2.ts +195 -0
  340. package/claude-assets/skills/cfn-loop-output-processing/src/cli/process-loop3.ts +157 -0
  341. package/claude-assets/skills/cfn-loop-output-processing/src/output-processor.ts +632 -0
  342. package/claude-assets/skills/cfn-loop-output-processing/tests/output-processor.test.ts +617 -0
  343. package/claude-assets/skills/{cfn-docker-redis-coordination → cfn-loop-output-processing}/tsconfig.json +16 -7
  344. package/claude-assets/skills/cfn-loop-validation/IMPLEMENTATION_SUMMARY.md +672 -0
  345. package/claude-assets/skills/cfn-loop-validation/INDEX.md +531 -0
  346. package/claude-assets/skills/cfn-loop-validation/README_TYPESCRIPT.md +454 -0
  347. package/claude-assets/skills/cfn-loop-validation/SKILL.md +48 -1
  348. package/claude-assets/skills/cfn-loop-validation/SKILL.md.backup +353 -0
  349. package/claude-assets/skills/cfn-loop-validation/SKILL_TYPESCRIPT.md +782 -0
  350. package/claude-assets/skills/cfn-loop-validation/VAPOR_DETECTION_EXAMPLES.md +598 -0
  351. package/claude-assets/skills/cfn-loop-validation/check-dependencies.sh +22 -0
  352. package/claude-assets/skills/cfn-loop-validation/check-dependencies.sh.backup +31 -0
  353. package/claude-assets/skills/cfn-loop-validation/detect-vapor.sh +59 -0
  354. package/claude-assets/skills/cfn-loop-validation/detect-vapor.sh.backup +37 -0
  355. package/claude-assets/skills/cfn-loop-validation/dist/.tsbuildinfo +1 -0
  356. package/claude-assets/skills/cfn-loop-validation/dist/cli/detect-vapor.d.ts +14 -0
  357. package/claude-assets/skills/cfn-loop-validation/dist/cli/detect-vapor.d.ts.map +1 -0
  358. package/claude-assets/skills/cfn-loop-validation/dist/cli/detect-vapor.js +185 -0
  359. package/claude-assets/skills/cfn-loop-validation/dist/cli/detect-vapor.js.map +1 -0
  360. package/claude-assets/skills/cfn-loop-validation/dist/cli/validate-deliverables.d.ts +14 -0
  361. package/claude-assets/skills/cfn-loop-validation/dist/cli/validate-deliverables.d.ts.map +1 -0
  362. package/claude-assets/skills/cfn-loop-validation/dist/cli/validate-deliverables.js +176 -0
  363. package/claude-assets/skills/cfn-loop-validation/dist/cli/validate-deliverables.js.map +1 -0
  364. package/claude-assets/skills/cfn-loop-validation/dist/cli/validate-gate.d.ts +19 -0
  365. package/claude-assets/skills/cfn-loop-validation/dist/cli/validate-gate.d.ts.map +1 -0
  366. package/claude-assets/skills/cfn-loop-validation/dist/cli/validate-gate.js +123 -0
  367. package/claude-assets/skills/cfn-loop-validation/dist/cli/validate-gate.js.map +1 -0
  368. package/claude-assets/skills/cfn-loop-validation/dist/types.d.ts +156 -0
  369. package/claude-assets/skills/cfn-loop-validation/dist/types.d.ts.map +1 -0
  370. package/claude-assets/skills/cfn-loop-validation/dist/types.js +66 -0
  371. package/claude-assets/skills/cfn-loop-validation/dist/types.js.map +1 -0
  372. package/claude-assets/skills/cfn-loop-validation/dist/validator.d.ts +85 -0
  373. package/claude-assets/skills/cfn-loop-validation/dist/validator.d.ts.map +1 -0
  374. package/claude-assets/skills/cfn-loop-validation/dist/validator.js +411 -0
  375. package/claude-assets/skills/cfn-loop-validation/dist/validator.js.map +1 -0
  376. package/claude-assets/skills/cfn-loop-validation/orchestrate-cfn-loop.sh +22 -0
  377. package/claude-assets/skills/cfn-loop-validation/orchestrate-cfn-loop.sh.backup +252 -0
  378. package/claude-assets/skills/cfn-loop-validation/package.json +93 -0
  379. package/claude-assets/skills/cfn-loop-validation/src/cli/detect-vapor.ts +177 -0
  380. package/claude-assets/skills/cfn-loop-validation/src/cli/validate-deliverables.ts +161 -0
  381. package/claude-assets/skills/cfn-loop-validation/src/cli/validate-gate.ts +139 -0
  382. package/claude-assets/skills/cfn-loop-validation/src/types.ts +215 -0
  383. package/claude-assets/skills/cfn-loop-validation/src/validator.ts +503 -0
  384. package/claude-assets/skills/cfn-loop-validation/tests/validator.test.ts +537 -0
  385. package/claude-assets/skills/{cfn-redis-coordination → cfn-loop-validation}/tsconfig.json +34 -31
  386. package/claude-assets/skills/cfn-loop-validation/validate-deliverables.sh +59 -0
  387. package/claude-assets/skills/cfn-loop-validation/validate-deliverables.sh.backup +37 -0
  388. package/claude-assets/skills/cfn-loop-validation/validate-gate.sh +63 -0
  389. package/claude-assets/skills/cfn-loop-validation/validate-gate.sh.backup +41 -0
  390. package/claude-assets/skills/cfn-loop-validation/validate-iteration.sh +22 -0
  391. package/claude-assets/skills/cfn-loop-validation/validate-iteration.sh.backup +134 -0
  392. package/claude-assets/skills/cfn-product-owner-decision/SKILL.md +479 -147
  393. package/claude-assets/skills/cfn-product-owner-decision/TYPESCRIPT_IMPLEMENTATION.md +653 -0
  394. package/{.claude/skills/cfn-product-owner-decision → claude-assets/skills/cfn-product-owner-decision/archive/legacy-bash}/execute-decision.sh +24 -2
  395. package/claude-assets/skills/cfn-provider-routing/README.md +129 -0
  396. package/claude-assets/skills/cfn-provider-routing/SKILL.md +192 -0
  397. package/claude-assets/skills/cfn-provider-routing/resolve-provider-model.ts +223 -0
  398. package/claude-assets/skills/pre-edit-backup/SKILL.md +324 -0
  399. package/claude-assets/skills/pre-edit-backup/SKILL.md.backup +277 -0
  400. package/claude-assets/skills/pre-edit-backup/backup.sh +22 -0
  401. package/claude-assets/skills/pre-edit-backup/backup.sh.backup +107 -0
  402. package/dist/agents/agent-loader.js +146 -165
  403. package/dist/agents/agent-loader.js.map +1 -1
  404. package/dist/api/auth-endpoints.js +415 -0
  405. package/dist/api/auth-endpoints.js.map +1 -0
  406. package/dist/api/task-endpoints.js +562 -0
  407. package/dist/api/task-endpoints.js.map +1 -0
  408. package/dist/backend/server.js +418 -0
  409. package/dist/backend/server.js.map +1 -0
  410. package/dist/cfn-loop/product-owner/decision-parser.js +356 -0
  411. package/dist/cfn-loop/product-owner/decision-parser.js.map +1 -0
  412. package/dist/cfn-loop/product-owner/index.js +1 -0
  413. package/dist/cfn-loop/product-owner/index.js.map +1 -1
  414. package/dist/cli/agent-command.js +1 -1
  415. package/dist/cli/agent-command.js.map +1 -1
  416. package/dist/cli/agent-completion.js +273 -0
  417. package/dist/cli/agent-completion.js.map +1 -0
  418. package/dist/cli/agent-definition-parser.js +37 -4
  419. package/dist/cli/agent-definition-parser.js.map +1 -1
  420. package/dist/cli/agent-executor.js +32 -2
  421. package/dist/cli/agent-executor.js.map +1 -1
  422. package/dist/cli/agent-prompt-builder.js +83 -48
  423. package/dist/cli/agent-prompt-builder.js.map +1 -1
  424. package/dist/cli/agent-spawner.js +499 -0
  425. package/dist/cli/agent-spawner.js.map +1 -0
  426. package/dist/cli/anthropic-client.js +10 -3
  427. package/dist/cli/anthropic-client.js.map +1 -1
  428. package/dist/cli/config-manager.js.map +1 -1
  429. package/dist/cli/index.js +11 -0
  430. package/dist/cli/index.js.map +1 -1
  431. package/dist/cli/parse-decision-cli.js +268 -0
  432. package/dist/cli/parse-decision-cli.js.map +1 -0
  433. package/dist/cli/post-edit-hook.js +83 -0
  434. package/dist/cli/post-edit-hook.js.map +1 -0
  435. package/dist/cli/pre-edit-hook.js +77 -0
  436. package/dist/cli/pre-edit-hook.js.map +1 -0
  437. package/dist/cli/spawn-agent-cli.js +209 -0
  438. package/dist/cli/spawn-agent-cli.js.map +1 -0
  439. package/dist/coordination/coordination-wrapper.js +383 -0
  440. package/dist/coordination/coordination-wrapper.js.map +1 -0
  441. package/dist/coordination/store-success-criteria.js +68 -0
  442. package/dist/coordination/store-success-criteria.js.map +1 -0
  443. package/dist/coordination/store-task-context.js +65 -0
  444. package/dist/coordination/store-task-context.js.map +1 -0
  445. package/dist/hooks/backup-manager.js +273 -0
  446. package/dist/hooks/backup-manager.js.map +1 -0
  447. package/dist/hooks/post-edit-validator.js +388 -0
  448. package/dist/hooks/post-edit-validator.js.map +1 -0
  449. package/dist/integration/index.js +19 -0
  450. package/dist/integration/index.js.map +1 -0
  451. package/dist/integration/task-mode-adapter.js +297 -0
  452. package/dist/integration/task-mode-adapter.js.map +1 -0
  453. package/dist/integration/trigger-dev-client.js +253 -0
  454. package/dist/integration/trigger-dev-client.js.map +1 -0
  455. package/dist/integration/trigger-dev-webhooks.js +362 -0
  456. package/dist/integration/trigger-dev-webhooks.js.map +1 -0
  457. package/dist/lib/path-validator.js +14 -5
  458. package/dist/lib/path-validator.js.map +1 -1
  459. package/dist/lib/redis-queue-manager.js +5 -1
  460. package/dist/lib/redis-queue-manager.js.map +1 -1
  461. package/dist/middleware/authentication.js +317 -0
  462. package/dist/middleware/authentication.js.map +1 -0
  463. package/dist/services/authentication.js +669 -0
  464. package/dist/services/authentication.js.map +1 -0
  465. package/dist/services/session-management.js +436 -0
  466. package/dist/services/session-management.js.map +1 -0
  467. package/dist/services/skill-deployment.js +8 -6
  468. package/dist/services/skill-deployment.js.map +1 -1
  469. package/dist/services/user-service.js +710 -0
  470. package/dist/services/user-service.js.map +1 -0
  471. package/dist/types/trigger-dev-events.d.js +10 -0
  472. package/dist/types/trigger-dev-events.d.js.map +1 -0
  473. package/docs/README.md +240 -0
  474. package/package.json +13 -4
  475. package/scripts/compare-workflow-performance.sh +556 -0
  476. package/scripts/migrate-to-optimized-workflows.sh +438 -0
  477. package/scripts/organize-docs.sh +338 -0
  478. package/scripts/trigger-dev-setup.sh +267 -0
  479. package/.claude/skills/cfn-docker-redis-coordination/MIGRATION_SUMMARY.md +0 -348
  480. package/.claude/skills/cfn-docker-redis-coordination/README.md +0 -294
  481. package/.claude/skills/cfn-docker-redis-coordination/SKILL.md +0 -435
  482. package/.claude/skills/cfn-docker-redis-coordination/coordinate.sh +0 -650
  483. package/.claude/skills/cfn-docker-redis-coordination/coordinate.sh.backup-1763145142 +0 -641
  484. package/.claude/skills/cfn-docker-redis-coordination/package-lock.json +0 -5259
  485. package/.claude/skills/cfn-docker-redis-coordination/package.json +0 -40
  486. package/.claude/skills/cfn-docker-redis-coordination/src/coordinator.ts +0 -801
  487. package/.claude/skills/cfn-docker-redis-coordination/src/index.ts +0 -42
  488. package/.claude/skills/cfn-docker-redis-coordination/src/types.ts +0 -351
  489. package/.claude/skills/cfn-docker-redis-coordination/tests/coordinator.test.ts +0 -1464
  490. package/.claude/skills/cfn-docker-redis-coordination/tsconfig.json +0 -30
  491. package/.claude/skills/cfn-loop-orchestration/helpers/auto-tune-timeouts.sh +0 -228
  492. package/.claude/skills/cfn-loop-orchestration/helpers/consensus-ts.sh +0 -104
  493. package/.claude/skills/cfn-loop-orchestration/helpers/consensus.sh +0 -94
  494. package/.claude/skills/cfn-loop-orchestration/helpers/context-injection.sh +0 -142
  495. package/.claude/skills/cfn-loop-orchestration/helpers/context-lookup.sh +0 -359
  496. package/.claude/skills/cfn-loop-orchestration/helpers/deliverable-verifier-ts.sh +0 -123
  497. package/.claude/skills/cfn-loop-orchestration/helpers/deliverable-verifier.sh +0 -71
  498. package/.claude/skills/cfn-loop-orchestration/helpers/gate-check.sh +0 -56
  499. package/.claude/skills/cfn-loop-orchestration/helpers/iteration-manager-ts.sh +0 -89
  500. package/.claude/skills/cfn-loop-orchestration/helpers/iteration-manager.sh +0 -87
  501. package/.claude/skills/cfn-loop-orchestration/helpers/orchestrate-ts.sh +0 -104
  502. package/.claude/skills/cfn-loop-orchestration/helpers/parse-test-results.sh +0 -56
  503. package/.claude/skills/cfn-loop-orchestration/helpers/spawn-agents.sh +0 -290
  504. package/.claude/skills/cfn-loop-orchestration/helpers/timeout-calculator-ts.sh +0 -47
  505. package/.claude/skills/cfn-loop-orchestration/helpers/timeout-calculator.sh +0 -51
  506. package/.claude/skills/cfn-loop-orchestration/orchestrate.sh +0 -1345
  507. package/.claude/skills/cfn-redis-coordination/AGENT_LOGGING.md +0 -280
  508. package/.claude/skills/cfn-redis-coordination/BZPOPMIN_FIX_SUMMARY.md +0 -209
  509. package/.claude/skills/cfn-redis-coordination/CENTRALIZED_REDIS_WRAPPER.md +0 -319
  510. package/.claude/skills/cfn-redis-coordination/agent-log.sh.bak +0 -124
  511. package/.claude/skills/cfn-redis-coordination/config.json +0 -61
  512. package/.claude/skills/cfn-redis-coordination/demos/phase4-wake-queue-test-report.md +0 -82
  513. package/.claude/skills/cfn-redis-coordination/demos/test-bzpopmin-fix.sh +0 -274
  514. package/.claude/skills/cfn-redis-coordination/demos/test-cancel-swarm.sh +0 -0
  515. package/.claude/skills/cfn-redis-coordination/docs/migration/PHASE_3_REDIS_COORDINATION_COMPLETION_REPORT.md +0 -553
  516. package/.claude/skills/cfn-redis-coordination/jest.config.js +0 -23
  517. package/.claude/skills/cfn-redis-coordination/package-lock.json +0 -5272
  518. package/.claude/skills/cfn-redis-coordination/package.json +0 -45
  519. package/.claude/skills/cfn-redis-coordination/src/agent-logger.ts +0 -446
  520. package/.claude/skills/cfn-redis-coordination/src/agent-recovery.ts +0 -454
  521. package/.claude/skills/cfn-redis-coordination/src/completion-reporter.ts +0 -396
  522. package/.claude/skills/cfn-redis-coordination/src/context-manager.ts +0 -327
  523. package/.claude/skills/cfn-redis-coordination/src/index.ts +0 -82
  524. package/.claude/skills/cfn-redis-coordination/src/mode-detector.ts +0 -155
  525. package/.claude/skills/cfn-redis-coordination/src/redis/redis-client.ts +0 -305
  526. package/.claude/skills/cfn-redis-coordination/src/redis/redis-functions.ts +0 -283
  527. package/.claude/skills/cfn-redis-coordination/src/redis-client.ts +0 -654
  528. package/.claude/skills/cfn-redis-coordination/src/result-collector.ts +0 -437
  529. package/.claude/skills/cfn-redis-coordination/src/swarm-manager.ts +0 -494
  530. package/.claude/skills/cfn-redis-coordination/src/task-analyzer.ts +0 -404
  531. package/.claude/skills/cfn-redis-coordination/src/task-executor.ts +0 -423
  532. package/.claude/skills/cfn-redis-coordination/src/types.ts +0 -235
  533. package/.claude/skills/cfn-redis-coordination/src/waiting-coordinator.ts +0 -587
  534. package/.claude/skills/cfn-redis-coordination/store-success-criteria.sh +0 -85
  535. package/.claude/skills/cfn-redis-coordination/test-connection-attempts.js +0 -70
  536. package/.claude/skills/cfn-redis-coordination/test-mode-simple.js +0 -121
  537. package/.claude/skills/cfn-redis-coordination/test-redis-check.js +0 -84
  538. package/.claude/skills/cfn-redis-coordination/test-task-mode-redis.cjs +0 -391
  539. package/.claude/skills/cfn-redis-coordination/tests/coordination.test.ts +0 -788
  540. package/.claude/skills/cfn-redis-coordination/update-all-scripts.sh +0 -67
  541. package/claude-assets/agents/cfn-dev-team/coordinators/cfn-v3-coordinator.md +0 -976
  542. package/claude-assets/agents/typescript-specialist.md +0 -280
  543. package/claude-assets/skills/cfn-docker-redis-coordination/MIGRATION_SUMMARY.md +0 -348
  544. package/claude-assets/skills/cfn-docker-redis-coordination/README.md +0 -294
  545. package/claude-assets/skills/cfn-docker-redis-coordination/SKILL.md +0 -435
  546. package/claude-assets/skills/cfn-docker-redis-coordination/coordinate.sh +0 -650
  547. package/claude-assets/skills/cfn-docker-redis-coordination/coordinate.sh.backup-1763145142 +0 -641
  548. package/claude-assets/skills/cfn-docker-redis-coordination/jest.config.js +0 -37
  549. package/claude-assets/skills/cfn-docker-redis-coordination/package-lock.json +0 -5259
  550. package/claude-assets/skills/cfn-docker-redis-coordination/package.json +0 -40
  551. package/claude-assets/skills/cfn-docker-redis-coordination/src/coordinator.ts +0 -801
  552. package/claude-assets/skills/cfn-docker-redis-coordination/src/index.ts +0 -42
  553. package/claude-assets/skills/cfn-docker-redis-coordination/src/types.ts +0 -351
  554. package/claude-assets/skills/cfn-docker-redis-coordination/tests/coordinator.test.ts +0 -1464
  555. package/claude-assets/skills/cfn-loop-orchestration/helpers/auto-tune-timeouts.sh +0 -228
  556. package/claude-assets/skills/cfn-loop-orchestration/helpers/consensus-ts.sh +0 -104
  557. package/claude-assets/skills/cfn-loop-orchestration/helpers/consensus.sh +0 -94
  558. package/claude-assets/skills/cfn-loop-orchestration/helpers/context-injection.sh +0 -142
  559. package/claude-assets/skills/cfn-loop-orchestration/helpers/context-lookup.sh +0 -359
  560. package/claude-assets/skills/cfn-loop-orchestration/helpers/deliverable-verifier-ts.sh +0 -123
  561. package/claude-assets/skills/cfn-loop-orchestration/helpers/deliverable-verifier.sh +0 -71
  562. package/claude-assets/skills/cfn-loop-orchestration/helpers/gate-check.sh +0 -56
  563. package/claude-assets/skills/cfn-loop-orchestration/helpers/iteration-manager-ts.sh +0 -89
  564. package/claude-assets/skills/cfn-loop-orchestration/helpers/iteration-manager.sh +0 -87
  565. package/claude-assets/skills/cfn-loop-orchestration/helpers/orchestrate-ts.sh +0 -104
  566. package/claude-assets/skills/cfn-loop-orchestration/helpers/parse-test-results.sh +0 -56
  567. package/claude-assets/skills/cfn-loop-orchestration/helpers/spawn-agents.sh +0 -290
  568. package/claude-assets/skills/cfn-loop-orchestration/helpers/timeout-calculator-ts.sh +0 -47
  569. package/claude-assets/skills/cfn-loop-orchestration/helpers/timeout-calculator.sh +0 -51
  570. package/claude-assets/skills/cfn-loop-orchestration/orchestrate.sh +0 -1345
  571. package/claude-assets/skills/cfn-redis-cleanup/cleanup-redis.sh +0 -130
  572. package/claude-assets/skills/cfn-redis-coordination/AGENT_LOGGING.md +0 -280
  573. package/claude-assets/skills/cfn-redis-coordination/BZPOPMIN_FIX_SUMMARY.md +0 -209
  574. package/claude-assets/skills/cfn-redis-coordination/CENTRALIZED_REDIS_WRAPPER.md +0 -319
  575. package/claude-assets/skills/cfn-redis-coordination/agent-log.sh.bak +0 -124
  576. package/claude-assets/skills/cfn-redis-coordination/config.json +0 -61
  577. package/claude-assets/skills/cfn-redis-coordination/demos/phase4-wake-queue-test-report.md +0 -82
  578. package/claude-assets/skills/cfn-redis-coordination/demos/test-bzpopmin-fix.sh +0 -274
  579. package/claude-assets/skills/cfn-redis-coordination/demos/test-cancel-swarm.sh +0 -0
  580. package/claude-assets/skills/cfn-redis-coordination/docs/migration/PHASE_3_REDIS_COORDINATION_COMPLETION_REPORT.md +0 -553
  581. package/claude-assets/skills/cfn-redis-coordination/jest.config.js +0 -23
  582. package/claude-assets/skills/cfn-redis-coordination/package-lock.json +0 -5272
  583. package/claude-assets/skills/cfn-redis-coordination/package.json +0 -45
  584. package/claude-assets/skills/cfn-redis-coordination/src/agent-logger.ts +0 -446
  585. package/claude-assets/skills/cfn-redis-coordination/src/agent-recovery.ts +0 -454
  586. package/claude-assets/skills/cfn-redis-coordination/src/completion-reporter.ts +0 -396
  587. package/claude-assets/skills/cfn-redis-coordination/src/context-manager.ts +0 -327
  588. package/claude-assets/skills/cfn-redis-coordination/src/index.ts +0 -82
  589. package/claude-assets/skills/cfn-redis-coordination/src/mode-detector.ts +0 -155
  590. package/claude-assets/skills/cfn-redis-coordination/src/redis/redis-client.ts +0 -305
  591. package/claude-assets/skills/cfn-redis-coordination/src/redis/redis-functions.ts +0 -283
  592. package/claude-assets/skills/cfn-redis-coordination/src/redis-client.ts +0 -654
  593. package/claude-assets/skills/cfn-redis-coordination/src/result-collector.ts +0 -437
  594. package/claude-assets/skills/cfn-redis-coordination/src/swarm-manager.ts +0 -494
  595. package/claude-assets/skills/cfn-redis-coordination/src/task-analyzer.ts +0 -404
  596. package/claude-assets/skills/cfn-redis-coordination/src/task-executor.ts +0 -423
  597. package/claude-assets/skills/cfn-redis-coordination/src/types.ts +0 -235
  598. package/claude-assets/skills/cfn-redis-coordination/src/waiting-coordinator.ts +0 -587
  599. package/claude-assets/skills/cfn-redis-coordination/store-success-criteria.sh +0 -85
  600. package/claude-assets/skills/cfn-redis-coordination/test-connection-attempts.js +0 -70
  601. package/claude-assets/skills/cfn-redis-coordination/test-mode-simple.js +0 -121
  602. package/claude-assets/skills/cfn-redis-coordination/test-redis-check.js +0 -84
  603. package/claude-assets/skills/cfn-redis-coordination/test-task-mode-redis.cjs +0 -391
  604. package/claude-assets/skills/cfn-redis-coordination/tests/coordination.test.ts +0 -788
  605. package/claude-assets/skills/cfn-redis-coordination/update-all-scripts.sh +0 -67
  606. package/claude-assets/skills/cfn-redis-data-extraction/SKILL.md +0 -442
  607. package/claude-assets/skills/cfn-redis-data-extraction/extract.sh +0 -306
  608. package/dist/coordination/index.js +0 -25
  609. package/dist/coordination/index.js.map +0 -1
  610. package/docs/BUG_19_MEMORY_LEAK_TASK_MODE.md +0 -405
  611. package/docs/MEMORY_CLEANUP_GUIDE.md +0 -358
  612. package/docs/MEMORY_LEAK_FIX_SUMMARY.md +0 -322
  613. package/docs/REDIS_CLEANUP_EXECUTIVE_SUMMARY.md +0 -319
  614. package/docs/REDIS_CLEANUP_VERIFICATION_REPORT.md +0 -574
  615. /package/.claude/skills/cfn-loop-orchestration/{inject-loop-context.sh → archive/legacy-bash/inject-loop-context.sh} +0 -0
  616. /package/.claude/skills/cfn-loop-orchestration/{monitor-execution.sh → archive/legacy-bash/monitor-execution.sh} +0 -0
  617. /package/.claude/skills/cfn-redis-coordination/{agent-log.sh → agent-log.sh.backup} +0 -0
  618. /package/.claude/skills/cfn-redis-coordination/{agent-recovery.sh → agent-recovery.sh.backup} +0 -0
  619. /package/.claude/skills/cfn-redis-coordination/{analyze-task-complexity.sh → analyze-task-complexity.sh.backup} +0 -0
  620. /package/.claude/skills/cfn-redis-coordination/bash-wrappers/{store-context.sh → store-context.sh.backup} +0 -0
  621. /package/.claude/skills/cfn-redis-coordination/{cancel-swarm.sh → cancel-swarm.sh.backup} +0 -0
  622. /package/.claude/skills/cfn-redis-coordination/{cfn-loop-exec.sh → cfn-loop-exec.sh.backup} +0 -0
  623. /package/.claude/skills/cfn-redis-coordination/{cfn-loop-relaunch.sh → cfn-loop-relaunch.sh.backup} +0 -0
  624. /package/.claude/skills/cfn-redis-coordination/{collect-confidence-scores.sh → collect-confidence-scores.sh.backup} +0 -0
  625. /package/.claude/skills/cfn-redis-coordination/{collect-results.sh → collect-results.sh.backup} +0 -0
  626. /package/.claude/skills/cfn-redis-coordination/{complete-swarm.sh → complete-swarm.sh.backup} +0 -0
  627. /package/.claude/skills/cfn-redis-coordination/{get-context.sh → get-context.sh.backup} +0 -0
  628. /package/.claude/skills/cfn-redis-coordination/{get-success-criteria.sh → get-success-criteria.sh.backup} +0 -0
  629. /package/.claude/skills/cfn-redis-coordination/{invoke-waiting-mode.sh → invoke-waiting-mode.sh.backup} +0 -0
  630. /package/.claude/skills/cfn-redis-coordination/{redis-cli-wrapper.sh → redis-cli-wrapper.sh.backup} +0 -0
  631. /package/.claude/skills/cfn-redis-coordination/{redis-functions.sh → redis-functions.sh.backup} +0 -0
  632. /package/.claude/skills/cfn-redis-coordination/{report-completion.sh → report-completion.sh.backup} +0 -0
  633. /package/.claude/skills/cfn-redis-coordination/{store-context.sh → store-context.sh.backup} +0 -0
  634. /package/claude-assets/skills/cfn-loop-orchestration/{inject-loop-context.sh → archive/legacy-bash/inject-loop-context.sh} +0 -0
  635. /package/claude-assets/skills/cfn-loop-orchestration/{monitor-execution.sh → archive/legacy-bash/monitor-execution.sh} +0 -0
  636. /package/claude-assets/skills/cfn-redis-coordination/{agent-log.sh → agent-log.sh.backup} +0 -0
  637. /package/claude-assets/skills/cfn-redis-coordination/{agent-recovery.sh → agent-recovery.sh.backup} +0 -0
  638. /package/claude-assets/skills/cfn-redis-coordination/{analyze-task-complexity.sh → analyze-task-complexity.sh.backup} +0 -0
  639. /package/claude-assets/skills/cfn-redis-coordination/bash-wrappers/{store-context.sh → store-context.sh.backup} +0 -0
  640. /package/claude-assets/skills/cfn-redis-coordination/{cancel-swarm.sh → cancel-swarm.sh.backup} +0 -0
  641. /package/claude-assets/skills/cfn-redis-coordination/{cfn-loop-exec.sh → cfn-loop-exec.sh.backup} +0 -0
  642. /package/claude-assets/skills/cfn-redis-coordination/{cfn-loop-relaunch.sh → cfn-loop-relaunch.sh.backup} +0 -0
  643. /package/claude-assets/skills/cfn-redis-coordination/{collect-confidence-scores.sh → collect-confidence-scores.sh.backup} +0 -0
  644. /package/claude-assets/skills/cfn-redis-coordination/{collect-results.sh → collect-results.sh.backup} +0 -0
  645. /package/claude-assets/skills/cfn-redis-coordination/{complete-swarm.sh → complete-swarm.sh.backup} +0 -0
  646. /package/claude-assets/skills/cfn-redis-coordination/{get-context.sh → get-context.sh.backup} +0 -0
  647. /package/claude-assets/skills/cfn-redis-coordination/{get-success-criteria.sh → get-success-criteria.sh.backup} +0 -0
  648. /package/claude-assets/skills/cfn-redis-coordination/{invoke-waiting-mode.sh → invoke-waiting-mode.sh.backup} +0 -0
  649. /package/claude-assets/skills/cfn-redis-coordination/{redis-cli-wrapper.sh → redis-cli-wrapper.sh.backup} +0 -0
  650. /package/claude-assets/skills/cfn-redis-coordination/{redis-functions.sh → redis-functions.sh.backup} +0 -0
  651. /package/claude-assets/skills/cfn-redis-coordination/{report-completion.sh → report-completion.sh.backup} +0 -0
  652. /package/claude-assets/skills/cfn-redis-coordination/{store-context.sh → store-context.sh.backup} +0 -0
@@ -1 +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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"}
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, StandardError } 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 // Re-throw duplicate errors without wrapping\r\n if (error instanceof StandardError && error.code === ErrorCode.DB_DUPLICATE_KEY) {\r\n throw error;\r\n }\r\n\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","StandardError","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","code","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,317 @@
1
+ /**
2
+ * Authentication Middleware
3
+ *
4
+ * Comprehensive authentication and authorization middleware for Express.js
5
+ * with JWT token validation, role-based access control, and security features.
6
+ */ import jwt from 'jsonwebtoken';
7
+ import bcrypt from 'bcrypt';
8
+ import { logger } from '../utils/logger.js';
9
+ import { StandardError, ErrorCode } from '../../lib/errors.js';
10
+ /**
11
+ * Authentication middleware that validates JWT tokens
12
+ *
13
+ * @param config Authentication configuration
14
+ * @returns Express middleware function
15
+ */ export function authenticationMiddleware(config) {
16
+ return async (req, res, next)=>{
17
+ try {
18
+ // Check for authorization header
19
+ const authHeader = req.headers.authorization;
20
+ if (!authHeader) {
21
+ res.status(401).json({
22
+ error: 'Unauthorized',
23
+ message: 'No authorization header provided',
24
+ errorCode: 'AUTH_001'
25
+ });
26
+ return;
27
+ }
28
+ // Validate authorization header format
29
+ if (!authHeader.startsWith('Bearer ')) {
30
+ res.status(401).json({
31
+ error: 'Unauthorized',
32
+ message: 'Invalid authorization header format',
33
+ errorCode: 'AUTH_003'
34
+ });
35
+ return;
36
+ }
37
+ // Extract and sanitize token
38
+ const token = authHeader.slice(7).trim();
39
+ if (!token) {
40
+ res.status(401).json({
41
+ error: 'Unauthorized',
42
+ message: 'No token provided',
43
+ errorCode: 'AUTH_005'
44
+ });
45
+ return;
46
+ }
47
+ // Verify JWT token
48
+ let decoded;
49
+ try {
50
+ decoded = jwt.verify(token, config.jwtSecret);
51
+ } catch (error) {
52
+ // Handle specific JWT errors
53
+ if (error instanceof jwt.TokenExpiredError) {
54
+ res.status(401).json({
55
+ error: 'Unauthorized',
56
+ message: 'Token has expired',
57
+ errorCode: 'AUTH_004'
58
+ });
59
+ return;
60
+ } else if (error instanceof jwt.JsonWebTokenError) {
61
+ res.status(401).json({
62
+ error: 'Unauthorized',
63
+ message: 'Invalid or expired token',
64
+ errorCode: 'AUTH_002'
65
+ });
66
+ return;
67
+ } else {
68
+ logger.error('Unexpected JWT verification error:', error);
69
+ res.status(401).json({
70
+ error: 'Unauthorized',
71
+ message: 'Token verification failed',
72
+ errorCode: 'AUTH_006'
73
+ });
74
+ return;
75
+ }
76
+ }
77
+ // Attach user information to request
78
+ req.user = {
79
+ userId: decoded.userId,
80
+ email: decoded.email,
81
+ role: decoded.role,
82
+ iat: decoded.iat,
83
+ exp: decoded.exp
84
+ };
85
+ // Log successful authentication
86
+ logger.info(`User authenticated: ${decoded.userId} (${decoded.email})`, {
87
+ userId: decoded.userId,
88
+ role: decoded.role,
89
+ ip: req.ip,
90
+ userAgent: req.headers['user-agent']
91
+ });
92
+ next();
93
+ } catch (error) {
94
+ logger.error('Authentication middleware error:', error);
95
+ res.status(500).json({
96
+ error: 'Internal Server Error',
97
+ message: 'Authentication service unavailable',
98
+ errorCode: 'AUTH_500'
99
+ });
100
+ }
101
+ };
102
+ }
103
+ /**
104
+ * Authorization middleware for role-based access control
105
+ *
106
+ * @param requiredRoles Array of roles that are allowed to access the resource
107
+ * @returns Express middleware function
108
+ */ export function authorizationMiddleware(requiredRoles) {
109
+ return (req, res, next)=>{
110
+ try {
111
+ // Check if user is authenticated
112
+ if (!req.user) {
113
+ res.status(401).json({
114
+ error: 'Unauthorized',
115
+ message: 'User not authenticated'
116
+ });
117
+ return;
118
+ }
119
+ // Check if user has required role
120
+ if (!requiredRoles.includes(req.user.role)) {
121
+ res.status(403).json({
122
+ error: 'Forbidden',
123
+ message: 'Insufficient permissions',
124
+ requiredRoles,
125
+ userRole: req.user.role
126
+ });
127
+ return;
128
+ }
129
+ // Log successful authorization
130
+ logger.info(`User authorized: ${req.user.userId} (${req.user.role})`, {
131
+ userId: req.user.userId,
132
+ role: req.user.role,
133
+ requiredRoles
134
+ });
135
+ next();
136
+ } catch (error) {
137
+ logger.error('Authorization middleware error:', error);
138
+ res.status(500).json({
139
+ error: 'Internal Server Error',
140
+ message: 'Authorization service unavailable'
141
+ });
142
+ }
143
+ };
144
+ }
145
+ /**
146
+ * Password utilities for secure password handling
147
+ */ export class PasswordUtils {
148
+ /**
149
+ * Hash a password using bcrypt
150
+ *
151
+ * @param password Plain text password
152
+ * @param rounds Number of bcrypt rounds (default 12)
153
+ * @returns Hashed password
154
+ */ static async hashPassword(password, rounds = 12) {
155
+ try {
156
+ return await bcrypt.hash(password, rounds);
157
+ } catch (error) {
158
+ logger.error('Password hashing error:', error);
159
+ throw new StandardError('Failed to hash password', ErrorCode.INTERNAL_ERROR);
160
+ }
161
+ }
162
+ /**
163
+ * Generate salt for password hashing
164
+ *
165
+ * @param rounds Number of bcrypt rounds (default 12)
166
+ * @returns Salt string
167
+ */ static async generateSalt(rounds = 12) {
168
+ try {
169
+ return await bcrypt.genSalt(rounds);
170
+ } catch (error) {
171
+ logger.error('Salt generation error:', error);
172
+ throw new StandardError('Failed to generate salt', ErrorCode.INTERNAL_ERROR);
173
+ }
174
+ }
175
+ /**
176
+ * Compare a plain text password with a hash
177
+ *
178
+ * @param password Plain text password
179
+ * @param hash Hashed password
180
+ * @returns True if passwords match
181
+ */ static async comparePassword(password, hash) {
182
+ try {
183
+ return await bcrypt.compare(password, hash);
184
+ } catch (error) {
185
+ logger.error('Password comparison error:', error);
186
+ throw new StandardError('Failed to compare passwords', ErrorCode.INTERNAL_ERROR);
187
+ }
188
+ }
189
+ /**
190
+ * Validate password strength
191
+ *
192
+ * @param password Password to validate
193
+ * @returns True if password meets strength requirements
194
+ */ static validatePasswordStrength(password) {
195
+ // Minimum 8 characters, at least one uppercase, one lowercase, one number, and one special character
196
+ const minLength = 8;
197
+ const hasUpperCase = /[A-Z]/.test(password);
198
+ const hasLowerCase = /[a-z]/.test(password);
199
+ const hasNumbers = /\d/.test(password);
200
+ const hasSpecialChar = /[!@#$%^&*(),.?":{}|<>]/.test(password);
201
+ return password.length >= minLength && hasUpperCase && hasLowerCase && hasNumbers && hasSpecialChar;
202
+ }
203
+ }
204
+ /**
205
+ * JWT utilities for token management
206
+ */ export class JWTUtils {
207
+ /**
208
+ * Generate a JWT token
209
+ *
210
+ * @param payload Token payload
211
+ * @param secret JWT secret
212
+ * @param expiresIn Token expiration time
213
+ * @returns JWT token
214
+ */ static generateToken(payload, secret, expiresIn = '24h') {
215
+ try {
216
+ return jwt.sign(payload, secret, {
217
+ expiresIn
218
+ });
219
+ } catch (error) {
220
+ logger.error('Token generation error:', error);
221
+ throw new StandardError('Failed to generate token', ErrorCode.INTERNAL_ERROR);
222
+ }
223
+ }
224
+ /**
225
+ * Verify a JWT token
226
+ *
227
+ * @param token JWT token
228
+ * @param secret JWT secret
229
+ * @returns Decoded payload
230
+ */ static verifyToken(token, secret) {
231
+ try {
232
+ return jwt.verify(token, secret);
233
+ } catch (error) {
234
+ if (error instanceof jwt.TokenExpiredError) {
235
+ throw new StandardError('Token has expired', ErrorCode.TOKEN_EXPIRED);
236
+ } else if (error instanceof jwt.JsonWebTokenError) {
237
+ throw new StandardError('Invalid token', ErrorCode.INVALID_TOKEN);
238
+ } else {
239
+ throw new StandardError('Token verification failed', ErrorCode.INTERNAL_ERROR);
240
+ }
241
+ }
242
+ }
243
+ /**
244
+ * Decode a JWT token without verification (for debugging)
245
+ *
246
+ * @param token JWT token
247
+ * @returns Decoded payload
248
+ */ static decodeToken(token) {
249
+ try {
250
+ return jwt.decode(token);
251
+ } catch (error) {
252
+ logger.error('Token decoding error:', error);
253
+ return null;
254
+ }
255
+ }
256
+ }
257
+ /**
258
+ * Rate limiting utilities for authentication endpoints
259
+ */ export class AuthRateLimit {
260
+ static attempts = new Map();
261
+ /**
262
+ * Check if user has exceeded login attempts
263
+ *
264
+ * @param identifier User identifier (email, IP, etc.)
265
+ * @param maxAttempts Maximum allowed attempts
266
+ * @param windowMs Time window in milliseconds
267
+ * @returns True if attempts exceeded
268
+ */ static hasExceededAttempts(identifier, maxAttempts = 5, windowMs = 15 * 60 * 1000 // 15 minutes
269
+ ) {
270
+ const now = Date.now();
271
+ const attempts = this.attempts.get(identifier);
272
+ if (!attempts) {
273
+ this.attempts.set(identifier, {
274
+ count: 1,
275
+ lastAttempt: now
276
+ });
277
+ return false;
278
+ }
279
+ // Reset if window has expired
280
+ if (now - attempts.lastAttempt > windowMs) {
281
+ this.attempts.set(identifier, {
282
+ count: 1,
283
+ lastAttempt: now
284
+ });
285
+ return false;
286
+ }
287
+ // Increment attempts
288
+ attempts.count++;
289
+ attempts.lastAttempt = now;
290
+ // Check if exceeded
291
+ if (attempts.count > maxAttempts) {
292
+ logger.warn(`Login attempts exceeded for ${identifier}`, {
293
+ identifier,
294
+ attempts: attempts.count,
295
+ windowMs
296
+ });
297
+ return true;
298
+ }
299
+ return false;
300
+ }
301
+ /**
302
+ * Clear failed attempts for a user
303
+ *
304
+ * @param identifier User identifier
305
+ */ static clearAttempts(identifier) {
306
+ this.attempts.delete(identifier);
307
+ }
308
+ }
309
+ export default {
310
+ authenticationMiddleware,
311
+ authorizationMiddleware,
312
+ PasswordUtils,
313
+ JWTUtils,
314
+ AuthRateLimit
315
+ };
316
+
317
+ //# sourceMappingURL=authentication.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/middleware/authentication.ts"],"sourcesContent":["/**\r\n * Authentication Middleware\r\n * \r\n * Comprehensive authentication and authorization middleware for Express.js\r\n * with JWT token validation, role-based access control, and security features.\r\n */\r\n\r\nimport { Request, Response, NextFunction } from 'express';\r\nimport jwt from 'jsonwebtoken';\r\nimport bcrypt from 'bcrypt';\r\nimport { logger } from '../utils/logger.js';\r\nimport { StandardError, ErrorCode } from '../../lib/errors.js';\r\n\r\n// Extend Express Request type to include user\r\ndeclare global {\r\n namespace Express {\r\n interface Request {\r\n user?: {\r\n userId: string;\r\n email: string;\r\n role: string;\r\n iat?: number;\r\n exp?: number;\r\n };\r\n }\r\n }\r\n}\r\n\r\nexport interface AuthConfig {\r\n jwtSecret: string;\r\n jwtExpiration: string;\r\n bcryptRounds: number;\r\n}\r\n\r\nexport interface JWTPayload {\r\n userId: string;\r\n email: string;\r\n role: string;\r\n iat?: number;\r\n exp?: number;\r\n}\r\n\r\n/**\r\n * Authentication middleware that validates JWT tokens\r\n * \r\n * @param config Authentication configuration\r\n * @returns Express middleware function\r\n */\r\nexport function authenticationMiddleware(config: AuthConfig) {\r\n return async (req: Request, res: Response, next: NextFunction): Promise<void> => {\r\n try {\r\n // Check for authorization header\r\n const authHeader = req.headers.authorization;\r\n if (!authHeader) {\r\n res.status(401).json({\r\n error: 'Unauthorized',\r\n message: 'No authorization header provided',\r\n errorCode: 'AUTH_001',\r\n });\r\n return;\r\n }\r\n\r\n // Validate authorization header format\r\n if (!authHeader.startsWith('Bearer ')) {\r\n res.status(401).json({\r\n error: 'Unauthorized',\r\n message: 'Invalid authorization header format',\r\n errorCode: 'AUTH_003',\r\n });\r\n return;\r\n }\r\n\r\n // Extract and sanitize token\r\n const token = authHeader.slice(7).trim();\r\n if (!token) {\r\n res.status(401).json({\r\n error: 'Unauthorized',\r\n message: 'No token provided',\r\n errorCode: 'AUTH_005',\r\n });\r\n return;\r\n }\r\n\r\n // Verify JWT token\r\n let decoded: JWTPayload;\r\n try {\r\n decoded = jwt.verify(token, config.jwtSecret) as JWTPayload;\r\n } catch (error) {\r\n // Handle specific JWT errors\r\n if (error instanceof jwt.TokenExpiredError) {\r\n res.status(401).json({\r\n error: 'Unauthorized',\r\n message: 'Token has expired',\r\n errorCode: 'AUTH_004',\r\n });\r\n return;\r\n } else if (error instanceof jwt.JsonWebTokenError) {\r\n res.status(401).json({\r\n error: 'Unauthorized',\r\n message: 'Invalid or expired token',\r\n errorCode: 'AUTH_002',\r\n });\r\n return;\r\n } else {\r\n logger.error('Unexpected JWT verification error:', error);\r\n res.status(401).json({\r\n error: 'Unauthorized',\r\n message: 'Token verification failed',\r\n errorCode: 'AUTH_006',\r\n });\r\n return;\r\n }\r\n }\r\n\r\n // Attach user information to request\r\n req.user = {\r\n userId: decoded.userId,\r\n email: decoded.email,\r\n role: decoded.role,\r\n iat: decoded.iat,\r\n exp: decoded.exp,\r\n };\r\n\r\n // Log successful authentication\r\n logger.info(`User authenticated: ${decoded.userId} (${decoded.email})`, {\r\n userId: decoded.userId,\r\n role: decoded.role,\r\n ip: req.ip,\r\n userAgent: req.headers['user-agent'],\r\n });\r\n\r\n next();\r\n } catch (error) {\r\n logger.error('Authentication middleware error:', error);\r\n res.status(500).json({\r\n error: 'Internal Server Error',\r\n message: 'Authentication service unavailable',\r\n errorCode: 'AUTH_500',\r\n });\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Authorization middleware for role-based access control\r\n * \r\n * @param requiredRoles Array of roles that are allowed to access the resource\r\n * @returns Express middleware function\r\n */\r\nexport function authorizationMiddleware(requiredRoles: string[]) {\r\n return (req: Request, res: Response, next: NextFunction): void => {\r\n try {\r\n // Check if user is authenticated\r\n if (!req.user) {\r\n res.status(401).json({\r\n error: 'Unauthorized',\r\n message: 'User not authenticated',\r\n });\r\n return;\r\n }\r\n\r\n // Check if user has required role\r\n if (!requiredRoles.includes(req.user.role)) {\r\n res.status(403).json({\r\n error: 'Forbidden',\r\n message: 'Insufficient permissions',\r\n requiredRoles,\r\n userRole: req.user.role,\r\n });\r\n return;\r\n }\r\n\r\n // Log successful authorization\r\n logger.info(`User authorized: ${req.user.userId} (${req.user.role})`, {\r\n userId: req.user.userId,\r\n role: req.user.role,\r\n requiredRoles,\r\n });\r\n\r\n next();\r\n } catch (error) {\r\n logger.error('Authorization middleware error:', error);\r\n res.status(500).json({\r\n error: 'Internal Server Error',\r\n message: 'Authorization service unavailable',\r\n });\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Password utilities for secure password handling\r\n */\r\nexport class PasswordUtils {\r\n /**\r\n * Hash a password using bcrypt\r\n * \r\n * @param password Plain text password\r\n * @param rounds Number of bcrypt rounds (default 12)\r\n * @returns Hashed password\r\n */\r\n static async hashPassword(password: string, rounds: number = 12): Promise<string> {\r\n try {\r\n return await bcrypt.hash(password, rounds);\r\n } catch (error) {\r\n logger.error('Password hashing error:', error);\r\n throw new StandardError('Failed to hash password', ErrorCode.INTERNAL_ERROR);\r\n }\r\n }\r\n\r\n /**\r\n * Generate salt for password hashing\r\n * \r\n * @param rounds Number of bcrypt rounds (default 12)\r\n * @returns Salt string\r\n */\r\n static async generateSalt(rounds: number = 12): Promise<string> {\r\n try {\r\n return await bcrypt.genSalt(rounds);\r\n } catch (error) {\r\n logger.error('Salt generation error:', error);\r\n throw new StandardError('Failed to generate salt', ErrorCode.INTERNAL_ERROR);\r\n }\r\n }\r\n\r\n /**\r\n * Compare a plain text password with a hash\r\n * \r\n * @param password Plain text password\r\n * @param hash Hashed password\r\n * @returns True if passwords match\r\n */\r\n static async comparePassword(password: string, hash: string): Promise<boolean> {\r\n try {\r\n return await bcrypt.compare(password, hash);\r\n } catch (error) {\r\n logger.error('Password comparison error:', error);\r\n throw new StandardError('Failed to compare passwords', ErrorCode.INTERNAL_ERROR);\r\n }\r\n }\r\n\r\n /**\r\n * Validate password strength\r\n * \r\n * @param password Password to validate\r\n * @returns True if password meets strength requirements\r\n */\r\n static validatePasswordStrength(password: string): boolean {\r\n // Minimum 8 characters, at least one uppercase, one lowercase, one number, and one special character\r\n const minLength = 8;\r\n const hasUpperCase = /[A-Z]/.test(password);\r\n const hasLowerCase = /[a-z]/.test(password);\r\n const hasNumbers = /\\d/.test(password);\r\n const hasSpecialChar = /[!@#$%^&*(),.?\":{}|<>]/.test(password);\r\n\r\n return (\r\n password.length >= minLength &&\r\n hasUpperCase &&\r\n hasLowerCase &&\r\n hasNumbers &&\r\n hasSpecialChar\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * JWT utilities for token management\r\n */\r\nexport class JWTUtils {\r\n /**\r\n * Generate a JWT token\r\n * \r\n * @param payload Token payload\r\n * @param secret JWT secret\r\n * @param expiresIn Token expiration time\r\n * @returns JWT token\r\n */\r\n static generateToken(\r\n payload: Omit<JWTPayload, 'iat' | 'exp'>,\r\n secret: string,\r\n expiresIn: string = '24h'\r\n ): string {\r\n try {\r\n return jwt.sign(payload, secret, { expiresIn });\r\n } catch (error) {\r\n logger.error('Token generation error:', error);\r\n throw new StandardError('Failed to generate token', ErrorCode.INTERNAL_ERROR);\r\n }\r\n }\r\n\r\n /**\r\n * Verify a JWT token\r\n * \r\n * @param token JWT token\r\n * @param secret JWT secret\r\n * @returns Decoded payload\r\n */\r\n static verifyToken(token: string, secret: string): JWTPayload {\r\n try {\r\n return jwt.verify(token, secret) as JWTPayload;\r\n } catch (error) {\r\n if (error instanceof jwt.TokenExpiredError) {\r\n throw new StandardError('Token has expired', ErrorCode.TOKEN_EXPIRED);\r\n } else if (error instanceof jwt.JsonWebTokenError) {\r\n throw new StandardError('Invalid token', ErrorCode.INVALID_TOKEN);\r\n } else {\r\n throw new StandardError('Token verification failed', ErrorCode.INTERNAL_ERROR);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Decode a JWT token without verification (for debugging)\r\n * \r\n * @param token JWT token\r\n * @returns Decoded payload\r\n */\r\n static decodeToken(token: string): JWTPayload | null {\r\n try {\r\n return jwt.decode(token) as JWTPayload;\r\n } catch (error) {\r\n logger.error('Token decoding error:', error);\r\n return null;\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Rate limiting utilities for authentication endpoints\r\n */\r\nexport class AuthRateLimit {\r\n private static attempts = new Map<string, { count: number; lastAttempt: number }>();\r\n\r\n /**\r\n * Check if user has exceeded login attempts\r\n * \r\n * @param identifier User identifier (email, IP, etc.)\r\n * @param maxAttempts Maximum allowed attempts\r\n * @param windowMs Time window in milliseconds\r\n * @returns True if attempts exceeded\r\n */\r\n static hasExceededAttempts(\r\n identifier: string,\r\n maxAttempts: number = 5,\r\n windowMs: number = 15 * 60 * 1000 // 15 minutes\r\n ): boolean {\r\n const now = Date.now();\r\n const attempts = this.attempts.get(identifier);\r\n\r\n if (!attempts) {\r\n this.attempts.set(identifier, { count: 1, lastAttempt: now });\r\n return false;\r\n }\r\n\r\n // Reset if window has expired\r\n if (now - attempts.lastAttempt > windowMs) {\r\n this.attempts.set(identifier, { count: 1, lastAttempt: now });\r\n return false;\r\n }\r\n\r\n // Increment attempts\r\n attempts.count++;\r\n attempts.lastAttempt = now;\r\n\r\n // Check if exceeded\r\n if (attempts.count > maxAttempts) {\r\n logger.warn(`Login attempts exceeded for ${identifier}`, {\r\n identifier,\r\n attempts: attempts.count,\r\n windowMs,\r\n });\r\n return true;\r\n }\r\n\r\n return false;\r\n }\r\n\r\n /**\r\n * Clear failed attempts for a user\r\n * \r\n * @param identifier User identifier\r\n */\r\n static clearAttempts(identifier: string): void {\r\n this.attempts.delete(identifier);\r\n }\r\n}\r\n\r\nexport default {\r\n authenticationMiddleware,\r\n authorizationMiddleware,\r\n PasswordUtils,\r\n JWTUtils,\r\n AuthRateLimit,\r\n};"],"names":["jwt","bcrypt","logger","StandardError","ErrorCode","authenticationMiddleware","config","req","res","next","authHeader","headers","authorization","status","json","error","message","errorCode","startsWith","token","slice","trim","decoded","verify","jwtSecret","TokenExpiredError","JsonWebTokenError","user","userId","email","role","iat","exp","info","ip","userAgent","authorizationMiddleware","requiredRoles","includes","userRole","PasswordUtils","hashPassword","password","rounds","hash","INTERNAL_ERROR","generateSalt","genSalt","comparePassword","compare","validatePasswordStrength","minLength","hasUpperCase","test","hasLowerCase","hasNumbers","hasSpecialChar","length","JWTUtils","generateToken","payload","secret","expiresIn","sign","verifyToken","TOKEN_EXPIRED","INVALID_TOKEN","decodeToken","decode","AuthRateLimit","attempts","Map","hasExceededAttempts","identifier","maxAttempts","windowMs","now","Date","get","set","count","lastAttempt","warn","clearAttempts","delete"],"mappings":"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"}