@howlil/ez-agents 3.4.2 → 4.0.0
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/README.md +735 -462
- package/agents/ez-architect-agent.md +267 -0
- package/agents/ez-backend-agent.md +303 -0
- package/agents/ez-chief-strategist.md +271 -0
- package/agents/ez-codebase-mapper.md +770 -770
- package/agents/ez-context-manager.md +319 -0
- package/agents/ez-debugger.md +1255 -1255
- package/agents/ez-design-expert.md +347 -0
- package/agents/ez-devops-agent.md +331 -0
- package/agents/ez-executor.md +487 -487
- package/agents/ez-frontend-agent.md +322 -0
- package/agents/ez-phase-researcher.md +553 -553
- package/agents/ez-planner.md +1307 -1307
- package/agents/ez-product-engineer.md +435 -0
- package/agents/ez-project-researcher.md +629 -629
- package/agents/ez-qa-agent.md +320 -0
- package/agents/ez-release-agent.md +333 -0
- package/agents/ez-requirements-agent.md +377 -0
- package/agents/ez-roadmapper.md +650 -650
- package/agents/ez-technical-writer.md +551 -0
- package/agents/ez-ux-expert.md +393 -0
- package/agents/ez-verifier.md +579 -579
- package/bin/guards/autonomy-guard.cjs +346 -0
- package/bin/guards/context-budget-guard.cjs +278 -0
- package/bin/guards/hallucination-guard.cjs +380 -0
- package/bin/guards/hidden-state-guard.cjs +182 -0
- package/bin/guards/team-overhead-guard.cjs +266 -0
- package/bin/guards/tool-sprawl-guard.cjs +271 -0
- package/bin/install.js +3221 -3272
- package/bin/lib/analytics/analytics-collector.cjs +86 -0
- package/bin/lib/analytics/analytics-reporter.cjs +130 -0
- package/bin/lib/analytics/cohort-analyzer.cjs +138 -0
- package/bin/lib/analytics/funnel-analyzer.cjs +147 -0
- package/bin/lib/analytics/nps-tracker.cjs +147 -0
- package/bin/lib/archetype-detector.cjs +289 -0
- package/bin/lib/assistant-adapter.cjs +361 -0
- package/bin/lib/audit-exec.cjs +175 -0
- package/bin/lib/auth.cjs +176 -0
- package/bin/lib/backup-service.cjs +422 -0
- package/bin/lib/bdd-validator.cjs +622 -0
- package/bin/lib/business-flow-mapper.cjs +429 -0
- package/bin/lib/circuit-breaker.cjs +276 -0
- package/bin/lib/code-complexity-analyzer.cjs +360 -0
- package/bin/lib/codebase-analyzer.cjs +241 -0
- package/bin/lib/commands.cjs +691 -0
- package/bin/lib/config.cjs +236 -0
- package/bin/lib/constraint-extractor.cjs +526 -0
- package/bin/lib/content-scanner.cjs +238 -0
- package/bin/lib/context-cache.cjs +154 -0
- package/bin/lib/context-compressor.cjs +102 -0
- package/bin/lib/context-deduplicator.cjs +105 -0
- package/bin/lib/context-errors.cjs +78 -0
- package/bin/lib/context-manager.cjs +338 -0
- package/bin/lib/context-metadata-tracker.cjs +140 -0
- package/bin/lib/context-relevance-scorer.cjs +99 -0
- package/bin/lib/core.cjs +507 -0
- package/bin/lib/cost-alerts.cjs +174 -0
- package/bin/lib/cost-tracker.cjs +275 -0
- package/bin/lib/crash-recovery.cjs +220 -0
- package/bin/lib/dependency-graph.cjs +319 -0
- package/bin/lib/deploy/deploy-audit-log.cjs +76 -0
- package/bin/lib/deploy/deploy-detector.cjs +69 -0
- package/bin/lib/deploy/deploy-env-manager.cjs +109 -0
- package/bin/lib/deploy/deploy-health-check.cjs +88 -0
- package/bin/lib/deploy/deploy-pre-flight.cjs +57 -0
- package/bin/lib/deploy/deploy-rollback.cjs +72 -0
- package/bin/lib/deploy/deploy-runner.cjs +97 -0
- package/bin/lib/deploy/deploy-status.cjs +74 -0
- package/bin/lib/discussion-synthesizer.cjs +439 -0
- package/bin/lib/error-cache.cjs +114 -0
- package/bin/lib/error-registry.cjs +177 -0
- package/bin/lib/file-access.cjs +207 -0
- package/bin/lib/file-lock.cjs +236 -0
- package/bin/lib/finops/budget-enforcer.cjs +126 -0
- package/bin/lib/finops/cost-reporter.cjs +132 -0
- package/bin/lib/finops/finops-analyzer.cjs +112 -0
- package/bin/lib/finops/spot-manager.cjs +118 -0
- package/bin/lib/framework-detector.cjs +396 -0
- package/bin/lib/frontmatter.cjs +313 -0
- package/bin/lib/fs-utils.cjs +153 -0
- package/bin/lib/gate-executor.cjs +272 -0
- package/bin/lib/gates/README.md +374 -0
- package/bin/lib/gates/gate-01-requirement.cjs +303 -0
- package/bin/lib/gates/gate-02-architecture.cjs +555 -0
- package/bin/lib/gates/gate-03-code.cjs +635 -0
- package/bin/lib/gates/gate-04-security.cjs +829 -0
- package/bin/lib/git-errors.cjs +83 -0
- package/bin/lib/git-utils.cjs +321 -0
- package/bin/lib/git-workflow-engine.cjs +1157 -0
- package/bin/lib/health-check.cjs +227 -0
- package/bin/lib/index.cjs +279 -0
- package/bin/lib/init.cjs +725 -0
- package/bin/lib/lock-logger.cjs +194 -0
- package/bin/lib/lock-state.cjs +263 -0
- package/bin/lib/lockfile-validator.cjs +227 -0
- package/bin/lib/log-rotation.cjs +71 -0
- package/bin/lib/logger.cjs +125 -0
- package/bin/lib/memory-compression.cjs +256 -0
- package/bin/lib/milestone.cjs +247 -0
- package/bin/lib/model-provider.cjs +241 -0
- package/bin/lib/package-manager-detector.cjs +203 -0
- package/bin/lib/package-manager-executor.cjs +385 -0
- package/bin/lib/package-manager-service.cjs +216 -0
- package/bin/lib/perf/api-monitor.cjs +88 -0
- package/bin/lib/perf/db-optimizer.cjs +78 -0
- package/bin/lib/perf/frontend-performance.cjs +56 -0
- package/bin/lib/perf/perf-analyzer.cjs +77 -0
- package/bin/lib/perf/perf-baseline.cjs +102 -0
- package/bin/lib/perf/perf-reporter.cjs +117 -0
- package/bin/lib/perf/regression-detector.cjs +92 -0
- package/bin/lib/phase.cjs +963 -0
- package/bin/lib/planning-write.cjs +123 -0
- package/bin/lib/project-reporter.cjs +565 -0
- package/bin/lib/quality-gate.cjs +332 -0
- package/bin/lib/quality-metrics.cjs +324 -0
- package/bin/lib/recovery-manager.cjs +98 -0
- package/bin/lib/release-validator.cjs +617 -0
- package/bin/lib/retry.cjs +119 -0
- package/bin/lib/roadmap.cjs +309 -0
- package/bin/lib/safe-exec.cjs +173 -0
- package/bin/lib/safe-path.cjs +130 -0
- package/bin/lib/security-errors.cjs +62 -0
- package/bin/lib/session-chain.cjs +304 -0
- package/bin/lib/session-errors.cjs +81 -0
- package/bin/lib/session-export.cjs +251 -0
- package/bin/lib/session-import.cjs +262 -0
- package/bin/lib/session-manager.cjs +280 -0
- package/bin/lib/skill-context.cjs +148 -0
- package/bin/lib/skill-matcher.cjs +236 -0
- package/bin/lib/skill-registry.cjs +360 -0
- package/bin/lib/skill-resolver.cjs +449 -0
- package/bin/lib/skill-triggers.cjs +90 -0
- package/bin/lib/skill-validator.cjs +270 -0
- package/bin/lib/skill-versioning.cjs +355 -0
- package/bin/lib/stack-detector.cjs +399 -0
- package/bin/lib/state.cjs +736 -0
- package/bin/lib/tech-debt-analyzer.cjs +309 -0
- package/bin/lib/temp-file.cjs +239 -0
- package/bin/lib/template.cjs +223 -0
- package/bin/lib/test-file-lock.cjs +112 -0
- package/bin/lib/test-graceful.cjs +93 -0
- package/bin/lib/test-logger.cjs +60 -0
- package/bin/lib/test-safe-exec.cjs +38 -0
- package/bin/lib/test-safe-path.cjs +33 -0
- package/bin/lib/test-temp-file.cjs +125 -0
- package/bin/lib/tier-manager.cjs +428 -0
- package/bin/lib/timeout-exec.cjs +63 -0
- package/bin/lib/tradeoff-analyzer.cjs +284 -0
- package/bin/lib/url-fetch.cjs +170 -0
- package/bin/lib/verify.cjs +863 -0
- package/bin/update.js +217 -214
- package/commands/deploy.cjs +53 -0
- package/commands/ez/add-tests.md +41 -41
- package/commands/ez/audit-milestone.md +36 -36
- package/commands/ez/complete-milestone.md +136 -136
- package/commands/ez/discuss-phase.md +90 -90
- package/commands/ez/execute-phase.md +52 -41
- package/commands/ez/help.md +22 -22
- package/commands/ez/map-codebase.md +71 -71
- package/commands/ez/new-milestone.md +44 -44
- package/commands/ez/new-project.md +51 -42
- package/commands/ez/plan-phase.md +53 -45
- package/commands/ez/progress.md +36 -24
- package/commands/ez/quick.md +45 -45
- package/commands/ez/resume-work.md +40 -40
- package/commands/ez/run-phase.md +580 -0
- package/commands/ez/settings.md +36 -36
- package/commands/ez/update.md +37 -37
- package/commands/ez/verify-work.md +402 -38
- package/commands/health-check.cjs +44 -0
- package/commands/rollback.cjs +47 -0
- package/ez-agents/bin/ez-tools.cjs +1692 -716
- package/ez-agents/bin/guards/autonomy-guard.cjs +346 -0
- package/ez-agents/bin/guards/context-budget-guard.cjs +247 -0
- package/ez-agents/bin/guards/hallucination-guard.cjs +271 -0
- package/ez-agents/bin/guards/hidden-state-guard.cjs +182 -0
- package/ez-agents/bin/guards/team-overhead-guard.cjs +266 -0
- package/ez-agents/bin/guards/tool-sprawl-guard.cjs +271 -0
- package/ez-agents/bin/lib/analytics/analytics-collector.cjs +86 -0
- package/ez-agents/bin/lib/analytics/analytics-reporter.cjs +130 -0
- package/ez-agents/bin/lib/analytics/cohort-analyzer.cjs +138 -0
- package/ez-agents/bin/lib/analytics/funnel-analyzer.cjs +147 -0
- package/ez-agents/bin/lib/analytics/nps-tracker.cjs +147 -0
- package/ez-agents/bin/lib/archetype-detector.cjs +289 -0
- package/ez-agents/bin/lib/audit-exec.cjs +166 -167
- package/ez-agents/bin/lib/auth.cjs +176 -176
- package/ez-agents/bin/lib/backup-service.cjs +422 -0
- package/ez-agents/bin/lib/bdd-validator.cjs +622 -0
- package/ez-agents/bin/lib/business-flow-mapper.cjs +429 -0
- package/ez-agents/bin/lib/code-complexity-analyzer.cjs +360 -0
- package/ez-agents/bin/lib/codebase-analyzer.cjs +241 -0
- package/ez-agents/bin/lib/commands.cjs +685 -685
- package/ez-agents/bin/lib/config.cjs +41 -1
- package/ez-agents/bin/lib/constraint-extractor.cjs +526 -0
- package/ez-agents/bin/lib/content-scanner.cjs +238 -0
- package/ez-agents/bin/lib/context-cache.cjs +154 -0
- package/ez-agents/bin/lib/context-errors.cjs +71 -0
- package/ez-agents/bin/lib/context-manager.cjs +220 -0
- package/ez-agents/bin/lib/core.cjs +507 -512
- package/ez-agents/bin/lib/cost-tracker.cjs +243 -0
- package/ez-agents/bin/lib/crash-recovery.cjs +172 -0
- package/ez-agents/bin/lib/dependency-graph.cjs +319 -0
- package/ez-agents/bin/lib/deploy/deploy-audit-log.cjs +76 -0
- package/ez-agents/bin/lib/deploy/deploy-detector.cjs +69 -0
- package/ez-agents/bin/lib/deploy/deploy-env-manager.cjs +109 -0
- package/ez-agents/bin/lib/deploy/deploy-health-check.cjs +88 -0
- package/ez-agents/bin/lib/deploy/deploy-pre-flight.cjs +57 -0
- package/ez-agents/bin/lib/deploy/deploy-rollback.cjs +72 -0
- package/ez-agents/bin/lib/deploy/deploy-runner.cjs +97 -0
- package/ez-agents/bin/lib/deploy/deploy-status.cjs +74 -0
- package/ez-agents/bin/lib/discussion-synthesizer.cjs +458 -0
- package/ez-agents/bin/lib/file-access.cjs +207 -0
- package/ez-agents/bin/lib/finops/budget-enforcer.cjs +126 -0
- package/ez-agents/bin/lib/finops/cost-reporter.cjs +132 -0
- package/ez-agents/bin/lib/finops/finops-analyzer.cjs +112 -0
- package/ez-agents/bin/lib/finops/spot-manager.cjs +118 -0
- package/ez-agents/bin/lib/framework-detector.cjs +396 -0
- package/ez-agents/bin/lib/frontmatter.cjs +3 -1
- package/ez-agents/bin/lib/gates/README.md +374 -0
- package/ez-agents/bin/lib/gates/gate-01-requirement.cjs +303 -0
- package/ez-agents/bin/lib/gates/gate-02-architecture.cjs +555 -0
- package/ez-agents/bin/lib/gates/gate-03-code.cjs +635 -0
- package/ez-agents/bin/lib/gates/gate-04-security.cjs +829 -0
- package/ez-agents/bin/lib/git-errors.cjs +83 -0
- package/ez-agents/bin/lib/git-utils.cjs +118 -0
- package/ez-agents/bin/lib/git-workflow-engine.cjs +1157 -0
- package/ez-agents/bin/lib/health-check.cjs +162 -162
- package/ez-agents/bin/lib/index.cjs +40 -2
- package/ez-agents/bin/lib/init.cjs +0 -2
- package/ez-agents/bin/lib/lockfile-validator.cjs +227 -0
- package/ez-agents/bin/lib/log-rotation.cjs +71 -0
- package/ez-agents/bin/lib/logger.cjs +99 -154
- package/ez-agents/bin/lib/memory-compression.cjs +256 -0
- package/ez-agents/bin/lib/package-manager-detector.cjs +203 -0
- package/ez-agents/bin/lib/package-manager-executor.cjs +385 -0
- package/ez-agents/bin/lib/package-manager-service.cjs +216 -0
- package/ez-agents/bin/lib/perf/api-monitor.cjs +88 -0
- package/ez-agents/bin/lib/perf/db-optimizer.cjs +78 -0
- package/ez-agents/bin/lib/perf/frontend-performance.cjs +56 -0
- package/ez-agents/bin/lib/perf/perf-analyzer.cjs +77 -0
- package/ez-agents/bin/lib/perf/perf-baseline.cjs +102 -0
- package/ez-agents/bin/lib/perf/perf-reporter.cjs +117 -0
- package/ez-agents/bin/lib/perf/regression-detector.cjs +92 -0
- package/ez-agents/bin/lib/project-reporter.cjs +502 -0
- package/ez-agents/bin/lib/quality-gate.cjs +332 -0
- package/ez-agents/bin/lib/recovery-manager.cjs +98 -0
- package/ez-agents/bin/lib/release-validator.cjs +617 -0
- package/ez-agents/bin/lib/safe-exec.cjs +128 -214
- package/ez-agents/bin/lib/security-errors.cjs +62 -0
- package/ez-agents/bin/lib/session-chain.cjs +304 -0
- package/ez-agents/bin/lib/session-errors.cjs +81 -0
- package/ez-agents/bin/lib/session-export.cjs +251 -0
- package/ez-agents/bin/lib/session-import.cjs +262 -0
- package/ez-agents/bin/lib/session-manager.cjs +280 -0
- package/ez-agents/bin/lib/skill-context.cjs +148 -0
- package/ez-agents/bin/lib/skill-matcher.cjs +236 -0
- package/ez-agents/bin/lib/skill-registry.cjs +341 -0
- package/ez-agents/bin/lib/skill-resolver.cjs +449 -0
- package/ez-agents/bin/lib/skill-triggers.cjs +90 -0
- package/ez-agents/bin/lib/skill-validator.cjs +270 -0
- package/ez-agents/bin/lib/skill-versioning.cjs +355 -0
- package/ez-agents/bin/lib/stack-detector.cjs +399 -0
- package/ez-agents/bin/lib/tech-debt-analyzer.cjs +309 -0
- package/ez-agents/bin/lib/tier-manager.cjs +428 -0
- package/ez-agents/bin/lib/tradeoff-analyzer.cjs +284 -0
- package/ez-agents/bin/lib/url-fetch.cjs +170 -0
- package/ez-agents/bin/lib/verify.cjs +863 -863
- package/ez-agents/references/decimal-phase-calculation.md +65 -65
- package/ez-agents/references/git-integration.md +248 -248
- package/ez-agents/references/git-planning-commit.md +38 -38
- package/ez-agents/references/metrics-schema.md +118 -0
- package/ez-agents/references/model-profile-resolution.md +34 -34
- package/ez-agents/references/model-profiles.md +93 -93
- package/ez-agents/references/phase-argument-parsing.md +61 -61
- package/ez-agents/references/planning-config.md +340 -200
- package/ez-agents/references/tier-strategy.md +103 -0
- package/ez-agents/references/ui-brand.md +160 -160
- package/ez-agents/references/verification-patterns.md +612 -612
- package/ez-agents/templates/DEBUG.md +164 -164
- package/ez-agents/templates/UAT.md +247 -247
- package/ez-agents/templates/agent-output-format.md +404 -0
- package/ez-agents/templates/bdd-feature.md +173 -0
- package/ez-agents/templates/codebase/architecture.md +255 -255
- package/ez-agents/templates/codebase/structure.md +285 -285
- package/ez-agents/templates/copilot-instructions.md +7 -7
- package/ez-agents/templates/debug-subagent-prompt.md +91 -91
- package/ez-agents/templates/discovery.md +146 -146
- package/ez-agents/templates/discussion.md +68 -0
- package/ez-agents/templates/handoff-protocol.md +294 -0
- package/ez-agents/templates/incident-runbook.md +205 -0
- package/ez-agents/templates/mode-workflow-templates.md +301 -0
- package/ez-agents/templates/phase-prompt.md +610 -610
- package/ez-agents/templates/planner-subagent-prompt.md +117 -117
- package/ez-agents/templates/project.md +184 -184
- package/ez-agents/templates/release-checklist.md +136 -0
- package/ez-agents/templates/research.md +552 -552
- package/ez-agents/templates/rollback-plan.md +201 -0
- package/ez-agents/templates/security-user-setup.md +244 -0
- package/ez-agents/templates/skill-validation-rules.md +476 -0
- package/ez-agents/templates/state.md +180 -176
- package/ez-agents/templates/summary-complex.md +59 -59
- package/ez-agents/tests/gates/gate-01-02.test.cjs +812 -0
- package/ez-agents/tests/gates/gate-03-04.test.cjs +762 -0
- package/ez-agents/tests/gates/gate-05-validator.test.cjs +145 -0
- package/ez-agents/tests/gates/gate-06-docs-validator.test.cjs +244 -0
- package/ez-agents/tests/gates/gate-07-release-validator.test.cjs +219 -0
- package/ez-agents/tests/guards/context-budget-guard.test.cjs +145 -0
- package/ez-agents/tests/guards/edge-case-guards.test.cjs +238 -0
- package/ez-agents/tests/guards/hallucination-guard.test.cjs +124 -0
- package/ez-agents/workflows/audit-milestone.md +1 -1
- package/ez-agents/workflows/autonomous.md +131 -30
- package/ez-agents/workflows/complete-milestone.md +1 -1
- package/ez-agents/workflows/discuss-phase.md +1 -1
- package/ez-agents/workflows/execute-phase.md +169 -3
- package/ez-agents/workflows/help.md +86 -133
- package/ez-agents/workflows/hotfix.md +291 -0
- package/ez-agents/workflows/new-milestone.md +340 -11
- package/ez-agents/workflows/new-project.md +294 -318
- package/ez-agents/workflows/plan-phase.md +22 -40
- package/ez-agents/workflows/progress.md +15 -25
- package/ez-agents/workflows/release.md +253 -0
- package/ez-agents/workflows/resume-session.md +215 -0
- package/ez-agents/workflows/run-phase.md +531 -0
- package/ez-agents/workflows/settings.md +2 -35
- package/hooks/dist/ez-check-update.js +81 -81
- package/hooks/dist/ez-context-monitor.js +148 -141
- package/hooks/dist/ez-statusline.js +115 -115
- package/package.json +78 -64
- package/scripts/fix-qwen-installation.js +144 -144
- package/agents/ez-integration-checker.md +0 -443
- package/agents/ez-nyquist-auditor.md +0 -176
- package/agents/ez-plan-checker.md +0 -706
- package/agents/ez-research-synthesizer.md +0 -247
- package/agents/ez-ui-auditor.md +0 -439
- package/agents/ez-ui-checker.md +0 -300
- package/agents/ez-ui-researcher.md +0 -353
- package/commands/ez/add-phase.md +0 -43
- package/commands/ez/add-todo.md +0 -47
- package/commands/ez/auth.md +0 -87
- package/commands/ez/autonomous.md +0 -41
- package/commands/ez/check-todos.md +0 -45
- package/commands/ez/cleanup.md +0 -18
- package/commands/ez/debug.md +0 -168
- package/commands/ez/health.md +0 -22
- package/commands/ez/insert-phase.md +0 -32
- package/commands/ez/join-discord.md +0 -18
- package/commands/ez/list-phase-assumptions.md +0 -46
- package/commands/ez/pause-work.md +0 -38
- package/commands/ez/plan-milestone-gaps.md +0 -34
- package/commands/ez/reapply-patches.md +0 -124
- package/commands/ez/remove-phase.md +0 -31
- package/commands/ez/research-phase.md +0 -190
- package/commands/ez/set-profile.md +0 -34
- package/commands/ez/stats.md +0 -18
- package/commands/ez/ui-phase.md +0 -34
- package/commands/ez/ui-review.md +0 -32
- package/commands/ez/validate-phase.md +0 -35
- package/ez-agents/templates/UI-SPEC.md +0 -100
- package/ez-agents/templates/VALIDATION.md +0 -76
- package/ez-agents/templates/context.md +0 -352
- package/ez-agents/templates/verification-report.md +0 -322
- package/ez-agents/workflows/research-phase.md +0 -74
- package/ez-agents/workflows/ui-phase.md +0 -290
- package/ez-agents/workflows/ui-review.md +0 -157
- package/ez-agents/workflows/validate-phase.md +0 -167
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Skill Matcher — Rule-based skill matching algorithm
|
|
5
|
+
*
|
|
6
|
+
* Matches context to skills using 5-rule matching:
|
|
7
|
+
* - Rule 1: Stack skills (mandatory, priority 100)
|
|
8
|
+
* - Rule 2: Domain skills (if project type detected, priority 90)
|
|
9
|
+
* - Rule 3: Mode skills (ceremony level, priority 85)
|
|
10
|
+
* - Rule 4: Constraint-based skills (deadline, team, compliance, priority 80)
|
|
11
|
+
* - Rule 5: Universal skills (always activate, priority 50)
|
|
12
|
+
*
|
|
13
|
+
* Enforces 3-7 skill limit per task (EDGE-05 compliance)
|
|
14
|
+
*
|
|
15
|
+
* Usage:
|
|
16
|
+
* const { SkillMatcher, SKILL_LIMITS } = require('./skill-matcher.cjs');
|
|
17
|
+
* const matcher = new SkillMatcher(registry);
|
|
18
|
+
* const result = matcher.match(context);
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
const Logger = require('./logger.cjs');
|
|
22
|
+
const logger = new Logger();
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Skill activation limits (EDGE-05 compliance)
|
|
26
|
+
*/
|
|
27
|
+
const SKILL_LIMITS = {
|
|
28
|
+
MIN_ACTIVE: 3,
|
|
29
|
+
MAX_ACTIVE: 7,
|
|
30
|
+
CRITICAL_TASK_MAX: 5, // For security-sensitive tasks
|
|
31
|
+
MVP_MODE_MAX: 4, // Rapid MVP mode reduces complexity
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Skill Matcher class for matching context to skills
|
|
36
|
+
*/
|
|
37
|
+
class SkillMatcher {
|
|
38
|
+
/**
|
|
39
|
+
* Create a SkillMatcher instance
|
|
40
|
+
* @param {Object} registry - SkillRegistry instance
|
|
41
|
+
* @param {Object} options - Matcher options
|
|
42
|
+
*/
|
|
43
|
+
constructor(registry, options = {}) {
|
|
44
|
+
this.registry = registry;
|
|
45
|
+
this.logger = options.logger || logger;
|
|
46
|
+
this.rules = this.loadMatchingRules();
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Match context to skills
|
|
51
|
+
* @param {Object} context - Matching context
|
|
52
|
+
* @returns {Object} Match result: { activatedSkills, rationale, conflicts, metadata }
|
|
53
|
+
*/
|
|
54
|
+
match(context) {
|
|
55
|
+
const candidates = [];
|
|
56
|
+
|
|
57
|
+
// Rule 1: Stack skills (mandatory)
|
|
58
|
+
if (context.stack?.framework || context.stack?.language) {
|
|
59
|
+
const stackSkills = this.findByStack(context.stack);
|
|
60
|
+
stackSkills.forEach(skill => {
|
|
61
|
+
candidates.push({ skill, priority: 100, rule: 'stack' });
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Rule 2: Domain skills (if project type detected)
|
|
66
|
+
if (context.projectType) {
|
|
67
|
+
const domainSkills = this.findByDomain(context.projectType);
|
|
68
|
+
domainSkills.forEach(skill => {
|
|
69
|
+
candidates.push({ skill, priority: 90, rule: 'domain' });
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Rule 3: Mode skills (ceremony level)
|
|
74
|
+
if (context.mode) {
|
|
75
|
+
const modeSkills = this.findByMode(context.mode);
|
|
76
|
+
modeSkills.forEach(skill => {
|
|
77
|
+
candidates.push({ skill, priority: 85, rule: 'mode' });
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Rule 4: Constraint-based skills
|
|
82
|
+
const constraintSkills = this.findByConstraints(context.constraints);
|
|
83
|
+
constraintSkills.forEach(skill => {
|
|
84
|
+
candidates.push({ skill, priority: 80, rule: 'constraint' });
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
// Rule 5: Universal skills (always activate)
|
|
88
|
+
const universalSkills = this.registry.findByTag('universal');
|
|
89
|
+
universalSkills.forEach(skill => {
|
|
90
|
+
candidates.push({ skill, priority: 50, rule: 'universal' });
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
// Sort by priority and apply limits
|
|
94
|
+
const sorted = candidates.sort((a, b) => b.priority - a.priority);
|
|
95
|
+
const limited = this.enforceSkillLimits(sorted, context);
|
|
96
|
+
const activatedSkills = limited.map(c => c.skill);
|
|
97
|
+
|
|
98
|
+
return {
|
|
99
|
+
activatedSkills,
|
|
100
|
+
rationale: this.generateRationale(activatedSkills, context),
|
|
101
|
+
conflicts: [], // Reserved for Phase 36 SKILL-07
|
|
102
|
+
metadata: {
|
|
103
|
+
totalCandidates: candidates.length,
|
|
104
|
+
rulesApplied: [...new Set(candidates.map(c => c.rule))],
|
|
105
|
+
limitEnforced: candidates.length > limited.length
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Enforce skill activation limits
|
|
112
|
+
* @param {Object[]} candidates - Sorted candidate skills
|
|
113
|
+
* @param {Object} context - Matching context
|
|
114
|
+
* @returns {Object[]} Limited candidate array
|
|
115
|
+
* @private
|
|
116
|
+
*/
|
|
117
|
+
enforceSkillLimits(candidates, context) {
|
|
118
|
+
const maxSkills = context.mode === 'rapid-mvp'
|
|
119
|
+
? SKILL_LIMITS.MVP_MODE_MAX
|
|
120
|
+
: SKILL_LIMITS.MAX_ACTIVE;
|
|
121
|
+
|
|
122
|
+
if (candidates.length > maxSkills) {
|
|
123
|
+
this.logger.warn('Skill limit exceeded', {
|
|
124
|
+
candidateCount: candidates.length,
|
|
125
|
+
maxSkills,
|
|
126
|
+
mode: context.mode,
|
|
127
|
+
skills: candidates.slice(0, maxSkills).map(c => c.skill.name)
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return candidates.slice(0, maxSkills);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Generate rationale for skill activation
|
|
136
|
+
* @param {Object[]} skills - Activated skills
|
|
137
|
+
* @param {Object} context - Matching context
|
|
138
|
+
* @returns {string} Rationale string
|
|
139
|
+
* @private
|
|
140
|
+
*/
|
|
141
|
+
generateRationale(skills, context) {
|
|
142
|
+
const categories = {};
|
|
143
|
+
skills.forEach(skill => {
|
|
144
|
+
const cat = skill.category || 'other';
|
|
145
|
+
if (!categories[cat]) categories[cat] = [];
|
|
146
|
+
categories[cat].push(skill.name);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
const parts = [];
|
|
150
|
+
if (categories.stack) parts.push(`stack: ${categories.stack.join(', ')}`);
|
|
151
|
+
if (categories.domain) parts.push(`domain: ${categories.domain.join(', ')}`);
|
|
152
|
+
if (categories.mode) parts.push(`mode: ${categories.mode.join(', ')}`);
|
|
153
|
+
if (categories.constraint) parts.push(`constraint: ${categories.constraint.join(', ')}`);
|
|
154
|
+
if (categories.universal) parts.push(`universal: ${categories.universal.join(', ')}`);
|
|
155
|
+
|
|
156
|
+
return `Activated ${skills.length} skills based on ${context.mode || 'default'} mode: ${parts.join('; ')}`;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Find skills by stack
|
|
161
|
+
* @param {Object|string} stack - Stack identifier
|
|
162
|
+
* @returns {Object[]} Matching skills
|
|
163
|
+
*/
|
|
164
|
+
findByStack(stack) {
|
|
165
|
+
return this.registry.findByStack(stack);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Find skills by domain/project type
|
|
170
|
+
* @param {string} projectType - Project type
|
|
171
|
+
* @returns {Object[]} Matching skills
|
|
172
|
+
*/
|
|
173
|
+
findByDomain(projectType) {
|
|
174
|
+
return this.registry.findByTag(projectType);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Find skills by mode
|
|
179
|
+
* @param {string} mode - Mode identifier
|
|
180
|
+
* @returns {Object[]} Matching skills
|
|
181
|
+
*/
|
|
182
|
+
findByMode(mode) {
|
|
183
|
+
return this.registry.findByTag(mode);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Find skills by constraints
|
|
188
|
+
* @param {Object} constraints - Constraint object
|
|
189
|
+
* @returns {Object[]} Matching skills
|
|
190
|
+
* @private
|
|
191
|
+
*/
|
|
192
|
+
findByConstraints(constraints) {
|
|
193
|
+
const skills = [];
|
|
194
|
+
if (!constraints) return skills;
|
|
195
|
+
|
|
196
|
+
// Deadline-based skills
|
|
197
|
+
if (constraints.deadline === '2-weeks' || constraints.deadline === '1-week') {
|
|
198
|
+
const rapid = this.registry.get('rapid_delivery_skill_v1');
|
|
199
|
+
if (rapid) skills.push(rapid);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Compliance-based skills
|
|
203
|
+
if (constraints.compliance?.includes('hipaa')) {
|
|
204
|
+
const hipaa = this.registry.get('hipaa_compliance_skill_v1');
|
|
205
|
+
if (hipaa) skills.push(hipaa);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Team size skills
|
|
209
|
+
if (constraints.teamSize === 1) {
|
|
210
|
+
const solo = this.registry.get('solo_developer_skill_v1');
|
|
211
|
+
if (solo) skills.push(solo);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
return skills;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Load matching rules configuration
|
|
219
|
+
* @returns {Object} Rules configuration
|
|
220
|
+
* @private
|
|
221
|
+
*/
|
|
222
|
+
loadMatchingRules() {
|
|
223
|
+
return {
|
|
224
|
+
stack: { priority: 100, required: true },
|
|
225
|
+
domain: { priority: 90, required: false },
|
|
226
|
+
mode: { priority: 85, required: false },
|
|
227
|
+
constraint: { priority: 80, required: false },
|
|
228
|
+
universal: { priority: 50, required: true }
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
module.exports = {
|
|
234
|
+
SkillMatcher,
|
|
235
|
+
SKILL_LIMITS
|
|
236
|
+
};
|
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Skill Registry — Core module for loading, indexing, and searching skills
|
|
5
|
+
*
|
|
6
|
+
* Provides file-based skill registry with:
|
|
7
|
+
* - Load skills from global and local directories
|
|
8
|
+
* - Get skill by name
|
|
9
|
+
* - Filter by tag, category, or stack
|
|
10
|
+
* - Search across name, description, and tags
|
|
11
|
+
* - Lazy loading with cache (LazySkillRegistry subclass)
|
|
12
|
+
*
|
|
13
|
+
* Usage:
|
|
14
|
+
* const { SkillRegistry, LazySkillRegistry } = require('./skill-registry.cjs');
|
|
15
|
+
* const registry = new SkillRegistry();
|
|
16
|
+
* await registry.load();
|
|
17
|
+
* const skill = registry.get('laravel_11_structure_skill_v2');
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
const fs = require('fs');
|
|
21
|
+
const path = require('path');
|
|
22
|
+
const { extractFrontmatter } = require('./frontmatter.cjs');
|
|
23
|
+
const { safeReadFile } = require('./safe-path.cjs');
|
|
24
|
+
const Logger = require('./logger.cjs');
|
|
25
|
+
const logger = new Logger();
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Skill Registry class for managing skills
|
|
29
|
+
*/
|
|
30
|
+
class SkillRegistry {
|
|
31
|
+
/**
|
|
32
|
+
* Create a SkillRegistry instance
|
|
33
|
+
* @param {Object} options - Registry options
|
|
34
|
+
* @param {string} options.globalPath - Global skills directory (default: skills/)
|
|
35
|
+
* @param {string} options.localPath - Local project skills directory (default: .planning/skills)
|
|
36
|
+
*/
|
|
37
|
+
constructor(options = {}) {
|
|
38
|
+
this.globalSkillsPath = options.globalPath || path.join(__dirname, '../../skills');
|
|
39
|
+
this.localSkillsPath = options.localPath || '.planning/skills';
|
|
40
|
+
this.skills = new Map();
|
|
41
|
+
this.loaded = false;
|
|
42
|
+
this.logger = logger;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Load skills from global and local directories
|
|
47
|
+
* @returns {Promise<SkillRegistry>} this for chaining
|
|
48
|
+
*/
|
|
49
|
+
async load() {
|
|
50
|
+
// Load global skills
|
|
51
|
+
await this._loadFromPath(this.globalSkillsPath, 'global');
|
|
52
|
+
|
|
53
|
+
// Load local project skills (override global)
|
|
54
|
+
if (fs.existsSync(this.localSkillsPath)) {
|
|
55
|
+
await this._loadFromPath(this.localSkillsPath, 'local');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
this.loaded = true;
|
|
59
|
+
this.logger.info('Skill registry loaded', {
|
|
60
|
+
skillCount: this.skills.size,
|
|
61
|
+
globalPath: this.globalSkillsPath,
|
|
62
|
+
localPath: this.localSkillsPath
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
return this;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Load skills from a specific path
|
|
70
|
+
* @param {string} basePath - Base directory to scan
|
|
71
|
+
* @param {string} scope - Scope identifier ('global' or 'local')
|
|
72
|
+
* @private
|
|
73
|
+
*/
|
|
74
|
+
_loadFromPath(basePath, scope) {
|
|
75
|
+
if (!fs.existsSync(basePath)) {
|
|
76
|
+
this.logger.debug('Skills path does not exist', { basePath });
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Read category directories
|
|
81
|
+
const categories = ['stack', 'architecture', 'domain', 'operational', 'governance'];
|
|
82
|
+
|
|
83
|
+
for (const category of categories) {
|
|
84
|
+
const categoryPath = path.join(basePath, category);
|
|
85
|
+
if (!fs.existsSync(categoryPath)) continue;
|
|
86
|
+
|
|
87
|
+
// Get skill group directories (e.g., 'laravel', 'react', etc.)
|
|
88
|
+
const skillGroups = fs.readdirSync(categoryPath, { withFileTypes: true })
|
|
89
|
+
.filter(d => d.isDirectory())
|
|
90
|
+
.map(d => d.name);
|
|
91
|
+
|
|
92
|
+
for (const group of skillGroups) {
|
|
93
|
+
const groupPath = path.join(categoryPath, group);
|
|
94
|
+
|
|
95
|
+
// Check for versioned skill directories within the group
|
|
96
|
+
const skillVersions = fs.readdirSync(groupPath, { withFileTypes: true })
|
|
97
|
+
.filter(d => d.isDirectory())
|
|
98
|
+
.map(d => d.name);
|
|
99
|
+
|
|
100
|
+
for (const versionDir of skillVersions) {
|
|
101
|
+
const skillPath = path.join(groupPath, versionDir, 'SKILL.md');
|
|
102
|
+
if (fs.existsSync(skillPath)) {
|
|
103
|
+
try {
|
|
104
|
+
const content = fs.readFileSync(skillPath, 'utf8');
|
|
105
|
+
const skill = this._parseSkill(skillPath, content, scope);
|
|
106
|
+
// Local skills override global skills with same name
|
|
107
|
+
this.skills.set(skill.name, skill);
|
|
108
|
+
} catch (err) {
|
|
109
|
+
this.logger.error('Failed to load skill', {
|
|
110
|
+
skillPath,
|
|
111
|
+
error: err.message
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Parse skill metadata from SKILL.md content
|
|
122
|
+
* @param {string} filePath - Path to SKILL.md file
|
|
123
|
+
* @param {string} content - File content
|
|
124
|
+
* @param {string} scope - Scope identifier
|
|
125
|
+
* @returns {Object} Parsed skill object
|
|
126
|
+
* @private
|
|
127
|
+
*/
|
|
128
|
+
_parseSkill(filePath, content, scope) {
|
|
129
|
+
const frontmatter = extractFrontmatter(content);
|
|
130
|
+
const body = content.replace(/^---[\s\S]+?\n---/, '').trim();
|
|
131
|
+
|
|
132
|
+
return {
|
|
133
|
+
name: frontmatter.name,
|
|
134
|
+
description: frontmatter.description,
|
|
135
|
+
version: frontmatter.version || '1.0.0',
|
|
136
|
+
tags: frontmatter.tags || [],
|
|
137
|
+
stack: frontmatter.stack,
|
|
138
|
+
category: frontmatter.category,
|
|
139
|
+
triggers: frontmatter.triggers,
|
|
140
|
+
prerequisites: frontmatter.prerequisites || [],
|
|
141
|
+
recommended_structure: frontmatter.recommended_structure,
|
|
142
|
+
workflow: frontmatter.workflow,
|
|
143
|
+
best_practices: frontmatter.best_practices || [],
|
|
144
|
+
anti_patterns: frontmatter.anti_patterns || [],
|
|
145
|
+
scaling_notes: frontmatter.scaling_notes,
|
|
146
|
+
when_not_to_use: frontmatter.when_not_to_use,
|
|
147
|
+
output_template: frontmatter.output_template,
|
|
148
|
+
dependencies: frontmatter.dependencies,
|
|
149
|
+
scope,
|
|
150
|
+
path: filePath,
|
|
151
|
+
body
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Get a skill by name
|
|
157
|
+
* @param {string} name - Skill name
|
|
158
|
+
* @returns {Object|undefined} Skill object or undefined
|
|
159
|
+
*/
|
|
160
|
+
get(name) {
|
|
161
|
+
return this.skills.get(name);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Get all skills
|
|
166
|
+
* @returns {Object[]} Array of all skill objects
|
|
167
|
+
*/
|
|
168
|
+
getAll() {
|
|
169
|
+
return Array.from(this.skills.values());
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Find skills by tag
|
|
174
|
+
* @param {string} tag - Tag to filter by
|
|
175
|
+
* @returns {Object[]} Array of matching skills
|
|
176
|
+
*/
|
|
177
|
+
findByTag(tag) {
|
|
178
|
+
return this.getAll().filter(s => s.tags?.includes(tag));
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Find skills by category
|
|
183
|
+
* @param {string} category - Category to filter by
|
|
184
|
+
* @returns {Object[]} Array of matching skills
|
|
185
|
+
*/
|
|
186
|
+
findByCategory(category) {
|
|
187
|
+
return this.getAll().filter(s => s.category === category);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Find skills by stack identifier
|
|
192
|
+
* @param {string|Object} stack - Stack identifier (string or object with language/framework)
|
|
193
|
+
* @returns {Object[]} Array of matching skills
|
|
194
|
+
*/
|
|
195
|
+
findByStack(stack) {
|
|
196
|
+
return this.getAll().filter(s => {
|
|
197
|
+
if (!s.stack) return false;
|
|
198
|
+
|
|
199
|
+
if (typeof stack === 'string') {
|
|
200
|
+
return s.stack === stack;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (typeof stack === 'object') {
|
|
204
|
+
// Support object format: { language: 'php', framework: 'laravel' }
|
|
205
|
+
const stackStr = `${stack.language}/${stack.framework}`;
|
|
206
|
+
return s.stack.includes(stackStr);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
return false;
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Search skills by keyword
|
|
215
|
+
* @param {string} query - Search query
|
|
216
|
+
* @returns {Object[]} Array of matching skills
|
|
217
|
+
*/
|
|
218
|
+
search(query) {
|
|
219
|
+
const q = query.toLowerCase();
|
|
220
|
+
return this.getAll().filter(s =>
|
|
221
|
+
s.name.toLowerCase().includes(q) ||
|
|
222
|
+
s.description.toLowerCase().includes(q) ||
|
|
223
|
+
s.tags?.some(t => t.toLowerCase().includes(q))
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Clear all loaded skills
|
|
229
|
+
*/
|
|
230
|
+
clear() {
|
|
231
|
+
this.skills.clear();
|
|
232
|
+
this.loaded = false;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Lazy Skill Registry with caching
|
|
238
|
+
* Extends SkillRegistry with TTL-based caching for better performance
|
|
239
|
+
*/
|
|
240
|
+
class LazySkillRegistry extends SkillRegistry {
|
|
241
|
+
/**
|
|
242
|
+
* Create a LazySkillRegistry instance
|
|
243
|
+
* @param {Object} options - Registry options
|
|
244
|
+
* @param {number} options.cacheTTL - Cache TTL in milliseconds (default: 5 minutes)
|
|
245
|
+
*/
|
|
246
|
+
constructor(options = {}) {
|
|
247
|
+
super(options);
|
|
248
|
+
this.cache = new Map();
|
|
249
|
+
this.cacheTTL = options.cacheTTL || 5 * 60 * 1000; // 5 minutes
|
|
250
|
+
this.cacheTimestamps = new Map();
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Get a skill by name with caching
|
|
255
|
+
* @param {string} name - Skill name
|
|
256
|
+
* @returns {Object|undefined} Skill object or undefined
|
|
257
|
+
*/
|
|
258
|
+
get(name) {
|
|
259
|
+
// Check cache first
|
|
260
|
+
const cached = this._getFromCache(name);
|
|
261
|
+
if (cached) {
|
|
262
|
+
return cached;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// Load from parent if not in cache
|
|
266
|
+
const skill = super.get(name);
|
|
267
|
+
if (skill) {
|
|
268
|
+
this._setInCache(name, skill);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
return skill;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Get all skills with caching
|
|
276
|
+
* @returns {Object[]} Array of all skill objects
|
|
277
|
+
*/
|
|
278
|
+
getAll() {
|
|
279
|
+
const cached = this._getFromCache('__all__');
|
|
280
|
+
if (cached) {
|
|
281
|
+
return cached;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
const skills = super.getAll();
|
|
285
|
+
this._setInCache('__all__', skills);
|
|
286
|
+
return skills;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Get item from cache with TTL check
|
|
291
|
+
* @param {string} key - Cache key
|
|
292
|
+
* @returns {any|null} Cached value or null if expired/missing
|
|
293
|
+
* @private
|
|
294
|
+
*/
|
|
295
|
+
_getFromCache(key) {
|
|
296
|
+
const timestamp = this.cacheTimestamps.get(key);
|
|
297
|
+
if (!timestamp) return null;
|
|
298
|
+
|
|
299
|
+
const age = Date.now() - timestamp;
|
|
300
|
+
if (age > this.cacheTTL) {
|
|
301
|
+
// Cache expired
|
|
302
|
+
this.cache.delete(key);
|
|
303
|
+
this.cacheTimestamps.delete(key);
|
|
304
|
+
return null;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
return this.cache.get(key);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Set item in cache with timestamp
|
|
312
|
+
* @param {string} key - Cache key
|
|
313
|
+
* @param {any} value - Value to cache
|
|
314
|
+
* @private
|
|
315
|
+
*/
|
|
316
|
+
_setInCache(key, value) {
|
|
317
|
+
this.cache.set(key, value);
|
|
318
|
+
this.cacheTimestamps.set(key, Date.now());
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Clear cache
|
|
323
|
+
*/
|
|
324
|
+
clearCache() {
|
|
325
|
+
this.cache.clear();
|
|
326
|
+
this.cacheTimestamps.clear();
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Clear all skills and cache
|
|
331
|
+
*/
|
|
332
|
+
clear() {
|
|
333
|
+
super.clear();
|
|
334
|
+
this.clearCache();
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
module.exports = {
|
|
339
|
+
SkillRegistry,
|
|
340
|
+
LazySkillRegistry
|
|
341
|
+
};
|