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,454 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skill Validator Service
|
|
3
|
+
*
|
|
4
|
+
* Validates skill content, schema compliance, and deployment readiness.
|
|
5
|
+
* Part of Task 1.1: Automated Skill Deployment Pipeline
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* const result = await validateSkill(dbService, '/path/to/skill');
|
|
10
|
+
* if (!result.valid) {
|
|
11
|
+
* console.error('Validation failed:', result.errors);
|
|
12
|
+
* }
|
|
13
|
+
* ```
|
|
14
|
+
*/ import * as fs from 'fs';
|
|
15
|
+
import * as path from 'path';
|
|
16
|
+
import { StandardError, ErrorCode } from '../lib/errors.js';
|
|
17
|
+
import { createLogger } from '../lib/logging.js';
|
|
18
|
+
import { validateVersion } from './skill-versioning.js';
|
|
19
|
+
const logger = createLogger('skill-validator');
|
|
20
|
+
/**
|
|
21
|
+
* Parse frontmatter from SKILL.md file
|
|
22
|
+
*
|
|
23
|
+
* @param skillPath - Path to skill directory
|
|
24
|
+
* @returns Parsed frontmatter object
|
|
25
|
+
* @throws StandardError if frontmatter is invalid or missing
|
|
26
|
+
*/ export function parseFrontmatter(skillPath) {
|
|
27
|
+
const skillMdPath = path.join(skillPath, 'SKILL.md');
|
|
28
|
+
if (!fs.existsSync(skillMdPath)) {
|
|
29
|
+
throw new StandardError(ErrorCode.FILE_NOT_FOUND, `SKILL.md not found in skill directory: ${skillPath}`, {
|
|
30
|
+
skillPath,
|
|
31
|
+
expectedFile: 'SKILL.md'
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
const content = fs.readFileSync(skillMdPath, 'utf-8');
|
|
35
|
+
// Extract frontmatter between --- markers
|
|
36
|
+
const frontmatterRegex = /^---\s*\n([\s\S]*?)\n---/;
|
|
37
|
+
const match = content.match(frontmatterRegex);
|
|
38
|
+
if (!match) {
|
|
39
|
+
throw new StandardError(ErrorCode.PARSE_ERROR, 'No frontmatter found in SKILL.md', {
|
|
40
|
+
skillPath,
|
|
41
|
+
file: skillMdPath
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
try {
|
|
45
|
+
// Parse YAML-like frontmatter (simple key: value format)
|
|
46
|
+
const frontmatterText = match[1];
|
|
47
|
+
const lines = frontmatterText.split('\n').filter((line)=>line.trim());
|
|
48
|
+
const frontmatter = {};
|
|
49
|
+
for (const line of lines){
|
|
50
|
+
const colonIndex = line.indexOf(':');
|
|
51
|
+
if (colonIndex === -1) continue;
|
|
52
|
+
const key = line.substring(0, colonIndex).trim();
|
|
53
|
+
let value = line.substring(colonIndex + 1).trim();
|
|
54
|
+
// Parse arrays (format: [item1, item2, item3])
|
|
55
|
+
if (value.startsWith('[') && value.endsWith(']')) {
|
|
56
|
+
value = value.substring(1, value.length - 1).split(',').map((v)=>v.trim()).filter((v)=>v);
|
|
57
|
+
}
|
|
58
|
+
frontmatter[key] = value;
|
|
59
|
+
}
|
|
60
|
+
// Validate required fields
|
|
61
|
+
if (!frontmatter.name || typeof frontmatter.name !== 'string') {
|
|
62
|
+
throw new StandardError(ErrorCode.VALIDATION_FAILED, 'Frontmatter missing required field: name', {
|
|
63
|
+
skillPath,
|
|
64
|
+
frontmatter
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
if (!frontmatter.version || typeof frontmatter.version !== 'string') {
|
|
68
|
+
throw new StandardError(ErrorCode.VALIDATION_FAILED, 'Frontmatter missing required field: version', {
|
|
69
|
+
skillPath,
|
|
70
|
+
frontmatter
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
return frontmatter;
|
|
74
|
+
} catch (error) {
|
|
75
|
+
if (error instanceof StandardError) {
|
|
76
|
+
throw error;
|
|
77
|
+
}
|
|
78
|
+
throw new StandardError(ErrorCode.PARSE_ERROR, `Failed to parse frontmatter in SKILL.md: ${error.message}`, {
|
|
79
|
+
skillPath,
|
|
80
|
+
file: skillMdPath
|
|
81
|
+
}, error);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Validate skill content path exists and has required files
|
|
86
|
+
*
|
|
87
|
+
* @param skillPath - Path to skill directory
|
|
88
|
+
* @returns Validation errors (empty if valid)
|
|
89
|
+
*/ export function validateContentPath(skillPath) {
|
|
90
|
+
const errors = [];
|
|
91
|
+
// Check if directory exists
|
|
92
|
+
if (!fs.existsSync(skillPath)) {
|
|
93
|
+
errors.push({
|
|
94
|
+
code: 'CONTENT_PATH_NOT_FOUND',
|
|
95
|
+
message: `Skill directory not found: ${skillPath}`,
|
|
96
|
+
context: {
|
|
97
|
+
skillPath
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
return errors;
|
|
101
|
+
}
|
|
102
|
+
// Check if it's a directory
|
|
103
|
+
const stats = fs.statSync(skillPath);
|
|
104
|
+
if (!stats.isDirectory()) {
|
|
105
|
+
errors.push({
|
|
106
|
+
code: 'CONTENT_PATH_NOT_DIRECTORY',
|
|
107
|
+
message: `Skill path is not a directory: ${skillPath}`,
|
|
108
|
+
context: {
|
|
109
|
+
skillPath
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
return errors;
|
|
113
|
+
}
|
|
114
|
+
// Check for required files
|
|
115
|
+
const requiredFiles = [
|
|
116
|
+
'SKILL.md',
|
|
117
|
+
'execute.sh'
|
|
118
|
+
];
|
|
119
|
+
for (const file of requiredFiles){
|
|
120
|
+
const filePath = path.join(skillPath, file);
|
|
121
|
+
if (!fs.existsSync(filePath)) {
|
|
122
|
+
errors.push({
|
|
123
|
+
code: 'REQUIRED_FILE_MISSING',
|
|
124
|
+
message: `Required file missing: ${file}`,
|
|
125
|
+
context: {
|
|
126
|
+
skillPath,
|
|
127
|
+
file,
|
|
128
|
+
expectedPath: filePath
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return errors;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Validate execute.sh is executable
|
|
137
|
+
*
|
|
138
|
+
* @param skillPath - Path to skill directory
|
|
139
|
+
* @returns Validation errors (empty if valid)
|
|
140
|
+
*/ export function validateExecuteScript(skillPath) {
|
|
141
|
+
const errors = [];
|
|
142
|
+
const executePath = path.join(skillPath, 'execute.sh');
|
|
143
|
+
if (!fs.existsSync(executePath)) {
|
|
144
|
+
// Already caught by validateContentPath
|
|
145
|
+
return errors;
|
|
146
|
+
}
|
|
147
|
+
try {
|
|
148
|
+
const stats = fs.statSync(executePath);
|
|
149
|
+
// Check if file has execute permission (any execute bit set)
|
|
150
|
+
const isExecutable = (stats.mode & 0o111) !== 0;
|
|
151
|
+
if (!isExecutable) {
|
|
152
|
+
errors.push({
|
|
153
|
+
code: 'EXECUTE_SCRIPT_NOT_EXECUTABLE',
|
|
154
|
+
message: 'execute.sh is not executable',
|
|
155
|
+
context: {
|
|
156
|
+
skillPath,
|
|
157
|
+
file: executePath,
|
|
158
|
+
mode: stats.mode.toString(8)
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
} catch (error) {
|
|
163
|
+
errors.push({
|
|
164
|
+
code: 'EXECUTE_SCRIPT_CHECK_FAILED',
|
|
165
|
+
message: `Failed to check execute.sh permissions: ${error.message}`,
|
|
166
|
+
context: {
|
|
167
|
+
skillPath,
|
|
168
|
+
file: executePath
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
return errors;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Validate skill schema compliance (frontmatter structure)
|
|
176
|
+
*
|
|
177
|
+
* @param skillPath - Path to skill directory
|
|
178
|
+
* @returns Validation errors (empty if valid)
|
|
179
|
+
*/ export function validateSchemaCompliance(skillPath) {
|
|
180
|
+
const errors = [];
|
|
181
|
+
try {
|
|
182
|
+
const frontmatter = parseFrontmatter(skillPath);
|
|
183
|
+
// Validate version format
|
|
184
|
+
if (!validateVersion(frontmatter.version)) {
|
|
185
|
+
errors.push({
|
|
186
|
+
code: 'INVALID_VERSION_FORMAT',
|
|
187
|
+
message: `Invalid semantic version format: ${frontmatter.version}`,
|
|
188
|
+
context: {
|
|
189
|
+
skillPath,
|
|
190
|
+
version: frontmatter.version,
|
|
191
|
+
expectedFormat: 'x.y.z'
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
// Validate name format (alphanumeric, hyphens, underscores only)
|
|
196
|
+
const nameRegex = /^[a-zA-Z0-9_-]+$/;
|
|
197
|
+
if (!nameRegex.test(frontmatter.name)) {
|
|
198
|
+
errors.push({
|
|
199
|
+
code: 'INVALID_NAME_FORMAT',
|
|
200
|
+
message: `Invalid skill name format: ${frontmatter.name}`,
|
|
201
|
+
context: {
|
|
202
|
+
skillPath,
|
|
203
|
+
name: frontmatter.name,
|
|
204
|
+
expectedFormat: 'alphanumeric, hyphens, and underscores only'
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
} catch (error) {
|
|
209
|
+
if (error instanceof StandardError) {
|
|
210
|
+
errors.push({
|
|
211
|
+
code: error.code,
|
|
212
|
+
message: error.message,
|
|
213
|
+
context: error.context
|
|
214
|
+
});
|
|
215
|
+
} else {
|
|
216
|
+
errors.push({
|
|
217
|
+
code: 'SCHEMA_VALIDATION_FAILED',
|
|
218
|
+
message: `Schema validation failed: ${error.message}`,
|
|
219
|
+
context: {
|
|
220
|
+
skillPath
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
return errors;
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Check if skill name is unique (no existing skill with same name)
|
|
229
|
+
*
|
|
230
|
+
* @param dbService - Database service instance
|
|
231
|
+
* @param skillName - Name of the skill to check
|
|
232
|
+
* @param excludeSkillId - Optional skill ID to exclude from uniqueness check (for updates)
|
|
233
|
+
* @returns Validation errors (empty if unique)
|
|
234
|
+
*/ export async function validateNameUniqueness(dbService, skillName, excludeSkillId) {
|
|
235
|
+
const errors = [];
|
|
236
|
+
try {
|
|
237
|
+
const adapter = dbService.getAdapter('sqlite');
|
|
238
|
+
let query = 'SELECT id, name FROM skills WHERE name = ?';
|
|
239
|
+
const params = [
|
|
240
|
+
skillName
|
|
241
|
+
];
|
|
242
|
+
if (excludeSkillId) {
|
|
243
|
+
query += ' AND id != ?';
|
|
244
|
+
params.push(excludeSkillId);
|
|
245
|
+
}
|
|
246
|
+
const result = await adapter.query(query, params);
|
|
247
|
+
if (result.rows && result.rows.length > 0) {
|
|
248
|
+
errors.push({
|
|
249
|
+
code: 'NAME_NOT_UNIQUE',
|
|
250
|
+
message: `Skill name already exists: ${skillName}`,
|
|
251
|
+
context: {
|
|
252
|
+
skillName,
|
|
253
|
+
existingSkillId: result.rows[0].id
|
|
254
|
+
}
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
} catch (error) {
|
|
258
|
+
errors.push({
|
|
259
|
+
code: 'NAME_UNIQUENESS_CHECK_FAILED',
|
|
260
|
+
message: `Failed to check name uniqueness: ${error.message}`,
|
|
261
|
+
context: {
|
|
262
|
+
skillName
|
|
263
|
+
}
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
return errors;
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Check for version conflicts (version already exists for this skill)
|
|
270
|
+
*
|
|
271
|
+
* @param dbService - Database service instance
|
|
272
|
+
* @param skillName - Name of the skill
|
|
273
|
+
* @param version - Version to check
|
|
274
|
+
* @returns Validation errors (empty if no conflict)
|
|
275
|
+
*/ export async function validateVersionConflict(dbService, skillName, version) {
|
|
276
|
+
const errors = [];
|
|
277
|
+
try {
|
|
278
|
+
const adapter = dbService.getAdapter('sqlite');
|
|
279
|
+
const result = await adapter.query('SELECT id, version FROM skills WHERE name = ? AND version = ?', [
|
|
280
|
+
skillName,
|
|
281
|
+
version
|
|
282
|
+
]);
|
|
283
|
+
if (result.rows && result.rows.length > 0) {
|
|
284
|
+
errors.push({
|
|
285
|
+
code: 'VERSION_CONFLICT',
|
|
286
|
+
message: `Version ${version} already exists for skill: ${skillName}`,
|
|
287
|
+
context: {
|
|
288
|
+
skillName,
|
|
289
|
+
version,
|
|
290
|
+
existingSkillId: result.rows[0].id
|
|
291
|
+
}
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
} catch (error) {
|
|
295
|
+
errors.push({
|
|
296
|
+
code: 'VERSION_CONFLICT_CHECK_FAILED',
|
|
297
|
+
message: `Failed to check version conflict: ${error.message}`,
|
|
298
|
+
context: {
|
|
299
|
+
skillName,
|
|
300
|
+
version
|
|
301
|
+
}
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
return errors;
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Validate tests exist and pass (optional check)
|
|
308
|
+
*
|
|
309
|
+
* @param skillPath - Path to skill directory
|
|
310
|
+
* @returns Validation warnings (not errors, as tests are optional)
|
|
311
|
+
*/ export function validateTests(skillPath) {
|
|
312
|
+
const warnings = [];
|
|
313
|
+
const testPath = path.join(skillPath, 'test.sh');
|
|
314
|
+
if (!fs.existsSync(testPath)) {
|
|
315
|
+
warnings.push({
|
|
316
|
+
code: 'TESTS_NOT_FOUND',
|
|
317
|
+
message: 'No test.sh found (tests are recommended but optional)',
|
|
318
|
+
context: {
|
|
319
|
+
skillPath,
|
|
320
|
+
expectedFile: testPath
|
|
321
|
+
}
|
|
322
|
+
});
|
|
323
|
+
return warnings;
|
|
324
|
+
}
|
|
325
|
+
// Check if test.sh is executable
|
|
326
|
+
try {
|
|
327
|
+
const stats = fs.statSync(testPath);
|
|
328
|
+
const isExecutable = (stats.mode & 0o111) !== 0;
|
|
329
|
+
if (!isExecutable) {
|
|
330
|
+
warnings.push({
|
|
331
|
+
code: 'TEST_SCRIPT_NOT_EXECUTABLE',
|
|
332
|
+
message: 'test.sh exists but is not executable',
|
|
333
|
+
context: {
|
|
334
|
+
skillPath,
|
|
335
|
+
file: testPath
|
|
336
|
+
}
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
} catch (error) {
|
|
340
|
+
warnings.push({
|
|
341
|
+
code: 'TEST_SCRIPT_CHECK_FAILED',
|
|
342
|
+
message: `Failed to check test.sh: ${error.message}`,
|
|
343
|
+
context: {
|
|
344
|
+
skillPath,
|
|
345
|
+
file: testPath
|
|
346
|
+
}
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
return warnings;
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Comprehensive skill validation
|
|
353
|
+
*
|
|
354
|
+
* Runs all validation checks and returns aggregated results.
|
|
355
|
+
*
|
|
356
|
+
* @param dbService - Database service instance
|
|
357
|
+
* @param skillPath - Path to skill directory
|
|
358
|
+
* @param excludeSkillId - Optional skill ID to exclude from uniqueness check
|
|
359
|
+
* @returns Validation result with all errors and warnings
|
|
360
|
+
*/ export async function validateSkill(dbService, skillPath, excludeSkillId) {
|
|
361
|
+
logger.info('Starting skill validation', {
|
|
362
|
+
skillPath
|
|
363
|
+
});
|
|
364
|
+
const errors = [];
|
|
365
|
+
const warnings = [];
|
|
366
|
+
let metadata = {};
|
|
367
|
+
// 1. Validate content path exists
|
|
368
|
+
const contentPathErrors = validateContentPath(skillPath);
|
|
369
|
+
errors.push(...contentPathErrors);
|
|
370
|
+
// If content path is invalid, stop here
|
|
371
|
+
if (contentPathErrors.length > 0) {
|
|
372
|
+
logger.warn('Skill validation failed: content path invalid', {
|
|
373
|
+
skillPath,
|
|
374
|
+
errorCount: errors.length
|
|
375
|
+
});
|
|
376
|
+
return {
|
|
377
|
+
valid: false,
|
|
378
|
+
errors,
|
|
379
|
+
warnings
|
|
380
|
+
};
|
|
381
|
+
}
|
|
382
|
+
// 2. Validate schema compliance
|
|
383
|
+
const schemaErrors = validateSchemaCompliance(skillPath);
|
|
384
|
+
errors.push(...schemaErrors);
|
|
385
|
+
// If schema is invalid, stop here
|
|
386
|
+
if (schemaErrors.length > 0) {
|
|
387
|
+
logger.warn('Skill validation failed: schema invalid', {
|
|
388
|
+
skillPath,
|
|
389
|
+
errorCount: errors.length
|
|
390
|
+
});
|
|
391
|
+
return {
|
|
392
|
+
valid: false,
|
|
393
|
+
errors,
|
|
394
|
+
warnings
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
// Parse frontmatter for subsequent checks
|
|
398
|
+
let frontmatter;
|
|
399
|
+
try {
|
|
400
|
+
frontmatter = parseFrontmatter(skillPath);
|
|
401
|
+
metadata = {
|
|
402
|
+
skillName: frontmatter.name,
|
|
403
|
+
version: frontmatter.version,
|
|
404
|
+
contentPath: skillPath
|
|
405
|
+
};
|
|
406
|
+
} catch (error) {
|
|
407
|
+
// Already handled in schema validation
|
|
408
|
+
logger.warn('Skill validation failed: frontmatter parsing error', {
|
|
409
|
+
skillPath,
|
|
410
|
+
error: error.message
|
|
411
|
+
});
|
|
412
|
+
return {
|
|
413
|
+
valid: false,
|
|
414
|
+
errors,
|
|
415
|
+
warnings,
|
|
416
|
+
metadata
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
// 3. Validate execute.sh is executable
|
|
420
|
+
const executeErrors = validateExecuteScript(skillPath);
|
|
421
|
+
errors.push(...executeErrors);
|
|
422
|
+
// 4. Validate name uniqueness
|
|
423
|
+
const nameErrors = await validateNameUniqueness(dbService, frontmatter.name, excludeSkillId);
|
|
424
|
+
errors.push(...nameErrors);
|
|
425
|
+
// 5. Validate version conflict
|
|
426
|
+
const versionErrors = await validateVersionConflict(dbService, frontmatter.name, frontmatter.version);
|
|
427
|
+
errors.push(...versionErrors);
|
|
428
|
+
// 6. Validate tests (warnings only)
|
|
429
|
+
const testWarnings = validateTests(skillPath);
|
|
430
|
+
warnings.push(...testWarnings);
|
|
431
|
+
const valid = errors.length === 0;
|
|
432
|
+
if (valid) {
|
|
433
|
+
logger.info('Skill validation passed', {
|
|
434
|
+
skillPath,
|
|
435
|
+
skillName: frontmatter.name,
|
|
436
|
+
version: frontmatter.version,
|
|
437
|
+
warningCount: warnings.length
|
|
438
|
+
});
|
|
439
|
+
} else {
|
|
440
|
+
logger.warn('Skill validation failed', {
|
|
441
|
+
skillPath,
|
|
442
|
+
errorCount: errors.length,
|
|
443
|
+
warningCount: warnings.length
|
|
444
|
+
});
|
|
445
|
+
}
|
|
446
|
+
return {
|
|
447
|
+
valid,
|
|
448
|
+
errors,
|
|
449
|
+
warnings,
|
|
450
|
+
metadata
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
//# sourceMappingURL=skill-validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/services/skill-validator.ts"],"sourcesContent":["/**\r\n * Skill Validator Service\r\n *\r\n * Validates skill content, schema compliance, and deployment readiness.\r\n * Part of Task 1.1: Automated Skill Deployment Pipeline\r\n *\r\n * @example\r\n * ```typescript\r\n * const result = await validateSkill(dbService, '/path/to/skill');\r\n * if (!result.valid) {\r\n * console.error('Validation failed:', result.errors);\r\n * }\r\n * ```\r\n */\r\n\r\nimport * as fs from 'fs';\r\nimport * as path from 'path';\r\nimport { DatabaseService } from '../lib/database-service.js';\r\nimport { StandardError, ErrorCode } from '../lib/errors.js';\r\nimport { createLogger } from '../lib/logging.js';\r\nimport { validateVersion } from './skill-versioning.js';\r\n\r\nconst logger = createLogger('skill-validator');\r\n\r\n/**\r\n * Validation error detail\r\n */\r\nexport interface ValidationError {\r\n code: string;\r\n message: string;\r\n context?: Record<string, any>;\r\n}\r\n\r\n/**\r\n * Skill validation result\r\n */\r\nexport interface ValidationResult {\r\n valid: boolean;\r\n errors: ValidationError[];\r\n warnings: ValidationError[];\r\n metadata?: {\r\n skillName?: string;\r\n version?: string;\r\n contentPath?: string;\r\n };\r\n}\r\n\r\n/**\r\n * Skill frontmatter schema (parsed from SKILL.md)\r\n */\r\nexport interface SkillFrontmatter {\r\n name: string;\r\n version: string;\r\n description?: string;\r\n author?: string;\r\n dependencies?: string[];\r\n tags?: string[];\r\n [key: string]: any;\r\n}\r\n\r\n/**\r\n * Parse frontmatter from SKILL.md file\r\n *\r\n * @param skillPath - Path to skill directory\r\n * @returns Parsed frontmatter object\r\n * @throws StandardError if frontmatter is invalid or missing\r\n */\r\nexport function parseFrontmatter(skillPath: string): SkillFrontmatter {\r\n const skillMdPath = path.join(skillPath, 'SKILL.md');\r\n\r\n if (!fs.existsSync(skillMdPath)) {\r\n throw new StandardError(\r\n ErrorCode.FILE_NOT_FOUND,\r\n `SKILL.md not found in skill directory: ${skillPath}`,\r\n { skillPath, expectedFile: 'SKILL.md' }\r\n );\r\n }\r\n\r\n const content = fs.readFileSync(skillMdPath, 'utf-8');\r\n\r\n // Extract frontmatter between --- markers\r\n const frontmatterRegex = /^---\\s*\\n([\\s\\S]*?)\\n---/;\r\n const match = content.match(frontmatterRegex);\r\n\r\n if (!match) {\r\n throw new StandardError(\r\n ErrorCode.PARSE_ERROR,\r\n 'No frontmatter found in SKILL.md',\r\n { skillPath, file: skillMdPath }\r\n );\r\n }\r\n\r\n try {\r\n // Parse YAML-like frontmatter (simple key: value format)\r\n const frontmatterText = match[1];\r\n const lines = frontmatterText.split('\\n').filter(line => line.trim());\r\n const frontmatter: any = {};\r\n\r\n for (const line of lines) {\r\n const colonIndex = line.indexOf(':');\r\n if (colonIndex === -1) continue;\r\n\r\n const key = line.substring(0, colonIndex).trim();\r\n let value: any = line.substring(colonIndex + 1).trim();\r\n\r\n // Parse arrays (format: [item1, item2, item3])\r\n if (value.startsWith('[') && value.endsWith(']')) {\r\n value = value\r\n .substring(1, value.length - 1)\r\n .split(',')\r\n .map(v => v.trim())\r\n .filter(v => v);\r\n }\r\n\r\n frontmatter[key] = value;\r\n }\r\n\r\n // Validate required fields\r\n if (!frontmatter.name || typeof frontmatter.name !== 'string') {\r\n throw new StandardError(\r\n ErrorCode.VALIDATION_FAILED,\r\n 'Frontmatter missing required field: name',\r\n { skillPath, frontmatter }\r\n );\r\n }\r\n\r\n if (!frontmatter.version || typeof frontmatter.version !== 'string') {\r\n throw new StandardError(\r\n ErrorCode.VALIDATION_FAILED,\r\n 'Frontmatter missing required field: version',\r\n { skillPath, frontmatter }\r\n );\r\n }\r\n\r\n return frontmatter as SkillFrontmatter;\r\n } catch (error) {\r\n if (error instanceof StandardError) {\r\n throw error;\r\n }\r\n throw new StandardError(\r\n ErrorCode.PARSE_ERROR,\r\n `Failed to parse frontmatter in SKILL.md: ${(error as Error).message}`,\r\n { skillPath, file: skillMdPath },\r\n error as Error\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Validate skill content path exists and has required files\r\n *\r\n * @param skillPath - Path to skill directory\r\n * @returns Validation errors (empty if valid)\r\n */\r\nexport function validateContentPath(skillPath: string): ValidationError[] {\r\n const errors: ValidationError[] = [];\r\n\r\n // Check if directory exists\r\n if (!fs.existsSync(skillPath)) {\r\n errors.push({\r\n code: 'CONTENT_PATH_NOT_FOUND',\r\n message: `Skill directory not found: ${skillPath}`,\r\n context: { skillPath },\r\n });\r\n return errors;\r\n }\r\n\r\n // Check if it's a directory\r\n const stats = fs.statSync(skillPath);\r\n if (!stats.isDirectory()) {\r\n errors.push({\r\n code: 'CONTENT_PATH_NOT_DIRECTORY',\r\n message: `Skill path is not a directory: ${skillPath}`,\r\n context: { skillPath },\r\n });\r\n return errors;\r\n }\r\n\r\n // Check for required files\r\n const requiredFiles = ['SKILL.md', 'execute.sh'];\r\n for (const file of requiredFiles) {\r\n const filePath = path.join(skillPath, file);\r\n if (!fs.existsSync(filePath)) {\r\n errors.push({\r\n code: 'REQUIRED_FILE_MISSING',\r\n message: `Required file missing: ${file}`,\r\n context: { skillPath, file, expectedPath: filePath },\r\n });\r\n }\r\n }\r\n\r\n return errors;\r\n}\r\n\r\n/**\r\n * Validate execute.sh is executable\r\n *\r\n * @param skillPath - Path to skill directory\r\n * @returns Validation errors (empty if valid)\r\n */\r\nexport function validateExecuteScript(skillPath: string): ValidationError[] {\r\n const errors: ValidationError[] = [];\r\n const executePath = path.join(skillPath, 'execute.sh');\r\n\r\n if (!fs.existsSync(executePath)) {\r\n // Already caught by validateContentPath\r\n return errors;\r\n }\r\n\r\n try {\r\n const stats = fs.statSync(executePath);\r\n // Check if file has execute permission (any execute bit set)\r\n const isExecutable = (stats.mode & 0o111) !== 0;\r\n\r\n if (!isExecutable) {\r\n errors.push({\r\n code: 'EXECUTE_SCRIPT_NOT_EXECUTABLE',\r\n message: 'execute.sh is not executable',\r\n context: { skillPath, file: executePath, mode: stats.mode.toString(8) },\r\n });\r\n }\r\n } catch (error) {\r\n errors.push({\r\n code: 'EXECUTE_SCRIPT_CHECK_FAILED',\r\n message: `Failed to check execute.sh permissions: ${(error as Error).message}`,\r\n context: { skillPath, file: executePath },\r\n });\r\n }\r\n\r\n return errors;\r\n}\r\n\r\n/**\r\n * Validate skill schema compliance (frontmatter structure)\r\n *\r\n * @param skillPath - Path to skill directory\r\n * @returns Validation errors (empty if valid)\r\n */\r\nexport function validateSchemaCompliance(skillPath: string): ValidationError[] {\r\n const errors: ValidationError[] = [];\r\n\r\n try {\r\n const frontmatter = parseFrontmatter(skillPath);\r\n\r\n // Validate version format\r\n if (!validateVersion(frontmatter.version)) {\r\n errors.push({\r\n code: 'INVALID_VERSION_FORMAT',\r\n message: `Invalid semantic version format: ${frontmatter.version}`,\r\n context: {\r\n skillPath,\r\n version: frontmatter.version,\r\n expectedFormat: 'x.y.z',\r\n },\r\n });\r\n }\r\n\r\n // Validate name format (alphanumeric, hyphens, underscores only)\r\n const nameRegex = /^[a-zA-Z0-9_-]+$/;\r\n if (!nameRegex.test(frontmatter.name)) {\r\n errors.push({\r\n code: 'INVALID_NAME_FORMAT',\r\n message: `Invalid skill name format: ${frontmatter.name}`,\r\n context: {\r\n skillPath,\r\n name: frontmatter.name,\r\n expectedFormat: 'alphanumeric, hyphens, and underscores only',\r\n },\r\n });\r\n }\r\n } catch (error) {\r\n if (error instanceof StandardError) {\r\n errors.push({\r\n code: error.code,\r\n message: error.message,\r\n context: error.context,\r\n });\r\n } else {\r\n errors.push({\r\n code: 'SCHEMA_VALIDATION_FAILED',\r\n message: `Schema validation failed: ${(error as Error).message}`,\r\n context: { skillPath },\r\n });\r\n }\r\n }\r\n\r\n return errors;\r\n}\r\n\r\n/**\r\n * Check if skill name is unique (no existing skill with same name)\r\n *\r\n * @param dbService - Database service instance\r\n * @param skillName - Name of the skill to check\r\n * @param excludeSkillId - Optional skill ID to exclude from uniqueness check (for updates)\r\n * @returns Validation errors (empty if unique)\r\n */\r\nexport async function validateNameUniqueness(\r\n dbService: DatabaseService,\r\n skillName: string,\r\n excludeSkillId?: string\r\n): Promise<ValidationError[]> {\r\n const errors: ValidationError[] = [];\r\n\r\n try {\r\n const adapter = dbService.getAdapter('sqlite');\r\n\r\n let query = 'SELECT id, name FROM skills WHERE name = ?';\r\n const params: any[] = [skillName];\r\n\r\n if (excludeSkillId) {\r\n query += ' AND id != ?';\r\n params.push(excludeSkillId);\r\n }\r\n\r\n const result = await adapter.query(query, params);\r\n\r\n if (result.rows && result.rows.length > 0) {\r\n errors.push({\r\n code: 'NAME_NOT_UNIQUE',\r\n message: `Skill name already exists: ${skillName}`,\r\n context: {\r\n skillName,\r\n existingSkillId: result.rows[0].id,\r\n },\r\n });\r\n }\r\n } catch (error) {\r\n errors.push({\r\n code: 'NAME_UNIQUENESS_CHECK_FAILED',\r\n message: `Failed to check name uniqueness: ${(error as Error).message}`,\r\n context: { skillName },\r\n });\r\n }\r\n\r\n return errors;\r\n}\r\n\r\n/**\r\n * Check for version conflicts (version already exists for this skill)\r\n *\r\n * @param dbService - Database service instance\r\n * @param skillName - Name of the skill\r\n * @param version - Version to check\r\n * @returns Validation errors (empty if no conflict)\r\n */\r\nexport async function validateVersionConflict(\r\n dbService: DatabaseService,\r\n skillName: string,\r\n version: string\r\n): Promise<ValidationError[]> {\r\n const errors: ValidationError[] = [];\r\n\r\n try {\r\n const adapter = dbService.getAdapter('sqlite');\r\n\r\n const result = await adapter.query(\r\n 'SELECT id, version FROM skills WHERE name = ? AND version = ?',\r\n [skillName, version]\r\n );\r\n\r\n if (result.rows && result.rows.length > 0) {\r\n errors.push({\r\n code: 'VERSION_CONFLICT',\r\n message: `Version ${version} already exists for skill: ${skillName}`,\r\n context: {\r\n skillName,\r\n version,\r\n existingSkillId: result.rows[0].id,\r\n },\r\n });\r\n }\r\n } catch (error) {\r\n errors.push({\r\n code: 'VERSION_CONFLICT_CHECK_FAILED',\r\n message: `Failed to check version conflict: ${(error as Error).message}`,\r\n context: { skillName, version },\r\n });\r\n }\r\n\r\n return errors;\r\n}\r\n\r\n/**\r\n * Validate tests exist and pass (optional check)\r\n *\r\n * @param skillPath - Path to skill directory\r\n * @returns Validation warnings (not errors, as tests are optional)\r\n */\r\nexport function validateTests(skillPath: string): ValidationError[] {\r\n const warnings: ValidationError[] = [];\r\n const testPath = path.join(skillPath, 'test.sh');\r\n\r\n if (!fs.existsSync(testPath)) {\r\n warnings.push({\r\n code: 'TESTS_NOT_FOUND',\r\n message: 'No test.sh found (tests are recommended but optional)',\r\n context: { skillPath, expectedFile: testPath },\r\n });\r\n return warnings;\r\n }\r\n\r\n // Check if test.sh is executable\r\n try {\r\n const stats = fs.statSync(testPath);\r\n const isExecutable = (stats.mode & 0o111) !== 0;\r\n\r\n if (!isExecutable) {\r\n warnings.push({\r\n code: 'TEST_SCRIPT_NOT_EXECUTABLE',\r\n message: 'test.sh exists but is not executable',\r\n context: { skillPath, file: testPath },\r\n });\r\n }\r\n } catch (error) {\r\n warnings.push({\r\n code: 'TEST_SCRIPT_CHECK_FAILED',\r\n message: `Failed to check test.sh: ${(error as Error).message}`,\r\n context: { skillPath, file: testPath },\r\n });\r\n }\r\n\r\n return warnings;\r\n}\r\n\r\n/**\r\n * Comprehensive skill validation\r\n *\r\n * Runs all validation checks and returns aggregated results.\r\n *\r\n * @param dbService - Database service instance\r\n * @param skillPath - Path to skill directory\r\n * @param excludeSkillId - Optional skill ID to exclude from uniqueness check\r\n * @returns Validation result with all errors and warnings\r\n */\r\nexport async function validateSkill(\r\n dbService: DatabaseService,\r\n skillPath: string,\r\n excludeSkillId?: string\r\n): Promise<ValidationResult> {\r\n logger.info('Starting skill validation', { skillPath });\r\n\r\n const errors: ValidationError[] = [];\r\n const warnings: ValidationError[] = [];\r\n let metadata: ValidationResult['metadata'] = {};\r\n\r\n // 1. Validate content path exists\r\n const contentPathErrors = validateContentPath(skillPath);\r\n errors.push(...contentPathErrors);\r\n\r\n // If content path is invalid, stop here\r\n if (contentPathErrors.length > 0) {\r\n logger.warn('Skill validation failed: content path invalid', {\r\n skillPath,\r\n errorCount: errors.length,\r\n });\r\n return { valid: false, errors, warnings };\r\n }\r\n\r\n // 2. Validate schema compliance\r\n const schemaErrors = validateSchemaCompliance(skillPath);\r\n errors.push(...schemaErrors);\r\n\r\n // If schema is invalid, stop here\r\n if (schemaErrors.length > 0) {\r\n logger.warn('Skill validation failed: schema invalid', {\r\n skillPath,\r\n errorCount: errors.length,\r\n });\r\n return { valid: false, errors, warnings };\r\n }\r\n\r\n // Parse frontmatter for subsequent checks\r\n let frontmatter: SkillFrontmatter;\r\n try {\r\n frontmatter = parseFrontmatter(skillPath);\r\n metadata = {\r\n skillName: frontmatter.name,\r\n version: frontmatter.version,\r\n contentPath: skillPath,\r\n };\r\n } catch (error) {\r\n // Already handled in schema validation\r\n logger.warn('Skill validation failed: frontmatter parsing error', {\r\n skillPath,\r\n error: (error as Error).message,\r\n });\r\n return { valid: false, errors, warnings, metadata };\r\n }\r\n\r\n // 3. Validate execute.sh is executable\r\n const executeErrors = validateExecuteScript(skillPath);\r\n errors.push(...executeErrors);\r\n\r\n // 4. Validate name uniqueness\r\n const nameErrors = await validateNameUniqueness(\r\n dbService,\r\n frontmatter.name,\r\n excludeSkillId\r\n );\r\n errors.push(...nameErrors);\r\n\r\n // 5. Validate version conflict\r\n const versionErrors = await validateVersionConflict(\r\n dbService,\r\n frontmatter.name,\r\n frontmatter.version\r\n );\r\n errors.push(...versionErrors);\r\n\r\n // 6. Validate tests (warnings only)\r\n const testWarnings = validateTests(skillPath);\r\n warnings.push(...testWarnings);\r\n\r\n const valid = errors.length === 0;\r\n\r\n if (valid) {\r\n logger.info('Skill validation passed', {\r\n skillPath,\r\n skillName: frontmatter.name,\r\n version: frontmatter.version,\r\n warningCount: warnings.length,\r\n });\r\n } else {\r\n logger.warn('Skill validation failed', {\r\n skillPath,\r\n errorCount: errors.length,\r\n warningCount: warnings.length,\r\n });\r\n }\r\n\r\n return { valid, errors, warnings, metadata };\r\n}\r\n"],"names":["fs","path","StandardError","ErrorCode","createLogger","validateVersion","logger","parseFrontmatter","skillPath","skillMdPath","join","existsSync","FILE_NOT_FOUND","expectedFile","content","readFileSync","frontmatterRegex","match","PARSE_ERROR","file","frontmatterText","lines","split","filter","line","trim","frontmatter","colonIndex","indexOf","key","substring","value","startsWith","endsWith","length","map","v","name","VALIDATION_FAILED","version","error","message","validateContentPath","errors","push","code","context","stats","statSync","isDirectory","requiredFiles","filePath","expectedPath","validateExecuteScript","executePath","isExecutable","mode","toString","validateSchemaCompliance","expectedFormat","nameRegex","test","validateNameUniqueness","dbService","skillName","excludeSkillId","adapter","getAdapter","query","params","result","rows","existingSkillId","id","validateVersionConflict","validateTests","warnings","testPath","validateSkill","info","metadata","contentPathErrors","warn","errorCount","valid","schemaErrors","contentPath","executeErrors","nameErrors","versionErrors","testWarnings","warningCount"],"mappings":"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"}
|