@polymorphism-tech/morph-spec 4.12.0 → 4.14.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.
Files changed (316) hide show
  1. package/CLAUDE.md +7 -7
  2. package/README.md +28 -34
  3. package/bin/morph-spec.js +41 -24
  4. package/bin/task-manager.js +962 -1341
  5. package/bin/validate.js +1 -1
  6. package/claude-plugin.json +1 -1
  7. package/docs/CHEATSHEET.md +14 -16
  8. package/docs/QUICKSTART.md +15 -15
  9. package/framework/CLAUDE.md +5 -2
  10. package/framework/agents/README.md +3 -4
  11. package/framework/agents/ai-agents/ai-system-architect.md +6 -10
  12. package/framework/agents/architecture/seo-growth-hacker.md +166 -326
  13. package/framework/agents/architecture/standards-architect.md +21 -31
  14. package/framework/agents/backend/dotnet-senior.md +160 -86
  15. package/framework/agents/backend/ef-modeler.md +2 -6
  16. package/framework/agents/backend/hangfire-orchestrator.md +8 -9
  17. package/framework/agents/backend/ms-agent-expert.md +1 -1
  18. package/framework/agents/frontend/nextjs-expert.md +198 -133
  19. package/framework/agents/frontend/ui-ux-designer.md +226 -267
  20. package/framework/agents/infrastructure/infra-architect.md +191 -27
  21. package/framework/agents/integrations/clerk-auth.md +19 -26
  22. package/framework/agents/integrations/hangfire-integration.md +1 -4
  23. package/framework/agents.json +1084 -2278
  24. package/framework/commands/morph-apply.md +4 -6
  25. package/framework/commands/morph-preflight.md +192 -269
  26. package/framework/commands/morph-proposal.md +210 -238
  27. package/framework/commands/morph-status.md +72 -92
  28. package/framework/commands/morph-troubleshoot.md +6 -13
  29. package/framework/hooks/README.md +1 -6
  30. package/framework/hooks/claude-code/post-tool-use/validator-feedback.js +4 -6
  31. package/framework/hooks/claude-code/pre-compact/save-morph-context.js +12 -7
  32. package/framework/hooks/claude-code/pre-tool-use/enforce-phase-writes.js +2 -2
  33. package/framework/hooks/claude-code/pre-tool-use/protect-spec-files.js +2 -2
  34. package/framework/hooks/claude-code/pre-tool-use/task-tracking-guard.js +5 -10
  35. package/framework/hooks/claude-code/session-start/inject-morph-context.js +63 -30
  36. package/framework/hooks/claude-code/session-start/resume-context.js +77 -0
  37. package/framework/hooks/claude-code/statusline.py +4 -5
  38. package/framework/hooks/claude-code/stop/validate-completion.js +4 -4
  39. package/framework/hooks/claude-code/user-prompt/enrich-prompt.js +8 -8
  40. package/framework/hooks/shared/compact-restore.js +28 -5
  41. package/framework/hooks/shared/phase-utils.js +4 -8
  42. package/framework/hooks/shared/state-reader.js +34 -3
  43. package/framework/phases.json +162 -200
  44. package/framework/rules/ai-agents-standards.md +15 -0
  45. package/framework/rules/asaas-standards.md +13 -0
  46. package/framework/rules/clerk-standards.md +13 -0
  47. package/framework/rules/csharp-standards.md +8 -4
  48. package/framework/rules/data-standards.md +18 -0
  49. package/framework/rules/dotnet-templates.md +87 -0
  50. package/framework/rules/frontend-standards.md +13 -13
  51. package/framework/rules/hangfire-standards.md +13 -0
  52. package/framework/rules/infrastructure-standards.md +27 -16
  53. package/framework/rules/morph-workflow.md +73 -13
  54. package/framework/rules/nextjs-standards.md +1 -0
  55. package/framework/rules/nextjs-templates.md +40 -0
  56. package/framework/rules/resend-standards.md +12 -0
  57. package/framework/rules/supabase-standards.md +29 -0
  58. package/framework/skills/README.md +6 -8
  59. package/framework/skills/level-0-meta/mcp-registry.json +21 -99
  60. package/framework/{standards/ai-agents/team-orchestration.md → skills/level-0-meta/morph-agent-teams/SKILL.md} +472 -479
  61. package/framework/skills/level-0-meta/morph-brainstorming/SKILL.md +28 -1
  62. package/framework/skills/level-0-meta/morph-checklist/SKILL.md +2 -2
  63. package/framework/skills/level-0-meta/morph-code-review/SKILL.md +1 -5
  64. package/framework/skills/level-0-meta/morph-code-review/scripts/scan-csharp.mjs +1 -1
  65. package/framework/skills/level-0-meta/morph-frontend-review/SKILL.md +23 -41
  66. package/framework/skills/level-0-meta/morph-init/SKILL.md +18 -14
  67. package/framework/skills/level-0-meta/morph-parallel-dispatch/SKILL.md +225 -0
  68. package/framework/skills/level-0-meta/morph-post-implementation/SKILL.md +20 -0
  69. package/framework/skills/level-0-meta/morph-tool-usage-guide/SKILL.md +4 -8
  70. package/framework/skills/level-0-meta/morph-tool-usage-guide/references/tools-per-phase.md +15 -59
  71. package/framework/skills/level-0-meta/morph-verification-before-completion/SKILL.md +7 -19
  72. package/framework/skills/level-0-meta/morph-verification-before-completion/scripts/check-phase-outputs.mjs +8 -8
  73. package/framework/skills/level-1-workflows/README.md +1 -1
  74. package/framework/skills/level-1-workflows/morph-phase-codebase-analysis/SKILL.md +49 -50
  75. package/framework/skills/level-1-workflows/morph-phase-design/SKILL.md +57 -123
  76. package/framework/skills/level-1-workflows/morph-phase-design/references/architecture-analysis-guide.md +5 -50
  77. package/framework/skills/level-1-workflows/morph-phase-design/references/spec-example.md +1 -1
  78. package/framework/skills/level-1-workflows/morph-phase-implement/SKILL.md +127 -159
  79. package/framework/skills/level-1-workflows/morph-phase-implement/prompts/code-quality-reviewer-prompt.md +1 -1
  80. package/framework/skills/level-1-workflows/morph-phase-implement/prompts/implementer-prompt.md +4 -3
  81. package/framework/skills/level-1-workflows/morph-phase-implement/prompts/spec-reviewer-prompt.md +2 -2
  82. package/framework/skills/level-1-workflows/morph-phase-implement/references/recap-example.md +1 -1
  83. package/framework/skills/level-1-workflows/morph-phase-plan/SKILL.md +17 -13
  84. package/framework/skills/level-1-workflows/morph-phase-tasks/SKILL.md +22 -40
  85. package/framework/skills/level-1-workflows/morph-phase-tasks/references/task-planning-patterns.md +143 -172
  86. package/framework/skills/level-1-workflows/morph-phase-tasks/references/tasks-example.md +5 -5
  87. package/framework/skills/level-1-workflows/morph-phase-uiux/SKILL.md +57 -77
  88. package/framework/skills/level-1-workflows/morph-scope-escalation/SKILL.md +1 -1
  89. package/framework/squad-templates/backend-only.json +6 -6
  90. package/framework/squad-templates/frontend-only.json +17 -8
  91. package/framework/squad-templates/full-stack.json +29 -24
  92. package/framework/standards/STANDARDS.json +1021 -2369
  93. package/framework/standards/backend/dotnet/fluent-validation-vsa.md +200 -0
  94. package/framework/standards/backend/dotnet/result-pattern.md +213 -0
  95. package/framework/standards/backend/dotnet/scalar-ui.md +172 -0
  96. package/framework/standards/backend/dotnet/scrutor.md +158 -0
  97. package/framework/standards/backend/dotnet/vsa-handler-patterns.md +274 -0
  98. package/framework/standards/frontend/nextjs/motion-patterns.md +1 -1
  99. package/framework/standards/infrastructure/supabase/mcp-setup.md +83 -193
  100. package/framework/standards/integration/mcp/mcp-tools.md +91 -77
  101. package/framework/templates/IDE-SNIPPETS.md +2 -6
  102. package/framework/templates/README.md +709 -814
  103. package/framework/templates/REGISTRY.json +223 -762
  104. package/framework/templates/code/dotnet/abstractions/api-endpoint.cs +7 -0
  105. package/framework/templates/code/dotnet/abstractions/error.cs +60 -0
  106. package/framework/templates/code/dotnet/abstractions/handler.cs +12 -0
  107. package/framework/templates/code/dotnet/abstractions/result.cs +74 -0
  108. package/framework/templates/code/dotnet/backend/repository.cs +148 -141
  109. package/framework/templates/code/dotnet/constants/api-tags.cs +6 -0
  110. package/framework/templates/code/dotnet/exceptions/exception-handler.cs +32 -0
  111. package/framework/templates/code/dotnet/extensions/database-extensions.cs +20 -0
  112. package/framework/templates/code/dotnet/extensions/handler-registration.cs +38 -0
  113. package/framework/templates/code/dotnet/extensions/health-checks.cs +24 -0
  114. package/framework/templates/code/dotnet/extensions/map-endpoints.cs +35 -0
  115. package/framework/templates/code/dotnet/extensions/result-extensions.cs +29 -0
  116. package/framework/templates/code/dotnet/feature/endpoint.cs.hbs +21 -0
  117. package/framework/templates/code/dotnet/feature/entity.cs.hbs +8 -0
  118. package/framework/templates/code/dotnet/feature/errors.cs.hbs +8 -0
  119. package/framework/templates/code/dotnet/feature/handler.cs.hbs +24 -0
  120. package/framework/templates/code/dotnet/feature/request.cs.hbs +4 -0
  121. package/framework/templates/code/dotnet/feature/response.cs.hbs +4 -0
  122. package/framework/templates/code/dotnet/feature/validator.cs.hbs +15 -0
  123. package/framework/templates/code/dotnet/jobs/job.cs +21 -17
  124. package/framework/templates/code/dotnet/pipelines/logging-decorator.cs +31 -0
  125. package/framework/templates/code/dotnet/pipelines/validation-decorator.cs +97 -0
  126. package/framework/templates/code/dotnet/test.cs +192 -106
  127. package/framework/templates/context/ARCHITECTURE.md +89 -0
  128. package/framework/templates/context/CONTEXT-FEATURE.md +2 -2
  129. package/framework/templates/context/CONTEXT.md +180 -181
  130. package/framework/templates/context/design-system.md +1 -5
  131. package/framework/templates/docs/onboarding.md +2 -3
  132. package/framework/templates/docs/proposal.md +171 -182
  133. package/framework/templates/docs/spec.md +1 -3
  134. package/framework/templates/docs/ui-components.md +0 -72
  135. package/framework/templates/examples/design-system-examples.md +4 -4
  136. package/framework/templates/feature/decisions.md +0 -66
  137. package/framework/templates/feature/recap.md +1 -2
  138. package/framework/templates/infrastructure/github/README.md +56 -593
  139. package/framework/templates/integrations/clerk-config.cs +0 -41
  140. package/framework/templates/meta-prompts/parallel-workers/parallel-worker.md +2 -2
  141. package/framework/templates/meta-prompts/squad-leaders/backend-squad.md +1 -2
  142. package/framework/templates/meta-prompts/squad-leaders/frontend-squad.md +83 -126
  143. package/framework/templates/meta-prompts/validators/pre-commit-validator.md +2 -2
  144. package/framework/templates/project/validate.js +2 -4
  145. package/framework/templates/ui/design-system.css +1 -1
  146. package/framework/workflows/README.md +8 -8
  147. package/framework/workflows/configs/fast-track.json +51 -0
  148. package/framework/workflows/configs/full.json +68 -0
  149. package/framework/workflows/configs/standard.json +7 -3
  150. package/framework/workflows/docs/STORY-DRIVEN-DEVELOPMENT.md +1 -1
  151. package/framework/workflows/docs/enforcement-pipeline.md +18 -19
  152. package/framework/workflows/docs/full-morph.md +69 -76
  153. package/framework/workflows/docs/standard.md +49 -44
  154. package/framework/workflows/docs/ui-refresh.md +1 -1
  155. package/package.json +3 -3
  156. package/src/commands/agents/dispatch-agents.js +55 -116
  157. package/src/commands/context/context-refresh.js +79 -0
  158. package/src/commands/phase/phase-reset.js +1 -1
  159. package/src/commands/project/doctor.js +10 -32
  160. package/src/commands/project/init.js +12 -0
  161. package/src/commands/project/status.js +6 -12
  162. package/src/commands/scaffold/scaffold.js +131 -0
  163. package/src/commands/scope/escalate.js +1 -1
  164. package/src/commands/state/advance-phase.js +15 -29
  165. package/src/commands/state/state.js +20 -5
  166. package/src/commands/tasks/task.js +0 -30
  167. package/src/commands/validation/validate-feature.js +3 -10
  168. package/src/core/paths/output-schema.js +12 -13
  169. package/src/core/state/phase-state-machine.js +211 -217
  170. package/src/core/state/state-manager.js +9 -9
  171. package/src/lib/agents/agents-manager.js +2 -2
  172. package/src/lib/agents/output-collector.js +1 -2
  173. package/src/lib/detectors/design-system-detector.js +4 -4
  174. package/src/lib/detectors/index.js +1 -11
  175. package/src/lib/generators/architecture-scanner.js +640 -0
  176. package/src/lib/generators/context-generator.js +3 -3
  177. package/src/lib/generators/design-system-generator.js +508 -587
  178. package/src/lib/generators/index.js +12 -10
  179. package/src/lib/generators/metadata-extractor.js +386 -387
  180. package/src/lib/generators/recap-generator.js +4 -4
  181. package/src/lib/generators/scaffold-generator.js +317 -0
  182. package/src/lib/generators/settings-generator.js +0 -1
  183. package/src/lib/phase-chain/phase-validator.js +64 -42
  184. package/src/lib/stack/stack-profile.js +2 -2
  185. package/src/lib/standards/digest-builder.js +72 -285
  186. package/src/lib/tasks/task-parser.js +11 -5
  187. package/src/lib/validators/architecture/architecture-validator.js +259 -387
  188. package/src/lib/validators/content/content-validator.js +287 -287
  189. package/src/lib/validators/css/css-validator.js +340 -352
  190. package/src/lib/validators/packages/package-validator.js +347 -360
  191. package/src/lib/validators/shared/issue-counter.js +14 -18
  192. package/src/lib/validators/validation-runner.js +3 -19
  193. package/src/scripts/setup-infra.js +1 -1
  194. package/src/utils/agents-installer.js +61 -10
  195. package/src/utils/file-copier.js +1 -0
  196. package/src/utils/hooks-installer.js +11 -19
  197. package/src/utils/skills-installer.js +178 -178
  198. package/framework/agents/architecture/prompt-engineer.md +0 -195
  199. package/framework/agents/backend/api-designer.md +0 -106
  200. package/framework/agents/frontend/blazor-builder.md +0 -229
  201. package/framework/agents/frontend/nextjs-ui-specialist.md +0 -218
  202. package/framework/agents/infrastructure/azure-architect.md +0 -150
  203. package/framework/agents/infrastructure/azure-deploy-specialist.md +0 -707
  204. package/framework/agents/infrastructure/bicep-architect.md +0 -132
  205. package/framework/agents/infrastructure/container-specialist.md +0 -137
  206. package/framework/agents/infrastructure/devops-engineer.md +0 -126
  207. package/framework/agents/integrations/azure-identity.md +0 -148
  208. package/framework/agents/quality/code-analyzer.md +0 -239
  209. package/framework/agents/quality/testing-specialist.md +0 -130
  210. package/framework/hooks/claude-code/notification/approval-reminder.js +0 -57
  211. package/framework/hooks/claude-code/post-tool-use/context-refresh.js +0 -109
  212. package/framework/hooks/claude-code/post-tool-use/skill-reminder.js +0 -78
  213. package/framework/index/troubleshooting-index.json +0 -184
  214. package/framework/rules/testing-standards.md +0 -14
  215. package/framework/skills/level-0-meta/morph-replicate/SKILL.md +0 -230
  216. package/framework/skills/level-0-meta/morph-replicate/references/blazor-html-mapping.md +0 -70
  217. package/framework/skills/level-1-workflows/morph-phase-clarify/SKILL.md +0 -256
  218. package/framework/skills/level-1-workflows/morph-phase-clarify/references/clarifications-example.md +0 -117
  219. package/framework/skills/level-1-workflows/morph-phase-setup/SKILL.md +0 -269
  220. package/framework/standards/ai-agents/blazor-ui.md +0 -364
  221. package/framework/standards/architecture/ddd/aggregates.md +0 -120
  222. package/framework/standards/architecture/ddd/bounded-contexts.md +0 -105
  223. package/framework/standards/architecture/ddd/complexity-levels.md +0 -108
  224. package/framework/standards/architecture/ddd/entities.md +0 -99
  225. package/framework/standards/architecture/ddd/ubiquitous-language.md +0 -58
  226. package/framework/standards/architecture/ddd/value-objects.md +0 -124
  227. package/framework/standards/backend/api/minimal-api.md +0 -494
  228. package/framework/standards/backend/api/rest.md +0 -492
  229. package/framework/standards/backend/authentication/passkeys.md +0 -428
  230. package/framework/standards/backend/database/ef-core.md +0 -199
  231. package/framework/standards/backend/database/migrations.md +0 -393
  232. package/framework/standards/backend/database/repository-patterns.md +0 -528
  233. package/framework/standards/backend/dotnet/async.md +0 -366
  234. package/framework/standards/backend/dotnet/core.md +0 -117
  235. package/framework/standards/backend/dotnet/di.md +0 -439
  236. package/framework/standards/backend/dotnet/program-cs-checklist.md +0 -92
  237. package/framework/standards/context/analytics.md +0 -96
  238. package/framework/standards/context/bundles.md +0 -110
  239. package/framework/standards/context/priming.md +0 -78
  240. package/framework/standards/core/architecture.md +0 -185
  241. package/framework/standards/core/coding.md +0 -214
  242. package/framework/standards/core/git-branching-strategy.md +0 -403
  243. package/framework/standards/core/git.md +0 -185
  244. package/framework/standards/core/testing.md +0 -295
  245. package/framework/standards/data/nosql/blob-storage.md +0 -102
  246. package/framework/standards/data/vector-search/azure-ai-search.md +0 -121
  247. package/framework/standards/frontend/blazor/design-checklist.md +0 -222
  248. package/framework/standards/frontend/blazor/fluent-ui-setup.md +0 -595
  249. package/framework/standards/frontend/blazor/fluent-ui.md +0 -137
  250. package/framework/standards/frontend/blazor/html-conversion.md +0 -184
  251. package/framework/standards/frontend/blazor/lifecycle.md +0 -195
  252. package/framework/standards/frontend/blazor/pitfalls.md +0 -198
  253. package/framework/standards/frontend/blazor/state.md +0 -191
  254. package/framework/standards/frontend/design-system/aesthetic-direction.md +0 -266
  255. package/framework/standards/frontend/design-system/design-trends.md +0 -171
  256. package/framework/standards/infrastructure/azure/azure.md +0 -624
  257. package/framework/standards/infrastructure/azure/bicep/bicep-patterns.md +0 -422
  258. package/framework/standards/infrastructure/azure/devops/azure-devops-setup.md +0 -516
  259. package/framework/standards/infrastructure/azure/devops/local-development.md +0 -520
  260. package/framework/standards/infrastructure/azure/services/functions.md +0 -486
  261. package/framework/standards/infrastructure/azure/services/service-bus.md +0 -459
  262. package/framework/standards/infrastructure/azure/services/storage.md +0 -407
  263. package/framework/standards/infrastructure/vercel/vercel-database.md +0 -106
  264. package/framework/standards/integration/api/graphql.md +0 -91
  265. package/framework/standards/integration/api/grpc.md +0 -114
  266. package/framework/standards/integration/api/rest-design.md +0 -95
  267. package/framework/standards/integration/event-driven/cqrs.md +0 -101
  268. package/framework/standards/integration/event-driven/event-sourcing.md +0 -124
  269. package/framework/standards/integration/event-driven/service-bus.md +0 -95
  270. package/framework/standards/observability/logging.md +0 -131
  271. package/framework/standards/observability/metrics.md +0 -121
  272. package/framework/standards/observability/monitoring.md +0 -114
  273. package/framework/standards/observability/tracing.md +0 -132
  274. package/framework/standards/workflows/parallel-execution.md +0 -112
  275. package/framework/standards/workflows/thread-management.md +0 -113
  276. package/framework/templates/code/dotnet/backend/service.cs +0 -139
  277. package/framework/templates/code/dotnet/contracts/Commands.cs +0 -74
  278. package/framework/templates/code/dotnet/contracts/Entities.cs +0 -25
  279. package/framework/templates/code/dotnet/contracts/Queries.cs +0 -74
  280. package/framework/templates/code/dotnet/contracts/api-contracts.cs +0 -173
  281. package/framework/templates/code/dotnet/contracts/contracts-level1.cs +0 -69
  282. package/framework/templates/code/dotnet/contracts/contracts-level2.cs +0 -86
  283. package/framework/templates/code/dotnet/contracts/contracts-level3.cs +0 -41
  284. package/framework/templates/code/dotnet/frontend/component.razor +0 -239
  285. package/framework/templates/infrastructure/azure/Dockerfile.example +0 -82
  286. package/framework/templates/infrastructure/azure/README.md +0 -286
  287. package/framework/templates/infrastructure/azure/app-insights.bicep +0 -63
  288. package/framework/templates/infrastructure/azure/app-service.bicep +0 -164
  289. package/framework/templates/infrastructure/azure/container-app-env.bicep +0 -49
  290. package/framework/templates/infrastructure/azure/container-app.bicep +0 -156
  291. package/framework/templates/infrastructure/azure/deploy-checklist.md +0 -426
  292. package/framework/templates/infrastructure/azure/deploy.ps1 +0 -229
  293. package/framework/templates/infrastructure/azure/deploy.sh +0 -208
  294. package/framework/templates/infrastructure/azure/key-vault.bicep +0 -91
  295. package/framework/templates/infrastructure/azure/main.bicep +0 -189
  296. package/framework/templates/infrastructure/azure/parameters.dev.json +0 -29
  297. package/framework/templates/infrastructure/azure/parameters.prod.json +0 -29
  298. package/framework/templates/infrastructure/azure/parameters.staging.json +0 -29
  299. package/framework/templates/infrastructure/azure/sql-database.bicep +0 -103
  300. package/framework/templates/infrastructure/azure/storage.bicep +0 -106
  301. package/framework/templates/infrastructure/github/actions/azure-auth/action.yml.hbs +0 -22
  302. package/framework/templates/infrastructure/github/workflows/deploy-azure-app-service.yml.hbs +0 -61
  303. package/framework/templates/integrations/azure-identity-config.cs +0 -288
  304. package/framework/templates/project-structure/dotnet-ddd.md +0 -70
  305. package/framework/templates/saas/subscription.cs +0 -347
  306. package/framework/templates/saas/tenant.cs +0 -338
  307. package/framework/templates/ui/FluentDesignTheme.cs +0 -149
  308. package/framework/templates/ui/MudTheme.cs +0 -281
  309. package/framework/workflows/configs/nodejs-cli.json +0 -40
  310. package/src/commands/standards/context-budget.js +0 -89
  311. package/src/lib/standards/index.js +0 -7
  312. package/src/lib/standards/standards-context-injector.js +0 -302
  313. package/src/lib/validators/blazor/blazor-concurrency-analyzer.js +0 -316
  314. package/src/lib/validators/blazor/blazor-state-validator.js +0 -279
  315. package/src/lib/validators/blazor/blazor-validator.js +0 -369
  316. package/src/lib/validators/blazor/index.js +0 -9
