@djm204/agent-skills 1.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 +597 -0
- package/bin/cli.js +8 -0
- package/package.json +55 -0
- package/src/index.js +1817 -0
- package/src/index.test.js +1264 -0
- package/templates/_shared/code-quality.mdc +52 -0
- package/templates/_shared/communication.mdc +43 -0
- package/templates/_shared/core-principles.mdc +67 -0
- package/templates/_shared/git-workflow.mdc +48 -0
- package/templates/_shared/security-fundamentals.mdc +41 -0
- package/templates/agents/utility-agent/.cursor/rules/action-control.mdc +71 -0
- package/templates/agents/utility-agent/.cursor/rules/context-management.mdc +61 -0
- package/templates/agents/utility-agent/.cursor/rules/hallucination-prevention.mdc +58 -0
- package/templates/agents/utility-agent/.cursor/rules/overview.mdc +34 -0
- package/templates/agents/utility-agent/.cursor/rules/token-optimization.mdc +71 -0
- package/templates/agents/utility-agent/CLAUDE.md +513 -0
- package/templates/business/market-intelligence/.cursor/rules/data-sources.mdc +62 -0
- package/templates/business/market-intelligence/.cursor/rules/overview.mdc +55 -0
- package/templates/business/market-intelligence/.cursor/rules/reporting.mdc +59 -0
- package/templates/business/market-intelligence/.cursor/rules/risk-signals.mdc +63 -0
- package/templates/business/market-intelligence/.cursor/rules/sentiment-analysis.mdc +70 -0
- package/templates/business/market-intelligence/.cursor/rules/trend-detection.mdc +72 -0
- package/templates/business/market-intelligence/CLAUDE.md +371 -0
- package/templates/business/marketing-expert/.cursor/rules/brand-strategy.mdc +74 -0
- package/templates/business/marketing-expert/.cursor/rules/campaign-planning.mdc +60 -0
- package/templates/business/marketing-expert/.cursor/rules/growth-frameworks.mdc +69 -0
- package/templates/business/marketing-expert/.cursor/rules/market-analysis.mdc +70 -0
- package/templates/business/marketing-expert/.cursor/rules/marketing-analytics.mdc +71 -0
- package/templates/business/marketing-expert/.cursor/rules/overview.mdc +56 -0
- package/templates/business/marketing-expert/CLAUDE.md +567 -0
- package/templates/business/predictive-maintenance/.cursor/rules/alerting.mdc +56 -0
- package/templates/business/predictive-maintenance/.cursor/rules/asset-lifecycle.mdc +71 -0
- package/templates/business/predictive-maintenance/.cursor/rules/failure-prediction.mdc +65 -0
- package/templates/business/predictive-maintenance/.cursor/rules/maintenance-scheduling.mdc +61 -0
- package/templates/business/predictive-maintenance/.cursor/rules/overview.mdc +55 -0
- package/templates/business/predictive-maintenance/.cursor/rules/sensor-analytics.mdc +66 -0
- package/templates/business/predictive-maintenance/CLAUDE.md +529 -0
- package/templates/business/product-manager/.cursor/rules/communication.mdc +77 -0
- package/templates/business/product-manager/.cursor/rules/discovery.mdc +79 -0
- package/templates/business/product-manager/.cursor/rules/metrics.mdc +75 -0
- package/templates/business/product-manager/.cursor/rules/overview.mdc +47 -0
- package/templates/business/product-manager/.cursor/rules/prioritization.mdc +66 -0
- package/templates/business/product-manager/.cursor/rules/requirements.mdc +79 -0
- package/templates/business/product-manager/CLAUDE.md +593 -0
- package/templates/business/project-manager/.cursor/rules/overview.mdc +53 -0
- package/templates/business/project-manager/.cursor/rules/reporting.mdc +68 -0
- package/templates/business/project-manager/.cursor/rules/risk-management.mdc +71 -0
- package/templates/business/project-manager/.cursor/rules/scheduling.mdc +67 -0
- package/templates/business/project-manager/.cursor/rules/scope-management.mdc +66 -0
- package/templates/business/project-manager/.cursor/rules/stakeholder-management.mdc +70 -0
- package/templates/business/project-manager/CLAUDE.md +540 -0
- package/templates/business/regulatory-sentinel/.cursor/rules/compliance-tracking.mdc +74 -0
- package/templates/business/regulatory-sentinel/.cursor/rules/impact-assessment.mdc +62 -0
- package/templates/business/regulatory-sentinel/.cursor/rules/monitoring.mdc +67 -0
- package/templates/business/regulatory-sentinel/.cursor/rules/overview.mdc +55 -0
- package/templates/business/regulatory-sentinel/.cursor/rules/reporting.mdc +61 -0
- package/templates/business/regulatory-sentinel/.cursor/rules/risk-classification.mdc +73 -0
- package/templates/business/regulatory-sentinel/CLAUDE.md +572 -0
- package/templates/business/resource-allocator/.cursor/rules/capacity-modeling.mdc +65 -0
- package/templates/business/resource-allocator/.cursor/rules/coordination.mdc +67 -0
- package/templates/business/resource-allocator/.cursor/rules/crisis-management.mdc +64 -0
- package/templates/business/resource-allocator/.cursor/rules/demand-prediction.mdc +52 -0
- package/templates/business/resource-allocator/.cursor/rules/overview.mdc +76 -0
- package/templates/business/resource-allocator/.cursor/rules/scheduling.mdc +63 -0
- package/templates/business/resource-allocator/CLAUDE.md +525 -0
- package/templates/business/strategic-negotiator/.cursor/rules/contract-analysis.mdc +60 -0
- package/templates/business/strategic-negotiator/.cursor/rules/deal-structuring.mdc +66 -0
- package/templates/business/strategic-negotiator/.cursor/rules/game-theory.mdc +64 -0
- package/templates/business/strategic-negotiator/.cursor/rules/overview.mdc +55 -0
- package/templates/business/strategic-negotiator/.cursor/rules/preparation.mdc +79 -0
- package/templates/business/strategic-negotiator/.cursor/rules/scenario-modeling.mdc +66 -0
- package/templates/business/strategic-negotiator/CLAUDE.md +640 -0
- package/templates/business/supply-chain/.cursor/rules/cost-modeling.mdc +67 -0
- package/templates/business/supply-chain/.cursor/rules/demand-forecasting.mdc +67 -0
- package/templates/business/supply-chain/.cursor/rules/inventory-management.mdc +69 -0
- package/templates/business/supply-chain/.cursor/rules/logistics.mdc +61 -0
- package/templates/business/supply-chain/.cursor/rules/overview.mdc +64 -0
- package/templates/business/supply-chain/.cursor/rules/supplier-evaluation.mdc +66 -0
- package/templates/business/supply-chain/CLAUDE.md +590 -0
- package/templates/business/supply-chain-harmonizer/.cursor/rules/disruption-response.mdc +67 -0
- package/templates/business/supply-chain-harmonizer/.cursor/rules/inventory-rebalancing.mdc +63 -0
- package/templates/business/supply-chain-harmonizer/.cursor/rules/overview.mdc +65 -0
- package/templates/business/supply-chain-harmonizer/.cursor/rules/rerouting.mdc +64 -0
- package/templates/business/supply-chain-harmonizer/.cursor/rules/scenario-simulation.mdc +68 -0
- package/templates/business/supply-chain-harmonizer/.cursor/rules/stakeholder-notifications.mdc +61 -0
- package/templates/business/supply-chain-harmonizer/CLAUDE.md +600 -0
- package/templates/creative/brand-guardian/.cursor/rules/brand-voice.mdc +64 -0
- package/templates/creative/brand-guardian/.cursor/rules/content-review.mdc +47 -0
- package/templates/creative/brand-guardian/.cursor/rules/ethical-guidelines.mdc +47 -0
- package/templates/creative/brand-guardian/.cursor/rules/multi-channel.mdc +49 -0
- package/templates/creative/brand-guardian/.cursor/rules/overview.mdc +58 -0
- package/templates/creative/brand-guardian/.cursor/rules/visual-identity.mdc +64 -0
- package/templates/creative/brand-guardian/CLAUDE.md +634 -0
- package/templates/creative/content-creation-expert/.cursor/rules/content-strategy.mdc +65 -0
- package/templates/creative/content-creation-expert/.cursor/rules/copywriting.mdc +59 -0
- package/templates/creative/content-creation-expert/.cursor/rules/editorial-operations.mdc +65 -0
- package/templates/creative/content-creation-expert/.cursor/rules/multimedia-production.mdc +64 -0
- package/templates/creative/content-creation-expert/.cursor/rules/overview.mdc +58 -0
- package/templates/creative/content-creation-expert/.cursor/rules/seo-content.mdc +75 -0
- package/templates/creative/content-creation-expert/CLAUDE.md +568 -0
- package/templates/creative/narrative-architect/.cursor/rules/collaboration.mdc +62 -0
- package/templates/creative/narrative-architect/.cursor/rules/continuity-tracking.mdc +56 -0
- package/templates/creative/narrative-architect/.cursor/rules/overview.mdc +68 -0
- package/templates/creative/narrative-architect/.cursor/rules/story-bible.mdc +77 -0
- package/templates/creative/narrative-architect/.cursor/rules/timeline-management.mdc +60 -0
- package/templates/creative/narrative-architect/.cursor/rules/world-building.mdc +78 -0
- package/templates/creative/narrative-architect/CLAUDE.md +737 -0
- package/templates/creative/social-media-expert/.cursor/rules/audience-growth.mdc +62 -0
- package/templates/creative/social-media-expert/.cursor/rules/community-management.mdc +67 -0
- package/templates/creative/social-media-expert/.cursor/rules/content-strategy.mdc +60 -0
- package/templates/creative/social-media-expert/.cursor/rules/overview.mdc +48 -0
- package/templates/creative/social-media-expert/.cursor/rules/platform-strategy.mdc +64 -0
- package/templates/creative/social-media-expert/.cursor/rules/social-analytics.mdc +64 -0
- package/templates/creative/social-media-expert/CLAUDE.md +624 -0
- package/templates/creative/trend-forecaster/.cursor/rules/cultural-analysis.mdc +59 -0
- package/templates/creative/trend-forecaster/.cursor/rules/forecasting-methods.mdc +63 -0
- package/templates/creative/trend-forecaster/.cursor/rules/overview.mdc +58 -0
- package/templates/creative/trend-forecaster/.cursor/rules/reporting.mdc +61 -0
- package/templates/creative/trend-forecaster/.cursor/rules/signal-analysis.mdc +74 -0
- package/templates/creative/trend-forecaster/.cursor/rules/trend-lifecycle.mdc +75 -0
- package/templates/creative/trend-forecaster/CLAUDE.md +717 -0
- package/templates/creative/ux-designer/.cursor/rules/accessibility.mdc +69 -0
- package/templates/creative/ux-designer/.cursor/rules/emotional-design.mdc +59 -0
- package/templates/creative/ux-designer/.cursor/rules/handoff.mdc +73 -0
- package/templates/creative/ux-designer/.cursor/rules/information-architecture.mdc +62 -0
- package/templates/creative/ux-designer/.cursor/rules/interaction-design.mdc +66 -0
- package/templates/creative/ux-designer/.cursor/rules/overview.mdc +61 -0
- package/templates/creative/ux-designer/.cursor/rules/research.mdc +61 -0
- package/templates/creative/ux-designer/.cursor/rules/visual-design.mdc +68 -0
- package/templates/creative/ux-designer/CLAUDE.md +124 -0
- package/templates/dogfood/project-overview.mdc +12 -0
- package/templates/dogfood/project-structure.mdc +82 -0
- package/templates/dogfood/rules-creation-best-practices.mdc +45 -0
- package/templates/education/educator/.cursor/rules/accessibility.mdc +67 -0
- package/templates/education/educator/.cursor/rules/assessment.mdc +68 -0
- package/templates/education/educator/.cursor/rules/curriculum.mdc +57 -0
- package/templates/education/educator/.cursor/rules/engagement.mdc +65 -0
- package/templates/education/educator/.cursor/rules/instructional-design.mdc +69 -0
- package/templates/education/educator/.cursor/rules/overview.mdc +57 -0
- package/templates/education/educator/.cursor/rules/retention.mdc +64 -0
- package/templates/education/educator/CLAUDE.md +338 -0
- package/templates/engineering/blockchain/.cursor/rules/defi-patterns.mdc +48 -0
- package/templates/engineering/blockchain/.cursor/rules/gas-optimization.mdc +77 -0
- package/templates/engineering/blockchain/.cursor/rules/overview.mdc +41 -0
- package/templates/engineering/blockchain/.cursor/rules/security.mdc +61 -0
- package/templates/engineering/blockchain/.cursor/rules/smart-contracts.mdc +64 -0
- package/templates/engineering/blockchain/.cursor/rules/testing.mdc +77 -0
- package/templates/engineering/blockchain/.cursor/rules/web3-integration.mdc +47 -0
- package/templates/engineering/blockchain/CLAUDE.md +389 -0
- package/templates/engineering/cli-tools/.cursor/rules/architecture.mdc +76 -0
- package/templates/engineering/cli-tools/.cursor/rules/arguments.mdc +65 -0
- package/templates/engineering/cli-tools/.cursor/rules/distribution.mdc +40 -0
- package/templates/engineering/cli-tools/.cursor/rules/error-handling.mdc +67 -0
- package/templates/engineering/cli-tools/.cursor/rules/overview.mdc +58 -0
- package/templates/engineering/cli-tools/.cursor/rules/testing.mdc +42 -0
- package/templates/engineering/cli-tools/.cursor/rules/user-experience.mdc +43 -0
- package/templates/engineering/cli-tools/CLAUDE.md +356 -0
- package/templates/engineering/data-engineering/.cursor/rules/data-modeling.mdc +71 -0
- package/templates/engineering/data-engineering/.cursor/rules/data-quality.mdc +78 -0
- package/templates/engineering/data-engineering/.cursor/rules/overview.mdc +49 -0
- package/templates/engineering/data-engineering/.cursor/rules/performance.mdc +71 -0
- package/templates/engineering/data-engineering/.cursor/rules/pipeline-design.mdc +79 -0
- package/templates/engineering/data-engineering/.cursor/rules/security.mdc +79 -0
- package/templates/engineering/data-engineering/.cursor/rules/testing.mdc +75 -0
- package/templates/engineering/data-engineering/CLAUDE.md +974 -0
- package/templates/engineering/devops-sre/.cursor/rules/capacity-planning.mdc +49 -0
- package/templates/engineering/devops-sre/.cursor/rules/change-management.mdc +51 -0
- package/templates/engineering/devops-sre/.cursor/rules/chaos-engineering.mdc +50 -0
- package/templates/engineering/devops-sre/.cursor/rules/disaster-recovery.mdc +54 -0
- package/templates/engineering/devops-sre/.cursor/rules/incident-management.mdc +56 -0
- package/templates/engineering/devops-sre/.cursor/rules/observability.mdc +50 -0
- package/templates/engineering/devops-sre/.cursor/rules/overview.mdc +76 -0
- package/templates/engineering/devops-sre/.cursor/rules/postmortems.mdc +49 -0
- package/templates/engineering/devops-sre/.cursor/rules/runbooks.mdc +49 -0
- package/templates/engineering/devops-sre/.cursor/rules/slo-sli.mdc +46 -0
- package/templates/engineering/devops-sre/.cursor/rules/toil-reduction.mdc +52 -0
- package/templates/engineering/devops-sre/CLAUDE.md +1007 -0
- package/templates/engineering/fullstack/.cursor/rules/api-contracts.mdc +79 -0
- package/templates/engineering/fullstack/.cursor/rules/architecture.mdc +79 -0
- package/templates/engineering/fullstack/.cursor/rules/overview.mdc +61 -0
- package/templates/engineering/fullstack/.cursor/rules/shared-types.mdc +77 -0
- package/templates/engineering/fullstack/.cursor/rules/testing.mdc +72 -0
- package/templates/engineering/fullstack/CLAUDE.md +349 -0
- package/templates/engineering/ml-ai/.cursor/rules/data-engineering.mdc +71 -0
- package/templates/engineering/ml-ai/.cursor/rules/deployment.mdc +43 -0
- package/templates/engineering/ml-ai/.cursor/rules/model-development.mdc +44 -0
- package/templates/engineering/ml-ai/.cursor/rules/monitoring.mdc +45 -0
- package/templates/engineering/ml-ai/.cursor/rules/overview.mdc +42 -0
- package/templates/engineering/ml-ai/.cursor/rules/security.mdc +51 -0
- package/templates/engineering/ml-ai/.cursor/rules/testing.mdc +44 -0
- package/templates/engineering/ml-ai/CLAUDE.md +1136 -0
- package/templates/engineering/mobile/.cursor/rules/navigation.mdc +75 -0
- package/templates/engineering/mobile/.cursor/rules/offline-first.mdc +68 -0
- package/templates/engineering/mobile/.cursor/rules/overview.mdc +76 -0
- package/templates/engineering/mobile/.cursor/rules/performance.mdc +78 -0
- package/templates/engineering/mobile/.cursor/rules/testing.mdc +77 -0
- package/templates/engineering/mobile/CLAUDE.md +233 -0
- package/templates/engineering/platform-engineering/.cursor/rules/ci-cd.mdc +51 -0
- package/templates/engineering/platform-engineering/.cursor/rules/developer-experience.mdc +48 -0
- package/templates/engineering/platform-engineering/.cursor/rules/infrastructure-as-code.mdc +62 -0
- package/templates/engineering/platform-engineering/.cursor/rules/kubernetes.mdc +51 -0
- package/templates/engineering/platform-engineering/.cursor/rules/observability.mdc +52 -0
- package/templates/engineering/platform-engineering/.cursor/rules/overview.mdc +44 -0
- package/templates/engineering/platform-engineering/.cursor/rules/security.mdc +74 -0
- package/templates/engineering/platform-engineering/.cursor/rules/testing.mdc +59 -0
- package/templates/engineering/platform-engineering/CLAUDE.md +850 -0
- package/templates/engineering/qa-engineering/.cursor/rules/automation.mdc +71 -0
- package/templates/engineering/qa-engineering/.cursor/rules/metrics.mdc +68 -0
- package/templates/engineering/qa-engineering/.cursor/rules/overview.mdc +45 -0
- package/templates/engineering/qa-engineering/.cursor/rules/quality-gates.mdc +54 -0
- package/templates/engineering/qa-engineering/.cursor/rules/test-design.mdc +59 -0
- package/templates/engineering/qa-engineering/.cursor/rules/test-strategy.mdc +62 -0
- package/templates/engineering/qa-engineering/CLAUDE.md +726 -0
- package/templates/engineering/testing/.cursor/rules/advanced-techniques.mdc +44 -0
- package/templates/engineering/testing/.cursor/rules/ci-cd-integration.mdc +43 -0
- package/templates/engineering/testing/.cursor/rules/overview.mdc +61 -0
- package/templates/engineering/testing/.cursor/rules/performance-testing.mdc +39 -0
- package/templates/engineering/testing/.cursor/rules/quality-metrics.mdc +74 -0
- package/templates/engineering/testing/.cursor/rules/reliability.mdc +39 -0
- package/templates/engineering/testing/.cursor/rules/tdd-methodology.mdc +52 -0
- package/templates/engineering/testing/.cursor/rules/test-data.mdc +46 -0
- package/templates/engineering/testing/.cursor/rules/test-design.mdc +45 -0
- package/templates/engineering/testing/.cursor/rules/test-types.mdc +71 -0
- package/templates/engineering/testing/CLAUDE.md +1134 -0
- package/templates/engineering/unity-dev-expert/.cursor/rules/csharp-architecture.mdc +61 -0
- package/templates/engineering/unity-dev-expert/.cursor/rules/multiplayer-networking.mdc +67 -0
- package/templates/engineering/unity-dev-expert/.cursor/rules/overview.mdc +56 -0
- package/templates/engineering/unity-dev-expert/.cursor/rules/performance-optimization.mdc +76 -0
- package/templates/engineering/unity-dev-expert/.cursor/rules/physics-rendering.mdc +59 -0
- package/templates/engineering/unity-dev-expert/.cursor/rules/ui-systems.mdc +59 -0
- package/templates/engineering/unity-dev-expert/CLAUDE.md +534 -0
- package/templates/engineering/web-backend/.cursor/rules/api-design.mdc +64 -0
- package/templates/engineering/web-backend/.cursor/rules/authentication.mdc +69 -0
- package/templates/engineering/web-backend/.cursor/rules/database-patterns.mdc +73 -0
- package/templates/engineering/web-backend/.cursor/rules/error-handling.mdc +66 -0
- package/templates/engineering/web-backend/.cursor/rules/overview.mdc +74 -0
- package/templates/engineering/web-backend/.cursor/rules/security.mdc +60 -0
- package/templates/engineering/web-backend/.cursor/rules/testing.mdc +74 -0
- package/templates/engineering/web-backend/CLAUDE.md +366 -0
- package/templates/engineering/web-frontend/.cursor/rules/accessibility.mdc +75 -0
- package/templates/engineering/web-frontend/.cursor/rules/component-patterns.mdc +76 -0
- package/templates/engineering/web-frontend/.cursor/rules/overview.mdc +77 -0
- package/templates/engineering/web-frontend/.cursor/rules/performance.mdc +73 -0
- package/templates/engineering/web-frontend/.cursor/rules/state-management.mdc +71 -0
- package/templates/engineering/web-frontend/.cursor/rules/styling.mdc +69 -0
- package/templates/engineering/web-frontend/.cursor/rules/testing.mdc +75 -0
- package/templates/engineering/web-frontend/CLAUDE.md +399 -0
- package/templates/languages/cpp-expert/.cursor/rules/concurrency.mdc +68 -0
- package/templates/languages/cpp-expert/.cursor/rules/error-handling.mdc +65 -0
- package/templates/languages/cpp-expert/.cursor/rules/memory-and-ownership.mdc +68 -0
- package/templates/languages/cpp-expert/.cursor/rules/modern-cpp.mdc +75 -0
- package/templates/languages/cpp-expert/.cursor/rules/overview.mdc +37 -0
- package/templates/languages/cpp-expert/.cursor/rules/performance.mdc +74 -0
- package/templates/languages/cpp-expert/.cursor/rules/testing.mdc +70 -0
- package/templates/languages/cpp-expert/.cursor/rules/tooling.mdc +77 -0
- package/templates/languages/cpp-expert/CLAUDE.md +242 -0
- package/templates/languages/csharp-expert/.cursor/rules/aspnet-core.mdc +78 -0
- package/templates/languages/csharp-expert/.cursor/rules/async-patterns.mdc +71 -0
- package/templates/languages/csharp-expert/.cursor/rules/dependency-injection.mdc +76 -0
- package/templates/languages/csharp-expert/.cursor/rules/error-handling.mdc +65 -0
- package/templates/languages/csharp-expert/.cursor/rules/language-features.mdc +74 -0
- package/templates/languages/csharp-expert/.cursor/rules/overview.mdc +47 -0
- package/templates/languages/csharp-expert/.cursor/rules/performance.mdc +66 -0
- package/templates/languages/csharp-expert/.cursor/rules/testing.mdc +78 -0
- package/templates/languages/csharp-expert/.cursor/rules/tooling.mdc +78 -0
- package/templates/languages/csharp-expert/CLAUDE.md +360 -0
- package/templates/languages/golang-expert/.cursor/rules/concurrency.mdc +79 -0
- package/templates/languages/golang-expert/.cursor/rules/error-handling.mdc +77 -0
- package/templates/languages/golang-expert/.cursor/rules/interfaces-and-types.mdc +77 -0
- package/templates/languages/golang-expert/.cursor/rules/overview.mdc +74 -0
- package/templates/languages/golang-expert/.cursor/rules/performance.mdc +76 -0
- package/templates/languages/golang-expert/.cursor/rules/production-patterns.mdc +76 -0
- package/templates/languages/golang-expert/.cursor/rules/stdlib-and-tooling.mdc +68 -0
- package/templates/languages/golang-expert/.cursor/rules/testing.mdc +77 -0
- package/templates/languages/golang-expert/CLAUDE.md +361 -0
- package/templates/languages/java-expert/.cursor/rules/concurrency.mdc +69 -0
- package/templates/languages/java-expert/.cursor/rules/error-handling.mdc +70 -0
- package/templates/languages/java-expert/.cursor/rules/modern-java.mdc +74 -0
- package/templates/languages/java-expert/.cursor/rules/overview.mdc +42 -0
- package/templates/languages/java-expert/.cursor/rules/performance.mdc +69 -0
- package/templates/languages/java-expert/.cursor/rules/persistence.mdc +74 -0
- package/templates/languages/java-expert/.cursor/rules/spring-boot.mdc +73 -0
- package/templates/languages/java-expert/.cursor/rules/testing.mdc +79 -0
- package/templates/languages/java-expert/.cursor/rules/tooling.mdc +76 -0
- package/templates/languages/java-expert/CLAUDE.md +325 -0
- package/templates/languages/javascript-expert/.cursor/rules/language-deep-dive.mdc +74 -0
- package/templates/languages/javascript-expert/.cursor/rules/node-patterns.mdc +77 -0
- package/templates/languages/javascript-expert/.cursor/rules/overview.mdc +66 -0
- package/templates/languages/javascript-expert/.cursor/rules/performance.mdc +64 -0
- package/templates/languages/javascript-expert/.cursor/rules/react-patterns.mdc +70 -0
- package/templates/languages/javascript-expert/.cursor/rules/testing.mdc +76 -0
- package/templates/languages/javascript-expert/.cursor/rules/tooling.mdc +72 -0
- package/templates/languages/javascript-expert/.cursor/rules/typescript-deep-dive.mdc +77 -0
- package/templates/languages/javascript-expert/CLAUDE.md +479 -0
- package/templates/languages/kotlin-expert/.cursor/rules/coroutines.mdc +75 -0
- package/templates/languages/kotlin-expert/.cursor/rules/error-handling.mdc +69 -0
- package/templates/languages/kotlin-expert/.cursor/rules/frameworks.mdc +76 -0
- package/templates/languages/kotlin-expert/.cursor/rules/language-features.mdc +78 -0
- package/templates/languages/kotlin-expert/.cursor/rules/overview.mdc +38 -0
- package/templates/languages/kotlin-expert/.cursor/rules/performance.mdc +73 -0
- package/templates/languages/kotlin-expert/.cursor/rules/testing.mdc +70 -0
- package/templates/languages/kotlin-expert/.cursor/rules/tooling.mdc +67 -0
- package/templates/languages/kotlin-expert/CLAUDE.md +276 -0
- package/templates/languages/python-expert/.cursor/rules/async-python.mdc +71 -0
- package/templates/languages/python-expert/.cursor/rules/overview.mdc +76 -0
- package/templates/languages/python-expert/.cursor/rules/patterns-and-idioms.mdc +77 -0
- package/templates/languages/python-expert/.cursor/rules/performance.mdc +74 -0
- package/templates/languages/python-expert/.cursor/rules/testing.mdc +77 -0
- package/templates/languages/python-expert/.cursor/rules/tooling.mdc +77 -0
- package/templates/languages/python-expert/.cursor/rules/type-system.mdc +77 -0
- package/templates/languages/python-expert/.cursor/rules/web-and-apis.mdc +76 -0
- package/templates/languages/python-expert/CLAUDE.md +264 -0
- package/templates/languages/ruby-expert/.cursor/rules/concurrency-and-threading.mdc +65 -0
- package/templates/languages/ruby-expert/.cursor/rules/error-handling.mdc +69 -0
- package/templates/languages/ruby-expert/.cursor/rules/idioms-and-style.mdc +76 -0
- package/templates/languages/ruby-expert/.cursor/rules/overview.mdc +60 -0
- package/templates/languages/ruby-expert/.cursor/rules/performance.mdc +68 -0
- package/templates/languages/ruby-expert/.cursor/rules/rails-and-frameworks.mdc +60 -0
- package/templates/languages/ruby-expert/.cursor/rules/testing.mdc +56 -0
- package/templates/languages/ruby-expert/.cursor/rules/tooling.mdc +52 -0
- package/templates/languages/ruby-expert/CLAUDE.md +102 -0
- package/templates/languages/rust-expert/.cursor/rules/concurrency.mdc +69 -0
- package/templates/languages/rust-expert/.cursor/rules/ecosystem-and-tooling.mdc +76 -0
- package/templates/languages/rust-expert/.cursor/rules/error-handling.mdc +76 -0
- package/templates/languages/rust-expert/.cursor/rules/overview.mdc +62 -0
- package/templates/languages/rust-expert/.cursor/rules/ownership-and-borrowing.mdc +70 -0
- package/templates/languages/rust-expert/.cursor/rules/performance-and-unsafe.mdc +70 -0
- package/templates/languages/rust-expert/.cursor/rules/testing.mdc +73 -0
- package/templates/languages/rust-expert/.cursor/rules/traits-and-generics.mdc +76 -0
- package/templates/languages/rust-expert/CLAUDE.md +283 -0
- package/templates/languages/swift-expert/.cursor/rules/concurrency.mdc +77 -0
- package/templates/languages/swift-expert/.cursor/rules/error-handling.mdc +76 -0
- package/templates/languages/swift-expert/.cursor/rules/language-features.mdc +78 -0
- package/templates/languages/swift-expert/.cursor/rules/overview.mdc +46 -0
- package/templates/languages/swift-expert/.cursor/rules/performance.mdc +69 -0
- package/templates/languages/swift-expert/.cursor/rules/swiftui.mdc +77 -0
- package/templates/languages/swift-expert/.cursor/rules/testing.mdc +75 -0
- package/templates/languages/swift-expert/.cursor/rules/tooling.mdc +77 -0
- package/templates/languages/swift-expert/CLAUDE.md +275 -0
- package/templates/professional/documentation/.cursor/rules/adr.mdc +65 -0
- package/templates/professional/documentation/.cursor/rules/api-documentation.mdc +64 -0
- package/templates/professional/documentation/.cursor/rules/code-comments.mdc +75 -0
- package/templates/professional/documentation/.cursor/rules/maintenance.mdc +58 -0
- package/templates/professional/documentation/.cursor/rules/overview.mdc +48 -0
- package/templates/professional/documentation/.cursor/rules/readme-standards.mdc +70 -0
- package/templates/professional/documentation/CLAUDE.md +120 -0
- package/templates/professional/executive-assistant/.cursor/rules/calendar.mdc +51 -0
- package/templates/professional/executive-assistant/.cursor/rules/confidentiality.mdc +53 -0
- package/templates/professional/executive-assistant/.cursor/rules/email.mdc +49 -0
- package/templates/professional/executive-assistant/.cursor/rules/meetings.mdc +39 -0
- package/templates/professional/executive-assistant/.cursor/rules/overview.mdc +42 -0
- package/templates/professional/executive-assistant/.cursor/rules/prioritization.mdc +48 -0
- package/templates/professional/executive-assistant/.cursor/rules/stakeholder-management.mdc +50 -0
- package/templates/professional/executive-assistant/.cursor/rules/travel.mdc +43 -0
- package/templates/professional/executive-assistant/CLAUDE.md +620 -0
- package/templates/professional/grant-writer/.cursor/rules/budgets.mdc +55 -0
- package/templates/professional/grant-writer/.cursor/rules/compliance.mdc +47 -0
- package/templates/professional/grant-writer/.cursor/rules/funding-research.mdc +47 -0
- package/templates/professional/grant-writer/.cursor/rules/narrative.mdc +58 -0
- package/templates/professional/grant-writer/.cursor/rules/overview.mdc +68 -0
- package/templates/professional/grant-writer/.cursor/rules/post-award.mdc +59 -0
- package/templates/professional/grant-writer/.cursor/rules/review-criteria.mdc +51 -0
- package/templates/professional/grant-writer/.cursor/rules/sustainability.mdc +48 -0
- package/templates/professional/grant-writer/CLAUDE.md +577 -0
- package/templates/professional/knowledge-synthesis/.cursor/rules/document-management.mdc +51 -0
- package/templates/professional/knowledge-synthesis/.cursor/rules/knowledge-graphs.mdc +63 -0
- package/templates/professional/knowledge-synthesis/.cursor/rules/overview.mdc +74 -0
- package/templates/professional/knowledge-synthesis/.cursor/rules/research-workflow.mdc +50 -0
- package/templates/professional/knowledge-synthesis/.cursor/rules/search-retrieval.mdc +62 -0
- package/templates/professional/knowledge-synthesis/.cursor/rules/summarization.mdc +61 -0
- package/templates/professional/knowledge-synthesis/CLAUDE.md +593 -0
- package/templates/professional/life-logistics/.cursor/rules/financial-optimization.mdc +78 -0
- package/templates/professional/life-logistics/.cursor/rules/negotiation.mdc +68 -0
- package/templates/professional/life-logistics/.cursor/rules/overview.mdc +75 -0
- package/templates/professional/life-logistics/.cursor/rules/research-methodology.mdc +76 -0
- package/templates/professional/life-logistics/.cursor/rules/scheduling.mdc +68 -0
- package/templates/professional/life-logistics/.cursor/rules/task-management.mdc +47 -0
- package/templates/professional/life-logistics/CLAUDE.md +601 -0
- package/templates/professional/research-assistant/.cursor/rules/citation-attribution.mdc +61 -0
- package/templates/professional/research-assistant/.cursor/rules/information-synthesis.mdc +65 -0
- package/templates/professional/research-assistant/.cursor/rules/overview.mdc +56 -0
- package/templates/professional/research-assistant/.cursor/rules/research-methodologies.mdc +54 -0
- package/templates/professional/research-assistant/.cursor/rules/search-strategies.mdc +57 -0
- package/templates/professional/research-assistant/.cursor/rules/source-evaluation.mdc +59 -0
- package/templates/professional/research-assistant/CLAUDE.md +318 -0
- package/templates/professional/wellness-orchestrator/.cursor/rules/adaptive-planning.mdc +69 -0
- package/templates/professional/wellness-orchestrator/.cursor/rules/data-integration.mdc +60 -0
- package/templates/professional/wellness-orchestrator/.cursor/rules/fitness-programming.mdc +66 -0
- package/templates/professional/wellness-orchestrator/.cursor/rules/nutrition-planning.mdc +57 -0
- package/templates/professional/wellness-orchestrator/.cursor/rules/overview.mdc +76 -0
- package/templates/professional/wellness-orchestrator/.cursor/rules/sleep-optimization.mdc +68 -0
- package/templates/professional/wellness-orchestrator/CLAUDE.md +573 -0
package/src/index.js
ADDED
|
@@ -0,0 +1,1817 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
import { exec } from 'child_process';
|
|
5
|
+
import { promisify } from 'util';
|
|
6
|
+
|
|
7
|
+
const execAsync = promisify(exec);
|
|
8
|
+
|
|
9
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
10
|
+
const __dirname = path.dirname(__filename);
|
|
11
|
+
const TEMPLATES_DIR = path.join(__dirname, '..', 'templates');
|
|
12
|
+
|
|
13
|
+
// Cursor rules directory paths
|
|
14
|
+
const CURSOR_RULES_DIR = '.cursor/rules'; // New path (Cursor IDE)
|
|
15
|
+
const LEGACY_CURSORRULES_DIR = '.cursorrules'; // Deprecated path
|
|
16
|
+
|
|
17
|
+
// Read package.json for version info
|
|
18
|
+
const packageJsonPath = path.join(__dirname, '..', 'package.json');
|
|
19
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
20
|
+
const PACKAGE_NAME = packageJson.name;
|
|
21
|
+
const CURRENT_VERSION = packageJson.version;
|
|
22
|
+
const REPO_URL = 'https://github.com/djm204/agent-skills';
|
|
23
|
+
const CHANGELOG_URL = `${REPO_URL}/releases/tag/${PACKAGE_NAME}-v${CURRENT_VERSION}`;
|
|
24
|
+
|
|
25
|
+
// Template categories (storage-only, not exposed to CLI users)
|
|
26
|
+
const CATEGORIES = [
|
|
27
|
+
'engineering',
|
|
28
|
+
'languages',
|
|
29
|
+
'creative',
|
|
30
|
+
'business',
|
|
31
|
+
'professional',
|
|
32
|
+
'education',
|
|
33
|
+
'agents',
|
|
34
|
+
];
|
|
35
|
+
|
|
36
|
+
// Available templates
|
|
37
|
+
const TEMPLATES = {
|
|
38
|
+
'brand-guardian': {
|
|
39
|
+
category: 'creative',
|
|
40
|
+
description: 'Brand voice enforcement, visual identity compliance, content review workflows, and multi-channel consistency',
|
|
41
|
+
rules: ['brand-voice.mdc', 'content-review.mdc', 'ethical-guidelines.mdc', 'multi-channel.mdc', 'overview.mdc', 'visual-identity.mdc']
|
|
42
|
+
},
|
|
43
|
+
'blockchain': {
|
|
44
|
+
category: 'engineering',
|
|
45
|
+
description: 'Smart contracts, DeFi protocols, and Web3 applications (Solidity, Foundry, Viem)',
|
|
46
|
+
rules: ['defi-patterns.mdc', 'gas-optimization.mdc', 'overview.mdc', 'security.mdc', 'smart-contracts.mdc', 'testing.mdc', 'web3-integration.mdc']
|
|
47
|
+
},
|
|
48
|
+
'cpp-expert': {
|
|
49
|
+
category: 'languages',
|
|
50
|
+
description: 'Principal-level C++ engineering (modern C++, RAII, concurrency, templates, performance)',
|
|
51
|
+
rules: ['concurrency.mdc', 'error-handling.mdc', 'memory-and-ownership.mdc', 'modern-cpp.mdc', 'overview.mdc', 'performance.mdc', 'testing.mdc', 'tooling.mdc']
|
|
52
|
+
},
|
|
53
|
+
'csharp-expert': {
|
|
54
|
+
category: 'languages',
|
|
55
|
+
description: 'Principal-level C# engineering (async, DI, EF Core, ASP.NET Core, testing)',
|
|
56
|
+
rules: ['aspnet-core.mdc', 'async-patterns.mdc', 'dependency-injection.mdc', 'error-handling.mdc', 'language-features.mdc', 'overview.mdc', 'performance.mdc', 'testing.mdc', 'tooling.mdc']
|
|
57
|
+
},
|
|
58
|
+
'content-creation-expert': {
|
|
59
|
+
category: 'creative',
|
|
60
|
+
description: 'Content strategy, long-form writing, copywriting, SEO content, multimedia production, and editorial operations',
|
|
61
|
+
rules: ['content-strategy.mdc', 'copywriting.mdc', 'editorial-operations.mdc', 'multimedia-production.mdc', 'overview.mdc', 'seo-content.mdc']
|
|
62
|
+
},
|
|
63
|
+
'cli-tools': {
|
|
64
|
+
category: 'engineering',
|
|
65
|
+
description: 'Command-line applications and developer tools (Cobra, Commander, Click)',
|
|
66
|
+
rules: ['architecture.mdc', 'arguments.mdc', 'distribution.mdc', 'error-handling.mdc', 'overview.mdc', 'testing.mdc', 'user-experience.mdc']
|
|
67
|
+
},
|
|
68
|
+
'data-engineering': {
|
|
69
|
+
category: 'engineering',
|
|
70
|
+
description: 'Data platforms and pipelines (ETL, data modeling, data quality)',
|
|
71
|
+
rules: ['data-modeling.mdc', 'data-quality.mdc', 'overview.mdc', 'performance.mdc', 'pipeline-design.mdc', 'security.mdc', 'testing.mdc']
|
|
72
|
+
},
|
|
73
|
+
'devops-sre': {
|
|
74
|
+
category: 'engineering',
|
|
75
|
+
description: 'DevOps and SRE practices (incident management, observability, SLOs, chaos engineering)',
|
|
76
|
+
rules: ['capacity-planning.mdc', 'change-management.mdc', 'chaos-engineering.mdc', 'disaster-recovery.mdc', 'incident-management.mdc', 'observability.mdc', 'overview.mdc', 'postmortems.mdc', 'runbooks.mdc', 'slo-sli.mdc', 'toil-reduction.mdc']
|
|
77
|
+
},
|
|
78
|
+
'documentation': {
|
|
79
|
+
category: 'professional',
|
|
80
|
+
description: 'Technical documentation standards (READMEs, API docs, ADRs, code comments)',
|
|
81
|
+
rules: ['adr.mdc', 'api-documentation.mdc', 'code-comments.mdc', 'maintenance.mdc', 'overview.mdc', 'readme-standards.mdc']
|
|
82
|
+
},
|
|
83
|
+
'educator': {
|
|
84
|
+
category: 'education',
|
|
85
|
+
description: 'World-class pedagogy with evidence-based teaching, learning retention, gamification, and assessment design',
|
|
86
|
+
rules: ['accessibility.mdc', 'assessment.mdc', 'curriculum.mdc', 'engagement.mdc', 'instructional-design.mdc', 'overview.mdc', 'retention.mdc']
|
|
87
|
+
},
|
|
88
|
+
'executive-assistant': {
|
|
89
|
+
category: 'professional',
|
|
90
|
+
description: 'Executive support with calendar optimization, communication management, meeting coordination, and priority triage',
|
|
91
|
+
rules: ['calendar.mdc', 'confidentiality.mdc', 'email.mdc', 'meetings.mdc', 'overview.mdc', 'prioritization.mdc', 'stakeholder-management.mdc', 'travel.mdc']
|
|
92
|
+
},
|
|
93
|
+
'fullstack': {
|
|
94
|
+
category: 'engineering',
|
|
95
|
+
description: 'Full-stack web applications (Next.js, Nuxt, SvelteKit, Remix)',
|
|
96
|
+
rules: ['api-contracts.mdc', 'architecture.mdc', 'overview.mdc', 'shared-types.mdc', 'testing.mdc']
|
|
97
|
+
},
|
|
98
|
+
'grant-writer': {
|
|
99
|
+
category: 'professional',
|
|
100
|
+
description: 'Grant writing with proposal development, budget justification, compliance management, and post-award stewardship',
|
|
101
|
+
rules: ['budgets.mdc', 'compliance.mdc', 'funding-research.mdc', 'narrative.mdc', 'overview.mdc', 'post-award.mdc', 'review-criteria.mdc', 'sustainability.mdc']
|
|
102
|
+
},
|
|
103
|
+
'golang-expert': {
|
|
104
|
+
category: 'languages',
|
|
105
|
+
description: 'Principal-level Go engineering (concurrency, stdlib, production patterns, testing)',
|
|
106
|
+
rules: ['concurrency.mdc', 'error-handling.mdc', 'interfaces-and-types.mdc', 'overview.mdc', 'performance.mdc', 'production-patterns.mdc', 'stdlib-and-tooling.mdc', 'testing.mdc']
|
|
107
|
+
},
|
|
108
|
+
'java-expert': {
|
|
109
|
+
category: 'languages',
|
|
110
|
+
description: 'Principal-level Java engineering (JVM, Spring Boot, concurrency, JPA, testing)',
|
|
111
|
+
rules: ['concurrency.mdc', 'error-handling.mdc', 'modern-java.mdc', 'overview.mdc', 'performance.mdc', 'persistence.mdc', 'spring-boot.mdc', 'testing.mdc', 'tooling.mdc']
|
|
112
|
+
},
|
|
113
|
+
'javascript-expert': {
|
|
114
|
+
category: 'languages',
|
|
115
|
+
description: 'Principal-level JavaScript & TypeScript engineering (Node.js, React, type system, testing)',
|
|
116
|
+
rules: ['language-deep-dive.mdc', 'node-patterns.mdc', 'overview.mdc', 'performance.mdc', 'react-patterns.mdc', 'testing.mdc', 'tooling.mdc', 'typescript-deep-dive.mdc']
|
|
117
|
+
},
|
|
118
|
+
'knowledge-synthesis': {
|
|
119
|
+
category: 'professional',
|
|
120
|
+
description: 'Knowledge management with document ingestion, knowledge graphs, search/retrieval, summarization, and research workflows',
|
|
121
|
+
rules: ['document-management.mdc', 'knowledge-graphs.mdc', 'overview.mdc', 'research-workflow.mdc', 'search-retrieval.mdc', 'summarization.mdc']
|
|
122
|
+
},
|
|
123
|
+
'kotlin-expert': {
|
|
124
|
+
category: 'languages',
|
|
125
|
+
description: 'Principal-level Kotlin engineering (coroutines, multiplatform, Ktor, Spring Boot, testing)',
|
|
126
|
+
rules: ['coroutines.mdc', 'error-handling.mdc', 'frameworks.mdc', 'language-features.mdc', 'overview.mdc', 'performance.mdc', 'testing.mdc', 'tooling.mdc']
|
|
127
|
+
},
|
|
128
|
+
'life-logistics': {
|
|
129
|
+
category: 'professional',
|
|
130
|
+
description: 'Personal logistics optimization including scheduling, bill negotiation, insurance comparison, and vendor research',
|
|
131
|
+
rules: ['financial-optimization.mdc', 'negotiation.mdc', 'overview.mdc', 'research-methodology.mdc', 'scheduling.mdc', 'task-management.mdc']
|
|
132
|
+
},
|
|
133
|
+
'market-intelligence': {
|
|
134
|
+
category: 'business',
|
|
135
|
+
description: 'Market intelligence with data source aggregation, sentiment analysis, trend detection, and risk signal monitoring',
|
|
136
|
+
rules: ['data-sources.mdc', 'overview.mdc', 'reporting.mdc', 'risk-signals.mdc', 'sentiment-analysis.mdc', 'trend-detection.mdc']
|
|
137
|
+
},
|
|
138
|
+
'marketing-expert': {
|
|
139
|
+
category: 'business',
|
|
140
|
+
description: 'Principal marketing strategy covering brand positioning, campaign planning, market analysis, analytics, and growth frameworks',
|
|
141
|
+
rules: ['brand-strategy.mdc', 'campaign-planning.mdc', 'growth-frameworks.mdc', 'market-analysis.mdc', 'marketing-analytics.mdc', 'overview.mdc']
|
|
142
|
+
},
|
|
143
|
+
'ml-ai': {
|
|
144
|
+
category: 'engineering',
|
|
145
|
+
description: 'Machine learning and AI systems (model development, deployment, monitoring)',
|
|
146
|
+
rules: ['data-engineering.mdc', 'deployment.mdc', 'model-development.mdc', 'monitoring.mdc', 'overview.mdc', 'security.mdc', 'testing.mdc']
|
|
147
|
+
},
|
|
148
|
+
'narrative-architect': {
|
|
149
|
+
category: 'creative',
|
|
150
|
+
description: 'World-building, continuity tracking, timeline management, story bible creation, and collaborative storytelling',
|
|
151
|
+
rules: ['collaboration.mdc', 'continuity-tracking.mdc', 'overview.mdc', 'story-bible.mdc', 'timeline-management.mdc', 'world-building.mdc']
|
|
152
|
+
},
|
|
153
|
+
'mobile': {
|
|
154
|
+
category: 'engineering',
|
|
155
|
+
description: 'Mobile applications (React Native, Flutter, native iOS/Android)',
|
|
156
|
+
rules: ['navigation.mdc', 'offline-first.mdc', 'overview.mdc', 'performance.mdc', 'testing.mdc']
|
|
157
|
+
},
|
|
158
|
+
'predictive-maintenance': {
|
|
159
|
+
category: 'business',
|
|
160
|
+
description: 'Industrial sensor monitoring, failure prediction, maintenance scheduling, asset lifecycle management, and alerting',
|
|
161
|
+
rules: ['alerting.mdc', 'asset-lifecycle.mdc', 'failure-prediction.mdc', 'maintenance-scheduling.mdc', 'overview.mdc', 'sensor-analytics.mdc']
|
|
162
|
+
},
|
|
163
|
+
'platform-engineering': {
|
|
164
|
+
category: 'engineering',
|
|
165
|
+
description: 'Internal developer platforms, infrastructure automation, and reliability engineering',
|
|
166
|
+
rules: ['ci-cd.mdc', 'developer-experience.mdc', 'infrastructure-as-code.mdc', 'kubernetes.mdc', 'observability.mdc', 'overview.mdc', 'security.mdc', 'testing.mdc']
|
|
167
|
+
},
|
|
168
|
+
'product-manager': {
|
|
169
|
+
category: 'business',
|
|
170
|
+
description: 'Product management with customer-centric discovery, prioritization, and execution',
|
|
171
|
+
rules: ['communication.mdc', 'discovery.mdc', 'metrics.mdc', 'overview.mdc', 'prioritization.mdc', 'requirements.mdc']
|
|
172
|
+
},
|
|
173
|
+
'regulatory-sentinel': {
|
|
174
|
+
category: 'business',
|
|
175
|
+
description: 'Regulatory compliance tracking, impact assessment, monitoring, risk classification, and compliance reporting',
|
|
176
|
+
rules: ['compliance-tracking.mdc', 'impact-assessment.mdc', 'monitoring.mdc', 'overview.mdc', 'reporting.mdc', 'risk-classification.mdc']
|
|
177
|
+
},
|
|
178
|
+
'research-assistant': {
|
|
179
|
+
category: 'professional',
|
|
180
|
+
description: 'World-class research with advanced search strategies, source evaluation, OSINT techniques, and rigorous synthesis',
|
|
181
|
+
rules: ['citation-attribution.mdc', 'information-synthesis.mdc', 'overview.mdc', 'research-methodologies.mdc', 'search-strategies.mdc', 'source-evaluation.mdc']
|
|
182
|
+
},
|
|
183
|
+
'resource-allocator': {
|
|
184
|
+
category: 'business',
|
|
185
|
+
description: 'Resource allocation with demand prediction, scheduling optimization, crisis management, and capacity modeling',
|
|
186
|
+
rules: ['capacity-modeling.mdc', 'coordination.mdc', 'crisis-management.mdc', 'demand-prediction.mdc', 'overview.mdc', 'scheduling.mdc']
|
|
187
|
+
},
|
|
188
|
+
'project-manager': {
|
|
189
|
+
category: 'business',
|
|
190
|
+
description: 'Project management with WBS planning, risk management, status reporting, and change control',
|
|
191
|
+
rules: ['overview.mdc', 'reporting.mdc', 'risk-management.mdc', 'scheduling.mdc', 'scope-management.mdc', 'stakeholder-management.mdc']
|
|
192
|
+
},
|
|
193
|
+
'python-expert': {
|
|
194
|
+
category: 'languages',
|
|
195
|
+
description: 'Principal-level Python engineering (type system, async, testing, FastAPI, Django)',
|
|
196
|
+
rules: ['async-python.mdc', 'overview.mdc', 'patterns-and-idioms.mdc', 'performance.mdc', 'testing.mdc', 'tooling.mdc', 'type-system.mdc', 'web-and-apis.mdc']
|
|
197
|
+
},
|
|
198
|
+
'qa-engineering': {
|
|
199
|
+
category: 'engineering',
|
|
200
|
+
description: 'Quality assurance programs for confident, rapid software delivery',
|
|
201
|
+
rules: ['automation.mdc', 'metrics.mdc', 'overview.mdc', 'quality-gates.mdc', 'test-design.mdc', 'test-strategy.mdc']
|
|
202
|
+
},
|
|
203
|
+
'social-media-expert': {
|
|
204
|
+
category: 'creative',
|
|
205
|
+
description: 'Social media strategy covering platform optimization, content planning, audience growth, community management, and analytics',
|
|
206
|
+
rules: ['audience-growth.mdc', 'community-management.mdc', 'content-strategy.mdc', 'overview.mdc', 'platform-strategy.mdc', 'social-analytics.mdc']
|
|
207
|
+
},
|
|
208
|
+
'strategic-negotiator': {
|
|
209
|
+
category: 'business',
|
|
210
|
+
description: 'Negotiation strategy with game theory, deal structuring, scenario modeling, preparation frameworks, and contract analysis',
|
|
211
|
+
rules: ['contract-analysis.mdc', 'deal-structuring.mdc', 'game-theory.mdc', 'overview.mdc', 'preparation.mdc', 'scenario-modeling.mdc']
|
|
212
|
+
},
|
|
213
|
+
'supply-chain-harmonizer': {
|
|
214
|
+
category: 'business',
|
|
215
|
+
description: 'Supply chain optimization with disruption response, rerouting, inventory rebalancing, and scenario simulation',
|
|
216
|
+
rules: ['disruption-response.mdc', 'inventory-rebalancing.mdc', 'overview.mdc', 'rerouting.mdc', 'scenario-simulation.mdc', 'stakeholder-notifications.mdc']
|
|
217
|
+
},
|
|
218
|
+
'ruby-expert': {
|
|
219
|
+
category: 'languages',
|
|
220
|
+
description: 'Principal-level Ruby engineering (idioms, concurrency, Rails, performance, testing)',
|
|
221
|
+
rules: ['concurrency-and-threading.mdc', 'error-handling.mdc', 'idioms-and-style.mdc', 'overview.mdc', 'performance.mdc', 'rails-and-frameworks.mdc', 'testing.mdc', 'tooling.mdc']
|
|
222
|
+
},
|
|
223
|
+
'rust-expert': {
|
|
224
|
+
category: 'languages',
|
|
225
|
+
description: 'Principal-level Rust engineering (ownership, concurrency, unsafe, traits, async)',
|
|
226
|
+
rules: ['concurrency.mdc', 'ecosystem-and-tooling.mdc', 'error-handling.mdc', 'overview.mdc', 'ownership-and-borrowing.mdc', 'performance-and-unsafe.mdc', 'testing.mdc', 'traits-and-generics.mdc']
|
|
227
|
+
},
|
|
228
|
+
'supply-chain': {
|
|
229
|
+
category: 'business',
|
|
230
|
+
description: 'Supply chain management with inventory optimization, demand forecasting, supplier evaluation, and logistics',
|
|
231
|
+
rules: ['cost-modeling.mdc', 'demand-forecasting.mdc', 'inventory-management.mdc', 'logistics.mdc', 'overview.mdc', 'supplier-evaluation.mdc']
|
|
232
|
+
},
|
|
233
|
+
'swift-expert': {
|
|
234
|
+
category: 'languages',
|
|
235
|
+
description: 'Principal-level Swift engineering (concurrency, SwiftUI, protocols, testing, Apple platforms)',
|
|
236
|
+
rules: ['concurrency.mdc', 'error-handling.mdc', 'language-features.mdc', 'overview.mdc', 'performance.mdc', 'swiftui.mdc', 'testing.mdc', 'tooling.mdc']
|
|
237
|
+
},
|
|
238
|
+
'trend-forecaster': {
|
|
239
|
+
category: 'creative',
|
|
240
|
+
description: 'Trend analysis with signal detection, cultural analysis, trend lifecycle modeling, forecasting methods, and reporting',
|
|
241
|
+
rules: ['cultural-analysis.mdc', 'forecasting-methods.mdc', 'overview.mdc', 'reporting.mdc', 'signal-analysis.mdc', 'trend-lifecycle.mdc']
|
|
242
|
+
},
|
|
243
|
+
'testing': {
|
|
244
|
+
category: 'engineering',
|
|
245
|
+
description: 'Comprehensive testing practices (TDD, test design, CI/CD integration, performance testing)',
|
|
246
|
+
rules: ['advanced-techniques.mdc', 'ci-cd-integration.mdc', 'overview.mdc', 'performance-testing.mdc', 'quality-metrics.mdc', 'reliability.mdc', 'tdd-methodology.mdc', 'test-data.mdc', 'test-design.mdc', 'test-types.mdc']
|
|
247
|
+
},
|
|
248
|
+
'unity-dev-expert': {
|
|
249
|
+
category: 'engineering',
|
|
250
|
+
description: 'Unity game development with C# architecture, ECS/DOTS, physics/rendering, UI systems, multiplayer networking, and performance optimization',
|
|
251
|
+
rules: ['csharp-architecture.mdc', 'multiplayer-networking.mdc', 'overview.mdc', 'performance-optimization.mdc', 'physics-rendering.mdc', 'ui-systems.mdc']
|
|
252
|
+
},
|
|
253
|
+
'utility-agent': {
|
|
254
|
+
category: 'agents',
|
|
255
|
+
description: 'AI agent utilities with context management and hallucination prevention',
|
|
256
|
+
rules: ['action-control.mdc', 'context-management.mdc', 'hallucination-prevention.mdc', 'overview.mdc', 'token-optimization.mdc']
|
|
257
|
+
},
|
|
258
|
+
'ux-designer': {
|
|
259
|
+
category: 'creative',
|
|
260
|
+
description: 'Principal-level UX design with user research, interaction design, design systems, accessibility, and emotional design',
|
|
261
|
+
rules: ['accessibility.mdc', 'emotional-design.mdc', 'handoff.mdc', 'information-architecture.mdc', 'interaction-design.mdc', 'overview.mdc', 'research.mdc', 'visual-design.mdc']
|
|
262
|
+
},
|
|
263
|
+
'wellness-orchestrator': {
|
|
264
|
+
category: 'professional',
|
|
265
|
+
description: 'Unified wellness planning across fitness, nutrition, sleep, and mental wellness with wearable data integration',
|
|
266
|
+
rules: ['adaptive-planning.mdc', 'data-integration.mdc', 'fitness-programming.mdc', 'nutrition-planning.mdc', 'overview.mdc', 'sleep-optimization.mdc']
|
|
267
|
+
},
|
|
268
|
+
'web-backend': {
|
|
269
|
+
category: 'engineering',
|
|
270
|
+
description: 'Backend APIs and services (REST, GraphQL, microservices)',
|
|
271
|
+
rules: ['api-design.mdc', 'authentication.mdc', 'database-patterns.mdc', 'error-handling.mdc', 'overview.mdc', 'security.mdc', 'testing.mdc']
|
|
272
|
+
},
|
|
273
|
+
'web-frontend': {
|
|
274
|
+
category: 'engineering',
|
|
275
|
+
description: 'Frontend web applications (SPAs, SSR, static sites, PWAs)',
|
|
276
|
+
rules: ['accessibility.mdc', 'component-patterns.mdc', 'overview.mdc', 'performance.mdc', 'state-management.mdc', 'styling.mdc', 'testing.mdc']
|
|
277
|
+
}
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
// Shorthand aliases for language expert templates
|
|
281
|
+
const TEMPLATE_ALIASES = {
|
|
282
|
+
'js': 'javascript-expert',
|
|
283
|
+
'javascript': 'javascript-expert',
|
|
284
|
+
'ts': 'javascript-expert',
|
|
285
|
+
'typescript': 'javascript-expert',
|
|
286
|
+
'go': 'golang-expert',
|
|
287
|
+
'golang': 'golang-expert',
|
|
288
|
+
'py': 'python-expert',
|
|
289
|
+
'python': 'python-expert',
|
|
290
|
+
'rs': 'rust-expert',
|
|
291
|
+
'rust': 'rust-expert',
|
|
292
|
+
'ruby': 'ruby-expert',
|
|
293
|
+
'rb': 'ruby-expert',
|
|
294
|
+
'swift': 'swift-expert',
|
|
295
|
+
'kotlin': 'kotlin-expert',
|
|
296
|
+
'kt': 'kotlin-expert',
|
|
297
|
+
'java': 'java-expert',
|
|
298
|
+
'cpp': 'cpp-expert',
|
|
299
|
+
'csharp': 'csharp-expert',
|
|
300
|
+
'cs': 'csharp-expert',
|
|
301
|
+
'unity': 'unity-dev-expert',
|
|
302
|
+
'teach': 'educator',
|
|
303
|
+
'teacher': 'educator',
|
|
304
|
+
'marketing': 'marketing-expert',
|
|
305
|
+
'social-media': 'social-media-expert',
|
|
306
|
+
'content-creation': 'content-creation-expert',
|
|
307
|
+
'ux': 'ux-designer',
|
|
308
|
+
'uxd': 'ux-designer',
|
|
309
|
+
'design': 'ux-designer',
|
|
310
|
+
'designer': 'ux-designer',
|
|
311
|
+
'research': 'research-assistant',
|
|
312
|
+
'researcher': 'research-assistant',
|
|
313
|
+
// Engineering
|
|
314
|
+
'frontend': 'web-frontend',
|
|
315
|
+
'fe': 'web-frontend',
|
|
316
|
+
'backend': 'web-backend',
|
|
317
|
+
'api': 'web-backend',
|
|
318
|
+
'devops': 'devops-sre',
|
|
319
|
+
'sre': 'devops-sre',
|
|
320
|
+
'cli': 'cli-tools',
|
|
321
|
+
'data': 'data-engineering',
|
|
322
|
+
'dataeng': 'data-engineering',
|
|
323
|
+
'ml': 'ml-ai',
|
|
324
|
+
'ai': 'ml-ai',
|
|
325
|
+
'qa': 'qa-engineering',
|
|
326
|
+
'test': 'testing',
|
|
327
|
+
'chain': 'blockchain',
|
|
328
|
+
'web3': 'blockchain',
|
|
329
|
+
'platform': 'platform-engineering',
|
|
330
|
+
'platform-eng': 'platform-engineering',
|
|
331
|
+
// Professional
|
|
332
|
+
'docs': 'documentation',
|
|
333
|
+
'grants': 'grant-writer',
|
|
334
|
+
'exec': 'executive-assistant',
|
|
335
|
+
'ea': 'executive-assistant',
|
|
336
|
+
'knowledge': 'knowledge-synthesis',
|
|
337
|
+
'wellness': 'wellness-orchestrator',
|
|
338
|
+
'life': 'life-logistics',
|
|
339
|
+
'logistics': 'life-logistics',
|
|
340
|
+
// Business
|
|
341
|
+
'product': 'product-manager',
|
|
342
|
+
'project': 'project-manager',
|
|
343
|
+
'compliance': 'regulatory-sentinel',
|
|
344
|
+
'regulatory': 'regulatory-sentinel',
|
|
345
|
+
'allocator': 'resource-allocator',
|
|
346
|
+
'resources': 'resource-allocator',
|
|
347
|
+
'market-intel': 'market-intelligence',
|
|
348
|
+
'supplychain': 'supply-chain',
|
|
349
|
+
'harmonizer': 'supply-chain-harmonizer',
|
|
350
|
+
'negotiator': 'strategic-negotiator',
|
|
351
|
+
'predictive': 'predictive-maintenance',
|
|
352
|
+
// Creative
|
|
353
|
+
'brand': 'brand-guardian',
|
|
354
|
+
'narrative': 'narrative-architect',
|
|
355
|
+
'story': 'narrative-architect',
|
|
356
|
+
'trends': 'trend-forecaster',
|
|
357
|
+
// Agents
|
|
358
|
+
'agent': 'utility-agent',
|
|
359
|
+
'utility': 'utility-agent',
|
|
360
|
+
};
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* Resolve a template alias to its canonical name
|
|
364
|
+
* @param {string} name - Template name or alias
|
|
365
|
+
* @returns {string} Canonical template name
|
|
366
|
+
*/
|
|
367
|
+
function resolveTemplateAlias(name) {
|
|
368
|
+
return TEMPLATE_ALIASES[name] || name;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
/**
|
|
372
|
+
* Get the source path for a template's rule files
|
|
373
|
+
* @param {string} template - Template name
|
|
374
|
+
* @param {string} rule - Rule filename
|
|
375
|
+
* @returns {string} Full path to the rule file in templates/<category>/<template>/.cursor/rules/
|
|
376
|
+
*/
|
|
377
|
+
function getTemplateRulePath(template, rule) {
|
|
378
|
+
const { category } = TEMPLATES[template];
|
|
379
|
+
return path.join(TEMPLATES_DIR, category, template, '.cursor', 'rules', rule);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
const SHARED_RULES = [
|
|
383
|
+
'code-quality.mdc',
|
|
384
|
+
'communication.mdc',
|
|
385
|
+
'core-principles.mdc',
|
|
386
|
+
'git-workflow.mdc',
|
|
387
|
+
'security-fundamentals.mdc'
|
|
388
|
+
];
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* Extract the description field from a .mdc file's YAML front matter
|
|
392
|
+
* Falls back to the first heading or the filename.
|
|
393
|
+
* @param {string} filePath - Full path to the .mdc file
|
|
394
|
+
* @returns {string} Description text
|
|
395
|
+
*/
|
|
396
|
+
function extractDescription(filePath) {
|
|
397
|
+
try {
|
|
398
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
399
|
+
const fmMatch = content.match(/^---\s*\n([\s\S]*?)\n---/);
|
|
400
|
+
if (fmMatch) {
|
|
401
|
+
const descMatch = fmMatch[1].match(/description:\s*(.+)/);
|
|
402
|
+
if (descMatch) return descMatch[1].trim();
|
|
403
|
+
}
|
|
404
|
+
const headingMatch = content.match(/^#\s+(.+)/m);
|
|
405
|
+
return headingMatch ? headingMatch[1].trim() : path.basename(filePath, '.mdc');
|
|
406
|
+
} catch {
|
|
407
|
+
return path.basename(filePath, '.mdc');
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
// Supported IDEs/tools
|
|
412
|
+
const SUPPORTED_IDES = ['cursor', 'claude', 'codex'];
|
|
413
|
+
const DEFAULT_IDES = ['cursor', 'claude', 'codex']; // Default: install for all IDEs
|
|
414
|
+
|
|
415
|
+
// Colors
|
|
416
|
+
const colors = {
|
|
417
|
+
red: (s) => `\x1b[31m${s}\x1b[0m`,
|
|
418
|
+
green: (s) => `\x1b[32m${s}\x1b[0m`,
|
|
419
|
+
yellow: (s) => `\x1b[33m${s}\x1b[0m`,
|
|
420
|
+
blue: (s) => `\x1b[34m${s}\x1b[0m`,
|
|
421
|
+
dim: (s) => `\x1b[2m${s}\x1b[0m`,
|
|
422
|
+
cyan: (s) => `\x1b[36m${s}\x1b[0m`,
|
|
423
|
+
};
|
|
424
|
+
|
|
425
|
+
/**
|
|
426
|
+
* Compare two semver version strings
|
|
427
|
+
* @returns {number} -1 if a < b, 0 if a === b, 1 if a > b
|
|
428
|
+
*/
|
|
429
|
+
function compareVersions(a, b) {
|
|
430
|
+
const partsA = a.split('.').map(Number);
|
|
431
|
+
const partsB = b.split('.').map(Number);
|
|
432
|
+
|
|
433
|
+
for (let i = 0; i < 3; i++) {
|
|
434
|
+
const numA = partsA[i] || 0;
|
|
435
|
+
const numB = partsB[i] || 0;
|
|
436
|
+
if (numA < numB) return -1;
|
|
437
|
+
if (numA > numB) return 1;
|
|
438
|
+
}
|
|
439
|
+
return 0;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* Check npm for the latest version and notify if update available
|
|
444
|
+
* Fails silently on network errors
|
|
445
|
+
*/
|
|
446
|
+
async function checkForUpdates() {
|
|
447
|
+
try {
|
|
448
|
+
const { stdout } = await execAsync(`npm view ${PACKAGE_NAME} version`, {
|
|
449
|
+
timeout: 5000, // 5 second timeout
|
|
450
|
+
});
|
|
451
|
+
const latestVersion = stdout.trim();
|
|
452
|
+
|
|
453
|
+
if (compareVersions(CURRENT_VERSION, latestVersion) < 0) {
|
|
454
|
+
console.log(colors.cyan(`
|
|
455
|
+
┌────────────────────────────────────────────────────────────┐
|
|
456
|
+
│ Update available: ${CURRENT_VERSION} → ${latestVersion} │
|
|
457
|
+
│ Run: npx ${PACKAGE_NAME}@latest │
|
|
458
|
+
└────────────────────────────────────────────────────────────┘
|
|
459
|
+
`));
|
|
460
|
+
}
|
|
461
|
+
} catch {
|
|
462
|
+
// Silently ignore network errors or timeouts
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
function printBanner() {
|
|
467
|
+
console.log(colors.blue(`
|
|
468
|
+
╔═══════════════════════════════════════════════════════════╗
|
|
469
|
+
║ Agent Skills Installer ║
|
|
470
|
+
╚═══════════════════════════════════════════════════════════╝
|
|
471
|
+
`));
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
function printHelp() {
|
|
475
|
+
console.log(`${colors.yellow('Usage:')}
|
|
476
|
+
npx @djm204/agent-skills <templates...> [options]
|
|
477
|
+
npx @djm204/agent-skills --remove <templates...> [options]
|
|
478
|
+
npx @djm204/agent-skills --reset [options]
|
|
479
|
+
|
|
480
|
+
${colors.yellow('Options:')}
|
|
481
|
+
--ide=<name> Install for specific IDE (cursor, claude, codex)
|
|
482
|
+
Can be specified multiple times: --ide=cursor --ide=claude
|
|
483
|
+
Default: all (cursor, claude, codex)
|
|
484
|
+
--list, -l List available templates
|
|
485
|
+
--help, -h Show this help message
|
|
486
|
+
--version, -v Show version number
|
|
487
|
+
--dry-run Show what would be changed
|
|
488
|
+
--force, -f Overwrite/remove even if files were modified
|
|
489
|
+
--yes, -y Skip confirmation prompt (for --remove and --reset)
|
|
490
|
+
|
|
491
|
+
${colors.yellow('Removal Options:')}
|
|
492
|
+
--remove Remove specified templates (keeps shared rules and other templates)
|
|
493
|
+
--reset Remove ALL installed content (shared rules, templates, generated files)
|
|
494
|
+
|
|
495
|
+
${colors.yellow('IDE Targets:')}
|
|
496
|
+
cursor .cursor/rules/ directory (Cursor IDE)
|
|
497
|
+
claude CLAUDE.md file (Claude Code, Cursor with Claude)
|
|
498
|
+
codex .github/copilot-instructions.md (GitHub Copilot)
|
|
499
|
+
|
|
500
|
+
${colors.yellow('Shorthand Aliases:')}
|
|
501
|
+
Languages: js, ts, go, py, rs, ruby, rb, swift, kotlin, kt, java, cpp, csharp, cs
|
|
502
|
+
Engineering: frontend, fe, backend, api, devops, sre, cli, data, ml, ai, qa, test, chain, web3, platform
|
|
503
|
+
Professional: docs, grants, exec, ea, knowledge, wellness, life, logistics, research
|
|
504
|
+
Business: product, project, compliance, allocator, market-intel, supplychain, harmonizer, negotiator
|
|
505
|
+
Creative: ux, design, brand, narrative, story, trends, marketing, social-media, content-creation
|
|
506
|
+
Other: unity, teach, teacher, agent, utility
|
|
507
|
+
|
|
508
|
+
Run --list to see full alias → template mapping.
|
|
509
|
+
|
|
510
|
+
${colors.yellow('Examples:')}
|
|
511
|
+
npx @djm204/agent-skills js
|
|
512
|
+
npx @djm204/agent-skills web-frontend
|
|
513
|
+
npx @djm204/agent-skills web-frontend --ide=cursor
|
|
514
|
+
npx @djm204/agent-skills web-frontend --ide=claude --ide=codex
|
|
515
|
+
npx @djm204/agent-skills fullstack --ide=codex
|
|
516
|
+
npx @djm204/agent-skills web-backend --force
|
|
517
|
+
|
|
518
|
+
${colors.yellow('Removal Examples:')}
|
|
519
|
+
npx @djm204/agent-skills --remove web-frontend
|
|
520
|
+
npx @djm204/agent-skills --remove web-frontend web-backend
|
|
521
|
+
npx @djm204/agent-skills --remove web-frontend --ide=cursor
|
|
522
|
+
npx @djm204/agent-skills --reset
|
|
523
|
+
npx @djm204/agent-skills --reset --ide=cursor
|
|
524
|
+
npx @djm204/agent-skills --reset --yes
|
|
525
|
+
|
|
526
|
+
${colors.dim('Shared rules (code-quality, security, git-workflow, etc.) are always included.')}
|
|
527
|
+
${colors.dim('Identical files are skipped. Modified files are preserved; ours saved as *-1.mdc.')}
|
|
528
|
+
${colors.dim('CLAUDE.md: missing sections are intelligently merged (not overwritten).')}
|
|
529
|
+
`);
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
function printTemplates() {
|
|
533
|
+
// Build reverse map: canonical name -> list of aliases
|
|
534
|
+
const aliasesByTemplate = {};
|
|
535
|
+
for (const [alias, canonical] of Object.entries(TEMPLATE_ALIASES)) {
|
|
536
|
+
if (!aliasesByTemplate[canonical]) {
|
|
537
|
+
aliasesByTemplate[canonical] = [];
|
|
538
|
+
}
|
|
539
|
+
aliasesByTemplate[canonical].push(alias);
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
console.log(colors.yellow('Available Templates:\n'));
|
|
543
|
+
|
|
544
|
+
// Group templates by category
|
|
545
|
+
const byCategory = {};
|
|
546
|
+
for (const [name, info] of Object.entries(TEMPLATES)) {
|
|
547
|
+
const cat = info.category;
|
|
548
|
+
if (!byCategory[cat]) byCategory[cat] = [];
|
|
549
|
+
byCategory[cat].push({ name, info });
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
for (const category of CATEGORIES) {
|
|
553
|
+
const templates = byCategory[category];
|
|
554
|
+
if (!templates || templates.length === 0) continue;
|
|
555
|
+
const label = category.charAt(0).toUpperCase() + category.slice(1);
|
|
556
|
+
console.log(colors.blue(` ${label}:`));
|
|
557
|
+
for (const { name, info } of templates) {
|
|
558
|
+
const aliases = aliasesByTemplate[name];
|
|
559
|
+
const aliasSuffix = aliases ? ` ${colors.dim(`(aliases: ${aliases.join(', ')})`)}` : '';
|
|
560
|
+
console.log(` ${colors.green(name)}${aliasSuffix}`);
|
|
561
|
+
console.log(` ${info.description}\n`);
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
console.log(colors.blue('Shared rules (always included):'));
|
|
566
|
+
for (const rule of SHARED_RULES) {
|
|
567
|
+
console.log(` - ${rule.replace('.mdc', '')}`);
|
|
568
|
+
}
|
|
569
|
+
console.log();
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
/**
|
|
573
|
+
* Check if two files have identical content
|
|
574
|
+
*/
|
|
575
|
+
function filesMatch(file1, file2) {
|
|
576
|
+
try {
|
|
577
|
+
const content1 = fs.readFileSync(file1, 'utf8');
|
|
578
|
+
const content2 = fs.readFileSync(file2, 'utf8');
|
|
579
|
+
return content1 === content2;
|
|
580
|
+
} catch {
|
|
581
|
+
return false;
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
/**
|
|
586
|
+
* Parse markdown content into sections by ## headings
|
|
587
|
+
* @param {string} content - Markdown content
|
|
588
|
+
* @returns {Array<{heading: string, content: string, signature: string}>}
|
|
589
|
+
*/
|
|
590
|
+
function parseMarkdownSections(content) {
|
|
591
|
+
const lines = content.split('\n');
|
|
592
|
+
const sections = [];
|
|
593
|
+
let currentSection = null;
|
|
594
|
+
let preamble = [];
|
|
595
|
+
|
|
596
|
+
for (const line of lines) {
|
|
597
|
+
if (line.startsWith('## ')) {
|
|
598
|
+
// Save previous section
|
|
599
|
+
if (currentSection) {
|
|
600
|
+
currentSection.content = currentSection.lines.join('\n');
|
|
601
|
+
currentSection.signature = generateSectionSignature(currentSection.heading, currentSection.lines);
|
|
602
|
+
delete currentSection.lines;
|
|
603
|
+
sections.push(currentSection);
|
|
604
|
+
}
|
|
605
|
+
// Start new section
|
|
606
|
+
currentSection = {
|
|
607
|
+
heading: line.slice(3).trim(),
|
|
608
|
+
lines: []
|
|
609
|
+
};
|
|
610
|
+
} else if (currentSection) {
|
|
611
|
+
currentSection.lines.push(line);
|
|
612
|
+
} else {
|
|
613
|
+
// Content before first ## heading (preamble)
|
|
614
|
+
preamble.push(line);
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
// Don't forget the last section
|
|
619
|
+
if (currentSection) {
|
|
620
|
+
currentSection.content = currentSection.lines.join('\n');
|
|
621
|
+
currentSection.signature = generateSectionSignature(currentSection.heading, currentSection.lines);
|
|
622
|
+
delete currentSection.lines;
|
|
623
|
+
sections.push(currentSection);
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
return { preamble: preamble.join('\n'), sections };
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
/**
|
|
630
|
+
* Generate a signature for a section based on heading + first meaningful lines
|
|
631
|
+
* Used for matching sections even if heading text differs slightly
|
|
632
|
+
* @param {string} heading
|
|
633
|
+
* @param {string[]} lines
|
|
634
|
+
* @returns {string}
|
|
635
|
+
*/
|
|
636
|
+
function generateSectionSignature(heading, lines) {
|
|
637
|
+
// Normalize heading: lowercase, remove special chars, collapse whitespace
|
|
638
|
+
const normalizedHeading = heading.toLowerCase()
|
|
639
|
+
.replace(/[^a-z0-9\s]/g, '')
|
|
640
|
+
.replace(/\s+/g, ' ')
|
|
641
|
+
.trim();
|
|
642
|
+
|
|
643
|
+
// Get first 3 non-empty, non-heading lines for content signature
|
|
644
|
+
const meaningfulLines = lines
|
|
645
|
+
.filter(l => l.trim() && !l.startsWith('#') && !l.startsWith('|') && !l.startsWith('-'))
|
|
646
|
+
.slice(0, 3)
|
|
647
|
+
.map(l => l.toLowerCase().replace(/[^a-z0-9\s]/g, '').replace(/\s+/g, ' ').trim())
|
|
648
|
+
.join(' ');
|
|
649
|
+
|
|
650
|
+
return `${normalizedHeading}::${meaningfulLines.slice(0, 100)}`;
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
/**
|
|
654
|
+
* Find sections from template that are missing in existing content
|
|
655
|
+
* @param {string} existingContent
|
|
656
|
+
* @param {string} templateContent
|
|
657
|
+
* @returns {{missing: Array<{heading: string, content: string}>, matchedCount: number}}
|
|
658
|
+
*/
|
|
659
|
+
function findMissingSections(existingContent, templateContent) {
|
|
660
|
+
const existing = parseMarkdownSections(existingContent);
|
|
661
|
+
const template = parseMarkdownSections(templateContent);
|
|
662
|
+
|
|
663
|
+
const existingSignatures = new Set(existing.sections.map(s => s.signature));
|
|
664
|
+
const existingHeadings = new Set(existing.sections.map(s => s.heading.toLowerCase()));
|
|
665
|
+
|
|
666
|
+
const missing = [];
|
|
667
|
+
let matchedCount = 0;
|
|
668
|
+
|
|
669
|
+
for (const section of template.sections) {
|
|
670
|
+
// Check by signature first (heading + content), then by heading alone
|
|
671
|
+
const signatureMatch = existingSignatures.has(section.signature);
|
|
672
|
+
const headingMatch = existingHeadings.has(section.heading.toLowerCase());
|
|
673
|
+
|
|
674
|
+
if (signatureMatch || headingMatch) {
|
|
675
|
+
matchedCount++;
|
|
676
|
+
} else {
|
|
677
|
+
missing.push(section);
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
return { missing, matchedCount };
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
/**
|
|
685
|
+
* Merge template sections into existing content, inserting missing sections in template order
|
|
686
|
+
* @param {string} existingContent
|
|
687
|
+
* @param {string} templateContent
|
|
688
|
+
* @returns {{merged: string, addedSections: string[]}}
|
|
689
|
+
*/
|
|
690
|
+
function mergeClaudeContent(existingContent, templateContent) {
|
|
691
|
+
const existing = parseMarkdownSections(existingContent);
|
|
692
|
+
const template = parseMarkdownSections(templateContent);
|
|
693
|
+
const { missing } = findMissingSections(existingContent, templateContent);
|
|
694
|
+
|
|
695
|
+
if (missing.length === 0) {
|
|
696
|
+
return { merged: existingContent, addedSections: [] };
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
// Build a map of existing sections by normalized heading for insertion point lookup
|
|
700
|
+
const existingByHeading = new Map();
|
|
701
|
+
existing.sections.forEach((s, i) => {
|
|
702
|
+
existingByHeading.set(s.heading.toLowerCase(), i);
|
|
703
|
+
});
|
|
704
|
+
|
|
705
|
+
// Find template section order and determine where to insert missing sections
|
|
706
|
+
const templateOrder = template.sections.map(s => s.heading.toLowerCase());
|
|
707
|
+
|
|
708
|
+
// For each missing section, find the best insertion point based on template order
|
|
709
|
+
const insertions = []; // { afterIndex: number, section: section }
|
|
710
|
+
|
|
711
|
+
for (const missingSection of missing) {
|
|
712
|
+
const missingIndex = templateOrder.indexOf(missingSection.heading.toLowerCase());
|
|
713
|
+
|
|
714
|
+
// Find the closest preceding section that exists in the existing content
|
|
715
|
+
let insertAfterIndex = -1; // -1 means insert at beginning (after preamble)
|
|
716
|
+
|
|
717
|
+
for (let i = missingIndex - 1; i >= 0; i--) {
|
|
718
|
+
const precedingHeading = templateOrder[i];
|
|
719
|
+
if (existingByHeading.has(precedingHeading)) {
|
|
720
|
+
insertAfterIndex = existingByHeading.get(precedingHeading);
|
|
721
|
+
break;
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
insertions.push({ afterIndex: insertAfterIndex, section: missingSection });
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
// Sort insertions by afterIndex (descending) so we insert from bottom to top
|
|
729
|
+
// This preserves indices as we insert
|
|
730
|
+
insertions.sort((a, b) => b.afterIndex - a.afterIndex);
|
|
731
|
+
|
|
732
|
+
// Build the merged content
|
|
733
|
+
const mergedSections = [...existing.sections];
|
|
734
|
+
const addedSections = [];
|
|
735
|
+
|
|
736
|
+
for (const { afterIndex, section } of insertions) {
|
|
737
|
+
const insertAt = afterIndex + 1;
|
|
738
|
+
mergedSections.splice(insertAt, 0, section);
|
|
739
|
+
addedSections.push(section.heading);
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
// Reconstruct the markdown
|
|
743
|
+
let merged = existing.preamble;
|
|
744
|
+
if (merged && !merged.endsWith('\n\n')) {
|
|
745
|
+
merged = merged.trimEnd() + '\n\n';
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
for (const section of mergedSections) {
|
|
749
|
+
merged += `## ${section.heading}\n${section.content}\n`;
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
// addedSections is in reverse order due to sorting, reverse it back
|
|
753
|
+
addedSections.reverse();
|
|
754
|
+
|
|
755
|
+
return { merged: merged.trimEnd() + '\n', addedSections };
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
/**
|
|
759
|
+
* Get alternate filename with -1 suffix (e.g., code-quality.mdc -> code-quality-1.mdc)
|
|
760
|
+
*/
|
|
761
|
+
function getAlternateFilename(filepath) {
|
|
762
|
+
const dir = path.dirname(filepath);
|
|
763
|
+
const ext = path.extname(filepath);
|
|
764
|
+
const base = path.basename(filepath, ext);
|
|
765
|
+
return path.join(dir, `${base}-1${ext}`);
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
/**
|
|
769
|
+
* Copy file, handling existing files intelligently
|
|
770
|
+
* @returns {{ status: string, destFile: string }}
|
|
771
|
+
* status: 'copied' | 'skipped' | 'renamed' | 'updated'
|
|
772
|
+
* destFile: actual destination path (may differ if renamed)
|
|
773
|
+
*/
|
|
774
|
+
function copyFile(src, dest, force = false) {
|
|
775
|
+
const destDir = path.dirname(dest);
|
|
776
|
+
if (!fs.existsSync(destDir)) {
|
|
777
|
+
fs.mkdirSync(destDir, { recursive: true });
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
const exists = fs.existsSync(dest);
|
|
781
|
+
|
|
782
|
+
if (!exists) {
|
|
783
|
+
// File doesn't exist - copy normally
|
|
784
|
+
fs.copyFileSync(src, dest);
|
|
785
|
+
return { status: 'copied', destFile: dest };
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
if (force) {
|
|
789
|
+
// Force mode - overwrite
|
|
790
|
+
fs.copyFileSync(src, dest);
|
|
791
|
+
return { status: 'updated', destFile: dest };
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
// File exists - check if it matches our template
|
|
795
|
+
if (filesMatch(src, dest)) {
|
|
796
|
+
// Same content - skip
|
|
797
|
+
return { status: 'skipped', destFile: dest };
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
// Different content - save ours alongside with -1 suffix
|
|
801
|
+
const altDest = getAlternateFilename(dest);
|
|
802
|
+
fs.copyFileSync(src, altDest);
|
|
803
|
+
return { status: 'renamed', destFile: altDest };
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
function generateClaudeMdContent(installedTemplates) {
|
|
807
|
+
const templateList = installedTemplates
|
|
808
|
+
.map(t => `- **${t}**: ${TEMPLATES[t].description}`)
|
|
809
|
+
.join('\n');
|
|
810
|
+
|
|
811
|
+
const templateRuleTables = installedTemplates.map(template => {
|
|
812
|
+
const rules = TEMPLATES[template].rules
|
|
813
|
+
.map(rule => `| \`${template}-${rule}\` | ${rule.replace('.mdc', '').replace(/-/g, ' ')} guidelines |`)
|
|
814
|
+
.join('\n');
|
|
815
|
+
|
|
816
|
+
return `
|
|
817
|
+
#### ${template.charAt(0).toUpperCase() + template.slice(1)} Rules
|
|
818
|
+
|
|
819
|
+
| Rule | Purpose |
|
|
820
|
+
|------|---------|
|
|
821
|
+
${rules}`;
|
|
822
|
+
}).join('\n');
|
|
823
|
+
|
|
824
|
+
return `# CLAUDE.md - Development Guide
|
|
825
|
+
|
|
826
|
+
This project uses AI-assisted development. Rules in \`.cursor/rules/\` provide guidance.
|
|
827
|
+
|
|
828
|
+
## Installed Templates
|
|
829
|
+
|
|
830
|
+
- **Shared** (always included): Core principles, code quality, security, git workflow, communication
|
|
831
|
+
${templateList}
|
|
832
|
+
|
|
833
|
+
## Rule Files
|
|
834
|
+
|
|
835
|
+
All rules are in \`.cursor/rules/\`. The AI assistant reads these automatically.
|
|
836
|
+
|
|
837
|
+
#### Shared Rules
|
|
838
|
+
|
|
839
|
+
| Rule | Purpose |
|
|
840
|
+
|------|---------|
|
|
841
|
+
| \`core-principles.mdc\` | Honesty, simplicity, testing requirements |
|
|
842
|
+
| \`code-quality.mdc\` | SOLID, DRY, clean code patterns |
|
|
843
|
+
| \`security-fundamentals.mdc\` | Zero trust, input validation, secrets |
|
|
844
|
+
| \`git-workflow.mdc\` | Commits, branches, PRs, safety |
|
|
845
|
+
| \`communication.mdc\` | Direct, objective, professional |
|
|
846
|
+
${templateRuleTables}
|
|
847
|
+
|
|
848
|
+
## Customization
|
|
849
|
+
|
|
850
|
+
- Create new \`.mdc\` files in \`.cursor/rules/\` for project-specific rules
|
|
851
|
+
- Edit existing files directly; changes take effect immediately
|
|
852
|
+
- Re-run to update: \`npx @djm204/agent-skills ${installedTemplates.join(' ')}\`
|
|
853
|
+
`;
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
function generateClaudeMd(targetDir, installedTemplates) {
|
|
857
|
+
const content = generateClaudeMdContent(installedTemplates);
|
|
858
|
+
fs.writeFileSync(path.join(targetDir, 'CLAUDE.md'), content);
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
function generateClaudeMdToPath(targetDir, installedTemplates, destPath) {
|
|
862
|
+
const content = generateClaudeMdContent(installedTemplates);
|
|
863
|
+
fs.writeFileSync(destPath, content);
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
/**
|
|
867
|
+
* Generate content for GitHub Copilot instructions file.
|
|
868
|
+
* Uses description-based summaries instead of full content concatenation
|
|
869
|
+
* to keep the file within context window limits.
|
|
870
|
+
*/
|
|
871
|
+
function generateCopilotInstructionsContent(installedTemplates) {
|
|
872
|
+
// Build shared rules table with descriptions from front matter
|
|
873
|
+
const sharedRulesTable = SHARED_RULES.map(rule => {
|
|
874
|
+
const rulePath = path.join(TEMPLATES_DIR, '_shared', rule);
|
|
875
|
+
const desc = extractDescription(rulePath);
|
|
876
|
+
return `| \`${rule}\` | ${desc} |`;
|
|
877
|
+
}).join('\n');
|
|
878
|
+
|
|
879
|
+
// Build template rules tables with descriptions from front matter
|
|
880
|
+
const templateTables = installedTemplates.map(template => {
|
|
881
|
+
const rulesRows = TEMPLATES[template].rules.map(rule => {
|
|
882
|
+
const rulePath = getTemplateRulePath(template, rule);
|
|
883
|
+
const desc = extractDescription(rulePath);
|
|
884
|
+
return `| \`${rule}\` | ${desc} |`;
|
|
885
|
+
}).join('\n');
|
|
886
|
+
|
|
887
|
+
return `### ${template}
|
|
888
|
+
|
|
889
|
+
${TEMPLATES[template].description}
|
|
890
|
+
|
|
891
|
+
| Rule | Guidance |
|
|
892
|
+
|------|----------|
|
|
893
|
+
${rulesRows}`;
|
|
894
|
+
}).join('\n\n');
|
|
895
|
+
|
|
896
|
+
return `# Copilot Instructions
|
|
897
|
+
|
|
898
|
+
Guidelines for GitHub Copilot in this project. Full rules are in \`.cursor/rules/\`.
|
|
899
|
+
|
|
900
|
+
## Project Configuration
|
|
901
|
+
|
|
902
|
+
**Installed Templates:** ${installedTemplates.join(', ')}
|
|
903
|
+
|
|
904
|
+
## Core Principles
|
|
905
|
+
|
|
906
|
+
- **Honesty over output**: Say what works and what doesn't; admit uncertainty
|
|
907
|
+
- **Security first**: Zero trust, validate all inputs, no secrets in code
|
|
908
|
+
- **Tests required**: No feature ships without tests; test behavior, not implementation
|
|
909
|
+
- **Code quality**: SOLID, DRY, explicit over implicit
|
|
910
|
+
|
|
911
|
+
## Shared Rules
|
|
912
|
+
|
|
913
|
+
| Rule | Guidance |
|
|
914
|
+
|------|----------|
|
|
915
|
+
${sharedRulesTable}
|
|
916
|
+
|
|
917
|
+
## Template Rules
|
|
918
|
+
|
|
919
|
+
${templateTables}
|
|
920
|
+
`;
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
async function install(targetDir, templates, dryRun = false, force = false, ides = DEFAULT_IDES, skipConfirm = false) {
|
|
924
|
+
const stats = { copied: 0, skipped: 0, updated: 0, renamed: 0 };
|
|
925
|
+
const renamedFiles = [];
|
|
926
|
+
const installedFor = [];
|
|
927
|
+
|
|
928
|
+
console.log(`${colors.blue('Installing to:')} ${targetDir}`);
|
|
929
|
+
console.log(`${colors.blue('Target IDEs:')} ${ides.join(', ')}`);
|
|
930
|
+
if (!force) {
|
|
931
|
+
console.log(colors.dim('(identical files skipped, modified files preserved with ours saved as *-1.mdc)'));
|
|
932
|
+
}
|
|
933
|
+
console.log();
|
|
934
|
+
|
|
935
|
+
// 1. Install .cursor/rules/ for Cursor IDE
|
|
936
|
+
if (ides.includes('cursor')) {
|
|
937
|
+
installedFor.push('cursor');
|
|
938
|
+
const cursorRulesDir = path.join(targetDir, CURSOR_RULES_DIR);
|
|
939
|
+
|
|
940
|
+
if (!dryRun && !fs.existsSync(cursorRulesDir)) {
|
|
941
|
+
fs.mkdirSync(cursorRulesDir, { recursive: true });
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
// Install shared rules
|
|
945
|
+
console.log(colors.green(`► Installing shared rules (${CURSOR_RULES_DIR}/)...`));
|
|
946
|
+
for (const rule of SHARED_RULES) {
|
|
947
|
+
const src = path.join(TEMPLATES_DIR, '_shared', rule);
|
|
948
|
+
const dest = path.join(cursorRulesDir, rule);
|
|
949
|
+
|
|
950
|
+
if (dryRun) {
|
|
951
|
+
const exists = fs.existsSync(dest);
|
|
952
|
+
if (!exists) {
|
|
953
|
+
console.log(` ${colors.dim('[copy]')} ${rule}`);
|
|
954
|
+
} else if (force) {
|
|
955
|
+
console.log(` ${colors.dim('[update]')} ${rule}`);
|
|
956
|
+
} else if (filesMatch(src, dest)) {
|
|
957
|
+
console.log(` ${colors.yellow('[skip]')} ${rule} (identical)`);
|
|
958
|
+
} else {
|
|
959
|
+
const altName = path.basename(getAlternateFilename(dest));
|
|
960
|
+
console.log(` ${colors.blue('[rename]')} ${rule} → ${altName}`);
|
|
961
|
+
}
|
|
962
|
+
} else {
|
|
963
|
+
const result = copyFile(src, dest, force);
|
|
964
|
+
stats[result.status]++;
|
|
965
|
+
if (result.status === 'skipped') {
|
|
966
|
+
console.log(` ${colors.yellow('[skip]')} ${rule} (identical)`);
|
|
967
|
+
} else if (result.status === 'renamed') {
|
|
968
|
+
const altName = path.basename(result.destFile);
|
|
969
|
+
renamedFiles.push({ original: rule, renamed: altName });
|
|
970
|
+
console.log(` ${colors.blue('[rename]')} ${rule} → ${altName}`);
|
|
971
|
+
} else {
|
|
972
|
+
console.log(` ${colors.dim(`[${result.status}]`)} ${rule}`);
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
console.log();
|
|
977
|
+
|
|
978
|
+
// Install template-specific rules
|
|
979
|
+
for (const template of templates) {
|
|
980
|
+
console.log(colors.green(`► Installing ${template} template (${CURSOR_RULES_DIR}/)...`));
|
|
981
|
+
|
|
982
|
+
for (const rule of TEMPLATES[template].rules) {
|
|
983
|
+
const src = getTemplateRulePath(template, rule);
|
|
984
|
+
const dest = path.join(cursorRulesDir, `${template}-${rule}`);
|
|
985
|
+
const destName = `${template}-${rule}`;
|
|
986
|
+
|
|
987
|
+
if (dryRun) {
|
|
988
|
+
const exists = fs.existsSync(dest);
|
|
989
|
+
if (!exists) {
|
|
990
|
+
console.log(` ${colors.dim('[copy]')} ${destName}`);
|
|
991
|
+
} else if (force) {
|
|
992
|
+
console.log(` ${colors.dim('[update]')} ${destName}`);
|
|
993
|
+
} else if (filesMatch(src, dest)) {
|
|
994
|
+
console.log(` ${colors.yellow('[skip]')} ${destName} (identical)`);
|
|
995
|
+
} else {
|
|
996
|
+
const altName = path.basename(getAlternateFilename(dest));
|
|
997
|
+
console.log(` ${colors.blue('[rename]')} ${destName} → ${altName}`);
|
|
998
|
+
}
|
|
999
|
+
} else {
|
|
1000
|
+
const result = copyFile(src, dest, force);
|
|
1001
|
+
stats[result.status]++;
|
|
1002
|
+
if (result.status === 'skipped') {
|
|
1003
|
+
console.log(` ${colors.yellow('[skip]')} ${destName} (identical)`);
|
|
1004
|
+
} else if (result.status === 'renamed') {
|
|
1005
|
+
const altName = path.basename(result.destFile);
|
|
1006
|
+
renamedFiles.push({ original: destName, renamed: altName });
|
|
1007
|
+
console.log(` ${colors.blue('[rename]')} ${destName} → ${altName}`);
|
|
1008
|
+
} else {
|
|
1009
|
+
console.log(` ${colors.dim(`[${result.status}]`)} ${destName}`);
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
console.log();
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
// Legacy .cursorrules/ detection and cleanup
|
|
1017
|
+
const legacyDir = path.join(targetDir, LEGACY_CURSORRULES_DIR);
|
|
1018
|
+
if (fs.existsSync(legacyDir)) {
|
|
1019
|
+
console.log(colors.yellow(`⚠ Deprecated ${LEGACY_CURSORRULES_DIR}/ directory detected.`));
|
|
1020
|
+
console.log(colors.yellow(` Cursor now uses ${CURSOR_RULES_DIR}/ for rule files.`));
|
|
1021
|
+
console.log(colors.yellow(` New rules have been installed to ${CURSOR_RULES_DIR}/.`));
|
|
1022
|
+
console.log();
|
|
1023
|
+
console.log(colors.yellow(` Your existing ${LEGACY_CURSORRULES_DIR}/ files are still present.`));
|
|
1024
|
+
console.log(colors.yellow(` Support for ${LEGACY_CURSORRULES_DIR}/ will be removed in a future version.`));
|
|
1025
|
+
console.log();
|
|
1026
|
+
|
|
1027
|
+
if (!dryRun) {
|
|
1028
|
+
const shouldCleanup = skipConfirm || await confirm(
|
|
1029
|
+
colors.yellow(`? Would you like to remove the deprecated ${LEGACY_CURSORRULES_DIR}/ directory?`)
|
|
1030
|
+
);
|
|
1031
|
+
|
|
1032
|
+
if (shouldCleanup) {
|
|
1033
|
+
// Copy legacy rule files to .cursor/rules/ before removing (don't overwrite existing)
|
|
1034
|
+
const legacyEntries = fs.readdirSync(legacyDir, { withFileTypes: true });
|
|
1035
|
+
let copiedCount = 0;
|
|
1036
|
+
for (const entry of legacyEntries) {
|
|
1037
|
+
if (!entry.isFile()) continue;
|
|
1038
|
+
const name = entry.name;
|
|
1039
|
+
const legacyPath = path.join(legacyDir, name);
|
|
1040
|
+
const destPath = path.join(cursorRulesDir, name);
|
|
1041
|
+
if (!fs.existsSync(destPath)) {
|
|
1042
|
+
fs.copyFileSync(legacyPath, destPath);
|
|
1043
|
+
console.log(colors.dim(` ${colors.green('[migrated]')} ${name} → ${CURSOR_RULES_DIR}/`));
|
|
1044
|
+
copiedCount++;
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
if (copiedCount > 0) {
|
|
1048
|
+
console.log(colors.green(` ✓ Migrated ${copiedCount} file(s) from ${LEGACY_CURSORRULES_DIR}/ to ${CURSOR_RULES_DIR}/.`));
|
|
1049
|
+
}
|
|
1050
|
+
fs.rmSync(legacyDir, { recursive: true });
|
|
1051
|
+
console.log(colors.green(` ✓ Removed deprecated ${LEGACY_CURSORRULES_DIR}/ directory.`));
|
|
1052
|
+
} else {
|
|
1053
|
+
// Create reference file so Cursor AI knows about legacy rules
|
|
1054
|
+
const noticePath = path.join(cursorRulesDir, 'legacy-cursorrules-notice.md');
|
|
1055
|
+
const noticeContent = `# Legacy Rules Notice
|
|
1056
|
+
|
|
1057
|
+
This project contains additional rule files in the deprecated \`.cursorrules/\` directory
|
|
1058
|
+
at the project root. Those rules are still active and should be consulted alongside the
|
|
1059
|
+
rules in this directory.
|
|
1060
|
+
|
|
1061
|
+
The \`.cursorrules/\` directory will be removed in a future version.
|
|
1062
|
+
To clean up manually, move any custom rules to \`.cursor/rules/\` and delete \`.cursorrules/\`.
|
|
1063
|
+
`;
|
|
1064
|
+
fs.writeFileSync(noticePath, noticeContent);
|
|
1065
|
+
console.log(colors.dim(` Created ${CURSOR_RULES_DIR}/legacy-cursorrules-notice.md as a reference.`));
|
|
1066
|
+
}
|
|
1067
|
+
} else {
|
|
1068
|
+
console.log(colors.dim(' (dry-run: skipping cleanup prompt)'));
|
|
1069
|
+
}
|
|
1070
|
+
console.log();
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
// 2. Generate CLAUDE.md for Claude Code
|
|
1075
|
+
if (ides.includes('claude')) {
|
|
1076
|
+
installedFor.push('claude');
|
|
1077
|
+
const claudePath = path.join(targetDir, 'CLAUDE.md');
|
|
1078
|
+
const claudeExists = fs.existsSync(claudePath);
|
|
1079
|
+
const templateContent = generateClaudeMdContent(templates);
|
|
1080
|
+
|
|
1081
|
+
console.log(colors.green('► Generating CLAUDE.md (Claude Code)...'));
|
|
1082
|
+
if (dryRun) {
|
|
1083
|
+
if (!claudeExists) {
|
|
1084
|
+
console.log(` ${colors.dim('[copy]')} CLAUDE.md`);
|
|
1085
|
+
} else if (force) {
|
|
1086
|
+
console.log(` ${colors.dim('[update]')} CLAUDE.md`);
|
|
1087
|
+
} else {
|
|
1088
|
+
const existingContent = fs.readFileSync(claudePath, 'utf8');
|
|
1089
|
+
const { missing } = findMissingSections(existingContent, templateContent);
|
|
1090
|
+
if (missing.length === 0) {
|
|
1091
|
+
console.log(` ${colors.yellow('[skip]')} CLAUDE.md (all sections present)`);
|
|
1092
|
+
} else {
|
|
1093
|
+
console.log(` ${colors.blue('[merge]')} CLAUDE.md (would add ${missing.length} section(s))`);
|
|
1094
|
+
for (const section of missing) {
|
|
1095
|
+
console.log(` ${colors.dim('+')} ${section.heading}`);
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
} else if (!claudeExists) {
|
|
1100
|
+
fs.writeFileSync(claudePath, templateContent);
|
|
1101
|
+
console.log(` ${colors.dim('[copied]')} CLAUDE.md`);
|
|
1102
|
+
stats.copied++;
|
|
1103
|
+
} else if (force) {
|
|
1104
|
+
fs.writeFileSync(claudePath, templateContent);
|
|
1105
|
+
console.log(` ${colors.dim('[updated]')} CLAUDE.md`);
|
|
1106
|
+
stats.updated++;
|
|
1107
|
+
} else {
|
|
1108
|
+
const existingContent = fs.readFileSync(claudePath, 'utf8');
|
|
1109
|
+
const { merged, addedSections } = mergeClaudeContent(existingContent, templateContent);
|
|
1110
|
+
|
|
1111
|
+
if (addedSections.length === 0) {
|
|
1112
|
+
console.log(` ${colors.yellow('[skip]')} CLAUDE.md (all sections present)`);
|
|
1113
|
+
stats.skipped++;
|
|
1114
|
+
} else {
|
|
1115
|
+
fs.writeFileSync(claudePath, merged);
|
|
1116
|
+
console.log(` ${colors.blue('[merged]')} CLAUDE.md`);
|
|
1117
|
+
console.log(` ${colors.green('Added sections:')}`);
|
|
1118
|
+
for (const heading of addedSections) {
|
|
1119
|
+
console.log(` ${colors.dim('+')} ${heading}`);
|
|
1120
|
+
}
|
|
1121
|
+
stats.updated++;
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
console.log();
|
|
1125
|
+
}
|
|
1126
|
+
|
|
1127
|
+
// 3. Generate .github/copilot-instructions.md for GitHub Copilot (Codex)
|
|
1128
|
+
if (ides.includes('codex')) {
|
|
1129
|
+
installedFor.push('codex');
|
|
1130
|
+
const githubDir = path.join(targetDir, '.github');
|
|
1131
|
+
const copilotPath = path.join(githubDir, 'copilot-instructions.md');
|
|
1132
|
+
const copilotExists = fs.existsSync(copilotPath);
|
|
1133
|
+
const copilotContent = generateCopilotInstructionsContent(templates);
|
|
1134
|
+
|
|
1135
|
+
if (!dryRun && !fs.existsSync(githubDir)) {
|
|
1136
|
+
fs.mkdirSync(githubDir, { recursive: true });
|
|
1137
|
+
}
|
|
1138
|
+
|
|
1139
|
+
console.log(colors.green('► Generating .github/copilot-instructions.md (GitHub Copilot)...'));
|
|
1140
|
+
if (dryRun) {
|
|
1141
|
+
if (!copilotExists) {
|
|
1142
|
+
console.log(` ${colors.dim('[copy]')} .github/copilot-instructions.md`);
|
|
1143
|
+
} else if (force) {
|
|
1144
|
+
console.log(` ${colors.dim('[update]')} .github/copilot-instructions.md`);
|
|
1145
|
+
} else {
|
|
1146
|
+
const existingContent = fs.readFileSync(copilotPath, 'utf8');
|
|
1147
|
+
const { missing } = findMissingSections(existingContent, copilotContent);
|
|
1148
|
+
if (missing.length === 0) {
|
|
1149
|
+
console.log(` ${colors.yellow('[skip]')} .github/copilot-instructions.md (all sections present)`);
|
|
1150
|
+
} else {
|
|
1151
|
+
console.log(` ${colors.blue('[merge]')} .github/copilot-instructions.md (would add ${missing.length} section(s))`);
|
|
1152
|
+
}
|
|
1153
|
+
}
|
|
1154
|
+
} else if (!copilotExists) {
|
|
1155
|
+
fs.writeFileSync(copilotPath, copilotContent);
|
|
1156
|
+
console.log(` ${colors.dim('[copied]')} .github/copilot-instructions.md`);
|
|
1157
|
+
stats.copied++;
|
|
1158
|
+
} else if (force) {
|
|
1159
|
+
fs.writeFileSync(copilotPath, copilotContent);
|
|
1160
|
+
console.log(` ${colors.dim('[updated]')} .github/copilot-instructions.md`);
|
|
1161
|
+
stats.updated++;
|
|
1162
|
+
} else {
|
|
1163
|
+
const existingContent = fs.readFileSync(copilotPath, 'utf8');
|
|
1164
|
+
const { merged, addedSections } = mergeClaudeContent(existingContent, copilotContent);
|
|
1165
|
+
|
|
1166
|
+
if (addedSections.length === 0) {
|
|
1167
|
+
console.log(` ${colors.yellow('[skip]')} .github/copilot-instructions.md (all sections present)`);
|
|
1168
|
+
stats.skipped++;
|
|
1169
|
+
} else {
|
|
1170
|
+
fs.writeFileSync(copilotPath, merged);
|
|
1171
|
+
console.log(` ${colors.blue('[merged]')} .github/copilot-instructions.md`);
|
|
1172
|
+
stats.updated++;
|
|
1173
|
+
}
|
|
1174
|
+
}
|
|
1175
|
+
console.log();
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1178
|
+
// Summary
|
|
1179
|
+
console.log(colors.green('════════════════════════════════════════════════════════════'));
|
|
1180
|
+
console.log(colors.green('✓ Installation complete!\n'));
|
|
1181
|
+
|
|
1182
|
+
console.log(colors.yellow('Summary:'));
|
|
1183
|
+
console.log(` - ${stats.copied} files created`);
|
|
1184
|
+
if (stats.updated > 0) {
|
|
1185
|
+
console.log(` - ${stats.updated} files updated`);
|
|
1186
|
+
}
|
|
1187
|
+
if (stats.skipped > 0) {
|
|
1188
|
+
console.log(` - ${stats.skipped} files skipped (identical to template)`);
|
|
1189
|
+
}
|
|
1190
|
+
if (stats.renamed > 0) {
|
|
1191
|
+
console.log(` - ${colors.blue(`${stats.renamed} files saved as *-1.mdc`)} (yours preserved)`);
|
|
1192
|
+
}
|
|
1193
|
+
console.log();
|
|
1194
|
+
|
|
1195
|
+
console.log(colors.yellow('Installed for:'));
|
|
1196
|
+
for (const ide of installedFor) {
|
|
1197
|
+
const ideInfo = {
|
|
1198
|
+
cursor: '.cursor/rules/ (Cursor IDE)',
|
|
1199
|
+
claude: 'CLAUDE.md (Claude Code)',
|
|
1200
|
+
codex: '.github/copilot-instructions.md (GitHub Copilot)'
|
|
1201
|
+
};
|
|
1202
|
+
console.log(` - ${ideInfo[ide]}`);
|
|
1203
|
+
}
|
|
1204
|
+
console.log();
|
|
1205
|
+
|
|
1206
|
+
console.log(colors.yellow('Templates:'));
|
|
1207
|
+
console.log(' - _shared (always included)');
|
|
1208
|
+
for (const template of templates) {
|
|
1209
|
+
console.log(` - ${template}`);
|
|
1210
|
+
}
|
|
1211
|
+
console.log();
|
|
1212
|
+
|
|
1213
|
+
if (renamedFiles.length > 0) {
|
|
1214
|
+
console.log(colors.blue('Files saved alongside existing (your files preserved):'));
|
|
1215
|
+
for (const { original, renamed } of renamedFiles) {
|
|
1216
|
+
console.log(` - ${original} → ${renamed}`);
|
|
1217
|
+
}
|
|
1218
|
+
console.log(colors.dim('\nReview the -1 files and merge changes as needed.'));
|
|
1219
|
+
console.log(colors.dim('Use --force to overwrite existing files instead.'));
|
|
1220
|
+
console.log();
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1223
|
+
console.log(colors.blue('Next steps:'));
|
|
1224
|
+
if (installedFor.includes('claude')) {
|
|
1225
|
+
console.log(' 1. Review CLAUDE.md for any customization');
|
|
1226
|
+
}
|
|
1227
|
+
if (installedFor.includes('codex')) {
|
|
1228
|
+
console.log(' 2. Review .github/copilot-instructions.md');
|
|
1229
|
+
}
|
|
1230
|
+
console.log(' 3. Commit the new files to your repository');
|
|
1231
|
+
console.log();
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1234
|
+
/**
|
|
1235
|
+
* Prompt user for confirmation
|
|
1236
|
+
* @param {string} message - The prompt message
|
|
1237
|
+
* @returns {Promise<boolean>}
|
|
1238
|
+
*/
|
|
1239
|
+
async function confirm(message) {
|
|
1240
|
+
const readline = await import('readline');
|
|
1241
|
+
const rl = readline.createInterface({
|
|
1242
|
+
input: process.stdin,
|
|
1243
|
+
output: process.stdout
|
|
1244
|
+
});
|
|
1245
|
+
|
|
1246
|
+
return new Promise((resolve) => {
|
|
1247
|
+
rl.question(`${message} [y/N] `, (answer) => {
|
|
1248
|
+
rl.close();
|
|
1249
|
+
resolve(answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes');
|
|
1250
|
+
});
|
|
1251
|
+
});
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
/**
|
|
1255
|
+
* Check if a file was created by our installer (matches template content)
|
|
1256
|
+
* @param {string} filePath - Path to the file
|
|
1257
|
+
* @param {string} templatePath - Path to the template file
|
|
1258
|
+
* @returns {boolean}
|
|
1259
|
+
*/
|
|
1260
|
+
function isOurFile(filePath, templatePath) {
|
|
1261
|
+
if (!fs.existsSync(filePath)) return false;
|
|
1262
|
+
if (!fs.existsSync(templatePath)) return true; // No template to compare, assume ours
|
|
1263
|
+
return filesMatch(filePath, templatePath);
|
|
1264
|
+
}
|
|
1265
|
+
|
|
1266
|
+
/**
|
|
1267
|
+
* Remove specific templates from the installation
|
|
1268
|
+
*/
|
|
1269
|
+
async function remove(targetDir, templates, dryRun = false, force = false, skipConfirm = false, ides = DEFAULT_IDES) {
|
|
1270
|
+
const stats = { removed: 0, skipped: 0, notFound: 0 };
|
|
1271
|
+
const filesToRemove = [];
|
|
1272
|
+
const modifiedFiles = [];
|
|
1273
|
+
|
|
1274
|
+
console.log(`${colors.blue('Removing from:')} ${targetDir}`);
|
|
1275
|
+
console.log(`${colors.blue('Target IDEs:')} ${ides.join(', ')}`);
|
|
1276
|
+
console.log(`${colors.blue('Templates:')} ${templates.join(', ')}`);
|
|
1277
|
+
console.log();
|
|
1278
|
+
|
|
1279
|
+
// 1. Collect files to remove from .cursor/rules/ (and legacy .cursorrules/)
|
|
1280
|
+
if (ides.includes('cursor')) {
|
|
1281
|
+
const cursorRulesDir = path.join(targetDir, CURSOR_RULES_DIR);
|
|
1282
|
+
const legacyDir = path.join(targetDir, LEGACY_CURSORRULES_DIR);
|
|
1283
|
+
const dirsToScan = [];
|
|
1284
|
+
|
|
1285
|
+
if (fs.existsSync(cursorRulesDir)) dirsToScan.push({ dir: cursorRulesDir, label: CURSOR_RULES_DIR });
|
|
1286
|
+
if (fs.existsSync(legacyDir)) dirsToScan.push({ dir: legacyDir, label: LEGACY_CURSORRULES_DIR });
|
|
1287
|
+
|
|
1288
|
+
if (dirsToScan.length > 0) {
|
|
1289
|
+
for (const template of templates) {
|
|
1290
|
+
console.log(colors.yellow(`► Scanning ${template} template files...`));
|
|
1291
|
+
|
|
1292
|
+
for (const { dir, label } of dirsToScan) {
|
|
1293
|
+
for (const rule of TEMPLATES[template].rules) {
|
|
1294
|
+
const destName = `${template}-${rule}`;
|
|
1295
|
+
const destPath = path.join(dir, destName);
|
|
1296
|
+
const srcPath = getTemplateRulePath(template, rule);
|
|
1297
|
+
|
|
1298
|
+
if (!fs.existsSync(destPath)) {
|
|
1299
|
+
continue;
|
|
1300
|
+
}
|
|
1301
|
+
|
|
1302
|
+
const isUnmodified = isOurFile(destPath, srcPath);
|
|
1303
|
+
const displayName = `${destName} (${label}/)`;
|
|
1304
|
+
|
|
1305
|
+
if (!isUnmodified && !force) {
|
|
1306
|
+
console.log(` ${colors.yellow('[modified]')} ${displayName} (use --force to remove)`);
|
|
1307
|
+
modifiedFiles.push(displayName);
|
|
1308
|
+
stats.skipped++;
|
|
1309
|
+
} else {
|
|
1310
|
+
console.log(` ${colors.red('[remove]')} ${displayName}${!isUnmodified ? ' (modified, --force)' : ''}`);
|
|
1311
|
+
filesToRemove.push({ path: destPath, name: displayName });
|
|
1312
|
+
}
|
|
1313
|
+
}
|
|
1314
|
+
|
|
1315
|
+
// Also check for -1 variant files
|
|
1316
|
+
for (const rule of TEMPLATES[template].rules) {
|
|
1317
|
+
const altName = `${template}-${rule.replace('.mdc', '-1.mdc')}`;
|
|
1318
|
+
const altPath = path.join(dir, altName);
|
|
1319
|
+
|
|
1320
|
+
if (fs.existsSync(altPath)) {
|
|
1321
|
+
console.log(` ${colors.red('[remove]')} ${altName} (${label}/, alternate file)`);
|
|
1322
|
+
filesToRemove.push({ path: altPath, name: altName });
|
|
1323
|
+
}
|
|
1324
|
+
}
|
|
1325
|
+
}
|
|
1326
|
+
|
|
1327
|
+
// Check for legacy-cursorrules-notice.md in new dir
|
|
1328
|
+
const noticePath = path.join(cursorRulesDir, 'legacy-cursorrules-notice.md');
|
|
1329
|
+
if (fs.existsSync(noticePath)) {
|
|
1330
|
+
console.log(` ${colors.red('[remove]')} legacy-cursorrules-notice.md`);
|
|
1331
|
+
filesToRemove.push({ path: noticePath, name: 'legacy-cursorrules-notice.md' });
|
|
1332
|
+
}
|
|
1333
|
+
|
|
1334
|
+
// Log not-found for templates that weren't in either dir
|
|
1335
|
+
for (const rule of TEMPLATES[template].rules) {
|
|
1336
|
+
const destName = `${template}-${rule}`;
|
|
1337
|
+
const inNew = fs.existsSync(path.join(cursorRulesDir, destName));
|
|
1338
|
+
const inLegacy = fs.existsSync(path.join(legacyDir, destName));
|
|
1339
|
+
if (!inNew && !inLegacy) {
|
|
1340
|
+
console.log(` ${colors.dim('[not found]')} ${destName}`);
|
|
1341
|
+
stats.notFound++;
|
|
1342
|
+
}
|
|
1343
|
+
}
|
|
1344
|
+
|
|
1345
|
+
console.log();
|
|
1346
|
+
}
|
|
1347
|
+
} else {
|
|
1348
|
+
console.log(colors.dim(`No ${CURSOR_RULES_DIR}/ or ${LEGACY_CURSORRULES_DIR}/ directory found.\n`));
|
|
1349
|
+
}
|
|
1350
|
+
}
|
|
1351
|
+
|
|
1352
|
+
// 2. Note about CLAUDE.md and copilot-instructions.md
|
|
1353
|
+
// These are regenerated, not patched, so we can't easily remove just one template's content
|
|
1354
|
+
// We'll warn the user about this
|
|
1355
|
+
if (ides.includes('claude') || ides.includes('codex')) {
|
|
1356
|
+
console.log(colors.yellow('Note: CLAUDE.md and copilot-instructions.md contain merged content.'));
|
|
1357
|
+
console.log(colors.dim('To update these files, re-run the installer with the remaining templates.\n'));
|
|
1358
|
+
}
|
|
1359
|
+
|
|
1360
|
+
if (filesToRemove.length === 0) {
|
|
1361
|
+
console.log(colors.yellow('Nothing to remove.\n'));
|
|
1362
|
+
return;
|
|
1363
|
+
}
|
|
1364
|
+
|
|
1365
|
+
// Confirmation
|
|
1366
|
+
if (!dryRun && !skipConfirm) {
|
|
1367
|
+
console.log(colors.yellow(`\nAbout to remove ${filesToRemove.length} file(s).`));
|
|
1368
|
+
const confirmed = await confirm(colors.red('Proceed with removal?'));
|
|
1369
|
+
if (!confirmed) {
|
|
1370
|
+
console.log(colors.dim('\nAborted.\n'));
|
|
1371
|
+
return;
|
|
1372
|
+
}
|
|
1373
|
+
console.log();
|
|
1374
|
+
}
|
|
1375
|
+
|
|
1376
|
+
// Execute removal
|
|
1377
|
+
if (dryRun) {
|
|
1378
|
+
console.log(colors.yellow('DRY RUN - No files were removed.\n'));
|
|
1379
|
+
} else {
|
|
1380
|
+
for (const file of filesToRemove) {
|
|
1381
|
+
try {
|
|
1382
|
+
fs.unlinkSync(file.path);
|
|
1383
|
+
stats.removed++;
|
|
1384
|
+
} catch (err) {
|
|
1385
|
+
console.error(colors.red(`Failed to remove ${file.name}: ${err.message}`));
|
|
1386
|
+
}
|
|
1387
|
+
}
|
|
1388
|
+
}
|
|
1389
|
+
|
|
1390
|
+
// Summary
|
|
1391
|
+
console.log(colors.green('════════════════════════════════════════════════════════════'));
|
|
1392
|
+
console.log(colors.green(`✓ Removal complete!\n`));
|
|
1393
|
+
|
|
1394
|
+
console.log(colors.yellow('Summary:'));
|
|
1395
|
+
console.log(` - ${stats.removed} files removed`);
|
|
1396
|
+
if (stats.skipped > 0) {
|
|
1397
|
+
console.log(` - ${stats.skipped} files skipped (modified, use --force)`);
|
|
1398
|
+
}
|
|
1399
|
+
if (stats.notFound > 0) {
|
|
1400
|
+
console.log(` - ${stats.notFound} files not found`);
|
|
1401
|
+
}
|
|
1402
|
+
console.log();
|
|
1403
|
+
|
|
1404
|
+
if (modifiedFiles.length > 0) {
|
|
1405
|
+
console.log(colors.yellow('Modified files preserved:'));
|
|
1406
|
+
for (const file of modifiedFiles) {
|
|
1407
|
+
console.log(` - ${file}`);
|
|
1408
|
+
}
|
|
1409
|
+
console.log(colors.dim('\nUse --force to remove modified files.\n'));
|
|
1410
|
+
}
|
|
1411
|
+
}
|
|
1412
|
+
|
|
1413
|
+
/**
|
|
1414
|
+
* Reset - remove all installed content
|
|
1415
|
+
*/
|
|
1416
|
+
async function reset(targetDir, dryRun = false, force = false, skipConfirm = false, ides = DEFAULT_IDES) {
|
|
1417
|
+
const stats = { removed: 0, skipped: 0 };
|
|
1418
|
+
const filesToRemove = [];
|
|
1419
|
+
const modifiedFiles = [];
|
|
1420
|
+
const dirsToRemove = [];
|
|
1421
|
+
|
|
1422
|
+
console.log(`${colors.blue('Resetting:')} ${targetDir}`);
|
|
1423
|
+
console.log(`${colors.blue('Target IDEs:')} ${ides.join(', ')}`);
|
|
1424
|
+
console.log();
|
|
1425
|
+
|
|
1426
|
+
// 1. Remove .cursor/rules/ and legacy .cursorrules/ contents for Cursor
|
|
1427
|
+
if (ides.includes('cursor')) {
|
|
1428
|
+
const cursorRulesDir = path.join(targetDir, CURSOR_RULES_DIR);
|
|
1429
|
+
const legacyDir = path.join(targetDir, LEGACY_CURSORRULES_DIR);
|
|
1430
|
+
const dirsToScan = [];
|
|
1431
|
+
|
|
1432
|
+
if (fs.existsSync(cursorRulesDir)) dirsToScan.push({ dir: cursorRulesDir, label: CURSOR_RULES_DIR });
|
|
1433
|
+
if (fs.existsSync(legacyDir)) dirsToScan.push({ dir: legacyDir, label: LEGACY_CURSORRULES_DIR });
|
|
1434
|
+
|
|
1435
|
+
if (dirsToScan.length > 0) {
|
|
1436
|
+
for (const { dir, label } of dirsToScan) {
|
|
1437
|
+
console.log(colors.yellow(`► Scanning ${label}/ directory...`));
|
|
1438
|
+
|
|
1439
|
+
// Check shared rules
|
|
1440
|
+
for (const rule of SHARED_RULES) {
|
|
1441
|
+
const destPath = path.join(dir, rule);
|
|
1442
|
+
const srcPath = path.join(TEMPLATES_DIR, '_shared', rule);
|
|
1443
|
+
|
|
1444
|
+
if (!fs.existsSync(destPath)) continue;
|
|
1445
|
+
|
|
1446
|
+
const isUnmodified = isOurFile(destPath, srcPath);
|
|
1447
|
+
|
|
1448
|
+
if (!isUnmodified && !force) {
|
|
1449
|
+
console.log(` ${colors.yellow('[modified]')} ${rule} (use --force to remove)`);
|
|
1450
|
+
modifiedFiles.push(`${rule} (${label}/)`);
|
|
1451
|
+
stats.skipped++;
|
|
1452
|
+
} else {
|
|
1453
|
+
console.log(` ${colors.red('[remove]')} ${rule}${!isUnmodified ? ' (modified, --force)' : ''}`);
|
|
1454
|
+
filesToRemove.push({ path: destPath, name: `${rule} (${label}/)` });
|
|
1455
|
+
}
|
|
1456
|
+
|
|
1457
|
+
// Check for -1 variant
|
|
1458
|
+
const altPath = path.join(dir, rule.replace('.mdc', '-1.mdc'));
|
|
1459
|
+
if (fs.existsSync(altPath)) {
|
|
1460
|
+
console.log(` ${colors.red('[remove]')} ${rule.replace('.mdc', '-1.mdc')} (alternate file)`);
|
|
1461
|
+
filesToRemove.push({ path: altPath, name: rule.replace('.mdc', '-1.mdc') });
|
|
1462
|
+
}
|
|
1463
|
+
}
|
|
1464
|
+
|
|
1465
|
+
// Check template-specific rules
|
|
1466
|
+
for (const [templateName, templateInfo] of Object.entries(TEMPLATES)) {
|
|
1467
|
+
for (const rule of templateInfo.rules) {
|
|
1468
|
+
const destName = `${templateName}-${rule}`;
|
|
1469
|
+
const destPath = path.join(dir, destName);
|
|
1470
|
+
const srcPath = getTemplateRulePath(templateName, rule);
|
|
1471
|
+
|
|
1472
|
+
if (!fs.existsSync(destPath)) continue;
|
|
1473
|
+
|
|
1474
|
+
const isUnmodified = isOurFile(destPath, srcPath);
|
|
1475
|
+
|
|
1476
|
+
if (!isUnmodified && !force) {
|
|
1477
|
+
console.log(` ${colors.yellow('[modified]')} ${destName} (use --force to remove)`);
|
|
1478
|
+
modifiedFiles.push(`${destName} (${label}/)`);
|
|
1479
|
+
stats.skipped++;
|
|
1480
|
+
} else {
|
|
1481
|
+
console.log(` ${colors.red('[remove]')} ${destName}${!isUnmodified ? ' (modified, --force)' : ''}`);
|
|
1482
|
+
filesToRemove.push({ path: destPath, name: `${destName} (${label}/)` });
|
|
1483
|
+
}
|
|
1484
|
+
|
|
1485
|
+
// Check for -1 variant
|
|
1486
|
+
const altName = destName.replace('.mdc', '-1.mdc');
|
|
1487
|
+
const altPath = path.join(dir, altName);
|
|
1488
|
+
if (fs.existsSync(altPath)) {
|
|
1489
|
+
console.log(` ${colors.red('[remove]')} ${altName} (alternate file)`);
|
|
1490
|
+
filesToRemove.push({ path: altPath, name: altName });
|
|
1491
|
+
}
|
|
1492
|
+
}
|
|
1493
|
+
}
|
|
1494
|
+
|
|
1495
|
+
// Check for legacy-cursorrules-notice.md
|
|
1496
|
+
const noticePath = path.join(dir, 'legacy-cursorrules-notice.md');
|
|
1497
|
+
if (fs.existsSync(noticePath)) {
|
|
1498
|
+
console.log(` ${colors.red('[remove]')} legacy-cursorrules-notice.md`);
|
|
1499
|
+
filesToRemove.push({ path: noticePath, name: 'legacy-cursorrules-notice.md' });
|
|
1500
|
+
}
|
|
1501
|
+
|
|
1502
|
+
// Check if we should remove the directory itself (only if it would be empty)
|
|
1503
|
+
const remainingFiles = fs.readdirSync(dir).filter(f => {
|
|
1504
|
+
const fullPath = path.join(dir, f);
|
|
1505
|
+
const willBeRemoved = filesToRemove.some(fr => fr.path === fullPath);
|
|
1506
|
+
return !willBeRemoved;
|
|
1507
|
+
});
|
|
1508
|
+
|
|
1509
|
+
if (remainingFiles.length === 0 || force) {
|
|
1510
|
+
console.log(` ${colors.red('[remove]')} ${label}/ directory`);
|
|
1511
|
+
dirsToRemove.push(dir);
|
|
1512
|
+
// If removing .cursor/rules/, also check if .cursor/ would be empty
|
|
1513
|
+
if (label === CURSOR_RULES_DIR) {
|
|
1514
|
+
const cursorDir = path.join(targetDir, '.cursor');
|
|
1515
|
+
dirsToRemove.push(cursorDir);
|
|
1516
|
+
}
|
|
1517
|
+
} else if (remainingFiles.length > 0) {
|
|
1518
|
+
console.log(colors.dim(` ${label}/ will be kept (${remainingFiles.length} non-template file(s) remain)`));
|
|
1519
|
+
}
|
|
1520
|
+
|
|
1521
|
+
console.log();
|
|
1522
|
+
}
|
|
1523
|
+
} else {
|
|
1524
|
+
console.log(colors.dim(`No ${CURSOR_RULES_DIR}/ or ${LEGACY_CURSORRULES_DIR}/ directory found.\n`));
|
|
1525
|
+
}
|
|
1526
|
+
}
|
|
1527
|
+
|
|
1528
|
+
// 2. Remove CLAUDE.md for Claude
|
|
1529
|
+
if (ides.includes('claude')) {
|
|
1530
|
+
const claudePath = path.join(targetDir, 'CLAUDE.md');
|
|
1531
|
+
|
|
1532
|
+
if (fs.existsSync(claudePath)) {
|
|
1533
|
+
console.log(colors.yellow('► Checking CLAUDE.md...'));
|
|
1534
|
+
|
|
1535
|
+
// Check if it contains our signature content
|
|
1536
|
+
const content = fs.readFileSync(claudePath, 'utf8');
|
|
1537
|
+
const isOurs = content.includes('# CLAUDE.md - Development Guide') &&
|
|
1538
|
+
(content.includes('.cursor/rules/') || content.includes('.cursorrules/'));
|
|
1539
|
+
|
|
1540
|
+
if (!isOurs && !force) {
|
|
1541
|
+
console.log(` ${colors.yellow('[modified]')} CLAUDE.md (doesn't match template, use --force)`);
|
|
1542
|
+
modifiedFiles.push('CLAUDE.md');
|
|
1543
|
+
stats.skipped++;
|
|
1544
|
+
} else {
|
|
1545
|
+
console.log(` ${colors.red('[remove]')} CLAUDE.md${!isOurs ? ' (modified, --force)' : ''}`);
|
|
1546
|
+
filesToRemove.push({ path: claudePath, name: 'CLAUDE.md' });
|
|
1547
|
+
}
|
|
1548
|
+
console.log();
|
|
1549
|
+
}
|
|
1550
|
+
}
|
|
1551
|
+
|
|
1552
|
+
// 3. Remove .github/copilot-instructions.md for Codex
|
|
1553
|
+
if (ides.includes('codex')) {
|
|
1554
|
+
const copilotPath = path.join(targetDir, '.github', 'copilot-instructions.md');
|
|
1555
|
+
|
|
1556
|
+
if (fs.existsSync(copilotPath)) {
|
|
1557
|
+
console.log(colors.yellow('► Checking .github/copilot-instructions.md...'));
|
|
1558
|
+
|
|
1559
|
+
// Check if it contains our signature content
|
|
1560
|
+
const content = fs.readFileSync(copilotPath, 'utf8');
|
|
1561
|
+
const isOurs = content.includes('# Copilot Instructions') &&
|
|
1562
|
+
content.includes('Installed Templates:');
|
|
1563
|
+
|
|
1564
|
+
if (!isOurs && !force) {
|
|
1565
|
+
console.log(` ${colors.yellow('[modified]')} .github/copilot-instructions.md (doesn't match template, use --force)`);
|
|
1566
|
+
modifiedFiles.push('.github/copilot-instructions.md');
|
|
1567
|
+
stats.skipped++;
|
|
1568
|
+
} else {
|
|
1569
|
+
console.log(` ${colors.red('[remove]')} .github/copilot-instructions.md${!isOurs ? ' (modified, --force)' : ''}`);
|
|
1570
|
+
filesToRemove.push({ path: copilotPath, name: '.github/copilot-instructions.md' });
|
|
1571
|
+
}
|
|
1572
|
+
console.log();
|
|
1573
|
+
}
|
|
1574
|
+
}
|
|
1575
|
+
|
|
1576
|
+
if (filesToRemove.length === 0 && dirsToRemove.length === 0) {
|
|
1577
|
+
console.log(colors.yellow('Nothing to remove.\n'));
|
|
1578
|
+
return;
|
|
1579
|
+
}
|
|
1580
|
+
|
|
1581
|
+
// Confirmation
|
|
1582
|
+
if (!dryRun && !skipConfirm) {
|
|
1583
|
+
const totalItems = filesToRemove.length + dirsToRemove.length;
|
|
1584
|
+
console.log(colors.yellow(`\nAbout to remove ${totalItems} item(s).`));
|
|
1585
|
+
const confirmed = await confirm(colors.red('Proceed with reset?'));
|
|
1586
|
+
if (!confirmed) {
|
|
1587
|
+
console.log(colors.dim('\nAborted.\n'));
|
|
1588
|
+
return;
|
|
1589
|
+
}
|
|
1590
|
+
console.log();
|
|
1591
|
+
}
|
|
1592
|
+
|
|
1593
|
+
// Execute removal
|
|
1594
|
+
if (dryRun) {
|
|
1595
|
+
console.log(colors.yellow('DRY RUN - No files were removed.\n'));
|
|
1596
|
+
} else {
|
|
1597
|
+
// Remove files first
|
|
1598
|
+
for (const file of filesToRemove) {
|
|
1599
|
+
try {
|
|
1600
|
+
fs.unlinkSync(file.path);
|
|
1601
|
+
stats.removed++;
|
|
1602
|
+
} catch (err) {
|
|
1603
|
+
console.error(colors.red(`Failed to remove ${file.name}: ${err.message}`));
|
|
1604
|
+
}
|
|
1605
|
+
}
|
|
1606
|
+
|
|
1607
|
+
// Then remove directories
|
|
1608
|
+
for (const dir of dirsToRemove) {
|
|
1609
|
+
try {
|
|
1610
|
+
// Check if directory is now empty
|
|
1611
|
+
const remaining = fs.existsSync(dir) ? fs.readdirSync(dir) : [];
|
|
1612
|
+
if (remaining.length === 0) {
|
|
1613
|
+
fs.rmdirSync(dir);
|
|
1614
|
+
stats.removed++;
|
|
1615
|
+
} else if (force) {
|
|
1616
|
+
fs.rmSync(dir, { recursive: true });
|
|
1617
|
+
stats.removed++;
|
|
1618
|
+
}
|
|
1619
|
+
} catch (err) {
|
|
1620
|
+
console.error(colors.red(`Failed to remove directory: ${err.message}`));
|
|
1621
|
+
}
|
|
1622
|
+
}
|
|
1623
|
+
}
|
|
1624
|
+
|
|
1625
|
+
// Summary
|
|
1626
|
+
console.log(colors.green('════════════════════════════════════════════════════════════'));
|
|
1627
|
+
console.log(colors.green(`✓ Reset complete!\n`));
|
|
1628
|
+
|
|
1629
|
+
console.log(colors.yellow('Summary:'));
|
|
1630
|
+
console.log(` - ${stats.removed} items removed`);
|
|
1631
|
+
if (stats.skipped > 0) {
|
|
1632
|
+
console.log(` - ${stats.skipped} files skipped (modified, use --force)`);
|
|
1633
|
+
}
|
|
1634
|
+
console.log();
|
|
1635
|
+
|
|
1636
|
+
if (modifiedFiles.length > 0) {
|
|
1637
|
+
console.log(colors.yellow('Modified files preserved:'));
|
|
1638
|
+
for (const file of modifiedFiles) {
|
|
1639
|
+
console.log(` - ${file}`);
|
|
1640
|
+
}
|
|
1641
|
+
console.log(colors.dim('\nUse --force to remove modified files.\n'));
|
|
1642
|
+
}
|
|
1643
|
+
}
|
|
1644
|
+
|
|
1645
|
+
export async function run(args) {
|
|
1646
|
+
const templates = [];
|
|
1647
|
+
const ides = [];
|
|
1648
|
+
let dryRun = false;
|
|
1649
|
+
let force = false;
|
|
1650
|
+
let skipConfirm = false;
|
|
1651
|
+
let removeMode = false;
|
|
1652
|
+
let resetMode = false;
|
|
1653
|
+
|
|
1654
|
+
// Parse arguments
|
|
1655
|
+
for (const arg of args) {
|
|
1656
|
+
if (arg === '--list' || arg === '-l') {
|
|
1657
|
+
printBanner();
|
|
1658
|
+
printTemplates();
|
|
1659
|
+
process.exit(0);
|
|
1660
|
+
} else if (arg === '--help' || arg === '-h') {
|
|
1661
|
+
printBanner();
|
|
1662
|
+
printHelp();
|
|
1663
|
+
process.exit(0);
|
|
1664
|
+
} else if (arg === '--version' || arg === '-v') {
|
|
1665
|
+
console.log(`${PACKAGE_NAME} v${CURRENT_VERSION}`);
|
|
1666
|
+
console.log(`${colors.dim('Changelog:')} ${CHANGELOG_URL}`);
|
|
1667
|
+
process.exit(0);
|
|
1668
|
+
} else if (arg === '--dry-run') {
|
|
1669
|
+
dryRun = true;
|
|
1670
|
+
} else if (arg === '--force' || arg === '-f') {
|
|
1671
|
+
force = true;
|
|
1672
|
+
} else if (arg === '--yes' || arg === '-y') {
|
|
1673
|
+
skipConfirm = true;
|
|
1674
|
+
} else if (arg === '--remove') {
|
|
1675
|
+
removeMode = true;
|
|
1676
|
+
} else if (arg === '--reset') {
|
|
1677
|
+
resetMode = true;
|
|
1678
|
+
} else if (arg.startsWith('--ide=')) {
|
|
1679
|
+
const ide = arg.slice(6).toLowerCase();
|
|
1680
|
+
if (!SUPPORTED_IDES.includes(ide)) {
|
|
1681
|
+
console.error(colors.red(`Error: Unknown IDE '${ide}'`));
|
|
1682
|
+
console.error(colors.dim(`Supported: ${SUPPORTED_IDES.join(', ')}`));
|
|
1683
|
+
process.exit(1);
|
|
1684
|
+
}
|
|
1685
|
+
if (!ides.includes(ide)) {
|
|
1686
|
+
ides.push(ide);
|
|
1687
|
+
}
|
|
1688
|
+
} else if (arg.startsWith('-')) {
|
|
1689
|
+
console.error(colors.red(`Error: Unknown option '${arg}'`));
|
|
1690
|
+
printHelp();
|
|
1691
|
+
process.exit(1);
|
|
1692
|
+
} else {
|
|
1693
|
+
templates.push(arg);
|
|
1694
|
+
}
|
|
1695
|
+
}
|
|
1696
|
+
|
|
1697
|
+
printBanner();
|
|
1698
|
+
|
|
1699
|
+
// Check for updates (non-blocking, fails silently)
|
|
1700
|
+
await checkForUpdates();
|
|
1701
|
+
|
|
1702
|
+
// Resolve template aliases to canonical names
|
|
1703
|
+
const resolvedTemplates = templates.map(resolveTemplateAlias);
|
|
1704
|
+
|
|
1705
|
+
// Use default IDEs if none specified
|
|
1706
|
+
const targetIdes = ides.length > 0 ? ides : DEFAULT_IDES;
|
|
1707
|
+
|
|
1708
|
+
// Handle reset mode
|
|
1709
|
+
if (resetMode) {
|
|
1710
|
+
if (removeMode) {
|
|
1711
|
+
console.error(colors.red('Error: Cannot use --remove and --reset together\n'));
|
|
1712
|
+
process.exit(1);
|
|
1713
|
+
}
|
|
1714
|
+
if (resolvedTemplates.length > 0) {
|
|
1715
|
+
console.error(colors.red('Error: --reset does not accept template arguments\n'));
|
|
1716
|
+
console.error(colors.dim('Use --remove <templates...> to remove specific templates.\n'));
|
|
1717
|
+
process.exit(1);
|
|
1718
|
+
}
|
|
1719
|
+
|
|
1720
|
+
if (dryRun) {
|
|
1721
|
+
console.log(colors.yellow('DRY RUN - No changes will be made\n'));
|
|
1722
|
+
}
|
|
1723
|
+
if (force) {
|
|
1724
|
+
console.log(colors.yellow('FORCE MODE - Modified files will be removed\n'));
|
|
1725
|
+
}
|
|
1726
|
+
|
|
1727
|
+
await reset(process.cwd(), dryRun, force, skipConfirm, targetIdes);
|
|
1728
|
+
return;
|
|
1729
|
+
}
|
|
1730
|
+
|
|
1731
|
+
// Handle remove mode
|
|
1732
|
+
if (removeMode) {
|
|
1733
|
+
if (resolvedTemplates.length === 0) {
|
|
1734
|
+
console.error(colors.red('Error: No templates specified for removal\n'));
|
|
1735
|
+
console.error(colors.dim('Usage: npx @djm204/agent-skills --remove <templates...>\n'));
|
|
1736
|
+
printTemplates();
|
|
1737
|
+
process.exit(1);
|
|
1738
|
+
}
|
|
1739
|
+
|
|
1740
|
+
for (const template of resolvedTemplates) {
|
|
1741
|
+
if (!TEMPLATES[template]) {
|
|
1742
|
+
console.error(colors.red(`Error: Unknown template '${template}'\n`));
|
|
1743
|
+
printTemplates();
|
|
1744
|
+
process.exit(1);
|
|
1745
|
+
}
|
|
1746
|
+
}
|
|
1747
|
+
|
|
1748
|
+
if (dryRun) {
|
|
1749
|
+
console.log(colors.yellow('DRY RUN - No changes will be made\n'));
|
|
1750
|
+
}
|
|
1751
|
+
if (force) {
|
|
1752
|
+
console.log(colors.yellow('FORCE MODE - Modified files will be removed\n'));
|
|
1753
|
+
}
|
|
1754
|
+
|
|
1755
|
+
await remove(process.cwd(), resolvedTemplates, dryRun, force, skipConfirm, targetIdes);
|
|
1756
|
+
return;
|
|
1757
|
+
}
|
|
1758
|
+
|
|
1759
|
+
// Install mode (default)
|
|
1760
|
+
if (resolvedTemplates.length === 0) {
|
|
1761
|
+
console.error(colors.red('Error: No templates specified\n'));
|
|
1762
|
+
printHelp();
|
|
1763
|
+
process.exit(1);
|
|
1764
|
+
}
|
|
1765
|
+
|
|
1766
|
+
for (const template of resolvedTemplates) {
|
|
1767
|
+
if (!TEMPLATES[template]) {
|
|
1768
|
+
console.error(colors.red(`Error: Unknown template '${template}'\n`));
|
|
1769
|
+
printTemplates();
|
|
1770
|
+
process.exit(1);
|
|
1771
|
+
}
|
|
1772
|
+
}
|
|
1773
|
+
|
|
1774
|
+
if (dryRun) {
|
|
1775
|
+
console.log(colors.yellow('DRY RUN - No changes will be made\n'));
|
|
1776
|
+
}
|
|
1777
|
+
|
|
1778
|
+
if (force) {
|
|
1779
|
+
console.log(colors.yellow('FORCE MODE - Existing files will be overwritten\n'));
|
|
1780
|
+
}
|
|
1781
|
+
|
|
1782
|
+
// Install to current directory
|
|
1783
|
+
await install(process.cwd(), resolvedTemplates, dryRun, force, targetIdes, skipConfirm);
|
|
1784
|
+
}
|
|
1785
|
+
|
|
1786
|
+
// Export internals for testing
|
|
1787
|
+
export const _internals = {
|
|
1788
|
+
PACKAGE_NAME,
|
|
1789
|
+
CURRENT_VERSION,
|
|
1790
|
+
REPO_URL,
|
|
1791
|
+
CHANGELOG_URL,
|
|
1792
|
+
CURSOR_RULES_DIR,
|
|
1793
|
+
LEGACY_CURSORRULES_DIR,
|
|
1794
|
+
CATEGORIES,
|
|
1795
|
+
TEMPLATES,
|
|
1796
|
+
TEMPLATE_ALIASES,
|
|
1797
|
+
SHARED_RULES,
|
|
1798
|
+
SUPPORTED_IDES,
|
|
1799
|
+
DEFAULT_IDES,
|
|
1800
|
+
compareVersions,
|
|
1801
|
+
checkForUpdates,
|
|
1802
|
+
resolveTemplateAlias,
|
|
1803
|
+
getTemplateRulePath,
|
|
1804
|
+
filesMatch,
|
|
1805
|
+
parseMarkdownSections,
|
|
1806
|
+
generateSectionSignature,
|
|
1807
|
+
findMissingSections,
|
|
1808
|
+
mergeClaudeContent,
|
|
1809
|
+
getAlternateFilename,
|
|
1810
|
+
copyFile,
|
|
1811
|
+
generateClaudeMdContent,
|
|
1812
|
+
generateCopilotInstructionsContent,
|
|
1813
|
+
isOurFile,
|
|
1814
|
+
install,
|
|
1815
|
+
remove,
|
|
1816
|
+
reset,
|
|
1817
|
+
};
|