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,297 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LRU Skill Cache
|
|
3
|
+
*
|
|
4
|
+
* Memory-aware LRU (Least Recently Used) cache for skill content.
|
|
5
|
+
* Tracks memory usage per skill and evicts LRU entries when budget exceeded.
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
8
|
+
* - Memory budget enforcement (bytes, not just entry count)
|
|
9
|
+
* - LRU eviction policy
|
|
10
|
+
* - Cache statistics (hits, misses, evictions)
|
|
11
|
+
* - Thread-safe operations
|
|
12
|
+
* - TTL support (optional)
|
|
13
|
+
*
|
|
14
|
+
* @module skill-cache
|
|
15
|
+
*/ import { createLogger } from './logging.js';
|
|
16
|
+
import { StandardError } from './errors.js';
|
|
17
|
+
/**
|
|
18
|
+
* LRU Skill Cache with memory budget enforcement
|
|
19
|
+
*/ export class LRUSkillCache {
|
|
20
|
+
cache;
|
|
21
|
+
maxMemoryBytes;
|
|
22
|
+
maxEntries;
|
|
23
|
+
defaultTTLMs;
|
|
24
|
+
currentMemoryBytes = 0;
|
|
25
|
+
logger;
|
|
26
|
+
debug;
|
|
27
|
+
// Statistics
|
|
28
|
+
stats = {
|
|
29
|
+
hits: 0,
|
|
30
|
+
misses: 0,
|
|
31
|
+
evictions: 0
|
|
32
|
+
};
|
|
33
|
+
constructor(config){
|
|
34
|
+
this.cache = new Map();
|
|
35
|
+
this.maxMemoryBytes = config.maxMemoryBytes;
|
|
36
|
+
this.maxEntries = config.maxEntries ?? Number.MAX_SAFE_INTEGER;
|
|
37
|
+
this.defaultTTLMs = config.defaultTTLMs;
|
|
38
|
+
this.logger = config.logger ?? createLogger('lru-skill-cache');
|
|
39
|
+
this.debug = config.debug ?? false;
|
|
40
|
+
if (this.debug) {
|
|
41
|
+
this.logger.info('LRU cache initialized', {
|
|
42
|
+
maxMemoryBytes: this.maxMemoryBytes,
|
|
43
|
+
maxMemoryMB: (this.maxMemoryBytes / 1024 / 1024).toFixed(2),
|
|
44
|
+
maxEntries: this.maxEntries,
|
|
45
|
+
defaultTTLMs: this.defaultTTLMs
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Get value from cache
|
|
51
|
+
*
|
|
52
|
+
* Updates last access time (LRU tracking).
|
|
53
|
+
* Returns undefined if not found or expired.
|
|
54
|
+
*/ get(key) {
|
|
55
|
+
const entry = this.cache.get(key);
|
|
56
|
+
if (!entry) {
|
|
57
|
+
this.stats.misses++;
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
// Check expiry
|
|
61
|
+
if (entry.expiresAt && entry.expiresAt < new Date()) {
|
|
62
|
+
if (this.debug) {
|
|
63
|
+
this.logger.debug('Cache entry expired', {
|
|
64
|
+
key
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
this.delete(key);
|
|
68
|
+
this.stats.misses++;
|
|
69
|
+
return undefined;
|
|
70
|
+
}
|
|
71
|
+
// Update last accessed (LRU tracking)
|
|
72
|
+
entry.lastAccessed = new Date();
|
|
73
|
+
this.stats.hits++;
|
|
74
|
+
if (this.debug) {
|
|
75
|
+
this.logger.debug('Cache hit', {
|
|
76
|
+
key,
|
|
77
|
+
sizeBytes: entry.sizeBytes,
|
|
78
|
+
age: Date.now() - entry.createdAt.getTime()
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
return entry.value;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Set value in cache
|
|
85
|
+
*
|
|
86
|
+
* Evicts LRU entries if memory budget would be exceeded.
|
|
87
|
+
*
|
|
88
|
+
* @param key - Cache key
|
|
89
|
+
* @param value - Value to cache
|
|
90
|
+
* @param sizeBytes - Size of value in bytes
|
|
91
|
+
* @param ttlMs - TTL in milliseconds (optional, overrides default)
|
|
92
|
+
*/ set(key, value, sizeBytes, ttlMs) {
|
|
93
|
+
// Check if entry already exists
|
|
94
|
+
const existing = this.cache.get(key);
|
|
95
|
+
if (existing) {
|
|
96
|
+
// Update existing entry
|
|
97
|
+
this.currentMemoryBytes -= existing.sizeBytes;
|
|
98
|
+
this.currentMemoryBytes += sizeBytes;
|
|
99
|
+
existing.value = value;
|
|
100
|
+
existing.sizeBytes = sizeBytes;
|
|
101
|
+
existing.lastAccessed = new Date();
|
|
102
|
+
existing.createdAt = new Date();
|
|
103
|
+
if (ttlMs !== undefined || this.defaultTTLMs !== undefined) {
|
|
104
|
+
const ttl = ttlMs ?? this.defaultTTLMs;
|
|
105
|
+
existing.expiresAt = new Date(Date.now() + ttl);
|
|
106
|
+
}
|
|
107
|
+
if (this.debug) {
|
|
108
|
+
this.logger.debug('Cache entry updated', {
|
|
109
|
+
key,
|
|
110
|
+
sizeBytes,
|
|
111
|
+
memoryUsageBytes: this.currentMemoryBytes
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
// Evict entries if needed
|
|
117
|
+
this.evictIfNeeded(sizeBytes);
|
|
118
|
+
// Create new entry
|
|
119
|
+
const entry = {
|
|
120
|
+
key,
|
|
121
|
+
value,
|
|
122
|
+
sizeBytes,
|
|
123
|
+
lastAccessed: new Date(),
|
|
124
|
+
createdAt: new Date()
|
|
125
|
+
};
|
|
126
|
+
if (ttlMs !== undefined || this.defaultTTLMs !== undefined) {
|
|
127
|
+
const ttl = ttlMs ?? this.defaultTTLMs;
|
|
128
|
+
entry.expiresAt = new Date(Date.now() + ttl);
|
|
129
|
+
}
|
|
130
|
+
this.cache.set(key, entry);
|
|
131
|
+
this.currentMemoryBytes += sizeBytes;
|
|
132
|
+
if (this.debug) {
|
|
133
|
+
this.logger.debug('Cache entry added', {
|
|
134
|
+
key,
|
|
135
|
+
sizeBytes,
|
|
136
|
+
memoryUsageBytes: this.currentMemoryBytes,
|
|
137
|
+
memoryUtilization: (this.currentMemoryBytes / this.maxMemoryBytes).toFixed(2)
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Delete entry from cache
|
|
143
|
+
*/ delete(key) {
|
|
144
|
+
const entry = this.cache.get(key);
|
|
145
|
+
if (!entry) {
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
this.cache.delete(key);
|
|
149
|
+
this.currentMemoryBytes -= entry.sizeBytes;
|
|
150
|
+
if (this.debug) {
|
|
151
|
+
this.logger.debug('Cache entry deleted', {
|
|
152
|
+
key,
|
|
153
|
+
sizeBytes: entry.sizeBytes,
|
|
154
|
+
memoryUsageBytes: this.currentMemoryBytes
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
return true;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Check if key exists in cache
|
|
161
|
+
*/ has(key) {
|
|
162
|
+
const entry = this.cache.get(key);
|
|
163
|
+
if (!entry) {
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
166
|
+
// Check expiry
|
|
167
|
+
if (entry.expiresAt && entry.expiresAt < new Date()) {
|
|
168
|
+
this.delete(key);
|
|
169
|
+
return false;
|
|
170
|
+
}
|
|
171
|
+
return true;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Clear all entries
|
|
175
|
+
*/ clear() {
|
|
176
|
+
this.cache.clear();
|
|
177
|
+
this.currentMemoryBytes = 0;
|
|
178
|
+
if (this.debug) {
|
|
179
|
+
this.logger.debug('Cache cleared');
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Get cache size (number of entries)
|
|
184
|
+
*/ get size() {
|
|
185
|
+
return this.cache.size;
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Get current memory usage (bytes)
|
|
189
|
+
*/ get memoryUsageBytes() {
|
|
190
|
+
return this.currentMemoryBytes;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Get cache statistics
|
|
194
|
+
*/ getStatistics() {
|
|
195
|
+
const totalOps = this.stats.hits + this.stats.misses;
|
|
196
|
+
const hitRate = totalOps > 0 ? this.stats.hits / totalOps : 0;
|
|
197
|
+
const evictionRate = totalOps > 0 ? this.stats.evictions / totalOps : 0;
|
|
198
|
+
const memoryUtilization = this.currentMemoryBytes / this.maxMemoryBytes;
|
|
199
|
+
return {
|
|
200
|
+
size: this.cache.size,
|
|
201
|
+
maxSize: this.maxEntries,
|
|
202
|
+
memoryUsageBytes: this.currentMemoryBytes,
|
|
203
|
+
maxMemoryBytes: this.maxMemoryBytes,
|
|
204
|
+
hits: this.stats.hits,
|
|
205
|
+
misses: this.stats.misses,
|
|
206
|
+
evictions: this.stats.evictions,
|
|
207
|
+
hitRate,
|
|
208
|
+
evictionRate,
|
|
209
|
+
memoryUtilization
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Reset statistics
|
|
214
|
+
*/ resetStatistics() {
|
|
215
|
+
this.stats = {
|
|
216
|
+
hits: 0,
|
|
217
|
+
misses: 0,
|
|
218
|
+
evictions: 0
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Get all cache keys
|
|
223
|
+
*/ keys() {
|
|
224
|
+
return Array.from(this.cache.keys());
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Evict entries if needed to fit new entry
|
|
228
|
+
*
|
|
229
|
+
* Uses LRU (Least Recently Used) eviction policy.
|
|
230
|
+
*
|
|
231
|
+
* @param newEntrySizeBytes - Size of new entry to add
|
|
232
|
+
*/ evictIfNeeded(newEntrySizeBytes) {
|
|
233
|
+
// Check entry count limit
|
|
234
|
+
while(this.cache.size >= this.maxEntries){
|
|
235
|
+
this.evictLRU();
|
|
236
|
+
}
|
|
237
|
+
// Check memory budget
|
|
238
|
+
while(this.currentMemoryBytes + newEntrySizeBytes > this.maxMemoryBytes && this.cache.size > 0){
|
|
239
|
+
this.evictLRU();
|
|
240
|
+
}
|
|
241
|
+
// Final check: if single entry exceeds budget, throw error
|
|
242
|
+
if (newEntrySizeBytes > this.maxMemoryBytes) {
|
|
243
|
+
throw new StandardError('CACHE_ENTRY_TOO_LARGE', `Entry size (${newEntrySizeBytes} bytes) exceeds maximum memory budget (${this.maxMemoryBytes} bytes)`, {
|
|
244
|
+
newEntrySizeBytes,
|
|
245
|
+
maxMemoryBytes: this.maxMemoryBytes
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Evict least recently used entry
|
|
251
|
+
*/ evictLRU() {
|
|
252
|
+
let oldestKey;
|
|
253
|
+
let oldestTime;
|
|
254
|
+
// Find LRU entry
|
|
255
|
+
for (const [key, entry] of this.cache.entries()){
|
|
256
|
+
if (!oldestTime || entry.lastAccessed < oldestTime) {
|
|
257
|
+
oldestKey = key;
|
|
258
|
+
oldestTime = entry.lastAccessed;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
if (oldestKey) {
|
|
262
|
+
const entry = this.cache.get(oldestKey);
|
|
263
|
+
this.delete(oldestKey);
|
|
264
|
+
this.stats.evictions++;
|
|
265
|
+
if (this.debug) {
|
|
266
|
+
this.logger.debug('Evicted LRU entry', {
|
|
267
|
+
key: oldestKey,
|
|
268
|
+
sizeBytes: entry.sizeBytes,
|
|
269
|
+
age: Date.now() - entry.createdAt.getTime(),
|
|
270
|
+
lastAccessed: entry.lastAccessed.toISOString()
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Remove expired entries
|
|
277
|
+
*
|
|
278
|
+
* @returns Number of expired entries removed
|
|
279
|
+
*/ cleanupExpired() {
|
|
280
|
+
const now = new Date();
|
|
281
|
+
let removed = 0;
|
|
282
|
+
for (const [key, entry] of this.cache.entries()){
|
|
283
|
+
if (entry.expiresAt && entry.expiresAt < now) {
|
|
284
|
+
this.delete(key);
|
|
285
|
+
removed++;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
if (removed > 0 && this.debug) {
|
|
289
|
+
this.logger.debug('Cleaned up expired entries', {
|
|
290
|
+
count: removed
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
return removed;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
//# sourceMappingURL=skill-cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/lib/skill-cache.ts"],"sourcesContent":["/**\r\n * LRU Skill Cache\r\n *\r\n * Memory-aware LRU (Least Recently Used) cache for skill content.\r\n * Tracks memory usage per skill and evicts LRU entries when budget exceeded.\r\n *\r\n * Features:\r\n * - Memory budget enforcement (bytes, not just entry count)\r\n * - LRU eviction policy\r\n * - Cache statistics (hits, misses, evictions)\r\n * - Thread-safe operations\r\n * - TTL support (optional)\r\n *\r\n * @module skill-cache\r\n */\r\n\r\nimport { createLogger, Logger } from './logging.js';\r\nimport { StandardError } from './errors.js';\r\n\r\n/**\r\n * Cache entry with LRU metadata\r\n */\r\nexport interface CacheEntry<T> {\r\n /** Cache key (skill ID) */\r\n key: string;\r\n\r\n /** Cached value (skill content) */\r\n value: T;\r\n\r\n /** Entry size in bytes */\r\n sizeBytes: number;\r\n\r\n /** Last access timestamp */\r\n lastAccessed: Date;\r\n\r\n /** Creation timestamp */\r\n createdAt: Date;\r\n\r\n /** Expiry timestamp (optional) */\r\n expiresAt?: Date;\r\n}\r\n\r\n/**\r\n * Cache statistics\r\n */\r\nexport interface CacheStatistics {\r\n /** Current number of entries */\r\n size: number;\r\n\r\n /** Maximum number of entries */\r\n maxSize: number;\r\n\r\n /** Current memory usage (bytes) */\r\n memoryUsageBytes: number;\r\n\r\n /** Maximum memory budget (bytes) */\r\n maxMemoryBytes: number;\r\n\r\n /** Total cache hits */\r\n hits: number;\r\n\r\n /** Total cache misses */\r\n misses: number;\r\n\r\n /** Total evictions */\r\n evictions: number;\r\n\r\n /** Cache hit rate (0-1) */\r\n hitRate: number;\r\n\r\n /** Eviction rate (evictions / total operations) */\r\n evictionRate: number;\r\n\r\n /** Memory utilization (0-1) */\r\n memoryUtilization: number;\r\n}\r\n\r\n/**\r\n * LRU Cache configuration\r\n */\r\nexport interface LRUCacheConfig {\r\n /** Maximum memory budget in bytes */\r\n maxMemoryBytes: number;\r\n\r\n /** Maximum number of entries (optional, defaults to unlimited) */\r\n maxEntries?: number;\r\n\r\n /** Default TTL in milliseconds (optional, defaults to no expiry) */\r\n defaultTTLMs?: number;\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 * LRU Skill Cache with memory budget enforcement\r\n */\r\nexport class LRUSkillCache<T> {\r\n private cache: Map<string, CacheEntry<T>>;\r\n private maxMemoryBytes: number;\r\n private maxEntries: number;\r\n private defaultTTLMs?: number;\r\n private currentMemoryBytes: number = 0;\r\n private logger: Logger;\r\n private debug: boolean;\r\n\r\n // Statistics\r\n private stats = {\r\n hits: 0,\r\n misses: 0,\r\n evictions: 0,\r\n };\r\n\r\n constructor(config: LRUCacheConfig) {\r\n this.cache = new Map();\r\n this.maxMemoryBytes = config.maxMemoryBytes;\r\n this.maxEntries = config.maxEntries ?? Number.MAX_SAFE_INTEGER;\r\n this.defaultTTLMs = config.defaultTTLMs;\r\n this.logger = config.logger ?? createLogger('lru-skill-cache');\r\n this.debug = config.debug ?? false;\r\n\r\n if (this.debug) {\r\n this.logger.info('LRU cache initialized', {\r\n maxMemoryBytes: this.maxMemoryBytes,\r\n maxMemoryMB: (this.maxMemoryBytes / 1024 / 1024).toFixed(2),\r\n maxEntries: this.maxEntries,\r\n defaultTTLMs: this.defaultTTLMs,\r\n });\r\n }\r\n }\r\n\r\n /**\r\n * Get value from cache\r\n *\r\n * Updates last access time (LRU tracking).\r\n * Returns undefined if not found or expired.\r\n */\r\n get(key: string): T | undefined {\r\n const entry = this.cache.get(key);\r\n\r\n if (!entry) {\r\n this.stats.misses++;\r\n return undefined;\r\n }\r\n\r\n // Check expiry\r\n if (entry.expiresAt && entry.expiresAt < new Date()) {\r\n if (this.debug) {\r\n this.logger.debug('Cache entry expired', { key });\r\n }\r\n this.delete(key);\r\n this.stats.misses++;\r\n return undefined;\r\n }\r\n\r\n // Update last accessed (LRU tracking)\r\n entry.lastAccessed = new Date();\r\n this.stats.hits++;\r\n\r\n if (this.debug) {\r\n this.logger.debug('Cache hit', {\r\n key,\r\n sizeBytes: entry.sizeBytes,\r\n age: Date.now() - entry.createdAt.getTime(),\r\n });\r\n }\r\n\r\n return entry.value;\r\n }\r\n\r\n /**\r\n * Set value in cache\r\n *\r\n * Evicts LRU entries if memory budget would be exceeded.\r\n *\r\n * @param key - Cache key\r\n * @param value - Value to cache\r\n * @param sizeBytes - Size of value in bytes\r\n * @param ttlMs - TTL in milliseconds (optional, overrides default)\r\n */\r\n set(key: string, value: T, sizeBytes: number, ttlMs?: number): void {\r\n // Check if entry already exists\r\n const existing = this.cache.get(key);\r\n if (existing) {\r\n // Update existing entry\r\n this.currentMemoryBytes -= existing.sizeBytes;\r\n this.currentMemoryBytes += sizeBytes;\r\n\r\n existing.value = value;\r\n existing.sizeBytes = sizeBytes;\r\n existing.lastAccessed = new Date();\r\n existing.createdAt = new Date();\r\n\r\n if (ttlMs !== undefined || this.defaultTTLMs !== undefined) {\r\n const ttl = ttlMs ?? this.defaultTTLMs!;\r\n existing.expiresAt = new Date(Date.now() + ttl);\r\n }\r\n\r\n if (this.debug) {\r\n this.logger.debug('Cache entry updated', {\r\n key,\r\n sizeBytes,\r\n memoryUsageBytes: this.currentMemoryBytes,\r\n });\r\n }\r\n\r\n return;\r\n }\r\n\r\n // Evict entries if needed\r\n this.evictIfNeeded(sizeBytes);\r\n\r\n // Create new entry\r\n const entry: CacheEntry<T> = {\r\n key,\r\n value,\r\n sizeBytes,\r\n lastAccessed: new Date(),\r\n createdAt: new Date(),\r\n };\r\n\r\n if (ttlMs !== undefined || this.defaultTTLMs !== undefined) {\r\n const ttl = ttlMs ?? this.defaultTTLMs!;\r\n entry.expiresAt = new Date(Date.now() + ttl);\r\n }\r\n\r\n this.cache.set(key, entry);\r\n this.currentMemoryBytes += sizeBytes;\r\n\r\n if (this.debug) {\r\n this.logger.debug('Cache entry added', {\r\n key,\r\n sizeBytes,\r\n memoryUsageBytes: this.currentMemoryBytes,\r\n memoryUtilization: (this.currentMemoryBytes / this.maxMemoryBytes).toFixed(2),\r\n });\r\n }\r\n }\r\n\r\n /**\r\n * Delete entry from cache\r\n */\r\n delete(key: string): boolean {\r\n const entry = this.cache.get(key);\r\n if (!entry) {\r\n return false;\r\n }\r\n\r\n this.cache.delete(key);\r\n this.currentMemoryBytes -= entry.sizeBytes;\r\n\r\n if (this.debug) {\r\n this.logger.debug('Cache entry deleted', {\r\n key,\r\n sizeBytes: entry.sizeBytes,\r\n memoryUsageBytes: this.currentMemoryBytes,\r\n });\r\n }\r\n\r\n return true;\r\n }\r\n\r\n /**\r\n * Check if key exists in cache\r\n */\r\n has(key: string): boolean {\r\n const entry = this.cache.get(key);\r\n if (!entry) {\r\n return false;\r\n }\r\n\r\n // Check expiry\r\n if (entry.expiresAt && entry.expiresAt < new Date()) {\r\n this.delete(key);\r\n return false;\r\n }\r\n\r\n return true;\r\n }\r\n\r\n /**\r\n * Clear all entries\r\n */\r\n clear(): void {\r\n this.cache.clear();\r\n this.currentMemoryBytes = 0;\r\n\r\n if (this.debug) {\r\n this.logger.debug('Cache cleared');\r\n }\r\n }\r\n\r\n /**\r\n * Get cache size (number of entries)\r\n */\r\n get size(): number {\r\n return this.cache.size;\r\n }\r\n\r\n /**\r\n * Get current memory usage (bytes)\r\n */\r\n get memoryUsageBytes(): number {\r\n return this.currentMemoryBytes;\r\n }\r\n\r\n /**\r\n * Get cache statistics\r\n */\r\n getStatistics(): CacheStatistics {\r\n const totalOps = this.stats.hits + this.stats.misses;\r\n const hitRate = totalOps > 0 ? this.stats.hits / totalOps : 0;\r\n const evictionRate = totalOps > 0 ? this.stats.evictions / totalOps : 0;\r\n const memoryUtilization = this.currentMemoryBytes / this.maxMemoryBytes;\r\n\r\n return {\r\n size: this.cache.size,\r\n maxSize: this.maxEntries,\r\n memoryUsageBytes: this.currentMemoryBytes,\r\n maxMemoryBytes: this.maxMemoryBytes,\r\n hits: this.stats.hits,\r\n misses: this.stats.misses,\r\n evictions: this.stats.evictions,\r\n hitRate,\r\n evictionRate,\r\n memoryUtilization,\r\n };\r\n }\r\n\r\n /**\r\n * Reset statistics\r\n */\r\n resetStatistics(): void {\r\n this.stats = {\r\n hits: 0,\r\n misses: 0,\r\n evictions: 0,\r\n };\r\n }\r\n\r\n /**\r\n * Get all cache keys\r\n */\r\n keys(): string[] {\r\n return Array.from(this.cache.keys());\r\n }\r\n\r\n /**\r\n * Evict entries if needed to fit new entry\r\n *\r\n * Uses LRU (Least Recently Used) eviction policy.\r\n *\r\n * @param newEntrySizeBytes - Size of new entry to add\r\n */\r\n private evictIfNeeded(newEntrySizeBytes: number): void {\r\n // Check entry count limit\r\n while (this.cache.size >= this.maxEntries) {\r\n this.evictLRU();\r\n }\r\n\r\n // Check memory budget\r\n while (\r\n this.currentMemoryBytes + newEntrySizeBytes > this.maxMemoryBytes &&\r\n this.cache.size > 0\r\n ) {\r\n this.evictLRU();\r\n }\r\n\r\n // Final check: if single entry exceeds budget, throw error\r\n if (newEntrySizeBytes > this.maxMemoryBytes) {\r\n throw new StandardError(\r\n 'CACHE_ENTRY_TOO_LARGE',\r\n `Entry size (${newEntrySizeBytes} bytes) exceeds maximum memory budget (${this.maxMemoryBytes} bytes)`,\r\n { newEntrySizeBytes, maxMemoryBytes: this.maxMemoryBytes }\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Evict least recently used entry\r\n */\r\n private evictLRU(): void {\r\n let oldestKey: string | undefined;\r\n let oldestTime: Date | undefined;\r\n\r\n // Find LRU entry\r\n for (const [key, entry] of this.cache.entries()) {\r\n if (!oldestTime || entry.lastAccessed < oldestTime) {\r\n oldestKey = key;\r\n oldestTime = entry.lastAccessed;\r\n }\r\n }\r\n\r\n if (oldestKey) {\r\n const entry = this.cache.get(oldestKey)!;\r\n this.delete(oldestKey);\r\n this.stats.evictions++;\r\n\r\n if (this.debug) {\r\n this.logger.debug('Evicted LRU entry', {\r\n key: oldestKey,\r\n sizeBytes: entry.sizeBytes,\r\n age: Date.now() - entry.createdAt.getTime(),\r\n lastAccessed: entry.lastAccessed.toISOString(),\r\n });\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Remove expired entries\r\n *\r\n * @returns Number of expired entries removed\r\n */\r\n cleanupExpired(): number {\r\n const now = new Date();\r\n let removed = 0;\r\n\r\n for (const [key, entry] of this.cache.entries()) {\r\n if (entry.expiresAt && entry.expiresAt < now) {\r\n this.delete(key);\r\n removed++;\r\n }\r\n }\r\n\r\n if (removed > 0 && this.debug) {\r\n this.logger.debug('Cleaned up expired entries', { count: removed });\r\n }\r\n\r\n return removed;\r\n }\r\n}\r\n"],"names":["createLogger","StandardError","LRUSkillCache","cache","maxMemoryBytes","maxEntries","defaultTTLMs","currentMemoryBytes","logger","debug","stats","hits","misses","evictions","config","Map","Number","MAX_SAFE_INTEGER","info","maxMemoryMB","toFixed","get","key","entry","undefined","expiresAt","Date","delete","lastAccessed","sizeBytes","age","now","createdAt","getTime","value","set","ttlMs","existing","ttl","memoryUsageBytes","evictIfNeeded","memoryUtilization","has","clear","size","getStatistics","totalOps","hitRate","evictionRate","maxSize","resetStatistics","keys","Array","from","newEntrySizeBytes","evictLRU","oldestKey","oldestTime","entries","toISOString","cleanupExpired","removed","count"],"mappings":"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"}
|
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skill Content Manager
|
|
3
|
+
*
|
|
4
|
+
* Manages standardized skill content storage, organization, and versioning
|
|
5
|
+
* Enforces directory structure, validates required files, tracks versions
|
|
6
|
+
*
|
|
7
|
+
* @module skill-content-manager
|
|
8
|
+
* @version 1.0.0
|
|
9
|
+
*/ import { join, basename } from 'path';
|
|
10
|
+
import { stat, readdir, access, chmod, readFile, writeFile, mkdir } from 'fs/promises';
|
|
11
|
+
import { constants } from 'fs';
|
|
12
|
+
import { StandardError } from './errors.js';
|
|
13
|
+
import { parseFrontmatter, validateFrontmatter, parseAndValidate, updateFrontmatter, createSkillDocument } from './skill-frontmatter-parser.js';
|
|
14
|
+
import { calculateFileHash, getCommitMetadata, getVersionHistory, commitFile, hasUncommittedChanges, verifyContentIntegrity, getFileCreationDate, getFileModificationDate } from './skill-git-integration.js';
|
|
15
|
+
/**
|
|
16
|
+
* Required files in skill directory
|
|
17
|
+
*/ export const REQUIRED_SKILL_FILES = [
|
|
18
|
+
'SKILL.md',
|
|
19
|
+
'execute.sh',
|
|
20
|
+
'test.sh',
|
|
21
|
+
'validate.sh',
|
|
22
|
+
'package.json'
|
|
23
|
+
];
|
|
24
|
+
/**
|
|
25
|
+
* Skill content manager error
|
|
26
|
+
*/ export class SkillContentError extends StandardError {
|
|
27
|
+
context;
|
|
28
|
+
constructor(message, context){
|
|
29
|
+
super('SKILL_CONTENT_ERROR', message, context), this.context = context;
|
|
30
|
+
this.name = 'SkillContentError';
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Validate skill directory structure
|
|
35
|
+
*
|
|
36
|
+
* @param skillPath - Path to skill directory
|
|
37
|
+
* @returns Validation result with details
|
|
38
|
+
*/ export async function validateSkillStructure(skillPath) {
|
|
39
|
+
const skillName = basename(skillPath);
|
|
40
|
+
const missingFiles = [];
|
|
41
|
+
const invalidPermissions = [];
|
|
42
|
+
const errors = [];
|
|
43
|
+
const warnings = [];
|
|
44
|
+
try {
|
|
45
|
+
// Check if directory exists
|
|
46
|
+
const dirStat = await stat(skillPath);
|
|
47
|
+
if (!dirStat.isDirectory()) {
|
|
48
|
+
errors.push(`${skillPath} is not a directory`);
|
|
49
|
+
return {
|
|
50
|
+
valid: false,
|
|
51
|
+
skillName,
|
|
52
|
+
skillPath,
|
|
53
|
+
missingFiles,
|
|
54
|
+
invalidPermissions,
|
|
55
|
+
errors,
|
|
56
|
+
warnings
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
} catch (error) {
|
|
60
|
+
errors.push(`Skill directory does not exist: ${skillPath}`);
|
|
61
|
+
return {
|
|
62
|
+
valid: false,
|
|
63
|
+
skillName,
|
|
64
|
+
skillPath,
|
|
65
|
+
missingFiles,
|
|
66
|
+
invalidPermissions,
|
|
67
|
+
errors,
|
|
68
|
+
warnings
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
// Check required files
|
|
72
|
+
for (const fileName of REQUIRED_SKILL_FILES){
|
|
73
|
+
const filePath = join(skillPath, fileName);
|
|
74
|
+
try {
|
|
75
|
+
await access(filePath, constants.F_OK);
|
|
76
|
+
// Check execute permission for .sh files
|
|
77
|
+
if (fileName.endsWith('.sh')) {
|
|
78
|
+
try {
|
|
79
|
+
await access(filePath, constants.X_OK);
|
|
80
|
+
} catch {
|
|
81
|
+
invalidPermissions.push(fileName);
|
|
82
|
+
errors.push(`${fileName} is not executable`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
} catch {
|
|
86
|
+
missingFiles.push(fileName);
|
|
87
|
+
errors.push(`Required file missing: ${fileName}`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// Validate SKILL.md frontmatter if exists
|
|
91
|
+
const skillMdPath = join(skillPath, 'SKILL.md');
|
|
92
|
+
try {
|
|
93
|
+
await access(skillMdPath, constants.F_OK);
|
|
94
|
+
const content = await readFile(skillMdPath, 'utf-8');
|
|
95
|
+
try {
|
|
96
|
+
const parsed = parseFrontmatter(content);
|
|
97
|
+
const validation = validateFrontmatter(parsed.frontmatter);
|
|
98
|
+
if (!validation.valid) {
|
|
99
|
+
errors.push(...validation.errors);
|
|
100
|
+
}
|
|
101
|
+
warnings.push(...validation.warnings);
|
|
102
|
+
} catch (error) {
|
|
103
|
+
errors.push(`SKILL.md frontmatter error: ${error instanceof Error ? error.message : String(error)}`);
|
|
104
|
+
}
|
|
105
|
+
} catch {
|
|
106
|
+
// Already reported as missing file
|
|
107
|
+
}
|
|
108
|
+
return {
|
|
109
|
+
valid: errors.length === 0,
|
|
110
|
+
skillName,
|
|
111
|
+
skillPath,
|
|
112
|
+
missingFiles,
|
|
113
|
+
invalidPermissions,
|
|
114
|
+
errors,
|
|
115
|
+
warnings
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Fix skill file permissions
|
|
120
|
+
*
|
|
121
|
+
* @param skillPath - Path to skill directory
|
|
122
|
+
* @returns Array of files that were fixed
|
|
123
|
+
*/ export async function fixSkillPermissions(skillPath) {
|
|
124
|
+
const fixed = [];
|
|
125
|
+
for (const fileName of REQUIRED_SKILL_FILES){
|
|
126
|
+
if (fileName.endsWith('.sh')) {
|
|
127
|
+
const filePath = join(skillPath, fileName);
|
|
128
|
+
try {
|
|
129
|
+
await access(filePath, constants.F_OK);
|
|
130
|
+
await chmod(filePath, 0o755); // rwxr-xr-x
|
|
131
|
+
fixed.push(fileName);
|
|
132
|
+
} catch {
|
|
133
|
+
// File doesn't exist, skip
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return fixed;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Load skill metadata with git integration
|
|
141
|
+
*
|
|
142
|
+
* @param skillPath - Path to skill directory
|
|
143
|
+
* @param includeHistory - Include version history (default: false)
|
|
144
|
+
* @returns Complete skill metadata
|
|
145
|
+
*/ export async function loadSkillMetadata(skillPath, includeHistory = false) {
|
|
146
|
+
const skillMdPath = join(skillPath, 'SKILL.md');
|
|
147
|
+
try {
|
|
148
|
+
// Read and parse SKILL.md
|
|
149
|
+
const content = await readFile(skillMdPath, 'utf-8');
|
|
150
|
+
const parsed = parseAndValidate(content);
|
|
151
|
+
// Calculate content hash
|
|
152
|
+
const contentHash = calculateFileHash(skillMdPath);
|
|
153
|
+
// Get git metadata (graceful fallback if not in git repo)
|
|
154
|
+
let gitMetadata;
|
|
155
|
+
let versionHistory;
|
|
156
|
+
let hasChanges;
|
|
157
|
+
let fileCreated;
|
|
158
|
+
let fileModified;
|
|
159
|
+
try {
|
|
160
|
+
gitMetadata = await getCommitMetadata(skillMdPath);
|
|
161
|
+
hasChanges = await hasUncommittedChanges(skillMdPath);
|
|
162
|
+
fileCreated = await getFileCreationDate(skillMdPath);
|
|
163
|
+
fileModified = await getFileModificationDate(skillMdPath);
|
|
164
|
+
if (includeHistory) {
|
|
165
|
+
versionHistory = await getVersionHistory(skillMdPath);
|
|
166
|
+
}
|
|
167
|
+
} catch {
|
|
168
|
+
// Not in git repo or no git history - continue without git data
|
|
169
|
+
}
|
|
170
|
+
return {
|
|
171
|
+
...parsed.frontmatter,
|
|
172
|
+
skillPath,
|
|
173
|
+
contentHash: await contentHash,
|
|
174
|
+
gitMetadata,
|
|
175
|
+
versionHistory,
|
|
176
|
+
hasUncommittedChanges: hasChanges,
|
|
177
|
+
fileCreated,
|
|
178
|
+
fileModified
|
|
179
|
+
};
|
|
180
|
+
} catch (error) {
|
|
181
|
+
throw new SkillContentError(`Failed to load skill metadata from ${skillPath}`, {
|
|
182
|
+
error: error instanceof Error ? error.message : String(error)
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Update skill frontmatter
|
|
188
|
+
*
|
|
189
|
+
* @param skillPath - Path to skill directory
|
|
190
|
+
* @param updates - Partial frontmatter updates
|
|
191
|
+
* @param options - Update options
|
|
192
|
+
* @returns Updated skill metadata
|
|
193
|
+
*/ export async function updateSkillFrontmatter(skillPath, updates, options = {}) {
|
|
194
|
+
const { autoCommit = false, commitMessage, updateTimestamp = true, validateStructure = true } = options;
|
|
195
|
+
const skillMdPath = join(skillPath, 'SKILL.md');
|
|
196
|
+
try {
|
|
197
|
+
// Validate structure first if requested
|
|
198
|
+
if (validateStructure) {
|
|
199
|
+
const validation = await validateSkillStructure(skillPath);
|
|
200
|
+
if (!validation.valid) {
|
|
201
|
+
throw new SkillContentError('Skill structure validation failed', {
|
|
202
|
+
errors: validation.errors
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
// Read current content
|
|
207
|
+
const currentContent = await readFile(skillMdPath, 'utf-8');
|
|
208
|
+
// Update frontmatter
|
|
209
|
+
const updatedContent = updateFrontmatter(currentContent, updates);
|
|
210
|
+
// Write updated content
|
|
211
|
+
await writeFile(skillMdPath, updatedContent, 'utf-8');
|
|
212
|
+
// Auto-commit if requested
|
|
213
|
+
if (autoCommit) {
|
|
214
|
+
const message = commitMessage || `Update ${basename(skillPath)} frontmatter`;
|
|
215
|
+
await commitFile(skillMdPath, message);
|
|
216
|
+
}
|
|
217
|
+
// Return updated metadata
|
|
218
|
+
return await loadSkillMetadata(skillPath);
|
|
219
|
+
} catch (error) {
|
|
220
|
+
throw new SkillContentError(`Failed to update skill frontmatter for ${skillPath}`, {
|
|
221
|
+
error: error instanceof Error ? error.message : String(error)
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Create new skill directory with standard structure
|
|
227
|
+
*
|
|
228
|
+
* @param parentDir - Parent directory for skills
|
|
229
|
+
* @param skillName - Name of skill to create
|
|
230
|
+
* @param frontmatter - Initial frontmatter
|
|
231
|
+
* @param content - Initial SKILL.md content
|
|
232
|
+
* @returns Created skill metadata
|
|
233
|
+
*/ export async function createSkill(parentDir, skillName, frontmatter, content = '') {
|
|
234
|
+
const skillPath = join(parentDir, skillName);
|
|
235
|
+
try {
|
|
236
|
+
// Create skill directory
|
|
237
|
+
await mkdir(skillPath, {
|
|
238
|
+
recursive: true
|
|
239
|
+
});
|
|
240
|
+
// Create SKILL.md
|
|
241
|
+
const skillMdPath = join(skillPath, 'SKILL.md');
|
|
242
|
+
const skillDocument = createSkillDocument(frontmatter, content);
|
|
243
|
+
await writeFile(skillMdPath, skillDocument, 'utf-8');
|
|
244
|
+
// Create placeholder files
|
|
245
|
+
const executeSh = `#!/bin/bash
|
|
246
|
+
# ${frontmatter.name} - Execution Script
|
|
247
|
+
# Version: ${frontmatter.version}
|
|
248
|
+
|
|
249
|
+
set -euo pipefail
|
|
250
|
+
|
|
251
|
+
echo "Executing ${frontmatter.name}..."
|
|
252
|
+
# Add implementation here
|
|
253
|
+
`;
|
|
254
|
+
const testSh = `#!/bin/bash
|
|
255
|
+
# ${frontmatter.name} - Test Script
|
|
256
|
+
# Version: ${frontmatter.version}
|
|
257
|
+
|
|
258
|
+
set -euo pipefail
|
|
259
|
+
|
|
260
|
+
echo "Testing ${frontmatter.name}..."
|
|
261
|
+
# Add tests here
|
|
262
|
+
`;
|
|
263
|
+
const validateSh = `#!/bin/bash
|
|
264
|
+
# ${frontmatter.name} - Validation Script
|
|
265
|
+
# Version: ${frontmatter.version}
|
|
266
|
+
|
|
267
|
+
set -euo pipefail
|
|
268
|
+
|
|
269
|
+
echo "Validating ${frontmatter.name}..."
|
|
270
|
+
# Add validation here
|
|
271
|
+
`;
|
|
272
|
+
const packageJson = {
|
|
273
|
+
name: skillName,
|
|
274
|
+
version: frontmatter.version,
|
|
275
|
+
description: frontmatter.description,
|
|
276
|
+
scripts: {
|
|
277
|
+
execute: './execute.sh',
|
|
278
|
+
test: './test.sh',
|
|
279
|
+
validate: './validate.sh'
|
|
280
|
+
}
|
|
281
|
+
};
|
|
282
|
+
await writeFile(join(skillPath, 'execute.sh'), executeSh, 'utf-8');
|
|
283
|
+
await writeFile(join(skillPath, 'test.sh'), testSh, 'utf-8');
|
|
284
|
+
await writeFile(join(skillPath, 'validate.sh'), validateSh, 'utf-8');
|
|
285
|
+
await writeFile(join(skillPath, 'package.json'), JSON.stringify(packageJson, null, 2), 'utf-8');
|
|
286
|
+
// Fix permissions
|
|
287
|
+
await fixSkillPermissions(skillPath);
|
|
288
|
+
// Return metadata
|
|
289
|
+
return await loadSkillMetadata(skillPath);
|
|
290
|
+
} catch (error) {
|
|
291
|
+
throw new SkillContentError(`Failed to create skill ${skillName}`, {
|
|
292
|
+
error: error instanceof Error ? error.message : String(error)
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Scan directory for all skills
|
|
298
|
+
*
|
|
299
|
+
* @param skillsDir - Path to skills directory
|
|
300
|
+
* @returns Array of skill paths
|
|
301
|
+
*/ export async function scanSkills(skillsDir) {
|
|
302
|
+
try {
|
|
303
|
+
const entries = await readdir(skillsDir, {
|
|
304
|
+
withFileTypes: true
|
|
305
|
+
});
|
|
306
|
+
const skillPaths = [];
|
|
307
|
+
for (const entry of entries){
|
|
308
|
+
if (entry.isDirectory()) {
|
|
309
|
+
const skillPath = join(skillsDir, entry.name);
|
|
310
|
+
const skillMdPath = join(skillPath, 'SKILL.md');
|
|
311
|
+
try {
|
|
312
|
+
await access(skillMdPath, constants.F_OK);
|
|
313
|
+
skillPaths.push(skillPath);
|
|
314
|
+
} catch {
|
|
315
|
+
// Not a valid skill directory, skip
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
return skillPaths.sort();
|
|
320
|
+
} catch (error) {
|
|
321
|
+
throw new SkillContentError(`Failed to scan skills directory ${skillsDir}`, {
|
|
322
|
+
error: error instanceof Error ? error.message : String(error)
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* Verify skill content integrity
|
|
328
|
+
*
|
|
329
|
+
* @param skillPath - Path to skill directory
|
|
330
|
+
* @param expectedHash - Expected content hash
|
|
331
|
+
* @returns True if content matches expected hash
|
|
332
|
+
*/ export async function verifySkillIntegrity(skillPath, expectedHash) {
|
|
333
|
+
const skillMdPath = join(skillPath, 'SKILL.md');
|
|
334
|
+
return await verifyContentIntegrity(skillMdPath, expectedHash);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
//# sourceMappingURL=skill-content-manager.js.map
|