@@ -1,18 +1,14 @@
1
- /**
2
- * Shared issue counting utility for validators
3
- *
4
- * Consolidates duplicate implementations from:
5
- * - blazor-validator.js
6
- * - blazor-state-validator.js
7
- * - blazor-concurrency-analyzer.js
8
- *
9
- * @param {Array} issues - Array of validation issues with type property
10
- * @returns {{errors: number, warnings: number, infos: number}} Count by type
11
- */
12
- export function countIssues(issues) {
13
- return {
14
- errors: issues.filter((i) => i.type === 'error').length,
15
- warnings: issues.filter((i) => i.type === 'warning').length,
16
- infos: issues.filter((i) => i.type === 'info').length,
17
- };
18
- }
1
+ /**
2
+ * Shared issue counting utility for validators
3
+ *
4
+ *
5
+ * @param {Array} issues - Array of validation issues with type property
6
+ * @returns {{errors: number, warnings: number, infos: number}} Count by type
7
+ */
8
+ export function countIssues(issues) {
9
+ return {
10
+ errors: issues.filter((i) => i.type === 'error').length,
11
+ warnings: issues.filter((i) => i.type === 'warning').length,
12
+ infos: issues.filter((i) => i.type === 'info').length,
13
+ };
14
+ }
@@ -14,10 +14,9 @@ import { loadState } from '../../core/state/state-manager.js';
14
14
  import { getAbsoluteOutputPath, resolveContractsOutputType } from '../../core/paths/output-schema.js';
