claude-flow-novice 2.15.3 → 2.15.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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-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 +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-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 +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/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 +16 -2
- 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 +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-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 +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-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/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/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/package.json +201 -177
- package/readme/README.md +19 -4
- 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/.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 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/lib/idempotent-write.ts"],"sourcesContent":["/**\r\n * Idempotent Write Utility\r\n *\r\n * Provides content-based deduplication for metrics logging using SHA256 hashing.\r\n * Part of Task 2.3: Unified Metrics and Execution Logging\r\n *\r\n * Features:\r\n * - Content-based idempotency keys (prevents duplicate metrics)\r\n * - TTL-based cleanup (24-hour retention)\r\n * - Atomic write tracking across databases\r\n */\r\n\r\nimport * as crypto from 'crypto';\r\nimport { IDatabaseAdapter, OperationResult } from './database-service/types.js';\r\nimport { createLogger } from './logging.js';\r\n\r\nconst logger = createLogger('idempotent-write');\r\n\r\n/**\r\n * Execution metrics interface (must match ExecutionMetrics in metrics-logger.ts)\r\n */\r\nexport interface ExecutionMetrics {\r\n id?: string;\r\n timestamp: Date;\r\n agent_id: string;\r\n skill_id?: string;\r\n task_id: string;\r\n duration_ms: number;\r\n tokens_used: number;\r\n cost_usd: number;\r\n status: 'success' | 'failure' | 'timeout' | 'cancelled';\r\n error_message?: string;\r\n metadata?: Record<string, any>;\r\n}\r\n\r\n/**\r\n * Idempotency key record\r\n */\r\nexport interface IdempotencyKey {\r\n key: string;\r\n metrics_id?: string;\r\n written_at: Date;\r\n expires_at: Date;\r\n}\r\n\r\n/**\r\n * Default TTL for idempotency keys (24 hours)\r\n */\r\nconst DEFAULT_TTL_MS = 24 * 60 * 60 * 1000;\r\n\r\n/**\r\n * Create idempotency key from execution metrics\r\n *\r\n * Key is based on: agent_id + task_id + timestamp + duration_ms\r\n * This combination ensures uniqueness while allowing retries to be detected\r\n *\r\n * @param metrics - Execution metrics to create key from\r\n * @returns SHA256 hash as idempotency key\r\n */\r\nexport function createIdempotentKey(metrics: ExecutionMetrics): string {\r\n // Normalize timestamp to ISO string for consistent hashing\r\n const timestampStr = metrics.timestamp instanceof Date\r\n ? metrics.timestamp.toISOString()\r\n : new Date(metrics.timestamp).toISOString();\r\n\r\n // Build content string for hashing\r\n const content = [\r\n metrics.agent_id,\r\n metrics.task_id,\r\n timestampStr,\r\n metrics.duration_ms.toString(),\r\n metrics.status,\r\n ].join(':');\r\n\r\n // Generate SHA256 hash\r\n const hash = crypto.createHash('sha256').update(content).digest('hex');\r\n\r\n logger.debug('Created idempotency key', {\r\n agent_id: metrics.agent_id,\r\n task_id: metrics.task_id,\r\n key: hash.substring(0, 16) + '...', // Log truncated key\r\n });\r\n\r\n return hash;\r\n}\r\n\r\n/**\r\n * Check if metrics have already been written\r\n *\r\n * @param key - Idempotency key to check\r\n * @param db - Database adapter\r\n * @returns True if already written, false otherwise\r\n */\r\nexport async function hasBeenWritten(\r\n key: string,\r\n db: IDatabaseAdapter\r\n): Promise<boolean> {\r\n try {\r\n // Query idempotency_keys table\r\n const result = await db.get<IdempotencyKey>(`idempotency_keys:${key}`);\r\n\r\n if (!result) {\r\n logger.debug('Idempotency key not found', { key: key.substring(0, 16) + '...' });\r\n return false;\r\n }\r\n\r\n // Check if key has expired\r\n const expiresAt = new Date(result.expires_at);\r\n const now = new Date();\r\n\r\n if (expiresAt < now) {\r\n logger.debug('Idempotency key expired', {\r\n key: key.substring(0, 16) + '...',\r\n expired_at: expiresAt.toISOString(),\r\n });\r\n return false;\r\n }\r\n\r\n logger.debug('Idempotency key found', {\r\n key: key.substring(0, 16) + '...',\r\n written_at: result.written_at,\r\n });\r\n\r\n return true;\r\n } catch (error) {\r\n logger.error('Failed to check idempotency key', {\r\n key: key.substring(0, 16) + '...',\r\n error: error instanceof Error ? error.message : String(error),\r\n });\r\n\r\n // On error, assume not written to allow retry\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Mark metrics as written\r\n *\r\n * @param key - Idempotency key\r\n * @param db - Database adapter\r\n * @param metricsId - Optional metrics ID to link\r\n * @param ttlMs - Time-to-live in milliseconds (default: 24 hours)\r\n */\r\nexport async function markWritten(\r\n key: string,\r\n db: IDatabaseAdapter,\r\n metricsId?: string,\r\n ttlMs: number = DEFAULT_TTL_MS\r\n): Promise<void> {\r\n try {\r\n const now = new Date();\r\n const expiresAt = new Date(now.getTime() + ttlMs);\r\n\r\n const idempotencyRecord: IdempotencyKey = {\r\n key,\r\n metrics_id: metricsId,\r\n written_at: now,\r\n expires_at: expiresAt,\r\n };\r\n\r\n // Insert into idempotency_keys table\r\n await db.insert('idempotency_keys', idempotencyRecord);\r\n\r\n logger.debug('Marked idempotency key as written', {\r\n key: key.substring(0, 16) + '...',\r\n metrics_id: metricsId,\r\n expires_at: expiresAt.toISOString(),\r\n });\r\n } catch (error) {\r\n logger.error('Failed to mark idempotency key', {\r\n key: key.substring(0, 16) + '...',\r\n error: error instanceof Error ? error.message : String(error),\r\n });\r\n\r\n throw error;\r\n }\r\n}\r\n\r\n/**\r\n * Batch check for written metrics\r\n *\r\n * @param keys - Array of idempotency keys\r\n * @param db - Database adapter\r\n * @returns Map of key -> boolean (written status)\r\n */\r\nexport async function batchCheckWritten(\r\n keys: string[],\r\n db: IDatabaseAdapter\r\n): Promise<Map<string, boolean>> {\r\n const results = new Map<string, boolean>();\r\n\r\n try {\r\n // Check all keys in parallel\r\n const checks = keys.map(async (key) => {\r\n const written = await hasBeenWritten(key, db);\r\n return { key, written };\r\n });\r\n\r\n const checkResults = await Promise.all(checks);\r\n\r\n // Build result map\r\n checkResults.forEach(({ key, written }) => {\r\n results.set(key, written);\r\n });\r\n\r\n logger.debug('Batch idempotency check complete', {\r\n total_keys: keys.length,\r\n already_written: Array.from(results.values()).filter(v => v).length,\r\n });\r\n\r\n return results;\r\n } catch (error) {\r\n logger.error('Failed to batch check idempotency keys', {\r\n total_keys: keys.length,\r\n error: error instanceof Error ? error.message : String(error),\r\n });\r\n\r\n throw error;\r\n }\r\n}\r\n\r\n/**\r\n * Batch mark metrics as written\r\n *\r\n * @param entries - Array of { key, metricsId? } entries\r\n * @param db - Database adapter\r\n * @param ttlMs - Time-to-live in milliseconds (default: 24 hours)\r\n */\r\nexport async function batchMarkWritten(\r\n entries: Array<{ key: string; metricsId?: string }>,\r\n db: IDatabaseAdapter,\r\n ttlMs: number = DEFAULT_TTL_MS\r\n): Promise<void> {\r\n try {\r\n const now = new Date();\r\n const expiresAt = new Date(now.getTime() + ttlMs);\r\n\r\n const records: IdempotencyKey[] = entries.map(({ key, metricsId }) => ({\r\n key,\r\n metrics_id: metricsId,\r\n written_at: now,\r\n expires_at: expiresAt,\r\n }));\r\n\r\n // Batch insert\r\n await db.insertMany('idempotency_keys', records);\r\n\r\n logger.debug('Batch marked idempotency keys as written', {\r\n total_keys: entries.length,\r\n expires_at: expiresAt.toISOString(),\r\n });\r\n } catch (error) {\r\n logger.error('Failed to batch mark idempotency keys', {\r\n total_keys: entries.length,\r\n error: error instanceof Error ? error.message : String(error),\r\n });\r\n\r\n throw error;\r\n }\r\n}\r\n\r\n/**\r\n * Cleanup expired idempotency keys\r\n *\r\n * @param db - Database adapter\r\n * @returns Number of keys deleted\r\n */\r\nexport async function cleanupExpiredKeys(db: IDatabaseAdapter): Promise<number> {\r\n try {\r\n const now = new Date();\r\n\r\n // Query for expired keys\r\n const expiredKeys = await db.query<IdempotencyKey>('idempotency_keys', [\r\n {\r\n field: 'expires_at' as keyof IdempotencyKey,\r\n operator: 'lt',\r\n value: now,\r\n },\r\n ]);\r\n\r\n // Delete expired keys\r\n let deletedCount = 0;\r\n for (const key of expiredKeys) {\r\n await db.delete('idempotency_keys', key.key);\r\n deletedCount++;\r\n }\r\n\r\n logger.info('Cleaned up expired idempotency keys', {\r\n deleted_count: deletedCount,\r\n });\r\n\r\n return deletedCount;\r\n } catch (error) {\r\n logger.error('Failed to cleanup expired idempotency keys', {\r\n error: error instanceof Error ? error.message : String(error),\r\n });\r\n\r\n throw error;\r\n }\r\n}\r\n\r\n/**\r\n * Validate cost accuracy (within $0.001 precision)\r\n *\r\n * @param cost - Cost value to validate\r\n * @returns True if cost is accurate to $0.001\r\n */\r\nexport function validateCostAccuracy(cost: number): boolean {\r\n const rounded = parseFloat(cost.toFixed(3));\r\n return Math.abs(cost - rounded) < 0.0001;\r\n}\r\n\r\n/**\r\n * Round cost to $0.001 precision\r\n *\r\n * Uses standard \"round half up\" behavior for consistent rounding.\r\n *\r\n * @param cost - Cost value to round\r\n * @returns Cost rounded to 3 decimal places\r\n */\r\nexport function roundCost(cost: number): number {\r\n // Use Math.round for proper \"round half up\" behavior\r\n // Multiply by 1000, round, then divide by 1000 for $0.001 precision\r\n return Math.round(cost * 1000) / 1000;\r\n}\r\n"],"names":["crypto","createLogger","logger","DEFAULT_TTL_MS","createIdempotentKey","metrics","timestampStr","timestamp","Date","toISOString","content","agent_id","task_id","duration_ms","toString","status","join","hash","createHash","update","digest","debug","key","substring","hasBeenWritten","db","result","get","expiresAt","expires_at","now","expired_at","written_at","error","Error","message","String","markWritten","metricsId","ttlMs","getTime","idempotencyRecord","metrics_id","insert","batchCheckWritten","keys","results","Map","checks","map","written","checkResults","Promise","all","forEach","set","total_keys","length","already_written","Array","from","values","filter","v","batchMarkWritten","entries","records","insertMany","cleanupExpiredKeys","expiredKeys","query","field","operator","value","deletedCount","delete","info","deleted_count","validateCostAccuracy","cost","rounded","parseFloat","toFixed","Math","abs","roundCost","round"],"mappings":"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"}
|
|
@@ -0,0 +1,522 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Integration Schema Validator
|
|
3
|
+
*
|
|
4
|
+
* Task: P2-3.2 - JSON Schema Validation Enforcement
|
|
5
|
+
* Enforces JSON Schema validation at all 47 integration points
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
8
|
+
* - Automatic validation at data boundaries
|
|
9
|
+
* - Schema registry with versioning
|
|
10
|
+
* - Migration support between schema versions
|
|
11
|
+
* - Performance: <50ms validation, <100ms schema loading
|
|
12
|
+
* - Comprehensive error reporting with StandardError
|
|
13
|
+
*
|
|
14
|
+
* @module integration-schema-validator
|
|
15
|
+
*/ import Ajv from 'ajv';
|
|
16
|
+
import addFormats from 'ajv-formats';
|
|
17
|
+
import { StandardError, ErrorCode } from './errors.js';
|
|
18
|
+
import { getGlobalLogger } from './logging.js';
|
|
19
|
+
import fs from 'fs/promises';
|
|
20
|
+
import path from 'path';
|
|
21
|
+
const logger = getGlobalLogger();
|
|
22
|
+
// ============================================================================
|
|
23
|
+
// Integration Categories (6 categories, 47 points total)
|
|
24
|
+
// ============================================================================
|
|
25
|
+
const INTEGRATION_CATEGORIES = [
|
|
26
|
+
'database-handoffs',
|
|
27
|
+
'file-operations',
|
|
28
|
+
'cfn-loop-communication',
|
|
29
|
+
'phase4-workflow',
|
|
30
|
+
'api-layer',
|
|
31
|
+
'data-format-transformations'
|
|
32
|
+
];
|
|
33
|
+
// ============================================================================
|
|
34
|
+
// IntegrationSchemaValidator Class
|
|
35
|
+
// ============================================================================
|
|
36
|
+
export class IntegrationSchemaValidator {
|
|
37
|
+
config;
|
|
38
|
+
ajv;
|
|
39
|
+
schemaCache;
|
|
40
|
+
migrations;
|
|
41
|
+
initialized = false;
|
|
42
|
+
constructor(config){
|
|
43
|
+
this.config = {
|
|
44
|
+
schemaPath: config.schemaPath,
|
|
45
|
+
enableCache: config.enableCache ?? true,
|
|
46
|
+
strictMode: config.strictMode ?? true,
|
|
47
|
+
maxCacheSize: config.maxCacheSize ?? 1000,
|
|
48
|
+
schemaExtension: config.schemaExtension ?? '.schema.json'
|
|
49
|
+
};
|
|
50
|
+
// Initialize Ajv with formats support
|
|
51
|
+
this.ajv = new Ajv({
|
|
52
|
+
allErrors: true,
|
|
53
|
+
strict: this.config.strictMode,
|
|
54
|
+
validateFormats: true,
|
|
55
|
+
verbose: true
|
|
56
|
+
});
|
|
57
|
+
addFormats(this.ajv); // Add format validators (date-time, email, uri, etc.)
|
|
58
|
+
this.schemaCache = new Map();
|
|
59
|
+
this.migrations = {};
|
|
60
|
+
logger.debug('IntegrationSchemaValidator initialized', {
|
|
61
|
+
schemaPath: this.config.schemaPath,
|
|
62
|
+
enableCache: this.config.enableCache,
|
|
63
|
+
strictMode: this.config.strictMode
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Initialize validator by loading all schemas
|
|
68
|
+
*/ async initialize() {
|
|
69
|
+
if (this.initialized) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
try {
|
|
73
|
+
// Verify schema directory exists
|
|
74
|
+
await fs.access(this.config.schemaPath);
|
|
75
|
+
// Load all schemas from directory
|
|
76
|
+
const categories = await this.loadSchemaDirectory();
|
|
77
|
+
logger.info('Schema validator initialized', {
|
|
78
|
+
categories: categories.length,
|
|
79
|
+
schemasLoaded: this.schemaCache.size
|
|
80
|
+
});
|
|
81
|
+
this.initialized = true;
|
|
82
|
+
} catch (error) {
|
|
83
|
+
logger.error('Failed to initialize schema validator', error, {
|
|
84
|
+
schemaPath: this.config.schemaPath
|
|
85
|
+
});
|
|
86
|
+
throw new StandardError(ErrorCode.CONFIGURATION_ERROR, `Failed to initialize schema validator: ${error.message}`, {
|
|
87
|
+
schemaPath: this.config.schemaPath
|
|
88
|
+
}, error);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Shutdown validator and clear caches
|
|
93
|
+
*/ async shutdown() {
|
|
94
|
+
this.schemaCache.clear();
|
|
95
|
+
this.migrations = {};
|
|
96
|
+
this.initialized = false;
|
|
97
|
+
logger.debug('Schema validator shutdown complete');
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Validate data against a schema
|
|
101
|
+
*
|
|
102
|
+
* @param data - Data to validate
|
|
103
|
+
* @param schemaId - Schema identifier (e.g., "database-handoffs/pattern-deployment")
|
|
104
|
+
* @param version - Schema version (defaults to latest)
|
|
105
|
+
* @throws StandardError with VALIDATION_FAILED code if validation fails
|
|
106
|
+
*/ async validate(data, schemaId, version) {
|
|
107
|
+
this.ensureInitialized();
|
|
108
|
+
const startTime = Date.now();
|
|
109
|
+
try {
|
|
110
|
+
// Get schema validator
|
|
111
|
+
const schema = await this.getSchema(schemaId, version);
|
|
112
|
+
// Perform validation
|
|
113
|
+
const valid = schema.validator(data);
|
|
114
|
+
if (!valid) {
|
|
115
|
+
const errors = this.formatErrors(schema.validator.errors || []);
|
|
116
|
+
logger.warn('Schema validation failed', {
|
|
117
|
+
schemaId,
|
|
118
|
+
version: schema.version,
|
|
119
|
+
errorCount: errors.length,
|
|
120
|
+
duration: Date.now() - startTime
|
|
121
|
+
});
|
|
122
|
+
throw new StandardError(ErrorCode.VALIDATION_FAILED, `Schema validation failed for ${schemaId}@${schema.version}`, {
|
|
123
|
+
schemaId,
|
|
124
|
+
version: schema.version,
|
|
125
|
+
errors,
|
|
126
|
+
suggestions: this.generateSuggestions(errors, data)
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
logger.debug('Schema validation succeeded', {
|
|
130
|
+
schemaId,
|
|
131
|
+
version: schema.version,
|
|
132
|
+
duration: Date.now() - startTime
|
|
133
|
+
});
|
|
134
|
+
} catch (error) {
|
|
135
|
+
if (error instanceof StandardError) {
|
|
136
|
+
throw error;
|
|
137
|
+
}
|
|
138
|
+
throw new StandardError(ErrorCode.VALIDATION_FAILED, `Validation error: ${error.message}`, {
|
|
139
|
+
schemaId,
|
|
140
|
+
version
|
|
141
|
+
}, error);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Validate batch of records
|
|
146
|
+
*/ async validateBatch(records, schemaId, version, options = {}) {
|
|
147
|
+
this.ensureInitialized();
|
|
148
|
+
const result = {
|
|
149
|
+
valid: true,
|
|
150
|
+
totalRecords: records.length,
|
|
151
|
+
validRecords: 0,
|
|
152
|
+
invalidRecords: 0,
|
|
153
|
+
errors: []
|
|
154
|
+
};
|
|
155
|
+
for(let i = 0; i < records.length; i++){
|
|
156
|
+
try {
|
|
157
|
+
await this.validate(records[i], schemaId, version);
|
|
158
|
+
result.validRecords++;
|
|
159
|
+
} catch (error) {
|
|
160
|
+
result.invalidRecords++;
|
|
161
|
+
result.valid = false;
|
|
162
|
+
if (error instanceof StandardError) {
|
|
163
|
+
result.errors.push({
|
|
164
|
+
index: i,
|
|
165
|
+
errors: error.context?.errors || []
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
if (options.failFast) {
|
|
169
|
+
break;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
logger.info('Batch validation completed', {
|
|
174
|
+
schemaId,
|
|
175
|
+
version,
|
|
176
|
+
total: result.totalRecords,
|
|
177
|
+
valid: result.validRecords,
|
|
178
|
+
invalid: result.invalidRecords
|
|
179
|
+
});
|
|
180
|
+
return result;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Migrate data from one schema version to another
|
|
184
|
+
*/ async migrate(data, schemaId, fromVersion, toVersion) {
|
|
185
|
+
this.ensureInitialized();
|
|
186
|
+
const transition = `${fromVersion}->${toVersion}`;
|
|
187
|
+
const migrationFn = this.migrations[schemaId]?.[transition];
|
|
188
|
+
if (!migrationFn) {
|
|
189
|
+
// Check if migration is needed (same version)
|
|
190
|
+
if (fromVersion === toVersion) {
|
|
191
|
+
return data;
|
|
192
|
+
}
|
|
193
|
+
// No migration function registered
|
|
194
|
+
throw new StandardError(ErrorCode.CONFIGURATION_ERROR, `No migration available for ${schemaId} from ${fromVersion} to ${toVersion}`, {
|
|
195
|
+
schemaId,
|
|
196
|
+
fromVersion,
|
|
197
|
+
toVersion,
|
|
198
|
+
transition
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
try {
|
|
202
|
+
const migrated = await migrationFn(data, fromVersion, toVersion);
|
|
203
|
+
logger.info('Schema migration completed', {
|
|
204
|
+
schemaId,
|
|
205
|
+
fromVersion,
|
|
206
|
+
toVersion
|
|
207
|
+
});
|
|
208
|
+
return migrated;
|
|
209
|
+
} catch (error) {
|
|
210
|
+
throw new StandardError(ErrorCode.VALIDATION_FAILED, `Migration failed: ${error.message}`, {
|
|
211
|
+
schemaId,
|
|
212
|
+
fromVersion,
|
|
213
|
+
toVersion
|
|
214
|
+
}, error);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Register a migration function
|
|
219
|
+
*/ registerMigration(schemaId, fromVersion, toVersion, migrationFn) {
|
|
220
|
+
const transition = `${fromVersion}->${toVersion}`;
|
|
221
|
+
if (!this.migrations[schemaId]) {
|
|
222
|
+
this.migrations[schemaId] = {};
|
|
223
|
+
}
|
|
224
|
+
this.migrations[schemaId][transition] = migrationFn;
|
|
225
|
+
logger.debug('Migration registered', {
|
|
226
|
+
schemaId,
|
|
227
|
+
transition
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Get schema metadata
|
|
232
|
+
*/ async getSchema(schemaId, version) {
|
|
233
|
+
const cacheKey = `${schemaId}@${version || 'latest'}`;
|
|
234
|
+
// Check cache
|
|
235
|
+
if (this.config.enableCache && this.schemaCache.has(cacheKey)) {
|
|
236
|
+
return this.schemaCache.get(cacheKey);
|
|
237
|
+
}
|
|
238
|
+
// Load schema from file
|
|
239
|
+
const schema = await this.loadSchema(schemaId, version);
|
|
240
|
+
// Cache schema
|
|
241
|
+
if (this.config.enableCache) {
|
|
242
|
+
this.schemaCache.set(cacheKey, schema);
|
|
243
|
+
// Enforce cache size limit
|
|
244
|
+
if (this.schemaCache.size > this.config.maxCacheSize) {
|
|
245
|
+
const firstKey = this.schemaCache.keys().next().value;
|
|
246
|
+
this.schemaCache.delete(firstKey);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
return schema;
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Check if schema exists
|
|
253
|
+
*/ async hasSchema(schemaId, version) {
|
|
254
|
+
try {
|
|
255
|
+
await this.getSchema(schemaId, version);
|
|
256
|
+
return true;
|
|
257
|
+
} catch {
|
|
258
|
+
return false;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* List all available schemas
|
|
263
|
+
*/ async listSchemas(category) {
|
|
264
|
+
this.ensureInitialized();
|
|
265
|
+
const schemas = Array.from(this.schemaCache.keys()).map((key)=>key.split('@')[0]) // Remove version
|
|
266
|
+
.filter((id, index, self)=>self.indexOf(id) === index); // Unique
|
|
267
|
+
if (category) {
|
|
268
|
+
return schemas.filter((id)=>id.startsWith(`${category}/`));
|
|
269
|
+
}
|
|
270
|
+
return schemas;
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Get all available versions for a schema
|
|
274
|
+
*/ async getVersions(schemaId) {
|
|
275
|
+
const versions = Array.from(this.schemaCache.keys()).filter((key)=>key.startsWith(`${schemaId}@`)).map((key)=>key.split('@')[1]).filter((v)=>v !== 'latest');
|
|
276
|
+
// Also check filesystem for versions not yet cached
|
|
277
|
+
const schemaDir = path.join(this.config.schemaPath, schemaId);
|
|
278
|
+
try {
|
|
279
|
+
const files = await fs.readdir(schemaDir);
|
|
280
|
+
const fileVersions = files.filter((f)=>f.endsWith(this.config.schemaExtension)).map((f)=>{
|
|
281
|
+
const match = f.match(/v([\d.]+)/);
|
|
282
|
+
return match ? match[1] : null;
|
|
283
|
+
}).filter((v)=>v !== null);
|
|
284
|
+
// Merge and deduplicate
|
|
285
|
+
const allVersions = [
|
|
286
|
+
...new Set([
|
|
287
|
+
...versions,
|
|
288
|
+
...fileVersions
|
|
289
|
+
])
|
|
290
|
+
];
|
|
291
|
+
return allVersions.sort();
|
|
292
|
+
} catch {
|
|
293
|
+
return versions;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Get integration categories
|
|
298
|
+
*/ async getCategories() {
|
|
299
|
+
return [
|
|
300
|
+
...INTEGRATION_CATEGORIES
|
|
301
|
+
];
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* Get validator configuration
|
|
305
|
+
*/ getConfig() {
|
|
306
|
+
return {
|
|
307
|
+
...this.config
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
// ============================================================================
|
|
311
|
+
// Private Methods
|
|
312
|
+
// ============================================================================
|
|
313
|
+
ensureInitialized() {
|
|
314
|
+
if (!this.initialized) {
|
|
315
|
+
throw new StandardError(ErrorCode.CONFIGURATION_ERROR, 'Schema validator not initialized. Call initialize() first.', {
|
|
316
|
+
initialized: this.initialized
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
async loadSchemaDirectory() {
|
|
321
|
+
const loadedCategories = [];
|
|
322
|
+
for (const category of INTEGRATION_CATEGORIES){
|
|
323
|
+
const categoryPath = path.join(this.config.schemaPath, category);
|
|
324
|
+
try {
|
|
325
|
+
await fs.access(categoryPath);
|
|
326
|
+
await this.loadCategorySchemas(category);
|
|
327
|
+
loadedCategories.push(category);
|
|
328
|
+
} catch (error) {
|
|
329
|
+
logger.warn(`Category directory not found: ${category}`, {
|
|
330
|
+
categoryPath
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
return loadedCategories;
|
|
335
|
+
}
|
|
336
|
+
async loadCategorySchemas(category) {
|
|
337
|
+
const categoryPath = path.join(this.config.schemaPath, category);
|
|
338
|
+
try {
|
|
339
|
+
const entries = await fs.readdir(categoryPath, {
|
|
340
|
+
withFileTypes: true
|
|
341
|
+
});
|
|
342
|
+
for (const entry of entries){
|
|
343
|
+
if (entry.isDirectory()) {
|
|
344
|
+
// Schema subdirectory (e.g., pattern-deployment/)
|
|
345
|
+
const schemaName = entry.name;
|
|
346
|
+
const schemaId = `${category}/${schemaName}`;
|
|
347
|
+
await this.loadSchemaVersions(schemaId, path.join(categoryPath, schemaName));
|
|
348
|
+
} else if (entry.isFile() && entry.name.endsWith(this.config.schemaExtension)) {
|
|
349
|
+
// Direct schema file
|
|
350
|
+
const schemaName = entry.name.replace(this.config.schemaExtension, '');
|
|
351
|
+
const schemaId = `${category}/${schemaName}`;
|
|
352
|
+
await this.loadSchemaFile(schemaId, path.join(categoryPath, entry.name), '1.0.0');
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
} catch (error) {
|
|
356
|
+
logger.error(`Failed to load schemas for category: ${category}`, error, {
|
|
357
|
+
categoryPath
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
async loadSchemaVersions(schemaId, schemaDir) {
|
|
362
|
+
try {
|
|
363
|
+
const files = await fs.readdir(schemaDir);
|
|
364
|
+
for (const file of files){
|
|
365
|
+
if (file.endsWith(this.config.schemaExtension)) {
|
|
366
|
+
const versionMatch = file.match(/v([\d.]+)/);
|
|
367
|
+
const version = versionMatch ? versionMatch[1] : '1.0.0';
|
|
368
|
+
const filePath = path.join(schemaDir, file);
|
|
369
|
+
await this.loadSchemaFile(schemaId, filePath, version);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
} catch (error) {
|
|
373
|
+
logger.error(`Failed to load schema versions: ${schemaId}`, error, {
|
|
374
|
+
schemaDir
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
async loadSchemaFile(schemaId, filePath, version) {
|
|
379
|
+
try {
|
|
380
|
+
// Check if already loaded in cache
|
|
381
|
+
const cacheKey = `${schemaId}@${version}`;
|
|
382
|
+
if (this.schemaCache.has(cacheKey)) {
|
|
383
|
+
logger.debug('Schema already cached', {
|
|
384
|
+
schemaId,
|
|
385
|
+
version
|
|
386
|
+
});
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
const content = await fs.readFile(filePath, 'utf-8');
|
|
390
|
+
const schema = JSON.parse(content);
|
|
391
|
+
// Check if schema with this $id already exists in Ajv
|
|
392
|
+
const schemaKey = schema.$id || `${schemaId}/${version}`;
|
|
393
|
+
if (this.ajv.getSchema(schemaKey)) {
|
|
394
|
+
logger.debug('Schema already compiled in Ajv', {
|
|
395
|
+
schemaId,
|
|
396
|
+
version,
|
|
397
|
+
schemaKey
|
|
398
|
+
});
|
|
399
|
+
// Use existing compiled schema
|
|
400
|
+
const validator = this.ajv.getSchema(schemaKey);
|
|
401
|
+
const category = schemaId.split('/')[0];
|
|
402
|
+
const metadata = {
|
|
403
|
+
id: schemaId,
|
|
404
|
+
version,
|
|
405
|
+
category,
|
|
406
|
+
description: schema.description,
|
|
407
|
+
validator
|
|
408
|
+
};
|
|
409
|
+
this.schemaCache.set(cacheKey, metadata);
|
|
410
|
+
return;
|
|
411
|
+
}
|
|
412
|
+
// Compile schema with Ajv
|
|
413
|
+
const validator = this.ajv.compile(schema);
|
|
414
|
+
// Extract category from schemaId
|
|
415
|
+
const category = schemaId.split('/')[0];
|
|
416
|
+
const metadata = {
|
|
417
|
+
id: schemaId,
|
|
418
|
+
version,
|
|
419
|
+
category,
|
|
420
|
+
description: schema.description,
|
|
421
|
+
validator
|
|
422
|
+
};
|
|
423
|
+
// Cache with version
|
|
424
|
+
this.schemaCache.set(cacheKey, metadata);
|
|
425
|
+
logger.debug('Schema loaded', {
|
|
426
|
+
schemaId,
|
|
427
|
+
version,
|
|
428
|
+
filePath
|
|
429
|
+
});
|
|
430
|
+
} catch (error) {
|
|
431
|
+
logger.error(`Failed to load schema file: ${filePath}`, error, {
|
|
432
|
+
schemaId,
|
|
433
|
+
version
|
|
434
|
+
});
|
|
435
|
+
throw error;
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
async loadSchema(schemaId, version) {
|
|
439
|
+
const category = schemaId.split('/')[0];
|
|
440
|
+
const schemaName = schemaId.split('/').slice(1).join('/');
|
|
441
|
+
// Determine file path
|
|
442
|
+
const categoryPath = path.join(this.config.schemaPath, category);
|
|
443
|
+
const schemaPath = path.join(categoryPath, schemaName);
|
|
444
|
+
// Try versioned schema directory
|
|
445
|
+
try {
|
|
446
|
+
const versionedFile = version ? `v${version}${this.config.schemaExtension}` : `v1.0.0${this.config.schemaExtension}`;
|
|
447
|
+
const filePath = path.join(schemaPath, versionedFile);
|
|
448
|
+
await fs.access(filePath);
|
|
449
|
+
const actualVersion = version || '1.0.0';
|
|
450
|
+
await this.loadSchemaFile(schemaId, filePath, actualVersion);
|
|
451
|
+
return this.schemaCache.get(`${schemaId}@${actualVersion}`);
|
|
452
|
+
} catch {
|
|
453
|
+
// Try direct schema file
|
|
454
|
+
const directFile = path.join(categoryPath, `${schemaName}${this.config.schemaExtension}`);
|
|
455
|
+
try {
|
|
456
|
+
await fs.access(directFile);
|
|
457
|
+
const actualVersion = version || '1.0.0';
|
|
458
|
+
await this.loadSchemaFile(schemaId, directFile, actualVersion);
|
|
459
|
+
return this.schemaCache.get(`${schemaId}@${actualVersion}`);
|
|
460
|
+
} catch (error) {
|
|
461
|
+
throw new StandardError(ErrorCode.FILE_NOT_FOUND, `Schema not found: ${schemaId}${version ? `@${version}` : ''}`, {
|
|
462
|
+
schemaId,
|
|
463
|
+
version,
|
|
464
|
+
searchPaths: [
|
|
465
|
+
schemaPath,
|
|
466
|
+
directFile
|
|
467
|
+
]
|
|
468
|
+
}, error);
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
formatErrors(errors) {
|
|
473
|
+
return errors.map((error)=>({
|
|
474
|
+
path: error.instancePath || error.schemaPath,
|
|
475
|
+
message: error.message || 'Validation failed',
|
|
476
|
+
keyword: error.keyword,
|
|
477
|
+
params: error.params
|
|
478
|
+
}));
|
|
479
|
+
}
|
|
480
|
+
generateSuggestions(errors, data) {
|
|
481
|
+
const suggestions = [];
|
|
482
|
+
for (const error of errors){
|
|
483
|
+
if (error.keyword === 'required' && error.params?.missingProperty) {
|
|
484
|
+
const missing = error.params.missingProperty;
|
|
485
|
+
suggestions.push(missing);
|
|
486
|
+
// Check for typos in data keys
|
|
487
|
+
const dataKeys = Object.keys(data);
|
|
488
|
+
const similar = dataKeys.filter((key)=>this.levenshteinDistance(key, missing) <= 2);
|
|
489
|
+
if (similar.length > 0) {
|
|
490
|
+
suggestions.push(`Did you mean: ${similar.join(', ')}?`);
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
return [
|
|
495
|
+
...new Set(suggestions)
|
|
496
|
+
]; // Deduplicate
|
|
497
|
+
}
|
|
498
|
+
levenshteinDistance(a, b) {
|
|
499
|
+
const matrix = [];
|
|
500
|
+
for(let i = 0; i <= b.length; i++){
|
|
501
|
+
matrix[i] = [
|
|
502
|
+
i
|
|
503
|
+
];
|
|
504
|
+
}
|
|
505
|
+
for(let j = 0; j <= a.length; j++){
|
|
506
|
+
matrix[0][j] = j;
|
|
507
|
+
}
|
|
508
|
+
for(let i = 1; i <= b.length; i++){
|
|
509
|
+
for(let j = 1; j <= a.length; j++){
|
|
510
|
+
if (b.charAt(i - 1) === a.charAt(j - 1)) {
|
|
511
|
+
matrix[i][j] = matrix[i - 1][j - 1];
|
|
512
|
+
} else {
|
|
513
|
+
matrix[i][j] = Math.min(matrix[i - 1][j - 1] + 1, matrix[i][j - 1] + 1, matrix[i - 1][j] + 1 // deletion
|
|
514
|
+
);
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
return matrix[b.length][a.length];
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
//# sourceMappingURL=integration-schema-validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/lib/integration-schema-validator.ts"],"sourcesContent":["/**\r\n * Integration Schema Validator\r\n *\r\n * Task: P2-3.2 - JSON Schema Validation Enforcement\r\n * Enforces JSON Schema validation at all 47 integration points\r\n *\r\n * Features:\r\n * - Automatic validation at data boundaries\r\n * - Schema registry with versioning\r\n * - Migration support between schema versions\r\n * - Performance: <50ms validation, <100ms schema loading\r\n * - Comprehensive error reporting with StandardError\r\n *\r\n * @module integration-schema-validator\r\n */\r\n\r\nimport Ajv, { ValidateFunction, ErrorObject } from 'ajv';\r\nimport addFormats from 'ajv-formats';\r\nimport { StandardError, ErrorCode, createValidationError } from './errors.js';\r\nimport { getGlobalLogger } from './logging.js';\r\nimport fs from 'fs/promises';\r\nimport path from 'path';\r\n\r\nconst logger = getGlobalLogger();\r\n\r\n// ============================================================================\r\n// Type Definitions\r\n// ============================================================================\r\n\r\nexport interface SchemaValidatorConfig {\r\n /**\r\n * Path to directory containing JSON schemas\r\n */\r\n schemaPath: string;\r\n\r\n /**\r\n * Enable schema caching for performance\r\n * @default true\r\n */\r\n enableCache?: boolean;\r\n\r\n /**\r\n * Strict mode - fail on additional properties\r\n * @default true\r\n */\r\n strictMode?: boolean;\r\n\r\n /**\r\n * Maximum cache size (number of schemas)\r\n * @default 1000\r\n */\r\n maxCacheSize?: number;\r\n\r\n /**\r\n * Schema file extension\r\n * @default '.schema.json'\r\n */\r\n schemaExtension?: string;\r\n}\r\n\r\nexport interface ValidationResult {\r\n valid: boolean;\r\n errors?: ValidationError[];\r\n warnings?: string[];\r\n}\r\n\r\nexport interface ValidationError {\r\n path: string;\r\n message: string;\r\n keyword?: string;\r\n params?: Record<string, any>;\r\n}\r\n\r\nexport interface BatchValidationResult {\r\n valid: boolean;\r\n totalRecords: number;\r\n validRecords: number;\r\n invalidRecords: number;\r\n errors: Array<{\r\n index: number;\r\n errors: ValidationError[];\r\n }>;\r\n}\r\n\r\nexport interface BatchValidationOptions {\r\n /**\r\n * Stop validation on first error\r\n * @default false\r\n */\r\n failFast?: boolean;\r\n\r\n /**\r\n * Include valid records in result\r\n * @default false\r\n */\r\n includeValidRecords?: boolean;\r\n}\r\n\r\nexport type MigrationFunction = (data: any, fromVersion: string, toVersion: string) => Promise<any>;\r\n\r\ninterface SchemaMetadata {\r\n id: string;\r\n version: string;\r\n category: string;\r\n description?: string;\r\n validator: ValidateFunction;\r\n}\r\n\r\ninterface MigrationRegistry {\r\n [schemaId: string]: {\r\n [transition: string]: MigrationFunction; // \"1.0.0->2.0.0\"\r\n };\r\n}\r\n\r\n// ============================================================================\r\n// Integration Categories (6 categories, 47 points total)\r\n// ============================================================================\r\n\r\nconst INTEGRATION_CATEGORIES = [\r\n 'database-handoffs', // 9 points\r\n 'file-operations', // 11 points\r\n 'cfn-loop-communication', // 8 points\r\n 'phase4-workflow', // 7 points\r\n 'api-layer', // 7 points\r\n 'data-format-transformations', // 5 points\r\n] as const;\r\n\r\nexport type IntegrationCategory = typeof INTEGRATION_CATEGORIES[number];\r\n\r\n// ============================================================================\r\n// IntegrationSchemaValidator Class\r\n// ============================================================================\r\n\r\nexport class IntegrationSchemaValidator {\r\n private config: Required<SchemaValidatorConfig>;\r\n private ajv: Ajv;\r\n private schemaCache: Map<string, SchemaMetadata>;\r\n private migrations: MigrationRegistry;\r\n private initialized: boolean = false;\r\n\r\n constructor(config: SchemaValidatorConfig) {\r\n this.config = {\r\n schemaPath: config.schemaPath,\r\n enableCache: config.enableCache ?? true,\r\n strictMode: config.strictMode ?? true,\r\n maxCacheSize: config.maxCacheSize ?? 1000,\r\n schemaExtension: config.schemaExtension ?? '.schema.json',\r\n };\r\n\r\n // Initialize Ajv with formats support\r\n this.ajv = new Ajv({\r\n allErrors: true, // Report all errors, not just first\r\n strict: this.config.strictMode,\r\n validateFormats: true,\r\n verbose: true, // Include schema and data in error messages\r\n });\r\n\r\n addFormats(this.ajv); // Add format validators (date-time, email, uri, etc.)\r\n\r\n this.schemaCache = new Map();\r\n this.migrations = {};\r\n\r\n logger.debug('IntegrationSchemaValidator initialized', {\r\n schemaPath: this.config.schemaPath,\r\n enableCache: this.config.enableCache,\r\n strictMode: this.config.strictMode,\r\n });\r\n }\r\n\r\n /**\r\n * Initialize validator by loading all schemas\r\n */\r\n async initialize(): Promise<void> {\r\n if (this.initialized) {\r\n return;\r\n }\r\n\r\n try {\r\n // Verify schema directory exists\r\n await fs.access(this.config.schemaPath);\r\n\r\n // Load all schemas from directory\r\n const categories = await this.loadSchemaDirectory();\r\n\r\n logger.info('Schema validator initialized', {\r\n categories: categories.length,\r\n schemasLoaded: this.schemaCache.size,\r\n });\r\n\r\n this.initialized = true;\r\n } catch (error) {\r\n logger.error('Failed to initialize schema validator', error as Error, {\r\n schemaPath: this.config.schemaPath,\r\n });\r\n\r\n throw new StandardError(\r\n ErrorCode.CONFIGURATION_ERROR,\r\n `Failed to initialize schema validator: ${(error as Error).message}`,\r\n { schemaPath: this.config.schemaPath },\r\n error as Error\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Shutdown validator and clear caches\r\n */\r\n async shutdown(): Promise<void> {\r\n this.schemaCache.clear();\r\n this.migrations = {};\r\n this.initialized = false;\r\n\r\n logger.debug('Schema validator shutdown complete');\r\n }\r\n\r\n /**\r\n * Validate data against a schema\r\n *\r\n * @param data - Data to validate\r\n * @param schemaId - Schema identifier (e.g., \"database-handoffs/pattern-deployment\")\r\n * @param version - Schema version (defaults to latest)\r\n * @throws StandardError with VALIDATION_FAILED code if validation fails\r\n */\r\n async validate(data: any, schemaId: string, version?: string): Promise<void> {\r\n this.ensureInitialized();\r\n\r\n const startTime = Date.now();\r\n\r\n try {\r\n // Get schema validator\r\n const schema = await this.getSchema(schemaId, version);\r\n\r\n // Perform validation\r\n const valid = schema.validator(data);\r\n\r\n if (!valid) {\r\n const errors = this.formatErrors(schema.validator.errors || []);\r\n\r\n logger.warn('Schema validation failed', {\r\n schemaId,\r\n version: schema.version,\r\n errorCount: errors.length,\r\n duration: Date.now() - startTime,\r\n });\r\n\r\n throw new StandardError(\r\n ErrorCode.VALIDATION_FAILED,\r\n `Schema validation failed for ${schemaId}@${schema.version}`,\r\n {\r\n schemaId,\r\n version: schema.version,\r\n errors,\r\n suggestions: this.generateSuggestions(errors, data),\r\n }\r\n );\r\n }\r\n\r\n logger.debug('Schema validation succeeded', {\r\n schemaId,\r\n version: schema.version,\r\n duration: Date.now() - startTime,\r\n });\r\n } catch (error) {\r\n if (error instanceof StandardError) {\r\n throw error;\r\n }\r\n\r\n throw new StandardError(\r\n ErrorCode.VALIDATION_FAILED,\r\n `Validation error: ${(error as Error).message}`,\r\n { schemaId, version },\r\n error as Error\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Validate batch of records\r\n */\r\n async validateBatch(\r\n records: any[],\r\n schemaId: string,\r\n version?: string,\r\n options: BatchValidationOptions = {}\r\n ): Promise<BatchValidationResult> {\r\n this.ensureInitialized();\r\n\r\n const result: BatchValidationResult = {\r\n valid: true,\r\n totalRecords: records.length,\r\n validRecords: 0,\r\n invalidRecords: 0,\r\n errors: [],\r\n };\r\n\r\n for (let i = 0; i < records.length; i++) {\r\n try {\r\n await this.validate(records[i], schemaId, version);\r\n result.validRecords++;\r\n } catch (error) {\r\n result.invalidRecords++;\r\n result.valid = false;\r\n\r\n if (error instanceof StandardError) {\r\n result.errors.push({\r\n index: i,\r\n errors: error.context?.errors || [],\r\n });\r\n }\r\n\r\n if (options.failFast) {\r\n break;\r\n }\r\n }\r\n }\r\n\r\n logger.info('Batch validation completed', {\r\n schemaId,\r\n version,\r\n total: result.totalRecords,\r\n valid: result.validRecords,\r\n invalid: result.invalidRecords,\r\n });\r\n\r\n return result;\r\n }\r\n\r\n /**\r\n * Migrate data from one schema version to another\r\n */\r\n async migrate(\r\n data: any,\r\n schemaId: string,\r\n fromVersion: string,\r\n toVersion: string\r\n ): Promise<any> {\r\n this.ensureInitialized();\r\n\r\n const transition = `${fromVersion}->${toVersion}`;\r\n const migrationFn = this.migrations[schemaId]?.[transition];\r\n\r\n if (!migrationFn) {\r\n // Check if migration is needed (same version)\r\n if (fromVersion === toVersion) {\r\n return data;\r\n }\r\n\r\n // No migration function registered\r\n throw new StandardError(\r\n ErrorCode.CONFIGURATION_ERROR,\r\n `No migration available for ${schemaId} from ${fromVersion} to ${toVersion}`,\r\n { schemaId, fromVersion, toVersion, transition }\r\n );\r\n }\r\n\r\n try {\r\n const migrated = await migrationFn(data, fromVersion, toVersion);\r\n\r\n logger.info('Schema migration completed', {\r\n schemaId,\r\n fromVersion,\r\n toVersion,\r\n });\r\n\r\n return migrated;\r\n } catch (error) {\r\n throw new StandardError(\r\n ErrorCode.VALIDATION_FAILED,\r\n `Migration failed: ${(error as Error).message}`,\r\n { schemaId, fromVersion, toVersion },\r\n error as Error\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Register a migration function\r\n */\r\n registerMigration(\r\n schemaId: string,\r\n fromVersion: string,\r\n toVersion: string,\r\n migrationFn: MigrationFunction\r\n ): void {\r\n const transition = `${fromVersion}->${toVersion}`;\r\n\r\n if (!this.migrations[schemaId]) {\r\n this.migrations[schemaId] = {};\r\n }\r\n\r\n this.migrations[schemaId][transition] = migrationFn;\r\n\r\n logger.debug('Migration registered', { schemaId, transition });\r\n }\r\n\r\n /**\r\n * Get schema metadata\r\n */\r\n async getSchema(schemaId: string, version?: string): Promise<SchemaMetadata> {\r\n const cacheKey = `${schemaId}@${version || 'latest'}`;\r\n\r\n // Check cache\r\n if (this.config.enableCache && this.schemaCache.has(cacheKey)) {\r\n return this.schemaCache.get(cacheKey)!;\r\n }\r\n\r\n // Load schema from file\r\n const schema = await this.loadSchema(schemaId, version);\r\n\r\n // Cache schema\r\n if (this.config.enableCache) {\r\n this.schemaCache.set(cacheKey, schema);\r\n\r\n // Enforce cache size limit\r\n if (this.schemaCache.size > this.config.maxCacheSize) {\r\n const firstKey = this.schemaCache.keys().next().value;\r\n this.schemaCache.delete(firstKey);\r\n }\r\n }\r\n\r\n return schema;\r\n }\r\n\r\n /**\r\n * Check if schema exists\r\n */\r\n async hasSchema(schemaId: string, version?: string): Promise<boolean> {\r\n try {\r\n await this.getSchema(schemaId, version);\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n }\r\n\r\n /**\r\n * List all available schemas\r\n */\r\n async listSchemas(category?: IntegrationCategory): Promise<string[]> {\r\n this.ensureInitialized();\r\n\r\n const schemas = Array.from(this.schemaCache.keys())\r\n .map((key) => key.split('@')[0]) // Remove version\r\n .filter((id, index, self) => self.indexOf(id) === index); // Unique\r\n\r\n if (category) {\r\n return schemas.filter((id) => id.startsWith(`${category}/`));\r\n }\r\n\r\n return schemas;\r\n }\r\n\r\n /**\r\n * Get all available versions for a schema\r\n */\r\n async getVersions(schemaId: string): Promise<string[]> {\r\n const versions = Array.from(this.schemaCache.keys())\r\n .filter((key) => key.startsWith(`${schemaId}@`))\r\n .map((key) => key.split('@')[1])\r\n .filter((v) => v !== 'latest');\r\n\r\n // Also check filesystem for versions not yet cached\r\n const schemaDir = path.join(this.config.schemaPath, schemaId);\r\n\r\n try {\r\n const files = await fs.readdir(schemaDir);\r\n const fileVersions = files\r\n .filter((f) => f.endsWith(this.config.schemaExtension))\r\n .map((f) => {\r\n const match = f.match(/v([\\d.]+)/);\r\n return match ? match[1] : null;\r\n })\r\n .filter((v): v is string => v !== null);\r\n\r\n // Merge and deduplicate\r\n const allVersions = [...new Set([...versions, ...fileVersions])];\r\n return allVersions.sort();\r\n } catch {\r\n return versions;\r\n }\r\n }\r\n\r\n /**\r\n * Get integration categories\r\n */\r\n async getCategories(): Promise<IntegrationCategory[]> {\r\n return [...INTEGRATION_CATEGORIES];\r\n }\r\n\r\n /**\r\n * Get validator configuration\r\n */\r\n getConfig(): Required<SchemaValidatorConfig> {\r\n return { ...this.config };\r\n }\r\n\r\n // ============================================================================\r\n // Private Methods\r\n // ============================================================================\r\n\r\n private ensureInitialized(): void {\r\n if (!this.initialized) {\r\n throw new StandardError(\r\n ErrorCode.CONFIGURATION_ERROR,\r\n 'Schema validator not initialized. Call initialize() first.',\r\n { initialized: this.initialized }\r\n );\r\n }\r\n }\r\n\r\n private async loadSchemaDirectory(): Promise<IntegrationCategory[]> {\r\n const loadedCategories: IntegrationCategory[] = [];\r\n\r\n for (const category of INTEGRATION_CATEGORIES) {\r\n const categoryPath = path.join(this.config.schemaPath, category);\r\n\r\n try {\r\n await fs.access(categoryPath);\r\n await this.loadCategorySchemas(category);\r\n loadedCategories.push(category);\r\n } catch (error) {\r\n logger.warn(`Category directory not found: ${category}`, {\r\n categoryPath,\r\n });\r\n }\r\n }\r\n\r\n return loadedCategories;\r\n }\r\n\r\n private async loadCategorySchemas(category: IntegrationCategory): Promise<void> {\r\n const categoryPath = path.join(this.config.schemaPath, category);\r\n\r\n try {\r\n const entries = await fs.readdir(categoryPath, { withFileTypes: true });\r\n\r\n for (const entry of entries) {\r\n if (entry.isDirectory()) {\r\n // Schema subdirectory (e.g., pattern-deployment/)\r\n const schemaName = entry.name;\r\n const schemaId = `${category}/${schemaName}`;\r\n await this.loadSchemaVersions(schemaId, path.join(categoryPath, schemaName));\r\n } else if (entry.isFile() && entry.name.endsWith(this.config.schemaExtension)) {\r\n // Direct schema file\r\n const schemaName = entry.name.replace(this.config.schemaExtension, '');\r\n const schemaId = `${category}/${schemaName}`;\r\n await this.loadSchemaFile(schemaId, path.join(categoryPath, entry.name), '1.0.0');\r\n }\r\n }\r\n } catch (error) {\r\n logger.error(`Failed to load schemas for category: ${category}`, error as Error, {\r\n categoryPath,\r\n });\r\n }\r\n }\r\n\r\n private async loadSchemaVersions(schemaId: string, schemaDir: string): Promise<void> {\r\n try {\r\n const files = await fs.readdir(schemaDir);\r\n\r\n for (const file of files) {\r\n if (file.endsWith(this.config.schemaExtension)) {\r\n const versionMatch = file.match(/v([\\d.]+)/);\r\n const version = versionMatch ? versionMatch[1] : '1.0.0';\r\n const filePath = path.join(schemaDir, file);\r\n\r\n await this.loadSchemaFile(schemaId, filePath, version);\r\n }\r\n }\r\n } catch (error) {\r\n logger.error(`Failed to load schema versions: ${schemaId}`, error as Error, {\r\n schemaDir,\r\n });\r\n }\r\n }\r\n\r\n private async loadSchemaFile(\r\n schemaId: string,\r\n filePath: string,\r\n version: string\r\n ): Promise<void> {\r\n try {\r\n // Check if already loaded in cache\r\n const cacheKey = `${schemaId}@${version}`;\r\n if (this.schemaCache.has(cacheKey)) {\r\n logger.debug('Schema already cached', { schemaId, version });\r\n return;\r\n }\r\n\r\n const content = await fs.readFile(filePath, 'utf-8');\r\n const schema = JSON.parse(content);\r\n\r\n // Check if schema with this $id already exists in Ajv\r\n const schemaKey = schema.$id || `${schemaId}/${version}`;\r\n if (this.ajv.getSchema(schemaKey)) {\r\n logger.debug('Schema already compiled in Ajv', { schemaId, version, schemaKey });\r\n // Use existing compiled schema\r\n const validator = this.ajv.getSchema(schemaKey)!;\r\n\r\n const category = schemaId.split('/')[0] as IntegrationCategory;\r\n const metadata: SchemaMetadata = {\r\n id: schemaId,\r\n version,\r\n category,\r\n description: schema.description,\r\n validator,\r\n };\r\n\r\n this.schemaCache.set(cacheKey, metadata);\r\n return;\r\n }\r\n\r\n // Compile schema with Ajv\r\n const validator = this.ajv.compile(schema);\r\n\r\n // Extract category from schemaId\r\n const category = schemaId.split('/')[0] as IntegrationCategory;\r\n\r\n const metadata: SchemaMetadata = {\r\n id: schemaId,\r\n version,\r\n category,\r\n description: schema.description,\r\n validator,\r\n };\r\n\r\n // Cache with version\r\n this.schemaCache.set(cacheKey, metadata);\r\n\r\n logger.debug('Schema loaded', { schemaId, version, filePath });\r\n } catch (error) {\r\n logger.error(`Failed to load schema file: ${filePath}`, error as Error, {\r\n schemaId,\r\n version,\r\n });\r\n throw error;\r\n }\r\n }\r\n\r\n private async loadSchema(schemaId: string, version?: string): Promise<SchemaMetadata> {\r\n const category = schemaId.split('/')[0] as IntegrationCategory;\r\n const schemaName = schemaId.split('/').slice(1).join('/');\r\n\r\n // Determine file path\r\n const categoryPath = path.join(this.config.schemaPath, category);\r\n const schemaPath = path.join(categoryPath, schemaName);\r\n\r\n // Try versioned schema directory\r\n try {\r\n const versionedFile = version\r\n ? `v${version}${this.config.schemaExtension}`\r\n : `v1.0.0${this.config.schemaExtension}`;\r\n\r\n const filePath = path.join(schemaPath, versionedFile);\r\n await fs.access(filePath);\r\n\r\n const actualVersion = version || '1.0.0';\r\n await this.loadSchemaFile(schemaId, filePath, actualVersion);\r\n\r\n return this.schemaCache.get(`${schemaId}@${actualVersion}`)!;\r\n } catch {\r\n // Try direct schema file\r\n const directFile = path.join(categoryPath, `${schemaName}${this.config.schemaExtension}`);\r\n\r\n try {\r\n await fs.access(directFile);\r\n\r\n const actualVersion = version || '1.0.0';\r\n await this.loadSchemaFile(schemaId, directFile, actualVersion);\r\n\r\n return this.schemaCache.get(`${schemaId}@${actualVersion}`)!;\r\n } catch (error) {\r\n throw new StandardError(\r\n ErrorCode.FILE_NOT_FOUND,\r\n `Schema not found: ${schemaId}${version ? `@${version}` : ''}`,\r\n { schemaId, version, searchPaths: [schemaPath, directFile] },\r\n error as Error\r\n );\r\n }\r\n }\r\n }\r\n\r\n private formatErrors(errors: ErrorObject[]): ValidationError[] {\r\n return errors.map((error) => ({\r\n path: error.instancePath || error.schemaPath,\r\n message: error.message || 'Validation failed',\r\n keyword: error.keyword,\r\n params: error.params,\r\n }));\r\n }\r\n\r\n private generateSuggestions(errors: ValidationError[], data: any): string[] {\r\n const suggestions: string[] = [];\r\n\r\n for (const error of errors) {\r\n if (error.keyword === 'required' && error.params?.missingProperty) {\r\n const missing = error.params.missingProperty;\r\n suggestions.push(missing);\r\n\r\n // Check for typos in data keys\r\n const dataKeys = Object.keys(data);\r\n const similar = dataKeys.filter(\r\n (key) => this.levenshteinDistance(key, missing) <= 2\r\n );\r\n\r\n if (similar.length > 0) {\r\n suggestions.push(`Did you mean: ${similar.join(', ')}?`);\r\n }\r\n }\r\n }\r\n\r\n return [...new Set(suggestions)]; // Deduplicate\r\n }\r\n\r\n private levenshteinDistance(a: string, b: string): number {\r\n const matrix: number[][] = [];\r\n\r\n for (let i = 0; i <= b.length; i++) {\r\n matrix[i] = [i];\r\n }\r\n\r\n for (let j = 0; j <= a.length; j++) {\r\n matrix[0][j] = j;\r\n }\r\n\r\n for (let i = 1; i <= b.length; i++) {\r\n for (let j = 1; j <= a.length; j++) {\r\n if (b.charAt(i - 1) === a.charAt(j - 1)) {\r\n matrix[i][j] = matrix[i - 1][j - 1];\r\n } else {\r\n matrix[i][j] = Math.min(\r\n matrix[i - 1][j - 1] + 1, // substitution\r\n matrix[i][j - 1] + 1, // insertion\r\n matrix[i - 1][j] + 1 // deletion\r\n );\r\n }\r\n }\r\n }\r\n\r\n return matrix[b.length][a.length];\r\n }\r\n}\r\n"],"names":["Ajv","addFormats","StandardError","ErrorCode","getGlobalLogger","fs","path","logger","INTEGRATION_CATEGORIES","IntegrationSchemaValidator","config","ajv","schemaCache","migrations","initialized","schemaPath","enableCache","strictMode","maxCacheSize","schemaExtension","allErrors","strict","validateFormats","verbose","Map","debug","initialize","access","categories","loadSchemaDirectory","info","length","schemasLoaded","size","error","CONFIGURATION_ERROR","message","shutdown","clear","validate","data","schemaId","version","ensureInitialized","startTime","Date","now","schema","getSchema","valid","validator","errors","formatErrors","warn","errorCount","duration","VALIDATION_FAILED","suggestions","generateSuggestions","validateBatch","records","options","result","totalRecords","validRecords","invalidRecords","i","push","index","context","failFast","total","invalid","migrate","fromVersion","toVersion","transition","migrationFn","migrated","registerMigration","cacheKey","has","get","loadSchema","set","firstKey","keys","next","value","delete","hasSchema","listSchemas","category","schemas","Array","from","map","key","split","filter","id","self","indexOf","startsWith","getVersions","versions","v","schemaDir","join","files","readdir","fileVersions","f","endsWith","match","allVersions","Set","sort","getCategories","getConfig","loadedCategories","categoryPath","loadCategorySchemas","entries","withFileTypes","entry","isDirectory","schemaName","name","loadSchemaVersions","isFile","replace","loadSchemaFile","file","versionMatch","filePath","content","readFile","JSON","parse","schemaKey","$id","metadata","description","compile","slice","versionedFile","actualVersion","directFile","FILE_NOT_FOUND","searchPaths","instancePath","keyword","params","missingProperty","missing","dataKeys","Object","similar","levenshteinDistance","a","b","matrix","j","charAt","Math","min"],"mappings":"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"}
|