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,427 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skill Loader with Memory Budget
|
|
3
|
+
*
|
|
4
|
+
* High-performance skill loading system with:
|
|
5
|
+
* - Lazy loading (metadata at startup, content on-demand)
|
|
6
|
+
* - Memory budget enforcement (100MB default)
|
|
7
|
+
* - LRU cache with eviction
|
|
8
|
+
* - SHA-256 hash validation
|
|
9
|
+
* - <2s startup for 500 skills
|
|
10
|
+
* - <100ms cache hit, <500ms cache miss
|
|
11
|
+
*
|
|
12
|
+
* @module skill-loader
|
|
13
|
+
*/ import * as fs from 'fs/promises';
|
|
14
|
+
import * as path from 'path';
|
|
15
|
+
import * as crypto from 'crypto';
|
|
16
|
+
import { LRUSkillCache } from '../lib/skill-cache.js';
|
|
17
|
+
import { createLogger } from '../lib/logging.js';
|
|
18
|
+
import { StandardError } from '../lib/errors.js';
|
|
19
|
+
/**
|
|
20
|
+
* Skill Loader with memory budget and lazy loading
|
|
21
|
+
*/ export class SkillLoader {
|
|
22
|
+
cache;
|
|
23
|
+
metadata;
|
|
24
|
+
dbService;
|
|
25
|
+
skillsBasePath;
|
|
26
|
+
logger;
|
|
27
|
+
debug;
|
|
28
|
+
maxMemoryBytes;
|
|
29
|
+
initialized = false;
|
|
30
|
+
// Loading locks (prevent duplicate loads)
|
|
31
|
+
loadingLocks = new Map();
|
|
32
|
+
// Metrics
|
|
33
|
+
metrics = {
|
|
34
|
+
hashMismatches: 0,
|
|
35
|
+
cacheInvalidations: 0
|
|
36
|
+
};
|
|
37
|
+
constructor(config){
|
|
38
|
+
this.dbService = config.dbService;
|
|
39
|
+
this.maxMemoryBytes = config.maxMemoryBytes ?? 100 * 1024 * 1024; // 100MB default
|
|
40
|
+
this.skillsBasePath = config.skillsBasePath ?? path.join(process.cwd(), '.claude/skills');
|
|
41
|
+
this.logger = config.logger ?? createLogger('skill-loader');
|
|
42
|
+
this.debug = config.debug ?? false;
|
|
43
|
+
// Initialize metadata map
|
|
44
|
+
this.metadata = new Map();
|
|
45
|
+
// Initialize LRU cache
|
|
46
|
+
this.cache = new LRUSkillCache({
|
|
47
|
+
maxMemoryBytes: this.maxMemoryBytes,
|
|
48
|
+
logger: this.logger,
|
|
49
|
+
debug: this.debug
|
|
50
|
+
});
|
|
51
|
+
if (this.debug) {
|
|
52
|
+
this.logger.info('SkillLoader initialized', {
|
|
53
|
+
maxMemoryBytes: this.maxMemoryBytes,
|
|
54
|
+
maxMemoryMB: (this.maxMemoryBytes / 1024 / 1024).toFixed(2),
|
|
55
|
+
skillsBasePath: this.skillsBasePath
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Initialize loader
|
|
61
|
+
*
|
|
62
|
+
* Scans skills directory and loads metadata (NOT content).
|
|
63
|
+
* Fast: <2s for 500 skills.
|
|
64
|
+
*/ async initialize() {
|
|
65
|
+
const startTime = Date.now();
|
|
66
|
+
if (this.initialized) {
|
|
67
|
+
this.logger.warn('SkillLoader already initialized');
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
this.logger.info('Initializing SkillLoader', {
|
|
71
|
+
skillsBasePath: this.skillsBasePath
|
|
72
|
+
});
|
|
73
|
+
// Scan skills directory
|
|
74
|
+
await this.scanSkillsDirectory();
|
|
75
|
+
// Load metadata from database (if available)
|
|
76
|
+
if (this.dbService) {
|
|
77
|
+
await this.loadMetadataFromDatabase();
|
|
78
|
+
}
|
|
79
|
+
this.initialized = true;
|
|
80
|
+
const initTime = Date.now() - startTime;
|
|
81
|
+
this.logger.info('SkillLoader initialized', {
|
|
82
|
+
skillsLoaded: this.metadata.size,
|
|
83
|
+
initTimeMs: initTime
|
|
84
|
+
});
|
|
85
|
+
if (initTime >= 2000) {
|
|
86
|
+
this.logger.warn('Initialization time exceeded target', {
|
|
87
|
+
initTimeMs: initTime,
|
|
88
|
+
target: 2000
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Load skill content
|
|
94
|
+
*
|
|
95
|
+
* Lazy loading: content loaded on-demand.
|
|
96
|
+
* - Cache hit: <100ms
|
|
97
|
+
* - Cache miss: <500ms (disk I/O + hash validation)
|
|
98
|
+
*
|
|
99
|
+
* @param skillId - Skill ID to load
|
|
100
|
+
* @returns Loaded skill with content
|
|
101
|
+
*/ async loadSkill(skillId) {
|
|
102
|
+
const startTime = Date.now();
|
|
103
|
+
if (!this.initialized) {
|
|
104
|
+
throw new StandardError('LOADER_NOT_INITIALIZED', 'SkillLoader not initialized. Call initialize() first.');
|
|
105
|
+
}
|
|
106
|
+
// Check if already loading (prevent duplicate loads)
|
|
107
|
+
const existingLoad = this.loadingLocks.get(skillId);
|
|
108
|
+
if (existingLoad) {
|
|
109
|
+
if (this.debug) {
|
|
110
|
+
this.logger.debug('Waiting for existing load', {
|
|
111
|
+
skillId
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
return existingLoad;
|
|
115
|
+
}
|
|
116
|
+
// Create loading promise
|
|
117
|
+
const loadPromise = this.doLoadSkill(skillId, startTime);
|
|
118
|
+
this.loadingLocks.set(skillId, loadPromise);
|
|
119
|
+
try {
|
|
120
|
+
const skill = await loadPromise;
|
|
121
|
+
return skill;
|
|
122
|
+
} finally{
|
|
123
|
+
this.loadingLocks.delete(skillId);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Internal skill loading implementation
|
|
128
|
+
*/ async doLoadSkill(skillId, startTime) {
|
|
129
|
+
// Get metadata
|
|
130
|
+
const meta = this.metadata.get(skillId);
|
|
131
|
+
if (!meta) {
|
|
132
|
+
throw new StandardError('SKILL_NOT_FOUND', `Skill not found: ${skillId}`, {
|
|
133
|
+
skillId
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
// Check cache first
|
|
137
|
+
const cached = this.cache.get(skillId);
|
|
138
|
+
if (cached) {
|
|
139
|
+
const loadTime = Date.now() - startTime;
|
|
140
|
+
if (this.debug) {
|
|
141
|
+
this.logger.debug('Cache hit', {
|
|
142
|
+
skillId,
|
|
143
|
+
loadTimeMs: loadTime
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
// Verify hash (detect file changes)
|
|
147
|
+
const currentHash = await this.computeFileHash(meta.path);
|
|
148
|
+
if (currentHash !== meta.hash) {
|
|
149
|
+
// Hash mismatch - invalidate cache and reload
|
|
150
|
+
this.metrics.hashMismatches++;
|
|
151
|
+
this.metrics.cacheInvalidations++;
|
|
152
|
+
this.cache.delete(skillId);
|
|
153
|
+
if (this.debug) {
|
|
154
|
+
this.logger.debug('Hash mismatch detected, reloading', {
|
|
155
|
+
skillId,
|
|
156
|
+
oldHash: meta.hash,
|
|
157
|
+
newHash: currentHash
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
// Fall through to load from disk
|
|
161
|
+
} else {
|
|
162
|
+
// Cache hit with valid hash
|
|
163
|
+
return {
|
|
164
|
+
...meta,
|
|
165
|
+
content: cached
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
// Cache miss - load from disk
|
|
170
|
+
const content = await this.loadSkillFromDisk(meta);
|
|
171
|
+
const loadTime = Date.now() - startTime;
|
|
172
|
+
if (this.debug) {
|
|
173
|
+
this.logger.debug('Cache miss, loaded from disk', {
|
|
174
|
+
skillId,
|
|
175
|
+
loadTimeMs: loadTime
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
if (loadTime >= 500) {
|
|
179
|
+
this.logger.warn('Load time exceeded target', {
|
|
180
|
+
skillId,
|
|
181
|
+
loadTimeMs: loadTime,
|
|
182
|
+
target: 500
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
// Update metadata with new hash (if changed)
|
|
186
|
+
const currentHash = await this.computeFileHash(meta.path);
|
|
187
|
+
if (currentHash !== meta.hash) {
|
|
188
|
+
meta.hash = currentHash;
|
|
189
|
+
this.metrics.hashMismatches++;
|
|
190
|
+
// Update database
|
|
191
|
+
if (this.dbService) {
|
|
192
|
+
await this.updateMetadataInDatabase(meta);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
// Cache the content
|
|
196
|
+
const contentSize = this.estimateContentSize(content);
|
|
197
|
+
this.cache.set(skillId, content, contentSize);
|
|
198
|
+
return {
|
|
199
|
+
...meta,
|
|
200
|
+
content
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Load skill content from disk
|
|
205
|
+
*/ async loadSkillFromDisk(meta) {
|
|
206
|
+
const skillPath = path.join(this.skillsBasePath, meta.path);
|
|
207
|
+
try {
|
|
208
|
+
const markdown = await fs.readFile(skillPath, 'utf-8');
|
|
209
|
+
// Validate content
|
|
210
|
+
if (!markdown || markdown.trim().length === 0) {
|
|
211
|
+
throw new StandardError('EMPTY_SKILL_FILE', `Empty skill file: ${meta.id}`, {
|
|
212
|
+
skillId: meta.id,
|
|
213
|
+
path: skillPath
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
// Check for corrupted content (null bytes, invalid characters)
|
|
217
|
+
if (markdown.includes('\0') || /[\x00-\x08\x0B-\x0C\x0E-\x1F]/.test(markdown)) {
|
|
218
|
+
throw new StandardError('CORRUPTED_SKILL_FILE', `Corrupted skill file (invalid characters): ${meta.id}`, {
|
|
219
|
+
skillId: meta.id,
|
|
220
|
+
path: skillPath
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
// Validate minimum content length (reasonable skill should be >50 chars)
|
|
224
|
+
if (markdown.trim().length < 50) {
|
|
225
|
+
throw new StandardError('INVALID_SKILL_FILE', `Invalid skill file (too short): ${meta.id}`, {
|
|
226
|
+
skillId: meta.id,
|
|
227
|
+
path: skillPath,
|
|
228
|
+
length: markdown.trim().length
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
// Parse frontmatter (simple implementation)
|
|
232
|
+
const { frontmatter, content } = this.parseFrontmatter(markdown);
|
|
233
|
+
return {
|
|
234
|
+
markdown,
|
|
235
|
+
frontmatter,
|
|
236
|
+
title: frontmatter?.title ?? meta.id,
|
|
237
|
+
description: frontmatter?.description
|
|
238
|
+
};
|
|
239
|
+
} catch (error) {
|
|
240
|
+
throw new StandardError('SKILL_LOAD_ERROR', `Failed to load skill from disk: ${meta.id}`, {
|
|
241
|
+
skillId: meta.id,
|
|
242
|
+
path: skillPath,
|
|
243
|
+
error: String(error)
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Scan skills directory and load metadata
|
|
249
|
+
*/ async scanSkillsDirectory() {
|
|
250
|
+
try {
|
|
251
|
+
const entries = await fs.readdir(this.skillsBasePath, {
|
|
252
|
+
withFileTypes: true
|
|
253
|
+
});
|
|
254
|
+
for (const entry of entries){
|
|
255
|
+
if (entry.isDirectory()) {
|
|
256
|
+
const skillId = entry.name;
|
|
257
|
+
const skillFile = path.join(this.skillsBasePath, skillId, 'SKILL.md');
|
|
258
|
+
try {
|
|
259
|
+
const stat = await fs.stat(skillFile);
|
|
260
|
+
const hash = await this.computeFileHash(path.join(skillId, 'SKILL.md'));
|
|
261
|
+
const metadata = {
|
|
262
|
+
id: skillId,
|
|
263
|
+
path: path.join(skillId, 'SKILL.md'),
|
|
264
|
+
hash,
|
|
265
|
+
size: stat.size
|
|
266
|
+
};
|
|
267
|
+
this.metadata.set(skillId, metadata);
|
|
268
|
+
} catch (error) {
|
|
269
|
+
// Skip invalid skills
|
|
270
|
+
if (this.debug) {
|
|
271
|
+
this.logger.debug('Skipping invalid skill', {
|
|
272
|
+
skillId,
|
|
273
|
+
error: String(error)
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
} catch (error) {
|
|
280
|
+
throw new StandardError('SCAN_ERROR', 'Failed to scan skills directory', {
|
|
281
|
+
skillsBasePath: this.skillsBasePath,
|
|
282
|
+
error: String(error)
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Compute SHA-256 hash of file
|
|
288
|
+
*/ async computeFileHash(relativePath) {
|
|
289
|
+
const fullPath = path.join(this.skillsBasePath, relativePath);
|
|
290
|
+
const content = await fs.readFile(fullPath, 'utf-8');
|
|
291
|
+
return crypto.createHash('sha256').update(content, 'utf-8').digest('hex');
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Load metadata from database
|
|
295
|
+
*/ async loadMetadataFromDatabase() {
|
|
296
|
+
if (!this.dbService) {
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
try {
|
|
300
|
+
const sqliteAdapter = this.dbService.getAdapter('sqlite');
|
|
301
|
+
const rows = await sqliteAdapter.raw('SELECT id, path, hash, size, last_loaded FROM skill_metadata');
|
|
302
|
+
for (const row of rows){
|
|
303
|
+
const existing = this.metadata.get(row.id);
|
|
304
|
+
if (existing) {
|
|
305
|
+
// Update with database values
|
|
306
|
+
existing.lastLoaded = row.last_loaded ? new Date(row.last_loaded) : undefined;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
} catch (error) {
|
|
310
|
+
// Table might not exist yet
|
|
311
|
+
if (this.debug) {
|
|
312
|
+
this.logger.debug('Failed to load metadata from database', {
|
|
313
|
+
error: String(error)
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Update metadata in database
|
|
320
|
+
*/ async updateMetadataInDatabase(meta) {
|
|
321
|
+
if (!this.dbService) {
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
try {
|
|
325
|
+
const sqliteAdapter = this.dbService.getAdapter('sqlite');
|
|
326
|
+
await sqliteAdapter.raw(`INSERT OR REPLACE INTO skill_metadata (id, path, hash, size, last_loaded)
|
|
327
|
+
VALUES (?, ?, ?, ?, ?)`, [
|
|
328
|
+
meta.id,
|
|
329
|
+
meta.path,
|
|
330
|
+
meta.hash,
|
|
331
|
+
meta.size,
|
|
332
|
+
new Date().toISOString()
|
|
333
|
+
]);
|
|
334
|
+
} catch (error) {
|
|
335
|
+
if (this.debug) {
|
|
336
|
+
this.logger.debug('Failed to update metadata in database', {
|
|
337
|
+
skillId: meta.id,
|
|
338
|
+
error: String(error)
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* Parse frontmatter from markdown
|
|
345
|
+
*/ parseFrontmatter(markdown) {
|
|
346
|
+
const frontmatterRegex = /^---\s*\n([\s\S]*?)\n---\s*\n([\s\S]*)$/;
|
|
347
|
+
const match = markdown.match(frontmatterRegex);
|
|
348
|
+
if (!match) {
|
|
349
|
+
return {
|
|
350
|
+
content: markdown
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
const [, frontmatterText, content] = match;
|
|
354
|
+
const frontmatter = {};
|
|
355
|
+
// Simple YAML parser (key: value)
|
|
356
|
+
const lines = frontmatterText.split('\n');
|
|
357
|
+
for (const line of lines){
|
|
358
|
+
const colonIndex = line.indexOf(':');
|
|
359
|
+
if (colonIndex > 0) {
|
|
360
|
+
const key = line.substring(0, colonIndex).trim();
|
|
361
|
+
const value = line.substring(colonIndex + 1).trim();
|
|
362
|
+
frontmatter[key] = value;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
return {
|
|
366
|
+
frontmatter,
|
|
367
|
+
content
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* Estimate content size in bytes
|
|
372
|
+
*/ estimateContentSize(content) {
|
|
373
|
+
// Rough estimate: markdown size + frontmatter overhead
|
|
374
|
+
let size = Buffer.byteLength(content.markdown, 'utf-8');
|
|
375
|
+
if (content.frontmatter) {
|
|
376
|
+
size += JSON.stringify(content.frontmatter).length;
|
|
377
|
+
}
|
|
378
|
+
return size;
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* Get loader metrics
|
|
382
|
+
*/ getMetrics() {
|
|
383
|
+
const cacheStats = this.cache.getStatistics();
|
|
384
|
+
const contentLoaded = this.cache.size;
|
|
385
|
+
return {
|
|
386
|
+
skillsLoaded: this.metadata.size,
|
|
387
|
+
skillContentLoaded: contentLoaded,
|
|
388
|
+
memoryUsageBytes: cacheStats.memoryUsageBytes,
|
|
389
|
+
cacheHits: cacheStats.hits,
|
|
390
|
+
cacheMisses: cacheStats.misses,
|
|
391
|
+
evictions: cacheStats.evictions,
|
|
392
|
+
hashMismatches: this.metrics.hashMismatches,
|
|
393
|
+
cacheInvalidations: this.metrics.cacheInvalidations,
|
|
394
|
+
cacheHitRate: cacheStats.hitRate
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* Reset metrics
|
|
399
|
+
*/ resetMetrics() {
|
|
400
|
+
this.cache.resetStatistics();
|
|
401
|
+
this.metrics = {
|
|
402
|
+
hashMismatches: 0,
|
|
403
|
+
cacheInvalidations: 0
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
/**
|
|
407
|
+
* Get cache statistics
|
|
408
|
+
*/ getCacheStatistics() {
|
|
409
|
+
return this.cache.getStatistics();
|
|
410
|
+
}
|
|
411
|
+
/**
|
|
412
|
+
* Get loader configuration
|
|
413
|
+
*/ getConfig() {
|
|
414
|
+
return {
|
|
415
|
+
maxMemoryBytes: this.maxMemoryBytes,
|
|
416
|
+
skillsBasePath: this.skillsBasePath
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
/**
|
|
420
|
+
* Clear cache
|
|
421
|
+
*/ clearCache() {
|
|
422
|
+
this.cache.clear();
|
|
423
|
+
this.logger.info('Cache cleared');
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
//# sourceMappingURL=skill-loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/services/skill-loader.ts"],"sourcesContent":["/**\r\n * Skill Loader with Memory Budget\r\n *\r\n * High-performance skill loading system with:\r\n * - Lazy loading (metadata at startup, content on-demand)\r\n * - Memory budget enforcement (100MB default)\r\n * - LRU cache with eviction\r\n * - SHA-256 hash validation\r\n * - <2s startup for 500 skills\r\n * - <100ms cache hit, <500ms cache miss\r\n *\r\n * @module skill-loader\r\n */\r\n\r\nimport * as fs from 'fs/promises';\r\nimport * as path from 'path';\r\nimport * as crypto from 'crypto';\r\nimport { LRUSkillCache, CacheStatistics } from '../lib/skill-cache.js';\r\nimport { DatabaseService } from '../lib/database-service.js';\r\nimport { createLogger, Logger } from '../lib/logging.js';\r\nimport { StandardError } from '../lib/errors.js';\r\n\r\n/**\r\n * Skill metadata (loaded at startup)\r\n */\r\nexport interface SkillMetadata {\r\n /** Skill ID */\r\n id: string;\r\n\r\n /** Skill file path (relative to skills base) */\r\n path: string;\r\n\r\n /** SHA-256 content hash */\r\n hash: string;\r\n\r\n /** File size in bytes */\r\n size: number;\r\n\r\n /** Last loaded timestamp */\r\n lastLoaded?: Date;\r\n\r\n /** Skill content (lazy loaded) */\r\n content?: SkillContent;\r\n}\r\n\r\n/**\r\n * Skill content (lazy loaded)\r\n */\r\nexport interface SkillContent {\r\n /** Full markdown content */\r\n markdown: string;\r\n\r\n /** Parsed frontmatter (optional) */\r\n frontmatter?: Record<string, any>;\r\n\r\n /** Skill title */\r\n title?: string;\r\n\r\n /** Skill description */\r\n description?: string;\r\n}\r\n\r\n/**\r\n * Skill with content loaded\r\n */\r\nexport interface LoadedSkill extends SkillMetadata {\r\n /** Skill content (always defined for loaded skill) */\r\n content: SkillContent;\r\n}\r\n\r\n/**\r\n * Loader metrics\r\n */\r\nexport interface LoaderMetrics {\r\n /** Total skills discovered (metadata loaded) */\r\n skillsLoaded: number;\r\n\r\n /** Skills with content loaded */\r\n skillContentLoaded: number;\r\n\r\n /** Current memory usage (bytes) */\r\n memoryUsageBytes: number;\r\n\r\n /** Cache hits */\r\n cacheHits: number;\r\n\r\n /** Cache misses */\r\n cacheMisses: number;\r\n\r\n /** Cache evictions */\r\n evictions: number;\r\n\r\n /** Hash mismatches detected */\r\n hashMismatches: number;\r\n\r\n /** Cache invalidations */\r\n cacheInvalidations: number;\r\n\r\n /** Cache hit rate (0-1) */\r\n cacheHitRate: number;\r\n}\r\n\r\n/**\r\n * Loader configuration\r\n */\r\nexport interface SkillLoaderConfig {\r\n /** Database service */\r\n dbService?: DatabaseService;\r\n\r\n /** Maximum memory budget (bytes) */\r\n maxMemoryBytes?: number;\r\n\r\n /** Skills base path */\r\n skillsBasePath?: string;\r\n\r\n /** Logger instance */\r\n logger?: Logger;\r\n\r\n /** Enable debug logging */\r\n debug?: boolean;\r\n}\r\n\r\n/**\r\n * Skill Loader with memory budget and lazy loading\r\n */\r\nexport class SkillLoader {\r\n private cache: LRUSkillCache<SkillContent>;\r\n private metadata: Map<string, SkillMetadata>;\r\n private dbService?: DatabaseService;\r\n private skillsBasePath: string;\r\n private logger: Logger;\r\n private debug: boolean;\r\n private maxMemoryBytes: number;\r\n private initialized: boolean = false;\r\n\r\n // Loading locks (prevent duplicate loads)\r\n private loadingLocks: Map<string, Promise<LoadedSkill>> = new Map();\r\n\r\n // Metrics\r\n private metrics = {\r\n hashMismatches: 0,\r\n cacheInvalidations: 0,\r\n };\r\n\r\n constructor(config: SkillLoaderConfig) {\r\n this.dbService = config.dbService;\r\n this.maxMemoryBytes = config.maxMemoryBytes ?? 100 * 1024 * 1024; // 100MB default\r\n this.skillsBasePath = config.skillsBasePath ?? path.join(process.cwd(), '.claude/skills');\r\n this.logger = config.logger ?? createLogger('skill-loader');\r\n this.debug = config.debug ?? false;\r\n\r\n // Initialize metadata map\r\n this.metadata = new Map();\r\n\r\n // Initialize LRU cache\r\n this.cache = new LRUSkillCache<SkillContent>({\r\n maxMemoryBytes: this.maxMemoryBytes,\r\n logger: this.logger,\r\n debug: this.debug,\r\n });\r\n\r\n if (this.debug) {\r\n this.logger.info('SkillLoader initialized', {\r\n maxMemoryBytes: this.maxMemoryBytes,\r\n maxMemoryMB: (this.maxMemoryBytes / 1024 / 1024).toFixed(2),\r\n skillsBasePath: this.skillsBasePath,\r\n });\r\n }\r\n }\r\n\r\n /**\r\n * Initialize loader\r\n *\r\n * Scans skills directory and loads metadata (NOT content).\r\n * Fast: <2s for 500 skills.\r\n */\r\n async initialize(): Promise<void> {\r\n const startTime = Date.now();\r\n\r\n if (this.initialized) {\r\n this.logger.warn('SkillLoader already initialized');\r\n return;\r\n }\r\n\r\n this.logger.info('Initializing SkillLoader', { skillsBasePath: this.skillsBasePath });\r\n\r\n // Scan skills directory\r\n await this.scanSkillsDirectory();\r\n\r\n // Load metadata from database (if available)\r\n if (this.dbService) {\r\n await this.loadMetadataFromDatabase();\r\n }\r\n\r\n this.initialized = true;\r\n\r\n const initTime = Date.now() - startTime;\r\n this.logger.info('SkillLoader initialized', {\r\n skillsLoaded: this.metadata.size,\r\n initTimeMs: initTime,\r\n });\r\n\r\n if (initTime >= 2000) {\r\n this.logger.warn('Initialization time exceeded target', {\r\n initTimeMs: initTime,\r\n target: 2000,\r\n });\r\n }\r\n }\r\n\r\n /**\r\n * Load skill content\r\n *\r\n * Lazy loading: content loaded on-demand.\r\n * - Cache hit: <100ms\r\n * - Cache miss: <500ms (disk I/O + hash validation)\r\n *\r\n * @param skillId - Skill ID to load\r\n * @returns Loaded skill with content\r\n */\r\n async loadSkill(skillId: string): Promise<LoadedSkill> {\r\n const startTime = Date.now();\r\n\r\n if (!this.initialized) {\r\n throw new StandardError(\r\n 'LOADER_NOT_INITIALIZED',\r\n 'SkillLoader not initialized. Call initialize() first.'\r\n );\r\n }\r\n\r\n // Check if already loading (prevent duplicate loads)\r\n const existingLoad = this.loadingLocks.get(skillId);\r\n if (existingLoad) {\r\n if (this.debug) {\r\n this.logger.debug('Waiting for existing load', { skillId });\r\n }\r\n return existingLoad;\r\n }\r\n\r\n // Create loading promise\r\n const loadPromise = this.doLoadSkill(skillId, startTime);\r\n this.loadingLocks.set(skillId, loadPromise);\r\n\r\n try {\r\n const skill = await loadPromise;\r\n return skill;\r\n } finally {\r\n this.loadingLocks.delete(skillId);\r\n }\r\n }\r\n\r\n /**\r\n * Internal skill loading implementation\r\n */\r\n private async doLoadSkill(skillId: string, startTime: number): Promise<LoadedSkill> {\r\n // Get metadata\r\n const meta = this.metadata.get(skillId);\r\n if (!meta) {\r\n throw new StandardError(\r\n 'SKILL_NOT_FOUND',\r\n `Skill not found: ${skillId}`,\r\n { skillId }\r\n );\r\n }\r\n\r\n // Check cache first\r\n const cached = this.cache.get(skillId);\r\n if (cached) {\r\n const loadTime = Date.now() - startTime;\r\n\r\n if (this.debug) {\r\n this.logger.debug('Cache hit', {\r\n skillId,\r\n loadTimeMs: loadTime,\r\n });\r\n }\r\n\r\n // Verify hash (detect file changes)\r\n const currentHash = await this.computeFileHash(meta.path);\r\n if (currentHash !== meta.hash) {\r\n // Hash mismatch - invalidate cache and reload\r\n this.metrics.hashMismatches++;\r\n this.metrics.cacheInvalidations++;\r\n this.cache.delete(skillId);\r\n\r\n if (this.debug) {\r\n this.logger.debug('Hash mismatch detected, reloading', {\r\n skillId,\r\n oldHash: meta.hash,\r\n newHash: currentHash,\r\n });\r\n }\r\n\r\n // Fall through to load from disk\r\n } else {\r\n // Cache hit with valid hash\r\n return {\r\n ...meta,\r\n content: cached,\r\n };\r\n }\r\n }\r\n\r\n // Cache miss - load from disk\r\n const content = await this.loadSkillFromDisk(meta);\r\n const loadTime = Date.now() - startTime;\r\n\r\n if (this.debug) {\r\n this.logger.debug('Cache miss, loaded from disk', {\r\n skillId,\r\n loadTimeMs: loadTime,\r\n });\r\n }\r\n\r\n if (loadTime >= 500) {\r\n this.logger.warn('Load time exceeded target', {\r\n skillId,\r\n loadTimeMs: loadTime,\r\n target: 500,\r\n });\r\n }\r\n\r\n // Update metadata with new hash (if changed)\r\n const currentHash = await this.computeFileHash(meta.path);\r\n if (currentHash !== meta.hash) {\r\n meta.hash = currentHash;\r\n this.metrics.hashMismatches++;\r\n\r\n // Update database\r\n if (this.dbService) {\r\n await this.updateMetadataInDatabase(meta);\r\n }\r\n }\r\n\r\n // Cache the content\r\n const contentSize = this.estimateContentSize(content);\r\n this.cache.set(skillId, content, contentSize);\r\n\r\n return {\r\n ...meta,\r\n content,\r\n };\r\n }\r\n\r\n /**\r\n * Load skill content from disk\r\n */\r\n private async loadSkillFromDisk(meta: SkillMetadata): Promise<SkillContent> {\r\n const skillPath = path.join(this.skillsBasePath, meta.path);\r\n\r\n try {\r\n const markdown = await fs.readFile(skillPath, 'utf-8');\r\n\r\n // Validate content\r\n if (!markdown || markdown.trim().length === 0) {\r\n throw new StandardError(\r\n 'EMPTY_SKILL_FILE',\r\n `Empty skill file: ${meta.id}`,\r\n { skillId: meta.id, path: skillPath }\r\n );\r\n }\r\n\r\n // Check for corrupted content (null bytes, invalid characters)\r\n if (markdown.includes('\\0') || /[\\x00-\\x08\\x0B-\\x0C\\x0E-\\x1F]/.test(markdown)) {\r\n throw new StandardError(\r\n 'CORRUPTED_SKILL_FILE',\r\n `Corrupted skill file (invalid characters): ${meta.id}`,\r\n { skillId: meta.id, path: skillPath }\r\n );\r\n }\r\n\r\n // Validate minimum content length (reasonable skill should be >50 chars)\r\n if (markdown.trim().length < 50) {\r\n throw new StandardError(\r\n 'INVALID_SKILL_FILE',\r\n `Invalid skill file (too short): ${meta.id}`,\r\n { skillId: meta.id, path: skillPath, length: markdown.trim().length }\r\n );\r\n }\r\n\r\n // Parse frontmatter (simple implementation)\r\n const { frontmatter, content } = this.parseFrontmatter(markdown);\r\n\r\n return {\r\n markdown,\r\n frontmatter,\r\n title: frontmatter?.title ?? meta.id,\r\n description: frontmatter?.description,\r\n };\r\n } catch (error) {\r\n throw new StandardError(\r\n 'SKILL_LOAD_ERROR',\r\n `Failed to load skill from disk: ${meta.id}`,\r\n { skillId: meta.id, path: skillPath, error: String(error) }\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Scan skills directory and load metadata\r\n */\r\n private async scanSkillsDirectory(): Promise<void> {\r\n try {\r\n const entries = await fs.readdir(this.skillsBasePath, { withFileTypes: true });\r\n\r\n for (const entry of entries) {\r\n if (entry.isDirectory()) {\r\n const skillId = entry.name;\r\n const skillFile = path.join(this.skillsBasePath, skillId, 'SKILL.md');\r\n\r\n try {\r\n const stat = await fs.stat(skillFile);\r\n const hash = await this.computeFileHash(path.join(skillId, 'SKILL.md'));\r\n\r\n const metadata: SkillMetadata = {\r\n id: skillId,\r\n path: path.join(skillId, 'SKILL.md'),\r\n hash,\r\n size: stat.size,\r\n };\r\n\r\n this.metadata.set(skillId, metadata);\r\n } catch (error) {\r\n // Skip invalid skills\r\n if (this.debug) {\r\n this.logger.debug('Skipping invalid skill', {\r\n skillId,\r\n error: String(error),\r\n });\r\n }\r\n }\r\n }\r\n }\r\n } catch (error) {\r\n throw new StandardError(\r\n 'SCAN_ERROR',\r\n 'Failed to scan skills directory',\r\n { skillsBasePath: this.skillsBasePath, error: String(error) }\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Compute SHA-256 hash of file\r\n */\r\n private async computeFileHash(relativePath: string): Promise<string> {\r\n const fullPath = path.join(this.skillsBasePath, relativePath);\r\n const content = await fs.readFile(fullPath, 'utf-8');\r\n return crypto.createHash('sha256').update(content, 'utf-8').digest('hex');\r\n }\r\n\r\n /**\r\n * Load metadata from database\r\n */\r\n private async loadMetadataFromDatabase(): Promise<void> {\r\n if (!this.dbService) {\r\n return;\r\n }\r\n\r\n try {\r\n const sqliteAdapter = this.dbService.getAdapter('sqlite');\r\n const rows = await sqliteAdapter.raw<any[]>(\r\n 'SELECT id, path, hash, size, last_loaded FROM skill_metadata'\r\n );\r\n\r\n for (const row of rows) {\r\n const existing = this.metadata.get(row.id);\r\n if (existing) {\r\n // Update with database values\r\n existing.lastLoaded = row.last_loaded ? new Date(row.last_loaded) : undefined;\r\n }\r\n }\r\n } catch (error) {\r\n // Table might not exist yet\r\n if (this.debug) {\r\n this.logger.debug('Failed to load metadata from database', {\r\n error: String(error),\r\n });\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Update metadata in database\r\n */\r\n private async updateMetadataInDatabase(meta: SkillMetadata): Promise<void> {\r\n if (!this.dbService) {\r\n return;\r\n }\r\n\r\n try {\r\n const sqliteAdapter = this.dbService.getAdapter('sqlite');\r\n await sqliteAdapter.raw(\r\n `INSERT OR REPLACE INTO skill_metadata (id, path, hash, size, last_loaded)\r\n VALUES (?, ?, ?, ?, ?)`,\r\n [meta.id, meta.path, meta.hash, meta.size, new Date().toISOString()]\r\n );\r\n } catch (error) {\r\n if (this.debug) {\r\n this.logger.debug('Failed to update metadata in database', {\r\n skillId: meta.id,\r\n error: String(error),\r\n });\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Parse frontmatter from markdown\r\n */\r\n private parseFrontmatter(markdown: string): {\r\n frontmatter?: Record<string, any>;\r\n content: string;\r\n } {\r\n const frontmatterRegex = /^---\\s*\\n([\\s\\S]*?)\\n---\\s*\\n([\\s\\S]*)$/;\r\n const match = markdown.match(frontmatterRegex);\r\n\r\n if (!match) {\r\n return { content: markdown };\r\n }\r\n\r\n const [, frontmatterText, content] = match;\r\n const frontmatter: Record<string, any> = {};\r\n\r\n // Simple YAML parser (key: value)\r\n const lines = frontmatterText.split('\\n');\r\n for (const line of lines) {\r\n const colonIndex = line.indexOf(':');\r\n if (colonIndex > 0) {\r\n const key = line.substring(0, colonIndex).trim();\r\n const value = line.substring(colonIndex + 1).trim();\r\n frontmatter[key] = value;\r\n }\r\n }\r\n\r\n return { frontmatter, content };\r\n }\r\n\r\n /**\r\n * Estimate content size in bytes\r\n */\r\n private estimateContentSize(content: SkillContent): number {\r\n // Rough estimate: markdown size + frontmatter overhead\r\n let size = Buffer.byteLength(content.markdown, 'utf-8');\r\n\r\n if (content.frontmatter) {\r\n size += JSON.stringify(content.frontmatter).length;\r\n }\r\n\r\n return size;\r\n }\r\n\r\n /**\r\n * Get loader metrics\r\n */\r\n getMetrics(): LoaderMetrics {\r\n const cacheStats = this.cache.getStatistics();\r\n const contentLoaded = this.cache.size;\r\n\r\n return {\r\n skillsLoaded: this.metadata.size,\r\n skillContentLoaded: contentLoaded,\r\n memoryUsageBytes: cacheStats.memoryUsageBytes,\r\n cacheHits: cacheStats.hits,\r\n cacheMisses: cacheStats.misses,\r\n evictions: cacheStats.evictions,\r\n hashMismatches: this.metrics.hashMismatches,\r\n cacheInvalidations: this.metrics.cacheInvalidations,\r\n cacheHitRate: cacheStats.hitRate,\r\n };\r\n }\r\n\r\n /**\r\n * Reset metrics\r\n */\r\n resetMetrics(): void {\r\n this.cache.resetStatistics();\r\n this.metrics = {\r\n hashMismatches: 0,\r\n cacheInvalidations: 0,\r\n };\r\n }\r\n\r\n /**\r\n * Get cache statistics\r\n */\r\n getCacheStatistics(): CacheStatistics {\r\n return this.cache.getStatistics();\r\n }\r\n\r\n /**\r\n * Get loader configuration\r\n */\r\n getConfig(): { maxMemoryBytes: number; skillsBasePath: string } {\r\n return {\r\n maxMemoryBytes: this.maxMemoryBytes,\r\n skillsBasePath: this.skillsBasePath,\r\n };\r\n }\r\n\r\n /**\r\n * Clear cache\r\n */\r\n clearCache(): void {\r\n this.cache.clear();\r\n this.logger.info('Cache cleared');\r\n }\r\n}\r\n"],"names":["fs","path","crypto","LRUSkillCache","createLogger","StandardError","SkillLoader","cache","metadata","dbService","skillsBasePath","logger","debug","maxMemoryBytes","initialized","loadingLocks","Map","metrics","hashMismatches","cacheInvalidations","config","join","process","cwd","info","maxMemoryMB","toFixed","initialize","startTime","Date","now","warn","scanSkillsDirectory","loadMetadataFromDatabase","initTime","skillsLoaded","size","initTimeMs","target","loadSkill","skillId","existingLoad","get","loadPromise","doLoadSkill","set","skill","delete","meta","cached","loadTime","loadTimeMs","currentHash","computeFileHash","hash","oldHash","newHash","content","loadSkillFromDisk","updateMetadataInDatabase","contentSize","estimateContentSize","skillPath","markdown","readFile","trim","length","id","includes","test","frontmatter","parseFrontmatter","title","description","error","String","entries","readdir","withFileTypes","entry","isDirectory","name","skillFile","stat","relativePath","fullPath","createHash","update","digest","sqliteAdapter","getAdapter","rows","raw","row","existing","lastLoaded","last_loaded","undefined","toISOString","frontmatterRegex","match","frontmatterText","lines","split","line","colonIndex","indexOf","key","substring","value","Buffer","byteLength","JSON","stringify","getMetrics","cacheStats","getStatistics","contentLoaded","skillContentLoaded","memoryUsageBytes","cacheHits","hits","cacheMisses","misses","evictions","cacheHitRate","hitRate","resetMetrics","resetStatistics","getCacheStatistics","getConfig","clearCache","clear"],"mappings":"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"}
|