15
15
  import { getStackProfile } from '../stack/stack-profile.js';
16
16
 
17
- /** Validators that only make sense for .NET/Blazor projects. */
17
+ /** Validators that only make sense for .NET projects. */
18
18
  const DOTNET_ONLY_VALIDATORS = new Set([
19
- 'architecture', 'packages', 'blazor', 'blazor-concurrency',
20
- 'blazor-state', 'contract-compliance'
19
+ 'architecture', 'packages', 'contract-compliance'
21
20
  ]);
22
21
 
23
22
  /**
@@ -26,7 +25,7 @@ const DOTNET_ONLY_VALIDATORS = new Set([
26
25
  */
27
26
  const HEAVY_VALIDATORS = new Set([
28
27
  'architecture', 'packages', 'contract-compliance',
29
- 'blazor-concurrency', 'css', 'design-system'
28
+ 'css', 'design-system'
30
29
  ]);
31
30
 
32
31
  /**
@@ -228,21 +227,6 @@ async function runSingleValidator(validatorId, projectPath, featureName, options
228
227
  return await validateContrast(projectPath, options);
229
228
  }
230
229
 
231
- case 'blazor': {
232
- const { validateBlazorPatterns } = await import('./blazor/blazor-validator.js');
233
- return await validateBlazorPatterns(projectPath, options);
234
- }
235
-
236
- case 'blazor-concurrency': {
237
- const { validateConcurrencyFiles } = await import('./blazor/blazor-concurrency-analyzer.js');
238
- return await validateConcurrencyFiles(projectPath, options);
239
- }
240
-
241
- case 'blazor-state': {
242
- const { validateState } = await import('./blazor/blazor-state-validator.js');
243
- return await validateState(projectPath, options);
244
- }
245
-
246
230
  case 'css': {
247
231
  const { validateCss } = await import('./css/css-validator.js');
248
232
  return await validateCss(projectPath, options);
@@ -141,7 +141,7 @@ export async function setupInfra(targetPath, { _exec = execSync } = {}) {
141
141
  const contextReadmePath = join(contextDir, 'README.md');
142
142
  if (!(await pathExists(contextReadmePath))) {
143
143
  const dirName = targetPath.split(/[\/]/).pop();
144
- const readmeContent = `# ${dirName} — Project Context\n\nRun /morph-init to generate project context.\n`;
144
+ const readmeContent = `# ${dirName} — Project Context\n\nRun \`morph-spec context refresh\` to generate architecture context.\n`;
145
145
  await writeFile(contextReadmePath, readmeContent);
146
146
  }
147
147
 
@@ -103,23 +103,31 @@ export async function installAgents(projectDir, frameworkDir = 'framework', opti
103
103
  /**
104
104
  * Tier-based defaults for Claude Code subagent frontmatter fields.
105
105
  *
106
- * Tier 1 (Orchestrators): can spawn subagents via Task tool, 30 turns, project memory.
107
- * Tier 2 (Domain Leaders): coordinate specialists but do not spawn subagents, 20 turns, local memory.
106
+ * Tier 1 (Orchestrators): opus model, can spawn subagents via Agent tool, 30 turns, project memory, high effort.
107
+ * Tier 2 (Domain Leaders): sonnet model, coordinate specialists, 20 turns, local memory, medium effort.
108
+ * Tier 3 (Specialists): sonnet model, implementation focus, 15 turns, local memory, medium effort.
109
+ * Tier 4 (Validators): haiku model, read-only scanning, 10 turns, background execution, low effort.
108
110
  */
