claude-flow-novice 2.15.2 → 2.15.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/cfn-extras/skills/advanced-features/cfn-agent-swap/recommend-swap.sh +59 -59
- package/.claude/cfn-extras/skills/analytics/cfn-improvement-recommender/recommend-improvements.sh +91 -91
- package/.claude/cfn-extras/skills/analytics/cfn-pattern-extraction/extract-patterns.sh +79 -79
- package/.claude/cfn-extras/skills/analytics/cfn-retrospective-report/generate-report.sh +100 -100
- package/.claude/cfn-extras/skills/analytics/cfn-telemetry/start-telemetry.sh +110 -110
- package/.claude/cfn-extras/skills/deprecated/cfn-ace-system/add-bullet.sh +145 -145
- package/.claude/cfn-extras/skills/deprecated/cfn-ace-system/log-merge.sh +67 -67
- package/.claude/cfn-extras/skills/deprecated/cfn-ace-system/monitor-injection-performance.sh +137 -137
- package/.claude/cfn-extras/skills/deprecated/cfn-ace-system/optimize-injection-pipeline.sh +168 -168
- package/.claude/cfn-extras/skills/deprecated/cfn-ace-system/query-reflections.sh +35 -35
- package/.claude/cfn-extras/skills/deprecated/cfn-ace-system/store-reflection.sh +45 -45
- package/.claude/cfn-extras/skills/deprecated/cfn-ace-system/track-ab-test.sh +41 -41
- package/.claude/cfn-extras/skills/deprecated/cfn-ace-system/update-reflection.sh +41 -41
- package/.claude/cfn-extras/skills/deprecated/cfn-cli-setup/validate-cli-environment.sh +191 -191
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-ad-campaigns/operations/create-campaign.sh +231 -231
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-ad-campaigns/operations/get-campaign-performance.sh +190 -190
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-ad-campaigns/operations/pause-campaign.sh +142 -142
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-ad-campaigns/operations/set-budget.sh +181 -181
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-ad-campaigns/operations/update-bid-strategy.sh +133 -133
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-chatbot-conversations/operations/get-conversation-history.sh +121 -121
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-chatbot-conversations/operations/qualify-lead.sh +156 -156
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-chatbot-conversations/operations/schedule-demo.sh +181 -181
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-chatbot-conversations/operations/send-message.sh +137 -137
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-chatbot-conversations/operations/transfer-to-human.sh +179 -179
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-sms-campaigns/operations/create-campaign.sh +183 -183
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-sms-campaigns/operations/get-delivery-status.sh +139 -139
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-sms-campaigns/operations/opt-out.sh +150 -150
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-sms-campaigns/operations/schedule-campaign.sh +187 -187
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-sms-campaigns/operations/send-sms.sh +181 -181
- package/.claude/cfn-extras/skills/ui-portal/cfn-web-portal/test-web-portal-skill.sh +50 -50
- package/.claude/cfn-extras/skills/ui-portal/cfn-web-portal/validate-deployment.sh +84 -84
- package/.claude/cfn-extras/skills/utility/cfn-environment-sanitization/sanitize-environment.sh +243 -243
- package/.claude/commands/cfn-loop-cli.md +16 -2
- package/.claude/commands/switch-api.md +31 -10
- package/.claude/hooks/cfn-BACKUP_USAGE.md +243 -243
- package/.claude/hooks/cfn-invoke-security-validation.sh +69 -69
- package/.claude/hooks/cfn-lint-sql-injection.sh +61 -0
- package/.claude/hooks/cfn-post-edit-cfn-retrospective.sh +109 -78
- package/.claude/hooks/cfn-post-edit.config.json +44 -44
- package/.claude/hooks/cfn-pre-edit-security-warning.sh +40 -0
- package/.claude/skills/cfn-agent-spawning/spawn-agent.sh +22 -24
- package/.claude/skills/cfn-docker-agent-spawning/SKILL.md +28 -4
- package/.claude/skills/cfn-docker-agent-spawning/spawn-agent.sh +3 -1
- package/.claude/skills/cfn-docker-loop-orchestration/orchestrate.sh +224 -20
- package/.claude/skills/cfn-hybrid-routing/check-dependencies.sh +51 -51
- package/.claude/skills/cfn-loop-orchestration/helpers/gate-check.sh +550 -46
- package/.claude/skills/cfn-loop-orchestration/helpers/parse-test-results.sh +277 -0
- package/.claude/skills/cfn-loop-orchestration/orchestrate.sh +184 -23
- package/.claude/skills/cfn-loop-orchestration/security_utils.sh +24 -0
- package/.claude/skills/cfn-loop-orchestration/test-iteration-context-injection.sh +366 -0
- package/.claude/skills/cfn-loop-validation/orchestrate-cfn-loop.sh +252 -252
- package/.claude/skills/cfn-redis-coordination/CENTRALIZED_REDIS_WRAPPER.md +319 -0
- package/.claude/skills/cfn-redis-coordination/agent-log.sh +4 -0
- package/.claude/skills/cfn-redis-coordination/agent-log.sh.bak +124 -0
- package/.claude/skills/cfn-redis-coordination/agent-recovery.sh +74 -74
- package/.claude/skills/cfn-redis-coordination/collect-confidence-scores.sh +30 -0
- package/.claude/skills/cfn-redis-coordination/get-context.sh +145 -112
- package/.claude/skills/cfn-redis-coordination/get-success-criteria.sh +54 -0
- package/.claude/skills/cfn-redis-coordination/invoke-waiting-mode.sh +3 -0
- package/.claude/skills/cfn-redis-coordination/redis-cli-wrapper.sh +24 -3
- package/.claude/skills/cfn-redis-coordination/redis-functions.sh +33 -0
- package/.claude/skills/cfn-redis-coordination/report-completion.sh +24 -31
- package/.claude/skills/cfn-redis-coordination/store-context.sh +4 -0
- package/.claude/skills/cfn-redis-coordination/store-success-criteria.sh +85 -0
- package/.claude/skills/cfn-redis-coordination/update-all-scripts.sh +67 -0
- package/.claude/skills/cfn-sqlite-memory/ttl-cleanup.sh +17 -25
- package/.claude/skills/cfn-transparency-middleware/middleware-config.sh +28 -28
- package/.claude/skills/cfn-transparency-middleware/performance-benchmark.sh +78 -78
- package/.claude/skills/cfn-transparency-middleware/test-e2e.sh +15 -0
- package/.claude/skills/cfn-transparency-middleware/test-integration.sh +161 -161
- package/.claude/skills/cfn-transparency-middleware/test-transparency-skill.sh +367 -367
- package/.claude/skills/cfn-transparency-middleware/tests/input-validation.sh +107 -92
- package/.claude/skills/cfn-transparency-middleware/wrap-agent.sh +131 -131
- package/README.md +116 -475
- package/claude-assets/agents/cfn-dev-team/README.md +103 -0
- package/claude-assets/agents/cfn-dev-team/architecture/goal-planner.md +1 -1
- package/claude-assets/agents/cfn-dev-team/coordinators/cfn-frontend-coordinator.md +77 -15
- package/claude-assets/agents/cfn-dev-team/coordinators/cfn-v3-coordinator.md +355 -6
- package/claude-assets/agents/cfn-dev-team/coordinators/consensus-builder.md +82 -1
- package/claude-assets/agents/cfn-dev-team/coordinators/handoff-coordinator.md +82 -1
- package/claude-assets/agents/cfn-dev-team/coordinators/multi-sprint-coordinator.md +77 -15
- package/claude-assets/agents/cfn-dev-team/dev-ops/docker-specialist.md +99 -12
- package/claude-assets/agents/cfn-dev-team/dev-ops/github-commit-agent.md +1 -1
- package/claude-assets/agents/cfn-dev-team/dev-ops/kubernetes-specialist.md +97 -0
- package/claude-assets/agents/cfn-dev-team/dev-ops/monitoring-specialist.md +20 -1
- package/claude-assets/agents/cfn-dev-team/developers/api-gateway-specialist.md +97 -0
- package/claude-assets/agents/cfn-dev-team/developers/backend-developer.md +110 -13
- package/claude-assets/agents/cfn-dev-team/developers/data/data-engineer.md +106 -15
- package/claude-assets/agents/cfn-dev-team/developers/database/database-architect.md +115 -11
- package/claude-assets/agents/cfn-dev-team/developers/frontend/mobile-dev.md +94 -7
- package/claude-assets/agents/cfn-dev-team/developers/frontend/react-frontend-engineer.md +87 -9
- package/claude-assets/agents/cfn-dev-team/developers/frontend/typescript-specialist.md +85 -7
- package/claude-assets/agents/cfn-dev-team/developers/frontend/ui-designer.md +160 -28
- package/claude-assets/agents/cfn-dev-team/developers/graphql-specialist.md +101 -19
- package/claude-assets/agents/cfn-dev-team/developers/rust-developer.md +108 -14
- package/claude-assets/agents/cfn-dev-team/reviewers/{reviewer.md → code-reviewer.md} +95 -8
- package/claude-assets/agents/cfn-dev-team/reviewers/quality/code-quality-validator.md +107 -7
- package/claude-assets/agents/cfn-dev-team/reviewers/quality/perf-analyzer.md +98 -7
- package/claude-assets/agents/cfn-dev-team/reviewers/quality/performance-benchmarker.md +95 -7
- package/claude-assets/agents/cfn-dev-team/reviewers/quality/security-specialist.md +136 -9
- package/claude-assets/agents/cfn-dev-team/testers/api-testing-specialist.md +108 -1
- package/claude-assets/agents/cfn-dev-team/testers/chaos-engineering-specialist.md +107 -13
- package/claude-assets/agents/cfn-dev-team/testers/contract-tester.md +737 -0
- package/claude-assets/agents/cfn-dev-team/testers/e2e/playwright-tester.md +1 -1
- package/claude-assets/agents/cfn-dev-team/testers/integration-tester.md +828 -0
- package/claude-assets/agents/cfn-dev-team/testers/interaction-tester.md +106 -7
- package/claude-assets/agents/cfn-dev-team/testers/load-testing-specialist.md +77 -0
- package/claude-assets/agents/cfn-dev-team/testers/mutation-testing-specialist.md +684 -0
- package/claude-assets/agents/cfn-dev-team/testers/playwright-tester.md +110 -1
- package/claude-assets/agents/cfn-dev-team/testers/tester.md +94 -7
- package/claude-assets/agents/cfn-dev-team/utility/code-booster.md +1 -3
- package/claude-assets/agents/cfn-dev-team/utility/epic-creator.md +87 -13
- package/claude-assets/agents/cfn-dev-team/utility/memory-leak-specialist.md +103 -7
- package/claude-assets/agents/cfn-dev-team/utility/researcher.md +1 -3
- package/claude-assets/agents/cfn-dev-team/utility/z-ai-specialist.md +94 -7
- package/claude-assets/agents/docker-coordinators/cfn-docker-v3-coordinator.md +46 -0
- package/claude-assets/agents/project-only-agents/npm-package-specialist.md +1 -1
- package/claude-assets/cfn-extras/skills/advanced-features/cfn-agent-swap/recommend-swap.sh +59 -59
- package/claude-assets/cfn-extras/skills/analytics/cfn-improvement-recommender/recommend-improvements.sh +91 -91
- package/claude-assets/cfn-extras/skills/analytics/cfn-pattern-extraction/extract-patterns.sh +79 -79
- package/claude-assets/cfn-extras/skills/analytics/cfn-retrospective-report/generate-report.sh +100 -100
- package/claude-assets/cfn-extras/skills/analytics/cfn-telemetry/start-telemetry.sh +110 -110
- package/claude-assets/cfn-extras/skills/deprecated/cfn-ace-system/add-bullet.sh +145 -145
- package/claude-assets/cfn-extras/skills/deprecated/cfn-ace-system/log-merge.sh +67 -67
- package/claude-assets/cfn-extras/skills/deprecated/cfn-ace-system/monitor-injection-performance.sh +137 -137
- package/claude-assets/cfn-extras/skills/deprecated/cfn-ace-system/optimize-injection-pipeline.sh +168 -168
- package/claude-assets/cfn-extras/skills/deprecated/cfn-ace-system/query-reflections.sh +35 -35
- package/claude-assets/cfn-extras/skills/deprecated/cfn-ace-system/store-reflection.sh +45 -45
- package/claude-assets/cfn-extras/skills/deprecated/cfn-ace-system/track-ab-test.sh +41 -41
- package/claude-assets/cfn-extras/skills/deprecated/cfn-ace-system/update-reflection.sh +41 -41
- package/claude-assets/cfn-extras/skills/deprecated/cfn-cli-setup/validate-cli-environment.sh +191 -191
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-ad-campaigns/operations/create-campaign.sh +231 -231
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-ad-campaigns/operations/get-campaign-performance.sh +190 -190
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-ad-campaigns/operations/pause-campaign.sh +142 -142
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-ad-campaigns/operations/set-budget.sh +181 -181
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-ad-campaigns/operations/update-bid-strategy.sh +133 -133
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-chatbot-conversations/operations/get-conversation-history.sh +121 -121
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-chatbot-conversations/operations/qualify-lead.sh +156 -156
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-chatbot-conversations/operations/schedule-demo.sh +181 -181
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-chatbot-conversations/operations/send-message.sh +137 -137
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-chatbot-conversations/operations/transfer-to-human.sh +179 -179
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-sms-campaigns/operations/create-campaign.sh +183 -183
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-sms-campaigns/operations/get-delivery-status.sh +139 -139
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-sms-campaigns/operations/opt-out.sh +150 -150
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-sms-campaigns/operations/schedule-campaign.sh +187 -187
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-sms-campaigns/operations/send-sms.sh +181 -181
- package/claude-assets/cfn-extras/skills/ui-portal/cfn-web-portal/test-web-portal-skill.sh +50 -50
- package/claude-assets/cfn-extras/skills/ui-portal/cfn-web-portal/validate-deployment.sh +84 -84
- package/claude-assets/cfn-extras/skills/utility/cfn-environment-sanitization/sanitize-environment.sh +243 -243
- package/claude-assets/commands/cfn-loop-cli.md +16 -2
- package/claude-assets/commands/switch-api.md +31 -10
- package/claude-assets/hooks/cfn-BACKUP_USAGE.md +243 -243
- package/claude-assets/hooks/cfn-invoke-security-validation.sh +69 -69
- package/claude-assets/hooks/cfn-lint-sql-injection.sh +61 -0
- package/claude-assets/hooks/cfn-post-edit-cfn-retrospective.sh +109 -78
- package/claude-assets/hooks/cfn-post-edit.config.json +44 -44
- package/claude-assets/hooks/cfn-post-execution/memory-cleanup.sh +19 -19
- package/claude-assets/hooks/cfn-pre-edit-security-warning.sh +40 -0
- package/claude-assets/hooks/cfn-pre-execution/memory-check.sh +19 -19
- package/claude-assets/hooks/detect-hardcoded-credentials.sh +212 -0
- package/claude-assets/skills/SKILL_TEMPLATE.md +774 -0
- package/claude-assets/skills/agent-lifecycle/execute-lifecycle-hook.sh +543 -572
- package/claude-assets/skills/agent-lifecycle/simple-audit.sh +57 -30
- package/claude-assets/skills/agent-template-generator/SKILL.md +440 -0
- package/claude-assets/skills/agent-template-generator/generate-agent.sh +405 -0
- package/claude-assets/skills/agent-validation-linter/SKILL.md +589 -0
- package/claude-assets/skills/agent-validation-linter/lint-agents.sh +271 -0
- package/claude-assets/skills/bootstrap/bash-fundamentals.md +786 -0
- package/claude-assets/skills/bootstrap/database-connection.md +464 -0
- package/claude-assets/skills/bootstrap/error-handling.md +580 -0
- package/claude-assets/skills/bootstrap/file-operations.md +699 -0
- package/claude-assets/skills/bootstrap/skill-loader.md +616 -0
- package/claude-assets/skills/bootstrap/sqlite-params.sh +287 -0
- package/claude-assets/skills/cfn-agent-spawning/spawn-agent.sh +22 -24
- package/claude-assets/skills/cfn-automatic-memory-persistence/persist-agent-output.sh +48 -48
- package/claude-assets/skills/cfn-automatic-memory-persistence/query-agent-history.sh +34 -34
- package/claude-assets/skills/cfn-automatic-memory-persistence/test-memory-persistence.sh +17 -16
- package/claude-assets/skills/cfn-deliverable-validation/confidence-calculator.sh +261 -261
- package/claude-assets/skills/cfn-deployment/SKILL.md +293 -0
- package/claude-assets/skills/cfn-deployment/execute.sh +21 -0
- package/claude-assets/skills/cfn-docker-agent-spawning/SKILL.md +28 -4
- package/claude-assets/skills/cfn-docker-agent-spawning/spawn-agent.sh +3 -1
- package/claude-assets/skills/cfn-docker-loop-orchestration/orchestrate.sh +224 -20
- package/claude-assets/skills/cfn-environment-sanitization/sanitize-environment.sh +38 -0
- package/claude-assets/skills/cfn-error-batching-strategy/lib/core-functions.sh +47 -47
- package/claude-assets/skills/cfn-expert-update/update-expert.sh +345 -345
- package/claude-assets/skills/cfn-file-operations/SKILL.md +290 -0
- package/claude-assets/skills/cfn-file-operations/execute.sh +129 -0
- package/claude-assets/skills/cfn-file-operations/lib/atomic-write.sh +294 -0
- package/claude-assets/skills/cfn-file-operations/lib/lock.sh +361 -0
- package/claude-assets/skills/cfn-file-operations/test.sh +369 -0
- package/claude-assets/skills/cfn-hybrid-routing/check-dependencies.sh +51 -51
- package/claude-assets/skills/cfn-intervention-detector/detect-intervention.sh +110 -110
- package/claude-assets/skills/cfn-intervention-orchestrator/execute-intervention.sh +58 -58
- package/claude-assets/skills/cfn-log-operations/SKILL.md +308 -0
- package/claude-assets/skills/cfn-log-operations/execute.sh +420 -0
- package/claude-assets/skills/cfn-log-operations/lib/rotate.sh +406 -0
- package/claude-assets/skills/cfn-log-operations/lib/search.sh +448 -0
- package/claude-assets/skills/cfn-log-operations/test.sh +394 -0
- package/claude-assets/skills/cfn-loop-orchestration/helpers/gate-check.sh +550 -46
- package/claude-assets/skills/cfn-loop-orchestration/helpers/parse-test-results.sh +277 -0
- package/claude-assets/skills/cfn-loop-orchestration/orchestrate.sh +184 -23
- package/claude-assets/skills/cfn-loop-orchestration/security_utils.sh +24 -0
- package/claude-assets/skills/cfn-loop-orchestration/test-iteration-context-injection.sh +366 -0
- package/claude-assets/skills/cfn-loop-validation/orchestrate-cfn-loop.sh +252 -252
- package/claude-assets/skills/cfn-loop2-output-processing/process-validator-output.sh +275 -275
- package/claude-assets/skills/cfn-memory-management/check-memory.sh +159 -159
- package/claude-assets/skills/cfn-memory-management/cleanup-memory.sh +196 -196
- package/claude-assets/skills/cfn-node-heap-sizer/task-mode-heap-limiter.sh +325 -325
- package/claude-assets/skills/cfn-parameterized-queries/SKILL.md +339 -0
- package/claude-assets/skills/cfn-playbook/query-playbook.sh +19 -15
- package/claude-assets/skills/cfn-playbook/update-playbook.sh +25 -14
- package/claude-assets/skills/cfn-playbook-auto-update/auto-update-playbook.sh +85 -85
- package/claude-assets/skills/cfn-process-instrumentation/instrument-process.sh +44 -0
- package/claude-assets/skills/cfn-promotion/SKILL.md +305 -0
- package/claude-assets/skills/cfn-redis-coordination/CENTRALIZED_REDIS_WRAPPER.md +319 -0
- package/claude-assets/skills/cfn-redis-coordination/agent-log.sh +4 -0
- package/claude-assets/skills/cfn-redis-coordination/agent-log.sh.bak +124 -0
- package/claude-assets/skills/cfn-redis-coordination/agent-recovery.sh +74 -74
- package/claude-assets/skills/cfn-redis-coordination/collect-confidence-scores.sh +30 -0
- package/claude-assets/skills/cfn-redis-coordination/get-context.sh +145 -112
- package/claude-assets/skills/cfn-redis-coordination/get-success-criteria.sh +54 -0
- package/claude-assets/skills/cfn-redis-coordination/invoke-waiting-mode.sh +3 -0
- package/claude-assets/skills/cfn-redis-coordination/redis-cli-wrapper.sh +24 -3
- package/claude-assets/skills/cfn-redis-coordination/redis-functions.sh +33 -0
- package/claude-assets/skills/cfn-redis-coordination/report-completion.sh +24 -31
- package/claude-assets/skills/cfn-redis-coordination/store-context.sh +4 -0
- package/claude-assets/skills/cfn-redis-coordination/store-success-criteria.sh +85 -0
- package/claude-assets/skills/cfn-redis-coordination/update-all-scripts.sh +67 -0
- package/claude-assets/skills/cfn-scope-simplifier/simplify-scope.sh +67 -67
- package/claude-assets/skills/cfn-skill-loader/SKILL.md +466 -0
- package/claude-assets/skills/cfn-skill-loader/execute.sh +344 -0
- package/claude-assets/skills/cfn-specialist-injection/recommend-specialist.sh +56 -56
- package/claude-assets/skills/cfn-sqlite-memory/ttl-cleanup.sh +17 -25
- package/claude-assets/skills/cfn-standardized-error-handling/capture-agent-error.sh +86 -86
- package/claude-assets/skills/cfn-standardized-error-handling/test-error-handling.sh +165 -165
- package/claude-assets/skills/cfn-task-audit/get-audit-data.sh +42 -21
- package/claude-assets/skills/cfn-task-audit/store-task-audit.sh +17 -10
- package/claude-assets/skills/cfn-task-config-init/initialize-config.sh +264 -264
- package/claude-assets/skills/cfn-task-decomposition/task-decomposer.sh +278 -278
- package/claude-assets/skills/cfn-test-runner/detect-regressions.sh +17 -14
- package/claude-assets/skills/cfn-test-runner/detect-regressions.sh.backup-1763392821 +55 -0
- package/claude-assets/skills/cfn-test-runner/store-benchmarks.sh +17 -19
- package/claude-assets/skills/cfn-transparency-middleware/middleware-config.sh +28 -28
- package/claude-assets/skills/cfn-transparency-middleware/performance-benchmark.sh +78 -78
- package/claude-assets/skills/cfn-transparency-middleware/test-e2e.sh +15 -0
- package/claude-assets/skills/cfn-transparency-middleware/test-integration.sh +161 -161
- package/claude-assets/skills/cfn-transparency-middleware/test-transparency-skill.sh +367 -367
- package/claude-assets/skills/cfn-transparency-middleware/tests/input-validation.sh +107 -92
- package/claude-assets/skills/cfn-transparency-middleware/wrap-agent.sh +131 -131
- package/claude-assets/skills/cfn-utilities/SKILL.md +237 -0
- package/claude-assets/skills/cfn-utilities/execute.sh +32 -0
- package/claude-assets/skills/cfn-utilities/lib/errors.sh +56 -0
- package/claude-assets/skills/cfn-utilities/lib/file-ops.sh +164 -0
- package/claude-assets/skills/cfn-utilities/lib/logging.sh +77 -0
- package/claude-assets/skills/cfn-utilities/lib/retry.sh +127 -0
- package/claude-assets/skills/cfn-utilities/test.sh +317 -0
- package/claude-assets/skills/docker-build/SKILL.md +96 -203
- package/claude-assets/skills/docker-build/build.sh +73 -73
- package/claude-assets/skills/integration/agent-handoff.sh +492 -0
- package/claude-assets/skills/integration/file-operations.sh +414 -0
- package/claude-assets/skills/json-validation/SKILL.md +431 -0
- package/claude-assets/skills/json-validation/test-validate-success-criteria.sh +421 -0
- package/claude-assets/skills/json-validation/validate-success-criteria.sh +197 -0
- package/claude-assets/skills/redis-coordination/validate-parameters.sh +34 -0
- package/claude-assets/skills/workflow-codification/APPROVAL_WORKFLOW.md +806 -0
- package/claude-assets/skills/workflow-codification/COST_TRACKING.md +637 -0
- package/claude-assets/skills/workflow-codification/DEPLOY_QUICK_REFERENCE.md +106 -0
- package/claude-assets/skills/workflow-codification/EDGE_CASE_TRACKING.md +404 -0
- package/claude-assets/skills/workflow-codification/PROPAGATE_UPDATE_QUICK_REFERENCE.md +366 -0
- package/claude-assets/skills/workflow-codification/README_PHASE4.md +457 -0
- package/claude-assets/skills/workflow-codification/SKILL.md +110 -0
- package/claude-assets/skills/workflow-codification/analyze-patterns.sh +899 -0
- package/claude-assets/skills/workflow-codification/approval-workflow.sh +514 -0
- package/claude-assets/skills/workflow-codification/deploy-approved-skill.sh +481 -0
- package/claude-assets/skills/workflow-codification/deploy-approved-skill.sh.backup-1763392820 +512 -0
- package/claude-assets/skills/workflow-codification/generate-skill-update.sh +525 -0
- package/claude-assets/skills/workflow-codification/lib/security-utils.sh +204 -0
- package/claude-assets/skills/workflow-codification/propagate-skill-update.sh +648 -0
- package/claude-assets/skills/workflow-codification/propagate-skill-update.sh.backup-1763392820 +664 -0
- package/claude-assets/skills/workflow-codification/review-skill.sh +643 -0
- package/claude-assets/skills/workflow-codification/templates/email-notification.txt +114 -0
- package/claude-assets/skills/workflow-codification/templates/slack-notification.md +85 -0
- package/claude-assets/skills/workflow-codification/test-integration.sh +296 -0
- package/claude-assets/skills/workflow-codification/test-metadata-update.sh +350 -0
- package/claude-assets/skills/workflow-codification/track-cost-savings.sh +486 -0
- package/claude-assets/skills/workflow-codification/track-cost-savings.sh.backup-1763392821 +445 -0
- package/claude-assets/skills/workflow-codification/track-edge-case.sh +290 -0
- package/claude-assets/skills/workflow-codification/workflow-codification.db +0 -0
- package/dist/ace/ace-curator.js +10 -2
- package/dist/ace/ace-curator.js.map +1 -1
- package/dist/ace/ace-generator.js +4 -0
- package/dist/ace/ace-generator.js.map +1 -1
- package/dist/ace/ace-reflector.js +1 -1
- package/dist/ace/ace-reflector.js.map +1 -1
- package/dist/ace/context-injection.js +24 -2
- package/dist/ace/context-injection.js.map +1 -1
- package/dist/agents/agent-loader.js +146 -165
- package/dist/agents/agent-loader.js.map +1 -1
- package/dist/agents/task-agent-integration.js +1 -1
- package/dist/agents/task-agent-integration.js.map +1 -1
- package/dist/api/health-endpoints.js +390 -0
- package/dist/api/health-endpoints.js.map +1 -0
- package/dist/cli/agent-executor.js +4 -1
- package/dist/cli/agent-executor.js.map +1 -1
- package/dist/cli/agent-prompt-builder.js +89 -1
- package/dist/cli/agent-prompt-builder.js.map +1 -1
- package/dist/cli/agent-spawn.js +130 -37
- package/dist/cli/agent-spawn.js.map +1 -1
- package/dist/cli/config-manager.js +91 -109
- package/dist/cli/config-manager.js.map +1 -1
- package/dist/cli/skill-cache-validator.js +412 -0
- package/dist/cli/skill-cache-validator.js.map +1 -0
- package/dist/cli/skill-cli.js +991 -0
- package/dist/cli/skill-cli.js.map +1 -0
- package/dist/cli/skill-execution-logger.js +284 -0
- package/dist/cli/skill-execution-logger.js.map +1 -0
- package/dist/cli/skill-loader.js +457 -0
- package/dist/cli/skill-loader.js.map +1 -0
- package/dist/coordination/event-bus.js +2 -2
- package/dist/coordination/event-bus.js.map +1 -1
- package/dist/coordination/fleet-manager.js +1 -1
- package/dist/coordination/fleet-manager.js.map +1 -1
- package/dist/coordination/index.js +23 -9
- package/dist/coordination/index.js.map +1 -1
- package/dist/coordination/types/fleet-manager.types.js.map +1 -1
- package/dist/db/migration-manager.js +483 -0
- package/dist/db/migration-manager.js.map +1 -0
- package/dist/db/skills-query.js +535 -0
- package/dist/db/skills-query.js.map +1 -0
- package/dist/integration/DatabaseHandoff.js +507 -0
- package/dist/integration/DatabaseHandoff.js.map +1 -0
- package/dist/integration/StandardAdapter.js +291 -0
- package/dist/integration/StandardAdapter.js.map +1 -0
- package/dist/jobs/edge-case-analyzer.js +367 -0
- package/dist/jobs/edge-case-analyzer.js.map +1 -0
- package/dist/jobs/promotion-sla-enforcer.js +288 -0
- package/dist/jobs/promotion-sla-enforcer.js.map +1 -0
- package/dist/lib/agent-output-parser.js +518 -0
- package/dist/lib/agent-output-parser.js.map +1 -0
- package/dist/lib/agent-output-validator.js +950 -0
- package/dist/lib/agent-output-validator.js.map +1 -0
- package/dist/lib/agent-workspace.js +281 -0
- package/dist/lib/agent-workspace.js.map +1 -0
- package/dist/lib/artifact-registry.js +443 -0
- package/dist/lib/artifact-registry.js.map +1 -0
- package/dist/lib/atomic-file-writer.js +377 -0
- package/dist/lib/atomic-file-writer.js.map +1 -0
- package/dist/lib/backup-manager.js +779 -0
- package/dist/lib/backup-manager.js.map +1 -0
- package/dist/lib/checkpoint-manager.js +837 -0
- package/dist/lib/checkpoint-manager.js.map +1 -0
- package/dist/lib/circuit-breaker.js +340 -0
- package/dist/lib/circuit-breaker.js.map +1 -0
- package/dist/lib/completion-signal-handler.js +243 -0
- package/dist/lib/completion-signal-handler.js.map +1 -0
- package/dist/lib/config-manager.js +312 -0
- package/dist/lib/config-manager.js.map +1 -0
- package/dist/lib/config-migrator.js +386 -0
- package/dist/lib/config-migrator.js.map +1 -0
- package/dist/lib/config-validator.js +687 -0
- package/dist/lib/config-validator.js.map +1 -0
- package/dist/lib/correlation-cache.js +311 -0
- package/dist/lib/correlation-cache.js.map +1 -0
- package/dist/lib/correlation.js +263 -0
- package/dist/lib/correlation.js.map +1 -0
- package/dist/lib/database-service/connection-pool-manager.js +520 -0
- package/dist/lib/database-service/connection-pool-manager.js.map +1 -0
- package/dist/lib/database-service/correlation.js +329 -0
- package/dist/lib/database-service/correlation.js.map +1 -0
- package/dist/lib/database-service/errors.js +120 -0
- package/dist/lib/database-service/errors.js.map +1 -0
- package/dist/lib/database-service/index.js +168 -0
- package/dist/lib/database-service/index.js.map +1 -0
- package/dist/lib/database-service/postgres-adapter.js +526 -0
- package/dist/lib/database-service/postgres-adapter.js.map +1 -0
- package/dist/lib/database-service/redis-adapter.js +360 -0
- package/dist/lib/database-service/redis-adapter.js.map +1 -0
- package/dist/lib/database-service/sqlite-adapter.js +544 -0
- package/dist/lib/database-service/sqlite-adapter.js.map +1 -0
- package/dist/lib/database-service/transaction-manager.js +773 -0
- package/dist/lib/database-service/transaction-manager.js.map +1 -0
- package/dist/lib/database-service/types.js +23 -0
- package/dist/lib/database-service/types.js.map +1 -0
- package/dist/lib/deadlock-resolver.js +292 -0
- package/dist/lib/deadlock-resolver.js.map +1 -0
- package/dist/lib/distributed-lock.js +451 -0
- package/dist/lib/distributed-lock.js.map +1 -0
- package/dist/lib/edge-case-deduplicator.js +227 -0
- package/dist/lib/edge-case-deduplicator.js.map +1 -0
- package/dist/lib/encryption-manager.js +322 -0
- package/dist/lib/encryption-manager.js.map +1 -0
- package/dist/lib/error-aggregator.js +234 -0
- package/dist/lib/error-aggregator.js.map +1 -0
- package/dist/lib/errors.js +287 -0
- package/dist/lib/errors.js.map +1 -0
- package/dist/lib/file-lock-manager.js +578 -0
- package/dist/lib/file-lock-manager.js.map +1 -0
- package/dist/lib/file-operations.js +367 -0
- package/dist/lib/file-operations.js.map +1 -0
- package/dist/lib/idempotent-write.js +237 -0
- package/dist/lib/idempotent-write.js.map +1 -0
- package/dist/lib/integration-schema-validator.js +522 -0
- package/dist/lib/integration-schema-validator.js.map +1 -0
- package/dist/lib/lock-health-monitor.js +298 -0
- package/dist/lib/lock-health-monitor.js.map +1 -0
- package/dist/lib/log-shipper.js +422 -0
- package/dist/lib/log-shipper.js.map +1 -0
- package/dist/lib/logging.js +146 -0
- package/dist/lib/logging.js.map +1 -0
- package/dist/lib/message-deduplicator.js +439 -0
- package/dist/lib/message-deduplicator.js.map +1 -0
- package/dist/lib/multi-system-query.js +604 -0
- package/dist/lib/multi-system-query.js.map +1 -0
- package/dist/lib/orphan-detector.js +332 -0
- package/dist/lib/orphan-detector.js.map +1 -0
- package/dist/lib/password-generator.js +166 -0
- package/dist/lib/password-generator.js.map +1 -0
- package/dist/lib/path-validator.js +429 -0
- package/dist/lib/path-validator.js.map +1 -0
- package/dist/lib/query-translator.js +905 -0
- package/dist/lib/query-translator.js.map +1 -0
- package/dist/lib/queue-recovery.js +469 -0
- package/dist/lib/queue-recovery.js.map +1 -0
- package/dist/lib/redis-queue-manager.js +512 -0
- package/dist/lib/redis-queue-manager.js.map +1 -0
- package/dist/lib/reflection-archiver.js +272 -0
- package/dist/lib/reflection-archiver.js.map +1 -0
- package/dist/lib/retry-manager.js +453 -0
- package/dist/lib/retry-manager.js.map +1 -0
- package/dist/lib/retry.js +262 -0
- package/dist/lib/retry.js.map +1 -0
- package/dist/lib/schema-transform.js +695 -0
- package/dist/lib/schema-transform.js.map +1 -0
- package/dist/lib/schema-validator.js +491 -0
- package/dist/lib/schema-validator.js.map +1 -0
- package/dist/lib/skill-cache.js +297 -0
- package/dist/lib/skill-cache.js.map +1 -0
- package/dist/lib/skill-content-manager.js +337 -0
- package/dist/lib/skill-content-manager.js.map +1 -0
- package/dist/lib/skill-frontmatter-parser.js +237 -0
- package/dist/lib/skill-frontmatter-parser.js.map +1 -0
- package/dist/lib/skill-git-integration.js +275 -0
- package/dist/lib/skill-git-integration.js.map +1 -0
- package/dist/lib/skill-markdown-validator.js +396 -0
- package/dist/lib/skill-markdown-validator.js.map +1 -0
- package/dist/lib/skill-output-parser.js +312 -0
- package/dist/lib/skill-output-parser.js.map +1 -0
- package/dist/lib/unified-query-api.js +467 -0
- package/dist/lib/unified-query-api.js.map +1 -0
- package/dist/middleware/auth-middleware.js +350 -0
- package/dist/middleware/auth-middleware.js.map +1 -0
- package/dist/middleware/schema-validation.js +347 -0
- package/dist/middleware/schema-validation.js.map +1 -0
- package/dist/providers/anthropic-provider.js +1 -1
- package/dist/providers/anthropic-provider.js.map +1 -1
- package/dist/providers/provider-factory.js +2 -2
- package/dist/providers/provider-factory.js.map +1 -1
- package/dist/services/edge-case-analyzer.js +321 -0
- package/dist/services/edge-case-analyzer.js.map +1 -0
- package/dist/services/edge-case-deduplicator.js +266 -0
- package/dist/services/edge-case-deduplicator.js.map +1 -0
- package/dist/services/edge-case-detector.js +337 -0
- package/dist/services/edge-case-detector.js.map +1 -0
- package/dist/services/edge-case-tracker.js +547 -0
- package/dist/services/edge-case-tracker.js.map +1 -0
- package/dist/services/health-check-system.js +586 -0
- package/dist/services/health-check-system.js.map +1 -0
- package/dist/services/metrics-logger.js +412 -0
- package/dist/services/metrics-logger.js.map +1 -0
- package/dist/services/patch-generator.js +378 -0
- package/dist/services/patch-generator.js.map +1 -0
- package/dist/services/patch-validator.js +337 -0
- package/dist/services/patch-validator.js.map +1 -0
- package/dist/services/performance-monitor.js +811 -0
- package/dist/services/performance-monitor.js.map +1 -0
- package/dist/services/promotion-pipeline.js +918 -0
- package/dist/services/promotion-pipeline.js.map +1 -0
- package/dist/services/promotion-validator.js +394 -0
- package/dist/services/promotion-validator.js.map +1 -0
- package/dist/services/reflection-logger.js +388 -0
- package/dist/services/reflection-logger.js.map +1 -0
- package/dist/services/skill-deployment.js +472 -0
- package/dist/services/skill-deployment.js.map +1 -0
- package/dist/services/skill-loader.js +427 -0
- package/dist/services/skill-loader.js.map +1 -0
- package/dist/services/skill-promotion.js +372 -0
- package/dist/services/skill-promotion.js.map +1 -0
- package/dist/services/skill-validator.js +454 -0
- package/dist/services/skill-validator.js.map +1 -0
- package/dist/services/skill-versioning.js +244 -0
- package/dist/services/skill-versioning.js.map +1 -0
- package/dist/services/workspace-supervisor.js +597 -0
- package/dist/services/workspace-supervisor.js.map +1 -0
- package/dist/types/agent-output.js +44 -0
- package/dist/types/agent-output.js.map +1 -0
- package/dist/types/config.js +28 -0
- package/dist/types/config.js.map +1 -0
- package/dist/types/edge-case.js +45 -0
- package/dist/types/edge-case.js.map +1 -0
- package/package.json +201 -176
- package/readme/README.md +19 -4
- package/scripts/artifact-cleanup.sh +392 -0
- package/scripts/backup-cleanup.sh +627 -0
- package/scripts/cleanup-workspaces.sh +412 -0
- package/scripts/cleanup-yaml-configs.sh +141 -0
- package/scripts/deploy-approved-skills.sh +263 -0
- package/scripts/deploy-production.sh +355 -355
- package/scripts/docker-playwright-fix.sh +311 -311
- package/scripts/docker-rebuild-all-agents.sh +127 -127
- package/scripts/health-check.sh +447 -0
- package/scripts/log-aggregator.sh +554 -0
- package/scripts/log-monitor.sh +629 -0
- package/scripts/manage-agent-workspaces.sh +434 -0
- package/scripts/memory-leak-prevention.sh +305 -305
- package/scripts/migrate-artifacts.sh +563 -0
- package/scripts/migrate-schema.sh +533 -0
- package/scripts/migrate-yaml-to-json.sh +465 -0
- package/scripts/promote-staged-skills.sh +423 -0
- package/scripts/run-marketing-tests.sh +42 -42
- package/scripts/update_paths.sh +46 -46
- package/scripts/verify-no-secrets.sh +88 -35
- package/.claude/cfn-extras/agents/deprecated-coordinators/adaptive-coordinator.md.backup +0 -161
- package/.claude/cfn-extras/agents/deprecated-coordinators/blocking-coordinator-example.md.backup +0 -728
- package/.claude/cfn-extras/agents/deprecated-coordinators/mesh-coordinator.md.backup +0 -131
- package/.claude/skills/cfn-agent-spawning/spawn-agent.sh.backup +0 -273
- package/.claude/skills/cfn-loop-orchestration/orchestrate.sh.backup +0 -949
- package/README.md.backup_before_replace +0 -781
- package/claude-assets/cfn-extras/agents/deprecated-coordinators/adaptive-coordinator.md.backup +0 -161
- package/claude-assets/cfn-extras/agents/deprecated-coordinators/blocking-coordinator-example.md.backup +0 -728
- package/claude-assets/cfn-extras/agents/deprecated-coordinators/mesh-coordinator.md.backup +0 -131
- package/claude-assets/skills/cfn-agent-spawning/spawn-agent.sh.backup +0 -273
- package/claude-assets/skills/cfn-loop-orchestration/orchestrate.sh.backup +0 -949
|
@@ -0,0 +1,451 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Distributed Lock Manager - Enhanced v2
|
|
3
|
+
*
|
|
4
|
+
* Provides distributed locking mechanism for cross-database transactions using Redis.
|
|
5
|
+
* Prevents concurrent modifications and ensures data consistency.
|
|
6
|
+
*
|
|
7
|
+
* Enhanced Features (Phase 2, Task P2-2.2):
|
|
8
|
+
* - Mandatory TTL enforcement with automatic expiration
|
|
9
|
+
* - Lock renewal mechanism for long-running operations
|
|
10
|
+
* - Auto-renewal with configurable interval
|
|
11
|
+
* - Lock health monitoring and statistics
|
|
12
|
+
* - Deadlock detection support
|
|
13
|
+
* - Stale lock cleanup
|
|
14
|
+
* - Backward compatible with existing usage
|
|
15
|
+
*
|
|
16
|
+
* Part of Task 3.1 (enhanced in Task P2-2.2)
|
|
17
|
+
*/ import { randomUUID } from 'crypto';
|
|
18
|
+
import { createLogger } from './logging.js';
|
|
19
|
+
import { generateCorrelationId } from './correlation.js';
|
|
20
|
+
const logger = createLogger('distributed-lock');
|
|
21
|
+
/**
|
|
22
|
+
* Enhanced Redis-backed distributed lock manager
|
|
23
|
+
*/ export class DistributedLockManager {
|
|
24
|
+
redisClient;
|
|
25
|
+
activeLocks = new Map();
|
|
26
|
+
renewalTimers = new Map();
|
|
27
|
+
statistics = {
|
|
28
|
+
totalAcquisitions: 0,
|
|
29
|
+
totalReleases: 0,
|
|
30
|
+
currentlyHeld: 0,
|
|
31
|
+
totalRenewals: 0,
|
|
32
|
+
averageDuration: 0,
|
|
33
|
+
failedAcquisitions: 0
|
|
34
|
+
};
|
|
35
|
+
lockDurations = [];
|
|
36
|
+
constructor(redisClient){
|
|
37
|
+
this.redisClient = redisClient;
|
|
38
|
+
logger.info('Enhanced distributed lock manager initialized (v2)');
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Acquire lock on a resource with TTL enforcement and optional auto-renewal
|
|
42
|
+
*/ async acquireLock(options) {
|
|
43
|
+
// Validate TTL (REQUIRED in v2)
|
|
44
|
+
if (options.ttl === undefined || options.ttl === null) {
|
|
45
|
+
// Backward compatibility: use default 60s TTL
|
|
46
|
+
options.ttl = 60000;
|
|
47
|
+
}
|
|
48
|
+
if (options.ttl <= 0) {
|
|
49
|
+
throw new Error('TTL must be positive');
|
|
50
|
+
}
|
|
51
|
+
const opts = {
|
|
52
|
+
timeout: options.timeout ?? 10000,
|
|
53
|
+
transactionId: options.transactionId,
|
|
54
|
+
retryInterval: options.retryInterval ?? 100,
|
|
55
|
+
correlationId: options.correlationId ?? generateCorrelationId()
|
|
56
|
+
};
|
|
57
|
+
const lockKey = this.buildLockKey(options.key);
|
|
58
|
+
const lockId = randomUUID();
|
|
59
|
+
const startTime = Date.now();
|
|
60
|
+
logger.debug('Attempting lock acquisition', {
|
|
61
|
+
lockKey,
|
|
62
|
+
lockId,
|
|
63
|
+
ttl: options.ttl,
|
|
64
|
+
renewInterval: options.renewInterval,
|
|
65
|
+
transactionId: opts.transactionId,
|
|
66
|
+
timeout: opts.timeout,
|
|
67
|
+
correlationId: opts.correlationId
|
|
68
|
+
});
|
|
69
|
+
// Try to acquire lock with timeout
|
|
70
|
+
while(Date.now() - startTime < opts.timeout){
|
|
71
|
+
const acquired = await this.tryAcquire(lockKey, lockId, options, opts);
|
|
72
|
+
if (acquired) {
|
|
73
|
+
const lock = {
|
|
74
|
+
id: lockId,
|
|
75
|
+
key: options.key,
|
|
76
|
+
acquiredAt: new Date(),
|
|
77
|
+
transactionId: opts.transactionId,
|
|
78
|
+
ttl: options.ttl,
|
|
79
|
+
renewInterval: options.renewInterval,
|
|
80
|
+
correlationId: opts.correlationId
|
|
81
|
+
};
|
|
82
|
+
this.activeLocks.set(lockId, lock);
|
|
83
|
+
this.statistics.totalAcquisitions++;
|
|
84
|
+
this.statistics.currentlyHeld++;
|
|
85
|
+
// Start auto-renewal if configured
|
|
86
|
+
if (options.renewInterval) {
|
|
87
|
+
this.startAutoRenewal(lock);
|
|
88
|
+
}
|
|
89
|
+
logger.info('Lock acquired successfully', {
|
|
90
|
+
lockId,
|
|
91
|
+
lockKey,
|
|
92
|
+
ttl: options.ttl,
|
|
93
|
+
renewInterval: options.renewInterval,
|
|
94
|
+
transactionId: opts.transactionId,
|
|
95
|
+
duration: Date.now() - startTime
|
|
96
|
+
});
|
|
97
|
+
return lock;
|
|
98
|
+
}
|
|
99
|
+
// Wait before retry
|
|
100
|
+
await this.sleep(opts.retryInterval);
|
|
101
|
+
}
|
|
102
|
+
// Timeout reached
|
|
103
|
+
const currentHolder = await this.getLockInfo(options.key);
|
|
104
|
+
this.statistics.failedAcquisitions++;
|
|
105
|
+
logger.warn('Lock acquisition timeout', {
|
|
106
|
+
lockKey,
|
|
107
|
+
lockId,
|
|
108
|
+
timeout: opts.timeout,
|
|
109
|
+
currentHolder,
|
|
110
|
+
correlationId: opts.correlationId
|
|
111
|
+
});
|
|
112
|
+
throw new LockAcquisitionError(`Failed to acquire lock on ${lockKey} within ${opts.timeout}ms`, lockKey, currentHolder);
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Try to acquire lock atomically (single attempt)
|
|
116
|
+
*/ async tryAcquire(lockKey, lockId, options, opts) {
|
|
117
|
+
try {
|
|
118
|
+
const now = new Date();
|
|
119
|
+
const metadata = {
|
|
120
|
+
lockId,
|
|
121
|
+
transactionId: opts.transactionId,
|
|
122
|
+
processId: process.pid,
|
|
123
|
+
acquiredAt: now.toISOString(),
|
|
124
|
+
expiresAt: new Date(now.getTime() + options.ttl).toISOString(),
|
|
125
|
+
correlationId: opts.correlationId
|
|
126
|
+
};
|
|
127
|
+
// Use Redis SET NX (set if not exists) with TTL (PX = milliseconds)
|
|
128
|
+
// This is atomic and prevents race conditions
|
|
129
|
+
const result = await this.redisClient.set(lockKey, JSON.stringify(metadata), 'PX', options.ttl, 'NX' // only set if not exists
|
|
130
|
+
);
|
|
131
|
+
return result === 'OK';
|
|
132
|
+
} catch (err) {
|
|
133
|
+
logger.error('Error during lock acquisition attempt', err, {
|
|
134
|
+
lockKey,
|
|
135
|
+
lockId
|
|
136
|
+
});
|
|
137
|
+
return false;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Renew lock TTL (extends expiration time)
|
|
142
|
+
*/ async renewLock(lockId, ttl) {
|
|
143
|
+
const lock = this.activeLocks.get(lockId);
|
|
144
|
+
if (!lock) {
|
|
145
|
+
throw new LockOwnershipError(`Cannot renew lock ${lockId}: lock not found in active locks`, lockId, 'unknown');
|
|
146
|
+
}
|
|
147
|
+
const lockKey = this.buildLockKey(lock.key);
|
|
148
|
+
try {
|
|
149
|
+
// Get current lock metadata
|
|
150
|
+
const metadata = await this.getLockInfo(lock.key);
|
|
151
|
+
if (!metadata) {
|
|
152
|
+
throw new Error('Lock has expired or been released');
|
|
153
|
+
}
|
|
154
|
+
if (metadata.lockId !== lockId) {
|
|
155
|
+
throw new LockOwnershipError(`Cannot renew lock ${lockKey}: ownership mismatch`, lockId, metadata.lockId);
|
|
156
|
+
}
|
|
157
|
+
// Update expiration time
|
|
158
|
+
const now = new Date();
|
|
159
|
+
metadata.expiresAt = new Date(now.getTime() + ttl).toISOString();
|
|
160
|
+
metadata.lastRenewedAt = now.toISOString();
|
|
161
|
+
// Update Redis with new TTL
|
|
162
|
+
await this.redisClient.set(lockKey, JSON.stringify(metadata), 'PX', ttl);
|
|
163
|
+
// Update local lock object
|
|
164
|
+
lock.ttl = ttl;
|
|
165
|
+
this.statistics.totalRenewals++;
|
|
166
|
+
logger.debug('Lock renewed successfully', {
|
|
167
|
+
lockId,
|
|
168
|
+
lockKey,
|
|
169
|
+
newTtl: ttl
|
|
170
|
+
});
|
|
171
|
+
} catch (err) {
|
|
172
|
+
logger.error('Error renewing lock', err, {
|
|
173
|
+
lockId,
|
|
174
|
+
lockKey
|
|
175
|
+
});
|
|
176
|
+
throw err;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Start auto-renewal for a lock
|
|
181
|
+
*/ startAutoRenewal(lock) {
|
|
182
|
+
if (!lock.renewInterval) {
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
const timer = setInterval(async ()=>{
|
|
186
|
+
try {
|
|
187
|
+
await this.renewLock(lock.id, lock.ttl);
|
|
188
|
+
logger.debug('Auto-renewal completed', {
|
|
189
|
+
lockId: lock.id,
|
|
190
|
+
key: lock.key
|
|
191
|
+
});
|
|
192
|
+
} catch (err) {
|
|
193
|
+
logger.error('Auto-renewal failed', err, {
|
|
194
|
+
lockId: lock.id,
|
|
195
|
+
key: lock.key
|
|
196
|
+
});
|
|
197
|
+
// Stop renewal on failure
|
|
198
|
+
this.stopAutoRenewal(lock.id);
|
|
199
|
+
}
|
|
200
|
+
}, lock.renewInterval);
|
|
201
|
+
this.renewalTimers.set(lock.id, timer);
|
|
202
|
+
logger.debug('Auto-renewal started', {
|
|
203
|
+
lockId: lock.id,
|
|
204
|
+
key: lock.key,
|
|
205
|
+
interval: lock.renewInterval
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Stop auto-renewal for a lock
|
|
210
|
+
*/ stopAutoRenewal(lockId) {
|
|
211
|
+
const timer = this.renewalTimers.get(lockId);
|
|
212
|
+
if (timer) {
|
|
213
|
+
clearInterval(timer);
|
|
214
|
+
this.renewalTimers.delete(lockId);
|
|
215
|
+
logger.debug('Auto-renewal stopped', {
|
|
216
|
+
lockId
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Release a lock manually
|
|
222
|
+
*/ async releaseLock(lockId) {
|
|
223
|
+
const lock = this.activeLocks.get(lockId);
|
|
224
|
+
if (!lock) {
|
|
225
|
+
logger.warn('Lock not found in active locks', {
|
|
226
|
+
lockId
|
|
227
|
+
});
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
const lockKey = this.buildLockKey(lock.key);
|
|
231
|
+
logger.debug('Releasing lock', {
|
|
232
|
+
lockId,
|
|
233
|
+
lockKey,
|
|
234
|
+
transactionId: lock.transactionId
|
|
235
|
+
});
|
|
236
|
+
try {
|
|
237
|
+
// Stop auto-renewal if active
|
|
238
|
+
this.stopAutoRenewal(lockId);
|
|
239
|
+
// Verify we own the lock before releasing
|
|
240
|
+
const metadata = await this.getLockInfo(lock.key);
|
|
241
|
+
if (!metadata) {
|
|
242
|
+
logger.warn('Lock already released or expired', {
|
|
243
|
+
lockId,
|
|
244
|
+
lockKey
|
|
245
|
+
});
|
|
246
|
+
this.activeLocks.delete(lockId);
|
|
247
|
+
this.statistics.currentlyHeld = Math.max(0, this.statistics.currentlyHeld - 1);
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
if (metadata.lockId !== lockId) {
|
|
251
|
+
logger.error('Lock ownership mismatch', new Error('Lock ownership mismatch'), {
|
|
252
|
+
expectedLockId: lockId,
|
|
253
|
+
actualLockId: metadata.lockId,
|
|
254
|
+
lockKey
|
|
255
|
+
});
|
|
256
|
+
throw new LockOwnershipError(`Cannot release lock ${lockKey}: ownership mismatch`, lockId, metadata.lockId);
|
|
257
|
+
}
|
|
258
|
+
// Delete lock from Redis
|
|
259
|
+
await this.redisClient.del(lockKey);
|
|
260
|
+
// Track duration for statistics
|
|
261
|
+
const duration = Date.now() - lock.acquiredAt.getTime();
|
|
262
|
+
this.lockDurations.push(duration);
|
|
263
|
+
// Keep only last 100 durations for average calculation
|
|
264
|
+
if (this.lockDurations.length > 100) {
|
|
265
|
+
this.lockDurations.shift();
|
|
266
|
+
}
|
|
267
|
+
// Update statistics
|
|
268
|
+
this.statistics.totalReleases++;
|
|
269
|
+
this.statistics.currentlyHeld = Math.max(0, this.statistics.currentlyHeld - 1);
|
|
270
|
+
this.statistics.averageDuration = this.calculateAverageDuration();
|
|
271
|
+
this.activeLocks.delete(lockId);
|
|
272
|
+
logger.info('Lock released successfully', {
|
|
273
|
+
lockId,
|
|
274
|
+
lockKey,
|
|
275
|
+
duration,
|
|
276
|
+
transactionId: lock.transactionId
|
|
277
|
+
});
|
|
278
|
+
} catch (err) {
|
|
279
|
+
logger.error('Error releasing lock', err, {
|
|
280
|
+
lockId,
|
|
281
|
+
lockKey
|
|
282
|
+
});
|
|
283
|
+
throw err;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Check if a resource is currently locked
|
|
288
|
+
*/ async isLocked(key) {
|
|
289
|
+
const lockKey = this.buildLockKey(key);
|
|
290
|
+
try {
|
|
291
|
+
const exists = await this.redisClient.exists(lockKey);
|
|
292
|
+
return exists === 1;
|
|
293
|
+
} catch (err) {
|
|
294
|
+
logger.error('Error checking lock status', err, {
|
|
295
|
+
lockKey
|
|
296
|
+
});
|
|
297
|
+
return false; // Assume unlocked on error (fail-safe)
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Get lock metadata for a resource
|
|
302
|
+
*/ async getLockInfo(key) {
|
|
303
|
+
const lockKey = this.buildLockKey(key);
|
|
304
|
+
try {
|
|
305
|
+
const data = await this.redisClient.get(lockKey);
|
|
306
|
+
if (!data) {
|
|
307
|
+
return null;
|
|
308
|
+
}
|
|
309
|
+
const metadata = JSON.parse(data);
|
|
310
|
+
return metadata;
|
|
311
|
+
} catch (err) {
|
|
312
|
+
logger.error('Error retrieving lock info', err, {
|
|
313
|
+
lockKey
|
|
314
|
+
});
|
|
315
|
+
return null;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Force release of a lock (admin operation - use with caution)
|
|
320
|
+
*/ async forceRelease(key) {
|
|
321
|
+
const lockKey = this.buildLockKey(key);
|
|
322
|
+
logger.warn('Force releasing lock', {
|
|
323
|
+
lockKey
|
|
324
|
+
});
|
|
325
|
+
try {
|
|
326
|
+
await this.redisClient.del(lockKey);
|
|
327
|
+
// Clean up from active locks if present
|
|
328
|
+
for (const [id, lock] of Array.from(this.activeLocks.entries())){
|
|
329
|
+
if (lock.key === key) {
|
|
330
|
+
this.stopAutoRenewal(id);
|
|
331
|
+
this.activeLocks.delete(id);
|
|
332
|
+
this.statistics.currentlyHeld = Math.max(0, this.statistics.currentlyHeld - 1);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
logger.info('Lock force released', {
|
|
336
|
+
lockKey
|
|
337
|
+
});
|
|
338
|
+
} catch (err) {
|
|
339
|
+
logger.error('Error force releasing lock', err, {
|
|
340
|
+
lockKey
|
|
341
|
+
});
|
|
342
|
+
throw err;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Get all active locks managed by this instance
|
|
347
|
+
*/ getActiveLocks() {
|
|
348
|
+
return Array.from(this.activeLocks.values());
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Get lock statistics
|
|
352
|
+
*/ getStatistics() {
|
|
353
|
+
return {
|
|
354
|
+
...this.statistics
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* Clean up expired locks from tracking
|
|
359
|
+
*/ cleanupExpiredLocks() {
|
|
360
|
+
const now = Date.now();
|
|
361
|
+
let cleaned = 0;
|
|
362
|
+
for (const [id, lock] of Array.from(this.activeLocks.entries())){
|
|
363
|
+
const expiresAt = lock.acquiredAt.getTime() + lock.ttl;
|
|
364
|
+
if (now > expiresAt) {
|
|
365
|
+
this.stopAutoRenewal(id);
|
|
366
|
+
this.activeLocks.delete(id);
|
|
367
|
+
this.statistics.currentlyHeld = Math.max(0, this.statistics.currentlyHeld - 1);
|
|
368
|
+
cleaned++;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
if (cleaned > 0) {
|
|
372
|
+
logger.debug('Cleaned up expired locks from tracking', {
|
|
373
|
+
count: cleaned
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
return cleaned;
|
|
377
|
+
}
|
|
378
|
+
/**
|
|
379
|
+
* Release all active locks (cleanup on shutdown)
|
|
380
|
+
*/ async releaseAll() {
|
|
381
|
+
logger.info('Releasing all active locks', {
|
|
382
|
+
count: this.activeLocks.size
|
|
383
|
+
});
|
|
384
|
+
const releases = Array.from(this.activeLocks.values()).map((lock)=>this.releaseLock(lock.id).catch((err)=>{
|
|
385
|
+
logger.error('Error releasing lock during cleanup', err, {
|
|
386
|
+
lockId: lock.id
|
|
387
|
+
});
|
|
388
|
+
}));
|
|
389
|
+
await Promise.all(releases);
|
|
390
|
+
logger.info('All locks released');
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* Build Redis key for lock resource
|
|
394
|
+
*/ buildLockKey(key) {
|
|
395
|
+
return `lock:${key}`;
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* Calculate average lock duration
|
|
399
|
+
*/ calculateAverageDuration() {
|
|
400
|
+
if (this.lockDurations.length === 0) {
|
|
401
|
+
return 0;
|
|
402
|
+
}
|
|
403
|
+
const sum = this.lockDurations.reduce((acc, dur)=>acc + dur, 0);
|
|
404
|
+
return Math.round(sum / this.lockDurations.length);
|
|
405
|
+
}
|
|
406
|
+
/**
|
|
407
|
+
* Sleep utility for retry intervals
|
|
408
|
+
*/ sleep(ms) {
|
|
409
|
+
return new Promise((resolve)=>setTimeout(resolve, ms));
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* Lock acquisition error
|
|
414
|
+
*/ export class LockAcquisitionError extends Error {
|
|
415
|
+
lockKey;
|
|
416
|
+
currentHolder;
|
|
417
|
+
constructor(message, lockKey, currentHolder){
|
|
418
|
+
super(message), this.lockKey = lockKey, this.currentHolder = currentHolder;
|
|
419
|
+
this.name = 'LockAcquisitionError';
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
/**
|
|
423
|
+
* Lock ownership error
|
|
424
|
+
*/ export class LockOwnershipError extends Error {
|
|
425
|
+
expectedLockId;
|
|
426
|
+
actualLockId;
|
|
427
|
+
constructor(message, expectedLockId, actualLockId){
|
|
428
|
+
super(message), this.expectedLockId = expectedLockId, this.actualLockId = actualLockId;
|
|
429
|
+
this.name = 'LockOwnershipError';
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
/**
|
|
433
|
+
* Utility: Execute function with distributed lock
|
|
434
|
+
*/ export async function withLock(lockManager, key, fn, options) {
|
|
435
|
+
const lock = await lockManager.acquireLock({
|
|
436
|
+
key,
|
|
437
|
+
ttl: options?.ttl ?? 60000,
|
|
438
|
+
...options
|
|
439
|
+
});
|
|
440
|
+
try {
|
|
441
|
+
const result = await fn();
|
|
442
|
+
await lockManager.releaseLock(lock.id);
|
|
443
|
+
return result;
|
|
444
|
+
} catch (err) {
|
|
445
|
+
await lockManager.releaseLock(lock.id);
|
|
446
|
+
throw err;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
export { DistributedLockManager as DistributedLock };
|
|
450
|
+
|
|
451
|
+
//# sourceMappingURL=distributed-lock.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/lib/distributed-lock.ts"],"sourcesContent":["/**\r\n * Distributed Lock Manager - Enhanced v2\r\n *\r\n * Provides distributed locking mechanism for cross-database transactions using Redis.\r\n * Prevents concurrent modifications and ensures data consistency.\r\n *\r\n * Enhanced Features (Phase 2, Task P2-2.2):\r\n * - Mandatory TTL enforcement with automatic expiration\r\n * - Lock renewal mechanism for long-running operations\r\n * - Auto-renewal with configurable interval\r\n * - Lock health monitoring and statistics\r\n * - Deadlock detection support\r\n * - Stale lock cleanup\r\n * - Backward compatible with existing usage\r\n *\r\n * Part of Task 3.1 (enhanced in Task P2-2.2)\r\n */\r\n\r\nimport { randomUUID } from 'crypto';\r\nimport { createLogger } from './logging.js';\r\nimport { generateCorrelationId } from './correlation.js';\r\n\r\nconst logger = createLogger('distributed-lock');\r\n\r\n/**\r\n * Lock acquisition options (enhanced)\r\n */\r\nexport interface LockOptions {\r\n /** Lock resource key (required) */\r\n key: string;\r\n /** Auto-release TTL in milliseconds (REQUIRED in v2) */\r\n ttl: number;\r\n /** Lock acquisition timeout in milliseconds (default: 10000) */\r\n timeout?: number;\r\n /** Auto-renewal interval in milliseconds (optional, enables auto-renewal) */\r\n renewInterval?: number;\r\n /** Transaction ID to associate with lock */\r\n transactionId?: string;\r\n /** Retry interval for lock acquisition in milliseconds (default: 100) */\r\n retryInterval?: number;\r\n /** Correlation ID for tracking */\r\n correlationId?: string;\r\n}\r\n\r\n/**\r\n * Lock instance (enhanced)\r\n */\r\nexport interface Lock {\r\n /** Unique lock ID */\r\n id: string;\r\n /** Lock resource key */\r\n key: string;\r\n /** Lock acquisition timestamp */\r\n acquiredAt: Date;\r\n /** Associated transaction ID */\r\n transactionId?: string;\r\n /** Lock TTL in milliseconds */\r\n ttl: number;\r\n /** Auto-renewal interval (if enabled) */\r\n renewInterval?: number;\r\n /** Correlation ID */\r\n correlationId: string;\r\n}\r\n\r\n/**\r\n * Lock metadata (stored in Redis)\r\n */\r\nexport interface LockMetadata {\r\n /** Lock ID */\r\n lockId: string;\r\n /** Transaction ID */\r\n transactionId?: string;\r\n /** Process ID (for deadlock detection) */\r\n processId: number;\r\n /** Acquired timestamp (ISO string) */\r\n acquiredAt: string;\r\n /** Expiration timestamp (ISO string) */\r\n expiresAt: string;\r\n /** Last renewal timestamp (ISO string) */\r\n lastRenewedAt?: string;\r\n /** Correlation ID */\r\n correlationId: string;\r\n}\r\n\r\n/**\r\n * Lock statistics\r\n */\r\nexport interface LockStatistics {\r\n /** Total lock acquisitions */\r\n totalAcquisitions: number;\r\n /** Total lock releases */\r\n totalReleases: number;\r\n /** Currently held locks */\r\n currentlyHeld: number;\r\n /** Total renewals performed */\r\n totalRenewals: number;\r\n /** Average lock duration (ms) */\r\n averageDuration: number;\r\n /** Failed acquisition attempts */\r\n failedAcquisitions: number;\r\n}\r\n\r\n/**\r\n * Enhanced Redis-backed distributed lock manager\r\n */\r\nexport class DistributedLockManager {\r\n private redisClient: any;\r\n private activeLocks: Map<string, Lock> = new Map();\r\n private renewalTimers: Map<string, NodeJS.Timeout> = new Map();\r\n private statistics: LockStatistics = {\r\n totalAcquisitions: 0,\r\n totalReleases: 0,\r\n currentlyHeld: 0,\r\n totalRenewals: 0,\r\n averageDuration: 0,\r\n failedAcquisitions: 0,\r\n };\r\n private lockDurations: number[] = [];\r\n\r\n constructor(redisClient: any) {\r\n this.redisClient = redisClient;\r\n logger.info('Enhanced distributed lock manager initialized (v2)');\r\n }\r\n\r\n /**\r\n * Acquire lock on a resource with TTL enforcement and optional auto-renewal\r\n */\r\n async acquireLock(options: LockOptions): Promise<Lock> {\r\n // Validate TTL (REQUIRED in v2)\r\n if (options.ttl === undefined || options.ttl === null) {\r\n // Backward compatibility: use default 60s TTL\r\n options.ttl = 60000;\r\n }\r\n\r\n if (options.ttl <= 0) {\r\n throw new Error('TTL must be positive');\r\n }\r\n\r\n const opts = {\r\n timeout: options.timeout ?? 10000,\r\n transactionId: options.transactionId,\r\n retryInterval: options.retryInterval ?? 100,\r\n correlationId: options.correlationId ?? generateCorrelationId(),\r\n };\r\n\r\n const lockKey = this.buildLockKey(options.key);\r\n const lockId = randomUUID();\r\n const startTime = Date.now();\r\n\r\n logger.debug('Attempting lock acquisition', {\r\n lockKey,\r\n lockId,\r\n ttl: options.ttl,\r\n renewInterval: options.renewInterval,\r\n transactionId: opts.transactionId,\r\n timeout: opts.timeout,\r\n correlationId: opts.correlationId,\r\n });\r\n\r\n // Try to acquire lock with timeout\r\n while (Date.now() - startTime < opts.timeout) {\r\n const acquired = await this.tryAcquire(lockKey, lockId, options, opts);\r\n\r\n if (acquired) {\r\n const lock: Lock = {\r\n id: lockId,\r\n key: options.key,\r\n acquiredAt: new Date(),\r\n transactionId: opts.transactionId,\r\n ttl: options.ttl,\r\n renewInterval: options.renewInterval,\r\n correlationId: opts.correlationId,\r\n };\r\n\r\n this.activeLocks.set(lockId, lock);\r\n this.statistics.totalAcquisitions++;\r\n this.statistics.currentlyHeld++;\r\n\r\n // Start auto-renewal if configured\r\n if (options.renewInterval) {\r\n this.startAutoRenewal(lock);\r\n }\r\n\r\n logger.info('Lock acquired successfully', {\r\n lockId,\r\n lockKey,\r\n ttl: options.ttl,\r\n renewInterval: options.renewInterval,\r\n transactionId: opts.transactionId,\r\n duration: Date.now() - startTime,\r\n });\r\n\r\n return lock;\r\n }\r\n\r\n // Wait before retry\r\n await this.sleep(opts.retryInterval);\r\n }\r\n\r\n // Timeout reached\r\n const currentHolder = await this.getLockInfo(options.key);\r\n\r\n this.statistics.failedAcquisitions++;\r\n\r\n logger.warn('Lock acquisition timeout', {\r\n lockKey,\r\n lockId,\r\n timeout: opts.timeout,\r\n currentHolder,\r\n correlationId: opts.correlationId,\r\n });\r\n\r\n throw new LockAcquisitionError(\r\n `Failed to acquire lock on ${lockKey} within ${opts.timeout}ms`,\r\n lockKey,\r\n currentHolder\r\n );\r\n }\r\n\r\n /**\r\n * Try to acquire lock atomically (single attempt)\r\n */\r\n private async tryAcquire(\r\n lockKey: string,\r\n lockId: string,\r\n options: LockOptions,\r\n opts: { transactionId?: string; correlationId: string }\r\n ): Promise<boolean> {\r\n try {\r\n const now = new Date();\r\n const metadata: LockMetadata = {\r\n lockId,\r\n transactionId: opts.transactionId,\r\n processId: process.pid,\r\n acquiredAt: now.toISOString(),\r\n expiresAt: new Date(now.getTime() + options.ttl).toISOString(),\r\n correlationId: opts.correlationId,\r\n };\r\n\r\n // Use Redis SET NX (set if not exists) with TTL (PX = milliseconds)\r\n // This is atomic and prevents race conditions\r\n const result = await this.redisClient.set(\r\n lockKey,\r\n JSON.stringify(metadata),\r\n 'PX', // milliseconds\r\n options.ttl,\r\n 'NX' // only set if not exists\r\n );\r\n\r\n return result === 'OK';\r\n } catch (err) {\r\n logger.error('Error during lock acquisition attempt', err as Error, {\r\n lockKey,\r\n lockId,\r\n });\r\n return false;\r\n }\r\n }\r\n\r\n /**\r\n * Renew lock TTL (extends expiration time)\r\n */\r\n async renewLock(lockId: string, ttl: number): Promise<void> {\r\n const lock = this.activeLocks.get(lockId);\r\n\r\n if (!lock) {\r\n throw new LockOwnershipError(\r\n `Cannot renew lock ${lockId}: lock not found in active locks`,\r\n lockId,\r\n 'unknown'\r\n );\r\n }\r\n\r\n const lockKey = this.buildLockKey(lock.key);\r\n\r\n try {\r\n // Get current lock metadata\r\n const metadata = await this.getLockInfo(lock.key);\r\n\r\n if (!metadata) {\r\n throw new Error('Lock has expired or been released');\r\n }\r\n\r\n if (metadata.lockId !== lockId) {\r\n throw new LockOwnershipError(\r\n `Cannot renew lock ${lockKey}: ownership mismatch`,\r\n lockId,\r\n metadata.lockId\r\n );\r\n }\r\n\r\n // Update expiration time\r\n const now = new Date();\r\n metadata.expiresAt = new Date(now.getTime() + ttl).toISOString();\r\n metadata.lastRenewedAt = now.toISOString();\r\n\r\n // Update Redis with new TTL\r\n await this.redisClient.set(\r\n lockKey,\r\n JSON.stringify(metadata),\r\n 'PX',\r\n ttl\r\n );\r\n\r\n // Update local lock object\r\n lock.ttl = ttl;\r\n\r\n this.statistics.totalRenewals++;\r\n\r\n logger.debug('Lock renewed successfully', {\r\n lockId,\r\n lockKey,\r\n newTtl: ttl,\r\n });\r\n } catch (err) {\r\n logger.error('Error renewing lock', err as Error, {\r\n lockId,\r\n lockKey,\r\n });\r\n throw err;\r\n }\r\n }\r\n\r\n /**\r\n * Start auto-renewal for a lock\r\n */\r\n private startAutoRenewal(lock: Lock): void {\r\n if (!lock.renewInterval) {\r\n return;\r\n }\r\n\r\n const timer = setInterval(async () => {\r\n try {\r\n await this.renewLock(lock.id, lock.ttl);\r\n logger.debug('Auto-renewal completed', {\r\n lockId: lock.id,\r\n key: lock.key,\r\n });\r\n } catch (err) {\r\n logger.error('Auto-renewal failed', err as Error, {\r\n lockId: lock.id,\r\n key: lock.key,\r\n });\r\n // Stop renewal on failure\r\n this.stopAutoRenewal(lock.id);\r\n }\r\n }, lock.renewInterval);\r\n\r\n this.renewalTimers.set(lock.id, timer);\r\n\r\n logger.debug('Auto-renewal started', {\r\n lockId: lock.id,\r\n key: lock.key,\r\n interval: lock.renewInterval,\r\n });\r\n }\r\n\r\n /**\r\n * Stop auto-renewal for a lock\r\n */\r\n private stopAutoRenewal(lockId: string): void {\r\n const timer = this.renewalTimers.get(lockId);\r\n\r\n if (timer) {\r\n clearInterval(timer);\r\n this.renewalTimers.delete(lockId);\r\n\r\n logger.debug('Auto-renewal stopped', { lockId });\r\n }\r\n }\r\n\r\n /**\r\n * Release a lock manually\r\n */\r\n async releaseLock(lockId: string): Promise<void> {\r\n const lock = this.activeLocks.get(lockId);\r\n\r\n if (!lock) {\r\n logger.warn('Lock not found in active locks', { lockId });\r\n return;\r\n }\r\n\r\n const lockKey = this.buildLockKey(lock.key);\r\n\r\n logger.debug('Releasing lock', {\r\n lockId,\r\n lockKey,\r\n transactionId: lock.transactionId,\r\n });\r\n\r\n try {\r\n // Stop auto-renewal if active\r\n this.stopAutoRenewal(lockId);\r\n\r\n // Verify we own the lock before releasing\r\n const metadata = await this.getLockInfo(lock.key);\r\n\r\n if (!metadata) {\r\n logger.warn('Lock already released or expired', {\r\n lockId,\r\n lockKey,\r\n });\r\n this.activeLocks.delete(lockId);\r\n this.statistics.currentlyHeld = Math.max(0, this.statistics.currentlyHeld - 1);\r\n return;\r\n }\r\n\r\n if (metadata.lockId !== lockId) {\r\n logger.error('Lock ownership mismatch', new Error('Lock ownership mismatch'), {\r\n expectedLockId: lockId,\r\n actualLockId: metadata.lockId,\r\n lockKey,\r\n });\r\n throw new LockOwnershipError(\r\n `Cannot release lock ${lockKey}: ownership mismatch`,\r\n lockId,\r\n metadata.lockId\r\n );\r\n }\r\n\r\n // Delete lock from Redis\r\n await this.redisClient.del(lockKey);\r\n\r\n // Track duration for statistics\r\n const duration = Date.now() - lock.acquiredAt.getTime();\r\n this.lockDurations.push(duration);\r\n\r\n // Keep only last 100 durations for average calculation\r\n if (this.lockDurations.length > 100) {\r\n this.lockDurations.shift();\r\n }\r\n\r\n // Update statistics\r\n this.statistics.totalReleases++;\r\n this.statistics.currentlyHeld = Math.max(0, this.statistics.currentlyHeld - 1);\r\n this.statistics.averageDuration = this.calculateAverageDuration();\r\n\r\n this.activeLocks.delete(lockId);\r\n\r\n logger.info('Lock released successfully', {\r\n lockId,\r\n lockKey,\r\n duration,\r\n transactionId: lock.transactionId,\r\n });\r\n } catch (err) {\r\n logger.error('Error releasing lock', err as Error, {\r\n lockId,\r\n lockKey,\r\n });\r\n throw err;\r\n }\r\n }\r\n\r\n /**\r\n * Check if a resource is currently locked\r\n */\r\n async isLocked(key: string): Promise<boolean> {\r\n const lockKey = this.buildLockKey(key);\r\n\r\n try {\r\n const exists = await this.redisClient.exists(lockKey);\r\n return exists === 1;\r\n } catch (err) {\r\n logger.error('Error checking lock status', err as Error, {\r\n lockKey,\r\n });\r\n return false; // Assume unlocked on error (fail-safe)\r\n }\r\n }\r\n\r\n /**\r\n * Get lock metadata for a resource\r\n */\r\n async getLockInfo(key: string): Promise<LockMetadata | null> {\r\n const lockKey = this.buildLockKey(key);\r\n\r\n try {\r\n const data = await this.redisClient.get(lockKey);\r\n\r\n if (!data) {\r\n return null;\r\n }\r\n\r\n const metadata: LockMetadata = JSON.parse(data);\r\n return metadata;\r\n } catch (err) {\r\n logger.error('Error retrieving lock info', err as Error, {\r\n lockKey,\r\n });\r\n return null;\r\n }\r\n }\r\n\r\n /**\r\n * Force release of a lock (admin operation - use with caution)\r\n */\r\n async forceRelease(key: string): Promise<void> {\r\n const lockKey = this.buildLockKey(key);\r\n\r\n logger.warn('Force releasing lock', {\r\n lockKey,\r\n });\r\n\r\n try {\r\n await this.redisClient.del(lockKey);\r\n\r\n // Clean up from active locks if present\r\n for (const [id, lock] of Array.from(this.activeLocks.entries())) {\r\n if (lock.key === key) {\r\n this.stopAutoRenewal(id);\r\n this.activeLocks.delete(id);\r\n this.statistics.currentlyHeld = Math.max(0, this.statistics.currentlyHeld - 1);\r\n }\r\n }\r\n\r\n logger.info('Lock force released', {\r\n lockKey,\r\n });\r\n } catch (err) {\r\n logger.error('Error force releasing lock', err as Error, {\r\n lockKey,\r\n });\r\n throw err;\r\n }\r\n }\r\n\r\n /**\r\n * Get all active locks managed by this instance\r\n */\r\n getActiveLocks(): Lock[] {\r\n return Array.from(this.activeLocks.values());\r\n }\r\n\r\n /**\r\n * Get lock statistics\r\n */\r\n getStatistics(): LockStatistics {\r\n return { ...this.statistics };\r\n }\r\n\r\n /**\r\n * Clean up expired locks from tracking\r\n */\r\n cleanupExpiredLocks(): number {\r\n const now = Date.now();\r\n let cleaned = 0;\r\n\r\n for (const [id, lock] of Array.from(this.activeLocks.entries())) {\r\n const expiresAt = lock.acquiredAt.getTime() + lock.ttl;\r\n\r\n if (now > expiresAt) {\r\n this.stopAutoRenewal(id);\r\n this.activeLocks.delete(id);\r\n this.statistics.currentlyHeld = Math.max(0, this.statistics.currentlyHeld - 1);\r\n cleaned++;\r\n }\r\n }\r\n\r\n if (cleaned > 0) {\r\n logger.debug('Cleaned up expired locks from tracking', { count: cleaned });\r\n }\r\n\r\n return cleaned;\r\n }\r\n\r\n /**\r\n * Release all active locks (cleanup on shutdown)\r\n */\r\n async releaseAll(): Promise<void> {\r\n logger.info('Releasing all active locks', { count: this.activeLocks.size });\r\n\r\n const releases = Array.from(this.activeLocks.values()).map(lock =>\r\n this.releaseLock(lock.id).catch(err => {\r\n logger.error('Error releasing lock during cleanup', err, {\r\n lockId: lock.id,\r\n });\r\n })\r\n );\r\n\r\n await Promise.all(releases);\r\n\r\n logger.info('All locks released');\r\n }\r\n\r\n /**\r\n * Build Redis key for lock resource\r\n */\r\n private buildLockKey(key: string): string {\r\n return `lock:${key}`;\r\n }\r\n\r\n /**\r\n * Calculate average lock duration\r\n */\r\n private calculateAverageDuration(): number {\r\n if (this.lockDurations.length === 0) {\r\n return 0;\r\n }\r\n\r\n const sum = this.lockDurations.reduce((acc, dur) => acc + dur, 0);\r\n return Math.round(sum / this.lockDurations.length);\r\n }\r\n\r\n /**\r\n * Sleep utility for retry intervals\r\n */\r\n private sleep(ms: number): Promise<void> {\r\n return new Promise(resolve => setTimeout(resolve, ms));\r\n }\r\n}\r\n\r\n/**\r\n * Lock acquisition error\r\n */\r\nexport class LockAcquisitionError extends Error {\r\n constructor(\r\n message: string,\r\n public lockKey: string,\r\n public currentHolder?: LockMetadata | null\r\n ) {\r\n super(message);\r\n this.name = 'LockAcquisitionError';\r\n }\r\n}\r\n\r\n/**\r\n * Lock ownership error\r\n */\r\nexport class LockOwnershipError extends Error {\r\n constructor(\r\n message: string,\r\n public expectedLockId: string,\r\n public actualLockId: string\r\n ) {\r\n super(message);\r\n this.name = 'LockOwnershipError';\r\n }\r\n}\r\n\r\n/**\r\n * Utility: Execute function with distributed lock\r\n */\r\nexport async function withLock<T>(\r\n lockManager: DistributedLockManager,\r\n key: string,\r\n fn: () => Promise<T>,\r\n options?: Omit<LockOptions, 'key'>\r\n): Promise<T> {\r\n const lock = await lockManager.acquireLock({\r\n key,\r\n ttl: options?.ttl ?? 60000,\r\n ...options,\r\n });\r\n\r\n try {\r\n const result = await fn();\r\n await lockManager.releaseLock(lock.id);\r\n return result;\r\n } catch (err) {\r\n await lockManager.releaseLock(lock.id);\r\n throw err;\r\n }\r\n}\r\n\r\n// Backward compatibility exports\r\nexport type { LockOptions, Lock, LockMetadata };\r\nexport { DistributedLockManager as DistributedLock };\r\n"],"names":["randomUUID","createLogger","generateCorrelationId","logger","DistributedLockManager","redisClient","activeLocks","Map","renewalTimers","statistics","totalAcquisitions","totalReleases","currentlyHeld","totalRenewals","averageDuration","failedAcquisitions","lockDurations","info","acquireLock","options","ttl","undefined","Error","opts","timeout","transactionId","retryInterval","correlationId","lockKey","buildLockKey","key","lockId","startTime","Date","now","debug","renewInterval","acquired","tryAcquire","lock","id","acquiredAt","set","startAutoRenewal","duration","sleep","currentHolder","getLockInfo","warn","LockAcquisitionError","metadata","processId","process","pid","toISOString","expiresAt","getTime","result","JSON","stringify","err","error","renewLock","get","LockOwnershipError","lastRenewedAt","newTtl","timer","setInterval","stopAutoRenewal","interval","clearInterval","delete","releaseLock","Math","max","expectedLockId","actualLockId","del","push","length","shift","calculateAverageDuration","isLocked","exists","data","parse","forceRelease","Array","from","entries","getActiveLocks","values","getStatistics","cleanupExpiredLocks","cleaned","count","releaseAll","size","releases","map","catch","Promise","all","sum","reduce","acc","dur","round","ms","resolve","setTimeout","message","name","withLock","lockManager","fn","DistributedLock"],"mappings":"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"}
|