claude-flow-novice 2.15.3 → 2.15.5
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 +29 -6
- package/.claude/commands/switch-api.md +31 -10
- package/.claude/hooks/cfn-lint-sql-injection.sh +61 -0
- package/.claude/hooks/cfn-post-edit-cfn-retrospective.sh +33 -2
- 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-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 +238 -29
- 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-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 +2 -2
- package/.claude/skills/cfn-redis-coordination/collect-confidence-scores.sh +30 -0
- package/.claude/skills/cfn-redis-coordination/get-context.sh +33 -0
- package/.claude/skills/cfn-redis-coordination/get-success-criteria.sh +54 -0
- package/.claude/skills/cfn-redis-coordination/invoke-waiting-mode.sh +6 -2
- package/.claude/skills/cfn-redis-coordination/redis-cli-wrapper.sh +24 -3
- package/.claude/skills/cfn-redis-coordination/redis-functions.sh +34 -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/test-e2e.sh +15 -0
- package/.claude/skills/cfn-transparency-middleware/tests/input-validation.sh +15 -0
- 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 +29 -6
- package/claude-assets/commands/switch-api.md +31 -10
- package/claude-assets/hooks/cfn-lint-sql-injection.sh +61 -0
- package/claude-assets/hooks/cfn-post-edit-cfn-retrospective.sh +33 -2
- package/claude-assets/hooks/cfn-pre-edit-security-warning.sh +40 -0
- 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 +84 -113
- package/claude-assets/skills/agent-lifecycle/simple-audit.sh +33 -6
- 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/test-memory-persistence.sh +17 -16
- 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-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-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 +238 -29
- 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-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-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 +2 -2
- package/claude-assets/skills/cfn-redis-coordination/collect-confidence-scores.sh +30 -0
- package/claude-assets/skills/cfn-redis-coordination/get-context.sh +33 -0
- package/claude-assets/skills/cfn-redis-coordination/get-success-criteria.sh +54 -0
- package/claude-assets/skills/cfn-redis-coordination/invoke-waiting-mode.sh +6 -2
- package/claude-assets/skills/cfn-redis-coordination/redis-cli-wrapper.sh +24 -3
- package/claude-assets/skills/cfn-redis-coordination/redis-functions.sh +34 -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-skill-loader/SKILL.md +466 -0
- package/claude-assets/skills/cfn-skill-loader/execute.sh +344 -0
- package/claude-assets/skills/cfn-sqlite-memory/ttl-cleanup.sh +17 -25
- 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-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/test-e2e.sh +15 -0
- package/claude-assets/skills/cfn-transparency-middleware/tests/input-validation.sh +15 -0
- 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/integration/agent-handoff.sh +62 -64
- 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/DEPLOY_QUICK_REFERENCE.md +106 -0
- package/claude-assets/skills/workflow-codification/PROPAGATE_UPDATE_QUICK_REFERENCE.md +366 -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/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/test-integration.sh +15 -0
- package/claude-assets/skills/workflow-codification/test-metadata-update.sh +350 -0
- package/claude-assets/skills/workflow-codification/track-cost-savings.sh +55 -14
- package/claude-assets/skills/workflow-codification/track-cost-savings.sh.backup-1763392821 +445 -0
- package/claude-assets/skills/workflow-codification/track-edge-case.sh +27 -60
- 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/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 +109 -91
- package/dist/cli/config-manager.js.map +1 -1
- package/dist/cli/conversation-fork-cleanup.js +201 -0
- package/dist/cli/conversation-fork-cleanup.js.map +1 -0
- package/dist/cli/conversation-fork.js +16 -3
- package/dist/cli/conversation-fork.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 +1 -1
- package/dist/integration/DatabaseHandoff.js.map +1 -1
- 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.map +1 -1
- package/dist/lib/agent-output-validator.js.map +1 -1
- package/dist/lib/agent-workspace.js +281 -0
- package/dist/lib/agent-workspace.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.map +1 -1
- 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/edge-case.js +45 -0
- package/dist/types/edge-case.js.map +1 -0
- package/docs/BUG_19_MEMORY_LEAK_TASK_MODE.md +405 -0
- package/docs/MEMORY_CLEANUP_GUIDE.md +358 -0
- package/docs/MEMORY_LEAK_FIX_SUMMARY.md +322 -0
- package/docs/REDIS_CLEANUP_EXECUTIVE_SUMMARY.md +319 -0
- package/docs/REDIS_CLEANUP_VERIFICATION_REPORT.md +574 -0
- package/package.json +35 -4
- package/readme/README.md +53 -5
- 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/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/migrate-schema.sh +533 -0
- package/scripts/promote-staged-skills.sh +423 -0
- package/scripts/verify-no-secrets.sh +88 -35
- package/scripts/verify-redis-cleanup.sh +173 -0
- package/tests/README.md +84 -0
- package/tests/test-memory-leak-task-mode.sh +435 -0
- 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/agent-lifecycle/SKILL.md +0 -60
- package/.claude/skills/agent-lifecycle/execute-lifecycle-hook.sh +0 -573
- package/.claude/skills/agent-lifecycle/simple-audit.sh +0 -31
- 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,837 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checkpoint Manager
|
|
3
|
+
*
|
|
4
|
+
* Manages dual persistence model with Redis (runtime/ephemeral) and SQLite (durable/persistent).
|
|
5
|
+
* Provides idempotent checkpointing with atomic operations and state validation.
|
|
6
|
+
*
|
|
7
|
+
* Task: Integration Standardization Plan - Task 4.5
|
|
8
|
+
* Version: 1.0.0
|
|
9
|
+
*
|
|
10
|
+
* Persistence Boundaries:
|
|
11
|
+
* - Redis: Agent execution state, coordination signals, temporary queues, active locks
|
|
12
|
+
* - SQLite: Completed task results, agent metrics, audit trail, skill metadata
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* const checkpointMgr = new CheckpointManager(dbService);
|
|
17
|
+
* await checkpointMgr.initialize();
|
|
18
|
+
*
|
|
19
|
+
* // Create checkpoint on task completion
|
|
20
|
+
* await checkpointMgr.createCheckpoint('task-123', CheckpointTrigger.TASK_COMPLETION);
|
|
21
|
+
*
|
|
22
|
+
* // Recover from checkpoint
|
|
23
|
+
* const state = await checkpointMgr.recoverFromCheckpoint('task-123');
|
|
24
|
+
* ```
|
|
25
|
+
*/ import * as crypto from 'crypto';
|
|
26
|
+
import { getGlobalLogger } from './logging.js';
|
|
27
|
+
import { StandardError, ErrorCode } from './errors.js';
|
|
28
|
+
const logger = getGlobalLogger();
|
|
29
|
+
// ============================================================================
|
|
30
|
+
// Type Definitions
|
|
31
|
+
// ============================================================================
|
|
32
|
+
/**
|
|
33
|
+
* Checkpoint trigger types
|
|
34
|
+
*/ export var CheckpointTrigger = /*#__PURE__*/ function(CheckpointTrigger) {
|
|
35
|
+
/** Triggered when a task completes */ CheckpointTrigger["TASK_COMPLETION"] = "task_completion";
|
|
36
|
+
/** Triggered at iteration boundaries (CFN Loop iterations) */ CheckpointTrigger["ITERATION_BOUNDARY"] = "iteration_boundary";
|
|
37
|
+
/** Triggered periodically (default: 5 minutes) */ CheckpointTrigger["PERIODIC"] = "periodic";
|
|
38
|
+
/** Manually triggered checkpoint */ CheckpointTrigger["MANUAL"] = "manual";
|
|
39
|
+
return CheckpointTrigger;
|
|
40
|
+
}({});
|
|
41
|
+
/**
|
|
42
|
+
* Checkpoint status
|
|
43
|
+
*/ export var CheckpointStatus = /*#__PURE__*/ function(CheckpointStatus) {
|
|
44
|
+
/** Checkpoint creation in progress */ CheckpointStatus["IN_PROGRESS"] = "in_progress";
|
|
45
|
+
/** Checkpoint completed successfully */ CheckpointStatus["COMPLETED"] = "completed";
|
|
46
|
+
/** Checkpoint failed */ CheckpointStatus["FAILED"] = "failed";
|
|
47
|
+
/** Checkpoint recovered and applied */ CheckpointStatus["RECOVERED"] = "recovered";
|
|
48
|
+
return CheckpointStatus;
|
|
49
|
+
}({});
|
|
50
|
+
// ============================================================================
|
|
51
|
+
// Checkpoint Manager
|
|
52
|
+
// ============================================================================
|
|
53
|
+
/**
|
|
54
|
+
* Checkpoint Manager
|
|
55
|
+
*
|
|
56
|
+
* Manages dual persistence model with idempotent checkpointing and recovery.
|
|
57
|
+
*/ export class CheckpointManager {
|
|
58
|
+
dbService;
|
|
59
|
+
redisAdapter;
|
|
60
|
+
sqliteAdapter;
|
|
61
|
+
config;
|
|
62
|
+
periodicCheckpointTimer;
|
|
63
|
+
initialized = false;
|
|
64
|
+
constructor(dbService, config = {}){
|
|
65
|
+
this.dbService = dbService;
|
|
66
|
+
// Get adapters
|
|
67
|
+
this.redisAdapter = dbService.getAdapter('redis');
|
|
68
|
+
this.sqliteAdapter = dbService.getAdapter('sqlite');
|
|
69
|
+
// Set config with defaults
|
|
70
|
+
this.config = {
|
|
71
|
+
enablePeriodicCheckpoints: config.enablePeriodicCheckpoints ?? true,
|
|
72
|
+
periodicInterval: config.periodicInterval ?? 300000,
|
|
73
|
+
retentionPeriod: config.retentionPeriod ?? 7 * 24 * 60 * 60 * 1000,
|
|
74
|
+
enableAutoCleanup: config.enableAutoCleanup ?? true,
|
|
75
|
+
validationTimeout: config.validationTimeout ?? 5000
|
|
76
|
+
};
|
|
77
|
+
logger.info('CheckpointManager initialized', {
|
|
78
|
+
config: this.config
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Initialize checkpoint manager and setup periodic checkpoints
|
|
83
|
+
*/ async initialize() {
|
|
84
|
+
if (this.initialized) {
|
|
85
|
+
logger.warn('CheckpointManager already initialized');
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
try {
|
|
89
|
+
// Create SQLite tables for checkpoint storage
|
|
90
|
+
await this.createCheckpointTables();
|
|
91
|
+
// Start periodic checkpoints if enabled
|
|
92
|
+
if (this.config.enablePeriodicCheckpoints) {
|
|
93
|
+
this.startPeriodicCheckpoints();
|
|
94
|
+
}
|
|
95
|
+
this.initialized = true;
|
|
96
|
+
logger.info('CheckpointManager initialization complete');
|
|
97
|
+
} catch (error) {
|
|
98
|
+
const err = error;
|
|
99
|
+
logger.error('Failed to initialize CheckpointManager', err);
|
|
100
|
+
throw new StandardError(ErrorCode.CONFIGURATION_ERROR, 'Failed to initialize CheckpointManager', {
|
|
101
|
+
error: err.message
|
|
102
|
+
}, err);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Shutdown checkpoint manager and cleanup resources
|
|
107
|
+
*/ async shutdown() {
|
|
108
|
+
if (this.periodicCheckpointTimer) {
|
|
109
|
+
clearInterval(this.periodicCheckpointTimer);
|
|
110
|
+
this.periodicCheckpointTimer = undefined;
|
|
111
|
+
}
|
|
112
|
+
this.initialized = false;
|
|
113
|
+
logger.info('CheckpointManager shutdown complete');
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Create a checkpoint for the given task
|
|
117
|
+
*
|
|
118
|
+
* Idempotent: Creating checkpoint with same state produces same result
|
|
119
|
+
*/ async createCheckpoint(taskId, trigger, metadata) {
|
|
120
|
+
this.ensureInitialized();
|
|
121
|
+
const startTime = Date.now();
|
|
122
|
+
const checkpointId = this.generateCheckpointId(taskId, trigger);
|
|
123
|
+
logger.info('Creating checkpoint', {
|
|
124
|
+
taskId,
|
|
125
|
+
checkpointId,
|
|
126
|
+
trigger
|
|
127
|
+
});
|
|
128
|
+
try {
|
|
129
|
+
// 1. Capture runtime state from Redis
|
|
130
|
+
const runtimeState = await this.captureRuntimeState(taskId);
|
|
131
|
+
const runtimeStateHash = this.hashState(runtimeState);
|
|
132
|
+
// 2. Capture durable state from SQLite
|
|
133
|
+
const durableState = await this.captureDurableState(taskId);
|
|
134
|
+
const durableStateHash = this.hashState(durableState);
|
|
135
|
+
// 3. Check for idempotency (same state hash = skip checkpoint)
|
|
136
|
+
const existingCheckpoint = await this.findCheckpointByHash(taskId, runtimeStateHash, durableStateHash);
|
|
137
|
+
if (existingCheckpoint && existingCheckpoint.status === "completed") {
|
|
138
|
+
logger.info('Checkpoint already exists with same state hash (idempotent)', {
|
|
139
|
+
checkpointId: existingCheckpoint.checkpointId,
|
|
140
|
+
taskId
|
|
141
|
+
});
|
|
142
|
+
return existingCheckpoint;
|
|
143
|
+
}
|
|
144
|
+
// 4. Create checkpoint metadata
|
|
145
|
+
const checkpointMetadata = {
|
|
146
|
+
checkpointId,
|
|
147
|
+
taskId,
|
|
148
|
+
trigger,
|
|
149
|
+
status: "in_progress",
|
|
150
|
+
runtimeStateHash,
|
|
151
|
+
durableStateHash,
|
|
152
|
+
createdAt: new Date(),
|
|
153
|
+
metadata
|
|
154
|
+
};
|
|
155
|
+
// 5. Store checkpoint metadata
|
|
156
|
+
await this.storeCheckpointMetadata(checkpointMetadata);
|
|
157
|
+
// 6. Validate state before storing (atomic check)
|
|
158
|
+
await this.validateState(runtimeState, durableState);
|
|
159
|
+
// 7. Store checkpoint data atomically
|
|
160
|
+
await this.storeCheckpointData(checkpointId, runtimeState, durableState);
|
|
161
|
+
// 8. Update checkpoint status to completed
|
|
162
|
+
checkpointMetadata.status = "completed";
|
|
163
|
+
checkpointMetadata.completedAt = new Date();
|
|
164
|
+
await this.updateCheckpointMetadata(checkpointMetadata);
|
|
165
|
+
const duration = Date.now() - startTime;
|
|
166
|
+
logger.info('Checkpoint created successfully', {
|
|
167
|
+
checkpointId,
|
|
168
|
+
taskId,
|
|
169
|
+
trigger,
|
|
170
|
+
duration,
|
|
171
|
+
runtimeStateHash,
|
|
172
|
+
durableStateHash
|
|
173
|
+
});
|
|
174
|
+
return checkpointMetadata;
|
|
175
|
+
} catch (error) {
|
|
176
|
+
const err = error;
|
|
177
|
+
logger.error('Failed to create checkpoint', err, {
|
|
178
|
+
taskId,
|
|
179
|
+
checkpointId
|
|
180
|
+
});
|
|
181
|
+
// Mark checkpoint as failed
|
|
182
|
+
const failedMetadata = {
|
|
183
|
+
checkpointId,
|
|
184
|
+
taskId,
|
|
185
|
+
trigger,
|
|
186
|
+
status: "failed",
|
|
187
|
+
runtimeStateHash: '',
|
|
188
|
+
durableStateHash: '',
|
|
189
|
+
createdAt: new Date(),
|
|
190
|
+
error: err.message,
|
|
191
|
+
metadata
|
|
192
|
+
};
|
|
193
|
+
await this.storeCheckpointMetadata(failedMetadata);
|
|
194
|
+
throw new StandardError(ErrorCode.OPERATION_TIMEOUT, 'Failed to create checkpoint', {
|
|
195
|
+
taskId,
|
|
196
|
+
checkpointId,
|
|
197
|
+
trigger
|
|
198
|
+
}, err);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Recover from the latest checkpoint for the given task
|
|
203
|
+
*/ async recoverFromCheckpoint(taskId) {
|
|
204
|
+
this.ensureInitialized();
|
|
205
|
+
logger.info('Starting checkpoint recovery', {
|
|
206
|
+
taskId
|
|
207
|
+
});
|
|
208
|
+
try {
|
|
209
|
+
// 1. Find latest completed checkpoint
|
|
210
|
+
const checkpoint = await this.findLatestCheckpoint(taskId);
|
|
211
|
+
if (!checkpoint) {
|
|
212
|
+
throw new StandardError(ErrorCode.DB_NOT_FOUND, 'No checkpoint found for task', {
|
|
213
|
+
taskId
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
// 2. Load checkpoint data
|
|
217
|
+
const checkpointData = await this.loadCheckpointData(checkpoint.checkpointId);
|
|
218
|
+
// 3. Validate checkpoint data
|
|
219
|
+
await this.validateCheckpointData(checkpointData);
|
|
220
|
+
// 4. Restore runtime state to Redis
|
|
221
|
+
const runtimeRestored = await this.restoreRuntimeState(taskId, checkpointData.runtimeState);
|
|
222
|
+
// 5. Restore durable state to SQLite (if needed)
|
|
223
|
+
const durableRestored = await this.restoreDurableState(taskId, checkpointData.durableState);
|
|
224
|
+
// 6. Update checkpoint status
|
|
225
|
+
checkpoint.status = "recovered";
|
|
226
|
+
await this.updateCheckpointMetadata(checkpoint);
|
|
227
|
+
const result = {
|
|
228
|
+
success: true,
|
|
229
|
+
checkpointId: checkpoint.checkpointId,
|
|
230
|
+
taskId,
|
|
231
|
+
runtimeStateRestored: runtimeRestored,
|
|
232
|
+
durableStateRestored: durableRestored,
|
|
233
|
+
timestamp: new Date()
|
|
234
|
+
};
|
|
235
|
+
logger.info('Checkpoint recovery completed', result);
|
|
236
|
+
return result;
|
|
237
|
+
} catch (error) {
|
|
238
|
+
const err = error;
|
|
239
|
+
logger.error('Failed to recover from checkpoint', err, {
|
|
240
|
+
taskId
|
|
241
|
+
});
|
|
242
|
+
return {
|
|
243
|
+
success: false,
|
|
244
|
+
checkpointId: '',
|
|
245
|
+
taskId,
|
|
246
|
+
runtimeStateRestored: false,
|
|
247
|
+
durableStateRestored: false,
|
|
248
|
+
timestamp: new Date(),
|
|
249
|
+
errors: [
|
|
250
|
+
err.message
|
|
251
|
+
]
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* List checkpoints for a task
|
|
257
|
+
*/ async listCheckpoints(taskId) {
|
|
258
|
+
this.ensureInitialized();
|
|
259
|
+
try {
|
|
260
|
+
const rows = await this.sqliteAdapter.list('checkpoints', {
|
|
261
|
+
filters: [
|
|
262
|
+
{
|
|
263
|
+
field: 'task_id',
|
|
264
|
+
operator: 'eq',
|
|
265
|
+
value: taskId
|
|
266
|
+
}
|
|
267
|
+
],
|
|
268
|
+
orderBy: 'created_at',
|
|
269
|
+
order: 'desc'
|
|
270
|
+
});
|
|
271
|
+
return rows.map((row)=>this.deserializeCheckpointMetadata(row));
|
|
272
|
+
} catch (error) {
|
|
273
|
+
const err = error;
|
|
274
|
+
logger.error('Failed to list checkpoints', err, {
|
|
275
|
+
taskId
|
|
276
|
+
});
|
|
277
|
+
throw new StandardError(ErrorCode.DB_QUERY_FAILED, 'Failed to list checkpoints', {
|
|
278
|
+
taskId
|
|
279
|
+
}, err);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Delete old checkpoints (cleanup)
|
|
284
|
+
*/ async cleanupOldCheckpoints() {
|
|
285
|
+
this.ensureInitialized();
|
|
286
|
+
if (!this.config.enableAutoCleanup) {
|
|
287
|
+
logger.info('Automatic cleanup disabled');
|
|
288
|
+
return 0;
|
|
289
|
+
}
|
|
290
|
+
try {
|
|
291
|
+
const cutoffDate = new Date(Date.now() - this.config.retentionPeriod);
|
|
292
|
+
const result = await this.sqliteAdapter.raw(`
|
|
293
|
+
DELETE FROM checkpoints
|
|
294
|
+
WHERE created_at < ?
|
|
295
|
+
`, [
|
|
296
|
+
cutoffDate.toISOString()
|
|
297
|
+
]);
|
|
298
|
+
const deletedCount = result.rowsAffected || 0;
|
|
299
|
+
logger.info('Cleaned up old checkpoints', {
|
|
300
|
+
deletedCount,
|
|
301
|
+
cutoffDate: cutoffDate.toISOString()
|
|
302
|
+
});
|
|
303
|
+
return deletedCount;
|
|
304
|
+
} catch (error) {
|
|
305
|
+
const err = error;
|
|
306
|
+
logger.error('Failed to cleanup old checkpoints', err);
|
|
307
|
+
throw new StandardError(ErrorCode.DB_QUERY_FAILED, 'Failed to cleanup old checkpoints', {}, err);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
// ============================================================================
|
|
311
|
+
// Private Methods - State Capture
|
|
312
|
+
// ============================================================================
|
|
313
|
+
async captureRuntimeState(taskId) {
|
|
314
|
+
try {
|
|
315
|
+
// Capture agent execution state
|
|
316
|
+
const agentKeys = await this.redisAdapter.raw('KEYS', [
|
|
317
|
+
`agent:${taskId}:*`
|
|
318
|
+
]);
|
|
319
|
+
const agents = [];
|
|
320
|
+
for (const key of agentKeys){
|
|
321
|
+
const data = await this.redisAdapter.get(key);
|
|
322
|
+
if (data) {
|
|
323
|
+
agents.push({
|
|
324
|
+
agentId: data.agentId || '',
|
|
325
|
+
agentType: data.agentType || '',
|
|
326
|
+
status: data.status || 'in_progress',
|
|
327
|
+
confidence: data.confidence,
|
|
328
|
+
startedAt: new Date(data.startedAt || Date.now()),
|
|
329
|
+
completedAt: data.completedAt ? new Date(data.completedAt) : undefined,
|
|
330
|
+
metadata: data.metadata
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
// Capture coordination signals
|
|
335
|
+
const signalKeys = await this.redisAdapter.raw('KEYS', [
|
|
336
|
+
`swarm:${taskId}:*`
|
|
337
|
+
]);
|
|
338
|
+
const coordinationSignals = [];
|
|
339
|
+
for (const key of signalKeys){
|
|
340
|
+
const value = await this.redisAdapter.get(key);
|
|
341
|
+
const ttl = await this.redisAdapter.raw('TTL', [
|
|
342
|
+
key
|
|
343
|
+
]);
|
|
344
|
+
if (value) {
|
|
345
|
+
coordinationSignals.push({
|
|
346
|
+
key,
|
|
347
|
+
value,
|
|
348
|
+
ttl: ttl > 0 ? ttl : undefined,
|
|
349
|
+
createdAt: new Date()
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
// Capture queue data
|
|
354
|
+
const queueKeys = await this.redisAdapter.raw('KEYS', [
|
|
355
|
+
`queue:${taskId}:*`
|
|
356
|
+
]);
|
|
357
|
+
const queueData = [];
|
|
358
|
+
for (const key of queueKeys){
|
|
359
|
+
const items = await this.redisAdapter.raw('LRANGE', [
|
|
360
|
+
key,
|
|
361
|
+
'0',
|
|
362
|
+
'-1'
|
|
363
|
+
]);
|
|
364
|
+
if (items && items.length > 0) {
|
|
365
|
+
queueData.push({
|
|
366
|
+
queueName: key,
|
|
367
|
+
items
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
// Capture active locks
|
|
372
|
+
const lockKeys = await this.redisAdapter.raw('KEYS', [
|
|
373
|
+
`lock:${taskId}:*`
|
|
374
|
+
]);
|
|
375
|
+
const activeLocks = [];
|
|
376
|
+
for (const key of lockKeys){
|
|
377
|
+
const owner = await this.redisAdapter.get(key);
|
|
378
|
+
const ttl = await this.redisAdapter.raw('TTL', [
|
|
379
|
+
key
|
|
380
|
+
]);
|
|
381
|
+
if (owner && ttl > 0) {
|
|
382
|
+
activeLocks.push({
|
|
383
|
+
lockKey: key,
|
|
384
|
+
owner,
|
|
385
|
+
acquiredAt: new Date(),
|
|
386
|
+
expiresAt: new Date(Date.now() + ttl * 1000)
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
return {
|
|
391
|
+
taskId,
|
|
392
|
+
agents,
|
|
393
|
+
coordinationSignals,
|
|
394
|
+
queueData,
|
|
395
|
+
activeLocks,
|
|
396
|
+
capturedAt: new Date()
|
|
397
|
+
};
|
|
398
|
+
} catch (error) {
|
|
399
|
+
const err = error;
|
|
400
|
+
logger.error('Failed to capture runtime state', err, {
|
|
401
|
+
taskId
|
|
402
|
+
});
|
|
403
|
+
throw new StandardError(ErrorCode.DB_QUERY_FAILED, 'Failed to capture runtime state from Redis', {
|
|
404
|
+
taskId
|
|
405
|
+
}, err);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
async captureDurableState(taskId) {
|
|
409
|
+
try {
|
|
410
|
+
// Capture task results
|
|
411
|
+
const taskResults = await this.sqliteAdapter.list('task_results', {
|
|
412
|
+
filters: [
|
|
413
|
+
{
|
|
414
|
+
field: 'taskId',
|
|
415
|
+
operator: 'eq',
|
|
416
|
+
value: taskId
|
|
417
|
+
}
|
|
418
|
+
]
|
|
419
|
+
});
|
|
420
|
+
// Capture agent metrics
|
|
421
|
+
const agentMetrics = await this.sqliteAdapter.list('agent_metrics', {
|
|
422
|
+
filters: [
|
|
423
|
+
{
|
|
424
|
+
field: 'taskId',
|
|
425
|
+
operator: 'eq',
|
|
426
|
+
value: taskId
|
|
427
|
+
}
|
|
428
|
+
]
|
|
429
|
+
});
|
|
430
|
+
// Capture audit trail
|
|
431
|
+
const auditTrail = await this.sqliteAdapter.list('audit_trail', {
|
|
432
|
+
filters: [
|
|
433
|
+
{
|
|
434
|
+
field: 'taskId',
|
|
435
|
+
operator: 'eq',
|
|
436
|
+
value: taskId
|
|
437
|
+
}
|
|
438
|
+
]
|
|
439
|
+
});
|
|
440
|
+
// Capture skill metadata
|
|
441
|
+
const skillMetadata = await this.sqliteAdapter.list('skill_metadata', {});
|
|
442
|
+
return {
|
|
443
|
+
taskId,
|
|
444
|
+
taskResults,
|
|
445
|
+
agentMetrics,
|
|
446
|
+
auditTrail,
|
|
447
|
+
skillMetadata,
|
|
448
|
+
capturedAt: new Date()
|
|
449
|
+
};
|
|
450
|
+
} catch (error) {
|
|
451
|
+
const err = error;
|
|
452
|
+
logger.error('Failed to capture durable state', err, {
|
|
453
|
+
taskId
|
|
454
|
+
});
|
|
455
|
+
throw new StandardError(ErrorCode.DB_QUERY_FAILED, 'Failed to capture durable state from SQLite', {
|
|
456
|
+
taskId
|
|
457
|
+
}, err);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
// ============================================================================
|
|
461
|
+
// Private Methods - State Storage
|
|
462
|
+
// ============================================================================
|
|
463
|
+
async storeCheckpointData(checkpointId, runtimeState, durableState) {
|
|
464
|
+
try {
|
|
465
|
+
// Store runtime state as JSON in a key-value table
|
|
466
|
+
await this.sqliteAdapter.insert('checkpoint_data', {
|
|
467
|
+
key: `checkpoint_runtime:${checkpointId}`,
|
|
468
|
+
value: JSON.stringify(runtimeState)
|
|
469
|
+
});
|
|
470
|
+
// Store durable state as JSON in a key-value table
|
|
471
|
+
await this.sqliteAdapter.insert('checkpoint_data', {
|
|
472
|
+
key: `checkpoint_durable:${checkpointId}`,
|
|
473
|
+
value: JSON.stringify(durableState)
|
|
474
|
+
});
|
|
475
|
+
logger.debug('Checkpoint data stored', {
|
|
476
|
+
checkpointId
|
|
477
|
+
});
|
|
478
|
+
} catch (error) {
|
|
479
|
+
const err = error;
|
|
480
|
+
logger.error('Failed to store checkpoint data', err, {
|
|
481
|
+
checkpointId
|
|
482
|
+
});
|
|
483
|
+
throw new StandardError(ErrorCode.DB_QUERY_FAILED, 'Failed to store checkpoint data', {
|
|
484
|
+
checkpointId
|
|
485
|
+
}, err);
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
async loadCheckpointData(checkpointId) {
|
|
489
|
+
try {
|
|
490
|
+
// Load metadata from checkpoints table
|
|
491
|
+
const metadataRow = await this.sqliteAdapter.get(`checkpoints:${checkpointId}`);
|
|
492
|
+
if (!metadataRow) {
|
|
493
|
+
throw new StandardError(ErrorCode.DB_NOT_FOUND, 'Checkpoint metadata not found', {
|
|
494
|
+
checkpointId
|
|
495
|
+
});
|
|
496
|
+
}
|
|
497
|
+
// Load runtime state from checkpoint_data table
|
|
498
|
+
const runtimeStateRow = await this.sqliteAdapter.get(`checkpoint_data:checkpoint_runtime:${checkpointId}`);
|
|
499
|
+
if (!runtimeStateRow || !runtimeStateRow.value) {
|
|
500
|
+
throw new StandardError(ErrorCode.DB_NOT_FOUND, 'Checkpoint runtime state not found', {
|
|
501
|
+
checkpointId
|
|
502
|
+
});
|
|
503
|
+
}
|
|
504
|
+
// Load durable state from checkpoint_data table
|
|
505
|
+
const durableStateRow = await this.sqliteAdapter.get(`checkpoint_data:checkpoint_durable:${checkpointId}`);
|
|
506
|
+
if (!durableStateRow || !durableStateRow.value) {
|
|
507
|
+
throw new StandardError(ErrorCode.DB_NOT_FOUND, 'Checkpoint durable state not found', {
|
|
508
|
+
checkpointId
|
|
509
|
+
});
|
|
510
|
+
}
|
|
511
|
+
return {
|
|
512
|
+
metadata: this.deserializeCheckpointMetadata(metadataRow),
|
|
513
|
+
runtimeState: JSON.parse(runtimeStateRow.value),
|
|
514
|
+
durableState: JSON.parse(durableStateRow.value)
|
|
515
|
+
};
|
|
516
|
+
} catch (error) {
|
|
517
|
+
const err = error;
|
|
518
|
+
logger.error('Failed to load checkpoint data', err, {
|
|
519
|
+
checkpointId
|
|
520
|
+
});
|
|
521
|
+
throw new StandardError(ErrorCode.DB_QUERY_FAILED, 'Failed to load checkpoint data', {
|
|
522
|
+
checkpointId
|
|
523
|
+
}, err);
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
// ============================================================================
|
|
527
|
+
// Private Methods - State Restoration
|
|
528
|
+
// ============================================================================
|
|
529
|
+
async restoreRuntimeState(taskId, runtimeState) {
|
|
530
|
+
try {
|
|
531
|
+
// Restore agent execution state
|
|
532
|
+
for (const agent of runtimeState.agents){
|
|
533
|
+
await this.redisAdapter.insert(`agent:${taskId}:${agent.agentId}`, agent);
|
|
534
|
+
}
|
|
535
|
+
// Restore coordination signals
|
|
536
|
+
for (const signal of runtimeState.coordinationSignals){
|
|
537
|
+
await this.redisAdapter.insert(signal.key, signal.value);
|
|
538
|
+
if (signal.ttl) {
|
|
539
|
+
await this.redisAdapter.raw('EXPIRE', [
|
|
540
|
+
signal.key,
|
|
541
|
+
signal.ttl.toString()
|
|
542
|
+
]);
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
// Restore queue data
|
|
546
|
+
for (const queue of runtimeState.queueData){
|
|
547
|
+
await this.redisAdapter.raw('DEL', [
|
|
548
|
+
queue.queueName
|
|
549
|
+
]);
|
|
550
|
+
for (const item of queue.items){
|
|
551
|
+
await this.redisAdapter.raw('RPUSH', [
|
|
552
|
+
queue.queueName,
|
|
553
|
+
JSON.stringify(item)
|
|
554
|
+
]);
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
// Restore active locks
|
|
558
|
+
for (const lock of runtimeState.activeLocks){
|
|
559
|
+
const ttl = Math.floor((lock.expiresAt.getTime() - Date.now()) / 1000);
|
|
560
|
+
if (ttl > 0) {
|
|
561
|
+
await this.redisAdapter.insert(lock.lockKey, lock.owner);
|
|
562
|
+
await this.redisAdapter.raw('EXPIRE', [
|
|
563
|
+
lock.lockKey,
|
|
564
|
+
ttl.toString()
|
|
565
|
+
]);
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
logger.info('Runtime state restored to Redis', {
|
|
569
|
+
taskId
|
|
570
|
+
});
|
|
571
|
+
return true;
|
|
572
|
+
} catch (error) {
|
|
573
|
+
const err = error;
|
|
574
|
+
logger.error('Failed to restore runtime state', err, {
|
|
575
|
+
taskId
|
|
576
|
+
});
|
|
577
|
+
return false;
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
async restoreDurableState(taskId, durableState) {
|
|
581
|
+
try {
|
|
582
|
+
// Durable state in SQLite is already persistent
|
|
583
|
+
// This method is for future enhancements (e.g., restoring to different instance)
|
|
584
|
+
logger.info('Durable state validation complete', {
|
|
585
|
+
taskId
|
|
586
|
+
});
|
|
587
|
+
return true;
|
|
588
|
+
} catch (error) {
|
|
589
|
+
const err = error;
|
|
590
|
+
logger.error('Failed to restore durable state', err, {
|
|
591
|
+
taskId
|
|
592
|
+
});
|
|
593
|
+
return false;
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
// ============================================================================
|
|
597
|
+
// Private Methods - Validation
|
|
598
|
+
// ============================================================================
|
|
599
|
+
async validateState(runtimeState, durableState) {
|
|
600
|
+
// Validate runtime state
|
|
601
|
+
if (!runtimeState.taskId) {
|
|
602
|
+
throw new StandardError(ErrorCode.VALIDATION_FAILED, 'Invalid runtime state: missing taskId', {
|
|
603
|
+
runtimeState
|
|
604
|
+
});
|
|
605
|
+
}
|
|
606
|
+
if (!Array.isArray(runtimeState.agents)) {
|
|
607
|
+
throw new StandardError(ErrorCode.VALIDATION_FAILED, 'Invalid runtime state: agents must be an array', {
|
|
608
|
+
runtimeState
|
|
609
|
+
});
|
|
610
|
+
}
|
|
611
|
+
// Validate durable state
|
|
612
|
+
if (!durableState.taskId) {
|
|
613
|
+
throw new StandardError(ErrorCode.VALIDATION_FAILED, 'Invalid durable state: missing taskId', {
|
|
614
|
+
durableState
|
|
615
|
+
});
|
|
616
|
+
}
|
|
617
|
+
if (runtimeState.taskId !== durableState.taskId) {
|
|
618
|
+
throw new StandardError(ErrorCode.VALIDATION_FAILED, 'Task ID mismatch between runtime and durable state', {
|
|
619
|
+
runtimeTaskId: runtimeState.taskId,
|
|
620
|
+
durableTaskId: durableState.taskId
|
|
621
|
+
});
|
|
622
|
+
}
|
|
623
|
+
logger.debug('State validation passed', {
|
|
624
|
+
taskId: runtimeState.taskId
|
|
625
|
+
});
|
|
626
|
+
}
|
|
627
|
+
async validateCheckpointData(checkpointData) {
|
|
628
|
+
await this.validateState(checkpointData.runtimeState, checkpointData.durableState);
|
|
629
|
+
if (checkpointData.metadata.status !== "completed") {
|
|
630
|
+
throw new StandardError(ErrorCode.VALIDATION_FAILED, 'Cannot recover from incomplete checkpoint', {
|
|
631
|
+
status: checkpointData.metadata.status
|
|
632
|
+
});
|
|
633
|
+
}
|
|
634
|
+
logger.debug('Checkpoint data validation passed', {
|
|
635
|
+
checkpointId: checkpointData.metadata.checkpointId
|
|
636
|
+
});
|
|
637
|
+
}
|
|
638
|
+
// ============================================================================
|
|
639
|
+
// Private Methods - Utilities
|
|
640
|
+
// ============================================================================
|
|
641
|
+
generateCheckpointId(taskId, trigger) {
|
|
642
|
+
const timestamp = Date.now();
|
|
643
|
+
const random = crypto.randomBytes(4).toString('hex');
|
|
644
|
+
return `checkpoint_${taskId}_${trigger}_${timestamp}_${random}`;
|
|
645
|
+
}
|
|
646
|
+
hashState(state) {
|
|
647
|
+
const stateJson = JSON.stringify(state, Object.keys(state).sort());
|
|
648
|
+
return crypto.createHash('sha256').update(stateJson).digest('hex');
|
|
649
|
+
}
|
|
650
|
+
async findCheckpointByHash(taskId, runtimeHash, durableHash) {
|
|
651
|
+
try {
|
|
652
|
+
const rows = await this.sqliteAdapter.list('checkpoints', {
|
|
653
|
+
filters: [
|
|
654
|
+
{
|
|
655
|
+
field: 'task_id',
|
|
656
|
+
operator: 'eq',
|
|
657
|
+
value: taskId
|
|
658
|
+
},
|
|
659
|
+
{
|
|
660
|
+
field: 'runtime_state_hash',
|
|
661
|
+
operator: 'eq',
|
|
662
|
+
value: runtimeHash
|
|
663
|
+
},
|
|
664
|
+
{
|
|
665
|
+
field: 'durable_state_hash',
|
|
666
|
+
operator: 'eq',
|
|
667
|
+
value: durableHash
|
|
668
|
+
}
|
|
669
|
+
],
|
|
670
|
+
limit: 1
|
|
671
|
+
});
|
|
672
|
+
if (rows.length === 0) {
|
|
673
|
+
return null;
|
|
674
|
+
}
|
|
675
|
+
return this.deserializeCheckpointMetadata(rows[0]);
|
|
676
|
+
} catch (error) {
|
|
677
|
+
const err = error;
|
|
678
|
+
logger.error('Failed to find checkpoint by hash', err, {
|
|
679
|
+
taskId
|
|
680
|
+
});
|
|
681
|
+
return null;
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
async findLatestCheckpoint(taskId) {
|
|
685
|
+
try {
|
|
686
|
+
const rows = await this.sqliteAdapter.list('checkpoints', {
|
|
687
|
+
filters: [
|
|
688
|
+
{
|
|
689
|
+
field: 'task_id',
|
|
690
|
+
operator: 'eq',
|
|
691
|
+
value: taskId
|
|
692
|
+
},
|
|
693
|
+
{
|
|
694
|
+
field: 'status',
|
|
695
|
+
operator: 'eq',
|
|
696
|
+
value: "completed"
|
|
697
|
+
}
|
|
698
|
+
],
|
|
699
|
+
orderBy: 'created_at',
|
|
700
|
+
order: 'desc',
|
|
701
|
+
limit: 1
|
|
702
|
+
});
|
|
703
|
+
if (rows.length === 0) {
|
|
704
|
+
return null;
|
|
705
|
+
}
|
|
706
|
+
return this.deserializeCheckpointMetadata(rows[0]);
|
|
707
|
+
} catch (error) {
|
|
708
|
+
const err = error;
|
|
709
|
+
logger.error('Failed to find latest checkpoint', err, {
|
|
710
|
+
taskId
|
|
711
|
+
});
|
|
712
|
+
return null;
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
async storeCheckpointMetadata(metadata) {
|
|
716
|
+
try {
|
|
717
|
+
await this.sqliteAdapter.insert('checkpoints', {
|
|
718
|
+
checkpoint_id: metadata.checkpointId,
|
|
719
|
+
task_id: metadata.taskId,
|
|
720
|
+
trigger: metadata.trigger,
|
|
721
|
+
status: metadata.status,
|
|
722
|
+
runtime_state_hash: metadata.runtimeStateHash,
|
|
723
|
+
durable_state_hash: metadata.durableStateHash,
|
|
724
|
+
created_at: metadata.createdAt.toISOString(),
|
|
725
|
+
completed_at: metadata.completedAt?.toISOString(),
|
|
726
|
+
error: metadata.error,
|
|
727
|
+
metadata: JSON.stringify(metadata.metadata || {})
|
|
728
|
+
});
|
|
729
|
+
logger.debug('Checkpoint metadata stored', {
|
|
730
|
+
checkpointId: metadata.checkpointId
|
|
731
|
+
});
|
|
732
|
+
} catch (error) {
|
|
733
|
+
const err = error;
|
|
734
|
+
logger.error('Failed to store checkpoint metadata', err, {
|
|
735
|
+
checkpointId: metadata.checkpointId
|
|
736
|
+
});
|
|
737
|
+
throw new StandardError(ErrorCode.DB_QUERY_FAILED, 'Failed to store checkpoint metadata', {
|
|
738
|
+
checkpointId: metadata.checkpointId
|
|
739
|
+
}, err);
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
async updateCheckpointMetadata(metadata) {
|
|
743
|
+
try {
|
|
744
|
+
await this.sqliteAdapter.update('checkpoints', metadata.checkpointId, {
|
|
745
|
+
status: metadata.status,
|
|
746
|
+
completed_at: metadata.completedAt?.toISOString(),
|
|
747
|
+
error: metadata.error
|
|
748
|
+
});
|
|
749
|
+
} catch (error) {
|
|
750
|
+
// If update fails, try insert (first time)
|
|
751
|
+
await this.storeCheckpointMetadata(metadata);
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
deserializeCheckpointMetadata(row) {
|
|
755
|
+
return {
|
|
756
|
+
checkpointId: row.checkpoint_id,
|
|
757
|
+
taskId: row.task_id,
|
|
758
|
+
trigger: row.trigger,
|
|
759
|
+
status: row.status,
|
|
760
|
+
runtimeStateHash: row.runtime_state_hash,
|
|
761
|
+
durableStateHash: row.durable_state_hash,
|
|
762
|
+
createdAt: new Date(row.created_at),
|
|
763
|
+
completedAt: row.completed_at ? new Date(row.completed_at) : undefined,
|
|
764
|
+
error: row.error,
|
|
765
|
+
metadata: row.metadata ? JSON.parse(row.metadata) : undefined
|
|
766
|
+
};
|
|
767
|
+
}
|
|
768
|
+
async createCheckpointTables() {
|
|
769
|
+
try {
|
|
770
|
+
// Create checkpoints table
|
|
771
|
+
await this.sqliteAdapter.raw(`
|
|
772
|
+
CREATE TABLE IF NOT EXISTS checkpoints (
|
|
773
|
+
checkpoint_id TEXT PRIMARY KEY,
|
|
774
|
+
task_id TEXT NOT NULL,
|
|
775
|
+
trigger TEXT NOT NULL,
|
|
776
|
+
status TEXT NOT NULL,
|
|
777
|
+
runtime_state_hash TEXT NOT NULL,
|
|
778
|
+
durable_state_hash TEXT NOT NULL,
|
|
779
|
+
created_at TEXT NOT NULL,
|
|
780
|
+
completed_at TEXT,
|
|
781
|
+
error TEXT,
|
|
782
|
+
metadata TEXT
|
|
783
|
+
)
|
|
784
|
+
`, []);
|
|
785
|
+
// Create checkpoint_data table for storing state JSON
|
|
786
|
+
await this.sqliteAdapter.raw(`
|
|
787
|
+
CREATE TABLE IF NOT EXISTS checkpoint_data (
|
|
788
|
+
key TEXT PRIMARY KEY,
|
|
789
|
+
value TEXT NOT NULL
|
|
790
|
+
)
|
|
791
|
+
`, []);
|
|
792
|
+
// Create indexes
|
|
793
|
+
await this.sqliteAdapter.raw(`
|
|
794
|
+
CREATE INDEX IF NOT EXISTS idx_checkpoints_task_id ON checkpoints(task_id)
|
|
795
|
+
`, []);
|
|
796
|
+
await this.sqliteAdapter.raw(`
|
|
797
|
+
CREATE INDEX IF NOT EXISTS idx_checkpoints_status ON checkpoints(status)
|
|
798
|
+
`, []);
|
|
799
|
+
await this.sqliteAdapter.raw(`
|
|
800
|
+
CREATE INDEX IF NOT EXISTS idx_checkpoints_created_at ON checkpoints(created_at)
|
|
801
|
+
`, []);
|
|
802
|
+
logger.info('Checkpoint tables created successfully');
|
|
803
|
+
} catch (error) {
|
|
804
|
+
const err = error;
|
|
805
|
+
logger.error('Failed to create checkpoint tables', err);
|
|
806
|
+
throw new StandardError(ErrorCode.DB_QUERY_FAILED, 'Failed to create checkpoint tables', {}, err);
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
startPeriodicCheckpoints() {
|
|
810
|
+
this.periodicCheckpointTimer = setInterval(async ()=>{
|
|
811
|
+
try {
|
|
812
|
+
logger.debug('Running periodic checkpoint cleanup');
|
|
813
|
+
await this.cleanupOldCheckpoints();
|
|
814
|
+
} catch (error) {
|
|
815
|
+
const err = error;
|
|
816
|
+
logger.error('Periodic checkpoint cleanup failed', err);
|
|
817
|
+
}
|
|
818
|
+
}, this.config.periodicInterval);
|
|
819
|
+
logger.info('Periodic checkpoints started', {
|
|
820
|
+
interval: this.config.periodicInterval
|
|
821
|
+
});
|
|
822
|
+
}
|
|
823
|
+
ensureInitialized() {
|
|
824
|
+
if (!this.initialized) {
|
|
825
|
+
throw new StandardError(ErrorCode.CONFIGURATION_ERROR, 'CheckpointManager not initialized. Call initialize() first.', {});
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
/**
|
|
830
|
+
* Export convenience functions
|
|
831
|
+
*/ /**
|
|
832
|
+
* Create a checkpoint manager instance
|
|
833
|
+
*/ export function createCheckpointManager(dbService, config) {
|
|
834
|
+
return new CheckpointManager(dbService, config);
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
//# sourceMappingURL=checkpoint-manager.js.map
|