109
111
  const TIER_DEFAULTS = {
110
112
  1: {
111
- model: 'inherit',
112
- tools: 'Read, Grep, Glob, Bash, Task, Write, Edit',
113
+ model: 'opus',
114
+ tools: 'Read, Grep, Glob, Bash, Agent, Write, Edit',
113
115
  maxTurns: 30,
114
116
  skills: ['morph-checklist'],
115
117
  memory: 'project',
118
+ effort: 'high',
119
+ permissionMode: 'acceptEdits',
120
+ background: false,
116
121
  },
117
122
  2: {
118
- model: 'inherit',
123
+ model: 'sonnet',
119
124
  tools: 'Read, Write, Edit, Bash, Glob, Grep',
120
125
  maxTurns: 20,
121
126
  skills: ['morph-checklist'],
122
127
  memory: 'local',
128
+ effort: 'medium',
129
+ permissionMode: 'acceptEdits',
130
+ background: false,
123
131
  },
124
132
  3: {
125
133
  model: 'sonnet',
@@ -127,6 +135,9 @@ const TIER_DEFAULTS = {
127
135
  maxTurns: 15,
128
136
  skills: [],
129
137
  memory: 'local',
138
+ effort: 'medium',
139
+ permissionMode: 'default',
140
+ background: false,
130
141
  },
131
142
  4: {
132
143
  model: 'haiku',
@@ -134,6 +145,9 @@ const TIER_DEFAULTS = {
134
145
  maxTurns: 10,
135
146
  skills: [],
136
147
  memory: 'project',
148
+ effort: 'low',
149
+ permissionMode: 'plan',
150
+ background: true,
137
151
  },
138
152
  };
139
153
 
@@ -149,10 +163,14 @@ function buildFrontmatter(agent, description) {
149
163
  const defaults = TIER_DEFAULTS[agent.tier] ?? TIER_DEFAULTS[2];
150
164
  const name = agent.title ?? agent.name;
151
165
 
152
- // Allow per-agent tool overrides (e.g., morph-spec-validator needs Bash for npm test)
166
+ // Allow per-agent overrides from teammate config
153
167
  const tools = agent.teammate?.tools ?? defaults.tools;
154
- // Allow per-agent maxTurns override
155
168
  const maxTurns = agent.teammate?.maxTurns ?? defaults.maxTurns;
169
+ const effort = agent.teammate?.effort ?? defaults.effort;
170
+ const permissionMode = agent.teammate?.permissionMode ?? defaults.permissionMode;
171
+ const background = agent.teammate?.background ?? defaults.background;
172
+ // color is a top-level field on the agent (not inside teammate)
173
+ const color = agent.color;
156
174
 
157
175
  const lines = [
158
176
  `name: ${name}`,
@@ -162,6 +180,11 @@ function buildFrontmatter(agent, description) {
162
180
  `maxTurns: ${maxTurns}`,
163
181
  ];
164
182
 
183
+ if (color) lines.push(`color: ${color}`);
184
+ if (effort) lines.push(`effort: ${effort}`);
185
+ if (permissionMode && permissionMode !== 'default') lines.push(`permissionMode: ${permissionMode}`);
186
+ if (background) lines.push(`background: true`);
187
+
165
188
  if (defaults.skills.length > 0) {
166
189
  const skillsList = defaults.skills.map(s => ` - ${s}`).join('\n');
167
190
  lines.push(`skills:`, skillsList);
@@ -171,10 +194,30 @@ function buildFrontmatter(agent, description) {
171
194
  return lines.join('\n');
172
195
  }
173
196
 
197
+ /** Maps agent group to task categories for routing hints in description */
198
+ const GROUP_TO_CATEGORIES = {
199
+ 'backend': 'Domain, Infrastructure, Application',
200
+ 'frontend': 'Presentation',
201
+ 'domain-analysis': 'Architecture, Cross-cutting',
202
+ 'testing': 'Tests',
203
+ 'infra': 'Infra, DevOps',
204
+ 'ai': 'AI, Automation',
205
+ };
206
+
174
207
  function buildDescription(agent) {
175
- const base = agent.teammate?.role ?? `Handles ${(agent.domains ?? []).join(', ')}`;
208
+ const role = agent.teammate?.role ?? `Handles ${(agent.domains ?? []).join(', ')}`;
209
+ const triggers = agent.teammate?.triggers;
210
+ const categories = GROUP_TO_CATEGORIES[agent.group];
211
+
212
+ let desc = role;
213
+ if (triggers) {
214
+ desc += `. Use proactively when: ${triggers}`;
215
+ } else if (categories) {
216
+ desc += ` | Tasks: ${categories}`;
217
+ }
218
+
176
219
  // Truncate to 200 chars for settings display
177
- return base.length > 200 ? base.slice(0, 197) + '...' : base;
220
+ return desc.length > 200 ? desc.slice(0, 197) + '...' : desc;
178
221
  }
179
222
 
180
223
  /**
@@ -200,8 +243,16 @@ function buildBody(agent) {
200
243
  lines.push(`\n## Domains\n${agent.domains.map(d => `- ${d}`).join('\n')}`);
201
244
  }
202
245
  }
246
+
247
+ // Task routing — tells the agent which task categories it handles
248
+ const categories = GROUP_TO_CATEGORIES[agent.group];
249
+ if (categories) {
250
+ lines.push(`\n## Task Routing\nHandle tasks categorized as: ${categories}`);
251
+ }
252
+
253
+ // Key standards — @ references for upfront awareness
203
254
  if (agent.standards?.length) {
204
- lines.push(`\n## Standards to Reference\n${agent.standards.map(formatStandardRef).join('\n')}`);
255
+ lines.push(`\n## Key Standards\n${agent.standards.map(formatStandardRef).join('\n')}`);
205
256
  }
206
257
  return lines.join('\n');
207
258
  }
@@ -149,6 +149,7 @@ export async function updateGitignore(projectPath) {
149
149
  '.claude/CLAUDE.md',
150
150
  '.claude/settings.local.json',
151
151
  '.worktrees/',
152
+ '.playwright-mcp/',
152
153
  'docs/superpowers/',
153
154
  ''
154
155
  ];
@@ -15,7 +15,7 @@ import { homedir } from 'os';
15
15
  import { execSync } from 'child_process';
16
16
 
17
17
  /** Current hooks schema version — bump when hook definitions change */
18
- const HOOKS_VERSION = '2.13.0';
18
+ const HOOKS_VERSION = '2.14.0';
19
19
 
20
20
  /** Marker for old dispatch.js (v1) */
21
21
  const OLD_DISPATCH_COMMAND = 'node framework/hooks/agent-teams/dispatch.js';
@@ -70,6 +70,16 @@ const MORPH_HOOKS = [
70
70
  }]
71
71
  },
72
72
 
73
+ // === SessionStart: resume only — orientation context ===
74
+ {
75
+ event: 'SessionStart',
76
+ matcher: 'resume',
77
+ hooks: [{
78
+ type: 'command',
79
+ command: 'node framework/hooks/claude-code/session-start/resume-context.js'
80
+ }]
81
+ },
82
+
73
83
  // === UserPromptSubmit ===
74
84
  {
75
85
  event: 'UserPromptSubmit',
@@ -138,14 +148,6 @@ Otherwise respond: {"ok": true}`
138
148
  type: 'command',
139
149
  command: 'node framework/hooks/claude-code/post-tool-use/dispatch.js'
140
150
  },
141
- {
142
- type: 'command',
143
- command: 'node framework/hooks/claude-code/post-tool-use/context-refresh.js'
144
- },
145
- {
146
- type: 'command',
147
- command: 'node framework/hooks/claude-code/post-tool-use/skill-reminder.js'
148
- },
149
151
  {
150
152
  type: 'command',
151
153
  command: 'node framework/hooks/claude-code/post-tool-use/validator-feedback.js'
@@ -184,16 +186,6 @@ Otherwise respond: {"ok": true}`
184
186
  }]
185
187
  },
186
188
 
187
- // === Notification ===
188
- {
189
- event: 'Notification',
190
- matcher: 'idle_prompt',
191
- hooks: [{
192
- type: 'command',
193
- command: 'node framework/hooks/claude-code/notification/approval-reminder.js'
194
- }]
195
- },
196
-
197
189
  // === TeammateIdle ===
198
190
  // Fires when an Agent Team teammate finishes and is about to go idle.
199
191
  // Exit 2 = send feedback to teammate to continue working (validation failed).
@@ -1,178 +1,178 @@
1
- /**
2
- * Skills Installer
3
- *
4
- * Copies framework skills to .claude/skills/ during morph-spec init.
5
- * Installs level-0-meta and level-1-workflows skills using the native Claude Code
6
- * subdirectory format: .claude/skills/{skill-name}/SKILL.md (plus optional
7
- * scripts/, references/, and assets/ subdirectories).
8
- * Level-2 domain specialists are installed as native subagents via installDomainAgents().
9
- * Level-3 and level-4 only contain README.md placeholder files and are skipped.
10
- *
11
- * Source skills can be either:
12
- * - Directory-based: framework/skills/{level}/{skill-name}/SKILL.md (preferred)
13
- * - Flat file: framework/skills/{level}/{skill-name}.md (legacy, still supported)
14
- *
15
- * Directory-based skills have their entire directory copied (scripts/, references/,
16
- * assets/) so Claude Code can execute scripts and load references on demand.
17
- */
18
-
19
- import { mkdirSync, copyFileSync, existsSync, readdirSync, statSync, readFileSync, rmSync } from 'fs';
20
- import { join } from 'path';
21
- import { fileURLToPath } from 'url';
22
- import { parseStacks, shouldInstall } from '../lib/stack-filter.js';
23
-
24
- const __dirname = fileURLToPath(new URL('.', import.meta.url));
25
- const FRAMEWORK_SKILLS_DIR = join(__dirname, '..', '..', 'framework', 'skills');
26
-
27
- /**
28
- * Skill levels to install in .claude/skills/.
29
- * Level-0 meta skills (planning, reviewing) and level-1 workflow skills
30
- * (phase-design, phase-implement, etc.) are installed. Level-2 domain
31
- * specialists are installed as native subagents via installDomainAgents()
32
- * instead. Level-3 and level-4 are skipped (no content yet).
33
- */
34
- const SKILL_LEVELS_TO_INSTALL = ['level-0-meta', 'level-1-workflows'];
35
-
36
- /**
37
- * Check if a skill should be installed based on its stacks: frontmatter.
38
- * @param {string} skillContent - Raw SKILL.md content
39
- * @param {string[]} projectTags - Stack tags from config
40
- * @returns {boolean}
41
- */
42
- export function shouldInstallSkill(skillContent, projectTags) {
43
- return shouldInstall(parseStacks(skillContent), projectTags);
44
- }
45
-
46
- /**
47
- * Recursively copy a directory tree from src to dest.
48
- * Creates dest if it doesn't exist. Skips README.md files.
49
- *
50
- * @param {string} src - Source directory path
51
- * @param {string} dest - Destination directory path
52
- */
53
- function copyDirectory(src, dest) {
54
- mkdirSync(dest, { recursive: true });
55
- for (const entry of readdirSync(src)) {
56
- if (entry === 'README.md') continue;
57
- const srcPath = join(src, entry);
58
- const destPath = join(dest, entry);
59
- if (statSync(srcPath).isDirectory()) {
60
- copyDirectory(srcPath, destPath);
61
- } else {
62
- copyFileSync(srcPath, destPath);
63
- }
64
- }
65
- }
66
-
67
- /**
68
- * Walk srcDir and install skills into destDir.
69
- *
70
- * Handles two source formats:
71
- * 1. Directory-based skill: srcDir/{skill-name}/SKILL.md
72
- * → copies entire directory (SKILL.md + scripts/ + references/ + assets/)
73
- * → destDir/{skill-name}/
74
- *
75
- * 2. Flat .md skill (legacy): srcDir/{skill-name}.md
76
- * → destDir/{skill-name}/SKILL.md
77
- *
78
- * Level directories (level-0-meta, level-1-workflows, sub-categories) are
79
- * traversed recursively. A directory is recognized as a skill directory when
80
- * it contains a SKILL.md file.
81
- *
82
- * @param {string} srcDir - Source directory to walk
83
- * @param {string} destDir - Destination base directory (.claude/skills/)
84
- */
85
- function installSkillsFromDir(srcDir, destDir, projectTags) {
86
- const entries = readdirSync(srcDir);
87
- for (const entry of entries) {
88
- const srcPath = join(srcDir, entry);
89
- const stat = statSync(srcPath);
90
-
91
- if (stat.isDirectory()) {
92
- const skillMdPath = join(srcPath, 'SKILL.md');
93
- if (existsSync(skillMdPath)) {
94
- // Directory-based skill — check stack filter before copying
95
- const content = readFileSync(skillMdPath, 'utf-8');
96
- if (!shouldInstallSkill(content, projectTags)) continue;
97
- const skillDestDir = join(destDir, entry);
98
- copyDirectory(srcPath, skillDestDir);
99
- } else {
100
- // Level/category directory — recurse
101
- installSkillsFromDir(srcPath, destDir, projectTags);
102
- }
103
- } else if (entry.endsWith('.md') && entry !== 'README.md') {
104
- // Legacy flat .md skill — check stack filter before copying
105
- const content = readFileSync(srcPath, 'utf-8');
106
- if (!shouldInstallSkill(content, projectTags)) continue;
107
- const skillName = entry.slice(0, -3);
108
- const skillDir = join(destDir, skillName);
109
- mkdirSync(skillDir, { recursive: true });
110
- copyFileSync(srcPath, join(skillDir, 'SKILL.md'));
111
- }
112
- }
113
- }
114
-
115
- function collectSourceSkillNames() {
116
- const names = new Set();
117
- for (const level of SKILL_LEVELS_TO_INSTALL) {
118
- const levelDir = join(FRAMEWORK_SKILLS_DIR, level);
119
- if (!existsSync(levelDir)) continue;
120
- collectNamesFromDir(levelDir, names);
121
- }
122
- return names;
123
- }
124
-
125
- function collectNamesFromDir(dir, names) {
126
- for (const entry of readdirSync(dir)) {
127
- const fullPath = join(dir, entry);
128
- if (!statSync(fullPath).isDirectory()) continue;
129
- if (existsSync(join(fullPath, 'SKILL.md'))) {
130
- names.add(entry);
131
- } else {
132
- collectNamesFromDir(fullPath, names);
133
- }
134
- }
135
- }
136
-
137
- /**
138
- * Install morph framework skills to .claude/skills/ in the target project.
139
- * Skills are copied into subdirectories as SKILL.md files so Claude Code can
140
- * discover them natively via /<skill-name> syntax (e.g., /phase-design,
141
- * /blazor-builder). Directory-based skills also get their scripts/,
142
- * references/, and assets/ subdirectories copied for on-demand loading.
143
- *
144
- * Stack filtering: if projectTags is provided, only skills whose `stacks:`
145
- * frontmatter matches the project tags are installed. Skills without a
146
- * `stacks:` field are always installed (universal).
147
- *
148
- * @param {string} projectDir - Target project root directory
149
- * @param {Object} [options]
150
- * @param {string[]} [options.projectTags=[]] - Stack tags from config
151
- */
152
- export async function installSkills(projectDir, { projectTags = [] } = {}) {
153
- const claudeSkillsDir = join(projectDir, '.claude', 'skills');
154
- mkdirSync(claudeSkillsDir, { recursive: true });
155
-
156
- for (const level of SKILL_LEVELS_TO_INSTALL) {
157
- const levelDir = join(FRAMEWORK_SKILLS_DIR, level);
158
- if (!existsSync(levelDir)) continue;
159
- installSkillsFromDir(levelDir, claudeSkillsDir, projectTags);
160
- }
161
-
162
- // Collect installed morph-* skill names
163
- const installed = new Set();
164
- for (const entry of readdirSync(claudeSkillsDir)) {
165
- if (existsSync(join(claudeSkillsDir, entry, 'SKILL.md'))) {
166
- installed.add(entry);
167
- }
168
- }
169
-
170
- // Cleanup orphan morph-* skill dirs that exist in source but were filtered out
171
- const allSourceSkills = collectSourceSkillNames();
172
- for (const entry of readdirSync(claudeSkillsDir)) {
173
- if (!entry.startsWith('morph-')) continue;
174
- if (!installed.has(entry) && allSourceSkills.has(entry)) {
175
- rmSync(join(claudeSkillsDir, entry), { recursive: true, force: true });
176
- }
177
- }
178
- }
1
+ /**
2
+ * Skills Installer
3
+ *
4
+ * Copies framework skills to .claude/skills/ during morph-spec init.
5
+ * Installs level-0-meta and level-1-workflows skills using the native Claude Code
6
+ * subdirectory format: .claude/skills/{skill-name}/SKILL.md (plus optional
7
+ * scripts/, references/, and assets/ subdirectories).
8
+ * Level-2 domain specialists are installed as native subagents via installDomainAgents().
9
+ * Level-3 and level-4 only contain README.md placeholder files and are skipped.
10
+ *
11
+ * Source skills can be either:
12
+ * - Directory-based: framework/skills/{level}/{skill-name}/SKILL.md (preferred)
13
+ * - Flat file: framework/skills/{level}/{skill-name}.md (legacy, still supported)
14
+ *
15
+ * Directory-based skills have their entire directory copied (scripts/, references/,
16
+ * assets/) so Claude Code can execute scripts and load references on demand.
17
+ */
18
+
19
+ import { mkdirSync, copyFileSync, existsSync, readdirSync, statSync, readFileSync, rmSync } from 'fs';
20
+ import { join } from 'path';
21
+ import { fileURLToPath } from 'url';
22
+ import { parseStacks, shouldInstall } from '../lib/stack-filter.js';
23
+
24
+ const __dirname = fileURLToPath(new URL('.', import.meta.url));
25
+ const FRAMEWORK_SKILLS_DIR = join(__dirname, '..', '..', 'framework', 'skills');
26
+
27
+ /**
28
+ * Skill levels to install in .claude/skills/.
29
+ * Level-0 meta skills (planning, reviewing) and level-1 workflow skills
30
+ * (phase-design, phase-implement, etc.) are installed. Level-2 domain
31
+ * specialists are installed as native subagents via installDomainAgents()
32
+ * instead. Level-3 and level-4 are skipped (no content yet).
33
+ */
34
+ const SKILL_LEVELS_TO_INSTALL = ['level-0-meta', 'level-1-workflows'];
35
+
36
+ /**
37
+ * Check if a skill should be installed based on its stacks: frontmatter.
38
+ * @param {string} skillContent - Raw SKILL.md content
39
+ * @param {string[]} projectTags - Stack tags from config
40
+ * @returns {boolean}
41
+ */
42
+ export function shouldInstallSkill(skillContent, projectTags) {
43
+ return shouldInstall(parseStacks(skillContent), projectTags);
44
+ }
45
+
46
+ /**
47
+ * Recursively copy a directory tree from src to dest.
48
+ * Creates dest if it doesn't exist. Skips README.md files.
49
+ *
50
+ * @param {string} src - Source directory path
51
+ * @param {string} dest - Destination directory path
52
+ */
53
+ function copyDirectory(src, dest) {
54
+ mkdirSync(dest, { recursive: true });
55
+ for (const entry of readdirSync(src)) {
56
+ if (entry === 'README.md') continue;
57
+ const srcPath = join(src, entry);
58
+ const destPath = join(dest, entry);
59
+ if (statSync(srcPath).isDirectory()) {
60
+ copyDirectory(srcPath, destPath);
61
+ } else {
62
+ copyFileSync(srcPath, destPath);
63
+ }
64
+ }
65
+ }
66
+
67
+ /**
68
+ * Walk srcDir and install skills into destDir.
69
+ *
70
+ * Handles two source formats:
71
+ * 1. Directory-based skill: srcDir/{skill-name}/SKILL.md
72
+ * → copies entire directory (SKILL.md + scripts/ + references/ + assets/)
73
+ * → destDir/{skill-name}/
74
+ *
75
+ * 2. Flat .md skill (legacy): srcDir/{skill-name}.md
76
+ * → destDir/{skill-name}/SKILL.md
77
+ *
78
+ * Level directories (level-0-meta, level-1-workflows, sub-categories) are
79
+ * traversed recursively. A directory is recognized as a skill directory when
80
+ * it contains a SKILL.md file.
81
+ *
82
+ * @param {string} srcDir - Source directory to walk
83
+ * @param {string} destDir - Destination base directory (.claude/skills/)
84
+ */
85
+ function installSkillsFromDir(srcDir, destDir, projectTags) {
86
+ const entries = readdirSync(srcDir);
87
+ for (const entry of entries) {
88
+ const srcPath = join(srcDir, entry);
89
+ const stat = statSync(srcPath);
90
+
91
+ if (stat.isDirectory()) {
92
+ const skillMdPath = join(srcPath, 'SKILL.md');
93
+ if (existsSync(skillMdPath)) {
94
+ // Directory-based skill — check stack filter before copying
95
+ const content = readFileSync(skillMdPath, 'utf-8');
96
+ if (!shouldInstallSkill(content, projectTags)) continue;
97
+ const skillDestDir = join(destDir, entry);
98
+ copyDirectory(srcPath, skillDestDir);
99
+ } else {
100
+ // Level/category directory — recurse
101
+ installSkillsFromDir(srcPath, destDir, projectTags);
102
+ }
103
+ } else if (entry.endsWith('.md') && entry !== 'README.md') {
104
+ // Legacy flat .md skill — check stack filter before copying
105
+ const content = readFileSync(srcPath, 'utf-8');
106
+ if (!shouldInstallSkill(content, projectTags)) continue;
107
+ const skillName = entry.slice(0, -3);
108
+ const skillDir = join(destDir, skillName);
109
+ mkdirSync(skillDir, { recursive: true });
110
+ copyFileSync(srcPath, join(skillDir, 'SKILL.md'));
111
+ }
112
+ }
113
+ }
114
+
115
+ function collectSourceSkillNames() {
116
+ const names = new Set();
117
+ for (const level of SKILL_LEVELS_TO_INSTALL) {
118
+ const levelDir = join(FRAMEWORK_SKILLS_DIR, level);
119
+ if (!existsSync(levelDir)) continue;
120
+ collectNamesFromDir(levelDir, names);
121
+ }
122
+ return names;
123
+ }
124
+
125
+ function collectNamesFromDir(dir, names) {
126
+ for (const entry of readdirSync(dir)) {
127
+ const fullPath = join(dir, entry);
128
+ if (!statSync(fullPath).isDirectory()) continue;
129
+ if (existsSync(join(fullPath, 'SKILL.md'))) {
130
+ names.add(entry);
131
+ } else {
132
+ collectNamesFromDir(fullPath, names);
133
+ }
134
+ }
135
+ }
136
+
137
+ /**
138
+ * Install morph framework skills to .claude/skills/ in the target project.
139
+ * Skills are copied into subdirectories as SKILL.md files so Claude Code can
140
+ * discover them natively via /<skill-name> syntax (e.g., /phase-design,
141
+ * /nextjs-expert). Directory-based skills also get their scripts/,
142
+ * references/, and assets/ subdirectories copied for on-demand loading.
143
+ *
144
+ * Stack filtering: if projectTags is provided, only skills whose `stacks:`
145
+ * frontmatter matches the project tags are installed. Skills without a
146
+ * `stacks:` field are always installed (universal).
147
+ *
148
+ * @param {string} projectDir - Target project root directory
149
+ * @param {Object} [options]
150
+ * @param {string[]} [options.projectTags=[]] - Stack tags from config
151
+ */
152
+ export async function installSkills(projectDir, { projectTags = [] } = {}) {
153
+ const claudeSkillsDir = join(projectDir, '.claude', 'skills');
154
+ mkdirSync(claudeSkillsDir, { recursive: true });
155
+
156
+ for (const level of SKILL_LEVELS_TO_INSTALL) {
157
+ const levelDir = join(FRAMEWORK_SKILLS_DIR, level);
158
+ if (!existsSync(levelDir)) continue;
159
+ installSkillsFromDir(levelDir, claudeSkillsDir, projectTags);
160
+ }
161
+
162
+ // Collect installed morph-* skill names
163
+ const installed = new Set();
164
+ for (const entry of readdirSync(claudeSkillsDir)) {
165
+ if (existsSync(join(claudeSkillsDir, entry, 'SKILL.md'))) {
166
+ installed.add(entry);
167
+ }
168
+ }
169
+
170
+ // Cleanup orphan morph-* skill dirs that exist in source but were filtered out
171
+ const allSourceSkills = collectSourceSkillNames();
172
+ for (const entry of readdirSync(claudeSkillsDir)) {
173
+ if (!entry.startsWith('morph-')) continue;
174
+ if (!installed.has(entry) && allSourceSkills.has(entry)) {
175
+ rmSync(join(claudeSkillsDir, entry), { recursive: true, force: true });
176
+ }
177
+ }
178
+ }