claude-flow-novice 2.15.2 → 2.15.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/cfn-extras/skills/advanced-features/cfn-agent-swap/recommend-swap.sh +59 -59
- package/.claude/cfn-extras/skills/analytics/cfn-improvement-recommender/recommend-improvements.sh +91 -91
- package/.claude/cfn-extras/skills/analytics/cfn-pattern-extraction/extract-patterns.sh +79 -79
- package/.claude/cfn-extras/skills/analytics/cfn-retrospective-report/generate-report.sh +100 -100
- package/.claude/cfn-extras/skills/analytics/cfn-telemetry/start-telemetry.sh +110 -110
- package/.claude/cfn-extras/skills/deprecated/cfn-ace-system/add-bullet.sh +145 -145
- package/.claude/cfn-extras/skills/deprecated/cfn-ace-system/log-merge.sh +67 -67
- package/.claude/cfn-extras/skills/deprecated/cfn-ace-system/monitor-injection-performance.sh +137 -137
- package/.claude/cfn-extras/skills/deprecated/cfn-ace-system/optimize-injection-pipeline.sh +168 -168
- package/.claude/cfn-extras/skills/deprecated/cfn-ace-system/query-reflections.sh +35 -35
- package/.claude/cfn-extras/skills/deprecated/cfn-ace-system/store-reflection.sh +45 -45
- package/.claude/cfn-extras/skills/deprecated/cfn-ace-system/track-ab-test.sh +41 -41
- package/.claude/cfn-extras/skills/deprecated/cfn-ace-system/update-reflection.sh +41 -41
- package/.claude/cfn-extras/skills/deprecated/cfn-cli-setup/validate-cli-environment.sh +191 -191
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-ad-campaigns/operations/create-campaign.sh +231 -231
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-ad-campaigns/operations/get-campaign-performance.sh +190 -190
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-ad-campaigns/operations/pause-campaign.sh +142 -142
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-ad-campaigns/operations/set-budget.sh +181 -181
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-ad-campaigns/operations/update-bid-strategy.sh +133 -133
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-chatbot-conversations/operations/get-conversation-history.sh +121 -121
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-chatbot-conversations/operations/qualify-lead.sh +156 -156
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-chatbot-conversations/operations/schedule-demo.sh +181 -181
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-chatbot-conversations/operations/send-message.sh +137 -137
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-chatbot-conversations/operations/transfer-to-human.sh +179 -179
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-sms-campaigns/operations/create-campaign.sh +183 -183
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-sms-campaigns/operations/get-delivery-status.sh +139 -139
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-sms-campaigns/operations/opt-out.sh +150 -150
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-sms-campaigns/operations/schedule-campaign.sh +187 -187
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-sms-campaigns/operations/send-sms.sh +181 -181
- package/.claude/cfn-extras/skills/ui-portal/cfn-web-portal/test-web-portal-skill.sh +50 -50
- package/.claude/cfn-extras/skills/ui-portal/cfn-web-portal/validate-deployment.sh +84 -84
- package/.claude/cfn-extras/skills/utility/cfn-environment-sanitization/sanitize-environment.sh +243 -243
- package/.claude/commands/cfn-loop-cli.md +16 -2
- package/.claude/commands/switch-api.md +31 -10
- package/.claude/hooks/cfn-BACKUP_USAGE.md +243 -243
- package/.claude/hooks/cfn-invoke-security-validation.sh +69 -69
- package/.claude/hooks/cfn-lint-sql-injection.sh +61 -0
- package/.claude/hooks/cfn-post-edit-cfn-retrospective.sh +109 -78
- package/.claude/hooks/cfn-post-edit.config.json +44 -44
- package/.claude/hooks/cfn-pre-edit-security-warning.sh +40 -0
- package/.claude/skills/cfn-agent-spawning/spawn-agent.sh +22 -24
- package/.claude/skills/cfn-docker-agent-spawning/SKILL.md +28 -4
- package/.claude/skills/cfn-docker-agent-spawning/spawn-agent.sh +3 -1
- package/.claude/skills/cfn-docker-loop-orchestration/orchestrate.sh +224 -20
- package/.claude/skills/cfn-hybrid-routing/check-dependencies.sh +51 -51
- package/.claude/skills/cfn-loop-orchestration/helpers/gate-check.sh +550 -46
- package/.claude/skills/cfn-loop-orchestration/helpers/parse-test-results.sh +277 -0
- package/.claude/skills/cfn-loop-orchestration/orchestrate.sh +184 -23
- package/.claude/skills/cfn-loop-orchestration/security_utils.sh +24 -0
- package/.claude/skills/cfn-loop-orchestration/test-iteration-context-injection.sh +366 -0
- package/.claude/skills/cfn-loop-validation/orchestrate-cfn-loop.sh +252 -252
- package/.claude/skills/cfn-redis-coordination/CENTRALIZED_REDIS_WRAPPER.md +319 -0
- package/.claude/skills/cfn-redis-coordination/agent-log.sh +4 -0
- package/.claude/skills/cfn-redis-coordination/agent-log.sh.bak +124 -0
- package/.claude/skills/cfn-redis-coordination/agent-recovery.sh +74 -74
- package/.claude/skills/cfn-redis-coordination/collect-confidence-scores.sh +30 -0
- package/.claude/skills/cfn-redis-coordination/get-context.sh +145 -112
- package/.claude/skills/cfn-redis-coordination/get-success-criteria.sh +54 -0
- package/.claude/skills/cfn-redis-coordination/invoke-waiting-mode.sh +3 -0
- package/.claude/skills/cfn-redis-coordination/redis-cli-wrapper.sh +24 -3
- package/.claude/skills/cfn-redis-coordination/redis-functions.sh +33 -0
- package/.claude/skills/cfn-redis-coordination/report-completion.sh +24 -31
- package/.claude/skills/cfn-redis-coordination/store-context.sh +4 -0
- package/.claude/skills/cfn-redis-coordination/store-success-criteria.sh +85 -0
- package/.claude/skills/cfn-redis-coordination/update-all-scripts.sh +67 -0
- package/.claude/skills/cfn-sqlite-memory/ttl-cleanup.sh +17 -25
- package/.claude/skills/cfn-transparency-middleware/middleware-config.sh +28 -28
- package/.claude/skills/cfn-transparency-middleware/performance-benchmark.sh +78 -78
- package/.claude/skills/cfn-transparency-middleware/test-e2e.sh +15 -0
- package/.claude/skills/cfn-transparency-middleware/test-integration.sh +161 -161
- package/.claude/skills/cfn-transparency-middleware/test-transparency-skill.sh +367 -367
- package/.claude/skills/cfn-transparency-middleware/tests/input-validation.sh +107 -92
- package/.claude/skills/cfn-transparency-middleware/wrap-agent.sh +131 -131
- package/README.md +116 -475
- package/claude-assets/agents/cfn-dev-team/README.md +103 -0
- package/claude-assets/agents/cfn-dev-team/architecture/goal-planner.md +1 -1
- package/claude-assets/agents/cfn-dev-team/coordinators/cfn-frontend-coordinator.md +77 -15
- package/claude-assets/agents/cfn-dev-team/coordinators/cfn-v3-coordinator.md +355 -6
- package/claude-assets/agents/cfn-dev-team/coordinators/consensus-builder.md +82 -1
- package/claude-assets/agents/cfn-dev-team/coordinators/handoff-coordinator.md +82 -1
- package/claude-assets/agents/cfn-dev-team/coordinators/multi-sprint-coordinator.md +77 -15
- package/claude-assets/agents/cfn-dev-team/dev-ops/docker-specialist.md +99 -12
- package/claude-assets/agents/cfn-dev-team/dev-ops/github-commit-agent.md +1 -1
- package/claude-assets/agents/cfn-dev-team/dev-ops/kubernetes-specialist.md +97 -0
- package/claude-assets/agents/cfn-dev-team/dev-ops/monitoring-specialist.md +20 -1
- package/claude-assets/agents/cfn-dev-team/developers/api-gateway-specialist.md +97 -0
- package/claude-assets/agents/cfn-dev-team/developers/backend-developer.md +110 -13
- package/claude-assets/agents/cfn-dev-team/developers/data/data-engineer.md +106 -15
- package/claude-assets/agents/cfn-dev-team/developers/database/database-architect.md +115 -11
- package/claude-assets/agents/cfn-dev-team/developers/frontend/mobile-dev.md +94 -7
- package/claude-assets/agents/cfn-dev-team/developers/frontend/react-frontend-engineer.md +87 -9
- package/claude-assets/agents/cfn-dev-team/developers/frontend/typescript-specialist.md +85 -7
- package/claude-assets/agents/cfn-dev-team/developers/frontend/ui-designer.md +160 -28
- package/claude-assets/agents/cfn-dev-team/developers/graphql-specialist.md +101 -19
- package/claude-assets/agents/cfn-dev-team/developers/rust-developer.md +108 -14
- package/claude-assets/agents/cfn-dev-team/reviewers/{reviewer.md → code-reviewer.md} +95 -8
- package/claude-assets/agents/cfn-dev-team/reviewers/quality/code-quality-validator.md +107 -7
- package/claude-assets/agents/cfn-dev-team/reviewers/quality/perf-analyzer.md +98 -7
- package/claude-assets/agents/cfn-dev-team/reviewers/quality/performance-benchmarker.md +95 -7
- package/claude-assets/agents/cfn-dev-team/reviewers/quality/security-specialist.md +136 -9
- package/claude-assets/agents/cfn-dev-team/testers/api-testing-specialist.md +108 -1
- package/claude-assets/agents/cfn-dev-team/testers/chaos-engineering-specialist.md +107 -13
- package/claude-assets/agents/cfn-dev-team/testers/contract-tester.md +737 -0
- package/claude-assets/agents/cfn-dev-team/testers/e2e/playwright-tester.md +1 -1
- package/claude-assets/agents/cfn-dev-team/testers/integration-tester.md +828 -0
- package/claude-assets/agents/cfn-dev-team/testers/interaction-tester.md +106 -7
- package/claude-assets/agents/cfn-dev-team/testers/load-testing-specialist.md +77 -0
- package/claude-assets/agents/cfn-dev-team/testers/mutation-testing-specialist.md +684 -0
- package/claude-assets/agents/cfn-dev-team/testers/playwright-tester.md +110 -1
- package/claude-assets/agents/cfn-dev-team/testers/tester.md +94 -7
- package/claude-assets/agents/cfn-dev-team/utility/code-booster.md +1 -3
- package/claude-assets/agents/cfn-dev-team/utility/epic-creator.md +87 -13
- package/claude-assets/agents/cfn-dev-team/utility/memory-leak-specialist.md +103 -7
- package/claude-assets/agents/cfn-dev-team/utility/researcher.md +1 -3
- package/claude-assets/agents/cfn-dev-team/utility/z-ai-specialist.md +94 -7
- package/claude-assets/agents/docker-coordinators/cfn-docker-v3-coordinator.md +46 -0
- package/claude-assets/agents/project-only-agents/npm-package-specialist.md +1 -1
- package/claude-assets/cfn-extras/skills/advanced-features/cfn-agent-swap/recommend-swap.sh +59 -59
- package/claude-assets/cfn-extras/skills/analytics/cfn-improvement-recommender/recommend-improvements.sh +91 -91
- package/claude-assets/cfn-extras/skills/analytics/cfn-pattern-extraction/extract-patterns.sh +79 -79
- package/claude-assets/cfn-extras/skills/analytics/cfn-retrospective-report/generate-report.sh +100 -100
- package/claude-assets/cfn-extras/skills/analytics/cfn-telemetry/start-telemetry.sh +110 -110
- package/claude-assets/cfn-extras/skills/deprecated/cfn-ace-system/add-bullet.sh +145 -145
- package/claude-assets/cfn-extras/skills/deprecated/cfn-ace-system/log-merge.sh +67 -67
- package/claude-assets/cfn-extras/skills/deprecated/cfn-ace-system/monitor-injection-performance.sh +137 -137
- package/claude-assets/cfn-extras/skills/deprecated/cfn-ace-system/optimize-injection-pipeline.sh +168 -168
- package/claude-assets/cfn-extras/skills/deprecated/cfn-ace-system/query-reflections.sh +35 -35
- package/claude-assets/cfn-extras/skills/deprecated/cfn-ace-system/store-reflection.sh +45 -45
- package/claude-assets/cfn-extras/skills/deprecated/cfn-ace-system/track-ab-test.sh +41 -41
- package/claude-assets/cfn-extras/skills/deprecated/cfn-ace-system/update-reflection.sh +41 -41
- package/claude-assets/cfn-extras/skills/deprecated/cfn-cli-setup/validate-cli-environment.sh +191 -191
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-ad-campaigns/operations/create-campaign.sh +231 -231
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-ad-campaigns/operations/get-campaign-performance.sh +190 -190
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-ad-campaigns/operations/pause-campaign.sh +142 -142
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-ad-campaigns/operations/set-budget.sh +181 -181
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-ad-campaigns/operations/update-bid-strategy.sh +133 -133
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-chatbot-conversations/operations/get-conversation-history.sh +121 -121
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-chatbot-conversations/operations/qualify-lead.sh +156 -156
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-chatbot-conversations/operations/schedule-demo.sh +181 -181
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-chatbot-conversations/operations/send-message.sh +137 -137
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-chatbot-conversations/operations/transfer-to-human.sh +179 -179
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-sms-campaigns/operations/create-campaign.sh +183 -183
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-sms-campaigns/operations/get-delivery-status.sh +139 -139
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-sms-campaigns/operations/opt-out.sh +150 -150
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-sms-campaigns/operations/schedule-campaign.sh +187 -187
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-sms-campaigns/operations/send-sms.sh +181 -181
- package/claude-assets/cfn-extras/skills/ui-portal/cfn-web-portal/test-web-portal-skill.sh +50 -50
- package/claude-assets/cfn-extras/skills/ui-portal/cfn-web-portal/validate-deployment.sh +84 -84
- package/claude-assets/cfn-extras/skills/utility/cfn-environment-sanitization/sanitize-environment.sh +243 -243
- package/claude-assets/commands/cfn-loop-cli.md +16 -2
- package/claude-assets/commands/switch-api.md +31 -10
- package/claude-assets/hooks/cfn-BACKUP_USAGE.md +243 -243
- package/claude-assets/hooks/cfn-invoke-security-validation.sh +69 -69
- package/claude-assets/hooks/cfn-lint-sql-injection.sh +61 -0
- package/claude-assets/hooks/cfn-post-edit-cfn-retrospective.sh +109 -78
- package/claude-assets/hooks/cfn-post-edit.config.json +44 -44
- package/claude-assets/hooks/cfn-post-execution/memory-cleanup.sh +19 -19
- package/claude-assets/hooks/cfn-pre-edit-security-warning.sh +40 -0
- package/claude-assets/hooks/cfn-pre-execution/memory-check.sh +19 -19
- package/claude-assets/hooks/detect-hardcoded-credentials.sh +212 -0
- package/claude-assets/skills/SKILL_TEMPLATE.md +774 -0
- package/claude-assets/skills/agent-lifecycle/execute-lifecycle-hook.sh +543 -572
- package/claude-assets/skills/agent-lifecycle/simple-audit.sh +57 -30
- package/claude-assets/skills/agent-template-generator/SKILL.md +440 -0
- package/claude-assets/skills/agent-template-generator/generate-agent.sh +405 -0
- package/claude-assets/skills/agent-validation-linter/SKILL.md +589 -0
- package/claude-assets/skills/agent-validation-linter/lint-agents.sh +271 -0
- package/claude-assets/skills/bootstrap/bash-fundamentals.md +786 -0
- package/claude-assets/skills/bootstrap/database-connection.md +464 -0
- package/claude-assets/skills/bootstrap/error-handling.md +580 -0
- package/claude-assets/skills/bootstrap/file-operations.md +699 -0
- package/claude-assets/skills/bootstrap/skill-loader.md +616 -0
- package/claude-assets/skills/bootstrap/sqlite-params.sh +287 -0
- package/claude-assets/skills/cfn-agent-spawning/spawn-agent.sh +22 -24
- package/claude-assets/skills/cfn-automatic-memory-persistence/persist-agent-output.sh +48 -48
- package/claude-assets/skills/cfn-automatic-memory-persistence/query-agent-history.sh +34 -34
- package/claude-assets/skills/cfn-automatic-memory-persistence/test-memory-persistence.sh +17 -16
- package/claude-assets/skills/cfn-deliverable-validation/confidence-calculator.sh +261 -261
- package/claude-assets/skills/cfn-deployment/SKILL.md +293 -0
- package/claude-assets/skills/cfn-deployment/execute.sh +21 -0
- package/claude-assets/skills/cfn-docker-agent-spawning/SKILL.md +28 -4
- package/claude-assets/skills/cfn-docker-agent-spawning/spawn-agent.sh +3 -1
- package/claude-assets/skills/cfn-docker-loop-orchestration/orchestrate.sh +224 -20
- package/claude-assets/skills/cfn-environment-sanitization/sanitize-environment.sh +38 -0
- package/claude-assets/skills/cfn-error-batching-strategy/lib/core-functions.sh +47 -47
- package/claude-assets/skills/cfn-expert-update/update-expert.sh +345 -345
- package/claude-assets/skills/cfn-file-operations/SKILL.md +290 -0
- package/claude-assets/skills/cfn-file-operations/execute.sh +129 -0
- package/claude-assets/skills/cfn-file-operations/lib/atomic-write.sh +294 -0
- package/claude-assets/skills/cfn-file-operations/lib/lock.sh +361 -0
- package/claude-assets/skills/cfn-file-operations/test.sh +369 -0
- package/claude-assets/skills/cfn-hybrid-routing/check-dependencies.sh +51 -51
- package/claude-assets/skills/cfn-intervention-detector/detect-intervention.sh +110 -110
- package/claude-assets/skills/cfn-intervention-orchestrator/execute-intervention.sh +58 -58
- package/claude-assets/skills/cfn-log-operations/SKILL.md +308 -0
- package/claude-assets/skills/cfn-log-operations/execute.sh +420 -0
- package/claude-assets/skills/cfn-log-operations/lib/rotate.sh +406 -0
- package/claude-assets/skills/cfn-log-operations/lib/search.sh +448 -0
- package/claude-assets/skills/cfn-log-operations/test.sh +394 -0
- package/claude-assets/skills/cfn-loop-orchestration/helpers/gate-check.sh +550 -46
- package/claude-assets/skills/cfn-loop-orchestration/helpers/parse-test-results.sh +277 -0
- package/claude-assets/skills/cfn-loop-orchestration/orchestrate.sh +184 -23
- package/claude-assets/skills/cfn-loop-orchestration/security_utils.sh +24 -0
- package/claude-assets/skills/cfn-loop-orchestration/test-iteration-context-injection.sh +366 -0
- package/claude-assets/skills/cfn-loop-validation/orchestrate-cfn-loop.sh +252 -252
- package/claude-assets/skills/cfn-loop2-output-processing/process-validator-output.sh +275 -275
- package/claude-assets/skills/cfn-memory-management/check-memory.sh +159 -159
- package/claude-assets/skills/cfn-memory-management/cleanup-memory.sh +196 -196
- package/claude-assets/skills/cfn-node-heap-sizer/task-mode-heap-limiter.sh +325 -325
- package/claude-assets/skills/cfn-parameterized-queries/SKILL.md +339 -0
- package/claude-assets/skills/cfn-playbook/query-playbook.sh +19 -15
- package/claude-assets/skills/cfn-playbook/update-playbook.sh +25 -14
- package/claude-assets/skills/cfn-playbook-auto-update/auto-update-playbook.sh +85 -85
- package/claude-assets/skills/cfn-process-instrumentation/instrument-process.sh +44 -0
- package/claude-assets/skills/cfn-promotion/SKILL.md +305 -0
- package/claude-assets/skills/cfn-redis-coordination/CENTRALIZED_REDIS_WRAPPER.md +319 -0
- package/claude-assets/skills/cfn-redis-coordination/agent-log.sh +4 -0
- package/claude-assets/skills/cfn-redis-coordination/agent-log.sh.bak +124 -0
- package/claude-assets/skills/cfn-redis-coordination/agent-recovery.sh +74 -74
- package/claude-assets/skills/cfn-redis-coordination/collect-confidence-scores.sh +30 -0
- package/claude-assets/skills/cfn-redis-coordination/get-context.sh +145 -112
- package/claude-assets/skills/cfn-redis-coordination/get-success-criteria.sh +54 -0
- package/claude-assets/skills/cfn-redis-coordination/invoke-waiting-mode.sh +3 -0
- package/claude-assets/skills/cfn-redis-coordination/redis-cli-wrapper.sh +24 -3
- package/claude-assets/skills/cfn-redis-coordination/redis-functions.sh +33 -0
- package/claude-assets/skills/cfn-redis-coordination/report-completion.sh +24 -31
- package/claude-assets/skills/cfn-redis-coordination/store-context.sh +4 -0
- package/claude-assets/skills/cfn-redis-coordination/store-success-criteria.sh +85 -0
- package/claude-assets/skills/cfn-redis-coordination/update-all-scripts.sh +67 -0
- package/claude-assets/skills/cfn-scope-simplifier/simplify-scope.sh +67 -67
- package/claude-assets/skills/cfn-skill-loader/SKILL.md +466 -0
- package/claude-assets/skills/cfn-skill-loader/execute.sh +344 -0
- package/claude-assets/skills/cfn-specialist-injection/recommend-specialist.sh +56 -56
- package/claude-assets/skills/cfn-sqlite-memory/ttl-cleanup.sh +17 -25
- package/claude-assets/skills/cfn-standardized-error-handling/capture-agent-error.sh +86 -86
- package/claude-assets/skills/cfn-standardized-error-handling/test-error-handling.sh +165 -165
- package/claude-assets/skills/cfn-task-audit/get-audit-data.sh +42 -21
- package/claude-assets/skills/cfn-task-audit/store-task-audit.sh +17 -10
- package/claude-assets/skills/cfn-task-config-init/initialize-config.sh +264 -264
- package/claude-assets/skills/cfn-task-decomposition/task-decomposer.sh +278 -278
- package/claude-assets/skills/cfn-test-runner/detect-regressions.sh +17 -14
- package/claude-assets/skills/cfn-test-runner/detect-regressions.sh.backup-1763392821 +55 -0
- package/claude-assets/skills/cfn-test-runner/store-benchmarks.sh +17 -19
- package/claude-assets/skills/cfn-transparency-middleware/middleware-config.sh +28 -28
- package/claude-assets/skills/cfn-transparency-middleware/performance-benchmark.sh +78 -78
- package/claude-assets/skills/cfn-transparency-middleware/test-e2e.sh +15 -0
- package/claude-assets/skills/cfn-transparency-middleware/test-integration.sh +161 -161
- package/claude-assets/skills/cfn-transparency-middleware/test-transparency-skill.sh +367 -367
- package/claude-assets/skills/cfn-transparency-middleware/tests/input-validation.sh +107 -92
- package/claude-assets/skills/cfn-transparency-middleware/wrap-agent.sh +131 -131
- package/claude-assets/skills/cfn-utilities/SKILL.md +237 -0
- package/claude-assets/skills/cfn-utilities/execute.sh +32 -0
- package/claude-assets/skills/cfn-utilities/lib/errors.sh +56 -0
- package/claude-assets/skills/cfn-utilities/lib/file-ops.sh +164 -0
- package/claude-assets/skills/cfn-utilities/lib/logging.sh +77 -0
- package/claude-assets/skills/cfn-utilities/lib/retry.sh +127 -0
- package/claude-assets/skills/cfn-utilities/test.sh +317 -0
- package/claude-assets/skills/docker-build/SKILL.md +96 -203
- package/claude-assets/skills/docker-build/build.sh +73 -73
- package/claude-assets/skills/integration/agent-handoff.sh +492 -0
- package/claude-assets/skills/integration/file-operations.sh +414 -0
- package/claude-assets/skills/json-validation/SKILL.md +431 -0
- package/claude-assets/skills/json-validation/test-validate-success-criteria.sh +421 -0
- package/claude-assets/skills/json-validation/validate-success-criteria.sh +197 -0
- package/claude-assets/skills/redis-coordination/validate-parameters.sh +34 -0
- package/claude-assets/skills/workflow-codification/APPROVAL_WORKFLOW.md +806 -0
- package/claude-assets/skills/workflow-codification/COST_TRACKING.md +637 -0
- package/claude-assets/skills/workflow-codification/DEPLOY_QUICK_REFERENCE.md +106 -0
- package/claude-assets/skills/workflow-codification/EDGE_CASE_TRACKING.md +404 -0
- package/claude-assets/skills/workflow-codification/PROPAGATE_UPDATE_QUICK_REFERENCE.md +366 -0
- package/claude-assets/skills/workflow-codification/README_PHASE4.md +457 -0
- package/claude-assets/skills/workflow-codification/SKILL.md +110 -0
- package/claude-assets/skills/workflow-codification/analyze-patterns.sh +899 -0
- package/claude-assets/skills/workflow-codification/approval-workflow.sh +514 -0
- package/claude-assets/skills/workflow-codification/deploy-approved-skill.sh +481 -0
- package/claude-assets/skills/workflow-codification/deploy-approved-skill.sh.backup-1763392820 +512 -0
- package/claude-assets/skills/workflow-codification/generate-skill-update.sh +525 -0
- package/claude-assets/skills/workflow-codification/lib/security-utils.sh +204 -0
- package/claude-assets/skills/workflow-codification/propagate-skill-update.sh +648 -0
- package/claude-assets/skills/workflow-codification/propagate-skill-update.sh.backup-1763392820 +664 -0
- package/claude-assets/skills/workflow-codification/review-skill.sh +643 -0
- package/claude-assets/skills/workflow-codification/templates/email-notification.txt +114 -0
- package/claude-assets/skills/workflow-codification/templates/slack-notification.md +85 -0
- package/claude-assets/skills/workflow-codification/test-integration.sh +296 -0
- package/claude-assets/skills/workflow-codification/test-metadata-update.sh +350 -0
- package/claude-assets/skills/workflow-codification/track-cost-savings.sh +486 -0
- package/claude-assets/skills/workflow-codification/track-cost-savings.sh.backup-1763392821 +445 -0
- package/claude-assets/skills/workflow-codification/track-edge-case.sh +290 -0
- package/claude-assets/skills/workflow-codification/workflow-codification.db +0 -0
- package/dist/ace/ace-curator.js +10 -2
- package/dist/ace/ace-curator.js.map +1 -1
- package/dist/ace/ace-generator.js +4 -0
- package/dist/ace/ace-generator.js.map +1 -1
- package/dist/ace/ace-reflector.js +1 -1
- package/dist/ace/ace-reflector.js.map +1 -1
- package/dist/ace/context-injection.js +24 -2
- package/dist/ace/context-injection.js.map +1 -1
- package/dist/agents/agent-loader.js +146 -165
- package/dist/agents/agent-loader.js.map +1 -1
- package/dist/agents/task-agent-integration.js +1 -1
- package/dist/agents/task-agent-integration.js.map +1 -1
- package/dist/api/health-endpoints.js +390 -0
- package/dist/api/health-endpoints.js.map +1 -0
- package/dist/cli/agent-executor.js +4 -1
- package/dist/cli/agent-executor.js.map +1 -1
- package/dist/cli/agent-prompt-builder.js +89 -1
- package/dist/cli/agent-prompt-builder.js.map +1 -1
- package/dist/cli/agent-spawn.js +130 -37
- package/dist/cli/agent-spawn.js.map +1 -1
- package/dist/cli/config-manager.js +91 -109
- package/dist/cli/config-manager.js.map +1 -1
- package/dist/cli/skill-cache-validator.js +412 -0
- package/dist/cli/skill-cache-validator.js.map +1 -0
- package/dist/cli/skill-cli.js +991 -0
- package/dist/cli/skill-cli.js.map +1 -0
- package/dist/cli/skill-execution-logger.js +284 -0
- package/dist/cli/skill-execution-logger.js.map +1 -0
- package/dist/cli/skill-loader.js +457 -0
- package/dist/cli/skill-loader.js.map +1 -0
- package/dist/coordination/event-bus.js +2 -2
- package/dist/coordination/event-bus.js.map +1 -1
- package/dist/coordination/fleet-manager.js +1 -1
- package/dist/coordination/fleet-manager.js.map +1 -1
- package/dist/coordination/index.js +23 -9
- package/dist/coordination/index.js.map +1 -1
- package/dist/coordination/types/fleet-manager.types.js.map +1 -1
- package/dist/db/migration-manager.js +483 -0
- package/dist/db/migration-manager.js.map +1 -0
- package/dist/db/skills-query.js +535 -0
- package/dist/db/skills-query.js.map +1 -0
- package/dist/integration/DatabaseHandoff.js +507 -0
- package/dist/integration/DatabaseHandoff.js.map +1 -0
- package/dist/integration/StandardAdapter.js +291 -0
- package/dist/integration/StandardAdapter.js.map +1 -0
- package/dist/jobs/edge-case-analyzer.js +367 -0
- package/dist/jobs/edge-case-analyzer.js.map +1 -0
- package/dist/jobs/promotion-sla-enforcer.js +288 -0
- package/dist/jobs/promotion-sla-enforcer.js.map +1 -0
- package/dist/lib/agent-output-parser.js +518 -0
- package/dist/lib/agent-output-parser.js.map +1 -0
- package/dist/lib/agent-output-validator.js +950 -0
- package/dist/lib/agent-output-validator.js.map +1 -0
- package/dist/lib/agent-workspace.js +281 -0
- package/dist/lib/agent-workspace.js.map +1 -0
- package/dist/lib/artifact-registry.js +443 -0
- package/dist/lib/artifact-registry.js.map +1 -0
- package/dist/lib/atomic-file-writer.js +377 -0
- package/dist/lib/atomic-file-writer.js.map +1 -0
- package/dist/lib/backup-manager.js +779 -0
- package/dist/lib/backup-manager.js.map +1 -0
- package/dist/lib/checkpoint-manager.js +837 -0
- package/dist/lib/checkpoint-manager.js.map +1 -0
- package/dist/lib/circuit-breaker.js +340 -0
- package/dist/lib/circuit-breaker.js.map +1 -0
- package/dist/lib/completion-signal-handler.js +243 -0
- package/dist/lib/completion-signal-handler.js.map +1 -0
- package/dist/lib/config-manager.js +312 -0
- package/dist/lib/config-manager.js.map +1 -0
- package/dist/lib/config-migrator.js +386 -0
- package/dist/lib/config-migrator.js.map +1 -0
- package/dist/lib/config-validator.js +687 -0
- package/dist/lib/config-validator.js.map +1 -0
- package/dist/lib/correlation-cache.js +311 -0
- package/dist/lib/correlation-cache.js.map +1 -0
- package/dist/lib/correlation.js +263 -0
- package/dist/lib/correlation.js.map +1 -0
- package/dist/lib/database-service/connection-pool-manager.js +520 -0
- package/dist/lib/database-service/connection-pool-manager.js.map +1 -0
- package/dist/lib/database-service/correlation.js +329 -0
- package/dist/lib/database-service/correlation.js.map +1 -0
- package/dist/lib/database-service/errors.js +120 -0
- package/dist/lib/database-service/errors.js.map +1 -0
- package/dist/lib/database-service/index.js +168 -0
- package/dist/lib/database-service/index.js.map +1 -0
- package/dist/lib/database-service/postgres-adapter.js +526 -0
- package/dist/lib/database-service/postgres-adapter.js.map +1 -0
- package/dist/lib/database-service/redis-adapter.js +360 -0
- package/dist/lib/database-service/redis-adapter.js.map +1 -0
- package/dist/lib/database-service/sqlite-adapter.js +544 -0
- package/dist/lib/database-service/sqlite-adapter.js.map +1 -0
- package/dist/lib/database-service/transaction-manager.js +773 -0
- package/dist/lib/database-service/transaction-manager.js.map +1 -0
- package/dist/lib/database-service/types.js +23 -0
- package/dist/lib/database-service/types.js.map +1 -0
- package/dist/lib/deadlock-resolver.js +292 -0
- package/dist/lib/deadlock-resolver.js.map +1 -0
- package/dist/lib/distributed-lock.js +451 -0
- package/dist/lib/distributed-lock.js.map +1 -0
- package/dist/lib/edge-case-deduplicator.js +227 -0
- package/dist/lib/edge-case-deduplicator.js.map +1 -0
- package/dist/lib/encryption-manager.js +322 -0
- package/dist/lib/encryption-manager.js.map +1 -0
- package/dist/lib/error-aggregator.js +234 -0
- package/dist/lib/error-aggregator.js.map +1 -0
- package/dist/lib/errors.js +287 -0
- package/dist/lib/errors.js.map +1 -0
- package/dist/lib/file-lock-manager.js +578 -0
- package/dist/lib/file-lock-manager.js.map +1 -0
- package/dist/lib/file-operations.js +367 -0
- package/dist/lib/file-operations.js.map +1 -0
- package/dist/lib/idempotent-write.js +237 -0
- package/dist/lib/idempotent-write.js.map +1 -0
- package/dist/lib/integration-schema-validator.js +522 -0
- package/dist/lib/integration-schema-validator.js.map +1 -0
- package/dist/lib/lock-health-monitor.js +298 -0
- package/dist/lib/lock-health-monitor.js.map +1 -0
- package/dist/lib/log-shipper.js +422 -0
- package/dist/lib/log-shipper.js.map +1 -0
- package/dist/lib/logging.js +146 -0
- package/dist/lib/logging.js.map +1 -0
- package/dist/lib/message-deduplicator.js +439 -0
- package/dist/lib/message-deduplicator.js.map +1 -0
- package/dist/lib/multi-system-query.js +604 -0
- package/dist/lib/multi-system-query.js.map +1 -0
- package/dist/lib/orphan-detector.js +332 -0
- package/dist/lib/orphan-detector.js.map +1 -0
- package/dist/lib/password-generator.js +166 -0
- package/dist/lib/password-generator.js.map +1 -0
- package/dist/lib/path-validator.js +429 -0
- package/dist/lib/path-validator.js.map +1 -0
- package/dist/lib/query-translator.js +905 -0
- package/dist/lib/query-translator.js.map +1 -0
- package/dist/lib/queue-recovery.js +469 -0
- package/dist/lib/queue-recovery.js.map +1 -0
- package/dist/lib/redis-queue-manager.js +512 -0
- package/dist/lib/redis-queue-manager.js.map +1 -0
- package/dist/lib/reflection-archiver.js +272 -0
- package/dist/lib/reflection-archiver.js.map +1 -0
- package/dist/lib/retry-manager.js +453 -0
- package/dist/lib/retry-manager.js.map +1 -0
- package/dist/lib/retry.js +262 -0
- package/dist/lib/retry.js.map +1 -0
- package/dist/lib/schema-transform.js +695 -0
- package/dist/lib/schema-transform.js.map +1 -0
- package/dist/lib/schema-validator.js +491 -0
- package/dist/lib/schema-validator.js.map +1 -0
- package/dist/lib/skill-cache.js +297 -0
- package/dist/lib/skill-cache.js.map +1 -0
- package/dist/lib/skill-content-manager.js +337 -0
- package/dist/lib/skill-content-manager.js.map +1 -0
- package/dist/lib/skill-frontmatter-parser.js +237 -0
- package/dist/lib/skill-frontmatter-parser.js.map +1 -0
- package/dist/lib/skill-git-integration.js +275 -0
- package/dist/lib/skill-git-integration.js.map +1 -0
- package/dist/lib/skill-markdown-validator.js +396 -0
- package/dist/lib/skill-markdown-validator.js.map +1 -0
- package/dist/lib/skill-output-parser.js +312 -0
- package/dist/lib/skill-output-parser.js.map +1 -0
- package/dist/lib/unified-query-api.js +467 -0
- package/dist/lib/unified-query-api.js.map +1 -0
- package/dist/middleware/auth-middleware.js +350 -0
- package/dist/middleware/auth-middleware.js.map +1 -0
- package/dist/middleware/schema-validation.js +347 -0
- package/dist/middleware/schema-validation.js.map +1 -0
- package/dist/providers/anthropic-provider.js +1 -1
- package/dist/providers/anthropic-provider.js.map +1 -1
- package/dist/providers/provider-factory.js +2 -2
- package/dist/providers/provider-factory.js.map +1 -1
- package/dist/services/edge-case-analyzer.js +321 -0
- package/dist/services/edge-case-analyzer.js.map +1 -0
- package/dist/services/edge-case-deduplicator.js +266 -0
- package/dist/services/edge-case-deduplicator.js.map +1 -0
- package/dist/services/edge-case-detector.js +337 -0
- package/dist/services/edge-case-detector.js.map +1 -0
- package/dist/services/edge-case-tracker.js +547 -0
- package/dist/services/edge-case-tracker.js.map +1 -0
- package/dist/services/health-check-system.js +586 -0
- package/dist/services/health-check-system.js.map +1 -0
- package/dist/services/metrics-logger.js +412 -0
- package/dist/services/metrics-logger.js.map +1 -0
- package/dist/services/patch-generator.js +378 -0
- package/dist/services/patch-generator.js.map +1 -0
- package/dist/services/patch-validator.js +337 -0
- package/dist/services/patch-validator.js.map +1 -0
- package/dist/services/performance-monitor.js +811 -0
- package/dist/services/performance-monitor.js.map +1 -0
- package/dist/services/promotion-pipeline.js +918 -0
- package/dist/services/promotion-pipeline.js.map +1 -0
- package/dist/services/promotion-validator.js +394 -0
- package/dist/services/promotion-validator.js.map +1 -0
- package/dist/services/reflection-logger.js +388 -0
- package/dist/services/reflection-logger.js.map +1 -0
- package/dist/services/skill-deployment.js +472 -0
- package/dist/services/skill-deployment.js.map +1 -0
- package/dist/services/skill-loader.js +427 -0
- package/dist/services/skill-loader.js.map +1 -0
- package/dist/services/skill-promotion.js +372 -0
- package/dist/services/skill-promotion.js.map +1 -0
- package/dist/services/skill-validator.js +454 -0
- package/dist/services/skill-validator.js.map +1 -0
- package/dist/services/skill-versioning.js +244 -0
- package/dist/services/skill-versioning.js.map +1 -0
- package/dist/services/workspace-supervisor.js +597 -0
- package/dist/services/workspace-supervisor.js.map +1 -0
- package/dist/types/agent-output.js +44 -0
- package/dist/types/agent-output.js.map +1 -0
- package/dist/types/config.js +28 -0
- package/dist/types/config.js.map +1 -0
- package/dist/types/edge-case.js +45 -0
- package/dist/types/edge-case.js.map +1 -0
- package/package.json +201 -176
- package/readme/README.md +19 -4
- package/scripts/artifact-cleanup.sh +392 -0
- package/scripts/backup-cleanup.sh +627 -0
- package/scripts/cleanup-workspaces.sh +412 -0
- package/scripts/cleanup-yaml-configs.sh +141 -0
- package/scripts/deploy-approved-skills.sh +263 -0
- package/scripts/deploy-production.sh +355 -355
- package/scripts/docker-playwright-fix.sh +311 -311
- package/scripts/docker-rebuild-all-agents.sh +127 -127
- package/scripts/health-check.sh +447 -0
- package/scripts/log-aggregator.sh +554 -0
- package/scripts/log-monitor.sh +629 -0
- package/scripts/manage-agent-workspaces.sh +434 -0
- package/scripts/memory-leak-prevention.sh +305 -305
- package/scripts/migrate-artifacts.sh +563 -0
- package/scripts/migrate-schema.sh +533 -0
- package/scripts/migrate-yaml-to-json.sh +465 -0
- package/scripts/promote-staged-skills.sh +423 -0
- package/scripts/run-marketing-tests.sh +42 -42
- package/scripts/update_paths.sh +46 -46
- package/scripts/verify-no-secrets.sh +88 -35
- package/.claude/cfn-extras/agents/deprecated-coordinators/adaptive-coordinator.md.backup +0 -161
- package/.claude/cfn-extras/agents/deprecated-coordinators/blocking-coordinator-example.md.backup +0 -728
- package/.claude/cfn-extras/agents/deprecated-coordinators/mesh-coordinator.md.backup +0 -131
- package/.claude/skills/cfn-agent-spawning/spawn-agent.sh.backup +0 -273
- package/.claude/skills/cfn-loop-orchestration/orchestrate.sh.backup +0 -949
- package/README.md.backup_before_replace +0 -781
- package/claude-assets/cfn-extras/agents/deprecated-coordinators/adaptive-coordinator.md.backup +0 -161
- package/claude-assets/cfn-extras/agents/deprecated-coordinators/blocking-coordinator-example.md.backup +0 -728
- package/claude-assets/cfn-extras/agents/deprecated-coordinators/mesh-coordinator.md.backup +0 -131
- package/claude-assets/skills/cfn-agent-spawning/spawn-agent.sh.backup +0 -273
- package/claude-assets/skills/cfn-loop-orchestration/orchestrate.sh.backup +0 -949
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Completion Signal Handler
|
|
3
|
+
*
|
|
4
|
+
* Provides reliable completion signaling for agent-coordinator communication.
|
|
5
|
+
* Part of Task 2.1: Persistent Agent Output Workspace (Integration)
|
|
6
|
+
*
|
|
7
|
+
* Signal File Format:
|
|
8
|
+
* COMPLETION_SIGNAL.json
|
|
9
|
+
* {
|
|
10
|
+
* "success": true,
|
|
11
|
+
* "confidence": 0.85,
|
|
12
|
+
* "deliverables": ["file1.ts", "file2.ts"],
|
|
13
|
+
* "errors": [],
|
|
14
|
+
* "metrics": { "executionTimeMs": 5420 },
|
|
15
|
+
* "timestamp": "2025-01-15T10:30:00.000Z",
|
|
16
|
+
* "agentId": "agent-123",
|
|
17
|
+
* "taskId": "task-456"
|
|
18
|
+
* }
|
|
19
|
+
*
|
|
20
|
+
* Usage:
|
|
21
|
+
* // Agent writes completion signal
|
|
22
|
+
* await writeCompletionSignal(workspace, {
|
|
23
|
+
* success: true,
|
|
24
|
+
* confidence: 0.85,
|
|
25
|
+
* deliverables: ['file.ts'],
|
|
26
|
+
* taskId: 'task-123',
|
|
27
|
+
* agentId: 'agent-456',
|
|
28
|
+
* timestamp: new Date()
|
|
29
|
+
* });
|
|
30
|
+
*
|
|
31
|
+
* // Coordinator polls for completion
|
|
32
|
+
* const signal = await pollForCompletion(workspace, 300000);
|
|
33
|
+
*/ import * as path from 'path';
|
|
34
|
+
import { atomicWrite } from './file-operations.js';
|
|
35
|
+
import { createLogger } from './logging.js';
|
|
36
|
+
import { createError, ErrorCode, createTimeoutError } from './errors.js';
|
|
37
|
+
const logger = createLogger('completion-signal-handler');
|
|
38
|
+
/**
|
|
39
|
+
* Completion signal file name
|
|
40
|
+
*/ const COMPLETION_SIGNAL_FILE = 'COMPLETION_SIGNAL.json';
|
|
41
|
+
/**
|
|
42
|
+
* Default poll options
|
|
43
|
+
*/ const DEFAULT_POLL_OPTIONS = {
|
|
44
|
+
timeoutMs: 300000,
|
|
45
|
+
intervalMs: 500
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Write completion signal to workspace
|
|
49
|
+
*
|
|
50
|
+
* Pattern: Atomic write ensures signal is never partially written
|
|
51
|
+
*
|
|
52
|
+
* @param workspace - Workspace path information
|
|
53
|
+
* @param signal - Completion signal data
|
|
54
|
+
* @returns Promise that resolves when signal is written
|
|
55
|
+
* @throws FILE_WRITE_FAILED if write fails
|
|
56
|
+
*/ export async function writeCompletionSignal(workspace, signal) {
|
|
57
|
+
// Validate signal
|
|
58
|
+
validateSignal(signal);
|
|
59
|
+
const signalPath = path.join(workspace.path, COMPLETION_SIGNAL_FILE);
|
|
60
|
+
// Prepare signal data (convert Date to ISO string for JSON)
|
|
61
|
+
const signalData = {
|
|
62
|
+
...signal,
|
|
63
|
+
timestamp: signal.timestamp.toISOString()
|
|
64
|
+
};
|
|
65
|
+
try {
|
|
66
|
+
await atomicWrite(signalPath, JSON.stringify(signalData, null, 2));
|
|
67
|
+
logger.info('Completion signal written', {
|
|
68
|
+
taskId: workspace.taskId,
|
|
69
|
+
agentId: workspace.agentId,
|
|
70
|
+
success: signal.success,
|
|
71
|
+
confidence: signal.confidence
|
|
72
|
+
});
|
|
73
|
+
} catch (error) {
|
|
74
|
+
throw createError(ErrorCode.FILE_WRITE_FAILED, 'Failed to write completion signal', {
|
|
75
|
+
taskId: workspace.taskId,
|
|
76
|
+
agentId: workspace.agentId,
|
|
77
|
+
error: error.message
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Read completion signal from workspace
|
|
83
|
+
*
|
|
84
|
+
* @param workspace - Workspace path information
|
|
85
|
+
* @returns Completion signal data or null if not found
|
|
86
|
+
* @throws FILE_READ_FAILED if read fails (other than ENOENT)
|
|
87
|
+
*/ export async function readCompletionSignal(workspace) {
|
|
88
|
+
const signalPath = path.join(workspace.path, COMPLETION_SIGNAL_FILE);
|
|
89
|
+
try {
|
|
90
|
+
const fs = await import('fs/promises');
|
|
91
|
+
const content = await fs.readFile(signalPath, 'utf8');
|
|
92
|
+
const signalData = JSON.parse(content);
|
|
93
|
+
// Convert ISO string back to Date
|
|
94
|
+
return {
|
|
95
|
+
...signalData,
|
|
96
|
+
timestamp: new Date(signalData.timestamp)
|
|
97
|
+
};
|
|
98
|
+
} catch (error) {
|
|
99
|
+
const err = error;
|
|
100
|
+
if (err.code === 'ENOENT') {
|
|
101
|
+
// Signal file doesn't exist yet
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
throw createError(ErrorCode.FILE_READ_FAILED, 'Failed to read completion signal', {
|
|
105
|
+
taskId: workspace.taskId,
|
|
106
|
+
agentId: workspace.agentId,
|
|
107
|
+
error: error.message
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Poll for completion signal with timeout
|
|
113
|
+
*
|
|
114
|
+
* Pattern: Non-blocking polling with configurable interval and timeout
|
|
115
|
+
*
|
|
116
|
+
* @param workspace - Workspace path information
|
|
117
|
+
* @param timeoutMs - Timeout in milliseconds (default: 300000 = 5 minutes)
|
|
118
|
+
* @param options - Poll options
|
|
119
|
+
* @returns Completion signal data
|
|
120
|
+
* @throws TIMEOUT if signal not received within timeout
|
|
121
|
+
* @throws FILE_READ_FAILED if read fails
|
|
122
|
+
*/ export async function pollForCompletion(workspace, timeoutMs, options = {}) {
|
|
123
|
+
const pollOptions = {
|
|
124
|
+
...DEFAULT_POLL_OPTIONS,
|
|
125
|
+
...timeoutMs !== undefined ? {
|
|
126
|
+
timeoutMs
|
|
127
|
+
} : {},
|
|
128
|
+
...options
|
|
129
|
+
};
|
|
130
|
+
const startTime = Date.now();
|
|
131
|
+
const endTime = startTime + pollOptions.timeoutMs;
|
|
132
|
+
logger.debug('Starting completion polling', {
|
|
133
|
+
taskId: workspace.taskId,
|
|
134
|
+
agentId: workspace.agentId,
|
|
135
|
+
timeoutMs: pollOptions.timeoutMs,
|
|
136
|
+
intervalMs: pollOptions.intervalMs
|
|
137
|
+
});
|
|
138
|
+
while(Date.now() < endTime){
|
|
139
|
+
// Try to read signal
|
|
140
|
+
const signal = await readCompletionSignal(workspace);
|
|
141
|
+
if (signal) {
|
|
142
|
+
const elapsedMs = Date.now() - startTime;
|
|
143
|
+
logger.info('Completion signal received', {
|
|
144
|
+
taskId: workspace.taskId,
|
|
145
|
+
agentId: workspace.agentId,
|
|
146
|
+
success: signal.success,
|
|
147
|
+
confidence: signal.confidence,
|
|
148
|
+
elapsedMs
|
|
149
|
+
});
|
|
150
|
+
return signal;
|
|
151
|
+
}
|
|
152
|
+
// Wait before next poll
|
|
153
|
+
await sleep(pollOptions.intervalMs);
|
|
154
|
+
}
|
|
155
|
+
// Timeout reached
|
|
156
|
+
const elapsedMs = Date.now() - startTime;
|
|
157
|
+
throw createTimeoutError('Completion signal timeout', pollOptions.timeoutMs, {
|
|
158
|
+
taskId: workspace.taskId,
|
|
159
|
+
agentId: workspace.agentId,
|
|
160
|
+
elapsedMs
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Check if completion signal exists
|
|
165
|
+
*
|
|
166
|
+
* @param workspace - Workspace path information
|
|
167
|
+
* @returns True if signal exists, false otherwise
|
|
168
|
+
*/ export async function hasCompletionSignal(workspace) {
|
|
169
|
+
const signal = await readCompletionSignal(workspace);
|
|
170
|
+
return signal !== null;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Delete completion signal
|
|
174
|
+
*
|
|
175
|
+
* Useful for resetting workspace state.
|
|
176
|
+
*
|
|
177
|
+
* @param workspace - Workspace path information
|
|
178
|
+
* @returns Promise that resolves when signal is deleted
|
|
179
|
+
*/ export async function deleteCompletionSignal(workspace) {
|
|
180
|
+
const signalPath = path.join(workspace.path, COMPLETION_SIGNAL_FILE);
|
|
181
|
+
try {
|
|
182
|
+
const fs = await import('fs/promises');
|
|
183
|
+
await fs.unlink(signalPath);
|
|
184
|
+
logger.debug('Completion signal deleted', {
|
|
185
|
+
taskId: workspace.taskId,
|
|
186
|
+
agentId: workspace.agentId
|
|
187
|
+
});
|
|
188
|
+
} catch (error) {
|
|
189
|
+
const err = error;
|
|
190
|
+
if (err.code === 'ENOENT') {
|
|
191
|
+
// Signal file doesn't exist, nothing to delete
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
throw error;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Validate completion signal data
|
|
199
|
+
*
|
|
200
|
+
* @param signal - Completion signal to validate
|
|
201
|
+
* @throws INVALID_INPUT if signal is invalid
|
|
202
|
+
*/ function validateSignal(signal) {
|
|
203
|
+
if (typeof signal.success !== 'boolean') {
|
|
204
|
+
throw createError(ErrorCode.INVALID_INPUT, 'Signal success must be a boolean', {
|
|
205
|
+
signal
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
if (typeof signal.confidence !== 'number' || signal.confidence < 0 || signal.confidence > 1) {
|
|
209
|
+
throw createError(ErrorCode.INVALID_INPUT, 'Signal confidence must be a number between 0 and 1', {
|
|
210
|
+
signal
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
if (!Array.isArray(signal.deliverables)) {
|
|
214
|
+
throw createError(ErrorCode.INVALID_INPUT, 'Signal deliverables must be an array', {
|
|
215
|
+
signal
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
if (!signal.taskId || typeof signal.taskId !== 'string') {
|
|
219
|
+
throw createError(ErrorCode.INVALID_INPUT, 'Signal taskId must be a non-empty string', {
|
|
220
|
+
signal
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
if (!signal.agentId || typeof signal.agentId !== 'string') {
|
|
224
|
+
throw createError(ErrorCode.INVALID_INPUT, 'Signal agentId must be a non-empty string', {
|
|
225
|
+
signal
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
if (!(signal.timestamp instanceof Date)) {
|
|
229
|
+
throw createError(ErrorCode.INVALID_INPUT, 'Signal timestamp must be a Date object', {
|
|
230
|
+
signal
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Sleep for specified duration
|
|
236
|
+
*
|
|
237
|
+
* @param ms - Duration in milliseconds
|
|
238
|
+
* @returns Promise that resolves after duration
|
|
239
|
+
*/ function sleep(ms) {
|
|
240
|
+
return new Promise((resolve)=>setTimeout(resolve, ms));
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
//# sourceMappingURL=completion-signal-handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/lib/completion-signal-handler.ts"],"sourcesContent":["/**\r\n * Completion Signal Handler\r\n *\r\n * Provides reliable completion signaling for agent-coordinator communication.\r\n * Part of Task 2.1: Persistent Agent Output Workspace (Integration)\r\n *\r\n * Signal File Format:\r\n * COMPLETION_SIGNAL.json\r\n * {\r\n * \"success\": true,\r\n * \"confidence\": 0.85,\r\n * \"deliverables\": [\"file1.ts\", \"file2.ts\"],\r\n * \"errors\": [],\r\n * \"metrics\": { \"executionTimeMs\": 5420 },\r\n * \"timestamp\": \"2025-01-15T10:30:00.000Z\",\r\n * \"agentId\": \"agent-123\",\r\n * \"taskId\": \"task-456\"\r\n * }\r\n *\r\n * Usage:\r\n * // Agent writes completion signal\r\n * await writeCompletionSignal(workspace, {\r\n * success: true,\r\n * confidence: 0.85,\r\n * deliverables: ['file.ts'],\r\n * taskId: 'task-123',\r\n * agentId: 'agent-456',\r\n * timestamp: new Date()\r\n * });\r\n *\r\n * // Coordinator polls for completion\r\n * const signal = await pollForCompletion(workspace, 300000);\r\n */\r\n\r\nimport * as path from 'path';\r\nimport { atomicWrite } from './file-operations.js';\r\nimport { createLogger } from './logging.js';\r\nimport { createError, ErrorCode, createTimeoutError } from './errors.js';\r\nimport { WorkspacePath } from './agent-workspace.js';\r\n\r\nconst logger = createLogger('completion-signal-handler');\r\n\r\n/**\r\n * Completion signal file name\r\n */\r\nconst COMPLETION_SIGNAL_FILE = 'COMPLETION_SIGNAL.json';\r\n\r\n/**\r\n * Completion metadata (partial, provided by caller)\r\n */\r\nexport interface CompletionMetadata {\r\n /** Whether the task completed successfully */\r\n success: boolean;\r\n /** Agent confidence score (0.0 - 1.0) */\r\n confidence: number;\r\n /** List of deliverable file paths */\r\n deliverables: string[];\r\n /** List of errors encountered (optional) */\r\n errors?: string[];\r\n /** Performance metrics (optional) */\r\n metrics?: {\r\n executionTimeMs?: number;\r\n tokensUsed?: number;\r\n costUsd?: number;\r\n [key: string]: any;\r\n };\r\n}\r\n\r\n/**\r\n * Complete completion signal (written to file)\r\n */\r\nexport interface CompletionSignal extends CompletionMetadata {\r\n /** Task ID */\r\n taskId: string;\r\n /** Agent ID */\r\n agentId: string;\r\n /** Signal timestamp */\r\n timestamp: Date;\r\n}\r\n\r\n/**\r\n * Poll options\r\n */\r\nexport interface PollOptions {\r\n /** Timeout in milliseconds (default: 300000 = 5 minutes) */\r\n timeoutMs?: number;\r\n /** Poll interval in milliseconds (default: 500) */\r\n intervalMs?: number;\r\n}\r\n\r\n/**\r\n * Default poll options\r\n */\r\nconst DEFAULT_POLL_OPTIONS: Required<PollOptions> = {\r\n timeoutMs: 300000, // 5 minutes\r\n intervalMs: 500, // 500ms\r\n};\r\n\r\n/**\r\n * Write completion signal to workspace\r\n *\r\n * Pattern: Atomic write ensures signal is never partially written\r\n *\r\n * @param workspace - Workspace path information\r\n * @param signal - Completion signal data\r\n * @returns Promise that resolves when signal is written\r\n * @throws FILE_WRITE_FAILED if write fails\r\n */\r\nexport async function writeCompletionSignal(\r\n workspace: WorkspacePath,\r\n signal: CompletionSignal\r\n): Promise<void> {\r\n // Validate signal\r\n validateSignal(signal);\r\n\r\n const signalPath = path.join(workspace.path, COMPLETION_SIGNAL_FILE);\r\n\r\n // Prepare signal data (convert Date to ISO string for JSON)\r\n const signalData = {\r\n ...signal,\r\n timestamp: signal.timestamp.toISOString(),\r\n };\r\n\r\n try {\r\n await atomicWrite(signalPath, JSON.stringify(signalData, null, 2));\r\n logger.info('Completion signal written', {\r\n taskId: workspace.taskId,\r\n agentId: workspace.agentId,\r\n success: signal.success,\r\n confidence: signal.confidence,\r\n });\r\n } catch (error) {\r\n throw createError(\r\n ErrorCode.FILE_WRITE_FAILED,\r\n 'Failed to write completion signal',\r\n {\r\n taskId: workspace.taskId,\r\n agentId: workspace.agentId,\r\n error: (error as Error).message,\r\n }\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Read completion signal from workspace\r\n *\r\n * @param workspace - Workspace path information\r\n * @returns Completion signal data or null if not found\r\n * @throws FILE_READ_FAILED if read fails (other than ENOENT)\r\n */\r\nexport async function readCompletionSignal(\r\n workspace: WorkspacePath\r\n): Promise<CompletionSignal | null> {\r\n const signalPath = path.join(workspace.path, COMPLETION_SIGNAL_FILE);\r\n\r\n try {\r\n const fs = await import('fs/promises');\r\n const content = await fs.readFile(signalPath, 'utf8');\r\n const signalData = JSON.parse(content);\r\n\r\n // Convert ISO string back to Date\r\n return {\r\n ...signalData,\r\n timestamp: new Date(signalData.timestamp),\r\n };\r\n } catch (error) {\r\n const err = error as NodeJS.ErrnoException;\r\n if (err.code === 'ENOENT') {\r\n // Signal file doesn't exist yet\r\n return null;\r\n }\r\n throw createError(\r\n ErrorCode.FILE_READ_FAILED,\r\n 'Failed to read completion signal',\r\n {\r\n taskId: workspace.taskId,\r\n agentId: workspace.agentId,\r\n error: (error as Error).message,\r\n }\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Poll for completion signal with timeout\r\n *\r\n * Pattern: Non-blocking polling with configurable interval and timeout\r\n *\r\n * @param workspace - Workspace path information\r\n * @param timeoutMs - Timeout in milliseconds (default: 300000 = 5 minutes)\r\n * @param options - Poll options\r\n * @returns Completion signal data\r\n * @throws TIMEOUT if signal not received within timeout\r\n * @throws FILE_READ_FAILED if read fails\r\n */\r\nexport async function pollForCompletion(\r\n workspace: WorkspacePath,\r\n timeoutMs?: number,\r\n options: PollOptions = {}\r\n): Promise<CompletionSignal> {\r\n const pollOptions = {\r\n ...DEFAULT_POLL_OPTIONS,\r\n ...(timeoutMs !== undefined ? { timeoutMs } : {}),\r\n ...options,\r\n };\r\n\r\n const startTime = Date.now();\r\n const endTime = startTime + pollOptions.timeoutMs;\r\n\r\n logger.debug('Starting completion polling', {\r\n taskId: workspace.taskId,\r\n agentId: workspace.agentId,\r\n timeoutMs: pollOptions.timeoutMs,\r\n intervalMs: pollOptions.intervalMs,\r\n });\r\n\r\n while (Date.now() < endTime) {\r\n // Try to read signal\r\n const signal = await readCompletionSignal(workspace);\r\n if (signal) {\r\n const elapsedMs = Date.now() - startTime;\r\n logger.info('Completion signal received', {\r\n taskId: workspace.taskId,\r\n agentId: workspace.agentId,\r\n success: signal.success,\r\n confidence: signal.confidence,\r\n elapsedMs,\r\n });\r\n return signal;\r\n }\r\n\r\n // Wait before next poll\r\n await sleep(pollOptions.intervalMs);\r\n }\r\n\r\n // Timeout reached\r\n const elapsedMs = Date.now() - startTime;\r\n throw createTimeoutError(\r\n 'Completion signal timeout',\r\n pollOptions.timeoutMs,\r\n {\r\n taskId: workspace.taskId,\r\n agentId: workspace.agentId,\r\n elapsedMs,\r\n }\r\n );\r\n}\r\n\r\n/**\r\n * Check if completion signal exists\r\n *\r\n * @param workspace - Workspace path information\r\n * @returns True if signal exists, false otherwise\r\n */\r\nexport async function hasCompletionSignal(\r\n workspace: WorkspacePath\r\n): Promise<boolean> {\r\n const signal = await readCompletionSignal(workspace);\r\n return signal !== null;\r\n}\r\n\r\n/**\r\n * Delete completion signal\r\n *\r\n * Useful for resetting workspace state.\r\n *\r\n * @param workspace - Workspace path information\r\n * @returns Promise that resolves when signal is deleted\r\n */\r\nexport async function deleteCompletionSignal(\r\n workspace: WorkspacePath\r\n): Promise<void> {\r\n const signalPath = path.join(workspace.path, COMPLETION_SIGNAL_FILE);\r\n\r\n try {\r\n const fs = await import('fs/promises');\r\n await fs.unlink(signalPath);\r\n logger.debug('Completion signal deleted', {\r\n taskId: workspace.taskId,\r\n agentId: workspace.agentId,\r\n });\r\n } catch (error) {\r\n const err = error as NodeJS.ErrnoException;\r\n if (err.code === 'ENOENT') {\r\n // Signal file doesn't exist, nothing to delete\r\n return;\r\n }\r\n throw error;\r\n }\r\n}\r\n\r\n/**\r\n * Validate completion signal data\r\n *\r\n * @param signal - Completion signal to validate\r\n * @throws INVALID_INPUT if signal is invalid\r\n */\r\nfunction validateSignal(signal: CompletionSignal): void {\r\n if (typeof signal.success !== 'boolean') {\r\n throw createError(\r\n ErrorCode.INVALID_INPUT,\r\n 'Signal success must be a boolean',\r\n { signal }\r\n );\r\n }\r\n\r\n if (\r\n typeof signal.confidence !== 'number' ||\r\n signal.confidence < 0 ||\r\n signal.confidence > 1\r\n ) {\r\n throw createError(\r\n ErrorCode.INVALID_INPUT,\r\n 'Signal confidence must be a number between 0 and 1',\r\n { signal }\r\n );\r\n }\r\n\r\n if (!Array.isArray(signal.deliverables)) {\r\n throw createError(\r\n ErrorCode.INVALID_INPUT,\r\n 'Signal deliverables must be an array',\r\n { signal }\r\n );\r\n }\r\n\r\n if (!signal.taskId || typeof signal.taskId !== 'string') {\r\n throw createError(\r\n ErrorCode.INVALID_INPUT,\r\n 'Signal taskId must be a non-empty string',\r\n { signal }\r\n );\r\n }\r\n\r\n if (!signal.agentId || typeof signal.agentId !== 'string') {\r\n throw createError(\r\n ErrorCode.INVALID_INPUT,\r\n 'Signal agentId must be a non-empty string',\r\n { signal }\r\n );\r\n }\r\n\r\n if (!(signal.timestamp instanceof Date)) {\r\n throw createError(\r\n ErrorCode.INVALID_INPUT,\r\n 'Signal timestamp must be a Date object',\r\n { signal }\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Sleep for specified duration\r\n *\r\n * @param ms - Duration in milliseconds\r\n * @returns Promise that resolves after duration\r\n */\r\nfunction sleep(ms: number): Promise<void> {\r\n return new Promise((resolve) => setTimeout(resolve, ms));\r\n}\r\n"],"names":["path","atomicWrite","createLogger","createError","ErrorCode","createTimeoutError","logger","COMPLETION_SIGNAL_FILE","DEFAULT_POLL_OPTIONS","timeoutMs","intervalMs","writeCompletionSignal","workspace","signal","validateSignal","signalPath","join","signalData","timestamp","toISOString","JSON","stringify","info","taskId","agentId","success","confidence","error","FILE_WRITE_FAILED","message","readCompletionSignal","fs","content","readFile","parse","Date","err","code","FILE_READ_FAILED","pollForCompletion","options","pollOptions","undefined","startTime","now","endTime","debug","elapsedMs","sleep","hasCompletionSignal","deleteCompletionSignal","unlink","INVALID_INPUT","Array","isArray","deliverables","ms","Promise","resolve","setTimeout"],"mappings":"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"}
|
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration Manager v2
|
|
3
|
+
* YAML-based configuration management with hot reload and migration support
|
|
4
|
+
*
|
|
5
|
+
* @version 2.0.0
|
|
6
|
+
* @description Standardized configuration management for CFN
|
|
7
|
+
*/ import * as fs from 'fs/promises';
|
|
8
|
+
import * as path from 'path';
|
|
9
|
+
import * as yaml from 'js-yaml';
|
|
10
|
+
import Ajv from 'ajv';
|
|
11
|
+
import { EventEmitter } from 'events';
|
|
12
|
+
import * as chokidar from 'chokidar';
|
|
13
|
+
/**
|
|
14
|
+
* ConfigManager - Type-safe YAML configuration management
|
|
15
|
+
*/ export class ConfigManager extends EventEmitter {
|
|
16
|
+
config = {};
|
|
17
|
+
configPath;
|
|
18
|
+
schemaPath;
|
|
19
|
+
ajv;
|
|
20
|
+
watcher = null;
|
|
21
|
+
environment = 'default';
|
|
22
|
+
options;
|
|
23
|
+
constructor(configPath, schemaPath, options = {}){
|
|
24
|
+
super();
|
|
25
|
+
this.configPath = configPath;
|
|
26
|
+
this.schemaPath = schemaPath;
|
|
27
|
+
this.ajv = new Ajv({
|
|
28
|
+
allErrors: true,
|
|
29
|
+
strict: false
|
|
30
|
+
});
|
|
31
|
+
this.options = {
|
|
32
|
+
enableHotReload: false,
|
|
33
|
+
validateOnLoad: true,
|
|
34
|
+
coerceTypes: true,
|
|
35
|
+
...options
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Load configuration from file
|
|
40
|
+
*/ async load(environment = 'default') {
|
|
41
|
+
this.environment = environment;
|
|
42
|
+
try {
|
|
43
|
+
// Load base configuration
|
|
44
|
+
const baseConfig = await this.loadConfigFile(this.configPath);
|
|
45
|
+
// Load environment-specific overrides if not default
|
|
46
|
+
let envConfig = {};
|
|
47
|
+
if (environment !== 'default') {
|
|
48
|
+
const envPath = this.getEnvironmentConfigPath(environment);
|
|
49
|
+
try {
|
|
50
|
+
envConfig = await this.loadConfigFile(envPath);
|
|
51
|
+
} catch (error) {
|
|
52
|
+
// Environment override file doesn't exist - that's okay
|
|
53
|
+
this.emit('warning', `Environment config not found: ${envPath}`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
// Merge configurations (environment overrides base)
|
|
57
|
+
this.config = this.deepMerge(baseConfig, envConfig);
|
|
58
|
+
// Type coercion if enabled
|
|
59
|
+
if (this.options.coerceTypes) {
|
|
60
|
+
this.config = this.coerceTypes(this.config);
|
|
61
|
+
}
|
|
62
|
+
// Validate against schema
|
|
63
|
+
if (this.options.validateOnLoad) {
|
|
64
|
+
await this.validate();
|
|
65
|
+
}
|
|
66
|
+
this.emit('loaded', this.config);
|
|
67
|
+
} catch (error) {
|
|
68
|
+
if (error instanceof Error) {
|
|
69
|
+
throw new Error(`Failed to load configuration: ${error.message}`);
|
|
70
|
+
}
|
|
71
|
+
throw error;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Load configuration from YAML or JSON file
|
|
76
|
+
*/ async loadConfigFile(filePath) {
|
|
77
|
+
const content = await fs.readFile(filePath, 'utf-8');
|
|
78
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
79
|
+
try {
|
|
80
|
+
if (ext === '.yml' || ext === '.yaml') {
|
|
81
|
+
return yaml.load(content);
|
|
82
|
+
} else if (ext === '.json') {
|
|
83
|
+
this.emit('warning', `JSON format is deprecated. Please migrate to YAML: ${filePath}`);
|
|
84
|
+
return JSON.parse(content);
|
|
85
|
+
} else {
|
|
86
|
+
throw new Error(`Unsupported configuration format: ${ext}`);
|
|
87
|
+
}
|
|
88
|
+
} catch (error) {
|
|
89
|
+
if (error instanceof yaml.YAMLException) {
|
|
90
|
+
throw new Error(`YAML parsing error: ${error.message}`);
|
|
91
|
+
}
|
|
92
|
+
throw error;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Get environment-specific config path
|
|
97
|
+
*/ getEnvironmentConfigPath(environment) {
|
|
98
|
+
const dir = path.dirname(this.configPath);
|
|
99
|
+
const ext = path.extname(this.configPath);
|
|
100
|
+
return path.join(dir, `${environment}${ext}`);
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Validate configuration against JSON schema
|
|
104
|
+
*/ async validate() {
|
|
105
|
+
const schemaContent = await fs.readFile(this.schemaPath, 'utf-8');
|
|
106
|
+
const schema = JSON.parse(schemaContent);
|
|
107
|
+
const validate = this.ajv.compile(schema);
|
|
108
|
+
const valid = validate(this.config);
|
|
109
|
+
if (!valid) {
|
|
110
|
+
const errors = validate.errors?.map((err)=>`${err.instancePath} ${err.message}`).join(', ');
|
|
111
|
+
throw new Error(`Configuration schema validation failed: ${errors}`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Coerce types from strings to proper types
|
|
116
|
+
*/ coerceTypes(obj, parentKey) {
|
|
117
|
+
if (obj === null || obj === undefined) {
|
|
118
|
+
return obj;
|
|
119
|
+
}
|
|
120
|
+
if (Array.isArray(obj)) {
|
|
121
|
+
return obj.map((item)=>this.coerceTypes(item));
|
|
122
|
+
}
|
|
123
|
+
if (typeof obj === 'object') {
|
|
124
|
+
const coerced = {};
|
|
125
|
+
for (const [key, value] of Object.entries(obj)){
|
|
126
|
+
coerced[key] = this.coerceTypes(value, key);
|
|
127
|
+
}
|
|
128
|
+
return coerced;
|
|
129
|
+
}
|
|
130
|
+
if (typeof obj === 'string') {
|
|
131
|
+
// Don't coerce 'version' fields - keep as strings
|
|
132
|
+
if (parentKey === 'version') {
|
|
133
|
+
return obj;
|
|
134
|
+
}
|
|
135
|
+
// Boolean coercion (case insensitive)
|
|
136
|
+
const lower = obj.toLowerCase();
|
|
137
|
+
if (lower === 'true') return true;
|
|
138
|
+
if (lower === 'false') return false;
|
|
139
|
+
// Null coercion
|
|
140
|
+
if (lower === 'null') return null;
|
|
141
|
+
// Number coercion - only if it looks like a pure number
|
|
142
|
+
// Don't coerce version strings like "1.0", "2.5.0"
|
|
143
|
+
if (/^-?\d+$/.test(obj)) {
|
|
144
|
+
return parseInt(obj, 10);
|
|
145
|
+
}
|
|
146
|
+
if (/^-?\d+\.\d+$/.test(obj) && !obj.match(/\d+\.\d+\.\d+/)) {
|
|
147
|
+
return parseFloat(obj);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return obj;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Deep merge two objects
|
|
154
|
+
*/ deepMerge(target, source) {
|
|
155
|
+
if (!source) return target;
|
|
156
|
+
if (!target) return source;
|
|
157
|
+
const output = {
|
|
158
|
+
...target
|
|
159
|
+
};
|
|
160
|
+
for(const key in source){
|
|
161
|
+
if (source.hasOwnProperty(key)) {
|
|
162
|
+
if (typeof source[key] === 'object' && source[key] !== null && !Array.isArray(source[key])) {
|
|
163
|
+
if (key in output) {
|
|
164
|
+
output[key] = this.deepMerge(output[key], source[key]);
|
|
165
|
+
} else {
|
|
166
|
+
output[key] = source[key];
|
|
167
|
+
}
|
|
168
|
+
} else {
|
|
169
|
+
output[key] = source[key];
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return output;
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Get configuration value by key path
|
|
177
|
+
*/ get(keyPath, defaultValue) {
|
|
178
|
+
const keys = keyPath.split('.');
|
|
179
|
+
let value = this.config;
|
|
180
|
+
for (const key of keys){
|
|
181
|
+
if (value && typeof value === 'object' && key in value) {
|
|
182
|
+
value = value[key];
|
|
183
|
+
} else {
|
|
184
|
+
return defaultValue;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return value;
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Get all configuration
|
|
191
|
+
*/ getAll() {
|
|
192
|
+
return {
|
|
193
|
+
...this.config
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Set configuration value (runtime only, not persisted)
|
|
198
|
+
*/ set(keyPath, value) {
|
|
199
|
+
const keys = keyPath.split('.');
|
|
200
|
+
let current = this.config;
|
|
201
|
+
for(let i = 0; i < keys.length - 1; i++){
|
|
202
|
+
const key = keys[i];
|
|
203
|
+
if (!(key in current) || typeof current[key] !== 'object') {
|
|
204
|
+
current[key] = {};
|
|
205
|
+
}
|
|
206
|
+
current = current[key];
|
|
207
|
+
}
|
|
208
|
+
current[keys[keys.length - 1]] = value;
|
|
209
|
+
this.emit('changed', keyPath, value);
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Enable hot reload (file watching)
|
|
213
|
+
*/ async enableHotReload() {
|
|
214
|
+
if (this.watcher) {
|
|
215
|
+
return; // Already watching
|
|
216
|
+
}
|
|
217
|
+
const watchPaths = [
|
|
218
|
+
this.configPath
|
|
219
|
+
];
|
|
220
|
+
// Add environment-specific config if not default
|
|
221
|
+
if (this.environment !== 'default') {
|
|
222
|
+
watchPaths.push(this.getEnvironmentConfigPath(this.environment));
|
|
223
|
+
}
|
|
224
|
+
this.watcher = chokidar.watch(watchPaths, {
|
|
225
|
+
persistent: true,
|
|
226
|
+
ignoreInitial: true,
|
|
227
|
+
awaitWriteFinish: {
|
|
228
|
+
stabilityThreshold: 300,
|
|
229
|
+
pollInterval: 100
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
this.watcher.on('change', async (filePath)=>{
|
|
233
|
+
try {
|
|
234
|
+
await this.reload();
|
|
235
|
+
this.emit('reload', this.config);
|
|
236
|
+
} catch (error) {
|
|
237
|
+
this.emit('error', error);
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
this.emit('hotReloadEnabled');
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Disable hot reload
|
|
244
|
+
*/ async disableHotReload() {
|
|
245
|
+
if (this.watcher) {
|
|
246
|
+
await this.watcher.close();
|
|
247
|
+
this.watcher = null;
|
|
248
|
+
this.emit('hotReloadDisabled');
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Reload configuration from disk
|
|
253
|
+
*/ async reload() {
|
|
254
|
+
await this.load(this.environment);
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Check if configuration has a key
|
|
258
|
+
*/ has(keyPath) {
|
|
259
|
+
const keys = keyPath.split('.');
|
|
260
|
+
let value = this.config;
|
|
261
|
+
for (const key of keys){
|
|
262
|
+
if (value && typeof value === 'object' && key in value) {
|
|
263
|
+
value = value[key];
|
|
264
|
+
} else {
|
|
265
|
+
return false;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
return true;
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Export configuration to YAML string
|
|
272
|
+
*/ toYAML() {
|
|
273
|
+
return yaml.dump(this.config, {
|
|
274
|
+
indent: 2,
|
|
275
|
+
lineWidth: 80,
|
|
276
|
+
noRefs: true
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Export configuration to JSON string
|
|
281
|
+
*/ toJSON() {
|
|
282
|
+
return JSON.stringify(this.config, null, 2);
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Cleanup resources
|
|
286
|
+
*/ async destroy() {
|
|
287
|
+
await this.disableHotReload();
|
|
288
|
+
this.removeAllListeners();
|
|
289
|
+
this.config = {};
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Singleton instance for global configuration
|
|
294
|
+
*/ let globalInstance = null;
|
|
295
|
+
export function getGlobalConfigManager() {
|
|
296
|
+
if (!globalInstance) {
|
|
297
|
+
throw new Error('ConfigManager not initialized. Call initializeConfigManager() first.');
|
|
298
|
+
}
|
|
299
|
+
return globalInstance;
|
|
300
|
+
}
|
|
301
|
+
export function initializeConfigManager(configPath, schemaPath, options) {
|
|
302
|
+
globalInstance = new ConfigManager(configPath, schemaPath, options);
|
|
303
|
+
return globalInstance;
|
|
304
|
+
}
|
|
305
|
+
export function resetGlobalConfigManager() {
|
|
306
|
+
if (globalInstance) {
|
|
307
|
+
globalInstance.destroy();
|
|
308
|
+
globalInstance = null;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
//# sourceMappingURL=config-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/lib/config-manager.ts"],"sourcesContent":["/**\r\n * Configuration Manager v2\r\n * YAML-based configuration management with hot reload and migration support\r\n *\r\n * @version 2.0.0\r\n * @description Standardized configuration management for CFN\r\n */\r\n\r\nimport * as fs from 'fs/promises';\r\nimport * as path from 'path';\r\nimport * as yaml from 'js-yaml';\r\nimport Ajv, { JSONSchemaType } from 'ajv';\r\nimport { EventEmitter } from 'events';\r\nimport * as chokidar from 'chokidar';\r\n\r\nexport interface ConfigValue {\r\n [key: string]: string | number | boolean | ConfigValue | ConfigValue[] | null;\r\n}\r\n\r\nexport interface ConfigSchema {\r\n version?: string;\r\n [key: string]: ConfigValue | string | number | boolean | null | undefined;\r\n}\r\n\r\nexport interface ConfigManagerOptions {\r\n enableHotReload?: boolean;\r\n validateOnLoad?: boolean;\r\n coerceTypes?: boolean;\r\n}\r\n\r\n/**\r\n * ConfigManager - Type-safe YAML configuration management\r\n */\r\nexport class ConfigManager extends EventEmitter {\r\n private config: ConfigSchema = {};\r\n private configPath: string;\r\n private schemaPath: string;\r\n private ajv: Ajv;\r\n private watcher: chokidar.FSWatcher | null = null;\r\n private environment: string = 'default';\r\n private options: ConfigManagerOptions;\r\n\r\n constructor(\r\n configPath: string,\r\n schemaPath: string,\r\n options: ConfigManagerOptions = {}\r\n ) {\r\n super();\r\n this.configPath = configPath;\r\n this.schemaPath = schemaPath;\r\n this.ajv = new Ajv({ allErrors: true, strict: false });\r\n this.options = {\r\n enableHotReload: false,\r\n validateOnLoad: true,\r\n coerceTypes: true,\r\n ...options\r\n };\r\n }\r\n\r\n /**\r\n * Load configuration from file\r\n */\r\n async load(environment: string = 'default'): Promise<void> {\r\n this.environment = environment;\r\n\r\n try {\r\n // Load base configuration\r\n const baseConfig = await this.loadConfigFile(this.configPath);\r\n\r\n // Load environment-specific overrides if not default\r\n let envConfig: ConfigSchema = {};\r\n if (environment !== 'default') {\r\n const envPath = this.getEnvironmentConfigPath(environment);\r\n try {\r\n envConfig = await this.loadConfigFile(envPath);\r\n } catch (error) {\r\n // Environment override file doesn't exist - that's okay\r\n this.emit('warning', `Environment config not found: ${envPath}`);\r\n }\r\n }\r\n\r\n // Merge configurations (environment overrides base)\r\n this.config = this.deepMerge(baseConfig, envConfig);\r\n\r\n // Type coercion if enabled\r\n if (this.options.coerceTypes) {\r\n this.config = this.coerceTypes(this.config);\r\n }\r\n\r\n // Validate against schema\r\n if (this.options.validateOnLoad) {\r\n await this.validate();\r\n }\r\n\r\n this.emit('loaded', this.config);\r\n } catch (error) {\r\n if (error instanceof Error) {\r\n throw new Error(`Failed to load configuration: ${error.message}`);\r\n }\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Load configuration from YAML or JSON file\r\n */\r\n private async loadConfigFile(filePath: string): Promise<ConfigSchema> {\r\n const content = await fs.readFile(filePath, 'utf-8');\r\n const ext = path.extname(filePath).toLowerCase();\r\n\r\n try {\r\n if (ext === '.yml' || ext === '.yaml') {\r\n return yaml.load(content) as ConfigSchema;\r\n } else if (ext === '.json') {\r\n this.emit('warning', `JSON format is deprecated. Please migrate to YAML: ${filePath}`);\r\n return JSON.parse(content) as ConfigSchema;\r\n } else {\r\n throw new Error(`Unsupported configuration format: ${ext}`);\r\n }\r\n } catch (error) {\r\n if (error instanceof yaml.YAMLException) {\r\n throw new Error(`YAML parsing error: ${error.message}`);\r\n }\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Get environment-specific config path\r\n */\r\n private getEnvironmentConfigPath(environment: string): string {\r\n const dir = path.dirname(this.configPath);\r\n const ext = path.extname(this.configPath);\r\n return path.join(dir, `${environment}${ext}`);\r\n }\r\n\r\n /**\r\n * Validate configuration against JSON schema\r\n */\r\n private async validate(): Promise<void> {\r\n const schemaContent = await fs.readFile(this.schemaPath, 'utf-8');\r\n const schema = JSON.parse(schemaContent);\r\n\r\n const validate = this.ajv.compile(schema);\r\n const valid = validate(this.config);\r\n\r\n if (!valid) {\r\n const errors = validate.errors?.map(err =>\r\n `${err.instancePath} ${err.message}`\r\n ).join(', ');\r\n throw new Error(`Configuration schema validation failed: ${errors}`);\r\n }\r\n }\r\n\r\n /**\r\n * Coerce types from strings to proper types\r\n */\r\n private coerceTypes(obj: any, parentKey?: string): any {\r\n if (obj === null || obj === undefined) {\r\n return obj;\r\n }\r\n\r\n if (Array.isArray(obj)) {\r\n return obj.map(item => this.coerceTypes(item));\r\n }\r\n\r\n if (typeof obj === 'object') {\r\n const coerced: any = {};\r\n for (const [key, value] of Object.entries(obj)) {\r\n coerced[key] = this.coerceTypes(value, key);\r\n }\r\n return coerced;\r\n }\r\n\r\n if (typeof obj === 'string') {\r\n // Don't coerce 'version' fields - keep as strings\r\n if (parentKey === 'version') {\r\n return obj;\r\n }\r\n\r\n // Boolean coercion (case insensitive)\r\n const lower = obj.toLowerCase();\r\n if (lower === 'true') return true;\r\n if (lower === 'false') return false;\r\n\r\n // Null coercion\r\n if (lower === 'null') return null;\r\n\r\n // Number coercion - only if it looks like a pure number\r\n // Don't coerce version strings like \"1.0\", \"2.5.0\"\r\n if (/^-?\\d+$/.test(obj)) {\r\n return parseInt(obj, 10);\r\n }\r\n if (/^-?\\d+\\.\\d+$/.test(obj) && !obj.match(/\\d+\\.\\d+\\.\\d+/)) {\r\n return parseFloat(obj);\r\n }\r\n }\r\n\r\n return obj;\r\n }\r\n\r\n /**\r\n * Deep merge two objects\r\n */\r\n private deepMerge(target: any, source: any): any {\r\n if (!source) return target;\r\n if (!target) return source;\r\n\r\n const output = { ...target };\r\n\r\n for (const key in source) {\r\n if (source.hasOwnProperty(key)) {\r\n if (\r\n typeof source[key] === 'object' &&\r\n source[key] !== null &&\r\n !Array.isArray(source[key])\r\n ) {\r\n if (key in output) {\r\n output[key] = this.deepMerge(output[key], source[key]);\r\n } else {\r\n output[key] = source[key];\r\n }\r\n } else {\r\n output[key] = source[key];\r\n }\r\n }\r\n }\r\n\r\n return output;\r\n }\r\n\r\n /**\r\n * Get configuration value by key path\r\n */\r\n get<T = any>(keyPath: string, defaultValue?: T): T {\r\n const keys = keyPath.split('.');\r\n let value: any = this.config;\r\n\r\n for (const key of keys) {\r\n if (value && typeof value === 'object' && key in value) {\r\n value = value[key];\r\n } else {\r\n return defaultValue as T;\r\n }\r\n }\r\n\r\n return value as T;\r\n }\r\n\r\n /**\r\n * Get all configuration\r\n */\r\n getAll(): ConfigSchema {\r\n return { ...this.config };\r\n }\r\n\r\n /**\r\n * Set configuration value (runtime only, not persisted)\r\n */\r\n set(keyPath: string, value: any): void {\r\n const keys = keyPath.split('.');\r\n let current: any = this.config;\r\n\r\n for (let i = 0; i < keys.length - 1; i++) {\r\n const key = keys[i];\r\n if (!(key in current) || typeof current[key] !== 'object') {\r\n current[key] = {};\r\n }\r\n current = current[key];\r\n }\r\n\r\n current[keys[keys.length - 1]] = value;\r\n this.emit('changed', keyPath, value);\r\n }\r\n\r\n /**\r\n * Enable hot reload (file watching)\r\n */\r\n async enableHotReload(): Promise<void> {\r\n if (this.watcher) {\r\n return; // Already watching\r\n }\r\n\r\n const watchPaths = [this.configPath];\r\n\r\n // Add environment-specific config if not default\r\n if (this.environment !== 'default') {\r\n watchPaths.push(this.getEnvironmentConfigPath(this.environment));\r\n }\r\n\r\n this.watcher = chokidar.watch(watchPaths, {\r\n persistent: true,\r\n ignoreInitial: true,\r\n awaitWriteFinish: {\r\n stabilityThreshold: 300,\r\n pollInterval: 100\r\n }\r\n });\r\n\r\n this.watcher.on('change', async (filePath: string) => {\r\n try {\r\n await this.reload();\r\n this.emit('reload', this.config);\r\n } catch (error) {\r\n this.emit('error', error);\r\n }\r\n });\r\n\r\n this.emit('hotReloadEnabled');\r\n }\r\n\r\n /**\r\n * Disable hot reload\r\n */\r\n async disableHotReload(): Promise<void> {\r\n if (this.watcher) {\r\n await this.watcher.close();\r\n this.watcher = null;\r\n this.emit('hotReloadDisabled');\r\n }\r\n }\r\n\r\n /**\r\n * Reload configuration from disk\r\n */\r\n async reload(): Promise<void> {\r\n await this.load(this.environment);\r\n }\r\n\r\n /**\r\n * Check if configuration has a key\r\n */\r\n has(keyPath: string): boolean {\r\n const keys = keyPath.split('.');\r\n let value: any = this.config;\r\n\r\n for (const key of keys) {\r\n if (value && typeof value === 'object' && key in value) {\r\n value = value[key];\r\n } else {\r\n return false;\r\n }\r\n }\r\n\r\n return true;\r\n }\r\n\r\n /**\r\n * Export configuration to YAML string\r\n */\r\n toYAML(): string {\r\n return yaml.dump(this.config, {\r\n indent: 2,\r\n lineWidth: 80,\r\n noRefs: true\r\n });\r\n }\r\n\r\n /**\r\n * Export configuration to JSON string\r\n */\r\n toJSON(): string {\r\n return JSON.stringify(this.config, null, 2);\r\n }\r\n\r\n /**\r\n * Cleanup resources\r\n */\r\n async destroy(): Promise<void> {\r\n await this.disableHotReload();\r\n this.removeAllListeners();\r\n this.config = {};\r\n }\r\n}\r\n\r\n/**\r\n * Singleton instance for global configuration\r\n */\r\nlet globalInstance: ConfigManager | null = null;\r\n\r\nexport function getGlobalConfigManager(): ConfigManager {\r\n if (!globalInstance) {\r\n throw new Error('ConfigManager not initialized. Call initializeConfigManager() first.');\r\n }\r\n return globalInstance;\r\n}\r\n\r\nexport function initializeConfigManager(\r\n configPath: string,\r\n schemaPath: string,\r\n options?: ConfigManagerOptions\r\n): ConfigManager {\r\n globalInstance = new ConfigManager(configPath, schemaPath, options);\r\n return globalInstance;\r\n}\r\n\r\nexport function resetGlobalConfigManager(): void {\r\n if (globalInstance) {\r\n globalInstance.destroy();\r\n globalInstance = null;\r\n }\r\n}\r\n"],"names":["fs","path","yaml","Ajv","EventEmitter","chokidar","ConfigManager","config","configPath","schemaPath","ajv","watcher","environment","options","allErrors","strict","enableHotReload","validateOnLoad","coerceTypes","load","baseConfig","loadConfigFile","envConfig","envPath","getEnvironmentConfigPath","error","emit","deepMerge","validate","Error","message","filePath","content","readFile","ext","extname","toLowerCase","JSON","parse","YAMLException","dir","dirname","join","schemaContent","schema","compile","valid","errors","map","err","instancePath","obj","parentKey","undefined","Array","isArray","item","coerced","key","value","Object","entries","lower","test","parseInt","match","parseFloat","target","source","output","hasOwnProperty","get","keyPath","defaultValue","keys","split","getAll","set","current","i","length","watchPaths","push","watch","persistent","ignoreInitial","awaitWriteFinish","stabilityThreshold","pollInterval","on","reload","disableHotReload","close","has","toYAML","dump","indent","lineWidth","noRefs","toJSON","stringify","destroy","removeAllListeners","globalInstance","getGlobalConfigManager","initializeConfigManager","resetGlobalConfigManager"],"mappings":"AAAA;;;;;;CAMC,GAED,YAAYA,QAAQ,cAAc;AAClC,YAAYC,UAAU,OAAO;AAC7B,YAAYC,UAAU,UAAU;AAChC,OAAOC,SAA6B,MAAM;AAC1C,SAASC,YAAY,QAAQ,SAAS;AACtC,YAAYC,cAAc,WAAW;AAiBrC;;CAEC,GACD,OAAO,MAAMC,sBAAsBF;IACzBG,SAAuB,CAAC,EAAE;IAC1BC,WAAmB;IACnBC,WAAmB;IACnBC,IAAS;IACTC,UAAqC,KAAK;IAC1CC,cAAsB,UAAU;IAChCC,QAA8B;IAEtC,YACEL,UAAkB,EAClBC,UAAkB,EAClBI,UAAgC,CAAC,CAAC,CAClC;QACA,KAAK;QACL,IAAI,CAACL,UAAU,GAAGA;QAClB,IAAI,CAACC,UAAU,GAAGA;QAClB,IAAI,CAACC,GAAG,GAAG,IAAIP,IAAI;YAAEW,WAAW;YAAMC,QAAQ;QAAM;QACpD,IAAI,CAACF,OAAO,GAAG;YACbG,iBAAiB;YACjBC,gBAAgB;YAChBC,aAAa;YACb,GAAGL,OAAO;QACZ;IACF;IAEA;;GAEC,GACD,MAAMM,KAAKP,cAAsB,SAAS,EAAiB;QACzD,IAAI,CAACA,WAAW,GAAGA;QAEnB,IAAI;YACF,0BAA0B;YAC1B,MAAMQ,aAAa,MAAM,IAAI,CAACC,cAAc,CAAC,IAAI,CAACb,UAAU;YAE5D,qDAAqD;YACrD,IAAIc,YAA0B,CAAC;YAC/B,IAAIV,gBAAgB,WAAW;gBAC7B,MAAMW,UAAU,IAAI,CAACC,wBAAwB,CAACZ;gBAC9C,IAAI;oBACFU,YAAY,MAAM,IAAI,CAACD,cAAc,CAACE;gBACxC,EAAE,OAAOE,OAAO;oBACd,wDAAwD;oBACxD,IAAI,CAACC,IAAI,CAAC,WAAW,CAAC,8BAA8B,EAAEH,SAAS;gBACjE;YACF;YAEA,oDAAoD;YACpD,IAAI,CAAChB,MAAM,GAAG,IAAI,CAACoB,SAAS,CAACP,YAAYE;YAEzC,2BAA2B;YAC3B,IAAI,IAAI,CAACT,OAAO,CAACK,WAAW,EAAE;gBAC5B,IAAI,CAACX,MAAM,GAAG,IAAI,CAACW,WAAW,CAAC,IAAI,CAACX,MAAM;YAC5C;YAEA,0BAA0B;YAC1B,IAAI,IAAI,CAACM,OAAO,CAACI,cAAc,EAAE;gBAC/B,MAAM,IAAI,CAACW,QAAQ;YACrB;YAEA,IAAI,CAACF,IAAI,CAAC,UAAU,IAAI,CAACnB,MAAM;QACjC,EAAE,OAAOkB,OAAO;YACd,IAAIA,iBAAiBI,OAAO;gBAC1B,MAAM,IAAIA,MAAM,CAAC,8BAA8B,EAAEJ,MAAMK,OAAO,EAAE;YAClE;YACA,MAAML;QACR;IACF;IAEA;;GAEC,GACD,MAAcJ,eAAeU,QAAgB,EAAyB;QACpE,MAAMC,UAAU,MAAMhC,GAAGiC,QAAQ,CAACF,UAAU;QAC5C,MAAMG,MAAMjC,KAAKkC,OAAO,CAACJ,UAAUK,WAAW;QAE9C,IAAI;YACF,IAAIF,QAAQ,UAAUA,QAAQ,SAAS;gBACrC,OAAOhC,KAAKiB,IAAI,CAACa;YACnB,OAAO,IAAIE,QAAQ,SAAS;gBAC1B,IAAI,CAACR,IAAI,CAAC,WAAW,CAAC,mDAAmD,EAAEK,UAAU;gBACrF,OAAOM,KAAKC,KAAK,CAACN;YACpB,OAAO;gBACL,MAAM,IAAIH,MAAM,CAAC,kCAAkC,EAAEK,KAAK;YAC5D;QACF,EAAE,OAAOT,OAAO;YACd,IAAIA,iBAAiBvB,KAAKqC,aAAa,EAAE;gBACvC,MAAM,IAAIV,MAAM,CAAC,oBAAoB,EAAEJ,MAAMK,OAAO,EAAE;YACxD;YACA,MAAML;QACR;IACF;IAEA;;GAEC,GACD,AAAQD,yBAAyBZ,WAAmB,EAAU;QAC5D,MAAM4B,MAAMvC,KAAKwC,OAAO,CAAC,IAAI,CAACjC,UAAU;QACxC,MAAM0B,MAAMjC,KAAKkC,OAAO,CAAC,IAAI,CAAC3B,UAAU;QACxC,OAAOP,KAAKyC,IAAI,CAACF,KAAK,GAAG5B,cAAcsB,KAAK;IAC9C;IAEA;;GAEC,GACD,MAAcN,WAA0B;QACtC,MAAMe,gBAAgB,MAAM3C,GAAGiC,QAAQ,CAAC,IAAI,CAACxB,UAAU,EAAE;QACzD,MAAMmC,SAASP,KAAKC,KAAK,CAACK;QAE1B,MAAMf,WAAW,IAAI,CAAClB,GAAG,CAACmC,OAAO,CAACD;QAClC,MAAME,QAAQlB,SAAS,IAAI,CAACrB,MAAM;QAElC,IAAI,CAACuC,OAAO;YACV,MAAMC,SAASnB,SAASmB,MAAM,EAAEC,IAAIC,CAAAA,MAClC,GAAGA,IAAIC,YAAY,CAAC,CAAC,EAAED,IAAInB,OAAO,EAAE,EACpCY,KAAK;YACP,MAAM,IAAIb,MAAM,CAAC,wCAAwC,EAAEkB,QAAQ;QACrE;IACF;IAEA;;GAEC,GACD,AAAQ7B,YAAYiC,GAAQ,EAAEC,SAAkB,EAAO;QACrD,IAAID,QAAQ,QAAQA,QAAQE,WAAW;YACrC,OAAOF;QACT;QAEA,IAAIG,MAAMC,OAAO,CAACJ,MAAM;YACtB,OAAOA,IAAIH,GAAG,CAACQ,CAAAA,OAAQ,IAAI,CAACtC,WAAW,CAACsC;QAC1C;QAEA,IAAI,OAAOL,QAAQ,UAAU;YAC3B,MAAMM,UAAe,CAAC;YACtB,KAAK,MAAM,CAACC,KAAKC,MAAM,IAAIC,OAAOC,OAAO,CAACV,KAAM;gBAC9CM,OAAO,CAACC,IAAI,GAAG,IAAI,CAACxC,WAAW,CAACyC,OAAOD;YACzC;YACA,OAAOD;QACT;QAEA,IAAI,OAAON,QAAQ,UAAU;YAC3B,kDAAkD;YAClD,IAAIC,cAAc,WAAW;gBAC3B,OAAOD;YACT;YAEA,sCAAsC;YACtC,MAAMW,QAAQX,IAAIf,WAAW;YAC7B,IAAI0B,UAAU,QAAQ,OAAO;YAC7B,IAAIA,UAAU,SAAS,OAAO;YAE9B,gBAAgB;YAChB,IAAIA,UAAU,QAAQ,OAAO;YAE7B,wDAAwD;YACxD,mDAAmD;YACnD,IAAI,UAAUC,IAAI,CAACZ,MAAM;gBACvB,OAAOa,SAASb,KAAK;YACvB;YACA,IAAI,eAAeY,IAAI,CAACZ,QAAQ,CAACA,IAAIc,KAAK,CAAC,kBAAkB;gBAC3D,OAAOC,WAAWf;YACpB;QACF;QAEA,OAAOA;IACT;IAEA;;GAEC,GACD,AAAQxB,UAAUwC,MAAW,EAAEC,MAAW,EAAO;QAC/C,IAAI,CAACA,QAAQ,OAAOD;QACpB,IAAI,CAACA,QAAQ,OAAOC;QAEpB,MAAMC,SAAS;YAAE,GAAGF,MAAM;QAAC;QAE3B,IAAK,MAAMT,OAAOU,OAAQ;YACxB,IAAIA,OAAOE,cAAc,CAACZ,MAAM;gBAC9B,IACE,OAAOU,MAAM,CAACV,IAAI,KAAK,YACvBU,MAAM,CAACV,IAAI,KAAK,QAChB,CAACJ,MAAMC,OAAO,CAACa,MAAM,CAACV,IAAI,GAC1B;oBACA,IAAIA,OAAOW,QAAQ;wBACjBA,MAAM,CAACX,IAAI,GAAG,IAAI,CAAC/B,SAAS,CAAC0C,MAAM,CAACX,IAAI,EAAEU,MAAM,CAACV,IAAI;oBACvD,OAAO;wBACLW,MAAM,CAACX,IAAI,GAAGU,MAAM,CAACV,IAAI;oBAC3B;gBACF,OAAO;oBACLW,MAAM,CAACX,IAAI,GAAGU,MAAM,CAACV,IAAI;gBAC3B;YACF;QACF;QAEA,OAAOW;IACT;IAEA;;GAEC,GACDE,IAAaC,OAAe,EAAEC,YAAgB,EAAK;QACjD,MAAMC,OAAOF,QAAQG,KAAK,CAAC;QAC3B,IAAIhB,QAAa,IAAI,CAACpD,MAAM;QAE5B,KAAK,MAAMmD,OAAOgB,KAAM;YACtB,IAAIf,SAAS,OAAOA,UAAU,YAAYD,OAAOC,OAAO;gBACtDA,QAAQA,KAAK,CAACD,IAAI;YACpB,OAAO;gBACL,OAAOe;YACT;QACF;QAEA,OAAOd;IACT;IAEA;;GAEC,GACDiB,SAAuB;QACrB,OAAO;YAAE,GAAG,IAAI,CAACrE,MAAM;QAAC;IAC1B;IAEA;;GAEC,GACDsE,IAAIL,OAAe,EAAEb,KAAU,EAAQ;QACrC,MAAMe,OAAOF,QAAQG,KAAK,CAAC;QAC3B,IAAIG,UAAe,IAAI,CAACvE,MAAM;QAE9B,IAAK,IAAIwE,IAAI,GAAGA,IAAIL,KAAKM,MAAM,GAAG,GAAGD,IAAK;YACxC,MAAMrB,MAAMgB,IAAI,CAACK,EAAE;YACnB,IAAI,CAAErB,CAAAA,OAAOoB,OAAM,KAAM,OAAOA,OAAO,CAACpB,IAAI,KAAK,UAAU;gBACzDoB,OAAO,CAACpB,IAAI,GAAG,CAAC;YAClB;YACAoB,UAAUA,OAAO,CAACpB,IAAI;QACxB;QAEAoB,OAAO,CAACJ,IAAI,CAACA,KAAKM,MAAM,GAAG,EAAE,CAAC,GAAGrB;QACjC,IAAI,CAACjC,IAAI,CAAC,WAAW8C,SAASb;IAChC;IAEA;;GAEC,GACD,MAAM3C,kBAAiC;QACrC,IAAI,IAAI,CAACL,OAAO,EAAE;YAChB,QAAQ,mBAAmB;QAC7B;QAEA,MAAMsE,aAAa;YAAC,IAAI,CAACzE,UAAU;SAAC;QAEpC,iDAAiD;QACjD,IAAI,IAAI,CAACI,WAAW,KAAK,WAAW;YAClCqE,WAAWC,IAAI,CAAC,IAAI,CAAC1D,wBAAwB,CAAC,IAAI,CAACZ,WAAW;QAChE;QAEA,IAAI,CAACD,OAAO,GAAGN,SAAS8E,KAAK,CAACF,YAAY;YACxCG,YAAY;YACZC,eAAe;YACfC,kBAAkB;gBAChBC,oBAAoB;gBACpBC,cAAc;YAChB;QACF;QAEA,IAAI,CAAC7E,OAAO,CAAC8E,EAAE,CAAC,UAAU,OAAO1D;YAC/B,IAAI;gBACF,MAAM,IAAI,CAAC2D,MAAM;gBACjB,IAAI,CAAChE,IAAI,CAAC,UAAU,IAAI,CAACnB,MAAM;YACjC,EAAE,OAAOkB,OAAO;gBACd,IAAI,CAACC,IAAI,CAAC,SAASD;YACrB;QACF;QAEA,IAAI,CAACC,IAAI,CAAC;IACZ;IAEA;;GAEC,GACD,MAAMiE,mBAAkC;QACtC,IAAI,IAAI,CAAChF,OAAO,EAAE;YAChB,MAAM,IAAI,CAACA,OAAO,CAACiF,KAAK;YACxB,IAAI,CAACjF,OAAO,GAAG;YACf,IAAI,CAACe,IAAI,CAAC;QACZ;IACF;IAEA;;GAEC,GACD,MAAMgE,SAAwB;QAC5B,MAAM,IAAI,CAACvE,IAAI,CAAC,IAAI,CAACP,WAAW;IAClC;IAEA;;GAEC,GACDiF,IAAIrB,OAAe,EAAW;QAC5B,MAAME,OAAOF,QAAQG,KAAK,CAAC;QAC3B,IAAIhB,QAAa,IAAI,CAACpD,MAAM;QAE5B,KAAK,MAAMmD,OAAOgB,KAAM;YACtB,IAAIf,SAAS,OAAOA,UAAU,YAAYD,OAAOC,OAAO;gBACtDA,QAAQA,KAAK,CAACD,IAAI;YACpB,OAAO;gBACL,OAAO;YACT;QACF;QAEA,OAAO;IACT;IAEA;;GAEC,GACDoC,SAAiB;QACf,OAAO5F,KAAK6F,IAAI,CAAC,IAAI,CAACxF,MAAM,EAAE;YAC5ByF,QAAQ;YACRC,WAAW;YACXC,QAAQ;QACV;IACF;IAEA;;GAEC,GACDC,SAAiB;QACf,OAAO9D,KAAK+D,SAAS,CAAC,IAAI,CAAC7F,MAAM,EAAE,MAAM;IAC3C;IAEA;;GAEC,GACD,MAAM8F,UAAyB;QAC7B,MAAM,IAAI,CAACV,gBAAgB;QAC3B,IAAI,CAACW,kBAAkB;QACvB,IAAI,CAAC/F,MAAM,GAAG,CAAC;IACjB;AACF;AAEA;;CAEC,GACD,IAAIgG,iBAAuC;AAE3C,OAAO,SAASC;IACd,IAAI,CAACD,gBAAgB;QACnB,MAAM,IAAI1E,MAAM;IAClB;IACA,OAAO0E;AACT;AAEA,OAAO,SAASE,wBACdjG,UAAkB,EAClBC,UAAkB,EAClBI,OAA8B;IAE9B0F,iBAAiB,IAAIjG,cAAcE,YAAYC,YAAYI;IAC3D,OAAO0F;AACT;AAEA,OAAO,SAASG;IACd,IAAIH,gBAAgB;QAClBA,eAAeF,OAAO;QACtBE,iBAAiB;IACnB;AACF"}
|